mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-18 06:13:55 -07:00
Some checks failed
checkrefs / lfscheck (push) Has been cancelled
checkrefs / checkrefs (push) Has been cancelled
lint / cppcheck (push) Has been cancelled
lint / copyright (push) Has been cancelled
lint / jenkinsfiles (push) Has been cancelled
pre-commit / build (push) Has been cancelled
Persians -> Achaemenids Pers -> Achae Addressing Checkrefs Internal Achaemenid and Persian references Reported by @Stan` Update unit_tables.py
208 lines
6.2 KiB
JavaScript
208 lines
6.2 KiB
JavaScript
function Builder() {}
|
|
|
|
Builder.prototype.Schema =
|
|
"<a:help>Allows the unit to construct and repair buildings.</a:help>" +
|
|
"<a:example>" +
|
|
"<Rate>1.0</Rate>" +
|
|
"<Entities datatype='tokens'>" +
|
|
"\n structures/{civ}/barracks\n structures/{native}/civil_centre\n structures/achae/apadana\n " +
|
|
"</Entities>" +
|
|
"</a:example>" +
|
|
"<element name='Rate' a:help='Construction speed multiplier (1.0 is normal speed, higher values are faster).'>" +
|
|
"<ref name='positiveDecimal'/>" +
|
|
"</element>" +
|
|
"<element name='Entities' a:help='Space-separated list of entity template names that this unit can build. The special string \"{civ}\" will be automatically replaced by the civ code of the unit's owner, while the string \"{native}\" will be automatically replaced by the unit's civ code. This element can also be empty, in which case no new foundations may be placed by the unit, but they can still repair existing buildings.'>" +
|
|
"<attribute name='datatype'>" +
|
|
"<value>tokens</value>" +
|
|
"</attribute>" +
|
|
"<text/>" +
|
|
"</element>";
|
|
|
|
/*
|
|
* Build interval and repeat time, in ms.
|
|
*/
|
|
Builder.prototype.BUILD_INTERVAL = 1000;
|
|
|
|
Builder.prototype.Init = function()
|
|
{
|
|
};
|
|
|
|
Builder.prototype.GetEntitiesList = function()
|
|
{
|
|
let string = this.template.Entities._string;
|
|
if (!string)
|
|
return [];
|
|
|
|
const cmpPlayer = QueryOwnerInterface(this.entity);
|
|
if (!cmpPlayer)
|
|
return [];
|
|
|
|
string = ApplyValueModificationsToEntity("Builder/Entities/_string", string, this.entity);
|
|
|
|
const cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity);
|
|
if (cmpIdentity)
|
|
string = string.replace(/\{native\}/g, cmpIdentity.GetCiv());
|
|
|
|
const entities = string.replace(/\{civ\}/g, QueryOwnerInterface(this.entity, IID_Identity).GetCiv()).split(/\s+/);
|
|
|
|
const disabledTemplates = cmpPlayer.GetDisabledTemplates();
|
|
|
|
const cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
|
|
|
|
return entities.filter(ent => !disabledTemplates[ent] && cmpTemplateManager.TemplateExists(ent));
|
|
};
|
|
|
|
Builder.prototype.GetRange = function()
|
|
{
|
|
let max = 2;
|
|
const cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);
|
|
if (cmpObstruction)
|
|
max += cmpObstruction.GetSize();
|
|
|
|
return { "max": max, "min": 0 };
|
|
};
|
|
|
|
Builder.prototype.GetRate = function()
|
|
{
|
|
return ApplyValueModificationsToEntity("Builder/Rate", +this.template.Rate, this.entity);
|
|
};
|
|
|
|
/**
|
|
* @param {number} target - The target to check.
|
|
* @return {boolean} - Whether we can build/repair the given target.
|
|
*/
|
|
Builder.prototype.CanRepair = function(target)
|
|
{
|
|
const cmpFoundation = QueryMiragedInterface(target, IID_Foundation);
|
|
const cmpRepairable = QueryMiragedInterface(target, IID_Repairable);
|
|
if (!cmpFoundation && (!cmpRepairable || !cmpRepairable.IsRepairable()))
|
|
return false;
|
|
|
|
const cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
|
return cmpOwnership && IsOwnedByAllyOfPlayer(cmpOwnership.GetOwner(), target);
|
|
};
|
|
|
|
/**
|
|
* @param {number} target - The target to repair.
|
|
* @param {number} callerIID - The IID to notify on specific events.
|
|
* @return {boolean} - Whether we started repairing.
|
|
*/
|
|
Builder.prototype.StartRepairing = function(target, callerIID)
|
|
{
|
|
if (this.target)
|
|
this.StopRepairing();
|
|
|
|
if (!this.CanRepair(target))
|
|
return false;
|
|
|
|
const cmpBuilderList = QueryBuilderListInterface(target);
|
|
if (cmpBuilderList)
|
|
cmpBuilderList.AddBuilder(this.entity);
|
|
|
|
const cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
|
|
if (cmpVisual)
|
|
cmpVisual.SelectAnimation("build", false, 1.0);
|
|
|
|
this.target = target;
|
|
this.callerIID = callerIID;
|
|
|
|
const cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
|
this.timer = cmpTimer.SetInterval(this.entity, IID_Builder, "PerformBuilding", this.BUILD_INTERVAL, this.BUILD_INTERVAL, null);
|
|
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* @param {string} reason - The reason why we stopped repairing.
|
|
*/
|
|
Builder.prototype.StopRepairing = function(reason)
|
|
{
|
|
if (!this.target)
|
|
return;
|
|
|
|
const cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
|
cmpTimer.CancelTimer(this.timer);
|
|
delete this.timer;
|
|
|
|
const cmpBuilderList = QueryBuilderListInterface(this.target);
|
|
if (cmpBuilderList)
|
|
cmpBuilderList.RemoveBuilder(this.entity);
|
|
|
|
delete this.target;
|
|
|
|
const cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
|
|
if (cmpVisual)
|
|
cmpVisual.SelectAnimation("idle", false, 1.0);
|
|
|
|
// The callerIID component may start again,
|
|
// replacing the callerIID, hence save that.
|
|
const callerIID = this.callerIID;
|
|
delete this.callerIID;
|
|
|
|
if (reason && callerIID)
|
|
{
|
|
const component = Engine.QueryInterface(this.entity, callerIID);
|
|
if (component)
|
|
component.ProcessMessage(reason, null);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Repair our target entity.
|
|
* @params - data and lateness are unused.
|
|
*/
|
|
Builder.prototype.PerformBuilding = function(data, lateness)
|
|
{
|
|
if (!this.CanRepair(this.target))
|
|
{
|
|
this.StopRepairing("TargetInvalidated");
|
|
return;
|
|
}
|
|
|
|
if (!this.IsTargetInRange(this.target))
|
|
{
|
|
this.StopRepairing("OutOfRange");
|
|
return;
|
|
}
|
|
|
|
// ToDo: Enable entities to keep facing a target.
|
|
Engine.QueryInterface(this.entity, IID_UnitAI)?.FaceTowardsTarget(this.target);
|
|
|
|
const cmpFoundation = Engine.QueryInterface(this.target, IID_Foundation);
|
|
if (cmpFoundation)
|
|
{
|
|
cmpFoundation.Build(this.entity, this.GetRate());
|
|
return;
|
|
}
|
|
|
|
const cmpRepairable = Engine.QueryInterface(this.target, IID_Repairable);
|
|
if (cmpRepairable)
|
|
{
|
|
cmpRepairable.Repair(this.entity, this.GetRate());
|
|
return;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @param {number} - The entity ID of the target to check.
|
|
* @return {boolean} - Whether this entity is in range of its target.
|
|
*/
|
|
Builder.prototype.IsTargetInRange = function(target)
|
|
{
|
|
const range = this.GetRange();
|
|
const cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager);
|
|
return cmpObstructionManager.IsInTargetRange(this.entity, target, range.min, range.max, false);
|
|
};
|
|
|
|
Builder.prototype.OnValueModification = function(msg)
|
|
{
|
|
if (msg.component != "Builder" || !msg.valueNames.some(name => name.endsWith('_string')))
|
|
return;
|
|
|
|
// Token changes may require selection updates.
|
|
const cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
|
|
if (cmpPlayer)
|
|
Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface).SetSelectionDirty(cmpPlayer.GetPlayerID());
|
|
};
|
|
|
|
Engine.RegisterComponentType(IID_Builder, "Builder", Builder);
|