mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 19:28:01 +00:00
Merge branch 'pfps_master' into 'master'
GameAction: add PlayerController:confirmMulliganScry See merge request pfps/forge!1
This commit is contained in:
@@ -1209,8 +1209,7 @@ public class AiController {
|
||||
}
|
||||
|
||||
public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
||||
ApiType api = (sa == null ) ? null : sa.getApi();
|
||||
if ( api == null && mode == PlayerActionConfirmMode.Scry ) return true; // special hack for mulligan
|
||||
ApiType api = sa.getApi();
|
||||
|
||||
// Abilities without api may also use this routine, However they should provide a unique mode value ?? How could this work?
|
||||
if (api == null) {
|
||||
|
||||
@@ -1164,4 +1164,10 @@ public class PlayerControllerAi extends PlayerController {
|
||||
|
||||
return chosenOptCosts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean confirmMulliganScry(Player p) {
|
||||
// Always true?
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1714,15 +1714,18 @@ public class GameAction {
|
||||
} while (!allKept);
|
||||
|
||||
//Vancouver Mulligan as a scry with the decisions inside
|
||||
ArrayList<Player> scryers = new ArrayList<Player>();
|
||||
List<Player> scryers = Lists.newArrayList();
|
||||
for(Player p : whoCanMulligan) {
|
||||
if (p.getStartingHandSize() > p.getZone(ZoneType.Hand).size()) {
|
||||
scryers.add(p);
|
||||
}
|
||||
}
|
||||
if ( scryers.size() > 0 ) {
|
||||
scry(scryers,1,true,null);
|
||||
}
|
||||
|
||||
for(Player p : scryers) {
|
||||
if (p.getController().confirmMulliganScry(p)) {
|
||||
scry(ImmutableList.of(p), 1, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void runPreOpeningHandActions(final Player first) {
|
||||
@@ -1830,51 +1833,56 @@ public class GameAction {
|
||||
// 701.17c If multiple players scry at once, each of those players looks at the top cards of their library
|
||||
// at the same time. Those players decide in APNAP order (see rule 101.4) where to put those
|
||||
// cards, then those cards move at the same time.
|
||||
public void scry(List<Player>players,int numScry, boolean isOptional, SpellAbility cause) {
|
||||
if ( numScry == 0 ) { return; }
|
||||
// reveal the top N library cards to the player (only)
|
||||
if ( players.size() > 1 ) { // no real need to separate out the look if there is only one player scrying
|
||||
for ( final Player p : players ) {
|
||||
final CardCollection topN = new CardCollection(p.getCardsIn(ZoneType.Library, numScry));
|
||||
p.getGame().getAction().revealTo(topN,p);
|
||||
}
|
||||
}
|
||||
// make the decisions
|
||||
ArrayList<ImmutablePair<CardCollection, CardCollection>> decisions =
|
||||
new ArrayList<ImmutablePair<CardCollection, CardCollection>>();
|
||||
for ( final Player p : players ) {
|
||||
if (isOptional && !p.getController().confirmAction(cause, PlayerActionConfirmMode.Scry, "Do you want to scry?")) {
|
||||
decisions.add(new ImmutablePair<CardCollection, CardCollection>(new CardCollection(),new CardCollection()));
|
||||
} else {
|
||||
final CardCollection topN = new CardCollection(p.getCardsIn(ZoneType.Library, numScry));
|
||||
ImmutablePair<CardCollection, CardCollection> decision = p.getController().arrangeForScry(topN);
|
||||
decisions.add(decision);
|
||||
int numToTop = decision.getLeft()==null ? 0 : decision.getLeft().size();
|
||||
int numToBottom = decision.getRight()==null ? 0 : decision.getRight().size();
|
||||
p.getGame().fireEvent(new GameEventScry(p, numToTop, numToBottom)); // publicize the decision
|
||||
}
|
||||
}
|
||||
// do the moves after all the decisions (maybe not necesssary, but let's do it the official way)
|
||||
for ( int i = 0; i<players.size(); i++ ) { // no good iterate simultaneously in Java
|
||||
final Player p = players.get(i);
|
||||
final CardCollection toTop = decisions.get(i).getLeft();
|
||||
final CardCollection toBottom = decisions.get(i).getRight();
|
||||
if (toTop != null) {
|
||||
Collections.reverse(toTop); // reverse to get the correct order
|
||||
for(Card c : toTop) {
|
||||
p.getGame().getAction().moveToLibrary(c, cause, null);
|
||||
}
|
||||
}
|
||||
if (toBottom != null) {
|
||||
for(Card c : toBottom) {
|
||||
p.getGame().getAction().moveToBottomOfLibrary(c, cause, null);
|
||||
}
|
||||
}
|
||||
// set up triggers (but not actually do them until later)
|
||||
final Map<String, Object> runParams = Maps.newHashMap();
|
||||
runParams.put("Player", p);
|
||||
p.getGame().getTriggerHandler().runTrigger(TriggerType.Scry, runParams, false);
|
||||
}
|
||||
}
|
||||
public void scry(List<Player> players, int numScry, SpellAbility cause) {
|
||||
if (numScry == 0) {
|
||||
return;
|
||||
}
|
||||
// reveal the top N library cards to the player (only)
|
||||
// no real need to separate out the look if
|
||||
// there is only one player scrying
|
||||
if (players.size() > 1) {
|
||||
for (final Player p : players) {
|
||||
final CardCollection topN = new CardCollection(p.getCardsIn(ZoneType.Library, numScry));
|
||||
revealTo(topN, p);
|
||||
}
|
||||
}
|
||||
// make the decisions
|
||||
List<ImmutablePair<CardCollection, CardCollection>> decisions = Lists.newArrayList();
|
||||
for (final Player p : players) {
|
||||
final CardCollection topN = new CardCollection(p.getCardsIn(ZoneType.Library, numScry));
|
||||
ImmutablePair<CardCollection, CardCollection> decision = p.getController().arrangeForScry(topN);
|
||||
decisions.add(decision);
|
||||
int numToTop = decision.getLeft() == null ? 0 : decision.getLeft().size();
|
||||
int numToBottom = decision.getRight() == null ? 0 : decision.getRight().size();
|
||||
|
||||
// publicize the decision
|
||||
game.fireEvent(new GameEventScry(p, numToTop, numToBottom));
|
||||
}
|
||||
// do the moves after all the decisions (maybe not necesssary, but let's
|
||||
// do it the official way)
|
||||
for (int i = 0; i < players.size(); i++) {
|
||||
// no good iterate simultaneously in Java
|
||||
final Player p = players.get(i);
|
||||
final CardCollection toTop = decisions.get(i).getLeft();
|
||||
final CardCollection toBottom = decisions.get(i).getRight();
|
||||
if (toTop != null) {
|
||||
Collections.reverse(toTop); // reverse to get the correct order
|
||||
for (Card c : toTop) {
|
||||
moveToLibrary(c, cause, null);
|
||||
}
|
||||
}
|
||||
if (toBottom != null) {
|
||||
for (Card c : toBottom) {
|
||||
moveToBottomOfLibrary(c, cause, null);
|
||||
}
|
||||
}
|
||||
|
||||
if (cause != null) {
|
||||
// set up triggers (but not actually do them until later)
|
||||
final Map<String, Object> runParams = Maps.newHashMap();
|
||||
runParams.put("Player", p);
|
||||
game.getTriggerHandler().runTrigger(TriggerType.Scry, runParams, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,18 +4,17 @@ import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
|
||||
public class ScryEffect extends SpellAbilityEffect {
|
||||
@Override
|
||||
protected String getStackDescription(SpellAbility sa) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
|
||||
for (final Player p : tgtPlayers) {
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
sb.append(p.toString()).append(" ");
|
||||
}
|
||||
|
||||
@@ -37,18 +36,16 @@ public class ScryEffect extends SpellAbilityEffect {
|
||||
|
||||
boolean isOptional = sa.hasParam("Optional");
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
final ArrayList<Player> players = new ArrayList<Player>(); // players really affected
|
||||
final List<Player> players = Lists.newArrayList(); // players really affected
|
||||
|
||||
// Optional here for spells that have optional multi-player scrying
|
||||
for (final Player p : tgtPlayers) {
|
||||
if ( ((tgt == null) || p.canBeTargetedBy(sa)) &&
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if ( (!sa.usesTargeting() || p.canBeTargetedBy(sa)) &&
|
||||
(!isOptional || p.getController().confirmAction(sa, null, "Do you want to scry?")) ) {
|
||||
players.add(p);
|
||||
}
|
||||
}
|
||||
sa.getActivatingPlayer().getGame().getAction().scry(players,num,false,sa);
|
||||
sa.getActivatingPlayer().getGame().getAction().scry(players, num, sa);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,6 @@ public enum PlayerActionConfirmMode {
|
||||
OptionalChoose,
|
||||
Tribute,
|
||||
// Ripple;
|
||||
Scry;
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
@@ -260,4 +260,6 @@ public abstract class PlayerController {
|
||||
}
|
||||
|
||||
public abstract List<OptionalCostValue> chooseOptionalCosts(SpellAbility choosen, List<OptionalCostValue> optionalCostValues);
|
||||
|
||||
public abstract boolean confirmMulliganScry(final Player p);
|
||||
}
|
||||
|
||||
@@ -678,4 +678,10 @@ public class PlayerControllerForTests extends PlayerController {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean confirmMulliganScry(Player p) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2889,4 +2889,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
optionalCost, choosen.getHostCard().getView());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean confirmMulliganScry(Player p) {
|
||||
return InputConfirm.confirm(this, (SpellAbility)null, "Do you want to scry?");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user