It is currently 11 Sep 2025, 19:26
   
Text Size

spLoseLife[Tgt] keyword

Post MTG Forge Related Programming Questions Here

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

spLoseLife[Tgt] keyword

Postby Rob Cashwalker » 26 Feb 2010, 14:50

As I looked at revising Chris' spLoseLifeGainLife keyword, I found that there were very few additional cards that lose life AND gain life. But there were a couple extra cards that could be done that just cause loss of life. The Drawback$ functionality easily adds the gain life effect to those cards that need it.

So, here's the syntax:
Code: Select all
spLoseLife{Tgt}:NumLife:{Drawback}:{SpellDescription}:{StackDescription}
Simple, right?

Yes, Tgt is optional, because the keyword can support Stronghold Discipline. So far, it's the only one, but it's always nice to be flexible.

Existing cards:
Code: Select all
Absorb Vis
6 B
Sorcery
no text
spLoseLifeTgt:4:Drawback$YouGainLife/4:Target player loses 4 life and you gain 4 life.
TypeCycling:Basic:1 B

Last Caress
2 B
Sorcery
no text
spLoseLifeTgt:1:Drawback$YouGainLife/1:Target player loses 1 life and you gain 1 life.
Draw a card.

Soul Feast
3 B B
Sorcery
no text
spLoseLifeTgt:4:Drawback$YouGainLife/4:Target player loses 4 life and you gain 4 life.

Morsel Theft
2 B B
Tribal Sorcery Rogue
(NOTE: "Prowl" is not implemented.)
spLoseLifeTgt:3:Drawback$YouGainLife/3:Target player loses 3 life and you gain 3 life.:Morsel Theft - target player loses life and you gain life
New cards:
Code: Select all
Exotic Disease
4 B
Sorcery
no text
spLoseLifeTgt:X:Drawback$YouGainLife/X:Domain - Target player loses X life and you gain X life, where X is the number of basic land types among lands you control.
SVar:X:Count$Domain

Stronghold Discipline
2 B B
Sorcery
no text
spLoseLife:X:Drawback$OppLoseLife/dX:Each player loses 1 life for each creature he or she controls.:Stronghold Discipline - each player loses life
SVar:X:Count$TypeYouCtrl.Creature
SVar:dX:Count$TypeOppCtrl.Creature

Syphon Life
1 B B
Sorcery
(NOTE: "Retrace" is not implemented.)
spLoseLifeTgt:2:Drawback$YouGainLife/2:Target player loses 2 life and you gain 2 life.:Syphone Life - target player loses life and you gain life
CardFactory:
Code: Select all
    if (hasKeyword(card, "spLoseLife") != -1)
    {
       int n = hasKeyword(card, "spLoseLife");
       if (n != -1)
       {
          String parse = card.getKeyword().get(n).toString();
          card.removeIntrinsicKeyword(parse);
          
          String k[] = parse.split(":");
          
            final boolean Tgt[] = {false};
            Tgt[0] = k[0].contains("Tgt");

          final int NumLife[] = {-1};
          final String NumLifeX[] = {"none"};
          
            if (k[1].matches("X"))
            {
               String x = card.getSVar(k[1]);
               if (x.startsWith("Count$"))
               {
                  String kk[] = x.split("\\$");
                  NumLifeX[0] = kk[1];
               }
            }
            else if (k[1].matches("[0-9][0-9]?"))
               NumLife[0] = Integer.parseInt(k[1]);
           
            // drawbacks and descriptions
            final String DrawBack[] = {"none"};
            final String spDesc[] = {"none"};
            final String stDesc[] = {"none"};
            if (k.length > 2)
            {
               if (k[2].contains("Drawback$"))
               {
                  String kk[] = k[2].split("\\$");
                  DrawBack[0] = kk[1];
                  if (k.length > 3)
                     spDesc[0] = k[3];
                  if (k.length > 4)
                     stDesc[0] = k[4];
               }
               else
               {
                  if (k.length > 2)
                     spDesc[0] = k[2];
                  if (k.length > 3)
                     stDesc[0] = k[3];
               }
            }
            else
            {
               if (Tgt[0] == true)
               {
                  spDesc[0] = "Target player loses " + NumLife[0] + " life.";
                  stDesc[0] =  cardName + " - target player loses life";
               }
               else
               {
                  spDesc[0] = "You lose " + NumLife[0] + " life.";
                  stDesc[0] = cardName + " - you lose life";
               }
            }
           
           
            final SpellAbility spLoseLife = new Spell(card)
            {
            private static final long serialVersionUID = -8361697584661592092L;

             public int getNumLife()
             {
                if (NumLife[0] != -1)
                   return NumLife[0];

                if (! NumLifeX[0].equals("none"))
                   return CardFactoryUtil.xCount(card, NumLifeX[0]);
               
                return 0;
             }
             
             public boolean canPlayAI()
             {
                if (Tgt[0] == true)
                {
                   setTargetPlayer(Constant.Player.Human);
                   return true;
                }
                else   // pretty much just for Stronghold Discipline...
                {      // assumes there's a good Drawback$ that makes losing life worth it
                   int nlife = getNumLife();
                   if ((AllZone.Computer_Life.getLife() - nlife) > 10)
                      return true;
                   else
                      return false;
                }
             }

            public void resolve()
               {
                  int nlife = getNumLife();
                  String TgtPlayer;

                  if (Tgt[0] == true)
                     TgtPlayer = getTargetPlayer();
                  else
                     TgtPlayer = card.getController();
                 
                  AllZone.GameAction.subLife(TgtPlayer, nlife);
                 
                  if (!DrawBack[0].equals("none"))
                     CardFactoryUtil.doDrawBack(DrawBack[0], nlife, card.getController(), AllZone.GameAction.getOpponent(card.getController()), TgtPlayer, card, null);
               }//resolve()
            };//SpellAbility
           
            if (Tgt[0] == true)
               spLoseLife.setBeforePayMana(CardFactoryUtil.input_targetPlayer(spLoseLife));
           
            spLoseLife.setDescription(spDesc[0]);
            spLoseLife.setStackDescription(stDesc[0]);
           
            card.clearSpellAbility();
            card.addSpellAbility(spLoseLife);
       }
    }
