1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Added initiator-player to packs that add/remove/move objects

This commit is contained in:
Ivan Savenko 2023-09-18 22:09:55 +03:00
parent 3cdc3daa2c
commit 8c0d78f1d9
30 changed files with 152 additions and 115 deletions

View File

@ -349,7 +349,7 @@ void AIGateway::newObject(const CGObjectInstance * obj)
//to prevent AI from accessing objects that got deleted while they became invisible (Cover of Darkness, enemy hero moved etc.) below code allows AI to know deletion of objects out of sight
//see: RemoveObject::applyFirstCl, to keep AI "not cheating" do not use advantage of this and use this function just to prevent crashes
void AIGateway::objectRemoved(const CGObjectInstance * obj)
void AIGateway::objectRemoved(const CGObjectInstance * obj, const PlayerColor & initiator)
{
LOG_TRACE(logAi);
NET_EVENT_HANDLER;

View File

@ -156,7 +156,7 @@ public:
void showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector<Component> & components, int soundID) override;
void requestRealized(PackageApplied * pa) override;
void receivedResource() override;
void objectRemoved(const CGObjectInstance * obj) override;
void objectRemoved(const CGObjectInstance * obj, const PlayerColor & initiator) override;
void showUniversityWindow(const IMarket * market, const CGHeroInstance * visitor) override;
void heroManaPointsChanged(const CGHeroInstance * hero) override;
void heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val) override;

View File

@ -385,7 +385,7 @@ void VCAI::newObject(const CGObjectInstance * obj)
//to prevent AI from accessing objects that got deleted while they became invisible (Cover of Darkness, enemy hero moved etc.) below code allows AI to know deletion of objects out of sight
//see: RemoveObject::applyFirstCl, to keep AI "not cheating" do not use advantage of this and use this function just to prevent crashes
void VCAI::objectRemoved(const CGObjectInstance * obj)
void VCAI::objectRemoved(const CGObjectInstance * obj, const PlayerColor & initiator)
{
LOG_TRACE(logAi);
NET_EVENT_HANDLER;

View File

@ -189,7 +189,7 @@ public:
void showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector<Component> & components, int soundID) override;
void requestRealized(PackageApplied * pa) override;
void receivedResource() override;
void objectRemoved(const CGObjectInstance * obj) override;
void objectRemoved(const CGObjectInstance * obj, const PlayerColor & initiator) override;
void showUniversityWindow(const IMarket * market, const CGHeroInstance * visitor) override;
void heroManaPointsChanged(const CGHeroInstance * hero) override;
void heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val) override;

View File

@ -1391,10 +1391,10 @@ void CPlayerInterface::centerView (int3 pos, int focusTime)
CCS->curh->show();
}
void CPlayerInterface::objectRemoved(const CGObjectInstance * obj)
void CPlayerInterface::objectRemoved(const CGObjectInstance * obj, const PlayerColor & initiator)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
if(LOCPLINT->cb->isPlayerMakingTurn(playerID) && obj->getRemovalSound())
if(playerID == initiator && obj->getRemovalSound())
{
waitWhileDialog();
CCS->soundh->playSound(obj->getRemovalSound().value());

View File

@ -140,7 +140,7 @@ protected: // Call-ins from server, should not be called directly, but only via
void centerView (int3 pos, int focusTime) override;
void beforeObjectPropertyChanged(const SetObjectProperty * sop) override;
void objectPropertyChanged(const SetObjectProperty * sop) override;
void objectRemoved(const CGObjectInstance *obj) override;
void objectRemoved(const CGObjectInstance *obj, const PlayerColor & initiator) override;
void objectRemovedAfter() override;
void playerBlocked(int reason, bool start) override;
void gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult) override;

View File

@ -161,8 +161,8 @@ public:
friend class CBattleCallback; //handling players actions
void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> & spells) override {};
bool removeObject(const CGObjectInstance * obj) override {return false;};
void createObject(const int3 & visitablePosition, Obj type, int32_t subtype ) override {};
bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override {return false;};
void createObject(const int3 & visitablePosition, const PlayerColor & initiator, Obj type, int32_t subtype ) override {};
void setOwner(const CGObjectInstance * obj, PlayerColor owner) override {};
void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, bool abs = false) override {};
void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs = false) override {};
@ -204,7 +204,7 @@ public:
void setMovePoints(SetMovePoints * smp) override {};
void setManaPoints(ObjectInstanceID hid, int val) override {};
void giveHero(ObjectInstanceID id, PlayerColor player, ObjectInstanceID boatId = ObjectInstanceID()) override {};
void changeObjPos(ObjectInstanceID objid, int3 newPos) override {};
void changeObjPos(ObjectInstanceID objid, int3 newPos, const PlayerColor & initiator) override {};
void sendAndApply(CPackForClient * pack) override {};
void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2) override {};
void castSpell(const spells::Caster * caster, SpellID spellID, const int3 &pos) override {};

View File

