/* * format: * $owner-uid;nr-spells;spell1-name;spell1-uid;spell2-name;spell2-uid;...;\n */ void instance::draw_spells(puppet_ptr inPuppet, int inNrOfSpells) { if (!inPuppet) inPuppet = active_puppet_; const int mMaxSpellsInHand = 6; drawn_spells_.str(""); drawn_spells_ << "[draw];" << inNrOfSpells << "\n"; drawn_spells_ << "$" << inPuppet->getUID() << ";"; // create nrSpellsPerTurn spells from the hero's deck Deck* lDeck = inPuppet->getDeck(); int i; for (i=0; i< inNrOfSpells; ++i) { Spell* lSpell = lDeck->drawSpell(); // assign UID and attach to puppet lSpell->setUID(generate_uid()); inPuppet->attachSpell(lSpell); pass_to_lua("Spells.onDrawSpell", 2, "Pixy::Puppet", inPuppet.get(), "Pixy::Spell", lSpell); drawn_spells_ << lSpell->getName() << ";" << lSpell->getUID() << ";"; lSpell = 0; } drawn_spells_ << "\n"; // tell it to drop some spells if its hand is overflown drawn_spells_ << "[drop];"; int nrOverflow = inPuppet->nrSpellsInHand() - mMaxSpellsInHand; //~ std::cout << "Puppet has " << inPuppet->nrSpellsInHand() << " spells in hand, an overflow of= " << nrOverflow << "\n"; if (nrOverflow > 0) { drawn_spells_ << nrOverflow << "\n$" << inPuppet->getUID() << ";"; } else drawn_spells_ << 0; Entity::spells_t const& lHand = inPuppet->getHand(); while (inPuppet->nrSpellsInHand() > mMaxSpellsInHand) { Spell* lSpell = lHand.front(); drawn_spells_ << lSpell->getUID() << ";"; pass_to_lua("Spells.onDropSpell", 2, "Pixy::Puppet", inPuppet.get(), "Pixy::Spell", lSpell); inPuppet->detachSpell(lSpell->getUID()); lSpell = 0; } drawn_spells_ << "\n"; //~ log_->infoStream() << "sending drawn spells to Puppet " << inPuppet->getName(); std::cout << "drawn spells:\n" << drawn_spells_.str() << "\n"; // broadcast the data Event evt(EventUID::DrawSpells, EventFeedback::Ok, Event::NoFormat); evt.setProperty("Data", drawn_spells_.str()); broadcast(evt); }
void instance::on_cast_spell(const Event& inEvt) { if (!inEvt.hasProperty("Spell")) { Event evt(inEvt); reject(evt); return; } // find the spell object Spell* lSpell; try { lSpell = get_spell(convertTo<int>(inEvt.getProperty("Spell"))); } catch (invalid_uid& e) { // reject the event log_->errorStream() << "couldn't find requested Spell with id " << inEvt.getProperty("Spell"); Event evt(inEvt); reject(evt); return; } Entity* lCaster = lSpell->getCaster(); assert(lCaster && lSpell); log_->debugStream() << "spell cast: " << lSpell->getUID() << "#" << lSpell->getName(); log_->debugStream() << "caster: " << lCaster->getUID() << "#" << lCaster->getName(); // allow only ALL or CASTING spells to be cast by active puppets if (lSpell->getPhase() != BLOCKING && active_puppet_->getUID() != lCaster->getOwner()->getUID()) { Event evt(inEvt); return reject(evt); } // blocking spells can only be cast when the active is not the caster else if (lSpell->getPhase() == BLOCKING && active_puppet_->getUID() == lCaster->getOwner()->getUID()) { Event evt(inEvt); return reject(evt); } Entity* lTarget = 0; if (inEvt.hasProperty("T")) { try { // is the target a puppet? lTarget = get_puppet(convertTo<int>(inEvt.getProperty("T"))).get(); log_->debugStream() << "target: " << lTarget->getUID() << "#" << lTarget->getName(); } catch (invalid_uid& e) { try { // a unit? lTarget = get_unit(convertTo<int>(inEvt.getProperty("T"))); log_->debugStream() << "target: " << lTarget->getUID() << "#" << lTarget->getName(); } catch (invalid_uid& e) { // invalid UID log_->errorStream() << "couldn't find spell target with id " << inEvt.getProperty("T"); Event evt(inEvt); reject(evt); return; } } assert(lTarget); lSpell->setTarget(lTarget); } else { // if the spell requires a target, it must be given #ifdef PARANOID assert(!lSpell->requiresTarget()); #else // gracefully reject the event if (lSpell->requiresTarget()) { log_->errorStream() << "an invalid spell request#" << lSpell->getUID() << "; target is required but not given"; Event e(inEvt); return reject(e); } #endif // otherwise, the spell's target is the caster itself lSpell->setTarget(lCaster); } // verify the caster having enough resources to cast the spell { bool valid = true; if (lCaster->getRank() == PUPPET) { if (lSpell->getCostWP() > ((Puppet*)lCaster)->getWP()) valid = valid && false; // heroes can't have less than 1 channel if (lSpell->getCostChannels() >= ((Puppet*)lCaster)->getChannels()) valid = valid && false; } if (lSpell->getCostHP() > lCaster->getHP()) valid = valid && false; if (!valid) { if (lCaster->getRank() == PUPPET) { Puppet* tCaster = (Puppet*)lCaster; log_->errorStream() << "caster" << tCaster->getUID() << " failed the resources requirements of the spell" << lSpell->getUID() << " : \t " << lSpell->getCostWP() << ":" << lSpell->getCostHP() << ":" << lSpell->getCostChannels() << " vs " << tCaster->getWP() << ":" << tCaster->getHP() << ":" << tCaster->getChannels(); } Event e(inEvt); return reject(e); } } // prepare the response event Event resp(inEvt); resp.setProperty("Spell", lSpell->getUID()); resp.setProperty("C", lSpell->getCaster()->getUID()); if (lSpell->requiresTarget()) resp.setProperty("T", lSpell->getTarget()->getUID()); // dispatch to Lua /*lua_getfield(lua_, LUA_GLOBALSINDEX, "process_spell"); if(!lua_isfunction(lua_, 1)) { log_->errorStream() << "could not find Lua event processor!"; lua_pop(lua_,1); Event e(inEvt); return reject(e); } log_->debugStream() << "\t things are looking good, passing to lua: " << ", cost: " << lSpell->getCostWP() << ":" << lSpell->getCostHP() << ":" << lSpell->getCostChannels(); tolua_pushusertype(lua_,(void*)lCaster,"Pixy::Entity"); tolua_pushusertype(lua_,(void*)lTarget,"Pixy::Entity"); tolua_pushusertype(lua_,(void*)lSpell,"Pixy::Spell"); tolua_pushusertype(lua_,(void*)&inEvt,"Pixy::Event"); try { lua_call(lua_, 4, 1); } catch (std::exception& e) { log_->errorStream() << "Lua Handler: " << e.what(); } bool result = lua_toboolean(lua_, lua_gettop(lua_)); lua_remove(lua_, lua_gettop(lua_));*/ bool result = pass_to_lua( "Spells.onCastSpell", 3, "Pixy::Entity", lCaster, "Pixy::Entity", lTarget, "Pixy::Spell", lSpell); log_->debugStream() << "\t back from lua: " << ", cost: " << lSpell->getCostWP() << ":" << lSpell->getCostHP() << ":" << lSpell->getCostChannels(); // if the spell cast was successful, we first broadcast the command to // the clients, then detach the spell from the caster, and finally // we apply any resource changes to the caster and broadcast them too if (result) { // broadcast the CastSpell event to players, confirming it { resp.Feedback = EventFeedback::Ok; broadcast(resp); } // update the caster stats and broadcast them { Event evt(EventUID::Unassigned, EventFeedback::Ok); evt.setProperty("UID", lCaster->getUID()); if (lCaster->getRank() == PUPPET) { Puppet* tCaster = static_cast<Puppet*>(lCaster); evt.UID = EventUID::UpdatePuppet; // apply WP cost, if any if (lSpell->getCostWP() > 0) { tCaster->setWP(tCaster->getWP() - lSpell->getCostWP()); evt.setProperty("WP", tCaster->getWP()); log_->debugStream() << tCaster->getName() << " paid " << lSpell->getCostWP() << " wp," << " and now has " << tCaster->getWP() << " wp."; } // apply the Channels cost, if any if (lSpell->getCostChannels() > 0) { tCaster->setChannels(tCaster->getChannels() - lSpell->getCostChannels()); evt.setProperty("Channels", tCaster->getChannels()); log_->debugStream() << tCaster->getName() << " paid " << lSpell->getCostChannels() << " channels," << " and now has " << tCaster->getChannels() << " channels."; } } else evt.UID = EventUID::UpdateUnit; // apply HP cost, if any if (lSpell->getCostHP() > 0) { lCaster->setHP(lCaster->getHP() - lSpell->getCostHP()); evt.setProperty("HP", lCaster->getHP()); log_->debugStream() << lCaster->getName() << " paid " << lSpell->getCostHP() << " hp," << " and now has " << lCaster->getHP() << " hp."; } broadcast(evt); } // don't delete the spell object if it's a buff lCaster->detachSpell(lSpell->getUID(), lSpell->getDuration() == 0); } else { // we reject the request //Event e(inEvt); resp.Feedback = EventFeedback::Error; return reject(resp); } lSpell = 0; lCaster = 0; lTarget = 0; //return result; }