Register FAQ Search Today's Posts Mark Forums Read
Go Back   JazzJackrabbit Community Forums » Open Forums » JCS & Scripting

How can I add a sound effect to my level with AS?

jjturbo9

JCF Member

Joined: Mar 2025

Posts: 6

jjturbo9 has disabled reputation

Mar 23, 2025, 05:40 PM
jjturbo9 is offline
Reply With Quote
Red face How can I add a sound effect to my level with AS?

I'm trying to trigger a sound when the player walks into a certain tile. On the tile is a trigger zone event and I would like to trigger the sound COMMON_ITEMTRE when the players walks through the trigger zone, but only that particular trigger zone ID. I'm a noob with AS and programming in general, I tried to understand the AS readme, searched some threads, checked some code snippets from this site and looked how other users use AS in their levels but I still don't get it to work. I made the sugar rush counter code snippet from Bloody Body work with AS though so if I know the code I can do it.

Thank you very much in advance!
Violet CLM

JCF Éminence Grise

Joined: Mar 2001

Posts: 11,090

Violet CLM has disabled reputation

Mar 24, 2025, 06:50 AM
Violet CLM is offline
Reply With Quote
This sounds like a perfect use case for an onFunction# hook, like

Code:
void onFunction0(jjPLAYER@ player) {
  if (!jjTriggers[66]) {
    jjTriggers[66] = true;
    jjSample(player.xPos, player.yPos, SOUND::COMMON_ITEMTRE);
  }
}
but replace "66" with whatever "that particular trigger zone ID" is. If you want to reuse this system for multiple trigger IDs, not just one, you would use the parameter on the Text event and then:

Code:
void onFunction0(jjPLAYER@ player, uint8 triggerID) {
  if (!jjTriggers[triggerID]) {
    jjTriggers[triggerID] = true;
    jjSample(player.xPos, player.yPos, SOUND::COMMON_ITEMTRE);
  }
}
__________________
jjturbo9

JCF Member

Joined: Mar 2025

Posts: 6

jjturbo9 has disabled reputation

Mar 24, 2025, 12:18 PM
jjturbo9 is offline
Reply With Quote
Thanks a lot!! I will try this code now. I wonder why you have to write player.xPos and player.yPos though. Seems irrelevant to me, what am I missing?

I just tried it but I don't hear the sound yet. To be extra clear about what I try:
When Jazz (or another) walks through the event 'Trigger Zone 21 | onoff 1 | switch 0' the sound COMMON_ITEMTRE has to be played. But only the first time he walks through it, I don't want the sound to trigger every time, only when the thing is triggered the first time. But I think that would be the case automatically anyways?

I just copy/pasted the first code you send in my AS file where the other AS code already worked. And replaced 66 for 21, but when I trigger the thing I don't hear anything. I already checked if I wrote COMMON_ITEMTRE correctly and that's not the issue...

Code:
//Sugar rush counter
bool onDrawLives(jjPLAYER@ player, jjCANVAS@ screen) {
    screen.drawSprite(590, 45, ANIM::PICKUPS, 1, jjGameTicks>>2, -1, SPRITE::NORMAL);
    screen.drawSprite(580, 30, ANIM::PICKUPS, 13, jjGameTicks>>2, -1, SPRITE::NORMAL);
    screen.drawString(570, 15, "SUGAR RUSH", STRING::SMALL, STRING::PALSHIFT, 16);
    screen.drawString(600, 35, formatInt(player.food%100, "1") + " / 100", STRING::MEDIUM, STRING::PALSHIFT, 16);
    return false;
}
//Sound effect for getting key
void onFunction0(jjPLAYER@ player) {
  if (!jjTriggers[21]) {
    jjTriggers[21] = true;
    jjSample(player.xPos, player.yPos, SOUND::COMMON_ITEMTRE);
  }
}
I'm curious what the issue is but I have no idea tbh. Hope you can help At least the original code still works even with this code in it, previously when I added non-working code the sugar rush counter stopped working too.

Last edited by jjturbo9; Mar 24, 2025 at 12:32 PM.
Seren

JCF Member

Joined: Feb 2010

Posts: 872

Seren is a name known to allSeren is a name known to allSeren is a name known to allSeren is a name known to allSeren is a name known to allSeren is a name known to all

