- Added PayLife as a new kind of Ability_Cost

- Pulled targeting from Ability_Cost into it's own class. 
- Added Player info to PlayerLife
- Added Reckless Assault as a sample of PayLife<> cost.
This commit is contained in:
jendave
2011-08-06 06:13:55 +00:00
parent 86a1929c6f
commit b99c986393
14 changed files with 540 additions and 331 deletions

3
.gitattributes vendored
View File

@@ -557,12 +557,15 @@ src/forge/Spell.java svneol=native#text/plain
src/forge/SpellAbility.java -text svneol=native#text/plain
src/forge/SpellAbilityList.java svneol=native#text/plain
src/forge/SpellAbilityUtil.java svneol=native#text/plain
src/forge/SpellAbility_Requirements.java -text svneol=native#text/plain
src/forge/Spell_Evoke.java svneol=native#text/plain
src/forge/Spell_Permanent.java svneol=native#text/plain
src/forge/StackObserver.java svneol=native#text/plain
src/forge/StaticEffects.java -text svneol=native#text/plain
src/forge/TableModel.java -text svneol=native#text/plain
src/forge/TableSorter.java svneol=native#text/plain
src/forge/Target.java -text svneol=native#text/plain
src/forge/Target_Selection.java -text svneol=native#text/plain
src/forge/TempRun.java svneol=native#text/plain
src/forge/Test.java svneol=native#text/plain
src/forge/TestMove.java svneol=native#text/plain

View File

@@ -1,3 +1,10 @@
Reckless Assault
2 B R
Enchantment
no text
abDamageTgtCP 1 PayLife<2>:1
SVar:RemAIDeck:True
Disfigure
B
Instant

View File

@@ -1,25 +1,6 @@
package forge;
public class Ability_Cost {
private boolean tgtPlayer = false;
public boolean canTgtPlayer() { return tgtPlayer; }
private boolean tgtCreature = false;
public boolean canTgtCreature() { return tgtCreature; }
public boolean canTgtCreaturePlayer() { return tgtCreature && tgtPlayer; }
public boolean doesTarget() { return tgtCreature || tgtPlayer; }
private int minTargets = 0;
public int getMinTargets() { return minTargets; }
private int maxTargets = 0;
public int getMaxTargets() { return maxTargets; }
// add array of targets here?
private int numTargeted = 0;
public int getNumTargeted() { return numTargeted; }
public void incrementTargets() { numTargeted++; }
public void resetTargets() { numTargeted = 0; }
private boolean sacCost = false;
public boolean getSacCost() { return sacCost; }
private String sacType = ""; // <type> or CARDNAME
@@ -30,7 +11,7 @@ public class Ability_Cost {
private boolean tapCost = false;
public boolean getTap() { return tapCost; }
// future expansion of Ability_Cost class: untap, and lifeCost
// future expansion of Ability_Cost class: untap
// private boolean untapCost = false;
private boolean subtractCounterCost = false;
@@ -44,7 +25,9 @@ public class Ability_Cost {
public Counters getCounterType() { return counterType; }
private boolean lifeCost = false;
public boolean getLifeCost() { return lifeCost; }
private int lifeAmount = 0;
public int getLifeAmount() { return lifeAmount; }
public boolean hasNoManaCost() { return manaCost.equals("") || manaCost.equals("0"); };
private String manaCost = "";
@@ -57,34 +40,8 @@ public class Ability_Cost {
// when adding new costs for cost string, place them here
name = cardName;
if (parse.contains("Tgt")){
// Tgt{C}{P}{/<MinTargets>/<MaxTargets>}
int tgtPos = parse.indexOf("Tgt");
int endTgt = parse.indexOf(" ");
//System.out.println(cardName);
String tgtStr = parse.substring(tgtPos, endTgt);
parse = parse.substring(endTgt+1);
tgtStr = tgtStr.replace("Tgt", "");
String[] tgtSplit = tgtStr.split("/");
if (tgtSplit[0].contains("C"))
tgtCreature = true;
if (tgtSplit[0].contains("P"))
tgtPlayer = true;
//todo(sol) add Opp
if (tgtSplit.length != 3){
minTargets = 1;
maxTargets = 1;
}
else{
minTargets = Integer.parseInt(tgtSplit[1]);
maxTargets = Integer.parseInt(tgtSplit[2]);
}
}
if(parse.contains("SubCounter<")) {
// SubCounter/<Counter Type>/counters removed
// SubCounter<CounterType/NumCounters>
subtractCounterCost = true;
int counterPos = parse.indexOf("SubCounter<");
int endPos = parse.indexOf(">", counterPos);
@@ -99,11 +56,26 @@ public class Ability_Cost {
counterAmount = Integer.parseInt(strSplit[1]);
}
if(parse.contains("PayLife<")) {
// PayLife<LifeCost>
lifeCost = true;
int lifePos = parse.indexOf("PayLife<");
int endPos = parse.indexOf(">", lifePos);
String str = parse.substring(lifePos, endPos+1);
parse = parse.replace(str, "").trim();
str = str.replace("PayLife<", "");
str = str.replace(">", "");
lifeAmount = Integer.parseInt(str);
}
if(parse.contains("Sac-")) {
sacCost = true;
int sacPos = parse.indexOf("Sac-");
sacType = parse.substring(sacPos).replace("Sac-", "").trim();
sacThis = (sacType.equals("CARDNAME"));
if (sacPos > 0)
parse = parse.substring(0,sacPos-1).trim();
}
@@ -158,6 +130,7 @@ public class Ability_Cost {
else
cost.append(", Pay ");
cost.append(lifeAmount);
cost.append(" Life");
caps = false;
}
@@ -192,19 +165,4 @@ public class Ability_Cost {
}
return cost.toString();
}
public String targetString()
{
String tgt = "";
if (tgtCreature)
tgt += "creature";
if (tgtPlayer && !tgt.equals(""))
tgt += " or ";
if (tgtPlayer)
tgt += "player";
tgt += ".";
return "target " + tgt;
}
}

View File

@@ -37,8 +37,8 @@ public class AllZone implements NewConstants {
public static Combat Combat = new Combat();
public static Combat pwCombat = new Combat();//for Planeswalker combat
public static PlayerLife Human_Life = new PlayerLife();
public static PlayerLife Computer_Life = new PlayerLife();
public static PlayerLife Human_Life = new PlayerLife(Constant.Player.Human);
public static PlayerLife Computer_Life = new PlayerLife(Constant.Player.Computer);
public static PlayerPoisonCounter Human_PoisonCounter = new PlayerPoisonCounter();
public static PlayerPoisonCounter Computer_PoisonCounter = new PlayerPoisonCounter();

View File

@@ -1267,10 +1267,10 @@ public class CardFactory implements NewConstants {
card.removeIntrinsicKeyword(parse);
String k[] = parse.split(":");
String tmpCost[] = k[0].replace("abAllPump", "").split(" ", 2);
String tmpCost = k[0].substring(9);
final Ability_Cost abCost = new Ability_Cost(tmpCost, card.getName());
final Target abTgt = new Target(tmpCost[0]);
final Ability_Cost abCost = new Ability_Cost(tmpCost[1], card.getName());
final String Scope[] = k[1].split("/");
@@ -1423,6 +1423,8 @@ public class CardFactory implements NewConstants {
// temporarily disabled until AI is improved
if (abCost.getSacCost()) return false;
if (abCost.getSubCounter()) return false;
if (abCost.getLifeCost()) return false;
if (abCost.getTap() && (card.isTapped() || card.isSick()))
return false;
@@ -1516,6 +1518,7 @@ public class CardFactory implements NewConstants {
abAllPump.setDescription(abCost.toString() + spDesc[0]);
abAllPump.setStackDescription(stDesc[0]);
abAllPump.setPayCosts(abCost);
abAllPump.setTarget(abTgt);
card.addSpellAbility(abAllPump);
}
@@ -1528,10 +1531,12 @@ public class CardFactory implements NewConstants {
card.removeIntrinsicKeyword(parse);
String k[] = parse.split(":");
String tmp = k[0].replace("abPump", "");
String tmpCost = k[0].substring(6);
String[] tmpCost = tmp.split(" ", 2);
final Ability_Cost abCost = new Ability_Cost(tmpCost, card.getName());
final Target abTgt = new Target(tmpCost[0]);
final Ability_Cost abCost = new Ability_Cost(tmpCost[1], card.getName());
final int NumAttack[] = {-1138};
final String AttackX[] = {"none"};
@@ -1597,7 +1602,7 @@ public class CardFactory implements NewConstants {
if((AttackX[0].equals("none") && !(NumAttack[0] == -1138))
&& (DefenseX[0].equals("none") && !(NumDefense[0] == -1138)) && Keyword[0].equals("none")) {
// pt boost
if(abCost.doesTarget()) sbD.append("Target creature gets ");
if(abTgt.doesTarget()) sbD.append("Target creature gets ");
else {
sbD.append(cardName);
sbD.append(" gets ");
@@ -1621,7 +1626,7 @@ public class CardFactory implements NewConstants {
if((AttackX[0].equals("none") && NumAttack[0] == -1138)
&& (DefenseX[0].equals("none") && NumDefense[0] == -1138) && !Keyword[0].equals("none")) {
// k boost
if(abCost.doesTarget()) sbD.append("Target creature gains ");
if(abTgt.doesTarget()) sbD.append("Target creature gains ");
else {
sbD.append(cardName);
sbD.append(" gains ");
@@ -1633,7 +1638,7 @@ public class CardFactory implements NewConstants {
if((AttackX[0].equals("none") && !(NumAttack[0] == -1138))
&& (DefenseX[0].equals("none") && !(NumDefense[0] == -1138)) && !Keyword[0].equals("none")) {
// ptk boost
if(abCost.doesTarget()) sbD.append("Target creature gets ");
if(abTgt.doesTarget()) sbD.append("Target creature gets ");
else {
sbD.append(cardName);
sbD.append(" gets ");
@@ -1700,6 +1705,7 @@ public class CardFactory implements NewConstants {
// temporarily disabled until AI is improved
if (abCost.getSacCost()) return false;
if (abCost.getSubCounter()) return false;
if (abCost.getLifeCost()) return false;
if (!ComputerUtil.canPayCost(this))
return false;
@@ -1709,7 +1715,7 @@ public class CardFactory implements NewConstants {
if(AllZone.Phase.getPhase().equals(Constant.Phase.Main2)) return false;
if(!abCost.doesTarget()) {
if(!abTgt.doesTarget()) {
setTargetCard(card);
if((card.getNetDefense() + defense > 0) && (!card.getKeyword().contains(keyword))) {
@@ -1778,9 +1784,9 @@ public class CardFactory implements NewConstants {
@Override
public void resolve() {
if(AllZone.GameAction.isCardInPlay(getTargetCard())
&& (CardFactoryUtil.canTarget(card, getTargetCard()) || !abCost.doesTarget() )) {
&& (CardFactoryUtil.canTarget(card, getTargetCard()) || !abTgt.doesTarget() )) {
final Card[] creature = new Card[1];
if(abCost.doesTarget()) creature[0] = getTargetCard();
if(abTgt.doesTarget()) creature[0] = getTargetCard();
else creature[0] = card;
final int a = getNumAttack();
@@ -1829,8 +1835,10 @@ public class CardFactory implements NewConstants {
ability.setDescription(spDesc[0]);
ability.setStackDescription(stDesc[0]);
if(!abCost.doesTarget())
if(!abTgt.doesTarget())
ability.setTargetCard(card);
else
ability.setTarget(abTgt);
card.addSpellAbility(ability);
}
@@ -2265,9 +2273,10 @@ public class CardFactory implements NewConstants {
card.removeIntrinsicKeyword(parse);
String k[] = parse.split(":");
String tmpCost = k[0].substring(8);
String tmpCost[] = k[0].replace("abDamage", "").split(" ", 2);
final Ability_Cost abCost = new Ability_Cost(tmpCost, card.getName());
final Target abTgt = new Target(tmpCost[0]);
final Ability_Cost abCost = new Ability_Cost(tmpCost[1], card.getName());
final int NumDmg[] = {-1};
final String NumDmgX[] = {"none"};
@@ -2301,7 +2310,7 @@ public class CardFactory implements NewConstants {
sb.append(card.getName());
sb.append(" deals " + NumDmg[0] + " damage to ");
sb.append(abCost.targetString());
sb.append(abTgt.targetString());
spDesc[0] = sb.toString();
stDesc[0] = card.getName() + " -" + sb.toString();
}
@@ -2380,6 +2389,7 @@ public class CardFactory implements NewConstants {
// temporarily disabled until better AI
if (abCost.getSacCost()) return false;
if (abCost.getSubCounter()) return false;
if (abCost.getLifeCost()) return false;
if (!ComputerUtil.canPayCost(this))
return false;
@@ -2391,7 +2401,7 @@ public class CardFactory implements NewConstants {
if(r.nextFloat() <= Math.pow(.6667, card.getAbilityUsed()))
rr = true;
if(abCost.canTgtCreaturePlayer()) {
if(abTgt.canTgtCreaturePlayer()) {
if(shouldTgtP()) {
setTargetPlayer(Constant.Player.Human);
return rr;
@@ -2404,12 +2414,12 @@ public class CardFactory implements NewConstants {
}
}
if(abCost.canTgtPlayer()/* || TgtOpp[0] == true */) {
if(abTgt.canTgtPlayer()/* || TgtOpp[0] == true */) {
setTargetPlayer(Constant.Player.Human);
return rr;
}
if(abCost.canTgtCreature()) {
if(abTgt.canTgtCreature()) {
Card c = chooseTgtC();
if(c != null) {
setTargetCard(c);
@@ -2453,6 +2463,7 @@ public class CardFactory implements NewConstants {
};//Ability_Activated
abDamage.setPayCosts(abCost);
abDamage.setTarget(abTgt);
abDamage.setDescription(spDesc[0]);
abDamage.setStackDescription(stDesc[0]);

View File

@@ -31,6 +31,7 @@ public class ComputerUtil
AllZone.Computer_Hand.remove(all[i].getSourceCard());
Ability_Cost cost = all[i].getPayCosts();
Target tgt = all[i].getTarget();
if (cost == null){
if(all[i] instanceof Ability_Tap)
@@ -43,6 +44,9 @@ public class ComputerUtil
AllZone.Stack.add(all[i]);
}
else{
if (tgt != null && tgt.doesTarget())
all[i].chooseTargetAI();
Cost_Payment pay = new Cost_Payment(cost, all[i]);
pay.payComputerCosts();
}
@@ -232,6 +236,11 @@ public class ComputerUtil
}
}
if (cost.getLifeCost()){
if (AllZone.GameAction.getPlayerLife(Constant.Player.Computer).getLife() <= cost.getLifeAmount())
return false;
}
// check additional costs.
if (cost.getSacCost()){
// if there's a sacrifice in the cost, just because we can Pay it doesn't mean we want to.

View File

@@ -1,23 +1,28 @@
package forge;
import javax.swing.JOptionPane;
public class Cost_Payment {
Ability_Cost cost = null;
SpellAbility ability = null;
Card card = null;
private Ability_Cost cost = null;
private SpellAbility ability = null;
private Card card = null;
private SpellAbility_Requirements req = null;
public Ability_Cost getCost() { return cost; }
public SpellAbility getAbility() { return ability; }
public Card getCard() { return card; }
public void setRequirements(SpellAbility_Requirements reqs) { req = reqs; }
public void setCancel(boolean cancel) { bCancel = cancel; }
public void setDoneTarget(boolean done) { bCancel = done; }
public boolean isCanceled() { return bCancel; }
private boolean payTap = false;
private boolean payMana = false;
private boolean paySubCounter = false;
private boolean paySac = false;
private boolean payLife = false;
private boolean bCancel = false;
private boolean bCasting = false;
private boolean bDoneTarget = false;
private PlayerZone fromZone = null;
public void setPayMana(boolean bPay){ payMana = bPay; }
public void setPaySac(boolean bSac){ paySac = bSac; }
@@ -33,6 +38,7 @@ public class Cost_Payment {
payMana = cost.hasNoManaCost();
paySubCounter = !cost.getSubCounter();
paySac = !cost.getSacCost();
payLife = !cost.getLifeCost();
}
public boolean canPayAdditionalCosts(){
@@ -48,6 +54,12 @@ public class Cost_Payment {
}
}
if (cost.getLifeCost()){
int curLife = AllZone.GameAction.getPlayerLife(card.getController()).getLife();
if (curLife < cost.getLifeAmount())
return false;
}
if (cost.getSacCost()){
if (!cost.getSacThis()){
PlayerZone play = AllZone.getZone(Constant.Zone.Play, card.getController());
@@ -64,27 +76,8 @@ public class Cost_Payment {
}
public boolean payCost(){
if (bCancel || bDoneTarget && cost.getNumTargeted() < cost.getMinTargets()){
cancelPayment();
return false;
}
if (ability instanceof Spell && !bCasting){
// remove from hand, todo(sol) be careful of spell copies when spells start using this
bCasting = true;
Card c = ability.getSourceCard();
fromZone = AllZone.getZone(c);
fromZone.remove(c);
}
// targetting, with forward code for multiple target abilities
if (!bDoneTarget && cost.getMinTargets() > 0 && cost.getNumTargeted() < cost.getMaxTargets()){
if (cost.canTgtCreature() && cost.canTgtPlayer())
changeInput.stopSetNext(targetCreaturePlayer(ability, Command.Blank, true, this));
else if(cost.canTgtCreature())
changeInput.stopSetNext(targetCreature(ability, this));
else if(cost.canTgtPlayer())
changeInput.stopSetNext(targetPlayer(ability, this));
if (bCancel){
req.finishPaying();
return false;
}
@@ -98,13 +91,12 @@ public class Cost_Payment {
}
// insert untap here
if (!payMana && !cost.hasNoManaCost()){
// pay mana here
if (!payMana && !cost.hasNoManaCost()){ // pay mana here
changeInput.stopSetNext(new Input_PayCostMana(this));
return false;
}
if (!paySubCounter && cost.getSubCounter()){
// subtract counters here.
if (!paySubCounter && cost.getSubCounter()){ // pay counters here.
Counters c = cost.getCounterType();
int countersLeft = card.getCounters(c) - cost.getCounterNum();
if (countersLeft >= 0){
@@ -112,12 +104,35 @@ public class Cost_Payment {
paySubCounter = true;
}
else{
cancelPayment();
bCancel = true;
req.finishPaying();
return false;
}
}
if (!paySac && cost.getSacCost())
{
if (!payLife && cost.getLifeCost()){ // pay life here
// todo: should ask with a yes/no popup box to pay life?
StringBuilder sb = new StringBuilder();
sb.append(getCard().getName());
sb.append(" - Pay ");
sb.append(cost.getLifeAmount());
sb.append(" Life?");
Object[] possibleValues = {"Yes", "No"};
Object choice = JOptionPane.showOptionDialog(null, sb.toString(), getCard().getName() + " - Cost",
JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
null, possibleValues, possibleValues[0]);
if(choice.equals(0)) {
AllZone.GameAction.getPlayerLife(card.getController()).payLife(cost.getLifeAmount());
payLife = true;
}
else{
bCancel = true;
req.finishPaying();
return false;
}
}
if (!paySac && cost.getSacCost()){
// sacrifice stuff here
if (cost.getSacThis())
changeInput.stopSetNext(sacrificeThis(ability, this));
@@ -126,28 +141,16 @@ public class Cost_Payment {
return false;
}
if (isAllPaid())
allPaid();
req.finishPaying();
return true;
}
public boolean isAllPaid(){
return (payTap && payMana && paySubCounter && paySac);
}
public void allPaid(){
AllZone.ManaPool.clearPay(false);
AllZone.Stack.add(ability);
cost.resetTargets();
return (payTap && payMana && paySubCounter && paySac && payLife);
}
public void cancelPayment(){
// unpay anything we can.
cost.resetTargets();
if (bCasting){
// add back to hand
fromZone.add(ability.getSourceCard());
}
if (cost.getTap() && payTap){
// untap if tapped
card.untap();
@@ -162,9 +165,61 @@ public class Cost_Payment {
card.setCounter(c, countersLeft);
}
// refund life
if (cost.getLifeCost() && payLife){
PlayerLife life = AllZone.GameAction.getPlayerLife(card.getController());
life.payLife(cost.getLifeAmount()*-1);
}
// can't really unsacrifice things
}
public void payComputerCosts(){
Card sacCard = null;
ability.setActivatingPlayer(Constant.Player.Computer);
// double check if something can be sacrificed here. Real check is in ComputerUtil.canPayAdditionalCosts()
if (cost.getSacCost()){
if (cost.getSacThis())
sacCard = card;
else
sacCard = ComputerUtil.chooseSacrificeType(cost.getSacType(), card, ability.getTargetCard());
if (sacCard == null){
System.out.println("Couldn't find a valid card to sacrifice for: "+card.getName());
return;
}
}
// double check if counters available? Real check is in ComputerUtil.canPayAdditionalCosts()
int countersLeft = 0;
if (cost.getSubCounter()){
Counters c = cost.getCounterType();
countersLeft = card.getCounters(c) - cost.getCounterNum();
if (countersLeft < 0){
System.out.println("Not enough " + c.getName() + " on "+card.getName());
return;
}
}
if (cost.getTap())
card.tap();
if (!cost.hasNoManaCost())
ComputerUtil.payManaCost(ability);
if (cost.getSubCounter())
card.setCounter(cost.getCounterType(), countersLeft);
if (cost.getLifeCost())
AllZone.GameAction.getPlayerLife(card.getController()).payLife(cost.getLifeAmount());
if (cost.getSacCost())
AllZone.GameAction.sacrifice(sacCard);
AllZone.Stack.add(ability);
}
public static Input sacrificeThis(final SpellAbility spell, final Cost_Payment payment) {
Input target = new Input() {
private static final long serialVersionUID = 2685832214519141903L;
@@ -172,10 +227,15 @@ public class Cost_Payment {
@Override
public void showMessage() {
Card card = spell.getSourceCard();
String[] choices = {"Yes", "No"};
if(card.getController().equals(Constant.Player.Human)) {
Object o = AllZone.Display.getChoice("Sacrifice " + card.getName() + " ?", choices);
if(o.equals("Yes")) {
StringBuilder sb = new StringBuilder();
sb.append(card.getName());
sb.append(" - Sacrifice?");
Object[] possibleValues = {"Yes", "No"};
Object choice = JOptionPane.showOptionDialog(null, sb.toString(), card.getName() + " - Cost",
JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
null, possibleValues, possibleValues[0]);
if(choice.equals(0)) {
AllZone.GameAction.sacrifice(card);
payment.setPaySac(true);
stop();
@@ -226,171 +286,4 @@ public class Cost_Payment {
};
return target;
}//sacrificeType()
public static Input targetCreaturePlayer(final SpellAbility ability, final Command paid, final boolean targeted, final Cost_Payment payment) {
Input target = new Input() {
private static final long serialVersionUID = 2781418414287281005L;
@Override
public void showMessage() {
AllZone.Display.showMessage("Select target Creature, Player, or Planeswalker");
// when multi targets (Arc Mage) are added, need this:
// if payment.targeted < mintarget only enable cancel
// else if payment.targeted < maxtarget enable cancel and ok
ButtonUtil.enableOnlyCancel();
}
@Override
public void selectButtonCancel() {
payment.setCancel(true);
stop();
payment.payCost();
}
@Override
public void selectButtonOK() {
payment.setDoneTarget(true);
stop();
payment.payCost();
}
@Override
public void selectCard(Card card, PlayerZone zone) {
if((card.isCreature() || card.isPlaneswalker()) && zone.is(Constant.Zone.Play)
&& (!targeted || CardFactoryUtil.canTarget(ability, card))) {
ability.setTargetCard(card);
done();
}
}//selectCard()
@Override
public void selectPlayer(String player) {
ability.setTargetPlayer(player);
done();
}
void done() {
payment.getCost().incrementTargets();
paid.execute();
stop();
payment.payCost();
}
};
return target;
}//input_targetCreaturePlayer()
public static Input targetCreature(final SpellAbility ability, final Cost_Payment payment) {
Input target = new Input() {
private static final long serialVersionUID = 2781418414287281005L;
@Override
public void showMessage() {
AllZone.Display.showMessage("Select target Creature");
ButtonUtil.enableOnlyCancel();
}
@Override
public void selectButtonCancel() {
payment.setCancel(true);
stop();
payment.payCost();
}
@Override
public void selectCard(Card card, PlayerZone zone) {
if(card.isCreature() && zone.is(Constant.Zone.Play) && (CardFactoryUtil.canTarget(ability, card))) {
ability.setTargetCard(card);
done();
}
}//selectCard()
void done() {
payment.getCost().incrementTargets();
stop();
payment.payCost();
}
};
return target;
}//targetCreature()
public static Input targetPlayer(final SpellAbility ability, final Cost_Payment payment) {
Input target = new Input() {
private static final long serialVersionUID = 2781418414287281005L;
@Override
public void showMessage() {
AllZone.Display.showMessage("Select target Player or Planeswalker");
ButtonUtil.enableOnlyCancel();
}
@Override
public void selectButtonCancel() {
payment.setCancel(true);
stop();
payment.payCost();
}
@Override
public void selectCard(Card card, PlayerZone zone) {
if(card.isPlaneswalker() && zone.is(Constant.Zone.Play) && (!CardFactoryUtil.canTarget(ability, card))) {
ability.setTargetCard(card);
done();
}
}//selectCard()
@Override
public void selectPlayer(String player) {
ability.setTargetPlayer(player);
done();
}
void done() {
payment.getCost().incrementTargets();
stop();
payment.payCost();
}
};
return target;
}//targetPlayer()
public void payComputerCosts(){
Card sacCard = null;
ability.setActivatingPlayer(Constant.Player.Computer);
if (cost.doesTarget())
ability.chooseTargetAI();
// double check if something can be sacrificed here. Real check is in ComputerUtil.canPayAdditionalCosts()
if (cost.getSacCost()){
if (cost.getSacThis())
sacCard = card;
else
sacCard = ComputerUtil.chooseSacrificeType(cost.getSacType(), card, ability.getTargetCard());
if (sacCard == null){
System.out.println("Couldn't find a valid card to sacrifice for: "+card.getName());
return;
}
}
// double check if counters available? Real check is in ComputerUtil.canPayAdditionalCosts()
int countersLeft = 0;
if (cost.getSubCounter()){
Counters c = cost.getCounterType();
countersLeft = card.getCounters(c) - cost.getCounterNum();
if (countersLeft < 0){
System.out.println("Not enough " + c.getName() + " on "+card.getName());
return;
}
}
if (cost.getTap())
card.tap();
if (!cost.hasNoManaCost())
ComputerUtil.payManaCost(ability);
if (cost.getSubCounter())
card.setCounter(cost.getCounterType(), countersLeft);
if (cost.getSacCost())
AllZone.GameAction.sacrifice(sacCard);
AllZone.Stack.add(ability);
}
}

View File

@@ -3456,8 +3456,11 @@ public class GameAction {
public void playSpellAbility(SpellAbility sa) {
sa.setActivatingPlayer(Constant.Player.Human);
if (sa.getPayCosts() != null){
Target_Selection ts = new Target_Selection(sa.getTarget(), sa);
Cost_Payment payment = new Cost_Payment(sa.getPayCosts(), sa);
payment.payCost();
SpellAbility_Requirements req = new SpellAbility_Requirements(sa, ts, payment);
req.fillRequirements();
}
else{
ManaCost manaCost = new ManaCost(sa.getManaCost());

View File

@@ -16,7 +16,7 @@ public class Input_PayCostMana extends Input {
public Input_PayCostMana(Cost_Payment payment) {
costPayment = payment;
originalManaCost = costPayment.cost.getMana();
originalManaCost = costPayment.getCost().getMana();
sa = payment.getAbility();
if(Phase.GameBegins == 1) {

View File

@@ -3,12 +3,23 @@ public class PlayerLife extends MyObservable implements java.io.Serializable
{
private static final long serialVersionUID = -1614695903669967202L;
private String player;
private Card playerCard;
private int life;
private int assignedDamage;//from combat
public void setAssignedDamage(int n) {assignedDamage = n;}
public int getAssignedDamage() {return assignedDamage;}
public PlayerLife(String pl)
{
player = pl;
if (player.equals(Constant.Player.Human))
playerCard = AllZone.CardFactory.HumanNullCard;
else
playerCard = AllZone.CardFactory.ComputerNullCard;
}
public int getLife()
{
return life;
@@ -18,39 +29,28 @@ public class PlayerLife extends MyObservable implements java.io.Serializable
life = life2;
this.updateObservers();
}
public void addLife(int life2)
{
Card WhoGainedLife = new Card();
if(AllZone.Human_Life.getLife() != AllZone.Computer_Life.getLife()) {
if(AllZone.Human_Life.getLife() == life) WhoGainedLife = AllZone.CardFactory.HumanNullCard;
else WhoGainedLife = AllZone.CardFactory.ComputerNullCard;
}
life += life2;
if(WhoGainedLife != AllZone.CardFactory.HumanNullCard && WhoGainedLife != AllZone.CardFactory.ComputerNullCard) {
if(AllZone.Human_Life.getLife() == life) WhoGainedLife = AllZone.CardFactory.HumanNullCard;
else WhoGainedLife = AllZone.CardFactory.ComputerNullCard;
}
Object[] Life_Whenever_Parameters = new Object[1];
Life_Whenever_Parameters[0] = life2;
AllZone.GameAction.CheckWheneverKeyword(WhoGainedLife, "GainLife", Life_Whenever_Parameters);
AllZone.GameAction.CheckWheneverKeyword(playerCard, "GainLife", Life_Whenever_Parameters);
this.updateObservers();
}
public void subtractLife(int life2, Card SourceCard)
{
Card WhoGainedLife = new Card();
if(AllZone.Human_Life.getLife() != AllZone.Computer_Life.getLife()) {
if(AllZone.Human_Life.getLife() == life) WhoGainedLife = AllZone.CardFactory.HumanNullCard;
else WhoGainedLife = AllZone.CardFactory.ComputerNullCard;
}
life -= life2;
if(WhoGainedLife != AllZone.CardFactory.HumanNullCard && WhoGainedLife != AllZone.CardFactory.ComputerNullCard) {
if(AllZone.Human_Life.getLife() == life) WhoGainedLife = AllZone.CardFactory.HumanNullCard;
else WhoGainedLife = AllZone.CardFactory.ComputerNullCard;
}
Object[] DealsDamage_Whenever_Parameters = new Object[3];
DealsDamage_Whenever_Parameters[0] = WhoGainedLife.getController();
DealsDamage_Whenever_Parameters[0] = player;
DealsDamage_Whenever_Parameters[2] = SourceCard;
AllZone.GameAction.CheckWheneverKeyword(WhoGainedLife, "DealsDamage", DealsDamage_Whenever_Parameters);
AllZone.GameAction.CheckWheneverKeyword(playerCard, "DealsDamage", DealsDamage_Whenever_Parameters);
this.updateObservers();
}
public void payLife(int life2)
{
life -= life2;
this.updateObservers();
}
}

View File

@@ -40,6 +40,7 @@ public abstract class SpellAbility {
private Input afterPayMana;
protected Ability_Cost payCosts = null;
protected Target chosenTarget = null;
private Command cancelCommand = Command.Blank;
private Command beforePayManaAI = Command.Blank;
@@ -238,6 +239,14 @@ public abstract class SpellAbility {
payCosts = abCost;
}
public Target getTarget() {
return chosenTarget;
}
public void setTarget(Target tgt) {
chosenTarget = tgt;
}
public Input getAfterResolve() {
return afterResolve;
}

View File

@@ -0,0 +1,74 @@
package forge;
public class SpellAbility_Requirements {
private SpellAbility ability = null;
private Target_Selection select = null;
private Cost_Payment payment = null;
private PlayerZone fromZone = null;
private boolean bCasting = false;
public SpellAbility_Requirements(SpellAbility sa, Target_Selection ts, Cost_Payment cp){
ability = sa;
select = ts;
payment = cp;
}
public void fillRequirements(){
if (ability instanceof Spell && !bCasting){
// remove from hand, todo(sol) be careful of spell copies if spells start using this
bCasting = true;
Card c = ability.getSourceCard();
fromZone = AllZone.getZone(c);
fromZone.remove(c);
}
if (select.getTgt().doesTarget()){
select.setRequirements(this);
select.chooseTargets();
}
else
startPaying();
}
public void finishedTargeting(){
if (select.isCanceled()){
// cancel ability during target choosing
if (bCasting){ // and not a copy
// add back to hand
fromZone.add(ability.getSourceCard());
}
select.getTgt().resetTargets();
return;
}
startPaying();
}
public void startPaying(){
payment.setRequirements(this);
payment.payCost();
}
public void finishPaying(){
if (payment.isAllPaid())
addAbilityToStack();
else if (payment.isCanceled()){
if (bCasting){ // and not a copy
// add back to hand
fromZone.add(ability.getSourceCard());
}
if (select.getTgt().doesTarget())
select.getTgt().resetTargets();
payment.cancelPayment();
}
}
public void addAbilityToStack(){
AllZone.ManaPool.clearPay(false);
AllZone.Stack.add(ability);
if (select != null)
select.getTgt().resetTargets();
}
}

60
src/forge/Target.java Normal file
View File

@@ -0,0 +1,60 @@
package forge;
public class Target {
private boolean tgtPlayer = false;
public boolean canTgtPlayer() { return tgtPlayer; }
private boolean tgtCreature = false;
public boolean canTgtCreature() { return tgtCreature; }
public boolean canTgtCreaturePlayer() { return tgtCreature && tgtPlayer; }
public boolean doesTarget() { return tgtCreature || tgtPlayer; }
private int minTargets = 0;
public int getMinTargets() { return minTargets; }
private int maxTargets = 0;
public int getMaxTargets() { return maxTargets; }
// add array of targets here?
private int numTargeted = 0;
public int getNumTargeted() { return numTargeted; }
public void incrementTargets() { numTargeted++; }
public void resetTargets() { numTargeted = 0; }
public Target(String parse){
if (parse.contains("Tgt")){
// Tgt{C}{P}[/<MinTargets>/<MaxTargets>] min-max is optional
String tgtStr = parse.replace("Tgt", "");
String[] tgtSplit = tgtStr.split("/");
if (tgtSplit[0].contains("C")) // creature
tgtCreature = true;
if (tgtSplit[0].contains("P")) // player
tgtPlayer = true;
//todo add Opponent and other permanent types
if (tgtSplit.length != 3){
minTargets = 1;
maxTargets = 1;
}
else{
minTargets = Integer.parseInt(tgtSplit[1]);
maxTargets = Integer.parseInt(tgtSplit[2]);
}
}
}
public String targetString()
{
String tgt = "";
if (tgtCreature)
tgt += "creature";
if (tgtPlayer && !tgt.equals(""))
tgt += " or ";
if (tgtPlayer)
tgt += "player";
tgt += ".";
return "target " + tgt;
}
}

View File

@@ -0,0 +1,182 @@
package forge;
public class Target_Selection {
private Target target = null;
private SpellAbility ability = null;
private Card card = null;
public Target getTgt() { return target; }
public SpellAbility getAbility() { return ability; }
public Card getCard() { return card; }
private SpellAbility_Requirements req = null;
public void setRequirements(SpellAbility_Requirements reqs) { req = reqs; }
private boolean bCancel = false;
public void setCancel(boolean done) { bCancel = done; }
public boolean isCanceled() { return bCancel; }
private boolean bDoneTarget = false;
public void setDoneTarget(boolean done) { bDoneTarget = done; }
final private Input changeInput = new Input() {
private static final long serialVersionUID = -5750122411788688459L; };
public Target_Selection(Target tgt, SpellAbility sa){
target = tgt;
ability = sa;
card = sa.getSourceCard();
}
public boolean chooseTargets(){
// if not enough targets chosen, reset and cancel Ability
if (bCancel || bDoneTarget && target.getNumTargeted() < target.getMinTargets()){
bCancel = true;
target.resetTargets();
return false;
}
// if we haven't reached minimum targets, or we're stil less than Max targets keep choosing
// targetting, with forward code for multiple target abilities
if (!bDoneTarget && target.getMinTargets() > 0 && target.getNumTargeted() < target.getMaxTargets()){
if (target.canTgtCreature() && target.canTgtPlayer())
changeInput.stopSetNext(targetCreaturePlayer(ability, Command.Blank, true, this, req));
else if(target.canTgtCreature())
changeInput.stopSetNext(targetCreature(ability, this, req));
else if(target.canTgtPlayer())
changeInput.stopSetNext(targetPlayer(ability, this, req));
return false;
}
return true;
}
public static Input targetCreaturePlayer(final SpellAbility ability, final Command paid, final boolean targeted,
final Target_Selection select, final SpellAbility_Requirements req) {
Input target = new Input() {
private static final long serialVersionUID = 2781418414287281005L;
@Override
public void showMessage() {
AllZone.Display.showMessage("Select target Creature, Player, or Planeswalker");
// when multi targets (Arc Mage) are added, need this:
// if payment.targeted < mintarget only enable cancel
// else if payment.targeted < maxtarget enable cancel and ok
ButtonUtil.enableOnlyCancel();
}
@Override
public void selectButtonCancel() {
select.setCancel(true);
stop();
req.finishedTargeting();
}
@Override
public void selectButtonOK() {
select.setDoneTarget(true);
stop();
req.finishedTargeting();
}
@Override
public void selectCard(Card card, PlayerZone zone) {
if((card.isCreature() || card.isPlaneswalker()) && zone.is(Constant.Zone.Play)
&& (!targeted || CardFactoryUtil.canTarget(ability, card))) {
ability.setTargetCard(card);
done();
}
}//selectCard()
@Override
public void selectPlayer(String player) {
ability.setTargetPlayer(player);
// if multitarget increment then select again
done();
}
void done() {
select.getTgt().incrementTargets();
paid.execute();
stop();
req.finishedTargeting();
}
};
return target;
}//input_targetCreaturePlayer()
public static Input targetCreature(final SpellAbility ability, final Target_Selection select, final SpellAbility_Requirements req) {
Input target = new Input() {
private static final long serialVersionUID = 2781418414287281005L;
@Override
public void showMessage() {
AllZone.Display.showMessage("Select target Creature");
ButtonUtil.enableOnlyCancel();
}
@Override
public void selectButtonCancel() {
select.setCancel(true);
stop();
req.finishedTargeting();
}
@Override
public void selectCard(Card card, PlayerZone zone) {
if(card.isCreature() && zone.is(Constant.Zone.Play) && (CardFactoryUtil.canTarget(ability, card))) {
ability.setTargetCard(card);
done();
}
}//selectCard()
void done() {
select.getTgt().incrementTargets();
stop();
req.finishedTargeting();
}
};
return target;
}//targetCreature()
public static Input targetPlayer(final SpellAbility ability, final Target_Selection select, final SpellAbility_Requirements req) {
Input target = new Input() {
private static final long serialVersionUID = 2781418414287281005L;
@Override
public void showMessage() {
AllZone.Display.showMessage("Select target Player or Planeswalker");
ButtonUtil.enableOnlyCancel();
}
@Override
public void selectButtonCancel() {
select.setCancel(true);
stop();
req.finishedTargeting();
}
@Override
public void selectCard(Card card, PlayerZone zone) {
if(card.isPlaneswalker() && zone.is(Constant.Zone.Play) && (!CardFactoryUtil.canTarget(ability, card))) {
ability.setTargetCard(card);
done();
}
}//selectCard()
@Override
public void selectPlayer(String player) {
ability.setTargetPlayer(player);
done();
}
void done() {
select.getTgt().incrementTargets();
stop();
req.finishedTargeting();
}
};
return target;
}//targetPlayer()
}