Streets of Rage X (Windows / Android)

In Progress Streets of Rage X (Windows / Android) Beta 33

No permission to download
The project is currently under development.
@Kratus I've testing the last demo and I having an issue on windows -
I feel that there are small stutters during the game, something that didn't happen in the other versions I've played before - I was going to record a video for my channel, but I gave up because of this.

Generally, these small chokes occur for two reasons (and I suspect that it is one of them or even both happening at the same time):

1 - Load of sound effects on the fly. I noticed that when using the native "sound" command, the engine loads all the sound effects along with the sprites when loading an entity into memory. However, when we load a sound effect via script, the engine will only load this sound effect into memory when the script that loads it is executed. So both inline type scripts or animationscript functions only load the effect into memory when we execute that script.

One way I found to not suffer from this is to make a "follow" animation that I don't use for anything in the game, just to place the sound effects paths (since the engine checks if a sample has already been loaded into memory before load again)

2- HD reading speed. I have this problem if I try to play my game, in "data" format, from my external HD. Generally, if I use it in .pak format, it minimizes a lot.

But in your case, I'm reading from my HD SSD, which has no problem with that. I suspect it's the encryption method used (I'll explain more by dm later).
 
I feel that there are small stutters during the game, something that didn't happen in the other versions I've played before - I was going to record a video for my channel, but I gave up because of this.
@O Ilusionista
Thanks, I will check it. All my tests were made in the data folder directly, maybe this is explains why I didn't see it before. I will do some full playthroughs with the mixed executable to see if it happens.

1 - Load of sound effects on the fly. I noticed that when using the native "sound" command, the engine loads all the sound effects along with the sprites when loading an entity into memory. However, when we load a sound effect via script, the engine will only load this sound effect into memory when the script that loads it is executed. So both inline type scripts or animationscript functions only load the effect into memory when we execute that script.
Yeah, indeed the entire sound system is scripted and to save some memory they are loaded only when used. But in case it causes problems to the mixed exe, I prefer give away from this method and load all samples in the first loading screen directly (I already load some assets there), the external musics are more important than saving memory in this case.

Thanks for the feedbacks, buddy :)

Why does Neo X shoot a missile at Mr. X's brain when you beat him?
My thoughts when I created this way was just a self destruction system, which would make the entire base explode in case someone was able to break the glass tube and destroy Mr. X's brain. In the end, Mr. X will be killed but bringing everyone with him.

So, seeing that heroes are successful at beating Neo. X, his last action was to suicide, trying to kill all heroes and destroying the city at the same time before Dr. Zan deactivates the entire system with no destruction.

But you can consider a Neo. X malfunctioned too due to getting too many punches/kicks in his motherboard hahaha.
 
Last edited:
@O Ilusionista
Thanks, I will check it. All my tests were made in the data folder directly, maybe this is explains why I didn't see it before. I will do some full playthroughs with the mixed executable to see if it happens.


Yeah, indeed the entire sound system is scripted and to save some memory they are loaded only when used. But in case it causes problems to the mixed exe, I prefer give away from this method and load all samples in the first loading screen directly (I already load some assets there), the external musics are more important than saving memory in this case.

Thanks for the feedbacks, buddy :)


My thoughts when I created this way was just a self destruction system, which would make the entire base explode in case someone was able to break the glass tube and destroy Mr. X's brain. In the end, Mr. X will be killed but bringing everyone with him.

So, seeing that heroes are successful at beating Neo. X, his last action was to suicide, trying to kill all heroes and destroying the city at the same time before Dr. Zan deactivates the entire system with no destruction.

But you can consider a Neo. X malfunctioned too due to getting too many punches/kicks in his motherboard hahaha.
What happens if you get hit by that last missile Neo X shoots?
 
1 - Load of sound effects on the fly. I noticed that when using the native "sound" command, the engine loads all the sound effects along with the sprites when loading an entity into memory. However, when we load a sound effect via script, the engine will only load this sound effect into memory when the script that loads it is executed. So both inline type scripts or animationscript functions only load the effect into memory when we execute that script.

Yeah, indeed the entire sound system is scripted and to save some memory they are loaded only when used. But in case it causes problems to the mixed exe, I prefer give away from this method and load all samples in the first loading screen directly (I already load some assets there), the external musics are more important than saving memory in this case.

FWIW, I found it more organized to load sounds on start-up and dump their IDs into a multidimensional array. Obviously this uses some memory, but it's well worth it for the performance gain and versatility. Aside from pre-loading the sounds, I can choose randomly from a hierarchy of <group (ex. model> -> <type (ex. heavy attack)> -> <individual sounds>. So when it's time to play, I just reference the type, and then I get a random sound from sounds under a type.

This is function responsible for preloading a sound:

C:
/*
* Caskey, Damon V.
* 2018-10-23
*
* Load a sound file and place its sample ID with designated category
* and type into the sound array for later use.
*/
void dc_fidelity_setup(char category, int type, char file)
{
    void category_list;    // Key - Category, Value - Sound types array.
    void type_list;        // Key - Sound Type, Value - Sound index array.
    void index_list;    // Key - Numeric, Value - Sound file index.
    int  sample_id;        // Sample ID loaded to element.
    
    int size;    // Array size.
    int i;        // Loop index.

    /*
    * Get the category list array.
    * If we don't have an array, initialize a new one.
    */

    category_list = dc_fidelity_get_member_category_list();
    
    if (!category_list)
    {
        /*
        * Create array and store its pointer in
        * a globalvar for future access.
        */

        category_list = array(0);
        
        dc_fidelity_set_member_category_list(category_list);
    }

    /*
    * Get array of sound types for a category.
    * If we don't have an array, initialize a new one.
    */

    type_list = get(category_list, category);
    
    if (!type_list)
    {
        /*
        * Create array and store its pointer in
        * a globalvar for future access.
        */

        type_list = array(0);
        
        set(category_list, category, type_list);
    }

    /*
    * Get array of sound indexes for a sound type.
    * If we don't have an array, initialize a new one.
    */

    index_list = get(type_list, type);
    
    if (!index_list)
    {
        /*
        * Create array and store its pointer in
        * a globalvar for future access.
        */

        index_list = array(0);
        
        set(type_list, type, index_list);
    }

    /*
    * Get the array size, we can use this as
    * the index since we want to add an element.
    */
    size = size(index_list);

    /*
    * Load the sample, then add a new
    * array element and populate its
    * value with the sample ID.
    */
    
    sample_id = loadsample(file);

    add(index_list, size, sample_id);
    
    if (DC_FIDELITY_LOGGING & DC_FIDELITY_LOG_LOAD)
    {
        /* Output to the log. */
        log("\n DC Fidelity - Loading sound sample");
        log("\n");
        log("\t");
        log("File:\t\t" + file);
        log("\n");
        log("\t");
        log("Category:\t" + category);
        log("\n");
        log("\t");
        log("Type:\t\t" + type);
        log("\n");
        log("\t");
        log("Index:\t\t" + size);
        log("\n");
        log("\t");
        log("Sample ID:\t" + sample_id);
        log("\n...done. \n");
    }   
}

Here's the implementation for a model.

C:
/* Amazon */
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_SHOUT_LIGHT, "data/chars/amazon/sounds/v_atk_0.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_SHOUT_LIGHT, "data/chars/amazon/sounds/v_atk_1.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_SHOUT_LIGHT, "data/chars/amazon/sounds/v_atk_2.wav");

    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_SHOUT_MEDIUM, "data/chars/amazon/sounds/v_atk_0.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_SHOUT_MEDIUM, "data/chars/amazon/sounds/v_atk_1.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_SHOUT_MEDIUM, "data/chars/amazon/sounds/v_atk_2.wav");

    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_SHOUT_HEAVY, "data/chars/amazon/sounds/v_atk_0.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_SHOUT_HEAVY, "data/chars/amazon/sounds/v_atk_1.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_SHOUT_HEAVY, "data/chars/amazon/sounds/v_atk_2.wav");

    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_BATTLE_TAUNT, "data/chars/amazon/sounds/v_bt_0.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_BATTLE_TAUNT, "data/chars/amazon/sounds/v_bt_1.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_BATTLE_TAUNT, "data/chars/amazon/sounds/v_bt_2.wav");

    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_PAIN, "data/chars/amazon/sounds/v_pain_0.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_PAIN, "data/chars/amazon/sounds/v_pain_1.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_PAIN, "data/chars/amazon/sounds/v_pain_2.wav");

    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_PAIN_FALL, "data/chars/amazon/sounds/v_pain_0.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_PAIN_FALL, "data/chars/amazon/sounds/v_pain_1.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_PAIN_FALL, "data/chars/amazon/sounds/v_pain_2.wav");

    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_KO, "data/chars/amazon/sounds/v_ko_0.wav");   

    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_LAUGH, "data/chars/amazon/sounds/v_laugh_0.wav");

    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_BLOCK_TAUNT, "data/chars/amazon/sounds/v_think_again_0.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_BLOCK_TAUNT, "data/chars/amazon/sounds/v_useless_0.wav");   

    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_COMMAND, "data/chars/amazon/sounds/v_useless_0.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_COMMAND, "data/chars/amazon/sounds/v_useless_0.wav");

    dc_fidelity_setup("bor_steam", DC_FIDELITY_TYPE_VOICE_SPAWN_NEW, "data/sounds/custom/v_spawn_0.wav");

