Wednesday, November 22, 2023

Inventory System Port to Godot 4 C# Complete!

Greetings to all and a Happy Thanksgiving to those of us in America.  As my wonderful wife is hard at work preparing for Thanksgiving tomorrow, I am finishing what has been a very huge re-write of my game's inventory system from Godot 3 and GDScript to Godot 4 and C#.  It took longer than I expected, but then I did chase many rabbits which resulted in many great new features.

I want to talk a little bit about what the process was like and compare the two implementations.  Permit me to dive right in.

Godot 3: (March 2023)

Godot 3 Alpha

The Godot 3 version stored static inventory item definitions in Resource files.  This worked well and made updating the properties of each inventory item easy to do directly from the Godot user interface.  All instanced data was stored in Godot dictionaries.  The system was comprised of a Singleton for much of the inventory system logic, three UI nodes for the slots (small, medium, large) and a UI node for the base inventory window (shown below).  The inventory window dynamically builds itself based on the configuration of the properties stored in the Resource file for the respective container object.  The system had two types of objects, being containers and items.  Liquids were considered items.  It offered basic drag and drop, stack splitting and animated opening and closing.  Finally, it supported weight values shown in standard and metric systems.

I enjoyed learning about the Resource system in Godot and I only have one critique about it.  Sometimes my data structures were complex and when my resource contained an array, it was very difficult to add something to the array without having to re-key the data into the array in order to pick up a change.  GD Script was also fun to learn and I was able to quickly put together a basic system.

Godot 4: (November 2023)

Godot 4 Alpha

The Godot 4 version of the inventory system was essentially a complete re-write from GDScript to C#.  I switched from Godot Resources to JSON files and from Godot dictionaries to C# dictionaries.  I also switched from using Godot Signals to using C# Event Handlers.  Hum... what else...  I structured my Visual Studio solution to be close to a Clean Architecture style where I have my scripts broken down into an Application folder for the UI scripts, a Domain folder for my inventory classes, and an infrastructure folder for injections like my JSON implementation., etc.  It's not completely Clean Architecture simply because everything is on one DLL.  But it helps me organize my code.

There are so many new features as I found myself chasing rabbits. Even so, it was a rewarding experience to put this system together (again).  Let me share some feature highlights with you.

