diff --git a/data/json/mutations/mutations.json b/data/json/mutations/mutations.json index 1d45e59e26487..588a47fa9193a 100644 --- a/data/json/mutations/mutations.json +++ b/data/json/mutations/mutations.json @@ -336,6 +336,16 @@ "category": [ "ELFA" ], "hearing_modifier": 1.75 }, + { + "type": "mutation", + "id": "INATTENTIVE", + "name": { "str": "Inattentive" }, + "points": -2, + "starting_trait": true, + "description": "You never paid attention to your surroundings and specifically to people around you. You can't judge intent of critters you see.", + "purifiable": false, + "valid": false + }, { "type": "mutation", "id": "OUTDOORSMAN", diff --git a/src/cata_tiles.cpp b/src/cata_tiles.cpp index 8f7649fdc13f8..c4e5e2407c855 100644 --- a/src/cata_tiles.cpp +++ b/src/cata_tiles.cpp @@ -75,6 +75,7 @@ static const efftype_id effect_ridden( "ridden" ); static const itype_id itype_corpse( "corpse" ); +static const trait_id trait_INATTENTIVE( "INATTENTIVE" ); static const std::string ITEM_HIGHLIGHT( "highlight_item" ); static const std::string ZOMBIE_REVIVAL_INDICATOR( "zombie_revival_indicator" ); @@ -3564,7 +3565,7 @@ bool cata_tiles::draw_critter_at( const tripoint &p, lit_level ll, int &height_3 if( result && !is_player ) { std::string draw_id = "overlay_" + Creature::attitude_raw_string( attitude ); - if( sees_player ) { + if( sees_player && !you.has_trait( trait_INATTENTIVE ) ) { draw_id += "_sees_player"; } if( tileset_ptr->find_tile_type( draw_id ) ) { diff --git a/src/character.cpp b/src/character.cpp index fea3ec4256e96..8e4b827798a57 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -9621,6 +9621,7 @@ Creature::Attitude Character::attitude_to( const Creature &other ) const case MATT_ATTACK: return Attitude::HOSTILE; case MATT_NULL: + case MATT_UNKNOWN: case NUM_MONSTER_ATTITUDES: break; } diff --git a/src/game.cpp b/src/game.cpp index f204468d3a08d..c00bfd6fec92b 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -281,6 +281,7 @@ static const string_id npc_template_cyborg_rescued( "cyborg_rescue static const trait_id trait_BADKNEES( "BADKNEES" ); static const trait_id trait_CENOBITE( "CENOBITE" ); static const trait_id trait_ILLITERATE( "ILLITERATE" ); +static const trait_id trait_INATTENTIVE( "INATTENTIVE" ); static const trait_id trait_INFIMMUNE( "INFIMMUNE" ); static const trait_id trait_INFRESIST( "INFRESIST" ); static const trait_id trait_LEG_TENT_BRACE( "LEG_TENT_BRACE" ); @@ -7416,11 +7417,16 @@ void game::list_items_monsters() } std::sort( mons.begin(), mons.end(), [&]( const Creature * lhs, const Creature * rhs ) { - const Creature::Attitude att_lhs = lhs->attitude_to( u ); - const Creature::Attitude att_rhs = rhs->attitude_to( u ); + if( !u.has_trait( trait_INATTENTIVE ) ) { + const Creature::Attitude att_lhs = lhs->attitude_to( u ); + const Creature::Attitude att_rhs = rhs->attitude_to( u ); + + return att_lhs < att_rhs || ( att_lhs == att_rhs + && rl_dist( u.pos(), lhs->pos() ) < rl_dist( u.pos(), rhs->pos() ) ); + } else { // Sort just by ditance if player has inattentive trait + return ( rl_dist( u.pos(), lhs->pos() ) < rl_dist( u.pos(), rhs->pos() ) ); + } - return att_lhs < att_rhs || ( att_lhs == att_rhs - && rl_dist( u.pos(), lhs->pos() ) < rl_dist( u.pos(), rhs->pos() ) ); } ); // If the current list is empty, switch to the non-empty list @@ -8007,12 +8013,14 @@ game::vmenu_ret game::list_monsters( const std::vector &monster_list // first integer is the row the attitude category string is printed in the menu std::map mSortCategory; - - for( int i = 0, last_attitude = -1; i < static_cast( monster_list.size() ); i++ ) { - const Creature::Attitude attitude = monster_list[i]->attitude_to( u ); - if( static_cast( attitude ) != last_attitude ) { - mSortCategory[i + mSortCategory.size()] = attitude; - last_attitude = static_cast( attitude ); + const bool player_knows = !u.has_trait( trait_INATTENTIVE ); + if( player_knows ) { + for( int i = 0, last_attitude = -1; i < static_cast( monster_list.size() ); i++ ) { + const Creature::Attitude attitude = monster_list[i]->attitude_to( u ); + if( static_cast( attitude ) != last_attitude ) { + mSortCategory[i + mSortCategory.size()] = attitude; + last_attitude = static_cast( attitude ); + } } } @@ -8062,7 +8070,8 @@ game::vmenu_ret game::list_monsters( const std::vector &monster_list const int endY = std::min( iMaxRows - 1, iMenuSize ); for( int y = 0; y < endY; ++y ) { - if( CatSortIter != mSortCategory.cend() ) { + + if( player_knows && CatSortIter != mSortCategory.cend() ) { const int iCurPos = iStartPos + y; const int iCatPos = CatSortIter->first; if( iCurPos == iCatPos ) { @@ -8073,11 +8082,12 @@ game::vmenu_ret game::list_monsters( const std::vector &monster_list continue; } } + // select current monster Creature *critter = monster_list[iCurMon]; const bool selected = iCurMon == iActive; ++iCurMon; - if( critter->sees( u ) ) { + if( critter->sees( u ) && player_knows ) { mvwprintz( w_monsters, point( 0, y ), c_yellow, "!" ); } bool is_npc = false; @@ -8134,7 +8144,11 @@ game::vmenu_ret game::list_monsters( const std::vector &monster_list sText = npc_attitude_name( p->get_attitude() ); color = p->symbol_color(); } - mvwprintz( w_monsters, point( width - 25, y ), color, sText ); + if( !player_knows ) { + sText = _( "Unknown" ); + color = c_yellow; + } + mvwprintz( w_monsters, point( width - 19, y ), color, sText ); const int mon_dist = rl_dist( u.pos(), critter->pos() ); const int numd = mon_dist > 999 ? 4 : diff --git a/src/monster.cpp b/src/monster.cpp index cbad9ba103597..33d2a03ff6ced 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -148,6 +148,7 @@ static const trait_id trait_ANIMALEMPATH( "ANIMALEMPATH" ); static const trait_id trait_ANIMALEMPATH2( "ANIMALEMPATH2" ); static const trait_id trait_BEE( "BEE" ); static const trait_id trait_FLOWERS( "FLOWERS" ); +static const trait_id trait_INATTENTIVE( "INATTENTIVE" ); static const trait_id trait_KILLER( "KILLER" ); static const trait_id trait_MYCUS_FRIEND( "MYCUS_FRIEND" ); static const trait_id trait_PHEROMONE_AMPHIBIAN( "PHEROMONE_AMPHIBIAN" ); @@ -178,6 +179,7 @@ static const std::map> attitu {monster_attitude::MATT_FOLLOW, {translate_marker( "Tracking." ), def_c_yellow}}, {monster_attitude::MATT_IGNORE, {translate_marker( "Ignoring." ), def_c_light_gray}}, {monster_attitude::MATT_ATTACK, {translate_marker( "Hostile!" ), def_c_red}}, + {monster_attitude::MATT_UNKNOWN, {translate_marker( "Unknown" ), def_c_yellow}}, //Should only be used for UI. {monster_attitude::MATT_NULL, {translate_marker( "BUG: Behavior unnamed." ), def_h_red}}, }; @@ -698,15 +700,26 @@ int monster::print_info( const catacurses::window &w, int vStart, int vLines, in oss << "" << get_effect_status() << ""; vStart += fold_and_print( w, point( column, vStart ), max_width, c_white, oss.str() ); + Character &pc = get_player_character(); + bool sees_player = sees( pc ); + const bool player_knows = !pc.has_trait( trait_INATTENTIVE ); + // Hostility indicator on the second line. std::pair att = get_attitude(); - mvwprintz( w, point( column, vStart++ ), att.second, att.first ); + if( player_knows ) { + mvwprintz( w, point( column, vStart++ ), att.second, att.first ); + } else { + mvwprintz( w, point( column, vStart++ ), all_colors.get( attitude_names.at( MATT_UNKNOWN ).second ), + attitude_names.at( MATT_UNKNOWN ).first ); + } // Awareness indicator in the third line. - bool sees_player = sees( get_player_character() ); std::string senses_str = sees_player ? _( "Can see to your current location" ) : _( "Can't see to your current location" ); - vStart += fold_and_print( w, point( column, vStart ), max_width, sees_player ? c_red : c_green, + senses_str = !player_knows ? _( "You have no idea what is it doing" ) : + senses_str; + vStart += fold_and_print( w, point( column, vStart ), max_width, player_knows && + sees_player ? c_red : c_green, senses_str ); const std::string speed_desc = speed_description( @@ -1196,6 +1209,7 @@ Creature::Attitude monster::attitude_to( const Creature &other ) const case MATT_ATTACK: return Attitude::HOSTILE; case MATT_NULL: + case MATT_UNKNOWN: case NUM_MONSTER_ATTITUDES: break; } diff --git a/src/monster.h b/src/monster.h index 7cea5a7fd51e8..139e8f18e1d52 100644 --- a/src/monster.h +++ b/src/monster.h @@ -61,6 +61,7 @@ enum monster_attitude { MATT_IGNORE, MATT_FOLLOW, MATT_ATTACK, + MATT_UNKNOWN, NUM_MONSTER_ATTITUDES }; diff --git a/src/npc.cpp b/src/npc.cpp index 8f1ec86648a38..bb2a0555f9e93 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -2528,6 +2528,7 @@ Creature::Attitude npc::attitude_to( const Creature &other ) const case MATT_ATTACK: return Attitude::HOSTILE; case MATT_NULL: + case MATT_UNKNOWN: case NUM_MONSTER_ATTITUDES: break; }