From d7af7fc8a01da5a732782c239a2a8bcecb399a53 Mon Sep 17 00:00:00 2001 From: Fris0uman <41293484+Fris0uman@users.noreply.github.com> Date: Mon, 25 Oct 2021 22:30:21 +0200 Subject: [PATCH] Basic Appliance implementation (#51286) * Implement APPLIANCE flag * Don't show non appliance parts when trying to install on a powergrid * Don't show vehicle information on a power grid * Add json to be able to start power grid * Don't show the vehicle menu on appliances * Simplify construction code * Can place place appliances from contruction menu, fridge exemple * Tweak appliance interact code * Add a fridge appliance * Appliance tag on vehicle * Missing definition of has_tag and add_tag * Can plug aplliance into nearby vehicle * Don't drop the power cord * Name appliance with the name of the part installed --- data/json/construction.json | 11 ++++++ data/json/construction_category.json | 5 +++ data/json/construction_group.json | 5 +++ data/json/flags.json | 8 ++++ data/json/items/appliances.json | 44 ++++++++++++++++++++++ data/json/recipes/recipe_vehicle.json | 24 ++++++++++++ data/json/vehicleparts/appliances.json | 52 ++++++++++++++++++++++++++ data/json/vehicleparts/vp_flags.json | 4 ++ src/construction.cpp | 21 +++++++++++ src/iuse.cpp | 7 +++- src/veh_interact.cpp | 6 ++- src/veh_type.cpp | 1 + src/veh_type.h | 1 + src/vehicle.cpp | 17 +++++++-- src/vehicle.h | 5 +++ src/vehicle_use.cpp | 33 ++++++++++++++-- 16 files changed, 235 insertions(+), 9 deletions(-) create mode 100644 data/json/items/appliances.json create mode 100644 data/json/vehicleparts/appliances.json diff --git a/data/json/construction.json b/data/json/construction.json index 83ede539d4380..da438eeb783c2 100644 --- a/data/json/construction.json +++ b/data/json/construction.json @@ -2808,6 +2808,17 @@ "pre_special": "check_empty", "post_terrain": "f_barricade_road" }, + { + "type": "construction", + "id": "app_fridge", + "group": "place_fridge", + "category": "APPLIANCE", + "required_skills": [ [ "fabrication", 0 ] ], + "time": "5 m", + "components": [ [ [ "fridge", 1 ] ] ], + "pre_special": "check_empty", + "post_special": "done_appliance" + }, { "type": "construction", "id": "constr_pontoon_dp", diff --git a/data/json/construction_category.json b/data/json/construction_category.json index e0745cec3302d..41995110d4cee 100644 --- a/data/json/construction_category.json +++ b/data/json/construction_category.json @@ -5,6 +5,11 @@ "id": "ALL", "name": "All" }, + { + "type": "construction_category", + "id": "APPLIANCE", + "name": "Appliances" + }, { "type": "construction_category", "id": "CONSTRUCT", diff --git a/data/json/construction_group.json b/data/json/construction_group.json index 00bd0d2b53681..2f01c25e2140b 100644 --- a/data/json/construction_group.json +++ b/data/json/construction_group.json @@ -1029,6 +1029,11 @@ "id": "paint_wall_yellow", "name": "Paint Wall Yellow" }, + { + "type": "construction_group", + "id": "place_fridge", + "name": "Place Fridge" + }, { "type": "construction_group", "id": "place_forge", diff --git a/data/json/flags.json b/data/json/flags.json index 605060505987c..a738a18515db5 100644 --- a/data/json/flags.json +++ b/data/json/flags.json @@ -985,6 +985,10 @@ "id": "ALWAYS_TWOHAND", "type": "json_flag" }, + { + "id": "APPLIANCE", + "type": "json_flag" + }, { "id": "BIPOD", "type": "json_flag" @@ -1358,6 +1362,10 @@ "id": "POWERED", "type": "json_flag" }, + { + "id": "POWER_CORD", + "type": "json_flag" + }, { "id": "PROCESSING", "type": "json_flag" diff --git a/data/json/items/appliances.json b/data/json/items/appliances.json new file mode 100644 index 0000000000000..cc6b393fa73fa --- /dev/null +++ b/data/json/items/appliances.json @@ -0,0 +1,44 @@ +[ + { + "type": "GENERIC", + "id": "fridge", + "looks_like": "minifridge", + "symbol": "F", + "color": "light_blue", + "name": { "str": "fridge" }, + "description": "A fridge for keeping food cool. Provides some insulation from outside weather.", + "longest_side": "1700 mm", + "insulation": 10, + "volume": "800 L", + "weight": "70 kg", + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "rigid": true, + "watertight": true, + "max_contains_volume": "700 L", + "max_contains_weight": "400 kg" + } + ] + }, + { + "type": "TOOL", + "id": "power_cord", + "name": { "str": "power cord" }, + "description": "A power cord, like you've seen many times before: it's a short multi-stranded copper cord with power outlet at the end.", + "to_hit": 1, + "color": "dark_gray", + "symbol": "&", + "material": [ "steel", "plastic" ], + "volume": "500 ml", + "weight": "75 g", + "bashing": 2, + "category": "tools", + "price": 1, + "price_postapoc": 100, + "max_charges": 3, + "initial_charges": 3, + "use_action": [ "CABLE_ATTACH" ], + "flags": [ "CABLE_SPOOL", "POWER_CORD" ] + } +] diff --git a/data/json/recipes/recipe_vehicle.json b/data/json/recipes/recipe_vehicle.json index 6fc3b6e6fd97d..d35eaaf59ba86 100644 --- a/data/json/recipes/recipe_vehicle.json +++ b/data/json/recipes/recipe_vehicle.json @@ -444,6 +444,30 @@ [ [ "plastic_chunk", 8 ] ] ] }, + { + "result": "fridge", + "type": "recipe", + "activity_level": "MODERATE_EXERCISE", + "copy-from": "minifridge", + "skills_required": [ "fabrication", 4 ], + "proficiencies": [ { "proficiency": "prof_plasticworking", "required": false, "time_multiplier": 1.1, "learning_time_multiplier": 0.1 } ], + "qualities": [ + { "id": "HAMMER", "level": 2 }, + { "id": "SAW_M", "level": 1 }, + { "id": "DRILL", "level": 1 }, + { "id": "SCREW", "level": 1 }, + { "id": "WRENCH", "level": 1 } + ], + "components": [ + [ [ "sheet_metal", 20 ] ], + [ [ "condensor_coil", 1 ] ], + [ [ "evaporator_coil", 1 ] ], + [ [ "thermostat", 1 ] ], + [ [ "motor_small", 1 ] ], + [ [ "refrigerant_tank", 1 ] ], + [ [ "plastic_chunk", 16 ] ] + ] + }, { "result": "mountable_heater", "type": "recipe", diff --git a/data/json/vehicleparts/appliances.json b/data/json/vehicleparts/appliances.json new file mode 100644 index 0000000000000..8928271dd5a8e --- /dev/null +++ b/data/json/vehicleparts/appliances.json @@ -0,0 +1,52 @@ +[ + { + "type": "vehicle_part", + "id": "ap_fridge", + "name": { "str": "fridge" }, + "symbol": "H", + "looks_like": "f_fridge", + "categories": [ "cargo" ], + "color": "light_blue", + "broken_symbol": "#", + "broken_color": "light_blue", + "damage_modifier": 80, + "durability": 100, + "description": "A fridge. When turned on, it will cool the food inside, extended the time until the food spoils.", + "//": "Use average consumption, not the max on the appliance rating plate. 30W ~ 260kWh per annum", + "epower": -30, + "size": 300, + "item": "fridge", + "location": "center", + "requirements": { + "install": { "skills": [ [ "mechanics", 3 ] ], "time": "60 m", "using": [ [ "vehicle_wrench_2", 1 ] ] }, + "removal": { "skills": [ [ "mechanics", 2 ] ], "time": "30 m", "using": [ [ "vehicle_wrench_2", 1 ] ] }, + "repair": { "skills": [ [ "mechanics", 4 ] ], "time": "60 m", "using": [ [ "welding_standard", 5 ] ] } + }, + "flags": [ "CARGO", "OBSTACLE", "FRIDGE", "COVERED", "ENABLED_DRAINS_EPOWER", "APPLIANCE", "CTRL_ELECTRONIC" ], + "breaks_into": [ + { "item": "steel_lump", "count": [ 8, 13 ] }, + { "item": "steel_chunk", "count": [ 8, 13 ] }, + { "item": "scrap", "count": [ 8, 13 ] }, + { "item": "hose", "prob": 50 }, + { "item": "motor_tiny", "prob": 25 } + ], + "damage_reduction": { "all": 32 } + }, + { + "type": "vehicle_part", + "id": "power_cord", + "name": { "str": "power cord" }, + "symbol": "{", + "categories": [ "other" ], + "color": "yellow", + "broken_symbol": "s", + "broken_color": "dark_gray", + "damage_modifier": 10, + "epower": 0, + "//": "Epower for POWER_TRANSFER stuff is how much percentage-wise loss there is in transmission", + "durability": 120, + "description": "A power cord sticking out of an appliance. You need to plug it in a powered grid for the appliance to work properly.", + "item": "power_cord", + "flags": [ "NOINSTALL", "NO_UNINSTALL", "UNMOUNT_ON_DAMAGE", "UNMOUNT_ON_MOVE", "POWER_TRANSFER" ] + } +] diff --git a/data/json/vehicleparts/vp_flags.json b/data/json/vehicleparts/vp_flags.json index e1bba2de6adac..c4aa1d46dd0a9 100644 --- a/data/json/vehicleparts/vp_flags.json +++ b/data/json/vehicleparts/vp_flags.json @@ -424,6 +424,10 @@ "id": "NOINSTALL", "type": "json_flag" }, + { + "id": "NO_UNINSTALL", + "type": "json_flag" + }, { "id": "OBSTACLE", "type": "json_flag" diff --git a/src/construction.cpp b/src/construction.cpp index f0523f20bb578..d705b2d844f6a 100644 --- a/src/construction.cpp +++ b/src/construction.cpp @@ -119,6 +119,7 @@ static void done_nothing( const tripoint & ) {} void done_trunk_plank( const tripoint & ); void done_grave( const tripoint & ); void done_vehicle( const tripoint & ); +void done_appliance( const tripoint & ); void done_deconstruct( const tripoint & ); void done_digormine_stair( const tripoint &, bool ); void done_dig_stair( const tripoint & ); @@ -1309,6 +1310,25 @@ void construct::done_vehicle( const tripoint &p ) here.add_vehicle_to_cache( veh ); } +void construct::done_appliance( const tripoint &p ) +{ + map &here = get_map(); + vehicle *veh = here.add_vehicle( vproto_id( "none" ), p, 270_degrees, 0, 0 ); + + if( !veh ) { + debugmsg( "error constructing vehicle" ); + return; + } + const vpart_id &vpart = vpart_from_item( get_avatar().lastconsumed ); + veh->install_part( point_zero, vpart ); + veh->add_tag( "APPLIANCE" ); + + veh->name = vpart->name(); + // Update the vehicle cache immediately, + // or the appliance will be invisible for the first couple of turns. + here.add_vehicle_to_cache( veh ); +} + void construct::done_deconstruct( const tripoint &p ) { map &here = get_map(); @@ -1664,6 +1684,7 @@ void load_construction( const JsonObject &jo ) { "done_trunk_plank", construct::done_trunk_plank }, { "done_grave", construct::done_grave }, { "done_vehicle", construct::done_vehicle }, + { "done_appliance", construct::done_appliance }, { "done_deconstruct", construct::done_deconstruct }, { "done_dig_stair", construct::done_dig_stair }, { "done_mine_downstair", construct::done_mine_downstair }, diff --git a/src/iuse.cpp b/src/iuse.cpp index de3a803cca727..57463e56e6c28 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -8723,13 +8723,16 @@ cata::optional iuse::cable_attach( Character *p, item *it, bool, const trip const bool solar_pack = initial_state == "solar_pack"; const bool UPS = initial_state == "UPS"; bool loose_ends = paying_out || cable_cbm || solar_pack || UPS; + bool is_power_cord = it->has_flag( flag_id( "POWER_CORD" ) ); uilist kmenu; kmenu.text = _( "Using cable:" ); - kmenu.addentry( 0, true, -1, _( "Detach and re-spool the cable" ) ); + if( !is_power_cord ) { + kmenu.addentry( 0, true, -1, _( "Detach and re-spool the cable" ) ); + } kmenu.addentry( 1, ( paying_out || cable_cbm ) && !solar_pack && !UPS, -1, _( "Attach loose end to vehicle" ) ); - if( has_bio_cable && loose_ends ) { + if( has_bio_cable && loose_ends && !is_power_cord ) { kmenu.addentry( 2, !cable_cbm, -1, _( "Attach loose end to self" ) ); if( wearing_solar_pack ) { kmenu.addentry( 3, !solar_pack && !paying_out && !UPS, -1, _( "Attach loose end to solar pack" ) ); diff --git a/src/veh_interact.cpp b/src/veh_interact.cpp index 559b3efd721d9..d6ac6da208b42 100644 --- a/src/veh_interact.cpp +++ b/src/veh_interact.cpp @@ -2253,7 +2253,7 @@ bool veh_interact::can_potentially_install( const vpart_info &vpart ) engine_reqs_met = engines < 2; } - return hammerspace || ( can_make && engine_reqs_met ); + return hammerspace || ( can_make && engine_reqs_met && !vpart.has_flag( VPFLAG_APPLIANCE ) ); } /** @@ -2842,6 +2842,10 @@ void veh_interact::display_list( size_t pos, const std::vector vtypes; static const std::unordered_map vpart_bitflag_map = { { "ARMOR", VPFLAG_ARMOR }, + { "APPLIANCE", VPFLAG_APPLIANCE }, { "EVENTURN", VPFLAG_EVENTURN }, { "ODDTURN", VPFLAG_ODDTURN }, { "CONE_LIGHT", VPFLAG_CONE_LIGHT }, diff --git a/src/veh_type.h b/src/veh_type.h index fa223f99a6f8c..4fef4cced9d6c 100644 --- a/src/veh_type.h +++ b/src/veh_type.h @@ -33,6 +33,7 @@ class vehicle; // won't be going away, are involved in core functionality, and are checked frequently enum vpart_bitflags : int { VPFLAG_ARMOR, + VPFLAG_APPLIANCE, VPFLAG_EVENTURN, VPFLAG_ODDTURN, VPFLAG_CONE_LIGHT, diff --git a/src/vehicle.cpp b/src/vehicle.cpp index bb015423bc49f..e52e9728794b3 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -1243,8 +1243,9 @@ bool vehicle::can_mount( const point &dp, const vpart_id &id ) const const std::vector parts_in_square = parts_at_relative( dp, false ); - //First part in an empty square MUST be a structural part - if( parts_in_square.empty() && part.location != part_location_structure ) { + //First part in an empty square MUST be a structural part or be an appliance + if( parts_in_square.empty() && part.location != part_location_structure && + !part.has_flag( "APPLIANCE" ) ) { return false; } // If its a part that harnesses animals that don't allow placing on it. @@ -6232,7 +6233,7 @@ void vehicle::shed_loose_parts() tow_data.clear_towing(); } const vehicle_part *part = &parts[elem]; - if( !magic ) { + if( !magic && !part->properties_to_item().has_flag( flag_id( "POWER_CORD" ) ) ) { item drop = part->properties_to_item(); here.add_item_or_charges( global_part_pos3( *part ), drop ); } @@ -7275,6 +7276,16 @@ tripoint vehicle::exhaust_dest( int part ) const return global_pos3() + tripoint( q, 0 ); } +void vehicle::add_tag( std::string tag ) +{ + tags.insert( tag ); +} + +bool vehicle::has_tag( std::string tag ) +{ + return tags.count( tag ) > 0; +} + template<> bool vehicle_part_with_feature_range::matches( const size_t part ) const { diff --git a/src/vehicle.h b/src/vehicle.h index 6bd3ee1c09787..b5eb5aaf4f31b 100644 --- a/src/vehicle.h +++ b/src/vehicle.h @@ -893,6 +893,8 @@ class vehicle */ void use_controls( const tripoint &pos ); + void plug_in( const tripoint &pos ); + // Fold up the vehicle bool fold_up(); @@ -1916,6 +1918,9 @@ class vehicle cata::optional smart_controller_cfg = cata::nullopt; bool has_enabled_smart_controller = false; // NOLINT(cata-serialize) + void add_tag( std::string tag ); + bool has_tag( std::string tag ); + private: mutable units::mass mass_cache; // NOLINT(cata-serialize) // cached pivot point diff --git a/src/vehicle_use.cpp b/src/vehicle_use.cpp index 372218eda662b..8bbce3e349001 100644 --- a/src/vehicle_use.cpp +++ b/src/vehicle_use.cpp @@ -821,6 +821,22 @@ void vehicle::use_controls( const tripoint &pos ) } } +void vehicle::plug_in( const tripoint &pos ) +{ + item powercord( "power_cord" ); + powercord.set_var( "source_x", pos.x ); + powercord.set_var( "source_y", pos.y ); + powercord.set_var( "source_z", pos.z ); + powercord.set_var( "state", "pay_out_cable" ); + powercord.active = true; + + if( powercord.get_use( "CABLE_ATTACH" ) ) { + powercord.get_use( "CABLE_ATTACH" )->call( get_player_character(), powercord, powercord.active, + pos ); + } + +} + bool vehicle::fold_up() { const bool can_be_folded = is_foldable(); @@ -2049,15 +2065,22 @@ void vehicle::interact_with( const vpart_position &vp ) const bool has_planter = vp.avail_part_with_feature( "PLANTER" ) || vp.avail_part_with_feature( "ADVANCED_PLANTER" ); + bool is_appliance = has_tag( "APPLIANCE" ); + enum { EXAMINE, TRACK, HANDBRAKE, CONTROL, CONTROL_ELECTRONICS, GET_ITEMS, GET_ITEMS_ON_GROUND, FOLD_VEHICLE, UNLOAD_TURRET, RELOAD_TURRET, FILL_CONTAINER, DRINK, PURIFY_TANK, USE_AUTOCLAVE, USE_WASHMACHINE, - USE_DISHWASHER, USE_MONSTER_CAPTURE, USE_BIKE_RACK, USE_HARNESS, RELOAD_PLANTER, WORKBENCH, PEEK_CURTAIN, TOOLS_OFFSET + USE_DISHWASHER, USE_MONSTER_CAPTURE, USE_BIKE_RACK, USE_HARNESS, RELOAD_PLANTER, WORKBENCH, PEEK_CURTAIN, TOOLS_OFFSET, PLUG }; uilist selectmenu; - selectmenu.addentry( EXAMINE, true, 'e', _( "Examine vehicle" ) ); - selectmenu.addentry( TRACK, true, keybind( "TOGGLE_TRACKING" ), tracking_toggle_string() ); + + if( !is_appliance ) { + selectmenu.addentry( EXAMINE, true, 'e', _( "Examine vehicle" ) ); + selectmenu.addentry( TRACK, true, keybind( "TOGGLE_TRACKING" ), tracking_toggle_string() ); + } else { + selectmenu.addentry( PLUG, true, 'g', _( "Plug in appliance" ) ); + } if( vp_controls ) { selectmenu.addentry( HANDBRAKE, true, 'h', _( "Pull handbrake" ) ); selectmenu.addentry( CONTROL, true, 'v', _( "Control vehicle" ) ); @@ -2326,6 +2349,10 @@ void vehicle::interact_with( const vpart_position &vp ) iexamine::workbench_internal( player_character, vp.pos(), vp_workbench ); return; } + case PLUG: { + plug_in( here.getabs( vp.pos() ) ); + return; + } default: { if( choice >= TOOLS_OFFSET ) { use_vehicle_tool( veh_tools[choice - TOOLS_OFFSET].first );