Feature - Implemented Add sounds to barrel smashing! (patch included)

five35

New member
This patch adds a satisfying, woody "crunch" sound to smashing barrels during smash parties or while in the Barrel full of Barrels. Mechanically, this works by attaching the sound to the same events which trigger the explosion of barrel particles. The sound used was dedicated to the public domain and, for simplicity, I dedicate my changes to it (primarily format conversion) to the public domain as well.

The sound has been placed in the images/ directory, for lack of a more obviously correct place to put it. It cannot be located in the relay/ directory due to (I believe) files in that folder being assumed to be UTF-8 rather than binary, causing the file to be corrupted when downloaded by the browser.

Code:
Index: src/data/defaults.txt
===================================================================
--- src/data/defaults.txt	(revision 16319)
+++ src/data/defaults.txt	(working copy)
@@ -108,6 +108,7 @@
 global	previousUpdateRevision	0
 global	protectAgainstOverdrink	true
 global	proxySet	false
+global	relayAddSounds	true
 global	relayAddsCustomCombat	true
 global	relayAddsDiscoHelper	false
 global	relayAddsGraphicalCLI	false
Index: src/images/barrel_smash.mp3
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: src/images/barrel_smash.mp3
===================================================================
--- src/images/barrel_smash.mp3	(revision 0)
+++ src/images/barrel_smash.mp3	(working copy)

Property changes on: src/images/barrel_smash.mp3
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: src/net/sourceforge/kolmafia/KoLConstants.java
===================================================================
--- src/net/sourceforge/kolmafia/KoLConstants.java	(revision 16319)
+++ src/net/sourceforge/kolmafia/KoLConstants.java	(working copy)
@@ -393,6 +393,7 @@
 	public static final int MALLPRICES_VERSION = 0xF00D5;
 
 	// The current versioned name of each KoLmafia-supplied relay file
+	public static final String BARREL_SOUNDS_JS = "barrel_sounds.js";
 	public static final String BASEMENT_JS = "basement.js";
 	public static final String BASICS_CSS = "basics.1.css";
 	public static final String BASICS_JS = "basics.js";
@@ -409,6 +410,7 @@
 
 	public static final String[] RELAY_FILES =
 	{
+		BARREL_SOUNDS_JS,
 		BASEMENT_JS,
 		BASICS_CSS,
 		BASICS_JS,
Index: src/net/sourceforge/kolmafia/RequestEditorKit.java
===================================================================
--- src/net/sourceforge/kolmafia/RequestEditorKit.java	(revision 16319)
+++ src/net/sourceforge/kolmafia/RequestEditorKit.java	(working copy)
@@ -438,6 +438,7 @@
 			RequestEditorKit.fixTavernCellar( buffer );
 			StationaryButtonDecorator.decorate( location, buffer );
 			RequestEditorKit.addChoiceSpoilers( location, buffer );
+			RequestEditorKit.addBarrelSounds( buffer );
 		}
 		else if ( location.startsWith( "clan_hobopolis.php" ) )
 		{
@@ -1991,6 +1992,19 @@
 		buffer.append( text.substring( index1 ) );
 	}
 
