- Added AF_Drawback for Pump, Fog, Untap, Tap

This commit is contained in:
jendave
2011-08-06 12:42:08 +00:00
parent 86e090b84a
commit db1bc32856
5 changed files with 401 additions and 143 deletions

View File

@@ -212,6 +212,7 @@ public class AbilityFactory {
SA = AbilityFactory_Counters.createDrawbackProliferate(this);
}
// do we want to merge Fetch, Retrieve and Bounce into ChangeZone?
if (API.equals("Fetch")){
if (isAb)
SA = AbilityFactory_Fetch.createAbilityFetch(this);
@@ -226,6 +227,15 @@ public class AbilityFactory {
SA = AbilityFactory_Fetch.createSpellRetrieve(this);
}
if (API.equals("Bounce")){
if (isAb)
SA = AbilityFactory_Bounce.createAbilityBounce(this);
else if (isSp)
SA = AbilityFactory_Bounce.createSpellBounce(this);
hostCard.setSVar("PlayMain1", "TRUE");
}
// Above to be merged? If so, merge then do SubAbility for each
if (API.equals("Pump"))
{
AbilityFactory_Pump afPump = new AbilityFactory_Pump(this);
@@ -234,8 +244,11 @@ public class AbilityFactory {
SA = afPump.getAbility();
else if (isSp)
SA = afPump.getSpell();
else if (isDb)
SA = afPump.getDrawback();
hostCard.setSVar("PlayMain1", "TRUE");
if (isAb || isSp)
hostCard.setSVar("PlayMain1", "TRUE");
}
if (API.equals("GainLife")){
@@ -261,14 +274,8 @@ public class AbilityFactory {
SA = AbilityFactory_Combat.createAbilityFog(this);
else if (isSp)
SA = AbilityFactory_Combat.createSpellFog(this);
}
if (API.equals("Bounce")){
if (isAb)
SA = AbilityFactory_Bounce.createAbilityBounce(this);
else if (isSp)
SA = AbilityFactory_Bounce.createSpellBounce(this);
hostCard.setSVar("PlayMain1", "TRUE");
else if (isDb)
SA = AbilityFactory_Combat.createDrawbackFog(this);
}
if (API.equals("Untap")){
@@ -276,6 +283,8 @@ public class AbilityFactory {
SA = AbilityFactory_PermanentState.createAbilityUntap(this);
else if (isSp)
SA = AbilityFactory_PermanentState.createSpellUntap(this);
else if (isDb)
SA = AbilityFactory_PermanentState.createDrawbackUntap(this);
}
if (API.equals("Tap")){
@@ -283,6 +292,8 @@ public class AbilityFactory {
SA = AbilityFactory_PermanentState.createAbilityTap(this);
else if (isSp)
SA = AbilityFactory_PermanentState.createSpellTap(this);
else if (isDb)
SA = AbilityFactory_PermanentState.createDrawbackTap(this);
}
if (API.equals("Regenerate")){

View File

@@ -9,19 +9,14 @@ public class AbilityFactory_Combat {
final AbilityFactory af = AF;
public boolean canPlay(){
// super takes care of AdditionalCosts
return super.canPlay();
}
public boolean canPlayAI()
{
return putCanPlayAI(af, this);
return fogCanPlayAI(af, this);
}
@Override
public void resolve() {
putResolve(af, this);
fogResolve(af, this);
}
};
@@ -34,28 +29,48 @@ public class AbilityFactory_Combat {
final AbilityFactory af = AF;
public boolean canPlay(){
// super takes care of AdditionalCosts
return super.canPlay();
}
public boolean canPlayAI()
{
return putCanPlayAI(af, this);
return fogCanPlayAI(af, this);
}
@Override
public void resolve() {
putResolve(af, this);
fogResolve(af, this);
}
};
return spFog;
}
public static boolean putCanPlayAI(final AbilityFactory af, SpellAbility sa){
// AI cannot use this properly until he can use SAs during Humans turn
boolean chance = false;
public static SpellAbility createDrawbackFog(final AbilityFactory AF){
final SpellAbility dbFog = new Ability_Sub(AF.getHostCard(), AF.getAbTgt()){
private static final long serialVersionUID = -5141246507533353605L;
final AbilityFactory af = AF;
@Override
public void resolve() {
fogResolve(af, this);
}
@Override
public boolean chkAI_Drawback() {
return fogCanPlayAI(af, this);
}
};
return dbFog;
}
public static boolean fogCanPlayAI(final AbilityFactory af, SpellAbility sa){
// AI should only activate this during Human's Declare Blockers phase
boolean chance = AllZone.Phase.is(Constant.Phase.Combat_Declare_Blockers_InstantAbility, sa.getActivatingPlayer().getOpponent());
// Only cast when Stack is empty, so Human uses spells/abilities first
chance &= AllZone.Stack.size() == 0;
// Some additional checks on how much Damage/Poison AI would take, or how many creatures would be lost
Ability_Sub subAb = sa.getSubAbility();
if (subAb != null)
@@ -64,7 +79,19 @@ public class AbilityFactory_Combat {
return chance;
}
public static void putResolve(final AbilityFactory af, final SpellAbility sa){
public static boolean fogPlayDrawbackAI(final AbilityFactory af, SpellAbility sa){
// AI should only activate this during Human's turn
boolean chance = AllZone.Phase.isPlayerTurn(sa.getActivatingPlayer().getOpponent()) ||
AllZone.Phase.isAfter(Constant.Phase.Combat_Damage);
Ability_Sub subAb = sa.getSubAbility();
if (subAb != null)
chance &= subAb.chkAI_Drawback();
return chance;
}
public static void fogResolve(final AbilityFactory af, final SpellAbility sa){
HashMap<String,String> params = af.getMapParams();
Card card = sa.getSourceCard();
String DrawBack = params.get("SubAbility");

View File

@@ -17,11 +17,6 @@ public class AbilityFactory_PermanentState {
return untapStackDescription(af, this);
}
public boolean canPlay(){
// super takes care of AdditionalCosts
return super.canPlay();
}
public boolean canPlayAI()
{
return untapCanPlayAI(af,this);
@@ -46,12 +41,7 @@ public class AbilityFactory_PermanentState {
public String getStackDescription(){
return untapStackDescription(af, this);
}
public boolean canPlay(){
// super takes care of AdditionalCosts
return super.canPlay();
}
public boolean canPlayAI()
{
return untapCanPlayAI(af, this);
@@ -66,11 +56,39 @@ public class AbilityFactory_PermanentState {
return spUntap;
}
public static SpellAbility createDrawbackUntap(final AbilityFactory AF){
final SpellAbility dbUntap = new Ability_Sub(AF.getHostCard(), AF.getAbTgt()){
private static final long serialVersionUID = -4990932993654533449L;
final AbilityFactory af = AF;
@Override
public String getStackDescription(){
return untapStackDescription(af, this);
}
@Override
public void resolve() {
untapResolve(af, this);
}
@Override
public boolean chkAI_Drawback() {
return untapPlayDrawbackAI(af, this);
}
};
return dbUntap;
}
public static String untapStackDescription(AbilityFactory af, SpellAbility sa){
// when getStackDesc is called, just build exactly what is happening
StringBuilder sb = new StringBuilder();
sb.append(sa.getSourceCard()).append(" - ");
if (sa instanceof Ability_Sub)
sb.append(" ");
else
sb.append(sa.getSourceCard()).append(" - ");
sb.append("Untap ");
@@ -161,6 +179,69 @@ public class AbilityFactory_PermanentState {
return randomReturn;
}
public static boolean untapPlayDrawbackAI(final AbilityFactory af, SpellAbility sa){
// AI cannot use this properly until he can use SAs during Humans turn
Target tgt = af.getAbTgt();
Card source = sa.getSourceCard();
boolean randomReturn = true;
if (tgt == null){
// who cares if its already untapped, it's only a subability?
}
else{
CardList untapList = AllZoneUtil.getPlayerCardsInPlay(AllZone.ComputerPlayer);
untapList = untapList.filter(AllZoneUtil.tapped);
untapList = untapList.getValidCards(tgt.getValidTgts(), source.getController(), source);
// filter out enchantments and planeswalkers, their tapped state doesn't matter.
String[] tappablePermanents = {"Creature", "Land", "Artifact"};
untapList = untapList.getValidCards(tappablePermanents, source.getController(), source);
if (untapList.size() == 0)
return false;
while(tgt.getNumTargeted() < tgt.getMaxTargets(sa.getSourceCard(), sa)){
Card choice = null;
if (untapList.size() == 0){
if (tgt.getNumTargeted() < tgt.getMinTargets(sa.getSourceCard(), sa) || tgt.getNumTargeted() == 0){
tgt.resetTargets();
return false;
}
else{
// todo is this good enough? for up to amounts?
break;
}
}
if (untapList.getNotType("Creature").size() == 0)
choice = CardFactoryUtil.AI_getBestCreature(untapList); //if only creatures take the best
else
choice = CardFactoryUtil.AI_getMostExpensivePermanent(untapList, af.getHostCard(), false);
if (choice == null){ // can't find anything left
if (tgt.getNumTargeted() < tgt.getMinTargets(sa.getSourceCard(), sa) || tgt.getNumTargeted() == 0){
tgt.resetTargets();
return false;
}
else{
// todo is this good enough? for up to amounts?
break;
}
}
untapList.remove(choice);
tgt.addTarget(choice);
}
}
Ability_Sub subAb = sa.getSubAbility();
if (subAb != null)
randomReturn &= subAb.chkAI_Drawback();
return randomReturn;
}
public static void untapResolve(final AbilityFactory af, final SpellAbility sa){
HashMap<String,String> params = af.getMapParams();
Card card = sa.getSourceCard();
@@ -192,8 +273,10 @@ public class AbilityFactory_PermanentState {
}
}
}
// ****************************************
// ************** Tapping *****************
// ****************************************
// ****** Tapping ********
public static SpellAbility createAbilityTap(final AbilityFactory AF){
final SpellAbility abTap = new Ability_Activated(AF.getHostCard(), AF.getAbCost(), AF.getAbTgt()){
private static final long serialVersionUID = 5445572699000471299L;
@@ -205,11 +288,6 @@ public class AbilityFactory_PermanentState {
return tapStackDescription(af, this);
}
public boolean canPlay(){
// super takes care of AdditionalCosts
return super.canPlay();
}
public boolean canPlayAI()
{
return tapCanPlayAI(af,this);
@@ -235,11 +313,6 @@ public class AbilityFactory_PermanentState {
return tapStackDescription(af, this);
}
public boolean canPlay(){
// super takes care of AdditionalCosts
return super.canPlay();
}
public boolean canPlayAI()
{
return tapCanPlayAI(af, this);
@@ -254,11 +327,39 @@ public class AbilityFactory_PermanentState {
return spTap;
}
public static SpellAbility createDrawbackTap(final AbilityFactory AF){
final SpellAbility dbTap = new Ability_Sub(AF.getHostCard(), AF.getAbTgt()){
private static final long serialVersionUID = -4990932993654533449L;
final AbilityFactory af = AF;
@Override
public String getStackDescription(){
return tapStackDescription(af, this);
}
@Override
public void resolve() {
tapResolve(af, this);
}
@Override
public boolean chkAI_Drawback() {
return tapPlayDrawbackAI(af, this);
}
};
return dbTap;
}
public static String tapStackDescription(AbilityFactory af, SpellAbility sa){
// when getStackDesc is called, just build exactly what is happening
StringBuilder sb = new StringBuilder();
sb.append(sa.getSourceCard()).append(" - ");
if (sa instanceof Ability_Sub)
sb.append(" ");
else
sb.append(sa.getSourceCard()).append(" - ");
sb.append("Tap ");
@@ -349,6 +450,70 @@ public class AbilityFactory_PermanentState {
return randomReturn;
}
public static boolean tapPlayDrawbackAI(final AbilityFactory af, SpellAbility sa){
// AI cannot use this properly until he can use SAs during Humans turn
Target tgt = af.getAbTgt();
Card source = sa.getSourceCard();
boolean randomReturn = true;
if (tgt == null){
// who cares if its already tapped, it's only a subability?
}
else{
// target section, maybe pull this out?
CardList tapList = AllZoneUtil.getPlayerCardsInPlay(AllZone.ComputerPlayer);
tapList = tapList.filter(AllZoneUtil.untapped);
tapList = tapList.getValidCards(tgt.getValidTgts(), source.getController(), source);
// filter out enchantments and planeswalkers, their tapped state doesn't matter.
String[] tappablePermanents = {"Creature", "Land", "Artifact"};
tapList = tapList.getValidCards(tappablePermanents, source.getController(), source);
if (tapList.size() == 0)
return false;
while(tgt.getNumTargeted() < tgt.getMaxTargets(sa.getSourceCard(), sa)){
Card choice = null;
if (tapList.size() == 0){
if (tgt.getNumTargeted() < tgt.getMinTargets(sa.getSourceCard(), sa) || tgt.getNumTargeted() == 0){
tgt.resetTargets();
return false;
}
else{
// todo is this good enough? for up to amounts?
break;
}
}
if (tapList.getNotType("Creature").size() == 0)
choice = CardFactoryUtil.AI_getBestCreature(tapList); //if only creatures take the best
else
choice = CardFactoryUtil.AI_getMostExpensivePermanent(tapList, af.getHostCard(), false);
if (choice == null){ // can't find anything left
if (tgt.getNumTargeted() < tgt.getMinTargets(sa.getSourceCard(), sa) || tgt.getNumTargeted() == 0){
tgt.resetTargets();
return false;
}
else{
// todo is this good enough? for up to amounts?
break;
}
}
tapList.remove(choice);
tgt.addTarget(choice);
}
}
Ability_Sub subAb = sa.getSubAbility();
if (subAb != null)
randomReturn &= subAb.chkAI_Drawback();
return randomReturn;
}
public static void tapResolve(final AbilityFactory af, final SpellAbility sa){
HashMap<String,String> params = af.getMapParams();
Card card = sa.getSourceCard();

View File

@@ -50,7 +50,7 @@ public class AbilityFactory_Pump {
private static final long serialVersionUID = 42244224L;
public boolean canPlayAI() {
return doTgtAI(this);
return pumpPlayAI(this);
}
@Override
@@ -73,69 +73,7 @@ public class AbilityFactory_Pump {
@Override
public boolean canPlayAI() {
if (!AllZone.GameAction.isCardInPlay(hostCard)) return false;
// temporarily disabled until AI is improved
if (AF.getAbCost().getSacCost()) return false;
if (AF.getAbCost().getLifeCost()) return false;
if (AF.getAbCost().getSubCounter()){
// instead of never removing counters, we will have a random possibility of failure.
// all the other tests still need to pass if a counter will be removed
Counters count = AF.getAbCost().getCounterType();
double chance = .66;
if (count.equals(Counters.P1P1)){ // 10% chance to remove +1/+1 to pump
chance = .1;
}
else if (count.equals(Counters.CHARGE)){ // 50% chance to remove +1/+1 to pump
chance = .5;
}
Random r = new Random();
if(r.nextFloat() > chance)
return false;
}
//if (bPumpEquipped && card.getEquippingCard() == null) return false;
if (!ComputerUtil.canPayCost(this))
return false;
//don't risk sacrificing a creature just to pump it
if(this.getRestrictions().getActivationNumberSacrifice() != -1 &&
this.getRestrictions().getNumberTurnActivations() >= (this.getRestrictions().getActivationNumberSacrifice() - 1)) {
return false;
}
int defense = getNumDefense(this);
if(AllZone.Phase.getPhase().equals(Constant.Phase.Main2)) return false;
if(AF.getAbTgt() == null || !AF.getAbTgt().doesTarget()) {
Card creature;
//if (bPumpEquipped)
// creature = card.getEquippingCard();
//else
creature = hostCard;
if((creature.getNetDefense() + defense > 0) && (!creature.hasAnyKeyword(Keywords))) {
if(creature.hasSickness() && Keywords.contains("Haste"))
return true;
else if (creature.hasSickness() ^ Keywords.contains("Haste"))
return false;
else {
Random r = new Random();
if(r.nextFloat() <= Math.pow(.6667, hostCard.getAbilityUsed()))
return CardFactoryUtil.AI_doesCreatureAttack(creature);
}
}
}
else
return doTgtAI(this);
return false;
}
@Override
public boolean canPlay() {
return super.canPlay();
return pumpPlayAI(this);
}
@Override
@@ -156,6 +94,33 @@ public class AbilityFactory_Pump {
return abPump;
}
public SpellAbility getDrawback()
{
SpellAbility dbPump = new Ability_Sub(hostCard, AF.getAbTgt()) {
private static final long serialVersionUID = 42244224L;
public boolean canPlayAI() {
return pumpPlayAI(this);
}
@Override
public String getStackDescription(){
return pumpStackDescription(AF, this);
}
public void resolve() {
doResolve(this);
}//resolve
@Override
public boolean chkAI_Drawback() {
return doDrawbackAI(this);
}
};//SpellAbility
return dbPump;
}
private int getNumAttack(SpellAbility sa) {
return AbilityFactory.calculateAmount(hostCard, numAttack, sa);
}
@@ -232,6 +197,69 @@ public class AbilityFactory_Pump {
return list;
}
private boolean pumpPlayAI(SpellAbility sa){
// if there is no target and host card isn't in play, don't activate
if (AF.getAbTgt() == null && !AllZone.GameAction.isCardInPlay(hostCard))
return false;
// temporarily disabled until AI is improved
if (AF.getAbCost().getSacCost()) return false;
if (AF.getAbCost().getLifeCost()) return false;
if (AF.getAbCost().getSubCounter()){
// instead of never removing counters, we will have a random possibility of failure.
// all the other tests still need to pass if a counter will be removed
Counters count = AF.getAbCost().getCounterType();
double chance = .66;
if (count.equals(Counters.P1P1)){ // 10% chance to remove +1/+1 to pump
chance = .1;
}
else if (count.equals(Counters.CHARGE)){ // 50% chance to remove +1/+1 to pump
chance = .5;
}
Random r = new Random();
if(r.nextFloat() > chance)
return false;
}
//if (bPumpEquipped && card.getEquippingCard() == null) return false;
if (!ComputerUtil.canPayCost(sa))
return false;
//don't risk sacrificing a creature just to pump it
if(sa.getRestrictions().getActivationNumberSacrifice() != -1 &&
sa.getRestrictions().getNumberTurnActivations() >= (sa.getRestrictions().getActivationNumberSacrifice() - 1)) {
return false;
}
int defense = getNumDefense(sa);
if(AllZone.Phase.is(Constant.Phase.Main2)) return false;
if(AF.getAbTgt() == null || !AF.getAbTgt().doesTarget()) {
Card creature;
//if (bPumpEquipped)
// creature = card.getEquippingCard();
//else
creature = hostCard;
if((creature.getNetDefense() + defense > 0) && (!creature.hasAnyKeyword(Keywords))) {
if(creature.hasSickness() && Keywords.contains("Haste"))
return true;
else if (creature.hasSickness() ^ Keywords.contains("Haste"))
return false;
else {
Random r = new Random();
if(r.nextFloat() <= Math.pow(.6667, hostCard.getAbilityUsed()))
return CardFactoryUtil.AI_doesCreatureAttack(creature);
}
}
}
else
return doTgtAI(sa);
return false;
}
private boolean doTgtAI(SpellAbility sa)
{
@@ -297,9 +325,25 @@ public class AbilityFactory_Pump {
}
return true;
}
private boolean doDrawbackAI(SpellAbility sa)
{
if(AF.getAbTgt() == null || !AF.getAbTgt().doesTarget()) {
int defense = getNumDefense(sa);
if (hostCard.isCreature()){
if (!hostCard.hasKeyword("Indestructible") && hostCard.getNetDefense() + defense <= hostCard.getDamage())
return false;
if (hostCard.getNetDefense() + defense <= 0)
return false;
}
}
else
return doTgtAI(sa);
return true;
}
private String pumpStackDescription(AbilityFactory af, SpellAbility sa){
// when damageStackDescription is called, just build exactly what is happening
StringBuilder sb = new StringBuilder();
@@ -313,8 +357,12 @@ public class AbilityFactory_Pump {
tgtCards = new ArrayList<Card>();
tgtCards.add(hostCard);
}
sb.append(name).append(" - ");
if (sa instanceof Ability_Sub)
sb.append(" ");
else
sb.append(name).append(" - ");
for(Card c : tgtCards){
sb.append(c.getName());
sb.append(" ");
@@ -343,7 +391,8 @@ public class AbilityFactory_Pump {
}
}
sb.append("until end of turn.");
if (!params.containsKey("Permanent"))
sb.append("until end of turn.");
Ability_Sub abSub = sa.getSubAbility();
@@ -379,28 +428,7 @@ public class AbilityFactory_Pump {
final int a = getNumAttack(sa);
final int d = getNumDefense(sa);
final Command untilEOT = new Command() {
private static final long serialVersionUID = -42244224L;
public void execute() {
if(AllZone.GameAction.isCardInPlay(tgtC)) {
tgtC.addTempAttackBoost(-1 * a);
tgtC.addTempDefenseBoost(-1 * d);
if(Keywords.size() > 0)
{
for (int i=0; i<Keywords.size(); i++)
{
if (!Keywords.get(i).equals("none"))
tgtC.removeExtrinsicKeyword(Keywords.get(i));
}
}
}
}
};
tgtC.addTempAttackBoost(a);
tgtC.addTempDefenseBoost(d);
if(Keywords.size() > 0)
@@ -412,8 +440,31 @@ public class AbilityFactory_Pump {
}
}
AllZone.EndOfTurn.addUntil(untilEOT);
if (!params.containsKey("Permanent")){
// If not Permanent, remove Pumped at EOT
final Command untilEOT = new Command() {
private static final long serialVersionUID = -42244224L;
public void execute() {
if(AllZone.GameAction.isCardInPlay(tgtC)) {
tgtC.addTempAttackBoost(-1 * a);
tgtC.addTempDefenseBoost(-1 * d);
if(Keywords.size() > 0)
{
for (int i=0; i<Keywords.size(); i++)
{
if (!Keywords.get(i).equals("none"))
tgtC.removeExtrinsicKeyword(Keywords.get(i));
}
}
}
}
};
AllZone.EndOfTurn.addUntil(untilEOT);
}
}

View File

@@ -478,6 +478,10 @@ public class Phase extends MyObservable
public synchronized boolean is(String phase) {
return (getPhase().equals(phase));
}
public boolean isAfter(String phase) {
return phaseIndex > findIndex(phase);
}
private int findIndex(String phase) {
for(int i = 0; i < phaseOrder.length; i++) {