diff --git a/src/iuse.cpp b/src/iuse.cpp index 9d8739776605d..0b947c551eded 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -3858,13 +3858,36 @@ static std::string get_music_description() } void iuse::play_music( Character *p, const tripoint &source, const int volume, - const int max_morale ) + const int max_morale, bool play_sounds ) { - // TODO: what about other "player", e.g. when a NPC is listening or when the PC is listening, - // the other characters around should be able to profit as well. - const bool do_effects = p && p->can_hear( source, volume ) && !p->in_sleep_state(); std::string sound = "music"; + auto lambda_should_do_effects = [&source, &volume]( Character * p ) { + return p && p->can_hear( source, volume ) && !p->in_sleep_state(); + }; + + auto lambda_add_music_effects = [&max_morale, &volume]( Character & guy ) { + guy.add_effect( effect_music, 1_turns ); + guy.add_morale( morale_music, 1, max_morale, 5_minutes, 2_minutes, true ); + // mp3 player reduces hearing + if( volume == 0 ) { + guy.add_effect( effect_earphones, 1_turns ); + } + }; + + // check NPCs that can hear the source of the music + for( npc &guy : g->all_npcs() ) { + if( guy.is_active() && lambda_should_do_effects( &guy ) ) { + lambda_add_music_effects( guy ); + } + } + + // player is not a NPC so they need to check separately + Character &player_character = get_player_character(); + if( lambda_should_do_effects( &player_character ) ) { + lambda_add_music_effects( player_character ); + } + if( calendar::once_every( time_duration::from_minutes( get_option( "DESCRIBE_MUSIC_FREQUENCY" ) ) ) ) { // Every X minutes, describe the music @@ -3872,24 +3895,15 @@ void iuse::play_music( Character *p, const tripoint &source, const int volume, if( !music.empty() ) { sound = music; // descriptions aren't printed for sounds at our position - if( do_effects && p->pos() == source ) { + if( lambda_should_do_effects( p ) && p->pos() == source ) { p->add_msg_if_player( _( "You listen to %s" ), music ); } } } - if( volume != 0 ) { + if( volume != 0 && play_sounds ) { sounds::ambient_sound( source, volume, sounds::sound_t::music, sound ); } - - if( do_effects ) { - p->add_effect( effect_music, 1_turns ); - p->add_morale( morale_music, 1, max_morale, 5_minutes, 2_minutes, true ); - // mp3 player reduces hearing - if( volume == 0 ) { - p->add_effect( effect_earphones, 1_turns ); - } - } } std::optional iuse::mp3_on( Character *p, item *, const tripoint &pos ) diff --git a/src/iuse.h b/src/iuse.h index df15797bcb200..1136195e78b84 100644 --- a/src/iuse.h +++ b/src/iuse.h @@ -224,7 +224,8 @@ std::optional disassemble( Character *, item *, const tripoint & ); // Helper functions for other iuse functions void cut_log_into_planks( Character & ); -void play_music( Character *p, const tripoint &source, int volume, int max_morale ); +void play_music( Character *p, const tripoint &source, int volume, int max_morale, + bool play_sounds = true ); std::optional purify_water( Character *p, item *purifier, item_location &water ); int towel_common( Character *, item *, bool ); diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index 9e3bfd70e568a..d3a74c2f24df4 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -137,7 +137,6 @@ static const itype_id itype_syringe( "syringe" ); static const json_character_flag json_flag_BIONIC_LIMB( "BIONIC_LIMB" ); static const json_character_flag json_flag_MANUAL_CBM_INSTALLATION( "MANUAL_CBM_INSTALLATION" ); -static const morale_type morale_music( "morale_music" ); static const morale_type morale_pyromania_nofire( "morale_pyromania_nofire" ); static const morale_type morale_pyromania_startfire( "morale_pyromania_startfire" ); @@ -2243,14 +2242,14 @@ std::optional musical_instrument_actor::use( Character *p, item &it, if( !p->has_effect( effect_music ) && p->can_hear( p->pos(), volume ) ) { // Sound code doesn't describe noises at the player position - if( p->is_avatar() && desc != "music" ) { - add_msg( m_info, desc ); + if( desc != "music" ) { + p->add_msg_if_player( m_info, desc ); } - p->add_effect( effect_music, 1_turns ); - const int sign = morale_effect > 0 ? 1 : -1; - p->add_morale( morale_music, sign, morale_effect, 5_minutes, 2_minutes, true ); } + // We already played the sounds, just handle applying effects now + iuse::play_music( p, p->pos(), volume, morale_effect, /*play_sounds=*/false ); + return 0; }