/* * SummonBoatEffect.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */ #include "StdInc.h" #include "SummonBoatEffect.h" #include "../CSpellHandler.h" #include "../../mapObjects/CGHeroInstance.h" #include "../../mapObjects/MiscObjects.h" #include "../../mapping/CMap.h" #include "../../networkPacks/PacksForClient.h" VCMI_LIB_NAMESPACE_BEGIN SummonBoatEffect::SummonBoatEffect(const CSpell * s, const JsonNode & config) : owner(s) , useExistingBoat(config["useExistingBoat"].Bool()) , createNewBoat(config["createNewBoat"].Bool()) { } bool SummonBoatEffect::canCreateNewBoat() const { return createNewBoat; } int SummonBoatEffect::getSuccessChance(const spells::Caster * caster) const { const auto schoolLevel = caster->getSpellSchoolLevel(owner); return owner->getLevelPower(schoolLevel); } bool SummonBoatEffect::canBeCastImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const { if(!caster->getHeroCaster()) return false; if(caster->getHeroCaster()->inBoat()) { MetaString message = MetaString::createFromTextID("core.genrltxt.333"); caster->getCasterName(message); problem.add(std::move(message)); return false; } int3 summonPos = caster->getHeroCaster()->bestLocation(); if(summonPos.x < 0) { MetaString message = MetaString::createFromTextID("core.genrltxt.334"); caster->getCasterName(message); problem.add(std::move(message)); return false; } return true; } ESpellCastResult SummonBoatEffect::applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const { //check if spell works at all if(env->getRNG()->nextInt(0, 99) >= getSuccessChance(parameters.caster)) //power is % chance of success { InfoWindow iw; iw.player = parameters.caster->getCasterOwner(); iw.text.appendLocalString(EMetaText::GENERAL_TXT, 336); //%s tried to summon a boat, but failed. parameters.caster->getCasterName(iw.text); env->apply(iw); return ESpellCastResult::OK; } //try to find unoccupied boat to summon const CGBoat * nearest = nullptr; if (useExistingBoat) { double dist = 0; for(const auto & b : env->getMap()->getObjects()) { if(b->getBoardedHero() || b->layer != EPathfindingLayer::SAIL) continue; //we're looking for unoccupied boat double nDist = b->visitablePos().dist2d(parameters.caster->getHeroCaster()->visitablePos()); if(!nearest || nDist < dist) //it's first boat or closer than previous { nearest = b; dist = nDist; } } } int3 summonPos = parameters.caster->getHeroCaster()->bestLocation(); if(nullptr != nearest) //we found boat to summon { ChangeObjPos cop; cop.objid = nearest->id; cop.nPos = summonPos; cop.initiator = parameters.caster->getCasterOwner(); env->apply(cop); } else if(!createNewBoat) //none or basic level -> cannot create boat :( { InfoWindow iw; iw.player = parameters.caster->getCasterOwner(); iw.text.appendLocalString(EMetaText::GENERAL_TXT, 335); //There are no boats to summon. env->apply(iw); return ESpellCastResult::ERROR; } else //create boat { env->createBoat(summonPos, BoatId::NECROPOLIS, parameters.caster->getCasterOwner()); } return ESpellCastResult::OK; } VCMI_LIB_NAMESPACE_END