MCS' Coding Tips
                 "Success!"



  
Adding a new enemy

   Written by MCS
   Tested by Wolf Skevos-Jones

   
Main Page

News

Wolfenstein 3D
Texture Library


MCS' Coding
Tips - "Success"!


Utilities

Spear
Resurrection


Wolfendoom

Wolf
Collection


Original Wolf 3D

Doom/Duke
maps


Other Stuff

Links

Questions?
Email us!
Adding a new enemy means quite a lot of work. To cover all viewing angles in both standing, patrolling and attacking modes, as well as the death sequence animation, you'll need at least 44 new sprites.
In this example, we're going to add the "space marine" sprite from AReyeP's Wolfendoom (available via the left-hand link) to the standard Wolf source and data files. Remember, it's only an example, I'm not encouraging you to steal Steve's graphics :-)

First of all, you'll have to import all the new sprites into the VSWAP using FloEdit. If you're not familiar with this, please read Flo's helptext on this subject carefully. Keep in mind that it's very important to insert the sprites in the right order, or you will get some strange results later on. For this demonstration, this means that you have to extract the Space Marine sprites out of Wolfendoom (FloEdit index numbers 50 up to 98).

IMPORTANT: In order to avoid the infamous "Abnormal Program Termination" error message, you'll need to free up some memory first. Please refer to the appropriate tutorial in the Codingtips section if this applies to you.

Now we'll add the necessary coding modifications step by step. We'll use the following colors to determine between the various actions:

Blue lines:       lines to locate
Yellow lines:   lines to add or modify


1. Adding definitions to WL_DEF.H

Locate this block:

SPR_CHAINREADY,SPR_CHAINATK1,SPR_CHAINATK2,SPR_CHAINATK3,
  SPR_CHAINATK4,

 
Add these lines below:

//
// space marine
//
  SPR_SPC_S_1,SPR_SPC_S_2,SPR_SPC_S_3,SPR_SPC_S_4,
  SPR_SPC_S_5,SPR_SPC_S_6,SPR_SPC_S_7,SPR_SPC_S_8,

  SPR_SPC_W1_1,SPR_SPC_W1_2,SPR_SPC_W1_3,SPR_SPC_W1_4,
  SPR_SPC_W1_5,SPR_SPC_W1_6,SPR_SPC_W1_7,SPR_SPC_W1_8,

  SPR_SPC_W2_1,SPR_SPC_W2_2,SPR_SPC_W2_3,SPR_SPC_W2_4,
  SPR_SPC_W2_5,SPR_SPC_W2_6,SPR_SPC_W2_7,SPR_SPC_W2_8,

  SPR_SPC_W3_1,SPR_SPC_W3_2,SPR_SPC_W3_3,SPR_SPC_W3_4,
  SPR_SPC_W3_5,SPR_SPC_W3_6,SPR_SPC_W3_7,SPR_SPC_W3_8,

  SPR_SPC_W4_1,SPR_SPC_W4_2,SPR_SPC_W4_3,SPR_SPC_W4_4,
  SPR_SPC_W4_5,SPR_SPC_W4_6,SPR_SPC_W4_7,SPR_SPC_W4_8,

  SPR_SPC_PAIN_1,SPR_SPC_DIE_1,SPR_SPC_DIE_2,SPR_SPC_DIE_3,
  SPR_SPC_PAIN_2,SPR_SPC_DEAD,

  SPR_SPC_SHOOT1,SPR_SPC_SHOOT2,SPR_SPC_SHOOT3,

};

Next block:

fakeobj,
mechahitlerobj,
mutantobj,

spaceobj,
needleobj,

Next block:

