diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index f80efe6283b28..5188433a83724 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -1676,7 +1676,7 @@ void activity_handlers::firstaid_finish( player_activity *act, player *p ) { static const std::string iuse_name_string( "heal" ); - item &it = p->i_at( act->position ); + item &it = *act->targets.front(); item *used_tool = it.get_usable_item( iuse_name_string ); if( used_tool == nullptr ) { debugmsg( "Lost tool used for healing" ); @@ -1794,7 +1794,7 @@ void activity_handlers::generic_game_do_turn( player_activity * /*act*/, player void activity_handlers::game_do_turn( player_activity *act, player *p ) { - item &game_item = p->i_at( act->position ); + item &game_item = *act->targets.front(); //Deduct 1 battery charge for every minute spent playing if( calendar::once_every( 1_minutes ) ) { @@ -1952,7 +1952,7 @@ void activity_handlers::pickaxe_do_turn( player_activity *act, player * ) void activity_handlers::pickaxe_finish( player_activity *act, player *p ) { const tripoint pos( g->m.getlocal( act->placement ) ); - item &it = p->i_at( act->position ); + item &it = *act->targets.front(); // Invalidate the activity early to prevent a query from mod_pain() act->set_to_null(); if( p->is_avatar() ) { @@ -2153,7 +2153,7 @@ void activity_handlers::start_fire_finish( player_activity *act, player *p ) { static const std::string iuse_name_string( "firestarter" ); - item &it = p->i_at( act->position ); + item &it = *act->targets.front(); item *used_tool = it.get_usable_item( iuse_name_string ); if( used_tool == nullptr ) { debugmsg( "Lost tool used for starting fire" ); @@ -2189,7 +2189,7 @@ void activity_handlers::start_fire_do_turn( player_activity *act, player *p ) } } - item &firestarter = p->i_at( act->position ); + item &firestarter = *act->targets.front(); if( firestarter.has_flag( flag_REQUIRES_TINDER ) ) { if( !g->m.tinder_at( act->placement ) ) { p->add_msg_if_player( m_info, _( "This item requires tinder to light." ) ); @@ -2326,7 +2326,7 @@ void activity_handlers::hand_crank_do_turn( player_activity *act, player *p ) // to 10 watt (suspicious claims from some manufacturers) sustained output. // It takes 2.4 minutes to produce 1kj at just slightly under 7 watts (25 kj per hour) // time-based instead of speed based because it's a sustained activity - item &hand_crank_item = p ->i_at( act->position ); + item &hand_crank_item = *act->targets.front(); if( calendar::once_every( 144_seconds ) ) { p->mod_fatigue( 1 ); @@ -2349,7 +2349,7 @@ void activity_handlers::vibe_do_turn( player_activity *act, player *p ) //Using a vibrator takes time (10 minutes), not speed //Linear increase in morale during action with a small boost at end //Deduct 1 battery charge for every minute in use, or vibrator is much less effective - item &vibrator_item = p->i_at( act->position ); + item &vibrator_item = *act->targets.front(); if( ( p->is_wearing( "rebreather" ) ) || ( p->is_wearing( "rebreather_xl" ) ) || ( p->is_wearing( "mask_h20survivor" ) ) ) { @@ -2456,7 +2456,7 @@ void activity_handlers::oxytorch_do_turn( player_activity *act, player *p ) return; } - item &it = p->i_at( act->position ); + item &it = *act->targets.front(); // act->values[0] is the number of charges yet to be consumed const int charges_used = std::min( act->values[0], it.ammo_required() ); @@ -2476,7 +2476,7 @@ void activity_handlers::oxytorch_finish( player_activity *act, player *p ) const ter_id ter = g->m.ter( pos ); // fast players might still have some charges left to be consumed - p->i_at( act->position ).ammo_consume( act->values[0], p->pos() ); + act->targets.front()->ammo_consume( act->values[0], p->pos() ); if( g->m.furn( pos ) == f_rack ) { g->m.furn_set( pos, f_null ); @@ -2874,8 +2874,8 @@ void activity_handlers::gunmod_add_finish( player_activity *act, player *p ) return; } - item &gun = p->i_at( act->position ); - item &mod = p->i_at( act->values[0] ); + item &gun = *act->targets.at( 0 ); + item &mod = *act->targets.at( 1 ); // chance of success (%) const int roll = act->values[1]; @@ -3117,7 +3117,7 @@ static void rod_fish( player *p, const std::vector &fishables ) void activity_handlers::fish_do_turn( player_activity *act, player *p ) { - item &it = p->i_at( act->position ); + item &it = *act->targets.front(); int fish_chance = 1; int survival_skill = p->get_skill_level( skill_survival ); if( it.has_flag( flag_FISH_POOR ) ) { diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index bcf8636fd9f7c..f0a08ce577405 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -2828,7 +2828,8 @@ static bool generic_multi_activity_do( player &p, const activity_id &act_id, p.activity = player_activity(); item *best_rod = p.best_quality_item( qual_FISHING ); p.assign_activity( ACT_FISH, to_moves( 5_hours ), 0, - p.get_item_position( best_rod ), best_rod->tname() ); + 0, best_rod->tname() ); + p.activity.targets.push_back( item_location( p, best_rod ) ); p.activity.coord_set = g->get_fishable_locations( ACTIVITY_SEARCH_DISTANCE, src_loc ); return false; } else if( reason == NEEDS_MINING ) { diff --git a/src/iexamine.cpp b/src/iexamine.cpp index e217e4be62297..4a6f4021e1572 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -552,7 +552,7 @@ class atm_menu item *dst; if( u.activity.id() == ACT_ATM ) { u.activity.set_to_null(); // stop for now, if required, it will be created again. - dst = &u.i_at( u.activity.position ); + dst = u.activity.targets.front().get_item(); if( dst->is_null() || dst->typeId() != "cash_card" ) { return false; } @@ -573,7 +573,8 @@ class atm_menu // Money from `*i` could be transferred, but we're out of moves, schedule it for // the next turn. Putting this here makes sure there will be something to be // done next turn. - u.assign_activity( ACT_ATM, 0, transfer_all_money, u.get_item_position( dst ) ); + u.assign_activity( ACT_ATM, 0, transfer_all_money ); + u.activity.targets.push_back( item_location( u, dst ) ); break; } diff --git a/src/iuse.cpp b/src/iuse.cpp index a8347cc893699..85157f34b8a18 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -1762,8 +1762,8 @@ int iuse::fishing_rod( player *p, item *it, bool, const tripoint & ) return 0; } p->add_msg_if_player( _( "You cast your line and wait to hook something…" ) ); - p->assign_activity( ACT_FISH, to_moves( 5_hours ), 0, - p->get_item_position( it ), it->tname() ); + p->assign_activity( ACT_FISH, to_moves( 5_hours ), 0, 0, it->tname() ); + p->activity.targets.push_back( item_location( *p, it ) ); p->activity.coord_set = g->get_fishable_locations( 60, *found ); return 0; } @@ -3313,7 +3313,8 @@ int iuse::pickaxe( player *p, item *it, bool, const tripoint &pos ) break; } - p->assign_activity( ACT_PICKAXE, moves, -1, p->get_item_position( it ) ); + p->assign_activity( ACT_PICKAXE, moves, -1 ); + p->activity.targets.push_back( item_location( *p, it ) ); p->activity.placement = g->m.getabs( pnt ); p->add_msg_if_player( _( "You strike the %1$s with your %2$s." ), g->m.tername( pnt ), it->tname() ); @@ -4412,7 +4413,8 @@ int iuse::portable_game( player *p, item *it, bool, const tripoint & ) p->get_item_position( it ), "gaming" ); return it->type->charges_to_use(); } - p->assign_activity( ACT_GAME, moves, -1, p->get_item_position( it ), "gaming" ); + p->assign_activity( ACT_GAME, moves, -1, 0, "gaming" ); + p->activity.targets.push_back( item_location( *p, it ) ); std::map game_data; game_data.clear(); int game_score = 0; @@ -4460,8 +4462,8 @@ int iuse::hand_crank( player *p, item *it, bool, const tripoint & ) if( it->ammo_capacity() > it->ammo_remaining() ) { p->add_msg_if_player( _( "You start cranking the %s to charge its %s." ), it->tname(), it->magazine_current()->tname() ); - p->assign_activity( ACT_HAND_CRANK, moves, -1, p->get_item_position( it ), - "hand-cranking" ); + p->assign_activity( ACT_HAND_CRANK, moves, -1, 0, "hand-cranking" ); + p->activity.targets.push_back( item_location( *p, it ) ); } else { p->add_msg_if_player( _( "You could use the %s to charge its %s, but it's already charged." ), it->tname(), magazine->tname() ); @@ -4505,8 +4507,8 @@ int iuse::vibe( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( _( "You whip out your %s and start getting the tension out." ), it->tname() ); } - p->assign_activity( ACT_VIBE, moves, -1, p->get_item_position( it ), - "de-stressing" ); + p->assign_activity( ACT_VIBE, moves, -1, 0, "de-stressing" ); + p->activity.targets.push_back( item_location( *p, it ) ); } return it->type->charges_to_use(); } @@ -4923,8 +4925,8 @@ int iuse::oxytorch( player *p, item *it, bool, const tripoint & ) } // placing ter here makes resuming tasks work better - p->assign_activity( ACT_OXYTORCH, moves, static_cast( ter ), - p->get_item_position( it ) ); + p->assign_activity( ACT_OXYTORCH, moves, static_cast( ter ) ); + p->activity.targets.push_back( item_location( *p, it ) ); p->activity.placement = pnt; p->activity.values.push_back( charges ); diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index 4d6f9021e738f..faa541d0582c3 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -1454,8 +1454,8 @@ int firestarter_actor::use( player &p, item &it, bool t, const tripoint &spos ) const int potential_skill_gain = moves_modifier + moves_cost_fast / 100.0 + 2; p.assign_activity( ACT_START_FIRE, moves, potential_skill_gain, - p.get_item_position( &it ), - it.tname() ); + 0, it.tname() ); + p.activity.targets.push_back( item_location( p, &it ) ); p.activity.values.push_back( g->natural_light_level( pos.z ) ); p.activity.placement = pos; // charges to use are handled by the activity @@ -3621,7 +3621,8 @@ int heal_actor::use( player &p, item &it, bool, const tripoint &pos ) const if( long_action && &patient == &p && !p.is_npc() ) { // Assign first aid long action. /** @EFFECT_FIRSTAID speeds up firstaid activity */ - p.assign_activity( ACT_FIRSTAID, cost, 0, p.get_item_position( &it ), it.tname() ); + p.assign_activity( ACT_FIRSTAID, cost, 0, 0, it.tname() ); + p.activity.targets.push_back( item_location( p, &it ) ); p.activity.values.push_back( hpp ); p.moves = 0; return 0; diff --git a/src/player.cpp b/src/player.cpp index c082811ea1f1a..b65cabf282771 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -4050,8 +4050,10 @@ void player::gunmod_add( item &gun, item &mod ) const int moves = !has_trait( trait_DEBUG_HS ) ? mod.type->gunmod->install_time : 0; - assign_activity( activity_id( "ACT_GUNMOD_ADD" ), moves, -1, get_item_position( &gun ), tool ); - activity.values.push_back( get_item_position( &mod ) ); + assign_activity( activity_id( "ACT_GUNMOD_ADD" ), moves, -1, 0, tool ); + activity.targets.push_back( item_location( *this, &gun ) ); + activity.targets.push_back( item_location( *this, &mod ) ); + activity.values.push_back( 0 ); // dummy value activity.values.push_back( roll ); // chance of success (%) activity.values.push_back( risk ); // chance of damage (%) activity.values.push_back( qty ); // tool charges diff --git a/src/player_activity.cpp b/src/player_activity.cpp index c3f2dd354d16b..b577383c541b4 100644 --- a/src/player_activity.cpp +++ b/src/player_activity.cpp @@ -13,6 +13,17 @@ #include "itype.h" #include "skill.h" +static const activity_id ACT_FIRSTAID( "ACT_FIRSTAID" ); +static const activity_id ACT_GAME( "ACT_GAME" ); +static const activity_id ACT_PICKAXE( "ACT_PICKAXE" ); +static const activity_id ACT_START_FIRE( "ACT_START_FIRE" ); +static const activity_id ACT_HAND_CRANK( "ACT_HAND_CRANK" ); +static const activity_id ACT_VIBE( "ACT_VIBE" ); +static const activity_id ACT_OXYTORCH( "ACT_OXYTORCH" ); +static const activity_id ACT_FISH( "ACT_FISH" ); +static const activity_id ACT_ATM( "ACT_ATM" ); +static const activity_id ACT_GUNMOD_ADD( "ACT_GUNMOD_ADD" ); + player_activity::player_activity() : type( activity_id::NULL_ID() ) { } player_activity::player_activity( activity_id t, int turns, int Index, int pos, @@ -29,6 +40,24 @@ player_activity::player_activity( const activity_actor &actor ) : type( actor.ge { } +void player_activity::migrate_item_position( Character &guy ) +{ + const bool simple_action_replace = + type == ACT_FIRSTAID || type == ACT_GAME || + type == ACT_PICKAXE || type == ACT_START_FIRE || + type == ACT_HAND_CRANK || type == ACT_VIBE || + type == ACT_OXYTORCH || type == ACT_FISH || + type == ACT_ATM; + + if( simple_action_replace ) { + targets.push_back( item_location( guy, &guy.i_at( position ) ) ); + } else if( type == ACT_GUNMOD_ADD ) { + // this activity has two indices; "position" = gun and "values[0]" = mod + targets.push_back( item_location( guy, &guy.i_at( position ) ) ); + targets.push_back( item_location( guy, &guy.i_at( values[0] ) ) ); + } +} + void player_activity::set_to_null() { type = activity_id::NULL_ID(); diff --git a/src/player_activity.h b/src/player_activity.h index 7b5c486cd36de..b8fe60f7fb90d 100644 --- a/src/player_activity.h +++ b/src/player_activity.h @@ -42,7 +42,10 @@ class player_activity int moves_left = 0; /** An activity specific value. */ int index = 0; - /** An activity specific value. */ + /** + * An activity specific value. + * DO NOT USE FOR ITEM INDEX + */ int position = 0; /** An activity specific value. */ std::string name; @@ -114,6 +117,9 @@ class player_activity void serialize( JsonOut &json ) const; void deserialize( JsonIn &jsin ); + // used to migrate the item indices to item_location + // obsolete after 0.F stable + void migrate_item_position( Character &guy ); /** Convert from the old enumeration to the new string_id */ void deserialize_legacy_type( int legacy_type, activity_id &dest ); diff --git a/src/savegame.cpp b/src/savegame.cpp index e1969774f0956..636ef3f00f3ce 100644 --- a/src/savegame.cpp +++ b/src/savegame.cpp @@ -51,7 +51,7 @@ extern std::map> quick_shortcuts_map; * Changes that break backwards compatibility should bump this number, so the game can * load a legacy format loader. */ -const int savegame_version = 27; +const int savegame_version = 28; /* * This is a global set by detected version header in .sav, maps.txt, or overmap. diff --git a/src/savegame_json.cpp b/src/savegame_json.cpp index 44581e31d3c2e..ba0c4e9d67f40 100644 --- a/src/savegame_json.cpp +++ b/src/savegame_json.cpp @@ -601,6 +601,14 @@ void Character::load( const JsonObject &data ) JsonIn *invin = data.get_raw( "inv" ); inv.json_load_items( *invin ); } + // this is after inventory is loaded to make it more obvious that + // it needs to be changed again when Character::i_at is removed for nested containers + if( savegame_loading_version < 28 ) { + activity.migrate_item_position( *this ); + destination_activity.migrate_item_position( *this ); + stashed_outbounds_activity.migrate_item_position( *this ); + stashed_outbounds_backlog.migrate_item_position( *this ); + } weapon = item( "null", 0 ); data.read( "weapon", weapon );