@ -368,15 +368,16 @@ void ApplyFirstClientNetPackVisitor::visitChangeObjPos(ChangeObjPos & pack)
{
CGObjectInstance *obj = gs.getObjInstance(pack.objid);
if(CGI->mh)
CGI->mh->onObjectFadeOut(obj);
CGI->mh->onObjectFadeOut(obj, pack.initiator);
CGI->mh->waitForOngoingAnimations();
}
void ApplyClientNetPackVisitor::visitChangeObjPos(ChangeObjPos & pack)
{
CGObjectInstance *obj = gs.getObjInstance(pack.objid);
if(CGI->mh)
CGI->mh->onObjectFadeIn(obj);
CGI->mh->onObjectFadeIn(obj, pack.initiator);
CGI->mh->waitForOngoingAnimations();
cl.invalidatePaths();
@ -447,10 +448,10 @@ void ApplyClientNetPackVisitor::visitRemoveBonus(RemoveBonus & pack)
void ApplyFirstClientNetPackVisitor::visitRemoveObject(RemoveObject & pack)
{
const CGObjectInstance *o = cl.getObj(pack.id);
const CGObjectInstance *o = cl.getObj(pack.objectID);
if(CGI->mh)
CGI->mh->onObjectFadeOut(o);
CGI->mh->onObjectFadeOut(o, pack.initiator);
//notify interfaces about removal
for(auto i=cl.playerint.begin(); i!=cl.playerint.end(); i++)
@ -458,7 +459,7 @@ void ApplyFirstClientNetPackVisitor::visitRemoveObject(RemoveObject & pack)
//below line contains little cheat for AI so it will be aware of deletion of enemy heroes that moved or got re-covered by FoW
//TODO: loose requirements as next AI related crashes appear, for example another pack.player collects object that got re-covered by FoW, unsure if AI code workarounds this
if(gs.isVisible(o, i->first) || (!cl.getPlayerState(i->first)->human && o->ID == Obj::HERO && o->tempOwner != i->first))
i->second->objectRemoved(o);
i->second->objectRemoved(o, pack.initiator);
}
CGI->mh->waitForOngoingAnimations();
@ -543,12 +544,12 @@ void ApplyClientNetPackVisitor::visitNewStructures(NewStructures & pack)
CGTownInstance *town = gs.getTown(pack.tid);
for(const auto & id : pack.bid)
{
callInterfaceIfPresent(cl, town->tempOwner, &IGameEventsReceiver::buildChanged, town, id, 1);
callInterfaceIfPresent(cl, town->getOwner(), &IGameEventsReceiver::buildChanged, town, id, 1);
}
// invalidate section of map view with our object and force an update
CGI->mh->onObjectInstantRemove(town);
CGI->mh->onObjectInstantAdd(town);
CGI->mh->onObjectInstantRemove(town, town->getOwner());
CGI->mh->onObjectInstantAdd(town, town->getOwner());
}
void ApplyClientNetPackVisitor::visitRazeStructures(RazeStructures & pack)
@ -556,12 +557,12 @@ void ApplyClientNetPackVisitor::visitRazeStructures(RazeStructures & pack)
CGTownInstance * town = gs.getTown(pack.tid);
for(const auto & id : pack.bid)
{
callInterfaceIfPresent(cl, town->tempOwner, &IGameEventsReceiver::buildChanged, town, id, 2);
callInterfaceIfPresent(cl, town->getOwner(), &IGameEventsReceiver::buildChanged, town, id, 2);
}
// invalidate section of map view with our object and force an update
CGI->mh->onObjectInstantRemove(town);
CGI->mh->onObjectInstantAdd(town);
CGI->mh->onObjectInstantRemove(town, town->getOwner());
CGI->mh->onObjectInstantAdd(town, town->getOwner());
}
void ApplyClientNetPackVisitor::visitSetAvailableCreatures(SetAvailableCreatures & pack)
@ -609,17 +610,17 @@ void ApplyClientNetPackVisitor::visitHeroRecruited(HeroRecruited & pack)
if(callInterfaceIfPresent(cl, h->tempOwner, &IGameEventsReceiver::heroCreated, h))
{
if(const CGTownInstance *t = gs.getTown(pack.tid))
callInterfaceIfPresent(cl, h->tempOwner, &IGameEventsReceiver::heroInGarrisonChange, t);
callInterfaceIfPresent(cl, h->getOwner(), &IGameEventsReceiver::heroInGarrisonChange, t);
}
if(CGI->mh)
CGI->mh->onObjectInstantAdd(h);
CGI->mh->onObjectInstantAdd(h, h->getOwner());
}
void ApplyClientNetPackVisitor::visitGiveHero(GiveHero & pack)
{
CGHeroInstance *h = gs.getHero(pack.id);
if(CGI->mh)
CGI->mh->onObjectInstantAdd(h);
CGI->mh->onObjectInstantAdd(h, h->getOwner());
callInterfaceIfPresent(cl, h->tempOwner, &IGameEventsReceiver::heroCreated, h);
}
@ -646,7 +647,10 @@ void ApplyFirstClientNetPackVisitor::visitSetObjectProperty(SetObjectProperty &
// invalidate section of map view with our object and force an update with new flag color
if (pack.what == ObjProperty::OWNER)
CGI->mh->onObjectInstantRemove(gs.getObjInstance(pack.id));
{
auto object = gs.getObjInstance(pack.id);
CGI->mh->onObjectInstantRemove(object, object->getOwner());
}
}
void ApplyClientNetPackVisitor::visitSetObjectProperty(SetObjectProperty & pack)
@ -660,7 +664,10 @@ void ApplyClientNetPackVisitor::visitSetObjectProperty(SetObjectProperty & pack)
// invalidate section of map view with our object and force an update with new flag color
if (pack.what == ObjProperty::OWNER)
CGI->mh->onObjectInstantAdd(gs.getObjInstance(pack.id));
{
auto object = gs.getObjInstance(pack.id);
CGI->mh->onObjectInstantAdd(object, object->getOwner());
}
}
void ApplyClientNetPackVisitor::visitHeroLevelUp(HeroLevelUp & pack)
@ -996,7 +1003,7 @@ void ApplyClientNetPackVisitor::visitNewObject(NewObject & pack)
const CGObjectInstance *obj = cl.getObj(pack.createdObjectID);
if(CGI->mh)
CGI->mh->onObjectFadeIn(obj);
CGI->mh->onObjectFadeIn(obj, pack.initiator);
for(auto i=cl.playerint.begin(); i!=cl.playerint.end(); i++)
{

View File

@ -50,22 +50,22 @@ void MapAudioPlayer::onAfterHeroDisembark(const CGHeroInstance * obj, const int3
update();
}
void MapAudioPlayer::onObjectFadeIn(const CGObjectInstance * obj)
void MapAudioPlayer::onObjectFadeIn(const CGObjectInstance * obj, const PlayerColor & initiator)
{
addObject(obj);
}
void MapAudioPlayer::onObjectFadeOut(const CGObjectInstance * obj)
void MapAudioPlayer::onObjectFadeOut(const CGObjectInstance * obj, const PlayerColor & initiator)
{
removeObject(obj);
}
void MapAudioPlayer::onObjectInstantAdd(const CGObjectInstance * obj)
void MapAudioPlayer::onObjectInstantAdd(const CGObjectInstance * obj, const PlayerColor & initiator)
{
addObject(obj);
}
void MapAudioPlayer::onObjectInstantRemove(const CGObjectInstance * obj)
void MapAudioPlayer::onObjectInstantRemove(const CGObjectInstance * obj, const PlayerColor & initiator)
{
removeObject(obj);
}

View File

@ -15,6 +15,7 @@
VCMI_LIB_NAMESPACE_BEGIN
class ObjectInstanceID;
class CArmedInstance;
class PlayerColor;
VCMI_LIB_NAMESPACE_END
class MapAudioPlayer : public IMapObjectObserver
@ -38,10 +39,10 @@ class MapAudioPlayer : public IMapObjectObserver
protected:
// IMapObjectObserver impl
bool hasOngoingAnimations() override;
void onObjectFadeIn(const CGObjectInstance * obj) override;
void onObjectFadeOut(const CGObjectInstance * obj) override;
void onObjectInstantAdd(const CGObjectInstance * obj) override;
void onObjectInstantRemove(const CGObjectInstance * obj) override;
void onObjectFadeIn(const CGObjectInstance * obj, const PlayerColor & initiator) override;
void onObjectFadeOut(const CGObjectInstance * obj, const PlayerColor & initiator) override;
void onObjectInstantAdd(const CGObjectInstance * obj, const PlayerColor & initiator) override;
void onObjectInstantRemove(const CGObjectInstance * obj, const PlayerColor & initiator) override;
void onHeroMoved(const CGHeroInstance * obj, const int3 & from, const int3 & dest) override;
void onAfterHeroTeleported(const CGHeroInstance * obj, const int3 & from, const int3 & dest) override;

View File

@ -14,6 +14,7 @@ VCMI_LIB_NAMESPACE_BEGIN
class int3;
class CGObjectInstance;
class CGHeroInstance;
class PlayerColor;
VCMI_LIB_NAMESPACE_END
@ -26,16 +27,16 @@ public:
virtual bool hasOngoingAnimations() = 0;
/// Plays fade-in animation and adds object to map
virtual void onObjectFadeIn(const CGObjectInstance * obj) = 0;
virtual void onObjectFadeIn(const CGObjectInstance * obj, const PlayerColor & initiator) = 0;
/// Plays fade-out animation and removed object from map
virtual void onObjectFadeOut(const CGObjectInstance * obj) = 0;
virtual void onObjectFadeOut(const CGObjectInstance * obj, const PlayerColor & initiator) = 0;
/// Adds object to map instantly, with no animation
virtual void onObjectInstantAdd(const CGObjectInstance * obj) = 0;
virtual void onObjectInstantAdd(const CGObjectInstance * obj, const PlayerColor & initiator) = 0;
/// Removes object from map instantly, with no animation
virtual void onObjectInstantRemove(const CGObjectInstance * obj) = 0;
virtual void onObjectInstantRemove(const CGObjectInstance * obj, const PlayerColor & initiator) = 0;
/// Perform hero movement animation, moving hero across terrain
virtual void onHeroMoved(const CGHeroInstance * obj, const int3 & from, const int3 & dest) = 0;

View File

@ -168,7 +168,7 @@ void MapViewController::tick(uint32_t timeDelta)
if(!hero)
hero = boat->hero;
double heroMoveTime = LOCPLINT->makingTurn ?
double heroMoveTime = LOCPLINT->playerID == hero->getOwner() ?
settings["adventure"]["heroMoveTime"].Float() :
settings["adventure"]["enemyMoveTime"].Float();
@ -267,31 +267,35 @@ void MapViewController::afterRender()
}
}
bool MapViewController::isEventInstant(const CGObjectInstance * obj)
bool MapViewController::isEventInstant(const CGObjectInstance * obj, const PlayerColor & initiator)
{
if (!isEventVisible(obj))
if (!isEventVisible(obj, initiator))
return true;
if(!LOCPLINT->makingTurn && settings["adventure"]["enemyMoveTime"].Float() <= 0)
if(initiator != LOCPLINT->playerID && settings["adventure"]["enemyMoveTime"].Float() <= 0)
return true; // instant movement speed
if(LOCPLINT->makingTurn && settings["adventure"]["heroMoveTime"].Float() <= 0)
if(initiator == LOCPLINT->playerID && settings["adventure"]["heroMoveTime"].Float() <= 0)
return true; // instant movement speed
return false;
}
bool MapViewController::isEventVisible(const CGObjectInstance * obj)
bool MapViewController::isEventVisible(const CGObjectInstance * obj, const PlayerColor & initiator)
{
if(adventureContext == nullptr)
return false;
if(!LOCPLINT->makingTurn && settings["adventure"]["enemyMoveTime"].Float() < 0)
if(initiator != LOCPLINT->playerID && settings["adventure"]["enemyMoveTime"].Float() < 0)
return false; // enemy move speed set to "hidden/none"
if(!GH.windows().isTopWindow(adventureInt))
return false;
// do not focus on actions of other players during our turn (e.g. simturns)
if (LOCPLINT->makingTurn && initiator != LOCPLINT->playerID)
return false;
if(obj->isVisitable())
return context->isVisible(obj->visitablePos());
else
@ -303,12 +307,16 @@ bool MapViewController::isEventVisible(const CGHeroInstance * obj, const int3 &
if(adventureContext == nullptr)
return false;
if(!LOCPLINT->makingTurn && settings["adventure"]["enemyMoveTime"].Float() < 0)
if(obj->getOwner() != LOCPLINT->playerID && settings["adventure"]["enemyMoveTime"].Float() < 0)
return false; // enemy move speed set to "hidden/none"
if(!GH.windows().isTopWindow(adventureInt))
return false;
// do not focus on actions of other players during our turn (e.g. simturns)
if (LOCPLINT->makingTurn && obj->getOwner() != LOCPLINT->playerID)
return false;
if(context->isVisible(obj->convertToVisitablePos(from)))
return true;
@ -394,7 +402,7 @@ void MapViewController::onBeforeHeroEmbark(const CGHeroInstance * obj, const int
{
if(isEventVisible(obj, from, dest))
{
if (!isEventInstant(obj))
if (!isEventInstant(obj, obj->getOwner()))
fadeOutObject(obj);
setViewCenter(obj->getSightCenter());
}
@ -418,39 +426,39 @@ void MapViewController::onAfterHeroDisembark(const CGHeroInstance * obj, const i
{
if(isEventVisible(obj, from, dest))
{
if (!isEventInstant(obj))
if (!isEventInstant(obj, obj->getOwner()))
fadeInObject(obj);
setViewCenter(obj->getSightCenter());
}
addObject(obj);
}
void MapViewController::onObjectFadeIn(const CGObjectInstance * obj)
void MapViewController::onObjectFadeIn(const CGObjectInstance * obj, const PlayerColor & initiator)
{
assert(!hasOngoingAnimations());
if(isEventVisible(obj) && !isEventInstant(obj) )
if(isEventVisible(obj, initiator) && !isEventInstant(obj, initiator) )
fadeInObject(obj);
addObject(obj);
}
void MapViewController::onObjectFadeOut(const CGObjectInstance * obj)
void MapViewController::onObjectFadeOut(const CGObjectInstance * obj, const PlayerColor & initiator)
{
assert(!hasOngoingAnimations());
if(isEventVisible(obj) && !isEventInstant(obj) )
if(isEventVisible(obj, initiator) && !isEventInstant(obj, initiator) )
fadeOutObject(obj);
else
removeObject(obj);
}
void MapViewController::onObjectInstantAdd(const CGObjectInstance * obj)
void MapViewController::onObjectInstantAdd(const CGObjectInstance * obj, const PlayerColor & initiator)
{
addObject(obj);
};
void MapViewController::onObjectInstantRemove(const CGObjectInstance * obj)
void MapViewController::onObjectInstantRemove(const CGObjectInstance * obj, const PlayerColor & initiator)
{
removeObject(obj);
};

View File

@ -14,6 +14,7 @@
VCMI_LIB_NAMESPACE_BEGIN
struct ObjectPosInfo;
class PlayerColor;
VCMI_LIB_NAMESPACE_END
struct MapRendererContextState;
@ -55,8 +56,8 @@ private:
Point targetTileSize = Point(32, 32);
bool wasInDeadZone = true;
bool isEventInstant(const CGObjectInstance * obj);
bool isEventVisible(const CGObjectInstance * obj);
bool isEventInstant(const CGObjectInstance * obj, const PlayerColor & initiator);
bool isEventVisible(const CGObjectInstance * obj, const PlayerColor & initiator);
bool isEventVisible(const CGHeroInstance * obj, const int3 & from, const int3 & dest);
void fadeOutObject(const CGObjectInstance * obj);
@ -67,10 +68,10 @@ private:
// IMapObjectObserver impl
bool hasOngoingAnimations() override;
void onObjectFadeIn(const CGObjectInstance * obj) override;
void onObjectFadeOut(const CGObjectInstance * obj) override;
void onObjectInstantAdd(const CGObjectInstance * obj) override;
void onObjectInstantRemove(const CGObjectInstance * obj) override;
void onObjectFadeIn(const CGObjectInstance * obj, const PlayerColor & initiator) override;
void onObjectFadeOut(const CGObjectInstance * obj, const PlayerColor & initiator) override;
void onObjectInstantAdd(const CGObjectInstance * obj, const PlayerColor & initiator) override;
void onObjectInstantRemove(const CGObjectInstance * obj, const PlayerColor & initiator) override;
void onAfterHeroTeleported(const CGHeroInstance * obj, const int3 & from, const int3 & dest) override;
void onBeforeHeroTeleported(const CGHeroInstance * obj, const int3 & from, const int3 & dest) override;
void onHeroMoved(const CGHeroInstance * obj, const int3 & from, const int3 & dest) override;

View File

@ -144,16 +144,16 @@ bool CMapHandler::isInMap(const int3 & tile)
return map->isInTheMap(tile);
}
void CMapHandler::onObjectFadeIn(const CGObjectInstance * obj)
void CMapHandler::onObjectFadeIn(const CGObjectInstance * obj, const PlayerColor & initiator)
{
for(auto * observer : observers)
observer->onObjectFadeIn(obj);
observer->onObjectFadeIn(obj, initiator);
}
void CMapHandler::onObjectFadeOut(const CGObjectInstance * obj)
void CMapHandler::onObjectFadeOut(const CGObjectInstance * obj, const PlayerColor & initiator)
{
for(auto * observer : observers)
observer->onObjectFadeOut(obj);
observer->onObjectFadeOut(obj, initiator);
}
void CMapHandler::onBeforeHeroEmbark(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
@ -180,16 +180,16 @@ void CMapHandler::onAfterHeroDisembark(const CGHeroInstance * obj, const int3 &
observer->onAfterHeroDisembark(obj, from, dest);
}
void CMapHandler::onObjectInstantAdd(const CGObjectInstance * obj)
void CMapHandler::onObjectInstantAdd(const CGObjectInstance * obj, const PlayerColor & initiator)
{
for(auto * observer : observers)
observer->onObjectInstantAdd(obj);
observer->onObjectInstantAdd(obj, initiator);
}
void CMapHandler::onObjectInstantRemove(const CGObjectInstance * obj)
void CMapHandler::onObjectInstantRemove(const CGObjectInstance * obj, const PlayerColor & initiator)
{
for(auto * observer : observers)
observer->onObjectInstantRemove(obj);
observer->onObjectInstantRemove(obj, initiator);
}
void CMapHandler::onAfterHeroTeleported(const CGHeroInstance * obj, const int3 & from, const int3 & dest)

View File

@ -47,10 +47,10 @@ public:
bool isInMap(const int3 & tile);
/// see MapObjectObserver interface
void onObjectFadeIn(const CGObjectInstance * obj);
void onObjectFadeOut(const CGObjectInstance * obj);
void onObjectInstantAdd(const CGObjectInstance * obj);
void onObjectInstantRemove(const CGObjectInstance * obj);
void onObjectFadeIn(const CGObjectInstance * obj, const PlayerColor & initiator);
void onObjectFadeOut(const CGObjectInstance * obj, const PlayerColor & initiator);
void onObjectInstantAdd(const CGObjectInstance * obj, const PlayerColor & initiator);
void onObjectInstantRemove(const CGObjectInstance * obj, const PlayerColor & initiator);
void onBeforeHeroTeleported(const CGHeroInstance * obj, const int3 & from, const int3 & dest);
void onAfterHeroTeleported(const CGHeroInstance * obj, const int3 & from, const int3 & dest);
void onBeforeHeroEmbark(const CGHeroInstance * obj, const int3 & from, const int3 & dest);

View File

@ -89,8 +89,8 @@ public:
virtual void showInfoDialog(const std::string & msg, PlayerColor player) = 0;
virtual void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> &spells)=0;
virtual bool removeObject(const CGObjectInstance * obj)=0;
virtual void createObject(const int3 & visitablePosition, Obj type, int32_t subtype = 0) = 0;
virtual bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) = 0;
virtual void createObject(const int3 & visitablePosition, const PlayerColor & initiator, Obj type, int32_t subtype = 0) = 0;
virtual void setOwner(const CGObjectInstance * objid, PlayerColor owner)=0;
virtual void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, bool abs=false)=0;
virtual void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false)=0;
@ -132,7 +132,7 @@ public:
virtual void setMovePoints(SetMovePoints * smp)=0;
virtual void setManaPoints(ObjectInstanceID hid, int val)=0;
virtual void giveHero(ObjectInstanceID id, PlayerColor player, ObjectInstanceID boatId = ObjectInstanceID()) = 0;
virtual void changeObjPos(ObjectInstanceID objid, int3 newPos)=0;
virtual void changeObjPos(ObjectInstanceID objid, int3 newPos, const PlayerColor & initiator)=0;
virtual void sendAndApply(CPackForClient * pack) = 0;
virtual void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2)=0; //when two heroes meet on adventure map
virtual void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) = 0;

