MCS' Coding Tips
                 "Success!"



  
Seamless level progression

   Written by MCS
   Tested by BrotherTank


  
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!
Most ppl use the seamless level tutorial by B.J. Rowan these days. It works OK, but it has a few drawbacks, as stated by B.J. Rowan himself.
Using this method, you will have flawless level progression like in Spear of Destiny, with full level ratios (including total mission ratios) without memory constraints.

In
WL_MENU.C, do a search for this line:

// JAPANESE VERSION

remove EVERYTHING from this line to end of file
and insert this block instead:

if (!findfirst("*.WL6",&f,FA_ARCH))
{
  strcpy(extension,"WL6");
}
else
  Quit("NO WOLFENSTEIN DATA FILES TO BE FOUND!");

strcat(configname,extension);
strcat(SaveName,extension);
strcat(PageFileName,extension);
strcat(audioname,extension);
strcat(demoname,extension);
strcat(helpfilename,extension);
strcat(endfilename,extension);
}


Also in
WL_MENU.C, do a search for:

void CP_NewGame(void)

and scroll down until you'll find

pickquick = 0;

remove anything between these lines, and reinsert the block below.
The complete function should read like this:

void CP_NewGame(void)
{
int which,episode;
episode = 0;
//
// ALREADY IN A GAME?
//
DrawNewGame();
if (ingame)
  if (!Confirm(CURGAME))
  {
   MenuFadeOut();
   return;
  }
DrawNewGame();
which=HandleMenu(&NewItems,&NewMenu[0],DrawNewGameDiff);
if (which<0)
{
  MenuFadeOut();
  return;
}
ShootSnd();
NewGame(which,episode);
StartGame=1;
MenuFadeOut();
//
// CHANGE "READ THIS!" TO NORMAL COLOR
//
#ifndef SPEAR
#ifndef GOODTIMES
MainMenu[readthis].active=1;
#endif
#endif
pickquick = 0;
}

Now open
WL_GAME.C and remove this block:

#ifndef SPEAR
   //
   // COMING BACK FROM SECRET LEVEL
   //
   if (gamestate.mapon == 9)
    gamestate.mapon = ElevatorBackTo[gamestate.episode]; // back from secret
   else
   //
   // GOING TO SECRET LEVEL
   //
   if (playstate == ex_secretlevel)
    gamestate.mapon = 9;
#else


now scroll down 25 lines until you reach
#endif and remove this as well.
Next, open
WL_INTER.C and locate this block:

#ifndef SPEAR
LRstruct LevelRatios[8];


Change the 8 to the amount of levels you want to have in your project.

Same goes for the following line:
(Thanks to Andy_Nonymous for pointing this out!)

for (kr = sr = tr = sec = i = 0;i < 8;i++)

Again, change the 8 to the desired amount of levels (boss and secret levels included)

Next, locate these lines:

#ifndef SPEAR
  //
  // Episode One Par Times


remove all lines up to and including the next
#else
now scroll down 24 lines until you reach
#endif and remove this as well.
If all went well, you should end up with the following:

  {1.5, "01:30"},
  {3.5, "03:30"},
  {2.75, "02:45"},
  {3.5, "03:30"},
  {0, "??:??"}, // Boss 1
  {4.5, "04:30"},
  {3.25, "03:15"},
  {2.75, "02:45"},
  {4.75, "04:45"},
  {1, "01:00"}, // Boss 2
  {6.5, "06:30"},
  {4.5, "04:30"},
  {2.75, "02:45"},
  {4.5, "04:30"},
  {6, "06:00"},
  {0, "??:??"}, // Boss 3
  {6, "06:00"},
  {0, "??:??"}, // Boss 4
  {0, "??:??"}, // Secret level 1
  {0, "??:??"}, // Secret level 2


These are the par times for your levels. 
IMPORTANT: The number of par time lines has to match the value you entered in the LRstruct LevelRatios variable (see previous page).
The par times are calculated in minutes. Look at the first line in this block:

{1.5, "01:30"},

1.5 means one minute and a half. The "01:30" is just the time to display in the intermission screen.
All regular levels must have a par time greater than zero. The zero values and the "??:??" strings are for boss and  secret levels only.

Handling secret levels.

Using this method, secret levels should be handled in a different way. I'll show you what I mean. Open
WL_GAME.C and locate this block:

#define FROMSECRET1  3
#define FROMSECRET2  11

   //
   // GOING TO SECRET LEVEL
   //
   if (playstate == ex_secretlevel)
    switch(gamestate.mapon)
    {
     case FROMSECRET1: gamestate.mapon = 18; break;
     case FROMSECRET2: gamestate.mapon = 19; break;
    }
   else
   //
   // COMING BACK FROM SECRET LEVEL
   //
   if (gamestate.mapon == 18 || gamestate.mapon == 19)
    switch(gamestate.mapon)
    {
     case 18: gamestate.mapon = FROMSECRET1+1; break;
     case 19: gamestate.mapon = FROMSECRET2+1; break;
    }


Remember,
the gamestate.mapon variable always points to the level referred to, MINUS 1! So gamestate.mapon == 18 refers to level 19 and so on.
Study the abovementioned block carefully:

#define FROMSECRET1  3
#define FROMSECRET2  11


This means that both level 4 and 12 contain secret elevators.

    
case FROMSECRET1: gamestate.mapon = 18; break;
     case FROMSECRET2: gamestate.mapon = 19; break;


This means that after entering a secret elevator, gameplay should continue with secret levels 19 and/or 20 respectively.

    
case 18: gamestate.mapon = FROMSECRET1+1; break;
     case 19: gamestate.mapon = FROMSECRET2+1; break;


This means that upon completion of a secret level, gameplay should resume with the next regular level, i.c. 5 and/or 13 respectively.
If you understand all of this, it should be easy to modify things to suit your needs.

Customized boss and secret level intermission screens.

As stated before, both boss and secret levels don't have any par times. Instead, a screen is displayed that says "Hans Grosse defeated!" or "Secret Castle Level Completed".
To have your own boss and secret intermission messages, do the following:
Open
WL_INTER.C and locate this block:

#ifdef SPEAR
#ifndef SPEARDEMO

 
switch(mapon)
   {
    case 4: Write(14,4," trans\n"
        " grosse\n"
        STR_DEFEATED); break;
    case 9: Write(14,4,"barnacle\n"
        "wilhelm\n"
        STR_DEFEATED); break;
    case 15: Write(14,4,"ubermutant\n"
         STR_DEFEATED); break;
    case 17: Write(14,4," death\n"
         " knight\n"
         STR_DEFEATED); break;
    case 18: Write(13,4,"secret tunnel\n"
         "    area\n"
         "  completed!"); break;
    case 19: Write(13,4,"secret castle\n"
         "    area\n"
         "  completed!"); break;
   }

#endif
#else
   Write(14,4,"secret floor\n completed!");
#endif


Remove the yellow lines. Boss intermission texts will follow levels 5, 10, 16 and 18, while secret level intermission texts will be displayed after level 19 and 20.
Needless to say that the levels mentioned above have to match your par time table, as stated above.
Next, locate this block:

#ifndef SPEAR
if (mapon<8)
#else

if (mapon != 4 &&
  mapon != 9 &&
  mapon != 15 &&
  mapon < 17)

#endif

Again, remove the yellow lines. Also make sure that the mentioned mapon values represent your boss and secret levels (remember, MINUS 1)

Finally, locate these lines:

kr /= 8;
sr /= 8;
tr /= 8;


and replace the 8 with the number of regular levels in your addon (boss and secret levels excluded).

I realize it would be quite some work to build all of this into your addon. And if you already made lots of modifications, it isn't worth the trouble anyway, I presume. But if you're about to start a new project, you might want to use these alterations as a starting point. To make things easy, you can download all the modifications in one package
here.  This package is prepared to have 60 levels. To save some memory, you might want to delete the par times that you don't need and adjust the LRstruct LevelRatios accordingly.

Success!
MCS.