diff --git a/binaries/data/mods/public/simulation/components/Visibility.js b/binaries/data/mods/public/simulation/components/Visibility.js
new file mode 100644
index 0000000000..0b137ca18c
--- /dev/null
+++ b/binaries/data/mods/public/simulation/components/Visibility.js
@@ -0,0 +1,59 @@
+const VIS_HIDDEN = 0;
+const VIS_FOGGED = 1;
+const VIS_VISIBLE = 2;
+
+function Visibility() {}
+
+Visibility.prototype.Schema =
+ "";
+
+Visibility.prototype.Init = function()
+{
+
+};
+
+/**
+ * This function is called for entities in explored territory.
+ * isOutsideFog: true if we're in the vision range of a unit, false otherwise
+ * forceRetainInFog: useful for previewed entities, see the RangeManager system component documentation
+ */
+Visibility.prototype.GetLosVisibility = function(player, isOutsideFog, forceRetainInFog)
+{
+ if (isOutsideFog)
+ return VIS_VISIBLE;
+
+ // Fogged if the 'retain in fog' flag is set, and in a non-visible explored region
+ var cmpVision = Engine.QueryInterface(this.entity, IID_Vision);
+ if (!forceRetainInFog && !(cmpVision && cmpVision.GetRetainInFog()))
+ return VIS_HIDDEN;
+
+ var cmpMirage = Engine.QueryInterface(this.entity, IID_Mirage);
+ if (cmpMirage && cmpMirage.GetPlayer() == player)
+ return VIS_FOGGED;
+
+ var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
+ if (!cmpOwnership)
+ return VIS_FOGGED;
+
+ if (cmpOwnership.GetOwner() == player)
+ {
+ var cmpFogging = Engine.QueryInterface(this.entity, IID_Fogging);
+ if (!cmpFogging)
+ return VIS_FOGGED;
+
+ // Fogged entities must not disappear while the mirage is not ready
+ if (!cmpFogging.IsMiraged(player))
+ return VIS_FOGGED;
+
+ return VIS_HIDDEN;
+ }
+
+ // Fogged entities must not disappear while the mirage is not ready
+ var cmpFogging = Engine.QueryInterface(this.entity, IID_Fogging);
+ if (cmpFogging && cmpFogging.WasSeen(player) && !cmpFogging.IsMiraged(player))
+ return VIS_FOGGED;
+
+ return VIS_HIDDEN;
+};
+
+Engine.RegisterComponentType(IID_Visibility, "Visibility", Visibility);
diff --git a/binaries/data/mods/public/simulation/templates/template_gaia.xml b/binaries/data/mods/public/simulation/templates/template_gaia.xml
index 7a5f54b1c0..5acbdb1ff5 100644
--- a/binaries/data/mods/public/simulation/templates/template_gaia.xml
+++ b/binaries/data/mods/public/simulation/templates/template_gaia.xml
@@ -20,6 +20,7 @@
0.333
5.0
+
0
true
diff --git a/binaries/data/mods/public/simulation/templates/template_structure.xml b/binaries/data/mods/public/simulation/templates/template_structure.xml
index 47cc0efea7..c1cf8cfd15 100644
--- a/binaries/data/mods/public/simulation/templates/template_structure.xml
+++ b/binaries/data/mods/public/simulation/templates/template_structure.xml
@@ -101,6 +101,7 @@
5
+
40
true
diff --git a/binaries/data/mods/public/simulation/templates/template_unit.xml b/binaries/data/mods/public/simulation/templates/template_unit.xml
index 131fc734ed..79ad81a10d 100644
--- a/binaries/data/mods/public/simulation/templates/template_unit.xml
+++ b/binaries/data/mods/public/simulation/templates/template_unit.xml
@@ -104,6 +104,7 @@
default
default
+
10
false
diff --git a/source/ps/TemplateLoader.cpp b/source/ps/TemplateLoader.cpp
index 3c985fc829..07ceea6c5b 100644
--- a/source/ps/TemplateLoader.cpp
+++ b/source/ps/TemplateLoader.cpp
@@ -352,6 +352,7 @@ void CTemplateLoader::CopyPreviewSubset(CParamNode& out, const CParamNode& in, b
permittedComponentTypes.insert("Identity");
permittedComponentTypes.insert("Ownership");
permittedComponentTypes.insert("Position");
+ permittedComponentTypes.insert("Visibility");
permittedComponentTypes.insert("VisualActor");
permittedComponentTypes.insert("Footprint");
permittedComponentTypes.insert("Obstruction");
@@ -408,6 +409,7 @@ void CTemplateLoader::CopyMirageSubset(CParamNode& out, const CParamNode& in)
permittedComponentTypes.insert("Ownership");
permittedComponentTypes.insert("Position");
permittedComponentTypes.insert("Selectable");
+ permittedComponentTypes.insert("Visibility");
permittedComponentTypes.insert("VisualActor");
CParamNode::LoadXMLString(out, "");
@@ -454,6 +456,7 @@ void CTemplateLoader::CopyFoundationSubset(CParamNode& out, const CParamNode& in
permittedComponentTypes.insert("Decay");
permittedComponentTypes.insert("Cost");
permittedComponentTypes.insert("Sound");
+ permittedComponentTypes.insert("Visibility");
permittedComponentTypes.insert("Vision");
permittedComponentTypes.insert("AIProxy");
permittedComponentTypes.insert("RallyPoint");
diff --git a/source/simulation2/TypeList.h b/source/simulation2/TypeList.h
index eb5ac6a0ad..7b71ce1f46 100644
--- a/source/simulation2/TypeList.h
+++ b/source/simulation2/TypeList.h
@@ -174,6 +174,9 @@ COMPONENT(UnitMotionScripted)
INTERFACE(UnitRenderer)
COMPONENT(UnitRenderer)
+INTERFACE(Visibility)
+COMPONENT(VisibilityScripted)
+
INTERFACE(Vision)
COMPONENT(Vision)
diff --git a/source/simulation2/components/CCmpRangeManager.cpp b/source/simulation2/components/CCmpRangeManager.cpp
index a0df174e86..1dfaef1915 100644
--- a/source/simulation2/components/CCmpRangeManager.cpp
+++ b/source/simulation2/components/CCmpRangeManager.cpp
@@ -28,6 +28,7 @@
#include "simulation2/components/ICmpOwnership.h"
#include "simulation2/components/ICmpPosition.h"
#include "simulation2/components/ICmpTerritoryManager.h"
+#include "simulation2/components/ICmpVisibility.h"
#include "simulation2/components/ICmpVision.h"
#include "simulation2/components/ICmpWaterManager.h"
#include "simulation2/helpers/Render.h"
@@ -1377,10 +1378,6 @@ public:
virtual ELosVisibility GetLosVisibility(CEntityHandle ent, player_id_t player, bool forceRetainInFog)
{
- // This function provides the real visibility of any entity (even local ones) at any time.
- // The m_EntityData visibility is updated at most once per turn with this function's return value
- // and must not be used for rendering
-
// Entities not with positions in the world are never visible
if (ent.GetId() == INVALID_ENTITY)
return VIS_HIDDEN;
@@ -1409,42 +1406,21 @@ public:
// Visible if within a visible region
CLosQuerier los(GetSharedLosMask(player), m_LosState, m_TerrainVerticesPerSide);
+ if (!los.IsExplored(i, j))
+ return VIS_HIDDEN;
+
+ // Try to ask the Visibility component of the entity, if any
+ CmpPtr cmpVisibility(ent);
+ if (cmpVisibility)
+ return cmpVisibility->GetLosVisibility(player, los.IsVisible(i, j), forceRetainInFog);
+
+ // Default behaviour
if (los.IsVisible(i, j))
return VIS_VISIBLE;
-
- if (!los.IsExplored(i, j))
- return VIS_HIDDEN;
-
- // Fogged if the 'retain in fog' flag is set, and in a non-visible explored region
- CmpPtr cmpVision(ent);
- if (!forceRetainInFog && !(cmpVision && cmpVision->GetRetainInFog()))
- return VIS_HIDDEN;
-
- if (cmpMirage && cmpMirage->GetPlayer() == player)
- return VIS_FOGGED;
-
- CmpPtr cmpOwnership(ent);
- if (!cmpOwnership)
- return VIS_VISIBLE;
- if (cmpOwnership->GetOwner() == player)
- {
- CmpPtr cmpFogging(ent);
- if (!cmpFogging)
- return VIS_VISIBLE;
-
- // Fogged entities must not disappear while the mirage is not ready
- if (!cmpFogging->IsMiraged(player))
- return VIS_FOGGED;
-
- return VIS_HIDDEN;
- }
-
- // Fogged entities must not disappear while the mirage is not ready
- CmpPtr cmpFogging(ent);
- if (cmpFogging && cmpFogging->WasSeen(player) && !cmpFogging->IsMiraged(player))
+ if (forceRetainInFog)
return VIS_FOGGED;
-
+
return VIS_HIDDEN;
}
diff --git a/source/simulation2/components/ICmpVisibility.cpp b/source/simulation2/components/ICmpVisibility.cpp
new file mode 100644
index 0000000000..d2963f991c
--- /dev/null
+++ b/source/simulation2/components/ICmpVisibility.cpp
@@ -0,0 +1,52 @@
+/* Copyright (C) 2014 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D. If not, see .
+ */
+
+#include "precompiled.h"
+
+#include "ICmpVisibility.h"
+
+#include "simulation2/scripting/ScriptComponent.h"
+#include "simulation2/system/InterfaceScripted.h"
+
+BEGIN_INTERFACE_WRAPPER(Visibility)
+END_INTERFACE_WRAPPER(Visibility)
+
+class CCmpVisibilityScripted : public ICmpVisibility
+{
+public:
+ DEFAULT_SCRIPT_WRAPPER(VisibilityScripted)
+
+ virtual ICmpRangeManager::ELosVisibility GetLosVisibility(player_id_t player, bool isOutsideFog, bool forceRetainInFog)
+ {
+ int visibility = m_Script.Call("GetLosVisibility", player, isOutsideFog, forceRetainInFog);
+
+ switch (visibility)
+ {
+ case ICmpRangeManager::VIS_HIDDEN:
+ return ICmpRangeManager::VIS_HIDDEN;
+ case ICmpRangeManager::VIS_FOGGED:
+ return ICmpRangeManager::VIS_FOGGED;
+ case ICmpRangeManager::VIS_VISIBLE:
+ return ICmpRangeManager::VIS_VISIBLE;
+ default:
+ LOGERROR(L"Received the invalid visibility value %d from the Visibility scripted component!", visibility);
+ return ICmpRangeManager::VIS_HIDDEN;
+ }
+ }
+};
+
+REGISTER_COMPONENT_SCRIPT_WRAPPER(VisibilityScripted)
diff --git a/source/simulation2/components/ICmpVisibility.h b/source/simulation2/components/ICmpVisibility.h
new file mode 100644
index 0000000000..15f30efa21
--- /dev/null
+++ b/source/simulation2/components/ICmpVisibility.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2014 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D. If not, see .
+ */
+
+#ifndef INCLUDED_ICMPVISIBILITY
+#define INCLUDED_ICMPVISIBILITY
+
+#include "simulation2/system/Interface.h"
+
+#include "simulation2/components/ICmpRangeManager.h"
+
+class ICmpVisibility : public IComponent
+{
+public:
+ virtual ICmpRangeManager::ELosVisibility GetLosVisibility(player_id_t player, bool isOutsideFog, bool forceRetainInFog) = 0;
+
+ DECLARE_INTERFACE_TYPE(Visibility)
+};
+
+#endif // INCLUDED_ICMPVISIBILITY