HTH,
DC
 
FWIW, I found it more organized to load sounds on start-up and dump their IDs into a multidimensional array. Obviously this uses some memory, but it's well worth it for the performance gain and versatility. Aside from pre-loading the sounds, I can choose randomly from a hierarchy of <group (ex. model> -> <type (ex. heavy attack)> -> <individual sounds>. So when it's time to play, I just reference the type, and then I get a random sound from sounds under a type.

This is function responsible for preloading a sound:

C:
/*
* Caskey, Damon V.
* 2018-10-23
*
* Load a sound file and place its sample ID with designated category
* and type into the sound array for later use.
*/
void dc_fidelity_setup(char category, int type, char file)
{
    void category_list;    // Key - Category, Value - Sound types array.
    void type_list;        // Key - Sound Type, Value - Sound index array.
    void index_list;    // Key - Numeric, Value - Sound file index.
    int  sample_id;        // Sample ID loaded to element.
   
    int size;    // Array size.
    int i;        // Loop index.

    /*
    * Get the category list array.
    * If we don't have an array, initialize a new one.
    */

    category_list = dc_fidelity_get_member_category_list();
   
    if (!category_list)
    {
        /*
        * Create array and store its pointer in
        * a globalvar for future access.
        */

        category_list = array(0);
       
        dc_fidelity_set_member_category_list(category_list);
    }

    /*
    * Get array of sound types for a category.
    * If we don't have an array, initialize a new one.
    */

    type_list = get(category_list, category);
   
    if (!type_list)
    {
        /*
        * Create array and store its pointer in
        * a globalvar for future access.
        */

        type_list = array(0);
       
        set(category_list, category, type_list);
    }

    /*
    * Get array of sound indexes for a sound type.
    * If we don't have an array, initialize a new one.
    */

    index_list = get(type_list, type);
   
    if (!index_list)
    {
        /*
        * Create array and store its pointer in
        * a globalvar for future access.
        */

        index_list = array(0);
       
        set(type_list, type, index_list);
    }

    /*
    * Get the array size, we can use this as
    * the index since we want to add an element.
    */
    size = size(index_list);

    /*
    * Load the sample, then add a new
    * array element and populate its
    * value with the sample ID.
    */
   
    sample_id = loadsample(file);

    add(index_list, size, sample_id);
   
    if (DC_FIDELITY_LOGGING & DC_FIDELITY_LOG_LOAD)
    {
        /* Output to the log. */
        log("\n DC Fidelity - Loading sound sample");
        log("\n");
        log("\t");
        log("File:\t\t" + file);
        log("\n");
        log("\t");
        log("Category:\t" + category);
        log("\n");
        log("\t");
        log("Type:\t\t" + type);
        log("\n");
        log("\t");
        log("Index:\t\t" + size);
        log("\n");
        log("\t");
        log("Sample ID:\t" + sample_id);
        log("\n...done. \n");
    }  
}

Here's the implementation for a model.

C:
/* Amazon */
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_SHOUT_LIGHT, "data/chars/amazon/sounds/v_atk_0.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_SHOUT_LIGHT, "data/chars/amazon/sounds/v_atk_1.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_SHOUT_LIGHT, "data/chars/amazon/sounds/v_atk_2.wav");

    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_SHOUT_MEDIUM, "data/chars/amazon/sounds/v_atk_0.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_SHOUT_MEDIUM, "data/chars/amazon/sounds/v_atk_1.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_SHOUT_MEDIUM, "data/chars/amazon/sounds/v_atk_2.wav");

    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_SHOUT_HEAVY, "data/chars/amazon/sounds/v_atk_0.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_SHOUT_HEAVY, "data/chars/amazon/sounds/v_atk_1.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_SHOUT_HEAVY, "data/chars/amazon/sounds/v_atk_2.wav");

    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_BATTLE_TAUNT, "data/chars/amazon/sounds/v_bt_0.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_BATTLE_TAUNT, "data/chars/amazon/sounds/v_bt_1.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_BATTLE_TAUNT, "data/chars/amazon/sounds/v_bt_2.wav");

    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_PAIN, "data/chars/amazon/sounds/v_pain_0.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_PAIN, "data/chars/amazon/sounds/v_pain_1.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_PAIN, "data/chars/amazon/sounds/v_pain_2.wav");

    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_PAIN_FALL, "data/chars/amazon/sounds/v_pain_0.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_PAIN_FALL, "data/chars/amazon/sounds/v_pain_1.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_PAIN_FALL, "data/chars/amazon/sounds/v_pain_2.wav");

    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_KO, "data/chars/amazon/sounds/v_ko_0.wav");  

    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_LAUGH, "data/chars/amazon/sounds/v_laugh_0.wav");

    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_BLOCK_TAUNT, "data/chars/amazon/sounds/v_think_again_0.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_BLOCK_TAUNT, "data/chars/amazon/sounds/v_useless_0.wav");  

    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_COMMAND, "data/chars/amazon/sounds/v_useless_0.wav");
    dc_fidelity_setup("Amazon", DC_FIDELITY_TYPE_VOICE_ATTACK_COMMAND, "data/chars/amazon/sounds/v_useless_0.wav");

    dc_fidelity_setup("bor_steam", DC_FIDELITY_TYPE_VOICE_SPAWN_NEW, "data/sounds/custom/v_spawn_0.wav");

