Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add graphics support for building-hacks #4380

Open
wants to merge 38 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
9a7370f
Add graphics support for building-hacks
warmist Mar 17, 2024
c4266c5
Update to new structures and simplify api a bit
warmist Mar 18, 2024
6ade67e
Fix bugs and refactor lua c api to use indexed access
warmist Mar 18, 2024
b295d57
Update plugin lua module
warmist Mar 18, 2024
c67d685
whitespace fixes
warmist Mar 19, 2024
fe0bc2f
Fix uint32_t getting set to -1
warmist Mar 19, 2024
2cdeee8
Add event to vmethod interpose setTriggerState for lever/trap plate l…
warmist Mar 20, 2024
010928c
big refactor and api cleanup
warmist Mar 24, 2024
3138d3a
Doc update
warmist Mar 24, 2024
cd59595
Fix bad string compare
warmist Mar 24, 2024
16bc0b6
whitespace fixes
warmist Mar 24, 2024
bd09cb5
Add error on failing to find gears for auto-machines and auto-animate
warmist Mar 25, 2024
60e21b9
Add a way to change graphics tiles when auto generating connection po…
warmist Mar 29, 2024
796f480
Fix repeated calling animation creating more and more frames
warmist Mar 29, 2024
11ef74a
Fix graphics bug
warmist Mar 29, 2024
61920e3
Update docs/dev/Lua API.rst
warmist Apr 1, 2024
73f2d23
Switch map to unordered map
warmist Apr 2, 2024
3cd0bc8
Just use 0 as invalid tile marker. It's used in df code like that
warmist Apr 2, 2024
6ce0bcc
Redo the categorize to prevent issue that scripts run after world has…
warmist Apr 2, 2024
6a48246
Redo plugin to auto-enable on first use and expose enabled state to d…
warmist Apr 2, 2024
2a1db17
Fix graphics tile types
warmist Apr 2, 2024
1e68060
docs: add correct tags to the plugin docs
warmist Apr 2, 2024
6faacc0
docs: add note about workshop ids
warmist Apr 5, 2024
aaf3f9c
remove boolean arg from fixImpassible and setOwnableBuilding and doc …
warmist Apr 5, 2024
a975fd9
Allow passing numeric id to auto functions. Tidy up docs api some more.
warmist Apr 5, 2024
e462846
docs: more info about animation tiles
warmist Apr 5, 2024
1439fcb
fix lua syntax error and whitespaces
warmist Apr 5, 2024
9e14ac4
update to new structures
warmist Jun 7, 2024
e8763fe
docs: use bhacks instead of bld in examples
warmist Dec 30, 2024
41a0df5
Don't hold the CoreSuspend over INTERPOSE_NEXT
warmist Dec 30, 2024
5360b98
swap getPower returns to be same as setPower
warmist Dec 30, 2024
b27a61a
docs: change wording on many thingies
warmist Dec 30, 2024
d43fb3a
change how frames are loaded
warmist Dec 30, 2024
3355f6b
saner frameskip logic
warmist Dec 30, 2024
f49d203
docs: update frame doc
warmist Dec 30, 2024
92fa5cf
building-hacks.lua update
warmist Dec 30, 2024
7a79fab
docs: yet another day, yet another doc update. Also improved optional…
warmist Dec 31, 2024
f2c038d
remove coresuspend from vmethod interpose
warmist Jan 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 132 additions & 65 deletions docs/dev/Lua API.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6520,87 +6520,154 @@ The names of the functions are also available as the keys of the
building-hacks
==============

This plugin overwrites some methods in workshop df class so that mechanical workshops are
possible. Although plugin export a function it's recommended to use lua decorated function.
This plugin extends DF workshops to support custom powered buildings.

.. note::
When using numeric ids for workshops be aware that those id can change between worlds,
depending on what other custom types exist in the raws for that world.

.. contents::
:local:

Functions
---------

``registerBuilding(table)`` where table must contain name, as a workshop raw name,
the rest are optional:

:name:
custom workshop id e.g., ``SOAPMAKER``

.. note:: this is the only mandatory field.

:fix_impassible:
if true make impassable tiles impassable to liquids too
:consume:
how much machine power is needed to work.
Disables reactions if not supplied enough and ``needs_power==1``
:produce:
how much machine power is produced.
:needs_power:
if produced in network < consumed stop working, default true
:gears:
a table or ``{x=?,y=?}`` of connection points for machines.
:action:
a table of number (how much ticks to skip) and a function which
gets called on shop update
:animate:
a table of frames which can be a table of:

