2023-10-19 16:19:09 +02:00
|
|
|
/*
|
|
|
|
* StartInfo.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 "vstd/DateUtils.h"
|
|
|
|
|
|
|
|
#include "GameConstants.h"
|
|
|
|
#include "TurnTimerInfo.h"
|
2023-12-28 21:48:19 +02:00
|
|
|
#include "ExtraOptionsInfo.h"
|
2023-10-19 16:19:09 +02:00
|
|
|
#include "campaign/CampaignConstants.h"
|
2024-05-07 21:17:05 +02:00
|
|
|
#include "serializer/Serializeable.h"
|
2024-07-16 00:40:39 +02:00
|
|
|
#include "ResourceSet.h"
|
2023-10-19 16:19:09 +02:00
|
|
|
|
|
|
|
VCMI_LIB_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
class CMapGenOptions;
|
|
|
|
class CampaignState;
|
|
|
|
class CMapInfo;
|
|
|
|
struct PlayerInfo;
|
|
|
|
class PlayerColor;
|
|
|
|
|
|
|
|
struct DLL_LINKAGE SimturnsInfo
|
|
|
|
{
|
|
|
|
/// Minimal number of turns that must be played simultaneously even if contact has been detected
|
|
|
|
int requiredTurns = 0;
|
|
|
|
/// Maximum number of turns that might be played simultaneously unless contact is detected
|
|
|
|
int optionalTurns = 0;
|
|
|
|
/// If set to true, human and 1 AI can act at the same time
|
2023-11-13 19:50:53 +02:00
|
|
|
bool allowHumanWithAI = false;
|
2024-05-19 22:13:42 +02:00
|
|
|
/// If set to true, allied players can play simultaneously even after contacting each other
|
|
|
|
bool ignoreAlliedContacts = true;
|
2023-10-19 16:19:09 +02:00
|
|
|
|
2023-12-07 16:36:44 +02:00
|
|
|
bool operator == (const SimturnsInfo & other) const
|
|
|
|
{
|
|
|
|
return requiredTurns == other.requiredTurns &&
|
|
|
|
optionalTurns == other.optionalTurns &&
|
2024-05-19 22:13:42 +02:00
|
|
|
ignoreAlliedContacts == other.ignoreAlliedContacts &&
|
2023-12-07 16:36:44 +02:00
|
|
|
allowHumanWithAI == other.allowHumanWithAI;
|
|
|
|
}
|
|
|
|
|
2023-10-19 16:19:09 +02:00
|
|
|
template <typename Handler>
|
2024-01-20 20:34:51 +02:00
|
|
|
void serialize(Handler &h)
|
2023-10-19 16:19:09 +02:00
|
|
|
{
|
|
|
|
h & requiredTurns;
|
|
|
|
h & optionalTurns;
|
|
|
|
h & allowHumanWithAI;
|
2024-05-19 22:13:42 +02:00
|
|
|
|
2024-08-29 20:51:53 +02:00
|
|
|
if (h.version >= Handler::Version::SAVE_COMPATIBILITY_FIXES)
|
|
|
|
h & ignoreAlliedContacts;
|
|
|
|
else
|
|
|
|
ignoreAlliedContacts = true;
|
2023-10-19 16:19:09 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class PlayerStartingBonus : int8_t
|
|
|
|
{
|
|
|
|
RANDOM = -1,
|
|
|
|
ARTIFACT = 0,
|
|
|
|
GOLD = 1,
|
|
|
|
RESOURCE = 2
|
|
|
|
};
|
|
|
|
|
2024-07-29 22:54:42 +02:00
|
|
|
struct DLL_LINKAGE Handicap {
|
|
|
|
TResources startBonus = TResources();
|
|
|
|
int percentIncome = 100;
|
|
|
|
int percentGrowth = 100;
|
|
|
|
|
|
|
|
template <typename Handler>
|
|
|
|
void serialize(Handler &h)
|
|
|
|
{
|
|
|
|
h & startBonus;
|
|
|
|
h & percentIncome;
|
|
|
|
h & percentGrowth;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-10-19 16:19:09 +02:00
|
|
|
/// Struct which describes the name, the color, the starting bonus of a player
|
|
|
|
struct DLL_LINKAGE PlayerSettings
|
|
|
|
{
|
|
|
|
enum { PLAYER_AI = 0 }; // for use in playerID
|
|
|
|
|
|
|
|
PlayerStartingBonus bonus;
|
|
|
|
FactionID castle;
|
|
|
|
HeroTypeID hero;
|
|
|
|
HeroTypeID heroPortrait; //-1 if default, else ID
|
|
|
|
|
|
|
|
std::string heroNameTextId;
|
|
|
|
PlayerColor color; //from 0 -
|
2024-07-29 22:54:42 +02:00
|
|
|
|
|
|
|
Handicap handicap;
|
2023-10-19 16:19:09 +02:00
|
|
|
|
|
|
|
std::string name;
|
|
|
|
std::set<ui8> connectedPlayerIDs; //Empty - AI, or connectrd player ids
|
|
|
|
bool compOnly; //true if this player is a computer only player; required for RMG
|
|
|
|
template <typename Handler>
|
2024-01-20 20:34:51 +02:00
|
|
|
void serialize(Handler &h)
|
2023-10-19 16:19:09 +02:00
|
|
|
{
|
|
|
|
h & castle;
|
|
|
|
h & hero;
|
|
|
|
h & heroPortrait;
|
|
|
|
h & heroNameTextId;
|
|
|
|
h & bonus;
|
|
|
|
h & color;
|
2024-07-16 00:40:39 +02:00
|
|
|
if (h.version >= Handler::Version::PLAYER_HANDICAP)
|
2024-07-29 22:54:42 +02:00
|
|
|
h & handicap;
|
2024-07-16 00:40:39 +02:00
|
|
|
else
|
2024-07-29 22:54:42 +02:00
|
|
|
{
|
|
|
|
enum EHandicap {NO_HANDICAP, MILD, SEVERE};
|
2024-07-29 23:05:55 +02:00
|
|
|
EHandicap handicapLegacy = NO_HANDICAP;
|
2024-07-16 00:40:39 +02:00
|
|
|
h & handicapLegacy;
|
2024-07-29 22:54:42 +02:00
|
|
|
}
|
2023-10-19 16:19:09 +02:00
|
|
|
h & name;
|
|
|
|
h & connectedPlayerIDs;
|
|
|
|
h & compOnly;
|
|
|
|
}
|
|
|
|
|
|
|
|
PlayerSettings();
|
|
|
|
bool isControlledByAI() const;
|
|
|
|
bool isControlledByHuman() const;
|
|
|
|
|
|
|
|
FactionID getCastleValidated() const;
|
|
|
|
HeroTypeID getHeroValidated() const;
|
|
|
|
};
|
|
|
|
|
2024-01-21 16:48:36 +02:00
|
|
|
enum class EStartMode : int32_t
|
|
|
|
{
|
|
|
|
NEW_GAME,
|
|
|
|
LOAD_GAME,
|
|
|
|
CAMPAIGN,
|
|
|
|
INVALID = 255
|
|
|
|
};
|
|
|
|
|
2023-10-19 16:19:09 +02:00
|
|
|
/// Struct which describes the difficulty, the turn time,.. of a heroes match.
|
2024-05-07 21:17:05 +02:00
|
|
|
struct DLL_LINKAGE StartInfo : public Serializeable
|
2023-10-19 16:19:09 +02:00
|
|
|
{
|
2024-01-21 16:48:36 +02:00
|
|
|
EStartMode mode;
|
2023-10-19 16:19:09 +02:00
|
|
|
ui8 difficulty; //0=easy; 4=impossible
|
|
|
|
|
|
|
|
using TPlayerInfos = std::map<PlayerColor, PlayerSettings>;
|
|
|
|
TPlayerInfos playerInfos; //color indexed
|
|
|
|
|
2024-10-31 00:23:56 +02:00
|
|
|
time_t startTime;
|
2023-10-19 16:19:09 +02:00
|
|
|
std::string fileURI;
|
|
|
|
SimturnsInfo simturnsInfo;
|
|
|
|
TurnTimerInfo turnTimerInfo;
|
2023-12-28 21:48:19 +02:00
|
|
|
ExtraOptionsInfo extraOptionsInfo;
|
2023-10-19 16:19:09 +02:00
|
|
|
std::string mapname; // empty for random map, otherwise name of the map or savegame
|
|
|
|
bool createRandomMap() const { return mapGenOptions != nullptr; }
|
|
|
|
std::shared_ptr<CMapGenOptions> mapGenOptions;
|
|
|
|
|
|
|
|
std::shared_ptr<CampaignState> campState;
|
|
|
|
|
|
|
|
PlayerSettings & getIthPlayersSettings(const PlayerColor & no);
|
|
|
|
const PlayerSettings & getIthPlayersSettings(const PlayerColor & no) const;
|
|
|
|
PlayerSettings * getPlayersSettings(const ui8 connectedPlayerId);
|
|
|
|
|
|
|
|
// TODO: Must be client-side
|
|
|
|
std::string getCampaignName() const;
|
|
|
|
|
2024-11-17 15:52:16 +02:00
|
|
|
/// Controls hardcoded check for handling of garrisons by AI in Restoration of Erathia campaigns to match H3 behavior
|
|
|
|
bool isRestorationOfErathiaCampaign() const;
|
2024-04-20 16:30:50 +02:00
|
|
|
|
2023-10-19 16:19:09 +02:00
|
|
|
template <typename Handler>
|
2024-01-20 20:34:51 +02:00
|
|
|
void serialize(Handler &h)
|
2023-10-19 16:19:09 +02:00
|
|
|
{
|
|
|
|
h & mode;
|
|
|
|
h & difficulty;
|
|
|
|
h & playerInfos;
|
2024-06-01 18:20:32 +02:00
|
|
|
if (h.version < Handler::Version::REMOVE_LIB_RNG)
|
|
|
|
{
|
2024-07-12 14:15:30 +02:00
|
|
|
uint32_t oldSeeds = 0;
|
2024-06-01 18:20:32 +02:00
|
|
|
h & oldSeeds;
|
|
|
|
h & oldSeeds;
|
|
|
|
h & oldSeeds;
|
|
|
|
}
|
2024-10-31 00:23:56 +02:00
|
|
|
if (h.version < Handler::Version::FOLDER_NAME_REWORK)
|
|
|
|
{
|
|
|
|
std::string startTimeLegacy;
|
|
|
|
h & startTimeLegacy;
|
|
|
|
struct std::tm tm;
|
|
|
|
std::istringstream ss(startTimeLegacy);
|
|
|
|
ss >> std::get_time(&tm, "%Y%m%dT%H%M%S");
|
|
|
|
startTime = mktime(&tm);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
h & startTime;
|
2023-10-19 16:19:09 +02:00
|
|
|
h & fileURI;
|
|
|
|
h & simturnsInfo;
|
|
|
|
h & turnTimerInfo;
|
2024-08-29 20:51:53 +02:00
|
|
|
h & extraOptionsInfo;
|
2023-10-19 16:19:09 +02:00
|
|
|
h & mapname;
|
|
|
|
h & mapGenOptions;
|
|
|
|
h & campState;
|
|
|
|
}
|
|
|
|
|
2024-06-01 18:20:32 +02:00
|
|
|
StartInfo()
|
|
|
|
: mode(EStartMode::INVALID)
|
|
|
|
, difficulty(1)
|
2024-10-31 00:23:56 +02:00
|
|
|
, startTime(std::time(nullptr))
|
2023-10-19 16:19:09 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ClientPlayer
|
|
|
|
{
|
|
|
|
int connection;
|
|
|
|
std::string name;
|
|
|
|
|
2024-01-20 20:34:51 +02:00
|
|
|
template <typename Handler> void serialize(Handler &h)
|
2023-10-19 16:19:09 +02:00
|
|
|
{
|
|
|
|
h & connection;
|
|
|
|
h & name;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct DLL_LINKAGE LobbyState
|
|
|
|
{
|
|
|
|
std::shared_ptr<StartInfo> si;
|
|
|
|
std::shared_ptr<CMapInfo> mi;
|
|
|
|
std::map<ui8, ClientPlayer> playerNames; // id of player <-> player name; 0 is reserved as ID of AI "players"
|
|
|
|
int hostClientId;
|
|
|
|
// TODO: Campaign-only and we don't really need either of them.
|
|
|
|
// Before start both go into CCampaignState that is part of StartInfo
|
|
|
|
CampaignScenarioID campaignMap;
|
|
|
|
int campaignBonus;
|
|
|
|
|
|
|
|
LobbyState() : si(new StartInfo()), hostClientId(-1), campaignMap(CampaignScenarioID::NONE), campaignBonus(-1) {}
|
|
|
|
|
2024-01-20 20:34:51 +02:00
|
|
|
template <typename Handler> void serialize(Handler &h)
|
2023-10-19 16:19:09 +02:00
|
|
|
{
|
|
|
|
h & si;
|
|
|
|
h & mi;
|
|
|
|
h & playerNames;
|
|
|
|
h & hostClientId;
|
|
|
|
h & campaignMap;
|
|
|
|
h & campaignBonus;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct DLL_LINKAGE LobbyInfo : public LobbyState
|
|
|
|
{
|
|
|
|
std::string uuid;
|
|
|
|
|
|
|
|
LobbyInfo() {}
|
|
|
|
|
|
|
|
void verifyStateBeforeStart(bool ignoreNoHuman = false) const;
|
|
|
|
|
|
|
|
bool isClientHost(int clientId) const;
|
2023-11-18 16:34:18 +02:00
|
|
|
bool isPlayerHost(const PlayerColor & color) const;
|
|
|
|
std::set<PlayerColor> getAllClientPlayers(int clientId) const;
|
2023-10-19 16:19:09 +02:00
|
|
|
std::vector<ui8> getConnectedPlayerIdsForClient(int clientId) const;
|
|
|
|
|
|
|
|
// Helpers for lobby state access
|
|
|
|
std::set<PlayerColor> clientHumanColors(int clientId);
|
|
|
|
PlayerColor clientFirstColor(int clientId) const;
|
|
|
|
bool isClientColor(int clientId, const PlayerColor & color) const;
|
|
|
|
ui8 clientFirstId(int clientId) const; // Used by chat only!
|
|
|
|
PlayerInfo & getPlayerInfo(PlayerColor color);
|
|
|
|
TeamID getPlayerTeamId(const PlayerColor & color);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
VCMI_LIB_NAMESPACE_END
|