It is currently 30 Oct 2025, 18:48
   
Text Size

Implementing new Ability Factories and Card Support Code

Post MTG Forge Related Programming Questions Here

Moderators: timmermac, Agetian, friarsol, Blacksmith, KrazyTheFox, CCGHQ Admins

Re: Considerations and Questions: Ability Factories

Postby Sloth » 07 Nov 2012, 16:43

Agetian wrote:I'm working on an experimental version of the code which may later become a part of a new AF that deals with choosing a source (for Circles of Protection and whatever other cards may refer to "source"). I need a little consultation in this regard. Currently my mockup version of a source chooser does the following:

1) If there are any effects on the stack, it adds the cards that were the sources of those effects into the list, marking them with "(From stack)".
2) To the list of effects on the stack, it adds all the permanents currently in play.

It lists all of that and lets the user pick one.
This looks good. It should probably be included in TargetSelection.

Agetian wrote:I have a question: does the above cover all the possible scenarios of a "source"? I just can't possibly imagine what else there could be - if it's neither visible on the stack nor in play as a permanent, what else can it be?
From the comprehensive rules:
119.7. | Open
119.7. The source of damage is the object that dealt it. If an effect requires a player to choose a source
of damage, he or she may choose a permanent; a spell on the stack (including a permanent spell);
any object referred to by an object on the stack, by a prevention or replacement effect that’s waiting
to apply, or by a delayed triggered ability that’s waiting to trigger (even if that object is no longer in
the zone it used to be in); or, in certain casual variant games, a face-up card in the command zone.
A source doesn’t need to be capable of dealing damage to be a legal choice. See rule 609.7,
“Sources of Damage.”
Technically a card in another zone than the battlefield could sometimes be chosen.

Agetian wrote:Also, another question is: is there any implementation of "Prevent damage from <...>" currently in Forge? I looked at the damage prevention facilities in the current ability factory but could only find code related to preventing damage *to* a card, not coming *from* a card - if there is any code like that, I'd like to take a look at it, can you please tell me where I can find it? If there's no such implementation yet, can you please tell me what would be the easiest way to detect if a card has any damage-dealing effects (which includes combat damage and spell abilities and whatnot)?
I think this can be handled with storing "Remembered" objects. A CoP will create an Effect (these fake cards created by AF Effect) which remembers the target of the ability. I think the script of Awe Strike does all we want already.
User avatar
Sloth
Programmer
 
Posts: 3498
Joined: 23 Jun 2009, 19:40
Has thanked: 125 times
Been thanked: 507 times

Re: Considerations and Questions: Ability Factories

Postby Agetian » 07 Nov 2012, 17:06

Nice. Thanks a lot, Sloth!
Continuing our meditations on "source", do you mean that the command zone is sometimes included in the list? I'm not sure if Forge supports command zone yet, I'll take a look... By the description of rule 119.7, I don't see how a card can be chosen in another zone except for the battlefield, the command zone, or indirectly via the effect placed on the stack... Please, if possible, clarify what other zones may be included in the selection except the battlefield and the command zone (and the stack effects).

P.S. I was looking at TargetSelection but couldn't understand much of how it works... can you please clarify how exactly targeting starts and what function triggers it, in case you know? I'd like to, if possible, make the selection interactive (as in "let the user click either on the ability on the stack or on the permanent card"), but I have difficulties with how to approach this problem... The GUI selection window and the implementation of a ChooseCard-like AF seems feasible though.

- Agetian
Agetian
Programmer
 
Posts: 3490
Joined: 14 Mar 2011, 05:58
Has thanked: 684 times
Been thanked: 572 times

Re: Considerations and Questions: Ability Factories

Postby friarsol » 07 Nov 2012, 17:16

Agetian wrote:1) If there are any effects on the stack, it adds the cards that were the sources of those effects into the list, marking them with "(From stack)".
2) To the list of effects on the stack, it adds all the permanents currently in play.

It lists all of that and lets the user pick one.
I have a question: does the above cover all the possible scenarios of a "source"? I just can't possibly imagine what else there could be - if it's neither visible on the stack nor in play as a permanent, what else can it be?
I think you are also missing any card referenced by an SA on the stack.

Example: Electropotence is in play, and you cast Force of Savagery. Electropotence triggers for the Force ETB, but immediately goes to the graveyard. If I want to use my COP:Green to prevent that damage, since it's originating creature is neither on the battlefield, or the source of the SA. I wouldn't be able to choose the Force.