I tried to update my CardFactory before commiting, but I now have 100's of errors. It looks like someone has changed the "{" from being on its own line to being on the line with the declaration or statement ie:
Code: Select all
if (condition) {
   ...
}
as opposed to the standard:
Code: Select all
if (condition)
{
   ...
}
anyway, this means that I need Dennis to integrate the code, and I'll pull a completely fresh copy of the project.
Last edited by Rob Cashwalker on 26 Feb 2010, 15:05, edited 1 time in total.
The Force will be with you, Always.
User avatar
Rob Cashwalker
Programmer
 
Posts: 2167
Joined: 09 Sep 2008, 15:09
Location: New York
Has thanked: 5 times
Been thanked: 40 times

Re: spLoseLife[Tgt] keyword

Postby Chris H. » 26 Feb 2010, 15:04

I remember that there was a problem when Absorb Vis was added. I can not remember the particulars very well.

At the very least we did not have both of the choices displayed when the card was cast. I know that I went back in and added code for the {SpellDescription}:{StackDescription} fields.

This type of situation has come up with several of the newer cards with cycling.

I may have also been forced to add a special case test for Absorb Vis and if true add in the TypeCycling keyword. As I said, I can not remember the particulars very well. :mrgreen:
User avatar
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: spLoseLife[Tgt] keyword

Postby Rob Cashwalker » 26 Feb 2010, 15:08

I don't recall seeing anything particular to Absorb Vis in TypeCycling.... But it worked fine for me in testing.

BTW, I just noticed I forgot to add stack descriptions to some of those cards.
The Force will be with you, Always.
User avatar
Rob Cashwalker
Programmer
 
Posts: 2167
Joined: 09 Sep 2008, 15:09
Location: New York
Has thanked: 5 times
Been thanked: 40 times

Re: spLoseLife[Tgt] keyword

Postby silly freak » 26 Feb 2010, 15:34

do you have compile time errors, or did you mean merging errors? i'm sorry that you're having problems, i meant to remove all the warnings regarding missing @Override tags, but my eclipse is configured to format source code automatically on a save, and I just like that style over the "standard" way.

I think the easiest thing would be to extract your changes to some temporary location (the synchronization perspective does a great job here), then update to the newest revision and paste your code back in. that's what I usually do
___

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: spLoseLife[Tgt] keyword

Postby DennisBergkamp » 26 Feb 2010, 19:13

Do the errors happen because there's some extra curly brace somewhere? Or is it because of the @Override annotations?
In the latter case, just set your Eclipse build path to use java 1.6 (I know this sounds kind of counter-intuitive, since we're supposed to make this whole thing 1.5 compatible - but it doesn't make a difference, as long as your Project settings are set to 1.5).

Either way, I'll merge your code, no problems :)
User avatar
DennisBergkamp
AI Programmer
 
Posts: 2602
Joined: 09 Sep 2008, 15:46
Has thanked: 0 time
Been thanked: 0 time

Re: spLoseLife[Tgt] keyword

Postby silly freak » 26 Feb 2010, 21:04

I did the changes with 1.5 settings, so that should be alright. I normally use 1.6 though, since the SwingWorker class is 1.6+

the actual work did eclipse, I set it up to automaticall add missing @Overrides when saving, and then inserted a blank somewhere. no additional curly braces. the class compiles fine for me
___

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: spLoseLife[Tgt] keyword

Postby DennisBergkamp » 26 Feb 2010, 21:48

I know there's no additional curly braces because of your work (stuff compiles fine for me too, after all), but it sounds like one might've slipped into his local version when he was changing things.