+	private static final void addBarrelSounds( final StringBuffer buffer )
+	{
+		if ( !Preferences.getBoolean( "relayAddSounds" ) )
+		{
+			return;
+		}
+
+		if ( buffer.indexOf( "barrelpart" ) != -1 )
+		{
+			StringUtilities.insertBefore( buffer, "</html>", "<script src=\"/" + KoLConstants.BARREL_SOUNDS_JS + "\"></script>" );
+		}
+	}
+
 	private static final void decorateChoiceResponse( final String location, final StringBuffer buffer )
 	{
 		Matcher matcher = RequestEditorKit.CHOICE2_PATTERN.matcher( location );
Index: src/net/sourceforge/kolmafia/swingui/OptionsFrame.java
===================================================================
--- src/net/sourceforge/kolmafia/swingui/OptionsFrame.java	(revision 16319)
+++ src/net/sourceforge/kolmafia/swingui/OptionsFrame.java	(working copy)
@@ -232,6 +232,7 @@
 				{},
 				{ "relayAllowRemoteAccess", "Allow network devices to access relay browser (requires restart)" },
 				{ "relayOverridesImages", "Override certain KoL images" },
+				{ "relayAddSounds", "Add sounds to certain events" },
 				{},
 				{ "relayAddsWikiLinks", "Check wiki for item descriptions (fails for unknowns)" },
 				{ "relayAddsQuickScripts", "Add quick script links to menu bar (see Links tab)" },
Index: src/relay/barrel_sounds.js
===================================================================
--- src/relay/barrel_sounds.js	(revision 0)
+++ src/relay/barrel_sounds.js	(working copy)
@@ -0,0 +1,56 @@
+(function(window) {
+	var BARREL_SMASH_SOUND = "/images/barrel_smash.mp3";
+
+	var AudioContext = window.AudioContext || window.webkitAudioContext;
+
+	if (AudioContext) {
+		// web audio API
+
+		var context = new AudioContext();
+		var audioBuffer;
+
+		function play_source() {
+			if (audioBuffer) {
+				var source = context.createBufferSource();
+
+				source.buffer = audioBuffer;
+				source.playbackRate.value = 1 + Math.random() / 2;
+				source.connect(context.destination)
+				source.start(context.currentTime);
+			}
+		}
+
+		var request = new XMLHttpRequest();
+
+		request.open("GET", BARREL_SMASH_SOUND);
+		request.responseType = "arraybuffer";
+
+		request.onload = function() {
+			context.decodeAudioData(request.response, function(decodedBuffer) {
+				audioBuffer = decodedBuffer;
+
+				if ($(document).live) {
+					$(".spot").live("click", play_source);
+				} else {
+					$(document).on("click", ".spot", play_source);
+				}
+			});
+		}
+
+		request.send();
+	} else if (window.Audio) {
+		// HTML5 audio element
+
+		var audio = new Audio(BARREL_SMASH_SOUND);
+
+		function play_element() {
+			audio.play();
+		}
+
+		if ($(document).live) {
+			$(".spot").live("click", play_element);
+		} else {
+			$(document).on("click", ".spot", play_element);
+		}
+	}
+})(this);
 

Attachments

  • barrel-sounds.zip
    15.6 KB · Views: 32

Bale

Minion
Wouldn't this be more awesome if there was a different sound for each type of barrel? Or at least each of the main divisions. Just throwing that out there.

Unfortunately it is tough. If the sound you are using would be an indoor barrel, here's a decent outdoor barrel sound and this could be an underground barrel.

Yeah, I'm making this waaaay too complicated.
 

five35

New member
It does play a a slightly random pitch if the browser supports it. More distinct sounds (and per-barrel-type sounds) would be cool, but I didn't want to push it too much for (I think?) the very first sounds Mafia introduces. ;-)
 

fronobulax

Developer
Staff member
(I think?) the very first sounds Mafia introduces. ;-)

I have a vague recollection that there might be some kind of beep in KoLmafia - incoming chat message, perhaps? I'm not a big fan of adding any sound to KoLmafia mostly because there is always that one time I forget to mute my computer, but I won't lobby against this.
 

lostcalpolydude

Developer
Staff member
Yes, chatBeep is off by default for incoming PMs. This could maybe be added with a default value of false (especially with the setting not having a place to change it in the GUI), but I wouldn't enable it.
 

roippi

Developer
Comments:

Surprising/delightful UX moments are always welcome
That said the feature should default off
Use $.ajax to do your ajax request
I forget where exactly we insert our scripts onto the page, but doing everything on $(document).ready is good practice
 
I <3 this idea. I do agree that it should be disabled by default, so no one's unsuspectingly annoyed. Varying the pitch is awesome already, but a selection of sounds would be even better. It doesn't even have to be tied to barrel type - I'd be happy with a randomized sound for each smash, from a selection.
 

fronobulax

Developer
Staff member
As the person who increases their commit count by committing other people's work, I'm sensing enough interest in this to look at it. Three things come to mind. First the default has to be no sounds which is an easy change for me to make. Next will this have a noticeable effect on the jar file size and my expectation is yes, but not enough to matter. My last question, which I don't have an answer to, is why is the sound file in images?

I assume that this is going to work on the supported operating systems with reasonably standard browser configurations.
 

xKiv

Active member
My last question, which I don't have an answer to, is why is the sound file in images?

OP:

The sound has been placed in the images/ directory, for lack of a more obviously correct place to put it. It cannot be located in the relay/ directory due to (I believe) files in that folder being assumed to be UTF-8 rather than binary, causing the file to be corrupted when downloaded by the browser.
 

fronobulax

Developer
Staff member

OK. Rephrase the question - Where is the best place to put it and what changes to mafia might be required to do that? Would a re-implementation that kept the file as a resource in the jar work and be worth the effort? Are there constraints on the relay browser that I am not aware of?
 

Veracity

