Changeset View
Standalone View
binaries/data/mods/public/simulation/components/GarrisonHolder.js
Show All 30 Lines | "<optional>" + | ||||
"</element>" + | "</element>" + | ||||
"</optional>" + | "</optional>" + | ||||
"<optional>" + | "<optional>" + | ||||
"<element name='VisibleGarrisonPoints' a:help='Points that will be used to visibly garrison a unit'>" + | "<element name='VisibleGarrisonPoints' a:help='Points that will be used to visibly garrison a unit'>" + | ||||
"<zeroOrMore>" + | "<zeroOrMore>" + | ||||
"<element a:help='Element containing the offset coordinates'>" + | "<element a:help='Element containing the offset coordinates'>" + | ||||
"<anyName/>" + | "<anyName/>" + | ||||
"<interleave>" + | "<interleave>" + | ||||
"<optional>" + | |||||
"<interleave>" + | |||||
"<element name='Template'>" + | |||||
"<text/>" + | |||||
"</element>" + | |||||
"<element name='Fixed' a:help='Whether this template is tied to the garrison position (i.e. not allowed to ungarrison).'>" + | |||||
"<data type='boolean'/>" + | |||||
"</element>" + | |||||
"</interleave>" + | |||||
"</optional>" + | |||||
"<element name='X'>" + | "<element name='X'>" + | ||||
"<data type='decimal'/>" + | "<data type='decimal'/>" + | ||||
"</element>" + | "</element>" + | ||||
"<element name='Y'>" + | "<element name='Y'>" + | ||||
"<data type='decimal'/>" + | "<data type='decimal'/>" + | ||||
"</element>" + | "</element>" + | ||||
"<element name='Z'>" + | "<element name='Z'>" + | ||||
"<data type='decimal'/>" + | "<data type='decimal'/>" + | ||||
Show All 32 Lines | GarrisonHolder.prototype.Init = function() | ||||
if (!this.template.VisibleGarrisonPoints) | if (!this.template.VisibleGarrisonPoints) | ||||
return; | return; | ||||
let points = this.template.VisibleGarrisonPoints; | let points = this.template.VisibleGarrisonPoints; | ||||
for (let point in points) | for (let point in points) | ||||
this.visibleGarrisonPoints.push({ | this.visibleGarrisonPoints.push({ | ||||
"offset": { | "offset": { | ||||
"x": +points[point].X, | "x": +points[point].X, | ||||
"y": +points[point].Y, | "y": +points[point].Y, | ||||
Stan: early return ? | |||||
"z": +points[point].Z | "z": +points[point].Z | ||||
}, | }, | ||||
Done Inline Actionsearly return if no ownership ? Stan: early return if no ownership ? | |||||
"allowedClasses": points[point].AllowedClasses, | "allowedClasses": points[point].AllowedClasses, | ||||
"angle": points[point].Angle ? +points[point].Angle * Math.PI / 180 : null, | "angle": points[point].Angle ? +points[point].Angle * Math.PI / 180 : null, | ||||
"entity": null | "entity": null, | ||||
"template": points[point].Template, | |||||
"fixed": points[point].Fixed && points[point].Fixed == "true" | |||||
}); | }); | ||||
}; | }; | ||||
Done Inline Actionsearly continue; Stan: early continue; | |||||
/** | /** | ||||
* Autogarrison the turrets as specified in the template. | |||||
* This function has to be called from ownership change for all components ought to be initialised. | |||||
wraitiiUnsubmitted Done Inline ActionsWhich components? Whose? wraitii: Which components? Whose?
It is better to state the requirement & not the fact that these… | |||||
*/ | |||||
GarrisonHolder.prototype.AutogarrisonTurrets = function() | |||||
{ | |||||
if (!this.visibleGarrisonPoints) | |||||
return; | |||||
for (let point of this.visibleGarrisonPoints) | |||||
Done Inline ActionsNo need for that variable ? Stan: No need for that variable ? | |||||
if (point.template) | |||||
Done Inline ActionsVariable redefinition ? Stan: Variable redefinition ? | |||||
this.CreateTurret(point); | |||||
}; | |||||
/** | |||||
* Add a turret as specified in the template. | |||||
* This function can be called from AutogarrisonTurrets | |||||
* or when retraining a turret. | |||||
wraitiiUnsubmitted Done Inline ActionsIs there a reason why? Is it broken otherwise? If this is just stating a fact, it seems rather useless. wraitii: Is there a reason why? Is it broken otherwise?
If this is just stating a fact, it seems rather… | |||||
* | |||||
* @param {Object} vgp - A visible garrison point to (re)create the predefined turret for. | |||||
* | |||||
* @return {boolean} - Whether the turret creation has succeeded. | |||||
*/ | |||||
GarrisonHolder.prototype.CreateTurret = function(vgp) | |||||
{ | |||||
// This position is already occupied. | |||||
if (vgp.entity) | |||||
return false; | |||||
let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); | |||||
if (!cmpOwnership) | |||||
return false; | |||||
let owner = cmpOwnership.GetOwner(); | |||||
let filter = vgp.fixed ? "fixedgarrison|" : ""; | |||||
let ent = Engine.AddEntity(filter + vgp.template); | |||||
let cmpEntOwnership = Engine.QueryInterface(ent, IID_Ownership); | |||||
if (cmpEntOwnership) | |||||
cmpEntOwnership.SetOwner(owner); | |||||
return this.Garrison(ent, vgp, true) || Engine.DestroyEntity(ent); | |||||
wraitiiUnsubmitted Done Inline ActionsThe hard dependency on Ownership seems un-necessary here. wraitii: The hard dependency on Ownership seems un-necessary here. | |||||
FreagarachAuthorUnsubmitted Done Inline ActionsBut it should have the component at least? Freagarach: But it should have the component at least? | |||||
wraitiiUnsubmitted Done Inline ActionsI don't really see why. If you don't have an owner but neither does your turret, is that a problem? wraitii: I don't really see why. If you don't have an owner but neither does your turret, is that a… | |||||
}; | |||||
/** | |||||
* @return {Object} max and min range at which entities can garrison the holder. | * @return {Object} max and min range at which entities can garrison the holder. | ||||
*/ | */ | ||||
GarrisonHolder.prototype.GetLoadingRange = function() | GarrisonHolder.prototype.GetLoadingRange = function() | ||||
{ | { | ||||
return { "max": +this.template.LoadingRange, "min": 0 }; | return { "max": +this.template.LoadingRange, "min": 0 }; | ||||
}; | }; | ||||
GarrisonHolder.prototype.CanPickup = function(ent) | GarrisonHolder.prototype.CanPickup = function(ent) | ||||
{ | { | ||||
if (!this.template.Pickup || this.IsFull()) | if (!this.template.Pickup || this.IsFull()) | ||||
return false; | return false; | ||||
let cmpOwner = Engine.QueryInterface(this.entity, IID_Ownership); | let cmpOwner = Engine.QueryInterface(this.entity, IID_Ownership); | ||||
return !!cmpOwner && IsOwnedByPlayer(cmpOwner.GetOwner(), ent); | return !!cmpOwner && IsOwnedByPlayer(cmpOwner.GetOwner(), ent); | ||||
}; | }; | ||||
GarrisonHolder.prototype.GetEntities = function() | GarrisonHolder.prototype.GetEntities = function() | ||||
{ | { | ||||
return this.entities; | return this.entities; | ||||
}; | }; | ||||
/** | /** | ||||
* Get the entity IDs of the entities which are not visibly garrisoned. | |||||
* Used in the GUI to display in the garrison panel. | |||||
* | |||||
* @return {number[]} - An array containing entity IDs. | |||||
*/ | |||||
GarrisonHolder.prototype.GetHiddenGarrisonedEntities = function() | |||||
Done Inline ActionsNonVisible ? Hidden ? Stan: NonVisible ? Hidden ? | |||||
{ | |||||
return this.entities.filter(entity => !this.IsVisiblyGarrisoned(entity)); | |||||
}; | |||||
/** | |||||
* Test whether the entity is visibly garrisoned. | |||||
Done Inline Actionsarray.find ? Stan: array.find ? | |||||
* | |||||
* @param {number} entity - The entity ID of the entity to check. | |||||
* | |||||
* @return {boolean} - Whether the entity is visibly garrisoned. | |||||
*/ | |||||
GarrisonHolder.prototype.IsVisiblyGarrisoned = function(entity) | |||||
{ | |||||
return this.visibleGarrisonPoints.some(vgp => vgp.entity == entity); | |||||
}; | |||||
/** | |||||
* Get the visible garrison points of this entity. | |||||
Done Inline Actionsarray.some ? Stan: array.some ? | |||||
* | |||||
* @return {Object[]} - An array containing visibly garrison points. | |||||
*/ | |||||
GarrisonHolder.prototype.GetVisibleGarrisonPoints = function() | |||||
{ | |||||
return this.visibleGarrisonPoints; | |||||
}; | |||||
/** | |||||
* Get the visible garrison point this entity occupies. | |||||
* | |||||
* @param {number} entity - The entity ID of the entity to check. | |||||
* | |||||
* @return {Object[]} - An array containing visibly garrison points. | |||||
*/ | |||||
GarrisonHolder.prototype.GetVisibleGarrisonPoint = function(entity) | |||||
{ | |||||
return this.visibleGarrisonPoints.find(vgp => vgp.entity == entity); | |||||
}; | |||||
/** | |||||
* @return {Array} unit classes which can be garrisoned inside this | * @return {Array} unit classes which can be garrisoned inside this | ||||
* particular entity. Obtained from the entity's template. | * particular entity. Obtained from the entity's template. | ||||
*/ | */ | ||||
GarrisonHolder.prototype.GetAllowedClasses = function() | GarrisonHolder.prototype.GetAllowedClasses = function() | ||||
{ | { | ||||
return this.template.List._string; | return this.template.List._string; | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | GarrisonHolder.prototype.AllowedToVisibleGarrisoning = function(entity, visibleGarrisonPoint) | ||||
if (!visibleGarrisonPoint.allowedClasses) | if (!visibleGarrisonPoint.allowedClasses) | ||||
return true; | return true; | ||||
let cmpIdentity = Engine.QueryInterface(entity, IID_Identity); | let cmpIdentity = Engine.QueryInterface(entity, IID_Identity); | ||||
return cmpIdentity && MatchesClassList(cmpIdentity.GetClassesList(), visibleGarrisonPoint.allowedClasses._string); | return cmpIdentity && MatchesClassList(cmpIdentity.GetClassesList(), visibleGarrisonPoint.allowedClasses._string); | ||||
}; | }; | ||||
/** | /** | ||||
* Garrison a unit inside. The timer for AutoHeal is started here. | * Garrison a unit inside. | ||||
* @param {number} vgpEntity - The visual garrison point that will be used. | * @param {Object} vgpEntity - The visual garrison point that will be used. | ||||
* If vgpEntity is given, this visualGarrisonPoint will be used for the entity. | * If vgpEntity is given, this visualGarrisonPoint will be used for the entity. | ||||
* @return {boolean} - Whether the entity was garrisoned. | * @param {boolean} forced - Whether the garrison is forced (e.g. a turret created on init). | ||||
* | |||||
* @return {boolean} Whether the entity was garrisoned. | |||||
*/ | */ | ||||
GarrisonHolder.prototype.Garrison = function(entity, vgpEntity) | GarrisonHolder.prototype.Garrison = function(entity, vgpEntity, forced) | ||||
wraitiiUnsubmitted Done Inline ActionsSeems like this function should be split in two to me, Garrison and SetTurret or something. wraitii: Seems like this function should be split in two to me, `Garrison` and `SetTurret` or something. | |||||
FreagarachAuthorUnsubmitted Done Inline ActionsFreagarach: D2367 | |||||
{ | { | ||||
let cmpPosition = Engine.QueryInterface(entity, IID_Position); | let cmpPosition = Engine.QueryInterface(entity, IID_Position); | ||||
if (!cmpPosition) | if (!cmpPosition) | ||||
return false; | return false; | ||||
if (!this.PerformGarrison(entity)) | if (!this.PerformGarrison(entity, forced)) | ||||
return false; | return false; | ||||
let visibleGarrisonPoint; | let visibleGarrisonPoint; | ||||
if (vgpEntity && this.AllowedToVisibleGarrisoning(entity, vgpEntity)) | if (vgpEntity && this.AllowedToVisibleGarrisoning(entity, vgpEntity)) | ||||
visibleGarrisonPoint = vgpEntity; | visibleGarrisonPoint = vgpEntity; | ||||
if (!visibleGarrisonPoint) | if (!visibleGarrisonPoint) | ||||
visibleGarrisonPoint = this.visibleGarrisonPoints.find(vgp => !vgp.entity && this.AllowedToVisibleGarrisoning(entity, vgp)); | visibleGarrisonPoint = this.visibleGarrisonPoints.find(vgp => !vgp.entity && this.AllowedToVisibleGarrisoning(entity, vgp)); | ||||
let isVisiblyGarrisoned = false; | let isVisiblyGarrisoned = false; | ||||
if (visibleGarrisonPoint) | if (visibleGarrisonPoint) | ||||
{ | { | ||||
visibleGarrisonPoint.entity = entity; | visibleGarrisonPoint.entity = entity; | ||||
// Angle of turrets: | // Angle of turrets: | ||||
// Renamed entities (vgpEntity != undefined) should keep their angle. | // Renamed entities (vgpEntity != undefined) should keep their angle. | ||||
// Otherwise if an angle is given in the visibleGarrisonPoint, use it. | // Otherwise if an angle is given in the visibleGarrisonPoint, use it. | ||||
// If no such angle given (usually walls for which outside/inside not well defined), we keep | // If no such angle given (usually walls for which outside/inside not well defined), we keep | ||||
// the current angle as it was used for garrisoning and thus quite often was from inside to | // the current angle as it was used for garrisoning and thus quite often was from inside to | ||||
// outside, except when garrisoning from outWorld where we take as default PI. | // outside, except when garrisoning from outWorld where we take as default PI. | ||||
let cmpTurretPosition = Engine.QueryInterface(this.entity, IID_Position); | let cmpTurretPosition = Engine.QueryInterface(this.entity, IID_Position); | ||||
if (!vgpEntity && visibleGarrisonPoint.angle != null) | if (!vgpEntity && visibleGarrisonPoint.angle != null || forced) | ||||
Done Inline ActionsMissing parenthesis ? && has precedence over || Stan: Missing parenthesis ? && has precedence over || | |||||
Done Inline ActionsNope. Freagarach: Nope. | |||||
cmpPosition.SetYRotation(cmpTurretPosition.GetRotation().y + visibleGarrisonPoint.angle); | cmpPosition.SetYRotation(cmpTurretPosition.GetRotation().y + visibleGarrisonPoint.angle); | ||||
else if (!vgpEntity && !cmpPosition.IsInWorld()) | else if (!vgpEntity && !cmpPosition.IsInWorld()) | ||||
cmpPosition.SetYRotation(cmpTurretPosition.GetRotation().y + Math.PI); | cmpPosition.SetYRotation(cmpTurretPosition.GetRotation().y + Math.PI); | ||||
let cmpUnitMotion = Engine.QueryInterface(entity, IID_UnitMotion); | let cmpUnitMotion = Engine.QueryInterface(entity, IID_UnitMotion); | ||||
if (cmpUnitMotion) | if (cmpUnitMotion) | ||||
cmpUnitMotion.SetFacePointAfterMove(false); | cmpUnitMotion.SetFacePointAfterMove(false); | ||||
cmpPosition.SetTurretParent(this.entity, visibleGarrisonPoint.offset); | cmpPosition.SetTurretParent(this.entity, visibleGarrisonPoint.offset); | ||||
let cmpUnitAI = Engine.QueryInterface(entity, IID_UnitAI); | let cmpUnitAI = Engine.QueryInterface(entity, IID_UnitAI); | ||||
if (cmpUnitAI) | if (cmpUnitAI) | ||||
{ | |||||
cmpUnitAI.SetTurretStance(); | cmpUnitAI.SetTurretStance(); | ||||
cmpUnitAI.SetGarrisoned(); | |||||
} | |||||
isVisiblyGarrisoned = true; | isVisiblyGarrisoned = true; | ||||
} | } | ||||
else | else | ||||
cmpPosition.MoveOutOfWorld(); | cmpPosition.MoveOutOfWorld(); | ||||
// Should only be called after the garrison has been performed else the visible Garrison Points are not updated yet. | // Should only be called after the garrison has been performed else the visible Garrison Points are not updated yet. | ||||
Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { | Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { | ||||
"added": [entity], | "added": [entity], | ||||
"removed": [], | "removed": [], | ||||
"visible": { | "visible": { | ||||
[entity]: isVisiblyGarrisoned, | [entity]: isVisiblyGarrisoned, | ||||
} | } | ||||
}); | }); | ||||
return true; | return true; | ||||
}; | }; | ||||
/** | /** | ||||
* @return {boolean} Whether the entity was garrisonned. | * @param {number} entity - The entity ID to garrison. | ||||
* @param {boolean} forced - Whether the garrison has to be forced (e.g. turret creation on init). | |||||
* | |||||
* @return {boolean} Whether the entity was garrisoned. | |||||
*/ | */ | ||||
GarrisonHolder.prototype.PerformGarrison = function(entity) | GarrisonHolder.prototype.PerformGarrison = function(entity, forced) | ||||
{ | { | ||||
if (!this.HasEnoughHealth()) | if (!this.HasEnoughHealth()) | ||||
return false; | return false; | ||||
// Check if the unit is allowed to be garrisoned inside the building | // Check if the unit is allowed to be garrisoned inside this entity. | ||||
if (!this.IsAllowedToGarrison(entity)) | // If it is forced we don't care whether it is allowed or not. | ||||
if (!forced && !this.IsAllowedToGarrison(entity)) | |||||
return false; | return false; | ||||
// Check the capacity | // Check the capacity. | ||||
let extraCount = 0; | let extraCount = 0; | ||||
let cmpGarrisonHolder = Engine.QueryInterface(entity, IID_GarrisonHolder); | let cmpGarrisonHolder = Engine.QueryInterface(entity, IID_GarrisonHolder); | ||||
if (cmpGarrisonHolder) | if (cmpGarrisonHolder) | ||||
extraCount += cmpGarrisonHolder.GetGarrisonedEntitiesCount(); | extraCount += cmpGarrisonHolder.GetGarrisonedEntitiesCount(); | ||||
if (this.GetGarrisonedEntitiesCount() + extraCount >= this.GetCapacity()) | if (this.GetGarrisonedEntitiesCount() + extraCount >= this.GetCapacity()) | ||||
return false; | return false; | ||||
if (!this.timer && this.GetHealRate() > 0) | if (!this.timer && this.GetHealRate() > 0) | ||||
Show All 9 Lines | GarrisonHolder.prototype.PerformGarrison = function(entity, forced) | ||||
if (cmpProductionQueue) | if (cmpProductionQueue) | ||||
cmpProductionQueue.PauseProduction(); | cmpProductionQueue.PauseProduction(); | ||||
let cmpAura = Engine.QueryInterface(entity, IID_Auras); | let cmpAura = Engine.QueryInterface(entity, IID_Auras); | ||||
if (cmpAura && cmpAura.HasGarrisonAura()) | if (cmpAura && cmpAura.HasGarrisonAura()) | ||||
cmpAura.ApplyGarrisonAura(this.entity); | cmpAura.ApplyGarrisonAura(this.entity); | ||||
return true; | return true; | ||||
}; | }; | ||||
wraitiiUnsubmitted Done Inline ActionsMany of those seem like they would no longer apply to a turret, such as the health check. It seems like you want something more explicit than forced, such as a way to skip health checks, adding to the # of garrisoned units (a turret in a tank takes no room, arguably). Perhaps the whole thing must be refactored more to make sense. wraitii: Many of those seem like they would no longer apply to a turret, such as the health check.
It… | |||||
FreagarachAuthorUnsubmitted Done Inline ActionsThere are some separate diffs of mine concerning garrisoning. Freagarach: There are some separate diffs of mine concerning garrisoning. | |||||
/** | /** | ||||
* Simply eject the unit from the garrisoning entity without moving it | * Simply eject the unit from the garrisoning entity without moving it | ||||
* @param {number} entity - Id of the entity to be ejected. | * @param {number} entity - Id of the entity to be ejected. | ||||
* @param {boolean} forced - Whether eject is forced (i.e. if building is destroyed). | * @param {boolean} forced - Whether eject is forced (i.e. if building is destroyed). | ||||
* @return {boolean} Whether the entity was ejected. | * @return {boolean} Whether the entity was ejected. | ||||
*/ | */ | ||||
GarrisonHolder.prototype.Eject = function(entity, forced) | GarrisonHolder.prototype.Eject = function(entity, forced) | ||||
▲ Show 20 Lines • Show All 153 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* Unload unit from the garrisoning entity and order them | * Unload unit from the garrisoning entity and order them | ||||
* to move to the rally point. | * to move to the rally point. | ||||
* @return {boolean} Whether the command was successful. | * @return {boolean} Whether the command was successful. | ||||
*/ | */ | ||||
GarrisonHolder.prototype.Unload = function(entity, forced) | GarrisonHolder.prototype.Unload = function(entity, forced) | ||||
{ | { | ||||
return this.PerformEject([entity], forced); | return this.IsUnloadable(entity) && this.PerformEject([entity], forced); | ||||
}; | }; | ||||
/** | /** | ||||
* Unload one or all units that match a template and owner from | * Unload one or all units that match a template and owner from | ||||
* the garrisoning entity and order them to move to the rally point. | * the garrisoning entity and order them to move to the rally point. | ||||
* @param {string} template - Type of units that should be ejected. | * @param {string} template - Type of units that should be ejected. | ||||
* @param {number} owner - Id of the player whose units should be ejected. | * @param {number} owner - Id of the player whose units should be ejected. | ||||
* @param {boolean} all - Whether all units should be ejected. | * @param {boolean} all - Whether all units should be ejected. | ||||
Show All 29 Lines | |||||
* @param {boolean} forced - Whether unload is forced. | * @param {boolean} forced - Whether unload is forced. | ||||
* @param {number} owner - Id of the player whose units should be ejected. | * @param {number} owner - Id of the player whose units should be ejected. | ||||
* @return {boolean} Whether the unloading was successful. | * @return {boolean} Whether the unloading was successful. | ||||
*/ | */ | ||||
GarrisonHolder.prototype.UnloadAllByOwner = function(owner, forced) | GarrisonHolder.prototype.UnloadAllByOwner = function(owner, forced) | ||||
{ | { | ||||
let entities = this.entities.filter(ent => { | let entities = this.entities.filter(ent => { | ||||
let cmpOwnership = Engine.QueryInterface(ent, IID_Ownership); | let cmpOwnership = Engine.QueryInterface(ent, IID_Ownership); | ||||
return cmpOwnership && cmpOwnership.GetOwner() == owner; | return cmpOwnership && cmpOwnership.GetOwner() == owner && this.IsUnloadable(ent); | ||||
}); | }); | ||||
return this.PerformEject(entities, forced); | return this.PerformEject(entities, forced); | ||||
}; | }; | ||||
/** | /** | ||||
* Unload all units from the entity and order them to move to the rally point. | * Unload all units from the entity and order them to move to the rally point. | ||||
* @param {boolean} forced - Whether unload is forced. | * @param {boolean} forced - Whether unload is forced. | ||||
* @return {boolean} Whether the unloading was successful. | * @return {boolean} Whether the unloading was successful. | ||||
*/ | */ | ||||
GarrisonHolder.prototype.UnloadAll = function(forced) | GarrisonHolder.prototype.UnloadAll = function(forced) | ||||
{ | { | ||||
return this.PerformEject(this.entities.slice(), forced); | return this.PerformEject(this.entities.slice().filter(ent => this.IsUnloadable(ent)), forced); | ||||
}; | }; | ||||
/** | /** | ||||
* Used to check if the garrisoning entity's health has fallen below | * Used to check if the garrisoning entity's health has fallen below | ||||
* a certain limit after which all garrisoned units are unloaded. | * a certain limit after which all garrisoned units are unloaded. | ||||
*/ | */ | ||||
GarrisonHolder.prototype.OnHealthChanged = function(msg) | GarrisonHolder.prototype.OnHealthChanged = function(msg) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
/** | /** | ||||
* If a garrisoned entity is captured, or about to be killed (so its owner changes to '-1'), | * If a garrisoned entity is captured, or about to be killed (so its owner changes to '-1'), | ||||
* remove it from the building so we only ever contain valid entities. | * remove it from the building so we only ever contain valid entities. | ||||
*/ | */ | ||||
GarrisonHolder.prototype.OnGlobalOwnershipChanged = function(msg) | GarrisonHolder.prototype.OnGlobalOwnershipChanged = function(msg) | ||||
{ | { | ||||
// The ownership change may be on the garrisonholder | // The ownership change may be on the garrisonholder... | ||||
if (this.entity == msg.entity) | if (this.entity == msg.entity) | ||||
{ | { | ||||
let entities = this.entities.filter(ent => msg.to == INVALID_PLAYER || !IsOwnedByMutualAllyOfEntity(this.entity, ent)); | let entities = this.entities.filter(ent => msg.to == INVALID_PLAYER || !IsOwnedByMutualAllyOfEntity(this.entity, ent)); | ||||
// If the visible garrison point is forced and the garrisonholder did not die, transfer the turrets ownership as well. | |||||
if (msg.to != INVALID_PLAYER) | |||||
for (let point of this.visibleGarrisonPoints) | |||||
if (point.entity != null && point.forced) | |||||
{ | |||||
let entIndex = this.entities.indexOf(point.entity); | |||||
if (entIndex == -1) | |||||
continue; | |||||
let cmpEntOwnership = Engine.QueryInterface(point.entity, IID_Ownership) | |||||
if (cmpEntOwnership) | |||||
cmpEntOwnership.SetOwner(msg.to); | |||||
entities.splice(entIndex, 1); | |||||
} | |||||
if (entities.length) | if (entities.length) | ||||
this.EjectOrKill(entities); | this.EjectOrKill(entities); | ||||
Done Inline ActionsThis will kill all units when converted Stan: This will kill all units when converted | |||||
// If the garrison holder has just been created, autogarrison turrets. | |||||
// If there is a initGarrison, assume the turrets will already be created | |||||
// (e.g. by loading a map) and don't create new ones. | |||||
if (msg.from == INVALID_PLAYER && !this.initGarrison) | |||||
this.AutogarrisonTurrets(); | |||||
return; | return; | ||||
} | } | ||||
// or on some of its garrisoned units | // ...or on some of its garrisoned units. | ||||
Done Inline ActionsOr. Stan: Or. | |||||
Done Inline ActionsIts a continuation of // The ownership change may be on the garrisonholder... Freagarach: Its a continuation of `// The ownership change may be on the garrisonholder...` | |||||
let entityIndex = this.entities.indexOf(msg.entity); | let entityIndex = this.entities.indexOf(msg.entity); | ||||
if (entityIndex != -1) | if (entityIndex != -1) | ||||
{ | { | ||||
// If the entity is dead, remove it directly instead of ejecting the corpse | // If the entity is dead, remove it directly instead of ejecting the corpse | ||||
let cmpHealth = Engine.QueryInterface(msg.entity, IID_Health); | let cmpHealth = Engine.QueryInterface(msg.entity, IID_Health); | ||||
if (cmpHealth && cmpHealth.GetHitpoints() == 0) | if (cmpHealth && cmpHealth.GetHitpoints() == 0) | ||||
{ | { | ||||
this.entities.splice(entityIndex, 1); | this.entities.splice(entityIndex, 1); | ||||
▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | GarrisonHolder.prototype.EjectOrKill = function(entities) | ||||
{ | { | ||||
let entityIndex = this.entities.indexOf(entity); | let entityIndex = this.entities.indexOf(entity); | ||||
if (entityIndex == -1) | if (entityIndex == -1) | ||||
continue; | continue; | ||||
let cmpHealth = Engine.QueryInterface(entity, IID_Health); | let cmpHealth = Engine.QueryInterface(entity, IID_Health); | ||||
if (cmpHealth) | if (cmpHealth) | ||||
cmpHealth.Kill(); | cmpHealth.Kill(); | ||||
this.entities.splice(entityIndex, 1); | this.entities.splice(entityIndex, 1); | ||||
for (let vgp of this.visibleGarrisonPoints) | |||||
{ | |||||
if (vgp.entity != entity) | |||||
continue; | |||||
vgp.entity = null; | |||||
break; | |||||
} | |||||
killedEntities.push(entity); | killedEntities.push(entity); | ||||
} | } | ||||
if (killedEntities.length) | if (killedEntities.length) | ||||
{ | { | ||||
let visibleEntitiesIds = {}; | let visibleEntitiesIds = {}; | ||||
for (let ent of killedEntities) | for (let ent of killedEntities) | ||||
visibleEntitiesIds[ent] = this.IsVisiblyGarrisoned(ent); | visibleEntitiesIds[ent] = this.IsVisiblyGarrisoned(ent); | ||||
Show All 18 Lines | |||||
/** | /** | ||||
* Whether an entity is ejectable. | * Whether an entity is ejectable. | ||||
* @param {number} entity - The entity-ID to be tested. | * @param {number} entity - The entity-ID to be tested. | ||||
* @return {boolean} - Whether the entity is ejectable. | * @return {boolean} - Whether the entity is ejectable. | ||||
*/ | */ | ||||
GarrisonHolder.prototype.IsEjectable = function(entity) | GarrisonHolder.prototype.IsEjectable = function(entity) | ||||
{ | { | ||||
if (!this.entities.find(ent => ent == entity)) | if (!this.IsUnloadable(entity)) | ||||
return false; | return false; | ||||
let ejectableClasses = this.template.EjectClassesOnDestroy._string; | let ejectableClasses = this.template.EjectClassesOnDestroy._string; | ||||
let entityClasses = Engine.QueryInterface(entity, IID_Identity).GetClassesList(); | let entityClasses = Engine.QueryInterface(entity, IID_Identity).GetClassesList(); | ||||
return MatchesClassList(entityClasses, ejectableClasses); | return MatchesClassList(entityClasses, ejectableClasses); | ||||
}; | }; | ||||
/** | /** | ||||
* Sets the intitGarrison to the specified entities. Used by the mapreader. | * Sets the intitGarrison to the specified entities. Used by the mapreader. | ||||
* | * | ||||
* @param {number[]} entities - The entity IDs to garrison on init. | * @param {number[]} entities - The entity IDs to garrison on init. | ||||
*/ | */ | ||||
GarrisonHolder.prototype.SetInitGarrison = function(entities) | GarrisonHolder.prototype.SetInitGarrison = function(entities) | ||||
{ | { | ||||
this.initGarrison = clone(entities); | this.initGarrison = clone(entities); | ||||
Done Inline Actionssome() ? (You don't use the returned object) Stan: some() ? (You don't use the returned object) | |||||
}; | }; | ||||
/** | /** | ||||
* Whether an entity is unloadable. | |||||
Done Inline Actionsreturn cmpGarrisonable && cmpGarrisonable.IsUnloadable(); Nuke the three lines below Stan: ```lang=cpp
return cmpGarrisonable && cmpGarrisonable.IsUnloadable();
```
Nuke the three lines… | |||||
* @param {number} entity - The entity-ID to be tested. | |||||
* @return {boolean} - Whether the entity is unloadable. | |||||
*/ | |||||
GarrisonHolder.prototype.IsUnloadable = function(entity) | |||||
{ | |||||
if (!this.entities.some(ent => ent == entity)) | |||||
return false; | |||||
let cmpGarrisonable = Engine.QueryInterface(entity, IID_Garrisonable); | |||||
return cmpGarrisonable && cmpGarrisonable.IsUnloadable(); | |||||
}; | |||||
/** | |||||
* Initialise the garrisoned units. | * Initialise the garrisoned units. | ||||
*/ | */ | ||||
GarrisonHolder.prototype.OnGlobalInitGame = function(msg) | GarrisonHolder.prototype.OnGlobalInitGame = function(msg) | ||||
{ | { | ||||
if (!this.initGarrison) | if (!this.initGarrison) | ||||
return; | return; | ||||
for (let ent of this.initGarrison) | for (let ent of this.initGarrison) | ||||
Show All 28 Lines |
early return ?