add a basic working AF for CopyPermanent. It will need tweaking as new cards are attempted. And the AI could be improved to be more flexible, but basically, it works, and changes related to copy can be made in a central location. Tested with Kiki-Jiki and Myr Propagator.

This commit is contained in:
jendave
2011-08-06 23:19:33 +00:00
parent 43836f96ed
commit 1307940889
3 changed files with 368 additions and 0 deletions

1
.gitattributes vendored
View File

@@ -8740,6 +8740,7 @@ src/forge/card/abilityFactory/AbilityFactory_ChangeZone.java -text svneol=native
src/forge/card/abilityFactory/AbilityFactory_Choose.java -text svneol=native#text/plain
src/forge/card/abilityFactory/AbilityFactory_Clash.java -text svneol=native#text/plain
src/forge/card/abilityFactory/AbilityFactory_Combat.java -text svneol=native#text/plain
src/forge/card/abilityFactory/AbilityFactory_Copy.java -text svneol=native#text/plain
src/forge/card/abilityFactory/AbilityFactory_CounterMagic.java -text svneol=native#text/plain
src/forge/card/abilityFactory/AbilityFactory_Counters.java -text svneol=native#text/plain
src/forge/card/abilityFactory/AbilityFactory_DealDamage.java -text svneol=native#text/plain

View File

@@ -631,6 +631,15 @@ public class AbilityFactory {
SA = AbilityFactory_Choose.createDrawbackChooseType(this);
}
if(API.equals("CopyPermanent")){
if(isAb)
SA = AbilityFactory_Copy.createAbilityCopyPermanent(this);
else if(isSp)
SA = AbilityFactory_Copy.createSpellCopyPermanent(this);
else if(isDb)
SA = AbilityFactory_Copy.createDrawbackCopyPermanent(this);
}
if (SA == null)
throw new RuntimeException("AbilityFactory : SpellAbility was not created for "+hostCard.getName()+". Looking for API: "+API);

View File

