Refactor TokenEffect to be easier to add in TokenScripts

This commit is contained in:
Chris H
2017-12-30 21:55:20 -05:00
committed by tehdiplomat
parent 74d9791f03
commit d374da0481
2 changed files with 196 additions and 182 deletions

View File

@@ -18,10 +18,12 @@
package forge.game.ability.effects; package forge.game.ability.effects;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import forge.card.MagicColor;
import forge.game.card.token.TokenInfo; import forge.game.card.token.TokenInfo;
import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@@ -184,6 +186,7 @@ public class TokenEffect extends SpellAbilityEffect {
@Override @Override
public void resolve(SpellAbility sa) { public void resolve(SpellAbility sa) {
final Card host = sa.getHostCard(); final Card host = sa.getHostCard();
final Game game = host.getGame();
final SpellAbility root = sa.getRootAbility(); final SpellAbility root = sa.getRootAbility();
readParameters(sa); readParameters(sa);
@@ -194,30 +197,11 @@ public class TokenEffect extends SpellAbilityEffect {
cause = (SpellAbility)root.getReplacingObject("Cause"); cause = (SpellAbility)root.getReplacingObject("Cause");
} }
String cost = ""; String originalColorDesc = parseColorForImage();
// Construct original colors
String originalColorDesc = "";
for (final String col : this.tokenOriginalColors) {
if (col.equalsIgnoreCase("White")) {
originalColorDesc += "W ";
} else if (col.equalsIgnoreCase("Blue")) {
originalColorDesc += "U ";
} else if (col.equalsIgnoreCase("Black")) {
originalColorDesc += "B ";
} else if (col.equalsIgnoreCase("Red")) {
originalColorDesc += "R ";
} else if (col.equalsIgnoreCase("Green")) {
originalColorDesc += "G ";
} else if (col.equalsIgnoreCase("Colorless")) {
originalColorDesc = "C";
}
}
final List<String> imageNames = Lists.newArrayListWithCapacity(1); final List<String> imageNames = Lists.newArrayListWithCapacity(1);
if (this.tokenImage.equals("")) { if (this.tokenImage.equals("")) {
imageNames.add(PaperToken.makeTokenFileName(TextUtil.fastReplace(originalColorDesc, imageNames.add(PaperToken.makeTokenFileName(originalColorDesc, tokenPower, tokenToughness, tokenOriginalName));
" ", ""), tokenPower, tokenToughness, tokenOriginalName));
} else { } else {
imageNames.add(0, this.tokenImage); imageNames.add(0, this.tokenImage);
} }
@@ -225,34 +209,7 @@ public class TokenEffect extends SpellAbilityEffect {
imageNames.addAll(Arrays.asList(this.tokenAltImages)); imageNames.addAll(Arrays.asList(this.tokenAltImages));
} }
final String[] substitutedColors = Arrays.copyOf(this.tokenColors, this.tokenColors.length); String cost = determineTokenColor(host);
for (int i = 0; i < substitutedColors.length; i++) {
if (substitutedColors[i].equals("ChosenColor")) {
// this currently only supports 1 chosen color
substitutedColors[i] = host.getChosenColor();
}
}
String colorDesc = "";
for (final String col : substitutedColors) {
if (col.equalsIgnoreCase("White")) {
colorDesc += "W ";
} else if (col.equalsIgnoreCase("Blue")) {
colorDesc += "U ";
} else if (col.equalsIgnoreCase("Black")) {
colorDesc += "B ";
} else if (col.equalsIgnoreCase("Red")) {
colorDesc += "R ";
} else if (col.equalsIgnoreCase("Green")) {
colorDesc += "G ";
} else if (col.equalsIgnoreCase("Colorless")) {
colorDesc = "C";
}
}
for (final char c : colorDesc.toCharArray()) {
cost += c + ' ';
}
cost = colorDesc.replace('C', '1').trim();
final int finalPower = AbilityUtils.calculateAmount(host, this.tokenPower, sa); final int finalPower = AbilityUtils.calculateAmount(host, this.tokenPower, sa);
final int finalToughness = AbilityUtils.calculateAmount(host, this.tokenToughness, sa); final int finalToughness = AbilityUtils.calculateAmount(host, this.tokenToughness, sa);
@@ -269,117 +226,39 @@ public class TokenEffect extends SpellAbilityEffect {
final boolean remember = sa.hasParam("RememberTokens"); final boolean remember = sa.hasParam("RememberTokens");
final boolean imprint = sa.hasParam("ImprintTokens"); final boolean imprint = sa.hasParam("ImprintTokens");
final List<Card> allTokens = Lists.newArrayList(); final List<Card> allTokens = Lists.newArrayList();
boolean combatChanged = false;
boolean inCombat = game.getPhaseHandler().inCombat();
for (final Player controller : AbilityUtils.getDefinedPlayers(host, this.tokenOwner, sa)) { for (final Player controller : AbilityUtils.getDefinedPlayers(host, this.tokenOwner, sa)) {
final Game game = controller.getGame();
for (int i = 0; i < finalAmount; i++) {
final String imageName = imageNames.get(MyRandom.getRandom().nextInt(imageNames.size())); final String imageName = imageNames.get(MyRandom.getRandom().nextInt(imageNames.size()));
final TokenInfo tokenInfo = new TokenInfo(substitutedName, imageName, final TokenInfo tokenInfo = new TokenInfo(substitutedName, imageName,
cost, substitutedTypes, this.tokenKeywords, finalPower, finalToughness); cost, substitutedTypes, this.tokenKeywords, finalPower, finalToughness);
final List<Card> tokens = tokenInfo.makeTokenWithMultiplier(controller, cause != null); final List<Card> tokens = tokenInfo.makeTokenWithMultiplier(controller, finalAmount, cause != null);
// Grant rule changes grantHiddenKeywords(tokens);
if (this.tokenHiddenKeywords != null) { grantAbilities(tokens, root);
for (final String s : this.tokenHiddenKeywords) { grantTriggers(tokens, root);
for (final Card c : tokens) { grantSvars(tokens, root);
c.addHiddenExtrinsicKeyword(s); grantStatics(tokens, root);
}
}
}
// Grant SVars
if (this.tokenSVars != null) {
for (final String s : this.tokenSVars) {
String actualSVar = AbilityUtils.getSVar(root, s);
String name = s;
if (actualSVar.startsWith("SVar")) {
actualSVar = actualSVar.split("SVar:")[1];
name = actualSVar.split(":")[0];
actualSVar = actualSVar.split(":")[1];
}
for (final Card c : tokens) {
c.setSVar(name, actualSVar);
}
}
}
// Grant abilities
if (this.tokenAbilities != null) {
for (final String s : this.tokenAbilities) {
final String actualAbility = AbilityUtils.getSVar(root, s);
for (final Card c : tokens) {
final SpellAbility grantedAbility = AbilityFactory.getAbility(actualAbility, c);
// Set intrinsic, so that effects like Clone will copy these.
grantedAbility.setIntrinsic(true);
c.addSpellAbility(grantedAbility);
}
}
}
// Grant triggers
if (this.tokenTriggers != null) {
for (final String s : this.tokenTriggers) {
final String actualTrigger = AbilityUtils.getSVar(root, s);
for (final Card c : tokens) {
final Trigger parsedTrigger = TriggerHandler.parseTrigger(actualTrigger, c, true);
final String ability = AbilityUtils.getSVar(root, parsedTrigger.getMapParams().get("Execute"));
parsedTrigger.setOverridingAbility(AbilityFactory.getAbility(ability, c));
c.addTrigger(parsedTrigger);
}
}
}
// Grant static abilities
if (this.tokenStaticAbilities != null) {
for (final String s : this.tokenStaticAbilities) {
final String actualAbility = AbilityUtils.getSVar(root, s);
for (final Card c : tokens) {
c.addStaticAbility(actualAbility);
}
}
}
for (Card tok : tokens) { for (Card tok : tokens) {
if (this.tokenTapped) { if (this.tokenTapped) {
tok.setTapped(true); tok.setTapped(true);
} }
game.getAction().moveToPlay(tok, sa); // Should this be catching the Card that's returned?
} Card c = game.getAction().moveToPlay(tok, sa);
game.fireEvent(new GameEventTokenCreated());
boolean combatChanged = false;
for (final Card c : tokens) {
if (sa.hasParam("AtEOTTrig")) { if (sa.hasParam("AtEOTTrig")) {
addSelfTrigger(sa, sa.getParam("AtEOTTrig"), c); addSelfTrigger(sa, sa.getParam("AtEOTTrig"), c);
} }
// To show the Abilities and Trigger on the Token
if (inCombat) {
combatChanged = addTokenToCombat(game, c, controller, sa, host) || combatChanged;
}
c.updateStateForView(); c.updateStateForView();
if (this.tokenAttacking && game.getPhaseHandler().inCombat()) {
final Combat combat = game.getCombat();
// into battlefield attacking only should work if you are the attacking player
if (combat.getAttackingPlayer().equals(controller)) {
final FCollectionView<GameEntity> defs = combat.getDefenders();
final GameEntity defender = controller.getController().chooseSingleEntityForEffect(defs, sa, "Choose which defender to attack with " + c, false);
combat.addAttacker(c, defender);
combatChanged = true;
}
}
if (this.tokenBlocking != null && game.getPhaseHandler().inCombat()) {
final Combat combat = game.getPhaseHandler().getCombat();
final Card attacker = Iterables.getFirst(AbilityUtils.getDefinedCards(host, this.tokenBlocking, sa), null);
if (attacker != null) {
final boolean wasBlocked = combat.isBlocked(attacker);
combat.addBlocker(attacker, c);
combat.orderAttackersForDamageAssignment(c);
// Run triggers for new blocker and add it to damage assignment order
if (!wasBlocked) {
combat.setBlocked(attacker, true);
combat.addBlockerToDamageAssignmentOrder(attacker, c);
}
combatChanged = true;
}
}
if (remember) { if (remember) {
game.getCardState(sa.getHostCard()).addRemembered(c); game.getCardState(sa.getHostCard()).addRemembered(c);
} }
@@ -396,19 +275,154 @@ public class TokenEffect extends SpellAbilityEffect {
token.addRemembered(o); token.addRemembered(o);
} }
} }
allTokens.add(c);
} }
if (tokenName.equals("Clue")) { // investigate trigger if (tokenName.equals("Clue")) { // investigate trigger
controller.addInvestigatedThisTurn(); controller.addInvestigatedThisTurn();
} }
}
game.fireEvent(new GameEventTokenCreated());
if (combatChanged) { if (combatChanged) {
game.updateCombatForView(); game.updateCombatForView();
game.fireEvent(new GameEventCombatChanged()); game.fireEvent(new GameEventCombatChanged());
} }
allTokens.addAll(tokens);
}
}
if (sa.hasParam("AtEOT")) { if (sa.hasParam("AtEOT")) {
registerDelayedTrigger(sa, sa.getParam("AtEOT"), allTokens); registerDelayedTrigger(sa, sa.getParam("AtEOT"), allTokens);
} }
} }
private String parseColorForImage() {
String originalColorDesc = "";
for (final String col : this.tokenOriginalColors) {
originalColorDesc += MagicColor.toShortString(col);
if (originalColorDesc.equals("C")) {
return originalColorDesc;
}
}
return originalColorDesc;
}
private String determineTokenColor(Card host) {
Set<String> colorSet = new HashSet<>();
final String[] substitutedColors = Arrays.copyOf(this.tokenColors, this.tokenColors.length);
for (int i = 0; i < substitutedColors.length; i++) {
if (substitutedColors[i].equals("ChosenColor")) {
// this currently only supports 1 chosen color
substitutedColors[i] = host.getChosenColor();
}
}
StringBuilder sb = new StringBuilder();
for (final String col : substitutedColors) {
String str = MagicColor.toShortString(col);
if (str.equals("C")) {
return "1";
}
sb.append(str).append(" ");
}
return sb.toString().trim();
}
private void grantHiddenKeywords(List<Card> tokens) {
// Grant rule changes
if (this.tokenHiddenKeywords != null) {
for (final String s : this.tokenHiddenKeywords) {
for (final Card c : tokens) {
c.addHiddenExtrinsicKeyword(s);
}
}
}
}
private void grantAbilities(List<Card> tokens, SpellAbility root) {
if (this.tokenAbilities != null) {
for (final String s : this.tokenAbilities) {
final String actualAbility = AbilityUtils.getSVar(root, s);
for (final Card c : tokens) {
final SpellAbility grantedAbility = AbilityFactory.getAbility(actualAbility, c);
// Set intrinsic, so that effects like Clone will copy these.
grantedAbility.setIntrinsic(true);
c.addSpellAbility(grantedAbility);
}
}
}
}
private void grantTriggers(List<Card> tokens, SpellAbility root) {
if (this.tokenTriggers != null) {
for (final String s : this.tokenTriggers) {
final String actualTrigger = AbilityUtils.getSVar(root, s);
for (final Card c : tokens) {
final Trigger parsedTrigger = TriggerHandler.parseTrigger(actualTrigger, c, true);
final String ability = AbilityUtils.getSVar(root, parsedTrigger.getMapParams().get("Execute"));
parsedTrigger.setOverridingAbility(AbilityFactory.getAbility(ability, c));
c.addTrigger(parsedTrigger);
}
}
}
}
private void grantSvars(List<Card> tokens, SpellAbility root) {
if (this.tokenSVars != null) {
for (final String s : this.tokenSVars) {
String actualSVar = AbilityUtils.getSVar(root, s);
String name = s;
if (actualSVar.startsWith("SVar")) {
actualSVar = actualSVar.split("SVar:")[1];
name = actualSVar.split(":")[0];
actualSVar = actualSVar.split(":")[1];
}
for (final Card c : tokens) {
c.setSVar(name, actualSVar);
}
}
}
}
private void grantStatics(List<Card> tokens, SpellAbility root) {
if (this.tokenStaticAbilities != null) {
for (final String s : this.tokenStaticAbilities) {
final String actualAbility = AbilityUtils.getSVar(root, s);
for (final Card c : tokens) {
c.addStaticAbility(actualAbility);
}
}
}
}
private boolean addTokenToCombat(Game game, Card c, Player controller, SpellAbility sa, Card host) {
boolean combatChanged = false;
if (this.tokenAttacking) {
final Combat combat = game.getCombat();
// into battlefield attacking only should work if you are the attacking player
if (combat.getAttackingPlayer().equals(controller)) {
final FCollectionView<GameEntity> defs = combat.getDefenders();
final GameEntity defender = controller.getController().chooseSingleEntityForEffect(defs, sa, "Choose which defender to attack with " + c, false);
combat.addAttacker(c, defender);
combatChanged = true;
}
}
if (this.tokenBlocking != null) {
final Combat combat = game.getPhaseHandler().getCombat();
final Card attacker = Iterables.getFirst(AbilityUtils.getDefinedCards(host, this.tokenBlocking, sa), null);
if (attacker != null) {
final boolean wasBlocked = combat.isBlocked(attacker);
combat.addBlocker(attacker, c);
combat.orderAttackersForDamageAssignment(c);
// Run triggers for new blocker and add it to damage assignment order
if (!wasBlocked) {
combat.setBlocked(attacker, true);
combat.addBlockerToDamageAssignmentOrder(attacker, c);
}
combatChanged = true;
}
}
return combatChanged;
}
} }

View File

@@ -133,7 +133,7 @@ public class TokenInfo {
return sb.toString(); return sb.toString();
} }
public List<Card> makeTokenWithMultiplier(final Player controller, final boolean applyMultiplier) { public List<Card> makeTokenWithMultiplier(final Player controller, int amount, final boolean applyMultiplier) {
final List<Card> list = Lists.newArrayList(); final List<Card> list = Lists.newArrayList();
final Game game = controller.getGame(); final Game game = controller.getGame();
@@ -158,8 +158,8 @@ public class TokenInfo {
return list; return list;
} }
for (int i = 0; i < multiplier; i++) { for (int i = 0; i < multiplier * amount; i++) {
list.add(makeOneToken(player)); list.add(makeOneToken(controller));
} }
return list; return list;
} }