Multiple Lifebars w/o changing color like SoR or Final Fight?

afhc2x17

Active member
Hi, I was searching in between the tutorials (and I have seen Golden Axe Legend's scripted lifebar, but that doesn't answer my question), because I want to design one lifebar for enemies and bosses that works like SoR or Final Fight, that is: the lifebar changes color layers as a whole before getting to the standard lifebar when it's the last one. Someone has made a script for a lifebar that is closer to this behavior? Thanks in advance.
 
afhc2x17

It's not the exact same thing as what you want, but I wrote code that is the basis of it. Check out this demo video of my Golden Axe project - pay attention to the player and enemy health. As damage accrues the rightmost block switches color (Blue > Yellow > Orange > Red) and then disappears. The enemy meter only has one block, so it's pretty straight forward. Calculate % of remaining HP and draw a colored block accordingly: Blue >= 75%, Yellow < 75%, Orange < 50%Red <= 25%.

The player meter is a bit more complicated, but it's the one you need to look at. In its case, there are multiple blocks, and only the rightmost changes color. Each block mathematically represents 25% of remaining HP, and then I subdivide that into quarters. So if the player has 100/100 HP, the right most block is representing 75 - 100. By breaking that down, you get 25/25. Then I calculate how much of that 25 remains. Example: If the player is at 90/100 HP, subdivided value is 15/25. You calculate the % from that subdivided value (in this case 60%), and you get the color bar to display - Yellow. On screen, the player will have three blue blocks and one yellow in their life meter.

To modify for your needs, all you really need to do is not worry about displaying multiple blocks. You just need to show one large block (or use the drawbox function) to display the colored bar. Then you just stylize that bar or block to give the appearance of a full meter that only changes color. You can add as many color graduations as you like. The formula is still the same. In fact I wrote it so I could have as many or as few as I want already, so that's done for you.

The main difference is what happens once you get down to where you want the meter to start moving conventionally. Instead of displaying a red block like I do, you will want to draw a meter using the examples you found already looking around. The trick (and its very important) is you will draw that meter using the subdivided value.

https://www.youtube.com/watch?v=JossdCHwwIw

Code:
#include "data/scripts/dc_hud/config.h"

#import "data/scripts/dc_hud/block-sprites.c"
#import "data/scripts/dc_hud/health-fraction.c"