Developer
Staff member
The sound has been placed in the images/ directory, for lack of a more obviously correct place to put it. It cannot be located in the relay/ directory due to (I believe) files in that folder being assumed to be UTF-8 rather than binary, causing the file to be corrupted when downloaded by the browser.
Who "assumes" that files in that folder are UTF-8?

RelayRequest.printHeaders:

Code:
			if ( this.responseCode == 200 && this.rawByteBuffer != null )
			{
				ostream.print( "Content-Type: " );
				ostream.print( this.contentType );

				if ( this.contentType.startsWith( "text" ) )
				{
					ostream.print( "; charset=UTF-8" );
				}

				ostream.println();

				ostream.print( "Content-Length: " );
				ostream.print( this.rawByteBuffer.length );
				ostream.println();

				ostream.println( "Cache-Control: no-cache, must-revalidate" );
				ostream.println( "Pragma: no-cache" );
			}
and RelayRequest.pseudoResponse:

Code:
			if ( this.contentType.equals( "text/html" ) )
			{
				this.headers.add( "Content-Type: text/html; charset=UTF-8" );
				this.headers.add( "Cache-Control: no-cache, must-revalidate" );
				this.headers.add( "Pragma: no-cache" );
			}
			else
			{
				this.headers.add( "Content-Type: " + this.contentType );
			}
So, the question is, where does this.contentType get calculated?

RelayRequest.constructURLString:

Code:
		if ( path.endsWith( ".css" ) )
		{
			this.contentType = "text/css";
		}
		else if ( path.endsWith( ".js" ) )
		{
			this.contentType = "text/javascript";
		}
		else if ( path.endsWith( ".gif" ) )
		{
			this.contentType = "image/gif";
		}
		else if ( path.endsWith( ".png" ) )
		{
			this.contentType = "image/png";
		}
		else if ( path.endsWith( ".jpg" ) || path.endsWith( ".jpeg" ) )
		{
			this.contentType = "image/jpeg";
		}
		else if ( path.endsWith( ".ico" ) )
		{
			this.contentType = "image/x-icon";
		}
		else if ( path.endsWith( ".php" ) || path.endsWith( ".html" ) || path.endsWith( ".ash" ) )
		{
			this.contentType = "text/html";
		}
		else
		{
			this.contentType = "text/plain";
		}
It is strictly based on filename. If we don't recognize the extension, it defaults to text/plain. I don't see any code to choose content type based on directory.

You have .mp3 files. What HTML Content-Type does that map to?
 

fronobulax

Developer
Staff member
This is not dead (for me) but there are two things someone else needs to address before I will commit anything:

1) It appears that using the images subdirectory was based upon incomplete or misunderstood information. I think the sound file belongs elsewhere and that wherever that is will become a de facto standard for KoLmafia. It needs to be moved or I need to understand why this is not the good idea I think it is.

2) I am in violent agreement that based on precedents this is best as a relay script. So I need to understand the technical hurdles to providing the functionality in a script.

Are there any advocates with some 'splainin' to do?
 

Bale

Minion
1) I'm not certain that the images directory is completely inappropriate. The directory does not only contain images. It also contains javascript and css files. Since the directory has already had its purview widened to "things that load on webpages" this seems to be in the category.

2) I got nothin! What is the name of the page to intercept with a relay script?
 
Last edited:

Bale

Minion
choice.php (choice 1101) for smash party and barrel.php

Then that's an answer for concern number 2. It's not a huge technological hurdle for the script writer to have two pages to cover (obviously choice.php would import barrel.php), but the problem comes in with the need to integrate yet one more choice.php override. For the user, that could be an insurmountable problem.
 

fronobulax

Developer
Staff member
Perhaps I am confused. The images subdirectory created by running KoLmafia does not seem to be a good place for this because the cache clear command will delete the contents, thus requiring some mechanism to detect its absence and replace it. The images directory in the KoLmafia source tree contains nothing but images unless I have made an error inspecting it.
 

heeheehee

Developer
Staff member
Any reason why we can't just serve audio/mpeg files from relay/ with the correct MIME type, as Veracity was investigating?
 

Veracity

Developer
Staff member
I don't see why not. It requires a trivial change in RelayRequest.constructURLString to set the correct MIME type, but then .mp3 files should be served correctly, whether we build this in or make it a relay script.

The fact that it would be a choice.php override makes a relay script less desirable, in my opinion - until/unless we figure out how to easily have choice overrides for individual choice numbers, as discussed elsewhere in a Feature request.
 
Top