spLoseLife[Tgt] keyword
Post MTG Forge Related Programming Questions Here
Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins
14 posts
• Page 1 of 1
spLoseLife[Tgt] keyword
by 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:
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:
So, here's the syntax:
- Code: Select all
spLoseLife{Tgt}:NumLife:{Drawback}:{SpellDescription}:{StackDescription}
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
- 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
- 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);
}
}
- Code: Select all
if (condition) {
...
}
- Code: Select all
if (condition)
{
...
}
Last edited by Rob Cashwalker on 26 Feb 2010, 15:05, edited 1 time in total.
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
Re: spLoseLife[Tgt] keyword
by 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.
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.

-
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
by 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.
BTW, I just noticed I forgot to add stack descriptions to some of those cards.
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
Re: spLoseLife[Tgt] keyword
by 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
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!
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
by 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
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

-
DennisBergkamp - AI Programmer
- Posts: 2602
- Joined: 09 Sep 2008, 15:46
- Has thanked: 0 time
- Been thanked: 0 time
Re: spLoseLife[Tgt] keyword
by 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
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!
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
by 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.
Anyway, the latest version (with Rob's merged stuff) is on the SVN now.
-
DennisBergkamp - AI Programmer
- Posts: 2602
- Joined: 09 Sep 2008, 15:46
- Has thanked: 0 time
- Been thanked: 0 time
Re: spLoseLife[Tgt] keyword
by 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.
-
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
-
DennisBergkamp - AI Programmer
- Posts: 2602
- Joined: 09 Sep 2008, 15:46
- Has thanked: 0 time
- Been thanked: 0 time
Re: spLoseLife[Tgt] keyword
by 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 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.
-
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
by 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
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
by 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.
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.
-
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
by 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
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
by 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....
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.
-
Rob Cashwalker - Programmer
- Posts: 2167
- Joined: 09 Sep 2008, 15:09
- Location: New York
- Has thanked: 5 times
- Been thanked: 40 times
14 posts
• Page 1 of 1
Who is online
Users browsing this forum: No registered users and 38 guests