- Convert Balance to script, Simplify Balancing Act

- Add Restore Balance
- Adding a Balance Effect API
This commit is contained in:
Sol
2013-06-18 00:06:51 +00:00
parent 9996b26eba
commit 7073eb5494
8 changed files with 137 additions and 133 deletions

3
.gitattributes vendored
View File

@@ -8843,6 +8843,7 @@ res/cardsfolder/r/restless_dead.txt svneol=native#text/plain
res/cardsfolder/r/restless_dreams.txt -text
res/cardsfolder/r/restock.txt svneol=native#text/plain
res/cardsfolder/r/restoration_angel.txt -text
res/cardsfolder/r/restore_balance.txt -text
res/cardsfolder/r/restore_the_peace.txt -text
res/cardsfolder/r/restrain.txt -text
res/cardsfolder/r/resurrection.txt svneol=native#text/plain
@@ -14042,6 +14043,7 @@ src/main/java/forge/card/ability/ai/AlwaysPlayAi.java -text
src/main/java/forge/card/ability/ai/AnimateAi.java -text
src/main/java/forge/card/ability/ai/AnimateAllAi.java -text
src/main/java/forge/card/ability/ai/AttachAi.java -text
src/main/java/forge/card/ability/ai/BalanceAi.java -text
src/main/java/forge/card/ability/ai/BecomesBlockedAi.java -text
src/main/java/forge/card/ability/ai/BondAi.java -text
src/main/java/forge/card/ability/ai/CanPlayAsDrawbackAi.java -text
@@ -14143,6 +14145,7 @@ src/main/java/forge/card/ability/effects/AnimateAllEffect.java -text
src/main/java/forge/card/ability/effects/AnimateEffect.java -text
src/main/java/forge/card/ability/effects/AnimateEffectBase.java svneol=native#text/plain
src/main/java/forge/card/ability/effects/AttachEffect.java -text
src/main/java/forge/card/ability/effects/BalanceEffect.java -text
src/main/java/forge/card/ability/effects/BecomesBlockedEffect.java -text
src/main/java/forge/card/ability/effects/BondEffect.java -text
src/main/java/forge/card/ability/effects/ChangeTargetsEffect.java -text

View File

@@ -1,12 +1,8 @@
Name:Balance
ManaCost:1 W
Types:Sorcery
Text:Each player chooses a number of lands he or she controls equal to the number of lands controlled by the player who controls the fewest, then sacrifices the rest. Players discard cards and sacrifice creatures the same way.
A:SP$ Balance | Cost$ 1 W | Valid$ Land | AILogic$ BalanceCreaturesAndLands | SubAbility$ BalanceHands | SpellDescription$ Each player chooses a number of lands he or she controls equal to the number of lands controlled by the player who controls the fewest, then sacrifices the rest. Players discard cards and sacrifice creatures the same way.
SVar:BalanceHands:DB$ Balance | Zone$ Hand | SubAbility$ BalanceCreatures
SVar:BalanceCreatures:DB$ Balance | Valid$ Creature
SVar:Picture:http://www.wizards.com/global/images/magic/general/balance.jpg
Oracle:Each player chooses a number of lands he or she controls equal to the number of lands controlled by the player who controls the fewest, then sacrifices the rest. Players discard cards and sacrifice creatures the same way.
SetInfo:2ED Rare
SetInfo:V09 Mythic
SetInfo:LEB Rare
SetInfo:LEA Rare
SetInfo:4ED Rare
SetInfo:3ED Rare

View File

