Merge branch 'develop' into myk_docs

develop
Myk Taylor 2023-01-06 15:22:03 -08:00
commit 91df585bf8
No known key found for this signature in database
GPG Key ID: 8A39CA0FA0C16E78
161 changed files with 2268 additions and 1630 deletions

@ -195,8 +195,8 @@ if(NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl
endif() endif()
# set up versioning. # set up versioning.
set(DF_VERSION "0.50.03") set(DF_VERSION "50.05")
set(DFHACK_RELEASE "alpha0pre1") set(DFHACK_RELEASE "alpha0")
set(DFHACK_PRERELEASE TRUE) set(DFHACK_PRERELEASE TRUE)
set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}")
@ -258,6 +258,7 @@ if(UNIX)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 -march=i686") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 -march=i686")
endif() endif()
string(REPLACE "-DNDEBUG" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") string(REPLACE "-DNDEBUG" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
set(CMAKE_INSTALL_RPATH "hack")
elseif(MSVC) elseif(MSVC)
# for msvc, tell it to always use 8-byte pointers to member functions to avoid confusion # for msvc, tell it to always use 8-byte pointers to member functions to avoid confusion
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /vmg /vmm /MP") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /vmg /vmm /MP")
@ -447,8 +448,6 @@ endif()
file(WRITE "${CMAKE_BINARY_DIR}/dfhack_setarch.txt" ${DFHACK_SETARCH}) file(WRITE "${CMAKE_BINARY_DIR}/dfhack_setarch.txt" ${DFHACK_SETARCH})
install(FILES "${CMAKE_BINARY_DIR}/dfhack_setarch.txt" DESTINATION "${DFHACK_DATA_DESTINATION}") install(FILES "${CMAKE_BINARY_DIR}/dfhack_setarch.txt" DESTINATION "${DFHACK_DATA_DESTINATION}")
install(DIRECTORY dfhack-config/ DESTINATION dfhack-config/default)
# build the plugins # build the plugins
if(BUILD_PLUGINS) if(BUILD_PLUGINS)
add_subdirectory(plugins) add_subdirectory(plugins)

@ -1,20 +1,23 @@
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/dfhack-config/
DESTINATION "${DFHACK_DATA_DESTINATION}/data/dfhack-config-defaults")
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/init/ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/init/
DESTINATION "${DFHACK_DATA_DESTINATION}/init") DESTINATION "${DFHACK_DATA_DESTINATION}/init")
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/base_command_counts.json install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/base_command_counts.json
DESTINATION "${DFHACK_DATA_DESTINATION}/data/base_command_counts.json") DESTINATION "${DFHACK_DATA_DESTINATION}/data")
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/quickfort/ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/quickfort/
DESTINATION "${DFHACK_DATA_DESTINATION}/data/quickfort") DESTINATION "${DFHACK_DATA_DESTINATION}/data/quickfort")
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/orders/ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/orders/
DESTINATION dfhack-config/orders/library) DESTINATION "${DFHACK_DATA_DESTINATION}/data/orders")
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/examples/ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/art/
DESTINATION "${DFHACK_DATA_DESTINATION}/examples") DESTINATION "${DFHACK_DATA_DESTINATION}/data/art")
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/professions/ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/professions/
DESTINATION dfhack-config/professions/library) DESTINATION "${DFHACK_DATA_DESTINATION}/data/professions")
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/blueprints/ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/blueprints/
DESTINATION blueprints DESTINATION blueprints

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -0,0 +1,8 @@
{
"hotkeys.menu": {
"enabled": true
},
"unsuspend.overlay": {
"enabled": true
}
}

@ -0,0 +1,7 @@
You can put scripts you write or download in this folder and DFHack will find
them.
If a script in this directory has the same name as a default DFHack script, the
script in this directory will take precedence.
Everything you add to this folder will be kept safe when you upgrade DFHack.

