From 6f98147e265d72979aa6e9cb65419ca1c5457d95 Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Sun, 9 Dec 2018 14:05:18 -0600 Subject: [PATCH 1/3] dialogue.h: make the effect functions easier to access In order to move mission start functions into JSON, it would be useful to be have access to the dialogue system's effect infrastructure. Move that code outside of talk_response:: and to the top level. --- src/dialogue.h | 177 +++++++++++++++++++++------------------- src/npctalk.cpp | 63 +++++++------- tests/npc_talk_test.cpp | 2 +- 3 files changed, 125 insertions(+), 117 deletions(-) diff --git a/src/dialogue.h b/src/dialogue.h index 58b13adbc693b..b5ecb873c78e3 100644 --- a/src/dialogue.h +++ b/src/dialogue.h @@ -81,98 +81,103 @@ struct talk_topic { std::string reason; }; +struct talk_effect_fun_t { + private: + std::function function; + + public: + talk_effect_fun_t() = default; + talk_effect_fun_t( talkfunction_ptr effect ); + talk_effect_fun_t( const std::function effect ); + void set_companion_mission( const std::string &role_id ); + void set_u_add_permanent_effect( const std::string &new_effect ); + void set_u_add_effect( const std::string &new_effect, const time_duration &duration ); + void set_npc_add_permanent_effect( const std::string &new_effect ); + void set_npc_add_effect( const std::string &new_effect, const time_duration &duration ); + void set_u_add_trait( const std::string &new_trait ); + void set_npc_add_trait( const std::string &new_trait ); + void set_u_buy_item( const std::string &new_trait, int cost, int count, + const std::string &container_name ); + void set_u_spend_cash( int amount ); + void set_npc_change_faction( const std::string &faction_name ); + void set_change_faction_rep( int amount ); + void operator()( const dialogue &d ) const { + if( !function ) { + return; + } + return function( d ); + } +}; + /** - * This defines possible responses from the player character. + * Defines what happens when the trial succeeds or fails. If trial is + * TALK_TRIAL_NONE it always succeeds. */ -struct talk_response { +struct talk_effect_t { /** - * What the player character says (literally). Should already be translated and will be - * displayed. - */ - std::string text; - talk_trial trial; + * How (if at all) the NPCs opinion of the player character (@ref npc::op_of_u) will change. + */ + npc_opinion opinion; /** - * The following values are forwarded to the chatbin of the NPC (see @ref npc_chatbin). - */ - mission *mission_selected = nullptr; - skill_id skill = skill_id::NULL_ID(); - matype_id style = matype_id::NULL_ID(); - struct effect_fun_t { - private: - std::function function; - - public: - effect_fun_t() = default; - effect_fun_t( talkfunction_ptr effect ); - effect_fun_t( std::function effect ); - void set_companion_mission( std::string &role_id ); - void set_u_add_permanent_effect( std::string &new_effect ); - void set_u_add_effect( std::string &new_effect, const time_duration &duration ); - void set_npc_add_permanent_effect( std::string &new_effect ); - void set_npc_add_effect( std::string &new_effect, const time_duration &duration ); - void set_u_add_trait( std::string &new_trait ); - void set_npc_add_trait( std::string &new_trait ); - void set_u_buy_item( std::string &new_trait, int cost, int count, std::string &container_name ); - void set_u_spend_cash( int amount ); - void set_npc_change_faction( std::string &faction_name ); - void set_change_faction_rep( int amount ); - void operator()( const dialogue &d ) const { - if( !function ) { - return; - } - return function( d ); - } - }; + * Topic to switch to. TALK_DONE ends the talking, TALK_NONE keeps the current topic. + */ + talk_topic next_topic = talk_topic( "TALK_NONE" ); + + talk_topic apply( dialogue &d ) const; + dialogue_consequence get_consequence( const dialogue &d ) const; + + /** + * Sets an effect and consequence based on function pointer. + */ + void set_effect( talkfunction_ptr effect ); + void set_effect( talk_effect_fun_t effect ); /** - * Defines what happens when the trial succeeds or fails. If trial is - * TALK_TRIAL_NONE it always succeeds. + * Sets an effect to a function object and consequence to explicitly given one. + */ + void set_effect_consequence( const talk_effect_fun_t &eff, dialogue_consequence con ); + void set_effect_consequence( std::function ptr, dialogue_consequence con ); + + void load_effect( JsonObject &jo ); + void parse_sub_effect( JsonObject jo ); + void parse_string_effect( const std::string &type, JsonObject &jo ); + + talk_effect_t() = default; + talk_effect_t( JsonObject ); + + /** + * Functions that are called when the response is chosen. */ - struct effect_t { - /** - * How (if at all) the NPCs opinion of the player character (@ref npc::op_of_u) will change. - */ - npc_opinion opinion; - /** - * Topic to switch to. TALK_DONE ends the talking, TALK_NONE keeps the current topic. - */ - talk_topic next_topic = talk_topic( "TALK_NONE" ); - - talk_topic apply( dialogue &d ) const; - dialogue_consequence get_consequence( const dialogue &d ) const; - - /** - * Sets an effect and consequence based on function pointer. - */ - void set_effect( talkfunction_ptr effect ); - void set_effect( effect_fun_t effect ); - /** - * Sets an effect to a function object and consequence to explicitly given one. - */ - void set_effect_consequence( const effect_fun_t &eff, dialogue_consequence con ); - void set_effect_consequence( std::function ptr, dialogue_consequence con ); - - void load_effect( JsonObject &jo ); - void parse_sub_effect( JsonObject jo ); - void parse_string_effect( const std::string &type, JsonObject &jo ); - - effect_t() = default; - effect_t( JsonObject ); - - private: - /** - * Functions that are called when the response is chosen. - */ - std::vector effects; - dialogue_consequence guaranteed_consequence = dialogue_consequence::none; - }; - effect_t success; - effect_t failure; - - talk_data create_option_line( const dialogue &d, char letter ); - std::set get_consequences( const dialogue &d ) const; - - talk_response() = default; - talk_response( JsonObject ); + std::vector effects; + private: + dialogue_consequence guaranteed_consequence = dialogue_consequence::none; +}; + + +/** + * This defines possible responses from the player character. + */ +struct talk_response { + /** + * What the player character says (literally). Should already be translated and will be + * displayed. + */ + std::string text; + talk_trial trial; + /** + * The following values are forwarded to the chatbin of the NPC (see @ref npc_chatbin). + */ + mission *mission_selected = nullptr; + skill_id skill = skill_id::NULL_ID(); + matype_id style = matype_id::NULL_ID(); + + talk_effect_t success; + talk_effect_t failure; + + talk_data create_option_line( const dialogue &d, char letter ); + std::set get_consequences( const dialogue &d ) const; + + talk_response() = default; + talk_response( JsonObject ); }; struct dialogue { diff --git a/src/npctalk.cpp b/src/npctalk.cpp index bffc9843116f7..c2c8332d45cc9 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -1651,7 +1651,7 @@ std::set talk_response::get_consequences( const dialogue & return {{ success.get_consequence( d ), failure.get_consequence( d ) }}; } -dialogue_consequence talk_response::effect_t::get_consequence( const dialogue &d ) const +dialogue_consequence talk_effect_t::get_consequence( const dialogue &d ) const { if( d.beta->op_of_u.anger + opinion.anger >= d.beta->hostile_anger_level() ) { return dialogue_consequence::hostile; @@ -1811,7 +1811,7 @@ talk_topic load_inline_topic( JsonObject jo ) return talk_topic( id ); } -talk_response::effect_fun_t::effect_fun_t( talkfunction_ptr ptr ) +talk_effect_fun_t::talk_effect_fun_t( talkfunction_ptr ptr ) { function = [ptr]( const dialogue &d ) { npc &p = *d.beta; @@ -1819,7 +1819,7 @@ talk_response::effect_fun_t::effect_fun_t( talkfunction_ptr ptr ) }; } -talk_response::effect_fun_t::effect_fun_t( std::function ptr ) +talk_effect_fun_t::talk_effect_fun_t( std::function ptr ) { function = [ptr]( const dialogue &d ) { npc &p = *d.beta; @@ -1827,7 +1827,7 @@ talk_response::effect_fun_t::effect_fun_t( std::function ptr ) }; } -void talk_response::effect_fun_t::set_companion_mission( std::string &role_id ) +void talk_effect_fun_t::set_companion_mission( const std::string &role_id ) { function = [role_id]( const dialogue &d ) { npc &p = *d.beta; @@ -1836,7 +1836,7 @@ void talk_response::effect_fun_t::set_companion_mission( std::string &role_id ) }; } -void talk_response::effect_fun_t::set_u_add_permanent_effect( std::string &new_effect ) +void talk_effect_fun_t::set_u_add_permanent_effect( const std::string &new_effect ) { function = [new_effect]( const dialogue &d ) { player &u = *d.alpha; @@ -1844,7 +1844,7 @@ void talk_response::effect_fun_t::set_u_add_permanent_effect( std::string &new_e }; } -void talk_response::effect_fun_t::set_u_add_effect( std::string &new_effect, const time_duration &duration ) +void talk_effect_fun_t::set_u_add_effect( const std::string &new_effect, const time_duration &duration ) { function = [new_effect, duration]( const dialogue &d ) { player &u = *d.alpha; @@ -1852,7 +1852,7 @@ void talk_response::effect_fun_t::set_u_add_effect( std::string &new_effect, con }; } -void talk_response::effect_fun_t::set_npc_add_permanent_effect( std::string &new_effect ) +void talk_effect_fun_t::set_npc_add_permanent_effect( const std::string &new_effect ) { function = [new_effect]( const dialogue &d ) { npc &p = *d.beta; @@ -1860,7 +1860,8 @@ void talk_response::effect_fun_t::set_npc_add_permanent_effect( std::string &new }; } -void talk_response::effect_fun_t::set_npc_add_effect( std::string &new_effect, const time_duration &duration ) +void talk_effect_fun_t::set_npc_add_effect( const std::string &new_effect, + const time_duration &duration ) { function = [new_effect, duration]( const dialogue &d ) { npc &p = *d.beta; @@ -1868,7 +1869,7 @@ void talk_response::effect_fun_t::set_npc_add_effect( std::string &new_effect, c }; } -void talk_response::effect_fun_t::set_u_add_trait( std::string &new_trait ) +void talk_effect_fun_t::set_u_add_trait( const std::string &new_trait ) { function = [new_trait]( const dialogue &d ) { player &u = *d.alpha; @@ -1876,7 +1877,7 @@ void talk_response::effect_fun_t::set_u_add_trait( std::string &new_trait ) }; } -void talk_response::effect_fun_t::set_npc_add_trait( std::string &new_trait ) +void talk_effect_fun_t::set_npc_add_trait( const std::string &new_trait ) { function = [new_trait]( const dialogue &d ) { npc &p = *d.beta; @@ -1884,7 +1885,8 @@ void talk_response::effect_fun_t::set_npc_add_trait( std::string &new_trait ) }; } -void talk_response::effect_fun_t::set_u_buy_item( std::string &item_name, int cost, int count, std::string &container_name ) +void talk_effect_fun_t::set_u_buy_item( const std::string &item_name, int cost, int count, + const std::string &container_name ) { function = [item_name, cost, count, container_name]( const dialogue &d ) { npc &p = *d.beta; @@ -1910,7 +1912,7 @@ void talk_response::effect_fun_t::set_u_buy_item( std::string &item_name, int co }; } -void talk_response::effect_fun_t::set_u_spend_cash( int amount ) +void talk_effect_fun_t::set_u_spend_cash( int amount ) { function = [amount]( const dialogue &d ) { player &u = *d.alpha; @@ -1918,7 +1920,7 @@ void talk_response::effect_fun_t::set_u_spend_cash( int amount ) }; } -void talk_response::effect_fun_t::set_npc_change_faction( std::string &faction_name ) +void talk_effect_fun_t::set_npc_change_faction( const std::string &faction_name ) { function = [faction_name]( const dialogue &d ) { npc &p = *d.beta; @@ -1926,7 +1928,7 @@ void talk_response::effect_fun_t::set_npc_change_faction( std::string &faction_n }; } -void talk_response::effect_fun_t::set_change_faction_rep( int rep_change ) +void talk_effect_fun_t::set_change_faction_rep( int rep_change ) { function = [rep_change]( const dialogue &d ) { npc &p = *d.beta; @@ -1935,31 +1937,32 @@ void talk_response::effect_fun_t::set_change_faction_rep( int rep_change ) }; } -void talk_response::effect_t::set_effect_consequence( const effect_fun_t &fun, dialogue_consequence con ) +void talk_effect_t::set_effect_consequence( const talk_effect_fun_t &fun, dialogue_consequence con ) { effects.push_back( fun ); guaranteed_consequence = std::max( guaranteed_consequence, con ); } -void talk_response::effect_t::set_effect_consequence( std::function ptr, dialogue_consequence con ) +void talk_effect_t::set_effect_consequence( std::function ptr, dialogue_consequence con ) { - effect_fun_t npctalk_setter( ptr ); + talk_effect_fun_t npctalk_setter( ptr ); set_effect_consequence( npctalk_setter, con ); } -void talk_response::effect_t::set_effect( effect_fun_t fun ) +void talk_effect_t::set_effect( talk_effect_fun_t fun ) { effects.push_back( fun ); guaranteed_consequence = std::max( guaranteed_consequence, dialogue_consequence::none ); } -void talk_response::effect_t::set_effect( talkfunction_ptr ptr ) +void talk_effect_t::set_effect( talkfunction_ptr ptr ) { - effect_fun_t npctalk_setter( ptr ); + talk_effect_fun_t npctalk_setter( ptr ); dialogue_consequence response; if( ptr == &talk_function::hostile ) { response = dialogue_consequence::hostile; - } else if( ptr == &talk_function::player_weapon_drop || ptr == &talk_function::player_weapon_away || + } else if( ptr == &talk_function::player_weapon_drop || + ptr == &talk_function::player_weapon_away || ptr == &talk_function::start_mugging ) { response = dialogue_consequence::helpless; } else { @@ -1968,9 +1971,9 @@ void talk_response::effect_t::set_effect( talkfunction_ptr ptr ) set_effect_consequence( npctalk_setter, response ); } -talk_topic talk_response::effect_t::apply( dialogue &d ) const +talk_topic talk_effect_t::apply( dialogue &d ) const { - for( const effect_fun_t &effect: effects ) { + for( const talk_effect_fun_t &effect: effects ) { effect( d ); } d.beta->op_of_u += opinion; @@ -1993,7 +1996,7 @@ talk_topic talk_response::effect_t::apply( dialogue &d ) const return next_topic; } -talk_response::effect_t::effect_t( JsonObject jo ) +talk_effect_t::talk_effect_t( JsonObject jo ) { load_effect( jo ); if( jo.has_object( "topic" ) ) { @@ -2008,9 +2011,9 @@ talk_response::effect_t::effect_t( JsonObject jo ) } } -void talk_response::effect_t::parse_sub_effect( JsonObject jo ) +void talk_effect_t::parse_sub_effect( JsonObject jo ) { - effect_fun_t subeffect_fun; + talk_effect_fun_t subeffect_fun; if( jo.has_string( "companion_mission" ) ) { std::string role_id = jo.get_string( "companion_mission" ); subeffect_fun.set_companion_mission( role_id ); @@ -2064,7 +2067,7 @@ void talk_response::effect_t::parse_sub_effect( JsonObject jo ) set_effect( subeffect_fun ); } -void talk_response::effect_t::parse_string_effect( const std::string &type, JsonObject &jo ) +void talk_effect_t::parse_string_effect( const std::string &type, JsonObject &jo ) { static const std::unordered_map static_functions_map = { { @@ -2124,7 +2127,7 @@ void talk_response::effect_t::parse_string_effect( const std::string &type, Json jo.throw_error( "unknown effect string", type ); } -void talk_response::effect_t::load_effect( JsonObject &jo ) +void talk_effect_t::load_effect( JsonObject &jo ) { static const std::string member_name( "effect" ); if( !jo.has_member( member_name ) ) { @@ -2159,7 +2162,7 @@ talk_response::talk_response( JsonObject jo ) trial = talk_trial( jo.get_object( "trial" ) ); } if( jo.has_member( "success" ) ) { - success = effect_t( jo.get_object( "success" ) ); + success = talk_effect_t( jo.get_object( "success" ) ); } else if( jo.has_string( "topic" ) ) { // This is for simple topic switching without a possible failure success.next_topic = talk_topic( jo.get_string( "topic" ) ); @@ -2171,7 +2174,7 @@ talk_response::talk_response( JsonObject jo ) jo.throw_error( "the failure effect is mandatory if a talk_trial has been defined" ); } if( jo.has_member( "failure" ) ) { - failure = effect_t( jo.get_object( "failure" ) ); + failure = talk_effect_t( jo.get_object( "failure" ) ); } text = _( jo.get_string( "text" ).c_str() ); // TODO: mission_selected diff --git a/tests/npc_talk_test.cpp b/tests/npc_talk_test.cpp index e0701a0d080c3..6ad07a0ea5f20 100644 --- a/tests/npc_talk_test.cpp +++ b/tests/npc_talk_test.cpp @@ -274,7 +274,7 @@ TEST_CASE( "npc_talk_test" ) d.gen_responses( d.topic_stack.back() ); REQUIRE( d.responses.size() == 9 ); REQUIRE( !g->u.has_effect( effect_infection ) ); - talk_response::effect_t &effects = d.responses[1].success; + talk_effect_t &effects = d.responses[1].success; effects.apply( d ); CHECK( g->u.has_effect( effect_infection ) ); CHECK( g->u.get_effect_dur( effect_infection ) == time_duration::from_turns( 10 ) ); From 1a5776483674b6106c339d36c579c3f2a8743e7b Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Sun, 9 Dec 2018 20:31:54 -0600 Subject: [PATCH 2/3] mission_start: replace some "start" functions with JSON objects start adding the infrastructure to move the mission "start" value from hardcoded C++ functions to a more flexible JSON interface. As a first step, add a way to invoke dialogue effects. Also add a way to call the reveal overmap terrain and target overmap terrain functions. Fix the MGOAL_KILL_MONSTER_TYPE and MGOAL_KILL_MONSTER_SPECIES goals to not need a hardcoded function to set the goal count. --- data/json/npcs/missiondef.json | 47 ++++++--- doc/MISSIONS_JSON.md | 123 ++++++++++++++++++++++ doc/NPCs.md | 3 + src/mission.h | 12 +++ src/mission_start.cpp | 185 +++++++++++++++++++++++++++++---- src/missiondef.cpp | 7 +- 6 files changed, 340 insertions(+), 37 deletions(-) create mode 100644 doc/MISSIONS_JSON.md diff --git a/data/json/npcs/missiondef.json b/data/json/npcs/missiondef.json index cc6cbd5e0b678..d6e19de585b21 100644 --- a/data/json/npcs/missiondef.json +++ b/data/json/npcs/missiondef.json @@ -27,7 +27,10 @@ "goal": "MGOAL_GO_TO_TYPE", "difficulty": 2, "value": 50000, - "start": "open_sarcophagus", + "start": { + "effect": [ "follow", { "u_buy_item": "sarcophagus_access_code" } ], + "target_om_ter": { "om_ter": "haz_sar", "reveal_rad": 3 } + }, "origins": [ "ORIGIN_SECONDARY" ], "destination": "haz_sar_b1", "dialogue": { @@ -215,7 +218,10 @@ "difficulty": 2, "value": 150000, "item": "black_box_transcript", - "start": "reveal_lab_black_box", + "start": { + "effect": { "u_buy_item": "black_box" }, + "target_om_ter": { "om_ter": "lab", "reveal_rad": 3 } + }, "origins": [ "ORIGIN_SECONDARY" ], "followup": "MISSION_EXPLORE_SARCOPHAGUS", "dialogue": { @@ -281,7 +287,7 @@ "difficulty": 2, "value": 140000, "item": "record_accounting", - "start": "reveal_office_tower", + "start": { "reveal_om_ter": "office_tower_1" }, "origins": [ "ORIGIN_OPENER_NPC", "ORIGIN_ANY_NPC" ], "followup": "MISSION_GET_SAFE_BOX", "dialogue": { @@ -304,7 +310,7 @@ "difficulty": 2, "value": 60000, "item": "record_patient", - "start": "reveal_doctors_office", + "start": { "reveal_om_ter": [ "office_doctor", "hospital_2" ] }, "origins": [ "ORIGIN_OPENER_NPC", "ORIGIN_ANY_NPC" ], "followup": "MISSION_REACH_FEMA_CAMP", "dialogue": { @@ -327,7 +333,7 @@ "difficulty": 2, "value": 50000, "item": "record_weather", - "start": "reveal_weather_station", + "start": { "reveal_om_ter": "station_radio" }, "origins": [ "ORIGIN_OPENER_NPC", "ORIGIN_ANY_NPC" ], "dialogue": { "describe": "I wonder if a retreat might exist...", @@ -349,7 +355,7 @@ "difficulty": 2, "value": 100000, "item": "small_relic", - "start": "reveal_cathedral", + "start": { "reveal_om_ter": [ "cathedral_1", "museum" ] }, "origins": [ "ORIGIN_OPENER_NPC", "ORIGIN_ANY_NPC" ], "followup": "MISSION_RECOVER_PRIEST_DIARY", "dialogue": { @@ -418,7 +424,10 @@ "difficulty": 8, "value": 250000, "item": "software_blood_data", - "start": "reveal_hospital", + "start": { + "effect": [ { "u_buy_item": "vacutainer" }, { "u_buy_item": "usb_drive" } ], + "target_om_ter": { "om_ter": "hospital_2", "reveal_rad": 3 } + }, "origins": [ "ORIGIN_SECONDARY" ], "dialogue": { "describe": "It could be very informative to perform an analysis of zombie blood...", @@ -440,7 +449,7 @@ "difficulty": 2, "value": 150000, "item": "etched_skull", - "start": "point_cabin_strange", + "start": { "target_om_ter": { "om_ter": "cabin_strange", "reveal_rad": 3 } }, "origins": [ "ORIGIN_SECONDARY" ], "followup": "MISSION_INVESTIGATE_PRISON_VISIONARY", "dialogue": { @@ -463,7 +472,7 @@ "difficulty": 2, "value": 150000, "item": "visions_solitude", - "start": "point_prison", + "start": { "target_om_ter": { "om_ter": "prison_1_5", "reveal_rad": 3 } }, "origins": [ "ORIGIN_SECONDARY" ], "dialogue": { "describe": "St. Michael the archangel defend me in battle...", @@ -486,7 +495,7 @@ "value": 0, "urgent": true, "item": "badge_deputy", - "start": "join", + "start": { "effect": "follow" }, "origins": [ "ORIGIN_SECONDARY" ], "dialogue": { "describe": "Well damn, you must be the guys here to pick me up...", @@ -509,7 +518,7 @@ "monster_kill_goal": 100, "difficulty": 5, "value": 250000, - "start": "join", + "start": { "effect": "follow" }, "end": "leave", "origins": [ "ORIGIN_SECONDARY" ], "followup": "MISSION_KILL_HORDE_MASTER", @@ -646,8 +655,8 @@ "goal": "MGOAL_KILL_MONSTER_TYPE", "difficulty": 5, "value": 250000, - "start": "kill_20_nightmares", "monster_type": "mon_charred_nightmare", + "start": { "target_om_ter": { "om_ter": "necropolis_c_44", "zlevel": -2 } }, "monster_kill_goal": 20, "origins": [ "ORIGIN_SECONDARY" ], "dialogue": { @@ -670,7 +679,10 @@ "difficulty": 2, "value": 250000, "item": "radio_repeater_mod", - "start": "radio_repeater", + "start": { + "effect": { "u_buy_item": "repeater_mod_guide" }, + "target_om_ter": { "om_ter": "necropolis_c_23", "reveal_rad": 3, "zlevel": -2 } + }, "origins": [ "ORIGIN_SECONDARY" ], "followup": "MISSION_OLD_GUARD_NEC_COMMO_2", "dialogue": { @@ -1722,7 +1734,7 @@ "goal": "MGOAL_GO_TO_TYPE", "difficulty": 2, "value": 60000, - "start": "join", + "start": { "effect": "follow" }, "end": "leave", "origins": [ "ORIGIN_SECONDARY" ], "destination": "farm", @@ -1745,7 +1757,7 @@ "goal": "MGOAL_GO_TO_TYPE", "difficulty": 2, "value": 60000, - "start": "join", + "start": { "effect": "follow" }, "origins": [ "ORIGIN_SECONDARY" ], "followup": "MISSION_REACH_FARM_HOUSE", "destination": "fema", @@ -1867,7 +1879,10 @@ "difficulty": 5, "value": 50000, "item": "software_blood_data", - "start": "reveal_hospital", + "start": { + "effect": [ { "u_buy_item": "vacutainer" }, { "u_buy_item": "usb_drive" } ], + "target_om_ter": { "om_ter": "hospital_2", "reveal_rad": 3 } + }, "origins": [ "ORIGIN_SECONDARY" ], "followup": "MISSION_SCIENCE_REP_2", "dialogue": { diff --git a/doc/MISSIONS_JSON.md b/doc/MISSIONS_JSON.md new file mode 100644 index 0000000000000..b1850f381a3ea --- /dev/null +++ b/doc/MISSIONS_JSON.md @@ -0,0 +1,123 @@ +# Creating missions + +NPCs can assign missions to the player. There is a fairly regular structure for this: + +```JSON + { + "id": "MISSION_GET_BLACK_BOX_TRANSCRIPT", + "type": "mission_definition", + "name": "Retrieve Black Box Transcript", + "goal": "MGOAL_FIND_ITEM", + "difficulty": 2, + "value": 150000, + "item": "black_box_transcript", + "start": { + "effect": { "u_buy_item": "black_box" }, + "target_om_ter": { "om_ter": "lab", "reveal_rad": 3 } + }, + "origins": [ "ORIGIN_SECONDARY" ], + "followup": "MISSION_EXPLORE_SARCOPHAGUS", + "dialogue": { + "describe": "With the black box in hand, we need to find a lab.", + "offer": "Thanks to your searching we've got the black box but now we need to have a look'n-side her. Now, most buildings don't have power anymore but there are a few that might be of use. Have you ever seen one of those science labs that have popped up in the middle of nowhere? Them suckers have a glowing terminal out front so I know they have power somewhere inside'em. If you can get inside and find a computer lab that still works you ought to be able to find out what's in the black box.", + "accepted": "Fuck ya, America!", + "rejected": "Do you have any better ideas?", + "advice": "When I was play'n with the terminal for the one I ran into it kept asking for an ID card. Finding one would be the first order of business.", + "inquire": "How 'bout that black box?", + "success": "America, fuck ya! I was in the guard a few years back so I'm confident I can make heads-or-tails of these transmissions.", + "success_lie": "What?! I out'ta whip you're ass.", + "failure": "Damn, I maybe we can find an egg-head to crack the terminal." + } + } +``` + +### type +Must always be there and must always be "mission_definition". + +### id +The mission id is required, but for new missions, it can be arbitrary. Convention is to start +it with "MISSION" and to use a fairly desriptive name. + +### name +The name is also required, and the name is what is displayed in the 'm'issions menu, so please +make it descriptive. + +### goal +Must be included, and must be one of these strings: +"MGOAL_GO_TO" - Reach a specific overmap tile +"MGOAL_GO_TO_TYPE" - Reach any instance of a specified overmap tile type +"MGOAL_COMPUTER_TOGGLE" - Activating the correct terminal will complete the mission +"MGOAL_FIND_ITEM" - Find 1 or more items of a given type +"MGOAL_FIND_ANY_ITEM" - Find 1 or more items of a given type, tagged for this mission +"MGOAL_FIND_MONSTER" - Find and retrieve a friendly monster +"MGOAL_FIND_NPC" - Find a specific NPC +"MGOAL_RECRUIT_NPC" - Recruit a specific NPC +"MGOAL_RECRUIT_NPC_CLASS" - Recruit an NPC of a specific class +"MGOAL_ASSASSINATE" - Kill a specific NPC +"MGOAL_KILL_MONSTER" - Kill a specific hostile monster +"MGOAL_KILL_MONSTER_TYPE" - Kill some number of a specific monster type +"MGOAL_KILL_MONSTER_SPEC" - Kill some number of monsters from a specific species + +Currently, only "MGOAL_FIND_ITEM", "MGOAL_KILL_MONSTER_TYPE", and "MGOAL_KILL_MONSTER_SPEC" +missions can be fully defined in JSON without requiring C++ code support. + +### start +Optional field. If it is present and a string, it must be name of a function in mission_start:: +that takes a mission * and performs the start code for the mission. A hardcoded function is +currently necessary to set up any mission other than MGOAL_FIND_ITEM", "MGOAL_KILL_MONSTER_TYPE", +or "MGOAL_KILL_MONSTER_SPEC". + +Alternately, if present, it can be an object with any of the following optional fields: + +#### effects +This is an effects array, exactly as defined in NPCs.md, and can use any of the values from +effects. In all cases, the NPC involved is the quest giver. + +#### reveal_om_ter +This can be a string or a list of strings, all of which must be overmap terrain ids. A randomly +selected overmap terrain tile with that id - or one of the ids from list, randomly selected - +will be revealed, and there is a 1 in 3 chance that the road route to the map tile will also +be revealed. + +#### target_om_ter or target_om_ter_random or target_om_ter_random_or_create +Each of these is an object, with a mandatory field of "om_ter" that must be an overmap terrain +id. "target_om_ter_random_or_create" also has mandatory fields of "om_spec" and "om_replace_ter", +which must be an overmap special id and an overmap terrain id, respectively. + +All three also have the optional fields of "reveal_rad" which is an number, and "must_see" +which is a boolean. "target_om_ter" has a third optional field of "zlevel", which again is a +number, while the other two have "range", which is also a number. + +"target_om_ter" sets the mission target to be the closet terrain of om_ter, optionally the closest +that the player has already seen if "must_see" is true. If "reveal_rad" is 1 or more, it also +reveals the overmap around the target for reveal_rad tiles. The terrain can be at a different +z-level by passing a non-zero value into "zlevel". + +"target_om_ter_random" finds all om_ter terrains in "range", defaulting to 5, and sets and +reveals the target to a randomly chosen terrain. "must_see" and "reveal_rad" have the same +meaning. + +"target_om_ter_random_or_create" works like "target_om_ter_random", except that if there are +no instances of "om_ter" in range, it creates an instance of "om_spec" on some unseen territory +of type "om_replace_ter" and then reveals and targets that. "om_spec" must include "om_ter". + +### monster_species +For "MGOAL_KILL_MONSTER_SPEC", sets the target monster species. + +### monster_type +For "MGOAL_KILL_MONSTER_TYPE", sets the target monster type. + +### monster_kill_goal +For "MGOAL_KILL_MONSTER_SPEC" and "MGOAL_KILL_MONSTER_TYPE", sets the number of monsters above +the player's current kill count that must be killed to complete the mission. + +### dialogue +This is a dictionary of strings. The NPC says these exact strings in response to the player +inquiring about the mission or reporting its completion. + +## Adding new missions to NPC dialogue +Any NPC that has missions needs to either: +* Add one of their talk_topic IDs to the list of generic mission reponse IDs in the first +talk_topic of data/json/npcs/TALK_COMMON_MISSION.json +* Have a similar talk_topic with responses that lead to TALK_MISSION_INQUIRE and +TALK_MISSION_LIST_ASSIGNED. diff --git a/doc/NPCs.md b/doc/NPCs.md index c76fedb054cab..f3dd342f421fe 100644 --- a/doc/NPCs.md +++ b/doc/NPCs.md @@ -5,6 +5,9 @@ Dialogues work like state machines. They start with a certain topic (the NPC say Note that it is perfectly fine to have a response that switches the topic back to itself. +NPC missions are controlled by a seperate but related JSON structure and are documented in +MISSIONS_JSON.md. + Two topics are special: - "TALK_DONE" ends the dialogue immediately. - "TALK_NONE" goes to the previously talked about topic. diff --git a/src/mission.h b/src/mission.h index 7cd5b8c63f4d5..9aa177221d230 100644 --- a/src/mission.h +++ b/src/mission.h @@ -19,6 +19,7 @@ class npc; class Creature; class npc_class; class JsonObject; +class JsonArray; class JsonIn; class JsonOut; struct mission_type; @@ -77,6 +78,16 @@ struct mission_place { static bool near_town( const tripoint & ); }; +struct mission_start_t { + void set_reveal( const std::string &terrain ); + void set_reveal_any( JsonArray &ja ); + void set_target_om( JsonObject &jo, bool random ); + void set_target_om_or_create( JsonObject &jo ); + void load( JsonObject &jo ); + void apply( mission *miss ) const; + std::vector> start_funcs; +}; + /* mission_start functions are first run when a mission is accepted; this * initializes the mission's key values, like the target and description. */ @@ -232,6 +243,7 @@ struct mission_type { static void check_consistency(); + void parse_start( JsonObject &jo ); void load( JsonObject &jo, const std::string &src ); }; diff --git a/src/mission_start.cpp b/src/mission_start.cpp index f2dff95063b2c..f4af59a6e74cc 100644 --- a/src/mission_start.cpp +++ b/src/mission_start.cpp @@ -3,8 +3,10 @@ #include "computer.h" #include "coordinate_conversions.h" #include "debug.h" +#include "dialogue.h" #include "field.h" #include "game.h" +#include "json.h" #include "line.h" #include "map.h" #include "map_iterator.h" @@ -23,6 +25,8 @@ #include "translations.h" #include "trap.h" +#include + const mtype_id mon_charred_nightmare( "mon_charred_nightmare" ); const mtype_id mon_dog( "mon_dog" ); const mtype_id mon_graboid( "mon_graboid" ); @@ -165,7 +169,8 @@ static tripoint target_om_ter_random( const std::string &omter, int reveal_rad, * that fails, it will print a debug message. */ static tripoint target_om_ter_random_or_create( const std::string &omter, int reveal_rad, - mission *miss, bool must_see, int range, const std::string &replace_omter ) + mission *miss, bool must_see, int range, const std::string &om_spec, + const std::string &replace_omter ) { tripoint site = target_om_ter_random( omter, reveal_rad, miss, must_see, range ); @@ -180,8 +185,8 @@ static tripoint target_om_ter_random_or_create( const std::string &omter, int re } } debugmsg( "Failed to find either an extant overmap tile of type %s, or an unvisited tile " - "of type %s that could be replaced with one. (Search radius: %d)", - omter, replace_omter, range ); + "of type %s that could be replaced with one as part of a %s. (Search radius: %d)", + omter, replace_omter, om_spec, range ); } return site; @@ -201,7 +206,7 @@ void mission_start::infect_npc( mission *miss ) { npc *p = g->find_npc( miss->npc_id ); if( p == nullptr ) { - debugmsg( "mission_start::infect_npc() couldn't find an NPC!" ); + debugmsg( "couldn't find an NPC!" ); return; } p->add_effect( effect_infection, 1_turns, num_bp, true, true ); @@ -217,7 +222,7 @@ void mission_start::need_drugs_npc( mission *miss ) { npc *p = g->find_npc( miss->npc_id ); if( p == nullptr ) { - debugmsg( "mission_start::need_drugs_npc() couldn't find an NPC!" ); + debugmsg( "couldn't find an NPC!" ); return; } // make sure they don't have any item goal @@ -237,7 +242,7 @@ void mission_start::place_dog( mission *miss ) return; } g->u.i_add( item( "dog_whistle", 0 ) ); - add_msg( _( "%s gave you a dog whistle." ), dev->name.c_str() ); + add_msg( _( "%s gave you a dog whistle." ), dev->name ); miss->target = house; overmap_buffer.reveal( house, 6 ); @@ -326,7 +331,8 @@ void mission_start::place_caravan_ambush( mission *miss ) void mission_start::place_bandit_cabin( mission *miss ) { - tripoint site = target_om_ter_random_or_create( "bandit_cabin", 1, miss, false, 50, "forest" ); + tripoint site = target_om_ter_random_or_create( "bandit_cabin", 1, miss, false, 50, "bandit_cabin", + "forest" ); tinymap cabin; cabin.load( site.x * 2, site.y * 2, site.z, false ); @@ -372,13 +378,14 @@ void mission_start::place_bandit_camp( mission *miss ) g->u.i_add( item( "44magnum", calendar::turn ) ); g->u.i_add( item( "holster", calendar::turn ) ); g->u.i_add( item( "badge_marshal", calendar::turn ) ); - add_msg( m_good, _( "%s has instated you as a marshal!" ), p->name.c_str() ); + add_msg( m_good, _( "%s has instated you as a marshal!" ), p->name ); // Ideally this would happen at the end of the mission // (you're told that they entered your image into the databases, etc) // but better to get it working. g->u.set_mutation( trait_id( "PROF_FED" ) ); - tripoint site = target_om_ter_random_or_create( "bandit_camp_1", 1, miss, false, 50, "forest" ); + tripoint site = target_om_ter_random_or_create( "bandit_camp_1", 1, miss, false, 50, "bandit_camp", + "forest" ); tinymap bay1; bay1.load( site.x * 2, site.y * 2, site.z, false ); @@ -488,7 +495,7 @@ void mission_start::place_npc_software( mission *miss ) return; } g->u.i_add( item( "usb_drive", 0 ) ); - add_msg( _( "%s gave you a USB drive." ), dev->name.c_str() ); + add_msg( _( "%s gave you a USB drive." ), dev->name ); std::string type = "house"; @@ -599,7 +606,7 @@ void mission_start::reveal_lab_black_box( mission *miss ) npc *dev = g->find_npc( miss->npc_id ); if( dev != nullptr ) { g->u.i_add( item( "black_box", 0 ) ); - add_msg( _( "%s gave you back the black box." ), dev->name.c_str() ); + add_msg( _( "%s gave you back the black box." ), dev->name ); } target_om_ter( "lab", 3, miss, false ); } @@ -610,7 +617,7 @@ void mission_start::open_sarcophagus( mission *miss ) if( p != nullptr ) { p->set_attitude( NPCATT_FOLLOW ); g->u.i_add( item( "sarcophagus_access_code", 0 ) ); - add_msg( m_good, _( "%s gave you sarcophagus access code." ), p->name.c_str() ); + add_msg( m_good, _( "%s gave you sarcophagus access code." ), p->name ); } else { DebugLog( D_ERROR, DC_ALL ) << "mission_start: open_sarcophagus() <= Can't find NPC"; } @@ -622,9 +629,9 @@ void mission_start::reveal_hospital( mission *miss ) npc *dev = g->find_npc( miss->npc_id ); if( dev != nullptr ) { g->u.i_add( item( "vacutainer", 0 ) ); - add_msg( _( "%s gave you a blood draw kit." ), dev->name.c_str() ); + add_msg( _( "%s gave you a blood draw kit." ), dev->name ); g->u.i_add( item( "usb_drive", 0 ) ); - add_msg( _( "%s gave you a USB drive." ), dev->name.c_str() ); + add_msg( _( "%s gave you a USB drive." ), dev->name ); } target_om_ter( "hospital_2", 3, miss, false ); } @@ -1737,7 +1744,7 @@ void reveal_route( mission *miss, const tripoint destination ) { const npc *p = g->find_npc( miss->get_npc_id() ); if( p == nullptr ) { - debugmsg( "mission_start::infect_npc() couldn't find an NPC!" ); + debugmsg( "couldn't find an NPC!" ); return; } @@ -1747,8 +1754,7 @@ void reveal_route( mission *miss, const tripoint destination ) const tripoint dest_road = overmap_buffer.find_closest( destination, "road", 3, false ); if( overmap_buffer.reveal_route( source_road, dest_road ) ) { - add_msg( _( "%s also marks the road that leads to it..." ), - p->name.c_str() ); + add_msg( _( "%s also marks the road that leads to it..." ), p->name ); } } @@ -1756,15 +1762,14 @@ void reveal_target( mission *miss, const std::string &omter_id ) { const npc *p = g->find_npc( miss->get_npc_id() ); if( p == nullptr ) { - debugmsg( "mission_start::infect_npc() couldn't find an NPC!" ); + debugmsg( "couldn't find an NPC!" ); return; } const tripoint destination = reveal_destination( omter_id ); if( destination != overmap::invalid_tripoint ) { const oter_id oter = overmap_buffer.ter( destination ); - add_msg( _( "%s has marked the only %s known to them on your map." ), - p->name.c_str(), oter->get_name().c_str() ); + add_msg( _( "%s has marked the only %s known to them on your map." ), p->name, oter->get_name() ); miss->set_target( destination ); if( one_in( 3 ) ) { reveal_route( miss, destination ); @@ -1930,3 +1935,143 @@ void mission_start::reveal_lab_train_depot( mission *miss ) const tripoint target = target_closest_lab_entrance( place, 2, miss ); reveal_road( g->u.global_omt_location(), target, overmap_buffer ); } + +void mission_start_t::set_reveal( const std::string &terrain ) +{ + const auto start_func = [ terrain ]( mission * miss ) { + reveal_target( miss, terrain ); + }; + start_funcs.push_back( start_func ); +} + +void mission_start_t::set_reveal_any( JsonArray &ja ) +{ + std::vector terrains; + while( ja.has_more() ) { + std::string terrain = ja.next_string(); + terrains.push_back( terrain ); + } + const auto start_func = [ terrains ]( mission * miss ) { + reveal_any_target( miss, terrains ); + }; + start_funcs.push_back( start_func ); +} + + +void mission_start_t::set_target_om( JsonObject &jo, bool random = false ) +{ + int reveal_rad = 1; + bool must_see = false; + int target_z = 0; + int range = 5; + if( !jo.has_string( "om_ter" ) ) { + return; + } + std::string omter = jo.get_string( "om_ter" ); + if( jo.has_int( "reveal_rad" ) ) { + reveal_rad = std::max( 1, jo.get_int( "reveal_rad" ) ); + } + if( jo.has_bool( "must_see" ) ) { + must_see = jo.get_bool( "must_see" ); + } + if( jo.has_int( "zlevel" ) ) { + target_z = jo.get_int( "zlevel" ); + } + if( jo.has_int( "range" ) ) { + range = jo.get_int( "range" ); + } + if( random ) { + const auto start_func = [ omter, reveal_rad, must_see, range ]( mission * miss ) { + target_om_ter_random( omter, reveal_rad, miss, must_see, range ); + }; + start_funcs.push_back( start_func ); + } else { + const auto start_func = [ omter, reveal_rad, must_see, target_z ]( mission * miss ) { + target_om_ter( omter, reveal_rad, miss, must_see, target_z ); + }; + start_funcs.push_back( start_func ); + } +} + +void mission_start_t::set_target_om_or_create( JsonObject &jo ) +{ + int reveal_rad = 1; + bool must_see = false; + int range = 5; + if( !( jo.has_string( "om_ter" ) && jo.has_string( "om_spec" ) && + jo.has_string( "om_replace_ter" ) ) ) { + return; + } + std::string omter = jo.get_string( "om_ter" ); + std::string om_spec = jo.get_string( "om_spec" ); + std::string om_replace_ter = jo.get_string( "om_replace_ter" ); + if( jo.has_int( "reveal_rad" ) ) { + reveal_rad = std::max( 1, jo.get_int( "reveal_rad" ) ); + } + if( jo.has_bool( "must_see" ) ) { + must_see = jo.get_bool( "must_see" ); + } + if( jo.has_int( "range" ) ) { + range = jo.get_int( "range" ); + } + const auto start_func = [ omter, reveal_rad, must_see, range, om_spec, + om_replace_ter ]( mission * miss ) { + target_om_ter_random_or_create( omter, reveal_rad, miss, must_see, range, + om_spec, om_replace_ter ); + }; + start_funcs.push_back( start_func ); +} + +void mission_start_t::load( JsonObject &jo ) +{ + if( jo.has_string( "reveal_om_ter" ) ) { + const std::string target_terrain = jo.get_string( "reveal_om_ter" ); + set_reveal( target_terrain ); + } else if( jo.has_array( "reveal_om_ter" ) ) { + JsonArray target_terrain = jo.get_array( "reveal_om_ter" ); + set_reveal_any( target_terrain ); + } else if( jo.has_object( "target_om_ter" ) ) { + JsonObject target_terrain = jo.get_object( "target_om_ter" ); + set_target_om( target_terrain ); + } else if( jo.has_object( "target_om_ter_random" ) ) { + JsonObject target_terrain = jo.get_object( "target_om_ter_random" ); + set_target_om( target_terrain, true ); + } else if( jo.has_object( "target_om_ter_random_create" ) ) { + JsonObject target_terrain = jo.get_object( "target_om_ter_random_create" ); + set_target_om_or_create( target_terrain ); + } +} + +void mission_start_t::apply( mission *miss ) const +{ + for( auto &start_func : start_funcs ) { + start_func( miss ); + } +} + +void mission_type::parse_start( JsonObject &jo ) +{ + /* this is a kind of gross hijack of the dialogue responses effect system, but I don't want to + * write that code in two places so here it goes. + */ + talk_effect_t talk_effects; + talk_effects.load_effect( jo ); + mission_start_t mission_start_fun; + mission_start_fun.load( jo ); + // BevapDin will probably tell me how to do this is a less baroque way, but in the meantime, + // I have no better idea on how satisfy the compiler. + start = [ mission_start_fun, talk_effects ]( mission * miss ) { + ::dialogue d; + d.beta = g->find_npc( miss->get_npc_id() ); + if( d.beta == nullptr ) { + debugmsg( "couldn't find an NPC!" ); + return; + } + d.alpha = &g->u; + for( const talk_effect_fun_t &effect : talk_effects.effects ) { + effect( d ); + } + mission_start_fun.apply( miss ); + }; +} + diff --git a/src/missiondef.cpp b/src/missiondef.cpp index 3af7ca6413ca1..99fbe1cb6ad71 100644 --- a/src/missiondef.cpp +++ b/src/missiondef.cpp @@ -299,7 +299,12 @@ void mission_type::load( JsonObject &jo, const std::string &src ) goal = jo.get_enum_value( "goal" ); assign_function( jo, "place", place, tripoint_function_map ); - assign_function( jo, "start", start, mission_function_map ); + if( jo.has_string( "start" ) ) { + assign_function( jo, "start", start, mission_function_map ); + } else if( jo.has_member( "start" ) ) { + JsonObject j_start = jo.get_object( "start" ); + parse_start( j_start ); + } assign_function( jo, "end", end, mission_function_map ); assign_function( jo, "fail", fail, mission_function_map ); From ffbbb44a7cf2cbf370b8e33e680b736245f171f8 Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Mon, 10 Dec 2018 13:07:44 -0600 Subject: [PATCH 3/3] mission start: remove dead code Now that these mission start functions are replaced by generic JSON, they can be removed. --- src/mission_start.cpp | 71 ------------------------------------------- src/missiondef.cpp | 10 ------ 2 files changed, 81 deletions(-) diff --git a/src/mission_start.cpp b/src/mission_start.cpp index f4af59a6e74cc..07ee699a95e18 100644 --- a/src/mission_start.cpp +++ b/src/mission_start.cpp @@ -601,41 +601,6 @@ void mission_start::place_deposit_box( mission *miss ) compmap.save(); } -void mission_start::reveal_lab_black_box( mission *miss ) -{ - npc *dev = g->find_npc( miss->npc_id ); - if( dev != nullptr ) { - g->u.i_add( item( "black_box", 0 ) ); - add_msg( _( "%s gave you back the black box." ), dev->name ); - } - target_om_ter( "lab", 3, miss, false ); -} - -void mission_start::open_sarcophagus( mission *miss ) -{ - npc *p = g->find_npc( miss->npc_id ); - if( p != nullptr ) { - p->set_attitude( NPCATT_FOLLOW ); - g->u.i_add( item( "sarcophagus_access_code", 0 ) ); - add_msg( m_good, _( "%s gave you sarcophagus access code." ), p->name ); - } else { - DebugLog( D_ERROR, DC_ALL ) << "mission_start: open_sarcophagus() <= Can't find NPC"; - } - target_om_ter( "haz_sar", 3, miss, false ); -} - -void mission_start::reveal_hospital( mission *miss ) -{ - npc *dev = g->find_npc( miss->npc_id ); - if( dev != nullptr ) { - g->u.i_add( item( "vacutainer", 0 ) ); - add_msg( _( "%s gave you a blood draw kit." ), dev->name ); - g->u.i_add( item( "usb_drive", 0 ) ); - add_msg( _( "%s gave you a USB drive." ), dev->name ); - } - target_om_ter( "hospital_2", 3, miss, false ); -} - void mission_start::find_safety( mission *miss ) { const tripoint place = g->u.global_omt_location(); @@ -686,16 +651,6 @@ void mission_start::find_safety( mission *miss ) } } -void mission_start::point_prison( mission *miss ) -{ - target_om_ter( "prison_1_5", 3, miss, false ); -} - -void mission_start::point_cabin_strange( mission *miss ) -{ - target_om_ter( "cabin_strange", 3, miss, false ); -} - void mission_start::recruit_tracker( mission *miss ) { npc *p = g->find_npc( miss->npc_id ); @@ -718,12 +673,6 @@ void mission_start::recruit_tracker( mission *miss ) temp->getID() ) ); } -void mission_start::radio_repeater( mission *miss ) -{ - target_om_ter( "necropolis_c_23", 3, miss, false, -2 ); - g->u.i_add( item( "repeater_mod_guide", calendar::turn ) ); -} - void mission_start::start_commune( mission *miss ) { // Check entire overmap for now. @@ -1782,26 +1731,6 @@ void reveal_any_target( mission *miss, const std::vector &omter_ids reveal_target( miss, random_entry( omter_ids ) ); } -void mission_start::reveal_weather_station( mission *miss ) -{ - reveal_target( miss, "station_radio" ); -} - -void mission_start::reveal_office_tower( mission *miss ) -{ - reveal_target( miss, "office_tower_1" ); -} - -void mission_start::reveal_doctors_office( mission *miss ) -{ - reveal_any_target( miss, { "office_doctor", "hospital_2" } ); -} - -void mission_start::reveal_cathedral( mission *miss ) -{ - reveal_any_target( miss, { "cathedral_1", "museum" } ); -} - void mission_start::reveal_refugee_center( mission *miss ) { const tripoint your_pos = g->u.global_omt_location(); diff --git a/src/missiondef.cpp b/src/missiondef.cpp index 99fbe1cb6ad71..af9009e2af691 100644 --- a/src/missiondef.cpp +++ b/src/missiondef.cpp @@ -110,14 +110,8 @@ static const std::map> mission_fun { "place_npc_software", mission_start::place_npc_software }, { "place_priest_diary", mission_start::place_priest_diary }, { "place_deposit_box", mission_start::place_deposit_box }, - { "reveal_lab_black_box", mission_start::reveal_lab_black_box }, - { "open_sarcophagus", mission_start::open_sarcophagus }, - { "reveal_hospital", mission_start::reveal_hospital }, { "find_safety", mission_start::find_safety }, - { "point_prison", mission_start::point_prison }, - { "point_cabin_strange", mission_start::point_cabin_strange }, { "recruit_tracker", mission_start::recruit_tracker }, - { "radio_repeater", mission_start::radio_repeater }, { "start_commune", mission_start::start_commune }, { "ranch_construct_1", mission_start::ranch_construct_1 }, { "ranch_construct_2", mission_start::ranch_construct_2 }, @@ -152,10 +146,6 @@ static const std::map> mission_fun { "ranch_bartender_3", mission_start::ranch_bartender_3 }, { "ranch_bartender_4", mission_start::ranch_bartender_4 }, { "place_book", mission_start::place_book }, - { "reveal_weather_station", mission_start::reveal_weather_station }, - { "reveal_office_tower", mission_start::reveal_office_tower }, - { "reveal_doctors_office", mission_start::reveal_doctors_office }, - { "reveal_cathedral", mission_start::reveal_cathedral }, { "reveal_refugee_center", mission_start::reveal_refugee_center }, { "create_lab_console", mission_start::create_lab_console }, { "create_hidden_lab_console", mission_start::create_hidden_lab_console },