- Added Order of Succession

This commit is contained in:
swordshine
2014-06-08 11:01:14 +00:00
parent 876e9260fe
commit 8ccdcf93c8
14 changed files with 175 additions and 12 deletions

3
.gitattributes vendored
View File

@@ -48,6 +48,7 @@ forge-ai/src/main/java/forge/ai/ability/CharmAi.java -text
forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java -text
forge-ai/src/main/java/forge/ai/ability/ChooseCardNameAi.java -text
forge-ai/src/main/java/forge/ai/ability/ChooseColorAi.java -text
forge-ai/src/main/java/forge/ai/ability/ChooseDirectionAi.java -text
forge-ai/src/main/java/forge/ai/ability/ChooseGenericEffectAi.java -text
forge-ai/src/main/java/forge/ai/ability/ChooseNumberAi.java -text
forge-ai/src/main/java/forge/ai/ability/ChoosePlayerAi.java -text
@@ -307,6 +308,7 @@ forge-game/src/main/java/forge/game/ability/effects/CharmEffect.java -text
forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java -text
forge-game/src/main/java/forge/game/ability/effects/ChooseCardNameEffect.java -text
forge-game/src/main/java/forge/game/ability/effects/ChooseColorEffect.java -text
forge-game/src/main/java/forge/game/ability/effects/ChooseDirectionEffect.java -text
forge-game/src/main/java/forge/game/ability/effects/ChooseGenericEffect.java -text
forge-game/src/main/java/forge/game/ability/effects/ChooseNumberEffect.java -text
forge-game/src/main/java/forge/game/ability/effects/ChoosePlayerEffect.java -text
@@ -9560,6 +9562,7 @@ forge-gui/res/cardsfolder/o/ordeal_of_purphoros.txt -text
forge-gui/res/cardsfolder/o/ordeal_of_thassa.txt -text
forge-gui/res/cardsfolder/o/order_chaos.txt -text
forge-gui/res/cardsfolder/o/order_of_leitbur.txt svneol=native#text/plain
forge-gui/res/cardsfolder/o/order_of_succession.txt -text
forge-gui/res/cardsfolder/o/order_of_the_ebon_hand.txt svneol=native#text/plain
forge-gui/res/cardsfolder/o/order_of_the_golden_cricket.txt svneol=native#text/plain
forge-gui/res/cardsfolder/o/order_of_the_sacred_bell.txt svneol=native#text/plain

View File

@@ -41,6 +41,7 @@ import forge.card.mana.ManaCost;
import forge.deck.CardPool;
import forge.deck.Deck;
import forge.deck.DeckSection;
import forge.game.Direction;
import forge.game.Game;
import forge.game.GameActionUtil;
import forge.game.GameEntity;
@@ -1534,6 +1535,23 @@ public class AiController {
}
}
public boolean chooseDirection(SpellAbility sa) {
if( sa == null || sa.getApi() == null ) {
throw new UnsupportedOperationException();
}
// Left:True; Right:False
if ("GainControl".equals(sa.getParam("AILogic")) && game.getPlayers().size() > 2) {
List<Card> creats = CardLists.getType(game.getCardsIn(ZoneType.Battlefield), "Creature");
List<Card> left = CardLists.filterControlledBy(creats, game.getNextPlayerAfter(player, Direction.Left));
List<Card> right = CardLists.filterControlledBy(creats, game.getNextPlayerAfter(player, Direction.Right));
if (!left.isEmpty() || !right.isEmpty()) {
List<Card> all = new ArrayList<Card>(left);
all.addAll(right);
return left.contains(ComputerUtilCard.getBestCreatureAI(all));
}
}
return MyRandom.getRandom().nextBoolean();
}
}

View File

@@ -503,6 +503,7 @@ public class PlayerControllerAi extends PlayerController {
case TapOrUntap: return true;
case UntapOrLeaveTapped: return defaultVal != null && defaultVal.booleanValue();
case UntapTimeVault: return false; // TODO Should AI skip his turn for time vault?
case LeftOrRight: return brains.chooseDirection(sa);
default:
return MyRandom.getRandom().nextBoolean();
}

View File

