Changeset View
Standalone View
binaries/data/mods/public/gui/session/unit_actions.js
Show First 20 Lines • Show All 1,085 Lines • ▼ Show 20 Lines | "actionCheck": function(target, selection) | ||||
return { | return { | ||||
"type": "unset-rallypoint", | "type": "unset-rallypoint", | ||||
"cursor": "action-unset-rally" | "cursor": "action-unset-rally" | ||||
}; | }; | ||||
}, | }, | ||||
"specificness": 11, | "specificness": 11, | ||||
}, | }, | ||||
// This is a "fake" action to show a failure cursor | |||||
// when only uncontrollable entities are selected. | |||||
"uncontrollable": | |||||
{ | |||||
"execute": function(target, action, selection, queued) | |||||
{ | |||||
return true; | |||||
}, | |||||
"actionCheck": function(target, selection) | |||||
{ | |||||
// Only show this action if all entities are marked uncontrollable. | |||||
let playerState = g_SimState.players[g_ViewedPlayer]; | |||||
if (playerState && playerState.controlsAll && selection.some(ent => { | |||||
let entState = GetEntityState(ent); | |||||
return entState && entState.identity && entState.identity.controllable; | |||||
})) | |||||
bb: linter complaining about indent | |||||
return false; | |||||
return { | |||||
"type": "none", | |||||
"cursor": "cursor-no", | |||||
"tooltip": translatePlural("This entity cannot be controlled.", "These entities cannot be controlled.", selection.length) | |||||
}; | |||||
}, | |||||
"specificness": 100, | |||||
}, | |||||
"none": | "none": | ||||
{ | { | ||||
"execute": function(target, action, selection, queued) | "execute": function(target, action, selection, queued) | ||||
{ | { | ||||
return true; | return true; | ||||
}, | }, | ||||
"specificness": 100, | "specificness": 100, | ||||
}, | }, | ||||
▲ Show 20 Lines • Show All 448 Lines • ▼ Show 20 Lines | if (playerState && playerState.controlsAll) | ||||
return false; | return false; | ||||
if (entState.resourceSupply && entState.resourceSupply.killBeforeGather) | if (entState.resourceSupply && entState.resourceSupply.killBeforeGather) | ||||
return translate("The entity has to be killed before it can be gathered from"); | return translate("The entity has to be killed before it can be gathered from"); | ||||
if (entState.capturePoints && entState.capturePoints[entState.player] < entState.maxCapturePoints / 2) | if (entState.capturePoints && entState.capturePoints[entState.player] < entState.maxCapturePoints / 2) | ||||
return translate("You cannot destroy this entity as you own less than half the capture points"); | return translate("You cannot destroy this entity as you own less than half the capture points"); | ||||
if (!entState.identity.canDelete) | if (!entState.identity.canDelete) | ||||
Done Inline ActionsShould we return undeletable when there is no controllability component? Freagarach: Should we return `undeletable` when there is no controllability component? | |||||
return translate("This entity is undeletable"); | return translate("This entity is undeletable"); | ||||
return false; | return false; | ||||
} | } | ||||
function DrawTargetMarker(target) | function DrawTargetMarker(target) | ||||
{ | { | ||||
Engine.GuiInterfaceCall("AddTargetMarker", { | Engine.GuiInterfaceCall("AddTargetMarker", { | ||||
Show All 14 Lines | function findGatherType(gatherer, supply) | ||||
if (gatherer.resourceGatherRates[supply.type.generic]) | if (gatherer.resourceGatherRates[supply.type.generic]) | ||||
return supply.type.generic; | return supply.type.generic; | ||||
return undefined; | return undefined; | ||||
} | } | ||||
function getActionInfo(action, target, selection) | function getActionInfo(action, target, selection) | ||||
{ | { | ||||
let simState = GetSimState(); | if (!selection || !selection.length || !GetEntityState(selection[0])) | ||||
// If the selection doesn't exist, no action | |||||
if (!GetEntityState(selection[0])) | |||||
return { "possible": false }; | return { "possible": false }; | ||||
if (!target) // TODO move these non-target actions to an object like unit_actions.js | if (!target) // TODO move these non-target actions to an object like unit_actions.js | ||||
Done Inline ActionsThis prevents restricting the move order,,, Freagarach: This prevents restricting the move order,,, | |||||
Done Inline ActionsIt seems to me you could just put the controllable check in this function. Then you don't have to add it everywhere, and you can still restrict the move order. wraitii: It seems to me you could just put the controllable check in this function. Then you don't have… | |||||
Done Inline ActionsFilter the entities which cannot be controlled? Freagarach: Filter the entities which cannot be controlled? | |||||
Done Inline ActionsYeah that would probably do the trick. I can't foresee a good reason why it wouldn't work, but maybe there's one wraitii: Yeah that would probably do the trick. I can't foresee a good reason why it wouldn't work, but… | |||||
Done Inline ActionsWell, there is quite a performance impact,,, (50 - 300 µs per tick.) Freagarach: Well, there is quite a performance impact,,, (50 - 300 µs per tick.) | |||||
Done Inline ActionsHow is that different when doing it in the orders? We're still iterating over all entities in the loop below. It's fine if you have to repeat the code a few times for different code paths. wraitii: How is that different when doing it in the orders? We're still iterating over all entities in… | |||||
Done Inline ActionsIt is different because one has to do it twice now ^^ Freagarach: It is different because one has to do it twice now ^^ | |||||
{ | { | ||||
// Ensure one entity at least is controllable. | |||||
let playerState = g_SimState.players[g_ViewedPlayer]; | |||||
if (playerState && !playerState.controlsAll && !selection.some(ent => { | |||||
let entState = GetEntityState(ent); | |||||
return entState && entState.identity && entState.identity.controllable; | |||||
})) | |||||
return { "possible": false }; | |||||
if (action == "set-rallypoint") | if (action == "set-rallypoint") | ||||
{ | { | ||||
let cursor = ""; | let cursor = ""; | ||||
let data = { "command": "walk" }; | let data = { "command": "walk" }; | ||||
if (Engine.HotkeyIsPressed("session.attackmove")) | if (Engine.HotkeyIsPressed("session.attackmove")) | ||||
{ | { | ||||
data.command = "attack-walk"; | data.command = "attack-walk"; | ||||
data.targetClasses = Engine.HotkeyIsPressed("session.attackmoveUnit") ? | data.targetClasses = Engine.HotkeyIsPressed("session.attackmoveUnit") ? | ||||
Show All 20 Lines | function getActionInfo(action, target, selection) | ||||
// Look at the first targeted entity | // Look at the first targeted entity | ||||
// (TODO: maybe we eventually want to look at more, and be more context-sensitive? | // (TODO: maybe we eventually want to look at more, and be more context-sensitive? | ||||
// e.g. prefer to attack an enemy unit, even if some friendly units are closer to the mouse) | // e.g. prefer to attack an enemy unit, even if some friendly units are closer to the mouse) | ||||
let targetState = GetEntityState(target); | let targetState = GetEntityState(target); | ||||
if (!targetState) | if (!targetState) | ||||
return { "possible": false }; | return { "possible": false }; | ||||
let simState = GetSimState(); | |||||
Done Inline ActionsI wonder if we could compute only if we need it. something like; let simState = null; if (selection.some(s => { if (!entState || !entState.identity.controllable) return false; return (g_UnitActions[action] && g_UnitActions[action].getActionInfo); })) let simState = GetSimState(); But that requires going through the loop twice. Maybe it's faster than getting the simstate dunno. Stan: I wonder if we could compute only if we need it.
something like;
```lang=js
let simState =… | |||||
Done Inline ActionsIt's quite likely that we'll have at least one entity with a GetActionInfo, particularly if we have man entities, so I think it's a pessimisation in general. wraitii: It's quite likely that we'll have at least one entity with a GetActionInfo, particularly if we… | |||||
Done Inline ActionsSimstate costs between 1 and 5 microseconds. Freagarach: Simstate costs between 1 and 5 microseconds. | |||||
let playerState = g_SimState.players[g_ViewedPlayer]; | |||||
// Check if any entities in the selection can do some of the available actions with target | // Check if any entities in the selection can do some of the available actions with target | ||||
for (let entityID of selection) | for (let entityID of selection) | ||||
{ | { | ||||
let entState = GetEntityState(entityID); | let entState = GetEntityState(entityID); | ||||
if (!entState) | if (!entState) | ||||
continue; | continue; | ||||
if (playerState && !playerState.controlsAll && !entState.identity.controllable) | |||||
continue; | |||||
if (g_UnitActions[action] && g_UnitActions[action].getActionInfo) | if (g_UnitActions[action] && g_UnitActions[action].getActionInfo) | ||||
{ | { | ||||
let r = g_UnitActions[action].getActionInfo(entState, targetState, simState); | let r = g_UnitActions[action].getActionInfo(entState, targetState, simState); | ||||
if (r && r.possible) // return true if it's possible for one of the entities | if (r && r.possible) // return true if it's possible for one of the entities | ||||
return r; | return r; | ||||
} | } | ||||
} | } | ||||
return { "possible": false }; | return { "possible": false }; | ||||
} | } |
linter complaining about indent