Water restarts music

Ask for help about creating mods and scripts for Grimrock 2 or share your tips, scripts, tools and assets with other modders here. Warning: forum contains spoilers!
minmay
Posts: 2780
Joined: Mon Sep 23, 2013 2:24 am

Water restarts music

Post by minmay »

Falling into water changes the level's background music to "underwater", and climbing back out changes it back, which makes perfect sense. However, this also has the effect of restarting the background music. This is not much of a problem for the ambient tracks in the original game, but I'm making a mod with background music that's actually...well, music. And the restarting is very awkward and grating.
Is there a way for me to let players dive into water without restarting the music? It restarts even if the above-water and below-water music are both the "underwater" track, so redefining that won't work.

(Boss fights do this too, but that's not much of a problem since I'm going to end up implementing my own boss fight system anyway...)

edit: not defining the "underwater" track at all also doesn't work. The original music will keep playing when you enter the water (though the console will complain), but as you might expect, it will still restart when you leave the water.
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
Batty
Posts: 509
Joined: Sun Apr 15, 2012 7:04 pm

Re: Water restarts music

Post by Batty »

I would define the above-water ambient as nothing or silent. Then add a Sound component to an object that follows the party everywhere & have it play your track. You can adjust the volume of Sound components (SoundComponent:setVolume(number) - I assume works dynamically) so when water is entered turn the volume to zero, turn it back up on exit.

Just an idea, haven't tried any of it. :)

Edit: you could maybe set maxDistance in the sound's definition at 32 and just stick the object with the Sound component in the wall somewhere.

Edit #2: :lol: I made a rock that plays all the game sounds, here's the script, bit long but yes you can adjust sound volume dynamically:

Code: Select all

