The Birth of the Item Factory - Items to Data File Overhaul - Help needed

An item, itype, item_map_group, tool_groups, component_group, and crafting recipe overhaul.

https://github.com/GlyphGryph/Cataclysm-DDA/tree/add_item_manager

What is done:
The skeleton of a factory class, to handle spawning items by id or by item group
The ability to read in basic item templates/itypes from json
the ability to read in group definitions from json

To Do List
Part 1 -
Item subclasses: Guns, Gunmods, Tools, Comestibles, Vehicle parts, ammos, armors, books, containers, bionics, macguffins, software
Special pseudo items, styles, and undroppables.
Artifact handling
Implement the crafting system to use the new tool-type and tool-quality system.
Once the last batch of dependencies have been removed and itypedef is deleted, restructure a lot of the logic that exists only to support the current ‘mixed state’ abomination.
Make factory read from all files in the correct directories, rather than requiring them to be manually named in the code.
Clean up all the json handling code. Gotta try to figure out catajson, that might help.
Replace all the debug messages with PROPER debug messages.

And then I should be (mostly) done with the basic Item Factory - but not with the item overhaul!
Part 2 -
Crafting recipes moved over to their own files into the new format.
Replace a ton of itype and other enums with maps or some other appropriate data structure that doesn’t need to be hardcoded.
Finish item group implementations, pull from item groups for map code and placement.
Rework items with fallthrough accessors.
Implement resultant variants via alternative selectors in item definitions.
Introduce item quality/durability.
Make some changes to crafting, have three ‘required’ sections - Tools, Components, and Consumed, rather than the current two.
Introduce a components system that tracks what pieces an item was made of when crafted
Tweak the ammo implementation and the restrictions thereof, probably as part of…
Removing/reworking various subclasses of items, and replacing it with a more sensible/dynamic system.

2 Likes

I noticed in the items the descriptions all start with a ‘’. Is it an actual part of the description or is it being used just to let you start another line because it seems like it could be either with how it is used.

That’s just so that descriptions can start on a new line. In order to get a literal “” in a string, you have to write “\”. Otherwise, it’s used as an escape character.

Okay, I can never remember if its the / or \ that does it though thats mostly because both are used in various things and in different ways. Maybe this time I will be able to make it stick in my mind.

* Get iuse on items working.

Here is a function to get a iuse method pointer from a string, ie. to do:

it_comest honey;
c.use = iuseFromString("honeyComb"); 

It still needs in Item_manager::load_item_templates_from a way to construct the correct itype (it_tool,it_comest,it_gun,etc).

diff --git a/item_manager.cpp b/item_manager.cpp
index fda5acf..53a8e1f 100644
--- a/item_manager.cpp
+++ b/item_manager.cpp
@@ -207,6 +207,10 @@ void Item_manager::load_item_templates_from(const std::string file_name){
             }
         }
     }
+
+    // compile test;
+    it_tool c;
+    c.use = iuseFromString("honeyComb");
 }
 
 //Grab string, with appropriate error handling
@@ -343,3 +347,141 @@ material Item_manager::material_from_tag(item_tag new_id, item_tag name){
         return MNULL;
     }
 }