@@ -1,24 +1,8 @@
Name:Balancing Act
ManaCost:2 W W
Types:Sorcery
A:SP$ RepeatEach | Cost$ 2 W W | RepeatPlayers$ Player | RepeatSubAbility$ FindFewestPermanent | StackDescription$ SpellDescription | SubAbility$ DBChooseRepeat | SpellDescription$ Each player chooses a number of permanents he or she controls equal to the number of permanents controlled by the player who controls the fewest, then sacrifices the rest. Each player discards cards the same way.
SVar:FindFewestPermanent:DB$ StoreSVar | SVar$ MinPermanent | Type$ CountSVar | Expression$ NumPermanent | ConditionCheckSVar$ NumPermanent | ConditionSVarCompare$ LTMinPermanent
SVar:NumPermanent:Count$Valid Permanent.RememberedPlayerCtrl
SVar:MinPermanent:Number$9999
SVar:DBChooseRepeat:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ DBChoose | StackDescription$ None | SubAbility$ SacAll
SVar:DBChoose:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Permanent.RememberedPlayerCtrl | Amount$ MinPermanent | References$ MinPermanent | ChoiceTitle$ Choose permanents you control | RememberChosen$ True
SVar:SacAll:DB$ SacrificeAll | ValidCards$ Permanent.IsNotRemembered | SubAbility$ DBCleanup1 | StackDescription$ None
SVar:DBCleanup1:DB$ Cleanup | ClearRemembered$ True | SubAbility$ DBFindFewestHand
SVar:DBFindFewestHand:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ FindFewestHand | StackDescription$ None | SubAbility$ DBChooseRepeat2
SVar:FindFewestHand:DB$ StoreSVar | SVar$ MinHand | Type$ CountSVar | Expression$ NumHand | ConditionCheckSVar$ NumHand | ConditionSVarCompare$ LTMinHand
SVar:MinHand:Number$9999
SVar:NumHand:Count$ValidHand Card.RememberedPlayerCtrl
SVar:DBChooseRepeat2:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ DBChooseHand | StackDescription$ None | SubAbility$ DisCardAll
SVar:DBChooseHand:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Card.RememberedPlayerCtrl | ChoiceZone$ Hand | Amount$ MinHand | References$ MinHand | ChoiceTitle$ Choose cards in your hand | RememberChosen$ True
SVar:DisCardAll:DB$ Discard | Mode$ Defined | DefinedCards$ ValidHand Card.IsNotRemembered | Defined$ Each | SubAbility$ DBCleanup2
SVar:DBCleanup2:DB$ Cleanup | ClearRemembered$ True | SubAbility$ DBReset1
SVar:DBReset1:DB$ StoreSVar | SVar$ MinPermanent | Type$ Number | Expression$ 9999 | SubAbility$ DBReset2
SVar:DBReset2:DB$ StoreSVar | SVar$ MinHand | Type$ Number | Expression$ 9999
A:SP$ Balance | Cost$ 2 W W | Valid$ Permanent | AILogic$ BalancePermanents | SubAbility$ BalanceHands | SpellDescription$ Each player chooses a number of permanents he or she controls equal to the number of permanents controlled by the player who controls the fewest, then sacrifices the rest. Each player discards cards the same way.
SVar:BalanceHands:DB$ Balance | Zone$ Hand
SVar:Picture:http://www.wizards.com/global/images/magic/general/balancing_act.jpg
SVar:RemAIDeck:True
SVar:RemRandomDeck:True

View File

@@ -0,0 +1,11 @@
Name:Restore Balance
ManaCost:no cost
Types:Sorcery
Colors:white
K:Suspend:6:W
A:SP$ Balance | Cost$ 1 W | Valid$ Land | AILogic$ BalanceCreaturesAndLands | SubAbility$ BalanceCreatures | SpellDescription$ Each player chooses a number of lands he or she controls equal to the number of lands controlled by the player who controls the fewest, then sacrifices the rest. Players discard cards and sacrifice creatures the same way. | ActivationLimit$ 0
SVar:BalanceCreatures:DB$ Balance | Valid$ Creature | SubAbility$ BalanceHands
SVar:BalanceHands:DB$ Balance | Zone$ Hand
SVar:RemAIDeck:True
SVar:Picture:http://www.wizards.com/global/images/magic/general/restore_balance.jpg
Oracle:Sorcery\nSuspend 6- {W} (Rather than cast this card from your hand, pay {W} and exile it with six time counters on it. At the beginning of your upkeep, remove a time counter. When the last is removed, cast it without paying its mana cost.)\nEach player chooses a number of lands he or she controls equal to the number of lands controlled by the player who controls the fewest, then sacrifices the rest. Players sacrifice creatures and discard cards the same way.

View File

