Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various link up fixes #67376

Merged
merged 14 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions data/json/items/tool/cables.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"type": "TOOL",
"id": "extension_cable",
"name": { "str": "extension cord" },
"description": "A long 30-foot (or about 10 m) orange extension cord for connecting appliances. Could be used on any appliance or other household electrical system.",
"description": "A long 30-foot (or about 10 m) orange extension cord for extending cables or connecting appliances. Could be used on any appliance or other household electrical system.",
"to_hit": 1,
"color": "light_blue",
"symbol": "&",
Expand All @@ -86,7 +86,7 @@
"type": "TOOL",
"id": "long_extension_cable",
"name": { "str": "outdoor extension cord" },
"description": "An extra-long 100-foot (or about 30 m) orange extension cord for connecting outdoor appliances. Could be used on any appliance or other household electrical system.",
"description": "An extra-long 100-foot (or about 30 m) orange extension cord for extending cables or connecting outdoor appliances. Could be used on any appliance or other household electrical system.",
"copy-from": "extension_cable",
"volume": "3750 ml",
"weight": "2500 g",
Expand All @@ -98,7 +98,7 @@
"type": "TOOL",
"id": "hd_tow_cable",
"name": { "str": "heavy-duty tow cable" },
"description": "An extremely heavy-duty 75-foot (or about 24 m) tow cable made from thick steel wire coated in plastic. If attached to a vehicle, it could be used to pull another vehicle of any weight.",
"description": "An extremely heavy-duty 30-foot (or about 9 m) tow cable made from thick steel wire coated in plastic. If attached to a vehicle, it could be used to pull another vehicle of any weight.",
"to_hit": -1,
"color": "light_blue",
"symbol": "&",
Expand All @@ -108,8 +108,8 @@
"category": "tools",
"price": 80,
"price_postapoc": 500,
"max_charges": 6,
"initial_charges": 6,
"max_charges": 8,
"initial_charges": 8,
"use_action": {
"type": "link_up",
"menu_text": "Attach / Manage connections",
Expand Down
2 changes: 1 addition & 1 deletion data/json/items/tool/cooking.json
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@
"symbol": ";",
"color": "red",
"ammo": [ "battery" ],
"flags": [ "WATER_BREAK", "ELECTRONIC" ],
"flags": [ "WATER_BREAK", "ELECTRONIC", "ALLOWS_REMOTE_USE" ],
"power_draw": "100 W",
"qualities": [ [ "CONTAIN", 1 ] ],
"use_action": [ "MULTICOOKER", { "type": "link_up", "cable_length": 2, "charge_rate": "1000 W" } ],
Expand Down
2 changes: 1 addition & 1 deletion doc/JSON_FLAGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1346,7 +1346,7 @@ Melee flags are fully compatible with tool flags, and vice versa.
- ```ALLOWS_REMOTE_USE``` This item can be activated or reloaded from adjacent tile without picking it up.
- ```BELT_CLIP``` The item can be clipped or hooked on to a belt loop of the appropriate size (belt loops are limited by their max_volume and max_weight properties)
- ```BOMB``` It can be a remote controlled bomb.
- ```CABLE_SPOOL``` This item is a cable spool and must be processed as such. It should usually have a "link_up" iuse_action that describes what it can be connected to and how.
- ```CABLE_SPOOL``` This item is a spool of cable and must be processed as such. It should usually have a "link_up" iuse_action, which it has special behavior for.
- ```CANNIBALISM``` The item is a food that contains human flesh, and applies all applicable effects when consumed.
- ```CHARGEDIM``` If illuminated, light intensity fades with charge, starting at 20% charge left.
- ```DIG_TOOL``` If wielded, digs thorough terrain like rock and walls, as player walks into them. If item also has ```POWERED``` flag, then it digs faster, but uses up the item's ammo as if activating it.
Expand Down
1 change: 1 addition & 0 deletions doc/JSON_INFO.md
Original file line number Diff line number Diff line change
Expand Up @@ -4035,6 +4035,7 @@ The contents of use_action fields can either be a string indicating a built-in f
},
"use_action": {
"type": "link_up", // Connect item to a vehicle or appliance, such as plugging a chargeable device into a power source.
// If the item has the CABLE_SPOOL flag, it has special behaviors available, like connecting vehicles together.
"cable_length": 4 // Maximum length of the cable ( Optional, defaults to the item type's maximum charges ).
// If extended by other cables, will use the sum of all cables' lengths.
"charge_rate": "60 W" // The charge rate of the plugged-in device's batteries in watts. ( Optional, defaults to "0 W" )
Expand Down
7 changes: 4 additions & 3 deletions src/avatar_action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1154,9 +1154,10 @@ void avatar_action::use_item( avatar &you, item_location &loc, std::string const
if( use_in_place ) {
update_lum( loc, false );
you.use( loc, pre_obtain_moves, method );
update_lum( loc, true );

loc.make_active();
if( loc ) {
update_lum( loc, true );
loc.make_active();
}
} else {
you.use( loc, pre_obtain_moves, method );

Expand Down
10 changes: 9 additions & 1 deletion src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12965,7 +12965,7 @@ void item::set_link_traits( const bool assign_t_state )
const link_up_actor *it_actor = static_cast<const link_up_actor *>
( get_use( "link_up" )->get_actor_ptr() );
link->max_length = it_actor->cable_length == -1 ? type->maximum_charges() : it_actor->cable_length;
link->efficiency = it_actor->efficiency < MIN_LINK_EFFICIENCY ? 0.0f : link->efficiency;
link->efficiency = it_actor->efficiency < MIN_LINK_EFFICIENCY ? 0.0f : it_actor->efficiency;
// Reset s_bub_pos to force the item to check the length during process_link.
link->s_bub_pos = tripoint_min;

Expand All @@ -12981,6 +12981,13 @@ void item::set_link_traits( const bool assign_t_state )
link->efficiency * actor->efficiency;
}

link->charge_rate = link->efficiency < MIN_LINK_EFFICIENCY ? 0 : it_actor->charge_rate.value();
// Convert charge_rate to how long it takes to charge 1 kW, the unit batteries use.
// 0 means batteries won't be charged, but it can still provide power to devices unless efficiency is also 0.
link->charge_interval = link->efficiency < MIN_LINK_EFFICIENCY || it_actor->charge_rate == 0_W ? 0 :
std::max( static_cast<int>( std::floor( 1000000.0 / abs( it_actor->charge_rate.value() ) + 0.5 ) ),
1 );

if( assign_t_state && link->t_veh_safe ) {
// Assign t_state based on the parts available at the connected mount point.
if( it_actor->targets.find( link_state::vehicle_port ) != it_actor->targets.end() &&
Expand Down Expand Up @@ -13562,6 +13569,7 @@ bool item::process_internal( map &here, Character *carrier, const tripoint &pos,
}
if( has_flag( flag_CABLE_SPOOL ) && mark_flag() ) {
// DO NOT process this as a tool! It really isn't!
// Cables have been reworked and shouldn't be active items anymore.
active = false;
return false;
}
Expand Down
3 changes: 3 additions & 0 deletions src/item_contents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1558,6 +1558,9 @@ const item &item_contents::only_item() const
item *item_contents::get_item_with( const std::function<bool( const item &it )> &filter )
{
for( item_pocket &pocket : contents ) {
if( pocket.is_type( item_pocket::pocket_type::CABLE ) ) {
continue;
}
item *it = pocket.get_item_with( filter );
if( it != nullptr ) {
return it;
Expand Down
8 changes: 4 additions & 4 deletions src/iuse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3861,7 +3861,7 @@ std::optional<int> iuse::tazer( Character *p, item *it, bool, const tripoint &po

std::optional<int> iuse::tazer2( Character *p, item *it, bool b, const tripoint &pos )
{
if( it->ammo_remaining( p ) >= 2 ) {
if( it->ammo_remaining( p, true ) >= 2 ) {
// Instead of having a ctrl+c+v of the function above, spawn a fake tazer and use it
// Ugly, but less so than copied blocks
item fake( "tazer", calendar::turn_zero );
Expand Down Expand Up @@ -7614,7 +7614,7 @@ std::optional<int> iuse::multicooker( Character *p, item *it, bool t, const trip

if( t ) {
//stop action before power runs out and iuse deletes the cooker
if( it->ammo_remaining( p ) < charge_buffer ) {
if( it->ammo_remaining( p, true ) < charge_buffer ) {
it->active = false;
it->erase_var( "RECIPE" );
it->convert( itype_multi_cooker );
Expand Down Expand Up @@ -7709,7 +7709,7 @@ std::optional<int> iuse::multicooker( Character *p, item *it, bool t, const trip
menu.addentry( mc_stop, true, 's', _( "Stop cooking" ) );
} else {
if( dish_it == nullptr ) {
if( it->ammo_remaining( p ) < charges_to_start ) {
if( it->ammo_remaining( p, true ) < charges_to_start ) {
p->add_msg_if_player( _( "Batteries are low." ) );
return 0;
}
Expand Down Expand Up @@ -7845,7 +7845,7 @@ std::optional<int> iuse::multicooker( Character *p, item *it, bool t, const trip
const int all_charges = charges_to_start + mealtime / 1000 * units::to_watt(
it->type->tool->power_draw ) / 1000;

if( it->ammo_remaining( p ) < all_charges ) {
if( it->ammo_remaining( p, true ) < all_charges ) {

p->add_msg_if_player( m_warning,
_( "The multi-cooker needs %d charges to cook this dish." ),
Expand Down
33 changes: 18 additions & 15 deletions src/iuse_actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4387,7 +4387,7 @@ std::string link_up_actor::get_name() const
return iuse_actor::get_name();
}

std::optional<int> link_up_actor::use( Character *p, item &it, bool t, const tripoint & ) const
std::optional<int> link_up_actor::use( Character *p, item &it, bool t, const tripoint &pnt ) const
{
if( t ) {
return std::nullopt;
Expand Down Expand Up @@ -4595,7 +4595,7 @@ std::optional<int> link_up_actor::use( Character *p, item &it, bool t, const tri

} else if( choice == 30 ) {
// Selection: Attach to another cable, resulting in a longer one.
return link_extend_cable( p, it );
return link_extend_cable( p, it, pnt );

} else if( choice == 31 ) {
// Selection: Remove all cable extensions and give the individual cables to the player.
Expand Down Expand Up @@ -4811,7 +4811,7 @@ std::optional<int> link_up_actor::link_to_veh_app( Character *p, item &it,
( it.link->t_abs_pos + prev_veh->coord_translate( it.link->t_mount ) ).raw(),
it.link->t_abs_pos.raw() );

for( const vpart_reference &vpr : sel_veh->get_any_parts( "POWER_TRANSFER" ) ) {
for( const vpart_reference &vpr : prev_veh->get_any_parts( "POWER_TRANSFER" ) ) {
if( vpr.part().target.first == prev_part_target.first &&
vpr.part().target.second == prev_part_target.second ) {
p->add_msg_if_player( m_warning, _( "The %1$s and %2$s are already connected." ),
Expand Down Expand Up @@ -5041,7 +5041,8 @@ std::optional<int> link_up_actor::link_tow_cable( Character *p, item &it,
}
}

std::optional<int> link_up_actor::link_extend_cable( Character *p, item &it ) const
std::optional<int> link_up_actor::link_extend_cable( Character *p, item &it,
const tripoint &pnt ) const
{
avatar *you = p->as_avatar();
if( !you ) {
Expand Down Expand Up @@ -5082,8 +5083,8 @@ std::optional<int> link_up_actor::link_extend_cable( Character *p, item &it ) co
return std::nullopt;
}

item_location extension = is_cable_item ? form_loc( *p, tripoint_min, it ) : selected;
item_location extended = is_cable_item ? selected : form_loc( *p, tripoint_min, it );
item_location extension = is_cable_item ? form_loc( *p, pnt, it ) : selected;
item_location extended = is_cable_item ? selected : form_loc( *p, pnt, it );
std::optional<item> extended_copy;

// We'll make a copy of the extended item and check pocket weight/volume capacity if:
Expand Down Expand Up @@ -5121,31 +5122,33 @@ std::optional<int> link_up_actor::link_extend_cable( Character *p, item &it ) co

if( extended_copy ) {
// Check if there's another pocket on the same container that can hold the extended item, respecting pocket settings.
if( extended.has_parent() &&
extended.parent_item()->can_contain( *extended_ptr, false, false, false,
item_location(), 10000000_ml, false ).success() ) {
if( !extended.parent_item()->put_in( *extended_ptr,
item_pocket::pocket_type::CONTAINER ).success() ) {
item_location parent = extended.parent_item();
if( parent->can_contain( *extended_ptr, false, false, false,
item_location(), 10000000_ml, false ).success() ) {
if( !parent->put_in( *extended_ptr, item_pocket::pocket_type::CONTAINER ).success() ) {
debugmsg( "Failed to put %s inside %s!", extended_ptr->type_name(),
extended.parent_item()->type_name() );
parent->type_name() );
return std::nullopt;
}
extended.remove_item();
} else {
if( !query_yn( _( "The %1$s can't contain the %2$s with the %3$s attached. Continue?" ),
extended.parent_item()->type_name(), extended_ptr->type_name(), extension->type_name() ) ) {
parent->type_name(), extended_ptr->type_name(), extension->type_name() ) ) {
return std::nullopt;
}
// Attach the cord, even though it won't fit, and let it spill out naturally.
extended.parent_pocket()->add( *extended_ptr );
extended.remove_item();
}
extended.make_active();
extended.remove_item();
}

p->add_msg_if_player( is_cable_item ? _( "You extend the %1$s with the %2$s." ) :
_( "You extend the %1$s's cable with the %2$s." ),
extended_ptr->type_name(), extension->type_name() );
extension.remove_item();
p->invalidate_inventory_validity_cache();
p->invalidate_weight_carried_cache();
p->drop_invalid_inventory();
p->moves -= move_cost;
return 0;
}
Expand Down
4 changes: 2 additions & 2 deletions src/iuse_actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -1072,14 +1072,14 @@ class link_up_actor : public iuse_actor

std::optional<int> link_to_veh_app( Character *p, item &it, bool to_ports ) const;
std::optional<int> link_tow_cable( Character *p, item &it, bool to_towing ) const;
std::optional<int> link_extend_cable( Character *p, item &it ) const;
std::optional<int> link_extend_cable( Character *p, item &it, const tripoint &pnt ) const;
std::optional<int> remove_extensions( Character *p, item &it ) const;

link_up_actor() : iuse_actor( "link_up" ) {}

~link_up_actor() override = default;
void load( const JsonObject &jo ) override;
std::optional<int> use( Character *p, item &it, bool t, const tripoint & ) const override;
std::optional<int> use( Character *p, item &it, bool t, const tripoint &pnt ) const override;
std::unique_ptr<iuse_actor> clone() const override;
void info( const item &, std::vector<iteminfo> & ) const override;
std::string get_name() const override;
Expand Down
2 changes: 1 addition & 1 deletion src/savegame_json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2870,8 +2870,8 @@ void item::link_data::serialize( JsonOut &jsout ) const
jsout.member( "link_max_length", max_length );
jsout.member( "link_last_processed", last_processed );
jsout.member( "link_charge_rate", charge_rate );
jsout.member( "link_charge_interval", charge_interval );
jsout.member( "link_charge_efficiency", efficiency );
jsout.member( "link_charge_interval", charge_interval );
jsout.end_object();
}

Expand Down
2 changes: 1 addition & 1 deletion src/veh_appliance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ void veh_app_interact::plug()
{
const int part = veh->part_at( a_point );
const tripoint pos = veh->global_part_pos3( part );
veh->plug_in( get_map().getabs( pos ) );
veh->plug_in( pos );
}

void veh_app_interact::populate_app_actions()
Expand Down
49 changes: 29 additions & 20 deletions src/vehicle_use.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,7 @@ item vehicle::init_cord( const tripoint &pos )
cord.link->t_veh_safe = get_safe_reference();
cord.link->t_abs_pos = get_map().getglobal( pos );
cord.set_link_traits();
cord.link->max_length = 2;

return cord;
}
Expand All @@ -568,34 +569,42 @@ void vehicle::connect( const tripoint &source_pos, const tripoint &target_pos )
item cord = init_cord( source_pos );
map &here = get_map();

const optional_vpart_position target_vp = here.veh_at( target_pos );
const optional_vpart_position source_vp = here.veh_at( source_pos );
const optional_vpart_position sel_vp = here.veh_at( target_pos );
const optional_vpart_position prev_vp = here.veh_at( source_pos );

if( !target_vp ) {
if( !sel_vp ) {
return;
}
vehicle *const target_veh = &target_vp->vehicle();
vehicle *const source_veh = &source_vp->vehicle();
if( source_veh == target_veh ) {
vehicle *const sel_veh = &sel_vp->vehicle();
vehicle *const prev_veh = &prev_vp->vehicle();
if( prev_veh == sel_veh ) {
return ;
}

tripoint target_global = here.getabs( target_pos );
const vpart_id vpid( cord.typeId().str() );

point vcoords = source_vp->mount();
vehicle_part source_part( vpid, item( cord ) );
source_part.target.first = target_global;
source_part.target.second = target_veh->global_square_location().raw();
source_veh->install_part( vcoords, std::move( source_part ) );
source_veh->precalc_mounts( 1, source_veh->pivot_rotation[1], source_veh->pivot_anchor[1] );

vcoords = target_vp->mount();
vehicle_part target_part( vpid, item( cord ) );
target_part.target.first = cord.link->t_abs_pos.raw();
target_part.target.second = source_veh->global_square_location().raw();
target_veh->install_part( vcoords, std::move( target_part ) );
target_veh->precalc_mounts( 1, target_veh->pivot_rotation[1], target_veh->pivot_anchor[1] );
// Prepare target tripoints for the cable parts that'll be added to the selected/previous vehicles
const std::pair<tripoint, tripoint> prev_part_target = std::make_pair(
here.getabs( target_pos ),
sel_veh->global_square_location().raw() );
const std::pair<tripoint, tripoint> sel_part_target = std::make_pair(
( cord.link->t_abs_pos + prev_veh->coord_translate( cord.link->t_mount ) ).raw(),
cord.link->t_abs_pos.raw() );

const point vcoords1 = cord.link->t_mount;
const point vcoords2 = sel_vp->mount();

vehicle_part prev_veh_part( vpid, item( cord ) );
prev_veh_part.target.first = prev_part_target.first;
prev_veh_part.target.second = prev_part_target.second;
prev_veh->install_part( vcoords1, std::move( prev_veh_part ) );
prev_veh->precalc_mounts( 1, prev_veh->pivot_rotation[1], prev_veh->pivot_anchor[1] );

vehicle_part sel_veh_part( vpid, item( cord ) );
sel_veh_part.target.first = sel_part_target.first;
sel_veh_part.target.second = sel_part_target.second;
sel_veh->install_part( vcoords2, std::move( sel_veh_part ) );
sel_veh->precalc_mounts( 1, sel_veh->pivot_rotation[1], sel_veh->pivot_anchor[1] );
}

double vehicle::engine_cold_factor( const vehicle_part &vp ) const
Expand Down