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

Merge remote-tracking branch 'vcmi/develop' into lobby

This commit is contained in:
Ivan Savenko 2024-01-20 23:01:49 +02:00
commit fc4ae3bd8c
192 changed files with 1119 additions and 1100 deletions

View File

@ -350,10 +350,11 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
LOGL("Casting spells sounds like fun. Let's see...");
//Get all spells we can cast
std::vector<const CSpell*> possibleSpells;
vstd::copy_if(VLC->spellh->objects, std::back_inserter(possibleSpells), [hero, this](const CSpell *s) -> bool
{
return s->canBeCast(cb->getBattle(battleID).get(), spells::Mode::HERO, hero);
});
for (auto const & s : VLC->spellh->objects)
if (s->canBeCast(cb->getBattle(battleID).get(), spells::Mode::HERO, hero))
possibleSpells.push_back(s.get());
LOGFL("I can cast %d spells.", possibleSpells.size());
vstd::erase_if(possibleSpells, [](const CSpell *s)

View File

@ -276,12 +276,10 @@ creInfo infoFromDC(const dwellingContent & dc)
ci.creID = dc.second.size() ? dc.second.back() : CreatureID(-1); //should never be accessed
if (ci.creID != CreatureID::NONE)
{
ci.cre = VLC->creatures()->getById(ci.creID);
ci.level = ci.cre->getLevel(); //this is creature tier, while tryRealize expects dwelling level. Ignore.
ci.level = ci.creID.toCreature()->getLevel(); //this is creature tier, while tryRealize expects dwelling level. Ignore.
}
else
{
ci.cre = nullptr;
ci.level = 0;
}
return ci;

View File

@ -163,7 +163,6 @@ struct creInfo
{
int count;
CreatureID creID;
const Creature * cre;
int level;
};
creInfo infoFromDC(const dwellingContent & dc);

View File

@ -63,9 +63,9 @@ std::vector<SlotInfo> ArmyManager::toSlotInfo(std::vector<creInfo> army) const
{
SlotInfo slot;
slot.creature = VLC->creh->objects[i.cre->getId()];
slot.creature = i.creID.toCreature();
slot.count = i.count;
slot.power = evaluateStackPower(i.cre, i.count);
slot.power = evaluateStackPower(i.creID.toCreature(), i.count);
result.push_back(slot);
}
@ -128,7 +128,7 @@ class TemporaryArmy : public CArmedInstance
public:
void armyChanged() override {}
TemporaryArmy()
:CArmedInstance(true)
:CArmedInstance(nullptr, true)
{
}
};
@ -259,7 +259,7 @@ std::shared_ptr<CCreatureSet> ArmyManager::getArmyAvailableToBuyAsCCreatureSet(
if(!ci.count || ci.creID == CreatureID::NONE)
continue;
vstd::amin(ci.count, availableRes / ci.cre->getFullRecruitCost()); //max count we can afford
vstd::amin(ci.count, availableRes / ci.creID.toCreature()->getFullRecruitCost()); //max count we can afford
if(!ci.count)
continue;
@ -270,7 +270,7 @@ std::shared_ptr<CCreatureSet> ArmyManager::getArmyAvailableToBuyAsCCreatureSet(
break;
army->setCreature(dst, ci.creID, ci.count);
availableRes -= ci.cre->getFullRecruitCost() * ci.count;
availableRes -= ci.creID.toCreature()->getFullRecruitCost() * ci.count;
}
return army;
@ -287,7 +287,7 @@ ui64 ArmyManager::howManyReinforcementsCanBuy(
for(const creInfo & ci : army)
{
aivalue += ci.count * ci.cre->getAIValue();
aivalue += ci.count * ci.creID.toCreature()->getAIValue();
}
return aivalue;
@ -320,7 +320,7 @@ std::vector<creInfo> ArmyManager::getArmyAvailableToBuy(
if(i < GameConstants::CREATURES_PER_TOWN && countGrowth)
{
ci.count += town ? town->creatureGrowth(i) : ci.cre->getGrowth();
ci.count += town ? town->creatureGrowth(i) : ci.creID.toCreature()->getGrowth();
}
if(!ci.count) continue;
@ -334,13 +334,13 @@ std::vector<creInfo> ArmyManager::getArmyAvailableToBuy(
freeHeroSlots--; //new slot will be occupied
}
vstd::amin(ci.count, availableRes / ci.cre->getFullRecruitCost()); //max count we can afford
vstd::amin(ci.count, availableRes / ci.creID.toCreature()->getFullRecruitCost()); //max count we can afford
if(!ci.count) continue;
ci.level = i; //this is important for Dungeon Summoning Portal
creaturesInDwellings.push_back(ci);
availableRes -= ci.cre->getFullRecruitCost() * ci.count;
availableRes -= ci.creID.toCreature()->getFullRecruitCost() * ci.count;
}
return creaturesInDwellings;

View File

@ -165,7 +165,7 @@ void DangerHitMapAnalyzer::calculateTileOwners()
auto addTownHero = [&](const CGTownInstance * town)
{
auto townHero = new CGHeroInstance();
auto townHero = new CGHeroInstance(town->cb);
CRandomGenerator rng;
auto visitablePos = town->visitablePos();

View File

@ -30,7 +30,7 @@ ui64 FuzzyHelper::estimateBankDanger(const CBank * bank)
ui64 totalStrength = 0;
ui8 totalChance = 0;
for(auto config : bankInfo->getPossibleGuards())
for(auto config : bankInfo->getPossibleGuards(bank->cb))
{
totalStrength += config.second.totalStrength * config.first;
totalChance += config.first;

View File

@ -141,7 +141,7 @@ uint64_t getCreatureBankArmyReward(const CGObjectInstance * target, const CGHero
{
auto objectInfo = target->getObjectHandler()->getObjectInfo(target->appearance);
CBankInfo * bankInfo = dynamic_cast<CBankInfo *>(objectInfo.get());
auto creatures = bankInfo->getPossibleCreaturesReward();
auto creatures = bankInfo->getPossibleCreaturesReward(target->cb);
uint64_t result = 0;
const auto& slots = hero->Slots();
@ -236,7 +236,7 @@ int getDwellingArmyCost(const CGObjectInstance * target)
return cost;
}
uint64_t evaluateArtifactArmyValue(CArtifactInstance * art)
static uint64_t evaluateArtifactArmyValue(const CArtifactInstance * art)
{
if(art->artType->getId() == ArtifactID::SPELL_SCROLL)
return 1500;

View File

@ -54,12 +54,12 @@ void BuyArmy::accept(AIGateway * ai)
if(objid != CreatureID::NONE && ci.creID.getNum() != objid)
continue;
vstd::amin(ci.count, res / ci.cre->getFullRecruitCost());
vstd::amin(ci.count, res / ci.creID.toCreature()->getFullRecruitCost());
if(ci.count)
{
cb->recruitCreatures(town, town->getUpperArmy(), ci.creID, ci.count, ci.level);
valueBought += ci.count * ci.cre->getAIValue();
valueBought += ci.count * ci.creID.toCreature()->getAIValue();
}
}

View File

@ -98,7 +98,7 @@ std::string CompleteQuest::questToString() const
return "inactive quest";
MetaString ms;
q.quest->getRolloverText(ms, false);
q.quest->getRolloverText(q.obj->cb, ms, false);
return ms.toString();
}

View File

@ -373,10 +373,10 @@ HeroExchangeArmy * HeroExchangeMap::tryUpgrade(
for(auto & creatureToBuy : buyArmy)
{
auto targetSlot = target->getSlotFor(dynamic_cast<const CCreature*>(creatureToBuy.cre));
auto targetSlot = target->getSlotFor(creatureToBuy.creID.toCreature());
target->addToSlot(targetSlot, creatureToBuy.creID, creatureToBuy.count);
target->armyCost += creatureToBuy.cre->getFullRecruitCost() * creatureToBuy.count;
target->armyCost += creatureToBuy.creID.toCreature()->getFullRecruitCost() * creatureToBuy.count;
target->requireBuyArmy = true;
}
}

View File

@ -31,7 +31,7 @@ public:
virtual bool needsLastStack() const override;
std::shared_ptr<SpecialAction> getActorAction() const;
HeroExchangeArmy(): CArmedInstance(true), requireBuyArmy(false) {}
HeroExchangeArmy(): CArmedInstance(nullptr, true), requireBuyArmy(false) {}
};
struct ExchangeResult

View File

@ -72,7 +72,7 @@ ui64 FuzzyHelper::estimateBankDanger(const CBank * bank)
ui64 totalStrength = 0;
ui8 totalChance = 0;
for(auto config : bankInfo->getPossibleGuards())
for(auto config : bankInfo->getPossibleGuards(bank->cb))
{
totalStrength += config.second.totalStrength * config.first;
totalChance += config.first;

View File

@ -103,7 +103,7 @@ std::string CompleteQuest::questToString() const
return "inactive quest";
MetaString ms;
q.quest->getRolloverText(ms, false);
q.quest->getRolloverText(q.obj->cb, ms, false);
return ms.toString();
}

View File

@ -22,7 +22,6 @@
#include "../../lib/CHeroHandler.h"
#include "../../lib/GameSettings.h"
#include "../../lib/gameState/CGameState.h"
#include "../../lib/bonuses/CBonusSystemNode.h"
#include "../../lib/bonuses/Limiters.h"
#include "../../lib/bonuses/Updaters.h"
#include "../../lib/bonuses/Propagators.h"

View File

@ -16,6 +16,7 @@
#include "client/Client.h"
#include "lib/mapping/CMap.h"
#include "lib/mapObjects/CGHeroInstance.h"
#include "lib/mapObjects/CGTownInstance.h"
#include "lib/CBuildingHandler.h"
#include "lib/CGeneralTextHandler.h"
#include "lib/CHeroHandler.h"

View File

@ -12,16 +12,13 @@
#include "../lib/VCMI_Lib.h"
const CGameInfo * CGI;
CGameInfo * CGI;
CClientState * CCS = nullptr;
CServerHandler * CSH;
CGameInfo::CGameInfo()
{
generaltexth = nullptr;
mh = nullptr;
townh = nullptr;
globalServices = nullptr;
}

View File

@ -56,7 +56,7 @@ extern CClientState * CCS;
/// CGameInfo class
/// for allowing different functions for accessing game informations
class CGameInfo : public Services
class CGameInfo final : public Services
{
public:
const ArtifactService * artifacts() const override;
@ -78,19 +78,20 @@ public:
const spells::effects::Registry * spellEffects() const override;
spells::effects::Registry * spellEffects() override;
ConstTransitivePtr<CModHandler> modh; //public?
ConstTransitivePtr<BattleFieldHandler> battleFieldHandler;
ConstTransitivePtr<CHeroHandler> heroh;
ConstTransitivePtr<CCreatureHandler> creh;
ConstTransitivePtr<CSpellHandler> spellh;
ConstTransitivePtr<CSkillHandler> skillh;
ConstTransitivePtr<CObjectHandler> objh;
ConstTransitivePtr<TerrainTypeHandler> terrainTypeHandler;
ConstTransitivePtr<CObjectClassesHandler> objtypeh;
ConstTransitivePtr<ObstacleHandler> obstacleHandler;
CGeneralTextHandler * generaltexth;
CMapHandler * mh;
CTownHandler * townh;
std::shared_ptr<const CModHandler> modh;
std::shared_ptr<const BattleFieldHandler> battleFieldHandler;
std::shared_ptr<const CHeroHandler> heroh;
std::shared_ptr<const CCreatureHandler> creh;
std::shared_ptr<const CSpellHandler> spellh;
std::shared_ptr<const CSkillHandler> skillh;
std::shared_ptr<const CObjectHandler> objh;
std::shared_ptr<const TerrainTypeHandler> terrainTypeHandler;
std::shared_ptr<const CObjectClassesHandler> objtypeh;
std::shared_ptr<const ObstacleHandler> obstacleHandler;
std::shared_ptr<const CGeneralTextHandler> generaltexth;
std::shared_ptr<const CTownHandler> townh;
std::shared_ptr<CMapHandler> mh;
void setFromLib();
@ -98,4 +99,4 @@ public:
private:
const Services * globalServices;
};
extern const CGameInfo* CGI;
extern CGameInfo* CGI;

View File

@ -72,7 +72,7 @@ void init()
CStopWatch tmh;
loadDLLClasses();
const_cast<CGameInfo*>(CGI)->setFromLib();
CGI->setFromLib();
logGlobal->info("Initializing VCMI_Lib: %d ms", tmh.getDiff());

View File

@ -82,7 +82,6 @@
#include "../lib/UnlockGuard.h"
#include "../lib/VCMIDirs.h"
#include "../lib/bonuses/CBonusSystemNode.h"
#include "../lib/bonuses/Limiters.h"
#include "../lib/bonuses/Propagators.h"
#include "../lib/bonuses/Updaters.h"

View File

@ -277,6 +277,9 @@ void CServerHandler::onConnectionFailed(const std::string & errorMessage)
// retry - local server might be still starting up
logNetwork->debug("\nCannot establish connection. %s. Retrying...", errorMessage);
networkHandler->createTimer(*this, std::chrono::milliseconds(100));
nextClient = std::make_unique<CClient>();
c->setCallback(nextClient.get());
}
else
{
@ -633,7 +636,8 @@ void CServerHandler::startGameplay(VCMI_LIB_WRAP_NAMESPACE(CGameState) * gameSta
{
if(CMM)
CMM->disable();
client = new CClient();
std::swap(client, nextClient);
highScoreCalc = nullptr;
@ -667,7 +671,7 @@ void CServerHandler::endGameplay(bool closeConnection, bool restart)
}
client->endGame();
vstd::clear_pointer(client);
client.reset();
if(!restart)
{
@ -683,8 +687,12 @@ void CServerHandler::endGameplay(bool closeConnection, bool restart)
}
if(c)
{
nextClient = std::make_unique<CClient>();
c->setCallback(nextClient.get());
c->enterLobbyConnectionMode();
}
}
void CServerHandler::startCampaignScenario(HighScoreParameter param, std::shared_ptr<CampaignState> cs)
{

View File

@ -95,6 +95,11 @@ class CServerHandler final : public IServerAPI, public LobbyInfo, public INetwor
void threadRunNetwork();
void threadRunServer(bool connectToLobby);
/// temporary helper member that exists while game in lobby mode
/// required to correctly deserialize gamestate using client-side game callback
std::unique_ptr<CClient> nextClient;
void onServerFinished();
void sendLobbyPack(const CPackForLobby & pack) const override;
@ -131,7 +136,7 @@ public:
std::unique_ptr<boost::thread> threadRunLocalServer;
std::unique_ptr<boost::thread> threadNetwork;
CClient * client;
std::unique_ptr<CClient> client;
CondSh<bool> campaignServerRestartLock;

View File

@ -140,14 +140,10 @@ CClient::CClient()
waitingRequest.clear();
applier = std::make_shared<CApplier<CBaseForCLApply>>();
registerTypesClientPacks(*applier);
IObjectInterface::cb = this;
gs = nullptr;
}
CClient::~CClient()
{
IObjectInterface::cb = nullptr;
}
CClient::~CClient() = default;
const Services * CClient::services() const
{
@ -178,8 +174,9 @@ void CClient::newGame(CGameState * initializedGameState)
{
CSH->th->update();
CMapService mapService;
gs = initializedGameState ? initializedGameState : new CGameState();
gs->preInit(VLC);
assert(initializedGameState);
gs = initializedGameState;
gs->preInit(VLC, this);
logNetwork->trace("\tCreating gamestate: %i", CSH->th->getDiff());
if(!initializedGameState)
{
@ -201,7 +198,7 @@ void CClient::loadGame(CGameState * initializedGameState)
logNetwork->info("Game state was transferred over network, loading.");
gs = initializedGameState;
gs->preInit(VLC);
gs->preInit(VLC, this);
gs->updateOnLoad(CSH->si.get());
logNetwork->info("Game loaded, initialize interfaces.");
@ -371,7 +368,7 @@ void CClient::endGame()
logNetwork->info("Ending current game!");
removeGUI();
vstd::clear_pointer(const_cast<CGameInfo *>(CGI)->mh);
CGI->mh.reset();
vstd::clear_pointer(gs);
logNetwork->info("Deleted mapHandler and gameState.");
@ -393,7 +390,7 @@ void CClient::initMapHandler()
// During loading CPlayerInterface from serialized state it's depend on MH
if(!settings["session"]["headless"].Bool())
{
const_cast<CGameInfo *>(CGI)->mh = new CMapHandler(gs->map);
CGI->mh = std::make_shared<CMapHandler>(gs->map);
logNetwork->trace("Creating mapHandler: %d ms", CSH->th->getDiff());
}

View File

@ -203,7 +203,7 @@ void ClientCommandManager::handleConvertTextCommand()
try
{
// load and drop loaded map - we only need loader to run over all maps
mapService.loadMap(mapName);
mapService.loadMap(mapName, nullptr);
}
catch(std::exception & e)
{
@ -216,7 +216,7 @@ void ClientCommandManager::handleConvertTextCommand()
{
auto state = CampaignHandler::getCampaign(campaignName.getName());
for (auto const & part : state->allScenarios())
state->getMap(part);
state->getMap(part, nullptr);
}
VLC->generaltexth->dumpAllTexts();

View File

@ -39,6 +39,7 @@
#include "../lib/StartInfo.h"
#include "../lib/CConfigHandler.h"
#include "../lib/mapObjects/CGMarket.h"
#include "../lib/mapObjects/CGTownInstance.h"
#include "../lib/gameState/CGameState.h"
#include "../lib/CStack.h"
#include "../lib/battle/BattleInfo.h"

View File

@ -530,7 +530,7 @@ void StackInfoBasicPanel::initializeData(const CStack * stack)
if (hasGraphics)
{
//FIXME: support permanent duration
int duration = stack->getBonusLocalFirst(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(effect)))->turnsRemain;
int duration = stack->getFirstBonus(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(effect)))->turnsRemain;
icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("SpellInt"), effect + 1, 0, firstPos.x + offset.x * printed, firstPos.y + offset.y * printed));
if(settings["general"]["enableUiEnhancements"].Bool())

View File

@ -601,7 +601,7 @@ void BattleWindow::bSpellf()
{
//TODO: move to spell mechanics, add more information to spell cast problem
//Handle Orb of Inhibition-like effects -> we want to display dialog with info, why casting is impossible
auto blockingBonus = owner.currentHero()->getBonusLocalFirst(Selector::type()(BonusType::BLOCK_ALL_MAGIC));
auto blockingBonus = owner.currentHero()->getFirstBonus(Selector::type()(BonusType::BLOCK_ALL_MAGIC));
if (!blockingBonus)
return;

View File

@ -21,6 +21,7 @@
#include "../../lib/Point.h"
#include "../../lib/mapObjects/CGHeroInstance.h"
#include "../../lib/mapObjects/MiscObjects.h"
#include "../../lib/spells/CSpellHandler.h"
#include "../../lib/mapping/CMap.h"
#include "../../lib/pathfinder/CGPathNode.h"

View File

@ -225,7 +225,7 @@ CStackWindow::ActiveSpellsSection::ActiveSpellsSection(CStackWindow * owner, int
spellText = CGI->generaltexth->allTexts[610]; //"%s, duration: %d rounds."
boost::replace_first(spellText, "%s", spell->getNameTranslated());
//FIXME: support permanent duration
int duration = battleStack->getBonusLocalFirst(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(effect)))->turnsRemain;
int duration = battleStack->getFirstBonus(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(effect)))->turnsRemain;
boost::replace_first(spellText, "%d", std::to_string(duration));
spellIcons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("SpellInt"), effect + 1, 0, firstPos.x + offset.x * printed, firstPos.y + offset.y * printed));

View File

@ -104,7 +104,7 @@ std::vector<Canvas> CMapOverviewWidget::createMinimaps(ResourcePath resource) co
std::unique_ptr<CMap> map;
try
{
map = mapService.loadMap(resource);
map = mapService.loadMap(resource, nullptr);
}
catch (const std::exception & e)
{
@ -169,7 +169,7 @@ CMapOverviewWidget::CMapOverviewWidget(CMapOverview& parent):
lf >> *(mapHeader) >> startInfo;
if(startInfo->campState)
campaignMap = startInfo->campState->getMap(*startInfo->campState->currentScenario());
campaignMap = startInfo->campState->getMap(*startInfo->campState->currentScenario(), nullptr);
res = ResourcePath(startInfo->fileURI, EResType::MAP);
}
if(!campaignMap)

View File

@ -160,7 +160,7 @@ void CQuestLog::recreateLabelList()
}
MetaString text;
quests[i].quest->getRolloverText (text, false);
quests[i].quest->getRolloverText (quests[i].obj->cb, text, false);
if (quests[i].obj)
{
if (auto seersHut = dynamic_cast<const CGSeerHut *>(quests[i].obj))
@ -236,7 +236,7 @@ void CQuestLog::selectQuest(int which, int labelId)
MetaString text;
std::vector<Component> components;
currentQuest->quest->getVisitText(text, components, true);
currentQuest->quest->getVisitText(currentQuest->obj->cb, text, components, true);
if(description->slider)
description->slider->scrollToMin(); // scroll text to start position
description->setText(text.toString()); //TODO: use special log entry text

View File

@ -629,6 +629,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
${MAIN_LIB_DIR}/CThreadHelper.h
${MAIN_LIB_DIR}/CTownHandler.h
${MAIN_LIB_DIR}/FunctionList.h
${MAIN_LIB_DIR}/GameCallbackHolder.h
${MAIN_LIB_DIR}/GameConstants.h
${MAIN_LIB_DIR}/GameSettings.h
${MAIN_LIB_DIR}/IBonusTypeHandler.h

View File

@ -24,6 +24,7 @@ VCMI is an open-source recreation of Heroes of Might & Magic III engine, giving
* Bugtracker: https://github.com/vcmi/vcmi/issues
* Slack: https://slack.vcmi.eu/
* Discord: https://discord.gg/chBT42V
* GPT Store: https://chat.openai.com/g/g-1kNhX0mlO-vcmi-assistant
## Latest release

View File

@ -187,14 +187,14 @@ DLL_LINKAGE std::vector<const CArtifact*> ArtifactUtils::assemblyPossibilities(
DLL_LINKAGE CArtifactInstance * ArtifactUtils::createScroll(const SpellID & sid)
{
auto ret = new CArtifactInstance(VLC->arth->objects[ArtifactID::SPELL_SCROLL]);
auto ret = new CArtifactInstance(ArtifactID(ArtifactID::SPELL_SCROLL).toArtifact());
auto bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SPELL,
BonusSource::ARTIFACT_INSTANCE, -1, BonusSourceID(ArtifactID(ArtifactID::SPELL_SCROLL)), BonusSubtypeID(sid));
ret->addNewBonus(bonus);
return ret;
}
DLL_LINKAGE CArtifactInstance * ArtifactUtils::createNewArtifactInstance(CArtifact * art)
DLL_LINKAGE CArtifactInstance * ArtifactUtils::createNewArtifactInstance(const CArtifact * art)
{
assert(art);
@ -216,7 +216,7 @@ DLL_LINKAGE CArtifactInstance * ArtifactUtils::createNewArtifactInstance(CArtifa
DLL_LINKAGE CArtifactInstance * ArtifactUtils::createNewArtifactInstance(const ArtifactID & aid)
{
return ArtifactUtils::createNewArtifactInstance((*VLC->arth)[aid]);
return ArtifactUtils::createNewArtifactInstance(aid.toArtifact());
}
DLL_LINKAGE CArtifactInstance * ArtifactUtils::createArtifact(CMap * map, const ArtifactID & aid, SpellID spellID)

View File

@ -40,7 +40,7 @@ namespace ArtifactUtils
DLL_LINKAGE bool isBackpackFreeSlots(const CArtifactSet * target, const size_t reqSlots = 1);
DLL_LINKAGE std::vector<const CArtifact*> assemblyPossibilities(const CArtifactSet * artSet, const ArtifactID & aid);
DLL_LINKAGE CArtifactInstance * createScroll(const SpellID & sid);
DLL_LINKAGE CArtifactInstance * createNewArtifactInstance(CArtifact * art);
DLL_LINKAGE CArtifactInstance * createNewArtifactInstance(const CArtifact * art);
DLL_LINKAGE CArtifactInstance * createNewArtifactInstance(const ArtifactID & aid);
DLL_LINKAGE CArtifactInstance * createArtifact(CMap * map, const ArtifactID & aid, SpellID spellID = SpellID::NONE);
DLL_LINKAGE void insertScrrollSpellName(std::string & description, const SpellID & sid);

View File

@ -49,12 +49,12 @@ bool CCombinedArtifact::isCombined() const
return !(constituents.empty());
}
const std::vector<CArtifact*> & CCombinedArtifact::getConstituents() const
const std::vector<const CArtifact*> & CCombinedArtifact::getConstituents() const
{
return constituents;
}
const std::vector<CArtifact*> & CCombinedArtifact::getPartOf() const
const std::vector<const CArtifact*> & CCombinedArtifact::getPartOf() const
{
return partOf;
}
@ -328,7 +328,7 @@ std::vector<JsonNode> CArtHandler::loadLegacyData()
const std::vector<std::string> artSlots = { ART_POS_LIST };
#undef ART_POS
static std::map<char, std::string> classes =
static const std::map<char, std::string> classes =
{{'S',"SPECIAL"}, {'T',"TREASURE"},{'N',"MINOR"},{'J',"MAJOR"},{'R',"RELIC"},};
CLegacyConfigParser parser(TextPath::builtin("DATA/ARTRAITS.TXT"));
@ -353,7 +353,7 @@ std::vector<JsonNode> CArtHandler::loadLegacyData()
artData["slot"].Vector().back().String() = artSlot;
}
}
artData["class"].String() = classes[parser.readString()[0]];
artData["class"].String() = classes.at(parser.readString()[0]);
artData["text"]["description"].String() = parser.readString();
parser.endLine();
@ -597,7 +597,7 @@ void CArtHandler::loadComponents(CArtifact * art, const JsonNode & node)
{
// when this code is called both combinational art as well as component are loaded
// so it is safe to access any of them
art->constituents.push_back(objects[id]);
art->constituents.push_back(ArtifactID(id).toArtifact());
objects[id]->partOf.push_back(art);
});
}

