mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 03:38:01 +00:00
- Implemented <SubType> Offering ability from BOK.
- Added Patron of the Akki, Patron of the Kitsune, Patron of the Moon and Patron of the Orochi
This commit is contained in:
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -7827,6 +7827,10 @@ res/cardsfolder/p/patriarchs_desire.txt -text svneol=unset#text/plain
|
|||||||
res/cardsfolder/p/patricians_scorn.txt -text svneol=unset#text/plain
|
res/cardsfolder/p/patricians_scorn.txt -text svneol=unset#text/plain
|
||||||
res/cardsfolder/p/patrol_hound.txt -text
|
res/cardsfolder/p/patrol_hound.txt -text
|
||||||
res/cardsfolder/p/patrol_signaler.txt svneol=native#text/plain
|
res/cardsfolder/p/patrol_signaler.txt svneol=native#text/plain
|
||||||
|
res/cardsfolder/p/patron_of_the_akki.txt -text
|
||||||
|
res/cardsfolder/p/patron_of_the_kitsune.txt -text
|
||||||
|
res/cardsfolder/p/patron_of_the_moon.txt -text
|
||||||
|
res/cardsfolder/p/patron_of_the_orochi.txt -text
|
||||||
res/cardsfolder/p/patron_of_the_wild.txt svneol=native#text/plain
|
res/cardsfolder/p/patron_of_the_wild.txt svneol=native#text/plain
|
||||||
res/cardsfolder/p/patron_wizard.txt svneol=native#text/plain
|
res/cardsfolder/p/patron_wizard.txt svneol=native#text/plain
|
||||||
res/cardsfolder/p/pattern_of_rebirth.txt svneol=native#text/plain
|
res/cardsfolder/p/pattern_of_rebirth.txt svneol=native#text/plain
|
||||||
|
|||||||
11
res/cardsfolder/p/patron_of_the_akki.txt
Normal file
11
res/cardsfolder/p/patron_of_the_akki.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
Name:Patron of the Akki
|
||||||
|
ManaCost:4 R R
|
||||||
|
Types:Legendary Creature Spirit
|
||||||
|
PT:5/5
|
||||||
|
K:Goblin offering
|
||||||
|
T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Whenever CARDNAME attacks, creatures you control get +2/+0 until end of turn.
|
||||||
|
SVar:TrigPump:AB$ PumpAll | Cost$ 0 | ValidCards$ Creature.YouCtrl | NumAtt$ 2
|
||||||
|
SVar:RemAIDeck:True
|
||||||
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/patron_of_the_akki.jpg
|
||||||
|
Oracle:Goblin offering (You may cast this card any time you could cast an instant by sacrificing a Goblin and paying the difference in mana costs between this and the sacrificed Goblin. Mana cost includes color.)\nWhenever Patron of the Akki attacks, creatures you control get +2/+0 until end of turn.
|
||||||
|
SetInfo:BOK Rare
|
||||||
11
res/cardsfolder/p/patron_of_the_kitsune.txt
Normal file
11
res/cardsfolder/p/patron_of_the_kitsune.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
Name:Patron of the Kitsune
|
||||||
|
ManaCost:4 W W
|
||||||
|
Types:Legendary Creature Spirit
|
||||||
|
PT:5/6
|
||||||
|
K:Fox offering
|
||||||
|
T:Mode$ Attacks | ValidCard$ Creature | TriggerZones$ Battlefield | Execute$ PatronLife | OptionalDecider$ You | TriggerDescription$ Whenever a creature attacks, you gain 1 life.
|
||||||
|
SVar:PatronLife:AB$ GainLife | Cost$ 0 | LifeAmount$ 1
|
||||||
|
SVar:RemAIDeck:True
|
||||||
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/patron_of_the_kitsune.jpg
|
||||||
|
Oracle:Fox offering (You may cast this card any time you could cast an instant by sacrificing a Fox and paying the difference in mana costs between this and the sacrificed Fox. Mana cost includes color.)\nWhenever a creature attacks, you may gain 1 life.
|
||||||
|
SetInfo:BOK Rare
|
||||||
11
res/cardsfolder/p/patron_of_the_moon.txt
Normal file
11
res/cardsfolder/p/patron_of_the_moon.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
Name:Patron of the Moon
|
||||||
|
ManaCost:5 U U
|
||||||
|
Types:Legendary Creature Spirit
|
||||||
|
PT:5/4
|
||||||
|
K:Moonfolk offering
|
||||||
|
K:Flying
|
||||||
|
A:AB$ ChangeZone | Cost$ 1 | ChangeNum$ 2 | Origin$ Hand | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.YouCtrl | SpellDescription$ Put up to two land cards from your hand onto the battlefield tapped.
|
||||||
|
SVar:RemAIDeck:True
|
||||||
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/patron_of_the_moon.jpg
|
||||||
|
Oracle:Moonfolk offering (You may cast this card any time you could cast an instant by sacrificing a Moonfolk and paying the difference in mana costs between this and the sacrificed Moonfolk. Mana cost includes color.)\nFlying\n{1}: Put up to two land cards from your hand onto the battlefield tapped.
|
||||||
|
SetInfo:BOK Rare
|
||||||
10
res/cardsfolder/p/patron_of_the_orochi.txt
Normal file
10
res/cardsfolder/p/patron_of_the_orochi.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Name:Patron of the Orochi
|
||||||
|
ManaCost:6 G G
|
||||||
|
Types:Legendary Creature Spirit
|
||||||
|
PT:7/7
|
||||||
|
K:Snake offering
|
||||||
|
A:AB$ UntapAll | Cost$ T | ValidCards$ Forest,Creature.Green | ActivationLimit$ 1 | SpellDescription$ Untap all Forests and all green creatures. Activate this ability only once each turn.
|
||||||
|
SVar:RemAIDeck:True
|
||||||
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/patron_of_the_orochi.jpg
|
||||||
|
Oracle:Snake offering (You may cast this card any time you could cast an instant by sacrificing a Snake and paying the difference in mana costs between this and the sacrificed Snake. Mana cost includes color.)\n{T}: Untap all Forests and all green creatures. Activate this ability only once each turn.
|
||||||
|
SetInfo:BOK Rare
|
||||||
@@ -2149,6 +2149,17 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
sb.append("\r\n");
|
sb.append("\r\n");
|
||||||
}
|
}
|
||||||
sb.append("Convoke (Each creature you tap while casting this spell reduces its cost by 1 or by one mana of that creature's color.)");
|
sb.append("Convoke (Each creature you tap while casting this spell reduces its cost by 1 or by one mana of that creature's color.)");
|
||||||
|
} else if (keyword.endsWith(" offering")) {
|
||||||
|
String offeringType = keyword.split(" ")[0];
|
||||||
|
if (sb.length() != 0) {
|
||||||
|
sb.append("\r\n");
|
||||||
|
}
|
||||||
|
sbLong.append(keywords.get(i));
|
||||||
|
sbLong.append(" (You may cast this card any time you could cast an instant by sacrificing a ");
|
||||||
|
sbLong.append(offeringType);
|
||||||
|
sbLong.append("and paying the difference in mana costs between this and the sacrificed ");
|
||||||
|
sbLong.append(offeringType);
|
||||||
|
sbLong.append(". Mana cost includes color.)");
|
||||||
} else if (keyword.startsWith("Soulbond")) {
|
} else if (keyword.startsWith("Soulbond")) {
|
||||||
sbLong.append(keywords.get(i));
|
sbLong.append(keywords.get(i));
|
||||||
sbLong.append(" (You may pair this creature ");
|
sbLong.append(" (You may pair this creature ");
|
||||||
@@ -2429,6 +2440,17 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + 3);
|
sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + 3);
|
||||||
}
|
}
|
||||||
sb.append("Convoke (Each creature you tap while casting this spell reduces its cost by 1 or by one mana of that creature's color.)\r\n");
|
sb.append("Convoke (Each creature you tap while casting this spell reduces its cost by 1 or by one mana of that creature's color.)\r\n");
|
||||||
|
} else if (keyword.endsWith(" offering")) {
|
||||||
|
if (sb.toString().endsWith("\r\n\r\n")) {
|
||||||
|
sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + 3);
|
||||||
|
}
|
||||||
|
String offeringType = keyword.split(" ")[0];
|
||||||
|
sb.append(keyword);
|
||||||
|
sb.append(" (You may cast this card any time you could cast an instant by sacrificing a ");
|
||||||
|
sb.append(offeringType);
|
||||||
|
sb.append("and paying the difference in mana costs between this and the sacrificed ");
|
||||||
|
sb.append(offeringType);
|
||||||
|
sb.append(". Mana cost includes color.)");
|
||||||
} else if (keyword.equals("Remove CARDNAME from your deck before playing if you're not playing for ante.")) {
|
} else if (keyword.equals("Remove CARDNAME from your deck before playing if you're not playing for ante.")) {
|
||||||
if (sb.toString().endsWith("\r\n\r\n")) {
|
if (sb.toString().endsWith("\r\n\r\n")) {
|
||||||
sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + 3);
|
sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + 3);
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public class SacrificeEffect extends SpellAbilityEffect {
|
|||||||
choosenToSacrifice = Aggregates.random(validTargets, Math.min(amount, validTargets.size()));
|
choosenToSacrifice = Aggregates.random(validTargets, Math.min(amount, validTargets.size()));
|
||||||
} else {
|
} else {
|
||||||
boolean isOptional = sa.hasParam("Optional");
|
boolean isOptional = sa.hasParam("Optional");
|
||||||
choosenToSacrifice = p.getController().choosePermanentsToSacrifice(validTargets, valid, amount, sa, destroy, isOptional);
|
choosenToSacrifice = p.getController().choosePermanentsToSacrifice(validTargets, valid, amount, sa, destroy, isOptional, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(Card sac : choosenToSacrifice) {
|
for(Card sac : choosenToSacrifice) {
|
||||||
|
|||||||
@@ -129,6 +129,10 @@ public class CostPartMana extends CostPart {
|
|||||||
|
|
||||||
InputPayMana inpPayment;
|
InputPayMana inpPayment;
|
||||||
toPay.applySpellCostChange(ability);
|
toPay.applySpellCostChange(ability);
|
||||||
|
if (ability.isOffering() && ability.getSacrificedAsOffering() == null) {
|
||||||
|
System.out.println("Sacrifice input for Offering cancelled");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!toPay.isPaid()) {
|
if (!toPay.isPaid()) {
|
||||||
inpPayment = new InputPayManaOfCostPayment(toPay, ability);
|
inpPayment = new InputPayManaOfCostPayment(toPay, ability);
|
||||||
Singletons.getControl().getInputQueue().setInputAndWait(inpPayment);
|
Singletons.getControl().getInputQueue().setInputAndWait(inpPayment);
|
||||||
@@ -143,13 +147,30 @@ public class CostPartMana extends CostPart {
|
|||||||
source.setXManaCostPaid(0);
|
source.setXManaCostPaid(0);
|
||||||
inpPayment = new InputPayManaX(ability, this.getAmountOfX(), this.canXbe0());
|
inpPayment = new InputPayManaX(ability, this.getAmountOfX(), this.canXbe0());
|
||||||
Singletons.getControl().getInputQueue().setInputAndWait(inpPayment);
|
Singletons.getControl().getInputQueue().setInputAndWait(inpPayment);
|
||||||
if(!inpPayment.isPaid())
|
if (!inpPayment.isPaid()) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
int x = AbilityUtils.calculateAmount(source, "X", ability);
|
int x = AbilityUtils.calculateAmount(source, "X", ability);
|
||||||
source.setXManaCostPaid(x);
|
source.setXManaCostPaid(x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle convoke and offerings if InputPayManaOfCostPayment was skipped because cost was reduced to 0
|
||||||
|
if (ability.isOffering() && ability.getSacrificedAsOffering() != null) {
|
||||||
|
System.out.println("Finishing up Offering");
|
||||||
|
final Card offering = ability.getSacrificedAsOffering();
|
||||||
|
offering.setUsedToPay(false);
|
||||||
|
game.getAction().sacrifice(offering, ability);
|
||||||
|
ability.resetSacrificedAsOffering();
|
||||||
|
}
|
||||||
|
if (ability.getTappedForConvoke() != null) {
|
||||||
|
for (final Card c : ability.getTappedForConvoke()) {
|
||||||
|
c.setTapped(false);
|
||||||
|
c.tap();
|
||||||
|
}
|
||||||
|
ability.clearTappedForConvoke();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -398,6 +398,19 @@ public class ManaCostBeingPaid {
|
|||||||
increaseColorlessMana(extra.getGenericCost());
|
increaseColorlessMana(extra.getGenericCost());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final void determineManaCostDifference(final ManaCost subThisManaCost) {
|
||||||
|
for (ManaCostShard shard : subThisManaCost.getShards()) {
|
||||||
|
if (shard == ManaCostShard.X) {
|
||||||
|
cntX--;
|
||||||
|
} else if (unpaidShards.containsKey(shard)) {
|
||||||
|
decreaseShard(shard, 1);
|
||||||
|
} else {
|
||||||
|
decreaseColorlessMana(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
decreaseColorlessMana(subThisManaCost.getGenericCost());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To string.
|
* To string.
|
||||||
*
|
*
|
||||||
@@ -554,6 +567,9 @@ public class ManaCostBeingPaid {
|
|||||||
for (final StaticAbility stAb : reduceAbilities) {
|
for (final StaticAbility stAb : reduceAbilities) {
|
||||||
stAb.applyAbility("ReduceCost", spell, this);
|
stAb.applyAbility("ReduceCost", spell, this);
|
||||||
}
|
}
|
||||||
|
if (spell.isSpell() && spell.isOffering()) { // cost reduction from offerings
|
||||||
|
adjustCostByOffering(sa, spell);
|
||||||
|
}
|
||||||
|
|
||||||
// Set cost (only used by Trinisphere) is applied last
|
// Set cost (only used by Trinisphere) is applied last
|
||||||
for (final StaticAbility stAb : setAbilities) {
|
for (final StaticAbility stAb : setAbilities) {
|
||||||
@@ -636,6 +652,33 @@ public class ManaCostBeingPaid {
|
|||||||
return usableColors;
|
return usableColors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void adjustCostByOffering(final SpellAbility sa, final SpellAbility spell) {
|
||||||
|
String offeringType = "";
|
||||||
|
for (String kw : sa.getSourceCard().getKeyword()) {
|
||||||
|
if (kw.endsWith(" offering")) {
|
||||||
|
offeringType = kw.split(" ")[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Card toSac = null;
|
||||||
|
List<Card> canOffer = CardLists.filter(spell.getActivatingPlayer().getCardsIn(ZoneType.Battlefield),
|
||||||
|
CardPredicates.isType(offeringType));
|
||||||
|
|
||||||
|
final List<Card> toSacList = sa.getSourceCard().getController().getController().choosePermanentsToSacrifice(canOffer,
|
||||||
|
offeringType, 1, spell, false, false, true);
|
||||||
|
if (!toSacList.isEmpty()) {
|
||||||
|
toSac = toSacList.get(0);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
determineManaCostDifference(toSac.getManaCost());
|
||||||
|
|
||||||
|
sa.setSacrificedAsOffering(toSac);
|
||||||
|
toSac.setUsedToPay(true); //stop it from interfering with mana input
|
||||||
|
}
|
||||||
|
|
||||||
public String getSourceRestriction() {
|
public String getSourceRestriction() {
|
||||||
return sourceRestriction;
|
return sourceRestriction;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ public abstract class SpellAbility implements ISpellAbility {
|
|||||||
private boolean replicate = false;
|
private boolean replicate = false;
|
||||||
private boolean cycling = false;
|
private boolean cycling = false;
|
||||||
private boolean delve = false;
|
private boolean delve = false;
|
||||||
|
private boolean offering = false;
|
||||||
|
|
||||||
private Card targetCard;
|
private Card targetCard;
|
||||||
/** The chosen target. */
|
/** The chosen target. */
|
||||||
@@ -100,6 +101,7 @@ public abstract class SpellAbility implements ISpellAbility {
|
|||||||
private HashMap<String, Object> replacingObjects = new HashMap<String, Object>();
|
private HashMap<String, Object> replacingObjects = new HashMap<String, Object>();
|
||||||
|
|
||||||
private List<Card> tappedForConvoke = new ArrayList<Card>();
|
private List<Card> tappedForConvoke = new ArrayList<Card>();
|
||||||
|
private Card sacrificedAsOffering = null;
|
||||||
|
|
||||||
private HashMap<String, String> sVars = new HashMap<String, String>();
|
private HashMap<String, String> sVars = new HashMap<String, String>();
|
||||||
|
|
||||||
@@ -1309,6 +1311,47 @@ public abstract class SpellAbility implements ISpellAbility {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the SA is a patron offering.
|
||||||
|
*/
|
||||||
|
public boolean isOffering() {
|
||||||
|
return this.offering;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the SA as a patron offering.
|
||||||
|
*
|
||||||
|
* @param c card sacrificed for a patron offering
|
||||||
|
*/
|
||||||
|
public void setIsOffering(final boolean bOffering) {
|
||||||
|
this.offering = bOffering;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the card sacrificed for a patron offering.
|
||||||
|
*
|
||||||
|
* @param c card sacrificed for a patron offering
|
||||||
|
*/
|
||||||
|
public void setSacrificedAsOffering(final Card c) {
|
||||||
|
this.sacrificedAsOffering = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the card sacrificed for a patron offering.
|
||||||
|
*
|
||||||
|
* @return the card sacrificed for a patron offering
|
||||||
|
*/
|
||||||
|
public Card getSacrificedAsOffering() {
|
||||||
|
return this.sacrificedAsOffering;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the card sacrificed for a patron offering.
|
||||||
|
*/
|
||||||
|
public void resetSacrificedAsOffering() {
|
||||||
|
this.sacrificedAsOffering = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the splicedCards
|
* @return the splicedCards
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -292,7 +292,7 @@ public class SpellAbilityRestriction extends SpellAbilityVariables {
|
|||||||
* @return a boolean.
|
* @return a boolean.
|
||||||
*/
|
*/
|
||||||
public final boolean canPlay(final Card c, final SpellAbility sa) {
|
public final boolean canPlay(final Card c, final SpellAbility sa) {
|
||||||
if (c.isPhasedOut()) {
|
if (c.isPhasedOut() || c.isUsedToPay()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -792,6 +792,26 @@ public final class GameActionUtil {
|
|||||||
newSA.setDescription(sa.getDescription() + " (by paying " + actualcost.toSimpleString() + " instead of its mana cost)");
|
newSA.setDescription(sa.getDescription() + " (by paying " + actualcost.toSimpleString() + " instead of its mana cost)");
|
||||||
alternatives.add(newSA);
|
alternatives.add(newSA);
|
||||||
}
|
}
|
||||||
|
if (sa.isSpell() && keyword.endsWith(" offering")) {
|
||||||
|
final String offeringType = keyword.split(" ")[0];
|
||||||
|
List<Card> canOffer = CardLists.filter(sa.getSourceCard().getController().getCardsIn(ZoneType.Battlefield),
|
||||||
|
CardPredicates.isType(offeringType));
|
||||||
|
if (source.getController().hasKeyword("You can't sacrifice creatures to cast spells or activate abilities.")) {
|
||||||
|
canOffer = CardLists.getNotType(canOffer, "Creature");
|
||||||
|
}
|
||||||
|
if (!canOffer.isEmpty()) {
|
||||||
|
final SpellAbility newSA = sa.copy();
|
||||||
|
SpellAbilityRestriction sar = new SpellAbilityRestriction();
|
||||||
|
sar.setVariables(sa.getRestrictions());
|
||||||
|
sar.setInstantSpeed(true);
|
||||||
|
newSA.setRestrictions(sar);
|
||||||
|
newSA.setBasicSpell(false);
|
||||||
|
newSA.setIsOffering(true);
|
||||||
|
newSA.setPayCosts(sa.getPayCosts());
|
||||||
|
newSA.setDescription(sa.getDescription() + " (" + offeringType + " offering)");
|
||||||
|
alternatives.add(newSA);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (sa.hasParam("Equip") && sa instanceof AbilityActivated && keyword.equals("EquipInstantSpeed")) {
|
if (sa.hasParam("Equip") && sa instanceof AbilityActivated && keyword.equals("EquipInstantSpeed")) {
|
||||||
final SpellAbility newSA = ((AbilityActivated) sa).getCopy();
|
final SpellAbility newSA = ((AbilityActivated) sa).getCopy();
|
||||||
SpellAbilityRestriction sar = new SpellAbilityRestriction();
|
SpellAbilityRestriction sar = new SpellAbilityRestriction();
|
||||||
|
|||||||
@@ -194,6 +194,16 @@ public class ComputerUtilMana {
|
|||||||
|
|
||||||
manapool.clearManaPaid(sa, test);
|
manapool.clearManaPaid(sa, test);
|
||||||
|
|
||||||
|
// handle Offerings for AI
|
||||||
|
if (sa.isOffering() && sa.getSacrificedAsOffering() != null) {
|
||||||
|
final Card offering = sa.getSacrificedAsOffering();
|
||||||
|
offering.setUsedToPay(false);
|
||||||
|
if (cost.isPaid() && !test) {
|
||||||
|
sa.getSourceCard().getController().getGame().getAction().sacrifice(offering, sa);
|
||||||
|
}
|
||||||
|
sa.resetSacrificedAsOffering();
|
||||||
|
}
|
||||||
|
|
||||||
if( DEBUG_MANA_PAYMENT )
|
if( DEBUG_MANA_PAYMENT )
|
||||||
System.err.printf("%s > [%s] payment has %s (%s +%d) for (%s) %s:%n\t%s%n%n", FThreads.debugGetCurrThreadId(), test ? "test" : "PROD", cost.isPaid() ? "*PAID*" : "failed", originalCost, extraMana, sa.getSourceCard(), sa.toUnsuppressedString(), StringUtils.join(paymentPlan, "\n\t") );
|
System.err.printf("%s > [%s] payment has %s (%s +%d) for (%s) %s:%n\t%s%n%n", FThreads.debugGetCurrThreadId(), test ? "test" : "PROD", cost.isPaid() ? "*PAID*" : "failed", originalCost, extraMana, sa.getSourceCard(), sa.toUnsuppressedString(), StringUtils.join(paymentPlan, "\n\t") );
|
||||||
|
|
||||||
|
|||||||
@@ -1048,7 +1048,7 @@ public class CombatUtil {
|
|||||||
final Player opponent = game.getCombat().getDefendingPlayerRelatedTo(c).get(0);
|
final Player opponent = game.getCombat().getDefendingPlayerRelatedTo(c).get(0);
|
||||||
//List<Card> list = AbilityUtils.filterListByType(opponent.getCardsIn(ZoneType.Battlefield), "Permanent", this);
|
//List<Card> list = AbilityUtils.filterListByType(opponent.getCardsIn(ZoneType.Battlefield), "Permanent", this);
|
||||||
final List<Card> list = opponent.getCardsIn(ZoneType.Battlefield);
|
final List<Card> list = opponent.getCardsIn(ZoneType.Battlefield);
|
||||||
List<Card> toSac = opponent.getController().choosePermanentsToSacrifice(list, "Card", a, this, false, false);
|
List<Card> toSac = opponent.getController().choosePermanentsToSacrifice(list, "Card", a, this, false, false, false);
|
||||||
|
|
||||||
for(Card sacd : toSac) {
|
for(Card sacd : toSac) {
|
||||||
game.getAction().sacrifice(sacd, this);
|
game.getAction().sacrifice(sacd, this);
|
||||||
|
|||||||
@@ -455,7 +455,7 @@ public class Upkeep extends Phase {
|
|||||||
lowest.add(c);
|
lowest.add(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Card> toSac = player.getController().choosePermanentsToSacrifice(lowest, "Select creature with power: " + power + " to destroy.", 1, this, true, false);
|
List<Card> toSac = player.getController().choosePermanentsToSacrifice(lowest, "Select creature with power: " + power + " to destroy.", 1, this, true, false, false);
|
||||||
game.getAction().destroyNoRegeneration(toSac.get(0), this);
|
game.getAction().destroyNoRegeneration(toSac.get(0), this);
|
||||||
}
|
}
|
||||||
} // resolve
|
} // resolve
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ public abstract class PlayerController {
|
|||||||
public abstract Map<Card, Integer> assignCombatDamage(Card attacker, List<Card> blockers, int damageDealt, GameEntity defender);
|
public abstract Map<Card, Integer> assignCombatDamage(Card attacker, List<Card> blockers, int damageDealt, GameEntity defender);
|
||||||
|
|
||||||
public abstract Integer announceRequirements(SpellAbility ability, String announce, boolean allowZero);
|
public abstract Integer announceRequirements(SpellAbility ability, String announce, boolean allowZero);
|
||||||
public abstract List<Card> choosePermanentsToSacrifice(List<Card> validTargets, String validMessage, int amount, SpellAbility sa, boolean destroy, boolean isOptional);
|
public abstract List<Card> choosePermanentsToSacrifice(List<Card> validTargets, String validMessage, int amount, SpellAbility sa, boolean destroy, boolean isOptional, boolean canCancel);
|
||||||
public abstract Target chooseTargets(SpellAbility ability);
|
public abstract Target chooseTargets(SpellAbility ability);
|
||||||
|
|
||||||
public Card chooseSingleCardForEffect(List<Card> sourceList, SpellAbility sa, String title) { return chooseSingleCardForEffect(sourceList, sa, title, false); }
|
public Card chooseSingleCardForEffect(List<Card> sourceList, SpellAbility sa, String title) { return chooseSingleCardForEffect(sourceList, sa, title, false); }
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Card> choosePermanentsToSacrifice(List<Card> validTargets, String validMessage, int amount, SpellAbility sa, boolean destroy, boolean isOptional) {
|
public List<Card> choosePermanentsToSacrifice(List<Card> validTargets, String validMessage, int amount, SpellAbility sa, boolean destroy, boolean isOptional, boolean canCancel) {
|
||||||
return ComputerUtil.choosePermanentsToSacrifice(player, validTargets, amount, sa, destroy, isOptional);
|
return ComputerUtil.choosePermanentsToSacrifice(player, validTargets, amount, sa, destroy, isOptional);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ public class PlayerControllerHuman extends PlayerController {
|
|||||||
* @see forge.game.player.PlayerController#choosePermanentsToSacrifice(java.util.List, int, forge.card.spellability.SpellAbility, boolean, boolean)
|
* @see forge.game.player.PlayerController#choosePermanentsToSacrifice(java.util.List, int, forge.card.spellability.SpellAbility, boolean, boolean)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<Card> choosePermanentsToSacrifice(List<Card> validTargets, String validMessage, int amount, SpellAbility sa, boolean destroy, boolean isOptional) {
|
public List<Card> choosePermanentsToSacrifice(List<Card> validTargets, String validMessage, int amount, SpellAbility sa, boolean destroy, boolean isOptional, boolean canCancel) {
|
||||||
int max = Math.min(amount, validTargets.size());
|
int max = Math.min(amount, validTargets.size());
|
||||||
if (max <= 0)
|
if (max <= 0)
|
||||||
return new ArrayList<Card>();
|
return new ArrayList<Card>();
|
||||||
@@ -223,10 +223,12 @@ public class PlayerControllerHuman extends PlayerController {
|
|||||||
InputSelectCards inp = new InputSelectCardsFromList(min, max, validTargets);
|
InputSelectCards inp = new InputSelectCardsFromList(min, max, validTargets);
|
||||||
// TODO: Either compose a message here, or pass it as parameter from caller.
|
// TODO: Either compose a message here, or pass it as parameter from caller.
|
||||||
inp.setMessage("Select %d " + validMessage + "(s) to sacrifice");
|
inp.setMessage("Select %d " + validMessage + "(s) to sacrifice");
|
||||||
|
inp.setCancelAllowed(canCancel);
|
||||||
|
|
||||||
Singletons.getControl().getInputQueue().setInputAndWait(inp);
|
Singletons.getControl().getInputQueue().setInputAndWait(inp);
|
||||||
if( inp.hasCancelled() )
|
if (inp.hasCancelled()) {
|
||||||
return new ArrayList<Card>();
|
return new ArrayList<Card>();
|
||||||
|
}
|
||||||
else return inp.getSelected();
|
else return inp.getSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
|||||||
player.getZone(ZoneType.Battlefield).updateObservers();
|
player.getZone(ZoneType.Battlefield).updateObservers();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isAlredyPaid() {
|
protected boolean isAlreadyPaid() {
|
||||||
if (manaCost.isPaid()) {
|
if (manaCost.isPaid()) {
|
||||||
bPaid = true;
|
bPaid = true;
|
||||||
}
|
}
|
||||||
@@ -256,7 +256,7 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void onStateChanged() {
|
protected void onStateChanged() {
|
||||||
if( isAlredyPaid() ) {
|
if( isAlreadyPaid() ) {
|
||||||
done();
|
done();
|
||||||
stop();
|
stop();
|
||||||
} else
|
} else
|
||||||
@@ -283,5 +283,16 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void handleOfferings(boolean isCancelled) {
|
||||||
|
final Card offering = saPaidFor.getSacrificedAsOffering();
|
||||||
|
if (offering != null) {
|
||||||
|
offering.setUsedToPay(false);
|
||||||
|
if (!isCancelled) {
|
||||||
|
game.getAction().sacrifice(offering, saPaidFor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
saPaidFor.resetSacrificedAsOffering();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isPaid() { return bPaid; }
|
public boolean isPaid() { return bPaid; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,11 +39,19 @@ public class InputPayManaOfCostPayment extends InputPayMana {
|
|||||||
// any mana tapabilities can't be used in payment as well as being tapped for convoke)
|
// any mana tapabilities can't be used in payment as well as being tapped for convoke)
|
||||||
|
|
||||||
handleConvokedCards(false);
|
handleConvokedCards(false);
|
||||||
|
|
||||||
|
if (saPaidFor.isOffering()) {
|
||||||
|
handleOfferings(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCancel() {
|
protected void onCancel() {
|
||||||
handleConvokedCards(true);
|
handleConvokedCards(true);
|
||||||
|
|
||||||
|
if (saPaidFor.isOffering()) {
|
||||||
|
handleOfferings(true);
|
||||||
|
}
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -92,12 +92,18 @@ public class InputPayManaSimple extends InputPayMana {
|
|||||||
|
|
||||||
handleConvokedCards(false);
|
handleConvokedCards(false);
|
||||||
}
|
}
|
||||||
|
if (!this.saPaidFor.isOffering()) {
|
||||||
|
handleOfferings(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
protected final void onCancel() {
|
protected final void onCancel() {
|
||||||
handleConvokedCards(true);
|
handleConvokedCards(true);
|
||||||
|
if (!this.saPaidFor.isOffering()) {
|
||||||
|
handleOfferings(true);
|
||||||
|
}
|
||||||
|
|
||||||
player.getManaPool().refundManaPaid(this.saPaidFor, true);
|
player.getManaPool().refundManaPaid(this.saPaidFor, true);
|
||||||
player.getZone(ZoneType.Battlefield).updateObservers(); // DO
|
player.getZone(ZoneType.Battlefield).updateObservers(); // DO
|
||||||
|
|||||||
Reference in New Issue
Block a user