Edit: Fixing COP card that is relevant
Last edited by friarsol on 07 Nov 2012, 18:15, edited 1 time in total.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Considerations and Questions: Ability Factories

Postby Agetian » 07 Nov 2012, 17:27

friarsol wrote:I think you are also missing any card referenced by an SA on the stack.

Example: Electropotence is in play, and you cast Force of Savagery. Electropotence triggers for the Force ETB, but immediately goes to the graveyard. If I want to use my COP:Red to prevent that damage, since it's originating creature is neither on the battlefield, or the source of the SA. I wouldn't be able to choose the Force.
Hmm yeah, I can see that happening. I'm not sure what can be done to enumerate cards like that though, do you have any advice related to how card effects like that can be enumerated? Also, would this situation warrant a COP:Red or a COP:Green? I'm not sure what the damage dealer is going to be in this case - if it's Force of Savagery, it's going to be a green damage source, and if it's Electropotence, it's going to be a red damage source.

P.S. Electropotence is going to appear on the stack per se, but probably it's not going to be the damage dealing card in that case (thus I'm also not sure that the damage dealt would count as coming from a red or a green source :\ )

- Agetian
Agetian
Programmer
 
Posts: 3490
Joined: 14 Mar 2011, 05:58
Has thanked: 684 times
Been thanked: 572 times

Re: Considerations and Questions: Ability Factories

Postby friarsol » 07 Nov 2012, 17:50

Agetian wrote:P.S. Electropotence is going to appear on the stack per se, but probably it's not going to be the damage dealing card in that case (thus I'm also not sure that the damage dealt would count as coming from a red or a green source :\ )
Oh right, it should be COP:Green because the source is definitely the Force (unlike something like Fling).
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Considerations and Questions: Ability Factories

Postby Agetian » 07 Nov 2012, 18:05

friarsol wrote:
Agetian wrote:P.S. Electropotence is going to appear on the stack per se, but probably it's not going to be the damage dealing card in that case (thus I'm also not sure that the damage dealt would count as coming from a red or a green source :\ )
Oh right, it should be COP:Green because the source is definitely the Force (unlike something like Fling).
Yeah, makes sense. As of right now, the best idea would be to enumerate all the cards in zones where an affected card could possibly be - which might actually be a bunch of zones (not sure if e.g. exile or one's hand could be affected in that manner). Does anyone know of a more optimal way to enumerate referenced cards for effects on the stack (or for other cards in general)?

- Agetian
Agetian
Programmer
 
Posts: 3490
Joined: 14 Mar 2011, 05:58
Has thanked: 684 times
Been thanked: 572 times

Re: Considerations and Questions: Ability Factories

Postby Agetian » 07 Nov 2012, 19:34

Ok, here's my first mockup of the code that enumerates different sources and presents a choice. For the referenced effects, the best I could have done at the moment was iterate over getTriggeringObjects, hoping that that would provide a list of cards that are referenced. I'm afraid that it might not always be the case, I need some help in this regard (what would be the optimal way to enumerate all referenced cards?)

Currently this script allows you to pick where you're going to be choosing from (permanents, stack, or referenced cards) and then gives you the list of cards to choose from based on that criterion.

As of right now, this code is just linked to a custom button in the dev mode that I implemented for experiments in my local experimental SVN copy. Please, if possible, tell me where this code should normally go - should it become the basis of targeting for a new Ability Factory (like AF ChooseSource) or somehow be implemented in TargetingSelection (in the case of the latter, I have a rather vague idea how it works...) Any help you can provide is highly welcome.

Here's the first mockup code I came up with (EDIT: removed some useless code from it):

Code: Select all
Stack<SpellAbilityStackInstance> stack = Singletons.getModel().getGame().getStack().getStack();

List<Card> permanentCards = Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield);
List<Card> stackCards = new ArrayList<Card>();
List<Card> referencedCards = new ArrayList<Card>();

List<Card> cardsToChooseFrom = new ArrayList<Card>();

if (stack != null) {
    for (SpellAbilityStackInstance stackinst : stack) {
        if (!stackCards.contains(stackinst.getSourceCard())) {
             stackCards.add(stackinst.getSourceCard());
        }
        if (null != stackinst.getSpellAbility().getTriggeringObjects()) {
             for (Object c : (Collection<Object>)stackinst.getSpellAbility().getTriggeringObjects().values())
                 if (c instanceof Card)
                     referencedCards.add((Card)c);
        }
    }
}

