Custom Object tutorial/File structure

From SRB2 Wiki
Jump to navigation Jump to search
  Custom Object tutorial [view]

Chapter 1: Basic knowledgeChapter 2: File structureChapter 3: Syntax issues and conventionsChapter 4: Creating an enemyChapter 5: Sounds and spritesChapter 6: Advanced techniques

Now we have learned what SOCs consist of, but we haven't yet learned how they are constructed. To do that, we will take a look at a typical SOC file.

Creating an example

Let's look at an example of a state and of an Object type in a SOC file. Create a new SOC file, open it in Notepad and paste the following text into it:

State S_POSS_RUN1
SpriteName = POSS
SpriteFrame = A
Duration = 3
Next = S_POSS_RUN2
Action = A_Chase
Var1 = 0
Var2 = 0

Object MT_BLUECRAWLA
MapThingNum = 100
SpawnState = S_POSS_STND
SpawnHealth = 1
SeeState = S_POSS_RUN1
SeeSound = sfx_None
ReactionTime = 32
AttackSound = sfx_None
PainState = S_NULL
PainChance = 200
PainSound = sfx_None
MeleeState = S_NULL
MissileState = S_NULL
DeathState = S_XPLD1
XDeathState = S_NULL
DeathSound = sfx_pop
Speed = 3
Radius = 24*FRACUNIT
Height = 32*FRACUNIT
DispOffset = 0
Mass = 100
Damage = 0
ActiveSound = sfx_None
Flags = MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE
RaiseState = S_NULL

What you see here is a part of the SOC language. When the SOC file is loaded into the game, it will read from top to bottom and left to right through this text and apply the given parameters.

States

  • State S_POSS_RUN1: This is the header for the state block. S_POSS_RUN1 is the name of the state that this block will modify. In our case, this is the first state of the blue Crawla's running animation. Note that this is a state that already exists in SRB2. Had we used a name that does not correspond to a state in SRB2, we would have needed to declare it in the freeslot block first, to allow SRB2 to associate it with a state slot. Since we chose to modify an existing Object, all parameters that we set in this block will overwrite SRB2's default values when we load the SOC, and we would see a difference in the blue Crawla's behavior. States always begin with a S_ prefix.
  • SpriteName: This is the name of the sprite set the Object displays as long as this state lasts. In our case this is POSS, the sprite set for the blue Crawla. The names for sprite sets always have four letters. Each sprite set consists of multiple frames. The Sonic sprite set for example has one frame for its standing animation and a set of frames for its walking animation.
  • SpriteFrame: This defines which frame of the sprite set should be shown. In our case this is frame A, the first frame of the set.
  • Duration: This controls how long the state should last. The time unit is "tics". A second consists of 35 tics, so one tic is 1/35th of a second. In our case, this is set to 3, so the state will last about a tenth of a second.
  • Next: This indicates which state will follow after the Duration has passed. In our case, this is S_POSS_RUN2. If you set it to S_NULL, nothing will happen after this state is complete. You can also set states to loop back to themselves.
  • Action: This is where things become interesting. As mentioned in the last chapter, actions are functions that control what the Object does during the state, so whenever you want your Object to do something, no matter what, you'll need to use these. Furthermore, an action is executed only once per state and at the start of the state (during its first tic). There are over 100 different actions programmed into SRB2. Except for "None" (meaning no action at all should be performed), they all start out with the prefix "A_", followed by the action's name. In our case, this is A_Chase. This is a very basic enemy thinker that (each time it is called) forces the Object to make one step into its target's direction. The target of the Object was set by another action in a state that was called before this one, and is the player in this case. Now you know why the Duration value was so short. Since all the Object does is make a step, the state doesn't need to be long. To look up how many actions there are, what they do and how they work, see the Actions article.
  • Var1 and Var2: These are variables that are used by some actions for additional parameters. They have a different meaning depending on which action you call. A_Chase does not need any additional parameters. This is why both values are set to 0 here (changing them has no effect).

This is what state blocks look like. But what about Objects? Let's move on to the next text block.

