1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-17 01:32:21 +02:00

Fix regressions

This commit is contained in:
Ivan Savenko
2025-04-10 12:27:18 +03:00
parent e6a8e5d4bd
commit 912c2eae94
17 changed files with 94 additions and 98 deletions

View File

@ -1332,7 +1332,7 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
{ {
auto tile = cb->getTile(coord, false); auto tile = cb->getTile(coord, false);
assert(tile); assert(tile);
return cb->getObj(tile->topVisitableObj(ignoreHero)); return cb->getObj(tile->topVisitableObj(ignoreHero), false);
}; };
auto isTeleportAction = [&](EPathNodeAction action) -> bool auto isTeleportAction = [&](EPathNodeAction action) -> bool

View File

@ -214,6 +214,7 @@ void DangerHitMapAnalyzer::calculateTileOwners()
CRandomGenerator rng; CRandomGenerator rng;
auto visitablePos = town->visitablePos(); auto visitablePos = town->visitablePos();
townHero->id = town->id;
townHero->setOwner(ai->playerID); // lets avoid having multiple colors townHero->setOwner(ai->playerID); // lets avoid having multiple colors
townHero->initHero(rng, static_cast<HeroTypeID>(0)); townHero->initHero(rng, static_cast<HeroTypeID>(0));
townHero->pos = townHero->convertFromVisitablePos(visitablePos); townHero->pos = townHero->convertFromVisitablePos(visitablePos);

View File

