From a9327b3fa3fe94e743f2a704db366df24d7416a4 Mon Sep 17 00:00:00 2001 From: Laserlicht <13953785+Laserlicht@users.noreply.github.com> Date: Fri, 27 Sep 2024 22:47:22 +0200 Subject: [PATCH] netpacks --- CCallback.cpp | 6 ++++++ CCallback.h | 2 ++ client/Client.h | 1 + client/windows/CCastleInterface.cpp | 13 +++++++----- client/windows/CCastleInterface.h | 5 ++++- config/gameConfig.json | 2 +- lib/IGameCallback.h | 1 + lib/gameState/CGameState.cpp | 2 +- lib/networkPacks/NetPackVisitor.h | 2 ++ lib/networkPacks/NetPacksLib.cpp | 16 +++++++++++++++ lib/networkPacks/PacksForClient.h | 18 ++++++++++++++++ lib/networkPacks/PacksForServer.h | 18 ++++++++++++++++ lib/serializer/RegisterTypes.h | 2 ++ server/CGameHandler.cpp | 32 +++++++++++++++++++++++++++++ server/CGameHandler.h | 3 +++ server/NetPacksServer.cpp | 5 +++++ server/ServerNetPackVisitors.h | 1 + 17 files changed, 121 insertions(+), 8 deletions(-) diff --git a/CCallback.cpp b/CCallback.cpp index 8d2709f3d..e5953394e 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -249,6 +249,12 @@ int CBattleCallback::sendRequest(const CPackForServer * request) return requestID; } +void CCallback::spellResearch( const CGTownInstance *town ) +{ + SpellResearch pack(town->id); + sendRequest(&pack); +} + void CCallback::swapGarrisonHero( const CGTownInstance *town ) { if(town->tempOwner == *player || (town->garrisonHero && town->garrisonHero->tempOwner == *player )) diff --git a/CCallback.h b/CCallback.h index a934113ce..3e9778387 100644 --- a/CCallback.h +++ b/CCallback.h @@ -78,6 +78,7 @@ public: virtual bool visitTownBuilding(const CGTownInstance *town, BuildingID buildingID)=0; virtual void recruitCreatures(const CGDwelling *obj, const CArmedInstance * dst, CreatureID ID, ui32 amount, si32 level=-1)=0; virtual bool upgradeCreature(const CArmedInstance *obj, SlotID stackPos, CreatureID newID=CreatureID::NONE)=0; //if newID==-1 then best possible upgrade will be made + virtual void spellResearch(const CGTownInstance *town)=0; virtual void swapGarrisonHero(const CGTownInstance *town)=0; virtual void trade(const ObjectInstanceID marketId, EMarketMode mode, TradeItemSell id1, TradeItemBuy id2, ui32 val1, const CGHeroInstance * hero)=0; //mode==0: sell val1 units of id1 resource for id2 resiurce @@ -187,6 +188,7 @@ public: bool dismissCreature(const CArmedInstance *obj, SlotID stackPos) override; bool upgradeCreature(const CArmedInstance *obj, SlotID stackPos, CreatureID newID=CreatureID::NONE) override; void endTurn() override; + void spellResearch(const CGTownInstance *town) override; void swapGarrisonHero(const CGTownInstance *town) override; void buyArtifact(const CGHeroInstance *hero, ArtifactID aid) override; void trade(const ObjectInstanceID marketId, EMarketMode mode, TradeItemSell id1, TradeItemBuy id2, ui32 val1, const CGHeroInstance * hero = nullptr) override; diff --git a/client/Client.h b/client/Client.h index d63f70578..cfb00e26c 100644 --- a/client/Client.h +++ b/client/Client.h @@ -159,6 +159,7 @@ public: friend class CBattleCallback; //handling players actions void changeSpells(const CGHeroInstance * hero, bool give, const std::set & spells) override {}; + void setTownSpells(const CGTownInstance * town, int level, const std::vector spells) override {}; bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override {return false;}; void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) override {}; void setOwner(const CGObjectInstance * obj, PlayerColor owner) override {}; diff --git a/client/windows/CCastleInterface.cpp b/client/windows/CCastleInterface.cpp index e8086f830..56211c500 100644 --- a/client/windows/CCastleInterface.cpp +++ b/client/windows/CCastleInterface.cpp @@ -1966,7 +1966,7 @@ void CFortScreen::RecruitArea::showPopupWindow(const Point & cursorPosition) } CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner, const ImagePath & imagename) - : CWindowObject(BORDERED, imagename) + : CWindowObject(BORDERED, imagename), town(owner->town) { OBJECT_CONSTRUCTION; @@ -1997,15 +1997,15 @@ CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner, const ImagePath & i for(size_t j=0; jtown->mageGuildLevel() && owner->town->spells[i].size()>j) - spells.push_back(std::make_shared(positions[i][j], owner->town->spells[i][j].toSpell())); + spells.push_back(std::make_shared(positions[i][j], owner->town->spells[i][j].toSpell(), town)); else emptyScrolls.push_back(std::make_shared(AnimationPath::builtin("TPMAGES.DEF"), 1, 0, positions[i][j].x, positions[i][j].y)); } } } -CMageGuildScreen::Scroll::Scroll(Point position, const CSpell *Spell) - : spell(Spell) +CMageGuildScreen::Scroll::Scroll(Point position, const CSpell *Spell, const CGTownInstance *town) + : spell(Spell), town(town) { OBJECT_CONSTRUCTION; @@ -2017,7 +2017,10 @@ CMageGuildScreen::Scroll::Scroll(Point position, const CSpell *Spell) void CMageGuildScreen::Scroll::clickPressed(const Point & cursorPosition) { - LOCPLINT->showInfoDialog(spell->getDescriptionTranslated(0), std::make_shared(ComponentType::SPELL, spell->id)); + if(LOCPLINT->cb->getSettings().getBoolean(EGameSettings::TOWNS_SPELL_RESEARCH)) + LOCPLINT->cb->spellResearch(town); + else + LOCPLINT->showInfoDialog(spell->getDescriptionTranslated(0), std::make_shared(ComponentType::SPELL, spell->id)); } void CMageGuildScreen::Scroll::showPopupWindow(const Point & cursorPosition) diff --git a/client/windows/CCastleInterface.h b/client/windows/CCastleInterface.h index 3b8fb6037..3091d48ab 100644 --- a/client/windows/CCastleInterface.h +++ b/client/windows/CCastleInterface.h @@ -379,9 +379,10 @@ class CMageGuildScreen : public CStatusbarWindow { const CSpell * spell; std::shared_ptr image; + const CGTownInstance *town; public: - Scroll(Point position, const CSpell *Spell); + Scroll(Point position, const CSpell *Spell, const CGTownInstance *town); void clickPressed(const Point & cursorPosition) override; void showPopupWindow(const Point & cursorPosition) override; void hover(bool on) override; @@ -393,6 +394,8 @@ class CMageGuildScreen : public CStatusbarWindow std::shared_ptr resdatabar; + const CGTownInstance *town; + public: CMageGuildScreen(CCastleInterface * owner, const ImagePath & image); }; diff --git a/config/gameConfig.json b/config/gameConfig.json index 3f439f223..9e4e5a4a3 100644 --- a/config/gameConfig.json +++ b/config/gameConfig.json @@ -313,7 +313,7 @@ // Chances for a town with default buildings to receive corresponding dwelling level built in start "startingDwellingChances": [100, 50], // Enable spell research in mage guild - "spellResearch": false + "spellResearch": true }, "combat": diff --git a/lib/IGameCallback.h b/lib/IGameCallback.h index a9cc7b655..9e1e8c1ca 100644 --- a/lib/IGameCallback.h +++ b/lib/IGameCallback.h @@ -94,6 +94,7 @@ public: virtual void showInfoDialog(InfoWindow * iw) = 0; virtual void changeSpells(const CGHeroInstance * hero, bool give, const std::set &spells)=0; + virtual void setTownSpells(const CGTownInstance * town, int level, const std::vector spells)=0; virtual bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) = 0; virtual void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) = 0; virtual void setOwner(const CGObjectInstance * objid, PlayerColor owner)=0; diff --git a/lib/gameState/CGameState.cpp b/lib/gameState/CGameState.cpp index 31bd4e2de..fed910807 100644 --- a/lib/gameState/CGameState.cpp +++ b/lib/gameState/CGameState.cpp @@ -915,7 +915,7 @@ void CGameState::initTowns() vti->spells[s->getLevel()-1].push_back(s->id); vti->possibleSpells -= s->id; } - vti->possibleSpells.clear(); + vti->possibleSpells.clear(); //SR } } diff --git a/lib/networkPacks/NetPackVisitor.h b/lib/networkPacks/NetPackVisitor.h index 475b9b5db..4cfb0e402 100644 --- a/lib/networkPacks/NetPackVisitor.h +++ b/lib/networkPacks/NetPackVisitor.h @@ -42,6 +42,7 @@ public: virtual void visitSetSecSkill(SetSecSkill & pack) {} virtual void visitHeroVisitCastle(HeroVisitCastle & pack) {} virtual void visitChangeSpells(ChangeSpells & pack) {} + virtual void visitSetTownSpells(SetTownSpells & pack) {} virtual void visitSetMana(SetMana & pack) {} virtual void visitSetMovePoints(SetMovePoints & pack) {} virtual void visitFoWChange(FoWChange & pack) {} @@ -128,6 +129,7 @@ public: virtual void visitBuildStructure(BuildStructure & pack) {} virtual void visitVisitTownBuilding(VisitTownBuilding & pack) {} virtual void visitRazeStructure(RazeStructure & pack) {} + virtual void visitSpellResearch(SpellResearch & pack) {} virtual void visitRecruitCreatures(RecruitCreatures & pack) {} virtual void visitUpgradeCreature(UpgradeCreature & pack) {} virtual void visitGarrisonHeroSwap(GarrisonHeroSwap & pack) {} diff --git a/lib/networkPacks/NetPacksLib.cpp b/lib/networkPacks/NetPacksLib.cpp index 43309a8c5..a2cb60448 100644 --- a/lib/networkPacks/NetPacksLib.cpp +++ b/lib/networkPacks/NetPacksLib.cpp @@ -162,6 +162,10 @@ void ChangeSpells::visitTyped(ICPackVisitor & visitor) visitor.visitChangeSpells(*this); } +void SetTownSpells::visitTyped(ICPackVisitor & visitor) +{ + visitor.visitSetTownSpells(*this); +} void SetMana::visitTyped(ICPackVisitor & visitor) { visitor.visitSetMana(*this); @@ -592,6 +596,11 @@ void RazeStructure::visitTyped(ICPackVisitor & visitor) visitor.visitRazeStructure(*this); } +void SpellResearch::visitTyped(ICPackVisitor & visitor) +{ + visitor.visitSpellResearch(*this); +} + void RecruitCreatures::visitTyped(ICPackVisitor & visitor) { visitor.visitRecruitCreatures(*this); @@ -930,6 +939,13 @@ void ChangeSpells::applyGs(CGameState *gs) hero->removeSpellFromSpellbook(sid); } +void SetTownSpells::applyGs(CGameState *gs) +{ + CGTownInstance *town = gs->getTown(tid); + + town->spells[level] = spells; +} + void SetMana::applyGs(CGameState *gs) { CGHeroInstance * hero = gs->getHero(hid); diff --git a/lib/networkPacks/PacksForClient.h b/lib/networkPacks/PacksForClient.h index 5a81ec806..ae1d23167 100644 --- a/lib/networkPacks/PacksForClient.h +++ b/lib/networkPacks/PacksForClient.h @@ -288,6 +288,24 @@ struct DLL_LINKAGE ChangeSpells : public CPackForClient } }; +struct DLL_LINKAGE SetTownSpells : public CPackForClient +{ + void applyGs(CGameState * gs) override; + + void visitTyped(ICPackVisitor & visitor) override; + + ui8 level = 0; + ObjectInstanceID tid; + std::vector spells; + + template void serialize(Handler & h) + { + h & level; + h & tid; + h & spells; + } +}; + struct DLL_LINKAGE SetMana : public CPackForClient { void applyGs(CGameState * gs) override; diff --git a/lib/networkPacks/PacksForServer.h b/lib/networkPacks/PacksForServer.h index a909cf652..b35254f23 100644 --- a/lib/networkPacks/PacksForServer.h +++ b/lib/networkPacks/PacksForServer.h @@ -306,6 +306,24 @@ struct DLL_LINKAGE RazeStructure : public BuildStructure void visitTyped(ICPackVisitor & visitor) override; }; +struct DLL_LINKAGE SpellResearch : public CPackForServer +{ + SpellResearch() = default; + SpellResearch(const ObjectInstanceID & TID) + : tid(TID) + { + } + ObjectInstanceID tid; + + void visitTyped(ICPackVisitor & visitor) override; + + template void serialize(Handler & h) + { + h & static_cast(*this); + h & tid; + } +}; + struct DLL_LINKAGE RecruitCreatures : public CPackForServer { RecruitCreatures() = default; diff --git a/lib/serializer/RegisterTypes.h b/lib/serializer/RegisterTypes.h index 94663357e..6fcbc5e20 100644 --- a/lib/serializer/RegisterTypes.h +++ b/lib/serializer/RegisterTypes.h @@ -288,6 +288,8 @@ void registerTypes(Serializer &s) s.template registerType(238); s.template registerType(239); s.template registerType(240); + s.template registerType(241); + s.template registerType(242); } VCMI_LIB_NAMESPACE_END diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 35dde1615..c14248b54 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -1235,6 +1235,15 @@ void CGameHandler::changeSpells(const CGHeroInstance * hero, bool give, const st sendAndApply(&cs); } +void CGameHandler::setTownSpells(const CGTownInstance * town, int level, const std::vector spells) +{ + SetTownSpells cs; + cs.tid = town->id; + cs.spells = spells; + cs.level = level; + sendAndApply(&cs); +} + void CGameHandler::giveHeroBonus(GiveBonus * bonus) { sendAndApply(bonus); @@ -2233,6 +2242,29 @@ bool CGameHandler::razeStructure (ObjectInstanceID tid, BuildingID bid) return true; } +bool CGameHandler::spellResearch(ObjectInstanceID tid) +{ + if(!getSettings().getBoolean(EGameSettings::TOWNS_SPELL_RESEARCH) && complain("Spell research not allowed!")) + return false; + + CGTownInstance *t = gs->getTown(tid); + auto spells = t->spells.at(1); + auto spell = SpellID(SpellID::FLY); + spells.at(0) = spell; + setTownSpells(t, 1, spells); + spellResearchFinished(tid); + return true; +} + +void CGameHandler::spellResearchFinished(ObjectInstanceID tid) +{ + const CGTownInstance * t = getTown(tid); + if(t->visitingHero) + giveSpells(t, t->visitingHero); + if(t->garrisonHero) + giveSpells(t, t->garrisonHero); +} + bool CGameHandler::recruitCreatures(ObjectInstanceID objid, ObjectInstanceID dstid, CreatureID crid, ui32 cram, si32 fromLvl, PlayerColor player) { const CGDwelling * dwelling = dynamic_cast(getObj(objid)); diff --git a/server/CGameHandler.h b/server/CGameHandler.h index cdb194377..b1540b636 100644 --- a/server/CGameHandler.h +++ b/server/CGameHandler.h @@ -107,6 +107,7 @@ public: //from IGameCallback //do sth void changeSpells(const CGHeroInstance * hero, bool give, const std::set &spells) override; + void setTownSpells(const CGTownInstance * town, int level, const std::vector spells) override; bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override; void setOwner(const CGObjectInstance * obj, PlayerColor owner) override; void giveExperience(const CGHeroInstance * hero, TExpType val) override; @@ -218,6 +219,8 @@ public: bool buildStructure(ObjectInstanceID tid, BuildingID bid, bool force=false);//force - for events: no cost, no checkings bool visitTownBuilding(ObjectInstanceID tid, BuildingID bid); bool razeStructure(ObjectInstanceID tid, BuildingID bid); + bool spellResearch(ObjectInstanceID tid); + void spellResearchFinished(ObjectInstanceID tid); bool disbandCreature( ObjectInstanceID id, SlotID pos ); bool arrangeStacks( ObjectInstanceID id1, ObjectInstanceID id2, ui8 what, SlotID p1, SlotID p2, si32 val, PlayerColor player); bool bulkMoveArmy(ObjectInstanceID srcArmy, ObjectInstanceID destArmy, SlotID srcSlot); diff --git a/server/NetPacksServer.cpp b/server/NetPacksServer.cpp index 2a7b493d4..90e8f2062 100644 --- a/server/NetPacksServer.cpp +++ b/server/NetPacksServer.cpp @@ -138,6 +138,11 @@ void ApplyGhNetPackVisitor::visitBuildStructure(BuildStructure & pack) result = gh.buildStructure(pack.tid, pack.bid); } +void ApplyGhNetPackVisitor::visitSpellResearch(SpellResearch & pack) +{ + result = gh.spellResearch(pack.tid); +} + void ApplyGhNetPackVisitor::visitVisitTownBuilding(VisitTownBuilding & pack) { gh.throwIfWrongOwner(&pack, pack.tid); diff --git a/server/ServerNetPackVisitors.h b/server/ServerNetPackVisitors.h index 34593c1da..ba94157cb 100644 --- a/server/ServerNetPackVisitors.h +++ b/server/ServerNetPackVisitors.h @@ -41,6 +41,7 @@ public: void visitBulkSmartSplitStack(BulkSmartSplitStack & pack) override; void visitDisbandCreature(DisbandCreature & pack) override; void visitBuildStructure(BuildStructure & pack) override; + void visitSpellResearch(SpellResearch & pack) override; void visitVisitTownBuilding(VisitTownBuilding & pack) override; void visitRecruitCreatures(RecruitCreatures & pack) override; void visitUpgradeCreature(UpgradeCreature & pack) override;