diff --git a/data/json/flags.json b/data/json/flags.json index 55790cb89fe06..788a4116c97d4 100644 --- a/data/json/flags.json +++ b/data/json/flags.json @@ -1893,6 +1893,10 @@ "id": "USES_BIONIC_POWER", "type": "json_flag" }, + { + "id": "USES_NEARBY_AMMO", + "type": "json_flag" + }, { "id": "USE_EAT_VERB", "type": "json_flag" diff --git a/data/json/itemgroups/Clothing_Gear/clothing.json b/data/json/itemgroups/Clothing_Gear/clothing.json index bceb49aec7284..c89fa36611ff8 100644 --- a/data/json/itemgroups/Clothing_Gear/clothing.json +++ b/data/json/itemgroups/Clothing_Gear/clothing.json @@ -3380,7 +3380,7 @@ [ "throw_extinguisher", 2 ], { "item": "small_repairkit", "prob": 14, "charges": [ 0, 500 ] }, [ "grapnel", 6 ], - { "item": "misc_repairkit", "prob": 8, "charges-min": 0 }, + { "item": "misc_repairkit", "prob": 8 }, { "distribution": [ { "group": "full_survival_kit" }, { "group": "used_survival_kit" } ], "prob": 3 }, { "group": "tools_toolbox", "prob": 1 }, [ "survivor_belt_notools", 2 ], diff --git a/data/json/itemgroups/Locations_MapExtras/locations.json b/data/json/itemgroups/Locations_MapExtras/locations.json index 82c1d57a54e45..5fa1b28924daf 100644 --- a/data/json/itemgroups/Locations_MapExtras/locations.json +++ b/data/json/itemgroups/Locations_MapExtras/locations.json @@ -1851,7 +1851,7 @@ { "item": "wearable_light", "prob": 10, "charges": [ 0, 100 ] }, [ "antiparasitic", 5 ], { "prob": 5, "group": "diazepam_bottle_plastic_pill_prescription_1_10" }, - { "item": "misc_repairkit", "prob": 5, "charges-min": 0 }, + { "item": "misc_repairkit", "prob": 5 }, { "group": "tools_toolbox", "prob": 2 }, [ "apron_cotton", 5 ], [ "apron_leather", 5 ], diff --git a/data/json/itemgroups/Locations_MapExtras/locations_commercial.json b/data/json/itemgroups/Locations_MapExtras/locations_commercial.json index 5e3c824f95575..fb7368869e2ae 100644 --- a/data/json/itemgroups/Locations_MapExtras/locations_commercial.json +++ b/data/json/itemgroups/Locations_MapExtras/locations_commercial.json @@ -1210,7 +1210,7 @@ { "item": "manual_fabrication", "prob": 20 }, { "item": "duct_tape", "prob": 70, "charges": [ 50, 200 ] }, { "item": "superglue", "prob": 25 }, - { "item": "misc_repairkit", "prob": 15, "charges-min": 0 }, + { "item": "misc_repairkit", "prob": 15 }, { "group": "tools_toolbox", "prob": 2 } ] }, @@ -1271,7 +1271,7 @@ { "item": "socket_screwdriver_set", "prob": 20 }, { "item": "duct_tape", "prob": 50 }, { "item": "superglue", "prob": 10 }, - { "item": "misc_repairkit", "prob": 25, "charges": 200 }, + { "item": "misc_repairkit", "prob": 25 }, { "group": "tools_toolbox", "prob": 2 } ] } diff --git a/data/json/itemgroups/activities_hobbies.json b/data/json/itemgroups/activities_hobbies.json index fd29f1c00b66c..016a68c708fb3 100644 --- a/data/json/itemgroups/activities_hobbies.json +++ b/data/json/itemgroups/activities_hobbies.json @@ -241,7 +241,7 @@ [ "rope_30", 35 ], [ "hatchet", 10 ], [ "storage_line", 20 ], - { "item": "misc_repairkit", "prob": 5, "charges-min": 0 }, + { "item": "misc_repairkit", "prob": 5 }, { "item": "mess_kit", "prob": 10 }, { "item": "portable_stove", "prob": 10, "container-item": "nylon_bag" }, [ "pot", 20 ], @@ -461,7 +461,7 @@ [ "rope_30", 35 ], [ "hatchet", 10 ], [ "storage_line", 20 ], - { "item": "misc_repairkit", "prob": 5, "charges-min": 0 }, + { "item": "misc_repairkit", "prob": 5 }, { "item": "mess_kit", "prob": 10 }, [ "pot", 20 ], [ "folded_inflatable_boat", 25 ], diff --git a/data/json/itemgroups/collections_trades.json b/data/json/itemgroups/collections_trades.json index d85ed654725a2..d2a1c0f307c4c 100644 --- a/data/json/itemgroups/collections_trades.json +++ b/data/json/itemgroups/collections_trades.json @@ -41,7 +41,7 @@ { "item": "cable", "prob": 60 }, { "item": "sm_extinguisher", "prob": 10, "charges": 10 }, { "item": "grapnel", "prob": 1 }, - { "item": "misc_repairkit", "prob": 5, "charges-min": 0 }, + { "item": "misc_repairkit", "prob": 5 }, { "item": "knitting_needles", "prob": 1 }, { "item": "medium_propane_tank", "prob": 20, "count": [ 1, 2 ], "charges": 15000 } ] diff --git a/data/json/itemgroups/tools.json b/data/json/itemgroups/tools.json index 75bb6bf2d79ad..34aba00a9742e 100644 --- a/data/json/itemgroups/tools.json +++ b/data/json/itemgroups/tools.json @@ -118,7 +118,7 @@ [ "rake", 15 ], [ "rake_plastic", 25 ], [ "aluminum_stepladder", 5 ], - { "item": "misc_repairkit", "prob": 25, "charges-min": 0 }, + { "item": "misc_repairkit", "prob": 25 }, [ "saw", 60 ], { "item": "bow_saw", "prob": 50 }, { "group": "tools_common_small", "prob": 500 } @@ -861,7 +861,7 @@ [ "vac_mold", 10 ], [ "polycarbonate_sheet", 50 ], [ "duct_tape", 8 ], - { "item": "misc_repairkit", "prob": 15, "charges-min": 0 }, + { "item": "misc_repairkit", "prob": 15 }, { "item": "welder", "prob": 10 }, { "item": "welding_blanket", "prob": 10, "count": [ 0, 1 ] }, { diff --git a/data/json/items/tool/workshop.json b/data/json/items/tool/workshop.json index 8d299467bdb29..dcbd221025e1d 100644 --- a/data/json/items/tool/workshop.json +++ b/data/json/items/tool/workshop.json @@ -758,7 +758,6 @@ "symbol": ";", "color": "light_gray", "ammo": [ "tape" ], - "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "tape": 200 } } ], "charges_per_use": 5, "qualities": [ [ "CUT", 2 ], [ "CUT_FINE", 2 ], [ "AXE", 1 ], [ "SAW_W", 2 ], [ "BUTCHER", 7 ], [ "FABRIC_CUT", 1 ] ], "use_action": [ @@ -772,7 +771,7 @@ "move_cost": 1000 } ], - "flags": [ "ALLOWS_REMOTE_USE" ], + "flags": [ "ALLOWS_REMOTE_USE", "USES_NEARBY_AMMO" ], "melee_damage": { "bash": 2 } }, { diff --git a/data/json/npcs/NC_JUNK_SHOPKEEP.json b/data/json/npcs/NC_JUNK_SHOPKEEP.json index 0a045b0ed7f92..7767c2444525e 100644 --- a/data/json/npcs/NC_JUNK_SHOPKEEP.json +++ b/data/json/npcs/NC_JUNK_SHOPKEEP.json @@ -101,7 +101,7 @@ { "prob": 15, "group": "diazepam_bottle_plastic_pill_prescription_10" }, { "item": "small_repairkit", "prob": 20 }, { "item": "grapnel", "prob": 5 }, - { "item": "misc_repairkit", "prob": 15, "charges-min": 0 }, + { "item": "misc_repairkit", "prob": 15 }, { "group": "tools_toolbox", "prob": 20 }, { "item": "crowbar", "prob": 25 }, { "item": "machete", "prob": 25 }, diff --git a/data/json/npcs/godco/classes.json b/data/json/npcs/godco/classes.json index e7a7e09c11b1e..c70f77e23031d 100644 --- a/data/json/npcs/godco/classes.json +++ b/data/json/npcs/godco/classes.json @@ -1028,7 +1028,7 @@ "items": [ { "item": "rebreather", "prob": 3, "ammo-item": "rebreather_cartridge_o2" }, { "item": "UPS_off", "prob": 5, "charges": [ 0, 1000 ] }, - { "item": "misc_repairkit", "prob": 20, "charges-min": 25 }, + { "item": "misc_repairkit", "prob": 20 }, { "item": "bbgun", "prob": 15, "charges-min": 100 }, { "item": "bb", "prob": 10, "charges-min": 100 }, { "item": "tailors_kit", "prob": 15, "charges-min": 0 }, diff --git a/data/json/npcs/items_generic.json b/data/json/npcs/items_generic.json index 933265881c620..0259ba09ef61b 100644 --- a/data/json/npcs/items_generic.json +++ b/data/json/npcs/items_generic.json @@ -817,7 +817,7 @@ [ "meth", 5 ], [ "milk_powder", 3 ], [ "mintpatties", 3 ], - { "item": "misc_repairkit", "prob": 5, "charges-min": 0 }, + { "item": "misc_repairkit", "prob": 5 }, [ "ballistic_vest_esapi", 1 ], [ "molasses", 3 ], [ "money_strap_one", 10 ], diff --git a/data/json/vehicles/helicopters.json b/data/json/vehicles/helicopters.json index 12684fa7a1666..ab4e0245ac87b 100644 --- a/data/json/vehicles/helicopters.json +++ b/data/json/vehicles/helicopters.json @@ -1590,7 +1590,7 @@ { "x": -1, "y": 2, "chance": 7, "items": [ "wrench" ] }, { "x": -1, "y": 2, "chance": 5, "items": [ "duct_tape" ] }, { "x": -1, "y": 2, "chance": 7, "items": [ "mag_fieldrepair" ] }, - { "x": -1, "y": 2, "chance": 7, "items": [ "misc_repairkit" ], "ammo": 100 }, + { "x": -1, "y": 2, "chance": 7, "items": [ "misc_repairkit" ] }, { "x": -1, "y": 2, "chance": 5, "items": [ "two_way_radio" ] }, { "x": 0, "y": 2, "chance": 7, "items": [ "roadmap" ] }, { "x": 0, "y": 2, "chance": 7, "items": [ "pockknife" ] }, @@ -1711,7 +1711,7 @@ { "x": -1, "y": 2, "chance": 7, "items": [ "wrench" ] }, { "x": -1, "y": 2, "chance": 5, "items": [ "duct_tape" ] }, { "x": -1, "y": 2, "chance": 7, "items": [ "mag_fieldrepair" ] }, - { "x": -1, "y": 2, "chance": 7, "items": [ "misc_repairkit" ], "ammo": 100 }, + { "x": -1, "y": 2, "chance": 7, "items": [ "misc_repairkit" ] }, { "x": -1, "y": 2, "chance": 5, "items": [ "two_way_radio" ] }, { "x": 0, "y": 2, "chance": 7, "items": [ "roadmap" ] }, { "x": 0, "y": 2, "chance": 7, "items": [ "pockknife" ] }, @@ -1818,7 +1818,7 @@ { "x": -1, "y": 2, "chance": 7, "items": [ "wrench" ] }, { "x": -1, "y": 2, "chance": 5, "items": [ "duct_tape" ] }, { "x": -1, "y": 2, "chance": 7, "items": [ "mag_fieldrepair" ] }, - { "x": -1, "y": 2, "chance": 7, "items": [ "misc_repairkit" ], "ammo": 100 }, + { "x": -1, "y": 2, "chance": 7, "items": [ "misc_repairkit" ] }, { "x": -1, "y": 2, "chance": 5, "items": [ "two_way_radio" ] }, { "x": 0, "y": 2, "chance": 7, "items": [ "roadmap" ] }, { "x": 0, "y": 2, "chance": 7, "items": [ "pockknife" ] }, diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 8245893705163..7914eb54a8999 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -2564,10 +2564,15 @@ void repair_item_finish( player_activity *act, Character *you, bool no_menu ) } } - title += string_format( _( "Charges: %s/%s %s (%s per use)\n" ), - ammo_remaining, used_tool->ammo_capacity( current_ammo, true ), - ammo_name, - used_tool->ammo_required() ); + title += used_tool->is_tool() && used_tool->has_flag( flag_USES_NEARBY_AMMO ) + ? string_format( _( "Charges: %s %s (%s per use)\n" ), + ammo_remaining, + ammo_name, + used_tool->ammo_required() ) + : string_format( _( "Charges: %s/%s %s (%s per use)\n" ), + ammo_remaining, used_tool->ammo_capacity( current_ammo, true ), + ammo_name, + used_tool->ammo_required() ); title += string_format( _( "Materials available: %s\n" ), string_join( material_list, ", " ) ); title += string_format( _( "Skill used: %s (%s)\n" ), actor->used_skill.obj().name(), level ); diff --git a/src/flag.cpp b/src/flag.cpp index 4ead11c439f35..e06556bb6c867 100644 --- a/src/flag.cpp +++ b/src/flag.cpp @@ -350,6 +350,7 @@ const flag_id flag_UNRECOVERABLE( "UNRECOVERABLE" ); const flag_id flag_UNRESTRICTED( "UNRESTRICTED" ); const flag_id flag_URSINE_HONEY( "URSINE_HONEY" ); const flag_id flag_USES_BIONIC_POWER( "USES_BIONIC_POWER" ); +const flag_id flag_USES_NEARBY_AMMO( "USES_NEARBY_AMMO" ); const flag_id flag_USE_EAT_VERB( "USE_EAT_VERB" ); const flag_id flag_USE_PLAYER_ENERGY( "USE_PLAYER_ENERGY" ); const flag_id flag_USE_POWER_WHEN_HIT( "USE_POWER_WHEN_HIT" ); diff --git a/src/flag.h b/src/flag.h index 2c0c7a4827488..1543e28ded848 100644 --- a/src/flag.h +++ b/src/flag.h @@ -354,6 +354,7 @@ extern const flag_id flag_UNRECOVERABLE; extern const flag_id flag_UNRESTRICTED; extern const flag_id flag_URSINE_HONEY; extern const flag_id flag_USES_BIONIC_POWER; +extern const flag_id flag_USES_NEARBY_AMMO; extern const flag_id flag_USE_EAT_VERB; extern const flag_id flag_USE_PLAYER_ENERGY; extern const flag_id flag_USE_POWER_WHEN_HIT; diff --git a/src/item.cpp b/src/item.cpp index 8f829c7c8b835..0dd6636580e14 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -6890,7 +6890,9 @@ std::string item::display_name( unsigned int quantity ) const max_amount = mag->ammo_capacity( item_controller->find_template( mag->ammo_default() )->ammo->type ); } - + } else if( is_tool() && has_flag( flag_USES_NEARBY_AMMO ) ) { + show_amt = true; + amount = ammo_remaining( player_character.as_character() ); } else if( !ammo_types().empty() ) { // anything that can be reloaded including tools, magazines, guns and auxiliary gunmods // but excluding bows etc., which have ammo, but can't be reloaded @@ -10677,6 +10679,14 @@ int item::shots_remaining( const Character *carrier ) const int item::ammo_remaining( const std::set &ammo, const Character *carrier, const bool include_linked ) const { + const bool is_tool_with_carrier = carrier != nullptr && type->tool; + + if( is_tool_with_carrier && has_flag( flag_USES_NEARBY_AMMO ) && !ammo.empty() ) { + const inventory &crafting_inventory = carrier->crafting_inventory(); + const ammotype &a = *ammo.begin(); + return crafting_inventory.charges_of( a->default_ammotype(), INT_MAX ); + } + int ret = 0; // Magazine in the item @@ -10722,7 +10732,7 @@ int item::ammo_remaining( const std::set &ammo, const Character *carri // UPS/bionic power can replace ammo requirement. // Only for tools. Guns should always use energy_drain for electricity use. - if( carrier != nullptr && type->tool ) { + if( is_tool_with_carrier ) { if( has_flag( flag_USES_BIONIC_POWER ) ) { ret += units::to_kilojoule( carrier->get_power_level() ); } @@ -10879,6 +10889,23 @@ int item::ammo_consume( int qty, const tripoint &pos, Character *carrier ) return 0; } const int wanted_qty = qty; + const bool is_tool_with_carrier = carrier != nullptr && is_tool(); + + if( is_tool_with_carrier && has_flag( flag_USES_NEARBY_AMMO ) ) { + const ammotype ammo = ammo_type(); + if( !ammo.is_null() ) { + const inventory& carrier_inventory = carrier->crafting_inventory(); + itype_id ammo_type = ammo->default_ammotype(); + const int charges_avalable = carrier_inventory.charges_of( ammo_type, INT_MAX ); + + qty = std::min( wanted_qty, charges_avalable ); + + std::vector components; + components.emplace_back( ammo_type, qty ); + carrier->consume_items( components, 1 ); + return wanted_qty - qty; + } + } // Consume power from appliances/vehicles connected with cables if( has_link_data() ) { @@ -10914,10 +10941,11 @@ int item::ammo_consume( int qty, const tripoint &pos, Character *carrier ) qty -= charg_used; } + bool is_off_grid_powered = has_flag( flag_USE_UPS ) || has_flag( flag_USES_BIONIC_POWER ); + // Modded tools can consume UPS/bionic energy instead of ammo. // Guns handle energy in energy_consume() - if( carrier != nullptr && type->tool && - ( has_flag( flag_USE_UPS ) || has_flag( flag_USES_BIONIC_POWER ) ) ) { + if( is_tool_with_carrier && is_off_grid_powered ) { units::energy wanted_energy = units::from_kilojoule( static_cast( qty ) ); if( has_flag( flag_USE_UPS ) ) { @@ -11021,6 +11049,9 @@ itype_id item::ammo_current() const if( ammo ) { return ammo->get_id(); } + if( is_tool() && has_flag( flag_USES_NEARBY_AMMO ) ) { + return ammo_default(); + } return itype_id::NULL_ID(); } @@ -11064,6 +11095,11 @@ std::set item::ammo_types( bool conversion ) const if( is_gun() ) { return type->gun->ammo; } + + if( is_tool() && has_flag( flag_USES_NEARBY_AMMO ) ) { + return type->tool->ammo_id; + } + return contents.ammo_types(); } @@ -11072,6 +11108,14 @@ ammotype item::ammo_type() const if( is_ammo() ) { return type->ammo->type; } + + if( is_tool() && has_flag( flag_USES_NEARBY_AMMO ) ) { + const std::set ammo_type_choices = ammo_types(); + if( !ammo_type_choices.empty() ) { + return *ammo_type_choices.begin(); + } + } + return ammotype::NULL_ID(); }