mirror of
https://github.com/magefree/mage.git
synced 2026-01-26 21:29:17 -08:00
Refactor CreateTokenEffect to allow multiple tokens at once. (#12704)
* Refactor CreateTokenEffect to allow multiple tokens at once. Partial solution to #10811 - Token copy effects still need to be redone so that mass token copy effects (Ocelot Pride, Mirror Match, other similar effects) can be created in a single batch.
This commit is contained in:
parent
da48821754
commit
543f9f074e
26 changed files with 132 additions and 154 deletions
|
|
@ -16,6 +16,7 @@ import mage.target.targetpointer.FixedTarget;
|
|||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -24,7 +25,7 @@ import java.util.UUID;
|
|||
*/
|
||||
public class CreateTokenEffect extends OneShotEffect {
|
||||
|
||||
private final Token token;
|
||||
private final List<Token> tokens = new ArrayList<>();
|
||||
private final DynamicValue amount;
|
||||
private final boolean tapped;
|
||||
private final boolean attacking;
|
||||
|
|
@ -56,7 +57,10 @@ public class CreateTokenEffect extends OneShotEffect {
|
|||
|
||||
public CreateTokenEffect(Token token, DynamicValue amount, boolean tapped, boolean attacking) {
|
||||
super(Outcome.PutCreatureInPlay);
|
||||
this.token = token;
|
||||
if (token == null) {
|
||||
throw new IllegalArgumentException("Wrong code usage. Token provided to CreateTokenEffect must not be null.");
|
||||
}
|
||||
this.tokens.add(token);
|
||||
this.amount = amount.copy();
|
||||
this.tapped = tapped;
|
||||
this.attacking = attacking;
|
||||
|
|
@ -66,7 +70,9 @@ public class CreateTokenEffect extends OneShotEffect {
|
|||
protected CreateTokenEffect(final CreateTokenEffect effect) {
|
||||
super(effect);
|
||||
this.amount = effect.amount.copy();
|
||||
this.token = effect.token.copy();
|
||||
for (Token token : effect.tokens) {
|
||||
this.tokens.add(token.copy());
|
||||
}
|
||||
this.tapped = effect.tapped;
|
||||
this.attacking = effect.attacking;
|
||||
this.lastAddedTokenIds.addAll(effect.lastAddedTokenIds);
|
||||
|
|
@ -82,6 +88,11 @@ public class CreateTokenEffect extends OneShotEffect {
|
|||
return this;
|
||||
}
|
||||
|
||||
public CreateTokenEffect withAdditionalTokens(Token... tokens) {
|
||||
this.tokens.addAll(Arrays.asList(tokens));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreateTokenEffect copy() {
|
||||
return new CreateTokenEffect(this);
|
||||
|
|
@ -90,8 +101,8 @@ public class CreateTokenEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
int value = amount.calculate(game, source, this);
|
||||
token.putOntoBattlefield(value, game, source, source.getControllerId(), tapped, attacking);
|
||||
this.lastAddedTokenIds = token.getLastAddedTokenIds();
|
||||
tokens.get(0).putOntoBattlefield(value, game, source, source.getControllerId(), tapped, attacking, null, null, true, tokens);
|
||||
this.lastAddedTokenIds = tokens.get(0).getLastAddedTokenIds();
|
||||
// TODO: Workaround to add counters to all created tokens, necessary for correct interactions with cards like Chatterfang, Squirrel General and Ochre Jelly / Printlifter Ooze. See #10786
|
||||
if (counterType != null) {
|
||||
for (UUID tokenId : lastAddedTokenIds) {
|
||||
|
|
@ -150,41 +161,53 @@ public class CreateTokenEffect extends OneShotEffect {
|
|||
}
|
||||
|
||||
private void setText() {
|
||||
String tokenDescription = token.getDescription();
|
||||
boolean singular = amount.toString().equals("1");
|
||||
if (tokenDescription.contains(", a legendary")) {
|
||||
staticText = "create " + tokenDescription;
|
||||
return;
|
||||
}
|
||||
if (oldPhrasing) {
|
||||
tokenDescription = tokenDescription.replace("token with \"",
|
||||
singular ? "token. It has \"" : "tokens. They have \"");
|
||||
}
|
||||
StringBuilder sb = new StringBuilder("create ");
|
||||
if (singular) {
|
||||
if (tapped && !attacking) {
|
||||
sb.append("a tapped ");
|
||||
for (int i = 0; i < tokens.size(); i++) {
|
||||
if (i > 0) {
|
||||
if (tokens.size() > 2) {
|
||||
sb.append(", ");
|
||||
} else {
|
||||
sb.append(" ");
|
||||
}
|
||||
if (i+1 == tokens.size()) {
|
||||
sb.append("and ");
|
||||
}
|
||||
}
|
||||
String tokenDescription = tokens.get(i).getDescription();
|
||||
if (tokenDescription.contains(", a legendary")) {
|
||||
sb.append(tokenDescription);
|
||||
continue;
|
||||
}
|
||||
if (oldPhrasing) {
|
||||
tokenDescription = tokenDescription.replace("token with \"",
|
||||
singular ? "token. It has \"" : "tokens. They have \"");
|
||||
}
|
||||
if (singular) {
|
||||
if (tapped && !attacking) {
|
||||
sb.append("a tapped ");
|
||||
sb.append(tokenDescription);
|
||||
} else {
|
||||
sb.append(CardUtil.addArticle(tokenDescription));
|
||||
}
|
||||
} else {
|
||||
sb.append(CardUtil.addArticle(tokenDescription));
|
||||
}
|
||||
} else {
|
||||
sb.append(CardUtil.numberToText(amount.toString())).append(' ');
|
||||
if (tapped && !attacking) {
|
||||
sb.append("tapped ");
|
||||
}
|
||||
sb.append(tokenDescription);
|
||||
if (tokenDescription.endsWith("token")) {
|
||||
sb.append("s");
|
||||
}
|
||||
int tokenLocation = sb.indexOf("token ");
|
||||
if (tokenLocation != -1) {
|
||||
sb.replace(tokenLocation, tokenLocation + 6, "tokens ");
|
||||
sb.append(CardUtil.numberToText(amount.toString())).append(' ');
|
||||
if (tapped && !attacking) {
|
||||
sb.append("tapped ");
|
||||
}
|
||||
sb.append(tokenDescription);
|
||||
if (tokenDescription.endsWith("token")) {
|
||||
sb.append("s");
|
||||
}
|
||||
int tokenLocation = sb.indexOf("token ");
|
||||
if (tokenLocation != -1) {
|
||||
sb.replace(tokenLocation, tokenLocation + 6, "tokens ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (attacking) {
|
||||
if (singular) {
|
||||
if (singular && tokens.size() == 1) {
|
||||
sb.append(" that's");
|
||||
} else {
|
||||
sb.append(" that are");
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import mage.abilities.Ability;
|
|||
import mage.game.permanent.token.Token;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -17,11 +18,15 @@ public class CreateTokenEvent extends GameEvent {
|
|||
* @param source
|
||||
* @param controllerId
|
||||
* @param amount
|
||||
* @param token
|
||||
* @param tokensList
|
||||
*/
|
||||
public CreateTokenEvent(Ability source, UUID controllerId, int amount, Token token) {
|
||||
public CreateTokenEvent(Ability source, UUID controllerId, int amount, List<Token> tokensList) {
|
||||
super(GameEvent.EventType.CREATE_TOKEN, null, source, controllerId, amount, false);
|
||||
tokens.put(token, amount);
|
||||
if (tokensList != null) {
|
||||
for (Token token : tokensList) {
|
||||
tokens.put(token, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Map<Token, Integer> getTokens() {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ public interface Token extends MageObject {
|
|||
|
||||
boolean putOntoBattlefield(int amount, Game game, Ability source, UUID controllerId, boolean tapped, boolean attacking, UUID attackedPlayer, UUID attachedTo, boolean created);
|
||||
|
||||
boolean putOntoBattlefield(int amount, Game game, Ability source, UUID controllerId, boolean tapped, boolean attacking, UUID attackedPlayer, UUID attachedTo, boolean created, List<Token> additionalTokens);
|
||||
|
||||
void setPower(int power);
|
||||
|
||||
void setToughness(int toughness);
|
||||
|
|
|
|||
|
|
@ -218,8 +218,12 @@ public abstract class TokenImpl extends MageObjectImpl implements Token {
|
|||
return putOntoBattlefield(amount, game, source, controllerId, tapped, attacking, attackedPlayer, attachedTo, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putOntoBattlefield(int amount, Game game, Ability source, UUID controllerId, boolean tapped, boolean attacking, UUID attackedPlayer, UUID attachedTo, boolean created) {
|
||||
return putOntoBattlefield(amount, game, source, controllerId, tapped, attacking, attackedPlayer, attachedTo, created, Collections.singletonList(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putOntoBattlefield(int amount, Game game, Ability source, UUID controllerId, boolean tapped, boolean attacking, UUID attackedPlayer, UUID attachedTo, boolean created, List<Token> tokens) {
|
||||
Player controller = game.getPlayer(controllerId);
|
||||
if (controller == null) {
|
||||
return false;
|
||||
|
|
@ -229,7 +233,11 @@ public abstract class TokenImpl extends MageObjectImpl implements Token {
|
|||
}
|
||||
lastAddedTokenIds.clear();
|
||||
|
||||
CreateTokenEvent event = new CreateTokenEvent(source, controllerId, amount, this);
|
||||
if (tokens == null || tokens.get(0) != this) {
|
||||
throw new IllegalArgumentException("Wrong code usage. token.putOntoBattlefield parameter tokens must be initialized to a list of all tokens to be made, with the first element being the token you are calling putOntoBattlefield() on.");
|
||||
}
|
||||
|
||||
CreateTokenEvent event = new CreateTokenEvent(source, controllerId, amount, tokens);
|
||||
if (!created || !game.replaceEvent(event)) {
|
||||
int currentTokens = game.getBattlefield().countTokens(event.getPlayerId());
|
||||
int tokenSlots = Math.max(MAX_TOKENS_PER_GAME - currentTokens, 0);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue