mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 20:28:00 +00:00
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:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
233
src/forge/AbilityFactory_DealDamage.java
Normal file
233
src/forge/AbilityFactory_DealDamage.java
Normal 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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user