Modding Tutorials/Smelter

From RimWorld Wiki
Jump to navigation Jump to search

Modding Tutorials


== This tutorial is out of date, however there is still some useful information here. ==

This tutorial introduces how to make an interactive building. Currently, only work benches can be fully modified using .xml. The Comms console and Nutrient paste dispenser have hard-coded elements. So here we will set out to make a building that follows the work bench pattern.

Concept

All mods start with a concept. Some are grandiose (adding robot space pirate ghosts to the game). Some, like this one, are modest. The concept of the smelter is simple. Make a building where colonists can take slag debris to melt down into usable metal.

Overview

When you set out to make a building or piece of furniture that operates as a workbench, you need to define three things:

Making recipes is optional if your building duplicates the behavior of an already existing one. For example, if you are making a stone kitchen that uses stone blocks instead of metal to construct, you could skip step 3 and use the same recipes as the standard kitchen model.

Also, if you haven't already, make sure you define an About.xml for the mod. You can make a new one or copy the following:

<?xml version="1.0" encoding="utf-8"?>
<ModMetaData>
	<name>Smelter Tutorial</name>
	<author>Your Name Here!</author>
	<url>http://rimworldwiki.com/Modding_Tutorials/Smelter</url>
	<targetVersion>Alpha 6</targetVersion>
	<description>Tutorial mod for recipes and interactive buildings.</description>
</ModMetaData>

Create the Building Definition

This part should be easy. You already did it in the first tutorial. But here is the boilerplate for a new building which will become our smelter. Save this in a file called "Buildings_Smelter.xml" in your mod folder in the Defs/ThingDefs/ subfolder.

 <?xml version="1.0" encoding="utf-8" ?>
 <Buildings>
  
  <!-- Boilerplate --> 
  
  <ThingDef Name="BuildingBase" Abstract="True">
    <category>Building</category>
    <bulletImpactSound>BulletImpactMetal</bulletImpactSound>
    <selectable>true</selectable>
    <drawerType>MapMeshAndRealTime</drawerType>
    <surfaceNeeded>Light</surfaceNeeded>
    <constructionEffect>ConstructMetal</constructionEffect>
    <repairEffect>Repair</repairEffect>
  </ThingDef>
  
  <!-- Smelter building definition -->
  
  <ThingDef ParentName="BuildingBase">
    <DefName>BuildingSmelter</DefName>
    <EType>BuildingComplex</EType>
    <Label>Smelter</Label>
    <ThingClass>Building</ThingClass>
    <Description>A large, hot furnace used to produce metal from ore.</Description>
    <TexturePath>Things/Building/Production/TableStonecutter</TexturePath>
    <CostList>
      <li>
        <thingDef>Metal</thingDef>
        <count>30</count>
      </li>
    </CostList>
    <AltitudeLayer>BuildingTall</AltitudeLayer>
    <WorkToBuild>600</WorkToBuild>
    <maxHealth>200</maxHealth>
    <Size>(3,2)</Size>
    <surfaceNeeded>Heavy</surfaceNeeded>
    <DesignationCategory>Production</DesignationCategory>
    <Passability>Impassable</Passability>
  </ThingDef>
 </Buildings>

Go ahead and run the game to test out the above definition. You'll see your colonists build a 3x2 structure that looks about the same as the stone cutter's table (that's because we told it to use the same texture for simplicity's sake).

Now let's add the interaction space. To do this you will need to add the following:

 <hasInteractionSquare>true</hasInteractionSquare>
 <interactionSquareOffset>(0,0,2)</interactionSquareOffset>

The first tag, "hasInteractionSquare" tells the game that this building has an interaction square. It's phrased sort of like a question: "The Smelter has an interaction square?" and then answers the question "Yes, that's true." The second tag, "interactionSquareOffset" tells the game where that square is. The three values refer to the x, y, and z coordinates in the game. This is a bit confusing unless you are are intimately aware of how the Unity engine works. Basically, since Unity is used for 3d games, x, y, and z are mandatory. But Rimworld is 2d so only the x and z coordinates matter. Wait, x and z?! Yes, because in Unity, the y coordinate refers to the vertical space. This value is always 0 because Rimworld is flat. It may be easier to just ignore all this and think of the value as "x, 0, y" instead. The offset is measured as distance from the origin of the object. The smelter is 3 units wide by 2 units tall. It's interaction square will be 2 units above its origin.

