Sign in to follow this  
Followers 0

Game logic/behaviour documentation

Hi,
I am not a programmer... just did graphics, some maps for quake, some modeling, sounddesign and a bit of scripting.

I would like to take a closer look at the doom "AI", Monster behavior etc. and possibly play around a bit with it.

Does anyone have a recommendation where I should begin?

I do NOT intend to learn how to code an engine ; )
All I want is to understand how the gamelogic/behaviour "ticks" and try what happens if I change certain things...

Any ideas where I could start at?

Thanks

Share this post


Link to post

I'd say starting from the Doom source code (or that of any port reasonably close to it, e.g. prBoom or Chocolate Doom) and study the p_ modules. There are no shortcuts to this process, and you will learn how to code an engine until you get there.

Share this post


Link to post

ok, thanks......
which of the ports - I don't care if it's outdated in terms of graphics - has the "best" documentation?


found this in the doom wiki....
"The original plan for the source code release involved a book Kreimeier was to write on the Doom engine; however, due to Doom's decreasing relevance in the gaming community, it was eventually judged not to be a marketable idea, and the project was abandoned."

does anyone know if something similar was ever released?

Share this post


Link to post

The AI in DOOM is a basic state machine, at any one time a monster is in a particular state (such as "spawn" state at start of map), and usually cycles to the next state after a short time, and eventually around in a loop. Each state also decides the sprite frame to use to draw the monster.

When a new state is entered, the monster can perform an action, such as A_Look to look for players to attack, or A_Chase to move the monster in the general direction of the player (and maybe perform an attack too).

These actions can cause state changes too, if the A_Look action sees a player then the monster go from "spawn" state to "chase" states where it uses the A_Chase action to chase and attack the player. Other events also cause a state change, shooting a monster will make it enter its "pain" states, and killing it makes it enter its "death" states.

The more interesting stuff is in the code for actions like A_Chase. The p_enemy.c file in the code has most of them.

Share this post


Link to post

If you're not a programmer, I'd recommend that you *not* start by looking at the code - instead, start by experimenting with Dehacked, playing with the state tables and seeing how the monsters progress from one state to the other and different behaviors are triggered. That will provide a much more accessible way to learn how things work, and you can even experiment with changing things without the hassle of having to set up a compiler. Then, once you've learnt enough of that, and if you're curious, dig down into how the code works.

Share this post


Link to post

I'd suggest you look on the ZDoom wiki. Go to the Doom actors page, look one of them up, and there you go. You'll see in the DECORATE code a streamlined, much easier to understand depiction of the original state tables; and you can click on any of the codepointers (the A_* functions like A_Chase) to see its documentation.

Share this post


Link to post

Thanks a lot. Those were ALL very helpful hints! ; )

Share this post


Link to post

Perfectly valid nevertheless.

