It is currently 27 Apr 2024, 10:28
   
Text Size

Programming a card

Post MTG Forge Related Programming Questions Here

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

Re: Programming a card

Postby DennisBergkamp » 12 Dec 2009, 01:21

I don't think there's an easy way to get the actual active player though :(
User avatar
DennisBergkamp
AI Programmer
 
Posts: 2602
Joined: 09 Sep 2008, 15:46
Has thanked: 0 time
Been thanked: 0 time

Re: Programming a card

Postby Triadasoul » 12 Dec 2009, 09:44

DennisBergkamp wrote:Hmm, but shouldn't Prowess of the Fair be called through something like this:

Code: Select all
else if (c.getName().equals("Prowess of the Fair") && destroyed.getType().contains("Elf")) && !destroyed.isToken() && !c.equals(destroyed) )
            destroyCreature_Prowess_of_the_Fair(c, destroyed);
exactly. But it doesn't work at all, so i tried to experiment with it a little to know what i made wrong and I've found funny things that something wrong with the card name "Prowess of the Fair" and i supposed that it should be added somewhere else.

Here's the full code of mine:
Code: Select all
else if (c.getName().equals("Prowess of the Fair") && destroyed.getType().contains("Elf") && !destroyed.isToken() && !c.equals(destroyed) )
            destroyCreature_Prowess_of_the_Fair(c, destroyed);
         


private static void destroyCreature_Prowess_of_the_Fair(Card c, Card destroyed)
   {
      final Card crd = c;
      final Card crd2 = c;
      Ability ability = new Ability(c, "0")
      {
         public void resolve()
         {
            String player = crd.getController();
            if (player.equals(Constant.Player.Human)) {
               if (showDialog(crd2))
                  makeToken();
            }
            else
               makeToken();
         }
         public void makeToken()
         {
            String player = crd.getController();
             Card c = new Card();

                c.setName("Elf Warrior");
                  c.setImageName("G 1 1 Elf Warrior");

                  c.setOwner(player);
                  c.setController(player);

                  c.setManaCost("G");
                  c.setToken(true);
                 
                  c.addType("Creature");
                  c.addType("Elf");
                  c.addType("Warrior");
                  c.setBaseAttack(1);
                  c.setBaseDefense(1);

                  PlayerZone play = AllZone.getZone(Constant.Zone.Play, player);
                  play.add(c);
         }
      };
      ability.setStackDescription("Prowess of the Fair - " + c.getController() +" may put a 1/1 green Elf Warrior creature token onto the battlefield.");
      AllZone.Stack.add(ability);
   }
Triadasoul
 
Posts: 223
Joined: 21 Jun 2008, 20:17
Has thanked: 0 time
Been thanked: 4 times

Re: Programming a card

Postby DennisBergkamp » 14 Dec 2009, 19:58

Looking at the code, that should work... but I guess it doesn't, no idea why not though #-o
User avatar
DennisBergkamp
AI Programmer
 
Posts: 2602
Joined: 09 Sep 2008, 15:46
Has thanked: 0 time
Been thanked: 0 time

Re: Programming a card

Postby nantuko84 » 18 Dec 2009, 06:09

Triadasoul> don't you have debug?
as I use Forge architecture, I can say that I had similar problems when card names weren't trimmed.
To get to know this, try the code:

Code: Select all
else if (c.getName().trim().equals("Prowess of the Fair") && destroyed.getType().contains("Elf")) && !destroyed.isToken() && !c.equals(destroyed) )
            destroyCreature_Prowess_of_the_Fair(c, destroyed);
but as for me, I would add observers for such effects

anyway let me know about the results (first I thought about logging, but as far as I remember there is no one in Forge)
nantuko84
DEVELOPER
 
Posts: 266
Joined: 08 Feb 2009, 21:14
Has thanked: 2 times
Been thanked: 9 times

Re: Programming a card

Postby Triadasoul » 18 Dec 2009, 08:24

I didn't try debug yet, cause for now i don't know how to use it for such a big program like this.
I tried your variant, it also doesn't work. Anyway thank your for your feedback.
Triadasoul
 
Posts: 223
Joined: 21 Jun 2008, 20:17
Has thanked: 0 time
Been thanked: 4 times

Re: Programming a card

Postby nantuko84 » 18 Dec 2009, 11:33

Triadasoul> I debuged it for you
there are two major issues:

