Step Three - Edit your iff
Volcanic has now created a mostly empty iff and has very kindly opened that new file in its Editor for you.
The newly created iff file has 2 resources in it, an OBJD (which is, in part, displayed on the Object tab that you've opened onto), and a STR#128 Strings resource that is used to list any animations your sim might need to do while interacting with this object. We wont be using any animations for this project, so we'll just ignore the string resource altogether.
The first thing you'll have noticed is that Volcanic does not automatically create any graphics resources so all you see in the preview window is the little yellow floor-tile marking where your object is. That is fine. We'll get to that later.
You'll also notice the large "<NO CTSS>" in the middle of your editor window. The CTSS is the strings resource where your catalog text (buymode) goes. We'll be adding that in a short while as well. Additional catalog information is filled in right here on the Object tab. Since we want our decor to be available for all lots we will leave all Lot Categories UNCHECKED. (Only check things when you want to restrict your object to specific lot types)
The "Motives Rating" section does not work in Volcanic yet, but when it does this is where you'll enter the number(s) that you wish to be displayed in the buymode catalog information. For this project, for example, we would enter a "4" for the room score. Entering a number here would not actually GIVE our object the roomscore, though. This field simply informs the purchaser what roomscore they can expect from this object. You will actually give your object a functioning roomscore when we work on the "tree" resources. So even though this section isn't up as and running yet (at the time this was written, at least), your object will still be able to contribute roomscore in-game.
You can also ignore "Sale Price" altogether. FreeSO uses a different method of setting the prices and cannot generate a thumbnail until after the art has been included so we are done on this tab for now.
Switch to the TREES AND RESOURCES tab. This is where most of the work gets done in Volcanic.
You start off on the Trees item of the drop down list. Anyone who worked in the old TS1 programs will know these as BHAVs instead of Trees.
Trees and Resources - Trees
Every object needs a minimum of 2 trees, the "main" and the "init" tree.
The INIT tree tells the object how to begin existing in the lot. It sets up a bunch of rules-n-stuff including the starting values for attributes, permissions, and placement rules, and so on before the object is even placed on the lot. Many of these values get changed by other trees later. Some simple examples of the the things you'd declare in an Init tree are "yes, this object can go on slopes", "no, not on pools", "this object can sit on tables", "this object cannot have a wall on its left side", "this object is a light source" and so on.
The MAIN tree tells the object how to continue existing after it has been initialized. In the case of our nice, simple tutorial object we want it to just sit there and look pretty. Nothing more. But if we were making a lit candle we'd want it to constantly flicker through a few different graphics so the flame would be animated. Or if it were a balloon we might want it to just sit there for 12 hours and then pop or float away. If it were a plant might we'd want a water counter to tick down or a bloom counter to tick up over time. All of these things would be done in the main tree.
These two trees, the main and the init, can exist inside of the iff file itself or in a global file that your object has access to. We are going to build them right here inside of the iff itself. Click the NEW button to add your first one.
We'll start with the "main". When naming your resources you get more points for clarity than wit, so always keep your labels simple, accurate, and clear. So use the unimaginative, very on-the-nose "main" for your chunk label. You can leave this chunk ID at the starting value of 4096.
With your new main tree selected, click the Edit Tree button (or double click the "main" tree in the list) and open the trees editor.
As mentioned above, our tutorial object has no function other than to exist and look pretty. All that is required to 'exist' in the game is a single node in the main tree: an idle node. Needing to "idle" for a span of time is extremely common, so a few variations were pre-made and placed in the global file (global.iff) that every single object has access to. We are going to use one of those.
To find it type "idle" in the search field and select [Global: Idle] from the results. Click anywhere in your workspace to place it.
It is designed to idle for however long you tell it to and you do that by clicking your placed node and entering a number in the Argument 1 field. The number you are entering is how many ticks you want your object to sleep (idle) for. More ticks means a longer time. There isn't a number for "forever' which is what we want so, instead, we'll enter a huge number like 20000.
Fabulous!! Next we must tell it what to do once 20000 ticks have passed. That's what the little red X bubble and the little green Check bubble are for .. the next instructions. The red bubble is for False returns. The green bubble is for True returns. All we need to worry about in this case, is the True return. Once 20000 ticks have passed successfully what should the main do? Sleep for another 20000 ticks! So grab that little green bubble and drag it upward back to it's own node. A little green arrow head will appear overlapping the green bubble pointing back at it's own node making the main loop back on itself forever which, in a Main, is a good thing.
The idle node wont ever return a False, but lets not ignore it. Using the menu bar, Insert a "False" (or Ctrl + F), and drag the False bubble's arrow to it.
That completes the Main tree so close the trees editor and lets move on to our second required tree, the init.
As before, click the New button to create a tree. Increase the Chunk ID by one (to 4097) and name this tree "init" and then open it up in the Trees editor.
The Global has another pre-made tree in it that we can use to kick our new init tree off. Search for "init". Only 2 entries are found this time and one of those, the one labeled "Private:", is the tree that you've just made. A private subroutine is one that exists inside of the self-same object. The one labeled "Global:" is the subroutine that exists inside of global.iff and it contains all of the basics a sim object needs. Choose that one and place it in your workspace.
Now that you have laid a basic foundation, you will add to it and refine it to your project's specific needs.
Our little decor, for example, should go on surfaces, which is not set up in the very-useful-yet-generic [Global: Init Object] tree. We'll also want to add some roomscore to our decorative object. To add these refinements we will add our own nodes after the [Global: Init Object] call we've just placed. "After" is very important as it allows us to countermand any rule have been set by the global tree, that don't fit the way we want our object to work.
There are a variety of primitives available, but for our purposes we need the oft-used Expression primitive. You can find it by searching for "expression" (if it does not show up, you may need to click the All filter button), or you can use one of the colorful Filter buttons to shorten the list to more manageable length. Expression can be found under both the green Math or the yellow Control filter buttons. No matter how where you found it, the Expression node will always starts out as yellow and then, depending on the operator you choose for it, may turn green.
Add one to your workspace, remember to click on it after it has been placed to select it, and Edit the LHS (Left Hand Side). We'll start with making our decor go on surfaces and that means setting its "allowed height flags".
TIP: Both the Source and the Data fields act as searches when you type in them. (Double SQUEE!!)
In this case, you want to choose the "Set Flag:" operator from the Operator dropdown menu. This operator tells the game to do something rather than asking it to check on a condition. Since returning false would be impossible in such a case, the True/False bubbles have been replaced with a single, blue "Done" bubble.
And, finally, edit the RHS (Right Hand Side), this time choosing "Tuning" and typing in the number "16515". When your node updates it'll display the label for a Global Constant used for heights and even include the literal value in parenthesis for you. An alternative way of doing this would have been to pick "Literal" instead of "Tuning" and type in the value directly. Both ways give the exact same results, but using constants means everything stays in sync if someone were to come along and makes a change in the future.
There is no way to tell this from the information displayed on the node (yet?), but setting this flag (Constant std height #3 (4)) will allow our decor to sit on counters.
Add 3 more nodes just like this one changing, the RHS so our decor can sit on end tables (Tuning 16520), tables and desks (Tuning 16514), and coffee tables (Tuning 16513). Yes, we skipped heights "(7)", "(6)", and "(5)". Those are used by the game for other things and we don't need them.
Our generic global call to [Global:Init] tells it that is IS allowed on a floor, since so many objects are. Normally, I love when things go on surfaces AND the floor, but for the sake of learning we're going to overwrite that sucker and expressly forbid it by placing a conflicting rule AFTER that global call we started this tree with. Remember, the game will always respect the last rule it received on the matter so make sure your new, specific rules always come after the generic set up.
Make one more node, set the LHS up the same way, but this time choose "Clear Flag:" as the operator and RHS should be Tuning 16516 (cause Maxis put this one out of order). This node actively prevents the object from being placed at floor height.
We've placed 5 new nodes into our tree but simply being in there, free floating like that, isn't enough. The game needs a clear set of instructions on which nodes to use, in which order, and under what circumstances. We give it these instructions by linking the nodes toogether with True/False/Done returns. Everything else in our workspace is completely ignored.
If you look closely you'll notice that the very first node we added to this tree has a green border, instead of the normal white one or the red that shows us which node is currently selected. The green border tells us that this is The First Node. The game always starts at The First Node of each tree and follows our GOTO instructions (True/False/Done) from there. So let's go ahead and give it some instruction. Start with the First node and drag your (green) True bubble down connect to to your first height node. Then drag the (blue) Done bubbles from each of those nodes to the next, chaining them together.
If you ever make a mistake and realize that you actually need another node to be the start of a tree, you change fix that by highlighting it and clicking CTRL+1 or by choosing "Set As First" from the Edit in the menu bar.
There's our height rules done. Some of the surfaces we chose (like end table) reject larger objects even when the allowed height flag has been set. This is an interesting combination of the table's container slot settings, support strength, and our objects weight and size. Our global init tree set a size but didn't really set a weight, so lets add another node and give our decor a little weight.
Find "weight" for the LHS
This time for RHS we'll use a literal number. "5" is a good weight for tiny objects. ("5 whats?", I hear you asking. I have no blessed clue. But 5 is used in other small objects, so we are following Maxis' lead.)
And for operator choose := which is the symbol for "assign to"
There we have it. "My weight assign to 5"
Our final task in this tree is to set it's room score contribution up. Remember that "4" we would've added to the Object tab's "room" field a while back? The one that would have been just a bit of text in the buymode catalog. This is where we turn that from an empty Buymode Catalog Promise to a legit Roomscore Reality. I don't know what the exactly what the forumla is for converting "roomscore contribution" into the 10 point room score rating that we see in the buymode catalog, so, just as I did with weight, I took a look inside of existing decorative objects (sculptures) to find out what room score contribution to use and it turns out that to rate as a "room score 4" object we need to make our room score contribution "70".
Add a final node to our init and, using a literal value on the RHS, make it look like this (pop quiz, baby!) and have it terminate as true.
Now that we've created both of the trees that our object requires, we must assign them to the functions that they were created for. As you learned earlier, just because something has been created and is sitting around inside of our IFF file, doesn't mean the game will automatically use it. The game will only use things when it has a reason to. We must instruct it to use these two trees, which we will do on the ENTRY POINTS tab.
Entry Points (The Functions Table)
Switch to the Entry Points tab and the first two functions you will see listed are init and main. They are highlighted in a mildly alarming red because nothing has actually been listed for these two crucial functions.
Select the init function's line, click the Set Action Tree, and choose the init you have just created (Private: init) and Select init as the Action tree for this function. (NOTE: the select button text changes slightly with the selected tree's name displayed. If you named your init tree something else, that will be displayed on the button instead. And in that case I'll trust you can make that conversion with everything else from here on out, smarty pants!)
Repeat to select your "Private: main" tree as the Action Tree for the main function.
Trees and Resources - Catalog Strings
Now let's finish setting up that buymode catalog. For this we need a "catalog string" which you'll find it further down the list in the drop down menu, below the "Trees" option.
Click New to create your catalog string. Traditionally, these use chunk IDs in the 2000 range, starting with 2000 itself so let's use that. The name can be anything and is usually as the object's internal name. (I confess I'm pretty lazy so I usually just name them "catalog". Don't judge me!)
Highlight your new Catalog String resource to open the Strings editor. A catalog string only needs 2 lines. The first is for the object's name and the second is for the buymode catalog description.
Hit the New String button to create the first one and highlight it. Now you can enter your object's name as it should read in the buymode catalog into the "String" frame to the right. While Volcanic automatically saves your changes in its other editors, it does not do so in the Strings editor. Once you've finished typing your text in, click the Save button to actually save it in the STR resource.
Repeat to add the second line, this time typing in the description that you want displayed in the buymode catalog (don't forget to hit Save again!)
Your catalog string resource is complete, but, once again, the game wont know to use it until you assign it to your object. This is done by highlighting it in the resource list and clicking the Select as My Catalog Strings button. You'll notice the name of the resource turns purple afterward (you may have to click somewhere to effect the change)
Take a Moment to Save Your File
This is a great time to save your file. This is done back on the main Volcanic window on the Resources tab.
These should be the only things listed, but if you were naughty and got distracted and went nosing about in other objects you may find additional "changes" wanting to be saved in other objects. Ignore those. Just check the boxes for the ones for your new object and then click the Save Changes button on the right. Once your saved changes are no longer listed, you can Discard All other changes to make sure you don't mess up the rest of the files you were looking at.
Step Four - Edit your iff some more: Import your art
OK! That is your iff's "function" taken care of. Next we work on its "form" by importing your artwork into the object. This is done in three parts.
- First you import your 2D sprites.
- Next you create Drawgroups and fill those with your sprites.
- Last you import your meshes, associating them with the drawgroups you've created.
Trees and Resources - Sprites
Return to the TREES AND RESOURCES tab if you haven't already and choose "Sprites" from the drop down menu.
Just as you did when you created your Trees and Catalog Strings resources, click the New button to create a SPR resource. Each SPR resource holds 1 complete set of sprites. Label this one whatever you'd like. Just to mix it up a bit I'm going to name mine "vase" instead of the more generic "My First Decor" that I've been using for everything so far. You can actually leave the Chunk ID at 1, but I'm switching mine to 100 out of habit.
Highlight your new SPR resource to switch to the Sprites Editor where we'll import our sprites.
We want to import sprites that have already been made, but the Import and Import All buttons are both greyed out. We need to create placeholder sprites inside of our sprite resource in order to be able to use those buttons and we do this by clicking the New button on the right. We're going to leave "Automatically Generate Medium and Far Zooms checked". This will give us 1/3rd of the work to do. If you ever find yourself unhappy with the quality of the medium and far zooms in a future project, however, remember you can uncheck that and do them all manually.
Now that the Import and Export buttons are enabled, we can import our sprites. Choose Import All and navigate to the folder on your computer that has the sprites set for this SPR resource. In future projects when you work with multi-tiled and animated objects you'll have more than one SPR and so will have more than one set of sprites made, but for this project we have just the one folder.
Even though we only created one sprite (rotation 0) when we clicked the New button earlier, the Import All button imported all of the bmps contained in our folder and, using their file names, figured out which ones belong with what rotation.
Don't be alarmed by the rather rough look of your object. You are looking at only one of three sprites that are used by the game, the "Color" sprite. If you are curious about the other two, you can check them out using the drops down menu below the sprite previews. The other two sprite types are the Alpha (A channel) and Depth (Z-buffer). The A channel smooths those ugly rough edges that you are seeing on the Color sprite, and the Z buffer is how the game fakes a sense of depth when you are playing in 2D.
The SPR resource need to get assigned to drawgroups next so the game can use them properly. To do this we switch to the Appearance tab.
The Drawgroup editor on the Appearances tab uses pluses (+) and minuses (-) to add and remove things rather than "New" and "Delete" buttons, which leaves room for the up (↑) and down (↓) arrow buttons that allow you to rearrange the order of these elements. Add one drawgroup by clicking the + button, then select your new drawgroup and Rename it. (Normally I'd name it "Vase", but here I'm using "Vase graphic" to make it easy to tell the difference between the drawgroup and the sprites in the next few screenshots.)
With the drawgroup still selected, add one sprite using the + button in the "Sprites" frame. A placeholder "sprite" is created for you. Use the Change button to open a window that looks very much like the SPR Editor you used earlier to choose one of your real sprites.
After selecting the SPR you want to use (you do not need to choose a rotation here. That gets done on the next screen), click the Select as Chosen Sprite button to close this window.
Now, back on the Appearance tab, you can see all three sprites working together. Wow, that A channel smoothing those edges makes a mighty big difference! If you have worked on TS1 objects in the past, you'll also notice, to your delight, that Volcanic figured out exactly where to place your object on the tile without you having to fuss with X and Y coordinates. You do still have the option of moving the object manually, should you ever need it, though.
If you are using your own art, you will probably find that your decor isn't facing the way you expect it to. If your object has a front, choose different rotations from the rotation drop down menu until your object is facing toward the lower left corner, otherwise go ahead and choose Rotation 2. If you are using the sprites of my simple little vase, you'll not notice any difference at all since it has no distinguishing features on any side. (So perhaps this wasn't the best object for this project. Hrm)
This takes care of one of your four rotations. Now you have 3 more to do. Recently an "AutoRot" checkbox has been added to Volcanic, but it does not currently work for me so we're just going to ignore it and continue manually. Slide your Rotation slider over one tick, add a place holder sprite ( + ), choose your real SPR, and set the correct rotation. This time you'll want your object facing up and to the left so you are looking at its back. If you are using the example vase sprites, set this one to Rotation 3.
Repeat this twice more for the other two ticks on the slider, rotating your object clockwise as you go. That means choosing rotation 0 for the third tick and rotation 1 for the fourth, if you are using the vase sprites.
Your drawgroup is now complete but, just as with the catalog strings earlier, the game wont know it should be used unless you assign it to your object. The game needs to be told two things for drawgroups. First, it needs to be told which drawgroup to use as its first graphic ("graphic 0"). Do this by selecting your drawgroup and clicking the Set as First button.
The second thing it needs to be told is how many drawgroups should be used. (The answer for this project is "one", of course, but animated objects can have several.) This is done in Volcanic by setting a "last" graphic in the same way a "first" was set and letting Volcanic do the counting. With our one drawgroup still selected, click the Set as Last button
That finishes your 2D artwork and now would be an excellent time to switch back to your main Volcanic window, in the Resources tab and SAVE YOUR FILE again.
3D Debug (FSOMs)
Importing 3D art is done on the 3D Debug tab.
Check the "Save Changes to IFF (FSOM, MTEX)" checkbox and click the Use Custom... button (which will switch it the [Custom Mesh] options. The "Use Reconstruction" button will toggle you back to the [Reconstruction] options.)
With your drawgroup selected, press the Import .OBJ button and navigate to the project folder on your computer that has the model you want to use and select it.
Your object might not look quite as good as you'd hoped at this point, but reserve judgment until you've seen it in-game where the lighting is very different.
Remember to Save Changes again.
Now we can check it out in the game and make sure everything is working as expected.