diff --git a/data/json/snippets/lab.json b/data/json/snippets/lab.json index 8657d7083c35c..0345abe842a29 100644 --- a/data/json/snippets/lab.json +++ b/data/json/snippets/lab.json @@ -30,81 +30,131 @@ "type": "snippet", "category": "lab_postit_bio", "text": [ - { "id": "lab_postit_bio_1", "text": "Subject amortization too high. Lower dosage?" }, - { "id": "lab_postit_bio_2", "text": "Enrichment makes for better data. Coloring book?" }, - { "id": "lab_postit_bio_3", "text": "Reduce caloric intake. Stress potentiates the process." }, - { "id": "lab_postit_bio_4", "text": "WHEN IN DOUBT, INCINERATE" }, - { "id": "lab_postit_bio_5", "text": "Requisition more subjects when half have been processed." }, - { "id": "lab_postit_bio_6", "text": "Droppings caustic, handle with care" }, - { "id": "lab_postit_bio_7", "text": "DON'T remove from cage between 10-12 PM (it knows)" }, - { "id": "lab_postit_bio_8", "text": "Can walk on ceiling" }, - { "id": "lab_postit_bio_9", "text": "More eggs, keeps eating them" }, - { "id": "lab_postit_bio_10", "text": "DON'T LICK" } + { "name": "green postit 1", "id": "lab_postit_bio_1", "text": "Subject amortization too high. Lower dosage?" }, + { + "name": "green postit 2", + "id": "lab_postit_bio_2", + "text": "Enrichment makes for better data. Coloring book?" + }, + { + "name": "green postit 3", + "id": "lab_postit_bio_3", + "text": "Reduce caloric intake. Stress potentiates the process." + }, + { "name": "green postit 4", "id": "lab_postit_bio_4", "text": "WHEN IN DOUBT, INCINERATE" }, + { + "name": "green postit 5", + "id": "lab_postit_bio_5", + "text": "Requisition more subjects when half have been processed." + }, + { "name": "green postit 6", "id": "lab_postit_bio_6", "text": "Droppings caustic, handle with care" }, + { + "name": "green postit 7", + "id": "lab_postit_bio_7", + "text": "DON'T remove from cage between 10-12 PM (it knows)" + }, + { "name": "green postit 8", "id": "lab_postit_bio_8", "text": "Can walk on ceiling" }, + { "name": "green postit 9", "id": "lab_postit_bio_9", "text": "More eggs, keeps eating them" }, + { "name": "green postit 10", "id": "lab_postit_bio_10", "text": "DON'T LICK" } ] }, { "type": "snippet", "category": "lab_postit_blob", "text": [ - { "id": "lab_postit_blob_1", "text": "Dismember within 15 minutes" }, - { "id": "lab_postit_blob_2", "text": "No weight difference - superpositional?" }, - { "id": "lab_postit_blob_3", "text": "TODO: terminate subject within a week" }, - { "id": "lab_postit_blob_4", "text": "Need more bodies - Mass General?" }, - { "id": "lab_postit_blob_5", "text": "Reinforce doors" }, - { "id": "lab_postit_blob_6", "text": "Where does the energy come from?" }, - { "id": "lab_postit_blob_7", "text": "Anaerobic conditions without change in activity <-> temperature?!" }, - { "id": "lab_postit_blob_8", "text": "Ashes still contaminated" }, - { "id": "lab_postit_blob_9", "text": "Removed parts fuse preferentially to original host" }, - { "id": "lab_postit_blob_10", "text": "Never dead" } + { "name": "grey postit 1", "id": "lab_postit_blob_1", "text": "Dismember within 15 minutes" }, + { "name": "grey postit 2", "id": "lab_postit_blob_2", "text": "No weight difference - superpositional?" }, + { "name": "grey postit 3", "id": "lab_postit_blob_3", "text": "TODO: terminate subject within a week" }, + { "name": "grey postit 4", "id": "lab_postit_blob_4", "text": "Need more bodies - Mass General?" }, + { "name": "grey postit 5", "id": "lab_postit_blob_5", "text": "Reinforce doors" }, + { "name": "grey postit 6", "id": "lab_postit_blob_6", "text": "Where does the energy come from?" }, + { + "name": "grey postit 7", + "id": "lab_postit_blob_7", + "text": "Anaerobic conditions without change in activity <-> temperature?!" + }, + { "name": "grey postit 8", "id": "lab_postit_blob_8", "text": "Ashes still contaminated" }, + { + "name": "grey postit 9", + "id": "lab_postit_blob_9", + "text": "Removed parts fuse preferentially to original host" + }, + { "name": "grey postit 10", "id": "lab_postit_blob_10", "text": "Never dead" } ] }, { "type": "snippet", "category": "lab_postit_migo", "text": [ - { "id": "lab_postit_migo_1", "text": "Don't listen" }, - { "id": "lab_postit_migo_2", "text": "Damage -> Resin\nArmor?\nBlood?\nBribe?" }, - { "id": "lab_postit_migo_3", "text": "Stay quiet. They can hear you." }, + { "name": "pink postit 1", "id": "lab_postit_migo_1", "text": "Don't listen" }, + { "name": "pink postit 2", "id": "lab_postit_migo_2", "text": "Damage -> Resin\nArmor?\nBlood?\nBribe?" }, + { "name": "pink postit 3", "id": "lab_postit_migo_3", "text": "Stay quiet. They can hear you." }, { + "name": "pink postit 4", "id": "lab_postit_migo_4", "text": "Resin return: 0.45 on vegetable matter, 0.51 on meat, 0.66 on nonsedated live meal (vertebrate preference)" }, - { "id": "lab_postit_migo_5", "text": "How can they see me up here?" }, - { "id": "lab_postit_migo_6", "text": "Only post-mortems on the big ones from now on -- equipment's expensive" }, - { "id": "lab_postit_migo_7", "text": "Dim lights before feeding for lightshow" }, + { "name": "pink postit 5", "id": "lab_postit_migo_5", "text": "How can they see me up here?" }, { + "name": "pink postit 6", + "id": "lab_postit_migo_6", + "text": "Only post-mortems on the big ones from now on -- equipment's expensive" + }, + { "name": "pink postit 7", "id": "lab_postit_migo_7", "text": "Dim lights before feeding for lightshow" }, + { + "name": "pink postit 8", "id": "lab_postit_migo_8", "text": "Prefers prey capable of vocalization -- implanted speakers work but no repeats" }, - { "id": "lab_postit_migo_9", "text": "Blast with white noise as a deterrent?" }, - { "id": "lab_postit_migo_10", "text": "Likes it warm, not bothered by cold" } + { "name": "pink postit 9", "id": "lab_postit_migo_9", "text": "Blast with white noise as a deterrent?" }, + { "name": "pink postit 10", "id": "lab_postit_migo_10", "text": "Likes it warm, not bothered by cold" } ] }, { "type": "snippet", "category": "lab_postit_portal", "text": [ - { "id": "lab_postit_portal_1", "text": "Increase frequencies in odd steps - local discontinuity!" }, - { "id": "lab_postit_portal_2", "text": "Limit time spent in-phase to 29.1 minutes" }, - { "id": "lab_postit_portal_3", "text": "Sub-plane 117RA likes prime-numbered calibration pings" }, - { "id": "lab_postit_portal_4", "text": "First the candle, then the blood, NOT THE OTHER WAY AROUND" }, - { "id": "lab_postit_portal_5", "text": "Remember Jake? Me neither." }, - { "id": "lab_postit_portal_6", "text": "Keep line of sight minimal" }, - { "id": "lab_postit_portal_7", "text": "Calibrate on 013TQ for manned transfers" }, - { "id": "lab_postit_portal_8", "text": "No touching returning probes, even if they beg you to" }, - { "id": "lab_postit_portal_9", "text": "Remember to forget. Forget to remember." }, - { "id": "lab_postit_portal_10", "text": "Scream at Maintenance for a replacement again" } + { + "name": "orange postit 1", + "id": "lab_postit_portal_1", + "text": "Increase frequencies in odd steps - local discontinuity!" + }, + { "name": "orange postit 2", "id": "lab_postit_portal_2", "text": "Limit time spent in-phase to 29.1 minutes" }, + { + "name": "orange postit 3", + "id": "lab_postit_portal_3", + "text": "Sub-plane 117RA likes prime-numbered calibration pings" + }, + { + "name": "orange postit 4", + "id": "lab_postit_portal_4", + "text": "First the candle, then the blood, NOT THE OTHER WAY AROUND" + }, + { "name": "orange postit 5", "id": "lab_postit_portal_5", "text": "Remember Jake? Me neither." }, + { "name": "orange postit 6", "id": "lab_postit_portal_6", "text": "Keep line of sight minimal" }, + { "name": "orange postit 7", "id": "lab_postit_portal_7", "text": "Calibrate on 013TQ for manned transfers" }, + { + "name": "orange postit 8", + "id": "lab_postit_portal_8", + "text": "No touching returning probes, even if they beg you to" + }, + { "name": "orange postit 9", "id": "lab_postit_portal_9", "text": "Remember to forget. Forget to remember." }, + { + "name": "orange postit 10", + "id": "lab_postit_portal_10", + "text": "Scream at Maintenance for a replacement again" + } ] }, { "type": "snippet", "category": "lab_postit_tech", "text": [ - { "id": "lab_postit_tech_1", "text": "Don't release switch before discharge" }, - { "id": "lab_postit_tech_2", "text": "Shielding corrodes too fast\n\nMount on drone?" }, - { "id": "lab_postit_tech_3", "text": "Meltdown after 3 shots" }, - { "id": "lab_postit_tech_4", "text": "Need more power" }, - { "id": "lab_postit_tech_5", "text": "Ho lasers stabilise the compound long enough" } + { "name": "red postit 1", "id": "lab_postit_tech_1", "text": "Don't release switch before discharge" }, + { "name": "red postit 2", "id": "lab_postit_tech_2", "text": "Shielding corrodes too fast\n\nMount on drone?" }, + { "name": "red postit 3", "id": "lab_postit_tech_3", "text": "Meltdown after 3 shots" }, + { "name": "red postit 4", "id": "lab_postit_tech_4", "text": "Need more power" }, + { "name": "red postit 5", "id": "lab_postit_tech_5", "text": "Ho lasers stabilise the compound long enough" } ] }, { diff --git a/src/avatar.cpp b/src/avatar.cpp index bbff99a7fc808..7af4cf3e83394 100644 --- a/src/avatar.cpp +++ b/src/avatar.cpp @@ -835,6 +835,11 @@ bool avatar::has_seen_snippet( const snippet_id &snippet ) const return snippets_read.count( snippet ) > 0; } +const std::set &avatar::get_snippets() +{ + return snippets_read; +} + void avatar::vomit() { if( stomach.contains() != 0_ml ) { diff --git a/src/avatar.h b/src/avatar.h index 78aa60b9d5d4f..72ef9916e9402 100644 --- a/src/avatar.h +++ b/src/avatar.h @@ -207,7 +207,7 @@ class avatar : public Character void add_snippet( snippet_id snippet ); bool has_seen_snippet( const snippet_id &snippet ) const; - const std::unordered_set get_snippets(); + const std::set &get_snippets(); // the encumbrance on your limbs reducing your dodging ability int limb_dodge_encumbrance() const; @@ -394,7 +394,7 @@ class avatar : public Character std::unordered_set items_identified; // Snippets the player has seen - std::unordered_set snippets_read; + std::set snippets_read; object_type grab_type; diff --git a/src/faction.cpp b/src/faction.cpp index c07238e4e0ed1..3dea4374c914d 100644 --- a/src/faction.cpp +++ b/src/faction.cpp @@ -35,6 +35,7 @@ #include "pimpl.h" #include "point.h" #include "skill.h" +#include "text_snippets.h" #include "string_formatter.h" #include "talker.h" #include "translations.h" @@ -729,6 +730,7 @@ void faction_manager::display() const TAB_MYFACTION = 0, TAB_FOLLOWERS, TAB_OTHERFACTIONS, + TAB_LORE, NUM_TABS, FIRST_TAB = 0, LAST_TAB = NUM_TABS - 1 @@ -756,6 +758,8 @@ void faction_manager::display() const basecamp *camp = nullptr; std::vector camps; size_t active_vec_size = 0; + std::vector> lore; // Lore we have seen + std::pair *snippet = nullptr; ui.on_redraw( [&]( const ui_adaptor & ) { werase( w_missions ); @@ -768,6 +772,7 @@ void faction_manager::display() const { tab_mode::TAB_MYFACTION, _( "YOUR FACTION" ) }, { tab_mode::TAB_FOLLOWERS, _( "YOUR FOLLOWERS" ) }, { tab_mode::TAB_OTHERFACTIONS, _( "OTHER FACTIONS" ) }, + { tab_mode::TAB_LORE, _( "LORE" ) }, }; draw_tabs( w_missions, tabs, tab ); draw_border_below_tabs( w_missions ); @@ -849,6 +854,29 @@ void faction_manager::display() const } } break; + case tab_mode::TAB_LORE: { + const std::string no_lore = _( "You haven't learned anything about the world." ); + if( active_vec_size > 0 ) { + draw_scrollbar( w_missions, selection, entries_per_page, active_vec_size, + point( 0, 3 ) ); + for( size_t i = top_of_page; i < active_vec_size && i < top_of_page + entries_per_page; i++ ) { + const int y = i - top_of_page + 3; + trim_and_print( w_missions, point( 1, y ), 28, selection == i ? hilite( col ) : col, + _( lore[i].second ) ); + } + if( snippet != nullptr ) { + int y = 2; + fold_and_print( w_missions, point( 31, ++y ), getmaxx( w_missions ) - 31 - 2, c_light_gray, + SNIPPET.get_snippet_by_id( snippet->first ).value().translated() ); + } else { + mvwprintz( w_missions, point( 31, 4 ), c_light_red, no_lore ); + } + break; + } else { + mvwprintz( w_missions, point( 31, 4 ), c_light_red, no_lore ); + } + } + break; default: break; } @@ -875,6 +903,7 @@ void faction_manager::display() const } guy = nullptr; cur_fac = nullptr; + snippet = nullptr; interactable = false; radio_interactable = false; camp = nullptr; @@ -888,6 +917,21 @@ void faction_manager::display() const basecamp *temp_camp = *p; camps.push_back( temp_camp ); } + lore.clear(); + for( const auto &elem : player_character.get_snippets() ) { + cata::optional name = SNIPPET.get_name_by_id( elem ); + if( !name->empty() ) { + lore.push_back( std::pair( elem, name->translated() ) ); + } else { + lore.push_back( std::pair( elem, elem.str() ) ); + } + } + auto compare_second = + []( const std::pair &a, + const std::pair &b ) { + return localized_compare( a.second, b.second ); + }; + std::sort( lore.begin(), lore.end(), compare_second ); if( tab < tab_mode::FIRST_TAB || tab >= tab_mode::NUM_TABS ) { debugmsg( "The sanity check failed because tab=%d", static_cast( tab ) ); tab = tab_mode::FIRST_TAB; @@ -908,6 +952,11 @@ void faction_manager::display() const cur_fac = valfac[selection]; } active_vec_size = valfac.size(); + } else if( tab == tab_mode::TAB_LORE ) { + if( selection < lore.size() ) { + snippet = &lore[selection]; + } + active_vec_size = lore.size(); } ui_manager::redraw(); diff --git a/src/savegame_json.cpp b/src/savegame_json.cpp index 44f94288da23c..36d8ae4e4780d 100644 --- a/src/savegame_json.cpp +++ b/src/savegame_json.cpp @@ -1429,6 +1429,9 @@ void avatar::store( JsonOut &json ) const // Player only, books they have read at least once. json.member( "items_identified", items_identified ); + // Player only, snippets they have read at least once. + json.member( "snippets_read", snippets_read ); + json.member( "translocators", translocators ); // mission stuff @@ -1602,6 +1605,8 @@ void avatar::load( const JsonObject &data ) data.read( "calorie_diary", calorie_diary ); data.read( "preferred_aiming_mode", preferred_aiming_mode ); + + data.read( "snippets_read", snippets_read ); } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/text_snippets.cpp b/src/text_snippets.cpp index 259cdd0ecd6ec..bfa072b84bbd3 100644 --- a/src/text_snippets.cpp +++ b/src/text_snippets.cpp @@ -67,9 +67,11 @@ void snippet_library::add_snippet_from_json( const std::string &category, const snippets_by_category[category].ids.emplace_back( id ); snippets_by_id[id] = text; if( jo.has_member( "effect_on_examine" ) ) { - //JsonObject effect_obj = jo.get_object( "effect_on_examine" ); EOC_by_id[id] = talk_effect_t( jo, "effect_on_examine" ); } + translation name; + optional( jo, false, "name", name ); + name_by_id[id] = name; } else { snippets_by_category[category].no_id.emplace_back( text ); } @@ -105,6 +107,15 @@ cata::optional snippet_library::get_EOC_by_id( const snippet_id & return it->second; } +cata::optional snippet_library::get_name_by_id( const snippet_id &id ) const +{ + const auto it = name_by_id.find( id ); + if( it == name_by_id.end() ) { + return cata::nullopt; + } + return it->second; +} + const translation &snippet_library::get_snippet_ref_by_id( const snippet_id &id ) const { const auto it = snippets_by_id.find( id ); diff --git a/src/text_snippets.h b/src/text_snippets.h index 801b83125d465..8160f683fb252 100644 --- a/src/text_snippets.h +++ b/src/text_snippets.h @@ -51,6 +51,11 @@ class snippet_library * is no snippet with such id. */ cata::optional get_EOC_by_id( const snippet_id &id ) const; + /** + * Returns the name connected with the snippet referenced by the id, or cata::nullopt if there + * is no snippet with such id. + */ + cata::optional get_name_by_id( const snippet_id &id ) const; /** * Returns a reference to the snippet with the id, or a reference to an * empty translation object if no such snippet exist. @@ -109,6 +114,8 @@ class snippet_library private: std::unordered_map snippets_by_id; + // front facing name + std::unordered_map name_by_id; std::unordered_map EOC_by_id; struct category_snippets {