+
+Item_manager::IUSE_FUNCTIONPOINTER Item_manager::iuseFromString(const std::string& iuseName)
+{
+  if (iuseName == "weed") return &iuse::weed;
+  else if (iuseName == "coke") return &iuse::coke; 
+  else if (iuseName == "sewage") return &iuse::sewage;
+  else if (iuseName == "honeycomb") return &iuse::honeycomb;
+  else if (iuseName == "royal_jelly") return &iuse::royal_jelly;
+  else if (iuseName == "bandage") return &iuse::bandage;
+  else if (iuseName == "firstaid") return &iuse::firstaid;
+  else if (iuseName == "caff") return &iuse::caff;
+  else if (iuseName == "alcohol") return &iuse::alcohol;
+  else if (iuseName == "alcohol_weak") return &iuse::alcohol_weak;
+  else if (iuseName == "pkill_1") return &iuse::pkill_1;
+  else if (iuseName == "pkill_2") return &iuse::pkill_2;
+  else if (iuseName == "pkill_3") return &iuse::pkill_3;
+  else if (iuseName == "pkill_4") return &iuse::pkill_4;
+  else if (iuseName == "pkill_l") return &iuse::pkill_l;
+  else if (iuseName == "xanax") return &iuse::xanax;
+  else if (iuseName == "cig") return &iuse::cig;
+  else if (iuseName == "antibiotic") return &iuse::antibiotic;
+  else if (iuseName == "weed") return &iuse::weed;
+  else if (iuseName == "coke") return &iuse::coke;
+  else if (iuseName == "crack") return &iuse::crack;
+  else if (iuseName == "grack") return &iuse::grack;
+  else if (iuseName == "meth") return &iuse::meth;
+  else if (iuseName == "poison") return &iuse::poison;
+  else if (iuseName == "hallu") return &iuse::hallu;
+  else if (iuseName == "thorazine") return &iuse::thorazine;
+  else if (iuseName == "prozac") return &iuse::prozac;
+  else if (iuseName == "sleep") return &iuse::sleep;
+  else if (iuseName == "iodine") return &iuse::iodine;
+  else if (iuseName == "flumed") return &iuse::flumed;
+  else if (iuseName == "flusleep") return &iuse::flusleep;
+  else if (iuseName == "inhaler") return &iuse::inhaler;
+  else if (iuseName == "blech") return &iuse::blech;
+  else if (iuseName == "mutagen") return &iuse::mutagen;
+  else if (iuseName == "mutagen_3") return &iuse::mutagen_3;
+  else if (iuseName == "purifier") return &iuse::purifier;
+  else if (iuseName == "marloss") return &iuse::marloss;
+  else if (iuseName == "dogfood") return &iuse::dogfood;
+  else if (iuseName == "lighter") return &iuse::lighter;
+  else if (iuseName == "sew") return &iuse::sew;
+  else if (iuseName == "scissors") return &iuse::scissors;
+  else if (iuseName == "extinguisher") return &iuse::extinguisher;
+  else if (iuseName == "hammer") return &iuse::hammer;
+  else if (iuseName == "light_off") return &iuse::light_off;
+  else if (iuseName == "light_on") return &iuse::light_on;
+  else if (iuseName == "cauterize_elec") return &iuse::cauterize_elec;
+  else if (iuseName == "water_purifier") return &iuse::water_purifier;
+  else if (iuseName == "two_way_radio") return &iuse::two_way_radio;
+  else if (iuseName == "radio_off") return &iuse::radio_off;
+  else if (iuseName == "radio_on") return &iuse::radio_on;
+  else if (iuseName == "roadmap") return &iuse::roadmap;
+  else if (iuseName == "picklock") return &iuse::picklock;
+  else if (iuseName == "crowbar") return &iuse::crowbar;
+  else if (iuseName == "makemound") return &iuse::makemound;
+  else if (iuseName == "dig") return &iuse::dig;
+  else if (iuseName == "chainsaw_off") return &iuse::chainsaw_off;
+  else if (iuseName == "chainsaw_on") return &iuse::chainsaw_on;
+  else if (iuseName == "jackhammer") return &iuse::jackhammer;
+  else if (iuseName == "jacqueshammer") return &iuse::jacqueshammer;
+  else if (iuseName == "pickaxe") return &iuse::pickaxe;
+  else if (iuseName == "set_trap") return &iuse::set_trap;
+  else if (iuseName == "geiger") return &iuse::geiger;
+  else if (iuseName == "teleport") return &iuse::teleport;
+  else if (iuseName == "can_goo") return &iuse::can_goo;
+  else if (iuseName == "pipebomb") return &iuse::pipebomb;
+  else if (iuseName == "pipebomb_act") return &iuse::pipebomb_act;
+  else if (iuseName == "grenade") return &iuse::grenade;
+  else if (iuseName == "grenade_act") return &iuse::grenade_act;
+  else if (iuseName == "flashbang") return &iuse::flashbang;
+  else if (iuseName == "flashbang_act") return &iuse::flashbang_act;
+  else if (iuseName == "c4") return &iuse::c4;
+  else if (iuseName == "c4armed") return &iuse::c4armed;
+  else if (iuseName == "EMPbomb") return &iuse::EMPbomb;
+  else if (iuseName == "EMPbomb_act") return &iuse::EMPbomb_act;
+  else if (iuseName == "scrambler") return &iuse::scrambler;
+  else if (iuseName == "scrambler_act") return &iuse::scrambler_act;
+  else if (iuseName == "gasbomb") return &iuse::gasbomb;
+  else if (iuseName == "gasbomb_act") return &iuse::gasbomb_act;
+  else if (iuseName == "smokebomb") return &iuse::smokebomb;
+  else if (iuseName == "smokebomb_act") return &iuse::smokebomb_act;
+  else if (iuseName == "acidbomb") return &iuse::acidbomb;
+  else if (iuseName == "acidbomb_act") return &iuse::acidbomb_act;
+  else if (iuseName == "molotov") return &iuse::molotov;
+  else if (iuseName == "molotov_lit") return &iuse::molotov_lit;
+  else if (iuseName == "dynamite") return &iuse::dynamite;
+  else if (iuseName == "dynamite_act") return &iuse::dynamite_act;
+  else if (iuseName == "firecracker_pack") return &iuse::firecracker_pack;
+  else if (iuseName == "firecracker_pack_act") return &iuse::firecracker_pack_act;
+  else if (iuseName == "firecracker") return &iuse::firecracker;
+  else if (iuseName == "firecracker_act") return &iuse::firecracker_act;
+  else if (iuseName == "mininuke") return &iuse::mininuke;
+  else if (iuseName == "mininuke_act") return &iuse::mininuke_act;
+  else if (iuseName == "pheromone") return &iuse::pheromone;
+  else if (iuseName == "portal") return &iuse::portal;
+  else if (iuseName == "manhack") return &iuse::manhack;
+  else if (iuseName == "turret") return &iuse::turret;
+  else if (iuseName == "UPS_off") return &iuse::UPS_off;
+  else if (iuseName == "UPS_on") return &iuse::UPS_on;
+  else if (iuseName == "tazer") return &iuse::tazer;
+  else if (iuseName == "mp3") return &iuse::mp3;
+  else if (iuseName == "mp3_on") return &iuse::mp3_on;
+  else if (iuseName == "vortex") return &iuse::vortex;
+  else if (iuseName == "dog_whistle") return &iuse::dog_whistle;
+  else if (iuseName == "vacutainer") return &iuse::vacutainer;
+  else if (iuseName == "knife") return &iuse::knife;
+  else if (iuseName == "lumber") return &iuse::lumber;
+  else if (iuseName == "hacksaw") return &iuse::hacksaw;
+  else if (iuseName == "tent") return &iuse::tent;
+  else if (iuseName == "shelter") return &iuse::shelter;
+  else if (iuseName == "torch") return &iuse::torch;
+  else if (iuseName == "torch_lit") return &iuse::torch_lit;
+  else if (iuseName == "candle") return &iuse::candle;
+  else if (iuseName == "candle_lit") return &iuse::candle_lit;
+  else if (iuseName == "bullet_puller") return &iuse::bullet_puller;
+  //else if (iuseName == "screwdriver") return &iuse::screwdriver;  // TODO: unimplemented
+  //else if (iuseName == "wrench") return &iuse::wrench;  // TODO: unimplemented
+  else if (iuseName == "boltcutters") return &iuse::boltcutters;
+  else if (iuseName == "mop") return &iuse::mop;
+  else if (iuseName == "spray_can") return &iuse::spray_can;
+  else if (iuseName == "rag") return &iuse::rag;
+  else if (iuseName == "pda") return &iuse::pda;
+  else if (iuseName == "pda_flashlight") return &iuse::pda_flashlight;
+  else if (iuseName == "LAW") return &iuse::LAW;
+  else if (iuseName == "heatpack") return &iuse::heatpack;
+  else if (iuseName == "mcg_note") return &iuse::mcg_note;
+  else if (iuseName == "artifact") return &iuse::artifact;
+  //else if (iuseName == "heal") return &iuse::heal;  // TODO: unimplemented
+  //else if (iuseName == "twist_space") return &iuse::twist_space;  // TODO: unimplemented
+  //else if (iuseName == "mass_vampire") return &iuse::mass_vampire;  // TODO: unimplemented
+  //else if (iuseName == "growth") return &iuse::growth;  // TODO: unimplemented
+  //else if (iuseName == "water") return &iuse::water;  // TODO: unimplemented
+  //else if (iuseName == "lava") return &iuse::lava;  // TODO: unimplemented
+   
+  return &iuse::none; 
+}
diff --git a/item_manager.h b/item_manager.h
index 9d183e2..4d44f65 100644
--- a/item_manager.h
+++ b/item_manager.h
@@ -46,6 +46,9 @@ private:
     itype*  m_missing_item;
     std::map<item_tag, tag_list> m_template_groups;
 
