How is the multi input/multi output recipe for stonecutting implemented?

Started by Lupin III, September 23, 2015, 03:57:41 PM

Previous topic - Next topic

Lupin III

So I'm trying to make a mod that allows me to repair any apparel or weapon on its respective table with a single recipe (two actually, one for all apparel and one for all weapons). Apparently there's no way to make this as an XML only mod, which I would have preferred (https://ludeon.com/forums/index.php?topic=16264).

I now set up visual studio and made a DLL mod. It seems to me that stone cutting does something very similar. There's a single recipe to cut stone and it takes any stone chunk it can find, while the output is dependent on what kind of chunk was used. I adapted what I could find by decompiling (not much more than replacing the categories of "StoneChunks" by "Apparel"). I never programmed anything in C# before, but I managed to compile a DLL and the game even starts with it without crashing now (it took me a while to find out that the culprit was the .pdb file also created in the Assemblies directory that causes the game to crash as soon as the mod is loaded. WHY?!). The recipe is also available as it should be at the tailor's table (but that's something that also worked without any DLL anyway). But the apparels that get used in the recipe currently vanish into thin air. So how does the stone cutting recipe do that? How can I define the product of the recipe? (it should be the same apparel as the ingredient just with 100% HP).

This is what I did until now (pretty much a copy of the stone cutting stuff):
Mending.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using UnityEngine;
using RimWorld;
using Verse;

namespace Lupin_Mend
{
public class RecipeWorkerCounter_MendApparel : RecipeWorkerCounter
{
private List<ThingDef> apparelDefs;

public override bool CanCountProducts(Bill_Production bill)
{
return true;
}

public override int CountProducts(Bill_Production bill)
{
if (this.apparelDefs == null)
{
ThingCategoryDef item = ThingCategoryDef.Named("Apparel");
this.apparelDefs = new List<ThingDef>(16);
foreach (ThingDef current in DefDatabase<ThingDef>.AllDefsListForReading)
{
if (current.thingCategories != null && current.thingCategories.Contains(item))
{
this.apparelDefs.Add(current);
}
}
}
int num = 0;
for (int i = 0; i < this.apparelDefs.Count; i++)
{
num += Find.ResourceCounter.GetCount(this.apparelDefs[i]);
}
return num;
}

public override string ProductsDescription(Bill_Production bill)
{
return ThingCategoryDef.Named("Apparel").label;
}
}
}


mend_apparel.xml (recipe):

<?xml version="1.0" encoding="utf-8" ?>
<RecipeDefs>

<RecipeDef>
<workerCounterClass>Lupin_Mend.RecipeWorkerCounter_MendApparel</workerCounterClass>
<defName>Lupin_MendApparel</defName>
<label>mend apparel</label>
<description>Mend clothing</description>
<jobString>Mending.</jobString>
<workAmount>1400</workAmount>
<workSpeedStat>TailoringSpeed</workSpeedStat>
<workSkill>Crafting</workSkill>
<workSkillLearnFactor>0.1</workSkillLearnFactor>
<effectWorking>Tailor</effectWorking>
<soundWorking>Recipe_Tailor</soundWorking>
<ingredients>
<li>
<filter>
<categories>
<li>Apparel</li>
</categories>
</filter>
<count>1</count>
</li>
</ingredients>
<fixedIngredientFilter>
<categories>
<li>Apparel</li>
</categories>
</fixedIngredientFilter>
<recipeUsers>
<li>TableTailor</li>
</recipeUsers>
</RecipeDef>

</RecipeDefs>

Fluffy (l2032)

I'ts not quite so simple. The recipe currently has no outputs at all, you'll notice that the block recipe has specialOutputs - butchery listed. This is handled in the core code, and things/pawns that can be butchered define butchery outputs (and some fluff is added depending on worker skill etc.)

You'ld need to make the game recognize a specialOutput of mending for this to work without altering any xml in the apparel. I'm not sure this is entirely possible without overwriting half the game.

It might really be easier to use the base butchery. I think you should be able to dynamically inject the required butcherProducts tags through CCL's special injectors, so you don't have to manually update all the xml's (and it would handle modded content, yay!).

*disclaimer: this is all if the top of my head, without having access to the game or it's source. The slack is a great way to get quicker and probably better answers; E (100010101010 or some such), Latta, Skullywag, Mrofa, Alistaire and NoImageAvailable and I'm sure others are all on there with some regularity and are more experienced with the C# side than I am.