1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-07 00:58:39 +02:00

NewObject pack now receives visitable position instead of h3m position

This commit is contained in:
Ivan Savenko
2023-06-20 22:06:45 +03:00
parent 56680e102d
commit d8879f1e53
8 changed files with 45 additions and 64 deletions

View File

@ -961,7 +961,7 @@ void ApplyClientNetPackVisitor::visitNewObject(NewObject & pack)
{ {
cl.invalidatePaths(); cl.invalidatePaths();
const CGObjectInstance *obj = cl.getObj(pack.id); const CGObjectInstance *obj = cl.getObj(pack.createdObjectID);
if(CGI->mh) if(CGI->mh)
CGI->mh->onObjectFadeIn(obj); CGI->mh->onObjectFadeIn(obj);

View File

@ -745,11 +745,14 @@ struct DLL_LINKAGE NewObject : public CPackForClient
{ {
void applyGs(CGameState * gs); void applyGs(CGameState * gs);
/// Object ID to create
Obj ID; Obj ID;
/// Object secondary ID to create
ui32 subID = 0; ui32 subID = 0;
int3 pos; /// Position of visitable tile of created object
int3 targetPos;
ObjectInstanceID id; //used locally, filled during applyGs ObjectInstanceID createdObjectID; //used locally, filled during applyGs
virtual void visitTyped(ICPackVisitor & visitor) override; virtual void visitTyped(ICPackVisitor & visitor) override;
@ -757,7 +760,7 @@ struct DLL_LINKAGE NewObject : public CPackForClient
{ {
h & ID; h & ID;
h & subID; h & subID;
h & pos; h & targetPos;
} }
}; };

View File

@ -1492,32 +1492,20 @@ void NewObject::applyGs(CGameState *gs)
{ {
TerrainId terrainType = ETerrainId::NONE; TerrainId terrainType = ETerrainId::NONE;
if(ID == Obj::BOAT && !gs->isInTheMap(pos)) //special handling for bug #3060 - pos outside map but visitablePos is not if (!gs->isInTheMap(targetPos))
{ {
CGObjectInstance testObject = CGObjectInstance(); logGlobal->error("Attempt to create object outside map at %s!", targetPos.toString());
testObject.pos = pos; return;
testObject.appearance = VLC->objtypeh->getHandlerFor(ID, subID)->getTemplates(ETerrainId::WATER).front(); }
[[maybe_unused]] const int3 previousXAxisTile = CGBoat::translatePos(pos, true); const TerrainTile & t = gs->map->getTile(targetPos);
assert(gs->isInTheMap(previousXAxisTile) && (testObject.visitablePos() == previousXAxisTile));
}
else
{
const TerrainTile & t = gs->map->getTile(pos);
terrainType = t.terType->getId(); terrainType = t.terType->getId();
}
auto handler = VLC->objtypeh->getHandlerFor(ID, subID); auto handler = VLC->objtypeh->getHandlerFor(ID, subID);
CGObjectInstance * o = handler->create(); CGObjectInstance * o = handler->create();
handler->configureObject(o, gs->getRandomGenerator()); handler->configureObject(o, gs->getRandomGenerator());
switch(ID) if (ID == Obj::MONSTER) //probably more options will be needed
{
case Obj::BOAT:
terrainType = ETerrainId::WATER; //TODO: either boat should only spawn on water, or all water objects should be handled this way
break;
case Obj::MONSTER: //probably more options will be needed
{ {
//CStackInstance hlp; //CStackInstance hlp;
auto * cre = dynamic_cast<CGCreature *>(o); auto * cre = dynamic_cast<CGCreature *>(o);
@ -1529,20 +1517,27 @@ void NewObject::applyGs(CGameState *gs)
cre->identifier = -1; cre->identifier = -1;
cre->addToSlot(SlotID(0), new CStackInstance(CreatureID(subID), -1)); //add placeholder stack cre->addToSlot(SlotID(0), new CStackInstance(CreatureID(subID), -1)); //add placeholder stack
} }
break;
} assert(!handler->getTemplates(terrainType).empty());
if (!handler->getTemplates(terrainType).empty())
o->appearance = handler->getTemplates(terrainType).front();
else
o->appearance = handler->getTemplates().front();
o->id = ObjectInstanceID(static_cast<si32>(gs->map->objects.size()));
o->ID = ID; o->ID = ID;
o->subID = subID; o->subID = subID;
o->pos = pos; o->pos = targetPos - o->getVisitableOffset();
o->appearance = handler->getTemplates(terrainType).front();
id = o->id = ObjectInstanceID(static_cast<si32>(gs->map->objects.size()));
gs->map->objects.emplace_back(o); gs->map->objects.emplace_back(o);
gs->map->addBlockVisTiles(o); gs->map->addBlockVisTiles(o);
o->initObj(gs->getRandomGenerator()); o->initObj(gs->getRandomGenerator());
gs->map->calculateGuardingGreaturePositions(); gs->map->calculateGuardingGreaturePositions();
logGlobal->debug("Added object id=%d; address=%x; name=%s", id, (intptr_t)o, o->getObjectName()); createdObjectID = o->id;
logGlobal->debug("Added object id=%d; address=%x; name=%s", o->id, (intptr_t)o, o->getObjectName());
} }
void NewArtifact::applyGs(CGameState *gs) void NewArtifact::applyGs(CGameState *gs)

View File

@ -454,6 +454,7 @@ void CGHeroInstance::onHeroVisit(const CGHeroInstance * h) const
NewObject no; NewObject no;
no.ID = Obj::BOAT; no.ID = Obj::BOAT;
no.subID = getBoatType().getNum(); no.subID = getBoatType().getNum();
no.targetPos = boatPos;
cb->sendAndApply(&no); cb->sendAndApply(&no);

View File

@ -1294,22 +1294,6 @@ CGBoat::CGBoat()
layer = EPathfindingLayer::EEPathfindingLayer::SAIL; layer = EPathfindingLayer::EEPathfindingLayer::SAIL;
} }
int3 CGBoat::translatePos(const int3& pos, bool reverse /* = false */)
{
//pos - offset we want to place the boat at the map
//returned value - actual position as seen by game mechanics
//If reverse = true, then it's the opposite.
if (!reverse)
{
return pos + int3(1, 0, 0);
}
else
{
return pos - int3(1, 0, 0);
}
}
void CGSirens::initObj(CRandomGenerator & rand) void CGSirens::initObj(CRandomGenerator & rand)
{ {
blockVisit = true; blockVisit = true;
@ -1409,8 +1393,7 @@ void CGShipyard::serializeJsonOptions(JsonSerializeFormat& handler)
BoatId CGShipyard::getBoatType() const BoatId CGShipyard::getBoatType() const
{ {
// In H3, external shipyard will always create same boat as castle return createdBoat;
return EBoatId::CASTLE;
} }
void CCartographer::onHeroVisit( const CGHeroInstance * h ) const void CCartographer::onHeroVisit( const CGHeroInstance * h ) const

View File

@ -359,7 +359,6 @@ public:
std::array<std::string, PlayerColor::PLAYER_LIMIT_I> flagAnimations; std::array<std::string, PlayerColor::PLAYER_LIMIT_I> flagAnimations;
CGBoat(); CGBoat();
static int3 translatePos(const int3 &pos, bool reverse = false);
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {

View File

@ -201,7 +201,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
{ {
ChangeObjPos cop; ChangeObjPos cop;
cop.objid = nearest->id; cop.objid = nearest->id;
cop.nPos = CGBoat::translatePos(summonPos); cop.nPos = summonPos;
env->apply(&cop); env->apply(&cop);
} }
else if(schoolLevel < 2) //none or basic level -> cannot create boat :( else if(schoolLevel < 2) //none or basic level -> cannot create boat :(
@ -216,7 +216,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
NewObject no; NewObject no;
no.ID = Obj::BOAT; no.ID = Obj::BOAT;
no.subID = BoatId(EBoatId::NECROPOLIS); no.subID = BoatId(EBoatId::NECROPOLIS);
no.pos = CGBoat::translatePos(summonPos); no.targetPos = summonPos;
env->apply(&no); env->apply(&no);
} }
return ESpellCastResult::OK; return ESpellCastResult::OK;

View File

@ -4432,7 +4432,7 @@ bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, PlayerColor pl
NewObject no; NewObject no;
no.ID = Obj::BOAT; no.ID = Obj::BOAT;
no.subID = nh->getBoatType().getNum(); no.subID = nh->getBoatType().getNum();
no.pos = hr.tile + int3(1,0,0); no.targetPos = obj->visitablePos();
sendAndApply(&no); sendAndApply(&no);
hr.boatId = getTopObj(hr.tile)->id; hr.boatId = getTopObj(hr.tile)->id;
@ -5660,7 +5660,7 @@ bool CGameHandler::buildBoat(ObjectInstanceID objid, PlayerColor playerID)
NewObject no; NewObject no;
no.ID = Obj::BOAT; no.ID = Obj::BOAT;
no.subID = obj->getBoatType().getNum(); no.subID = obj->getBoatType().getNum();
no.pos = tile + int3(1,0,0); no.targetPos = tile;
sendAndApply(&no); sendAndApply(&no);
return true; return true;
@ -5806,7 +5806,7 @@ bool CGameHandler::dig(const CGHeroInstance *h)
//create a hole //create a hole
NewObject no; NewObject no;
no.ID = Obj::HOLE; no.ID = Obj::HOLE;
no.pos = h->visitablePos(); no.targetPos = h->visitablePos();
no.subID = 0; no.subID = 0;
sendAndApply(&no); sendAndApply(&no);
@ -7409,7 +7409,7 @@ const ObjectInstanceID CGameHandler::putNewObject(Obj ID, int subID, int3 pos)
NewObject no; NewObject no;
no.ID = ID; //creature no.ID = ID; //creature
no.subID= subID; no.subID= subID;
no.pos = pos; no.targetPos = pos;
sendAndApply(&no); sendAndApply(&no);
return no.id; //id field will be filled during applying on gs return no.createdObjectID; //id field will be filled during applying on gs
} }