+    typedef void (iuse::*IUSE_FUNCTIONPOINTER)(game *, player *, item *, bool);    
+    IUSE_FUNCTIONPOINTER iuseFromString(const std::string& iuseName);
+
     //json data handlers
     void load_item_templates();
     void load_item_templates_from(const std::string file_name);

I don’t suppose you can send me a pull request for that so I can more easily review it? If not, I’ll still get around to it in the next couple days if its a reasonable implementation, but it would be appreciated. :slight_smile:

Now lets give it a quick lookover…

Hmm… a big if/else if loop, eh? I’m actually doing the same thing for materials right now, and at the very least it’s acceptable as a temporary but useful thing to get stuff working, but I think we’re going to want to end up with something a bit more robust sooner rather than later. Still, I’ll be happy to stick that in when I get a chance.

Just going to post that since I don’t know how to format the json files for items I have been making a sql database of all items so later I can use that to output whatever way you want them formatted.
Also your talking about a big if/else stack, I think a switch would be better for that if you can’t find a better way of doing it. If you want you can point me to the wherever the if/else stuff is and I can work on turning it into a switch. If anything it will be more readable and I think the compilers are better able to optimize a switch as well.

My suggestion is to insert all the function pointers into a map with the “TAG” as the key, so
std::map<std::string, void (iuse::*puse)(game *, player *, item , bool) iuse_methods;
followed by an init function that does the usual iuse_methods[“TAG”] = iuse_method; for each method
.
Remember to verify that a given string matches an entry with iuse_methods.find() or iuse_methods.count() when the string is supplied by a config file. Ideally this will only be necessary when hooking up items to their functions in the factory.

*If/when we switch to C++11, I believe this can be replaced with initializer lists.

I’ve replaced the if/else block with a std::map<string, iuse::(…)>, [edit: what Kevin said]
It is better cause you can add tags/iuse::
from different mods without having it all hardcoded in one place, you could have the default tag/pointers and then add some from lua or something.