a. tables of 4 numbers ``{tile,fore,back,bright}`` OR
b. empty table (tile not modified) OR
c. ``{x=<number> y=<number> + 4 numbers like in first case}``,
this generates full frame useful for animations that change little (1-2 tiles)

:canBeRoomSubset:
a flag if this building can be counted in room. 1 means it can,
0 means it can't and -1 default building behaviour
:auto_gears:
a flag that automatically fills up gears and animations.
It looks over the building definition for gear icons and maps them.

Animate table also might contain:

:frameLength:
how many ticks does one frame take OR
:isMechanical:
a bool that says to try to match to mechanical system (i.e., how gears are turning)

``getPower(building)`` returns two number - produced and consumed power if building can be
modified and returns nothing otherwise

``setPower(building,produced,consumed)`` sets current power production and
consumption for a building.
* ``setOwnableBuilding(workshop_type)``

Set workshop to be included in zones (such as a bedroom or tavern).

:workshop_type: custom workshop string id, e.g. ``SOAPMAKER`` or numeric id

* ``fixImpassible(workshop_type)``

Set workshop non walkable tiles to also block liquids (i.e. water and magma).

:workshop_type: custom workshop string id, e.g. ``SOAPMAKER`` or numeric id

* ``setMachineInfo(workshop_type, needs_power, power_consumed, power_produced, connection_points)``
warmist marked this conversation as resolved.
Show resolved Hide resolved

Setup and enable machine-like functionality for the workshop. All workshops of this type will have
this as their default power consumption/production. Note: due to implementation limitations,
workshops only connect to other machines if the other machines are planned after than this one.

:workshop_type: custom workshop string id e.g. ``SOAPMAKER`` or numeric id
warmist marked this conversation as resolved.
Show resolved Hide resolved
:needs_power: true if the workshop should only be usable if it has sufficient power
:power_consumed: buildings of this type consume this amount of power by default
:power_produced: buildings of this type output this amount of power by default
:connection_points: a table of ``{x=?,y=?}`` zero-based coordinates that can connect to other machines

* ``setMachineInfoAuto(workshop_type, needs_power, power_consumed, power_produced, [gear_tiles])``

Same as ``setMachineInfo`` but fills out the ``connection_points`` table based on the
building definition in the raws. It places connection points on tiles which have the gear
tile. ``gear_tiles`` is an optional array of two tiles that are counted as gears in the
workshop ascii tile raws. The default gear tiles are ``42`` and ``15``.

* ``setAnimationInfo(workshop_type, frames, frame_skip)``
warmist marked this conversation as resolved.
Show resolved Hide resolved

Animate workshop by replacing displayed tiles (or graphical tiles). There are two ways this works:
if ``frame_skip>0`` then it shows each frame for ``frame_skip`` of frames or if ``frame_skip<=0``
Frames are synchronized with the machines this building is connected to.

:workshop_type: custom workshop string id, e.g. ``SOAPMAKER`` or numeric id
:frames: table of frames. Each frame is array of rows of tiles with ids from ``1`` to ``31``.
Each frame tile is table of with following optional members: ``ch``, ``fg``,
``bg``, ``bold``, ``tile``, ``tile_overlay``, ``tile_signpost``, ``tile_item``.
First 4 are function same as ascii workshop definition. The latter 4 are graphics
layers. ``tile_signpost`` is only valid in first row and it shows up above the workshop.

:frame_skip: How many ticks to display one frame. If set to negative number, zero or skipped, frames
are synchronized with machine animation.

* ``setAnimationInfoAuto(workshop_type, make_graphics_too[, frame_length][, gear_tiles])``

Animate workshop as with function above but generate frames automatically. This works by finding
tiles which have gears and animating them with alternating gear tiles.

:workshop_type: custom workshop string id, e.g. ``SOAPMAKER`` or numeric id
:make_graphics_too: replace same tiles in graphics mode with tiles from vanilla df mechanism
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when would you want this set to false?

:frame_length: How many ticks to display one frame. If set to negative number, zero or skipped, frames
are synchronized with machine animation.
:gear_tiles: Optional table with ``ch``, ``ch_alt``, ``tile``, ``tile_alt``. First two are ascii
gear tiles and are used to find tiles in workshop raw and animate them. Second two are
used to animate graphical tiles.

* ``setOnUpdate(workshop_type, interval, callback)``

Register callback to be called every ``interval`` ticks for each building of this
type. This can be very expensive if the interval is low and/or there are many
workshops of this type. Keep these callbacks light!

