From 886e55207713a015c462986b39b1bd10e626d47d Mon Sep 17 00:00:00 2001 From: Lee Martin Date: Sat, 16 Nov 2019 13:04:43 +0000 Subject: [PATCH] Remove failed craft when losing last component Currently, in progress crafts that lose their last component still exist, but with a volume of 0 as there is nothing in them. I've added this fix where if a player/npc bungles a craft and loses the last component of it (and the craft had components to start with), the craft item is removed from the game. fixes #34072 --- src/activity_handlers.cpp | 9 ++++++++- src/crafting.cpp | 11 ++++++++--- src/item.h | 3 ++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index f8069c706ed51..0bab9943bf2d6 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -3481,7 +3481,14 @@ void activity_handlers::craft_do_turn( player_activity *act, player *p ) } } } else if( craft->item_counter >= craft->get_next_failure_point() ) { - craft->handle_craft_failure( *p ); + bool destroy = craft->handle_craft_failure( *p ); + // If the craft needs to be destroyed, do it and stop crafting. + if( destroy ) { + p->add_msg_player_or_npc( _( "There is nothing left of the %s to craft from." ), + _( "There is nothing left of the %s was crafting." ), craft->tname() ); + act->targets.front().remove_item(); + p->cancel_activity(); + } } } diff --git a/src/crafting.cpp b/src/crafting.cpp index 49ead82965c45..0ee97d04e6dcc 100644 --- a/src/crafting.cpp +++ b/src/crafting.cpp @@ -986,15 +986,15 @@ static void destroy_random_component( item &craft, const player &crafter ) _( " messes up and destroys the %s" ), destroyed.tname() ); } -void item::handle_craft_failure( player &crafter ) +bool item::handle_craft_failure( player &crafter ) { if( !is_craft() ) { debugmsg( "handle_craft_failure() called on non-craft '%s.' Aborting.", tname() ); - return; + return false; } const double success_roll = crafter.crafting_success_roll( get_making() ); - + const int starting_components = this->components.size(); // Destroy at most 75% of the components, always a chance of losing 1 though const size_t max_destroyed = std::max( 1, components.size() * 3 / 4 ); for( size_t i = 0; i < max_destroyed; i++ ) { @@ -1008,6 +1008,10 @@ void item::handle_craft_failure( player &crafter ) } destroy_random_component( *this, crafter ); } + if( starting_components > 0 && this->components.empty() ) { + // The craft had components and all of them were destroyed. + return true; + } // Minimum 25% progress lost, average 35%. Falls off exponentially // Loss is scaled by the success roll @@ -1024,6 +1028,7 @@ void item::handle_craft_failure( player &crafter ) if( !crafter.can_continue_craft( *this ) ) { crafter.cancel_activity(); } + return false; } requirement_data item::get_continue_reqs() const diff --git a/src/item.h b/src/item.h index c0a4255d1ccf6..74f9f9e2aa87c 100644 --- a/src/item.h +++ b/src/item.h @@ -1992,8 +1992,9 @@ class item : public visitable * Handle failure during crafting. * Destroy components, lose progress, and set a new failure point. * @param crafter the crafting player. + * @return whether the craft being worked on should be entirely destroyed */ - void handle_craft_failure( player &crafter ); + bool handle_craft_failure( player &crafter ); /** * Returns requirement data representing what is needed to resume work on an in progress craft.