diff --git a/projects/mtg/src/ActionStack.cpp b/projects/mtg/src/ActionStack.cpp index 9db2530d2..33284ea1b 100644 --- a/projects/mtg/src/ActionStack.cpp +++ b/projects/mtg/src/ActionStack.cpp @@ -1,6 +1,6 @@ /* - The Action Stack contains all information for Game Events that can be interrupted (Interruptible) - */ +The Action Stack contains all information for Game Events that can be interrupted (Interruptible) +*/ #include "PrecompiledHeader.h" #include "ActionStack.h" @@ -18,8 +18,8 @@ #include /* - NextGamePhase requested by user - */ +NextGamePhase requested by user +*/ int NextGamePhase::resolve() { @@ -31,7 +31,7 @@ const string NextGamePhase::getDisplayName() const { std::ostringstream stream; stream << "NextGamePhase. (Current phase is: " << PhaseRing::phaseName(GameObserver::GetInstance()->getCurrentGamePhase()) - << ")"; + << ")"; return stream.str(); } @@ -55,7 +55,7 @@ void NextGamePhase::Render() } NextGamePhase::NextGamePhase(int id) : - Interruptible(id) +Interruptible(id) { mHeight = 40; type = ACTION_NEXTGAMEPHASE; @@ -70,878 +70,878 @@ ostream& NextGamePhase::toString(ostream& out) const const string Interruptible::getDisplayName() const { return typeid(*this).name(); - } - - void Interruptible::Render(MTGCardInstance * source, JQuad * targetQuad, string alt1, string alt2, string action, - bool bigQuad) - { - WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); - mFont->SetColor(ARGB(255,255,255,255)); - mFont->SetScale(DEFAULT_MAIN_FONT_SCALE); - mFont->DrawString(_(action).c_str(), x + 30, y, JGETEXT_LEFT); - JRenderer * renderer = JRenderer::GetInstance(); - JQuad * quad = WResourceManager::Instance()->RetrieveCard(source, CACHE_THUMB); - if (!quad) - quad = CardGui::AlternateThumbQuad(source); - if (quad) - { - quad->SetColor(ARGB(255,255,255,255)); - float scale = mHeight / quad->mHeight; - renderer->RenderQuad(quad, x + 10 * scale, y + 15 * scale, 0, scale, scale); - } - else if (alt1.size()) - { - mFont->DrawString(_(alt1).c_str(), x, y - 15); - } - - if (bigQuad) - { - Pos pos = Pos(CardGui::BigWidth / 2, CardGui::BigHeight / 2 - 10, 1.0, 0.0, 220); - CardGui::DrawCard(source, pos, CardSelectorSingleton::Instance()->GetDrawMode()); - } - - if (targetQuad) - { - float backupX = targetQuad->mHotSpotX; - float backupY = targetQuad->mHotSpotY; - targetQuad->SetColor(ARGB(255,255,255,255)); - targetQuad->SetHotSpot(targetQuad->mWidth / 2, targetQuad->mHeight / 2); - float scale = mHeight / targetQuad->mHeight; - renderer->RenderQuad(targetQuad, x + 150, y + 15 * scale, 0, scale, scale); - targetQuad->SetHotSpot(backupX, backupY); - } - else if (alt2.size()) - { - mFont->DrawString(_(alt2).c_str(), x + 120, y); - } - } - - /* Ability */ - int StackAbility::resolve() - { - return (ability->resolve()); - } - void StackAbility::Render() - { - string action = ability->getMenuText(); - MTGCardInstance * source = ability->source; - string alt1 = source->getName(); - - Targetable * _target = ability->target; - if (ability->tc) - { - Targetable * t = ability->tc->getNextTarget(); - if (t) - _target = t; - } - Damageable * target = NULL; - if (_target != ability->source && (_target->typeAsTarget() == TARGET_CARD || _target->typeAsTarget() - == TARGET_PLAYER)) - { - target = (Damageable *) _target; - } - - JQuad * quad = NULL; - string alt2 = ""; - if (target) - { - quad = target->getIcon(); - if (target->type_as_damageable == DAMAGEABLE_MTGCARDINSTANCE) - { - alt2 = ((MTGCardInstance *) target)->name; - } - } - - Interruptible::Render(source, quad, alt1, alt2, action); - } - StackAbility::StackAbility(int id, MTGAbility * _ability) : - Interruptible(id), ability(_ability) - { - type = ACTION_ABILITY; - } - - ostream& StackAbility::toString(ostream& out) const - { - out << "StackAbility ::: ability : " << ability; - return out; - } - - const string StackAbility::getDisplayName() const - { - std::ostringstream stream; - stream << "StackAbility. (Source: " << ability->source->getDisplayName() << ")"; - - return stream.str(); - } - - /* Spell Cast */ - - Spell::Spell(MTGCardInstance * _source) : - Interruptible(0) - { - source = _source; - mHeight = 40; - type = ACTION_SPELL; - cost = NEW ManaCost(); - tc = NULL; - from = _source->getCurrentZone(); - } - - Spell::Spell(int id, MTGCardInstance * _source, TargetChooser * tc, ManaCost * _cost, int payResult) : - Interruptible(id), tc(tc), cost(_cost), payResult(payResult) - { - source = _source; - mHeight = 40; - type = ACTION_SPELL; - from = _source->getCurrentZone(); - } - - int Spell::computeX(MTGCardInstance * card) - { - ManaCost * c = cost->Diff(card->getManaCost()); - int x = c->getCost(Constants::MTG_NB_COLORS); - delete c; - return x; - } - - int Spell::computeXX(MTGCardInstance * card) - { - ManaCost * c = cost->Diff(card->getManaCost()); - int xx = c->getCost(Constants::MTG_NB_COLORS) / 2; - delete c; - return xx; - } - - bool Spell::FullfilledAlternateCost(const int &costType) - { - bool hasFullfilledAlternateCost = false; - - switch (costType) - { - case ManaCost::MANA_PAID_WITH_KICKER: - hasFullfilledAlternateCost = (payResult == ManaCost::MANA_PAID_WITH_KICKER); - break; - case ManaCost::MANA_PAID_WITH_ALTERNATIVE: - hasFullfilledAlternateCost = (payResult == ManaCost::MANA_PAID_WITH_ALTERNATIVE); - break; - case ManaCost::MANA_PAID_WITH_BUYBACK: - hasFullfilledAlternateCost = (payResult == ManaCost::MANA_PAID_WITH_BUYBACK); - break; - case ManaCost::MANA_PAID_WITH_FLASHBACK: - hasFullfilledAlternateCost = (payResult == ManaCost::MANA_PAID_WITH_FLASHBACK); - break; - case ManaCost::MANA_PAID_WITH_RETRACE: - hasFullfilledAlternateCost = (payResult == ManaCost::MANA_PAID_WITH_RETRACE); - break; - } - - return hasFullfilledAlternateCost; - } - - const string Spell::getDisplayName() const - { - return source->getName(); - } - Spell::~Spell() - { - SAFE_DELETE(cost); - SAFE_DELETE(tc); - } - - int Spell::resolve() - { - GameObserver * game = GameObserver::GetInstance(); - if (!source->hasType("instant") && !source->hasType("sorcery")) - { - Player * p = source->controller(); - source = p->game->putInZone(source, from, p->game->battlefield); - from = p->game->battlefield; - } - - //Play SFX - if (options[Options::SFXVOLUME].number > 0) - { - JSample * sample = source->getSample(); - if (sample) - { - JSoundSystem::GetInstance()->PlaySample(sample); - } - } - - AbilityFactory af; - af.addAbilities(game->mLayers->actionLayer()->getMaxId(), this); - return 1; - } - - MTGCardInstance * Spell::getNextCardTarget(MTGCardInstance * previous) - { - if (!tc) - return NULL; - return tc->getNextCardTarget(previous); - } - Player * Spell::getNextPlayerTarget(Player * previous) - { - if (!tc) - return NULL; - return tc->getNextPlayerTarget(previous); - } - Damageable * Spell::getNextDamageableTarget(Damageable * previous) - { - if (!tc) - return NULL; - return tc->getNextDamageableTarget(previous); - } - Interruptible * Spell::getNextInterruptible(Interruptible * previous, int type) - { - if (!tc) - return NULL; - return tc->getNextInterruptible(previous, type); - } - Spell * Spell::getNextSpellTarget(Spell * previous) - { - if (!tc) - return NULL; - return tc->getNextSpellTarget(previous); - } - Damage * Spell::getNextDamageTarget(Damage * previous) - { - if (!tc) - return NULL; - return tc->getNextDamageTarget(previous); - } - Targetable * Spell::getNextTarget(Targetable * previous, int type) - { - if (!tc) - return NULL; - return tc->getNextTarget(previous, type); - } - - int Spell::getNbTargets() - { - if (!tc) - return 0; - return tc->cursor; - } - - void Spell::Render() - { - string action = source->getName(); - string alt1 = ""; - - JQuad * quad = NULL; - string alt2 = ""; - Damageable * target = getNextDamageableTarget(); - if (target) - { - quad = target->getIcon(); - if (target->type_as_damageable == DAMAGEABLE_MTGCARDINSTANCE) - { - alt2 = ((MTGCardInstance *) target)->name; - } - } - Interruptible::Render(source, quad, alt1, alt2, action, true); - } - - ostream& Spell::toString(ostream& out) const - { - out << "Spell ::: cost : " << cost; - return out; - } - - /* Put a card in graveyard */ - - PutInGraveyard::PutInGraveyard(int id, MTGCardInstance * _card) : - Interruptible(id) - { - card = _card; - removeFromGame = 0; - type = ACTION_PUTINGRAVEYARD; - } - - int PutInGraveyard::resolve() - { - GameObserver * g = GameObserver::GetInstance(); - MTGGameZone * zone = card->getCurrentZone(); - if (zone == g->players[0]->game->inPlay || zone == g->players[1]->game->inPlay) - { - card->owner->game->putInZone(card, zone, card->owner->game->graveyard); - return 1; - } - return 0; - } - - void PutInGraveyard::Render() - { - WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); - mFont->SetBase(0); - mFont->SetScale(DEFAULT_MAIN_FONT_SCALE); - if (!removeFromGame) - { - mFont->DrawString(_("goes to graveyard").c_str(), x + 30, y, JGETEXT_LEFT); - } - else - { - mFont->DrawString(_("is exiled").c_str(), x + 30, y, JGETEXT_LEFT); - } - JRenderer * renderer = JRenderer::GetInstance(); - JQuad * quad = WResourceManager::Instance()->RetrieveCard(card, CACHE_THUMB); - if (quad) - { - quad->SetColor(ARGB(255,255,255,255)); - float scale = 30 / quad->mHeight; - renderer->RenderQuad(quad, x, y, 0, scale, scale); - } - else - { - mFont->DrawString(_(card->name).c_str(), x, y - 15); - } - } - - ostream& PutInGraveyard::toString(ostream& out) const - { - out << "PutInGraveyard ::: removeFromGame : " << removeFromGame; - return out; - } - - /* Draw a Card */ - DrawAction::DrawAction(int id, Player * _player, int _nbcards) : - Interruptible(id), nbcards(_nbcards), player(_player) - { - } - - int DrawAction::resolve() - { - for (int i = 0; i < nbcards; i++) - { - player->game->drawFromLibrary(); - } - return 1; - } - - void DrawAction::Render() - { - WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); - mFont->SetBase(0); - mFont->SetScale(DEFAULT_MAIN_FONT_SCALE); - char buffer[200]; - int playerId = 1; - if (player == GameObserver::GetInstance()->players[1]) - playerId = 2; - sprintf(buffer, _("Player %i draws %i card").c_str(), playerId, nbcards); - mFont->DrawString(buffer, x + 20, y, JGETEXT_LEFT); - } - - ostream& DrawAction::toString(ostream& out) const - { - out << "DrawAction ::: nbcards : " << nbcards << " ; player : " << player; - return out; - } - - /* The Action Stack itself */ - int ActionStack::addPutInGraveyard(MTGCardInstance * card) - { - PutInGraveyard * death = NEW PutInGraveyard(mCount, card); - addAction(death); - return 1; - } - - int ActionStack::addAbility(MTGAbility * ability) - { - StackAbility * stackAbility = NEW StackAbility(mCount, ability); - int result = addAction(stackAbility); - if (!game->players[0]->isAI() && ability->source->controller() == game->players[0] && 0 - == options[Options::INTERRUPTMYABILITIES].number) - interruptDecision[0] = DONT_INTERRUPT; - return result; - } - - int ActionStack::addDraw(Player * player, int nb_cards) - { - DrawAction * draw = NEW DrawAction(mCount, player, nb_cards); - addAction(draw); - GameObserver *g = GameObserver::GetInstance(); - WEvent * e = NEW WEventcardDraw(player, nb_cards); - g->receiveEvent(e); - return 1; - } - - int ActionStack::addDamage(MTGCardInstance * _source, Damageable * _target, int _damage) - { - Damage * damage = NEW Damage(_source, _target, _damage); - addAction(damage); - return 1; - } - - int ActionStack::AddNextGamePhase() - { - if (getNext(NULL, NOT_RESOLVED)) - return 0; - NextGamePhase * next = NEW NextGamePhase(mCount); - addAction(next); - int playerId = 0; - game->currentActionPlayer = game->GetInstance()->currentActionPlayer; - if (game->currentActionPlayer == game->players[1]) - { - playerId = 1; - } - interruptDecision[playerId] = 1; - return 1; - } - - int ActionStack::AddNextCombatStep() - { - if (getNext(NULL, NOT_RESOLVED)) - return 0; - NextGamePhase * next = NEW NextGamePhase(mCount); - addAction(next); - return 1; - } - - int ActionStack::setIsInterrupting(Player * player) - { - if (player == game->players[0]) - { - interruptDecision[0] = -1; - } - else - { - interruptDecision[1] = -1; - } - game->isInterrupting = player; - askIfWishesToInterrupt = NULL; - return 1; - } - - int ActionStack::addAction(Interruptible * action) - { - for (int i = 0; i < 2; i++) - { - interruptDecision[i] = 0; - } - Add(action); - DebugTrace("Action added to stack: " << action->getDisplayName()); - - return 1; - } - - Spell * ActionStack::addSpell(MTGCardInstance * _source, TargetChooser * tc, ManaCost * mana, int payResult, - int storm) - { - DebugTrace("ACTIONSTACK Add spell"); - if (storm > 0) - { - mana = NULL; - } - if (mana < 0) - { - mana = 0; - } - Spell * spell = NEW Spell(mCount, _source, tc, mana, payResult); - addAction(spell); - if (!game->players[0]->isAI() && _source->controller() == game->players[0] && 0 - == options[Options::INTERRUPTMYSPELLS].number) - interruptDecision[0] = DONT_INTERRUPT; - return spell; - } - - Interruptible * ActionStack::getAt(int id) - { - if (id < 0) - id = mCount + id; - if (id > mCount - 1) - return NULL; - return (Interruptible *) mObjects[id]; - } - - ActionStack::ActionStack(GameObserver* game) : - game(game) - { - for (int i = 0; i < 2; i++) - interruptDecision[i] = 0; - askIfWishesToInterrupt = NULL; - timer = -1; - currentState = -1; - mode = ACTIONSTACK_STANDARD; - checked = 0; - - } - - int ActionStack::has(MTGAbility * ability) - { - for (int i = 0; i < mCount; i++) - { - if (((Interruptible *) mObjects[i])->type == ACTION_ABILITY) - { - StackAbility * action = ((StackAbility *) mObjects[i]); - if (action->state == NOT_RESOLVED && action->ability == ability) - return 1; - } - } - return 0; - } - - int ActionStack::has(Interruptible * action) - { - for (int i = 0; i < mCount; i++) - { - if (mObjects[i] == action) - return 1; - } - return 0; - } - - int ActionStack::resolve() - { - Interruptible * action = getLatest(NOT_RESOLVED); - - if (!action) - return 0; - - DebugTrace("Resolving Action on stack: " << action->getDisplayName()); - if (action->resolve()) - { - action->state = RESOLVED_OK; - } - else - { - action->state = RESOLVED_NOK; - } - if (action->type == ACTION_DAMAGE) - ((Damage *) action)->target->afterDamage(); - - if (!getNext(NULL, NOT_RESOLVED)) - { - for (int i = 0; i < 2; i++) - { - interruptDecision[i] = 0; - } - } - else - { - for (int i = 0; i < 2; i++) - { - if (interruptDecision[i] != 2) - interruptDecision[i] = 0; - } - } - - return 1; - - } - - Interruptible * ActionStack::getPrevious(Interruptible * next, int type, int state, int display) - { - int n = getPreviousIndex(next, type, state, display); - if (n == -1) - return NULL; - return ((Interruptible *) mObjects[n]); - } - - int ActionStack::getPreviousIndex(Interruptible * next, int type, int state, int display) - { - int found = 0; - if (!next) - found = 1; - for (int i = mCount - 1; i >= 0; i--) - { - Interruptible * current = (Interruptible *) mObjects[i]; - if (found && (type == 0 || current->type == type) && (state == 0 || current->state == state) && (display - == -1 || current->display == display)) - { - return i; - } - if (current == next) - found = 1; - } - if (!found) - return getPreviousIndex(NULL, type, state, display); - return -1; - } - - int ActionStack::count(int type, int state, int display) - { - int result = 0; - for (int i = 0; i < mCount; i++) - { - Interruptible * current = (Interruptible *) mObjects[i]; - if ((type == 0 || current->type == type) && (state == 0 || current->state == state) && (display == -1 - || current->display == display)) - { - result++; - } - } - return result; - } - - Interruptible * ActionStack::getNext(Interruptible * previous, int type, int state, int display) - { - int n = getNextIndex(previous, type, state, display); - if (n == -1) - return NULL; - return ((Interruptible *) mObjects[n]); - } - - int ActionStack::getNextIndex(Interruptible * previous, int type, int state, int display) - { - int found = 0; - if (!previous) - found = 1; - for (int i = 0; i < mCount; i++) - { - Interruptible * current = (Interruptible *) mObjects[i]; - if (found && (type == 0 || current->type == type) && (state == 0 || current->state == state) && (display - == -1 || current->display == display)) - { - return i; - } - if (current == previous) - found = 1; - } - if (!found) - return getNextIndex(NULL, type, state, display); - return -1; - } - - Interruptible * ActionStack::getLatest(int state) - { - for (int i = mCount - 1; i >= 0; i--) - { - Interruptible * action = ((Interruptible *) mObjects[i]); - if (action->state == state) - return action; - } - return NULL; - } - - int ActionStack::receiveEventPlus(WEvent * event) - { - int result = 0; - for (int i = 0; i < mCount; ++i) - { - Interruptible * current = (Interruptible *) mObjects[i]; - result += current->receiveEvent(event); - } - return result; - } - - void ActionStack::Update(float dt) - { - askIfWishesToInterrupt = NULL; - //modal = 0; - GameObserver * game = GameObserver::GetInstance(); - TargetChooser * tc = game->getCurrentTargetChooser(); - int newState = game->getCurrentGamePhase(); - currentState = newState; - if (!tc) - checked = 0; - - //Select Stack's display mode - if (mode == ACTIONSTACK_STANDARD && tc && !checked) - { - checked = 1; - for (int i = 0; i < mCount; i++) - { - Interruptible * current = (Interruptible *) mObjects[i]; - if (tc->canTarget(current)) - { - if (mCurr < (int) mObjects.size() && mObjects[mCurr]) - mObjects[mCurr]->Leaving(JGE_BTN_UP); - current->display = 1; - mCurr = i; - mObjects[mCurr]->Entering(); - mode = ACTIONSTACK_TARGET; - modal = 1; - } - else - { - current->display = 0; - } - } - if (mode != ACTIONSTACK_TARGET) - { - } - } - else if (mode == ACTIONSTACK_TARGET && !tc) - { - mode = ACTIONSTACK_STANDARD; - checked = 0; - } - - if (mode == ACTIONSTACK_STANDARD) - { - modal = 0; - if (getLatest(NOT_RESOLVED)) - { - int currentPlayerId = 0; - int otherPlayerId = 1; - if (game->currentlyActing() != game->players[0]) - { - currentPlayerId = 1; - otherPlayerId = 0; - } - if (interruptDecision[currentPlayerId] == NOT_DECIDED) - { - askIfWishesToInterrupt = game->players[currentPlayerId]; - game->isInterrupting = game->players[currentPlayerId]; - modal = 1; - } - else if (interruptDecision[currentPlayerId] == INTERRUPT) - { - game->isInterrupting = game->players[currentPlayerId]; - - } - else - { - if (interruptDecision[otherPlayerId] == NOT_DECIDED) - { - askIfWishesToInterrupt = game->players[otherPlayerId]; - game->isInterrupting = game->players[otherPlayerId]; - modal = 1; - } - else if (interruptDecision[otherPlayerId] == INTERRUPT) - { - game->isInterrupting = game->players[otherPlayerId]; - } - else - { - resolve(); - } - } - } - } - else if (mode == ACTIONSTACK_TARGET) - { - GuiLayer::Update(dt); - } - if (askIfWishesToInterrupt) - { - // WALDORF - added code to use a game option setting to determine how - // long the Interrupt timer should be. If it is set to zero (0), the - // game will wait for ever for the user to make a selection. - if (options[Options::INTERRUPT_SECONDS].number > 0) - { - if (timer < 0) - timer = options[Options::INTERRUPT_SECONDS].number; - timer -= dt; - if (timer < 0) - cancelInterruptOffer(); - } - } - } - - void ActionStack::cancelInterruptOffer(int cancelMode) - { - if (game->isInterrupting == game->players[0]) - { - interruptDecision[0] = cancelMode; - } - else - { - interruptDecision[1] = cancelMode; - } - askIfWishesToInterrupt = NULL; - game->isInterrupting = NULL; - timer = -1; - } - - void ActionStack::endOfInterruption() - { - if (game->isInterrupting == game->players[0]) - { - interruptDecision[0] = 0; - } - else - { - interruptDecision[1] = 0; - } - game->isInterrupting = NULL; - } - - bool ActionStack::CheckUserInput(JButton key) - { - JButton trigger = (options[Options::REVERSETRIGGERS].number ? JGE_BTN_NEXT : JGE_BTN_PREV); - if (mode == ACTIONSTACK_STANDARD) - { - if (askIfWishesToInterrupt) - { - if (JGE_BTN_SEC == key) - { - setIsInterrupting(askIfWishesToInterrupt); - return true; - } - else if ((JGE_BTN_OK == key) || (trigger == key)) - { - cancelInterruptOffer(); - return true; - } - else if ((JGE_BTN_PRI == key)) - { - cancelInterruptOffer(2); - return true; - } - return true; - } - else if (game->isInterrupting) - { - if (JGE_BTN_SEC == key) - { - endOfInterruption(); - return true; - } - } - } - else if (mode == ACTIONSTACK_TARGET) - { - if (modal) - { - if (JGE_BTN_UP == key) - { - if (mObjects[mCurr]) - { - int n = getPreviousIndex(((Interruptible *) mObjects[mCurr]), 0, 0, 1); - if (n != -1 && n != mCurr && mObjects[mCurr]->Leaving(JGE_BTN_UP)) - { - mCurr = n; - mObjects[mCurr]->Entering(); -DebugTrace ("ACTIONSTACK UP TO mCurr = " << mCurr); - } - } - return true; - } - else if (JGE_BTN_DOWN == key) - { - if( mObjects[mCurr]) - { - int n = getNextIndex(((Interruptible *) mObjects[mCurr]), 0, 0, 1); - if (n!= -1 && n != mCurr && mObjects[mCurr]->Leaving(JGE_BTN_DOWN)) - { - mCurr = n; - mObjects[mCurr]->Entering(); - DebugTrace("ACTIONSTACK DOWN TO mCurr " << mCurr); - } - } - return true; - } - else if (JGE_BTN_OK == key) - { - DebugTrace("ACTIONSTACK CLICKED mCurr = " << mCurr); - - game->stackObjectClicked(((Interruptible *) mObjects[mCurr])); - return true; - } - return true; //Steal the input to other layers if we're visible - } - if (JGE_BTN_CANCEL == key) - { - if (modal) modal = 0; - else modal = 1; - return true; - } - } - return false; +} + +void Interruptible::Render(MTGCardInstance * source, JQuad * targetQuad, string alt1, string alt2, string action, + bool bigQuad) +{ + WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); + mFont->SetColor(ARGB(255,255,255,255)); + mFont->SetScale(DEFAULT_MAIN_FONT_SCALE); + mFont->DrawString(_(action).c_str(), x + 30, y, JGETEXT_LEFT); + JRenderer * renderer = JRenderer::GetInstance(); + JQuad * quad = WResourceManager::Instance()->RetrieveCard(source, CACHE_THUMB); + if (!quad) + quad = CardGui::AlternateThumbQuad(source); + if (quad) + { + quad->SetColor(ARGB(255,255,255,255)); + float scale = mHeight / quad->mHeight; + renderer->RenderQuad(quad, x + 10 * scale, y + 15 * scale, 0, scale, scale); + } + else if (alt1.size()) + { + mFont->DrawString(_(alt1).c_str(), x, y - 15); + } + + if (bigQuad) + { + Pos pos = Pos(CardGui::BigWidth / 2, CardGui::BigHeight / 2 - 10, 1.0, 0.0, 220); + CardGui::DrawCard(source, pos, CardSelectorSingleton::Instance()->GetDrawMode()); + } + + if (targetQuad) + { + float backupX = targetQuad->mHotSpotX; + float backupY = targetQuad->mHotSpotY; + targetQuad->SetColor(ARGB(255,255,255,255)); + targetQuad->SetHotSpot(targetQuad->mWidth / 2, targetQuad->mHeight / 2); + float scale = mHeight / targetQuad->mHeight; + renderer->RenderQuad(targetQuad, x + 150, y + 15 * scale, 0, scale, scale); + targetQuad->SetHotSpot(backupX, backupY); + } + else if (alt2.size()) + { + mFont->DrawString(_(alt2).c_str(), x + 120, y); + } +} + +/* Ability */ +int StackAbility::resolve() +{ + return (ability->resolve()); +} +void StackAbility::Render() +{ + string action = ability->getMenuText(); + MTGCardInstance * source = ability->source; + string alt1 = source->getName(); + + Targetable * _target = ability->target; + if (ability->tc) + { + Targetable * t = ability->tc->getNextTarget(); + if (t) + _target = t; + } + Damageable * target = NULL; + if (_target != ability->source && (_target->typeAsTarget() == TARGET_CARD || _target->typeAsTarget() + == TARGET_PLAYER)) + { + target = (Damageable *) _target; + } + + JQuad * quad = NULL; + string alt2 = ""; + if (target) + { + quad = target->getIcon(); + if (target->type_as_damageable == DAMAGEABLE_MTGCARDINSTANCE) + { + alt2 = ((MTGCardInstance *) target)->name; + } + } + + Interruptible::Render(source, quad, alt1, alt2, action); +} +StackAbility::StackAbility(int id, MTGAbility * _ability) : +Interruptible(id), ability(_ability) +{ + type = ACTION_ABILITY; +} + +ostream& StackAbility::toString(ostream& out) const +{ + out << "StackAbility ::: ability : " << ability; + return out; +} + +const string StackAbility::getDisplayName() const +{ + std::ostringstream stream; + stream << "StackAbility. (Source: " << ability->source->getDisplayName() << ")"; + + return stream.str(); +} + +/* Spell Cast */ + +Spell::Spell(MTGCardInstance * _source) : +Interruptible(0) +{ + source = _source; + mHeight = 40; + type = ACTION_SPELL; + cost = NEW ManaCost(); + tc = NULL; + from = _source->getCurrentZone(); +} + +Spell::Spell(int id, MTGCardInstance * _source, TargetChooser * tc, ManaCost * _cost, int payResult) : +Interruptible(id), tc(tc), cost(_cost), payResult(payResult) +{ + source = _source; + mHeight = 40; + type = ACTION_SPELL; + from = _source->getCurrentZone(); +} + +int Spell::computeX(MTGCardInstance * card) +{ + ManaCost * c = cost->Diff(card->getManaCost()); + int x = c->getCost(Constants::MTG_NB_COLORS); + delete c; + return x; +} + +int Spell::computeXX(MTGCardInstance * card) +{ + ManaCost * c = cost->Diff(card->getManaCost()); + int xx = c->getCost(Constants::MTG_NB_COLORS) / 2; + delete c; + return xx; +} + +bool Spell::FullfilledAlternateCost(const int &costType) +{ + bool hasFullfilledAlternateCost = false; + + switch (costType) + { + case ManaCost::MANA_PAID_WITH_KICKER: + hasFullfilledAlternateCost = (payResult == ManaCost::MANA_PAID_WITH_KICKER); + break; + case ManaCost::MANA_PAID_WITH_ALTERNATIVE: + hasFullfilledAlternateCost = (payResult == ManaCost::MANA_PAID_WITH_ALTERNATIVE); + break; + case ManaCost::MANA_PAID_WITH_BUYBACK: + hasFullfilledAlternateCost = (payResult == ManaCost::MANA_PAID_WITH_BUYBACK); + break; + case ManaCost::MANA_PAID_WITH_FLASHBACK: + hasFullfilledAlternateCost = (payResult == ManaCost::MANA_PAID_WITH_FLASHBACK); + break; + case ManaCost::MANA_PAID_WITH_RETRACE: + hasFullfilledAlternateCost = (payResult == ManaCost::MANA_PAID_WITH_RETRACE); + break; + } + + return hasFullfilledAlternateCost; +} + +const string Spell::getDisplayName() const +{ + return source->getName(); +} +Spell::~Spell() +{ + SAFE_DELETE(cost); + SAFE_DELETE(tc); +} + +int Spell::resolve() +{ + GameObserver * game = GameObserver::GetInstance(); + if (!source->hasType("instant") && !source->hasType("sorcery")) + { + Player * p = source->controller(); + source = p->game->putInZone(source, from, p->game->battlefield); + from = p->game->battlefield; + } + + //Play SFX + if (options[Options::SFXVOLUME].number > 0) + { + JSample * sample = source->getSample(); + if (sample) + { + JSoundSystem::GetInstance()->PlaySample(sample); + } + } + + AbilityFactory af; + af.addAbilities(game->mLayers->actionLayer()->getMaxId(), this); + return 1; +} + +MTGCardInstance * Spell::getNextCardTarget(MTGCardInstance * previous) +{ + if (!tc) + return NULL; + return tc->getNextCardTarget(previous); +} +Player * Spell::getNextPlayerTarget(Player * previous) +{ + if (!tc) + return NULL; + return tc->getNextPlayerTarget(previous); +} +Damageable * Spell::getNextDamageableTarget(Damageable * previous) +{ + if (!tc) + return NULL; + return tc->getNextDamageableTarget(previous); +} +Interruptible * Spell::getNextInterruptible(Interruptible * previous, int type) +{ + if (!tc) + return NULL; + return tc->getNextInterruptible(previous, type); +} +Spell * Spell::getNextSpellTarget(Spell * previous) +{ + if (!tc) + return NULL; + return tc->getNextSpellTarget(previous); +} +Damage * Spell::getNextDamageTarget(Damage * previous) +{ + if (!tc) + return NULL; + return tc->getNextDamageTarget(previous); +} +Targetable * Spell::getNextTarget(Targetable * previous, int type) +{ + if (!tc) + return NULL; + return tc->getNextTarget(previous, type); +} + +int Spell::getNbTargets() +{ + if (!tc) + return 0; + return tc->cursor; +} + +void Spell::Render() +{ + string action = source->getName(); + string alt1 = ""; + + JQuad * quad = NULL; + string alt2 = ""; + Damageable * target = getNextDamageableTarget(); + if (target) + { + quad = target->getIcon(); + if (target->type_as_damageable == DAMAGEABLE_MTGCARDINSTANCE) + { + alt2 = ((MTGCardInstance *) target)->name; + } + } + Interruptible::Render(source, quad, alt1, alt2, action, true); +} + +ostream& Spell::toString(ostream& out) const +{ + out << "Spell ::: cost : " << cost; + return out; +} + +/* Put a card in graveyard */ + +PutInGraveyard::PutInGraveyard(int id, MTGCardInstance * _card) : +Interruptible(id) +{ + card = _card; + removeFromGame = 0; + type = ACTION_PUTINGRAVEYARD; +} + +int PutInGraveyard::resolve() +{ + GameObserver * g = GameObserver::GetInstance(); + MTGGameZone * zone = card->getCurrentZone(); + if (zone == g->players[0]->game->inPlay || zone == g->players[1]->game->inPlay) + { + card->owner->game->putInZone(card, zone, card->owner->game->graveyard); + return 1; + } + return 0; +} + +void PutInGraveyard::Render() +{ + WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); + mFont->SetBase(0); + mFont->SetScale(DEFAULT_MAIN_FONT_SCALE); + if (!removeFromGame) + { + mFont->DrawString(_("goes to graveyard").c_str(), x + 30, y, JGETEXT_LEFT); + } + else + { + mFont->DrawString(_("is exiled").c_str(), x + 30, y, JGETEXT_LEFT); + } + JRenderer * renderer = JRenderer::GetInstance(); + JQuad * quad = WResourceManager::Instance()->RetrieveCard(card, CACHE_THUMB); + if (quad) + { + quad->SetColor(ARGB(255,255,255,255)); + float scale = 30 / quad->mHeight; + renderer->RenderQuad(quad, x, y, 0, scale, scale); + } + else + { + mFont->DrawString(_(card->name).c_str(), x, y - 15); + } +} + +ostream& PutInGraveyard::toString(ostream& out) const +{ + out << "PutInGraveyard ::: removeFromGame : " << removeFromGame; + return out; +} + +/* Draw a Card */ +DrawAction::DrawAction(int id, Player * _player, int _nbcards) : +Interruptible(id), nbcards(_nbcards), player(_player) +{ +} + +int DrawAction::resolve() +{ + for (int i = 0; i < nbcards; i++) + { + player->game->drawFromLibrary(); + } + return 1; +} + +void DrawAction::Render() +{ + WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); + mFont->SetBase(0); + mFont->SetScale(DEFAULT_MAIN_FONT_SCALE); + char buffer[200]; + int playerId = 1; + if (player == GameObserver::GetInstance()->players[1]) + playerId = 2; + sprintf(buffer, _("Player %i draws %i card").c_str(), playerId, nbcards); + mFont->DrawString(buffer, x + 20, y, JGETEXT_LEFT); +} + +ostream& DrawAction::toString(ostream& out) const +{ + out << "DrawAction ::: nbcards : " << nbcards << " ; player : " << player; + return out; +} + +/* The Action Stack itself */ +int ActionStack::addPutInGraveyard(MTGCardInstance * card) +{ + PutInGraveyard * death = NEW PutInGraveyard(mCount, card); + addAction(death); + return 1; +} + +int ActionStack::addAbility(MTGAbility * ability) +{ + StackAbility * stackAbility = NEW StackAbility(mCount, ability); + int result = addAction(stackAbility); + if (!game->players[0]->isAI() && ability->source->controller() == game->players[0] && 0 + == options[Options::INTERRUPTMYABILITIES].number) + interruptDecision[0] = DONT_INTERRUPT; + return result; +} + +int ActionStack::addDraw(Player * player, int nb_cards) +{ + DrawAction * draw = NEW DrawAction(mCount, player, nb_cards); + addAction(draw); + GameObserver *g = GameObserver::GetInstance(); + WEvent * e = NEW WEventcardDraw(player, nb_cards); + g->receiveEvent(e); + return 1; +} + +int ActionStack::addDamage(MTGCardInstance * _source, Damageable * _target, int _damage) +{ + Damage * damage = NEW Damage(_source, _target, _damage); + addAction(damage); + return 1; +} + +int ActionStack::AddNextGamePhase() +{ + if (getNext(NULL, NOT_RESOLVED)) + return 0; + NextGamePhase * next = NEW NextGamePhase(mCount); + addAction(next); + int playerId = 0; + game->currentActionPlayer = game->GetInstance()->currentActionPlayer; + if (game->currentActionPlayer == game->players[1]) + { + playerId = 1; + } + interruptDecision[playerId] = 1; + return 1; +} + +int ActionStack::AddNextCombatStep() +{ + if (getNext(NULL, NOT_RESOLVED)) + return 0; + NextGamePhase * next = NEW NextGamePhase(mCount); + addAction(next); + return 1; +} + +int ActionStack::setIsInterrupting(Player * player) +{ + if (player == game->players[0]) + { + interruptDecision[0] = -1; + } + else + { + interruptDecision[1] = -1; + } + game->isInterrupting = player; + askIfWishesToInterrupt = NULL; + return 1; +} + +int ActionStack::addAction(Interruptible * action) +{ + for (int i = 0; i < 2; i++) + { + interruptDecision[i] = 0; + } + Add(action); + DebugTrace("Action added to stack: " << action->getDisplayName()); + + return 1; +} + +Spell * ActionStack::addSpell(MTGCardInstance * _source, TargetChooser * tc, ManaCost * mana, int payResult, + int storm) +{ + DebugTrace("ACTIONSTACK Add spell"); + if (storm > 0) + { + mana = NULL; + } + if (mana < 0) + { + mana = 0; + } + Spell * spell = NEW Spell(mCount, _source, tc, mana, payResult); + addAction(spell); + if (!game->players[0]->isAI() && _source->controller() == game->players[0] && 0 + == options[Options::INTERRUPTMYSPELLS].number) + interruptDecision[0] = DONT_INTERRUPT; + return spell; +} + +Interruptible * ActionStack::getAt(int id) +{ + if (id < 0) + id = mCount + id; + if (id > mCount - 1) + return NULL; + return (Interruptible *) mObjects[id]; +} + +ActionStack::ActionStack(GameObserver* game) : +game(game) +{ + for (int i = 0; i < 2; i++) + interruptDecision[i] = 0; + askIfWishesToInterrupt = NULL; + timer = -1; + currentState = -1; + mode = ACTIONSTACK_STANDARD; + checked = 0; + +} + +int ActionStack::has(MTGAbility * ability) +{ + for (int i = 0; i < mCount; i++) + { + if (((Interruptible *) mObjects[i])->type == ACTION_ABILITY) + { + StackAbility * action = ((StackAbility *) mObjects[i]); + if (action->state == NOT_RESOLVED && action->ability == ability) + return 1; + } + } + return 0; +} + +int ActionStack::has(Interruptible * action) +{ + for (int i = 0; i < mCount; i++) + { + if (mObjects[i] == action) + return 1; + } + return 0; +} + +int ActionStack::resolve() +{ + Interruptible * action = getLatest(NOT_RESOLVED); + + if (!action) + return 0; + + DebugTrace("Resolving Action on stack: " << action->getDisplayName()); + if (action->resolve()) + { + action->state = RESOLVED_OK; + } + else + { + action->state = RESOLVED_NOK; + } + if (action->type == ACTION_DAMAGE) + ((Damage *) action)->target->afterDamage(); + + if (!getNext(NULL, NOT_RESOLVED)) + { + for (int i = 0; i < 2; i++) + { + interruptDecision[i] = 0; + } + } + else + { + for (int i = 0; i < 2; i++) + { + if (interruptDecision[i] != 2) + interruptDecision[i] = 0; + } + } + + return 1; + +} + +Interruptible * ActionStack::getPrevious(Interruptible * next, int type, int state, int display) +{ + int n = getPreviousIndex(next, type, state, display); + if (n == -1) + return NULL; + return ((Interruptible *) mObjects[n]); +} + +int ActionStack::getPreviousIndex(Interruptible * next, int type, int state, int display) +{ + int found = 0; + if (!next) + found = 1; + for (int i = mCount - 1; i >= 0; i--) + { + Interruptible * current = (Interruptible *) mObjects[i]; + if (found && (type == 0 || current->type == type) && (state == 0 || current->state == state) && (display + == -1 || current->display == display)) + { + return i; + } + if (current == next) + found = 1; + } + if (!found) + return getPreviousIndex(NULL, type, state, display); + return -1; +} + +int ActionStack::count(int type, int state, int display) +{ + int result = 0; + for (int i = 0; i < mCount; i++) + { + Interruptible * current = (Interruptible *) mObjects[i]; + if ((type == 0 || current->type == type) && (state == 0 || current->state == state) && (display == -1 + || current->display == display)) + { + result++; + } + } + return result; +} + +Interruptible * ActionStack::getNext(Interruptible * previous, int type, int state, int display) +{ + int n = getNextIndex(previous, type, state, display); + if (n == -1) + return NULL; + return ((Interruptible *) mObjects[n]); +} + +int ActionStack::getNextIndex(Interruptible * previous, int type, int state, int display) +{ + int found = 0; + if (!previous) + found = 1; + for (int i = 0; i < mCount; i++) + { + Interruptible * current = (Interruptible *) mObjects[i]; + if (found && (type == 0 || current->type == type) && (state == 0 || current->state == state) && (display + == -1 || current->display == display)) + { + return i; + } + if (current == previous) + found = 1; + } + if (!found) + return getNextIndex(NULL, type, state, display); + return -1; +} + +Interruptible * ActionStack::getLatest(int state) +{ + for (int i = mCount - 1; i >= 0; i--) + { + Interruptible * action = ((Interruptible *) mObjects[i]); + if (action->state == state) + return action; + } + return NULL; +} + +int ActionStack::receiveEventPlus(WEvent * event) +{ + int result = 0; + for (int i = 0; i < mCount; ++i) + { + Interruptible * current = (Interruptible *) mObjects[i]; + result += current->receiveEvent(event); + } + return result; +} + +void ActionStack::Update(float dt) +{ + askIfWishesToInterrupt = NULL; + //modal = 0; + GameObserver * game = GameObserver::GetInstance(); + TargetChooser * tc = game->getCurrentTargetChooser(); + int newState = game->getCurrentGamePhase(); + currentState = newState; + if (!tc) + checked = 0; + + //Select Stack's display mode + if (mode == ACTIONSTACK_STANDARD && tc && !checked) + { + checked = 1; + for (int i = 0; i < mCount; i++) + { + Interruptible * current = (Interruptible *) mObjects[i]; + if (tc->canTarget(current)) + { + if (mCurr < (int) mObjects.size() && mObjects[mCurr]) + mObjects[mCurr]->Leaving(JGE_BTN_UP); + current->display = 1; + mCurr = i; + mObjects[mCurr]->Entering(); + mode = ACTIONSTACK_TARGET; + modal = 1; } + else + { + current->display = 0; + } + } + if (mode != ACTIONSTACK_TARGET) + { + } + } + else if (mode == ACTIONSTACK_TARGET && !tc) + { + mode = ACTIONSTACK_STANDARD; + checked = 0; + } - //Cleans history of last turn + if (mode == ACTIONSTACK_STANDARD) + { + modal = 0; + if (getLatest(NOT_RESOLVED)) + { + int currentPlayerId = 0; + int otherPlayerId = 1; + if (game->currentlyActing() != game->players[0]) + { + currentPlayerId = 1; + otherPlayerId = 0; + } + if (interruptDecision[currentPlayerId] == NOT_DECIDED) + { + askIfWishesToInterrupt = game->players[currentPlayerId]; + game->isInterrupting = game->players[currentPlayerId]; + modal = 1; + } + else if (interruptDecision[currentPlayerId] == INTERRUPT) + { + game->isInterrupting = game->players[currentPlayerId]; + + } + else + { + if (interruptDecision[otherPlayerId] == NOT_DECIDED) + { + askIfWishesToInterrupt = game->players[otherPlayerId]; + game->isInterrupting = game->players[otherPlayerId]; + modal = 1; + } + else if (interruptDecision[otherPlayerId] == INTERRUPT) + { + game->isInterrupting = game->players[otherPlayerId]; + } + else + { + resolve(); + } + } + } + } + else if (mode == ACTIONSTACK_TARGET) + { + GuiLayer::Update(dt); + } + if (askIfWishesToInterrupt) + { + // WALDORF - added code to use a game option setting to determine how + // long the Interrupt timer should be. If it is set to zero (0), the + // game will wait for ever for the user to make a selection. + if (options[Options::INTERRUPT_SECONDS].number > 0) + { + if (timer < 0) + timer = options[Options::INTERRUPT_SECONDS].number; + timer -= dt; + if (timer < 0) + cancelInterruptOffer(); + } + } +} + +void ActionStack::cancelInterruptOffer(int cancelMode) +{ + if (game->isInterrupting == game->players[0]) + { + interruptDecision[0] = cancelMode; + } + else + { + interruptDecision[1] = cancelMode; + } + askIfWishesToInterrupt = NULL; + game->isInterrupting = NULL; + timer = -1; +} + +void ActionStack::endOfInterruption() +{ + if (game->isInterrupting == game->players[0]) + { + interruptDecision[0] = 0; + } + else + { + interruptDecision[1] = 0; + } + game->isInterrupting = NULL; +} + +bool ActionStack::CheckUserInput(JButton key) +{ + JButton trigger = (options[Options::REVERSETRIGGERS].number ? JGE_BTN_NEXT : JGE_BTN_PREV); + if (mode == ACTIONSTACK_STANDARD) + { + if (askIfWishesToInterrupt) + { + if (JGE_BTN_SEC == key) + { + setIsInterrupting(askIfWishesToInterrupt); + return true; + } + else if ((JGE_BTN_OK == key) || (trigger == key)) + { + cancelInterruptOffer(); + return true; + } + else if ((JGE_BTN_PRI == key)) + { + cancelInterruptOffer(2); + return true; + } + return true; + } + else if (game->isInterrupting) + { + if (JGE_BTN_SEC == key) + { + endOfInterruption(); + return true; + } + } + } + else if (mode == ACTIONSTACK_TARGET) + { + if (modal) + { + if (JGE_BTN_UP == key) + { + if (mObjects[mCurr]) + { + int n = getPreviousIndex(((Interruptible *) mObjects[mCurr]), 0, 0, 1); + if (n != -1 && n != mCurr && mObjects[mCurr]->Leaving(JGE_BTN_UP)) + { + mCurr = n; + mObjects[mCurr]->Entering(); + DebugTrace ("ACTIONSTACK UP TO mCurr = " << mCurr); + } + } + return true; + } + else if (JGE_BTN_DOWN == key) + { + if( mObjects[mCurr]) + { + int n = getNextIndex(((Interruptible *) mObjects[mCurr]), 0, 0, 1); + if (n!= -1 && n != mCurr && mObjects[mCurr]->Leaving(JGE_BTN_DOWN)) + { + mCurr = n; + mObjects[mCurr]->Entering(); + DebugTrace("ACTIONSTACK DOWN TO mCurr " << mCurr); + } + } + return true; + } + else if (JGE_BTN_OK == key) + { + DebugTrace("ACTIONSTACK CLICKED mCurr = " << mCurr); + + game->stackObjectClicked(((Interruptible *) mObjects[mCurr])); + return true; + } + return true; //Steal the input to other layers if we're visible + } + if (JGE_BTN_CANCEL == key) + { + if (modal) modal = 0; + else modal = 1; + return true; + } + } + return false; +} + +//Cleans history of last turn int ActionStack::garbageCollect() { std::vector::iterator iter = mObjects.begin(); @@ -1098,44 +1098,44 @@ void Interruptible::Dump() string stype, sstate, sdisplay = ""; switch (type) { - case ACTION_SPELL: + case ACTION_SPELL: stype = "spell"; break; - case ACTION_DAMAGE: + case ACTION_DAMAGE: stype = "damage"; break; - case ACTION_DAMAGES: + case ACTION_DAMAGES: stype = "damages"; break; - case ACTION_NEXTGAMEPHASE: + case ACTION_NEXTGAMEPHASE: stype = "next phase"; break; - case ACTION_DRAW: + case ACTION_DRAW: stype = "draw"; break; - case ACTION_PUTINGRAVEYARD: + case ACTION_PUTINGRAVEYARD: stype = "put in graveyard"; break; - case ACTION_ABILITY: + case ACTION_ABILITY: stype = "ability"; break; - default: + default: stype = "unknown"; break; } switch(state) { - case NOT_RESOLVED: + case NOT_RESOLVED: sstate = "not resolved"; break; - case RESOLVED_OK: + case RESOLVED_OK: sstate = "resolved"; break; - case RESOLVED_NOK: + case RESOLVED_NOK: sstate = "fizzled"; break; - default: + default: sstate = "unknown"; break; }