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:
parent
6b5b35c245
commit
ab77ec40e4
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
<Vision>
|
||||
<Range>0</Range>
|
||||
<RetainInFog>true</RetainInFog>
|
||||
<AlwaysVisible>false</AlwaysVisible>
|
||||
</Vision>
|
||||
<StatusBars>
|
||||
<BarWidth>2.0</BarWidth>
|
||||
|
@ -52,6 +52,7 @@
|
||||
<Vision>
|
||||
<Range>36</Range>
|
||||
<RetainInFog>true</RetainInFog>
|
||||
<AlwaysVisible>false</AlwaysVisible>
|
||||
</Vision>
|
||||
<RallyPoint/>
|
||||
<Sound>
|
||||
|
@ -20,6 +20,8 @@
|
||||
<Static width="32.0" depth="32.0"/>
|
||||
</Obstruction>
|
||||
<Vision>
|
||||
<Range>0</Range>
|
||||
<RetainInFog>true</RetainInFog>
|
||||
<AlwaysVisible>false</AlwaysVisible>
|
||||
</Vision>
|
||||
</Entity>
|
||||
|
@ -70,5 +70,6 @@
|
||||
<Vision>
|
||||
<Range>24</Range>
|
||||
<RetainInFog>false</RetainInFog>
|
||||
<AlwaysVisible>false</AlwaysVisible>
|
||||
</Vision>
|
||||
</Entity>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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)
|
||||
|
@ -32,6 +32,8 @@ public:
|
||||
|
||||
virtual bool GetRetainInFog() = 0;
|
||||
|
||||
virtual bool GetAlwaysVisible() = 0;
|
||||
|
||||
DECLARE_INTERFACE_TYPE(Vision)
|
||||
};
|
||||
|
||||
|
@ -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>");
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user