-
+
This plugin makes reactions with names starting with SPATTER_ADD_
produce contaminants on the items instead of improvements. The produced
contaminants are immune to being washed away by water or destroyed by
diff --git a/Readme.rst b/Readme.rst
index 9b8fd07cb..499920cab 100644
--- a/Readme.rst
+++ b/Readme.rst
@@ -2335,6 +2335,10 @@ alternatively pass cage IDs as arguments::
stripcaged weapons 25321 34228
+undump-buildings
+================
+Undesignates building base materials for dumping.
+
create-items
============
Spawn arbitrary items under the cursor.
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp
index 8c76a36f7..3a374445f 100644
--- a/library/LuaApi.cpp
+++ b/library/LuaApi.cpp
@@ -1337,6 +1337,7 @@ static const LuaWrapper::FunctionReg dfhack_job_module[] = {
WRAPM(Job,checkDesignationsNow),
WRAPM(Job,isSuitableItem),
WRAPM(Job,isSuitableMaterial),
+ WRAPM(Job,getName),
WRAPN(is_equal, jobEqual),
WRAPN(is_item_equal, jobItemEqual),
{ NULL, NULL }
@@ -1475,6 +1476,8 @@ static const LuaWrapper::FunctionReg dfhack_items_module[] = {
WRAPM(Items, isCasteMaterial),
WRAPM(Items, getSubtypeCount),
WRAPM(Items, getSubtypeDef),
+ WRAPM(Items, getItemBaseValue),
+ WRAPM(Items, getValue),
WRAPN(moveToGround, items_moveToGround),
WRAPN(moveToContainer, items_moveToContainer),
WRAPN(moveToBuilding, items_moveToBuilding),
diff --git a/library/include/df/custom/viewscreen.methods.inc b/library/include/df/custom/viewscreen.methods.inc
new file mode 100644
index 000000000..c5d277716
--- /dev/null
+++ b/library/include/df/custom/viewscreen.methods.inc
@@ -0,0 +1 @@
+friend struct df::interfacest;
diff --git a/library/include/modules/Items.h b/library/include/modules/Items.h
index 34ca98162..e5b6eb4df 100644
--- a/library/include/modules/Items.h
+++ b/library/include/modules/Items.h
@@ -173,5 +173,11 @@ DFHACK_EXPORT bool remove(MapExtras::MapCache &mc, df::item *item, bool no_uncat
/// Detaches the items from its current location and turns it into a projectile
DFHACK_EXPORT df::proj_itemst *makeProjectile(MapExtras::MapCache &mc, df::item *item);
+
+/// Gets value of base-quality item with specified type and material
+DFHACK_EXPORT int getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat_type, int32_t mat_subtype);
+
+/// Gets the value of a specific item, ignoring civ values and trade agreements
+DFHACK_EXPORT int getValue(df::item *item);
}
}
diff --git a/library/include/modules/Job.h b/library/include/modules/Job.h
index b13d9c5a9..4b3950ebd 100644
--- a/library/include/modules/Job.h
+++ b/library/include/modules/Job.h
@@ -81,6 +81,7 @@ namespace DFHack
DFHACK_EXPORT bool isSuitableItem(df::job_item *item, df::item_type itype, int isubtype);
DFHACK_EXPORT bool isSuitableMaterial(df::job_item *item, int mat_type, int mat_index);
+ DFHACK_EXPORT std::string getName(df::job *job);
}
DFHACK_EXPORT bool operator== (const df::job_item &a, const df::job_item &b);
diff --git a/library/modules/EventManager.cpp b/library/modules/EventManager.cpp
index bfc7c4907..88f4d56d6 100644
--- a/library/modules/EventManager.cpp
+++ b/library/modules/EventManager.cpp
@@ -30,6 +30,7 @@
using namespace std;
using namespace DFHack;
using namespace EventManager;
+using namespace df::enums;
/*
* TODO:
@@ -322,12 +323,8 @@ static void manageJobInitiatedEvent(color_ostream& out) {
//helper function for manageJobCompletedEvent
static int32_t getWorkerID(df::job* job) {
- for ( size_t a = 0; a < job->general_refs.size(); a++ ) {
- if ( job->general_refs[a]->getType() != df::enums::general_ref_type::UNIT_WORKER )
- continue;
- return ((df::general_ref_unit_workerst*)job->general_refs[a])->unit_id;
- }
- return -1;
+ auto ref = findRef(job->general_refs, general_ref_type::UNIT_WORKER);
+ return ref ? ref->getID() : -1;
}
/*
diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp
index 6673e6f1b..38d63d867 100644
--- a/library/modules/Items.cpp
+++ b/library/modules/Items.cpp
@@ -534,7 +534,7 @@ bool Items::setOwner(df::item *item, df::unit *unit)
{
df::general_ref *ref = item->general_refs[i];
- if (!strict_virtual_cast(ref))
+ if (ref->getType() != general_ref_type::UNIT_ITEMOWNER)
continue;
if (auto cur = ref->getUnit())
@@ -997,16 +997,22 @@ df::proj_itemst *Items::makeProjectile(MapExtras::MapCache &mc, df::item *item)
if (!ref)
return NULL;
+ auto proj = df::allocate();
+ if (!proj) {
+ delete ref;
+ return NULL;
+ }
+
if (!detachItem(mc, item))
{
delete ref;
+ delete proj;
return NULL;
}
item->pos = pos;
item->flags.bits.in_job = true;
- auto proj = new df::proj_itemst();
proj->link = new df::proj_list_link();
proj->link->item = proj;
proj->id = (*proj_next_id)++;
@@ -1022,3 +1028,303 @@ df::proj_itemst *Items::makeProjectile(MapExtras::MapCache &mc, df::item *item)
return proj;
}
+
+int Items::getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat_type, int32_t mat_subtype)
+{
+ int value = 0;
+ switch (item_type)
+ {
+ case item_type::BAR:
+ case item_type::SMALLGEM:
+ case item_type::BLOCKS:
+ case item_type::SKIN_TANNED:
+ value = 5;
+ break;
+
+ case item_type::ROUGH:
+ case item_type::BOULDER:
+ case item_type::WOOD:
+ value = 3;
+ break;
+
+ case item_type::DOOR:
+ case item_type::FLOODGATE:
+ case item_type::BED:
+ case item_type::CHAIR:
+ case item_type::CHAIN:
+ case item_type::FLASK:
+ case item_type::GOBLET:
+ case item_type::INSTRUMENT:
+ case item_type::TOY:
+ case item_type::CAGE:
+ case item_type::BARREL:
+ case item_type::BUCKET:
+ case item_type::ANIMALTRAP:
+ case item_type::TABLE:
+ case item_type::COFFIN:
+ case item_type::BOX:
+ case item_type::BIN:
+ case item_type::ARMORSTAND:
+ case item_type::WEAPONRACK:
+ case item_type::CABINET:
+ case item_type::FIGURINE:
+ case item_type::AMULET:
+ case item_type::SCEPTER:
+ case item_type::CROWN:
+ case item_type::RING:
+ case item_type::EARRING:
+ case item_type::BRACELET:
+ case item_type::GEM:
+ case item_type::ANVIL:
+ case item_type::TOTEM:
+ case item_type::BACKPACK:
+ case item_type::QUIVER:
+ case item_type::BALLISTAARROWHEAD:
+ case item_type::PIPE_SECTION:
+ case item_type::HATCH_COVER:
+ case item_type::GRATE:
+ case item_type::QUERN:
+ case item_type::MILLSTONE:
+ case item_type::SPLINT:
+ case item_type::CRUTCH:
+ case item_type::SLAB:
+ case item_type::BOOK:
+ value = 10;
+ break;
+
+ case item_type::WINDOW:
+ case item_type::STATUE:
+ value = 25;
+ break;
+
+ case item_type::CORPSE:
+ case item_type::CORPSEPIECE:
+ case item_type::REMAINS:
+ return 0;
+
+ case item_type::WEAPON:
+ if (size_t(item_subtype) < world->raws.itemdefs.weapons.size())
+ value = world->raws.itemdefs.weapons[item_subtype]->value;
+ else
+ value = 10;
+ break;
+
+ case item_type::ARMOR:
+ if (size_t(item_subtype) < world->raws.itemdefs.armor.size())
+ value = world->raws.itemdefs.armor[item_subtype]->value;
+ else
+ value = 10;
+ break;
+
+ case item_type::SHOES:
+ if (size_t(item_subtype) < world->raws.itemdefs.shoes.size())
+ value = world->raws.itemdefs.shoes[item_subtype]->value;
+ else
+ value = 5;
+ break;
+
+ case item_type::SHIELD:
+ if (size_t(item_subtype) < world->raws.itemdefs.shields.size())
+ value = world->raws.itemdefs.shields[item_subtype]->value;
+ else
+ value = 10;
+ break;
+
+ case item_type::HELM:
+ if (size_t(item_subtype) < world->raws.itemdefs.helms.size())
+ value = world->raws.itemdefs.helms[item_subtype]->value;
+ else
+ value = 10;
+ break;
+
+ case item_type::GLOVES:
+ if (size_t(item_subtype) < world->raws.itemdefs.gloves.size())
+ value = world->raws.itemdefs.gloves[item_subtype]->value;
+ else
+ value = 5;
+ break;
+
+ case item_type::AMMO:
+ if (size_t(item_subtype) < world->raws.itemdefs.ammo.size())
+ value = world->raws.itemdefs.ammo[item_subtype]->value;
+ else
+ value = 1;
+ break;
+
+ case item_type::MEAT:
+ case item_type::PLANT:
+ case item_type::LEAVES:
+ case item_type::CHEESE:
+ value = 2;
+ break;
+
+ case item_type::FISH:
+ case item_type::FISH_RAW:
+ case item_type::EGG:
+ value = 2;
+ if (size_t(mat_type) < world->raws.creatures.all.size())
+ {
+ auto creature = world->raws.creatures.all[mat_type];
+ if (size_t(mat_subtype) < creature->caste.size())
+ {
+ auto caste = creature->caste[mat_subtype];
+ mat_type = caste->misc.bone_mat;
+ mat_subtype = caste->misc.bone_matidx;
+ }
+ }
+ break;
+
+ case item_type::VERMIN:
+ value = 0;
+ if (size_t(mat_type) < world->raws.creatures.all.size())
+ {
+ auto creature = world->raws.creatures.all[mat_type];
+ if (size_t(mat_subtype) < creature->caste.size())
+ value = creature->caste[mat_subtype]->misc.petvalue;
+ }
+ value /= 2;
+ if (!value)
+ return 1;
+ return value;
+
+ case item_type::PET:
+ if (size_t(mat_type) < world->raws.creatures.all.size())
+ {
+ auto creature = world->raws.creatures.all[mat_type];
+ if (size_t(mat_subtype) < creature->caste.size())
+ return creature->caste[mat_subtype]->misc.petvalue;
+ }
+ return 0;
+
+ case item_type::SEEDS:
+ case item_type::DRINK:
+ case item_type::POWDER_MISC:
+ case item_type::LIQUID_MISC:
+ case item_type::COIN:
+ case item_type::GLOB:
+ case item_type::ORTHOPEDIC_CAST:
+ value = 1;
+ break;
+
+ case item_type::THREAD:
+ value = 6;
+ break;
+
+ case item_type::CLOTH:
+ value = 7;
+ break;
+
+ case item_type::PANTS:
+ if (size_t(item_subtype) < world->raws.itemdefs.pants.size())
+ value = world->raws.itemdefs.pants[item_subtype]->value;
+ else
+ value = 10;
+ break;
+
+ case item_type::CATAPULTPARTS:
+ case item_type::BALLISTAPARTS:
+ case item_type::TRAPPARTS:
+ value = 30;
+ break;
+
+ case item_type::SIEGEAMMO:
+ case item_type::TRACTION_BENCH:
+ value = 20;
+ break;
+
+ case item_type::TRAPCOMP:
+ if (size_t(item_subtype) < world->raws.itemdefs.trapcomps.size())
+ value = world->raws.itemdefs.trapcomps[item_subtype]->value;
+ else
+ value = 10;
+ break;
+
+ case item_type::FOOD:
+ return 10;
+
+// case item_type::ROCK:
+ default:
+ return 0;
+
+ case item_type::TOOL:
+ if (size_t(item_subtype) < world->raws.itemdefs.tools.size())
+ value = world->raws.itemdefs.tools[item_subtype]->value;
+ else
+ value = 10;
+ break;
+ }
+
+ MaterialInfo mat;
+ if (mat.decode(mat_type, mat_subtype))
+ value *= mat.material->material_value;
+ return value;
+}
+
+int Items::getValue(df::item *item)
+{
+ CHECK_NULL_POINTER(item);
+
+ int16_t item_type = item->getType();
+ int16_t item_subtype = item->getSubtype();
+ int16_t mat_type = item->getMaterial();
+ int32_t mat_subtype = item->getMaterialIndex();
+
+ // Get base value for item type, subtype, and material
+ int value = getItemBaseValue(item_type, item_subtype, mat_type, mat_subtype);
+
+ // Ignore entity value modifications
+
+ // Improve value based on quality
+ int quality = item->getQuality();
+ value *= (quality + 1);
+ if (quality == 5)
+ value *= 2;
+
+ // Add improvement values
+ int impValue = item->getThreadDyeValue(NULL) + item->getImprovementsValue(NULL);
+ if (item_type == item_type::AMMO) // Ammo improvements are worth less
+ impValue /= 30;
+ value += impValue;
+
+ // Degrade value due to wear
+ switch (item->getWear())
+ {
+ case 1:
+ value = value * 3 / 4;
+ break;
+ case 2:
+ value = value / 2;
+ break;
+ case 3:
+ value = value / 4;
+ break;
+ }
+
+ // Ignore value bonuses from magic, since that never actually happens
+
+ // Artifacts have 10x value
+ if (item->flags.bits.artifact_mood)
+ value *= 10;
+
+ // Boost value from stack size
+ value *= item->getStackSize();
+ // ...but not for coins
+ if (item_type == item_type::COIN)
+ {
+ value /= 500;
+ if (!value)
+ value = 1;
+ }
+
+ // Handle vermin swarms
+ if (item_type == item_type::VERMIN || item_type == item_type::PET)
+ {
+ int divisor = 1;
+ auto creature = vector_get(world->raws.creatures.all, mat_type);
+ if (creature && size_t(mat_subtype) < creature->caste.size())
+ divisor = creature->caste[mat_subtype]->misc.petvalue_divisor;
+ if (divisor > 1)
+ value /= divisor;
+ }
+ return value;
+}
\ No newline at end of file
diff --git a/library/modules/Job.cpp b/library/modules/Job.cpp
index a86a82d8a..1cfc0fa78 100644
--- a/library/modules/Job.cpp
+++ b/library/modules/Job.cpp
@@ -53,6 +53,7 @@ using namespace std;
#include "df/general_ref.h"
#include "df/general_ref_unit_workerst.h"
#include "df/general_ref_building_holderst.h"
+#include "df/interface_button_building_new_jobst.h"
using namespace DFHack;
using namespace df::enums;
@@ -92,7 +93,7 @@ df::job *DFHack::Job::cloneJobStruct(df::job *job, bool keepEverything)
pnew->job_items[a] = new df::job_item(*pnew->job_items[a]);
for ( size_t a = 0; a < job->general_refs.size(); a++ )
- if ( keepEverything || job->general_refs[a]->getType() != df::enums::general_ref_type::UNIT_WORKER )
+ if ( keepEverything || job->general_refs[a]->getType() != general_ref_type::UNIT_WORKER )
pnew->general_refs.push_back(job->general_refs[a]->clone());
return pnew;
@@ -264,28 +265,18 @@ df::building *DFHack::Job::getHolder(df::job *job)
{
CHECK_NULL_POINTER(job);
- for (size_t i = 0; i < job->general_refs.size(); i++)
- {
- VIRTUAL_CAST_VAR(ref, df::general_ref_building_holderst, job->general_refs[i]);
- if (ref)
- return ref->getBuilding();
- }
+ auto ref = getGeneralRef(job, general_ref_type::BUILDING_HOLDER);
- return NULL;
+ return ref ? ref->getBuilding() : NULL;
}
df::unit *DFHack::Job::getWorker(df::job *job)
{
CHECK_NULL_POINTER(job);
- for (size_t i = 0; i < job->general_refs.size(); i++)
- {
- VIRTUAL_CAST_VAR(ref, df::general_ref_unit_workerst, job->general_refs[i]);
- if (ref)
- return ref->getUnit();
- }
+ auto ref = getGeneralRef(job, general_ref_type::UNIT_WORKER);
- return NULL;
+ return ref ? ref->getUnit() : NULL;
}
void DFHack::Job::setJobCooldown(df::building *workshop, df::unit *worker, int cooldown)
@@ -325,8 +316,8 @@ bool DFHack::Job::removeWorker(df::job *job, int cooldown)
for (size_t i = 0; i < job->general_refs.size(); i++)
{
- VIRTUAL_CAST_VAR(ref, df::general_ref_unit_workerst, job->general_refs[i]);
- if (!ref)
+ df::general_ref *ref = job->general_refs[i];
+ if (ref->getType() != general_ref_type::UNIT_WORKER)
continue;
auto worker = ref->getUnit();
@@ -476,3 +467,25 @@ bool Job::isSuitableMaterial(df::job_item *item, int mat_type, int mat_index)
return minfo.isValid() && iinfo.matches(*item, &minfo);
}
+
+std::string Job::getName(df::job *job)
+{
+ CHECK_NULL_POINTER(job);
+
+ std::string desc;
+ auto button = df::allocate();
+ button->reaction_name = job->reaction_name;
+ button->hist_figure_id = job->hist_figure_id;
+ button->job_type = job->job_type;
+ button->item_type = job->item_type;
+ button->item_subtype = job->item_subtype;
+ button->mat_type = job->mat_type;
+ button->mat_index = job->mat_index;
+ button->item_category = job->item_category;
+ button->material_category = job->material_category;
+
+ button->getLabel(&desc);
+ delete button;
+
+ return desc;
+}
diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp
index 655371091..fd1ccc523 100644
--- a/library/modules/Maps.cpp
+++ b/library/modules/Maps.cpp
@@ -584,8 +584,8 @@ bool Maps::canStepBetween(df::coord pos1, df::coord pos2)
if ( dx == 0 && dy == 0 ) {
//check for forbidden hatches and floors and such
- df::enums::tile_building_occ::tile_building_occ upOcc = index_tile(block2->occupancy,pos2).bits.building;
- if ( upOcc == df::enums::tile_building_occ::Impassable || upOcc == df::enums::tile_building_occ::Obstacle || upOcc == df::enums::tile_building_occ::Floored )
+ df::tile_building_occ upOcc = index_tile(block2->occupancy,pos2).bits.building;
+ if ( upOcc == tile_building_occ::Impassable || upOcc == tile_building_occ::Obstacle || upOcc == tile_building_occ::Floored )
return false;
if ( shape1 == tiletype_shape::STAIR_UPDOWN && shape2 == shape1 )
@@ -617,7 +617,7 @@ bool Maps::canStepBetween(df::coord pos1, df::coord pos2)
return false; //unusable ramp
//there has to be an unforbidden hatch above the ramp
- if ( index_tile(block2->occupancy,pos2).bits.building != df::enums::tile_building_occ::Dynamic )
+ if ( index_tile(block2->occupancy,pos2).bits.building != tile_building_occ::Dynamic )
return false;
//note that forbidden hatches have Floored occupancy. unforbidden ones have dynamic occupancy
df::building* building = Buildings::findAtTile(pos2);
@@ -625,7 +625,7 @@ bool Maps::canStepBetween(df::coord pos1, df::coord pos2)
out << __FILE__ << ", line " << __LINE__ << ": couldn't find hatch.\n";
return false;
}
- if ( building->getType() != df::enums::building_type::Hatch ) {
+ if ( building->getType() != building_type::Hatch ) {
return false;
}
return true;
@@ -661,8 +661,8 @@ bool Maps::canStepBetween(df::coord pos1, df::coord pos2)
if ( !blockUp )
return false;
- df::enums::tile_building_occ::tile_building_occ occupancy = index_tile(blockUp->occupancy,up).bits.building;
- if ( occupancy == df::enums::tile_building_occ::Obstacle || occupancy == df::enums::tile_building_occ::Floored || occupancy == df::enums::tile_building_occ::Impassable )
+ df::tile_building_occ occupancy = index_tile(blockUp->occupancy,up).bits.building;
+ if ( occupancy == tile_building_occ::Obstacle || occupancy == tile_building_occ::Floored || occupancy == tile_building_occ::Impassable )
return false;
return true;
}
diff --git a/library/xml b/library/xml
index 42736fe49..499507eac 160000
--- a/library/xml
+++ b/library/xml
@@ -1 +1 @@
-Subproject commit 42736fe494e7edeb884caa45a8669996a0eafb11
+Subproject commit 499507eac5bdd3abc70e204497248627327cf8de
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
index 6e1425b9c..e13284274 100644
--- a/plugins/CMakeLists.txt
+++ b/plugins/CMakeLists.txt
@@ -164,6 +164,7 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(3dveins 3dveins.cpp)
DFHACK_PLUGIN(strangemood strangemood.cpp)
DFHACK_PLUGIN(command-prompt command-prompt.cpp)
+ DFHACK_PLUGIN(building-hacks building-hacks.cpp LINK_LIBRARIES lua)
endif()
# this is the skeleton plugin. If you want to make your own, make a copy and then change it
diff --git a/plugins/building-hacks.cpp b/plugins/building-hacks.cpp
new file mode 100644
index 000000000..b9c9ea3c9
--- /dev/null
+++ b/plugins/building-hacks.cpp
@@ -0,0 +1,389 @@
+//most of the code is shamelessly stolen from steam-engine.cpp
+#include "Core.h"
+#include "Error.h"
+#include
+#include
+#include
+
+#include "LuaTools.h"
+#include
+#include "MiscUtils.h"
+
+#include "df/building_doorst.h"
+#include "df/building_workshopst.h"
+#include "df/machine.h"
+#include "df/machine_tile_set.h"
+#include "df/power_info.h"
+#include "df/world.h"
+#include "df/buildings_other_id.h"
+#include "df/coord.h"
+#include "df/tile_building_occ.h"
+#include "df/building_drawbuffer.h"
+
+#include