Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/components/GarrisonHolder.js
Show First 20 Lines • Show All 189 Lines • ▼ Show 20 Lines | Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { | ||||
"added": [entity], | "added": [entity], | ||||
"removed": [] | "removed": [] | ||||
}); | }); | ||||
return true; | return true; | ||||
}; | }; | ||||
/** | /** | ||||
* Simply eject the unit from the garrisoning entity without moving it | |||||
* @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} renamed - Whether eject was due to entity renaming. | |||||
* | |||||
* @return {boolean} Whether the entity was ejected. | |||||
*/ | |||||
GarrisonHolder.prototype.Eject = function(entity, forced, renamed = false) | |||||
{ | |||||
let entityIndex = this.entities.indexOf(entity); | |||||
// Error: invalid entity ID, usually it's already been ejected | |||||
if (entityIndex == -1) | |||||
return false; | |||||
let cmpGarrisonable = Engine.QueryInterface(entity, IID_Garrisonable); | |||||
if (!cmpGarrisonable || !cmpGarrisonable.UnGarrison(forced, renamed)) | |||||
return false; | |||||
this.entities.splice(entityIndex, 1); | |||||
Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { | |||||
"added": [], | |||||
"removed": [entity] | |||||
}); | |||||
return true; | |||||
}; | |||||
/** | |||||
* @param {number} entity - EntityID to find the spawn position for. | * @param {number} entity - EntityID to find the spawn position for. | ||||
* @param {boolean} forced - Optionally whether the spawning is forced. | * @param {boolean} forced - Optionally whether the spawning is forced. | ||||
* @return {Vector3D} - An appropriate spawning position. | * @return {Vector3D} - An appropriate spawning position. | ||||
*/ | */ | ||||
GarrisonHolder.prototype.GetSpawnPosition = function(entity, forced) | GarrisonHolder.prototype.GetSpawnPosition = function(entity, forced) | ||||
{ | { | ||||
let cmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint); | let cmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint); | ||||
let cmpHealth = Engine.QueryInterface(this.entity, IID_Health); | let cmpHealth = Engine.QueryInterface(this.entity, IID_Health); | ||||
Show All 20 Lines | GarrisonHolder.prototype.GetSpawnPosition = function(entity, forced) | ||||
return pos; | return pos; | ||||
}; | }; | ||||
/** | /** | ||||
* Ejects units and orders them to move to the rally point. If an ejection | * Ejects units and orders them to move to the rally point. If an ejection | ||||
* with a given obstruction radius has failed, we won't try anymore to eject | * with a given obstruction radius has failed, we won't try anymore to eject | ||||
* entities with a bigger obstruction as that is compelled to also fail. | * entities with a bigger obstruction as that is compelled to also fail. | ||||
* @param {Array} entities - An array containing the ids of the entities to eject. | * @param {Array} entities - An array containing the ids of the entities to eject. | ||||
* @param {boolean} forced - Whether eject is forced (ie: if building is destroyed). | * @param {boolean} forced - Whether eject is forced (e.g. if building is destroyed). | ||||
* @return {boolean} Whether the entities were ejected. | * @return {boolean} Whether the entities were ejected. | ||||
*/ | */ | ||||
GarrisonHolder.prototype.PerformEject = function(entities, forced) | GarrisonHolder.prototype.PerformEject = function(entities, forced) | ||||
wraitii: Thinks you must rename this. It's just 'RemoveFromGarrisonedList' or something now | |||||
{ | { | ||||
if (!this.IsGarrisoningAllowed() && !forced) | if (!this.IsGarrisoningAllowed() && !forced) | ||||
return false; | return false; | ||||
let ejectedEntities = []; | let ejectedEntities = []; | ||||
let success = true; | let success = true; | ||||
let failedRadius; | let failedRadius; | ||||
let radius; | let radius; | ||||
let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); | |||||
for (let entity of entities) | for (let entity of entities) | ||||
{ | { | ||||
if (failedRadius !== undefined) | let entityIndex = this.entities.indexOf(entity); | ||||
{ | // Error: invalid entity ID, usually it's already been ejected | ||||
let cmpObstruction = Engine.QueryInterface(entity, IID_Obstruction); | if (entityIndex == -1) | ||||
radius = cmpObstruction ? cmpObstruction.GetSize() : 0; | |||||
if (radius >= failedRadius) | |||||
continue; | continue; | ||||
} | |||||
if (this.Eject(entity, forced)) | this.entities.splice(entityIndex, 1); | ||||
{ | |||||
let cmpEntOwnership = Engine.QueryInterface(entity, IID_Ownership); | |||||
if (cmpOwnership && cmpEntOwnership && cmpOwnership.GetOwner() == cmpEntOwnership.GetOwner()) | |||||
ejectedEntities.push(entity); | ejectedEntities.push(entity); | ||||
} | } | ||||
else | |||||
{ | |||||
success = false; | |||||
if (failedRadius !== undefined) | |||||
failedRadius = Math.min(failedRadius, radius); | |||||
else | |||||
{ | |||||
let cmpObstruction = Engine.QueryInterface(entity, IID_Obstruction); | |||||
failedRadius = cmpObstruction ? cmpObstruction.GetSize() : 0; | |||||
} | |||||
} | |||||
} | |||||
this.OrderWalkToRallyPoint(ejectedEntities); | if (!ejectedEntities.length) | ||||
return success; | |||||
this.UpdateGarrisonFlag(); | this.UpdateGarrisonFlag(); | ||||
Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { | |||||
"added": [], | |||||
"removed": ejectedEntities | |||||
}); | |||||
return success; | return success; | ||||
}; | }; | ||||
/** | /** | ||||
* Order entities to walk to the rally point. | * Order entities to walk to the rally point. | ||||
* @param {Array} entities - An array containing all the ids of the entities. | * @param {Array} entities - An array containing all the ids of the entities. | ||||
*/ | */ | ||||
GarrisonHolder.prototype.OrderWalkToRallyPoint = function(entities) | GarrisonHolder.prototype.OrderWalkToRallyPoint = function(entities) | ||||
Done Inline ActionsThis is definitely the wrong name -> it's not only walking. wraitii: This is definitely the wrong name -> it's not only walking. | |||||
{ | { | ||||
let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); | |||||
let cmpRallyPoint = Engine.QueryInterface(this.entity, IID_RallyPoint); | let cmpRallyPoint = Engine.QueryInterface(this.entity, IID_RallyPoint); | ||||
if (!cmpRallyPoint || !cmpRallyPoint.GetPositions()[0]) | if (!cmpRallyPoint || !cmpRallyPoint.GetPositions()[0]) | ||||
return; | return; | ||||
let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); | |||||
if (!cmpOwnership) | |||||
return; | |||||
entities = entities.filter(ent => { | |||||
let cmpEntOwnership = Engine.QueryInterface(ent, IID_Ownership); | |||||
return cmpEntOwnership && cmpOwnership.GetOwner() == cmpEntOwnership.GetOwner(); | |||||
}); | |||||
let commands = GetRallyPointCommands(cmpRallyPoint, entities); | let commands = GetRallyPointCommands(cmpRallyPoint, entities); | ||||
// Ignore the rally point if it is autogarrison | // Ignore the rally point if it is autogarrison | ||||
if (commands[0].type == "garrison" && commands[0].target == this.entity) | if (commands[0].type == "garrison" && commands[0].target == this.entity) | ||||
return; | return; | ||||
for (let command of commands) | for (let command of commands) | ||||
ProcessCommand(cmpOwnership.GetOwner(), command); | ProcessCommand(cmpOwnership.GetOwner(), command); | ||||
}; | }; | ||||
/** | /** | ||||
* Unload unit from the garrisoning entity and order them | * Tell unit to unload from this entity. | ||||
* to move to the rally point. | * @param {number} entity - The entity to unload. | ||||
* @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) | ||||
{ | |||||
let cmpGarrisonable = Engine.QueryInterface(entity, IID_Garrisonable); | |||||
return cmpGarrisonable && cmpGarrisonable.UnGarrison(); | |||||
}; | |||||
/** | |||||
* Tell units to unload from this entity. | |||||
* @param {number[]} entities - The entities to unload. | |||||
* @return {boolean} - Whether all unloads were successful. | |||||
*/ | |||||
GarrisonHolder.prototype.UnloadEntities = function(entities) | |||||
{ | { | ||||
return this.PerformEject([entity], forced); | let success = true; | ||||
for (let entity of entities) | |||||
if (!this.Unload(entity)) | |||||
success = false; | |||||
return success; | |||||
}; | }; | ||||
/** | /** | ||||
* Unload one or all units that match a template and owner from | * Unload one or all units that match a template and owner from us. | ||||
* 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. | ||||
* @param {boolean} forced - Whether unload is forced. | |||||
* @return {boolean} Whether the unloading was successful. | * @return {boolean} Whether the unloading was successful. | ||||
*/ | */ | ||||
GarrisonHolder.prototype.UnloadTemplate = function(template, owner, all, forced) | GarrisonHolder.prototype.UnloadTemplate = function(template, owner, all) | ||||
{ | { | ||||
let entities = []; | let entities = []; | ||||
let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | ||||
for (let entity of this.entities) | for (let entity of this.entities) | ||||
{ | { | ||||
let cmpIdentity = Engine.QueryInterface(entity, IID_Identity); | let cmpIdentity = Engine.QueryInterface(entity, IID_Identity); | ||||
// Units with multiple ranks are grouped together. | // Units with multiple ranks are grouped together. | ||||
let name = cmpIdentity.GetSelectionGroupName() || cmpTemplateManager.GetCurrentTemplateName(entity); | let name = cmpIdentity.GetSelectionGroupName() || cmpTemplateManager.GetCurrentTemplateName(entity); | ||||
if (name != template || owner != Engine.QueryInterface(entity, IID_Ownership).GetOwner()) | if (name != template || owner != Engine.QueryInterface(entity, IID_Ownership).GetOwner()) | ||||
continue; | continue; | ||||
entities.push(entity); | entities.push(entity); | ||||
// If 'all' is false, only ungarrison the first matched unit. | // If 'all' is false, only ungarrison the first matched unit. | ||||
if (!all) | if (!all) | ||||
break; | break; | ||||
} | } | ||||
return this.PerformEject(entities, forced); | return this.UnloadEntities(entities); | ||||
}; | }; | ||||
/** | /** | ||||
* Unload all units, that belong to certain player | * Unload all units, that belong to certain player | ||||
* and order all own units to move to the rally point. | * and order all own units to move to the rally point. | ||||
* @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) | ||||
{ | { | ||||
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; | ||||
}); | }); | ||||
return this.PerformEject(entities, forced); | return this.UnloadEntities(entities); | ||||
}; | }; | ||||
/** | /** | ||||
* 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. | |||||
* @return {boolean} Whether the unloading was successful. | * @return {boolean} Whether the unloading was successful. | ||||
*/ | */ | ||||
GarrisonHolder.prototype.UnloadAll = function(forced) | GarrisonHolder.prototype.UnloadAll = function() | ||||
{ | { | ||||
return this.PerformEject(this.entities.slice(), forced); | return this.UnloadEntities(this.entities.slice()); | ||||
}; | }; | ||||
/** | /** | ||||
* 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 134 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | ||||
// Eject the units which can be ejected (if not in world, it generally means this holder | // Eject the units which can be ejected (if not in world, it generally means this holder | ||||
// is inside a holder which kills its entities, so do not eject) | // is inside a holder which kills its entities, so do not eject) | ||||
if (cmpPosition && cmpPosition.IsInWorld()) | if (cmpPosition && cmpPosition.IsInWorld()) | ||||
{ | { | ||||
let ejectables = entities.filter(ent => this.IsEjectable(ent)); | let ejectables = entities.filter(ent => this.IsEjectable(ent)); | ||||
if (ejectables.length) | if (ejectables.length) | ||||
this.PerformEject(ejectables, false); | this.UnloadEntities(ejectables); | ||||
} | } | ||||
// And destroy all remaining entities | // And destroy all remaining entities | ||||
let killedEntities = []; | let killedEntities = []; | ||||
for (let entity of entities) | for (let entity of 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(); | ||||
else | |||||
Engine.DestroyEntity(entity); | |||||
this.entities.splice(entityIndex, 1); | this.entities.splice(entityIndex, 1); | ||||
killedEntities.push(entity); | killedEntities.push(entity); | ||||
} | } | ||||
if (killedEntities.length) | if (killedEntities.length) | ||||
{ | { | ||||
Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { | Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { | ||||
"added": [], | "added": [], | ||||
▲ Show 20 Lines • Show All 77 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator
Thinks you must rename this. It's just 'RemoveFromGarrisonedList' or something now