mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 19:28:01 +00:00
- Added Order of Succession
This commit is contained in:
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -117,8 +117,8 @@ public class RepeatEachEffect extends SpellAbilityEffect {
|
||||
}
|
||||
if (recordChoice) {
|
||||
boolean random = sa.hasParam("Random");
|
||||
Map<Player, List<Card>> recordMap = new HashMap<Player, List<Card>>();
|
||||
if (sa.hasParam("ChoosePlayer")) {
|
||||
Map<Player, List<Card>> recordMap = new HashMap<Player, List<Card>>();
|
||||
for (Card card : repeatCards) {
|
||||
Player p;
|
||||
if (random) {
|
||||
@@ -132,14 +132,40 @@ public class RepeatEachEffect extends SpellAbilityEffect {
|
||||
recordMap.put(p, Lists.newArrayList(card));
|
||||
}
|
||||
}
|
||||
for (Entry<Player, List<Card>> entry : recordMap.entrySet()) {
|
||||
// Remember the player and imprint the cards
|
||||
source.addRemembered(entry.getKey());
|
||||
source.getImprinted().addAll(entry.getValue());
|
||||
AbilityUtils.resolve(repeat);
|
||||
source.removeRemembered(entry.getKey());
|
||||
source.getImprinted().removeAll(entry.getValue());
|
||||
}
|
||||
} 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());
|
||||
source.getImprinted().addAll(entry.getValue());
|
||||
AbilityUtils.resolve(repeat);
|
||||
source.removeRemembered(entry.getKey());
|
||||
source.getImprinted().removeAll(entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
@@ -5476,7 +5491,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
if (o instanceof Player) {
|
||||
if (!p.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5485,7 +5500,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
if (o instanceof Player) {
|
||||
if (!p.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (property.startsWith("nonRememberedPlayerCtrl")) {
|
||||
|
||||
@@ -65,6 +65,7 @@ public abstract class PlayerController {
|
||||
OddsOrEvens,
|
||||
UntapOrLeaveTapped,
|
||||
UntapTimeVault,
|
||||
LeftOrRight,
|
||||
}
|
||||
|
||||
protected final Game game;
|
||||
|
||||
8
forge-gui/res/cardsfolder/o/order_of_succession.txt
Normal file
8
forge-gui/res/cardsfolder/o/order_of_succession.txt
Normal 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
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user