[ ][x][ ] x = the interaction space (2 spaces above the origin)
[■][■][■] 
[■][□][■] 
    ^--------the origin.

Fire up the game and see what happens. Now when you build the smelter, you should see a yellow circle above it just like with the other interactive buildings in the game. You have successfully told Rimworld that your building has an interaction square! But so far, that's all. Your colonists still have no idea what to do with it.

The next thing to do is to tell the game that the smelter is used to make stuff from something else. This means updating the EType and ThingClass tags. We are going to tell the game that this building is a work table because that function best fits our concept. Edit the tags as follows:

 <EType>Building_WorkTable</EType>
 <ThingClass>Building_WorkTable</ThingClass>

This is just more boilerplate necessary to make the building function as desired. Don't worry about the nuances of Building_WorkTable vs. BuildingComplex or Building_Worktable vs. Building. Those are advanced concepts beyond the scope of this tutorial.

The next thing to add is a definition for the inspector tab. When you click on a building, the inspector tab gives you information about it. We also want to give orders for the smelter on this tab. To do so add the following:

 <inspectorTabs>
  <li>ITab_Bills</li>
 </inspectorTabs>

This tells the game to use the Bills user interface in the inspection tab of this building. Launch the game again, build a smelter, then click on it to see what happens. You should notice a button called "Bills" above the inspector tab. You can press it just like you can on the kitchen or the stone cutter's table and open the bills menu! If you then click "Add bill"... nothing happens. That's because we haven't given the smelter any "recipes" yet. That is the final addition to the smelter building to make.

Recipes are listed under the recipes tag. For now, we will just add one recipe, the recipe for melting slag into metal:

 <recipes>
  <li>SmeltDebrisSlag</li>
 </recipes>

You may be asking yourself, "Where does this recipe come from?" And the answer is nowhere yet. We've told the smelter to use a recipe called "SmeltDebrisSlag" but before we launch the game again, we'll have to write the recipe! For now, though, we are done with defining the smelter building. Close the file.

Create a Recipe

So we have a building that let's your colonists cook slag into metal using a recipe called "SmeltSlagDebris". Only one problem, we haven't written the recipe next. To do that make a file called "Recipe_Smelter.xml" in your mod folder in the Defs/RecipeDefs/ subfolder. In this file, add the following boilerplate:

 <?xml version="1.0" encoding="utf-8" ?>
 <RecipeDefs>
  <RecipeDef>
    <defName>SmeltDebrisSlag</defName>
    <label>Smelt slag debris</label>
    <description>Decomposes slag to extract metal.</description>
    <jobString>Smelting slag.</jobString>
    <workAmount>1000</workAmount>
  <RecipeDef>
 </RecipeDefs>

Now that the recipe exists, you can start up the game again. Now when you click the "Add bill" button the recipe you just defined should appear! At this point you might be getting a bit tired of waiting for your colonists to build your smelter. There are a couple things you can do. You can either change the value of the "WorkToBuild" tag in the building definition to something much lower, or you can turn on "God mode" which will let you build anything instantly. This is very useful and now might be a good time to become familiar with it if you haven't already!

You might be asking, "What does this recipe actually do?" Well, nothing yet. That's the next step and it's also where things get interesting. Recipes consist of two important parts: ingredients and products. Ingredients go in; products come out.

First, let's start with the easy part, the product. We know we want metal to come out, we tell the game this using the Products tag. Add the following to your recipe:

 <products>
  <li>
    <thingDef>Metal</thingDef>
    <count>5</count>
  </li>
 </products>

We could add even more things to be produced by adding addition li entries. But for now metal is enough. We set the count value to 5. This may not seem like much, but remember this is slag that we are smelting, which by definition shouldn't have any metal in it at all. But since slag is left in game from crashed shuttles and destroyed buildings, it's ok if we get a little out of it. But it shouldn't be more than the original metal used to make the building that blew up creating the slag. That would be an exploit. It's important to think about how your mod will affect the game's balance if you expect other people to try it out.

