* K'rrik, Son of Yawgmoth - Fixe phyrexian mana like payment of mana costs (closes #6928 related to #6698).

This commit is contained in:
LevelX2 2020-08-03 19:17:07 +02:00
parent e9999de931
commit 244cf2a1e9
7 changed files with 160 additions and 70 deletions

View file

@ -120,7 +120,7 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
}
Player player = game.getPlayer(controllerId);
handleKrrikPhyrexianManaCosts(controllerId, ability, game);
handleLikePhyrexianManaCosts(controllerId, ability, game); // e.g. K'rrik, Son of Yawgmoth
if (!player.getManaPool().isForcedToPay()) {
assignPayment(game, ability, player.getManaPool(), this);
}
@ -170,11 +170,6 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
while (manaCostIterator.hasNext()) {
ManaCost manaCost = manaCostIterator.next();
PhyrexianManaCost tempPhyrexianCost = null;
Mana mana = manaCost.getMana();
FilterMana phyrexianColors = player.getPhyrexianColors();
if (manaCost instanceof PhyrexianManaCost) {
PhyrexianManaCost phyrexianManaCost = (PhyrexianManaCost) manaCost;
PayLifeCost payLifeCost = new PayLifeCost(2);
@ -189,7 +184,7 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
tempCosts.pay(source, game, source.getSourceId(), player.getId(), false, null);
}
private void handleKrrikPhyrexianManaCosts(UUID payingPlayerId, Ability source, Game game) {
private void handleLikePhyrexianManaCosts(UUID payingPlayerId, Ability source, Game game) {
Player player = game.getPlayer(payingPlayerId);
if (this == null || player == null) {
return; // nothing to be done without any mana costs. prevents NRE from occurring here

View file

@ -932,10 +932,16 @@ public interface Player extends MageItem, Copyable<Player> {
List<Designation> getDesignations();
/**
* Set the mana colors the user can pay with 2 life instead
* @param colors
*/
void addPhyrexianToColors(FilterMana colors);
void removePhyrexianFromColors(FilterMana colors);
/**
* Mana colors the player can pay instead with 2 life
* @return
*/
FilterMana getPhyrexianColors();
}

View file

@ -174,6 +174,7 @@ public abstract class PlayerImpl implements Player, Serializable {
protected List<Designation> designations = new ArrayList<>();
// mana colors the player can handle like Phyrexian mana
protected FilterMana phyrexianColors;
// Used during available mana calculation to give back possible available net mana from triggered mana abilities (No need to copy)
@ -196,7 +197,7 @@ public abstract class PlayerImpl implements Player, Serializable {
manaPool = new ManaPool(playerId);
library = new Library(playerId);
sideboard = new CardsImpl();
phyrexianColors = new FilterMana();
phyrexianColors = null;
}
protected PlayerImpl(UUID id) {
@ -279,8 +280,7 @@ public abstract class PlayerImpl implements Player, Serializable {
this.castSourceIdCosts.putAll(player.castSourceIdCosts);
this.payManaMode = player.payManaMode;
this.phyrexianColors = player.phyrexianColors.copy();
this.phyrexianColors = player.getPhyrexianColors() != null ? player.phyrexianColors.copy() : null;
this.designations.addAll(player.designations);
}
@ -357,8 +357,8 @@ public abstract class PlayerImpl implements Player, Serializable {
for (Entry<UUID, Costs<Cost>> entry : player.getCastSourceIdCosts().entrySet()) {
this.castSourceIdCosts.put(entry.getKey(), entry.getValue().copy());
}
this.phyrexianColors = player.getPhyrexianColors().copy();
this.phyrexianColors = player.getPhyrexianColors() != null ? player.getPhyrexianColors().copy() : null;
this.designations.clear();
this.designations.addAll(player.getDesignations());
@ -434,7 +434,7 @@ public abstract class PlayerImpl implements Player, Serializable {
this.clearCastSourceIdManaCosts();
this.getManaPool().init(); // needed to remove mana that not empties on step change from previous game if left
this.phyrexianColors = new FilterMana();
this.phyrexianColors = null;
this.designations.clear();
}
@ -459,7 +459,7 @@ public abstract class PlayerImpl implements Player, Serializable {
this.alternativeSourceCosts.clear();
this.clearCastSourceIdManaCosts();
this.getManaPool().clearEmptyManaPoolRules();
this.phyrexianColors = new FilterMana();
this.phyrexianColors = null;
}
@Override
@ -3115,6 +3115,11 @@ public abstract class PlayerImpl implements Player, Serializable {
if (availableMana == null) {
return true;
}
// Check for pay option with like phyrexian mana
if (getPhyrexianColors() != null) {
addPhyrexianLikePayOptions(abilityOptions, availableMana, game);
}
MageObjectReference permittingObject = game.getContinuousEffects().asThough(ability.getSourceId(),
AsThoughEffectType.SPEND_OTHER_MANA, ability, ability.getControllerId(), game);
for (Mana mana : abilityOptions) {
@ -3137,6 +3142,49 @@ public abstract class PlayerImpl implements Player, Serializable {
return false;
}
private void addPhyrexianLikePayOptions(ManaOptions abilityOptions, ManaOptions availableMana, Game game) {
int maxLifeMana = getLife() / 2;
if (maxLifeMana > 0) {
Set<Mana> phyrexianOptions = new HashSet<>();
for (Mana mana : abilityOptions) {
int availableLifeMana = maxLifeMana;
if (getPhyrexianColors().isBlack()) {
createReducedManaPayOption(availableLifeMana, mana, phyrexianOptions, ManaType.BLACK);
}
if (getPhyrexianColors().isBlue()) {
createReducedManaPayOption(availableLifeMana, mana, phyrexianOptions, ManaType.BLUE);
}
if (getPhyrexianColors().isRed()) {
createReducedManaPayOption(availableLifeMana, mana, phyrexianOptions, ManaType.RED);
}
if (getPhyrexianColors().isGreen()) {
createReducedManaPayOption(availableLifeMana, mana, phyrexianOptions, ManaType.GREEN);
}
if (getPhyrexianColors().isWhite()) {
createReducedManaPayOption(availableLifeMana, mana, phyrexianOptions, ManaType.WHITE);
}
}
abilityOptions.addAll(phyrexianOptions);
}
}
private int createReducedManaPayOption(int availableLifeMana, Mana oldPayOption, Set<Mana> phyrexianOptions, ManaType manaType) {
if (oldPayOption.get(manaType) > 0) {
Mana manaCopy = oldPayOption.copy();
int restVal;
if (availableLifeMana > oldPayOption.get(manaType)) {
restVal = 0;
availableLifeMana -= oldPayOption.get(manaType);
} else {
restVal = oldPayOption.get(manaType) - availableLifeMana;
availableLifeMana = 0;
}
manaCopy.set(manaType, restVal);
phyrexianOptions.add(manaCopy);
}
return availableLifeMana;
}
protected boolean canPlayCardByAlternateCost(Card sourceObject, ManaOptions availableMana, Ability ability, Game game) {
if (sourceObject != null && !(sourceObject instanceof Permanent)) {
Ability copyAbility; // for alternative cost and reduce tries
@ -4544,39 +4592,24 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public void addPhyrexianToColors(FilterMana colors) {
if (colors.isWhite()) {
this.phyrexianColors.setWhite(true);
}
if (colors.isBlue()) {
this.phyrexianColors.setBlue(true);
}
if (colors.isBlack()) {
this.phyrexianColors.setBlack(true);
}
if (colors.isRed()) {
this.phyrexianColors.setRed(true);
}
if (colors.isGreen()) {
this.phyrexianColors.setGreen(true);
}
}
@Override
public void removePhyrexianFromColors(FilterMana colors) {
if (colors.isWhite()) {
this.phyrexianColors.setWhite(false);
}
if (colors.isBlue()) {
this.phyrexianColors.setBlue(false);
}
if (colors.isBlack()) {
this.phyrexianColors.setBlack(false);
}
if (colors.isRed()) {
this.phyrexianColors.setRed(false);
}
if (colors.isGreen()) {
this.phyrexianColors.setGreen(false);
if (phyrexianColors == null) {
phyrexianColors = colors.copy();
} else {
if (colors.isWhite()) {
this.phyrexianColors.setWhite(true);
}
if (colors.isBlue()) {
this.phyrexianColors.setBlue(true);
}
if (colors.isBlack()) {
this.phyrexianColors.setBlack(true);
}
if (colors.isRed()) {
this.phyrexianColors.setRed(true);
}
if (colors.isGreen()) {
this.phyrexianColors.setGreen(true);
}
}
}

View file

@ -225,11 +225,6 @@ public class StubPlayer extends PlayerImpl implements Player {
}
@Override
public void removePhyrexianFromColors(FilterMana colors) {
}
@Override
public FilterMana getPhyrexianColors() {
return (new FilterMana());