From e933ecc70ce297d21ebb66868a07c087b2bddc9f Mon Sep 17 00:00:00 2001 From: swordshine Date: Sat, 3 May 2014 12:54:33 +0000 Subject: [PATCH] - Added three bid life cards --- .gitattributes | 5 ++ .../src/main/java/forge/ai/AiController.java | 16 ++++ .../java/forge/ai/PlayerControllerAi.java | 8 ++ .../src/main/java/forge/ai/SpellApiToAi.java | 1 + .../main/java/forge/ai/ability/BidLifeAi.java | 53 ++++++++++++ .../main/java/forge/game/ability/ApiType.java | 1 + .../game/ability/effects/BidLifeEffect.java | 81 +++++++++++++++++++ .../game/player/PlayerActionConfirmMode.java | 1 + .../forge/game/player/PlayerController.java | 5 +- .../util/PlayerControllerForTests.java | 7 ++ .../res/cardsfolder/i/illicit_auction.txt | 9 +++ forge-gui/res/cardsfolder/m/mages_contest.txt | 9 +++ forge-gui/res/cardsfolder/p/pains_reward.txt | 9 +++ .../forge/player/PlayerControllerHuman.java | 7 ++ 14 files changed, 209 insertions(+), 3 deletions(-) create mode 100644 forge-ai/src/main/java/forge/ai/ability/BidLifeAi.java create mode 100644 forge-game/src/main/java/forge/game/ability/effects/BidLifeEffect.java create mode 100644 forge-gui/res/cardsfolder/i/illicit_auction.txt create mode 100644 forge-gui/res/cardsfolder/m/mages_contest.txt create mode 100644 forge-gui/res/cardsfolder/p/pains_reward.txt diff --git a/.gitattributes b/.gitattributes index 7598ebf5569..9c3b7aacba2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -37,6 +37,7 @@ forge-ai/src/main/java/forge/ai/ability/AnimateAllAi.java -text forge-ai/src/main/java/forge/ai/ability/AttachAi.java -text forge-ai/src/main/java/forge/ai/ability/BalanceAi.java -text forge-ai/src/main/java/forge/ai/ability/BecomesBlockedAi.java -text +forge-ai/src/main/java/forge/ai/ability/BidLifeAi.java -text forge-ai/src/main/java/forge/ai/ability/BondAi.java -text forge-ai/src/main/java/forge/ai/ability/CanPlayAsDrawbackAi.java -text forge-ai/src/main/java/forge/ai/ability/CannotPlayAi.java -text @@ -296,6 +297,7 @@ forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java svneo forge-game/src/main/java/forge/game/ability/effects/AttachEffect.java -text forge-game/src/main/java/forge/game/ability/effects/BalanceEffect.java -text forge-game/src/main/java/forge/game/ability/effects/BecomesBlockedEffect.java -text +forge-game/src/main/java/forge/game/ability/effects/BidLifeEffect.java -text forge-game/src/main/java/forge/game/ability/effects/BondEffect.java -text forge-game/src/main/java/forge/game/ability/effects/ChangeTargetsEffect.java -text forge-game/src/main/java/forge/game/ability/effects/ChangeZoneAllEffect.java -text @@ -6877,6 +6879,7 @@ forge-gui/res/cardsfolder/i/iizuka_the_ruthless.txt svneol=native#text/plain forge-gui/res/cardsfolder/i/ikiral_outrider.txt svneol=native#text/plain forge-gui/res/cardsfolder/i/ill_gotten_gains.txt svneol=native#text/plain forge-gui/res/cardsfolder/i/ill_tempered_cyclops.txt -text +forge-gui/res/cardsfolder/i/illicit_auction.txt -text forge-gui/res/cardsfolder/i/illness_in_the_ranks.txt -text forge-gui/res/cardsfolder/i/illuminate.txt -text forge-gui/res/cardsfolder/i/illuminated_folio.txt -text @@ -8135,6 +8138,7 @@ forge-gui/res/cardsfolder/m/mage_il_vec.txt svneol=native#text/plain forge-gui/res/cardsfolder/m/mage_slayer.txt svneol=native#text/plain forge-gui/res/cardsfolder/m/magebane_armor.txt -text forge-gui/res/cardsfolder/m/magefire_wings.txt svneol=native#text/plain +forge-gui/res/cardsfolder/m/mages_contest.txt -text forge-gui/res/cardsfolder/m/mages_guile.txt svneol=native#text/plain forge-gui/res/cardsfolder/m/mageta_the_lion.txt svneol=native#text/plain forge-gui/res/cardsfolder/m/magetas_boon.txt svneol=native#text/plain @@ -9590,6 +9594,7 @@ forge-gui/res/cardsfolder/p/pain_suffering.txt -text forge-gui/res/cardsfolder/p/painbringer.txt -text svneol=unset#text/plain forge-gui/res/cardsfolder/p/painful_memories.txt svneol=native#text/plain forge-gui/res/cardsfolder/p/painful_quandary.txt -text +forge-gui/res/cardsfolder/p/pains_reward.txt -text forge-gui/res/cardsfolder/p/painsmith.txt svneol=native#text/plain forge-gui/res/cardsfolder/p/painters_servant.txt svneol=native#text/plain forge-gui/res/cardsfolder/p/painwracker_oni.txt svneol=native#text/plain diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index 3277d21e936..973ee77c34c 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -922,6 +922,22 @@ public class AiController { return SpellApiToAi.Converter.get(api).confirmAction(player, sa, mode, message); } + public boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode mode, String message, + int bid, Player winner) { + if (mode != null) switch (mode) { + case BidLife: + if (sa.hasParam("AIBidMax")) { + return !player.equals(winner) && bid < Integer.parseInt(sa.getParam("AIBidMax")) && player.getLife() > bid + 5; + } else { + return false; + } + default: + return false; + } + return false; + } + + public boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message) { if (logic.equalsIgnoreCase("ProtectFriendly")) { final Player controller = hostCard.getController(); diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java index 59842bddb54..c505742590c 100644 --- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java +++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java @@ -122,6 +122,8 @@ public class PlayerControllerAi extends PlayerController { switch (ability.getApi()) { case ChooseNumber: return ability.getActivatingPlayer().isOpponentOf(player) ? 0 : ComputerUtilMana.determineLeftoverMana(ability, player); + case BidLife: + return 0; default: return null; } @@ -166,6 +168,12 @@ public class PlayerControllerAi extends PlayerController { public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message) { return getAi().confirmAction(sa, mode, message); } + + @Override + public boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode mode, String string, + int bid, Player winner) { + return getAi().confirmBidAction(sa, mode, string, bid, winner); + } @Override public boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message) { diff --git a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java index ddd6f165370..63594f93907 100644 --- a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java +++ b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java @@ -22,6 +22,7 @@ public enum SpellApiToAi { apiToClass.put(ApiType.Attach, AttachAi.class); apiToClass.put(ApiType.Balance, BalanceAi.class); apiToClass.put(ApiType.BecomesBlocked, BecomesBlockedAi.class); + apiToClass.put(ApiType.BidLife, BidLifeAi.class); apiToClass.put(ApiType.Bond, BondAi.class); apiToClass.put(ApiType.ChangeTargets, ChangeTargetsAi.class); apiToClass.put(ApiType.ChangeZone, ChangeZoneAi.class); diff --git a/forge-ai/src/main/java/forge/ai/ability/BidLifeAi.java b/forge-ai/src/main/java/forge/ai/ability/BidLifeAi.java new file mode 100644 index 00000000000..c8486e6805a --- /dev/null +++ b/forge-ai/src/main/java/forge/ai/ability/BidLifeAi.java @@ -0,0 +1,53 @@ +package forge.ai.ability; + +import java.util.List; + +import forge.ai.ComputerUtilCard; +import forge.ai.SpellAbilityAi; +import forge.game.Game; +import forge.game.card.Card; +import forge.game.card.CardFactoryUtil; +import forge.game.card.CardLists; +import forge.game.player.Player; +import forge.game.spellability.SpellAbility; +import forge.game.spellability.TargetRestrictions; +import forge.game.zone.ZoneType; +import forge.util.MyRandom; + +public class BidLifeAi extends SpellAbilityAi { + + @Override + protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) { + final Card source = sa.getHostCard(); + final Game game = source.getGame(); + TargetRestrictions tgt = sa.getTargetRestrictions(); + if (tgt != null) { + sa.resetTargets(); + if (tgt.canTgtCreature()) { + List list = CardLists.getTargetableCards(aiPlayer.getOpponent().getCardsIn(ZoneType.Battlefield), sa); + list = CardLists.getValidCards(list, tgt.getValidTgts(), source.getController(), source); + if (list.isEmpty()) { + return false; + } + Card c = ComputerUtilCard.getBestCreatureAI(list); + sa.getTargets().add(c); + } else if (tgt.getZone().contains(ZoneType.Stack)) { + if (game.getStack().isEmpty()) { + return false; + } + final SpellAbility topSA = game.getStack().peekAbility(); + if (!CardFactoryUtil.isCounterableBy(topSA.getHostCard(), sa) || aiPlayer.equals(topSA.getActivatingPlayer())) { + return false; + } + if (sa.canTargetSpellAbility(topSA)) { + sa.getTargets().add(topSA); + } else { + return false; + } + } + } + boolean chance = MyRandom.getRandom().nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn()); + return chance; + } + +} diff --git a/forge-game/src/main/java/forge/game/ability/ApiType.java b/forge-game/src/main/java/forge/game/ability/ApiType.java index f37cf168565..cbfb75d8590 100644 --- a/forge-game/src/main/java/forge/game/ability/ApiType.java +++ b/forge-game/src/main/java/forge/game/ability/ApiType.java @@ -21,6 +21,7 @@ public enum ApiType { Attach (AttachEffect.class), Balance (BalanceEffect.class), BecomesBlocked (BecomesBlockedEffect.class), + BidLife (BidLifeEffect.class), Bond (BondEffect.class), ChangeTargets (ChangeTargetsEffect.class), ChangeZone (ChangeZoneEffect.class), diff --git a/forge-game/src/main/java/forge/game/ability/effects/BidLifeEffect.java b/forge-game/src/main/java/forge/game/ability/effects/BidLifeEffect.java new file mode 100644 index 00000000000..0857a7382ac --- /dev/null +++ b/forge-game/src/main/java/forge/game/ability/effects/BidLifeEffect.java @@ -0,0 +1,81 @@ +package forge.game.ability.effects; + +import com.google.common.collect.Iterables; +import forge.game.ability.AbilityFactory; +import forge.game.ability.AbilityUtils; +import forge.game.ability.SpellAbilityEffect; +import forge.game.card.Card; +import forge.game.player.Player; +import forge.game.player.PlayerActionConfirmMode; +import forge.game.spellability.AbilitySub; +import forge.game.spellability.SpellAbility; + +import java.util.ArrayList; +import java.util.List; + +public class BidLifeEffect extends SpellAbilityEffect { + + /* (non-Javadoc) + * @see forge.card.abilityfactory.SpellEffect#getStackDescription(java.util.Map, forge.card.spellability.SpellAbility) + */ + @Override + protected String getStackDescription(SpellAbility sa) { + return "Bid Life"; + } + + /* (non-Javadoc) + * @see forge.card.abilityfactory.SpellEffect#resolve(java.util.Map, forge.card.spellability.SpellAbility) + */ + @Override + public void resolve(SpellAbility sa) { + final Card host = sa.getHostCard(); + final Player activator = sa.getActivatingPlayer(); + final List bidPlayers = new ArrayList(); + final int startBidding; + if (sa.hasParam("StartBidding")) { + String start = sa.getParam("StartBidding"); + if ("Any".equals(start)) { + startBidding = activator.getController().announceRequirements(sa, "Choose a starting bid", true); + } else { + startBidding = AbilityUtils.calculateAmount(host, start, sa); + } + } else { + startBidding = 0; + } + + if (sa.hasParam("OtherBidder")) { + bidPlayers.add(activator); + bidPlayers.addAll(AbilityUtils.getDefinedPlayers(host, sa.getParam("OtherBidder"), sa)); + } else{ + bidPlayers.addAll(activator.getGame().getPlayers()); + int pSize = bidPlayers.size(); + // start with the activator + while (bidPlayers.contains(activator) && !activator.equals(Iterables.getFirst(bidPlayers, null))) { + bidPlayers.add(pSize - 1, bidPlayers.remove(0)); + } + } + boolean willBid = true; + Player winner = activator; + int bid = startBidding; + while (willBid) { + willBid = false; + for (final Player p : bidPlayers) { + final boolean result = p.getController().confirmBidAction(sa, PlayerActionConfirmMode.BidLife, + "Do you want to top bid? Current Bid =" + String.valueOf(bid), bid, winner); + willBid |= result; + if (result) { // a different choose number + bid += p.getController().chooseNumber(sa, "Bid life:", 1, 9); + winner = p; + } + } + } + + host.setChosenNumber(bid); + host.addRemembered(winner); + final SpellAbility action = AbilityFactory.getAbility(host.getSVar(sa.getParam("BidSubAbility")), host); + action.setActivatingPlayer(sa.getActivatingPlayer()); + ((AbilitySub) action).setParent(sa); + AbilityUtils.resolve(action); + host.clearRemembered(); + } +} diff --git a/forge-game/src/main/java/forge/game/player/PlayerActionConfirmMode.java b/forge-game/src/main/java/forge/game/player/PlayerActionConfirmMode.java index b7b1b879ad7..1a9f937e7c2 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerActionConfirmMode.java +++ b/forge-game/src/main/java/forge/game/player/PlayerActionConfirmMode.java @@ -11,6 +11,7 @@ public enum PlayerActionConfirmMode { ChangeZoneToAltDestination, ChangeZoneFromAltSource, ChangeZoneGeneral, + BidLife, Tribute; // Ripple; diff --git a/forge-game/src/main/java/forge/game/player/PlayerController.java b/forge-game/src/main/java/forge/game/player/PlayerController.java index 0a66df230c2..3f56d286501 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerController.java +++ b/forge-game/src/main/java/forge/game/player/PlayerController.java @@ -143,6 +143,7 @@ public abstract class PlayerController { public abstract SpellAbility chooseSingleSpellForEffect(List spells, SpellAbility sa, String title); public abstract boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message); + public abstract boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode bidlife, String string, int bid, Player winner); public abstract boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message); public abstract boolean confirmTrigger(SpellAbility sa, Trigger regtrig, Map triggerParams, boolean isMandatory); public abstract boolean getWillPlayOnFirstTurn(boolean isFirstGame); @@ -234,8 +235,6 @@ public abstract class PlayerController { public abstract String chooseCardName(SpellAbility sa, Predicate cpp, String valid, String message); // better to have this odd method than those if playerType comparison in ChangeZone - public abstract Card chooseSingleCardForZoneChange(ZoneType destination, List origin, SpellAbility sa, List fetchList, String selectPrompt, boolean b, Player decider); - - + public abstract Card chooseSingleCardForZoneChange(ZoneType destination, List origin, SpellAbility sa, List fetchList, String selectPrompt, boolean b, Player decider); } \ No newline at end of file diff --git a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java index 05da108b20b..811d38d4993 100644 --- a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java +++ b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java @@ -173,6 +173,12 @@ public class PlayerControllerForTests extends PlayerController { return true; } + @Override + public boolean confirmBidAction(SpellAbility sa, + PlayerActionConfirmMode bidlife, String string, int bid, Player winner) { + return false; + } + @Override public boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message) { return true; @@ -600,4 +606,5 @@ public class PlayerControllerForTests extends PlayerController { // TODO Auto-generated method stub return ChangeZoneAi.chooseCardToHiddenOriginChangeZone(destination, origin, sa, fetchList, player, decider); } + } diff --git a/forge-gui/res/cardsfolder/i/illicit_auction.txt b/forge-gui/res/cardsfolder/i/illicit_auction.txt new file mode 100644 index 00000000000..b647251722c --- /dev/null +++ b/forge-gui/res/cardsfolder/i/illicit_auction.txt @@ -0,0 +1,9 @@ +Name:Illicit Auction +ManaCost:3 R R +Types:Sorcery +A:SP$ BidLife | Cost$ 3 R R | ValidTgts$ Creature | AILogic$ Min | AIBidMax$ 8 | BidSubAbility$ DBLoseLife | SpellDescription$ Each player may bid life for control of target creature. You start the bidding with a bid of 0. In turn order, each player may top the high bid. The bidding ends if the high bid stands. The high bidder loses life equal to the high bid and gains control of the creature. (This effect lasts indefinitely.) +SVar:DBLoseLife:DB$ LoseLife | Defined$ Remembered | LifeAmount$ X | References$ X | SubAbility$ DBControl +SVar:DBControl:DB$ GainControl | Defined$ Targeted | NewController$ Remembered +SVar:X:Count$ChosenNumber +SVar:Picture:http://www.wizards.com/global/images/magic/general/illicit_auction.jpg +Oracle:Each player may bid life for control of target creature. You start the bidding with a bid of 0. In turn order, each player may top the high bid. The bidding ends if the high bid stands. The high bidder loses life equal to the high bid and gains control of the creature. (This effect lasts indefinitely.) diff --git a/forge-gui/res/cardsfolder/m/mages_contest.txt b/forge-gui/res/cardsfolder/m/mages_contest.txt new file mode 100644 index 00000000000..6588fa50b1c --- /dev/null +++ b/forge-gui/res/cardsfolder/m/mages_contest.txt @@ -0,0 +1,9 @@ +Name:Mages' Contest +ManaCost:1 R R +Types:Instant +A:SP$ BidLife | Cost$ 1 R R | TargetType$ Spell | ValidTgts$ Card | TgtZone$ Stack | OtherBidder$ TargetedController | StartBidding$ 1 | AILogic$ Min | AIBidMax$ 8 | BidSubAbility$ DBLoseLife | SpellDescription$ You and target spell's controller bid life. You start the bidding with a bid of 1. In turn order, each player may top the high bid. The bidding ends if the high bid stands. The high bidder loses life equal to the high bid. If you win the bidding, counter that spell. +SVar:DBLoseLife:DB$ LoseLife | Defined$ Remembered | LifeAmount$ X | References$ X | SubAbility$ DBCounter +SVar:DBCounter:DB$ Counter | Defined$ Targeted | ConditionPlayerDefined$ Remembered | ConditionPlayerContains$ You +SVar:X:Count$ChosenNumber +SVar:Picture:http://www.wizards.com/global/images/magic/general/mages_contest.jpg +Oracle:You and target spell's controller bid life. You start the bidding with a bid of 1. In turn order, each player may top the high bid. The bidding ends if the high bid stands. The high bidder loses life equal to the high bid. If you win the bidding, counter that spell. diff --git a/forge-gui/res/cardsfolder/p/pains_reward.txt b/forge-gui/res/cardsfolder/p/pains_reward.txt new file mode 100644 index 00000000000..15868b8af05 --- /dev/null +++ b/forge-gui/res/cardsfolder/p/pains_reward.txt @@ -0,0 +1,9 @@ +Name:Pain's Reward +ManaCost:2 B +Types:Sorcery +A:SP$ BidLife | Cost$ 2 B | StartBidding$ Any | AILogic$ Min | AIBidMax$ 10 | BidSubAbility$ DBLoseLife | SpellDescription$ Each player may bid life. You start the bidding with a bid of any number. In turn order, each player may top the high bid. The bidding ends if the high bid stands. The high bidder loses life equal to the high bid and draws four cards. +SVar:DBLoseLife:DB$ LoseLife | Defined$ Remembered | LifeAmount$ X | References$ X | SubAbility$ DBDraw +SVar:DBDraw:DB$ Draw | Defined$ Remembered | NumCards$ 4 +SVar:X:Count$ChosenNumber +SVar:Picture:http://www.wizards.com/global/images/magic/general/pains_reward.jpg +Oracle:Each player may bid life. You start the bidding with a bid of any number. In turn order, each player may top the high bid. The bidding ends if the high bid stands. The high bidder loses life equal to the high bid and draws four cards. diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index a5719a264b2..3200d2d0179 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -317,6 +317,12 @@ public class PlayerControllerHuman extends PlayerController { return SGuiDialog.confirm(sa.getHostCard(), message); } + @Override + public boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode bidlife, + String string, int bid, Player winner) { + return SGuiDialog.confirm(sa.getHostCard(), string + " Highest Bidder " + winner); + } + @Override public boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message) { return SGuiDialog.confirm(hostCard, message); @@ -1032,4 +1038,5 @@ public class PlayerControllerHuman extends PlayerController { public Card chooseSingleCardForZoneChange(ZoneType destination, List origin, SpellAbility sa, List fetchList, String selectPrompt, boolean b, Player decider) { return chooseSingleEntityForEffect(fetchList, sa, selectPrompt, b, decider); } + }