@ -1,9 +0,0 @@
# The DFHack Example Configuration File Library
This folder contains ready-to-use examples of various DFHack configuration
files. You can use them by copying them to appropriate folders where DFHack
and its plugins can find them. You can use them unmodified, or you can
customize them to better suit your preferences.
For information on each of the files in this library, see the
[DFHack Example Configuration File Guide](https://docs.dfhack.org/en/stable/docs/guides/examples-guide.html).

@ -20,7 +20,7 @@ keybinding add Ctrl-Shift-C hotkeys
keybinding add Ctrl-Shift-K gui/cp437-table keybinding add Ctrl-Shift-K gui/cp437-table
# an in-game init file editor # an in-game init file editor
keybinding add Alt-S@title|dwarfmode/Default|dungeonmode gui/settings-manager #keybinding add Alt-S@title|dwarfmode/Default|dungeonmode gui/settings-manager
###################### ######################
@ -28,142 +28,142 @@ keybinding add Alt-S@title|dwarfmode/Default|dungeonmode gui/settings-manager
###################### ######################
# quicksave, only in main dwarfmode screen and menu page # quicksave, only in main dwarfmode screen and menu page
keybinding add Ctrl-Alt-S@dwarfmode/Default quicksave #keybinding add Ctrl-Alt-S@dwarfmode/Default quicksave
# toggle the display of water level as 1-7 tiles # toggle the display of water level as 1-7 tiles
keybinding add Ctrl-W@dwarfmode|dungeonmode twaterlvl keybinding add Ctrl-W@dwarfmode|dungeonmode twaterlvl
# designate the whole vein for digging # designate the whole vein for digging
keybinding add Ctrl-V@dwarfmode digv #keybinding add Ctrl-V@dwarfmode digv
keybinding add Ctrl-Shift-V@dwarfmode "digv x" #keybinding add Ctrl-Shift-V@dwarfmode "digv x"
# clean the selected tile of blood etc # clean the selected tile of blood etc
keybinding add Ctrl-C spotclean #keybinding add Ctrl-C spotclean
# destroy the selected item # destroy the selected item
keybinding add Ctrl-K@dwarfmode autodump-destroy-item #keybinding add Ctrl-K@dwarfmode autodump-destroy-item
# destroy items designated for dump in the selected tile # destroy items designated for dump in the selected tile
keybinding add Ctrl-Shift-K@dwarfmode autodump-destroy-here #keybinding add Ctrl-Shift-K@dwarfmode autodump-destroy-here
# apply blueprints to the map (Alt-F for compatibility with LNP Quickfort) # apply blueprints to the map (Alt-F for compatibility with LNP Quickfort)
keybinding add Ctrl-Shift-Q@dwarfmode gui/quickfort #keybinding add Ctrl-Shift-Q@dwarfmode gui/quickfort
keybinding add Alt-F@dwarfmode gui/quickfort #keybinding add Alt-F@dwarfmode gui/quickfort
# show information collected by dwarfmonitor # show information collected by dwarfmonitor
keybinding add Alt-M@dwarfmode/Default "dwarfmonitor prefs" #keybinding add Alt-M@dwarfmode/Default "dwarfmonitor prefs"
keybinding add Ctrl-F@dwarfmode/Default "dwarfmonitor stats" #keybinding add Ctrl-F@dwarfmode/Default "dwarfmonitor stats"
# set the zone or cage under the cursor as the default # set the zone or cage under the cursor as the default
keybinding add Alt-Shift-I@dwarfmode/Zones "zone set" #keybinding add Alt-Shift-I@dwarfmode/Zones "zone set"
# Stocks plugin # Stocks plugin
keybinding add Ctrl-Shift-Z@dwarfmode/Default "stocks show" #keybinding add Ctrl-Shift-Z@dwarfmode/Default "stocks show"
# open an overview window summarising some stocks (dfstatus) # open an overview window summarising some stocks (dfstatus)
keybinding add Ctrl-Shift-I@dwarfmode/Default|dfhack/lua/dfstatus gui/dfstatus #keybinding add Ctrl-Shift-I@dwarfmode/Default|dfhack/lua/dfstatus gui/dfstatus
# change quantity of manager orders # change quantity of manager orders
keybinding add Alt-Q@jobmanagement/Main gui/manager-quantity #keybinding add Alt-Q@jobmanagement/Main gui/manager-quantity
# re-check manager orders # re-check manager orders
keybinding add Alt-R@jobmanagement/Main workorder-recheck #keybinding add Alt-R@jobmanagement/Main workorder-recheck
# set workorder item details (on workorder details screen press D again) # set workorder item details (on workorder details screen press D again)
keybinding add D@workquota_details gui/workorder-details #keybinding add D@workquota_details gui/workorder-details
# view combat reports for the selected unit/corpse/spatter # view combat reports for the selected unit/corpse/spatter
keybinding add Ctrl-Shift-R@dwarfmode|unit|unitlist|joblist|dungeon_monsterstatus|layer_unit_relationship|item|workshop_profile|layer_noblelist|locations|pets|layer_overall_health|textviewer|reportlist|announcelist|layer_military|layer_unit_health|customize_unit|buildinglist|workshop_profile view-unit-reports #keybinding add Ctrl-Shift-R@dwarfmode|unit|unitlist|joblist|dungeon_monsterstatus|layer_unit_relationship|item|workshop_profile|layer_noblelist|locations|pets|layer_overall_health|textviewer|reportlist|announcelist|layer_military|layer_unit_health|customize_unit|buildinglist|workshop_profile view-unit-reports
# view extra unit information # view extra unit information
keybinding add Alt-I@dwarfmode/ViewUnits|unitlist gui/unit-info-viewer #keybinding add Alt-I@dwarfmode/ViewUnits|unitlist gui/unit-info-viewer
# boost priority of jobs related to the selected entity # boost priority of jobs related to the selected entity
keybinding add Alt-N@dwarfmode|job|joblist|unit|unitlist|joblist|dungeon_monsterstatus|layer_unit_relationship|item|layer_noblelist|locations|pets|layer_overall_health|textviewer|reportlist|announcelist|layer_military|layer_unit_health|customize_unit|buildinglist|textviewer|item|layer_assigntrade|tradegoods|store|assign_display_item|treasurelist do-job-now #keybinding add Alt-N@dwarfmode|job|joblist|unit|unitlist|joblist|dungeon_monsterstatus|layer_unit_relationship|item|layer_noblelist|locations|pets|layer_overall_health|textviewer|reportlist|announcelist|layer_military|layer_unit_health|customize_unit|buildinglist|textviewer|item|layer_assigntrade|tradegoods|store|assign_display_item|treasurelist do-job-now
# export a Dwarf's preferences screen in BBCode to post to a forum # export a Dwarf's preferences screen in BBCode to post to a forum
keybinding add Ctrl-Shift-F@textviewer forum-dwarves #keybinding add Ctrl-Shift-F@textviewer forum-dwarves
# q->stockpile - copy & paste stockpiles # q->stockpile - copy & paste stockpiles
keybinding add Alt-P@dwarfmode/QueryBuilding/Some/Stockpile copystock #keybinding add Alt-P@dwarfmode/QueryBuilding/Some/Stockpile copystock
# q->stockpile - load and save stockpile settings out of game # q->stockpile - load and save stockpile settings out of game
keybinding add Alt-L@dwarfmode/QueryBuilding/Some/Stockpile "gui/stockpiles -load" #keybinding add Alt-L@dwarfmode/QueryBuilding/Some/Stockpile "gui/stockpiles -load"
keybinding add Alt-S@dwarfmode/QueryBuilding/Some/Stockpile "gui/stockpiles -save" #keybinding add Alt-S@dwarfmode/QueryBuilding/Some/Stockpile "gui/stockpiles -save"
# q->workshop - duplicate the selected job # q->workshop - duplicate the selected job
keybinding add Ctrl-D job-duplicate #keybinding add Ctrl-D job-duplicate
# materials: q->workshop; b->select items # materials: q->workshop; b->select items
keybinding add Shift-A "job-material ALUNITE" #keybinding add Shift-A "job-material ALUNITE"
keybinding add Shift-M "job-material MICROCLINE" #keybinding add Shift-M "job-material MICROCLINE"
keybinding add Shift-D "job-material DACITE" #keybinding add Shift-D "job-material DACITE"
keybinding add Shift-R "job-material RHYOLITE" #keybinding add Shift-R "job-material RHYOLITE"
keybinding add Shift-I "job-material CINNABAR" #keybinding add Shift-I "job-material CINNABAR"
keybinding add Shift-B "job-material COBALTITE" #keybinding add Shift-B "job-material COBALTITE"
keybinding add Shift-O "job-material OBSIDIAN" #keybinding add Shift-O "job-material OBSIDIAN"
keybinding add Shift-T "job-material ORTHOCLASE" #keybinding add Shift-T "job-material ORTHOCLASE"
keybinding add Shift-G "job-material GLASS_GREEN" #keybinding add Shift-G "job-material GLASS_GREEN"
# sort units and items in the on-screen list # sort units and items in the on-screen list
keybinding add Alt-Shift-N "sort-units name" "sort-items description" #keybinding add Alt-Shift-N "sort-units name" "sort-items description"
keybinding add Alt-Shift-R "sort-units arrival" #keybinding add Alt-Shift-R "sort-units arrival"
keybinding add Alt-Shift-T "sort-units profession" "sort-items type material" #keybinding add Alt-Shift-T "sort-units profession" "sort-items type material"
keybinding add Alt-Shift-Q "sort-units squad_position" "sort-items quality" #keybinding add Alt-Shift-Q "sort-units squad_position" "sort-items quality"
# browse linked mechanisms # browse linked mechanisms
keybinding add Ctrl-M@dwarfmode/QueryBuilding/Some gui/mechanisms #keybinding add Ctrl-M@dwarfmode/QueryBuilding/Some gui/mechanisms
# browse rooms of same owner # browse rooms of same owner
keybinding add Alt-R@dwarfmode/QueryBuilding/Some gui/room-list #keybinding add Alt-R@dwarfmode/QueryBuilding/Some gui/room-list
# interface for the liquids plugin - spawn water/magma/obsidian # interface for the liquids plugin - spawn water/magma/obsidian
keybinding add Alt-L@dwarfmode/LookAround gui/liquids #keybinding add Alt-L@dwarfmode/LookAround gui/liquids
# machine power sensitive pressure plate construction # machine power sensitive pressure plate construction
keybinding add Ctrl-Shift-M@dwarfmode/Build/Position/Trap gui/power-meter #keybinding add Ctrl-Shift-M@dwarfmode/Build/Position/Trap gui/power-meter
# siege engine control # siege engine control
keybinding add Alt-A@dwarfmode/QueryBuilding/Some/SiegeEngine gui/siege-engine #keybinding add Alt-A@dwarfmode/QueryBuilding/Some/SiegeEngine gui/siege-engine
# military weapon auto-select # military weapon auto-select
keybinding add Ctrl-W@layer_military/Equip/Customize/View gui/choose-weapons #keybinding add Ctrl-W@layer_military/Equip/Customize/View gui/choose-weapons
# military copy uniform # military copy uniform
keybinding add Ctrl-C@layer_military/Uniforms gui/clone-uniform #keybinding add Ctrl-C@layer_military/Uniforms gui/clone-uniform
# minecart Guide path # minecart Guide path
keybinding add Alt-P@dwarfmode/Hauling/DefineStop/Cond/Guide gui/guide-path #keybinding add Alt-P@dwarfmode/Hauling/DefineStop/Cond/Guide gui/guide-path
# workshop job details # workshop job details
keybinding add Alt-A@dwarfmode/QueryBuilding/Some/Workshop/Job gui/workshop-job #keybinding add Alt-A@dwarfmode/QueryBuilding/Some/Workshop/Job gui/workshop-job
# workflow front-end # workflow front-end
keybinding add Alt-W@dwarfmode/QueryBuilding/Some/Workshop/Job gui/workflow #keybinding add Alt-W@dwarfmode/QueryBuilding/Some/Workshop/Job gui/workflow
keybinding add Alt-W@overallstatus "gui/workflow status" #keybinding add Alt-W@overallstatus "gui/workflow status"
# equivalent to the one above when gui/extended-status is enabled # equivalent to the one above when gui/extended-status is enabled
keybinding add Alt-W@dfhack/lua/status_overlay "gui/workflow status" #keybinding add Alt-W@dfhack/lua/status_overlay "gui/workflow status"
# autobutcher front-end # autobutcher front-end
keybinding add Shift-B@pet/List/Unit gui/autobutcher #keybinding add Shift-B@pet/List/Unit gui/autobutcher
# view pathable tiles from active cursor # view pathable tiles from active cursor
keybinding add Alt-Shift-P@dwarfmode/LookAround gui/pathable #keybinding add Alt-Shift-P@dwarfmode/LookAround gui/pathable
# gui/rename script - rename units and buildings # gui/rename script - rename units and buildings
keybinding add Ctrl-Shift-N@dwarfmode|unit|unitlist|joblist|dungeon_monsterstatus|layer_unit_relationship|item|workshop_profile|layer_noblelist|locations|pets|layer_overall_health|textviewer|reportlist|announcelist|layer_military|layer_unit_health|customize_unit|buildinglist gui/rename #keybinding add Ctrl-Shift-N@dwarfmode|unit|unitlist|joblist|dungeon_monsterstatus|layer_unit_relationship|item|workshop_profile|layer_noblelist|locations|pets|layer_overall_health|textviewer|reportlist|announcelist|layer_military|layer_unit_health|customize_unit|buildinglist gui/rename
keybinding add Ctrl-Shift-T@dwarfmode|unit|unitlist|joblist|dungeon_monsterstatus|layer_unit_relationship|item|workshop_profile|layer_noblelist|locations|pets|layer_overall_health|textviewer|reportlist|announcelist|layer_military|layer_unit_health|customize_unit "gui/rename unit-profession" #keybinding add Ctrl-Shift-T@dwarfmode|unit|unitlist|joblist|dungeon_monsterstatus|layer_unit_relationship|item|workshop_profile|layer_noblelist|locations|pets|layer_overall_health|textviewer|reportlist|announcelist|layer_military|layer_unit_health|customize_unit "gui/rename unit-profession"
##################### #####################
# adv mode bindings # # adv mode bindings #
##################### #####################
keybinding add Ctrl-A@dungeonmode/ConversationSpeak adv-rumors #keybinding add Ctrl-A@dungeonmode/ConversationSpeak adv-rumors
keybinding add Ctrl-B@dungeonmode adv-bodyswap #keybinding add Ctrl-B@dungeonmode adv-bodyswap
keybinding add Ctrl-Shift-B@dungeonmode "adv-bodyswap force" #keybinding add Ctrl-Shift-B@dungeonmode "adv-bodyswap force"
keybinding add Shift-O@dungeonmode gui/companion-order #keybinding add Shift-O@dungeonmode gui/companion-order
keybinding add Ctrl-T@dungeonmode gui/advfort #keybinding add Ctrl-T@dungeonmode gui/advfort
######################### #########################
@ -171,4 +171,4 @@ keybinding add Ctrl-T@dungeonmode gui/advfort
######################### #########################
# export all information, or just the detailed maps (doesn't handle site maps) # export all information, or just the detailed maps (doesn't handle site maps)
keybinding add Ctrl-A@legends "exportlegends all" #keybinding add Ctrl-A@legends "exportlegends all"

@ -9,7 +9,7 @@
############################ ############################
# stabilize the cursor of dwarfmode when switching menus # stabilize the cursor of dwarfmode when switching menus
tweak stable-cursor #tweak stable-cursor
# stop stacked liquid/bar/thread/cloth items from lasting forever # stop stacked liquid/bar/thread/cloth items from lasting forever
# if used in reactions that use only a fraction of the dimension. # if used in reactions that use only a fraction of the dimension.
@ -18,114 +18,116 @@ tweak stable-cursor
# make reactions requiring containers usable in advmode - the issue is # make reactions requiring containers usable in advmode - the issue is
# that the screen asks for those reagents to be selected directly # that the screen asks for those reagents to be selected directly
tweak advmode-contained #tweak advmode-contained
# support Shift-Enter in Trade and Move Goods to Depot screens for faster # support Shift-Enter in Trade and Move Goods to Depot screens for faster
# selection; it selects the current item or stack and scrolls down one line # selection; it selects the current item or stack and scrolls down one line
tweak fast-trade #tweak fast-trade
# stop the right list in military->positions from resetting to top all the time # stop the right list in military->positions from resetting to top all the time
tweak military-stable-assign #tweak military-stable-assign
# in same list, color units already assigned to squads in brown & green # in same list, color units already assigned to squads in brown & green
tweak military-color-assigned #tweak military-color-assigned
# make crafted cloth items wear out with time like in old versions (bug 6003) # make crafted cloth items wear out with time like in old versions (bug 6003)
tweak craft-age-wear #tweak craft-age-wear
# stop adamantine clothing from wearing out (bug 6481) # stop adamantine clothing from wearing out (bug 6481)
#tweak adamantine-cloth-wear #tweak adamantine-cloth-wear
# Add "Select all" and "Deselect all" options to farm plot menus # Add "Select all" and "Deselect all" options to farm plot menus
tweak farm-plot-select #tweak farm-plot-select
# Add Shift-Left/Right controls to import agreement screen # Add Shift-Left/Right controls to import agreement screen
tweak import-priority-category #tweak import-priority-category
# Fixes a crash in the work order contition material list (bug 9905). # Fixes a crash in the work order contition material list (bug 9905).
tweak condition-material #tweak condition-material
# Adds an option to clear currently-bound hotkeys # Adds an option to clear currently-bound hotkeys
tweak hotkey-clear #tweak hotkey-clear
# Allows lowercase letters in embark profile names, and allows exiting the name prompt without saving # Allows lowercase letters in embark profile names, and allows exiting the name prompt without saving
tweak embark-profile-name #tweak embark-profile-name
# Reduce performance impact of temperature changes # Reduce performance impact of temperature changes
tweak fast-heat 100 #tweak fast-heat 100
# Misc. UI tweaks # Misc. UI tweaks
tweak block-labors # Prevents labors that can't be used from being toggled #tweak block-labors # Prevents labors that can't be used from being toggled
tweak burrow-name-cancel #tweak burrow-name-cancel
tweak cage-butcher #tweak cage-butcher
tweak civ-view-agreement #tweak civ-view-agreement
tweak do-job-now #tweak do-job-now
tweak eggs-fertile #tweak eggs-fertile
tweak fps-min #tweak fps-min
tweak hide-priority #tweak hide-priority
tweak kitchen-prefs-all #tweak kitchen-prefs-all
tweak kitchen-prefs-empty #tweak kitchen-prefs-empty
tweak max-wheelbarrow #tweak max-wheelbarrow
tweak partial-items #tweak partial-items
tweak shift-8-scroll #tweak shift-8-scroll
tweak stone-status-all #tweak stone-status-all
tweak title-start-rename #tweak title-start-rename
tweak tradereq-pet-gender #tweak tradereq-pet-gender
########################### ###########################
# Globally acting plugins # # Globally acting plugins #
########################### ###########################
# Display DFHack version on title screen # Display DFHack version on title screen
enable title-version #enable title-version
# Allow DFHack tools to overlay functionality and information on the DF screen
enable overlay
# Dwarf Manipulator (simple in-game Dwarf Therapist replacement) # Dwarf Manipulator (simple in-game Dwarf Therapist replacement)
enable manipulator #enable manipulator
# Search tool in various screens (by falconne) # Search tool in various screens (by falconne)
enable search #enable search
# Improved build material selection interface (by falconne) # Improved build material selection interface (by falconne)
enable automaterial #enable automaterial
# Other interface improvement tools # Other interface improvement tools
enable \ #enable \
overlay \ # confirm \
confirm \ # dwarfmonitor \
dwarfmonitor \ # mousequery \
mousequery \ # autogems \
autogems \ # autodump \
autodump \ # automelt \
automelt \ # autotrade \
autotrade \ # buildingplan \
buildingplan \ # trackstop \
trackstop \ # zone \
zone \ # stocks \
stocks \ # autochop \
autochop \ # stockpiles
stockpiles
#end a line with a backslash to make it continue to the next line. The \ is deleted for the final command. #end a line with a backslash to make it continue to the next line. The \ is deleted for the final command.
# Multiline commands are ONLY supported for scripts like dfhack.init. You cannot do multiline command manually on the DFHack console. # Multiline commands are ONLY supported for scripts like dfhack.init. You cannot do multiline command manually on the DFHack console.
# You cannot extend a commented line. # You cannot extend a commented line.
# You can comment out the extension of a line. # You can comment out the extension of a line.
# enable mouse controls and sand indicator in embark screen # enable mouse controls and sand indicator in embark screen
embark-tools enable sticky sand mouse #embark-tools enable sticky sand mouse
# enable option to enter embark assistant # enable option to enter embark assistant
enable embark-assistant #enable embark-assistant
########### ###########
# Scripts # # Scripts #
########### ###########
# write extra information to the gamelog # write extra information to the gamelog
modtools/extra-gamelog enable #modtools/extra-gamelog enable
# extended status screen (bedrooms page) # extended status screen (bedrooms page)
enable gui/extended-status #enable gui/extended-status
# add information to item viewscreens # add information to item viewscreens
view-item-info enable #view-item-info enable
# a replacement for the "load game" screen # a replacement for the "load game" screen
gui/load-screen enable #gui/load-screen enable

@ -1,17 +0,0 @@
{
"dwarfmonitor.date": {
"enabled": true
},
"dwarfmonitor.misery": {
"enabled": true
},
"dwarfmonitor.weather": {
"enabled": true
},
"hotkeys.menu": {
"enabled": true
},
"unsuspend.overlay": {
"enabled": true
}
}

@ -21,10 +21,11 @@ DFHack commands can be implemented in any of three ways:
same version of DFHack. They are less flexible than scripts, same version of DFHack. They are less flexible than scripts,
but used for complex or ongoing tasks because they run faster. but used for complex or ongoing tasks because they run faster.
:scripts: are Ruby or Lua scripts stored in ``hack/scripts/``. :scripts: are Ruby or Lua scripts stored in ``hack/scripts/`` or other
Because they don't need to be compiled, scripts are directories in the `script-paths`. Because they don't need to
more flexible about versions, and easier to distribute. be compiled, scripts are more flexible about versions, and
Most third-party DFHack addons are scripts. they are easier to distribute. Most third-party DFHack addons
are scripts.
All tools distributed with DFHack are documented `here <tools>`. All tools distributed with DFHack are documented `here <tools>`.
@ -37,6 +38,8 @@ DFHack commands can be executed in a number of ways:
#. Pressing a key combination set up with `keybinding` #. Pressing a key combination set up with `keybinding`
#. From one of several `init-files`, automatically #. From one of several `init-files`, automatically
#. Using `script` to run a batch of commands from a file #. Using `script` to run a batch of commands from a file
#. From an in-game command launcher interface like `gui/launcher`, the
`hotkeys` overlay widget, or `gui/quickcmd`.
The DFHack console The DFHack console
------------------ ------------------
@ -144,7 +147,7 @@ save-specific init files in the save folders.
DFHack looks for init files in three places each time they could be run: DFHack looks for init files in three places each time they could be run:
#. The :file:`dfhack-config/init` subdirectory in the main DF directory #. The :file:`dfhack-config/init` subdirectory in the main DF directory
#. :file:`data/save/{world}/raw`, where ``world`` is the current save, and #. :file:`data/save/{world}/raw`, where ``{world}`` is the current save, and
#. :file:`data/save/{world}/raw/objects` #. :file:`data/save/{world}/raw/objects`
For each of those directories, all matching init files will be executed in For each of those directories, all matching init files will be executed in
@ -171,7 +174,7 @@ dfhack\*.init
On startup, DFHack looks for files of the form ``dfhack*.init`` (where ``*`` is On startup, DFHack looks for files of the form ``dfhack*.init`` (where ``*`` is
a placeholder for any string, including the empty string). a placeholder for any string, including the empty string).
These files are best used for keybindings and enabling persistent plugins These files are best used for keybindings and enabling persistent tools
which do not require a world to be loaded. which do not require a world to be loaded.
@ -230,9 +233,10 @@ Script paths are folders that DFHack searches to find a script when a command is
run. By default, the following folders are searched, in order (relative to the run. By default, the following folders are searched, in order (relative to the
root DF folder): root DF folder):
1. :file:`data/save/{<region folder>}/raw/scripts` (only if a save is loaded) #. :file:`dfhack-config/scripts`
2. :file:`raw/scripts` #. :file:`data/save/{<region folder>}/raw/scripts` (only if a save is loaded)
3. :file:`hack/scripts` #. :file:`raw/scripts`
#. :file:`hack/scripts`
For example, if ``teleport`` is run, these folders are searched in order for For example, if ``teleport`` is run, these folders are searched in order for
``teleport.lua`` or ``teleport.rb``, and the first matching file is run. ``teleport.lua`` or ``teleport.rb``, and the first matching file is run.

@ -38,17 +38,24 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
## Fixes ## Fixes
## Misc Improvements ## Misc Improvements
- Scrollable widgets now react to mouse wheel events when the mouse is over the widget
- the ``dfhack-config/scripts/`` folder is now searched for scripts by default
- `hotkeys`: overlay hotspot widget now shows the DFHack logo in graphics mode and "DFHack" in text mode
## Documentation ## Documentation
- `overlay-dev-guide`: added troubleshooting tips and common development workflows - `overlay-dev-guide`: added troubleshooting tips and common development workflows
- added DFHack architecture diagrams to the dev intro - added DFHack architecture diagrams to the dev intro
## API ## API
- ``Gui::getDwarfmodeDims``: now only returns map viewport dimensions; menu dimensions are obsolete
- ``Gui::getDFViewscreen``: returns the topmost underlying DF viewscreen
## Lua ## Lua
- ``gui.View``: ``visible`` and ``active`` can now be functions that return a boolean - ``gui.View``: ``visible`` and ``active`` can now be functions that return a boolean
- ``widgets.Panel``: new attributes to control window dragging and resizing with mouse or keyboard - ``widgets.Panel``: new attributes to control window dragging and resizing with mouse or keyboard
- ``widgets.Window``: Panel subclass with attributes preset for top-level windows - ``widgets.Window``: Panel subclass with attributes preset for top-level windows
- `overlay`: ``OverlayWidget`` now inherits from ``Panel`` instead of ``Widget`` to get all the frame and mouse integration goodies
- ``dfhack.gui.getDFViewscreen()``: returns the topmost underlying DF viewscreen
## Internals ## Internals

@ -965,6 +965,11 @@ Screens
the specified type (e.g. ``df.viewscreen_titlest``), or ``nil`` if none match. the specified type (e.g. ``df.viewscreen_titlest``), or ``nil`` if none match.
If ``depth`` is not specified or is less than 1, all viewscreens are checked. If ``depth`` is not specified or is less than 1, all viewscreens are checked.
* ``dfhack.gui.getDFViewscreen([skip_dismissed])``
Returns the topmost viewscreen not owned by DFHack. If ``skip_dismissed`` is
``true``, ignores screens already marked to be removed.
General-purpose selections General-purpose selections
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -1011,7 +1016,7 @@ Fortress mode
* ``dfhack.gui.getDwarfmodeViewDims()`` * ``dfhack.gui.getDwarfmodeViewDims()``
Returns dimensions of the main fortress mode screen. See ``getPanelLayout()`` Returns dimensions of the displayed map viewport. See ``getPanelLayout()``
in the ``gui.dwarfmode`` module for a more Lua-friendly version. in the ``gui.dwarfmode`` module for a more Lua-friendly version.
* ``dfhack.gui.resetDwarfmodeView([pause])`` * ``dfhack.gui.resetDwarfmodeView([pause])``
@ -1121,7 +1126,8 @@ Other
* ``dfhack.gui.getDepthAt(x, y)`` * ``dfhack.gui.getDepthAt(x, y)``
Returns the distance from the z-level of the tile at map coordinates (x, y) to Returns the distance from the z-level of the tile at map coordinates (x, y) to
the closest ground z-level below. Defaults to 0, unless overridden by plugins. the closest rendered ground z-level below. Defaults to 0, unless overridden by
plugins.
Job module Job module
---------- ----------
@ -2161,7 +2167,14 @@ Functions:
* ``dfhack.screen.getMousePos()`` * ``dfhack.screen.getMousePos()``
Returns *x,y* of the tile the mouse is over. Returns *x,y* of the UI interface tile the mouse is over, with the upper left
corner being ``0,0``. To get the map tile coordinate that the mouse is over,
see ``dfhack.gui.getMousePos()``.
* ``dfhack.screen.getMousePixels()``
Returns *x,y* of the screen coordinates the mouse is over in pixels, with the
upper left corner being ``0,0``.
* ``dfhack.screen.inGraphicsMode()`` * ``dfhack.screen.inGraphicsMode()``
@ -2355,7 +2368,14 @@ Supported callbacks and fields are:
where the above painting functions work correctly. where the above painting functions work correctly.
If omitted, the screen is cleared; otherwise it should do that itself. If omitted, the screen is cleared; otherwise it should do that itself.
In order to make a see-through dialog, call ``self._native.parent:render()``. In order to make a dialog where portions of the parent viewscreen are still
visible in the background, call ``screen:renderParent()``.
If artifacts are left on the parent even after this function is called, such
as when the window is dragged or is resized, any code can set
``gui.Screen.request_full_screen_refresh`` to ``true``. Then when
``screen.renderParent()`` is next called, it will do a full flush of the
graphics and clear the screen of artifacts.
* ``function screen:onIdle()`` * ``function screen:onIdle()``
@ -2377,13 +2397,13 @@ Supported callbacks and fields are:
``_STRING`` ``_STRING``
Maps to an integer in range 0-255. Duplicates a separate "STRING_A???" code for convenience. Maps to an integer in range 0-255. Duplicates a separate "STRING_A???" code for convenience.
``_MOUSE_L, _MOUSE_R`` ``_MOUSE_L, _MOUSE_R, _MOUSE_M``
If the left or right mouse button is being pressed. If the left, right, and/or middle mouse button is being pressed.
``_MOUSE_L_DOWN, _MOUSE_R_DOWN`` ``_MOUSE_L_DOWN, _MOUSE_R_DOWN, _MOUSE_M_DOWN``
If the left or right mouse button was just pressed. If the left, right, and/or middle mouse button was just pressed.
If this method is omitted, the screen is dismissed on receival of the ``LEAVESCREEN`` key. If this method is omitted, the screen is dismissed on reception of the ``LEAVESCREEN`` key.
* ``function screen:onGetSelectedUnit()`` * ``function screen:onGetSelectedUnit()``
* ``function screen:onGetSelectedItem()`` * ``function screen:onGetSelectedItem()``
@ -2614,8 +2634,8 @@ and are only documented here for completeness:
Registers ``path`` as a `script path <script-paths>`. Registers ``path`` as a `script path <script-paths>`.
If ``search_before`` is passed and ``true``, the path will be searched before If ``search_before`` is passed and ``true``, the path will be searched before
the default paths (e.g. ``raw/scripts``, ``hack/scripts``); otherwise, it will the default paths (e.g. ``dfhack-config/scripts``, ``hack/scripts``); otherwise,
be searched after. it will be searched after.
Returns ``true`` if successful or ``false`` otherwise (e.g. if the path does Returns ``true`` if successful or ``false`` otherwise (e.g. if the path does
not exist or has already been registered). not exist or has already been registered).
@ -3632,11 +3652,6 @@ considered stable.
Misc Misc
---- ----
* ``USE_GRAPHICS``
Contains the value of ``dfhack.screen.inGraphicsMode()``, which cannot be
changed without restarting the game and thus is constant during the session.
* ``CLEAR_PEN`` * ``CLEAR_PEN``
The black pen used to clear the screen. The black pen used to clear the screen.
@ -4144,6 +4159,8 @@ Base of all the widgets. Inherits from View and has the following attributes:
The pen to fill the outer frame with. Defaults to no fill. The pen to fill the outer frame with. Defaults to no fill.
.. _panel:
Panel class Panel class
----------- -----------
@ -4306,7 +4323,6 @@ Attributes:
If it returns false, the character is ignored. If it returns false, the character is ignored.
:on_change: Change notification callback; used as ``on_change(new_text,old_text)``. :on_change: Change notification callback; used as ``on_change(new_text,old_text)``.
:on_submit: Enter key callback; if set the field will handle the key and call ``on_submit(text)``. :on_submit: Enter key callback; if set the field will handle the key and call ``on_submit(text)``.
:on_submit2: Shift-Enter key callback; if set the field will handle the key and call ``on_submit2(text)``.
:key: If specified, the field is disabled until this key is pressed. Must be given as a string. :key: If specified, the field is disabled until this key is pressed. Must be given as a string.
:key_sep: If specified, will be used to customize how the activation key is :key_sep: If specified, will be used to customize how the activation key is
displayed. See ``token.key_sep`` in the ``Label`` documentation below. displayed. See ``token.key_sep`` in the ``Label`` documentation below.
@ -4336,21 +4352,36 @@ You can click where you want the cursor to move or you can use any of the
following keyboard hotkeys: following keyboard hotkeys:
- Left/Right arrow: move the cursor one character to the left or right. - Left/Right arrow: move the cursor one character to the left or right.
- Ctrl-Left/Right arrow: move the cursor one word to the left or right. - Ctrl-B/Ctrl-F: move the cursor one word back or forward.
- Alt-Left/Right arrow: move the cursor to the beginning/end of the text. - Ctrl-A/Ctrl-E: move the cursor to the beginning/end of the text.
The ``EditField`` class also provides the following functions:
* ``editfield:setCursor([cursor_pos])``
Sets the text insert cursor to the specified position. If ``cursor_pos`` is
not specified or is past the end of the current text string, the cursor will
be set to the end of the current input (that is, ``#editfield.text + 1``).
* ``editfield:setText(text[, cursor_pos])``
Sets the input text string and, optionally, the cursor position. If the
cursor position is not specified, it sets it to the end of the string.
* ``editfield:insert(text)``
Inserts the given text at the current cursor position.
Scrollbar class Scrollbar class
--------------- ---------------
This Widget subclass implements mouse-interactive scrollbars whose bar sizes This Widget subclass implements mouse-interactive scrollbars whose bar sizes
represent the amount of content currently visible in an associated display represent the amount of content currently visible in an associated display
widget (like a `Label class`_ or a `List class`_). By default they are styled widget (like a `Label class`_ or a `List class`_). They are styled like scrollbars
like scrollbars used in the vanilla DF help screens, but they are configurable. used in vanilla DF.
Scrollbars have the following attributes: Scrollbars have the following attributes:
:fg: Specifies the pen for the scroll icons and the active part of the bar. Default is ``COLOR_LIGHTGREEN``.
:bg: Specifies the pen for the background part of the scrollbar. Default is ``COLOR_CYAN``.
:on_scroll: A callback called when the scrollbar is scrolled. If the scrollbar is clicked, :on_scroll: A callback called when the scrollbar is scrolled. If the scrollbar is clicked,
the callback will be called with one of the following string parameters: "up_large", the callback will be called with one of the following string parameters: "up_large",
"down_large", "up_small", or "down_small". If the scrollbar is dragged, the callback will "down_large", "up_small", or "down_small". If the scrollbar is dragged, the callback will
@ -4377,6 +4408,10 @@ direction. The amount of scrolling done in each case in determined by the
associated widget, and after scrolling is complete, the associated widget must associated widget, and after scrolling is complete, the associated widget must
call ``scrollbar:update()`` with updated new display info. call ``scrollbar:update()`` with updated new display info.
If the mouse wheel is scrolled while the mouse is over the Scrollbar widget's
parent view, then the parent is scrolled accordingly. Holding :kbd:`Shift`
while scrolling will result in faster movement.
You can click and drag the scrollbar to scroll to a specific spot, or you can You can click and drag the scrollbar to scroll to a specific spot, or you can
click and hold on the end arrows or in the unfilled portion of the scrollbar to click and hold on the end arrows or in the unfilled portion of the scrollbar to
scroll multiple times, just like in a normal browser scrollbar. The speed of scroll multiple times, just like in a normal browser scrollbar. The speed of
@ -4621,8 +4656,8 @@ It has the following attributes:
with an empty list. with an empty list.
:on_submit: Enter key or mouse click callback; if specified, the list reacts to the :on_submit: Enter key or mouse click callback; if specified, the list reacts to the
key/click and calls the callback as ``on_submit(index,choice)``. key/click and calls the callback as ``on_submit(index,choice)``.
:on_submit2: Shift-Enter key or shift-mouse click callback; if specified, the list :on_submit2: Shift-click callback; if specified, the list reacts to the click and
reacts to the key/click and calls it as ``on_submit2(index,choice)``. calls the callback as ``on_submit2(index,choice)``.
:row_height: Height of every row in text lines. :row_height: Height of every row in text lines.
:icon_width: If not *nil*, the specified number of character columns :icon_width: If not *nil*, the specified number of character columns
are reserved to the left of the list item for the icons. are reserved to the left of the list item for the icons.
@ -5455,11 +5490,11 @@ Scripts
:local: :local:
Any files with the ``.lua`` extension placed into the :file:`hack/scripts` folder Any files with the ``.lua`` extension placed into the :file:`hack/scripts` folder
are automatically made available as DFHack commands. The command corresponding to (or any other folder in your `script-paths`) are automatically made available as
a script is simply the script's filename, relative to the scripts folder, with DFHack commands. The command corresponding to a script is simply the script's
the extension omitted. For example: filename, relative to the scripts folder, with the extension omitted. For example:
* :file:`hack/scripts/add-thought.lua` is invoked as ``add-thought`` * :file:`dfhack-config/scripts/startup.lua` is invoked as ``startup``
* :file:`hack/scripts/gui/teleport.lua` is invoked as ``gui/teleport`` * :file:`hack/scripts/gui/teleport.lua` is invoked as ``gui/teleport``
.. note:: .. note::
@ -5476,12 +5511,6 @@ the extension omitted. For example:
a mod developer would want to run a script from the console, it should a mod developer would want to run a script from the console, it should
not be placed in this folder) not be placed in this folder)
Scripts can also be placed in other folders - by default, these include
:file:`raw/scripts` and :file:`data/save/{region}/raw/scripts`, but additional
folders can be added (for example, a copy of the
:source-scripts:`scripts repository <>` for local development). See
`script-paths` for more information on how to configure this behavior.
Scripts are read from disk when run for the first time, or if they have changed Scripts are read from disk when run for the first time, or if they have changed
since the last time they were run. since the last time they were run.
@ -5509,7 +5538,7 @@ General script API
* ``dfhack.run_script(name[,args...])`` * ``dfhack.run_script(name[,args...])``
Run a Lua script in :file:`hack/scripts/`, as if it were started from the Run a Lua script in your `script-paths`, as if it were started from the
DFHack command-line. The ``name`` argument should be the name of the script DFHack command-line. The ``name`` argument should be the name of the script
without its extension, as it would be used on the command line. without its extension, as it would be used on the command line.
@ -5551,8 +5580,8 @@ Importing scripts
Loads a Lua script and returns its environment (i.e. a table of all global Loads a Lua script and returns its environment (i.e. a table of all global
functions and variables). This is similar to the built-in ``require()``, but functions and variables). This is similar to the built-in ``require()``, but
searches all script paths for the first matching ``name.lua`` file instead searches all `script-paths` for the first matching ``name.lua`` file instead
of searching the Lua library paths (like ``hack/lua``). of searching the Lua library paths (like ``hack/lua/``).
Most scripts can be made to support ``reqscript()`` without significant Most scripts can be made to support ``reqscript()`` without significant
changes (in contrast, ``require()`` requires the use of ``mkmodule()`` and changes (in contrast, ``require()`` requires the use of ``mkmodule()`` and

@ -38,7 +38,7 @@ Overlay widget API
------------------ ------------------
Overlay widgets are Lua classes that inherit from ``overlay.OverlayWidget`` Overlay widgets are Lua classes that inherit from ``overlay.OverlayWidget``
(which itself inherits from `widgets.Widget <widget>`). The regular (which itself inherits from `widgets.Panel <panel>`). The regular
``onInput(keys)``, ``onRenderFrame(dc, frame_rect)``, and ``onRenderBody(dc)`` ``onInput(keys)``, ``onRenderFrame(dc, frame_rect)``, and ``onRenderBody(dc)``
functions work as normal, and they are called when the viewscreen that the functions work as normal, and they are called when the viewscreen that the
widget is associated with does its usual input and render processing. The widget widget is associated with does its usual input and render processing. The widget
@ -125,6 +125,10 @@ The ``overlay.OverlayWidget`` superclass defines the following class attributes:
not annoy the player. Set to 0 to be called at the maximum rate. Be aware not annoy the player. Set to 0 to be called at the maximum rate. Be aware
that running more often than you really need to will impact game FPS, that running more often than you really need to will impact game FPS,
especially if your widget can run while the game is unpaused. especially if your widget can run while the game is unpaused.
- ``always_enabled`` (default: ``false``)
Set this to ``true`` if you don't want to let the user disable the widget.
This is useful for widgets that are controlled purely through their
triggers. See `gui/pathable` for an example.
Registering a widget with the overlay framework Registering a widget with the overlay framework
*********************************************** ***********************************************

@ -60,9 +60,10 @@ For scripts with the same name, the `order of precedence <script-paths>` will
be: be:
1. ``own-scripts/`` 1. ``own-scripts/``
2. ``data/save/*/raw/scripts/`` 2. ``dfhack-config/scripts/``
3. ``raw/scripts/`` 3. ``data/save/*/raw/scripts/``
4. ``hack/scripts/`` 4. ``raw/scripts/``
5. ``hack/scripts/``
The structure of the game The structure of the game
------------------------- -------------------------

@ -12,7 +12,7 @@ watch list. Units will be ignored if they are:
* Untamed * Untamed
* Nicknamed (for custom protection; you can use the `rename` ``unit`` tool * Nicknamed (for custom protection; you can use the `rename` ``unit`` tool
individually, or `zone` ``nick`` for groups) individually, or `zone` ``nick`` for groups)
* Caged, if and only if the cage is defined as a room (to protect zoos) * Caged, if and only if the cage is in a zone (to protect zoos)
* Trained for war or hunting * Trained for war or hunting
Creatures who will not reproduce (because they're not interested in the Creatures who will not reproduce (because they're not interested in the

@ -7,4 +7,4 @@ pathable
:no-command: :no-command:
This plugin provides a Lua API, but no direct commands. See `pathable-api` for This plugin provides a Lua API, but no direct commands. See `pathable-api` for
details. details and `gui/pathable` for the user interface.

@ -96,6 +96,7 @@ endif()
set(MAIN_SOURCES_WINDOWS set(MAIN_SOURCES_WINDOWS
${CONSOLE_SOURCES} ${CONSOLE_SOURCES}
Hooks-windows.cpp Hooks-windows.cpp
Hooks.cpp
PlugLoad-windows.cpp PlugLoad-windows.cpp
Process-windows.cpp Process-windows.cpp
) )
@ -123,6 +124,7 @@ set(MODULE_HEADERS
include/modules/Buildings.h include/modules/Buildings.h
include/modules/Burrows.h include/modules/Burrows.h
include/modules/Constructions.h include/modules/Constructions.h
include/modules/DFSDL.h
include/modules/Designations.h include/modules/Designations.h
include/modules/EventManager.h include/modules/EventManager.h
include/modules/Filesystem.h include/modules/Filesystem.h
@ -140,6 +142,7 @@ set(MODULE_HEADERS
include/modules/Random.h include/modules/Random.h
include/modules/Renderer.h include/modules/Renderer.h
include/modules/Screen.h include/modules/Screen.h
include/modules/Textures.h
include/modules/Translation.h include/modules/Translation.h
include/modules/Units.h include/modules/Units.h
include/modules/World.h include/modules/World.h
@ -149,6 +152,7 @@ set(MODULE_SOURCES
modules/Buildings.cpp modules/Buildings.cpp
modules/Burrows.cpp modules/Burrows.cpp
modules/Constructions.cpp modules/Constructions.cpp
modules/DFSDL.cpp
modules/Designations.cpp modules/Designations.cpp
modules/EventManager.cpp modules/EventManager.cpp
modules/Filesystem.cpp modules/Filesystem.cpp
@ -165,6 +169,7 @@ set(MODULE_SOURCES
modules/Random.cpp modules/Random.cpp
modules/Renderer.cpp modules/Renderer.cpp
modules/Screen.cpp modules/Screen.cpp
modules/Textures.cpp
modules/Translation.cpp modules/Translation.cpp
modules/Units.cpp modules/Units.cpp
modules/World.cpp modules/World.cpp
@ -374,6 +379,8 @@ if(WIN32)
else() else()
set_target_properties(dfhack PROPERTIES COMPILE_FLAGS "-include Export.h" ) set_target_properties(dfhack PROPERTIES COMPILE_FLAGS "-include Export.h" )
set_target_properties(dfhack-client PROPERTIES COMPILE_FLAGS "-include Export.h" ) set_target_properties(dfhack-client PROPERTIES COMPILE_FLAGS "-include Export.h" )
add_library(dfhooks SHARED Hooks.cpp)
target_link_libraries(dfhooks dfhack)
endif() endif()
# effectively disables debug builds... # effectively disables debug builds...
@ -422,6 +429,9 @@ if(UNIX)
install(PROGRAMS ${dfhack_SOURCE_DIR}/package/linux/dfhack-run install(PROGRAMS ${dfhack_SOURCE_DIR}/package/linux/dfhack-run
DESTINATION .) DESTINATION .)
endif() endif()
install(TARGETS dfhooks
LIBRARY DESTINATION .
RUNTIME DESTINATION .)
else() else()
# On windows, copy the renamed SDL so DF can still run. # On windows, copy the renamed SDL so DF can still run.
install(PROGRAMS ${dfhack_SOURCE_DIR}/package/windows/win${DFHACK_BUILD_ARCH}/SDLreal.dll install(PROGRAMS ${dfhack_SOURCE_DIR}/package/windows/win${DFHACK_BUILD_ARCH}/SDLreal.dll

@ -49,9 +49,11 @@ using namespace std;
#include "VersionInfo.h" #include "VersionInfo.h"
#include "PluginManager.h" #include "PluginManager.h"
#include "ModuleFactory.h" #include "ModuleFactory.h"
#include "modules/DFSDL.h"
#include "modules/EventManager.h" #include "modules/EventManager.h"
#include "modules/Filesystem.h" #include "modules/Filesystem.h"
#include "modules/Gui.h" #include "modules/Gui.h"
#include "modules/Textures.h"
#include "modules/World.h" #include "modules/World.h"
#include "modules/Persistence.h" #include "modules/Persistence.h"
#include "RemoteServer.h" #include "RemoteServer.h"
@ -63,8 +65,8 @@ using namespace std;
using namespace DFHack; using namespace DFHack;
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/ui_sidebar_menus.h" #include "df/gamest.h"
#include "df/world.h" #include "df/world.h"
#include "df/world_data.h" #include "df/world_data.h"
#include "df/interfacest.h" #include "df/interfacest.h"
@ -104,6 +106,9 @@ namespace DFHack {
DBG_DECLARE(core,keybinding,DebugCategory::LINFO); DBG_DECLARE(core,keybinding,DebugCategory::LINFO);
DBG_DECLARE(core,script,DebugCategory::LINFO); DBG_DECLARE(core,script,DebugCategory::LINFO);
static const std::string CONFIG_PATH = "dfhack-config/";
static const std::string CONFIG_DEFAULTS_PATH = "hack/data/dfhack-config-defaults/";
class MainThread { class MainThread {
public: public:
//! MainThread::suspend keeps the main DF thread suspended from Core::Init to //! MainThread::suspend keeps the main DF thread suspended from Core::Init to
@ -484,9 +489,10 @@ void Core::getScriptPaths(std::vector<std::string> *dest)
{ {
lock_guard<mutex> lock(script_path_mutex); lock_guard<mutex> lock(script_path_mutex);
dest->clear(); dest->clear();
string df_path = this->p->getPath(); string df_path = this->p->getPath() + "/";
for (auto it = script_paths[0].begin(); it != script_paths[0].end(); ++it) for (auto it = script_paths[0].begin(); it != script_paths[0].end(); ++it)
dest->push_back(*it); dest->push_back(*it);
dest->push_back(df_path + CONFIG_PATH + "scripts");
if (df::global::world && isWorldLoaded()) { if (df::global::world && isWorldLoaded()) {
string save = World::ReadWorldFolder(); string save = World::ReadWorldFolder();
if (save.size()) if (save.size())
@ -515,7 +521,7 @@ string Core::findScript(string name)
bool loadScriptPaths(color_ostream &out, bool silent = false) bool loadScriptPaths(color_ostream &out, bool silent = false)
{ {
using namespace std; using namespace std;
string filename("dfhack-config/script-paths.txt"); string filename(CONFIG_PATH + "script-paths.txt");
ifstream file(filename); ifstream file(filename);
if (!file) if (!file)
{ {
@ -1014,10 +1020,12 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
else if (first == "fpause") else if (first == "fpause")
{ {
World::SetPauseState(true); World::SetPauseState(true);
/* TODO: understand how this changes for v50
if (auto scr = Gui::getViewscreenByType<df::viewscreen_new_regionst>()) if (auto scr = Gui::getViewscreenByType<df::viewscreen_new_regionst>())
{ {
scr->worldgen_paused = true; scr->worldgen_paused = true;
} }
*/
con.print("The game was forced to pause!\n"); con.print("The game was forced to pause!\n");
} }
else if (first == "cls" || first == "clear") else if (first == "cls" || first == "clear")
@ -1299,18 +1307,18 @@ bool Core::loadScriptFile(color_ostream &out, string fname, bool silent)
static void run_dfhack_init(color_ostream &out, Core *core) static void run_dfhack_init(color_ostream &out, Core *core)
{ {
CoreSuspender lock; CoreSuspender lock;
if (!df::global::world || !df::global::ui || !df::global::gview) if (!df::global::world || !df::global::plotinfo || !df::global::gview)
{ {
out.printerr("Key globals are missing, skipping loading dfhack.init.\n"); out.printerr("Key globals are missing, skipping loading dfhack.init.\n");
return; return;
} }
// load baseline defaults // load baseline defaults
core->loadScriptFile(out, "dfhack-config/init/default.dfhack.init", false); core->loadScriptFile(out, CONFIG_PATH + "init/default.dfhack.init", false);
// load user overrides // load user overrides
std::vector<std::string> prefixes(1, "dfhack"); std::vector<std::string> prefixes(1, "dfhack");
loadScriptFiles(core, out, prefixes, "dfhack-config/init"); loadScriptFiles(core, out, prefixes, CONFIG_PATH + "init");
} }
// Load dfhack.init in a dedicated thread (non-interactive console mode) // Load dfhack.init in a dedicated thread (non-interactive console mode)
@ -1326,14 +1334,14 @@ void fInitthread(void * iodata)
// A thread function... for the interactive console. // A thread function... for the interactive console.
void fIOthread(void * iodata) void fIOthread(void * iodata)
{ {
static const char * HISTORY_FILE = "dfhack-config/dfhack.history"; static const std::string HISTORY_FILE = CONFIG_PATH + "dfhack.history";
IODATA * iod = ((IODATA*) iodata); IODATA * iod = ((IODATA*) iodata);
Core * core = iod->core; Core * core = iod->core;
PluginManager * plug_mgr = ((IODATA*) iodata)->plug_mgr; PluginManager * plug_mgr = ((IODATA*) iodata)->plug_mgr;
CommandHistory main_history; CommandHistory main_history;
main_history.load(HISTORY_FILE); main_history.load(HISTORY_FILE.c_str());
Console & con = core->getConsole(); Console & con = core->getConsole();
if (plug_mgr == 0) if (plug_mgr == 0)
@ -1374,7 +1382,7 @@ void fIOthread(void * iodata)
{ {
// a proper, non-empty command was entered // a proper, non-empty command was entered
main_history.add(command); main_history.add(command);
main_history.save(HISTORY_FILE); main_history.save(HISTORY_FILE.c_str());
} }
auto rv = core->runCommand(con, command); auto rv = core->runCommand(con, command);
@ -1479,11 +1487,14 @@ bool Core::Init()
// make it obvious what's going on if someone checks the *.txt files. // make it obvious what's going on if someone checks the *.txt files.
#ifndef LINUX_BUILD #ifndef LINUX_BUILD
// Don't do this on Linux because it will break PRINT_MODE:TEXT // Don't do this on Linux because it will break PRINT_MODE:TEXT
// this is handled as appropriate in Console-posix.cpp
fprintf(stdout, "dfhack: redirecting stdout to stdout.log (again)\n"); fprintf(stdout, "dfhack: redirecting stdout to stdout.log (again)\n");
fprintf(stderr, "dfhack: redirecting stderr to stderr.log (again)\n"); if (!freopen("stdout.log", "w", stdout))
freopen("stdout.log", "w", stdout); cerr << "Could not redirect stdout to stdout.log" << endl;
freopen("stderr.log", "w", stderr);
#endif #endif
fprintf(stderr, "dfhack: redirecting stderr to stderr.log\n");
if (!freopen("stderr.log", "w", stderr))
cerr << "Could not redirect stderr to stderr.log" << endl;
Filesystem::init(); Filesystem::init();
@ -1606,46 +1617,44 @@ bool Core::Init()
// initialize data defs // initialize data defs
virtual_identity::Init(this); virtual_identity::Init(this);
// create config directory if it doesn't already exist
if (!Filesystem::mkdir_recursive(CONFIG_PATH))
con.printerr("Failed to create config directory: '%s'\n", CONFIG_PATH.c_str());
// copy over default config files if necessary // copy over default config files if necessary
std::map<std::string, bool> config_files; std::map<std::string, bool> config_files;
std::map<std::string, bool> default_config_files; std::map<std::string, bool> default_config_files;
if (Filesystem::listdir_recursive("dfhack-config", config_files, 10, false) != 0) if (Filesystem::listdir_recursive(CONFIG_PATH, config_files, 10, false) != 0)
con.printerr("Failed to list directory: dfhack-config"); con.printerr("Failed to list directory: '%s'\n", CONFIG_PATH.c_str());
else if (Filesystem::listdir_recursive("dfhack-config/default", default_config_files, 10, false) != 0) else if (Filesystem::listdir_recursive(CONFIG_DEFAULTS_PATH, default_config_files, 10, false) != 0)
con.printerr("Failed to list directory: dfhack-config/default"); con.printerr("Failed to list directory: '%s'\n", CONFIG_DEFAULTS_PATH.c_str());
else else
{ {
// ensure all config file directories exist before we start copying files // ensure all config file directories exist before we start copying files
for (auto it = default_config_files.begin(); it != default_config_files.end(); ++it) for (auto &entry : default_config_files) {
{
// skip over files // skip over files
if (!it->second) if (!entry.second)
continue; continue;
std::string dirname = "dfhack-config/" + it->first; std::string dirname = CONFIG_PATH + entry.first;
if (!Filesystem::mkdir_recursive(dirname)) if (!Filesystem::mkdir_recursive(dirname))
{
con.printerr("Failed to create config directory: '%s'\n", dirname.c_str()); con.printerr("Failed to create config directory: '%s'\n", dirname.c_str());
}
} }
// copy files from the default tree that don't already exist in the config tree // copy files from the default tree that don't already exist in the config tree
for (auto it = default_config_files.begin(); it != default_config_files.end(); ++it) for (auto &entry : default_config_files) {
{
// skip over directories // skip over directories
if (it->second) if (entry.second)
continue; continue;
std::string filename = it->first; std::string filename = entry.first;
if (config_files.find(filename) == config_files.end()) if (!config_files.count(filename)) {
{ std::string src_file = CONFIG_DEFAULTS_PATH + filename;
std::string src_file = std::string("dfhack-config/default/") + filename;
if (!Filesystem::isfile(src_file)) if (!Filesystem::isfile(src_file))
continue; continue;
std::string dest_file = std::string("dfhack-config/") + filename; std::string dest_file = CONFIG_PATH + filename;
std::ifstream src(src_file, std::ios::binary); std::ifstream src(src_file, std::ios::binary);
std::ofstream dest(dest_file, std::ios::binary); std::ofstream dest(dest_file, std::ios::binary);
if (!src.good() || !dest.good()) if (!src.good() || !dest.good()) {
{ con.printerr("Copy failed: '%s'\n", filename.c_str());
con.printerr("Copy failed: %s\n", filename.c_str());
continue; continue;
} }
dest << src.rdbuf(); dest << src.rdbuf();
@ -1664,8 +1673,15 @@ bool Core::Init()
return false; return false;
} }
cerr << "Binding to SDL.\n";
if (!DFSDL::init(con)) {
fatal("cannot bind SDL libraries");
return false;
}
cerr << "Initializing textures.\n";
Textures::init(con);
// create mutex for syncing with interactive tasks // create mutex for syncing with interactive tasks
cerr << "Initializing Plugins.\n"; cerr << "Initializing plugins.\n";
// create plugin manager // create plugin manager
plug_mgr = new PluginManager(this); plug_mgr = new PluginManager(this);
plug_mgr->init(); plug_mgr->init();
@ -1696,10 +1712,10 @@ bool Core::Init()
if (!listen.get()) if (!listen.get())
cerr << "TCP listen failed.\n"; cerr << "TCP listen failed.\n";
if (df::global::ui_sidebar_menus) if (df::global::game)
{ {
vector<string> args; vector<string> args;
const string & raw = df::global::ui_sidebar_menus->command_line.original; const string & raw = df::global::game->command_line.original;
size_t offset = 0; size_t offset = 0;
while (offset < raw.size()) while (offset < raw.size())
{ {
@ -1758,6 +1774,9 @@ bool Core::Init()
} }
cerr << "DFHack is running.\n"; cerr << "DFHack is running.\n";
onStateChange(con, SC_CORE_INITIALIZED);
return true; return true;
} }
/// sets the current hotkey command /// sets the current hotkey command
@ -1833,17 +1852,10 @@ bool Core::isSuspended(void)
return ownerThread.load() == std::this_thread::get_id(); return ownerThread.load() == std::this_thread::get_id();
} }
void Core::doUpdate(color_ostream &out, bool first_update) void Core::doUpdate(color_ostream &out)
{ {
Lua::Core::Reset(out, "DF code execution"); Lua::Core::Reset(out, "DF code execution");
if (first_update) {
auto L = Lua::Core::State;
Lua::StackUnwinder top(L);
Lua::CallLuaModuleFunction(out, L, "script-manager", "reload");
onStateChange(out, SC_CORE_INITIALIZED);
}
// find the current viewscreen // find the current viewscreen
df::viewscreen *screen = NULL; df::viewscreen *screen = NULL;
if (df::global::gview) if (df::global::gview)
@ -1867,7 +1879,7 @@ void Core::doUpdate(color_ostream &out, bool first_update)
strict_virtual_cast<df::viewscreen_savegamest>(screen); strict_virtual_cast<df::viewscreen_savegamest>(screen);
// save data (do this before updating last_world_data_ptr and triggering unload events) // save data (do this before updating last_world_data_ptr and triggering unload events)
if ((df::global::ui->main.autosave_request && !d->last_autosave_request) || if ((df::global::plotinfo->main.autosave_request && !d->last_autosave_request) ||
(is_load_save && !d->was_load_save && strict_virtual_cast<df::viewscreen_savegamest>(screen))) (is_load_save && !d->was_load_save && strict_virtual_cast<df::viewscreen_savegamest>(screen)))
{ {
doSaveData(out); doSaveData(out);
@ -1929,7 +1941,7 @@ void Core::doUpdate(color_ostream &out, bool first_update)
// Execute per-frame handlers // Execute per-frame handlers
onUpdate(out); onUpdate(out);
d->last_autosave_request = df::global::ui->main.autosave_request; d->last_autosave_request = df::global::plotinfo->main.autosave_request;
d->was_load_save = is_load_save; d->was_load_save = is_load_save;
out << std::flush; out << std::flush;
@ -1946,19 +1958,15 @@ int Core::Update()
// Pretend this thread has suspended the core in the usual way, // Pretend this thread has suspended the core in the usual way,
// and run various processing hooks. // and run various processing hooks.
{ {
// Initialize the core
bool first_update = false;
if(!started) if(!started)
{ {
first_update = true; // Initialize the core
Init(); Init();
if(errorstate) if(errorstate)
return -1; return -1;
Lua::Core::Reset(con, "core init");
} }
doUpdate(out, first_update); doUpdate(out);
} }
// Let all commands run that require CoreSuspender // Let all commands run that require CoreSuspender
@ -2083,9 +2091,9 @@ void Core::handleLoadAndUnloadScripts(color_ostream& out, state_change_event eve
const std::vector<std::string>& set = i->second; const std::vector<std::string>& set = i->second;
// load baseline defaults // load baseline defaults
this->loadScriptFile(out, "dfhack-config/init/default." + set[0] + ".init", false); this->loadScriptFile(out, CONFIG_PATH + "init/default." + set[0] + ".init", false);
loadScriptFiles(this, out, set, "dfhack-config/init"); loadScriptFiles(this, out, set, CONFIG_PATH + "init");
loadScriptFiles(this, out, set, rawFolder); loadScriptFiles(this, out, set, rawFolder);
loadScriptFiles(this, out, set, rawFolder + "objects/"); loadScriptFiles(this, out, set, rawFolder + "objects/");
} }
@ -2135,6 +2143,13 @@ void Core::onStateChange(color_ostream &out, state_change_event event)
switch (event) switch (event)
{ {
case SC_CORE_INITIALIZED:
{
auto L = Lua::Core::State;
Lua::StackUnwinder top(L);
Lua::CallLuaModuleFunction(con, L, "script-manager", "reload");
}
break;
case SC_WORLD_LOADED: case SC_WORLD_LOADED:
case SC_WORLD_UNLOADED: case SC_WORLD_UNLOADED:
case SC_MAP_LOADED: case SC_MAP_LOADED:
@ -2168,6 +2183,10 @@ void Core::onStateChange(color_ostream &out, state_change_event event)
evtlog << std::endl; evtlog << std::endl;
} }
} }
break;
case SC_VIEWSCREEN_CHANGED:
Textures::init(out);
break;
default: default:
break; break;
} }
@ -2245,6 +2264,8 @@ int Core::Shutdown ( void )
} }
// invalidate all modules // invalidate all modules
allModules.clear(); allModules.clear();
Textures::cleanup();
DFSDL::cleanup();
memset(&(s_mods), 0, sizeof(s_mods)); memset(&(s_mods), 0, sizeof(s_mods));
d.reset(); d.reset();
return -1; return -1;
@ -2264,16 +2285,17 @@ bool Core::ncurses_wgetch(int in, int & out)
} }
if(in >= KEY_F(1) && in <= KEY_F(8)) if(in >= KEY_F(1) && in <= KEY_F(8))
{ {
/* TODO: understand how this changes for v50
int idx = in - KEY_F(1); int idx = in - KEY_F(1);
// FIXME: copypasta, push into a method! // FIXME: copypasta, push into a method!
if(df::global::ui && df::global::gview) if(df::global::plotinfo && df::global::gview)
{ {
df::viewscreen * ws = Gui::getCurViewscreen(); df::viewscreen * ws = Gui::getCurViewscreen();
if (strict_virtual_cast<df::viewscreen_dwarfmodest>(ws) && if (strict_virtual_cast<df::viewscreen_dwarfmodest>(ws) &&
df::global::ui->main.mode != ui_sidebar_mode::Hotkeys && df::global::plotinfo->main.mode != ui_sidebar_mode::Hotkeys &&
df::global::ui->main.hotkeys[idx].cmd == df::ui_hotkey::T_cmd::None) df::global::plotinfo->main.hotkeys[idx].cmd == df::ui_hotkey::T_cmd::None)
{ {
setHotkeyCmd(df::global::ui->main.hotkeys[idx].name); setHotkeyCmd(df::global::plotinfo->main.hotkeys[idx].name);
return false; return false;
} }
else else
@ -2282,11 +2304,20 @@ bool Core::ncurses_wgetch(int in, int & out)
return true; return true;
} }
} }
*/
} }
out = in; out = in;
return true; return true;
} }
bool Core::DFH_ncurses_key(int key)
{
if (getenv("DFHACK_HEADLESS"))
return true;
int dummy;
return !ncurses_wgetch(key, dummy);
}
int UnicodeAwareSym(const SDL::KeyboardEvent& ke) int UnicodeAwareSym(const SDL::KeyboardEvent& ke)
{ {
// Assume keyboard layouts don't change the order of numbers: // Assume keyboard layouts don't change the order of numbers:
@ -2391,7 +2422,7 @@ int Core::DFH_SDL_Event(SDL::Event* ev)
bool Core::SelectHotkey(int sym, int modifiers) bool Core::SelectHotkey(int sym, int modifiers)
{ {
// Find the topmost viewscreen // Find the topmost viewscreen
if (!df::global::gview || !df::global::ui) if (!df::global::gview || !df::global::plotinfo)
return false; return false;
df::viewscreen *screen = &df::global::gview->view; df::viewscreen *screen = &df::global::gview->view;
@ -2441,15 +2472,17 @@ bool Core::SelectHotkey(int sym, int modifiers)
int idx = sym - SDL::K_F1; int idx = sym - SDL::K_F1;
if(idx >= 0 && idx < 8) if(idx >= 0 && idx < 8)
{ {
/* TODO: understand how this changes for v50
if (modifiers & 1) if (modifiers & 1)
idx += 8; idx += 8;
if (strict_virtual_cast<df::viewscreen_dwarfmodest>(screen) && if (strict_virtual_cast<df::viewscreen_dwarfmodest>(screen) &&
df::global::ui->main.mode != ui_sidebar_mode::Hotkeys && df::global::plotinfo->main.mode != ui_sidebar_mode::Hotkeys &&
df::global::ui->main.hotkeys[idx].cmd == df::ui_hotkey::T_cmd::None) df::global::plotinfo->main.hotkeys[idx].cmd == df::ui_hotkey::T_cmd::None)
{ {
cmd = df::global::ui->main.hotkeys[idx].name; cmd = df::global::plotinfo->main.hotkeys[idx].name;
} }
*/
} }
} }
} }

@ -6,7 +6,7 @@
#include "df/world.h" #include "df/world.h"
#include "df/world_data.h" #include "df/world_data.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "DataIdentity.h" #include "DataIdentity.h"

@ -279,9 +279,8 @@ DFhackCExport int DFH_SDL_Init(uint32_t flags)
{ {
// reroute stderr // reroute stderr
fprintf(stderr,"dfhack: attempting to hook in\n"); fprintf(stderr,"dfhack: attempting to hook in\n");
freopen("stderr.log", "w", stderr);
// we don't reroute stdout until we figure out if this should be done at all // we don't reroute stdout until we figure out if this should be done at all
// See: Console-linux.cpp // See: Console-posix.cpp
// find real functions // find real functions
fprintf(stderr,"dfhack: saving real SDL functions\n"); fprintf(stderr,"dfhack: saving real SDL functions\n");

@ -117,12 +117,6 @@ DFhackCExport int wgetch(WINDOW *win)
static int (*_SDL_Init)(uint32_t flags) = 0; static int (*_SDL_Init)(uint32_t flags) = 0;
DFhackCExport int SDL_Init(uint32_t flags) DFhackCExport int SDL_Init(uint32_t flags)
{ {
// reroute stderr
if (!freopen("stderr.log", "w", stderr))
fprintf(stderr, "dfhack: failed to reroute stderr\n");
// we don't reroute stdout until we figure out if this should be done at all
// See: Console-linux.cpp
// find real functions // find real functions
_SDL_Init = (int (*)( uint32_t )) dlsym(RTLD_NEXT, "SDL_Init"); _SDL_Init = (int (*)( uint32_t )) dlsym(RTLD_NEXT, "SDL_Init");
_SDL_Quit = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_Quit"); _SDL_Quit = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_Quit");

@ -0,0 +1,33 @@
#include "Core.h"
#include "Export.h"
// called before main event loop starts
DFhackCExport void dfhooks_init() {
DFHack::Core::getInstance().Init();
}
// called after main event loops exits
DFhackCExport void dfhooks_shutdown() {
DFHack::Core::getInstance().Shutdown();
}
// called in the main event loop
DFhackCExport void dfhooks_update() {
DFHack::Core::getInstance().Update();
}
// called just before adding the macro recording/playback overlay
DFhackCExport void dfhooks_prerender() {
// TODO: render overlay widgets that are not attached to a viewscreen
}
// called for each SDL event, if true is returned, then the event has been
// consumed and further processing shouldn't happen
DFhackCExport bool dfhooks_sdl_event(SDL::Event* event) {
return DFHack::Core::getInstance().DFH_SDL_Event(event);
}
// called for each utf-8 char read from the ncurses input
// key is positive for ncurses keys and negative for everything else
DFhackCExport bool dfhooks_ncurses_key(int key) {
return DFHack::Core::getInstance().DFH_ncurses_key(key);
}

@ -57,6 +57,7 @@ distribution.
#include "modules/Materials.h" #include "modules/Materials.h"
#include "modules/Random.h" #include "modules/Random.h"
#include "modules/Screen.h" #include "modules/Screen.h"
#include "modules/Textures.h"
#include "modules/Translation.h" #include "modules/Translation.h"
#include "modules/Units.h" #include "modules/Units.h"
#include "modules/World.h" #include "modules/World.h"
@ -1436,17 +1437,8 @@ static int gui_getDwarfmodeViewDims(lua_State *state)
lua_newtable(state); lua_newtable(state);
Lua::TableInsert(state, "map_x1", dims.map_x1); Lua::TableInsert(state, "map_x1", dims.map_x1);
Lua::TableInsert(state, "map_x2", dims.map_x2); Lua::TableInsert(state, "map_x2", dims.map_x2);
Lua::TableInsert(state, "menu_x1", dims.menu_x1);
Lua::TableInsert(state, "menu_x2", dims.menu_x2);
Lua::TableInsert(state, "area_x1", dims.area_x1);
Lua::TableInsert(state, "area_x2", dims.area_x2);
Lua::TableInsert(state, "y1", dims.y1);
Lua::TableInsert(state, "y2", dims.y2);
Lua::TableInsert(state, "map_y1", dims.map_y1); Lua::TableInsert(state, "map_y1", dims.map_y1);
Lua::TableInsert(state, "map_y2", dims.map_y2); Lua::TableInsert(state, "map_y2", dims.map_y2);
Lua::TableInsert(state, "menu_on", dims.menu_on);
Lua::TableInsert(state, "area_on", dims.area_on);
Lua::TableInsert(state, "menu_forced", dims.menu_forced);
return 1; return 1;
} }
@ -1462,6 +1454,7 @@ static int gui_getMousePos(lua_State *L)
static const LuaWrapper::FunctionReg dfhack_gui_module[] = { static const LuaWrapper::FunctionReg dfhack_gui_module[] = {
WRAPM(Gui, getCurViewscreen), WRAPM(Gui, getCurViewscreen),
WRAPM(Gui, getDFViewscreen),
WRAPM(Gui, getFocusString), WRAPM(Gui, getFocusString),
WRAPM(Gui, getCurFocus), WRAPM(Gui, getCurFocus),
WRAPM(Gui, getSelectedWorkshopJob), WRAPM(Gui, getSelectedWorkshopJob),
@ -1679,6 +1672,13 @@ static const luaL_Reg dfhack_job_funcs[] = {
{ NULL, NULL } { NULL, NULL }
}; };
/***** Textures module *****/
static const LuaWrapper::FunctionReg dfhack_textures_module[] = {
WRAPM(Textures, getDfhackLogoTexposStart),
{ NULL, NULL }
};
/***** Units module *****/ /***** Units module *****/
static const LuaWrapper::FunctionReg dfhack_units_module[] = { static const LuaWrapper::FunctionReg dfhack_units_module[] = {
@ -2373,6 +2373,11 @@ static int screen_getMousePos(lua_State *L)
return Lua::PushPosXY(L, Screen::getMousePos()); return Lua::PushPosXY(L, Screen::getMousePos());
} }
static int screen_getMousePixels(lua_State *L)
{
return Lua::PushPosXY(L, Screen::getMousePixels());
}
static int screen_getWindowSize(lua_State *L) static int screen_getWindowSize(lua_State *L)
{ {
return Lua::PushPosXY(L, Screen::getWindowSize()); return Lua::PushPosXY(L, Screen::getWindowSize());
@ -2452,6 +2457,17 @@ static int screen_findGraphicsTile(lua_State *L)
} }
} }
static int screen_raise(lua_State *L) {
df::viewscreen *screen = dfhack_lua_viewscreen::get_pointer(L, 1, false);
// remove screen from the stack so it doesn't get returned as an output
lua_remove(L, 1);
Screen::raise(screen);
return 0;
}
static int screen_hideGuard(lua_State *L) { static int screen_hideGuard(lua_State *L) {
df::viewscreen *screen = dfhack_lua_viewscreen::get_pointer(L, 1, false); df::viewscreen *screen = dfhack_lua_viewscreen::get_pointer(L, 1, false);
luaL_checktype(L, 2, LUA_TFUNCTION); luaL_checktype(L, 2, LUA_TFUNCTION);
@ -2563,12 +2579,14 @@ static int screen_zoom(lua_State *L)
static const luaL_Reg dfhack_screen_funcs[] = { static const luaL_Reg dfhack_screen_funcs[] = {
{ "getMousePos", screen_getMousePos }, { "getMousePos", screen_getMousePos },
{ "getMousePixels", screen_getMousePixels },
{ "getWindowSize", screen_getWindowSize }, { "getWindowSize", screen_getWindowSize },
{ "paintTile", screen_paintTile }, { "paintTile", screen_paintTile },
{ "readTile", screen_readTile }, { "readTile", screen_readTile },
{ "paintString", screen_paintString }, { "paintString", screen_paintString },
{ "fillRect", screen_fillRect }, { "fillRect", screen_fillRect },
{ "findGraphicsTile", screen_findGraphicsTile }, { "findGraphicsTile", screen_findGraphicsTile },
CWRAP(raise, screen_raise),
CWRAP(hideGuard, screen_hideGuard), CWRAP(hideGuard, screen_hideGuard),
CWRAP(show, screen_show), CWRAP(show, screen_show),
CWRAP(dismiss, screen_dismiss), CWRAP(dismiss, screen_dismiss),
@ -3360,6 +3378,7 @@ void OpenDFHackApi(lua_State *state)
luaL_setfuncs(state, dfhack_funcs, 0); luaL_setfuncs(state, dfhack_funcs, 0);
OpenModule(state, "gui", dfhack_gui_module, dfhack_gui_funcs); OpenModule(state, "gui", dfhack_gui_module, dfhack_gui_funcs);
OpenModule(state, "job", dfhack_job_module, dfhack_job_funcs); OpenModule(state, "job", dfhack_job_module, dfhack_job_funcs);
OpenModule(state, "textures", dfhack_textures_module);
OpenModule(state, "units", dfhack_units_module, dfhack_units_funcs); OpenModule(state, "units", dfhack_units_module, dfhack_units_funcs);
OpenModule(state, "items", dfhack_items_module, dfhack_items_funcs); OpenModule(state, "items", dfhack_items_module, dfhack_items_funcs);
OpenModule(state, "maps", dfhack_maps_module, dfhack_maps_funcs); OpenModule(state, "maps", dfhack_maps_module, dfhack_maps_funcs);

@ -131,9 +131,16 @@ void DFHack::Lua::GetVector(lua_State *state, std::vector<std::string> &pvec)
} }
} }
static bool trigger_inhibit_l_down = false;
static bool trigger_inhibit_r_down = false;
static bool trigger_inhibit_m_down = false;
static bool inhibit_l_down = false;
static bool inhibit_r_down = false;
static bool inhibit_m_down = false;
void DFHack::Lua::PushInterfaceKeys(lua_State *L, void DFHack::Lua::PushInterfaceKeys(lua_State *L,
const std::set<df::interface_key> &keys) { const std::set<df::interface_key> &keys) {
lua_createtable(L, 0, keys.size() + 5); lua_createtable(L, 0, keys.size() + 7);
for (auto &key : keys) for (auto &key : keys)
{ {
@ -154,23 +161,32 @@ void DFHack::Lua::PushInterfaceKeys(lua_State *L,
} }
if (df::global::enabler) { if (df::global::enabler) {
if (df::global::enabler->mouse_lbut_down) { if (!inhibit_l_down && df::global::enabler->mouse_lbut_down) {
lua_pushboolean(L, true); lua_pushboolean(L, true);
lua_setfield(L, -2, "_MOUSE_L_DOWN"); lua_setfield(L, -2, "_MOUSE_L_DOWN");
trigger_inhibit_l_down = true;
} }
if (df::global::enabler->mouse_rbut_down) { if (!inhibit_r_down && df::global::enabler->mouse_rbut_down) {
lua_pushboolean(L, true); lua_pushboolean(L, true);
lua_setfield(L, -2, "_MOUSE_R_DOWN"); lua_setfield(L, -2, "_MOUSE_R_DOWN");
trigger_inhibit_r_down = true;
}
if (!inhibit_m_down && df::global::enabler->mouse_mbut_down) {
lua_pushboolean(L, true);
lua_setfield(L, -2, "_MOUSE_M_DOWN");
trigger_inhibit_m_down = true;
} }
if (df::global::enabler->mouse_lbut) { if (df::global::enabler->mouse_lbut) {
lua_pushboolean(L, true); lua_pushboolean(L, true);
lua_setfield(L, -2, "_MOUSE_L"); lua_setfield(L, -2, "_MOUSE_L");
df::global::enabler->mouse_lbut_down = 0;
} }
if (df::global::enabler->mouse_rbut) { if (df::global::enabler->mouse_rbut) {
lua_pushboolean(L, true); lua_pushboolean(L, true);
lua_setfield(L, -2, "_MOUSE_R"); lua_setfield(L, -2, "_MOUSE_R");
df::global::enabler->mouse_rbut_down = 0; }
if (df::global::enabler->mouse_mbut) {
lua_pushboolean(L, true);
lua_setfield(L, -2, "_MOUSE_M");
} }
} }
} }
@ -2134,4 +2150,24 @@ void DFHack::Lua::Core::Reset(color_ostream &out, const char *where)
out.printerr("Common lua context stack top left at %d after %s.\n", top, where); out.printerr("Common lua context stack top left at %d after %s.\n", top, where);
lua_settop(State, 0); lua_settop(State, 0);
} }
if (trigger_inhibit_l_down) {
trigger_inhibit_l_down = false;
inhibit_l_down = true;
}
if (trigger_inhibit_r_down) {
trigger_inhibit_r_down = false;
inhibit_r_down = true;
}
if (trigger_inhibit_m_down) {
trigger_inhibit_m_down = false;
inhibit_m_down = true;
}
if (!df::global::enabler->mouse_lbut)
inhibit_l_down = false;
if (!df::global::enabler->mouse_rbut)
inhibit_r_down = false;
if (!df::global::enabler->mouse_mbut)
inhibit_m_down = false;
} }

@ -35,7 +35,6 @@ distribution.
#include <stdio.h> #include <stdio.h>
#include "tinythread.h" #include "tinythread.h"
#include "../plugins/uicommon.h"
/* /*
* Plugin loading functions * Plugin loading functions

@ -59,8 +59,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include "LuaTools.h" #include "LuaTools.h"
#include "DataDefs.h" #include "DataDefs.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/ui_advmode.h" #include "df/adventurest.h"
#include "df/world.h" #include "df/world.h"
#include "df/world_data.h" #include "df/world_data.h"
#include "df/unit.h" #include "df/unit.h"
@ -375,11 +375,11 @@ static command_result GetDFVersion(color_ostream &stream,
static command_result GetWorldInfo(color_ostream &stream, static command_result GetWorldInfo(color_ostream &stream,
const EmptyMessage *, GetWorldInfoOut *out) const EmptyMessage *, GetWorldInfoOut *out)
{ {
using df::global::ui; using df::global::plotinfo;
using df::global::ui_advmode; using df::global::adventure;
using df::global::world; using df::global::world;
if (!ui || !world || !Core::getInstance().isWorldLoaded()) if (!plotinfo || !world || !Core::getInstance().isWorldLoaded())
return CR_NOT_FOUND; return CR_NOT_FOUND;
df::game_type gt = game_type::DWARF_MAIN; df::game_type gt = game_type::DWARF_MAIN;
@ -397,10 +397,10 @@ static command_result GetWorldInfo(color_ostream &stream,
case game_type::DWARF_RECLAIM: case game_type::DWARF_RECLAIM:
case game_type::DWARF_UNRETIRE: case game_type::DWARF_UNRETIRE:
out->set_mode(GetWorldInfoOut::MODE_DWARF); out->set_mode(GetWorldInfoOut::MODE_DWARF);
out->set_civ_id(ui->civ_id); out->set_civ_id(plotinfo->civ_id);
out->set_site_id(ui->site_id); out->set_site_id(plotinfo->site_id);
out->set_group_id(ui->group_id); out->set_group_id(plotinfo->group_id);
out->set_race_id(ui->race_id); out->set_race_id(plotinfo->race_id);
break; break;
case game_type::ADVENTURE_MAIN: case game_type::ADVENTURE_MAIN:
@ -410,10 +410,10 @@ static command_result GetWorldInfo(color_ostream &stream,
if (auto unit = vector_get(world->units.active, 0)) if (auto unit = vector_get(world->units.active, 0))
out->set_player_unit_id(unit->id); out->set_player_unit_id(unit->id);
if (!ui_advmode) if (!adventure)
break; break;
if (auto nemesis = vector_get(world->nemesis.all, ui_advmode->player_id)) if (auto nemesis = vector_get(world->nemesis.all, adventure->player_id))
{ {
if (nemesis->figure) if (nemesis->figure)
out->set_player_histfig_id(nemesis->figure->id); out->set_player_histfig_id(nemesis->figure->id);
@ -613,7 +613,7 @@ static command_result ListUnits(color_ostream &stream,
static command_result ListSquads(color_ostream &stream, static command_result ListSquads(color_ostream &stream,
const ListSquadsIn *in, ListSquadsOut *out) const ListSquadsIn *in, ListSquadsOut *out)
{ {
auto entity = df::historical_entity::find(df::global::ui->group_id); auto entity = df::historical_entity::find(df::global::plotinfo->group_id);
if (!entity) if (!entity)
return CR_NOT_FOUND; return CR_NOT_FOUND;

@ -121,6 +121,12 @@ namespace DFHack
friend int ::SDL_Init(uint32_t flags); friend int ::SDL_Init(uint32_t flags);
friend int ::wgetch(WINDOW * w); friend int ::wgetch(WINDOW * w);
#endif #endif
friend void ::dfhooks_init();
friend void ::dfhooks_shutdown();
friend void ::dfhooks_update();
friend void ::dfhooks_prerender();
friend bool ::dfhooks_sdl_event(SDL::Event* event);
friend bool ::dfhooks_ncurses_key(int key);
public: public:
/// Get the single Core instance or make one. /// Get the single Core instance or make one.
static Core& getInstance() static Core& getInstance()
@ -202,8 +208,9 @@ namespace DFHack
int Shutdown (void); int Shutdown (void);
int DFH_SDL_Event(SDL::Event* event); int DFH_SDL_Event(SDL::Event* event);
bool ncurses_wgetch(int in, int & out); bool ncurses_wgetch(int in, int & out);
bool DFH_ncurses_key(int key);
void doUpdate(color_ostream &out, bool first_update); void doUpdate(color_ostream &out);
void onUpdate(color_ostream &out); void onUpdate(color_ostream &out);
void onStateChange(color_ostream &out, state_change_event event); void onStateChange(color_ostream &out, state_change_event event);
void handleLoadAndUnloadScripts(color_ostream &out, state_change_event event); void handleLoadAndUnloadScripts(color_ostream &out, state_change_event event);

@ -394,6 +394,7 @@ namespace df
template<class T> template<class T>
class ro_stl_container_identity : public container_identity { class ro_stl_container_identity : public container_identity {
protected:
const char *name; const char *name;
public: public:
@ -419,6 +420,30 @@ namespace df
} }
}; };
template<class T>
class ro_stl_assoc_container_identity : public ro_stl_container_identity<T> {
type_identity *key_identity;
type_identity *item_identity;
public:
ro_stl_assoc_container_identity(const char *name, type_identity *key, type_identity *item)
: ro_stl_container_identity<T>(name, item),
key_identity(key),
item_identity(item)
{}
virtual std::string getFullName(type_identity*) override {
return std::string(ro_stl_assoc_container_identity<T>::name) + "<" + key_identity->getFullName() + ", " + item_identity->getFullName() + ">";
}
protected:
virtual void *item_pointer(type_identity *item, void *ptr, int idx) override {
auto iter = (*(T*)ptr).begin();
for (; idx > 0; idx--) ++iter;
return (void*)&iter->second;
}
};
class bit_array_identity : public bit_container_identity { class bit_array_identity : public bit_container_identity {
public: public:
/* /*
@ -609,6 +634,10 @@ namespace df
static container_identity *get(); static container_identity *get();
}; };
template<class KT, class T> struct identity_traits<std::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; }
@ -679,6 +708,13 @@ namespace df
return &identity; return &identity;
} }
template<class KT, class T>
inline container_identity *identity_traits<std::map<KT, T>>::get() {
typedef std::map<KT, T> container;
static ro_stl_assoc_container_identity<container> identity("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());

@ -42,13 +42,13 @@ class DebugCategory;
/*! /*!
* \brief Container holding all registered runtime debug categories * \brief Container holding all registered runtime debug categories
* Singleton DebugManager is a minor extension to std::vector that allows signal * Singleton DebugManager is a minor extension to std::vector that allows signal
* callbacks to be attached from ui code that manages. * callbacks to be attached from plotinfo code that manages.
* *
* To avoid parallel plugin unload causing issues access to DebugManager must be * To avoid parallel plugin unload causing issues access to DebugManager must be
* protected by mutex. The access mutex will be taken when * protected by mutex. The access mutex will be taken when
* DFHack::DebugCategory::~DebugCategory performs unregister calls to * DFHack::DebugCategory::~DebugCategory performs unregister calls to
* DFHack::DebugManager. The mutex will protect from memory disappearing while * DFHack::DebugManager. The mutex will protect from memory disappearing while
* ui code is accessing or changing the runtime state. * plotinfo code is accessing or changing the runtime state.
* *
* Signal emitting happens from a locked contexts. Taking the * Signal emitting happens from a locked contexts. Taking the
* DFHack::DebugManager::access_mutex_ in a signal callback will results to a * DFHack::DebugManager::access_mutex_ in a signal callback will results to a

@ -74,3 +74,11 @@ DFhackCExport void * SDL_GetVideoSurface(void);
DFhackCExport int SDL_SemWait(vPtr sem); DFhackCExport int SDL_SemWait(vPtr sem);
DFhackCExport int SDL_SemPost(vPtr sem); DFhackCExport int SDL_SemPost(vPtr sem);
// new Hooks API
DFhackCExport void dfhooks_init();
DFhackCExport void dfhooks_shutdown();
DFhackCExport void dfhooks_update();
DFhackCExport void dfhooks_prerender();
DFhackCExport bool dfhooks_sdl_event(SDL::Event* event);
DFhackCExport bool dfhooks_ncurses_key(int key);

@ -0,0 +1,92 @@
#pragma once
#include "Export.h"
#include "ColorText.h"
namespace DFHack
{
// SDL stand-in type definitions
typedef signed short SINT16;
typedef void DFSDL_sem;
typedef struct
{
int16_t x, y;
uint16_t w, h;
} DFSDL_Rect;
typedef struct
{
void *palette; // SDL_Palette*
uint8_t BitsPerPixel;
uint8_t BytesPerPixel;
uint8_t Rloss;
uint8_t Gloss;
uint8_t Bloss;
uint8_t Aloss;
uint8_t Rshift;
uint8_t Gshift;
uint8_t Bshift;
uint8_t Ashift;
uint32_t Rmask;
uint32_t Gmask;
uint32_t Bmask;
uint32_t Amask;
uint32_t colorkey;
uint8_t alpha;
} DFSDL_PixelFormat;
typedef struct
{
uint32_t flags;
DFSDL_PixelFormat* format;
int w, h;
int pitch;
void* pixels;
void* userdata; // as far as i could see DF doesnt use this
int locked;
void* lock_data;
DFSDL_Rect clip_rect;
void* map;
int refcount;
} DFSDL_Surface;
// =========
struct DFTileSurface
{
bool paintOver; // draw over original tile?
DFSDL_Surface* surface; // from where it should be drawn
DFSDL_Rect* rect; // from which coords (NULL to draw whole surface)
DFSDL_Rect* dstResize; // if not NULL dst rect will be resized (x/y/w/h will be added to original dst)
};
/**
* The DFSDL module - provides access to SDL functions without actually
* requiring build-time linkage to SDL
* \ingroup grp_modules
* \ingroup grp_dfsdl
*/
namespace DFSDL
{
/**
* Call this on DFHack init so we can load the SDL functions. Returns false on
* failure.
*/
bool init(DFHack::color_ostream &out);
/**
* Call this when DFHack is being unloaded.
*/
void cleanup();
DFHACK_EXPORT DFSDL_Surface * DFIMG_Load(const char *file);
DFHACK_EXPORT int DFSDL_SetAlpha(DFSDL_Surface *surface, uint32_t flag, uint8_t alpha);
DFHACK_EXPORT DFSDL_Surface * DFSDL_CreateRGBSurface(uint32_t flags, int width, int height, int depth, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask);
DFHACK_EXPORT int DFSDL_UpperBlit(DFSDL_Surface *src, const DFSDL_Rect *srcrect, DFSDL_Surface *dst, DFSDL_Rect *dstrect);
DFHACK_EXPORT DFSDL_Surface * DFSDL_ConvertSurface(DFSDL_Surface *src, const DFSDL_PixelFormat *fmt, uint32_t flags);
DFHACK_EXPORT void DFSDL_FreeSurface(DFSDL_Surface *surface);
DFHACK_EXPORT int DFSDL_SemWait(DFSDL_sem *sem);
DFHACK_EXPORT int DFSDL_SemPost(DFSDL_sem *sem);
}
}

@ -33,42 +33,11 @@ distribution.
#include <stdint.h> #include <stdint.h>
#include "Export.h" #include "Export.h"
#include "Module.h" #include "Module.h"
#include "DFSDL.h"
#include <vector> #include <vector>
namespace DFHack namespace DFHack
{ {
// SDL stuff
typedef signed short SINT16;
typedef struct
{
int16_t x, y;
uint16_t w, h;
} DFSDL_Rect;
typedef struct
{
uint32_t flags;
void* format; // PixelFormat*
int w, h;
int pitch;
void* pixels;
void* userdata; // as far as i could see DF doesnt use this
int locked;
void* lock_data;
DFSDL_Rect clip_rect;
void* map;
int refcount;
} DFSDL_Surface;
// =========
struct DFTileSurface
{
bool paintOver; // draw over original tile?
DFSDL_Surface* surface; // from where it should be drawn
DFSDL_Rect* rect; // from which coords (NULL to draw whole surface)
DFSDL_Rect* dstResize; // if not NULL dst rect will be resized (x/y/w/h will be added to original dst)
};
class DFHACK_EXPORT Graphic : public Module class DFHACK_EXPORT Graphic : public Module
{ {
public: public:
@ -83,7 +52,6 @@ namespace DFHack
private: private:
std::vector<DFTileSurface* (*)(int, int)> funcs; std::vector<DFTileSurface* (*)(int, int)> funcs;
}; };
} }
#endif #endif

@ -33,7 +33,7 @@ distribution.
#include "DataDefs.h" #include "DataDefs.h"
#include "df/init.h" #include "df/init.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/announcement_type.h" #include "df/announcement_type.h"
#include "df/announcement_flags.h" #include "df/announcement_flags.h"
#include "df/report_init.h" #include "df/report_init.h"
@ -143,13 +143,10 @@ namespace DFHack
static const int MENU_WIDTH = 30; static const int MENU_WIDTH = 30;
struct DwarfmodeDims { struct DwarfmodeDims {
int map_x1, map_x2, menu_x1, menu_x2, area_x1, area_x2; int map_x1, map_x2;
int y1, y2;
int map_y1, map_y2; int map_y1, map_y2;
bool menu_on, area_on, menu_forced;
rect2d map() { return mkrect_xy(map_x1, map_y1, map_x2, map_y2); } rect2d map() { return mkrect_xy(map_x1, map_y1, map_x2, map_y2); }
rect2d menu() { return mkrect_xy(menu_x1, y1, menu_x2, y2); }
}; };
DFHACK_EXPORT DwarfmodeDims getDwarfmodeViewDims(); DFHACK_EXPORT DwarfmodeDims getDwarfmodeViewDims();
@ -184,6 +181,9 @@ namespace DFHack
DFHACK_EXPORT df::viewscreen *getViewscreenByIdentity(virtual_identity &id, int n = 1); DFHACK_EXPORT df::viewscreen *getViewscreenByIdentity(virtual_identity &id, int n = 1);
/// Get the top-most underlying DF viewscreen (not owned by DFHack)
DFHACK_EXPORT df::viewscreen *getDFViewscreen(bool skip_dismissed = false);
/// Get the top-most viewscreen of the given type from the top `n` viewscreens (or all viewscreens if n < 1) /// Get the top-most viewscreen of the given type from the top `n` viewscreens (or all viewscreens if n < 1)
/// returns NULL if none match /// returns NULL if none match
template <typename T> template <typename T>
@ -198,18 +198,6 @@ namespace DFHack
/// get the size of the window buffer /// get the size of the window buffer
DFHACK_EXPORT bool getWindowSize(int32_t & width, int32_t & height); DFHACK_EXPORT bool getWindowSize(int32_t & width, int32_t & height);
/**
*Menu width:
*3:3 - menu and area map closed
*2:3 - menu open single width
*1:3 - menu open double width
*1:2 - menu and area map open
*2:2 - area map open
*/
DFHACK_EXPORT bool getMenuWidth(uint8_t & menu_width, uint8_t & area_map_width);
DFHACK_EXPORT bool setMenuWidth(const uint8_t menu_width, const uint8_t area_map_width);
namespace Hooks { namespace Hooks {
GUI_HOOK_DECLARE(depth_at, int, (int32_t x, int32_t y)); GUI_HOOK_DECLARE(depth_at, int, (int32_t x, int32_t y));
GUI_HOOK_DECLARE(dwarfmode_view_dims, DwarfmodeDims, ()); GUI_HOOK_DECLARE(dwarfmode_view_dims, DwarfmodeDims, ());

@ -75,7 +75,7 @@ DFHACK_EXPORT void clearLimits();
DFHACK_EXPORT std::size_t size(); DFHACK_EXPORT std::size_t size();
// Finds the index of a kitchen exclusion in ui.kitchen.exc_types. Returns -1 if not found. // Finds the index of a kitchen exclusion in plotinfo.kitchen.exc_types. Returns -1 if not found.
DFHACK_EXPORT int findExclusion(df::kitchen_exc_type type, DFHACK_EXPORT int findExclusion(df::kitchen_exc_type type,
df::item_type item_type, int16_t item_subtype, df::item_type item_type, int16_t item_subtype,
int16_t mat_type, int32_t mat_index); int16_t mat_type, int32_t mat_index);

@ -5,13 +5,6 @@
#pragma once #pragma once
namespace DFHack { namespace Renderer { namespace DFHack { namespace Renderer {
// If the the 'x' parameter points to this value, then the 'y' parameter will
// be interpreted as a boolean flag for whether to return map coordinates (false)
// or text tile coordinates (true). Only TWBT implements this logic, and this
// sentinel value can be removed once DF provides an API for retrieving the
// two sets of coordinates.
DFHACK_EXPORT extern const int32_t GET_MOUSE_COORDS_SENTINEL;
struct DFHACK_EXPORT renderer_wrap : public df::renderer { struct DFHACK_EXPORT renderer_wrap : public df::renderer {
void set_to_null(); void set_to_null();
void copy_from_parent(); void copy_from_parent();
@ -19,19 +12,12 @@ namespace DFHack { namespace Renderer {
renderer_wrap *parent; renderer_wrap *parent;
renderer_wrap *child; renderer_wrap *child;
virtual void update_tile(int32_t x, int32_t y);
virtual void update_all();
virtual void render();
virtual void set_fullscreen();
virtual void zoom(df::zoom_commands z);
virtual void resize(int32_t w, int32_t h);
virtual void grid_resize(int32_t w, int32_t h);
virtual ~renderer_wrap() { virtual ~renderer_wrap() {
// All necessary cleanup should be handled by RemoveRenderer() // All necessary cleanup should be handled by RemoveRenderer()
}; };
virtual bool get_mouse_coords(int32_t *x, int32_t *y);
virtual bool uses_opengl();
}; };
/* TODO: we can't cat enabler->renderer to renderer_wrap and expect it to work
// Returns the renderer instance given on success, or deletes it and returns NULL on failure // Returns the renderer instance given on success, or deletes it and returns NULL on failure
// Usage: renderer_foo *r = AddRenderer(new renderer_foo) // Usage: renderer_foo *r = AddRenderer(new renderer_foo)
DFHACK_EXPORT renderer_wrap *AddRenderer(renderer_wrap*, bool refresh_screen = false); DFHACK_EXPORT renderer_wrap *AddRenderer(renderer_wrap*, bool refresh_screen = false);
@ -42,4 +28,5 @@ namespace DFHack { namespace Renderer {
{ {
return (renderer_wrap*)(df::global::enabler ? df::global::enabler->renderer : NULL); return (renderer_wrap*)(df::global::enabler ? df::global::enabler->renderer : NULL);
} }
*/
}} }}

@ -222,6 +222,7 @@ namespace DFHack
DFHACK_EXPORT void dismiss(df::viewscreen *screen, bool to_first = false); DFHACK_EXPORT void dismiss(df::viewscreen *screen, bool to_first = false);
DFHACK_EXPORT bool isDismissed(df::viewscreen *screen); DFHACK_EXPORT bool isDismissed(df::viewscreen *screen);
DFHACK_EXPORT bool hasActiveScreens(Plugin *p); DFHACK_EXPORT bool hasActiveScreens(Plugin *p);
DFHACK_EXPORT void raise(df::viewscreen *screen);
/// Retrieve the string representation of the bound key. /// Retrieve the string representation of the bound key.
DFHACK_EXPORT std::string getKeyDisplay(df::interface_key key); DFHACK_EXPORT std::string getKeyDisplay(df::interface_key key);

@ -0,0 +1,34 @@
#pragma once
#include "Export.h"
#include "ColorText.h"
namespace DFHack {
/**
* The Textures module - loads and provides access to DFHack textures
* \ingroup grp_modules
* \ingroup grp_textures
*/
namespace Textures {
/**
* Call this on DFHack init and on every viewscreen change so we can reload
* and reindex textures as needed.
*/
void init(DFHack::color_ostream &out);
/**
* Call this when DFHack is being unloaded.
*
*/
void cleanup();
/**
* Get first texpos for the DFHack logo. This texpos and the next 11 make up the
* 4x3 grid of logo textures that can be displayed on the UI layer.
*/
DFHACK_EXPORT long getDfhackLogoTexposStart();
}
}

@ -7,17 +7,17 @@ local utils = require('utils')
local dscreen = dfhack.screen local dscreen = dfhack.screen
local getval = utils.getval local getval = utils.getval
USE_GRAPHICS = dscreen.inGraphicsMode()
local to_pen = dfhack.pen.parse local to_pen = dfhack.pen.parse
CLEAR_PEN = to_pen{ch=32,fg=0,bg=0} CLEAR_PEN = to_pen{tile=909, ch=32, fg=0, bg=0}
local FAKE_INPUT_KEYS = { local FAKE_INPUT_KEYS = {
_MOUSE_L = true, _MOUSE_L = true,
_MOUSE_R = true, _MOUSE_R = true,
_MOUSE_M = true,
_MOUSE_L_DOWN = true, _MOUSE_L_DOWN = true,
_MOUSE_R_DOWN = true, _MOUSE_R_DOWN = true,
_MOUSE_M_DOWN = true,
_STRING = true, _STRING = true,
} }
@ -484,6 +484,10 @@ function View:getMousePos(view_rect)
end end
end end
function View:getMouseFramePos()
return self:getMousePos(ViewRect{rect=self.frame_rect})
end
function View:computeFrame(parent_rect) function View:computeFrame(parent_rect)
return mkdims_wh(0,0,parent_rect.width,parent_rect.height) return mkdims_wh(0,0,parent_rect.width,parent_rect.height)
end end
@ -599,6 +603,7 @@ end
Screen = defclass(Screen, View) Screen = defclass(Screen, View)
Screen.text_input_mode = false Screen.text_input_mode = false
Screen.request_full_screen_refresh = false
function Screen:postinit() function Screen:postinit()
self:onResize(dscreen.getWindowSize()) self:onResize(dscreen.getWindowSize())
@ -624,6 +629,10 @@ function Screen:renderParent()
else else
dscreen.clear() dscreen.clear()
end end
if Screen.request_full_screen_refresh then
df.global.gps.force_full_display_count = 1
Screen.request_full_screen_refresh = false
end
end end
function Screen:sendInputToParent(...) function Screen:sendInputToParent(...)
@ -658,6 +667,8 @@ function Screen:dismiss()
if self._native then if self._native then
dscreen.dismiss(self) dscreen.dismiss(self)
end end
-- don't leave artifacts behind on the parent screen when we disappear
Screen.request_full_screen_refresh = true
end end
function Screen:onDismiss() function Screen:onDismiss()
@ -674,9 +685,67 @@ function Screen:onRender()
self:render(Painter.new()) self:render(Painter.new())
end end
------------------------ -----------------------------
-- Z-order swapping screen --
-----------------------------
ZScreen = defclass(ZScreen, Screen)
function ZScreen:onIdle()
if self._native and self._native.parent then
self._native.parent:logic()
end
end
function ZScreen:render(dc)
self:renderParent()
ZScreen.super.render(self, dc)
end
local function zscreen_is_top(self)
return dfhack.gui.getCurViewscreen(true) == self._native
end
function ZScreen:onInput(keys)
if not zscreen_is_top(self) then
if keys._MOUSE_L_DOWN and self:isMouseOver() then
self:raise()
else
self:sendInputToParent(keys)
return
end
end
if ZScreen.super.onInput(self, keys) then
return
end
if keys.LEAVESCREEN or keys._MOUSE_R_DOWN then
self:dismiss()
return
end
if not keys._MOUSE_L or not self:isMouseOver() then
self:sendInputToParent(keys)
end
end
-- move this viewscreen to the top of the stack (if it's not there already)
function ZScreen:raise()
if self:isDismissed() or zscreen_is_top(self) then
return
end
dscreen.raise(self)
end
-- subclasses should override this and return whether the mouse is over an
-- owned screen element
function ZScreen:isMouseOver()
return false
end
--------------------------
-- Framed screen object -- -- Framed screen object --
------------------------ --------------------------
-- Plain grey-colored frame. -- Plain grey-colored frame.
GREY_FRAME = { GREY_FRAME = {
@ -687,21 +756,23 @@ GREY_FRAME = {
-- The usual boundary used by the DF screens. Often has fancy pattern in tilesets. -- The usual boundary used by the DF screens. Often has fancy pattern in tilesets.
BOUNDARY_FRAME = { BOUNDARY_FRAME = {
frame_pen = to_pen{ ch = 0xDB, fg = COLOR_DARKGREY, bg = COLOR_BLACK }, frame_pen = to_pen{ ch = 0xDB, fg = COLOR_GREY, bg = COLOR_BLACK },
title_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_GREY }, title_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_GREY },
signature_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_DARKGREY }, signature_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_GREY },
} }
GREY_LINE_FRAME = { GREY_LINE_FRAME = {
frame_pen = to_pen{ ch = 206, fg = COLOR_GREY, bg = COLOR_BLACK }, frame_pen = to_pen{ ch=206, fg=COLOR_GREY, bg=COLOR_BLACK },
h_frame_pen = to_pen{ ch = 205, fg = COLOR_GREY, bg = COLOR_BLACK }, t_frame_pen = to_pen{ tile=902, ch=205, fg=COLOR_GREY, bg=COLOR_BLACK },
v_frame_pen = to_pen{ ch = 186, fg = COLOR_GREY, bg = COLOR_BLACK }, l_frame_pen = to_pen{ tile=908, ch=186, fg=COLOR_GREY, bg=COLOR_BLACK },
lt_frame_pen = to_pen{ ch = 201, fg = COLOR_GREY, bg = COLOR_BLACK }, b_frame_pen = to_pen{ tile=916, ch=205, fg=COLOR_GREY, bg=COLOR_BLACK },
lb_frame_pen = to_pen{ ch = 200, fg = COLOR_GREY, bg = COLOR_BLACK }, r_frame_pen = to_pen{ tile=910, ch=186, fg=COLOR_GREY, bg=COLOR_BLACK },
rt_frame_pen = to_pen{ ch = 187, fg = COLOR_GREY, bg = COLOR_BLACK }, lt_frame_pen = to_pen{ tile=901, ch=201, fg=COLOR_GREY, bg=COLOR_BLACK },
rb_frame_pen = to_pen{ ch = 188, fg = COLOR_GREY, bg = COLOR_BLACK }, lb_frame_pen = to_pen{ tile=915, ch=200, fg=COLOR_GREY, bg=COLOR_BLACK },
title_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_GREY }, rt_frame_pen = to_pen{ tile=903, ch=187, fg=COLOR_GREY, bg=COLOR_BLACK },
signature_pen = to_pen{ fg = COLOR_DARKGREY, bg = COLOR_BLACK }, rb_frame_pen = to_pen{ tile=917, ch=188, fg=COLOR_GREY, bg=COLOR_BLACK },
title_pen = to_pen{ fg=COLOR_BLACK, bg=COLOR_GREY },
signature_pen = to_pen{ fg=COLOR_GREY, bg=COLOR_BLACK },
} }
function paint_frame(dc,rect,style,title) function paint_frame(dc,rect,style,title)

@ -258,8 +258,8 @@ function BuildingDialog:onSubmitItem(idx, item)
end end
function BuildingDialog:onInput(keys) function BuildingDialog:onInput(keys)
if keys.LEAVESCREEN or keys.LEAVESCREEN_ALL then if keys.LEAVESCREEN then
if self.subviews.back.visible and not keys.LEAVESCREEN_ALL then if self.subviews.back.visible then
self:onGoBack() self:onGoBack()
else else
self:dismiss() self:dismiss()
@ -267,9 +267,9 @@ function BuildingDialog:onInput(keys)
self.on_cancel() self.on_cancel()
end end
end end
else return true
self:inputToSubviews(keys)
end end
self:inputToSubviews(keys)
end end
function showBuildingPrompt(title, prompt, on_select, on_cancel, build_filter) function showBuildingPrompt(title, prompt, on_select, on_cancel, build_filter)

@ -48,7 +48,7 @@ end
function MessageBox:onRenderFrame(dc,rect) function MessageBox:onRenderFrame(dc,rect)
MessageBox.super.onRenderFrame(self,dc,rect) MessageBox.super.onRenderFrame(self,dc,rect)
if self.on_accept then if self.on_accept then
dc:seek(rect.x1+2,rect.y2):key('LEAVESCREEN'):string('/'):key('MENU_CONFIRM') dc:seek(rect.x1+2,rect.y2):key('LEAVESCREEN'):string('/'):key('SELECT')
end end
end end
@ -59,19 +59,16 @@ function MessageBox:onDestroy()
end end
function MessageBox:onInput(keys) function MessageBox:onInput(keys)
if keys.MENU_CONFIRM then if keys.SELECT or keys.LEAVESCREEN then
self:dismiss() self:dismiss()
if self.on_accept then if keys.SELECT and self.on_accept then
self.on_accept() self.on_accept()
end elseif keys.LEAVESCREEN and self.on_cancel then
elseif keys.LEAVESCREEN or (keys.SELECT and not self.on_accept) then
self:dismiss()
if self.on_cancel then
self.on_cancel() self.on_cancel()
end end
else return true
self:inputToSubviews(keys)
end end
return self:inputToSubviews(keys)
end end
function showMessage(title, text, tcolor, on_close) function showMessage(title, text, tcolor, on_close)
@ -132,14 +129,15 @@ function InputBox:onInput(keys)
if self.on_input then if self.on_input then
self.on_input(self.subviews.edit.text) self.on_input(self.subviews.edit.text)
end end
return true
elseif keys.LEAVESCREEN then elseif keys.LEAVESCREEN then
self:dismiss() self:dismiss()
if self.on_cancel then if self.on_cancel then
self.on_cancel() self.on_cancel()
end end
else return true
self:inputToSubviews(keys)
end end
return self:inputToSubviews(keys)
end end
function showInputPrompt(title, text, tcolor, input, on_input, on_cancel, min_width) function showInputPrompt(title, text, tcolor, input, on_input, on_cancel, min_width)
@ -238,9 +236,9 @@ function ListBox:onInput(keys)
if self.on_cancel then if self.on_cancel then
self.on_cancel() self.on_cancel()
end end
else return true
self:inputToSubviews(keys)
end end
return self:inputToSubviews(keys)
end end
function showListPrompt(title, text, tcolor, choices, on_select, on_cancel, min_width, filter) function showListPrompt(title, text, tcolor, choices, on_select, on_cancel, min_width, filter)

@ -49,7 +49,7 @@ function enterSidebarMode(sidebar_mode, max_esc)
while remaining_esc > 0 do while remaining_esc > 0 do
local screen = dfhack.gui.getCurViewscreen(true) local screen = dfhack.gui.getCurViewscreen(true)
focus_string = dfhack.gui.getFocusString(screen) focus_string = dfhack.gui.getFocusString(screen)
if df.global.ui.main.mode == df.ui_sidebar_mode.Default and if df.global.plotinfo.main.mode == df.ui_sidebar_mode.Default and
focus_string == 'dwarfmode/Default' then focus_string == 'dwarfmode/Default' then
if #navkey > 0 then gui.simulateInput(screen, navkey) end if #navkey > 0 then gui.simulateInput(screen, navkey) end
if navkey == 'D_DESIGNATE' then if navkey == 'D_DESIGNATE' then
@ -71,30 +71,9 @@ end
function getPanelLayout() function getPanelLayout()
local dims = dfhack.gui.getDwarfmodeViewDims() local dims = dfhack.gui.getDwarfmodeViewDims()
local area_pos = df.global.ui_menu_width[1] return {
local menu_pos = df.global.ui_menu_width[0] map=gui.mkdims_xy(dims.map_x1, dims.map_y1, dims.map_x2, dims.map_y2),
if dims.menu_forced then
menu_pos = area_pos - 1
end
local rv = {
menu_pos = menu_pos,
area_pos = area_pos,
map = gui.mkdims_xy(dims.map_x1, dims.map_y1, dims.map_x2, dims.map_y2),
} }
if dims.menu_forced then
rv.menu_forced = true
end
if dims.menu_on then
rv.menu = gui.mkdims_xy(dims.menu_x1, dims.y1, dims.menu_x2, dims.y2)
end
if dims.area_on then
rv.area_map = gui.mkdims_xy(dims.area_x1, dims.y1, dims.area_x2, dims.y2)
end
return rv
end end
function getCursorPos() function getCursorPos()
@ -267,6 +246,10 @@ function Viewport:reveal(target,gap,max_scroll,scroll_gap,scroll_z)
end end
MOVEMENT_KEYS = { MOVEMENT_KEYS = {
KEYBOARD_CURSOR_UP = { 0, -1, 0 }, KEYBOARD_CURSOR_DOWN = { 0, 1, 0 },
KEYBOARD_CURSOR_LEFT = { -1, 0, 0 }, KEYBOARD_CURSOR_RIGHT = { 1, 0, 0 },
KEYBOARD_CURSOR_UP_FAST = { 0, -1, 0, true }, KEYBOARD_CURSOR_DOWN_FAST = { 0, 1, 0, true },
KEYBOARD_CURSOR_LEFT_FAST = { -1, 0, 0, true }, KEYBOARD_CURSOR_RIGHT_FAST = { 1, 0, 0, true },
CURSOR_UP = { 0, -1, 0 }, CURSOR_DOWN = { 0, 1, 0 }, CURSOR_UP = { 0, -1, 0 }, CURSOR_DOWN = { 0, 1, 0 },
CURSOR_LEFT = { -1, 0, 0 }, CURSOR_RIGHT = { 1, 0, 0 }, CURSOR_LEFT = { -1, 0, 0 }, CURSOR_RIGHT = { 1, 0, 0 },
CURSOR_UPLEFT = { -1, -1, 0 }, CURSOR_UPRIGHT = { 1, -1, 0 }, CURSOR_UPLEFT = { -1, -1, 0 }, CURSOR_UPRIGHT = { 1, -1, 0 },
@ -292,7 +275,7 @@ end
HOTKEY_KEYS = {} HOTKEY_KEYS = {}
for i,v in ipairs(df.global.ui.main.hotkeys) do for i,v in ipairs(df.global.plotinfo.main.hotkeys) do
HOTKEY_KEYS['D_HOTKEY'..(i+1)] = v HOTKEY_KEYS['D_HOTKEY'..(i+1)] = v
end end
@ -450,7 +433,7 @@ function MenuOverlay:init()
end end
if self.sidebar_mode then if self.sidebar_mode then
self.saved_sidebar_mode = df.global.ui.main.mode self.saved_sidebar_mode = df.global.plotinfo.main.mode
-- what mode should we restore when this window is dismissed? ideally, we'd -- what mode should we restore when this window is dismissed? ideally, we'd
-- restore the mode that the user has set, but we should fall back to -- restore the mode that the user has set, but we should fall back to
-- restoring the default mode if either of the following conditions are -- restoring the default mode if either of the following conditions are
@ -553,66 +536,4 @@ function MenuOverlay:renderMapOverlay(get_overlay_char_fn, bounds_rect)
end end
end end
--fakes a "real" workshop sidebar menu, but on exactly selected workshop
WorkshopOverlay = defclass(WorkshopOverlay, MenuOverlay)
WorkshopOverlay.focus_path="WorkshopOverlay"
WorkshopOverlay.ATTRS={
workshop=DEFAULT_NIL,
}
function WorkshopOverlay:onAboutToShow(below)
WorkshopOverlay.super.onAboutToShow(self,below)
if df.global.world.selected_building ~= self.workshop then
error("The workshop overlay tried to show up for incorrect workshop")
end
end
function WorkshopOverlay:onInput(keys)
local allowedKeys={ --TODO add options: job management, profile, etc...
"CURSOR_RIGHT","CURSOR_RIGHT_FAST","CURSOR_LEFT","CURSOR_LEFT_FAST","CURSOR_UP","CURSOR_UP_FAST","CURSOR_DOWN","CURSOR_DOWN_FAST",
"CURSOR_UPRIGHT","CURSOR_UPRIGHT_FAST","CURSOR_UPLEFT","CURSOR_UPLEFT_FAST","CURSOR_DOWNRIGHT","CURSOR_DOWNRIGHT_FAST","CURSOR_DOWNLEFT","CURSOR_DOWNLEFT_FAST",
"CURSOR_UP_Z","CURSOR_DOWN_Z","DESTROYBUILDING","CHANGETAB","SUSPENDBUILDING"}
if keys.LEAVESCREEN then
self:dismiss()
self:sendInputToParent('LEAVESCREEN')
elseif keys.CHANGETAB then
self:sendInputToParent("CHANGETAB")
self:inputToSubviews(keys)
self:updateLayout()
else
for _,name in ipairs(allowedKeys) do
if keys[name] then
self:sendInputToParent(name)
break
end
end
self:inputToSubviews(keys)
end
if df.global.world.selected_building ~= self.workshop then
self:dismiss()
return
end
end
function WorkshopOverlay:onGetSelectedBuilding()
return self.workshop
end
local function is_slated_for_remove( bld )
for i,v in ipairs(bld.jobs) do
if v.job_type==df.job_type.DestroyBuilding then
return true
end
end
return false
end
function WorkshopOverlay:render(dc)
self:renderParent()
if df.global.world.selected_building ~= self.workshop then
return
end
if is_slated_for_remove(self.workshop) then
return
end
WorkshopOverlay.super.render(self, dc)
end
return _ENV return _ENV

@ -255,8 +255,8 @@ function MaterialDialog:onSubmitItem(idx, item)
end end
function MaterialDialog:onInput(keys) function MaterialDialog:onInput(keys)
if keys.LEAVESCREEN or keys.LEAVESCREEN_ALL then if keys.LEAVESCREEN then
if self.subviews.back.visible and not keys.LEAVESCREEN_ALL then if self.subviews.back.visible then
self:onGoBack() self:onGoBack()
else else
self:dismiss() self:dismiss()
@ -264,9 +264,9 @@ function MaterialDialog:onInput(keys)
self.on_cancel() self.on_cancel()
end end
end end
else return true
self:inputToSubviews(keys)
end end
return self:inputToSubviews(keys)
end end
function showMaterialPrompt(title, prompt, on_select, on_cancel, mat_filter) function showMaterialPrompt(title, prompt, on_select, on_cancel, mat_filter)

@ -8,6 +8,7 @@ local utils = require('utils')
local dscreen = dfhack.screen local dscreen = dfhack.screen
local getval = utils.getval local getval = utils.getval
local to_pen = dfhack.pen.parse
local function show_view(view,vis) local function show_view(view,vis)
if view then if view then
@ -25,16 +26,13 @@ end
STANDARDSCROLL = { STANDARDSCROLL = {
STANDARDSCROLL_UP = -1, STANDARDSCROLL_UP = -1,
KEYBOARD_CURSOR_UP = -1,
STANDARDSCROLL_DOWN = 1, STANDARDSCROLL_DOWN = 1,
KEYBOARD_CURSOR_DOWN = 1,
STANDARDSCROLL_PAGEUP = '-page', STANDARDSCROLL_PAGEUP = '-page',
KEYBOARD_CURSOR_UP_FAST = '-page',
STANDARDSCROLL_PAGEDOWN = '+page', STANDARDSCROLL_PAGEDOWN = '+page',
} KEYBOARD_CURSOR_DOWN_FAST = '+page',
SECONDSCROLL = {
SECONDSCROLL_UP = -1,
SECONDSCROLL_DOWN = 1,
SECONDSCROLL_PAGEUP = '-page',
SECONDSCROLL_PAGEDOWN = '+page',
} }
------------ ------------
@ -89,7 +87,7 @@ Panel.ATTRS {
function Panel:init(args) function Panel:init(args)
if not self.drag_anchors then if not self.drag_anchors then
self.drag_anchors = {title=true, frame=false, body=false} self.drag_anchors = {title=true, frame=false, body=true}
end end
if not self.resize_anchors then if not self.resize_anchors then
self.resize_anchors = {t=false, l=true, r=true, b=true} self.resize_anchors = {t=false, l=true, r=true, b=true}
@ -305,8 +303,7 @@ function Panel:onInput(keys)
return true return true
end end
if not keys._MOUSE_L_DOWN then return end if not keys._MOUSE_L_DOWN then return end
local rect = self.frame_rect local x,y = self:getMouseFramePos()
local x,y = self:getMousePos(gui.ViewRect{rect=rect})
if not x then return end if not x then return end
if self.resizable and y == 0 then if self.resizable and y == 0 then
@ -365,8 +362,10 @@ function Panel:setKeyboardDragEnabled(enabled)
return return
end end
if enabled then if enabled then
local kbd_get_pos = function() return {x=0, y=0} end local kbd_get_pos = function()
Panel_begin_drag(self, kbd_get_pos()) return {x=self.frame_rect.x1, y=self.frame_rect.y1}
end
Panel_begin_drag(self)
self.kbd_get_pos = kbd_get_pos self.kbd_get_pos = kbd_get_pos
else else
Panel_end_drag(self) Panel_end_drag(self)
@ -441,6 +440,9 @@ end
-- if self.autoarrange_subviews is true, lay out visible subviews vertically, -- if self.autoarrange_subviews is true, lay out visible subviews vertically,
-- adding gaps between widgets according to self.autoarrange_gap. -- adding gaps between widgets according to self.autoarrange_gap.
function Panel:postUpdateLayout() function Panel:postUpdateLayout()
-- don't leave artifacts behind on the parent screen when we move
gui.Screen.request_full_screen_refresh = true
if not self.autoarrange_subviews then return end if not self.autoarrange_subviews then return end
local gap = self.autoarrange_gap local gap = self.autoarrange_gap
@ -465,7 +467,7 @@ function Panel:onRenderFrame(dc, rect)
gui.paint_frame(dc, rect, self.frame_style, self.frame_title) gui.paint_frame(dc, rect, self.frame_style, self.frame_title)
if self.kbd_get_pos then if self.kbd_get_pos then
local pos = self.kbd_get_pos() local pos = self.kbd_get_pos()
local pen = dfhack.pen.parse{fg=COLOR_GREEN, bg=COLOR_BLACK} local pen = to_pen{fg=COLOR_GREEN, bg=COLOR_BLACK}
dc:seek(pos.x, pos.y):pen(pen):char(string.char(0xDB)) dc:seek(pos.x, pos.y):pen(pen):char(string.char(0xDB))
end end
if self.drag_offset and not self.kbd_get_pos if self.drag_offset and not self.kbd_get_pos
@ -654,6 +656,12 @@ function EditField:onRenderBody(dc)
dc:string((' '):rep(dc.clip_x2 - dc.x)) dc:string((' '):rep(dc.clip_x2 - dc.x))
end end
function EditField:insert(text)
local old = self.text
self:setText(old:sub(1,self.cursor-1)..text..old:sub(self.cursor),
self.cursor + #text)
end
function EditField:onInput(keys) function EditField:onInput(keys)
if not self.focus then if not self.focus then
-- only react to our hotkey -- only react to our hotkey
@ -676,22 +684,20 @@ function EditField:onInput(keys)
return true return true
end end
if keys.SELECT then if keys.SELECT or keys.CUSTOM_SHIFT_ENTER then
if self.key then if self.key then
self:setFocus(false) self:setFocus(false)
end end
if self.on_submit then if keys.CUSTOM_SHIFT_ENTER then
self.on_submit(self.text) if self.on_submit2 then
return true self.on_submit2(self.text)
end return true
return not not self.key end
elseif keys.SEC_SELECT then else
if self.key then if self.on_submit then
self:setFocus(false) self.on_submit(self.text)
end return true
if self.on_submit2 then end
self.on_submit2(self.text)
return true
end end
return not not self.key return not not self.key
elseif keys._MOUSE_L then elseif keys._MOUSE_L then
@ -712,8 +718,7 @@ function EditField:onInput(keys)
else else
local cv = string.char(keys._STRING) local cv = string.char(keys._STRING)
if not self.on_char or self.on_char(cv, old) then if not self.on_char or self.on_char(cv, old) then
self:setText(old:sub(1,self.cursor-1)..cv..old:sub(self.cursor), self:insert(cv)
self.cursor + 1)
elseif self.on_char then elseif self.on_char then
return self.modal return self.modal
end end
@ -722,25 +727,25 @@ function EditField:onInput(keys)
self.on_change(self.text, old) self.on_change(self.text, old)
end end
return true return true
elseif keys.CURSOR_LEFT then elseif keys.KEYBOARD_CURSOR_LEFT then
self:setCursor(self.cursor - 1) self:setCursor(self.cursor - 1)
return true return true
elseif keys.A_MOVE_W_DOWN then -- Ctrl-Left (end of prev word) elseif keys.CUSTOM_CTRL_B then -- back one word
local _, prev_word_end = self.text:sub(1, self.cursor-1): local _, prev_word_end = self.text:sub(1, self.cursor-1):
find('.*[%w_%-][^%w_%-]') find('.*[%w_%-][^%w_%-]')
self:setCursor(prev_word_end or 1) self:setCursor(prev_word_end or 1)
return true return true
elseif keys.A_CARE_MOVE_W then -- Alt-Left (home) elseif keys.CUSTOM_CTRL_A then -- home
self:setCursor(1) self:setCursor(1)
return true return true
elseif keys.CURSOR_RIGHT then elseif keys.KEYBOARD_CURSOR_RIGHT then
self:setCursor(self.cursor + 1) self:setCursor(self.cursor + 1)
return true return true
elseif keys.A_MOVE_E_DOWN then -- Ctrl-Right (beginning of next word) elseif keys.CUSTOM_CTRL_F then -- forward one word
local _,next_word_start = self.text:find('[^%w_%-][%w_%-]', self.cursor) local _,next_word_start = self.text:find('[^%w_%-][%w_%-]', self.cursor)
self:setCursor(next_word_start) self:setCursor(next_word_start)
return true return true
elseif keys.A_CARE_MOVE_E then -- Alt-Right (end) elseif keys.CUSTOM_CTRL_E then -- end
self:setCursor() self:setCursor()
return true return true
end end
@ -759,14 +764,12 @@ SCROLL_DELAY_MS = 20
Scrollbar = defclass(Scrollbar, Widget) Scrollbar = defclass(Scrollbar, Widget)
Scrollbar.ATTRS{ Scrollbar.ATTRS{
fg = COLOR_LIGHTGREEN,
bg = COLOR_CYAN,
on_scroll = DEFAULT_NIL, on_scroll = DEFAULT_NIL,
} }
function Scrollbar:preinit(init_table) function Scrollbar:preinit(init_table)
init_table.frame = init_table.frame or {} init_table.frame = init_table.frame or {}
init_table.frame.w = init_table.frame.w or 1 init_table.frame.w = init_table.frame.w or 2
end end
function Scrollbar:init() function Scrollbar:init()
@ -824,36 +827,95 @@ local function scrollbar_is_visible(scrollbar)
return scrollbar.elems_per_page < scrollbar.num_elems return scrollbar.elems_per_page < scrollbar.num_elems
end end
local UP_ARROW_CHAR = string.char(24) local SCROLLBAR_UP_LEFT_PEN = to_pen{tile=922, ch=47, fg=COLOR_CYAN, bg=COLOR_BLACK}
local DOWN_ARROW_CHAR = string.char(25) local SCROLLBAR_UP_RIGHT_PEN = to_pen{tile=923, ch=92, fg=COLOR_CYAN, bg=COLOR_BLACK}
local NO_ARROW_CHAR = string.char(32) local SCROLLBAR_DOWN_LEFT_PEN = to_pen{tile=946, ch=92, fg=COLOR_CYAN, bg=COLOR_BLACK}
local BAR_CHAR = string.char(7) local SCROLLBAR_DOWN_RIGHT_PEN = to_pen{tile=947, ch=47, fg=COLOR_CYAN, bg=COLOR_BLACK}
local BAR_BG_CHAR = string.char(179) local SCROLLBAR_BAR_UP_LEFT_PEN = to_pen{tile=930, ch=219, fg=COLOR_CYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_UP_RIGHT_PEN = to_pen{tile=931, ch=219, fg=COLOR_CYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_LEFT_PEN = to_pen{tile=954, ch=219, fg=COLOR_CYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_RIGHT_PEN = to_pen{tile=955, ch=219, fg=COLOR_CYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_CENTER_UP_LEFT_PEN = to_pen{tile=932, ch=219, fg=COLOR_CYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_CENTER_UP_RIGHT_PEN = to_pen{tile=933, ch=219, fg=COLOR_CYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_CENTER_DOWN_LEFT_PEN = to_pen{tile=960, ch=219, fg=COLOR_CYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_CENTER_DOWN_RIGHT_PEN = to_pen{tile=961, ch=219, fg=COLOR_CYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_CENTER_LEFT_PEN = to_pen{tile=940, ch=219, fg=COLOR_CYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_CENTER_RIGHT_PEN = to_pen{tile=941, ch=219, fg=COLOR_CYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_DOWN_LEFT_PEN = to_pen{tile=966, ch=219, fg=COLOR_CYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_DOWN_RIGHT_PEN = to_pen{tile=967, ch=219, fg=COLOR_CYAN, bg=COLOR_BLACK}
local SCROLLBAR_UP_LEFT_HOVER_PEN = to_pen{tile=924, ch=47, fg=COLOR_LIGHTCYAN, bg=COLOR_BLACK}
local SCROLLBAR_UP_RIGHT_HOVER_PEN = to_pen{tile=925, ch=92, fg=COLOR_LIGHTCYAN, bg=COLOR_BLACK}
local SCROLLBAR_DOWN_LEFT_HOVER_PEN = to_pen{tile=936, ch=92, fg=COLOR_LIGHTCYAN, bg=COLOR_BLACK}
local SCROLLBAR_DOWN_RIGHT_HOVER_PEN = to_pen{tile=937, ch=47, fg=COLOR_LIGHTCYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_UP_LEFT_HOVER_PEN = to_pen{tile=930, ch=219, fg=COLOR_LIGHTCYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_UP_RIGHT_HOVER_PEN = to_pen{tile=931, ch=219, fg=COLOR_LIGHTCYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_LEFT_HOVER_PEN = to_pen{tile=954, ch=219, fg=COLOR_LIGHTCYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_RIGHT_HOVER_PEN = to_pen{tile=955, ch=219, fg=COLOR_LIGHTCYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_CENTER_UP_LEFT_HOVER_PEN = to_pen{tile=956, ch=219, fg=COLOR_LIGHTCYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_CENTER_UP_RIGHT_HOVER_PEN = to_pen{tile=957, ch=219, fg=COLOR_LIGHTCYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_CENTER_DOWN_LEFT_HOVER_PEN = to_pen{tile=968, ch=219, fg=COLOR_LIGHTCYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_CENTER_DOWN_RIGHT_HOVER_PEN = to_pen{tile=969, ch=219, fg=COLOR_LIGHTCYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_CENTER_LEFT_HOVER_PEN = to_pen{tile=942, ch=219, fg=COLOR_LIGHTCYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_CENTER_RIGHT_HOVER_PEN = to_pen{tile=943, ch=219, fg=COLOR_LIGHTCYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_DOWN_LEFT_HOVER_PEN = to_pen{tile=966, ch=219, fg=COLOR_LIGHTCYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_DOWN_RIGHT_HOVER_PEN = to_pen{tile=967, ch=219, fg=COLOR_LIGHTCYAN, bg=COLOR_BLACK}
local SCROLLBAR_BAR_BG_LEFT_PEN = to_pen{tile=934, ch=176, fg=COLOR_DARKGREY, bg=COLOR_BLACK}
local SCROLLBAR_BAR_BG_RIGHT_PEN = to_pen{tile=935, ch=176, fg=COLOR_DARKGREY, bg=COLOR_BLACK}
function Scrollbar:onRenderBody(dc) function Scrollbar:onRenderBody(dc)
-- don't draw if all elements are visible -- don't draw if all elements are visible
if not scrollbar_is_visible(self) then if not scrollbar_is_visible(self) then
return return
end end
-- render up arrow if we're not at the top -- determine which elements should be highlighted
dc:seek(0, 0):char( local _,hover_y = self:getMousePos()
self.top_elem == 1 and NO_ARROW_CHAR or UP_ARROW_CHAR, self.fg, self.bg) local hover_up, hover_down, hover_bar = false, false, false
if hover_y == 0 then
hover_up = true
elseif hover_y == dc.height-1 then
hover_down = true
elseif hover_y then
hover_bar = true
end
-- render up arrow
dc:seek(0, 0)
dc:char(nil, hover_up and SCROLLBAR_UP_LEFT_HOVER_PEN or SCROLLBAR_UP_LEFT_PEN)
dc:char(nil, hover_up and SCROLLBAR_UP_RIGHT_HOVER_PEN or SCROLLBAR_UP_RIGHT_PEN)
-- render scrollbar body -- render scrollbar body
local starty = self.bar_offset + 1 local starty = self.bar_offset + 1
local endy = self.bar_offset + self.bar_height local endy = self.bar_offset + self.bar_height
local midy = (starty + endy)/2
for y=1,dc.height-2 do for y=1,dc.height-2 do
dc:seek(0, y) dc:seek(0, y)
if y >= starty and y <= endy then if y >= starty and y <= endy then
dc:char(BAR_CHAR, self.fg) if y == starty and y <= midy - 1 then
dc:char(nil, hover_bar and SCROLLBAR_BAR_UP_LEFT_HOVER_PEN or SCROLLBAR_BAR_UP_LEFT_PEN)
dc:char(nil, hover_bar and SCROLLBAR_BAR_UP_RIGHT_HOVER_PEN or SCROLLBAR_BAR_UP_RIGHT_PEN)
elseif y == midy - 0.5 then
dc:char(nil, hover_bar and SCROLLBAR_BAR_CENTER_UP_LEFT_HOVER_PEN or SCROLLBAR_BAR_CENTER_UP_LEFT_PEN)
dc:char(nil, hover_bar and SCROLLBAR_BAR_CENTER_UP_RIGHT_HOVER_PEN or SCROLLBAR_BAR_CENTER_UP_RIGHT_PEN)
elseif y == midy + 0.5 then
dc:char(nil, hover_bar and SCROLLBAR_BAR_CENTER_DOWN_LEFT_HOVER_PEN or SCROLLBAR_BAR_CENTER_DOWN_LEFT_PEN)
dc:char(nil, hover_bar and SCROLLBAR_BAR_CENTER_DOWN_RIGHT_HOVER_PEN or SCROLLBAR_BAR_CENTER_DOWN_RIGHT_PEN)
elseif y == midy then
dc:char(nil, hover_bar and SCROLLBAR_BAR_CENTER_LEFT_HOVER_PEN or SCROLLBAR_BAR_CENTER_LEFT_PEN)
dc:char(nil, hover_bar and SCROLLBAR_BAR_CENTER_RIGHT_HOVER_PEN or SCROLLBAR_BAR_CENTER_RIGHT_PEN)
elseif y == endy and y >= midy + 1 then
dc:char(nil, hover_bar and SCROLLBAR_BAR_DOWN_LEFT_HOVER_PEN or SCROLLBAR_BAR_DOWN_LEFT_PEN)
dc:char(nil, hover_bar and SCROLLBAR_BAR_DOWN_RIGHT_HOVER_PEN or SCROLLBAR_BAR_DOWN_RIGHT_PEN)
else
dc:char(nil, hover_bar and SCROLLBAR_BAR_LEFT_HOVER_PEN or SCROLLBAR_BAR_LEFT_PEN)
dc:char(nil, hover_bar and SCROLLBAR_BAR_RIGHT_HOVER_PEN or SCROLLBAR_BAR_RIGHT_PEN)
end
else else
dc:char(BAR_BG_CHAR, self.bg) dc:char(nil, SCROLLBAR_BAR_BG_LEFT_PEN)
dc:char(nil, SCROLLBAR_BAR_BG_RIGHT_PEN)
end end
end end
-- render down arrow if we're not at the bottom -- render down arrow
local last_visible_el = self.top_elem + self.elems_per_page - 1 dc:seek(0, dc.height-1)
dc:seek(0, dc.height-1):char( dc:char(nil, hover_down and SCROLLBAR_DOWN_LEFT_HOVER_PEN or SCROLLBAR_DOWN_LEFT_PEN)
last_visible_el >= self.num_elems and NO_ARROW_CHAR or DOWN_ARROW_CHAR, dc:char(nil, hover_down and SCROLLBAR_DOWN_RIGHT_HOVER_PEN or SCROLLBAR_DOWN_RIGHT_PEN)
self.fg, self.bg)
if not self.on_scroll then return end if not self.on_scroll then return end
-- manage state for dragging and continuous scrolling -- manage state for dragging and continuous scrolling
if self.is_dragging then if self.is_dragging then
@ -877,10 +939,26 @@ function Scrollbar:onRenderBody(dc)
end end
function Scrollbar:onInput(keys) function Scrollbar:onInput(keys)
if not keys._MOUSE_L_DOWN or not self.on_scroll if not self.on_scroll or not scrollbar_is_visible(self) then
or not scrollbar_is_visible(self) then
return false return false
end end
if self.parent_view:getMousePos() then
if keys.CONTEXT_SCROLL_UP then
self.on_scroll('up_small')
return true
elseif keys.CONTEXT_SCROLL_DOWN then
self.on_scroll('down_small')
return true
elseif keys.CONTEXT_SCROLL_PAGEUP then
self.on_scroll('up_large')
return true
elseif keys.CONTEXT_SCROLL_PAGEDOWN then
self.on_scroll('down_large')
return true
end
end
if not keys._MOUSE_L_DOWN then return false end
local _,y = self:getMousePos() local _,y = self:getMousePos()
if not y then return false end if not y then return false end
local scroll_spec = nil local scroll_spec = nil
@ -988,13 +1066,13 @@ function render_text(obj,dc,x0,y0,pen,dpen,disabled)
if token.tile then if token.tile then
x = x + 1 x = x + 1
if dc then if dc then
dc:char(nil, token.tile) dc:tile(nil, token.tile)
end end
end end
if token.text or token.key then if token.text or token.key then
local text = ''..(getval(token.text) or '') local text = ''..(getval(token.text) or '')
local keypen = dfhack.pen.parse(token.key_pen or COLOR_LIGHTGREEN) local keypen = to_pen(token.key_pen or COLOR_LIGHTGREEN)
if dc then if dc then
local tpen = getval(token.pen) local tpen = getval(token.pen)
@ -1027,6 +1105,9 @@ function render_text(obj,dc,x0,y0,pen,dpen,disabled)
end end
if token.key then if token.key then
if type(token.key) == 'string' and not df.interface_key[token.key] then
error('Invalid interface_key: ' .. token.key)
end
local keystr = gui.getKeyDisplay(token.key) local keystr = gui.getKeyDisplay(token.key)
local sep = token.key_sep or '' local sep = token.key_sep or ''
@ -1244,7 +1325,7 @@ end
-- we can't set the text in init() since we may not yet have a frame that we -- we can't set the text in init() since we may not yet have a frame that we
-- can get wrapping bounds from. -- can get wrapping bounds from.
function WrappedLabel:postComputeFrame() function WrappedLabel:postComputeFrame()
local wrapped_text = self:getWrappedText(self.frame_body.width-1) local wrapped_text = self:getWrappedText(self.frame_body.width-3)
if not wrapped_text then return end if not wrapped_text then return end
local text = {} local text = {}
for _,line in ipairs(wrapped_text:split(NEWLINE)) do for _,line in ipairs(wrapped_text:split(NEWLINE)) do
@ -1619,12 +1700,14 @@ end
function List:submit() function List:submit()
if self.on_submit and #self.choices > 0 then if self.on_submit and #self.choices > 0 then
self.on_submit(self:getSelected()) self.on_submit(self:getSelected())
return true
end end
end end
function List:submit2() function List:submit2()
if self.on_submit2 and #self.choices > 0 then if self.on_submit2 and #self.choices > 0 then
self.on_submit2(self:getSelected()) self.on_submit2(self:getSelected())
return true
end end
end end
@ -1632,12 +1715,10 @@ function List:onInput(keys)
if self:inputToSubviews(keys) then if self:inputToSubviews(keys) then
return true return true
end end
if self.on_submit and keys.SELECT then if keys.SELECT then
self:submit() return self:submit()
return true elseif keys.CUSTOM_SHIFT_ENTER then
elseif self.on_submit2 and keys.SEC_SELECT then return self:submit2()
self:submit2()
return true
elseif keys._MOUSE_L_DOWN then elseif keys._MOUSE_L_DOWN then
local idx = self:getIdxUnderMouse() local idx = self:getIdxUnderMouse()
if idx then if idx then

@ -288,11 +288,11 @@ end
function make_own(unit) function make_own(unit)
--tweak makeown --tweak makeown
unit.flags2.resident = false; unit.flags1.merchant = false; unit.flags1.forest = false; unit.flags2.resident = false; unit.flags1.merchant = false; unit.flags1.forest = false;
unit.civ_id = df.global.ui.civ_id unit.civ_id = df.global.plotinfo.civ_id
if unit.profession == df.profession.MERCHANT then unit.profession = df.profession.TRADER end if unit.profession == df.profession.MERCHANT then unit.profession = df.profession.TRADER end
if unit.profession2 == df.profession.MERCHANT then unit.profession2 = df.profession.TRADER end if unit.profession2 == df.profession.MERCHANT then unit.profession2 = df.profession.TRADER end
fix_clothing_ownership(unit) fix_clothing_ownership(unit)
if unit.race == df.global.ui.race_id then if unit.race == df.global.plotinfo.race_id then
make_citizen(unit) make_citizen(unit)
end end
end end

@ -81,14 +81,14 @@ using namespace DFHack;
#include "df/job_item.h" #include "df/job_item.h"
#include "df/map_block.h" #include "df/map_block.h"
#include "df/tile_occupancy.h" #include "df/tile_occupancy.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/ui_look_list.h" #include "df/ui_look_list.h"
#include "df/unit.h" #include "df/unit.h"
#include "df/unit_relationship_type.h" #include "df/unit_relationship_type.h"
#include "df/world.h" #include "df/world.h"
using namespace df::enums; using namespace df::enums;
using df::global::ui; using df::global::plotinfo;
using df::global::world; using df::global::world;
using df::global::d_init; using df::global::d_init;
using df::global::building_next_id; using df::global::building_next_id;
@ -425,7 +425,7 @@ df::building *Buildings::allocInstance(df::coord pos, df::building_type type, in
bld->y1 = bld->y2 = bld->centery = pos.y; bld->y1 = bld->y2 = bld->centery = pos.y;
bld->z = pos.z; bld->z = pos.z;
bld->race = ui->race_id; bld->race = plotinfo->race_id;
if (subtype != -1) if (subtype != -1)
bld->setSubtype(subtype); bld->setSubtype(subtype);
@ -989,7 +989,7 @@ static void linkRooms(df::building *bld)
} }
if (changed) if (changed)
df::global::ui->equipment.update.bits.buildings = true; df::global::plotinfo->equipment.update.bits.buildings = true;
*/ */
} }
@ -1238,7 +1238,7 @@ bool Buildings::constructWithFilters(df::building *bld, std::vector<df::job_item
bool Buildings::deconstruct(df::building *bld) bool Buildings::deconstruct(df::building *bld)
{ {
using df::global::ui; using df::global::plotinfo;
using df::global::world; using df::global::world;
using df::global::ui_look_list; using df::global::ui_look_list;
@ -1263,7 +1263,7 @@ bool Buildings::deconstruct(df::building *bld)
// Assume: no parties. // Assume: no parties.
unlinkRooms(bld); unlinkRooms(bld);
// Assume: not unit destroy target // Assume: not unit destroy target
vector_erase_at(ui->tax_collection.rooms, linear_index(ui->tax_collection.rooms, bld->id)); vector_erase_at(plotinfo->tax_collection.rooms, linear_index(plotinfo->tax_collection.rooms, bld->id));
// Assume: not used in punishment // Assume: not used in punishment
// Assume: not used in non-own jobs // Assume: not used in non-own jobs
// Assume: does not affect pathfinding // Assume: does not affect pathfinding

@ -42,14 +42,14 @@ using namespace std;
#include "df/block_burrow_link.h" #include "df/block_burrow_link.h"
#include "df/burrow.h" #include "df/burrow.h"
#include "df/map_block.h" #include "df/map_block.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/world.h" #include "df/world.h"
using namespace DFHack; using namespace DFHack;
using namespace df::enums; using namespace df::enums;
using df::global::world; using df::global::world;
using df::global::ui; using df::global::plotinfo;
df::burrow *Burrows::findByName(std::string name) df::burrow *Burrows::findByName(std::string name)
{ {
@ -76,15 +76,17 @@ void Burrows::clearUnits(df::burrow *burrow)
burrow->units.clear(); burrow->units.clear();
// Sync ui if active /* TODO: understand how this changes for v50
if (ui && ui->main.mode == ui_sidebar_mode::Burrows && // Sync plotinfo if active
ui->burrows.in_add_units_mode && ui->burrows.sel_id == burrow->id) if (plotinfo && plotinfo->main.mode == ui_sidebar_mode::Burrows &&
plotinfo->burrows.in_add_units_mode && plotinfo->burrows.sel_id == burrow->id)
{ {
auto &sel = ui->burrows.sel_units; auto &sel = plotinfo->burrows.sel_units;
for (size_t i = 0; i < sel.size(); i++) for (size_t i = 0; i < sel.size(); i++)
sel[i] = false; sel[i] = false;
} }
*/
} }
bool Burrows::isAssignedUnit(df::burrow *burrow, df::unit *unit) bool Burrows::isAssignedUnit(df::burrow *burrow, df::unit *unit)
@ -97,7 +99,7 @@ bool Burrows::isAssignedUnit(df::burrow *burrow, df::unit *unit)
void Burrows::setAssignedUnit(df::burrow *burrow, df::unit *unit, bool enable) void Burrows::setAssignedUnit(df::burrow *burrow, df::unit *unit, bool enable)
{ {
using df::global::ui; using df::global::plotinfo;
CHECK_NULL_POINTER(unit); CHECK_NULL_POINTER(unit);
CHECK_NULL_POINTER(burrow); CHECK_NULL_POINTER(burrow);
@ -113,14 +115,16 @@ void Burrows::setAssignedUnit(df::burrow *burrow, df::unit *unit, bool enable)
erase_from_vector(burrow->units, unit->id); erase_from_vector(burrow->units, unit->id);
} }
// Sync ui if active /* TODO: understand how this changes for v50
if (ui && ui->main.mode == ui_sidebar_mode::Burrows && // Sync plotinfo if active
ui->burrows.in_add_units_mode && ui->burrows.sel_id == burrow->id) if (plotinfo && plotinfo->main.mode == ui_sidebar_mode::Burrows &&
plotinfo->burrows.in_add_units_mode && plotinfo->burrows.sel_id == burrow->id)
{ {
int idx = linear_index(ui->burrows.list_units, unit); int idx = linear_index(plotinfo->burrows.list_units, unit);
if (idx >= 0) if (idx >= 0)
ui->burrows.sel_units[idx] = enable; plotinfo->burrows.sel_units[idx] = enable;
} }
*/
} }
void Burrows::listBlocks(std::vector<df::map_block*> *pvec, df::burrow *burrow) void Burrows::listBlocks(std::vector<df::map_block*> *pvec, df::burrow *burrow)

@ -0,0 +1,120 @@
#include "Internal.h"
#include "modules/DFSDL.h"
#include "Debug.h"
#include "PluginManager.h"
namespace DFHack {
DBG_DECLARE(core, dfsdl, DebugCategory::LINFO);
}
using namespace DFHack;
static DFLibrary *g_sdl_handle = nullptr;
static DFLibrary *g_sdl_image_handle = nullptr;
static const std::vector<std::string> SDL_LIBS {
"SDLreal.dll", // TODO: change to SDL.dll once we move to dfhooks
"SDL.framework/Versions/A/SDL",
"SDL.framework/SDL",
"libSDL-1.2.so.0"
};
static const std::vector<std::string> SDL_IMAGE_LIBS {
"SDL_image.dll",
"SDL_image.framework/Versions/A/SDL_image",
"SDL_image.framework/SDL_image",
"libSDL_image-1.2.so.0"
};
DFSDL_Surface * (*g_IMG_Load)(const char *) = nullptr;
int (*g_SDL_SetAlpha)(DFSDL_Surface *, uint32_t, uint8_t) = nullptr;
DFSDL_Surface * (*g_SDL_CreateRGBSurface)(uint32_t, int, int, int, uint32_t, uint32_t, uint32_t, uint32_t);
int (*g_SDL_UpperBlit)(DFSDL_Surface *, const DFSDL_Rect *, DFSDL_Surface *, DFSDL_Rect *);
DFSDL_Surface * (*g_SDL_ConvertSurface)(DFSDL_Surface *, const DFSDL_PixelFormat *, uint32_t);
void (*g_SDL_FreeSurface)(DFSDL_Surface *);
int (*g_SDL_SemWait)(DFSDL_sem *);
int (*g_SDL_SemPost)(DFSDL_sem *);
bool DFSDL::init(color_ostream &out) {
for (auto &lib_str : SDL_LIBS) {
if ((g_sdl_handle = OpenPlugin(lib_str.c_str())))
break;
}
if (!g_sdl_handle) {
out.printerr("DFHack could not find SDL\n");
return false;
}
for (auto &lib_str : SDL_IMAGE_LIBS) {
if ((g_sdl_image_handle = OpenPlugin(lib_str.c_str())))
break;
}
if (!g_sdl_image_handle) {
out.printerr("DFHack could not find SDL_image\n");
return false;
}
#define bind(handle, name) \
g_##name = (decltype(g_##name))LookupPlugin(handle, #name); \
if (!g_##name) { \
out.printerr("DFHack could not find: " #name "\n"); \
return false; \
}
bind(g_sdl_image_handle, IMG_Load);
bind(g_sdl_handle, SDL_SetAlpha);
bind(g_sdl_handle, SDL_CreateRGBSurface);
bind(g_sdl_handle, SDL_UpperBlit);
bind(g_sdl_handle, SDL_ConvertSurface);
bind(g_sdl_handle, SDL_FreeSurface);
bind(g_sdl_handle, SDL_SemWait);
bind(g_sdl_handle, SDL_SemPost);
#undef bind
DEBUG(dfsdl,out).print("sdl successfully loaded\n");
return true;
}
// It's ok to leave NULLs in the raws list (according to usage in g_src)
void DFSDL::cleanup() {
if (g_sdl_handle) {
ClosePlugin(g_sdl_handle);
g_sdl_handle = nullptr;
}
if (g_sdl_image_handle) {
ClosePlugin(g_sdl_image_handle);
g_sdl_image_handle = nullptr;
}
}
DFSDL_Surface * DFSDL::DFIMG_Load(const char *file) {
return g_IMG_Load(file);
}
int DFSDL::DFSDL_SetAlpha(DFSDL_Surface *surface, uint32_t flag, uint8_t alpha) {
return g_SDL_SetAlpha(surface, flag, alpha);
}
DFSDL_Surface * DFSDL::DFSDL_CreateRGBSurface(uint32_t flags, int width, int height, int depth, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask) {
return g_SDL_CreateRGBSurface(flags, width, height, depth, Rmask, Gmask, Bmask, Amask);
}
int DFSDL::DFSDL_UpperBlit(DFSDL_Surface *src, const DFSDL_Rect *srcrect, DFSDL_Surface *dst, DFSDL_Rect *dstrect) {
return g_SDL_UpperBlit(src, srcrect, dst, dstrect);
}
DFSDL_Surface * DFSDL::DFSDL_ConvertSurface(DFSDL_Surface *src, const DFSDL_PixelFormat *fmt, uint32_t flags) {
return g_SDL_ConvertSurface(src, fmt, flags);
}
void DFSDL::DFSDL_FreeSurface(DFSDL_Surface *surface) {
g_SDL_FreeSurface(surface);
}
int DFSDL::DFSDL_SemWait(DFSDL_sem *sem) {
return g_SDL_SemWait(sem);
}
int DFSDL::DFSDL_SemPost(DFSDL_sem *sem) {
return g_SDL_SemPost(sem);
}

@ -1,5 +1,6 @@
#include "Core.h" #include "Core.h"
#include "Console.h" #include "Console.h"
#include "Debug.h"
#include "VTableInterpose.h" #include "VTableInterpose.h"
#include "modules/Buildings.h" #include "modules/Buildings.h"
#include "modules/Constructions.h" #include "modules/Constructions.h"
@ -26,7 +27,7 @@
#include "df/job.h" #include "df/job.h"
#include "df/job_list_link.h" #include "df/job_list_link.h"
#include "df/report.h" #include "df/report.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/unit.h" #include "df/unit.h"
#include "df/unit_flags1.h" #include "df/unit_flags1.h"
#include "df/unit_inventory_item.h" #include "df/unit_inventory_item.h"
@ -43,6 +44,10 @@
#include <unordered_set> #include <unordered_set>
#include <array> #include <array>
namespace DFHack {
DBG_DECLARE(eventmanager, log, DebugCategory::LINFO);
}
using namespace std; using namespace std;
using namespace DFHack; using namespace DFHack;
using namespace EventManager; using namespace EventManager;
@ -63,6 +68,7 @@ static int32_t eventLastTick[EventType::EVENT_MAX];
static const int32_t ticksPerYear = 403200; static const int32_t ticksPerYear = 403200;
void DFHack::EventManager::registerListener(EventType::EventType e, EventHandler handler, Plugin* plugin) { void DFHack::EventManager::registerListener(EventType::EventType e, EventHandler handler, Plugin* plugin) {
DEBUG(log).print("registering handler %p from plugin %s for event %d\n", handler.eventHandler, plugin->getName().c_str(), e);
handlers[e].insert(pair<Plugin*, EventHandler>(plugin, handler)); handlers[e].insert(pair<Plugin*, EventHandler>(plugin, handler));
} }
@ -78,6 +84,7 @@ int32_t DFHack::EventManager::registerTick(EventHandler handler, int32_t when, P
} }
handler.freq = when; handler.freq = when;
tickQueue.insert(pair<int32_t, EventHandler>(handler.freq, handler)); tickQueue.insert(pair<int32_t, EventHandler>(handler.freq, handler));
DEBUG(log).print("registering handler %p from plugin %s for event TICK\n", handler.eventHandler, plugin->getName().c_str());
handlers[EventType::TICK].insert(pair<Plugin*,EventHandler>(plugin,handler)); handlers[EventType::TICK].insert(pair<Plugin*,EventHandler>(plugin,handler));
return when; return when;
} }
@ -103,6 +110,7 @@ void DFHack::EventManager::unregister(EventType::EventType e, EventHandler handl
i++; i++;
continue; continue;
} }
DEBUG(log).print("unregistering handler %p from plugin %s for event %d\n", handler.eventHandler, plugin->getName().c_str(), e);
i = handlers[e].erase(i); i = handlers[e].erase(i);
if ( e == EventType::TICK ) if ( e == EventType::TICK )
removeFromTickQueue(handler); removeFromTickQueue(handler);
@ -110,6 +118,7 @@ void DFHack::EventManager::unregister(EventType::EventType e, EventHandler handl
} }
void DFHack::EventManager::unregisterAll(Plugin* plugin) { void DFHack::EventManager::unregisterAll(Plugin* plugin) {
DEBUG(log).print("unregistering all handlers for plugin %s\n", plugin->getName().c_str());
for ( auto i = handlers[EventType::TICK].find(plugin); i != handlers[EventType::TICK].end(); i++ ) { for ( auto i = handlers[EventType::TICK].find(plugin); i != handlers[EventType::TICK].end(); i++ ) {
if ( (*i).first != plugin ) if ( (*i).first != plugin )
break; break;
@ -268,6 +277,7 @@ void DFHack::EventManager::onStateChange(color_ostream& out, state_change_event
multimap<Plugin*,EventHandler> copy(handlers[EventType::UNLOAD].begin(), handlers[EventType::UNLOAD].end()); multimap<Plugin*,EventHandler> copy(handlers[EventType::UNLOAD].begin(), handlers[EventType::UNLOAD].end());
for (auto &key_value : copy) { for (auto &key_value : copy) {
DEBUG(log,out).print("calling handler for map unloaded state change event\n");
key_value.second.eventHandler(out, nullptr); key_value.second.eventHandler(out, nullptr);
} }
} else if ( event == DFHack::SC_MAP_LOADED ) { } else if ( event == DFHack::SC_MAP_LOADED ) {
@ -287,14 +297,14 @@ void DFHack::EventManager::onStateChange(color_ostream& out, state_change_event
return; return;
if (!df::global::job_next_id) if (!df::global::job_next_id)
return; return;
if (!df::global::ui) if (!df::global::plotinfo)
return; return;
if (!df::global::world) if (!df::global::world)
return; return;
nextItem = *df::global::item_next_id; nextItem = *df::global::item_next_id;
nextBuilding = *df::global::building_next_id; nextBuilding = *df::global::building_next_id;
nextInvasion = df::global::ui->invasions.next_id; nextInvasion = df::global::plotinfo->invasions.next_id;
lastJobId = -1 + *df::global::job_next_id; lastJobId = -1 + *df::global::job_next_id;
constructions.clear(); constructions.clear();
@ -358,6 +368,7 @@ void DFHack::EventManager::manageEvents(color_ostream& out) {
CoreSuspender suspender; CoreSuspender suspender;
int32_t tick = df::global::world->frame_counter; int32_t tick = df::global::world->frame_counter;
TRACE(log,out).print("processing events at tick %d\n", tick);
for ( size_t a = 0; a < EventType::EVENT_MAX; a++ ) { for ( size_t a = 0; a < EventType::EVENT_MAX; a++ ) {
if ( handlers[a].empty() ) if ( handlers[a].empty() )
@ -389,6 +400,7 @@ static void manageTickEvent(color_ostream& out) {
break; break;
EventHandler &handle = (*tickQueue.begin()).second; EventHandler &handle = (*tickQueue.begin()).second;
tickQueue.erase(tickQueue.begin()); tickQueue.erase(tickQueue.begin());
DEBUG(log,out).print("calling handler for tick event\n");
handle.eventHandler(out, (void*)intptr_t(tick)); handle.eventHandler(out, (void*)intptr_t(tick));
toRemove.insert(handle); toRemove.insert(handle);
} }
@ -429,6 +441,7 @@ static void manageJobInitiatedEvent(color_ostream& out) {
continue; continue;
for (auto &key_value : copy) { for (auto &key_value : copy) {
EventHandler &handle = key_value.second; EventHandler &handle = key_value.second;
DEBUG(log,out).print("calling handler for job initiated event\n");
handle.eventHandler(out, (void*)link->item); handle.eventHandler(out, (void*)link->item);
} }
} }
@ -451,6 +464,7 @@ static void manageJobStartedEvent(color_ostream& out) {
for (auto &key_value : copy) { for (auto &key_value : copy) {
auto &handler = key_value.second; auto &handler = key_value.second;
// the jobs must have a worker to start // the jobs must have a worker to start
DEBUG(log,out).print("calling handler for job started event\n");
handler.eventHandler(out, job); handler.eventHandler(out, job);
} }
} }
@ -561,6 +575,7 @@ static void manageJobCompletedEvent(color_ostream& out) {
//still false positive if cancelled at EXACTLY the right time, but experiments show this doesn't happen //still false positive if cancelled at EXACTLY the right time, but experiments show this doesn't happen
for (auto &key_value : copy) { for (auto &key_value : copy) {
EventHandler &handle = key_value.second; EventHandler &handle = key_value.second;
DEBUG(log,out).print("calling handler for repeated job completed event\n");
handle.eventHandler(out, (void*)&job0); handle.eventHandler(out, (void*)&job0);
} }
continue; continue;
@ -573,6 +588,7 @@ static void manageJobCompletedEvent(color_ostream& out) {
for (auto &key_value : copy) { for (auto &key_value : copy) {
EventHandler &handle = key_value.second; EventHandler &handle = key_value.second;
DEBUG(log,out).print("calling handler for job completed event\n");
handle.eventHandler(out, (void*)&job0); handle.eventHandler(out, (void*)&job0);
} }
} }
@ -607,6 +623,7 @@ static void manageNewUnitActiveEvent(color_ostream& out) {
int32_t id = unit->id; int32_t id = unit->id;
if (!activeUnits.count(id)) { if (!activeUnits.count(id)) {
activeUnits.emplace(id); activeUnits.emplace(id);
DEBUG(log,out).print("calling handler for new unit event\n");
handler.eventHandler(out, (void*) intptr_t(id)); // intptr_t() avoids cast from smaller type warning handler.eventHandler(out, (void*) intptr_t(id)); // intptr_t() avoids cast from smaller type warning
} }
} }
@ -630,6 +647,7 @@ static void manageUnitDeathEvent(color_ostream& out) {
for (auto &key_value : copy) { for (auto &key_value : copy) {
EventHandler &handle = key_value.second; EventHandler &handle = key_value.second;
DEBUG(log,out).print("calling handler for unit death event\n");
handle.eventHandler(out, (void*)intptr_t(unit->id)); handle.eventHandler(out, (void*)intptr_t(unit->id));
} }
livingUnits.erase(unit->id); livingUnits.erase(unit->id);
@ -667,6 +685,7 @@ static void manageItemCreationEvent(color_ostream& out) {
continue; continue;
for (auto &key_value : copy) { for (auto &key_value : copy) {
EventHandler &handle = key_value.second; EventHandler &handle = key_value.second;
DEBUG(log,out).print("calling handler for item created event\n");
handle.eventHandler(out, (void*)intptr_t(item->id)); handle.eventHandler(out, (void*)intptr_t(item->id));
} }
} }
@ -694,6 +713,7 @@ static void manageBuildingEvent(color_ostream& out) {
buildings.insert(a); buildings.insert(a);
for (auto &key_value : copy) { for (auto &key_value : copy) {
EventHandler &handle = key_value.second; EventHandler &handle = key_value.second;
DEBUG(log,out).print("calling handler for created building event\n");
handle.eventHandler(out, (void*)intptr_t(a)); handle.eventHandler(out, (void*)intptr_t(a));
} }
} }
@ -710,6 +730,7 @@ static void manageBuildingEvent(color_ostream& out) {
for (auto &key_value : copy) { for (auto &key_value : copy) {
EventHandler &handle = key_value.second; EventHandler &handle = key_value.second;
DEBUG(log,out).print("calling handler for destroyed building event\n");
handle.eventHandler(out, (void*)intptr_t(id)); handle.eventHandler(out, (void*)intptr_t(id));
} }
a = buildings.erase(a); a = buildings.erase(a);
@ -733,6 +754,7 @@ static void manageConstructionEvent(color_ostream& out) {
// send construction to handlers, because it was removed // send construction to handlers, because it was removed
for (const auto &key_value: copy) { for (const auto &key_value: copy) {
EventHandler handle = key_value.second; EventHandler handle = key_value.second;
DEBUG(log,out).print("calling handler for destroyed construction event\n");
handle.eventHandler(out, (void*) &construction); handle.eventHandler(out, (void*) &construction);
} }
// erase from existent constructions // erase from existent constructions
@ -747,6 +769,7 @@ static void manageConstructionEvent(color_ostream& out) {
// send construction to handlers, because it is new // send construction to handlers, because it is new
for (const auto &key_value: copy) { for (const auto &key_value: copy) {
EventHandler handle = key_value.second; EventHandler handle = key_value.second;
DEBUG(log,out).print("calling handler for created construction event\n");
handle.eventHandler(out, (void*) &construction); handle.eventHandler(out, (void*) &construction);
} }
} }
@ -775,6 +798,7 @@ static void manageSyndromeEvent(color_ostream& out) {
SyndromeData data(unit->id, b); SyndromeData data(unit->id, b);
for (auto &key_value : copy) { for (auto &key_value : copy) {
EventHandler &handle = key_value.second; EventHandler &handle = key_value.second;
DEBUG(log,out).print("calling handler for syndrome event\n");
handle.eventHandler(out, (void*)&data); handle.eventHandler(out, (void*)&data);
} }
} }
@ -783,16 +807,17 @@ static void manageSyndromeEvent(color_ostream& out) {
} }
static void manageInvasionEvent(color_ostream& out) { static void manageInvasionEvent(color_ostream& out) {
if (!df::global::ui) if (!df::global::plotinfo)
return; return;
multimap<Plugin*,EventHandler> copy(handlers[EventType::INVASION].begin(), handlers[EventType::INVASION].end()); multimap<Plugin*,EventHandler> copy(handlers[EventType::INVASION].begin(), handlers[EventType::INVASION].end());
if ( df::global::ui->invasions.next_id <= nextInvasion ) if ( df::global::plotinfo->invasions.next_id <= nextInvasion )
return; return;
nextInvasion = df::global::ui->invasions.next_id; nextInvasion = df::global::plotinfo->invasions.next_id;
for (auto &key_value : copy) { for (auto &key_value : copy) {
EventHandler &handle = key_value.second; EventHandler &handle = key_value.second;
DEBUG(log,out).print("calling handler for invasion event\n");
handle.eventHandler(out, (void*)intptr_t(nextInvasion-1)); handle.eventHandler(out, (void*)intptr_t(nextInvasion-1));
} }
} }
@ -834,6 +859,7 @@ static void manageEquipmentEvent(color_ostream& out) {
InventoryChangeData data(unit->id, nullptr, &item_new); InventoryChangeData data(unit->id, nullptr, &item_new);
for (auto &key_value : copy) { for (auto &key_value : copy) {
EventHandler &handle = key_value.second; EventHandler &handle = key_value.second;
DEBUG(log,out).print("calling handler for new item equipped inventory change event\n");
handle.eventHandler(out, (void*)&data); handle.eventHandler(out, (void*)&data);
} }
continue; continue;
@ -849,6 +875,7 @@ static void manageEquipmentEvent(color_ostream& out) {
InventoryChangeData data(unit->id, &item_old, &item_new); InventoryChangeData data(unit->id, &item_old, &item_new);
for (auto &key_value : copy) { for (auto &key_value : copy) {
EventHandler &handle = key_value.second; EventHandler &handle = key_value.second;
DEBUG(log,out).print("calling handler for inventory change event\n");
handle.eventHandler(out, (void*)&data); handle.eventHandler(out, (void*)&data);
} }
} }
@ -860,6 +887,7 @@ static void manageEquipmentEvent(color_ostream& out) {
InventoryChangeData data(unit->id, &i, nullptr); InventoryChangeData data(unit->id, &i, nullptr);
for (auto &key_value : copy) { for (auto &key_value : copy) {
EventHandler &handle = key_value.second; EventHandler &handle = key_value.second;
DEBUG(log,out).print("calling handler for dropped item inventory change event\n");
handle.eventHandler(out, (void*)&data); handle.eventHandler(out, (void*)&data);
} }
} }
@ -913,6 +941,7 @@ static void manageReportEvent(color_ostream& out) {
df::report* report = reports[idx]; df::report* report = reports[idx];
for (auto &key_value : copy) { for (auto &key_value : copy) {
EventHandler &handle = key_value.second; EventHandler &handle = key_value.second;
DEBUG(log,out).print("calling handler for report event\n");
handle.eventHandler(out, (void*)intptr_t(report->id)); handle.eventHandler(out, (void*)intptr_t(report->id));
} }
lastReport = report->id; lastReport = report->id;
@ -990,6 +1019,7 @@ static void manageUnitAttackEvent(color_ostream& out) {
alreadyDone[data.attacker][data.defender] = 1; alreadyDone[data.attacker][data.defender] = 1;
for (auto &key_value : copy) { for (auto &key_value : copy) {
EventHandler &handle = key_value.second; EventHandler &handle = key_value.second;
DEBUG(log,out).print("calling handler for unit1 attack unit attack event\n");
handle.eventHandler(out, (void*)&data); handle.eventHandler(out, (void*)&data);
} }
} }
@ -1002,6 +1032,7 @@ static void manageUnitAttackEvent(color_ostream& out) {
alreadyDone[data.attacker][data.defender] = 1; alreadyDone[data.attacker][data.defender] = 1;
for (auto &key_value : copy) { for (auto &key_value : copy) {
EventHandler &handle = key_value.second; EventHandler &handle = key_value.second;
DEBUG(log,out).print("calling handler for unit2 attack unit attack event\n");
handle.eventHandler(out, (void*)&data); handle.eventHandler(out, (void*)&data);
} }
} }
@ -1013,6 +1044,7 @@ static void manageUnitAttackEvent(color_ostream& out) {
alreadyDone[data.attacker][data.defender] = 1; alreadyDone[data.attacker][data.defender] = 1;
for (auto &key_value : copy) { for (auto &key_value : copy) {
EventHandler &handle = key_value.second; EventHandler &handle = key_value.second;
DEBUG(log,out).print("calling handler for unit1 killed unit attack event\n");
handle.eventHandler(out, (void*)&data); handle.eventHandler(out, (void*)&data);
} }
} }
@ -1024,6 +1056,7 @@ static void manageUnitAttackEvent(color_ostream& out) {
alreadyDone[data.attacker][data.defender] = 1; alreadyDone[data.attacker][data.defender] = 1;
for (auto &key_value : copy) { for (auto &key_value : copy) {
EventHandler &handle = key_value.second; EventHandler &handle = key_value.second;
DEBUG(log,out).print("calling handler for unit2 killed unit attack event\n");
handle.eventHandler(out, (void*)&data); handle.eventHandler(out, (void*)&data);
} }
} }
@ -1282,6 +1315,7 @@ static void manageInteractionEvent(color_ostream& out) {
//fire event //fire event
for (auto &key_value : copy) { for (auto &key_value : copy) {
EventHandler &handle = key_value.second; EventHandler &handle = key_value.second;
DEBUG(log,out).print("calling handler for interaction event\n");
handle.eventHandler(out, (void*)&data); handle.eventHandler(out, (void*)&data);
} }
//TODO: deduce attacker from latest defend event first //TODO: deduce attacker from latest defend event first

@ -61,12 +61,12 @@ using namespace DFHack;
#include "df/general_ref.h" #include "df/general_ref.h"
#include "df/global_objects.h" #include "df/global_objects.h"
#include "df/graphic.h" #include "df/graphic.h"
#include "df/graphic_viewportst.h"
#include "df/historical_figure.h" #include "df/historical_figure.h"
#include "df/interfacest.h" #include "df/interfacest.h"
#include "df/item_corpsepiecest.h" #include "df/item_corpsepiecest.h"
#include "df/item_corpsest.h" #include "df/item_corpsest.h"
#include "df/job.h" #include "df/job.h"
#include "df/layer_object_listst.h"
#include "df/occupation.h" #include "df/occupation.h"
#include "df/plant.h" #include "df/plant.h"
#include "df/popup_message.h" #include "df/popup_message.h"
@ -74,10 +74,10 @@ using namespace DFHack;
#include "df/report_zoom_type.h" #include "df/report_zoom_type.h"
#include "df/route_stockpile_link.h" #include "df/route_stockpile_link.h"
#include "df/stop_depart_condition.h" #include "df/stop_depart_condition.h"
#include "df/ui_advmode.h" #include "df/adventurest.h"
#include "df/ui_build_selector.h" #include "df/buildreq.h"
#include "df/ui_look_list.h" #include "df/ui_look_list.h"
#include "df/ui_sidebar_menus.h" #include "df/gamest.h"
#include "df/ui_unit_view_mode.h" #include "df/ui_unit_view_mode.h"
#include "df/unit.h" #include "df/unit.h"
#include "df/unit_inventory_item.h" #include "df/unit_inventory_item.h"
@ -101,9 +101,9 @@ using df::global::gps;
using df::global::gview; using df::global::gview;
using df::global::init; using df::global::init;
using df::global::selection_rect; using df::global::selection_rect;
using df::global::ui; using df::global::plotinfo;
using df::global::ui_menu_width; using df::global::ui_menu_width;
using df::global::ui_sidebar_menus; using df::global::game;
using df::global::world; using df::global::world;
/* TODO: understand how this changes for v50 /* TODO: understand how this changes for v50
@ -143,6 +143,7 @@ static std::map<virtual_identity*, getFocusStringHandler> getFocusStringHandlers
DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode)
{ {
/* TODO: understand how this changes for v50
using namespace df::enums::ui_sidebar_mode; using namespace df::enums::ui_sidebar_mode;
using df::global::ui_workshop_in_add; using df::global::ui_workshop_in_add;
@ -157,9 +158,9 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode)
using df::global::ui_building_assign_items; using df::global::ui_building_assign_items;
using df::global::ui_building_in_assign; using df::global::ui_building_in_assign;
focus += "/" + enum_item_key(ui->main.mode); focus += "/" + enum_item_key(plotinfo->main.mode);
switch (ui->main.mode) switch (plotinfo->main.mode)
{ {
case QueryBuilding: case QueryBuilding:
if (df::building *selected = world->selected_building) if (df::building *selected = world->selected_building)
@ -303,39 +304,38 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode)
break; break;
case Burrows: case Burrows:
if (ui->burrows.in_confirm_delete) if (plotinfo->burrows.in_confirm_delete)
focus += "/ConfirmDelete"; focus += "/ConfirmDelete";
else if (ui->burrows.in_add_units_mode) else if (plotinfo->burrows.in_add_units_mode)
focus += "/AddUnits"; focus += "/AddUnits";
else if (ui->burrows.in_edit_name_mode) else if (plotinfo->burrows.in_edit_name_mode)
focus += "/EditName"; focus += "/EditName";
else if (ui->burrows.in_define_mode) else if (plotinfo->burrows.in_define_mode)
focus += "/Define"; focus += "/Define";
else else
focus += "/List"; focus += "/List";
break; break;
/* TODO: understand how this changes for v50
case Hauling: case Hauling:
if (ui->hauling.in_assign_vehicle) if (plotinfo->hauling.in_assign_vehicle)
{ {
auto vehicle = vector_get(ui->hauling.vehicles, ui->hauling.cursor_vehicle); auto vehicle = vector_get(plotinfo->hauling.vehicles, plotinfo->hauling.cursor_vehicle);
focus += "/AssignVehicle/" + std::string(vehicle ? "Some" : "None"); focus += "/AssignVehicle/" + std::string(vehicle ? "Some" : "None");
} }
else else
{ {
int idx = ui->hauling.cursor_top; int idx = plotinfo->hauling.cursor_top;
auto route = vector_get(ui->hauling.view_routes, idx); auto route = vector_get(plotinfo->hauling.view_routes, idx);
auto stop = vector_get(ui->hauling.view_stops, idx); auto stop = vector_get(plotinfo->hauling.view_stops, idx);
std::string tag = stop ? "Stop" : (route ? "Route" : "None"); std::string tag = stop ? "Stop" : (route ? "Route" : "None");
if (ui->hauling.in_name) if (plotinfo->hauling.in_name)
focus += "/Rename/" + tag; focus += "/Rename/" + tag;
else if (ui->hauling.in_stop) else if (plotinfo->hauling.in_stop)
{ {
int sidx = ui->hauling.cursor_stop; int sidx = plotinfo->hauling.cursor_stop;
auto cond = vector_get(ui->hauling.stop_conditions, sidx); auto cond = vector_get(plotinfo->hauling.stop_conditions, sidx);
auto link = vector_get(ui->hauling.stop_links, sidx); auto link = vector_get(plotinfo->hauling.stop_links, sidx);
focus += "/DefineStop"; focus += "/DefineStop";
@ -354,22 +354,22 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode)
focus += "/Select/" + tag; focus += "/Select/" + tag;
} }
break; break;
*/
default: default:
break; break;
} }
*/
} }
/* TODO: understand how this changes for v50 /* TODO: understand how this changes for v50
DEFINE_GET_FOCUS_STRING_HANDLER(dungeonmode) DEFINE_GET_FOCUS_STRING_HANDLER(dungeonmode)
{ {
using df::global::ui_advmode; using df::global::adventure;
if (!ui_advmode) if (!adventure)
return; return;
focus += "/" + enum_item_key(ui_advmode->menu); focus += "/" + enum_item_key(adventure->menu);
} }
DEFINE_GET_FOCUS_STRING_HANDLER(unitlist) DEFINE_GET_FOCUS_STRING_HANDLER(unitlist)
@ -667,14 +667,15 @@ bool Gui::cursor_hotkey(df::viewscreen *top)
bool Gui::workshop_job_hotkey(df::viewscreen *top) bool Gui::workshop_job_hotkey(df::viewscreen *top)
{ {
if (!dwarfmode_hotkey(top))
return false;
/* TODO: understand how this changes for v50
using namespace ui_sidebar_mode; using namespace ui_sidebar_mode;
using df::global::ui_workshop_in_add; using df::global::ui_workshop_in_add;
using df::global::ui_workshop_job_cursor; using df::global::ui_workshop_job_cursor;
if (!dwarfmode_hotkey(top)) switch (plotinfo->main.mode) {
return false;
switch (ui->main.mode) {
case QueryBuilding: case QueryBuilding:
{ {
if (!ui_workshop_job_cursor) // allow missing if (!ui_workshop_job_cursor) // allow missing
@ -699,17 +700,19 @@ bool Gui::workshop_job_hotkey(df::viewscreen *top)
default: default:
return false; return false;
} }
*/ return false;
} }
bool Gui::build_selector_hotkey(df::viewscreen *top) bool Gui::build_selector_hotkey(df::viewscreen *top)
{ {
using namespace ui_sidebar_mode;
using df::global::ui_build_selector;
if (!dwarfmode_hotkey(top)) if (!dwarfmode_hotkey(top))
return false; return false;
switch (ui->main.mode) { /* TODO: understand how this changes for v50
using namespace ui_sidebar_mode;
using df::global::ui_build_selector;
switch (plotinfo->main.mode) {
case Build: case Build:
{ {
if (!ui_build_selector) // allow missing if (!ui_build_selector) // allow missing
@ -726,20 +729,23 @@ bool Gui::build_selector_hotkey(df::viewscreen *top)
default: default:
return false; return false;
} }
*/ return false;
} }
bool Gui::view_unit_hotkey(df::viewscreen *top) bool Gui::view_unit_hotkey(df::viewscreen *top)
{ {
using df::global::ui_selected_unit;
if (!dwarfmode_hotkey(top)) if (!dwarfmode_hotkey(top))
return false; return false;
if (ui->main.mode != ui_sidebar_mode::ViewUnits) /* TODO: understand how this changes for v50
using df::global::ui_selected_unit;
if (plotinfo->main.mode != ui_sidebar_mode::ViewUnits)
return false; return false;
if (!ui_selected_unit) // allow missing if (!ui_selected_unit) // allow missing
return false; return false;
return vector_get(world->units.active, *ui_selected_unit) != NULL; return vector_get(world->units.active, *ui_selected_unit) != NULL;
*/ return false;
} }
bool Gui::unit_inventory_hotkey(df::viewscreen *top) bool Gui::unit_inventory_hotkey(df::viewscreen *top)
@ -826,6 +832,7 @@ df::job *Gui::getSelectedJob(color_ostream &out, bool quiet)
df::unit *Gui::getAnyUnit(df::viewscreen *top) df::unit *Gui::getAnyUnit(df::viewscreen *top)
{ {
/* TODO: understand how this changes for v50
using namespace ui_sidebar_mode; using namespace ui_sidebar_mode;
using df::global::ui_look_cursor; using df::global::ui_look_cursor;
using df::global::ui_look_list; using df::global::ui_look_list;
@ -834,7 +841,6 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top)
using df::global::ui_building_assign_units; using df::global::ui_building_assign_units;
using df::global::ui_building_item_cursor; using df::global::ui_building_item_cursor;
/* TODO: understand how this changes for v50
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_unitst, top)) if (VIRTUAL_CAST_VAR(screen, df::viewscreen_unitst, top))
{ {
return screen->unit; return screen->unit;
@ -1011,19 +1017,19 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top)
if (!Gui::dwarfmode_hotkey(top)) if (!Gui::dwarfmode_hotkey(top))
return NULL; return NULL;
if (!ui) if (!plotinfo)
return NULL; return NULL;
// general assigning units in building, i.e. (q)uery cage -> (a)ssign // general assigning units in building, i.e. (q)uery cage -> (a)ssign
if (ui_building_in_assign && *ui_building_in_assign if (ui_building_in_assign && *ui_building_in_assign
&& ui_building_assign_units && ui_building_item_cursor && ui_building_assign_units && ui_building_item_cursor
&& ui->main.mode != Zones) // dont show for (i) zone && plotinfo->main.mode != Zones) // dont show for (i) zone
return vector_get(*ui_building_assign_units, *ui_building_item_cursor); return vector_get(*ui_building_assign_units, *ui_building_item_cursor);
if (ui->follow_unit != -1) if (plotinfo->follow_unit != -1)
return df::unit::find(ui->follow_unit); return df::unit::find(plotinfo->follow_unit);
switch (ui->main.mode) { switch (plotinfo->main.mode) {
case ViewUnits: case ViewUnits:
{ {
if (!ui_selected_unit || !world) if (!ui_selected_unit || !world)
@ -1041,8 +1047,8 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top)
} }
case Burrows: case Burrows:
{ {
if (ui->burrows.in_add_units_mode) if (plotinfo->burrows.in_add_units_mode)
return vector_get(ui->burrows.list_units, ui->burrows.unit_cursor_pos); return vector_get(plotinfo->burrows.list_units, plotinfo->burrows.unit_cursor_pos);
return NULL; return NULL;
} }
@ -1108,13 +1114,13 @@ df::unit *Gui::getSelectedUnit(color_ostream &out, bool quiet)
df::item *Gui::getAnyItem(df::viewscreen *top) df::item *Gui::getAnyItem(df::viewscreen *top)
{ {
/* TODO: understand how this changes for v50
using namespace ui_sidebar_mode; using namespace ui_sidebar_mode;
using df::global::ui_look_cursor; using df::global::ui_look_cursor;
using df::global::ui_look_list; using df::global::ui_look_list;
using df::global::ui_unit_view_mode; using df::global::ui_unit_view_mode;
using df::global::ui_building_item_cursor; using df::global::ui_building_item_cursor;
/* TODO: understand how this changes for v50
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_textviewerst, top)) if (VIRTUAL_CAST_VAR(screen, df::viewscreen_textviewerst, top))
{ {
// return the main item if the parent screen is a viewscreen_itemst // return the main item if the parent screen is a viewscreen_itemst
@ -1190,16 +1196,16 @@ df::item *Gui::getAnyItem(df::viewscreen *top)
if (!Gui::dwarfmode_hotkey(top)) if (!Gui::dwarfmode_hotkey(top))
return NULL; return NULL;
switch (ui->main.mode) { switch (plotinfo->main.mode) {
case ViewUnits: case ViewUnits:
{ {
if (!ui_unit_view_mode || !ui_look_cursor || !ui_sidebar_menus) if (!ui_unit_view_mode || !ui_look_cursor || !game)
return NULL; return NULL;
if (ui_unit_view_mode->value != df::ui_unit_view_mode::Inventory) if (ui_unit_view_mode->value != df::ui_unit_view_mode::Inventory)
return NULL; return NULL;
auto inv_item = vector_get(ui_sidebar_menus->unit.inv_items, *ui_look_cursor); auto inv_item = vector_get(game->unit.inv_items, *ui_look_cursor);
return inv_item ? inv_item->item : NULL; return inv_item ? inv_item->item : NULL;
} }
case LookAround: case LookAround:
@ -1248,11 +1254,11 @@ df::item *Gui::getSelectedItem(color_ostream &out, bool quiet)
df::building *Gui::getAnyBuilding(df::viewscreen *top) df::building *Gui::getAnyBuilding(df::viewscreen *top)
{ {
/* TODO: understand how this changes for v50
using namespace ui_sidebar_mode; using namespace ui_sidebar_mode;
using df::global::ui_look_list; using df::global::ui_look_list;
using df::global::ui_look_cursor; using df::global::ui_look_cursor;
/* TODO: understand how this changes for v50
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_buildinglistst, top)) if (VIRTUAL_CAST_VAR(screen, df::viewscreen_buildinglistst, top))
return vector_get(screen->buildings, screen->cursor); return vector_get(screen->buildings, screen->cursor);
@ -1265,7 +1271,7 @@ df::building *Gui::getAnyBuilding(df::viewscreen *top)
if (!Gui::dwarfmode_hotkey(top)) if (!Gui::dwarfmode_hotkey(top))
return NULL; return NULL;
switch (ui->main.mode) { switch (plotinfo->main.mode) {
case LookAround: case LookAround:
{ {
if (!ui_look_list || !ui_look_cursor) if (!ui_look_list || !ui_look_cursor)
@ -1287,8 +1293,8 @@ df::building *Gui::getAnyBuilding(df::viewscreen *top)
case ZonesPitInfo: case ZonesPitInfo:
case ZonesHospitalInfo: case ZonesHospitalInfo:
{ {
if (ui_sidebar_menus) if (game)
return ui_sidebar_menus->zone.selected; return game->zone.selected;
return NULL; return NULL;
} }
default: default:
@ -1321,13 +1327,15 @@ df::plant *Gui::getAnyPlant(df::viewscreen *top)
if (Gui::dwarfmode_hotkey(top)) if (Gui::dwarfmode_hotkey(top))
{ {
if (!cursor || !ui || !world) if (!cursor || !plotinfo || !world)
return nullptr; return nullptr;
if (ui->main.mode == ui_sidebar_mode::LookAround) /* TODO: understand how this changes for v50
if (plotinfo->main.mode == ui_sidebar_mode::LookAround)
{ {
return Maps::getPlantAtTile(cursor->x, cursor->y, cursor->z); return Maps::getPlantAtTile(cursor->x, cursor->y, cursor->z);
} }
*/
} }
return nullptr; return nullptr;
@ -1865,6 +1873,12 @@ bool Gui::autoDFAnnouncement(df::announcement_type type, df::coord pos, std::str
return autoDFAnnouncement(r, message); return autoDFAnnouncement(r, message);
} }
static df::viewscreen * do_skip_dismissed(df::viewscreen * ws) {
while (ws && Screen::isDismissed(ws) && ws->parent)
ws = ws->parent;
return ws;
}
df::viewscreen *Gui::getCurViewscreen(bool skip_dismissed) df::viewscreen *Gui::getCurViewscreen(bool skip_dismissed)
{ {
if (!gview) if (!gview)
@ -1875,10 +1889,7 @@ df::viewscreen *Gui::getCurViewscreen(bool skip_dismissed)
ws = ws->child; ws = ws->child;
if (skip_dismissed) if (skip_dismissed)
{ ws = do_skip_dismissed(ws);
while (ws && Screen::isDismissed(ws) && ws->parent)
ws = ws->parent;
}
return ws; return ws;
} }
@ -1898,6 +1909,16 @@ df::viewscreen *Gui::getViewscreenByIdentity (virtual_identity &id, int n)
return NULL; return NULL;
} }
df::viewscreen *Gui::getDFViewscreen(bool skip_dismissed) {
df::viewscreen *screen = Gui::getCurViewscreen(skip_dismissed);
while (screen && dfhack_viewscreen::is_instance(screen)) {
screen = screen->parent;
if (skip_dismissed)
screen = do_skip_dismissed(screen);
}
return screen;
}
df::coord Gui::getViewportPos() df::coord Gui::getViewportPos()
{ {
if (!df::global::window_x || !df::global::window_y || !df::global::window_z) if (!df::global::window_x || !df::global::window_y || !df::global::window_z)
@ -1919,47 +1940,14 @@ Gui::DwarfmodeDims getDwarfmodeViewDims_default()
{ {
Gui::DwarfmodeDims dims; Gui::DwarfmodeDims dims;
auto ws = Screen::getWindowSize(); bool use_graphics = Screen::inGraphicsMode();
dims.y1 = 1; auto dimx = use_graphics ? gps->main_viewport->dim_x : gps->dimx;
dims.y2 = ws.y-2; auto dimy = use_graphics ? gps->main_viewport->dim_y : gps->dimy;
dims.map_x1 = 1;
dims.map_x2 = ws.x-2;
dims.map_y1 = dims.y1;
dims.map_y2 = dims.y2;
dims.area_x1 = dims.area_x2 = dims.menu_x1 = dims.menu_x2 = -1;
dims.menu_forced = false;
int menu_pos = (ui_menu_width ? (*ui_menu_width)[0] : 2); dims.map_x1 = 0;
int area_pos = (ui_menu_width ? (*ui_menu_width)[1] : 3); dims.map_x2 = dimx - 1;
dims.map_y1 = 0;
if (ui && ui->main.mode != ui_sidebar_mode::Default && ui->main.mode != ui_sidebar_mode::ArenaWeather && menu_pos >= area_pos) dims.map_y2 = dimy - 1;
{
dims.menu_forced = true;
menu_pos = area_pos-1;
}
dims.area_on = (area_pos < 3);
dims.menu_on = (menu_pos < area_pos);
if (dims.menu_on)
{
dims.menu_x2 = ws.x - 2;
dims.menu_x1 = dims.menu_x2 - Gui::MENU_WIDTH + 1;
if (menu_pos == 1)
dims.menu_x1 -= Gui::AREA_MAP_WIDTH + 1;
dims.map_x2 = dims.menu_x1 - 2;
}
if (dims.area_on)
{
dims.area_x2 = ws.x-2;
dims.area_x1 = dims.area_x2 - Gui::AREA_MAP_WIDTH + 1;
if (dims.menu_on)
dims.menu_x2 = dims.area_x1 - 2;
else
dims.map_x2 = dims.area_x1 - 2;
}
return dims; return dims;
} }
@ -1974,11 +1962,13 @@ void Gui::resetDwarfmodeView(bool pause)
{ {
using df::global::cursor; using df::global::cursor;
if (ui) if (plotinfo)
{ {
ui->follow_unit = -1; plotinfo->follow_unit = -1;
ui->follow_item = -1; plotinfo->follow_item = -1;
ui->main.mode = ui_sidebar_mode::Default; /* TODO: understand how this changes for v50
plotinfo->main.mode = ui_sidebar_mode::Default;
*/
} }
if (selection_rect) if (selection_rect)
@ -2034,8 +2024,8 @@ bool Gui::revealInDwarfmodeMap(int32_t x, int32_t y, int32_t z, bool center)
*window_x = clip_range(new_win_x, 0, (world->map.x_count - w)); *window_x = clip_range(new_win_x, 0, (world->map.x_count - w));
*window_y = clip_range(new_win_y, 0, (world->map.y_count - h)); *window_y = clip_range(new_win_y, 0, (world->map.y_count - h));
*window_z = clip_range(new_win_z, 0, (world->map.z_count - 1)); *window_z = clip_range(new_win_z, 0, (world->map.z_count - 1));
ui_sidebar_menus->minimap.need_render = true; game->minimap.need_render = true;
ui_sidebar_menus->minimap.need_scan = true; game->minimap.need_scan = true;
return true; return true;
} }
@ -2081,10 +2071,10 @@ bool Gui::refreshSidebar()
bool Gui::inRenameBuilding() bool Gui::inRenameBuilding()
{ {
if (!ui_sidebar_menus) if (!game)
return false; return false;
/* TODO: understand how this changes for v50 /* TODO: understand how this changes for v50
return ui_sidebar_menus->barracks.in_rename; return game->barracks.in_rename;
*/ */
return false; return false;
} }
@ -2150,24 +2140,33 @@ bool Gui::setDesignationCoords (const int32_t x, const int32_t y, const int32_t
df::coord Gui::getMousePos() df::coord Gui::getMousePos()
{ {
df::coord pos; df::coord pos;
/* TODO: understand how this changes for v50 if (gps && gps->precise_mouse_x > -1) {
if (gps && gps->mouse_x > -1) {
// return invalid coords if the cursor is not over the map
DwarfmodeDims dims = getDwarfmodeViewDims();
if (gps->mouse_x < dims.map_x1 || gps->mouse_x > dims.map_x2 ||
gps->mouse_y < dims.map_y1 || gps->mouse_y > dims.map_y2) {
return pos;
}
pos = getViewportPos(); pos = getViewportPos();
pos.x += gps->mouse_x - 1; if (Screen::inGraphicsMode()) {
pos.y += gps->mouse_y - 1; int32_t map_tile_pixels = gps->viewport_zoom_factor / 4;
pos.x += gps->precise_mouse_x / map_tile_pixels;
pos.y += gps->precise_mouse_y / map_tile_pixels;
} else {
pos.x += gps->mouse_x;
pos.y += gps->mouse_y;
}
} }
*/ if (!Maps::isValidTilePos(pos.x, pos.y, pos.z))
return df::coord();
return pos; return pos;
} }
int getDepthAt_default (int32_t x, int32_t y) int getDepthAt_default (int32_t x, int32_t y)
{ {
auto &main_vp = gps->main_viewport;
if (x < 0 || x >= main_vp->dim_x || y < 0 || y >= main_vp->dim_y)
return 0;
const size_t num_viewports = gps->viewport.size();
const size_t index = (x * main_vp->dim_y) + y;
for (size_t depth = 0; depth < num_viewports; ++depth) {
if (gps->viewport[depth]->screentexpos_background[index])
return depth;
}
return 0; return 0;
} }
@ -2190,17 +2189,3 @@ bool Gui::getWindowSize (int32_t &width, int32_t &height)
return false; return false;
} }
} }
bool Gui::getMenuWidth(uint8_t &menu_width, uint8_t &area_map_width)
{
menu_width = (*ui_menu_width)[0];
area_map_width = (*ui_menu_width)[1];
return true;
}
bool Gui::setMenuWidth(const uint8_t menu_width, const uint8_t area_map_width)
{
(*ui_menu_width)[0] = menu_width;
(*ui_menu_width)[1] = area_map_width;
return true;
}

@ -87,7 +87,7 @@ using namespace std;
#include "df/reaction_product_itemst.h" #include "df/reaction_product_itemst.h"
#include "df/tool_uses.h" #include "df/tool_uses.h"
#include "df/trapcomp_flags.h" #include "df/trapcomp_flags.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/unit.h" #include "df/unit.h"
#include "df/unit_inventory_item.h" #include "df/unit_inventory_item.h"
#include "df/vehicle.h" #include "df/vehicle.h"
@ -100,7 +100,7 @@ using namespace std;
using namespace DFHack; using namespace DFHack;
using namespace df::enums; using namespace df::enums;
using df::global::world; using df::global::world;
using df::global::ui; using df::global::plotinfo;
using df::global::ui_selected_unit; using df::global::ui_selected_unit;
using df::global::proj_next_id; using df::global::proj_next_id;
@ -922,11 +922,13 @@ static bool detachItem(MapExtras::MapCache &mc, df::item *item)
case general_ref_type::UNIT_HOLDER: case general_ref_type::UNIT_HOLDER:
if (auto unit = ref->getUnit()) if (auto unit = ref->getUnit())
{ {
/* TODO: understand how this changes for v50
// Unit view sidebar holds inventory item pointers // Unit view sidebar holds inventory item pointers
if (ui->main.mode == ui_sidebar_mode::ViewUnits && if (plotinfo->main.mode == ui_sidebar_mode::ViewUnits &&
(!ui_selected_unit || (!ui_selected_unit ||
vector_get(world->units.active, *ui_selected_unit) == unit)) vector_get(world->units.active, *ui_selected_unit) == unit))
return false; return false;
*/
for (int i = unit->inventory.size()-1; i >= 0; i--) for (int i = unit->inventory.size()-1; i >= 0; i--)
{ {
@ -1532,7 +1534,7 @@ int32_t Items::createItem(df::item_type item_type, int16_t item_subtype, int16_t
df::enums::game_type::game_type type = *df::global::gametype; df::enums::game_type::game_type type = *df::global::gametype;
prod->produce(unit, &out_products, &out_items, &in_reag, &in_items, 1, job_skill::NONE, prod->produce(unit, &out_products, &out_items, &in_reag, &in_items, 1, job_skill::NONE,
0, df::historical_entity::find(unit->civ_id), 0, df::historical_entity::find(unit->civ_id),
((type == df::enums::game_type::DWARF_MAIN) || (type == df::enums::game_type::DWARF_RECLAIM)) ? df::world_site::find(df::global::ui->site_id) : NULL, ((type == df::enums::game_type::DWARF_MAIN) || (type == df::enums::game_type::DWARF_RECLAIM)) ? df::world_site::find(df::global::plotinfo->site_id) : NULL,
NULL); NULL);
if ( out_items.size() != 1 ) if ( out_items.size() != 1 )
return -1; return -1;
@ -1641,9 +1643,9 @@ bool Items::isRouteVehicle(df::item *item)
bool Items::isSquadEquipment(df::item *item) bool Items::isSquadEquipment(df::item *item)
{ {
CHECK_NULL_POINTER(item); CHECK_NULL_POINTER(item);
if (!ui) if (!plotinfo)
return false; return false;
auto &vec = ui->equipment.items_assigned[item->getType()]; auto &vec = plotinfo->equipment.items_assigned[item->getType()];
return binsearch_index(vec, &df::item::id, item->id) >= 0; return binsearch_index(vec, &df::item::id, item->id) >= 0;
} }

@ -43,7 +43,7 @@ using namespace std;
#include "DataDefs.h" #include "DataDefs.h"
#include "df/world.h" #include "df/world.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/unit.h" #include "df/unit.h"
#include "df/building.h" #include "df/building.h"
#include "df/job.h" #include "df/job.h"

@ -20,13 +20,13 @@ using namespace DFHack;
#include "DataDefs.h" #include "DataDefs.h"
#include "df/world.h" #include "df/world.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/item_type.h" #include "df/item_type.h"
#include "df/plant_raw.h" #include "df/plant_raw.h"
using namespace df::enums; using namespace df::enums;
using df::global::world; using df::global::world;
using df::global::ui; using df::global::plotinfo;
// Special values used by "seedwatch" plugin to store seed limits // Special values used by "seedwatch" plugin to store seed limits
const df::enums::item_type::item_type SEEDLIMIT_ITEMTYPE = df::enums::item_type::BAR; const df::enums::item_type::item_type SEEDLIMIT_ITEMTYPE = df::enums::item_type::BAR;
@ -41,12 +41,12 @@ void Kitchen::debug_print(color_ostream &out)
{ {
out.print("%2zu: IT:%2i IS:%i MT:%3i MI:%2i ET:%i %s\n", out.print("%2zu: IT:%2i IS:%i MT:%3i MI:%2i ET:%i %s\n",
i, i,
ui->kitchen.item_types[i], plotinfo->kitchen.item_types[i],
ui->kitchen.item_subtypes[i], plotinfo->kitchen.item_subtypes[i],
ui->kitchen.mat_types[i], plotinfo->kitchen.mat_types[i],
ui->kitchen.mat_indices[i], plotinfo->kitchen.mat_indices[i],
ui->kitchen.exc_types[i], plotinfo->kitchen.exc_types[i],
(ui->kitchen.mat_types[i] >= 419 && ui->kitchen.mat_types[i] <= 618) ? world->raws.plants.all[ui->kitchen.mat_indices[i]]->id.c_str() : "n/a" (plotinfo->kitchen.mat_types[i] >= 419 && plotinfo->kitchen.mat_types[i] <= 618) ? world->raws.plants.all[plotinfo->kitchen.mat_indices[i]]->id.c_str() : "n/a"
); );
} }
out.print("\n"); out.print("\n");
@ -83,11 +83,11 @@ void Kitchen::fillWatchMap(std::map<int32_t, int16_t>& watchMap)
watchMap.clear(); watchMap.clear();
for (std::size_t i = 0; i < size(); ++i) for (std::size_t i = 0; i < size(); ++i)
{ {
if (ui->kitchen.item_subtypes[i] == SEEDLIMIT_ITEMTYPE && if (plotinfo->kitchen.item_subtypes[i] == SEEDLIMIT_ITEMTYPE &&
ui->kitchen.item_subtypes[i] == SEEDLIMIT_ITEMSUBTYPE && plotinfo->kitchen.item_subtypes[i] == SEEDLIMIT_ITEMSUBTYPE &&
ui->kitchen.exc_types[i] == SEEDLIMIT_EXCTYPE) plotinfo->kitchen.exc_types[i] == SEEDLIMIT_EXCTYPE)
{ {
watchMap[ui->kitchen.mat_indices[i]] = ui->kitchen.mat_types[i]; watchMap[plotinfo->kitchen.mat_indices[i]] = plotinfo->kitchen.mat_types[i];
} }
} }
} }
@ -96,10 +96,10 @@ int Kitchen::findLimit(int32_t plant_id)
{ {
for (size_t i = 0; i < size(); ++i) for (size_t i = 0; i < size(); ++i)
{ {
if (ui->kitchen.item_types[i] == SEEDLIMIT_ITEMTYPE && if (plotinfo->kitchen.item_types[i] == SEEDLIMIT_ITEMTYPE &&
ui->kitchen.item_subtypes[i] == SEEDLIMIT_ITEMSUBTYPE && plotinfo->kitchen.item_subtypes[i] == SEEDLIMIT_ITEMSUBTYPE &&
ui->kitchen.mat_indices[i] == plant_id && plotinfo->kitchen.mat_indices[i] == plant_id &&
ui->kitchen.exc_types[i] == SEEDLIMIT_EXCTYPE) plotinfo->kitchen.exc_types[i] == SEEDLIMIT_EXCTYPE)
{ {
return int(i); return int(i);
} }
@ -113,11 +113,11 @@ bool Kitchen::removeLimit(int32_t plant_id)
if (i < 0) if (i < 0)
return false; return false;
ui->kitchen.item_types.erase(ui->kitchen.item_types.begin() + i); plotinfo->kitchen.item_types.erase(plotinfo->kitchen.item_types.begin() + i);
ui->kitchen.item_subtypes.erase(ui->kitchen.item_subtypes.begin() + i); plotinfo->kitchen.item_subtypes.erase(plotinfo->kitchen.item_subtypes.begin() + i);
ui->kitchen.mat_types.erase(ui->kitchen.mat_types.begin() + i); plotinfo->kitchen.mat_types.erase(plotinfo->kitchen.mat_types.begin() + i);
ui->kitchen.mat_indices.erase(ui->kitchen.mat_indices.begin() + i); plotinfo->kitchen.mat_indices.erase(plotinfo->kitchen.mat_indices.begin() + i);
ui->kitchen.exc_types.erase(ui->kitchen.exc_types.begin() + i); plotinfo->kitchen.exc_types.erase(plotinfo->kitchen.exc_types.begin() + i);
return true; return true;
} }
@ -129,15 +129,15 @@ bool Kitchen::setLimit(int32_t plant_id, int16_t limit)
int i = findLimit(plant_id); int i = findLimit(plant_id);
if (i < 0) if (i < 0)
{ {
ui->kitchen.item_types.push_back(SEEDLIMIT_ITEMTYPE); plotinfo->kitchen.item_types.push_back(SEEDLIMIT_ITEMTYPE);
ui->kitchen.item_subtypes.push_back(SEEDLIMIT_ITEMSUBTYPE); plotinfo->kitchen.item_subtypes.push_back(SEEDLIMIT_ITEMSUBTYPE);
ui->kitchen.mat_types.push_back(limit); plotinfo->kitchen.mat_types.push_back(limit);
ui->kitchen.mat_indices.push_back(plant_id); plotinfo->kitchen.mat_indices.push_back(plant_id);
ui->kitchen.exc_types.push_back(SEEDLIMIT_EXCTYPE); plotinfo->kitchen.exc_types.push_back(SEEDLIMIT_EXCTYPE);
} }
else else
{ {
ui->kitchen.mat_types[i] = limit; plotinfo->kitchen.mat_types[i] = limit;
} }
return true; return true;
} }
@ -146,11 +146,11 @@ void Kitchen::clearLimits()
{ {
for (size_t i = 0; i < size(); ++i) for (size_t i = 0; i < size(); ++i)
{ {
if (ui->kitchen.item_types[i] == SEEDLIMIT_ITEMTYPE && if (plotinfo->kitchen.item_types[i] == SEEDLIMIT_ITEMTYPE &&
ui->kitchen.item_subtypes[i] == SEEDLIMIT_ITEMSUBTYPE && plotinfo->kitchen.item_subtypes[i] == SEEDLIMIT_ITEMSUBTYPE &&
ui->kitchen.exc_types[i] == SEEDLIMIT_EXCTYPE) plotinfo->kitchen.exc_types[i] == SEEDLIMIT_EXCTYPE)
{ {
removeLimit(ui->kitchen.mat_indices[i]); removeLimit(plotinfo->kitchen.mat_indices[i]);
--i; --i;
} }
} }
@ -158,7 +158,7 @@ void Kitchen::clearLimits()
size_t Kitchen::size() size_t Kitchen::size()
{ {
return ui->kitchen.item_types.size(); return plotinfo->kitchen.item_types.size();
} }
int Kitchen::findExclusion(df::kitchen_exc_type type, int Kitchen::findExclusion(df::kitchen_exc_type type,
@ -167,11 +167,11 @@ int Kitchen::findExclusion(df::kitchen_exc_type type,
{ {
for (size_t i = 0; i < size(); i++) for (size_t i = 0; i < size(); i++)
{ {
if (ui->kitchen.item_types[i] == item_type && if (plotinfo->kitchen.item_types[i] == item_type &&
ui->kitchen.item_subtypes[i] == item_subtype && plotinfo->kitchen.item_subtypes[i] == item_subtype &&
ui->kitchen.mat_types[i] == mat_type && plotinfo->kitchen.mat_types[i] == mat_type &&
ui->kitchen.mat_indices[i] == mat_index && plotinfo->kitchen.mat_indices[i] == mat_index &&
ui->kitchen.exc_types[i] == type) plotinfo->kitchen.exc_types[i] == type)
{ {
return int(i); return int(i);
} }
@ -186,11 +186,11 @@ bool Kitchen::addExclusion(df::kitchen_exc_type type,
if (findExclusion(type, item_type, item_subtype, mat_type, mat_index) >= 0) if (findExclusion(type, item_type, item_subtype, mat_type, mat_index) >= 0)
return false; return false;
ui->kitchen.item_types.push_back(item_type); plotinfo->kitchen.item_types.push_back(item_type);
ui->kitchen.item_subtypes.push_back(item_subtype); plotinfo->kitchen.item_subtypes.push_back(item_subtype);
ui->kitchen.mat_types.push_back(mat_type); plotinfo->kitchen.mat_types.push_back(mat_type);
ui->kitchen.mat_indices.push_back(mat_index); plotinfo->kitchen.mat_indices.push_back(mat_index);
ui->kitchen.exc_types.push_back(type); plotinfo->kitchen.exc_types.push_back(type);
return true; return true;
} }
@ -202,10 +202,10 @@ bool Kitchen::removeExclusion(df::kitchen_exc_type type,
if (i < 0) if (i < 0)
return false; return false;
ui->kitchen.item_types.erase(ui->kitchen.item_types.begin() + i); plotinfo->kitchen.item_types.erase(plotinfo->kitchen.item_types.begin() + i);
ui->kitchen.item_subtypes.erase(ui->kitchen.item_subtypes.begin() + i); plotinfo->kitchen.item_subtypes.erase(plotinfo->kitchen.item_subtypes.begin() + i);
ui->kitchen.mat_types.erase(ui->kitchen.mat_types.begin() + i); plotinfo->kitchen.mat_types.erase(plotinfo->kitchen.mat_types.begin() + i);
ui->kitchen.mat_indices.erase(ui->kitchen.mat_indices.begin() + i); plotinfo->kitchen.mat_indices.erase(plotinfo->kitchen.mat_indices.begin() + i);
ui->kitchen.exc_types.erase(ui->kitchen.exc_types.begin() + i); plotinfo->kitchen.exc_types.erase(plotinfo->kitchen.exc_types.begin() + i);
return true; return true;
} }

@ -42,7 +42,7 @@ using namespace std;
#include "MiscUtils.h" #include "MiscUtils.h"
#include "df/world.h" #include "df/world.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/item.h" #include "df/item.h"
#include "df/creature_raw.h" #include "df/creature_raw.h"
#include "df/caste_raw.h" #include "df/caste_raw.h"
@ -68,7 +68,7 @@ using namespace DFHack;
using namespace df::enums; using namespace df::enums;
using df::global::world; using df::global::world;
using df::global::ui; using df::global::plotinfo;
bool MaterialInfo::decode(df::item *item) bool MaterialInfo::decode(df::item *item)
{ {
@ -516,7 +516,7 @@ void MaterialInfo::getMatchBits(df::job_item_flags2 &ok, df::job_item_flags2 &ma
TEST(fire_safe, material->heat.melting_point > 11000); TEST(fire_safe, material->heat.melting_point > 11000);
TEST(magma_safe, material->heat.melting_point > 12000); TEST(magma_safe, material->heat.melting_point > 12000);
TEST(deep_material, FLAG(inorganic, inorganic_flags::SPECIAL)); TEST(deep_material, FLAG(inorganic, inorganic_flags::SPECIAL));
TEST(non_economic, !inorganic || !(ui && vector_get(ui->economic_stone, index))); TEST(non_economic, !inorganic || !(plotinfo && vector_get(plotinfo->economic_stone, index)));
TEST(plant, plant); TEST(plant, plant);
TEST(silk, MAT_FLAG(SILK)); TEST(silk, MAT_FLAG(SILK));

@ -7,10 +7,9 @@ using df::global::enabler;
using df::global::gps; using df::global::gps;
using DFHack::Renderer::renderer_wrap; using DFHack::Renderer::renderer_wrap;
/*
static renderer_wrap *original_renderer = NULL; static renderer_wrap *original_renderer = NULL;
const int32_t Renderer::GET_MOUSE_COORDS_SENTINEL = 0xcd1aa471;
bool init() bool init()
{ {
if (!original_renderer) if (!original_renderer)
@ -156,3 +155,4 @@ bool Renderer::renderer_wrap::get_mouse_coords(int32_t* x, int32_t* y) {
bool Renderer::renderer_wrap::uses_opengl() { bool Renderer::renderer_wrap::uses_opengl() {
return parent->uses_opengl(); return parent->uses_opengl();
}; };
*/

@ -34,6 +34,7 @@ using namespace std;
#include "modules/Renderer.h" #include "modules/Renderer.h"
#include "modules/Screen.h" #include "modules/Screen.h"
#include "modules/GuiHooks.h" #include "modules/GuiHooks.h"
#include "Debug.h"
#include "MemAccess.h" #include "MemAccess.h"
#include "VersionInfo.h" #include "VersionInfo.h"
#include "Types.h" #include "Types.h"
@ -49,10 +50,11 @@ using namespace DFHack;
#include "DataDefs.h" #include "DataDefs.h"
#include "df/init.h" #include "df/init.h"
#include "df/texture_handler.h" #include "df/texture_handlerst.h"
#include "df/tile_page.h" #include "df/tile_pagest.h"
#include "df/interfacest.h" #include "df/interfacest.h"
#include "df/enabler.h" #include "df/enabler.h"
#include "df/graphic_viewportst.h"
#include "df/unit.h" #include "df/unit.h"
#include "df/item.h" #include "df/item.h"
#include "df/job.h" #include "df/job.h"
@ -72,30 +74,29 @@ using Screen::PenArray;
using std::string; using std::string;
namespace DFHack {
DBG_DECLARE(core, screen, DebugCategory::LINFO);
}
/* /*
* Screen painting API. * Screen painting API.
*/ */
// returns text grid coordinates, even if the game map is scaled differently // returns ui grid coordinates, even if the game map is scaled differently
df::coord2d Screen::getMousePos() df::coord2d Screen::getMousePos()
{ {
int32_t pixelx = 0, pixely = 0, tilex = 0, tiley = 0; if (!gps)
if (!enabler || !enabler->renderer->get_mouse_coords(
&pixelx, &pixely, &tilex, &tiley)) {
return df::coord2d(-1, -1); return df::coord2d(-1, -1);
} return df::coord2d(gps->mouse_x, gps->mouse_y);
return df::coord2d(tilex, tiley);
} }
// returns the screen pixel coordinates // returns the screen pixel coordinates
df::coord2d Screen::getMousePixels() df::coord2d Screen::getMousePixels()
{ {
int32_t pixelx = 0, pixely = 0, tilex = 0, tiley = 0; if (!gps)
if (!enabler || !enabler->renderer->get_mouse_coords(
&pixelx, &pixely, &tilex, &tiley)) {
return df::coord2d(-1, -1); return df::coord2d(-1, -1);
} return df::coord2d(gps->precise_mouse_x, gps->precise_mouse_y);
return df::coord2d(pixelx, pixely);
} }
df::coord2d Screen::getWindowSize() df::coord2d Screen::getWindowSize()
@ -114,25 +115,88 @@ bool Screen::inGraphicsMode()
return init && init->display.flag.is_set(init_display_flags::USE_GRAPHICS); return init && init->display.flag.is_set(init_display_flags::USE_GRAPHICS);
} }
static bool doSetTile_map(const Pen &pen, int x, int y) {
size_t max_index = gps->main_viewport->dim_x * gps->main_viewport->dim_y - 1;
size_t index = (x * gps->main_viewport->dim_y) + y;
if (index < 0 || index > max_index)
return false;
long texpos = pen.tile;
if (texpos == 0) {
texpos = init->font.large_font_texpos[(uint8_t)pen.ch];
}
gps->main_viewport->screentexpos_interface[index] = texpos;
return true;
}
static bool doSetTile_default(const Pen &pen, int x, int y, bool map) static bool doSetTile_default(const Pen &pen, int x, int y, bool map)
{ {
auto dim = Screen::getWindowSize(); bool use_graphics = Screen::inGraphicsMode();
if (x < 0 || x >= dim.x || y < 0 || y >= dim.y)
if (map && use_graphics)
return doSetTile_map(pen, x, y);
size_t index = (x * gps->dimy) + y;
uint8_t *screen = &gps->screen[index * 8];
if (screen > gps->screen_limit)
return false; return false;
/* TODO: understand how this changes for v50 long *texpos = &gps->screentexpos[index];
int index = ((x * gps->dimy) + y); long *texpos_lower = &gps->screentexpos_lower[index];
auto screen = gps->screen + index*4; uint32_t *flag = &gps->screentexpos_flag[index];
screen[0] = uint8_t(pen.ch);
screen[1] = uint8_t(pen.fg) & 15; *screen = 0;
screen[2] = uint8_t(pen.bg) & 15; *texpos = 0;
screen[3] = uint8_t(pen.bold) & 1; *texpos_lower = 0;
gps->screentexpos[index] = pen.tile; gps->screentexpos_anchored[index] = 0;
gps->screentexpos_addcolor[index] = (pen.tile_mode == Screen::Pen::CharColor); // keep SCREENTEXPOS_FLAG_ANCHOR_SUBORDINATE so occluded anchored textures
gps->screentexpos_grayscale[index] = (pen.tile_mode == Screen::Pen::TileColor); // don't appear corrupted
gps->screentexpos_cf[index] = pen.tile_fg; *flag &= 4;
gps->screentexpos_cbr[index] = pen.tile_bg;
*/ if (gps->top_in_use) {
screen = &gps->screen_top[index * 8];
texpos = &gps->screentexpos_top[index];
texpos_lower = &gps->screentexpos_top_lower[index];
flag = &gps->screentexpos_top_flag[index];
*screen = 0;
*texpos = 0;
*texpos_lower = 0;
gps->screentexpos_top_anchored[index] = 0;
*flag &= 4; // keep SCREENTEXPOS_FLAG_ANCHOR_SUBORDINATE
}
uint8_t fg = pen.fg | (pen.bold << 3);
uint8_t bg = pen.bg;
if (pen.tile_mode == Screen::Pen::CharColor)
*flag |= 2; // SCREENTEXPOS_FLAG_ADDCOLOR
else if (pen.tile_mode == Screen::Pen::TileColor) {
*flag |= 1; // SCREENTEXPOS_FLAG_GRAYSCALE
if (pen.tile_fg)
fg = pen.tile_fg;
if (pen.tile_bg)
bg = pen.tile_bg;
}
if (pen.tile && use_graphics) {
*texpos = pen.tile;
} else {
screen[0] = uint8_t(pen.ch);
*texpos_lower = 909;
}
auto rgb_fg = &gps->uccolor[fg][0];
auto rgb_bg = &gps->uccolor[bg][0];
screen[1] = rgb_fg[0];
screen[2] = rgb_fg[1];
screen[3] = rgb_fg[2];
screen[4] = rgb_bg[0];
screen[5] = rgb_bg[1];
screen[6] = rgb_bg[2];
return true; return true;
} }
@ -150,39 +214,83 @@ bool Screen::paintTile(const Pen &pen, int x, int y, bool map)
return true; return true;
} }
static Pen doGetTile_default(int x, int y, bool map) static Pen doGetTile_map(int x, int y) {
{ size_t max_index = gps->main_viewport->dim_x * gps->main_viewport->dim_y - 1;
auto dim = Screen::getWindowSize(); size_t index = (x * gps->main_viewport->dim_y) + y;
if (x < 0 || x >= dim.x || y < 0 || y >= dim.y)
return Pen(0,0,0,-1);
/* TODO: understand how this changes for v50 if (index < 0 || index > max_index)
int index = x*dim.y + y; return Pen(0, 0, 0, -1);
auto screen = gps->screen + index*4;
if (screen[3] & 0x80)
return Pen(0,0,0,-1);
Pen pen( int tile = gps->main_viewport->screentexpos[index];
screen[0], screen[1], screen[2], screen[3]?true:false, if (tile == 0)
gps->screentexpos[index] tile = gps->main_viewport->screentexpos_item[index];
); if (tile == 0)
tile = gps->main_viewport->screentexpos_building_one[index];
if (tile == 0)
tile = gps->main_viewport->screentexpos_background_two[index];
if (tile == 0)
tile = gps->main_viewport->screentexpos_background[index];
if (pen.tile) char ch = 0;
{ uint8_t fg = 0;
if (gps->screentexpos_grayscale[index]) uint8_t bg = 0;
{ return Pen(ch, fg, bg, tile, false);
pen.tile_mode = Screen::Pen::TileColor; }
pen.tile_fg = gps->screentexpos_cf[index];
pen.tile_bg = gps->screentexpos_cbr[index]; static uint8_t to_16_bit_color(uint8_t *rgb) {
} for (uint8_t c = 0; c < 16; ++c) {
else if (gps->screentexpos_addcolor[index]) if (rgb[0] == gps->uccolor[c][0] &&
{ rgb[1] == gps->uccolor[c][1] &&
pen.tile_mode = Screen::Pen::CharColor; rgb[2] == gps->uccolor[c][2]) {
return c;
} }
} }
return 0;
}
static Pen doGetTile_default(int x, int y, bool map) {
if (x < 0 || y < 0)
return Pen(0, 0, 0, -1);
bool use_graphics = Screen::inGraphicsMode();
return pen; if (map && use_graphics)
*/ return Pen(0,0,0,-1); return doGetTile_map(x, y);
size_t index = (x * gps->dimy) + y;
uint8_t *screen = &gps->screen[index * 8];
if (screen > gps->screen_limit)
return Pen(0, 0, 0, -1);
long *texpos = &gps->screentexpos[index];
uint32_t *flag = &gps->screentexpos_flag[index];
if (gps->top_in_use &&
(gps->screen_top[index * 8] ||
(use_graphics && gps->screentexpos_top[index]))) {
screen = &gps->screen_top[index * 8];
texpos = &gps->screentexpos_top[index];
flag = &gps->screentexpos_top_flag[index];
}
char ch = *screen;
uint8_t fg = to_16_bit_color(&screen[1]);
uint8_t bg = to_16_bit_color(&screen[4]);
int tile = 0;
if (use_graphics)
tile = *texpos;
if (*flag & 1) {
// TileColor
return Pen(ch, fg&7, bg, !!(fg&8), tile, fg, bg);
} else if (*flag & 2) {
// CharColor
return Pen(ch, fg, bg, tile, true);
}
// AsIs
return Pen(ch, fg, bg, tile, false);
} }
GUI_HOOK_DEFINE(Screen::Hooks::get_tile, doGetTile_default); GUI_HOOK_DEFINE(Screen::Hooks::get_tile, doGetTile_default);
@ -394,6 +502,10 @@ bool Screen::hasActiveScreens(Plugin *plugin)
return false; return false;
} }
void Screen::raise(df::viewscreen *screen) {
Hide swapper(screen, Screen::Hide::RESTORE_AT_TOP);
}
namespace DFHack { namespace Screen { namespace DFHack { namespace Screen {
Hide::Hide(df::viewscreen* screen, int flags) : Hide::Hide(df::viewscreen* screen, int flags) :
@ -592,11 +704,13 @@ bool dfhack_viewscreen::key_conflict(df::interface_key key)
if (key == interface_key::OPTIONS) if (key == interface_key::OPTIONS)
return true; return true;
/* TODO: understand how this changes for v50
if (text_input_mode) if (text_input_mode)
{ {
if (key == interface_key::HELP || key == interface_key::MOVIES) if (key == interface_key::HELP || key == interface_key::MOVIES)
return true; return true;
} }
*/
return false; return false;
} }

@ -0,0 +1,148 @@
#include "Internal.h"
#include "modules/DFSDL.h"
#include "modules/Textures.h"
#include "Debug.h"
#include "PluginManager.h"
#include "df/enabler.h"
using df::global::enabler;
using namespace DFHack;
using namespace DFHack::DFSDL;
namespace DFHack {
DBG_DECLARE(core, textures, DebugCategory::LINFO);
}
static bool g_loaded = false;
static long g_num_dfhack_textures = 0;
static long g_dfhack_logo_texpos_start = -1;
// Converts an arbitrary Surface to something like the display format
// (32-bit RGBA), and converts magenta to transparency if convert_magenta is set
// and the source surface didn't already have an alpha channel.
// It also deletes the source surface.
//
// It uses the same pixel format (RGBA, R at lowest address) regardless of
// hardware.
DFSDL_Surface * canonicalize_format(DFSDL_Surface *src) {
DFSDL_PixelFormat fmt;
fmt.palette = NULL;
fmt.BitsPerPixel = 32;
fmt.BytesPerPixel = 4;
fmt.Rloss = fmt.Gloss = fmt.Bloss = fmt.Aloss = 0;
//#if SDL_BYTEORDER == SDL_BIG_ENDIAN
// fmt.Rshift = 24; fmt.Gshift = 16; fmt.Bshift = 8; fmt.Ashift = 0;
//#else
fmt.Rshift = 0; fmt.Gshift = 8; fmt.Bshift = 16; fmt.Ashift = 24;
//#endif
fmt.Rmask = 255 << fmt.Rshift;
fmt.Gmask = 255 << fmt.Gshift;
fmt.Bmask = 255 << fmt.Bshift;
fmt.Amask = 255 << fmt.Ashift;
fmt.colorkey = 0;
fmt.alpha = 255;
DFSDL_Surface *tgt = DFSDL_ConvertSurface(src, &fmt, 0); // SDL_SWSURFACE
DFSDL_FreeSurface(src);
return tgt;
}
const uint32_t TILE_WIDTH_PX = 8;
const uint32_t TILE_HEIGHT_PX = 12;
static size_t load_textures(color_ostream & out, const char * fname,
long *texpos_start) {
DFSDL_Surface *s = DFIMG_Load(fname);
if (!s) {
out.printerr("unable to load textures from '%s'\n", fname);
return 0;
}
s = canonicalize_format(s);
DFSDL_SetAlpha(s, 0, 255);
int dimx = s->w / TILE_WIDTH_PX;
int dimy = s->h / TILE_HEIGHT_PX;
long count = 0;
for (int y = 0; y < dimy; y++) {
for (int x = 0; x < dimx; x++) {
DFSDL_Surface *tile = DFSDL_CreateRGBSurface(0, // SDL_SWSURFACE
TILE_WIDTH_PX, TILE_HEIGHT_PX, 32,
s->format->Rmask, s->format->Gmask, s->format->Bmask,
s->format->Amask);
DFSDL_SetAlpha(tile, 0,255);
DFSDL_Rect vp;
vp.x = TILE_WIDTH_PX * x;
vp.y = TILE_HEIGHT_PX * y;
vp.w = TILE_WIDTH_PX;
vp.h = TILE_HEIGHT_PX;
DFSDL_UpperBlit(s, &vp, tile, NULL);
if (!count++)
*texpos_start = enabler->textures.raws.size();
enabler->textures.raws.push_back(tile);
}
}
DFSDL_FreeSurface(s);
DEBUG(textures,out).print("loaded %ld textures from '%s'\n", count, fname);
return count;
}
// DFHack could conceivably be loaded at any time, so we need to be able to
// handle loading textures before or after a world is loaded.
// If a world is already loaded, then append our textures to the raws. they'll
// be freed when the world is unloaded and we'll reload when we get to the title
// screen. If it's pre-world, append our textures and then adjust the "init"
// texture count so our textures will no longer be freed when worlds are
// unloaded.
//
void Textures::init(color_ostream &out) {
auto & textures = enabler->textures;
long num_textures = textures.raws.size();
if (num_textures <= g_dfhack_logo_texpos_start)
g_loaded = false;
if (g_loaded)
return;
bool is_pre_world = num_textures == textures.init_texture_size;
g_num_dfhack_textures = load_textures(out, "hack/data/art/dfhack.png",
&g_dfhack_logo_texpos_start);
DEBUG(textures,out).print("loaded %ld textures\n", g_num_dfhack_textures);
if (is_pre_world)
textures.init_texture_size += g_num_dfhack_textures;
// NOTE: when GL modes are supported, we'll have to re-upload textures here
g_loaded = true;
}
// It's ok to leave NULLs in the raws list (according to usage in g_src)
void Textures::cleanup() {
if (!g_loaded)
return;
auto & textures = enabler->textures;
auto &raws = textures.raws;
size_t texpos_end = g_dfhack_logo_texpos_start + g_num_dfhack_textures;
for (size_t idx = g_dfhack_logo_texpos_start; idx <= texpos_end; ++idx) {
DFSDL_FreeSurface((DFSDL_Surface *)raws[idx]);
raws[idx] = NULL;
}
if (g_dfhack_logo_texpos_start == textures.init_texture_size - g_num_dfhack_textures)
textures.init_texture_size -= g_num_dfhack_textures;
g_loaded = false;
g_num_dfhack_textures = 0;
g_dfhack_logo_texpos_start = -1;
}
long Textures::getDfhackLogoTexposStart() {
return g_dfhack_logo_texpos_start;
}

@ -73,7 +73,7 @@ using namespace std;
#include "df/nemesis_record.h" #include "df/nemesis_record.h"
#include "df/squad.h" #include "df/squad.h"
#include "df/tile_occupancy.h" #include "df/tile_occupancy.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/unit_inventory_item.h" #include "df/unit_inventory_item.h"
#include "df/unit_misc_trait.h" #include "df/unit_misc_trait.h"
#include "df/unit_relationship_type.h" #include "df/unit_relationship_type.h"
@ -87,7 +87,7 @@ using namespace std;
using namespace DFHack; using namespace DFHack;
using namespace df::enums; using namespace df::enums;
using df::global::world; using df::global::world;
using df::global::ui; using df::global::plotinfo;
using df::global::gamemode; using df::global::gamemode;
using df::global::gametype; using df::global::gametype;
@ -178,7 +178,7 @@ bool Units::isFortControlled(df::unit *unit)
unit->flags2.bits.resident) unit->flags2.bits.resident)
return false; return false;
return unit->civ_id != -1 && unit->civ_id == ui->civ_id; return unit->civ_id != -1 && unit->civ_id == plotinfo->civ_id;
} }
// check if creature belongs to the player's civilization // check if creature belongs to the player's civilization
@ -186,7 +186,7 @@ bool Units::isFortControlled(df::unit *unit)
bool Units::isOwnCiv(df::unit* unit) bool Units::isOwnCiv(df::unit* unit)
{ {
CHECK_NULL_POINTER(unit); CHECK_NULL_POINTER(unit);
return unit->civ_id == ui->civ_id; return unit->civ_id == plotinfo->civ_id;
} }
// check if creature belongs to the player's group // check if creature belongs to the player's group
@ -199,7 +199,7 @@ bool Units::isOwnGroup(df::unit* unit)
for (size_t i = 0; i < histfig->entity_links.size(); i++) for (size_t i = 0; i < histfig->entity_links.size(); i++)
{ {
auto link = histfig->entity_links[i]; auto link = histfig->entity_links[i];
if (link->entity_id == ui->group_id && link->getType() == df::histfig_entity_link_type::MEMBER) if (link->entity_id == plotinfo->group_id && link->getType() == df::histfig_entity_link_type::MEMBER)
return true; return true;
} }
return false; return false;
@ -210,7 +210,7 @@ bool Units::isOwnGroup(df::unit* unit)
bool Units::isOwnRace(df::unit* unit) bool Units::isOwnRace(df::unit* unit)
{ {
CHECK_NULL_POINTER(unit); CHECK_NULL_POINTER(unit);
return unit->race == ui->race_id; return unit->race == plotinfo->race_id;
} }
@ -622,8 +622,8 @@ bool Units::isDwarf(df::unit *unit)
{ {
CHECK_NULL_POINTER(unit); CHECK_NULL_POINTER(unit);
return unit->race == ui->race_id || return unit->race == plotinfo->race_id ||
unit->enemy.normal_race == ui->race_id; unit->enemy.normal_race == plotinfo->race_id;
} }
bool Units::isAnimal(df::unit* unit) { bool Units::isAnimal(df::unit* unit) {
@ -1301,7 +1301,7 @@ bool Units::setLaborValidity(df::unit_labor labor, bool isValid)
return false; return false;
if (labor == df::unit_labor::NONE) if (labor == df::unit_labor::NONE)
return false; return false;
df::historical_entity *entity = df::historical_entity::find(ui->civ_id); df::historical_entity *entity = df::historical_entity::find(plotinfo->civ_id);
if (!entity || !entity->entity_raw) if (!entity || !entity->entity_raw)
return false; return false;
entity->entity_raw->jobs.permitted_labor[labor] = isValid; entity->entity_raw->jobs.permitted_labor[labor] = isValid;
@ -1704,7 +1704,7 @@ std::string Units::getCasteProfessionName(int race, int casteid, df::profession
if (pid < (df::profession)0 || !is_valid_enum_item(pid)) if (pid < (df::profession)0 || !is_valid_enum_item(pid))
return ""; return "";
int16_t current_race = df::global::ui->race_id; int16_t current_race = df::global::plotinfo->race_id;
if (df::global::gamemode && *df::global::gamemode == df::game_mode::ADVENTURE) if (df::global::gamemode && *df::global::gamemode == df::game_mode::ADVENTURE)
current_race = world->units.active[0]->race; current_race = world->units.active[0]->race;
bool use_race_prefix = (race >= 0 && race != current_race); bool use_race_prefix = (race >= 0 && race != current_race);

@ -1 +1 @@
Subproject commit 617d6acc10d499f6b158d3f51776d84c689aac9e Subproject commit d026f34ed1f7ab79aebb1c5bc8a36ee9b30bd13d

@ -0,0 +1 @@
!buildingplan/

@ -2,12 +2,12 @@ include(Plugins.cmake)
option(BUILD_STONESENSE "Build stonesense (needs a checkout first)." OFF) option(BUILD_STONESENSE "Build stonesense (needs a checkout first)." OFF)
if(BUILD_STONESENSE) if(BUILD_STONESENSE)
add_subdirectory(stonesense) #add_subdirectory(stonesense)
endif() endif()
option(BUILD_ISOWORLD "Build isoworld (needs a checkout first)." OFF) option(BUILD_ISOWORLD "Build isoworld (needs a checkout first)." OFF)
if(BUILD_ISOWORLD) if(BUILD_ISOWORLD)
add_subdirectory(isoworld) #add_subdirectory(isoworld)
if(UNIX) if(UNIX)
if(APPLE) if(APPLE)
# TODO: add an OSX runner script # TODO: add an OSX runner script
@ -21,12 +21,12 @@ endif()
option(BUILD_DEV_PLUGINS "Build developer plugins." OFF) option(BUILD_DEV_PLUGINS "Build developer plugins." OFF)
if(BUILD_DEV_PLUGINS) if(BUILD_DEV_PLUGINS)
add_subdirectory(devel) #add_subdirectory(devel)
endif() endif()
option(BUILD_RUBY "Build ruby binding." ON) option(BUILD_RUBY "Build ruby binding." ON)
if(BUILD_RUBY) if(BUILD_RUBY)
add_subdirectory(ruby) #add_subdirectory(ruby)
endif() endif()
install(DIRECTORY lua/ install(DIRECTORY lua/
@ -75,111 +75,108 @@ add_custom_target(generate_proto DEPENDS ${PROJECT_PROTO_TMP_FILES})
set_source_files_properties( Brushes.h PROPERTIES HEADER_FILE_ONLY TRUE ) set_source_files_properties( Brushes.h PROPERTIES HEADER_FILE_ONLY TRUE )
# Plugins # Plugins
option(BUILD_SUPPORTED "Build the supported plugins (reveal, probe, etc.)." ON) # If you are adding a plugin that you do not intend to commit to the DFHack repo,
if(BUILD_SUPPORTED) # see instructions for adding "external" plugins at the end of this file.
# If you are adding a plugin that you do not intend to commit to the DFHack repo,
# see instructions for adding "external" plugins at the end of this file. #dfhack_plugin(3dveins 3dveins.cpp)
#dfhack_plugin(add-spatter add-spatter.cpp)
dfhack_plugin(3dveins 3dveins.cpp) dfhack_plugin(autobutcher autobutcher.cpp LINK_LIBRARIES lua)
dfhack_plugin(add-spatter add-spatter.cpp) #dfhack_plugin(autochop autochop.cpp)
dfhack_plugin(autobutcher autobutcher.cpp LINK_LIBRARIES lua) #dfhack_plugin(autoclothing autoclothing.cpp)
dfhack_plugin(autochop autochop.cpp) #dfhack_plugin(autodump autodump.cpp)
dfhack_plugin(autoclothing autoclothing.cpp) #dfhack_plugin(autofarm autofarm.cpp)
dfhack_plugin(autodump autodump.cpp) #dfhack_plugin(autogems autogems.cpp LINK_LIBRARIES jsoncpp_static)
dfhack_plugin(autofarm autofarm.cpp) #add_subdirectory(autolabor)
dfhack_plugin(autogems autogems.cpp LINK_LIBRARIES jsoncpp_static) #dfhack_plugin(automaterial automaterial.cpp LINK_LIBRARIES lua)
add_subdirectory(autolabor) #dfhack_plugin(automelt automelt.cpp)
dfhack_plugin(automaterial automaterial.cpp LINK_LIBRARIES lua) #dfhack_plugin(autonestbox autonestbox.cpp LINK_LIBRARIES lua)
dfhack_plugin(automelt automelt.cpp) #dfhack_plugin(autotrade autotrade.cpp)
dfhack_plugin(autonestbox autonestbox.cpp LINK_LIBRARIES lua) #dfhack_plugin(blueprint blueprint.cpp LINK_LIBRARIES lua)
dfhack_plugin(autotrade autotrade.cpp) #dfhack_plugin(burrows burrows.cpp LINK_LIBRARIES lua)
dfhack_plugin(blueprint blueprint.cpp LINK_LIBRARIES lua) #dfhack_plugin(building-hacks building-hacks.cpp LINK_LIBRARIES lua)
dfhack_plugin(burrows burrows.cpp LINK_LIBRARIES lua) #add_subdirectory(buildingplan)
dfhack_plugin(building-hacks building-hacks.cpp LINK_LIBRARIES lua) #dfhack_plugin(changeitem changeitem.cpp)
add_subdirectory(buildingplan) #dfhack_plugin(changelayer changelayer.cpp)
dfhack_plugin(changeitem changeitem.cpp) #dfhack_plugin(changevein changevein.cpp)
dfhack_plugin(changelayer changelayer.cpp) #add_subdirectory(channel-safely)
dfhack_plugin(changevein changevein.cpp) #dfhack_plugin(cleanconst cleanconst.cpp)
add_subdirectory(channel-safely) #dfhack_plugin(cleaners cleaners.cpp)
dfhack_plugin(cleanconst cleanconst.cpp) #dfhack_plugin(cleanowned cleanowned.cpp)
dfhack_plugin(cleaners cleaners.cpp) #dfhack_plugin(confirm confirm.cpp LINK_LIBRARIES lua)
dfhack_plugin(cleanowned cleanowned.cpp) #dfhack_plugin(createitem createitem.cpp)
dfhack_plugin(confirm confirm.cpp LINK_LIBRARIES lua) #dfhack_plugin(cursecheck cursecheck.cpp)
dfhack_plugin(createitem createitem.cpp) #dfhack_plugin(cxxrandom cxxrandom.cpp LINK_LIBRARIES lua)
dfhack_plugin(cursecheck cursecheck.cpp) #dfhack_plugin(deramp deramp.cpp)
dfhack_plugin(cxxrandom cxxrandom.cpp LINK_LIBRARIES lua) dfhack_plugin(debug debug.cpp LINK_LIBRARIES jsoncpp_static)
dfhack_plugin(deramp deramp.cpp) #dfhack_plugin(dig dig.cpp)
dfhack_plugin(debug debug.cpp LINK_LIBRARIES jsoncpp_static) #dfhack_plugin(dig-now dig-now.cpp LINK_LIBRARIES lua)
dfhack_plugin(dig dig.cpp) #dfhack_plugin(digFlood digFlood.cpp)
dfhack_plugin(dig-now dig-now.cpp LINK_LIBRARIES lua) #add_subdirectory(diggingInvaders)
dfhack_plugin(digFlood digFlood.cpp) #dfhack_plugin(dwarfvet dwarfvet.cpp)
add_subdirectory(diggingInvaders) #dfhack_plugin(dwarfmonitor dwarfmonitor.cpp LINK_LIBRARIES lua)
dfhack_plugin(dwarfvet dwarfvet.cpp) #add_subdirectory(embark-assistant)
dfhack_plugin(dwarfmonitor dwarfmonitor.cpp LINK_LIBRARIES lua) #dfhack_plugin(embark-tools embark-tools.cpp)
add_subdirectory(embark-assistant) dfhack_plugin(eventful eventful.cpp LINK_LIBRARIES lua)
dfhack_plugin(embark-tools embark-tools.cpp) #dfhack_plugin(fastdwarf fastdwarf.cpp)
dfhack_plugin(eventful eventful.cpp LINK_LIBRARIES lua) #dfhack_plugin(filltraffic filltraffic.cpp)
dfhack_plugin(fastdwarf fastdwarf.cpp) #dfhack_plugin(fix-unit-occupancy fix-unit-occupancy.cpp)
dfhack_plugin(filltraffic filltraffic.cpp) #dfhack_plugin(fixveins fixveins.cpp)
dfhack_plugin(fix-unit-occupancy fix-unit-occupancy.cpp) #dfhack_plugin(flows flows.cpp)
dfhack_plugin(fixveins fixveins.cpp) #dfhack_plugin(follow follow.cpp)
dfhack_plugin(flows flows.cpp) #dfhack_plugin(forceequip forceequip.cpp)
dfhack_plugin(follow follow.cpp) #dfhack_plugin(generated-creature-renamer generated-creature-renamer.cpp)
dfhack_plugin(forceequip forceequip.cpp) #dfhack_plugin(getplants getplants.cpp)
dfhack_plugin(generated-creature-renamer generated-creature-renamer.cpp) dfhack_plugin(hotkeys hotkeys.cpp LINK_LIBRARIES lua)
dfhack_plugin(getplants getplants.cpp) #dfhack_plugin(infiniteSky infiniteSky.cpp)
dfhack_plugin(hotkeys hotkeys.cpp LINK_LIBRARIES lua) #dfhack_plugin(isoworldremote isoworldremote.cpp PROTOBUFS isoworldremote)
dfhack_plugin(infiniteSky infiniteSky.cpp) #dfhack_plugin(jobutils jobutils.cpp)
dfhack_plugin(isoworldremote isoworldremote.cpp PROTOBUFS isoworldremote) #dfhack_plugin(lair lair.cpp)
dfhack_plugin(jobutils jobutils.cpp) #dfhack_plugin(liquids liquids.cpp Brushes.h LINK_LIBRARIES lua)
dfhack_plugin(lair lair.cpp) #dfhack_plugin(luasocket luasocket.cpp LINK_LIBRARIES clsocket lua dfhack-tinythread)
dfhack_plugin(liquids liquids.cpp Brushes.h LINK_LIBRARIES lua) #dfhack_plugin(manipulator manipulator.cpp)
dfhack_plugin(luasocket luasocket.cpp LINK_LIBRARIES clsocket lua dfhack-tinythread) #dfhack_plugin(map-render map-render.cpp LINK_LIBRARIES lua)
dfhack_plugin(manipulator manipulator.cpp) #dfhack_plugin(misery misery.cpp)
dfhack_plugin(map-render map-render.cpp LINK_LIBRARIES lua) #dfhack_plugin(mode mode.cpp)
dfhack_plugin(misery misery.cpp) #dfhack_plugin(mousequery mousequery.cpp)
dfhack_plugin(mode mode.cpp) #dfhack_plugin(nestboxes nestboxes.cpp)
dfhack_plugin(mousequery mousequery.cpp) #dfhack_plugin(orders orders.cpp LINK_LIBRARIES jsoncpp_static)
dfhack_plugin(nestboxes nestboxes.cpp) dfhack_plugin(overlay overlay.cpp LINK_LIBRARIES lua)
dfhack_plugin(orders orders.cpp LINK_LIBRARIES jsoncpp_static) dfhack_plugin(pathable pathable.cpp LINK_LIBRARIES lua)
dfhack_plugin(overlay overlay.cpp LINK_LIBRARIES lua) #dfhack_plugin(petcapRemover petcapRemover.cpp)
dfhack_plugin(pathable pathable.cpp LINK_LIBRARIES lua) #dfhack_plugin(plants plants.cpp)
dfhack_plugin(petcapRemover petcapRemover.cpp) #dfhack_plugin(probe probe.cpp)
dfhack_plugin(plants plants.cpp) #dfhack_plugin(prospector prospector.cpp LINK_LIBRARIES lua)
dfhack_plugin(probe probe.cpp) #dfhack_plugin(power-meter power-meter.cpp LINK_LIBRARIES lua)
dfhack_plugin(prospector prospector.cpp LINK_LIBRARIES lua) #dfhack_plugin(regrass regrass.cpp)
dfhack_plugin(power-meter power-meter.cpp LINK_LIBRARIES lua) #add_subdirectory(remotefortressreader)
dfhack_plugin(regrass regrass.cpp) #dfhack_plugin(rename rename.cpp LINK_LIBRARIES lua PROTOBUFS rename)
add_subdirectory(remotefortressreader) #add_subdirectory(rendermax)
dfhack_plugin(rename rename.cpp LINK_LIBRARIES lua PROTOBUFS rename) dfhack_plugin(reveal reveal.cpp LINK_LIBRARIES lua)
add_subdirectory(rendermax) #dfhack_plugin(search search.cpp)
dfhack_plugin(reveal reveal.cpp LINK_LIBRARIES lua) #dfhack_plugin(seedwatch seedwatch.cpp)
dfhack_plugin(search search.cpp) #dfhack_plugin(showmood showmood.cpp)
dfhack_plugin(seedwatch seedwatch.cpp) #dfhack_plugin(siege-engine siege-engine.cpp LINK_LIBRARIES lua)
dfhack_plugin(showmood showmood.cpp) #dfhack_plugin(sort sort.cpp LINK_LIBRARIES lua)
dfhack_plugin(siege-engine siege-engine.cpp LINK_LIBRARIES lua) #dfhack_plugin(steam-engine steam-engine.cpp)
dfhack_plugin(sort sort.cpp LINK_LIBRARIES lua) #add_subdirectory(spectate)
dfhack_plugin(steam-engine steam-engine.cpp) #dfhack_plugin(stockflow stockflow.cpp LINK_LIBRARIES lua)
add_subdirectory(spectate) #add_subdirectory(stockpiles)
dfhack_plugin(stockflow stockflow.cpp LINK_LIBRARIES lua) #dfhack_plugin(stocks stocks.cpp)
add_subdirectory(stockpiles) #dfhack_plugin(strangemood strangemood.cpp)
dfhack_plugin(stocks stocks.cpp) #dfhack_plugin(tailor tailor.cpp)
dfhack_plugin(strangemood strangemood.cpp) #dfhack_plugin(tiletypes tiletypes.cpp Brushes.h LINK_LIBRARIES lua)
dfhack_plugin(tailor tailor.cpp) #dfhack_plugin(title-folder title-folder.cpp)
dfhack_plugin(tiletypes tiletypes.cpp Brushes.h LINK_LIBRARIES lua) #dfhack_plugin(title-version title-version.cpp)
dfhack_plugin(title-folder title-folder.cpp) #dfhack_plugin(trackstop trackstop.cpp)
dfhack_plugin(title-version title-version.cpp) #dfhack_plugin(tubefill tubefill.cpp)
dfhack_plugin(trackstop trackstop.cpp) #add_subdirectory(tweak)
dfhack_plugin(tubefill tubefill.cpp) #dfhack_plugin(workflow workflow.cpp LINK_LIBRARIES lua)
add_subdirectory(tweak) #dfhack_plugin(workNow workNow.cpp)
dfhack_plugin(workflow workflow.cpp LINK_LIBRARIES lua) #dfhack_plugin(xlsxreader xlsxreader.cpp LINK_LIBRARIES lua xlsxio_read_STATIC zip expat)
dfhack_plugin(workNow workNow.cpp) #dfhack_plugin(zone zone.cpp)
dfhack_plugin(xlsxreader xlsxreader.cpp LINK_LIBRARIES lua xlsxio_read_STATIC zip expat)
dfhack_plugin(zone zone.cpp) # If you are adding a plugin that you do not intend to commit to the DFHack repo,
# see instructions for adding "external" plugins at the end of this file.
# If you are adding a plugin that you do not intend to commit to the DFHack repo,
# see instructions for adding "external" plugins at the end of this file.
endif()
# this is the skeleton plugin. If you want to make your own, make a copy and then change it # this is the skeleton plugin. If you want to make your own, make a copy and then change it
option(BUILD_SKELETON "Build the skeleton plugin." OFF) option(BUILD_SKELETON "Build the skeleton plugin." OFF)

@ -24,7 +24,7 @@
#include "df/job.h" #include "df/job.h"
#include "df/job_item.h" #include "df/job_item.h"
#include "df/job_item_ref.h" #include "df/job_item_ref.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/report.h" #include "df/report.h"
#include "df/reaction.h" #include "df/reaction.h"
#include "df/reaction_reagent_itemst.h" #include "df/reaction_reagent_itemst.h"
@ -45,7 +45,7 @@ DFHACK_PLUGIN("add-spatter");
DFHACK_PLUGIN_IS_ENABLED(is_enabled); DFHACK_PLUGIN_IS_ENABLED(is_enabled);
REQUIRE_GLOBAL(gps); REQUIRE_GLOBAL(gps);
REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(plotinfo);
typedef df::reaction_product_item_improvementst improvement_product; typedef df::reaction_product_item_improvementst improvement_product;

@ -712,13 +712,20 @@ static bool hasValidMapPos(df::unit *unit) {
&& unit->pos.z < world->map.z_count; && unit->pos.z < world->map.z_count;
} }
// built cage defined as room (supposed to detect zoo cages) // built cage in a zone (supposed to detect zoo cages)
static bool isInBuiltCageRoom(df::unit *unit) { static bool isInBuiltCageRoom(df::unit *unit) {
for (auto building : world->buildings.all) { for (auto building : world->buildings.all) {
// !!! building->isRoom() returns true if the building can be made a room but currently isn't if (building->getType() != df::building_type::Cage)
// !!! except for coffins/tombs which always return false continue;
// !!! using the bool is_room however gives the correct state/value
if (!building->is_room || building->getType() != df::building_type::Cage) bool in_zone = false;
for (auto relation : building->relations) {
if (relation->getType() == df::building_type::Civzone) {
in_zone = true;
break;
}
}
if (!in_zone)
continue; continue;
df::building_cagest* cage = (df::building_cagest*)building; df::building_cagest* cage = (df::building_cagest*)building;

@ -22,7 +22,7 @@
#include "df/plant_tree_tile.h" #include "df/plant_tree_tile.h"
#include "df/plant_raw.h" #include "df/plant_raw.h"
#include "df/tile_dig_designation.h" #include "df/tile_dig_designation.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/viewscreen_dwarfmodest.h" #include "df/viewscreen_dwarfmodest.h"
#include "df/world.h" #include "df/world.h"
@ -45,7 +45,7 @@ using namespace df::enums;
#define PLUGIN_VERSION 0.3 #define PLUGIN_VERSION 0.3
DFHACK_PLUGIN("autochop"); DFHACK_PLUGIN("autochop");
REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(plotinfo);
static int get_log_count(); static int get_log_count();
@ -499,7 +499,7 @@ public:
burrows_column.clear(); burrows_column.clear();
for (df::burrow *burrow : ui->burrows.list) for (df::burrow *burrow : plotinfo->burrows.list)
{ {
string name = burrow->name; string name = burrow->name;
if (name.empty()) if (name.empty())
@ -820,7 +820,7 @@ struct autochop_hook : public df::viewscreen_dwarfmodest
bool isInDesignationMenu() bool isInDesignationMenu()
{ {
using namespace df::enums::ui_sidebar_mode; using namespace df::enums::ui_sidebar_mode;
return (ui->main.mode == DesignateChopTrees); return (plotinfo->main.mode == DesignateChopTrees);
} }
void sendKey(const df::interface_key &key) void sendKey(const df::interface_key &key)

@ -5,7 +5,7 @@
#include "DataDefs.h" #include "DataDefs.h"
#include "df/world.h" #include "df/world.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/building_type.h" #include "df/building_type.h"
#include "df/building_farmplotst.h" #include "df/building_farmplotst.h"
#include "df/buildings_other_id.h" #include "df/buildings_other_id.h"
@ -30,7 +30,7 @@ using namespace DFHack;
using namespace df::enums; using namespace df::enums;
using df::global::world; using df::global::world;
using df::global::ui; using df::global::plotinfo;
static command_result autofarm(color_ostream& out, std::vector<std::string>& parameters); static command_result autofarm(color_ostream& out, std::vector<std::string>& parameters);
@ -348,7 +348,7 @@ static std::unique_ptr<AutoFarm> autofarmInstance;
DFhackCExport command_result plugin_init(color_ostream& out, std::vector <PluginCommand>& commands) DFhackCExport command_result plugin_init(color_ostream& out, std::vector <PluginCommand>& commands)
{ {
if (world && ui) { if (world && plotinfo) {
commands.push_back( commands.push_back(
PluginCommand("autofarm", PluginCommand("autofarm",
"Automatically manage farm crop selection.", "Automatically manage farm crop selection.",

@ -33,7 +33,7 @@ using namespace DFHack;
DFHACK_PLUGIN("autogems"); DFHACK_PLUGIN("autogems");
DFHACK_PLUGIN_IS_ENABLED(enabled); DFHACK_PLUGIN_IS_ENABLED(enabled);
REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(plotinfo);
REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(world);
typedef int32_t item_id; typedef int32_t item_id;
@ -242,7 +242,7 @@ struct autogem_hook : public df::viewscreen_dwarfmodest {
bool in_menu() { bool in_menu() {
// Determines whether we're looking at the Workshop Orders screen. // Determines whether we're looking at the Workshop Orders screen.
return ui->main.mode == ui_sidebar_mode::OrdersWorkshop; return plotinfo->main.mode == ui_sidebar_mode::OrdersWorkshop;
} }
bool handleInput(std::set<df::interface_key> *input) { bool handleInput(std::set<df::interface_key> *input) {

@ -12,7 +12,7 @@
// DF data structure definition headers // DF data structure definition headers
#include "DataDefs.h" #include "DataDefs.h"
#include <df/ui.h> #include <df/plotinfost.h>
#include <df/world.h> #include <df/world.h>
#include <df/unit.h> #include <df/unit.h>
#include <df/unit_soul.h> #include <df/unit_soul.h>
@ -32,7 +32,7 @@
#include <df/building_tradedepotst.h> #include <df/building_tradedepotst.h>
#include <df/building_stockpilest.h> #include <df/building_stockpilest.h>
#include <df/items_other_id.h> #include <df/items_other_id.h>
#include <df/ui.h> #include <df/plotinfost.h>
#include <df/activity_info.h> #include <df/activity_info.h>
#include <MiscUtils.h> #include <MiscUtils.h>
@ -47,7 +47,7 @@ using namespace DFHack;
using namespace df::enums; using namespace df::enums;
DFHACK_PLUGIN("autohauler"); DFHACK_PLUGIN("autohauler");
REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(plotinfo);
REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(world);
#define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0])) #define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0]))

@ -12,7 +12,7 @@
// DF data structure definition headers // DF data structure definition headers
#include "DataDefs.h" #include "DataDefs.h"
#include <df/ui.h> #include <df/plotinfost.h>
#include <df/world.h> #include <df/world.h>
#include <df/unit.h> #include <df/unit.h>
#include <df/unit_soul.h> #include <df/unit_soul.h>
@ -32,7 +32,7 @@
#include <df/building_tradedepotst.h> #include <df/building_tradedepotst.h>
#include <df/building_stockpilest.h> #include <df/building_stockpilest.h>
#include <df/items_other_id.h> #include <df/items_other_id.h>
#include <df/ui.h> #include <df/plotinfost.h>
#include <df/activity_info.h> #include <df/activity_info.h>
#include <MiscUtils.h> #include <MiscUtils.h>
@ -47,7 +47,7 @@ using namespace DFHack;
using namespace df::enums; using namespace df::enums;
DFHACK_PLUGIN("autolabor"); DFHACK_PLUGIN("autolabor");
REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(plotinfo);
REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(world);
#define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0])) #define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0]))
@ -813,7 +813,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
// identify dwarfs who are needed for meetings and mark them for exclusion // identify dwarfs who are needed for meetings and mark them for exclusion
for (auto& act : ui->activities) for (auto& act : plotinfo->activities)
{ {
if (!act) continue; if (!act) continue;
bool p1 = act->unit_actor == dwarfs[dwarf]; bool p1 = act->unit_actor == dwarfs[dwarf];

@ -56,7 +56,7 @@ using std::string;
using std::endl; using std::endl;
using namespace DFHack; using namespace DFHack;
using namespace df::enums; using namespace df::enums;
using df::global::ui; using df::global::plotinfo;
using df::global::world; using df::global::world;
#include "labormanager.h" #include "labormanager.h"

@ -25,7 +25,7 @@
#include "DataDefs.h" #include "DataDefs.h"
#include <MiscUtils.h> #include <MiscUtils.h>
#include <df/ui.h> #include <df/plotinfost.h>
#include <df/world.h> #include <df/world.h>
#include <df/unit.h> #include <df/unit.h>
#include <df/unit_relationship_type.h> #include <df/unit_relationship_type.h>
@ -46,7 +46,7 @@
#include <df/building_tradedepotst.h> #include <df/building_tradedepotst.h>
#include <df/building_stockpilest.h> #include <df/building_stockpilest.h>
#include <df/items_other_id.h> #include <df/items_other_id.h>
#include <df/ui.h> #include <df/plotinfost.h>
#include <df/activity_info.h> #include <df/activity_info.h>
#include <df/tile_dig_designation.h> #include <df/tile_dig_designation.h>
#include <df/item_weaponst.h> #include <df/item_weaponst.h>
@ -64,7 +64,7 @@
#include <df/building_design.h> #include <df/building_design.h>
#include <df/vehicle.h> #include <df/vehicle.h>
#include <df/units_other_id.h> #include <df/units_other_id.h>
#include <df/ui.h> #include <df/plotinfost.h>
#include <df/training_assignment.h> #include <df/training_assignment.h>
#include <df/general_ref_contains_itemst.h> #include <df/general_ref_contains_itemst.h>
#include <df/personality_facet_type.h> #include <df/personality_facet_type.h>
@ -82,7 +82,7 @@ using std::string;
using std::endl; using std::endl;
using namespace DFHack; using namespace DFHack;
using namespace df::enums; using namespace df::enums;
using df::global::ui; using df::global::plotinfo;
using df::global::world; using df::global::world;
#define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0])) #define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0]))
@ -948,9 +948,9 @@ private:
// identify dwarfs who are needed for meetings and mark them for exclusion // identify dwarfs who are needed for meetings and mark them for exclusion
for (size_t i = 0; i < ui->activities.size(); ++i) for (size_t i = 0; i < plotinfo->activities.size(); ++i)
{ {
df::activity_info *act = ui->activities[i]; df::activity_info *act = plotinfo->activities[i];
if (!act) continue; if (!act) continue;
bool p1 = act->unit_actor == dwarf->dwarf; bool p1 = act->unit_actor == dwarf->dwarf;
@ -996,11 +996,11 @@ private:
for (size_t j = 0; j < dwarf->dwarf->inventory.size(); j++) for (size_t j = 0; j < dwarf->dwarf->inventory.size(); j++)
{ {
df::unit_inventory_item* ui = dwarf->dwarf->inventory[j]; df::unit_inventory_item* plotinfo = dwarf->dwarf->inventory[j];
if (ui->mode == df::unit_inventory_item::Weapon && ui->item->isWeapon()) if (plotinfo->mode == df::unit_inventory_item::Weapon && plotinfo->item->isWeapon())
{ {
dwarf->armed = true; dwarf->armed = true;
df::itemdef_weaponst* weapondef = ((df::item_weaponst*)(ui->item))->subtype; df::itemdef_weaponst* weapondef = ((df::item_weaponst*)(plotinfo->item))->subtype;
df::job_skill weaponsk = (df::job_skill) weapondef->skill_melee; df::job_skill weaponsk = (df::job_skill) weapondef->skill_melee;
df::job_skill rangesk = (df::job_skill) weapondef->skill_ranged; df::job_skill rangesk = (df::job_skill) weapondef->skill_ranged;
if (weaponsk == df::job_skill::AXE) if (weaponsk == df::job_skill::AXE)
@ -1408,8 +1408,8 @@ public:
(isOptionEnabled(CF_ALLOW_HUNTING) && has_butchers) ? 1 : 0; (isOptionEnabled(CF_ALLOW_HUNTING) && has_butchers) ? 1 : 0;
/* add animal trainers */ /* add animal trainers */
for (auto a = df::global::ui->equipment.training_assignments.begin(); for (auto a = df::global::plotinfo->equipment.training_assignments.begin();
a != df::global::ui->equipment.training_assignments.end(); a != df::global::plotinfo->equipment.training_assignments.end();
a++) a++)
{ {
labor_needed[df::unit_labor::ANIMALTRAIN]++; labor_needed[df::unit_labor::ANIMALTRAIN]++;

@ -21,8 +21,8 @@
#include "df/build_req_choice_specst.h" #include "df/build_req_choice_specst.h"
#include "df/construction_type.h" #include "df/construction_type.h"
#include "df/item.h" #include "df/item.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/ui_build_selector.h" #include "df/buildreq.h"
#include "df/viewscreen_dwarfmodest.h" #include "df/viewscreen_dwarfmodest.h"
#include "df/items_other_id.h" #include "df/items_other_id.h"
#include "df/job.h" #include "df/job.h"
@ -50,7 +50,7 @@ using namespace df::enums;
DFHACK_PLUGIN("automaterial"); DFHACK_PLUGIN("automaterial");
REQUIRE_GLOBAL(gps); REQUIRE_GLOBAL(gps);
REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(plotinfo);
REQUIRE_GLOBAL(ui_build_selector); REQUIRE_GLOBAL(ui_build_selector);
namespace DFHack { namespace DFHack {
@ -115,14 +115,14 @@ static inline bool in_material_choice_stage()
{ {
return Gui::build_selector_hotkey(Core::getTopViewscreen()) && return Gui::build_selector_hotkey(Core::getTopViewscreen()) &&
ui_build_selector->building_type == df::building_type::Construction && ui_build_selector->building_type == df::building_type::Construction &&
ui->main.mode == ui_sidebar_mode::Build && plotinfo->main.mode == ui_sidebar_mode::Build &&
ui_build_selector->stage == 2; ui_build_selector->stage == 2;
} }
static inline bool in_placement_stage() static inline bool in_placement_stage()
{ {
return Gui::dwarfmode_hotkey(Core::getTopViewscreen()) && return Gui::dwarfmode_hotkey(Core::getTopViewscreen()) &&
ui->main.mode == ui_sidebar_mode::Build && plotinfo->main.mode == ui_sidebar_mode::Build &&
ui_build_selector && ui_build_selector &&
ui_build_selector->building_type == df::building_type::Construction && ui_build_selector->building_type == df::building_type::Construction &&
ui_build_selector->stage == 1; ui_build_selector->stage == 1;
@ -131,7 +131,7 @@ static inline bool in_placement_stage()
static inline bool in_type_choice_stage() static inline bool in_type_choice_stage()
{ {
return Gui::dwarfmode_hotkey(Core::getTopViewscreen()) && return Gui::dwarfmode_hotkey(Core::getTopViewscreen()) &&
ui->main.mode == ui_sidebar_mode::Build && plotinfo->main.mode == ui_sidebar_mode::Build &&
ui_build_selector && ui_build_selector &&
ui_build_selector->building_type < 0; ui_build_selector->building_type < 0;
} }
@ -713,7 +713,7 @@ struct jobutils_hook : public df::viewscreen_dwarfmodest
if (!box_select_enabled) if (!box_select_enabled)
return; return;
if (ui->main.mode != df::ui_sidebar_mode::Build || if (plotinfo->main.mode != df::ui_sidebar_mode::Build ||
ui_build_selector->building_type != df::building_type::Construction) ui_build_selector->building_type != df::building_type::Construction)
return; return;

@ -9,7 +9,7 @@
#include "df/building_stockpilest.h" #include "df/building_stockpilest.h"
#include "modules/Buildings.h" #include "modules/Buildings.h"
#include "modules/Items.h" #include "modules/Items.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "modules/Maps.h" #include "modules/Maps.h"
#include "modules/World.h" #include "modules/World.h"
#include "df/item_quality.h" #include "df/item_quality.h"
@ -21,7 +21,7 @@ DFHACK_PLUGIN("automelt");
REQUIRE_GLOBAL(gps); REQUIRE_GLOBAL(gps);
REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(cursor); REQUIRE_GLOBAL(cursor);
REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(plotinfo);
static const string PERSISTENCE_KEY = "automelt/stockpiles"; static const string PERSISTENCE_KEY = "automelt/stockpiles";

@ -15,7 +15,7 @@
#include "df/job.h" #include "df/job.h"
#include "df/job_item_ref.h" #include "df/job_item_ref.h"
#include "modules/Job.h" #include "modules/Job.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/mandate.h" #include "df/mandate.h"
#include "modules/Maps.h" #include "modules/Maps.h"
@ -25,7 +25,7 @@ DFHACK_PLUGIN("autotrade");
REQUIRE_GLOBAL(gps); REQUIRE_GLOBAL(gps);
REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(cursor); REQUIRE_GLOBAL(cursor);
REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(plotinfo);
static const string PERSISTENCE_KEY = "autotrade/stockpiles"; static const string PERSISTENCE_KEY = "autotrade/stockpiles";

@ -6,7 +6,7 @@
#include "df/building_type.h" #include "df/building_type.h"
#include "df/general_ref_building_holderst.h" #include "df/general_ref_building_holderst.h"
#include "df/job_item.h" #include "df/job_item.h"
#include "df/ui_build_selector.h" #include "df/buildreq.h"
#include "modules/Buildings.h" #include "modules/Buildings.h"
#include "modules/Gui.h" #include "modules/Gui.h"

@ -1,7 +1,7 @@
#include "df/construction_type.h" #include "df/construction_type.h"
#include "df/entity_position.h" #include "df/entity_position.h"
#include "df/interface_key.h" #include "df/interface_key.h"
#include "df/ui_build_selector.h" #include "df/buildreq.h"
#include "df/viewscreen_dwarfmodest.h" #include "df/viewscreen_dwarfmodest.h"
#include "modules/Gui.h" #include "modules/Gui.h"
@ -18,7 +18,7 @@
DFHACK_PLUGIN("buildingplan"); DFHACK_PLUGIN("buildingplan");
#define PLUGIN_VERSION "2.0" #define PLUGIN_VERSION "2.0"
REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(plotinfo);
REQUIRE_GLOBAL(ui_build_selector); REQUIRE_GLOBAL(ui_build_selector);
REQUIRE_GLOBAL(world); // used in buildingplan library REQUIRE_GLOBAL(world); // used in buildingplan library
@ -455,8 +455,8 @@ struct buildingplan_query_hook : public df::viewscreen_dwarfmodest
bool isInPlannedBuildingQueryMode() bool isInPlannedBuildingQueryMode()
{ {
return (ui->main.mode == df::ui_sidebar_mode::QueryBuilding || return (plotinfo->main.mode == df::ui_sidebar_mode::QueryBuilding ||
ui->main.mode == df::ui_sidebar_mode::BuildingItems) && plotinfo->main.mode == df::ui_sidebar_mode::BuildingItems) &&
planner.getPlannedBuilding(world->selected_building); planner.getPlannedBuilding(world->selected_building);
} }
@ -595,7 +595,7 @@ struct buildingplan_place_hook : public df::viewscreen_dwarfmodest
bool isInPlannedBuildingPlacementMode() bool isInPlannedBuildingPlacementMode()
{ {
return ui->main.mode == ui_sidebar_mode::Build && return plotinfo->main.mode == ui_sidebar_mode::Build &&
df::global::ui_build_selector && df::global::ui_build_selector &&
df::global::ui_build_selector->stage < 2 && df::global::ui_build_selector->stage < 2 &&
planner.isPlannableBuilding(toBuildingTypeKey(ui_build_selector)); planner.isPlannableBuilding(toBuildingTypeKey(ui_build_selector));
@ -861,7 +861,7 @@ struct buildingplan_room_hook : public df::viewscreen_dwarfmodest
std::vector<Units::NoblePosition> getNoblePositionOfSelectedBuildingOwner() std::vector<Units::NoblePosition> getNoblePositionOfSelectedBuildingOwner()
{ {
std::vector<Units::NoblePosition> np; std::vector<Units::NoblePosition> np;
if (ui->main.mode != df::ui_sidebar_mode::QueryBuilding || if (plotinfo->main.mode != df::ui_sidebar_mode::QueryBuilding ||
!world->selected_building || !world->selected_building ||
!world->selected_building->owner) !world->selected_building->owner)
{ {
@ -1084,7 +1084,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
static bool is_paused() static bool is_paused()
{ {
return World::ReadPauseState() || return World::ReadPauseState() ||
ui->main.mode > df::ui_sidebar_mode::Squads || plotinfo->main.mode > df::ui_sidebar_mode::Squads ||
!strict_virtual_cast<df::viewscreen_dwarfmodest>(Gui::getCurViewscreen(true)); !strict_virtual_cast<df::viewscreen_dwarfmodest>(Gui::getCurViewscreen(true));
} }

@ -17,7 +17,7 @@
#include "TileTypes.h" #include "TileTypes.h"
#include "DataDefs.h" #include "DataDefs.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/world.h" #include "df/world.h"
#include "df/unit.h" #include "df/unit.h"
#include "df/burrow.h" #include "df/burrow.h"
@ -38,7 +38,7 @@ using namespace df::enums;
using namespace dfproto; using namespace dfproto;
DFHACK_PLUGIN("burrows"); DFHACK_PLUGIN("burrows");
REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(plotinfo);
REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(gamemode); REQUIRE_GLOBAL(gamemode);
@ -102,11 +102,11 @@ DEFINE_LUA_EVENT_1(onBurrowRename, handle_burrow_rename, df::burrow*);
static void detect_burrow_renames(color_ostream &out) static void detect_burrow_renames(color_ostream &out)
{ {
if (ui->main.mode == ui_sidebar_mode::Burrows && if (plotinfo->main.mode == ui_sidebar_mode::Burrows &&
ui->burrows.in_edit_name_mode && plotinfo->burrows.in_edit_name_mode &&
ui->burrows.sel_id >= 0) plotinfo->burrows.sel_id >= 0)
{ {
name_burrow_id = ui->burrows.sel_id; name_burrow_id = plotinfo->burrows.sel_id;
} }
else if (name_burrow_id >= 0) else if (name_burrow_id >= 0)
{ {
@ -222,7 +222,7 @@ static std::map<std::string,int> name_lookup;
static void parse_names() static void parse_names()
{ {
auto &list = ui->burrows.list; auto &list = plotinfo->burrows.list;
grow_burrows.clear(); grow_burrows.clear();
name_lookup.clear(); name_lookup.clear();

@ -36,7 +36,7 @@ using std::vector;
DFHACK_PLUGIN("confirm"); DFHACK_PLUGIN("confirm");
DFHACK_PLUGIN_IS_ENABLED(is_enabled); DFHACK_PLUGIN_IS_ENABLED(is_enabled);
REQUIRE_GLOBAL(gps); REQUIRE_GLOBAL(gps);
REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(plotinfo);
typedef std::set<df::interface_key> ikey_set; typedef std::set<df::interface_key> ikey_set;
command_result df_confirm (color_ostream &out, vector <string> & parameters); command_result df_confirm (color_ostream &out, vector <string> & parameters);

@ -16,7 +16,7 @@
#include "DataDefs.h" #include "DataDefs.h"
#include "df/game_type.h" #include "df/game_type.h"
#include "df/world.h" #include "df/world.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/unit.h" #include "df/unit.h"
#include "df/historical_entity.h" #include "df/historical_entity.h"
#include "df/world_site.h" #include "df/world_site.h"
@ -38,7 +38,7 @@ using namespace df::enums;
DFHACK_PLUGIN("createitem"); DFHACK_PLUGIN("createitem");
REQUIRE_GLOBAL(cursor); REQUIRE_GLOBAL(cursor);
REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(plotinfo);
REQUIRE_GLOBAL(gametype); REQUIRE_GLOBAL(gametype);
REQUIRE_GLOBAL(cur_year_tick); REQUIRE_GLOBAL(cur_year_tick);
@ -78,7 +78,7 @@ bool makeItem (df::reaction_product_itemst *prod, df::unit *unit, bool second_it
prod->produce(unit, &out_products, &out_items, &in_reag, &in_items, 1, job_skill::NONE, prod->produce(unit, &out_products, &out_items, &in_reag, &in_items, 1, job_skill::NONE,
0, df::historical_entity::find(unit->civ_id), 0, df::historical_entity::find(unit->civ_id),
(World::isFortressMode()) ? df::world_site::find(ui->site_id) : NULL, NULL); (World::isFortressMode()) ? df::world_site::find(plotinfo->site_id) : NULL, NULL);
if (!out_items.size()) if (!out_items.size())
return false; return false;
// if we asked to make shoes and we got twice as many as we asked, then we're okay // if we asked to make shoes and we got twice as many as we asked, then we're okay

@ -43,7 +43,7 @@ namespace DFHack {
DBG_DECLARE(debug,filter); DBG_DECLARE(debug,filter);
DBG_DECLARE(debug,init); DBG_DECLARE(debug,init);
DBG_DECLARE(debug,command); DBG_DECLARE(debug,command);
DBG_DECLARE(debug,ui); DBG_DECLARE(debug,plotinfo);
DBG_DECLARE(debug,example,DebugCategory::LINFO); DBG_DECLARE(debug,example,DebugCategory::LINFO);
} }

@ -33,7 +33,7 @@ using namespace DFHack;
DFHACK_PLUGIN("kittens"); DFHACK_PLUGIN("kittens");
DFHACK_PLUGIN_IS_ENABLED(is_enabled); DFHACK_PLUGIN_IS_ENABLED(is_enabled);
REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(plotinfo);
REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(world);
namespace DFHack { namespace DFHack {
@ -119,9 +119,9 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
} }
if(trackmenu_flg) if(trackmenu_flg)
{ {
if (last_menu != ui->main.mode) if (last_menu != plotinfo->main.mode)
{ {
last_menu = ui->main.mode; last_menu = plotinfo->main.mode;
out.print("Menu: %d\n",last_menu); out.print("Menu: %d\n",last_menu);
} }
} }
@ -157,7 +157,7 @@ command_result trackmenu (color_ostream &out, vector <string> & parameters)
else else
{ {
is_enabled = true; is_enabled = true;
last_menu = ui->main.mode; last_menu = plotinfo->main.mode;
out.print("Menu: %d\n",last_menu); out.print("Menu: %d\n",last_menu);
trackmenu_flg = true; trackmenu_flg = true;
return CR_OK; return CR_OK;

@ -5,7 +5,7 @@
#include "DataDefs.h" #include "DataDefs.h"
#include "df/world.h" #include "df/world.h"
#include "df/ui.h" #include "df/plotinfost.h"
#include "df/building_stockpilest.h" #include "df/building_stockpilest.h"
#include "df/global_objects.h" #include "df/global_objects.h"
#include "df/item.h" #include "df/item.h"
@ -24,7 +24,7 @@ using namespace DFHack;
using namespace df::enums; using namespace df::enums;
using df::global::world; using df::global::world;
using df::global::ui; using df::global::plotinfo;
using df::global::selection_rect; using df::global::selection_rect;
using df::building_stockpilest; using df::building_stockpilest;
@ -35,7 +35,7 @@ DFHACK_PLUGIN("stockcheck");
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
{ {
if (world && ui) { if (world && plotinfo) {
commands.push_back( commands.push_back(
PluginCommand("stockcheck", "Check for unprotected rottable items.", PluginCommand("stockcheck", "Check for unprotected rottable items.",
stockcheck, false, stockcheck, false,

@ -20,7 +20,7 @@ using namespace std;
#include "modules/World.h" #include "modules/World.h"
#include "MiscUtils.h" #include "MiscUtils.h"
#include <df/ui.h> #include <df/plotinfost.h>
#include "df/world.h" #include "df/world.h"
#include "df/world_raws.h" #include "df/world_raws.h"
#include "df/building_def.h" #include "df/building_def.h"
@ -34,7 +34,7 @@ using namespace DFHack;
using namespace df::enums; using namespace df::enums;
using df::global::world; using df::global::world;
using df::global::cursor; using df::global::cursor;
using df::global::ui; using df::global::plotinfo;
using namespace DFHack::Gui; using namespace DFHack::Gui;

@ -20,14 +20,14 @@
#include <df/reaction_product_itemst.h> #include <df/reaction_product_itemst.h>
#include <df/tile_designation.h> #include <df/tile_designation.h>
#include <df/tile_occupancy.h> #include <df/tile_occupancy.h>
#include <df/ui.h> #include <df/plotinfost.h>
#include <df/unit.h> #include <df/unit.h>
#include <df/vermin.h> #include <df/vermin.h>
#include <df/world.h> #include <df/world.h>
#include <df/world_site.h> #include <df/world_site.h>
DFHACK_PLUGIN("dig-now"); DFHACK_PLUGIN("dig-now");
REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(plotinfo);
REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(world);
using namespace DFHack; using namespace DFHack;
@ -678,7 +678,7 @@ static void create_boulders(color_ostream &out,
df::unit *unit = world->units.active[0]; df::unit *unit = world->units.active[0];
df::historical_entity *civ = df::historical_entity::find(unit->civ_id); df::historical_entity *civ = df::historical_entity::find(unit->civ_id);
df::world_site *site = World::isFortressMode() ? df::world_site *site = World::isFortressMode() ?
df::world_site::find(ui->site_id) : NULL; df::world_site::find(plotinfo->site_id) : NULL;
std::vector<df::reaction_reagent *> in_reag; std::vector<df::reaction_reagent *> in_reag;
std::vector<df::item *> in_items; std::vector<df::item *> in_items;

@ -16,7 +16,7 @@
#include "modules/Maps.h" #include "modules/Maps.h"
#include "modules/Materials.h" #include "modules/Materials.h"
#include "df/ui_sidebar_menus.h" #include "df/gamest.h"
using std::vector; using std::vector;
using std::string; using std::string;
@ -33,7 +33,7 @@ command_result digcircle (color_ostream &out, vector <string> & parameters);
command_result digtype (color_ostream &out, vector <string> & parameters); command_result digtype (color_ostream &out, vector <string> & parameters);
DFHACK_PLUGIN("dig"); DFHACK_PLUGIN("dig");
REQUIRE_GLOBAL(ui_sidebar_menus); REQUIRE_GLOBAL(game);
REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(window_z); REQUIRE_GLOBAL(window_z);
@ -213,7 +213,7 @@ bool lineY (MapExtras::MapCache & MCache,
int32_t parse_priority(color_ostream &out, vector<string> &parameters) int32_t parse_priority(color_ostream &out, vector<string> &parameters)
{ {
int32_t default_priority = ui_sidebar_menus->designation.priority; int32_t default_priority = game->designation.priority;
for (auto it = parameters.begin(); it != parameters.end(); ++it) for (auto it = parameters.begin(); it != parameters.end(); ++it)
{ {

Some files were not shown because too many files have changed in this diff Show More