mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-27 21:49:10 +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
|
||||
{
|
||||
auto obj = cb->getObjByQuestIdentifier(q.quest->killTarget);
|
||||
auto obj = cb->getObj(q.quest->killTarget);
|
||||
|
||||
if(!obj)
|
||||
return CaptureObjectsBehavior(q.obj).decompose();
|
||||
|
@ -241,7 +241,7 @@ TGoalVec CompleteQuest::missionDestroyObj() const
|
||||
{
|
||||
TGoalVec solutions;
|
||||
|
||||
auto obj = cb->getObjByQuestIdentifier(q.quest->killTarget);
|
||||
auto obj = cb->getObj(q.quest->killTarget);
|
||||
|
||||
if(!obj)
|
||||
return ai->ah->howToVisitObj(q.obj);
|
||||
|
@ -124,20 +124,6 @@ TurnTimerInfo CGameInfoCallback::getPlayerTurnTime(PlayerColor color) const
|
||||
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;
|
||||
// const CGObjectInstance * getTopObj (int3 pos) const;
|
||||
// PlayerColor getOwner(ObjectInstanceID heroID) const;
|
||||
// const CGObjectInstance *getObjByQuestIdentifier(ObjectInstanceID identifier) const; //nullptr if object has been removed (eg. killed)
|
||||
|
||||
//map
|
||||
// int3 guardingCreaturePosition (int3 pos) const;
|
||||
@ -190,7 +189,6 @@ public:
|
||||
virtual std::vector <const CGObjectInstance * > getFlaggableObjects(int3 pos) const;
|
||||
virtual const CGObjectInstance * getTopObj (int3 pos) const;
|
||||
virtual PlayerColor getOwner(ObjectInstanceID heroID) const;
|
||||
virtual const CGObjectInstance *getObjByQuestIdentifier(ObjectInstanceID identifier) const; //nullptr if object has been removed (eg. killed)
|
||||
|
||||
//map
|
||||
virtual int3 guardingCreaturePosition (int3 pos) const;
|
||||
|
@ -52,6 +52,10 @@ public:
|
||||
bool human; //true if human controlled player, false for AI
|
||||
TeamID team;
|
||||
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<VisitedObjectGlobal> visitedObjectsGlobal;
|
||||
std::vector<ConstTransitivePtr<CGHeroInstance> > heroes;
|
||||
@ -110,6 +114,8 @@ public:
|
||||
h & enteredLosingCheatCode;
|
||||
h & enteredWinningCheatCode;
|
||||
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(const auto * hero = getHero(condition.objectID))
|
||||
return boost::range::find(gs->map->heroesOnMap, hero) == gs->map->heroesOnMap.end();
|
||||
else
|
||||
return getObj(condition.objectID) == nullptr;
|
||||
return p->destroyedObjects.count(condition.objectID);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -129,12 +129,12 @@ bool CQuest::checkQuest(const CGHeroInstance * h) const
|
||||
if(!mission.heroAllowed(h))
|
||||
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 true;
|
||||
}
|
||||
|
||||
@ -612,7 +612,7 @@ void CGSeerHut::onHeroVisit(const CGHeroInstance * h) 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.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 CGObjectInstance *o = cb->getObjByQuestIdentifier(quest->killTarget);
|
||||
const CGObjectInstance *o = cb->getObj(quest->killTarget);
|
||||
if(allowNull && !o)
|
||||
return nullptr;
|
||||
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 CGObjectInstance *o = cb->getObjByQuestIdentifier(quest->killTarget);
|
||||
const CGObjectInstance *o = cb->getObj(quest->killTarget);
|
||||
if(allowNull && !o)
|
||||
return nullptr;
|
||||
return dynamic_cast<const CGCreature *>(o);
|
||||
|
@ -136,8 +136,8 @@ public:
|
||||
virtual void init(CRandomGenerator & rand);
|
||||
int checkDirection() const; //calculates the region of map where monster is placed
|
||||
void setObjToKill(); //remember creatures / heroes to kill after they are initialized
|
||||
const CGHeroInstance *getHeroToKill(bool allowNull = false) const;
|
||||
const CGCreature *getCreatureToKill(bool allowNull = false) const;
|
||||
const CGHeroInstance *getHeroToKill(bool allowNull) const;
|
||||
const CGCreature *getCreatureToKill(bool allowNull) const;
|
||||
void getRolloverText (MetaString &text, bool onHover) const;
|
||||
|
||||
void afterAddToMap(CMap * map) override;
|
||||
|
@ -684,4 +684,15 @@ void CMap::resetStaticData()
|
||||
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
|
||||
|
@ -126,6 +126,7 @@ public:
|
||||
void checkForObjectives();
|
||||
|
||||
void resetStaticData();
|
||||
void resolveQuestIdentifiers();
|
||||
|
||||
ui32 checksum;
|
||||
std::vector<Rumor> rumors;
|
||||
@ -186,7 +187,14 @@ public:
|
||||
h & artInstances;
|
||||
h & quests;
|
||||
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
|
||||
h & terrain;
|
||||
|
@ -2392,6 +2392,8 @@ void CMapLoaderH3M::afterRead()
|
||||
p.posOfMainTown = posOfMainTown + mainTown->getVisitableOffset();
|
||||
}
|
||||
}
|
||||
|
||||
map->resolveQuestIdentifiers();
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -1156,6 +1156,9 @@ void RemoveObject::applyGs(CGameState *gs)
|
||||
//unblock tiles
|
||||
gs->map->removeBlockVisTiles(obj);
|
||||
|
||||
if (initiator.isValidPlayer())
|
||||
gs->getPlayerState(initiator)->destroyedObjects.insert(objectID);
|
||||
|
||||
if(obj->ID == Obj::HERO) //remove beaten hero
|
||||
{
|
||||
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->objects[objectID.getNum()].dellNull();
|
||||
gs->map->calculateGuardingGreaturePositions();
|
||||
|
@ -34,6 +34,7 @@ enum class ESerializationVersion : int32_t
|
||||
MINIMAL = 831,
|
||||
RELEASE_143, // 832 +text container in campaigns, +starting hero in RMG options
|
||||
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