Move the MaterialInfo class to the main library.

develop
Alexander Gavrilov 2012-01-03 19:25:55 +04:00
parent fb736a8556
commit f8814909a9
6 changed files with 352 additions and 201 deletions

@ -124,6 +124,12 @@ namespace DFHack
template<class T> template<class T>
T *ifnull(T *a, T *b) { return a ? a : b; } T *ifnull(T *a, T *b) { return a ? a : b; }
template<class T, T start, bool (*isvalid)(T)>
inline T next_enum_item_(T v) {
v = T(int(v) + 1);
return isvalid(v) ? v : start;
}
} }
namespace df namespace df
@ -171,6 +177,11 @@ namespace df
#define ENUM_FIRST_ITEM(enum) (df::enums::enum::_first_item_of_##enum) #define ENUM_FIRST_ITEM(enum) (df::enums::enum::_first_item_of_##enum)
#define ENUM_LAST_ITEM(enum) (df::enums::enum::_last_item_of_##enum) #define ENUM_LAST_ITEM(enum) (df::enums::enum::_last_item_of_##enum)
#define ENUM_NEXT_ITEM(enum,val) \
(DFHack::next_enum_item_<df::enum,ENUM_FIRST_ITEM(enum),df::enums::enum::is_valid>(val))
#define FOR_ENUM_ITEMS(enum,iter) \
for(df::enum iter = ENUM_FIRST_ITEM(enum); iter < ENUM_LAST_ITEM(enum); iter = df::enum(1+int(iter)))
namespace df { namespace df {
#define DF_KNOWN_GLOBALS \ #define DF_KNOWN_GLOBALS \
GLOBAL(cursor,cursor) \ GLOBAL(cursor,cursor) \

@ -34,11 +34,80 @@ distribution.
#include "Types.h" #include "Types.h"
#include "BitArray.h" #include "BitArray.h"
#include "DataDefs.h"
#include "df/material.h"
#include <vector> #include <vector>
#include <string> #include <string>
namespace df
{
struct item;
struct inorganic_raw;
struct plant_raw;
struct creature_raw;
struct historical_figure;
union job_material_category;
}
namespace DFHack namespace DFHack
{ {
struct DFHACK_EXPORT MaterialInfo {
static const int NUM_BUILTIN = 19;
static const int GROUP_SIZE = 200;
static const int CREATURE_BASE = NUM_BUILTIN;
static const int FIGURE_BASE = NUM_BUILTIN + GROUP_SIZE;
static const int PLANT_BASE = NUM_BUILTIN + GROUP_SIZE*2;
static const int END_BASE = NUM_BUILTIN + GROUP_SIZE*3;
int16_t type;
int32_t index;
df::material *material;
enum Mode {
Builtin,
Inorganic,
Creature,
Plant
};
Mode mode;
int16_t subtype;
df::inorganic_raw *inorganic;
df::creature_raw *creature;
df::plant_raw *plant;
df::historical_figure *figure;
public:
MaterialInfo(int16_t type = -1, int32_t index = -1) { decode(type, index); }
MaterialInfo(df::item *item) { decode(item); }
bool isValid() const { return material != NULL; }
bool decode(int16_t type, int32_t index = -1);
bool decode(df::item *item);
bool find(const std::string &token, const std::string &subtoken = std::string());
bool findBuiltin(const std::string &token);
bool findInorganic(const std::string &token);
bool findPlant(const std::string &token, const std::string &subtoken);
bool findCreature(const std::string &token, const std::string &subtoken);
std::string toString(uint16_t temp = 10015, bool named = true);
df::craft_material_class getCraftClass();
bool matches(const df::job_material_category &cat);
};
inline bool operator== (const MaterialInfo &a, const MaterialInfo &b) {
return a.type == b.type && a.index == b.index;
}
inline bool operator!= (const MaterialInfo &a, const MaterialInfo &b) {
return a.type != b.type || a.index != b.index;
}
typedef int32_t t_materialIndex; typedef int32_t t_materialIndex;
typedef int16_t t_materialType, t_itemType, t_itemSubtype; typedef int16_t t_materialType, t_itemType, t_itemSubtype;

@ -40,7 +40,239 @@ using namespace std;
#include "ModuleFactory.h" #include "ModuleFactory.h"
#include "Core.h" #include "Core.h"
#include "MiscUtils.h"
#include "df/world.h"
#include "df/item.h"
#include "df/inorganic_raw.h"
#include "df/plant_raw.h"
#include "df/creature_raw.h"
#include "df/historical_figure.h"
#include "df/job_material_category.h"
#include "df/matter_state.h"
using namespace DFHack; using namespace DFHack;
using namespace df::enums;
bool MaterialInfo::decode(df::item *item)
{
if (!item)
decode(-1);
else
decode(item->getActualMaterial(), item->getActualMaterialIndex());
}
bool MaterialInfo::decode(int16_t type, int32_t index)
{
this->type = type;
this->index = index;
material = NULL;
mode = Builtin; subtype = 0;
inorganic = NULL; plant = NULL; creature = NULL;
figure = NULL;
df::world_raws &raws = df::global::world->raws;
if (type < 0 || type >= sizeof(raws.mat_table.builtin)/sizeof(void*))
return false;
if (index < 0)
{
material = raws.mat_table.builtin[type];
}
else if (type == 0)
{
mode = Inorganic;
inorganic = df::inorganic_raw::find(index);
if (!inorganic)
return false;
material = &inorganic->material;
}
else if (type < CREATURE_BASE)
{
material = raws.mat_table.builtin[type];
}
else if (type < FIGURE_BASE)
{
mode = Creature;
subtype = type-CREATURE_BASE;
creature = df::creature_raw::find(index);
if (!creature || subtype >= creature->material.size())
return false;
material = creature->material[subtype];
}
else if (type < PLANT_BASE)
{
mode = Creature;
subtype = type-FIGURE_BASE;
figure = df::historical_figure::find(index);
if (!figure)
return false;
creature = df::creature_raw::find(figure->race);
if (!creature || subtype >= creature->material.size())
return false;
material = creature->material[subtype];
}
else if (type < END_BASE)
{
mode = Plant;
subtype = type-PLANT_BASE;
plant = df::plant_raw::find(index);
if (!plant || subtype >= plant->material.size())
return false;
material = plant->material[subtype];
}
else
{
material = raws.mat_table.builtin[type];
}
return (material != NULL);
}
bool MaterialInfo::find(const std::string &token, const std::string &subtoken)
{
if (findBuiltin(token))
return true;
if (subtoken.empty())
{
if (findInorganic(token))
return true;
}
else
{
if (findPlant(token, subtoken))
return true;
if (findCreature(token, subtoken))
return true;
}
return false;
}
bool MaterialInfo::findBuiltin(const std::string &token)
{
df::world_raws &raws = df::global::world->raws;
for (int i = 1; i < NUM_BUILTIN; i++)
if (raws.mat_table.builtin[i]->id == token)
return decode(i, -1);
return decode(-1);
}
bool MaterialInfo::findInorganic(const std::string &token)
{
df::world_raws &raws = df::global::world->raws;
for (unsigned i = 0; i < raws.inorganics.size(); i++)
{
df::inorganic_raw *p = raws.inorganics[i];
if (p->id == token)
return decode(0, i);
}
return decode(-1);
}
bool MaterialInfo::findPlant(const std::string &token, const std::string &subtoken)
{
df::world_raws &raws = df::global::world->raws;
for (unsigned i = 0; i < raws.plants.all.size(); i++)
{
df::plant_raw *p = raws.plants.all[i];
if (p->id != token)
continue;
for (unsigned j = 0; j < p->material.size(); j++)
if (p->material[j]->id == subtoken)
return decode(PLANT_BASE+j, i);
break;
}
return decode(-1);
}
bool MaterialInfo::findCreature(const std::string &token, const std::string &subtoken)
{
df::world_raws &raws = df::global::world->raws;
for (unsigned i = 0; i < raws.creatures.all.size(); i++)
{
df::creature_raw *p = raws.creatures.all[i];
if (p->creature_id != token)
continue;
for (unsigned j = 0; j < p->material.size(); j++)
if (p->material[j]->id == subtoken)
return decode(CREATURE_BASE+j, i);
break;
}
return decode(-1);
}
std::string MaterialInfo::toString(uint16_t temp, bool named)
{
if (type == -1)
return "NONE";
if (!material)
return stl_sprintf("INVALID %d:%d", type, index);
df::matter_state state = matter_state::Solid;
if (temp >= material->heat.melting_point)
state = matter_state::Liquid;
if (temp >= material->heat.boiling_point)
state = matter_state::Gas;
std::string name = material->state_name[state];
if (!material->prefix.empty())
name = material->prefix + " " + name;
if (named && figure)
name += stl_sprintf(" of HF %d", index);
return name;
}
df::craft_material_class MaterialInfo::getCraftClass()
{
if (!material)
return craft_material_class::None;
if (type == 0 && index == -1)
return craft_material_class::Stone;
FOR_ENUM_ITEMS(material_flags, i)
{
df::craft_material_class ccv = ENUM_ATTR(material_flags, type, i);
if (ccv == craft_material_class::None)
continue;
if (material->flags.is_set(i))
return ccv;
}
return craft_material_class::None;
}
bool MaterialInfo::matches(const df::job_material_category &cat)
{
if (!material)
return false;
using namespace df::enums::material_flags;
#define TEST(bit,flag) if (cat.bits.bit && material->flags.is_set(flag)) return true;
TEST(plant, STRUCTURAL_PLANT_MAT);
TEST(wood, WOOD);
TEST(cloth, THREAD_PLANT);
TEST(silk, SILK);
TEST(leather, LEATHER);
TEST(bone, BONE);
TEST(shell, SHELL);
TEST(wood2, WOOD);
TEST(soap, SOAP);
TEST(tooth, TOOTH);
TEST(horn, HORN);
TEST(pearl, PEARL);
TEST(yarn, YARN);
#undef TEST
return false;
}
Module* DFHack::createMaterials() Module* DFHack::createMaterials()
{ {

@ -1 +1 @@
Subproject commit c99be2349fef32db026af7541676e2e4f24e4636 Subproject commit f50bf32d3d4d29667720d648bf455896072c77f9

@ -51,10 +51,7 @@ DFhackCExport command_result twaterlvl(Core * c, vector <string> & parameters)
DFhackCExport command_result tidlers(Core * c, vector <string> & parameters) DFhackCExport command_result tidlers(Core * c, vector <string> & parameters)
{ {
// HOTKEY COMMAND: CORE ALREADY SUSPENDED // HOTKEY COMMAND: CORE ALREADY SUSPENDED
df::d_init_idlers iv = df::d_init_idlers(int(d_init->idlers) + 1); d_init->idlers = ENUM_NEXT_ITEM(d_init_idlers, d_init->idlers);
if (!d_init_idlers::is_valid(iv)) c->con << "Toggled the display of idlers to " << ENUM_KEY_STR(d_init_idlers, d_init->idlers) << endl;
iv = ENUM_FIRST_ITEM(d_init_idlers);
d_init->idlers = iv;
c->con << "Toggled the display of idlers to " << ENUM_KEY_STR(d_init_idlers, iv) << endl;
return CR_OK; return CR_OK;
} }

@ -4,6 +4,8 @@
#include <PluginManager.h> #include <PluginManager.h>
#include <MiscUtils.h> #include <MiscUtils.h>
#include <modules/Materials.h>
#include <DataDefs.h> #include <DataDefs.h>
#include <df/world.h> #include <df/world.h>
#include <df/ui.h> #include <df/ui.h>
@ -13,11 +15,6 @@
#include <df/build_req_choice_specst.h> #include <df/build_req_choice_specst.h>
#include <df/building_workshopst.h> #include <df/building_workshopst.h>
#include <df/building_furnacest.h> #include <df/building_furnacest.h>
#include <df/material.h>
#include <df/inorganic_raw.h>
#include <df/plant_raw.h>
#include <df/creature_raw.h>
#include <df/historical_figure.h>
#include <df/job.h> #include <df/job.h>
#include <df/job_item.h> #include <df/job_item.h>
#include <df/item.h> #include <df/item.h>
@ -28,156 +25,6 @@ using std::endl;
using namespace DFHack; using namespace DFHack;
using namespace df::enums; using namespace df::enums;
/*
* TODO: This should be in core:
*/
struct MaterialInfo {
int16_t type;
int32_t index;
df::material *material;
enum Mode {
Builtin,
Inorganic,
Creature,
Plant
};
Mode mode;
int16_t subtype;
df::inorganic_raw *inorganic;
df::creature_raw *creature;
df::plant_raw *plant;
df::historical_figure *figure;
MaterialInfo(int16_t type = -1, int32_t index = -1) {
decode(type, index);
}
bool isValid() const { return material != NULL; }
bool decode(int16_t type, int32_t index = -1);
bool findInorganic(const std::string &token);
std::string toString(uint16_t temp = 10015, bool named = true);
};
inline bool operator== (const MaterialInfo &a, const MaterialInfo &b) {
return a.type == b.type && a.index == b.index;
}
inline bool operator!= (const MaterialInfo &a, const MaterialInfo &b) {
return a.type != b.type || a.index != b.index;
}
bool MaterialInfo::decode(int16_t type, int32_t index)
{
this->type = type;
this->index = index;
material = NULL;
mode = Builtin; subtype = 0;
inorganic = NULL; plant = NULL; creature = NULL;
figure = NULL;
if (type < 0 || type >= 659)
return false;
df::world_raws &raws = df::global::world->raws;
if (index < 0)
{
material = raws.mat_table.builtin[type];
}
else if (type == 0)
{
mode = Inorganic;
inorganic = df::inorganic_raw::find(index);
if (!inorganic)
return false;
material = &inorganic->material;
}
else if (type < 19)
{
material = raws.mat_table.builtin[type];
}
else if (type < 219)
{
mode = Creature;
subtype = type-19;
creature = df::creature_raw::find(index);
if (!creature || subtype >= creature->material.size())
return false;
material = creature->material[subtype];
}
else if (type < 419)
{
mode = Creature;
subtype = type-219;
figure = df::historical_figure::find(index);
if (!figure)
return false;
creature = df::creature_raw::find(figure->race);
if (!creature || subtype >= creature->material.size())
return false;
material = creature->material[subtype];
}
else if (type < 619)
{
mode = Plant;
subtype = type-419;
plant = df::plant_raw::find(index);
if (!plant || subtype >= plant->material.size())
return false;
material = plant->material[subtype];
}
else
{
material = raws.mat_table.builtin[type];
}
return (material != NULL);
}
bool MaterialInfo::findInorganic(const std::string &token)
{
df::world_raws &raws = df::global::world->raws;
for (unsigned i = 0; i < raws.inorganics.size(); i++)
{
df::inorganic_raw *p = raws.inorganics[i];
if (p->id == token)
return decode(0, i);
}
return decode(-1);
}
std::string MaterialInfo::toString(uint16_t temp, bool named)
{
if (type == -1)
return "NONE";
if (!material)
return stl_sprintf("INVALID %d:%d", type, index);
int idx = 0;
if (temp >= material->heat.melting_point)
idx = 1;
if (temp >= material->heat.boiling_point)
idx = 2;
std::string name = material->state_name[idx];
if (!material->prefix.empty())
name = material->prefix + " " + name;
if (named && figure)
name += stl_sprintf(" of HF %d", index);
return name;
}
/*
* Plugin-specific code starts here.
*/
using df::global::world; using df::global::world;
using df::global::ui; using df::global::ui;
using df::global::ui_build_selector; using df::global::ui_build_selector;
@ -277,6 +124,7 @@ static command_result job_material_in_job(Core *c, MaterialInfo &new_mat)
} }
df::job *job = selected->jobs[idx]; df::job *job = selected->jobs[idx];
MaterialInfo cur_mat(job->matType, job->matIndex); MaterialInfo cur_mat(job->matType, job->matIndex);
if (!cur_mat.isValid() || cur_mat.type != 0) if (!cur_mat.isValid() || cur_mat.type != 0)
@ -286,26 +134,17 @@ static command_result job_material_in_job(Core *c, MaterialInfo &new_mat)
return CR_FAILURE; return CR_FAILURE;
} }
// Verify that the new material matches the old one df::craft_material_class old_class = cur_mat.getCraftClass();
df::material_flags rq_flag = material_flags::IS_STONE; if (old_class == craft_material_class::None)
if (cur_mat.mode != MaterialInfo::Builtin)
{
if (cur_mat.material->flags.is_set(material_flags::IS_GEM))
rq_flag = material_flags::IS_GEM;
else if (cur_mat.material->flags.is_set(material_flags::IS_METAL))
rq_flag = material_flags::IS_METAL;
else if (!cur_mat.material->flags.is_set(rq_flag))
{ {
c->con.printerr("Unexpected current material type: %s\n", c->con.printerr("Unexpected current material type: %s\n",
cur_mat.toString().c_str()); cur_mat.toString().c_str());
return CR_FAILURE; return CR_FAILURE;
} }
} if (new_mat.getCraftClass() != old_class)
if (!new_mat.material->flags.is_set(rq_flag))
{ {
c->con.printerr("New material %s does not satisfy requirement: %s\n", c->con.printerr("New material %s does not satisfy requirement: %s\n",
new_mat.toString().c_str(), ENUM_KEY_STR(material_flags, rq_flag)); new_mat.toString().c_str(), ENUM_KEY_STR(craft_material_class, old_class));
return CR_FAILURE; return CR_FAILURE;
} }
@ -334,26 +173,20 @@ static command_result job_material_in_job(Core *c, MaterialInfo &new_mat)
} }
c->con << "Applied material '" << new_mat.toString() c->con << "Applied material '" << new_mat.toString()
<< " jo job " << ENUM_KEY_STR(job_type,job->job_id) << endl; << "' to job " << ENUM_KEY_STR(job_type,job->job_id) << endl;
return CR_OK; return CR_OK;
} }
static command_result job_material_in_build(Core *c, MaterialInfo &new_mat) static bool build_choice_matches(df::ui_build_item_req *req, df::build_req_choicest *choice,
MaterialInfo &new_mat)
{ {
df::ui_build_item_req *req = ui_build_selector->requirements[ui_build_selector->req_index];
for (unsigned i = 0; i < ui_build_selector->choices.size(); i++)
{
df::build_req_choicest *choice = ui_build_selector->choices[i];
bool found = false;
if (VIRTUAL_CAST_VAR(gen, df::build_req_choice_genst, choice)) if (VIRTUAL_CAST_VAR(gen, df::build_req_choice_genst, choice))
{ {
if (gen->matType == new_mat.type && if (gen->matType == new_mat.type &&
gen->matIndex == new_mat.index && gen->matIndex == new_mat.index &&
gen->used_count < gen->candidates.size()) gen->used_count < gen->candidates.size())
{ {
found = true; return true;
} }
} }
else if (VIRTUAL_CAST_VAR(spec, df::build_req_choice_specst, choice)) else if (VIRTUAL_CAST_VAR(spec, df::build_req_choice_specst, choice))
@ -363,11 +196,20 @@ static command_result job_material_in_build(Core *c, MaterialInfo &new_mat)
spec->candidate->getActualMaterialIndex() == new_mat.index && spec->candidate->getActualMaterialIndex() == new_mat.index &&
!req->candidate_selected[spec->candidate_id]) !req->candidate_selected[spec->candidate_id])
{ {
found = true; return true;
} }
} }
if (found) return false;
}
static command_result job_material_in_build(Core *c, MaterialInfo &new_mat)
{
df::ui_build_item_req *req = ui_build_selector->requirements[ui_build_selector->req_index];
for (unsigned i = 0; i < ui_build_selector->choices.size(); i++)
{
if (build_choice_matches(req, ui_build_selector->choices[i], new_mat))
{ {
ui_build_selector->sel_index = i; ui_build_selector->sel_index = i;
return CR_OK; return CR_OK;