String choices[] = {"Permanent", "Stack", "Referenced"};
String choice = GuiChoose.one("Choose a source from...", choices);

if (choice.equals("Permanent")) {
    cardsToChooseFrom.addAll(permanentCards);
} else if (choice.equals("Stack")) {
    cardsToChooseFrom.addAll(stackCards);
} else if (choice.equals("Referenced")) {
    cardsToChooseFrom.addAll(referencedCards);
}

if (cardsToChooseFrom.size() > 0) {
    Card chosen = GuiChoose.one("Choose a source", cardsToChooseFrom);
Agetian
Programmer
 
Posts: 3490
Joined: 14 Mar 2011, 05:58
Has thanked: 684 times
Been thanked: 572 times

Re: Considerations and Questions: Ability Factories

Postby Agetian » 08 Nov 2012, 06:18

Currently I'm in the middle of a dilemma that I need someone's help to solve... Before I begin the actual implementation of the ability factory (or a targeting mode, if that'd be possible), I need opinions on the following:

1. Would choosing from the list be OK or would targeting with a mouse be the option I should go for? I'd assume the latter would be more intuitive, but it seems it'd be hell to implement (at least currently I'm clueless as to how mouse targeting works and how I should best approach the implementation, so any advice at all is highly welcome).
2. How should the limitation by color and by type be best implemented? Am I correct in assumption that it's done via filtering the list of possible choices through CardLists.getValidCards(...)? (in this case, the parameters will come from the script and the filter command will do the magic) EDIT: Did some tests and it seems like this statement is true.
3. Is there anything to add to the blueprint of the algorithm I posted above? I'm especially curious about the "objects referenced by other objects" part, because I have no idea how that is best enumerated (I've found a way to enumerate at least a part of those objects, but probably that's not all - if it isn't, your suggestions are highly welcome).

As soon as these three questions are resolved, I'll begin implementing the code that will power the CoP/RoP cards.

EDIT: Here's the latest version of the mockup blueprint of the code, currently filtered through CardLists.getValidCards to get only red cards, as well as only showing choice options that are valid at the current time.

Code: Select all
            Stack<SpellAbilityStackInstance> stack = Singletons.getModel().getGame().getStack().getStack();

            List<Card> permanentCards = Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield);
            List<Card> stackCards = new ArrayList<Card>();
            List<Card> referencedCards = new ArrayList<Card>();

            List<Card> cardsToChooseFrom = new ArrayList<Card>();

            if (stack != null) {
                for (SpellAbilityStackInstance stackinst : stack) {
                    if (!stackCards.contains(stackinst.getSourceCard())) {
                        stackCards.add(stackinst.getSourceCard());
                    }
                    if (null != stackinst.getSpellAbility().getTriggeringObjects()) {
                        for (Object c : (Collection<Object>) stackinst.getSpellAbility().getTriggeringObjects().values()) {
                            if (c instanceof Card) {
                                referencedCards.add((Card) c);
                            }
                        }
                    }
                }
            }

            // + FILTER TEST +
            permanentCards = CardLists.getValidCards(permanentCards, "Card.Red", null, null);
            stackCards = CardLists.getValidCards(stackCards, "Card.Red", null, null);
            referencedCards = CardLists.getValidCards(referencedCards, "Card.Red", null, null);
            // - FILTER TEST -

            ArrayList<String> choices = new ArrayList<String>();
            if (permanentCards.size() > 0)
                choices.add("Permanent");
            if (stackCards.size() > 0)
                choices.add("Stack");
            if (referencedCards.size() > 0)
                choices.add("Referenced By Another Object");
           
            String choice = GuiChoose.one("Choose a source from...", choices);

            if (choice.equals("Permanent")) {
                cardsToChooseFrom.addAll(permanentCards);
            } else if (choice.equals("Stack")) {
                cardsToChooseFrom.addAll(stackCards);
            } else if (choice.equals("Referenced By Another Object")) {
                cardsToChooseFrom.addAll(referencedCards);
            }

            if (cardsToChooseFrom.size() > 0) {
                Card chosen = GuiChoose.one("Choose a source", cardsToChooseFrom);
            }
- Agetian
Agetian
Programmer
 
Posts: 3490
Joined: 14 Mar 2011, 05:58
Has thanked: 684 times
Been thanked: 572 times

Re: Considerations and Questions: Ability Factories

Postby Sloth » 08 Nov 2012, 08:36

Agetian wrote:1. Would choosing from the list be OK or would targeting with a mouse be the option I should go for? I'd assume the latter would be more intuitive, but it seems it'd be hell to implement (at least currently I'm clueless as to how mouse targeting works and how I should best approach the implementation, so any advice at all is highly welcome).
Choosing from lists is ok. Look at chooseCardFromList in the TargetSelection class. Most of what you want is already there.

Agetian wrote:2. How should the limitation by color and by type be best implemented? Am I correct in assumption that it's done via filtering the list of possible choices through CardLists.getValidCards(...)? (in this case, the parameters will come from the script and the filter command will do the magic) EDIT: Did some tests and it seems like this statement is true.
Yes. This is the way to go.

Agetian wrote:3. Is there anything to add to the blueprint of the algorithm I posted above? I'm especially curious about the "objects referenced by other objects" part, because I have no idea how that is best enumerated (I've found a way to enumerate at least a part of those objects, but probably that's not all - if it isn't, your suggestions are highly welcome).
I haven't looked at your code, because i guess chooseCardFromList already does most of the stuff and can be expanded as needed.
User avatar
Sloth
Programmer
 
Posts: 3498
Joined: 23 Jun 2009, 19:40
Has thanked: 125 times
Been thanked: 507 times

Re: Considerations and Questions: Ability Factories

Postby Agetian » 08 Nov 2012, 09:30

Sloth wrote:I haven't looked at your code, because i guess chooseCardFromList already does most of the stuff and can be expanded as needed.
Thanks for help, Sloth!

I'm currently trying to come up with a working script for CoP:Red that would prevent damage from a red source (initially - from a red card) that is chosen from a list of possibilities. However, the following script, based on a mockup referenced in another thread, does not work (it creates the effect but the effect does not prevent damage; also, the card chosen is remembered not on the effect, but on CoP itself, and when the effect goes away at the end of the turn, the chosen card is still remembered on CoP):

Code: Select all
Name:Circle of Protection Red
ManaCost:1 W
Types:Enchantment
Text:no text
A:AB$ ChooseCard | Cost$ 1 | Choices$ Card.Red | RememberChosen$ True | AILogic$ NeedsPrevention | SubAbility$ DBEffect | SVars$ DBEffect,RPreventNextFromSource,ExileEffect
SVar:DBEffect:DB$ Effect | ReplacementEffects$ RPreventNextFromSource | RememberObjects$ Chosen | SVars$ RPreventNextFromSource
SVar:RPreventNextFromSource:Event$ DamageDone | ValidSource$ Card.IsRemembered | ValidTarget$ You | ReplaceWith$ ExileEffect | PreventionEffect$ True | Description$ The next time the chosen source deals damage to you, prevent that damage.
SVar:ExileEffect:DB$ ChangeZone | Defined$ Self | Origin$ Battlefield | Destination$ Exile
SetInfo:4ED|Common|http://no.picture.yet
End
Can someone please tell me what's wrong with that script and why it won't prevent damage and remember objects the right way? For now, it's OK if this script would prevent damage just from cards, not from sources, I'll adapt it to my code for choosing sources as soon as it's ready.

P.S. I also tried to adapt the script of "Awe Strike" to the needs of CoP cards, but it uses mouse targeting instead of list-based card selection, and I'm not sure how to switch it over to a list. :\

- Agetian
Agetian
Programmer
 
Posts: 3490
Joined: 14 Mar 2011, 05:58
Has thanked: 684 times
Been thanked: 572 times

Re: Considerations and Questions: Ability Factories

Postby friarsol » 08 Nov 2012, 13:59

I made some small changes to your script. Basically, RememberObjects$ Chosen doesn't work, so you have to remember it (like you did) and then reference the Remembered Object down below.

Code: Select all
A:AB$ ChooseCard | Cost$ 1 | Choices$ Card.Red | RememberChosen$ True | AILogic$ NeedsPrevention | SubAbility$ DBEffect | SVars$ DBEffect,RPreventNextFromSource,ExileEffect
SVar:DBEffect:DB$ Effect | ReplacementEffects$ RPreventNextFromSource | RememberObjects$ Remembered | SVars$ RPreventNextFromSource,ExileEffect | SubAbility$ DBCleanup
SVar:RPreventNextFromSource:Event$ DamageDone | ValidSource$ Card.IsRemembered | ValidTarget$ You | ReplaceWith$ ExileEffect | PreventionEffect$ True | Description$ The next time the chosen source deals damage to you, prevent that damage.
SVar:ExileEffect:DB$ ChangeZone | Defined$ Self | Origin$ Battlefield | Destination$ Exile
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
I can't really test this, but I think that should get you closer.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Considerations and Questions: Ability Factories

Postby Agetian » 08 Nov 2012, 16:47

Thanks, Sol, that works perfectly fine! Ok, now on to writing the support code for choosing sources...

- Agetian
Agetian
Programmer
 
Posts: 3490
Joined: 14 Mar 2011, 05:58
Has thanked: 684 times
Been thanked: 572 times

Re: Considerations and Questions: Ability Factories

Postby friarsol » 08 Nov 2012, 17:06

There may be a few more cards out there where you have to worry about an SA reference being able to deal damage. But here's a basic list (obviously not all of these deal damage, but it's a start) for your testing.