Also, made a std::map to load items based on category (it_comest, it_book, etc).

I don't suppose you can send me a pull request
hmmm, I dont know how to do that.

patch -p1 < “git diff” should apply the changes.

diff --git a/item_manager.cpp b/item_manager.cpp
index fda5acf..edfa9cf 100644
--- a/item_manager.cpp
+++ b/item_manager.cpp
@@ -16,6 +16,14 @@ Item_manager::Item_manager(){
     m_missing_item->description = "Error: No item template of this type.";
     m_templates["MISSING_ITEM"]=m_missing_item;
     load_item_templates();
+
+    categoryLoaders.insert(CATLOAD_MAP::value_type("comestible", &load_comest));
+    categoryLoaders.insert(CATLOAD_MAP::value_type("ammo", &load_ammo));
+    categoryLoaders.insert(CATLOAD_MAP::value_type("armor", &load_armor));
+    categoryLoaders.insert(CATLOAD_MAP::value_type("gun", &load_gun));
+    categoryLoaders.insert(CATLOAD_MAP::value_type("book", &load_book));
+    categoryLoaders.insert(CATLOAD_MAP::value_type("tool", &load_tool));
+    categoryLoaders.insert(CATLOAD_MAP::value_type("container", &load_container));
 }
 
 void Item_manager::init(){
@@ -186,23 +194,17 @@ void Item_manager::load_item_templates_from(const std::string file_name){
                 if(m_templates.find(new_id) != m_templates.end()){
                     std::cerr << "Item definition skipped, id " << new_id << " already exists." << std::endl;
                 } else {
-                    item_template* new_item_template =  new itype();
-                    new_item_template->id = new_id;
-                    m_templates[new_id] = new_item_template;
-
-                    // And then proceed to assign the correct field
-                    new_item_template->rarity = int_from_json(new_id, "rarity", entry_body); 
-                    new_item_template->name = string_from_json(new_id, "name", entry_body); 
-                    new_item_template->sym = char_from_json(new_id, "symbol", entry_body); 
-                    new_item_template->color = color_from_json(new_id, "color", entry_body); 
-                    new_item_template->description = string_from_json(new_id, "description", entry_body); 
-                    new_item_template->m1 = materials_from_json(new_id, "material", entry_body)[0];
-                    new_item_template->m2 = materials_from_json(new_id, "material", entry_body)[1];
-                    new_item_template->volume = int_from_json(new_id, "volume", entry_body); 
-                    new_item_template->weight = int_from_json(new_id, "weight", entry_body); 
-                    new_item_template->melee_dam = int_from_json(new_id, "damage", entry_body); 
-                    new_item_template->melee_cut = int_from_json(new_id, "cutting", entry_body); 
-                    new_item_template->m_to_hit = int_from_json(new_id, "to_hit", entry_body); 
+		  item_template* new_item_template = 0;
+		  std::string category = string_from_json(new_id, "category", entry_body);
+		  CATLOAD_MAP::iterator it = categoryLoaders.find(category);
+		  if (it != categoryLoaders.end())
+		    new_item_template = (*it).second(new_id,entry_body);
+		  else
+		    new_item_template = load_default(new_id, entry_body);
+		  
+		  //new_item_template->id = new_id;
+		  if (new_item_template)      // if json entry has errors, skip ?
+		    m_templates[new_id] = new_item_template;                    
                 }
             }
         }
@@ -343,3 +345,217 @@ material Item_manager::material_from_tag(item_tag new_id, item_tag name){
         return MNULL;
     }
 }
