Merge branch '5010-beta' into develop

develop
Myk Taylor 2023-09-17 21:15:33 -07:00
commit 53574fb2b3
No known key found for this signature in database
15 changed files with 219 additions and 180 deletions

@ -92,13 +92,6 @@ jobs:
repository: ${{ inputs.structures_ref && github.repository || 'DFHack/df-structures' }} repository: ${{ inputs.structures_ref && github.repository || 'DFHack/df-structures' }}
ref: ${{ inputs.structures_ref }} ref: ${{ inputs.structures_ref }}
path: library/xml path: library/xml
- name: Clone structures (temporary override)
if: '!inputs.structures_ref'
uses: actions/checkout@v3
with:
repository: DFHack/df-structures
ref: refs/heads/linux
path: library/xml
- name: Fetch ccache - name: Fetch ccache
if: inputs.platform-files if: inputs.platform-files
uses: actions/cache/restore@v3 uses: actions/cache/restore@v3

@ -7,9 +7,9 @@ cmake_policy(SET CMP0074 NEW)
project(dfhack) project(dfhack)
# set up versioning. # set up versioning.
set(DF_VERSION "50.09") set(DF_VERSION "50.10")
set(DFHACK_RELEASE "r4") set(DFHACK_RELEASE "beta1")
set(DFHACK_PRERELEASE FALSE) set(DFHACK_PRERELEASE TRUE)
set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}")
set(DFHACK_ABI_VERSION 1) set(DFHACK_ABI_VERSION 1)

Before

Width:  |  Height:  |  Size: 997 B

After

Width:  |  Height:  |  Size: 997 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

