Skip to content

Commit a5e5a13

Browse files
authored
Jackhammers cannot tunnel through walls (#82757)
* Jackhammers cannot tunnel through walls * Pipe everything through iuse / dig_tool() Remove crafting helpers Remove move adjustment based on strength Remove bizarre misleading message based on bash resistance Remove unreachable/impossible check for incorporeal effect
1 parent 0e1f354 commit a5e5a13

File tree

2 files changed

+44
-65
lines changed

2 files changed

+44
-65
lines changed

src/activity_item_handling.cpp

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "item_pocket.h"
4444
#include "item_stack.h"
4545
#include "itype.h"
46+
#include "iuse.h"
4647
#include "map.h"
4748
#include "map_iterator.h"
4849
#include "map_scale_constants.h"
@@ -76,13 +77,10 @@
7677
#include "vpart_position.h"
7778
#include "weather.h"
7879

79-
struct use_function;
80-
8180
static const activity_id ACT_BUILD( "ACT_BUILD" );
8281
static const activity_id ACT_BUTCHER_FULL( "ACT_BUTCHER_FULL" );
8382
static const activity_id ACT_FETCH_REQUIRED( "ACT_FETCH_REQUIRED" );
8483
static const activity_id ACT_FISH( "ACT_FISH" );
85-
static const activity_id ACT_JACKHAMMER( "ACT_JACKHAMMER" );
8684
static const activity_id ACT_MOVE_LOOT( "ACT_MOVE_LOOT" );
8785
static const activity_id ACT_MULTIPLE_BUTCHER( "ACT_MULTIPLE_BUTCHER" );
8886
static const activity_id ACT_MULTIPLE_CHOP_PLANKS( "ACT_MULTIPLE_CHOP_PLANKS" );
@@ -95,16 +93,13 @@ static const activity_id ACT_MULTIPLE_FISH( "ACT_MULTIPLE_FISH" );
9593
static const activity_id ACT_MULTIPLE_MINE( "ACT_MULTIPLE_MINE" );
9694
static const activity_id ACT_MULTIPLE_MOP( "ACT_MULTIPLE_MOP" );
9795
static const activity_id ACT_MULTIPLE_READ( "ACT_MULTIPLE_READ" );
98-
static const activity_id ACT_PICKAXE( "ACT_PICKAXE" );
9996
static const activity_id ACT_TIDY_UP( "ACT_TIDY_UP" );
10097
static const activity_id ACT_VEHICLE( "ACT_VEHICLE" );
10198
static const activity_id ACT_VEHICLE_DECONSTRUCTION( "ACT_VEHICLE_DECONSTRUCTION" );
10299
static const activity_id ACT_VEHICLE_REPAIR( "ACT_VEHICLE_REPAIR" );
103100

104101
static const addiction_id addiction_alcohol( "alcohol" );
105102

106-
static const efftype_id effect_incorporeal( "incorporeal" );
107-
108103
static const flag_id json_flag_CUT_HARVEST( "CUT_HARVEST" );
109104
static const flag_id json_flag_MOP( "MOP" );
110105
static const flag_id json_flag_NO_AUTO_CONSUME( "NO_AUTO_CONSUME" );
@@ -2550,16 +2545,20 @@ static int chop_moves( Character &you, item &it )
25502545

25512546
static bool mine_activity( Character &you, const tripoint_bub_ms &src_loc )
25522547
{
2553-
std::vector<item *> mining_inv = you.items_with( [&you]( const item & itm ) {
2548+
map &here = get_map();
2549+
// We pre-exclude jackhammers for wall mining here, just in case the character is carrying both a jackhammer and a pickaxe.
2550+
// If we don't then our iteration will preferentially select the (powered) jackhammer and always fail in subsequent calls to dig_tool(). Very troublesome!
2551+
const bool is_wall_mining = here.has_flag_ter_or_furn( ter_furn_flag::TFLAG_WALL, src_loc );
2552+
std::vector<item *> mining_inv = you.items_with( [&you, is_wall_mining]( const item & itm ) {
25542553
return ( itm.has_flag( flag_DIG_TOOL ) && !itm.type->can_use( "JACKHAMMER" ) ) ||
2555-
( itm.type->can_use( "JACKHAMMER" ) && itm.ammo_sufficient( &you ) );
2554+
( !is_wall_mining && ( itm.type->can_use( "JACKHAMMER" ) && itm.ammo_sufficient( &you ) ) );
25562555
} );
2557-
map &here = get_map();
2558-
if( mining_inv.empty() || you.is_mounted() || you.is_underwater() || here.veh_at( src_loc ) ||
2559-
!here.has_flag( ter_furn_flag::TFLAG_MINEABLE, src_loc ) || you.has_effect( effect_incorporeal ) ||
2560-
here.impassable_field_at( src_loc ) ) {
2556+
// All other failure conditions are handled in subsequent calls to dig_tool() with specific messaging for the player. This is just an early short circuit.
2557+
if( mining_inv.empty() ) {
25612558
return false;
25622559
}
2560+
2561+
25632562
item *chosen_item = nullptr;
25642563
bool powered = false;
25652564
// is it a pickaxe or jackhammer?
@@ -2581,20 +2580,14 @@ static bool mine_activity( Character &you, const tripoint_bub_ms &src_loc )
25812580
if( chosen_item == nullptr ) {
25822581
return false;
25832582
}
2584-
int moves = to_moves<int>( powered ? 30_minutes : 20_minutes );
2585-
if( !powered ) {
2586-
moves += ( ( MAX_STAT + 4 ) - std::min( you.get_arm_str(),
2587-
MAX_STAT ) ) * to_moves<int>( 5_minutes );
2588-
}
2589-
if( here.move_cost( src_loc ) == 2 ) {
2590-
// We're breaking up some flat surface like pavement, which is much easier
2591-
moves /= 2;
2583+
std::optional<int> did_we_mine = std::nullopt;
2584+
if( powered ) {
2585+
did_we_mine = iuse::jackhammer( &you, chosen_item, src_loc );
2586+
} else {
2587+
did_we_mine = iuse::pickaxe( &you, chosen_item, src_loc );
25922588
}
2593-
you.assign_activity( powered ? ACT_JACKHAMMER : ACT_PICKAXE, moves );
2594-
you.activity.targets.emplace_back( you, chosen_item );
2595-
you.activity.placement = here.get_abs( src_loc );
2596-
return true;
2597-
2589+
// Any value at all means that we succeeded and started the activity. Actual contained value will be 0 on success, for iuse's normal returns.
2590+
return did_we_mine.has_value();
25982591
}
25992592

26002593
// Not really an activity like the others; relies on zone activity alerting on enemies

src/iuse.cpp

Lines changed: 26 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3091,13 +3091,14 @@ std::optional<int> iuse::change_skin( Character *p, item *, const tripoint_bub_m
30913091
return std::nullopt;
30923092
}
30933093

3094-
static std::optional<int> dig_tool( Character *p, item *it, const tripoint_bub_ms &pos,
3094+
static std::optional<int> dig_tool( Character *p, item *it, const tripoint_bub_ms &target,
30953095
const activity_id activity,
3096-
const std::string &prompt, const std::string &fail, const std::string &success,
3097-
int extra_moves = 0 )
3096+
const std::string &prompt, const std::string &fail, const std::string &success )
30983097
{
3099-
// use has_enough_charges to check for UPS availability
3100-
// p is assumed to exist for iuse cases
3098+
if( !p || !it ) {
3099+
debugmsg( "Misconfigured call to dig_tool, invalid character or item pointer" );
3100+
return std::nullopt;
3101+
}
31013102
if( !it->ammo_sufficient( p ) ) {
31023103
return std::nullopt;
31033104
}
@@ -3108,8 +3109,9 @@ static std::optional<int> dig_tool( Character *p, item *it, const tripoint_bub_m
31083109
return std::nullopt;
31093110
}
31103111

3111-
tripoint_bub_ms pnt( pos );
3112-
if( pos == p->pos_bub() ) {
3112+
tripoint_bub_ms pnt( target );
3113+
// This should only be true when called through activating the item directly. That is, the player activated it.
3114+
if( target == p->pos_bub() ) {
31133115
const std::optional<tripoint_bub_ms> pnt_ = choose_adjacent( prompt );
31143116
if( !pnt_ ) {
31153117
return std::nullopt;
@@ -3118,40 +3120,38 @@ static std::optional<int> dig_tool( Character *p, item *it, const tripoint_bub_m
31183120
}
31193121

31203122
map &here = get_map();
3123+
if( here.impassable_field_at( pnt ) ) {
3124+
std::optional<field_entry> null_zone = here.get_impassable_field_at( pnt );
3125+
p->add_msg_if_player( m_warning, _( "You can't make it through the %s there." ),
3126+
null_zone->name() );
3127+
return std::nullopt;
3128+
}
31213129
const bool mineable_furn = here.has_flag_furn( ter_furn_flag::TFLAG_MINEABLE, pnt );
31223130
const bool mineable_ter = here.has_flag_ter( ter_furn_flag::TFLAG_MINEABLE, pnt );
3123-
const bool impassable_fields = here.impassable_field_at( pnt );
3124-
const int max_mining_ability = 70;
3125-
if( ( !mineable_furn && !mineable_ter ) || impassable_fields ) {
3131+
if( !mineable_furn && !mineable_ter ) {
31263132
p->add_msg_if_player( m_info, fail );
3127-
if( here.bash_resistance( pnt ) > max_mining_ability ) {
3128-
p->add_msg_if_player( m_info,
3129-
_( "The material is too hard for you to even make a dent." ) );
3130-
}
31313133
return std::nullopt;
31323134
}
31333135
if( here.veh_at( pnt ) ) {
31343136
p->add_msg_if_player( _( "There's a vehicle in the way!" ) );
31353137
return std::nullopt;
31363138
}
31373139

3138-
int moves = to_moves<int>( 30_minutes );
3139-
3140-
const std::vector<Character *> helpers = p->get_crafting_helpers();
3141-
const std::size_t helpersize = p->get_num_crafting_helpers( 3 );
3142-
moves *= ( 1.0f - ( helpersize / 10.0f ) );
3143-
for( std::size_t i = 0; i < helpersize; i++ ) {
3144-
add_msg( m_info, _( "%s helps with this task…" ), helpers[i]->get_name() );
3140+
const bool using_jackhammer = it->type->can_use( "JACKHAMMER" );
3141+
if( using_jackhammer && here.has_flag_ter( ter_furn_flag::TFLAG_WALL, pnt ) ) {
3142+
p->add_msg_if_player( _( "You can't mine a wall with a %s!" ), it->tname() );
3143+
return std::nullopt;
31453144
}
31463145

3147-
moves += extra_moves;
3146+
// FIXME: Activity is interruptable but progress is not saved!
3147+
time_duration digging_time = 30_minutes;
31483148

3149-
if( here.move_cost( pnt ) == 2 ) {
3149+
if( here.has_flag( ter_furn_flag::TFLAG_FLAT, pnt ) ) {
31503150
// We're breaking up some flat surface like pavement, which is much easier
3151-
moves /= 2;
3151+
digging_time /= 2;
31523152
}
31533153

3154-
p->assign_activity( activity, moves );
3154+
p->assign_activity( activity, to_moves<int>( digging_time ) );
31553155
p->activity.targets.emplace_back( *p, it );
31563156
p->activity.placement = here.get_abs( pnt );
31573157

@@ -3165,12 +3165,6 @@ static std::optional<int> dig_tool( Character *p, item *it, const tripoint_bub_m
31653165

31663166
std::optional<int> iuse::jackhammer( Character *p, item *it, const tripoint_bub_ms &pos )
31673167
{
3168-
// use has_enough_charges to check for UPS availability
3169-
// p is assumed to exist for iuse cases
3170-
if( !it->ammo_sufficient( p ) ) {
3171-
return std::nullopt;
3172-
}
3173-
31743168
return dig_tool( p, it, pos, ACT_JACKHAMMER,
31753169
_( "Drill where?" ), _( "You can't drill there." ),
31763170
_( "You start drilling into the %1$s with your %2$s." ) );
@@ -3226,16 +3220,8 @@ std::optional<int> iuse::pick_lock( Character *p, item *it, const tripoint_bub_m
32263220

32273221
std::optional<int> iuse::pickaxe( Character *p, item *it, const tripoint_bub_ms &pos )
32283222
{
3229-
if( p->is_npc() ) {
3230-
// Long action
3231-
return std::nullopt;
3232-
}
3233-
/** @EFFECT_STR decreases time to dig with a pickaxe */
3234-
int extra_moves = ( ( MAX_STAT + 4 ) -
3235-
std::min( p->get_arm_str(), MAX_STAT ) ) * to_moves<int>( 5_minutes );
32363223
return dig_tool( p, it, pos, ACT_PICKAXE,
3237-
_( "Mine where?" ), _( "You can't mine there." ), _( "You strike the %1$s with your %2$s." ),
3238-
extra_moves );
3224+
_( "Mine where?" ), _( "You can't mine there." ), _( "You strike the %1$s with your %2$s." ) );
32393225

32403226
}
32413227

0 commit comments

Comments
 (0)