+
+Item_manager::IUSE_FUNCTIONPOINTER Item_manager::iuseFromString(const std::string& iuseName)
+{
+  IUSE_MAP::iterator it = iuseMapping.find(iuseName);
+  if (it != iuseMapping.end())
+    return (*it).second;
+  
+  return &iuse::none;
+}
+
+void Item_manager::addIUseMapping(const std::string& iuseName, IUSE_FUNCTIONPOINTER func)
+{
+  iuseMapping.insert(IUSE_MAP::value_type(iuseName,func));  
+}
+
+void Item_manager::setDefaultIUseMappings()
+{
+  iuseMapping.clear();  
+  addIUseMapping("SEWAGE", &iuse::sewage);
+  addIUseMapping("HONEYCOMB", &iuse::honeycomb);
+  addIUseMapping("ROYAL_JELLY", &iuse::royal_jelly);
+  addIUseMapping("BANDAGE", &iuse::bandage);
+  addIUseMapping("FIRSTAID", &iuse::firstaid);
+  addIUseMapping("CAFF", &iuse::caff);
+  addIUseMapping("ALCOHOL", &iuse::alcohol);
+  addIUseMapping("ALCOHOL_WEAK", &iuse::alcohol_weak);
+  addIUseMapping("PKILL_1", &iuse::pkill_1);
+  addIUseMapping("PKILL_2", &iuse::pkill_2);
+  addIUseMapping("PKILL_3", &iuse::pkill_3);
+  addIUseMapping("PKILL_4", &iuse::pkill_4);
+  addIUseMapping("PKILL_L", &iuse::pkill_l);
+  addIUseMapping("XANAX", &iuse::xanax);
+  addIUseMapping("CIG", &iuse::cig);
+  addIUseMapping("ANTIBIOTIC", &iuse::antibiotic);
+  addIUseMapping("WEED", &iuse::weed);
+  addIUseMapping("COKE", &iuse::coke);
+  addIUseMapping("CRACK", &iuse::crack);
+  addIUseMapping("GRACK", &iuse::grack);
+  addIUseMapping("METH", &iuse::meth);
+  addIUseMapping("POISON", &iuse::poison);
+  addIUseMapping("HALLU", &iuse::hallu);
+  addIUseMapping("THORAZINE", &iuse::thorazine);
+  addIUseMapping("PROZAC", &iuse::prozac);
+  addIUseMapping("SLEEP", &iuse::sleep);
+  addIUseMapping("IODINE", &iuse::iodine);
+  addIUseMapping("FLUMED", &iuse::flumed);
+  addIUseMapping("FLUSLEEP", &iuse::flusleep);
+  addIUseMapping("INHALER", &iuse::inhaler);
+  addIUseMapping("BLECH", &iuse::blech);
+  addIUseMapping("MUTAGEN", &iuse::mutagen);
+  addIUseMapping("MUTAGEN_3", &iuse::mutagen_3);
+  addIUseMapping("PURIFIER", &iuse::purifier);
+  addIUseMapping("MARLOSS", &iuse::marloss);
+  addIUseMapping("DOGFOOD", &iuse::dogfood);
+  addIUseMapping("LIGHTER", &iuse::lighter);
+  addIUseMapping("SEW", &iuse::sew);
+  addIUseMapping("SCISSORS", &iuse::scissors);
+  addIUseMapping("EXTINGUISHER", &iuse::extinguisher);
+  addIUseMapping("HAMMER", &iuse::hammer);
+  addIUseMapping("LIGHT_OFF", &iuse::light_off);
+  addIUseMapping("LIGHT_ON", &iuse::light_on);
+  addIUseMapping("CAUTERIZE_ELEC", &iuse::cauterize_elec);
+  addIUseMapping("WATER_PURIFIER", &iuse::water_purifier);
+  addIUseMapping("TWO_WAY_RADIO", &iuse::two_way_radio);
+  addIUseMapping("RADIO_OFF", &iuse::radio_off);
+  addIUseMapping("RADIO_ON", &iuse::radio_on);
+  addIUseMapping("ROADMAP", &iuse::roadmap);
+  addIUseMapping("PICKLOCK", &iuse::picklock);
+  addIUseMapping("CROWBAR", &iuse::crowbar);
+  addIUseMapping("MAKEMOUND", &iuse::makemound);
+  addIUseMapping("DIG", &iuse::dig);
+  addIUseMapping("CHAINSAW_OFF", &iuse::chainsaw_off);
+  addIUseMapping("CHAINSAW_ON", &iuse::chainsaw_on);
+  addIUseMapping("JACKHAMMER", &iuse::jackhammer);
+  addIUseMapping("JACQUESHAMMER", &iuse::jacqueshammer);
+  addIUseMapping("PICKAXE", &iuse::pickaxe);
+  addIUseMapping("SET_TRAP", &iuse::set_trap);
+  addIUseMapping("GEIGER", &iuse::geiger);
+  addIUseMapping("TELEPORT", &iuse::teleport);
+  addIUseMapping("CAN_GOO", &iuse::can_goo);
+  addIUseMapping("PIPEBOMB", &iuse::pipebomb);
+  addIUseMapping("PIPEBOMB_ACT", &iuse::pipebomb_act);
+  addIUseMapping("GRENADE", &iuse::grenade);
+  addIUseMapping("GRENADE_ACT", &iuse::grenade_act);
+  addIUseMapping("FLASHBANG", &iuse::flashbang);
+  addIUseMapping("FLASHBANG_ACT", &iuse::flashbang_act);
+  addIUseMapping("C4", &iuse::c4);
+  addIUseMapping("C4ARMED", &iuse::c4armed);
+  addIUseMapping("EMPBOMB", &iuse::EMPbomb);
+  addIUseMapping("EMPBOMB_ACT", &iuse::EMPbomb_act);
+  addIUseMapping("SCRAMBLER", &iuse::scrambler);
+  addIUseMapping("SCRAMBLER_ACT", &iuse::scrambler_act);
+  addIUseMapping("GASBOMB", &iuse::gasbomb);
+  addIUseMapping("GASBOMB_ACT", &iuse::gasbomb_act);
+  addIUseMapping("SMOKEBOMB", &iuse::smokebomb);
+  addIUseMapping("SMOKEBOMB_ACT", &iuse::smokebomb_act);
+  addIUseMapping("ACIDBOMB", &iuse::acidbomb);
+  addIUseMapping("ACIDBOMB_ACT", &iuse::acidbomb_act);
+  addIUseMapping("MOLOTOV", &iuse::molotov);
+  addIUseMapping("MOLOTOV_LIT", &iuse::molotov_lit);
+  addIUseMapping("DYNAMITE", &iuse::dynamite);
+  addIUseMapping("DYNAMITE_ACT", &iuse::dynamite_act);
+  addIUseMapping("FIRECRACKER_PACK", &iuse::firecracker_pack);
+  addIUseMapping("FIRECRACKER_PACK_ACT", &iuse::firecracker_pack_act);
+  addIUseMapping("FIRECRACKER", &iuse::firecracker);
+  addIUseMapping("FIRECRACKER_ACT", &iuse::firecracker_act);
+  addIUseMapping("MININUKE", &iuse::mininuke);
+  addIUseMapping("MININUKE_ACT", &iuse::mininuke_act);
+  addIUseMapping("PHEROMONE", &iuse::pheromone);
+  addIUseMapping("PORTAL", &iuse::portal);
+  addIUseMapping("MANHACK", &iuse::manhack);
+  addIUseMapping("TURRET", &iuse::turret);
+  addIUseMapping("UPS_OFF", &iuse::UPS_off);
+  addIUseMapping("UPS_ON", &iuse::UPS_on);
+  addIUseMapping("TAZER", &iuse::tazer);
+  addIUseMapping("MP3", &iuse::mp3);
+  addIUseMapping("MP3_ON", &iuse::mp3_on);
+  addIUseMapping("VORTEX", &iuse::vortex);
+  addIUseMapping("DOG_WHISTLE", &iuse::dog_whistle);
+  addIUseMapping("VACUTAINER", &iuse::vacutainer);
+  addIUseMapping("KNIFE", &iuse::knife);
+  addIUseMapping("LUMBER", &iuse::lumber);
+  addIUseMapping("HACKSAW", &iuse::hacksaw);
+  addIUseMapping("TENT", &iuse::tent);
+  addIUseMapping("SHELTER", &iuse::shelter);
+  addIUseMapping("TORCH", &iuse::torch);
+  addIUseMapping("TORCH_LIT", &iuse::torch_lit);
+  addIUseMapping("CANDLE", &iuse::candle);
+  addIUseMapping("CANDLE_LIT", &iuse::candle_lit);
+  addIUseMapping("BULLET_PULLER", &iuse::bullet_puller);
+//  addIUseMapping("SCREWDRIVER", &iuse::screwdriver);
+//  addIUseMapping("WRENCH", &iuse::wrench);
+  addIUseMapping("BOLTCUTTERS", &iuse::boltcutters);
+  addIUseMapping("MOP", &iuse::mop);
+  addIUseMapping("SPRAY_CAN", &iuse::spray_can);
+  addIUseMapping("RAG", &iuse::rag);
+  addIUseMapping("PDA", &iuse::pda);
+  addIUseMapping("PDA_FLASHLIGHT", &iuse::pda_flashlight);
+  addIUseMapping("LAW", &iuse::LAW);
+  addIUseMapping("HEATPACK", &iuse::heatpack);
+  addIUseMapping("MCG_NOTE", &iuse::mcg_note);
+  addIUseMapping("ARTIFACT", &iuse::artifact);
+  //addIUseMapping("HEAL", &iuse::heal);
+  //addIUseMapping("TWIST_SPACE", &iuse::twist_space);
+  //addIUseMapping("MASS_VAMPIRE", &iuse::mass_vampire);
+  //addIUseMapping("GROWTH", &iuse::growth);
+  //addIUseMapping("WATER", &iuse::water);
+  //addIUseMapping("LAVA", &iuse::lava);
+}
+
+// Loader for item category 
+item_template* load_comest(item_tag new_id, const picojson::value::object& value_map)
+{
+  
+  return 0; 
+}
+
+// Loader for item category 
+item_template* load_ammo(item_tag new_id, const picojson::value::object& value_map)
+{
+  return 0;
+}
+
+// Loader for item category 
+item_template* load_armor(item_tag new_id, const picojson::value::object& value_map)
+{
+  return 0;  
+}
+
+// Loader for item category 
+item_template* load_gun(item_tag new_id, const picojson::value::object& value_map)
+{
+  return 0;
+}
+
+// Loader for item category 
+item_template* load_book(item_tag new_id, const picojson::value::object& value_map)
+{
+  return 0;
+}
+
+// Loader for item category 
+item_template* load_tool(item_tag new_id, const picojson::value::object& value_map)
+{
+  return 0;
+}
+
+// Loader for item category 
+item_template* load_container(item_tag new_id, const picojson::value::object& value_map)
+{
+  return 0;
+}
+
+// Loader for item category 
+item_template* load_default(item_tag new_id, const picojson::value::object& entry_body)
+{
+// And then proceed to assign the correct field
+  item_template* new_item_template = new itype();
+/*
+  new_item_template->rarity = int_from_json(new_id, "rarity", entry_body); 
+  new_item_template->name = string_from_json(new_id, "name", entry_body); 
+  new_item_template->sym = char_from_json(new_id, "symbol", entry_body); 
+  new_item_template->color = color_from_json(new_id, "color", entry_body); 
+  new_item_template->description = string_from_json(new_id, "description", entry_body); 
+  new_item_template->m1 = materials_from_json(new_id, "material", entry_body)[0];
+  new_item_template->m2 = materials_from_json(new_id, "material", entry_body)[1];
+  new_item_template->volume = int_from_json(new_id, "volume", entry_body); 
+  new_item_template->weight = int_from_json(new_id, "weight", entry_body); 
+  new_item_template->melee_dam = int_from_json(new_id, "damage", entry_body); 
+  new_item_template->melee_cut = int_from_json(new_id, "cutting", entry_body); 
+  new_item_template->m_to_hit = int_from_json(new_id, "to_hit", entry_body);*/
+  return new_item_template;  
+}
+
diff --git a/item_manager.h b/item_manager.h
index 9d183e2..6f80f59 100644
--- a/item_manager.h
+++ b/item_manager.h
@@ -16,6 +16,14 @@ typedef std::map<item_tag, itype*> item_template_container;
 typedef std::set<item_tag> tag_list;
 typedef std::vector<item*> item_list;
 
