Skip to content

Commit

Permalink
Additional features for order / cursor behavior (FAForever#4474)
Browse files Browse the repository at this point in the history
Introduces various new features to make it easier to issue orders:
- CTRL no longer toggles formation move, instead it represents a move command that ignores everything else
- ALT now represents an attack move command that ignores everything else
- Ground attack can no longer snap to props or units

In addition, when you hold CTRL or ALT the command mode (e.g., a reclaim order via hotkey) is cached and restored. This allows you to enable the reclaim mode, click a few props to reclaim, hold ctrl to issue move order, release ctrl, click more props to reclaim - all without entering reclaim mode again.
  • Loading branch information
Garanas authored Dec 8, 2022
1 parent 446d6bc commit 5840c79
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 65 deletions.
2 changes: 1 addition & 1 deletion engine/User.lua
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ function InternalSaveGame(filename, friendlyname, oncompletion)
end

---
---@param keyCode string
---@param keyCode string | number
---@return boolean
function IsKeyDown(keyCode)
end
Expand Down
2 changes: 1 addition & 1 deletion lua/platoon.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2511,7 +2511,7 @@ Platoon = Class(moho.platoon_methods) {
end
end
if not upgradeID and EntityCategoryContains(categories.MOBILE, v) then
upgradeID = aiBrain:FindUpgradeBP(v.UnitId, UpgradeTemplates.UpgradeTemplates[UnitBeingUpgradeFactionIndex])
upgradeID = aiBrain:FindUpgradeBP(v.UnitId, UpgradeTemplates.UnitUpgradeTemplates[UnitBeingUpgradeFactionIndex])
-- if we can't find a UnitUpgradeTemplate for this unit, warn the programmer
if not upgradeID then
-- Output: WARNING: [platoon.lua, line:xxx] *UnitUpgradeAI ERROR: Can\'t find UnitUpgradeTemplate for mobile unit: ABC1234
Expand Down
147 changes: 87 additions & 60 deletions lua/ui/controls/worldview.lua
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,12 @@ local orderToCursorCallback = {

-- orders that have use of a cursors
RULEUCC_Move = 'OnCursorMove',
RULEUCC_MoveAlt = 'OnCursorMoveAlt',
RULEUCC_Guard = 'OnCursorGuard',
RULEUCC_Repair = 'OnCursorRepair',
RULEUCC_Attack = 'OnCursorAttack',
RULEUCC_AttackAlt = 'OnCursorAttackAlt',
RULEUCC_AttackGround = 'OnCursorAttackGround',
RULEUCC_Patrol = 'OnCursorPatrol',
RULEUCC_Teleport = 'OnCursorTeleport',
RULEUCC_Tactical = 'OnCursorTactical',
Expand Down Expand Up @@ -233,9 +236,6 @@ WorldView = Class(moho.UIWorldView, Control) {
--- Flag that indicates whether the cursor is over the world (instead of the UI)
self.CursorOverWorld = false

--- Flag that indicates whether we ignore a lot of the processing and focus only on move and attack move commands
self.IgnoreMode = false

self.Trash = TrashBag()
end,

Expand All @@ -244,6 +244,7 @@ WorldView = Class(moho.UIWorldView, Control) {
SetIgnoreSelectTolerance = function(self)
local tolerance = -1000
if tolerance != self.SelectionTolerance then
LOG('Tolerance set to: ' .. tolerance)
ConExecute(string.format("ui_SelectTolerance %i", tolerance))
self.SelectionTolerance = tolerance
end
Expand All @@ -260,6 +261,7 @@ WorldView = Class(moho.UIWorldView, Control) {
end

if tolerance != self.SelectionTolerance then
LOG('Tolerance set to: ' .. tolerance)
ConExecute(string.format("ui_SelectTolerance %i", tolerance))
self.SelectionTolerance = tolerance
end
Expand All @@ -271,6 +273,7 @@ WorldView = Class(moho.UIWorldView, Control) {
local tolerance = Prefs.GetFromCurrentProfile('options.selection_threshold_reclaim')

if tolerance != self.SelectionTolerance then
LOG('Tolerance set to: ' .. tolerance)
ConExecute(string.format("ui_SelectTolerance %i", tolerance))
self.SelectionTolerance = tolerance
end
Expand Down Expand Up @@ -314,48 +317,33 @@ WorldView = Class(moho.UIWorldView, Control) {
local command_mode, command_data = unpack(CommandMode.GetCommandMode()) -- is set when we issue orders manually, try to build something, etc
local orderViaMouse = self:GetRightMouseButtonOrder() -- is set when our mouse is over a hostile unit, reclaim, etc and not in command mode

-- check if ignore mode is enabled
local ignoreMode = self:CheckIgnoreMode()
if ignoreMode ~= self.IgnoreMode then
if ignoreMode then
self:EnableIgnoreMode(true)
else
self:EnableIgnoreMode(false)
end

self.IgnoreMode = ignoreMode
end

-- process precedence hierarchy
---@type CommandCap | 'CommandHighlight'
local order

-- if toggled, we ignore everything but move and attack move
if self.IgnoreMode then
if orderViaMouse == 'RULEUCC_Move' and IsKeyDown(KeyCodeAlt) and selection then
order = 'RULEUCC_Attack'
else
order = 'RULEUCC_Move'
end
-- attack move that ignores everything
if IsKeyDown(KeyCodeAlt) and selection then
order = 'RULEUCC_AttackAlt'

-- otherwise, process as usual
-- regular move that ignores everything
elseif IsKeyDown(KeyCodeCtrl) and selection then
order = 'RULEUCC_MoveAlt'

-- usual order structure
else
-- first command mode
-- 1. command mode
if command_mode then
order = command_data.cursor or command_data.name

-- then command highlighting
if order == 'RULEUCC_Attack' then
order = 'RULEUCC_AttackGround'
end
-- 2. then command highlighting
elseif self:HasHighlightCommand() then
order = 'CommandHighlight'

-- then commands inherited by what the mouse is hovering over
else
-- check for right click, then it becomes an attack move order
if orderViaMouse == 'RULEUCC_Move' and IsKeyDown(KeyCodeAlt) and selection then
order = 'RULEUCC_Attack'
elseif orderViaMouse ~= 'RULEUCC_Move' then
order = orderViaMouse
end
-- 3. then whatever is below the mouse
elseif orderViaMouse and orderViaMouse != 'RULEUCC_Move' then
order = orderViaMouse
end
end

Expand All @@ -379,6 +367,9 @@ WorldView = Class(moho.UIWorldView, Control) {
-- attempt to create a new cursor
if event and self[event] then
self[event](self, identifier, true, event ~= self.CursorLastEvent)
if (event ~= self.CursorLastEvent) then
LOG(event)
end
else
self:OnCursorReset(identifier, true, event ~= self.CursorLastEvent)
end
Expand Down Expand Up @@ -460,42 +451,43 @@ WorldView = Class(moho.UIWorldView, Control) {
self:ApplyCursor()
end,

--- Called when the user starts dragging a command
--- Called when the order `RULEUCC_Move` is being applied
---@param self WorldView
---@param identifier CommandCap
---@param identifier 'RULEUCC_Move'
---@param enabled boolean
---@param changed boolean
OnCursorCommandDragStart = function(self, identifier, enabled, changed)
OnCursorMove = function(self, identifier, enabled, changed)
if enabled then
if changed then
local cursor = self.Cursor
cursor[1], cursor[2], cursor[3], cursor[4], cursor[5] = UIUtil.GetCursor("DRAGCOMMAND")
cursor[1], cursor[2], cursor[3], cursor[4], cursor[5] = UIUtil.GetCursor(identifier)
self:ApplyCursor()

self:EnableIgnoreMode(true)
end
else
self:EnableIgnoreMode(false)
end
end,

--- Called when the user stops dragging a command
--- Called when we hold control
---@param self WorldView
---@param identifier CommandCap
---@param identifier 'RULEUCC_MoveAlt'
---@param enabled boolean
---@param changed boolean
OnCursorCommandDragEnd = function(self, identifier, enabled, changed)
self:OnUpdateCursor()
end,

--- Called when the order `RULEUCC_Move` is being applied
---@param self WorldView
---@param identifier 'RULEUCC_Move'
---@param enabled boolean
---@param changed boolean
OnCursorMove = function(self, identifier, enabled, changed)
OnCursorMoveAlt = function(self, identifier, enabled, changed)
if enabled then
if changed then
local cursor = self.Cursor
cursor[1], cursor[2], cursor[3], cursor[4], cursor[5] = UIUtil.GetCursor(identifier)
cursor[1], cursor[2], cursor[3], cursor[4], cursor[5] = UIUtil.GetCursor('RULEUCC_Move')
self:ApplyCursor()

self:EnableIgnoreMode(true)
CommandMode.CacheAndClearCommandMode()
end
else
self:EnableIgnoreMode(false)
CommandMode.RestoreCommandMode()
end
end,

Expand Down Expand Up @@ -562,6 +554,47 @@ WorldView = Class(moho.UIWorldView, Control) {
end
end,

--- Called when we hold alt
---@param self WorldView
---@param identifier 'RULEUCC_AttackAlt'
---@param enabled boolean
---@param changed boolean
OnCursorAttackAlt = function(self, identifier, enabled, changed)
if enabled then
if changed then
local cursor = self.Cursor
cursor[1], cursor[2], cursor[3], cursor[4], cursor[5] = UIUtil.GetCursor('RULEUCC_Attack')
self:ApplyCursor()

self:EnableIgnoreMode(true)
CommandMode.CacheAndClearCommandMode()
end
else
self:EnableIgnoreMode(false)
CommandMode.RestoreCommandMode()
end
end,

---@param self WorldView
---@param identifier 'RULEUCC_AttackGround'
---@param enabled boolean
---@param changed boolean
OnCursorAttackGround = function(self, identifier, enabled, changed)
if enabled then
if changed then
local cursor = self.Cursor
cursor[1], cursor[2], cursor[3], cursor[4], cursor[5] = UIUtil.GetCursor('RULEUCC_Attack')
self:ApplyCursor()

self:EnableIgnoreMode(true)
end
else
self:EnableIgnoreMode(false)
end

self:OnCursorDecals(identifier, enabled, changed, AttackDecalFunc)
end,

--- Called when the order `RULEUCC_Patrol` is being applied
---@param self WorldView
---@param identifier 'RULEUCC_Attack'
Expand Down Expand Up @@ -607,9 +640,7 @@ WorldView = Class(moho.UIWorldView, Control) {
self:EnableIgnoreMode(true)
end
else
if not self.IgnoreMode then
self:EnableIgnoreMode(false)
end
self:EnableIgnoreMode(false)
end

self:OnCursorDecals(identifier, enabled, changed, TacticalDecalFunc)
Expand All @@ -630,9 +661,7 @@ WorldView = Class(moho.UIWorldView, Control) {
self:EnableIgnoreMode(true)
end
else
if not self.IgnoreMode then
self:EnableIgnoreMode(false)
end
self:EnableIgnoreMode(false)
end

self:OnCursorDecals(identifier, enabled, changed, NukeDecalFunc)
Expand Down Expand Up @@ -696,9 +725,7 @@ WorldView = Class(moho.UIWorldView, Control) {
end
end
else
if not self.IgnoreMode then
self:SetDefaultSelectTolerance()
end
self:SetDefaultSelectTolerance()
end
end,

Expand Down
31 changes: 28 additions & 3 deletions lua/ui/game/commandmode.lua
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,18 @@ local MathAtan = math.atan

---@alias CommandModeData CommandModeDataOrder | CommandModeDataBuild | CommandModeDataBuildAnchored | false

---@type CommandMode
local cachedCommandMode = false

---@type CommandMode
local commandMode = false

---@type CommandModeData
local modeData = false

---@type CommandModeData
local cachedModeData = false

--- Auto-disable command mode right after one command - used when shift is not pressed down.
local issuedOneCommand = false
local startBehaviors = {}
Expand Down Expand Up @@ -108,15 +114,15 @@ function StartCommandMode(newCommandMode, data)
end

--- Called when the command mode ends and deconstructs all the data.
-- @param isCancel Is set to true when it cancels a current command mode for a new one.
---@param isCancel boolean set when we're at the end of (a sequence of) order(s), is usually always true
function EndCommandMode(isCancel)

if ignoreSelection then
return
end

-- in case we want to end the command mode, without knowing it has already ended or not
if modeData then
if modeData then
-- regain selection if we were cheating in units
if modeData.cheat then
if modeData.ids and modeData.index <= table.getn(modeData.ids) then
Expand Down Expand Up @@ -164,6 +170,25 @@ function EndCommandMode(isCancel)
issuedOneCommand = false
end

--- Caches the command mode, allows us to restore it
function CacheCommandMode()
cachedCommandMode = commandMode
cachedModeData = modeData
end

function CacheAndClearCommandMode()
CacheCommandMode()
commandMode = false
modeData = false
end

--- Restores the cached command mode
function RestoreCommandMode()
if cachedCommandMode and cachedModeData then
StartCommandMode(cachedCommandMode, cachedModeData)
end
end

-- allocate the table once for performance
local commandModeTable = { }

Expand Down Expand Up @@ -449,7 +474,7 @@ function OnCommandIssued(command)
return false
end

-- unknown when set, do not understand when this applies yet. In other words: ???
-- is set when we hold shift, to queue up multiple commands. This is where the command mode stops
if not command.Clear then
issuedOneCommand = true
else
Expand Down
1 change: 1 addition & 0 deletions lua/ui/game/gamemain.lua
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,7 @@ ObserveSelection = import("/lua/shared/observable.lua").Create()
local hotkeyLabelsOnSelectionChanged = false
local upgradeTab = false
function OnSelectionChanged(oldSelection, newSelection, added, removed)

if ignoreSelection then
return
end
Expand Down

0 comments on commit 5840c79

Please sign in to comment.