1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
|
/*
* 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 "../filesystem/ResourcePath.h"
#include "../serializer/Serializeable.h"
#include "../texts/TextLocalizationContainer.h"
#include "CampaignConstants.h"
#include "CampaignScenarioPrologEpilog.h"
#include "../gameState/HighScore.h"
#include "../Point.h"
VCMI_LIB_NAMESPACE_BEGIN
struct StartInfo;
class CGHeroInstance;
class CBinaryReader;
class CInputStream;
class CMap;
class CMapHeader;
class CMapInfo;
class JsonNode;
class IGameCallback;
class DLL_LINKAGE CampaignRegions
{
std::string campPrefix;
std::vector<std::string> campSuffix;
std::string campBackground;
int colorSuffixLength;
struct DLL_LINKAGE RegionDescription
{
std::string infix;
Point pos;
std::optional<Point> labelPos;
template <typename Handler> void serialize(Handler &h)
{
h & infix;
if (h.version >= Handler::Version::REGION_LABEL)
{
h & pos;
h & labelPos;
}
else
{
h & pos.x;
h & pos.y;
}
}
static CampaignRegions::RegionDescription fromJson(const JsonNode & node);
static JsonNode toJson(CampaignRegions::RegionDescription & rd);
};
std::vector<RegionDescription> regions;
ImagePath getNameFor(CampaignScenarioID which, int color, std::string type) const;
public:
ImagePath getBackgroundName() const;
Point getPosition(CampaignScenarioID which) const;
std::optional<Point> getLabelPosition(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 <typename Handler> void serialize(Handler &h)
{
h & campPrefix;
h & colorSuffixLength;
h & regions;
if (h.version >= Handler::Version::CAMPAIGN_REGIONS)
{
h & campSuffix;
h & campBackground;
}
}
static CampaignRegions fromJson(const JsonNode & node);
static JsonNode toJson(CampaignRegions cr);
static CampaignRegions getLegacy(int campId);
};
class DLL_LINKAGE CampaignHeader : public boost::noncopyable
{
friend class CampaignHandler;
friend class Campaign;
CampaignVersion version = CampaignVersion::NONE;
CampaignRegions campaignRegions;
MetaString name;
MetaString description;
MetaString author;
MetaString authorContact;
MetaString campaignVersion;
std::time_t creationDateTime;
AudioPath music;
std::string filename;
std::string modName;
std::string encoding;
ImagePath loadingBackground;
ImagePath videoRim;
VideoPath introVideo;
VideoPath outroVideo;
int numberOfScenarios = 0;
bool difficultyChosenByPlayer = false;
void loadLegacyData(ui8 campId);
void loadLegacyData(CampaignRegions regions, int numOfScenario);
TextContainerRegistrable textContainer;
public:
bool playerSelectedDifficulty() const;
bool formatVCMI() const;
std::string getDescriptionTranslated() const;
std::string getNameTranslated() const;
std::string getAuthor() const;
std::string getAuthorContact() const;
std::string getCampaignVersion() const;
time_t getCreationDateTime() const;
std::string getFilename() const;
std::string getModName() const;
std::string getEncoding() const;
AudioPath getMusic() const;
ImagePath getLoadingBackground() const;
ImagePath getVideoRim() const;
VideoPath getIntroVideo() const;
VideoPath getOutroVideo() const;
const CampaignRegions & getRegions() const;
TextContainerRegistrable & getTexts();
template <typename Handler> void serialize(Handler &h)
{
h & version;
h & campaignRegions;
h & numberOfScenarios;
h & name;
h & description;
if (h.version >= Handler::Version::MAP_FORMAT_ADDITIONAL_INFOS)
{
h & author;
h & authorContact;
h & campaignVersion;
h & creationDateTime;
}
h & difficultyChosenByPlayer;
h & filename;
h & modName;
h & music;
h & encoding;
h & textContainer;
if (h.version >= Handler::Version::CHRONICLES_SUPPORT)
{
h & loadingBackground;
h & videoRim;
h & introVideo;
}
if (h.version >= Handler::Version::CAMPAIGN_OUTRO_SUPPORT)
h & outroVideo;
}
};
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 <typename Handler> void serialize(Handler &h)
{
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 <typename Handler> void serialize(Handler &h)
{
h & experience;
h & primarySkills;
h & secondarySkills;
h & spells;
h & artifacts;
}
};
std::set<CreatureID> monstersKeptByHero;
std::set<ArtifactID> artifactsKeptByHero;
std::vector<CampaignBonus> 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 <typename Handler> void serialize(Handler &h)
{
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<CampaignScenarioID> 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 <typename Handler> void serialize(Handler &h)
{
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, public Serializeable
{
friend class CampaignHandler;
std::map<CampaignScenarioID, CampaignScenario> scenarios;
public:
const CampaignScenario & scenario(CampaignScenarioID which) const;
std::set<CampaignScenarioID> allScenarios() const;
int scenariosCount() const;
void overrideCampaign();
void overrideCampaignScenarios();
template <typename Handler> void serialize(Handler &h)
{
h & static_cast<CampaignHeader&>(*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<JsonNode>;
using CampaignPoolType = std::map<CampaignScenarioID, ScenarioPoolType>;
using GlobalPoolType = std::map<HeroTypeID, JsonNode>;
/// List of all maps completed by player, in order of their completion
std::vector<CampaignScenarioID> mapsConquered;
/// List of previously loaded campaign maps, to prevent translation of transferred hero names getting lost after their original map has been completed
std::map<CampaignScenarioID, TextContainerRegistrable> mapTranslations;
std::map<CampaignScenarioID, std::vector<uint8_t> > mapPieces; //binary h3ms, scenario number -> map data
std::map<CampaignScenarioID, ui8> chosenCampaignBonuses;
std::optional<CampaignScenarioID> 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<CampaignScenarioID> lastScenario() const;
std::optional<CampaignScenarioID> currentScenario() const;
std::set<CampaignScenarioID> conqueredScenarios() const;
/// Returns bonus selected for specific scenario
std::optional<CampaignBonus> getBonus(CampaignScenarioID which) const;
/// Returns index of selected bonus for specified scenario
std::optional<ui8> 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<CMap> getMap(CampaignScenarioID scenarioId, IGameCallback * cb);
std::unique_ptr<CMapHeader> getMapHeader(CampaignScenarioID scenarioId) const;
std::shared_ptr<CMapInfo> getMapInfo(CampaignScenarioID scenarioId) const;
void setCurrentMap(CampaignScenarioID which);
void setCurrentMapBonus(ui8 which);
void setCurrentMapAsConquered(std::vector<CGHeroInstance*> heroes);
/// Returns list of heroes that must be reserved for campaign and can only be used for hero placeholders
std::set<HeroTypeID> 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<JsonNode> & 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;
JsonNode crossoverSerialize(CGHeroInstance * hero) const;
CGHeroInstance * crossoverDeserialize(const JsonNode & node, CMap * map) const;
std::string campaignSet;
std::vector<HighScoreParameter> highscoreParameters;
template <typename Handler> void serialize(Handler &h)
{
h & static_cast<Campaign&>(*this);
h & scenarioHeroPool;
h & globalHeroPool;
h & mapPieces;
h & mapsConquered;
h & currentMap;
h & chosenCampaignBonuses;
h & campaignSet;
h & mapTranslations;
if (h.version >= Handler::Version::HIGHSCORE_PARAMETERS)
h & highscoreParameters;
}
};
VCMI_LIB_NAMESPACE_END
|