Changeset View
Standalone View
binaries/data/mods/public/gui/session/selection.js
Show First 20 Lines • Show All 283 Lines • ▼ Show 20 Lines | EntitySelection.prototype.addList = function(ents, quiet, force = false) | ||||
// If someone else's player is the sole selected unit, don't allow adding to the selection | // If someone else's player is the sole selected unit, don't allow adding to the selection | ||||
let firstEntState = selection.length == 1 && GetEntityState(selection[0]); | let firstEntState = selection.length == 1 && GetEntityState(selection[0]); | ||||
if (firstEntState && firstEntState.player != g_ViewedPlayer && !force) | if (firstEntState && firstEntState.player != g_ViewedPlayer && !force) | ||||
return; | return; | ||||
let i = 1; | let i = 1; | ||||
let added = []; | let added = []; | ||||
ents = this.addBattalionMembers(ents); | |||||
Stan: It seems a bit dirty to overwrite the function param. | |||||
for (let ent of ents) | for (let ent of ents) | ||||
{ | { | ||||
if (selection.length + i > g_MaxSelectionSize) | if (selection.length + i > g_MaxSelectionSize) | ||||
break; | break; | ||||
if (this.selected[ent]) | if (this.selected[ent]) | ||||
continue; | continue; | ||||
Show All 26 Lines | EntitySelection.prototype.addList = function(ents, quiet, force = false) | ||||
} | } | ||||
this.groups.add(this.toList()); // Create Selection Groups | this.groups.add(this.toList()); // Create Selection Groups | ||||
this.onChange(); | this.onChange(); | ||||
}; | }; | ||||
EntitySelection.prototype.removeList = function(ents) | EntitySelection.prototype.removeList = function(ents) | ||||
{ | { | ||||
var removed = []; | var removed = []; | ||||
ents = this.addBattalionMembers(ents); | |||||
Done Inline ActionsI'd name the argument 'treatFormationsAsOne' or something like that. You can leave the explanation for the orderOne case. wraitii: I'd name the argument 'treatFormationsAsOne' or something like that. You can leave the… | |||||
Done Inline ActionsYeah I meant to ask for that too, because it might be confused with the orderone feature [ALT] keyword. Stan: Yeah I meant to ask for that too, because it might be confused with the orderone feature [ALT]… | |||||
for (let ent of ents) | for (let ent of ents) | ||||
if (this.selected[ent]) | if (this.selected[ent]) | ||||
{ | { | ||||
this.groups.removeEnt(ent); | this.groups.removeEnt(ent); | ||||
removed.push(ent); | removed.push(ent); | ||||
delete this.selected[ent]; | delete this.selected[ent]; | ||||
} | } | ||||
Show All 39 Lines | EntitySelection.prototype.toList = function() | ||||
let ents = []; | let ents = []; | ||||
for (let ent in this.selected) | for (let ent in this.selected) | ||||
ents.push(+ent); | ents.push(+ent); | ||||
return ents; | return ents; | ||||
}; | }; | ||||
EntitySelection.prototype.setHighlightList = function(ents) | EntitySelection.prototype.setHighlightList = function(ents) | ||||
{ | { | ||||
var highlighted = {}; | var highlighted = {}; | ||||
Done Inline ActionsForgot this one :) Stan: Forgot this one :) | |||||
Done Inline ActionsNot really, ents is used twice here in this function. ;) Freagarach: Not really, `ents` is used twice here in this function. ;) | |||||
ents = this.addBattalionMembers(ents); | |||||
for (let ent of ents) | for (let ent of ents) | ||||
highlighted[ent] = ent; | highlighted[ent] = ent; | ||||
var removed = []; | var removed = []; | ||||
var added = []; | var added = []; | ||||
// Remove highlighting for the old units that are no longer highlighted | // Remove highlighting for the old units that are no longer highlighted | ||||
// (excluding ones that are actively selected too) | // (excluding ones that are actively selected too) | ||||
Show All 25 Lines | |||||
EntitySelection.prototype.onChange = function() | EntitySelection.prototype.onChange = function() | ||||
{ | { | ||||
this.dirty = true; | this.dirty = true; | ||||
if (this.isSelection) | if (this.isSelection) | ||||
onSelectionChange(); | onSelectionChange(); | ||||
}; | }; | ||||
/** | /** | ||||
* Adds the battalion members of a selected entity to the selection. | |||||
* @param {number[]} ents - The entity IDs of selected entities. | |||||
* @return {number[]} - Some more entity IDs if part of a battalion was selected. | |||||
*/ | |||||
EntitySelection.prototype.addBattalionMembers = function(ents) | |||||
{ | |||||
for (let battalion of g_Battalions.battalions) | |||||
Done Inline ActionsMove below conditions Silier: Move below conditions | |||||
Done Inline ActionsCan entities be null? Should we check for it? Stan: Can entities be null? Should we check for it? | |||||
Done Inline ActionsThe rest doesn't check either, so I don't think we should check for it. (This errors out nicely when called with nullish value.) Freagarach: The rest doesn't check either, so I don't think we should check for it. (This errors out nicely… | |||||
if (ents.some(ent => battalion.ents.indexOf(ent) != -1)) | |||||
ents = ents.concat(battalion.ents.filter(ent => ents.indexOf(ent) == -1)); | |||||
Done Inline ActionsDo you really need that check ? Stan: Do you really need that check ? | |||||
Done Inline ActionsNot sure, I'll test. I thought it might save some performance perhaps, when not selecting a grouped entity. Freagarach: Not sure, I'll test. I thought it might save some performance perhaps, when not selecting a… | |||||
Done Inline ActionsApparently we do, otherwise hovering doesn't work. Freagarach: Apparently we do, otherwise hovering doesn't work. | |||||
Done Inline ActionsYou could inline here Silier: You could inline here | |||||
Done Inline ActionsI wonder if you couldn't save some cycles by filtering then checking the length and if more than 0 assign ? Would avoid the some. Stan: I wonder if you couldn't save some cycles by filtering then checking the length and if more… | |||||
Done Inline ActionsIt is again hovering that holds this off. Not sure why though,,, Freagarach: It is again hovering that holds this off. Not sure why though,,, | |||||
return ents; | |||||
}; | |||||
/** | |||||
* Cache some quantities which depends only on selection | * Cache some quantities which depends only on selection | ||||
Done Inline ActionsI measured somewhere that concat was really slow and that it's better to have a for loop with .push, but not sure it's worth the hassle. Stan: I measured somewhere that concat was really slow and that it's better to have a for loop with . | |||||
Done Inline ActionsAh, since this is called often in a large selection, it might indeed be worth the hassle. It may even be worth using a Set. Freagarach: Ah, since this is called often in a large selection, it might indeed be worth the hassle. It… | |||||
*/ | */ | ||||
var g_Selection = new EntitySelection(); | var g_Selection = new EntitySelection(); | ||||
g_Selection.isSelection = true; | g_Selection.isSelection = true; | ||||
var g_canMoveIntoFormation = {}; | var g_canMoveIntoFormation = {}; | ||||
var g_allBuildableEntities; | var g_allBuildableEntities; | ||||
var g_allTrainableEntities; | var g_allTrainableEntities; | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | for (let group of this.groups) | ||||
{ | { | ||||
group.rebuildGroup(renamedLookup); | group.rebuildGroup(renamedLookup); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
}; | }; | ||||
var g_Groups = new EntityGroupsContainer(); | var g_Groups = new EntityGroupsContainer(); | ||||
var g_Battalions = new BattalionsContainer(); | |||||
/** | |||||
* EntityBattalions class for managing entities in battalions (i.e. select one, select all). | |||||
*/ | |||||
function BattalionsContainer() | |||||
{ | |||||
this.battalions = []; | |||||
} | |||||
/** | |||||
* Adds an entity/entities to the battalion. | |||||
* @param {number[]} ents - The creatures from LOTR. | |||||
*/ | |||||
BattalionsContainer.prototype.formBattalion = function(ents) | |||||
{ | |||||
warn("Selection form-function called! " + uneval(ents)); | |||||
// Check whether there are free battalion spots. | |||||
for (let id = 0; true; id++) | |||||
{ | |||||
if (!this.battalions.some(battalion => battalion.id == id)) | |||||
{ | |||||
warn(id); | |||||
let index = this.battalions.length; | |||||
warn(index); | |||||
this.battalions[index] = {"id": id}; | |||||
this.addEntities(id, ents); | |||||
break; | |||||
} | |||||
} | |||||
warn("Selection form-function finished! " + uneval(this.battalions)); | |||||
}; | |||||
/** | |||||
* Removes battalion(s). | |||||
* @param {number[]} battalionIDs - The unique IDs of the battalions. | |||||
*/ | |||||
BattalionsContainer.prototype.disbandBattalion = function(battalionIDs) | |||||
{ | |||||
warn("Selection disband-function called! " + uneval(battalionIDs)); | |||||
warn("Selection disband-function battalions: " + uneval(this.battalions)); | |||||
this.battalions = this.battalions.filter(battalion => battalionIDs.indexOf(battalion.id) == -1); | |||||
warn("Selection disband-function finished! " + uneval(this.battalions)); | |||||
}; | |||||
/** | |||||
* Adds an entity/entities to the battalion. | |||||
* @param {number} battalionID - The unique ID of the battalion, passed by "formBattalion". | |||||
* @param {number[]} ents - The creatures from LOTR. | |||||
*/ | |||||
BattalionsContainer.prototype.addEntities = function(battalionID, ents) | |||||
{ | |||||
warn("Selection add-function called! " + uneval(battalionID) + ": " + uneval(ents)); | |||||
let index = +this.battalions.length - 1; | |||||
this.battalions[index].ents = []; | |||||
for (let ent of ents) | |||||
{ | |||||
// Entities cannot be in more than one battalion at the same time. | |||||
let bat = this.isPartOfBattalion(ent); | |||||
if (bat !== false) | |||||
this.removeEntity(bat, ent); | |||||
if (this.battalions[index].ents.indexOf(ent) != -1) | |||||
continue; | |||||
let entState = GetEntityState(ent); | |||||
// When this function is called during group rebuild, deleted | |||||
// entities will not yet have been removed, so entities might | |||||
// still be present in the group despite not existing. | |||||
if (!entState) | |||||
continue; | |||||
let templateName = entState.template; | |||||
let key = GetTemplateData(templateName).selectionGroupName || templateName; | |||||
this.battalions[index].ents.push(ent); | |||||
if (!this.battalions[index].template) | |||||
this.battalions[index].template = key; | |||||
} | |||||
}; | |||||
/** | |||||
* Removes an entity/entities from the battalion. | |||||
* @param {number} battalionID - The unique ID of the battalion. | |||||
* @param {number} ent - The entity ID of the entity to remove. | |||||
*/ | |||||
BattalionsContainer.prototype.removeEntity = function(battalionID, ent) | |||||
{ | |||||
warn("Selection remove-function called! " + uneval(battalionID) + ": " + uneval(ent)); | |||||
for (let battalion of this.battalions) | |||||
{ | |||||
if (battalion.id != battalionID) | |||||
continue; | |||||
let entIndex = battalion.ents.indexOf(ent); | |||||
if (entIndex != -1) | |||||
{ | |||||
let battalionIndex = this.battalions.indexOf(battalion); | |||||
this.battalions[battalionIndex].ents.splice(entIndex, 1); | |||||
} | |||||
} | |||||
warn("Selection remove-function finished! " + uneval(this.battalions)); | |||||
}; | |||||
/** | |||||
* Check wheter an entity is part of an battalion. | |||||
* @param {number} ent - The entity IDs to check. | |||||
* @return {number|boolean} - Either a number when the entity is part of a battalion | |||||
* or false when it is not. | |||||
*/ | |||||
BattalionsContainer.prototype.isPartOfBattalion = function(ent) | |||||
{ | |||||
//warn("Selection isPartOfBattalion-function called! " + uneval(ent)); | |||||
//warn("Selection isPartOfBattalion-function battalions: " + uneval(this.battalions)); | |||||
for (let battalion of this.battalions) | |||||
if (battalion.ents.indexOf(ent) != -1) | |||||
return battalion.id; | |||||
//warn("Selection isPartOfBattalion-function? Nope!"); | |||||
return false; | |||||
}; | |||||
/** | |||||
* Update the battalions. E.g when units die or change ownership and such. | |||||
*/ | |||||
BattalionsContainer.prototype.update = function() | |||||
{ | |||||
warn("Selection update-function called! " + uneval(this.battalions)); | |||||
this.checkRenamedEntities(); | |||||
let battalionsToDisband = []; | |||||
let battalions = this.battalions; | |||||
for (let battalion of battalions) | |||||
{ | |||||
warn("Selection update-function iteration: " + uneval(battalions)); | |||||
for (let ent of battalion.ents) | |||||
{ | |||||
let entState = GetEntityState(+ent); | |||||
// Remove deleted units | |||||
if (!entState) | |||||
this.removeEntity(battalion.id, ent); | |||||
} | |||||
warn("Selection update-function iteration: " + uneval(battalion)); | |||||
if (!battalion.ents.length) | |||||
battalionsToDisband.push(battalion.id); | |||||
} | |||||
if (battalionsToDisband.length) | |||||
this.disbandBattalion(battalionsToDisband); | |||||
warn("Selection update-function finished! " + uneval(this.battalions)); | |||||
}; | |||||
/** | |||||
* Update battalions if some entities in the battalion were renamed | |||||
* (in case of unit promotion or finishing building structure). | |||||
*/ | |||||
BattalionsContainer.prototype.checkRenamedEntities = function() | |||||
{ | |||||
let renamedEntities = Engine.GuiInterfaceCall("GetRenamedEntities"); | |||||
if (renamedEntities.length > 0) | |||||
{ | |||||
let renamedLookup = {}; | |||||
for (let renamedEntity of renamedEntities) | |||||
renamedLookup[renamedEntity.entity] = renamedEntity.newentity; | |||||
for (let battalion of this.battalions) | |||||
for (let renamedEntity of renamedEntities) | |||||
// Reconstruct the group if at least one entity has been renamed. | |||||
if (renamedEntity.entity in battalion.ents) | |||||
{ | |||||
let oldEnts = battalion.ents; | |||||
// We probably want to keep the old battalion ID? Just "add entities" might do the job. | |||||
this.disbandBattalion(battalion.id); | |||||
this.formBattalion(oldEnts); | |||||
break; | |||||
} | |||||
} | |||||
}; |
It seems a bit dirty to overwrite the function param.