HTH,
DC
@DCurrent
Thanks man! Interesting, you are storing/playing samples without using local/entity/global variables, I will try this way. I'm wondering about how to clear these kinds of variables, because in SORX I have a routine at the title screen that always runs the clearglobalvar/clearlocalvar functions to save memory.
 
Here's a playthrough I did of route 1 with Shiva, I had a lot of fun while playing, all the customizable options really make for a unique experience every time. hands down the best beat em' up I've ever played.


The only thing I would change is the loading screens, It breaks the immersion for me and the overall feel of the game. I edited them out of the video so you can see what I mean. It would be cool if they were in a gallery mode via the main menu or something but in between levels the art throws me off a bit, even just a black screen would be better.
 
Last edited:
@DCurrent
Thanks man! Interesting, you are storing/playing samples without using local/entity/global variables, I will try this way. I'm wondering about how to clear these kinds of variables, because in SORX I have a routine at the title screen that always runs the clearglobalvar/clearlocalvar functions to save memorvariables.

It's still a global variable, but just one that keeps the parent array pointer. When the game shuts down, I have a routine that works through the elements to delete the nested arrays, then the parent array, and then of course the global var.

Multidimensional arrays are a royal pain to conceptualize, but they are incredibly powerful once you get used to them. You can essentially create your own structures and objects with them almost like we do in the engine's source code.

DC
 
It's still a global variable, but just one that keeps the parent array pointer. When the game shuts down, I have a routine that works through the elements to delete the nested arrays, then the parent array, and then of course the global var.

Multidimensional arrays are a royal pain to conceptualize, but they are incredibly powerful once you get used to them. You can essentially create your own structures and objects with them almost like we do in the engine's source code.

DC
I liked the way you categorize them, it may be useful in SORX because I have 4 types of samples (SOR1/2/3/X). One more question, in what event this code must be used?

Here's a playthrough I did of route 1 with Shiva, I had a lot of fun while playing, all the customizable options really make for a unique experience every time. hands down the best beat em' up I've ever played.

Great :) I'm glad you liked the game! I still have a lot of work to do on the game's balance but I think the base structure is going well according to the feedbacks.

The only thing I would change is the loading screens, It breaks the immersion for me and the overall feel of the game. I edited them out of the video so you can see what I mean. It would be cool if they were in a gallery mode via the main menu or something but in between levels the art throws me off a bit, even just a black screen would be better.
Yeah, I thought of removing the images as loading screens and putting something simpler like a small animation somewhere on a black screen. I will take some tests, thanks for the suggestion.
 
Last edited:
WTF is up with the bosses in this mod???? Why do they take so much damage??? This isn't a fun challenge it's a slog to wittle them down. Am i doing something wrong?
 
Why does the game crash when i copy from unpacked android pak to unpacked SoR 2X 2.3 folder? This is due to an outdated openbor version?
 
This is due to an outdated openbor version?
Exactly, SORX will not work in any other engine except the one that came with the game.

WTF is up with the bosses in this mod???? Why do they take so much damage??? This isn't a fun challenge it's a slog to wittle them down. Am i doing something wrong?
Thanks for the feedback, I'm working to improve the gameplay.

I wrote some instructions in the changelog.txt related to it, indeed the game received a huge rebalance on all health/damages. Once it's in a beta state it means that there's many adjustments to be made yet.
Now the game has health values similar to the classics, players reduced from 400 to 100 and bosses are scaled to every 100. This value corresponds to the real life bar size, which is 100px and it was done to allow the original life bar style. All the damages were updated too but still needs adjustments.

1685061967788.png

However, the result is in fact the opposite, now enemies/bosses can be killed faster if you do a good combo+rage, like in the video below:
 
The gameplay seems to be very promising from what I've observed in the videos. However, if you have the opportune time, I simply recommended changing SOR2 Shiva's KO scream to match the one in his BK3/SOR3 incarnation. The latter forementioned should apply to Axel and Blaze as well as Yamato.
 
Back
Top Bottom