From 751a334e5a98c5867ab1a81501efba3501411eca Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 11 Mar 2025 13:41:14 +0000 Subject: [PATCH] Fix possible crash on accessing Cannon Yard from HotA (cherry picked from commit e273263334ef8900c8fee8e0ae04959ec10b6073) --- lib/mapObjects/CGDwelling.cpp | 14 +++++++++++--- server/CGameHandler.cpp | 11 +++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/lib/mapObjects/CGDwelling.cpp b/lib/mapObjects/CGDwelling.cpp index af8de0b43..b169e5446 100644 --- a/lib/mapObjects/CGDwelling.cpp +++ b/lib/mapObjects/CGDwelling.cpp @@ -474,9 +474,17 @@ void CGDwelling::heroAcceptsCreatures( const CGHeroInstance *h) const SetAvailableCreatures sac; sac.tid = id; sac.creatures = creatures; - sac.creatures[0].first = !h->getArt(ArtifactPosition::MACH1); //ballista - sac.creatures[1].first = !h->getArt(ArtifactPosition::MACH3); //first aid tent - sac.creatures[2].first = !h->getArt(ArtifactPosition::MACH2); //ammo cart + + for (auto & entry : sac.creatures) + { + CreatureID creature = entry.second.at(0); + ArtifactID warMachine = creature.toCreature()->warMachine; + + if (h->hasArt(warMachine, true, false)) + entry.first = 0; + else + entry.first = 1; + } cb->sendAndApply(sac); } diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 14ad48a2a..f0eae8dae 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -2397,7 +2397,18 @@ bool CGameHandler::recruitCreatures(ObjectInstanceID objid, ObjectInstanceID dst COMPLAIN_RET_FALSE_IF(!hero, "Only hero can buy war machines"); COMPLAIN_RET_FALSE_IF(artId == ArtifactID::CATAPULT, "Catapult cannot be recruited!"); COMPLAIN_RET_FALSE_IF(nullptr == art, "Invalid war machine artifact"); + COMPLAIN_RET_FALSE_IF(hero->hasArt(artId),"Hero already has this machine!"); + bool hasFreeSlot = false; + for(auto slot : art->getPossibleSlots().at(ArtBearer::HERO)) + if (hero->getArt(slot) == nullptr) + hasFreeSlot = true; + + if (!hasFreeSlot) + { + auto slot = art->getPossibleSlots().at(ArtBearer::HERO).front(); + removeArtifact(ArtifactLocation(hero->id, slot)); + } return giveHeroNewArtifact(hero, artId, ArtifactPosition::FIRST_AVAILABLE); } else