From 9f1d9ccf94b175615065ce9d9c6bad04d8f4acfa Mon Sep 17 00:00:00 2001 From: ehughsbaird <44244083+ehughsbaird@users.noreply.github.com> Date: Thu, 19 Oct 2023 22:02:47 -0700 Subject: [PATCH] Revamp foldable solar panels (#68705) * Add deploy_appliance iuse actor Enabled activating an item to place an appliance. * vpart: allow removal into different item Allow vehicle parts to have a different base item than the item they are removed to. This allows having fake items for appliances that are not the same item they remove to. * Make folding solar panel a camping solar panel Folding solar panels seem to be normal solar panels, modified in some way to fold (add hinges?). Outside of spacecraft, I'm not sure such things exist in real life, and this camping solar panel is probably a lot more familiar to most people. Remove the recipe for the folding solar panel, and add some spawns in the camping ground (and add it to some large bugout bags). Make it deployable as an appliance, so it can be used on the go to charge devices. It's done in a bit of a hacky way due to the requirement for a battery, but I think it's fine. It probably shouldn't really be installable on vehicles, as it's got too large of a surface area (and so is better than a normal vehicle solar panel), but I didn't want to cause problems with existing vehicles. Since it doesn't have components any more, I've made it break into an XX damaged folding solar panel. * Make folding_solar_panel_v2 a solar suitcase Instead of not-spawning, have turn the solar_panel_v2 into a solar suitcase. Add some spawns to vehicles, and allow it to be deployed as an appliance for charging items. Still a bit hacky, like the smaller folding solar panel. Recipe was also removed, though it is potentially reasonable to craft a solar suitcase. I just don't know enough about it to say the recipe is still accurate. * Remove vehicle folding solar panels These are voluminous enough that it doesn't make sense to have a whole lot on a folding vehicle, and they don't deliver that much juice either. It just makes more sense to carry around the folding panels and deploy them. Also, these are too big (surface area) to fit on a vehicle tile. --- .../furniture_and_terrain/appliances.json | 29 +++++++ data/json/item_actions.json | 5 ++ data/json/itemgroups/activities_hobbies.json | 1 + data/json/itemgroups/stashes.json | 10 ++- .../itemgroups/vehicles_fuel_related.json | 2 + data/json/items/vehicle/solar.json | 64 ++++++++++++-- .../obsoletion/migration_vehicle_parts.json | 10 +++ data/json/recipes/other/power_supplies.json | 42 --------- data/json/vehicleparts/vehicle_parts.json | 21 ----- doc/JSON_INFO.md | 9 ++ src/item.cpp | 2 +- src/item_factory.cpp | 1 + src/iuse_actor.cpp | 87 ++++++++++++++----- src/iuse_actor.h | 17 ++++ src/veh_interact.cpp | 2 +- src/veh_type.cpp | 1 + src/veh_type.h | 3 + src/vehicle.cpp | 9 ++ src/vehicle.h | 6 ++ 19 files changed, 224 insertions(+), 97 deletions(-) diff --git a/data/json/furniture_and_terrain/appliances.json b/data/json/furniture_and_terrain/appliances.json index 266da6464d1e2..00373bd1e7c84 100644 --- a/data/json/furniture_and_terrain/appliances.json +++ b/data/json/furniture_and_terrain/appliances.json @@ -671,6 +671,35 @@ "flags": [ "APPLIANCE", "OBSTACLE", "WALL_MOUNTED", "WIRING" ], "variants": [ { "symbols": "_", "symbols_broken": "/" } ] }, + { + "type": "vehicle_part", + "id": "ap_folding_solar_panel", + "name": { "str": "deployed folding solar panel" }, + "flags": [ "SOLAR_PANEL", "OBSTACLE", "APPLIANCE" ], + "description": "This folding solar panel has been unfolded, and it is ready to charge connected devices, if the sun is out.", + "copy-from": "solar_panel", + "color": "light_blue", + "broken_color": "light_gray", + "proportional": { "durability": 0.5 }, + "epower": "120 W", + "requirements": { "removal": { "time": "5 s" } }, + "breaks_into": [ { "item": "folding_solar_panel", "damage": [ 5, 5 ] } ], + "remove_as": "folding_solar_panel", + "item": "folding_solar_panel_deployed" + }, + { + "type": "vehicle_part", + "id": "ap_folding_solar_panel_v2", + "flags": [ "SOLAR_PANEL", "OBSTACLE", "APPLIANCE" ], + "name": { "str": "deployed solar suitcase" }, + "description": "This solar suitcase has been unpacked and is ready to supply power.", + "copy-from": "ap_folding_solar_panel", + "epower": "200 W", + "breaks_into": [ { "item": "folding_solar_panel_v2", "damage": [ 5, 5 ] } ], + "requirements": { "removal": { "time": "1 m" } }, + "remove_as": "folding_solar_panel_v2", + "item": "folding_solar_panel_v2_deployed" + }, { "type": "vehicle_part", "id": "ap_solar_panel", diff --git a/data/json/item_actions.json b/data/json/item_actions.json index 94ab4a721a806..b67b5e12e11ee 100644 --- a/data/json/item_actions.json +++ b/data/json/item_actions.json @@ -35,6 +35,11 @@ "id": "deploy_furn", "name": { "str": "Deploy item" } }, + { + "type": "item_action", + "id": "deploy_appliance", + "name": { "str": "Deploy item" } + }, { "type": "item_action", "id": "CROWBAR_WEAK", diff --git a/data/json/itemgroups/activities_hobbies.json b/data/json/itemgroups/activities_hobbies.json index 4ef5b9b3775cf..c1c49afae7155 100644 --- a/data/json/itemgroups/activities_hobbies.json +++ b/data/json/itemgroups/activities_hobbies.json @@ -257,6 +257,7 @@ [ "waffleiron", 25 ], [ "binoculars", 20 ], [ "firecracker_pack", 5 ], + [ "folding_solar_panel", 3 ], { "item": "hotplate", "prob": 10, "charges": [ 0, 500 ] }, { "item": "popcan_stove", "prob": 10, "charges": [ 0, 500 ] }, { "item": "coffeemaker", "prob": 5, "charges": [ 0, 500 ] }, diff --git a/data/json/itemgroups/stashes.json b/data/json/itemgroups/stashes.json index 05bd5fc3b5c34..0e45867144918 100644 --- a/data/json/itemgroups/stashes.json +++ b/data/json/itemgroups/stashes.json @@ -159,7 +159,8 @@ { "group": "bugout_food", "prob": 50, "count": [ 1, 3 ] }, { "group": "bugout_water", "prob": 50, "count": [ 1, 3 ] }, { "group": "bugout_extras", "prob": 100, "count": [ 2, 6 ] }, - { "group": "civilian_armor", "count": 2, "prob": 35 } + { "group": "civilian_armor", "count": 2, "prob": 35 }, + { "group": "bugout_large_extras", "prob": 40 } ] }, { @@ -261,6 +262,13 @@ { "group": "bugout_bad_pack", "prob": 100 } ] }, + { + "type": "item_group", + "id": "bugout_large_extras", + "subtype": "distribution", + "//": "Large items of questionable use in a bugout bag.", + "entries": [ { "item": "folding_solar_panel" } ] + }, { "type": "item_group", "id": "bugout_bad_pack", diff --git a/data/json/itemgroups/vehicles_fuel_related.json b/data/json/itemgroups/vehicles_fuel_related.json index a7c6b1dd0b62c..a456f756f3f25 100644 --- a/data/json/itemgroups/vehicles_fuel_related.json +++ b/data/json/itemgroups/vehicles_fuel_related.json @@ -124,6 +124,7 @@ [ "hose", 50 ], [ "jumper_cable", 30 ], [ "hand_pump", 30 ], + [ "folding_solar_panel_v2", 2 ], { "group": "bugout_bag", "prob": 3 } ] }, @@ -160,6 +161,7 @@ [ "sunglasses", 20 ], [ "knife_swissarmy", 10 ], [ "eclipse_glasses", 1 ], + [ "folding_solar_panel_v2", 2 ], [ "thermos", 20 ] ] }, diff --git a/data/json/items/vehicle/solar.json b/data/json/items/vehicle/solar.json index 06816285c519c..e258256a5ac53 100644 --- a/data/json/items/vehicle/solar.json +++ b/data/json/items/vehicle/solar.json @@ -35,19 +35,67 @@ "type": "GENERIC", "copy-from": "solar_panel", "id": "folding_solar_panel", - "name": { "str": "collapsible solar array" }, - "description": "An electronic device that can convert solar radiation into electric power, mounted on a folding frame. This one is a common, inexpensive type made with polycrystalline silicon cells.", - "price": 120000, - "price_postapoc": 1500 + "name": { "str": "folding solar panel" }, + "description": "This \"little\" solar panel folds up to carry around, in case you need to charge anything on the go. Its small size means in might take quite some time to charge, however.", + "//": [ + "Based on https://www.bluettipower.com/products/bluetti-pv120-120w-solar-panel", + "53cmx47cmx~3cm = 7.5L (assuming it's folded). Weighs in at 5.7kg", + "'up to' 23.4% efficiency, max power = 120W (~20V ~6A)", + "surface area is 53cmx165cm = 0.8754m^2. 'solar_panel' above is 0.25m^2", + "From relative surface area, we get 175W. So 120W seems an alright figure" + ], + "weight": "5700 g", + "volume": "7473 ml", + "longest_side": "53 cm", + "use_action": { "type": "deploy_appliance", "base": "folding_solar_panel_deployed" }, + "price": 28000, + "price_postapoc": 500 + }, + { + "type": "MAGAZINE", + "copy-from": "folding_solar_panel", + "id": "folding_solar_panel_deployed", + "name": { "str": "deployed folding solar panel" }, + "//": [ + "Deployed version of the above. Shouldn't spawn in game.", + "Has a little hacky battery pocket so it can charge phones and the like" + ], + "ammo_type": [ "battery" ], + "capacity": 1, + "flags": [ "NO_SALVAGE", "NO_UNLOAD", "NO_RELOAD", "RECHARGE" ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "battery": 1 } } ] }, { "type": "GENERIC", "copy-from": "folding_solar_panel", "id": "folding_solar_panel_v2", - "name": { "str": "advanced collapsible solar array" }, - "description": "An electronic device that can convert solar radiation into electric power, mounted on a folding frame. This one is a high-performance type made with monocrystalline silicon cells.", - "price": 220000, - "price_postapoc": 3500 + "name": { "str": "solar suitcase" }, + "description": "A large, ready-to-deploy set of solar panels, designed for portable off-the-grid use.", + "//": [ + "Based on https://www.renogy.com/200-watt-12-volt-monocrystalline-foldable-solar-suitcase", + "26.4x32.5x2.8 inches is 39.4L, 38.6lbs = 17.5kg", + "Surface area 0.554m^2, listed 200W. Half of solar_panel_v2 for half surface area" + ], + "weight": "17500 g", + "volume": "39400 ml", + "longest_side": "83 cm", + "use_action": { "type": "deploy_appliance", "base": "folding_solar_panel_v2_deployed" }, + "price": 32000, + "price_postapoc": 2000 + }, + { + "type": "MAGAZINE", + "copy-from": "folding_solar_panel_v2", + "id": "folding_solar_panel_v2_deployed", + "name": { "str": "deployed solar suitcase" }, + "//": [ + "Deployed version of the above. Shouldn't spawn in game.", + "Has a little hacky battery pocket so it can charge phones and the like" + ], + "ammo_type": [ "battery" ], + "capacity": 1, + "flags": [ "NO_SALVAGE", "NO_UNLOAD", "NO_RELOAD", "RECHARGE" ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "battery": 1 } } ] }, { "type": "GENERIC", diff --git a/data/json/obsoletion/migration_vehicle_parts.json b/data/json/obsoletion/migration_vehicle_parts.json index 1ec51eec0ce4a..5dc0ca444756a 100644 --- a/data/json/obsoletion/migration_vehicle_parts.json +++ b/data/json/obsoletion/migration_vehicle_parts.json @@ -71,6 +71,16 @@ "to": "seat", "variant": "windshield_front" }, + { + "type": "vehicle_part_migration", + "from": "foldable_solar_panel", + "to": "solar_panel" + }, + { + "type": "vehicle_part_migration", + "from": "advanced_foldable_solar_panel", + "to": "solar_panel_v2" + }, { "type": "vehicle_part_migration", "from": "seat_swivel_chair", diff --git a/data/json/recipes/other/power_supplies.json b/data/json/recipes/other/power_supplies.json index 97c422df36698..868359618fe20 100644 --- a/data/json/recipes/other/power_supplies.json +++ b/data/json/recipes/other/power_supplies.json @@ -21,48 +21,6 @@ "qualities": [ { "id": "SAW_M", "level": 1 } ], "components": [ [ [ "solar_panel", 1 ] ], [ [ "reinforced_glass_pane", 1 ] ], [ [ "scrap", 1 ] ] ] }, - { - "type": "recipe", - "activity_level": "MODERATE_EXERCISE", - "result": "folding_solar_panel", - "category": "CC_OTHER", - "subcategory": "CSC_OTHER_PARTS", - "skill_used": "fabrication", - "difficulty": 4, - "time": "2 h", - "reversible": true, - "autolearn": true, - "//": "30cm weld", - "using": [ [ "welding_standard", 30 ] ], - "proficiencies": [ - { "proficiency": "prof_metalworking" }, - { "proficiency": "prof_welding_basic", "skill_penalty": 0.5 }, - { "proficiency": "prof_welding" } - ], - "qualities": [ { "id": "SAW_M", "level": 1 } ], - "components": [ [ [ "solar_panel", 1 ] ], [ [ "scrap", 2 ] ], [ [ "wire", 2 ] ], [ [ "nuts_bolts", 8 ] ] ] - }, - { - "type": "recipe", - "activity_level": "MODERATE_EXERCISE", - "result": "folding_solar_panel_v2", - "category": "CC_OTHER", - "subcategory": "CSC_OTHER_PARTS", - "skill_used": "fabrication", - "difficulty": 4, - "time": "2 h", - "reversible": true, - "autolearn": true, - "//": "30cm weld", - "using": [ [ "welding_standard", 30 ] ], - "proficiencies": [ - { "proficiency": "prof_metalworking" }, - { "proficiency": "prof_welding_basic", "skill_penalty": 0.5 }, - { "proficiency": "prof_welding" } - ], - "qualities": [ { "id": "SAW_M", "level": 1 } ], - "components": [ [ [ "solar_panel_v2", 1 ] ], [ [ "scrap", 2 ] ], [ [ "wire", 2 ] ], [ [ "nuts_bolts", 8 ] ] ] - }, { "type": "recipe", "activity_level": "MODERATE_EXERCISE", diff --git a/data/json/vehicleparts/vehicle_parts.json b/data/json/vehicleparts/vehicle_parts.json index a732e6ed581b3..ca7ded6fef84a 100644 --- a/data/json/vehicleparts/vehicle_parts.json +++ b/data/json/vehicleparts/vehicle_parts.json @@ -1758,27 +1758,6 @@ "damage_reduction": { "all": 9 }, "variants": [ { "symbols": "Y", "symbols_broken": "X" } ] }, - { - "type": "vehicle_part", - "id": "foldable_solar_panel", - "copy-from": "solar_panel", - "name": { "str": "collapsible solar array" }, - "color": "light_blue", - "broken_color": "light_gray", - "proportional": { "epower": 0.68, "durability": 0.5 }, - "folded_volume": "2 L", - "description": "A small array of solar panels designed to be able to fold into one another.", - "item": "folding_solar_panel" - }, - { - "type": "vehicle_part", - "id": "advanced_foldable_solar_panel", - "copy-from": "foldable_solar_panel", - "name": { "str": "advanced collapsible solar array" }, - "proportional": { "epower": 2 }, - "description": "A small array of high-performance solar panels designed to be able to fold into one another.", - "item": "folding_solar_panel_v2" - }, { "type": "vehicle_part", "id": "reinforced_solar_panel", diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 55c4494b22139..9838289b69d00 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -2863,6 +2863,7 @@ Vehicle components when installed on a vehicle. // When sun is at 90 degrees the panel produces the full epower. "item": "wheel", // The item used to install this part, and the item obtained when // removing this part. +"remove_as": "solar_panel", // Overrides "item", item returned when removing this part. "difficulty": 4, // Your mechanics skill must be at least this level to install this part "breaks_into" : [ // When the vehicle part is destroyed, items from this item group // (see ITEM_SPAWN.md) will be spawned around the part on the ground. @@ -4291,6 +4292,14 @@ The contents of use_action fields can either be a string indicating a built-in f "ELECTRICAL_DEVICES" // "ELECTRICAL_DEVICES" is a special keyword that lets this cable extend all electrical devices that have link_up actions. ] }, +"use_action" : { + "type" : "deploy_furn", + "furn_type" : "f_foo", // What furniture this item will be transmuted into +}, +"use_action" : { + "type" : "deploy_appliance", + "base" : "item_id", // Base item of the appliance this item will turn into +}, "use_action" : { "type" : "delayed_transform", // Like transform, but it will only transform when the item has a certain age "transform_age" : 600, // The minimal age of the item. Items that are younger wont transform. In turns (60 turns = 1 minute) diff --git a/src/item.cpp b/src/item.cpp index bcd35df584a78..a59761605ff63 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -9885,7 +9885,7 @@ bool item::is_emissive() const bool item::is_deployable() const { - return type->can_use( "deploy_furn" ); + return type->can_use( "deploy_furn" ) || type->can_use( "deploy_appliance" ); } bool item::is_tool() const diff --git a/src/item_factory.cpp b/src/item_factory.cpp index d82208bb98f83..d452bdfcdea4b 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -1832,6 +1832,7 @@ void Item_factory::init() add_actor( std::make_unique() ); add_actor( std::make_unique() ); add_actor( std::make_unique() ); + add_actor( std::make_unique() ); add_actor( std::make_unique() ); add_actor( std::make_unique() ); add_actor( std::make_unique() ); diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index d8e9a2821b4f4..55500e1978d01 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -84,6 +84,7 @@ #include "ui.h" #include "units_utility.h" #include "value_ptr.h" +#include "veh_appliance.h" #include "veh_type.h" #include "vehicle.h" #include "vehicle_selector.h" @@ -1043,25 +1044,24 @@ void deploy_furn_actor::load( const JsonObject &obj ) furn_type = furn_str_id( obj.get_string( "furn_type" ) ); } -std::optional deploy_furn_actor::use( Character *p, item &it, - const tripoint &pos ) const + +static ret_val check_deploy_square( Character *p, item &it, const tripoint &pos ) { if( p->cant_do_mounted() ) { - return std::nullopt; + return ret_val::make_failure( pos ); } tripoint pnt = pos; if( pos == p->pos() ) { if( const std::optional pnt_ = choose_adjacent( _( "Deploy where?" ) ) ) { pnt = *pnt_; } else { - return std::nullopt; + return ret_val::make_failure( pos ); } } if( pnt == p->pos() ) { - p->add_msg_if_player( m_info, - _( "You attempt to become one with the furniture. It doesn't work." ) ); - return std::nullopt; + return ret_val::make_failure( pos, + _( "You attempt to become one with the %s. It doesn't work." ), it.tname() ); } map &here = get_map(); @@ -1069,20 +1069,19 @@ std::optional deploy_furn_actor::use( Character *p, item &it, if( veh_there.has_value() ) { // TODO: check for protrusion+short furniture, wheels+tiny furniture, NOCOLLIDE flag, etc. // and/or integrate furniture deployment with construction (which already seems to perform these checks sometimes?) - p->add_msg_if_player( m_info, _( "The space under %s is too cramped to deploy a %s in." ), - veh_there.value().vehicle().disp_name(), it.tname() ); - return std::nullopt; + return ret_val::make_failure( pos, + _( "The space under %s is too cramped to deploy a %s in." ), + veh_there.value().vehicle().disp_name(), it.tname() ); } // For example: dirt = 2, long grass = 3 if( here.move_cost( pnt ) != 2 && here.move_cost( pnt ) != 3 ) { - p->add_msg_if_player( m_info, _( "You can't deploy a %s there." ), it.tname() ); - return std::nullopt; + return ret_val::make_failure( pos, _( "You can't deploy a %s there." ), it.tname() ); } if( here.has_furn( pnt ) ) { - p->add_msg_if_player( m_info, _( "There is already furniture at that location." ) ); - return std::nullopt; + return ret_val::make_failure( pos, _( "The %s at that location is blocking the %s." ), + here.furnname( pnt ), it.tname() ); } if( here.has_items( pnt ) ) { @@ -1091,8 +1090,8 @@ std::optional deploy_furn_actor::use( Character *p, item &it, map &temp = get_map(); for( item &i : temp.i_at( pnt ) ) { if( !i.is_owned_by( *p, true ) ) { - p->add_msg_if_player( m_info, _( "You can't deploy furniture on other people's belongings!" ) ); - return std::nullopt; + return ret_val::make_failure( pos, + _( "You can't deploy the %s on other people's belongings!" ), it.tname() ); } } @@ -1101,19 +1100,61 @@ std::optional deploy_furn_actor::use( Character *p, item &it, if( here.terrain_moppable( tripoint_bub_ms( pnt ) ) ) { if( get_avatar().crafting_inventory().has_quality( qual_MOP ) ) { here.mop_spills( tripoint_bub_ms( pnt ) ); - p->add_msg_if_player( m_info, - _( "You mopped up the spill with a nearby mop when deploying furniture." ) ); + p->add_msg_if_player( m_info, _( "You mopped up the spill with a nearby mop when deploying a %s." ), + it.tname() ); p->moves -= 15; } else { - p->add_msg_if_player( m_info, - _( "You need a mop to clean up liquids before deploying furniture." ) ); - return std::nullopt; + return ret_val::make_failure( pos, + _( "You need a mop to clean up liquids before deploying the %s." ), it.tname() ); } } } - here.furn_set( pnt, furn_type ); - it.spill_contents( pnt ); + return ret_val::make_success( pnt ); +} + +std::optional deploy_furn_actor::use( Character *p, item &it, + const tripoint &pos ) const +{ + ret_val suitable = check_deploy_square( p, it, pos ); + if( !suitable.success() ) { + p->add_msg_if_player( m_info, suitable.str() ); + return std::nullopt; + } + + get_map().furn_set( suitable.value(), furn_type ); + it.spill_contents( suitable.value() ); + p->mod_moves( -to_moves( 2_seconds ) ); + return 1; +} + +std::unique_ptr deploy_appliance_actor::clone() const +{ + return std::make_unique( *this ); +} + +void deploy_appliance_actor::info( const item &, std::vector &dump ) const +{ + dump.emplace_back( "DESCRIPTION", + string_format( _( "Can be activated to deploy as an appliance (%s)." ), + vpart_appliance_from_item( appliance_base )->name() ) ); +} + +void deploy_appliance_actor::load( const JsonObject &obj ) +{ + mandatory( obj, false, "base", appliance_base ); +} + +std::optional deploy_appliance_actor::use( Character *p, item &it, const tripoint &pos ) const +{ + ret_val suitable = check_deploy_square( p, it, pos ); + if( !suitable.success() ) { + p->add_msg_if_player( m_info, suitable.str() ); + return std::nullopt; + } + + place_appliance( suitable.value(), vpart_appliance_from_item( appliance_base ) ); + it.spill_contents( suitable.value() ); p->mod_moves( -to_moves( 2_seconds ) ); return 1; } diff --git a/src/iuse_actor.h b/src/iuse_actor.h index 0a5be8fd77fcf..fb4d01dcb5614 100644 --- a/src/iuse_actor.h +++ b/src/iuse_actor.h @@ -404,6 +404,23 @@ class deploy_furn_actor : public iuse_actor void info( const item &, std::vector & ) const override; }; +/** + * Deployable appliances from items + */ +class deploy_appliance_actor : public iuse_actor +{ + public: + itype_id appliance_base; + + deploy_appliance_actor() : iuse_actor( "deploy_appliance" ) {} + ~deploy_appliance_actor() override = default; + + void load( const JsonObject &obj ) override; + std::optional use( Character *, item &, const tripoint & ) const override; + std::unique_ptr clone() const override; + void info( const item &, std::vector & ) const override; +}; + /** * Reveals specific things on the overmap. */ diff --git a/src/veh_interact.cpp b/src/veh_interact.cpp index 05bff818f69cf..de47d2ca725c4 100644 --- a/src/veh_interact.cpp +++ b/src/veh_interact.cpp @@ -3318,7 +3318,7 @@ void veh_interact::complete_vehicle( Character &you ) item_group::ItemList pieces = vp.pieces_for_broken_part(); resulting_items.insert( resulting_items.end(), pieces.begin(), pieces.end() ); } else { - resulting_items.push_back( veh.part_to_item( vp ) ); + resulting_items.push_back( veh.removed_part( vp ) ); // damage reduces chance of success (0.8^damage_level) const double component_success_chance = std::pow( 0.8, vp.damage_level() ); diff --git a/src/veh_type.cpp b/src/veh_type.cpp index eb2427c3316a8..40da63a8d0acb 100644 --- a/src/veh_type.cpp +++ b/src/veh_type.cpp @@ -261,6 +261,7 @@ void vpart_info::load( const JsonObject &jo, const std::string &src ) assign( jo, "name", name_, strict ); assign( jo, "item", base_item, strict ); + assign( jo, "remove_as", removed_item, strict ); assign( jo, "location", location, strict ); assign( jo, "durability", durability, strict ); assign( jo, "damage_modifier", dmg_mod, strict ); diff --git a/src/veh_type.h b/src/veh_type.h index 51b4842f021b0..fc24fdd026462 100644 --- a/src/veh_type.h +++ b/src/veh_type.h @@ -392,6 +392,9 @@ class vpart_info /** base item for this part */ itype_id base_item; + /** item it should be removed as */ + std::optional removed_item; + /** What slot of the vehicle tile does this part occupy? */ std::string location; diff --git a/src/vehicle.cpp b/src/vehicle.cpp index e58a18e6733fa..58bb1130b5cfb 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -8066,6 +8066,15 @@ item vehicle::part_to_item( const vehicle_part &vp ) const return tmp; } +item vehicle::removed_part( const vehicle_part &vp ) const +{ + item ret = part_to_item( vp ); + if( vp.info().removed_item ) { + ret.convert( *vp.info().removed_item ); + } + return ret; +} + bool vehicle::refresh_zones() { if( zones_dirty ) { diff --git a/src/vehicle.h b/src/vehicle.h index bab16b55cf90a..ee45c4e0d6ef1 100644 --- a/src/vehicle.h +++ b/src/vehicle.h @@ -2123,6 +2123,12 @@ class vehicle */ item part_to_item( const vehicle_part &vp ) const; + /** + * If the vehicle part has an item it is removed as, transform the item + * to the item it is removed_as + */ + item removed_part( const vehicle_part &vp ) const; + // Updates the internal precalculated mount offsets after the vehicle has been displaced // used in map::displace_vehicle() std::set advance_precalc_mounts( const point &new_pos, const tripoint &src,