Inventory Window Base Scene

  • Inventory container window scenes build dynamically from JSON definitions where each container can have up to three slot sizes in any combination of slot counts and slot columns.
  • Container windows can be dragged anywhere in the game and locked in a set position.
  • Containers that have child containers can be opened via double-click or clicking the bottom right icon to open/close all child containers at once.
  • Weights can be configured to show in standard or metric measures.
  • Static JSON-based inventory definition files for image locations and data for items, containers, and liquids.  The goal is to allow players to be able to introduce their own items into the game or tweak any item to customize the game experience.
  • Instance game data will also be saved as JSON files.
  • Sound effects for valid and invalid actions, including liquids pouring from one container to another with the sound effect selected based on how much liquid is actually being moved around.
  • Extensive drag and drop scenarios (item to slot, item to container, item to item, container to container, etc.
  • Shift-drag-and-drop to split stacks in half.
  • Ctrl-drag-and-drop to bring up a quantity dialog for specific amounts.
  • Auto-merge and auto-fill when dragging items onto slots and containers while respecting volume constraints.
  • Containers have max volume constraints and separate liquid unit measurements for those containers that can hold liquid.
  • Dragging an item from a slot will double the size of the item visually
  • Custom tooltips which display summary information for containers, items, and liquids.

These are some of the features currently coded for the inventory system.  Some features I want to add in the future include selecting multiple slots at one time for drag-and-drop between containers, the ability to sort items inside containers based on name, type, etc., and the ability to pick up all items and deposit them into the player's inventory from a loot drop.

What's next on my list?  I am now going to move on to finishing my flora system along with all remaining features of the Godot 3 version that have not yet been ported over.  I hope you have enjoyed reading about my game.  Feel free to comment or suggest here in my blog, or on Twitter.

Until next time,

I'm Bound2bCoding

Wednesday, November 8, 2023

November Update

I want to mention briefly that I have changed my YouTube and Twitter handles.  Eyesgood is a name I have long used in gaming and I have really wanted to identify with a different handle in the context of my game development life.  Yesterday, I had a moment of inspiration and came up with:  Bound2bCoding.  Look for that name going forward as I sunset the use of Eyesgood in my dev life.

October was an amazing month of development work.  While working on converting the inventory engine to C#, I expanded the capabilities of the inventory system to handle scenarios that were not even considered in Godot 3.  I am still in the midst of this translating and refactoring process which I expect to run out to the end of the year.

C# Tip:  Unsubscribe C# Events Before Removing Scenes

One thing I discovered while testing my C# version may be of interest to any developers reading this.  I learned that C# events that are subscribed to are NOT unsubscribed just because the node is removed from the scene tree in Godot.  For example, I have a singleton named InventoryEngine which handles all the drag and drop transactions among other things.  I also have an InventoryWindow scene that subscribes to an event in the InventoryEngine.  The window node is instantiated each time a container is opened.  When the inventory window is closed, it is removed from the scene tree along with all its children.  

InventoryEngine (singleton)  

    public event EventHandler<int> RefreshContainerWindow;

InventoryWindow (node)    

    _inventoryEngine.RefreshContainerWindow += On_InventoryEngine_RefreshContainerWindow;   

InventoryWindow (node)

        _inventoryEngine.RefreshContainerWindow += On_InventoryEngine_RefreshContainerWindow;

I was having weird issues with my inventory windows not refreshing when dragging and dropping items.  It took me a long while to realize that events were firing from nodes that were no longer in the scene.  This was because I was not using Godot Signals, but rather ordinary C# event handlers.  According to the documentation, Godot handles the Godot Signals for disposed objects, but it does NOT handle any C# event listeners.  To fix this, I had to unsubscribe those subscribers in the InventoryWindow code behind before deleting the window node.  This is done in the _ExitTree() method.

public override void _ExitTree()
{
    _inventoryEngine.RefreshContainerWindow -= On_InventoryEngine_RefreshContainerWindow;          
    base._ExitTree();
}

I hope this helps someone else who may be pulling their hair out trying to track down this kind of issue.

Visual Studio Tip:  Don't forget to point your debug to the new DLL when upgrading Godot.

Here is another gotcha for Visual Studio.  When you upgrade your Godot version, Visual Studio => {project name}Debug Properties => Path to the executable, and click Browse to locate the new Godot executable.  This will allow debugging in the version you have upgraded to.

That's all for now.  I hope you have learned something useful.

Until next time...

I'm Bound2bCoding


Friday, September 29, 2023

September Update

August and September have been really excellent months for progress on my conversion from Godot 3 to Godot 4.  The tilemap conversion work is pretty much done.  The flora engine work is almost done.  I started writing the C# version of the inventory engine and that is almost done.  I also started bringing over some of the user interface.  There has just been a lot of progress all-around.

I have been quite surprised at how many hits I have been getting on this blog lately.  I don't know if it has anything to do with the UNITY fiasco or not, but it is encouraging to see thousands of hits per month now.  The YouTube channel subscriptions are up as well, although not from me giving attention to it.  I have been meaning to get another video posted to share my tilemap implementation, but I selfishly opted for more coding over more videos of coding.  The end of the year is typically when I have more time to devote to my hobbies (like this game) and I expect to be able to provide some informative videos on my channel very soon.  If you are one of the many who have asked me for videos, thank you for your patience.

In this post I want to mention a few things about Godot 4 and the tilemap terrain features.  For one, the terrain is too slow for my purposes.  The bottleneck seems to be the tilemap.set_cells_terrain_connect method, which paints the atlas sprites onto the tilemap using the auto-tiling terrain masks.  That method is brutally slow, while the Godot 3 counterpart tilemap.update_bitmask_region method is amazingly fast.  I eventually wrote my own bitmask solution for auto-tiling.  I will cover that in a future video.  I read recently that tilemaps have been given some optimization attention in the upcoming 4.2 update.  We shall see if the performance at least matches Godot 3.  I can tell you honestly that Godot 3 outshines Godot 4 in the area of terrain bitmasking by leaps and bounds.

Another issue I have discovered with Godot 4 has to do with the fact that physics interpolation has not been implemented yet.  What that means for me is that I have to endure the constant, nagging studder in my tilemap implementation until the feature makes it into Godot 4. That is frustrating.

There are also some heavy discussions happening regarding C# and Godot 4 as of this writing.  Some major changes are in the works, and while I welcome them, it makes moving to Godot 4 that much more challenging.  On a positive note, the C# code runs much faster than the GDScript.  

 

Until next time...

Monday, August 7, 2023

Godot 4 Upgrade and Migration from GDScript to C# August Breakthrough!

The month of August is already proving to be a great month for progress in my attempts to upgrade my game from Godot 3 to Godot 4.  Until this weekend, the tilemap had been a huge setback for me.  Coming into the conversion with only limited understanding of the new tilemap system, I made the mistake of assuming it was similar enough to Godot 3 that I could just create the tilesets, add the terrain, and convert my script to C# and it would work.  That was surely a mistaken assumption!

Once I debugged the C# code, I discovered my method of creating a chunk-less map that refreshed the visible tiles for each player movement wasn't going to work the same way in Godot 4 because the method to handle auto-tiling in Godot 4 is slow.  Extremely slow!  I had to step back and re-think my approach. By the end of the weekend I had the system working again and I am very impressed so far with how smooth the refresh is.  I haven't added the trees into the scene yet, but everything looks promising.  Already, I can tell this is going to be amazing!

Getting past the tilemap hurdle, I see wide-open highway in front of me.  Next on my list is completing the flora system conversion, which is already well underway.  Then, I will focus on the inventory system and finally the user interface.  Thanks for following along on this project.

Until next time...

Saturday, July 1, 2023

Godot 4 Upgrade and Migration from GDScript to C# Continued

The upgrade from Godot 3.5.2 to Godot 4.0.3 continues into July.  Nothing much to mention, although I did learn that Godot signals cannot pass C# objects as parameters.  Since I am replacing all my GDScripts with C# files, I needed to fall back to using C# Events and Handlers when the need to pass List<T> and C# Dictionary data was desired.  Another change I am making involves discarding Godot resource files.  While they are convenient for storing static data, I find them a bit cumbersome if the data structure is the least bit complex.  Crafting recipes readily comes to mind as an example.  If the resource defines Dictionaries and Arrays, the .tres files can be really frustrating to manage especially when I need to add or remove some piece of dictionary or array data.  In Godot 3.5.2, I sometimes have to re-enter dictionary data just to add a new record.  Therefore, part of this migration of scenes, scripts, and resources includes moving away from resource and tres files towards using json files to store game data.  They are much easier to work with, produce smaller files, and they can be managed using proven 3rd party libraries like Newtonsoft's Json library.  There is still so much to do and I will plug along until I get it done.  I can't wait to see the fruit of all this labor.

Until next time...

Sunday, May 28, 2023

Godot 4 Upgrade and Migration from GDScript to C#

This is just a quick note to say that I have decided to move forward with upgrading my game project from Godot 3.5.2 to Godot 4.0.3.  I am not planning to use the upgrade tool because, quite frankly, I don't trust it.  Instead, I am creating a new project where I can open the V3 and the V4 projects side by side to create the scenes and scripts anew.  My reason for doing this is to master the translation of GDScript to my professional language of C# and to ensure all existing scenes are the way I want them to be moving forward.  When I am done, I will have a new codebase written in C# using classes to store domain structure and JSON to store both game and player data. 

This will likely take me several months, after which I will do a comparison video showing any performance boosts achieved from this process.  For now, I am heads down with this task and will check back in once I am ready to showcase the changes.

Until next time...

Sunday, April 2, 2023

Marching Into Crafting

March is in the history books.  I made significant progress on my crafting engine.  I will demo it on my YouTube channel shortly.  But I would like to share with you my first design concept and why I felt it ultimately failed.  Then, I will show you my second one and why I feel it is a much better design.

First Concept:  Craftwork With Integrated Inventory Window

In this initial design, I thought to allow the player to open the Inventory window and the Craftwork window so that ingredients and tools could be dragged and dropped based on the recipe requirements. In order to provide for the drag-and-drop feature, I modified the inventory window code to hide buttons and other pieces of the inventory window so that I could instantiate an inventory window within the Craftwork window.  The result looked like this.

Instantiating the Inventory window scene was easy enough and the hidden controls were only hidden when the Inventory scene was instantiated by the Craftwork scene.  What I hoped to provide was selective ingredients.  By that, I mean I wanted the player to be able to choose the specific inventory items to be used in the crafting recipe by providing drag-and-drop capability.  Once that part of the design was implemented, I starting thinking about the user experience and the coding needed to pull it all together.  The user experience was first and foremost the most important concern in the design.  So, I thought through it carefully.  The steps were as follows.

1. The player opens the Craftwork window

2. The player opens the Inventory window.

3. The player chooses the recipe from the list on the left.  Line 1 and Line 2 give details about the recipe such as ingredients and tools required.  

4. The player then drags over from Inventory the ingredients and tools into the corresponding slot sizes.  The colored bars have not yet been coded, but they will be Percentage of Success, Resulting Quality, Amount of Focus applied (more time means a better outcome), and horizontally a progress bar.  The hammer tabs will provide lists of recipes by category.  

5. The player clicks the Craft button and the crafting process begins providing the items in the slots matched the recipe selected.

It all looked really fine to me until I realized how draggy and clicky it was.  There was so much the user had to do just to craft something.  But also, behind the scenes I had to manage two sets of inventory containers, coordinate passing back to the Inventory all non-consumable tools and items along with the crafted item and clean up if the user decided to cancel the session.  It was a huge lift for the player and fairly complicated for the developer.  I wasn't satisfied with it at all.

Focusing my attention on the draginess and clickiness (are those even words?) I decided to toss out the Inventory window and replace it with an image of the crafted item.  I did away with drag-and-drop altogether.  I also eliminated the necessity of opening Inventory unless the player just wants to.  Here is the second design.

Second Concept: Independent Craftwork Window With Auto-Ingredient Tracking


The second concept is much less work for the user and the developer.  The steps are as follows:

1. The Player opens the Craftwork window.

2. The Player selects a recipe.

3. The Player clicks the Craft button.

Behind the scenes when the player selects a recipe, the code checks for the existence of the ingredients and tools in the Inventory and holds a reference to their object id's.  There are two additional buttons above the Craft button.  The Down arrow allows the player to indicate he wants to use the lowest quality ingredients and tools from Inventory.  The Up arrow will select the highest quality ingredients and tools.  While not as specific as the first design, I think I can bake in some additional features to the Inventory window to allow more precise selection, such as active tool slotting.  When the player clicks the Craft button, all ingredients are immediately removed from Inventory and the timer and associated crafting sounds are presented.  Upon success, the item displayed in the Craftwork window is deposited in Inventory.  If the player does not have the proper ingredients and tools, a message is presented in the message window.  This solution is smaller, easier on the player and much easier to maintain.  I feel it is a superior design all around.

In the month of April, I intend to focus on building out the features of the Craftwork system and provide many new recipes.  If you have any suggestions for me, please feel free to post them here.  You can also check out my YouTube channel for the latest Dev Blog videos.

Until next time...

Saturday, February 25, 2023

February - A Month of Conflicting Priorities

February is almost gone and I have spent this shortest month of the year deciding what to do about upgrading my project to Godot 4 (G4).  In the end, I have decided to pull the project back into Godot 3.5.1  (G3) while I wait for breaking changes and non-working 2D features to get fixed.  Let me briefly share some thoughts on my experience.

Once G4 reached release candidate status, I downloaded the latest build and created a copy of my current G3 project.  Once I opened the project in G4, it commenced to upgrade the project and left me with several hundred errors and warnings.  That's OK, I expected them.  Systematically, I walked down the list to identify major breaking changes and found the following:

1. Shaders were broken.  I wasn't too surprised about this.  Upgrading a language-centric feature like the shader system is obviously going to create incompatibilities.  The upgrade tool was kind in giving some suggestions on how to make my existing shaders backwards compatible to the extend they would continue to function.  

2. Open Simplex Noise (OSN) was deprecated.  This one was a little frustrating.  G4 has replaced OSN with an entirely new library called FastNoiseLite (FNL).  I did not delve much into the differences between OSN and FNL nor did I refactor my code to use the new library's methods.  This was because I never reached that point in the process.  Another feature hindered that effort.  It appears the FNL library seems to be able to create more varied noise than FNL, which is definitely a good thing.  I wasn't very impressed with OSN to begin with.  It produced noise that was strangely predictable, which is not what you expect from a noise library.  For example, noise (0,0) was always the same value, every single time.  Anyway, I look forward to playing with FNL when I finally do upgrade to G4.

3.  GDScript updates.  Not much to say here.  As with the shader scripting, I totally expected changes to the language and I am sure the changes will be for the best.  I am so looking forward to learning it. 

4.  Tilemaps.  I saved the best (or worst) for last.  Tilemaps, where do I start? When I think of G4 Tilemaps, a train-wreck comes to mind.  Seriously, the new Tilemap system is buggy and more importantly, it is amazingly convoluted.  For example, it provides for the ability to create what are called Terrain Sets, which are another level below Tilesets.  The Terrain Sets provide a feature that incorporates the auto-tiling logic, which I definitely need.  But within a Tilemap and TileSet, and Terrain Set, there is yet another level called Terrains.  No, they are not the same thing.  Terrain Sets (many) can have many Terrains.  Oh, then yet another many relationship is Layers. Confused yet?  I was and still am!  What is the purpose of having the ability to create multiple Terrain Sets with each having multiple Terrains with multiple Layers? It seems convoluted and unnecessary. Plus, the Terrains that are configured for auto-tiling within the same Terrain Set within the same Tilemap don't even auto-tile correctly with each other.  It is totally broken as of this post. I tried creating multiple sets of terrains for my grass (spring, summer, fall, winter) - a simple use-case. Forget about coding procedural generated tiles, just painting them on the map using the tools showed me they do not auto-tile correctly over each other.  The tiles become confused and auto-tiling doesn't seem to know how to adjust. Throw in Layers and what exists today is just not understandable.  There are some other points I could mention, but a broken Tilemap system blocks my upgrade path.   

I know that Godot is a community project and those that contribute to the development of the engine do so with absolutely no compensation other than the good feeling of being able to contribute.  I get that and I appreciate every hour of every day that these developers spend working on the game engine I love and will use for my game.  That said, I think in their zeal to reinvent the wheel, they created a system that not only breaks every game that has ever used Godot Tilemaps, but they did so in a manner that should be avoided.  If you are making a 2D game, Tilemaps are probably at the center of your design.  It would have been much better to take an already working and capable Tilemap system and ease in the changes in such a way as to make upgrading easier and to allow for community feedback over an extended set of releases.  I am certain this would have been a much better path for everyone. 

I have been in software for over 18 years.  I understand what it is like to over-engineer a system or feature in the hopes of making something that is extremely flexible and powerful.  I understand because I have done it many times.  But this was overkill in my opinion.  And it is the one major feature that will keep G4 at arms length for probably the rest of this year. 

So, I will march into March with G3.5.1 and continue building my craftwork crafting system along with the gathering system in hopes that the Godot developers working on the Tilemap system will either create some videos, or more importantly update the documentation with code examples and explanations of convoluted features so that more of us in G3 land can make the crossing to G4.

I hope to be posting more videos soon on my YouTube channel.  Thanks for reading.

Until next time...

Monday, January 30, 2023

January Focus: World Object Spawn Engine (sort of)

The month of January, where did it go?  I was able to get a ton of work done in December while on a very long vacation and it is unfortunate that I cannot devote as much time to the game as I did then.  But such is life, and my development efforts here are returning to normal levels.

The focus this month was the world object spawn engine.  I had several goals with this but did not realize just how much ground needed to be cleared before starting to build this important piece of the game. What is this thing I call the World Object Spawn Engine?  Simply put, it is the part of the game that allows me to manage the spawning of objects into the game world.  For example, chopping down a tree is supposed to yield one or more logs.  The world spawner needs to know what to spawn, when to spawn it and where.

As I started looking into this, I discovered a few issues with the map, viewport size, and the placement of trees and the player.  What I thought was fairly accurate turned out to be a bit messy when I actually wired up the ability to see the tile positions in relation to the player and the trees.  These obscure issues really led me down a rabbit hole.  First off, I created a tile selector.  It is a hollow square that follows the mouse around the map snapping itself to whatever tile it is hovering over.  As with many things in the Godot game engine, it was amazingly easy to implement.  

func _physics_process(delta):

var tile_pos = ground_tilemap.map_to_world(ground_tilemap.world_to_map(get_global_mouse_position()))
position.x = tile_pos.x
position.y = tile_pos.y 

This script is attached to the Selector object, which is an Area2D.  The Area2D has a Collisionshape2D child, and that has a child Sprite.  Voila!  Simple.  With this visual aid I was able to factually know the location of tile edges.  This helped me determine where the trunks of trees should be and where the player should be.

While my attention was focused on the tilemaps and aligning the player, I made a decision to remove the north-face and south-face player sprite animations.  This is by no means set in stone, but I felt that east and west facing sprites were completely sufficient for the purpose.  A few more tweaks and adjustments here and there and by mid-month my attention finally shifted to the object spawn engine.

There is a saying in software engineering, "Data is king."  It means the most important decisions we make will always revolve around the data we are wanting to manage.  I needed to think about what kinds of data this engine would manage.  Stewing on this made me realize I had to think beyond the spawn engine in order to develop it.  Game objects and systems are very tightly intertwined, and they should be.  Gathering world objects creates inventory items which are used as ingredients for crafting recipes to make other world objects.  They all tie-in together like a puzzle.  

Crafting requires recipes, which require ingredients and tools.  Recipes need to be stored in some kind of data structure that identifies a) the item to be created, b) the ingredients required, c) the quantity of each ingredient, d) any tools that may be required to craft the item, and e) how long it would normally take.  Crafted items are made from other items and it is typical to start the whole process with gathering.  You are probably well familiar with the stick, rock, and plant fiber paradigm especially in the context of sandbox survival games, which this hopes to become.  The player gathers raw resources that are in themselves usable crafting ingredients and sometimes tools.  From there, a + b = crafting something else, and so the tree grows from there.  Data!  We must be able to wrap all this around some kind of data.

