Permalink
Browse files

Improvements to repair item activity.

  • Loading branch information...
swofle committed Jan 1, 2019
1 parent d8ad3af commit 533124b78cf0858a95375547645f4103dcfe16e3
Showing with 103 additions and 62 deletions.
  1. +84 −37 src/activity_handlers.cpp
  2. +13 −23 src/iuse_actor.cpp
  3. +6 −2 src/iuse_actor.h
@@ -2053,12 +2053,13 @@ void activity_handlers::open_gate_finish( player_activity *act, player * )
}

enum repeat_type : int {
REPEAT_ONCE = 0, // Repeat just once
// REPEAT_INIT should be zero. In some scenarios (veh welder), activity value default to zero.
REPEAT_INIT = 0, // Haven't found repeat value yet.
REPEAT_ONCE, // Repeat just once
REPEAT_FOREVER, // Repeat for as long as possible
REPEAT_FULL, // Repeat until damage==0
REPEAT_EVENT, // Repeat until something interesting happens
REPEAT_CANCEL, // Stop repeating
REPEAT_INIT // Haven't found repeat value yet.
};

repeat_type repeat_menu( const std::string &title, repeat_type last_selection )
@@ -2070,11 +2071,12 @@ repeat_type repeat_menu( const std::string &title, repeat_type last_selection )
rmenu.addentry( REPEAT_FOREVER, true, '2', _( "Repeat as long as you can" ) );
rmenu.addentry( REPEAT_FULL, true, '3', _( "Repeat until fully repaired, but don't reinforce" ) );
rmenu.addentry( REPEAT_EVENT, true, '4', _( "Repeat until success/failure/level up" ) );
rmenu.addentry( REPEAT_INIT, true, '5', _( "Back to item selection" ) );

rmenu.selected = last_selection;

rmenu.selected = last_selection - REPEAT_ONCE;
rmenu.query();
if( rmenu.ret >= REPEAT_ONCE && rmenu.ret <= REPEAT_EVENT ) {

if( rmenu.ret >= REPEAT_INIT && rmenu.ret <= REPEAT_EVENT ) {
return static_cast<repeat_type>( rmenu.ret );
}

@@ -2130,6 +2132,10 @@ struct weldrig_hack {
veh->charge_battery( pseudo.charges );
pseudo.charges = 0;
}

~weldrig_hack() {
clean_up();
}
};

void activity_handlers::repair_item_finish( player_activity *act, player *p )
@@ -2147,13 +2153,15 @@ void activity_handlers::repair_item_finish( player_activity *act, player *p )
ploc ?
**ploc : p->i_at( act->index ) : w_hack.get_item();

p->add_msg_if_player( m_info, _( "repair_item_finish()" ) );
g->draw_sidebar_messages(); //GY: ** To remove

item *used_tool = main_tool.get_usable_item( iuse_name_string );
if( used_tool == nullptr ) {
debugmsg( "Lost tool used for long repair" );
act->set_to_null();
return;
}
bool event_happened = false;

const auto use_fun = used_tool->get_use( iuse_name_string );
// TODO: De-uglify this block. Something like get_use<iuse_actor_type>() maybe?
@@ -2164,18 +2172,10 @@ void activity_handlers::repair_item_finish( player_activity *act, player *p )
return;
}

// TODO: Allow setting this in the actor
// TODO: Don't use charges_to_use: welder has 50 charges per use, soldering iron has 1
if( !used_tool->ammo_sufficient() ) {
p->add_msg_if_player( _( "Your %s ran out of charges" ), used_tool->tname().c_str() );
act->set_to_null();
return;
}

item &fix = p->i_at( act->position );
// Valid Repeat choice and target, attempt repair.
if( repeat != REPEAT_INIT && act->position != INT_MIN ) {
item &fix = p->i_at( act->position );

// The first time through we just find out how many times the player wants to repeat the action.
if( repeat != REPEAT_INIT ) {
// Remember our level: we want to stop retrying on level up
const int old_level = p->get_skill_level( actor->used_skill );
const auto attempt = actor->repair( *p, *used_tool, fix );
@@ -2186,34 +2186,68 @@ void activity_handlers::repair_item_finish( player_activity *act, player *p )
p->consume_charges( *used_tool, used_tool->ammo_required() );
}
}
p->add_msg_if_player( m_info, _( "Repair attempt ." ) );

// TODO: Allow setting this in the actor
// TODO: Don't use charges_to_use: welder has 50 charges per use, soldering iron has 1
if( !used_tool->ammo_sufficient() ) {
p->add_msg_if_player( _( "Your %s ran out of charges" ), used_tool->tname().c_str() );
act->set_to_null();
return;
}

