mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 03:08:02 +00:00
- Convert Balance to script, Simplify Balancing Act
- Add Restore Balance - Adding a Balance Effect API
This commit is contained in:
@@ -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),
|
||||
|
||||
53
src/main/java/forge/card/ability/ai/BalanceAi.java
Normal file
53
src/main/java/forge/card/ability/ai/BalanceAi.java
Normal 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;
|
||||
}
|
||||
}
|
||||
61
src/main/java/forge/card/ability/effects/BalanceEffect.java
Normal file
61
src/main/java/forge/card/ability/effects/BalanceEffect.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user