Object types

  • Object MT_BLUECRAWLA: This is the header for the Object type block. MT_BLUECRAWLA is the name of the Object type that this block will modify. In our case, this is – as the name tells us – the blue Crawla. Object type names always begin with a MT_ prefix.
  • MapThingNum: This number is used by map editors to refer to this Object type. This sets the Thing type that this Object type can be placed with on a map. It can be set to any random number as long as it's not already reserved. Later on, when you create a level with your first own enemy, you'll need to place a Thing on the map that uses this number as its type ID. If you don't want your Object to be placed as a Thing, set this value to "-1" or omit it. Maximum is 4095.
  • SpawnState: This is the state that will be called at the time when the Object is spawned. Most enemies start off with a state (S_POSS_STND in our example) that loops back to itself and constantly executes A_Look. This action tells the Object to sit and wait until it sees a player. Then it will change its target to this particular player and call the SeeState. Note that the first time the SpawnState is called, its action is usually not executed. However, since in our case the state loops back to itself, it will start being executed shortly afterwards when the state is called for the second time.
  • SpawnHealth: These represent the Object's health points. If an Object gets attacked, its life points will decrease by one for each tic the harming contact lasts. Crawlas have this set to 1, since they will be destroyed by one hit.
  • SeeState: This is the state the Object will call if it detects a player through A_Look. In our example, this is S_POSS_RUN1, the same state that our first text block represents. Now you should get a grasp of how the Crawla behaves: Upon spawning, it looks out for a player until it finds one, and then chases this player.
  • SeeSound: This is the sound that will be played if an Object sees a player through A_Look. Since the blue Crawla plays no sound upon detecting a player, this is set to sfx_None. The playback of this sound is optional, and can be turned on or off by A_Look's Var2. Similar to other sounds, this may also be called by other actions, but it mainly executes when the SeeState is called.
  • ReactionTime: This is relevant for various purposes and specific to an Object's thinker/actions. Usually, you can ignore it.
  • AttackSound: This is the sound that is played when certain actions are used. Usually, set it to sfx_None and ignore it.
  • PainState: This state will be called every time the Object is attacked, except if its SpawnHealth reaches 0. Since the blue Crawla only has one health point, this state is unused and therefore set to S_NULL.
  • PainChance: This is relevant for various purposes and specific to an Object's thinker/actions. Usually, you can ignore it.
  • PainSound: This is the sound that will be played when an Object uses A_Pain or the PainState is called.
  • MeleeState and MissileState: These states are used as attack patterns by some of the more complex enemies, as well as bosses. Usually, you can ignore them.
  • DeathState: This state will be called if the Object's SpawnHealth reaches 0, which means the Object dies. In the blue Crawla's case, this is S_XPLD1, a generic state that is used by all dying enemies.
  • XDeathState: This State is used for various purposes, most notably for bosses. Usually, you can ignore it.
  • DeathSound: This is the sound that will be played when an Object uses A_Scream or the DeathState is called. In our case, it is the popping sound, sfx_pop.
  • Speed: This defines the movement speed of the Object. In our case, 3 as a value means that the Object will cover a distance of 3 fracunits with each step it makes.
  • Radius and Height: Keeping in mind that an Object's animation consists of 2D sprites, its actual 3D size obviously has to be defined by something else. This is done with these two values. Each Object in SRB2 has a cuboid shape whose distance from its center to the center of each of its sides is Radius, and whose height is Height. You will notice that in our example, both values are multiplied by FRACUNIT. FRACUNIT is a special constant that represents the number 65536. This is necessary because internally, the game uses a very precise length measuring that allows for very small adjustments. One fracunit equals 65536 of these very small units, so to give to Object a size that makes sense, you have to convert the value to fracunits. This is what the FRACUNIT constant does.
  • DispOffset: This value is used to draw certain sprites in front of others when they are in the same location. Usually, you can ignore it.
  • Mass: This is used internally by the game for various purposes. It has no relation whatsoever with the Object's heaviness. Usually, you can ignore it.
  • Damage: This is relevant for various purposes and specific to an Object's thinker/actions. Usually, you can ignore it.
  • ActiveSound: This is a sound that is played when certain actions are used. Usually, you can ignore it.
  • Flags are a series of variables that define the general properties of the Object. In our case, the Object has three flags: MF_ENEMY means that the Object is an enemy. MF_SHOOTABLE means that it can be hurt by attacks. MF_SPECIAL means that the player can interact with the Object by touching it. There are numerous other flags that an Object can have; look at the Object flags article for a complete lists. You will see that the flag names are separated by the "|" character. This is necessary because internally, the game stores the flags as a single 32-bit number, where every bit stands for one flag: If the bit is 0, the flag is disabled, if it is 1, the flag is enabled. Just as with Object/state/sprite/sound names, the game recognizes the flag names and automatically converts them to the corresponding flag values. The "|" character tells the game to calculate the bitwise OR function, which is needed to add the flags together.
  • RaiseState: This state is used for various purposes, most notably for dropping Objects. Usually, you can ignore it.
  Custom Object tutorial [view]

Chapter 1: Basic knowledgeChapter 2: File structureChapter 3: Syntax issues and conventionsChapter 4: Creating an enemyChapter 5: Sounds and spritesChapter 6: Advanced techniques