Custom Object tutorial/Basic knowledge
|Custom Object tutorial||[view]|
Before we start actually making a SOC, we need to know what we are talking about. This requires a bit of theory. We need to ask ourselves a few questions:
- What is SOC?
- What are Objects and how do they work?
- How can I create a SOC file?
In this section, you will learn the answers to these questions, so that you are equipped with the basic knowledge you need to create your own SOCs.
SOC stands for Sonic Object Configuration. It is a so-called "content definition language". What this means is that it allows you to modify and add data that is used in the game without having to edit its source code. SOC can modify and create a wide variety of data, such as level headers, cutscenes, unlockables and emblems, but the type of data we will be looking at here – and the one that SOC gets its name from – are Objects.
To create or modify data with SOC, you simply create a text file that lists all the data you want to create or modify in a specific format. This text file is called a SOC script or simply a SOC. If you add this file to the game, SRB2 will read the data within it and add it to the game. This allows you to modify the game without knowing anything about coding or programming at all.
An Object is basically any kind of item that exists in a map but isn't part of the level geometry, e.g., the sectors, linedefs and vertices that form the layout of the map. For example, the player is an Object, an enemy or a boss is an Object, rings and monitors are Objects, a missile is an Object, all scenery Things are Objects. Note that Objects are not the same as Things. Things are what you use to place Objects in a map. Most Objects also have a corresponding Thing. For example, a ring is both a Thing and an Object. Some Objects, however, don't have Things: The player is an Object, but not a Thing, since you cannot place players on the map in a level editor. Missiles shot by enemies are also Objects, but not Things. Likewise, there are a few Things that have no corresponding Objects, such as player starts.
Another important distinction you need to know about is between Objects and Object types. Object types group Objects that have the same general appearance and behavior together. For example, the blue Crawla is an Object type, but each individual blue Crawla in GFZ1 is its own Object. The Object type "Blue Crawla" tells the game the basic properties of blue Crawlas, e.g. which sprites it uses, that it slowly chases towards the player, and so forth. Each invididual blue Crawla is an instance of this Object type, i.e., it looks and behaves just as outlined by the Object type. However, different Crawlas can be in different states of their animation at the same time; they can be at different positions in the map, facing in different directions, and so forth.
What we want to do here is define a new Object type. We want to tell the game which sprites our Object should use and how it should behave in certain situations. Then, when we place instances of our Object type in a map, they will behave just as outlined in our Object type definition.
States, sprites, actions and sounds
The appearance and behavior of Objects is controlled through states. Each state is a small sub-unit that controls how the Object looks and behaves for a given time. Once that time is over, the Object changes to another state. Certain states are called by the Object when certain events happen, and then further states can be called by the states themselves. To breathe life into an Object, we usually make it cycle through a sequences of multiple states.
The appearance of the Object is set through sprites, which are just graphics that Objects display. Each Object type typically has its own sprite set, which consists of all the sprites that it can display. In each state, the Object displays a certain frame from its sprite set. Since Objects can be viewed from different angles, each frame in turn consists of multiple rotations that show the Object from different angles.
The behavior of the Object is set through actions. An action is a special function in the source code that tells the game what the Object should do during the current state. By calling an action in a state, we can make the Object do something. However, when using only SOC, we are limited to the actions that are provided with SRB2. If we want the Object to do something else that isn't possible with any of available actions, we have to use Lua scripting to create new actions.
Finally, sounds are just what the name suggests: sound effects. Objects have a few different slots for sounds that they can play when certain actions are performed.
Slots and freeslots
There is a limit to the number of Object types, states, sprites and sounds that can exist in the game. For each of these four types, there is a limited number of slots that can be occupied. For example, there are exactly 673 Object type slots in the game. Of these, 417 are reserved for SRB2's own Object types. The rest are freeslots. They are empty by default and unused in unmodified SRB2, but they can be occupied by custom Object types. Correspondingly, states, sprites and sounds also have a fixed number of available slots, of which some are occupied by default and others are freeslots.
The slots themselves are numbered, but to make SOCs easier to read, the slots are never actually referred to by number. Instead, each slot is associated with the name of the Object type/state/sprite/sound that occupies it. For example, Object type slot 3 is occupied by
MT_PLAYER, the Object type for the player. Whenever you need to refer to the player Object type in a SOC, you could use its slot number (3) to represent it. However, this would make the SOC harder to read, and you would have to look up the number of each Object type, state, sprite or sound every time you refer to it. Therefore, what you would actually do in a SOC is use the Object's name,
MT_PLAYER, to refer to it. The game will then automatically convert the name back to the associated slot number and find the corresponding Object type for you.
Things become slightly more complicated when using freeslots. Because freeslots are empty by default, there is no Object type/state/sprite/sound name to associate the slot with. Therefore, when using freeslots, you must first define a name for your Object type/state/sprite/sound. This is done in a separate section of your SOC called the freeslot block. How such a freeslot block looks will be explained later. When you load the SOC, the game will then go through the freeslot block and assign each entry to the first unused freeslot it can find. This allows you to refer to custom Object types/states/sprites/sounds by name instead of number, just like with Object types/states/sprites/sounds that are in the game by default.
The advantage of this method is that the game only decides which entries are associated with which slots when the SOC is loaded, making the SOC itself independent of which slots are actually occupied. For example, if the next version of SRB2 adds new Objects (which it probably will), your custom Objects will still work because the game will simply load them into different slots than before. Likewise, if you add multiple SOCs at once, they will not conflict with each other (unless they have Object types/states/sprites/sounds that share the same name) because the entries will simply be loaded into whichever slots are available.
SOC creation and implementation
Writing a SOC file is easy, because it consists of plain text. The next chapter will show how this text is formatted. But first you need to know how to create a new SOC file. First of all, assuming you are using Windows as your operating system, make sure you enabled "Show complete filename" inside your folder options. If you did, all filenames will be shown with their filename extensions, such as "srb2win.exe" or "test.txt". Now, create a new text document of the type ".txt". After doing so, rename it so that its filename extension changes to ".soc" (for example "myfirstobj.soc"). Now you will probably see Windows alerting you that the file type will be changed and that information might get lost. Ignore this warning.
Our file now changed its icon, indicating that Windows does not know which program should open the file. Right-click on it and choose "Open with". Now scroll through the programs and select Notepad. Make sure to check the "Open data type every time with this program" box. Now we created a SOC file and made sure every new SOC file we create will be opened with Notepad.
To use a bare SOC file in-game, put it into your SRB2 main folder. You can then add the SOC to the game via the Addons menu or by opening the console and typing in
addfile [filename].soc. To implement a SOC script into a WAD or PK3 file, you need a lump editor like SLADE. Create a new text lump and paste your code into it. If you are using a PK3 file, you need to put your SOC lump in the
SOC/ folder to make the game recognize it. If you are using a WAD file, the lump's name must start with
SOC_, or be
|Custom Object tutorial||[view]|