@ -31,8 +31,8 @@ namespace AIPathfinding
bool QuestAction::canAct(const Nullkiller * ai, const CGHeroInstance * hero) const bool QuestAction::canAct(const Nullkiller * ai, const CGHeroInstance * hero) const
{ {
auto object = questInfo.getObject(cb); auto object = questInfo.getObject(ai->cb.get());
auto quest = questInfo.getQuest(cb); auto quest = questInfo.getQuest(ai->cb.get());
if(object->ID == Obj::BORDER_GATE || object->ID == Obj::BORDERGUARD) if(object->ID == Obj::BORDER_GATE || object->ID == Obj::BORDERGUARD)
{ {
return dynamic_cast<const IQuestObject *>(object)->checkQuest(hero); return dynamic_cast<const IQuestObject *>(object)->checkQuest(hero);

View File

@ -371,8 +371,10 @@ int CClient::sendRequest(const CPackForServer & request, PlayerColor player)
return requestID; return requestID;
} }
void CClient::battleStarted(const BattleInfo * info) void CClient::battleStarted(const BattleID & battleID)
{ {
const BattleInfo * info = gameState()->getBattle(battleID);
std::shared_ptr<CPlayerInterface> att; std::shared_ptr<CPlayerInterface> att;
std::shared_ptr<CPlayerInterface> def; std::shared_ptr<CPlayerInterface> def;
const auto & leftSide = info->getSide(BattleSide::LEFT_SIDE); const auto & leftSide = info->getSide(BattleSide::LEFT_SIDE);

View File

@ -164,7 +164,7 @@ public:
void handlePack(CPackForClient & pack); //applies the given pack and deletes it void handlePack(CPackForClient & pack); //applies the given pack and deletes it
int sendRequest(const CPackForServer & request, PlayerColor player); //returns ID given to that request int sendRequest(const CPackForServer & request, PlayerColor player); //returns ID given to that request
void battleStarted(const BattleInfo * info); void battleStarted(const BattleID & battle);
void battleFinished(const BattleID & battleID); void battleFinished(const BattleID & battleID);
void startPlayerBattleAction(const BattleID & battleID, PlayerColor color); void startPlayerBattleAction(const BattleID & battleID, PlayerColor color);

View File

@ -754,7 +754,7 @@ void ApplyFirstClientNetPackVisitor::visitBattleStart(BattleStart & pack)
void ApplyClientNetPackVisitor::visitBattleStart(BattleStart & pack) void ApplyClientNetPackVisitor::visitBattleStart(BattleStart & pack)
{ {
cl.battleStarted(pack.info.get()); cl.battleStarted(pack.battleID);
} }
void ApplyFirstClientNetPackVisitor::visitBattleNextRound(BattleNextRound & pack) void ApplyFirstClientNetPackVisitor::visitBattleNextRound(BattleNextRound & pack)

View File

@ -516,6 +516,7 @@ void CCreatureSet::putStack(const SlotID & slot, std::unique_ptr<CStackInstance>
{ {
assert(slot.getNum() < GameConstants::ARMY_SIZE); assert(slot.getNum() < GameConstants::ARMY_SIZE);
assert(!hasStackAtSlot(slot)); assert(!hasStackAtSlot(slot));
stacks[slot] = std::move(stack); stacks[slot] = std::move(stack);
stacks[slot]->setArmy(getArmy()); stacks[slot]->setArmy(getArmy());
armyChanged(); armyChanged();

View File

@ -443,16 +443,6 @@ bool CGameInfoCallback::isVisible(const CGObjectInstance *obj) const
{ {
return isVisible(obj, getPlayerID()); return isVisible(obj, getPlayerID());
} }
// const CCreatureSet* CInfoCallback::getGarrison(const CGObjectInstance *obj) const
// {
// //std::shared_lock<std::shared_mutex> lock(*gameState()->mx);
// if()
// const CArmedInstance *armi = dynamic_cast<const CArmedInstance*>(obj);
// if(!armi)
// return nullptr;
// else
// return armi;
// }
std::vector <const CGObjectInstance *> CGameInfoCallback::getBlockingObjs( int3 pos ) const std::vector <const CGObjectInstance *> CGameInfoCallback::getBlockingObjs( int3 pos ) const
{ {
@ -473,7 +463,9 @@ std::vector <const CGObjectInstance *> CGameInfoCallback::getVisitableObjs(int3
for(const auto & objID : t->visitableObjects) for(const auto & objID : t->visitableObjects)
{ {
const auto & object = getObj(objID); const auto & object = getObj(objID, false);
if (!object)
continue; // event - visitable, but not visible
if(!getPlayerID().has_value() || object->ID != Obj::EVENT) //hide events from players if(!getPlayerID().has_value() || object->ID != Obj::EVENT) //hide events from players
ret.push_back(object); ret.push_back(object);

View File

@ -577,7 +577,6 @@ void CGameState::removeHeroPlaceholders()
for(auto obj : map->getObjects<CGHeroPlaceholder>()) for(auto obj : map->getObjects<CGHeroPlaceholder>())
{ {
map->removeBlockVisTiles(obj, true); map->removeBlockVisTiles(obj, true);
map->instanceNames.erase(obj->instanceName);
map->eraseObject(obj->id); map->eraseObject(obj->id);
} }
} }
@ -623,20 +622,18 @@ void CGameState::initHeroes()
for(const HeroTypeID & htype : heroesToCreate) //all not used allowed heroes go with default state into the pool for(const HeroTypeID & htype : heroesToCreate) //all not used allowed heroes go with default state into the pool
{ {
auto vhi = map->tryTakeFromHeroPool(htype); CGHeroInstance * heroInPool = map->tryGetFromHeroPool(htype);
if (vhi) // some heroes are created as part of map loading (sod+ h3m maps)
// instances for h3 heroes from roe/ab h3m maps and heroes from mods at this point don't exist -> create them
if (!heroInPool)
{ {
vhi->initHero(getRandomGenerator()); auto newHeroPtr = std::make_shared<CGHeroInstance>(cb);
newHeroPtr->subID = htype.getNum();
map->addToHeroPool(newHeroPtr);
heroInPool = newHeroPtr.get();
} }
else heroInPool->initHero(getRandomGenerator());
{
vhi = std::make_shared<CGHeroInstance>(cb);
vhi->initHero(getRandomGenerator(), htype);
}
map->addToHeroPool(vhi);
heroesPool->addHeroToPool(vhi->getHeroTypeID());
} }
for(auto & elem : map->disposedHeroes) for(auto & elem : map->disposedHeroes)

View File

@ -155,13 +155,12 @@ CBonusSystemNode & CArmedInstance::whatShouldBeAttached()
void CArmedInstance::attachToBonusSystem(CGameState * gs) void CArmedInstance::attachToBonusSystem(CGameState * gs)
{ {
CArmedInstance::restoreBonusSystem(gs); whatShouldBeAttached().attachTo(whereShouldBeAttached(gs));
} }
void CArmedInstance::restoreBonusSystem(CGameState * gs) void CArmedInstance::restoreBonusSystem(CGameState * gs)
{ {
whatShouldBeAttached().attachTo(whereShouldBeAttached(gs)); whatShouldBeAttached().attachTo(whereShouldBeAttached(gs));
for(const auto & elem : stacks) for(const auto & elem : stacks)
elem.second->artDeserializationFix(gs, elem.second.get()); elem.second->artDeserializationFix(gs, elem.second.get());
} }
@ -169,14 +168,12 @@ void CArmedInstance::restoreBonusSystem(CGameState * gs)
void CArmedInstance::detachFromBonusSystem(CGameState * gs) void CArmedInstance::detachFromBonusSystem(CGameState * gs)
{ {
whatShouldBeAttached().detachFrom(whereShouldBeAttached(gs)); whatShouldBeAttached().detachFrom(whereShouldBeAttached(gs));
// TODO: the opposite
// for(const auto & elem : stacks)
// elem.second->artDeserializationFix(elem.second.get());
} }
void CArmedInstance::attachUnitsToArmy() void CArmedInstance::attachUnitsToArmy()
{ {
assert(getArmy() != nullptr);
for(const auto & elem : stacks) for(const auto & elem : stacks)
elem.second->attachTo(*getArmy()); elem.second->attachTo(*getArmy());
} }

View File

@ -1317,10 +1317,19 @@ CGBoat * CGHeroInstance::getBoat()
void CGHeroInstance::setBoat(CGBoat* newBoat) void CGHeroInstance::setBoat(CGBoat* newBoat)
{ {
assert(newBoat); if (newBoat)
{
boardedBoat = newBoat->id; boardedBoat = newBoat->id;
attachTo(*newBoat); attachTo(*newBoat);
newBoat->setBoardedHero(this); newBoat->setBoardedHero(this);
}
else if (boardedBoat.hasValue())
{
auto oldBoat = getBoat();
boardedBoat = {};
detachFrom(*oldBoat);
oldBoat->setBoardedHero(nullptr);
}
} }
void CGHeroInstance::restoreBonusSystem(CGameState * gs) void CGHeroInstance::restoreBonusSystem(CGameState * gs)
@ -1348,7 +1357,7 @@ void CGHeroInstance::attachToBonusSystem(CGameState * gs)
void CGHeroInstance::detachFromBonusSystem(CGameState * gs) void CGHeroInstance::detachFromBonusSystem(CGameState * gs)
{ {
CArmedInstance::attachToBonusSystem(gs); CArmedInstance::detachFromBonusSystem(gs);
if (boardedBoat.hasValue()) if (boardedBoat.hasValue())
{ {
auto boat = gs->getObjInstance(boardedBoat); auto boat = gs->getObjInstance(boardedBoat);

View File

@ -769,20 +769,17 @@ void CGTownInstance::setVisitingHero(CGHeroInstance *h)
if(h) if(h)
{ {
PlayerState *p = cb->gameState()->getPlayerState(h->tempOwner); h->detachFromBonusSystem(cb->gameState());
assert(p);
h->detachFrom(*p);
h->attachTo(townAndVis);
h->setVisitedTown(this, false); h->setVisitedTown(this, false);
h->attachToBonusSystem(cb->gameState());
visitingHero = h->id; visitingHero = h->id;
} }
else else if (visitingHero.hasValue())
{ {
auto oldVisitor = dynamic_cast<CGHeroInstance*>(cb->gameState()->getObjInstance(visitingHero)); auto oldVisitor = dynamic_cast<CGHeroInstance*>(cb->gameState()->getObjInstance(visitingHero));
PlayerState *p = cb->gameState()->getPlayerState(getVisitingHero()->tempOwner); oldVisitor->detachFromBonusSystem(cb->gameState());
oldVisitor->setVisitedTown(nullptr, false); oldVisitor->setVisitedTown(nullptr, false);
oldVisitor->detachFrom(townAndVis); oldVisitor->attachToBonusSystem(cb->gameState());
oldVisitor->attachTo(*p);
visitingHero = {}; visitingHero = {};
} }
} }
@ -794,20 +791,17 @@ void CGTownInstance::setGarrisonedHero(CGHeroInstance *h)
if(h) if(h)
{ {
PlayerState *p = cb->gameState()->getPlayerState(h->tempOwner); h->detachFromBonusSystem(cb->gameState());
assert(p);
h->detachFrom(*p);
h->attachTo(*this);
h->setVisitedTown(this, true); h->setVisitedTown(this, true);
h->attachToBonusSystem(cb->gameState());
garrisonHero = h->id; garrisonHero = h->id;
} }
else else if (garrisonHero.hasValue())
{ {
PlayerState *p = cb->gameState()->getPlayerState(getGarrisonHero()->tempOwner); auto oldVisitor = dynamic_cast<CGHeroInstance*>(cb->gameState()->getObjInstance(garrisonHero));
auto oldVisitor = dynamic_cast<CGHeroInstance*>(cb->gameState()->getObjInstance(visitingHero)); oldVisitor->detachFromBonusSystem(cb->gameState());
oldVisitor->setVisitedTown(nullptr, false); oldVisitor->setVisitedTown(nullptr, false);
oldVisitor->detachFrom(*this); oldVisitor->attachToBonusSystem(cb->gameState());
oldVisitor->attachTo(*p);
garrisonHero = {}; garrisonHero = {};
} }
updateMoraleBonusFromArmy(); //avoid giving morale bonus for same army twice updateMoraleBonusFromArmy(); //avoid giving morale bonus for same army twice

View File

@ -581,6 +581,7 @@ std::shared_ptr<CGObjectInstance> CMap::eraseObject(ObjectInstanceID oldObjectID
{ {
auto oldObject = objects.at(oldObjectID.getNum()); auto oldObject = objects.at(oldObjectID.getNum());
instanceNames.erase(oldObject->instanceName);
objects.at(oldObjectID) = nullptr; objects.at(oldObjectID) = nullptr;
removeBlockVisTiles(oldObject.get(), true); removeBlockVisTiles(oldObject.get(), true);
oldObject->afterRemoveFromMap(this); oldObject->afterRemoveFromMap(this);
@ -849,6 +850,13 @@ void CMap::addToHeroPool(std::shared_ptr<CGHeroInstance> hero)
assert(heroesPool.at(hero->getHeroTypeID().getNum()) == nullptr); assert(heroesPool.at(hero->getHeroTypeID().getNum()) == nullptr);
heroesPool.at(hero->getHeroTypeID().getNum()) = hero; heroesPool.at(hero->getHeroTypeID().getNum()) = hero;
if (!hero->id.hasValue())
{
// reserve ID for this new hero, if needed (but don't actually add it since hero is not present on map)
hero->id = ObjectInstanceID(objects.size());
objects.push_back(nullptr);
}
} }
CGHeroInstance * CMap::tryGetFromHeroPool(HeroTypeID hero) CGHeroInstance * CMap::tryGetFromHeroPool(HeroTypeID hero)

View File

@ -1104,7 +1104,7 @@ std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readPandora(const int3 & mapPos
void CMapLoaderH3M::readBoxContent(CGPandoraBox * object, const int3 & mapPosition, const ObjectInstanceID & idToBeGiven) void CMapLoaderH3M::readBoxContent(CGPandoraBox * object, const int3 & mapPosition, const ObjectInstanceID & idToBeGiven)
{ {
readMessageAndGuards(object->message, object, mapPosition); readMessageAndGuards(object->message, object, mapPosition, idToBeGiven);
Rewardable::VisitInfo vinfo; Rewardable::VisitInfo vinfo;
auto & reward = vinfo.reward; auto & reward = vinfo.reward;
@ -1182,6 +1182,7 @@ void CMapLoaderH3M::readBoxHotaContent(CGPandoraBox * object, const int3 & mapPo
std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readMonster(const int3 & mapPosition, const ObjectInstanceID & objectInstanceID) std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readMonster(const int3 & mapPosition, const ObjectInstanceID & objectInstanceID)
{ {
auto object = std::make_shared<CGCreature>(map->cb); auto object = std::make_shared<CGCreature>(map->cb);
object->id = objectInstanceID;
if(features.levelAB) if(features.levelAB)
{ {
@ -1369,12 +1370,12 @@ std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readScholar(const int3 & positi
return object; return object;
} }
std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readGarrison(const int3 & mapPosition) std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readGarrison(const int3 & mapPosition, const ObjectInstanceID & idToBeGiven)
{ {
auto object = std::make_shared<CGGarrison>(map->cb); auto object = std::make_shared<CGGarrison>(map->cb);
setOwnerAndValidate(mapPosition, object.get(), reader->readPlayer32()); setOwnerAndValidate(mapPosition, object.get(), reader->readPlayer32());
readCreatureSet(object.get(), 7); readCreatureSet(object.get(), idToBeGiven);
if(features.levelAB) if(features.levelAB)
object->removableUnits = reader->readBool(); object->removableUnits = reader->readBool();
else else
@ -1384,12 +1385,12 @@ std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readGarrison(const int3 & mapPo
return object; return object;
} }
std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readArtifact(const int3 & mapPosition, std::shared_ptr<const ObjectTemplate> objectTemplate) std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readArtifact(const int3 & mapPosition, std::shared_ptr<const ObjectTemplate> objectTemplate, const ObjectInstanceID & idToBeGiven)
{ {
ArtifactID artID = ArtifactID::NONE; //random, set later ArtifactID artID = ArtifactID::NONE; //random, set later
auto object = std::make_shared<CGArtifact>(map->cb); auto object = std::make_shared<CGArtifact>(map->cb);
readMessageAndGuards(object->message, object.get(), mapPosition); readMessageAndGuards(object->message, object.get(), mapPosition, idToBeGiven);
//specific artifact //specific artifact
if(objectTemplate->id == Obj::ARTIFACT) if(objectTemplate->id == Obj::ARTIFACT)
@ -1410,21 +1411,21 @@ std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readArtifact(const int3 & mapPo
return object; return object;
} }
std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readScroll(const int3 & mapPosition, std::shared_ptr<const ObjectTemplate> objectTemplate) std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readScroll(const int3 & mapPosition, std::shared_ptr<const ObjectTemplate> objectTemplate, const ObjectInstanceID & idToBeGiven)
{ {
auto object = std::make_shared<CGArtifact>(map->cb); auto object = std::make_shared<CGArtifact>(map->cb);
readMessageAndGuards(object->message, object.get(), mapPosition); readMessageAndGuards(object->message, object.get(), mapPosition, idToBeGiven);
SpellID spellID = reader->readSpell32(); SpellID spellID = reader->readSpell32();
object->setArtifactInstance(map->createArtifact(ArtifactID::SPELL_SCROLL, spellID.getNum())); object->setArtifactInstance(map->createArtifact(ArtifactID::SPELL_SCROLL, spellID.getNum()));
return object; return object;
} }
std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readResource(const int3 & mapPosition, std::shared_ptr<const ObjectTemplate> objectTemplate) std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readResource(const int3 & mapPosition, std::shared_ptr<const ObjectTemplate> objectTemplate, const ObjectInstanceID & idToBeGiven)
{ {
auto object = std::make_shared<CGResource>(map->cb); auto object = std::make_shared<CGResource>(map->cb);
readMessageAndGuards(object->message, object.get(), mapPosition); readMessageAndGuards(object->message, object.get(), mapPosition, idToBeGiven);
object->amount = reader->readUInt32(); object->amount = reader->readUInt32();
@ -1798,7 +1799,7 @@ std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readObject(MapObjectID id, MapO
case Obj::GARRISON: case Obj::GARRISON:
case Obj::GARRISON2: case Obj::GARRISON2:
return readGarrison(mapPosition); return readGarrison(mapPosition, objectInstanceID);
case Obj::ARTIFACT: case Obj::ARTIFACT:
case Obj::RANDOM_ART: case Obj::RANDOM_ART:
@ -1806,16 +1807,16 @@ std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readObject(MapObjectID id, MapO
case Obj::RANDOM_MINOR_ART: case Obj::RANDOM_MINOR_ART:
case Obj::RANDOM_MAJOR_ART: case Obj::RANDOM_MAJOR_ART:
case Obj::RANDOM_RELIC_ART: case Obj::RANDOM_RELIC_ART:
return readArtifact(mapPosition, objectTemplate); return readArtifact(mapPosition, objectTemplate, objectInstanceID);
case Obj::SPELL_SCROLL: case Obj::SPELL_SCROLL:
return readScroll(mapPosition, objectTemplate); return readScroll(mapPosition, objectTemplate, objectInstanceID);
case Obj::RANDOM_RESOURCE: case Obj::RANDOM_RESOURCE:
case Obj::RESOURCE: case Obj::RESOURCE:
return readResource(mapPosition, objectTemplate); return readResource(mapPosition, objectTemplate, objectInstanceID);
case Obj::RANDOM_TOWN: case Obj::RANDOM_TOWN:
case Obj::TOWN: case Obj::TOWN:
return readTown(mapPosition, objectTemplate); return readTown(mapPosition, objectTemplate, objectInstanceID);
case Obj::MINE: case Obj::MINE:
case Obj::ABANDONED_MINE: case Obj::ABANDONED_MINE:
@ -1952,14 +1953,7 @@ void CMapLoaderH3M::readObjects()
if (newObject->isVisitable() && !map->isInTheMap(newObject->visitablePos())) if (newObject->isVisitable() && !map->isInTheMap(newObject->visitablePos()))
logGlobal->error("Map '%s': Object at %s - outside of map borders!", mapName, mapPosition.toString()); logGlobal->error("Map '%s': Object at %s - outside of map borders!", mapName, mapPosition.toString());
{ map->generateUniqueInstanceName(newObject.get());
//TODO: define valid typeName and subtypeName for H3M maps
//boost::format fmt("%s_%d");
//fmt % nobj->typeName % nobj->id.getNum();
boost::format fmt("obj_%d");
fmt % newObject->id.getNum();
newObject->instanceName = fmt.str();
}
map->addNewObject(newObject); map->addNewObject(newObject);
nextObjectID.num += 1; nextObjectID.num += 1;
} }
@ -1967,9 +1961,12 @@ void CMapLoaderH3M::readObjects()
map->postInitialize(); map->postInitialize();
} }
void CMapLoaderH3M::readCreatureSet(CCreatureSet * out, int number) void CMapLoaderH3M::readCreatureSet(CArmedInstance * out, const ObjectInstanceID & idToBeGiven)
{ {
for(int index = 0; index < number; ++index) constexpr int unitsToRead = 7;
out->id = idToBeGiven;
for(int index = 0; index < unitsToRead; ++index)
{ {
CreatureID creatureID = reader->readCreature(); CreatureID creatureID = reader->readCreature();
int count = reader->readUInt16(); int count = reader->readUInt16();
@ -2106,7 +2103,7 @@ std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readHero(const int3 & mapPositi
bool hasGarison = reader->readBool(); bool hasGarison = reader->readBool();
if(hasGarison) if(hasGarison)
readCreatureSet(object.get(), 7); readCreatureSet(object.get(), objectInstanceID);
object->formation = static_cast<EArmyFormation>(reader->readInt8Checked(0, 1)); object->formation = static_cast<EArmyFormation>(reader->readInt8Checked(0, 1));
assert(object->formation == EArmyFormation::LOOSE || object->formation == EArmyFormation::TIGHT); assert(object->formation == EArmyFormation::LOOSE || object->formation == EArmyFormation::TIGHT);
@ -2494,7 +2491,7 @@ EQuestMission CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & positi
return missionId; return missionId;
} }
std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readTown(const int3 & position, std::shared_ptr<const ObjectTemplate> objectTemplate) std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readTown(const int3 & position, std::shared_ptr<const ObjectTemplate> objectTemplate, const ObjectInstanceID & idToBeGiven)
{ {
auto object = std::make_shared<CGTownInstance>(map->cb); auto object = std::make_shared<CGTownInstance>(map->cb);
if(features.levelAB) if(features.levelAB)
@ -2512,7 +2509,7 @@ std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readTown(const int3 & position,
bool hasGarrison = reader->readBool(); bool hasGarrison = reader->readBool();
if(hasGarrison) if(hasGarrison)
readCreatureSet(object.get(), 7); readCreatureSet(object.get(), idToBeGiven);
object->formation = static_cast<EArmyFormation>(reader->readInt8Checked(0, 1)); object->formation = static_cast<EArmyFormation>(reader->readInt8Checked(0, 1));
assert(object->formation == EArmyFormation::LOOSE || object->formation == EArmyFormation::TIGHT); assert(object->formation == EArmyFormation::LOOSE || object->formation == EArmyFormation::TIGHT);
@ -2698,7 +2695,7 @@ void CMapLoaderH3M::readEvents()
} }
} }
void CMapLoaderH3M::readMessageAndGuards(MetaString & message, CCreatureSet * guards, const int3 & position) void CMapLoaderH3M::readMessageAndGuards(MetaString & message, CArmedInstance * guards, const int3 & position, const ObjectInstanceID & idToBeGiven)
{ {
bool hasMessage = reader->readBool(); bool hasMessage = reader->readBool();
if(hasMessage) if(hasMessage)
@ -2706,7 +2703,7 @@ void CMapLoaderH3M::readMessageAndGuards(MetaString & message, CCreatureSet * gu
message.appendTextID(readLocalizedString(TextIdentifier("guards", position.x, position.y, position.z, "message"))); message.appendTextID(readLocalizedString(TextIdentifier("guards", position.x, position.y, position.z, "message")));
bool hasGuards = reader->readBool(); bool hasGuards = reader->readBool();
if(hasGuards) if(hasGuards)
readCreatureSet(guards, 7); readCreatureSet(guards, idToBeGiven);
reader->skipZero(4); reader->skipZero(4);
} }

View File

@ -20,6 +20,7 @@ class CGHeroInstance;
class MapReaderH3M; class MapReaderH3M;
class MetaString; class MetaString;
class CArtifactInstance; class CArtifactInstance;
class CArmedInstance;
class CGObjectInstance; class CGObjectInstance;
class CGSeerHut; class CGSeerHut;
class IQuestObject; class IQuestObject;
@ -192,14 +193,14 @@ private:
std::shared_ptr<CGObjectInstance> readMonster(const int3 & objectPosition, const ObjectInstanceID & idToBeGiven); std::shared_ptr<CGObjectInstance> readMonster(const int3 & objectPosition, const ObjectInstanceID & idToBeGiven);
std::shared_ptr<CGObjectInstance> readHero(const int3 & initialPos, const ObjectInstanceID & idToBeGiven); std::shared_ptr<CGObjectInstance> readHero(const int3 & initialPos, const ObjectInstanceID & idToBeGiven);
std::shared_ptr<CGObjectInstance> readSeerHut(const int3 & initialPos, const ObjectInstanceID & idToBeGiven); std::shared_ptr<CGObjectInstance> readSeerHut(const int3 & initialPos, const ObjectInstanceID & idToBeGiven);
std::shared_ptr<CGObjectInstance> readTown(const int3 & position, std::shared_ptr<const ObjectTemplate> objTempl); std::shared_ptr<CGObjectInstance> readTown(const int3 & position, std::shared_ptr<const ObjectTemplate> objTempl, const ObjectInstanceID & idToBeGiven);
std::shared_ptr<CGObjectInstance> readSign(const int3 & position); std::shared_ptr<CGObjectInstance> readSign(const int3 & position);
std::shared_ptr<CGObjectInstance> readWitchHut(const int3 & position, std::shared_ptr<const ObjectTemplate> objectTemplate); std::shared_ptr<CGObjectInstance> readWitchHut(const int3 & position, std::shared_ptr<const ObjectTemplate> objectTemplate);
std::shared_ptr<CGObjectInstance> readScholar(const int3 & position, std::shared_ptr<const ObjectTemplate> objectTemplate); std::shared_ptr<CGObjectInstance> readScholar(const int3 & position, std::shared_ptr<const ObjectTemplate> objectTemplate);
std::shared_ptr<CGObjectInstance> readGarrison(const int3 & mapPosition); std::shared_ptr<CGObjectInstance> readGarrison(const int3 & mapPosition, const ObjectInstanceID & idToBeGiven);
std::shared_ptr<CGObjectInstance> readArtifact(const int3 & position, std::shared_ptr<const ObjectTemplate> objTempl); std::shared_ptr<CGObjectInstance> readArtifact(const int3 & position, std::shared_ptr<const ObjectTemplate> objTempl, const ObjectInstanceID & idToBeGiven);
std::shared_ptr<CGObjectInstance> readScroll(const int3 & position, std::shared_ptr<const ObjectTemplate> objTempl); std::shared_ptr<CGObjectInstance> readScroll(const int3 & position, std::shared_ptr<const ObjectTemplate> objTempl, const ObjectInstanceID & idToBeGiven);
std::shared_ptr<CGObjectInstance> readResource(const int3 & position, std::shared_ptr<const ObjectTemplate> objTempl); std::shared_ptr<CGObjectInstance> readResource(const int3 & position, std::shared_ptr<const ObjectTemplate> objTempl, const ObjectInstanceID & idToBeGiven);
std::shared_ptr<CGObjectInstance> readMine(const int3 & position); std::shared_ptr<CGObjectInstance> readMine(const int3 & position);
std::shared_ptr<CGObjectInstance> readAbandonedMine(const int3 & position); std::shared_ptr<CGObjectInstance> readAbandonedMine(const int3 & position);
std::shared_ptr<CGObjectInstance> readPandora(const int3 & position, const ObjectInstanceID & idToBeGiven); std::shared_ptr<CGObjectInstance> readPandora(const int3 & position, const ObjectInstanceID & idToBeGiven);
@ -225,7 +226,7 @@ private:
* @param out the loaded creature set * @param out the loaded creature set
* @param number the count of creatures to read * @param number the count of creatures to read
*/ */
void readCreatureSet(CCreatureSet * out, int number); void readCreatureSet(CArmedInstance * out, const ObjectInstanceID & idToBeGiven);
void readBoxContent(CGPandoraBox * object, const int3 & position, const ObjectInstanceID & idToBeGiven); void readBoxContent(CGPandoraBox * object, const int3 & position, const ObjectInstanceID & idToBeGiven);
void readBoxHotaContent(CGPandoraBox * object, const int3 & position, const ObjectInstanceID & idToBeGiven); void readBoxHotaContent(CGPandoraBox * object, const int3 & position, const ObjectInstanceID & idToBeGiven);
@ -249,7 +250,7 @@ private:
/** /**
* read optional message and optional guards * read optional message and optional guards
*/ */
void readMessageAndGuards(MetaString & message, CCreatureSet * guards, const int3 & position); void readMessageAndGuards(MetaString & message, CArmedInstance * guards, const int3 & position, const ObjectInstanceID & idToBeGiven);
/// reads string from input stream and converts it to unicode /// reads string from input stream and converts it to unicode
std::string readBasicString(); std::string readBasicString();

View File

@ -1246,7 +1246,7 @@ void RemoveObject::applyGs(CGameState *gs)
} }
} }
gs->getMap().instanceNames.erase(obj->instanceName);
gs->getMap().eraseObject(objectID); gs->getMap().eraseObject(objectID);
gs->getMap().calculateGuardingGreaturePositions();//FIXME: excessive, update only affected tiles gs->getMap().calculateGuardingGreaturePositions();//FIXME: excessive, update only affected tiles
} }
@ -1322,17 +1322,13 @@ void TryMoveHero::applyGs(CGameState *gs)
gs->getMap().removeBlockVisTiles(boat); //hero blockvis mask will be used, we don't need to duplicate it with boat gs->getMap().removeBlockVisTiles(boat); //hero blockvis mask will be used, we don't need to duplicate it with boat
h->setBoat(boat); h->setBoat(boat);
h->attachTo(*boat);
boat->setBoardedHero(h);
} }
else if(result == DISEMBARK) //hero leaves boat to destination tile else if(result == DISEMBARK) //hero leaves boat to destination tile
{ {
auto * b = h->getBoat(); auto * b = h->getBoat();
b->direction = h->moveDir; b->direction = h->moveDir;
b->pos = start; b->pos = start;
b->setBoardedHero(nullptr);
gs->getMap().addBlockVisTiles(b); gs->getMap().addBlockVisTiles(b);
h->detachFrom(*b);
h->setBoat(nullptr); h->setBoat(nullptr);
} }

View File

@ -4263,6 +4263,7 @@ std::shared_ptr<CGObjectInstance> CGameHandler::createNewObject(const int3 & vis
auto o = handler->create(gameState()->cb, nullptr); auto o = handler->create(gameState()->cb, nullptr);
handler->configureObject(o.get(), getRandomGenerator()); handler->configureObject(o.get(), getRandomGenerator());
assert(o->ID == objectID); assert(o->ID == objectID);
gameState()->getMap().generateUniqueInstanceName(o.get());
assert(!handler->getTemplates(terrainType).empty()); assert(!handler->getTemplates(terrainType).empty());
if (handler->getTemplates().empty()) if (handler->getTemplates().empty())