Pages: [1] 2
  Print  
Author Topic: Tutorial: Adding Waaaay More Spikes (Basic Spelunky Level Modification)  (Read 4270 times)
DariusK
Bulb
*
Posts: 97



View Profile WWW
« on: January 07, 2010, 08:01:30 PM »

So marsgreekgod requested this tutorial and I have some extra time tonight and figured I'd write it up. It's based off a blog post I did back in September, but has a lot more detail about actually modifying it.

How to Make Spelunky Generate a Lot More Spikes

Overview

The high-level view of how Spelunky generates levels is that each level is divided into a 4×4 grid of 16 rooms. Each room consists of 80 tiles, 10 tiles wide and 8 tiles high. In the source code, rooms are structured as 80-character strings. Here’s an example:

“00000000110060000L040000000P110000000L110000000L11000000001100000000111112222111″

If we add line breaks every ten characters to create our 10x8 room, we can begin to see the way rooms are laid out:

Code:
0000000011
0060000L04
0000000P11
0000000L11
0000000L11
0000000011
0000000011
1112222111

The game does some neat stuff in terms of figuring out how to create a path through the level and make sure there's a way through every time, but I'm not going to discuss that in this post.

How Basic Rooms Are Generated

There are 4 basic room generation scripts, one for each area of the game.

  • scrRoomGen: basic cave
  • scrRoomGen2: jungle
  • scrRoomGen3: yeti
  • scrRoomGen4: temple

I'm going to focus on scrRoomGen, which generates rooms for the first four levels of the game.

A room layout generally contains walls, ladders, pushblocks, and obstacles. Let's look at our first example:

Code:
0000000011
0000000L04
0000000P11
0000000L11
5000000L11
0000000011
0000000011
1112222111

"1" means wall/floor, "2" means there's a 1 in 10 chance of a pushblock, otherwise it's a brick, "L" means ladder, "P" means top platform of a ladder, "4" means a 1in 4 chance of a pushblock, otherwise it's empty. "5" is special and I'll explain it in a bit. This is an example of a room where there's a solid floor of bricks and maybe pushblocks, there's a wall to right with a ladder going up to the top, and there might be a pushblock at the top of the wall where it blocks you from getting to the other side. (Note: svenski posted a partial guide to these symbols that might come in handy.)

How Obstacles Get Added

"5" is our special case here. It's an obstacle. An obstacle is a 5x3 block of tiles which gets overlaid onto the map wherever there's a 5 (in this case). 5 is used to signify ground obstacles, like spikes, so this is the one we care about.

If we go to line 265 in the scrRoomGen script, we see this:

Code:
    else if (tile == "5") // ground
    {
        switch(rand(1,16))
        {
            case 1: { strObs1 = "11111"; strObs2 = "00000"; strObs3 = "00000"; break; }
            case 2: { strObs1 = "00000"; strObs2 = "11110"; strObs3 = "00000"; break; }
            case 3: { strObs1 = "00000"; strObs2 = "01111"; strObs3 = "00000"; break; }
            case 4: { strObs1 = "00000"; strObs2 = "00000"; strObs3 = "11111"; break; }
            case 5: { strObs1 = "00000"; strObs2 = "20200"; strObs3 = "17177"; break; }
            case 6: { strObs1 = "00000"; strObs2 = "02020"; strObs3 = "71717"; break; }
            case 7: { strObs1 = "00000"; strObs2 = "00202"; strObs3 = "77171"; break; }
            case 8: { strObs1 = "00000"; strObs2 = "22200"; strObs3 = "11100"; break; }
            case 9: { strObs1 = "00000"; strObs2 = "02220"; strObs3 = "01110"; break; }
            case 10: { strObs1 = "00000"; strObs2 = "00222"; strObs3 = "00111"; break; }
            case 11: { strObs1 = "11100"; strObs2 = "22200"; strObs3 = "00000"; break; }
            case 12: { strObs1 = "01110"; strObs2 = "02220"; strObs3 = "00000"; break; }
            case 13: { strObs1 = "00111"; strObs2 = "00222"; strObs3 = "00000"; break; }
            case 14: { strObs1 = "00000"; strObs2 = "02220"; strObs3 = "21112"; break; }
            case 15: { strObs1 = "00000"; strObs2 = "20100"; strObs3 = "77117"; break; }
            case 16: { strObs1 = "00000"; strObs2 = "00102"; strObs3 = "71177"; break; }
        }
    }