Mar 25, 2025, 01:59 AM
Seren is offline
Reply With Quote
Quote:
Originally Posted by jjturbo9 View Post
I wonder why you have to write player.xPos and player.yPos though. Seems irrelevant to me, what am I missing?
The main reason is that most people have two ears rather than one. Our brains like to believe every sound is coming from a point in space, and if that point is distant, the sound gets quieter, and if it's to our left, we hear it better with our left ear, etc. Most gaming computer setups support this notion by using audio output peripherals with at least two independent speakers, such as stereo headphones, but sometimes more, such as surround sound systems. For this reason, audio libraries allow you to precisely position the source of each sound in space, which in this case Violet guessed you'd want to be where the player is. You can imagine potentially manipulating this value to instead guide the player towards the direction where a door just opened.

Quote:
Originally Posted by jjturbo9 View Post
I just tried it but I don't hear the sound yet. To be extra clear about what I try:
When Jazz (or another) walks through the event 'Trigger Zone 21 | onoff 1 | switch 0' the sound COMMON_ITEMTRE has to be played. But only the first time he walks through it, I don't want the sound to trigger every time, only when the thing is triggered the first time. But I think that would be the case automatically anyways?
The scripting system is very powerful and could detect the player entering a trigger zone and doing everything you describe, but the code to do so would be more complicated than what Violet is suggesting. Violet's suggestion is to use a text event instead, which JJ2+ modifies such that, with the right parameters, it can directly trigger execution of user-defined AngelScript code specified by functions named onFunction0 through onFunction255. The details show up early in the introduction section of the AngelScript readme, which you mentioned you tried reading, so Violet might've assumed you would implicitly understand you have to change the event in the level too.