View File

@ -129,7 +129,7 @@ public:
virtual void requestRealized(PackageApplied *pa){};
virtual void beforeObjectPropertyChanged(const SetObjectProperty * sop){}; //eg. mine has been flagged
virtual void objectPropertyChanged(const SetObjectProperty * sop){}; //eg. mine has been flagged
virtual void objectRemoved(const CGObjectInstance *obj){}; //eg. collected resource, picked artifact, beaten hero
virtual void objectRemoved(const CGObjectInstance *obj, const PlayerColor & initiator){}; //eg. collected resource, picked artifact, beaten hero
virtual void objectRemovedAfter(){}; //eg. collected resource, picked artifact, beaten hero
virtual void playerBlocked(int reason, bool start){}; //reason: 0 - upcoming battle
virtual void gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult) {}; //player lost or won the game

View File

@ -424,6 +424,8 @@ struct DLL_LINKAGE ChangeObjPos : public CPackForClient
ObjectInstanceID objid;
/// New position of visitable tile of an object
int3 nPos;
/// Player that initiated this action, if any
PlayerColor initiator;
virtual void visitTyped(ICPackVisitor & visitor) override;
@ -431,6 +433,7 @@ struct DLL_LINKAGE ChangeObjPos : public CPackForClient
{
h & objid;
h & nPos;
h & initiator;
}
};
@ -613,19 +616,25 @@ struct DLL_LINKAGE ChangeFormation : public CPackForClient
struct DLL_LINKAGE RemoveObject : public CPackForClient
{
RemoveObject() = default;
RemoveObject(const ObjectInstanceID & ID)
: id(ID)
RemoveObject(const ObjectInstanceID & objectID, const PlayerColor & initiator)
: objectID(objectID)
, initiator(initiator)
{
}
void applyGs(CGameState * gs);
virtual void visitTyped(ICPackVisitor & visitor) override;
ObjectInstanceID id;
/// ID of removed object
ObjectInstanceID objectID;
/// Player that initiated this action, if any
PlayerColor initiator;
template <typename Handler> void serialize(Handler & h, const int version)
{
h & id;
h & objectID;
h & initiator;
}
};
@ -803,6 +812,8 @@ struct DLL_LINKAGE NewObject : public CPackForClient
ui32 subID = 0;
/// Position of visitable tile of created object
int3 targetPos;
/// Which player initiated creation of this object
PlayerColor initiator;
ObjectInstanceID createdObjectID; //used locally, filled during applyGs
@ -813,6 +824,7 @@ struct DLL_LINKAGE NewObject : public CPackForClient
h & ID;
h & subID;
h & targetPos;
h & initiator;
}
};