What it does is this. After the game builds all the basic, and trap-free, rooms, it goes through every tile and checks if there's an obstacle. (5, 6, and 8 count as obstacles for the first four levels of the game.) If it hits a 5, it runs the above code. It then picks one of the 16 possible 5x3 obstacle setups at random. Let's assume it picked number 6.

If we take case number 6 and "stack" the different strings with strObs1 on top and strObs3 on the bottom, we get this:

Code:
00000
02020
71717

What that means is this:

  • The top row of tiles won't modify the tiles they're on top of. So if the 5 in our room had a 1 next to it, that 1 would stay a 1 (probably solid ground) no matter what.
  • The second row has two tiles in it that have a 1 in 2 chance of being a brick (with a small chance of being a pushblock)
  • The third row goes like this: spike-block-spike-block-spike (a 7 means spike)

It's not *exactly* that, though. Spelunky loves to pile randomization upon randomization. If we look down in the code a little bit, we see this:

Code:
else if (tile == "7" and rand(1,3) == 1) instance_create(xpos, ypos, oSpikes);

Turns out there's only a 1 in 3 chance of a spike appearing whenever there's a 7!

Finally, Adding Some Spikes!

So the first thing we can do is increase the chances of spikes appearing. Let's go totally crazy and make it a 1 in 1 chance: that is, whenever there's a 7, there's a spike. What happens?

Code:
else if (tile == "7" and rand(1,1) == 1) instance_create(xpos, ypos, oSpikes);



Hmm, it's definitely spikier than usual but not what I would call ridiculously spikey. The reason for this is that if we look at the 16 different cases up above, only about half of them have any spikes at all! So even when a "7" means "definitely put a spike here," it's not going to help us when there are no 7's at all! So let's modify things a little!

We'll add a crapload more 7's to the strObs3 of each of the 16 cases. (The reason we only do it to strObs3 is that it's the one that's always going to be on the ground. Otherwise we end up with floating spikes.)

Code:
    else if (tile == "5") // ground
    {
        switch(rand(1,16))
        {
            case 1: { strObs1 = "11111"; strObs2 = "00000"; strObs3 = "77707"; break; }
            case 2: { strObs1 = "00000"; strObs2 = "11110"; strObs3 = "07770"; break; }
            case 3: { strObs1 = "00000"; strObs2 = "01111"; strObs3 = "70707"; break; }
            case 4: { strObs1 = "00000"; strObs2 = "00000"; strObs3 = "11111"; break; }
            case 5: { strObs1 = "00000"; strObs2 = "20200"; strObs3 = "17177"; break; }
            case 6: { strObs1 = "00000"; strObs2 = "02020"; strObs3 = "71717"; break; }
            case 7: { strObs1 = "00000"; strObs2 = "00202"; strObs3 = "77171"; break; }
            case 8: { strObs1 = "00000"; strObs2 = "22200"; strObs3 = "11177"; break; }
            case 9: { strObs1 = "00000"; strObs2 = "02220"; strObs3 = "71110"; break; }
            case 10: { strObs1 = "00000"; strObs2 = "00222"; strObs3 = "77111"; break; }
            case 11: { strObs1 = "11100"; strObs2 = "22200"; strObs3 = "77007"; break; }
            case 12: { strObs1 = "01110"; strObs2 = "02220"; strObs3 = "70077"; break; }
            case 13: { strObs1 = "00111"; strObs2 = "00222"; strObs3 = "77777"; break; }
            case 14: { strObs1 = "00000"; strObs2 = "02220"; strObs3 = "21112"; break; }
            case 15: { strObs1 = "00000"; strObs2 = "20100"; strObs3 = "77117"; break; }
            case 16: { strObs1 = "00000"; strObs2 = "00102"; strObs3 = "71177"; break; }
        }
    }



