diff --git a/.gitignore b/.gitignore index 9f2b009c6..b4a578ec0 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,6 @@ dfhack/python/dist build/CPack*Config.cmake /cmakeall.bat + +# vim swap files +*.swp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b6f2f5da..c7c84e859 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,14 +58,10 @@ if (NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl OR NOT EXISTS ${dfhac endif() # set up versioning. -set(DF_VERSION_MAJOR "0") -set(DF_VERSION_MINOR "34") -set(DF_VERSION_PATCH "11") -set(DF_VERSION "${DF_VERSION_MAJOR}.${DF_VERSION_MINOR}.${DF_VERSION_PATCH}") +set(DF_VERSION "0.34.11") +SET(DFHACK_RELEASE "r3" CACHE STRING "Current release revision.") -SET(DFHACK_RELEASE "r2" CACHE STRING "Current release revision.") - -set(DFHACK_VERSION "${DF_VERSION_MAJOR}.${DF_VERSION_MINOR}.${DF_VERSION_PATCH}-${DFHACK_RELEASE}") +set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") add_definitions(-DDFHACK_VERSION="${DFHACK_VERSION}") ## where to install things (after the build is done, classic 'make install' or package structure) @@ -122,7 +118,7 @@ ADD_DEFINITIONS(-DPROTOBUF_USE_DLLS) ADD_DEFINITIONS(-DLUA_BUILD_AS_DLL) if(APPLE) - add_definitions(-D_DARWIN) + add_definitions(-D_DARWIN) elseif(UNIX) add_definitions(-D_LINUX) elseif(WIN32) @@ -146,7 +142,7 @@ include_directories(depends/clsocket/src) add_subdirectory(depends) -find_package(Docutils) +#find_package(Docutils) #set (RST_FILES #"Readme" @@ -173,6 +169,7 @@ IF(BUILD_LIBRARY) add_subdirectory (library) ## install the default documentation files install(FILES LICENSE "Lua API.html" Readme.html Compile.html Contributors.html DESTINATION ${DFHACK_USERDOC_DESTINATION}) + install(DIRECTORY images DESTINATION ${DFHACK_USERDOC_DESTINATION}) endif() #build the plugins @@ -182,11 +179,11 @@ endif() # Packaging with CPack! IF(UNIX) - if(APPLE) - SET(CPACK_GENERATOR "ZIP") - else() - SET(CPACK_GENERATOR "TGZ") - endif() + if(APPLE) + SET(CPACK_GENERATOR "ZIP") + else() + SET(CPACK_GENERATOR "TGZ") + endif() ELSEIF(WIN32) SET(CPACK_GENERATOR "ZIP") ENDIF() diff --git a/Compile.html b/Compile.html index 41d409112..e5f6ca679 100644 --- a/Compile.html +++ b/Compile.html @@ -334,20 +334,21 @@ ul.auto-toc {
Download and unpack a copy of the latest DF
+Install Xcode from Mac App Store
+Open Xcode, go to Preferences > Downloads, and install the Command Line Tools.
+Install MacPorts.
+Install dependencies from MacPorts:
+sudo port install gcc45 +universal cmake +universal git-core +universal
+This will take some time—maybe hours, depending on your machine.
+At some point during this process, it may ask you to install a Java environment; let it do so.
+Install perl dependencies
++++
+- +
sudo cpan
+If this is the first time you've run cpan, you will need to go through the setup +process. Just stick with the defaults for everything and you'll be fine.
+- +
install XML::LibXML
+- +
install XML::LibXSLT
+
Get the dfhack source:
++git clone https://github.com/danaris/dfhack.git +cd dfhack +git submodule init +git submodule update ++
Build dfhack:
++mkdir build-osx +cd build-osx +export CC=/opt/local/bin/gcc-mp-4.5 +export CXX=/opt/local/bin/g++-mp-4.5 +cmake .. -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX=/path/to/DF/directory +make +make install ++
On Windows, DFHack replaces the SDL library distributed with DF.
DFHack doesn't have any kind of system of code snapshots in place, so you will have to get code from the github repository using git. You will need some sort of Windows port of git, or a GUI. Some examples:
@@ -428,7 +484,7 @@ git submodule updateIf you want to get really involved with the development, create an account on github, make a clone there and then use that as your remote repository instead. Detailed instructions are beyond the scope of this document. If you need help, join us on IRC (#dfhack channel on freenode).
First, you need cmake. Get the win32 installer version from the official site: http://www.cmake.org/cmake/resources/software.html
It has the usual installer wizard. Make sure you let it add its binary folder @@ -445,7 +501,7 @@ Grab it from Microsoft's site.
If you already have a different version of perl (for example the one from cygwin), you can run into some trouble. Either remove the other perl install from PATH, or install libxml and libxslt for it instead. Strawberry perl works though and has all the required packages.
There are several different batch files in the build folder along with a script that's used for picking the DF path.
First, run set_df_path.vbs and point the dialog that pops up at your DF folder that you want to use for development. Next, run one of the scripts with generate prefix. These create the MSVC solution file(s):
@@ -467,7 +523,7 @@ So pick either Release or RelWithDebInfo build and build the INSTALL target.cmake allows you to pick a build type by changing this variable: CMAKE_BUILD_TYPE
@@ -479,7 +535,7 @@ cmake .. -DCMAKE_BUILD_TYPE:string=BUILD_TYPE 'RelWithDebInfo'. 'Debug' is not available on Windows.
Currently, the most direct way to use the library is to write a plugin that can be loaded by it. All the plugins can be found in the 'plugins' folder. There's no in-depth documentation on how to write one yet, but it should be easy enough to copy one and just follow the pattern.
@@ -497,29 +553,29 @@ The main license is zlib/libpng, some bits are MIT licensed, and some are BSD liFeel free to add your own extensions and plugins. Contributing back to the dfhack repository is welcome and the right thing to do :)
DFHack uses information about the game data structures, represented via xml files in the library/xml/ submodule.
Data structure layouts are described in files following the df.*.xml name pattern. This information is transformed by a perl script into C++ headers describing the structures, and associated metadata for the Lua wrapper. These headers and data are then compiled into the DFHack libraries, thus necessitating a compatibility break every time layouts change; in return it significantly boosts the efficiency and capabilities of DFHack code.
Global object addresses are stored in symbols.xml, which is copied to the dfhack release package and loaded as data at runtime.
DFHack supports remote access by exchanging Google protobuf messages via a TCP socket. Both the core and plugins can define remotely accessible methods. The dfhack-run command uses this interface to invoke ordinary console commands.
Currently the supported set of requests is limited, because the developers don't know what exactly is most useful.
Protocol client implementations exist for Java and C#.
Several things should be kept in mind when contributing to DFHack.
DFhack uses ANSI formatting and four spaces as indentation. Line endings are UNIX. The files use UTF-8 encoding. Code not following this won't make me happy, because I'll have to fix it. There's a good chance I'll make you fix it ;)
You can send patches or make a clone of the github repo and ask me on the IRC channel to pull your code in. I'll review it and see if there are any problems. I'll fix them if they are minor.
@@ -529,7 +585,7 @@ this is also a good place to dump new ideas and/or bugs that need fixing.If you want to do memory research, you'll need some tools and some knowledge. In general, you'll need a good memory viewer and optionally something to look at machine code without getting crazy :)
diff --git a/Compile.rst b/Compile.rst index 8fca0e1f5..ce5d93ddf 100644 --- a/Compile.rst +++ b/Compile.rst @@ -63,6 +63,63 @@ extra options. You can also use a cmake-friendly IDE like KDevelop 4 or the cmake-gui program. +======== +Mac OS X +======== + +If you are building on 10.6, please read the subsection below titled "Snow Leopard Changes" FIRST. + +1. Download and unpack a copy of the latest DF +2. Install Xcode from Mac App Store +3. Open Xcode, go to Preferences > Downloads, and install the Command Line Tools. +4. Install MacPorts. +5. Install dependencies from MacPorts: + + * ``sudo port install gcc45 +universal cmake +universal git-core +universal`` + + This will take some time—maybe hours, depending on your machine. + + * At some point during this process, it may ask you to install a Java environment; let it do so. + +6. Install perl dependencies + + 1. ``sudo cpan`` + + If this is the first time you've run cpan, you will need to go through the setup + process. Just stick with the defaults for everything and you'll be fine. + + 2. ``install XML::LibXML`` + 3. ``install XML::LibXSLT`` + +7. Get the dfhack source:: + + git clone https://github.com/danaris/dfhack.git + cd dfhack + git submodule init + git submodule update + +8. Build dfhack:: + + mkdir build-osx + cd build-osx + export CC=/opt/local/bin/gcc-mp-4.5 + export CXX=/opt/local/bin/g++-mp-4.5 + cmake .. -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX=/path/to/DF/directory + make + make install + + +Snow Leopard Changes +==================== + +1. Add a step 6.2a (before Install XML::LibXSLT):: + In a separate Terminal window or tab, run: + ``sudo ln -s /usr/include/libxml2/libxml /usr/include/libxml`` + +2. Add a step 7a (before building):: + InThe current version of DFHack has extensive support for @@ -932,6 +963,21 @@ Returns entry, did_create_new
and automatically stored in the save game, these save and retrieval functions can just copy values in memory without doing any actual I/O. However, currently every entry has a 180+-byte dead-weight overhead. +It is also possible to associate one bit per map tile with an entry, +using these two methods:
+entry:getTilemask(block[, create])
+Retrieves the tile bitmask associated with this entry in the given map +block. If create is true, an empty mask is created if none exists; +otherwise the function returns nil, which must be assumed to be the same +as an all-zero mask.
+entry:deleteTilemask(block)
+Deletes the associated tile mask from the given map block.
+Note that these masks are only saved in fortress mode, and also that deleting +the persistent entry will NOT delete the associated masks.
dfhack.getHackPath()
Returns the dfhack directory path, i.e. ".../df/hack/".
dfhack.getSavePath()
+Returns the path to the current save directory, or nil if no save loaded.
+dfhack.getTickCount()
Returns the tick count in ms, exactly as DF ui uses.
dfhack.job.printItemDetails(jobitem,idx)
Prints info about the job item.
dfhack.job.getGeneralRef(job, type)
+Searches for a general_ref with the given type.
+dfhack.job.getSpecificRef(job, type)
+Searches for a specific_ref with the given type.
+dfhack.job.getHolder(job)
Returns the building holding the job.
dfhack.job.isSuitableItem(job_item, item_type, item_subtype)
+Does basic sanity checks to verify if the suggested item type matches +the flags in the job item.
+dfhack.job.isSuitableMaterial(job_item, mat_type, mat_index)
+Likewise, if replacing material.
+dfhack.units.getPosition(unit)
Returns true x,y,z of the unit, or nil if invalid; may be not equal to unit.pos if caged.
dfhack.units.getGeneralRef(unit, type)
+Searches for a general_ref with the given type.
+dfhack.units.getSpecificRef(unit, type)
+Searches for a specific_ref with the given type.
+dfhack.units.getContainer(unit)
Returns the container (cage) item or nil.
dfhack.units.getEffectiveSkill(unit, skill)
Computes the effective rating for the given skill, taking into account exhaustion, pain etc.
dfhack.units.getExperience(unit, skill[, total])
+Returns the experience value for the given skill. If total is true, adds experience implied by the current rating.
+dfhack.units.computeMovementSpeed(unit)
Computes number of frames * 100 it takes the unit to move in its current state of mind and body.
dfhack.items.getContainedItems(item)
Returns a list of items contained in this one.
dfhack.items.getHolderBuilding(item)
+Returns the holder building or nil.
+dfhack.items.getHolderUnit(item)
+Returns the holder unit or nil.
+dfhack.items.moveToGround(item,pos)
Move the item to the ground at position. Returns false if impossible.
dfhack.items.makeProjectile(item)
Turns the item into a projectile, and returns the new object, or nil if impossible.
dfhack.items.isCasteMaterial(item_type)
+Returns true if this item type uses a creature/caste pair as its material.
+dfhack.items.getSubtypeCount(item_type)
+Returns the number of raw-defined subtypes of the given item type, or -1 if not applicable.
+dfhack.items.getSubtypeDef(item_type, subtype)
+Returns the raw definition for the given item type and subtype, or nil if invalid.
+dfhack.maps.getBlock(x,y,z)
Returns a map block object for given x,y,z in local block coordinates.
dfhack.maps.isValidTilePos(coords), or isValidTilePos(x,y,z)``
+dfhack.maps.isValidTilePos(coords), or isValidTilePos(x,y,z)
Checks if the given df::coord or x,y,z in local tile coordinates are valid.
dfhack.maps.getTileBlock(coords), or getTileBlock(x,y,z)
@@ -1258,6 +1344,12 @@ Returns false in case of error.dfhack.maps.ensureTileBlock(coords), or ensureTileBlock(x,y,z)
Like getTileBlock, but if the block is not allocated, try creating it.
dfhack.maps.getTileType(coords), or getTileType(x,y,z)
+Returns the tile type at the given coordinates, or nil if invalid.
+dfhack.maps.getTileFlags(coords), or getTileFlags(x,y,z)
+Returns designation and occupancy references for the given coordinates, or nil, nil if invalid.
+dfhack.maps.getRegionBiome(region_coord2d), or getRegionBiome(x,y)
Returns the biome info struct for the given global map region.
dfhack.maps.hasTileAssignment(tilemask)
+Checks if the tile_bitmask object is not nil and contains any set bits; returns true or false.
+dfhack.maps.getTileAssignment(tilemask,x,y)
+Checks if the tile_bitmask object is not nil and has the relevant bit set; returns true or false.
+dfhack.maps.setTileAssignment(tilemask,x,y,enable)
+Sets the relevant bit in the tile_bitmask object to the enable argument.
+dfhack.maps.resetTileAssignment(tilemask[,enable])
+Sets all bits in the mask to the enable argument.
+dfhack.buildings.getGeneralRef(building, type)
+Searches for a general_ref with the given type.
+dfhack.buildings.getSpecificRef(building, type)
+Searches for a specific_ref with the given type.
+dfhack.buildings.setOwner(item,unit)
Replaces the owner of the building. If unit is nil, removes ownership. Returns false in case of error.
@@ -1500,37 +1610,12 @@ be feasibly used in the core context.Checks if [GRAPHICS:YES] was specified in init.
dfhack.screen.paintTile(pen,x,y[,char,tile])
-Paints a tile using given parameters. Pen is a table with following possible fields:
-Provides the ordinary tile character, as either a 1-character string or a number. -Can be overridden with the char function parameter.
-Foreground color for the ordinary tile. Defaults to COLOR_GREY (7).
-Background color for the ordinary tile. Defaults to COLOR_BLACK (0).
-Bright/bold text flag. If nil, computed based on (fg & 8); fg is masked to 3 bits. -Otherwise should be true/false.
-Graphical tile id. Ignored unless [GRAPHICS:YES] was in init.txt.
-Specifies that the tile should be shaded with fg/bg.
-If specified, overrides tile_color and supplies shading colors directly.
-Paints a tile using given parameters. See below for a description of pen.
Returns false if coordinates out of bounds, or other error.
dfhack.screen.readTile(x,y)
Retrieves the contents of the specified tile from the screen buffers. -Returns a pen, or nil if invalid or TrueType.
+Returns a pen object, or nil if invalid or TrueType.dfhack.screen.paintString(pen,x,y,text)
Paints the string starting at x,y. Uses the string characters @@ -1554,6 +1639,63 @@ The values can then be used for the tile field of pen structur
Requests repaint of the screen by setting a flag. Unlike other functions in this section, this may be used at any time.
dfhack.screen.getKeyDisplay(key)
+Returns the string that should be used to represent the given +logical keybinding on the screen in texts like "press Key to ...".
+The "pen" argument used by functions above may be represented by +a table with the following possible fields:
++++
+- ch
+- Provides the ordinary tile character, as either a 1-character string or a number. +Can be overridden with the char function parameter.
+- fg
+- Foreground color for the ordinary tile. Defaults to COLOR_GREY (7).
+- bg
+- Background color for the ordinary tile. Defaults to COLOR_BLACK (0).
+- bold
+- Bright/bold text flag. If nil, computed based on (fg & 8); fg is masked to 3 bits. +Otherwise should be true/false.
+- tile
+- Graphical tile id. Ignored unless [GRAPHICS:YES] was in init.txt.
+- tile_color = true
+- Specifies that the tile should be shaded with fg/bg.
+- tile_fg, tile_bg
+- If specified, overrides tile_color and supplies shading colors directly.
+
Alternatively, it may be a pre-parsed native object with the following API:
+dfhack.pen.make(base[,pen_or_fg,bg,bold])
+Creates a new pre-parsed pen by combining its arguments according to the +following rules:
+This function always returns a new pre-parsed pen, or nil.
+dfhack.pen.parse(base[,pen_or_fg,bg,bold])
+Exactly like the above function, but returns base or pen_or_fg +directly if they are already a pre-parsed native object.
+pen.property, pen.property = value, pairs(pen)
+Pre-parsed pens support reading and setting their properties, +but don't behave exactly like a simple table would; for instance, +assigning to pen.tile_color also resets pen.tile_fg and +pen.tile_bg to nil.
+In order to actually be able to paint to the screen, it is necessary to create and register a viewscreen (basically a modal dialog) with @@ -1619,7 +1761,10 @@ options; if multiple interpretations exist, the table will contain multiple keys
Maps to an integer in range 0-255. Duplicates a separate "STRING_A???" code for convenience.
If the left or right mouse button is pressed.
+If the left or right mouse button is being pressed.
+If the left or right mouse button was just pressed.
If this method is omitted, the screen is dismissed on receival of the LEAVESCREEN key.
@@ -1654,9 +1799,17 @@ global environment, persistent between calls to the script.dfhack.internal.getVTable(name)
Returns the pre-extracted vtable address name, or nil.
dfhack.internal.getImageBase()
+Returns the mmap base of the executable.
+dfhack.internal.getRebaseDelta()
Returns the ASLR rebase offset of the DF executable.
dfhack.internal.adjustOffset(offset[,to_file])
+Returns the re-aligned offset, or nil if invalid. +If to_file is true, the offset is adjusted from memory to file. +This function returns the original value everywhere except windows.
+dfhack.internal.getMemRanges()
Returns a sequence of tables describing virtual memory ranges of the process.
dfhack.internal.patchBytes(write_table[, verify_table])
+The first argument must be a lua table, which is interpreted as a mapping from +memory addresses to byte values that should be stored there. The second argument +may be a similar table of values that need to be checked before writing anything.
+The function takes care to either apply all of write_table, or none of it. +An empty write_table with a nonempty verify_table can be used to reasonably +safely check if the memory contains certain values.
+Returns true if successful, or nil, error_msg, address if not.
+dfhack.internal.memmove(dest,src,count)
Wraps the standard memmove function. Accepts both numbers and refs as pointers.
Functions already described above
safecall, qerror, mkmodule, reload
Miscellaneous constants
+NEWLINE, COMMA, PERIOD: | |
---|---|
evaluate to the relevant character strings. | +|
DEFAULT_NIL: | is an unspecified unique token used by the class module below. | +
printall(obj)
If the argument is a lua table or DF object reference, prints all fields.
xyz2pos(x,y,z)
Returns a table with x, y and z as fields.
same_xyz(a,b)
+Checks if a and b have the same x, y and z fields.
+get_path_xyz(path,i)
+Returns path.x[i], path.y[i], path.z[i].
+pos2xy(obj), xy2pos(x,y), same_xy(a,b), get_path_xy(a,b)
+Same as above, but for 2D coordinates.
+safe_index(obj,index...)
Walks a sequence of dereferences, which may be represented by numbers or strings. Returns nil if any of obj or indices is nil, or a numeric index is out of array bounds.
@@ -1887,11 +2071,25 @@ are converted to 1-based lua sequences. as a guide to which values should be skipped as uninteresting. The force argument makes it always return a non-nil value.utils.parse_bitfield_int(value, type_ref)
+Given an int value, and a bitfield type in the df tree, +it returns a lua table mapping the enabled bit keys to true, +unless value is 0, in which case it returns nil.
+utils.list_bitfield_flags(bitfield[, list])
+Adds all enabled bitfield keys to list or a newly-allocated +empty sequence, and returns it. The bitfield argument may +be nil.
+utils.sort_vector(vector,field,cmpfun)
Sorts a native vector or lua sequence using the comparator function. If field is not nil, applies the comparator to the field instead of the whole object.
utils.linear_index(vector,key[,field])
+Searches for key in the vector, and returns index, found_value, +or nil if none found.
+utils.binsearch(vector,key,field,cmpfun,min,max)
Does a binary search in a native vector or lua sequence for key, using cmpfun and field like sort_vector. @@ -1914,6 +2112,25 @@ utils.insert_or_update(soul.skills, {new=true, id=..., rating=...}, 'id')
(For an explanation of new=true, see table assignment in the wrapper section)
utils.erase_sorted_key(vector,key,field,cmpfun)
+Removes the item with the given key from the list. Returns: did_erase, vector[idx], idx.
+utils.erase_sorted(vector,item,field,cmpfun)
+Exactly like erase_sorted_key, but if field is specified, takes the key from item[field].
+utils.call_with_string(obj,methodname,...)
+Allocates a temporary string object, calls obj:method(tmp,...), and +returns the value written into the temporary after deleting it.
+utils.getBuildingName(building)
+Returns the string description of the given building.
+utils.getBuildingCenter(building)
+Returns an x/y/z table pointing at the building center.
+utils.split_string(string, delimiter)
+Splits the string by the given delimiter, and returns a sequence of results.
+utils.prompt_yes_no(prompt, default)
Presents a yes/no prompt to the user. If default is not nil, allows just pressing Enter to submit the default choice. @@ -1965,19 +2182,31 @@ calling superclass methods.
from fields in the table used as the constructor argument. If omitted, they are initialized with the default values specified in this declaration.If the default value should be nil, use ATTRS { foo = DEFAULT_NIL }.
+Declaring an attribute is mostly the same as defining your init method like this:
++function Class.init(args) + self.attr1 = args.attr1 or default1 + self.attr2 = args.attr2 or default2 + ... +end ++
The main difference is that attributes are processed as a separate +initialization step, before any init methods are called. They +also make the directy relation between instance fields and constructor +arguments more explicit.
new_obj = Class{ foo = arg, bar = arg, ... }
Calling the class as a function creates and initializes a new instance. Initialization happens in this order:
instance:cb_getfield(field_name)
+Returns a closure that returns the specified field of the object when called.
+instance:cb_setfield(field_name)
+Returns a closure that sets the specified field to its argument when called.
+instance:invoke_before(method_name, args...)
Navigates the inheritance chain of the instance starting from the most specific class, and invokes the specified method with the arguments if it is defined in @@ -2016,15 +2251,758 @@ library itself uses them for constructors.
To avoid confusion, these methods cannot be redefined.
A number of lua modules with names starting with gui are dedicated +to wrapping the natives of the dfhack.screen module in a way that +is easy to use. This allows relatively easily and naturally creating +dialogs that integrate in the main game UI window.
+These modules make extensive use of the class module, and define +things ranging from the basic Painter, View and Screen +classes, to fully functional predefined dialogs.
+This module defines the most important classes and functions for +implementing interfaces. This documents those of them that are +considered stable.
+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
+The black pen used to clear the screen.
+simulateInput(screen, keys...)
+This function wraps an undocumented native function that passes a set of +keycodes to a screen, and is the official way to do that.
+Every argument after the initial screen may be nil, a numeric keycode, +a string keycode, a sequence of numeric or string keycodes, or a mapping +of keycodes to true or false. For instance, it is possible to use the +table passed as argument to onInput.
+mkdims_xy(x1,y1,x2,y2)
+Returns a table containing the arguments as fields, and also width and +height that contains the rectangle dimensions.
+mkdims_wh(x1,y1,width,height)
+Returns the same kind of table as mkdims_xy, only this time it computes +x2 and y2.
+is_in_rect(rect,x,y)
+Checks if the given point is within a rectangle, represented by a table produced +by one of the mkdims functions.
+blink_visible(delay)
+Returns true or false, with the value switching to the opposite every delay +msec. This is intended for rendering blinking interface objects.
+getKeyDisplay(keycode)
+Wraps dfhack.screen.getKeyDisplay in order to allow using strings for the keycode argument.
+This class represents an on-screen rectangle with an associated independent +clip area rectangle. It is the base of the Painter class, and is used by +Views to track their client area.
+ViewRect{ rect = ..., clip_rect = ..., view_rect = ..., clip_view = ... }
+The constructor has the following arguments:
+rect: | The mkdims rectangle in screen coordinates of the logical viewport. +Defaults to the whole screen. | +
---|---|
clip_rect: | The clip rectangle in screen coordinates. Defaults to rect. | +
view_rect: | A ViewRect object to copy from; overrides both rect and clip_rect. | +
clip_view: | A ViewRect object to intersect the specified clip area with. | +
rect:isDefunct()
+Returns true if the clip area is empty, i.e. no painting is possible.
+rect:inClipGlobalXY(x,y)
+Checks if these global coordinates are within the clip rectangle.
+rect:inClipLocalXY(x,y)
+Checks if these coordinates (specified relative to x1,y1) are within the clip rectangle.
+rect:localXY(x,y)
+Converts a pair of global coordinates to local; returns x_local,y_local.
+rect:globalXY(x,y)
+Converts a pair of local coordinates to global; returns x_global,y_global.
+rect:viewport(x,y,w,h) or rect:viewport(subrect)
+Returns a ViewRect representing a sub-rectangle of the current one. +The arguments are specified in local coordinates; the subrect +argument must be a mkdims table. The returned object consists of +the exact specified rectangle, and a clip area produced by intersecting +it with the clip area of the original object.
+The painting natives in dfhack.screen apply to the whole screen, are +completely stateless and don't implement clipping.
+The Painter class inherits from ViewRect to provide clipping and local +coordinates, and tracks current cursor position and current pen.
+Painter{ ..., pen = ..., key_pen = ... }
+In addition to ViewRect arguments, Painter accepts a suggestion of +the initial value for the main pen, and the keybinding pen. They +default to COLOR_GREY and COLOR_LIGHTGREEN otherwise.
+There are also some convenience functions that wrap this constructor:
+painter:isValidPos()
+Checks if the current cursor position is within the clip area.
+painter:viewport(x,y,w,h)
+Like the superclass method, but returns a Painter object.
+painter:cursor()
+Returns the current cursor x,y in local coordinates.
+painter:seek(x,y)
+Sets the current cursor position, and returns self. +Either of the arguments may be nil to keep the current value.
+painter:advance(dx,dy)
+Adds the given offsets to the cursor position, and returns self. +Either of the arguments may be nil to keep the current value.
+painter:newline([dx])
+Advances the cursor to the start of the next line plus the given x offset, and returns self.
+painter:pen(...)
+Sets the current pen to dfhack.pen.parse(old_pen,...), and returns self.
+painter:key_pen(...)
+Sets the current keybinding pen to dfhack.pen.parse(old_pen,...), and returns self.
+painter:clear()
+Fills the whole clip rectangle with CLEAR_PEN, and returns self.
+painter:fill(x1,y1,x2,y2[,...]) or painter:fill(rect[,...])
+Fills the specified local coordinate rectangle with dfhack.pen.parse(cur_pen,...), +and returns self.
+painter:char([char[, ...]])
+Paints one character using char and dfhack.pen.parse(cur_pen,...); returns self. +The char argument, if not nil, is used to override the ch property of the pen.
+painter:tile([char, tile[, ...]])
+Like above, but also allows overriding the tile property on ad-hoc basis.
+painter:string(text[, ...])
+Paints the string with dfhack.pen.parse(cur_pen,...); returns self.
+painter:key(keycode[, ...])
+Paints the description of the keycode using dfhack.pen.parse(cur_key_pen,...); returns self.
+As noted above, all painting methods return self, in order to allow chaining them like this:
++painter:pen(foo):seek(x,y):char(1):advance(1):string('bar')... ++
This class is the common abstract base of both the stand-alone screens +and common widgets to be used inside them. It defines the basic layout, +rendering and event handling framework.
+The class defines the following attributes:
+visible: | Specifies that the view should be painted. | +
---|---|
active: | Specifies that the view should receive events, if also visible. | +
view_id: | Specifies an identifier to easily identify the view among subviews. +This is reserved for implementation of top-level views, and should +not be used by widgets for their internal subviews. | +
It also always has the following fields:
+subviews: | Contains a table of all subviews. The sequence part of the +table is used for iteration. In addition, subviews are also +indexed under their view_id, if any; see addviews() below. | +
---|
These fields are computed by the layout process:
+frame_parent_rect: | |
---|---|
The ViewRect represeting the client area of the parent view. | +|
frame_rect: | The mkdims rect of the outer frame in parent-local coordinates. | +
frame_body: | The ViewRect representing the body part of the View's own frame. | +
The class has the following methods:
+view:addviews(list)
+Adds the views in the list to the subviews sequence. If any of the views +in the list have view_id attributes that don't conflict with existing keys +in subviews, also stores them under the string keys. Finally, copies any +non-conflicting string keys from the subviews tables of the listed views.
+Thus, doing something like this:
++self:addviews{ + Panel{ + view_id = 'panel', + subviews = { + Label{ view_id = 'label' } + } + } +} ++
Would make the label accessible as both self.subviews.label and +self.subviews.panel.subviews.label.
+view:getWindowSize()
+Returns the dimensions of the frame_body rectangle.
+view:getMousePos()
+Returns the mouse x,y in coordinates local to the frame_body +rectangle if it is within its clip area, or nothing otherwise.
+view:updateLayout([parent_rect])
+Recomputes layout of the view and its subviews. If no argument is +given, re-uses the previous parent rect. The process goes as follows:
+view:computeFrame(parent_rect) (for overriding)
+Called by updateLayout in order to compute the frame rectangle(s). +Should return the mkdims rectangle for the outer frame, and optionally +also for the body frame. If only one rectangle is returned, it is used +for both frames, and the margin becomes zero.
+view:updateSubviewLayout(frame_body)
+Calls updateLayout on all children.
+view:render(painter)
+Given the parent's painter, renders the view via the following process:
+view:renderSubviews(painter)
+Calls render on all visible subviews in the order they +appear in the subviews sequence.
+view:onRenderFrame(painter, rect) (for overriding)
+Called by render to paint the outer frame; by default does nothing.
+view:onRenderBody(painter) (for overriding)
+Called by render to paint the client area; by default does nothing.
+view:onInput(keys) (for overriding)
+Override this to handle events. By default directly calls inputToSubviews. +Return a true value from this method to signal that the event has been handled +and should not be passed on to more views.
+view:inputToSubviews(keys)
+Calls onInput on all visible active subviews, iterating the subviews +sequence in reverse order, so that topmost subviews get events first. +Returns true if any of the subviews handled the event.
+This is a View subclass intended for use as a stand-alone dialog or screen. +It adds the following methods:
+screen:isShown()
+Returns true if the screen is currently in the game engine's display stack.
+screen:isDismissed()
+Returns true if the screen is dismissed.
+screen:isActive()
+Returns true if the screen is shown and not dismissed.
+screen:invalidate()
+Requests a repaint. Note that currently using it is not necessary, because +repaints are constantly requested automatically, due to issues with native +screens happening otherwise.
+screen:renderParent()
+Asks the parent native screen to render itself, or clears the screen if impossible.
+screen:sendInputToParent(...)
+Uses simulateInput to send keypresses to the native parent screen.
+screen:show([parent])
+Adds the screen to the display stack with the given screen as the parent; +if parent is not specified, places this one one topmost. Before calling +dfhack.screen.show, calls self:onAboutToShow(parent).
+screen:onAboutToShow(parent) (for overriding)
+Called when dfhack.screen.show is about to be called.
+screen:onShow()
+Called by dfhack.screen.show once the screen is successfully shown.
+screen:dismiss()
+Dismisses the screen. A dismissed screen does not receive any more +events or paint requests, but may remain in the display stack for +a short time until the game removes it.
+screen:onDismiss() (for overriding)
+Called by dfhack.screen.dismiss().
+screen:onDestroy() (for overriding)
+Called by the native code when the screen is fully destroyed and removed +from the display stack. Place code that absolutely must be called whenever +the screen is removed by any means here.
+screen:onResize, screen:onRender
+Defined as callbacks for native code.
+A Screen subclass that paints a visible frame around its body. +Most dialogs should inherit from this class.
+A framed screen has the following attributes:
+frame_style: | A table that defines a set of pens to draw various parts of the frame. | +
---|---|
frame_title: | A string to display in the middle of the top of the frame. | +
frame_width: | Desired width of the client area. If nil, the screen will occupy the whole width. | +
frame_height: | Likewise, for height. | +
frame_inset: | The gap between the frame and the client area. Defaults to 0. | +
frame_background: | |
The pen to fill in the frame with. Defaults to CLEAR_PEN. | +
There are the following predefined frame style tables:
+GREY_FRAME
+A plain grey-colored frame.
+BOUNDARY_FRAME
+The same frame as used by the usual full-screen DF views, like dwarfmode.
+GREY_LINE_FRAME
+A frame consisting of grey lines, similar to the one used by titan announcements.
+This module implements some basic widgets based on the View infrastructure.
+Base of all the widgets. Inherits from View and has the following attributes:
+frame = {...}
+Specifies the constraints on the outer frame of the widget. +If omitted, the widget will occupy the whole parent rectangle.
+The frame is specified as a table with the following possible fields:
+l: | gap between the left edges of the frame and the parent. | +
---|---|
t: | gap between the top edges of the frame and the parent. | +
r: | gap between the right edges of the frame and the parent. | +
b: | gap between the bottom edges of the frame and the parent. | +
w: | maximum width of the frame. | +
h: | maximum heigth of the frame. | +
xalign: | X alignment of the frame. | +
yalign: | Y alignment of the frame. | +
First the l,t,r,b fields restrict the available area for +placing the frame. If w and h are not specified or +larger then the computed area, it becomes the frame. Otherwise +the smaller frame is placed within the are based on the +xalign/yalign fields. If the align hints are omitted, they +are assumed to be 0, 1, or 0.5 based on which of the l/r/t/b +fields are set.
+frame_inset = {...}
+Specifies the gap between the outer frame, and the client area. +The attribute may be a simple integer value to specify a uniform +inset, or a table with the following fields:
+l: | left margin. | +
---|---|
t: | top margin. | +
r: | right margin. | +
b: | bottom margin. | +
x: | left/right margin, if l and/or r are omitted. | +
y: | top/bottom margin, if t and/or b are omitted. | +
frame_background = pen
+The pen to fill the outer frame with. Defaults to no fill.
+Inherits from Widget, and intended for grouping a number of subviews.
+Has attributes:
+subviews = {}
+Used to initialize the subview list in the constructor.
+on_render = function(painter)
+Called from onRenderBody.
+Subclass of Panel; keeps exactly one child visible.
+Pages{ ..., selected = ... }
+Specifies which child to select initially; defaults to the first one.
+pages:getSelected()
+Returns the selected index, child.
+pages:setSelected(index)
+Selects the specified child, hiding the previous selected one. +It is permitted to use the subview object, or its view_id as index.
+Subclass of Widget; implements a simple edit field.
+Attributes:
+text: | The current contents of the field. | +
---|---|
text_pen: | The pen to draw the text with. | +
on_char: | Input validation callback; used as on_char(new_char,text). +If it returns false, the character is ignored. | +
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). | +
This Widget subclass implements flowing semi-static text.
+It has the following attributes:
+text_pen: | Specifies the pen for active text. | +
---|---|
text_dpen: | Specifies the pen for disabled text. | +
disabled: | Boolean or a callback; if true, the label is disabled. | +
enabled: | Boolean or a callback; if false, the label is disabled. | +
auto_height: | Sets self.frame.h from the text height. | +
auto_width: | Sets self.frame.w from the text width. | +
The text itself is represented as a complex structure, and passed +to the object via the text argument of the constructor, or via +the setText method, as one of:
+Every token in the sequence in turn may be either a string, possibly +containing newlines, or a table with the following possible fields:
+token.text = ...
+Specifies the main text content of a token, and may be a string, or +a callback returning a string.
+token.gap = ...
+Specifies the number of character positions to advance on the line +before rendering the token.
+token.tile = pen
+Specifies a pen to paint as one tile before the main part of the token.
+token.width = ...
+If specified either as a value or a callback, the text field is padded +or truncated to the specified number.
+token.pad_char = '?'
+If specified together with width, the padding area is filled with +this character instead of just being skipped over.
+token.key = '...'
+Specifies the keycode associated with the token. The string description +of the key binding is added to the text content of the token.
+token.key_sep = '...'
+Specifies the separator to place between the keybinding label produced +by token.key, and the main text of the token. If the separator is +'()', the token is formatted as text..' ('..binding..')'. Otherwise +it is simply binding..sep..text.
+token.enabled, token.disabled
+Same as the attributes of the label itself, but applies only to the token.
+token.pen, token.dpen
+Specify the pen and disabled pen to be used for the token's text. +The field may be either the pen itself, or a callback that returns it.
+token.on_activate
+If this field is not nil, and token.key is set, the token will actually +respond to that key binding unless disabled, and call this callback. Eventually +this may be extended with mouse click support.
+token.id
+Specifies a unique identifier for the token.
+token.line, token.x1, token.x2
+Reserved for internal use.
+The Label widget implements the following methods:
+label:setText(new_text)
+Replaces the text currently contained in the widget.
+label:itemById(id)
+Finds a token by its id field.
+label:getTextHeight()
+Computes the height of the text.
+label:getTextWidth()
+Computes the width of the text.
+The List widget implements a simple list with paging.
+It has the following attributes:
+text_pen: | Specifies the pen for deselected list entries. | +
---|---|
cursor_pen: | Specifies the pen for the selected entry. | +
inactive_pen: | If specified, used for the cursor when the widget is not active. | +
icon_pen: | Default pen for icons. | +
on_select: | Selection change callback; called as on_select(index,choice). +This is also called with nil arguments if setChoices is called +with an empty list. | +
on_submit: | Enter key callback; if specified, the list reacts to the key +and calls it as on_submit(index,choice). | +
on_submit2: | Shift-Enter key callback; if specified, the list reacts to the key +and calls it as on_submit2(index,choice). | +
row_height: | Height of every row in text lines. | +
icon_width: | If not nil, the specified number of character columns +are reserved to the left of the list item for the icons. | +
scroll_keys: | Specifies which keys the list should react to as a table. | +
Every list item may be specified either as a string, or as a lua table +with the following fields:
+text: | Specifies the label text in the same format as the Label text. | +
---|---|
caption, [1]: | Deprecated legacy aliases for text. | +
text_*: | Reserved for internal use. | +
key: | Specifies a keybinding that acts as a shortcut for the specified item. | +
icon: | Specifies an icon string, or a pen to paint a single character. May be a callback. | +
icon_pen: | When the icon is a string, used to paint it. | +
The list supports the following methods:
+List{ ..., choices = ..., selected = ... }
+Same as calling setChoices after construction.
+list:setChoices(choices[, selected])
+Replaces the list of choices, possibly also setting the currently selected index.
+list:setSelected(selected)
+Sets the currently selected index. Returns the index after validation.
+list:getChoices()
+Returns the list of choices.
+list:getSelected()
+Returns the selected index, choice, or nothing if the list is empty.
+list:getContentWidth()
+Returns the minimal width to draw all choices without clipping.
+list:getContentHeight()
+Returns the minimal width to draw all choices without scrolling.
+list:submit()
+Call the on_submit callback, as if the Enter key was handled.
+list:submit2()
+Call the on_submit2 callback, as if the Shift-Enter key was handled.
+This widget combines List, EditField and Label into a combo-box like +construction that allows filtering the list by subwords of its items.
+In addition to passing through all attributes supported by List, it +supports:
+edit_pen: | If specified, used instead of cursor_pen for the edit field. | +
---|---|
edit_below: | If true, the edit field is placed below the list instead of above. | +
not_found_label: | |
Specifies the text of the label shown when no items match the filter. | +
The list choices may include the following attributes:
+search_key: | If specified, used instead of text to match against the filter. | +
---|
The widget implements:
+list:setChoices(choices[, selected])
+Resets the filter, and passes through to the inner list.
+list:getChoices()
+Returns the list of all choices.
+list:getFilter()
+Returns the current filter string, and the filtered list of choices.
+list:setFilter(filter[,pos])
+Sets the new filter string, filters the list, and selects the item at +index pos in the unfiltered list if possible.
+list:canSubmit()
+Checks if there are currently any choices in the filtered list.
+list:getSelected(), list:getContentWidth(), list:getContentHeight(), list:submit()
+Same as with an ordinary list.
+DFHack plugins may export native functions and events to lua contexts. They are automatically imported by mkmodule('plugins.<name>'); this means that a lua module file is still necessary for require to read.
The following plugins have lua support.
Implements extended burrow manipulations.
Events:
The lua module file also re-exports functions from dfhack.burrows.
Does not export any native functions as of now. Instead, it calls lua code to perform the actual ordering of list items.
This plugin exports some events to lua thus allowing to run lua functions +on DF world events.
+onReactionComplete(reaction,unit,input_items,input_reagents,output_items,call_native)
+Auto activates if detects reactions starting with LUA_HOOK_. Is called when reaction finishes.
+onItemContaminateWound(item,unit,wound,number1,number2)
+Is called when item tries to contaminate wound (e.g. stuck in).
+onProjItemCheckMovement(projectile)
+Is called when projectile moves.
+onProjItemCheckImpact(projectile,somebool)
+Is called when projectile hits something.
+onProjUnitCheckMovement(projectile)
+Is called when projectile moves.
+onProjUnitCheckImpact(projectile,somebool)
+Is called when projectile hits something.
+onWorkshopFillSidebarMenu(workshop,callnative)
+Is called when viewing a workshop in 'q' mode, to populate reactions, useful for custom viewscreens for shops.
+postWorkshopFillSidebarMenu(workshop)
+Is called after calling (or not) native fillSidebarMenu(). Useful for job button +tweaking (e.g. adding custom reactions)
+registerReaction(reaction_name,callback)
+Simplified way of using onReactionComplete; the callback is function (same params as event).
+removeNative(shop_name)
+Removes native choice list from the building.
+addReactionToShop(reaction_name,shop_name)
+Add a custom reaction to the building.
+Spawn dragon breath on each item attempt to contaminate wound:
++b=require "plugins.eventful" +b.onItemContaminateWound.one=function(item,unit,un_wound,x,y) + local flw=dfhack.maps.spawnFlow(unit.pos,6,0,0,50000) +end ++
Reaction complete example:
++b=require "plugins.eventful" + +b.onReactionComplete.one=function(reaction,unit,in_items,in_reag,out_items,call_native) + local pos=copyall(unit.pos) + -- spawn dragonbreath after 100 ticks + dfhack.timeout(100,"ticks",function() dfhack.maps.spawnFlow(pos,6,0,0,50000) end) + --do not call real item creation code + call_native.value=false +end ++
Grenade example:
++b=require "plugins.eventful" +b.onProjItemCheckImpact.one=function(projectile) + -- you can check if projectile.item e.g. has correct material + dfhack.maps.spawnFlow(projectile.cur_pos,6,0,0,50000) +end ++
Integrated tannery:
++b=require "plugins.eventful" +b.addReactionToShop("TAN_A_HIDE","LEATHERWORKS") ++
Any files with the .lua extension placed into hack/scripts/* are automatically used by the DFHack core as commands. The matching command name consists of the name of the file sans @@ -2098,6 +3160,25 @@ The name argument should be the name stem, as
Note that this function lets errors propagate to the caller.
+If a save directory contains a file called raw/init.lua, it is +automatically loaded and executed every time the save is loaded. It +can also define the following functions to be called by dfhack:
+function onStateChange(op) ... end
+Automatically called from the regular onStateChange event as long +as the save is still loaded. This avoids the need to install a hook +into the global dfhack.onStateChange table, with associated +cleanup concerns.
+function onUnload() ... end
+Called when the save containing the script is unloaded. This function +should clean up any global hooks installed by the script.
+Within the init script, the path to the save directory is available as SAVE_PATH.
+diff --git a/Lua API.rst b/Lua API.rst index bf7ee45a7..6d4e6b51b 100644 --- a/Lua API.rst +++ b/Lua API.rst @@ -646,6 +646,24 @@ and automatically stored in the save game, these save and retrieval functions can just copy values in memory without doing any actual I/O. However, currently every entry has a 180+-byte dead-weight overhead. +It is also possible to associate one bit per map tile with an entry, +using these two methods: + +* ``entry:getTilemask(block[, create])`` + + Retrieves the tile bitmask associated with this entry in the given map + block. If ``create`` is *true*, an empty mask is created if none exists; + otherwise the function returns *nil*, which must be assumed to be the same + as an all-zero mask. + +* ``entry:deleteTilemask(block)`` + + Deletes the associated tile mask from the given map block. + +Note that these masks are only saved in fortress mode, and also that deleting +the persistent entry will **NOT** delete the associated masks. + + Material info lookup -------------------- @@ -723,6 +741,10 @@ can be omitted. Returns the dfhack directory path, i.e. ``".../df/hack/"``. +* ``dfhack.getSavePath()`` + + Returns the path to the current save directory, or *nil* if no save loaded. + * ``dfhack.getTickCount()`` Returns the tick count in ms, exactly as DF ui uses. @@ -815,6 +837,14 @@ Job module Prints info about the job item. +* ``dfhack.job.getGeneralRef(job, type)`` + + Searches for a general_ref with the given type. + +* ``dfhack.job.getSpecificRef(job, type)`` + + Searches for a specific_ref with the given type. + * ``dfhack.job.getHolder(job)`` Returns the building holding the job. @@ -845,6 +875,15 @@ Job module if there are any jobs with ``first_id <= id < job_next_id``, a lua list containing them. +* ``dfhack.job.isSuitableItem(job_item, item_type, item_subtype)`` + + Does basic sanity checks to verify if the suggested item type matches + the flags in the job item. + +* ``dfhack.job.isSuitableMaterial(job_item, mat_type, mat_index)`` + + Likewise, if replacing material. + Units module ------------ @@ -852,6 +891,14 @@ Units module Returns true *x,y,z* of the unit, or *nil* if invalid; may be not equal to unit.pos if caged. +* ``dfhack.units.getGeneralRef(unit, type)`` + + Searches for a general_ref with the given type. + +* ``dfhack.units.getSpecificRef(unit, type)`` + + Searches for a specific_ref with the given type. + * ``dfhack.units.getContainer(unit)`` Returns the container (cage) item or *nil*. @@ -927,6 +974,10 @@ Units module Computes the effective rating for the given skill, taking into account exhaustion, pain etc. +* ``dfhack.units.getExperience(unit, skill[, total])`` + + Returns the experience value for the given skill. If ``total`` is true, adds experience implied by the current rating. + * ``dfhack.units.computeMovementSpeed(unit)`` Computes number of frames * 100 it takes the unit to move in its current state of mind and body. @@ -992,6 +1043,14 @@ Items module Returns a list of items contained in this one. +* ``dfhack.items.getHolderBuilding(item)`` + + Returns the holder building or *nil*. + +* ``dfhack.items.getHolderUnit(item)`` + + Returns the holder unit or *nil*. + * ``dfhack.items.moveToGround(item,pos)`` Move the item to the ground at position. Returns *false* if impossible. @@ -1016,6 +1075,18 @@ Items module Turns the item into a projectile, and returns the new object, or *nil* if impossible. +* ``dfhack.items.isCasteMaterial(item_type)`` + + Returns *true* if this item type uses a creature/caste pair as its material. + +* ``dfhack.items.getSubtypeCount(item_type)`` + + Returns the number of raw-defined subtypes of the given item type, or *-1* if not applicable. + +* ``dfhack.items.getSubtypeDef(item_type, subtype)`` + + Returns the raw definition for the given item type and subtype, or *nil* if invalid. + Maps module ----------- @@ -1032,7 +1103,7 @@ Maps module Returns a map block object for given x,y,z in local block coordinates. -* ``dfhack.maps.isValidTilePos(coords)``, or isValidTilePos(x,y,z)`` +* ``dfhack.maps.isValidTilePos(coords)``, or ``isValidTilePos(x,y,z)`` Checks if the given df::coord or x,y,z in local tile coordinates are valid. @@ -1044,6 +1115,14 @@ Maps module Like ``getTileBlock``, but if the block is not allocated, try creating it. +* ``dfhack.maps.getTileType(coords)``, or ``getTileType(x,y,z)`` + + Returns the tile type at the given coordinates, or *nil* if invalid. + +* ``dfhack.maps.getTileFlags(coords)``, or ``getTileFlags(x,y,z)`` + + Returns designation and occupancy references for the given coordinates, or *nil, nil* if invalid. + * ``dfhack.maps.getRegionBiome(region_coord2d)``, or ``getRegionBiome(x,y)`` Returns the biome info struct for the given global map region. @@ -1079,6 +1158,22 @@ Maps module take into account anything that depends on the actual units, like burrows, or the presence of invaders. +* ``dfhack.maps.hasTileAssignment(tilemask)`` + + Checks if the tile_bitmask object is not *nil* and contains any set bits; returns *true* or *false*. + +* ``dfhack.maps.getTileAssignment(tilemask,x,y)`` + + Checks if the tile_bitmask object is not *nil* and has the relevant bit set; returns *true* or *false*. + +* ``dfhack.maps.setTileAssignment(tilemask,x,y,enable)`` + + Sets the relevant bit in the tile_bitmask object to the *enable* argument. + +* ``dfhack.maps.resetTileAssignment(tilemask[,enable])`` + + Sets all bits in the mask to the *enable* argument. + Burrows module -------------- @@ -1127,6 +1222,14 @@ Burrows module Buildings module ---------------- +* ``dfhack.buildings.getGeneralRef(building, type)`` + + Searches for a general_ref with the given type. + +* ``dfhack.buildings.getSpecificRef(building, type)`` + + Searches for a specific_ref with the given type. + * ``dfhack.buildings.setOwner(item,unit)`` Replaces the owner of the building. If unit is *nil*, removes ownership. @@ -1332,31 +1435,14 @@ Basic painting functions: * ``dfhack.screen.paintTile(pen,x,y[,char,tile])`` - Paints a tile using given parameters. Pen is a table with following possible fields: - - ``ch`` - Provides the ordinary tile character, as either a 1-character string or a number. - Can be overridden with the ``char`` function parameter. - ``fg`` - Foreground color for the ordinary tile. Defaults to COLOR_GREY (7). - ``bg`` - Background color for the ordinary tile. Defaults to COLOR_BLACK (0). - ``bold`` - Bright/bold text flag. If *nil*, computed based on (fg & 8); fg is masked to 3 bits. - Otherwise should be *true/false*. - ``tile`` - Graphical tile id. Ignored unless [GRAPHICS:YES] was in init.txt. - ``tile_color = true`` - Specifies that the tile should be shaded with *fg/bg*. - ``tile_fg, tile_bg`` - If specified, overrides *tile_color* and supplies shading colors directly. + Paints a tile using given parameters. See below for a description of pen. Returns *false* if coordinates out of bounds, or other error. * ``dfhack.screen.readTile(x,y)`` Retrieves the contents of the specified tile from the screen buffers. - Returns a pen, or *nil* if invalid or TrueType. + Returns a pen object, or *nil* if invalid or TrueType. * ``dfhack.screen.paintString(pen,x,y,text)`` @@ -1387,6 +1473,66 @@ Basic painting functions: Requests repaint of the screen by setting a flag. Unlike other functions in this section, this may be used at any time. +* ``dfhack.screen.getKeyDisplay(key)`` + + Returns the string that should be used to represent the given + logical keybinding on the screen in texts like "press Key to ...". + +The "pen" argument used by functions above may be represented by +a table with the following possible fields: + + ``ch`` + Provides the ordinary tile character, as either a 1-character string or a number. + Can be overridden with the ``char`` function parameter. + ``fg`` + Foreground color for the ordinary tile. Defaults to COLOR_GREY (7). + ``bg`` + Background color for the ordinary tile. Defaults to COLOR_BLACK (0). + ``bold`` + Bright/bold text flag. If *nil*, computed based on (fg & 8); fg is masked to 3 bits. + Otherwise should be *true/false*. + ``tile`` + Graphical tile id. Ignored unless [GRAPHICS:YES] was in init.txt. + ``tile_color = true`` + Specifies that the tile should be shaded with *fg/bg*. + ``tile_fg, tile_bg`` + If specified, overrides *tile_color* and supplies shading colors directly. + +Alternatively, it may be a pre-parsed native object with the following API: + +* ``dfhack.pen.make(base[,pen_or_fg,bg,bold])`` + + Creates a new pre-parsed pen by combining its arguments according to the + following rules: + + 1. The ``base`` argument may be a pen object, a pen table as specified above, + or a single color value. In the single value case, it is split into + ``fg`` and ``bold`` properties, and others are initialized to 0. + This argument will be converted to a pre-parsed object and returned + if there are no other arguments. + + 2. If the ``pen_or_fg`` argument is specified as a table or object, it + completely replaces the base, and is returned instead of it. + + 3. Otherwise, the non-nil subset of the optional arguments is used + to update the ``fg``, ``bg`` and ``bold`` properties of the base. + If the ``bold`` flag is *nil*, but *pen_or_fg* is a number, ``bold`` + is deduced from it like in the simple base case. + + This function always returns a new pre-parsed pen, or *nil*. + +* ``dfhack.pen.parse(base[,pen_or_fg,bg,bold])`` + + Exactly like the above function, but returns ``base`` or ``pen_or_fg`` + directly if they are already a pre-parsed native object. + +* ``pen.property``, ``pen.property = value``, ``pairs(pen)`` + + Pre-parsed pens support reading and setting their properties, + but don't behave exactly like a simple table would; for instance, + assigning to ``pen.tile_color`` also resets ``pen.tile_fg`` and + ``pen.tile_bg`` to *nil*. + In order to actually be able to paint to the screen, it is necessary to create and register a viewscreen (basically a modal dialog) with the game. @@ -1468,7 +1614,10 @@ Supported callbacks and fields are: Maps to an integer in range 0-255. Duplicates a separate "STRING_A???" code for convenience. ``_MOUSE_L, _MOUSE_R`` - If the left or right mouse button is pressed. + If the left or right mouse button is being pressed. + + ``_MOUSE_L_DOWN, _MOUSE_R_DOWN`` + If the left or right mouse button was just pressed. If this method is omitted, the screen is dismissed on receival of the ``LEAVESCREEN`` key. @@ -1504,10 +1653,20 @@ and are only documented here for completeness: Returns the pre-extracted vtable address ``name``, or *nil*. +* ``dfhack.internal.getImageBase()`` + + Returns the mmap base of the executable. + * ``dfhack.internal.getRebaseDelta()`` Returns the ASLR rebase offset of the DF executable. +* ``dfhack.internal.adjustOffset(offset[,to_file])`` + + Returns the re-aligned offset, or *nil* if invalid. + If ``to_file`` is true, the offset is adjusted from memory to file. + This function returns the original value everywhere except windows. + * ``dfhack.internal.getMemRanges()`` Returns a sequence of tables describing virtual memory ranges of the process. @@ -1518,6 +1677,18 @@ and are only documented here for completeness: If destination overlaps a completely invalid memory region, or another error occurs, returns false. +* ``dfhack.internal.patchBytes(write_table[, verify_table])`` + + The first argument must be a lua table, which is interpreted as a mapping from + memory addresses to byte values that should be stored there. The second argument + may be a similar table of values that need to be checked before writing anything. + + The function takes care to either apply all of ``write_table``, or none of it. + An empty ``write_table`` with a nonempty ``verify_table`` can be used to reasonably + safely check if the memory contains certain values. + + Returns *true* if successful, or *nil, error_msg, address* if not. + * ``dfhack.internal.memmove(dest,src,count)`` Wraps the standard memmove function. Accepts both numbers and refs as pointers. @@ -1675,6 +1846,11 @@ environment by the mandatory init file dfhack.lua: safecall, qerror, mkmodule, reload +* Miscellaneous constants + + :NEWLINE, COMMA, PERIOD: evaluate to the relevant character strings. + :DEFAULT_NIL: is an unspecified unique token used by the class module below. + * ``printall(obj)`` If the argument is a lua table or DF object reference, prints all fields. @@ -1693,6 +1869,18 @@ environment by the mandatory init file dfhack.lua: Returns a table with x, y and z as fields. +* ``same_xyz(a,b)`` + + Checks if ``a`` and ``b`` have the same x, y and z fields. + +* ``get_path_xyz(path,i)`` + + Returns ``path.x[i], path.y[i], path.z[i]``. + +* ``pos2xy(obj)``, ``xy2pos(x,y)``, ``same_xy(a,b)``, ``get_path_xy(a,b)`` + + Same as above, but for 2D coordinates. + * ``safe_index(obj,index...)`` Walks a sequence of dereferences, which may be represented by numbers or strings. @@ -1773,12 +1961,29 @@ utils as a guide to which values should be skipped as uninteresting. The ``force`` argument makes it always return a non-*nil* value. +* ``utils.parse_bitfield_int(value, type_ref)`` + + Given an int ``value``, and a bitfield type in the ``df`` tree, + it returns a lua table mapping the enabled bit keys to *true*, + unless value is 0, in which case it returns *nil*. + +* ``utils.list_bitfield_flags(bitfield[, list])`` + + Adds all enabled bitfield keys to ``list`` or a newly-allocated + empty sequence, and returns it. The ``bitfield`` argument may + be *nil*. + * ``utils.sort_vector(vector,field,cmpfun)`` Sorts a native vector or lua sequence using the comparator function. If ``field`` is not *nil*, applies the comparator to the field instead of the whole object. +* ``utils.linear_index(vector,key[,field])`` + + Searches for ``key`` in the vector, and returns *index, found_value*, + or *nil* if none found. + * ``utils.binsearch(vector,key,field,cmpfun,min,max)`` Does a binary search in a native vector or lua sequence for @@ -1806,6 +2011,31 @@ utils (For an explanation of ``new=true``, see table assignment in the wrapper section) +* ``utils.erase_sorted_key(vector,key,field,cmpfun)`` + + Removes the item with the given key from the list. Returns: *did_erase, vector[idx], idx*. + +* ``utils.erase_sorted(vector,item,field,cmpfun)`` + + Exactly like ``erase_sorted_key``, but if field is specified, takes the key from ``item[field]``. + +* ``utils.call_with_string(obj,methodname,...)`` + + Allocates a temporary string object, calls ``obj:method(tmp,...)``, and + returns the value written into the temporary after deleting it. + +* ``utils.getBuildingName(building)`` + + Returns the string description of the given building. + +* ``utils.getBuildingCenter(building)`` + + Returns an x/y/z table pointing at the building center. + +* ``utils.split_string(string, delimiter)`` + + Splits the string by the given delimiter, and returns a sequence of results. + * ``utils.prompt_yes_no(prompt, default)`` Presents a yes/no prompt to the user. If ``default`` is not *nil*, @@ -1865,19 +2095,32 @@ Implements a trivial single-inheritance class system. If the default value should be *nil*, use ``ATTRS { foo = DEFAULT_NIL }``. + Declaring an attribute is mostly the same as defining your ``init`` method like this:: + + function Class.init(args) + self.attr1 = args.attr1 or default1 + self.attr2 = args.attr2 or default2 + ... + end + + The main difference is that attributes are processed as a separate + initialization step, before any ``init`` methods are called. They + also make the directy relation between instance fields and constructor + arguments more explicit. + * ``new_obj = Class{ foo = arg, bar = arg, ... }`` Calling the class as a function creates and initializes a new instance. Initialization happens in this order: 1. An empty instance table is created, and its metatable set. - 2. The ``preinit`` method is called via ``invoke_before`` (see below) - with the table used as argument to the class. This method is intended + 2. The ``preinit`` methods are called via ``invoke_before`` (see below) + with the table used as argument to the class. These methods are intended for validating and tweaking that argument table. 3. Declared ATTRS are initialized from the argument table or their default values. - 4. The ``init`` method is called via ``invoke_after`` with the argument table. + 4. The ``init`` methods are called via ``invoke_after`` with the argument table. This is the main constructor method. - 5. The ``postinit`` method is called via ``invoke_after`` with the argument table. + 5. The ``postinit`` methods are called via ``invoke_after`` with the argument table. Place code that should be called after the object is fully constructed here. Predefined instance methods: @@ -1892,6 +2135,14 @@ Predefined instance methods: properly passing in self, and optionally a number of initial arguments too. The arguments given to the closure are appended to these. +* ``instance:cb_getfield(field_name)`` + + Returns a closure that returns the specified field of the object when called. + +* ``instance:cb_setfield(field_name)`` + + Returns a closure that sets the specified field to its argument when called. + * ``instance:invoke_before(method_name, args...)`` Navigates the inheritance chain of the instance starting from the most specific @@ -1916,6 +2167,734 @@ Predefined instance methods: To avoid confusion, these methods cannot be redefined. +================== +In-game UI Library +================== + +A number of lua modules with names starting with ``gui`` are dedicated +to wrapping the natives of the ``dfhack.screen`` module in a way that +is easy to use. This allows relatively easily and naturally creating +dialogs that integrate in the main game UI window. + +These modules make extensive use of the ``class`` module, and define +things ranging from the basic ``Painter``, ``View`` and ``Screen`` +classes, to fully functional predefined dialogs. + +gui +=== + +This module defines the most important classes and functions for +implementing interfaces. This documents those of them that are +considered stable. + + +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`` + + The black pen used to clear the screen. + +* ``simulateInput(screen, keys...)`` + + This function wraps an undocumented native function that passes a set of + keycodes to a screen, and is the official way to do that. + + Every argument after the initial screen may be *nil*, a numeric keycode, + a string keycode, a sequence of numeric or string keycodes, or a mapping + of keycodes to *true* or *false*. For instance, it is possible to use the + table passed as argument to ``onInput``. + +* ``mkdims_xy(x1,y1,x2,y2)`` + + Returns a table containing the arguments as fields, and also ``width`` and + ``height`` that contains the rectangle dimensions. + +* ``mkdims_wh(x1,y1,width,height)`` + + Returns the same kind of table as ``mkdims_xy``, only this time it computes + ``x2`` and ``y2``. + +* ``is_in_rect(rect,x,y)`` + + Checks if the given point is within a rectangle, represented by a table produced + by one of the ``mkdims`` functions. + +* ``blink_visible(delay)`` + + Returns *true* or *false*, with the value switching to the opposite every ``delay`` + msec. This is intended for rendering blinking interface objects. + +* ``getKeyDisplay(keycode)`` + + Wraps ``dfhack.screen.getKeyDisplay`` in order to allow using strings for the keycode argument. + + +ViewRect class +-------------- + +This class represents an on-screen rectangle with an associated independent +clip area rectangle. It is the base of the ``Painter`` class, and is used by +``Views`` to track their client area. + +* ``ViewRect{ rect = ..., clip_rect = ..., view_rect = ..., clip_view = ... }`` + + The constructor has the following arguments: + + :rect: The ``mkdims`` rectangle in screen coordinates of the logical viewport. + Defaults to the whole screen. + :clip_rect: The clip rectangle in screen coordinates. Defaults to ``rect``. + :view_rect: A ViewRect object to copy from; overrides both ``rect`` and ``clip_rect``. + :clip_view: A ViewRect object to intersect the specified clip area with. + +* ``rect:isDefunct()`` + + Returns *true* if the clip area is empty, i.e. no painting is possible. + +* ``rect:inClipGlobalXY(x,y)`` + + Checks if these global coordinates are within the clip rectangle. + +* ``rect:inClipLocalXY(x,y)`` + + Checks if these coordinates (specified relative to ``x1,y1``) are within the clip rectangle. + +* ``rect:localXY(x,y)`` + + Converts a pair of global coordinates to local; returns *x_local,y_local*. + +* ``rect:globalXY(x,y)`` + + Converts a pair of local coordinates to global; returns *x_global,y_global*. + +* ``rect:viewport(x,y,w,h)`` or ``rect:viewport(subrect)`` + + Returns a ViewRect representing a sub-rectangle of the current one. + The arguments are specified in local coordinates; the ``subrect`` + argument must be a ``mkdims`` table. The returned object consists of + the exact specified rectangle, and a clip area produced by intersecting + it with the clip area of the original object. + + +Painter class +------------- + +The painting natives in ``dfhack.screen`` apply to the whole screen, are +completely stateless and don't implement clipping. + +The Painter class inherits from ViewRect to provide clipping and local +coordinates, and tracks current cursor position and current pen. + +* ``Painter{ ..., pen = ..., key_pen = ... }`` + + In addition to ViewRect arguments, Painter accepts a suggestion of + the initial value for the main pen, and the keybinding pen. They + default to COLOR_GREY and COLOR_LIGHTGREEN otherwise. + + There are also some convenience functions that wrap this constructor: + + - ``Painter.new(rect,pen)`` + - ``Painter.new_view(view_rect,pen)`` + - ``Painter.new_xy(x1,y1,x2,y2,pen)`` + - ``Painter.new_wh(x1,y1,width,height,pen)`` + +* ``painter:isValidPos()`` + + Checks if the current cursor position is within the clip area. + +* ``painter:viewport(x,y,w,h)`` + + Like the superclass method, but returns a Painter object. + +* ``painter:cursor()`` + + Returns the current cursor *x,y* in local coordinates. + +* ``painter:seek(x,y)`` + + Sets the current cursor position, and returns *self*. + Either of the arguments may be *nil* to keep the current value. + +* ``painter:advance(dx,dy)`` + + Adds the given offsets to the cursor position, and returns *self*. + Either of the arguments may be *nil* to keep the current value. + +* ``painter:newline([dx])`` + + Advances the cursor to the start of the next line plus the given x offset, and returns *self*. + +* ``painter:pen(...)`` + + Sets the current pen to ``dfhack.pen.parse(old_pen,...)``, and returns *self*. + +* ``painter:key_pen(...)`` + + Sets the current keybinding pen to ``dfhack.pen.parse(old_pen,...)``, and returns *self*. + +* ``painter:clear()`` + + Fills the whole clip rectangle with ``CLEAR_PEN``, and returns *self*. + +* ``painter:fill(x1,y1,x2,y2[,...])`` or ``painter:fill(rect[,...])`` + + Fills the specified local coordinate rectangle with ``dfhack.pen.parse(cur_pen,...)``, + and returns *self*. + +* ``painter:char([char[, ...]])`` + + Paints one character using ``char`` and ``dfhack.pen.parse(cur_pen,...)``; returns *self*. + The ``char`` argument, if not nil, is used to override the ``ch`` property of the pen. + +* ``painter:tile([char, tile[, ...]])`` + + Like above, but also allows overriding the ``tile`` property on ad-hoc basis. + +* ``painter:string(text[, ...])`` + + Paints the string with ``dfhack.pen.parse(cur_pen,...)``; returns *self*. + +* ``painter:key(keycode[, ...])`` + + Paints the description of the keycode using ``dfhack.pen.parse(cur_key_pen,...)``; returns *self*. + +As noted above, all painting methods return *self*, in order to allow chaining them like this:: + + painter:pen(foo):seek(x,y):char(1):advance(1):string('bar')... + + +View class +---------- + +This class is the common abstract base of both the stand-alone screens +and common widgets to be used inside them. It defines the basic layout, +rendering and event handling framework. + +The class defines the following attributes: + +:visible: Specifies that the view should be painted. +:active: Specifies that the view should receive events, if also visible. +:view_id: Specifies an identifier to easily identify the view among subviews. + This is reserved for implementation of top-level views, and should + not be used by widgets for their internal subviews. + +It also always has the following fields: + +:subviews: Contains a table of all subviews. The sequence part of the + table is used for iteration. In addition, subviews are also + indexed under their *view_id*, if any; see ``addviews()`` below. + +These fields are computed by the layout process: + +:frame_parent_rect: The ViewRect represeting the client area of the parent view. +:frame_rect: The ``mkdims`` rect of the outer frame in parent-local coordinates. +:frame_body: The ViewRect representing the body part of the View's own frame. + +The class has the following methods: + +* ``view:addviews(list)`` + + Adds the views in the list to the ``subviews`` sequence. If any of the views + in the list have ``view_id`` attributes that don't conflict with existing keys + in ``subviews``, also stores them under the string keys. Finally, copies any + non-conflicting string keys from the ``subviews`` tables of the listed views. + + Thus, doing something like this:: + + self:addviews{ + Panel{ + view_id = 'panel', + subviews = { + Label{ view_id = 'label' } + } + } + } + + Would make the label accessible as both ``self.subviews.label`` and + ``self.subviews.panel.subviews.label``. + +* ``view:getWindowSize()`` + + Returns the dimensions of the ``frame_body`` rectangle. + +* ``view:getMousePos()`` + + Returns the mouse *x,y* in coordinates local to the ``frame_body`` + rectangle if it is within its clip area, or nothing otherwise. + +* ``view:updateLayout([parent_rect])`` + + Recomputes layout of the view and its subviews. If no argument is + given, re-uses the previous parent rect. The process goes as follows: + + 1. Calls ``preUpdateLayout(parent_rect)`` via ``invoke_before``. + 2. Uses ``computeFrame(parent_rect)`` to compute the desired frame. + 3. Calls ``postComputeFrame(frame_body)`` via ``invoke_after``. + 4. Calls ``updateSubviewLayout(frame_body)`` to update children. + 5. Calls ``postUpdateLayout(frame_body)`` via ``invoke_after``. + +* ``view:computeFrame(parent_rect)`` *(for overriding)* + + Called by ``updateLayout`` in order to compute the frame rectangle(s). + Should return the ``mkdims`` rectangle for the outer frame, and optionally + also for the body frame. If only one rectangle is returned, it is used + for both frames, and the margin becomes zero. + +* ``view:updateSubviewLayout(frame_body)`` + + Calls ``updateLayout`` on all children. + +* ``view:render(painter)`` + + Given the parent's painter, renders the view via the following process: + + 1. Calls ``onRenderFrame(painter, frame_rect)`` to paint the outer frame. + 2. Creates a new painter using the ``frame_body`` rect. + 3. Calls ``onRenderBody(new_painter)`` to paint the client area. + 4. Calls ``renderSubviews(new_painter)`` to paint visible children. + +* ``view:renderSubviews(painter)`` + + Calls ``render`` on all ``visible`` subviews in the order they + appear in the ``subviews`` sequence. + +* ``view:onRenderFrame(painter, rect)`` *(for overriding)* + + Called by ``render`` to paint the outer frame; by default does nothing. + +* ``view:onRenderBody(painter)`` *(for overriding)* + + Called by ``render`` to paint the client area; by default does nothing. + +* ``view:onInput(keys)`` *(for overriding)* + + Override this to handle events. By default directly calls ``inputToSubviews``. + Return a true value from this method to signal that the event has been handled + and should not be passed on to more views. + +* ``view:inputToSubviews(keys)`` + + Calls ``onInput`` on all visible active subviews, iterating the ``subviews`` + sequence in *reverse order*, so that topmost subviews get events first. + Returns *true* if any of the subviews handled the event. + + +Screen class +------------ + +This is a View subclass intended for use as a stand-alone dialog or screen. +It adds the following methods: + +* ``screen:isShown()`` + + Returns *true* if the screen is currently in the game engine's display stack. + +* ``screen:isDismissed()`` + + Returns *true* if the screen is dismissed. + +* ``screen:isActive()`` + + Returns *true* if the screen is shown and not dismissed. + +* ``screen:invalidate()`` + + Requests a repaint. Note that currently using it is not necessary, because + repaints are constantly requested automatically, due to issues with native + screens happening otherwise. + +* ``screen:renderParent()`` + + Asks the parent native screen to render itself, or clears the screen if impossible. + +* ``screen:sendInputToParent(...)`` + + Uses ``simulateInput`` to send keypresses to the native parent screen. + +* ``screen:show([parent])`` + + Adds the screen to the display stack with the given screen as the parent; + if parent is not specified, places this one one topmost. Before calling + ``dfhack.screen.show``, calls ``self:onAboutToShow(parent)``. + +* ``screen:onAboutToShow(parent)`` *(for overriding)* + + Called when ``dfhack.screen.show`` is about to be called. + +* ``screen:onShow()`` + + Called by ``dfhack.screen.show`` once the screen is successfully shown. + +* ``screen:dismiss()`` + + Dismisses the screen. A dismissed screen does not receive any more + events or paint requests, but may remain in the display stack for + a short time until the game removes it. + +* ``screen:onDismiss()`` *(for overriding)* + + Called by ``dfhack.screen.dismiss()``. + +* ``screen:onDestroy()`` *(for overriding)* + + Called by the native code when the screen is fully destroyed and removed + from the display stack. Place code that absolutely must be called whenever + the screen is removed by any means here. + +* ``screen:onResize``, ``screen:onRender`` + + Defined as callbacks for native code. + + +FramedScreen class +------------------ + +A Screen subclass that paints a visible frame around its body. +Most dialogs should inherit from this class. + +A framed screen has the following attributes: + +:frame_style: A table that defines a set of pens to draw various parts of the frame. +:frame_title: A string to display in the middle of the top of the frame. +:frame_width: Desired width of the client area. If *nil*, the screen will occupy the whole width. +:frame_height: Likewise, for height. +:frame_inset: The gap between the frame and the client area. Defaults to 0. +:frame_background: The pen to fill in the frame with. Defaults to CLEAR_PEN. + +There are the following predefined frame style tables: + +* ``GREY_FRAME`` + + A plain grey-colored frame. + +* ``BOUNDARY_FRAME`` + + The same frame as used by the usual full-screen DF views, like dwarfmode. + +* ``GREY_LINE_FRAME`` + + A frame consisting of grey lines, similar to the one used by titan announcements. + + +gui.widgets +=========== + +This module implements some basic widgets based on the View infrastructure. + +Widget class +------------ + +Base of all the widgets. Inherits from View and has the following attributes: + +* ``frame = {...}`` + + Specifies the constraints on the outer frame of the widget. + If omitted, the widget will occupy the whole parent rectangle. + + The frame is specified as a table with the following possible fields: + + :l: gap between the left edges of the frame and the parent. + :t: gap between the top edges of the frame and the parent. + :r: gap between the right edges of the frame and the parent. + :b: gap between the bottom edges of the frame and the parent. + :w: maximum width of the frame. + :h: maximum heigth of the frame. + :xalign: X alignment of the frame. + :yalign: Y alignment of the frame. + + First the ``l,t,r,b`` fields restrict the available area for + placing the frame. If ``w`` and ``h`` are not specified or + larger then the computed area, it becomes the frame. Otherwise + the smaller frame is placed within the are based on the + ``xalign/yalign`` fields. If the align hints are omitted, they + are assumed to be 0, 1, or 0.5 based on which of the ``l/r/t/b`` + fields are set. + +* ``frame_inset = {...}`` + + Specifies the gap between the outer frame, and the client area. + The attribute may be a simple integer value to specify a uniform + inset, or a table with the following fields: + + :l: left margin. + :t: top margin. + :r: right margin. + :b: bottom margin. + :x: left/right margin, if ``l`` and/or ``r`` are omitted. + :y: top/bottom margin, if ``t`` and/or ``b`` are omitted. + +* ``frame_background = pen`` + + The pen to fill the outer frame with. Defaults to no fill. + +Panel class +----------- + +Inherits from Widget, and intended for grouping a number of subviews. + +Has attributes: + +* ``subviews = {}`` + + Used to initialize the subview list in the constructor. + +* ``on_render = function(painter)`` + + Called from ``onRenderBody``. + +Pages class +----------- + +Subclass of Panel; keeps exactly one child visible. + +* ``Pages{ ..., selected = ... }`` + + Specifies which child to select initially; defaults to the first one. + +* ``pages:getSelected()`` + + Returns the selected *index, child*. + +* ``pages:setSelected(index)`` + + Selects the specified child, hiding the previous selected one. + It is permitted to use the subview object, or its ``view_id`` as index. + +EditField class +--------------- + +Subclass of Widget; implements a simple edit field. + +Attributes: + +:text: The current contents of the field. +:text_pen: The pen to draw the text with. +:on_char: Input validation callback; used as ``on_char(new_char,text)``. + If it returns false, the character is ignored. +: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)``. + +Label class +----------- + +This Widget subclass implements flowing semi-static text. + +It has the following attributes: + +:text_pen: Specifies the pen for active text. +:text_dpen: Specifies the pen for disabled text. +:disabled: Boolean or a callback; if true, the label is disabled. +:enabled: Boolean or a callback; if false, the label is disabled. +:auto_height: Sets self.frame.h from the text height. +:auto_width: Sets self.frame.w from the text width. + +The text itself is represented as a complex structure, and passed +to the object via the ``text`` argument of the constructor, or via +the ``setText`` method, as one of: + +* A simple string, possibly containing newlines. +* A sequence of tokens. + +Every token in the sequence in turn may be either a string, possibly +containing newlines, or a table with the following possible fields: + +* ``token.text = ...`` + + Specifies the main text content of a token, and may be a string, or + a callback returning a string. + +* ``token.gap = ...`` + + Specifies the number of character positions to advance on the line + before rendering the token. + +* ``token.tile = pen`` + + Specifies a pen to paint as one tile before the main part of the token. + +* ``token.width = ...`` + + If specified either as a value or a callback, the text field is padded + or truncated to the specified number. + +* ``token.pad_char = '?'`` + + If specified together with ``width``, the padding area is filled with + this character instead of just being skipped over. + +* ``token.key = '...'`` + + Specifies the keycode associated with the token. The string description + of the key binding is added to the text content of the token. + +* ``token.key_sep = '...'`` + + Specifies the separator to place between the keybinding label produced + by ``token.key``, and the main text of the token. If the separator is + '()', the token is formatted as ``text..' ('..binding..')'``. Otherwise + it is simply ``binding..sep..text``. + +* ``token.enabled``, ``token.disabled`` + + Same as the attributes of the label itself, but applies only to the token. + +* ``token.pen``, ``token.dpen`` + + Specify the pen and disabled pen to be used for the token's text. + The field may be either the pen itself, or a callback that returns it. + +* ``token.on_activate`` + + If this field is not nil, and ``token.key`` is set, the token will actually + respond to that key binding unless disabled, and call this callback. Eventually + this may be extended with mouse click support. + +* ``token.id`` + + Specifies a unique identifier for the token. + +* ``token.line``, ``token.x1``, ``token.x2`` + + Reserved for internal use. + +The Label widget implements the following methods: + +* ``label:setText(new_text)`` + + Replaces the text currently contained in the widget. + +* ``label:itemById(id)`` + + Finds a token by its ``id`` field. + +* ``label:getTextHeight()`` + + Computes the height of the text. + +* ``label:getTextWidth()`` + + Computes the width of the text. + +List class +---------- + +The List widget implements a simple list with paging. + +It has the following attributes: + +:text_pen: Specifies the pen for deselected list entries. +:cursor_pen: Specifies the pen for the selected entry. +:inactive_pen: If specified, used for the cursor when the widget is not active. +:icon_pen: Default pen for icons. +:on_select: Selection change callback; called as ``on_select(index,choice)``. + This is also called with *nil* arguments if ``setChoices`` is called + with an empty list. +:on_submit: Enter key callback; if specified, the list reacts to the key + and calls it as ``on_submit(index,choice)``. +:on_submit2: Shift-Enter key callback; if specified, the list reacts to the key + and calls it as ``on_submit2(index,choice)``. +:row_height: Height of every row in text lines. +:icon_width: If not *nil*, the specified number of character columns + are reserved to the left of the list item for the icons. +:scroll_keys: Specifies which keys the list should react to as a table. + +Every list item may be specified either as a string, or as a lua table +with the following fields: + +:text: Specifies the label text in the same format as the Label text. +:caption, [1]: Deprecated legacy aliases for **text**. +:text_*: Reserved for internal use. +:key: Specifies a keybinding that acts as a shortcut for the specified item. +:icon: Specifies an icon string, or a pen to paint a single character. May be a callback. +:icon_pen: When the icon is a string, used to paint it. + +The list supports the following methods: + +* ``List{ ..., choices = ..., selected = ... }`` + + Same as calling ``setChoices`` after construction. + +* ``list:setChoices(choices[, selected])`` + + Replaces the list of choices, possibly also setting the currently selected index. + +* ``list:setSelected(selected)`` + + Sets the currently selected index. Returns the index after validation. + +* ``list:getChoices()`` + + Returns the list of choices. + +* ``list:getSelected()`` + + Returns the selected *index, choice*, or nothing if the list is empty. + +* ``list:getContentWidth()`` + + Returns the minimal width to draw all choices without clipping. + +* ``list:getContentHeight()`` + + Returns the minimal width to draw all choices without scrolling. + +* ``list:submit()`` + + Call the ``on_submit`` callback, as if the Enter key was handled. + +* ``list:submit2()`` + + Call the ``on_submit2`` callback, as if the Shift-Enter key was handled. + +FilteredList class +------------------ + +This widget combines List, EditField and Label into a combo-box like +construction that allows filtering the list by subwords of its items. + +In addition to passing through all attributes supported by List, it +supports: + +:edit_pen: If specified, used instead of ``cursor_pen`` for the edit field. +:edit_below: If true, the edit field is placed below the list instead of above. +:not_found_label: Specifies the text of the label shown when no items match the filter. + +The list choices may include the following attributes: + +:search_key: If specified, used instead of **text** to match against the filter. + +The widget implements: + +* ``list:setChoices(choices[, selected])`` + + Resets the filter, and passes through to the inner list. + +* ``list:getChoices()`` + + Returns the list of *all* choices. + +* ``list:getFilter()`` + + Returns the current filter string, and the *filtered* list of choices. + +* ``list:setFilter(filter[,pos])`` + + Sets the new filter string, filters the list, and selects the item at + index ``pos`` in the *unfiltered* list if possible. + +* ``list:canSubmit()`` + + Checks if there are currently any choices in the filtered list. + +* ``list:getSelected()``, ``list:getContentWidth()``, ``list:getContentHeight()``, ``list:submit()`` + + Same as with an ordinary list. + ======= Plugins @@ -1979,6 +2958,96 @@ sort Does not export any native functions as of now. Instead, it calls lua code to perform the actual ordering of list items. +Eventful +======== + +This plugin exports some events to lua thus allowing to run lua functions +on DF world events. + +List of events +-------------- + +1. ``onReactionComplete(reaction,unit,input_items,input_reagents,output_items,call_native)`` + + Auto activates if detects reactions starting with ``LUA_HOOK_``. Is called when reaction finishes. + +2. ``onItemContaminateWound(item,unit,wound,number1,number2)`` + + Is called when item tries to contaminate wound (e.g. stuck in). + +3. ``onProjItemCheckMovement(projectile)`` + + Is called when projectile moves. + +4. ``onProjItemCheckImpact(projectile,somebool)`` + + Is called when projectile hits something. + +5. ``onProjUnitCheckMovement(projectile)`` + + Is called when projectile moves. + +6. ``onProjUnitCheckImpact(projectile,somebool)`` + + Is called when projectile hits something. + +7. ``onWorkshopFillSidebarMenu(workshop,callnative)`` + + Is called when viewing a workshop in 'q' mode, to populate reactions, useful for custom viewscreens for shops. + +8. ``postWorkshopFillSidebarMenu(workshop)`` + + Is called after calling (or not) native fillSidebarMenu(). Useful for job button + tweaking (e.g. adding custom reactions) + +Functions +--------- + +1. ``registerReaction(reaction_name,callback)`` + + Simplified way of using onReactionComplete; the callback is function (same params as event). + +2. ``removeNative(shop_name)`` + + Removes native choice list from the building. + +3. ``addReactionToShop(reaction_name,shop_name)`` + + Add a custom reaction to the building. + +Examples +-------- +Spawn dragon breath on each item attempt to contaminate wound:: + + b=require "plugins.eventful" + b.onItemContaminateWound.one=function(item,unit,un_wound,x,y) + local flw=dfhack.maps.spawnFlow(unit.pos,6,0,0,50000) + end + +Reaction complete example:: + + b=require "plugins.eventful" + + b.onReactionComplete.one=function(reaction,unit,in_items,in_reag,out_items,call_native) + local pos=copyall(unit.pos) + -- spawn dragonbreath after 100 ticks + dfhack.timeout(100,"ticks",function() dfhack.maps.spawnFlow(pos,6,0,0,50000) end) + --do not call real item creation code + call_native.value=false + end + +Grenade example:: + + b=require "plugins.eventful" + b.onProjItemCheckImpact.one=function(projectile) + -- you can check if projectile.item e.g. has correct material + dfhack.maps.spawnFlow(projectile.cur_pos,6,0,0,50000) + end + +Integrated tannery:: + + b=require "plugins.eventful" + b.addReactionToShop("TAN_A_HIDE","LEATHERWORKS") ======= Scripts @@ -2018,3 +3087,24 @@ from other scripts) in any context, via the same function the core uses: The ``name`` argument should be the name stem, as would be used on the command line. Note that this function lets errors propagate to the caller. + +Save init script +================ + +If a save directory contains a file called ``raw/init.lua``, it is +automatically loaded and executed every time the save is loaded. It +can also define the following functions to be called by dfhack: + +* ``function onStateChange(op) ... end`` + + Automatically called from the regular onStateChange event as long + as the save is still loaded. This avoids the need to install a hook + into the global ``dfhack.onStateChange`` table, with associated + cleanup concerns. + +* ``function onUnload() ... end`` + + Called when the save containing the script is unloaded. This function + should clean up any global hooks installed by the script. + +Within the init script, the path to the save directory is available as ``SAVE_PATH``. diff --git a/NEWS b/NEWS index 65339ad64..9c1cf6676 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,83 @@ DFHack future - Nothing yet! + Is not yet known. + +DFHack v0.34.11-r3 + + Internals: + - support for displaying active keybindings properly. + - support for reusable widgets in lua screen library. + - Maps::canStepBetween: returns whether you can walk between two tiles in one step. + - EventManager: monitors various in game events centrally so that individual plugins + don't have to monitor the same things redundantly. + Notable bugfixes: + - autobutcher can be re-enabled again after being stopped. + - stopped Dwarf Manipulator from unmasking vampires. + Misc improvements: + - fastdwarf: new mode using debug flags, and some internal consistency fixes. + - added a small stand-alone utility for applying and removing binary patches. + - removebadthoughts: add --dry-run option + - superdwarf: work in adventure mode too + - tweak stable-cursor: carries cursor location from/to Build menu. + - deathcause: allow selection from the unitlist screen + - slayrace: allow targetting undeads + New tweaks: + - tweak military-training: speed up melee squad training up to 10x (normally 3-5x). + New scripts: + - binpatch: the same as the stand-alone binpatch.exe, but works at runtime. + - region-pops: displays animal populations of the region and allows tweaking them. + - lua: lua interpreter front-end converted to a script from a native command. + - dfusion: misc scripts with a text based menu. + - embark: lets you embark anywhere. + - lever: list and pull fort levers from the dfhack console. + - stripcaged: mark items inside cages for dumping, eg caged goblin weapons. + - soundsense-season: writes the correct season to gamelog.txt on world load. + - create-items: spawn items + - fix/cloth-stockpile: fixes bug 5739; needs to be run after savegame load every time. + New GUI scripts: + - gui/guide-path: displays the cached path for minecart Guide orders. + - gui/workshop-job: displays inputs of a workshop job and allows tweaking them. + - gui/workflow: a front-end for the workflow plugin (part inspired by falconne). + - gui/assign-rack: works together with a binary patch to fix weapon racks. + - gui/gm-editor: an universal editor for lots of dfhack things. + - gui/companion-order: a adventure mode command interface for your companions. + - gui/advfort: a way to do jobs with your adventurer (e.g. build fort). + New binary patches (for use with binpatch): + - armorstand-capacity: doubles the capacity of armor stands. + - custom-reagent-size: lets custom reactions use small amounts of inputs. + - deconstruct-heapfall: stops some items still falling on head when deconstructing. + - deconstruct-teleport: stops items from 16x16 block teleporting when deconstructing. + - hospital-overstocking: stops hospital overstocking with supplies. + - training-ammo: lets dwarves with quiver full of combat-only ammo train. + - weaponrack-unassign: fixes bug that negates work done by gui/assign-rack. + Workflow plugin: + - properly considers minecarts assigned to routes busy. + - code for deducing job outputs rewritten in lua for flexibility. + - logic fix: collecting webs produces silk, and ungathered webs are not thread. + - items assigned to squads are considered busy, even if not in inventory. + - shearing and milking jobs are supported, but only with generic MILK or YARN outputs. + - workflow announces when the stock level gets very low once a season. + New Fix Armory plugin: + Together with a couple of binary patches and the gui/assign-rack script, + this plugin makes weapon racks, armor stands, chests and cabinets in + properly designated barracks be used again for storage of squad equipment. + New Search plugin by falconne: + Adds an incremental search function to the Stocks, Trading, Stockpile and Unit List screens. + New AutoMaterial plugin by falconne: + Makes building constructions (walls, floors, fortifications, etc) a little bit easier by + saving you from having to trawl through long lists of materials each time you place one. + Dfusion plugin: + Reworked to make use of lua modules, now all the scripts can be used from other scripts. + New Eventful plugin: + A collection of lua events, that will allow new ways to interact with df world. + Auto syndrome plugin: + A way of automatically applying boiling rock syndromes and calling dfhack commands controlled by raws. + Infinite sky plugin: + Create new z-levels automatically or on request. + True transformation plugin: + A better way of doing permanent transformations that allows later transformations. + Work now plugin: + Makes the game assign jobs every time you pause. DFHack v0.34.11-r2 diff --git a/Readme.html b/Readme.html index caf1f6a0e..7b008a261 100644 --- a/Readme.html +++ b/Readme.html @@ -3,13 +3,13 @@
- +