@@ -10,6 +10,7 @@ import forge.card.ability.ai.AlwaysPlayAi;
import forge.card.ability.ai.AnimateAi;
import forge.card.ability.ai.AnimateAllAi;
import forge.card.ability.ai.AttachAi;
import forge.card.ability.ai.BalanceAi;
import forge.card.ability.ai.BecomesBlockedAi;
import forge.card.ability.ai.BondAi;
import forge.card.ability.ai.CanPlayAsDrawbackAi;
@@ -114,6 +115,7 @@ public enum ApiType {
Animate (AnimateEffect.class, AnimateAi.class),
AnimateAll (AnimateAllEffect.class, AnimateAllAi.class),
Attach (AttachEffect.class, AttachAi.class),
Balance (BalanceEffect.class, BalanceAi.class),
BecomesBlocked (BecomesBlockedEffect.class, BecomesBlockedAi.class),
Bond (BondEffect.class, BondAi.class),
ChangeTargets(ChangeTargetsEffect.class, CannotPlayAi.class),

View File

@@ -0,0 +1,53 @@
package forge.card.ability.ai;
import java.util.List;
import org.apache.commons.lang.math.RandomUtils;
import forge.Card;
import forge.CardLists;
import forge.CardPredicates;
import forge.card.ability.SpellAbilityAi;
import forge.card.spellability.SpellAbility;
import forge.game.player.Player;
import forge.game.zone.ZoneType;
public class BalanceAi extends SpellAbilityAi {
/* (non-Javadoc)
* @see forge.card.ability.SpellAbilityAi#canPlayAI(forge.game.player.Player, forge.card.spellability.SpellAbility)
*/
@Override
protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) {
String logic = sa.getParam("AILogic");
int diff = 0;
// TODO Add support for multiplayer logic
final Player opp = aiPlayer.getOpponent();
final List<Card> humPerms = opp.getCardsIn(ZoneType.Battlefield);
final List<Card> compPerms = aiPlayer.getCardsIn(ZoneType.Battlefield);
if ("BalanceCreaturesAndLands".equals(logic)) {
// Copied over from hardcoded Balance. We should be checking value of the lands/creatures not just counting
diff += CardLists.filter(humPerms, CardPredicates.Presets.LANDS).size() -
CardLists.filter(compPerms, CardPredicates.Presets.LANDS).size();
diff += 1.5 * ( CardLists.filter(humPerms, CardPredicates.Presets.CREATURES).size() -
CardLists.filter(compPerms, CardPredicates.Presets.CREATURES).size());
} else if ("BalancePermanents".equals(logic)) {
// Don't cast if you have to sacrifice permanents
diff += humPerms.size() - compPerms.size();
}
if (diff < 0) {
// Don't sacrifice permanents even if opponent has a ton of cards in hand
return false;
}
final List<Card> humHand = opp.getCardsIn(ZoneType.Hand);
final List<Card> compHand = aiPlayer.getCardsIn(ZoneType.Hand);
diff += 0.5 * (humHand.size() - compHand.size());
// Larger differential == more chance to actually cast this spell
return diff > 2 && RandomUtils.nextInt(100) < diff*10;
}
}

View File

@@ -0,0 +1,61 @@
package forge.card.ability.effects;
import java.util.ArrayList;
import java.util.List;
import forge.Card;
import forge.CardLists;
import forge.card.ability.SpellAbilityEffect;
import forge.card.spellability.SpellAbility;
import forge.game.Game;
import forge.game.player.Player;
import forge.game.zone.ZoneType;
/**
* TODO: Write javadoc for this type.
*
*/
public class BalanceEffect extends SpellAbilityEffect {
/* (non-Javadoc)
* @see forge.card.ability.SpellAbilityEffect#resolve(forge.card.spellability.SpellAbility)
*/
@Override
public void resolve(SpellAbility sa) {
Player activator = sa.getActivatingPlayer();
Card source = sa.getSourceCard();
Game game = activator.getGame();
String valid = sa.hasParam("Valid") ? sa.getParam("Valid") : "Card";
ZoneType zone = sa.hasParam("Zone") ? ZoneType.smartValueOf(sa.getParam("Zone")) : ZoneType.Battlefield;
int min = Integer.MAX_VALUE;
final List<Player> players = game.getPlayers();
final List<List<Card>> validCards = new ArrayList<List<Card>>(players.size());
for(int i = 0; i < players.size(); i++) {
// Find the minimum of each Valid per player
validCards.add(CardLists.getValidCards(players.get(i).getCardsIn(zone), valid, activator, source));
min = Math.min(min, validCards.get(i).size());
}
for(int i = 0; i < players.size(); i++) {
Player p = players.get(i);
int numToBalance = validCards.get(i).size() - min;
if (numToBalance == 0) {
continue;
}
if (zone.equals(ZoneType.Hand)) {
for (Card card : p.getController().chooseCardsToDiscardFrom(p, sa, validCards.get(i), numToBalance, numToBalance)) {
if ( null == card ) continue;
p.discard(card, sa);
}
} else { // Battlefield
for(Card card : p.getController().choosePermanentsToSacrifice(sa, numToBalance, numToBalance, validCards.get(i), valid)) {
if ( null == card ) continue;
game.getAction().sacrifice(card, sa);
}
}
}
}
}