Godot offers a few data structures that we can work with.  They are the Dictionary{} and the Array[].  The dictionary has a key and a value.  The key has to be unique.  The value can be anything.  I have already identified most of the data elements I am going to need to manage object spawning, gathering, and crafting.  What can we do with these structures in Godot to manage this data?  Let's do a simple recipe of two ingredients.

recipe_type =  { "flint_and_steel" : ["flint_stone", 1]}

The recipe_type is a dictionary.  The key is the name of the item to be crafted, "flint_and_steel".  The ingredients will be the dictionary value, an array[].  So far, we have an array which contains a string value of the name of the ingredient "flint_stone" and an integer value which is the quantity needed of this ingredient, 1.  But how do we expand this to more than one ingredient when we already have an array as the value of the dictionary?  Take a look at this.

 recipe_type =  { "flint_and_steel" : [["flint_stone", 1], ["fire_steel", 1]]}

We now have an array of arrays.  The inner array is [ingredient, quantity].  The outer array contains two inner arrays, forming another array.  How would we read such a data structure?  We would reference it like this:  array[0][0] would equal "flint_stone".  Array[0][1] would equal 1.  Array[1,0] would equal "fire_steel" and, you get the picture.  This is close to what we need, but we also need to store some other pieces of data.  Ingredients are what we call many-to-many relationships.  Many recipes can have many ingredients.  But what can we do about a one-to-one relationship?  For example, we need to store the base crafting time (how long it takes) to make the flint_and_steel recipe_type.  Let's introduce another string value and integer value to the array.

