Solved Hole death sound

Question that is answered or resolved.

dantedevil

Well-known member
As everyone knows, my Mod has a large number of different deaths for each enemy. For this reason, I do not use the default death sound. This does not look good when the enemies fall into a hole, since it would be much better if they had a specific death scream sound for when they fall into a hole.
 
Sorry, but I will not allow that because it adds more internal complexity for a feature that's already supported. It's always been possible to have pit sounds. See here - made long, LONG before we had a pit attack type. You just had to do some simple math checks.


Anyway, it's even easier now. All you need now is to check the attack type that killed entity in your ondeath or takedamagescript. If it's ATTACK_PIT, play the death sound. That's it. You don't need any special animations or extra types.

Code:
// This is a built in function that runs when a script first loads - you put stuff in here that only needs to
// be run once for setting stuff up. Add it to your death script.
void oncreate()
{
     int sample; // Sound sample reference.

     // Load sound into memory and assign it a reference.
     sample = loadsample("path_to_your_sound_file");

     // Store in a localvar so other functions can use the sample, but other scripts can't.
     setlocalvar("sound_pit", sample);
}

// Add this code inside of your main()

int type; // Attack type that did the killing.
int sample; // Sound sample reference.

// Get attack type
type = getlocalcar("type");

// Pit?
if(type == openborconstant("ATK_PIT"))
{
     // Get the sample we preloaded in oncreate() and play it.
     sample = getlocalvar("sound_pit");
     playsample(sample, 1, 255, 255, 100, 0);
}

DC
 
dantedevil said:
As everyone knows, my Mod has a large number of different deaths for each enemy. For this reason, I do not use the default death sound. This does not look good when the enemies fall into a hole, since it would be much better if they had a specific death scream sound for when they fall into a hole.

Dante, there are specific attack types for pretty much all the cases you can imagine. Check in the manual for openborconstant attack type:

"ATK_ITEM" = attack type when hit by an "itembox" from an item.
"ATK_LAND" = is for damage taken when damage_on_landing is applied, or from the engine's default Throw system.
"ATK_LIFESPAN = attack type which happens when the LIFESPAN value is reached
"ATK_PIT" = its an attack type which happens when you fall on a hole
"ATK_TIMEOVER = attack type which happens when you got a time over

As DC said, its just a simple math here.
 
Sorry, I try to understand how works this, but all it's new to me.

I create a this file deaths.c
Code:
void oncreate()
{
     int sample; // Sound sample reference.

     // Load sound into memory and assign it a reference.
     sample = loadsample("data/sounds/fhole.wav");

     // Store in a localvar so other functions can use the sample, but other scripts can't.
     setlocalvar("sound_pit", sample);
}

// Add this code inside of your main()

int type; // Attack type that did the killing.
int sample; // Sound sample reference.

// Get attack type
type = getlocalcar("type");

// Pit?
if(type == openborconstant("ATK_PIT"))
{
     // Get the sample we preloaded in oncreate() and play it.
     sample = getlocalvar("sound_pit");
     playsample(sample, 1, 255, 255, 100, 0);
}

So next add this line in the character header:

ondeathscript data/scripts/deaths.c

I know this is wrong, but I don't understand exactly how works
 
I really appreciate all your help. But is there any manual that indicates step by step how to do this?
Sorry , by the indications that you give me I can not follow them, since they escape my understanding.
:-\
 
dantedevil said:
I really appreciate all your help. But is there any manual that indicates step by step how to do this?

Script is like a digital set of Lego blocks. There will never be a comprehensive "step-by-step" manual on how to do specific tasks with script, because that's the whole point - you custom build them to suit your needs. What we can do is provide manuals on how script works in general (of which there are many), and help you with tasks like this when they arise.

Now on to getting this done. I just assumed you did have a death script because your module is pretty complex, but it's no big deal if you don't. Let's get one made.

1. Create a blank text file with whatever name will help keep you organized, and rename the extension to ".c". Now you have a blank script.

2. Copy this into the script file:

Code:
// This function runs when a script is first loaded. It's good for initializing things that
// only need to be done one time, like pre-loading a sound or image file.
void oncreate()
{
     log("\n\n Created.");
}