View File

@ -1118,8 +1118,8 @@ void RemoveBonus::applyGs(CGameState *gs)
void RemoveObject::applyGs(CGameState *gs)
{
CGObjectInstance *obj = gs->getObjInstance(id);
logGlobal->debug("removing object id=%d; address=%x; name=%s", id, (intptr_t)obj, obj->getObjectName());
CGObjectInstance *obj = gs->getObjInstance(objectID);
logGlobal->debug("removing object id=%d; address=%x; name=%s", objectID, (intptr_t)obj, obj->getObjectName());
//unblock tiles
gs->map->removeBlockVisTiles(obj);
@ -1159,7 +1159,7 @@ void RemoveObject::applyGs(CGameState *gs)
//return hero to the pool, so he may reappear in tavern
gs->heroesPool->addHeroToPool(beatenHero);
gs->map->objects[id.getNum()] = nullptr;
gs->map->objects[objectID.getNum()] = nullptr;
//If hero on Boat is removed, the Boat disappears
if(beatenHero->boat)
@ -1210,7 +1210,7 @@ void RemoveObject::applyGs(CGameState *gs)
event.trigger = event.trigger.morph(patcher);
}
gs->map->instanceNames.erase(obj->instanceName);
gs->map->objects[id.getNum()].dellNull();
gs->map->objects[objectID.getNum()].dellNull();
gs->map->calculateGuardingGreaturePositions();
}

