Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions docs/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,12 @@ Template for new versions:
## Documentation

## API
- Added ``Maps::addMaterialSpatter``: add a spatter of the specified material + state to the indicated tile, returning whatever amount wouldn't fit in the tile.
- 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.

## Lua
- Added ``Maps::addMaterialSpatter`` as ``dfhack.maps.addMaterialSpatter``.
- Added ``Maps::addItemSpatter`` as ``dfhack.maps.addItemSpatter``.

## Removed

Expand Down
16 changes: 16 additions & 0 deletions docs/dev/Lua API.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2486,6 +2486,22 @@ Maps module
Removes an aquifer from the given tile position.
Returns *true* or *false* depending on success.

* ``dfhack.maps.addMaterialSpatter(pos, mat, matg, state, amount)``

Adds a material spatter to the specified map tile. If the tile is already
full of that spatter, returns the amount left over.

Specifying a state of -1 (None) will automatically choose either Solid,
Liquid, or Gas based on the material properties and the tile temperature.

* ``dfhack.maps.addItemSpatter(pos, i_type, i_subtype, subcat1, subcat2, print_variant, amount)``

Adds an item spatter to the specified map tile. If the tile is already
full of that spatter, returns the amount left over.

For plant growths, specifying a print_variant of -1 will automatically
choose an appropriate value. For other item types, this field is ignored.

Burrows module
--------------

Expand Down
36 changes: 36 additions & 0 deletions library/LuaApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2781,6 +2781,40 @@ static int maps_removeTileAquifer(lua_State* L)
return 1;
}

static int maps_addMaterialSpatter(lua_State *L)
{
int32_t rv;
df::coord pos;

Lua::CheckDFAssign(L, &pos, 1);
int16_t mat = lua_tointeger(L, 2);
int32_t matg = lua_tointeger(L, 3);
df::matter_state state = (df::matter_state)lua_tointeger(L, 4);
int32_t amount = lua_tointeger(L, 5);
rv = Maps::addMaterialSpatter(pos, mat, matg, state, amount);

lua_pushinteger(L, rv);
return 1;
}

static int maps_addItemSpatter(lua_State *L)
{
int32_t rv;
df::coord pos;

Lua::CheckDFAssign(L, &pos, 1);
df::item_type i_type = (df::item_type)lua_tointeger(L, 2);
int16_t i_subtype = lua_tointeger(L, 3);
int16_t i_subcat1 = lua_tointeger(L, 4);
int32_t i_subcat2 = lua_tointeger(L, 5);
int32_t print_variant = lua_tointeger(L, 6);
int32_t amount = lua_tointeger(L, 7);
rv = Maps::addItemSpatter(pos, i_type, i_subtype, i_subcat1, i_subcat2, print_variant, amount);

lua_pushinteger(L, rv);
return 1;
}

