Skip to content

Commit edda030

Browse files
committed
Add library functions for placing spatters
Required for #5703
1 parent 58af0b9 commit edda030

File tree

7 files changed

+363
-39
lines changed

7 files changed

+363
-39
lines changed

docs/changelog.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,14 @@ Template for new versions:
6565
## Documentation
6666

6767
## API
68+
- Added ``Maps::addMaterialSpatter``: add a spatter of the specified material + state to the indicated tile, returning whatever amount wouldn't fit in the tile.
69+
- Added ``Maps::addItemSpatter``: add a spatter of the specified item + material + growth print to the indicated tile, returning whatever amount wouldn't fit in the tile.
70+
- Added ``Items::pickGrowthPrint``: given a plant material and a growth index, returns the print variant corresponding to the current in-game time.
71+
- Added ``Items::useStandardMaterial``: given an item type, returns true if the item is made of a specific material and false if it has a race and caste instead.
6872

6973
## Lua
74+
- Added ``Maps::addMaterialSpatter`` as ``dfhack.maps.addMaterialSpatter``.
75+
- Added ``Maps::addItemSpatter`` as ``dfhack.maps.addItemSpatter``.
7076

7177
## Removed
7278

docs/dev/Lua API.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2486,6 +2486,22 @@ Maps module
24862486
Removes an aquifer from the given tile position.
24872487
Returns *true* or *false* depending on success.
24882488

2489+
* ``dfhack.maps.addMaterialSpatter(pos, mat, matg, state, amount)``
2490+
2491+
Adds a material spatter to the specified map tile. If the tile is already
2492+
full of that spatter, returns the amount left over.
2493+
2494+
Specifying a state of -1 (None) will automatically choose either Solid,
2495+
Liquid, or Gas based on the material properties and the tile temperature.
2496+
2497+
* ``dfhack.maps.addItemSpatter(pos, i_type, i_subtype, subcat1, subcat2, print_variant, amount)``
2498+
2499+
Adds an item spatter to the specified map tile. If the tile is already
2500+
full of that spatter, returns the amount left over.
2501+
2502+
For plant growths, specifying a print_variant of -1 will automatically
2503+
choose an appropriate value. For other item types, this field is ignored.
2504+
24892505
Burrows module
24902506
--------------
24912507

library/LuaApi.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2781,6 +2781,40 @@ static int maps_removeTileAquifer(lua_State* L)
27812781
return 1;
27822782
}
27832783