View File

@ -299,7 +299,7 @@ void CGCreature::fleeDecision(const CGHeroInstance *h, ui32 pursue) const
}
else
{
cb->removeObject(this);
cb->removeObject(this, h->getOwner());
}
}
@ -400,12 +400,12 @@ void CGCreature::battleFinished(const CGHeroInstance *hero, const BattleResult &
if(result.winner == 0)
{
giveReward(hero);
cb->removeObject(this);
cb->removeObject(this, hero->getOwner());
}
else if(result.winner > 1) // draw
{
// guarded reward is lost forever on draw
cb->removeObject(this);
cb->removeObject(this, hero->getOwner());
}
else
{

View File

@ -196,7 +196,7 @@ void CGPandoraBox::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answe
else if(getAvailableRewards(hero, Rewardable::EEventType::EVENT_FIRST_VISIT).empty())
{
hero->showInfoDialog(15);
cb->removeObject(this);
cb->removeObject(this, hero->getOwner());
}
else //if it gives something without battle
{

View File

@ -980,7 +980,7 @@ void CGBorderGuard::onHeroVisit(const CGHeroInstance * h) const
void CGBorderGuard::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
{
if (answer)
cb->removeObject(this);
cb->removeObject(this, hero->getOwner());
}
void CGBorderGuard::afterAddToMap(CMap * map)

View File

@ -299,7 +299,7 @@ void CGResource::collectRes(const PlayerColor & player) const
sii.components.emplace_back(Component::EComponentType::RESOURCE,subID,amount,0);
sii.soundID = soundBase::pickup01 + CRandomGenerator::getDefault().nextInt(6);
cb->showInfoDialog(&sii);
cb->removeObject(this);
cb->removeObject(this, player);
}
void CGResource::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
@ -797,7 +797,7 @@ void CGArtifact::onHeroVisit(const CGHeroInstance * h) const
void CGArtifact::pick(const CGHeroInstance * h) const
{
if(cb->giveHeroArtifact(h, storedArtifact, ArtifactPosition::FIRST_AVAILABLE))
cb->removeObject(this);
cb->removeObject(this, h->getOwner());
}
BattleField CGArtifact::getBattlefield() const
@ -1063,7 +1063,7 @@ void CGSignBottle::onHeroVisit( const CGHeroInstance * h ) const
cb->showInfoDialog(&iw);
if(ID == Obj::OCEAN_BOTTLE)
cb->removeObject(this);
cb->removeObject(this, h->getOwner());
}
void CGSignBottle::serializeJsonOptions(JsonSerializeFormat& handler)
@ -1113,7 +1113,7 @@ void CGScholar::onHeroVisit( const CGHeroInstance * h ) const
}
cb->showInfoDialog(&iw);
cb->removeObject(this);
cb->removeObject(this, h->getOwner());
}
void CGScholar::initObj(CRandomGenerator & rand)