static const luaL_Reg dfhack_maps_funcs[] = {
{ "isValidTilePos", maps_isValidTilePos },
{ "isTileVisible", maps_isTileVisible },
Expand All @@ -2796,6 +2830,8 @@ static const luaL_Reg dfhack_maps_funcs[] = {
{ "isTileHeavyAquifer", maps_isTileHeavyAquifer },
{ "setTileAquifer", maps_setTileAquifer },
{ "removeTileAquifer", maps_removeTileAquifer },
{ "addMaterialSpatter", maps_addMaterialSpatter },
{ "addItemSpatter", maps_addItemSpatter },
{ NULL, NULL }
};

Expand Down
6 changes: 6 additions & 0 deletions library/include/modules/Items.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ DFHACK_EXPORT int getItemBaseValue(int16_t item_type, int16_t item_subtype, int1
// Gets the value of a specific item, taking into account civ values and trade agreements if a caravan is given.
DFHACK_EXPORT int getValue(df::item *item, df::caravan_state *caravan = NULL);

// Automatically choose a growth print variant for the specified plant growth subtype+material
DFHACK_EXPORT int32_t pickGrowthPrint(int16_t subtype, int16_t mat, int32_t matg);

DFHACK_EXPORT bool createItem(std::vector<df::item *> &out_items, df::unit *creator, df::item_type type,
int16_t item_subtype, int16_t mat_type, int32_t mat_index, bool no_floor = false, int32_t count = 1);

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

// DF standard_material_itemtype - returns true if item has material/matgloss, false if race+caste
DFHACK_EXPORT bool usesStandardMaterial(df::item_type item_type);

// Returns true if the item can currently be melted. If game_ui, then able to be marked is enough.
DFHACK_EXPORT bool canMelt(df::item *item, bool game_ui = false);
// Marks the item for melting.
Expand Down
5 changes: 5 additions & 0 deletions library/include/modules/Maps.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ distribution.
#include "df/block_flags.h"
#include "df/feature_type.h"
#include "df/flow_type.h"
#include "df/matter_state.h"
#include "df/tile_dig_designation.h"
#include "df/tiletype.h"

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

// Add spatters at the specified location, returning the amount that couldn't be placed (e.g. due to overflow)
extern DFHACK_EXPORT int32_t addMaterialSpatter (df::coord pos, int16_t mat, int32_t matg, df::matter_state state, int32_t amount);
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);

// Remove a block event from the block by address.
extern DFHACK_EXPORT bool RemoveBlockEvent(int32_t x, int32_t y, int32_t z, df::block_square_event *which );
extern DFHACK_EXPORT bool RemoveBlockEvent(uint32_t x, uint32_t y, uint32_t z, df::block_square_event *which ); // TODO: deprecate me
Expand Down
87 changes: 48 additions & 39 deletions library/modules/Items.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1752,6 +1752,37 @@ int Items::getValue(df::item *item, df::caravan_state *caravan) {
return value;
}

// Automatically choose a growth print variant for the specified plant growth subtype+material
int32_t Items::pickGrowthPrint(int16_t subtype, int16_t mat, int32_t matg)
{
int growth_print = -1;
// Make sure it's made of a valid plant material, then grab its definition
if (mat >= 419 && mat <= 618 && matg >= 0 && (unsigned)matg < world->raws.plants.all.size())
{
auto plant_def = world->raws.plants.all[matg];
// Make sure it subtype is also valid
if (subtype >= 0 && (unsigned)subtype < plant_def->growths.size())
{
auto growth_def = plant_def->growths[subtype];
// Try and find a growth print matching the current time
// (in practice, only tree leaves use this for autumn color changes)
for (size_t i = 0; i < growth_def->prints.size(); i++)
{
auto print_def = growth_def->prints[i];
if (print_def->timing_start <= *df::global::cur_year_tick && *df::global::cur_year_tick <= print_def->timing_end)
{
growth_print = i;
break;
}
}
// If we didn't find one, then pick the first one (if it exists)
if (growth_print == -1 && !growth_def->prints.empty())
growth_print = 0;
}
}
return growth_print;
}

bool Items::createItem(vector<df::item *> &out_items, df::unit *unit, df::item_type item_type,
int16_t item_subtype, int16_t mat_type, int32_t mat_index, bool no_floor, int32_t count)
{ // Based on Quietust's plugins/createitem.cpp
Expand Down Expand Up @@ -1802,34 +1833,7 @@ bool Items::createItem(vector<df::item *> &out_items, df::unit *unit, df::item_t
for (auto out_item : out_items)
{ // Plant growths need a valid "growth print", otherwise they behave oddly
if (auto growth = virtual_cast<df::item_plant_growthst>(out_item))
{
int growth_print = -1;
// Make sure it's made of a valid plant material, then grab its definition
if (growth->mat_type >= 419 && growth->mat_type <= 618 && growth->mat_index >= 0 && (unsigned)growth->mat_index < world->raws.plants.all.size())
{
auto plant_def = world->raws.plants.all[growth->mat_index];
// Make sure it subtype is also valid
if (growth->subtype >= 0 && (unsigned)growth->subtype < plant_def->growths.size())
{
auto growth_def = plant_def->growths[growth->subtype];
// Try and find a growth print matching the current time
// (in practice, only tree leaves use this for autumn color changes)
for (size_t i = 0; i < growth_def->prints.size(); i++)
{
auto print_def = growth_def->prints[i];
if (print_def->timing_start <= *df::global::cur_year_tick && *df::global::cur_year_tick <= print_def->timing_end)
{
growth_print = i;
break;
}
}
// If we didn't find one, then pick the first one (if it exists)
if (growth_print == -1 && !growth_def->prints.empty())
growth_print = 0;
}
}
growth->growth_print = growth_print;
}
growth->growth_print = pickGrowthPrint(growth->subtype, growth->mat_type, growth->mat_index);
if (!no_floor)
out_item->moveToGround(pos.x, pos.y, pos.z);
}
Expand Down Expand Up @@ -1962,17 +1966,10 @@ bool Items::isRequestedTradeGood(df::item *item, df::caravan_state *caravan) {
return false;
}

/// When called with game_ui = true, this is equivalent to Bay12's itemst::meltable()
/// (i.e., returning true if and only if the item has a "designate for melting" button in game)
bool Items::canMelt(df::item *item, bool game_ui) {
CHECK_NULL_POINTER(item);
MaterialInfo mat(item);
if (mat.getCraftClass() != craft_material_class::Metal)
return false;

switch(item->getType())
bool Items::usesStandardMaterial(df::item_type item_type)
{
switch(item_type)
{ using namespace df::enums::item_type;
// These are not meltable, even if made from metal
case CORPSE:
case CORPSEPIECE:
case REMAINS:
Expand All @@ -1984,8 +1981,20 @@ bool Items::canMelt(df::item *item, bool game_ui) {
case EGG:
return false;
default:
break;
return true;
}
}

/// When called with game_ui = true, this is equivalent to Bay12's itemst::meltable()
/// (i.e., returning true if and only if the item has a "designate for melting" button in game)
bool Items::canMelt(df::item *item, bool game_ui) {
CHECK_NULL_POINTER(item);
MaterialInfo mat(item);
if (mat.getCraftClass() != craft_material_class::Metal)
return false;

if (!usesStandardMaterial(item->getType()))
return false;

if (item->flags.bits.artifact)
return false;
Expand Down
Loading