Skip to content

Commit 80a13e3

Browse files
authored
Merge pull request #5247 from myk002/myk_spectate
initial rewrite of spectate
2 parents 5f74a67 + c762108 commit 80a13e3

11 files changed

Lines changed: 672 additions & 787 deletions

File tree

data/init/dfhack.keybindings.init

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ keybinding add Ctrl-T@dwarfmode/ViewSheets/UNIT|dwarfmode/ViewSheets/ITEM|dungeo
4949
# quicksave
5050
keybinding add Ctrl-Alt-S@dwarfmode quicksave
5151

52+
# toggle spectate
53+
keybinding add Ctrl-Shift-S@dwarfmode/Default "spectate toggle"
54+
5255
# designate the whole vein for digging
5356
keybinding add Ctrl-V@dwarfmode digv
5457
keybinding add Ctrl-Shift-V@dwarfmode "digv x"

docs/changelog.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,15 @@ Template for new versions:
5555
## New Tools
5656

5757
## New Features
58+
- `spectate`: can now specify number of seconds (in real time) before switching to follow a new unit unit
59+
- `spectate`: new "cinematic-action" mode that dynamically speeds up perspective switches based on intensity of conflict
60+
- `spectate`: new global keybinding for toggling spectate mode: Ctrl-Shift-S
5861

5962
## Fixes
63+
- `spectate`: don't allow temporarily modified announcement settings to be written to disk when "auto-unpause" mode is enabled
6064

6165
## Misc Improvements
66+
- `spectate`: player-set configuration is now stored globally instead of per-fort
6267

6368
## Documentation
6469

docs/plugins/spectate.rst

Lines changed: 122 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,61 +2,147 @@ spectate
22
========
33

44
.. dfhack-tool::
5-
:summary: Automatically follow productive dwarves.
6-
:tags: fort interface
5+
:summary: Automated spectator mode.
6+
:tags: fort inspection interface
7+
8+
This tool is for those who like to watch their dwarves go about their business.
9+
10+
When enabled, `spectate` will lock the camera to following the dwarves
11+
scurrying around your fort. Every once in a while, it will automatically switch
12+
to following a different dwarf. It can also switch to following animals,
13+
hostiles, or visiting units. You can switch to the next target (or a previous
14+
target) immediately with the left/right arrow keys.
15+
16+
`spectate` will disengage and turn itself off when you move the map, just like
17+
the vanilla follow mechanic. It will also disengage immediately if you open the
18+
squads menu for military action.
19+
20+
It can also annotate your dwarves on the map with their name, job, and other
21+
information, either as floating tooltips or in a panel that comes up when you
22+
hover the mouse over a target.
23+
24+
Run `gui/spectate` to configure the plugin's settings.
25+
26+
Settings are saved globally, so your preferences for `spectate` and its
27+
overlays will apply to all forts, not just the currently loaded one. Follow
28+
mode is automatically disabled when you load a fort so you can get your
29+
bearings before re-enabling.
730

831
Usage
932
-----
1033

1134
::
1235

1336
enable spectate
14-
spectate
37+
spectate [status]
38+
spectate toggle
1539
spectate set <setting> <value>
16-
spectate enable|disable <feature>
17-
18-
When enabled, the plugin will lock the camera to following the dwarves
19-
scurrying around your fort. Every once in a while, it will automatically switch
20-
to following a different dwarf, preferring dwarves on z-levels with the highest
21-
job activity.
22-
23-
If you have the ``auto-disengage`` feature disabled, you can switch to a new
24-
dwarf immediately by hitting one of the map movement keys (``wasd`` by
25-
default). To stop following dwarves, bring up `gui/launcher` and run
26-
``disable spectate``.
27-
28-
Changes to settings will be saved with your fort, but if `spectate` is enabled
29-
when you save the fort, it will disenable itself when you load so you can get
30-
your bearings before re-enabling follow mode with ``enable spectate`` again.
40+
spectate overlay <name> enable|disable
3141

3242
Examples
3343
--------
3444

3545
``enable spectate``
36-
Starting following dwarves and observing life in your fort.
46+
Start following dwarves and observing life in your fort.
47+
48+
``spectate toggle``
49+
Toggle the plugin on or off. Intended for use with a keybinding. The
50+
default is Ctrl-Shift-S.
3751

3852
``spectate``
3953
The plugin reports its configured status.
4054

41-
``spectate enable auto-unpause``
42-
Enable the spectate plugin to automatically dismiss pause events caused
43-
by the game. Siege events are one example of such a game event.
55+
``spectate set auto-unpause true``
56+
Configure `spectate` to automatically dismiss popups and pause events, like
57+
siege announcements.
4458

45-
``spectate set tick-threshold 1000``
46-
Set the tick interval between camera changes back to its default value.
59+
``spectate set follow-seconds 30``
60+
Configure `spectate` to switch targets every 30 seconds when in follow mode.
4761

