diff --git a/data/json/furniture_and_terrain/terrain-liquids.json b/data/json/furniture_and_terrain/terrain-liquids.json index 8bbdf9117f87..bd543ad4f820 100644 --- a/data/json/furniture_and_terrain/terrain-liquids.json +++ b/data/json/furniture_and_terrain/terrain-liquids.json @@ -7,7 +7,7 @@ "symbol": "~", "color": "light_blue", "move_cost": 5, - "flags": [ "TRANSPARENT", "LIQUID", "NO_SCENT", "SWIMMABLE", "FISHABLE" ], + "flags": [ "TRANSPARENT", "LIQUID", "NO_SCENT", "SWIMMABLE", "FISHABLE", "SHALLOW_WATER" ], "connects_to": "WATER", "examine_action": "water_source" }, @@ -147,7 +147,7 @@ "looks_like": "t_water_sh", "color": "light_blue", "move_cost": 5, - "flags": [ "TRANSPARENT", "LIQUID", "NO_SCENT", "SWIMMABLE", "SALT_WATER", "FISHABLE" ], + "flags": [ "TRANSPARENT", "LIQUID", "NO_SCENT", "SWIMMABLE", "SALT_WATER", "FISHABLE", "SHALLOW_WATER" ], "connects_to": "WATER", "examine_action": "water_source" }, diff --git a/data/json/items/comestibles/seed.json b/data/json/items/comestibles/seed.json index 3ba3dc4f6607..a739956d94f8 100644 --- a/data/json/items/comestibles/seed.json +++ b/data/json/items/comestibles/seed.json @@ -240,8 +240,14 @@ "copy-from": "seed", "name": { "str_sp": "cattail seeds" }, "color": "green", - "description": "Some cattail seeds.", - "seed_data": { "plant_name": "cattail", "fruit": "cattail_stalk", "byproducts": [ "cattail_rhizome" ], "grow": "14 days" } + "description": "Some cattail seeds. Must be planted in shallow water.", + "seed_data": { + "plant_name": "cattail", + "fruit": "cattail_stalk", + "byproducts": [ "cattail_rhizome" ], + "grow": "14 days", + "required_terrain_flag": "SHALLOW_WATER" + } }, { "type": "COMESTIBLE", diff --git a/doc/src/content/docs/en/mod/json/reference/json_info.md b/doc/src/content/docs/en/mod/json/reference/json_info.md index 8c4e1ab7f340..dbce10b329fd 100644 --- a/doc/src/content/docs/en/mod/json/reference/json_info.md +++ b/doc/src/content/docs/en/mod/json/reference/json_info.md @@ -2011,6 +2011,9 @@ can be planted: "grow" : 91 // A time duration: how long it takes for a plant to fully mature. Based around a 91 day season length (roughly a real world season) to give better accuracy for longer season lengths // Note that growing time is later converted based upon the season_length option, basing it around 91 is just for accuracy purposes // A value 91 means 3 full seasons, a value of 30 would mean 1 season. + "required_terrain_flag": "PLANTABLE" // A tag that terrain and furniture would need to have in order for the seed to be plantable there. + // Default is "PLANTABLE", and using this will cause any terain the plant is wrown on to turn into dirt once the plant is planted, unless furniture is used. + // Using any other tag will not turn the terrain into dirt. } ``` diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index a995e33f9f3a..9e70c08d2aa8 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -3580,10 +3580,12 @@ void activity_handlers::plant_seed_finish( player_activity *act, player *p ) } used_seed.front()->set_flag( flag_HIDDEN_ITEM ); here.add_item_or_charges( examp, std::move( used_seed.front() ) ); - if( here.has_flag_furn( flag_PLANTABLE, examp ) ) { + if( here.has_flag_furn( seed_id->seed->required_terrain_flag, examp ) ) { here.furn_set( examp, furn_str_id( here.furn( examp )->plant->transform ) ); - } else { + } else if( seed_id->seed->required_terrain_flag == flag_PLANTABLE ) { here.set( examp, t_dirt, f_plant_seed ); + } else { + here.furn_set( examp, f_plant_seed ); } p->add_msg_player_or_npc( _( "You plant some %s." ), _( " plants some %s." ), item::nname( seed_id ) ); diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index 9f926bafaa98..a3e36169e118 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -141,7 +141,6 @@ static const std::string flag_BUTCHER_EQ( "BUTCHER_EQ" ); static const std::string flag_FISHABLE( "FISHABLE" ); static const std::string flag_GROWTH_HARVEST( "GROWTH_HARVEST" ); static const std::string flag_PLANT( "PLANT" ); -static const std::string flag_PLANTABLE( "PLANTABLE" ); static const std::string flag_PLOWABLE( "PLOWABLE" ); static const std::string flag_TREE( "TREE" ); @@ -1619,6 +1618,8 @@ static activity_reason_info can_do_activity_there( const activity_id &act, playe zones = mgr.get_zones( zone_type_FARM_PLOT, here.getabs( src_loc ) ); for( const zone_data &zone : zones ) { + const plot_options &options = dynamic_cast( zone.get_options() ); + const itype_id seed = options.get_seed(); if( here.has_flag_furn( flag_GROWTH_HARVEST, src_loc ) ) { // simple work, pulling up plants, nothing else required. return activity_reason_info::ok( do_activity_reason::NEEDS_HARVESTING ); @@ -1630,14 +1631,12 @@ static activity_reason_info can_do_activity_there( const activity_id &act, playe // we need a shovel/hoe return activity_reason_info::fail( do_activity_reason::NEEDS_TILLING ); } - } else if( here.has_flag_ter_or_furn( flag_PLANTABLE, src_loc ) && + } else if( here.has_flag_ter_or_furn( seed->seed->required_terrain_flag, src_loc ) && warm_enough_to_plant( src_loc ) ) { if( here.has_items( src_loc ) ) { return activity_reason_info::fail( do_activity_reason::BLOCKING_TILE ); } else { // do we have the required seed on our person? - const plot_options &options = dynamic_cast( zone.get_options() ); - const itype_id seed = options.get_seed(); // If its a farm zone with no specified seed, and we've checked for tilling and harvesting. // then it means no further work can be done here if( seed.is_empty() ) { @@ -2901,8 +2900,7 @@ static bool generic_multi_activity_do( player &p, const activity_id &act_id, p.backlog.emplace_front( std::make_unique( act_id ) ); p.activity->placement = src; return false; - } else if( reason == do_activity_reason::NEEDS_PLANTING && - here.has_flag_ter_or_furn( flag_PLANTABLE, src_loc ) ) { + } else if( reason == do_activity_reason::NEEDS_PLANTING ) { std::vector zones = mgr.get_zones( zone_type_FARM_PLOT, here.getabs( src_loc ) ); for( const zone_data &zone : zones ) { @@ -2916,6 +2914,9 @@ static bool generic_multi_activity_do( player &p, const activity_id &act_id, if( seed_inv.empty() ) { continue; } + if( !here.has_flag_ter_or_furn( seed->seed->required_terrain_flag, src_loc ) ) { + continue; + } iexamine::plant_seed( p, src_loc, itype_id( seed ) ); p.backlog.emplace_front( std::make_unique( act_id ) ); return false; diff --git a/src/iexamine.cpp b/src/iexamine.cpp index 35fc5f01c655..21c7a3204b95 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -2247,6 +2247,11 @@ void iexamine::dirtmound( player &p, const tripoint &examp ) } const auto &seed_id = std::get<0>( seed_entries[seed_index] ); + if( !here.has_flag_ter_or_furn( seed_id->seed->required_terrain_flag, examp ) ) { + add_msg( _( "This type of seed can not be planted in this location." ) ); + return; + } + plant_seed( p, examp, seed_id ); } diff --git a/src/item_factory.cpp b/src/item_factory.cpp index 53585c3bbe6e..61257d7b5597 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -2310,6 +2310,7 @@ void Item_factory::load( islot_seed &slot, const JsonObject &jo, const std::stri assign( jo, "fruit", slot.fruit_id ); assign( jo, "seeds", slot.spawn_seeds ); assign( jo, "byproducts", slot.byproducts ); + assign( jo, "required_terrain_flag", slot.required_terrain_flag ); } void Item_factory::load( islot_container &slot, const JsonObject &jo, const std::string & ) diff --git a/src/itype.h b/src/itype.h index 8c703764a0f2..ed6aa558354e 100644 --- a/src/itype.h +++ b/src/itype.h @@ -21,6 +21,7 @@ #include "explosion.h" #include "game_constants.h" #include "iuse.h" // use_function +#include "mapdata.h" #include "pldata.h" // add_type #include "shape.h" #include "stomach.h" @@ -765,7 +766,10 @@ struct islot_seed { * Additionally items (a list of their item ids) that will spawn when harvesting the plant. */ std::vector byproducts; - + /** + * Terrain tag required to plant the seed. + */ + std::string required_terrain_flag = "PLANTABLE"; islot_seed() = default; };