Pages: [1] 2
  Print  
Author Topic: Tutorial: How to Add a New Inventory Item Type + HUD Element  (Read 20022 times)
DariusK
Bulb
*
Posts: 97



View Profile WWW
« on: January 20, 2010, 12:44:24 PM »

Overview

So let's say you want to add a new inventory item to Spelunky -- something like bombs and ropes, but different. For the sake of this tutorial, let's have you be able to hold up to 99 rocks in your pockets. We'll make it so that rocks behave kind of like bombs: if you run across one, you can pick it up and it is added to your inventory when you switch away from it.

What we're going to do in this mod is: set the appropriate global variable, figure out how to switch to the new inventory item, and set up the new HUD element so we know how many rocks we have.

Setting the Global Variable

The amount of bombs and ropes you have are stored as global variables. The game sets them in the scrClearGlobals. This script is run at the beginning of every game, and it sets every global to false/0, except for bombs, ropes, and plife (player life), which all get set to 4. So in scrClearGlobals you want to make the following change at line 109:

Code:
else
{
    global.plife = 4;
    global.bombs = 4;
    global.rope = 4;
    // ADD THIS LINE (we're starting the player out with 1 rock)
    global.rocks = 1;
}

Switching to Our Rocks

Here's where we change the code so that pressing the "switch item" button will put a rock in our hands if we have more than 0 rocks. We also want to put in some code so that when we have the rock equipped, our global.rocks is reduced by 1 (so it works the same way bombs and ropes do).

Let's look at the code from oPlayer1 Step, in the second Action Block, line 952:

Code:
else if (inGame and kItemPressed and not whipping)
{   
    // switch items
    if (holdItem)
    {

// If we're holding a bomb and it's armed, we can't switch away.

        if (holdItem.sprite_index == sBombArmed)
        {
            // do nothing
        }

// If we're holding a bomb and it's not armed, then put it back in your
// inventory (increment the global), and then destroy it so you're not
// holding it anymore. Then, if there's more than 0 ropes, switch to
// ropes. Otherwise, switch to what you're holding (or nothing if
// you're not holding anything.)

        else if (holdItem.sprite_index == sBomb)
        {
            with holdItem
            {
                global.bombs += 1;
                instance_destroy();
            }
           
            if (global.rope > 0)
            {
                holdItem = instance_create(x, y, oRopeThrow);
                holdItem.held = true;
                global.rope -= 1;
                whoaTimer = whoaTimerMax;
            }
            else
            {
                scrHoldItem(pickupItemType);
            }
        }

// If we're holding a rope then put it back in your inventory
// (increment the global), and then destroy it so you're not
// holding it anymore. Then switch to what you're holding
// (or nothing if you're not holding anything.)

        else if (holdItem.sprite_index == sRopeEnd)
        {
            with holdItem
            {
                global.rope += 1;
                instance_destroy();
            }           
           
            scrHoldItem(pickupItemType);
        }

// If we're holding an item that's not heavy (damsel or Idol)
// and we have a bomb or a rope, then store it away as
// pickupItemType for later. If we have bombs, switch
// to bombs, if not, then switch to ropes.

        else if (not holdItem.heavy and holdItem.cost == 0)
        {
            if (global.bombs > 0 or global.rope > 0)
            {
                pickupItemType = holdItem.type;
                if (holdItem.type == "Bow" and bowArmed)
                {
                    scrFireBow();
                }
                with holdItem
                {
                    breakPieces = false;
                    instance_destroy();
                }
            }
           
            if (global.bombs > 0)
            {
                holdItem = instance_create(x, y, oBomb);
                if (global.hasStickyBombs) holdItem.sticky = true;
                holdItem.held = true;
                global.bombs -= 1;
                whoaTimer = whoaTimerMax;
            }
            else if (global.rope > 0)
            {
                holdItem = instance_create(x, y, oRopeThrow);
                holdItem.held = true;
                global.rope -= 1;
                whoaTimer = whoaTimerMax;
            }
        }
    }
// If you're not holding anything, switch to bombs if available.
// Otherwise switch to ropes if available.
    else
    {
        if (global.bombs > 0)
        {
            holdItem = instance_create(x, y, oBomb);
            if (global.hasStickyBombs) holdItem.sticky = true;
            holdItem.held = true;
            global.bombs -= 1;
            whoaTimer = whoaTimerMax;
        }
        else if (global.rope > 0)
        {
            holdItem = instance_create(x, y, oRopeThrow);
            holdItem.held = true;
            global.rope -= 1;
            whoaTimer = whoaTimerMax;
        }
    }
}

It's a little complex so you should read through my comments there. Basically, we take this structure and extend it so we have the logic for switching to rock. It's a good exercise to read through this code and figure out why I made the changes I did:

