From ab4a38415a52dd494d3187931c6f1b48682829ad Mon Sep 17 00:00:00 2001
From: Eric Wald
Date: Wed, 24 Apr 2013 11:22:19 -0600
Subject: [PATCH 01/18] Building base material undump script.
Based on an idea in https://github.com/peterix/dfhack/issues/119
---
scripts/undump-buildings.lua | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
create mode 100644 scripts/undump-buildings.lua
diff --git a/scripts/undump-buildings.lua b/scripts/undump-buildings.lua
new file mode 100644
index 000000000..aa2af0397
--- /dev/null
+++ b/scripts/undump-buildings.lua
@@ -0,0 +1,29 @@
+-- Undesignates building base materials for dumping.
+function undump_buildings()
+ local buildings = df.global.world.buildings.all
+ local undumped = 0
+ for i = 0, #buildings - 1 do
+ local building = buildings[i]
+ -- Zones and stockpiles don't have the contained_items field.
+ if not (df.building_civzonest:is_instance(building) or
+ df.building_stockpilest:is_instance(building)) then
+ local items = building.contained_items
+ for j = 0, #items - 1 do
+ local contained = items[j]
+ if contained.use_mode == 2 and contained.item.flags.dump then
+ -- print(building, contained.item)
+ undumped = undumped + 1
+ contained.item.flags.dump = false
+ end
+ end
+ end
+ end
+
+ if undumped > 0 then
+ local s = "s"
+ if undumped == 1 then s = "" end
+ print("Undumped "..undumped.." item"..s..".")
+ end
+end
+
+undump_buildings()
From f41525665047e58b40cf3e9409fe5a2c02e9723a Mon Sep 17 00:00:00 2001
From: Eric Wald
Date: Sun, 5 May 2013 16:48:12 -0600
Subject: [PATCH 02/18] Better way to check for the contained_items field.
---
scripts/undump-buildings.lua | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/scripts/undump-buildings.lua b/scripts/undump-buildings.lua
index aa2af0397..fc1511343 100644
--- a/scripts/undump-buildings.lua
+++ b/scripts/undump-buildings.lua
@@ -5,8 +5,7 @@ function undump_buildings()
for i = 0, #buildings - 1 do
local building = buildings[i]
-- Zones and stockpiles don't have the contained_items field.
- if not (df.building_civzonest:is_instance(building) or
- df.building_stockpilest:is_instance(building)) then
+ if df.building_actual:is_instance(building) then
local items = building.contained_items
for j = 0, #items - 1 do
local contained = items[j]
From 9e85aa4280cf28efa75a8529b48dcada196ee6ca Mon Sep 17 00:00:00 2001
From: Tareq A Khandaker
Date: Mon, 6 May 2013 23:58:21 -0400
Subject: [PATCH 03/18] Ignore Mac OS X .DS_Store files
---
.gitignore | 3 +++
1 file changed, 3 insertions(+)
diff --git a/.gitignore b/.gitignore
index b4a578ec0..76e60f329 100644
--- a/.gitignore
+++ b/.gitignore
@@ -60,3 +60,6 @@ build/CPack*Config.cmake
# vim swap files
*.swp
+
+# Mac OS X .DS_Store files
+.DS_Store
From 94b59613729d8b77080bdbee6756a22370776e89 Mon Sep 17 00:00:00 2001
From: Warmist
Date: Wed, 1 Jan 2014 16:09:41 +0200
Subject: [PATCH 04/18] New plugin: building-hacks. Allows workshops to block
liquids and consume mechanical power, connect to machines.
---
plugins/CMakeLists.txt | 1 +
plugins/building-hacks.cpp | 234 +++++++++++++++++++++++++++++++++
plugins/lua/building-hacks.lua | 3 +
3 files changed, 238 insertions(+)
create mode 100644 plugins/building-hacks.cpp
create mode 100644 plugins/lua/building-hacks.lua
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
index 29acba8a1..7dfef3225 100644
--- a/plugins/CMakeLists.txt
+++ b/plugins/CMakeLists.txt
@@ -163,6 +163,7 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(cleanconst cleanconst.cpp)
DFHACK_PLUGIN(3dveins 3dveins.cpp)
DFHACK_PLUGIN(strangemood strangemood.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..321fef1fa
--- /dev/null
+++ b/plugins/building-hacks.cpp
@@ -0,0 +1,234 @@
+//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
embark
lever
stripcaged
+undump-buildings
create-items
soundsense-season
@@ -2867,6 +2868,10 @@ alternatively pass cage IDs as arguments:
stripcaged weapons 25321 34228
+
+
+
Undesignates building base materials for dumping.
+
Spawn arbitrary items under the cursor.
diff --git a/Readme.rst b/Readme.rst
index cd9101aab..8cc5aaa1b 100644
--- a/Readme.rst
+++ b/Readme.rst
@@ -2057,6 +2057,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.
From c3d45c3a1efb2b4e9db590c3bafaf0c5fdcdbcc7 Mon Sep 17 00:00:00 2001
From: Quietust
Date: Wed, 23 Apr 2014 08:03:10 -0500
Subject: [PATCH 10/18] Add Job::getName(job *), also available from Lua
---
library/LuaApi.cpp | 1 +
library/include/modules/Job.h | 1 +
library/modules/Job.cpp | 23 +++++++++++++++++++++++
3 files changed, 25 insertions(+)
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp
index 8c76a36f7..4288802ea 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 }
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/Job.cpp b/library/modules/Job.cpp
index a86a82d8a..8750db4c7 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;
@@ -476,3 +477,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;
+}
From 57fbb1004b0c79fcd350a5a3a064f05b1f26c7ba Mon Sep 17 00:00:00 2001
From: Quietust
Date: Wed, 23 Apr 2014 08:23:34 -0500
Subject: [PATCH 11/18] Assorted cleanup
---
library/modules/EventManager.cpp | 9 +++------
library/modules/Items.cpp | 2 +-
library/modules/Job.cpp | 24 +++++++-----------------
library/modules/Maps.cpp | 12 ++++++------
4 files changed, 17 insertions(+), 30 deletions(-)
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..b243e5d85 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())
diff --git a/library/modules/Job.cpp b/library/modules/Job.cpp
index 8750db4c7..1cfc0fa78 100644
--- a/library/modules/Job.cpp
+++ b/library/modules/Job.cpp
@@ -93,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;
@@ -265,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)
@@ -326,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();
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;
}
From 0f4684f29dc77c0d2d79ee1ec99cf2cb9300b896 Mon Sep 17 00:00:00 2001
From: Quietust
Date: Fri, 25 Apr 2014 11:04:21 -0500
Subject: [PATCH 12/18] Add Items::getItemBaseValue and Items::getValue,
available from Lua
---
Lua API.html | 9 +
Lua API.rst | 12 ++
library/LuaApi.cpp | 2 +
library/include/modules/Items.h | 6 +
library/modules/Items.cpp | 297 ++++++++++++++++++++++++++++++++
5 files changed, 326 insertions(+)
diff --git a/Lua API.html b/Lua API.html
index bd17cc644..d73384241 100644
--- a/Lua API.html
+++ b/Lua API.html
@@ -1252,6 +1252,9 @@ the flags in the job item.
dfhack.job.isSuitableMaterial(job_item, mat_type, mat_index)
Likewise, if replacing material.
+dfhack.job.getName(job)
+Returns the job's description, as seen in the Units and Jobs screens.
+
@@ -1420,6 +1423,12 @@ Returns
false in case of error.
dfhack.items.getSubtypeDef(item_type, subtype)
Returns the raw definition for the given item type and subtype, or nil if invalid.
+
dfhack.items.getItemBaseValue(item_type, subtype, material, mat_index)
+Calculates the base value for an item of the specified type and material.
+
+
dfhack.items.getValue(item)
+Calculates the Basic Value of an item, as seen in the View Item screen.
+
diff --git a/Lua API.rst b/Lua API.rst
index 072d9265f..9afbb1e78 100644
--- a/Lua API.rst
+++ b/Lua API.rst
@@ -979,6 +979,10 @@ Job module
Likewise, if replacing material.
+* ``dfhack.job.getName(job)``
+
+ Returns the job's description, as seen in the Units and Jobs screens.
+
Units module
------------
@@ -1187,6 +1191,14 @@ Items module
Returns the raw definition for the given item type and subtype, or *nil* if invalid.
+* ``dfhack.items.getItemBaseValue(item_type, subtype, material, mat_index)``
+
+ Calculates the base value for an item of the specified type and material.
+
+* ``dfhack.items.getValue(item)``
+
+ Calculates the Basic Value of an item, as seen in the View Item screen.
+
Maps module
-----------
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp
index 4288802ea..3a374445f 100644
--- a/library/LuaApi.cpp
+++ b/library/LuaApi.cpp
@@ -1476,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/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/modules/Items.cpp b/library/modules/Items.cpp
index b243e5d85..d766b4166 100644
--- a/library/modules/Items.cpp
+++ b/library/modules/Items.cpp
@@ -1022,3 +1022,300 @@ 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 (item_subtype >= 0 && item_subtype < world->raws.itemdefs.weapons.size())
+ value = world->raws.itemdefs.weapons[item_subtype]->value;
+ else
+ value = 10;
+ break;
+
+ case item_type::ARMOR:
+ if (item_subtype >= 0 && item_subtype < world->raws.itemdefs.armor.size())
+ value = world->raws.itemdefs.armor[item_subtype]->value;
+ else
+ value = 10;
+ break;
+
+ case item_type::SHOES:
+ if (item_subtype >= 0 && item_subtype < world->raws.itemdefs.shoes.size())
+ value = world->raws.itemdefs.shoes[item_subtype]->value;
+ else
+ value = 5;
+ break;
+
+ case item_type::SHIELD:
+ if (item_subtype >= 0 && item_subtype < world->raws.itemdefs.shields.size())
+ value = world->raws.itemdefs.shields[item_subtype]->value;
+ else
+ value = 10;
+ break;
+
+ case item_type::HELM:
+ if (item_subtype >= 0 && item_subtype < world->raws.itemdefs.helms.size())
+ value = world->raws.itemdefs.helms[item_subtype]->value;
+ else
+ value = 10;
+ break;
+
+ case item_type::GLOVES:
+ if (item_subtype >= 0 && item_subtype < world->raws.itemdefs.gloves.size())
+ value = world->raws.itemdefs.gloves[item_subtype]->value;
+ else
+ value = 5;
+ break;
+
+ case item_type::AMMO:
+ if (item_subtype >= 0 && 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 (mat_type >= 0 && mat_type < world->raws.creatures.all.size())
+ {
+ auto creature = world->raws.creatures.all[mat_type];
+ if (mat_subtype >= 0 && mat_type < 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 (mat_type >= 0 && mat_type < world->raws.creatures.all.size())
+ {
+ auto creature = world->raws.creatures.all[mat_type];
+ if (mat_subtype >= 0 && mat_type < creature->caste.size())
+ value = creature->caste[mat_subtype]->misc.petvalue;
+ }
+ value /= 2;
+ if (!value)
+ return 1;
+ return value;
+
+ case item_type::PET:
+ if (mat_type >= 0 && mat_type < world->raws.creatures.all.size())
+ {
+ auto creature = world->raws.creatures.all[mat_type];
+ if (mat_subtype >= 0 && mat_type < 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 (item_subtype >= 0 && 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 (item_subtype >= 0 && 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 (item_subtype >= 0 && 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 = world->raws.creatures.all[mat_type]->caste[mat_subtype]->misc.petvalue_divisor;
+ if (divisor > 1)
+ value /= divisor;
+ }
+ return value;
+}
\ No newline at end of file
From 98325757e2511dc3dfbb48aeb6ca61f63857cddb Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Wed, 30 Apr 2014 20:44:22 +0400
Subject: [PATCH 13/18] Fix signed-unsigned mismatch warnings in the new item
value code.
Unsigned comparison allows catching negatives in the same check too.
Also, it didn't check the values in getValue.
---
library/modules/Items.cpp | 41 +++++++++++++++++++++------------------
1 file changed, 22 insertions(+), 19 deletions(-)
diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp
index d766b4166..8a3d0e128 100644
--- a/library/modules/Items.cpp
+++ b/library/modules/Items.cpp
@@ -1097,49 +1097,49 @@ int Items::getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat
return 0;
case item_type::WEAPON:
- if (item_subtype >= 0 && item_subtype < world->raws.itemdefs.weapons.size())
+ 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 (item_subtype >= 0 && item_subtype < world->raws.itemdefs.armor.size())
+ 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 (item_subtype >= 0 && item_subtype < world->raws.itemdefs.shoes.size())
+ 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 (item_subtype >= 0 && item_subtype < world->raws.itemdefs.shields.size())
+ 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 (item_subtype >= 0 && item_subtype < world->raws.itemdefs.helms.size())
+ 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 (item_subtype >= 0 && item_subtype < world->raws.itemdefs.gloves.size())
+ 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 (item_subtype >= 0 && item_subtype < world->raws.itemdefs.ammo.size())
+ if (size_t(item_subtype) < world->raws.itemdefs.ammo.size())
value = world->raws.itemdefs.ammo[item_subtype]->value;
else
value = 1;
@@ -1156,10 +1156,10 @@ int Items::getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat
case item_type::FISH_RAW:
case item_type::EGG:
value = 2;
- if (mat_type >= 0 && mat_type < world->raws.creatures.all.size())
+ if (size_t(mat_type) < world->raws.creatures.all.size())
{
auto creature = world->raws.creatures.all[mat_type];
- if (mat_subtype >= 0 && mat_type < creature->caste.size())
+ if (size_t(mat_subtype) < creature->caste.size())
{
auto caste = creature->caste[mat_subtype];
mat_type = caste->misc.bone_mat;
@@ -1170,10 +1170,10 @@ int Items::getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat
case item_type::VERMIN:
value = 0;
- if (mat_type >= 0 && mat_type < world->raws.creatures.all.size())
+ if (size_t(mat_type) < world->raws.creatures.all.size())
{
auto creature = world->raws.creatures.all[mat_type];
- if (mat_subtype >= 0 && mat_type < creature->caste.size())
+ if (size_t(mat_subtype) < creature->caste.size())
value = creature->caste[mat_subtype]->misc.petvalue;
}
value /= 2;
@@ -1182,10 +1182,10 @@ int Items::getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat
return value;
case item_type::PET:
- if (mat_type >= 0 && mat_type < world->raws.creatures.all.size())
+ if (size_t(mat_type) < world->raws.creatures.all.size())
{
auto creature = world->raws.creatures.all[mat_type];
- if (mat_subtype >= 0 && mat_type < creature->caste.size())
+ if (size_t(mat_subtype) < creature->caste.size())
return creature->caste[mat_subtype]->misc.petvalue;
}
return 0;
@@ -1209,7 +1209,7 @@ int Items::getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat
break;
case item_type::PANTS:
- if (item_subtype >= 0 && item_subtype < world->raws.itemdefs.pants.size())
+ if (size_t(item_subtype) < world->raws.itemdefs.pants.size())
value = world->raws.itemdefs.pants[item_subtype]->value;
else
value = 10;
@@ -1227,7 +1227,7 @@ int Items::getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat
break;
case item_type::TRAPCOMP:
- if (item_subtype >= 0 && item_subtype < world->raws.itemdefs.trapcomps.size())
+ if (size_t(item_subtype) < world->raws.itemdefs.trapcomps.size())
value = world->raws.itemdefs.trapcomps[item_subtype]->value;
else
value = 10;
@@ -1241,7 +1241,7 @@ int Items::getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat
return 0;
case item_type::TOOL:
- if (item_subtype >= 0 && item_subtype < world->raws.itemdefs.tools.size())
+ if (size_t(item_subtype) < world->raws.itemdefs.tools.size())
value = world->raws.itemdefs.tools[item_subtype]->value;
else
value = 10;
@@ -1313,9 +1313,12 @@ int Items::getValue(df::item *item)
// Handle vermin swarms
if (item_type == item_type::VERMIN || item_type == item_type::PET)
{
- int divisor = world->raws.creatures.all[mat_type]->caste[mat_subtype]->misc.petvalue_divisor;
- if (divisor > 1)
- value /= divisor;
+ 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
From 415cdad48999fe0c1bfaa2f70a479e37a4574207 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Wed, 30 Apr 2014 21:28:02 +0400
Subject: [PATCH 14/18] Make using new for allocating DF objects with vtables a
compile-time error.
When done from plugins, it doesn't correctly initialize the vtable
because of some weird things MSVC does, so the only safe way is to
use df::allocate(). For consistency, it is also enforced
for code in the main library. It reveals the issue in the digging
invaders plugin, first found by warmist.
This change is linked to a modification in df-structures codegen.
---
library/include/df/custom/viewscreen.methods.inc | 1 +
library/modules/Items.cpp | 8 +++++++-
library/xml | 2 +-
plugins/diggingInvaders/assignJob.cpp | 8 ++++----
4 files changed, 13 insertions(+), 6 deletions(-)
create mode 100644 library/include/df/custom/viewscreen.methods.inc
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/modules/Items.cpp b/library/modules/Items.cpp
index 8a3d0e128..38d63d867 100644
--- a/library/modules/Items.cpp
+++ b/library/modules/Items.cpp
@@ -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)++;
diff --git a/library/xml b/library/xml
index 9c280e13a..1558b2373 160000
--- a/library/xml
+++ b/library/xml
@@ -1 +1 @@
-Subproject commit 9c280e13ab2e2421b8b8cab4a0c146fffc355a3c
+Subproject commit 1558b2373fcf8fa63928167e007a7f9a709888b6
diff --git a/plugins/diggingInvaders/assignJob.cpp b/plugins/diggingInvaders/assignJob.cpp
index 9472fb0e7..eff2de4ad 100644
--- a/plugins/diggingInvaders/assignJob.cpp
+++ b/plugins/diggingInvaders/assignJob.cpp
@@ -88,10 +88,10 @@ int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_mapjob_type = df::enums::job_type::DestroyBuilding;
//job->flags.bits.special = 1;
- df::general_ref_building_holderst* buildingRef = new df::general_ref_building_holderst;
+ df::general_ref_building_holderst* buildingRef = df::allocate();
buildingRef->building_id = building->id;
job->general_refs.push_back(buildingRef);
- df::general_ref_unit_workerst* workerRef = new df::general_ref_unit_workerst;
+ df::general_ref_unit_workerst* workerRef = df::allocate();
workerRef->unit_id = firstInvader->id;
job->general_refs.push_back(workerRef);
getRidOfOldJob(firstInvader);
@@ -118,7 +118,7 @@ int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_mapjob_type = df::enums::job_type::RemoveConstruction;
- df::general_ref_unit_workerst* workerRef = new df::general_ref_unit_workerst;
+ df::general_ref_unit_workerst* workerRef = df::allocate();
workerRef->unit_id = firstInvader->id;
job->general_refs.push_back(workerRef);
job->pos = pt2;
@@ -189,7 +189,7 @@ int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_mappos = workHere;
firstInvader->path.dest = goHere;
location = goHere;
- df::general_ref_unit_workerst* ref = new df::general_ref_unit_workerst;
+ df::general_ref_unit_workerst* ref = df::allocate();
ref->unit_id = firstInvader->id;
job->general_refs.push_back(ref);
firstInvader->job.hunt_target = NULL;
From 401c8f3026577701725c0aff0da022142a1aa59c Mon Sep 17 00:00:00 2001
From: Warmist
Date: Sat, 8 Mar 2014 10:09:53 +0200
Subject: [PATCH 15/18] gm-editor: Added enum printing and selection.
gm-editor: a bugfix for some entries not having fields
---
scripts/gui/gm-editor.lua | 49 +++++++++++++++++++++++++++++++++++++--
1 file changed, 47 insertions(+), 2 deletions(-)
diff --git a/scripts/gui/gm-editor.lua b/scripts/gui/gm-editor.lua
index 269d09c31..d6d4c0e17 100644
--- a/scripts/gui/gm-editor.lua
+++ b/scripts/gui/gm-editor.lua
@@ -11,6 +11,7 @@ local keybindings={
insert={key="CUSTOM_ALT_I",desc="Insert a new value to the vector"},
delete={key="CUSTOM_ALT_D",desc="Delete selected entry"},
help={key="HELP",desc="Show this help"},
+ NOT_USED={key="SEC_SELECT",desc="Choose an enum value from a list"}, --not a binding...
}
function getTargetFromScreens()
local my_trg
@@ -75,6 +76,7 @@ function GmEditorUi:init(args)
local helpPage=widgets.Panel{
subviews={widgets.Label{text=helptext,frame = {l=1,t=1,yalign=0}}}}
local mainList=widgets.List{view_id="list_main",choices={},frame = {l=1,t=3,yalign=0},on_submit=self:callback("editSelected"),
+ on_submit2=self:callback("editSelectedEnum"),
text_pen=dfhack.pen.parse{fg=COLOR_DARKGRAY,bg=0},cursor_pen=dfhack.pen.parse{fg=COLOR_YELLOW,bg=0}}
local mainPage=widgets.Panel{
subviews={
@@ -155,6 +157,29 @@ end
function GmEditorUi:currentTarget()
return self.stack[#self.stack]
end
+function GmEditorUi:editSelectedEnum(index,choice)
+ local trg=self:currentTarget()
+ local trg_key=trg.keys[index]
+ if trg.target._field==nil then qerror("not an enum") end
+ local enum=trg.target:_field(trg_key)._type
+
+ if enum._kind=="enum-type" then
+ local list={}
+ for i=enum._first_item, enum._last_item do
+ table.insert(list,{text=tostring(enum[i]),value=i})
+ end
+ guiScript.start(function()
+ local ret,idx,choice=guiScript.showListPrompt("Choose item:",nil,3,list)
+ if ret then
+ trg.target[trg_key]=choice.value
+ self:updateTarget(true)
+ end
+ end)
+
+ else
+ qerror("not an enum")
+ end
+end
function GmEditorUi:editSelected(index,choice)
local trg=self:currentTarget()
local trg_key=trg.keys[index]
@@ -206,7 +231,6 @@ function GmEditorUi:set(key,input)
self:updateTarget(true)
end
function GmEditorUi:onInput(keys)
-
if keys.LEAVESCREEN then
if self.subviews.pages:getSelected()==2 then
self.subviews.pages:setSelected(1)
@@ -233,6 +257,27 @@ function GmEditorUi:onInput(keys)
self.super.onInput(self,keys)
end
+function getStringValue(trg,field)
+ local obj=trg.target
+
+ local text=tostring(obj[field])
+ pcall(function()
+ if obj._field ~= nil then
+ local enum=obj:_field(field)._type
+ if enum._kind=="enum-type" then
+ text=text.."("..tostring(enum[obj[field]])..")"
+ end
+ end
+ end)
+ return text
+
+ --[[local ok,ret=pcall(function() return trg.target[field]._enum end)
+ if ok then
+ print(trg.target[field]._kind,ok,ret)
+ text=text.."("..tostring(ret[field])..")"
+ end
+ return text]]
+end
function GmEditorUi:updateTarget(preserve_pos,reindex)
local trg=self:currentTarget()
if reindex then
@@ -244,7 +289,7 @@ function GmEditorUi:updateTarget(preserve_pos,reindex)
self.subviews.lbl_current_item:itemById('name').text=tostring(trg.target)
local t={}
for k,v in pairs(trg.keys) do
- table.insert(t,{text={{text=string.format("%-25s",tostring(v))},{gap=1,text=tostring(trg.target[v]),}}})
+ table.insert(t,{text={{text=string.format("%-25s",tostring(v))},{gap=1,text=getStringValue(trg,v)}}})
end
local last_pos
if preserve_pos then
From 9733b30ed6260bb7c316fe8a6bd7c4948a9190b4 Mon Sep 17 00:00:00 2001
From: Warmist
Date: Sat, 26 Apr 2014 21:50:52 +0300
Subject: [PATCH 16/18] gui/gm-editor: Fixed enum editing. And added free
pointer/reinterpret options
---
scripts/gui/gm-editor.lua | 25 +++++++++++++++----------
1 file changed, 15 insertions(+), 10 deletions(-)
diff --git a/scripts/gui/gm-editor.lua b/scripts/gui/gm-editor.lua
index d6d4c0e17..4d0b09c6a 100644
--- a/scripts/gui/gm-editor.lua
+++ b/scripts/gui/gm-editor.lua
@@ -2,6 +2,7 @@
local gui = require 'gui'
local dialog = require 'gui.dialogs'
local widgets =require 'gui.widgets'
+local guiScript = require 'gui.script'
local args={...}
local keybindings={
@@ -10,6 +11,7 @@ local keybindings={
lua_set={key="CUSTOM_ALT_S",desc="Set by using a lua function"},
insert={key="CUSTOM_ALT_I",desc="Insert a new value to the vector"},
delete={key="CUSTOM_ALT_D",desc="Delete selected entry"},
+ reinterpret={key="CUSTOM_ALT_R",desc="Open selected entry as something else"},
help={key="HELP",desc="Show this help"},
NOT_USED={key="SEC_SELECT",desc="Choose an enum value from a list"}, --not a binding...
}
@@ -180,6 +182,14 @@ function GmEditorUi:editSelectedEnum(index,choice)
qerror("not an enum")
end
end
+function GmEditorUi:openReinterpret(key)
+ local trg=self:currentTarget()
+ dialog.showInputPrompt(tostring(trg_key),"Enter new type:",COLOR_WHITE,
+ "",function(choice)
+ local ntype=df[tp]
+ self:pushTarget(df.reinterpret_cast(ntype,trg.target[key]))
+ end)
+end
function GmEditorUi:editSelected(index,choice)
local trg=self:currentTarget()
local trg_key=trg.keys[index]
@@ -242,17 +252,17 @@ function GmEditorUi:onInput(keys)
local _,stoff=df.sizeof(trg.target)
local size,off=df.sizeof(trg.target:_field(self:getSelectedKey()))
dialog.showMessage("Offset",string.format("Size hex=%x,%x dec=%d,%d\nRelative hex=%x dec=%d",size,off,size,off,off-stoff,off-stoff),COLOR_WHITE)
- --elseif keys.CUSTOM_ALT_F then --filter?
+
elseif keys[keybindings.find.key] then
self:find()
elseif keys[keybindings.lua_set.key] then
self:set(self:getSelectedKey())
- --elseif keys.CUSTOM_I then
- -- self:insertSimple()
elseif keys[keybindings.insert.key] then --insert
self:insertNew()
elseif keys[keybindings.delete.key] then --delete
self:deleteSelected(self:getSelectedKey())
+ elseif keys[keybindings.reinterpret.key] then
+ self:openReinterpret(self:getSelectedKey())
end
self.super.onInput(self,keys)
@@ -270,13 +280,6 @@ function getStringValue(trg,field)
end
end)
return text
-
- --[[local ok,ret=pcall(function() return trg.target[field]._enum end)
- if ok then
- print(trg.target[field]._kind,ok,ret)
- text=text.."("..tostring(ret[field])..")"
- end
- return text]]
end
function GmEditorUi:updateTarget(preserve_pos,reindex)
local trg=self:currentTarget()
@@ -337,6 +340,8 @@ if #args~=0 then
show_editor(t)
end
dialog.showInputPrompt("Gm Editor", "Object to edit:", COLOR_GRAY, "",thunk)
+ elseif args[1]=="free" then
+ show_editor(df.reinterpret_cast(df[args[2]],args[3]))
else
local t=load("return "..args[1])()
show_editor(t)
From 94904eb66b9c2207ea26bd3a178e8611251db32d Mon Sep 17 00:00:00 2001
From: Warmist
Date: Sun, 4 May 2014 18:27:18 +0300
Subject: [PATCH 17/18] Updated NEWS.
---
NEWS | 2 ++
1 file changed, 2 insertions(+)
diff --git a/NEWS b/NEWS
index b43ced4f0..0bd107f07 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,8 @@ DFHack future
Internals:
- support for calling a lua function via a protobuf request (demonstrated by dfhack-run --lua).
+ - eventful now has a more friendly way of making custom sidebars
+ - new plugin: building-hacks. Allows to add custom functionality and/or animations to buildings.
New commands:
- move the 'grow', 'extirpate' and 'immolate' commands as 'plant' subcommands
From cca801463019cfa62ec2205158addc8ed3b4dbc6 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Sun, 4 May 2014 19:53:48 +0400
Subject: [PATCH 18/18] Mention more clearly how the data structures are
defined in the Lua API.
---
Lua API.html | 7 ++++---
Lua API.rst | 7 ++++---
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/Lua API.html b/Lua API.html
index 1d61b1797..1a2888eb0 100644
--- a/Lua API.html
+++ b/Lua API.html
@@ -455,9 +455,10 @@ It does not describe all of the utility functions
implemented by Lua files located in hack/lua/...
-
DF structures described by the xml files in library/xml are exported
-to lua code as a tree of objects and functions under the df global,
-which broadly maps to the df namespace in C++.
+
Data structures of the game are defined in XML files located in library/xml
+(and online at http://github.com/DFHack/df-structures), and automatically exported
+to lua code as a tree of objects and functions under the df global, which
+also broadly maps to the df namespace in the headers generated for C++.
WARNING: The wrapper provides almost raw access to the memory
of the game, so mistakes in manipulating objects are as likely to
crash the game as equivalent plain C++ code would be. E.g. NULL
diff --git a/Lua API.rst b/Lua API.rst
index 013e8f18d..3f2cf64ad 100644
--- a/Lua API.rst
+++ b/Lua API.rst
@@ -25,9 +25,10 @@ implemented by Lua files located in hack/lua/...
DF data structure wrapper
=========================
-DF structures described by the xml files in library/xml are exported
-to lua code as a tree of objects and functions under the ``df`` global,
-which broadly maps to the ``df`` namespace in C++.
+Data structures of the game are defined in XML files located in library/xml
+(and online at http://github.com/DFHack/df-structures), and automatically exported
+to lua code as a tree of objects and functions under the ``df`` global, which
+also broadly maps to the ``df`` namespace in the headers generated for C++.
**WARNING**: The wrapper provides almost raw access to the memory
of the game, so mistakes in manipulating objects are as likely to