View File

@ -202,6 +202,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
ChangeObjPos cop;
cop.objid = nearest->id;
cop.nPos = summonPos;
cop.initiator = parameters.caster->getCasterOwner();
env->apply(&cop);
}
else if(schoolLevel < 2) //none or basic level -> cannot create boat :(
@ -217,6 +218,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
no.ID = Obj::BOAT;
no.subID = BoatId::NECROPOLIS;
no.targetPos = summonPos;
no.initiator = parameters.caster->getCasterOwner();
env->apply(&no);
}
return ESpellCastResult::OK;
@ -257,7 +259,8 @@ ESpellCastResult ScuttleBoatMechanics::applyAdventureEffects(SpellCastEnvironmen
}
RemoveObject ro;
ro.id = t->visitableObjects.back()->id;
ro.initiator = parameters.caster->getCasterOwner();
ro.objectID = t->visitableObjects.back()->id;
env->apply(&ro);
return ESpellCastResult::OK;
}

View File

@ -1045,7 +1045,7 @@ void CGameHandler::giveSpells(const CGTownInstance *t, const CGHeroInstance *h)
sendAndApply(&cs);
}
bool CGameHandler::removeObject(const CGObjectInstance * obj)
bool CGameHandler::removeObject(const CGObjectInstance * obj, const PlayerColor & initiator)
{
if (!obj || !getObj(obj->id))
{
@ -1054,7 +1054,8 @@ bool CGameHandler::removeObject(const CGObjectInstance * obj)
}
RemoveObject ro;
ro.id = obj->id;
ro.objectID = obj->id;
ro.initiator = initiator;
sendAndApply(&ro);
checkVictoryLossConditionsForAll(); //eg if monster escaped (removing objs after battle is done dircetly by endBattle, not this function)
@ -1111,7 +1112,8 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
const bool standAtObstacle = t.blocked && !t.visitable;
const bool standAtWater = !h->boat && t.terType->isWater() && (t.visitableObjects.empty() || !t.visitableObjects.back()->isCoastVisitable());
auto const complainRet = [&](const std::string & message){
const auto complainRet = [&](const std::string & message)
{
//send info about movement failure
complain(message);
sendAndApply(&tmh);
@ -1504,11 +1506,12 @@ void CGameHandler::giveHero(ObjectInstanceID id, PlayerColor player, ObjectInsta
changeFogOfWar(h->pos, h->getSightRadius(), player, false);
}
void CGameHandler::changeObjPos(ObjectInstanceID objid, int3 newPos)
void CGameHandler::changeObjPos(ObjectInstanceID objid, int3 newPos, const PlayerColor & initiator)
{
ChangeObjPos cop;
cop.objid = objid;
cop.nPos = newPos;
cop.initiator = initiator;
sendAndApply(&cop);
}
@ -3462,7 +3465,7 @@ bool CGameHandler::buildBoat(ObjectInstanceID objid, PlayerColor playerID)
}
giveResources(playerID, -boatCost);
createObject(tile, Obj::BOAT, obj->getBoatType().getNum());
createObject(tile, playerID, Obj::BOAT, obj->getBoatType().getNum());
return true;
}
@ -3538,7 +3541,7 @@ void CGameHandler::checkVictoryLossConditionsForPlayer(PlayerColor player)
for (auto h : hlp) //eliminate heroes
{
if (h.get())
removeObject(h);
removeObject(h, player);
}
//player lost -> all his objects become unflagged (neutral)
@ -3587,7 +3590,7 @@ bool CGameHandler::dig(const CGHeroInstance *h)
if (h->diggingStatus() != EDiggingStatus::CAN_DIG) //checks for terrain and movement
COMPLAIN_RETF("Hero cannot dig (error code %d)!", static_cast<int>(h->diggingStatus()));
createObject(h->visitablePos(), Obj::HOLE, 0 );
createObject(h->visitablePos(), h->getOwner(), Obj::HOLE, 0 );
//take MPs
SetMovePoints smp;
@ -3981,7 +3984,7 @@ void CGameHandler::spawnWanderingMonsters(CreatureID creatureID)
{
auto count = cre->getRandomAmount(std::rand);
createObject(*tile, Obj::MONSTER, creatureID);
createObject(*tile, PlayerColor::NEUTRAL, Obj::MONSTER, creatureID);
auto monsterId = getTopObj(*tile)->id;
setObjProperty(monsterId, ObjProperty::MONSTER_COUNT, count);
@ -4123,11 +4126,12 @@ scripting::Pool * CGameHandler::getGlobalContextPool() const
//}
#endif
void CGameHandler::createObject(const int3 & visitablePosition, Obj type, int32_t subtype)
void CGameHandler::createObject(const int3 & visitablePosition, const PlayerColor & initiator, Obj type, int32_t subtype)
{
NewObject no;
no.ID = type;
no.subID = subtype;
no.initiator = initiator;
no.targetPos = visitablePosition;
sendAndApply(&no);
}

View File

@ -100,8 +100,8 @@ public:
//from IGameCallback
//do sth
void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> &spells) override;
bool removeObject(const CGObjectInstance * obj) override;
void createObject(const int3 & visitablePosition, Obj type, int32_t subtype ) override;
bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override;
void createObject(const int3 & visitablePosition, const PlayerColor & initiator, Obj type, int32_t subtype ) override;
void setOwner(const CGObjectInstance * obj, PlayerColor owner) override;
void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, bool abs=false) override;
void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false) override;
@ -145,7 +145,7 @@ public:
void setMovePoints(SetMovePoints * smp) override;
void setManaPoints(ObjectInstanceID hid, int val) override;
void giveHero(ObjectInstanceID id, PlayerColor player, ObjectInstanceID boatId = ObjectInstanceID()) override;
void changeObjPos(ObjectInstanceID objid, int3 newPos) override;
void changeObjPos(ObjectInstanceID objid, int3 newPos, const PlayerColor & initiator) override;
void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2) override;
void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) override;