function grimRadio()

   if not findEntity('radioCounter') then
	
      spawn('counter', 1, 1, 1, 1, 1, 'radioCounter').counter:setValue(1)
      spawn('counter', 1, 1, 1, 1, 1, 'counter2D').counter:setValue(0)
	
   end

   tunes3D = { 'air_elemental_attack', 'air_elemental_die', 'air_elemental_hit',
               'air_elemental_walk', 'balance', 'barrel_die',
               'barrel_hit', 'beach_waves', '2D', 'blob',
               'blob_hit', 'blob_hit_receptor', 'blob_launch', '2D', 'brew_potion',
               'button', 'cage_open', 'cage_rattle', 'castle_button', 'champion_die',
               'chest_close', 'chest_open', '2D', '2D', '2D',
               'consume_potion', '2D', 'container_box_close', 'container_sack_close',
               'container_sack_open', 'crab_attack', 'crab_die', 'crab_hit', 'crab_walk', 
               'crowern_attack', 'crowern_die', 'crowern_footstep', 'crowern_hit',
               'crowern_walk', 'crows_flying', 'crystal_ambient', 'damage_bear', 'damage_human_female',
               'damage_human_male', 'damage_insectoid_female', 'damage_insectoid_male',
               'damage_lizardman_female', 'damage_lizardman_male', 'damage_minotaur_female',
               'damage_minotaur_male', 'damage_ratling_female', 'damage_ratling_male',
               'dark_acolyte_attack', 'dark_acolyte_die', 'dark_acolyte_hit', 'dark_acolyte_spell',
               'dark_acolyte_walk', 'dark_bolt', 'dark_bolt_hit', 'dark_bolt_launch', '2D',
               'dispel_hit', 'dispel_launch', 'essence_ambient', 'eyctopus_attack', 'eyctopus_die',
               'eyctopus_fart', 'eyctopus_hit', 'eyctopus_walk', 'fire_elemental_attack',
               'fire_elemental_burn', 'fire_elemental_die', 'fire_elemental_hit', 'fire_elemental_walk',
               'fire_pit', '2D', 'fireball', 'fireball_hit', 'fireball_launch',
               'fireburst', 'force_field_ambient', 'force_field_ambient_quiet', 'force_field_cast',
               'forest_trees_wind', 'frostbolt', 'frostbolt_hit', 'frostbolt_launch', 'frostburst',
               '2D', 'gate_close', 'gate_iron_close', 'gate_iron_open', 'gate_lock',
               'gate_open', 'generic_spell', 'goromorg_shield_break', 'goromorg_shield_hit',
               'gun_reload', 'gun_shot_cannon', 'gun_shot_large', 'gun_shot_small', '2D',
               'herder_attack', 'herder_big_attack', 'herder_big_die', 'herder_die', 'herder_footstep',
               'herder_hit', 'herder_small_attack', 'herder_small_die', 'herder_walk', 'ice_guardian_attack',
               'ice_guardian_die', 'ice_guardian_hit', 'ice_guardian_walk', 'ice_hit', 'ice_shard',
               'impact_arrow', 'impact_blade', 'impact_blunt', 'impact_generic', 'impact_plant',
               'impact_punch', 'insectoid_happy', '2D', '2D', '2D', 'key_lock',
               'key_lock_faint', '2D', 'lever', 'light', 'lightning_bolt', 'lightning_bolt_hit',
               'lightning_bolt_hit_small', 'lightning_bolt_launch', 'lindworm_attack', '2D',
               'lindworm_dash', 'lindworm_die', 'lindworm_fly_maneuver1', 'lindworm_fly_maneuver2',
               'lindworm_fly_maneuver3', 'lindworm_hit', 'lindworm_intro', 'lindworm_knockback',
               'lindworm_roar', 'lindworm_shield_break', 'lindworm_summon', 'lindworm_walk', 'lindworm_wing_attack',
               'lizardman_happy', 'lock_chest', 'lock_incorrect', 'magic_bridge_ambient', 'magma_golem_attack',
               'magma_golem_die', 'magma_golem_footstep', 'magma_golem_ground_pound', 'magma_golem_hit',
               'magma_golem_meteor_fall', 'magma_golem_ranged_attack', 'magma_golem_turn_attack', 'magma_golem_walk',
               'map_turn_page', 'master_gate_open', 'medusa_attack', 'medusa_die', 'medusa_gaze', 'medusa_hit',
               'medusa_walk', 'mimic_attack', 'mimic_die', 'mimic_hit', 'mimic_open', 'mimic_walk',
               'mosquito_swarm_attack', 'mosquito_swarm_die', 'mosquito_swarm_hit', 'mosquito_swarm_walk',
               'mummy_attack_01', 'mummy_attack_02', 'mummy_attack_03', 'mummy_attack_04', 'mummy_die',
               'mummy_footstep', 'mummy_hit', 'mummy_walk', 'ogre_attack', 'ogre_die', 'ogre_footstep', 'ogre_hit',
               'ogre_impact', 'ogre_rush_begin', 'ogre_walk', 'ogre_whoosh', 'party_climb_ladder', 'party_crushed',
               '2D', 'party_drown', 'party_enter_stairs', 'party_fall', 'party_land', 'party_move',
               '2D', 'party_move_burdened', 'party_move_dive', 'party_move_grass', 'party_move_overloaded',
               'party_move_wade', '2D', '2D', 'pit_close', 'pit_open',
               'power_attack_charging', 'power_attack_fail', '2D', '2D',
               'power_attack_yell_human_male', 'power_attack_yell_insectoid_female', 'power_attack_yell_insectoid_male',
               'power_attack_yell_lizardman_female', 'power_attack_yell_lizardman_male', '2D',
               '2D', 'power_attack_yell_ratling_female', 'power_attack_yell_ratling_male',
               'power_gem_ambient', 'pressure_plate_pressed', 'pressure_plate_released', 'projectile_hit_party',
               'pushable_block_blocked', 'pushable_block_fall', 'pushable_block_hover', 'pushable_block_push',
               'pushable_block_rise', 'rat_swarm_attack', 'rat_swarm_die', 'rat_swarm_hit', 'rat_swarm_walk',
               'ratling1_alert', 'ratling1_attack', 'ratling1_whoosh_01', 'ratling1_whoosh_02', 'ratling2_alert',
               'ratling2_attack', 'ratling3_alert', 'ratling3_attack', 'ratling_boss_alert', 'ratling_boss_attack',
               'ratling_boss_die', 'ratling_boss_footstep', 'ratling_boss_hit', 'ratling_boss_walk', 'ratling_die',
               'ratling_footstep', 'ratling_happy', 'ratling_hit', 'ratling_walk', 'read_scroll', 'read_tome',
               'river_ambient', '2D', '2D', 'serpent_staff', 'serpent_staff_blast', 'serpent_staff_launch',
               'shockburst', 'shrakk_torr_attack', 'shrakk_torr_die', 'shrakk_torr_fly', 'shrakk_torr_hit',
               'skeleton_archer_attack', 'skeleton_archer_footstep', 'skeleton_attack', 'skeleton_commander_attack',
               'skeleton_commander_ice_shards', 'skeleton_commander_move_attack', 'skeleton_commander_summon_spell',
               'skeleton_commander_turn_attack', 'skeleton_commander_walk', 'skeleton_die', 'skeleton_footstep',
               'skeleton_hit', 'skeleton_trooper_attack', 'skeleton_walk', 'slime_attack', 'slime_die', 'slime_hit',
               'slime_walk', 'snake_attack', 'snake_die', 'snake_hit', 'snake_walk', 'spear_door', '2D',
               'spell_fizzle', 'spell_out_of_energy', 'spider_attack', 'spider_die',
               'spider_eggs_ambient', 'spider_eggs_hit', 'spider_hit', 'spider_walk', 'spike_trap', 'spore_mushroom_die',
               'spore_mushroom_sprout', 'stone_philosopher_eyes', 'summon_stone_attack',
               'summon_stone_die', 'summon_stone_footstep', 'summon_stone_hit', 'summon_stone_wake_up', 'summon_stone_walk',
               '2D', 'swipe_bow', 'swipe_claw', 'swipe_heavy', 'swipe_light', 'swipe_special', '2D', 'teleport', 'teleporter_ambient',
               'terracotta_jar_die', 'terracotta_jar_hit', 'torch_burning', 'trickster_appear', '2D',
               'trickster_escape', 'trickster_laugh', '2D', 'trickster_pull_lever', 'trickster_throw',
               'trickster_walk', 'trickster_zap', 'turtle_alert', 'turtle_attack', 'turtle_die', 'turtle_dive',
               'turtle_diving_alert', 'turtle_diving_attack', 'turtle_double_attack', 'turtle_footstep', 'turtle_hit',
               'turtle_move_attack', 'turtle_walk', 'twigroot_attack', 'twigroot_die', 'twigroot_hit', 'twigroot_strafe',
               'twigroot_walk', 'uggardian_attack', 'uggardian_die', 'uggardian_hit', 'uggardian_walk', 'undead_attack',
               'undead_die', 'undead_rise', 'undead_walk', 'viper_root_attack', 'viper_root_die', 'viper_root_hit',
               'viper_root_ranged_attack', 'viper_root_rise', 'wall_fire', 'wall_sliding', 'wall_sliding_lock', 'wall_tapestry_tear',
               'wand_fear', 'warg_attack', 'warg_die', 'warg_hit', 'warg_howl', 'warg_walk', 'water_hit_large', 'water_hit_small',
               'wind_howl', 'wizard_check_door', 'wizard_clone_die', 'wizard_crystal', 'wizard_hit', 'wizard_laugh', 'wizard_letter',
               'wizard_push', 'wizard_ranged_attack', '2D', 'wizard_shield', 'wizard_teleport', 'wizard_turn',
               'wizard_warp', 'wyvern_attack', 'wyvern_die', 'wyvern_footstep', 'wyvern_hit', 'wyvern_walk',
               'xeloroid_attack', 'xeloroid_die', 'xeloroid_footstep', 'xeloroid_hit', 'xeloroid_lightning', 'xeloroid_walk',
               'zarchton_attack', 'zarchton_die', 'zarchton_dive', 'zarchton_diving_alert', 'zarchton_diving_attack',
               'zarchton_diving_leap_attack', 'zarchton_footstep', 'zarchton_hit', 'zarchton_leap_attack', 'zarchton_walk', '2D' }

   tunes2D = { 'beacon_furnace_activate', 'blow_horn', 'click_down', 'click_up', 'consume_food',
               'container_box_open', 'discover_spell', 'firearm_jammed', 'game_over', 'heal_party', 'item_drop',
               'item_equip', 'item_pick_up', 'level_up', 'lindworm_cinematic_tower', 'party_dig', 'party_move_blocked',
               'party_water_exit', 'party_water_exit_gasp', 'power_attack_ready', 'power_attack_yell_human_female',
               'power_attack_yell_minotaur_female', 'power_attack_yell_minotaur_male', 'scramble_writer', 'secret',
               'spell_expires', 'swipe', 'swipe_thrown', 'trickster_die', 'trickster_polymorph', 'wizard_rumble', 'spell_gesture' }
	
   if not findEntity('soundRock') then
	
      spawn('rock', party.level, party.x, party.y, 1, party.elevation, 'soundRock')
		
   else
	
      soundRock.sound:stop()
      soundRock:removeComponent('Sound')
	
   end
	
   if tunes3D[radioCounter.counter:getValue()] == '2D' then
	
      playSound(tunes2D[counter2D.counter:getValue()])
      hudPrint(radioCounter.counter:getValue() .. ' of ' .. #tunes3D .. ': ' .. tunes2D[counter2D.counter:getValue()])
	
   else
		
      soundRock:createComponent('Sound')
      soundRock.sound:setSound(tunes3D[radioCounter.counter:getValue()])
      soundRock.sound:setVolume(2)
      soundRock.sound:play(tunes3D[radioCounter.counter:getValue()])
      hudPrint(radioCounter.counter:getValue() .. ' of ' .. #tunes3D .. ': ' .. tunes3D[radioCounter.counter:getValue()])
		
   end
	
   hudPrint('')
   hudPrint('')

   if tunes3D[radioCounter.counter:getValue()] == '2D' and
      tunes2D[counter2D.counter:getValue()] == 'beacon_furnace_activate' then
	
      delayedCall(self.go.id, 15, 'grimRadio') 
      radioCounter.controller:increment()

   elseif tunes2D[radioCounter.counter:getValue()] == '2D' and
      tunes2D[counter2D.counter:getValue()] == 'game_over' then
	
      delayedCall(self.go.id, 9, 'grimRadio') 
      radioCounter.controller:increment()

   elseif tunes3D[radioCounter.counter:getValue()] == '2D' and
      tunes2D[counter2D.counter:getValue()] == 'trickster_die' then
	
      delayedCall(self.go.id, 17, 'grimRadio') 
      radioCounter.controller:increment()

   elseif radioCounter.counter:getValue() < #tunes3D then

      delayedCall(self.go.id, 3, 'grimRadio')
      radioCounter.controller:increment()
	
   else

      hudPrint('The End')
	
   end

   if tunes3D[radioCounter.counter:getValue()] == '2D' then counter2D.controller:increment() end
	
end
Last edited by Batty on Wed Nov 26, 2014 8:27 pm, edited 5 times in total.
NutJob
Posts: 426
Joined: Sun Oct 19, 2014 6:35 pm

Re: Water restarts music

Post by NutJob »

Ha! That's awesome Batty.
Batty
Posts: 509
Joined: Sun Apr 15, 2012 7:04 pm

Re: Water restarts music

Post by Batty »

Yes, just have a plate activate the script and you can drink Glögg and listen to all the sounds at 3:00 am, :lol: I even adjusted for length to account for some longer sounds. Takes a good while to listen to them all.
Last edited by Batty on Wed Nov 26, 2014 4:14 am, edited 1 time in total.
minmay
Posts: 2780
Joined: Mon Sep 23, 2013 2:24 am

Re: Water restarts music

Post by minmay »

As entertaining as your script is*, this is not a practical solution because ogg is not supported for sound effects, only ambient tracks. That's 85 MB per minute of stereo music, even a quality 10 (extremely high) stereo ogg is about 3 MB per minute at 44100Hz.

*Though I can't resist correcting you on one point: you have 3D and 2D sounds the wrong way around. "3D" sounds are actually the mono ones; they're so named because they have a position in the 3D world that determines their panning. 2D sounds are so named because they do not (they should really be called 0D sounds :P).
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
GoldenShadowGS
Posts: 168
Joined: Thu Oct 30, 2014 1:56 am

Re: Water restarts music

Post by GoldenShadowGS »

Batty wrote:Yes, just have a plate activate the script and you can drink Glögg and listen to all the sounds at 3:00 am, :lol: I even adjusted for length to account for some longer sounds. Takes a good while to listen to them all.
You can auto exec a function just by doing this:

Code: Select all

dothis()

function dothis()
--something here
end
Everything outside of the function definition is run automatically. Simpler than making an invisible trigger and connecting it to the function.
Batty
Posts: 509
Joined: Sun Apr 15, 2012 7:04 pm

Re: Water restarts music

Post by Batty »

GoldenShadowGS wrote: You can auto exec a function just by doing this:

Code: Select all

dothis()

function dothis()
--something here
end
Everything outside of the function definition is run automatically. Simpler than making an invisible trigger and connecting it to the function.
Ah, right, try the script, you don't want it autoexecuting. :)
Batty
Posts: 509
Joined: Sun Apr 15, 2012 7:04 pm

Re: Water restarts music

Post by Batty »

minmay wrote:As entertaining as your script is*, this is not a practical solution because ogg is not supported for sound effects, only ambient tracks. That's 85 MB per minute of stereo music, even a quality 10 (extremely high) stereo ogg is about 3 MB per minute at 44100Hz.
Oh yeah, only .wav in definitions, there is SoundComponent:setSoundType(type), I don't know what that does but I suspect it won't help.
minmay wrote:*Though I can't resist correcting you on one point: you have 3D and 2D sounds the wrong way around. "3D" sounds are actually the mono ones; they're so named because they have a position in the 3D world that determines their panning. 2D sounds are so named because they do not (they should really be called 0D sounds :P).
See this post, according to the editor the sounds in my tunes3D table are 3D.
minmay
Posts: 2780
Joined: Mon Sep 23, 2013 2:24 am

Re: Water restarts music

Post by minmay »

Batty wrote:See this post, according to the editor the sounds in my tunes3D table are 3D.
Again, you have it backwards. What that error message means is that you can't play a non-mono sound as a 3D sound. playSound() can play stereo or mono sounds because it doesn't play the sound in the game world, it just plays the sound. Using a stereo sound in the game world makes no sense because it's only being emitted from one place.
Batty wrote:Oh yeah, only .wav in definitions, there is SoundComponent:setSoundType(type), I don't know what that does but I suspect it won't help.
Ah, I missed that. If sound type is "point", the default, the component plays a 3D (mono) sound at its location. If the sound type is "ambient" it plays a 2D (stereo or mono) sound while activated - this is used for the stone philosophers in the main campaign. So you wouldn't need two sound components to have a stereo sound play all the time (but there's still the filesize problem).
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
Batty
Posts: 509
Joined: Sun Apr 15, 2012 7:04 pm

Re: Water restarts music

Post by Batty »

minmay wrote:Again, you have it backwards. What that error message means is that you can't play a non-mono sound as a 3D sound. playSound() can play stereo or mono sounds because it doesn't play the sound in the game world, it just plays the sound. Using a stereo sound in the game world makes no sense because it's only being emitted from one place.
Oh I get it, I read the error wrong, so the sounds that don't work with Sound components are stereo. The Sound component is for directional mono "3D" sounds. :)
Post Reply