/* * CampaignState.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 #include "../GameConstants.h" #include "../MetaString.h" #include "../filesystem/ResourcePath.h" #include "../CGeneralTextHandler.h" #include "CampaignConstants.h" #include "CampaignScenarioPrologEpilog.h" VCMI_LIB_NAMESPACE_BEGIN struct StartInfo; class CGHeroInstance; class CBinaryReader; class CInputStream; class CMap; class CMapHeader; class CMapInfo; class JsonNode; class Point; class DLL_LINKAGE CampaignRegions { std::string campPrefix; int colorSuffixLength; struct DLL_LINKAGE RegionDescription { std::string infix; int xpos, ypos; template void serialize(Handler &h, const int formatVersion) { h & infix; h & xpos; h & ypos; } static CampaignRegions::RegionDescription fromJson(const JsonNode & node); }; std::vector regions; ImagePath getNameFor(CampaignScenarioID which, int color, std::string type) const; public: ImagePath getBackgroundName() const; Point getPosition(CampaignScenarioID which) const; ImagePath getAvailableName(CampaignScenarioID which, int color) const; ImagePath getSelectedName(CampaignScenarioID which, int color) const; ImagePath getConqueredName(CampaignScenarioID which, int color) const; template void serialize(Handler &h, const int formatVersion) { h & campPrefix; h & colorSuffixLength; h & regions; } static CampaignRegions fromJson(const JsonNode & node); static CampaignRegions getLegacy(int campId); }; class DLL_LINKAGE CampaignHeader : public boost::noncopyable { friend class CampaignHandler; CampaignVersion version = CampaignVersion::NONE; CampaignRegions campaignRegions; MetaString name; MetaString description; AudioPath music; std::string filename; std::string modName; std::string encoding; int numberOfScenarios = 0; bool difficultyChoosenByPlayer = false; void loadLegacyData(ui8 campId); TextContainerRegistrable textContainer; public: bool playerSelectedDifficulty() const; bool formatVCMI() const; std::string getDescriptionTranslated() const; std::string getNameTranslated() const; std::string getFilename() const; std::string getModName() const; std::string getEncoding() const; AudioPath getMusic() const; const CampaignRegions & getRegions() const; TextContainerRegistrable & getTexts(); template void serialize(Handler &h, const int formatVersion) { h & version; h & campaignRegions; h & numberOfScenarios; h & name; h & description; h & difficultyChoosenByPlayer; h & filename; h & modName; h & music; h & encoding; if (formatVersion >= 832) h & textContainer; } }; struct DLL_LINKAGE CampaignBonus { CampaignBonusType type = CampaignBonusType::NONE; //purpose depends on type int32_t info1 = 0; int32_t info2 = 0; int32_t info3 = 0; bool isBonusForHero() const; template void serialize(Handler &h, const int formatVersion) { h & type; h & info1; h & info2; h & info3; } }; struct DLL_LINKAGE CampaignTravel { struct DLL_LINKAGE WhatHeroKeeps { bool experience = false; bool primarySkills = false; bool secondarySkills = false; bool spells = false; bool artifacts = false; template void serialize(Handler &h, const int formatVersion) { h & experience; h & primarySkills; h & secondarySkills; h & spells; h & artifacts; } }; std::set monstersKeptByHero; std::set artifactsKeptByHero; std::vector bonusesToChoose; WhatHeroKeeps whatHeroKeeps; CampaignStartOptions startOptions = CampaignStartOptions::NONE; //1 - start bonus, 2 - traveling hero, 3 - hero options PlayerColor playerColor = PlayerColor::NEUTRAL; //only for startOptions == 1 template void serialize(Handler &h, const int formatVersion) { h & whatHeroKeeps; h & monstersKeptByHero; h & artifactsKeptByHero; h & startOptions; h & playerColor; h & bonusesToChoose; } }; struct DLL_LINKAGE CampaignScenario { std::string mapName; //*.h3m MetaString scenarioName; //from header std::set preconditionRegions; //what we need to conquer to conquer this one (stored as bitfield in h3c) ui8 regionColor = 0; ui8 difficulty = 0; MetaString regionText; CampaignScenarioPrologEpilog prolog; CampaignScenarioPrologEpilog epilog; CampaignTravel travelOptions; void loadPreconditionRegions(ui32 regions); bool isNotVoid() const; template void serialize(Handler &h, const int formatVersion) { h & mapName; h & scenarioName; h & preconditionRegions; h & regionColor; h & difficulty; h & regionText; h & prolog; h & epilog; h & travelOptions; } }; /// Class that represents loaded campaign information class DLL_LINKAGE Campaign : public CampaignHeader { friend class CampaignHandler; std::map scenarios; public: const CampaignScenario & scenario(CampaignScenarioID which) const; std::set allScenarios() const; int scenariosCount() const; template void serialize(Handler &h, const int version) { h & static_cast(*this); h & scenarios; } }; /// Class that represent campaign that is being played at /// Contains campaign itself as well as current state of the campaign class DLL_LINKAGE CampaignState : public Campaign { friend class CampaignHandler; using ScenarioPoolType = std::vector; using CampaignPoolType = std::map; using GlobalPoolType = std::map; /// List of all maps completed by player, in order of their completion std::vector mapsConquered; std::map > mapPieces; //binary h3ms, scenario number -> map data std::map chosenCampaignBonuses; std::optional currentMap; /// Heroes from specific scenario, ordered by descending strength CampaignPoolType scenarioHeroPool; /// Pool of heroes currently reserved for usage in campaign GlobalPoolType globalHeroPool; public: CampaignState() = default; /// Returns last completed scenario, if any std::optional lastScenario() const; std::optional currentScenario() const; std::set conqueredScenarios() const; /// Returns bonus selected for specific scenario std::optional getBonus(CampaignScenarioID which) const; /// Returns index of selected bonus for specified scenario std::optional getBonusID(CampaignScenarioID which) const; /// Returns true if selected scenario can be selected and started by player bool isAvailable(CampaignScenarioID whichScenario) const; /// Returns true if selected scenario has been already completed by player bool isConquered(CampaignScenarioID whichScenario) const; /// Returns true if all available scenarios have been completed and campaign is finished bool isCampaignFinished() const; std::unique_ptr getMap(CampaignScenarioID scenarioId) const; std::unique_ptr getMapHeader(CampaignScenarioID scenarioId) const; std::shared_ptr getMapInfo(CampaignScenarioID scenarioId) const; void setCurrentMap(CampaignScenarioID which); void setCurrentMapBonus(ui8 which); void setCurrentMapAsConquered(std::vector heroes); /// Returns list of heroes that must be reserved for campaign and can only be used for hero placeholders std::set getReservedHeroes() const; /// Returns strongest hero from specified scenario, or null if none found const CGHeroInstance * strongestHero(CampaignScenarioID scenarioId, const PlayerColor & owner) const; /// Returns heroes that can be instantiated as hero placeholders by power const std::vector & getHeroesByPower(CampaignScenarioID scenarioId) const; /// Returns hero for instantiation as placeholder by type /// 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); std::string campaignSet; template void serialize(Handler &h, const int version) { h & static_cast(*this); h & scenarioHeroPool; h & globalHeroPool; h & mapPieces; h & mapsConquered; h & currentMap; h & chosenCampaignBonuses; h & campaignSet; } }; VCMI_LIB_NAMESPACE_END