mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-17 22:03:56 -07:00
Allows autogarrison of newly trained units, fixes #1044
This was SVN commit r14144.
This commit is contained in:
parent
fad8f7fce0
commit
2102648f7c
5 changed files with 117 additions and 60 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue