Fix entities not retaining repair order after target transforms

Update this.repairTarget in UnitAI when target renames.
Transfer builders among renamed entities.

Differential Revision: https://code.wildfiregames.com/D2360
Patch by: @Freagarach
Comments by: Stan, elexis
This was SVN commit r23449.
This commit is contained in:
Angen 2020-01-27 17:14:30 +00:00
parent 82a5ab6d19
commit 17c9950cee
5 changed files with 102 additions and 26 deletions

View file

@ -75,6 +75,16 @@ Foundation.prototype.GetBuildPercentage = function()
return Math.floor(this.GetBuildProgress() * 100);
};
/**
* Returns the current builders.
*
* @return {number[]} - An array containing the entity IDs of assigned builders.
*/
Foundation.prototype.GetBuilders = function()
{
return Array.from(this.builders.keys());
};
Foundation.prototype.GetNumBuilders = function()
{
return this.builders.size;
@ -116,23 +126,48 @@ Foundation.prototype.OnDestroy = function()
}
};
/**
* Adds an array of builders.
*
* @param {number[]} builders - An array containing the entity IDs of builders to assign.
*/
Foundation.prototype.AddBuilders = function(builders)
{
let changed = false;
for (let builder of builders)
changed = this.AddBuilderHelper(builder) || changed;
if (changed)
this.HandleBuildersChanged();
};
/**
* Adds a single builder to this entity.
*
* @param {number} builderEnt - The entity to add.
* @return {boolean} - Whether the addition was successful.
*/
Foundation.prototype.AddBuilderHelper = function(builderEnt)
{
if (this.builders.has(builderEnt))
return false;
let buildRate = Engine.QueryInterface(builderEnt, IID_Builder).GetRate();
this.builders.set(builderEnt, buildRate);
this.totalBuilderRate += buildRate;
return true;
}
/**
* Adds a builder to the counter.
*
* @param {number} builderEnt - The entity to add.
*/
Foundation.prototype.AddBuilder = function(builderEnt)
{
if (this.builders.has(builderEnt))
return;
this.builders.set(builderEnt, Engine.QueryInterface(builderEnt, IID_Builder).GetRate());
this.totalBuilderRate += this.builders.get(builderEnt);
this.SetBuildMultiplier();
let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
if (cmpVisual)
cmpVisual.SetVariable("numbuilders", this.builders.size);
Engine.PostMessage(this.entity, MT_FoundationBuildersChanged, { "to": Array.from(this.builders.keys()) });
if (this.AddBuilderHelper(builderEnt))
this.HandleBuildersChanged();
};
Foundation.prototype.RemoveBuilder = function(builderEnt)
@ -142,14 +177,22 @@ Foundation.prototype.RemoveBuilder = function(builderEnt)
this.totalBuilderRate -= this.builders.get(builderEnt);
this.builders.delete(builderEnt);
this.HandleBuildersChanged();
};
/**
* This has to be called whenever the number of builders change.
*/
Foundation.prototype.HandleBuildersChanged = function()
{
this.SetBuildMultiplier();
let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
if (cmpVisual)
cmpVisual.SetVariable("numbuilders", this.builders.size);
Engine.PostMessage(this.entity, MT_FoundationBuildersChanged, { "to": Array.from(this.builders.keys()) });
};
Engine.PostMessage(this.entity, MT_FoundationBuildersChanged, { "to": this.GetBuilders() });
}
/**
* The build multiplier is a penalty that is applied to each builder.

View file

@ -33,11 +33,32 @@ Repairable.prototype.GetBuildProgress = function()
return hitpoints / maxHitpoints;
};
/**
* Returns the current builders.
*
* @return {number[]} - An array containing the entity IDs of assigned builders.
*/
Repairable.prototype.GetBuilders = function()
{
return Array.from(this.builders.keys());
};
Repairable.prototype.GetNumBuilders = function()
{
return this.builders.size;
};
/**
* Adds an array of builders.
*
* @param {number[]} - An array containing the entity IDs of builders to assign.
*/
Repairable.prototype.AddBuilders = function(builders)
{
for (let builder of builders)
this.AddBuilder(builder);
}
Repairable.prototype.AddBuilder = function(builderEnt)
{
if (this.builders.has(builderEnt))

View file

@ -2754,11 +2754,13 @@ UnitAI.prototype.UnitFsmSpec = {
this.order.data.force = false;
this.repairTarget = this.order.data.target; // temporary, deleted in "leave".
// Check we can still reach and repair the target
// Needed to remove the entity from the builder list when leaving this state.
this.repairTarget = this.order.data.target;
// Check we can still reach and repair the target.
if (!this.CanRepair(this.repairTarget))
{
// Can't reach it, no longer owned by ally, or it doesn't exist any more
// Can't reach it, no longer owned by ally, or it doesn't exist any more.
this.FinishOrder();
return true;
}
@ -2768,8 +2770,8 @@ UnitAI.prototype.UnitFsmSpec = {
this.SetNextState("APPROACHING");
return true;
}
// Check if the target is still repairable
var cmpHealth = Engine.QueryInterface(this.repairTarget, IID_Health);
// Check if the target is still repairable.
let cmpHealth = Engine.QueryInterface(this.repairTarget, IID_Health);
if (cmpHealth && cmpHealth.GetHitpoints() >= cmpHealth.GetMaxHitpoints())
{
// The building was already finished/fully repaired before we arrived;
@ -2784,7 +2786,7 @@ UnitAI.prototype.UnitFsmSpec = {
if (cmpBuilderList)
cmpBuilderList.AddBuilder(this.entity);
this.FaceTowardsTarget(this.order.data.target);
this.FaceTowardsTarget(this.repairTarget);
this.SelectAnimation("build");
this.StartTimer(1000, 1000);
@ -2801,21 +2803,21 @@ UnitAI.prototype.UnitFsmSpec = {
},
"Timer": function(msg) {
// Check we can still reach and repair the target
// Check we can still reach and repair the target.
if (!this.CanRepair(this.repairTarget))
{
// No longer owned by ally, or it doesn't exist any more
// No longer owned by ally, or it doesn't exist any more.
this.FinishOrder();
return;
}
this.FaceTowardsTarget(this.order.data.target);
this.FaceTowardsTarget(this.repairTarget);
let cmpBuilder = Engine.QueryInterface(this.entity, IID_Builder);
cmpBuilder.PerformBuilding(this.repairTarget);
// if the building is completed, the leave() function will be called
// by the ConstructionFinished message
// in that case, the repairTarget is deleted, and we can just return
// If the building is completed, the leave() function will be called
// by the ConstructionFinished message.
// In that case, the repairTarget is deleted, and we can just return.
if (!this.repairTarget)
return;
if (!this.CheckTargetRange(this.repairTarget, IID_Builder))
@ -4093,6 +4095,9 @@ UnitAI.prototype.OnGlobalEntityRenamed = function(msg)
order.data.formationTarget = msg.newentity;
}
}
if (this.repairTarget && this.repairTarget == msg.entity)
this.repairTarget = msg.newentity;
if (changed)
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() });
};

View file

@ -4,12 +4,14 @@ Engine.LoadHelperScript("Transform.js");
Engine.LoadHelperScript("ValueModification.js");
Engine.LoadComponentScript("interfaces/ModifiersManager.js");
Engine.LoadComponentScript("interfaces/Capturable.js");
Engine.LoadComponentScript("interfaces/Foundation.js");
Engine.LoadComponentScript("interfaces/GarrisonHolder.js");
Engine.LoadComponentScript("interfaces/Guard.js");
Engine.LoadComponentScript("interfaces/Health.js");
Engine.LoadComponentScript("interfaces/Pack.js");
Engine.LoadComponentScript("interfaces/Player.js");
Engine.LoadComponentScript("interfaces/Promotion.js");
Engine.LoadComponentScript("interfaces/Repairable.js");
Engine.LoadComponentScript("interfaces/ResourceGatherer.js");
Engine.LoadComponentScript("interfaces/StatusEffectsReceiver.js");
Engine.LoadComponentScript("interfaces/Timer.js");

View file

@ -53,6 +53,11 @@ function ChangeEntityTemplate(oldEnt, newTemplate)
cmpNewHealth.SetHitpoints(cmpNewHealth.GetMaxHitpoints() * healthLevel);
}
let cmpBuilderList = QueryBuilderListInterface(oldEnt);
let cmpNewBuilderList = QueryBuilderListInterface(newEnt);
if (cmpBuilderList && cmpNewBuilderList)
cmpNewBuilderList.AddBuilders(cmpBuilderList.GetBuilders());
var cmpUnitAI = Engine.QueryInterface(oldEnt, IID_UnitAI);
var cmpNewUnitAI = Engine.QueryInterface(newEnt, IID_UnitAI);
if (cmpUnitAI && cmpNewUnitAI)