Add "tweak cage-butcher" and some extra Building module functions

* Buildings::markedForRemoval()
* Buildings::getCageOccupants()

Closes #906
develop
lethosor 2017-06-25 15:21:45 -04:00
parent db375ae83b
commit 10e13c532a
8 changed files with 189 additions and 5 deletions

@ -198,6 +198,7 @@ tweak embark-profile-name
# Misc. UI tweaks
tweak block-labors # Prevents labors that can't be used from being toggled
tweak cage-butcher
tweak civ-view-agreement
tweak eggs-fertile
tweak fps-min

@ -1486,6 +1486,12 @@ General
Returns a list of items stored on the given stockpile.
Ignores empty bins, barrels, and wheelbarrows assigned as storage and transport for that stockpile.
* ``dfhack.buildings.getCageOccupants(cage)``
Returns a list of units in the given built cage. Note that this is different
from the list of units assigned to the cage, which can be accessed with
``cage.assigned_units``.
Low-level
~~~~~~~~~
Low-level building creation functions:
@ -1531,6 +1537,11 @@ Low-level building creation functions:
Destroys the building, or queues a deconstruction job.
Returns *true* if the building was destroyed and deallocated immediately.
* ``dfhack.buildings.markedForRemoval(building)``
Returns *true* if the building is marked for removal (with :kbd:`x`), *false*
otherwise.
High-level
~~~~~~~~~~
More high-level functions are implemented in lua and can be loaded by

@ -275,6 +275,7 @@ Subcommands that persist until disabled or DF quits:
the contents separately from the container. This forcefully skips child
reagents.
:block-labors: Prevents labors that can't be used from being toggled
:cage-butcher: Adds an option to butcher units when viewing cages with :kbd:`q`
:civ-view-agreement: Fixes overlapping text on the "view agreement" screen
:condition-material: Fixes a crash in the work order contition material list (:bug:`9905`).
:craft-age-wear: Fixes the behavior of crafted items wearing out over time (:bug:`6003`).

@ -85,6 +85,7 @@ distribution.
#include "df/dfhack_material_category.h"
#include "df/job_material_category.h"
#include "df/burrow.h"
#include "df/building_cagest.h"
#include "df/building_civzonest.h"
#include "df/region_map_entry.h"
#include "df/flow_info.h"
@ -1985,6 +1986,7 @@ static const LuaWrapper::FunctionReg dfhack_buildings_module[] = {
WRAPM(Buildings, isPenPasture),
WRAPM(Buildings, isPitPond),
WRAPM(Buildings, isActive),
WRAPM(Buildings, markedForRemoval),
{ NULL, NULL }
};
@ -2066,6 +2068,14 @@ static int buildings_getStockpileContents(lua_State *state)
return 1;
}
static int buildings_getCageOccupants(lua_State *state)
{
std::vector<df::unit*> units;
Buildings::getCageOccupants(Lua::CheckDFObject<df::building_cagest>(state, 1), units);
Lua::PushVector(state, units);
return 1;
}
static const luaL_Reg dfhack_buildings_funcs[] = {
{ "findAtTile", buildings_findAtTile },
{ "findCivzonesAt", buildings_findCivzonesAt },
@ -2073,6 +2083,7 @@ static const luaL_Reg dfhack_buildings_funcs[] = {
{ "setSize", &Lua::CallWithCatchWrapper<buildings_setSize> },
{ "getStockpileContents", buildings_getStockpileContents },
{ "findPenPitAt", buildings_findPenPitAt },
{ "getCageOccupants", &Lua::CallWithCatchWrapper<buildings_getCageOccupants> },
{ NULL, NULL }
};

@ -43,10 +43,12 @@ distribution.
namespace df
{
struct job_item;
struct item;
struct building_extents;
struct building_cagest;
struct building_civzonest;
struct building_extents;
struct item;
struct job_item;
struct unit;
}
namespace DFHack
@ -188,6 +190,11 @@ DFHACK_EXPORT bool constructWithFilters(df::building *bld, std::vector<df::job_i
*/
DFHACK_EXPORT bool deconstruct(df::building *bld);
/**
* Determines whether this building is marked for removal.
*/
DFHACK_EXPORT bool markedForRemoval(df::building *bld);
void updateBuildings(color_ostream& out, void* ptr);
void clearBuildings(color_ostream& out);
@ -249,5 +256,10 @@ DFHACK_EXPORT bool isHospital(df::building * building);
DFHACK_EXPORT bool isAnimalTraining(df::building * building);
DFHACK_EXPORT df::building* findPenPitAt(df::coord coord);
/**
* Returns the units currently in the given cage
*/
DFHACK_EXPORT bool getCageOccupants(df::building_cagest *cage, std::vector<df::unit*> &units);
}
}