Code:
else if (inGame and kItemPressed and not whipping)
{   
    // switch items
    if (holdItem)
    {
        if (holdItem.sprite_index == sBombArmed)
        {
            // do nothing
        }
        else if (holdItem.sprite_index == sBomb)
        {
            with holdItem
            {
                global.bombs += 1;
                instance_destroy();
            }
           
            if (global.rope > 0)
            {
                holdItem = instance_create(x, y, oRopeThrow);
                holdItem.held = true;
                global.rope -= 1;
                whoaTimer = whoaTimerMax;
            }
            else
            {
                scrHoldItem(pickupItemType);
            }
        }
        else if (holdItem.sprite_index == sRopeEnd)
        {
            with holdItem
            {
                global.rope += 1;
                instance_destroy();
            }
           
            if (global.rocks > 0)
            {
                holdItem = instance_create(x, y, oRock);
                holdItem.held = true;
                global.rocks -= 1;
                whoaTimer = whoaTimerMax;
            }
           
            else
            {
                scrHoldItem(pickupItemType);
            }
        }
        else if (holdItem.sprite_index == sRock)
        {
       
//           global.plife = 0;
           
            with holdItem
            {
                global.rocks += 1;
                instance_destroy();
            }
           
            if (pickupItemType == "Rock") pickupItemType = "";
            scrHoldItem(pickupItemType);
        }
       
        else if (not holdItem.heavy and holdItem.cost == 0)
        {
            if (global.bombs > 0 or global.rope > 0 or global.rocks > 0)
            {
                pickupItemType = holdItem.type;
                if (holdItem.type == "Bow" and bowArmed)
                {
                    scrFireBow();
                }
                with holdItem
                {
                    breakPieces = false;
                    instance_destroy();
                }
            }
           
            if (global.bombs > 0)
            {
                holdItem = instance_create(x, y, oBomb);
                if (global.hasStickyBombs) holdItem.sticky = true;
                holdItem.held = true;
                global.bombs -= 1;
                whoaTimer = whoaTimerMax;
            }
            else if (global.rope > 0)
            {
                holdItem = instance_create(x, y, oRopeThrow);
                holdItem.held = true;
                global.rope -= 1;
                whoaTimer = whoaTimerMax;
            }
            else if (global.rocks > 0)
            {
                holdItem = instance_create(x, y, oRock);
                holdItem.held = true;
                global.rocks -= 1;
                whoaTimer = whoaTimerMax;
            }
        }
    }
    else
    {
        if (global.bombs > 0)
        {
            holdItem = instance_create(x, y, oBomb);
            if (global.hasStickyBombs) holdItem.sticky = true;
            holdItem.held = true;
            global.bombs -= 1;
            whoaTimer = whoaTimerMax;
        }
        else if (global.rope > 0)
        {
            holdItem = instance_create(x, y, oRopeThrow);
            holdItem.held = true;
            global.rope -= 1;
            whoaTimer = whoaTimerMax;
        }
        else if (global.rocks > 0)
        {
            holdItem = instance_create(x, y, oRock);
            holdItem.held = true;
            global.rocks -= 1;
            whoaTimer = whoaTimerMax;
        }
    }
}

Adding Rocks to the UI

Next we want to add a new UI element to the top of the screen that shows how many rocks we have. To do this, open up scrDrawHUD and you'll see this:

Code:
if (global.drawHUD and instance_exists(oPlayer1))
{
    lifeX = 8;
    bombX = 64;
    ropeX = 120;
    moneyX = 176;
    draw_set_font(global.myFont);
    draw_set_color(c_white);
    draw_sprite(sHeart, -1, lifeX, 8);
    life = global.plife;
    if (life < 0) life = 0;
    draw_text(lifeX+16, 8, life);
    if (global.hasStickyBombs) draw_sprite(sStickyBombIcon, -1, bombX, 8);
    else draw_sprite(sBombIcon, -1, bombX, 8);
    draw_text(bombX+16, 8, global.bombs);
    draw_sprite(sRopeIcon, -1, ropeX, 8);
    draw_text(ropeX+16, 8, global.rope);
    draw_sprite(sDollarSign, -1, moneyX, 8);
    draw_text(moneyX+16, 8, global.money);

What you'll want to do is create rockX, which is the X offset of the new rock UI element. I would put it in between rope and money, because money is variable length so you want it at the far right hand side. Then you just add the draw_text() and draw_sprite() functions. I used the sprite for the rock in the example below:

Code:
if (global.drawHUD and instance_exists(oPlayer1))
{
    lifeX = 8;
    bombX = 64;
    ropeX = 120;
    rockX = 176;
    moneyX = 232;
    draw_set_font(global.myFont);
    draw_set_color(c_white);
    draw_sprite(sHeart, -1, lifeX, 8);
    life = global.plife;
    if (life < 0) life = 0;
    draw_text(lifeX+16, 8, life);
    if (global.hasStickyBombs) draw_sprite(sStickyBombIcon, -1, bombX, 8);
    else draw_sprite(sBombIcon, -1, bombX, 8);
    draw_text(bombX+16, 8, global.bombs);
    draw_sprite(sRopeIcon, -1, ropeX, 8);
    draw_text(ropeX+16, 8, global.rope);
    // I messed around with the Y value until I  got something I liked
    draw_sprite(sRock, -1, rockX, 16);
    draw_text(rockX+16, 8, global.rocks);
    draw_sprite(sDollarSign, -1, moneyX, 8);   
    draw_text(moneyX+16, 8, global.money);

And we end up with this:



Logged

marsgreekgod
Mossy
*
Posts: 9806


The will of the Galaxy.


View Profile WWW Email
« Reply #1 on: January 20, 2010, 12:46:21 PM »

sweet! I likes it. good job. I can now make something NICE for 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!
Sudonimus
Mossy
*
Posts: 2743


Stop staring.


View Profile
« Reply #2 on: January 20, 2010, 04:21:33 PM »

Haha, what shortcut key would we use for that?
Logged

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


The will of the Galaxy.


View Profile WWW Email
« Reply #3 on: January 20, 2010, 04:26:23 PM »

what... do you mean?
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!
Sudonimus
Mossy
*
Posts: 2743


Stop staring.


View Profile
« Reply #4 on: January 20, 2010, 04:30:53 PM »

Unless he already said that...
Wasn't reading the whole thing.

Like A is for bombs, S is for ropes, D for rocks?
Logged

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


The will of the Galaxy.


View Profile WWW Email
« Reply #5 on: January 20, 2010, 04:34:56 PM »

No you have to switch threw with the bomb and ropes?
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!
Sudonimus
Mossy
*
Posts: 2743


Stop staring.


View Profile
« Reply #6 on: January 20, 2010, 04:41:43 PM »

How would you make a shortcut key for it?
Logged

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


Too Long Away

nrmario@hotmail.com
View Profile WWW
« Reply #7 on: January 20, 2010, 05:02:46 PM »

How would you make ammo boxes for it and so it appears in crates?

Like if I was making a Super Bomb like in Spelunky De Bombs.
Logged

I'm learning Japanese!
Add me on Steam! http://steamcommunity.com/id/KirbyLord/
Sudonimus
Mossy
*
Posts: 2743


Stop staring.


View Profile
« Reply #8 on: January 20, 2010, 05:04:16 PM »

In the mod with the bombrope, the bombrope
should be in the HUD. (And I should be able
to find out how to use the bombrope.
Logged

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


Yummy Gummy!


View Profile
« Reply #9 on: January 20, 2010, 07:33:26 PM »

Great!  Thanks Darius!

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
Arucard
Mossy
*
Posts: 2811


Hey! Is that CANDY?!?!?

Arucard.Tepes
View Profile Email
« Reply #10 on: January 21, 2010, 09:35:06 AM »

In the mod with the bombrope, the bombrope
should be in the HUD. (And I should be able
to find out how to use the bombrope.
I think it would just use one bomb and one rope, meaning there's no need for an extra icon.

How would you make a shortcut key for it?
This would be interesting, it seems like it would take a bit to make an extra shortcut key. There is a kMissle and kMisslePressed in the character create script. I don't think these are used (haven't seen them at least), but you should be able to add a code like kRockPressed = checkMisslePressed or something in the action event. Not sure about throwing it without making it a held item though.
Logged

Oh, they look like monsters to you?

There's a light in the darkness of everybody's life.
boggers
Seedling
*
Posts: 1


View Profile
« Reply #11 on: January 31, 2010, 06:18:39 AM »

Is there a mod like this that has been released?

I'd love to see a mod that let you stock up on small items like rocks, keys and arrows, and also let you go hands free to be able to pickup stuff and use the whip while still keeping shotgun / pistol etc. in your inventory. As it is, I spend a lot of time throwing keys and guns and stuff around the map so that I can carry damsels and idols.
Logged
gummybears123
Mossy
*
Posts: 5785


Yummy Gummy!


View Profile
« Reply #12 on: February 27, 2010, 05:59:03 PM »

I tried to do this in a mod I'm making, but it didn't work.

First of all, you said "Let's look at the code from oPlayer1 Step, in the second Action Block, line 952:" but I found it at line 552. Second, when I copied and pasted your code and I replaced the rocks with the one I'm using, it ended up saying ERROR AT LINE 703. UNEXPECTED SYMBOL (or something like that).
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
Kirby
Mossy
*
Posts: 1502


Too Long Away

nrmario@hotmail.com
View Profile WWW
« Reply #13 on: February 27, 2010, 06:07:54 PM »

Thank you! I now have flares on a HUD in my game.
Logged

I'm learning Japanese!
Add me on Steam! http://steamcommunity.com/id/KirbyLord/
gummybears123
Mossy
*
Posts: 5785


Yummy Gummy!


View Profile
« Reply #14 on: February 27, 2010, 06:09:15 PM »

I tried to do this in a mod I'm making, but it didn't work.

First of all, you said "Let's look at the code from oPlayer1 Step, in the second Action Block, line 952:" but I found it at line 552. Second, when I copied and pasted your code and I replaced the rocks with the one I'm using, it ended up saying ERROR AT LINE 703. UNEXPECTED SYMBOL (or something like that).

This didn't happen to you?!
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
Pages: [1] 2
  Print  
 
Jump to: