diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index 2c040da6b..500ce19b0 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/lib/mapObjects/CGTownInstance.cpp @@ -268,7 +268,8 @@ CGTownInstance::CGTownInstance(IGameCallback *cb): built(0), destroyed(0), identifier(0), - alignmentToPlayer(PlayerColor::NEUTRAL) + alignmentToPlayer(PlayerColor::NEUTRAL), + lastSpellResearchDay(0) { this->setNodeType(CBonusSystemNode::TOWN); } diff --git a/lib/mapObjects/CGTownInstance.h b/lib/mapObjects/CGTownInstance.h index fab98714e..e14802fd4 100644 --- a/lib/mapObjects/CGTownInstance.h +++ b/lib/mapObjects/CGTownInstance.h @@ -73,6 +73,7 @@ public: std::vector > spells; //spells[level] -> vector of spells, first will be available in guild std::vector events; std::pair bonusValue;//var to store town bonuses (rampart = resources from mystic pond, factory = save debts); + int lastSpellResearchDay; ////////////////////////////////////////////////////////////////////////// template void serialize(Handler &h) @@ -93,6 +94,9 @@ public: h & spells; h & events; + if (h.version >= Handler::Version::SPELL_RESEARCH) + h & lastSpellResearchDay; + if (h.version >= Handler::Version::NEW_TOWN_BUILDINGS) { h & rewardableBuildings; diff --git a/lib/serializer/ESerializationVersion.h b/lib/serializer/ESerializationVersion.h index dd0deb6b0..b4be54223 100644 --- a/lib/serializer/ESerializationVersion.h +++ b/lib/serializer/ESerializationVersion.h @@ -61,6 +61,7 @@ enum class ESerializationVersion : int32_t CAMPAIGN_OUTRO_SUPPORT, // 862 - support for campaign outro video REWARDABLE_BANKS, // 863 - team state contains list of scouted objects, coast visitable rewardable objects REGION_LABEL, // 864 - labels for campaign regions + SPELL_RESEARCH, // 865 - spell research - CURRENT = REGION_LABEL + CURRENT = SPELL_RESEARCH }; diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 607fdf620..fb9625012 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -2256,6 +2256,24 @@ bool CGameHandler::spellResearch(ObjectInstanceID tid, SpellID spellAtSlot) if(level == -1 && complain("Spell for replacement not found!")) return false; + + int daysSinceLastResearch = gs->getDate(Date::DAY) - t->lastSpellResearchDay; + if(!daysSinceLastResearch && complain("Already researched today!")) + return false; + + TResources cost; + cost[EGameResID::GOLD] = 1000; + cost[EGameResID::MERCURY] = (level + 1) * 2; + cost[EGameResID::SULFUR] = (level + 1) * 2; + cost[EGameResID::CRYSTAL] = (level + 1) * 2; + cost[EGameResID::GEMS] = (level + 1) * 2; + + if(!getPlayerState(t->getOwner())->resources.canAfford(cost) && complain("Spell replacement cannot be afforded!")) + return false; + + giveResources(t->getOwner(), -cost); + + t->lastSpellResearchDay = gs->getDate(Date::DAY); auto spells = t->spells.at(level); diff --git a/server/NetPacksServer.cpp b/server/NetPacksServer.cpp index b8f71167b..b4227f1ea 100644 --- a/server/NetPacksServer.cpp +++ b/server/NetPacksServer.cpp @@ -140,6 +140,9 @@ void ApplyGhNetPackVisitor::visitBuildStructure(BuildStructure & pack) void ApplyGhNetPackVisitor::visitSpellResearch(SpellResearch & pack) { + gh.throwIfWrongOwner(&pack, pack.tid); + gh.throwIfPlayerNotActive(&pack); + result = gh.spellResearch(pack.tid, pack.spellAtSlot); }