1. filter for DestroyCardEffects, now it is
Code: Select all
if (kw.startsWith("Whenever ") && kw.contains(" put into a graveyard from the battlefield,"))
               return true;
whereas your enchantment has "put into YOUR graveyard"

2. filter parses keywords and your card description doesn't contain any
so you need to add it or it's better to parse text as well
what I mean is:
2a.
Code: Select all
Prowess of the Fair
1 B
Tribal Enchantment Elf
Whenever another nontoken Elf is put into your graveyard from the battlefield, you may put a 1/1 green Elf Warrior creature token onto the battlefield.
Whenever another nontoken Elf is put into your graveyard from the battlefield, you may put a 1/1 green Elf Warrior creature token onto the battlefield.
first is text, the second is keyword that will be parsed
not good as for me

2b update filter to parse text as well (and better with regexp)

Code: Select all
public boolean addCard(Card c) {
         ArrayList<String> keywords = c.getKeyword();
         Pattern pattern = Pattern.compile(".*put into (\\S*) graveyard from the battlefield.*");
         Matcher m;
         for (String kw : keywords) {
            m = pattern.matcher(kw);
            if (kw.startsWith("Whenever") && m.matches())
               return true;
         }
         m = pattern.matcher(c.getText());
         return m.matches();
      }
it works for me though it triggeres SoulCatcher ability as I have
Code: Select all
else if (c.getName().equals("Prowess of the Fair") && destroyed.getType().contains("Elf") && !destroyed.isToken() && !c.equals(destroyed))
            destroyCreature_Soulcatcher(c, destroyed);   
I guess this is what you needed

p.s. btw, is there any way to put cards onto battlefield and into your hand before game starts?
now while testing Prowess of the Fair, I had to create deck with Llanowar Elves, Terrors, Forests, Swamps and Prowess of the Fair, but I had to be lucky to get them at once every game

how do you test your cards usually? is there any topic at forum regarding this?
nantuko84
DEVELOPER
 
Posts: 266
Joined: 08 Feb 2009, 21:14
Has thanked: 2 times
Been thanked: 9 times

Re: Programming a card

Postby Marek14 » 18 Dec 2009, 13:23

Incantus has a special card that costs 0 and has a bunch of powerful abilities that allow you, basically, to do anything for free - generate mana, deal damage, destroy permanents, move cards from graveyard or exile back to hand, tutor, etc. It's exactly for the purpose of testing cards (I have made use of it many, many times). MTGO has something similar, called, I believe "Library of Congress".
Marek14
Tester
 
Posts: 2761
Joined: 07 Jun 2008, 07:54
Has thanked: 0 time
Been thanked: 297 times

Re: Programming a card

Postby nantuko84 » 18 Dec 2009, 14:52

I also have such card in MagicWars:
http://img686.imageshack.us/img686/3112 ... tefull.jpg
(though add lots of mana is not correct wording ;))
but such card takes time anyway, that's why I can set game state using plain text:
Llanowar Elves <-- Gives to your hand
2
top:Path to Exile <-- Puts on top
1
grave:Call of the Herd <-- Puts into graveyard
1
and battlefield on another file with the same format

and I know how it is usefull, that's why I'm asking and will be suprised if there is no such :)
nantuko84
DEVELOPER
 
Posts: 266
Joined: 08 Feb 2009, 21:14
Has thanked: 2 times
Been thanked: 9 times

Re: Programming a card

Postby Triadasoul » 18 Dec 2009, 15:20

Thank you!! I should learn how to use the debugger in this context. 10 years passed since i used it last time in Pascal ))). As I thought it was somewhere else. Thank you for your code I'll add it today.

Usually I build a deck that completely consists of cards that I'm going to test (+lands of course, and accompanying cards, such as creatures for equipment) and playing with it against the same deck (to see how AI use it) and against some random decks. To speed things up you can change manacost in cards.txt to 1.
I haven't come on such a thread. I think the main thread about it is "Current Known Bug List" :roll:

UPD: I couldn't add the code cause i don't know what is "Pattern" and "Matcher" i'm a completely noob in java, but i'll change the condition to trigger Prowess of the Fair and such.
Triadasoul
 
Posts: 223
Joined: 21 Jun 2008, 20:17
Has thanked: 0 time
Been thanked: 4 times

Re: Programming a card

Postby silly freak » 18 Dec 2009, 16:38

