/* * 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" #include "ExtraOptionsInfo.h" #include "campaign/CampaignConstants.h" 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 bool allowHumanWithAI = false; /// If set to true, allied players can play simultaneously even after contacting each other bool ignoreAlliedContacts = true; bool operator == (const SimturnsInfo & other) const { return requiredTurns == other.requiredTurns && optionalTurns == other.optionalTurns && ignoreAlliedContacts == other.ignoreAlliedContacts && allowHumanWithAI == other.allowHumanWithAI; } template void serialize(Handler &h) { h & requiredTurns; h & optionalTurns; h & allowHumanWithAI; static_assert(Handler::Version::RELEASE_143 < Handler::Version::CURRENT, "Please add ignoreAlliedContacts to serialization for 1.6"); // disabled to allow multiplayer compatibility between 1.5.2 and 1.5.1 // h & ignoreAlliedContacts } }; enum class PlayerStartingBonus : int8_t { RANDOM = -1, ARTIFACT = 0, GOLD = 1, RESOURCE = 2 }; /// 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 - enum EHandicap {NO_HANDICAP, MILD, SEVERE}; EHandicap handicap;//0-no, 1-mild, 2-severe std::string name; std::set connectedPlayerIDs; //Empty - AI, or connectrd player ids bool compOnly; //true if this player is a computer only player; required for RMG template void serialize(Handler &h) { h & castle; h & hero; h & heroPortrait; h & heroNameTextId; h & bonus; h & color; h & handicap; h & name; h & connectedPlayerIDs; h & compOnly; } PlayerSettings(); bool isControlledByAI() const; bool isControlledByHuman() const; FactionID getCastleValidated() const; HeroTypeID getHeroValidated() const; }; enum class EStartMode : int32_t { NEW_GAME, LOAD_GAME, CAMPAIGN, INVALID = 255 }; /// Struct which describes the difficulty, the turn time,.. of a heroes match. struct DLL_LINKAGE StartInfo { EStartMode mode; ui8 difficulty; //0=easy; 4=impossible using TPlayerInfos = std::map; TPlayerInfos playerInfos; //color indexed ui32 seedToBeUsed; //0 if not sure (client requests server to decide, will be send in reply pack) ui32 seedPostInit; //so we know that game is correctly synced at the start; 0 if not known yet ui32 mapfileChecksum; //0 if not relevant std::string startTimeIso8601; std::string fileURI; SimturnsInfo simturnsInfo; TurnTimerInfo turnTimerInfo; ExtraOptionsInfo extraOptionsInfo; std::string mapname; // empty for random map, otherwise name of the map or savegame bool createRandomMap() const { return mapGenOptions != nullptr; } std::shared_ptr mapGenOptions; std::shared_ptr 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; /// Controls hardcoded check for "Steadwick's Fall" scenario from "Dungeon and Devils" campaign bool isSteadwickFallCampaignMission() const; template void serialize(Handler &h) { h & mode; h & difficulty; h & playerInfos; h & seedToBeUsed; h & seedPostInit; h & mapfileChecksum; h & startTimeIso8601; h & fileURI; h & simturnsInfo; h & turnTimerInfo; if(h.version >= Handler::Version::HAS_EXTRA_OPTIONS) h & extraOptionsInfo; else extraOptionsInfo = ExtraOptionsInfo(); h & mapname; h & mapGenOptions; h & campState; } StartInfo() : mode(EStartMode::INVALID), difficulty(1), seedToBeUsed(0), seedPostInit(0), mapfileChecksum(0), startTimeIso8601(vstd::getDateTimeISO8601Basic(std::time(nullptr))), fileURI("") { } }; struct ClientPlayer { int connection; std::string name; template void serialize(Handler &h) { h & connection; h & name; } }; struct DLL_LINKAGE LobbyState { std::shared_ptr si; std::shared_ptr mi; std::map 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) {} template void serialize(Handler &h) { 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; bool isPlayerHost(const PlayerColor & color) const; std::set getAllClientPlayers(int clientId) const; std::vector getConnectedPlayerIdsForClient(int clientId) const; // Helpers for lobby state access std::set 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