+item_template* load_comest(item_tag new_id, const picojson::value::object& value_map);
+item_template* load_ammo(item_tag new_id, const picojson::value::object& value_map);
+item_template* load_armor(item_tag new_id, const picojson::value::object& value_map);
+item_template* load_gun(item_tag new_id, const picojson::value::object& value_map);
+item_template* load_book(item_tag new_id, const picojson::value::object& value_map);
+item_template* load_tool(item_tag new_id, const picojson::value::object& value_map);
+item_template* load_container(item_tag new_id, const picojson::value::object& value_map);
+item_template* load_default(item_tag new_id, const picojson::value::object& value_map);
 
 class Item_manager
 {
@@ -41,6 +49,12 @@ public:
     item* create_random();
     item_list create_random(int quantity);
 
+
+    typedef void (iuse::*IUSE_FUNCTIONPOINTER)(game *, player *, item *, bool);    
+    void addIUseMapping(const std::string& iuseName, IUSE_FUNCTIONPOINTER func);
+    IUSE_FUNCTIONPOINTER iuseFromString(const std::string& iuseName);
+    void setDefaultIUseMappings();
+    
 private:
     item_template_container  m_templates;
     itype*  m_missing_item;
@@ -56,6 +70,13 @@ private:
     material* materials_from_json(item_tag new_id, item_tag index, picojson::value::object value_map);
     material material_from_tag(item_tag new_id, item_tag index);
 
+    typedef std::map<std::string, IUSE_FUNCTIONPOINTER> IUSE_MAP;
+    IUSE_MAP iuseMapping;   
+    
+    typedef item_template* (*CATLOAD_FUNCTIONPOINTER)(item_tag new_id, const picojson::value::object& value_map);
+    typedef std::map<std::string, CATLOAD_FUNCTIONPOINTER> CATLOAD_MAP;
+    CATLOAD_MAP categoryLoaders;
+
 };
 
 extern Item_manager* item_controller;

