diff --git a/binaries/data/mods/public/simulation/components/EndGameManager.js b/binaries/data/mods/public/simulation/components/EndGameManager.js index 47eeff07e8..e59e40210d 100644 --- a/binaries/data/mods/public/simulation/components/EndGameManager.js +++ b/binaries/data/mods/public/simulation/components/EndGameManager.js @@ -122,9 +122,10 @@ EndGameManager.prototype.UpdatePlayerStates = function() var cmpPlayer = Engine.QueryInterface(playerEntityId, IID_Player); cmpPlayer.SetState("won"); } - + + // Reveal the map to all players var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); - cmpRangeManager.SetLosRevealAll(true); + cmpRangeManager.SetLosRevealAll(-1, true); } break; diff --git a/binaries/data/mods/public/simulation/helpers/Commands.js b/binaries/data/mods/public/simulation/helpers/Commands.js index ab03567a71..471d0c1608 100644 --- a/binaries/data/mods/public/simulation/helpers/Commands.js +++ b/binaries/data/mods/public/simulation/helpers/Commands.js @@ -17,8 +17,10 @@ function ProcessCommand(player, cmd) break; case "reveal-map": + // Reveal the map for all players, not just the current player, + // primarily to make it obvious to everyone that the player is cheating var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); - cmpRangeManager.SetLosRevealAll(cmd.enable); + cmpRangeManager.SetLosRevealAll(-1, cmd.enable); break; case "walk": diff --git a/binaries/data/mods/public/simulation/helpers/Setup.js b/binaries/data/mods/public/simulation/helpers/Setup.js index 978320faf6..0863bda160 100644 --- a/binaries/data/mods/public/simulation/helpers/Setup.js +++ b/binaries/data/mods/public/simulation/helpers/Setup.js @@ -22,7 +22,7 @@ function LoadMapSettings(settings) { var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); if (cmpRangeManager) - cmpRangeManager.SetLosRevealAll(true); + cmpRangeManager.SetLosRevealAll(-1, true); } if (settings.CircularMap) diff --git a/source/simulation2/components/CCmpAIManager.cpp b/source/simulation2/components/CCmpAIManager.cpp index 93a261b6c6..5057cd559c 100644 --- a/source/simulation2/components/CCmpAIManager.cpp +++ b/source/simulation2/components/CCmpAIManager.cpp @@ -32,6 +32,7 @@ #include "simulation2/components/ICmpAIInterface.h" #include "simulation2/components/ICmpCommandQueue.h" #include "simulation2/components/ICmpObstructionManager.h" +#include "simulation2/components/ICmpRangeManager.h" #include "simulation2/components/ICmpTemplateManager.h" #include "simulation2/helpers/Grid.h" #include "simulation2/serialization/DebugSerializer.h" @@ -537,9 +538,17 @@ public: } } } + virtual void AddPlayer(std::wstring id, player_id_t player) { m_Worker.AddPlayer(id, player, true); + + // AI players can cheat and see through FoW/SoD, since that greatly simplifies + // their implementation. + // (TODO: maybe cleverer AIs should be able to optionally retain FoW/SoD) + CmpPtr cmpRangeManager(GetSimContext(), SYSTEM_ENTITY); + if (!cmpRangeManager.null()) + cmpRangeManager->SetLosRevealAll(player, true); } virtual void StartComputation() diff --git a/source/simulation2/components/CCmpRangeManager.cpp b/source/simulation2/components/CCmpRangeManager.cpp index 01e8573ff8..d47823b706 100644 --- a/source/simulation2/components/CCmpRangeManager.cpp +++ b/source/simulation2/components/CCmpRangeManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2011 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -185,7 +185,7 @@ public: // LOS state: - bool m_LosRevealAll; + std::map m_LosRevealAll; bool m_LosCircular; i32 m_TerrainVerticesPerSide; @@ -222,7 +222,10 @@ public: // SetBounds is called) ResetSubdivisions(entity_pos_t::FromInt(1), entity_pos_t::FromInt(1)); - m_LosRevealAll = false; + // The whole map should be visible to Gaia by default, else e.g. animals + // will get confused when trying to run from enemies + m_LosRevealAll[0] = true; + m_LosCircular = false; m_TerrainVerticesPerSide = 0; } @@ -243,7 +246,7 @@ public: SerializeMap()(serialize, "queries", m_Queries); SerializeMap()(serialize, "entity data", m_EntityData); - serialize.Bool("los reveal all", m_LosRevealAll); + SerializeMap()(serialize, "los reveal all", m_LosRevealAll); serialize.Bool("los circular", m_LosCircular); serialize.NumberI32_Unbounded("terrain verts per side", m_TerrainVerticesPerSide); @@ -557,11 +560,11 @@ public: return r; } - virtual std::vector GetEntitiesByPlayer(int playerId) + virtual std::vector GetEntitiesByPlayer(player_id_t player) { std::vector entities; - u32 ownerMask = CalcOwnerMask(playerId); + u32 ownerMask = CalcOwnerMask(player); for (std::map::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) { @@ -800,15 +803,15 @@ public: // LOS implementation: - virtual CLosQuerier GetLosQuerier(int player) + virtual CLosQuerier GetLosQuerier(player_id_t player) { - if (m_LosRevealAll) + if (GetLosRevealAll(player)) return CLosQuerier(player, m_LosStateRevealed, m_TerrainVerticesPerSide); else return CLosQuerier(player, m_LosState, m_TerrainVerticesPerSide); } - virtual ELosVisibility GetLosVisibility(entity_id_t ent, int player) + virtual ELosVisibility GetLosVisibility(entity_id_t ent, player_id_t player) { // (We can't use m_EntityData since this needs to handle LOCAL entities too) @@ -822,8 +825,8 @@ public: int i = (pos.X / (int)CELL_SIZE).ToInt_RoundToNearest(); int j = (pos.Y / (int)CELL_SIZE).ToInt_RoundToNearest(); - // Global flag makes all positioned entities visible - if (m_LosRevealAll) + // Reveal flag makes all positioned entities visible + if (GetLosRevealAll(player)) { if (LosIsOffWorld(i, j)) return VIS_HIDDEN; @@ -850,18 +853,26 @@ public: return VIS_HIDDEN; } - virtual void SetLosRevealAll(bool enabled) + virtual void SetLosRevealAll(player_id_t player, bool enabled) { - // Eventually we might want this to be a per-player flag (which is why - // GetLosRevealAll takes a player argument), but currently it's just a - // global setting since I can't quite work out where per-player would be useful - - m_LosRevealAll = enabled; + m_LosRevealAll[player] = enabled; } - virtual bool GetLosRevealAll(int UNUSED(player)) + virtual bool GetLosRevealAll(player_id_t player) { - return m_LosRevealAll; + std::map::const_iterator it; + + // Special player value can force reveal-all for every player + it = m_LosRevealAll.find(-1); + if (it != m_LosRevealAll.end() && it->second) + return true; + + // Otherwise check the player-specific flag + it = m_LosRevealAll.find(player); + if (it != m_LosRevealAll.end() && it->second) + return true; + + return false; } virtual void SetLosCircular(bool enabled) @@ -1181,11 +1192,11 @@ public: } } - virtual i32 GetPercentMapExplored(player_id_t playerId) + virtual i32 GetPercentMapExplored(player_id_t player) { i32 exploredVertices = 0; i32 overallVisibleVertices = 0; - CLosQuerier los(playerId, m_LosState, m_TerrainVerticesPerSide); + CLosQuerier los(player, m_LosState, m_TerrainVerticesPerSide); for (i32 j = 0; j < m_TerrainVerticesPerSide; j++) { diff --git a/source/simulation2/components/ICmpRangeManager.cpp b/source/simulation2/components/ICmpRangeManager.cpp index a0dbc9801a..3350b588e4 100644 --- a/source/simulation2/components/ICmpRangeManager.cpp +++ b/source/simulation2/components/ICmpRangeManager.cpp @@ -40,10 +40,10 @@ DEFINE_INTERFACE_METHOD_1("DestroyActiveQuery", void, ICmpRangeManager, DestroyA DEFINE_INTERFACE_METHOD_1("EnableActiveQuery", void, ICmpRangeManager, EnableActiveQuery, ICmpRangeManager::tag_t) DEFINE_INTERFACE_METHOD_1("DisableActiveQuery", void, ICmpRangeManager, DisableActiveQuery, ICmpRangeManager::tag_t) DEFINE_INTERFACE_METHOD_1("ResetActiveQuery", std::vector, ICmpRangeManager, ResetActiveQuery, ICmpRangeManager::tag_t) -DEFINE_INTERFACE_METHOD_1("GetEntitiesByPlayer", std::vector, ICmpRangeManager, GetEntitiesByPlayer, int) +DEFINE_INTERFACE_METHOD_1("GetEntitiesByPlayer", std::vector, ICmpRangeManager, GetEntitiesByPlayer, player_id_t) DEFINE_INTERFACE_METHOD_1("SetDebugOverlay", void, ICmpRangeManager, SetDebugOverlay, bool) -DEFINE_INTERFACE_METHOD_1("SetLosRevealAll", void, ICmpRangeManager, SetLosRevealAll, bool) -DEFINE_INTERFACE_METHOD_2("GetLosVisibility", std::string, ICmpRangeManager, GetLosVisibility_wrapper, entity_id_t, int) +DEFINE_INTERFACE_METHOD_2("SetLosRevealAll", void, ICmpRangeManager, SetLosRevealAll, player_id_t, bool) +DEFINE_INTERFACE_METHOD_2("GetLosVisibility", std::string, ICmpRangeManager, GetLosVisibility_wrapper, entity_id_t, player_id_t) DEFINE_INTERFACE_METHOD_1("SetLosCircular", void, ICmpRangeManager, SetLosCircular, bool) DEFINE_INTERFACE_METHOD_0("GetLosCircular", bool, ICmpRangeManager, GetLosCircular) DEFINE_INTERFACE_METHOD_1("GetPercentMapExplored", i32, ICmpRangeManager, GetPercentMapExplored, player_id_t) diff --git a/source/simulation2/components/ICmpRangeManager.h b/source/simulation2/components/ICmpRangeManager.h index a5e317e29b..e5d97eb99c 100644 --- a/source/simulation2/components/ICmpRangeManager.h +++ b/source/simulation2/components/ICmpRangeManager.h @@ -135,7 +135,7 @@ public: * Maybe it should be extended to be more like ExecuteQuery without * the range parameter.) */ - virtual std::vector GetEntitiesByPlayer(int playerId) = 0; + virtual std::vector GetEntitiesByPlayer(player_id_t player) = 0; /** * Toggle the rendering of debug info. @@ -171,7 +171,7 @@ public: friend class CCmpRangeManager; friend class TestLOSTexture; - CLosQuerier(int player, const std::vector& data, ssize_t verticesPerSide) : + CLosQuerier(player_id_t player, const std::vector& data, ssize_t verticesPerSide) : m_Data(&data[0]), m_VerticesPerSide(verticesPerSide) { if (player > 0 && player <= 16) @@ -254,30 +254,31 @@ public: /** * Returns a CLosQuerier for checking whether vertex positions are visible to the given player. */ - virtual CLosQuerier GetLosQuerier(int player) = 0; + virtual CLosQuerier GetLosQuerier(player_id_t player) = 0; /** * Returns the visibility status of the given entity, with respect to the given player. * Returns VIS_HIDDEN if the entity doesn't exist or is not in the world. * This respects the GetLosRevealAll flag. */ - virtual ELosVisibility GetLosVisibility(entity_id_t ent, int player) = 0; + virtual ELosVisibility GetLosVisibility(entity_id_t ent, player_id_t player) = 0; /** * GetLosVisibility wrapped for script calls. * Returns "hidden", "fogged" or "visible". */ - std::string GetLosVisibility_wrapper(entity_id_t ent, int player); + std::string GetLosVisibility_wrapper(entity_id_t ent, player_id_t player); /** - * Set globally whether the whole map should be made visible. + * Set whether the whole map should be made visible to the given player. + * If player is -1, the map will be made visible to all players. */ - virtual void SetLosRevealAll(bool enabled) = 0; + virtual void SetLosRevealAll(player_id_t player, bool enabled) = 0; /** * Returns whether the whole map has been made visible to the given player. */ - virtual bool GetLosRevealAll(int player) = 0; + virtual bool GetLosRevealAll(player_id_t player) = 0; /** * Set the LOS to be restricted to a circular map. @@ -290,9 +291,9 @@ public: virtual bool GetLosCircular() = 0; /** - * Get percent map explored statistics for specified player + * Get percent map explored statistics for specified player. */ - virtual i32 GetPercentMapExplored(player_id_t playerId) = 0; + virtual i32 GetPercentMapExplored(player_id_t player) = 0; DECLARE_INTERFACE_TYPE(RangeManager) }; diff --git a/source/simulation2/serialization/SerializeTemplates.h b/source/simulation2/serialization/SerializeTemplates.h index 16bdf8ca1f..9898d6f034 100644 --- a/source/simulation2/serialization/SerializeTemplates.h +++ b/source/simulation2/serialization/SerializeTemplates.h @@ -114,6 +114,32 @@ struct SerializeU32_Unbounded } }; +struct SerializeI32_Unbounded +{ + void operator()(ISerializer& serialize, const char* name, i32 value) + { + serialize.NumberI32_Unbounded(name, value); + } + + void operator()(IDeserializer& deserialize, const char* name, i32& value) + { + deserialize.NumberI32_Unbounded(name, value); + } +}; + +struct SerializeBool +{ + void operator()(ISerializer& serialize, const char* name, bool value) + { + serialize.Bool(name, value); + } + + void operator()(IDeserializer& deserialize, const char* name, bool& value) + { + deserialize.Bool(name, value); + } +}; + struct SerializeScriptVal { void operator()(ISerializer& serialize, const char* name, CScriptValRooted value) diff --git a/source/tools/atlas/GameInterface/ActorViewer.cpp b/source/tools/atlas/GameInterface/ActorViewer.cpp index 46ab493a9f..89b433be36 100644 --- a/source/tools/atlas/GameInterface/ActorViewer.cpp +++ b/source/tools/atlas/GameInterface/ActorViewer.cpp @@ -152,7 +152,7 @@ ActorViewer::ActorViewer() CmpPtr cmpRangeManager(m.Simulation2, SYSTEM_ENTITY); if (!cmpRangeManager.null()) - cmpRangeManager->SetLosRevealAll(true); + cmpRangeManager->SetLosRevealAll(-1, true); } ActorViewer::~ActorViewer() diff --git a/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp index 4d959a56a1..ddb1e9567e 100644 --- a/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp @@ -69,7 +69,7 @@ namespace // Disable fog-of-war CmpPtr cmpRangeManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY); if (!cmpRangeManager.null()) - cmpRangeManager->SetLosRevealAll(true); + cmpRangeManager->SetLosRevealAll(-1, true); } }