1
0
forked from 0ad/0ad

Fix highlighting of obstructed building placement previews.

Prevent building in non-visible areas.
Fixes #594.

This was SVN commit r8272.
This commit is contained in:
Ykkrosh 2010-10-04 17:34:33 +00:00
parent 6b5b35c245
commit ab77ec40e4
15 changed files with 107 additions and 29 deletions

View File

@ -331,8 +331,10 @@ GuiInterface.prototype.SetBuildingPlacementPreview = function(player, cmd)
if (this.placementEntity)
{
var ent = this.placementEntity[1];
// Move the preview into the right location
var pos = Engine.QueryInterface(this.placementEntity[1], IID_Position);
var pos = Engine.QueryInterface(ent, IID_Position);
if (pos)
{
pos.JumpTo(cmd.x, cmd.z);
@ -340,21 +342,26 @@ GuiInterface.prototype.SetBuildingPlacementPreview = function(player, cmd)
}
// Check whether it's obstructed by other entities
var cmpObstruction = Engine.QueryInterface(this.placementEntity[1], IID_Obstruction);
var cmpObstruction = Engine.QueryInterface(ent, IID_Obstruction);
var colliding = (cmpObstruction && cmpObstruction.CheckCollisions());
// Set it to a red shade if this is an obstructed location
var cmpVisual = Engine.QueryInterface(this.placementEntity[1], IID_Visual);
// Check whether it's in a visible region
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
var visible = (cmpRangeManager.GetLosVisibility(ent, player) == "visible");
var ok = (!colliding && visible);
// Set it to a red shade if this is an invalid location
var cmpVisual = Engine.QueryInterface(ent, IID_Visual);
if (cmpVisual)
{
if (colliding)
if (!ok)
cmpVisual.SetShadingColour(1.4, 0.4, 0.4, 1);
else
cmpVisual.SetShadingColour(1, 1, 1, 1);
}
if (!colliding)
return true;
return ok;
}
return false;

View File

@ -72,6 +72,7 @@ function ProcessCommand(player, cmd)
cmpPosition.JumpTo(cmd.x, cmd.z);
cmpPosition.SetYRotation(cmd.angle);
// Check whether it's obstructed by other entities
var cmpObstruction = Engine.QueryInterface(ent, IID_Obstruction);
if (cmpObstruction && cmpObstruction.CheckCollisions())
{
@ -83,14 +84,21 @@ function ProcessCommand(player, cmd)
break;
}
// Check whether it's in a visible region
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
var visible = (cmpRangeManager.GetLosVisibility(ent, player) == "visible");
if (!visible)
{
// TODO: report error to player (the building site was not visible)
Engine.DestroyEntity(ent);
break;
}
var cmpCost = Engine.QueryInterface(ent, IID_Cost);
if (!cmpPlayer.TrySubtractResources(cmpCost.GetResourceCosts()))
{
// TODO: report error to player (they ran out of resources)
// Remove the foundation because the construction was aborted
Engine.DestroyEntity(ent);
break;
}

View File

@ -7,6 +7,7 @@
<Vision>
<Range>0</Range>
<RetainInFog>true</RetainInFog>
<AlwaysVisible>false</AlwaysVisible>
</Vision>
<StatusBars>
<BarWidth>2.0</BarWidth>

View File

@ -52,6 +52,7 @@
<Vision>
<Range>36</Range>
<RetainInFog>true</RetainInFog>
<AlwaysVisible>false</AlwaysVisible>
</Vision>
<RallyPoint/>
<Sound>

View File

@ -20,6 +20,8 @@
<Static width="32.0" depth="32.0"/>
</Obstruction>
<Vision>
<Range>0</Range>
<RetainInFog>true</RetainInFog>
<AlwaysVisible>false</AlwaysVisible>
</Vision>
</Entity>

View File

@ -70,5 +70,6 @@
<Vision>
<Range>24</Range>
<RetainInFog>false</RetainInFog>
<AlwaysVisible>false</AlwaysVisible>
</Vision>
</Entity>

View File

@ -663,13 +663,17 @@ private:
{
// (We can't use m_EntityData since this needs to handle LOCAL entities too)
// Entities not with positions in the world are never visible
CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), ent);
if (cmpPosition.null() || !cmpPosition->IsInWorld())
return VIS_HIDDEN;
// Global flag makes all positioned entities visible
if (m_LosRevealAll)
return VIS_VISIBLE;
// Visible if within a visible region
CFixedVector2D pos = cmpPosition->GetPosition2D();
CLosQuerier los(player, m_LosState, m_TerrainVerticesPerSide);
@ -680,6 +684,7 @@ private:
if (los.IsVisible(i, j))
return VIS_VISIBLE;
// Fogged if the 'retain in fog' flag is set, and in a non-visible explored region
if (los.IsExplored(i, j))
{
CmpPtr<ICmpVision> cmpVision(GetSimContext(), ent);
@ -687,6 +692,7 @@ private:
return VIS_FOGGED;
}
// Otherwise not visible
return VIS_HIDDEN;
}

View File