// This function runs when a script is unloaded. It's good for cleaning stuff up.
void ondestroy()
{
     log("\n\n Destroyed.");
}

// This is the main function. This is what runs each time the script executes. It is required
// for all scripts except "animation" (because animation inserts a main() automatically). If
// you forget to add it, the engine will shut down and log an error.
void main()
{
     log("\n\n Main.");
}

3. Add this script to your model by putting its path in the ondeathscript header.

Now fire up your module, and if everything loads up OK, check the log. When an entity with this script spawns into play, you should see "Created" in the log. KO the entity, and you should then see "Main". When the entity is unloaded and removed from play, then "Destroyed". should appear. Now we know there's a working ondeathscript, and can move to the next portion. Let me know when you're done.

Protip: Open the log in your browser instead of Notepad - then you can just hit refresh to see any changes as you test.

DC
 
Awesome. Let's get the next portion done.

1. Get the pit death sound you want to use ready.

2. Add this to the top of the script file, outside of any functions. Note the "path-to-your-sound-file-here". Edit that to match the path and filename of your sound file. These are constants that we use to make the code more readable and easy to edit later.

Code:
#ifndef ONDEATH
#define ONDEATH 1

#define ONDEATH_LOAD_SAMPLE_LOG     0

#define ONDEATH_KEY_SAMPLE_ID       "sndsample_0"

#define ONDEATH_SOUND_PATH          "path-to-your-sound-file-here"
#define ONDEATH_SOUND_LOOP          0
#define ONDEATH_SOUND_PRIORITY      0
#define ONDEATH_SOUND_VOLUME_LEFT   255
#define ONDEATH_SOUND_VOLUME_RIGHT  255
#define ONDEATH_SOUND_VOLUME_SPEED  100

#endif // ONDEATH

3. Change the oncreate() function part of the script so it looks like this:

Code:
void oncreate()
{
    int sample_id;
    
    // Load the sound file and establish its ID.
    sample_id = loadsample(ONDEATH_SOUND_PATH, ONDEATH_LOAD_SAMPLE_LOG);
    
    // Store the sound sample for other functions.
    setlocalvar(ONDEATH_KEY_SAMPLE_ID, sample_id);

    // Put entries in the log for testing.
    log("\n\n Create.")
    log("\n Sample loaded: " + sample_id);
}

Now run the test again. This time when the entity is spawned in, you should see an entry in the log that indicates your sample was loaded with an ID number assigned.

DC
 
I really appreciate your help, my friend, but moments like this make me want to give up everything, because they frustrate me too much and take away my desire to move forward.
Lately I've made great advances in my game, but when I get stuck with things like this, I really lose the motivation I had, after everything I've overcome, it's hard for me to deal with more obstacles.

Here the log:
Code:
Script error: data/scripts/deaths.c, line 31: Invalid function call or expression 'log' (in production 'postfix_expr2')

 

    log("\n Sample loaded: " + sample_id);

    ^

 

 

 

Script error: data/scripts/deaths.c, line 31: Unknown error ';' (in production 'stmt_list2')

 

    log("\n Sample loaded: " + sample_id);

                                         ^

 

 

********** An Error Occurred **********

*            Shutting Down            *

 

Failed to parse script file: 'data/scripts/deaths.c'!

Total Ram: 2147483647 Bytes

Free Ram: 2147483647 Bytes

Used Ram: 159698944 Bytes

Here my deaths.c
Code:
#ifndef ONDEATH
#define ONDEATH 1

#define ONDEATH_LOAD_SAMPLE_LOG     0

#define ONDEATH_KEY_SAMPLE_ID       "sndsample_0"

#define ONDEATH_SOUND_PATH          "path-to-your-sound-file-here"
#define ONDEATH_SOUND_LOOP          0
#define ONDEATH_SOUND_PRIORITY      0
#define ONDEATH_SOUND_VOLUME_LEFT   255
#define ONDEATH_SOUND_VOLUME_RIGHT  255
#define ONDEATH_SOUND_VOLUME_SPEED  100

