mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 03:08:02 +00:00
Fix illegal distributions
This commit is contained in:
@@ -2146,10 +2146,10 @@ public class AiController {
|
||||
return library;
|
||||
} // smoothComputerManaCurve()
|
||||
|
||||
public int chooseNumber(SpellAbility sa, String title,List<Integer> options, Player relatedPlayer) {
|
||||
public int chooseNumber(SpellAbility sa, String title, List<Integer> options, Player relatedPlayer) {
|
||||
switch(sa.getApi())
|
||||
{
|
||||
case SetLife:
|
||||
case SetLife: // Reverse the Sands
|
||||
if (relatedPlayer.equals(sa.getHostCard().getController())) {
|
||||
return Collections.max(options);
|
||||
} else if (relatedPlayer.isOpponentOf(sa.getHostCard().getController())) {
|
||||
|
||||
@@ -3,9 +3,12 @@ package forge.game.ability.effects;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerCollection;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.util.Localizer;
|
||||
@@ -18,31 +21,75 @@ public class LifeSetEffect extends SpellAbilityEffect {
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
final boolean redistribute = sa.hasParam("Redistribute");
|
||||
final int lifeAmount = redistribute ? 20 : AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("LifeAmount"), sa);
|
||||
final int lifeAmount = redistribute ? 0 : AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("LifeAmount"), sa);
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
final List<Integer> lifetotals = new ArrayList<>();
|
||||
|
||||
final PlayerCollection players = getTargetPlayers(sa);
|
||||
|
||||
if (redistribute) {
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
for (final Player p : players) {
|
||||
if (tgt == null || p.canBeTargetedBy(sa)) {
|
||||
lifetotals.add(p.getLife());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
for (final Player p : players.threadSafeIterable()) {
|
||||
if (tgt == null || p.canBeTargetedBy(sa)) {
|
||||
if (!redistribute) {
|
||||
p.setLife(lifeAmount, sa.getHostCard());
|
||||
} else {
|
||||
int life = sa.getActivatingPlayer().getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblLifeTotal") + ": " + p, lifetotals, p);
|
||||
List<Integer> validChoices = getDistribution(players, true, lifetotals);
|
||||
int life = sa.getActivatingPlayer().getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblLifeTotal") + ": " + p, validChoices, p);
|
||||
p.setLife(life, sa.getHostCard());
|
||||
lifetotals.remove((Integer) life);
|
||||
players.remove(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Integer> getDistribution(PlayerCollection players, boolean top, List<Integer> remainingChoices) {
|
||||
// distribution was successful
|
||||
if (players.isEmpty()) {
|
||||
// carry signal back
|
||||
remainingChoices.add(1);
|
||||
return remainingChoices;
|
||||
}
|
||||
List<Integer> validChoices = Lists.newArrayList(remainingChoices);
|
||||
for (Player p : players) {
|
||||
for (Integer choice : remainingChoices) {
|
||||
// 119.7/8 illegal choice
|
||||
if ((p.getLife() < choice && !p.canGainLife()) || (p.getLife() > choice && !p.canLoseLife())) {
|
||||
if (top) {
|
||||
validChoices.remove(choice);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// combination is valid, check next
|
||||
PlayerCollection nextPlayers = new PlayerCollection(players);
|
||||
nextPlayers.remove(p);
|
||||
List<Integer> nextChoices = new ArrayList<>(remainingChoices);
|
||||
nextChoices.remove(choice);
|
||||
nextChoices = getDistribution(nextPlayers, false, nextChoices);
|
||||
if (nextChoices.isEmpty()) {
|
||||
if (top) {
|
||||
// top of recursion stack
|
||||
validChoices.remove(choice);
|
||||
}
|
||||
} else if (!top) {
|
||||
return nextChoices;
|
||||
}
|
||||
}
|
||||
if (top) {
|
||||
// checking first player is enough
|
||||
return validChoices;
|
||||
}
|
||||
}
|
||||
return new ArrayList<Integer>();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.abilityfactory.AbilityFactoryAlterLife.SpellEffect#getStackDescription(java.util.Map, forge.card.spellability.SpellAbility)
|
||||
*/
|
||||
|
||||
@@ -483,15 +483,15 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return gainLife(lifeGain, source, null);
|
||||
}
|
||||
public final boolean gainLife(int lifeGain, final Card source, final SpellAbility sa) {
|
||||
if (!canGainLife()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Run any applicable replacement effects.
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
|
||||
repParams.put(AbilityKey.LifeGained, lifeGain);
|
||||
repParams.put(AbilityKey.Source, source);
|
||||
|
||||
if (!canGainLife()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (getGame().getReplacementHandler().run(ReplacementType.GainLife, repParams)) {
|
||||
case NotReplaced:
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user