# Add rally points for newly-trained units, based on patch from evans.
Fixes #521. This was SVN commit r7849.
This commit is contained in:
parent
c39c4ac8d3
commit
07615310f2
@ -82,17 +82,35 @@ function determineAction(x, y)
|
||||
if (entState.player != player && !g_DevSettings.controlAll)
|
||||
return undefined;
|
||||
|
||||
// Work out whether the selection can have rally points
|
||||
var haveRallyPoints = selection.every(function(ent) {
|
||||
var entState = Engine.GuiInterfaceCall("GetEntityState", ent);
|
||||
return entState && entState.rallyPoint;
|
||||
});
|
||||
|
||||
var targets = Engine.PickEntitiesAtPoint(x, y);
|
||||
|
||||
// If there's no unit, just walk
|
||||
// If there's no target unit
|
||||
if (!targets.length)
|
||||
return {"type": "move"};
|
||||
{
|
||||
// If all selected entities are buildings,
|
||||
// set rally points, else make them walk
|
||||
if (haveRallyPoints)
|
||||
return {"type": "set-rallypoint"};
|
||||
else
|
||||
return {"type": "move"};
|
||||
}
|
||||
|
||||
// Look at the first targeted entity
|
||||
// (TODO: maybe we eventually want to look at more, and be more context-sensitive?
|
||||
// e.g. prefer to attack an enemy unit, even if some friendly units are closer to the mouse)
|
||||
var targetState = Engine.GuiInterfaceCall("GetEntityState", targets[0]);
|
||||
|
||||
// If we selected buildings with rally points, and then click on one of those selected
|
||||
// buildings, we should remove the rally point
|
||||
if (haveRallyPoints && selection.indexOf(targets[0]) != -1)
|
||||
return {"type": "unset-rallypoint"};
|
||||
|
||||
// Check if the target entity is a resource, foundation, or enemy unit.
|
||||
// Check if any entities in the selection can gather the requested resource, can build the foundation, or can attack the enemy
|
||||
for each (var entityID in selection)
|
||||
@ -499,6 +517,26 @@ function handleInputAfterGui(ev)
|
||||
Engine.PostNetworkCommand({"type": "gather", "entities": selection, "target": action.target, "queued": queued});
|
||||
return true;
|
||||
|
||||
case "set-rallypoint":
|
||||
var target = Engine.GetTerrainAtPoint(ev.x, ev.y);
|
||||
Engine.PostNetworkCommand({"type": "set-rallypoint", "entities": selection, "x": target.x, "z": target.z});
|
||||
// Display rally point at the new coordinates, to avoid display lag
|
||||
Engine.GuiInterfaceCall("DisplayRallyPoint", {
|
||||
"entities": selection,
|
||||
"x": target.x,
|
||||
"z": target.z
|
||||
});
|
||||
return true;
|
||||
|
||||
case "unset-rallypoint":
|
||||
var target = Engine.GetTerrainAtPoint(ev.x, ev.y);
|
||||
Engine.PostNetworkCommand({"type": "unset-rallypoint", "entities": selection});
|
||||
// Remove displayed rally point
|
||||
Engine.GuiInterfaceCall("DisplayRallyPoint", {
|
||||
"entities": []
|
||||
});
|
||||
return true;
|
||||
|
||||
default:
|
||||
throw new Error("Invalid action.type "+action.type);
|
||||
}
|
||||
@ -532,14 +570,11 @@ function handleInputAfterGui(ev)
|
||||
if (!ents.length)
|
||||
{
|
||||
g_Selection.reset();
|
||||
|
||||
inputState = INPUT_NORMAL;
|
||||
return true;
|
||||
}
|
||||
|
||||
g_Selection.reset();
|
||||
g_Selection.addList([ents[0]]);
|
||||
|
||||
inputState = INPUT_NORMAL;
|
||||
return true;
|
||||
}
|
||||
@ -675,4 +710,4 @@ function performCommand(entity, commandName)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +103,12 @@ function onTick()
|
||||
|
||||
// If the selection changed, we need to regenerate the sim display
|
||||
if (g_Selection.dirty)
|
||||
{
|
||||
onSimulationUpdate();
|
||||
|
||||
// Display rally points for selected buildings
|
||||
Engine.GuiInterfaceCall("DisplayRallyPoint", { "entities": g_Selection.toList() });
|
||||
}
|
||||
}
|
||||
|
||||
function onSimulationUpdate()
|
||||
|
@ -11,6 +11,7 @@ GuiInterface.prototype.Serialize = function()
|
||||
GuiInterface.prototype.Init = function()
|
||||
{
|
||||
this.placementEntity = undefined; // = undefined or [templateName, entityID]
|
||||
this.rallyPoints = undefined;
|
||||
};
|
||||
|
||||
GuiInterface.prototype.GetSimulationState = function(player)
|
||||
@ -124,6 +125,11 @@ GuiInterface.prototype.GetEntityState = function(player, ent)
|
||||
ret.resourceGatherRates = cmpResourceGatherer.GetGatherRates();
|
||||
}
|
||||
|
||||
var cmpRallyPoint = Engine.QueryInterface(ent, IID_RallyPoint);
|
||||
if (cmpRallyPoint)
|
||||
{
|
||||
ret.rallyPoint = { };
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
@ -169,6 +175,65 @@ GuiInterface.prototype.SetSelectionHighlight = function(player, cmd)
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Displays the rally point of a building
|
||||
*/
|
||||
GuiInterface.prototype.DisplayRallyPoint = function(player, cmd)
|
||||
{
|
||||
// If there are rally points already displayed, destroy them
|
||||
for each (var ent in this.rallyPoints)
|
||||
{
|
||||
// Hide it first (the destruction won't be instantaneous)
|
||||
var cmpPosition = Engine.QueryInterface(ent, IID_Position);
|
||||
cmpPosition.MoveOutOfWorld();
|
||||
|
||||
Engine.DestroyEntity(ent);
|
||||
}
|
||||
|
||||
this.rallyPoints = [];
|
||||
|
||||
var positions = [];
|
||||
// DisplayRallyPoints is called passing a list of entities for which
|
||||
// rally points must be displayed
|
||||
for each (var ent in cmd.entities)
|
||||
{
|
||||
var cmpRallyPoint = Engine.QueryInterface(ent, IID_RallyPoint);
|
||||
if (!cmpRallyPoint)
|
||||
continue;
|
||||
|
||||
// Verify the owner
|
||||
var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
|
||||
if (!cmpOwnership || cmpOwnership.GetOwner() != player)
|
||||
continue;
|
||||
|
||||
// If the command was passed an explicit position, use that and
|
||||
// override the real rally point position; otherwise use the real position
|
||||
var pos;
|
||||
if (cmd.x && cmd.z)
|
||||
pos = {"x": cmd.x, "z": cmd.z};
|
||||
else
|
||||
pos = cmpRallyPoint.GetPosition();
|
||||
|
||||
if (pos)
|
||||
{
|
||||
// TODO: it'd probably be nice if we could draw some kind of line
|
||||
// between the building and pos, to make the marker easy to find even
|
||||
// if it's a long way from the building
|
||||
|
||||
positions.push(pos);
|
||||
}
|
||||
}
|
||||
|
||||
// Add rally point entity for each building
|
||||
for each (var pos in positions)
|
||||
{
|
||||
var rallyPoint = Engine.AddLocalEntity("actor|props/special/common/waypoint_flag.xml");
|
||||
var cmpPosition = Engine.QueryInterface(rallyPoint, IID_Position);
|
||||
cmpPosition.JumpTo(pos.x, pos.z);
|
||||
this.rallyPoints.push(rallyPoint);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Display the building placement preview.
|
||||
* cmd.template is the name of the entity template, or "" to disable the preview.
|
||||
@ -269,6 +334,7 @@ var exposedFunctions = {
|
||||
"SetObstructionDebugOverlay": 1,
|
||||
"SetMotionDebugOverlay": 1,
|
||||
"SetRangeDebugOverlay": 1,
|
||||
"DisplayRallyPoint": 1
|
||||
};
|
||||
|
||||
GuiInterface.prototype.ScriptCall = function(player, name, args)
|
||||
|
@ -0,0 +1,29 @@
|
||||
function RallyPoint() {}
|
||||
|
||||
RallyPoint.prototype.Schema =
|
||||
"<a:component/><empty/>";
|
||||
|
||||
RallyPoint.prototype.Init = function()
|
||||
{
|
||||
this.pos = undefined;
|
||||
};
|
||||
|
||||
RallyPoint.prototype.SetPosition = function(x, z)
|
||||
{
|
||||
this.pos = {
|
||||
"x": x,
|
||||
"z": z
|
||||
}
|
||||
};
|
||||
|
||||
RallyPoint.prototype.Unset = function()
|
||||
{
|
||||
this.pos = undefined;
|
||||
};
|
||||
|
||||
RallyPoint.prototype.GetPosition = function()
|
||||
{
|
||||
return this.pos;
|
||||
};
|
||||
|
||||
Engine.RegisterComponentType(IID_RallyPoint, "RallyPoint", RallyPoint);
|
@ -158,7 +158,8 @@ TrainingQueue.prototype.SpawnUnits = function(templateName, count)
|
||||
var cmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint);
|
||||
var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
|
||||
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
||||
|
||||
var cmpRallyPoint = Engine.QueryInterface(this.entity, IID_RallyPoint);
|
||||
|
||||
for (var i = 0; i < count; ++i)
|
||||
{
|
||||
var ent = Engine.AddEntity(templateName);
|
||||
@ -180,7 +181,14 @@ TrainingQueue.prototype.SpawnUnits = function(templateName, count)
|
||||
var cmpNewOwnership = Engine.QueryInterface(ent, IID_Ownership);
|
||||
cmpNewOwnership.SetOwner(cmpOwnership.GetOwner());
|
||||
|
||||
// TODO: move to rally points
|
||||
// If a rally point is set, walk towards it
|
||||
var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
|
||||
if (cmpUnitAI && cmpRallyPoint)
|
||||
{
|
||||
var rallyPos = cmpRallyPoint.GetPosition();
|
||||
if (rallyPos)
|
||||
cmpUnitAI.Walk(rallyPos.x, rallyPos.z, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -0,0 +1 @@
|
||||
Engine.RegisterInterface("RallyPoint");
|
@ -3,6 +3,7 @@ Engine.LoadComponentScript("interfaces/Builder.js");
|
||||
Engine.LoadComponentScript("interfaces/DamageReceiver.js");
|
||||
Engine.LoadComponentScript("interfaces/Foundation.js");
|
||||
Engine.LoadComponentScript("interfaces/Health.js");
|
||||
Engine.LoadComponentScript("interfaces/RallyPoint.js");
|
||||
Engine.LoadComponentScript("interfaces/ResourceGatherer.js");
|
||||
Engine.LoadComponentScript("interfaces/ResourceSupply.js");
|
||||
Engine.LoadComponentScript("interfaces/TrainingQueue.js");
|
||||
|
@ -138,6 +138,24 @@ function ProcessCommand(player, cmd)
|
||||
|
||||
break;
|
||||
|
||||
case "set-rallypoint":
|
||||
for each (var ent in cmd.entities)
|
||||
{
|
||||
var cmpRallyPoint = Engine.QueryInterface(ent, IID_RallyPoint);
|
||||
if (cmpRallyPoint)
|
||||
cmpRallyPoint.SetPosition(cmd.x, cmd.z);
|
||||
}
|
||||
break;
|
||||
|
||||
case "unset-rallypoint":
|
||||
for each (var ent in cmd.entities)
|
||||
{
|
||||
var cmpRallyPoint = Engine.QueryInterface(ent, IID_RallyPoint);
|
||||
if (cmpRallyPoint)
|
||||
cmpRallyPoint.Unset();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
error("Ignoring unrecognised command type '" + cmd.type + "'");
|
||||
}
|
||||
|
@ -42,4 +42,5 @@
|
||||
<Range>36</Range>
|
||||
<RetainInFog>true</RetainInFog>
|
||||
</Vision>
|
||||
<RallyPoint/>
|
||||
</Entity>
|
||||
|
@ -51,6 +51,8 @@ public:
|
||||
std::wstring m_ActorName;
|
||||
CUnit* m_Unit;
|
||||
|
||||
bool m_Hidden; // only valid between Interpolate and RenderSubmit
|
||||
|
||||
// Current animation state
|
||||
std::string m_AnimName;
|
||||
bool m_AnimOnce;
|
||||
@ -60,11 +62,6 @@ public:
|
||||
|
||||
float m_AnimSyncRepeatTime; // 0.0 if not synced
|
||||
|
||||
CCmpVisualActor() :
|
||||
m_Unit(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
static std::string GetSchema()
|
||||
{
|
||||
return
|
||||
@ -93,6 +90,8 @@ public:
|
||||
|
||||
virtual void Init(const CSimContext& context, const CParamNode& paramNode)
|
||||
{
|
||||
m_Unit = NULL;
|
||||
|
||||
if (!context.HasUnitManager())
|
||||
return; // do nothing if graphics are disabled
|
||||
|
||||
@ -310,12 +309,15 @@ void CCmpVisualActor::Interpolate(const CSimContext& context, float frameTime, f
|
||||
if (cmpPosition.null())
|
||||
return;
|
||||
|
||||
// Disable rendering of the unit if it has no position
|
||||
if (!cmpPosition->IsInWorld())
|
||||
{
|
||||
// TODO: need to hide the unit from rendering
|
||||
m_Hidden = true;
|
||||
return;
|
||||
}
|
||||
|
||||
m_Hidden = false;
|
||||
|
||||
CMatrix3D transform(cmpPosition->GetInterpolatedTransform(frameOffset));
|
||||
|
||||
m_Unit->GetModel().SetTransform(transform);
|
||||
@ -327,6 +329,9 @@ void CCmpVisualActor::RenderSubmit(const CSimContext& UNUSED(context), SceneColl
|
||||
if (m_Unit == NULL)
|
||||
return;
|
||||
|
||||
if (m_Hidden)
|
||||
return;
|
||||
|
||||
// TODO: need to think about things like LOS here
|
||||
|
||||
CModel& model = m_Unit->GetModel();
|
||||
|
Loading…
Reference in New Issue
Block a user