1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-06 09:09:40 +02:00

Client: implement spectator mode via command-line options

If running with --spectate/-s CPlayerInterface will appear even without human players.
Following command-line options also available:
 --spectate-ignore-hero
 --spectate-hero-speed=N
 --spectate-battle-speed=N
 --spectate-skip-battle
 --spectate-skip-battle-result
Boolean options can also be changed in runtime via client console:
 set spectate-ignore-hero on / off
Spectator mode also:
 - Work with --onlyAI option when starting game or loading saves.
 - Allow to use any cheat codes.
 - Give recon on towns and heroes.
This commit is contained in:
Arseniy Shestakov
2017-06-03 08:25:10 +03:00
parent d95c74941b
commit 18161d3688
24 changed files with 196 additions and 54 deletions

View File

@@ -237,7 +237,7 @@ const CGTownInstance * CBattleInfoEssentials::battleGetDefendedTown() const
BattlePerspective::BattlePerspective CBattleInfoEssentials::battleGetMySide() const
{
RETURN_IF_NOT_BATTLE(BattlePerspective::INVALID);
if(!player)
if(!player || player.get().isSpectator())
return BattlePerspective::ALL_KNOWING;
if(*player == getBattle()->sides[0].color)
return BattlePerspective::LEFT_SIDE;

View File

@@ -595,7 +595,7 @@ const CMapHeader * CGameInfoCallback::getMapHeader() const
bool CGameInfoCallback::hasAccess(boost::optional<PlayerColor> playerId) const
{
return !player || gs->getPlayerRelations( *playerId, *player ) != PlayerRelations::ENEMIES;
return !player || player.get().isSpectator() || gs->getPlayerRelations( *playerId, *player ) != PlayerRelations::ENEMIES;
}
EPlayerStatus::EStatus CGameInfoCallback::getPlayerStatus(PlayerColor player, bool verbose) const

View File

@@ -2208,6 +2208,9 @@ bool CGameState::isVisible(int3 pos, PlayerColor player)
{
if(player == PlayerColor::NEUTRAL)
return false;
if(player.isSpectator())
return true;
return getPlayerTeam(player)->fogOfWarMap[pos.x][pos.y][pos.z];
}

View File

@@ -29,6 +29,7 @@ const SlotID SlotID::SUMMONED_SLOT_PLACEHOLDER = SlotID(-3);
const SlotID SlotID::WAR_MACHINES_SLOT = SlotID(-4);
const SlotID SlotID::ARROW_TOWERS_SLOT = SlotID(-5);
const PlayerColor PlayerColor::SPECTATOR = PlayerColor(252);
const PlayerColor PlayerColor::CANNOT_DETERMINE = PlayerColor(253);
const PlayerColor PlayerColor::UNFLAGGABLE = PlayerColor(254);
const PlayerColor PlayerColor::NEUTRAL = PlayerColor(255);
@@ -72,6 +73,11 @@ bool PlayerColor::isValidPlayer() const
return num < PLAYER_LIMIT_I;
}
bool PlayerColor::isSpectator() const
{
return num == 252;
}
std::string PlayerColor::getStr(bool L10n) const
{
std::string ret = "unnamed";

View File

@@ -257,12 +257,14 @@ class PlayerColor : public BaseForID<PlayerColor, ui8>
PLAYER_LIMIT_I = 8
};
DLL_LINKAGE static const PlayerColor SPECTATOR; //252
DLL_LINKAGE static const PlayerColor CANNOT_DETERMINE; //253
DLL_LINKAGE static const PlayerColor UNFLAGGABLE; //254 - neutral objects (pandora, banks)
DLL_LINKAGE static const PlayerColor NEUTRAL; //255
DLL_LINKAGE static const PlayerColor PLAYER_LIMIT; //player limit per map
DLL_LINKAGE bool isValidPlayer() const; //valid means < PLAYER_LIMIT (especially non-neutral)
DLL_LINKAGE bool isSpectator() const;
DLL_LINKAGE std::string getStr(bool L10n = false) const;
DLL_LINKAGE std::string getStrCap(bool L10n = false) const;

View File

@@ -1842,6 +1842,9 @@ DLL_LINKAGE void BattleSetStackProperty::applyGs(CGameState *gs)
DLL_LINKAGE void PlayerCheated::applyGs(CGameState *gs)
{
if(!player.isValidPlayer())
return;
gs->getPlayer(player)->enteredLosingCheatCode = losingCheatCode;
gs->getPlayer(player)->enteredWinningCheatCode = winningCheatCode;
}