[quote=“akhier the dragon hearted, post:7, topic:741”] Just going to post that since I don’t know how to format the json files for items I have been making a sql database of all items so later I can use that to output whatever way you want them formatted.
Also your talking about a big if/else stack, I think a switch would be better for that if you can’t find a better way of doing it. If you want you can point me to the wherever the if/else stuff is and I can work on turning it into a switch. If anything it will be more readable and I think the compilers are better able to optimize a switch as well.[/quote]

You can’t do switches on arbitrary data types in C++.

Also, format-wise, I included examples of both items and mapspawns in my repo I linked to. Check under data/raws/items/

Hmm, I don’ see what you mean with the not being able to do switches and I hope you don’t mind explaining what is wrong with what I was thinking. Anyway taking from the first bit monkey posted which had

if (iuseName == “weed”) return &iuse::weed;
else if (iuseName == “coke”) return &iuse::coke;

I was thinking that you could just

switch (iuseName)
{
case “weed”:
return &iuse::weed;
case “coke”:
return &iuse::coke;
}

If this is wrong whats wrong about it? Also I saw the formatting but its not one to one. The weapon example you give is so

[
{ “id”:“HATCHET”,
“symbol”: “;”,
“color”: “blue”,
“name”:“hatchet”,
“description”:“A one-handed hatchet. Makes a great melee weapon, and is useful both for cutting wood, and for use as a hammer.”,
“rarity”: 60,
“material”: [“WOOD”, “IRON”],
“weight”: 7,
“volume”: 6,
“damage”: 12,
“cutting”: 12,
“to_hit”: 1
}
]

and in the itypedef.cpp file the hatchet goes like so (I know what the numbers are so thats not the problem)

MELEE(“hatchet”, “hatchet”, 10, 95,’;’, c_ltgray, IRON, WOOD,
6, 7, 12, 12, 1, 0, “
A one-handed hatchet. Makes a great melee weapon, and is useful both for\n
cutting wood, and for use as a hammer.”);