@ -54,6 +54,7 @@ using namespace DFHack;
#include "df/building_bars_floorst.h"
#include "df/building_bars_verticalst.h"
#include "df/building_bridgest.h"
#include "df/building_cagest.h"
#include "df/building_civzonest.h"
#include "df/building_coffinst.h"
#include "df/building_def.h"
@ -72,7 +73,9 @@ using namespace DFHack;
#include "df/buildings_other_id.h"
#include "df/d_init.h"
#include "df/general_ref_building_holderst.h"
#include "df/general_ref_contains_unitst.h"
#include "df/item.h"
#include "df/item_cagest.h"
#include "df/job.h"
#include "df/job_item.h"
#include "df/map_block.h"
@ -1171,6 +1174,19 @@ bool Buildings::deconstruct(df::building *bld)
return true;
}
bool Buildings::markedForRemoval(df::building *bld)
{
CHECK_NULL_POINTER(bld);
for (df::job *job : bld->jobs)
{
if (job && job->job_type == df::job_type::DestroyBuilding)
{
return true;
}
}
return false;
}
static unordered_map<int32_t, df::coord> corner1;
static unordered_map<int32_t, df::coord> corner2;
@ -1350,3 +1366,29 @@ StockpileIterator& StockpileIterator::operator++() {
return *this;
}
bool Buildings::getCageOccupants(df::building_cagest *cage, vector<df::unit*> &units)
{
CHECK_NULL_POINTER(cage);
if (!world)
return false;
if (cage->contained_items.empty())
return false;
auto *cage_item = virtual_cast<df::item_cagest>(cage->contained_items[0]->item);
if (!cage_item)
return false;
units.clear();
for (df::general_ref *gref : cage_item->general_refs)
{
auto ref = virtual_cast<df::general_ref_contains_unitst>(gref);
if (ref)
{
df::unit *unit = df::unit::find(ref->unit_id);
if (unit)
units.push_back(unit);
}
}
return true;
}

@ -80,6 +80,7 @@
#include "tweaks/adamantine-cloth-wear.h"
#include "tweaks/advmode-contained.h"
#include "tweaks/block-labors.h"
#include "tweaks/cage-butcher.h"
#include "tweaks/civ-agreement-ui.h"
#include "tweaks/condition-material.h"
#include "tweaks/craft-age-wear.h"
@ -117,6 +118,8 @@ REQUIRE_GLOBAL(enabler);
REQUIRE_GLOBAL(ui);
REQUIRE_GLOBAL(ui_area_map_width);
REQUIRE_GLOBAL(ui_build_selector);
REQUIRE_GLOBAL(ui_building_in_assign);
REQUIRE_GLOBAL(ui_building_in_resize);
REQUIRE_GLOBAL(ui_building_item_cursor);
REQUIRE_GLOBAL(ui_menu_width);
REQUIRE_GLOBAL(ui_look_cursor);
@ -183,6 +186,8 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector <Plugi
" from the container. This forcefully skips child reagents.\n"
" tweak block-labors [disable]\n"
" Prevents labors that can't be used from being toggled.\n"
" tweak cage-butcher [disable]\n"
" Adds an option to butcher units when viewing cages.\n"
" tweak civ-view-agreement\n"
" Fixes overlapping text on the \"view agreement\" screen\n"
" tweak condition-material\n"
@ -250,6 +255,9 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector <Plugi
TWEAK_HOOK("block-labors", block_labors_hook, feed);
TWEAK_HOOK("block-labors", block_labors_hook, render);
TWEAK_HOOK("cage-butcher", cage_butcher_hook, feed);
TWEAK_HOOK("cage-butcher", cage_butcher_hook, render);
TWEAK_HOOK("civ-view-agreement", civ_agreement_view_hook, render);
TWEAK_HOOK("condition-material", condition_material_hook, feed);