@ -435,8 +435,8 @@ void CCmpTemplateManager::CopyPreviewSubset(CParamNode& out, const CParamNode& i
if (!corpse)
{
// Previews should always be visible in fog-of-war
CParamNode::LoadXMLString(out, "<Entity><Vision><Range>0</Range><RetainInFog>true</RetainInFog></Vision></Entity>");
// Previews should always be visible in fog-of-war/etc
CParamNode::LoadXMLString(out, "<Entity><Vision><Range>0</Range><RetainInFog>false</RetainInFog><AlwaysVisible>true</AlwaysVisible></Vision></Entity>");
}
if (corpse)

View File

@ -31,6 +31,7 @@ public:
entity_pos_t m_Range;
bool m_RetainInFog;
bool m_AlwaysVisible;
static std::string GetSchema()
{
@ -40,6 +41,9 @@ public:
"</element>"
"<element name='RetainInFog'>"
"<data type='boolean'/>"
"</element>"
"<element name='AlwaysVisible'>"
"<data type='boolean'/>"
"</element>";
}
@ -47,6 +51,7 @@ public:
{
m_Range = paramNode.GetChild("Range").ToFixed();
m_RetainInFog = paramNode.GetChild("RetainInFog").ToBool();
m_AlwaysVisible = paramNode.GetChild("AlwaysVisible").ToBool();
}
virtual void Deinit(const CSimContext& UNUSED(context))
@ -71,6 +76,11 @@ public:
{
return m_RetainInFog;
}
virtual bool GetAlwaysVisible()
{
return m_AlwaysVisible;
}
};
REGISTER_COMPONENT_TYPE(Vision)

View File

@ -54,6 +54,8 @@ public:
std::wstring m_ActorName;
CUnit* m_Unit;
fixed m_R, m_G, m_B; // shading colour
ICmpRangeManager::ELosVisibility m_Visibility; // only valid between Interpolate and RenderSubmit
// Current animation state
@ -106,6 +108,8 @@ public:
else
m_ActorName = paramNode.GetChild("Actor").ToString();
m_R = m_G = m_B = fixed::FromInt(1);
std::set<CStr> selections;
m_Unit = context.GetUnitManager().CreateUnit(m_ActorName, selections);
if (!m_Unit)
@ -280,10 +284,10 @@ public:
virtual void SetShadingColour(fixed r, fixed g, fixed b, fixed a)
{
if (!m_Unit)
return;
m_Unit->GetModel().SetShadingColor(CColor(r.ToFloat(), g.ToFloat(), b.ToFloat(), a.ToFloat()));
m_R = r;
m_G = g;
m_B = b;
UNUSED2(a); // TODO: why is this even an argument?
}
virtual void Hotload(const std::wstring& name)
@ -368,8 +372,18 @@ void CCmpVisualActor::Interpolate(float frameTime, float frameOffset)
return;
}
CmpPtr<ICmpRangeManager> cmpRangeManager(GetSimContext(), SYSTEM_ENTITY);
m_Visibility = cmpRangeManager->GetLosVisibility(GetEntityId(), GetSimContext().GetCurrentDisplayedPlayer());
// The 'always visible' flag means we should always render the unit
// (regardless of whether the LOS system thinks it's visible)
CmpPtr<ICmpVision> cmpVision(GetSimContext(), GetEntityId());
if (!cmpVision.null() && cmpVision->GetAlwaysVisible())
{
m_Visibility = ICmpRangeManager::VIS_VISIBLE;
}
else
{
CmpPtr<ICmpRangeManager> cmpRangeManager(GetSimContext(), SYSTEM_ENTITY);
m_Visibility = cmpRangeManager->GetLosVisibility(GetEntityId(), GetSimContext().GetCurrentDisplayedPlayer());
}
// Even if HIDDEN due to LOS, we need to set up the transforms
// so that projectiles will be launched from the right place
@ -378,8 +392,21 @@ void CCmpVisualActor::Interpolate(float frameTime, float frameOffset)
CMatrix3D transform(cmpPosition->GetInterpolatedTransform(frameOffset, floating));
m_Unit->GetModel().SetTransform(transform);
CModel& model = m_Unit->GetModel();
model.SetTransform(transform);
m_Unit->UpdateModel(frameTime);
// If not hidden, then we need to set up some extra state for rendering
if (m_Visibility != ICmpRangeManager::VIS_HIDDEN)
{
model.ValidatePosition();
if (m_Visibility == ICmpRangeManager::VIS_FOGGED)
model.SetShadingColor(CColor(0.7f * m_R.ToFloat(), 0.7f * m_G.ToFloat(), 0.7f * m_B.ToFloat(), 1.0f));
else
model.SetShadingColor(CColor(m_R.ToFloat(), m_G.ToFloat(), m_B.ToFloat(), 1.0f));
}
}
void CCmpVisualActor::RenderSubmit(SceneCollector& collector, const CFrustum& frustum, bool culling)
@ -392,15 +419,8 @@ void CCmpVisualActor::RenderSubmit(SceneCollector& collector, const CFrustum& fr
CModel& model = m_Unit->GetModel();
model.ValidatePosition();
if (culling && !frustum.IsBoxVisible(CVector3D(0, 0, 0), model.GetBounds()))
return;
if (m_Visibility == ICmpRangeManager::VIS_FOGGED)
model.SetShadingColor(CColor(0.7f, 0.7f, 0.7f, 1.0f));
else
model.SetShadingColor(CColor(1.0f, 1.0f, 1.0f, 1.0f));
collector.SubmitRecursive(&model);
}

