Changeset View
Standalone View
binaries/data/mods/public/simulation/helpers/Commands.js
Show First 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | var g_Commands = { | ||||
{ | { | ||||
var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); | var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); | ||||
var notification = { "players": [player] }; | var notification = { "players": [player] }; | ||||
for (var key in cmd) | for (var key in cmd) | ||||
notification[key] = cmd[key]; | notification[key] = cmd[key]; | ||||
cmpGuiInterface.PushNotification(notification); | cmpGuiInterface.PushNotification(notification); | ||||
}, | }, | ||||
"cheat": function(player, cmd, data) | "cheat": function(player, cmd, data) | ||||
elexis: It says "GUI-only" in the patch upload notes.
Should a player be able to send this command? | |||||
{ | { | ||||
Cheat(cmd); | Cheat(cmd); | ||||
}, | }, | ||||
"diplomacy": function(player, cmd, data) | "diplomacy": function(player, cmd, data) | ||||
{ | { | ||||
let cmpCeasefireManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager); | let cmpCeasefireManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager); | ||||
if (data.cmpPlayer.GetLockTeams() || | if (data.cmpPlayer.GetLockTeams() || | ||||
▲ Show 20 Lines • Show All 181 Lines • ▼ Show 20 Lines | "back-to-work": function(player, cmd, data) | ||||
for (let ent of data.entities) | for (let ent of data.entities) | ||||
{ | { | ||||
var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); | var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); | ||||
if(!cmpUnitAI || !cmpUnitAI.BackToWork()) | if(!cmpUnitAI || !cmpUnitAI.BackToWork()) | ||||
notifyBackToWorkFailure(player); | notifyBackToWorkFailure(player); | ||||
} | } | ||||
}, | }, | ||||
"assign-idle-villager": function(player, cmd, data) | |||||
{ | |||||
let workers = cmd.idlers; | |||||
for (let entity of data.entities) | |||||
{ | |||||
let action; | |||||
let filteredWorkers; | |||||
let cmpFoundation = Engine.QueryInterface(entity, IID_Foundation); | |||||
let cmpRepairable = Engine.QueryInterface(entity, IID_Repairable); | |||||
if (cmpFoundation || cmpRepairable) | |||||
{ | |||||
filteredWorkers = workers.filter(worker => { | |||||
let cmpUnitAI = Engine.QueryInterface(worker, IID_UnitAI); | |||||
return cmpUnitAI && cmpUnitAI.CanRepair(entity); | |||||
}) | |||||
action = "repair"; | |||||
} | |||||
let cmpResourceSupply = Engine.QueryInterface(entity, IID_ResourceSupply); | |||||
if (cmpResourceSupply && cmpResourceSupply.GetCurrentAmount() > 0 && cmpResourceSupply.GetFreeSpots() > 0) | |||||
{ | |||||
filteredWorkers = workers.filter(worker => { | |||||
let cmpUnitAI = Engine.QueryInterface(worker, IID_UnitAI); | |||||
return cmpUnitAI && cmpUnitAI.CanGather(entity); | |||||
}).slice(0, cmpResourceSupply.GetFreeSpots()); | |||||
action = "gather"; | |||||
} | |||||
// No appropriate idle workers. | |||||
if (!filteredWorkers.length) | |||||
{ | |||||
notifyAssignIdleVillagersFailure(player, action); | |||||
return; | |||||
} | |||||
elexisUnsubmitted Not Done Inline ActionsThe problem with the pattern in this function is that it hardcodes (1) which order types exist (2) their logic. So it has similar effects like duplication, it's another place that needs to be kept in sync. If there are 10 command types supported, there would be 10 related checks here. The quantity of code insertion isn't so much the problem as the code structuring. The less places that have to be kept in sync, the easier it is to maintain, insert, keep in sync. Consider unit_actions.js, Commands.js and components/, they use objects with similar formats, so one can insert one new command without modifying surrounding code. I would assume it might be possible to add one property to the objects in unit_actions.js per Command. Then it can be scaled more too, for example it could support traders, military units If the function is to be kept in this place, it looks like this code within this function could just be a for-entity loop containing a for-action loop with the actions being defined in some object somewhere. elexis: The problem with the pattern in this function is that it hardcodes (1) which order types exist… | |||||
// If not all workers are desired select only the first. | |||||
// Could be improved to use the closest? | |||||
if (!cmd.all) | |||||
filteredWorkers = [filteredWorkers[0]]; | |||||
if (action == "gather") | |||||
GetFormationUnitAIs(filteredWorkers, player).forEach(cmpUnitAI => { | |||||
cmpUnitAI.Gather(entity, false); | |||||
}); | |||||
else if (action == "repair") | |||||
GetFormationUnitAIs(filteredWorkers, player).forEach(cmpUnitAI => { | |||||
cmpUnitAI.Repair(entity, true, false); | |||||
}); | |||||
// Exclude the previously used workers. | |||||
workers = workers.filter(worker => filteredWorkers.indexOf(worker) == -1); | |||||
} | |||||
}, | |||||
"remove-guard": function(player, cmd, data) | "remove-guard": function(player, cmd, data) | ||||
{ | { | ||||
for (let ent of data.entities) | for (let ent of data.entities) | ||||
{ | { | ||||
var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); | var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); | ||||
if (cmpUnitAI) | if (cmpUnitAI) | ||||
cmpUnitAI.RemoveGuard(); | cmpUnitAI.RemoveGuard(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 592 Lines • ▼ Show 20 Lines | cmpGUIInterface.PushNotification({ | ||||
"type": "text", | "type": "text", | ||||
"players": [player], | "players": [player], | ||||
"message": markForTranslation("Some unit(s) can't go back to work"), | "message": markForTranslation("Some unit(s) can't go back to work"), | ||||
"translateMessage": true | "translateMessage": true | ||||
}); | }); | ||||
} | } | ||||
/** | /** | ||||
* Sends a GUI notification about no worker(s) that can be assigned to the specific task. | |||||
*/ | |||||
function notifyAssignIdleVillagersFailure(player, type) | |||||
{ | |||||
let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); | |||||
cmpGUIInterface.PushNotification({ | |||||
"type": "text", | |||||
"players": [player], | |||||
"message": markForTranslation("There are no idle villagers that can " + type), | |||||
FreagarachAuthorUnsubmitted Done Inline ActionsThis is wrong. More information is needed for proper translation. Freagarach: This is wrong. More information is needed for proper translation. | |||||
elexisUnsubmitted Done Inline Actionsvariables in translated strings using %(name)s markForTranslation("There are no idle villagers that can %(action)s"), otherwise the python script wont extract the string. If there should be a case distinction, I suppose there should be one string per action, defined by the action. (Just informing that the ordered task could not be performed could be performed might work too otherwise,) elexis: variables in translated strings using `%(name)s` markForTranslation("There are no idle… | |||||
"translateMessage": true | |||||
}); | |||||
} | |||||
/** | |||||
* Get some information about the formations used by entities. | * Get some information about the formations used by entities. | ||||
* The entities must have a UnitAI component. | * The entities must have a UnitAI component. | ||||
*/ | */ | ||||
function ExtractFormations(ents) | function ExtractFormations(ents) | ||||
{ | { | ||||
var entities = []; // subset of ents that have UnitAI | var entities = []; // subset of ents that have UnitAI | ||||
var members = {}; // { formationentity: [ent, ent, ...], ... } | var members = {}; // { formationentity: [ent, ent, ...], ... } | ||||
for (let ent of ents) | for (let ent of ents) | ||||
▲ Show 20 Lines • Show All 839 Lines • Show Last 20 Lines |
It says "GUI-only" in the patch upload notes.
Should a player be able to send this command?
(hint: if there is a simulation command defined, the player can send it with arbitrary arguments, arbitrarily often)