- fix a memory leak with "Prevent All combat damages" ability
- Fix issue 242 (Equip can be used outside of the main phases)
- introducing "attach" keyword. Same as equip but can be used anytime. Untested
- introducing "asSorcery" keyword. Can be used the same way as "myTurnOnly" on activated abilities to restrict their usage. Untested. Other similar keywords will follow, please let me know which ones would be useful
This commit is contained in:
wagic.the.homebrew@gmail.com
2009-12-13 03:28:50 +00:00
parent c7f23f2e5c
commit 7cc072bf77
7 changed files with 93 additions and 37 deletions

View File

@@ -102,6 +102,7 @@ behemoth_sledge.txt
behemoth_sledge2.txt
behemoth_sledge3.txt
behemoth_sledge4.txt
behemoth_sledge5.txt
belligerent_hatchling.txt
benalish_knight.txt
black_vise.txt

View File

@@ -0,0 +1,24 @@
#Test:equipment outside of main phase
[INIT]
COMBATATTACKERS
[PLAYER1]
manapool:{3}
inplay:grizzly bears,behemoth sledge
[PLAYER2]
[DO]
behemoth sledge
grizzly bears
next
#blockers
next
#damage
next
#end combat
[ASSERT]
COMBATEND
[PLAYER1]
life:20
inplay:grizzly bears,behemoth sledge
[PLAYER2]
life:18
[END]

View File