Hmm, pretty good but still not quite there. The reason we're STILL not seeing a lot of spikes is because it only goes through those 16 cases if it runs happens to run into a 5 tile! For example, the room you see in the above picture, in the center-left, just didn't have a 5 tile so there are no spikes.

The Hard Part

This is where the modding gets hard. You're going to need to go through each one of the 80-character room strings (there are about 30 of them) and break them into their 8x10 blocks, figure out where you want to put an extra 5 tile, and then put them back together. For example, let's go with this one:

"60000600000000000000000600000000000000000000000000000222220000111111001111111111"

We break it out into 8 rows of 10:

Code:
6000060000
0000000000
0006000000
0000000000
0000000000
0002222200
0011111100
1111111111

Hey, it looks like a pretty empty room. Let's add a 5. Since the 5 is a 5x3 block of tiles, 3 blocks tall, we need to put the 5 somewhere in the fourth row from the bottom. Otherwise our spike tiles will be floating in air, or worse!

Code:
6000060000
0000000000
0006000000
0000000000
5000050000
0002222200
0011111100
1111111111

Which then becomes this:

"60000600000000000000000600000000000000005000050000000222220000111111001111111111"

I added two 5's to the room. Combined with my super spikey obstacle set, this is probably going to have a lot of spikes in it!

I don't have the time to go through and artfully place all these obstacles (this is where the art of level design comes in handy!), but as a quick hack I just added a crapton of 5's in places that I was pretty sure ahead of time would *probably* be safe.



Now that's what I call spikey! You can see from the screenshot that there are a few places where spikes are randomly hanging in mid-air. That's why you need to do what I showed above, and for every room, painstakingly take it apart and replace the obstacle tiles where appropriate and stitch them back together. This is really hard, and this is one of the many reasons why Derek is a game design genius!

Anyway, if you want the source code that generated my super-spikey cave, you can find it here. Just replace scrRoomGen in the Spelunky source code with that script and you'll be in spike city. (Be sure to back up your old script first!)

Hope this helps! Spelunky Dude
Logged

marsgreekgod
Big Bossy
Mossy
*
Posts: 9773


The will of the Galaxy.


View Profile WWW Email
« Reply #1 on: January 07, 2010, 08:43:16 PM »

it does! This well let me make MEGA EVIL DEATH SPELUNKY!
Logged

Show your power, Gun Del Hell! Show them their fate! Yes! Yes! Yes! Yes! Yes! Here we go! Let's go, go, go, go, Django! Light and Dark! It comes down to this! Be afraid, Sun!
gummybears123
Mossy
*
Posts: 5776


Yummy Gummy!


View Profile
« Reply #2 on: January 07, 2010, 09:09:37 PM »

Oh no... more spikes?  And I didn't understand any of your long speech Darius Grin
Logged

I made a rap.
It sounds dumb, like reading a map
I really should stop this thing before it goes too far
But I don't really car as long as I stay below the radar
Those big companies won't get me no
I'll get away before the fuzz show

-Most famous rapper of Mossmouth
Kirbylord
ipwnu1337
Guest
« Reply #3 on: January 07, 2010, 09:20:22 PM »

it does! This well let me make MEGA EVIL DEATH SPELUNKY!

It would actually make the game so much more easy.

But it leaves less room for error, sadly.
Logged
marsgreekgod
Big Bossy
Mossy
*
Posts: 9773


The will of the Galaxy.


View Profile WWW Email
« Reply #4 on: January 07, 2010, 09:52:44 PM »

I didn't say more spikes would be the only thing I did.
Logged

