Commit 96e61114 authored by Hans Mackowiak's avatar Hans Mackowiak

Riot: Make Riot Enchantment look into the future

parent f8d360f2
......@@ -29,6 +29,7 @@ import forge.game.ability.effects.AttachEffect;
import forge.game.card.*;
import forge.game.event.*;
import forge.game.keyword.KeywordInterface;
import forge.game.keyword.KeywordsChange;
import forge.game.player.GameLossReason;
import forge.game.player.Player;
import forge.game.replacement.ReplacementEffect;
......@@ -292,6 +293,33 @@ public class GameAction {
copied.getOwner().addInboundToken(copied);
}
if (toBattlefield) {
// HACK for making the RIOT enchantment look into the Future
// need to check the Keywords what it would have on the Battlefield
Card riotLKI = CardUtil.getLKICopy(copied);
riotLKI.setLastKnownZone(zoneTo);
CardCollection preList = new CardCollection(riotLKI);
checkStaticAbilities(false, Sets.newHashSet(riotLKI), preList);
List<Long> changedTimeStamps = Lists.newArrayList();
for(Map.Entry<Long, KeywordsChange> e : riotLKI.getChangedCardKeywords().entrySet()) {
if (!copied.hasChangedCardKeywords(e.getKey())) {
KeywordsChange o = e.getValue();
o.setHostCard(copied);
for (KeywordInterface k : o.getKeywords()) {
for (ReplacementEffect re : k.getReplacements()) {
// this param need to be set, otherwise in ReplaceMoved it fails
re.getMapParams().put("BypassEtbCheck", "True");
}
}
copied.addChangedCardKeywordsInternal(o, e.getKey());
changedTimeStamps.add(e.getKey());
}
}
checkStaticAbilities(false);
}
Map<String, Object> repParams = Maps.newHashMap();
repParams.put("Event", "Moved");
repParams.put("Affected", copied);
......
......@@ -3404,6 +3404,15 @@ public class Card extends GameEntity implements Comparable<Card> {
return change;
}
public final boolean hasChangedCardKeywords(final long timestamp) {
return changedCardKeywords.containsKey(timestamp);
}
public final void addChangedCardKeywordsInternal(final KeywordsChange change, final long timestamp) {
changedCardKeywords.put(timestamp, change);
updateKeywordsCache(currentState);
}
// Hidden keywords will be left out
public final Collection<KeywordInterface> getUnhiddenKeywords() {
return getUnhiddenKeywords(currentState);
......@@ -5731,7 +5740,7 @@ public class Card extends GameEntity implements Comparable<Card> {
public void setChangedCardKeywords(Map<Long, KeywordsChange> changedCardKeywords) {
this.changedCardKeywords.clear();
for (Entry<Long, KeywordsChange> entry : changedCardKeywords.entrySet()) {
this.changedCardKeywords.put(entry.getKey(), entry.getValue());
this.changedCardKeywords.put(entry.getKey(), entry.getValue().copy(this, true));
}
}
......
......@@ -8,6 +8,8 @@ import java.util.Iterator;
import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;
import forge.game.card.Card;
public class KeywordCollection implements Iterable<String>, Serializable {
private static final long serialVersionUID = -2882986558147844702L;
......@@ -151,6 +153,12 @@ public class KeywordCollection implements Iterable<String>, Serializable {
return map.get(keyword);
}
public void setHostCard(final Card host) {
for (KeywordInterface k : map.values()) {
k.setHostCard(host);
}
}
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
......
......@@ -202,7 +202,7 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
public Collection<StaticAbility> getStaticAbilities() {
return staticAbilities;
}
/*
* (non-Javadoc)
* @see forge.game.keyword.KeywordInterface#copy()
......@@ -233,7 +233,7 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
return result;
} catch (final Exception ex) {
throw new RuntimeException("KeywordInstance : clone() error, " + ex);
throw new RuntimeException("KeywordInstance : clone() error", ex);
}
}
......@@ -252,4 +252,26 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
public boolean redundant(Collection<KeywordInterface> list) {
return !list.isEmpty() && keyword.isMultipleRedundant;
}
/* (non-Javadoc)
* @see forge.game.keyword.KeywordInterface#setHostCard(forge.game.card.Card)
*/
@Override
public void setHostCard(Card host) {
for (SpellAbility sa : this.abilities) {
sa.setHostCard(host);
}
for (Trigger tr : this.triggers) {
tr.setHostCard(host);
}
for (ReplacementEffect re : this.replacements) {
re.setHostCard(host);
}
for (StaticAbility sa : this.staticAbilities) {
sa.setHostCard(host);
}
}
}
......@@ -31,6 +31,7 @@ public interface KeywordInterface extends Cloneable {
public void addSpellAbility(final SpellAbility s);
public void addStaticAbility(final StaticAbility st);
public void setHostCard(final Card host);
/**
* @return the triggers
......
......@@ -30,12 +30,11 @@ import forge.game.card.Card;
* </p>
*
* @author Forge
* @version $Id: KeywordsChange.java 27095 2014-08-17 07:32:24Z elcnesh $
*/
public class KeywordsChange {
private final KeywordCollection keywords = new KeywordCollection();
private final List<KeywordInterface> removeKeywordInterfaces = Lists.newArrayList();
private final List<String> removeKeywords = Lists.newArrayList();
public class KeywordsChange implements Cloneable {
private KeywordCollection keywords = new KeywordCollection();
private List<KeywordInterface> removeKeywordInterfaces = Lists.newArrayList();
private List<String> removeKeywords = Lists.newArrayList();
private boolean removeAllKeywords;
private boolean removeIntrinsicKeywords;
......@@ -63,7 +62,7 @@ public class KeywordsChange {
this.removeAllKeywords = removeAll;
this.removeIntrinsicKeywords = removeIntrinsic;
}
public KeywordsChange(
final Collection<KeywordInterface> keywordList,
final Collection<KeywordInterface> removeKeywordInterfaces,
......@@ -172,4 +171,49 @@ public class KeywordsChange {
removeIntrinsicKeywords = true;
}
}
public void setHostCard(final Card host) {
keywords.setHostCard(host);
for (KeywordInterface k : removeKeywordInterfaces) {
k.setHostCard(host);
}
}
public KeywordsChange copy(final Card host, final boolean lki) {
try {
KeywordsChange result = (KeywordsChange)super.clone();
result.keywords = new KeywordCollection();
for (KeywordInterface ki : this.keywords.getValues()) {
result.keywords.insert(ki.copy(host, lki));
}
result.removeKeywords = Lists.newArrayList(removeKeywords);
result.removeKeywordInterfaces = Lists.newArrayList();
for (KeywordInterface ki : this.removeKeywordInterfaces) {
removeKeywordInterfaces.add(ki.copy(host, lki));
}
return result;
} catch (final Exception ex) {
throw new RuntimeException("KeywordsChange : clone() error", ex);
}
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("<+");
sb.append(this.keywords);
sb.append("|-");
sb.append(this.removeKeywordInterfaces);
sb.append("|-");
sb.append(this.removeKeywords);
sb.append(">");
return sb.toString();
}
}
......@@ -76,7 +76,7 @@ public class ReplaceMoved extends ReplacementEffect {
return false;
}
if (zt.equals(ZoneType.Battlefield) && getHostCard().equals(affected)) {
if (zt.equals(ZoneType.Battlefield) && getHostCard().equals(affected) && !hasParam("BypassEtbCheck")) {
// would be an etb replacement effect that enters the battlefield
Card lki = CardUtil.getLKICopy(affected);
lki.setLastKnownZone(lki.getController().getZone(zt));
......
......@@ -1503,4 +1503,23 @@ public class GameSimulatorTest extends SimulationTestCase {
}
public void testRiotEnchantment() {
Game game = initAndCreateGame();
Player p = game.getPlayers().get(0);
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
addCard("Rhythm of the Wild", p);
Card goblin = addCardToZone("Zhur-Taa Goblin", p, ZoneType.Hand);
addCard("Mountain", p);
addCard("Forest", p);
SpellAbility goblinSA = goblin.getFirstSpellAbility();
assertNotNull(goblinSA);
GameSimulator sim = createSimulator(game, p);
int score = sim.simulateSpellAbility(goblinSA).value;
assertTrue(score > 0);
}
}
......@@ -69,7 +69,7 @@ public class InputSelectFromTwoLists<T extends GameEntity> extends InputSelectMa
if ( valid1.contains(s) ) { selected1 = true; }
if ( valid2.contains(s) ) { selected2 = true; }
}
validChoices = selected1 ? ( selected2 ? FCollection.getEmpty() : valid2 ) : ( selected2 ? valid1 : validBoth );
validChoices = selected1 ? ( selected2 ? FCollection.<T>getEmpty() : valid2 ) : ( selected2 ? valid1 : validBoth );
setSelectables();
FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override public void run() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment