diff --git a/.gitignore b/.gitignore index 9633f8a158f6..530ee75ad58c 100644 --- a/.gitignore +++ b/.gitignore @@ -206,3 +206,4 @@ Xcode/ /tests/pch/tests-pch.hpp.pch /tests/catch/catch.hpp.gch /tests/catch/catch.hpp.pch +cbn_notes.txt diff --git a/src/iexamine.cpp b/src/iexamine.cpp index ae0fd466304c..0108a82c4e4c 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -389,6 +389,101 @@ void iexamine::gaspump( player &p, const tripoint &examp ) add_msg( m_info, _( "Out of order." ) ); } +static bool has_attunement_spell_prereqs( Character &you, const trait_id &attunement ) +{ + // for each prereq we need to check that the player has 2 level 15 spells + for( const trait_id &prereq : attunement->prereqs ) { + int spells_known = 0; + for( const spell &sp : you.spells_known_of_class( prereq ) ) { + if( sp.get_level() >= 15 ) { + spells_known++; + } + } + if( spells_known < 2 ) { + return false; + } + } + return true; +} + +void iexamine::attunement_altar( Character &you, const tripoint & ) +{ + std::set attunements; + for( const mutation_branch &mut : mutation_branch::get_all() ) { + if( mut.flags.count( json_flag_ATTUNEMENT ) ) { + attunements.emplace( mut.id ); + } + } + // remove the attunements the player does not have prereqs for + for( auto iter = attunements.begin(); iter != attunements.end(); ) { + bool has_prereq = true; + // the normal usage of prereqs only needs one, but attunements put all their prereqs into the same array + // each prereqs is required for it as well + for( const trait_id &prereq : ( *iter )->prereqs ) { + if( !you.has_trait( prereq ) ) { + has_prereq = false; + break; + } + } + if( has_prereq ) { + ++iter; + } else { + iter = attunements.erase( iter ); + } + } + if( attunements.empty() ) { + // the player doesn't have at least two base classes + you.add_msg_if_player( _( "This altar gives you the creeps." ) ); + return; + } + // remove the attunements the player has conflicts for + for( auto iter = attunements.begin(); iter != attunements.end(); ) { + if( !you.has_opposite_trait( *iter ) && you.mutation_ok( *iter, true, true, true ) ) { + ++iter; + } else { + iter = attunements.erase( iter ); + } + } + if( attunements.empty() ) { + you.add_msg_if_player( _( "You've attained what you can for now." ) ); + return; + } + for( auto iter = attunements.begin(); iter != attunements.end(); ) { + if( has_attunement_spell_prereqs( you, *iter ) ) { + ++iter; + } else { + iter = attunements.erase( iter ); + } + } + if( attunements.empty() ) { + you.add_msg_if_player( _( "You feel that the altar does not deem you worthy, yet." ) ); + return; + } + uilist attunement_list; + attunement_list.title = _( "Pick an Attunement to show the world your Worth." ); + for( const trait_id &attunement : attunements ) { + // There's no way for you to have this mutation, so a variant is pointless + attunement_list.addentry( attunement->name() ); + } + attunement_list.query(); + if( attunement_list.ret == UILIST_CANCEL ) { + you.add_msg_if_player( _( "Maybe later." ) ); + return; + } + auto attunement_iter = attunements.begin(); + std::advance( attunement_iter, attunement_list.ret ); + const trait_id &attunement = *attunement_iter; + // There's no way for you to have this mutation, so a variant is pointless + if( query_yn( string_format( _( "Are you sure you want to pick %s? This selection is permanent." ), + attunement->name() ) ) ) { + you.toggle_trait( attunement ); + // There's no way for you to have this mutation, so a variant is pointless + you.add_msg_if_player( m_info, attunement->desc() ); + } else { + you.add_msg_if_player( _( "Maybe later." ) ); + } +} + void iexamine::translocator( player &, const tripoint &examp ) { // TODO: fix point types diff --git a/src/iexamine.h b/src/iexamine.h index 5647ffcbc3c7..cfc4eb2448e1 100644 --- a/src/iexamine.h +++ b/src/iexamine.h @@ -103,6 +103,8 @@ void sign( player &p, const tripoint &examp ); void pay_gas( player &p, const tripoint &examp ); void ledge( player &p, const tripoint &examp ); void autodoc( player &p, const tripoint &examp ); +bool has_attunement_spell_prereqs( Character &you, const trait_id &attunement ) +void attunement_altar( Character &you, const tripoint &examp ); void translocator( player &p, const tripoint &examp ); void on_smoke_out( const tripoint &examp, const time_point &start_time ); //activates end of smoking effects diff --git a/src/mutation_data.cpp b/src/mutation_data.cpp index 9c95b97873e4..8ac84717eed9 100644 --- a/src/mutation_data.cpp +++ b/src/mutation_data.cpp @@ -620,7 +620,9 @@ void mutation_branch::check_consistency() nc_color mutation_branch::get_display_color() const { - if( threshold || profession ) { + if( flags.count( STATIC( json_character_flag( "ATTUNEMENT" ) ) ) ) { + return c_green; + } else if( threshold || profession ) { return c_white; } else if( debug ) { return c_light_cyan;