The code Violet sent says: "when onFunction0 is called, if trigger 66 is currently off, turn trigger 66 on and play this sound." So it encompasses the functionality of a trigger zone within it, meaning you can safely replace the relevant trigger zone in your level with a text event (text ID parameter should be 0 to call onFunction0, AngelScript parameter should be 1 to inform the event you're trying to execute a script function and not display text to the player). Note that, the way Violet formulated the script, the sound will indeed play only once, unless you later deactivate the trigger (e.g. by dying) and come back to activate it again, but it's definitely deliberate wording on her part and not "the case automatically."

Quote:
Originally Posted by jjturbo9 View Post
At least the original code still works even with this code in it, previously when I added non-working code the sugar rush counter stopped working too.
This is because this code is not erroneous, it just doesn't do anything unless the level contains the relevant text event. Your script will only fail to run wholesale if there's an error in it that makes the game fail to understand what you were trying to do. When this happens and AngelscriptDebug is enabled in your plus.ini, information about the error is printed to the chatlogger - it's a good setting to have enabled if you write scripts, the details again are mentioned in the introduction of the AngelScript readme.
__________________

I am an official JJ2+ programmer and this has been an official JJ2+ statement.
jjturbo9

JCF Member

Joined: Mar 2025

Posts: 6

jjturbo9 has disabled reputation

Mar 25, 2025, 05:20 AM
jjturbo9 is offline
Reply With Quote
Thank you Seren, I will try this later. I understand most of what you explained, and Violet's code makes sense now. But what do you mean with 'AngelScript parameter should be 1'. What exactly should I put to '1'? Ooo, wait.. I think I remember I saw an AngelScript parameter in the text event window, you probably mean that.... Right? Anyways, thanks!!
jjturbo9

JCF Member

Joined: Mar 2025

Posts: 6

jjturbo9 has disabled reputation

Mar 25, 2025, 05:29 AM
jjturbo9 is offline
Reply With Quote
Wow, it worked now!! After you explained it I actually remembered reading something about this in the readme but didn't think of using it here like this. Anyways this is my working code now:

Code:
//Sugar rush counter
bool onDrawLives(jjPLAYER@ player, jjCANVAS@ screen) {
    screen.drawSprite(590, 45, ANIM::PICKUPS, 1, jjGameTicks>>2, -1, SPRITE::NORMAL);
    screen.drawSprite(580, 30, ANIM::PICKUPS, 13, jjGameTicks>>2, -1, SPRITE::NORMAL);
    screen.drawString(570, 15, "SUGAR RUSH", STRING::SMALL, STRING::PALSHIFT, 16);
    screen.drawString(600, 35, formatInt(player.food%100, "1") + " / 100", STRING::MEDIUM, STRING::PALSHIFT, 16);
    return false;
}
//Sound effect for getting key
void onFunction100(jjPLAYER@ player) {
  if (!jjTriggers[21]) {
    jjTriggers[21] = true;
    jjSample(player.xPos, player.yPos, SOUND::COMMON_ITEMTRE);
  }
}
I think I'm gonna choose another sound though, now that I heard it come together. And is there a way to make it louder? Probably not necessary but just wondering, might be nice as a final touch.
jjturbo9

JCF Member

Joined: Mar 2025

Posts: 6

jjturbo9 has disabled reputation

Mar 25, 2025, 06:06 AM
jjturbo9 is offline
Reply With Quote
Excuse me, initially I wrote this message to ask a question but I already found an answer while explaining the question in detail xD So there's no question here anymore except maybe what I asked at the end of this message, although it's not that important because the code works now.
.
I decided I want the door to open when Jazz stands close to the door, as if Jazz opened the door with the key. Instead of opening together with getting the key. So I have to add another piece of code. Somehow it worked already with what I made up, but only because I made it simpler because I don't know how to code 2 'if' functions.

I want the door to open when walking through text event 101 but only if you walked through text event 100 first. I wrote this:

Code:
 
//Sound effect for getting key
void onFunction100(jjPLAYER@ player) {
  if (!jjTriggers[21]) {
    jjTriggers[21] = true;
    jjSample(player.xPos, player.yPos, SOUND::MENUSOUNDS_TYPEENTER);
  }
}
//Door opening only if you have the key and go to door after
void onFunction101(jjPLAYER@ player) {
  if (jjTriggers[21]) {
    jjTriggers[24] = true;
  }
}
Anyways, I puzzled a bit with the code and testing the level and eventually I also made it work to have a sound effect that only triggers when the door opens. It's this:

Code:
//Sound effect for getting key
void onFunction100(jjPLAYER@ player) {
  if (!jjTriggers[21]) {
    jjTriggers[21] = true;
    jjSample(player.xPos, player.yPos, SOUND::MENUSOUNDS_TYPEENTER);
  }
}
//Door opening only if you have the key and go to the door after + sound
void onFunction101(jjPLAYER@ player) {
  if (!jjTriggers[24])
  if (jjTriggers[21]) {
    jjTriggers[24] = true;
    jjSample(player.xPos, player.yPos, SOUND::COMMON_MONITOR);
  }
}
I didn't know how to write 'and' so I just added two ifs xD But it works now so I'm not complaining.

Last edited by jjturbo9; Mar 25, 2025 at 06:56 AM.
Seren

JCF Member

Joined: Feb 2010

Posts: 872

Seren is a name known to allSeren is a name known to allSeren is a name known to allSeren is a name known to allSeren is a name known to allSeren is a name known to all

Mar 25, 2025, 09:54 AM
Seren is offline
Reply With Quote
Quote:
Originally Posted by jjturbo9 View Post
I think I'm gonna choose another sound though, now that I heard it come together. And is there a way to make it louder? Probably not necessary but just wondering, might be nice as a final touch.
jjSample does take an optional volume argument but the default volume is already the maximum so no, sounds can't be made any louder than this.

Quote:
Originally Posted by jjturbo9 View Post
I didn't know how to write 'and' so I just added two ifs xD But it works now so I'm not complaining.
It was worth taking a guess: "and" works. In fact the "!" can also be replaced with "not" so the whole expression can be stated as
Code:
jjTriggers[21] and not jjTriggers[24]
In practice most AngelScript users state these symbolically with ! for not, && for and, and || for or (and sometimes ^^ for xor).
Code:
jjTriggers[21] && !jjTriggers[24]
Both ways are exactly equivalent.
__________________

I am an official JJ2+ programmer and this has been an official JJ2+ statement.
jjturbo9

JCF Member

Joined: Mar 2025

Posts: 6

jjturbo9 has disabled reputation

Mar 25, 2025, 01:52 PM
jjturbo9 is offline
Reply With Quote
Okay thank you, I see this now after I finished it. For next time this is better but now I use my less subtle but working way.
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is On

Forum Jump

All times are GMT -8. The time now is 02:25 PM.