Old school CRPGs

O

Override_X

Guest
So. Considering tackling this genre, doing something in the vain of say, The Bard's Tale, or Might and Magic (mid to late 80's versions, not later remakes). My understanding is that those types games used a simulated 3d view of the game world in the nav windows (usually upper left portion of the screen) as opposed to actual 3d renderings of the game world. I'm wondering what approaches to accomplishing this might be taken. The only solution that occurs to me is to have the actual 2d world laid out in a grid with an object in the parties position. Determine which of the cardinal directions the party is facing and then determine what objects would be in their line of sight. Finally, use draw functions to place "3d" sprite versions of those objects in the area of the screen which is supposed to be the world view. I can't seem to find much documentation on the methodology the old schoolers actually used, but I'm curious as to what approaches you might take. Here's a screen shot or 2 of what I'm trying to accomplish:hqdefault.jpg download (2).jpeg
 
L

Lonewolff

Guest
Back in those days it would have been drawn straight with no 3D involved.

On the C64, you used to be able to replace character maps with your own (even making multicoloured characters). I suspect this is how they did it on those platforms.



Note the 45 degree angles? This backs up my theory.

Crude example of how to draw the two left most buildings in the image above.

Code:
A
BA
BBA
BBBA
BBBB
BBBB
BBBBAAAA
BBBBBBBBA
BBBBBBBBBA
BBBBBBBBBBA
BBBBBBBBBBB
BBBBBBBBBBB
BBBBBBBBBBB
BBBBBBBBBC
BBBBBBBBC
BBBBBBBC
BBBB
BBBB
BBBC
BBC
BC
 
O

Override_X

Guest
Back in those days it would have been drawn straight with no 3D involved.

On the C64, you used to be able to replace character maps with your own (even making multicoloured characters). I suspect this is how they did it on those platforms.



Note the 45 degree angles? This backs up my theory.

Crude example of how to draw the two left most buildings in the image above.

Code:
A
BA
BBA
BBBA
BBBB
BBBB
BBBBAAAA
BBBBBBBBA
BBBBBBBBBA
BBBBBBBBBBA
BBBBBBBBBBB
BBBBBBBBBBB
BBBBBBBBBBB
BBBBBBBBBC
BBBBBBBBC
BBBBBBBC
BBBB
BBBB
BBBC
BBC
BC
So you are saying that they had an individual drawing for every location (coordinate and direction) in the game rather than an on the fly rendering based on what was present in the scene?
 
L

Lonewolff

Guest
So you are saying that they had an individual drawing for every location (coordinate and direction) in the game
Nope.

It would be trivial to replicate the image above programatically, with tons of variations. The shapes are always the same.



Depending on what you choose to draw and choose to omit, determines the illusion of what you are seeing.


rather than an on the fly rendering based on what was present in the scene?
Definitely not 3D rendering if that is what you are asking.

This is what the most advanced 3D rendering looked like in the day.

 
O

Override_X

Guest
I guess I haven't articulated my question properly, then.
I am aware that it wasn't an actual 3d rendering. I am also aware of the character mall replacement on the c64. However, neither of the 2 images in my original post come from a c64. One is from a dos based pc, and the other was from a Snes, both of which would have used 2d sprites drawn in a "3d" style or perspective.

The world exists on a 2d grid/plane, and each location on that grid consists of an x and y coordinate and a direction. In the first image you posted, and 1 of the ones I posted, the party can see at least 5 grid spaces ahead. And moving through the plane shifts the view 1 grid space, or rotates it 90 degrees in the case of a turn.

As I understand it, the view that the player sees is not the actual space that gameplay takes place in, but is instead a "simulated 3d representation" of the 2d plane where the action is actually taking place. The player never actually sees this 2d plane, or gets a dumbed down version of it in the case of the auto map...

It seems the thing you say is trivial is the part I'm trying to make sure I understand before I start trying to code it.
 

TheouAegis

Member
Are you familiar with auto-tiling using 8bit values? That's essentially all it is. The entire map is a grid with each cell having a value of 0 (no walls) to 15 (fully enclosed). You have the direction variable (0 to 3) to know what way the player is facing. The program looks at the value of the cell the player is on, performs dir bit rotations, then renders the walls near the player. Then it checks the direction to find the next cell, rotates the bits, then renders the second set of walls. If desired, it repeats one more time.