View File

@ -47,12 +47,12 @@ class DLL_LINKAGE CCombinedArtifact
protected:
CCombinedArtifact() = default;
std::vector<CArtifact*> constituents; // Artifacts IDs a combined artifact consists of, or nullptr.
std::vector<CArtifact*> partOf; // Reverse map of constituents - combined arts that include this art
std::vector<const CArtifact*> constituents; // Artifacts IDs a combined artifact consists of, or nullptr.
std::vector<const CArtifact*> partOf; // Reverse map of constituents - combined arts that include this art
public:
bool isCombined() const;
const std::vector<CArtifact*> & getConstituents() const;
const std::vector<CArtifact*> & getPartOf() const;
const std::vector<const CArtifact*> & getConstituents() const;
const std::vector<const CArtifact*> & getPartOf() const;
};
class DLL_LINKAGE CScrollArtifact

View File

@ -62,7 +62,7 @@ void CCombinedArtifactInstance::addPlacementMap(CArtifactSet::ArtPlacementMap &
SpellID CScrollArtifactInstance::getScrollSpellID() const
{
auto artInst = static_cast<const CArtifactInstance*>(this);
const auto bonus = artInst->getBonusLocalFirst(Selector::type()(BonusType::SPELL));
const auto bonus = artInst->getFirstBonus(Selector::type()(BonusType::SPELL));
if(!bonus)
return SpellID::NONE;
return bonus->subtype.as<SpellID>();
@ -107,7 +107,7 @@ void CArtifactInstance::init()
setNodeType(ARTIFACT_INSTANCE);
}
CArtifactInstance::CArtifactInstance(CArtifact * art)
CArtifactInstance::CArtifactInstance(const CArtifact * art)
{
init();
setType(art);
@ -118,10 +118,10 @@ CArtifactInstance::CArtifactInstance()
init();
}
void CArtifactInstance::setType(CArtifact * art)
void CArtifactInstance::setType(const CArtifact * art)
{
artType = art;
attachTo(*art);
attachToSource(*art);
}
std::string CArtifactInstance::nodeName() const

View File

@ -73,11 +73,11 @@ protected:
ArtifactInstanceID id;
public:
ConstTransitivePtr<CArtifact> artType;
const CArtifact * artType = nullptr;
CArtifactInstance(CArtifact * art);
CArtifactInstance(const CArtifact * art);
CArtifactInstance();
void setType(CArtifact * art);
void setType(const CArtifact * art);
std::string nodeName() const override;
std::string getDescription() const;
ArtifactID getTypeId() const;

View File

@ -407,20 +407,9 @@ void CCreature::serializeJson(JsonSerializeFormat & handler)
CCreatureHandler::CCreatureHandler()
: expAfterUpgrade(0)
{
VLC->creh = this;
loadCommanders();
}
const CCreature * CCreatureHandler::getCreature(const std::string & scope, const std::string & identifier) const
{
std::optional<si32> index = VLC->identifiers()->getIdentifier(scope, "creature", identifier);
if(!index)
throw std::runtime_error("Creature not found "+identifier);
return objects[*index];
}
void CCreatureHandler::loadCommanders()
{
auto configResource = JsonPath::builtin("config/commanders.json");
@ -797,7 +786,7 @@ void CCreatureHandler::loadCrExpBon(CBonusSystemNode & globalEffects)
bl.clear();
loadStackExp(b, bl, parser);
for(const auto & b : bl)
(*this)[sid]->addNewBonus(b); //add directly to CCreature Node
objects[sid.getNum()]->addNewBonus(b); //add directly to CCreature Node
}
while (parser.endLine());

View File

@ -222,8 +222,6 @@ public:
std::vector< std::vector <ui8> > skillLevels; //how much of a bonus will be given to commander with every level. SPELL_POWER also gives CASTS and RESISTANCE
std::vector <std::pair <std::shared_ptr<Bonus>, std::pair <ui8, ui8> > > skillRequirements; // first - Bonus, second - which two skills are needed to use it
const CCreature * getCreature(const std::string & scope, const std::string & identifier) const;
CreatureID pickRandomMonster(CRandomGenerator & rand, int tier = -1) const; //tier <1 - CREATURES_PER_TOWN> or -1 for any
CCreatureHandler();

View File

@ -739,11 +739,10 @@ void CStackInstance::giveStackExp(TExpType exp)
if (!vstd::iswithin(level, 1, 7))
level = 0;
CCreatureHandler * creh = VLC->creh;
ui32 maxExp = creh->expRanks[level].back();
ui32 maxExp = VLC->creh->expRanks[level].back();
vstd::amin(exp, static_cast<TExpType>(maxExp)); //prevent exp overflow due to different types
vstd::amin(exp, (maxExp * creh->maxExpPerBattle[level])/100);
vstd::amin(exp, (maxExp * VLC->creh->maxExpPerBattle[level])/100);
vstd::amin(experience += exp, maxExp); //can't get more exp than this limit
}
@ -759,7 +758,7 @@ void CStackInstance::setType(const CCreature *c)
{
if(type)
{
detachFrom(const_cast<CCreature&>(*type));
detachFromSource(*type);
if (type->isMyUpgrade(c) && VLC->settings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE))
experience = static_cast<TExpType>(experience * VLC->creh->expAfterUpgrade / 100.0);
}
@ -767,7 +766,7 @@ void CStackInstance::setType(const CCreature *c)
CStackBasicDescriptor::setType(c);
if(type)
attachTo(const_cast<CCreature&>(*type));
attachToSource(*type);
}
std::string CStackInstance::bonusToString(const std::shared_ptr<Bonus>& bonus, bool description) const
{
@ -1055,7 +1054,7 @@ void CStackBasicDescriptor::serializeJson(JsonSerializeFormat & handler)
std::string typeName;
handler.serializeString("type", typeName);
if(!typeName.empty())
setType(VLC->creh->getCreature(ModScope::scopeMap(), typeName));
setType(CreatureID(CreatureID::decode(typeName)).toCreature());
}
}

View File