This is the code for the cacodemon's states in Doom's source code:

    {SPR_SARG,0,10,{A_Look},S_SARG_STND2,0,0},	// S_SARG_STND
    {SPR_SARG,1,10,{A_Look},S_SARG_STND,0,0},	// S_SARG_STND2
    {SPR_SARG,0,2,{A_Chase},S_SARG_RUN2,0,0},	// S_SARG_RUN1
    {SPR_SARG,0,2,{A_Chase},S_SARG_RUN3,0,0},	// S_SARG_RUN2
    {SPR_SARG,1,2,{A_Chase},S_SARG_RUN4,0,0},	// S_SARG_RUN3
    {SPR_SARG,1,2,{A_Chase},S_SARG_RUN5,0,0},	// S_SARG_RUN4
    {SPR_SARG,2,2,{A_Chase},S_SARG_RUN6,0,0},	// S_SARG_RUN5
    {SPR_SARG,2,2,{A_Chase},S_SARG_RUN7,0,0},	// S_SARG_RUN6
    {SPR_SARG,3,2,{A_Chase},S_SARG_RUN8,0,0},	// S_SARG_RUN7
    {SPR_SARG,3,2,{A_Chase},S_SARG_RUN1,0,0},	// S_SARG_RUN8
    {SPR_SARG,4,8,{A_FaceTarget},S_SARG_ATK2,0,0},	// S_SARG_ATK1
    {SPR_SARG,5,8,{A_FaceTarget},S_SARG_ATK3,0,0},	// S_SARG_ATK2
    {SPR_SARG,6,8,{A_SargAttack},S_SARG_RUN1,0,0},	// S_SARG_ATK3
    {SPR_SARG,7,2,{NULL},S_SARG_PAIN2,0,0},	// S_SARG_PAIN
    {SPR_SARG,7,2,{A_Pain},S_SARG_RUN1,0,0},	// S_SARG_PAIN2
    {SPR_SARG,8,8,{NULL},S_SARG_DIE2,0,0},	// S_SARG_DIE1
    {SPR_SARG,9,8,{A_Scream},S_SARG_DIE3,0,0},	// S_SARG_DIE2
    {SPR_SARG,10,4,{NULL},S_SARG_DIE4,0,0},	// S_SARG_DIE3
    {SPR_SARG,11,4,{A_Fall},S_SARG_DIE5,0,0},	// S_SARG_DIE4
    {SPR_SARG,12,4,{NULL},S_SARG_DIE6,0,0},	// S_SARG_DIE5
    {SPR_SARG,13,-1,{NULL},S_NULL,0,0},	// S_SARG_DIE6
    {SPR_SARG,13,5,{NULL},S_SARG_RAISE2,0,0},	// S_SARG_RAISE1
    {SPR_SARG,12,5,{NULL},S_SARG_RAISE3,0,0},	// S_SARG_RAISE2
    {SPR_SARG,11,5,{NULL},S_SARG_RAISE4,0,0},	// S_SARG_RAISE3
    {SPR_SARG,10,5,{NULL},S_SARG_RAISE5,0,0},	// S_SARG_RAISE4
    {SPR_SARG,9,5,{NULL},S_SARG_RAISE6,0,0},	// S_SARG_RAISE5
    {SPR_SARG,8,5,{NULL},S_SARG_RUN1,0,0},	// S_SARG_RAISE6


    {		// MT_SERGEANT
	3002,		// doomednum
	S_SARG_STND,		// spawnstate
	150,		// spawnhealth
	S_SARG_RUN1,		// seestate
	sfx_sgtsit,		// seesound
	8,		// reactiontime
	sfx_sgtatk,		// attacksound
	S_SARG_PAIN,		// painstate
	180,		// painchance
	sfx_dmpain,		// painsound
	S_SARG_ATK1,		// meleestate
	0,		// missilestate
	S_SARG_DIE1,		// deathstate
	S_NULL,		// xdeathstate
	sfx_sgtdth,		// deathsound
	10,		// speed
	30*FRACUNIT,		// radius
	56*FRACUNIT,		// height
	400,		// mass
	0,		// damage
	sfx_dmact,		// activesound
	MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL,		// flags
	S_SARG_RAISE1		// raisestate
    },

It's in two different places in the info.c, and you have to refer to the lower part (the mobj declaration) to see how the states are attached.

The same code on the ZDoom wiki:
ACTOR Demon 3002
{
  Game Doom
  SpawnID 8
  Health 150
  PainChance 180
  Speed 10
  Radius 30
  Height 56
  Mass 400
  Monster
  +FLOORCLIP +FASTER +FASTMELEE
  SeeSound "demon/sight"
  AttackSound "demon/melee"
  PainSound "demon/pain"
  DeathSound "demon/death"
  ActiveSound "demon/active"
  Obituary "$OB_DEMONHIT" // "%o was bit by a demon."
  States
  {
  Spawn:
    SARG AB 10 A_Look
    Loop
  See:
    SARG AABBCCDD 2 A_Chase
    Loop
  Melee:
    SARG EF 8 A_FaceTarget
    SARG G 8 A_SargAttack
    Goto See
  Pain:
    SARG H 2
    SARG H 2 A_Pain
    Goto See
  Death:
    SARG I 8
    SARG J 8 A_Scream
    SARG K 4
    SARG L 4 A_NoBlocking
    SARG M 4
    SARG N -1
    Stop
  Raise:
    SARG N 5
    SARG MLKJI 5
    Goto See
  }
}
In addition, in ZDoom, everything is in the actor declaration. Those FASTER and FASTMELEE flags? In vanilla Doom, they don't exist, you have to grep through the source code for "MT_SERGEANT" to find out the parts that they refer to. The state table and mobj declarations are not enough, you also have to analyze common interaction functions to discover things such as why revenants prefer to punch you, or why archviles aren't retaliated against, etc.

Which one is the most legible, especially for a non-programmer?

Share this post


Link to post
Gez said:

Which one is the most legible, especially for a non-programmer?


In my opinion and in this particular case... the Zdoom version.
Since it's almost completely human (non-coder) readable text....


