Player Movement Sound Based on Variable Condition

Talk about anything related to Legend of Grimrock 2 here.
Post Reply
User avatar
The_Morlock
Posts: 24
Joined: Sun Jun 02, 2024 6:15 am

Player Movement Sound Based on Variable Condition

Post by The_Morlock »

I wanted to share something that I had been having difficulty with and the solution.

I have been working on my LoG2 mod and am working on a flooded level. With this flooded level, the water could go away (be drained), so the movement sound the party would make needs to change along with the change in environment. Minmay provided the following suggestion via Discord:
It would be easier to just give the tiles silent moveSounds and play your desired sounds manually when the party moves (the PartyComponent.onMove hook makes this pretty easy)

Create the Silent Sound
First thing, easiest IMHO, is to create a silent sound. I used Audacity to do this.
  • Open Audacity and in the track area, right-click > Add Mono Track.
  • Select an time period, like 1 second, then click Generate > Silence.
You will now have a sound with 1 second of silence.
Save the file as a WAV file and place it in your mod files. I picked:
\mod_assets\sounds\none.wav


Define the Silent Sound
Within your sounds.lua file (assume this is where your custom sounds are defined), add the following:

Code: Select all

defineSound{
	name = "none",
	filename = "mod_assets/sounds/none.wav",
	loop = false,
	volume = 0,
}
Note: Technically, the volume = 0, could be volume = 100, but it is a double whammy. You could use any sound and set the volume to 0 and it should work just the same.

Once defined and loaded into your game the above "none" can be chosen for any sound element, object, within a script, etc.


Define the Tile with the Silent Movement Sound
Now, this new "none" sound was needed for the tile. This is my example where I used it for my flooded tile that would either be flooded or not:

Code: Select all

defineTile{
	name = "dungeon_floor_flooded",
	editorIcon = 112,
	color = {120,120,180,255},
	builder = "dungeon",
	floor = {
		"dungeon_floor_dirt_01", 1,
	},
	ceiling = {
		"dungeon_ceiling", 1,
	},
	wall = {
		"dungeon_wall_01", 35,
		"dungeon_wall_02", 35,
		"dungeon_wall_drain", 2,
	},
	pillar = {
		"dungeon_pillar", 1,
	},
	ceilingEdgeVariations = true,
	ceilingShaft = "dungeon_ceiling_shaft",
	underwater = true, -- so that WaterSurfaceMeshComponent builds the mesh over it
	moveSound = "none",
	automapTile = "water",
}
Notice the moveSound = "none", is now using the sound that we've defined in the sounds.lua file.

With all that setup, we now have tiles when placed in your level, will have no walking sound. This is perfect. We won't have anything conflicting with our script that will now manage the movement.


Create a Timer to Trigger the Movement Sound
Within the Editor where this new silent flooded tile will be used, create a timer object. I set mine to 0.1 or 0.01. I also set my options to triggerOnStart and currentLevelOnly. That way this won't affect other levels and will start regardless where you begin the level.

Set this to the side for now and we will come back later to it.


Create the Script Object
Create a new script entity object and add the following script to it:

Code: Select all

-- ---------------------
-- Player Movement Sound
-- ---------------------
-- Initialize last known position as global variables
lastX = party.x
lastY = party.y

-- Player Movement Sound Function
function sewerPartySounds()
    -- Check if the party has moved to a new tile
    if party.x ~= lastX or party.y ~= lastY then
        -- Check if sewer is drained
        if sewerDrained == false then
            -- Play wading sound in water if not drained
            playSound("party_move_wade")
--            hudPrint("WATER!") -- DEBUG
        else
            -- Play normal movement sound if drained
            playSound("party_move")
--            hudPrint("NO WATER!") -- DEBUG
        end

        -- Update the last known position
        lastX = party.x
        lastY = party.y
    end
end

function onTimer()
    sewerPartySounds()  -- Continuously check if the party has moved to a new tile and set the appropriate sound
end
This script does several things. It marks where the party is to play the sound once and will play the defined sound based on the sewerDrained variable. If sewerDrained is false (meaning there is water on the tile), then it will play the party_move_wade movement sound. If sewerDrained is true (meaning there is no more water on the tile), then it will play the default party_move movement sound.

The point with the lastX and lastY variables is that it marks where the party is, plays the sound once, and then marks the new coords. This ensures that only one sound will play regardless of the timing on the timer.


Connect the Timer
Once the script is good, then go back to your timer object and connect it to the script and the onTimer function. This will call the sewerPartySounds function each time the timer interval is activated. Depending on your interval setting, it will trigger the movement sound once at each tile. Setting it to a low value will ensure that it plays as soon as it can, like a normal tile sound would. Having it too high will result in action and sound syncing delays.

Now, I have a two-key system that defines the sewerDrained variable. But for yourself, do as you wish with it.

Hope this helps someone!
My Project(s): Grimstone Keep, a reimagining of the 1995 Interplay game, Stonekeep.
Discord: https://discord.gg/AfZVYHc8JX
Patreon: https://patreon.com/GrimstoneKeep
Post Reply