View File

@ -44,7 +44,7 @@ void ApplyGhNetPackVisitor::visitEndTurn(EndTurn & pack)
void ApplyGhNetPackVisitor::visitDismissHero(DismissHero & pack)
{
gh.throwIfWrongOwner(&pack, pack.hid);
result = gh.removeObject(gh.getObj(pack.hid));
result = gh.removeObject(gh.getObj(pack.hid), pack.player);
}
void ApplyGhNetPackVisitor::visitMoveHero(MoveHero & pack)

View File

@ -469,12 +469,12 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
if(finishingBattle->loserHero) //remove beaten hero
{
RemoveObject ro(finishingBattle->loserHero->id);
RemoveObject ro(finishingBattle->loserHero->id, battle.battleGetArmyObject(0)->getOwner());
gameHandler->sendAndApply(&ro);
}
if(finishingBattle->isDraw() && finishingBattle->winnerHero) //for draw case both heroes should be removed
{
RemoveObject ro(finishingBattle->winnerHero->id);
RemoveObject ro(finishingBattle->winnerHero->id, battle.battleGetArmyObject(0)->getOwner());
gameHandler->sendAndApply(&ro);
}
@ -557,7 +557,7 @@ void BattleResultProcessor::battleAfterLevelUp(const BattleID & battleID, const
if (result.winner != 2 && finishingBattle->winnerHero && finishingBattle->winnerHero->stacks.empty()
&& (!finishingBattle->winnerHero->commander || !finishingBattle->winnerHero->commander->alive))
{
RemoveObject ro(finishingBattle->winnerHero->id);
RemoveObject ro(finishingBattle->winnerHero->id, finishingBattle->winnerHero->getOwner());
gameHandler->sendAndApply(&ro);
if (VLC->settings()->getBoolean(EGameSettings::HEROES_RETREAT_ON_WIN_WITHOUT_TROOPS))

View File

@ -203,7 +203,7 @@ bool HeroPoolProcessor::hireHero(const ObjectInstanceID & objectID, const HeroTy
if(gameHandler->getTile(targetPos)->isWater() && !recruitedHero->boat)
{
//Create a new boat for hero
gameHandler->createObject(targetPos , Obj::BOAT, recruitedHero->getBoatType().getNum());
gameHandler->createObject(targetPos, player, Obj::BOAT, recruitedHero->getBoatType().getNum());
hr.boatId = gameHandler->getTopObj(targetPos)->id;
}

View File

@ -61,7 +61,7 @@ void CObjectVisitQuery::onRemoval(PlayerColor color)
//TODO or should it be destructor?
//Can object visit affect 2 players and what would be desired behavior?
if(removeObjectAfterVisit)
gh->removeObject(visitedObject);
gh->removeObject(visitedObject, color);
}
void CObjectVisitQuery::onExposure(QueryPtr topQuery)