Skip to content

Commit

Permalink
Add new safemode rule category for ignoring sounds (#36786)
Browse files Browse the repository at this point in the history
* Added safe sound rule category
  • Loading branch information
Ramza13 authored and ZhilkinSerg committed Jan 23, 2020
1 parent 31768ac commit fe570fa
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 53 deletions.
168 changes: 121 additions & 47 deletions src/safemode_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,15 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in )
COLUMN_ATTITUDE,
COLUMN_PROXIMITY,
COLUMN_WHITE_BLACKLIST,
COLUMN_CATEGORY
};

std::map<int, int> column_pos;
column_pos[COLUMN_RULE] = 4;
column_pos[COLUMN_ATTITUDE] = 48;
column_pos[COLUMN_PROXIMITY] = 59;
column_pos[COLUMN_WHITE_BLACKLIST] = 66;
column_pos[COLUMN_ATTITUDE] = column_pos[COLUMN_RULE] + 38;
column_pos[COLUMN_PROXIMITY] = column_pos[COLUMN_ATTITUDE] + 10;
column_pos[COLUMN_WHITE_BLACKLIST] = column_pos[COLUMN_PROXIMITY] + 6;
column_pos[COLUMN_CATEGORY] = column_pos[COLUMN_WHITE_BLACKLIST] + 11;

const int num_columns = column_pos.size();

Expand Down Expand Up @@ -133,6 +135,8 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in )
mvwprintz( w_header, point( column_pos[COLUMN_ATTITUDE] + 2, 3 ), c_white, _( "Attitude" ) );
mvwprintz( w_header, point( column_pos[COLUMN_PROXIMITY] + 2, 3 ), c_white, _( "Dist" ) );
mvwprintz( w_header, point( column_pos[COLUMN_WHITE_BLACKLIST] + 2, 3 ), c_white, _( "B/W" ) );
mvwprintz( w_header, point( column_pos[COLUMN_CATEGORY] + 2, 3 ), c_white, pgettext( "category",
"Cat" ) );

wrefresh( w_header );
};
Expand Down Expand Up @@ -231,9 +235,13 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in )
};

draw_column( COLUMN_RULE, ( rule.rule.empty() ) ? _( "<empty rule>" ) : rule.rule );
draw_column( COLUMN_ATTITUDE, Creature::get_attitude_ui_data( rule.attitude ).first.translated() );
draw_column( COLUMN_PROXIMITY, ( !rule.whitelist ) ? to_string( rule.proximity ) : "---" );
draw_column( COLUMN_WHITE_BLACKLIST, ( rule.whitelist ) ? _( "Whitelist" ) : _( "Blacklist" ) );
draw_column( COLUMN_ATTITUDE, ( rule.category == Categories::HOSTILE_SPOTTED ) ?
Creature::get_attitude_ui_data( rule.attitude ).first.translated() : "---" );
draw_column( COLUMN_PROXIMITY, ( ( rule.category == Categories::SOUND ) ||
!rule.whitelist ) ? to_string( rule.proximity ) : "---" );
draw_column( COLUMN_WHITE_BLACKLIST, rule.whitelist ? _( "Whitelist" ) : _( "Blacklist" ) );
draw_column( COLUMN_CATEGORY, ( rule.category == Categories::SOUND ) ? _( "Sound" ) :
_( "Hostile" ) );
}
}

