Initial pass of Exert (lots of things to be improved, but should be good enough to start scripting)

This commit is contained in:
Sol
2017-04-16 20:00:42 +00:00
parent ea91d23bc2
commit 2f9319c420
12 changed files with 114 additions and 31 deletions

2
.gitattributes vendored
View File

@@ -716,6 +716,7 @@ forge-game/src/main/java/forge/game/trigger/TriggerDevoured.java -text
forge-game/src/main/java/forge/game/trigger/TriggerDiscarded.java svneol=native#text/plain
forge-game/src/main/java/forge/game/trigger/TriggerDrawn.java svneol=native#text/plain
forge-game/src/main/java/forge/game/trigger/TriggerEvolved.java -text
forge-game/src/main/java/forge/game/trigger/TriggerExerted.java -text
forge-game/src/main/java/forge/game/trigger/TriggerExploited.java -text
forge-game/src/main/java/forge/game/trigger/TriggerFight.java -text
forge-game/src/main/java/forge/game/trigger/TriggerFlippedCoin.java -text
@@ -16855,6 +16856,7 @@ forge-gui/res/cardsfolder/upcoming/trueheart_duelist.txt -text
forge-gui/res/cardsfolder/upcoming/unwavering_initiate.txt -text
forge-gui/res/cardsfolder/upcoming/vizier_of_remedies.txt -text
forge-gui/res/cardsfolder/upcoming/vizier_of_tumbling_sands.txt -text
forge-gui/res/cardsfolder/upcoming/watchful_naga.txt -text
forge-gui/res/cardsfolder/upcoming/wayward_servant.txt -text
forge-gui/res/cardsfolder/upcoming/winds_of_rebuke.txt -text
forge-gui/res/cardsfolder/upcoming/winged_shepherd.txt -text

View File