recipe_type =  { "flint_and_steel" : [["base_time", 20],["flint_stone", 1], ["fire_steel", 1]]}

I know that base_time is not an ingredient. Since every recipe needs a base_time value, I choose to place it at the beginning of the inner array and give it a special name, "base_time" and value x.  I placed it at the beginning of the outer array because I will extract that information always for every recipe from array[0][0], and [0][1].  I could search the array to find a match, but searching is typically an expensive operation in software development.  Better that I know where it is.  It is my data structure, after all!

Ok, so I know the first element is for base_time.  The rest (ever how many they are) will be ingredients.  This brings me to the last thing I need to manage, the tools.  Tools are interesting.  If a recipe calls for a cutting tool, do I just let the player pick any cutting tool, or do I dictate somehow which cutting tools would be appropriate?  I think the latter is more sensible, else the player might try to craft something requiring a knife by using a tomahawk!  This led me to another data structure that will help me manage these decisions.

tool_type = {"cutting_tool" : [["chert_chip", 15],["stone_hatchet", 25],["chert_knife", 30]]}

Similar to recipe_type, the tool_type dictionary will be an array of arrays.  The key will be the type of tool, in this example, cutting_tool.  Then, all the crafted items in the game that are considered able to cut something will be listed with an integer value representing how proficient they are at cutting.

Let's now suppose that I need to have a recipe which contains ingredients along with a cutting tool.  Back up in the recipe_type dictionary, I make another rule for myself.  If the Ingredient begins with an "*" it means it is a tool and not an ingredient.

recipe_type =  { "flint_and_steel" : [["base_time", 20],["flint_stone", 1], ["fire_steel", 1], ["*cutting_tool", 1]]}

The "*cutting_tool" will be processed as a tool type, not an ingredient.  I can take this reference and check to make sure the player chooses a tool that belongs to the "cutting_tool" category to satisfy the recipe for the item to craft.  Back in the tool_type dictionary, I can pull the cutting tool list from the key "cutting_tool" and obtain the success chance for any tool from that array.  

So then, I have two dictionaries, recipe_type and tool_type.  I can create recipes with any number of ingredients, any number of tool types, and I have all the information I need at this point in the development of my game crafting system.  I also know what kinds of data I need to manage.  And, I can built upon this system in any way I want. 

This is what I plan to do in February, to continue to design and implement a world object spawner, a recipe and crafting system, and the UI to make this all come together into something I hope will be thoroughly enjoyable.

Until next time...