Expand Down Expand Up @@ -273,12 +281,14 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in )
} else if( action == "ADD_DEFAULT_RULESET" ) {
changes_made = true;
current_tab.push_back( rules_class( "*", true, false, Creature::A_HOSTILE,
get_option<int>( "SAFEMODEPROXIMITY" ) ) );
get_option<int>( "SAFEMODEPROXIMITY" )
, HOSTILE_SPOTTED ) );
current_tab.push_back( rules_class( "*", true, true, Creature::A_HOSTILE, 5, SOUND ) );
line = current_tab.size() - 1;
} else if( action == "ADD_RULE" ) {
changes_made = true;
current_tab.push_back( rules_class( "", true, false, Creature::A_HOSTILE,
get_option<int>( "SAFEMODEPROXIMITY" ) ) );
get_option<int>( "SAFEMODEPROXIMITY" ), HOSTILE_SPOTTED ) );
line = current_tab.size() - 1;
} else if( action == "REMOVE_RULE" && !current_tab.empty() ) {
changes_made = true;
Expand Down Expand Up @@ -310,19 +320,37 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in )
} else if( action == "CONFIRM" && !current_tab.empty() ) {
changes_made = true;
if( column == COLUMN_RULE ) {
// NOLINTNEXTLINE(cata-use-named-point-constants)
fold_and_print( w_help, point( 1, 1 ), 999, c_white,
_(
"* is used as a Wildcard. A few Examples:\n"
"\n"
"human matches every NPC\n"
"zombie matches the monster name exactly\n"
"acidic zo* matches monsters beginning with 'acidic zo'\n"
"*mbie matches monsters ending with 'mbie'\n"
"*cid*zo*ie multiple * are allowed\n"
"AcI*zO*iE case insensitive search" )
);

switch( current_tab[line].category ) {
case Categories::HOSTILE_SPOTTED:
// NOLINTNEXTLINE(cata-use-named-point-constants)
fold_and_print( w_help, point( 1, 1 ), 999, c_white,
_(
"* is used as a Wildcard. A few Examples:\n"
"\n"
"human matches every NPC\n"
"zombie matches the monster name exactly\n"
"acidic zo* matches monsters beginning with 'acidic zo'\n"
"*mbie matches monsters ending with 'mbie'\n"
"*cid*zo*ie multiple * are allowed\n"
"AcI*zO*iE case insensitive search" )
);
break;
case Categories::SOUND:
// NOLINTNEXTLINE(cata-use-named-point-constants)
fold_and_print( w_help, point( 1, 1 ), 999, c_white,
_(
"* is used as a Wildcard. A few Examples:\n"
"\n"
"footsteps matches the sound name exactly\n"
"a loud ba* matches sounds beginning with 'a loud ba'\n"
"*losion! matches sounds ending with 'losion!'\n"
"a *oud*ba* multiple * are allowed\n"
"*LoU*bA* case insensitive search" )
);
break;
default:
break;
}
draw_border( w_help );
wrefresh( w_help );
current_tab[line].rule = wildcard_trim_rule( string_input_popup()
Expand All @@ -332,6 +360,12 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in )
.query_string() );
} else if( column == COLUMN_WHITE_BLACKLIST ) {
current_tab[line].whitelist = !current_tab[line].whitelist;
} else if( column == COLUMN_CATEGORY ) {
if( current_tab[line].category == HOSTILE_SPOTTED ) {
current_tab[line].category = SOUND;
} else if( current_tab[line].category == SOUND ) {
current_tab[line].category = HOSTILE_SPOTTED;
}
} else if( column == COLUMN_ATTITUDE ) {
auto &attitude = current_tab[line].attitude;
switch( attitude ) {
Expand All @@ -347,7 +381,8 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in )
case Creature::A_ANY:
attitude = Creature::A_HOSTILE;
}
} else if( column == COLUMN_PROXIMITY && !current_tab[line].whitelist ) {
} else if( column == COLUMN_PROXIMITY && ( current_tab[line].category == SOUND ||
!current_tab[line].whitelist ) ) {
const auto text = string_input_popup()
.title( _( "Proximity Distance (0=max view distance)" ) )
.width( 4 )
Expand Down Expand Up @@ -526,7 +561,7 @@ void safemode::add_rule( const std::string &rule_in, const Creature::Attitude at
const rule_state state_in )
{
character_rules.push_back( rules_class( rule_in, true, ( state_in == RULE_WHITELISTED ),
attitude_in, proximity_in ) );
attitude_in, proximity_in, HOSTILE_SPOTTED ) );
create_rules();

