DieHard Wolfers Forum Index DieHard Wolfers
A Wolfenstein 3d Fan Community


  Hosted by: MCS & Areyep.com - Designed by: BrotherTank

Original Yahoo Forum - Die Hard Archives

AReyeP HomepageAreyep Homepage DieHard Wolfenstein BunkerDieHard Wolfenstein Bunker Log inLog in RegisterRegister Banlist FAQFAQ Search ForumsSearch

  Username:    Password:      Remember me       

128x128 map size (DOS)
Page 1 of 1
DieHard Wolfers Forum Index -> Code Crackers View Previous TopicRefresh this PageAdd Topic to your Browser FavoritesSearch ForumsPrint this TopicE-mail TopicGoto Page BottomView Next Topic
Post new topicReply to topic
Author Message
Aryan_Wolf3D
DieHard Guard
DieHard Guard


Joined: 21 Jul 2011
Last Visit: 29 Jan 2020

Topics: 8
Posts: 292

blank.gif

PostPosted: Wed Dec 04, 2019 3:01 am
   Subject: 128x128 map size (DOS)
   [ IP : Logged ]
Reply with quote
Goto Top of PostsGoto Next PostGoto Bottom of Posts

128x128 (and larger) map sizes have been available in Wolf4SDL for awhile, but to my knowledge nobody has added this feature successfully to DOS yet. So let's do it now!

First off, open up ID_HEADS.H and add the lines in red:

::: CODE :::
#define   UPDATETERMINATE   0x0301

#define MAPSHIFT    7
#define MAPSIZE      (1 << MAPSHIFT)

extern   unsigned   mapwidth,mapheight,tics;
extern   boolean   compatability;


Then in WL_DEF.H, find and delete the now useless "#define MAPSIZE 64" line.

Now to hunt down some hardcoded numbers for the map size...

In ID_CA.C, go to the CAL_SetupMapFile function and add this:

::: CODE :::
   int   i;
   int handle;
   word size;
   long length,pos;
   char fname[13];

........

   size = MAPSIZE*MAPSIZE*2;

   for (i=0;i<MAPPLANES;i++)
   {
      MM_GetPtr (&(memptr)mapsegs[i],size);
      MM_SetLock (&(memptr)mapsegs[i],true);
   }


Although it may seem unnecessary, for whatever reason the game will bomb with an out of memory error if you try to put "MAPSIZE*MAPSIZE*2" directly in the second MM_GetPtr parameter, and I've no idea why...

Anyway, further down the file, in CA_CacheMap, change the "size" assignment to "MAPSIZE*MAPSIZE*2" again.

In WL_GAME.C, in the SetupGameLevel function, change the 64s in the line "if (mapwidth != 64 || mapheight != 64)" to MAPSIZE.

In WL_MAIN.C, in the InitGame function, change the 64 in the farmapylookup assignment to MAPSIZE.

In WL_DRAW.C, in the DrawScaleds function:

::: CODE :::
      if (*visspot
      || ( *(visspot-1) )
      || ( *(visspot+1) )
      || ( *(visspot-(mapwidth + 1)) )
      || ( *(visspot-mapwidth) )
      || ( *(visspot-(mapwidth - 1)) )
      || ( *(visspot+(mapwidth + 1)) )
      || ( *(visspot+mapwidth) )
      || ( *(visspot+(mapwidth - 1)) ) )
      {


Finally, open up WL_DR_A.ASM and make these changes:

::: CODE :::
initvars:
   call   NEAR xpartialbyystep   ; xpartial is in BX
   add   ax,[WORD viewy]
   adc   dx,[WORD viewy+2]
   mov   [WORD yintercept],ax
   mov   [WORD yintercept+2],dx

   mov   si,[focaltx]
   add   si,[xtilestep]
   mov   [xtile],si               ; xtile = focaltx+xtilestep
   shl   si,7
   add   si,dx                  ; xspot = (xtile<<6) + yinttile


   call   NEAR ypartialbyxstep   ; ypartial is in BP
   add   ax,[WORD viewx]
   adc   dx,[WORD viewx+2]
   mov   [WORD xintercept],ax
   mov   cx,dx

   mov   bx,[focalty]
   add   bx,[ytilestep]
   mov   bp,bx                  ; ytile = focalty+ytilestep
   mov   di,dx
   shl   di,7
   add   di,bx                  ; yspot = (xinttile<<6) + ytile

.....

passvert:
   mov   [BYTE spotvis+si],1         ; *((byte *)spotvis+xspot) = true;
   add   bx,[xtilestep]            ; xtile+=xtilestep
   mov   ax,[WORD ystep]
   add   [WORD yintercept],ax      ; yintercept += ystep
   adc   dx,[WORD ystep+2]
   mov   si,bx
   shl   si,7
   add   si,dx                  ; xspot = (xtile<<6)+yinttile
   jmp   vertcheck

.....

passhoriz:
   mov   [BYTE spotvis+di],1         ; *((byte *)spotvis+yspot) = true;
   add   bp,[ytilestep]            ; ytile+=ytilestep
   mov   ax,[WORD xstep]
   add   [WORD xintercept],ax      ; xintercept += xstep
   adc   cx,[WORD xstep+2]
   mov   di,cx
   shl   di,7
   add   di,bp                  ; yspot = (xinttile<<6)+ytile
   jmp   horizcheck


And that's it! You now have 128x128 mapsizes in DOS that work perfectly!!!

EXCEPT FOR ONE LITTLE PROBLEM...



Ah yes, the good old Abnormal Program Termination. The problem is, there are three MAPSIZE*MAPSIZE arrays (tilemap, spotvis, and actorat) which, when 128x128, will eat up all 64k of the DGROUP on their own. So we have to deal with those somehow... But how? Well, the easiest way would be to put them in main memory, where it's not as limited. But before we can do that, there are some major changes involved. One of these changes is easy enough, luckily, it's just tedious, and that is changing actorat to a byte so that it can be shoved into main mem. Luckily, there's already a tutorial for this here.

The other major change is to port all the ASM code from WL_DR_A.ASM to C, because I don't know how to make tilemap and spotvis work in far memory in the 16 bit ASM code, since it uses near pointers to index the tile coords of the intercept into them. If anyone knows how to do this, feel free to share it! Anyway, here's AsmRefresh in C (it's pretty big, so I'll put it in a spoiler)...


Just shove this into WL_DRAW.C, above the WallRefresh function:

::: CODE :::
/*
====================
=
= AsmRefresh
=
====================
*/

#pragma warn -rch
void AsmRefresh (void)
{
    int      angle;
    long     xstep,ystep;
    long     xinttemp,yinttemp;                                  // holds temporary intercept position
    unsigned xpartial,ypartial;
    boolean  passdoor;

    for (pixx = 0; pixx < viewwidth; pixx++)
    {
        //
        // setup to trace a ray through pixx view pixel
        //
        angle = midangle + pixelangle[pixx];                     // delta for this pixel

        if (angle < 0)                                           // -90 - -1 degree arc
            angle += ANG360;                                     // -90 is the same as 270
        if (angle >= ANG360)                                     // 360-449 degree arc
            angle -= ANG360;                                     // -449 is the same as 89

        //
        // setup xstep/ystep based on angle
        //
        if (angle < ANG90)                                       // 0-89 degree arc
        {
            xtilestep = 1;
            ytilestep = -1;
            xstep = finetangent[ANG90 - 1 - angle];
            ystep = -finetangent[angle];
            xpartial = xpartialup;
            ypartial = ypartialdown;
        }
        else if (angle < ANG180)                                 // 90-179 degree arc
        {
            xtilestep = -1;
            ytilestep = -1;
            xstep = -finetangent[angle - ANG90];
            ystep = -finetangent[ANG180 - 1 - angle];
            xpartial = xpartialdown;
            ypartial = ypartialdown;
        }
        else if (angle < ANG270)                                 // 180-269 degree arc
        {
            xtilestep = -1;
            ytilestep = 1;
            xstep = -finetangent[ANG270 - 1 - angle];
            ystep = finetangent[angle - ANG180];
            xpartial = xpartialdown;
            ypartial = ypartialup;
        }
        else if (angle < ANG360)                                 // 270-359 degree arc
        {
            xtilestep = 1;
            ytilestep = 1;
            xstep = finetangent[angle - ANG270];
            ystep = finetangent[ANG360 - 1 - angle];
            xpartial = xpartialup;
            ypartial = ypartialup;
        }

        //
        // initialise variables for intersection testing
        //
        yintercept = FixedByFrac(ystep,xpartial) + viewy;
        yinttile = yintercept >> TILESHIFT;                      // high word of yintercept
        xtile = focaltx + xtilestep;

        xintercept = FixedByFrac(xstep,ypartial) + viewx;
        xinttile = xintercept >> TILESHIFT;                      // high word of xintercept
        ytile = focalty + ytilestep;

//
// trace along this angle until we hit a wall
//
// CORE LOOP!
//
        while (1)
        {
            //
            // check intersections with vertical walls
            //
            if ((ytilestep == -1 && yinttile <= ytile) || (ytilestep == 1 && yinttile >= ytile))
                goto horizentry;
vertentry:
            //
            // get the wall value from tilemap
            //
            if (tilemap[xtile][ytile] && (xtile - xtilestep) == xinttile && (ytile - ytilestep) == yinttile)
            {
                //
                // exactly in the wall corner, so use the last tile
                //
                tilehit = lasttilehit;

                if (tilehit & 0x80)
                    passdoor = false;                                           // don't let the trace continue if it's a door
            }
            else
            {
                tilehit = tilemap[xtile][yinttile];

                if (tilehit & 0x80)
                    passdoor = true;
            }

            if (tilehit)
            {
                if (tilehit & 0x80)
                {
                    if ((tilehit & 0xc0) == 0xc0)
                    {
                        //
                        // hit a sliding vertical wall
                        //
                        // add partial step to current intercept
                        //
                        yinttemp = yintercept + FixedByFrac(ystep,pwallpos << 10);

                        //
                        // is it still in the same tile?
                        //
                        if (yinttemp >> TILESHIFT != yinttile)
                            goto passvert;                                      // no, it hit the side

                        xintercept = (long)xtile << TILESHIFT;
                        yintercept = yinttemp;                                  // save pixel intercept position
                        HitVertPWall ();
                    }
                    else
                    {
                        //
                        // hit a vertical door, so find which coordinate the door would be
                        // intersected at, and check to see if the door is open past that point
                        //
                        yinttemp = yintercept + (ystep >> 1);                   // add half step to current intercept position

                        //
                        // midpoint is outside tile, so it hit the side of the wall before a door
                        //
                        if (yinttemp >> TILESHIFT != yinttile && passdoor)
                            goto passvert;

                        //
                        // the trace hit the door plane at pixel position yintercept, see if the door is
                        // closed that much
                        //
                        if ((word)yinttemp < doorposition[tilehit & 0x7f])
                            goto passvert;

                        xintercept = ((long)xtile << TILESHIFT) + 0x8000;       // intercept in middle of tile
                        yintercept = yinttemp;                                  // save pixel intercept position
                        HitVertDoor ();
                    }
                }
                else
                {
                    //
                    // hit a normal vertical wall
                    //
                    xintercept = (long)xtile << TILESHIFT;
                    HitVertWall ();
                }

                break;                                                          // next pixel over
            }
passvert:
            //
            // mark the tile as visible and setup for next step
            //
            spotvis[xtile][yinttile] = true;
            xtile += xtilestep;
            yintercept += ystep;
            yinttile = yintercept >> TILESHIFT;
        }

        continue;                                                               // next pixel over

        while (1)
        {
            //
            // check intersections with horizontal walls
            //
            if ((xtilestep == -1 && xinttile <= xtile) || (xtilestep == 1 && xinttile >= xtile))
                goto vertentry;
horizentry:
            //
            // get the wall value from tilemap
            //
            if (tilemap[xtile][ytile] && (xtile - xtilestep) == xinttile && (ytile - ytilestep) == yinttile)
            {
                //
                // exactly in the wall corner, so use the last tile
                //
                tilehit = lasttilehit;

                if (tilehit & 0x80)
                    passdoor = false;                                           // don't let the trace continue if it's a door
            }
            else
            {
                tilehit = tilemap[xinttile][ytile];

                if (tilehit & 0x80)
                    passdoor = true;
            }

            if (tilehit)
            {
                if (tilehit & 0x80)
                {
                    if ((tilehit & 0xc0) == 0xc0)
                    {
                        //
                        // hit a sliding horizontal wall
                        //
                        // add partial step to current intercept
                        //
                        xinttemp = xintercept + FixedByFrac(xstep,pwallpos << 10);

                        //
                        // is it still in the same tile?
                        //
                        if (xinttemp >> TILESHIFT != xinttile)
                            goto passhoriz;                                     // no, it hit the side

                        xintercept = xinttemp;                                  // save pixel intercept position
                        yintercept = (long)ytile << TILESHIFT;
                        HitHorizPWall ();
                    }
                    else
                    {
                        //
                        // hit a horizontal door, so find which coordinate the door would be
                        // intersected at, and check to see if the door is open past that point
                        //
                        xinttemp = xintercept + (xstep >> 1);                   // add half step to current intercept position

                        //
                        // midpoint is outside tile, so it hit the side of the wall before a door
                        //
                        if (xinttemp >> TILESHIFT != xinttile && passdoor)
                            goto passhoriz;

                        //
                        // the trace hit the door plane at pixel position xintercept, see if the door is
                        // closed that much
                        //
                        if ((word)xinttemp < doorposition[tilehit & 0x7f])
                            goto passhoriz;

                        xintercept = xinttemp;                                  // save pixel intercept position
                        yintercept = ((long)ytile << TILESHIFT) + 0x8000;       // intercept in middle of tile
                        HitHorizDoor ();
                    }
                }
                else
                {
                    //
                    // hit a normal horizontal wall
                    //
                    yintercept = (long)ytile << TILESHIFT;
                    HitHorizWall ();
                }

                break;                                                          // next pixel over
            }
passhoriz:
            //
            // mark the tile as visible and setup for next step
            //
            spotvis[xinttile][ytile] = true;
            ytile += ytilestep;
            xintercept += xstep;
            xinttile = xintercept >> TILESHIFT;
        }
    }
}
#pragma warn +rch


Now you can delete the WL_DR_A.ASM file from your project.


Alright, now that this is in C, time to stop these arrays from eating up our precious DGROUP... Open up WL_DEF.H again, and search for tilemap:

::: CODE :::
extern   byte far    tilemap[MAPSIZE][MAPSIZE];   // wall values only
extern   byte far    spotvis[MAPSIZE][MAPSIZE];
extern   byte far   actorat[MAPSIZE][MAPSIZE];


And in WL_PLAY.C:
::: CODE :::

byte far   tilemap[MAPSIZE][MAPSIZE];   // wall values only
byte far   spotvis[MAPSIZE][MAPSIZE];
byte far   actorat[MAPSIZE][MAPSIZE];


Now open up WL_MAIN.C and go to InitGame again, and delete the nearmapylookup assignment to shut up a warning (the array is never used anyway).

In WL_GAME.C, In SetupGameLevel:

::: CODE :::
   _fmemset (tilemap,0,sizeof(tilemap));
   _fmemset (actorat,0,sizeof(actorat));


Before we deal with the spotvis stuff in DrawScaleds, there's a pointer stored in the static object structure that points to the address of spotvis[tilex][tiley], but it will cause problems if we try to use it as a far pointer (unless I missed something...). But it's no big deal, that pointer was always just a horrible waste of 800 bytes of memory anyway, so let's get rid of it. In WL_DEF.H, search for statstruct and remove "byte *visspot;". Then in WL_ACT1.C, go to the SpawnStatic function and remove "laststatobj->visspot = &spotvis[tilex][tiley]", and in PlaceItemType, remove "spot->visspot = &spotvis[tilex][tiley]".

OK, now back in WL_DRAW.C, go to the DrawScaleds function and make these changes:

::: CODE :::
void DrawScaleds (void)
{
   int       i,j,least,numvisable,height;
   memptr      shape;
   byte far    *visspot;
   int         shapenum;
   unsigned   spotloc;

   statobj_t   *statptr;
   objtype      *obj;

   visptr = &vislist[0];

//
// place static objects
//
   for (statptr = &statobjlist[0] ; statptr !=laststatobj ; statptr++)
   {
      if ((visptr->shapenum = statptr->shapenum) == -1)
         continue;                  // object has been deleted

        if (!spotvis[statptr->tilex][statptr->tiley])
         continue;                  // not visable

      if (TransformTile (statptr->tilex,statptr->tiley
         ,&visptr->viewx,&visptr->viewheight) && statptr->flags & FL_BONUS)
      {
         GetBonus (statptr);
         continue;
      }

      if (!visptr->viewheight)
         continue;                  // to close to the object

      if (visptr < &vislist[MAXVISABLE-1])   // don't let it overflow
         visptr++;
   }

//
// place active objects
//
   for (obj = player->next;obj;obj=obj->next)
   {
      if (!(visptr->shapenum = obj->state->shapenum))
         continue;                  // no shape

      visspot = &spotvis[obj->tilex][obj->tiley];


Notice that I removed all the *tilespot stuff... It wasn't doing anything useful, and in fact causes a visual bug with enemies in doorways, so good riddance.

Next, go down to ThreeDRefresh and change this:

::: CODE :::
asm   mov   ax,ds
asm   mov   es,ax
asm   mov   di,OFFSET spotvis
asm   xor   ax,ax
asm   mov   cx,2048                     // 64*64 / 2
asm   rep stosw


To this:

::: CODE :::
_fmemset (spotvis,0,sizeof(spotvis));


Now to just tie up a few loose ends... Go to the top of the file, then search for "xinttile", and change its data type from "unsigned" to "int". Then go down to HitVertWall and change this:

::: CODE :::
         ytile = yintercept>>TILESHIFT;
         if ( tilemap[xtile-xtilestep][ytile]&0x80 )


To this:

::: CODE :::
if ( tilemap[xtile-xtilestep][yinttile]&0x80 )


And then in HitHorizWall, change this:

::: CODE :::
         xtile = xintercept>>TILESHIFT;
         if ( tilemap[xtile][ytile-ytilestep]&0x80 )


To this:

::: CODE :::
if ( tilemap[xinttile][ytile-ytilestep]&0x80 )


This isn't necessary to do, but since we now have the high word of xintercept/yintercept saved in xinttile/yinttile, we might as well use them.

Finally, there's an ugly glitch that can happen in very large maps when looking at walls far away.



To fix this, go to CalcHeight and add the code in red:

::: CODE :::
   if (nx<mindist)
      nx=mindist;         // don't let divide overflow

   asm   mov   ax,[WORD PTR heightnumerator]
   asm   mov   dx,[WORD PTR heightnumerator+2]
   asm   idiv   [WORD PTR nx+1]         // nx>>8
    asm   cmp   ax,8
    asm   jge exit
   asm   mov   ax,8

exit:



This will ensure the wallheight is never less than 8, which is small enough for long distances without causing the glitch.

I think that's it... Save everything and compile, then try a 128x128 map and see if it works. Now that the 3 troublesome arrays are in main memory, you will also free up around 16k of the DGROUP that you can use to increase the object limits to accommodate the larger map size. Note that you can also increase the sizes of tilemap and actorat from a byte to a word, to allow more wall textures and actors.

Alright, let me know if I missed anything, and I hope to see a 128x128 mapset for DOS someday. Wink

Long Live DOS!
Aryan Wolf

_________________
"Way too many #ifdefs in the code!" - John Carmack


Last edited by Aryan_Wolf3D on Sat Dec 07, 2019 1:16 pm; edited 3 times in total
Wolf3DGuy
DieHard Guard
DieHard Guard


Joined: 01 Aug 2017
Last Visit: 1:54 ago.

Topics: 7
Posts: 251

blank.gif

PostPosted: Wed Dec 04, 2019 5:57 am
   Subject: Re: 128x128 map size (DOS)
   [ IP : Logged ]
Reply with quote
Goto Top of PostsGoto Previous PostGoto Next PostGoto Bottom of Posts

Good to see people still care about the original DOS game and it's source code these days. I wish people would still produce DOS Wolf3D mods using it's limitations in creative ways, or at least map packs (with 128x128 maps using this tutorial) that'd be great, but anyway thanks for this tutorial! Smile

_________________
https://www.moddb.com/mods/wolfenstein-3d-3-new-missions
Chris
DieHard Wolfer
DieHard Wolfer


Joined: 11 Mar 2003
Last Visit: 21 Jan 2020

Topics: 58
Posts: 2272
Location: Canada
blank.gif

PostPosted: Wed Dec 04, 2019 7:12 am
   Subject: Re: 128x128 map size (DOS)
   [ IP : Logged ]
Reply with quote
Goto Top of PostsGoto Previous PostGoto Next PostGoto Bottom of Posts

Nice. Think I'll try porting Ninth Gate to DOS and see if it runs better than Leiche Soldat in DOS4GW with this sometime. Wink

According to HWE, Gate 8 has the most of everything on it... more than any map in Leiche Soldat Surprised

objects: 1990
actors: 507
doors: 200

edit: Found my Leiche Soldat 4GW code so I guess that would be easier to try first: https://chokfiles.webs.com/diffLS.txt
edit2: It's working. Laughing Didn't play it extensively yet though: http://www.mediafire.com/file/i437x8bjhode7jo/LEICHE.EXE
gerolf
DieHard Wolfer
DieHard Wolfer


Joined: 28 Jan 2010
Last Visit: 22 Jan 2020

Topics: 162
Posts: 1117
Location: Virginia
usa.gif

PostPosted: Fri Dec 06, 2019 11:19 pm
   Subject: Re: 128x128 map size (DOS)
   [ IP : Logged ]
Reply with quote
Goto Top of PostsGoto Previous PostGoto Bottom of Posts

This is great! It is amazing what all is still possible with the DOS code. While ports are innovative and convenient, I definitely agree that there is just something to figuring things out in DOS constraints and making things never thought possible into a reality.

_________________
Display posts from previous:   
Post new topicReply to topic Time synchronized with the forum server time
DieHard Wolfers Forum Index -> Code Crackers View Previous TopicRefresh this PageAdd Topic to your Browser FavoritesSearch ForumsPrint this TopicE-mail TopicGoto Page TopView Next Topic
Page 1 of 1
Jump to:  

Related topics
 Topics   Replies   Views   Last Post 
No new posts Sticky: [Info] Help for newbie coders! C++ Tutorial
Author: Dugtrio17
20 11512 Sun Jan 10, 2010 12:26 pm
Fragstein3D View latest post
No new posts [Info] Black & White Effect - Tutorial
Author: Guest
10 300 Thu Mar 17, 2005 6:24 pm
Dugtrio17 View latest post
No new posts [Info] Breakable or Exploding Objects (colums or barrels)
Author: wolf3dbreaker
37 11831 Tue Feb 08, 2005 5:44 am
Guest View latest post
No new posts [Info] Assigning Static Objects problem.
Author: Guest
1 104 Sun Jul 06, 2003 1:25 pm
Guest View latest post
No new posts [Info] Alarm Sounding in game?? WSJ...??
Author: Guest
7 311 Tue Jun 17, 2003 10:04 pm
Reivax44 View latest post
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
   You cannot delete your posts in this forum
You cannot vote in polls in this forum


Copyright ©2003-2008 DieHard Wolfers
A Modified subBunker Theme by BrotherTank
Powered by phpBB © 2001, 2005 phpBB Group