mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
Merge branch 'gameCacheRework' into 'master'
Human Play: try to remove usage of game.getCard See merge request core-developers/forge!2804
This commit is contained in:
@@ -769,7 +769,7 @@ public class AiController {
|
||||
return AiPlayDecision.CantPlayAi;
|
||||
}
|
||||
}
|
||||
else if (sa.getPayCosts() != null){
|
||||
else {
|
||||
Cost payCosts = sa.getPayCosts();
|
||||
ManaCost mana = payCosts.getTotalMana();
|
||||
if (mana != null) {
|
||||
@@ -858,7 +858,7 @@ public class AiController {
|
||||
int neededMana = 0;
|
||||
boolean dangerousRecurringCost = false;
|
||||
|
||||
Cost costWithBuyback = sa.getPayCosts() != null ? sa.getPayCosts().copy() : Cost.Zero;
|
||||
Cost costWithBuyback = sa.getPayCosts().copy();
|
||||
for (OptionalCostValue opt : GameActionUtil.getOptionalCostValues(sa)) {
|
||||
if (opt.getType() == OptionalCost.Buyback) {
|
||||
costWithBuyback.add(opt.getCost());
|
||||
@@ -907,8 +907,8 @@ public class AiController {
|
||||
public int compare(final SpellAbility a, final SpellAbility b) {
|
||||
// sort from highest cost to lowest
|
||||
// we want the highest costs first
|
||||
int a1 = a.getPayCosts() == null ? 0 : a.getPayCosts().getTotalMana().getCMC();
|
||||
int b1 = b.getPayCosts() == null ? 0 : b.getPayCosts().getTotalMana().getCMC();
|
||||
int a1 = a.getPayCosts().getTotalMana().getCMC();
|
||||
int b1 = b.getPayCosts().getTotalMana().getCMC();
|
||||
|
||||
// deprioritize SAs explicitly marked as preferred to be activated last compared to all other SAs
|
||||
if (a.hasParam("AIActivateLast") && !b.hasParam("AIActivateLast")) {
|
||||
@@ -927,12 +927,12 @@ public class AiController {
|
||||
// deprioritize pump spells with pure energy cost (can be activated last,
|
||||
// since energy is generally scarce, plus can benefit e.g. Electrostatic Pummeler)
|
||||
int a2 = 0, b2 = 0;
|
||||
if (a.getApi() == ApiType.Pump && a.getPayCosts() != null && a.getPayCosts().getCostEnergy() != null) {
|
||||
if (a.getApi() == ApiType.Pump && a.getPayCosts().getCostEnergy() != null) {
|
||||
if (a.getPayCosts().hasOnlySpecificCostType(CostPayEnergy.class)) {
|
||||
a2 = a.getPayCosts().getCostEnergy().convertAmount();
|
||||
}
|
||||
}
|
||||
if (b.getApi() == ApiType.Pump && b.getPayCosts() != null && b.getPayCosts().getCostEnergy() != null) {
|
||||
if (b.getApi() == ApiType.Pump && b.getPayCosts().getCostEnergy() != null) {
|
||||
if (b.getPayCosts().hasOnlySpecificCostType(CostPayEnergy.class)) {
|
||||
b2 = b.getPayCosts().getCostEnergy().convertAmount();
|
||||
}
|
||||
@@ -956,8 +956,7 @@ public class AiController {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (a.getHostCard().equals(b.getHostCard()) && a.getApi() == b.getApi()
|
||||
&& a.getPayCosts() != null && b.getPayCosts() != null) {
|
||||
if (a.getHostCard().equals(b.getHostCard()) && a.getApi() == b.getApi()) {
|
||||
// Cheaper Spectacle costs should be preferred
|
||||
// FIXME: Any better way to identify that these are the same ability, one with Spectacle and one not?
|
||||
// (looks like it's not a full-fledged alternative cost as such, and is not processed with other alt costs)
|
||||
@@ -1479,7 +1478,7 @@ public class AiController {
|
||||
}
|
||||
|
||||
for (SpellAbility sa : card.getSpellAbilities()) {
|
||||
if (sa.getPayCosts() != null && sa.isAbility()
|
||||
if (sa.isAbility()
|
||||
&& sa.getPayCosts().getCostMana() != null
|
||||
&& sa.getPayCosts().getCostMana().getMana().getCMC() > 0
|
||||
&& (!sa.getPayCosts().hasTapCost() || !isTapLand)
|
||||
|
||||
@@ -494,7 +494,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
for (final SpellAbility sa : card.getSpellAbilities()) {
|
||||
if (sa.isManaAbility() && sa.getPayCosts() != null && sa.getPayCosts().hasTapCost()) {
|
||||
if (sa.isManaAbility() && sa.getPayCosts().hasTapCost()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,9 +113,7 @@ public class ComputerUtilAbility {
|
||||
List<SpellAbility> priorityAltSa = Lists.newArrayList();
|
||||
List<SpellAbility> otherAltSa = Lists.newArrayList();
|
||||
for (SpellAbility altSa : saAltCosts) {
|
||||
if (altSa.getPayCosts() == null || sa.getPayCosts() == null) {
|
||||
otherAltSa.add(altSa);
|
||||
} else if (sa.getPayCosts().isOnlyManaCost()
|
||||
if (sa.getPayCosts().isOnlyManaCost()
|
||||
&& altSa.getPayCosts().isOnlyManaCost() && sa.getPayCosts().getTotalMana().compareTo(altSa.getPayCosts().getTotalMana()) == 1) {
|
||||
// the alternative cost is strictly cheaper, so why not? (e.g. Omniscience etc.)
|
||||
priorityAltSa.add(altSa);
|
||||
|
||||
@@ -1474,7 +1474,7 @@ public class ComputerUtilCard {
|
||||
if (totalPowerUnblocked >= opp.getLife()) {
|
||||
return true;
|
||||
} else if (totalPowerUnblocked > dmg && sa.getHostCard() != null && sa.getHostCard().isInPlay()) {
|
||||
if (sa.getPayCosts() != null && sa.getPayCosts().hasNoManaCost()) {
|
||||
if (sa.getPayCosts().hasNoManaCost()) {
|
||||
return true; // always activate abilities which cost no mana and which can increase unblocked damage
|
||||
}
|
||||
}
|
||||
@@ -1785,10 +1785,6 @@ public class ComputerUtilCard {
|
||||
|
||||
for (Card c : otb) {
|
||||
for (SpellAbility sa : c.getSpellAbilities()) {
|
||||
if (sa.getPayCosts() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CostPayEnergy energyCost = sa.getPayCosts().getCostEnergy();
|
||||
if (energyCost != null) {
|
||||
int amount = energyCost.convertAmount();
|
||||
|
||||
@@ -1028,7 +1028,7 @@ public class ComputerUtilCombat {
|
||||
return power;
|
||||
}
|
||||
for (SpellAbility ability : blocker.getAllSpellAbilities()) {
|
||||
if (!(ability instanceof AbilityActivated) || ability.getPayCosts() == null) {
|
||||
if (!(ability instanceof AbilityActivated)) {
|
||||
continue;
|
||||
}
|
||||
if (ability.hasParam("ActivationPhases") || ability.hasParam("SorcerySpeed") || ability.hasParam("ActivationZone")) {
|
||||
@@ -1203,7 +1203,7 @@ public class ComputerUtilCombat {
|
||||
return toughness;
|
||||
}
|
||||
for (SpellAbility ability : blocker.getAllSpellAbilities()) {
|
||||
if (!(ability instanceof AbilityActivated) || ability.getPayCosts() == null) {
|
||||
if (!(ability instanceof AbilityActivated)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1426,7 +1426,7 @@ public class ComputerUtilCombat {
|
||||
return power;
|
||||
}
|
||||
for (SpellAbility ability : attacker.getAllSpellAbilities()) {
|
||||
if (!(ability instanceof AbilityActivated) || ability.getPayCosts() == null) {
|
||||
if (!(ability instanceof AbilityActivated)) {
|
||||
continue;
|
||||
}
|
||||
if (ability.hasParam("ActivationPhases") || ability.hasParam("SorcerySpeed") || ability.hasParam("ActivationZone")) {
|
||||
@@ -1662,7 +1662,7 @@ public class ComputerUtilCombat {
|
||||
return toughness;
|
||||
}
|
||||
for (SpellAbility ability : attacker.getAllSpellAbilities()) {
|
||||
if (!(ability instanceof AbilityActivated) || ability.getPayCosts() == null) {
|
||||
if (!(ability instanceof AbilityActivated)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2517,7 +2517,7 @@ public class ComputerUtilCombat {
|
||||
final Player controller = combatant.getController();
|
||||
for (Card c : controller.getCardsIn(ZoneType.Battlefield)) {
|
||||
for (SpellAbility ability : c.getAllSpellAbilities()) {
|
||||
if (!(ability instanceof AbilityActivated) || ability.getPayCosts() == null) {
|
||||
if (!(ability instanceof AbilityActivated)) {
|
||||
continue;
|
||||
}
|
||||
if (ability.getApi() != ApiType.Pump) {
|
||||
|
||||
@@ -529,7 +529,7 @@ public class ComputerUtilCost {
|
||||
public boolean apply(Card card) {
|
||||
boolean hasManaSa = false;
|
||||
for (final SpellAbility sa : card.getSpellAbilities()) {
|
||||
if (sa.isManaAbility() && sa.getPayCosts() != null && sa.getPayCosts().hasTapCost()) {
|
||||
if (sa.isManaAbility() && sa.getPayCosts().hasTapCost()) {
|
||||
hasManaSa = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -507,16 +507,10 @@ public class ComputerUtilMana {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (saPayment.getPayCosts() != null) {
|
||||
final CostPayment pay = new CostPayment(saPayment.getPayCosts(), saPayment);
|
||||
if (!pay.payComputerCosts(new AiCostDecision(ai, saPayment))) {
|
||||
saList.remove(saPayment);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
System.err.println("Ability " + saPayment + " from " + saPayment.getHostCard() + " had NULL as payCost");
|
||||
saPayment.getHostCard().tap();
|
||||
final CostPayment pay = new CostPayment(saPayment.getPayCosts(), saPayment);
|
||||
if (!pay.payComputerCosts(new AiCostDecision(ai, saPayment))) {
|
||||
saList.remove(saPayment);
|
||||
continue;
|
||||
}
|
||||
|
||||
ai.getGame().getStack().addAndUnfreeze(saPayment);
|
||||
@@ -837,10 +831,9 @@ public class ComputerUtilMana {
|
||||
if (checkCosts) {
|
||||
// Check if AI can still play this mana ability
|
||||
ma.setActivatingPlayer(ai);
|
||||
if (ma.getPayCosts() != null) { // if the AI can't pay the additional costs skip the mana ability
|
||||
if (!CostPayment.canPayAdditionalCosts(ma.getPayCosts(), ma)) {
|
||||
return false;
|
||||
}
|
||||
// if the AI can't pay the additional costs skip the mana ability
|
||||
if (!CostPayment.canPayAdditionalCosts(ma.getPayCosts(), ma)) {
|
||||
return false;
|
||||
}
|
||||
else if (sourceCard.isTapped()) {
|
||||
return false;
|
||||
@@ -1144,7 +1137,7 @@ public class ComputerUtilMana {
|
||||
ManaCostBeingPaid cost = new ManaCostBeingPaid(mana, restriction);
|
||||
|
||||
// Tack xMana Payments into mana here if X is a set value
|
||||
if (sa.getPayCosts() != null && (cost.getXcounter() > 0 || extraMana > 0)) {
|
||||
if (cost.getXcounter() > 0 || extraMana > 0) {
|
||||
int manaToAdd = 0;
|
||||
if (test && extraMana > 0) {
|
||||
final int multiplicator = Math.max(cost.getXcounter(), 1);
|
||||
@@ -1218,7 +1211,7 @@ public class ComputerUtilMana {
|
||||
for (SpellAbility ma : src.getManaAbilities()) {
|
||||
ma.setActivatingPlayer(p);
|
||||
if (!checkPlayable || ma.canPlay()) {
|
||||
int costsToActivate = ma.getPayCosts() != null && ma.getPayCosts().getCostMana() != null ? ma.getPayCosts().getCostMana().convertAmount() : 0;
|
||||
int costsToActivate = ma.getPayCosts().getCostMana() != null ? ma.getPayCosts().getCostMana().convertAmount() : 0;
|
||||
int producedMana = ma.getParamOrDefault("Produced", "").split(" ").length;
|
||||
int producedAmount = AbilityUtils.calculateAmount(src, ma.getParamOrDefault("Amount", "1"), ma);
|
||||
|
||||
@@ -1594,7 +1587,7 @@ public class ComputerUtilMana {
|
||||
}
|
||||
|
||||
public static int determineMaxAffordableX(Player ai, SpellAbility sa) {
|
||||
if (sa.getPayCosts() == null || sa.getPayCosts().getCostMana() == null) {
|
||||
if (sa.getPayCosts().getCostMana() == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -242,7 +242,7 @@ public class CreatureEvaluator implements Function<Card, Integer> {
|
||||
&& "+X".equals(sa.getParam("NumDef"))
|
||||
&& !sa.usesTargeting()
|
||||
&& (!sa.hasParam("Defined") || "Self".equals(sa.getParam("Defined")))) {
|
||||
if (sa.getPayCosts() != null && sa.getPayCosts().hasOnlySpecificCostType(CostPayEnergy.class)) {
|
||||
if (sa.getPayCosts().hasOnlySpecificCostType(CostPayEnergy.class)) {
|
||||
// Electrostatic Pummeler, can be expanded for similar cards
|
||||
int initPower = getEffectivePower(sa.getHostCard());
|
||||
int pumpedPower = initPower;
|
||||
|
||||
@@ -1216,7 +1216,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
public List<OptionalCostValue> chooseOptionalCosts(SpellAbility chosen,
|
||||
List<OptionalCostValue> optionalCostValues) {
|
||||
List<OptionalCostValue> chosenOptCosts = Lists.newArrayList();
|
||||
Cost costSoFar = chosen.getPayCosts() != null ? chosen.getPayCosts().copy() : Cost.Zero;
|
||||
Cost costSoFar = chosen.getPayCosts().copy();
|
||||
|
||||
for (OptionalCostValue opt : optionalCostValues) {
|
||||
// Choose the optional cost if it can be paid (to be improved later, check for playability and other conditions perhaps)
|
||||
@@ -1255,7 +1255,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
// TODO: improve the logic depending on the keyword and the playability of the cost-modified SA (enough targets present etc.)
|
||||
int chosenAmount = 0;
|
||||
|
||||
Cost costSoFar = sa.getPayCosts() != null ? sa.getPayCosts().copy() : Cost.Zero;
|
||||
Cost costSoFar = sa.getPayCosts().copy();
|
||||
|
||||
for (int i = 0; i < max; i++) {
|
||||
costSoFar.add(cost);
|
||||
|
||||
@@ -267,7 +267,7 @@ public abstract class SpellAbilityAi {
|
||||
|
||||
// TODO probably also consider if winter orb or similar are out
|
||||
|
||||
if (sa.getPayCosts() == null || sa instanceof AbilitySub) {
|
||||
if (sa instanceof AbilitySub) {
|
||||
return true; // This is only true for Drawbacks and triggers
|
||||
}
|
||||
|
||||
|
||||
@@ -247,7 +247,6 @@ public class AnimateAi extends SpellAbilityAi {
|
||||
final Player ai = sa.getActivatingPlayer();
|
||||
final PhaseHandler ph = ai.getGame().getPhaseHandler();
|
||||
final boolean alwaysActivatePWAbility = sa.hasParam("Planeswalker")
|
||||
&& sa.getPayCosts() != null
|
||||
&& sa.getPayCosts().hasSpecificCostType(CostPutCounter.class)
|
||||
&& sa.getTargetRestrictions() != null
|
||||
&& sa.getTargetRestrictions().getMinTargets(sa.getHostCard(), sa) == 0;
|
||||
|
||||
@@ -398,7 +398,7 @@ public class AttachAi extends SpellAbilityAi {
|
||||
if (!c.isCreature() && !c.getType().hasSubtype("Vehicle") && !c.isTapped()) {
|
||||
// try to identify if this thing can actually tap
|
||||
for (SpellAbility ab : c.getAllSpellAbilities()) {
|
||||
if (ab.getPayCosts() != null && ab.getPayCosts().hasTapCost()) {
|
||||
if (ab.getPayCosts().hasTapCost()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -560,7 +560,7 @@ public class AttachAi extends SpellAbilityAi {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
for (final SpellAbility sa : c.getSpellAbilities()) {
|
||||
if (sa.isAbility() && sa.getPayCosts() != null && sa.getPayCosts().hasTapCost()) {
|
||||
if (sa.isAbility() && sa.getPayCosts().hasTapCost()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1065,8 +1065,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
if (destination.equals(ZoneType.Exile) || origin.contains(ZoneType.Battlefield)) {
|
||||
|
||||
// don't rush bouncing stuff when not going to attack
|
||||
if (!immediately && sa.getPayCosts() != null
|
||||
&& game.getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)
|
||||
if (!immediately && game.getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)
|
||||
&& game.getPhaseHandler().isPlayerTurn(ai)
|
||||
&& ai.getCreaturesInPlay().isEmpty()) {
|
||||
return false;
|
||||
@@ -1103,8 +1102,8 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
|
||||
boolean doWithoutTarget = sa.hasParam("Planeswalker") && sa.getTargetRestrictions() != null
|
||||
&& sa.getTargetRestrictions().getMinTargets(source, sa) == 0 && sa.getPayCosts() != null
|
||||
boolean doWithoutTarget = sa.hasParam("Planeswalker") && sa.usesTargeting()
|
||||
&& sa.getTargetRestrictions().getMinTargets(source, sa) == 0
|
||||
&& sa.getPayCosts().hasSpecificCostType(CostPutCounter.class);
|
||||
|
||||
if (list.isEmpty() && !doWithoutTarget) {
|
||||
@@ -1790,6 +1789,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
public boolean doReturnCommanderLogic(SpellAbility sa, Player aiPlayer) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<AbilityKey, Object> originalParams = (Map<AbilityKey, Object>)sa.getReplacingObject(AbilityKey.OriginalParams);
|
||||
SpellAbility causeSa = (SpellAbility)originalParams.get(AbilityKey.Cause);
|
||||
SpellAbility causeSub = null;
|
||||
|
||||
@@ -233,7 +233,7 @@ public class ChooseCardAi extends SpellAbilityAi {
|
||||
return false;
|
||||
}
|
||||
for (SpellAbility sa : c.getAllSpellAbilities()) {
|
||||
if (sa.getPayCosts() != null && sa.getPayCosts().hasTapCost()) {
|
||||
if (sa.getPayCosts().hasTapCost()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ public class CopySpellAbilityAi extends SpellAbilityAi {
|
||||
|
||||
final SpellAbility top = game.getStack().peekAbility();
|
||||
if (top != null
|
||||
&& top.getPayCosts() != null && top.getPayCosts().getCostMana() != null
|
||||
&& sa.getPayCosts() != null && sa.getPayCosts().getCostMana() != null
|
||||
&& top.getPayCosts().getCostMana() != null
|
||||
&& sa.getPayCosts().getCostMana() != null
|
||||
&& top.getPayCosts().getCostMana().getMana().getCMC() >= sa.getPayCosts().getCostMana().getMana().getCMC() + diff) {
|
||||
// The copied spell has a significantly higher CMC than the copy spell, consider copying
|
||||
chance = 100;
|
||||
|
||||
@@ -454,7 +454,6 @@ public class CountersPutAi extends SpellAbilityAi {
|
||||
// but try to do it in Main 2 then so that the AI has a chance to play creatures first.
|
||||
if (list.isEmpty()
|
||||
&& sa.hasParam("Planeswalker")
|
||||
&& sa.getPayCosts() != null
|
||||
&& sa.getPayCosts().hasOnlySpecificCostType(CostPutCounter.class)
|
||||
&& sa.isTargetNumberValid()
|
||||
&& sa.getTargets().getNumTargeted() == 0
|
||||
@@ -706,7 +705,7 @@ public class CountersPutAi extends SpellAbilityAi {
|
||||
SpellAbility testSa = sa;
|
||||
int countX = 0;
|
||||
int nonXGlyphs = 0;
|
||||
while (testSa != null && testSa.getPayCosts() != null && countX == 0) {
|
||||
while (testSa != null && countX == 0) {
|
||||
countX = testSa.getPayCosts().getTotalMana().countX();
|
||||
nonXGlyphs = testSa.getPayCosts().getTotalMana().getGlyphCount() - countX;
|
||||
testSa = testSa.getSubAbility();
|
||||
|
||||
@@ -120,7 +120,7 @@ public class CountersPutAllAi extends SpellAbilityAi {
|
||||
//Check for cards that could profit from the ability
|
||||
PhaseHandler phase = ai.getGame().getPhaseHandler();
|
||||
if (type.equals("P1P1") && sa.isAbility() && source.isCreature()
|
||||
&& sa.getPayCosts() != null && sa.getPayCosts().hasTapCost()
|
||||
&& sa.getPayCosts().hasTapCost()
|
||||
&& sa instanceof AbilitySub
|
||||
&& (!phase.getNextTurn().equals(ai)
|
||||
|| phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS))) {
|
||||
|
||||
@@ -53,7 +53,6 @@ public class DamageAllAi extends SpellAbilityAi {
|
||||
x = source.getCounters(CounterType.LOYALTY);
|
||||
}
|
||||
if (x == -1) {
|
||||
Player bestOpp = determineOppToKill(ai, sa, source, dmg);
|
||||
if (determineOppToKill(ai, sa, source, dmg) != null) {
|
||||
// we already know we can kill a player, so go for it
|
||||
return true;
|
||||
@@ -138,7 +137,7 @@ public class DamageAllAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
int minGain = 200; // The minimum gain in destroyed creatures
|
||||
if (sa.getPayCosts() != null && sa.getPayCosts().isReusuableResource()) {
|
||||
if (sa.getPayCosts().isReusuableResource()) {
|
||||
if (computerList.isEmpty()) {
|
||||
minGain = 10; // nothing to lose
|
||||
// no creatures to lose and player can be damaged
|
||||
|
||||
@@ -285,7 +285,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
}
|
||||
}
|
||||
|
||||
if ("XCountersDamage".equals(logic) && sa.getPayCosts() != null) {
|
||||
if ("XCountersDamage".equals(logic)) {
|
||||
// Check to ensure that we have enough counters to remove per the defined PayX
|
||||
for (CostPart part : sa.getPayCosts().getCostParts()) {
|
||||
if (part instanceof CostRemoveCounter) {
|
||||
@@ -449,7 +449,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
int pwScore = curLoyalty * 10;
|
||||
|
||||
for (SpellAbility sa : pw.getSpellAbilities()) {
|
||||
if (sa.hasParam("Ultimate") && sa.getPayCosts() != null) {
|
||||
if (sa.hasParam("Ultimate")) {
|
||||
Integer loyaltyCost = 0;
|
||||
CostRemoveCounter remLoyalty = sa.getPayCosts().getCostPartByType(CostRemoveCounter.class);
|
||||
if (remLoyalty != null) {
|
||||
@@ -794,8 +794,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
if (((phase.is(PhaseType.END_OF_TURN) && phase.getNextTurn().equals(ai))
|
||||
|| (SpellAbilityAi.isSorcerySpeed(sa) && phase.is(PhaseType.MAIN2))
|
||||
|| ("PingAfterAttack".equals(logic) && phase.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && phase.isPlayerTurn(ai))
|
||||
|| sa.getPayCosts() == null || immediately
|
||||
|| this.shouldTgtP(ai, sa, dmg, noPrevention)) &&
|
||||
|| immediately || shouldTgtP(ai, sa, dmg, noPrevention)) &&
|
||||
(!avoidTargetP(ai, sa))) {
|
||||
tcs.add(enemy);
|
||||
if (divided) {
|
||||
@@ -1126,8 +1125,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
continue;
|
||||
}
|
||||
// currently works only with cards that don't have additional costs (only mana is supported)
|
||||
if (ab.getPayCosts() != null
|
||||
&& (ab.getPayCosts().hasNoManaCost() || ab.getPayCosts().hasOnlySpecificCostType(CostPartMana.class))) {
|
||||
if (ab.getPayCosts().hasNoManaCost() || ab.getPayCosts().hasOnlySpecificCostType(CostPartMana.class)) {
|
||||
String dmgDef = "0";
|
||||
if (ab.getApi() == ApiType.DealDamage) {
|
||||
dmgDef = ab.getParamOrDefault("NumDmg", "0");
|
||||
@@ -1151,7 +1149,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
}
|
||||
|
||||
// FIXME: should it also check restrictions for targeting players?
|
||||
ManaCost costSa = sa.getPayCosts() != null ? sa.getPayCosts().getTotalMana() : ManaCost.NO_COST;
|
||||
ManaCost costSa = sa.getPayCosts().getTotalMana();
|
||||
ManaCost costAb = ab.getPayCosts().getTotalMana(); // checked for null above
|
||||
ManaCost total = ManaCost.combine(costSa, costAb);
|
||||
SpellAbility combinedAb = ab.copyWithDefinedCost(new Cost(total, false));
|
||||
|
||||
@@ -262,22 +262,20 @@ public class DrawAi extends SpellAbilityAi {
|
||||
// Draw up to max hand size but leave at least 3 in library
|
||||
numCards = Math.min(computerMaxHandSize - computerHandSize, computerLibrarySize - 3);
|
||||
|
||||
if (sa.getPayCosts() != null) {
|
||||
if (sa.getPayCosts().hasSpecificCostType(CostPayLife.class)) {
|
||||
// [Necrologia, Pay X Life : Draw X Cards]
|
||||
// Don't draw more than what's "safe" and don't risk a near death experience
|
||||
// Maybe would be better to check for "serious danger" and take more risk?
|
||||
while ((ComputerUtil.aiLifeInDanger(ai, false, numCards) && (numCards > 0))) {
|
||||
numCards--;
|
||||
}
|
||||
} else if (sa.getPayCosts().hasSpecificCostType(CostSacrifice.class)) {
|
||||
// [e.g. Krav, the Unredeemed and other cases which say "Sacrifice X creatures: draw X cards]
|
||||
// TODO: Add special logic to limit/otherwise modify the ChosenX value here
|
||||
if (sa.getPayCosts().hasSpecificCostType(CostPayLife.class)) {
|
||||
// [Necrologia, Pay X Life : Draw X Cards]
|
||||
// Don't draw more than what's "safe" and don't risk a near death experience
|
||||
// Maybe would be better to check for "serious danger" and take more risk?
|
||||
while ((ComputerUtil.aiLifeInDanger(ai, false, numCards) && (numCards > 0))) {
|
||||
numCards--;
|
||||
}
|
||||
} else if (sa.getPayCosts().hasSpecificCostType(CostSacrifice.class)) {
|
||||
// [e.g. Krav, the Unredeemed and other cases which say "Sacrifice X creatures: draw X cards]
|
||||
// TODO: Add special logic to limit/otherwise modify the ChosenX value here
|
||||
|
||||
// Skip this ability if nothing is to be chosen for sacrifice
|
||||
if (numCards <= 0) {
|
||||
return false;
|
||||
}
|
||||
// Skip this ability if nothing is to be chosen for sacrifice
|
||||
if (numCards <= 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ public class EffectAi extends SpellAbilityAi {
|
||||
} else if (logic.equals("SpellCopy")) {
|
||||
// fetch Instant or Sorcery and AI has reason to play this turn
|
||||
// does not try to get itself
|
||||
final ManaCost costSa = sa.getPayCosts() != null ? sa.getPayCosts().getTotalMana() : ManaCost.NO_COST;
|
||||
final ManaCost costSa = sa.getPayCosts().getTotalMana();
|
||||
final int count = CardLists.count(ai.getCardsIn(ZoneType.Hand), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
@@ -135,7 +135,7 @@ public class EffectAi extends SpellAbilityAi {
|
||||
AiPlayDecision decision = ((PlayerControllerAi)ai.getController()).getAi().canPlaySa(ab);
|
||||
// see if we can pay both for this spell and for the Effect spell we're considering
|
||||
if (decision == AiPlayDecision.WillPlay || decision == AiPlayDecision.WaitForMain2) {
|
||||
ManaCost costAb = ab.getPayCosts() != null ? ab.getPayCosts().getTotalMana() : ManaCost.NO_COST;
|
||||
ManaCost costAb = ab.getPayCosts().getTotalMana();
|
||||
ManaCost total = ManaCost.combine(costSa, costAb);
|
||||
SpellAbility combinedAb = ab.copyWithDefinedCost(new Cost(total, false));
|
||||
// can we pay both costs?
|
||||
|
||||
@@ -88,7 +88,6 @@ public class LifeGainAi extends SpellAbilityAi {
|
||||
if (lifeCritical
|
||||
&& sa.isAbility()
|
||||
&& sa.getHostCard() != null && sa.getHostCard().isCreature()
|
||||
&& sa.getPayCosts() != null
|
||||
&& (sa.getPayCosts().hasSpecificCostType(CostRemoveCounter.class) || sa.getPayCosts().hasSpecificCostType(CostSacrifice.class))) {
|
||||
if (!game.getStack().isEmpty()) {
|
||||
SpellAbility saTop = game.getStack().peekAbility();
|
||||
|
||||
@@ -81,7 +81,7 @@ public class ManaEffectAi extends SpellAbilityAi {
|
||||
return true; // handled elsewhere, does not meet the standard requirements
|
||||
}
|
||||
|
||||
return sa.getPayCosts() != null && sa.getPayCosts().hasNoManaCost() && sa.getPayCosts().isReusuableResource()
|
||||
return sa.getPayCosts().hasNoManaCost() && sa.getPayCosts().isReusuableResource()
|
||||
&& sa.getSubAbility() == null && ComputerUtil.playImmediately(ai, sa);
|
||||
// return super.checkApiLogic(ai, sa);
|
||||
}
|
||||
@@ -119,7 +119,7 @@ public class ManaEffectAi extends SpellAbilityAi {
|
||||
int numCounters = 0;
|
||||
int manaSurplus = 0;
|
||||
if ("XChoice".equals(host.getSVar("X"))
|
||||
&& sa.getPayCosts() != null && sa.getPayCosts().hasSpecificCostType(CostRemoveCounter.class)) {
|
||||
&& sa.getPayCosts().hasSpecificCostType(CostRemoveCounter.class)) {
|
||||
CounterType ctrType = CounterType.KI; // Petalmane Baku
|
||||
for (CostPart part : sa.getPayCosts().getCostParts()) {
|
||||
if (part instanceof CostRemoveCounter) {
|
||||
|
||||
@@ -84,8 +84,8 @@ public class PlayAi extends SpellAbilityAi {
|
||||
return ComputerUtil.targetPlayableSpellCard(ai, cards, sa, sa.hasParam("WithoutManaCost"));
|
||||
} else if (logic.startsWith("NeedsChosenCard")) {
|
||||
int minCMC = 0;
|
||||
if (sa.getPayCosts() != null && sa.getPayCosts().getCostMana() != null) {
|
||||
minCMC = sa.getPayCosts().getCostMana().getMana().getCMC();
|
||||
if (sa.getPayCosts().getCostMana() != null) {
|
||||
minCMC = sa.getPayCosts().getTotalMana().getCMC();
|
||||
}
|
||||
validOpts = CardLists.filter(validOpts, CardPredicates.greaterCMC(minCMC));
|
||||
return chooseSingleCard(ai, sa, validOpts, sa.hasParam("Optional"), null) != null;
|
||||
@@ -156,9 +156,7 @@ public class PlayAi extends SpellAbilityAi {
|
||||
if (sa.hasParam("WithoutManaCost")) {
|
||||
// Try to avoid casting instants and sorceries with X in their cost, since X will be assumed to be 0.
|
||||
if (!(spell instanceof SpellPermanent)) {
|
||||
if (spell.getPayCosts() != null
|
||||
&& spell.getPayCosts().getCostMana() != null
|
||||
&& spell.getPayCosts().getCostMana().getMana().countX() > 0) {
|
||||
if (spell.getPayCosts().getTotalMana().countX() > 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ public class ProtectAi extends SpellAbilityAi {
|
||||
if (game.getStack().isEmpty()) {
|
||||
// If the cost is tapping, don't activate before declare
|
||||
// attack/block
|
||||
if ((sa.getPayCosts() != null) && sa.getPayCosts().hasTapCost()) {
|
||||
if (sa.getPayCosts().hasTapCost()) {
|
||||
if (game.getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)
|
||||
&& game.getPhaseHandler().isPlayerTurn(ai)) {
|
||||
list.remove(sa.getHostCard());
|
||||
|
||||
@@ -515,7 +515,7 @@ public class PumpAi extends PumpAiBase {
|
||||
if (game.getStack().isEmpty()) {
|
||||
// If the cost is tapping, don't activate before declare
|
||||
// attack/block
|
||||
if (sa.getPayCosts() != null && sa.getPayCosts().hasTapCost()) {
|
||||
if (sa.getPayCosts().hasTapCost()) {
|
||||
if (game.getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)
|
||||
&& game.getPhaseHandler().isPlayerTurn(ai)) {
|
||||
list.remove(sa.getHostCard());
|
||||
|
||||
@@ -94,7 +94,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
||||
List<Card> attackers = CardLists.filter(ai.getCreaturesInPlay(), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
if (c.equals(sa.getHostCard()) && sa.getPayCosts() != null && sa.getPayCosts().hasTapCost()
|
||||
if (c.equals(sa.getHostCard()) && sa.getPayCosts().hasTapCost()
|
||||
&& (combat == null || !combat.isAttacking(c))) {
|
||||
return false;
|
||||
}
|
||||
@@ -112,7 +112,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
||||
List<Card> attackers = CardLists.filter(ai.getCreaturesInPlay(), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
if (c.equals(sa.getHostCard()) && sa.getPayCosts() != null && sa.getPayCosts().hasTapCost()
|
||||
if (c.equals(sa.getHostCard()) && sa.getPayCosts().hasTapCost()
|
||||
&& (combat == null || !combat.isAttacking(c))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public class RearrangeTopOfLibraryAi extends SpellAbilityAi {
|
||||
final PhaseHandler ph = aiPlayer.getGame().getPhaseHandler();
|
||||
final Card source = sa.getHostCard();
|
||||
|
||||
if (source.isPermanent() && sa.getRestrictions().isInstantSpeed() && sa.getPayCosts() != null
|
||||
if (source.isPermanent() && sa.getRestrictions().isInstantSpeed()
|
||||
&& (sa.getPayCosts().hasTapCost() || sa.getPayCosts().hasManaCost())) {
|
||||
// If it has an associated cost, try to only do this before own turn
|
||||
if (!(ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == aiPlayer)) {
|
||||
|
||||
@@ -46,12 +46,10 @@ public class ScryAi extends SpellAbilityAi {
|
||||
// and right before the beginning of AI's turn, if possible, to avoid mana locking the AI and also to
|
||||
// try to scry right before drawing a card. Also, avoid tapping creatures in the AI's turn, if possible,
|
||||
// even if there's no mana cost.
|
||||
if (sa.getPayCosts() != null) {
|
||||
if (sa.getPayCosts().hasTapCost()
|
||||
&& (sa.getPayCosts().hasManaCost() || (sa.getHostCard() != null && sa.getHostCard().isCreature()))
|
||||
&& !SpellAbilityAi.isSorcerySpeed(sa)) {
|
||||
return ph.getNextTurn() == ai && ph.is(PhaseType.END_OF_TURN);
|
||||
}
|
||||
if (sa.getPayCosts().hasTapCost()
|
||||
&& (sa.getPayCosts().hasManaCost() || (sa.getHostCard() != null && sa.getHostCard().isCreature()))
|
||||
&& !SpellAbilityAi.isSorcerySpeed(sa)) {
|
||||
return ph.getNextTurn() == ai && ph.is(PhaseType.END_OF_TURN);
|
||||
}
|
||||
|
||||
// AI logic to scry in Main 1 if there is no better option, otherwise scry at opponent's EOT
|
||||
@@ -76,8 +74,7 @@ public class ScryAi extends SpellAbilityAi {
|
||||
boolean hasSomethingElse = false;
|
||||
for (Card c : CardLists.filter(ai.getCardsIn(ZoneType.Hand), Predicates.not(CardPredicates.Presets.LANDS))) {
|
||||
for (SpellAbility ab : c.getAllSpellAbilities()) {
|
||||
if (ab.getPayCosts() != null
|
||||
&& ab.getPayCosts().hasManaCost()
|
||||
if (ab.getPayCosts().hasManaCost()
|
||||
&& ComputerUtilMana.hasEnoughManaSourcesToCast(ab, ai)) {
|
||||
// TODO: currently looks for non-Scry cards, can most certainly be made smarter.
|
||||
if (ab.getApi() != ApiType.Scry) {
|
||||
|
||||
@@ -47,12 +47,10 @@ public class SurveilAi extends SpellAbilityAi {
|
||||
// and right before the beginning of AI's turn, if possible, to avoid mana locking the AI and also to
|
||||
// try to scry right before drawing a card. Also, avoid tapping creatures in the AI's turn, if possible,
|
||||
// even if there's no mana cost.
|
||||
if (sa.getPayCosts() != null) {
|
||||
if (sa.getPayCosts().hasTapCost()
|
||||
&& (sa.getPayCosts().hasManaCost() || (sa.getHostCard() != null && sa.getHostCard().isCreature()))
|
||||
&& !SpellAbilityAi.isSorcerySpeed(sa)) {
|
||||
return ph.getNextTurn() == ai && ph.is(PhaseType.END_OF_TURN);
|
||||
}
|
||||
if (sa.getPayCosts().hasTapCost()
|
||||
&& (sa.getPayCosts().hasManaCost() || (sa.getHostCard() != null && sa.getHostCard().isCreature()))
|
||||
&& !SpellAbilityAi.isSorcerySpeed(sa)) {
|
||||
return ph.getNextTurn() == ai && ph.is(PhaseType.END_OF_TURN);
|
||||
}
|
||||
|
||||
// in the player's turn Surveil should only be done in Main1 or in Upkeep if able
|
||||
|
||||
@@ -126,7 +126,7 @@ public abstract class TapAiBase extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
for (final SpellAbility sa : c.getSpellAbilities()) {
|
||||
if (sa.isAbility() && sa.getPayCosts() != null && sa.getPayCosts().hasTapCost()) {
|
||||
if (sa.isAbility() && sa.getPayCosts().hasTapCost()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -147,7 +147,7 @@ public abstract class TapAiBase extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
for (final SpellAbility sa : c.getSpellAbilities()) {
|
||||
if (sa.isAbility() && sa.getPayCosts() != null && sa.getPayCosts().hasTapCost()) {
|
||||
if (sa.isAbility() && sa.getPayCosts().hasTapCost()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,12 +153,11 @@ public class UntapAi extends SpellAbilityAi {
|
||||
|
||||
// Try to avoid potential infinite recursion,
|
||||
// e.g. Kiora's Follower untapping another Kiora's Follower and repeating infinitely
|
||||
if (sa.getPayCosts() != null && sa.getPayCosts().hasOnlySpecificCostType(CostTap.class)) {
|
||||
if (sa.getPayCosts().hasOnlySpecificCostType(CostTap.class)) {
|
||||
CardCollection toRemove = new CardCollection();
|
||||
for (Card c : untapList) {
|
||||
for (SpellAbility ab : c.getAllSpellAbilities()) {
|
||||
if (ab.getApi() == ApiType.Untap
|
||||
&& ab.getPayCosts() != null
|
||||
&& ab.getPayCosts().hasOnlySpecificCostType(CostTap.class)
|
||||
&& ab.canTarget(source)) {
|
||||
toRemove.add(c);
|
||||
|
||||
@@ -81,7 +81,7 @@ public class ForgeScript {
|
||||
return !cardState.getTypeWithChanges().hasSubtype(subType);
|
||||
} else if (property.equals("hasActivatedAbilityWithTapCost")) {
|
||||
for (final SpellAbility sa : cardState.getSpellAbilities()) {
|
||||
if (sa.isAbility() && (sa.getPayCosts() != null) && sa.getPayCosts().hasTapCost()) {
|
||||
if (sa.isAbility() && sa.getPayCosts().hasTapCost()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,19 +177,6 @@ public class Game {
|
||||
playerCache.put(Integer.valueOf(id), player);
|
||||
}
|
||||
|
||||
private final GameEntityCache<Card, CardView> cardCache = new GameEntityCache<>();
|
||||
public Card getCard(CardView cardView) {
|
||||
return cardCache.get(cardView);
|
||||
}
|
||||
public void addCard(int id, Card card) {
|
||||
cardCache.put(Integer.valueOf(id), card);
|
||||
}
|
||||
public CardCollection getCardList(Iterable<CardView> cardViews) {
|
||||
CardCollection list = new CardCollection();
|
||||
cardCache.addToList(cardViews, list);
|
||||
return list;
|
||||
}
|
||||
|
||||
// methods that deal with saving, retrieving and clearing LKI information about cards on zone change
|
||||
private final HashMap<Integer, Card> changeZoneLKIInfo = new HashMap<>();
|
||||
public final void addChangeZoneLKIInfo(Card c) {
|
||||
@@ -537,6 +524,33 @@ public class Game {
|
||||
return visit.getFound(notFound);
|
||||
}
|
||||
|
||||
private static class CardIdVisitor extends Visitor<Card> {
|
||||
Card found = null;
|
||||
int id;
|
||||
|
||||
private CardIdVisitor(final int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(Card object) {
|
||||
if (this.id == object.getId()) {
|
||||
found = object;
|
||||
}
|
||||
return found == null;
|
||||
}
|
||||
|
||||
public Card getFound() {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
public Card findById(int id) {
|
||||
CardIdVisitor visit = new CardIdVisitor(id);
|
||||
this.forEachCardInGame(visit);
|
||||
return visit.getFound();
|
||||
}
|
||||
|
||||
// Allows visiting cards in game without allocating a temporary list.
|
||||
public void forEachCardInGame(Visitor<Card> visitor) {
|
||||
for (final Player player : getPlayers()) {
|
||||
@@ -874,7 +888,6 @@ public class Game {
|
||||
}
|
||||
|
||||
public void clearCaches() {
|
||||
cardCache.clear();
|
||||
|
||||
lastStateBattlefield.clear();
|
||||
lastStateGraveyard.clear();
|
||||
|
||||
@@ -13,6 +13,11 @@ public class GameEntityCache<Entity extends IIdentifiable, View extends Trackabl
|
||||
public void put(Integer id, Entity entity) {
|
||||
entityCache.put(id, entity);
|
||||
}
|
||||
public void putAll(Iterable<Entity> entities) {
|
||||
for (Entity e : entities) {
|
||||
put(e.getId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(Integer id) {
|
||||
entityCache.remove(id);
|
||||
|
||||
@@ -24,6 +24,12 @@ public abstract class GameEntityView extends TrackableObject {
|
||||
return collection;
|
||||
}
|
||||
|
||||
public static <T extends GameEntity, V extends GameEntityView> GameEntityViewMap<T, V> getMap(Iterable<T> spabs) {
|
||||
GameEntityViewMap<T, V> gameViewCache = new GameEntityViewMap<T, V>();
|
||||
gameViewCache.putAll(spabs);
|
||||
return gameViewCache;
|
||||
}
|
||||
|
||||
protected GameEntityView(final int id0, final Tracker tracker) {
|
||||
super(id0, tracker);
|
||||
}
|
||||
|
||||
52
forge-game/src/main/java/forge/game/GameEntityViewMap.java
Normal file
52
forge-game/src/main/java/forge/game/GameEntityViewMap.java
Normal file
@@ -0,0 +1,52 @@
|
||||
package forge.game;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.ForwardingMap;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.trackable.TrackableCollection;
|
||||
|
||||
public class GameEntityViewMap<Entity extends GameEntity, View extends GameEntityView> extends ForwardingMap<View, Entity> {
|
||||
private Map<View, Entity> dataMap = Maps.newLinkedHashMap();
|
||||
|
||||
@Override
|
||||
protected Map<View, Entity> delegate() {
|
||||
return dataMap;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void put(Entity e) {
|
||||
this.put((View) e.getView(), e);
|
||||
}
|
||||
|
||||
public void putAll(Iterable<Entity> entities) {
|
||||
for (Entity e : entities) {
|
||||
put(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(Entity e) {
|
||||
this.remove(e.getView());
|
||||
}
|
||||
|
||||
public void removeAll(Iterable<Entity> entities) {
|
||||
for (Entity e : entities) {
|
||||
remove(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void addToList(Iterable<View> views, List<Entity> list) {
|
||||
for (View view : views) {
|
||||
Entity entity = get(view);
|
||||
if (entity != null) {
|
||||
list.add(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TrackableCollection<View> getTrackableKeys() {
|
||||
return new TrackableCollection<View>(this.keySet());
|
||||
}
|
||||
}
|
||||
@@ -1344,7 +1344,7 @@ public class AbilityUtils {
|
||||
Player pl = sa.getActivatingPlayer();
|
||||
final Game game = pl.getGame();
|
||||
|
||||
if (sa.isTrigger() && sa.getParent() == null && sa.getPayCosts() != null) {
|
||||
if (sa.isTrigger() && sa.getParent() == null) {
|
||||
// when trigger cost are paid before the effect does resolve, need to clean the trigger
|
||||
game.getTriggerHandler().resetActiveTriggers();
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
* @param id0 the unique id of the new card.
|
||||
*/
|
||||
public Card(final int id0, final Game game0) {
|
||||
this(id0, null, true, game0);
|
||||
this(id0, null, game0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -307,15 +307,9 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
* @see IPaperCard
|
||||
*/
|
||||
public Card(final int id0, final IPaperCard paperCard0, final Game game0) {
|
||||
this(id0, paperCard0, true, game0);
|
||||
}
|
||||
public Card(final int id0, final IPaperCard paperCard0, final boolean allowCache, final Game game0) {
|
||||
super(id0);
|
||||
|
||||
game = game0;
|
||||
if (id0 >= 0 && allowCache && game != null) {
|
||||
game.addCard(id0, this);
|
||||
}
|
||||
paperCard = paperCard0;
|
||||
view = new CardView(id0, game == null ? null : game.getTracker());
|
||||
currentState = new CardState(view.getCurrentState(), this);
|
||||
@@ -2083,9 +2077,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
if (sa.isAdventure() && state.getView().getState().equals(CardStateName.Original)) {
|
||||
StringBuilder sbSA = new StringBuilder();
|
||||
sbSA.append("Adventure — ").append(getState(CardStateName.Adventure).getName());
|
||||
if (sa.getPayCosts() != null) {
|
||||
sbSA.append(" ").append(sa.getPayCosts().toSimpleString());
|
||||
}
|
||||
sbSA.append(" ").append(sa.getPayCosts().toSimpleString());
|
||||
sbSA.append(": ");
|
||||
sbSA.append(sAbility);
|
||||
sAbility = sbSA.toString();
|
||||
|
||||
@@ -118,39 +118,6 @@ public class CardFactory {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* copyCardWithChangedStats
|
||||
* </p>
|
||||
*
|
||||
* This method copies the card together with certain temporarily changed stats of the card
|
||||
* (namely, changed color, changed types, changed keywords).
|
||||
*
|
||||
* copyCardWithChangedStats must NOT be used for ordinary card copy operations because
|
||||
* according to MTG rules the changed text (including keywords, types) is not copied over
|
||||
* to cards cloned by another card. However, this method is useful, for example, for certain
|
||||
* triggers that demand the latest information about the changes to the card which is lost
|
||||
* when the card changes its zone after GameAction::changeZone is called.
|
||||
*
|
||||
* @param in
|
||||
* a {@link forge.game.card.Card} object.
|
||||
* @param assignNewId
|
||||
* a boolean
|
||||
* @return a {@link forge.game.card.Card} object.
|
||||
*/
|
||||
public static final Card copyCardWithChangedStats(final Card in, boolean assignNewId) {
|
||||
Card out = copyCard(in, assignNewId);
|
||||
|
||||
// Copy changed color, type, keyword arrays (useful for some triggers that require
|
||||
// information about the latest state of the card as it left the battlefield)
|
||||
out.setChangedCardColors(in.getChangedCardColors());
|
||||
out.setChangedCardKeywords(in.getChangedCardKeywords());
|
||||
out.setChangedCardTypes(in.getChangedCardTypesMap());
|
||||
out.setChangedCardNames(in.getChangedCardNames());
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* copySpellHost.
|
||||
@@ -471,23 +438,6 @@ public class CardFactory {
|
||||
CardFactoryUtil.addAbilityFactoryAbilities(c, face.getAbilities());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of a card, including its copiable characteristics (but not
|
||||
* abilities).
|
||||
* @param from
|
||||
* @param newOwner
|
||||
* @return
|
||||
*/
|
||||
public static Card copyCopiableCharacteristics(final Card from, final Player newOwner) {
|
||||
int id = newOwner == null ? 0 : newOwner.getGame().nextCardId();
|
||||
final Card c = new Card(id, from.getPaperCard(), from.getGame());
|
||||
c.setOwner(newOwner);
|
||||
c.setSetCode(from.getSetCode());
|
||||
|
||||
copyCopiableCharacteristics(from, c);
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the copiable characteristics of one card to another, taking the
|
||||
* states of both cards into account.
|
||||
|
||||
@@ -206,7 +206,7 @@ public final class CardUtil {
|
||||
.build()
|
||||
);
|
||||
|
||||
final Card newCopy = new Card(in.getId(), in.getPaperCard(), false, in.getGame());
|
||||
final Card newCopy = new Card(in.getId(), in.getPaperCard(), in.getGame());
|
||||
newCopy.setSetCode(in.getSetCode());
|
||||
newCopy.setOwner(in.getOwner());
|
||||
newCopy.setController(in.getController(), 0);
|
||||
|
||||
@@ -3067,7 +3067,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public void createMonarchEffect() {
|
||||
final PlayerZone com = getZone(ZoneType.Command);
|
||||
if (monarchEffect == null) {
|
||||
monarchEffect = new Card(game.nextCardId(), null, false, game);
|
||||
monarchEffect = new Card(game.nextCardId(), null, game);
|
||||
monarchEffect.setOwner(this);
|
||||
monarchEffect.setImageKey("t:monarch");
|
||||
monarchEffect.setName("The Monarch");
|
||||
@@ -3163,7 +3163,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
final PlayerZone com = getZone(ZoneType.Command);
|
||||
|
||||
if(bless) {
|
||||
blessingEffect = new Card(game.nextCardId(), null, false, game);
|
||||
blessingEffect = new Card(game.nextCardId(), null, game);
|
||||
blessingEffect.setOwner(this);
|
||||
blessingEffect.setImageKey("t:blessing");
|
||||
blessingEffect.setName("City's Blessing");
|
||||
@@ -3257,7 +3257,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
|
||||
final PlayerZone com = getZone(ZoneType.Command);
|
||||
|
||||
keywordEffect = new Card(game.nextCardId(), null, false, game);
|
||||
keywordEffect = new Card(game.nextCardId(), null, game);
|
||||
keywordEffect.setImmutable(true);
|
||||
keywordEffect.setOwner(this);
|
||||
keywordEffect.setName("Keyword Effects");
|
||||
|
||||
@@ -34,7 +34,7 @@ public class ReplaceProduceMana extends ReplacementEffect {
|
||||
//Check for tapping
|
||||
if (!hasParam("NoTapCheck")) {
|
||||
final SpellAbility manaAbility = (SpellAbility) runParams.get(AbilityKey.AbilityMana);
|
||||
if (manaAbility == null || manaAbility.getRootAbility().getPayCosts() == null || !manaAbility.getRootAbility().getPayCosts().hasTapCost()) {
|
||||
if (manaAbility == null || !manaAbility.getRootAbility().getPayCosts().hasTapCost()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,10 +145,8 @@ public abstract class Spell extends SpellAbility implements java.io.Serializable
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.getPayCosts() != null) {
|
||||
if (!CostPayment.canPayAdditionalCosts(this.getPayCosts(), this)) {
|
||||
return false;
|
||||
}
|
||||
if (!CostPayment.canPayAdditionalCosts(this.getPayCosts(), this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return checkOtherRestrictions(card);
|
||||
|
||||
@@ -442,16 +442,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
}
|
||||
|
||||
public boolean costHasX() {
|
||||
if (getPayCosts() == null) {
|
||||
return false;
|
||||
}
|
||||
return getPayCosts().hasXInAnyCostPart();
|
||||
}
|
||||
|
||||
public boolean costHasManaX() {
|
||||
if (getPayCosts() == null) {
|
||||
return false;
|
||||
}
|
||||
if (getPayCosts().hasNoManaCost()) {
|
||||
return false;
|
||||
}
|
||||
@@ -890,9 +884,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
|
||||
clone.triggeringObjects = AbilityKey.newMap(this.triggeringObjects);
|
||||
|
||||
if (getPayCosts() != null) {
|
||||
clone.setPayCosts(getPayCosts().copy());
|
||||
}
|
||||
clone.setPayCosts(getPayCosts().copy());
|
||||
if (manaPart != null) {
|
||||
clone.manaPart = new AbilityManaPart(host, mapParams);
|
||||
}
|
||||
@@ -1422,16 +1414,15 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
int maxTargets = getTargetRestrictions().getMaxTargets(hostCard, this);
|
||||
int numTargets = getTargets().getNumTargeted();
|
||||
|
||||
if (maxTargets == 0 && this.getPayCosts() != null
|
||||
&& this.getPayCosts().hasSpecificCostType(CostRemoveCounter.class)
|
||||
&& this.hasSVar(this.getParam("TargetMax"))
|
||||
&& this.getSVar(this.getParam("TargetMax")).startsWith("Count$CardCounters")
|
||||
&& this.getHostCard() != null && this.getHostCard().hasSVar("CostCountersRemoved")) {
|
||||
if (maxTargets == 0 && getPayCosts().hasSpecificCostType(CostRemoveCounter.class)
|
||||
&& hasSVar(getParam("TargetMax"))
|
||||
&& getSVar(getParam("TargetMax")).startsWith("Count$CardCounters")
|
||||
&& getHostCard() != null && getHostCard().hasSVar("CostCountersRemoved")) {
|
||||
// TODO: Current AI implementation removes the counters during payment before the
|
||||
// ability is added to stack, resulting in maxTargets=0 at this point. We are
|
||||
// assuming here that the AI logic specified a legal number, and that number ended
|
||||
// up being in CostCountersRemoved that is created on the card during payment.
|
||||
maxTargets = Integer.parseInt(this.getHostCard().getSVar("CostCountersRemoved"));
|
||||
maxTargets = Integer.parseInt(getHostCard().getSVar("CostCountersRemoved"));
|
||||
}
|
||||
|
||||
return minTargets <= numTargets && maxTargets >= numTargets;
|
||||
@@ -1775,9 +1766,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
targetRestrictions.applyTargetTextChanges(this);
|
||||
}
|
||||
|
||||
if (getPayCosts() != null) {
|
||||
getPayCosts().applyTextChangeEffects(this);
|
||||
}
|
||||
getPayCosts().applyTextChangeEffects(this);
|
||||
|
||||
stackDescription = AbilityUtils.applyDescriptionTextChangeEffects(originalStackDescription, this);
|
||||
description = AbilityUtils.applyDescriptionTextChangeEffects(originalDescription, this);
|
||||
|
||||
@@ -60,7 +60,7 @@ public class TriggerTapsForMana extends Trigger {
|
||||
//Check for tapping
|
||||
if (!hasParam("NoTapCheck")) {
|
||||
final SpellAbility manaAbility = (SpellAbility) runParams.get(AbilityKey.AbilityMana);
|
||||
if (manaAbility == null || manaAbility.getRootAbility().getPayCosts() == null || !manaAbility.getRootAbility().getPayCosts().hasTapCost()) {
|
||||
if (manaAbility == null || !manaAbility.getRootAbility().getPayCosts().hasTapCost()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.match.input;
|
||||
|
||||
import forge.card.mana.ManaAtom;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.game.Game;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.mana.ManaCostBeingPaid;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.model.FModel;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.properties.ForgePreferences;
|
||||
import forge.util.ITriggerEvent;
|
||||
import forge.util.Localizer;
|
||||
|
||||
//pays the cost of a card played from the player's hand
|
||||
//the card is removed from the players hand if the cost is paid
|
||||
//CANNOT be used for ABILITIES
|
||||
public class InputPayManaSimple extends InputPayMana {
|
||||
// anything that uses this should be converted to Ability_Cost
|
||||
/** Constant <code>serialVersionUID=3467312982164195091L</code>. */
|
||||
private static final long serialVersionUID = 3467312982164195091L;
|
||||
|
||||
private final Card originalCard;
|
||||
private final ManaCost originalManaCost;
|
||||
|
||||
public InputPayManaSimple(final PlayerControllerHuman controller, final Game game, final SpellAbility sa, final ManaCostBeingPaid manaCostToPay) {
|
||||
super(controller, sa, sa.getActivatingPlayer());
|
||||
this.originalManaCost = manaCostToPay.toManaCost();
|
||||
this.originalCard = sa.getHostCard();
|
||||
|
||||
if (sa.getHostCard().isCopiedSpell() && sa.isSpell()) {
|
||||
this.manaCost = new ManaCostBeingPaid(ManaCost.ZERO);
|
||||
game.getStack().add(this.saPaidFor);
|
||||
}
|
||||
else {
|
||||
this.manaCost = manaCostToPay;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onManaAbilityPaid() {
|
||||
if (this.manaCost.isPaid()) {
|
||||
this.originalCard.setSunburstValue(this.manaCost.getSunburst());
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected final void onPlayerSelected(final Player selected, final ITriggerEvent triggerEvent) {
|
||||
if (player == selected) {
|
||||
if (player.canPayLife(this.phyLifeToLose + 2)) {
|
||||
if (manaCost.payPhyrexian()) {
|
||||
this.phyLifeToLose += 2;
|
||||
} else {
|
||||
if (player.hasKeyword("PayLifeInsteadOf:B") && manaCost.hasAnyKind(ManaAtom.BLACK)) {
|
||||
manaCost.decreaseShard(ManaCostShard.BLACK, 1);
|
||||
this.phyLifeToLose += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.showMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* done.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
protected void done() {
|
||||
this.originalCard.setSunburstValue(this.manaCost.getSunburst());
|
||||
|
||||
if (this.phyLifeToLose > 0) {
|
||||
player.payLife(this.phyLifeToLose, this.originalCard);
|
||||
}
|
||||
if (!this.saPaidFor.getHostCard().isCopiedSpell()) {
|
||||
if (this.saPaidFor.isSpell()) {
|
||||
this.saPaidFor.setHostCard(game.getAction().moveToStack(this.originalCard, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected final void onCancel() {
|
||||
player.getManaPool().refundManaPaid(this.saPaidFor);
|
||||
// Update UI
|
||||
|
||||
this.stop();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public final void showMessage() {
|
||||
if (isFinished()) { return; }
|
||||
|
||||
updateButtons();
|
||||
|
||||
if (this.manaCost.isPaid() && !new ManaCostBeingPaid(this.originalManaCost).isPaid()) {
|
||||
this.done();
|
||||
this.stop();
|
||||
}
|
||||
else {
|
||||
updateMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.control.input.InputPayManaBase#updateMessage()
|
||||
*/
|
||||
@Override
|
||||
protected String getMessage() {
|
||||
final StringBuilder msg = new StringBuilder();
|
||||
final Localizer localizer = Localizer.getInstance();
|
||||
if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DETAILED_SPELLDESC_IN_PROMPT)) {
|
||||
msg.append(saPaidFor.getStackDescription().replace("(Targeting ERROR)", "")).append("\n\n");
|
||||
}
|
||||
msg.append(localizer.getMessage("lblPayManaCost")).append(" ").append(this.manaCost.toString(false, player.getManaPool()));
|
||||
if (this.phyLifeToLose > 0) {
|
||||
msg.append(" ").append(String.format(localizer.getMessage("lblLifePaidForPhyrexianMana"), this.phyLifeToLose));
|
||||
}
|
||||
|
||||
boolean isLifeInsteadBlack = player.hasKeyword("PayLifeInsteadOf:B") && manaCost.hasAnyKind(ManaAtom.BLACK);
|
||||
|
||||
if (manaCost.containsPhyrexianMana() || isLifeInsteadBlack) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (manaCost.containsPhyrexianMana() && !isLifeInsteadBlack) {
|
||||
sb.append(localizer.getMessage("lblClickOnYourLifeTotalToPayLifeForPhyrexianMana"));
|
||||
} else if (!manaCost.containsPhyrexianMana() && isLifeInsteadBlack) {
|
||||
sb.append(localizer.getMessage("lblClickOnYourLifeTotalToPayLifeForBlackMana"));
|
||||
} else if (manaCost.containsPhyrexianMana() && isLifeInsteadBlack) {
|
||||
sb.append(localizer.getMessage("lblClickOnYourLifeTotalToPayLifeForPhyrexianOrBlackMana"));
|
||||
}
|
||||
msg.append("\n(").append(sb).append(")");
|
||||
}
|
||||
|
||||
// has its own variant of checkIfPaid
|
||||
return msg.toString();
|
||||
}
|
||||
}
|
||||
@@ -110,7 +110,7 @@ public class InputProxy implements Observer {
|
||||
}
|
||||
|
||||
private Card getCard(final CardView cardView) {
|
||||
return controller.getGame().getCard(cardView);
|
||||
return controller.getCard(cardView);
|
||||
}
|
||||
|
||||
public final String getActivateAction(final CardView cardView) {
|
||||
|
||||
@@ -14,6 +14,8 @@ import com.google.common.collect.Lists;
|
||||
import forge.card.CardType;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.GameEntityViewMap;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
@@ -35,6 +37,7 @@ import forge.match.input.InputSelectManyBase;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.collect.FCollectionView;
|
||||
import forge.util.gui.SGuiChoose;
|
||||
import forge.util.ITriggerEvent;
|
||||
import forge.util.Localizer;
|
||||
import forge.util.CardTranslation;
|
||||
@@ -310,11 +313,12 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
if (nNeeded == 0) {
|
||||
return PaymentDecision.number(0);
|
||||
}
|
||||
final Game game = controller.getGame();
|
||||
final Player p = game.getPlayer(controller.getGui().oneOrNone(Localizer.getInstance().getMessage("lblExileFromWhoseZone", cost.getFrom().getTranslatedName()), PlayerView.getCollection(payableZone)));
|
||||
if (p == null) {
|
||||
GameEntityViewMap<Player, PlayerView> gameCachePlayer = GameEntityView.getMap(payableZone);
|
||||
final PlayerView pv = controller.getGui().oneOrNone(Localizer.getInstance().getMessage("lblExileFromWhoseZone", cost.getFrom().getTranslatedName()), gameCachePlayer.getTrackableKeys());
|
||||
if (pv == null || !gameCachePlayer.containsKey(pv)) {
|
||||
return null;
|
||||
}
|
||||
final Player p = gameCachePlayer.get(pv);
|
||||
|
||||
final CardCollection typeList = CardLists.filter(list, CardPredicates.isOwner(p));
|
||||
final int count = typeList.size();
|
||||
@@ -322,8 +326,13 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
return null;
|
||||
}
|
||||
|
||||
final CardCollection toExile = game.getCardList(controller.getGui().many(Localizer.getInstance().getMessage("lblExileFromZone", cost.getFrom().getTranslatedName()), Localizer.getInstance().getMessage("lblToBeExiled"), nNeeded, CardView.getCollection(typeList), null));
|
||||
return PaymentDecision.card(toExile);
|
||||
GameEntityViewMap<Card, CardView> gameCacheExile = GameEntityView.getMap(typeList);
|
||||
List<CardView> views = controller.getGui().many(
|
||||
Localizer.getInstance().getMessage("lblExileFromZone", cost.getFrom().getTranslatedName()),
|
||||
Localizer.getInstance().getMessage("lblToBeExiled"), nNeeded, gameCacheExile.getTrackableKeys(), null);
|
||||
List<Card> result = Lists.newArrayList();
|
||||
gameCacheExile.addToList(views, result);
|
||||
return PaymentDecision.card(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -395,20 +404,17 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
return PaymentDecision.card(list);
|
||||
}
|
||||
|
||||
private Card getCard(final CardView cardView) {
|
||||
return controller.getGame().getCard(cardView);
|
||||
}
|
||||
|
||||
private PaymentDecision exileFromMiscZone(final CostExile cost, final SpellAbility sa, final int nNeeded, final CardCollection typeList) {
|
||||
if (typeList.size() < nNeeded) { return null; }
|
||||
|
||||
GameEntityViewMap<Card, CardView> gameCacheCard = GameEntityView.getMap(typeList);
|
||||
|
||||
final CardCollection exiled = new CardCollection();
|
||||
for (int i = 0; i < nNeeded; i++) {
|
||||
final Card c = getCard(controller.getGui().oneOrNone(Localizer.getInstance().getMessage("lblExileProgressFromZone", String.valueOf(i + 1), String.valueOf(nNeeded), cost.getFrom().getTranslatedName()), CardView.getCollection(typeList)));
|
||||
if (c == null) { return null; }
|
||||
final CardView cv = controller.getGui().oneOrNone(Localizer.getInstance().getMessage("lblExileProgressFromZone", String.valueOf(i + 1), String.valueOf(nNeeded), cost.getFrom().getTranslatedName()), gameCacheCard.getTrackableKeys());
|
||||
if (cv == null || !gameCacheCard.containsKey(cv)) { return null; }
|
||||
|
||||
typeList.remove(c);
|
||||
exiled.add(c);
|
||||
exiled.add(gameCacheCard.remove(cv));
|
||||
}
|
||||
return PaymentDecision.card(exiled);
|
||||
}
|
||||
@@ -438,12 +444,17 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
if (ability.isOptionalTrigger()) {
|
||||
min = 0;
|
||||
}
|
||||
final CardCollection choice = controller.getGame().getCardList(controller.getGui().many(Localizer.getInstance().getMessage("lblChooseAnExiledCardPutIntoGraveyard"), Localizer.getInstance().getMessage("lblToGraveyard"), min, c, CardView.getCollection(list), CardView.get(source)));
|
||||
GameEntityViewMap<Card, CardView> gameCacheExile = GameEntityView.getMap(list);
|
||||
List<CardView> views = controller.getGui().many(
|
||||
Localizer.getInstance().getMessage("lblChooseAnExiledCardPutIntoGraveyard"),
|
||||
Localizer.getInstance().getMessage("lblToGraveyard"), min, c, CardView.getCollection(list), CardView.get(source));
|
||||
|
||||
if (choice == null || choice.size() < c) {
|
||||
if (views == null || views.size() < c) {
|
||||
return null;
|
||||
}
|
||||
return PaymentDecision.card(choice);
|
||||
List<Card> result = Lists.newArrayList();
|
||||
gameCacheExile.addToList(views, result);
|
||||
return PaymentDecision.card(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -555,11 +566,12 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
return PaymentDecision.players(oppsThatCanGainLife);
|
||||
}
|
||||
|
||||
final Player chosenToGain = controller.getGame().getPlayer(controller.getGui().oneOrNone(Localizer.getInstance().getMessage("lblCardChooseAnOpponentToGainNLife", CardTranslation.getTranslatedName(source.getName()), String.valueOf(c)), PlayerView.getCollection(oppsThatCanGainLife)));
|
||||
if (chosenToGain == null) {
|
||||
GameEntityViewMap<Player, PlayerView> gameCachePlayer = GameEntityView.getMap(oppsThatCanGainLife);
|
||||
final PlayerView pv = controller.getGui().oneOrNone(Localizer.getInstance().getMessage("lblCardChooseAnOpponentToGainNLife", CardTranslation.getTranslatedName(source.getName()), String.valueOf(c)), gameCachePlayer.getTrackableKeys());
|
||||
if (pv == null || !gameCachePlayer.containsKey(pv)) {
|
||||
return null;
|
||||
}
|
||||
return PaymentDecision.players(Lists.newArrayList(chosenToGain));
|
||||
return PaymentDecision.players(Lists.newArrayList(gameCachePlayer.get(pv)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -694,13 +706,13 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
}
|
||||
|
||||
final CardCollection chosen = new CardCollection();
|
||||
GameEntityViewMap<Card, CardView> gameCacheCard = GameEntityView.getMap(typeList);
|
||||
for (int i = 0; i < nNeeded; i++) {
|
||||
final Card c = getCard(controller.getGui().oneOrNone(Localizer.getInstance().getMessage("lblFromZonePutToLibrary", fromZone.getTranslatedName()), CardView.getCollection(typeList)));
|
||||
if (c == null) {
|
||||
final CardView cv = controller.getGui().oneOrNone(Localizer.getInstance().getMessage("lblFromZonePutToLibrary", fromZone.getTranslatedName()), gameCacheCard.getTrackableKeys());
|
||||
if (cv == null || !gameCacheCard.containsKey(cv)) {
|
||||
return null;
|
||||
}
|
||||
typeList.remove(c);
|
||||
chosen.add(c);
|
||||
chosen.add(gameCacheCard.remove(cv));
|
||||
}
|
||||
return PaymentDecision.card(chosen);
|
||||
}
|
||||
@@ -710,10 +722,12 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
return PaymentDecision.number(0);
|
||||
}
|
||||
|
||||
final Player p = controller.getGame().getPlayer(controller.getGui().oneOrNone(TextUtil.concatNoSpace(Localizer.getInstance().getMessage("lblPutCardsFromWhoseZone"), fromZone.getTranslatedName()), PlayerView.getCollection(payableZone)));
|
||||
if (p == null) {
|
||||
GameEntityViewMap<Player, PlayerView> gameCachePlayer = GameEntityView.getMap(payableZone);
|
||||
PlayerView pv = SGuiChoose.oneOrNone(TextUtil.concatNoSpace(Localizer.getInstance().getMessage("lblPutCardsFromWhoseZone"), fromZone.getTranslatedName()), gameCachePlayer.getTrackableKeys());
|
||||
if (pv == null || !gameCachePlayer.containsKey(pv)) {
|
||||
return null;
|
||||
}
|
||||
Player p = gameCachePlayer.get(pv);
|
||||
|
||||
final CardCollection typeList = CardLists.filter(list, CardPredicates.isOwner(p));
|
||||
if (typeList.size() < nNeeded) {
|
||||
@@ -721,13 +735,13 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
}
|
||||
|
||||
final CardCollection chosen = new CardCollection();
|
||||
GameEntityViewMap<Card, CardView> gameCacheCard = GameEntityView.getMap(typeList);
|
||||
for (int i = 0; i < nNeeded; i++) {
|
||||
final Card c = getCard(controller.getGui().oneOrNone(Localizer.getInstance().getMessage("lblPutZoneCardsToLibrary", fromZone.getTranslatedName()), CardView.getCollection(typeList)));
|
||||
if (c == null) {
|
||||
final CardView cv = controller.getGui().oneOrNone(Localizer.getInstance().getMessage("lblPutZoneCardsToLibrary", fromZone.getTranslatedName()), gameCacheCard.getTrackableKeys());
|
||||
if (cv == null || !gameCacheCard.containsKey(cv)) {
|
||||
return null;
|
||||
}
|
||||
typeList.remove(c);
|
||||
chosen.add(c);
|
||||
chosen.add(gameCacheCard.remove(cv));
|
||||
}
|
||||
return PaymentDecision.card(chosen);
|
||||
}
|
||||
@@ -1068,15 +1082,14 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
}
|
||||
|
||||
// Rift Elemental only - always removes 1 counter, so there will be no code for N counters.
|
||||
final List<CardView> suspended = Lists.newArrayList();
|
||||
for (final Card crd : validCards) {
|
||||
if (crd.getCounters(cost.counter) > 0) {
|
||||
suspended.add(CardView.get(crd));
|
||||
}
|
||||
GameEntityViewMap<Card, CardView> gameCacheSuspended = GameEntityView.getMap(CardLists.filter(validCards, CardPredicates.hasCounter(cost.counter)));
|
||||
|
||||
final CardView cv = controller.getGui().oneOrNone(Localizer.getInstance().getMessage("lblRemoveCountersFromAInZoneCard", cost.zone.getTranslatedName()), gameCacheSuspended.getTrackableKeys());
|
||||
if (cv == null || !gameCacheSuspended.containsKey(cv)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Card card = getCard(controller.getGui().oneOrNone(Localizer.getInstance().getMessage("lblRemoveCountersFromAInZoneCard", cost.zone.getTranslatedName()), suspended));
|
||||
return null == card ? null : PaymentDecision.card(card, c);
|
||||
return PaymentDecision.card(gameCacheSuspended.get(cv), c);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -6,6 +6,8 @@ import forge.FThreads;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameActionUtil;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.GameEntityViewMap;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.ability.effects.CharmEffect;
|
||||
@@ -23,7 +25,6 @@ import forge.game.trigger.TriggerType;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.match.input.InputPayMana;
|
||||
import forge.match.input.InputPayManaOfCostPayment;
|
||||
import forge.match.input.InputPayManaSimple;
|
||||
import forge.match.input.InputSelectCardsFromList;
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.collect.FCollectionView;
|
||||
@@ -94,34 +95,9 @@ public class HumanPlay {
|
||||
source.animateBestow();
|
||||
}
|
||||
|
||||
// Need to check PayCosts, and Ability + All SubAbilities for Target
|
||||
boolean newAbility = sa.getPayCosts() != null;
|
||||
SpellAbility ability = sa;
|
||||
while ((ability != null) && !newAbility) {
|
||||
final TargetRestrictions tgt = ability.getTargetRestrictions();
|
||||
|
||||
newAbility |= tgt != null;
|
||||
ability = ability.getSubAbility();
|
||||
}
|
||||
|
||||
// System.out.println("Playing:" + sa.getDescription() + " of " + sa.getHostCard() + " new = " + newAbility);
|
||||
if (newAbility) {
|
||||
|
||||
final HumanPlaySpellAbility req = new HumanPlaySpellAbility(controller, sa);
|
||||
if (!req.playAbility(true, false, false)) {
|
||||
if (flippedToCast && !castFaceDown) {
|
||||
source.turnFaceDown(true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} else if (payManaCostIfNeeded(controller, p, sa)) {
|
||||
if (sa.isSpell() && !source.isCopiedSpell()) {
|
||||
sa.setHostCard(p.getGame().getAction().moveToStack(source, sa));
|
||||
}
|
||||
|
||||
p.getGame().getStack().add(sa);
|
||||
} else {
|
||||
// Failed to pay costs, revert to original state
|
||||
final HumanPlaySpellAbility req = new HumanPlaySpellAbility(controller, sa);
|
||||
if (!req.playAbility(true, false, false)) {
|
||||
if (flippedToCast && !castFaceDown) {
|
||||
source.turnFaceDown(true);
|
||||
}
|
||||
@@ -159,26 +135,6 @@ public class HumanPlay {
|
||||
//final List<SpellAbility> abilities = GameActionUtil.getOptionalCosts(original);
|
||||
}
|
||||
|
||||
private static boolean payManaCostIfNeeded(final PlayerControllerHuman controller, final Player p, final SpellAbility sa) {
|
||||
final ManaCostBeingPaid manaCost;
|
||||
if (sa.getHostCard().isCopiedSpell() && sa.isSpell()) {
|
||||
manaCost = new ManaCostBeingPaid(ManaCost.ZERO);
|
||||
}
|
||||
else {
|
||||
manaCost = new ManaCostBeingPaid(sa.getPayCosts().getTotalMana());
|
||||
CostAdjustment.adjust(manaCost, sa, null, false);
|
||||
}
|
||||
|
||||
boolean isPaid = manaCost.isPaid();
|
||||
|
||||
if (!isPaid) {
|
||||
InputPayManaSimple inputPay = new InputPayManaSimple(controller, p.getGame(), sa, manaCost);
|
||||
inputPay.showAndWait();
|
||||
isPaid = inputPay.isPaid();
|
||||
}
|
||||
return isPaid;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* playSpellAbilityForFree.
|
||||
@@ -193,26 +149,15 @@ public class HumanPlay {
|
||||
|
||||
source.setSplitStateToPlayAbility(sa);
|
||||
|
||||
if (sa.getPayCosts() != null) {
|
||||
if (!sa.isCopied()) {
|
||||
if (sa.getApi() == ApiType.Charm && !sa.isWrapper()) {
|
||||
CharmEffect.makeChoices(sa);
|
||||
}
|
||||
sa = AbilityUtils.addSpliceEffects(sa);
|
||||
if (!sa.isCopied()) {
|
||||
if (sa.getApi() == ApiType.Charm && !sa.isWrapper()) {
|
||||
CharmEffect.makeChoices(sa);
|
||||
}
|
||||
sa = AbilityUtils.addSpliceEffects(sa);
|
||||
}
|
||||
|
||||
final HumanPlaySpellAbility req = new HumanPlaySpellAbility(controller, sa);
|
||||
req.playAbility(mayChooseNewTargets, true, false);
|
||||
}
|
||||
else {
|
||||
if (sa.isSpell()) {
|
||||
final Card c = sa.getHostCard();
|
||||
if (!c.isCopiedSpell()) {
|
||||
sa.setHostCard(game.getAction().moveToStack(c, sa));
|
||||
}
|
||||
}
|
||||
game.getStack().add(sa);
|
||||
}
|
||||
final HumanPlaySpellAbility req = new HumanPlaySpellAbility(controller, sa);
|
||||
req.playAbility(mayChooseNewTargets, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,14 +175,8 @@ public class HumanPlay {
|
||||
public final static void playSpellAbilityNoStack(final PlayerControllerHuman controller, final Player player, final SpellAbility sa, boolean useOldTargets) {
|
||||
sa.setActivatingPlayer(player);
|
||||
|
||||
if (sa.getPayCosts() != null) {
|
||||
final HumanPlaySpellAbility req = new HumanPlaySpellAbility(controller, sa);
|
||||
|
||||
req.playAbility(!useOldTargets, false, true);
|
||||
}
|
||||
else if (payManaCostIfNeeded(controller, player, sa)) {
|
||||
AbilityUtils.resolve(sa);
|
||||
}
|
||||
final HumanPlaySpellAbility req = new HumanPlaySpellAbility(controller, sa);
|
||||
req.playAbility(!useOldTargets, false, true);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -506,14 +445,13 @@ public class HumanPlay {
|
||||
} else {
|
||||
// replace this with input
|
||||
CardCollection newList = new CardCollection();
|
||||
GameEntityViewMap<Card, CardView> gameCacheList = GameEntityView.getMap(list);
|
||||
for (int i = 0; i < nNeeded; i++) {
|
||||
final Card c = p.getGame().getCard(SGuiChoose.oneOrNone(Localizer.getInstance().getMessage("lblExileFromZone", from.getTranslatedName()), CardView.getCollection(list)));
|
||||
if (c == null) {
|
||||
final CardView cv = SGuiChoose.oneOrNone(Localizer.getInstance().getMessage("lblExileFromZone", from.getTranslatedName()), gameCacheList.getTrackableKeys());
|
||||
if (cv == null || !gameCacheList.containsKey(cv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
list.remove(c);
|
||||
newList.add(c);
|
||||
newList.add(gameCacheList.remove(cv));
|
||||
}
|
||||
costExile.payAsDecided(p, PaymentDecision.card(newList), sourceAbility);
|
||||
}
|
||||
@@ -543,27 +481,28 @@ public class HumanPlay {
|
||||
payableZone.add(player);
|
||||
}
|
||||
}
|
||||
Player chosen = controller.getGame().getPlayer(SGuiChoose.oneOrNone(Localizer.getInstance().getMessage("lblPutCardFromWhoseZone", from.getTranslatedName()), PlayerView.getCollection(payableZone)));
|
||||
if (chosen == null) {
|
||||
GameEntityViewMap<Player, PlayerView> gameCachePlayer = GameEntityView.getMap(payableZone);
|
||||
PlayerView pv = SGuiChoose.oneOrNone(Localizer.getInstance().getMessage("lblPutCardFromWhoseZone", from.getTranslatedName()), gameCachePlayer.getTrackableKeys());
|
||||
if (pv == null || !gameCachePlayer.containsKey(pv)) {
|
||||
return false;
|
||||
}
|
||||
Player chosen = gameCachePlayer.get(pv);
|
||||
|
||||
List<Card> typeList = CardLists.filter(list, CardPredicates.isOwner(chosen));
|
||||
|
||||
GameEntityViewMap<Card, CardView> gameCacheTypeList = GameEntityView.getMap(typeList);
|
||||
for (int i = 0; i < amount; i++) {
|
||||
if (typeList.isEmpty()) {
|
||||
if (gameCacheTypeList.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Card c = p.getGame().getCard(SGuiChoose.oneOrNone(Localizer.getInstance().getMessage("lblPutCardToLibrary"), CardView.getCollection(typeList)));
|
||||
|
||||
if (c != null) {
|
||||
typeList.remove(c);
|
||||
p.getGame().getAction().moveToLibrary(c, Integer.parseInt(((CostPutCardToLib) part).getLibPos()), null);
|
||||
}
|
||||
else {
|
||||
final CardView cv = SGuiChoose.oneOrNone(Localizer.getInstance().getMessage("lblPutCardToLibrary"), gameCacheTypeList.getTrackableKeys());
|
||||
if (cv == null || !gameCacheTypeList.containsKey(cv)) {
|
||||
return false;
|
||||
}
|
||||
final Card c = gameCacheTypeList.get(cv);
|
||||
|
||||
gameCacheTypeList.remove(c);
|
||||
p.getGame().getAction().moveToLibrary(c, Integer.parseInt(((CostPutCardToLib) part).getLibPos()), null);
|
||||
}
|
||||
}
|
||||
else { // Tainted Specter, Gurzigost, etc.
|
||||
|
||||
@@ -114,7 +114,7 @@ public class HumanPlaySpellAbility {
|
||||
|
||||
ability = GameActionUtil.addExtraKeywordCost(ability);
|
||||
|
||||
Cost abCost = ability.getPayCosts() == null ? new Cost("0", ability.isAbility()) : ability.getPayCosts();
|
||||
Cost abCost = ability.getPayCosts();
|
||||
CostPayment payment = new CostPayment(abCost, ability);
|
||||
|
||||
// TODO Apply this to the SAStackInstance instead of the Player
|
||||
|
||||
@@ -96,6 +96,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
private final Localizer localizer = Localizer.getInstance();
|
||||
|
||||
protected Map<SpellAbilityView, SpellAbility> spellViewCache = null;
|
||||
protected GameEntityViewMap<Card, CardView> gameCache = new GameEntityViewMap<>();
|
||||
|
||||
public PlayerControllerHuman(final Game game0, final Player p, final LobbyPlayer lp) {
|
||||
super(game0, p, lp);
|
||||
@@ -151,7 +152,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
if (t instanceof Card) {
|
||||
tempShowCard((Card) t);
|
||||
} else if (t instanceof CardView) {
|
||||
tempShowCard(game.getCard((CardView) t));
|
||||
tempShowCard(getCard((CardView) t));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -287,14 +288,16 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
if (defender != null && assignDamageAsIfNotBlocked(attacker)) {
|
||||
map.put(null, damageDealt);
|
||||
} else {
|
||||
final List<CardView> vBlockers = CardView.getCollection(blockers);
|
||||
if ((attacker.hasKeyword(Keyword.TRAMPLE) && defender != null) || (blockers.size() > 1)) {
|
||||
GameEntityViewMap<Card, CardView> gameCacheBlockers = GameEntityView.getMap(blockers);
|
||||
final CardView vAttacker = CardView.get(attacker);
|
||||
final GameEntityView vDefender = GameEntityView.get(defender);
|
||||
final Map<CardView, Integer> result = getGui().assignCombatDamage(vAttacker, vBlockers, damageDealt,
|
||||
final Map<CardView, Integer> result = getGui().assignCombatDamage(vAttacker, gameCacheBlockers.getTrackableKeys(), damageDealt,
|
||||
vDefender, overrideOrder);
|
||||
for (final Entry<CardView, Integer> e : result.entrySet()) {
|
||||
map.put(game.getCard(e.getKey()), e.getValue());
|
||||
if (gameCacheBlockers.containsKey(e.getKey())) {
|
||||
map.put(gameCacheBlockers.get(e.getKey()), e.getValue());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
map.put(blockers.get(0), damageDealt);
|
||||
@@ -377,9 +380,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
|
||||
final boolean useUiPointAtCard =
|
||||
(FModel.getPreferences().getPrefBoolean(FPref.UI_SELECT_FROM_CARD_DISPLAYS) && (!GuiBase.getInterface().isLibgdxPort())) ?
|
||||
(cz.is(ZoneType.Battlefield) || cz.is(ZoneType.Hand) || cz.is(ZoneType.Library) ||
|
||||
cz.is(ZoneType.Graveyard) || cz.is(ZoneType.Exile) || cz.is(ZoneType.Flashback) || cz.is(ZoneType.Command)) :
|
||||
(cz.is(ZoneType.Hand) && cz.getPlayer() == player || cz.is(ZoneType.Battlefield));
|
||||
(cz.is(ZoneType.Battlefield) || cz.is(ZoneType.Hand) || cz.is(ZoneType.Library) ||
|
||||
cz.is(ZoneType.Graveyard) || cz.is(ZoneType.Exile) || cz.is(ZoneType.Flashback) || cz.is(ZoneType.Command)) :
|
||||
(cz.is(ZoneType.Hand) && cz.getPlayer() == player || cz.is(ZoneType.Battlefield));
|
||||
if (!useUiPointAtCard) {
|
||||
return false;
|
||||
}
|
||||
@@ -412,23 +415,15 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
}
|
||||
|
||||
tempShowCards(sourceList);
|
||||
final CardCollection choices = getGame().getCardList(getGui().many(title, localizer.getMessage("lblChosenCards"), min, max,
|
||||
CardView.getCollection(sourceList), CardView.get(sa.getHostCard())));
|
||||
GameEntityViewMap<Card, CardView> gameCachechoose = GameEntityView.getMap(sourceList);
|
||||
List<CardView> views = getGui().many(title, localizer.getMessage("lblChosenCards"), min, max,
|
||||
gameCachechoose.getTrackableKeys(), CardView.get(sa.getHostCard()));
|
||||
endTempShowCards();
|
||||
|
||||
final CardCollection choices = new CardCollection();
|
||||
gameCachechoose.addToList(views, choices);
|
||||
return choices;
|
||||
}
|
||||
|
||||
// pfps there should be a better way
|
||||
private GameEntity convertToEntity(final GameEntityView view) {
|
||||
if (view instanceof CardView) {
|
||||
return game.getCard((CardView) view);
|
||||
} else if (view instanceof PlayerView) {
|
||||
return game.getPlayer((PlayerView) view);
|
||||
} else return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends GameEntity> T chooseSingleEntityForEffect(final FCollectionView<T> optionList,
|
||||
final DelayedReveal delayedReveal, final SpellAbility sa, final String title, final boolean isOptional,
|
||||
@@ -454,6 +449,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
if (delayedReveal != null) {
|
||||
tempShow(delayedReveal.getCards());
|
||||
}
|
||||
|
||||
GameEntityViewMap<T, GameEntityView> gameCacheChoose = GameEntityView.getMap(optionList);
|
||||
|
||||
if (useSelectCardsInput(optionList)) {
|
||||
final InputSelectEntitiesFromList<T> input = new InputSelectEntitiesFromList<>(this, isOptional ? 0 : 1, 1,
|
||||
optionList, sa);
|
||||
@@ -465,21 +463,25 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
}
|
||||
|
||||
final GameEntityView result = getGui().chooseSingleEntityForEffect(title,
|
||||
GameEntityView.getEntityCollection(optionList), delayedReveal, isOptional);
|
||||
gameCacheChoose.getTrackableKeys(), delayedReveal, isOptional);
|
||||
endTempShowCards();
|
||||
return (T) convertToEntity(result);
|
||||
if (result != null || !gameCacheChoose.containsKey(result)) {
|
||||
return null;
|
||||
}
|
||||
return gameCacheChoose.get(result);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends GameEntity> List<T> chooseEntitiesForEffect(final FCollectionView<T> optionList, final int min, final int max,
|
||||
final DelayedReveal delayedReveal, final SpellAbility sa, final String title, final Player targetedPlayer) {
|
||||
public <T extends GameEntity> List<T> chooseEntitiesForEffect(final FCollectionView<T> optionList, final int min,
|
||||
final int max, final DelayedReveal delayedReveal, final SpellAbility sa, final String title,
|
||||
final Player targetedPlayer) {
|
||||
|
||||
// useful details for debugging problems with the mass select logic
|
||||
Sentry.getContext().addExtra("Card", sa.getCardView().toString());
|
||||
Sentry.getContext().addExtra("SpellAbility", sa.toString());
|
||||
|
||||
// Human is supposed to read the message and understand from it what to // choose
|
||||
// Human is supposed to read the message and understand from it what to //
|
||||
// choose
|
||||
if (optionList.isEmpty()) {
|
||||
if (delayedReveal != null) {
|
||||
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(),
|
||||
@@ -494,29 +496,24 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
|
||||
tempShow(optionList);
|
||||
if (useSelectCardsInput(optionList)) {
|
||||
final InputSelectEntitiesFromList<T> input = new InputSelectEntitiesFromList<>(this, min, max,
|
||||
optionList, sa);
|
||||
final InputSelectEntitiesFromList<T> input = new InputSelectEntitiesFromList<>(this, min, max, optionList,
|
||||
sa);
|
||||
input.setCancelAllowed(min == 0);
|
||||
input.setMessage(MessageUtil.formatMessage(title, player, targetedPlayer));
|
||||
input.showAndWait();
|
||||
endTempShowCards();
|
||||
return (List<T>) input.getSelected();
|
||||
}
|
||||
final List<GameEntityView> chosen = getGui().chooseEntitiesForEffect(title,
|
||||
GameEntityView.getEntityCollection(optionList), min, max, delayedReveal);
|
||||
endTempShowCards();
|
||||
|
||||
List<T> results = new ArrayList<>(); //pfps I'm not sure that the chosens should be modified this way
|
||||
if (chosen instanceof List && chosen.size() > 0) {
|
||||
for (GameEntityView entry: chosen) {
|
||||
if (entry instanceof CardView) {
|
||||
results.add((T)game.getCard((CardView) entry));
|
||||
}
|
||||
if (entry instanceof PlayerView) {
|
||||
results.add((T)game.getPlayer((PlayerView) entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
GameEntityViewMap<T, GameEntityView> gameCacheEntity = GameEntityView.getMap(optionList);
|
||||
final List<GameEntityView> views = getGui().chooseEntitiesForEffect(title, gameCacheEntity.getTrackableKeys(), min, max, delayedReveal);
|
||||
endTempShowCards();
|
||||
|
||||
List<T> results = Lists.newArrayList();
|
||||
|
||||
if (views != null) {
|
||||
gameCacheEntity.addToList(views, results);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -686,43 +683,50 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
|
||||
@Override
|
||||
public CardCollection orderBlockers(final Card attacker, final CardCollection blockers) {
|
||||
GameEntityViewMap<Card, CardView> gameCacheBlockers = GameEntityView.getMap(blockers);
|
||||
final CardView vAttacker = CardView.get(attacker);
|
||||
getGui().setPanelSelection(vAttacker);
|
||||
return game.getCardList(getGui().order(localizer.getMessage("lblChooseDamageOrderFor", CardTranslation.getTranslatedName(vAttacker.getName())), localizer.getMessage("lblDamagedFirst"),
|
||||
CardView.getCollection(blockers), vAttacker));
|
||||
List<CardView> chosen = getGui().order(localizer.getMessage("lblChooseDamageOrderFor", CardTranslation.getTranslatedName(vAttacker.getName())), localizer.getMessage("lblDamagedFirst"),
|
||||
gameCacheBlockers.getTrackableKeys(), vAttacker);
|
||||
CardCollection chosenCards = new CardCollection();
|
||||
gameCacheBlockers.addToList(chosen, chosenCards);
|
||||
return chosenCards;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Card> exertAttackers(List<Card> attackers) {
|
||||
HashMap<CardView, Card> mapCVtoC = new HashMap<>();
|
||||
for (Card card : attackers) {
|
||||
mapCVtoC.put(card.getView(), card);
|
||||
}
|
||||
List<CardView> chosen;
|
||||
List<CardView> choices = new ArrayList<>(mapCVtoC.keySet());
|
||||
chosen = getGui().order(localizer.getMessage("lblExertAttackersConfirm"), localizer.getMessage("lblExerted"), 0, choices.size(), choices, null, null, false);
|
||||
List<Card> chosenCards = new ArrayList<>();
|
||||
for (CardView cardView : chosen) {
|
||||
chosenCards.add(mapCVtoC.get(cardView));
|
||||
}
|
||||
GameEntityViewMap<Card, CardView> gameCacheExert = GameEntityView.getMap(attackers);
|
||||
List<CardView> chosen = getGui().order(localizer.getMessage("lblExertAttackersConfirm"), localizer.getMessage("lblExerted"),
|
||||
0, gameCacheExert.size(), gameCacheExert.getTrackableKeys(), null, null, false);
|
||||
|
||||
List<Card> chosenCards = new CardCollection();
|
||||
gameCacheExert.addToList(chosen, chosenCards);
|
||||
return chosenCards;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CardCollection orderBlocker(final Card attacker, final Card blocker, final CardCollection oldBlockers) {
|
||||
GameEntityViewMap<Card, CardView> gameCacheBlockers = GameEntityView.getMap(oldBlockers);
|
||||
final CardView vAttacker = CardView.get(attacker);
|
||||
getGui().setPanelSelection(vAttacker);
|
||||
return game.getCardList(getGui().insertInList(
|
||||
List<CardView> chosen = getGui().insertInList(
|
||||
localizer.getMessage("lblChooseBlockerAfterWhichToPlaceAttackert", CardTranslation.getTranslatedName(vAttacker.getName())),
|
||||
CardView.get(blocker), CardView.getCollection(oldBlockers)));
|
||||
CardView.get(blocker), CardView.getCollection(oldBlockers));
|
||||
CardCollection chosenCards = new CardCollection();
|
||||
gameCacheBlockers.addToList(chosen, chosenCards);
|
||||
return chosenCards;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CardCollection orderAttackers(final Card blocker, final CardCollection attackers) {
|
||||
GameEntityViewMap<Card, CardView> gameCacheAttackers = GameEntityView.getMap(attackers);
|
||||
final CardView vBlocker = CardView.get(blocker);
|
||||
getGui().setPanelSelection(vBlocker);
|
||||
return game.getCardList(getGui().order(localizer.getMessage("lblChooseDamageOrderFor", CardTranslation.getTranslatedName(vBlocker.getName())), localizer.getMessage("lblDamagedFirst"),
|
||||
CardView.getCollection(attackers), vBlocker));
|
||||
List<CardView> chosen = getGui().order(localizer.getMessage("lblChooseDamageOrderFor", CardTranslation.getTranslatedName(vBlocker.getName())), localizer.getMessage("lblDamagedFirst"),
|
||||
CardView.getCollection(attackers), vBlocker);
|
||||
CardCollection chosenCards = new CardCollection();
|
||||
gameCacheAttackers.addToList(chosen, chosenCards);
|
||||
return chosenCards;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -739,7 +743,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
}
|
||||
final String fm = MessageUtil.formatMessage(message, getLocalPlayerView(), owner);
|
||||
if (!cards.isEmpty()) {
|
||||
tempShowCards(game.getCardList(cards));
|
||||
tempShowCards(getCardList(cards));
|
||||
getGui().reveal(fm, cards);
|
||||
endTempShowCards();
|
||||
} else {
|
||||
@@ -749,23 +753,27 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
}
|
||||
|
||||
public List<Card> manipulateCardList(final String title, final Iterable<Card> cards, final Iterable<Card> manipulable, final boolean toTop, final boolean toBottom, final boolean toAnywhere) {
|
||||
Iterable<CardView> result = getGui().manipulateCardList(title, CardView.getCollection(cards), CardView.getCollection(manipulable), toTop, toBottom, toAnywhere);
|
||||
return game.getCardList(result);
|
||||
GameEntityViewMap<Card, CardView> gameCacheManipulate = GameEntityView.getMap(cards);
|
||||
gameCacheManipulate.putAll(manipulable);
|
||||
List<CardView> views = getGui().manipulateCardList(title, CardView.getCollection(cards), CardView.getCollection(manipulable), toTop, toBottom, toAnywhere);
|
||||
List<Card> result = new CardCollection();
|
||||
gameCacheManipulate.addToList(views, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImmutablePair<CardCollection, CardCollection> arrangeForMove(final String title, final FCollectionView<Card> cards, final List<Card> manipulable, final boolean topOK, final boolean bottomOK) {
|
||||
List<Card> result = manipulateCardList(localizer.getMessage("lblMoveCardstoToporBbottomofLibrary"), cards, manipulable, topOK, bottomOK, false);
|
||||
List<Card> result = manipulateCardList(localizer.getMessage("lblMoveCardstoToporBbottomofLibrary"), cards, manipulable, topOK, bottomOK, false);
|
||||
CardCollection toBottom = new CardCollection();
|
||||
CardCollection toTop = new CardCollection();
|
||||
for (int i = 0; i<cards.size() && manipulable.contains(result.get(i)) ; i++ ) {
|
||||
toTop.add(result.get(i));
|
||||
}
|
||||
if (toTop.size() < cards.size()) { // the top isn't everything
|
||||
for (int i = result.size()-1; i>=0 && manipulable.contains(result.get(i)); i-- ) {
|
||||
toBottom.add(result.get(i));
|
||||
for (int i = 0; i<cards.size() && manipulable.contains(result.get(i)) ; i++ ) {
|
||||
toTop.add(result.get(i));
|
||||
}
|
||||
}
|
||||
return ImmutablePair.of(toTop,toBottom);
|
||||
if (toTop.size() < cards.size()) { // the top isn't everything
|
||||
for (int i = result.size()-1; i>=0 && manipulable.contains(result.get(i)); i-- ) {
|
||||
toBottom.add(result.get(i));
|
||||
}
|
||||
}
|
||||
return ImmutablePair.of(toTop,toBottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -789,16 +797,24 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
toBottom = topN;
|
||||
}
|
||||
} else {
|
||||
toBottom = game.getCardList(getGui().many(localizer.getMessage("lblSelectCardsToBeOutOnTheBottomOfYourLibrary"),
|
||||
localizer.getMessage("lblCardsToPutOnTheBottom"), -1, CardView.getCollection(topN), null));
|
||||
GameEntityViewMap<Card, CardView> cardCacheScry = GameEntityView.getMap(topN);
|
||||
|
||||
toBottom = new CardCollection();
|
||||
List<CardView> views = getGui().many(localizer.getMessage("lblSelectCardsToBeOutOnTheBottomOfYourLibrary"),
|
||||
localizer.getMessage("lblCardsToPutOnTheBottom"), -1, cardCacheScry.getTrackableKeys(), null);
|
||||
cardCacheScry.addToList(views, toBottom);
|
||||
|
||||
topN.removeAll(toBottom);
|
||||
if (topN.isEmpty()) {
|
||||
toTop = null;
|
||||
} else if (topN.size() == 1) {
|
||||
toTop = topN;
|
||||
} else {
|
||||
toTop = game.getCardList(getGui().order(localizer.getMessage("lblArrangeCardsToBePutOnTopOfYourLibrary"),
|
||||
localizer.getMessage("lblTopOfLibrary"), CardView.getCollection(topN), null));
|
||||
GameEntityViewMap<Card, CardView> cardCacheOrder = GameEntityView.getMap(topN);
|
||||
toTop = new CardCollection();
|
||||
views = getGui().order(localizer.getMessage("lblArrangeCardsToBePutOnTopOfYourLibrary"),
|
||||
localizer.getMessage("lblTopOfLibrary"), cardCacheOrder.getTrackableKeys(), null);
|
||||
cardCacheOrder.addToList(views, toTop);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -827,16 +843,22 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
toGrave = topN;
|
||||
}
|
||||
} else {
|
||||
toGrave = game.getCardList(getGui().many(localizer.getMessage("lblSelectCardsToBePutIntoTheGraveyard"),
|
||||
localizer.getMessage("lblCardsToPutInTheGraveyard"), -1, CardView.getCollection(topN), null));
|
||||
GameEntityViewMap<Card, CardView> gameCacheSurveil = GameEntityView.getMap(topN);
|
||||
toGrave = new CardCollection();
|
||||
List<CardView> views = getGui().many(localizer.getMessage("lblSelectCardsToBePutIntoTheGraveyard"),
|
||||
localizer.getMessage("lblCardsToPutInTheGraveyard"), -1, gameCacheSurveil.getTrackableKeys(), null);
|
||||
gameCacheSurveil.addToList(views, toGrave);
|
||||
topN.removeAll(toGrave);
|
||||
if (topN.isEmpty()) {
|
||||
toTop = null;
|
||||
} else if (topN.size() == 1) {
|
||||
toTop = topN;
|
||||
} else {
|
||||
toTop = game.getCardList(getGui().order(localizer.getMessage("lblArrangeCardsToBePutOnTopOfYourLibrary"),
|
||||
localizer.getMessage("lblTopOfLibrary"), CardView.getCollection(topN), null));
|
||||
GameEntityViewMap<Card, CardView> cardCacheOrder = GameEntityView.getMap(topN);
|
||||
toTop = new CardCollection();
|
||||
views = getGui().order(localizer.getMessage("lblArrangeCardsToBePutOnTopOfYourLibrary"),
|
||||
localizer.getMessage("lblTopOfLibrary"), cardCacheOrder.getTrackableKeys(), null);
|
||||
cardCacheOrder.addToList(views, toTop);
|
||||
}
|
||||
}
|
||||
endTempShowCards();
|
||||
@@ -882,32 +904,28 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
}
|
||||
}
|
||||
|
||||
List<CardView> choices;
|
||||
tempShowCards(cards);
|
||||
GameEntityViewMap<Card, CardView> gameCacheMove = GameEntityView.getMap(cards);
|
||||
List<CardView> choices = gameCacheMove.getTrackableKeys();
|
||||
|
||||
switch (destinationZone) {
|
||||
case Library:
|
||||
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoLibrary"), localizer.getMessage("lblClosestToTop"),
|
||||
CardView.getCollection(cards), null);
|
||||
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoLibrary"), localizer.getMessage("lblClosestToTop"), choices, null);
|
||||
break;
|
||||
case Battlefield:
|
||||
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutOntoBattlefield"), localizer.getMessage("lblPutFirst"),
|
||||
CardView.getCollection(cards), null);
|
||||
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutOntoBattlefield"), localizer.getMessage("lblPutFirst"), choices, null);
|
||||
break;
|
||||
case Graveyard:
|
||||
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoGraveyard"), localizer.getMessage("lblClosestToBottom"),
|
||||
CardView.getCollection(cards), null);
|
||||
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoGraveyard"), localizer.getMessage("lblClosestToBottom"), choices, null);
|
||||
break;
|
||||
case PlanarDeck:
|
||||
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoPlanarDeck"), localizer.getMessage("lblClosestToTop"),
|
||||
CardView.getCollection(cards), null);
|
||||
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoPlanarDeck"), localizer.getMessage("lblClosestToTop"), choices, null);
|
||||
break;
|
||||
case SchemeDeck:
|
||||
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoSchemeDeck"), localizer.getMessage("lblClosestToTop"),
|
||||
CardView.getCollection(cards), null);
|
||||
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoSchemeDeck"), localizer.getMessage("lblClosestToTop"), choices, null);
|
||||
break;
|
||||
case Stack:
|
||||
choices = getGui().order(localizer.getMessage("lblChooseOrderCopiesCast"), localizer.getMessage("lblPutFirst"), CardView.getCollection(cards),
|
||||
null);
|
||||
choices = getGui().order(localizer.getMessage("lblChooseOrderCopiesCast"), localizer.getMessage("lblPutFirst"), choices, null);
|
||||
break;
|
||||
default:
|
||||
System.out.println("ZoneType " + destinationZone + " - Not Ordered");
|
||||
@@ -915,7 +933,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
return cards;
|
||||
}
|
||||
endTempShowCards();
|
||||
return game.getCardList(choices);
|
||||
CardCollection result = new CardCollection();
|
||||
gameCacheMove.addToList(choices, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -923,10 +943,12 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
final CardCollection valid, final int min, final int max) {
|
||||
if (p != player) {
|
||||
tempShowCards(valid);
|
||||
final CardCollection choices = game
|
||||
.getCardList(getGui().many(String.format(localizer.getMessage("lblChooseMinCardToDiscard"), min),
|
||||
localizer.getMessage("lblDiscarded"), min, min, CardView.getCollection(valid), null));
|
||||
GameEntityViewMap<Card, CardView> gameCacheDiscard = GameEntityView.getMap(valid);
|
||||
List<CardView> views = getGui().many(String.format(localizer.getMessage("lblChooseMinCardToDiscard"), min),
|
||||
localizer.getMessage("lblDiscarded"), min, min, gameCacheDiscard.getTrackableKeys(), null);
|
||||
endTempShowCards();
|
||||
final CardCollection choices = new CardCollection();
|
||||
gameCacheDiscard.addToList(views, choices);
|
||||
return choices;
|
||||
}
|
||||
|
||||
@@ -949,18 +971,19 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
cntChoice.add(Integer.valueOf(i));
|
||||
}
|
||||
final int chosenAmount = getGui().one(localizer.getMessage("lblDelveHowManyCards"), cntChoice.build()).intValue();
|
||||
for (int i = 0; i < chosenAmount; i++) {
|
||||
final CardView nowChosen = getGui().oneOrNone(localizer.getMessage("lblExileWhichCard", String.valueOf(i + 1), String.valueOf(chosenAmount)), CardView.getCollection(grave));
|
||||
|
||||
if (nowChosen == null) {
|
||||
GameEntityViewMap<Card, CardView> gameCacheGrave = GameEntityView.getMap(grave);
|
||||
for (int i = 0; i < chosenAmount; i++) {
|
||||
String title = localizer.getMessage("lblExileWhichCard", String.valueOf(i + 1), String.valueOf(chosenAmount));
|
||||
final CardView nowChosen = getGui().oneOrNone(title, gameCacheGrave.getTrackableKeys());
|
||||
|
||||
if (nowChosen == null || !gameCacheGrave.containsKey(nowChosen)) {
|
||||
// User canceled,abort delving.
|
||||
toExile.clear();
|
||||
break;
|
||||
}
|
||||
|
||||
final Card card = game.getCard(nowChosen);
|
||||
grave.remove(card);
|
||||
toExile.add(card);
|
||||
toExile.add(gameCacheGrave.remove(nowChosen));
|
||||
}
|
||||
return toExile;
|
||||
}
|
||||
@@ -1355,6 +1378,8 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
|
||||
@Override
|
||||
public List<SpellAbility> chooseSaToActivateFromOpeningHand(final List<SpellAbility> usableFromOpeningHand) {
|
||||
|
||||
|
||||
final CardCollection srcCards = new CardCollection();
|
||||
for (final SpellAbility sa : usableFromOpeningHand) {
|
||||
srcCards.add(sa.getHostCard());
|
||||
@@ -1363,10 +1388,15 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
if (srcCards.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
GameEntityViewMap<Card, CardView> gameCacheOpenHand = GameEntityView.getMap(srcCards);
|
||||
|
||||
final List<CardView> chosen = getGui().many(localizer.getMessage("lblChooseCardsActivateOpeningHandandOrder"),
|
||||
localizer.getMessage("lblActivateFirst"), -1, CardView.getCollection(srcCards), null);
|
||||
for (final CardView view : chosen) {
|
||||
final Card c = game.getCard(view);
|
||||
if (!gameCacheOpenHand.containsKey(view)) {
|
||||
continue;
|
||||
}
|
||||
final Card c = gameCacheOpenHand.get(view);
|
||||
for (final SpellAbility sa : usableFromOpeningHand) {
|
||||
if (sa.getHostCard() == c) {
|
||||
result.add(sa);
|
||||
@@ -2160,12 +2190,14 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
|
||||
public void modifyCountersOnPermanent(boolean subtract) {
|
||||
final String titleMsg = subtract ? localizer.getMessage("lblRemoveCountersFromWhichCard") : localizer.getMessage("lblAddCountersToWhichCard");
|
||||
final CardCollectionView cards = game.getCardsIn(ZoneType.Battlefield);
|
||||
final Card card = game
|
||||
.getCard(getGui().oneOrNone(titleMsg, CardView.getCollection(cards)));
|
||||
if (card == null) {
|
||||
|
||||
GameEntityViewMap<Card, CardView> gameCacheCounters = GameEntityView.getMap(game.getCardsIn(ZoneType.Battlefield));
|
||||
|
||||
final CardView cv = getGui().oneOrNone(titleMsg, gameCacheCounters.getTrackableKeys());
|
||||
if (cv == null || !gameCacheCounters.containsKey(cv)) {
|
||||
return;
|
||||
}
|
||||
final Card card = gameCacheCounters.get(cv);
|
||||
|
||||
final ImmutableList<CounterType> counters = subtract ? ImmutableList.copyOf(card.getCounters().keySet())
|
||||
: CounterType.values;
|
||||
@@ -2247,11 +2279,14 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
*/
|
||||
@Override
|
||||
public void setPlayerLife() {
|
||||
final Player player = game.getPlayer(
|
||||
getGui().oneOrNone(localizer.getMessage("lblSetLifeforWhichPlayer"), PlayerView.getCollection(game.getPlayers())));
|
||||
if (player == null) {
|
||||
|
||||
GameEntityViewMap<Player, PlayerView> gameCachePlayer = GameEntityView.getMap(game.getPlayers());
|
||||
|
||||
final PlayerView pv = getGui().oneOrNone(localizer.getMessage("lblSetLifeforWhichPlayer"), gameCachePlayer.getTrackableKeys());
|
||||
if (pv == null || !gameCachePlayer.containsKey(pv)) {
|
||||
return;
|
||||
}
|
||||
final Player player = gameCachePlayer.get(pv);
|
||||
|
||||
final Integer life = getGui().getInteger(localizer.getMessage("lblSetLifetoWhat"), 0);
|
||||
if (life == null) {
|
||||
@@ -2375,12 +2410,21 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
}
|
||||
}
|
||||
|
||||
final Player p = repeatLast ? lastAddedPlayer
|
||||
: game.getPlayer(getGui().oneOrNone(message,
|
||||
PlayerView.getCollection(game.getPlayers())));
|
||||
if (p == null) {
|
||||
return;
|
||||
Player pOld = lastAddedPlayer;
|
||||
if (repeatLast) {
|
||||
if (pOld == null) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
GameEntityViewMap<Player, PlayerView> gameCachePlayer = GameEntityView.getMap(game.getPlayers());
|
||||
PlayerView pv = getGui().oneOrNone(message, gameCachePlayer.getTrackableKeys());
|
||||
if (pv == null || !gameCachePlayer.containsKey(pv)) {
|
||||
return;
|
||||
}
|
||||
pOld = gameCachePlayer.get(pv);
|
||||
}
|
||||
final Player p = pOld;
|
||||
|
||||
|
||||
final CardDb carddb = FModel.getMagicDb().getCommonCards();
|
||||
final List<ICardFace> faces = Lists.newArrayList(carddb.getAllFaces());
|
||||
@@ -2483,30 +2527,33 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
*/
|
||||
@Override
|
||||
public void exileCardsFromHand() {
|
||||
final Player p = game.getPlayer(getGui().oneOrNone(localizer.getMessage("lblExileCardsFromPlayerHandConfirm"),
|
||||
PlayerView.getCollection(game.getPlayers())));
|
||||
if (p == null) {
|
||||
GameEntityViewMap<Player, PlayerView> gameCachePlayer = GameEntityView.getMap(game.getPlayers());
|
||||
|
||||
final PlayerView pv = getGui().oneOrNone(localizer.getMessage("lblExileCardsFromPlayerHandConfirm"),
|
||||
gameCachePlayer.getTrackableKeys());
|
||||
if (pv == null || !gameCachePlayer.containsKey(pv)) {
|
||||
return;
|
||||
}
|
||||
Player p = gameCachePlayer.get(pv);
|
||||
|
||||
final CardCollection selection;
|
||||
GameEntityViewMap<Card, CardView> gameCacheExile = GameEntityView.getMap(p.getCardsIn(ZoneType.Hand));
|
||||
|
||||
CardCollectionView cardsInHand = p.getCardsIn(ZoneType.Hand);
|
||||
selection = game.getCardList(getGui().many(localizer.getMessage("lblChooseCardsExile"), localizer.getMessage("lblDiscarded"), 0, -1,
|
||||
CardView.getCollection(cardsInHand), null));
|
||||
List<CardView> views = getGui().many(localizer.getMessage("lblChooseCardsExile"), localizer.getMessage("lblDiscarded"), 0, -1,
|
||||
gameCacheExile.getTrackableKeys(), null);
|
||||
|
||||
if (selection != null && selection.size() > 0) {
|
||||
for (Card c : selection) {
|
||||
if (c == null) {
|
||||
continue;
|
||||
}
|
||||
if (game.getAction().moveTo(ZoneType.Exile, c, null) != null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(p).append(" exiles ").append(c).append(" due to Dev Cheats.");
|
||||
game.getGameLog().add(GameLogEntryType.DISCARD, sb.toString());
|
||||
} else {
|
||||
game.getGameLog().add(GameLogEntryType.INFORMATION, "DISCARD CHEAT ERROR");
|
||||
}
|
||||
final CardCollection selection = new CardCollection();
|
||||
gameCacheExile.addToList(views, selection);
|
||||
|
||||
for (Card c : selection) {
|
||||
if (c == null) {
|
||||
continue;
|
||||
}
|
||||
if (game.getAction().moveTo(ZoneType.Exile, c, null) != null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(p).append(" exiles ").append(c).append(" due to Dev Cheats.");
|
||||
game.getGameLog().add(GameLogEntryType.DISCARD, sb.toString());
|
||||
} else {
|
||||
game.getGameLog().add(GameLogEntryType.INFORMATION, "DISCARD CHEAT ERROR");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2518,30 +2565,33 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
*/
|
||||
@Override
|
||||
public void exileCardsFromBattlefield() {
|
||||
final Player p = game.getPlayer(getGui().oneOrNone(localizer.getMessage("lblExileCardsFromPlayerBattlefieldConfirm"),
|
||||
PlayerView.getCollection(game.getPlayers())));
|
||||
if (p == null) {
|
||||
GameEntityViewMap<Player, PlayerView> gameCachePlayer = GameEntityView.getMap(game.getPlayers());
|
||||
|
||||
final PlayerView pv = getGui().oneOrNone(localizer.getMessage("lblExileCardsFromPlayerBattlefieldConfirm"),
|
||||
gameCachePlayer.getTrackableKeys());
|
||||
if (pv == null || !gameCachePlayer.containsKey(pv)) {
|
||||
return;
|
||||
}
|
||||
Player p = gameCachePlayer.get(pv);
|
||||
|
||||
final CardCollection selection;
|
||||
GameEntityViewMap<Card, CardView> gameCacheExile = GameEntityView.getMap(p.getCardsIn(ZoneType.Battlefield));
|
||||
|
||||
CardCollectionView cardsInPlay = p.getCardsIn(ZoneType.Battlefield);
|
||||
selection = game.getCardList(getGui().many(localizer.getMessage("lblChooseCardsExile"), localizer.getMessage("lblDiscarded"), 0, -1,
|
||||
CardView.getCollection(cardsInPlay), null));
|
||||
List<CardView> views = getGui().many(localizer.getMessage("lblChooseCardsExile"), localizer.getMessage("lblDiscarded"), 0, -1,
|
||||
gameCacheExile.getTrackableKeys(), null);
|
||||
|
||||
if (selection != null && selection.size() > 0) {
|
||||
for (Card c : selection) {
|
||||
if (c == null) {
|
||||
continue;
|
||||
}
|
||||
if (game.getAction().moveTo(ZoneType.Exile, c, null) != null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(p).append(" exiles ").append(c).append(" due to Dev Cheats.");
|
||||
game.getGameLog().add(GameLogEntryType.ZONE_CHANGE, sb.toString());
|
||||
} else {
|
||||
game.getGameLog().add(GameLogEntryType.INFORMATION, "EXILE FROM PLAY CHEAT ERROR");
|
||||
}
|
||||
final CardCollection selection = new CardCollection();
|
||||
gameCacheExile.addToList(views, selection);
|
||||
|
||||
for (Card c : selection) {
|
||||
if (c == null) {
|
||||
continue;
|
||||
}
|
||||
if (game.getAction().moveTo(ZoneType.Exile, c, null) != null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(p).append(" exiles ").append(c).append(" due to Dev Cheats.");
|
||||
game.getGameLog().add(GameLogEntryType.ZONE_CHANGE, sb.toString());
|
||||
} else {
|
||||
game.getGameLog().add(GameLogEntryType.INFORMATION, "EXILE FROM PLAY CHEAT ERROR");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2553,33 +2603,36 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
*/
|
||||
@Override
|
||||
public void removeCardsFromGame() {
|
||||
final Player p = game.getPlayer(getGui().oneOrNone(localizer.getMessage("lblRemoveCardBelongingWitchPlayer"),
|
||||
PlayerView.getCollection(game.getPlayers())));
|
||||
if (p == null) {
|
||||
GameEntityViewMap<Player, PlayerView> gameCachePlayer = GameEntityView.getMap(game.getPlayers());
|
||||
|
||||
final PlayerView pv = getGui().oneOrNone(localizer.getMessage("lblRemoveCardBelongingWitchPlayer"),
|
||||
gameCachePlayer.getTrackableKeys());
|
||||
if (pv == null || !gameCachePlayer.containsKey(pv)) {
|
||||
return;
|
||||
}
|
||||
Player p = gameCachePlayer.get(pv);
|
||||
|
||||
final String zone = getGui().one(localizer.getMessage("lblRemoveCardFromWhichZone"),
|
||||
Arrays.asList("Hand", "Battlefield", "Library", "Graveyard", "Exile"));
|
||||
|
||||
final CardCollection selection;
|
||||
|
||||
CardCollectionView cards = p.getCardsIn(ZoneType.smartValueOf(zone));
|
||||
selection = game.getCardList(getGui().many(localizer.getMessage("lblChooseCardsRemoveFromGame"), localizer.getMessage("lblRemoved"), 0, -1,
|
||||
CardView.getCollection(cards), null));
|
||||
GameEntityViewMap<Card, CardView> gameCacheExile = GameEntityView.getMap(cards);
|
||||
List<CardView> views = getGui().many(localizer.getMessage("lblChooseCardsRemoveFromGame"), localizer.getMessage("lblRemoved"), 0, -1,
|
||||
gameCacheExile.getTrackableKeys(), null);
|
||||
|
||||
if (selection != null && selection.size() > 0) {
|
||||
for (Card c : selection) {
|
||||
if (c == null) {
|
||||
continue;
|
||||
}
|
||||
c.getZone().remove(c);
|
||||
c.ceaseToExist();
|
||||
final CardCollection selection = new CardCollection();
|
||||
gameCacheExile.addToList(views, selection);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(p).append(" removes ").append(c).append(" from game due to Dev Cheats.");
|
||||
game.getGameLog().add(GameLogEntryType.ZONE_CHANGE, sb.toString());
|
||||
for (Card c : selection) {
|
||||
if (c == null) {
|
||||
continue;
|
||||
}
|
||||
c.getZone().remove(c);
|
||||
c.ceaseToExist();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(p).append(" removes ").append(c).append(" from game due to Dev Cheats.");
|
||||
game.getGameLog().add(GameLogEntryType.ZONE_CHANGE, sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2590,11 +2643,13 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
*/
|
||||
@Override
|
||||
public void riggedPlanarRoll() {
|
||||
final Player player = game.getPlayer(
|
||||
getGui().oneOrNone(localizer.getMessage("lblWhichPlayerShouldRoll"), PlayerView.getCollection(game.getPlayers())));
|
||||
if (player == null) {
|
||||
GameEntityViewMap<Player, PlayerView> gameCachePlayer = GameEntityView.getMap(game.getPlayers());
|
||||
|
||||
final PlayerView pv = getGui().oneOrNone(localizer.getMessage("lblWhichPlayerShouldRoll"), gameCachePlayer.getTrackableKeys());
|
||||
if (pv == null || !gameCachePlayer.containsKey(pv)) {
|
||||
return;
|
||||
}
|
||||
final Player player = gameCachePlayer.get(pv);
|
||||
|
||||
final PlanarDice res = getGui().oneOrNone(localizer.getMessage("lblChooseResult"), PlanarDice.values);
|
||||
if (res == null) {
|
||||
@@ -2868,7 +2923,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
@Override
|
||||
public void reorderHand(final CardView card, final int index) {
|
||||
final PlayerZone hand = player.getZone(ZoneType.Hand);
|
||||
hand.reorder(game.getCard(card), index);
|
||||
hand.reorder(getCard(card), index);
|
||||
player.updateZoneForView(hand);
|
||||
}
|
||||
|
||||
@@ -2880,24 +2935,19 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
|
||||
@Override
|
||||
public List<Card> chooseCardsForSplice(SpellAbility sa, List<Card> cards) {
|
||||
HashMap<CardView, Card> mapCVtoC = new HashMap<>();
|
||||
for (Card card : cards) {
|
||||
mapCVtoC.put(card.getView(), card);
|
||||
}
|
||||
List<CardView> choices = new ArrayList<>(mapCVtoC.keySet());
|
||||
List<CardView> chosen;
|
||||
chosen = getGui().many(
|
||||
GameEntityViewMap<Card, CardView> gameCacheSplice = GameEntityView.getMap(cards);
|
||||
|
||||
List<CardView> chosen = getGui().many(
|
||||
localizer.getMessage("lblChooseCardstoSpliceonto"),
|
||||
localizer.getMessage("lblChosenCards"),
|
||||
0,
|
||||
choices.size(),
|
||||
choices,
|
||||
gameCacheSplice.size(),
|
||||
gameCacheSplice.getTrackableKeys(),
|
||||
sa.getHostCard().getView()
|
||||
);
|
||||
List<Card> chosenCards = new ArrayList<>();
|
||||
for (CardView cardView : chosen) {
|
||||
chosenCards.add(mapCVtoC.get(cardView));
|
||||
}
|
||||
|
||||
List<Card> chosenCards = new CardCollection();
|
||||
gameCacheSplice.addToList(chosen, chosenCards);
|
||||
return chosenCards;
|
||||
}
|
||||
|
||||
@@ -2942,5 +2992,25 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
return result;
|
||||
}
|
||||
|
||||
public Card getCard(final CardView cardView) {
|
||||
if (gameCache.containsKey(cardView)) {
|
||||
return gameCache.get(cardView);
|
||||
}
|
||||
|
||||
final Card c = getGame().findById(cardView.getId());
|
||||
gameCache.put(cardView, c);
|
||||
return c;
|
||||
}
|
||||
|
||||
public CardCollection getCardList(Iterable<CardView> cardViews) {
|
||||
CardCollection result = new CardCollection();
|
||||
for(CardView cardView : cardViews){
|
||||
final Card c = this.getCard(cardView);
|
||||
if (c != null) {
|
||||
result.add(c);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.GameEntityViewMap;
|
||||
import forge.game.GameObject;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardUtil;
|
||||
@@ -175,6 +177,8 @@ public class TargetSelection {
|
||||
// Send in a list of valid cards, and popup a choice box to target
|
||||
final Game game = ability.getActivatingPlayer().getGame();
|
||||
|
||||
GameEntityViewMap<Card, CardView> gameCacheChooseCard = GameEntityView.getMap(choices);
|
||||
|
||||
final List<CardView> crdsBattle = Lists.newArrayList();
|
||||
final List<CardView> crdsExile = Lists.newArrayList();
|
||||
final List<CardView> crdsGrave = Lists.newArrayList();
|
||||
@@ -245,7 +249,10 @@ public class TargetSelection {
|
||||
}
|
||||
|
||||
if (chosen instanceof CardView) {
|
||||
ability.getTargets().add(game.getCard((CardView) chosen));
|
||||
if (!gameCacheChooseCard.containsKey(chosen)) {
|
||||
return false;
|
||||
}
|
||||
ability.getTargets().add(gameCacheChooseCard.get((CardView) chosen));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user