Miscellaneous stuff (doors, chests, traps) are either also stored in a grid if the dungeon is small enough or indexed.
 
O

Override_X

Guest
Are you familiar with auto-tiling using 8bit values? That's essentially all it is. The entire map is a grid with each cell having a value of 0 (no walls) to 15 (fully enclosed). You have the direction variable (0 to 3) to know what way the player is facing. The program looks at the value of the cell the player is on, performs dir bit rotations, then renders the walls near the player. Then it checks the direction to find the next cell, rotates the bits, then renders the second set of walls. If desired, it repeats one more time.

Miscellaneous stuff (doors, chests, traps) are either also stored in a grid if the dungeon is small enough or indexed.
That's interesting. I'm not really familiar with it, but will check it out. Any leads on a decent tutorial where that's been implemented? Also, it just scales based in how many grid spaces away each wall is?
 
O

Override_X

Guest
SNES wasn't invented until the 90's
That's correct, of course. However, the game shown was released in 1988 for pc. I just happened to grab a screenshot of the Snes port. Here's a couple from the pc version for the sake of comparison.2954b050-30dd-012d-f821-0050569439b1.jpg images (4).jpeg
 
Hi, I'm currently working on an 80's style CRPG with this style of 2D dungeon graphics. I have quite a bit of experience with this, so let me try to explain it simply:

The way old-school RPGs used to do it and the ways I would recommend are two very different methods. I'm going to use as an example here the Homebrew Game Boy port of Ultima III: Exodus, because debugging emulator functions make it easy to explain what's going on, and other games of the time use similar or identical solutions. Take a look at this screenshot:

You'll notice that the dungeon display splits perfectly into 8x8 tiles. In the game data, dungeon wall sprites are stored in a tileset that looks like this:

Since the tileset has 256 tiles, every tile is mapped to a number from 0-255. This means that 6 tiles down and 3 tiles right corresponds to the hexadecimal value 0x63, which is the Uppercase F tile. The game then utilizes a tilemap, which stores these hex values in a format that can then be drawn to the screen. This is a visual example of the tilemap:

If you're not familiar with hexadecimal, the numbers 10-15 are represented with the characters A through F. While it is definitely possible to simulate this approach in GameMaker, these alternatives are what I recommend:
  • Just use 3D
  • Lonewolff's method. Make a "font" made of dungeon graphics.
  • Each wall in each position has its own sprite. This is what I do. You just draw the walls furthest away from the "camera" first and you get a 3D-like effect when layering the walls.
3D is by far the easiest method. Unless you're really married to the 2D aesthetic, 3D will be far easier to work with, modify, and get it to look good. The level of 3D knowledge required for this style of gameplay isn't difficult to achieve in GameMaker.

Are you familiar with auto-tiling using 8bit values? That's essentially all it is.
It's nothing like auto-tiling. I wouldn't recommend looking into it since it won't help for this.
 
Last edited:
O

Override_X

Guest
SNES wasn't invented until the 90's
I did find this image you posted to be very helpful, btw.GyjCmal.png
I'm just pondering the logistics of having what amounts to a single pixel traversing a maze on a 2d grid, all of which happens off camera, and then procedurally generating a pseudo 3d view based on what the pixel "sees" in front of it.

I imagine the problem is somewhat similar to (but maybe less complex than) the old 2d racers like pole position, or outrun (or one of my favorites, F-Zero!) Mike Dailly mentioned in a blog post that he did a pole position clone in a few hours back in May of '16. Wish I could take a look at the code for that. Lol
 
I'm just pondering the logistics of having what amounts to a single pixel traversing a maze on a 2d grid, all of which happens off camera, and then procedurally generating a pseudo 3d view based on what the pixel "sees" in front of it.
It's quite simple. First off, you have the "player", which is just an object with coordinate variables and a direction variable. The map is a 2D grid of some sort. Usually a ds_grid or a 2D array. Each cell in the grid contains information on which walls are filled and which are empty. You need to first establish what your camera's line of sight is, then you can find out which walls exist within line of sight, then draw them.
 
O

Override_X

Guest
Hi, I'm currently working on an 80's style CRPG with this style of 2D dungeon graphics. I have quite a bit of experience with this, so let me try to explain it simply:

The way old-school RPGs used to do it and the ways I would recommend are two very different methods. I'm going to use as an example here the Homebrew Game Boy port of Ultima III: Exodus, because debugging emulator functions make it easy to explain what's going on, and other games of the time use similar or identical solutions. Take a look at this screenshot:

You'll notice that the dungeon display splits perfectly into 8x8 tiles. In the game data, dungeon wall sprites are stored in a tileset that looks like this:

Since the tileset has 256 tiles, every tile is mapped to a number from 0-255. This means that 6 tiles down and 3 tiles right corresponds to the hexadecimal value 0x63, which is the Uppercase F tile. The game then utilizes a tilemap, which stores these hex values in a format that can then be drawn to the screen. This is a visual example of the tilemap:

If you're not familiar with hexadecimal, the numbers 10-15 are represented with the characters A through F. While it is definitely possible to simulate this approach in GameMaker, these alternatives are what I recommend:
  • Just use 3D
  • Lonewolff's method. Make a "font" made of dungeon graphics.
  • Each wall in each position has its own sprite. This is what I do. You just draw the walls furthest away from the "camera" first and you get a 3D-like effect when layering the walls.
3D is by far the easiest method. Unless you're really married to the 2D aesthetic, 3D will be far easier to work with, modify, and get it to look good. The level of 3D knowledge required for this style of gameplay isn't difficult to achieve in GameMaker.


It's nothing like auto-tiling. I wouldn't recommend looking into it since it won't help for this.
Super helpful. Thanks. The third way you mentioned (layered sprites for each position) is what I was imagining, although I can also see the benefit of a tileset or a font map.

I think I have a pretty solid grasp of how I'm going to handle it now. Thanks to everyone who provided input.
 

TheouAegis

Member
It's nothing like auto-tiling. I wouldn't recommend looking into it since it won't help for this.
Drawing the player's pseudo 3D view is nothing like autotiling, but the dungeons themselves are mapped out similarly to autotiling. They wouldn't say, "this cell uses this screen and this cell uses that screen and this cell use is a screen..." Well, they could do that if they really wanted to, but seems like a ton more work to me then just letting an algorithm map out the screen, especially if you eventually want to incorporate a random dungeon generator.

But really, all I was pointing out was the same method of utilizing bits would work pretty well. A 64x64 dungeon would take up only 256 bytes of RAM to map out walls and alleyways.
 
the dungeons themselves are mapped out similarly to autotiling.
Ah, I see where you're getting at with autotiling. You're thinking of block walls, like in Ultima III.

The vast majority of 80's CRPGs -- including all the ones OP mentioned in the first post -- utilize line walls.

An autotile-esque method is impossible with this. You have to think completely differently as you're storing vertical and horizontal walls into a grid instead of simple blocks.

My solution to dungeon data storage is to have each cell be a byte, and vertical and horizontal walls each take up one nibble. Taking 4 bits per wall allows storage of differing wall types like doors, one-way doors (you actually need 2 different types of one-way doors), passable walls, locked doors, and plenty of space left over for future expansion through other potential wall types.
 
O

Override_X

Guest
Drawing the player's pseudo 3D view is nothing like autotiling, but the dungeons themselves are mapped out similarly to autotiling. They wouldn't say, "this cell uses this screen and this cell uses that screen and this cell use is a screen..." Well, they could do that if they really wanted to, but seems like a ton more work to me then just letting an algorithm map out the screen, especially if you eventually want to incorporate a random dungeon generator.

But really, all I was pointing out was the same method of utilizing bits would work pretty well. A 64x64 dungeon would take up only 256 bytes of RAM to map out walls and alleyways.
Actually, I had a pretty similar thought to this for awhile utilizing color data in a bitmap. Each pixel in a bitmap could correspond to a variable, and using standard rgb data, each variable could have over 16 million values, or over 4 billion if you include an alpha channel. Obviously that's overkill, but each pixel could alternately cover 4 different variables, each with 256 potential values. Either way, it was a hypothetical exercise. However, a single 16x16 sprite could theoretically hold all the information needed for 1024 different variables. More than enough to cover even the most robust rpg character.
 
O

Override_X

Guest
Ah, I see where you're getting at with autotiling. You're thinking of block walls, like in Ultima III.

The vast majority of 80's CRPGs -- including all the ones OP mentioned in the first post -- utilize line walls.