Next we will specify the ingredients. This step is just a little more complicated. Insert the following into your recipe:

    <ingredients>
      <li>
        <filter>
          <thingDefs>
            <li>DebrisSlag</li>
          </thingDefs>
        </filter>
        <count>1</count>
      </li>
    </ingredients>

You will notice that the ingredients tag is almost identical in structure to the products tag but has one extra tier called "filter". Basically, the filter tag is a way to select what ingredients your colonists are allowed to use to do a recipe. For example, the cooking recipe bills default to disallow the use of human meat. There are actually more options for affecting the way ingredients are display in the user interface using the "ParentIngredientFilter" and the "DefaultIngredientFilter", both of which are not strictly necessary, so let's ignore them for now. Refer to RecipeDef if you are curious.

Launch the game and see what happens. Everything looks good, right? We added a bill and we can configure it in the bills menu. Wait... there's no slag on the screen. Activate God Mode and then choose "Tool: Spawn thing" from the menu (it's near the bottom of the second column). Then click "Slag debris" from the next menu (it's about the middle of the second column). Click around on screen and drop some slag. Right click when you've finished. Now that there's some slag lying about and a bill to melt it down at the smelter, colonists should start getting to work! Except... they aren't. They're just standing about. Selecting a colonist and right clicking on the smelter also doesn't do anything. That's because our colonists aren't aware that actually completing the bill at the smelter is, well, their job. And that is the third step in making our smelter.

Create a Work Giver Definition

To make the colonists aware of what work needs to be done, we need to write a WorkGiverDef. This will tell the game to tell them that, hey, you should do this task. Otherwise they'll ignore it. Who's to tell them that smelting slag is their job and not, say, that of the Muffalo? Eating plants is a job but no one told them to do that either.

To write the WorkGiverDef, first make a new file called "Workgiver_Smelter.xml" in your mod folder in the Defs/WorkgiverDefs/ subfolder. In it add the following:

<?xml version="1.0" encoding="utf-8" ?>
<WorkGivers>
  <WorkGiverDef>
    <DefName>DoBillsSmelter</DefName>
    <giverClass>AI.WorkGiver_DoBill</giverClass>
    <workType>Crafting</workType>
    <priorityInType>10</priorityInType>
    <WorkTableDef>BuildingSmelter</WorkTableDef>
    <verb>smelt</verb>
    <gerund>smelting</gerund>
  </WorkGiverDef>
</WorkGivers>

You can probably guess what these values mean by looking, but here's the most important thing to remember. Make sure the DefName is unique and not something used in the core or another mod. GiverClass just tells the game that the work to be done is a bill. Remember the smelter uses the bill assignment interface for smelting metal. The next most important thing is WorkTableDef. Make sure this is the definition name for the smelter. Remember way back we assigned smelter the DefName value "BuildingSmelter". WorkType simply tells the game which colonist skill is used to do the job. In this case, let's go with Crafting. But if you like, you can set it to any of the other colonist skills. If you believe in the fine art of metal smelting, you might change it to Art, for example. PriorityInType tells the game how important this job is relative to other Crafting jobs. Finally, Verb and Gerund are just the words that are used in the game text to tell the player what the colonist is doing. For example: "Prioritize smelting".

Now that the WorkGiverDef is finished, launch the game and test out the job. You should observe your colonists running off now to pick up slag and fill the bill created at your smelter!

Troubleshooting

If you are having problems, always try to reboot the game, close your text editors, and reopen the mod menu when you restart the game to make sure the data is up-to-date. If you still have problems, remember to check the modding help forum at the official site. Most likely someone else has had the same issue!

Below are the final .xml files used in this tutorial. Check to make sure your files are consistent.

Mods/SmelterTutorial/About/About.xml

<?xml version="1.0" encoding="utf-8"?>
<ModMetaData>
	<name>Smelter Tutorial</name>
	<author>Your Name</author>
	<url>http://http://rimworldwiki.com/</url>
	<targetVersion>Alpha 6</targetVersion>
	<description>Tutorial mod for recipes and interactive buildings.</description>
</ModMetaData>

Mods/SmelterTutorial/Defs/ThingDefs/Buildings_Smelter.xml

<?xml version="1.0" encoding="utf-8" ?>
<Buildings>
  
  <!-- Boilerplate -->
  
  <ThingDef Name="BuildingBase" Abstract="True">
    <category>Building</category>
    <bulletImpactSound>BulletImpactMetal</bulletImpactSound>
    <selectable>true</selectable>
    <drawerType>MapMeshAndRealTime</drawerType>
    <surfaceNeeded>Light</surfaceNeeded>
    <constructionEffect>ConstructMetal</constructionEffect>
    <repairEffect>Repair</repairEffect>
  </ThingDef>
  
  <!-- Smelter building definition -->
  
  <ThingDef ParentName="BuildingBase">
    <DefName>BuildingSmelter</DefName>
    <EType>Building_WorkTable</EType>
    <Label>Smelter</Label>
    <ThingClass>Building_WorkTable</ThingClass>
    <Description>A large, hot furnace used to produce metal from ore. The heat required consumes a great deal of electricity so it's best to turn it off when not in use.</Description>
    <TexturePath>Things/Building/Production/TableStonecutter</TexturePath>
    <CostList>
      <li>
        <thingDef>Metal</thingDef>
        <count>10</count>
      </li>
    </CostList>
    <AltitudeLayer>BuildingTall</AltitudeLayer>
    <WorkToBuild>600</WorkToBuild>
    <maxHealth>200</maxHealth>
    <Size>(3,2)</Size>
    <surfaceNeeded>Heavy</surfaceNeeded>
    <DesignationCategory>Production</DesignationCategory>
    <Passability>Impassable</Passability>
    <hasInteractionSquare>True</hasInteractionSquare>
    <interactionSquareOffset>(0,0,2)</interactionSquareOffset>
    <inspectorTabs>
      <li>UI.ITab_Bills</li>
    </inspectorTabs>
    <recipes>
      <li>SmeltDebrisSlag</li>
    </recipes>
  </ThingDef>
</Buildings>

Mods/SmelterTutorial/Defs/RecipeDefs/Recipe_Smelter.xml

<?xml version="1.0" encoding="utf-8" ?>
<RecipeDefs>
  <RecipeDef>
    <defName>SmeltDebrisSlag</defName>
    <label>Smelt slag debris</label>
    <description>Decomposes slag to extract metal.</description>
    <jobString>Smelting slag.</jobString>
    <workAmount>1000</workAmount>
    <products>
      <li>
        <thingDef>Metal</thingDef>
        <count>5</count>
      </li>
    </products>
    <ingredients>
      <li>
        <filter>
          <thingDefs>
            <li>DebrisSlag</li>
          </thingDefs>
        </filter>
        <count>1</count>
      </li>
    </ingredients>
  </RecipeDef>
</RecipeDefs>

Mods/SmelterTutorial/Defs/WorkGiverDefs/Workgiver_Smelter.xml

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

  <WorkGiverDef>
    <defName>DoBillsSmelter</defName>
    <giverClass>AI.WorkGiver_DoBill</giverClass>
    <workType>Crafting</workType>
    <priorityInType>10</priorityInType>
    <workTableDef>BuildingSmelter</workTableDef>
    <verb>smelt</verb>
    <gerund>smelting</gerund>
  </WorkGiverDef>

</WorkGivers>

Where to go From Here

We've just implemented the bare minimum for our smelter. There are still many things to make it better. As an exercise, consider adding the following features:

  • Make the smelter building out of stone. It's kind of silly to make a building that melts metal out of... metal. Make your building out of stone blocks and hide it from the menu until the stone crafting research has been unlocked.
  • Add another recipe. Smelters are not traditionally used for salvaging scrap. They were used to melt ore and extract precious metals leaving behind slag. Add another recipe that takes rock debris as an ingredient and produces silver.
  • Add electricity. It's fine to assume that your colonists are using firewood to operate the furnace, but you might want to enter the 21st century and make your smelter consume electricity. You can turn the power off when no one is using it.
  • Add skill. Award experience points to your colonists for smelting and have their skill affect their performance by writing a SkillNeedDef.
  • Add art. Make your own image to use in the game for the smelter. Add special effects to the colonists as they work. Add a shadow to the building.