2784+
static int maps_addMaterialSpatter(lua_State *L)
2785+
{
2786+
int32_t rv;
2787+
df::coord pos;
2788+
2789+
Lua::CheckDFAssign(L, &pos, 1);
2790+
int16_t mat = lua_tointeger(L, 2);
2791+
int32_t matg = lua_tointeger(L, 3);
2792+
df::matter_state state = (df::matter_state)lua_tointeger(L, 4);
2793+
int32_t amount = lua_tointeger(L, 5);
2794+
rv = Maps::addMaterialSpatter(pos, mat, matg, state, amount);
2795+
2796+
lua_pushinteger(L, rv);
2797+
return 1;
2798+
}
2799+
2800+
static int maps_addItemSpatter(lua_State *L)
2801+
{
2802+
int32_t rv;
2803+
df::coord pos;
2804+
2805+
Lua::CheckDFAssign(L, &pos, 1);
2806+
df::item_type i_type = (df::item_type)lua_tointeger(L, 2);
2807+
int16_t i_subtype = lua_tointeger(L, 3);
2808+
int16_t i_subcat1 = lua_tointeger(L, 4);
2809+
int32_t i_subcat2 = lua_tointeger(L, 5);
2810+
int32_t print_variant = lua_tointeger(L, 6);
2811+
int32_t amount = lua_tointeger(L, 7);
2812+
rv = Maps::addItemSpatter(pos, i_type, i_subtype, i_subcat1, i_subcat2, print_variant, amount);
2813+
2814+
lua_pushinteger(L, rv);
2815+
return 1;
2816+
}
2817+
27842818
static const luaL_Reg dfhack_maps_funcs[] = {
27852819
{ "isValidTilePos", maps_isValidTilePos },
27862820
{ "isTileVisible", maps_isTileVisible },
@@ -2796,6 +2830,8 @@ static const luaL_Reg dfhack_maps_funcs[] = {
27962830
{ "isTileHeavyAquifer", maps_isTileHeavyAquifer },
27972831
{ "setTileAquifer", maps_setTileAquifer },
27982832
{ "removeTileAquifer", maps_removeTileAquifer },
2833+
{ "addMaterialSpatter", maps_addMaterialSpatter },
2834+
{ "addItemSpatter", maps_addItemSpatter },
27992835
{ NULL, NULL }
28002836
};
28012837

library/include/modules/Items.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@ DFHACK_EXPORT int getItemBaseValue(int16_t item_type, int16_t item_subtype, int1
170170
// Gets the value of a specific item, taking into account civ values and trade agreements if a caravan is given.
171171
DFHACK_EXPORT int getValue(df::item *item, df::caravan_state *caravan = NULL);
172172

173+
// Automatically choose a growth print variant for the specified plant growth subtype+material
174+
DFHACK_EXPORT int32_t pickGrowthPrint(int16_t subtype, int16_t mat, int32_t matg);
175+
173176
DFHACK_EXPORT bool createItem(std::vector<df::item *> &out_items, df::unit *creator, df::item_type type,
174177
int16_t item_subtype, int16_t mat_type, int32_t mat_index, bool no_floor = false, int32_t count = 1);
175178

@@ -186,6 +189,9 @@ DFHACK_EXPORT bool markForTrade(df::item *item, df::building_tradedepotst *depot
186189
// Returns true if an active caravan will pay extra for the given item.
187190
DFHACK_EXPORT bool isRequestedTradeGood(df::item *item, df::caravan_state *caravan = NULL);
188191

192+
// DF standard_material_itemtype - returns true if item has material/matgloss, false if race+caste
193+
DFHACK_EXPORT bool usesStandardMaterial(df::item_type item_type);
194+
189195
// Returns true if the item can currently be melted. If game_ui, then able to be marked is enough.
190196
DFHACK_EXPORT bool canMelt(df::item *item, bool game_ui = false);
191197
// Marks the item for melting.

library/include/modules/Maps.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ distribution.
3838
#include "df/block_flags.h"
3939
#include "df/feature_type.h"
4040
#include "df/flow_type.h"
41+
#include "df/matter_state.h"
4142
#include "df/tile_dig_designation.h"
4243
#include "df/tiletype.h"
4344

@@ -372,6 +373,10 @@ extern DFHACK_EXPORT bool SortBlockEvents(df::map_block *block,
372373
std::vector<df::block_square_event_designation_priorityst *> *priorities = 0
373374
);
374375

376+
// Add spatters at the specified location, returning the amount that couldn't be placed (e.g. due to overflow)
377+
extern DFHACK_EXPORT int32_t addMaterialSpatter (df::coord pos, int16_t mat, int32_t matg, df::matter_state state, int32_t amount);
378+
extern DFHACK_EXPORT int32_t addItemSpatter (df::coord pos, df::item_type i_type, int16_t i_subtype, int16_t i_subcat1, int32_t i_subcat2, int32_t print_variant, int32_t amount);
379+
375380
// Remove a block event from the block by address.
376381
extern DFHACK_EXPORT bool RemoveBlockEvent(int32_t x, int32_t y, int32_t z, df::block_square_event *which );
377382
extern DFHACK_EXPORT bool RemoveBlockEvent(uint32_t x, uint32_t y, uint32_t z, df::block_square_event *which ); // TODO: deprecate me

library/modules/Items.cpp

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1752,6 +1752,37 @@ int Items::getValue(df::item *item, df::caravan_state *caravan) {
17521752
return value;
17531753
}
17541754

1755+
// Automatically choose a growth print variant for the specified plant growth subtype+material
1756+
int32_t Items::pickGrowthPrint(int16_t subtype, int16_t mat, int32_t matg)
1757+
{
1758+
int growth_print = -1;
1759+
// Make sure it's made of a valid plant material, then grab its definition
1760+
if (mat >= 419 && mat <= 618 && matg >= 0 && (unsigned)matg < world->raws.plants.all.size())
1761+
{
1762+
auto plant_def = world->raws.plants.all[matg];
1763+
// Make sure it subtype is also valid
1764+
if (subtype >= 0 && (unsigned)subtype < plant_def->growths.size())
1765+
{
1766+
auto growth_def = plant_def->growths[subtype];
1767+
// Try and find a growth print matching the current time
1768+
// (in practice, only tree leaves use this for autumn color changes)
1769+
for (size_t i = 0; i < growth_def->prints.size(); i++)
1770+
{
1771+
auto print_def = growth_def->prints[i];
1772+
if (print_def->timing_start <= *df::global::cur_year_tick && *df::global::cur_year_tick <= print_def->timing_end)
1773+
{
1774+
growth_print = i;
1775+
break;
1776+
}
1777+
}
1778+
// If we didn't find one, then pick the first one (if it exists)
1779+
if (growth_print == -1 && !growth_def->prints.empty())
1780+
growth_print = 0;
1781+
}
1782+
}
1783+
return growth_print;
1784+
}
1785+
17551786
bool Items::createItem(vector<df::item *> &out_items, df::unit *unit, df::item_type item_type,
17561787
int16_t item_subtype, int16_t mat_type, int32_t mat_index, bool no_floor, int32_t count)
17571788
{ // Based on Quietust's plugins/createitem.cpp
@@ -1802,34 +1833,7 @@ bool Items::createItem(vector<df::item *> &out_items, df::unit *unit, df::item_t
18021833
for (auto out_item : out_items)
18031834
{ // Plant growths need a valid "growth print", otherwise they behave oddly
18041835
if (auto growth = virtual_cast<df::item_plant_growthst>(out_item))
1805-
{
1806-
int growth_print = -1;
1807-
// Make sure it's made of a valid plant material, then grab its definition
1808-
if (growth->mat_type >= 419 && growth->mat_type <= 618 && growth->mat_index >= 0 && (unsigned)growth->mat_index < world->raws.plants.all.size())
1809-
{
1810-
auto plant_def = world->raws.plants.all[growth->mat_index];
1811-
// Make sure it subtype is also valid
1812-
if (growth->subtype >= 0 && (unsigned)growth->subtype < plant_def->growths.size())
1813-
{
1814-
auto growth_def = plant_def->growths[growth->subtype];
1815-
// Try and find a growth print matching the current time
1816-
// (in practice, only tree leaves use this for autumn color changes)
1817-
for (size_t i = 0; i < growth_def->prints.size(); i++)
1818-
{
1819-
auto print_def = growth_def->prints[i];
1820-
if (print_def->timing_start <= *df::global::cur_year_tick && *df::global::cur_year_tick <= print_def->timing_end)
1821-
{
1822-
growth_print = i;
1823-
break;
1824-
}
1825-
}
1826-
// If we didn't find one, then pick the first one (if it exists)
1827-
if (growth_print == -1 && !growth_def->prints.empty())
1828-
growth_print = 0;
1829-
}
1830-
}
1831-
growth->growth_print = growth_print;
1832-
}
1836+
growth->growth_print = pickGrowthPrint(growth->subtype, growth->mat_type, growth->mat_index);
18331837
if (!no_floor)
18341838
out_item->moveToGround(pos.x, pos.y, pos.z);
18351839
}
@@ -1962,17 +1966,10 @@ bool Items::isRequestedTradeGood(df::item *item, df::caravan_state *caravan) {
19621966
return false;
19631967
}
19641968

1965-
/// When called with game_ui = true, this is equivalent to Bay12's itemst::meltable()
1966-
/// (i.e., returning true if and only if the item has a "designate for melting" button in game)
1967-
bool Items::canMelt(df::item *item, bool game_ui) {
1968-
CHECK_NULL_POINTER(item);
1969-
MaterialInfo mat(item);
1970-
if (mat.getCraftClass() != craft_material_class::Metal)
1971-
return false;
1972-
1973-
switch(item->getType())
1969+
bool Items::usesStandardMaterial(df::item_type item_type)
1970+
{
1971+
switch(item_type)
19741972
{ using namespace df::enums::item_type;
1975-
// These are not meltable, even if made from metal
19761973
case CORPSE:
19771974
case CORPSEPIECE:
19781975
case REMAINS:
@@ -1984,8 +1981,20 @@ bool Items::canMelt(df::item *item, bool game_ui) {
19841981
case EGG:
19851982
return false;
19861983
default:
1987-
break;
1984+
return true;
19881985
}
1986+
}
1987+
1988+
/// When called with game_ui = true, this is equivalent to Bay12's itemst::meltable()
1989+
/// (i.e., returning true if and only if the item has a "designate for melting" button in game)
1990+
bool Items::canMelt(df::item *item, bool game_ui) {
1991+
CHECK_NULL_POINTER(item);
1992+
MaterialInfo mat(item);
1993+
if (mat.getCraftClass() != craft_material_class::Metal)
1994+
return false;
1995+
1996+
if (!usesStandardMaterial(item->getType()))
1997+
return false;
19891998

19901999
if (item->flags.bits.artifact)
19912000
return false;

0 commit comments

Comments
 (0)