An autotile-esque method is impossible with this. You have to think completely differently as you're storing vertical and horizontal walls into a grid instead of simple blocks.
correct. and each line could have completely different values depending on which side of the line you were on. A stone wall while standing outside the inn, but wood panel on the inside, for instance. In some cases, the wall was completely invisible from one side, while appearing solid from the other,
 
An autotile-esque method is impossible with this. You have to think completely differently as you're storing vertical and horizontal walls into a grid instead of simple blocks.
Pseudo-autotiling would still be possible, but instead of storing the wall cells in the grid, you would be storing the floor cells in the grid with each having an algorithmic calculation of which edges contain walls and what type/texture they are.
 
Pseudo-autotiling would still be possible, but instead of storing the wall cells in the grid, you would be storing the floor cells in the grid with each having an algorithmic calculation of which edges contain walls and what type/texture they are.
I still don't see how that's possible to put into a simple autotile algorithm. If the autotile algo sees this:
autotile1.png
How can it tell if the outcome is supposed to be either
autotile2.png
or
autotile3.png
?

At that point, it's procedural generation and no longer autotiling. You really don't even WANT to have auto-generated walls unless you're going full proc-gen. You lose out on the benefits of either 100% handcrafted content (quality) or 100% proc-gen content (quantity).
 
I still don't see how that's possible to put into a simple autotile algorithm
That's the thing, it isn't a simple algorithm. You would need to figure out a way to be able to say which side of the cell contains the wall (that is relatively easy, eg: 1,2,4,8 to identify top, right, bottom, left - with added values allowing multiple walls, eg: 3 = top and right, 1+2, etc). The difficult addition to this comes with defining how you would allow additional values for each wall to include the texture/image to be used.

It is possible, but would require a lot of thinking to come up with the perfect system.
 
That's the thing, it isn't a simple algorithm. You would need to figure out a way to be able to say which side of the cell contains the wall (that is relatively easy, eg: 1,2,4,8 to identify top, right, bottom, left - with added values allowing multiple walls, eg: 3 = top and right, 1+2, etc). The difficult addition to this comes with defining how you would allow additional values for each wall to include the texture/image to be used.

It is possible, but would require a lot of thinking to come up with the perfect system.
Aside from utilizing a bitmask, that has nothing in common with autotiling.

I will share some problems I ran into and my solutions:
You need to figure out what the wall is. Is it a door? One-way wall? One-way door? Invisible wall? Need several bits per wall for that. There's also no need to identify bottom and right walls since they're shared. The solution I came up with is to create my own binary file format:
Code:
    0x00-0x09
File header

   0x0a-0x0d
Map width/height

   0x0e-0x0f
Reserved for future use

   Next [height]*[width] bytes
Wall type data for vertical and horizontal walls
Each cell is stored as one byte and contains the top and left walls.
Top wall is low nibble (0000xxxx)
Left wall is high nibble (xxxx0000)
Aside from knowing what type of wall is in a certain position, you also need to know what the wall looks like. I don't have it programmed yet, but already I know exactly how I'm going to deal with this. My plan is to have another height*width bytes containing wall texture data for top and left walls, stored similarly to the wall data. This method may not lead to optimal file sizes, but there's really no significant benefit to optimize any further considering the storage even a decade-old PC provides make the file sizes you're dealing with look downright nanoscopic. The hassle of needing to add something later and lacking enough bits to play with is also a potential danger of optimizing a file format too early.
 
O

Override_X

Guest
Aside from utilizing a bitmask, that has nothing in common with autotiling.

I will share some problems I ran into and my solutions:
You need to figure out what the wall is. Is it a door? One-way wall? One-way door? Invisible wall? Need several bits per wall for that. There's also no need to identify bottom and right walls since they're shared. The solution I came up with is to create my own binary file format:
Code:
    0x00-0x09
File header

   0x0a-0x0d
Map width/height

   0x0e-0x0f
Reserved for future use

   Next [height]*[width] bytes
Wall type data for vertical and horizontal walls
Each cell is stored as one byte and contains the top and left walls.
Top wall is low nibble (0000xxxx)
Left wall is high nibble (xxxx0000)
Aside from knowing what type of wall is in a certain position, you also need to know what the wall looks like. I don't have it programmed yet, but already I know exactly how I'm going to deal with this. My plan is to have another height*width bytes containing wall texture data for top and left walls, stored similarly to the wall data. This method may not lead to optimal file sizes, but there's really no significant benefit to optimize any further considering the storage even a decade-old PC provides make the file sizes you're dealing with look downright nanoscopic. The hassle of needing to add something later and lacking enough bits to play with is also a potential danger of optimizing a file format too early.
Why would the right and bottom wall be shared?
 