if( !get_option<bool>( "SAFEMODE" ) &&
Expand Down Expand Up @@ -569,8 +604,8 @@ bool safemode::empty() const

void safemode::create_rules()
{
safemode_rules.clear();

safemode_rules_hostile.clear();
safemode_rules_sound.clear();
//process include/exclude in order of rules, global first, then character specific
add_rules( global_rules );
add_rules( character_rules );
Expand All @@ -581,41 +616,60 @@ void safemode::add_rules( const std::vector<rules_class> &rules_in )
//if a specific monster is being added, all the rules need to be checked now
//may have some performance issues since exclusion needs to check all monsters also
for( auto &rule : rules_in ) {
if( !rule.whitelist ) {
//Check include patterns against all monster mtypes
for( const auto &mtype : MonsterGenerator::generator().get_all_mtypes() ) {
set_rule( rule, mtype.nname(), RULE_BLACKLISTED );
}
} else {
//exclude monsters from the existing mapping
for( const auto &safemode_rule : safemode_rules ) {
set_rule( rule, safemode_rule.first, RULE_WHITELISTED );
}
switch( rule.category ) {
case HOSTILE_SPOTTED:
if( !rule.whitelist ) {
//Check include patterns against all monster mtypes
for( const auto &mtype : MonsterGenerator::generator().get_all_mtypes() ) {
set_rule( rule, mtype.nname(), RULE_BLACKLISTED );
}
} else {
//exclude monsters from the existing mapping
for( const auto &safemode_rule : safemode_rules_hostile ) {
set_rule( rule, safemode_rule.first, RULE_WHITELISTED );
}
}
break;
case SOUND:
set_rule( rule, rule.rule, rule.whitelist ? RULE_WHITELISTED : RULE_BLACKLISTED );
break;
default:
break;
}
}
}

void safemode::set_rule( const rules_class &rule_in, const std::string &name_in, rule_state rs_in )
{
static std::vector<Creature::Attitude> attitude_any = {{Creature::A_HOSTILE, Creature::A_NEUTRAL, Creature::A_FRIENDLY}};

if( !rule_in.rule.empty() && rule_in.active && wildcard_match( name_in, rule_in.rule ) ) {
if( rule_in.attitude == Creature::A_ANY ) {
for( auto &att : attitude_any ) {
safemode_rules[ name_in ][ att ] = rule_state_class( rs_in, rule_in.proximity );
static std::vector<Creature::Attitude> attitude_any = { {Creature::A_HOSTILE, Creature::A_NEUTRAL, Creature::A_FRIENDLY} };
switch( rule_in.category ) {
case HOSTILE_SPOTTED:
if( !rule_in.rule.empty() && rule_in.active && wildcard_match( name_in, rule_in.rule ) ) {
if( rule_in.attitude == Creature::A_ANY ) {
for( auto &att : attitude_any ) {
safemode_rules_hostile[name_in][att] = rule_state_class( rs_in, rule_in.proximity,
HOSTILE_SPOTTED );
}
} else {
safemode_rules_hostile[name_in][rule_in.attitude] = rule_state_class( rs_in, rule_in.proximity,
HOSTILE_SPOTTED );
}
}
} else {
safemode_rules[ name_in ][ rule_in.attitude ] = rule_state_class( rs_in, rule_in.proximity );
}
break;
case SOUND:
safemode_rules_sound.push_back( rule_in );
break;
default:
break;
}
}

rule_state safemode::check_monster( const std::string &creature_name_in,
const Creature::Attitude attitude_in,
const int proximity_in ) const
{
const auto iter = safemode_rules.find( creature_name_in );
if( iter != safemode_rules.end() ) {
const auto iter = safemode_rules_hostile.find( creature_name_in );
if( iter != safemode_rules_hostile.end() ) {
const auto &tmp = ( iter->second )[static_cast<int>( attitude_in )];
if( tmp.state == RULE_BLACKLISTED ) {
if( tmp.proximity == 0 || proximity_in <= tmp.proximity ) {
Expand All @@ -630,6 +684,23 @@ rule_state safemode::check_monster( const std::string &creature_name_in,
return RULE_NONE;
}

bool safemode::is_sound_safe( const std::string &sound_name_in,
const int proximity_in ) const
{
bool sound_safe = false;
for( unsigned int i = 0; i < safemode_rules_sound.size(); i++ ) {
if( wildcard_match( sound_name_in, safemode_rules_sound[i].rule ) &&
proximity_in >= safemode_rules_sound[i].proximity ) {
if( safemode_rules_sound[i].whitelist ) {
sound_safe = true;
} else {
return false;
}
}
};
return sound_safe;
}

void safemode::clear_character_rules()
{
character_rules.clear();
Expand Down Expand Up @@ -715,6 +786,7 @@ void safemode::serialize( JsonOut &json ) const
json.member( "whitelist", elem.whitelist );
json.member( "attitude", elem.attitude );
json.member( "proximity", elem.proximity );
json.member( "category", elem.category );

json.end_object();
}
Expand All @@ -736,9 +808,11 @@ void safemode::deserialize( JsonIn &jsin )
const bool whitelist = jo.get_bool( "whitelist" );
const Creature::Attitude attitude = static_cast<Creature::Attitude>( jo.get_int( "attitude" ) );
const int proximity = jo.get_int( "proximity" );
const Categories cat = jo.has_member( "category" ) ? static_cast<Categories>
( jo.get_int( "category" ) ) : HOSTILE_SPOTTED;

temp_rules.push_back(
rules_class( rule, active, whitelist, attitude, proximity )
rules_class( rule, active, whitelist, attitude, proximity, cat )
);
}
}
19 changes: 14 additions & 5 deletions src/safemode_ui.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ class safemode
MAX_TAB
};

enum Categories : int {
HOSTILE_SPOTTED,
SOUND
};

class rules_class
{
public:
Expand All @@ -30,13 +35,14 @@ class safemode
bool whitelist;
Creature::Attitude attitude;
int proximity;
Categories category;

rules_class() : active( false ), whitelist( false ), attitude( Creature::A_HOSTILE ),
proximity( 0 ) {}
proximity( 0 ), category( Categories::HOSTILE_SPOTTED ) {}
rules_class( const std::string &rule_in, bool active_in, bool whitelist_in,
Creature::Attitude attitude_in, int proximity_in ) : rule( rule_in ),
Creature::Attitude attitude_in, int proximity_in, Categories cat ) : rule( rule_in ),
active( active_in ), whitelist( whitelist_in ),
attitude( attitude_in ), proximity( proximity_in ) {}
attitude( attitude_in ), proximity( proximity_in ), category( cat ) {}
};

class rule_state_class
Expand All @@ -46,7 +52,7 @@ class safemode
int proximity;

rule_state_class() : state( RULE_NONE ), proximity( 0 ) {}
rule_state_class( rule_state state_in, int proximity_in ) : state( state_in ),
rule_state_class( rule_state state_in, int proximity_in, Categories ) : state( state_in ),
proximity( proximity_in ) {}
};

Expand All @@ -57,7 +63,8 @@ class safemode
* is added as the key, with RULE_WHITELISTED or RULE_BLACKLISTED as the values.
* safemode_rules[ 'creature name' ][ 'attitude' ].rule_state_class('rule_state', 'proximity')
*/
std::unordered_map < std::string, std::array < rule_state_class, 3 > > safemode_rules;
std::unordered_map < std::string, std::array < rule_state_class, 3 > > safemode_rules_hostile;
std::vector < rules_class > safemode_rules_sound;

/**
* current rules for global and character tab
Expand Down Expand Up @@ -87,6 +94,8 @@ class safemode
rule_state check_monster( const std::string &creature_name_in, Creature::Attitude attitude_in,
int proximity_in ) const;

bool is_sound_safe( const std::string &sound_name_in, const int proximity_in ) const;

std::string npc_type_name();

void show();
Expand Down
4 changes: 3 additions & 1 deletion src/sounds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "type_id.h"
#include "point.h"
#include "string_id.h"
#include "safemode_ui.h"

#if defined(SDL_SOUND)
# if defined(_MSC_VER) && defined(USE_VCPKG)
Expand Down Expand Up @@ -431,7 +432,8 @@ void sounds::process_sound_markers( player *p )

// don't print our own noise or things without descriptions
if( !sound.ambient && ( pos != p->pos() ) && !g->m.pl_sees( pos, distance_to_sound ) ) {
if( !p->activity.is_distraction_ignored( distraction_type::noise ) ) {
if( !p->activity.is_distraction_ignored( distraction_type::noise ) &&
!get_safemode().is_sound_safe( sound.description, distance_to_sound ) ) {
const std::string query = string_format( _( "Heard %s!" ), description );
g->cancel_activity_or_ignore_query( distraction_type::noise, query );
}
Expand Down

0 comments on commit fe570fa

Please sign in to comment.