Third draft of AbilityFactory. Overwrites changes in AbilityFactory from r2620.

Renamed DealDamage to AbilityFactory_DealDamage. Now supports the spell version. (Shock)
All static modifiers removed.
Added support for Buyback in the CardFactory handler for AbilityFactory cards.
This commit is contained in:
jendave
2011-08-06 08:57:11 +00:00
parent aab152403a
commit f9d481d5a6
6 changed files with 306 additions and 60 deletions

1
.gitattributes vendored
View File

@@ -5053,6 +5053,7 @@ src/com/esotericsoftware/minlog/Log.java svneol=native#text/plain
src/forge/Ability.java svneol=native#text/plain src/forge/Ability.java svneol=native#text/plain
src/forge/AbilityFactory.java -text svneol=native#text/plain src/forge/AbilityFactory.java -text svneol=native#text/plain
src/forge/AbilityFactory_Counters.java -text svneol=native#text/plain src/forge/AbilityFactory_Counters.java -text svneol=native#text/plain
src/forge/AbilityFactory_DealDamage.java -text svneol=native#text/plain
src/forge/Ability_Activated.java svneol=native#text/plain src/forge/Ability_Activated.java svneol=native#text/plain
src/forge/Ability_Cost.java -text svneol=native#text/plain src/forge/Ability_Cost.java -text svneol=native#text/plain
src/forge/Ability_Hand.java svneol=native#text/plain src/forge/Ability_Hand.java svneol=native#text/plain

View File

@@ -4,7 +4,7 @@ Types:Creature Human Wizard
Text:no text Text:no text
PT:1/1 PT:1/1
# K:abDamageTgtCP T:1 # K:abDamageTgtCP T:1
A:AB$DealDamage|Cost$T|Tgt$TgtCP|NumDmg$1|SpellDescription$Deal 1 damage to target creature or player. A:AB$DealDamage|Cost$T|Tgt$TgtCP|NumDmg$1|SpellDescription$Prodigal Pyromancer deals 1 damage to target creature or player.
SVar:Rarity:Common SVar:Rarity:Common
SVar:Picture:http://resources.wizards.com/magic/cards/plc/en-us/card122338.jpg SVar:Picture:http://resources.wizards.com/magic/cards/plc/en-us/card122338.jpg
End End

View File

@@ -2,7 +2,8 @@ Name:Shock
ManaCost:R ManaCost:R
Types:Instant Types:Instant
Text:no text Text:no text
K:spDamageTgtCP:2 # K:spDamageTgtCP:2
A:SP$DealDamage|Cost$R|Tgt$TgtCP|NumDmg$2|SpellDescription$Shock deals 2 damage to target creature or player.
SVar:Rarity:Common SVar:Rarity:Common
SVar:Picture:http://www.wizards.com/global/images/magic/general/shock.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/shock.jpg
End End

View File