Pattern and Matcher are classes for regular expressions, for example, the pattern "a*" or "a+" would match the string "aaaa"
you can do cool things: "." is the wildcard (any character):
Code: Select all
"Whenever .* put into a graveyard from the battlefield,"
to match almost exactly what you described above
___

where's the "trust me, that will work!" switch for the compiler?
Laterna Magica - blog, forum, project, 2010/09/06 release!
silly freak
DEVELOPER
 
Posts: 598
Joined: 26 Mar 2009, 07:18
Location: Vienna, Austria
Has thanked: 93 times
Been thanked: 25 times

Re: Programming a card

Postby Marek14 » 18 Dec 2009, 16:41

nantuko84 wrote:I also have such card in MagicWars:
http://img686.imageshack.us/img686/3112 ... tefull.jpg
(though add lots of mana is not correct wording ;))
but such card takes time anyway, that's why I can set game state using plain text:
Llanowar Elves <-- Gives to your hand
2
top:Path to Exile <-- Puts on top
1
grave:Call of the Herd <-- Puts into graveyard
1
and battlefield on another file with the same format

and I know how it is usefull, that's why I'm asking and will be suprised if there is no such :)
The thing is your card is still quite limited in what it can do. (For that matter, there is no need for it to be legendary - in Incantus I got great results by having each player have one in play to continue testing when one player had to pass turn to set up some new effects.)