Show your power, Gun Del Hell! Show them their fate! Yes! Yes! Yes! Yes! Yes! Here we go! Let's go, go, go, go, Django! Light and Dark! It comes down to this! Be afraid, Sun!
Kegluneq
Big Bossy
Mossy
*
Posts: 2205



View Profile Email
« Reply #5 on: January 08, 2010, 12:29:58 AM »

Humm so I was halfway there. I hadn't noticed the thing about the 5.
Very nice reverse engineering you've showed lately DariusK!
Logged

A wild SHINY MOSSY appeared!
DariusK
Bulb
*
Posts: 97



View Profile WWW
« Reply #6 on: January 08, 2010, 09:17:58 AM »

Humm so I was halfway there. I hadn't noticed the thing about the 5.
Very nice reverse engineering you've showed lately DariusK!
Thanks! I hope to post some more tutorials.
Logged

Svenski
Seedling
*
Posts: 4


View Profile
« Reply #7 on: January 08, 2010, 10:54:51 AM »

Nice explanation :D I hope you post more of these.
Logged
Sudonimus
Mossy
*
Posts: 2743


Stop staring.


View Profile
« Reply #8 on: January 08, 2010, 03:01:28 PM »

IF you're going to make more spikes,
make the spikes rules like v1.0 please.
It would make life so much better.
Logged

How is there no such thing as non-existence?!
gummybears123
Mossy
*
Posts: 5776


Yummy Gummy!


View Profile
« Reply #9 on: January 08, 2010, 03:03:15 PM »

MGG obviously isn't Tongue

Darius might
Logged

I made a rap.
It sounds dumb, like reading a map
I really should stop this thing before it goes too far
But I don't really car as long as I stay below the radar
Those big companies won't get me no
I'll get away before the fuzz show

-Most famous rapper of Mossmouth
Kirbylord
DariusK
Bulb
*
Posts: 97



View Profile WWW
« Reply #10 on: January 08, 2010, 03:06:40 PM »

IF you're going to make more spikes,
make the spikes rules like v1.0 please.
It would make life so much better.
I've been thinking about doing a little fan patch of v1.1. I might change the spike rules back 1.0, along with fixing some other bugs. The main problem with the 1.0 rules is that it makes the spike pits in the jungle area really easy to cross. But I agree, the new spike rule is kind of annoying.
Logged

gummybears123
Mossy
*
Posts: 5776


Yummy Gummy!


View Profile
« Reply #11 on: January 08, 2010, 03:23:26 PM »

Kind of?  Are you kidding me?
Logged

I made a rap.
It sounds dumb, like reading a map
I really should stop this thing before it goes too far
But I don't really car as long as I stay below the radar
Those big companies won't get me no
I'll get away before the fuzz show

-Most famous rapper of Mossmouth
Kirbylord
DariusK
Bulb
*
Posts: 97



View Profile WWW
« Reply #12 on: January 08, 2010, 03:24:32 PM »

Kind of?  Are you kidding me?
I personally thought 1.0 was too easy, I'm glad 1.1 has some tougher rules about things like spikes.
Logged

gummybears123
Mossy
*
Posts: 5776


Yummy Gummy!


View Profile
« Reply #13 on: January 08, 2010, 03:25:05 PM »

Have you tried EVIL spelunky?
Logged

I made a rap.
It sounds dumb, like reading a map
I really should stop this thing before it goes too far
But I don't really car as long as I stay below the radar
Those big companies won't get me no
I'll get away before the fuzz show

-Most famous rapper of Mossmouth
Kirbylord
DariusK
Bulb
*
Posts: 97



View Profile WWW
« Reply #14 on: January 08, 2010, 03:27:50 PM »

Have you tried EVIL spelunky?
Yes I have. It's too hard Smiley

Basically, I like my games to be hard but rewarding. Spelunky is like that. All respect to marsgreekgod, but EVIL Spelunky is waaaaay too evil for me Smiley
Logged

Pages: [1] 2
  Print  
 
Jump to: