From 47b71690e9e0478424c518b18e0f8e4ac0e7f182 Mon Sep 17 00:00:00 2001 From: Jason Jones Date: Wed, 21 Aug 2019 14:31:20 -0800 Subject: [PATCH] Add u_buy_monster talk effect --- doc/NPCs.md | 2 ++ src/dialogue.h | 2 ++ src/npctalk.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/doc/NPCs.md b/doc/NPCs.md index e43a706671349..12d389e6dda2c 100644 --- a/doc/NPCs.md +++ b/doc/NPCs.md @@ -449,6 +449,8 @@ Effect | Description `add_debt: mod_list` | Increases the NPC's debt to the player by the values in the `mod_list`.
The following would increase the NPC's debt to the player by 1500x the NPC's altruism and 1000x the NPC's opinion of the player's value: `{ "effect": { "add_debt": [ [ "ALTRUISM", 3 ], [ "VALUE", 2 ], [ "TOTAL", 500 ] ] } }` `u_consume_item`, `npc_consume_item: item_string`, (*optional* `count: count_num`) | You or the NPC will delete the item or `count_num` copies of the item from their inventory.
This effect will fail if the you or NPC does not have at least `count_num` copies of the item, so it should be checked with `u_has_items` or `npc_has_items`. `u_remove_item_with`, `npc_remove_item_with: item_string` | You or the NPC will delete any instances of item in inventory.
This is an unconditional remove and will not fail if you or the NPC does not have the item. +`u_buy_monster: monster_type_string`, (*optional* `cost: cost_num`, *optional* `count: count_num`, *optional* `name: name_string`, *optional* `pacified: pacified_bool`) | The NPC will give your character `count_num` (default 1) instances of the monster as pets and will subtract `cost_num` from `op_of_u.owed` if specified. If the `op_o_u.owed` is less than `cost_num`, the trade window will open and the player will have to trade to make up the difference; the NPC will not give the player the item unless `cost_num` is satisfied.
If cost isn't present, the NPC gives your character the item at no charge.
If `name_string` is specified the monster(s) will have the specified name. If `pacified_bool` is set to true, the monster will have the pacified effect applied. + #### Behaviour / AI diff --git a/src/dialogue.h b/src/dialogue.h index 3ddbe9ad1efbd..986b01fa3a87c 100644 --- a/src/dialogue.h +++ b/src/dialogue.h @@ -121,6 +121,8 @@ struct talk_effect_fun_t { void set_bulk_trade_accept( bool is_trade, bool is_npc = false ); void set_npc_gets_item( bool to_use ); void set_add_mission( std::string mission_id ); + void set_u_buy_monster( const std::string &monster_id, int cost, int count, bool pacified, + const std::string &name ); void operator()( const dialogue &d ) const { if( !function ) { diff --git a/src/npctalk.cpp b/src/npctalk.cpp index 8fad4c6fc2a63..697e5e36f9a72 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -32,6 +32,7 @@ #include "json.h" #include "line.h" #include "map.h" +#include "map_iterator.h" #include "mapgen_functions.h" #include "martialarts.h" #include "messages.h" @@ -2097,6 +2098,55 @@ void talk_effect_fun_t::set_add_mission( const std::string mission_id ) }; } +void talk_effect_fun_t::set_u_buy_monster( const std::string &monster_type_id, int cost, int count, + bool pacified, const std::string &name ) +{ + function = [monster_type_id, cost, count, pacified, name]( const dialogue & d ) { + npc &p = *d.beta; + player &u = *d.alpha; + if( !npc_trading::pay_npc( p, cost ) ) { + popup( _( "You can't afford it!" ) ); + return; + } + + const mtype_id mtype( monster_type_id ); + const efftype_id effect_pet( "pet" ); + const efftype_id effect_pacified( "pacified" ); + const tripoint_range points = g->m.points_in_radius( u.pos(), 3 ); + + for( int i = 0; i < count; i++ ) { + monster tmp( mtype ); + + // Our monster is always a pet. + tmp.friendly = -1; + tmp.add_effect( effect_pet, 1_turns, num_bp, true ); + + if( pacified ) { + tmp.add_effect( effect_pacified, 1_turns, num_bp, true ); + } + + if( !name.empty() ) { + tmp.unique_name = name; + } + + if( const cata::optional pos = random_point( points, [&]( const tripoint & p ) { + return g->is_empty( p ) && tmp.can_move_to( p ); + } ) ) { + tmp.spawn( *pos ); + g->add_zombie( tmp ); + } else { + add_msg( m_debug, "Cannot place u_buy_monster, no valid placement locations." ); + } + } + + if( name.empty() ) { + popup( _( "%1$s gives you %2$d %3$s." ), p.name, count, mtype.obj().nname( count ) ); + } else { + popup( _( "%1$s gives you %2$s." ), p.name, name ); + } + }; +} + void talk_effect_t::set_effect_consequence( const talk_effect_fun_t &fun, dialogue_consequence con ) { effects.push_back( fun ); @@ -2293,6 +2343,13 @@ void talk_effect_t::parse_sub_effect( JsonObject jo ) subeffect_fun.set_npc_cbm_recharge_rule( setting ); } else if( jo.has_member( "mapgen_update" ) ) { subeffect_fun.set_mapgen_update( jo, "mapgen_update" ); + } else if( jo.has_string( "u_buy_monster" ) ) { + const std::string &monster_type_id = jo.get_string( "u_buy_monster" ); + const int cost = jo.get_int( "cost", 0 ); + const int count = jo.get_int( "count", 1 ); + const bool pacified = jo.get_bool( "pacified", false ); + const std::string &name = jo.get_string( "name", "" ); + subeffect_fun.set_u_buy_monster( monster_type_id, cost, count, pacified, name ); } else { jo.throw_error( "invalid sub effect syntax :" + jo.str() ); }