@ -45,67 +45,75 @@ Here are some common tasks people use DFHack tools to accomplish:
- Quickly scan the map for visible ores of specific types so you can focus - Quickly scan the map for visible ores of specific types so you can focus
your mining efforts your mining efforts
Some tools are one-shot commands. For example, you can run `unforbid all <unforbid>` Some tools are one-shot commands. For example, you can run
to claim all (reachable) items on the map after a messy siege. `unforbid all <unforbid>` to claim all (reachable) items on the map after a
messy siege.
Other tools must be `enabled <enable>` and then they will run in the background.
For example, `enable seedwatch <seedwatch>` will start monitoring your stocks of Other tools must be `enabled <enable>` once and then they will run in the
seeds and prevent your chefs from cooking seeds that you need for planting. background. For example, once enabled, `seedwatch` will start monitoring your
Tools that are enabled in the context of a fort will save their state with that stocks of seeds and prevent your chefs from cooking seeds that you need for
fort, and they will remember that they are enabled the next time you load your save. planting. Tools that are enabled in the context of a fort will save their state
with that fort, and they will remember that they are enabled the next time you
A third class of tools add information to the screen or provide new integrated load your save.
functionality via the DFHack `overlay` framework. For example, the `unsuspend`
tool, in addition to its basic function of unsuspending all building construction A third class of tools adds information to the screen or provides new integrated
jobs, can also overlay a marker on suspended buildings to indicate that they are functionality via the DFHack `overlay` framework. For example, the `sort` tool
suspended (and will use different markers to tell you whether this is a problem). adds widgets to the squad member selection screen that allow you to search,
sort, and filter the list of military candidates. You don't have to run any
command to get the benefits of the tool, it appears automatically when you're
on the relevant screen.
How can I figure out which commands to run? How can I figure out which commands to run?
------------------------------------------- -------------------------------------------
There are several ways to scan DFHack tools and find the ones you need right now. There are several ways to scan DFHack tools and find the ones you need right
now.
The first place to check is the DFHack logo hover hotspot. It's in the upper The first place to check is the DFHack logo menu. It's in the upper left corner
left corner of the screen by default, though you can move it anywhere you want of the screen by default, though you can move it anywhere you want with the
with the `gui/overlay` configuration UI. `gui/overlay` configuration UI.
When you hover the mouse over the logo (or hit the Ctrl-Shift-C keyboard shortcut) When you click on the logo (or hit the Ctrl-Shift-C keyboard shortcut), a short
a list of DFHack tools relevant to the current context comes up. For example, when list of popular, relevant DFHack tools comes up. These are the tools that have
you have a unit selected, the hotspot will show a list of tools that inspect been assigned hotkeys that are active in the current context. For example, when
units, allow you to edit them, or maybe even teleport them. Next to each tool, you're looking at a fort map, the list will contain fortress design tools like
you'll see the hotkey you can hit to invoke the command without even opening the `gui/quickfort` and `gui/design`. You can click on the tools in the list, or
hover list. note the hotkeys listed next to them and maybe use them to launch the tool next
time without even opening the logo menu.
The second place to check is the DFHack control panel: `gui/control-panel`. It The second place to check is the DFHack control panel: `gui/control-panel`. It
will give you an overview of which tools are currently enabled, and will allow will give you an overview of which tools are currently enabled, and will allow
you to toggle them on or off, see help text for them, or launch their dedicated you to toggle them on or off, see help text for them, or launch their dedicated
configuration UIs. You can open the control panel from anywhere with the configuration UIs. You can open the control panel from anywhere with the
Ctrl-Shift-E hotkey or by selecting it from the logo hover list. Ctrl-Shift-E hotkey or by selecting it from the logo menu list.
In the control panel, you can also select which tools you'd like to be In the control panel, you can also select which tools you'd like to be
automatically enabled when you start a new fort. There are also system settings automatically enabled and popular commands you'd like to run when you start a
you can change, like whether DFHack windows will pause the game when they come new fort. On the "Preferences" tab, there are settings you can change, like
up. whether you want to limit DFHack functionality to interface improvements,
bugfixes, and productivity tools, hiding the god-mode tools ("mortal mode") or
Finally, you can explore the full extent of the DFHack catalog in `gui/launcher`, whether you want DFHack windows to pause the game when they come up.
which is always listed first in the DFHack logo hover list. You can also bring up
the launcher by tapping the backtick key (\`) or hitting Ctrl-Shift-D. In the Finally, you can explore the full extent of the DFHack catalog in
launcher, you can quickly autocomplete any command name by selecting it in the `gui/launcher`, which is always listed first in the DFHack logo menu list. You
list on the right side of the window. Commands are ordered by how often you run can also bring up the launcher by tapping the backtick key (\`) or hitting
them, so your favorite commands will always be on top. You can also pull full Ctrl-Shift-D. In the launcher, you can quickly autocomplete any command name by
commandlines out of your history with Alt-S or by clicking on the "history search" selecting it in the list on the right side of the window. Commands are ordered
hotkey hint. by how often you run them, so your favorite commands will always be on top. You
can also pull full commandlines out of your history with Alt-S or by clicking
Once you have typed (or autocompleted, or searched for) a command, other commands on the "history search" hotkey hint.
related to the one you have selected will appear in the right-hand panel. Scanning
through that list is a great way to learn about new tools that you might find Once you have typed (or autocompleted, or searched for) a command, other
useful. You can also see how commands are grouped by running the `tags` command. commands related to the one you have selected will appear in the right-hand
panel. Scanning through that list is a great way to learn about new tools that
you might find useful. You can also see how commands are grouped by running the
`tags` command.
The bottom panel will show the full help text for the command you are running, The bottom panel will show the full help text for the command you are running,
allowing you to refer to the usage documentation and examples when you are typing allowing you to refer to the usage documentation and examples when you are
your command. After you run a command, the bottom panel switches to command output typing your command. After you run a command, the bottom panel switches to
mode, but you can get back to the help text by hitting Ctrl-T or clicking on the command output mode, but you can get back to the help text by hitting Ctrl-T or
``Help`` tab. clicking on the ``Help`` tab.
How do DFHack in-game windows work? How do DFHack in-game windows work?
----------------------------------- -----------------------------------
@ -122,84 +130,88 @@ you type at the keyboard. Hit Esc or right click to close the window or cancel
the current action. You can click anywhere on the screen that is not a DFHack the current action. You can click anywhere on the screen that is not a DFHack
window to unfocus the window and let it just sit in the background. It won't window to unfocus the window and let it just sit in the background. It won't
respond to key presses or mouse clicks until you click on it again to give it respond to key presses or mouse clicks until you click on it again to give it
focus. If no DFHack windows are focused, you can right click directly on a window focus. If no DFHack windows are focused, you can right click directly on a
to close it without left clicking to focus it first. window to close it without left clicking to focus it first.
DFHack windows are draggable from the title bar or from anywhere on the window DFHack windows are draggable from the title bar or from anywhere on the window
that doesn't have a mouse-clickable widget on it. Many are resizable as well that doesn't have a mouse-clickable widget on it. Many are resizable as well
(if the tool window has components that can reasonably be resized). (if the tool window has components that can reasonably be resized).
You can generally use DFHack tools without interrupting the game. That is, if the You can generally use DFHack tools without interrupting the game. That is, if
game is unpaused, it can continue to run while a DFHack window is open. If configured the game is unpaused, it can continue to run while a DFHack window is open. If
to do so in `gui/control-panel`, tools will initially pause the game to let you configured to do so in `gui/control-panel`, tools will initially pause the game
focus on the task at hand, but you can unpause like normal if you want. You can to let you focus on the task at hand, but you can unpause like normal if you
also interact with the map, scrolling it with the keyboard or mouse and selecting want. You can also interact with the map, scrolling it with the keyboard or
units, buildings, and items. Some tools will intercept all mouse clicks to allow mouse and selecting units, buildings, and items. Some tools will intercept all
you to select regions on the map. When these tools have focus, you will not be able mouse clicks to allow you to select regions of the map. When these tools have
to use the mouse to interact with map elements or pause/unpause the game. Therefore, focus, you will not be able to use the mouse to interact with map elements or
these tools will pause the game when they open, regardless of your settings in pause/unpause the game. Therefore, these tools will pause the game when they
`gui/control-panel`. You can still unpause with the keyboard (spacebar by default), open, regardless of your settings in `gui/control-panel`. You can still unpause
though. with the keyboard (spacebar by default), though.
Where do I go next? Where do I go next?
------------------- -------------------
To recap: To recap:
You can get to popular, relevant tools for the current context by hovering You can get to popular, relevant tools for the current context by clicking on
the mouse over the DFHack logo or by hitting Ctrl-Shift-C. the DFHack logo or by hitting Ctrl-Shift-C.
You can enable DFHack tools and configure settings with `gui/control-panel`, You can enable DFHack tools and configure settings with `gui/control-panel`,
which you can access directly with the Ctrl-Shift-E hotkey. which you can open from the DFHack logo or access directly with the
Ctrl-Shift-E hotkey.
You can get to the launcher and its integrated autocomplete, history search, You can get to the launcher and its integrated autocomplete, history search,
and help text by hitting backtick (\`) or Ctrl-Shift-D, or, of course, by and help text by hitting backtick (\`) or Ctrl-Shift-D, or, of course, by
running it from the logo hover list. running it from the logo menu list.
With those three interfaces, you have the complete DFHack tool suite at your With those three interfaces, you have the complete DFHack tool suite at your
fingertips. So what to run first? Here are a few commands to get you started. fingertips. So what to run first? Here are a few examples to get you started.
You can run them all from the launcher.
First, let's import some useful manager orders to keep your fort stocked with First, let's import some useful manager orders to keep your fort stocked with
basic necessities. Run ``orders import library/basic``. If you go to your basic necessities. Run ``orders import library/basic``. If you go to your
manager orders screen, you can see all the orders that have been created for you. manager orders screen, you can see all the orders that have been created for
Note that you could have imported the orders directly from this screen as well, you. Note that you could have imported the orders directly from this screen as
using the DFHack `overlay` widget at the bottom of the manager orders panel. well, using the DFHack `overlay` widget at the bottom of the manager orders
panel.
Next, try setting up `autochop` to automatically designate trees for chopping when
you get low on usable logs. Run `gui/control-panel` and select ``autochop`` in the Next, try setting up `autochop` to automatically designate trees for chopping
``Fort`` list. Click on the button to the left of the name or hit Enter to enable when you get low on usable logs. Run `gui/control-panel` and select
it. You can then click on the configure button (the gear icon) to launch ``autochop`` in the ``Fort`` list. Click on the button to the left of the name
`gui/autochop` if you'd like to customize its settings. If you have the extra or hit Enter to enable it. You can then click on the configure button (the gear
screen space, you can go ahead and set the `gui/autochop` window to minimal mode icon) to launch `gui/autochop` if you'd like to customize its settings. If you
(click on the hint near the upper right corner of the window or hit Alt-M) and have the extra screen space, you can go ahead and set the `gui/autochop` window
click on the map so the window loses keyboard focus. As you play the game, you can to minimal mode (click on the hint near the upper right corner of the window or
glance at the live status panel to check on your stocks of wood. hit Alt-M) and click on the map so the window loses keyboard focus. As you play
the game, you can glance at the live status panel to check on your stocks of
Finally, let's do some fort design copy-pasting. Go to some bedrooms that you have wood.
set up in your fort. Run `gui/blueprint`, set a name for your blueprint by
clicking on the name field (or hitting the 'n' hotkey), typing "rooms" (or whatever) Finally, let's do some fort design copy-pasting. Go to some bedrooms that you
and hitting Enter to set. Then draw a box around the target area by clicking with have set up in your fort. Run `gui/blueprint`, set a name for your blueprint by
the mouse. When you select the second corner, the blueprint will be saved to your clicking on the name field (or hitting the 'n' hotkey), typing "rooms" (or
``blueprints`` subfolder. whatever) and hitting Enter to set. Then draw a box around the target area by
clicking with the mouse. When you select the second corner, the blueprint will
Now open up `gui/quickfort`. You can search for the blueprint you just created by be saved to your ``dfhack-config/blueprints`` subfolder.
typing its name, but it should be up near the top already. If you copied a dug-out
area with furniture in it, your blueprint will have two labels: "/dig" and "/build". Now open up `gui/quickfort`. You can search for the blueprint you just created
Click on the "/dig" blueprint or select it with the keyboard arrow keys and hit Enter. by typing its name, but it should be up near the top already. If you copied a
You can rotate or flip the blueprint around if you need to with the transform hotkeys. dug-out area with furniture in it, your blueprint will have two labels: "/dig"
You'll see a preview of where the blueprint will be applied as you move the mouse and "/build". Click on the "/dig" blueprint or select it with the keyboard
cursor around the map. Red outlines mean that the blueprint may fail to fully apply arrow keys and hit Enter. You can rotate or flip the blueprint around if you
at that location, so be sure to choose a spot where all the preview tiles are shown need to with the transform hotkeys. You'll see a preview of where the blueprint
with green diamonds. Click the mouse or hit Enter to apply the blueprint and will be applied as you move the mouse cursor around the map. Red outlines mean
designate the tiles for digging. Your dwarves will come and dig it out as if you that the blueprint may fail to fully apply at that location, so be sure to
had designated the tiles yourself. choose a spot where all the preview tiles are shown with green diamonds. Click
the mouse or hit Enter to apply the blueprint and designate the tiles for
Once the area is dug out, run `gui/quickfort` again and select the "/build" blueprint digging. Your dwarves will come and dig it out as if you had designated the
this time. Apply the blueprint in the dug-out area, and your furniture will be tiles yourself.
designated. It's just that easy! Note that `quickfort` uses `buildingplan` to place
buildings, so you don't even need to have the relevant furniture or building Once the area is dug out, run `gui/quickfort` again and select your "/build"
materials in stock. The planned furniture/buildings will get built whenever you are blueprint this time. Hit ``o`` to generate manager orders for the required
able to produce the building materials. furniture. Apply the blueprint in the dug-out area, and your furniture will be
designated. It's just that easy! Note that `quickfort` uses `buildingplan` to
place buildings, so you don't even need to have the relevant furniture or
building materials in stock yet. The planned furniture/buildings will get built
whenever you are able to produce the building materials.
There are many, many more tools to explore. Have fun! There are many, many more tools to explore. Have fun!

@ -19,14 +19,17 @@ Usage
Menu overlay widget Menu overlay widget
------------------- -------------------
The in-game hotkeys menu is registered with the `overlay` framework and can be The in-game hotkeys menu is registered with the `overlay` framework and appears
enabled as a hotspot in the upper-left corner of the screen. You can bring up as a DFHack logo in the upper-left corner of the screen. You can bring up the
the menu by hovering the mouse cursor over the hotspot and can select a command menu by clicking on the logo or by hitting the global :kbd:`Ctrl`:kbd:`Shift`:kbd:`c` hotkey. You can select a command to run from
to run from the list by clicking on it with the mouse or by using the keyboard the list by clicking on it with the mouse or by using the keyboard to select a
to select a command with the arrow keys and hitting :kbd:`Enter`. command with the arrow keys and hitting :kbd:`Enter`.
The menu closes automatically when an action is taken or when you click or
right click anywhere else on the screen.
A short description of the command will appear in a nearby textbox. If you'd A short description of the command will appear in a nearby textbox. If you'd
like to see the full help text for the command or edit the command before like to see the full help text for the command or edit the command before
running, you can open it for editing in `gui/launcher` by right clicking on the running, you can open it for editing in `gui/launcher` by shift clicking on the
command, left clicking on the arrow to the left of the command, or by pressing command, left clicking on the arrow to the left of the command, or by pressing
the right arrow key while the command is selected. the right arrow key while the command is selected.

@ -1033,7 +1033,11 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, s
} }
else if (first == "die") else if (first == "die")
{ {
#ifdef WIN32
TerminateProcess(GetCurrentProcess(),666);
#else
std::_Exit(666); std::_Exit(666);
#endif
} }
else if (first == "kill-lua") else if (first == "kill-lua")
{ {

@ -48,6 +48,8 @@ namespace df {
STL_OPAQUE_IDENTITY_TRAITS(fstream); STL_OPAQUE_IDENTITY_TRAITS(fstream);
STL_OPAQUE_IDENTITY_TRAITS(mutex); STL_OPAQUE_IDENTITY_TRAITS(mutex);
STL_OPAQUE_IDENTITY_TRAITS(future<void>); STL_OPAQUE_IDENTITY_TRAITS(future<void>);
STL_OPAQUE_IDENTITY_TRAITS(function<void()>);
STL_OPAQUE_IDENTITY_TRAITS(optional<std::function<void()> >);
buffer_container_identity buffer_container_identity::base_instance; buffer_container_identity buffer_container_identity::base_instance;
} }

@ -138,7 +138,7 @@ void Process::getMemRanges( vector<t_memrange> & ranges )
{ {
t_memrange temp; t_memrange temp;
temp.name[0] = 0; temp.name[0] = 0;
sscanf(buffer, "%zx-%zx %s %zx %2zx:%2zx %zu %[^\n]", sscanf(buffer, "%zx-%zx %s %zx %zx:%zx %zu %[^\n]",
&start, &start,
&end, &end,
(char*)&permissions, (char*)&permissions,

@ -25,11 +25,13 @@ distribution.
#pragma once #pragma once
#include <deque> #include <deque>
#include <future>
#include <map> #include <map>
#include <optional>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <unordered_map>
#include <vector> #include <vector>
#include <future>
#include "DataDefs.h" #include "DataDefs.h"
@ -573,6 +575,20 @@ namespace df
OPAQUE_IDENTITY_TRAITS(std::fstream); OPAQUE_IDENTITY_TRAITS(std::fstream);
OPAQUE_IDENTITY_TRAITS(std::mutex); OPAQUE_IDENTITY_TRAITS(std::mutex);
OPAQUE_IDENTITY_TRAITS(std::future<void>); OPAQUE_IDENTITY_TRAITS(std::future<void>);
OPAQUE_IDENTITY_TRAITS(std::function<void()>);
OPAQUE_IDENTITY_TRAITS(std::optional<std::function<void()> >);
#ifdef BUILD_DFHACK_LIB
template<typename T>
struct DFHACK_EXPORT identity_traits<std::shared_ptr<T>> {
static opaque_identity *get() {
typedef std::shared_ptr<T> type;
static std::string name = std::string("shared_ptr<") + typeid(T).name() + ">";
static opaque_identity identity(sizeof(type), allocator_noassign_fn<type>, name);
return &identity;
}
};
#endif
template<> struct DFHACK_EXPORT identity_traits<bool> { template<> struct DFHACK_EXPORT identity_traits<bool> {
static bool_identity identity; static bool_identity identity;
@ -653,6 +669,10 @@ namespace df
static container_identity *get(); static container_identity *get();
}; };
template<class KT, class T> struct identity_traits<std::unordered_map<KT, T>> {
static container_identity *get();
};
template<> struct identity_traits<BitArray<int> > { template<> struct identity_traits<BitArray<int> > {
static bit_array_identity identity; static bit_array_identity identity;
static bit_container_identity *get() { return &identity; } static bit_container_identity *get() { return &identity; }
@ -730,6 +750,13 @@ namespace df
return &identity; return &identity;
} }
template<class KT, class T>
inline container_identity *identity_traits<std::unordered_map<KT, T>>::get() {
typedef std::unordered_map<KT, T> container;
static ro_stl_assoc_container_identity<container> identity("unordered_map", identity_traits<KT>::get(), identity_traits<T>::get());
return &identity;
}
template<class T> template<class T>
inline bit_container_identity *identity_traits<BitArray<T> >::get() { inline bit_container_identity *identity_traits<BitArray<T> >::get() {
static bit_array_identity identity(identity_traits<T>::get()); static bit_array_identity identity(identity_traits<T>::get());

@ -962,6 +962,7 @@ int dfhack_lua_viewscreen::do_input(lua_State *L)
if (!self) return 0; if (!self) return 0;
auto keys = (std::set<df::interface_key>*)lua_touserdata(L, 2); auto keys = (std::set<df::interface_key>*)lua_touserdata(L, 2);
if (!keys) return 0;
lua_getfield(L, -1, "onInput"); lua_getfield(L, -1, "onInput");

@ -377,10 +377,14 @@ void Checker::dispatch_container(const QueueItem & item, const CheckedStructure
{ {
// TODO: check DfArray // TODO: check DfArray
} }
else if (base_container.substr(0, 4) == "map<") else if (base_container.starts_with("map<"))
{ {
// TODO: check map // TODO: check map
} }
else if (base_container.starts_with("unordered_map<"))
{
// TODO: check unordered_map
}
else else
{ {
UNEXPECTED; UNEXPECTED;

@ -82,7 +82,7 @@ haul_delete_stop.message = "Are you sure you want to delete this stop?"
depot_remove = defconf('depot-remove') depot_remove = defconf('depot-remove')
function depot_remove.intercept_key(key) function depot_remove.intercept_key(key)
if df.global.game.main_interface.current_hover == 299 and if df.global.game.main_interface.current_hover == 301 and
key == MOUSE_LEFT and key == MOUSE_LEFT and
df.building_tradedepotst:is_instance(dfhack.gui.getSelectedBuilding(true)) then df.building_tradedepotst:is_instance(dfhack.gui.getSelectedBuilding(true)) then
for _, caravan in pairs(df.global.plotinfo.caravans) do for _, caravan in pairs(df.global.plotinfo.caravans) do
@ -98,7 +98,7 @@ depot_remove.message = "Are you sure you want to remove this depot?\n" ..
squad_disband = defconf('squad-disband') squad_disband = defconf('squad-disband')
function squad_disband.intercept_key(key) function squad_disband.intercept_key(key)
return key == MOUSE_LEFT and df.global.game.main_interface.current_hover == 341 return key == MOUSE_LEFT and df.global.game.main_interface.current_hover == 343
end end
squad_disband.title = "Disband squad" squad_disband.title = "Disband squad"
squad_disband.message = "Are you sure you want to disband this squad?" squad_disband.message = "Are you sure you want to disband this squad?"

@ -5,7 +5,8 @@ local helpdb = require('helpdb')
local overlay = require('plugins.overlay') local overlay = require('plugins.overlay')
local widgets = require('gui.widgets') local widgets = require('gui.widgets')
local textures = dfhack.textures.loadTileset('hack/data/art/dfhack.png', 8, 12) local logo_textures = dfhack.textures.loadTileset('hack/data/art/logo.png', 8, 12)
local logo_hovered_textures = dfhack.textures.loadTileset('hack/data/art/logo_hovered.png', 8, 12)
local function get_command(cmdline) local function get_command(cmdline)
local first_word = cmdline:trim():split(' +')[1] local first_word = cmdline:trim():split(' +')[1]
@ -26,9 +27,9 @@ end
HotspotMenuWidget = defclass(HotspotMenuWidget, overlay.OverlayWidget) HotspotMenuWidget = defclass(HotspotMenuWidget, overlay.OverlayWidget)
HotspotMenuWidget.ATTRS{ HotspotMenuWidget.ATTRS{
default_pos={x=2,y=2}, default_pos={x=5,y=1},
default_enabled=true, default_enabled=true,
hotspot=true, version=2,
viewscreens={ viewscreens={
'adopt_region', 'adopt_region',
'choose_game_type', 'choose_game_type',
@ -47,55 +48,47 @@ HotspotMenuWidget.ATTRS{
'update_region', 'update_region',
'world' 'world'
}, },
overlay_onupdate_max_freq_seconds=0,
frame={w=4, h=3} frame={w=4, h=3}
} }
function HotspotMenuWidget:init() function HotspotMenuWidget:init()
self.mouseover = false local to_pen = dfhack.pen.parse
end local function tp(idx, ch)
return to_pen{
function HotspotMenuWidget:overlay_onupdate() tile=function() return dfhack.textures.getTexposByHandle(logo_textures[idx]) end,
local hasMouse = self:getMousePos() ch=ch,
if hasMouse and not self.mouseover then fg=COLOR_GREY,
self.mouseover = true }
return true
end end
self.mouseover = hasMouse local function tph(idx, ch)
return to_pen{
tile=function() return dfhack.textures.getTexposByHandle(logo_hovered_textures[idx]) end,
ch=ch,
fg=COLOR_WHITE,
}
end end
local function get_tile_token(idx, ch)
function HotspotMenuWidget:overlay_trigger() return {
return MenuScreen{hotspot=self}:show() tile=tp(idx, ch),
htile=tph(idx, ch),
width=1,
}
end end
local dscreen = dfhack.screen self:addviews{
widgets.Label{
function HotspotMenuWidget:onRenderBody(dc) text={
local x, y = dc.x, dc.y get_tile_token(1, '!'), get_tile_token(2, 'D'), get_tile_token(3, 'F'), get_tile_token(4, '!'), NEWLINE,
local tp = function(offset) get_tile_token(5, '!'), get_tile_token(6, 'H'), get_tile_token(7, 'a'), get_tile_token(8, '!'), NEWLINE,
return dfhack.textures.getTexposByHandle(textures[offset]) get_tile_token(9, '!'), get_tile_token(10, 'c'), get_tile_token(11, 'k'), get_tile_token(12, '!'),
},
on_click=function() dfhack.run_command('hotkeys') end,
},
}
end end
if tp(1) == nil then function HotspotMenuWidget:overlay_trigger()
dscreen.paintString(COLOR_WHITE, x, y + 0, '!DF!') return MenuScreen{hotspot=self}:show()
dscreen.paintString(COLOR_WHITE, x, y + 1, '!Ha!')
dscreen.paintString(COLOR_WHITE, x, y + 2, '!ck!')
else
dscreen.paintTile(COLOR_WHITE, x + 0, y + 0, '!', tp(1))
dscreen.paintTile(COLOR_WHITE, x + 1, y + 0, 'D', tp(2))
dscreen.paintTile(COLOR_WHITE, x + 2, y + 0, 'F', tp(3))
dscreen.paintTile(COLOR_WHITE, x + 3, y + 0, '!', tp(4))
dscreen.paintTile(COLOR_WHITE, x + 0, y + 1, '!', tp(5))
dscreen.paintTile(COLOR_WHITE, x + 1, y + 1, 'H', tp(6))
dscreen.paintTile(COLOR_WHITE, x + 2, y + 1, 'a', tp(7))
dscreen.paintTile(COLOR_WHITE, x + 3, y + 1, '!', tp(8))
dscreen.paintTile(COLOR_WHITE, x + 0, y + 2, '!', tp(9))
dscreen.paintTile(COLOR_WHITE, x + 1, y + 2, 'c', tp(10))
dscreen.paintTile(COLOR_WHITE, x + 2, y + 2, 'k', tp(11))
dscreen.paintTile(COLOR_WHITE, x + 3, y + 2, '!', tp(12))
end
end end
-- register the menu hotspot with the overlay -- register the menu hotspot with the overlay
@ -170,10 +163,16 @@ end
function Menu:init() function Menu:init()
local hotkeys, bindings = getHotkeys() local hotkeys, bindings = getHotkeys()
if #hotkeys == 0 then
hotkeys = {''}
bindings = {['']='gui/launcher'}
end
local is_inverted = not not self.hotspot.frame.b local is_inverted = not not self.hotspot.frame.b
local choices,list_width = get_choices(hotkeys, bindings, is_inverted) local choices,list_width = get_choices(hotkeys, bindings, is_inverted)
list_width = math.max(35, list_width)
local list_frame = copyall(self.hotspot.frame) local list_frame = copyall(self.hotspot.frame)
local list_widget_frame = {h=math.min(#choices, MAX_LIST_HEIGHT)} local list_widget_frame = {h=math.min(#choices, MAX_LIST_HEIGHT)}
local quickstart_frame = {} local quickstart_frame = {}
@ -272,7 +271,7 @@ end
function Menu:onInput(keys) function Menu:onInput(keys)
if keys.LEAVESCREEN or keys._MOUSE_R_DOWN then if keys.LEAVESCREEN or keys._MOUSE_R_DOWN then
return false return false
elseif keys.STANDARDSCROLL_RIGHT then elseif keys.KEYBOARD_CURSOR_RIGHT then
self:onSubmit2(self.subviews.list:getSelected()) self:onSubmit2(self.subviews.list:getSelected())
return true return true
elseif keys._MOUSE_L_DOWN then elseif keys._MOUSE_L_DOWN then
@ -283,7 +282,7 @@ function Menu:onInput(keys)
df.global.enabler.mouse_lbut = 0 df.global.enabler.mouse_lbut = 0
return true return true
end end
if not self:getMouseFramePos() and not self.hotspot:getMousePos() then if not self:getMouseFramePos() then
self.parent_view:dismiss() self.parent_view:dismiss()
return true return true
end end
@ -298,7 +297,7 @@ function Menu:onRenderFrame(dc, rect)
self.initialize() self.initialize()
self.initialize = nil self.initialize = nil
end end
Menu.super.onRenderFrame(dc, rect) Menu.super.onRenderFrame(self, dc, rect)
end end
function Menu:getMouseFramePos() function Menu:getMouseFramePos()
@ -307,7 +306,7 @@ function Menu:getMouseFramePos()
end end
function Menu:onRenderBody(dc) function Menu:onRenderBody(dc)
local panel = self.subviews.list_panel Menu.super.onRenderBody(self, dc)
local list = self.subviews.list local list = self.subviews.list
local idx = list:getIdxUnderMouse() local idx = list:getIdxUnderMouse()
if idx and idx ~= self.last_mouse_idx then if idx and idx ~= self.last_mouse_idx then
@ -317,13 +316,6 @@ function Menu:onRenderBody(dc)
list:setSelected(idx) list:setSelected(idx)
self.last_mouse_idx = idx self.last_mouse_idx = idx
end end
if self:getMouseFramePos() then
self.mouseover = true
elseif self.mouseover then
-- once the mouse has entered the list area, leaving the frame should
-- close the menu screen
self.parent_view:dismiss()
end
end end
-- ---------- -- -- ---------- --

@ -581,7 +581,8 @@ end
TitleVersionOverlay = defclass(TitleVersionOverlay, OverlayWidget) TitleVersionOverlay = defclass(TitleVersionOverlay, OverlayWidget)
TitleVersionOverlay.ATTRS{ TitleVersionOverlay.ATTRS{
default_pos={x=7, y=2}, default_pos={x=11, y=1},
version=2,
default_enabled=true, default_enabled=true,
viewscreens='title/Default', viewscreens='title/Default',
frame={w=35, h=5}, frame={w=35, h=5},