@ -0,0 +1,98 @@
#include "modules/Gui.h"
#include "modules/Screen.h"
#include "df/building_cagest.h"
#include "df/viewscreen_dwarfmodest.h"
#include "df/ui_sidebar_mode.h"
#include "df/unit.h"
using namespace DFHack;
using df::global::ui;
using df::global::ui_building_in_assign;
using df::global::ui_building_in_resize;
using df::global::ui_building_item_cursor;
struct cage_butcher_hook : df::viewscreen_dwarfmodest {
typedef df::viewscreen_dwarfmodest interpose_base;
inline df::building_cagest *get_cage()
{
if (*ui_building_in_assign || *ui_building_in_resize)
return nullptr;
if (ui->main.mode != df::ui_sidebar_mode::QueryBuilding)
return nullptr;
auto cage = virtual_cast<df::building_cagest>(Gui::getAnyBuilding(this));
if (!cage)
return nullptr;
if (cage->getBuildStage() < cage->getMaxBuildStage())
return nullptr;
if (cage->flags.bits.justice)
return nullptr;
if (Buildings::markedForRemoval(cage))
return nullptr;
return cage;
}
DEFINE_VMETHOD_INTERPOSE(void, render, ())
{
using namespace df::enums::interface_key;
INTERPOSE_NEXT(render)();
auto cage = get_cage();
if (!cage)
return;
std::vector<df::unit*> units;
if (!Buildings::getCageOccupants(cage, units))
return;
auto dims = Gui::getDwarfmodeViewDims();
for (int y = 4, i = (*ui_building_item_cursor/11)*11;
y <= 14 && i < units.size();
++y, ++i)
{
df::unit *unit = vector_get(units, i);
if (unit && unit->flags2.bits.slaughter)
{
int x = dims.menu_x2 - 2;
OutputString(COLOR_LIGHTMAGENTA, x, y, "Bu");
}
}
int x = dims.menu_x1 + 1, y = dims.y2;
OutputHotkeyString(x, y, "Butcher ", CUSTOM_B, false, 0, COLOR_WHITE, COLOR_LIGHTRED);
OutputHotkeyString(x, y, "all", CUSTOM_SHIFT_B, false, 0, COLOR_WHITE, COLOR_LIGHTRED);
}
DEFINE_VMETHOD_INTERPOSE(void, feed, (std::set<df::interface_key> *input))
{
using namespace df::enums::interface_key;
auto cage = get_cage();
if (cage)
{
std::vector<df::unit*> units;
if (Buildings::getCageOccupants(cage, units))
{
df::unit *unit = vector_get(units, *ui_building_item_cursor);
if (unit)
{
if (input->count(CUSTOM_B))
{
unit->flags2.bits.slaughter = !unit->flags2.bits.slaughter;
}
}
if (input->count(CUSTOM_SHIFT_B))
{
bool state = unit ? !unit->flags2.bits.slaughter : true;
for (auto u : units)
u->flags2.bits.slaughter = state;
}
}
}
INTERPOSE_NEXT(feed)(input);
}
};
IMPLEMENT_VMETHOD_INTERPOSE(cage_butcher_hook, feed);
IMPLEMENT_VMETHOD_INTERPOSE(cage_butcher_hook, render);