mirror of
https://github.com/vcmi/vcmi.git
synced 2025-04-25 12:14:46 +02:00
Implemented tracking of objects destroyed by players
This commit is contained in:
parent
ccea7fc1fb
commit
2e4895766a
AI
lib
CGameInfoCallback.cppCGameInfoCallback.hCPlayerState.h
gameState
mapObjects
mapping
networkPacks
serializer
@ -210,7 +210,7 @@ TGoalVec CompleteQuest::missionResources() const
|
|||||||
|
|
||||||
TGoalVec CompleteQuest::missionDestroyObj() const
|
TGoalVec CompleteQuest::missionDestroyObj() const
|
||||||
{
|
{
|
||||||
auto obj = cb->getObjByQuestIdentifier(q.quest->killTarget);
|
auto obj = cb->getObj(q.quest->killTarget);
|
||||||
|
|
||||||
if(!obj)
|
if(!obj)
|
||||||
return CaptureObjectsBehavior(q.obj).decompose();
|
return CaptureObjectsBehavior(q.obj).decompose();
|
||||||
|
@ -241,7 +241,7 @@ TGoalVec CompleteQuest::missionDestroyObj() const
|
|||||||
{
|
{
|
||||||
TGoalVec solutions;
|
TGoalVec solutions;
|
||||||
|
|
||||||
auto obj = cb->getObjByQuestIdentifier(q.quest->killTarget);
|
auto obj = cb->getObj(q.quest->killTarget);
|
||||||
|
|
||||||
if(!obj)
|
if(!obj)
|
||||||
return ai->ah->howToVisitObj(q.obj);
|
return ai->ah->howToVisitObj(q.obj);
|
||||||
|
@ -124,20 +124,6 @@ TurnTimerInfo CGameInfoCallback::getPlayerTurnTime(PlayerColor color) const
|
|||||||
return TurnTimerInfo{};
|
return TurnTimerInfo{};
|
||||||
}
|
}
|
||||||
|
|
||||||
const CGObjectInstance * CGameInfoCallback::getObjByQuestIdentifier(ObjectInstanceID identifier) const
|
|
||||||
{
|
|
||||||
if(gs->map->questIdentifierToId.empty())
|
|
||||||
{
|
|
||||||
//assume that it is VCMI map and quest identifier equals instance identifier
|
|
||||||
return getObj(identifier, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ERROR_RET_VAL_IF(!vstd::contains(gs->map->questIdentifierToId, identifier.getNum()), "There is no object with such quest identifier!", nullptr);
|
|
||||||
return getObj(gs->map->questIdentifierToId[identifier.getNum()]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
@ -93,7 +93,6 @@ public:
|
|||||||
// std::vector <const CGObjectInstance * > getFlaggableObjects(int3 pos) const;
|
// std::vector <const CGObjectInstance * > getFlaggableObjects(int3 pos) const;
|
||||||
// const CGObjectInstance * getTopObj (int3 pos) const;
|
// const CGObjectInstance * getTopObj (int3 pos) const;
|
||||||
// PlayerColor getOwner(ObjectInstanceID heroID) const;
|
// PlayerColor getOwner(ObjectInstanceID heroID) const;
|
||||||
// const CGObjectInstance *getObjByQuestIdentifier(ObjectInstanceID identifier) const; //nullptr if object has been removed (eg. killed)
|
|
||||||
|
|
||||||
//map
|
//map
|
||||||
// int3 guardingCreaturePosition (int3 pos) const;
|
// int3 guardingCreaturePosition (int3 pos) const;
|
||||||
@ -190,7 +189,6 @@ public:
|
|||||||
virtual std::vector <const CGObjectInstance * > getFlaggableObjects(int3 pos) const;
|
virtual std::vector <const CGObjectInstance * > getFlaggableObjects(int3 pos) const;
|
||||||
virtual const CGObjectInstance * getTopObj (int3 pos) const;
|
virtual const CGObjectInstance * getTopObj (int3 pos) const;
|
||||||
virtual PlayerColor getOwner(ObjectInstanceID heroID) const;
|
virtual PlayerColor getOwner(ObjectInstanceID heroID) const;
|
||||||
virtual const CGObjectInstance *getObjByQuestIdentifier(ObjectInstanceID identifier) const; //nullptr if object has been removed (eg. killed)
|
|
||||||
|
|
||||||
//map
|
//map
|
||||||
virtual int3 guardingCreaturePosition (int3 pos) const;
|
virtual int3 guardingCreaturePosition (int3 pos) const;
|
||||||
|
@ -52,6 +52,10 @@ public:
|
|||||||
bool human; //true if human controlled player, false for AI
|
bool human; //true if human controlled player, false for AI
|
||||||
TeamID team;
|
TeamID team;
|
||||||
TResources resources;
|
TResources resources;
|
||||||
|
|
||||||
|
/// list of objects that were "destroyed" by player, either via simple pick-up (e.g. resources) or defeated heroes or wandering monsters
|
||||||
|
std::set<ObjectInstanceID> destroyedObjects;
|
||||||
|
|
||||||
std::set<ObjectInstanceID> visitedObjects; // as a std::set, since most accesses here will be from visited status checks
|
std::set<ObjectInstanceID> visitedObjects; // as a std::set, since most accesses here will be from visited status checks
|
||||||
std::set<VisitedObjectGlobal> visitedObjectsGlobal;
|
std::set<VisitedObjectGlobal> visitedObjectsGlobal;
|
||||||
std::vector<ConstTransitivePtr<CGHeroInstance> > heroes;
|
std::vector<ConstTransitivePtr<CGHeroInstance> > heroes;
|
||||||
@ -110,6 +114,8 @@ public:
|
|||||||
h & enteredLosingCheatCode;
|
h & enteredLosingCheatCode;
|
||||||
h & enteredWinningCheatCode;
|
h & enteredWinningCheatCode;
|
||||||
h & static_cast<CBonusSystemNode&>(*this);
|
h & static_cast<CBonusSystemNode&>(*this);
|
||||||
|
if (h.version >= Handler::Version::DESTROYED_OBJECTS)
|
||||||
|
h & destroyedObjects;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1420,10 +1420,7 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio
|
|||||||
{
|
{
|
||||||
if (condition.objectID != ObjectInstanceID::NONE) // mode A - destroy specific object of this type
|
if (condition.objectID != ObjectInstanceID::NONE) // mode A - destroy specific object of this type
|
||||||
{
|
{
|
||||||
if(const auto * hero = getHero(condition.objectID))
|
return p->destroyedObjects.count(condition.objectID);
|
||||||
return boost::range::find(gs->map->heroesOnMap, hero) == gs->map->heroesOnMap.end();
|
|
||||||
else
|
|
||||||
return getObj(condition.objectID) == nullptr;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -129,12 +129,12 @@ bool CQuest::checkQuest(const CGHeroInstance * h) const
|
|||||||
if(!mission.heroAllowed(h))
|
if(!mission.heroAllowed(h))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(killTarget != ObjectInstanceID::NONE)
|
if(killTarget.hasValue())
|
||||||
{
|
{
|
||||||
if(h->cb->getObjByQuestIdentifier(killTarget))
|
PlayerColor owner = h->getOwner();
|
||||||
|
if (!h->cb->getPlayerState(owner)->destroyedObjects.count(killTarget))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -612,7 +612,7 @@ void CGSeerHut::onHeroVisit(const CGHeroInstance * h) const
|
|||||||
|
|
||||||
int CGSeerHut::checkDirection() const
|
int CGSeerHut::checkDirection() const
|
||||||
{
|
{
|
||||||
int3 cord = getCreatureToKill()->pos;
|
int3 cord = getCreatureToKill(false)->pos;
|
||||||
if(static_cast<double>(cord.x) / static_cast<double>(cb->getMapSize().x) < 0.34) //north
|
if(static_cast<double>(cord.x) / static_cast<double>(cb->getMapSize().x) < 0.34) //north
|
||||||
{
|
{
|
||||||
if(static_cast<double>(cord.y) / static_cast<double>(cb->getMapSize().y) < 0.34) //northwest
|
if(static_cast<double>(cord.y) / static_cast<double>(cb->getMapSize().y) < 0.34) //northwest
|
||||||
@ -644,7 +644,7 @@ int CGSeerHut::checkDirection() const
|
|||||||
|
|
||||||
const CGHeroInstance * CGSeerHut::getHeroToKill(bool allowNull) const
|
const CGHeroInstance * CGSeerHut::getHeroToKill(bool allowNull) const
|
||||||
{
|
{
|
||||||
const CGObjectInstance *o = cb->getObjByQuestIdentifier(quest->killTarget);
|
const CGObjectInstance *o = cb->getObj(quest->killTarget);
|
||||||
if(allowNull && !o)
|
if(allowNull && !o)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return dynamic_cast<const CGHeroInstance *>(o);
|
return dynamic_cast<const CGHeroInstance *>(o);
|
||||||
@ -652,7 +652,7 @@ const CGHeroInstance * CGSeerHut::getHeroToKill(bool allowNull) const
|
|||||||
|
|
||||||
const CGCreature * CGSeerHut::getCreatureToKill(bool allowNull) const
|
const CGCreature * CGSeerHut::getCreatureToKill(bool allowNull) const
|
||||||
{
|
{
|
||||||
const CGObjectInstance *o = cb->getObjByQuestIdentifier(quest->killTarget);
|
const CGObjectInstance *o = cb->getObj(quest->killTarget);
|
||||||
if(allowNull && !o)
|
if(allowNull && !o)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return dynamic_cast<const CGCreature *>(o);
|
return dynamic_cast<const CGCreature *>(o);
|
||||||
|
@ -136,8 +136,8 @@ public:
|
|||||||
virtual void init(CRandomGenerator & rand);
|
virtual void init(CRandomGenerator & rand);
|
||||||
int checkDirection() const; //calculates the region of map where monster is placed
|
int checkDirection() const; //calculates the region of map where monster is placed
|
||||||
void setObjToKill(); //remember creatures / heroes to kill after they are initialized
|
void setObjToKill(); //remember creatures / heroes to kill after they are initialized
|
||||||
const CGHeroInstance *getHeroToKill(bool allowNull = false) const;
|
const CGHeroInstance *getHeroToKill(bool allowNull) const;
|
||||||
const CGCreature *getCreatureToKill(bool allowNull = false) const;
|
const CGCreature *getCreatureToKill(bool allowNull) const;
|
||||||
void getRolloverText (MetaString &text, bool onHover) const;
|
void getRolloverText (MetaString &text, bool onHover) const;
|
||||||
|
|
||||||
void afterAddToMap(CMap * map) override;
|
void afterAddToMap(CMap * map) override;
|
||||||
|
@ -684,4 +684,15 @@ void CMap::resetStaticData()
|
|||||||
townUniversitySkills.clear();
|
townUniversitySkills.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CMap::resolveQuestIdentifiers()
|
||||||
|
{
|
||||||
|
//FIXME: move to CMapLoaderH3M
|
||||||
|
for (auto & quest : quests)
|
||||||
|
{
|
||||||
|
if (quest->killTarget != ObjectInstanceID::NONE)
|
||||||
|
quest->killTarget = questIdentifierToId[quest->killTarget.getNum()];
|
||||||
|
}
|
||||||
|
questIdentifierToId.clear();
|
||||||
|
}
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
@ -126,6 +126,7 @@ public:
|
|||||||
void checkForObjectives();
|
void checkForObjectives();
|
||||||
|
|
||||||
void resetStaticData();
|
void resetStaticData();
|
||||||
|
void resolveQuestIdentifiers();
|
||||||
|
|
||||||
ui32 checksum;
|
ui32 checksum;
|
||||||
std::vector<Rumor> rumors;
|
std::vector<Rumor> rumors;
|
||||||
@ -186,7 +187,14 @@ public:
|
|||||||
h & artInstances;
|
h & artInstances;
|
||||||
h & quests;
|
h & quests;
|
||||||
h & allHeroes;
|
h & allHeroes;
|
||||||
h & questIdentifierToId;
|
|
||||||
|
if (h.version < Handler::Version::DESTROYED_OBJECTS)
|
||||||
|
{
|
||||||
|
// old save compatibility
|
||||||
|
//FIXME: remove this field after save-breaking change
|
||||||
|
h & questIdentifierToId;
|
||||||
|
resolveQuestIdentifiers();
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: viccondetails
|
//TODO: viccondetails
|
||||||
h & terrain;
|
h & terrain;
|
||||||
|
@ -2392,6 +2392,8 @@ void CMapLoaderH3M::afterRead()
|
|||||||
p.posOfMainTown = posOfMainTown + mainTown->getVisitableOffset();
|
p.posOfMainTown = posOfMainTown + mainTown->getVisitableOffset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map->resolveQuestIdentifiers();
|
||||||
}
|
}
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
@ -1156,6 +1156,9 @@ void RemoveObject::applyGs(CGameState *gs)
|
|||||||
//unblock tiles
|
//unblock tiles
|
||||||
gs->map->removeBlockVisTiles(obj);
|
gs->map->removeBlockVisTiles(obj);
|
||||||
|
|
||||||
|
if (initiator.isValidPlayer())
|
||||||
|
gs->getPlayerState(initiator)->destroyedObjects.insert(objectID);
|
||||||
|
|
||||||
if(obj->ID == Obj::HERO) //remove beaten hero
|
if(obj->ID == Obj::HERO) //remove beaten hero
|
||||||
{
|
{
|
||||||
auto * beatenHero = dynamic_cast<CGHeroInstance *>(obj);
|
auto * beatenHero = dynamic_cast<CGHeroInstance *>(obj);
|
||||||
@ -1221,27 +1224,6 @@ void RemoveObject::applyGs(CGameState *gs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (TriggeredEvent & event : gs->map->triggeredEvents)
|
|
||||||
{
|
|
||||||
auto patcher = [&](EventCondition cond) -> EventExpression::Variant
|
|
||||||
{
|
|
||||||
if (cond.objectID == obj->id)
|
|
||||||
{
|
|
||||||
if (cond.condition == EventCondition::DESTROY)
|
|
||||||
{
|
|
||||||
cond.condition = EventCondition::CONST_VALUE;
|
|
||||||
cond.value = 1; // destroyed object, from now on always fulfilled
|
|
||||||
}
|
|
||||||
else if (cond.condition == EventCondition::CONTROL)
|
|
||||||
{
|
|
||||||
cond.condition = EventCondition::CONST_VALUE;
|
|
||||||
cond.value = 0; // destroyed object, from now on can not be fulfilled
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cond;
|
|
||||||
};
|
|
||||||
event.trigger = event.trigger.morph(patcher);
|
|
||||||
}
|
|
||||||
gs->map->instanceNames.erase(obj->instanceName);
|
gs->map->instanceNames.erase(obj->instanceName);
|
||||||
gs->map->objects[objectID.getNum()].dellNull();
|
gs->map->objects[objectID.getNum()].dellNull();
|
||||||
gs->map->calculateGuardingGreaturePositions();
|
gs->map->calculateGuardingGreaturePositions();
|
||||||
|
@ -34,6 +34,7 @@ enum class ESerializationVersion : int32_t
|
|||||||
MINIMAL = 831,
|
MINIMAL = 831,
|
||||||
RELEASE_143, // 832 +text container in campaigns, +starting hero in RMG options
|
RELEASE_143, // 832 +text container in campaigns, +starting hero in RMG options
|
||||||
HAS_EXTRA_OPTIONS, // 833 +extra options struct as part of startinfo
|
HAS_EXTRA_OPTIONS, // 833 +extra options struct as part of startinfo
|
||||||
|
DESTROYED_OBJECTS, // 834 +list of objects destroyed by player
|
||||||
|
|
||||||
CURRENT = HAS_EXTRA_OPTIONS
|
CURRENT = DESTROYED_OBJECTS
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user