Post tutorial RSS Doom Source Code tutorial 7

In this article we will show how easy it is to make changes to weapons' states and functions from within the source code.

Posted by on - Basic Client Side Coding

Doom Source Code tutorial 7
Game:
Doom or Doom2
Level: Basic.
Objective: modify the States data from within the source code.
Resources required:
VC++ 2008 Express Edition; source code for Doom (tested with Doomsday ver 1.9.0-beta6.9).
Introduction:
In previous tutorials we modified the chain gun and the shotgun by making changes to the States of these weapons in the objects.ded definitions file using just a text editor .While this method was very simple and served its purpose, we did also outline the disadvantages associated with this technique and why it was not recommended to modify the defs files directly. In this session we will re-create those changes inside our jDoom.dll using real source code. As we stated earlier, the values and data in these definitions files are loaded by the engine when doom starts up and so it is possible to just consider them as initial values. Doom can be programmed to ignore these and replace them dynamically with other chosen values instead. This will perfectly serve our purposes for creating mods to weapons and monsters and we no longer have to worry about attaching a specially modified ded file with our projects. Note this one will not apply to Chocolate doom as all of the defs data are already contained in a C file (info.c) that has to be compiled with the rest of source code anyway.
Procedure:
1. The first thing we want to look at before we set off is how things and states in the objects.ded file are handled. You may remember from previous work, we mentioned that all entries in this file are placed in a very strict order. This is because the engine accesses these data in a very strict sequence using a numeration system. That is, states can be linked to each other using an enumeration registered in a header file called info.h. You have here 973 entries corresponding to the states in the objects.ded file we examined in a previous article. The sequential data are serialized in a long list to identify each state relating to every map object in the game be it a weapon, monster or static item. The dot operator can be used to access the members and data in each State in the game code. Let's examine a portion for the enumeration of the "statenum" structure in this header file, info.h, for the chain gun ,shown in red:

S_CHAIN, // 049
S_CHAINDOWN, // 050
S_CHAINUP, // 051
S_CHAIN1, // 052
S_CHAIN2, // 053
S_CHAIN3, // 054
S_CHAINFLASH1, // 055
S_CHAINFLASH2, // 056

As you can see from the type definition declaration above each state entry begins with S and you can see the equivalent serial number for it on the right hand column. So you have the choice here of using either the figures or the labels when writing your code. But of course being humans we always opt for names not some ambiguous numeral .It is the very purpose of this list anyway.

2. Next we need to "analyze" the structure of the States for our example. First here is the type definition of the relevant state structure:

typedef struct state_s
{
int sprite;
int frame;
int tics;
acfnptr_t action;
int nextState;
int misc[NUM_STATE_MISC];
int flags;
} state_t;

Compare this with the chain gun states below. The order of the members within the structure is not important and you may notice some entries are missing. Do not worry about that for the time being.

State {
ID = "CHAIN1";
Sprite = "CHGG";
Frame = 0;
Tics = 4;
Action = "A_FireCGun";
Next state = "CHAIN2";
}

State {
ID = "CHAIN2";
Sprite = "CHGG";
Frame = 1;
Tics = 4;
Action = "A_FireCGun";
Next state = "CHAIN3";
}

3. So in order to access the data in this structure from within C code we use the definition STATES (yes it is an array) and the dot operator. So if we want to change the tics value for the chain gun from 4 to 1 for example, we do it this way:

from this :
STATES[S_CHAIN1].tics = 4;
to this:
STATES[S_CHAIN1].tics = 1;

And to change the action function used for a particular weapon; we would use a different function pointer in the same way, here we will replace the chain gun firing function to that of the normal shotgun:

STATES[S_CHAIN1].action = A_FireShotgun;

Do not forget your semi-column at the end as you are writing C code now!
Using this method you are now able to access and manipulate any value in the defs files and change them at will from inside the source code; so easy and neat!

4. Let's do a practical exercise. We will now repeat the shotgun modification we did in tutorial 5 using this method. For this we need to open the file "g_game.c" to initialize these values.Go to a suitable place near line 2170 as shown below and enter the code shown in red ,to set all the re-loading frame tics to 0:

#endif

STATES[S_ SGUN3].tics = 0;
STATES[S_ SGUN4].tics = 0;
STATES[S_ SGUN5].tics = 0;
STATES[S_ SGUN6].tics = 0;
STATES[S_ SGUN7].tics = 0;
// Fast missiles?
#if __JDOOM__ || __JHERETIC__ || __JDOOM64__
# if __JDOOM64__
speed = fastParm;
# elif __JDOOM__
speed = (fastParm || (skill == SM_NIGHTMARE && gameSkill != SM_NIGHTMARE));
# else
speed = skill == SM_NIGHTMARE;
# endif
for(i = 0; MonsterMissileInfo[i].type != -1; ++i)
{
MOBJINFO[MonsterMissileInfo[i].type].speed =
MonsterMissileInfo[i].speed[speed];
}
#endif
// <-- KLUDGE

Of course if you have a large number of states that you need to change , you want your code to look tidier and more professional, so replace your code with a loop like this:

for (i = S_SGUN3; i <= S_SGUN7; ++i)
STATES[i].tics = 0;

As an extra exercise,let's also change the action function pointer to that of the super shotgun, but pay attention to the fact that this will only work for doom2 as the sound for this weapon is not available in Doom 1. If you don't want to hear this advise then you will not hear any sound when you fire your gun! Copy and paste the following line right after the code above:

STATES[S_SGUN2].action = A_FireShotgun2;
Your final mod code should look like this:

for(i = S_SGUN3; i <= S_SGUN7; ++i)
STATES[i].tics = 0;
STATES[S_SGUN2].action = A_FireShotgun2;

I hear you say you want another example? OK, just use the above code for the chain gun but this time we'll replace the names with their corresponding numbers instead just to prove the point:

STATES[52].tics = 1;
STATES[53].tics = 1;
STATES[52].action = A_FireShotgun;
STATES[53].action = A_FireShotgun;

I am sure you got the picture by now. In the next tutorial we will apply this technique again when we study our enemies.
Bye for now.
Return to Tutorials Page.
Adam.

Post a comment
Sign in or join with:

Only registered members can share their thoughts. So come on! Join the community today (totally free - or sign in with your social account on the right) and join in the conversation.