mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 10:18:01 +00:00
Merge branch 'ai' into 'master'
Add ReplaceDamageAi See merge request core-developers/forge!5512
This commit is contained in:
@@ -473,7 +473,7 @@ public class AiAttackController {
|
||||
if (totalAttack > 0 && ai.getLife() <= totalAttack && !ai.cantLoseForZeroOrLessLife()) {
|
||||
return true;
|
||||
}
|
||||
return ai.getPoisonCounters() + totalPoison > 9;
|
||||
return ai.canReceiveCounters(CounterEnumType.POISON) && ai.getPoisonCounters() + totalPoison > 9;
|
||||
}
|
||||
|
||||
private boolean doAssault(final Player ai) {
|
||||
@@ -1468,7 +1468,7 @@ public class AiAttackController {
|
||||
if (artifact != null) {
|
||||
return artifact;
|
||||
}
|
||||
return null;//should never get here
|
||||
return null; //should never get here
|
||||
}
|
||||
|
||||
private void doLightmineFieldAttackLogic(List<Card> attackersLeft, int numForcedAttackers, boolean playAggro) {
|
||||
|
||||
@@ -770,7 +770,7 @@ public class ComputerUtil {
|
||||
final int considerSacThreshold = getAIPreferenceParameter(host, "CreatureEvalThreshold", source);
|
||||
|
||||
if ("OpponentOnly".equals(source.getParam("AILogic"))) {
|
||||
if(!source.getActivatingPlayer().isOpponentOf(ai)) {
|
||||
if (!source.getActivatingPlayer().isOpponentOf(ai)) {
|
||||
return sacrificed; // sacrifice none
|
||||
}
|
||||
} else if ("DesecrationDemon".equals(source.getParam("AILogic"))) {
|
||||
@@ -1719,7 +1719,7 @@ public class ComputerUtil {
|
||||
final Player p = (Player) o;
|
||||
|
||||
if (source.hasKeyword(Keyword.INFECT)) {
|
||||
if (ComputerUtilCombat.predictDamageTo(p, dmg, source, false) >= p.getPoisonCounters()) {
|
||||
if (p.canReceiveCounters(CounterEnumType.POISON) && ComputerUtilCombat.predictDamageTo(p, dmg, source, false) >= 10 - p.getPoisonCounters()) {
|
||||
threatened.add(p);
|
||||
}
|
||||
} else if (ComputerUtilCombat.predictDamageTo(p, dmg, source, false) >= p.getLife()) {
|
||||
|
||||
@@ -72,7 +72,7 @@ public class ComputerUtilAbility {
|
||||
if (!player.getCardsIn(ZoneType.Library).isEmpty()) {
|
||||
all.add(player.getCardsIn(ZoneType.Library).get(0));
|
||||
}
|
||||
for(Player p : game.getPlayers()) {
|
||||
for (Player p : game.getPlayers()) {
|
||||
all.addAll(p.getCardsIn(ZoneType.Exile));
|
||||
all.addAll(p.getCardsIn(ZoneType.Battlefield));
|
||||
}
|
||||
|
||||
@@ -436,7 +436,7 @@ public class ComputerUtilCard {
|
||||
// For ability of Oracle en-Vec, return the first card that are going to attack next turn
|
||||
public static Card getBestCreatureToAttackNextTurnAI(final Player aiPlayer, final Iterable<Card> list) {
|
||||
AiController aic = ((PlayerControllerAi)aiPlayer.getController()).getAi();
|
||||
for(final Card card : list) {
|
||||
for (final Card card : list) {
|
||||
if (aic.getPredictedCombatNextTurn().isAttacking(card)) {
|
||||
return card;
|
||||
}
|
||||
@@ -832,7 +832,7 @@ public class ComputerUtilCard {
|
||||
}
|
||||
}
|
||||
// same for Trigger that does make Tokens
|
||||
for(Trigger t:c.getTriggers()){
|
||||
for (Trigger t :c .getTriggers()) {
|
||||
SpellAbility sa = t.ensureAbility();
|
||||
if (sa != null) {
|
||||
if (sa.getApi() != ApiType.Token || !sa.hasParam("TokenTypes")) {
|
||||
@@ -851,7 +851,7 @@ public class ComputerUtilCard {
|
||||
}
|
||||
}
|
||||
// special rule for Fabricate and Servo
|
||||
if(c.hasStartOfKeyword(Keyword.FABRICATE.toString())){
|
||||
if (c.hasStartOfKeyword(Keyword.FABRICATE.toString())) {
|
||||
Integer count = typesInDeck.get("Servo");
|
||||
if (count == null) {
|
||||
count = 0;
|
||||
@@ -1694,7 +1694,7 @@ public class ComputerUtilCard {
|
||||
pumped.addHiddenExtrinsicKeywords(timestamp, 0, hiddenKws);
|
||||
}
|
||||
Set<CounterType> types = c.getCounters().keySet();
|
||||
for(CounterType ct : types) {
|
||||
for (CounterType ct : types) {
|
||||
pumped.addCounterFireNoEvents(ct, c.getCounters(ct), ai, sa, true, null);
|
||||
}
|
||||
//Copies tap-state and extra keywords (auras, equipment, etc.)
|
||||
|
||||
@@ -302,28 +302,26 @@ public class ComputerUtilCombat {
|
||||
public static int lifeThatWouldRemain(final Player ai, final Combat combat) {
|
||||
int damage = 0;
|
||||
|
||||
final List<Card> attackers = combat.getAttackersOf(ai);
|
||||
final List<Card> unblocked = Lists.newArrayList();
|
||||
if (ai.canLoseLife()) {
|
||||
final List<Card> attackers = combat.getAttackersOf(ai);
|
||||
final List<Card> unblocked = Lists.newArrayList();
|
||||
|
||||
for (final Card attacker : attackers) {
|
||||
final List<Card> blockers = combat.getBlockers(attacker);
|
||||
for (final Card attacker : attackers) {
|
||||
final List<Card> blockers = combat.getBlockers(attacker);
|
||||
|
||||
if ((blockers.size() == 0)
|
||||
|| attacker.hasKeyword("You may have CARDNAME assign its combat damage "
|
||||
+ "as though it weren't blocked.")) {
|
||||
unblocked.add(attacker);
|
||||
} else if (attacker.hasKeyword(Keyword.TRAMPLE)
|
||||
&& (getAttack(attacker) > totalShieldDamage(attacker, blockers))) {
|
||||
if (!attacker.hasKeyword(Keyword.INFECT)) {
|
||||
damage += getAttack(attacker) - totalShieldDamage(attacker, blockers);
|
||||
if ((blockers.size() == 0)
|
||||
|| attacker.hasKeyword("You may have CARDNAME assign its combat damage "
|
||||
+ "as though it weren't blocked.")) {
|
||||
unblocked.add(attacker);
|
||||
} else if (attacker.hasKeyword(Keyword.TRAMPLE)
|
||||
&& (getAttack(attacker) > totalShieldDamage(attacker, blockers))) {
|
||||
if (!attacker.hasKeyword(Keyword.INFECT)) {
|
||||
damage += getAttack(attacker) - totalShieldDamage(attacker, blockers);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
damage += sumDamageIfUnblocked(unblocked, ai);
|
||||
|
||||
if (!ai.canLoseLife()) {
|
||||
damage = 0;
|
||||
damage += sumDamageIfUnblocked(unblocked, ai);
|
||||
}
|
||||
|
||||
return ai.getLife() - damage;
|
||||
@@ -671,7 +669,6 @@ public class ComputerUtilCombat {
|
||||
|
||||
int flankingMagnitude = 0;
|
||||
if (attacker.hasKeyword(Keyword.FLANKING) && !blocker.hasKeyword(Keyword.FLANKING)) {
|
||||
|
||||
flankingMagnitude = attacker.getAmountOfKeyword(Keyword.FLANKING);
|
||||
|
||||
if (flankingMagnitude >= blocker.getNetToughness()) {
|
||||
|
||||
@@ -220,16 +220,16 @@ public class PlayerControllerAi extends PlayerController {
|
||||
if (delayedReveal != null) {
|
||||
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
|
||||
}
|
||||
FCollection<T> remaining = new FCollection<>(optionList);
|
||||
List<T> selecteds = new ArrayList<>();
|
||||
T selected;
|
||||
do {
|
||||
selected = chooseSingleEntityForEffect(remaining, null, sa, title, selecteds.size()>=min, targetedPlayer, params);
|
||||
if ( selected != null ) {
|
||||
remaining.remove(selected);
|
||||
selecteds.add(selected);
|
||||
}
|
||||
} while ( (selected != null ) && (selecteds.size() < max) );
|
||||
FCollection<T> remaining = new FCollection<>(optionList);
|
||||
List<T> selecteds = new ArrayList<>();
|
||||
T selected;
|
||||
do {
|
||||
selected = chooseSingleEntityForEffect(remaining, null, sa, title, selecteds.size()>=min, targetedPlayer, params);
|
||||
if ( selected != null ) {
|
||||
remaining.remove(selected);
|
||||
selecteds.add(selected);
|
||||
}
|
||||
} while ( (selected != null ) && (selecteds.size() < max) );
|
||||
return selecteds;
|
||||
}
|
||||
|
||||
@@ -361,8 +361,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
for (Card c: topN) {
|
||||
if (ComputerUtil.scryWillMoveCardToBottomOfLibrary(player, c)) {
|
||||
toBottom.add(c);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
toTop.add(c);
|
||||
}
|
||||
}
|
||||
@@ -525,8 +524,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
if (copySA instanceof Spell) {
|
||||
Spell spell = (Spell) copySA;
|
||||
((PlayerControllerAi) player.getController()).getAi().canPlayFromEffectAI(spell, true, true);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
getAi().canPlaySa(copySA);
|
||||
}
|
||||
}
|
||||
@@ -884,9 +882,8 @@ public class PlayerControllerAi extends PlayerController {
|
||||
byte chosenColorMask = MagicColor.fromName(c);
|
||||
if ((colors.getColor() & chosenColorMask) != 0) {
|
||||
return chosenColorMask;
|
||||
} else {
|
||||
return Iterables.getFirst(colors, (byte)0);
|
||||
}
|
||||
return Iterables.getFirst(colors, (byte)0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -905,9 +902,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
if ((colors.getColor() & chosenColorMask) != 0) {
|
||||
return chosenColorMask;
|
||||
}
|
||||
else {
|
||||
return Iterables.getFirst(colors, MagicColor.WHITE);
|
||||
}
|
||||
return Iterables.getFirst(colors, MagicColor.WHITE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1370,8 +1365,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int chooseNumberForKeywordCost(SpellAbility sa, Cost cost, KeywordInterface keyword, String prompt,
|
||||
int max) {
|
||||
public int chooseNumberForKeywordCost(SpellAbility sa, Cost cost, KeywordInterface keyword, String prompt, int max) {
|
||||
// TODO: improve the logic depending on the keyword and the playability of the cost-modified SA (enough targets present etc.)
|
||||
int chosenAmount = 0;
|
||||
|
||||
|
||||
@@ -142,9 +142,9 @@ public enum SpellApiToAi {
|
||||
.put(ApiType.Repeat, RepeatAi.class)
|
||||
.put(ApiType.RepeatEach, RepeatEachAi.class)
|
||||
.put(ApiType.ReplaceEffect, AlwaysPlayAi.class)
|
||||
.put(ApiType.ReplaceDamage, AlwaysPlayAi.class)
|
||||
.put(ApiType.ReplaceDamage, ReplaceDamageAi.class)
|
||||
.put(ApiType.ReplaceMana, AlwaysPlayAi.class)
|
||||
.put(ApiType.ReplaceSplitDamage, AlwaysPlayAi.class)
|
||||
.put(ApiType.ReplaceSplitDamage, ReplaceDamageAi.class)
|
||||
.put(ApiType.ReplaceToken, AlwaysPlayAi.class)
|
||||
.put(ApiType.RestartGame, RestartGameAi.class)
|
||||
.put(ApiType.Reveal, RevealAi.class)
|
||||
|
||||
@@ -78,8 +78,7 @@ public class AnimateAi extends SpellAbilityAi {
|
||||
SpellAbility topStack = game.getStack().peekAbility();
|
||||
if (topStack.getApi() == ApiType.Sacrifice) {
|
||||
final String valid = topStack.getParamOrDefault("SacValid", "Card.Self");
|
||||
String num = topStack.getParam("Amount");
|
||||
num = (num == null) ? "1" : num;
|
||||
String num = topStack.getParamOrDefault("Amount", "1");
|
||||
final int nToSac = AbilityUtils.calculateAmount(topStack.getHostCard(), num, topStack);
|
||||
CardCollection list = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), valid.split(","),
|
||||
ai.getWeakestOpponent(), topStack.getHostCard(), topStack);
|
||||
|
||||
@@ -178,7 +178,7 @@ public class CharmAi extends SpellAbilityAi {
|
||||
} else if (ai.canGainLife() && aiLife <= 5) {
|
||||
// critical Life try to gain more
|
||||
chosenList.add(gain);
|
||||
} else if(!ai.canGainLife() && aiLife == 14 ) {
|
||||
} else if (!ai.canGainLife() && aiLife == 14 ) {
|
||||
// ai cant gain life, but try to avoid falling to 13
|
||||
// but if a opponent does control Tainted Remedy its irrelevant
|
||||
chosenList.add(oppTainted ? lose : gain);
|
||||
|
||||
@@ -67,7 +67,7 @@ public class ChooseSourceAi extends SpellAbilityAi {
|
||||
if (sa.getParam("AILogic").equals("NeedsPrevention")) {
|
||||
if (!game.getStack().isEmpty()) {
|
||||
final SpellAbility topStack = game.getStack().peekAbility();
|
||||
if (sa.hasParam("Choices") && !topStack.getHostCard().isValid(sa.getParam("Choices"), ai, source, sa)) {
|
||||
if (sa.hasParam("Choices") && !topStack.matchesValid(topStack.getHostCard(), sa.getParam("Choices").split(","))) {
|
||||
return false;
|
||||
}
|
||||
final ApiType threatApi = topStack.getApi();
|
||||
@@ -111,8 +111,6 @@ public class ChooseSourceAi extends SpellAbilityAi {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public Card chooseSingleCard(final Player aiChoser, SpellAbility sa, Iterable<Card> options, boolean isOptional, Player targetedPlayer, Map<String, Object> params) {
|
||||
if ("NeedsPrevention".equals(sa.getParam("AILogic"))) {
|
||||
@@ -178,7 +176,7 @@ public class ChooseSourceAi extends SpellAbilityAi {
|
||||
final Card source = si.getSourceCard();
|
||||
final SpellAbility abilityOnStack = si.getSpellAbility(true);
|
||||
|
||||
if (sa.hasParam("Choices") && !abilityOnStack.getHostCard().isValid(sa.getParam("Choices"), ai, sa.getHostCard(), sa)) {
|
||||
if (sa.hasParam("Choices") && !abilityOnStack.matchesValid(source, sa.getParam("Choices").split(","))) {
|
||||
continue;
|
||||
}
|
||||
final ApiType threatApi = abilityOnStack.getApi();
|
||||
|
||||
@@ -419,15 +419,15 @@ public class CountersPutAi extends SpellAbilityAi {
|
||||
oa.setActivatingPlayer(ai);
|
||||
CardCollection targets = CardLists.getTargetableCards(ai.getOpponents().getCreaturesInPlay(), oa);
|
||||
|
||||
if (!targets.isEmpty()){
|
||||
if (!targets.isEmpty()) {
|
||||
boolean canSurvive = false;
|
||||
for (Card humanCreature : targets) {
|
||||
if (!FightAi.canKill(humanCreature, source, 0)){
|
||||
if (!FightAi.canKill(humanCreature, source, 0)) {
|
||||
canSurvive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!canSurvive){
|
||||
if (!canSurvive) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
dmg = 2;
|
||||
} else if ("OpponentHasCreatures".equals(logic)) {
|
||||
for (Player opp : ai.getOpponents()) {
|
||||
if (!opp.getCreaturesInPlay().isEmpty()){
|
||||
if (!opp.getCreaturesInPlay().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -287,7 +287,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
}
|
||||
|
||||
if ((damage.equals("X") && sa.getSVar(damage).equals("Count$xPaid")) ||
|
||||
sourceName.equals("Crater's Claws")){
|
||||
sourceName.equals("Crater's Claws")) {
|
||||
// If I can kill my target by paying less mana, do it
|
||||
if (sa.usesTargeting() && !sa.getTargets().isTargetingAnyPlayer() && !sa.isDividedAsYouChoose()) {
|
||||
int actualPay = dmg;
|
||||
@@ -330,7 +330,6 @@ public class DamageDealAi extends DamageAiBase {
|
||||
*/
|
||||
private Card dealDamageChooseTgtC(final Player ai, final SpellAbility sa, final int d, final boolean noPrevention,
|
||||
final Player pl, final boolean mandatory) {
|
||||
|
||||
// wait until stack is empty (prevents duplicate kills)
|
||||
if (!sa.isTrigger() && !ai.getGame().getStack().isEmpty()) {
|
||||
//TODO:all removal APIs require a check to prevent duplicate kill/bounce/exile/etc.
|
||||
@@ -345,7 +344,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
final Player activator = sa.getActivatingPlayer();
|
||||
final Card source = sa.getHostCard();
|
||||
final Game game = source.getGame();
|
||||
List<Card> hPlay = getTargetableCards(ai, sa, pl, tgt, activator, source, game);
|
||||
List<Card> hPlay = getTargetableCards(mandatory ? pl : ai, sa, pl, tgt, activator, source, game);
|
||||
|
||||
// Filter MustTarget requirements
|
||||
StaticAbilityMustTarget.filterMustTargetCards(ai, hPlay, sa);
|
||||
@@ -531,7 +530,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
|
||||
if ("PowerDmg".equals(logic)) {
|
||||
// check if it is better to target the player instead, the original target is already set in PumpAi.pumpTgtAI()
|
||||
if (tgt.canTgtCreatureAndPlayer() && shouldTgtP(ai, sa, dmg, noPrevention)){
|
||||
if (tgt.canTgtCreatureAndPlayer() && shouldTgtP(ai, sa, dmg, noPrevention)) {
|
||||
sa.resetTargets();
|
||||
sa.getTargets().add(enemy);
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ public class DelayedTriggerAi extends SpellAbilityAi {
|
||||
}
|
||||
});
|
||||
|
||||
if(count == 0) {
|
||||
if (count == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -28,6 +28,8 @@ import forge.game.keyword.Keyword;
|
||||
import forge.game.phase.PhaseHandler;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerCollection;
|
||||
import forge.game.player.PlayerPredicates;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Aggregates;
|
||||
@@ -43,7 +45,7 @@ public class ManaEffectAi extends SpellAbilityAi {
|
||||
@Override
|
||||
protected boolean checkAiLogic(Player ai, SpellAbility sa, String aiLogic) {
|
||||
if (aiLogic.startsWith("ManaRitual")) {
|
||||
return doManaRitualLogic(ai, sa);
|
||||
return doManaRitualLogic(ai, sa, false);
|
||||
} else if ("Always".equals(aiLogic)) {
|
||||
return true;
|
||||
}
|
||||
@@ -110,14 +112,32 @@ public class ManaEffectAi extends SpellAbilityAi {
|
||||
*/
|
||||
@Override
|
||||
protected boolean doTriggerAINoCost(Player aiPlayer, SpellAbility sa, boolean mandatory) {
|
||||
final String logic = sa.getParamOrDefault("AILogic", "");
|
||||
if (logic.startsWith("ManaRitual")) {
|
||||
return doManaRitualLogic(aiPlayer, sa, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Dark Ritual and other similar instants/sorceries that add mana to mana pool
|
||||
public static boolean doManaRitualLogic(Player ai, SpellAbility sa) {
|
||||
public static boolean doManaRitualLogic(Player ai, SpellAbility sa, boolean fromTrigger) {
|
||||
final Card host = sa.getHostCard();
|
||||
final String logic = sa.getParamOrDefault("AILogic", "");
|
||||
|
||||
if (sa.usesTargeting()) { // Rousing Refrain
|
||||
PlayerCollection targetableOpps = ai.getOpponents().filter(PlayerPredicates.isTargetableBy(sa));
|
||||
if (targetableOpps.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
Player mostCards = targetableOpps.max(PlayerPredicates.compareByZoneSize(ZoneType.Hand));
|
||||
sa.resetTargets();
|
||||
sa.getTargets().add(mostCards);
|
||||
if (fromTrigger) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
CardCollection manaSources = ComputerUtilMana.getAvailableManaSources(ai, true);
|
||||
int numManaSrcs = manaSources.size();
|
||||
int manaReceived = sa.hasParam("Amount") ? AbilityUtils.calculateAmount(host, sa.getParam("Amount"), sa) : 1;
|
||||
|
||||
@@ -34,8 +34,6 @@ import forge.game.phase.PhaseHandler;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerActionConfirmMode;
|
||||
import forge.game.player.PlayerCollection;
|
||||
import forge.game.player.PlayerPredicates;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
@@ -512,15 +510,6 @@ public class PumpAi extends PumpAiBase {
|
||||
}
|
||||
|
||||
return false;
|
||||
} else if ("ManaRitual".equals(sa.getParam("AILogic"))) {
|
||||
PlayerCollection targetableOpps = ai.getOpponents().filter(PlayerPredicates.isTargetableBy(sa));
|
||||
if (targetableOpps.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
Player mostCards = targetableOpps.max(PlayerPredicates.compareByZoneSize(ZoneType.Hand));
|
||||
sa.resetTargets();
|
||||
sa.getTargets().add(mostCards);
|
||||
return mandatory || ManaEffectAi.doManaRitualLogic(ai, sa.getSubAbility());
|
||||
}
|
||||
|
||||
if (isFight) {
|
||||
|
||||
@@ -114,7 +114,7 @@ public class RearrangeTopOfLibraryAi extends SpellAbilityAi {
|
||||
if (!top.isLand() && cmc - maxCastable >= uncastableCMCThreshold) {
|
||||
// Can't cast in the foreseeable future. Shuffle if doing it to ourselves or an ally, otherwise keep it
|
||||
return !p.isOpponentOf(player);
|
||||
} else if (top.isLand() && landsOTB <= minLandsToScryLandsAway){
|
||||
} else if (top.isLand() && landsOTB <= minLandsToScryLandsAway) {
|
||||
// We don't want to give the opponent a free land if his land count is low
|
||||
return p.isOpponentOf(player);
|
||||
}
|
||||
|
||||
@@ -52,14 +52,14 @@ public class RepeatEachAi extends SpellAbilityAi {
|
||||
}
|
||||
} else if ("OpponentHasCreatures".equals(logic)) { //TODO convert this to NeedsToPlayVar
|
||||
for (Player opp : aiPlayer.getOpponents()) {
|
||||
if (!opp.getCreaturesInPlay().isEmpty()){
|
||||
if (!opp.getCreaturesInPlay().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if ("OpponentHasMultipleCreatures".equals(logic)) {
|
||||
for (Player opp : aiPlayer.getOpponents()) {
|
||||
if (opp.getCreaturesInPlay().size() > 1){
|
||||
if (opp.getCreaturesInPlay().size() > 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
34
forge-ai/src/main/java/forge/ai/ability/ReplaceDamageAi.java
Normal file
34
forge-ai/src/main/java/forge/ai/ability/ReplaceDamageAi.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import forge.ai.ComputerUtilCard;
|
||||
import forge.ai.SpellAbilityAi;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.keyword.Keyword;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
|
||||
public class ReplaceDamageAi extends SpellAbilityAi {
|
||||
|
||||
@Override
|
||||
protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable<Card> options, boolean isOptional, Player targetedPlayer, Map<String, Object> params) {
|
||||
for (Card c : options) {
|
||||
// TODO check if enough shields to prevent trigger
|
||||
if (c.hasSVar("MustBeBlocked")) {
|
||||
return c;
|
||||
}
|
||||
// TODO check if target can receive counters
|
||||
if (c.hasKeyword(Keyword.INFECT)) {
|
||||
return c;
|
||||
}
|
||||
if (c.isCommander()) {
|
||||
return c;
|
||||
}
|
||||
if (c.hasKeyword(Keyword.LIFELINK) || c.hasSVar("LikeLifeLink")) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return ComputerUtilCard.getBestAI(options);
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ public class SetStateAi extends SpellAbilityAi {
|
||||
final String logic = sa.getParamOrDefault("AILogic", "");
|
||||
final Game game = source.getGame();
|
||||
|
||||
if("Transform".equals(mode)) {
|
||||
if ("Transform".equals(mode)) {
|
||||
if (!sa.usesTargeting()) {
|
||||
// no Transform with Defined which is not Self
|
||||
if (!source.canTransform()) {
|
||||
|
||||
@@ -35,7 +35,7 @@ public class TapAi extends TapAiBase {
|
||||
// Don't tap down after blockers
|
||||
return false;
|
||||
}
|
||||
} else if (!SpellAbilityAi.playReusable(ai, sa)){
|
||||
} else if (!SpellAbilityAi.playReusable(ai, sa)) {
|
||||
// Generally don't want to tap things with an Instant during Players turn outside of combat
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -230,8 +230,7 @@ public class TokenAi extends SpellAbilityAi {
|
||||
}
|
||||
final int nTokens = AbilityUtils.calculateAmount(sa.getHostCard(), tokenAmount, sa);
|
||||
final String valid = topStack.getParamOrDefault("SacValid", "Card.Self");
|
||||
String num = sa.getParam("Amount");
|
||||
num = (num == null) ? "1" : num;
|
||||
String num = sa.getParamOrDefault("Amount", "1");
|
||||
final int nToSac = AbilityUtils.calculateAmount(topStack.getHostCard(), num, topStack);
|
||||
CardCollection list = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), valid.split(","),
|
||||
ai.getWeakestOpponent(), topStack.getHostCard(), sa);
|
||||
|
||||
@@ -45,7 +45,7 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventGameOutcome ev) {
|
||||
for(String outcome : ev.result.getOutcomeStrings()) {
|
||||
for (String outcome : ev.result.getOutcomeStrings()) {
|
||||
log.add(GameLogEntryType.GAME_OUTCOME, outcome);
|
||||
}
|
||||
return generateSummary(ev.history);
|
||||
|
||||
@@ -2550,7 +2550,7 @@ public class AbilityUtils {
|
||||
int colorOcurrencices = 0;
|
||||
byte colorCode = ManaAtom.fromName(sq[1]);
|
||||
for (Card c0 : cards) {
|
||||
for (ManaCostShard sh : c0.getManaCost()){
|
||||
for (ManaCostShard sh : c0.getManaCost()) {
|
||||
if (sh.isColor(colorCode))
|
||||
colorOcurrencices++;
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ public enum ApiType {
|
||||
private static final Map<String, ApiType> allValues = new HashMap<>();
|
||||
|
||||
static {
|
||||
for(ApiType t : ApiType.values()) {
|
||||
for (ApiType t : ApiType.values()) {
|
||||
allValues.put(t.name().toLowerCase(), t);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ public class AmassEffect extends TokenEffectBase {
|
||||
tgtCards = pc.chooseCardsForEffect(tgtCards, sa, Localizer.getInstance().getMessage("lblChooseAnArmy"), 1, 1, false, params);
|
||||
|
||||
GameEntityCounterTable table = new GameEntityCounterTable();
|
||||
for(final Card tgtCard : tgtCards) {
|
||||
for (final Card tgtCard : tgtCards) {
|
||||
tgtCard.addCounter(CounterEnumType.P1P1, amount, activator, sa, true, table);
|
||||
game.updateLastStateForCard(tgtCard);
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ public class ChangeTargetsEffect extends SpellAbilityEffect {
|
||||
SpellAbility changingTgtSA = changingTgtSI.getSpellAbility(true);
|
||||
if (changingTgtSA.usesTargeting()) {
|
||||
// random target and DefinedMagnet works on single targets
|
||||
if (sa.hasParam("RandomTarget")){
|
||||
if (sa.hasParam("RandomTarget")) {
|
||||
int div = changingTgtSA.getTotalDividedValue();
|
||||
changingTgtSA.resetTargets();
|
||||
List<GameEntity> candidates = changingTgtSA.getTargetRestrictions().getAllCandidates(changingTgtSA, true);
|
||||
@@ -116,7 +116,7 @@ public class ChangeTargetsEffect extends SpellAbilityEffect {
|
||||
|
||||
changingTgtSI.updateTarget(changingTgtSA.getTargets(), sa.getHostCard());
|
||||
}
|
||||
else if (sa.hasParam("DefinedMagnet")){
|
||||
else if (sa.hasParam("DefinedMagnet")) {
|
||||
GameObject newTarget = Iterables.getFirst(getDefinedCardsOrTargeted(sa, "DefinedMagnet"), null);
|
||||
if (newTarget != null && changingTgtSA.canTarget(newTarget)) {
|
||||
int div = changingTgtSA.getTotalDividedValue();
|
||||
|
||||
@@ -222,7 +222,7 @@ public class CharmEffect extends SpellAbilityEffect {
|
||||
});
|
||||
|
||||
for (AbilitySub sub : chosen) {
|
||||
// Clone the chosen, just in case the some subAb gets chosen multiple times
|
||||
// Clone the chosen, just in case the same subAb gets chosen multiple times
|
||||
AbilitySub clone = (AbilitySub)sub.copy();
|
||||
|
||||
// update ActivatingPlayer
|
||||
@@ -250,7 +250,6 @@ public class CharmEffect extends SpellAbilityEffect {
|
||||
// add Clone to Tail of sa
|
||||
sa.appendSubAbility(clone);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
host.setNamedCard(chosen);
|
||||
if(!randomChoice) {
|
||||
if (!randomChoice) {
|
||||
p.getGame().getAction().notifyOfValue(sa, host, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), chosen), p);
|
||||
p.setNamedCard(chosen);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public class ControlSpellEffect extends SpellAbilityEffect {
|
||||
|
||||
sb.append(newController).append(" gains control of ");
|
||||
|
||||
for(SpellAbility spell : getTargetSpells(sa)) {
|
||||
for (SpellAbility spell : getTargetSpells(sa)) {
|
||||
Card c = spell.getHostCard();
|
||||
sb.append(" ");
|
||||
if (c.isFaceDown()) {
|
||||
|
||||
@@ -160,7 +160,7 @@ public class CopySpellAbilityEffect extends SpellAbilityEffect {
|
||||
if (sa.hasParam("MayChooseTarget")) {
|
||||
copy.setMayChooseNewTargets(true);
|
||||
}
|
||||
if (sa.hasParam("RandomTarget")){
|
||||
if (sa.hasParam("RandomTarget")) {
|
||||
List<GameEntity> candidates = copy.getTargetRestrictions().getAllCandidates(chosenSA, true);
|
||||
if (sa.hasParam("RandomTargetRestriction")) {
|
||||
candidates.removeIf(new Predicate<GameEntity>() {
|
||||
|
||||
@@ -37,7 +37,7 @@ public class CountersNoteEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
private void noteCounters(Card notee, Card source) {
|
||||
for(Entry<CounterType, Integer> counter : notee.getCounters().entrySet()) {
|
||||
for (Entry<CounterType, Integer> counter : notee.getCounters().entrySet()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(NOTE_COUNTERS).append(counter.getKey().getName());
|
||||
source.setSVar(sb.toString(), counter.getValue().toString());
|
||||
@@ -45,7 +45,7 @@ public class CountersNoteEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
private void loadCounters(Card notee, Card source, final Player p, final SpellAbility sa, GameEntityCounterTable table) {
|
||||
for(Entry<String, String> svar : source.getSVars().entrySet()) {
|
||||
for (Entry<String, String> svar : source.getSVars().entrySet()) {
|
||||
String key = svar.getKey();
|
||||
if (key.startsWith(NOTE_COUNTERS)) {
|
||||
notee.addCounter(
|
||||
|
||||
@@ -35,7 +35,7 @@ public class DamageAllEffect extends DamageBaseEffect {
|
||||
|
||||
if (!definedSources.isEmpty() && definedSources.get(0) != sa.getHostCard()) {
|
||||
sb.append(definedSources.get(0).toString()).append(" deals");
|
||||
} else if ("ParentTarget".equals(definedStr)){
|
||||
} else if ("ParentTarget".equals(definedStr)) {
|
||||
sb.append("Target creature deals");
|
||||
} else {
|
||||
sb.append("Deals");
|
||||
|
||||
@@ -96,7 +96,7 @@ public class DebuffEffect extends SpellAbilityEffect {
|
||||
for (final String kw : kws) {
|
||||
// Check if some of the Keywords are Protection from <color>
|
||||
if (!ProtectionFromColor && kw.startsWith("Protection from ")) {
|
||||
for(byte col : MagicColor.WUBRG) {
|
||||
for (byte col : MagicColor.WUBRG) {
|
||||
final String colString = MagicColor.toLongString(col);
|
||||
if (kw.endsWith(colString.toLowerCase())) {
|
||||
ProtectionFromColor = true;
|
||||
@@ -110,7 +110,7 @@ public class DebuffEffect extends SpellAbilityEffect {
|
||||
if (ProtectionFromColor && tgtC.hasKeyword(allColors)) {
|
||||
final List<String> allColorsProtect = Lists.newArrayList();
|
||||
|
||||
for(byte col : MagicColor.WUBRG) {
|
||||
for (byte col : MagicColor.WUBRG) {
|
||||
allColorsProtect.add("Protection from " + MagicColor.toLongString(col).toLowerCase());
|
||||
}
|
||||
allColorsProtect.removeAll(kws);
|
||||
@@ -123,7 +123,7 @@ public class DebuffEffect extends SpellAbilityEffect {
|
||||
if (ProtectionFromColor && tgtC.hasKeyword(allColors)) {
|
||||
final List<String> allColorsProtect = Lists.newArrayList();
|
||||
|
||||
for(byte col : MagicColor.WUBRG) {
|
||||
for (byte col : MagicColor.WUBRG) {
|
||||
final String colString = MagicColor.toLongString(col);
|
||||
if (!kws.contains("Protection from " + colString)) {
|
||||
allColorsProtect.add(
|
||||
|
||||
@@ -330,7 +330,7 @@ public class EffectEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
private void noteCounters(Card notee, Card source) {
|
||||
for(Map.Entry<CounterType, Integer> counter : notee.getCounters().entrySet()) {
|
||||
for (Map.Entry<CounterType, Integer> counter : notee.getCounters().entrySet()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("NoteCounters").append(counter.getKey().getName());
|
||||
source.setSVar(sb.toString(), counter.getValue().toString());
|
||||
|
||||
@@ -33,7 +33,7 @@ public class ManaEffect extends SpellAbilityEffect {
|
||||
public void resolve(SpellAbility sa) {
|
||||
final Card card = sa.getHostCard();
|
||||
AbilityManaPart abMana = sa.getManaPart();
|
||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
final List<Player> tgtPlayers = getDefinedPlayersOrTargeted(sa);
|
||||
|
||||
// Spells are not undoable
|
||||
sa.setUndoable(sa.isAbility() && sa.isUndoable() && tgtPlayers.size() < 2);
|
||||
|
||||
@@ -50,7 +50,7 @@ public class PeekAndRevealEffect extends SpellAbilityEffect {
|
||||
numPeek = Math.min(numPeek, library.size());
|
||||
|
||||
CardCollection peekCards = new CardCollection();
|
||||
for(int i = 0; i < numPeek; i++) {
|
||||
for (int i = 0; i < numPeek; i++) {
|
||||
peekCards.add(library.get(i));
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public class PeekAndRevealEffect extends SpellAbilityEffect {
|
||||
}
|
||||
if (imprintRevealed) {
|
||||
Map<Integer, Card> cachedMap = Maps.newHashMap();
|
||||
for(Card c : revealableCards) {
|
||||
for (Card c : revealableCards) {
|
||||
source.addImprintedCard(CardUtil.getLKICopy(c, cachedMap));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ public class PlaneswalkEffect extends SpellAbilityEffect {
|
||||
public void resolve(SpellAbility sa) {
|
||||
Game game = sa.getActivatingPlayer().getGame();
|
||||
|
||||
for(Player p : game.getPlayers()) {
|
||||
for (Player p : game.getPlayers()) {
|
||||
p.leaveCurrentPlane();
|
||||
}
|
||||
if (sa.hasParam("Defined")) {
|
||||
|
||||
@@ -103,7 +103,7 @@ public class PlayEffect extends SpellAbilityEffect {
|
||||
} else if (sa.hasParam("AnySupportedCard")) {
|
||||
final String valid = sa.getParam("AnySupportedCard");
|
||||
List<PaperCard> cards = null;
|
||||
if (valid.startsWith("Names:")){
|
||||
if (valid.startsWith("Names:")) {
|
||||
cards = new ArrayList<>();
|
||||
for (String name : valid.substring(6).split(",")) {
|
||||
name = name.replace(";", ",");
|
||||
|
||||
@@ -66,7 +66,7 @@ public class ProtectAllEffect extends SpellAbilityEffect {
|
||||
} else if (sa.getParam("Gains").equals("TargetedCardColor")) {
|
||||
for (final Card c : sa.getSATargetingCard().getTargets().getTargetCards()) {
|
||||
ColorSet cs = CardUtil.getColors(c);
|
||||
for(byte col : MagicColor.WUBRG) {
|
||||
for (byte col : MagicColor.WUBRG) {
|
||||
if (cs.hasAnyColor(col))
|
||||
gains.add(MagicColor.toLongString(col).toLowerCase());
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ public class TwoPilesEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
String title;
|
||||
if("One".equals(sa.getParamOrDefault("FaceDown", "False"))) {
|
||||
if ("One".equals(sa.getParamOrDefault("FaceDown", "False"))) {
|
||||
title = Localizer.getInstance().getMessage("lblSelectCardForFaceDownPile");
|
||||
} else if (isLeftRightPile) {
|
||||
title = Localizer.getInstance().getMessage("lblSelectCardForLeftPile");
|
||||
|
||||
@@ -2084,7 +2084,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
|| keyword.equals("Foretell") // for the ones without cost
|
||||
|| keyword.equals("Hideaway") || keyword.equals("Ascend")
|
||||
|| keyword.equals("Totem armor") || keyword.equals("Battle cry")
|
||||
|| keyword.equals("Devoid") || keyword.equals("Riot")){
|
||||
|| keyword.equals("Devoid") || keyword.equals("Riot")) {
|
||||
sbLong.append(keyword).append(" (").append(inst.getReminderText()).append(")");
|
||||
} else if (keyword.startsWith("Partner:")) {
|
||||
final String[] k = keyword.split(":");
|
||||
@@ -3541,7 +3541,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
public final CardTypeView getType() {
|
||||
return getType(currentState);
|
||||
}
|
||||
|
||||
public final CardTypeView getType(CardState state) {
|
||||
if (changedCardTypes.isEmpty() && changedCardTypesCharacterDefining.isEmpty()) {
|
||||
return state.getType();
|
||||
@@ -3580,10 +3579,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
return changed;
|
||||
}
|
||||
|
||||
public boolean clearChangedCardKeywords() {
|
||||
return clearChangedCardKeywords(false);
|
||||
}
|
||||
|
||||
public boolean clearChangedCardColors() {
|
||||
boolean changed = false;
|
||||
|
||||
@@ -3648,7 +3643,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
public final void removeChangedCardTypes(final long timestamp) {
|
||||
removeChangedCardTypes(timestamp, true);
|
||||
}
|
||||
|
||||
public final void removeChangedCardTypes(final long timestamp, final boolean updateView) {
|
||||
boolean removed = false;
|
||||
removed |= changedCardTypes.remove(timestamp) != null;
|
||||
@@ -3981,7 +3975,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
this.tempBoost = 0;
|
||||
this.bonusFromCounters = 0;
|
||||
}
|
||||
public StatBreakdown(int currentValue, int tempBoost, int bonusFromCounters){
|
||||
public StatBreakdown(int currentValue, int tempBoost, int bonusFromCounters) {
|
||||
this.currentValue = currentValue;
|
||||
this.tempBoost = tempBoost;
|
||||
this.bonusFromCounters = bonusFromCounters;
|
||||
@@ -4268,6 +4262,9 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
return change;
|
||||
}
|
||||
|
||||
public boolean clearChangedCardKeywords() {
|
||||
return clearChangedCardKeywords(false);
|
||||
}
|
||||
public final boolean clearChangedCardKeywords(final boolean updateView) {
|
||||
if (changedCardKeywords.isEmpty()) {
|
||||
return false;
|
||||
|
||||
@@ -270,7 +270,7 @@ public class CardFactory {
|
||||
original.addNonManaAbilities(card.getCurrentState().getNonManaAbilities());
|
||||
original.addIntrinsicKeywords(card.getCurrentState().getIntrinsicKeywords()); // Copy 'Fuse' to original side
|
||||
original.getSVars().putAll(card.getCurrentState().getSVars()); // Unfortunately need to copy these to (Effect looks for sVars on execute)
|
||||
} else if (state != CardStateName.Original){
|
||||
} else if (state != CardStateName.Original) {
|
||||
CardFactoryUtil.setupKeywordedAbilities(card);
|
||||
}
|
||||
if (state == CardStateName.Adventure) {
|
||||
|
||||
@@ -538,7 +538,7 @@ public class CardFactoryUtil {
|
||||
landkw.add(k);
|
||||
} else if (k.startsWith("Protection")) {
|
||||
protectionkw.add(k);
|
||||
for(byte col : MagicColor.WUBRG) {
|
||||
for (byte col : MagicColor.WUBRG) {
|
||||
final String colString = "Protection from " + MagicColor.toLongString(col).toLowerCase();
|
||||
if (k.contains(colString)) {
|
||||
protectionColorkw.add(colString);
|
||||
@@ -896,7 +896,7 @@ public class CardFactoryUtil {
|
||||
cascadeTrigger.setOverridingAbility(dig);
|
||||
|
||||
inst.addTrigger(cascadeTrigger);
|
||||
} else if (keyword.startsWith("Champion")){
|
||||
} else if (keyword.startsWith("Champion")) {
|
||||
final String[] k = keyword.split(":");
|
||||
final String[] valid = k[1].split(",");
|
||||
String desc = Lang.joinHomogenous(Lists.newArrayList(valid), null, "or");
|
||||
@@ -1688,7 +1688,7 @@ public class CardFactoryUtil {
|
||||
|
||||
int idx = 0;
|
||||
int skipId = 0;
|
||||
for(String ab : abs) {
|
||||
for (String ab : abs) {
|
||||
idx += 1;
|
||||
if (idx <= skipId) {
|
||||
continue;
|
||||
@@ -1898,7 +1898,7 @@ public class CardFactoryUtil {
|
||||
final List<String> abs = Arrays.asList(keyword.substring("Dungeon:".length()).split(","));
|
||||
final Map<String, SpellAbility> saMap = new LinkedHashMap<>();
|
||||
|
||||
for(String ab : abs) {
|
||||
for (String ab : abs) {
|
||||
saMap.put(ab, AbilityFactory.getAbility(card, ab));
|
||||
}
|
||||
for (SpellAbility sa : saMap.values()) {
|
||||
@@ -2956,7 +2956,7 @@ public class CardFactoryUtil {
|
||||
|
||||
inst.addSpellAbility(abilityMorphDown(card));
|
||||
inst.addSpellAbility(abilityMorphUp(card, k[1], false));
|
||||
} else if (keyword.startsWith("Megamorph")){
|
||||
} else if (keyword.startsWith("Megamorph")) {
|
||||
final String[] k = keyword.split(":");
|
||||
|
||||
inst.addSpellAbility(abilityMorphDown(card));
|
||||
@@ -3197,10 +3197,6 @@ public class CardFactoryUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.getHostCard().isInstant() || this.getHostCard().hasKeyword(Keyword.FLASH)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.getHostCard().getFirstSpellAbility().canCastTiming(this.getHostCard(), this.getActivatingPlayer());
|
||||
}
|
||||
|
||||
|
||||
@@ -354,7 +354,7 @@ public final class CardUtil {
|
||||
if ((combinedColor & color) == 0) {
|
||||
continue;
|
||||
}
|
||||
for(final Card c : game.getColoredCardsInPlay(MagicColor.toLongString(color))) {
|
||||
for (final Card c : game.getColoredCardsInPlay(MagicColor.toLongString(color))) {
|
||||
if (!res.contains(c) && !tgts.contains(c) && c.isValid(valid, source.getController(), source, targetSA)) {
|
||||
res.add(c);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public class AttackingBand {
|
||||
String[] validString = { "Legendary.Creature", "Creature.namedWolves of the Hunt", "Dinosaur" };
|
||||
|
||||
Card source = band.get(0);
|
||||
for(int i = 0; i < bandsWithString.length; i++) {
|
||||
for (int i = 0; i < bandsWithString.length; i++) {
|
||||
String keyword = bandsWithString[i];
|
||||
String valid = validString[i];
|
||||
|
||||
|
||||
@@ -807,7 +807,7 @@ public class Combat {
|
||||
if (defender instanceof Player && defender.hasKeyword("You assign combat damage of each creature attacking you.")) {
|
||||
assigningPlayer = (Player)defender;
|
||||
}
|
||||
else if (AttackingBand.isValidBand(orderedBlockers, true)){
|
||||
else if (AttackingBand.isValidBand(orderedBlockers, true)) {
|
||||
assigningPlayer = orderedBlockers.get(0).getController();
|
||||
}
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ public class CostPutCounter extends CostPartWithList {
|
||||
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
|
||||
*/
|
||||
@Override
|
||||
protected Card doPayment(SpellAbility ability, Card targetCard){
|
||||
protected Card doPayment(SpellAbility ability, Card targetCard) {
|
||||
final Integer i = this.convertAmount();
|
||||
targetCard.addCounter(this.getCounter(), i, ability.getActivatingPlayer(), null, ability.getRootAbility().isTrigger(), counterTable);
|
||||
return targetCard;
|
||||
|
||||
@@ -12,7 +12,6 @@ import forge.game.card.Card;
|
||||
|
||||
public class KeywordCollection implements Iterable<KeywordInterface> {
|
||||
|
||||
|
||||
private transient KeywordCollectionView view;
|
||||
// don't use enumKeys it causes a slow down
|
||||
private final Multimap<Keyword, KeywordInterface> map = MultimapBuilder.hashKeys()
|
||||
|
||||
@@ -36,7 +36,7 @@ import forge.game.trigger.Trigger;
|
||||
*
|
||||
* @author Forge
|
||||
*/
|
||||
public class KeywordsChange implements Cloneable {
|
||||
public class KeywordsChange implements Cloneable {
|
||||
private KeywordCollection keywords = new KeywordCollection();
|
||||
private List<KeywordInterface> removeKeywordInterfaces = Lists.newArrayList();
|
||||
private List<String> removeKeywords = Lists.newArrayList();
|
||||
|
||||
@@ -342,8 +342,7 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
// no first strikers, skip this step
|
||||
if (!combat.assignCombatDamage(true)) {
|
||||
givePriorityToPlayer = false;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
combat.dealAssignedDamage();
|
||||
}
|
||||
break;
|
||||
@@ -355,8 +354,7 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
|
||||
if (!combat.assignCombatDamage(false)) {
|
||||
givePriorityToPlayer = false;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
combat.dealAssignedDamage();
|
||||
}
|
||||
break;
|
||||
@@ -394,7 +392,7 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
final CardZoneTable table = new CardZoneTable();
|
||||
final CardCollection discarded = new CardCollection();
|
||||
boolean firstDiscarded = playerTurn.getNumDiscardedThisTurn() == 0;
|
||||
for (Card c : playerTurn.getController().chooseCardsToDiscardToMaximumHandSize(numDiscard)){
|
||||
for (Card c : playerTurn.getController().chooseCardsToDiscardToMaximumHandSize(numDiscard)) {
|
||||
if (playerTurn.discard(c, null, table) != null) {
|
||||
discarded.add(c);
|
||||
}
|
||||
@@ -590,7 +588,7 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
"You may exert CARDNAME as it attacks.");
|
||||
|
||||
if (!possibleExerters.isEmpty()) {
|
||||
for(Card exerter : whoDeclares.getController().exertAttackers(possibleExerters)) {
|
||||
for (Card exerter : whoDeclares.getController().exertAttackers(possibleExerters)) {
|
||||
exerter.exert();
|
||||
}
|
||||
}
|
||||
@@ -1087,7 +1085,7 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
sw.reset();
|
||||
}
|
||||
}
|
||||
else if (DEBUG_PHASES){
|
||||
else if (DEBUG_PHASES) {
|
||||
System.out.print(" >> (no priority given to " + getPriorityPlayer() + ")\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -483,7 +483,7 @@ public class PlayerView extends GameEntityView {
|
||||
if (cards == null)
|
||||
return 0;
|
||||
|
||||
for(CardView c : cards) {
|
||||
for (CardView c : cards) {
|
||||
types.addAll((Collection<? extends CardType.CoreType>) c.getCurrentState().getType().getCoreTypes());
|
||||
}
|
||||
|
||||
|
||||
@@ -2190,7 +2190,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
|
||||
@Override
|
||||
public int compareTo(SpellAbility ab) {
|
||||
if (this.isManaAbility() && ab.isManaAbility()){
|
||||
if (this.isManaAbility() && ab.isManaAbility()) {
|
||||
return this.calculateScoreForManaAbility() - ab.calculateScoreForManaAbility();
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -318,7 +318,7 @@ public class SpellAbilityStackInstance implements IIdentifiable, IHasCardView {
|
||||
SpellAbility compare = sa;
|
||||
SpellAbilityStackInstance sub = this;
|
||||
|
||||
if (!compare.equals(sub.ability)){
|
||||
if (!compare.equals(sub.ability)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
Name:Jeska's Will
|
||||
ManaCost:2 R
|
||||
Types:Sorcery
|
||||
A:SP$ Charm | Cost$ 2 R | MinCharmNum$ 1 | CharmNum$ X | Choices$ DBHandTarget,DBExile | AdditionalDescription$ If you control a commander as you cast this spell, you may choose both.
|
||||
SVar:DBHandTarget:DB$ Pump | ValidTgts$ Opponent | SubAbility$ DBMana | AILogic$ ManaRitual | SpellDescription$ Add {R} for each card in target opponent's hand.
|
||||
SVar:DBMana:DB$ Mana | Produced$ R | Amount$ Z | StackDescription$ None
|
||||
A:SP$ Charm | Cost$ 2 R | MinCharmNum$ 1 | CharmNum$ X | Choices$ DBMana,DBExile | AdditionalDescription$ If you control a commander as you cast this spell, you may choose both.
|
||||
SVar:DBMana:DB$ Mana | Defined$ You | ValidTgts$ Opponent | AILogic$ ManaRitual | Produced$ R | Amount$ Z | SpellDescription$ Add {R} for each card in target opponent's hand.
|
||||
SVar:DBExile:DB$ Dig | Defined$ You | DigNum$ 3 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | SubAbility$ DBEffect | SpellDescription$ Exile the top three cards of your library. You may play them this turn.
|
||||
SVar:DBEffect:DB$ Effect | RememberObjects$ RememberedCard | StaticAbilities$ Play | SubAbility$ DBCleanup | ForgetOnMoved$ Exile
|
||||
SVar:Play:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may play the exiled cards this turn.
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Rousing Refrain
|
||||
ManaCost:3 R R
|
||||
Types:Sorcery
|
||||
K:Suspend:3:1 R
|
||||
A:SP$ Pump | Cost$ 3 R R | ValidTgts$ Opponent | TgtPrompt$ Select target opponent | SubAbility$ DBMana | AILogic$ ManaRitual | StackDescription$ SpellDescription | SpellDescription$ Add {R} for each card in target opponent's hand.
|
||||
SVar:DBMana:DB$ Mana | Produced$ R | Amount$ Z | PersistentMana$ True | SubAbility$ DBChange | StackDescription$ SpellDescription | SpellDescription$ Until end of turn, you don't lose this mana as steps and phases end.
|
||||
A:SP$ Mana | Cost$ 3 R R | ValidTgts$ Opponent | TgtPrompt$ Select target opponent | SubAbility$ DBMana | AILogic$ ManaRitual | Produced$ R | Amount$ Z | PersistentMana$ True | Defined$ You | SubAbility$ DBChange | StackDescription$ SpellDescription | SpellDescription$ Until end of turn, you don't lose this mana as steps and phases end.
|
||||
SVar:Z:TargetedPlayer$CardsInHand
|
||||
SVar:DBChange:DB$ ChangeZone | Origin$ Stack | Destination$ Exile | WithCountersType$ TIME | WithCountersAmount$ 3 | SpellDescription$ Exile CARDNAME with three time counters on it.
|
||||
Oracle:Add {R} for each card in target opponent's hand. Until end of turn, you don't lose this mana as steps and phases end. Exile Rousing Refrain with three time counters on it.\nSuspend 3—{1}{R} (Rather than cast this card from your hand, you may pay {1}{R} and exile it with three 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.)
|
||||
|
||||
@@ -119,8 +119,7 @@ public abstract class GuiDownloadService implements Runnable {
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
//handle special case of zip service
|
||||
if (onReadyToStart != null) {
|
||||
onReadyToStart.run();
|
||||
@@ -147,8 +146,7 @@ public abstract class GuiDownloadService implements Runnable {
|
||||
progressBar.setDescription("All items have been downloaded.");
|
||||
btnStart.setText("OK");
|
||||
btnStart.setCommand(cmdClose);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
progressBar.setMaximum(files.size());
|
||||
progressBar.setDescription(files.size() == 1 ? "1 item found." : files.size() + " items found.");
|
||||
//for(Entry<String, String> kv : cards.entrySet()) System.out.printf("Will get %s from %s%n", kv.getKey(), kv.getValue());
|
||||
@@ -223,8 +221,7 @@ public abstract class GuiDownloadService implements Runnable {
|
||||
}
|
||||
|
||||
sb.append(String.format("%02d remaining.", t2Go / 1000));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
sb.append(String.format("%d of %d items finished! Skipped " + skipped + " items. Please close!",
|
||||
count, files.size()));
|
||||
finish();
|
||||
@@ -303,8 +300,7 @@ public abstract class GuiDownloadService implements Runnable {
|
||||
}
|
||||
|
||||
// if file is not found and this is a JPG, give PNG a shot...
|
||||
if ((conn.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) && (url.endsWith(".jpg")))
|
||||
{
|
||||
if ((conn.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) && (url.endsWith(".jpg"))) {
|
||||
fullborder = false;
|
||||
isJPG = false;
|
||||
conn.disconnect();
|
||||
@@ -342,8 +338,7 @@ public abstract class GuiDownloadService implements Runnable {
|
||||
System.out.println(" Connection failed for url: " + url);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
System.out.println(" Can't create folder: " + base.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
@@ -425,7 +420,7 @@ public abstract class GuiDownloadService implements Runnable {
|
||||
|
||||
String response = HttpUtil.getURL(manifestUrl);
|
||||
|
||||
if (response == null) return null;
|
||||
if (response == null) return null;
|
||||
|
||||
String[] strings = response.split("<a href=\"");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user