@ -16,6 +16,8 @@
#include "gameState/TavernHeroesPool.h"
#include "gameState/QuestInfo.h"
#include "mapObjects/CGHeroInstance.h"
#include "mapObjects/CGTownInstance.h"
#include "mapObjects/MiscObjects.h"
#include "networkPacks/ArtifactLocation.h"
#include "CGeneralTextHandler.h"
#include "StartInfo.h" // for StartInfo
@ -382,7 +384,7 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
if(creature->getFaction() == factionIndex && static_cast<int>(creature->getAIValue()) > maxAIValue)
{
maxAIValue = creature->getAIValue();
mostStrong = creature;
mostStrong = creature.get();
}
}
@ -791,7 +793,7 @@ int CPlayerSpecificInfoCallback::getHeroSerial(const CGHeroInstance * hero, bool
int3 CPlayerSpecificInfoCallback::getGrailPos( double *outKnownRatio )
{
if (!getPlayerID() || CGObelisk::obeliskCount == 0)
if (!getPlayerID() || gs->map->obeliskCount == 0)
{
*outKnownRatio = 0.0;
}
@ -799,10 +801,10 @@ int3 CPlayerSpecificInfoCallback::getGrailPos( double *outKnownRatio )
{
TeamID t = gs->getPlayerTeam(*getPlayerID())->id;
double visited = 0.0;
if(CGObelisk::visited.count(t))
visited = static_cast<double>(CGObelisk::visited[t]);
if(gs->map->obelisksVisited.count(t))
visited = static_cast<double>(gs->map->obelisksVisited[t]);
*outKnownRatio = visited / CGObelisk::obeliskCount;
*outKnownRatio = visited / gs->map->obeliskCount;
}
return gs->map->grailPos;
}

View File

@ -155,6 +155,14 @@ bool CHeroClass::isMagicHero() const
return affinity == MAGIC;
}
int CHeroClass::tavernProbability(FactionID targetFaction) const
{
auto it = selectionProbability.find(targetFaction);
if (it != selectionProbability.end())
return it->second;
return 0;
}
EAlignment CHeroClass::getAlignment() const
{
return VLC->factions()->getById(faction)->getAlignment();
@ -292,7 +300,7 @@ CHeroClass * CHeroClassHandler::loadFromJson(const std::string & scope, const Js
VLC->identifiers()->requestIdentifier ("creature", node["commander"],
[=](si32 commanderID)
{
heroClass->commander = VLC->creh->objects[commanderID];
heroClass->commander = CreatureID(commanderID).toCreature();
});
heroClass->defaultTavernChance = static_cast<ui32>(node["defaultTavern"].Float());
@ -369,9 +377,9 @@ std::vector<JsonNode> CHeroClassHandler::loadLegacyData()
void CHeroClassHandler::afterLoadFinalization()
{
// for each pair <class, town> set selection probability if it was not set before in tavern entries
for(CHeroClass * heroClass : objects)
for(auto & heroClass : objects)
{
for(CFaction * faction : VLC->townh->objects)
for(auto & faction : VLC->townh->objects)
{
if (!faction->town)
continue;
@ -394,7 +402,7 @@ void CHeroClassHandler::afterLoadFinalization()
}
}
for(CHeroClass * hc : objects)
for(const auto & hc : objects)
{
if(!hc->imageMapMale.empty())
{
@ -454,7 +462,7 @@ CHero * CHeroHandler::loadFromJson(const std::string & scope, const JsonNode & n
VLC->identifiers()->requestIdentifier("heroClass", node["class"],
[=](si32 classID)
{
hero->heroClass = classes[HeroClassID(classID)];
hero->heroClass = HeroClassID(classID).toHeroClass();
});
return hero;
@ -532,7 +540,7 @@ static std::vector<std::shared_ptr<Bonus>> createCreatureSpecialty(CreatureID ba
{
std::set<CreatureID> oldTargets = targets;
for (auto const & upgradeSourceID : oldTargets)
for(const auto & upgradeSourceID : oldTargets)
{
const CCreature * upgradeSource = upgradeSourceID.toCreature();
targets.insert(upgradeSource->upgrades.begin(), upgradeSource->upgrades.end());
@ -544,7 +552,7 @@ static std::vector<std::shared_ptr<Bonus>> createCreatureSpecialty(CreatureID ba
for(CreatureID cid : targets)
{
auto const & specCreature = *cid.toCreature();
const auto & specCreature = *cid.toCreature();
int stepSize = specCreature.getLevel() ? specCreature.getLevel() : 5;
{
@ -604,7 +612,7 @@ void CHeroHandler::beforeValidate(JsonNode & object)
void CHeroHandler::afterLoadFinalization()
{
for (auto const & functor : callAfterLoadFinalization)
for(const auto & functor : callAfterLoadFinalization)
functor();
callAfterLoadFinalization.clear();
@ -790,7 +798,7 @@ std::set<HeroTypeID> CHeroHandler::getDefaultAllowed() const
{
std::set<HeroTypeID> result;
for(const CHero * hero : objects)
for(auto & hero : objects)
if (hero && !hero->special)
result.insert(hero->getId());

View File

@ -57,7 +57,7 @@ public:
std::vector<InitialArmyStack> initialArmy;
CHeroClass * heroClass{};
const CHeroClass * heroClass = nullptr;
std::vector<std::pair<SecondarySkill, ui8> > secSkillsInit; //initial secondary skills; first - ID of skill, second - level of skill (1 - basic, 2 - adv., 3 - expert)
BonusList specialty;
std::set<SpellID> spells;
@ -121,7 +121,7 @@ public:
// resulting chance = sqrt(town.chance * heroClass.chance)
ui32 defaultTavernChance;
CCreature * commander;
const CCreature * commander;
std::vector<int> primarySkillInitial; // initial primary skills
std::vector<int> primarySkillLowLevel; // probability (%) of getting point of primary skill when getting level
@ -154,6 +154,8 @@ public:
void serializeJson(JsonSerializeFormat & handler);
EAlignment getAlignment() const;
int tavernProbability(FactionID faction) const;
};
class DLL_LINKAGE CHeroClassHandler : public CHandlerBase<HeroClassID, HeroClass, CHeroClass, HeroClassService>
@ -189,8 +191,6 @@ class DLL_LINKAGE CHeroHandler : public CHandlerBase<HeroTypeID, HeroType, CHero
std::vector<std::function<void()>> callAfterLoadFinalization;
public:
CHeroClassHandler classes;
ui32 level(TExpType experience) const; //calculates level corresponding to given experience amount
TExpType reqExp(ui32 level) const; //calculates experience required for given level
ui32 maxSupportedLevel() const;

View File

@ -23,8 +23,6 @@ PlayerState::PlayerState()
setNodeType(PLAYER);
}
PlayerState::PlayerState(PlayerState && other) noexcept = default;
PlayerState::~PlayerState() = default;
std::string PlayerState::nodeName() const

View File

@ -67,7 +67,6 @@ public:
TurnTimerInfo turnTimer;
PlayerState();
PlayerState(PlayerState && other) noexcept;
~PlayerState();
std::string nodeName() const override;
@ -123,7 +122,6 @@ public:
std::unique_ptr<boost::multi_array<ui8, 3>> fogOfWarMap; //[z][x][y] true - visible, false - hidden
TeamState();
TeamState(TeamState && other) noexcept;
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@ -72,7 +72,7 @@ void CStack::localInit(BattleInfo * battleInfo)
CArmedInstance * army = battle->battleGetArmyObject(side);
assert(army);
attachTo(*army);
attachTo(const_cast<CCreature&>(*type));
attachToSource(*type);
}
nativeTerrain = getNativeTerrain(); //save nativeTerrain in the variable on the battle start to avoid dead lock
CUnitState::localInit(this); //it causes execution of the CStack::isOnNativeTerrain where nativeTerrain will be considered

View File

@ -336,9 +336,9 @@ JsonNode readBuilding(CLegacyConfigParser & parser)
return ret;
}
TPropagatorPtr & CTownHandler::emptyPropagator()
const TPropagatorPtr & CTownHandler::emptyPropagator()
{
static TPropagatorPtr emptyProp(nullptr);
static const TPropagatorPtr emptyProp(nullptr);
return emptyProp;
}
@ -534,7 +534,7 @@ R CTownHandler::getMappedValue(const JsonNode & node, const R defval, const std:
void CTownHandler::addBonusesForVanilaBuilding(CBuilding * building) const
{
std::shared_ptr<Bonus> b;
static TPropagatorPtr playerPropagator = std::make_shared<CPropagatorNodeType>(CBonusSystemNode::ENodeTypes::PLAYER);
static const TPropagatorPtr playerPropagator = std::make_shared<CPropagatorNodeType>(CBonusSystemNode::ENodeTypes::PLAYER);
if(building->bid == BuildingID::TAVERN)
{
@ -578,7 +578,7 @@ std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, BonusType ty
return createBonus(build, type, val, subtype, emptyPropagator());
}
std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, BonusType type, int val, BonusSubtypeID subtype, TPropagatorPtr & prop) const
std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, BonusType type, int val, BonusSubtypeID subtype, const TPropagatorPtr & prop) const
{
std::ostringstream descr;
descr << build->getNameTranslated();
@ -589,7 +589,7 @@ std::shared_ptr<Bonus> CTownHandler::createBonusImpl(const BuildingID & building
const FactionID & faction,
BonusType type,
int val,
TPropagatorPtr & prop,
const TPropagatorPtr & prop,
const std::string & description,
BonusSubtypeID subtype) const
{
@ -991,7 +991,7 @@ void CTownHandler::loadTown(CTown * town, const JsonNode & source)
VLC->identifiers()->requestIdentifier(node.second.meta, "heroClass",node.first, [=](si32 classID)
{
VLC->heroh->classes[HeroClassID(classID)]->selectionProbability[town->faction->getId()] = chance;
VLC->heroclassesh->objects[classID]->selectionProbability[town->faction->getId()] = chance;
});
}

View File

@ -290,7 +290,7 @@ class DLL_LINKAGE CTownHandler : public CHandlerBase<FactionID, Faction, CFactio
std::vector<BuildingRequirementsHelper> requirementsToLoad;
std::vector<BuildingRequirementsHelper> overriddenBidsToLoad; //list of buildings, which bonuses should be overridden.
static TPropagatorPtr & emptyPropagator();
static const TPropagatorPtr & emptyPropagator();
void initializeRequirements();
void initializeOverridden();
@ -303,12 +303,12 @@ class DLL_LINKAGE CTownHandler : public CHandlerBase<FactionID, Faction, CFactio
std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val) const;
std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val, BonusSubtypeID subtype) const;
std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val, BonusSubtypeID subtype, TPropagatorPtr & prop) const;
std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val, BonusSubtypeID subtype, const TPropagatorPtr & prop) const;
std::shared_ptr<Bonus> createBonusImpl(const BuildingID & building,
const FactionID & faction,
BonusType type,
int val,
TPropagatorPtr & prop,
const TPropagatorPtr & prop,
const std::string & description,
BonusSubtypeID subtype) const;

26
lib/GameCallbackHolder.h Normal file
View File

@ -0,0 +1,26 @@
/*
* GameCallbackHolder.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
VCMI_LIB_NAMESPACE_BEGIN
class IGameCallback;
class DLL_LINKAGE GameCallbackHolder
{
public:
IGameCallback * const cb;
explicit GameCallbackHolder(IGameCallback *cb):
cb(cb)
{}
};
VCMI_LIB_NAMESPACE_END

View File

@ -16,7 +16,6 @@
#include "CBonusTypeHandler.h"
#include "BattleFieldHandler.h"
#include "ObstacleHandler.h"
#include "bonuses/CBonusSystemNode.h"
#include "bonuses/Limiters.h"
#include "bonuses/Propagators.h"
#include "bonuses/Updaters.h"
@ -26,7 +25,10 @@
#include "rmg/CMapGenOptions.h"
#include "mapObjectConstructors/AObjectTypeHandler.h"
#include "mapObjectConstructors/CObjectClassesHandler.h"
#include "mapObjects/CGTownInstance.h"
#include "mapObjects/CObjectHandler.h"
#include "mapObjects/CQuest.h"
#include "mapObjects/MiscObjects.h"
#include "mapObjects/ObjectTemplate.h"
#include "campaign/CampaignState.h"
#include "StartInfo.h"

View File

@ -44,11 +44,21 @@ public:
/// allows handler to do post-loading step for validation or integration of loaded data
virtual void afterLoadFinalization(){};
virtual ~IHandlerBase(){}
virtual ~IHandlerBase() = default;
};
template <class _ObjectID, class _ObjectBase, class _Object, class _ServiceBase> class CHandlerBase : public _ServiceBase, public IHandlerBase
{
const _Object * getObjectImpl(const int32_t index) const
{
if(index < 0 || index >= objects.size())
{
logMod->error("%s id %d is invalid", getTypeNames()[0], index);
throw std::runtime_error("Attempt to access invalid index " + std::to_string(index) + " of type " + getTypeNames().front());
}
return objects[index].get();
}
public:
virtual ~CHandlerBase()
{
@ -56,22 +66,21 @@ public:
{
o.dellNull();
}
}
const Entity * getBaseByIndex(const int32_t index) const override
{
return getByIndex(index);
return getObjectImpl(index);
}
const _ObjectBase * getById(const _ObjectID & id) const override
{
return (*this)[id].get();
return getObjectImpl(id.getNum());
}
const _ObjectBase * getByIndex(const int32_t index) const override
{
return (*this)[_ObjectID(index)].get();
return getObjectImpl(index);
}
void forEachBase(const std::function<void(const Entity * entity, bool & stop)> & cb) const override
@ -105,21 +114,14 @@ public:
registerObject(scope, type_name, name, object->getIndex());
}
ConstTransitivePtr<_Object> operator[] (const _ObjectID id) const
const _Object * operator[] (const _ObjectID id) const
{
const int32_t raw_id = id.getNum();
return operator[](raw_id);
return getObjectImpl(id.getNum());
}
ConstTransitivePtr<_Object> operator[] (int32_t index) const
const _Object * operator[] (int32_t index) const
{
if(index < 0 || index >= objects.size())
{
logMod->error("%s id %d is invalid", getTypeNames()[0], index);
throw std::runtime_error("Attempt to access invalid index " + std::to_string(index) + " of type " + getTypeNames().front());
}
return objects[index];
return getObjectImpl(index);
}
void updateEntity(int32_t index, const JsonNode & data)

View File

@ -694,7 +694,6 @@ std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonVector & ability_vec)
template <typename T>
const T parseByMap(const std::map<std::string, T> & map, const JsonNode * val, const std::string & err)
{
static T defaultValue = T();
if (!val->isNull())
{
const std::string & type = val->String();
@ -702,7 +701,7 @@ const T parseByMap(const std::map<std::string, T> & map, const JsonNode * val, c
if (it == map.end())
{
logMod->error("Error: invalid %s%s.", err, type);
return defaultValue;
return {};
}
else
{
@ -710,7 +709,7 @@ const T parseByMap(const std::map<std::string, T> & map, const JsonNode * val, c
}
}
else
return defaultValue;
return {};
}
template <typename T>

View File

@ -31,9 +31,7 @@
VCMI_LIB_NAMESPACE_BEGIN
namespace JsonRandom
{
si32 loadVariable(std::string variableGroup, const std::string & value, const Variables & variables, si32 defaultValue)
si32 JsonRandom::loadVariable(const std::string & variableGroup, const std::string & value, const Variables & variables, si32 defaultValue)
{
if (value.empty() || value[0] != '@')
{
@ -51,12 +49,12 @@ namespace JsonRandom
return variables.at(variableID);
}
si32 loadValue(const JsonNode & value, CRandomGenerator & rng, const Variables & variables, si32 defaultValue)
si32 JsonRandom::loadValue(const JsonNode & value, CRandomGenerator & rng, const Variables & variables, si32 defaultValue)
{
if(value.isNull())
return defaultValue;
if(value.isNumber())
return static_cast<si32>(value.Float());
return value.Integer();
if (value.isString())
return loadVariable("number", value.String(), variables, defaultValue);
@ -70,16 +68,16 @@ namespace JsonRandom
if(value.isStruct())
{
if (!value["amount"].isNull())
return static_cast<si32>(loadValue(value["amount"], rng, variables, defaultValue));
si32 min = static_cast<si32>(loadValue(value["min"], rng, variables, 0));
si32 max = static_cast<si32>(loadValue(value["max"], rng, variables, 0));
return loadValue(value["amount"], rng, variables, defaultValue);
si32 min = loadValue(value["min"], rng, variables, 0);
si32 max = loadValue(value["max"], rng, variables, 0);
return rng.getIntRange(min, max)();
}
return defaultValue;
}
template<typename IdentifierType>
IdentifierType decodeKey(const std::string & modScope, const std::string & value, const Variables & variables)
IdentifierType JsonRandom::decodeKey(const std::string & modScope, const std::string & value, const Variables & variables)
{
if (value.empty() || value[0] != '@')
return IdentifierType(*VLC->identifiers()->getIdentifier(modScope, IdentifierType::entityType(), value));
@ -88,7 +86,7 @@ namespace JsonRandom
}
template<typename IdentifierType>
IdentifierType decodeKey(const JsonNode & value, const Variables & variables)
IdentifierType JsonRandom::decodeKey(const JsonNode & value, const Variables & variables)
{
if (value.String().empty() || value.String()[0] != '@')
return IdentifierType(*VLC->identifiers()->getIdentifier(IdentifierType::entityType(), value));
@ -97,19 +95,19 @@ namespace JsonRandom
}
template<>
PlayerColor decodeKey(const JsonNode & value, const Variables & variables)
PlayerColor JsonRandom::decodeKey(const JsonNode & value, const Variables & variables)
{
return PlayerColor(*VLC->identifiers()->getIdentifier("playerColor", value));
}
template<>
PrimarySkill decodeKey(const JsonNode & value, const Variables & variables)
PrimarySkill JsonRandom::decodeKey(const JsonNode & value, const Variables & variables)
{
return PrimarySkill(*VLC->identifiers()->getIdentifier("primarySkill", value));
}
template<>
PrimarySkill decodeKey(const std::string & modScope, const std::string & value, const Variables & variables)
PrimarySkill JsonRandom::decodeKey(const std::string & modScope, const std::string & value, const Variables & variables)
{
if (value.empty() || value[0] != '@')
return PrimarySkill(*VLC->identifiers()->getIdentifier(modScope, "primarySkill", value));
@ -120,13 +118,13 @@ namespace JsonRandom
/// Method that allows type-specific object filtering
/// Default implementation is to accept all input objects
template<typename IdentifierType>
std::set<IdentifierType> filterKeysTyped(const JsonNode & value, const std::set<IdentifierType> & valuesSet)
std::set<IdentifierType> JsonRandom::filterKeysTyped(const JsonNode & value, const std::set<IdentifierType> & valuesSet)
{
return valuesSet;
}
template<>
std::set<ArtifactID> filterKeysTyped(const JsonNode & value, const std::set<ArtifactID> & valuesSet)
std::set<ArtifactID> JsonRandom::filterKeysTyped(const JsonNode & value, const std::set<ArtifactID> & valuesSet)
{
assert(value.isStruct());
@ -164,7 +162,7 @@ namespace JsonRandom
if(!allowedClasses.empty() && !allowedClasses.count(art->aClass))
continue;
if(!IObjectInterface::cb->isAllowed(art->getId()))
if(!cb->isAllowed(art->getId()))
continue;
if(!allowedPositions.empty())
@ -186,7 +184,7 @@ namespace JsonRandom
}
template<>
std::set<SpellID> filterKeysTyped(const JsonNode & value, const std::set<SpellID> & valuesSet)
std::set<SpellID> JsonRandom::filterKeysTyped(const JsonNode & value, const std::set<SpellID> & valuesSet)
{
std::set<SpellID> result = valuesSet;
@ -213,7 +211,7 @@ namespace JsonRandom
}
template<typename IdentifierType>
std::set<IdentifierType> filterKeys(const JsonNode & value, const std::set<IdentifierType> & valuesSet, const Variables & variables)
std::set<IdentifierType> JsonRandom::filterKeys(const JsonNode & value, const std::set<IdentifierType> & valuesSet, const Variables & variables)
{
if(value.isString())
return { decodeKey<IdentifierType>(value, variables) };
@ -257,7 +255,7 @@ namespace JsonRandom
return valuesSet;
}
TResources loadResources(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
TResources JsonRandom::loadResources(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
{
TResources ret;
@ -275,7 +273,7 @@ namespace JsonRandom
return ret;
}
TResources loadResource(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
TResources JsonRandom::loadResource(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
{
std::set<GameResID> defaultResources{
GameResID::WOOD,
@ -296,7 +294,7 @@ namespace JsonRandom
return ret;
}
PrimarySkill loadPrimary(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
PrimarySkill JsonRandom::loadPrimary(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
{
std::set<PrimarySkill> defaultSkills{
PrimarySkill::ATTACK,
@ -308,7 +306,7 @@ namespace JsonRandom
return *RandomGeneratorUtil::nextItem(potentialPicks, rng);
}
std::vector<si32> loadPrimaries(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
std::vector<si32> JsonRandom::loadPrimaries(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
{
std::vector<si32> ret(GameConstants::PRIMARY_SKILLS, 0);
std::set<PrimarySkill> defaultSkills{
@ -340,18 +338,18 @@ namespace JsonRandom
return ret;
}
SecondarySkill loadSecondary(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
SecondarySkill JsonRandom::loadSecondary(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
{
std::set<SecondarySkill> defaultSkills;
for(const auto & skill : VLC->skillh->objects)
if (IObjectInterface::cb->isAllowed(skill->getId()))
if (cb->isAllowed(skill->getId()))
defaultSkills.insert(skill->getId());
std::set<SecondarySkill> potentialPicks = filterKeys(value, defaultSkills, variables);
return *RandomGeneratorUtil::nextItem(potentialPicks, rng);
}
std::map<SecondarySkill, si32> loadSecondaries(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
std::map<SecondarySkill, si32> JsonRandom::loadSecondaries(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
{
std::map<SecondarySkill, si32> ret;
if(value.isStruct())
@ -366,7 +364,7 @@ namespace JsonRandom
{
std::set<SecondarySkill> defaultSkills;
for(const auto & skill : VLC->skillh->objects)
if (IObjectInterface::cb->isAllowed(skill->getId()))
if (cb->isAllowed(skill->getId()))
defaultSkills.insert(skill->getId());
for(const auto & element : value.Vector())
@ -381,19 +379,19 @@ namespace JsonRandom
return ret;
}
ArtifactID loadArtifact(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
ArtifactID JsonRandom::loadArtifact(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
{
std::set<ArtifactID> allowedArts;
for(const auto & artifact : VLC->arth->objects)
if (IObjectInterface::cb->isAllowed(artifact->getId()) && VLC->arth->legalArtifact(artifact->getId()))
if (cb->isAllowed(artifact->getId()) && VLC->arth->legalArtifact(artifact->getId()))
allowedArts.insert(artifact->getId());
std::set<ArtifactID> potentialPicks = filterKeys(value, allowedArts, variables);
return IObjectInterface::cb->gameState()->pickRandomArtifact(rng, potentialPicks);
return cb->gameState()->pickRandomArtifact(rng, potentialPicks);
}
std::vector<ArtifactID> loadArtifacts(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
std::vector<ArtifactID> JsonRandom::loadArtifacts(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
{
std::vector<ArtifactID> ret;
for (const JsonNode & entry : value.Vector())
@ -403,11 +401,11 @@ namespace JsonRandom
return ret;
}
SpellID loadSpell(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
SpellID JsonRandom::loadSpell(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
{
std::set<SpellID> defaultSpells;
for(const auto & spell : VLC->spellh->objects)
if (IObjectInterface::cb->isAllowed(spell->getId()) && !spell->isSpecial())
if (cb->isAllowed(spell->getId()) && !spell->isSpecial())
defaultSpells.insert(spell->getId());
std::set<SpellID> potentialPicks = filterKeys(value, defaultSpells, variables);
@ -420,7 +418,7 @@ namespace JsonRandom
return *RandomGeneratorUtil::nextItem(potentialPicks, rng);
}
std::vector<SpellID> loadSpells(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
std::vector<SpellID> JsonRandom::loadSpells(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
{
std::vector<SpellID> ret;
for (const JsonNode & entry : value.Vector())
@ -430,7 +428,7 @@ namespace JsonRandom
return ret;
}
std::vector<PlayerColor> loadColors(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
std::vector<PlayerColor> JsonRandom::loadColors(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
{
std::vector<PlayerColor> ret;
std::set<PlayerColor> defaultPlayers;
@ -446,7 +444,7 @@ namespace JsonRandom
return ret;
}
std::vector<HeroTypeID> loadHeroes(const JsonNode & value, CRandomGenerator & rng)
std::vector<HeroTypeID> JsonRandom::loadHeroes(const JsonNode & value, CRandomGenerator & rng)
{
std::vector<HeroTypeID> ret;
for(auto & entry : value.Vector())
@ -456,7 +454,7 @@ namespace JsonRandom
return ret;
}
std::vector<HeroClassID> loadHeroClasses(const JsonNode & value, CRandomGenerator & rng)
std::vector<HeroClassID> JsonRandom::loadHeroClasses(const JsonNode & value, CRandomGenerator & rng)
{
std::vector<HeroClassID> ret;
for(auto & entry : value.Vector())
@ -466,7 +464,7 @@ namespace JsonRandom
return ret;
}
CStackBasicDescriptor loadCreature(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
CStackBasicDescriptor JsonRandom::loadCreature(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
{
CStackBasicDescriptor stack;
@ -495,7 +493,7 @@ namespace JsonRandom
return stack;
}
std::vector<CStackBasicDescriptor> loadCreatures(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
std::vector<CStackBasicDescriptor> JsonRandom::loadCreatures(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
{
std::vector<CStackBasicDescriptor> ret;
for (const JsonNode & node : value.Vector())
@ -505,7 +503,7 @@ namespace JsonRandom
return ret;
}
std::vector<RandomStackInfo> evaluateCreatures(const JsonNode & value, const Variables & variables)
std::vector<JsonRandom::RandomStackInfo> JsonRandom::evaluateCreatures(const JsonNode & value, const Variables & variables)
{
std::vector<RandomStackInfo> ret;
for (const JsonNode & node : value.Vector())
@ -519,7 +517,8 @@ namespace JsonRandom
info.minAmount = static_cast<si32>(node["min"].Float());
info.maxAmount = static_cast<si32>(node["max"].Float());
}
const CCreature * crea = VLC->creh->objects[VLC->identifiers()->getIdentifier("creature", node["type"]).value()];
CreatureID creatureID(VLC->identifiers()->getIdentifier("creature", node["type"]).value());
const CCreature * crea = creatureID.toCreature();
info.allowedCreatures.push_back(crea);
if (node["upgradeChance"].Float() > 0)
{
@ -531,7 +530,7 @@ namespace JsonRandom
return ret;
}
std::vector<Bonus> DLL_LINKAGE loadBonuses(const JsonNode & value)
std::vector<Bonus> JsonRandom::loadBonuses(const JsonNode & value)
{
std::vector<Bonus> ret;
for (const JsonNode & entry : value.Vector())
@ -542,6 +541,4 @@ namespace JsonRandom
return ret;
}
}
VCMI_LIB_NAMESPACE_END

View File

@ -11,6 +11,7 @@
#include "GameConstants.h"
#include "ResourceSet.h"
#include "GameCallbackHolder.h"
VCMI_LIB_NAMESPACE_BEGIN
@ -22,10 +23,29 @@ struct Bonus;
struct Component;
class CStackBasicDescriptor;
namespace JsonRandom
class DLL_LINKAGE JsonRandom : public GameCallbackHolder
{
public:
using Variables = std::map<std::string, int>;
private:
template<typename IdentifierType>
std::set<IdentifierType> filterKeys(const JsonNode & value, const std::set<IdentifierType> & valuesSet, const Variables & variables);
template<typename IdentifierType>
std::set<IdentifierType> filterKeysTyped(const JsonNode & value, const std::set<IdentifierType> & valuesSet);
template<typename IdentifierType>
IdentifierType decodeKey(const std::string & modScope, const std::string & value, const Variables & variables);
template<typename IdentifierType>
IdentifierType decodeKey(const JsonNode & value, const Variables & variables);
si32 loadVariable(const std::string & variableGroup, const std::string & value, const Variables & variables, si32 defaultValue);
public:
using GameCallbackHolder::GameCallbackHolder;
struct DLL_LINKAGE RandomStackInfo
{
std::vector<const CCreature *> allowedCreatures;
@ -33,30 +53,30 @@ namespace JsonRandom
si32 maxAmount;
};
DLL_LINKAGE si32 loadValue(const JsonNode & value, CRandomGenerator & rng, const Variables & variables, si32 defaultValue = 0);
si32 loadValue(const JsonNode & value, CRandomGenerator & rng, const Variables & variables, si32 defaultValue = 0);
DLL_LINKAGE TResources loadResources(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
DLL_LINKAGE TResources loadResource(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
DLL_LINKAGE PrimarySkill loadPrimary(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
DLL_LINKAGE std::vector<si32> loadPrimaries(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
DLL_LINKAGE SecondarySkill loadSecondary(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
DLL_LINKAGE std::map<SecondarySkill, si32> loadSecondaries(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
TResources loadResources(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
TResources loadResource(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
PrimarySkill loadPrimary(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
std::vector<si32> loadPrimaries(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
SecondarySkill loadSecondary(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
std::map<SecondarySkill, si32> loadSecondaries(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
DLL_LINKAGE ArtifactID loadArtifact(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
DLL_LINKAGE std::vector<ArtifactID> loadArtifacts(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
ArtifactID loadArtifact(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
std::vector<ArtifactID> loadArtifacts(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
DLL_LINKAGE SpellID loadSpell(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
DLL_LINKAGE std::vector<SpellID> loadSpells(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
SpellID loadSpell(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
std::vector<SpellID> loadSpells(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
DLL_LINKAGE CStackBasicDescriptor loadCreature(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
DLL_LINKAGE std::vector<CStackBasicDescriptor> loadCreatures(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
DLL_LINKAGE std::vector<RandomStackInfo> evaluateCreatures(const JsonNode & value, const Variables & variables);
CStackBasicDescriptor loadCreature(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
std::vector<CStackBasicDescriptor> loadCreatures(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
std::vector<RandomStackInfo> evaluateCreatures(const JsonNode & value, const Variables & variables);
DLL_LINKAGE std::vector<PlayerColor> loadColors(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
DLL_LINKAGE std::vector<HeroTypeID> loadHeroes(const JsonNode & value, CRandomGenerator & rng);
DLL_LINKAGE std::vector<HeroClassID> loadHeroClasses(const JsonNode & value, CRandomGenerator & rng);
std::vector<PlayerColor> loadColors(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
std::vector<HeroTypeID> loadHeroes(const JsonNode & value, CRandomGenerator & rng);
std::vector<HeroClassID> loadHeroClasses(const JsonNode & value, CRandomGenerator & rng);
DLL_LINKAGE std::vector<Bonus> loadBonuses(const JsonNode & value);
}
static std::vector<Bonus> loadBonuses(const JsonNode & value);
};
VCMI_LIB_NAMESPACE_END

View File

@ -18,7 +18,7 @@ VCMI_LIB_NAMESPACE_BEGIN
RiverTypeHandler::RiverTypeHandler()
{
objects.push_back(new RiverType);
objects.push_back(new RiverType());
VLC->generaltexth->registerString("core", objects[0]->getNameTextID(), "");
}

View File

@ -18,7 +18,7 @@ VCMI_LIB_NAMESPACE_BEGIN
RoadTypeHandler::RoadTypeHandler()
{
objects.push_back(new RoadType);
objects.push_back(new RoadType());
VLC->generaltexth->registerString("core", objects[0]->getNameTextID(), "");
}

View File

@ -32,7 +32,7 @@ FactionID PlayerSettings::getCastleValidated() const
{
if (!castle.isValid())
return FactionID(0);
if (castle.getNum() < VLC->townh->size() && VLC->townh->objects[castle.getNum()]->town != nullptr)
if (castle.getNum() < VLC->townh->size() && castle.toEntity(VLC)->hasTown())
return castle;
return FactionID(0);

View File

@ -65,54 +65,54 @@ DLL_LINKAGE void loadDLLClasses(bool onlyEssential)
const ArtifactService * LibClasses::artifacts() const
{
return arth;
return arth.get();
}
const CreatureService * LibClasses::creatures() const
{
return creh;
return creh.get();
}
const FactionService * LibClasses::factions() const
{
return townh;
return townh.get();
}
const HeroClassService * LibClasses::heroClasses() const
{
return &heroh->classes;
return heroclassesh.get();
}
const HeroTypeService * LibClasses::heroTypes() const
{
return heroh;
return heroh.get();
}
#if SCRIPTING_ENABLED
const scripting::Service * LibClasses::scripts() const
{
return scriptHandler;
return scriptHandler.get();
}
#endif
const spells::Service * LibClasses::spells() const
{
return spellh;
return spellh.get();
}
const SkillService * LibClasses::skills() const
{
return skillh;
return skillh.get();
}
const IBonusTypeHandler * LibClasses::getBth() const
{
return bth;
return bth.get();
}
const CIdentifierStorage * LibClasses::identifiers() const
{
return identifiersHandler;
return identifiersHandler.get();
}
const spells::effects::Registry * LibClasses::spellEffects() const
@ -127,17 +127,17 @@ spells::effects::Registry * LibClasses::spellEffects()
const BattleFieldService * LibClasses::battlefields() const
{
return battlefieldsHandler;
return battlefieldsHandler.get();
}
const ObstacleService * LibClasses::obstacles() const
{
return obstacleHandler;
return obstacleHandler.get();
}
const IGameSettings * LibClasses::settings() const
{
return settingsHandler;
return settingsHandler.get();
}
void LibClasses::updateEntity(Metatype metatype, int32_t index, const JsonNode & data)
@ -154,7 +154,7 @@ void LibClasses::updateEntity(Metatype metatype, int32_t index, const JsonNode &
townh->updateEntity(index, data);
break;
case Metatype::HERO_CLASS:
heroh->classes.updateEntity(index, data);
heroclassesh->updateEntity(index, data);
break;
case Metatype::HERO_TYPE:
heroh->updateEntity(index, data);
@ -185,8 +185,8 @@ void LibClasses::loadFilesystem(bool extractArchives)
void LibClasses::loadModFilesystem()
{
CStopWatch loadTime;
modh = new CModHandler();
identifiersHandler = new CIdentifierStorage();
modh = std::make_unique<CModHandler>();
identifiersHandler = std::make_unique<CIdentifierStorage>();
modh->loadMods();
logGlobal->info("\tMod handler: %d ms", loadTime.getDiff());
@ -199,9 +199,9 @@ static void logHandlerLoaded(const std::string & name, CStopWatch & timer)
logGlobal->info("\t\t %s handler: %d ms", name, timer.getDiff());
}
template <class Handler> void createHandler(Handler *&handler, const std::string &name, CStopWatch &timer)
template <class Handler> void createHandler(std::shared_ptr<Handler> & handler, const std::string &name, CStopWatch &timer)
{
handler = new Handler();
handler = std::make_shared<Handler>();
logHandlerLoaded(name, timer);
}
@ -219,6 +219,7 @@ void LibClasses::init(bool onlyEssential)
createHandler(riverTypeHandler, "River", pomtime);
createHandler(terrainTypeHandler, "Terrain", pomtime);
createHandler(heroh, "Hero", pomtime);
createHandler(heroclassesh, "Hero classes", pomtime);
createHandler(arth, "Artifact", pomtime);
createHandler(creh, "Creature", pomtime);
createHandler(townh, "Town", pomtime);
@ -239,77 +240,6 @@ void LibClasses::init(bool onlyEssential)
modh->afterLoad(onlyEssential);
}
void LibClasses::clear()
{
delete heroh;
delete arth;
delete creh;
delete townh;
delete objh;
delete objtypeh;
delete spellh;
delete skillh;
delete modh;
delete bth;
delete tplh;
delete terviewh;
#if SCRIPTING_ENABLED
delete scriptHandler;
#endif
delete battlefieldsHandler;
delete generaltexth;
delete identifiersHandler;
delete obstacleHandler;
delete terrainTypeHandler;
delete riverTypeHandler;
delete roadTypeHandler;
delete settingsHandler;
makeNull();
}
void LibClasses::makeNull()
{
generaltexth = nullptr;
heroh = nullptr;
arth = nullptr;
creh = nullptr;
townh = nullptr;
objh = nullptr;
objtypeh = nullptr;
spellh = nullptr;
skillh = nullptr;
modh = nullptr;
bth = nullptr;
tplh = nullptr;
terviewh = nullptr;
#if SCRIPTING_ENABLED
scriptHandler = nullptr;
#endif
battlefieldsHandler = nullptr;
identifiersHandler = nullptr;
obstacleHandler = nullptr;
terrainTypeHandler = nullptr;
riverTypeHandler = nullptr;
roadTypeHandler = nullptr;
settingsHandler = nullptr;
}
LibClasses::LibClasses()
{
//init pointers to handlers
makeNull();
}
void LibClasses::callWhenDeserializing()
{
//FIXME: check if any of these are needed
//generaltexth = new CGeneralTextHandler();
//generaltexth->load();
//arth->load(true);
//modh->recreateHandlers();
//modh->loadConfigFromFile ("defaultMods"); //TODO: remember last saved config
}
#if SCRIPTING_ENABLED
void LibClasses::scriptsLoaded()
{
@ -317,10 +247,8 @@ void LibClasses::scriptsLoaded()
}
#endif
LibClasses::~LibClasses()
{
clear();
}
LibClasses::LibClasses() = default;
LibClasses::~LibClasses() = default;
std::shared_ptr<CContentHandler> LibClasses::getContent() const
{

View File

@ -16,6 +16,7 @@ VCMI_LIB_NAMESPACE_BEGIN
class CConsoleHandler;
class CArtHandler;
class CHeroHandler;
class CHeroClassHandler;
class CCreatureHandler;
class CSpellHandler;
class CSkillHandler;
@ -47,20 +48,15 @@ namespace scripting
}
#endif
/// Loads and constructs several handlers
class DLL_LINKAGE LibClasses : public Services
class DLL_LINKAGE LibClasses final : public Services
{
CBonusTypeHandler * bth;
std::shared_ptr<CBonusTypeHandler> bth;
void callWhenDeserializing(); //should be called only by serialize !!!
void makeNull(); //sets all handler pointers to null
std::shared_ptr<CContentHandler> getContent() const;
void setContent(std::shared_ptr<CContentHandler> content);
public:
bool IS_AI_ENABLED = false; //unused?
const ArtifactService * artifacts() const override;
const CreatureService * creatures() const override;
const FactionService * factions() const override;
@ -83,35 +79,34 @@ public:
const IBonusTypeHandler * getBth() const; //deprecated
const CIdentifierStorage * identifiers() const;
CArtHandler * arth;
CHeroHandler * heroh;
CCreatureHandler * creh;
CSpellHandler * spellh;
CSkillHandler * skillh;
CObjectHandler * objh;
CObjectClassesHandler * objtypeh;
CTownHandler * townh;
CGeneralTextHandler * generaltexth;
CModHandler * modh;
std::shared_ptr<CArtHandler> arth;
std::shared_ptr<CHeroHandler> heroh;
std::shared_ptr<CHeroClassHandler> heroclassesh;
std::shared_ptr<CCreatureHandler> creh;
std::shared_ptr<CSpellHandler> spellh;
std::shared_ptr<CSkillHandler> skillh;
std::shared_ptr<CObjectHandler> objh;
std::shared_ptr<CObjectClassesHandler> objtypeh;
std::shared_ptr<CTownHandler> townh;
std::shared_ptr<CGeneralTextHandler> generaltexth;
std::shared_ptr<CModHandler> modh;
std::shared_ptr<TerrainTypeHandler> terrainTypeHandler;
std::shared_ptr<RoadTypeHandler> roadTypeHandler;
std::shared_ptr<RiverTypeHandler> riverTypeHandler;
std::shared_ptr<CIdentifierStorage> identifiersHandler;
std::shared_ptr<CTerrainViewPatternConfig> terviewh;
std::shared_ptr<CRmgTemplateStorage> tplh;
std::shared_ptr<BattleFieldHandler> battlefieldsHandler;
std::shared_ptr<ObstacleHandler> obstacleHandler;
std::shared_ptr<GameSettings> settingsHandler;
TerrainTypeHandler * terrainTypeHandler;
RoadTypeHandler * roadTypeHandler;
RiverTypeHandler * riverTypeHandler;
CIdentifierStorage * identifiersHandler;
CTerrainViewPatternConfig * terviewh;
CRmgTemplateStorage * tplh;
BattleFieldHandler * battlefieldsHandler;
ObstacleHandler * obstacleHandler;
GameSettings * settingsHandler;
#if SCRIPTING_ENABLED
scripting::ScriptHandler * scriptHandler;
std::shared_ptr<scripting::ScriptHandler> scriptHandler;
#endif
LibClasses(); //c-tor, loads .lods and NULLs handlers
~LibClasses();
void init(bool onlyEssential); //uses standard config file
void clear(); //deletes all handlers and its data
// basic initialization. should be called before init(). Can also extract original H3 archives
void loadFilesystem(bool extractArchives);

View File

@ -240,7 +240,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
{
try
{
RangeGenerator obidgen(0, VLC->obstacleHandler->objects.size() - 1, ourRand);
RangeGenerator obidgen(0, VLC->obstacleHandler->size() - 1, ourRand);
auto obstPtr = std::make_shared<CObstacleInstance>();
obstPtr->obstacleType = CObstacleInstance::ABSOLUTE_OBSTACLE;
obstPtr->ID = obidgen.getSuchNumber(appropriateAbsoluteObstacle);
@ -262,7 +262,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
{
while(tilesToBlock > 0)
{
RangeGenerator obidgen(0, VLC->obstacleHandler->objects.size() - 1, ourRand);
RangeGenerator obidgen(0, VLC->obstacleHandler->size() - 1, ourRand);
auto tileAccessibility = curB->getAccesibility();
const int obid = obidgen.getSuchNumber(appropriateUsualObstacle);
const ObstacleInfo &obi = *Obstacle(obid).getInfo();
@ -1009,7 +1009,7 @@ scripting::Pool * BattleInfo::getContextPool() const
{
//this is real battle, use global scripting context pool
//TODO: make this line not ugly
return IObjectInterface::cb->getGlobalContextPool();
return battleGetFightingHero(0)->cb->getGlobalContextPool();
}
#endif

View File

@ -401,10 +401,9 @@ PlayerColor CBattleInfoEssentials::battleGetOwner(const battle::Unit * unit) con
PlayerColor initialOwner = getBattle()->getSidePlayer(unit->unitSide());
static CSelector selector = Selector::type()(BonusType::HYPNOTIZED);
static std::string cachingString = "type_103s-1";
static const CSelector selector = Selector::type()(BonusType::HYPNOTIZED);
if(unit->hasBonus(selector, cachingString))
if(unit->hasBonus(selector))
return otherPlayer(initialOwner);
else
return initialOwner;

View File

@ -10,7 +10,6 @@
#include "StdInc.h"
#include "Bonus.h"
#include "CBonusSystemNode.h"
#include "Limiters.h"
#include "Updaters.h"
#include "Propagators.h"

View File

@ -15,39 +15,39 @@ VCMI_LIB_NAMESPACE_BEGIN
namespace Selector
{
DLL_LINKAGE CSelectFieldEqual<BonusType> & type()
DLL_LINKAGE const CSelectFieldEqual<BonusType> & type()
{
static CSelectFieldEqual<BonusType> stype(&Bonus::type);
static const CSelectFieldEqual<BonusType> stype(&Bonus::type);
return stype;
}
DLL_LINKAGE CSelectFieldEqual<BonusSubtypeID> & subtype()
DLL_LINKAGE const CSelectFieldEqual<BonusSubtypeID> & subtype()
{
static CSelectFieldEqual<BonusSubtypeID> ssubtype(&Bonus::subtype);
static const CSelectFieldEqual<BonusSubtypeID> ssubtype(&Bonus::subtype);
return ssubtype;
}
DLL_LINKAGE CSelectFieldEqual<CAddInfo> & info()
DLL_LINKAGE const CSelectFieldEqual<CAddInfo> & info()
{
static CSelectFieldEqual<CAddInfo> sinfo(&Bonus::additionalInfo);
static const CSelectFieldEqual<CAddInfo> sinfo(&Bonus::additionalInfo);
return sinfo;
}
DLL_LINKAGE CSelectFieldEqual<BonusSource> & sourceType()
DLL_LINKAGE const CSelectFieldEqual<BonusSource> & sourceType()
{
static CSelectFieldEqual<BonusSource> ssourceType(&Bonus::source);
static const CSelectFieldEqual<BonusSource> ssourceType(&Bonus::source);
return ssourceType;
}
DLL_LINKAGE CSelectFieldEqual<BonusSource> & targetSourceType()
DLL_LINKAGE const CSelectFieldEqual<BonusSource> & targetSourceType()
{
static CSelectFieldEqual<BonusSource> ssourceType(&Bonus::targetSourceType);
static const CSelectFieldEqual<BonusSource> ssourceType(&Bonus::targetSourceType);
return ssourceType;
}
DLL_LINKAGE CSelectFieldEqual<BonusLimitEffect> & effectRange()
DLL_LINKAGE const CSelectFieldEqual<BonusLimitEffect> & effectRange()
{
static CSelectFieldEqual<BonusLimitEffect> seffectRange(&Bonus::effectRange);
static const CSelectFieldEqual<BonusLimitEffect> seffectRange(&Bonus::effectRange);
return seffectRange;
}

View File

@ -125,12 +125,12 @@ public:
namespace Selector
{
extern DLL_LINKAGE CSelectFieldEqual<BonusType> & type();
extern DLL_LINKAGE CSelectFieldEqual<BonusSubtypeID> & subtype();
extern DLL_LINKAGE CSelectFieldEqual<CAddInfo> & info();
extern DLL_LINKAGE CSelectFieldEqual<BonusSource> & sourceType();
extern DLL_LINKAGE CSelectFieldEqual<BonusSource> & targetSourceType();
extern DLL_LINKAGE CSelectFieldEqual<BonusLimitEffect> & effectRange();
extern DLL_LINKAGE const CSelectFieldEqual<BonusType> & type();
extern DLL_LINKAGE const CSelectFieldEqual<BonusSubtypeID> & subtype();
extern DLL_LINKAGE const CSelectFieldEqual<CAddInfo> & info();
extern DLL_LINKAGE const CSelectFieldEqual<BonusSource> & sourceType();
extern DLL_LINKAGE const CSelectFieldEqual<BonusSource> & targetSourceType();
extern DLL_LINKAGE const CSelectFieldEqual<BonusLimitEffect> & effectRange();
extern DLL_LINKAGE CWillLastTurns turns;
extern DLL_LINKAGE CWillLastDays days;

View File

@ -20,18 +20,25 @@ VCMI_LIB_NAMESPACE_BEGIN
std::atomic<int64_t> CBonusSystemNode::treeChanged(1);
constexpr bool CBonusSystemNode::cachingEnabled = true;
#define FOREACH_PARENT(pname) TNodes lparents; getParents(lparents); for(CBonusSystemNode *pname : lparents)
#define FOREACH_RED_CHILD(pname) TNodes lchildren; getRedChildren(lchildren); for(CBonusSystemNode *pname : lchildren)
std::shared_ptr<Bonus> CBonusSystemNode::getLocalBonus(const CSelector & selector)
{
auto ret = bonuses.getFirst(selector);
if(ret)
return ret;
return nullptr;
}
std::shared_ptr<Bonus> CBonusSystemNode::getBonusLocalFirst(const CSelector & selector)
std::shared_ptr<const Bonus> CBonusSystemNode::getFirstBonus(const CSelector & selector) const
{
auto ret = bonuses.getFirst(selector);
if(ret)
return ret;
FOREACH_PARENT(pname)
TCNodes lparents;
getParents(lparents);
for(const CBonusSystemNode *pname : lparents)
{
ret = pname->getBonusLocalFirst(selector);
ret = pname->getFirstBonus(selector);
if (ret)
return ret;
}
@ -39,28 +46,15 @@ std::shared_ptr<Bonus> CBonusSystemNode::getBonusLocalFirst(const CSelector & se
return nullptr;
}
std::shared_ptr<const Bonus> CBonusSystemNode::getBonusLocalFirst(const CSelector & selector) const
{
return (const_cast<CBonusSystemNode*>(this))->getBonusLocalFirst(selector);
}
void CBonusSystemNode::getParents(TCNodes & out) const /*retrieves list of parent nodes (nodes to inherit bonuses from) */
{
for(const auto * elem : parents)
for(const auto * elem : parentsToInherit)
out.insert(elem);
}
void CBonusSystemNode::getParents(TNodes &out)
{
for (auto * elem : parents)
{
out.insert(elem);
}
}
void CBonusSystemNode::getAllParents(TCNodes & out) const //retrieves list of parent nodes (nodes to inherit bonuses from)
{
for(auto * parent : parents)
for(auto * parent : parentsToInherit)
{
out.insert(parent);
parent->getAllParents(out);
@ -227,39 +221,6 @@ CBonusSystemNode::CBonusSystemNode(ENodeTypes NodeType):
{
}
CBonusSystemNode::CBonusSystemNode(CBonusSystemNode && other) noexcept:
bonuses(std::move(other.bonuses)),
exportedBonuses(std::move(other.exportedBonuses)),
nodeType(other.nodeType),
cachedLast(0),
isHypotheticNode(other.isHypotheticNode)
{
std::swap(parents, other.parents);
std::swap(children, other.children);
//fixing bonus tree without recalculation
if(!isHypothetic())
{
for(CBonusSystemNode * n : parents)
{
n->children -= &other;
n->children.push_back(this);
}
}
for(CBonusSystemNode * n : children)
{
n->parents -= &other;
n->parents.push_back(this);
}
//cache ignored
//cachedBonuses
//cachedRequests
}
CBonusSystemNode::~CBonusSystemNode()
{
detachFromAll();
@ -273,14 +234,14 @@ CBonusSystemNode::~CBonusSystemNode()
void CBonusSystemNode::attachTo(CBonusSystemNode & parent)
{
assert(!vstd::contains(parents, &parent));
parents.push_back(&parent);
assert(!vstd::contains(parentsToPropagate, &parent));
parentsToPropagate.push_back(&parent);
attachToSource(parent);
if(!isHypothetic())
{
if(parent.actsAsBonusSourceOnly())
parent.newRedDescendant(*this);
else
if(!parent.actsAsBonusSourceOnly())
newRedDescendant(parent);
parent.newChildAttached(*this);
@ -289,21 +250,35 @@ void CBonusSystemNode::attachTo(CBonusSystemNode & parent)
CBonusSystemNode::treeHasChanged();
}
void CBonusSystemNode::detachFrom(CBonusSystemNode & parent)
void CBonusSystemNode::attachToSource(const CBonusSystemNode & parent)
{
assert(vstd::contains(parents, &parent));
assert(!vstd::contains(parentsToInherit, &parent));
parentsToInherit.push_back(&parent);
if(!isHypothetic())
{
if(parent.actsAsBonusSourceOnly())
parent.removedRedDescendant(*this);
else
parent.newRedDescendant(*this);
}
CBonusSystemNode::treeHasChanged();
}
void CBonusSystemNode::detachFrom(CBonusSystemNode & parent)
{
assert(vstd::contains(parentsToPropagate, &parent));
if(!isHypothetic())
{
if(!parent.actsAsBonusSourceOnly())
removedRedDescendant(parent);
}
if (vstd::contains(parents, &parent))
detachFromSource(parent);
if (vstd::contains(parentsToPropagate, &parent))
{
parents -= &parent;
parentsToPropagate -= &parent;
}
else
{
@ -318,6 +293,30 @@ void CBonusSystemNode::detachFrom(CBonusSystemNode & parent)
CBonusSystemNode::treeHasChanged();
}
void CBonusSystemNode::detachFromSource(const CBonusSystemNode & parent)
{
assert(vstd::contains(parentsToInherit, &parent));
if(!isHypothetic())
{
if(parent.actsAsBonusSourceOnly())
parent.removedRedDescendant(*this);
}
if (vstd::contains(parentsToInherit, &parent))
{
parentsToInherit -= &parent;
}
else
{
logBonus->error("Error on Detach. Node %s (nodeType=%d) has not parent %s (nodeType=%d)"
, nodeShortInfo(), nodeType, parent.nodeShortInfo(), parent.nodeType);
}
CBonusSystemNode::treeHasChanged();
}
void CBonusSystemNode::removeBonusesRecursive(const CSelector & s)
{
removeBonuses(s);
@ -405,8 +404,10 @@ void CBonusSystemNode::propagateBonus(const std::shared_ptr<Bonus> & b, const CB
logBonus->trace("#$# %s #propagated to# %s", propagated->Description(), nodeName());
}
FOREACH_RED_CHILD(child)
child->propagateBonus(b, source);
TNodes lchildren;
getRedChildren(lchildren);
for(CBonusSystemNode *pname : lchildren)
pname->propagateBonus(b, source);
}
void CBonusSystemNode::unpropagateBonus(const std::shared_ptr<Bonus> & b)
@ -417,8 +418,10 @@ void CBonusSystemNode::unpropagateBonus(const std::shared_ptr<Bonus> & b)
logBonus->trace("#$# %s #is no longer propagated to# %s", b->Description(), nodeName());
}
FOREACH_RED_CHILD(child)
child->unpropagateBonus(b);
TNodes lchildren;
getRedChildren(lchildren);
for(CBonusSystemNode *pname : lchildren)
pname->unpropagateBonus(b);
}
void CBonusSystemNode::newChildAttached(CBonusSystemNode & child)
@ -440,13 +443,16 @@ void CBonusSystemNode::childDetached(CBonusSystemNode & child)
void CBonusSystemNode::detachFromAll()
{
while(!parents.empty())
detachFrom(*parents.front());
while(!parentsToPropagate.empty())
detachFrom(*parentsToPropagate.front());
while(!parentsToInherit.empty())
detachFromSource(*parentsToInherit.front());
}
bool CBonusSystemNode::isIndependentNode() const
{
return parents.empty() && children.empty();
return parentsToInherit.empty() && parentsToPropagate.empty() && children.empty();
}
std::string CBonusSystemNode::nodeName() const
@ -464,12 +470,13 @@ std::string CBonusSystemNode::nodeShortInfo() const
void CBonusSystemNode::deserializationFix()
{
exportBonuses();
}
void CBonusSystemNode::getRedParents(TNodes & out)
void CBonusSystemNode::getRedParents(TCNodes & out) const
{
FOREACH_PARENT(pname)
TCNodes lparents;
getParents(lparents);
for(const CBonusSystemNode *pname : lparents)
{
if(pname->actsAsBonusSourceOnly())
{
@ -479,7 +486,7 @@ void CBonusSystemNode::getRedParents(TNodes & out)
if(!actsAsBonusSourceOnly())
{
for(CBonusSystemNode *child : children)
for(const CBonusSystemNode *child : children)
{
out.insert(child);
}
@ -488,7 +495,7 @@ void CBonusSystemNode::getRedParents(TNodes & out)
void CBonusSystemNode::getRedChildren(TNodes &out)
{
FOREACH_PARENT(pname)
for(CBonusSystemNode *pname : parentsToPropagate)
{
if(!pname->actsAsBonusSourceOnly())
{
@ -505,17 +512,17 @@ void CBonusSystemNode::getRedChildren(TNodes &out)
}
}
void CBonusSystemNode::newRedDescendant(CBonusSystemNode & descendant)
void CBonusSystemNode::newRedDescendant(CBonusSystemNode & descendant) const
{
for(const auto & b : exportedBonuses)
{
if(b->propagator)
descendant.propagateBonus(b, *this);
}
TNodes redParents;
TCNodes redParents;
getRedAncestors(redParents); //get all red parents recursively
for(auto * parent : redParents)
for(const auto * parent : redParents)
{
for(const auto & b : parent->exportedBonuses)
{
@ -525,13 +532,13 @@ void CBonusSystemNode::newRedDescendant(CBonusSystemNode & descendant)
}
}
void CBonusSystemNode::removedRedDescendant(CBonusSystemNode & descendant)
void CBonusSystemNode::removedRedDescendant(CBonusSystemNode & descendant) const
{
for(const auto & b : exportedBonuses)
if(b->propagator)
descendant.unpropagateBonus(b);
TNodes redParents;
TCNodes redParents;
getRedAncestors(redParents); //get all red parents recursively
for(auto * parent : redParents)
@ -542,14 +549,14 @@ void CBonusSystemNode::removedRedDescendant(CBonusSystemNode & descendant)
}
}
void CBonusSystemNode::getRedAncestors(TNodes &out)
void CBonusSystemNode::getRedAncestors(TCNodes &out) const
{
getRedParents(out);
TNodes redParents;
TCNodes redParents;
getRedParents(redParents);
for(CBonusSystemNode * parent : redParents)
for(const CBonusSystemNode * parent : redParents)
parent->getRedAncestors(out);
}
@ -574,9 +581,9 @@ CBonusSystemNode::ENodeTypes CBonusSystemNode::getNodeType() const
return nodeType;
}
const TNodesVector& CBonusSystemNode::getParentNodes() const
const TCNodesVector& CBonusSystemNode::getParentNodes() const
{
return parents;
return parentsToInherit;
}
void CBonusSystemNode::setNodeType(CBonusSystemNode::ENodeTypes type)

View File

@ -19,6 +19,7 @@ VCMI_LIB_NAMESPACE_BEGIN
using TNodes = std::set<CBonusSystemNode *>;
using TCNodes = std::set<const CBonusSystemNode *>;
using TNodesVector = std::vector<CBonusSystemNode *>;
using TCNodesVector = std::vector<const CBonusSystemNode *>;
class DLL_LINKAGE CBonusSystemNode : public virtual IBonusBearer, public boost::noncopyable
{
@ -33,7 +34,8 @@ private:
BonusList bonuses; //wielded bonuses (local or up-propagated here)
BonusList exportedBonuses; //bonuses coming from this node (wielded or propagated away)
TNodesVector parents; //parents -> we inherit bonuses from them, we may attach our bonuses to them
TCNodesVector parentsToInherit; // we inherit bonuses from them
TNodesVector parentsToPropagate; // we may attach our bonuses to them
TNodesVector children;
ENodeTypes nodeType;
@ -54,8 +56,8 @@ private:
TConstBonusListPtr getAllBonusesWithoutCaching(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = nullptr) const;
std::shared_ptr<Bonus> getUpdatedBonus(const std::shared_ptr<Bonus> & b, const TUpdaterPtr & updater) const;
void getRedParents(TNodes &out); //retrieves list of red parent nodes (nodes bonuses propagate from)
void getRedAncestors(TNodes &out);
void getRedParents(TCNodes &out) const; //retrieves list of red parent nodes (nodes bonuses propagate from)
void getRedAncestors(TCNodes &out) const;
void getRedChildren(TNodes &out);
void getAllParents(TCNodes & out) const;
@ -66,8 +68,8 @@ private:
void unpropagateBonus(const std::shared_ptr<Bonus> & b);
bool actsAsBonusSourceOnly() const;
void newRedDescendant(CBonusSystemNode & descendant); //propagation needed
void removedRedDescendant(CBonusSystemNode & descendant); //de-propagation needed
void newRedDescendant(CBonusSystemNode & descendant) const; //propagation needed
void removedRedDescendant(CBonusSystemNode & descendant) const; //de-propagation needed
std::string nodeShortInfo() const;
@ -80,21 +82,23 @@ protected:
public:
explicit CBonusSystemNode(bool isHypotetic = false);
explicit CBonusSystemNode(ENodeTypes NodeType);
CBonusSystemNode(CBonusSystemNode && other) noexcept;
virtual ~CBonusSystemNode();
void limitBonuses(const BonusList &allBonuses, BonusList &out) const; //out will bo populed with bonuses that are not limited here
TBonusListPtr limitBonuses(const BonusList &allBonuses) const; //same as above, returns out by val for convienence
TConstBonusListPtr getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = nullptr, const std::string &cachingStr = "") const override;
void getParents(TCNodes &out) const; //retrieves list of parent nodes (nodes to inherit bonuses from),
std::shared_ptr<const Bonus> getBonusLocalFirst(const CSelector & selector) const;
//non-const interface
void getParents(TNodes &out); //retrieves list of parent nodes (nodes to inherit bonuses from)
std::shared_ptr<Bonus> getBonusLocalFirst(const CSelector & selector);
/// Returns first bonus matching selector
std::shared_ptr<const Bonus> getFirstBonus(const CSelector & selector) const;
/// Provides write access to first bonus from this node that matches selector
std::shared_ptr<Bonus> getLocalBonus(const CSelector & selector);
void attachTo(CBonusSystemNode & parent);
void attachToSource(const CBonusSystemNode & parent);
void detachFrom(CBonusSystemNode & parent);
void detachFromSource(const CBonusSystemNode & parent);
void detachFromAll();
virtual void addNewBonus(const std::shared_ptr<Bonus>& b);
void accumulateBonus(const std::shared_ptr<Bonus>& b); //add value of bonus with same type/subtype or create new
@ -115,7 +119,7 @@ public:
const BonusList & getExportedBonusList() const;
CBonusSystemNode::ENodeTypes getNodeType() const;
void setNodeType(CBonusSystemNode::ENodeTypes type);
const TNodesVector & getParentNodes() const;
const TCNodesVector & getParentNodes() const;
static void treeHasChanged();
@ -128,11 +132,9 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
// h & bonuses;
h & nodeType;
h & exportedBonuses;
BONUS_TREE_DESERIALIZATION_FIX
//h & parents & children;
}
friend class CBonusProxy;

View File

@ -10,7 +10,7 @@
#include "StdInc.h"
#include "CBonusSystemNode.h"
#include "IBonusBearer.h"
#include "BonusList.h"
VCMI_LIB_NAMESPACE_BEGIN

View File

@ -11,6 +11,7 @@
#include "CampaignState.h"
#include "../JsonNode.h"
#include "../Point.h"
#include "../filesystem/ResourcePath.h"
#include "../VCMI_Lib.h"
#include "../CGeneralTextHandler.h"
@ -224,7 +225,7 @@ std::set<HeroTypeID> CampaignState::getReservedHeroes() const
const CGHeroInstance * CampaignState::strongestHero(CampaignScenarioID scenarioId, const PlayerColor & owner) const
{
std::function<bool(const JsonNode & node)> isOwned = [owner](const JsonNode & node)
std::function<bool(const JsonNode & node)> isOwned = [&](const JsonNode & node)
{
auto * h = CampaignState::crossoverDeserialize(node, nullptr);
bool result = h->tempOwner == owner;
@ -316,7 +317,7 @@ std::optional<ui8> CampaignState::getBonusID(CampaignScenarioID which) const
return chosenCampaignBonuses.at(which);
}
std::unique_ptr<CMap> CampaignState::getMap(CampaignScenarioID scenarioId) const
std::unique_ptr<CMap> CampaignState::getMap(CampaignScenarioID scenarioId, IGameCallback * cb) const
{
// FIXME: there is certainly better way to handle maps inside campaigns
if(scenarioId == CampaignScenarioID::NONE)
@ -327,7 +328,7 @@ std::unique_ptr<CMap> CampaignState::getMap(CampaignScenarioID scenarioId) const
boost::to_lower(scenarioName);
scenarioName += ':' + std::to_string(scenarioId.getNum());
const auto & mapContent = mapPieces.find(scenarioId)->second;
return mapService.loadMap(mapContent.data(), mapContent.size(), scenarioName, getModName(), getEncoding());
return mapService.loadMap(mapContent.data(), mapContent.size(), scenarioName, getModName(), getEncoding(), cb);
}
std::unique_ptr<CMapHeader> CampaignState::getMapHeader(CampaignScenarioID scenarioId) const
@ -355,7 +356,7 @@ std::shared_ptr<CMapInfo> CampaignState::getMapInfo(CampaignScenarioID scenarioI
return mapInfo;
}
JsonNode CampaignState::crossoverSerialize(CGHeroInstance * hero)
JsonNode CampaignState::crossoverSerialize(CGHeroInstance * hero) const
{
JsonNode node;
JsonSerializer handler(nullptr, node);
@ -363,10 +364,10 @@ JsonNode CampaignState::crossoverSerialize(CGHeroInstance * hero)
return node;
}
CGHeroInstance * CampaignState::crossoverDeserialize(const JsonNode & node, CMap * map)
CGHeroInstance * CampaignState::crossoverDeserialize(const JsonNode & node, CMap * map) const
{
JsonDeserializer handler(nullptr, const_cast<JsonNode&>(node));
auto * hero = new CGHeroInstance();
auto * hero = new CGHeroInstance(map->cb);
hero->ID = Obj::HERO;
hero->serializeJsonOptions(handler);
if (map)

View File

@ -27,6 +27,7 @@ class CMapHeader;
class CMapInfo;
class JsonNode;
class Point;
class IGameCallback;
class DLL_LINKAGE CampaignRegions
{
@ -277,7 +278,7 @@ public:
/// Returns true if all available scenarios have been completed and campaign is finished
bool isCampaignFinished() const;
std::unique_ptr<CMap> getMap(CampaignScenarioID scenarioId) const;
std::unique_ptr<CMap> getMap(CampaignScenarioID scenarioId, IGameCallback * cb) const;
std::unique_ptr<CMapHeader> getMapHeader(CampaignScenarioID scenarioId) const;
std::shared_ptr<CMapInfo> getMapInfo(CampaignScenarioID scenarioId) const;
@ -298,8 +299,8 @@ public:
/// May return empty JsonNode if such hero was not found
const JsonNode & getHeroByType(HeroTypeID heroID) const;
static JsonNode crossoverSerialize(CGHeroInstance * hero);
static CGHeroInstance * crossoverDeserialize(const JsonNode & node, CMap * map);
JsonNode crossoverSerialize(CGHeroInstance * hero) const;
CGHeroInstance * crossoverDeserialize(const JsonNode & node, CMap * map) const;
std::string campaignSet;

View File

@ -151,6 +151,16 @@ std::string HeroClassID::entityType()
return "heroClass";
}
const CHeroClass * HeroClassID::toHeroClass() const
{
return dynamic_cast<const CHeroClass*>(toEntity(VLC));
}
const HeroClass * HeroClassID::toEntity(const Services * services) const
{
return services->heroClasses()->getByIndex(num);
}
si32 ObjectInstanceID::decode(const std::string & identifier)
{
return std::stoi(identifier);

View File

@ -21,6 +21,8 @@ class Creature;
class CreatureService;
class HeroType;
class CHero;
class CHeroClass;
class HeroClass;
class HeroTypeService;
class Faction;
class Skill;
@ -81,6 +83,9 @@ public:
DLL_LINKAGE static si32 decode(const std::string & identifier);
DLL_LINKAGE static std::string encode(const si32 index);
static std::string entityType();
const CHeroClass * toHeroClass() const;
const HeroClass * toEntity(const Services * services) const;
};
class DLL_LINKAGE HeroTypeID : public EntityIdentifier<HeroTypeID>

View File

@ -36,6 +36,8 @@
#include "../mapObjectConstructors/DwellingInstanceConstructor.h"
#include "../mapObjects/CGHeroInstance.h"
#include "../mapObjects/CGTownInstance.h"
#include "../mapObjects/CQuest.h"
#include "../mapObjects/MiscObjects.h"
#include "../mapping/CMap.h"
#include "../mapping/CMapEditManager.h"
#include "../mapping/CMapService.h"
@ -97,7 +99,7 @@ HeroTypeID CGameState::pickUnusedHeroTypeRandomly(const PlayerColor & owner)
const PlayerSettings &ps = scenarioOps->getIthPlayersSettings(owner);
for(const HeroTypeID & hid : getUnusedAllowedHeroes())
{
if(VLC->heroh->objects[hid.getNum()]->heroClass->faction == ps.castle)
if(hid.toHeroType()->heroClass->faction == ps.castle)
factionHeroes.push_back(hid);
else
otherHeroes.push_back(hid);
@ -169,14 +171,16 @@ CGameState::~CGameState()
initialOpts.dellNull();
}
void CGameState::preInit(Services * services)
void CGameState::preInit(Services * newServices, IGameCallback * newCallback)
{
this->services = services;
services = newServices;
callback = newCallback;
}
void CGameState::init(const IMapService * mapService, StartInfo * si, Load::ProgressAccumulator & progressTracking, bool allowSavingRandomMap)
{
preInitAuto();
assert(services);
assert(callback);
logGlobal->info("\tUsing random seed: %d", si->seedToBeUsed);
getRandomGenerator().setSeed(si->seedToBeUsed);
scenarioOps = CMemorySerializer::deepCopy(*si).release();
@ -224,7 +228,7 @@ void CGameState::init(const IMapService * mapService, StartInfo * si, Load::Prog
for(auto & elem : teams)
{
CGObelisk::visited[elem.first] = 0;
map->obelisksVisited[elem.first] = 0;
}
logGlobal->debug("\tChecking objectives");
@ -284,21 +288,13 @@ void CGameState::updateEntity(Metatype metatype, int32_t index, const JsonNode &
void CGameState::updateOnLoad(StartInfo * si)
{
preInitAuto();
assert(services);
assert(callback);
scenarioOps->playerInfos = si->playerInfos;
for(auto & i : si->playerInfos)
gs->players[i.first].human = i.second.isControlledByHuman();
}
void CGameState::preInitAuto()
{
if(services == nullptr)
{
logGlobal->error("Game state preinit missing");
preInit(VLC);
}
}
void CGameState::initNewGame(const IMapService * mapService, bool allowSavingRandomMap, Load::ProgressAccumulator & progressTracking)
{
if(scenarioOps->createRandomMap())
@ -307,7 +303,7 @@ void CGameState::initNewGame(const IMapService * mapService, bool allowSavingRan
CStopWatch sw;
// Gen map
CMapGenerator mapGenerator(*scenarioOps->mapGenOptions, scenarioOps->seedToBeUsed);
CMapGenerator mapGenerator(*scenarioOps->mapGenOptions, callback, scenarioOps->seedToBeUsed);
progressTracking.include(mapGenerator);
std::unique_ptr<CMap> randomMap = mapGenerator.generate();
@ -370,7 +366,7 @@ void CGameState::initNewGame(const IMapService * mapService, bool allowSavingRan
{
logGlobal->info("Open map file: %s", scenarioOps->mapname);
const ResourcePath mapURI(scenarioOps->mapname, EResType::MAP);
map = mapService->loadMap(mapURI).release();
map = mapService->loadMap(mapURI, callback).release();
}
}
@ -561,7 +557,7 @@ void CGameState::placeStartingHero(const PlayerColor & playerColor, const HeroTy
}
auto handler = VLC->objtypeh->getHandlerFor(Obj::HERO, heroTypeId.toHeroType()->heroClass->getIndex());
CGObjectInstance * obj = handler->create(handler->getTemplates().front());
CGObjectInstance * obj = handler->create(callback, handler->getTemplates().front());
CGHeroInstance * hero = dynamic_cast<CGHeroInstance *>(obj);
hero->ID = Obj::HERO;
@ -635,7 +631,7 @@ void CGameState::initHeroes()
if (tile.terType->isWater())
{
auto handler = VLC->objtypeh->getHandlerFor(Obj::BOAT, hero->getBoatType().getNum());
CGBoat * boat = dynamic_cast<CGBoat*>(handler->create());
auto boat = dynamic_cast<CGBoat*>(handler->create(callback, nullptr));
handler->configureObject(boat, gs->getRandomGenerator());
boat->pos = hero->pos;
@ -673,7 +669,7 @@ void CGameState::initHeroes()
for(const HeroTypeID & htype : heroesToCreate) //all not used allowed heroes go with default state into the pool
{
auto * vhi = new CGHeroInstance();
auto * vhi = new CGHeroInstance(callback);
vhi->initHero(getRandomGenerator(), htype);
int typeID = htype.getNum();
@ -772,11 +768,11 @@ void CGameState::initTowns()
if (campaign)
campaign->initTowns();
CGTownInstance::universitySkills.clear();
CGTownInstance::universitySkills.push_back(SecondarySkill(SecondarySkill::FIRE_MAGIC));
CGTownInstance::universitySkills.push_back(SecondarySkill(SecondarySkill::AIR_MAGIC));
CGTownInstance::universitySkills.push_back(SecondarySkill(SecondarySkill::WATER_MAGIC));
CGTownInstance::universitySkills.push_back(SecondarySkill(SecondarySkill::EARTH_MAGIC));
map->townUniversitySkills.clear();
map->townUniversitySkills.push_back(SecondarySkill(SecondarySkill::FIRE_MAGIC));
map->townUniversitySkills.push_back(SecondarySkill(SecondarySkill::AIR_MAGIC));
map->townUniversitySkills.push_back(SecondarySkill(SecondarySkill::WATER_MAGIC));
map->townUniversitySkills.push_back(SecondarySkill(SecondarySkill::EARTH_MAGIC));
for (auto & elem : map->towns)
{
@ -936,7 +932,7 @@ void CGameState::initMapObjects()
}
}
}
CGSubterraneanGate::postInit(); //pairing subterranean gates
CGSubterraneanGate::postInit(callback); //pairing subterranean gates
map->calculateGuardingGreaturePositions(); //calculate once again when all the guards are placed and initialized
}
@ -1208,7 +1204,7 @@ int3 CGameState::guardingCreaturePosition (int3 pos) const
void CGameState::updateRumor()
{
static std::vector<RumorState::ERumorType> rumorTypes = {RumorState::TYPE_MAP, RumorState::TYPE_SPECIAL, RumorState::TYPE_RAND, RumorState::TYPE_RAND};
static const std::vector<RumorState::ERumorType> rumorTypes = {RumorState::TYPE_MAP, RumorState::TYPE_SPECIAL, RumorState::TYPE_RAND, RumorState::TYPE_RAND};
std::vector<RumorState::ERumorTypeSpecial> sRumorTypes = {
RumorState::RUMOR_OBELISKS, RumorState::RUMOR_ARTIFACTS, RumorState::RUMOR_ARMY, RumorState::RUMOR_INCOME};
if(map->grailPos.valid()) // Grail should always be on map, but I had related crash I didn't manage to reproduce
@ -1722,10 +1718,10 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level)
}
if(level >= 3) //obelisks found
{
auto getObeliskVisited = [](const TeamID & t)
auto getObeliskVisited = [&](const TeamID & t)
{
if(CGObelisk::visited.count(t))
return CGObelisk::visited[t];
if(map->obelisksVisited.count(t))
return map->obelisksVisited[t];
else
return ui8(0);
};
@ -1928,14 +1924,6 @@ TeamState::TeamState()
fogOfWarMap = std::make_unique<boost::multi_array<ui8, 3>>();
}
TeamState::TeamState(TeamState && other) noexcept:
CBonusSystemNode(std::move(other)),
id(other.id)
{
std::swap(players, other.players);
std::swap(fogOfWarMap, other.fogOfWarMap);
}
CRandomGenerator & CGameState::getRandomGenerator()
{
return rand;

View File

@ -97,10 +97,12 @@ public:
/// list of players currently making turn. Usually - just one, except for simturns
std::set<PlayerColor> actingPlayers;
IGameCallback * callback;
CGameState();
virtual ~CGameState();
void preInit(Services * services);
void preInit(Services * services, IGameCallback * callback);
void init(const IMapService * mapService, StartInfo * si, Load::ProgressAccumulator &, bool allowSavingRandomMap = true);
void updateOnLoad(StartInfo * si);
@ -193,7 +195,6 @@ public:
private:
// ----- initialization -----
void preInitAuto();
void initNewGame(const IMapService * mapService, bool allowSavingRandomMap, Load::ProgressAccumulator & progressTracking);
void checkMapChecksum();
void initGlobalBonuses();

View File

@ -16,6 +16,7 @@
#include "../campaign/CampaignState.h"
#include "../mapping/CMapEditManager.h"
#include "../mapObjects/CGHeroInstance.h"
#include "../mapObjects/CGTownInstance.h"
#include "../networkPacks/ArtifactLocation.h"
#include "../mapObjectConstructors/AObjectTypeHandler.h"
#include "../mapObjectConstructors/CObjectClassesHandler.h"
@ -90,7 +91,7 @@ void CGameStateCampaign::trimCrossoverHeroesParameters(std::vector<CampaignHeroR
.And(Selector::subtype()(BonusSubtypeID(g)))
.And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL));
cgh->getBonusLocalFirst(sel)->val = cgh->type->heroClass->primarySkillInitial[g.getNum()];
cgh->getLocalBonus(sel)->val = cgh->type->heroClass->primarySkillInitial[g.getNum()];
}
}
}
@ -347,7 +348,7 @@ void CGameStateCampaign::replaceHeroesPlaceholders(const std::vector<CampaignHer
if(heroPlaceholder->tempOwner.isValidPlayer())
heroToPlace->tempOwner = heroPlaceholder->tempOwner;
heroToPlace->pos = heroPlaceholder->pos;
heroToPlace->type = VLC->heroh->objects[heroToPlace->getHeroType().getNum()];
heroToPlace->type = heroToPlace->getHeroType().toHeroType();
heroToPlace->appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, heroToPlace->type->heroClass->getIndex())->getTemplates().front();
gameState->map->removeBlockVisTiles(heroPlaceholder, true);
@ -402,7 +403,7 @@ std::vector<CampaignHeroReplacement> CGameStateCampaign::generateCampaignHeroesT
continue;
}
CGHeroInstance * hero = CampaignState::crossoverDeserialize(node, gameState->map);
CGHeroInstance * hero = campaignState->crossoverDeserialize(node, gameState->map);
logGlobal->info("Hero crossover: Loading placeholder for %d (%s)", hero->getHeroType(), hero->getNameTranslated());
@ -427,7 +428,7 @@ std::vector<CampaignHeroReplacement> CGameStateCampaign::generateCampaignHeroesT
if (nodeListIter == nodeList.end())
break;
CGHeroInstance * hero = CampaignState::crossoverDeserialize(*nodeListIter, gameState->map);
CGHeroInstance * hero = campaignState->crossoverDeserialize(*nodeListIter, gameState->map);
nodeListIter++;
logGlobal->info("Hero crossover: Loading placeholder as %d (%s)", hero->getHeroType(), hero->getNameTranslated());
@ -599,7 +600,7 @@ bool CGameStateCampaign::playerHasStartingHero(PlayerColor playerColor) const
std::unique_ptr<CMap> CGameStateCampaign::getCurrentMap() const
{
return gameState->scenarioOps->campState->getMap(CampaignScenarioID::NONE);
return gameState->scenarioOps->campState->getMap(CampaignScenarioID::NONE, gameState->callback);
}
VCMI_LIB_NAMESPACE_END

View File

@ -19,6 +19,7 @@ class ObjectTemplate;
class CGObjectInstance;
class CRandomGenerator;
class IObjectInfo;
class IGameCallback;
/// Class responsible for creation of objects of specific type & subtype
class DLL_LINKAGE AObjectTypeHandler : public boost::noncopyable
@ -109,7 +110,7 @@ public:
/// Creates object and set up core properties (like ID/subID). Object is NOT initialized
/// to allow creating objects before game start (e.g. map loading)
virtual CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const = 0;
virtual CGObjectInstance * create(IGameCallback * cb, std::shared_ptr<const ObjectTemplate> tmpl) const = 0;
/// Configures object properties. Should be re-entrable, resetting state of the object if necessarily
/// This should set remaining properties, including randomized or depending on map

View File

@ -34,18 +34,19 @@ void CBankInstanceConstructor::initTypeData(const JsonNode & input)
coastVisitable = input["coastVisitable"].Bool();
}
BankConfig CBankInstanceConstructor::generateConfig(const JsonNode & level, CRandomGenerator & rng) const
BankConfig CBankInstanceConstructor::generateConfig(IGameCallback * cb, const JsonNode & level, CRandomGenerator & rng) const
{
BankConfig bc;
JsonRandom randomizer(cb);
JsonRandom::Variables emptyVariables;
bc.chance = static_cast<ui32>(level["chance"].Float());
bc.guards = JsonRandom::loadCreatures(level["guards"], rng, emptyVariables);
bc.guards = randomizer.loadCreatures(level["guards"], rng, emptyVariables);
bc.resources = ResourceSet(level["reward"]["resources"]);
bc.creatures = JsonRandom::loadCreatures(level["reward"]["creatures"], rng, emptyVariables);
bc.artifacts = JsonRandom::loadArtifacts(level["reward"]["artifacts"], rng, emptyVariables);
bc.spells = JsonRandom::loadSpells(level["reward"]["spells"], rng, emptyVariables);
bc.creatures = randomizer.loadCreatures(level["reward"]["creatures"], rng, emptyVariables);
bc.artifacts = randomizer.loadArtifacts(level["reward"]["artifacts"], rng, emptyVariables);
bc.spells = randomizer.loadSpells(level["reward"]["spells"], rng, emptyVariables);
return bc;
}
@ -70,7 +71,7 @@ void CBankInstanceConstructor::randomizeObject(CBank * bank, CRandomGenerator &
cumulativeChance += static_cast<int>(node["chance"].Float());
if(selectedChance < cumulativeChance)
{
bank->setConfig(generateConfig(node, rng));
bank->setConfig(generateConfig(bank->cb, node, rng));
break;
}
}
@ -82,80 +83,16 @@ CBankInfo::CBankInfo(const JsonVector & Config) :
assert(!Config.empty());
}
static void addStackToArmy(IObjectInfo::CArmyStructure & army, const CCreature * crea, si32 amount)
{
army.totalStrength += crea->getFightValue() * amount;
bool walker = true;
if(crea->hasBonusOfType(BonusType::SHOOTER))
{
army.shootersStrength += crea->getFightValue() * amount;
walker = false;
}
if(crea->hasBonusOfType(BonusType::FLYING))
{
army.flyersStrength += crea->getFightValue() * amount;
walker = false;
}
if(walker)
army.walkersStrength += crea->getFightValue() * amount;
}
IObjectInfo::CArmyStructure CBankInfo::minGuards() const
{
JsonRandom::Variables emptyVariables;
std::vector<IObjectInfo::CArmyStructure> armies;
for(auto configEntry : config)
{
auto stacks = JsonRandom::evaluateCreatures(configEntry["guards"], emptyVariables);
IObjectInfo::CArmyStructure army;
for(auto & stack : stacks)
{
assert(!stack.allowedCreatures.empty());
auto weakest = boost::range::min_element(stack.allowedCreatures, [](const CCreature * a, const CCreature * b)
{
return a->getFightValue() < b->getFightValue();
});
addStackToArmy(army, *weakest, stack.minAmount);
}
armies.push_back(army);
}
return *boost::range::min_element(armies);
}
IObjectInfo::CArmyStructure CBankInfo::maxGuards() const
{
JsonRandom::Variables emptyVariables;
std::vector<IObjectInfo::CArmyStructure> armies;
for(auto configEntry : config)
{
auto stacks = JsonRandom::evaluateCreatures(configEntry["guards"], emptyVariables);
IObjectInfo::CArmyStructure army;
for(auto & stack : stacks)
{
assert(!stack.allowedCreatures.empty());
auto strongest = boost::range::max_element(stack.allowedCreatures, [](const CCreature * a, const CCreature * b)
{
return a->getFightValue() < b->getFightValue();
});
addStackToArmy(army, *strongest, stack.maxAmount);
}
armies.push_back(army);
}
return *boost::range::max_element(armies);
}
TPossibleGuards CBankInfo::getPossibleGuards() const
TPossibleGuards CBankInfo::getPossibleGuards(IGameCallback * cb) const
{
JsonRandom::Variables emptyVariables;
JsonRandom randomizer(cb);
TPossibleGuards out;
for(const JsonNode & configEntry : config)
{
const JsonNode & guardsInfo = configEntry["guards"];
auto stacks = JsonRandom::evaluateCreatures(guardsInfo, emptyVariables);
auto stacks = randomizer.evaluateCreatures(guardsInfo, emptyVariables);
IObjectInfo::CArmyStructure army;
@ -188,15 +125,16 @@ std::vector<PossibleReward<TResources>> CBankInfo::getPossibleResourcesReward()
return result;
}
std::vector<PossibleReward<CStackBasicDescriptor>> CBankInfo::getPossibleCreaturesReward() const
std::vector<PossibleReward<CStackBasicDescriptor>> CBankInfo::getPossibleCreaturesReward(IGameCallback * cb) const
{
JsonRandom::Variables emptyVariables;
JsonRandom randomizer(cb);
std::vector<PossibleReward<CStackBasicDescriptor>> aproximateReward;
for(const JsonNode & configEntry : config)
{
const JsonNode & guardsInfo = configEntry["reward"]["creatures"];
auto stacks = JsonRandom::evaluateCreatures(guardsInfo, emptyVariables);
auto stacks = randomizer.evaluateCreatures(guardsInfo, emptyVariables);
for(auto stack : stacks)
{

View File

@ -55,13 +55,9 @@ class DLL_LINKAGE CBankInfo : public IObjectInfo
public:
CBankInfo(const JsonVector & Config);
TPossibleGuards getPossibleGuards() const;
TPossibleGuards getPossibleGuards(IGameCallback * cb) const;
std::vector<PossibleReward<TResources>> getPossibleResourcesReward() const;
std::vector<PossibleReward<CStackBasicDescriptor>> getPossibleCreaturesReward() const;
// These functions should try to evaluate minimal possible/max possible guards to give provide information on possible thread to AI
CArmyStructure minGuards() const override;
CArmyStructure maxGuards() const override;
std::vector<PossibleReward<CStackBasicDescriptor>> getPossibleCreaturesReward(IGameCallback * cb) const;
bool givesResources() const override;
bool givesArtifacts() const override;
@ -71,7 +67,7 @@ public:
class CBankInstanceConstructor : public CDefaultObjectTypeHandler<CBank>
{
BankConfig generateConfig(const JsonNode & conf, CRandomGenerator & rng) const;
BankConfig generateConfig(IGameCallback * cb, const JsonNode & conf, CRandomGenerator & rng) const;
JsonVector levels;

View File

@ -27,9 +27,9 @@ class CDefaultObjectTypeHandler : public AObjectTypeHandler
randomizeObject(castedObject, rng);
}
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const final
CGObjectInstance * create(IGameCallback * cb, std::shared_ptr<const ObjectTemplate> tmpl) const final
{
ObjectType * result = createObject();
ObjectType * result = createObject(cb);
preInitObject(result);
@ -44,9 +44,9 @@ class CDefaultObjectTypeHandler : public AObjectTypeHandler
protected:
virtual void initializeObject(ObjectType * object) const {}
virtual void randomizeObject(ObjectType * object, CRandomGenerator & rng) const {}
virtual ObjectType * createObject() const
virtual ObjectType * createObject(IGameCallback * cb) const
{
return new ObjectType();
return new ObjectType(cb);
}
};

View File

@ -31,9 +31,9 @@ bool CRewardableConstructor::hasNameTextID() const
return !objectInfo.getParameters()["name"].isNull();
}
CGObjectInstance * CRewardableConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
CGObjectInstance * CRewardableConstructor::create(IGameCallback * cb, std::shared_ptr<const ObjectTemplate> tmpl) const
{
auto * ret = new CRewardableObject();
auto * ret = new CRewardableObject(cb);
preInitObject(ret);
ret->appearance = tmpl;
ret->blockVisit = blockVisit;
@ -44,7 +44,7 @@ void CRewardableConstructor::configureObject(CGObjectInstance * object, CRandomG
{
if(auto * rewardableObject = dynamic_cast<CRewardableObject*>(object))
{
objectInfo.configureObject(rewardableObject->configuration, rng);
objectInfo.configureObject(rewardableObject->configuration, rng, object->cb);
for(auto & rewardInfo : rewardableObject->configuration.info)
{
for (auto & bonus : rewardInfo.reward.bonuses)

View File

@ -25,7 +25,7 @@ class DLL_LINKAGE CRewardableConstructor : public AObjectTypeHandler
public:
bool hasNameTextID() const override;
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
CGObjectInstance * create(IGameCallback * cb, std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;

View File

@ -102,7 +102,7 @@ void CTownInstanceConstructor::initializeObject(CGTownInstance * obj) const
void CTownInstanceConstructor::randomizeObject(CGTownInstance * object, CRandomGenerator & rng) const
{
auto templ = getOverride(CGObjectInstance::cb->getTile(object->pos)->terType->getId(), object);
auto templ = getOverride(object->cb->getTile(object->pos)->terType->getId(), object);
if(templ)
object->appearance = templ;
}
@ -122,7 +122,7 @@ void CHeroInstanceConstructor::initTypeData(const JsonNode & input)
VLC->identifiers()->requestIdentifier(
"heroClass",
input["heroClass"],
[&](si32 index) { heroClass = VLC->heroh->classes[index]; });
[&](si32 index) { heroClass = HeroClassID(index).toHeroClass(); });
filtersJson = input["filters"];
}
@ -224,7 +224,7 @@ void MarketInstanceConstructor::initTypeData(const JsonNode & input)
speech = input["speech"].String();
}
CGMarket * MarketInstanceConstructor::createObject() const
CGMarket * MarketInstanceConstructor::createObject(IGameCallback * cb) const
{
if(marketModes.size() == 1)
{
@ -232,13 +232,13 @@ CGMarket * MarketInstanceConstructor::createObject() const
{
case EMarketMode::ARTIFACT_RESOURCE:
case EMarketMode::RESOURCE_ARTIFACT:
return new CGBlackMarket;
return new CGBlackMarket(cb);
case EMarketMode::RESOURCE_SKILL:
return new CGUniversity;
return new CGUniversity(cb);
}
}
return new CGMarket;
return new CGMarket(cb);
}
void MarketInstanceConstructor::initializeObject(CGMarket * market) const
@ -256,11 +256,12 @@ void MarketInstanceConstructor::initializeObject(CGMarket * market) const
void MarketInstanceConstructor::randomizeObject(CGMarket * object, CRandomGenerator & rng) const
{
JsonRandom randomizer(object->cb);
JsonRandom::Variables emptyVariables;
if(auto * university = dynamic_cast<CGUniversity *>(object))
{
for(auto skill : JsonRandom::loadSecondaries(predefinedOffer, rng, emptyVariables))
for(auto skill : randomizer.loadSecondaries(predefinedOffer, rng, emptyVariables))
university->skills.push_back(skill.first);
}
}

View File

@ -57,7 +57,7 @@ protected:
void initTypeData(const JsonNode & input) override;
public:
CFaction * faction = nullptr;
const CFaction * faction = nullptr;
std::map<std::string, LogicalExpression<BuildingID>> filters;
void initializeObject(CGTownInstance * object) const override;
@ -76,7 +76,7 @@ protected:
void initTypeData(const JsonNode & input) override;
public:
CHeroClass * heroClass = nullptr;
const CHeroClass * heroClass = nullptr;
std::map<std::string, LogicalExpression<HeroTypeID>> filters;
void initializeObject(CGHeroInstance * object) const override;
@ -121,7 +121,7 @@ protected:
std::string speech;
public:
CGMarket * createObject() const override;
CGMarket * createObject(IGameCallback * cb) const override;
void initializeObject(CGMarket * object) const override;
void randomizeObject(CGMarket * object, CRandomGenerator & rng) const override;

View File

@ -45,7 +45,7 @@ void DwellingInstanceConstructor::initTypeData(const JsonNode & input)
{
VLC->identifiers()->requestIdentifier("creature", creaturesOnLevel[currentCreature], [=] (si32 index)
{
availableCreatures[currentLevel][currentCreature] = VLC->creh->objects[index];
availableCreatures[currentLevel][currentCreature] = CreatureID(index).toCreature();
});
}
assert(!availableCreatures[currentLevel].empty());
@ -68,9 +68,9 @@ void DwellingInstanceConstructor::initializeObject(CGDwelling * obj) const
}
}
void DwellingInstanceConstructor::randomizeObject(CGDwelling * object, CRandomGenerator &rng) const
void DwellingInstanceConstructor::randomizeObject(CGDwelling * dwelling, CRandomGenerator &rng) const
{
auto * dwelling = dynamic_cast<CGDwelling *>(object);
JsonRandom randomizer(dwelling->cb);
dwelling->creatures.clear();
dwelling->creatures.reserve(availableCreatures.size());
@ -94,7 +94,7 @@ void DwellingInstanceConstructor::randomizeObject(CGDwelling * object, CRandomGe
else if(guards.getType() == JsonNode::JsonType::DATA_VECTOR) //custom guards (eg. Elemental Conflux)
{
JsonRandom::Variables emptyVariables;
for(auto & stack : JsonRandom::loadCreatures(guards, rng, emptyVariables))
for(auto & stack : randomizer.loadCreatures(guards, rng, emptyVariables))
{
dwelling->putStack(SlotID(dwelling->stacksCount()), new CStackInstance(stack.type->getId(), stack.count));
}

View File

@ -10,6 +10,7 @@
#pragma once
#include "CDefaultObjectTypeHandler.h"
#include "../mapObjects/CGDwelling.h"
VCMI_LIB_NAMESPACE_BEGIN

View File

@ -10,6 +10,7 @@
#pragma once
#include "CDefaultObjectTypeHandler.h"
#include "../mapObjects/MiscObjects.h"
VCMI_LIB_NAMESPACE_BEGIN

View File

@ -34,11 +34,6 @@ public:
}
};
/// Returns possible composition of guards. Actual guards would be
/// somewhere between these two values
virtual CArmyStructure minGuards() const { return CArmyStructure(); }
virtual CArmyStructure maxGuards() const { return CArmyStructure(); }
virtual bool givesResources() const { return false; }
virtual bool givesExperience() const { return false; }

View File

@ -10,6 +10,7 @@
#pragma once
#include "CDefaultObjectTypeHandler.h"
#include "../mapObjects/MiscObjects.h"
VCMI_LIB_NAMESPACE_BEGIN

View File

@ -40,12 +40,13 @@ void CArmedInstance::randomizeArmy(FactionID type)
// Take Angelic Alliance troop-mixing freedom of non-evil units into account.
CSelector CArmedInstance::nonEvilAlignmentMixSelector = Selector::type()(BonusType::NONEVIL_ALIGNMENT_MIX);
CArmedInstance::CArmedInstance()
:CArmedInstance(false)
CArmedInstance::CArmedInstance(IGameCallback *cb)
:CArmedInstance(cb, false)
{
}
CArmedInstance::CArmedInstance(bool isHypothetic):
CArmedInstance::CArmedInstance(IGameCallback *cb, bool isHypothetic):
CGObjectInstance(cb),
CBonusSystemNode(isHypothetic),
nonEvilAlignmentMix(this, nonEvilAlignmentMixSelector),
battle(nullptr)

View File

@ -42,8 +42,8 @@ public:
virtual CBonusSystemNode & whatShouldBeAttached();
//////////////////////////////////////////////////////////////////////////
CArmedInstance();
CArmedInstance(bool isHypothetic);
CArmedInstance(IGameCallback *cb);
CArmedInstance(IGameCallback *cb, bool isHypothetic);
PlayerColor getOwner() const override
{

View File

@ -37,8 +37,10 @@ static std::string visitedTxt(const bool visited)
return VLC->generaltexth->allTexts[id];
}
//must be instantiated in .cpp file for access to complete types of all member fields
CBank::CBank() = default;
CBank::CBank(IGameCallback *cb)
: CArmedInstance(cb)
{}
//must be instantiated in .cpp file for access to complete types of all member fields
CBank::~CBank() = default;

View File

@ -27,7 +27,7 @@ class DLL_LINKAGE CBank : public CArmedInstance
void doVisit(const CGHeroInstance * hero) const;
public:
CBank();
CBank(IGameCallback *cb);
~CBank() override;
void setConfig(const BankConfig & bc);

View File

@ -313,11 +313,11 @@ int CGCreature::takenAction(const CGHeroInstance *h, bool allowJoin) const
powerFactor = -3;
std::set<CreatureID> myKindCres; //what creatures are the same kind as we
const CCreature * myCreature = VLC->creh->objects[getCreature().getNum()];
const CCreature * myCreature = getCreature().toCreature();
myKindCres.insert(myCreature->getId()); //we
myKindCres.insert(myCreature->upgrades.begin(), myCreature->upgrades.end()); //our upgrades
for(ConstTransitivePtr<CCreature> &crea : VLC->creh->objects)
for(auto const & crea : VLC->creh->objects)
{
if(vstd::contains(crea->upgrades, myCreature->getId())) //it's our base creatures
myKindCres.insert(crea->getId());

View File

@ -18,6 +18,8 @@ VCMI_LIB_NAMESPACE_BEGIN
class DLL_LINKAGE CGCreature : public CArmedInstance //creatures on map
{
public:
using CArmedInstance::CArmedInstance;
enum Action {
FIGHT = -2, FLEE = -1, JOIN_FOR_FREE = 0 //values > 0 mean gold price
};

View File

@ -16,6 +16,7 @@
#include "../mapObjectConstructors/CObjectClassesHandler.h"
#include "../mapObjectConstructors/DwellingInstanceConstructor.h"
#include "../mapObjects/CGHeroInstance.h"
#include "../mapObjects/CGTownInstance.h"
#include "../networkPacks/StackLocation.h"
#include "../networkPacks/PacksForClient.h"
#include "../networkPacks/PacksForClientBattle.h"
@ -43,7 +44,10 @@ void CGDwellingRandomizationInfo::serializeJson(JsonSerializeFormat & handler)
}
}
CGDwelling::CGDwelling() = default;
CGDwelling::CGDwelling(IGameCallback *cb):
CArmedInstance(cb)
{}
CGDwelling::~CGDwelling() = default;
FactionID CGDwelling::randomizeFaction(CRandomGenerator & rand)

View File

@ -38,7 +38,7 @@ public:
std::optional<CGDwellingRandomizationInfo> randomizationInfo; //random dwelling options; not serialized
TCreaturesSet creatures; //creatures[level] -> <vector of alternative ids (base creature and upgrades, creatures amount>
CGDwelling();
CGDwelling(IGameCallback *cb);
~CGDwelling() override;
protected:

View File

@ -33,6 +33,7 @@
#include "../serializer/JsonSerializeFormat.h"
#include "../mapObjectConstructors/AObjectTypeHandler.h"
#include "../mapObjectConstructors/CObjectClassesHandler.h"
#include "../mapObjects/MiscObjects.h"
#include "../modding/ModScope.h"
#include "../networkPacks/PacksForClient.h"
#include "../networkPacks/PacksForClientBattle.h"
@ -274,7 +275,9 @@ int CGHeroInstance::movementPointsLimitCached(bool onLand, const TurnInfo * ti)
return ti->valOfBonuses(BonusType::MOVEMENT, onLand ? BonusCustomSubtype::heroMovementLand : BonusCustomSubtype::heroMovementSea);
}
CGHeroInstance::CGHeroInstance():
CGHeroInstance::CGHeroInstance(IGameCallback * cb)
: CArmedInstance(cb),
type(nullptr),
tacticFormationEnabled(false),
inTownGarrison(false),
moveDir(4),
@ -316,7 +319,7 @@ void CGHeroInstance::initHero(CRandomGenerator & rand)
{
assert(validTypes(true));
if(!type)
type = VLC->heroh->objects[getHeroType().getNum()];
type = getHeroType().toHeroType();
if (ID == Obj::HERO)
appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, type->heroClass->getIndex())->getTemplates().front();
@ -590,11 +593,11 @@ void CGHeroInstance::pickRandomObject(CRandomGenerator & rand)
{
ID = Obj::HERO;
subID = cb->gameState()->pickNextHeroType(getOwner());
type = VLC->heroh->objects[getHeroType().getNum()];
type = getHeroType().toHeroType();
randomizeArmy(type->heroClass->faction);
}
else
type = VLC->heroh->objects[getHeroType().getNum()];
type = getHeroType().toHeroType();
auto oldSubID = subID;
@ -789,7 +792,7 @@ void CGHeroInstance::spendMana(ServerCallback * server, const int spellCost) con
bool CGHeroInstance::canCastThisSpell(const spells::Spell * spell) const
{
const bool isAllowed = IObjectInterface::cb->isAllowed(spell->getId());
const bool isAllowed = cb->isAllowed(spell->getId());
const bool inSpellBook = vstd::contains(spells, spell->getId()) && hasSpellbook();
const bool specificBonus = hasBonusOfType(BonusType::SPELL, BonusSubtypeID(spell->getId()));
@ -853,7 +856,7 @@ bool CGHeroInstance::canLearnSpell(const spells::Spell * spell, bool allowBanned
return false;//creature abilities can not be learned
}
if(!allowBanned && !IObjectInterface::cb->isAllowed(spell->getId()))
if(!allowBanned && !cb->isAllowed(spell->getId()))
{
logGlobal->warn("Hero %s try to learn banned spell %s", nodeName(), spell->getNameTranslated());
return false;//banned spells should not be learned
@ -879,7 +882,7 @@ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &b
double necromancySkill = valOfBonuses(BonusType::UNDEAD_RAISE_PERCENTAGE) / 100.0;
const ui8 necromancyLevel = valOfBonuses(BonusType::IMPROVED_NECROMANCY);
vstd::amin(necromancySkill, 1.0); //it's impossible to raise more creatures than all...
const std::map<ui32,si32> &casualties = battleResult.casualties[!battleResult.winner];
const std::map<CreatureID,si32> &casualties = battleResult.casualties[!battleResult.winner];
// figure out what to raise - pick strongest creature meeting requirements
CreatureID creatureTypeRaised = CreatureID::NONE; //now we always have IMPROVED_NECROMANCY, no need for hardcode
int requiredCasualtyLevel = 1;
@ -888,7 +891,7 @@ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &b
{
int maxCasualtyLevel = 1;
for(const auto & casualty : casualties)
vstd::amax(maxCasualtyLevel, VLC->creatures()->getByIndex(casualty.first)->getLevel());
vstd::amax(maxCasualtyLevel, VLC->creatures()->getById(casualty.first)->getLevel());
// pick best bonus available
std::shared_ptr<Bonus> topPick;
for(const std::shared_ptr<Bonus> & newPick : *improvedNecromancy)
@ -936,7 +939,7 @@ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &b
double raisedUnits = 0;
for(const auto & casualty : casualties)
{
const CCreature * c = VLC->creh->objects[casualty.first];
const CCreature * c = casualty.first.toCreature();
double raisedFromCasualty = std::min(c->getMaxHealth() / raisedUnitHealth, 1.0) * casualty.second * necromancySkill;
if(c->getLevel() < requiredCasualtyLevel)
raisedFromCasualty *= 0.5;
@ -1258,7 +1261,7 @@ EDiggingStatus CGHeroInstance::diggingStatus() const
{
if(static_cast<int>(movement) < movementPointsLimit(true))
return EDiggingStatus::LACK_OF_MOVEMENT;
if(!VLC->arth->objects[ArtifactID::GRAIL]->canBePutAt(this))
if(ArtifactID(ArtifactID::GRAIL).toArtifact()->canBePutAt(this))
return EDiggingStatus::BACKPACK_IS_FULL;
return cb->getTileDigStatus(visitablePos());
}
@ -1409,7 +1412,7 @@ void CGHeroInstance::setPrimarySkill(PrimarySkill primarySkill, si64 value, ui8
{
if(primarySkill < PrimarySkill::EXPERIENCE)
{
auto skill = getBonusLocalFirst(Selector::type()(BonusType::PRIMARY_SKILL)
auto skill = getLocalBonus(Selector::type()(BonusType::PRIMARY_SKILL)
.And(Selector::subtype()(BonusSubtypeID(primarySkill)))
.And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL)));
assert(skill);
@ -1742,7 +1745,7 @@ void CGHeroInstance::serializeJsonOptions(JsonSerializeFormat & handler)
if(!appearance)
{
// crossoverDeserialize
type = VLC->heroh->objects[getHeroType().getNum()];
type = getHeroType().toHeroType();
appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, type->heroClass->getIndex())->getTemplates().front();
}
@ -1760,7 +1763,7 @@ void CGHeroInstance::serializeJsonDefinition(JsonSerializeFormat & handler)
bool CGHeroInstance::isMissionCritical() const
{
for(const TriggeredEvent & event : IObjectInterface::cb->getMapHeader()->triggeredEvents)
for(const TriggeredEvent & event : cb->getMapHeader()->triggeredEvents)
{
if (event.effect.type != EventEffect::DEFEAT)
continue;

View File

@ -28,6 +28,8 @@ enum class EHeroGender : uint8_t;
class DLL_LINKAGE CGHeroPlaceholder : public CGObjectInstance
{
public:
using CGObjectInstance::CGObjectInstance;
/// if this is placeholder by power, then power rank of desired hero
std::optional<ui8> powerRank;
@ -69,7 +71,7 @@ public:
//////////////////////////////////////////////////////////////////////////
ConstTransitivePtr<CHero> type;
const CHero * type;
TExpType exp; //experience points
ui32 level; //current level of hero
@ -249,7 +251,7 @@ public:
/// If this hero perishes, the scenario is failed
bool isMissionCritical() const;
CGHeroInstance();
CGHeroInstance(IGameCallback *cb);
virtual ~CGHeroInstance();
PlayerColor getOwner() const override;

View File

@ -55,9 +55,9 @@ std::vector<TradeItemBuy> CGMarket::availableItemsIds(EMarketMode mode) const
return std::vector<TradeItemBuy>();
}
CGMarket::CGMarket()
{
}
CGMarket::CGMarket(IGameCallback *cb):
CGObjectInstance(cb)
{}
std::vector<TradeItemBuy> CGBlackMarket::availableItemsIds(EMarketMode mode) const
{

View File

@ -25,7 +25,7 @@ public:
std::string title;
std::string speech; //currently shown only in university
CGMarket();
CGMarket(IGameCallback *cb);
///IObjectInterface
void onHeroVisit(const CGHeroInstance * h) const override; //open trading window
void initObj(CRandomGenerator & rand) override;//set skills for trade
@ -49,6 +49,8 @@ public:
class DLL_LINKAGE CGBlackMarket : public CGMarket
{
public:
using CGMarket::CGMarket;
std::vector<const CArtifact *> artifacts; //available artifacts
void newTurn(CRandomGenerator & rand) const override; //reset artifacts for black market every month
@ -64,6 +66,8 @@ public:
class DLL_LINKAGE CGUniversity : public CGMarket
{
public:
using CGMarket::CGMarket;
std::vector<TradeItemBuy> skills; //available skills
std::vector<TradeItemBuy> availableItemsIds(EMarketMode mode) const override;

Some files were not shown because too many files have changed in this diff Show More