:workshop_type: custom workshop string id, e.g. ``SOAPMAKER`` or numeric id
:interval: how many ticks to skip between event triggers
:callback: function to call. Function signature is ``func(workshop)`` where ``workshop`` is of type
``df.building_workshopst``

* ``getPower(building)``

If this building is of a type registered with building-hacks, returns values for
consumed and produced power. Otherwise, returns ``nil``.

:building: specific workshop that produces or consumes power

* ``setPower(building, power_consumed, power_produced)``

Dynamically sets current power production and consumption for a specific workshop
(which must be of a type registered with building-hacks).

:building: specific workshop that produces or consumes power
:power_consumed: set building to consume this amount of power
:power_produced: output this amount of power


Events
------

This module exports two events. However only one is documented here and is intended to be used directly. To use
``onUpdateAction`` instead call ``setOnUpdate`` function.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why does onUpdateAction exist as a Lua event, then?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The plugin lua part still uses that event (i.e. setOnUpdate function)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced this is sufficient reasoning. Why do you need a lua event to communicate with your own Lua layer? Why can't you call the Lua functions directly?


* ``onSetTriggerState(workshop, state)``

Notify when building is triggered from linked lever or trap.

:workshop: object of type ``df.building_workshopst`` that is triggered.
:state: integer value of new state.

Examples
--------

Simple mechanical workshop::

require('plugins.building-hacks').registerBuilding{name="BONE_GRINDER",
consume=15,
gears={x=0,y=0}, --connection point
animate={
isMechanical=true, --animate the same conn. point as vanilla gear
frames={
{{x=0,y=0,42,7,0,0}}, --first frame, 1 changed tile
{{x=0,y=0,15,7,0,0}} -- second frame, same
}
}
local bhacks = require('plugins.building-hacks')

--work only powered, consume 15 power and one connection point at 0, 0
bhacks.setMachineInfo("BONE_GRINDER", true, 15, 0, {{x=0, y=0}})

--load custom graphical tiles for use if graphics is enabled
local tile1=dfhack.screen.findGraphicsTile('DRAGON_ENGINE_TILES', 0, 0)
local tile2=dfhack.screen.findGraphicsTile('DRAGON_ENGINE_TILES', 1, 0)

local frames={}
--first frame - tile (1, 1) changed to character 42
ensure_key(frames, 1, 1)[1]={ch=42, fg=7, bg=0, bold=0, tile=tile1}
--second frame - tile (1,1) changed to character 15
ensure_key(frames, 2, 1)[1]={ch=15, fg=7, bg=0, bold=0, tile=tile2}

--set animation to switch between gear tiles at 1,1
bhacks.setAnimationInfo("BONE_GRINDER", frames)

Or with auto_gears::

require('plugins.building-hacks').registerBuilding{name="BONE_GRINDER",
consume=15,
auto_gears=true
}
local bhacks = require('plugins.building-hacks')

--load custom graphical tiles for use if graphics is enabled
local tile1=dfhack.screen.findGraphicsTile('DRAGON_ENGINE_TILES', 0, 0)
local tile2=dfhack.screen.findGraphicsTile('DRAGON_ENGINE_TILES', 1, 0)

--work only powered, consume 15 power and find connection point from building raws
bhacks.setMachineInfoAuto("BONE_GRINDER", true, 15)
--set animation to switch between default ascii gears and specific graphic tiles loaded above
bhacks.setAnimationInfoAuto("BONE_GRINDER", true, -1, {tile=tile1, tile_alt=tile2})

buildingplan
============
Expand Down
2 changes: 1 addition & 1 deletion docs/plugins/building-hacks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ building-hacks

.. dfhack-tool::
:summary: Provides a Lua API for creating powered workshops.
:tags: unavailable
:tags: fort gameplay buildings
:no-command:

See `building-hacks-api` for more details.
2 changes: 1 addition & 1 deletion plugins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ if(BUILD_SUPPORTED)
dfhack_plugin(autoslab autoslab.cpp)
dfhack_plugin(blueprint blueprint.cpp LINK_LIBRARIES lua)
dfhack_plugin(burrow burrow.cpp LINK_LIBRARIES lua)
#dfhack_plugin(building-hacks building-hacks.cpp LINK_LIBRARIES lua)
dfhack_plugin(building-hacks building-hacks.cpp LINK_LIBRARIES lua)
add_subdirectory(buildingplan)
dfhack_plugin(changeitem changeitem.cpp)
dfhack_plugin(changelayer changelayer.cpp)
Expand Down
Loading
Loading