@@ -0,0 +1,358 @@
package forge.card.abilityFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Random;
import forge.AllZone;
import forge.AllZoneUtil;
import forge.Card;
import forge.CardList;
import forge.Command;
import forge.ComputerUtil;
import forge.Constant;
import forge.MyRandom;
import forge.card.cardFactory.CardFactory;
import forge.card.cardFactory.CardFactoryUtil;
import forge.card.spellability.Ability;
import forge.card.spellability.Ability_Activated;
import forge.card.spellability.Ability_Sub;
import forge.card.spellability.Spell;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target;
import forge.card.trigger.Trigger;
public class AbilityFactory_Copy {
// *************************************************************************
// ************************* CopyPermanent *********************************
// *************************************************************************
public static SpellAbility createAbilityCopyPermanent(final AbilityFactory af) {
final SpellAbility abCopyPermanent = new Ability_Activated(af.getHostCard(), af.getAbCost(), af.getAbTgt()) {
private static final long serialVersionUID = 4557071554433108024L;
@Override
public String getStackDescription() {
return copyPermanentStackDescription(af, this);
}
@Override
public boolean canPlayAI() {
return copyPermanentCanPlayAI(af, this);
}
@Override
public void resolve() {
copyPermanentResolve(af, this);
}
@Override
public boolean doTrigger(boolean mandatory) {
return copyPermanentTriggerAI(af, this, mandatory);
}
};
return abCopyPermanent;
}
public static SpellAbility createSpellCopyPermanent(final AbilityFactory af) {
final SpellAbility spCopyPermanent = new Spell(af.getHostCard(), af.getAbCost(), af.getAbTgt()) {
private static final long serialVersionUID = 3313370358993251728L;
@Override
public String getStackDescription() {
return copyPermanentStackDescription(af, this);
}
@Override
public boolean canPlayAI() {
return copyPermanentCanPlayAI(af, this);
}
@Override
public void resolve() {
copyPermanentResolve(af, this);
}
};
return spCopyPermanent;
}
public static SpellAbility createDrawbackCopyPermanent(final AbilityFactory af) {
final SpellAbility dbCopyPermanent = new Ability_Sub(af.getHostCard(), af.getAbTgt()) {
private static final long serialVersionUID = -7725564505830285184L;
@Override
public String getStackDescription(){
return copyPermanentStackDescription(af, this);
}
@Override
public void resolve() {
copyPermanentResolve(af, this);
}
@Override
public boolean chkAI_Drawback() {
return true;
}
@Override
public boolean doTrigger(boolean mandatory) {
return copyPermanentTriggerAI(af, this, mandatory);
}
};
return dbCopyPermanent;
}
private static String copyPermanentStackDescription(AbilityFactory af, SpellAbility sa) {
StringBuilder sb = new StringBuilder();
if (!(sa instanceof Ability_Sub))
sb.append(sa.getSourceCard().getName()).append(" - ");
else
sb.append(" ");
ArrayList<Card> tgtCards;
Target tgt = af.getAbTgt();
if (tgt != null)
tgtCards = tgt.getTargetCards();
else
tgtCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), af.getMapParams().get("Defined"), sa);
sb.append("Copy ");
Iterator<Card> it = tgtCards.iterator();
while(it.hasNext()) {
sb.append(it.next());
if(it.hasNext()) sb.append(", ");
}
sb.append(".");
Ability_Sub abSub = sa.getSubAbility();
if(abSub != null) {
sb.append(abSub.getStackDescription());
}
return sb.toString();
}
private static boolean copyPermanentCanPlayAI(final AbilityFactory af, final SpellAbility sa) {
//TODO - I'm sure someone can do this AI better
HashMap<String,String> params = af.getMapParams();
if(params.containsKey("SacAtEOT") && !AllZone.Phase.is(Constant.Phase.Main1)) {
return false;
}
else return copyPermanentTriggerAI(af, sa, false);
}
private static boolean copyPermanentTriggerAI(final AbilityFactory af, final SpellAbility sa, boolean mandatory){
//HashMap<String,String> params = af.getMapParams();
Card source = sa.getSourceCard();
if (!ComputerUtil.canPayCost(sa) && !mandatory)
return false;
double chance = .4; // 40 percent chance with instant speed stuff
if (AbilityFactory.isSorcerySpeed(sa))
chance = .667; // 66.7% chance for sorcery speed (since it will never activate EOT)
Random r = MyRandom.random;
boolean randomReturn = r.nextFloat() <= Math.pow(chance, source.getAbilityUsed() + 1);
//////
// Targeting
Target abTgt = sa.getTarget();
if (abTgt != null){
CardList list = AllZoneUtil.getCardsInPlay();
list = list.getValidCards(abTgt.getValidTgts(), source.getController(), source);
abTgt.resetTargets();
// target loop
while(abTgt.getNumTargeted() < abTgt.getMaxTargets(sa.getSourceCard(), sa)){
if (list.size() == 0){
if (abTgt.getNumTargeted() < abTgt.getMinTargets(sa.getSourceCard(), sa) || abTgt.getNumTargeted() == 0){
abTgt.resetTargets();
return false;
}
else{
// todo is this good enough? for up to amounts?
break;
}
}
Card choice;
if(list.filter(AllZoneUtil.creatures).size() > 0) {
choice = CardFactoryUtil.AI_getBestCreature(list);
}
else {
choice = CardFactoryUtil.AI_getMostExpensivePermanent(list, source, true);
}
if (choice == null){ // can't find anything left
if (abTgt.getNumTargeted() < abTgt.getMinTargets(sa.getSourceCard(), sa) || abTgt.getNumTargeted() == 0){
abTgt.resetTargets();
return false;
}
else{
// todo is this good enough? for up to amounts?
break;
}
}
list.remove(choice);
abTgt.addTarget(choice);
}
}
else{
//if no targeting, it should always be ok
}
//end Targeting
if (af.hasSubAbility()){
Ability_Sub abSub = sa.getSubAbility();
if (abSub != null){
return randomReturn && abSub.chkAI_Drawback();
}
}
return randomReturn;
}
private static void copyPermanentResolve(final AbilityFactory af, final SpellAbility sa) {
HashMap<String,String> params = af.getMapParams();
Card card = af.getHostCard();
ArrayList<String> keywords = new ArrayList<String>();
if(params.containsKey("Keywords")) {
keywords.addAll(Arrays.asList(params.get("Keywords").split(" & ")));
}
ArrayList<Card> tgtCards;
Target tgt = af.getAbTgt();
if (tgt != null)
tgtCards = tgt.getTargetCards();
else
tgtCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), af.getMapParams().get("Defined"), sa);
for(Card c : tgtCards) {
if (tgt == null || CardFactoryUtil.canTarget(card, c)) {
//start copied Kiki code
int multiplier = AllZoneUtil.getDoublingSeasonMagnitude(card.getController());
Card[] crds = new Card[multiplier];
for(int i = 0; i < multiplier; i++) {
//TODO: Use central copy methods
Card copy;
if(!c.isToken()) {
//copy creature and put it onto the battlefield
copy = AllZone.CardFactory.getCard(c.getName(), c.getOwner());
//when copying something stolen:
copy.setController(c.getController());
copy.setToken(true);
copy.setCopiedToken(true);
}
else { //isToken()
copy = CardFactory.copyStats(c);
copy.setName(c.getName());
copy.setImageName(c.getImageName());
copy.setOwner(c.getController());
copy.setController(c.getController());
copy.setManaCost(c.getManaCost());
copy.setColor(c.getColor());
copy.setToken(true);
copy.setType(c.getType());
copy.setBaseAttack(c.getBaseAttack());
copy.setBaseDefense(c.getBaseDefense());
}
//add keywords from params
for(String kw : keywords) {
copy.addIntrinsicKeyword(kw);
}
//Slight hack in case we copy a creature with triggers.
for(Trigger t : copy.getTriggers()) {
AllZone.TriggerHandler.registerTrigger(t);
}
copy.setCurSetCode(c.getCurSetCode());
copy.setImageFilename(c.getImageFilename());
if(c.isFaceDown()) {
copy.setIsFaceDown(true);
copy.setManaCost("");
copy.setBaseAttack(2);
copy.setBaseDefense(2);
copy.setIntrinsicKeyword(new ArrayList<String>()); //remove all keywords
copy.setType(new ArrayList<String>()); //remove all types
copy.addType("Creature");
copy.clearSpellAbility(); //disallow "morph_up"
copy.setCurSetCode("");
copy.setImageFilename("morph.jpg");
}
AllZone.GameAction.moveToPlay(copy);
crds[i] = copy;
}
//have to do this since getTargetCard() might change
//if Kiki-Jiki somehow gets untapped again
final Card[] target = new Card[multiplier];
for(int i = 0; i < multiplier; i++) {
final int index = i;
target[index] = crds[index];
final SpellAbility sac = new Ability(target[index], "0") {
@Override
public void resolve() {
//technically your opponent could steal the token
//and the token shouldn't be sacrificed
if(AllZone.GameAction.isCardInPlay(target[index])) {
AllZone.GameAction.sacrifice(target[index]); //maybe do a setSacrificeAtEOT, but probably not.
//Slight hack in case we copy a creature with triggers
AllZone.TriggerHandler.removeAllFromCard(target[index]);
}
}
};
Command atEOT = new Command() {
private static final long serialVersionUID = -4184510100801568140L;
public void execute() {
sac.setStackDescription("Sacrifice "+target[index]);
AllZone.Stack.addSimultaneousStackEntry(sac);
}
};//Command
if(params.containsKey("SacAtEOT")) {
AllZone.EndOfTurn.addAt(atEOT);
}
//end copied Kiki code
}
}//end canTarget
if(af.hasSubAbility()) {
Ability_Sub abSub = sa.getSubAbility();
if(abSub != null) {
abSub.resolve();
}
}
}//end foreach Card
}//end resolve
}//end class AbilityFactory_Copy