#define NUMENEMIES  23
typedef enum {
en_guard,
en_officer,
en_ss,
en_dog,
en_boss,
en_schabbs,
en_fake,
en_hitler,
en_mutant,

en_space,
en_blinky,

Next block:

extern statetype s_grddie1;
extern statetype s_dogdie1;
extern statetype s_ofcdie1;
extern statetype s_mutdie1;
extern statetype s_spcdie1;
extern statetype s_ssdie1;


Next block:

extern statetype s_grdchase1;
extern statetype s_dogchase1;
extern statetype s_ofcchase1;
extern statetype s_sschase1;
extern statetype s_spcchase1;
extern statetype s_mutchase1;


Next block:

extern statetype s_grdpain;
extern statetype s_grdpain1;
extern statetype s_ofcpain;
extern statetype s_ofcpain1;
extern statetype s_sspain;
extern statetype s_sspain1;
extern statetype s_spcpain;
extern statetype s_spcpain1;

extern statetype s_mutpain;
extern statetype s_mutpain1;


2. Adding definitions in WL_ACT2.C

First block:

//
  // BABY MODE
  //
  {
  {25,           
   50,          
   100,        
   1,            
   850,        
   850,       
   200,        
   800,      
   45,          
  
30,        
   25,

   
Next block:
    
  //
  // DON'T HURT ME MODE
  //
 
{25,
   50,
   100,
   1,
   950,
   950,
   300,
   950,
   55,
  
35,
   25,

  
Repeat this step another two times for both "Bring 'em On" and "Death Incarnate" difficulty modes.

Note: in case you didn't know: these figures above represent the so_called "hitpoints" for each enemy per difficulty mode. By increasing these values you will make your enemy tougher to beat.

Next, locate this block:

statetype s_grddie2 = {false,SPR_GRD_DIE_2,15,NULL,NULL,&s_grddie3};
statetype s_grddie3 = {false,SPR_GRD_DIE_3,15,NULL,NULL,&s_grddie4};
statetype s_grddie4 = {false,SPR_GRD_DEAD,0,NULL,NULL,&s_grddie4};


And add this entire block below:

//
// space marine
//

extern statetype s_spcstand;

extern statetype s_spcpath1;
extern statetype s_spcpath1s;
extern statetype s_spcpath2;
extern statetype s_spcpath3;
extern statetype s_spcpath3s;
extern statetype s_spcpath4;

extern statetype s_spcpain;
extern statetype s_spcpain1;

extern statetype s_spcshoot1;
extern statetype s_spcshoot2;
extern statetype s_spcshoot3;
extern statetype s_spcshoot4;

extern statetype s_spcchase1;
extern statetype s_spcchase1s;
extern statetype s_spcchase2;
extern statetype s_spcchase3;
extern statetype s_spcchase3s;
extern statetype s_spcchase4;

extern statetype s_spcdie1;
extern statetype s_spcdie1d;
extern statetype s_spcdie2;
extern statetype s_spcdie3;
extern statetype s_spcdie4;

statetype s_spcstand = {true,SPR_SPC_S_1,0,T_Stand,NULL,&s_spcstand};

statetype s_spcpath1  = {true,SPR_SPC_W1_1,20,T_Path,NULL,&s_spcpath1s};
statetype s_spcpath1s  = {true,SPR_SPC_W1_1,5,NULL,NULL,&s_spcpath2};
statetype s_spcpath2  = {true,SPR_SPC_W2_1,15,T_Path,NULL,&s_spcpath3};
statetype s_spcpath3  = {true,SPR_SPC_W3_1,20,T_Path,NULL,&s_spcpath3s};
statetype s_spcpath3s  = {true,SPR_SPC_W3_1,5,NULL,NULL,&s_spcpath4};
statetype s_spcpath4  = {true,SPR_SPC_W4_1,15,T_Path,NULL,&s_spcpath1};

statetype s_spcpain  = {2,SPR_SPC_PAIN_1,10,NULL,NULL,&s_spcchase1};
statetype s_spcpain1  = {2,SPR_SPC_PAIN_2,10,NULL,NULL,&s_spcchase1};

statetype s_spcshoot1  = {false,SPR_SPC_SHOOT1,20,NULL,NULL,&s_spcshoot2};
statetype s_spcshoot2  = {false,SPR_SPC_SHOOT2,20,NULL,T_Shoot,&s_spcshoot3};
statetype s_spcshoot3  = {false,SPR_SPC_SHOOT3,20,NULL,NULL,&s_spcchase1};

statetype s_spcchase1  = {true,SPR_SPC_W1_1,10,T_Chase,NULL,&s_spcchase1s};
statetype s_spcchase1s  = {true,SPR_SPC_W1_1,3,NULL,NULL,&s_spcchase2};
statetype s_spcchase2  = {true,SPR_SPC_W2_1,8,T_Chase,NULL,&s_spcchase3};
statetype s_spcchase3  = {true,SPR_SPC_W3_1,10,T_Chase,NULL,&s_spcchase3s};
statetype s_spcchase3s  = {true,SPR_SPC_W3_1,3,NULL,NULL,&s_spcchase4};
statetype s_spcchase4  = {true,SPR_SPC_W4_1,8,T_Chase,NULL,&s_spcchase1};

statetype s_spcdie1 ={false,SPR_SPC_DIE_1,15,NULL,A_DeathScream,&s_spcdie2};
statetype s_spcdie2 = {false,SPR_SPC_DIE_2,15,NULL,NULL,&s_spcdie3};
statetype s_spcdie3 = {false,SPR_SPC_DIE_3,15,NULL,NULL,&s_spcdie4};
statetype s_spcdie4 = {false,SPR_SPC_DEAD,0,NULL,NULL,&s_spcdie4};


In SpawnStand function:

case en_guard:
  SpawnNewObj (tilex,tiley,&s_grdstand);
  new->speed = SPDPATROL;
  if (!loadedgame)
    gamestate.killtotal++;
  break;
 
case en_space:
  SpawnNewObj (tilex,tiley,&s_spcstand);
  new->speed = SPDPATROL;
  if (!loadedgame)
    gamestate.killtotal++;
  break;

In SpawnPatrol function:

case en_guard:
  SpawnNewObj (tilex,tiley,&s_grdpath1);
  new->speed = SPDPATROL;
  if (!loadedgame)
    gamestate.killtotal++;
  break;

 
case en_space:
  SpawnNewObj (tilex,tiley,&s_spcpath1);
  new->speed = SPDPATROL;
  if (!loadedgame)
    gamestate.killtotal++;
  break;


In A_DeathScream function:

case officerobj:
  PlaySoundLocActor(NEINSOVASSND,ob);
  break;
case ssobj:
  PlaySoundLocActor(LEBENSND,ob); // JAB
  break;

case spaceobj:
  PlaySoundLocActor(DEATHSCREAM1SND,ob);

 
If you want your enemy to have an original "dying" sound, you should insert it here, instead of DEATHSCREAM1SND, which refers to the first brown guard's  sigh of death.
For more information on how to add more sounds to the engine, please refer to the appropriate tutorial.

In T_Chase function:

  case guardobj:
    NewState (ob,&s_grdshoot1);
    break;
   case officerobj:
    NewState (ob,&s_ofcshoot1);
    break;
case spaceobj:
    NewState (ob,&s_spcshoot1);
    break;

   

3. Adding definitions in WL_STATE.C

In KillActor function:

case guardobj:
  GivePoints (100);
  NewState (ob,&s_grddie1);
  PlaceItemType (bo_clip2,tilex,tiley);
  break;

case officerobj:
  GivePoints (400);
  NewState (ob,&s_ofcdie1);
  PlaceItemType (bo_clip2,tilex,tiley);
  break;

 
case spaceobj:
  GivePoints (200);
  NewState (ob,&s_spcdie1);
  PlaceItemType (bo_clip2,tilex,tiley);
  break;


In DamageActor function:

 
case guardobj:
   if (ob->hitpoints&1)
    NewState (ob,&s_grdpain);
   else
    NewState (ob,&s_grdpain1);
   break;

  case officerobj:
   if (ob->hitpoints&1)
    NewState (ob,&s_ofcpain);
   else
    NewState (ob,&s_ofcpain1);
   break;


case spaceobj:
   if (ob->hitpoints&1)
    NewState (ob,&s_spcpain);
   else
    NewState (ob,&s_spcpain1);
   break;

In FirstSighting function:

case guardobj:
  PlaySoundLocActor(HALTSND,ob);
  NewState (ob,&s_grdchase1);
  ob->speed *= 3;   // go faster when chasing player
  break;

case officerobj:
  PlaySoundLocActor(SPIONSND,ob);
  NewState (ob,&s_ofcchase1);
  ob->speed *= 5;   // go faster when chasing player
  break;
 
case spaceobj:
  PlaySoundLocActor(HALTSND,ob);
  NewState (ob,&s_spcchase1);
  ob->speed *= 3;   // go faster when chasing player
  break;

Again, if you want the new enemy to use a different sound when he first sees you, insert it here instead of the HALTSND used for the brown guard.

In SightPlayer function:

case guardobj:
   ob->temp2 = 1+US_RndT()/4;
   break;
  case officerobj:
   ob->temp2 = 2;
   break;

 
case spaceobj:
   ob->temp2 = 1+US_RndT()/4;
   break;

  
  
4. Adding definitions in WL_GAME.C

Locate this block:

case 220:
   case 221:
   case 222:
   case 223:
    SpawnPatrol(en_mutant,x,y,tile-220);
    break;

   
and add this entire block below:

//
// space marine
//
   case 276:
   case 277:
   case 278:
   case 279:
    if (gamestate.difficulty<gd_hard)
     break;
    tile -= 8;
   case 268:
   case 269:
   case 270:
   case 271:
    if (gamestate.difficulty<gd_medium)
     break;
    tile -= 8;
   case 260:
   case 261:
   case 262:
   case 263:
    SpawnStand(en_space,x,y,tile-260);
    break;

   case 280:
   case 281:
   case 282:
   case 283:
    if (gamestate.difficulty<gd_hard)
     break;
    tile -= 8;
   case 272:
   case 273:
   case 274:
   case 275:
    if (gamestate.difficulty<gd_medium)
     break;
    tile -= 8;
   case 264:
   case 265:
   case 266:
   case 267:
    SpawnPatrol(en_space,x,y,tile-264);
    break;



5. Adding the definitions to MapEdit

In order to use your new enemy, you'll need to add its specifications to MapEdit (or whatever other map editor you're using)

Open the file
OBJDATA.WL6 and paste the following block at the very end of this file:

0104 c00S Space  1/S/E
0105 c00S Space  1/S/N
0106 c00S Space  1/S/W
0107 c00S Space  1/S/S
0108 c00S Space  1/M/E
0109 c00S Space  1/M/N
010a c00S Space  1/M/W
010b c00S Space  1/M/S
010c c00S Space  3/S/E
010d c00S Space  3/S/N
010e c00S Space  3/S/W
010f  c00S Space  3/S/S
0110 c00S Space  3/M/E
0111 c00S Space  3/M/N
0112 c00S Space  3/M/W
0113 c00S Space  3/M/S
0114 c00S Space  4/S/E
0115 c00S Space  4/S/N
0116 c00S Space  4/S/W
0117 c00S Space  4/S/S
0118 c00S Space  4/M/E
0119 c00S Space  4/M/N
011a c00S Space  4/M/W
011b c00S Space  4/M/S

That should be it. You're now ready to test your new enemy. Enjoy!

Success,
MCS.
// guards      
// officer     
// SS          
// dogs        
// Hans        
// Schabbs     
// fake hitler 
// mecha hitler
// mutants     
// space
// ghosts
// guards      
// officer     
// SS          
// dogs        
// Hans        
// Schabbs     
// fake hitler 
// mecha hitler
// mutants     
// space
// ghosts