@@ -30,11 +30,7 @@ import forge.card.CardTypeView;
import forge.game.GameEntity;
import forge.game.ability.ApiType;
import forge.game.ability.effects.ProtectEffect;
import forge.game.card.Card;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CounterType;
import forge.game.card.*;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.combat.GlobalAttackRestrictions;
@@ -79,10 +75,6 @@ public class AiAttackController {
* Constructor for ComputerUtil_Attack2.
* </p>
*
* @param possibleAttackers
* a {@link forge.CardList} object.
* @param possibleBlockers
* a {@link forge.CardList} object.
*/
public AiAttackController(final Player ai) {
this.ai = ai;
@@ -157,9 +149,6 @@ public class AiAttackController {
* sortAttackers.
* </p>
*
* @param in
* a {@link forge.CardList} object.
* @return a {@link forge.CardList} object.
*/
public final static List<Card> sortAttackers(final List<Card> in) {
final List<Card> list = new ArrayList<Card>();
@@ -971,7 +960,7 @@ public class AiAttackController {
* @param attacker
* a {@link forge.game.card.Card} object.
* @param defenders
* a {@link forge.CardList} object.
* a object.
* @param combat
* a {@link forge.game.combat.Combat} object.
* @return a boolean.
@@ -1118,6 +1107,18 @@ public class AiAttackController {
return false; // don't attack
}
public static List<Card> exertAttackers(List<Card> attackers) {
List<Card> exerters = Lists.newArrayList();
for(Card c : attackers) {
// TODO Improve when the AI wants to use Exert powers
if (random.nextBoolean()) {
exerters.add(c);
}
}
return exerters;
}
/**
* Find a protection type that will make an attacker unblockable.
* @param sa ability belonging to ApiType.Protection
@@ -1181,5 +1182,4 @@ public class AiAttackController {
}
return null; //should never get here
}
} // end class ComputerUtil_Attack2

View File

@@ -232,10 +232,15 @@ public class PlayerControllerAi extends PlayerController {
return AiBlockController.orderBlockers(attacker, blockers);
}
@Override
public List<Card> exertAttackers(List<Card> attackers) {
return AiAttackController.exertAttackers(attackers);
}
@Override
public CardCollection orderBlocker(Card attacker, Card blocker, CardCollection oldBlockers) {
return AiBlockController.orderBlocker(attacker, blocker, oldBlockers);
};
}
@Override
public CardCollection orderAttackers(Card blocker, CardCollection attackers) {

View File

@@ -49,6 +49,7 @@ public enum Keyword {
EVOKE(KeywordWithCost.class, false, "You may cast this spell for its evoke cost. If you do, it's sacrificed when it enters the battlefield."),
EVOLVE(SimpleKeyword.class, false, "Whenever a creature enters the battlefield under your control, if that creature has greater power or toughness than this creature, put a +1/+1 counter on this creature."),
EXALTED(SimpleKeyword.class, false, "Whenever a creature you control attacks alone, that creature gets +1/+1 until end of turn."),
EXERTED(SimpleKeyword.class, true, "This creature won't untap during your next untap step."),
EXPLOIT(SimpleKeyword.class, false, "When this creature enters the battlefield, you may sacrifice a creature."),
EXTORT(SimpleKeyword.class, false, "Whenever you cast a spell, you may pay {W/B}. If you do, each opponent loses 1 life and you gain that much life."),
FABRICATE(KeywordWithAmount.class, false, "When this creature enters the battlefield, put {%1$d:+1/+1 counter} on it, or create {%1$d:1/1 colorless Servo artifact creature token}."),

View File

@@ -508,6 +508,18 @@ public class PhaseHandler implements java.io.Serializable {
}
} while (!success);
// Exert creatures here
List<Card> possibleExerters = CardLists.getKeyword(combat.getAttackers(),
"You may exert CARDNAME as it attacks.");
for(Card exerter : whoDeclares.getController().exertAttackers(possibleExerters)) {
exerter.addExtrinsicKeyword("Exerted");
final HashMap<String, Object> runParams = new HashMap<String, Object>();
runParams.put("Card", exerter);
runParams.put("Player", playerTurn);
game.getTriggerHandler().runTrigger(TriggerType.Exerted, runParams, false);
}
}
if (game.isGameOver()) { // they just like to close window at any moment

View File

@@ -17,17 +17,8 @@
*/
package forge.game.phase;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import forge.card.CardType;
import forge.game.Game;
import forge.game.GameEntity;
@@ -43,6 +34,9 @@ import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.collect.FCollection;
import java.util.*;
import java.util.Map.Entry;
/**
* <p>
* Untap class.
@@ -91,7 +85,8 @@ public class Untap extends Phase {
if (c.hasKeyword("CARDNAME doesn't untap during your untap step.")
|| c.hasKeyword("This card doesn't untap during your next untap step.")
|| c.hasKeyword("This card doesn't untap during your next two untap steps.")
|| c.hasKeyword("This card doesn't untap.")) {
|| c.hasKeyword("This card doesn't untap.")
|| c.hasKeyword("Exerted")) {
return false;
}
return true;
@@ -211,6 +206,7 @@ public class Untap extends Phase {
c.removeAllExtrinsicKeyword("HIDDEN This card doesn't untap during your next two untap steps.");
c.addHiddenExtrinsicKeyword("HIDDEN This card doesn't untap during your next untap step.");
}
c.removeAllExtrinsicKeyword("Exerted");
}
} // end doUntap

View File

@@ -57,7 +57,7 @@ public abstract class PlayerController {
Echo,
Multikicker,
Replicate,
CumulativeUpkeep;
CumulativeUpkeep,
}
public static enum BinaryChoiceType {
@@ -126,6 +126,7 @@ public abstract class PlayerController {
public abstract Player chooseStartingPlayer(boolean isFirstGame);
public abstract CardCollection orderBlockers(Card attacker, CardCollection blockers);
public abstract List<Card> exertAttackers(List<Card> attackers);
/**
* Add a card to a pre-existing blocking order.
* @param attacker the attacking creature.
@@ -179,7 +180,7 @@ public abstract class PlayerController {
public abstract int chooseNumber(SpellAbility sa, String title, List<Integer> values, Player relatedPlayer);
public int chooseNumber(SpellAbility sa, String string, int min, int max, Map<String, Object> params) {
return chooseNumber(sa, string, min, max);
};
}
public final boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice) { return chooseBinary(sa, question, kindOfChoice, (Boolean) null); }
public abstract boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice, Boolean defaultChioce);

View File

@@ -0,0 +1,47 @@
package forge.game.trigger;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
import java.util.HashMap;
import java.util.Map;
public class TriggerExerted extends Trigger {
/**
* <p>
* Constructor for Trigger.
* </p>
*
* @param params a {@link HashMap} object.
* @param host a {@link Card} object.
* @param intrinsic
*/
public TriggerExerted(Map<String, String> params, Card host, boolean intrinsic) {
super(params, host, intrinsic);
}
@Override
public boolean performTest(Map<String, Object> runParams2) {
final Card exerter = (Card) runParams2.get("Card");
if (this.mapParams.containsKey("ValidCard")) {
if (!exerter.isValid(this.mapParams.get("ValidCard").split(","), this.getHostCard().getController(),
this.getHostCard(), null)) {
return false;
}
}
return true;
}
@Override
public void setTriggeringObjects(SpellAbility sa) {
sa.setTriggeringObject("Card", this.getRunParams().get("Card"));
sa.setTriggeringObject("Player", this.getRunParams().get("Player"));
}
@Override
public String getImportantStackObjects(SpellAbility sa) {
StringBuilder sb = new StringBuilder();
sb.append("Exerted: ").append(sa.getTriggeringObject("Card"));
return sb.toString();
}
}

View File

@@ -47,6 +47,7 @@ public enum TriggerType {
Discarded(TriggerDiscarded.class),
Drawn(TriggerDrawn.class),
Evolved(TriggerEvolved.class),
Exerted(TriggerExerted.class),
Exploited(TriggerExploited.class),
Fight(TriggerFight.class),
FlippedCoin(TriggerFlippedCoin.class),
@@ -104,7 +105,7 @@ public enum TriggerType {
/**
* TODO: Write javadoc for this method.
* @param string
* @param value
* @return
*/
public static TriggerType smartValueOf(String value) {

View File

@@ -221,6 +221,11 @@ public class PlayerControllerForTests extends PlayerController {
return blockers;
}
@Override
public List<Card> exertAttackers(List<Card> attackers) {
return Lists.newArrayList(attackers);
}
@Override
public CardCollection orderBlocker(final Card attacker, final Card blocker, final CardCollection oldBlockers) {
final CardCollection allBlockers = new CardCollection(oldBlockers);

View File

@@ -0,0 +1,8 @@
Name:Watchful Naga
ManaCost:2 G
Types:Creature Naga Wizard
PT:2/2
K:You may exert CARDNAME as it attacks.
T:Mode$ Exerted | ValidCard$ Card.Self | Execute$ DBDraw | TriggerDescription$ When you exert CARDNAME, draw a card.
SVar:DBDraw:DB$ Draw | Defined$ TriggeredPlayer
Oracle:You may exert Watchful Naga as it attacks. When you do, draw a card.

View File

@@ -576,6 +576,11 @@ public class PlayerControllerHuman
return game.getCardList(getGui().order("Choose Damage Order for " + vAttacker, "Damaged First", CardView.getCollection(blockers), vAttacker));
}
@Override
public List<Card> exertAttackers(List<Card> attackers) {
return getGui().getChoices("Exert Attackers?", 0, attackers.size(), attackers);
}
@Override
public CardCollection orderBlocker(final Card attacker, final Card blocker, final CardCollection oldBlockers) {
final CardView vAttacker = CardView.get(attacker);