AbilityFactory TODO list
Post MTG Forge Related Programming Questions Here
Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins
AbilityFactory TODO list
by slapshot5 » 07 Mar 2011, 17:44
We have discussed in several different threads the remaining AbilityFactory classes that we would like to create.
Here is a central place we can track those ideas and related discussions.
-slapshot5
Here is a central place we can track those ideas and related discussions.
-slapshot5
- slapshot5
- Programmer
- Posts: 1391
- Joined: 03 Jan 2010, 17:47
- Location: Mac OS X
- Has thanked: 25 times
- Been thanked: 68 times
Re: AbilityFactory TODO list
by slapshot5 » 07 Mar 2011, 17:46
First up, Sol, I think you mentioned you were looking into an AF for Animate things like manlands, Mimics, etc. If you haven't started it yet, (or haven't gotten too far along), I'll tackle that one.
-slapshot5
-slapshot5
- slapshot5
- Programmer
- Posts: 1391
- Joined: 03 Jan 2010, 17:47
- Location: Mac OS X
- Has thanked: 25 times
- Been thanked: 68 times
Re: AbilityFactory TODO list
by Hellfish » 07 Mar 2011, 17:56
We talked briefly about AF's for spell copying, clashing and attaching auras/equipment. I have no plans for either of those as of right now,though that may change.
So now you're
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
-
Hellfish - Programmer
- Posts: 1297
- Joined: 07 Jun 2009, 10:41
- Location: South of the Pumphouse
- Has thanked: 110 times
- Been thanked: 169 times
Re: AbilityFactory TODO list
by Chris H. » 07 Mar 2011, 18:15
AF_Animate will be tricky. Someone added some code to some of the manlands which would allow the AI to get some use out of these types of spells/abilities.
I remember some comments from the user base. The AI would animate a land and then tap the same land to pay for it's animation cost or to pay for some other cost for another spell or ability.
I spent a little time tracking down the AI mana code and found where it creates a list of untapped mana for the AI to use. I planned to sort his list so that the non-manland mana would appear first and the manlands would appear last in the list.
This would help to reduce the chance that the AI would waste it's mana to no effect. It might be worth it to create a flag that prevent an animate till EOT animation from tapping for mana.
I remember some comments from the user base. The AI would animate a land and then tap the same land to pay for it's animation cost or to pay for some other cost for another spell or ability.
I spent a little time tracking down the AI mana code and found where it creates a list of untapped mana for the AI to use. I planned to sort his list so that the non-manland mana would appear first and the manlands would appear last in the list.
This would help to reduce the chance that the AI would waste it's mana to no effect. It might be worth it to create a flag that prevent an animate till EOT animation from tapping for mana.
-
Chris H. - Forge Moderator
- Posts: 6320
- Joined: 04 Nov 2008, 12:11
- Location: Mac OS X Yosemite
- Has thanked: 644 times
- Been thanked: 643 times
Re: AbilityFactory TODO list
by Zirbert » 07 Mar 2011, 19:22
Some damage prevention would be good - "Prevent the next (x) damage that would be dealt to", "Prevent all damage that would be dealt by (x)", etc.
Re: AbilityFactory TODO list
by Sloth » 07 Mar 2011, 19:53
We need an AF to handle abilities like those of Serendib Sorcerer and Liquimetal Coating. Something like "DefineCharacteristic".
-
Sloth - Programmer
- Posts: 3498
- Joined: 23 Jun 2009, 19:40
- Has thanked: 125 times
- Been thanked: 507 times
Re: AbilityFactory TODO list
by friarsol » 07 Mar 2011, 20:56
I've been way too busy to work on anything lately. I have a list at home that I'll post tonight of what I think would be good things to do for AFs next.
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: AbilityFactory TODO list
by friarsol » 08 Mar 2011, 02:28
Alright here's my list. This may be repeats of others already mentioned.
SetLife (mostly written below, someone else can feel free to finish it up)
AssignType (granting additional or overriding types Liquidmetal Coating)
AssignColor (granting additional or overriding colors)
SetPowerToughness (setting Power/Toughness Serendib Sorcerer)
Conditional AF (for Flip a Coin, or other things that need to check that state of something, basically just calls subAbilities if true/false)
Peek/Reveal (Impulse is what I would consider the standard Peek/Reveal card. You look at the X cards of your Library, put Y of them somewhere, then put the rest somewhere.)
I thought I had some more but I can't find them. Might have deleted it by accident.
SetLife (mostly written below, someone else can feel free to finish it up)
AssignType (granting additional or overriding types Liquidmetal Coating)
AssignColor (granting additional or overriding colors)
SetPowerToughness (setting Power/Toughness Serendib Sorcerer)
Conditional AF (for Flip a Coin, or other things that need to check that state of something, basically just calls subAbilities if true/false)
Peek/Reveal (Impulse is what I would consider the standard Peek/Reveal card. You look at the X cards of your Library, put Y of them somewhere, then put the rest somewhere.)
I thought I had some more but I can't find them. Might have deleted it by accident.
- Code: Select all
// *************************************************************************
// ************************** SET LIFE *************************************
// *************************************************************************
public static SpellAbility createAbilitySetLife(final AbilityFactory AF){
final SpellAbility abSetLife = new Ability_Activated(AF.getHostCard(), AF.getAbCost(), AF.getAbTgt()){
private static final long serialVersionUID = 8869422603616247307L;
final AbilityFactory af = AF;
@Override
public String getStackDescription(){
// when getStackDesc is called, just build exactly what is happening
return setLifeStackDescription(af, this);
}
public boolean canPlayAI()
{
return setLifeCanPlayAI(af, this);
}
@Override
public void resolve() {
setLifeResolve(af, this);
}
@Override
public boolean doTrigger(boolean mandatory) {
return setLifeDoTriggerAI(af, this, mandatory);
}
};
return abSetLife;
}
public static SpellAbility createSpellSetLife(final AbilityFactory AF){
final SpellAbility spSetLife = new Spell(AF.getHostCard(), AF.getAbCost(), AF.getAbTgt()){
private static final long serialVersionUID = 6631124959690157874L;
final AbilityFactory af = AF;
@Override
public String getStackDescription(){
// when getStackDesc is called, just build exactly what is happening
return setLifeStackDescription(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 setLifeCanPlayAI(af, this);
}
@Override
public void resolve() {
setLifeResolve(af, this);
}
};
return spSetLife;
}
public static SpellAbility createDrawbackSetLife(final AbilityFactory AF){
final SpellAbility dbSetLife = new Ability_Sub(AF.getHostCard(), AF.getAbTgt()){
private static final long serialVersionUID = 6631124959690157874L;
final AbilityFactory af = AF;
@Override
public String getStackDescription(){
// when getStackDesc is called, just build exactly what is happening
return setLifeStackDescription(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 setLifeCanPlayAI(af, this);
}
@Override
public void resolve() {
setLifeResolve(af, this);
}
@Override
public boolean chkAI_Drawback() {
return true;
}
@Override
public boolean doTrigger(boolean mandatory) {
return setLifeDoTriggerAI(af, this, mandatory);
}
};
return dbSetLife;
}
public static String setLifeStackDescription(AbilityFactory af, SpellAbility sa){
StringBuilder sb = new StringBuilder();
int amount = AbilityFactory.calculateAmount(af.getHostCard(), af.getMapParams().get("LifeAmount"), sa);
if (!(sa instanceof Ability_Sub))
sb.append(sa.getSourceCard().getName()).append(" -");
sb.append(" ");
ArrayList<Player> tgtPlayers;
Target tgt = af.getAbTgt();
if (tgt != null)
tgtPlayers = tgt.getTargetPlayers();
else
tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), af.getMapParams().get("Defined"), sa);
for(Player player : tgtPlayers)
sb.append(player).append(" ");
sb.append("life total becomes ").append(amount).append(".");
Ability_Sub abSub = sa.getSubAbility();
if (abSub != null) {
sb.append(abSub.getStackDescription());
}
return sb.toString();
}
public static boolean setLifeCanPlayAI(final AbilityFactory af, final SpellAbility sa){
Random r = new Random();
Ability_Cost abCost = sa.getPayCosts();
final Card source = sa.getSourceCard();
int life = AllZone.ComputerPlayer.getLife();
String amountStr = af.getMapParams().get("LifeAmount");
if (!ComputerUtil.canPayCost(sa))
return false;
if (!AllZone.ComputerPlayer.canGainLife())
return false;
// TODO handle proper calculation of X values based on Cost and what would be paid
int amount;
if (amountStr.equals("X") && source.getSVar(amountStr).equals("Count$xPaid")){
// Set PayX here to maximum value.
int xPay = ComputerUtil.determineLeftoverMana(sa);
source.setSVar("PayX", Integer.toString(xPay));
amount = xPay;
}
else
amount = AbilityFactory.calculateAmount(af.getHostCard(), amountStr, sa);
// prevent run-away activations - first time will always return true
boolean chance = r.nextFloat() <= Math.pow(.6667, source.getAbilityUsed());
Target tgt = sa.getTarget();
if (tgt != null){
tgt.resetTargets();
if (tgt.canOnlyTgtOpponent())
tgt.addTarget(AllZone.HumanPlayer);
else
tgt.addTarget(AllZone.ComputerPlayer);
}
else{
}
return ((r.nextFloat() < .6667) && chance);
}
public static boolean setLifeDoTriggerAI(AbilityFactory af, SpellAbility sa, boolean mandatory){
if (!ComputerUtil.canPayCost(sa) && !mandatory) // If there is a cost payment it's usually not mandatory
return false;
// If the Target is gaining life, target self.
// if the Target is modifying how much life is gained, this needs to be handled better
Target tgt = sa.getTarget();
if (tgt != null){
tgt.resetTargets();
if (tgt.canOnlyTgtOpponent())
tgt.addTarget(AllZone.HumanPlayer);
else
tgt.addTarget(AllZone.ComputerPlayer);
}
Card source = sa.getSourceCard();
String amountStr = af.getMapParams().get("LifeAmount");
if (amountStr.equals("X") && source.getSVar(amountStr).equals("Count$xPaid")){
// Set PayX here to maximum value.
int xPay = ComputerUtil.determineLeftoverMana(sa);
source.setSVar("PayX", Integer.toString(xPay));
}
// check SubAbilities DoTrigger?
Ability_Sub abSub = sa.getSubAbility();
if (abSub != null) {
return abSub.doTrigger(mandatory);
}
return true;
}
public static void setLifeResolve(final AbilityFactory af, final SpellAbility sa){
HashMap<String,String> params = af.getMapParams();
Card card = af.getHostCard();
int lifeAmount = AbilityFactory.calculateAmount(af.getHostCard(), params.get("LifeAmount"), sa);
ArrayList<Player> tgtPlayers;
Target tgt = af.getAbTgt();
if (tgt != null && !params.containsKey("Defined"))
tgtPlayers = tgt.getTargetPlayers();
else
tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa);
for(Player p : tgtPlayers)
if (tgt == null || p.canTarget(af.getHostCard()))
p.gainLife(lifeAmount, sa.getSourceCard());
if (af.hasSubAbility()){
Ability_Sub abSub = sa.getSubAbility();
if (abSub != null){
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);
}
}
}
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: AbilityFactory TODO list
by slapshot5 » 08 Mar 2011, 04:21
SetLife was the other one I keep putting off. I'll take your code and finish that one up.
-slapshot5
-slapshot5
- slapshot5
- Programmer
- Posts: 1391
- Joined: 03 Jan 2010, 17:47
- Location: Mac OS X
- Has thanked: 25 times
- Been thanked: 68 times
Re: AbilityFactory TODO list
by slapshot5 » 08 Mar 2011, 13:35
Seems like in the Pay Mana code, we could add the following checks:Chris H. wrote:I remember some comments from the user base. The AI would animate a land and then tap the same land to pay for it's animation cost or to pay for some other cost for another spell or ability.
I spent a little time tracking down the AI mana code and found where it creates a list of untapped mana for the AI to use. I planned to sort his list so that the non-manland mana would appear first and the manlands would appear last in the list.
1. if this land is also a creature, don't tap it for mana
2. if a spell (or maybe specifically an animate spell even) is targeting a land, or has Defined$ Self, don't use that land to lay the cost.
That should help. Fortunately, most everything for Animate is Defined$ Self. There are very few things I have found like Kamahl, Fist of Krosa.
-slapshot5
- slapshot5
- Programmer
- Posts: 1391
- Joined: 03 Jan 2010, 17:47
- Location: Mac OS X
- Has thanked: 25 times
- Been thanked: 68 times
Re: AbilityFactory TODO list
by friarsol » 08 Mar 2011, 13:49
There are a few AnimateAlls but we can handle those afterwards.slapshot5 wrote:That should help. Fortunately, most everything for Animate is Defined$ Self. There are very few things I have found like Kamahl, Fist of Krosa.
Oh I also wanted an Effect AF. I'm not sure how the AI would work for it yet, but basically it would create an Effect "permanent", which is sorta like a token Card, but generally without any types. It would be similar to Token since you could give it abilities and whatnot. We could have Emblems use this AF, as well as Effects that last a certain amount of time that we have no way to keep track of right now. Like Dauntless Escort's ability.
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: AbilityFactory TODO list
by Replika » 08 Mar 2011, 15:32
An Effect AF would be very nice to handle abilities that have to stay even if its source dies, like Ethersworn Shieldmage.
I would also like a "Repeat this until" to do things like Treasure Hunt or the often requested Ad Nauseam.
I would also like a "Repeat this until" to do things like Treasure Hunt or the often requested Ad Nauseam.
Re: AbilityFactory TODO list
by slapshot5 » 08 Mar 2011, 17:46
I was going to enchance the generic aura code to Enchant <valid>, but since it should be an AF eventually, I'll just go to that instead.
Has anyone thought about what the Enchant/Equip AF would look like? I see them both going into an AbilityFactory_Attach.java file.
Then, do we add a fourth category when getting abilties in AbilityFactory?
Is there a better/different way anyone had thought of?
-slapshot5
Has anyone thought about what the Enchant/Equip AF would look like? I see them both going into an AbilityFactory_Attach.java file.
Then, do we add a fourth category when getting abilties in AbilityFactory?
- Code: Select all
if(API.equals("Enchant")) {
if(isAb)
SA = AbilityFactory_Attach.createAbilityEnchant(this);
else if(isSp)
SA = AbilityFactory_Attach.createSpellEnchant(this);
else if(isDb)
SA = AbilityFactory_Attach.createDrawbackEnchant(this);
else if(isAttachment)
SA = AbilityFactory_Attach.createAttachmentEnchant(this);
}
Is there a better/different way anyone had thought of?
-slapshot5
- slapshot5
- Programmer
- Posts: 1391
- Joined: 03 Jan 2010, 17:47
- Location: Mac OS X
- Has thanked: 25 times
- Been thanked: 68 times
Re: AbilityFactory TODO list
by Hellfish » 08 Mar 2011, 18:03
I found some old notes I'd made about a generic attach AF a while ago.Don't remember why I didn't implement it fully, probably AI problems.
Equip:
Equip:
- Code: Select all
AB$Attach | Cost$ 2 | DefinedAttachee$ Self | ValidAttachTo$ Creature.YouCtrl | PreCostDesc$ Equip -
- Code: Select all
SP$Attach | Cost$ U | ValidAttachee$ Aura.YouCtrl | ValidAttachTo$ Creature | SubAbility$SVar=DBDraw | SpellDescription$ Attach target Aura you control to target creature.
So now you're
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
-
Hellfish - Programmer
- Posts: 1297
- Joined: 07 Jun 2009, 10:41
- Location: South of the Pumphouse
- Has thanked: 110 times
- Been thanked: 169 times
Re: AbilityFactory TODO list
by Rob Cashwalker » 09 Mar 2011, 14:36
Something else to consider before going crazy adding new mechanics:
Charms and Commands
A Charm AF would wrap around three sub abilities, checking each AI, then chooses one from the positive returns, albeit randomly....
Charms and Commands
A Charm AF would wrap around three sub abilities, checking each AI, then chooses one from the positive returns, albeit randomly....
The Force will be with you, Always.
-
Rob Cashwalker - Programmer
- Posts: 2167
- Joined: 09 Sep 2008, 15:09
- Location: New York
- Has thanked: 5 times
- Been thanked: 40 times
Who is online
Users browsing this forum: No registered users and 30 guests