mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Moved stateful artifact randomization logic to gamestate from handler
This commit is contained in:
parent
34c012d119
commit
0691dfef3b
@ -607,75 +607,6 @@ void CArtHandler::loadComponents(CArtifact * art, const JsonNode & node)
|
||||
}
|
||||
}
|
||||
|
||||
ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, int flags, std::function<bool(ArtifactID)> accepts)
|
||||
{
|
||||
std::set<ArtifactID> potentialPicks;
|
||||
|
||||
// Select artifacts that satisfy provided criterias
|
||||
for (auto const * artifact : allowedArtifacts)
|
||||
{
|
||||
assert(artifact->aClass != CArtifact::ART_SPECIAL); // should be filtered out when allowedArtifacts is initialized
|
||||
|
||||
if ((flags & CArtifact::ART_TREASURE) == 0 && artifact->aClass == CArtifact::ART_TREASURE)
|
||||
continue;
|
||||
|
||||
if ((flags & CArtifact::ART_MINOR) == 0 && artifact->aClass == CArtifact::ART_MINOR)
|
||||
continue;
|
||||
|
||||
if ((flags & CArtifact::ART_MAJOR) == 0 && artifact->aClass == CArtifact::ART_MAJOR)
|
||||
continue;
|
||||
|
||||
if ((flags & CArtifact::ART_RELIC) == 0 && artifact->aClass == CArtifact::ART_RELIC)
|
||||
continue;
|
||||
|
||||
if (!accepts(artifact->id))
|
||||
continue;
|
||||
|
||||
potentialPicks.insert(artifact->id);
|
||||
}
|
||||
|
||||
return pickRandomArtifact(rand, potentialPicks);
|
||||
}
|
||||
|
||||
ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, std::set<ArtifactID> potentialPicks)
|
||||
{
|
||||
// No allowed artifacts at all - give Grail - this can't be banned (hopefully)
|
||||
// FIXME: investigate how such cases are handled by H3 - some heavily customized user-made maps likely rely on H3 behavior
|
||||
if (potentialPicks.empty())
|
||||
{
|
||||
logGlobal->warn("Failed to find artifact that matches requested parameters!");
|
||||
return ArtifactID::GRAIL;
|
||||
}
|
||||
|
||||
// Find how many times least used artifacts were picked by randomizer
|
||||
int leastUsedTimes = std::numeric_limits<int>::max();
|
||||
for (auto const & artifact : potentialPicks)
|
||||
if (allocatedArtifacts[artifact] < leastUsedTimes)
|
||||
leastUsedTimes = allocatedArtifacts[artifact];
|
||||
|
||||
// Pick all artifacts that were used least number of times
|
||||
std::set<ArtifactID> preferredPicks;
|
||||
for (auto const & artifact : potentialPicks)
|
||||
if (allocatedArtifacts[artifact] == leastUsedTimes)
|
||||
preferredPicks.insert(artifact);
|
||||
|
||||
assert(!preferredPicks.empty());
|
||||
|
||||
ArtifactID artID = *RandomGeneratorUtil::nextItem(preferredPicks, rand);
|
||||
allocatedArtifacts[artID] += 1; // record +1 more usage
|
||||
return artID;
|
||||
}
|
||||
|
||||
ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, std::function<bool(ArtifactID)> accepts)
|
||||
{
|
||||
return pickRandomArtifact(rand, 0xff, std::move(accepts));
|
||||
}
|
||||
|
||||
ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, int flags)
|
||||
{
|
||||
return pickRandomArtifact(rand, flags, [](const ArtifactID &) { return true; });
|
||||
}
|
||||
|
||||
void CArtHandler::makeItCreatureArt(CArtifact * a, bool onlyCreature)
|
||||
{
|
||||
if (onlyCreature)
|
||||
@ -723,7 +654,6 @@ bool CArtHandler::legalArtifact(const ArtifactID & id)
|
||||
void CArtHandler::initAllowedArtifactsList(const std::vector<bool> &allowed)
|
||||
{
|
||||
allowedArtifacts.clear();
|
||||
allocatedArtifacts.clear();
|
||||
|
||||
for (ArtifactID i=ArtifactID::SPELLBOOK; i < ArtifactID(static_cast<si32>(objects.size())); i.advance(1))
|
||||
{
|
||||
|
@ -141,9 +141,6 @@ public:
|
||||
class DLL_LINKAGE CArtHandler : public CHandlerBase<ArtifactID, Artifact, CArtifact, ArtifactService>
|
||||
{
|
||||
public:
|
||||
/// Stores number of times each artifact was placed on map via randomization
|
||||
std::map<ArtifactID, int> allocatedArtifacts;
|
||||
|
||||
/// List of artifacts allowed on the map
|
||||
std::vector<CArtifact *> allowedArtifacts;
|
||||
|
||||
@ -151,12 +148,6 @@ public:
|
||||
|
||||
static CArtifact::EartClass stringToClass(const std::string & className); //TODO: rework EartClass to make this a constructor
|
||||
|
||||
/// Gets a artifact ID randomly and removes the selected artifact from this handler.
|
||||
ArtifactID pickRandomArtifact(CRandomGenerator & rand, int flags);
|
||||
ArtifactID pickRandomArtifact(CRandomGenerator & rand, std::function<bool(ArtifactID)> accepts);
|
||||
ArtifactID pickRandomArtifact(CRandomGenerator & rand, int flags, std::function<bool(ArtifactID)> accepts);
|
||||
ArtifactID pickRandomArtifact(CRandomGenerator & rand, std::set<ArtifactID> filtered);
|
||||
|
||||
bool legalArtifact(const ArtifactID & id);
|
||||
void initAllowedArtifactsList(const std::vector<bool> &allowed); //allowed[art_id] -> 0 if not allowed, 1 if allowed
|
||||
static void makeItCreatureArt(CArtifact * a, bool onlyCreature = true);
|
||||
|
@ -144,14 +144,14 @@ void CPrivilegedInfoCallback::getAllTiles(std::unordered_set<int3> & tiles, std:
|
||||
}
|
||||
}
|
||||
|
||||
void CPrivilegedInfoCallback::pickAllowedArtsSet(std::vector<const CArtifact *> & out, CRandomGenerator & rand) const
|
||||
void CPrivilegedInfoCallback::pickAllowedArtsSet(std::vector<const CArtifact *> & out, CRandomGenerator & rand)
|
||||
{
|
||||
for (int j = 0; j < 3 ; j++)
|
||||
out.push_back(VLC->arth->pickRandomArtifact(rand, CArtifact::ART_TREASURE).toArtifact());
|
||||
out.push_back(gameState()->pickRandomArtifact(rand, CArtifact::ART_TREASURE).toArtifact());
|
||||
for (int j = 0; j < 3 ; j++)
|
||||
out.push_back(VLC->arth->pickRandomArtifact(rand, CArtifact::ART_MINOR).toArtifact());
|
||||
out.push_back(gameState()->pickRandomArtifact(rand, CArtifact::ART_MINOR).toArtifact());
|
||||
|
||||
out.push_back(VLC->arth->pickRandomArtifact(rand, CArtifact::ART_MAJOR).toArtifact());
|
||||
out.push_back(gameState()->pickRandomArtifact(rand, CArtifact::ART_MAJOR).toArtifact());
|
||||
}
|
||||
|
||||
void CPrivilegedInfoCallback::getAllowedSpells(std::vector<SpellID> & out, std::optional<ui16> level)
|
||||
|
@ -61,7 +61,7 @@ public:
|
||||
void getAllTiles(std::unordered_set<int3> &tiles, std::optional<PlayerColor> player, int level, std::function<bool(const TerrainTile *)> filter) const;
|
||||
|
||||
//gives 3 treasures, 3 minors, 1 major -> used by Black Market and Artifact Merchant
|
||||
void pickAllowedArtsSet(std::vector<const CArtifact *> & out, CRandomGenerator & rand) const;
|
||||
void pickAllowedArtsSet(std::vector<const CArtifact *> & out, CRandomGenerator & rand);
|
||||
void getAllowedSpells(std::vector<SpellID> &out, std::optional<ui16> level = std::nullopt);
|
||||
|
||||
template<typename Saver>
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "CSkillHandler.h"
|
||||
#include "CHeroHandler.h"
|
||||
#include "IGameCallback.h"
|
||||
#include "gameState/CGameState.h"
|
||||
#include "mapObjects/IObjectInterface.h"
|
||||
#include "modding/IdentifierStorage.h"
|
||||
#include "modding/ModScope.h"
|
||||
@ -388,7 +389,7 @@ namespace JsonRandom
|
||||
|
||||
std::set<ArtifactID> potentialPicks = filterKeys(value, allowedArts, variables);
|
||||
|
||||
return VLC->arth->pickRandomArtifact(rng, potentialPicks);
|
||||
return IObjectInterface::cb->gameState()->pickRandomArtifact(rng, potentialPicks);
|
||||
}
|
||||
|
||||
std::vector<ArtifactID> loadArtifacts(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
|
||||
|
@ -760,7 +760,7 @@ void CGameState::initStartingBonus()
|
||||
logGlobal->error("Cannot give starting artifact - no heroes!");
|
||||
break;
|
||||
}
|
||||
const Artifact * toGive = VLC->arth->pickRandomArtifact(getRandomGenerator(), CArtifact::ART_TREASURE).toEntity(VLC);
|
||||
const Artifact * toGive = pickRandomArtifact(getRandomGenerator(), CArtifact::ART_TREASURE).toEntity(VLC);
|
||||
|
||||
CGHeroInstance *hero = elem.second.heroes[0];
|
||||
if(!giveHeroArtifact(hero, toGive->getId()))
|
||||
@ -1971,4 +1971,73 @@ CRandomGenerator & CGameState::getRandomGenerator()
|
||||
return rand;
|
||||
}
|
||||
|
||||
ArtifactID CGameState::pickRandomArtifact(CRandomGenerator & rand, int flags, std::function<bool(ArtifactID)> accepts)
|
||||
{
|
||||
std::set<ArtifactID> potentialPicks;
|
||||
|
||||
// Select artifacts that satisfy provided criterias
|
||||
for (auto const * artifact : VLC->arth->allowedArtifacts)
|
||||
{
|
||||
assert(artifact->aClass != CArtifact::ART_SPECIAL); // should be filtered out when allowedArtifacts is initialized
|
||||
|
||||
if ((flags & CArtifact::ART_TREASURE) == 0 && artifact->aClass == CArtifact::ART_TREASURE)
|
||||
continue;
|
||||
|
||||
if ((flags & CArtifact::ART_MINOR) == 0 && artifact->aClass == CArtifact::ART_MINOR)
|
||||
continue;
|
||||
|
||||
if ((flags & CArtifact::ART_MAJOR) == 0 && artifact->aClass == CArtifact::ART_MAJOR)
|
||||
continue;
|
||||
|
||||
if ((flags & CArtifact::ART_RELIC) == 0 && artifact->aClass == CArtifact::ART_RELIC)
|
||||
continue;
|
||||
|
||||
if (!accepts(artifact->getId()))
|
||||
continue;
|
||||
|
||||
potentialPicks.insert(artifact->getId());
|
||||
}
|
||||
|
||||
return pickRandomArtifact(rand, potentialPicks);
|
||||
}
|
||||
|
||||
ArtifactID CGameState::pickRandomArtifact(CRandomGenerator & rand, std::set<ArtifactID> potentialPicks)
|
||||
{
|
||||
// No allowed artifacts at all - give Grail - this can't be banned (hopefully)
|
||||
// FIXME: investigate how such cases are handled by H3 - some heavily customized user-made maps likely rely on H3 behavior
|
||||
if (potentialPicks.empty())
|
||||
{
|
||||
logGlobal->warn("Failed to find artifact that matches requested parameters!");
|
||||
return ArtifactID::GRAIL;
|
||||
}
|
||||
|
||||
// Find how many times least used artifacts were picked by randomizer
|
||||
int leastUsedTimes = std::numeric_limits<int>::max();
|
||||
for (auto const & artifact : potentialPicks)
|
||||
if (allocatedArtifacts[artifact] < leastUsedTimes)
|
||||
leastUsedTimes = allocatedArtifacts[artifact];
|
||||
|
||||
// Pick all artifacts that were used least number of times
|
||||
std::set<ArtifactID> preferredPicks;
|
||||
for (auto const & artifact : potentialPicks)
|
||||
if (allocatedArtifacts[artifact] == leastUsedTimes)
|
||||
preferredPicks.insert(artifact);
|
||||
|
||||
assert(!preferredPicks.empty());
|
||||
|
||||
ArtifactID artID = *RandomGeneratorUtil::nextItem(preferredPicks, rand);
|
||||
allocatedArtifacts[artID] += 1; // record +1 more usage
|
||||
return artID;
|
||||
}
|
||||
|
||||
ArtifactID CGameState::pickRandomArtifact(CRandomGenerator & rand, std::function<bool(ArtifactID)> accepts)
|
||||
{
|
||||
return pickRandomArtifact(rand, 0xff, std::move(accepts));
|
||||
}
|
||||
|
||||
ArtifactID CGameState::pickRandomArtifact(CRandomGenerator & rand, int flags)
|
||||
{
|
||||
return pickRandomArtifact(rand, flags, [](const ArtifactID &) { return true; });
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -83,6 +83,9 @@ class DLL_LINKAGE CGameState : public CNonConstInfoCallback
|
||||
friend class CGameStateCampaign;
|
||||
|
||||
public:
|
||||
/// Stores number of times each artifact was placed on map via randomization
|
||||
std::map<ArtifactID, int> allocatedArtifacts;
|
||||
|
||||
/// List of currently ongoing battles
|
||||
std::vector<std::unique_ptr<BattleInfo>> currentBattles;
|
||||
/// ID that can be allocated to next battle
|
||||
@ -130,6 +133,12 @@ public:
|
||||
std::vector<CGObjectInstance*> guardingCreatures (int3 pos) const;
|
||||
void updateRumor();
|
||||
|
||||
/// Gets a artifact ID randomly and removes the selected artifact from this handler.
|
||||
ArtifactID pickRandomArtifact(CRandomGenerator & rand, int flags);
|
||||
ArtifactID pickRandomArtifact(CRandomGenerator & rand, std::function<bool(ArtifactID)> accepts);
|
||||
ArtifactID pickRandomArtifact(CRandomGenerator & rand, int flags, std::function<bool(ArtifactID)> accepts);
|
||||
ArtifactID pickRandomArtifact(CRandomGenerator & rand, std::set<ArtifactID> filtered);
|
||||
|
||||
/// Returns battle in which selected player is engaged, or nullptr if none.
|
||||
/// Can NOT be used with neutral player, use battle by ID instead
|
||||
const BattleInfo * getBattle(const PlayerColor & player) const;
|
||||
@ -176,6 +185,7 @@ public:
|
||||
h & rand;
|
||||
h & rumor;
|
||||
h & campaign;
|
||||
h & allocatedArtifacts;
|
||||
|
||||
BONUS_TREE_DESERIALIZATION_FIX
|
||||
}
|
||||
|
@ -724,19 +724,19 @@ void CGArtifact::pickRandomObject(CRandomGenerator & rand)
|
||||
switch(ID.toEnum())
|
||||
{
|
||||
case MapObjectID::RANDOM_ART:
|
||||
subID = VLC->arth->pickRandomArtifact(rand, CArtifact::ART_TREASURE | CArtifact::ART_MINOR | CArtifact::ART_MAJOR | CArtifact::ART_RELIC);
|
||||
subID = cb->gameState()->pickRandomArtifact(rand, CArtifact::ART_TREASURE | CArtifact::ART_MINOR | CArtifact::ART_MAJOR | CArtifact::ART_RELIC);
|
||||
break;
|
||||
case MapObjectID::RANDOM_TREASURE_ART:
|
||||
subID = VLC->arth->pickRandomArtifact(rand, CArtifact::ART_TREASURE);
|
||||
subID = cb->gameState()->pickRandomArtifact(rand, CArtifact::ART_TREASURE);
|
||||
break;
|
||||
case MapObjectID::RANDOM_MINOR_ART:
|
||||
subID = VLC->arth->pickRandomArtifact(rand, CArtifact::ART_MINOR);
|
||||
subID = cb->gameState()->pickRandomArtifact(rand, CArtifact::ART_MINOR);
|
||||
break;
|
||||
case MapObjectID::RANDOM_MAJOR_ART:
|
||||
subID = VLC->arth->pickRandomArtifact(rand, CArtifact::ART_MAJOR);
|
||||
subID = cb->gameState()->pickRandomArtifact(rand, CArtifact::ART_MAJOR);
|
||||
break;
|
||||
case MapObjectID::RANDOM_RELIC_ART:
|
||||
subID = VLC->arth->pickRandomArtifact(rand, CArtifact::ART_RELIC);
|
||||
subID = cb->gameState()->pickRandomArtifact(rand, CArtifact::ART_RELIC);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -858,7 +858,7 @@ void AddQuest::applyGs(CGameState * gs) const
|
||||
|
||||
void UpdateArtHandlerLists::applyGs(CGameState * gs) const
|
||||
{
|
||||
VLC->arth->allocatedArtifacts = allocatedArtifacts;
|
||||
gs->allocatedArtifacts = allocatedArtifacts;
|
||||
}
|
||||
|
||||
void UpdateMapEvents::applyGs(CGameState * gs) const
|
||||
|
@ -4057,7 +4057,7 @@ void CGameHandler::spawnWanderingMonsters(CreatureID creatureID)
|
||||
void CGameHandler::synchronizeArtifactHandlerLists()
|
||||
{
|
||||
UpdateArtHandlerLists uahl;
|
||||
uahl.allocatedArtifacts = VLC->arth->allocatedArtifacts;
|
||||
uahl.allocatedArtifacts = gs->allocatedArtifacts;
|
||||
sendAndApply(&uahl);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user