autoclothing: support disable

this also includes some minor refactorings:
* some debug messages have been "tagged" so it's obvious they're from autoclothing
* a serialized list of flag checks has been replaced with a maskcheck
* partial lua api added, currently only supports enable/disable
develop
Kelly Kinkade 2023-03-25 12:25:45 -05:00
parent 9f5e4eeda1
commit 1c25c9b80c
2 changed files with 86 additions and 30 deletions

@ -77,7 +77,7 @@ set_source_files_properties( Brushes.h PROPERTIES HEADER_FILE_ONLY TRUE )
#dfhack_plugin(add-spatter add-spatter.cpp) #dfhack_plugin(add-spatter add-spatter.cpp)
dfhack_plugin(autobutcher autobutcher.cpp LINK_LIBRARIES lua) dfhack_plugin(autobutcher autobutcher.cpp LINK_LIBRARIES lua)
dfhack_plugin(autochop autochop.cpp LINK_LIBRARIES lua) dfhack_plugin(autochop autochop.cpp LINK_LIBRARIES lua)
dfhack_plugin(autoclothing autoclothing.cpp) dfhack_plugin(autoclothing autoclothing.cpp LINK_LIBRARIES lua)
dfhack_plugin(autodump autodump.cpp) dfhack_plugin(autodump autodump.cpp)
dfhack_plugin(autofarm autofarm.cpp) dfhack_plugin(autofarm autofarm.cpp)
#dfhack_plugin(autogems autogems.cpp LINK_LIBRARIES jsoncpp_static) #dfhack_plugin(autogems autogems.cpp LINK_LIBRARIES jsoncpp_static)

@ -61,7 +61,25 @@ namespace DFHack {
} }
static const string CONFIG_KEY = string(plugin_name) + "/config"; static const string CONFIG_KEY = string(plugin_name) + "/config";
enum ConfigValues {
CONFIG_IS_ENABLED = 0,
};
//static int get_config_val(PersistentDataItem& c, int index) {
// if (!c.isValid())
// return -1;
// return c.ival(index);
//}
//static bool get_config_bool(PersistentDataItem& c, int index) {
// return get_config_val(c, index) == 1;
//}
static void set_config_val(PersistentDataItem& c, int index, int value) {
if (c.isValid())
c.ival(index) = value;
}
static void set_config_bool(PersistentDataItem& c, int index, bool value) {
set_config_val(c, index, value ? 1 : 0);
}
// Here go all the command declarations... // Here go all the command declarations...
// mostly to allow having the mandatory stuff on top of the file and commands on the bottom // mostly to allow having the mandatory stuff on top of the file and commands on the bottom
@ -250,6 +268,29 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
} }
DFhackCExport command_result plugin_enable(color_ostream& out, bool enable) {
if (!Core::getInstance().isWorldLoaded()) {
out.printerr("Cannot enable %s without a loaded world.\n", plugin_name);
return CR_FAILURE;
}
if (enable != autoclothing_enabled) {
auto enabled = World::GetPersistentData("autoclothing/enabled");
autoclothing_enabled = enable;
DEBUG(report, out).print("%s from the API; persisting\n",
autoclothing_enabled ? "enabled" : "disabled");
set_config_bool(enabled, CONFIG_IS_ENABLED, autoclothing_enabled);
if (enable)
do_autoclothing();
}
else {
DEBUG(report, out).print("%s from the API, but already %s; no action\n",
autoclothing_enabled ? "enabled" : "disabled",
autoclothing_enabled ? "enabled" : "disabled");
}
return CR_OK;
}
// Whatever you put here will be done in each game step. Don't abuse it. // Whatever you put here will be done in each game step. Don't abuse it.
// It's optional, so you can just comment it out like this if you don't need it. // It's optional, so you can just comment it out like this if you don't need it.
@ -389,6 +430,7 @@ command_result autoclothing(color_ostream &out, vector <string> & parameters)
if (parameters.size() == 0) if (parameters.size() == 0)
{ {
CoreSuspender suspend; CoreSuspender suspend;
out << "Automatic clothing management is currently " << (autoclothing_enabled ? "enabled" : "disabled") << "." << endl;
out << "Currently set " << clothingOrders.size() << " automatic clothing orders" << endl; out << "Currently set " << clothingOrders.size() << " automatic clothing orders" << endl;
for (size_t i = 0; i < clothingOrders.size(); i++) for (size_t i = 0; i < clothingOrders.size(); i++)
{ {
@ -523,7 +565,7 @@ static void find_needed_clothing_items()
if (!item) if (!item)
{ {
WARN(cycle).print("Invalid inventory item ID: %d\n", ownedItem); WARN(cycle).print("autoclothing: Invalid inventory item ID: %d\n", ownedItem);
continue; continue;
} }
@ -728,34 +770,28 @@ static void list_unit_counts(color_ostream& out, map<int, int>& unitList)
static bool isAvailableItem(df::item* item) static bool isAvailableItem(df::item* item)
{ {
if (item->flags.bits.in_job) static struct BadFlags {
return false; uint32_t whole;
if (item->flags.bits.hostile)
return false; BadFlags() {
if (item->flags.bits.in_building) df::item_flags flags;
return false; #define F(x) flags.bits.x = true;
if (item->flags.bits.in_building) F(in_job); F(hostile); F(in_building); F(encased);
return false; F(foreign); F(trader); F(owned); F(forbid);
if (item->flags.bits.encased) F(dump); F(on_fire); F(melt); F(hidden);
return false;
if (item->flags.bits.foreign) F(garbage_collect); F(rotten); F(construction);
return false; F(in_chest); F(removed); F(spider_web);
if (item->flags.bits.trader)
return false; // F(artifact); -- TODO: should this be included?
if (item->flags.bits.owned) #undef F
return false; whole = flags.whole;
if (item->flags.bits.artifact) }
return false; } badFlags;
if (item->flags.bits.forbid)
return false; if ((item->flags.whole & badFlags.whole) != 0)
if (item->flags.bits.dump)
return false;
if (item->flags.bits.on_fire)
return false;
if (item->flags.bits.melt)
return false;
if (item->flags.bits.hidden)
return false; return false;
if (item->getWear() > 1) if (item->getWear() > 1)
return false; return false;
if (!item->isClothing()) if (!item->isClothing())
@ -782,7 +818,7 @@ static void generate_report(color_ostream& out)
auto item = Items::findItemByID(itemId); auto item = Items::findItemByID(itemId);
if (!item) if (!item)
{ {
WARN(cycle,out).print("Invalid inventory item ID: %d\n", itemId); WARN(cycle,out).print("autoclothing: Invalid inventory item ID: %d\n", itemId);
continue; continue;
} }
if (item->getWear() >= 1) if (item->getWear() >= 1)
@ -915,3 +951,23 @@ static void generate_report(color_ostream& out)
} }
} }
/////////////////////////////////////////////////////
// Lua API
// TODO: implement Lua hooks to manipulate the persistent order configuration
//
static void autoclothing_doCycle(color_ostream& out) {
DEBUG(report, out).print("entering autoclothing_doCycle\n");
do_autoclothing();
}
DFHACK_PLUGIN_LUA_FUNCTIONS{
DFHACK_LUA_FUNCTION(autoclothing_doCycle),
DFHACK_LUA_END
};
DFHACK_PLUGIN_LUA_COMMANDS{
DFHACK_LUA_END
};