View File

@@ -17,12 +17,9 @@
*/
package forge.card.cardfactory;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import forge.Card;
import forge.CardLists;
import forge.CardPredicates;
import forge.Singletons;
import forge.CardPredicates.Presets;
import forge.card.cost.Cost;
@@ -45,108 +42,6 @@ import forge.gui.input.InputPayManaExecuteCommands;
*/
public class CardFactorySorceries {
private static final void balanceLands(Game game, Spell card) {
int minLands = Integer.MAX_VALUE;
for (Player p : game.getPlayers()) {
int pL = p.getLandsInPlay().size();
if( pL < minLands )
minLands = pL;
}
for (Player p : game.getPlayers()) {
List<Card> l = p.getLandsInPlay();
int sac = l.size() - minLands;
if (sac == 0) {
continue;
}
List<Card> toSac = p.getController().choosePermanentsToSacrifice(card, sac, sac, l, "land(s)");
for( Card crd : toSac )
p.getGame().getAction().sacrifice(crd, card);
}
}
private static final void balanceHands(Game game, Spell spell) {
int min = Integer.MAX_VALUE;
for (Player p : game.getPlayers()) {
min = Math.min(min, p.getZone(ZoneType.Hand).size());
}
for (Player p : game.getPlayers()) {
List<Card> hand = new ArrayList<Card>(p.getCardsIn(ZoneType.Hand));
int sac = hand.size() - min;
if (sac == 0) {
continue;
}
List<Card> toDiscard = p.getController().chooseCardsToDiscardFrom(p, spell, hand, sac, sac); // "Select %d more card(s) to discard"
for (Card c : toDiscard)
p.discard(c, spell);
}
}
private static final void balanceCreatures(Game game, Spell card) {
List<List<Card>> creats = new ArrayList<List<Card>>();
for (Player p : game.getPlayers()) {
creats.add(p.getCreaturesInPlay());
}
int min = Integer.MAX_VALUE;
for (List<Card> h : creats) {
int s = h.size();
min = Math.min(min, s);
}
Iterator<List<Card>> cc = creats.iterator();
for (Player p : game.getPlayers()) {
List<Card> c = cc.next();
int sac = c.size() - min;
if (sac == 0) {
continue;
}
List<Card> toSac = p.getController().choosePermanentsToSacrifice(card, sac, sac, c, "creature(s)");
for( Card crd : toSac )
p.getGame().getAction().sacrifice(crd, card);
}
}
private static final SpellAbility getBalance(final Card card) {
return new Spell(card) {
private static final long serialVersionUID = -5941893280103164961L;
@Override
public void resolve() {
final Game game = this.getActivatingPlayer().getGame();
balanceLands(game, this);
balanceHands(game, this);
balanceCreatures(game, this);
}
@Override
public boolean canPlayAI() {
int diff = 0;
final Player ai = getActivatingPlayer();
final Player opp = ai.getOpponent();
final List<Card> humLand = opp.getLandsInPlay();
final List<Card> compLand = ai.getLandsInPlay();
diff += humLand.size() - compLand.size();
final List<Card> humCreats = opp.getCreaturesInPlay();
List<Card> compCreats = ai.getCreaturesInPlay();
compCreats = CardLists.filter(compCreats, CardPredicates.Presets.CREATURES);
diff += 1.5 * (humCreats.size() - compCreats.size());
final List<Card> humHand = opp.getCardsIn(ZoneType.Hand);
final List<Card> compHand = ai.getCardsIn(ZoneType.Hand);
diff += 0.5 * (humHand.size() - compHand.size());
return diff > 2;
}
};
}
private static final SpellAbility getTransmuteArtifact(final Card card) {
/*
* Sacrifice an artifact. If you do, search your library for an
@@ -219,8 +114,7 @@ public class CardFactorySorceries {
public static void buildCard(final Card card, final String cardName) {
if (cardName.equals("Balance")) { card.addSpellAbility(getBalance(card));
} else if (cardName.equals("Transmute Artifact")) { card.addSpellAbility(getTransmuteArtifact(card));
if (cardName.equals("Transmute Artifact")) { card.addSpellAbility(getTransmuteArtifact(card));
}
} // getCard
}