Merge branch 'master' of https://github.com/tgstation/tgstation into upstream-sync

This commit is contained in:
xPokee
2025-10-04 05:28:09 -04:00
67 changed files with 1444 additions and 796 deletions
+16 -29
View File
@@ -10,39 +10,30 @@
worn_icon_state = "graft"
attack_verb_continuous = list("plants", "vegitizes", "crops", "reaps", "farms")
attack_verb_simple = list("plant", "vegitize", "crop", "reap", "farm")
///The stored trait taken from the parent plant. Defaults to perenial growth.
var/datum/plant_gene/stored_trait
///Determines the appearance of the graft. Rudimentary right now so it just picks randomly.
var/graft_appearance
/// The name of the plant this was taken from.
var/parent_name = ""
///The lifespan stat of the parent seed when the graft was taken.
var/lifespan
///The endurance stat of the parent seed when the graft was taken.
var/endurance
///The production stat of the parent seed when the graft was taken.
var/production
///The weed_rate stat of the parent seed when the graft was taken.
var/weed_rate
///The weed_chance stat of the parent seed when the graft was taken.
var/weed_chance
///The yield stat of the parent seed when the graft was taken.
var/yield
/// Our internal seed used to modify stats or genes by grafting or passed as our seed when propagating vegetatively,
var/obj/item/seeds/plant_dna = /obj/item/seeds/apple
/obj/item/graft/Initialize(mapload, datum/plant_gene/trait/trait_path)
/obj/item/graft/Initialize(mapload, obj/item/seeds/mother_plant)
. = ..()
//Default gene is repeated harvest.
if(trait_path)
stored_trait = new trait_path
else
stored_trait = new /datum/plant_gene/trait/repeated_harvest
//create our "plant dna" internal seed from the plant the cuttings are taken from.
if(mother_plant)
if(ispath(mother_plant))
plant_dna = new mother_plant()
if(!istype(plant_dna))
CRASH("Tried to create a graft using a non-seed path.")
else if(istype(mother_plant))
plant_dna = mother_plant.Copy()
else
CRASH("Tried to create a graft using a non-seed reference.")
icon_state = pick(
10 ; "graft_plant" , \
5 ; "graft_flower" , \
4 ; "graft_mushroom" , \
1 ; "graft_doom" )
name += " ([plant_dna.plantname])"
var/static/list/hovering_item_typechecks = list(
/obj/item/plant_analyzer = list(
SCREENTIP_CONTEXT_LMB = "Scan graft",
@@ -50,7 +41,3 @@
)
AddElement(/datum/element/contextual_screentip_item_typechecks, hovering_item_typechecks)
/obj/item/graft/Destroy()
QDEL_NULL(stored_trait)
return ..()
@@ -61,6 +61,8 @@
product = /obj/item/food/grown/rice
mutatelist = null
growthstages = 3
genes = list(/datum/plant_gene/trait/semiaquatic)
/obj/item/food/grown/rice
seed = /obj/item/seeds/wheat/rice
+1 -1
View File
@@ -14,7 +14,7 @@
growing_icon = 'icons/obj/service/hydroponics/growing_vegetables.dmi'
icon_grow = "potato-grow"
icon_dead = "potato-dead"
genes = list(/datum/plant_gene/trait/battery, /datum/plant_gene/trait/one_bite)
genes = list(/datum/plant_gene/trait/soil_lover, /datum/plant_gene/trait/battery, /datum/plant_gene/trait/one_bite)
mutatelist = list(/obj/item/seeds/potato/sweet)
reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
graft_gene = /datum/plant_gene/trait/battery
+4 -2
View File
@@ -14,6 +14,7 @@
growing_icon = 'icons/obj/service/hydroponics/growing_vegetables.dmi'
mutatelist = list(/obj/item/seeds/carrot/parsnip, /obj/item/seeds/carrot/cahnroot)
reagents_add = list(/datum/reagent/medicine/oculine = 0.1, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.05)
genes = list(/datum/plant_gene/trait/soil_lover)
/obj/item/food/grown/carrot
seed = /obj/item/seeds/carrot
@@ -91,7 +92,7 @@
species = "cahn'root"
plantname = "Cahn'root"
product = /obj/item/food/grown/cahnroot
genes = list(/datum/plant_gene/trait/plant_type/weed_hardy)
genes = list(/datum/plant_gene/trait/soil_lover, /datum/plant_gene/trait/plant_type/weed_hardy)
endurance = 50
instability = 10
icon_dead = "cahn'root-dead"
@@ -142,6 +143,7 @@
instability = 10
growing_icon = 'icons/obj/service/hydroponics/growing_vegetables.dmi'
icon_dead = "whitebeet-dead"
genes = list(/datum/plant_gene/trait/soil_lover)
mutatelist = list(/obj/item/seeds/redbeet)
reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/sugar = 0.2, /datum/reagent/consumable/nutriment = 0.05)
@@ -168,7 +170,7 @@
instability = 15
growing_icon = 'icons/obj/service/hydroponics/growing_vegetables.dmi'
icon_dead = "whitebeet-dead"
genes = list(/datum/plant_gene/trait/maxchem)
genes = list(/datum/plant_gene/trait/soil_lover, /datum/plant_gene/trait/maxchem)
reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.05, /datum/reagent/consumable/nutriment = 0.05)
graft_gene = /datum/plant_gene/trait/maxchem
+74 -89
View File
@@ -61,6 +61,11 @@
var/light_level = 0
///our snail overlay, if any
var/obj/effect/overlay/vis_effect/snail/our_snail
///Flags to indicate special tray type behaviours.
var/tray_flags = HYDROPONIC
///How many extra px to offset the plant sprite on the y axis, gets passed to the seed and added to the seeds offset
var/plant_offset_y = 0
/obj/machinery/hydroponics/Initialize(mapload)
//ALRIGHT YOU DEGENERATES. YOU HAD REAGENT HOLDERS FOR AT LEAST 4 YEARS AND NONE OF YOU MADE HYDROPONICS TRAYS HOLD NUTRIENT CHEMS INSTEAD OF USING "Points".
@@ -344,11 +349,11 @@
if(world.time > (lastcycle + cycledelay))
lastcycle = world.time
if(myseed && plant_status != HYDROTRAY_PLANT_DEAD)
// Advance age
age++
var/is_fungus = myseed.get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism)
// Advance age, if planted in mushroom friendly soil and we are a mushroom we mature 40% faster.
age += 1 * (is_fungus && (tray_flags & FAST_MUSHROOMS)) ? FAST_MUSH_MODIFIER : 1
if(age < myseed.maturation)
lastproduce = age
needs_update = TRUE
@@ -360,22 +365,25 @@
else
reagents.remove_all(nutridrain)
// Lack of nutrients hurts non-weeds
if(reagents.total_volume <= 0 && !myseed.get_gene(/datum/plant_gene/trait/plant_type/weed_hardy))
adjust_plant_health(-rand(1,3))
if(reagents.total_volume <= 0)
//The microbiome slowly create nutrients by fixing nitrogen from the air or metabolizing organic matter.
if(tray_flags & SLOW_RELEASE)
reagents.add_reagent(/datum/reagent/nitrogen, 1) // In reality the nitrogen is in the form of ammonia or nitrates but this might be too OP and boring.
// Lack of nutrients hurts non-weeds
else if(!myseed.get_gene(/datum/plant_gene/trait/plant_type/weed_hardy))
adjust_plant_health(-rand(1,3))
//Photosynthesis/////////////////////////////////////////////////////////
// Lack of light hurts non-mushrooms
var/is_fungus = myseed.get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism)
if(light_level < (is_fungus ? 0.2 : 0.4))
adjust_plant_health((is_fungus ? -1 : -2) / rating)
//Water//////////////////////////////////////////////////////////////////
// Drink random amount of water
adjust_waterlevel(-rand(1,6) / rating)
adjust_waterlevel(-rand(1,6) * ((tray_flags & SUPERWATER) ? SUPER_WATER_MODIFIER : 1) / rating )
// If the plant is dry, it loses health pretty fast, unless mushroom
if(waterlevel <= 10 && !myseed.get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
if(waterlevel <= 10 && !is_fungus)
adjust_plant_health(-rand(0,1) / rating)
if(waterlevel <= 0)
adjust_plant_health(-rand(0,2) / rating)
@@ -428,7 +436,7 @@
if(weedlevel >= 5 && !myseed.get_gene(/datum/plant_gene/trait/plant_type/weed_hardy))
if(myseed.yield >= 3)
myseed.adjust_yield(-rand(1,2)) //Weeds choke out the plant's ability to bear more fruit.
myseed.set_yield(min((myseed.yield), WEED_HARDY_YIELD_MIN, MAX_PLANT_YIELD))
myseed.set_yield(clamp((myseed.yield), WEED_HARDY_YIELD_MIN, MAX_PLANT_YIELD))
//This is the part with pollination
pollinate()
@@ -475,7 +483,7 @@
if(weedlevel >= 10 && prob(50) && !self_sustaining) // At this point the plant is kind of fucked. Weeds can overtake the plant spot.
if(myseed && myseed.yield >= 3)
myseed.adjust_yield(-rand(1,2)) //Loses even more yield per tick, quickly dropping to 3 minimum.
myseed.set_yield(min((myseed.yield), WEED_HARDY_YIELD_MIN, MAX_PLANT_YIELD))
myseed.set_yield(clamp((myseed.yield), WEED_HARDY_YIELD_MIN, MAX_PLANT_YIELD))
if(!myseed)
weedinvasion()
needs_update = 1
@@ -508,7 +516,7 @@
/obj/machinery/hydroponics/update_overlays()
. = ..()
if(myseed)
. += myseed.get_tray_overlay(age, plant_status)
. += myseed.get_tray_overlay(age, plant_status, plant_offset_y)
. += update_status_light_overlays()
if(self_sustaining && self_sustaining_overlay_icon_state)
@@ -667,8 +675,12 @@
* Raises the plant's weed level stat by a given amount.
* * adjustamt - Determines how much the weed level will be adjusted upwards or downwards.
*/
/obj/machinery/hydroponics/proc/adjust_weedlevel (amt)
set_weedlevel(clamp(weedlevel + amt, 0, MAX_TRAY_WEEDS), FALSE)
/obj/machinery/hydroponics/proc/adjust_weedlevel(amt)
var/weed_mod = 1
//If we are not a soil type tray and out plant is semiaquatic, increase weed.
if(!(tray_flags & SOIL) && myseed?.get_gene(/datum/plant_gene/trait/semiaquatic))
weed_mod *= SEMIAQUATIC_SOIL_WEED_MALUS
set_weedlevel(clamp(weedlevel + amt * weed_mod, 0, MAX_TRAY_WEEDS), FALSE)
/obj/machinery/hydroponics/examine(user)
. = ..()
@@ -793,13 +805,14 @@
* Plant Death Proc.
* Cleans up various stats for the plant upon death, including pests, harvestability, and plant health.
*/
/obj/machinery/hydroponics/proc/plantdies()
/obj/machinery/hydroponics/proc/plantdies(update_icon = TRUE)
set_plant_health(0, update_icon = FALSE, forced = TRUE)
set_plant_status(HYDROTRAY_PLANT_DEAD)
set_pestlevel(0, update_icon = FALSE) // Pests die
lastproduce = 0
update_appearance()
SEND_SIGNAL(src, COMSIG_HYDROTRAY_PLANT_DEATH)
if(update_icon)
update_appearance()
/**
* Plant Cross-Pollination.
@@ -879,6 +892,11 @@
visi_msg="[user] composts [reagent_source], spreading it through [target]"
transfer_amount = reagent_source.reagents.total_volume
SEND_SIGNAL(reagent_source, COMSIG_ITEM_ON_COMPOSTED, user)
if((tray_flags & WORM_HABITAT) && prob(transfer_amount / 2))
var/obj/item/food/bait/worm/premium/fat_worm = new(loc)
fat_worm.pixel_x = rand(-6,6)
fat_worm.pixel_y = rand(-6,6)
playsound(fat_worm, 'sound/items/eatfood.ogg', 20, TRUE)
else
transfer_amount = min(reagent_source.amount_per_transfer_from_this, reagent_source.reagents.total_volume)
if(istype(reagent_source, /obj/item/reagent_containers/syringe/))
@@ -919,21 +937,8 @@
return 1
else if(istype(O, /obj/item/seeds))
if(!myseed)
if(istype(O, /obj/item/seeds/kudzu))
investigate_log("had Kudzu planted in it by [key_name(user)] at [AREACOORD(src)].", INVESTIGATE_BOTANY)
if(!user.transferItemToLoc(O, src))
return
SEND_SIGNAL(O, COMSIG_SEED_ON_PLANTED, src)
to_chat(user, span_notice("You plant [O]."))
set_seed(O)
set_plant_health(myseed.endurance)
lastcycle = world.time
return
else
to_chat(user, span_warning("[src] already has seeds in it!"))
return
propagate_plant(O, user)
return
else if(istype(O, /obj/item/cultivator))
if(weedlevel > 0)
user.visible_message(span_notice("[user] uproots the weeds."), span_notice("You remove the weeds from [src]."))
@@ -950,8 +955,8 @@
else if(plant_status != HYDROTRAY_PLANT_HARVESTABLE)
to_chat(user, span_notice("This plant must be harvestable in order to be grafted."))
return
else if(myseed.grafted)
to_chat(user, span_notice("This plant has already been grafted."))
else if(myseed.grafts_taken >= ((tray_flags & MULTIGRAFT) ? MULTI_GRAFT_MAX_COUNT : 1))
to_chat(user, span_notice("You can't take any more cuttings from this plant!"))
return
else
user.visible_message(span_notice("[user] grafts off a limb from [src]."), span_notice("You carefully graft off a portion of [src]."))
@@ -960,7 +965,7 @@
return // The plant did not return a graft.
snip.forceMove(drop_location())
myseed.grafted = TRUE
myseed.grafts_taken++
adjust_plant_health(-5)
return
@@ -1003,12 +1008,17 @@
else if(istype(O, /obj/item/graft))
var/obj/item/graft/snip = O
if(!myseed)
if(tray_flags & GRAFT_MEDIUM)
propagate_plant(snip.plant_dna, user)
qdel(snip)
return
to_chat(user, span_notice("The tray is empty."))
return
if(myseed.apply_graft(snip))
to_chat(user, span_notice("You carefully integrate the grafted plant limb onto [myseed.plantname], granting it [snip.stored_trait.get_name()]."))
var/datum/plant_gene/grafted_trait = myseed.apply_graft(snip)
if(grafted_trait)
to_chat(user, span_notice("You carefully integrate the grafted plant limb onto [myseed.plantname], granting it [grafted_trait.get_name()]."))
else
to_chat(user, span_notice("You integrate the grafted plant limb onto [myseed.plantname], but it does not accept the [snip.stored_trait.get_name()] trait from the [snip]."))
to_chat(user, span_notice("You try to integrate the grafted plant limb onto [myseed.plantname], but it rejects the trait from the [snip]."))
qdel(snip)
return
@@ -1030,11 +1040,7 @@
span_notice("You start digging out [src]'s plants..."))
if(O.use_tool(src, user, 50, volume=50) || (!myseed && !weedlevel))
user.visible_message(span_notice("[user] digs out the plants in [src]!"), span_notice("You dig out all of [src]'s plants!"))
if(myseed) //Could be that they're just using it as a de-weeder
set_plant_health(0, update_icon = FALSE, forced = TRUE)
lastproduce = 0
set_seed(null)
set_weedlevel(0) //Has a side effect of cleaning up those nasty weeds
remove_plant()
return
else if(istype(O, /obj/item/gun/energy/floragun))
var/obj/item/gun/energy/floragun/flowergun = O
@@ -1167,54 +1173,33 @@
var/mob/living/C = new chosen(get_turf(src))
C.faction = list(FACTION_PLANTS)
///////////////////////////////////////////////////////////////////////////////
/obj/machinery/hydroponics/soil //Not actually hydroponics at all! Honk!
name = "soil"
desc = "A patch of dirt."
icon = 'icons/obj/service/hydroponics/equipment.dmi'
icon_state = "soil"
gender = PLURAL
circuit = null
density = FALSE
use_power = NO_POWER_USE
unwrenchable = FALSE
self_sustaining_overlay_icon_state = null
maxnutri = 15
/// Plants the seed / graft into the tray and resets growth related stats such as maturity on the tray.
/obj/machinery/hydroponics/proc/propagate_plant(obj/item/seeds/young_plant, mob/living/user)
if(!istype(young_plant))
return
if(myseed)
to_chat(user, span_warning("[src] already has a plant growing in it!"))
return
if(istype(young_plant, /obj/item/seeds/kudzu))
investigate_log("had Kudzu planted in it by [key_name(user)] at [AREACOORD(src)].", INVESTIGATE_BOTANY)
if(!user.transferItemToLoc(young_plant, src))
return
SEND_SIGNAL(young_plant, COMSIG_SEED_ON_PLANTED, src)
to_chat(user, span_notice("You plant [young_plant]."))
set_seed(young_plant)
set_plant_health(myseed.endurance)
lastcycle = world.time
/obj/machinery/hydroponics/soil/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver)
return NONE
/obj/machinery/hydroponics/soil/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct)
return NONE
/obj/machinery/hydroponics/soil/update_icon(updates=ALL)
. = ..()
if(self_sustaining)
add_atom_colour(rgb(255, 175, 0), FIXED_COLOUR_PRIORITY)
/obj/machinery/hydroponics/soil/update_status_light_overlays()
return // Has no lights
/obj/machinery/hydroponics/soil/attackby_secondary(obj/item/weapon, mob/user, list/modifiers, list/attack_modifiers)
if(weapon.tool_behaviour != TOOL_SHOVEL) //Spades can still uproot plants on left click
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
balloon_alert(user, "clearing up soil...")
if(weapon.use_tool(src, user, 1 SECONDS, volume=50))
balloon_alert(user, "cleared")
deconstruct(disassembled = TRUE)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/machinery/hydroponics/soil/click_ctrl(mob/user)
return CLICK_ACTION_BLOCKING //Soil has no electricity.
/obj/machinery/hydroponics/soil/on_deconstruction(disassembled)
new /obj/item/stack/ore/glass(drop_location(), 3)
/obj/machinery/hydroponics/soil/rich
name = "rich soil"
desc = "A rich patch of dirt, usually used in gardens."
icon_state = "rich_soil"
maxnutri = 20
/// Clears the plant from the tray, killing it in the process, optionally clearing weeds as well.
/obj/machinery/hydroponics/proc/remove_plant(clear_weeds = TRUE)
if(!myseed)
return
plantdies(FALSE)
if(clear_weeds)
set_weedlevel(0, FALSE)
if(self_sustaining) //No reason to pay for an empty tray.
set_self_sustaining(FALSE)
set_seed(null)
///The usb port circuit
+18
View File
@@ -988,3 +988,21 @@
/datum/plant_gene/trait/plant_type/alien_properties
name ="?????"
icon = FA_ICON_DISEASE
/datum/plant_gene/trait/carnivory
name = "Obligate Carnivory"
description = "Pests have positive effect on the plant health."
icon = FA_ICON_SPIDER
/datum/plant_gene/trait/semiaquatic
name = "Semiaquatic"
description = "A type of plant that thrives in flooded conditions due to less competion from weeds, but can also grow on land."
icon = FA_ICON_BOWL_RICE
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/datum/plant_gene/trait/soil_lover
name = "Soil Lover"
description = "A plant that needs the firm embrace of soil to develop properly, produces small irregular produce when grown hydroponically."
icon = FA_ICON_MOUND
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
+32 -36
View File
@@ -58,10 +58,10 @@
var/weed_rate = 1
///Percentage chance per tray update to grow weeds
var/weed_chance = 5
///Determines if the plant has had a graft removed or not.
var/grafted = FALSE
///How many grafts or cuttings have been taken from this plant.
var/grafts_taken = 0
///Type-path of trait to be applied when grafting a plant.
var/graft_gene
var/datum/plant_gene/graft_gene = /datum/plant_gene/trait/repeated_harvest
///Determines if the plant should be allowed to mutate early at 30+ instability.
var/seed_flags = MUTATE_EARLY
@@ -198,19 +198,22 @@
// Harvest procs
/obj/item/seeds/proc/getYield()
var/return_yield = yield
var/obj/machinery/hydroponics/parent = loc
// Handle hydroponics malus for soil lovers like rootcrops.
if(!(parent.tray_flags & SOIL) && get_gene(/datum/plant_gene/trait/soil_lover))
return_yield *= SOIL_LOVER_HYDRO_YIELD_MALUS
// Determine if the plant should get a yield bonus from bee pollination.
for(var/datum/plant_gene/trait/trait in genes)
if(trait.trait_flags & TRAIT_NO_POLLINATION)
return return_yield
var/obj/machinery/hydroponics/parent = loc
if(istype(loc, /obj/machinery/hydroponics))
if(parent.yieldmod == 0)
return_yield = min(return_yield, 1)//1 if above zero, 0 otherwise
else
return_yield *= (parent.yieldmod)
return return_yield
return round(return_yield)
/obj/item/seeds/proc/harvest(mob/user)
@@ -247,7 +250,13 @@
t_prod.seed.set_instability(round(instability * 0.5))
continue
else
t_prod = new product(output_loc, new_seed = src)
// Create a descendent seed so we can modify our offspring before creating a grown from it.
var/obj/item/seeds/descendent_seed = Copy()
// Cuck potency if a soil lover such as a root crop is grown in water.
if(!(parent.tray_flags & SOIL) && get_gene(/datum/plant_gene/trait/soil_lover))
descendent_seed.set_potency(round(potency * RANDOM_DECIMAL(SOIL_LOVER_HYDRO_POTENCY_MIN, SOIL_LOVER_HYDRO_POTENCY_MAX)))
t_prod = new product(output_loc, new_seed = descendent_seed)
if(parent.myseed.plantname != initial(parent.myseed.plantname))
t_prod.name = LOWER_TEXT(parent.myseed.plantname)
if(productdesc)
@@ -564,24 +573,11 @@
* Creates a graft from this plant.
*
* Creates a new graft from this plant.
* Sets the grafts trait to this plants graftable trait.
* Gives the graft a reference to this plant.
* Copies all the relevant stats from this plant to the graft.
* Passes this plant to the new graft so it can make a copy.
* Returns the created graft.
*/
/obj/item/seeds/proc/create_graft()
var/obj/item/graft/snip = new(loc, graft_gene)
snip.parent_name = plantname
snip.name += " ([plantname])"
// Copy over stats so the graft can outlive its parent.
snip.lifespan = lifespan
snip.endurance = endurance
snip.production = production
snip.weed_rate = weed_rate
snip.weed_chance = weed_chance
snip.yield = yield
var/obj/item/graft/snip = new(loc, src)
return snip
/**
@@ -596,25 +592,25 @@
* - [snip][/obj/item/graft]: The graft being used applied to this plant.
*/
/obj/item/seeds/proc/apply_graft(obj/item/graft/snip)
. = TRUE
var/datum/plant_gene/new_trait = snip.stored_trait
var/datum/plant_gene/new_trait = snip.plant_dna.graft_gene || /datum/plant_gene/trait/repeated_harvest
new_trait = new new_trait()
if(new_trait?.can_add(src))
genes += new_trait.Copy()
genes += new_trait
else
. = FALSE
return
// Adjust stats based on graft stats
set_lifespan(round(max(lifespan, (lifespan + (2/3)*(snip.lifespan - lifespan)))))
set_endurance(round(max(endurance, (endurance + (2/3)*(snip.endurance - endurance)))))
set_production(round(max(production, (production + (2/3)*(snip.production - production)))))
set_weed_rate(round(max(weed_rate, (weed_rate + (2/3)*(snip.weed_rate - weed_rate)))))
set_weed_chance(round(max(weed_chance, (weed_chance+ (2/3)*(snip.weed_chance - weed_chance)))))
set_yield(round(max(yield, (yield + (2/3)*(snip.yield - yield)))))
set_lifespan(round(max(lifespan, (lifespan + (2/3)*(snip.plant_dna.lifespan - lifespan)))))
set_endurance(round(max(endurance, (endurance + (2/3)*(snip.plant_dna.endurance - endurance)))))
set_production(round(max(production, (production + (2/3)*(snip.plant_dna.production - production)))))
set_weed_rate(round(max(weed_rate, (weed_rate + (2/3)*(snip.plant_dna.weed_rate - weed_rate)))))
set_weed_chance(round(max(weed_chance, (weed_chance+ (2/3)*(snip.plant_dna.weed_chance - weed_chance)))))
set_yield(round(max(yield, (yield + (2/3)*(snip.plant_dna.yield - yield)))))
// Add in any reagents, too.
reagents_from_genes()
return
// Return the new trait so the tray can know we were successful and display its name.
return new_trait
/*
* Both `/item/food/grown` and `/item/grown` implement a seed variable which tracks
@@ -659,7 +655,7 @@
reagents_from_genes()
/// Returns a mutable appearance to be used as an overlay for the plant in hydro trays.
/obj/item/seeds/proc/get_tray_overlay(age, status)
/obj/item/seeds/proc/get_tray_overlay(age, status, tray_offset)
var/mutable_appearance/plant_overlay = mutable_appearance(growing_icon, layer = OBJ_LAYER + 0.01)
switch(status)
if(HYDROTRAY_PLANT_DEAD)
@@ -669,7 +665,7 @@
else
var/t_growthstate = clamp(round((age / maturation) * growthstages), 1, growthstages)
plant_overlay.icon_state = "[icon_grow][t_growthstate]"
plant_overlay.pixel_z = plant_icon_offset
plant_overlay.pixel_z = plant_icon_offset + tray_offset
return plant_overlay
/// Called when the seed is set in a tray
+235
View File
@@ -0,0 +1,235 @@
///////////////////////////////////////////////////////////////////////////////
/obj/machinery/hydroponics/soil //Not actually hydroponics at all! Honk!
name = "soil"
desc = "A patch of dirt."
icon = 'icons/obj/service/hydroponics/equipment.dmi'
icon_state = "soil"
gender = PLURAL
circuit = null
density = FALSE
use_power = NO_POWER_USE
unwrenchable = FALSE
self_sustaining_overlay_icon_state = null
maxnutri = 15
tray_flags = SOIL
armor_type = /datum/armor/obj_soil
//which type of sack to create when shovled.
var/sack_type = /obj/item/soil_sack
/obj/machinery/hydroponics/soil/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver)
return NONE
/obj/machinery/hydroponics/soil/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct)
return NONE
/obj/machinery/hydroponics/soil/update_icon(updates=ALL)
. = ..()
if(self_sustaining)
add_atom_colour(rgb(255, 175, 0), FIXED_COLOUR_PRIORITY)
/obj/machinery/hydroponics/soil/update_status_light_overlays()
return // Has no lights
/obj/machinery/hydroponics/soil/attackby_secondary(obj/item/weapon, mob/user, list/modifiers, list/attack_modifiers)
if(weapon.tool_behaviour != TOOL_SHOVEL) //Spades can still uproot plants on left click
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
balloon_alert(user, "digging up soil...")
if(weapon.use_tool(src, user, 3 SECONDS, volume=50))
balloon_alert(user, "bagged")
new sack_type(loc, src) //The bag handles sucking up the soil, stopping processing and setting relevants stats.
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/machinery/hydroponics/soil/click_ctrl(mob/user)
return CLICK_ACTION_BLOCKING //Soil has no electricity.
/obj/machinery/hydroponics/soil/on_deconstruction(disassembled)
new /obj/item/stack/ore/glass(drop_location(), 3)
///called when a soil is plopped down on the ground.
/obj/machinery/hydroponics/soil/proc/on_place()
return
/datum/armor/obj_soil
melee = 80
bullet = 100
laser = 90
fire = 70
acid = 30
bomb = 15
/////////////// Advanced Soils //////////////
/obj/machinery/hydroponics/soil/vermaculite
name = "vermaculite growing medium"
desc = "A plant bed made of light, expanded mineral granules.\n\nThe plant health benefits from the high degree of soil aeration is especially useful for when propagating grafts."
icon_state = "soil_verm"
maxnutri = 20
maxwater = 150
tray_flags = SOIL | MULTIGRAFT | GRAFT_MEDIUM
sack_type = /obj/item/soil_sack/vermaculite
/obj/machinery/hydroponics/soil/gel
name = "hydrogel beads"
desc = "A plant bed made of superabsorbent polymer beads.\n\nThese types of water gel beads can hold onto an incredible amount of water and reduces evaporative losses to almost nothing."
icon_state = "soil_gel"
maxwater = 300
tray_flags = SOIL | HYDROPONIC | SUPERWATER
plant_offset_y = 2
sack_type = /obj/item/soil_sack/gel
/obj/machinery/hydroponics/soil/coir
name = "korta root coir"
desc = "A type of traditional growing medium from Tizira.\n\nUsed by the natives as a resourceful way to cultivate seraka mushrooms using waste korta roots.\nMushrooms of all kinds thrive due to the high organic content enabling them to mature faster."
icon_state = "soil_coir"
maxnutri = 20
tray_flags = SOIL | FAST_MUSHROOMS
sack_type = /obj/item/soil_sack/coir
/obj/machinery/hydroponics/soil/worm
name = "worm castings"
desc = "A type of compost created when the humble worm dutifully works the soil.\n\nIt is packed with nutrients unlocked by said creatures digestive system. Give thanks to the worm!"
icon_state = "soil_worm"
maxnutri = 35
maxwater = 200
tray_flags = SOIL | WORM_HABITAT | SLOW_RELEASE
plant_offset_y = 4
sack_type = /obj/item/soil_sack/worm
/obj/machinery/hydroponics/soil/worm/on_place()
. = ..()
flick("soil_worm_wiggle", src)
/obj/machinery/hydroponics/soil/rich
name = "rich soil"
desc = "A rich patch of dirt, usually used in gardens."
icon_state = "rich_soil"
maxnutri = 20
sack_type = /obj/item/soil_sack/rich
/////////////////// Soil Sacks ///////////////////////
/// Holder items that store the soils until deployed.
/obj/item/soil_sack
name = "soil sack"
desc = "A large plastic bag containing commercial garden soil. It is packed with sand, peat and manure. While you might not care much for such mixture, the plants have strange tastes."
icon = 'icons/obj/service/hydroponics/equipment.dmi'
icon_state = "soil_sack"
lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
base_icon_state = "soil_sack"
force = 7
throwforce = 17
attack_speed = 1.2 SECONDS
damtype = STAMINA
block_sound = 'sound/effects/bodyfall/bodyfall1.ogg'
w_class = WEIGHT_CLASS_HUGE
item_flags = SLOWS_WHILE_IN_HAND
resistance_flags = ACID_PROOF
hitsound = 'sound/items/pillow/pillow_hit.ogg'
drop_sound = 'sound/effects/footstep/woodbarefoot3.ogg' //could use better sounds in the future.
throw_drop_sound = 'sound/effects/bodyfall/bodyfall3.ogg'
custom_premium_price = PAYCHECK_CREW
throw_range = 3
throw_speed = 1
slowdown = 1
drag_slowdown = 1
var/obj/machinery/hydroponics/soil/stored_soil = /obj/machinery/hydroponics/soil
var/placement_sound = 'sound/effects/soil_plop.ogg'
/obj/item/soil_sack/Initialize(mapload, obj/machinery/hydroponics/soil/outside_soil)
. = ..()
AddComponent(/datum/component/two_handed, force_multiplier = 2, wield_callback = CALLBACK(src, PROC_REF(on_wield)), unwield_callback = CALLBACK(src, PROC_REF(on_unwield)))
if(outside_soil)
stored_soil = outside_soil
stored_soil.remove_plant()
stored_soil.forceMove(src)
STOP_PROCESSING(SSmachines, stored_soil)
animate(src, 100 MILLISECONDS, pixel_z = 4, easing = QUAD_EASING | EASE_OUT)
animate(time = 100 MILLISECONDS, pixel_z = 0, easing = QUAD_EASING | EASE_IN)
animate(time = 250 MILLISECONDS, pixel_x = rand(-6, 6), pixel_y = rand(-4, 4), flags = ANIMATION_PARALLEL)
/obj/item/soil_sack/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!isopenturf(interacting_with) || isgroundlessturf(interacting_with))
return ..()
if(locate(/obj/machinery/hydroponics/soil) in interacting_with)
to_chat(user, span_alert("There is already a bed of soil there!"))
return ITEM_INTERACT_BLOCKING
if(!do_after(user, 1 SECONDS, interacting_with))
return ITEM_INTERACT_BLOCKING
if(ispath(stored_soil))
stored_soil = new stored_soil(src)
stored_soil.reagents.add_reagent(/datum/reagent/plantnutriment/eznutriment, stored_soil.maxnutri / 2)
stored_soil.waterlevel = stored_soil.maxwater
else
START_PROCESSING(SSmachines, stored_soil)
stored_soil.forceMove(interacting_with)
playsound(stored_soil, placement_sound, 65, vary = TRUE)
stored_soil.on_place()
qdel(src)
return ITEM_INTERACT_SUCCESS
///Remove slowdown and add block chance when wielded.
/obj/item/soil_sack/proc/on_wield()
slowdown = 0
if(ismob(loc))
var/mob/wearer = loc
wearer.update_equipment_speed_mods()
block_chance = 25
inhand_icon_state = "[base_icon_state]_w"
///Reapply slowdown and remove block chance when unwielded.
/obj/item/soil_sack/proc/on_unwield()
slowdown = initial(slowdown)
if(ismob(loc))
var/mob/wearer = loc
wearer.update_equipment_speed_mods()
block_chance = initial(block_chance)
inhand_icon_state = base_icon_state
/obj/item/soil_sack/vermaculite
name = "NT vermaculite sack"
desc = "A sack of expanded mineral granules that can be used as soilless growing medium.\n\nYou like to think of it a bag of rocky popcorn that lets the roots breathe."
icon_state = "soil_sack_verm"
base_icon_state = "soil_sack_verm"
custom_premium_price = PAYCHECK_CREW * 2
stored_soil = /obj/machinery/hydroponics/soil/vermaculite
slowdown = 0
/obj/item/soil_sack/gel
name = "hydrogel bead sack"
desc = "A sack of space age superabsorbent gel beads! You wonder how shipping them prehydrated would ever make business sense..."
icon_state = "soil_sack_gel"
base_icon_state = "soil_sack_gel"
custom_premium_price = PAYCHECK_CREW * 2
placement_sound = 'sound/effects/meatslap.ogg'
stored_soil = /obj/machinery/hydroponics/soil/gel
/obj/item/soil_sack/coir
name = "#1™ korta coir sack"
desc = "A sack of Tiziran korta root coir. The fiberous roots are composted until they separate into individual fibres.\n\nProvides an excellent food source for saprotrophic mushrooms and helps hold onto water in the hot Tizirian climate."
icon_state = "soil_sack_coir"
base_icon_state = "soil_sack_coir"
custom_premium_price = PAYCHECK_CREW * 3
stored_soil = /obj/machinery/hydroponics/soil/coir
/obj/item/soil_sack/worm
name = "worm castings sack"
desc = "A sack of vermicompost, also known as worm castings.\n\nThis invertebrate manure not only contains plant nutrients and undigested organic matter, it also harbours a rich flora of beneficial microorganisms."
icon_state = "soil_sack_worm"
base_icon_state = "soil_sack_worm"
custom_premium_price = PAYCHECK_CREW * 4
stored_soil = /obj/machinery/hydroponics/soil/worm
/obj/item/soil_sack/rich
name = "rich soil sack"
desc = "A sack of rich black soil.\nAs your gaze falls upon it, you feel a bit more connected to the land."
custom_premium_price = PAYCHECK_CREW * 1.5
stored_soil = /obj/machinery/hydroponics/soil/rich