void AIStats::Render() { GameObserver * g = player->getObserver(); float x0 = 10; if (player == g->players[1]) x0 = 280; JRenderer::GetInstance()->FillRoundRect(x0, 10, 200, 180, 5, ARGB(50,0,0,0)); WFont * f = g->getResourceManager()->GetWFont(Fonts::MAIN_FONT); int i = 0; char buffer[512]; list<AIStat *>::iterator it; for (it = stats.begin(); it != stats.end(); ++it) { if (i > 10) break; AIStat * stat = *it; if (stat->value > 0) { MTGCard * card = MTGCollection()->getCardById(stat->source); if (card) { sprintf(buffer, "%s %i", card->data->getName().c_str(), stat->value); f->DrawString(buffer, x0 + 5, 10 + 16 * (float) i); i++; } } } }
int Counters::addCounter(const char * _name, int _power, int _toughness) { /*420.5n If a permanent has both a +1/+1 counter and a -1/-1 counter on it, N +1/+1 and N -1/-1 counters are removed from it, where N is the smaller of the number of +1/+1 and -1/-1 counters on it.*/ GameObserver *g = target->getObserver(); WEvent * e = NEW WEventCounters(this,_name,_power,_toughness); dynamic_cast<WEventCounters*>(e)->targetCard = this->target; if (e == g->replacementEffects->replace(e)) { for (int i = 0; i < mCount; i++) { if (counters[i]->sameAs(_name, _power, _toughness)) { counters[i]->added(); counters[i]->nb++; WEvent * j = NEW WEventCounters(this,_name,_power,_toughness,true,false); dynamic_cast<WEventCounters*>(j)->targetCard = this->target; g->receiveEvent(j); delete(e); return mCount; } } Counter * counter = NEW Counter(target, _name, _power, _toughness); counters.push_back(counter); counter->added(); WEvent * w = NEW WEventCounters(this,_name,_power,_toughness,true,false); dynamic_cast<WEventCounters*>(w)->targetCard = this->target; g->receiveEvent(w); mCount++; this->target->doDamageTest = 1; this->target->afterDamage(); } delete(e); return mCount; }
int AIAction::clickMultiAct(vector<Targetable*>& actionTargets) { GameObserver * g = owner->getObserver(); TargetChooser * tc = g->getCurrentTargetChooser(); if(!tc) return 0; vector<Targetable*>::iterator ite = actionTargets.begin(); while(ite != actionTargets.end()) { MTGCardInstance * card = ((MTGCardInstance *) (*ite)); if(card == (MTGCardInstance*)tc->source)//click source first. { g->cardClick(card); ite = actionTargets.erase(ite); continue; } ++ite; } //shuffle to make it less predictable, otherwise ai will always seem to target from right to left. making it very obvious. owner->getRandomGenerator()->random_shuffle(actionTargets.begin(), actionTargets.end()); for(int k = 0 ;k < int(actionTargets.size()) && k < tc->maxtargets; k++) { if (MTGCardInstance * card = dynamic_cast<MTGCardInstance *>(actionTargets[k])) { if(k+1 == int(actionTargets.size())) tc->done = true; g->cardClick(card); } } tc->attemptsToFill++; return 1; }
int Counters::removeCounter(const char * _name, int _power, int _toughness) { for (int i = 0; i < mCount; i++) { if (counters[i]->sameAs(_name, _power, _toughness)) { if (counters[i]->nb < 1) return 0; counters[i]->removed(); counters[i]->nb--; GameObserver *g = target->getObserver(); WEvent * e = NEW WEventCounters(this,_name,_power,_toughness,false,true); dynamic_cast<WEventCounters*>(e)->targetCard = this->target; g->receiveEvent(e); //special case:if a card is suspended and no longer has a time counter when the last is removed, the card is cast. if (target->suspended && !target->counters->hasCounter("time",0,0)) { GameObserver * game = target->getObserver(); MTGCardInstance * copy = target->controller()->game->putInZone(target, target->currentZone, target->controller()->game->stack); game->mLayers->stackLayer()->addSpell(copy, game->targetChooser, NULL,1, 0); game->targetChooser = NULL; } return mCount; } } return 0; }
/* * Starts running the game or continues a last run that was stopped * * quit_at_step: -1 to ignore step count */ void Game::run(GameObserver& observer, bool pause_at_end_of_input, int stop_at_step) { REQUIRE(initialised); bool stop_at_end_of_input = !pause_at_end_of_input; while (!observer.should_stop() && stop_at_step != get_steps() && !get_state().is_game_over()) { if (!observer.is_paused()) { auto input = get_input(); if (input.empty()) { if (stop_at_end_of_input) { break; } else { stop_at_end_of_input = true; observer.pause(); } } else { if (act(input)) { observer.finished_step(get_state()); } } } } }
void MTGPlayerCards::discardRandom(MTGGameZone * from, MTGCardInstance *) { if (!from->nb_cards) return; int r = owner->getObserver()->getRandomGenerator()->random() % (from->nb_cards); WEvent * e = NEW WEventCardDiscard(from->cards[r]); GameObserver * game = owner->getObserver(); game->receiveEvent(e); putInZone(from->cards[r], from, graveyard); }
int Counter::cancelCounter(int power, int toughness) { while(this->target->counters->hasCounter(power,toughness) && this->target->counters->hasCounter(power*-1,toughness*-1)) { GameObserver *g = this->target->getObserver(); this->removed(); this->nb--; WEvent * t = NEW WEventCounters(NULL,"",power*-1,toughness*-1,false,true); dynamic_cast<WEventCounters*>(t)->targetCard = this->target; g->receiveEvent(t); this->target->counters->removeCounter(power,toughness); } return 1; }
int SacrificeCost::doPay() { if (target) { MTGCardInstance * beforeCard = target; source->storedCard = target->createSnapShot(); target->controller()->game->putInGraveyard(target); WEvent * e = NEW WEventCardSacrifice(beforeCard,target); GameObserver * game = target->owner->getObserver(); game->receiveEvent(e); target = NULL; if (tc) tc->initTargets(); return 1; } return 0; }
int CycleCost::doPay() { MTGCardInstance * _source = (MTGCardInstance *) source; if (_source) { WEvent * e = NEW WEventCardDiscard(target);//cycling sends 2 events one for the discard and one for the specific cycle trigger GameObserver * game = _source->owner->getObserver(); game->receiveEvent(e); WEvent * e2 = NEW WEventCardCycle(_source); game->receiveEvent(e2); _source->controller()->game->putInGraveyard(_source); if (tc) tc->initTargets(); return 1; } return 0; }
int DiscardCost::doPay() { MTGCardInstance * _target = (MTGCardInstance *) target; if (target) { source->storedCard = target->createSnapShot(); WEvent * e = NEW WEventCardDiscard(target); GameObserver * game = target->owner->getObserver(); game->receiveEvent(e); _target->controller()->game->putInGraveyard(_target); target = NULL; if (tc) tc->initTargets(); return 1; } return 0; }
int Counters::removeCounter(const char * _name, int _power, int _toughness) { for (int i = 0; i < mCount; i++) { if (counters[i]->sameAs(_name, _power, _toughness)) { if (counters[i]->nb < 1) return 0; counters[i]->removed(); counters[i]->nb--; GameObserver *g = target->getObserver(); WEvent * e = NEW WEventCounters(this,_name,_power,_toughness,false,true); dynamic_cast<WEventCounters*>(e)->targetCard = this->target; g->receiveEvent(e); // special case: when the last time counter is removed from non-suspended card // sacrifice that card if (!target->suspended && counters[i]->name == "time" && counters[i]->nb == 0) { MTGCardInstance * beforeCard = target; target->controller()->game->putInGraveyard(target); WEvent * e = NEW WEventCardSacrifice(beforeCard, target); g->receiveEvent(e); } //special case:if a card is suspended and no longer has a time counter when the last is removed, the card is cast. if (target->suspended && !target->counters->hasCounter("time",0,0)) { GameObserver * game = target->getObserver(); MTGAbility *ac = NEW AACastCard(game, game->mLayers->actionLayer()->getMaxId(), target, target, false, false, true, "", "", false, false); MayAbility *ma1 = NEW MayAbility(game, game->mLayers->actionLayer()->getMaxId(), ac->clone(), target, true); MTGAbility *ga1 = NEW GenericAddToGame(game, game->mLayers->actionLayer()->getMaxId(), target, NULL, ma1->clone()); SAFE_DELETE(ac); SAFE_DELETE(ma1); ga1->resolve(); SAFE_DELETE(ga1); } return mCount; } } return 0; }
int AIAction::Act() { GameObserver * g = owner->getObserver(); if (player && !playerAbilityTarget) { g->cardClick(NULL, player); return 1; } if (ability) { g->cardClick(click, ability); if (target && !mAbilityTargets.size()) { g->cardClick(target); return 1; } else if(playerAbilityTarget && !mAbilityTargets.size()) { g->cardClick(NULL,(Player*)playerAbilityTarget); return 1; } if(mAbilityTargets.size()) { return clickMultiAct(mAbilityTargets); } } else if(mAbilityTargets.size()) { return clickMultiAct(mAbilityTargets); } else if (click) { //Shouldn't be used, really... g->cardClick(click, click); if (target) g->cardClick(target); return 1; } return 0; }
// Moves a card from one zone to another // If the card is not actually in the expected "from" zone, does nothing and returns null MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone * from, MTGGameZone * to,bool asCopy) { MTGCardInstance * copy = NULL; GameObserver *g = owner->getObserver(); if (!from || !to) return card; //Error check int doCopy = 1; bool shufflelibrary = card->basicAbilities[(int)Constants::SHUFFLELIBRARYDEATH]; bool inplaytoinplay = false; bool ripToken = false; if (g->players[0]->game->battlefield->hasName("Rest in Peace")||g->players[1]->game->battlefield->hasName("Rest in Peace")) ripToken = true; //Madness or Put in Play... for(int i = 0; i < 2; ++i) { if (card->discarded && (to == g->players[i]->game->graveyard) && (from == g->players[i]->game->hand)) { if(card->basicAbilities[(int)Constants::MADNESS]) to = g->players[i]->game->exile; } } //Darksteel Colossus, Legacy Weapon ... top priority since we replace destination directly automatically... for(int i = 0; i < 2; ++i) { if ((to == g->players[i]->game->graveyard) && ( card->basicAbilities[(int)Constants::LIBRARYDEATH]|| card->basicAbilities[(int)Constants::SHUFFLELIBRARYDEATH])) { to = g->players[i]->game->library; } } //Leyline of the Void, Yawgmoth's Agenda... effect... for(int i = 0; i < 2; ++i) { if ((to == g->players[i]->game->graveyard) && ( (g->players[i]->game->battlefield->hasAbility(Constants::MYGCREATUREEXILER) && card->isCreature()) || (g->players[i]->opponent()->game->battlefield->hasAbility(Constants::OPPGCREATUREEXILER) && card->isCreature())|| g->players[i]->game->battlefield->hasAbility(Constants::MYGRAVEEXILER) || g->players[i]->opponent()->game->battlefield->hasAbility(Constants::OPPGRAVEEXILER))) { if ((card->isToken && ripToken)) to = g->players[i]->game->exile; if (!card->isToken) to = g->players[i]->game->exile; } } //When a card is moved from inPlay to inPlay (controller change, for example), it is still the same object if ((to == g->players[0]->game->inPlay || to == g->players[1]->game->inPlay) && (from == g->players[0]->game->inPlay || from == g->players[1]->game->inPlay)) { doCopy = 0; asCopy = true;//don't send zone change event so it will not destroy the GUI when multiple switching of control... inplaytoinplay = true;//try sending different event... } if (!(copy = from->removeCard(card, doCopy))) return NULL; //ERROR if (card->miracle) { copy->miracle = true; } if (card->discarded) {//set discarded for madness... if(from == g->players[0]->game->hand || from == g->players[1]->game->hand) copy->discarded = true; else//turn off discarded if its previous zone is not in hand... copy->discarded = false; } if (options[Options::SFXVOLUME].number > 0) { if (to == g->players[0]->game->graveyard || to == g->players[1]->game->graveyard) { if (card->isCreature() && g->getResourceManager()) { g->getResourceManager()->PlaySample("graveyard.wav"); } } } MTGCardInstance * ret = copy; for(int i = 0; i < 2; ++i) { if(to == g->players[i]->game->library && from == g->players[i]->game->library)//if its going to the library from the library we intend to put it on top. { g->players[i]->game->temp->addCard(copy); g->players[i]->game->library->placeOnTop.push_back(copy); return ret;//don't send event } } to->addCard(copy); //The "Temp" zone are purely for code purposes, and we don't want the abilities engine to //Trigger when cards move in this zone // Additionally, when they move "from" this zone, // we trick the engine into believing that they moved from the zone the card was previously in // See http://code.google.com/p/wagic/issues/detail?id=335 { if (to == g->players[0]->game->temp || to == g->players[1]->game->temp) { //don't send event when moving to temp return ret; } if (from == g->players[0]->game->temp || from == g->players[1]->game->temp) { //remove temporary stuff MTGCardInstance * previous = copy->previous; MTGCardInstance * previous2 = previous->previous; from = previous->previousZone; copy->previous = previous2; if (previous2) previous2->next = copy; previous->previous = NULL; previous->next = NULL; SAFE_DELETE(previous); } } if(!asCopy) { if(shufflelibrary) copy->owner->game->library->shuffle(); WEvent * e = NEW WEventZoneChange(copy, from, to); g->receiveEvent(e); } if(inplaytoinplay) { WEvent * ep = NEW WEventCardControllerChange(copy); g->receiveEvent(ep); } return ret; }