From 0f4684f29dc77c0d2d79ee1ec99cf2cb9300b896 Mon Sep 17 00:00:00 2001
From: Quietust
Date: Fri, 25 Apr 2014 11:04:21 -0500
Subject: [PATCH] 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