diff --git a/data/json/item_actions.json b/data/json/item_actions.json index 086813a01f0e0..6ef8357bfa6c1 100644 --- a/data/json/item_actions.json +++ b/data/json/item_actions.json @@ -1024,6 +1024,11 @@ "id": "place_monster", "name": "Activate" }, + { + "type": "item_action", + "id": "place_npc", + "name": "Activate" + }, { "type": "item_action", "id": "place_trap", diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 3c7bb47759715..3905d7b9ae9ab 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -1851,6 +1851,13 @@ The contents of use_action fields can either be a string indicating a built-in f "skill2": "unarmed", // Another id, just like the skill1. Both entries are optional. "moves": 60 // how many move points the action takes. }, +"use_action": { + "type": "place_npc", // place npc of specific class on the map + "npc_class_id": "true_foodperson", // npc class id, see npcs/classes.json + "summon_msg": "You summon a food hero!", // (optional) message when summoning the npc. + "place_randomly": true, // if true: places npc randomly around the player, if false: let the player decide where to put it (default: false) + "moves": 50 // how many move points the action takes. +}, "use_action": { "type": "ups_based_armor", // Armor that can be activated and uses power from an UPS, needs additional json code to work "activate_msg": "You activate your foo.", // Message when the player activates the item. diff --git a/src/item_factory.cpp b/src/item_factory.cpp index 55f0ea6cc86c3..2427452933254 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -795,6 +795,7 @@ void Item_factory::init() add_actor( std::make_unique() ); add_actor( std::make_unique() ); add_actor( std::make_unique() ); + add_actor( std::make_unique() ); add_actor( std::make_unique() ); add_actor( std::make_unique() ); add_actor( std::make_unique() ); diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index 11d0f9db113fc..ced80ef91af46 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -859,6 +859,45 @@ std::unique_ptr ups_based_armor_actor::clone() const return std::make_unique( *this ); } +std::unique_ptr place_npc_iuse::clone() const +{ + return std::make_unique( *this ); +} + +void place_npc_iuse::load( const JsonObject &obj ) +{ + npc_class_id = string_id( obj.get_string( "npc_class_id" ) ); + obj.read( "summon_msg", summon_msg ); + obj.read( "moves", moves ); + obj.read( "place_randomly", place_randomly ); +} + +int place_npc_iuse::use( player &p, item &, bool, const tripoint & ) const +{ + cata::optional target_pos; + if( place_randomly ) { + const tripoint_range target_range = points_in_radius( p.pos(), 1 ); + target_pos = random_point( target_range, []( const tripoint & t ) { + return !g->m.passable( t ); + } ); + } else { + const std::string query = _( "Place npc where?" ); + target_pos = choose_adjacent( _( "Place npc where?" ) ); + } + if( !target_pos ) { + return 0; + } + if( !g->m.passable( target_pos.value() ) ) { + p.add_msg_if_player( m_info, _( "There is no square to spawn npc in!" ) ); + return 0; + } + + g->m.place_npc( target_pos.value().xy(), npc_class_id ); + p.mod_moves( -moves ); + p.add_msg_if_player( m_info, "%s", _( summon_msg ) ); + return 1; +} + void ups_based_armor_actor::load( const JsonObject &obj ) { obj.read( "activate_msg", activate_msg ); diff --git a/src/iuse_actor.h b/src/iuse_actor.h index 914830a8682fc..4b72ccb685c58 100644 --- a/src/iuse_actor.h +++ b/src/iuse_actor.h @@ -15,6 +15,7 @@ #include "explosion.h" #include "game_constants.h" #include "iuse.h" +class npc_template; #include "ret_val.h" #include "string_id.h" #include "translations.h" @@ -310,6 +311,24 @@ class place_monster_iuse : public iuse_actor std::unique_ptr clone() const override; }; +/** + * This iuse contains the logic to summon an npc on the map. + */ +class place_npc_iuse : public iuse_actor +{ + public: + string_id npc_class_id; + bool place_randomly = false; + int moves = 100; + std::string summon_msg; + + place_npc_iuse() : iuse_actor( "place_npc" ) { } + ~place_npc_iuse() override = default; + void load( const JsonObject &obj ) override; + int use( player &, item &, bool, const tripoint & ) const override; + std::unique_ptr clone() const override; +}; + /** * Items that can be worn and can be activated to consume energy from UPS. * Note that the energy consumption is done in @ref player::process_active_items, it is