@@ -57,11 +57,6 @@ public class AbilityFactory {
return abTgt; return abTgt;
} }
private boolean isCurse = false;
public boolean isCurse(){
return isCurse;
}
private boolean hasSubAb = false; private boolean hasSubAb = false;
public boolean hasSubAbility() public boolean hasSubAbility()
@@ -69,14 +64,17 @@ public class AbilityFactory {
return hasSubAb; return hasSubAb;
} }
private static boolean hasSpDesc = false; private boolean hasSpDesc = false;
public boolean hasSpDescription() public boolean hasSpDescription()
{ {
return hasSpDesc; return hasSpDesc;
} }
public SpellAbility getAbility(String abString, final Card hostCard){ //*******************************************************
public SpellAbility getAbility(String abString, Card hostCard){
SpellAbility SA = null; SpellAbility SA = null;
hostC = hostCard; hostC = hostCard;
@@ -99,19 +97,18 @@ public class AbilityFactory {
mapParams.put(aa[0], aa[1]); mapParams.put(aa[0], aa[1]);
} }
String abAPI = ""; // parse universal parameters
String spAPI = "";
// additional ability types here String API = "";
if (mapParams.containsKey("AB")) if (mapParams.containsKey("AB"))
{ {
isAb = true; isAb = true;
abAPI = mapParams.get("AB"); API = mapParams.get("AB");
} }
else if (mapParams.containsKey("SP")) else if (mapParams.containsKey("SP"))
{ {
isSp = true; isSp = true;
spAPI = mapParams.get("SP"); API = mapParams.get("SP");
} }
else else
throw new RuntimeException("AbilityFactory : getAbility -- no API in " + hostCard.getName()); throw new RuntimeException("AbilityFactory : getAbility -- no API in " + hostCard.getName());
@@ -121,10 +118,14 @@ public class AbilityFactory {
throw new RuntimeException("AbilityFactory : getAbility -- no Cost in " + hostCard.getName()); throw new RuntimeException("AbilityFactory : getAbility -- no Cost in " + hostCard.getName());
abCost = new Ability_Cost(mapParams.get("Cost"), hostCard.getName(), isAb); abCost = new Ability_Cost(mapParams.get("Cost"), hostCard.getName(), isAb);
if (mapParams.containsKey("ValidTgts")) if (mapParams.containsKey("ValidTgts"))
{ {
hasValid = true; hasValid = true;
isTargeted = true; isTargeted = true;
abTgt = new Target("TgtV");
abTgt.setValidTgts(mapParams.get("ValidTgts").split(","));
abTgt.setVTSelection(mapParams.get("TgtPrompt"));
} }
if (mapParams.containsKey("ValidCards")) if (mapParams.containsKey("ValidCards"))
@@ -133,31 +134,18 @@ public class AbilityFactory {
if (mapParams.containsKey("Tgt")) if (mapParams.containsKey("Tgt"))
{ {
isTargeted = true; isTargeted = true;
}
if (isTargeted)
{
if (hasValid)
abTgt = new Target("TgtV", mapParams.get("TgtPrompt"), mapParams.get("ValidTgts").split(","));
else
abTgt = new Target(mapParams.get("Tgt")); abTgt = new Target(mapParams.get("Tgt"));
} }
else{
abTgt = null;
}
if (mapParams.containsKey("IsCurse")){
isCurse = true;
}
if (mapParams.containsKey("SubAbility"))
hasSubAb = true;
if (mapParams.containsKey("SpellDescription"))
hasSpDesc = true;
if (abAPI.equals("DealDamage")) hasSubAb = mapParams.containsKey("SubAbility");
hasSpDesc = mapParams.containsKey("SpellDescription");
// ***********************************
// Match API keywords
if (API.equals("DealDamage"))
{ {
final int NumDmg[] = {-1}; final int NumDmg[] = {-1};
final String NumDmgX[] = {"none"}; final String NumDmgX[] = {"none"};
@@ -171,35 +159,40 @@ public class AbilityFactory {
NumDmg[0] = Integer.parseInt(tmpND); NumDmg[0] = Integer.parseInt(tmpND);
} }
AbilityFactory_DealDamage dd = new AbilityFactory_DealDamage();
if (isAb) if (isAb)
SA = DealDamage.getAbility(this, NumDmg[0], NumDmgX[0]); SA = dd.getAbility(this, NumDmg[0], NumDmgX[0]);
else if (isSp) else if (isSp)
SA = DealDamage.getSpell(this); SA = dd.getSpell(this, NumDmg[0], NumDmgX[0]);
} }
// additional keywords here // additional API keywords here
if (abAPI.equals("PutCounter")){
if (isAb)
SA = AbilityFactory_Counters.createAbilityPutCounters(this);
if (isSp){
// todo: createSpellPutCounters
}
}
// *********************************************
// set universal properties of the SpellAbility // set universal properties of the SpellAbility
if (isSp){
// Ability_Activated sets abTgt and abCost in the constructor so this only needs to be set for Spells
// Once Spells are more compatible with Tgt and abCost this block should be removed
if (isTargeted) if (isTargeted)
{
//if (isAb)
SA.setTarget(abTgt); SA.setTarget(abTgt);
SA.setPayCosts(abCost);
} }
//if (isAb)
SA.setPayCosts(abCost);
if (hasSpDesc) if (hasSpDesc)
SA.setDescription(abCost.toString() + mapParams.get("SpellDescription")); {
String desc = mapParams.get("SpellDescription");
if (isAb)
desc = abCost.toString() + desc;
SA.setDescription(desc);
}
return SA; return SA;
} }

View File

@@ -0,0 +1,233 @@
package forge;
import java.util.Random;
public class AbilityFactory_DealDamage {
private AbilityFactory AF = null;
private AbilityFactory getAF(){
return AF;
}
private int nDamage = -1;
private String XDamage = "none";
private boolean TgtOpp = false;
public SpellAbility getAbility(final AbilityFactory af, final int NumDmg, final String NumDmgX)
{
AF = af;
nDamage = NumDmg;
XDamage = NumDmgX;
if (AF.getMapParams().get("Tgt").equals("TgtOpp"))
TgtOpp = true;
final SpellAbility abDamage = new Ability_Activated(AF.getHostCard(), AF.getAbCost(), AF.getAbTgt())
{
private static final long serialVersionUID = -7560349014757367722L;
@Override
public boolean canPlay(){
return (Cost_Payment.canPayAdditionalCosts(AF.getAbCost(), this)
&& CardFactoryUtil.canUseAbility(AF.getHostCard())
&& super.canPlay());
}
@Override
public boolean canPlayAI() {
return doCanPlayAI(this);
}
@Override
public void resolve() {
doResolve(this);
AF.getHostCard().setAbilityUsed(AF.getHostCard().getAbilityUsed() + 1);
}
};//Ability_Activated
return abDamage;
}
public SpellAbility getSpell(final AbilityFactory af, final int NumDmg, final String NumDmgX)
{
AF = af;
nDamage = NumDmg;
XDamage = NumDmgX;
if (AF.getMapParams().get("Tgt").equals("TgtOpp"))
TgtOpp = true;
final SpellAbility spDealDamage = new Spell(AF.getHostCard()) {
private static final long serialVersionUID = 7239608350643325111L;
@Override
public boolean canPlay(){
return (Cost_Payment.canPayAdditionalCosts(AF.getAbCost(), this)
&& super.canPlay());
}
@Override
public boolean canPlayAI() {
return doCanPlayAI(this);
}
@Override
public void resolve() {
doResolve(this);
}
}; // Spell
return spDealDamage;
}
private int getNumDamage() {
if(nDamage != -1) return nDamage;
if(!XDamage.equals("none"))
return CardFactoryUtil.xCount(AF.getHostCard(), XDamage);
return 0;
}
private boolean shouldTgtP(int d) {
PlayerZone compHand = AllZone.getZone(Constant.Zone.Hand, Constant.Player.Computer);
CardList hand = new CardList(compHand.getCards());
if(AF.isSpell() && hand.size() > 7) // anti-discard-at-EOT
return true;
if(AllZone.Human_Life.getLife() - d < 10) // if damage from this spell would drop the human to less than 10 life
return true;
return false;
}
private Card chooseTgtC(final int d) {
// Combo alert!!
PlayerZone compy = AllZone.getZone(Constant.Zone.Play, Constant.Player.Computer);
CardList cPlay = new CardList(compy.getCards());
if(cPlay.size() > 0) for(int i = 0; i < cPlay.size(); i++)
if(cPlay.get(i).getName().equals("Stuffy Doll")) return cPlay.get(i);
PlayerZone human = AllZone.getZone(Constant.Zone.Play, Constant.Player.Human);
CardList hPlay = new CardList(human.getCards());
hPlay = hPlay.filter(new CardListFilter() {
public boolean addCard(Card c) {
// will include creatures already dealt damage
return c.isCreature() && ((c.getNetDefense() + c.getDamage()) <= d)
&& CardFactoryUtil.canTarget(AF.getHostCard(), c);
}
});
if(hPlay.size() > 0) {
Card best = hPlay.get(0);
if(hPlay.size() > 1) {
for(int i = 1; i < hPlay.size(); i++) {
Card b = hPlay.get(i);
// choose best overall creature?
if(b.getSpellAbility().length > best.getSpellAbility().length
|| b.getKeyword().size() > best.getKeyword().size()
|| b.getNetAttack() > best.getNetAttack()) best = b;
}
}
return best;
}
return null;
}
private boolean doCanPlayAI(SpellAbility saMe)
{
// temporarily disabled until better AI
if (AF.getAbCost().getSacCost()) return false;
if (AF.getAbCost().getSubCounter()) return false;
if (AF.getAbCost().getLifeCost()) return false;
if (!ComputerUtil.canPayCost(saMe))
return false;
int damage = getNumDamage();
boolean rr = false;
if (AF.isAbility())
{
Random r = new Random(); // prevent run-away activations
if(r.nextFloat() <= Math.pow(.6667, AF.getHostCard().getAbilityUsed()))
rr = true;
}
else if (AF.isSpell())
rr = true;
if(AF.getAbTgt().canTgtCreaturePlayer()) {
if(shouldTgtP(damage)) {
saMe.setTargetPlayer(Constant.Player.Human);
return rr;
}
Card c = chooseTgtC(damage);
if(c != null) {
saMe.setTargetCard(c);
return rr;
}
}
if(AF.getAbTgt().canTgtPlayer() || TgtOpp == true) {
saMe.setTargetPlayer(Constant.Player.Human);
return rr;
}
if(AF.getAbTgt().canTgtCreature()) {
Card c = chooseTgtC(damage);
if(c != null) {
saMe.setTargetCard(c);
return rr;
}
}
return false;
}
private void doResolve(SpellAbility saMe)
{
int damage = getNumDamage();
String tgtP = "";
if(TgtOpp == true) {
tgtP = AllZone.GameAction.getOpponent(AF.getHostCard().getController());
saMe.setTargetPlayer(tgtP);
}
Card c = saMe.getTargetCard();
if(c != null) {
if(AllZone.GameAction.isCardInPlay(c) && CardFactoryUtil.canTarget(AF.getHostCard(), c)) {
AllZone.GameAction.addDamage(c, AF.getHostCard(), damage);
tgtP = c.getController();
if(AF.hasSubAbility())
CardFactoryUtil.doDrawBack(AF.getMapParams().get("SubAbility"), damage,
AF.getHostCard().getController(), AllZone.GameAction.getOpponent(AF.getHostCard().getController()),
tgtP, AF.getHostCard(), c, saMe);
}
} else {
tgtP = saMe.getTargetPlayer();
AllZone.GameAction.addDamage(tgtP, AF.getHostCard(), damage);
if(AF.hasSubAbility())
CardFactoryUtil.doDrawBack(AF.getMapParams().get("SubAbility"), damage,
AF.getHostCard().getController(), AllZone.GameAction.getOpponent(AF.getHostCard().getController()),
tgtP, AF.getHostCard(), null, saMe);
}
}
}

View File

@@ -6097,10 +6097,28 @@ public class CardFactory implements NewConstants {
if (card.isInstant() || card.isSorcery()) if (card.isInstant() || card.isSorcery())
card.clearSpellAbility(); card.clearSpellAbility();
for (int i=0; i<IA.size(); i++){ for (int i=0; i<IA.size(); i++)
{
AbilityFactory AF = new AbilityFactory(); AbilityFactory AF = new AbilityFactory();
card.addSpellAbility(AF.getAbility(IA.get(i), card)); SpellAbility sa = AF.getAbility(IA.get(i), card);
card.addSpellAbility(sa);
String bbCost = card.getSVar("Buyback");
if (!bbCost.equals(""))
{
SpellAbility bbSA = sa.copy();
bbSA.setManaCost(CardUtil.addManaCosts(card.getManaCost(), bbCost));
StringBuilder sb = new StringBuilder();
sb.append("Buyback ").append(bbCost).append(" (You may pay an additional ").append(bbCost);
sb.append(" as you cast this spell. If you do, put this card into your hand as it resolves.)");
bbSA.setDescription(sb.toString());
bbSA.setIsBuyBackAbility(true);
card.addSpellAbility(bbSA);
} }
}
} }