From 6867e65a41a951cf696129923f75a231ab93ef50 Mon Sep 17 00:00:00 2001 From: RenechCDDA <84619419+RenechCDDA@users.noreply.github.com> Date: Wed, 17 Apr 2024 11:51:37 -0400 Subject: [PATCH 1/2] Refactor map::grow_plant --- .../furniture-domestic_plants.json | 2 +- src/item.cpp | 6 +- src/item.h | 4 +- src/map.cpp | 64 +++++++------------ 4 files changed, 29 insertions(+), 47 deletions(-) diff --git a/data/json/furniture_and_terrain/furniture-domestic_plants.json b/data/json/furniture_and_terrain/furniture-domestic_plants.json index a6d7995978031..03ee91f2ef5e3 100644 --- a/data/json/furniture_and_terrain/furniture-domestic_plants.json +++ b/data/json/furniture_and_terrain/furniture-domestic_plants.json @@ -93,7 +93,7 @@ ], "examine_action": "harvest_plant_ex", "bash": { "str_min": 4, "str_max": 10, "sound": "crunch.", "sound_fail": "whish." }, - "plant_data": { "transform": "f_null", "base": "f_null" } + "plant_data": { "transform": "f_plant_harvest", "base": "f_null" } }, { "type": "furniture", diff --git a/src/item.cpp b/src/item.cpp index b2ba44040e165..cd8664936a004 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -14145,7 +14145,7 @@ bool item::is_seed() const return !!type->seed; } -time_duration item::get_plant_epoch() const +time_duration item::get_plant_epoch( int num_epochs ) const { if( !type->seed ) { return 0_turns; @@ -14154,9 +14154,9 @@ time_duration item::get_plant_epoch() const // the default in-game season length to give // more accuracy for longer season lengths // Also note that seed->grow is the time it takes from seeding to harvest, this is - // divided by 3 to get the time it takes from one plant state to the next. + // divided by number of growth stages (usually 3) to get the time it takes from one plant state to the next. // TODO: move this into the islot_seed - return type->seed->grow * calendar::season_ratio() / 3; + return type->seed->grow * calendar::season_ratio() / num_epochs; } std::string item::get_plant_name() const diff --git a/src/item.h b/src/item.h index 1a94a783d860c..cbd33d74bb20a 100644 --- a/src/item.h +++ b/src/item.h @@ -2039,10 +2039,10 @@ class item : public visitable */ bool is_seed() const; /** - * Time it takes to grow from one stage to another. There are 4 plant stages: + * Time it takes to grow from one stage to another. There are normally 4 plant stages: * seed, seedling, mature and harvest. Non-seed items return 0. */ - time_duration get_plant_epoch() const; + time_duration get_plant_epoch( int num_epochs = 3 ) const; /** * The name of the plant as it appears in the various informational menus. This should be * translated. Returns an empty string for non-seed items. diff --git a/src/map.cpp b/src/map.cpp index d61e728f1fd85..7d38ff6030fe1 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -8387,28 +8387,26 @@ void map::grow_plant( const tripoint &p ) furn_set( p, furn_str_id::NULL_ID() ); return; } - const time_duration plantEpoch = seed->get_plant_epoch(); - if( seed->age() >= plantEpoch * furn.plant->growth_multiplier && - !furn.has_flag( ter_furn_flag::TFLAG_GROWTH_HARVEST ) ) { - if( seed->age() < plantEpoch * 2 ) { - if( has_flag_furn( ter_furn_flag::TFLAG_GROWTH_SEEDLING, p ) ) { - return; - } - - // Remove fertilizer if any - map_stack::iterator fertilizer = std::find_if( items.begin(), items.end(), []( const item & it ) { - return it.has_flag( flag_FERTILIZER ); - } ); - if( fertilizer != items.end() ) { - items.erase( fertilizer ); + // TODO: this should probably be read from the seed's data. But for now, everything uses exactly this many growth stages. + std::map plant_epochs; + plant_epochs[ter_furn_flag::TFLAG_GROWTH_SEEDLING] = 1; + plant_epochs[ter_furn_flag::TFLAG_GROWTH_MATURE] = 2; + plant_epochs[ter_furn_flag::TFLAG_GROWTH_HARVEST] = 3; + + const time_duration base_epoch_duration = seed->get_plant_epoch( plant_epochs.size() ); + const time_duration epoch_duration = base_epoch_duration * furn.plant->growth_multiplier; + if( seed->age() >= epoch_duration ) { + const int epoch_age = seed->age() / epoch_duration; + int current_epoch = 0; + for( std::pair pair : plant_epochs ) { + if( has_flag_furn( pair.first, p ) ) { + current_epoch = pair.second; + break; } + } + const int epochs_to_advance = epoch_age - current_epoch; - rotten_item_spawn( *seed, p ); - furn_set( p, furn_str_id( furn.plant->transform ) ); - } else if( seed->age() < plantEpoch * 3 * furn.plant->growth_multiplier ) { - if( has_flag_furn( ter_furn_flag::TFLAG_GROWTH_MATURE, p ) ) { - return; - } + for( int i = 0; i < epochs_to_advance; i++ ) { // Remove fertilizer if any map_stack::iterator fertilizer = std::find_if( items.begin(), items.end(), []( const item & it ) { return it.has_flag( flag_FERTILIZER ); @@ -8416,29 +8414,13 @@ void map::grow_plant( const tripoint &p ) if( fertilizer != items.end() ) { items.erase( fertilizer ); } + // spawn appropriate amount of rot_spawn, equivalent to number of times we iterate this loop rotten_item_spawn( *seed, p ); - //You've skipped the seedling stage so roll monsters twice - if( !has_flag_furn( ter_furn_flag::TFLAG_GROWTH_SEEDLING, p ) ) { - rotten_item_spawn( *seed, p ); - } - furn_set( p, furn_str_id( furn.plant->transform ) ); - - } else { - //You've skipped two stages so roll monsters two times - if( has_flag_furn( ter_furn_flag::TFLAG_GROWTH_SEEDLING, p ) ) { - rotten_item_spawn( *seed, p ); - rotten_item_spawn( *seed, p ); - //One stage change - } else if( has_flag_furn( ter_furn_flag::TFLAG_GROWTH_MATURE, p ) ) { - rotten_item_spawn( *seed, p ); - //Goes from seed to harvest in one check - } else { - rotten_item_spawn( *seed, p ); - rotten_item_spawn( *seed, p ); - rotten_item_spawn( *seed, p ); - } - furn_set( p, furn_str_id( furn.plant->transform ) ); + // Get an updated reference to the furniture each time we go through this loop, to make sure we transform each step in turn + const furn_t ¤t_furn = this->furn( p ).obj(); + furn_set( p, furn_str_id( current_furn.plant->transform ) ); } + } } From a4c021ec0d4f192b32a1d86eb209a04b3ca4c4c7 Mon Sep 17 00:00:00 2001 From: RenechCDDA <84619419+RenechCDDA@users.noreply.github.com> Date: Wed, 17 Apr 2024 13:54:20 -0400 Subject: [PATCH 2/2] Crops will overgrow and/or die if not harvested in time --- .../furniture-domestic_plants.json | 74 ++++++++++++++++++- .../furniture-terrains.json | 4 +- src/activity_handlers.h | 2 + src/activity_item_handling.cpp | 7 ++ src/iexamine.cpp | 21 +++++- src/iexamine.h | 1 + src/mapdata.cpp | 1 + src/mapdata.h | 1 + tools/spell_checker/dictionary.txt | 1 + 9 files changed, 106 insertions(+), 6 deletions(-) diff --git a/data/json/furniture_and_terrain/furniture-domestic_plants.json b/data/json/furniture_and_terrain/furniture-domestic_plants.json index 03ee91f2ef5e3..dfc908bf641d4 100644 --- a/data/json/furniture_and_terrain/furniture-domestic_plants.json +++ b/data/json/furniture_and_terrain/furniture-domestic_plants.json @@ -71,6 +71,32 @@ ] } }, + { + "type": "furniture", + "id": "f_plant_unharvested_overgrown", + "looks_like": "t_grass_tall", + "name": "overgrown plant", + "description": "This patch of green used to be a cultivated field or some sort of monocrop agriculture. Neglected for too long, it has been overtaken by nature.", + "symbol": "#", + "color": "red", + "coverage": 50, + "move_cost_mod": 2, + "required_str": -1, + "flags": [ + "PLANT", + "SEALED", + "TRANSPARENT", + "CONTAINER", + "NOITEM", + "TINY", + "DONT_REMOVE_ROTTEN", + "GROWTH_OVERGROWN", + "SMALL_HIDE" + ], + "examine_action": "clear_overgrown", + "bash": { "str_min": 4, "str_max": 10, "sound": "crunch.", "sound_fail": "whish." }, + "plant_data": { "transform": "f_plant_unharvested_overgrown", "base": "f_null" } + }, { "type": "furniture", "id": "f_plant_harvest", @@ -78,7 +104,8 @@ "description": "This plant is fully grown and ready to be harvested. Identifying how to harvest it requires closer examination.", "symbol": "#", "color": "light_green", - "move_cost_mod": 0, + "coverage": 30, + "move_cost_mod": 1, "required_str": -1, "flags": [ "PLANT", @@ -93,7 +120,7 @@ ], "examine_action": "harvest_plant_ex", "bash": { "str_min": 4, "str_max": 10, "sound": "crunch.", "sound_fail": "whish." }, - "plant_data": { "transform": "f_plant_harvest", "base": "f_null" } + "plant_data": { "transform": "f_plant_unharvested_overgrown", "base": "f_null" } }, { "type": "furniture", @@ -171,6 +198,47 @@ "plant_data": { "transform": "f_planter_seed" }, "examine_action": "dirtmound" }, + { + "type": "furniture", + "id": "f_planter_unharvested_overgrown", + "name": "planter with dead plants", + "description": "Somewhere beneath this heap of dying plants you can see the shape of wooden furniture. Left without care, the plants it used to nurture have shriveled and died.", + "symbol": "#", + "color": "red", + "looks_like": "f_planter", + "move_cost_mod": 3, + "required_str": -1, + "examine_action": "clear_overgrown", + "flags": [ + "PLANT", + "SEALED", + "TRANSPARENT", + "CONTAINER", + "NOITEM", + "TINY", + "DONT_REMOVE_ROTTEN", + "GROWTH_OVERGROWN", + "SMALL_HIDE" + ], + "deconstruct": { + "items": [ + { "item": "2x4", "count": [ 11, 12 ] }, + { "item": "nail", "charges": [ 30, 36 ] }, + { "item": "pebble", "charges": [ 180, 200 ] }, + { "item": "material_soil", "count": [ 70, 75 ] } + ] + }, + "bash": { + "str_min": 2, + "str_max": 4, + "sound": "rrrrip!", + "sound_fail": "brush.", + "sound_vol": 1, + "furn_set": "f_planter", + "items": [ { "item": "withered", "count": [ 1, 2 ] } ] + }, + "plant_data": { "transform": "f_planter_unharvested_overgrown", "base": "f_planter" } + }, { "type": "furniture", "id": "f_planter_harvest", @@ -214,7 +282,7 @@ { "item": "twig", "count": [ 1, 5 ] } ] }, - "plant_data": { "transform": "f_planter", "base": "f_planter" } + "plant_data": { "transform": "f_planter_unharvested_overgrown", "base": "f_planter" } }, { "type": "furniture", diff --git a/data/json/furniture_and_terrain/furniture-terrains.json b/data/json/furniture_and_terrain/furniture-terrains.json index a83d1cd383683..c6eb1a398d552 100644 --- a/data/json/furniture_and_terrain/furniture-terrains.json +++ b/data/json/furniture_and_terrain/furniture-terrains.json @@ -1366,7 +1366,7 @@ { "item": "twig", "count": [ 1, 5 ] } ] }, - "plant_data": { "transform": "f_dirtmound_shallow", "base": "f_dirtmound_shallow" }, + "plant_data": { "transform": "f_plant_unharvested_overgrown", "base": "f_dirtmound_shallow" }, "examine_action": "harvest_plant_ex" }, { @@ -1548,7 +1548,7 @@ { "item": "twig", "count": [ 1, 5 ] } ] }, - "plant_data": { "transform": "f_dirtmound_pile", "base": "f_dirtmound_pile" }, + "plant_data": { "transform": "f_plant_unharvested_overgrown", "base": "f_dirtmound_pile" }, "examine_action": "harvest_plant_ex" }, { diff --git a/src/activity_handlers.h b/src/activity_handlers.h index b463b9b2a9719..c2328d682ba39 100644 --- a/src/activity_handlers.h +++ b/src/activity_handlers.h @@ -64,6 +64,7 @@ enum class do_activity_reason : int { NO_ZONE, // There is no required zone anymore ALREADY_DONE, // the activity is done already ( maybe by someone else ) UNKNOWN_ACTIVITY, // This is probably an error - got to the end of function with no previous reason + NEEDS_CLEARING, // For farming - tile was neglected and became overgrown, can be cleared. NEEDS_HARVESTING, // For farming - tile is harvestable now. NEEDS_PLANTING, // For farming - tile can be planted NEEDS_TILLING, // For farming - tile can be tilled @@ -95,6 +96,7 @@ const std::vector do_activity_reason_string = { "NO_ZONE", "ALREADY_DONE", "UNKNOWN_ACTIVITY", + "NEEDS_CLEARING", "NEEDS_HARVESTING", "NEEDS_PLANTING", "NEEDS_TILLING", diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index abc53d671cd3b..7afd200863aa6 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -1296,6 +1296,10 @@ static activity_reason_info can_do_activity_there( const activity_id &act, Chara const plot_options &options = dynamic_cast( zone.get_options() ); const itype_id seed = options.get_seed(); + if( here.has_flag_furn( ter_furn_flag::TFLAG_GROWTH_OVERGROWN, src_loc ) ) { + return activity_reason_info::ok( do_activity_reason::NEEDS_CLEARING ); + } + if( here.has_flag_furn( ter_furn_flag::TFLAG_GROWTH_HARVEST, src_loc ) ) { map_stack items = here.i_at( src_loc ); const map_stack::iterator seed = std::find_if( items.begin(), items.end(), []( const item & it ) { @@ -2976,6 +2980,9 @@ static bool generic_multi_activity_do( here.has_flag_furn( ter_furn_flag::TFLAG_GROWTH_HARVEST, src_loc ) ) { // TODO: fix point types iexamine::harvest_plant( you, src_loc.raw(), true ); + } else if( ( reason == do_activity_reason::NEEDS_CLEARING ) && + here.has_flag_furn( ter_furn_flag::TFLAG_GROWTH_OVERGROWN, src_loc ) ) { + iexamine::clear_overgrown( you, src_loc.raw() ); } else if( reason == do_activity_reason::NEEDS_TILLING && here.has_flag( ter_furn_flag::TFLAG_PLOWABLE, src_loc ) && you.has_quality( qual_DIG, 1 ) && !here.has_furn( src_loc ) ) { diff --git a/src/iexamine.cpp b/src/iexamine.cpp index eb61fdbeac44b..0dd6365cc63ce 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -2626,6 +2626,24 @@ std::list iexamine::get_harvest_items( const itype &type, const int plant_ return result; } +// Cleaning up plants that have decayed and overgrown +void iexamine::clear_overgrown( Character &you, const tripoint &examp ) +{ + map &here = get_map(); + + if( !here.has_flag_furn( ter_furn_flag::TFLAG_GROWTH_OVERGROWN, examp ) ) { + debugmsg( "clear_overgrown called on tile which is not an overgrown crop!" ); + return; + } + + player_activity act( ACT_HARVEST, to_moves( 60_seconds ) ); + you.assign_activity( act ); + here.i_clear( examp ); + here.furn_set( examp, here.furn( examp )->plant->base ); + you.add_msg_if_player( m_neutral, + _( "You pull up what's left of the planted crop and trample the rest." ) ); +} + // Only harvest, used for autoforaging void iexamine::harvest_plant_ex( Character &you, const tripoint &examp ) { @@ -2714,7 +2732,7 @@ void iexamine::harvest_plant( Character &you, const tripoint &examp, bool from_a } here.add_item_or_charges( you.pos(), i ); } - here.furn_set( examp, furn_str_id( here.furn( examp )->plant->transform ) ); + here.furn_set( examp, furn_str_id( here.furn( examp )->plant->base ) ); you.add_msg_if_player( m_neutral, _( "You harvest the plant." ) ); } } @@ -7083,6 +7101,7 @@ iexamine_functions iexamine_functions_from_string( const std::string &function_n { "harvest_furn", &iexamine::harvest_furn }, { "harvest_ter_nectar", &iexamine::harvest_ter_nectar }, { "harvest_ter", &iexamine::harvest_ter }, + { "clear_overgrown", &iexamine::clear_overgrown }, { "harvest_plant_ex", &iexamine::harvest_plant_ex }, { "harvested_plant", &iexamine::harvested_plant }, { "shrub_marloss", &iexamine::shrub_marloss }, diff --git a/src/iexamine.h b/src/iexamine.h index 26144968aafd7..b6bc0425970a9 100644 --- a/src/iexamine.h +++ b/src/iexamine.h @@ -158,6 +158,7 @@ std::list get_harvest_items( const itype &type, int plant_count, std::vector get_seed_entries( const std::vector &seed_inv ); int query_seed( const std::vector &seed_entries ); void plant_seed( Character &you, const tripoint &examp, const itype_id &seed_id ); +void clear_overgrown( Character &you, const tripoint &examp ); void harvest_plant_ex( Character &you, const tripoint &examp ); void harvest_plant( Character &you, const tripoint &examp, bool from_activity ); void fertilize_plant( Character &you, const tripoint &tile, const itype_id &fertilizer ); diff --git a/src/mapdata.cpp b/src/mapdata.cpp index ff85288d8c5c1..54bbd23ac4ef6 100644 --- a/src/mapdata.cpp +++ b/src/mapdata.cpp @@ -208,6 +208,7 @@ std::string enum_to_string( ter_furn_flag data ) case ter_furn_flag::TFLAG_CONSOLE: return "CONSOLE"; case ter_furn_flag::TFLAG_PLANTABLE: return "PLANTABLE"; case ter_furn_flag::TFLAG_GROWTH_HARVEST: return "GROWTH_HARVEST"; + case ter_furn_flag::TFLAG_GROWTH_OVERGROWN: return "GROWTH_OVERGROWN"; case ter_furn_flag::TFLAG_MOUNTABLE: return "MOUNTABLE"; case ter_furn_flag::TFLAG_RAMP_END: return "RAMP_END"; case ter_furn_flag::TFLAG_FLOWER: return "FLOWER"; diff --git a/src/mapdata.h b/src/mapdata.h index 9d833c8db28f5..54aaf84783ab4 100644 --- a/src/mapdata.h +++ b/src/mapdata.h @@ -268,6 +268,7 @@ enum class ter_furn_flag : int { TFLAG_CONSOLE, TFLAG_PLANTABLE, TFLAG_GROWTH_HARVEST, + TFLAG_GROWTH_OVERGROWN, TFLAG_MOUNTABLE, TFLAG_RAMP_END, TFLAG_FLOWER, diff --git a/tools/spell_checker/dictionary.txt b/tools/spell_checker/dictionary.txt index 944accb566618..66fdb6fe91e45 100644 --- a/tools/spell_checker/dictionary.txt +++ b/tools/spell_checker/dictionary.txt @@ -3916,6 +3916,7 @@ Monegasque Mongolian Monica Monoco +monocrop monocrystalline monogyna monometal