1.First of all the id is in all caps, do you want this pattern continued from now on as the instruments had the same thing.

2.the hatchet has a manually input new line in the description and the json one doesn’t have it, is this because the game will do it as needed now or should I keep any instances of \n?

  1. the color is just a color and it doesn’t match up, for the hatchet if I had done the conversion the color would end up as c_ltgray or maybe just lightgray or some variation of it. Do you have some predefined colors I can go off of for the conversion or what?

Also something I noticed is that some items have a line under them going something like so (example from steel chain)
TECH(‘chain’, mfb(TEC_GRAB) );
what is this, is it defining something that is separate but kept with the chain because it goes with it or what?

Thanks for the questions, good things to bring up.

On switches:
You can’t do that with switches in C++. C++ has very limited switch capability, and can’t be used on strings. It only supports primitive, single element data types (even string literals are multi-element, meaning no support).

On other stuff:
Yes, all TAG elements should be in caps. TAG elements are anything that identifies something in-game in a unique way. A name is not a tag, but an ID is. A tooltype would also be a tag. Anything that will get replaced, in code, with a reference or access method as a way to point to an element, will be in caps. Pieces of information that stay as text will be cased normally. This will help avoid collisions with a gradual changeover, since none of the current element ids use caps.

Technically, the color should probably be a tag too except I really, really don’t want it to be, and need to figure out proper hex code color support methods. Thanks for the reminder, btw, I’m gonna add that to the first post. I don’t actually know for sure what to do here yet, though. For now, simply treat it as another tag - feel free to change it to LTGRAY or whatever you need to.

Newlines in descriptions were obseleted a while ago, and are stripped. Many descriptions are old, and will still have them, but they serve no purpose and have no meaning.

Also, yeah, Techs… I honestly don’t know what to do with those at the moment, hence the line in the first post that says “Get technique flags working for items with techniques.” >_< For now, I would just stick them in with a line:

“technique”: “TEC_GRAB"
or, if they have more than one
"technique”: [“TEC_GRAB”, “TEC_WHATEVER”]

Final note: For things that have only one material, you can simply write
"material": "WOOD"
without an array. And if they have no materials, you can just not add the property in.

I’m currently working on a minor update to recipes which requires me to go through every recipe anyway, so there’s a very good chance that I’ll push recipes to JSON soon. I’ll be working off the main repo, which hopefully works for you (you’ll just have to do a pull, is all).

Recipes moved to JSON, pull request 451.

I’m annoyed with picojson right now. Surely there must be an easier way to interface with JSON files? Maybe something that’s more optimized for usability, rather than optimized to fit in a header. 300 lines to do something that could be done in 50ish in JavaScript >_<.

I didn’t actually “review” all the recipes, I just wrote a Perl script to convert them to JSON (and made sure that the difficulty 0 ones were sane, of course). Would it help if I shared that script? It would take a little editing to be suitable for items themselves, but might still be handy as a starting point.

Hey, did you also get an architecture set up? I’m gonna have to look this over when I get time…

Yeah, I was opposed to json for the same reason. It’s not meant to be human writeable. YAML is, and would have been perfect here, but working with shoving in C++ libraries is basically the opposite of good times as we all learned when attempting to do it. The choice generally seems to be “boost or nothing”.

Oddly enough, JSON files are /supposed/ to be written in Javascript. Hence the name. Javascript Object Notation. You’re supposed to write them in javascript, and then save the javascript object as JSON. That’s even how I’ll be doing it for larger edits.

I’ve built a few javascript based json generators in my time, but I’m a web developer, and I’m not sure how useful that would be here. It would, at the least, be trivial to set up a web interface that let’s you edit the item list as part of a form and then spits out the json back to you at the end, if you think that would help.

I’d settle for a good CSV to JSON converter. There are some online, but I can’t seem to get the JSON arrays converted correctly with them.

Hah, didn’t build (or use) a proper JSON architecture in Perl, no. All I really did was extract the elements of the RECIPE macro using a regex, store those in a relevant place, and then print 'em in the format that I needed.

Also didn’t get a JSON architecture set up in C++, other than the bare minimum required to load recipes without assertion failures (granted, the bare minimum is too large, IMO).

I think I’ll look into whether I can read and write YAML in C++ with less pain, though…

So since people are talking about it can someone point me to where I learn wtf json is because what I have found with google when I checked didn’t really tell me so I probably googled the wrong things.

Hey GlyphGryph, do you have any plans to have the item factory store the items, as well? Like, handling creation and deletion, and all that? I ask because I’m currently having issues with player::sort_inv deleting and re-creating items, hence mangling references, and it would be useful if we could rely on pointers being valid long-term.

Well, the factory currently handles creation of items, at least for mapgen, but doesn’t track them. I don’t really think that is it’s place, though something that tracks the items might be worthwhile. Could you go into more details about what sort of problems you’re having? Why is sort_inv even deleting or creating ANYTHING? That seems incredibly confusing.

Also, haven’t worked on this in a bit, waiting for it to get merged in before continuing and it’s still not happened! >_<