From 13bcb8d22690b2a0c3adff67da53a6d3c68ecc90 Mon Sep 17 00:00:00 2001 From: LISPCoC Date: Sun, 30 Jul 2023 20:52:35 +0900 Subject: [PATCH 1/9] read repeatedly --- .../npcs/common_chat/TALK_COMMON_ALLY.json | 6 +++ data/json/player_activities.json | 11 ++++++ src/activity_handlers.cpp | 8 ++++ src/activity_handlers.h | 2 + src/activity_item_handling.cpp | 30 +++++++++++++++ src/character.cpp | 38 +++++++++++++++++++ src/character.h | 6 +++ src/npc.cpp | 38 ------------------- src/npc.h | 1 - src/npctalk.cpp | 7 ++++ src/npctalk.h | 1 + src/npctalk_funcs.cpp | 6 +++ 12 files changed, 115 insertions(+), 39 deletions(-) diff --git a/data/json/npcs/common_chat/TALK_COMMON_ALLY.json b/data/json/npcs/common_chat/TALK_COMMON_ALLY.json index dce4fbecab3a6..60f59ec78e0a9 100644 --- a/data/json/npcs/common_chat/TALK_COMMON_ALLY.json +++ b/data/json/npcs/common_chat/TALK_COMMON_ALLY.json @@ -932,6 +932,12 @@ "condition": { "and": [ { "not": "npc_has_activity" }, { "not": { "npc_has_trait": "HALLUCINATION" } } ] }, "effect": "do_eread" }, + { + "text": "Please study from books you have in order.", + "topic": "TALK_DONE", + "condition": { "and": [ { "not": "npc_has_activity" }, { "not": { "npc_has_trait": "HALLUCINATION" } } ] }, + "effect": "do_read_repeatedly" + }, { "text": "Please start deconstructing any vehicles in a deconstruction zone.", "topic": "TALK_DONE", diff --git a/data/json/player_activities.json b/data/json/player_activities.json index 21b131e7d41e2..6ab3ca975c657 100644 --- a/data/json/player_activities.json +++ b/data/json/player_activities.json @@ -66,6 +66,17 @@ "no_resume": true, "multi_activity": true }, + { + "id": "ACT_MULTIPLE_READ", + "type": "activity_type", + "activity_level": "NO_EXERCISE", + "verb": "reading", + "based_on": "neither", + "suspendable": false, + "no_resume": true, + "multi_activity": true, + "auto_needs": true + }, { "id": "ACT_MOP", "type": "activity_type", diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index bc53593d90233..92c0e2af7089c 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -137,6 +137,7 @@ static const activity_id ACT_MULTIPLE_FARM( "ACT_MULTIPLE_FARM" ); static const activity_id ACT_MULTIPLE_FISH( "ACT_MULTIPLE_FISH" ); static const activity_id ACT_MULTIPLE_MINE( "ACT_MULTIPLE_MINE" ); static const activity_id ACT_MULTIPLE_MOP( "ACT_MULTIPLE_MOP" ); +static const activity_id ACT_MULTIPLE_READ( "ACT_MULTIPLE_READ" ); static const activity_id ACT_OPERATION( "ACT_OPERATION" ); static const activity_id ACT_PICKAXE( "ACT_PICKAXE" ); static const activity_id ACT_PLANT_SEED( "ACT_PLANT_SEED" ); @@ -279,6 +280,7 @@ activity_handlers::do_turn_functions = { { ACT_STUDY_SPELL, study_spell_do_turn }, { ACT_WAIT_STAMINA, wait_stamina_do_turn }, { ACT_MULTIPLE_DIS, multiple_dis_do_turn }, + { ACT_MULTIPLE_READ, multiple_read_do_turn }, }; const std::map< activity_id, std::function > @@ -3273,11 +3275,17 @@ void activity_handlers::multiple_butcher_do_turn( player_activity *act, Characte { generic_multi_activity_handler( *act, *you ); } + void activity_handlers::multiple_dis_do_turn( player_activity *act, Character *you ) { generic_multi_activity_handler( *act, *you ); } +void activity_handlers::multiple_read_do_turn( player_activity *act, Character *you ) +{ + generic_multi_activity_handler( *act, *you ); +} + void activity_handlers::vehicle_deconstruction_do_turn( player_activity *act, Character *you ) { generic_multi_activity_handler( *act, *you ); diff --git a/src/activity_handlers.h b/src/activity_handlers.h index 05fa9be9f8542..9e7c0253a8533 100644 --- a/src/activity_handlers.h +++ b/src/activity_handlers.h @@ -67,6 +67,7 @@ enum class do_activity_reason : int { NEEDS_PLANTING, // For farming - tile can be planted NEEDS_TILLING, // For farming - tile can be tilled BLOCKING_TILE, // Something has made it's way onto the tile, so the activity cannot proceed + NEEDS_BOOK_TO_LEARN, // There is book to learn NEEDS_CHOPPING, // There is wood there to be chopped NEEDS_TREE_CHOPPING, // There is a tree there that needs to be chopped NEEDS_BIG_BUTCHERING, // There is at least one corpse there to butcher, and it's a big one @@ -180,6 +181,7 @@ void multiple_construction_do_turn( player_activity *act, Character *you ); void multiple_dis_do_turn( player_activity *act, Character *you ); void multiple_farm_do_turn( player_activity *act, Character *you ); void multiple_fish_do_turn( player_activity *act, Character *you ); +void multiple_read_do_turn( player_activity *act, Character *you ); void multiple_mine_do_turn( player_activity *act, Character *you ); void multiple_mop_do_turn( player_activity *act, Character *you ); void operation_do_turn( player_activity *act, Character *you ); diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index c4241821e5381..5406fb283e9da 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -83,6 +83,7 @@ static const activity_id ACT_MULTIPLE_CONSTRUCTION( "ACT_MULTIPLE_CONSTRUCTION" static const activity_id ACT_MULTIPLE_DIS( "ACT_MULTIPLE_DIS" ); static const activity_id ACT_MULTIPLE_FARM( "ACT_MULTIPLE_FARM" ); static const activity_id ACT_MULTIPLE_FISH( "ACT_MULTIPLE_FISH" ); +static const activity_id ACT_MULTIPLE_READ( "ACT_MULTIPLE_READ" ); static const activity_id ACT_MULTIPLE_MINE( "ACT_MULTIPLE_MINE" ); static const activity_id ACT_MULTIPLE_MOP( "ACT_MULTIPLE_MOP" ); static const activity_id ACT_PICKAXE( "ACT_PICKAXE" ); @@ -1219,6 +1220,17 @@ static activity_reason_info can_do_activity_there( const activity_id &act, Chara } return activity_reason_info::fail( do_activity_reason::NO_ZONE ); } + if( act == ACT_MULTIPLE_READ ) { + std::vector dummy; + const item_filter filter = [ &you, &dummy ]( const item & i ) { + return you.can_read( i, dummy ); + }; + if( !you.items_with( filter ).empty() ) { + return activity_reason_info::ok( do_activity_reason::NEEDS_BOOK_TO_LEARN ); + } + // TODO: find books from zone? + return activity_reason_info::fail( do_activity_reason::ALREADY_DONE ); + } if( act == ACT_MULTIPLE_CHOP_PLANKS ) { //are there even any logs there? for( item &i : here.i_at( src_loc ) ) { @@ -2503,6 +2515,10 @@ static std::unordered_set generic_multi_activity_locations( } } } + } else if( act_id == ACT_MULTIPLE_READ ) { + for( const tripoint_bub_ms &elem : here.points_in_radius( localpos, ACTIVITY_SEARCH_DISTANCE ) ) { + src_set.insert( here.getglobal( elem ) ); + } } else if( act_id != ACT_FETCH_REQUIRED ) { zone_type_id zone_type = get_zone_for_act( tripoint_bub_ms{}, mgr, act_id, _fac_id( you ) ); src_set = mgr.get_near( zone_type, abspos, ACTIVITY_SEARCH_DISTANCE, nullptr, _fac_id( you ) ); @@ -2876,6 +2892,20 @@ static bool generic_multi_activity_do( you.backlog.emplace_front( act_id ); return false; } + } else if( reason == do_activity_reason::NEEDS_BOOK_TO_LEARN ) { + std::vector dummy; + const item_filter filter = [ &you, &dummy ]( const item & i ) { + return you.can_read( i, dummy ); + }; + std::vector books = you.items_with( filter ); + if( !books.empty() && books[0] ) { + const time_duration time_taken = you.time_to_read( *books[0], you ); + item_location book = item_location( you, books[0] ); + item_location ereader; + you.backlog.emplace_front( act_id ); + you.assign_activity( read_activity_actor( time_taken, book, ereader, true ) ); + return false; + } } else if( reason == do_activity_reason::CAN_DO_CONSTRUCTION ) { if( here.partial_con_at( src_loc ) ) { you.backlog.emplace_front( act_id ); diff --git a/src/character.cpp b/src/character.cpp index a74a1e81fe385..b0cb0a0747748 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -3128,6 +3128,44 @@ bool Character::can_use( const item &it, const item &context ) const return true; } +bool Character::can_read( const item &book, std::vector &fail_reasons ) +{ + if( !book.is_book() ) { + fail_reasons.push_back( string_format( _( "This %s is not good reading material." ), + book.tname() ) ); + return false; + } + Character *pl = dynamic_cast( this ); + if( !pl ) { + return false; + } + const auto &type = book.type->book; + const skill_id &skill = type->skill; + const int skill_level = pl->get_knowledge_level( skill ); + if( skill && skill_level < type->req ) { + fail_reasons.push_back( string_format( _( "I'm not smart enough to read this book." ) ) ); + return false; + } + if( !skill || skill_level >= type->level ) { + fail_reasons.push_back( string_format( _( "I won't learn anything from this book." ) ) ); + return false; + } + + // Check for conditions that disqualify us + if( type->intel > 0 && has_trait( trait_ILLITERATE ) ) { + fail_reasons.emplace_back( _( "I can't read!" ) ); + } else if( has_flag( json_flag_HYPEROPIC ) && !worn_with_flag( flag_FIX_FARSIGHT ) && + !has_effect( effect_contacts ) && + !has_flag( STATIC( json_character_flag( "ENHANCED_VISION" ) ) ) ) { + fail_reasons.emplace_back( _( "I can't read without my glasses." ) ); + } else if( fine_detail_vision_mod() > 4 ) { + // Too dark to read only applies if the player can read to himself + fail_reasons.emplace_back( _( "It's too dark to read!" ) ); + return false; + } + return true; +} + ret_val Character::can_unwield( const item &it ) const { if( it.has_flag( flag_NO_UNWIELD ) ) { diff --git a/src/character.h b/src/character.h index b3a11bdc8b673..6ce1a1280c29f 100644 --- a/src/character.h +++ b/src/character.h @@ -2148,6 +2148,12 @@ class Character : public Creature, public visitable * @param with_equip_change If true returns if it could be worn if things were taken off */ ret_val can_wear( const item &it, bool with_equip_change = false ) const; + /** + * Check if the character needs and be able to read a book. + * @param book Thing to be read. + * @param fail_reasons Why the character cannot read. + */ + bool can_read( const item &book, std::vector &fail_reasons ); /** * Returns true if the character is wielding something. * Note: this item may not actually be used to attack. diff --git a/src/npc.cpp b/src/npc.cpp index dec7f23f2ea14..7df780e91f221 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -1299,44 +1299,6 @@ void npc::starting_weapon( const npc_class_id &type ) } } -bool npc::can_read( const item &book, std::vector &fail_reasons ) -{ - if( !book.is_book() ) { - fail_reasons.push_back( string_format( _( "This %s is not good reading material." ), - book.tname() ) ); - return false; - } - Character *pl = dynamic_cast( this ); - if( !pl ) { - return false; - } - const auto &type = book.type->book; - const skill_id &skill = type->skill; - const int skill_level = pl->get_knowledge_level( skill ); - if( skill && skill_level < type->req ) { - fail_reasons.push_back( string_format( _( "I'm not smart enough to read this book." ) ) ); - return false; - } - if( !skill || skill_level >= type->level ) { - fail_reasons.push_back( string_format( _( "I won't learn anything from this book." ) ) ); - return false; - } - - // Check for conditions that disqualify us - if( type->intel > 0 && has_trait( trait_ILLITERATE ) ) { - fail_reasons.emplace_back( _( "I can't read!" ) ); - } else if( has_flag( json_flag_HYPEROPIC ) && !worn_with_flag( flag_FIX_FARSIGHT ) && - !has_effect( effect_contacts ) && - !has_flag( STATIC( json_character_flag( "ENHANCED_VISION" ) ) ) ) { - fail_reasons.emplace_back( _( "I can't read without my glasses." ) ); - } else if( fine_detail_vision_mod() > 4 ) { - // Too dark to read only applies if the player can read to himself - fail_reasons.emplace_back( _( "It's too dark to read!" ) ); - return false; - } - return true; -} - time_duration npc::time_to_read( const item &book, const Character &reader ) const { const auto &type = book.type->book; diff --git a/src/npc.h b/src/npc.h index 3751b3ef8db95..5f792021cb770 100644 --- a/src/npc.h +++ b/src/npc.h @@ -946,7 +946,6 @@ class npc : public Character double value( const item &it, double market_price ) const; faction_price_rule const *get_price_rules( item const &it ) const; bool wear_if_wanted( const item &it, std::string &reason ); - bool can_read( const item &book, std::vector &fail_reasons ); time_duration time_to_read( const item &book, const Character &reader ) const; void do_npc_read( bool ebook = false ); void stow_item( item &it ); diff --git a/src/npctalk.cpp b/src/npctalk.cpp index 824fecf0bb68f..a087d4f07f52c 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -343,6 +343,7 @@ enum npc_chat_menu { NPC_CHAT_ACTIVITIES_FISHING, NPC_CHAT_ACTIVITIES_MINING, NPC_CHAT_ACTIVITIES_MOPPING, + NPC_CHAT_ACTIVITIES_READ_REPEATEDLY, NPC_CHAT_ACTIVITIES_VEHICLE_DECONSTRUCTION, NPC_CHAT_ACTIVITIES_VEHICLE_REPAIR, NPC_CHAT_ACTIVITIES_UNASSIGN @@ -591,6 +592,7 @@ static int npc_activities_menu() nmenu.addentry( NPC_CHAT_ACTIVITIES_FISHING, true, 'F', _( "Fishing in a zone" ) ); nmenu.addentry( NPC_CHAT_ACTIVITIES_MINING, true, 'M', _( "Mining out tiles" ) ); nmenu.addentry( NPC_CHAT_ACTIVITIES_MOPPING, true, 'm', _( "Mopping up stains" ) ); + nmenu.addentry( NPC_CHAT_ACTIVITIES_READ_REPEATEDLY, true, 'R', _( "Study from books you have in order" ) ); nmenu.addentry( NPC_CHAT_ACTIVITIES_VEHICLE_DECONSTRUCTION, true, 'v', _( "Deconstructing vehicles" ) ); nmenu.addentry( NPC_CHAT_ACTIVITIES_VEHICLE_REPAIR, true, 'V', _( "Repairing vehicles" ) ); @@ -1038,6 +1040,10 @@ void game::chat() talk_function::do_fishing( *selected_npc ); break; } + case NPC_CHAT_ACTIVITIES_READ_REPEATEDLY: { + talk_function::do_read_repeatedly( *selected_npc ); + break; + } case NPC_CHAT_ACTIVITIES_MINING: { talk_function::do_mining( *selected_npc ); break; @@ -5398,6 +5404,7 @@ void talk_effect_t::parse_string_effect( const std::string &effect_id, const Jso WRAP( do_mopping ), WRAP( do_read ), WRAP( do_eread ), + WRAP( do_read_repeatedly ), WRAP( do_butcher ), WRAP( do_farming ), WRAP( assign_guard ), diff --git a/src/npctalk.h b/src/npctalk.h index 7a3063d808810..b73faf8e1a9a5 100644 --- a/src/npctalk.h +++ b/src/npctalk.h @@ -54,6 +54,7 @@ void do_mining( npc & ); void do_mopping( npc & ); void do_read( npc & ); void do_eread( npc & ); +void do_read_repeatedly( npc & ); void do_chop_plank( npc & ); void do_vehicle_deconstruct( npc & ); void do_vehicle_repair( npc & ); diff --git a/src/npctalk_funcs.cpp b/src/npctalk_funcs.cpp index 38f88980c0a4d..390f4a5ba635c 100644 --- a/src/npctalk_funcs.cpp +++ b/src/npctalk_funcs.cpp @@ -69,6 +69,7 @@ static const activity_id ACT_MULTIPLE_CONSTRUCTION( "ACT_MULTIPLE_CONSTRUCTION" static const activity_id ACT_MULTIPLE_DIS( "ACT_MULTIPLE_DIS" ); static const activity_id ACT_MULTIPLE_FARM( "ACT_MULTIPLE_FARM" ); static const activity_id ACT_MULTIPLE_FISH( "ACT_MULTIPLE_FISH" ); +static const activity_id ACT_MULTIPLE_READ( "ACT_MULTIPLE_READ" ); static const activity_id ACT_MULTIPLE_MINE( "ACT_MULTIPLE_MINE" ); static const activity_id ACT_MULTIPLE_MOP( "ACT_MULTIPLE_MOP" ); static const activity_id ACT_SOCIALIZE( "ACT_SOCIALIZE" ); @@ -267,6 +268,11 @@ void talk_function::do_eread( npc &p ) p.do_npc_read( true ); } +void talk_function::do_read_repeatedly( npc &p ) +{ + p.assign_activity( ACT_MULTIPLE_READ ); +} + void talk_function::dismount( npc &p ) { p.npc_dismount(); From 2a511acfa93b8d6d89f0cffaeb06465ca34fded2 Mon Sep 17 00:00:00 2001 From: LISPCoC Date: Sun, 30 Jul 2023 21:16:34 +0900 Subject: [PATCH 2/9] Astyle Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/npctalk.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/npctalk.cpp b/src/npctalk.cpp index a087d4f07f52c..48028578bdb9f 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -592,7 +592,8 @@ static int npc_activities_menu() nmenu.addentry( NPC_CHAT_ACTIVITIES_FISHING, true, 'F', _( "Fishing in a zone" ) ); nmenu.addentry( NPC_CHAT_ACTIVITIES_MINING, true, 'M', _( "Mining out tiles" ) ); nmenu.addentry( NPC_CHAT_ACTIVITIES_MOPPING, true, 'm', _( "Mopping up stains" ) ); - nmenu.addentry( NPC_CHAT_ACTIVITIES_READ_REPEATEDLY, true, 'R', _( "Study from books you have in order" ) ); + nmenu.addentry( NPC_CHAT_ACTIVITIES_READ_REPEATEDLY, true, 'R', + _( "Study from books you have in order" ) ); nmenu.addentry( NPC_CHAT_ACTIVITIES_VEHICLE_DECONSTRUCTION, true, 'v', _( "Deconstructing vehicles" ) ); nmenu.addentry( NPC_CHAT_ACTIVITIES_VEHICLE_REPAIR, true, 'V', _( "Repairing vehicles" ) ); From 0f560b1cb417a0fa32761ee95e66a27d21fdac0d Mon Sep 17 00:00:00 2001 From: lispcoc Date: Mon, 31 Jul 2023 09:25:50 +0900 Subject: [PATCH 3/9] fix clang error --- src/activity_item_handling.cpp | 3 ++- src/npc.cpp | 4 ---- src/npctalk_funcs.cpp | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index 5406fb283e9da..e5264b50bcad9 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -83,8 +83,8 @@ static const activity_id ACT_MULTIPLE_CONSTRUCTION( "ACT_MULTIPLE_CONSTRUCTION" static const activity_id ACT_MULTIPLE_DIS( "ACT_MULTIPLE_DIS" ); static const activity_id ACT_MULTIPLE_FARM( "ACT_MULTIPLE_FARM" ); static const activity_id ACT_MULTIPLE_FISH( "ACT_MULTIPLE_FISH" ); -static const activity_id ACT_MULTIPLE_READ( "ACT_MULTIPLE_READ" ); static const activity_id ACT_MULTIPLE_MINE( "ACT_MULTIPLE_MINE" ); +static const activity_id ACT_MULTIPLE_READ( "ACT_MULTIPLE_READ" ); static const activity_id ACT_MULTIPLE_MOP( "ACT_MULTIPLE_MOP" ); static const activity_id ACT_PICKAXE( "ACT_PICKAXE" ); static const activity_id ACT_TIDY_UP( "ACT_TIDY_UP" ); @@ -2516,6 +2516,7 @@ static std::unordered_set generic_multi_activity_locations( } } } else if( act_id == ACT_MULTIPLE_READ ) { + // anywhere well lit for( const tripoint_bub_ms &elem : here.points_in_radius( localpos, ACTIVITY_SEARCH_DISTANCE ) ) { src_set.insert( here.getglobal( elem ) ); } diff --git a/src/npc.cpp b/src/npc.cpp index 7df780e91f221..39f56a3ee627a 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -87,7 +87,6 @@ #include "name.h" static const efftype_id effect_bouldering( "bouldering" ); -static const efftype_id effect_contacts( "contacts" ); static const efftype_id effect_controlled( "controlled" ); static const efftype_id effect_drunk( "drunk" ); static const efftype_id effect_high( "high" ); @@ -115,8 +114,6 @@ static const item_group_id Item_spawn_data_survivor_bashing( "survivor_bashing" static const item_group_id Item_spawn_data_survivor_cutting( "survivor_cutting" ); static const item_group_id Item_spawn_data_survivor_stabbing( "survivor_stabbing" ); -static const json_character_flag json_flag_HYPEROPIC( "HYPEROPIC" ); - static const mfaction_str_id monfaction_bee( "bee" ); static const mfaction_str_id monfaction_human( "human" ); static const mfaction_str_id monfaction_player( "player" ); @@ -151,7 +148,6 @@ static const trait_id trait_BEE( "BEE" ); static const trait_id trait_CANNIBAL( "CANNIBAL" ); static const trait_id trait_DEBUG_MIND_CONTROL( "DEBUG_MIND_CONTROL" ); static const trait_id trait_HALLUCINATION( "HALLUCINATION" ); -static const trait_id trait_ILLITERATE( "ILLITERATE" ); static const trait_id trait_MUTE( "MUTE" ); static const trait_id trait_NO_BASH( "NO_BASH" ); static const trait_id trait_PROF_DICEMASTER( "PROF_DICEMASTER" ); diff --git a/src/npctalk_funcs.cpp b/src/npctalk_funcs.cpp index 390f4a5ba635c..3c00c3b255a02 100644 --- a/src/npctalk_funcs.cpp +++ b/src/npctalk_funcs.cpp @@ -69,8 +69,8 @@ static const activity_id ACT_MULTIPLE_CONSTRUCTION( "ACT_MULTIPLE_CONSTRUCTION" static const activity_id ACT_MULTIPLE_DIS( "ACT_MULTIPLE_DIS" ); static const activity_id ACT_MULTIPLE_FARM( "ACT_MULTIPLE_FARM" ); static const activity_id ACT_MULTIPLE_FISH( "ACT_MULTIPLE_FISH" ); -static const activity_id ACT_MULTIPLE_READ( "ACT_MULTIPLE_READ" ); static const activity_id ACT_MULTIPLE_MINE( "ACT_MULTIPLE_MINE" ); +static const activity_id ACT_MULTIPLE_READ( "ACT_MULTIPLE_READ" ); static const activity_id ACT_MULTIPLE_MOP( "ACT_MULTIPLE_MOP" ); static const activity_id ACT_SOCIALIZE( "ACT_SOCIALIZE" ); static const activity_id ACT_TRAIN( "ACT_TRAIN" ); From e45826fed8f9f84a9b4bd03ee60266585ccbe80e Mon Sep 17 00:00:00 2001 From: lispcoc Date: Mon, 31 Jul 2023 11:05:01 +0900 Subject: [PATCH 4/9] cleanup reading condition --- src/activity_item_handling.cpp | 9 ++- src/character.cpp | 118 +++++++++++++++++---------------- src/character.h | 26 ++++++-- src/npc.cpp | 34 ++++++++++ src/npc.h | 1 + 5 files changed, 120 insertions(+), 68 deletions(-) diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index e5264b50bcad9..864e9645ee891 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -1221,9 +1221,8 @@ static activity_reason_info can_do_activity_there( const activity_id &act, Chara return activity_reason_info::fail( do_activity_reason::NO_ZONE ); } if( act == ACT_MULTIPLE_READ ) { - std::vector dummy; - const item_filter filter = [ &you, &dummy ]( const item & i ) { - return you.can_read( i, dummy ); + const item_filter filter = [ &you ]( const item & i ) { + return you.check_read_condition( i ) == read_condition_result::SUCCESS; }; if( !you.items_with( filter ).empty() ) { return activity_reason_info::ok( do_activity_reason::NEEDS_BOOK_TO_LEARN ); @@ -2895,8 +2894,8 @@ static bool generic_multi_activity_do( } } else if( reason == do_activity_reason::NEEDS_BOOK_TO_LEARN ) { std::vector dummy; - const item_filter filter = [ &you, &dummy ]( const item & i ) { - return you.can_read( i, dummy ); + const item_filter filter = [ &you ]( const item & i ) { + return you.check_read_condition( i ) == read_condition_result::SUCCESS; }; std::vector books = you.items_with( filter ); if( !books.empty() && books[0] ) { diff --git a/src/character.cpp b/src/character.cpp index b0cb0a0747748..97eb1122f0277 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -3128,44 +3128,6 @@ bool Character::can_use( const item &it, const item &context ) const return true; } -bool Character::can_read( const item &book, std::vector &fail_reasons ) -{ - if( !book.is_book() ) { - fail_reasons.push_back( string_format( _( "This %s is not good reading material." ), - book.tname() ) ); - return false; - } - Character *pl = dynamic_cast( this ); - if( !pl ) { - return false; - } - const auto &type = book.type->book; - const skill_id &skill = type->skill; - const int skill_level = pl->get_knowledge_level( skill ); - if( skill && skill_level < type->req ) { - fail_reasons.push_back( string_format( _( "I'm not smart enough to read this book." ) ) ); - return false; - } - if( !skill || skill_level >= type->level ) { - fail_reasons.push_back( string_format( _( "I won't learn anything from this book." ) ) ); - return false; - } - - // Check for conditions that disqualify us - if( type->intel > 0 && has_trait( trait_ILLITERATE ) ) { - fail_reasons.emplace_back( _( "I can't read!" ) ); - } else if( has_flag( json_flag_HYPEROPIC ) && !worn_with_flag( flag_FIX_FARSIGHT ) && - !has_effect( effect_contacts ) && - !has_flag( STATIC( json_character_flag( "ENHANCED_VISION" ) ) ) ) { - fail_reasons.emplace_back( _( "I can't read without my glasses." ) ); - } else if( fine_detail_vision_mod() > 4 ) { - // Too dark to read only applies if the player can read to himself - fail_reasons.emplace_back( _( "It's too dark to read!" ) ); - return false; - } - return true; -} - ret_val Character::can_unwield( const item &it ) const { if( it.has_flag( flag_NO_UNWIELD ) ) { @@ -11053,6 +11015,53 @@ bool Character::beyond_final_warning( const faction_id &id ) return false; } +read_condition_result Character::check_read_condition( const item &book ) const +{ + if( !book.is_book() ) { + return read_condition_result::NOT_BOOK; + } + + const optional_vpart_position vp = get_map().veh_at( pos() ); + if( vp && vp->vehicle().player_in_control( *this ) ) { + return read_condition_result::DRIVING; + } + + const cata::value_ptr &type = book.type->book; + const skill_id &book_skill = type->skill; + const int book_skill_requirement = type->req; + const bool book_requires_intelligence = type->intel > 0; + + if( !fun_to_read( book ) && !has_morale_to_read() && has_identified( book.typeId() ) ) { + return read_condition_result::MORALE_LOW; + } + + const book_mastery mastery = get_book_mastery( book ); + if( mastery == book_mastery::CANT_UNDERSTAND ) { + return read_condition_result::CANT_UNDERSTAND; + } + if( mastery == book_mastery::MASTERED ) { + return read_condition_result::MASTERED; + } + + if( book_requires_intelligence && has_trait( trait_ILLITERATE ) ) { + return read_condition_result::ILLITERATE; + } + if( has_flag( json_flag_HYPEROPIC ) && + !worn_with_flag( STATIC( flag_id( "FIX_FARSIGHT" ) ) ) && + !has_effect( effect_contacts ) && + !has_flag( STATIC( json_character_flag( "ENHANCED_VISION" ) ) ) ) { + return read_condition_result::NEED_GLASSES; + } + if( fine_detail_vision_mod() > 4 ) { + return read_condition_result::TOO_DARK; + } + if( is_blind() ) { + return read_condition_result::BLIND; + } + + return read_condition_result::SUCCESS; +} + const Character *Character::get_book_reader( const item &book, std::vector &reasons ) const { @@ -11072,19 +11081,19 @@ const Character *Character::get_book_reader( const item &book, const bool book_requires_intelligence = type->intel > 0; // Check for conditions that immediately disqualify the player from reading: - const optional_vpart_position vp = get_map().veh_at( pos() ); - if( vp && vp->vehicle().player_in_control( *this ) ) { + read_condition_result condition = check_read_condition( book ); + if( condition == read_condition_result::DRIVING ) { reasons.emplace_back( _( "It's a bad idea to read while driving!" ) ); return nullptr; } - if( !fun_to_read( book ) && !has_morale_to_read() && has_identified( book.typeId() ) ) { + if( condition == read_condition_result::MORALE_LOW ) { // Low morale still permits skimming reasons.emplace_back( is_avatar() ? _( "What's the point of studying? (Your morale is too low!)" ) : string_format( _( "What's the point of studying? (%s)'s morale is too low!)" ), disp_name() ) ); return nullptr; } - if( get_book_mastery( book ) == book_mastery::CANT_UNDERSTAND ) { + if( condition == read_condition_result::CANT_UNDERSTAND ) { reasons.push_back( is_avatar() ? string_format( _( "%s %d needed to understand. You have %d" ), book_skill->name(), book_skill_requirement, get_knowledge_level( book_skill ) ) : string_format( _( "%s %d needed to understand. %s has %d" ), book_skill->name(), @@ -11093,16 +11102,13 @@ const Character *Character::get_book_reader( const item &book, } // Check for conditions that disqualify us only if no NPCs can read to us - if( book_requires_intelligence && has_trait( trait_ILLITERATE ) ) { + if( condition == read_condition_result::ILLITERATE ) { reasons.emplace_back( is_avatar() ? _( "You're illiterate!" ) : string_format( _( "%s is illiterate!" ), disp_name() ) ); - } else if( has_flag( json_flag_HYPEROPIC ) && - !worn_with_flag( STATIC( flag_id( "FIX_FARSIGHT" ) ) ) && - !has_effect( effect_contacts ) && - !has_flag( STATIC( json_character_flag( "ENHANCED_VISION" ) ) ) ) { + } else if( condition == read_condition_result::NEED_GLASSES ) { reasons.emplace_back( is_avatar() ? _( "Your eyes won't focus without reading glasses." ) : string_format( _( "%s's eyes won't focus without reading glasses." ), disp_name() ) ); - } else if( fine_detail_vision_mod() > 4 ) { + } else if( condition == read_condition_result::TOO_DARK ) { // Too dark to read only applies if the player can read to himself reasons.emplace_back( _( "It's too dark to read!" ) ); return nullptr; @@ -11127,30 +11133,28 @@ const Character *Character::get_book_reader( const item &book, for( const npc *elem : candidates ) { // Check for disqualifying factors: - if( book_requires_intelligence && elem->has_trait( trait_ILLITERATE ) ) { + condition = elem->check_read_condition( book ); + if( condition == read_condition_result::ILLITERATE ) { reasons.push_back( string_format( _( "%s is illiterate!" ), elem->disp_name() ) ); - } else if( elem->get_book_mastery( book ) == book_mastery::CANT_UNDERSTAND ) { + } else if( condition == read_condition_result::CANT_UNDERSTAND ) { reasons.push_back( string_format( _( "%s %d needed to understand. %s has %d" ), book_skill->name(), book_skill_requirement, elem->disp_name(), elem->get_knowledge_level( book_skill ) ) ); - } else if( elem->has_flag( json_flag_HYPEROPIC ) && - !elem->worn_with_flag( STATIC( flag_id( "FIX_FARSIGHT" ) ) ) && - !elem->has_effect( effect_contacts ) ) { + } else if( condition == read_condition_result::NEED_GLASSES ) { reasons.push_back( string_format( _( "%s needs reading glasses!" ), elem->disp_name() ) ); - } else if( std::min( fine_detail_vision_mod(), elem->fine_detail_vision_mod() ) > 4 ) { + } else if( condition == read_condition_result::TOO_DARK ) { reasons.push_back( string_format( _( "It's too dark for %s to read!" ), elem->disp_name() ) ); } else if( !elem->sees( *this ) ) { reasons.push_back( string_format( _( "%s could read that to you, but they can't see you." ), elem->disp_name() ) ); - } else if( !elem->fun_to_read( book ) && !elem->has_morale_to_read() && - has_identified( book.typeId() ) ) { + } else if( condition == read_condition_result::MORALE_LOW ) { // Low morale still permits skimming reasons.push_back( string_format( _( "%s morale is too low!" ), elem->disp_name( true ) ) ); - } else if( elem->is_blind() ) { + } else if( condition == read_condition_result::BLIND ) { reasons.push_back( string_format( _( "%s is blind." ), elem->disp_name() ) ); } else { time_duration proj_time = time_to_read( book, *elem ); diff --git a/src/character.h b/src/character.h index 6ce1a1280c29f..1708e83021cd0 100644 --- a/src/character.h +++ b/src/character.h @@ -387,6 +387,19 @@ enum class book_mastery { MASTERED // can no longer increase skill by reading }; +enum class read_condition_result { + SUCCESS, + NOT_BOOK, + CANT_UNDERSTAND, + MASTERED, + DRIVING, + ILLITERATE, + NEED_GLASSES, + TOO_DARK, + MORALE_LOW, + BLIND +}; + /** @relates ret_val */ template<> struct ret_val::default_success : public @@ -2148,12 +2161,6 @@ class Character : public Creature, public visitable * @param with_equip_change If true returns if it could be worn if things were taken off */ ret_val can_wear( const item &it, bool with_equip_change = false ) const; - /** - * Check if the character needs and be able to read a book. - * @param book Thing to be read. - * @param fail_reasons Why the character cannot read. - */ - bool can_read( const item &book, std::vector &fail_reasons ); /** * Returns true if the character is wielding something. * Note: this item may not actually be used to attack. @@ -2330,6 +2337,13 @@ class Character : public Creature, public visitable time_duration time_to_read( const item &book, const Character &reader, const Character *learner = nullptr ) const; + /** + * Helper function for get_book_reader + * + * @param book The book being read + */ + read_condition_result check_read_condition( const item &book ) const; + /** Calls Creature::normalize() * nulls out the player's weapon * Should only be called through player::normalize(), not on it's own! diff --git a/src/npc.cpp b/src/npc.cpp index 39f56a3ee627a..9a4602fb54ed7 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -1295,6 +1295,40 @@ void npc::starting_weapon( const npc_class_id &type ) } } +bool npc::can_read( const item &book, std::vector &fail_reasons ) +{ + Character *pl = dynamic_cast( this ); + if( !pl ) { + return false; + } + read_condition_result condition = check_read_condition( book ); + if( condition == read_condition_result::NOT_BOOK ) { + fail_reasons.push_back( string_format( _( "This %s is not good reading material." ), + book.tname() ) ); + return false; + } + if( condition == read_condition_result::CANT_UNDERSTAND ) { + fail_reasons.push_back( string_format( _( "I'm not smart enough to read this book." ) ) ); + return false; + } + if( condition == read_condition_result::MASTERED ) { + fail_reasons.push_back( string_format( _( "I won't learn anything from this book." ) ) ); + return false; + } + + // Check for conditions that disqualify us + if( condition == read_condition_result::ILLITERATE ) { + fail_reasons.emplace_back( _( "I can't read!" ) ); + } else if( condition == read_condition_result::NEED_GLASSES ) { + fail_reasons.emplace_back( _( "I can't read without my glasses." ) ); + } else if( condition == read_condition_result::TOO_DARK ) { + // Too dark to read only applies if the player can read to himself + fail_reasons.emplace_back( _( "It's too dark to read!" ) ); + return false; + } + return true; +} + time_duration npc::time_to_read( const item &book, const Character &reader ) const { const auto &type = book.type->book; diff --git a/src/npc.h b/src/npc.h index 5f792021cb770..3751b3ef8db95 100644 --- a/src/npc.h +++ b/src/npc.h @@ -946,6 +946,7 @@ class npc : public Character double value( const item &it, double market_price ) const; faction_price_rule const *get_price_rules( item const &it ) const; bool wear_if_wanted( const item &it, std::string &reason ); + bool can_read( const item &book, std::vector &fail_reasons ); time_duration time_to_read( const item &book, const Character &reader ) const; void do_npc_read( bool ebook = false ); void stow_item( item &it ); From 5b6568f4f1910b2e367c4bb5dac7246202450998 Mon Sep 17 00:00:00 2001 From: lispcoc Date: Mon, 31 Jul 2023 11:12:44 +0900 Subject: [PATCH 5/9] remove unused variable --- src/character.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/character.cpp b/src/character.cpp index 97eb1122f0277..6d0b880028dae 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -11021,16 +11021,13 @@ read_condition_result Character::check_read_condition( const item &book ) const return read_condition_result::NOT_BOOK; } + const bool book_requires_intelligence = book.type->book->intel > 0; + const optional_vpart_position vp = get_map().veh_at( pos() ); if( vp && vp->vehicle().player_in_control( *this ) ) { return read_condition_result::DRIVING; } - const cata::value_ptr &type = book.type->book; - const skill_id &book_skill = type->skill; - const int book_skill_requirement = type->req; - const bool book_requires_intelligence = type->intel > 0; - if( !fun_to_read( book ) && !has_morale_to_read() && has_identified( book.typeId() ) ) { return read_condition_result::MORALE_LOW; } From 373247ad795a84e1cce7ccefaca94a42a36de694 Mon Sep 17 00:00:00 2001 From: lispcoc Date: Mon, 31 Jul 2023 12:16:37 +0900 Subject: [PATCH 6/9] remove unused variable 2 --- src/activity_item_handling.cpp | 1 - src/character.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index 864e9645ee891..aef6b26ad99c2 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -2893,7 +2893,6 @@ static bool generic_multi_activity_do( return false; } } else if( reason == do_activity_reason::NEEDS_BOOK_TO_LEARN ) { - std::vector dummy; const item_filter filter = [ &you ]( const item & i ) { return you.check_read_condition( i ) == read_condition_result::SUCCESS; }; diff --git a/src/character.cpp b/src/character.cpp index 6d0b880028dae..6e958981228f4 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -11075,7 +11075,6 @@ const Character *Character::get_book_reader( const item &book, const cata::value_ptr &type = book.type->book; const skill_id &book_skill = type->skill; const int book_skill_requirement = type->req; - const bool book_requires_intelligence = type->intel > 0; // Check for conditions that immediately disqualify the player from reading: read_condition_result condition = check_read_condition( book ); From 0b9b23378b1230ffde5fc4284b72a17207a96728 Mon Sep 17 00:00:00 2001 From: lispcoc Date: Mon, 31 Jul 2023 12:39:51 +0900 Subject: [PATCH 7/9] make read_condition_result flags --- src/activity_item_handling.cpp | 10 +++- src/character.cpp | 93 +++++++++++++++++----------------- src/character.h | 25 +++++---- src/npc.cpp | 12 ++--- 4 files changed, 75 insertions(+), 65 deletions(-) diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index aef6b26ad99c2..ff55384b7a590 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -1222,7 +1222,10 @@ static activity_reason_info can_do_activity_there( const activity_id &act, Chara } if( act == ACT_MULTIPLE_READ ) { const item_filter filter = [ &you ]( const item & i ) { - return you.check_read_condition( i ) == read_condition_result::SUCCESS; + // Check well lit after + read_condition_result condition = you.check_read_condition( i ); + return condition == read_condition_result::SUCCESS || + condition == read_condition_result::TOO_DARK; }; if( !you.items_with( filter ).empty() ) { return activity_reason_info::ok( do_activity_reason::NEEDS_BOOK_TO_LEARN ); @@ -2894,7 +2897,10 @@ static bool generic_multi_activity_do( } } else if( reason == do_activity_reason::NEEDS_BOOK_TO_LEARN ) { const item_filter filter = [ &you ]( const item & i ) { - return you.check_read_condition( i ) == read_condition_result::SUCCESS; + // Check well lit after + read_condition_result condition = you.check_read_condition( i ); + return condition == read_condition_result::SUCCESS || + condition == read_condition_result::TOO_DARK; }; std::vector books = you.items_with( filter ); if( !books.empty() && books[0] ) { diff --git a/src/character.cpp b/src/character.cpp index 6e958981228f4..e317181bcc777 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -11017,46 +11017,45 @@ bool Character::beyond_final_warning( const faction_id &id ) read_condition_result Character::check_read_condition( const item &book ) const { + read_condition_result result = read_condition_result::SUCCESS; if( !book.is_book() ) { - return read_condition_result::NOT_BOOK; - } - - const bool book_requires_intelligence = book.type->book->intel > 0; - - const optional_vpart_position vp = get_map().veh_at( pos() ); - if( vp && vp->vehicle().player_in_control( *this ) ) { - return read_condition_result::DRIVING; - } + result |= read_condition_result::NOT_BOOK; + } else { + const optional_vpart_position vp = get_map().veh_at( pos() ); + if( vp && vp->vehicle().player_in_control( *this ) ) { + result |= read_condition_result::DRIVING; + } - if( !fun_to_read( book ) && !has_morale_to_read() && has_identified( book.typeId() ) ) { - return read_condition_result::MORALE_LOW; - } + if( !fun_to_read( book ) && !has_morale_to_read() && has_identified( book.typeId() ) ) { + result |= read_condition_result::MORALE_LOW; + } - const book_mastery mastery = get_book_mastery( book ); - if( mastery == book_mastery::CANT_UNDERSTAND ) { - return read_condition_result::CANT_UNDERSTAND; - } - if( mastery == book_mastery::MASTERED ) { - return read_condition_result::MASTERED; - } + const book_mastery mastery = get_book_mastery( book ); + if( mastery == book_mastery::CANT_UNDERSTAND ) { + result |= read_condition_result::CANT_UNDERSTAND; + } + if( mastery == book_mastery::MASTERED ) { + result |= read_condition_result::MASTERED; + } - if( book_requires_intelligence && has_trait( trait_ILLITERATE ) ) { - return read_condition_result::ILLITERATE; - } - if( has_flag( json_flag_HYPEROPIC ) && - !worn_with_flag( STATIC( flag_id( "FIX_FARSIGHT" ) ) ) && - !has_effect( effect_contacts ) && - !has_flag( STATIC( json_character_flag( "ENHANCED_VISION" ) ) ) ) { - return read_condition_result::NEED_GLASSES; - } - if( fine_detail_vision_mod() > 4 ) { - return read_condition_result::TOO_DARK; - } - if( is_blind() ) { - return read_condition_result::BLIND; + const bool book_requires_intelligence = book.type->book->intel > 0; + if( book_requires_intelligence && has_trait( trait_ILLITERATE ) ) { + result |= read_condition_result::ILLITERATE; + } + if( has_flag( json_flag_HYPEROPIC ) && + !worn_with_flag( STATIC( flag_id( "FIX_FARSIGHT" ) ) ) && + !has_effect( effect_contacts ) && + !has_flag( STATIC( json_character_flag( "ENHANCED_VISION" ) ) ) ) { + result |= read_condition_result::NEED_GLASSES; + } + if( fine_detail_vision_mod() > 4 ) { + result |= read_condition_result::TOO_DARK; + } + if( is_blind() ) { + result |= read_condition_result::BLIND; + } } - - return read_condition_result::SUCCESS; + return result; } const Character *Character::get_book_reader( const item &book, @@ -11078,18 +11077,18 @@ const Character *Character::get_book_reader( const item &book, // Check for conditions that immediately disqualify the player from reading: read_condition_result condition = check_read_condition( book ); - if( condition == read_condition_result::DRIVING ) { + if( condition & read_condition_result::DRIVING ) { reasons.emplace_back( _( "It's a bad idea to read while driving!" ) ); return nullptr; } - if( condition == read_condition_result::MORALE_LOW ) { + if( condition & read_condition_result::MORALE_LOW ) { // Low morale still permits skimming reasons.emplace_back( is_avatar() ? _( "What's the point of studying? (Your morale is too low!)" ) : string_format( _( "What's the point of studying? (%s)'s morale is too low!)" ), disp_name() ) ); return nullptr; } - if( condition == read_condition_result::CANT_UNDERSTAND ) { + if( condition & read_condition_result::CANT_UNDERSTAND ) { reasons.push_back( is_avatar() ? string_format( _( "%s %d needed to understand. You have %d" ), book_skill->name(), book_skill_requirement, get_knowledge_level( book_skill ) ) : string_format( _( "%s %d needed to understand. %s has %d" ), book_skill->name(), @@ -11098,13 +11097,13 @@ const Character *Character::get_book_reader( const item &book, } // Check for conditions that disqualify us only if no NPCs can read to us - if( condition == read_condition_result::ILLITERATE ) { + if( condition & read_condition_result::ILLITERATE ) { reasons.emplace_back( is_avatar() ? _( "You're illiterate!" ) : string_format( _( "%s is illiterate!" ), disp_name() ) ); - } else if( condition == read_condition_result::NEED_GLASSES ) { + } else if( condition & read_condition_result::NEED_GLASSES ) { reasons.emplace_back( is_avatar() ? _( "Your eyes won't focus without reading glasses." ) : string_format( _( "%s's eyes won't focus without reading glasses." ), disp_name() ) ); - } else if( condition == read_condition_result::TOO_DARK ) { + } else if( condition & read_condition_result::TOO_DARK ) { // Too dark to read only applies if the player can read to himself reasons.emplace_back( _( "It's too dark to read!" ) ); return nullptr; @@ -11130,27 +11129,27 @@ const Character *Character::get_book_reader( const item &book, for( const npc *elem : candidates ) { // Check for disqualifying factors: condition = elem->check_read_condition( book ); - if( condition == read_condition_result::ILLITERATE ) { + if( condition & read_condition_result::ILLITERATE ) { reasons.push_back( string_format( _( "%s is illiterate!" ), elem->disp_name() ) ); - } else if( condition == read_condition_result::CANT_UNDERSTAND ) { + } else if( condition & read_condition_result::CANT_UNDERSTAND ) { reasons.push_back( string_format( _( "%s %d needed to understand. %s has %d" ), book_skill->name(), book_skill_requirement, elem->disp_name(), elem->get_knowledge_level( book_skill ) ) ); - } else if( condition == read_condition_result::NEED_GLASSES ) { + } else if( condition & read_condition_result::NEED_GLASSES ) { reasons.push_back( string_format( _( "%s needs reading glasses!" ), elem->disp_name() ) ); - } else if( condition == read_condition_result::TOO_DARK ) { + } else if( condition & read_condition_result::TOO_DARK ) { reasons.push_back( string_format( _( "It's too dark for %s to read!" ), elem->disp_name() ) ); } else if( !elem->sees( *this ) ) { reasons.push_back( string_format( _( "%s could read that to you, but they can't see you." ), elem->disp_name() ) ); - } else if( condition == read_condition_result::MORALE_LOW ) { + } else if( condition & read_condition_result::MORALE_LOW ) { // Low morale still permits skimming reasons.push_back( string_format( _( "%s morale is too low!" ), elem->disp_name( true ) ) ); - } else if( condition == read_condition_result::BLIND ) { + } else if( condition & read_condition_result::BLIND ) { reasons.push_back( string_format( _( "%s is blind." ), elem->disp_name() ) ); } else { time_duration proj_time = time_to_read( book, *elem ); diff --git a/src/character.h b/src/character.h index 1708e83021cd0..26d1c9b2cf5a4 100644 --- a/src/character.h +++ b/src/character.h @@ -388,16 +388,21 @@ enum class book_mastery { }; enum class read_condition_result { - SUCCESS, - NOT_BOOK, - CANT_UNDERSTAND, - MASTERED, - DRIVING, - ILLITERATE, - NEED_GLASSES, - TOO_DARK, - MORALE_LOW, - BLIND + SUCCESS = 0, + NOT_BOOK = 1 << 0, + CANT_UNDERSTAND = 1 << 1, + MASTERED = 1 << 2, + DRIVING = 1 << 3, + ILLITERATE = 1 << 4, + NEED_GLASSES = 1 << 5, + TOO_DARK = 1 << 6, + MORALE_LOW = 1 << 7, + BLIND = 1 << 8 +}; + +template<> +struct enum_traits { + static constexpr bool is_flag_enum = true; }; /** @relates ret_val */ diff --git a/src/npc.cpp b/src/npc.cpp index 9a4602fb54ed7..2b26ba5e5aacc 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -1302,26 +1302,26 @@ bool npc::can_read( const item &book, std::vector &fail_reasons ) return false; } read_condition_result condition = check_read_condition( book ); - if( condition == read_condition_result::NOT_BOOK ) { + if( condition & read_condition_result::NOT_BOOK ) { fail_reasons.push_back( string_format( _( "This %s is not good reading material." ), book.tname() ) ); return false; } - if( condition == read_condition_result::CANT_UNDERSTAND ) { + if( condition & read_condition_result::CANT_UNDERSTAND ) { fail_reasons.push_back( string_format( _( "I'm not smart enough to read this book." ) ) ); return false; } - if( condition == read_condition_result::MASTERED ) { + if( condition & read_condition_result::MASTERED ) { fail_reasons.push_back( string_format( _( "I won't learn anything from this book." ) ) ); return false; } // Check for conditions that disqualify us - if( condition == read_condition_result::ILLITERATE ) { + if( condition & read_condition_result::ILLITERATE ) { fail_reasons.emplace_back( _( "I can't read!" ) ); - } else if( condition == read_condition_result::NEED_GLASSES ) { + } else if( condition & read_condition_result::NEED_GLASSES ) { fail_reasons.emplace_back( _( "I can't read without my glasses." ) ); - } else if( condition == read_condition_result::TOO_DARK ) { + } else if( condition & read_condition_result::TOO_DARK ) { // Too dark to read only applies if the player can read to himself fail_reasons.emplace_back( _( "It's too dark to read!" ) ); return false; From 7cd14d84d42c0a66b745a806c82b89a9329b02df Mon Sep 17 00:00:00 2001 From: LISPCoC Date: Mon, 31 Jul 2023 18:32:42 +0900 Subject: [PATCH 8/9] fix light search --- src/activity_item_handling.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index ff55384b7a590..b72ac8e540c19 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -2897,10 +2897,8 @@ static bool generic_multi_activity_do( } } else if( reason == do_activity_reason::NEEDS_BOOK_TO_LEARN ) { const item_filter filter = [ &you ]( const item & i ) { - // Check well lit after read_condition_result condition = you.check_read_condition( i ); - return condition == read_condition_result::SUCCESS || - condition == read_condition_result::TOO_DARK; + return condition == read_condition_result::SUCCESS; }; std::vector books = you.items_with( filter ); if( !books.empty() && books[0] ) { From 83e960a7e66b05410a627039243fbee68354acf2 Mon Sep 17 00:00:00 2001 From: LISPCoC Date: Tue, 1 Aug 2023 00:27:20 +0900 Subject: [PATCH 9/9] sort error --- src/activity_item_handling.cpp | 2 +- src/npctalk_funcs.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index b72ac8e540c19..3e2a684a37d89 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -84,8 +84,8 @@ static const activity_id ACT_MULTIPLE_DIS( "ACT_MULTIPLE_DIS" ); static const activity_id ACT_MULTIPLE_FARM( "ACT_MULTIPLE_FARM" ); static const activity_id ACT_MULTIPLE_FISH( "ACT_MULTIPLE_FISH" ); static const activity_id ACT_MULTIPLE_MINE( "ACT_MULTIPLE_MINE" ); -static const activity_id ACT_MULTIPLE_READ( "ACT_MULTIPLE_READ" ); static const activity_id ACT_MULTIPLE_MOP( "ACT_MULTIPLE_MOP" ); +static const activity_id ACT_MULTIPLE_READ( "ACT_MULTIPLE_READ" ); static const activity_id ACT_PICKAXE( "ACT_PICKAXE" ); static const activity_id ACT_TIDY_UP( "ACT_TIDY_UP" ); static const activity_id ACT_VEHICLE( "ACT_VEHICLE" ); diff --git a/src/npctalk_funcs.cpp b/src/npctalk_funcs.cpp index 3c00c3b255a02..c6f63188353e8 100644 --- a/src/npctalk_funcs.cpp +++ b/src/npctalk_funcs.cpp @@ -70,8 +70,8 @@ static const activity_id ACT_MULTIPLE_DIS( "ACT_MULTIPLE_DIS" ); static const activity_id ACT_MULTIPLE_FARM( "ACT_MULTIPLE_FARM" ); static const activity_id ACT_MULTIPLE_FISH( "ACT_MULTIPLE_FISH" ); static const activity_id ACT_MULTIPLE_MINE( "ACT_MULTIPLE_MINE" ); -static const activity_id ACT_MULTIPLE_READ( "ACT_MULTIPLE_READ" ); static const activity_id ACT_MULTIPLE_MOP( "ACT_MULTIPLE_MOP" ); +static const activity_id ACT_MULTIPLE_READ( "ACT_MULTIPLE_READ" ); static const activity_id ACT_SOCIALIZE( "ACT_SOCIALIZE" ); static const activity_id ACT_TRAIN( "ACT_TRAIN" ); static const activity_id ACT_TRAIN_TEACHER( "ACT_TRAIN_TEACHER" );