48-
Features
49-
--------
50-
:auto-unpause: Toggle auto-dismissal of game pause events. (default: disabled)
51-
:auto-disengage: Toggle auto-disengagement of plugin through player
52-
intervention while unpaused. (default: disabled)
53-
:animals: Toggle whether to sometimes follow animals. (default: disabled)
54-
:hostiles: Toggle whether to sometimes follow hostiles (eg. undead,
55-
titans, invaders, etc.) (default: disabled)
56-
:visiting: Toggle whether to sometimes follow visiting units (eg.
57-
diplomats)
62+
``spectate overlay follow enable``
63+
Show informative tooltips that follow each unit on the map.
5864

5965
Settings
6066
--------
61-
:tick-threshold: Set the plugin's tick interval for changing the followed
62-
dwarf. (default: 1000)
67+
68+
``auto-disengage`` (default: enabled)
69+
Toggle automatically disabling the plugin when the player moves the map or
70+
opens the squad panel. If this is disabled, you will need to manually
71+
disable the plugin to turn off follow mode.
72+
73+
``auto-unpause`` (default: disabled)
74+
Toggle auto-dismissal of announcements that pause the game, like sieges,
75+
forgotten beasts, etc.
76+
77+
``cinematic-action`` (default: enabled)
78+
Toggle whether to switch targets more rapidly when there is conflict.
79+
80+
``follow-seconds`` (default: 10)
81+
Set the time interval for changing the followed unit. The interval does not
82+
include time that the game is paused.
83+
84+
``include-animals`` (default: disabled)
85+
Toggle whether to sometimes follow fort animals.
86+
87+
``include-hostiles`` (default: disabled)
88+
Toggle whether to sometimes follow hostiles (eg. undead, titans, invaders,
89+
etc.)
90+
91+
``include-visitors`` (default: disabled)
92+
Toggle whether to sometimes follow visiting units, like diplomats.
93+
94+
``include-wildlife`` (default: disabled)
95+
Toggle whether to sometimes follow wildlife.
96+
97+
``prefer-conflict`` (default: enabled)
98+
Toggle whether to prefer following units in active conflict.
99+
100+
``prefer-new-arrivals`` (default: enabled)
101+
Toggle whether to prefer following (non-siege) units that have newly
102+
arrived on the map.
103+
104+
``tooltip-follow-job`` (default: enabled)
105+
If the ``spectate.follow`` overlay is enabled, toggle whether to show the
106+
job of the dwarf in the tooltip.
107+
108+
``tooltip-follow-name`` (default: enabled)
109+
If the ``spectate.follow`` overlay is enabled, toggle whether to show the
110+
name of the dwarf in the tooltip.
111+
112+
``tooltip-follow-stress`` (default: enabled)
113+
If the ``spectate.follow`` overlay is enabled, toggle whether to show the
114+
happiness level (stress) of the dwarf in the tooltip.
115+
116+
``tooltip-hover-job`` (default: enabled)
117+
If the ``spectate.follow`` overlay is enabled, toggle whether to show the
118+
job of the dwarf in the hover panel.
119+
120+
``tooltip-hover-name`` (default: enabled)
121+
If the ``spectate.follow`` overlay is enabled, toggle whether to show the
122+
name of the dwarf in the hover panel.
123+
124+
``tooltip-hover-stress`` (default: enabled)
125+
If the ``spectate.follow`` overlay is enabled, toggle whether to show the
126+
happiness level (stress) of the dwarf in the hover panel.
127+
128+
Overlays
129+
--------
130+
131+
``spectate`` provides two overlays via the `overlay` framework to add
132+
information and functionality to the main map. These overlays can be controlled
133+
via the ``spectate overlay`` command or the ``Overlays`` tab in
134+
`gui/control-panel`.
135+
136+
The information displayed by these overlays can be configured via the
137+
``spectate set`` command or the `gui/spectate` interface.
138+
139+
``spectate.follow``
140+
Show informative tooltips that follow each unit on the map. You can enable
141+
this overlay by running ``spectate overlay follow enable`` or,
142+
equivalently, ``overlay enable spectate.follow``.
143+
144+
``spectate.hover``
145+
Show a popup panel with selected information when your mouse cursor hovers
146+
over a unit. You can enable this overlay by running
147+
``spectate overlay hover enable`` or, equivalently,
148+
``overlay enable spectate.hover``.

plugins/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ if(BUILD_SUPPORTED)
111111
#dfhack_plugin(siege-engine siege-engine.cpp LINK_LIBRARIES lua)
112112
dfhack_plugin(sort sort.cpp LINK_LIBRARIES lua)
113113
#dfhack_plugin(steam-engine steam-engine.cpp)
114-
add_subdirectory(spectate)
114+
dfhack_plugin(spectate spectate.cpp LINK_LIBRARIES lua)
115115
#dfhack_plugin(stockflow stockflow.cpp LINK_LIBRARIES lua)
116116
add_subdirectory(stockpiles)
117117
dfhack_plugin(stocks stocks.cpp LINK_LIBRARIES lua)