@@ -31,6 +31,7 @@ public enum SpellApiToAi {
apiToClass.put(ApiType.Charm, CharmAi.class);
apiToClass.put(ApiType.ChooseCard, ChooseCardAi.class);
apiToClass.put(ApiType.ChooseColor, ChooseColorAi.class);
apiToClass.put(ApiType.ChooseDirection, ChooseDirectionAi.class);
apiToClass.put(ApiType.ChooseNumber, ChooseNumberAi.class);
apiToClass.put(ApiType.ChoosePlayer, ChoosePlayerAi.class);
apiToClass.put(ApiType.ChooseSource, ChooseSourceAi.class);

View File

@@ -0,0 +1,32 @@
package forge.ai.ability;
import forge.ai.SpellAbilityAi;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
public class ChooseDirectionAi extends SpellAbilityAi {
/* (non-Javadoc)
* @see forge.card.abilityfactory.SpellAiLogic#canPlayAI(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility)
*/
@Override
protected boolean canPlayAI(Player ai, SpellAbility sa) {
final String logic = sa.getParam("AILogic");
if (logic == null) {
return false;
} else {
// TODO: default ai
}
return true;
}
@Override
public boolean chkAIDrawback(SpellAbility sa, Player ai) {
return canPlayAI(ai, sa);
}
@Override
protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) {
return canPlayAI(ai, sa);
}
}

View File

@@ -1,6 +1,8 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import forge.ai.ComputerUtilCard;
import forge.ai.SpellAbilityAi;
import forge.game.card.Card;
import forge.game.card.CardLists;
@@ -11,6 +13,7 @@ import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
@@ -114,4 +117,9 @@ public class RepeatEachAi extends SpellAbilityAi {
return true;
}
@Override
protected Card chooseSingleCard(Player ai, SpellAbility sa, Collection<Card> options, boolean isOptional, Player targetedPlayer) {
return ComputerUtilCard.getBestCreatureAI(options);
}
}

View File