#endif // ONDEATH

// This function runs when a script is first loaded. It's good for initializing things that
// only need to be done one time, like pre-loading a sound or image file.
void oncreate()
{
    int sample_id;
   
    // Load the sound file and establish its ID.
    sample_id = loadsample("data/sounds/m1death.wav", 0);
   
    // Store the sound sample for other functions.
    setlocalvar("sndsample_0", sample_id);

    // Put entries in the log for testing.
    log("\n\n Create.")
    log("\n Sample loaded: " + sample_id);
}

// This function runs when a script is unloaded. It's good for cleaning stuff up.
void ondestroy()
{
     log("\n\n Destroyed.");
}

// This is the main function. This is what runs each time the script executes. It is required
// for all scripts except "animation" (because animation inserts a main() automatically). If
// you forget to add it, the engine will shut down and log an error.
void main()
{
     log("\n\n Main.");
}
 
dantedevil said:

Don't be so melodramatic friend. Mistakes happen, and nothing worth doing is ever easy. In this case, it's just a simple typo.

This line right here - it should have a semi-colon at the end and I left it off.
Code:
log("\n\n Create.")

Just add the semi-colon so it looks like this:
Code:
log("\n\n Create.");


DC
 
Well my friend,  everything runs ok now.

In the log I can see:

Sample loaded: 360

But the problem is when enemy fall in the hole, never hear the sound of the death.
 
Of course not. We aren't done. I'm taking you through step by step.

DC
 
We're almost there. Replace the main() function with this.

Code:
void main()
{
    int sample_id;      // Sound sample ID.
    int attack_type;    // Damaging attack type.
    
    // Get attack type that killed us.
    attack_type = getlocalvar("attacktype");
    
    // Get the pre-loaded sample ID.
    sample_id = getlocalvar(ONDEATH_KEY_SAMPLE_ID);
    
    playsample(sample_id, ONDEATH_SOUND_PRIORITY, ONDEATH_SOUND_VOLUME_LEFT, ONDEATH_SOUND_VOLUME_RIGHT, ONDEATH_SOUND_VOLUME_SPEED, ONDEATH_SOUND_LOOP);

    log("\n\n Main.");
    log("\n Attack type: " + attack_type);
    log("\n Sample id: " + sample_id);
}

Now test again. You should hear the pit death whenever the entity is KO'd - it won't matter if they're in a pit. We'll add that logic in the next step.

DC
 
dantedevil said:
All runs perfect until now. :)

Great, now let's add the pit check logic. Replace main() with this, and note the attack_type check I added.

Code:
void main()
{
    int sample_id;      // Sound sample ID.
    int attack_type;    // Damaging attack type.
    
    // Get attack type that killed us.
    attack_type = getlocalvar("attacktype");
    
    // Get the pre-loaded sample ID.
    sample_id = getlocalvar(ONDEATH_KEY_SAMPLE_ID);
    
    // If a pit killed us, play the pit sound. "Ahhhhhhhhhhhhh!"...*splat* >:)
    if(attack_type == openborconstant("ATK_PIT"))
    {
      playsample(sample_id, ONDEATH_SOUND_PRIORITY, ONDEATH_SOUND_VOLUME_LEFT, ONDEATH_SOUND_VOLUME_RIGHT, ONDEATH_SOUND_VOLUME_SPEED, ONDEATH_SOUND_LOOP);  
    }
    
    log("\n\n Main.");
    log("\n Attack type: " + attack_type);
    log("\n Sample id: " + sample_id);
}

Test one more time, and you should only hear the sound when entity is killed by a pit.

DC
 
Bravo!!!

Works perfect my friend, thanks!

I appreciate very much, all your patience and your time to explain step by step how it works.
Thanks again my friend!
 
Awesome. This gets you the basic idea. There is a lot more we could do, but I'll not bug you with that for now. You do need to remove all the log() lines though, or else your log will still get spammed with all those testing entries.

You can either delete them outright, or comment them out by inserting "//". It works just like "#" in non-script text files.

Code:
//log("..blah blah blah...");

DC
 
Back
Top Bottom