// Print message explaining why we stopped
// But only if we didn't destroy the item (because then it's obvious)
const bool destroyed = attempt == repair_item_actor::AS_DESTROYED;
if( attempt == repair_item_actor::AS_CANT ||
destroyed ||
!actor->can_repair( *p, *used_tool, fix, !destroyed ) ) {
// Can't repeat any more
act->set_to_null();
w_hack.clean_up();
return;
!actor->can_repair_target( *p, fix, !destroyed ) ) {
// Cannot continue to repair target, select another target.
act->position = INT_MIN;
}

event_happened =
bool event_happened =
attempt == repair_item_actor::AS_FAILURE ||
attempt == repair_item_actor::AS_SUCCESS ||
old_level != p->get_skill_level( actor->used_skill );
} else {
repeat = REPEAT_ONCE;

const bool need_input =
repeat == REPEAT_ONCE ||
( repeat == REPEAT_EVENT && event_happened ) ||
( repeat == REPEAT_FULL && fix.damage() <= 0 );
if( need_input ) {
repeat = REPEAT_INIT;
}
}
// Check tool is valid before we query target and Repeat choice.
if( !actor->can_use_tool( *p, *used_tool, true ) ) {
act->set_to_null();
return;
}

// target selection and validation.
while( act->position == INT_MIN ) {
g->draw_sidebar_messages(); // Refresh messages to show feedback.
const int pos = g->inv_for_filter( _( "Repair what?" ), [&actor, &main_tool]( const item & itm ) {
return itm.made_of_any( actor->materials ) && !itm.count_by_charges() && !itm.is_firearm() &&
&itm != &main_tool;
}, string_format( _( "You have no items that could be repaired with a %s." ),
main_tool.type_name( 1 ).c_str() ) );

if( pos == INT_MIN ) {
p->add_msg_if_player( m_info, _( "Never mind." ) );
act->set_to_null();
return;
}
if( actor->can_repair_target( *p, p->i_at( pos ), true ) ) {
act->position = pos;
repeat = REPEAT_INIT;
}
}

w_hack.clean_up();
const bool need_input =
repeat == REPEAT_ONCE ||
( repeat == REPEAT_EVENT && event_happened ) ||
( repeat == REPEAT_FULL && fix.damage() <= 0 );
const item &fix = p->i_at( act->position );

if( need_input ) {
if( repeat == REPEAT_INIT ) {
g->draw();
const int level = p->get_skill_level( actor->used_skill );
auto action_type = actor->default_action( fix, level );
@@ -2230,17 +2264,28 @@ void activity_handlers::repair_item_finish( player_activity *act, player *p )
_( "%s\nSuccess chance: %.1f%%\nDamage chance: %.1f%%" ),
repair_item_actor::action_description( action_type ).c_str(),
100.0f * chance.first, 100.0f * chance.second );
repeat_type answer = repeat_menu( title, repeat );
if( answer == REPEAT_CANCEL ) {
act->set_to_null();
return;
}

if( act->values.empty() ) {
act->values.resize( 1 );
}
do {
g->draw_sidebar_messages();
repeat = repeat_menu( title, repeat );

act->values[0] = static_cast<int>( answer );
if( repeat == REPEAT_CANCEL ) {
act->set_to_null();
return;
}
act->values[0] = static_cast<int>( repeat );
if( repeat == REPEAT_INIT ) { // BACK selected, redo target selection next.
p->activity.position = INT_MIN;
return;
}
if( repeat == REPEAT_FULL && fix.damage() <= 0 ) {
p->add_msg_if_player( m_info, _( "Your %s is already fully repaired." ), fix.tname().c_str() );
repeat = REPEAT_INIT;
}
} while( repeat == REPEAT_INIT );
}

// Otherwise keep retrying
@@ -2420,6 +2465,8 @@ void activity_handlers::cracking_do_turn( player_activity *act, player *p )
void activity_handlers::repair_item_do_turn( player_activity *act, player *p )
{
// Moves are decremented based on a combination of speed and good vision (not in the dark, farsighted, etc)
p->add_msg_if_player( m_info, string_format( _( "Repair one turn, moves: %d." ),
act->moves_left ) );
const int effective_moves = p->moves / p->fine_detail_vision_mod();
if( effective_moves <= act->moves_left ) {
act->moves_left -= effective_moves;
@@ -2443,7 +2443,7 @@ void repair_item_actor::load( JsonObject &obj )
trains_skill_to = obj.get_int( "trains_skill_to", 5 ) - 1;
}

bool could_repair( const player &p, const item &it, bool print_msg )
bool repair_item_actor::can_use_tool( const player &p, const item &tool, bool print_msg ) const
{
if( p.is_underwater() ) {
if( print_msg ) {
@@ -2457,7 +2457,7 @@ bool could_repair( const player &p, const item &it, bool print_msg )
}
return false;
}
if( !it.ammo_sufficient() ) {
if( !tool.ammo_sufficient() ) {
if( print_msg ) {
p.add_msg_if_player( m_info, _( "Your tool does not have enough charges to do that." ) );
}
@@ -2478,25 +2478,16 @@ static item_location get_item_location( player &p, item &it, const tripoint &pos

long repair_item_actor::use( player &p, item &it, bool, const tripoint &position ) const
{
if( !could_repair( p, it, true ) ) {
if( !can_use_tool( p, it, true ) ) {
return 0;
}
const int pos = g->inv_for_filter( _( "Repair what?" ), [this, it]( const item & itm ) {
return itm.made_of_any( materials ) && !itm.count_by_charges() && !itm.is_firearm() && &itm != &it;
}, string_format( _( "You have no items that could be repaired with a %s." ),
it.type_name( 1 ).c_str() ) );

if( pos == INT_MIN ) {
p.add_msg_if_player( m_info, _( "Never mind." ) );
return 0;
}

p.assign_activity( activity_id( "ACT_REPAIR_ITEM" ), 0, p.get_item_position( &it ), pos );
p.assign_activity( activity_id( "ACT_REPAIR_ITEM" ), 0, p.get_item_position( &it ), INT_MIN );
// We also need to store the repair actor subtype in the activity
p.activity.str_values.push_back( type );
// storing of item_location to support repairs by tools on the ground
p.activity.targets.emplace_back( get_item_location( p, it, position ) );
// All repairs are done in the activity, including charge cost
// All repairs are done in the activity, including charge cost and target item selection
return 0;
}

@@ -2572,7 +2563,7 @@ bool repair_item_actor::handle_components( player &pl, const item &fix,

if( !just_check ) {
if( comps.empty() ) {
// This shouldn't happen - the check in can_repair should prevent it
// This shouldn't happen - the check in can_repair_target should prevent it
// But report it, just in case
debugmsg( "Attempted repair with no components" );
}
@@ -2613,13 +2604,9 @@ int repair_item_actor::repair_recipe_difficulty( const player &pl,
return min;
}

bool repair_item_actor::can_repair( player &pl, const item &tool, const item &fix,
bool print_msg ) const
bool repair_item_actor::can_repair_target( player &pl, const item &fix,
bool print_msg ) const
{
if( !could_repair( pl, tool, print_msg ) ) {
return false;
}

// In some rare cases (indices getting scrambled after inventory overflow)
// our `fix` can be a different item.
if( fix.is_null() ) {
@@ -2641,7 +2628,7 @@ bool repair_item_actor::can_repair( player &pl, const item &tool, const item &fi
return false;
}

if( &fix == &tool || any_of( materials.begin(), materials.end(), [&fix]( const material_id & mat ) {
if( any_of( materials.begin(), materials.end(), [&fix]( const material_id & mat ) {
return mat.obj()
.repaired_with() == fix.typeId();
} ) ) {
@@ -2782,7 +2769,10 @@ bool damage_item( player &pl, item &fix )

repair_item_actor::attempt_hint repair_item_actor::repair( player &pl, item &tool, item &fix ) const
{
if( !can_repair( pl, tool, fix, true ) ) {
if( !can_use_tool( pl, tool, true ) ) {
return AS_CANT_USE_TOOL;
}
if( !can_repair_target( pl, fix, true ) ) {
return AS_CANT;
}

@@ -775,6 +775,7 @@ class repair_item_actor : public iuse_actor
AS_FAILURE, // Failed hard, don't retry
AS_DESTROYED, // Failed and destroyed item
AS_CANT, // Couldn't attempt
AS_CANT_USE_TOOL, // Cannot use tool
AS_CANT_YET // Skill too low
};

@@ -789,9 +790,12 @@ class repair_item_actor : public iuse_actor

/** Attempts to repair target item with selected tool */
attempt_hint repair( player &pl, item &tool, item &target ) const;
/** Checks if repairs are possible.
/** Checks if repairs on target item are possible. Excludes checks on tool.
* Doesn't just estimate - should not return true if repairs are not possible or false if they are. */
bool can_repair( player &pl, const item &tool, const item &target, bool print_msg ) const;
bool can_repair_target( player &pl, const item &target, bool print_msg ) const;
/** Checks if we are allowed to use the tool. */
bool can_use_tool( const player &p, const item &tool, bool print_msg ) const;

/** Returns if components are available. Consumes them if `just_check` is false. */
bool handle_components( player &pl, const item &fix, bool print_msg, bool just_check ) const;
/** Returns the chance to repair and to damage an item. */

0 comments on commit 533124b

Please sign in to comment.