mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
Initial pass of Exert (lots of things to be improved, but should be good enough to start scripting)
This commit is contained in:
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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}."),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
8
forge-gui/res/cardsfolder/upcoming/watchful_naga.txt
Normal file
8
forge-gui/res/cardsfolder/upcoming/watchful_naga.txt
Normal 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.
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user