btw.. meanwhile I gathered some Dehacked info since it indeed seemed to be the simplest way to get a feeling for it.... but from what I've found so far it's too limited for the stuff that I want to look into.

Share this post


Link to post

If you are up to it, and surprised nobody has mentioned this yet, EDGE has extensive documentation on that ports' implementation (DDF) of monster/weapon states, etc. And it's n00b friendly.

Something I'll get around to in the next release of 3DGE is updating that document to fit with current 1.35+ standards. However, you can see it's very easy to read as well, and doesn't take as long as DECORATE does to jump into and start editing.

Same code of a Pinky that Gez posted, in Things.DDF:

[DEMON:3002]
SPAWNHEALTH=150;
REACTION_TIME=0.23;
RADIUS=30;
HEIGHT=56;
SPEED=10;
FAST=2;
MASS=400;
PAINCHANCE=70%;
SPECIAL=COUNT_AS_KILL,SOLID,CLIMBABLE,SHOOTABLE;
CASTORDER=6;
CAST_TITLE=DemonName;
BLOOD=BLOOD;
RESPAWN_EFFECT=RESPAWN_FLASH;
ACTIVE_SOUND=DMACT;
DEATH_SOUND=SGTDTH;
PAIN_SOUND=DMPAIN;
SIGHTING_SOUND=SGTSIT;
STARTCOMBAT_SOUND=SGTATK;
CLOSE_ATTACK=DEMON_CLOSECOMBAT;

STATES(IDLE)=SARG:A:10:NORMAL:LOOKOUT,
             SARG:B:10:NORMAL:LOOKOUT;

STATES(CHASE)=SARG:A:2:NORMAL:CHASE,
              SARG:A:2:NORMAL:CHASE,
              SARG:B:2:NORMAL:CHASE,
              SARG:B:2:NORMAL:CHASE,
              SARG:C:2:NORMAL:CHASE,
              SARG:C:2:NORMAL:CHASE,
              SARG:D:2:NORMAL:CHASE,
              SARG:D:2:NORMAL:CHASE;

STATES(MELEE)=SARG:E:8:NORMAL:FACETARGET,
              SARG:F:8:NORMAL:FACETARGET,
              SARG:G:8:NORMAL:CLOSE_ATTACK,
              #CHASE;

STATES(PAIN)=SARG:H:2:NORMAL:NOTHING,
             SARG:H:2:NORMAL:MAKEPAINSOUND,
             #CHASE;

STATES(DEATH)=SARG:I:8:NORMAL:NOTHING,
              SARG:J:8:NORMAL:MAKEDEATHSOUND,
              SARG:K:4:NORMAL:NOTHING,
              SARG:L:4:NORMAL:MAKEDEAD,
              SARG:M:4:NORMAL:NOTHING,
              SARG:N:-1:NORMAL:NOTHING;

STATES(RESPAWN)=SARG:N:5:NORMAL:NOTHING,
                 SARG:M:5:NORMAL:NOTHING,
                 SARG:L:5:NORMAL:NOTHING,
                 SARG:K:5:NORMAL:NOTHING,
                 SARG:J:5:NORMAL:NOTHING,
                 SARG:I:5:NORMAL:NOTHING,
                 #CHASE;

STATES(GIB)=POL5:A:-1:NORMAL:PLAYSOUND(CRUSH);
The Things.DDF links to others, like ATTACKS and WEAPONS.

DECORATE keeps this all contained in one file (as far as I know), which I suppose the 'advantage' comes from. Still, I find this [DDF] method easier IMO because it seperates these definitions into multiple files so you have a generally better idea of what you're looking for when you start modding (things, weapons code, sound code, etc).

Share this post


Link to post
Chu said:

DECORATE keeps this all contained in one file (as far as I know), which I suppose the 'advantage' comes from. Still, I find this [DDF] method easier IMO because it seperates these definitions into multiple files so you have a generally better idea of what you're looking for when you start modding (things, weapons code, sound code, etc).



Not correct.

DECORATE supports #include and if you have a look at the ZDoom definitions you'll find quite a large number of definition files.

You can put everything in one file but you don't have to.

Share this post


Link to post
Graf Zahl said:

Not correct.

DECORATE supports #include and if you have a look at the ZDoom definitions you'll find quite a large number of definition files.

You can put everything in one file but you don't have to.


Ah, I stand corrected. I haven't looked at anything Z in awhile - the WADS I've seen had all the DECORATE self-contained.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0