1
0
forked from 0ad/0ad

# Add rally points for newly-trained units, based on patch from evans.

Fixes #521.

This was SVN commit r7849.
This commit is contained in:
Ykkrosh 2010-08-05 10:20:47 +00:00
parent c39c4ac8d3
commit 07615310f2
10 changed files with 183 additions and 14 deletions

View File

@ -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;
}
}
}
}

View File

@ -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()

View File

@ -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)

View File

@ -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);

View File

@ -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);
}
}
};

View File

@ -0,0 +1 @@
Engine.RegisterInterface("RallyPoint");

View File

@ -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");

View File

@ -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 + "'");
}

View File

@ -42,4 +42,5 @@
<Range>36</Range>
<RetainInFog>true</RetainInFog>
</Vision>
<RallyPoint/>
</Entity>

View File

@ -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();