The Incantus version is, for one thing, playable from library (so you don't even have to draw it). Also, it has truly incredible number of abilities - perhaps the most powerful one is the ultimate mover that can move, I think, up to five cards from any zone to any other - that allows you to sculpt the game state any way you like. Adding counters, dealing damage, color changing and such are also basic abilities. Incantus might post the full code for it if he'd like to - I'm not sure if I can do that without permission.
Marek14
Tester
 
Posts: 2761
Joined: 07 Jun 2008, 07:54
Has thanked: 0 time
Been thanked: 297 times

Re: Programming a card

Postby Incantus » 18 Dec 2009, 18:21

Damn, i just wrote a long reply and it was lost (posting from my phone). In short, go ahead Marek14.
Incantus
DEVELOPER
 
Posts: 267
Joined: 29 May 2008, 15:53
Has thanked: 0 time
Been thanked: 3 times

Re: Programming a card

Postby Marek14 » 18 Dec 2009, 19:32

Code: Select all
name = 'Betatester Toolbox'
cardnum = 1
expansion = 'Testing'
type = characteristic('Artifact')
supertype = no_characteristic()
subtypes = no_characteristic()
cost = '0'
color = no_characteristic()
text = []

play_spell = play_permanent(cost)

in_play_role = Permanent(card, Artifact())

#################################

@activated(txt="0: Put into play from library", zone="library")
def effects(source):
    payment = yield ManaCost("0")
    yield NoTarget()
    source.move_to(source.owner.play)
    yield
abilities.add(effects)

@mana(txt="0: Add WUBRG")
def effects(source):
    payment = yield ManaCost("0")
    yield NoTarget()
    add_mana(source.controller, "WUBRG")
    yield
abilities.add(effects)

@activated(txt="0: Tap target permanent")
def effects(source):
    payment = yield ManaCost("0")
    target = yield Target(target_types=isPermanent)
    target.tap()
    yield
abilities.add(effects)

@activated(txt="0: Untap target permanent")
def effects(source):
    payment = yield ManaCost("0")
    target = yield Target(target_types=isPermanent)
    target.untap()
    yield
abilities.add(effects)

@activated(txt="0: Destroy target permanent")
def effects(source):
    payment = yield ManaCost("0")
    target = yield Target(target_types=isPermanent)
    target.destroy()
    yield
abilities.add(effects)

@activated(txt="0: Destroy all permanents")
def effects(source):
    payment = yield ManaCost("0")
    yield NoTarget()
    for permanent in source.controller.play.get(isPermanent, all=True):
        permanent.destroy()
    yield
abilities.add(effects)

@activated(txt="0: Deal 1 damage to target player or creature")
def effects(source):
    payment = yield ManaCost("0")
    target = yield Target(target_types=isCreatureOrPlayer)
    source.dealDamage(target, 1)
    yield
abilities.add(effects)

@activated(txt="0: Put 2 1/1 green Elf creatures into play")
def effects(source):
    payment = yield ManaCost("0")
    target = yield NoTarget()
    elf = {"type": "Creature","subtypes": ("Elf", "Warrior"),"color": "G", "power": 1, "toughness": 1}
    source.controller.play_token(elf, 2)
    yield
abilities.add(effects)

@activated(txt="0: Target creature gets +1/+1 until the end of the turn")
def effects(source):
    payment = yield ManaCost("0")
    target = yield Target(target_types=isCreature)
    until_end_of_turn(augment_power_toughness(target, 1, 1))
    yield
abilities.add(effects)

@activated(txt="0: Place a +1/+1 counter on target creature")
def effects(source):
    payment = yield ManaCost("0")
    target = yield Target(target_types=isCreature)
    target.add_counters(PowerToughnessCounter(1, 1))
    yield
abilities.add(effects)

@activated(txt="0: Place a -1/-1 counter on target creature")
def effects(source):
    payment = yield ManaCost("0")
    target = yield Target(target_types=isCreature)
    target.add_counters(PowerToughnessCounter(-1, -1))
    yield
abilities.add(effects)

@activated(txt="0: Target permanent is red until the end of the turn")
def effects(source):
    payment = yield ManaCost("0")
    target = yield Target(target_types=isPermanent)
    until_end_of_turn(target.color.set('R'))
    yield
abilities.add(effects)

@activated(txt="0: Steal control of target permanent until end of turn")
def effects(source):
    payment = yield ManaCost("0")
    target = yield Target(target_types=isPermanent)
    until_end_of_turn(change_controller(target, source.controller))
    yield
abilities.add(effects)

@activated(txt="0: Return target permanent card in a graveyard to play under your control")
def effects(source):
    payment = yield ManaCost("0")
    target = yield Target(target_types=isPermanentType, zone="graveyard")
    target.move_to(source.controller.play)
    yield
abilities.add(effects)

@activated(txt="0: Return target Permanent card that was removed from the game to play under your control")
def effects(source):
    payment = yield ManaCost("0")
    target = yield Target(target_types=isPermanentType, zone="removed")
    target.move_to(source.controller.play)
    yield
abilities.add(effects)

@activated(txt="0: Momentary blink all permanents")
def effects(source):
    payment = yield ManaCost("0")
    yield NoTarget()
    permanents = source.controller.play.get(isPermanent, all=True)
    for permanent in permanents: permanent.move_to(permanent.owner.removed)
    yield
    for permanent in permanents: permanent.move_to(permanent.owner.play)
    yield
abilities.add(effects)

@activated(txt="0: Draw a card")
def effects(source):
    payment = yield ManaCost("0")
    yield NoTarget()
    source.controller.draw()
    yield
abilities.add(effects)

@activated(txt="0: Return target creature to its owner's hand")
def effects(source):
    payment = yield ManaCost("0")
    target = yield Target(isCreature)
    target.move_to(target.owner.hand)
    yield
abilities.add(effects)

@static_tracking(txt="Creatures you control have haste")
def ability():
    def condition(source, card):
        return source.controller == card.controller and isCreature(card)
    def effects(card):
        yield card.abilities.add(haste())
    return condition, effects
abilities.add(ability)
Note - the code is slightly different for different people as everyone suits it to his own purposes.
Marek14
Tester
 
Posts: 2761
Joined: 07 Jun 2008, 07:54
Has thanked: 0 time
Been thanked: 297 times

Re: Programming a card

Postby Incantus » 19 Dec 2009, 04:25

Wow Marek, you have an old version. Here's the current one I use:

Code: Select all
name = 'Betatester Toolbox'
cardnum = 1
expansion = 'Testing'
types = characteristic('Artifact')
supertypes = no_characteristic()
subtypes = no_characteristic()
cost = '0'
color = no_characteristic()
text = []

#################################

@static_tracking(events=TypesModifiedEvent(), txt="Creatures you control get +1/+1 and have haste")
def ability():
    def condition(source, card):
        return source.controller == card.controller and isCreature(card)
    def effects(source, card):
        yield card.augment_power_toughness_static(1,1), card.abilities.add(haste())
    return condition, effects
#abilities.add(ability)

@activated(txt="0: Put into play from library", zone="library")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        yield NoTarget()
        source.move_to("play")
        yield
    return effects
abilities.add(ability)

@mana(txt="0: Add WUBRG")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        yield NoTarget()
        controller.add_mana("WUBRG")
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Tap target permanent")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        target = yield Target(isPermanent)
        target.tap()
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Untap target permanent")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        target = yield Target(isPermanent)
        target.untap()
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Destroy target permanent")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        target = yield Target(isPermanent)
        target.destroy()
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Remove target permanent from the game")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        target = yield Target(isPermanent)
        target.move_to("removed")
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Destroy all permanents")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        yield NoTarget()
        for permanent in controller.play.get(isPermanent, all=True):
            permanent.destroy()
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Momentary blink up to 5 target permanents")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        targets = yield MultipleTargets(isPermanent, number=5, up_to=True)
        removed = [permanent.move_to("removed") for permanent in targets]
        yield
        permanents = [rfg.move_to("play") for rfg in removed]
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Deal 1 damage to target player or creature")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        target = yield Target(isCreatureOrPlayer)
        source.deal_damage(target, 1)
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Deal 10 damage to target player or creature")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        target = yield Target(isCreatureOrPlayer)
        source.deal_damage(target, 10)
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Put 3 2/1 green Elf creature into play")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        target = yield NoTarget()
        elf = {"types": "Creature","subtypes": ("Elf", "Warrior"),"color": "G", "P/T": (2,1)}
        controller.play_tokens(elf, 3)
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Target creature gets +1/+1 until the end of the turn")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        target = yield Target(isCreature)
        until_end_of_turn(target.augment_power_toughness(1, 1))
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Place a flood counter on target land")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        target = yield Target(isLand)
        target.add_counters(Counter("flood"))
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Place a +1/+1 counter on target creature")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        target = yield Target(isCreature)
        target.add_counters(PowerToughnessCounter(1, 1))
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Place a -1/-1 counter on target creature")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        target = yield Target(isCreature)
        target.add_counters(PowerToughnessCounter(-1, -1))
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Target creature gains shroud until the end of the turn")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        target = yield Target(isCreature)
        until_end_of_turn(target.abilities.add(shroud()))
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Target permanent is a color of your choice until the end of the turn")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        target = yield Target(isPermanent)
        color = controller.getSelection("WUBRG", 1, prompt="Select color to set")
        until_end_of_turn(target.color.set(color))
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Target permanent loses all abilities until the end of the turn")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        target = yield Target(isPermanent)
        until_end_of_turn(target.abilities.remove_all())
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Steal control of target permanent until end of turn")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        target = yield Target(isPermanent)
        until_end_of_turn(target.set_controller(controller))
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Return target permanent card in a graveyard to play under your control")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        target = yield Target(isPermanentCard, zone="graveyard")
        target.move_to(controller.play)
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Draw a card")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        yield NoTarget()
        controller.draw()
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Target player discards hand")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        target = yield Target(isPlayer)
        target.force_discard(-1)
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Search a chosen zone for up to 3 cards and move them to another zone")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        yield NoTarget()
        zones = ["play", "hand", "library", "graveyard", "removed"]
        from_zone = controller.make_selection(zones, prompt="Move from zone")
        zones.remove(from_zone)
        to_zone = controller.make_selection(zones, prompt="Move to zone")
        for card in controller.choose_from_zone(number=3, cardtype=isCard, zone=from_zone, action="card to move to %s"%to_zone, required=False):
            card.move_to(to_zone)
        yield
    return effects
abilities.add(ability)

@activated(txt="0: Search your library for a permanent card and put that card into play")
def ability():
    def effects(controller, source):
        payment = yield ManaCost("0")
        yield NoTarget()
        for card in controller.choose_from_zone(number=1, cardtype=isPermanentCard, zone="library", action="permanent card to put into play", required=False):
            card.move_to(controller.play)
        yield
    return effects
abilities.add(ability)
Incantus
DEVELOPER
 
Posts: 267
Joined: 29 May 2008, 15:53
Has thanked: 0 time
Been thanked: 3 times

Re: Programming a card

Postby nantuko84 » 19 Dec 2009, 04:55

have you generated the picture for your card?

(with Incantus expansion symbol :lol: )
nantuko84
DEVELOPER
 
Posts: 266
Joined: 08 Feb 2009, 21:14
Has thanked: 2 times
Been thanked: 9 times

PreviousNext

Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 94 guests


Who is online

In total there are 94 users online :: 0 registered, 0 hidden and 94 guests (based on users active over the past 10 minutes)
Most users ever online was 4143 on 23 Jan 2024, 08:21

Users browsing this forum: No registered users and 94 guests

Login Form