I think generally, you'll want to grab the source of an object that's targeted, defined, or a triggerObject as your potential wildcard sources.

http://magiccards.info/query?q=%28%28o% ... rd&s=cname
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Considerations and Questions: Ability Factories

Postby Agetian » 08 Nov 2012, 19:15

Nice, thanks for the tip, I'll use that checklist for testing!

- Agetian
Agetian
Programmer
 
Posts: 3490
Joined: 14 Mar 2011, 05:58
Has thanked: 684 times
Been thanked: 572 times

Re: Considerations and Questions: Ability Factories

Postby Agetian » 09 Nov 2012, 08:34

Ok I'm well on my way towards implementing a good enough source chooser, the current test version indicates the possibility of choosing e.g. effects on the stack coming from cards of the given color, with the CoP card implemented with the above-mentioned script successfully preventing the damage from a source on the stack, and I'm currently working on implementing the possibility to choose a referenced object as well, so eventually I'll have a working implementation ready, hopefully within a few days.

However, that raises another important point: how do I teach the AI to properly use this source-choosing AF? I looked at the card-choosing AF canPlayAI and I believe it can be adapted to choosing sources, but somehow the AI needs to be aware of the initial check which asks the player where he wants to choose the source from (which can be either a permanent, or the stack, or an indirectly referenced object). I haven't found a way to implement this choice as a part of TargetSelection, no one has clarified how that works and even when it is triggered (and via what means) or how that is related to e.g. the ChooseCard AF, so instead I implemented a custom choice box for the origin of the source as a part of the ChooseSource AF. Since no choice boxes should ever appear when AI is deciding, and it may be tricky for the AI to distinguish between different origins, should I maybe "flatten" that list for the AI then, allowing it to pick a source from a list of all possibilities without necessarily subdividing it to stack/permanent/referenced?..

And another related question, what needs to be done to teach the AI to use CoPs in a logical fashion? Is there already a foundation which can be used to implement that via scripting (so, the AI can be made aware of the fact that CoPs are damage prevention cards and that it should activate their abilities on targets of specific color/type (e.g. CoP Red vs. CoP Artifacts) that deal damage to it), or should it be scripted completely from scratch, and if so, how would one go about it? (I've never touched the AI code of Forge, so I have a very vague idea about how it works and what needs to be done with it).

P.S. If it's too much of a difficulty to code on my own (which it might be, given the complexity of the AI code), would anyone be willing to volunteer to provide the AI backing for either the AF ChooseSource I'm writing or the CoP AI logic? (I think the latter may be an even bigger problem for me than the former).

Thanks in advance for help.

- Agetian
Agetian
Programmer
 
Posts: 3490
Joined: 14 Mar 2011, 05:58
Has thanked: 684 times
Been thanked: 572 times

PreviousNext

Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 21 guests

Main Menu

User Menu

Our Partners


Who is online

In total there are 21 users online :: 0 registered, 0 hidden and 21 guests (based on users active over the past 10 minutes)
Most users ever online was 9298 on 10 Oct 2025, 12:54

Users browsing this forum: No registered users and 21 guests

Login Form