plugins/lua/spectate.lua

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
local _ENV = mkmodule('plugins.spectate')
2+
3+
local argparse = require('argparse')
4+
local json = require('json')
5+
local overlay = require('plugins.overlay')
6+
local utils = require('utils')
7+
8+
-- settings starting with 'tooltip-' are not passed to the C++ plugin
9+
local lua_only_settings_prefix = 'tooltip-'
10+
11+
local function get_default_state()
12+
return {
13+
['auto-disengage']=true,
14+
['auto-unpause']=false,
15+
['cinematic-action']=true,
16+
['follow-seconds']=10,
17+
['include-animals']=false,
18+
['include-hostiles']=false,
19+
['include-visitors']=false,
20+
['include-wildlife']=false,
21+
['prefer-conflict']=true,
22+
['prefer-new-arrivals']=true,
23+
['tooltip-follow-job']=true,
24+
['tooltip-follow-name']=true,
25+
['tooltip-follow-stress']=true,
26+
['tooltip-hover-job']=true,
27+
['tooltip-hover-name']=true,
28+
['tooltip-hover-stress']=true,
29+
}
30+
end
31+
32+
local function load_state()
33+
local state = get_default_state()
34+
local config = json.open('dfhack-config/spectate.json')
35+
for key in pairs(config.data) do
36+
if state[key] == nil then
37+
config.data[key] = nil
38+
end
39+
end
40+
utils.assign(state, config.data)
41+
config.data = state
42+
return config
43+
end
44+
45+
local config = load_state()
46+
47+
function refresh_cpp_config()
48+
for name,value in pairs(config.data) do
49+
if not name:startswith(lua_only_settings_prefix) then
50+
if type(value) == 'boolean' then
51+
value = value and 1 or 0
52+
end
53+
spectate_setSetting(name, value)
54+
end
55+
end
56+
end
57+
58+
-----------------------------
59+
-- commandline interface
60+
61+
local function print_status()
62+
print('spectate is:', isEnabled() and 'enabled' or 'disabled')
63+
print()
64+
print('settings:')
65+
for key, value in pairs(config.data) do
66+
print(' ' .. key .. ': ' .. tostring(value))
67+
end
68+
end
69+
70+
local function do_toggle()
71+
if isEnabled() then
72+
dfhack.run_command('disable', 'spectate')
73+
else
74+
dfhack.run_command('enable', 'spectate')
75+
end
76+
end
77+
78+
local function set_setting(key, value)
79+
if config.data[key] == nil then
80+
qerror('unknown setting: ' .. key)
81+
end
82+
if key == 'follow-seconds' then
83+
value = argparse.positiveInt(value, 'follow-seconds')
84+
else
85+
value = argparse.boolean(value, key)
86+
end
87+
config.data[key] = value
88+
config:write()
89+
if not key:startswith(lua_only_settings_prefix) then
90+
if type(value) == 'boolean' then
91+
value = value and 1 or 0
92+
end
93+
spectate_setSetting(key, value)
94+
end
95+
end
96+
97+
local function set_overlay(name, value)
98+
if not name:startswith('spectate.') then
99+
name = 'spectate.' .. name
100+
end
101+
if name ~= 'spectate.follow' and name ~= 'spectate.hover' then
102+
qerror('unknown overlay: ' .. name)
103+
end
104+
value = argparse.boolean(value, name)
105+
dfhack.run_command('overlay', value and 'enable' or 'disable', name)
106+
end
107+
108+
function parse_commandline(args)
109+
local command = table.remove(args, 1)
110+
if not command or command == 'status' then
111+
print_status()
112+
elseif command == 'toggle' then
113+
do_toggle()
114+
elseif command == 'set' then
115+
set_setting(args[1], args[2])
116+
elseif command == 'overlay' then
117+
set_overlay(args[1], args[2])
118+
else
119+
return false
120+
end
121+
122+
return true
123+
end
124+
125+
-----------------------------
126+
-- overlays
127+
128+
FollowOverlay = defclass(FollowOverlay, overlay.OverlayWidget)
129+
FollowOverlay.ATTRS{
130+
desc='Adds info tooltips that follow units on the map.',
131+
default_pos={x=1,y=1},
132+
fullscreen=true,
133+
viewscreens='dwarfmode/Default',
134+
}
135+
136+
HoverOverlay = defclass(HoverOverlay, overlay.OverlayWidget)
137+
HoverOverlay.ATTRS{
138+
desc='Shows info popup when hovering the mouse over units on the map.',
139+
default_pos={x=1,y=1},
140+
fullscreen=true,
141+
viewscreens='dwarfmode/Default',
142+
}
143+
144+
OVERLAY_WIDGETS = {
145+
follow=FollowOverlay,
146+
hover=HoverOverlay,
147+
}
148+
149+
return _ENV

0 commit comments

Comments
 (0)