View File

@ -21,6 +21,18 @@
#include "simulation2/system/InterfaceScripted.h"
std::string ICmpRangeManager::GetLosVisibility_wrapper(entity_id_t ent, int player)
{
ELosVisibility visibility = GetLosVisibility(ent, player);
switch (visibility)
{
case VIS_HIDDEN: return "hidden";
case VIS_FOGGED: return "fogged";
case VIS_VISIBLE: return "visible";
default: return "error"; // should never happen
}
}
BEGIN_INTERFACE_WRAPPER(RangeManager)
DEFINE_INTERFACE_METHOD_4("ExecuteQuery", std::vector<entity_id_t>, ICmpRangeManager, ExecuteQuery, entity_id_t, entity_pos_t, std::vector<int>, int)
DEFINE_INTERFACE_METHOD_4("CreateActiveQuery", ICmpRangeManager::tag_t, ICmpRangeManager, CreateActiveQuery, entity_id_t, entity_pos_t, std::vector<int>, int)
@ -31,4 +43,5 @@ DEFINE_INTERFACE_METHOD_1("ResetActiveQuery", std::vector<entity_id_t>, ICmpRang
DEFINE_INTERFACE_METHOD_1("GetEntitiesByPlayer", std::vector<entity_id_t>, ICmpRangeManager, GetEntitiesByPlayer, int)
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)
END_INTERFACE_WRAPPER(RangeManager)

View File

@ -228,6 +228,12 @@ public:
*/
virtual ELosVisibility GetLosVisibility(entity_id_t ent, int player) = 0;
/**
* GetLosVisibility wrapped for script calls.
* Returns "hidden", "fogged" or "visible".
*/
std::string GetLosVisibility_wrapper(entity_id_t ent, int player);
/**
* Set globally whether the whole map should be made visible.
*/

View File

@ -24,4 +24,5 @@
BEGIN_INTERFACE_WRAPPER(Vision)
DEFINE_INTERFACE_METHOD_0("GetRange", entity_pos_t, ICmpVision, GetRange)
DEFINE_INTERFACE_METHOD_0("GetRetainInFog", bool, ICmpVision, GetRetainInFog)
DEFINE_INTERFACE_METHOD_0("GetAlwaysVisible", bool, ICmpVision, GetAlwaysVisible)
END_INTERFACE_WRAPPER(Vision)

View File

@ -32,6 +32,8 @@ public:
virtual bool GetRetainInFog() = 0;
virtual bool GetAlwaysVisible() = 0;
DECLARE_INTERFACE_TYPE(Vision)
};

View File

@ -83,7 +83,7 @@ public:
TS_ASSERT(preview != NULL);
TS_ASSERT_WSTR_EQUALS(preview->ToXML(),
L"<Position><Altitude>0</Altitude><Anchor>upright</Anchor><Floating>false</Floating></Position>"
L"<Vision><Range>0</Range><RetainInFog>true</RetainInFog></Vision>"
L"<Vision><AlwaysVisible>true</AlwaysVisible><Range>0</Range><RetainInFog>false</RetainInFog></Vision>"
L"<VisualActor><Actor>example</Actor></VisualActor>");
const CParamNode* previewobstruct = tempMan->LoadTemplate(ent2, "preview|unitobstruct", -1);
@ -92,14 +92,14 @@ public:
L"<Footprint><Circle radius=\"4\"></Circle><Height>1.0</Height></Footprint>"
L"<Obstruction><Inactive></Inactive><Unit radius=\"4\"></Unit></Obstruction>"
L"<Position><Altitude>0</Altitude><Anchor>upright</Anchor><Floating>false</Floating></Position>"
L"<Vision><Range>0</Range><RetainInFog>true</RetainInFog></Vision>"
L"<Vision><AlwaysVisible>true</AlwaysVisible><Range>0</Range><RetainInFog>false</RetainInFog></Vision>"
L"<VisualActor><Actor>example</Actor></VisualActor>");
const CParamNode* previewactor = tempMan->LoadTemplate(ent2, "preview|actor|example2", -1);
TS_ASSERT(previewactor != NULL);
TS_ASSERT_WSTR_EQUALS(previewactor->ToXML(),
L"<Position><Altitude>0</Altitude><Anchor>upright</Anchor><Floating>false</Floating></Position>"
L"<Vision><Range>0</Range><RetainInFog>true</RetainInFog></Vision>"
L"<Vision><AlwaysVisible>true</AlwaysVisible><Range>0</Range><RetainInFog>false</RetainInFog></Vision>"
L"<VisualActor><Actor>example2</Actor></VisualActor>");
}