@@ -384,7 +384,7 @@ class GenericActivatedAbility:public ActivatedAbility{
int limitPerTurn;
int counters;
MTGGameZone * activeZone;
GenericActivatedAbility(int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost, int _tap = 0, int limit = 0, int myTurnOnly = 0, MTGGameZone * dest = NULL):ActivatedAbility(_id, card,_cost,myTurnOnly,_tap),ability(a),limitPerTurn(limit),activeZone(dest){
GenericActivatedAbility(int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost, int _tap = 0, int limit = 0, int restrictions = 0, MTGGameZone * dest = NULL):ActivatedAbility(_id, card,_cost,restrictions,_tap),ability(a),limitPerTurn(limit),activeZone(dest){
counters = 0;
target = ability->target;
}
@@ -441,7 +441,7 @@ public:
int limitPerTurn;
int counters;
MTGGameZone * activeZone;
GenericTargetAbility(int _id, MTGCardInstance * _source, TargetChooser * _tc,MTGAbility * a, ManaCost * _cost = NULL, int _tap=0, int limit = 0, int myTurnOnly = 0, MTGGameZone * dest = NULL):TargetAbility(_id,_source, _tc,_cost,myTurnOnly,_tap),limitPerTurn(limit), activeZone(dest){
GenericTargetAbility(int _id, MTGCardInstance * _source, TargetChooser * _tc,MTGAbility * a, ManaCost * _cost = NULL, int _tap=0, int limit = 0, int restrictions = 0, MTGGameZone * dest = NULL):TargetAbility(_id,_source, _tc,_cost,restrictions,_tap),limitPerTurn(limit), activeZone(dest){
ability = a;
counters = 0;
}
@@ -988,7 +988,7 @@ class ABasicAbilityAuraModifierUntilEOT: public ActivatedAbility{
class AEquip:public TargetAbility{
public:
vector<MTGAbility *> currentAbilities;
AEquip(int _id, MTGCardInstance * _source, ManaCost * _cost=NULL, int doTap=0, int myturnOnly = 1):TargetAbility(_id,_source,NULL,_cost,myturnOnly,doTap){
AEquip(int _id, MTGCardInstance * _source, ManaCost * _cost=NULL, int doTap=0, int restrictions = ActivatedAbility::AS_SORCERY):TargetAbility(_id,_source,NULL,_cost,restrictions,doTap){
}
@@ -2316,12 +2316,12 @@ class APreventAllCombatDamage:public MTGAbility{
if (fromTc) fromTc->targetter = NULL;
re = NEW REDamagePrevention (this, fromTc, toTc, -1, false, DAMAGE_COMBAT);
game->replacementEffects->add(re);
return 1;
return MTGAbility::addToGame();
}
int destroy(){
game->replacementEffects->remove(re);
delete re;
SAFE_DELETE(re);
return 1;
}
@@ -2337,18 +2337,25 @@ class APreventAllCombatDamage:public MTGAbility{
class APreventAllCombatDamageUEOT: public InstantAbility{
public:
APreventAllCombatDamage * ability;
vector<APreventAllCombatDamage *> clones;
APreventAllCombatDamageUEOT(int id,MTGCardInstance * source,string to, string from):InstantAbility(id,source){
ability = NEW APreventAllCombatDamage(id,source,to, from);
}
int resolve(){
ability->target = this->target;
ability->addToGame();
APreventAllCombatDamage * a = ability->clone();
a->target = this->target;
a->forceDestroy = -1; //Prevent the effect from getting destroyed because its source is not inplay
a->addToGame();
clones.push_back(a);
return 1;
}
int destroy(){
ability->destroy();
for (size_t i = 0; i < clones.size(); ++i){
clones[i]->forceDestroy = 0;
}
clones.clear();
return 1;
}

View File

@@ -100,9 +100,14 @@ class TriggeredAbility:public MTGAbility{
class ActivatedAbility:public MTGAbility{
public:
int playerturnonly;
enum {
NO_RESTRICTION = 0,
PLAYER_TURN_ONLY = 1,
AS_SORCERY = 2
};
int restrictions;
int needsTapping;
ActivatedAbility(int id, MTGCardInstance * card,ManaCost * _cost = NULL, int _playerturnonly = 0,int tap = 1);
ActivatedAbility(int id, MTGCardInstance * card,ManaCost * _cost = NULL, int _restrictions = NO_RESTRICTION,int tap = 1);
virtual int reactToClick(MTGCardInstance * card);
virtual int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL);
virtual int reactToTargetClick(Targetable * object);
@@ -202,6 +207,7 @@ class AbilityFactory{
int countCards(TargetChooser * tc, Player * player = NULL, int option = 0);
int parsePowerToughness(string s, int *power, int *toughness);
TriggeredAbility * parseTrigger(string s, int id, Spell * spell, MTGCardInstance *card, Targetable * target);
int parseRestriction(string s);
public:
int getAbilities(vector<MTGAbility *> * v, Spell * spell, MTGCardInstance * card = NULL, int id = 0,MTGGameZone * dest = NULL);
MTGAbility * parseMagicLine(string s, int id, Spell * spell, MTGCardInstance *card, int activated = 0, int forceUEOT = 0,MTGGameZone * dest = NULL);

View File

@@ -11,7 +11,7 @@
#include "../include/utils.h"
#include "../include/DeckDataWrapper.h"
static const char* GAME_VERSION = "WTH?! 0.9.3 - by wololo";
static const char* GAME_VERSION = "WTH?! 0.10.0 - by wololo";
#define DEFAULT_ANGLE_MULTIPLIER 0.4
#define MAX_ANGLE_MULTIPLIER (3*M_PI)

View File

@@ -144,12 +144,12 @@ void GameStateOptions::Render()
"Art: Ilya B, Julio, Jeck, J",
"Check themeinfo.txt for the full credits of each theme!",
"",
"Dev Team: Abrasax, Daddy32, Dr.Solomat, J,",
"Jeck, Leungclj, Superhiro, Psyringe, Wololo",
"Dev Team: Abrasax, Daddy32, Dr.Solomat, J, Jeck",
"Leungclj, Superhiro, Psyringe, Wololo, Yeshua",
"",
"Thanks to everyone who contributes code/content on the forums!",
"",
"Developed with the JGE++ Library (http://jge.khors.com)",
"Developed with the JGE++ Library (http://code.google.com/p/wagic)",
"SFX From www.soundsnap.com",
"",
"Music by Celestial Aeon Project, http://www.jamendo.com",

View File

@@ -143,6 +143,11 @@ TriggeredAbility * AbilityFactory::parseTrigger(string magicText, int id, Spell
return NULL;
}
int AbilityFactory::parseRestriction(string s){
if (s.find("myturnonly") != string::npos) return ActivatedAbility::PLAYER_TURN_ONLY;
if (s.find("assorcery") != string::npos) return ActivatedAbility::AS_SORCERY;
return ActivatedAbility::NO_RESTRICTION;
}
//Parses a string and returns the corresponding MTGAbility object
@@ -186,8 +191,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
int doTap = 0; //Tap in the cost ?
if (s.find("{t}") != string::npos) doTap = 1;
int myTurnOnly = 0;
if (s.find("myturnonly") != string::npos) myTurnOnly = 1;
int restrictions = parseRestriction(s);
size_t delimiter = s.find("}:");
size_t firstNonSpace = s.find_first_not_of(" ");
@@ -213,15 +217,6 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
return amp;
}
AEquip *ae = dynamic_cast<AEquip*>(a);
if (ae){
ae->cost = cost;
TargetChooserFactory tcf;
ae->tc = tcf.createTargetChooser("creature|myBattlefield", card);
return ae;
}
int limit = 0;
unsigned int limit_str = s.find("limit:");
if (limit_str != string::npos){
@@ -238,8 +233,19 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
tc = tcf.createTargetChooser(starget, card);
}
if (tc) return NEW GenericTargetAbility(id, card, tc, a,cost, doTap,limit,myTurnOnly,dest);
return NEW GenericActivatedAbility(id, card, a,cost,doTap,limit,myTurnOnly,dest);
AEquip *ae = dynamic_cast<AEquip*>(a);
if (ae){
ae->cost = cost;
if (!tc) {
TargetChooserFactory tcf;
tc = tcf.createTargetChooser("creature|myBattlefield", card);
}
ae->tc = tc;
return ae;
}
if (tc) return NEW GenericTargetAbility(id, card, tc, a,cost, doTap,limit,restrictions,dest);
return NEW GenericActivatedAbility(id, card, a,cost,doTap,limit,restrictions,dest);
}
SAFE_DELETE(cost);
}
@@ -426,6 +432,13 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
return a;
}
//Equipment (attach)
found = s.find("attach");
if (found != string::npos){
MTGAbility * a = NEW AEquip(id,card,0,0,ActivatedAbility::NO_RESTRICTION);
return a;
}
//MoveTo Move a card from a zone to another
found = s.find("moveto(");
@@ -1702,15 +1715,25 @@ ostream& MTGAbility::toString(ostream& out) const
//
ActivatedAbility::ActivatedAbility(int id, MTGCardInstance * card, ManaCost * _cost, int _playerturnonly,int tap):MTGAbility(id,card), playerturnonly(_playerturnonly), needsTapping(tap){
ActivatedAbility::ActivatedAbility(int id, MTGCardInstance * card, ManaCost * _cost, int restrictions,int tap):MTGAbility(id,card), restrictions(restrictions), needsTapping(tap){
cost = _cost;
}
int ActivatedAbility::isReactingToClick(MTGCardInstance * card, ManaCost * mana){
Player * player = game->currentPlayer;
if (!playerturnonly) player = game->currentlyActing();
if (card == source && source->controller()==player && player==game->currentlyActing() && (!needsTapping || (!source->isTapped() && !source->hasSummoningSickness()))){
Player * player = game->currentlyActing();
int cPhase = game->getCurrentGamePhase();
switch(restrictions) {
case PLAYER_TURN_ONLY:
if (player != game->currentPlayer) return 0;
break;
case AS_SORCERY:
if (player != game->currentPlayer) return 0;
if (cPhase != Constants::MTG_PHASE_FIRSTMAIN && cPhase != Constants::MTG_PHASE_SECONDMAIN) return 0;
break;
}
if (card == source && source->controller()==player && (!needsTapping || (!source->isTapped() && !source->hasSummoningSickness()))){
if (!cost) return 1;
if (!mana) mana = player->getManaPool();
if (!mana->canAfford(cost)) return 0;
@@ -1756,18 +1779,13 @@ int ActivatedAbility::reactToTargetClick(Targetable * object){
ostream& ActivatedAbility::toString(ostream& out) const
{
out << "ActivatedAbility ::: playerturnonly : " << playerturnonly
out << "ActivatedAbility ::: restrictions : " << restrictions
<< " ; needsTapping : " << needsTapping
<< " (";
return MTGAbility::toString(out) << ")";
}
//The whole targetAbility mechanism is messed up, mainly because of its interactions with
// the ActionLayer, GameObserver, and parent class ActivatedAbility.
// Currently choosing a target is a complete different mechanism for put into play and for other abilities.
// It probably shouldn't be the case.
TargetAbility::TargetAbility(int id, MTGCardInstance * card, TargetChooser * _tc,ManaCost * _cost, int _playerturnonly,int tap):ActivatedAbility(id, card,_cost,_playerturnonly, tap){
tc = _tc;
ability = NULL;