// Draw player HUD, with icons, magic jars, and
// life blocks for the target entity.
void dc_golden_axe_player_hud()
{
    #define HEALTH_BLOCK_MAX        4   // Maximum number of health blocks that can be displayed for a single HUD entry.
    #define MAGIC_BLOCK_MAX         10  // Maximum number of magic blocks.

    #define PLAYER_HUD_WIDTH        160 // Total width of each player HUD (with padding).
    #define MP_AREA_MARGIN_LEFT     56  // Left of player HUD to first magic block.
    #define MP_BLOCK_MARGIN_LEFT    2
    #define MP_BLOCK_MARGIN_RIGHT   3

    void    target;                 // Target entity
    int     max_players;            // Number of available players.
    int     i;                      // Loop cursor.
    int     exists;                 // Entity exists flag.
    int     dead;                   // Entity dead flag.
    int     resolution_y;           // Screens vertical size in pixels.
    int     player_index;
    int     magic_count;            // How many symbols (jars, blocks, etc.) of magic to display.
    int     sprite_index;           // Placeholder for sprite reference.
    float   health_fraction;        // A sub-division of current health percentage.
    float   block_fraction;         //
    int     block_size_h;           // Size of mp block 9after OpenBOR auto trims).
    int     block_space;            // Size of mp block with margins included.
    int     block_position_left;    // Starting position of mp blocks in each player's HUD.
    int     block_position_x;       // X position of an individual mp block.
    int     block_position_Y;       // Y position of an individual mp block.

    // Get and loop through player collection.
    max_players = openborvariant("maxplayers");

    for(player_index=0; player_index<max_players; player_index++)
    {
        // Get target entity for this loop increment.
        target = getplayerproperty(player_index, "entity");

        // Make sure we got a valid target pointer.
        if(!target)
        {
            continue;
        }

        // Make sure the entity exists in play. We perform this
        // check because it's possible for an entity to be
        // removed but its pointer is still valid.
        exists  = getentityproperty(target, "exists");

        if(!exists)
        {
            continue;
        }

        // We're leaving dead enemies on the screen but
        // don't want to draw their HUD any more. For
        // this purpose the dead flag will work well
        // as a filter.
        dead = getentityproperty(target, "dead");

        if(dead)
        {
            continue;
        }

        resolution_y    = openborvariant("vresolution");
        magic_count     = getentityproperty(target, "mp") / MAGIC_BLOCK_MAX;
        sprite_index    = getlocalvar(VAR_KEY_SPRITE_MAGIC_JAR);

        // Magic meter.

        // We're drawing MP blocks in a row, so Y position
        // is always the same.
        block_position_Y = resolution_y-20;

        // X position will depend on several factors. Some
        // we can do here, and the rest will need to be
        // in a loop.
        //
        // Let's get the width of our meter block.
        // Remember that OpenBOR auto trims all sprites
        // as it loads them, so the size will reflect that.
        block_size_h = getgfxproperty(sprite_index, "srcwidth");

        // Now we add the block's margins, and that will get
        // total spacing for one block.
        block_space = block_size_h + MP_BLOCK_MARGIN_LEFT + MP_BLOCK_MARGIN_RIGHT;

        // Our starting position will be the leftmost of
        // current player's (in loop) HUD area. To get this,
        // we multiply current player index by total X size of
        // the player HUD.
        block_position_left = player_index * PLAYER_HUD_WIDTH;

        // Add the meter area's left margin to space it
        // out from the start of player HUD area.
        block_position_left += MP_AREA_MARGIN_LEFT;

        for(i=0; i<magic_count; i++)
        {
            // Multiply the total X space of a block
            // by the current cursor position. This places
            // each block in a row, left to right.
            block_position_x = i * block_space;

            // Now add the margin from player HUD to start
            // of block area to align blocks properly with
            // player HUD design.
            block_position_x += block_position_left;

            // Draw the MP sprite.
            drawsprite(sprite_index, block_position_x, block_position_Y, openborconstant("FRONTPANEL_Z")+18001);
        }

        // Health Meter
        //
        // Positioning works identically to MP meter. but health
        // meter also includes a color keying capability.

        // Color keying
        //
        // Our goal here is to replicate the Golden Axe style life
        // blocks, but also add in the feature from Altered Beast
        // the right most block would change color as health depleted
        // until it was gone, then onto the next block and so on.
        //
        // To do this, we need to go through a few steps.
        //
        // First we get a decimal value of current remaining health. For
        // example, if health is currently 80 of a max 100, then we get
        // a value of 0.8.
        //
        // Next, we multiply the decimal value of 0.8 by the maximum
        // number of blocks that can be displayed. This gives us a
        // value of 3.2. Just for labeling, we call it health fraction.
        //
        // Now we run a loop, with the cursor incrementing by 1, and
        // stopping when the cursor > our health fraction. Inside the
        // loop, we subject the current cursor value from health fraction
        // value to get a value we'll call block percentage.
        //
        // The loop is essentially getting a sub percentage value of
        // for each block. We then feed that to a function that will
        // determine which color of block to display. In our example,
        // the first three blocks will get a value of > 1. So they get
        // the 100% block. The forth block ends up with a value of 0.2.
        // That means the block is at 20% and the block sprite function
        // will choose accordingly.
        //
        // In our example, this is what the loop looks like:
        //
        // Health: 80 of 100
        // 4 * (80 / 100) = 3.2
        //
        // *loop starts*
        //
        // 3.2 - 0 = 3.2: Block 1 - 100%
        // 3.2 - 1 = 2.2: Block 2 - 100%
        // 3.2 - 2 = 1.2: Block 3 - 100%
        // 3.2 - 3 = 0.2: Block 4 - 20%
        //
        // *Loop stops, four blocks are displayed*
        //
        // If health drops to 35, it would then look like this:
        //
        // Health: 35 of 100
        // 4 * (80 / 100) = 1.4
        //
        // *loop starts*
        //
        // 1.4 - 0 = 1.4: Block 1 - 100%
        // 1.4 - 1 = 0.4: Block 2 - 40%
        //
        // Loop stops, two blocks are displayed.

        // Get health %, multiplied by number of displayable blocks.
        health_fraction = HEALTH_BLOCK_MAX * get_health_fraction(target);

        // Get Y position.
        block_position_Y = resolution_y-31;

        #define HP_BLOCK_MARGIN_LEFT 2
        #define HP_BLOCK_MARGIN_RIGHT 2


        // Loop each quarter of health.
        for(i=0; i < health_fraction; i++)
        {
            block_fraction = health_fraction - i;
            sprite_index   = dc_get_block_large(block_fraction);

            // Positioning works same way as MP meter, but
            // all initial math work has to be in loop since
            // we don't know until in side the loop which
            // sprite is in use.
            block_size_h = getgfxproperty(sprite_index, "srcwidth");

            // Now we add the margins, and that will get total
            // spacing for one block.
            block_space = block_size_h + HP_BLOCK_MARGIN_LEFT + HP_BLOCK_MARGIN_RIGHT;

            // Our starting position will be the leftmost of
            // current player's (in loop) HUD area.
            block_position_left = player_index * PLAYER_HUD_WIDTH;

            // Multiply the total X space of an MP block
            // by the current cursor position. This places
            // each block in a row, left to right.
            block_position_x = i * block_space;

            // Now add the margin from player HUD to start
            // of magic area to align blocks properly with
            // player HUD design.
            block_position_x += MP_AREA_MARGIN_LEFT;

            drawsprite(sprite_index, player_index*160+53+i*26, block_position_Y, openborconstant("FRONTPANEL_Z")+18001);
        }
    }

    #undef HEALTH_BLOCK_MAX
    #undef MAGIC_BLOCK_MAX

    #undef PLAYER_HUD_WIDTH
    #undef MP_AREA_MARGIN_LEFT
    #undef MP_BLOCK_MARGIN_LEFT
    #undef MP_BLOCK_MARGIN_RIGHT
}

HTH,
DC




 
Back
Top Bottom