mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-14 17:58:01 +00:00
Compare commits
2 Commits
daily-snap
...
linkedAbil
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fef579b9f2 | ||
|
|
eba393fc03 |
@@ -4,9 +4,11 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
import forge.card.CardStateName;
|
import forge.card.CardStateName;
|
||||||
@@ -35,6 +37,8 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
|
|||||||
protected Card hostCard;
|
protected Card hostCard;
|
||||||
protected CardState cardState = null;
|
protected CardState cardState = null;
|
||||||
|
|
||||||
|
protected List<StaticLayerInterface> grantedByStatic = Lists.newArrayList();
|
||||||
|
|
||||||
/** The map params. */
|
/** The map params. */
|
||||||
protected Map<String, String> originalMapParams = Maps.newHashMap(),
|
protected Map<String, String> originalMapParams = Maps.newHashMap(),
|
||||||
mapParams = Maps.newHashMap();
|
mapParams = Maps.newHashMap();
|
||||||
@@ -589,6 +593,31 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Card getOriginalOrHost() {
|
||||||
|
return ObjectUtils.defaultIfNull(getOriginalHost(), getHostCard());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<StaticLayerInterface> getGrantedByStatic() {
|
||||||
|
return grantedByStatic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGrantedByStatic(List<StaticLayerInterface> list) {
|
||||||
|
this.grantedByStatic = Lists.newArrayList(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addGrantedByStatic(final StaticLayerInterface stAb) {
|
||||||
|
grantedByStatic.add(stAb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO currently Clone effects doesn't set Grantor like giving Abilities does
|
||||||
|
// if it would, then this needs to be refactored anyway
|
||||||
|
public Card getFirstGrantor() {
|
||||||
|
if (grantedByStatic.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return grantedByStatic.get(0).getHostCard();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isCopiedTrait() {
|
public boolean isCopiedTrait() {
|
||||||
if (this.getCardState() == null) {
|
if (this.getCardState() == null) {
|
||||||
return false;
|
return false;
|
||||||
@@ -650,7 +679,8 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
|
|||||||
copy.mapParams = Maps.newHashMap(originalMapParams);
|
copy.mapParams = Maps.newHashMap(originalMapParams);
|
||||||
copy.setSVars(sVars);
|
copy.setSVars(sVars);
|
||||||
copy.setCardState(cardState);
|
copy.setCardState(cardState);
|
||||||
// dont use setHostCard to not trigger the not copied parts yet
|
copy.setGrantedByStatic(grantedByStatic);
|
||||||
|
// don't use setHostCard to not trigger the not copied parts yet
|
||||||
copy.hostCard = host;
|
copy.hostCard = host;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package forge.game;
|
||||||
|
|
||||||
|
import forge.game.card.Card;
|
||||||
|
|
||||||
|
public interface StaticLayerInterface {
|
||||||
|
|
||||||
|
public Card getHostCard();
|
||||||
|
}
|
||||||
@@ -105,9 +105,9 @@ public class AbilityUtils {
|
|||||||
}
|
}
|
||||||
else if (defined.equals("OriginalHost")) {
|
else if (defined.equals("OriginalHost")) {
|
||||||
if (sa instanceof SpellAbility) {
|
if (sa instanceof SpellAbility) {
|
||||||
c = ((SpellAbility)sa).getRootAbility().getOriginalHost();
|
c = ((SpellAbility)sa).getRootAbility().getFirstGrantor();
|
||||||
} else {
|
} else {
|
||||||
c = sa.getOriginalHost();
|
c = sa.getFirstGrantor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (defined.equals("EffectSource")) {
|
else if (defined.equals("EffectSource")) {
|
||||||
@@ -539,7 +539,7 @@ public class AbilityUtils {
|
|||||||
val = 0;
|
val = 0;
|
||||||
}
|
}
|
||||||
} else if (calcX[0].equals("OriginalHost")) {
|
} else if (calcX[0].equals("OriginalHost")) {
|
||||||
val = xCount(ability.getOriginalHost(), calcX[1], ability);
|
val = xCount(ability.getFirstGrantor(), calcX[1], ability);
|
||||||
} else if (calcX[0].startsWith("Remembered")) {
|
} else if (calcX[0].startsWith("Remembered")) {
|
||||||
// Add whole Remembered list to handlePaid
|
// Add whole Remembered list to handlePaid
|
||||||
final CardCollection list = new CardCollection();
|
final CardCollection list = new CardCollection();
|
||||||
|
|||||||
@@ -1,20 +1,21 @@
|
|||||||
package forge.game.card;
|
package forge.game.card;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
|
||||||
import com.google.common.base.Optional;
|
|
||||||
import com.google.common.collect.ForwardingTable;
|
import com.google.common.collect.ForwardingTable;
|
||||||
import com.google.common.collect.HashBasedTable;
|
import com.google.common.collect.HashBasedTable;
|
||||||
import com.google.common.collect.Table;
|
import com.google.common.collect.Table;
|
||||||
|
|
||||||
|
import forge.game.StaticLayerInterface;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.staticability.StaticAbility;
|
|
||||||
|
|
||||||
public class ActivationTable extends ForwardingTable<SpellAbility, Optional<StaticAbility>, Integer> {
|
public class ActivationTable extends ForwardingTable<SpellAbility, List<StaticLayerInterface>, Integer> {
|
||||||
Table<SpellAbility, Optional<StaticAbility>, Integer> dataTable = HashBasedTable.create();
|
Table<SpellAbility, List<StaticLayerInterface>, Integer> dataTable = HashBasedTable.create();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Table<SpellAbility, Optional<StaticAbility>, Integer> delegate() {
|
protected Table<SpellAbility, List<StaticLayerInterface>, Integer> delegate() {
|
||||||
return dataTable;
|
return dataTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ public class ActivationTable extends ForwardingTable<SpellAbility, Optional<Stat
|
|||||||
SpellAbility original = getOriginal(sa);
|
SpellAbility original = getOriginal(sa);
|
||||||
|
|
||||||
if (original != null) {
|
if (original != null) {
|
||||||
Optional<StaticAbility> st = Optional.fromNullable(root.getGrantorStatic());
|
List<StaticLayerInterface> st = root.getGrantedByStatic();
|
||||||
|
|
||||||
delegate().put(original, st, ObjectUtils.defaultIfNull(get(original, st), 0) + 1);
|
delegate().put(original, st, ObjectUtils.defaultIfNull(get(original, st), 0) + 1);
|
||||||
}
|
}
|
||||||
@@ -45,7 +46,7 @@ public class ActivationTable extends ForwardingTable<SpellAbility, Optional<Stat
|
|||||||
public Integer get(SpellAbility sa) {
|
public Integer get(SpellAbility sa) {
|
||||||
SpellAbility root = sa.getRootAbility();
|
SpellAbility root = sa.getRootAbility();
|
||||||
SpellAbility original = getOriginal(sa);
|
SpellAbility original = getOriginal(sa);
|
||||||
Optional<StaticAbility> st = Optional.fromNullable(root.getGrantorStatic());
|
List<StaticLayerInterface> st = root.getGrantedByStatic();
|
||||||
|
|
||||||
if (contains(original, st)) {
|
if (contains(original, st)) {
|
||||||
return get(original, st);
|
return get(original, st);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import forge.game.GameEntityCounterTable;
|
|||||||
import forge.game.GameStage;
|
import forge.game.GameStage;
|
||||||
import forge.game.GlobalRuleChange;
|
import forge.game.GlobalRuleChange;
|
||||||
import forge.game.IHasSVars;
|
import forge.game.IHasSVars;
|
||||||
|
import forge.game.StaticLayerInterface;
|
||||||
import forge.game.ability.AbilityFactory;
|
import forge.game.ability.AbilityFactory;
|
||||||
import forge.game.ability.AbilityKey;
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
@@ -74,6 +75,7 @@ import forge.util.collect.FCollection;
|
|||||||
import forge.util.collect.FCollectionView;
|
import forge.util.collect.FCollectionView;
|
||||||
import io.sentry.Breadcrumb;
|
import io.sentry.Breadcrumb;
|
||||||
import io.sentry.Sentry;
|
import io.sentry.Sentry;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.mutable.MutableBoolean;
|
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
@@ -149,11 +151,13 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
private final Table<Long, Long, CardTraitChanges> changedCardTraits = TreeBasedTable.create(); // Layer 6
|
private final Table<Long, Long, CardTraitChanges> changedCardTraits = TreeBasedTable.create(); // Layer 6
|
||||||
|
|
||||||
// stores the card traits created by static abilities
|
// stores the card traits created by static abilities
|
||||||
private final Table<StaticAbility, String, SpellAbility> storedSpellAbilility = TreeBasedTable.create();
|
private final Table<StaticAbility, String, SpellAbility> storedSpellAbility = TreeBasedTable.create();
|
||||||
private final Table<StaticAbility, String, Trigger> storedTrigger = TreeBasedTable.create();
|
private final Table<StaticAbility, String, Trigger> storedTrigger = TreeBasedTable.create();
|
||||||
private final Table<StaticAbility, String, ReplacementEffect> storedReplacementEffect = TreeBasedTable.create();
|
private final Table<StaticAbility, String, ReplacementEffect> storedReplacementEffect = TreeBasedTable.create();
|
||||||
private final Table<StaticAbility, String, StaticAbility> storedStaticAbility = TreeBasedTable.create();
|
private final Table<StaticAbility, String, StaticAbility> storedStaticAbility = TreeBasedTable.create();
|
||||||
|
|
||||||
|
private final Table<StaticLayerInterface, SpellAbility, SpellAbility> copiedSpellAbility = HashBasedTable.create();
|
||||||
|
|
||||||
// x=timestamp y=StaticAbility id
|
// x=timestamp y=StaticAbility id
|
||||||
private final Table<Long, Long, CardColor> changedCardColorsByText = TreeBasedTable.create(); // Layer 3 by Text Change
|
private final Table<Long, Long, CardColor> changedCardColorsByText = TreeBasedTable.create(); // Layer 3 by Text Change
|
||||||
private final Table<Long, Long, CardColor> changedCardColorsCharacterDefining = TreeBasedTable.create(); // Layer 5 CDA
|
private final Table<Long, Long, CardColor> changedCardColorsCharacterDefining = TreeBasedTable.create(); // Layer 5 CDA
|
||||||
@@ -329,11 +333,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
private final ActivationTable numberGameActivations = new ActivationTable();
|
private final ActivationTable numberGameActivations = new ActivationTable();
|
||||||
private final ActivationTable numberAbilityResolved = new ActivationTable();
|
private final ActivationTable numberAbilityResolved = new ActivationTable();
|
||||||
|
|
||||||
private final Map<SpellAbility, List<String>> chosenModesTurn = Maps.newHashMap();
|
private final LinkedAbilityTable<String> chosenModesTurn = new LinkedAbilityTable<String>();
|
||||||
private final Map<SpellAbility, List<String>> chosenModesGame = Maps.newHashMap();
|
private final LinkedAbilityTable<String> chosenModesGame = new LinkedAbilityTable<String>();
|
||||||
|
|
||||||
private final Table<SpellAbility, StaticAbility, List<String>> chosenModesTurnStatic = HashBasedTable.create();
|
|
||||||
private final Table<SpellAbility, StaticAbility, List<String>> chosenModesGameStatic = HashBasedTable.create();
|
|
||||||
|
|
||||||
private CombatLki combatLKI;
|
private CombatLki combatLKI;
|
||||||
|
|
||||||
@@ -4254,12 +4255,12 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final SpellAbility getSpellAbilityForStaticAbility(final String str, final StaticAbility stAb) {
|
public final SpellAbility getSpellAbilityForStaticAbility(final String str, final StaticAbility stAb) {
|
||||||
SpellAbility result = storedSpellAbilility.get(stAb, str);
|
SpellAbility result = storedSpellAbility.get(stAb, str);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
result = AbilityFactory.getAbility(str, this, stAb);
|
result = AbilityFactory.getAbility(str, this, stAb);
|
||||||
result.setIntrinsic(false);
|
result.setIntrinsic(false);
|
||||||
result.setGrantorStatic(stAb);
|
result.addGrantedByStatic(stAb);
|
||||||
storedSpellAbilility.put(stAb, str, result);
|
storedSpellAbility.put(stAb, str, result);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -4268,6 +4269,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
Trigger result = storedTrigger.get(stAb, str);
|
Trigger result = storedTrigger.get(stAb, str);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
result = TriggerHandler.parseTrigger(str, this, false, stAb);
|
result = TriggerHandler.parseTrigger(str, this, false, stAb);
|
||||||
|
result.addGrantedByStatic(stAb);
|
||||||
storedTrigger.put(stAb, str, result);
|
storedTrigger.put(stAb, str, result);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -4278,6 +4280,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
ReplacementEffect result = storedReplacementEffect.get(stAb, str);
|
ReplacementEffect result = storedReplacementEffect.get(stAb, str);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
result = ReplacementHandler.parseReplacement(str, this, false, stAb);
|
result = ReplacementHandler.parseReplacement(str, this, false, stAb);
|
||||||
|
result.addGrantedByStatic(stAb);
|
||||||
storedReplacementEffect.put(stAb, str, result);
|
storedReplacementEffect.put(stAb, str, result);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -4287,11 +4290,28 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
StaticAbility result = storedStaticAbility.get(stAb, str);
|
StaticAbility result = storedStaticAbility.get(stAb, str);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
result = StaticAbility.create(str, this, stAb.getCardState(), false);
|
result = StaticAbility.create(str, this, stAb.getCardState(), false);
|
||||||
|
result.addGrantedByStatic(stAb);
|
||||||
storedStaticAbility.put(stAb, str, result);
|
storedStaticAbility.put(stAb, str, result);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final SpellAbility copySpellAbilityForStaticAbility(final SpellAbility sa, final StaticAbility stAb, final boolean intrinsic) {
|
||||||
|
SpellAbility result = copiedSpellAbility.get(stAb, sa);
|
||||||
|
if (result == null) {
|
||||||
|
result = sa.copy(this, false);
|
||||||
|
if (stAb.hasParam("GainsAbilitiesLimitPerTurn")) {
|
||||||
|
result.setRestrictions(sa.getRestrictions());
|
||||||
|
result.getRestrictions().setLimitToCheck(stAb.getParam("GainsAbilitiesLimitPerTurn"));
|
||||||
|
}
|
||||||
|
result.setOriginalAbility(sa.getOriginalAbility()); // need to be set to get the Once Per turn Clause correct
|
||||||
|
result.addGrantedByStatic(stAb);
|
||||||
|
result.setIntrinsic(intrinsic);
|
||||||
|
copiedSpellAbility.put(stAb, sa, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public final void addChangedCardTraits(Collection<SpellAbility> spells, Collection<SpellAbility> removedAbilities,
|
public final void addChangedCardTraits(Collection<SpellAbility> spells, Collection<SpellAbility> removedAbilities,
|
||||||
Collection<Trigger> trigger, Collection<ReplacementEffect> replacements, Collection<StaticAbility> statics,
|
Collection<Trigger> trigger, Collection<ReplacementEffect> replacements, Collection<StaticAbility> statics,
|
||||||
boolean removeAll, boolean removeNonMana, long timestamp, long staticId) {
|
boolean removeAll, boolean removeNonMana, long timestamp, long staticId) {
|
||||||
@@ -6863,91 +6883,19 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getChosenModesTurn(SpellAbility ability) {
|
public List<String> getChosenModesTurn(SpellAbility ability) {
|
||||||
SpellAbility original = null;
|
return chosenModesTurn.get(ability);
|
||||||
SpellAbility root = ability.getRootAbility();
|
|
||||||
|
|
||||||
// because trigger spell abilities are copied, try to get original one
|
|
||||||
if (root.isTrigger()) {
|
|
||||||
original = root.getTrigger().getOverridingAbility();
|
|
||||||
} else {
|
|
||||||
original = ability.getOriginalAbility();
|
|
||||||
if (original == null) {
|
|
||||||
original = ability;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ability.getGrantorStatic() != null) {
|
|
||||||
return chosenModesTurnStatic.get(original, ability.getGrantorStatic());
|
|
||||||
}
|
|
||||||
return chosenModesTurn.get(original);
|
|
||||||
}
|
}
|
||||||
public List<String> getChosenModesGame(SpellAbility ability) {
|
public List<String> getChosenModesGame(SpellAbility ability) {
|
||||||
SpellAbility original = null;
|
return chosenModesGame.get(ability);
|
||||||
SpellAbility root = ability.getRootAbility();
|
|
||||||
|
|
||||||
// because trigger spell abilities are copied, try to get original one
|
|
||||||
if (root.isTrigger()) {
|
|
||||||
original = root.getTrigger().getOverridingAbility();
|
|
||||||
} else {
|
|
||||||
original = ability.getOriginalAbility();
|
|
||||||
if (original == null) {
|
|
||||||
original = ability;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ability.getGrantorStatic() != null) {
|
|
||||||
return chosenModesGameStatic.get(original, ability.getGrantorStatic());
|
|
||||||
}
|
|
||||||
return chosenModesGame.get(original);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addChosenModes(SpellAbility ability, String mode) {
|
public void addChosenModes(SpellAbility ability, String mode) {
|
||||||
SpellAbility original = null;
|
this.chosenModesTurn.put(mode, ability);
|
||||||
SpellAbility root = ability.getRootAbility();
|
this.chosenModesGame.put(mode, ability);
|
||||||
|
|
||||||
// because trigger spell abilities are copied, try to get original one
|
|
||||||
if (root.isTrigger()) {
|
|
||||||
original = root.getTrigger().getOverridingAbility();
|
|
||||||
} else {
|
|
||||||
original = ability.getOriginalAbility();
|
|
||||||
if (original == null) {
|
|
||||||
original = ability;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ability.getGrantorStatic() != null) {
|
|
||||||
List<String> result = chosenModesTurnStatic.get(original, ability.getGrantorStatic());
|
|
||||||
if (result == null) {
|
|
||||||
result = Lists.newArrayList();
|
|
||||||
chosenModesTurnStatic.put(original, ability.getGrantorStatic(), result);
|
|
||||||
}
|
|
||||||
result.add(mode);
|
|
||||||
result = chosenModesGameStatic.get(original, ability.getGrantorStatic());
|
|
||||||
if (result == null) {
|
|
||||||
result = Lists.newArrayList();
|
|
||||||
chosenModesGameStatic.put(original, ability.getGrantorStatic(), result);
|
|
||||||
}
|
|
||||||
result.add(mode);
|
|
||||||
} else {
|
|
||||||
List<String> result = chosenModesTurn.get(original);
|
|
||||||
if (result == null) {
|
|
||||||
result = Lists.newArrayList();
|
|
||||||
chosenModesTurn.put(original, result);
|
|
||||||
}
|
|
||||||
result.add(mode);
|
|
||||||
|
|
||||||
result = chosenModesGame.get(original);
|
|
||||||
if (result == null) {
|
|
||||||
result = Lists.newArrayList();
|
|
||||||
chosenModesGame.put(original, result);
|
|
||||||
}
|
|
||||||
result.add(mode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetChosenModeTurn() {
|
public void resetChosenModeTurn() {
|
||||||
chosenModesTurn.clear();
|
chosenModesTurn.clear();
|
||||||
chosenModesTurnStatic.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPlaneswalkerAbilityActivated() {
|
public int getPlaneswalkerAbilityActivated() {
|
||||||
|
|||||||
111
forge-game/src/main/java/forge/game/card/LinkedAbilityTable.java
Normal file
111
forge-game/src/main/java/forge/game/card/LinkedAbilityTable.java
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
package forge.game.card;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
|
||||||
|
import com.google.common.collect.ForwardingTable;
|
||||||
|
import com.google.common.collect.HashBasedTable;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Table;
|
||||||
|
|
||||||
|
import forge.game.CardTraitBase;
|
||||||
|
import forge.game.StaticLayerInterface;
|
||||||
|
import forge.util.collect.FCollection;
|
||||||
|
|
||||||
|
public class LinkedAbilityTable<T> extends ForwardingTable<Card, List<StaticLayerInterface>, FCollection<T>> {
|
||||||
|
private Table<Card, List<StaticLayerInterface>, FCollection<T>> dataTable = HashBasedTable.create();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Table<Card, List<StaticLayerInterface>, FCollection<T>> delegate() {
|
||||||
|
return dataTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected FCollection<T> getSupplier() {
|
||||||
|
return new FCollection<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected FCollection<T> putInternal(T object, Card host, List<StaticLayerInterface> st) {
|
||||||
|
host = ObjectUtils.defaultIfNull(host.getEffectSource(), host);
|
||||||
|
FCollection<T> old;
|
||||||
|
if (contains(host, st)) {
|
||||||
|
old = get(host, st);
|
||||||
|
} else {
|
||||||
|
old = getSupplier();
|
||||||
|
delegate().put(host, st, old);
|
||||||
|
}
|
||||||
|
old.add(object);
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
public FCollection<T> put(T object, Card host) {
|
||||||
|
return putInternal(object, host, null);
|
||||||
|
}
|
||||||
|
//*/
|
||||||
|
public FCollection<T> put(T object, CardTraitBase ctb) {
|
||||||
|
return putInternal(object, ctb.getOriginalOrHost(), ctb.getGrantedByStatic());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setInternal(Iterable<T> list, Card host, List<StaticLayerInterface> st) {
|
||||||
|
host = ObjectUtils.defaultIfNull(host.getEffectSource(), host);
|
||||||
|
if (list == null || Iterables.isEmpty(list)) {
|
||||||
|
delegate().remove(host, st);
|
||||||
|
} else {
|
||||||
|
FCollection<T> old = getSupplier();
|
||||||
|
old.addAll(list);
|
||||||
|
delegate().put(host, st, old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(Iterable<T> list, CardTraitBase ctb) {
|
||||||
|
setInternal(list, ctb.getOriginalOrHost(), ctb.getGrantedByStatic());
|
||||||
|
}
|
||||||
|
|
||||||
|
public FCollection<T> get(CardTraitBase ctb) {
|
||||||
|
Card host = ctb.getOriginalOrHost();
|
||||||
|
host = ObjectUtils.defaultIfNull(host.getEffectSource(), host);
|
||||||
|
List<StaticLayerInterface> st = ctb.getGrantedByStatic();
|
||||||
|
if (contains(host, st)) {
|
||||||
|
return get(host, st);
|
||||||
|
} else {
|
||||||
|
return FCollection.<T>getEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FCollection<T> get(Card host) {
|
||||||
|
if (contains(host, Lists.newArrayList())) {
|
||||||
|
return get(host, Lists.newArrayList());
|
||||||
|
} else {
|
||||||
|
return FCollection.<T>getEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(T object, CardTraitBase ctb) {
|
||||||
|
return get(ctb).contains(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean remove(T value) {
|
||||||
|
boolean changed = false;
|
||||||
|
for (FCollection<T> col : delegate().values()) {
|
||||||
|
if (col.remove(value)) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasOtherLinkedValues(Card host) {
|
||||||
|
for (List<StaticLayerInterface> o : this.columnKeySet()) {
|
||||||
|
if (!o.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Card ctbHost : this.rowKeySet()) {
|
||||||
|
if (!host.equals(ctbHost)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@ package forge.game.card.token;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
@@ -273,7 +272,7 @@ public class TokenInfo {
|
|||||||
final Card host = sa.getHostCard();
|
final Card host = sa.getHostCard();
|
||||||
final Game game = host.getGame();
|
final Game game = host.getGame();
|
||||||
|
|
||||||
String edition = ObjectUtils.firstNonNull(sa.getOriginalHost(), host).getSetCode();
|
String edition = sa.getOriginalOrHost().getSetCode();
|
||||||
PaperToken token = StaticData.instance().getAllTokens().getToken(script, edition);
|
PaperToken token = StaticData.instance().getAllTokens().getToken(script, edition);
|
||||||
|
|
||||||
if (token == null) {
|
if (token == null) {
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ public class CostRemoveCounter extends CostPart {
|
|||||||
} else {
|
} else {
|
||||||
List<Card> typeList;
|
List<Card> typeList;
|
||||||
if (type.equals("OriginalHost")) {
|
if (type.equals("OriginalHost")) {
|
||||||
typeList = Lists.newArrayList(ability.getOriginalHost());
|
typeList = Lists.newArrayList(ability.getFirstGrantor());
|
||||||
} else {
|
} else {
|
||||||
typeList = CardLists.getValidCards(payer.getCardsIn(this.zone), type.split(";"), payer, source, ability);
|
typeList = CardLists.getValidCards(payer.getCardsIn(this.zone), type.split(";"), payer, source, ability);
|
||||||
}
|
}
|
||||||
@@ -155,7 +155,7 @@ public class CostRemoveCounter extends CostPart {
|
|||||||
else {
|
else {
|
||||||
List<Card> typeList;
|
List<Card> typeList;
|
||||||
if (type.equals("OriginalHost")) {
|
if (type.equals("OriginalHost")) {
|
||||||
typeList = Lists.newArrayList(ability.getOriginalHost());
|
typeList = Lists.newArrayList(ability.getFirstGrantor());
|
||||||
} else {
|
} else {
|
||||||
typeList = CardLists.getValidCards(payer.getCardsIn(this.zone), type.split(";"), payer, source, ability);
|
typeList = CardLists.getValidCards(payer.getCardsIn(this.zone), type.split(";"), payer, source, ability);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,10 @@ public class CostSacrifice extends CostPartWithList {
|
|||||||
final Card source = ability.getHostCard();
|
final Card source = ability.getHostCard();
|
||||||
|
|
||||||
if (getType().equals("OriginalHost")) {
|
if (getType().equals("OriginalHost")) {
|
||||||
Card originalEquipment = ability.getOriginalHost();
|
Card originalEquipment = ability.getFirstGrantor();
|
||||||
|
if (!originalEquipment.getController().equals(activator)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return originalEquipment.isEquipping() && originalEquipment.canBeSacrificedBy(ability, effect);
|
return originalEquipment.isEquipping() && originalEquipment.canBeSacrificedBy(ability, effect);
|
||||||
}
|
}
|
||||||
else if (!payCostFromSource()) { // You can always sac all
|
else if (!payCostFromSource()) { // You can always sac all
|
||||||
@@ -131,7 +134,7 @@ public class CostSacrifice extends CostPartWithList {
|
|||||||
// if X is defined, it needs to be calculated and checked, if X is
|
// if X is defined, it needs to be calculated and checked, if X is
|
||||||
// choice, it can be Paid even if it's 0
|
// choice, it can be Paid even if it's 0
|
||||||
}
|
}
|
||||||
else return source.canBeSacrificedBy(ability, effect);
|
else return source.getController().equals(activator) && source.canBeSacrificedBy(ability, effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ public class CostUnattach extends CostPartWithList {
|
|||||||
if (type.equals("CARDNAME")) {
|
if (type.equals("CARDNAME")) {
|
||||||
return source.isEquipping();
|
return source.isEquipping();
|
||||||
} else if (type.equals("OriginalHost")) {
|
} else if (type.equals("OriginalHost")) {
|
||||||
Card originalEquipment = ability.getOriginalHost();
|
Card originalEquipment = ability.getFirstGrantor();
|
||||||
return originalEquipment.isEquipping();
|
return originalEquipment.isEquipping();
|
||||||
} else {
|
} else {
|
||||||
return CardLists.getValidCards(source.getEquippedBy(), type, payer, source, ability).size() > 0;
|
return CardLists.getValidCards(source.getEquippedBy(), type, payer, source, ability).size() > 0;
|
||||||
@@ -89,7 +89,7 @@ public class CostUnattach extends CostPartWithList {
|
|||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
} else if (getType().equals("OriginalHost")) {
|
} else if (getType().equals("OriginalHost")) {
|
||||||
Card originalEquipment = ability.getOriginalHost();
|
Card originalEquipment = ability.getFirstGrantor();
|
||||||
if (originalEquipment.isEquipping()) {
|
if (originalEquipment.isEquipping()) {
|
||||||
return originalEquipment;
|
return originalEquipment;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -920,8 +920,8 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
desc = CardTranslation.translateMultipleDescriptionText(desc, currentName);
|
desc = CardTranslation.translateMultipleDescriptionText(desc, currentName);
|
||||||
desc = TextUtil.fastReplace(desc, "CARDNAME", CardTranslation.getTranslatedName(currentName));
|
desc = TextUtil.fastReplace(desc, "CARDNAME", CardTranslation.getTranslatedName(currentName));
|
||||||
desc = TextUtil.fastReplace(desc, "NICKNAME", Lang.getInstance().getNickName(CardTranslation.getTranslatedName(currentName)));
|
desc = TextUtil.fastReplace(desc, "NICKNAME", Lang.getInstance().getNickName(CardTranslation.getTranslatedName(currentName)));
|
||||||
if (node.getOriginalHost() != null) {
|
if (node.getFirstGrantor() != null) {
|
||||||
desc = TextUtil.fastReplace(desc, "ORIGINALHOST", node.getOriginalHost().getName());
|
desc = TextUtil.fastReplace(desc, "ORIGINALHOST", node.getFirstGrantor().getName());
|
||||||
}
|
}
|
||||||
sb.append(desc);
|
sb.append(desc);
|
||||||
}
|
}
|
||||||
@@ -2354,7 +2354,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SpellAbility getOriginalAbility() {
|
public SpellAbility getOriginalAbility() {
|
||||||
return grantorOriginal;
|
return ObjectUtils.defaultIfNull(grantorOriginal, this);
|
||||||
}
|
}
|
||||||
public void setOriginalAbility(final SpellAbility sa) {
|
public void setOriginalAbility(final SpellAbility sa) {
|
||||||
grantorOriginal = sa;
|
grantorOriginal = sa;
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import forge.game.Game;
|
|||||||
import forge.game.GameEntity;
|
import forge.game.GameEntity;
|
||||||
import forge.game.GameStage;
|
import forge.game.GameStage;
|
||||||
import forge.game.IIdentifiable;
|
import forge.game.IIdentifiable;
|
||||||
|
import forge.game.StaticLayerInterface;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollection;
|
import forge.game.card.CardCollection;
|
||||||
@@ -51,7 +52,7 @@ import forge.util.TextUtil;
|
|||||||
/**
|
/**
|
||||||
* The Class StaticAbility.
|
* The Class StaticAbility.
|
||||||
*/
|
*/
|
||||||
public class StaticAbility extends CardTraitBase implements IIdentifiable, Cloneable, Comparable<StaticAbility> {
|
public class StaticAbility extends CardTraitBase implements IIdentifiable, Cloneable, Comparable<StaticAbility>, StaticLayerInterface {
|
||||||
private static int maxId = 0;
|
private static int maxId = 0;
|
||||||
private static int nextId() { return ++maxId; }
|
private static int nextId() { return ++maxId; }
|
||||||
|
|
||||||
|
|||||||
@@ -615,9 +615,7 @@ public final class StaticAbilityContinuous {
|
|||||||
List<KeywordInterface> keywords = Lists.newArrayList();
|
List<KeywordInterface> keywords = Lists.newArrayList();
|
||||||
|
|
||||||
for (SpellAbility sa : state.getSpellAbilities()) {
|
for (SpellAbility sa : state.getSpellAbilities()) {
|
||||||
SpellAbility newSA = sa.copy(affectedCard, false);
|
SpellAbility newSA = affectedCard.copySpellAbilityForStaticAbility(sa, stAb, true);
|
||||||
newSA.setOriginalAbility(sa); // need to be set to get the Once Per turn Clause correct
|
|
||||||
newSA.setGrantorStatic(stAb);
|
|
||||||
//newSA.setIntrinsic(false); needs to be changed by CardTextChanges
|
//newSA.setIntrinsic(false); needs to be changed by CardTextChanges
|
||||||
|
|
||||||
spellAbilities.add(newSA);
|
spellAbilities.add(newSA);
|
||||||
@@ -626,7 +624,6 @@ public final class StaticAbilityContinuous {
|
|||||||
for (String ability : params.get("GainTextAbilities").split(" & ")) {
|
for (String ability : params.get("GainTextAbilities").split(" & ")) {
|
||||||
final SpellAbility sa = AbilityFactory.getAbility(AbilityUtils.getSVar(stAb, ability), affectedCard, stAb);
|
final SpellAbility sa = AbilityFactory.getAbility(AbilityUtils.getSVar(stAb, ability), affectedCard, stAb);
|
||||||
sa.setIntrinsic(true); // needs to be affected by Text
|
sa.setIntrinsic(true); // needs to be affected by Text
|
||||||
sa.setGrantorStatic(stAb);
|
|
||||||
spellAbilities.add(sa);
|
spellAbilities.add(sa);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -835,15 +832,7 @@ public final class StaticAbilityContinuous {
|
|||||||
if (loyaltyAB && !sa.isPwAbility()) {
|
if (loyaltyAB && !sa.isPwAbility()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SpellAbility newSA = sa.copy(affectedCard, false);
|
addedAbilities.add(affectedCard.copySpellAbilityForStaticAbility(sa, stAb, false));
|
||||||
if (params.containsKey("GainsAbilitiesLimitPerTurn")) {
|
|
||||||
newSA.setRestrictions(sa.getRestrictions());
|
|
||||||
newSA.getRestrictions().setLimitToCheck(params.get("GainsAbilitiesLimitPerTurn"));
|
|
||||||
}
|
|
||||||
newSA.setOriginalAbility(sa); // need to be set to get the Once Per turn Clause correct
|
|
||||||
newSA.setGrantorStatic(stAb);
|
|
||||||
newSA.setIntrinsic(false);
|
|
||||||
addedAbilities.add(newSA);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -206,8 +206,8 @@ public abstract class Trigger extends TriggerReplacementBase {
|
|||||||
if (!saDesc.startsWith(sa.getHostCard().getName())) {
|
if (!saDesc.startsWith(sa.getHostCard().getName())) {
|
||||||
saDesc = saDesc.substring(0, 1).toLowerCase() + saDesc.substring(1);
|
saDesc = saDesc.substring(0, 1).toLowerCase() + saDesc.substring(1);
|
||||||
}
|
}
|
||||||
if (saDesc.contains("ORIGINALHOST") && sa.getOriginalHost() != null) {
|
if (saDesc.contains("ORIGINALHOST") && sa.getFirstGrantor() != null) {
|
||||||
saDesc = TextUtil.fastReplace(saDesc, "ORIGINALHOST", sa.getOriginalHost().getName());
|
saDesc = TextUtil.fastReplace(saDesc, "ORIGINALHOST", sa.getFirstGrantor().getName());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
saDesc = "<take no action>"; // printed in case nothing is chosen for the ability (e.g. Charm with Up to X)
|
saDesc = "<take no action>"; // printed in case nothing is chosen for the ability (e.g. Charm with Up to X)
|
||||||
|
|||||||
@@ -943,7 +943,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
|||||||
return PaymentDecision.card(source, cntRemoved >= 0 ? cntRemoved : maxCounters);
|
return PaymentDecision.card(source, cntRemoved >= 0 ? cntRemoved : maxCounters);
|
||||||
|
|
||||||
} else if (type.equals("OriginalHost")) {
|
} else if (type.equals("OriginalHost")) {
|
||||||
final int maxCounters = ability.getOriginalHost().getCounters(cost.counter);
|
final int maxCounters = ability.getFirstGrantor().getCounters(cost.counter);
|
||||||
if (amount.equals("All")) {
|
if (amount.equals("All")) {
|
||||||
cntRemoved = maxCounters;
|
cntRemoved = maxCounters;
|
||||||
}
|
}
|
||||||
@@ -951,7 +951,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return PaymentDecision.card(ability.getOriginalHost(), cntRemoved >= 0 ? cntRemoved : maxCounters);
|
return PaymentDecision.card(ability.getFirstGrantor(), cntRemoved >= 0 ? cntRemoved : maxCounters);
|
||||||
}
|
}
|
||||||
|
|
||||||
CardCollectionView validCards = CardLists.getValidCards(player.getCardsIn(cost.zone), type.split(";"), player, source, ability);
|
CardCollectionView validCards = CardLists.getValidCards(player.getCardsIn(cost.zone), type.split(";"), player, source, ability);
|
||||||
@@ -994,7 +994,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type.equals("OriginalHost")) {
|
if (type.equals("OriginalHost")) {
|
||||||
Card host = ability.getOriginalHost();
|
Card host = ability.getFirstGrantor();
|
||||||
if (host.getController() == ability.getActivatingPlayer() && host.isInPlay()) {
|
if (host.getController() == ability.getActivatingPlayer() && host.isInPlay()) {
|
||||||
return controller.confirmPayment(cost, Localizer.getInstance().getMessage("lblSacrificeCardConfirm", CardTranslation.getTranslatedName(host.getName())), ability) ? PaymentDecision.card(host) : null;
|
return controller.confirmPayment(cost, Localizer.getInstance().getMessage("lblSacrificeCardConfirm", CardTranslation.getTranslatedName(host.getName())), ability) ? PaymentDecision.card(host) : null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user