@@ -529,13 +529,25 @@ public class Game {
* {@code null} if there are no players in the game.
*/
public Player getNextPlayerAfter(final Player playerTurn) {
return getNextPlayerAfter(playerTurn, this.turnOrder);
}
/**
* Get the player whose turn it is after a given player's turn, taking turn
* order into account.
* @param playerTurn a {@link Player}, or {@code null}.
* @param turnOrder a {@link Direction}
* @return A {@link Player}, whose turn comes after the current player, or
* {@code null} if there are no players in the game.
*/
public Player getNextPlayerAfter(final Player playerTurn, final Direction turnOrder) {
int iPlayer = roIngamePlayers.indexOf(playerTurn);
if (roIngamePlayers.isEmpty()) {
return null;
}
final int shift = this.getTurnOrder().getShift();
final int shift = turnOrder.getShift();
final int totalNumPlayers = allPlayers.size();
if (-1 == iPlayer) { // if playerTurn has just lost
int iAlive;

View File

@@ -30,6 +30,7 @@ public enum ApiType {
Charm (CharmEffect.class),
ChooseCard (ChooseCardEffect.class),
ChooseColor (ChooseColorEffect.class),
ChooseDirection (ChooseDirectionEffect.class),
ChooseNumber (ChooseNumberEffect.class),
ChoosePlayer (ChoosePlayerEffect.class),
ChooseSource (ChooseSourceEffect.class),

View File

@@ -0,0 +1,35 @@
package forge.game.ability.effects;
import java.util.ArrayList;
import java.util.List;
import com.google.common.collect.Lists;
import forge.game.Direction;
import forge.game.Game;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.player.Player;
import forge.game.player.PlayerController.BinaryChoiceType;
import forge.game.spellability.SpellAbility;
public class ChooseDirectionEffect extends SpellAbilityEffect {
/* (non-Javadoc)
* @see forge.card.abilityfactory.SpellEffect#resolve(java.util.Map, forge.card.spellability.SpellAbility)
*/
@Override
public void resolve(final SpellAbility sa) {
final Card source = sa.getHostCard();
final Game game = source.getGame();
final List<Player> left = new ArrayList<Player>(game.getPlayers());
// TODO: We'd better set up turn order UI here
final String info = "Left (clockwise): " + left + "\r\nRight (anticlockwise):" + Lists.reverse(left);
sa.getActivatingPlayer().getController().notifyOfValue(sa, source, info);
boolean chosen = sa.getActivatingPlayer().getController().chooseBinary(sa,
"Choose a direction", BinaryChoiceType.LeftOrRight);
source.setChosenDirection(chosen ? Direction.Left : Direction.Right);
}
}

View File

@@ -117,8 +117,8 @@ public class RepeatEachEffect extends SpellAbilityEffect {
}
if (recordChoice) {
boolean random = sa.hasParam("Random");
if (sa.hasParam("ChoosePlayer")) {
Map<Player, List<Card>> recordMap = new HashMap<Player, List<Card>>();
if (sa.hasParam("ChoosePlayer")) {
for (Card card : repeatCards) {
Player p;
if (random) {
@@ -132,6 +132,33 @@ public class RepeatEachEffect extends SpellAbilityEffect {
recordMap.put(p, Lists.newArrayList(card));
}
}
} else if (sa.hasParam("ChooseCard")) {
List<Card> list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield),
sa.getParam("ChooseCard"), source.getController(), source);
String filterController = sa.getParam("FilterControlledBy");
// default: Starting with you and proceeding in the chosen direction
Player p = sa.getActivatingPlayer();
do {
List<Card> valid = new ArrayList<Card>(list);
if ("NextPlayerInChosenDirection".equals(filterController)) {
valid = CardLists.filterControlledBy(valid,
game.getNextPlayerAfter(p, source.getChosenDirection()));
}
Card card = p.getController().chooseSingleEntityForEffect(valid, sa, "Choose a card");
if (recordMap.containsKey(p)) {
recordMap.get(p).add(0, card);
} else {
recordMap.put(p, Lists.newArrayList(card));
}
if (source.getChosenDirection() != null) {
p = game.getNextPlayerAfter(p, source.getChosenDirection());
} else {
p = game.getNextPlayerAfter(p);
}
} while (!p.equals(sa.getActivatingPlayer()));
}
for (Entry<Player, List<Card>> entry : recordMap.entrySet()) {
// Remember the player and imprint the cards
source.addRemembered(entry.getKey());
@@ -143,4 +170,3 @@ public class RepeatEachEffect extends SpellAbilityEffect {
}
}
}
}

View File

@@ -207,6 +207,7 @@ public class Card extends GameEntity implements Comparable<Card> {
private int chosenNumber;
private Player chosenPlayer;
private List<Card> chosenCard = new ArrayList<Card>();
private Direction chosenDirection = null;
private Card cloneOrigin = null;
private final List<Card> clones = new ArrayList<Card>();
@@ -1725,6 +1726,14 @@ public class Card extends GameEntity implements Comparable<Card> {
this.chosenCard = c;
}
public Direction getChosenDirection() {
return chosenDirection;
}
public void setChosenDirection(Direction chosenDirection) {
this.chosenDirection = chosenDirection;
}
// used for cards like Meddling Mage...
/**
* <p>
@@ -1898,6 +1907,12 @@ public class Card extends GameEntity implements Comparable<Card> {
sb.append("]\r\n");
}
if (this.chosenDirection != null) {
sb.append("\r\n[Chosen direction: ");
sb.append(this.getChosenDirection());
sb.append("]\r\n");
}
if (this.hauntedBy.size() != 0) {
sb.append("Haunted by: ");
for (final Card c : this.hauntedBy) {

View File

@@ -65,6 +65,7 @@ public abstract class PlayerController {
OddsOrEvens,
UntapOrLeaveTapped,
UntapTimeVault,
LeftOrRight,
}
protected final Game game;

View File

@@ -0,0 +1,8 @@
Name:Order of Succession
ManaCost:3 U
Types:Sorcery
A:SP$ ChooseDirection | Cost$ 3 U | SubAbility$ DBRepeat | AILogic$ GainControl | SpellDescription$ Choose left or right. Starting with you and proceeding in the chosen direction, each player chooses a creature controlled by the next player in that direction. Each player gains control of the creature he or she chose.
SVar:DBRepeat:DB$ RepeatEach | RepeatSubAbility$ DBGainControl | RecordChoice$ True | ChooseCard$ Creature | FilterControlledBy$ NextPlayerInChosenDirection
SVar:DBGainControl:DB$ GainControl | NewController$ Remembered | AllValid$ Card.IsImprinted
SVar:RemAIDeck:True
SVar:Picture:http://www.wizards.com/global/images/magic/general/order_of_succession.jpg

View File

@@ -794,6 +794,8 @@ public class PlayerControllerHuman extends PlayerController {
return ("Result: " + value);
}
switch(sa.getApi()) {
case ChooseDirection:
return value;
case ChooseNumber:
if (sa.hasParam("SecretlyChoose")) {
return value;