forked from External/mage
implement [MH3] Nethergoyf, refactor targets usages by game param (#12267)
This commit is contained in:
parent
88b6f4036f
commit
754b382e78
62 changed files with 592 additions and 285 deletions
|
|
@ -67,7 +67,7 @@ public class CollectEvidenceCost extends CostImpl {
|
|||
// TODO: require target to have minimum selected total mana value (requires refactor)
|
||||
Target target = new TargetCardInYourGraveyard(1, Integer.MAX_VALUE) {
|
||||
@Override
|
||||
public String getMessage() {
|
||||
public String getMessage(Game game) {
|
||||
// shows selected mana value
|
||||
int totalMV = this
|
||||
.getTargets()
|
||||
|
|
@ -76,7 +76,7 @@ public class CollectEvidenceCost extends CostImpl {
|
|||
.filter(Objects::nonNull)
|
||||
.mapToInt(MageObject::getManaValue)
|
||||
.sum();
|
||||
return super.getMessage() + HintUtils.prepareText(
|
||||
return super.getMessage(game) + HintUtils.prepareText(
|
||||
" (selected mana value " + totalMV + " of " + amount + ")",
|
||||
totalMV >= amount ? Color.GREEN : Color.RED
|
||||
);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public class ExileTargetCost extends CostImpl {
|
|||
this.text = "exile " + target.getDescription();
|
||||
}
|
||||
|
||||
public ExileTargetCost(ExileTargetCost cost) {
|
||||
protected ExileTargetCost(ExileTargetCost cost) {
|
||||
super(cost);
|
||||
for (Permanent permanent : cost.permanents) {
|
||||
this.permanents.add(permanent.copy());
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ public class RollPlanarDieEffect extends OneShotEffect {
|
|||
}
|
||||
boolean done = false;
|
||||
while (controller.canRespond() && effect != null && !done) {
|
||||
if (target != null && !target.isChosen() && target.canChoose(controller.getId(), source, game)) {
|
||||
if (target != null && !target.isChosen(game) && target.canChoose(controller.getId(), source, game)) {
|
||||
controller.chooseTarget(Outcome.Benefit, target, source, game);
|
||||
source.addTarget(target);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ public class SacrificeAllEffect extends OneShotEffect {
|
|||
|
||||
/**
|
||||
* Each player sacrifices a permanent
|
||||
*
|
||||
* @param filter can be generic, will automatically add article and necessary sacrifice predicates
|
||||
*/
|
||||
public SacrificeAllEffect(FilterPermanent filter) {
|
||||
|
|
@ -35,6 +36,7 @@ public class SacrificeAllEffect extends OneShotEffect {
|
|||
|
||||
/**
|
||||
* Each player sacrifices N permanents
|
||||
*
|
||||
* @param filter can be generic, will automatically add necessary sacrifice predicates
|
||||
*/
|
||||
public SacrificeAllEffect(int amount, FilterPermanent filter) {
|
||||
|
|
@ -43,6 +45,7 @@ public class SacrificeAllEffect extends OneShotEffect {
|
|||
|
||||
/**
|
||||
* Each player sacrifices X permanents
|
||||
*
|
||||
* @param filter can be generic, will automatically add necessary sacrifice predicates
|
||||
*/
|
||||
public SacrificeAllEffect(DynamicValue amount, FilterPermanent filter) {
|
||||
|
|
@ -91,7 +94,7 @@ public class SacrificeAllEffect extends OneShotEffect {
|
|||
continue;
|
||||
}
|
||||
TargetSacrifice target = new TargetSacrifice(numTargets, filter);
|
||||
while (!target.isChosen() && target.canChoose(player.getId(), source, game) && player.canRespond()) {
|
||||
while (!target.isChosen(game) && target.canChoose(player.getId(), source, game) && player.canRespond()) {
|
||||
player.choose(Outcome.Sacrifice, target, source, game);
|
||||
}
|
||||
perms.addAll(target.getTargets());
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ public class SacrificeEffect extends OneShotEffect {
|
|||
continue;
|
||||
}
|
||||
TargetSacrifice target = new TargetSacrifice(amount, filter);
|
||||
while (!target.isChosen() && target.canChoose(player.getId(), source, game) && player.canRespond()) {
|
||||
while (!target.isChosen(game) && target.canChoose(player.getId(), source, game) && player.canRespond()) {
|
||||
player.choose(Outcome.Sacrifice, target, source, game);
|
||||
}
|
||||
for (UUID targetId : target.getTargets()) {
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ class CrewCost extends CostImpl {
|
|||
}
|
||||
Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true) {
|
||||
@Override
|
||||
public String getMessage() {
|
||||
public String getMessage(Game game) {
|
||||
// shows selected power
|
||||
int selectedPower = this.targets.keySet().stream()
|
||||
.map(game::getPermanent)
|
||||
|
|
@ -162,7 +162,7 @@ class CrewCost extends CostImpl {
|
|||
if (selectedPower >= value) {
|
||||
extraInfo = HintUtils.prepareText(extraInfo, Color.GREEN);
|
||||
}
|
||||
return super.getMessage() + " " + extraInfo;
|
||||
return super.getMessage(game) + " " + extraInfo;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -32,10 +32,14 @@ public class EscapeAbility extends SpellAbility {
|
|||
private final String staticText;
|
||||
|
||||
public EscapeAbility(Card card, String manaCost, int exileCount) {
|
||||
this(card, manaCost, exileCount, new CostsImpl<>());
|
||||
this(card, manaCost, new CostsImpl<>(), exileCount);
|
||||
}
|
||||
|
||||
public EscapeAbility(Card card, String manaCost, int exileCount, Costs<Cost> additionalCosts) {
|
||||
public EscapeAbility(Card card, String manaCost, Costs<Cost> additionalCost) {
|
||||
this(card, manaCost, additionalCost, 0);
|
||||
}
|
||||
|
||||
public EscapeAbility(Card card, String manaCost, Costs<Cost> additionalCosts, int exileCount) {
|
||||
super(card.getSpellAbility());
|
||||
this.newId();
|
||||
this.setCardName(card.getName() + " with Escape");
|
||||
|
|
@ -45,17 +49,22 @@ public class EscapeAbility extends SpellAbility {
|
|||
this.clearManaCosts();
|
||||
this.clearManaCostsToPay();
|
||||
|
||||
String text = "Escape—" + manaCost;
|
||||
this.addCost(new ManaCostsImpl<>(manaCost));
|
||||
for (Cost cost : additionalCosts) {
|
||||
text += ", " + CardUtil.getTextWithFirstCharUpperCase(cost.getText());
|
||||
this.addCost(cost.copy().setText("")); // hide additional cost text from rules
|
||||
}
|
||||
if (exileCount > 0) {
|
||||
this.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(exileCount, filter), "")); // hide additional cost text from rules
|
||||
}
|
||||
|
||||
text += ", Exile " + CardUtil.numberToText(exileCount) + " other cards from your graveyard."
|
||||
+ " <i>(You may cast this card from your graveyard for its escape cost.)</i>";
|
||||
this.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(exileCount, filter), "")); // hide additional cost text from rules
|
||||
|
||||
String text = "Escape—" + manaCost;
|
||||
for (Cost cost : additionalCosts) {
|
||||
text += ", " + CardUtil.getTextWithFirstCharUpperCase(cost.getText());
|
||||
}
|
||||
if (exileCount > 0) {
|
||||
text += ", Exile " + CardUtil.numberToText(exileCount) + " other cards from your graveyard";
|
||||
}
|
||||
text += ". <i>(You may cast this card from your graveyard for its escape cost.)</i>";
|
||||
this.staticText = text;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ class OfferingAsThoughEffect extends AsThoughEffectImpl {
|
|||
&& player.chooseUse(Outcome.Benefit, "Offer a " + filter.getMessage() + " to cast " + spellToCast.getName() + '?', source, game)) {
|
||||
Target target = new TargetSacrifice(filter);
|
||||
player.choose(Outcome.Sacrifice, target, source, game);
|
||||
if (!target.isChosen()) {
|
||||
if (!target.isChosen(game)) {
|
||||
return false;
|
||||
}
|
||||
game.getState().setValue("offering_" + card.getId(), true);
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ class SaddleCost extends CostImpl {
|
|||
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
|
||||
Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true) {
|
||||
@Override
|
||||
public String getMessage() {
|
||||
public String getMessage(Game game) {
|
||||
// shows selected power
|
||||
int selectedPower = this.targets.keySet().stream()
|
||||
.map(game::getPermanent)
|
||||
|
|
@ -125,7 +125,7 @@ class SaddleCost extends CostImpl {
|
|||
if (selectedPower >= value) {
|
||||
extraInfo = HintUtils.prepareText(extraInfo, Color.GREEN);
|
||||
}
|
||||
return super.getMessage() + " " + extraInfo;
|
||||
return super.getMessage(game) + " " + extraInfo;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4349,14 +4349,14 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
List<Ability> options = new ArrayList<>();
|
||||
if (ability.isModal()) {
|
||||
addModeOptions(options, ability, game);
|
||||
} else if (!ability.getTargets().getUnchosen().isEmpty()) {
|
||||
} else if (!ability.getTargets().getUnchosen(game).isEmpty()) {
|
||||
// TODO: Handle other variable costs than mana costs
|
||||
if (!ability.getManaCosts().getVariableCosts().isEmpty()) {
|
||||
addVariableXOptions(options, ability, 0, game);
|
||||
} else {
|
||||
addTargetOptions(options, ability, 0, game);
|
||||
}
|
||||
} else if (!ability.getCosts().getTargets().getUnchosen().isEmpty()) {
|
||||
} else if (!ability.getCosts().getTargets().getUnchosen(game).isEmpty()) {
|
||||
addCostTargetOptions(options, ability, 0, game);
|
||||
}
|
||||
|
||||
|
|
@ -4371,13 +4371,13 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
newOption.getModes().clearSelectedModes();
|
||||
newOption.getModes().addSelectedMode(mode.getId());
|
||||
newOption.getModes().setActiveMode(mode);
|
||||
if (!newOption.getTargets().getUnchosen().isEmpty()) {
|
||||
if (!newOption.getTargets().getUnchosen(game).isEmpty()) {
|
||||
if (!newOption.getManaCosts().getVariableCosts().isEmpty()) {
|
||||
addVariableXOptions(options, newOption, 0, game);
|
||||
} else {
|
||||
addTargetOptions(options, newOption, 0, game);
|
||||
}
|
||||
} else if (!newOption.getCosts().getTargets().getUnchosen().isEmpty()) {
|
||||
} else if (!newOption.getCosts().getTargets().getUnchosen(game).isEmpty()) {
|
||||
addCostTargetOptions(options, newOption, 0, game);
|
||||
} else {
|
||||
options.add(newOption);
|
||||
|
|
@ -4390,7 +4390,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
protected void addTargetOptions(List<Ability> options, Ability option, int targetNum, Game game) {
|
||||
for (Target target : option.getTargets().getUnchosen().get(targetNum).getTargetOptions(option, game)) {
|
||||
for (Target target : option.getTargets().getUnchosen(game).get(targetNum).getTargetOptions(option, game)) {
|
||||
Ability newOption = option.copy();
|
||||
if (target instanceof TargetAmount) {
|
||||
for (UUID targetId : target.getTargets()) {
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ import java.util.UUID;
|
|||
*/
|
||||
public interface Target extends Serializable {
|
||||
|
||||
boolean isChosen();
|
||||
boolean isChosen(Game game);
|
||||
|
||||
boolean doneChoosing();
|
||||
boolean doneChoosing(Game game);
|
||||
|
||||
void clearChosen();
|
||||
|
||||
|
|
@ -98,7 +98,10 @@ public interface Target extends Serializable {
|
|||
*/
|
||||
String getDescription();
|
||||
|
||||
String getMessage();
|
||||
/**
|
||||
* @return message displayed on choosing targets (can be dynamically changed on more target selected)
|
||||
*/
|
||||
String getMessage(Game game);
|
||||
|
||||
/**
|
||||
* @return single target name
|
||||
|
|
|
|||
|
|
@ -44,12 +44,12 @@ public abstract class TargetAmount extends TargetImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isChosen() {
|
||||
return doneChoosing();
|
||||
public boolean isChosen(Game game) {
|
||||
return doneChoosing(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doneChoosing() {
|
||||
public boolean doneChoosing(Game game) {
|
||||
return amountWasSet
|
||||
&& (remainingAmount == 0
|
||||
|| (getMinNumberOfTargets() < getMaxNumberOfTargets()
|
||||
|
|
@ -104,7 +104,7 @@ public abstract class TargetAmount extends TargetImpl {
|
|||
if (!amountWasSet) {
|
||||
setAmount(source, game);
|
||||
}
|
||||
chosen = isChosen();
|
||||
chosen = isChosen(game);
|
||||
while (remainingAmount > 0) {
|
||||
if (!player.canRespond()) {
|
||||
return chosen;
|
||||
|
|
@ -112,7 +112,7 @@ public abstract class TargetAmount extends TargetImpl {
|
|||
if (!getTargetController(game, playerId).chooseTargetAmount(outcome, this, source, game)) {
|
||||
return chosen;
|
||||
}
|
||||
chosen = isChosen();
|
||||
chosen = isChosen(game);
|
||||
}
|
||||
return chosen;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ public abstract class TargetImpl implements Target {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
public String getMessage(Game game) {
|
||||
// UI choose message
|
||||
String suffix = "";
|
||||
if (this.chooseHint != null) {
|
||||
|
|
@ -215,7 +215,7 @@ public abstract class TargetImpl implements Target {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isChosen() {
|
||||
public boolean isChosen(Game game) {
|
||||
if (getMaxNumberOfTargets() == 0 && getNumberOfTargets() == 0) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -223,7 +223,7 @@ public abstract class TargetImpl implements Target {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean doneChoosing() {
|
||||
public boolean doneChoosing(Game game) {
|
||||
return getMaxNumberOfTargets() != 0 && targets.size() == getMaxNumberOfTargets();
|
||||
}
|
||||
|
||||
|
|
@ -332,7 +332,7 @@ public abstract class TargetImpl implements Target {
|
|||
return chosen;
|
||||
}
|
||||
chosen = targets.size() >= getNumberOfTargets();
|
||||
} while (!isChosen() && !doneChoosing());
|
||||
} while (!isChosen(game) && !doneChoosing(game));
|
||||
return chosen;
|
||||
}
|
||||
|
||||
|
|
@ -375,7 +375,7 @@ public abstract class TargetImpl implements Target {
|
|||
}
|
||||
}
|
||||
chosen = targets.size() >= getNumberOfTargets();
|
||||
} while (!isChosen() && !doneChoosing());
|
||||
} while (!isChosen(game) && !doneChoosing(game));
|
||||
|
||||
return chosen;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ public class Targets extends ArrayList<Target> implements Copyable<Targets> {
|
|||
return this;
|
||||
}
|
||||
|
||||
public List<Target> getUnchosen() {
|
||||
return stream().filter(target -> !target.isChosen()).collect(Collectors.toList());
|
||||
public List<Target> getUnchosen(Game game) {
|
||||
return stream().filter(target -> !target.isChosen(game)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public void clearChosen() {
|
||||
|
|
@ -47,8 +47,8 @@ public class Targets extends ArrayList<Target> implements Copyable<Targets> {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean isChosen() {
|
||||
return stream().allMatch(Target::isChosen);
|
||||
public boolean isChosen(Game game) {
|
||||
return stream().allMatch(t -> t.isChosen(game));
|
||||
}
|
||||
|
||||
public boolean choose(Outcome outcome, UUID playerId, UUID sourceId, Ability source, Game game) {
|
||||
|
|
@ -56,8 +56,8 @@ public class Targets extends ArrayList<Target> implements Copyable<Targets> {
|
|||
if (!canChoose(playerId, source, game)) {
|
||||
return false;
|
||||
}
|
||||
while (!isChosen()) {
|
||||
Target target = this.getUnchosen().get(0);
|
||||
while (!isChosen(game)) {
|
||||
Target target = this.getUnchosen(game).get(0);
|
||||
if (!target.choose(outcome, playerId, sourceId, source, game)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -73,8 +73,8 @@ public class Targets extends ArrayList<Target> implements Copyable<Targets> {
|
|||
}
|
||||
|
||||
//int state = game.bookmarkState();
|
||||
while (!isChosen()) {
|
||||
Target target = this.getUnchosen().get(0);
|
||||
while (!isChosen(game)) {
|
||||
Target target = this.getUnchosen(game).get(0);
|
||||
UUID targetController = playerId;
|
||||
|
||||
// some targets can have controller different than ability controller
|
||||
|
|
@ -97,7 +97,7 @@ public class Targets extends ArrayList<Target> implements Copyable<Targets> {
|
|||
return false;
|
||||
}
|
||||
// Check if there are some rules for targets are violated, if so reset the targets and start again
|
||||
if (this.getUnchosen().isEmpty()
|
||||
if (this.getUnchosen(game).isEmpty()
|
||||
&& game.replaceEvent(new GameEvent(GameEvent.EventType.TARGETS_VALID, source.getSourceId(), source, source.getControllerId()), source)) {
|
||||
//game.restoreState(state, "Targets");
|
||||
clearChosen();
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ public class TargetCardInLibrary extends TargetCard {
|
|||
return chosen;
|
||||
}
|
||||
chosen = targets.size() >= getMinNumberOfTargets();
|
||||
} while (!isChosen() && !doneChoosing());
|
||||
} while (!isChosen(game) && !doneChoosing(game));
|
||||
return chosen;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue