mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
- Initial SubAbility work: DealDamage, GainLife, Draw, Mill all can now be called as a SubAbility and can call SubAbilities.
- Target_Selection will now Target for Parent ability and each subAbility that requires it - Stack will fizzle if ALL Targets are illegal on resolution - Merged Orcish Cannonade, Psionic Entity to AF+SubAbility - Added Lunge - Target Prompt now Optional in AFs
This commit is contained in:
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -2751,6 +2751,7 @@ res/cardsfolder/lull.txt -text svneol=native#text/plain
|
|||||||
res/cardsfolder/lumbering_satyr.txt -text svneol=native#text/plain
|
res/cardsfolder/lumbering_satyr.txt -text svneol=native#text/plain
|
||||||
res/cardsfolder/lumengrid_warden.txt -text svneol=native#text/plain
|
res/cardsfolder/lumengrid_warden.txt -text svneol=native#text/plain
|
||||||
res/cardsfolder/luminous_angel.txt -text svneol=native#text/plain
|
res/cardsfolder/luminous_angel.txt -text svneol=native#text/plain
|
||||||
|
res/cardsfolder/lunge.txt -text svneol=native#text/plain
|
||||||
res/cardsfolder/lure.txt -text svneol=native#text/plain
|
res/cardsfolder/lure.txt -text svneol=native#text/plain
|
||||||
res/cardsfolder/lurking_informant.txt -text svneol=native#text/plain
|
res/cardsfolder/lurking_informant.txt -text svneol=native#text/plain
|
||||||
res/cardsfolder/lurking_nightstalker.txt -text svneol=native#text/plain
|
res/cardsfolder/lurking_nightstalker.txt -text svneol=native#text/plain
|
||||||
@@ -5790,6 +5791,7 @@ src/forge/Ability_Cost.java -text svneol=native#text/plain
|
|||||||
src/forge/Ability_Mana.java -text svneol=native#text/plain
|
src/forge/Ability_Mana.java -text svneol=native#text/plain
|
||||||
src/forge/Ability_Reflected_Mana.java svneol=native#text/plain
|
src/forge/Ability_Reflected_Mana.java svneol=native#text/plain
|
||||||
src/forge/Ability_Static.java -text svneol=native#text/plain
|
src/forge/Ability_Static.java -text svneol=native#text/plain
|
||||||
|
src/forge/Ability_Sub.java -text svneol=native#text/plain
|
||||||
src/forge/Ability_Tap.java svneol=native#text/plain
|
src/forge/Ability_Tap.java svneol=native#text/plain
|
||||||
src/forge/Ability_Triggered.java svneol=native#text/plain
|
src/forge/Ability_Triggered.java svneol=native#text/plain
|
||||||
src/forge/AllZone.java svneol=native#text/plain
|
src/forge/AllZone.java svneol=native#text/plain
|
||||||
|
|||||||
9
res/cardsfolder/lunge.txt
Normal file
9
res/cardsfolder/lunge.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Name:Lunge
|
||||||
|
ManaCost:2 R
|
||||||
|
Types:Instant
|
||||||
|
Text:no text
|
||||||
|
A:SP$DealDamage | Cost$ 2 R | Tgt$ C | NumDmg$2 | SubAbility$SVar=DB1 | SpellDescription$ Lunge deals 2 damage to target creature and 2 damage to target player.
|
||||||
|
SVar:DB1:DB$DealDamage | NumDmg$ 2 | Tgt$ P
|
||||||
|
SVar:Rarity:Common
|
||||||
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/lunge.jpg
|
||||||
|
End
|
||||||
@@ -2,8 +2,9 @@ Name:Orcish Cannonade
|
|||||||
ManaCost:1 R R
|
ManaCost:1 R R
|
||||||
Types:Instant
|
Types:Instant
|
||||||
Text:no text
|
Text:no text
|
||||||
K:spDamageTgtCP:2:Drawback$DamageYou/3:Orcish Cannonade deals 2 damage to target creature or player and 3 damage to you.
|
A:SP$DealDamage | Cost$ 1 R R | Tgt$ CP | NumDmg$2 | SubAbility$SVar=DB1 | SpellDescription$ Orcish Cannonade deals 2 damage to target creature or player and 3 damage to you. Draw a card.
|
||||||
K:Draw a card.
|
SVar:DB1:DB$DealDamage | NumDmg$ 3 | Affected$ You | SubAbility$SVar=DB2
|
||||||
|
SVar:DB2:DB$Draw | NumCards$ 1
|
||||||
SVar:Rarity:Common
|
SVar:Rarity:Common
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/orcish_cannonade.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/orcish_cannonade.jpg
|
||||||
End
|
End
|
||||||
@@ -3,7 +3,8 @@ ManaCost:4 U
|
|||||||
Types:Creature Illusion
|
Types:Creature Illusion
|
||||||
Text:no text
|
Text:no text
|
||||||
PT:2/2
|
PT:2/2
|
||||||
K:abDamageTgtCP T:2:Drawback$DamageSelf/3:Psionic Entity deals 2 damage to target creature or player and 3 damage to itself.:Psionic Entity - deal damage to creature or player and itself.
|
A:AB$DealDamage | Cost$ T | Tgt$ CP | NumDmg$2 | SubAbility$SVar=DB1 | SpellDescription$ Psionic Entity deals 2 damage to target creature or player and 3 damage to itself.
|
||||||
|
SVar:DB1:DB$DealDamage | NumDmg$ 3 | Affected$ Self
|
||||||
SVar:Rarity:Rare
|
SVar:Rarity:Rare
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/psionic_entity.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/psionic_entity.jpg
|
||||||
End
|
End
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ public class AbilityFactory {
|
|||||||
|
|
||||||
private boolean isAb = false;
|
private boolean isAb = false;
|
||||||
private boolean isSp = false;
|
private boolean isSp = false;
|
||||||
|
private boolean isDb = false;
|
||||||
|
|
||||||
public boolean isAbility()
|
public boolean isAbility()
|
||||||
{
|
{
|
||||||
@@ -31,6 +32,10 @@ public class AbilityFactory {
|
|||||||
return isSp;
|
return isSp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isDrawback() {
|
||||||
|
return isDb;
|
||||||
|
}
|
||||||
|
|
||||||
private Ability_Cost abCost = null;
|
private Ability_Cost abCost = null;
|
||||||
|
|
||||||
public Ability_Cost getAbCost()
|
public Ability_Cost getAbCost()
|
||||||
@@ -120,14 +125,18 @@ public class AbilityFactory {
|
|||||||
isSp = true;
|
isSp = true;
|
||||||
API = mapParams.get("SP");
|
API = mapParams.get("SP");
|
||||||
}
|
}
|
||||||
|
else if (mapParams.containsKey("DB")) {
|
||||||
|
isDb = true;
|
||||||
|
API = mapParams.get("DB");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
throw new RuntimeException("AbilityFactory : getAbility -- no API in " + hostCard.getName());
|
throw new RuntimeException("AbilityFactory : getAbility -- no API in " + hostCard.getName());
|
||||||
|
|
||||||
|
if (!isDb){
|
||||||
if (!mapParams.containsKey("Cost"))
|
if (!mapParams.containsKey("Cost"))
|
||||||
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"))
|
||||||
{
|
{
|
||||||
@@ -145,8 +154,11 @@ public class AbilityFactory {
|
|||||||
int min = mapParams.containsKey("TargetMin") ? Integer.parseInt(mapParams.get("TargetMin")) : 1;
|
int min = mapParams.containsKey("TargetMin") ? Integer.parseInt(mapParams.get("TargetMin")) : 1;
|
||||||
int max = mapParams.containsKey("TargetMax") ? Integer.parseInt(mapParams.get("TargetMax")) : 1;
|
int max = mapParams.containsKey("TargetMax") ? Integer.parseInt(mapParams.get("TargetMax")) : 1;
|
||||||
|
|
||||||
if (hasValid)
|
if (hasValid){
|
||||||
abTgt = new Target(mapParams.get("TgtPrompt"), mapParams.get("ValidTgts").split(","), min, max);
|
// TgtPrompt now optional
|
||||||
|
String prompt = mapParams.containsKey("TgtPrompt") ? mapParams.get("TgtPrompt") : "Select target " + mapParams.get("ValidTgts");
|
||||||
|
abTgt = new Target(prompt, mapParams.get("ValidTgts").split(","), min, max);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
abTgt = new Target(mapParams.get("Tgt"), min, max);
|
abTgt = new Target(mapParams.get("Tgt"), min, max);
|
||||||
|
|
||||||
@@ -161,29 +173,18 @@ public class AbilityFactory {
|
|||||||
// ***********************************
|
// ***********************************
|
||||||
// Match API keywords
|
// Match API keywords
|
||||||
|
|
||||||
if (API.equals("DealDamage"))
|
if (API.equals("DealDamage"))
|
||||||
{
|
{
|
||||||
final int NumDmg[] = {-1};
|
AbilityFactory_DealDamage dd = new AbilityFactory_DealDamage(this);
|
||||||
final String NumDmgX[] = {"none"};
|
|
||||||
String tmpND = mapParams.get("NumDmg");
|
|
||||||
if (tmpND.length() > 0)
|
|
||||||
{
|
|
||||||
if (tmpND.matches("X"))
|
|
||||||
NumDmgX[0] = hostCard.getSVar(tmpND);
|
|
||||||
|
|
||||||
else if (tmpND.matches("[0-9][0-9]?"))
|
if (isAb)
|
||||||
NumDmg[0] = Integer.parseInt(tmpND);
|
SA = dd.getAbility();
|
||||||
}
|
|
||||||
|
|
||||||
AbilityFactory_DealDamage dd = new AbilityFactory_DealDamage();
|
|
||||||
|
|
||||||
if (isAb)
|
|
||||||
SA = dd.getAbility(this, NumDmg[0], NumDmgX[0]);
|
|
||||||
else if (isSp)
|
else if (isSp)
|
||||||
SA = dd.getSpell(this, NumDmg[0], NumDmgX[0]);
|
SA = dd.getSpell();
|
||||||
|
else if (isDb)
|
||||||
|
SA = dd.getDrawback();
|
||||||
}
|
SA.setSubAbility(dd.getSubAbility());
|
||||||
|
}
|
||||||
|
|
||||||
if (API.equals("PutCounter")){
|
if (API.equals("PutCounter")){
|
||||||
if (isAb)
|
if (isAb)
|
||||||
@@ -240,9 +241,12 @@ public class AbilityFactory {
|
|||||||
if (API.equals("GainLife")){
|
if (API.equals("GainLife")){
|
||||||
if (isAb)
|
if (isAb)
|
||||||
SA = AbilityFactory_AlterLife.createAbilityGainLife(this);
|
SA = AbilityFactory_AlterLife.createAbilityGainLife(this);
|
||||||
if (isSp){
|
else if (isSp)
|
||||||
SA = AbilityFactory_AlterLife.createSpellGainLife(this);
|
SA = AbilityFactory_AlterLife.createSpellGainLife(this);
|
||||||
}
|
else if (isDb)
|
||||||
|
SA = AbilityFactory_AlterLife.createSpellGainLife(this);
|
||||||
|
if(hasSubAbility())
|
||||||
|
SA.setSubAbility(getSubAbility());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (API.equals("LoseLife")){
|
if (API.equals("LoseLife")){
|
||||||
@@ -297,17 +301,23 @@ public class AbilityFactory {
|
|||||||
if (API.equals("Draw")){
|
if (API.equals("Draw")){
|
||||||
if (isAb)
|
if (isAb)
|
||||||
SA = AbilityFactory_ZoneAffecting.createAbilityDraw(this);
|
SA = AbilityFactory_ZoneAffecting.createAbilityDraw(this);
|
||||||
if (isSp){
|
else if (isSp)
|
||||||
SA = AbilityFactory_ZoneAffecting.createSpellDraw(this);
|
SA = AbilityFactory_ZoneAffecting.createSpellDraw(this);
|
||||||
}
|
else if (isDb)
|
||||||
|
SA = AbilityFactory_ZoneAffecting.createDrawbackDraw(this);
|
||||||
|
if(hasSubAbility())
|
||||||
|
SA.setSubAbility(getSubAbility());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (API.equals("Mill")){
|
if (API.equals("Mill")){
|
||||||
if (isAb)
|
if (isAb)
|
||||||
SA = AbilityFactory_ZoneAffecting.createAbilityMill(this);
|
SA = AbilityFactory_ZoneAffecting.createAbilityMill(this);
|
||||||
if (isSp){
|
else if (isSp)
|
||||||
SA = AbilityFactory_ZoneAffecting.createSpellMill(this);
|
SA = AbilityFactory_ZoneAffecting.createSpellMill(this);
|
||||||
}
|
else if (isDb)
|
||||||
|
SA = AbilityFactory_ZoneAffecting.createDrawbackMill(this);
|
||||||
|
if(hasSubAbility())
|
||||||
|
SA.setSubAbility(getSubAbility());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (API.equals("Destroy")){
|
if (API.equals("Destroy")){
|
||||||
@@ -402,6 +412,27 @@ public class AbilityFactory {
|
|||||||
return SA;
|
return SA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Easy creation of SubAbilities
|
||||||
|
public Ability_Sub getSubAbility(){
|
||||||
|
Ability_Sub abSub = null;
|
||||||
|
|
||||||
|
String sSub = getMapParams().get("SubAbility");
|
||||||
|
|
||||||
|
if (sSub.startsWith("SVar="))
|
||||||
|
sSub = getHostCard().getSVar(sSub.split("=")[1]);
|
||||||
|
|
||||||
|
if (sSub.startsWith("DB$"))
|
||||||
|
{
|
||||||
|
AbilityFactory afDB = new AbilityFactory();
|
||||||
|
abSub = (Ability_Sub)afDB.getAbility(sSub, getHostCard());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// Older style Drawback. May not be necessary?
|
||||||
|
}
|
||||||
|
|
||||||
|
return abSub;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,15 +18,7 @@ public class AbilityFactory_AlterLife {
|
|||||||
@Override
|
@Override
|
||||||
public String getStackDescription(){
|
public String getStackDescription(){
|
||||||
// when getStackDesc is called, just build exactly what is happening
|
// when getStackDesc is called, just build exactly what is happening
|
||||||
StringBuilder sb = new StringBuilder();
|
return gainLifeStackDescription(af, this);
|
||||||
String name = af.getHostCard().getName();
|
|
||||||
int amount = calculateAmount(af.getHostCard(), params.get("LifeAmount"), this);
|
|
||||||
String player = "You gain ";
|
|
||||||
if (af.getAbTgt() != null)
|
|
||||||
player = getTargetPlayer() + " gains ";
|
|
||||||
sb.append(name).append(" - ").append(player).append(amount).append(" life.");
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canPlay(){
|
public boolean canPlay(){
|
||||||
@@ -59,15 +51,7 @@ public class AbilityFactory_AlterLife {
|
|||||||
@Override
|
@Override
|
||||||
public String getStackDescription(){
|
public String getStackDescription(){
|
||||||
// when getStackDesc is called, just build exactly what is happening
|
// when getStackDesc is called, just build exactly what is happening
|
||||||
StringBuilder sb = new StringBuilder();
|
return gainLifeStackDescription(af, this);
|
||||||
String name = af.getHostCard().getName();
|
|
||||||
int amount = calculateAmount(af.getHostCard(), params.get("LifeAmount"), this);
|
|
||||||
String player = "You gain ";
|
|
||||||
if (af.getAbTgt() != null)
|
|
||||||
player = getTargetPlayer() + " gains ";
|
|
||||||
sb.append(name).append(" - ").append(player).append(amount).append(" life.");
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canPlay(){
|
public boolean canPlay(){
|
||||||
@@ -93,6 +77,42 @@ public class AbilityFactory_AlterLife {
|
|||||||
return spGainLife;
|
return spGainLife;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SpellAbility createDrawbackGainLife(final AbilityFactory AF){
|
||||||
|
final SpellAbility dbGainLife = new Ability_Sub(AF.getHostCard(), AF.getAbTgt()){
|
||||||
|
private static final long serialVersionUID = 6631124959690157874L;
|
||||||
|
|
||||||
|
final AbilityFactory af = AF;
|
||||||
|
final HashMap<String,String> params = af.getMapParams();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getStackDescription(){
|
||||||
|
// when getStackDesc is called, just build exactly what is happening
|
||||||
|
return gainLifeStackDescription(af, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canPlayAI()
|
||||||
|
{
|
||||||
|
// if X depends on abCost, the AI needs to choose which card he would sacrifice first
|
||||||
|
// then call xCount with that card to properly calculate the amount
|
||||||
|
// Or choosing how many to sacrifice
|
||||||
|
return gainLifeCanPlayAI(af, this, params.get("LifeAmount"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolve() {
|
||||||
|
int amount = calculateAmount(af.getHostCard(), params.get("LifeAmount"), this);
|
||||||
|
gainLifeResolve(af, this, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean chkAI_Drawback() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
return dbGainLife;
|
||||||
|
}
|
||||||
|
|
||||||
public static SpellAbility createAbilityLoseLife(final AbilityFactory AF){
|
public static SpellAbility createAbilityLoseLife(final AbilityFactory AF){
|
||||||
final SpellAbility abLoseLife = new Ability_Activated(AF.getHostCard(), AF.getAbCost(), AF.getAbTgt()){
|
final SpellAbility abLoseLife = new Ability_Activated(AF.getHostCard(), AF.getAbCost(), AF.getAbTgt()){
|
||||||
private static final long serialVersionUID = 1129762905315395160L;
|
private static final long serialVersionUID = 1129762905315395160L;
|
||||||
@@ -182,13 +202,6 @@ public class AbilityFactory_AlterLife {
|
|||||||
return abLoseLife;
|
return abLoseLife;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SpellAbility createAbilitySyphonLife(final AbilityFactory AF){ // tgt loses X life, you gain X life
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SpellAbility createSpellSyphonLife(final AbilityFactory AF){ // tgt loses X life, you gain X life
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int calculateAmount(Card card, String lifeAmount, SpellAbility ability){
|
public static int calculateAmount(Card card, String lifeAmount, SpellAbility ability){
|
||||||
if (lifeAmount.matches("X"))
|
if (lifeAmount.matches("X"))
|
||||||
@@ -212,6 +225,29 @@ public class AbilityFactory_AlterLife {
|
|||||||
return Integer.parseInt(lifeAmount);
|
return Integer.parseInt(lifeAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String gainLifeStackDescription(AbilityFactory af, SpellAbility sa){
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
int amount = calculateAmount(af.getHostCard(), af.getMapParams().get("LifeAmount"), sa);
|
||||||
|
|
||||||
|
if (!(sa instanceof Ability_Sub))
|
||||||
|
sb.append(sa.getSourceCard().getName()).append(" - ");
|
||||||
|
else
|
||||||
|
sb.append(" ");
|
||||||
|
|
||||||
|
String player = "You gain ";
|
||||||
|
if (af.getAbTgt() != null)
|
||||||
|
player = sa.getTargetPlayer() + " gains ";
|
||||||
|
sb.append(player).append(amount).append(" life.");
|
||||||
|
|
||||||
|
Ability_Sub abSub = sa.getSubAbility();
|
||||||
|
if (abSub != null) {
|
||||||
|
abSub.setParent(sa);
|
||||||
|
sb.append(abSub.getStackDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean gainLifeCanPlayAI(final AbilityFactory af, final SpellAbility sa, final String amountStr){
|
public static boolean gainLifeCanPlayAI(final AbilityFactory af, final SpellAbility sa, final String amountStr){
|
||||||
Random r = new Random();
|
Random r = new Random();
|
||||||
Ability_Cost abCost = sa.getPayCosts();
|
Ability_Cost abCost = sa.getPayCosts();
|
||||||
@@ -260,7 +296,6 @@ public class AbilityFactory_AlterLife {
|
|||||||
|
|
||||||
public static void gainLifeResolve(final AbilityFactory af, final SpellAbility sa, int lifeAmount){
|
public static void gainLifeResolve(final AbilityFactory af, final SpellAbility sa, int lifeAmount){
|
||||||
HashMap<String,String> params = af.getMapParams();
|
HashMap<String,String> params = af.getMapParams();
|
||||||
String DrawBack = params.get("SubAbility");
|
|
||||||
Card card = af.getHostCard();
|
Card card = af.getHostCard();
|
||||||
|
|
||||||
ArrayList<Player> tgtPlayers;
|
ArrayList<Player> tgtPlayers;
|
||||||
@@ -277,8 +312,20 @@ public class AbilityFactory_AlterLife {
|
|||||||
if (tgt == null || p.canTarget(af.getHostCard()))
|
if (tgt == null || p.canTarget(af.getHostCard()))
|
||||||
p.gainLife(lifeAmount, sa.getSourceCard());
|
p.gainLife(lifeAmount, sa.getSourceCard());
|
||||||
|
|
||||||
if (af.hasSubAbility())
|
|
||||||
CardFactoryUtil.doDrawBack(DrawBack, lifeAmount, card.getController(), card.getController().getOpponent(), tgtPlayers.get(0), card, null, sa);
|
if (af.hasSubAbility()){
|
||||||
|
Ability_Sub abSub = sa.getSubAbility();
|
||||||
|
if (abSub != null){
|
||||||
|
if (abSub.getParent() == null)
|
||||||
|
abSub.setParent(sa);
|
||||||
|
abSub.resolve();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
String DrawBack = params.get("SubAbility");
|
||||||
|
if (af.hasSubAbility())
|
||||||
|
CardFactoryUtil.doDrawBack(DrawBack, lifeAmount, card.getController(), card.getController().getOpponent(), tgtPlayers.get(0), card, null, sa);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean loseLifeCanPlayAI(final AbilityFactory af, final SpellAbility sa, final String amountStr){
|
public static boolean loseLifeCanPlayAI(final AbilityFactory af, final SpellAbility sa, final String amountStr){
|
||||||
|
|||||||
@@ -1,316 +1,397 @@
|
|||||||
package forge;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
package forge;
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
public class AbilityFactory_DealDamage {
|
import java.util.ArrayList;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
private AbilityFactory AF = null;
|
public class AbilityFactory_DealDamage {
|
||||||
|
private AbilityFactory AF = null;
|
||||||
|
|
||||||
private int nDamage = -1;
|
private int nDamage = -1;
|
||||||
|
|
||||||
private String XDamage = "none";
|
private String XDamage = "none";
|
||||||
|
|
||||||
private boolean TgtOpp = false;
|
private boolean TgtOpp = false;
|
||||||
|
|
||||||
public SpellAbility getAbility(final AbilityFactory af, final int NumDmg, final String NumDmgX)
|
private Ability_Sub subAbAF = null;
|
||||||
{
|
private boolean hasSubAbAF = false;
|
||||||
AF = af;
|
private String subAbStr = "none";
|
||||||
nDamage = NumDmg;
|
private boolean hasSubAbStr = false;
|
||||||
XDamage = NumDmgX;
|
|
||||||
|
|
||||||
if(af.getMapParams().containsKey("Tgt"))
|
public Ability_Sub getSubAbility() { return subAbAF; }
|
||||||
if (AF.getMapParams().get("Tgt").equals("TgtOpp"))
|
|
||||||
TgtOpp = true;
|
|
||||||
|
|
||||||
final SpellAbility abDamage = new Ability_Activated(AF.getHostCard(), AF.getAbCost(), AF.getAbTgt())
|
public AbilityFactory_DealDamage(AbilityFactory newAF)
|
||||||
{
|
{
|
||||||
private static final long serialVersionUID = -7560349014757367722L;
|
AF = newAF;
|
||||||
|
|
||||||
@Override
|
String tmpND = AF.getMapParams().get("NumDmg");
|
||||||
public boolean canPlay(){
|
if (tmpND.length() > 0)
|
||||||
return super.canPlay();
|
{
|
||||||
|
if (tmpND.matches("[xX]"))
|
||||||
|
XDamage = AF.getHostCard().getSVar(tmpND.substring(1));
|
||||||
|
|
||||||
|
else if (tmpND.matches("[0-9][0-9]?"))
|
||||||
|
nDamage = Integer.parseInt(tmpND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
if(AF.getMapParams().containsKey("Tgt"))
|
||||||
public boolean canPlayAI() {
|
if (AF.getMapParams().get("Tgt").equals("TgtOpp"))
|
||||||
return doCanPlayAI(this);
|
TgtOpp = true;
|
||||||
|
|
||||||
|
if(AF.hasSubAbility())
|
||||||
|
{
|
||||||
|
String sSub = AF.getMapParams().get("SubAbility");
|
||||||
|
|
||||||
|
if (sSub.startsWith("SVar="))
|
||||||
|
sSub = AF.getHostCard().getSVar(sSub.split("=")[1]);
|
||||||
|
|
||||||
|
if (sSub.startsWith("DB$"))
|
||||||
|
{
|
||||||
|
AbilityFactory afDB = new AbilityFactory();
|
||||||
|
subAbAF = (Ability_Sub)afDB.getAbility(sSub, AF.getHostCard());
|
||||||
|
hasSubAbAF = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
subAbStr = sSub;
|
||||||
|
hasSubAbStr = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
}
|
||||||
public String getStackDescription(){
|
|
||||||
return damageStackDescription(AF, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public SpellAbility getAbility()
|
||||||
public void resolve() {
|
{
|
||||||
doResolve(this);
|
final SpellAbility abDamage = new Ability_Activated(AF.getHostCard(), AF.getAbCost(), AF.getAbTgt())
|
||||||
AF.getHostCard().setAbilityUsed(AF.getHostCard().getAbilityUsed() + 1);
|
{
|
||||||
|
private static final long serialVersionUID = -7560349014757367722L;
|
||||||
|
|
||||||
}
|
@Override
|
||||||
};//Ability_Activated
|
public boolean canPlay(){
|
||||||
|
return super.canPlay();
|
||||||
return abDamage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SpellAbility getSpell(final AbilityFactory af, final int NumDmg, final String NumDmgX)
|
|
||||||
{
|
|
||||||
AF = af;
|
|
||||||
nDamage = NumDmg;
|
|
||||||
XDamage = NumDmgX;
|
|
||||||
|
|
||||||
if(af.getMapParams().containsKey("Tgt"))
|
|
||||||
if (AF.getMapParams().get("Tgt").equals("TgtOpp"))
|
|
||||||
TgtOpp = true;
|
|
||||||
|
|
||||||
final SpellAbility spDealDamage = new Spell(AF.getHostCard(), AF.getAbCost(), AF.getAbTgt()) {
|
|
||||||
private static final long serialVersionUID = 7239608350643325111L;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canPlay(){
|
|
||||||
return super.canPlay();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canPlayAI() {
|
|
||||||
return doCanPlayAI(this);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getStackDescription(){
|
|
||||||
return damageStackDescription(AF, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void resolve() {
|
|
||||||
doResolve(this);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}; // Spell
|
|
||||||
|
|
||||||
return spDealDamage;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getNumDamage(SpellAbility saMe) {
|
|
||||||
if(nDamage != -1) return nDamage;
|
|
||||||
|
|
||||||
String calcX[] = XDamage.split("\\$");
|
|
||||||
|
|
||||||
if (calcX.length == 1 || calcX[1].equals("none"))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (calcX[0].startsWith("Count"))
|
|
||||||
{
|
|
||||||
return CardFactoryUtil.xCount(AF.getHostCard(), calcX[1]);
|
|
||||||
}
|
|
||||||
else if (calcX[0].startsWith("Sacrificed"))
|
|
||||||
{
|
|
||||||
return CardFactoryUtil.handlePaid(saMe.getSacrificedCost(), calcX[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean shouldTgtP(int d) {
|
|
||||||
PlayerZone compHand = AllZone.getZone(Constant.Zone.Hand, AllZone.ComputerPlayer);
|
|
||||||
CardList hand = new CardList(compHand.getCards());
|
|
||||||
|
|
||||||
if(AF.isSpell() && hand.size() > 7) // anti-discard-at-EOT
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if(AllZone.HumanPlayer.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, AllZone.ComputerPlayer);
|
|
||||||
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, AllZone.HumanPlayer);
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPlayAI() {
|
||||||
|
return doCanPlayAI(this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getStackDescription(){
|
||||||
|
return damageStackDescription(AF, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolve() {
|
||||||
|
doResolve(this);
|
||||||
|
AF.getHostCard().setAbilityUsed(AF.getHostCard().getAbilityUsed() + 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
};//Ability_Activated
|
||||||
|
|
||||||
|
return abDamage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpellAbility getSpell()
|
||||||
|
{
|
||||||
|
final SpellAbility spDealDamage = new Spell(AF.getHostCard(), AF.getAbCost(), AF.getAbTgt()) {
|
||||||
|
private static final long serialVersionUID = 7239608350643325111L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPlay(){
|
||||||
|
return super.canPlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPlayAI() {
|
||||||
|
return doCanPlayAI(this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getStackDescription(){
|
||||||
|
return damageStackDescription(AF, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolve() {
|
||||||
|
doResolve(this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}; // Spell
|
||||||
|
|
||||||
|
return spDealDamage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpellAbility getDrawback()
|
||||||
|
{
|
||||||
|
final SpellAbility dbDealDamage = new Ability_Sub(AF.getHostCard(), AF.getAbTgt()) {
|
||||||
|
private static final long serialVersionUID = 7239608350643325111L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean chkAI_Drawback() {
|
||||||
|
return doCanPlayAI(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getStackDescription() {
|
||||||
|
return damageStackDescription(AF, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolve() {
|
||||||
|
doResolve(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // Spell
|
||||||
|
|
||||||
|
return dbDealDamage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private int getNumDamage(SpellAbility saMe) {
|
||||||
|
if(nDamage != -1) return nDamage;
|
||||||
|
|
||||||
|
String calcX[] = XDamage.split("\\$");
|
||||||
|
|
||||||
|
if (calcX.length == 1 || calcX[1].equals("none"))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (calcX[0].startsWith("Count"))
|
||||||
|
{
|
||||||
|
return CardFactoryUtil.xCount(AF.getHostCard(), calcX[1]);
|
||||||
|
}
|
||||||
|
else if (calcX[0].startsWith("Sacrificed"))
|
||||||
|
{
|
||||||
|
return CardFactoryUtil.handlePaid(saMe.getSacrificedCost(), calcX[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldTgtP(int d) {
|
||||||
|
PlayerZone compHand = AllZone.getZone(Constant.Zone.Hand, AllZone.ComputerPlayer);
|
||||||
|
CardList hand = new CardList(compHand.getCards());
|
||||||
|
|
||||||
|
if(AF.isSpell() && hand.size() > 7) // anti-discard-at-EOT
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(AllZone.HumanPlayer.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, AllZone.ComputerPlayer);
|
||||||
|
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, AllZone.HumanPlayer);
|
||||||
|
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 best;
|
return null;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean doCanPlayAI(SpellAbility saMe)
|
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;
|
|
||||||
|
|
||||||
// TODO handle proper calculation of X values based on Cost
|
|
||||||
int damage = getNumDamage(saMe);
|
|
||||||
|
|
||||||
boolean rr = AF.isSpell();
|
|
||||||
|
|
||||||
if (AF.isAbility())
|
|
||||||
{
|
{
|
||||||
Random r = new Random(); // prevent run-away activations
|
// temporarily disabled until better AI
|
||||||
if(r.nextFloat() <= Math.pow(.6667, AF.getHostCard().getAbilityUsed()))
|
if (AF.getAbCost().getSacCost()) return false;
|
||||||
rr = true;
|
if (AF.getAbCost().getSubCounter()) return false;
|
||||||
|
if (AF.getAbCost().getLifeCost()) return false;
|
||||||
|
|
||||||
|
if (!ComputerUtil.canPayCost(saMe))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// TODO handle proper calculation of X values based on Cost
|
||||||
|
int damage = getNumDamage(saMe);
|
||||||
|
|
||||||
|
boolean rr = AF.isSpell();
|
||||||
|
|
||||||
|
if (AF.isAbility())
|
||||||
|
{
|
||||||
|
Random r = new Random(); // prevent run-away activations
|
||||||
|
if(r.nextFloat() <= Math.pow(.6667, AF.getHostCard().getAbilityUsed()))
|
||||||
|
rr = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Target tgt = AF.getAbTgt();
|
||||||
|
// AI handle multi-targeting?
|
||||||
|
tgt.resetTargets();
|
||||||
|
// target loop
|
||||||
|
while(tgt.getNumTargeted() < tgt.getMaxTargets()){
|
||||||
|
// TODO: Consider targeting the planeswalker
|
||||||
|
if(tgt.canTgtCreatureAndPlayer()) {
|
||||||
|
|
||||||
|
if(shouldTgtP(damage)) {
|
||||||
|
tgt.addTarget(AllZone.HumanPlayer);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Card c = chooseTgtC(damage);
|
||||||
|
if(c != null) {
|
||||||
|
tgt.addTarget(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tgt.canTgtPlayer() || TgtOpp) {
|
||||||
|
tgt.addTarget(AllZone.HumanPlayer);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tgt.canTgtCreature()) {
|
||||||
|
Card c = chooseTgtC(damage);
|
||||||
|
if(c != null) {
|
||||||
|
tgt.addTarget(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// fell through all the choices, no targets left?
|
||||||
|
if (tgt.getNumTargeted() < tgt.getMinTargets() || tgt.getNumTargeted() == 0){
|
||||||
|
tgt.resetTargets();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// todo is this good enough? for up to amounts?
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Target tgt = AF.getAbTgt();
|
private String damageStackDescription(AbilityFactory af, SpellAbility sa){
|
||||||
// AI handle multi-targeting?
|
// when damageStackDescription is called, just build exactly what is happening
|
||||||
tgt.resetTargets();
|
StringBuilder sb = new StringBuilder();
|
||||||
// target loop
|
String name = af.getHostCard().getName();
|
||||||
while(tgt.getNumTargeted() < tgt.getMaxTargets()){
|
int damage = getNumDamage(sa);
|
||||||
// TODO: Consider targeting the planeswalker
|
|
||||||
if(tgt.canTgtCreatureAndPlayer()) {
|
|
||||||
|
|
||||||
if(shouldTgtP(damage)) {
|
ArrayList<Object> tgts = findTargets(sa);
|
||||||
tgt.addTarget(AllZone.HumanPlayer);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Card c = chooseTgtC(damage);
|
if (!(sa instanceof Ability_Sub))
|
||||||
if(c != null) {
|
sb.append(name).append(" - ");
|
||||||
tgt.addTarget(c);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(tgt.canTgtPlayer() || TgtOpp) {
|
sb.append("Deals ").append(damage).append(" damage to ");
|
||||||
tgt.addTarget(AllZone.HumanPlayer);
|
for(int i = 0; i < tgts.size(); i++){
|
||||||
continue;
|
if (i != 0)
|
||||||
}
|
sb.append(" ");
|
||||||
|
|
||||||
if(tgt.canTgtCreature()) {
|
Object o = tgts.get(0);
|
||||||
Card c = chooseTgtC(damage);
|
if (o instanceof Player){
|
||||||
if(c != null) {
|
sb.append(((Player)o).getName());
|
||||||
tgt.addTarget(c);
|
}
|
||||||
continue;
|
else{
|
||||||
}
|
sb.append(((Card)o).getName());
|
||||||
}
|
}
|
||||||
// fell through all the choices, no targets left?
|
|
||||||
if (tgt.getNumTargeted() < tgt.getMinTargets() || tgt.getNumTargeted() == 0){
|
|
||||||
tgt.resetTargets();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
// todo is this good enough? for up to amounts?
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rr;
|
}
|
||||||
|
sb.append(". ");
|
||||||
|
|
||||||
|
if (hasSubAbAF){
|
||||||
|
subAbAF.setParent(sa);
|
||||||
|
sb.append(subAbAF.getStackDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<Object> findTargets(SpellAbility saMe){
|
||||||
|
Target tgt = AF.getAbTgt();
|
||||||
|
ArrayList<Object> tgts;
|
||||||
|
if (tgt != null)
|
||||||
|
tgts = tgt.getTargets();
|
||||||
|
else{
|
||||||
|
tgts = new ArrayList<Object>();
|
||||||
|
if (TgtOpp){
|
||||||
|
tgts.add(saMe.getActivatingPlayer().getOpponent());
|
||||||
|
}
|
||||||
|
else if (AF.getMapParams().containsKey("Affected")){
|
||||||
|
String affected = AF.getMapParams().get("Affected");
|
||||||
|
if (affected.equals("You"))
|
||||||
|
tgts.add(saMe.getActivatingPlayer());
|
||||||
|
else if (affected.equals("Self"))
|
||||||
|
tgts.add(saMe.getSourceCard());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tgts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doResolve(SpellAbility saMe)
|
||||||
|
{
|
||||||
|
int damage = getNumDamage(saMe);
|
||||||
|
|
||||||
|
ArrayList<Object> tgts = findTargets(saMe);
|
||||||
|
boolean targeted = (AF.getAbTgt() != null) || TgtOpp;
|
||||||
|
|
||||||
|
if (tgts == null || tgts.size() == 0){
|
||||||
|
System.out.println("No targets?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Object o : tgts){
|
||||||
|
if (o instanceof Card){
|
||||||
|
Card c = (Card)o;
|
||||||
|
if(AllZone.GameAction.isCardInPlay(c) && (!targeted || CardFactoryUtil.canTarget(AF.getHostCard(), c)))
|
||||||
|
c.addDamage(damage, AF.getHostCard());
|
||||||
|
}
|
||||||
|
else if (o instanceof Player){
|
||||||
|
Player p = (Player) o;
|
||||||
|
if (!targeted || p.canTarget(AF.getHostCard()))
|
||||||
|
p.addDamage(damage, AF.getHostCard());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasSubAbAF) {
|
||||||
|
if (subAbAF.getParent() == null)
|
||||||
|
subAbAF.setParent(saMe);
|
||||||
|
subAbAF.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (hasSubAbStr){
|
||||||
|
Object obj = tgts.get(0);
|
||||||
|
|
||||||
|
Player pl = null;
|
||||||
|
Card c = null;
|
||||||
|
|
||||||
|
if (obj instanceof Card){
|
||||||
|
c = (Card)obj;
|
||||||
|
pl = c.getController();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
pl = (Player)obj;
|
||||||
|
}
|
||||||
|
CardFactoryUtil.doDrawBack(subAbStr, damage, AF.getHostCard().getController(),
|
||||||
|
AF.getHostCard().getController().getOpponent(), pl, AF.getHostCard(), c, saMe);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String damageStackDescription(AbilityFactory af, SpellAbility sa){
|
|
||||||
// when damageStackDescription is called, just build exactly what is happening
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
String name = af.getHostCard().getName();
|
|
||||||
int damage = getNumDamage(sa);
|
|
||||||
|
|
||||||
ArrayList<Object> tgts;
|
|
||||||
Target tgt = AF.getAbTgt();
|
|
||||||
if (tgt != null)
|
|
||||||
tgts = tgt.getTargets();
|
|
||||||
else{
|
|
||||||
tgts = new ArrayList<Object>();
|
|
||||||
if (TgtOpp)
|
|
||||||
tgts.add(AF.getHostCard().getController().getOpponent());
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.append(name).append(" - ");
|
|
||||||
sb.append("Deals ").append(damage).append(" damage to ");
|
|
||||||
for(int i = 0; i < tgts.size(); i++){
|
|
||||||
Object o = tgts.get(0);
|
|
||||||
if (o instanceof Player){
|
|
||||||
sb.append(((Player)o).getName());
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
sb.append(((Card)o).getName());
|
|
||||||
}
|
|
||||||
sb.append(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doResolve(SpellAbility saMe)
|
|
||||||
{
|
|
||||||
int damage = getNumDamage(saMe);
|
|
||||||
|
|
||||||
ArrayList<Object> tgts;
|
|
||||||
Target tgt = AF.getAbTgt();
|
|
||||||
if (tgt != null)
|
|
||||||
tgts = tgt.getTargets();
|
|
||||||
else{
|
|
||||||
tgts = new ArrayList<Object>();
|
|
||||||
if (TgtOpp)
|
|
||||||
tgts.add(AF.getHostCard().getController().getOpponent());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tgts.size() == 0){
|
|
||||||
System.out.println("No targets?");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(Object o : tgts){
|
|
||||||
if (o instanceof Card){
|
|
||||||
Card c = (Card)o;
|
|
||||||
if(AllZone.GameAction.isCardInPlay(c) && CardFactoryUtil.canTarget(AF.getHostCard(), c))
|
|
||||||
c.addDamage(damage, AF.getHostCard());
|
|
||||||
}
|
|
||||||
else if (o instanceof Player){
|
|
||||||
Player p = (Player) o;
|
|
||||||
if (p.canTarget(AF.getHostCard()))
|
|
||||||
p.addDamage(damage, AF.getHostCard());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Object obj = tgts.get(0);
|
|
||||||
|
|
||||||
Player pl = null;
|
|
||||||
Card c = null;
|
|
||||||
|
|
||||||
if (obj instanceof Card){
|
|
||||||
c = (Card)obj;
|
|
||||||
pl = c.getController();
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
pl = (Player)obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(AF.hasSubAbility())
|
|
||||||
CardFactoryUtil.doDrawBack(AF.getMapParams().get("SubAbility"), damage,
|
|
||||||
AF.getHostCard().getController(), AF.getHostCard().getController().getOpponent(),
|
|
||||||
pl, AF.getHostCard(), c, saMe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -14,17 +14,7 @@ public class AbilityFactory_ZoneAffecting {
|
|||||||
@Override
|
@Override
|
||||||
public String getStackDescription(){
|
public String getStackDescription(){
|
||||||
// when getStackDesc is called, just build exactly what is happening
|
// when getStackDesc is called, just build exactly what is happening
|
||||||
Player player = af.getAbTgt() == null ? getActivatingPlayer() : getTargetPlayer();
|
return drawStackDescription(af, this);
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
sb.append(getSourceCard().getName());
|
|
||||||
sb.append(" - ");
|
|
||||||
sb.append(player.toString());
|
|
||||||
sb.append(" draws (");
|
|
||||||
sb.append(af.getMapParams().get("NumCards"));
|
|
||||||
sb.append(")");
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canPlay(){
|
public boolean canPlay(){
|
||||||
@@ -55,17 +45,7 @@ public class AbilityFactory_ZoneAffecting {
|
|||||||
@Override
|
@Override
|
||||||
public String getStackDescription(){
|
public String getStackDescription(){
|
||||||
// when getStackDesc is called, just build exactly what is happening
|
// when getStackDesc is called, just build exactly what is happening
|
||||||
Player player = af.getAbTgt() == null ? getActivatingPlayer() : getTargetPlayer();
|
return drawStackDescription(af, this);
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
sb.append(getSourceCard().getName());
|
|
||||||
sb.append(" - ");
|
|
||||||
sb.append(player.toString());
|
|
||||||
sb.append(" draws (");
|
|
||||||
sb.append(af.getMapParams().get("NumCards"));
|
|
||||||
sb.append(")");
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canPlay(){
|
public boolean canPlay(){
|
||||||
@@ -87,6 +67,56 @@ public class AbilityFactory_ZoneAffecting {
|
|||||||
return spDraw;
|
return spDraw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SpellAbility createDrawbackDraw(final AbilityFactory AF){
|
||||||
|
final SpellAbility dbDraw = new Ability_Sub(AF.getHostCard(), AF.getAbTgt()){
|
||||||
|
private static final long serialVersionUID = -4990932993654533449L;
|
||||||
|
|
||||||
|
final AbilityFactory af = AF;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getStackDescription(){
|
||||||
|
// when getStackDesc is called, just build exactly what is happening
|
||||||
|
return drawStackDescription(af, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolve() {
|
||||||
|
drawResolve(af, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean chkAI_Drawback() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
return dbDraw;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String drawStackDescription(AbilityFactory af, SpellAbility sa){
|
||||||
|
Player player = af.getAbTgt() == null ? sa.getActivatingPlayer() : sa.getTargetPlayer();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
if (!(sa instanceof Ability_Sub))
|
||||||
|
sb.append(sa.getSourceCard().getName()).append(" - ");
|
||||||
|
else
|
||||||
|
sb.append(" ");
|
||||||
|
|
||||||
|
sb.append(player.toString());
|
||||||
|
sb.append(" draws (");
|
||||||
|
sb.append(af.getMapParams().get("NumCards"));
|
||||||
|
sb.append(").");
|
||||||
|
|
||||||
|
Ability_Sub abSub = sa.getSubAbility();
|
||||||
|
if (abSub != null){
|
||||||
|
abSub.setParent(sa);
|
||||||
|
sb.append(abSub.getStackDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean drawCanPlayAI(final AbilityFactory af, SpellAbility sa){
|
public static boolean drawCanPlayAI(final AbilityFactory af, SpellAbility sa){
|
||||||
// AI cannot use this properly until he can use SAs during Humans turn
|
// AI cannot use this properly until he can use SAs during Humans turn
|
||||||
if (!ComputerUtil.canPayCost(sa))
|
if (!ComputerUtil.canPayCost(sa))
|
||||||
@@ -161,13 +191,28 @@ public class AbilityFactory_ZoneAffecting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(Player p : tgtPlayers)
|
for(Player p : tgtPlayers)
|
||||||
if (tgt == null || p.canTarget(af.getHostCard()))
|
if (tgt == null || p.canTarget(af.getHostCard())){
|
||||||
p.drawCards(numCards);
|
if (params.containsKey("NextUpkeep"))
|
||||||
|
for(int i = 0; i < numCards; i++)
|
||||||
|
p.addSlowtripList(source);
|
||||||
|
else
|
||||||
|
p.drawCards(numCards);
|
||||||
|
|
||||||
String DrawBack = params.get("SubAbility");
|
}
|
||||||
if (af.hasSubAbility())
|
|
||||||
CardFactoryUtil.doDrawBack(DrawBack, 0, source.getController(), source.getController().getOpponent(), source.getController(), source, null, sa);
|
|
||||||
|
|
||||||
|
if (af.hasSubAbility()){
|
||||||
|
Ability_Sub abSub = sa.getSubAbility();
|
||||||
|
if (abSub != null){
|
||||||
|
if (abSub.getParent() == null)
|
||||||
|
abSub.setParent(sa);
|
||||||
|
abSub.resolve();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
String DrawBack = params.get("SubAbility");
|
||||||
|
if (af.hasSubAbility())
|
||||||
|
CardFactoryUtil.doDrawBack(DrawBack, 0, source.getController(), source.getController().getOpponent(), source.getController(), source, null, sa);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -181,18 +226,7 @@ public class AbilityFactory_ZoneAffecting {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getStackDescription(){
|
public String getStackDescription(){
|
||||||
// when getStackDesc is called, just build exactly what is happening
|
return millStackDescription(this, af);
|
||||||
Player player = af.getAbTgt() == null ? getActivatingPlayer() : getTargetPlayer();
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
sb.append(getSourceCard().getName());
|
|
||||||
sb.append(" - Mills ");
|
|
||||||
sb.append(af.getMapParams().get("NumCards"));
|
|
||||||
sb.append(" Cards from ");
|
|
||||||
sb.append(player.toString());
|
|
||||||
sb.append("'s library.");
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canPlay(){
|
public boolean canPlay(){
|
||||||
@@ -220,6 +254,11 @@ public class AbilityFactory_ZoneAffecting {
|
|||||||
|
|
||||||
final AbilityFactory af = AF;
|
final AbilityFactory af = AF;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getStackDescription(){
|
||||||
|
return millStackDescription(this, af);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean canPlay(){
|
public boolean canPlay(){
|
||||||
// super takes care of AdditionalCosts
|
// super takes care of AdditionalCosts
|
||||||
return super.canPlay();
|
return super.canPlay();
|
||||||
@@ -239,6 +278,61 @@ public class AbilityFactory_ZoneAffecting {
|
|||||||
return spMill;
|
return spMill;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SpellAbility createDrawbackMill(final AbilityFactory AF){
|
||||||
|
final SpellAbility dbMill = new Ability_Sub(AF.getHostCard(), AF.getAbTgt()){
|
||||||
|
private static final long serialVersionUID = -4990932993654533449L;
|
||||||
|
|
||||||
|
final AbilityFactory af = AF;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getStackDescription(){
|
||||||
|
return millStackDescription(this, af);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canPlayAI()
|
||||||
|
{
|
||||||
|
return millCanPlayAI(af, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolve() {
|
||||||
|
millResolve(af, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean chkAI_Drawback() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
return dbMill;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String millStackDescription(SpellAbility sa, AbilityFactory af){
|
||||||
|
// when getStackDesc is called, just build exactly what is happening
|
||||||
|
Player player = af.getAbTgt() == null ? sa.getActivatingPlayer() : sa.getTargetPlayer();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
if (!(sa instanceof Ability_Sub))
|
||||||
|
sb.append(sa.getSourceCard().getName()).append(" - ");
|
||||||
|
else
|
||||||
|
sb.append(" ");
|
||||||
|
|
||||||
|
sb.append("Mills ");
|
||||||
|
sb.append(af.getMapParams().get("NumCards"));
|
||||||
|
sb.append(" Card(s) from ");
|
||||||
|
sb.append(player.toString());
|
||||||
|
sb.append("'s library.");
|
||||||
|
|
||||||
|
Ability_Sub abSub = sa.getSubAbility();
|
||||||
|
if (abSub != null){
|
||||||
|
abSub.setParent(sa);
|
||||||
|
sb.append(abSub.getStackDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean millCanPlayAI(final AbilityFactory af, SpellAbility sa){
|
public static boolean millCanPlayAI(final AbilityFactory af, SpellAbility sa){
|
||||||
// AI cannot use this properly until he can use SAs during Humans turn
|
// AI cannot use this properly until he can use SAs during Humans turn
|
||||||
if (!ComputerUtil.canPayCost(sa))
|
if (!ComputerUtil.canPayCost(sa))
|
||||||
@@ -304,6 +398,7 @@ public class AbilityFactory_ZoneAffecting {
|
|||||||
HashMap<String,String> params = af.getMapParams();
|
HashMap<String,String> params = af.getMapParams();
|
||||||
|
|
||||||
Card source = sa.getSourceCard();
|
Card source = sa.getSourceCard();
|
||||||
|
// todo: handle deciding what X would be around here for Psychic Drain type cards
|
||||||
int numCards = Integer.parseInt(params.get("NumCards"));
|
int numCards = Integer.parseInt(params.get("NumCards"));
|
||||||
|
|
||||||
ArrayList<Player> tgtPlayers;
|
ArrayList<Player> tgtPlayers;
|
||||||
@@ -320,9 +415,18 @@ public class AbilityFactory_ZoneAffecting {
|
|||||||
if (tgt == null || p.canTarget(af.getHostCard()))
|
if (tgt == null || p.canTarget(af.getHostCard()))
|
||||||
p.mill(numCards);
|
p.mill(numCards);
|
||||||
|
|
||||||
String DrawBack = params.get("SubAbility");
|
if (af.hasSubAbility()){
|
||||||
if (af.hasSubAbility())
|
Ability_Sub abSub = sa.getSubAbility();
|
||||||
CardFactoryUtil.doDrawBack(DrawBack, 0, source.getController(), source.getController().getOpponent(), tgtPlayers.get(0), source, null, sa);
|
if (abSub != null){
|
||||||
|
if (abSub.getParent() == null)
|
||||||
|
abSub.setParent(sa);
|
||||||
|
abSub.resolve();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
String DrawBack = params.get("SubAbility");
|
||||||
|
if (af.hasSubAbility())
|
||||||
|
CardFactoryUtil.doDrawBack(DrawBack, 0, source.getController(), source.getController().getOpponent(), tgtPlayers.get(0), source, null, sa);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
29
src/forge/Ability_Sub.java
Normal file
29
src/forge/Ability_Sub.java
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package forge;
|
||||||
|
|
||||||
|
abstract public class Ability_Sub extends SpellAbility implements java.io.Serializable {
|
||||||
|
private static final long serialVersionUID = 4650634415821733134L;
|
||||||
|
|
||||||
|
private SpellAbility parent = null;
|
||||||
|
|
||||||
|
public Ability_Sub(Card sourceCard, Target tgt) {
|
||||||
|
super(SpellAbility.Ability, sourceCard);
|
||||||
|
setTarget(tgt);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPlay() {
|
||||||
|
// this should never be on the Stack by itself
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public boolean chkAI_Drawback();
|
||||||
|
|
||||||
|
public void setParent(SpellAbility parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.setActivatingPlayer(parent.getActivatingPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpellAbility getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -440,32 +440,7 @@ public class MagicStack extends MyObservable {
|
|||||||
|
|
||||||
AllZone.Phase.resetPriority(); // ActivePlayer gains priority first after Resolve
|
AllZone.Phase.resetPriority(); // ActivePlayer gains priority first after Resolve
|
||||||
Card source = sa.getSourceCard();
|
Card source = sa.getSourceCard();
|
||||||
boolean fizzle = false;
|
boolean fizzle = hasFizzled(sa, source);
|
||||||
|
|
||||||
Target tgt = sa.getTarget();
|
|
||||||
if (tgt != null){
|
|
||||||
fizzle = true;
|
|
||||||
// With multi-targets, as long as one target is still legal, we'll try to go through as much as possible
|
|
||||||
ArrayList<Object> tgts = tgt.getTargets();
|
|
||||||
for(Object o : tgts){
|
|
||||||
if (o instanceof Player){
|
|
||||||
Player p = (Player)o;
|
|
||||||
fizzle &= !(p.canTarget(sa.getTargetCard()));
|
|
||||||
}
|
|
||||||
if (o instanceof Card){
|
|
||||||
Card card = (Card)o;
|
|
||||||
fizzle &= !(CardFactoryUtil.isTargetStillValid(sa, card));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (sa.getTargetCard() != null) {
|
|
||||||
// Fizzling will only work for Abilities that use the Target class,
|
|
||||||
// since the info isn't available otherwise
|
|
||||||
fizzle = !CardFactoryUtil.isTargetStillValid(sa, sa.getTargetCard());
|
|
||||||
}
|
|
||||||
else if (sa.getTargetPlayer() != null) {
|
|
||||||
fizzle = !sa.getTargetPlayer().canTarget(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fizzle) {
|
if (!fizzle) {
|
||||||
final Card crd = source;
|
final Card crd = source;
|
||||||
@@ -546,6 +521,42 @@ public class MagicStack extends MyObservable {
|
|||||||
GuiDisplayUtil.updateGUI();
|
GuiDisplayUtil.updateGUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasFizzled(SpellAbility sa, Card source){
|
||||||
|
boolean fizzle = false;
|
||||||
|
|
||||||
|
Target tgt = sa.getTarget();
|
||||||
|
if (tgt != null){
|
||||||
|
fizzle = true;
|
||||||
|
// With multi-targets, as long as one target is still legal, we'll try to go through as much as possible
|
||||||
|
ArrayList<Object> tgts = tgt.getTargets();
|
||||||
|
for(Object o : tgts){
|
||||||
|
if (o instanceof Player){
|
||||||
|
Player p = (Player)o;
|
||||||
|
fizzle &= !(p.canTarget(sa.getTargetCard()));
|
||||||
|
}
|
||||||
|
if (o instanceof Card){
|
||||||
|
Card card = (Card)o;
|
||||||
|
fizzle &= !(CardFactoryUtil.isTargetStillValid(sa, card));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (sa.getTargetCard() != null) {
|
||||||
|
// Fizzling will only work for Abilities that use the Target class,
|
||||||
|
// since the info isn't available otherwise
|
||||||
|
fizzle = !CardFactoryUtil.isTargetStillValid(sa, sa.getTargetCard());
|
||||||
|
}
|
||||||
|
else if (sa.getTargetPlayer() != null) {
|
||||||
|
fizzle = !sa.getTargetPlayer().canTarget(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ability_Sub abSub = sa.getSubAbility();
|
||||||
|
if (abSub != null)
|
||||||
|
fizzle &= hasFizzled(abSub, source);
|
||||||
|
|
||||||
|
return fizzle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public SpellAbility pop() {
|
public SpellAbility pop() {
|
||||||
SpellAbility sp = (SpellAbility) stack.remove(0);
|
SpellAbility sp = (SpellAbility) stack.remove(0);
|
||||||
this.updateObservers();
|
this.updateObservers();
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ public abstract class SpellAbility {
|
|||||||
protected Target chosenTarget = null;
|
protected Target chosenTarget = null;
|
||||||
|
|
||||||
private SpellAbility_Restriction restrictions = new SpellAbility_Restriction();
|
private SpellAbility_Restriction restrictions = new SpellAbility_Restriction();
|
||||||
|
private Ability_Sub subAbility = null;
|
||||||
|
|
||||||
private CardList sacrificedCards = null;
|
private CardList sacrificedCards = null;
|
||||||
|
|
||||||
@@ -322,6 +323,14 @@ public abstract class SpellAbility {
|
|||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSubAbility(Ability_Sub subAbility) {
|
||||||
|
this.subAbility = subAbility;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Ability_Sub getSubAbility() {
|
||||||
|
return this.subAbility;
|
||||||
|
}
|
||||||
|
|
||||||
public Card getTargetCard() {
|
public Card getTargetCard() {
|
||||||
if(targetCard == null){
|
if(targetCard == null){
|
||||||
Target tgt = this.getTarget();
|
Target tgt = this.getTarget();
|
||||||
|
|||||||
@@ -28,13 +28,14 @@ public class SpellAbility_Requirements {
|
|||||||
// freeze Stack. No abilities should go onto the stack while I'm filling requirements.
|
// freeze Stack. No abilities should go onto the stack while I'm filling requirements.
|
||||||
AllZone.Stack.freezeStack();
|
AllZone.Stack.freezeStack();
|
||||||
|
|
||||||
if (select.doesTarget()){
|
// Skip to paying if parent ability doesn't target and has no subAbilities.
|
||||||
|
if (!select.doesTarget() && ability.getSubAbility() == null)
|
||||||
|
startPaying();
|
||||||
|
else{
|
||||||
select.setRequirements(this);
|
select.setRequirements(this);
|
||||||
select.resetTargets();
|
select.resetTargets();
|
||||||
select.chooseTargets();
|
select.chooseTargets();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
startPaying();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finishedTargeting(){
|
public void finishedTargeting(){
|
||||||
|
|||||||
@@ -47,9 +47,23 @@ public class Target_Selection {
|
|||||||
req.finishedTargeting();
|
req.finishedTargeting();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (bDoneTarget && target.isMinTargetsChosen() || target.isMaxTargetsChosen()){
|
else if (!doesTarget() || bDoneTarget && target.isMinTargetsChosen() || target.isMaxTargetsChosen()){
|
||||||
req.finishedTargeting();
|
Ability_Sub abSub = ability.getSubAbility();
|
||||||
return true;
|
|
||||||
|
if (abSub == null){
|
||||||
|
// if no more SubAbilities finish targeting
|
||||||
|
req.finishedTargeting();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// Has Sub Ability
|
||||||
|
Target_Selection ts = new Target_Selection(abSub.getTarget(), abSub);
|
||||||
|
ts.setRequirements(req);
|
||||||
|
ts.resetTargets();
|
||||||
|
boolean flag = ts.chooseTargets();
|
||||||
|
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//targets still needed
|
//targets still needed
|
||||||
|
|||||||
Reference in New Issue
Block a user