Allows autogarrison of newly trained units, fixes #1044

This was SVN commit r14144.
This commit is contained in:
mimo 2013-11-11 15:37:16 +00:00
parent fad8f7fce0
commit 2102648f7c
5 changed files with 117 additions and 60 deletions

View file

@ -269,8 +269,9 @@ hotkey.selection.group.add.9 = "Shift+9"
hotkey.session.kill = Delete ; Destroy selected units
hotkey.session.stop = "H" ; Stop the current action
hotkey.session.attack = "Ctrl+Alt" ; Modifier to force attack instead of another action
hotkey.session.garrison = Ctrl ; Modifier to garrison when clicking on building
hotkey.session.attackmove = Ctrl ; Modifier to attackmove when clicking on a point
hotkey.session.garrison = Ctrl ; Modifier to garrison when clicking on building
hotkey.session.autorallypoint = Ctrl ; Modifier to set the rally point on the building itself
hotkey.session.queue = Shift ; Modifier to queue unit orders instead of replacing
hotkey.session.batchtrain = Shift ; Modifier to train units in batches
hotkey.session.massbarter = Shift ; Modifier to barter bunch of resources

View file

@ -295,10 +295,14 @@ function getActionInfo(action, target)
}
}
// Don't allow the rally point to be set on any of the currently selected entities
for (var i = 0; i < selection.length; i++)
if (target === selection[i])
return {"possible": false};
// Don't allow the rally point to be set on any of the currently selected entities (used for unset)
// except if the autorallypoint hotkey is pressed and the target can produce entities
if (!Engine.HotkeyIsPressed("session.autorallypoint") || !targetState.production || !targetState.production.entities.length)
{
for (var i = 0; i < selection.length; i++)
if (target === selection[i])
return {"possible": false};
}
return {"possible": true, "data": data, "position": targetState.position, "cursor": cursor, "tooltip": tooltip};
}
@ -1791,8 +1795,6 @@ function performCommand(entity, commandName)
if (entity)
{
var entState = GetEntityState(entity);
var template = GetTemplateData(entState.template);
var unitName = getEntityName(template);
var playerID = Engine.GetPlayerID();
var simState = GetSimState();

View file

@ -200,6 +200,19 @@ GarrisonHolder.prototype.AllowedToGarrison = function(entity)
* The timer for AutoHeal is started here
*/
GarrisonHolder.prototype.Garrison = function(entity)
{
var cmpPosition = Engine.QueryInterface(entity, IID_Position);
if (!cmpPosition)
return false;
if (!this.PerformGarrison(entity))
return false;
cmpPosition.MoveOutOfWorld();
return true;
};
GarrisonHolder.prototype.PerformGarrison = function(entity)
{
if (!this.HasEnoughHealth())
return false;
@ -216,10 +229,6 @@ GarrisonHolder.prototype.Garrison = function(entity)
if (this.GetGarrisonedEntitiesCount() + extraCount >= this.GetCapacity())
return false;
var cmpPosition = Engine.QueryInterface(entity, IID_Position);
if (!cmpPosition)
return false;
if (!this.timer && this.GetHealRate() > 0)
{
var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
@ -228,7 +237,6 @@ GarrisonHolder.prototype.Garrison = function(entity)
// Actual garrisoning happens here
this.entities.push(entity);
cmpPosition.MoveOutOfWorld();
this.UpdateGarrisonFlag();
var cmpProductionQueue = Engine.QueryInterface(entity, IID_ProductionQueue);
if (cmpProductionQueue)
@ -309,6 +317,9 @@ GarrisonHolder.prototype.OrderWalkToRallyPoint = function(entities)
if (rallyPos)
{
var commands = GetRallyPointCommands(cmpRallyPoint, entities);
// ignore the rally point if it is autogarrison
if (commands[0].type == "garrison" && commands[0].target == this.entity)
return;
for each (var com in commands)
{
ProcessCommand(cmpOwnership.GetOwner(), com);

View file

@ -442,8 +442,9 @@ ProductionQueue.prototype.OnDestroy = function()
};
/*
* This function creates the entities and places them in world if possible.
* returns the number of successfully spawned entities.
* This function creates the entities and places them in world if possible
* and returns the number of successfully created entities.
* (some of these entities may be garrisoned directly if autogarrison, the others are spawned).
*/
ProductionQueue.prototype.SpawnUnits = function(templateName, count, metadata)
{
@ -452,6 +453,7 @@ ProductionQueue.prototype.SpawnUnits = function(templateName, count, metadata)
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
var cmpRallyPoint = Engine.QueryInterface(this.entity, IID_RallyPoint);
var createdEnts = [];
var spawnedEnts = [];
if (this.entityCache.length == 0)
@ -476,35 +478,52 @@ ProductionQueue.prototype.SpawnUnits = function(templateName, count, metadata)
}
}
var cmpAutoGarrison = undefined;
if (cmpRallyPoint)
{
var data = cmpRallyPoint.GetData()[0];
if (data && data.target == this.entity && data.command == "garrison")
cmpAutoGarrison = Engine.QueryInterface(this.entity, IID_GarrisonHolder);
}
for (var i = 0; i < count; ++i)
{
var ent = this.entityCache[0];
var pos = cmpFootprint.PickSpawnPoint(ent);
if (pos.y < 0)
var cmpNewOwnership = Engine.QueryInterface(ent, IID_Ownership);
cmpNewOwnership.SetOwner(cmpOwnership.GetOwner());
if (cmpAutoGarrison && cmpAutoGarrison.PerformGarrison(ent))
{
// Fail: there wasn't any space to spawn the unit
break;
var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
cmpUnitAI.Autogarrison();
}
else
{
// Successfully spawned
var cmpNewPosition = Engine.QueryInterface(ent, IID_Position);
cmpNewPosition.JumpTo(pos.x, pos.z);
// TODO: what direction should they face in?
var cmpNewOwnership = Engine.QueryInterface(ent, IID_Ownership);
cmpNewOwnership.SetOwner(cmpOwnership.GetOwner());
var cmpPlayerStatisticsTracker = QueryOwnerInterface(this.entity, IID_StatisticsTracker);
cmpPlayerStatisticsTracker.IncreaseTrainedUnitsCounter();
// Play a sound, but only for the first in the batch (to avoid nasty phasing effects)
if (spawnedEnts.length == 0)
PlaySound("trained", ent);
this.entityCache.shift();
spawnedEnts.push(ent);
var pos = cmpFootprint.PickSpawnPoint(ent);
if (pos.y < 0)
{
// Fail: there wasn't any space to spawn the unit
break;
}
else
{
// Successfully spawned
var cmpNewPosition = Engine.QueryInterface(ent, IID_Position);
cmpNewPosition.JumpTo(pos.x, pos.z);
// TODO: what direction should they face in?
spawnedEnts.push(ent);
}
}
var cmpPlayerStatisticsTracker = QueryOwnerInterface(this.entity, IID_StatisticsTracker);
cmpPlayerStatisticsTracker.IncreaseTrainedUnitsCounter();
// Play a sound, but only for the first in the batch (to avoid nasty phasing effects)
if (createdEnts.length == 0)
PlaySound("trained", ent);
this.entityCache.shift();
createdEnts.push(ent);
}
if (spawnedEnts.length > 0)
@ -518,20 +537,21 @@ ProductionQueue.prototype.SpawnUnits = function(templateName, count, metadata)
{
var commands = GetRallyPointCommands(cmpRallyPoint, spawnedEnts);
for each(var com in commands)
{
ProcessCommand(cmpOwnership.GetOwner(), com);
}
}
}
}
if (createdEnts.length > 0)
{
Engine.PostMessage(this.entity, MT_TrainingFinished, {
"entities": spawnedEnts,
"entities": createdEnts,
"owner": cmpOwnership.GetOwner(),
"metadata": metadata,
});
}
return spawnedEnts.length;
return createdEnts.length;
};
/*

View file

@ -663,6 +663,10 @@ var UnitFsmSpec = {
}
},
"Order.Autogarrison": function(msg) {
this.SetNextState("INDIVIDUAL.AUTOGARRISON");
},
"Order.Cheering": function(msg) {
this.SetNextState("INDIVIDUAL.CHEERING");
},
@ -770,31 +774,26 @@ var UnitFsmSpec = {
},
"Order.Garrison": function(msg) {
if (!Engine.QueryInterface(msg.data.target, IID_GarrisonHolder))
// TODO: on what should we base this range?
// Check if we are already in range, otherwise walk there
if (!this.CheckTargetRangeExplicit(msg.data.target, 0, 10))
{
this.FinishOrder();
if (!this.TargetIsAlive(msg.data.target) || !this.CheckTargetVisible(msg.data.target))
// The target was destroyed
this.FinishOrder();
else
// Out of range; move there in formation
this.PushOrderFront("WalkToTargetRange", { "target": msg.data.target, "min": 0, "max": 10 });
return;
}
// Check if we are already in range, otherwise walk there
if (!this.CheckGarrisonRange(msg.data.target))
{
if (!this.CheckTargetVisible(msg.data.target))
{
this.FinishOrder();
return;
}
else
{
// Out of range; move there in formation
if (this.MoveToGarrisonRange(msg.data.target))
{
this.SetNextState("GARRISON.APPROACHING");
return;
}
}
}
this.SetNextState("GARRISON.GARRISONING");
var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
// We don't want to rearrange the formation if the individual units are carrying
// out a task and one of the members dies/leaves the formation.
cmpFormation.SetRearrange(false);
cmpFormation.CallMemberFunction("Garrison", [msg.data.target, false]);
this.SetNextStateAlwaysEntering("MEMBER");
},
"Order.Gather": function(msg) {
@ -2463,6 +2462,22 @@ var UnitFsmSpec = {
},
},
"AUTOGARRISON": {
"enter": function() {
this.isGarrisoned = true;
return false;
},
"Order.Ungarrison": function() {
if (this.FinishOrder())
return;
},
"leave": function() {
this.isGarrisoned = false;
}
},
"CHEERING": {
"enter": function() {
// Unit is invulnerable while cheering
@ -4292,6 +4307,14 @@ UnitAI.prototype.Ungarrison = function()
}
};
/**
* Adds autogarrison order to the queue (only used by ProductionQueue for auto-garrisoning)
*/
UnitAI.prototype.Autogarrison = function()
{
this.AddOrder("Autogarrison", null, false);
};
/**
* Adds gather order to the queue, forced by the player
* until the target is reached