From 3a276ec41331037a4c41528a811dd9e4c166fd2a Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Wed, 10 Apr 2019 00:56:09 +0200 Subject: [PATCH 1/8] Initial workbench implementation --- data/json/furniture.json | 9 ++-- src/activity_handlers.cpp | 24 ++++++---- src/craft_command.cpp | 8 +++- src/craft_command.h | 12 +++-- src/crafting.cpp | 67 +++++++++++++++++++--------- src/game.cpp | 4 +- src/iexamine.cpp | 92 ++++++++++++++++++++++++++++++++++++++- src/iexamine.h | 1 + src/iuse.cpp | 4 +- src/player.h | 23 ++++++---- 10 files changed, 193 insertions(+), 51 deletions(-) diff --git a/data/json/furniture.json b/data/json/furniture.json index 3aa5ecb100a7e..3cc8bf99d5f11 100644 --- a/data/json/furniture.json +++ b/data/json/furniture.json @@ -754,7 +754,8 @@ "sound": "smash!", "sound_fail": "whump.", "items": [ { "item": "2x4", "count": [ 1, 3 ] }, { "item": "nail", "charges": [ 2, 6 ] }, { "item": "splinter", "count": 1 } ] - } + }, + "examine_action": "workbench" }, { "type": "furniture", @@ -864,7 +865,8 @@ "sound": "smash!", "sound_fail": "whump.", "items": [ { "item": "2x4", "count": [ 2, 6 ] }, { "item": "nail", "charges": [ 4, 8 ] }, { "item": "splinter", "count": 1 } ] - } + }, + "examine_action": "workbench" }, { "type": "furniture", @@ -4479,7 +4481,8 @@ { "item": "cable", "charges": [ 1, 3 ] }, { "item": "cu_pipe", "count": 1 } ] - } + }, + "examine_action": "workbench" }, { "type": "furniture", diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 12445db940a60..4e725f0408e1a 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -2641,12 +2641,8 @@ void activity_handlers::craft_do_turn( player_activity *act, player *p ) { item *craft = act->targets.front().get_item(); - if( !craft->is_craft() ) { - debugmsg( "ACT_CRAFT target '%s' is not a craft. Aborting ACT_CRAFT.", craft->tname() ); - p->cancel_activity(); - return; - } - if( !p->has_item( *craft ) ) { + // item_location::get_item() will return nullptr if the item is lost + if( !craft ) { p->add_msg_player_or_npc( string_format( _( "You no longer have the %1$s in your possession. You stop crafting. Reactivate the %1$s to continue crafting." ), @@ -2659,6 +2655,12 @@ void activity_handlers::craft_do_turn( player_activity *act, player *p ) return; } + if( !craft->is_craft() ) { + debugmsg( "ACT_CRAFT target '%s' is not a craft. Aborting ACT_CRAFT.", craft->tname() ); + p->cancel_activity(); + return; + } + const recipe &rec = craft->get_making(); const float crafting_speed = p->crafting_speed_multiplier( rec, true ); const bool is_long = act->values[0]; @@ -2696,12 +2698,16 @@ void activity_handlers::craft_do_turn( player_activity *act, player *p ) // if item_counter has reached 100% or more if( craft->item_counter >= 10000000 ) { + item craft_copy = *craft; + const tripoint loc = act->targets.front().where() == item_location::type::character ? + tripoint_zero : + act->targets.front().position(); + act->targets.front().remove_item(); p->cancel_activity(); - item craft_copy = p->i_rem( craft ); - p->complete_craft( craft_copy ); + p->complete_craft( craft_copy, loc ); if( is_long ) { if( p->making_would_work( p->lastrecipe, craft_copy.charges ) ) { - p->last_craft->execute(); + p->last_craft->execute( loc ); } } } diff --git a/src/craft_command.cpp b/src/craft_command.cpp index 0d501822931a0..fefb3978ecb35 100644 --- a/src/craft_command.cpp +++ b/src/craft_command.cpp @@ -32,12 +32,16 @@ std::string comp_selection::nname() const return item::nname( comp.type, comp.count ); } -void craft_command::execute() +void craft_command::execute( const tripoint &new_loc ) { if( empty() ) { return; } + if( new_loc != tripoint_zero ) { + loc = new_loc; + } + bool need_selections = true; inventory map_inv; map_inv.form_from_map( crafter->pos(), PICKUP_RANGE ); @@ -79,7 +83,7 @@ void craft_command::execute() } } - crafter->start_craft( *this ); + crafter->start_craft( *this, loc ); crafter->last_batch = batch_size; crafter->lastrecipe = rec->ident(); diff --git a/src/craft_command.h b/src/craft_command.h index c4e0ed3cfc814..668133c41b3f7 100644 --- a/src/craft_command.h +++ b/src/craft_command.h @@ -5,6 +5,7 @@ #include #include +#include "enums.h" #include "requirements.h" #include "string_id.h" @@ -54,11 +55,12 @@ class craft_command public: /** Instantiates an empty craft_command, which can't be executed. */ craft_command() = default; - craft_command( const recipe *to_make, int batch_size, bool is_long, player *crafter ) : - rec( to_make ), batch_size( batch_size ), longcraft( is_long ), crafter( crafter ) {} + craft_command( const recipe *to_make, int batch_size, bool is_long, player *crafter, + const tripoint loc = tripoint_zero ) : + rec( to_make ), batch_size( batch_size ), longcraft( is_long ), crafter( crafter ), loc( loc ) {} /** Selects components to use for the craft, then assigns the crafting activity to 'crafter'. */ - void execute(); + void execute( const tripoint &new_loc = tripoint_zero ); /** * Consumes the selected components and returns the resulting in progress craft item. @@ -89,6 +91,10 @@ class craft_command // This is mainly here for maintainability reasons. player *crafter; + // Location of the workbench to place the item on + // zero_tripoint indicates crafting without a workbench + tripoint loc = tripoint_zero; + std::vector> item_selections; std::vector> tool_selections; diff --git a/src/crafting.cpp b/src/crafting.cpp index e688a7dcefd8e..6daf966a50370 100644 --- a/src/crafting.cpp +++ b/src/crafting.cpp @@ -128,33 +128,33 @@ bool player::has_morale_to_craft() const return get_morale_level() >= -50; } -void player::craft() +void player::craft( const tripoint &loc ) { int batch_size = 0; const recipe *rec = select_crafting_recipe( batch_size ); if( rec ) { if( crafting_allowed( *this, *rec ) ) { - make_craft( rec->ident(), batch_size ); + make_craft( rec->ident(), batch_size, loc ); } } } -void player::recraft() +void player::recraft( const tripoint &loc ) { if( lastrecipe.str().empty() ) { popup( _( "Craft something first" ) ); } else if( making_would_work( lastrecipe, last_batch ) ) { - last_craft->execute(); + last_craft->execute( loc ); } } -void player::long_craft() +void player::long_craft( const tripoint &loc ) { int batch_size = 0; const recipe *rec = select_crafting_recipe( batch_size ); if( rec ) { if( crafting_allowed( *this, *rec ) ) { - make_all_craft( rec->ident(), batch_size ); + make_all_craft( rec->ident(), batch_size, loc ); } } } @@ -360,17 +360,18 @@ void player::invalidate_crafting_inventory() cached_time = calendar::before_time_starts; } -void player::make_craft( const recipe_id &id_to_make, int batch_size ) +void player::make_craft( const recipe_id &id_to_make, int batch_size, const tripoint &loc ) { - make_craft_with_command( id_to_make, batch_size ); + make_craft_with_command( id_to_make, batch_size, false, loc ); } -void player::make_all_craft( const recipe_id &id_to_make, int batch_size ) +void player::make_all_craft( const recipe_id &id_to_make, int batch_size, const tripoint &loc ) { - make_craft_with_command( id_to_make, batch_size, true ); + make_craft_with_command( id_to_make, batch_size, true, loc ); } -void player::make_craft_with_command( const recipe_id &id_to_make, int batch_size, bool is_long ) +void player::make_craft_with_command( const recipe_id &id_to_make, int batch_size, bool is_long, + const tripoint &loc ) { const auto &recipe_to_make = *id_to_make; @@ -378,7 +379,7 @@ void player::make_craft_with_command( const recipe_id &id_to_make, int batch_siz return; } - *last_craft = craft_command( &recipe_to_make, batch_size, is_long, this ); + *last_craft = craft_command( &recipe_to_make, batch_size, is_long, this, loc ); last_craft->execute(); } @@ -471,7 +472,7 @@ static void return_some_components_for_craft( player &p, std::list &used, } } -void player::start_craft( craft_command &command ) +void player::start_craft( craft_command &command, const tripoint &loc ) { if( command.empty() ) { debugmsg( "Attempted to start craft with empty command" ); @@ -485,22 +486,40 @@ void player::start_craft( craft_command &command ) reset_encumbrance(); } - item *craft_in_inventory = set_item_inventory( *this, craft ); - if( !has_item( *craft_in_inventory ) ) { - add_msg_if_player( _( "Activate the %s to start crafting" ), craft.tname() ); + if( loc == tripoint_zero ) { + item *craft_in_inventory = set_item_inventory( *this, craft ); + if( !has_item( *craft_in_inventory ) ) { + add_msg_if_player( _( "Activate the %s to start crafting" ), craft.tname() ); + } else { + add_msg_player_or_npc( + string_format( pgettext( "in progress craft", "You start working on the %s" ), + craft.tname() ), + string_format( pgettext( "in progress craft", " starts working on the %s" ), + craft.tname() ) ); + assign_activity( activity_id( "ACT_CRAFT" ) ); + activity.targets.push_back( item_location( *this, craft_in_inventory ) ); + activity.values.push_back( is_long ); + } } else { + item *craft_on_map = &g->m.add_item_or_charges( loc, craft ); + const furn_t &workbench = g->m.furn( loc ).obj(); + add_msg_player_or_npc( + string_format( pgettext( "in progress craft", "You put the %s on the %s" ), + craft.tname(), workbench.name() ), + string_format( pgettext( "in progress craft", " puts the %s on the %s" ), + craft.tname(), workbench.name() ) ); add_msg_player_or_npc( string_format( pgettext( "in progress craft", "You start working on the %s" ), craft.tname() ), string_format( pgettext( "in progress craft", " starts working on the %s" ), craft.tname() ) ); assign_activity( activity_id( "ACT_CRAFT" ) ); - activity.targets.push_back( item_location( *this, craft_in_inventory ) ); + activity.targets.push_back( item_location( map_cursor( loc ), craft_on_map ) ); activity.values.push_back( command.is_long() ); } } -void player::complete_craft( item &craft ) +void player::complete_craft( item &craft, const tripoint &loc ) { const recipe &making = craft.get_making(); // Which recipe is it? const int batch_size = craft.charges; @@ -754,7 +773,11 @@ void player::complete_craft( item &craft ) } finalize_crafted_item( newit ); - set_item_inventory( *this, newit ); + if( loc == tripoint_zero ) { + set_item_inventory( *this, newit ); + } else { + g->m.add_item_or_charges( loc, newit ); + } } if( making.has_byproducts() ) { @@ -772,7 +795,11 @@ void player::complete_craft( item &craft ) } } finalize_crafted_item( bp ); - set_item_inventory( *this, bp ); + if( loc == tripoint_zero ) { + set_item_inventory( *this, bp ); + } else { + g->m.add_item_or_charges( loc, bp ); + } } } diff --git a/src/game.cpp b/src/game.cpp index fbcceca1dc401..a1a5b3c6ceedc 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -6205,7 +6205,9 @@ void game::examine( const tripoint &examp ) if( m.tr_at( examp ).is_null() && m.i_at( examp ).empty() && m.has_flag( "CONTAINER", examp ) && none ) { add_msg( _( "It is empty." ) ); - } else if( m.has_flag( TFLAG_FIRE_CONTAINER, examp ) && xfurn_t.examine == &iexamine::fireplace ) { + } else if( ( m.has_flag( TFLAG_FIRE_CONTAINER, examp ) && + xfurn_t.examine == &iexamine::fireplace ) || + xfurn_t.examine == &iexamine::workbench ) { return; } else { sounds::process_sound_markers( &u ); diff --git a/src/iexamine.cpp b/src/iexamine.cpp index edd35601d1c6a..d1c5a6f6aed56 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -76,6 +76,7 @@ const efftype_id effect_sleep( "sleep" ); static const trait_id trait_AMORPHOUS( "AMORPHOUS" ); static const trait_id trait_ARACHNID_ARMS_OK( "ARACHNID_ARMS_OK" ); static const trait_id trait_BADKNEES( "BADKNEES" ); +static const trait_id trait_BURROW( "BURROW" ); static const trait_id trait_ILLITERATE( "ILLITERATE" ); static const trait_id trait_INSECT_ARMS_OK( "INSECT_ARMS_OK" ); static const trait_id trait_M_DEFENDER( "M_DEFENDER" ); @@ -84,10 +85,13 @@ static const trait_id trait_M_FERTILE( "M_FERTILE" ); static const trait_id trait_M_SPORES( "M_SPORES" ); static const trait_id trait_NOPAIN( "NOPAIN" ); static const trait_id trait_PARKOUR( "PARKOUR" ); +static const trait_id trait_SHELL2( "SHELL2" ); static const trait_id trait_THRESH_MARLOSS( "THRESH_MARLOSS" ); static const trait_id trait_THRESH_MYCUS( "THRESH_MYCUS" ); static const trait_id trait_BURROW( "BURROW" ); + const zone_type_id z_loot_unsorted( "LOOT_UNSORTED" ); + static void pick_plant( player &p, const tripoint &examp, const std::string &itemType, ter_id new_ter, bool seeds = false ); @@ -4595,6 +4599,91 @@ void iexamine::open_safe( player &, const tripoint &examp ) g->m.furn_set( examp, f_safe_o ); } +void iexamine::workbench( player &p, const tripoint &examp ) +{ + const furn_t &f_workbench = g->m.furn( examp ).obj(); + + uilist amenu; + + enum option : int { + start_craft = 0, + repeat_craft, + start_long_craft, + work_on_craft, + get_items + }; + + auto items_at_furn = g->m.i_at( examp ); + std::vector crafts; + for( item &it : items_at_furn ) { + if( it.is_craft() ) { + crafts.emplace_back( item_location( map_cursor( examp ), &it ) ); + } + } + + amenu.text = string_format( pgettext( "furniture", "What to do with the %s?" ), + f_workbench.name() ); + amenu.addentry( start_craft, true, '1', _( "Craft Items" ) ); + amenu.addentry( repeat_craft, true, '2', _( "Recraft last recipe" ) ); + amenu.addentry( start_long_craft, true, '3', _( "Craft as long as possible" ) ); + amenu.addentry( work_on_craft, !crafts.empty(), '4', _( "Work on craft" ) ); + amenu.addentry( get_items, !items_at_furn.empty(), '5', _( "Get items" ) ); + + amenu.query(); + + option choice = static_cast