Why would the right and bottom wall be shared?
With the format I'm using, the right wall of cell [x, 0] is going to be the same as the left wall of cell [x+1, 0]. Same with bottom wall of cell [0, y] and top wall of cell [0, y+1]. I saw very little benefit to keeping track of bottom and right walls, but of course, there are definitely reasons you might want to do otherwise. Keep in mind this is in the dungeon data file, not when checking the player view.
 

TheouAegis

Member
Lol just drop the auto-tiling discussion already!

Most of the time in a lot of the old games it was either wall or door. So 1 whole byte of data (HGFEDCBA; A thru D for walls, E thru H for doors). Want flavor art? Just add another byte of data.
Special things like signs and portals (e.g., shop or dungeon entrance) could just be in a small LUT.

Wouldn't a 1-way wall just be diskointed cells where one has a wall bit defined and the other doesn't? Like, instead of $01$02 to define two cells side by side with a wall on the rightside of the left cell (with a value of 1 for right and 2 for left), you'd have $01$00, then it would be a wall in left cell and no wall on the right cell. Granted, it would be solid for one and not the other, so a totally fake wall could be defined by a door bit sans wall bit; so $10$20 could be used to define a fake wall between the cells. ...which would require doors to have the wall bit set also, so $11$22 for a door between both cells. And then $1102 would be a door that can't be used because the adjacent cell does not have a door. Granted, this method would not work if a door can be locked but accessed from both sides, which would require a LUT scenario there, but that's still pretty flexible imho.
 
Last edited:
O

Override_X

Guest
Lol just drop the auto-tiling discussion already!

Most of the time in a lot of the old games it was either wall or door. So 1 whole byte of data (HGFEDCBA; A thru D for walls, E thru H for doors). Want flavor art? Just add another byte of data.
Special things like signs and portals (e.g., shop or dungeon entrance) could just be in a small LUT.

Wouldn't a 1-way wall just be diskointed cells where one has a wall bit defined and the other doesn't? Like, instead of $01$02 to define two cells side by side with a wall on the rightside of the left cell (with a value of 1 for left and 2 for right), you'd have $01$00, then it would be a wall in left cell and no wall on the right cell. Granted, it would be solid for one and not the other, so a totally fake wall could be defined by a door bit sans wall bit; so $10$20 could be used to define a fake wall between the cells. ...which would require doors to have the wall bit set also, so $11$22 for a door between both cells. And then $1102 would be a door that can't be used because the adjacent cell does not have a door. Granted, this method would not work if a door can be locked but accessed from both sides, which would require a LUT scenario there, but that's still pretty flexible imho.
As far as I can tell, this seems to be like most things in gms (and programming in general). There's about a thousand different ways to accomplish things. Tbh, I value any and all perspectives, whether auto-tiled or not. That's why I started the thread; to hear what different people had to say on the subject, and I'm grateful for everyone who's contributed so far.
 
Most of the time in a lot of the old games it was either wall or door.
You're not giving those "old games" enough credit! :) Even Wizardry had multiple types of doors. The only one I can think of off the top of my head that is as basic as you're describing is Ultima, but dungeon crawling and combat was never the focus of that series anyway. Still easy enough to deal with like you're suggesting if you throw more data at it.

Wouldn't a 1-way wall just be diskointed cells where one has a wall bit defined and the other doesn't? Like, instead of $01$02 to define two cells side by side with a wall on the rightside of the left cell (with a value of 1 for left and 2 for right), you'd have $01$00, then it would be a wall in left cell and no wall on the right cell. Granted, it would be solid for one and not the other, so a totally fake wall could be defined by a door bit sans wall bit; so $10$20 could be used to define a fake wall between the cells. ...which would require doors to have the wall bit set also, so $11$22 for a door between both cells. And then $1102 would be a door that can't be used because the adjacent cell does not have a door. Granted, this method would not work if a door can be locked but accessed from both sides, which would require a LUT scenario there, but that's still pretty flexible imho.
Yes, that is another very viable solution. Probably the better one if you're not doing super complicated dungeon design. I ended up having to devise my current solution because I had done this previously and it was getting to be quite the mess with all the lookups, haha!
 
Top