Anyway, the latest version (with Rob's merged stuff) is on the SVN now.
User avatar
DennisBergkamp
AI Programmer
 
Posts: 2602
Joined: 09 Sep 2008, 15:46
Has thanked: 0 time
Been thanked: 0 time

Re: spLoseLife[Tgt] keyword

Postby Chris H. » 27 Feb 2010, 00:04

I ran a quick test deck and everything works great. Stronghold Discipline has a StackDescription field and the others all use the targeted version. Good stuff.
User avatar
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: spLoseLife[Tgt] keyword

Postby DennisBergkamp » 27 Feb 2010, 00:32

Nice, good job Rob :mrgreen:
User avatar
DennisBergkamp
AI Programmer
 
Posts: 2602
Joined: 09 Sep 2008, 15:46
Has thanked: 0 time
Been thanked: 0 time

Re: spLoseLife[Tgt] keyword

Postby Rob Cashwalker » 27 Feb 2010, 01:51

The errors seemed like a {} mismatch somewhere... I really wish there was an easy way to find that sort of problem. It didn't complain about the @override.

The funny thing about the style choice of { placement, is that when I first started coding C, I used that style, having come from a QBasic and VB background. But when I had to match the traditional style in my company's software, I got used to it. There was a mish-mash of styles used in the Forge software from the beginning, but predominantly the traditional.

The problem I have, is that most of us just use default eclipse. If some people have set these fancy preferences, then it affects how other people are going to work with the code.

I'm thinking about making Buyback an SVar keyword. To be checked in each actual keyword code. If it has a Buyback SVar, then I'll make a copy of the spell ability, set it's isBuybackAbility property, then add both to the card. (Why am I rambling about it now? Because there's just one more spLoseLifeTgt card that it would enable... of course, once I write the skeleton, it is super easy to add to the others)
The Force will be with you, Always.
User avatar
Rob Cashwalker
Programmer
 
Posts: 2167
Joined: 09 Sep 2008, 15:09
Location: New York
Has thanked: 5 times
Been thanked: 40 times

Re: spLoseLife[Tgt] keyword

Postby zerker2000 » 27 Feb 2010, 14:52

Why have spLoseLife instead of spLoseLifeEach denominate "each player loses"?
O forest, hold thy wand'ring son
Though fears assail the door.
O foliage, cloak thy ravaged one
In vestments cut for war.


--Eladamri, the Seed of Freyalise
zerker2000
Programmer
 
Posts: 569
Joined: 09 May 2009, 21:40
Location: South Pasadena, CA
Has thanked: 0 time
Been thanked: 0 time

Re: spLoseLife[Tgt] keyword

Postby Rob Cashwalker » 27 Feb 2010, 17:16

I dunno... I could also have done spLoseLifeOpp like I did with spDamageTgt....

I just knew that limiting a keyword to JUST lose/gain like Chirs did, seemed counter intuitive. It wasn't until I was in the testing stage, that I looked at Stronghold Discipline. (I had skipped it during my initial research because it seemed too complex) I realized that it could be keyworded without additional code, if you think about the problem creatively.
The Force will be with you, Always.
User avatar
Rob Cashwalker
Programmer
 
Posts: 2167
Joined: 09 Sep 2008, 15:09
Location: New York
Has thanked: 5 times
Been thanked: 40 times

Re: spLoseLife[Tgt] keyword

Postby zerker2000 » 27 Feb 2010, 21:00

I meant simply namewise...
O forest, hold thy wand'ring son
Though fears assail the door.
O foliage, cloak thy ravaged one
In vestments cut for war.


--Eladamri, the Seed of Freyalise
zerker2000
Programmer
 
Posts: 569
Joined: 09 May 2009, 21:40
Location: South Pasadena, CA
Has thanked: 0 time
Been thanked: 0 time

Re: spLoseLife[Tgt] keyword

Postby Rob Cashwalker » 28 Feb 2010, 07:30

So far, the convention is to define the root effect as the root of the name...

abPump or abPumpTgt
They both have the pump effect, but the code checks to see that if it has the Tgt included, then it must choose a target, or allow the user to choose a target.

spPumpTgt
So far, no spell can self-pump, so Tgt is sort of redundant, but it might as well be there for readability.

spDamageTgtP or spDamageOpp
A few of our damage spells can only target an opponent. This is mainly checked for the human action, because the AI will never target itself. (unless some code is added to look for combos)
Thinking about it, by changing the keyword root to spDamage, I might be able to squeeze in a couple each player damage spells....

spLoseLife or spLoseLifeTgt
I'd rather let the code be ready for the corner cases, maybe a potential combo sometime. (like "whenever you lose life, CARDNAME deals damage to target OBJECT")
The fact that one of those corner cases was easily done not so much by writing a specific test to see if "Each" was included, but by abusing the Drawback parameter actually makes me glad that I had it in place before I knew how useful it was....

These are some baby steps toward more complete control of card functions by simple scripted elements. One can almost imagine my utopia where the abilities are generated on the fly and their resolve methods simply iterate through a few SVar's containing game action instructions....
The Force will be with you, Always.
User avatar
Rob Cashwalker
Programmer
 
Posts: 2167
Joined: 09 Sep 2008, 15:09
Location: New York
Has thanked: 5 times
Been thanked: 40 times


Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 38 guests

Main Menu

User Menu

Our Partners


Who is online

In total there are 38 users online :: 0 registered, 0 hidden and 38 guests (based on users active over the past 10 minutes)
Most users ever online was 7967 on 09 Sep 2025, 23:08

Users browsing this forum: No registered users and 38 guests

Login Form