From 93cf4f73c5553fca288ab0d30a4060e18c68209f Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Sun, 1 Feb 2015 20:02:59 +1030 Subject: [PATCH] More work on the vine system, fixing multiple bugs. --- baystation12.dme | 19 +- .../machinery}/biogenerator.dm | 0 code/game/turfs/simulated.dm | 10 +- code/modules/hydroponics/_hydro_setup.dm | 3 + code/modules/hydroponics/grown.dm | 2 +- code/modules/hydroponics/seed.dm | 773 +++++++++++++++++ code/modules/hydroponics/seed_datums.dm | 775 ------------------ .../hydroponics/{seeds.dm => seed_packets.dm} | 0 .../spreading.dm} | 98 +-- .../hydroponics/spreading/spreading_growth.dm | 75 ++ .../spreading/spreading_response.dm | 74 ++ .../{hydro_tray.dm => trays/tray.dm} | 273 +----- .../hydroponics/trays/tray_apiary.dm} | 0 .../modules/hydroponics/trays/tray_process.dm | 125 +++ .../hydroponics/trays/tray_reagents.dm | 143 ++++ code/modules/hydroponics/trays/tray_soil.dm | 68 ++ .../{hydro_tools.dm => trays/tray_tools.dm} | 0 .../hydroponics/trays/tray_update_icons.dm | 74 ++ 18 files changed, 1372 insertions(+), 1140 deletions(-) rename code/{modules/hydroponics => game/machinery}/biogenerator.dm (100%) create mode 100644 code/modules/hydroponics/seed.dm rename code/modules/hydroponics/{seeds.dm => seed_packets.dm} (100%) rename code/modules/hydroponics/{spread_plant.dm => spreading/spreading.dm} (65%) create mode 100644 code/modules/hydroponics/spreading/spreading_growth.dm create mode 100644 code/modules/hydroponics/spreading/spreading_response.dm rename code/modules/hydroponics/{hydro_tray.dm => trays/tray.dm} (64%) rename code/{game/machinery/bees_apiary.dm => modules/hydroponics/trays/tray_apiary.dm} (100%) create mode 100644 code/modules/hydroponics/trays/tray_process.dm create mode 100644 code/modules/hydroponics/trays/tray_reagents.dm create mode 100644 code/modules/hydroponics/trays/tray_soil.dm rename code/modules/hydroponics/{hydro_tools.dm => trays/tray_tools.dm} (100%) create mode 100644 code/modules/hydroponics/trays/tray_update_icons.dm diff --git a/baystation12.dme b/baystation12.dme index 265b12f047..5216e12a41 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -303,6 +303,7 @@ #include "code\game\machinery\autolathe_datums.dm" #include "code\game\machinery\Beacon.dm" #include "code\game\machinery\bees_items.dm" +#include "code\game\machinery\biogenerator.dm" #include "code\game\machinery\bioprinter.dm" #include "code\game\machinery\buttons.dm" #include "code\game\machinery\cell_charger.dm" @@ -957,18 +958,24 @@ #include "code\modules\games\cards.dm" #include "code\modules\genetics\side_effects.dm" #include "code\modules\hydroponics\_hydro_setup.dm" -#include "code\modules\hydroponics\bees_apiary.dm" -#include "code\modules\hydroponics\biogenerator.dm" #include "code\modules\hydroponics\grown.dm" #include "code\modules\hydroponics\grown_inedible.dm" -#include "code\modules\hydroponics\hydro_tools.dm" -#include "code\modules\hydroponics\hydro_tray.dm" +#include "code\modules\hydroponics\seed.dm" #include "code\modules\hydroponics\seed_datums.dm" #include "code\modules\hydroponics\seed_machines.dm" #include "code\modules\hydroponics\seed_mobs.dm" #include "code\modules\hydroponics\seed_storage.dm" -#include "code\modules\hydroponics\seeds.dm" -#include "code\modules\hydroponics\spread_plant.dm" +#include "code\modules\hydroponics\seed_packets.dm" +#include "code\modules\hydroponics\spreading\spreading.dm" +#include "code\modules\hydroponics\spreading\spreading_growth.dm" +#include "code\modules\hydroponics\spreading\spreading_response.dm" +#include "code\modules\hydroponics\trays\tray.dm" +#include "code\modules\hydroponics\trays\tray_apiary.dm" +#include "code\modules\hydroponics\trays\tray_process.dm" +#include "code\modules\hydroponics\trays\tray_reagents.dm" +#include "code\modules\hydroponics\trays\tray_soil.dm" +#include "code\modules\hydroponics\trays\tray_tools.dm" +#include "code\modules\hydroponics\trays\tray_update_icons.dm" #include "code\modules\library\lib_items.dm" #include "code\modules\library\lib_machines.dm" #include "code\modules\library\lib_readme.dm" diff --git a/code/modules/hydroponics/biogenerator.dm b/code/game/machinery/biogenerator.dm similarity index 100% rename from code/modules/hydroponics/biogenerator.dm rename to code/game/machinery/biogenerator.dm diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm index ae5d68582d..0aabdae3d0 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -25,11 +25,17 @@ usr << "\red Movement is admin-disabled." //This is to identify lag problems return - if (istype(A,/mob/living/carbon)) - var/mob/living/carbon/M = A + if (istype(A,/mob/living)) + var/mob/living/M = A if(M.lying) ..() return + + // Ugly hack :( Should never have multiple plants in the same tile. + var/obj/effect/plant/plant = locate() in contents + if(plant) plant.trodden_on(M) + + // Dirt overlays. dirt++ var/obj/effect/decal/cleanable/dirt/dirtoverlay = locate(/obj/effect/decal/cleanable/dirt, src) if (dirt >= 50) diff --git a/code/modules/hydroponics/_hydro_setup.dm b/code/modules/hydroponics/_hydro_setup.dm index c18043395c..05e4a8dae4 100644 --- a/code/modules/hydroponics/_hydro_setup.dm +++ b/code/modules/hydroponics/_hydro_setup.dm @@ -1,3 +1,6 @@ +//Misc +#define DEAD_PLANT_COLOUR "#C2A180" + // Definitions for genes (trait groupings) #define GENE_PRODUCTS "products" #define GENE_CONSUMPTION "consumption" diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 2d6e70033e..9a53ba5a22 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -172,7 +172,7 @@ return if(!reagents || reagents.total_volume <= 0) return - reagents.remove_any(rand(1,3)) + reagents.remove_any(rand(1,3)) //Todo, make it actually remove the reagents the seed uses. seed.do_thorns(H,src) seed.do_sting(H,src,pick("r_hand","l_hand")) diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm new file mode 100644 index 0000000000..e417c115dc --- /dev/null +++ b/code/modules/hydroponics/seed.dm @@ -0,0 +1,773 @@ +// Sprite lists. +var/global/list/plant_sprites = list() // List of all harvested product sprites. +var/global/list/plant_product_sprites = list() // List of all growth sprites plus number of growth stages. + +// Proc for creating a random seed type. +/proc/create_random_seed(var/survive_on_station) + var/datum/seed/seed = new() + seed.randomize() + seed.uid = seed_types.len + 1 + seed.name = "[seed.uid]" + seed_types[seed.name] = seed + + if(survive_on_station) + if(seed.consume_gasses) + seed.consume_gasses["phoron"] = null + seed.consume_gasses["carbon_dioxide"] = null + seed.set_trait(TRAIT_IDEAL_HEAT,293) + seed.set_trait(TRAIT_HEAT_TOLERANCE,20) + seed.set_trait(TRAIT_IDEAL_LIGHT,8) + seed.set_trait(TRAIT_LIGHT_TOLERANCE,5) + seed.set_trait(TRAIT_LOWKPA_TOLERANCE,25) + seed.set_trait(TRAIT_HIGHKPA_TOLERANCE,200) + + return seed + +// Debug for testing seed genes. +/client/proc/show_plant_genes() + set category = "Debug" + set name = "Show Plant Genes" + set desc = "Prints the round's plant gene masks." + + if(!holder) return + + if(!gene_tag_masks) + usr << "Gene masks not set." + return + + for(var/mask in gene_tag_masks) + usr << "[mask]: [gene_tag_masks[mask]]" + +// Predefined/roundstart varieties use a string key to make it +// easier to grab the new variety when mutating. Post-roundstart +// and mutant varieties use their uid converted to a string instead. +// Looks like shit but it's sort of necessary. + +proc/populate_seed_list() + + // Build the icon lists. + for(var/icostate in icon_states('icons/obj/hydroponics_growing.dmi')) + var/split = findtext(icostate,"-") + if(!split) + // invalid icon_state + continue + + var/ikey = copytext(icostate,(split+1)) + if(ikey == "dead") + // don't count dead icons + continue + ikey = text2num(ikey) + var/base = copytext(icostate,1,split) + + if(!(plant_sprites[base]) || (plant_sprites[base]\The [fruit]'s thorns pierce your [affecting.display_name] greedily!" + else + target << "\The [fruit]'s thorns pierce your flesh greedily!" + damage = get_trait(TRAIT_POTENCY)/2 + else + if(affecting) + target << "\The [fruit]'s thorns dig deeply into your [affecting.display_name]!" + else + target << "\The [fruit]'s thorns dig deeply into your flesh!" + damage = get_trait(TRAIT_POTENCY)/5 + else + return + + if(affecting) + affecting.take_damage(damage, 0) + affecting.add_autopsy_data("Thorns",damage) + else + target.adjustBruteLoss(damage) + target.UpdateDamageIcon() + target.updatehealth() + +// Adds reagents to a target. +/datum/seed/proc/do_sting(var/mob/living/carbon/human/target, var/obj/item/fruit) + if(!get_trait(TRAIT_STINGS)) + return + if(chems && chems.len) + target << "You are stung by \the [fruit]!" + for(var/rid in chems) + var/injecting = min(5,max(1,get_trait(TRAIT_POTENCY)/5)) + target.reagents.add_reagent(rid,injecting) + +//Splatter a turf. +/datum/seed/proc/splatter(var/turf/T,var/obj/item/thrown) + if(splat_type) + var/obj/effect/plant/splat = new splat_type(T, src) + if(!istype(splat)) // Plants handle their own stuff. + splat.name = "[thrown.name] [pick("smear","smudge","splatter")]" + if(get_trait(TRAIT_BIOLUM)) + if(get_trait(TRAIT_BIOLUM_COLOUR)) + splat.l_color = get_trait(TRAIT_BIOLUM_COLOUR) + splat.SetLuminosity(get_trait(TRAIT_BIOLUM)) + if(get_trait(TRAIT_PRODUCT_COLOUR)) + splat.color = get_trait(TRAIT_PRODUCT_COLOUR) + + if(chems) + for(var/mob/living/M in T.contents) + if(!M.reagents) + continue + for(var/chem in chems) + var/injecting = min(5,max(1,get_trait(TRAIT_POTENCY)/3)) + M.reagents.add_reagent(chem,injecting) + +//Applies an effect to a target atom. +/datum/seed/proc/thrown_at(var/obj/item/thrown,var/atom/target, var/force_explode) + + var/splatted + var/turf/origin_turf = get_turf(target) + + if(force_explode || get_trait(TRAIT_EXPLOSIVE)) + + var/flood_dist = min(10,max(1,get_trait(TRAIT_POTENCY)/15)) + var/list/open_turfs = list() + var/list/closed_turfs = list() + var/list/valid_turfs = list() + open_turfs |= origin_turf + + // Flood fill to get affected turfs. + while(open_turfs.len) + var/turf/T = pick(open_turfs) + open_turfs -= T + closed_turfs |= T + valid_turfs |= T + + for(var/dir in alldirs) + var/turf/neighbor = get_step(T,dir) + if(!neighbor || (neighbor in closed_turfs) || (neighbor in open_turfs)) + continue + if(neighbor.density || get_dist(neighbor,origin_turf) > flood_dist || istype(neighbor,/turf/space)) + closed_turfs |= neighbor + continue + // Check for windows. + var/no_los + var/turf/last_turf = origin_turf + for(var/turf/target_turf in getline(origin_turf,neighbor)) + if(!last_turf.Enter(target_turf) || target_turf.density) + no_los = 1 + break + last_turf = target_turf + if(!no_los && !origin_turf.Enter(neighbor)) + no_los = 1 + if(no_los) + closed_turfs |= neighbor + continue + open_turfs |= neighbor + + for(var/turf/T in valid_turfs) + for(var/mob/living/M in T.contents) + apply_special_effect(M) + splatter(T,thrown) + origin_turf.visible_message("The [thrown.name] explodes!") + del(thrown) + return + + if(istype(target,/mob/living)) + splatted = apply_special_effect(target,thrown) + else if(istype(target,/turf)) + splatted = 1 + for(var/mob/living/M in target.contents) + apply_special_effect(M) + + if(get_trait(TRAIT_JUICY) && splatted) + splatter(origin_turf,thrown) + origin_turf.visible_message("The [thrown.name] splatters against [target]!") + del(thrown) + +/datum/seed/proc/handle_environment(var/turf/current_turf, var/datum/gas_mixture/environment, var/check_only) + + var/health_change = 0 + // Handle gas consumption. + if(consume_gasses && consume_gasses.len) + var/missing_gas = 0 + for(var/gas in consume_gasses) + if(environment && environment.gas && environment.gas[gas] && \ + environment.gas[gas] >= consume_gasses[gas]) + if(!check_only) + environment.adjust_gas(gas,-consume_gasses[gas],1) + else + missing_gas++ + + if(missing_gas > 0) + health_change += missing_gas * HYDRO_SPEED_MULTIPLIER + + // Process it. + var/pressure = environment.return_pressure() + if(pressure < get_trait(TRAIT_LOWKPA_TOLERANCE)|| pressure > get_trait(TRAIT_HIGHKPA_TOLERANCE)) + health_change += rand(1,3) * HYDRO_SPEED_MULTIPLIER + + if(abs(environment.temperature - get_trait(TRAIT_IDEAL_HEAT)) > get_trait(TRAIT_HEAT_TOLERANCE)) + health_change += rand(1,3) * HYDRO_SPEED_MULTIPLIER + + // Handle gas production. + if(exude_gasses && exude_gasses.len && !check_only) + for(var/gas in exude_gasses) + environment.adjust_gas(gas, max(1,round((exude_gasses[gas]*get_trait(TRAIT_POTENCY))/exude_gasses.len))) + + // Handle light requirements. + var/area/A = get_area(current_turf) + if(A) + var/light_available + if(A.lighting_use_dynamic) + light_available = max(0,min(10,current_turf.lighting_lumcount)-5) + else + light_available = 5 + if(abs(light_available - get_trait(TRAIT_IDEAL_LIGHT)) > get_trait(TRAIT_LIGHT_TOLERANCE)) + health_change += rand(1,3) * HYDRO_SPEED_MULTIPLIER + + return health_change + +/datum/seed/proc/apply_special_effect(var/mob/living/target,var/obj/item/thrown) + + var/impact = 1 + do_sting(target,thrown) + do_thorns(target,thrown) + + // Bluespace tomato code copied over from grown.dm. + if(get_trait(TRAIT_TELEPORTING)) + + //Plant potency determines radius of teleport. + var/outer_teleport_radius = get_trait(TRAIT_POTENCY)/5 + var/inner_teleport_radius = get_trait(TRAIT_POTENCY)/15 + + var/list/turfs = list() + if(inner_teleport_radius > 0) + for(var/turf/T in orange(target,outer_teleport_radius)) + if(get_dist(target,T) >= inner_teleport_radius) + turfs |= T + + if(turfs.len) + // Moves the mob, causes sparks. + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, get_turf(target)) + s.start() + var/turf/picked = get_turf(pick(turfs)) // Just in case... + new/obj/effect/decal/cleanable/molten_item(get_turf(target)) // Leave a pile of goo behind for dramatic effect... + target.loc = picked // And teleport them to the chosen location. + + impact = 1 + + return impact + +//Creates a random seed. MAKE SURE THE LINE HAS DIVERGED BEFORE THIS IS CALLED. +/datum/seed/proc/randomize() + + roundstart = 0 + seed_name = "strange plant" // TODO: name generator. + display_name = "strange plants" // TODO: name generator. + mysterious = 1 + seed_noun = pick("spores","nodes","cuttings","seeds") + products = list(pick(typesof(/obj/item/weapon/reagent_containers/food/snacks/grown)-/obj/item/weapon/reagent_containers/food/snacks/grown)) + + set_trait(TRAIT_POTENCY,rand(5,30),200,0) + set_trait(TRAIT_PRODUCT_ICON,pick(plant_product_sprites)) + set_trait(TRAIT_PLANT_ICON,pick(plant_sprites)) + set_trait(TRAIT_PLANT_COLOUR,"#[get_random_colour(0,75,190)]") + set_trait(TRAIT_PRODUCT_COLOUR,"#[get_random_colour(0,75,190)]") + update_growth_stages() + + if(prob(20)) + set_trait(TRAIT_HARVEST_REPEAT,1) + + if(prob(15)) + if(prob(15)) + set_trait(TRAIT_JUICY,2) + else + set_trait(TRAIT_JUICY,1) + + if(prob(5)) + set_trait(TRAIT_STINGS,1) + + if(prob(5)) + set_trait(TRAIT_PRODUCES_POWER,1) + + if(prob(1)) + set_trait(TRAIT_EXPLOSIVE,1) + else if(prob(1)) + set_trait(TRAIT_TELEPORTING,1) + + if(prob(5)) + consume_gasses = list() + var/gas = pick("oxygen","nitrogen","phoron","carbon_dioxide") + consume_gasses[gas] = rand(3,9) + + if(prob(5)) + exude_gasses = list() + var/gas = pick("oxygen","nitrogen","phoron","carbon_dioxide") + exude_gasses[gas] = rand(3,9) + + chems = list() + if(prob(80)) + chems["nutriment"] = list(rand(1,10),rand(10,20)) + + var/additional_chems = rand(0,5) + + if(additional_chems) + var/list/possible_chems = list( + "bicaridine", + "hyperzine", + "cryoxadone", + "blood", + "water", + "potassium", + "plasticide", + "mutationtoxin", + "amutationtoxin", + "inaprovaline", + "space_drugs", + "paroxetine", + "mercury", + "sugar", + "radium", + "ryetalyn", + "alkysine", + "thermite", + "tramadol", + "cryptobiolin", + "dermaline", + "dexalin", + "phoron", + "synaptizine", + "impedrezene", + "hyronalin", + "peridaxon", + "toxin", + "rezadone", + "ethylredoxrazine", + "slimejelly", + "cyanide", + "mindbreaker", + "stoxin" + ) + + for(var/x=1;x<=additional_chems;x++) + if(!possible_chems.len) + break + var/new_chem = pick(possible_chems) + possible_chems -= new_chem + chems[new_chem] = list(rand(1,10),rand(10,20)) + + if(prob(90)) + set_trait(TRAIT_REQUIRES_NUTRIENTS,1) + set_trait(TRAIT_NUTRIENT_CONSUMPTION,rand(100)*0.1) + else + set_trait(TRAIT_REQUIRES_NUTRIENTS,0) + + if(prob(90)) + set_trait(TRAIT_REQUIRES_WATER,1) + set_trait(TRAIT_WATER_CONSUMPTION,rand(10)) + else + set_trait(TRAIT_REQUIRES_WATER,0) + + set_trait(TRAIT_IDEAL_HEAT, rand(100,400)) + set_trait(TRAIT_HEAT_TOLERANCE, rand(10,30)) + set_trait(TRAIT_IDEAL_LIGHT, rand(2,10)) + set_trait(TRAIT_LIGHT_TOLERANCE, rand(2,7)) + set_trait(TRAIT_TOXINS_TOLERANCE, rand(2,7)) + set_trait(TRAIT_PEST_TOLERANCE, rand(2,7)) + set_trait(TRAIT_WEED_TOLERANCE, rand(2,7)) + set_trait(TRAIT_LOWKPA_TOLERANCE, rand(10,50)) + set_trait(TRAIT_HIGHKPA_TOLERANCE,rand(100,300)) + + if(prob(5)) + set_trait(TRAIT_ALTER_TEMP,rand(-5,5)) + + if(prob(1)) + set_trait(TRAIT_IMMUTABLE,-1) + + var/carnivore_prob = rand(100) + if(carnivore_prob < 5) + set_trait(TRAIT_CARNIVOROUS,2) + else if(carnivore_prob < 10) + set_trait(TRAIT_CARNIVOROUS,1) + + if(prob(10)) + set_trait(TRAIT_PARASITE,1) + + var/vine_prob = rand(100) + if(vine_prob < 5) + set_trait(TRAIT_SPREAD,2) + else if(vine_prob < 10) + set_trait(TRAIT_SPREAD,1) + + if(prob(5)) + set_trait(TRAIT_BIOLUM,1) + set_trait(TRAIT_BIOLUM_COLOUR,"#[get_random_colour(0,75,190)]") + + set_trait(TRAIT_ENDURANCE,rand(60,100)) + set_trait(TRAIT_YIELD,rand(3,15)) + set_trait(TRAIT_MATURATION,rand(5,15)) + set_trait(TRAIT_PRODUCTION,get_trait(TRAIT_MATURATION)+rand(2,5)) + +//Returns a key corresponding to an entry in the global seed list. +/datum/seed/proc/get_mutant_variant() + if(!mutants || !mutants.len || get_trait(TRAIT_IMMUTABLE) > 0) return 0 + return pick(mutants) + +//Mutates the plant overall (randomly). +/datum/seed/proc/mutate(var/degree,var/turf/source_turf) + + if(!degree || get_trait(TRAIT_IMMUTABLE) > 0) return + + source_turf.visible_message("\The [display_name] quivers!") + + //This looks like shit, but it's a lot easier to read/change this way. + var/total_mutations = rand(1,1+degree) + for(var/i = 0;i\The [display_name] withers rapidly!") + if(1) + set_trait(TRAIT_NUTRIENT_CONSUMPTION,get_trait(TRAIT_NUTRIENT_CONSUMPTION)+rand(-(degree*0.1),(degree*0.1)),5,0) + set_trait(TRAIT_WATER_CONSUMPTION, get_trait(TRAIT_WATER_CONSUMPTION) +rand(-degree,degree),50,0) + set_trait(TRAIT_JUICY, !get_trait(TRAIT_JUICY)) + set_trait(TRAIT_STINGS, !get_trait(TRAIT_STINGS)) + if(2) + set_trait(TRAIT_IDEAL_HEAT, get_trait(TRAIT_IDEAL_HEAT) + (rand(-5,5)*degree),800,70) + set_trait(TRAIT_HEAT_TOLERANCE, get_trait(TRAIT_HEAT_TOLERANCE) + (rand(-5,5)*degree),800,70) + set_trait(TRAIT_LOWKPA_TOLERANCE, get_trait(TRAIT_LOWKPA_TOLERANCE)+ (rand(-5,5)*degree),80,0) + set_trait(TRAIT_HIGHKPA_TOLERANCE, get_trait(TRAIT_HIGHKPA_TOLERANCE)+(rand(-5,5)*degree),500,110) + set_trait(TRAIT_EXPLOSIVE,1) + if(3) + set_trait(TRAIT_IDEAL_LIGHT, get_trait(TRAIT_IDEAL_LIGHT)+(rand(-1,1)*degree),30,0) + set_trait(TRAIT_LIGHT_TOLERANCE, get_trait(TRAIT_LIGHT_TOLERANCE)+(rand(-2,2)*degree),10,0) + if(4) + set_trait(TRAIT_TOXINS_TOLERANCE, get_trait(TRAIT_TOXINS_TOLERANCE)+(rand(-2,2)*degree),10,0) + if(5) + set_trait(TRAIT_WEED_TOLERANCE, get_trait(TRAIT_WEED_TOLERANCE)+(rand(-2,2)*degree),10, 0) + if(prob(degree*5)) + set_trait(TRAIT_CARNIVOROUS, get_trait(TRAIT_CARNIVOROUS)+rand(-degree,degree),2, 0) + if(get_trait(TRAIT_CARNIVOROUS)) + source_turf.visible_message("\The [display_name] shudders hungrily.") + if(6) + set_trait(TRAIT_WEED_TOLERANCE, get_trait(TRAIT_WEED_TOLERANCE)+(rand(-2,2)*degree),10, 0) + if(prob(degree*5)) + set_trait(TRAIT_PARASITE,!get_trait(TRAIT_PARASITE)) + if(7) + if(get_trait(TRAIT_YIELD) != -1) + set_trait(TRAIT_YIELD, get_trait(TRAIT_YIELD)+(rand(-2,2)*degree),10,0) + if(8) + set_trait(TRAIT_ENDURANCE, get_trait(TRAIT_ENDURANCE)+(rand(-5,5)*degree),100,10) + set_trait(TRAIT_PRODUCTION, get_trait(TRAIT_PRODUCTION)+(rand(-1,1)*degree),10, 1) + set_trait(TRAIT_POTENCY, get_trait(TRAIT_POTENCY)+(rand(-20,20)*degree),200, 0) + if(prob(degree*5)) + set_trait(TRAIT_SPREAD, get_trait(TRAIT_SPREAD)+rand(-1,1),2, 0) + source_turf.visible_message("\The [display_name] spasms visibly, shifting in the tray.") + if(9) + set_trait(TRAIT_MATURATION, get_trait(TRAIT_MATURATION)+(rand(-1,1)*degree),30, 0) + if(prob(degree*5)) + set_trait(TRAIT_HARVEST_REPEAT, !get_trait(TRAIT_HARVEST_REPEAT)) + if(10) + if(prob(degree*2)) + set_trait(TRAIT_BIOLUM, !get_trait(TRAIT_BIOLUM)) + if(get_trait(TRAIT_BIOLUM)) + source_turf.visible_message("\The [display_name] begins to glow!") + if(prob(degree*2)) + set_trait(TRAIT_BIOLUM_COLOUR,"#[get_random_colour(0,75,190)]") + source_turf.visible_message("\The [display_name]'s glow changes colour!") + else + source_turf.visible_message("\The [display_name]'s glow dims...") + if(11) + set_trait(TRAIT_TELEPORTING,1) + + return + +//Mutates a specific trait/set of traits. +/datum/seed/proc/apply_gene(var/datum/plantgene/gene) + + if(!gene || !gene.values || get_trait(TRAIT_IMMUTABLE) > 0) return + + // Splicing products has some detrimental effects on yield and lifespan. + // We handle this before we do the rest of the looping, as normal traits don't really include lists. + if(gene.genetype == GENE_PRODUCTS) + for(var/trait in list(TRAIT_YIELD, TRAIT_ENDURANCE)) + if(get_trait(trait) > 0) set_trait(trait,get_trait(trait),null,1,0.85) + + if(!products) products = list() + products |= gene.values["[TRAIT_PRODUCTS]"] + + if(!chems) chems = list() + + var/list/gene_value = gene.values["[TRAIT_CHEMS]"] + for(var/rid in gene_value) + + var/list/gene_chem = gene_value[rid] + + if(!chems[rid]) + chems[rid] = gene_chem.Copy() + continue + + for(var/i=1;i<=gene_chem.len;i++) + + if(isnull(gene_chem[i])) gene_chem[i] = 0 + + if(chems[rid][i]) + chems[rid][i] = max(1,round((gene_chem[i] + chems[rid][i])/2)) + else + chems[rid][i] = gene_chem[i] + + var/list/new_gasses = gene.values["[TRAIT_EXUDE_GASSES]"] + if(islist(new_gasses)) + if(!exude_gasses) exude_gasses = list() + exude_gasses |= new_gasses + for(var/gas in exude_gasses) + exude_gasses[gas] = max(1,round(exude_gasses[gas]*0.8)) + + for(var/trait in gene.values) + set_trait(trait,gene.values["[trait]"]) + + update_growth_stages() + +//Returns a list of the desired trait values. +/datum/seed/proc/get_gene(var/genetype) + + if(!genetype) return 0 + + var/list/traits_to_copy + var/datum/plantgene/P = new() + P.genetype = genetype + P.values = list() + + switch(genetype) + if(GENE_PRODUCTS) + P.values["[TRAIT_PRODUCTS]"] = products + P.values["[TRAIT_CHEMS]"] = chems + P.values["[TRAIT_EXUDE_GASSES]"] = exude_gasses + traits_to_copy = list(TRAIT_ALTER_TEMP,TRAIT_POTENCY,TRAIT_HARVEST_REPEAT,TRAIT_PRODUCES_POWER,TRAIT_JUICY,TRAIT_PRODUCT_ICON,TRAIT_PLANT_ICON) + if(GENE_CONSUMPTION) + P.values["[TRAIT_CONSUME_GASSES]"] = consume_gasses + traits_to_copy = list(TRAIT_REQUIRES_NUTRIENTS,TRAIT_NUTRIENT_CONSUMPTION,TRAIT_REQUIRES_WATER,TRAIT_WATER_CONSUMPTION,TRAIT_CARNIVOROUS,TRAIT_PARASITE,TRAIT_STINGS) + if(GENE_ENVIRONMENT) + traits_to_copy = list(TRAIT_IDEAL_HEAT,TRAIT_HEAT_TOLERANCE,TRAIT_IDEAL_LIGHT,TRAIT_LIGHT_TOLERANCE,TRAIT_LOWKPA_TOLERANCE,TRAIT_HIGHKPA_TOLERANCE,TRAIT_EXPLOSIVE) + if(GENE_RESISTANCE) + traits_to_copy = list(TRAIT_TOXINS_TOLERANCE,TRAIT_PEST_TOLERANCE,TRAIT_WEED_TOLERANCE) + if(GENE_VIGOUR) + traits_to_copy = list(TRAIT_ENDURANCE,TRAIT_YIELD,TRAIT_SPREAD,TRAIT_MATURATION,TRAIT_PRODUCTION,TRAIT_TELEPORTING) + if(GENE_PIGMENT) + traits_to_copy = list(TRAIT_PLANT_COLOUR,TRAIT_PRODUCT_COLOUR,TRAIT_BIOLUM,TRAIT_BIOLUM_COLOUR) + + for(var/trait in traits_to_copy) + P.values["[trait]"] = get_trait(trait) + return (P ? P : 0) + +//Place the plant products at the feet of the user. +/datum/seed/proc/harvest(var/mob/user,var/yield_mod,var/harvest_sample,var/force_amount) + + if(!user) + return + + var/got_product + if(!isnull(products) && products.len && get_trait(TRAIT_YIELD) > 0) + got_product = 1 + + if(!force_amount && !got_product && !harvest_sample) + if(istype(user)) user << "You fail to harvest anything useful." + else + if(istype(user)) user << "You [harvest_sample ? "take a sample" : "harvest"] from the [display_name]." + + //This may be a new line. Update the global if it is. + if(name == "new line" || !(name in seed_types)) + uid = seed_types.len + 1 + name = "[uid]" + seed_types[name] = src + + if(harvest_sample) + var/obj/item/seeds/seeds = new(get_turf(user)) + seeds.seed_type = name + seeds.update_seed() + return + + var/total_yield = 0 + if(!isnull(force_amount)) + total_yield = force_amount + else + if(get_trait(TRAIT_YIELD) > -1) + if(isnull(yield_mod) || yield_mod < 1) + yield_mod = 0 + total_yield = get_trait(TRAIT_YIELD) + else + total_yield = get_trait(TRAIT_YIELD) + rand(yield_mod) + total_yield = max(1,total_yield) + + currently_querying = list() + for(var/i = 0;iThe pod disgorges [product]!") + handle_living_product(product) + if(istype(product,/mob/living/simple_animal/mushroom)) // Gross. + var/mob/living/simple_animal/mushroom/mush = product + mush.seed = src + +// When the seed in this machine mutates/is modified, the tray seed value +// is set to a new datum copied from the original. This datum won't actually +// be put into the global datum list until the product is harvested, though. +/datum/seed/proc/diverge(var/modified) + + if(get_trait(TRAIT_IMMUTABLE) > 0) return + + //Set up some basic information. + var/datum/seed/new_seed = new + new_seed.name = "new line" + new_seed.uid = 0 + new_seed.roundstart = 0 + new_seed.can_self_harvest = can_self_harvest + + //Copy over everything else. + if(products) new_seed.products = products.Copy() + if(mutants) new_seed.mutants = mutants.Copy() + if(chems) new_seed.chems = chems.Copy() + if(consume_gasses) new_seed.consume_gasses = consume_gasses.Copy() + if(exude_gasses) new_seed.exude_gasses = exude_gasses.Copy() + + new_seed.seed_name = "[(roundstart ? "[(modified ? "modified" : "mutant")] " : "")][seed_name]" + new_seed.display_name = "[(roundstart ? "[(modified ? "modified" : "mutant")] " : "")][display_name]" + new_seed.seed_noun = seed_noun + new_seed.traits = traits.Copy() + new_seed.update_growth_stages() + return new_seed + +/datum/seed/proc/update_growth_stages() + if(get_trait(TRAIT_PLANT_ICON)) + growth_stages = plant_sprites[get_trait(TRAIT_PLANT_ICON)] + else + growth_stages = 0 diff --git a/code/modules/hydroponics/seed_datums.dm b/code/modules/hydroponics/seed_datums.dm index fd453f7f22..d8a6dc00ce 100644 --- a/code/modules/hydroponics/seed_datums.dm +++ b/code/modules/hydroponics/seed_datums.dm @@ -1,778 +1,3 @@ -// Sprite lists. -var/global/list/plant_sprites = list() // List of all harvested product sprites. -var/global/list/plant_product_sprites = list() // List of all growth sprites plus number of growth stages. - -// Proc for creating a random seed type. -/proc/create_random_seed(var/survive_on_station) - var/datum/seed/seed = new() - seed.randomize() - seed.uid = seed_types.len + 1 - seed.name = "[seed.uid]" - seed_types[seed.name] = seed - - if(survive_on_station) - if(seed.consume_gasses) - seed.consume_gasses["phoron"] = null - seed.consume_gasses["carbon_dioxide"] = null - seed.set_trait(TRAIT_IDEAL_HEAT,293) - seed.set_trait(TRAIT_HEAT_TOLERANCE,20) - seed.set_trait(TRAIT_IDEAL_LIGHT,8) - seed.set_trait(TRAIT_LIGHT_TOLERANCE,5) - seed.set_trait(TRAIT_LOWKPA_TOLERANCE,25) - seed.set_trait(TRAIT_HIGHKPA_TOLERANCE,200) - - return seed - -// Debug for testing seed genes. -/client/proc/show_plant_genes() - set category = "Debug" - set name = "Show Plant Genes" - set desc = "Prints the round's plant gene masks." - - if(!holder) return - - if(!gene_tag_masks) - usr << "Gene masks not set." - return - - for(var/mask in gene_tag_masks) - usr << "[mask]: [gene_tag_masks[mask]]" - -// Predefined/roundstart varieties use a string key to make it -// easier to grab the new variety when mutating. Post-roundstart -// and mutant varieties use their uid converted to a string instead. -// Looks like shit but it's sort of necessary. - -proc/populate_seed_list() - - // Build the icon lists. - for(var/icostate in icon_states('icons/obj/hydroponics_growing.dmi')) - var/split = findtext(icostate,"-") - if(!split) - // invalid icon_state - continue - - var/ikey = copytext(icostate,(split+1)) - if(ikey == "dead") - // don't count dead icons - continue - ikey = text2num(ikey) - var/base = copytext(icostate,1,split) - - if(!(plant_sprites[base]) || (plant_sprites[base]\The [fruit]'s thorns pierce your [affecting.display_name] greedily!" - else - target << "\The [fruit]'s thorns pierce your flesh greedily!" - damage = get_trait(TRAIT_POTENCY)/2 - else - if(affecting) - target << "\The [fruit]'s thorns dig deeply into your [affecting.display_name]!" - else - target << "\The [fruit]'s thorns dig deeply into your flesh!" - damage = get_trait(TRAIT_POTENCY)/5 - else - return - - if(affecting) - affecting.take_damage(damage, 0) - affecting.add_autopsy_data("Thorns",damage) - else - target.adjustBruteLoss(damage) - target.UpdateDamageIcon() - target.updatehealth() - -// Adds reagents to a target. -/datum/seed/proc/do_sting(var/mob/living/carbon/human/target, var/obj/item/fruit) - if(!get_trait(TRAIT_STINGS)) - return - if(chems && chems.len) - target << "You are stung by \the [fruit]!" - for(var/rid in chems) - var/injecting = min(5,max(1,get_trait(TRAIT_POTENCY)/5)) - target.reagents.add_reagent(rid,injecting) - -//Splatter a turf. -/datum/seed/proc/splatter(var/turf/T,var/obj/item/thrown) - if(splat_type) - var/obj/effect/plant/splat = new splat_type(T, src) - if(!istype(splat)) // Plants handle their own stuff. - splat.name = "[thrown.name] [pick("smear","smudge","splatter")]" - if(get_trait(TRAIT_BIOLUM)) - if(get_trait(TRAIT_BIOLUM_COLOUR)) - splat.l_color = get_trait(TRAIT_BIOLUM_COLOUR) - splat.SetLuminosity(get_trait(TRAIT_BIOLUM)) - if(get_trait(TRAIT_PRODUCT_COLOUR)) - splat.color = get_trait(TRAIT_PRODUCT_COLOUR) - - if(chems) - for(var/mob/living/M in T.contents) - if(!M.reagents) - continue - for(var/chem in chems) - var/injecting = min(5,max(1,get_trait(TRAIT_POTENCY)/3)) - M.reagents.add_reagent(chem,injecting) - -//Applies an effect to a target atom. -/datum/seed/proc/thrown_at(var/obj/item/thrown,var/atom/target, var/force_explode) - - var/splatted - var/turf/origin_turf = get_turf(target) - - if(force_explode || get_trait(TRAIT_EXPLOSIVE)) - - var/flood_dist = min(10,max(1,get_trait(TRAIT_POTENCY)/15)) - var/list/open_turfs = list() - var/list/closed_turfs = list() - var/list/valid_turfs = list() - open_turfs |= origin_turf - - // Flood fill to get affected turfs. - while(open_turfs.len) - var/turf/T = pick(open_turfs) - open_turfs -= T - closed_turfs |= T - valid_turfs |= T - - for(var/dir in alldirs) - var/turf/neighbor = get_step(T,dir) - if(!neighbor || (neighbor in closed_turfs) || (neighbor in open_turfs)) - continue - if(neighbor.density || get_dist(neighbor,origin_turf) > flood_dist || istype(neighbor,/turf/space)) - closed_turfs |= neighbor - continue - // Check for windows. - var/no_los - var/turf/last_turf = origin_turf - for(var/turf/target_turf in getline(origin_turf,neighbor)) - if(!last_turf.Enter(target_turf) || target_turf.density) - no_los = 1 - break - last_turf = target_turf - if(!no_los && !origin_turf.Enter(neighbor)) - no_los = 1 - if(no_los) - closed_turfs |= neighbor - continue - open_turfs |= neighbor - - for(var/turf/T in valid_turfs) - for(var/mob/living/M in T.contents) - apply_special_effect(M) - splatter(T,thrown) - origin_turf.visible_message("The [thrown.name] explodes!") - del(thrown) - return - - if(istype(target,/mob/living)) - splatted = apply_special_effect(target,thrown) - else if(istype(target,/turf)) - splatted = 1 - for(var/mob/living/M in target.contents) - apply_special_effect(M) - - if(get_trait(TRAIT_JUICY) && splatted) - splatter(origin_turf,thrown) - origin_turf.visible_message("The [thrown.name] splatters against [target]!") - del(thrown) - -/datum/seed/proc/handle_environment(var/turf/current_turf, var/datum/gas_mixture/environment, var/check_only) - - var/health_change = 0 - // Handle gas consumption. - if(consume_gasses && consume_gasses.len) - var/missing_gas = 0 - for(var/gas in consume_gasses) - if(environment && environment.gas && environment.gas[gas] && \ - environment.gas[gas] >= consume_gasses[gas]) - if(!check_only) - environment.adjust_gas(gas,-consume_gasses[gas],1) - else - missing_gas++ - - if(missing_gas > 0) - health_change += missing_gas * HYDRO_SPEED_MULTIPLIER - - // Process it. - var/pressure = environment.return_pressure() - if(pressure < get_trait(TRAIT_LOWKPA_TOLERANCE)|| pressure > get_trait(TRAIT_HIGHKPA_TOLERANCE)) - health_change += rand(1,3) * HYDRO_SPEED_MULTIPLIER - - if(abs(environment.temperature - get_trait(TRAIT_IDEAL_HEAT)) > get_trait(TRAIT_HEAT_TOLERANCE)) - health_change += rand(1,3) * HYDRO_SPEED_MULTIPLIER - - // Handle gas production. - if(exude_gasses && exude_gasses.len && !check_only) - for(var/gas in exude_gasses) - environment.adjust_gas(gas, max(1,round((exude_gasses[gas]*get_trait(TRAIT_POTENCY))/exude_gasses.len))) - - // Handle light requirements. - var/area/A = get_area(current_turf) - if(A) - var/light_available - if(A.lighting_use_dynamic) - light_available = max(0,min(10,current_turf.lighting_lumcount)-5) - else - light_available = 5 - if(abs(light_available - get_trait(TRAIT_IDEAL_LIGHT)) > get_trait(TRAIT_LIGHT_TOLERANCE)) - health_change += rand(1,3) * HYDRO_SPEED_MULTIPLIER - - return health_change - -/datum/seed/proc/apply_special_effect(var/mob/living/target,var/obj/item/thrown) - - var/impact = 1 - do_sting(target,thrown) - do_thorns(target,thrown) - - // Bluespace tomato code copied over from grown.dm. - if(get_trait(TRAIT_TELEPORTING)) - - //Plant potency determines radius of teleport. - var/outer_teleport_radius = get_trait(TRAIT_POTENCY)/5 - var/inner_teleport_radius = get_trait(TRAIT_POTENCY)/15 - - var/list/turfs = list() - if(inner_teleport_radius > 0) - for(var/turf/T in orange(target,outer_teleport_radius)) - if(get_dist(target,T) >= inner_teleport_radius) - turfs |= T - - if(turfs.len) - // Moves the mob, causes sparks. - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, get_turf(target)) - s.start() - var/turf/picked = get_turf(pick(turfs)) // Just in case... - new/obj/effect/decal/cleanable/molten_item(get_turf(target)) // Leave a pile of goo behind for dramatic effect... - target.loc = picked // And teleport them to the chosen location. - - impact = 1 - - return impact - -//Creates a random seed. MAKE SURE THE LINE HAS DIVERGED BEFORE THIS IS CALLED. -/datum/seed/proc/randomize() - - roundstart = 0 - seed_name = "strange plant" // TODO: name generator. - display_name = "strange plants" // TODO: name generator. - mysterious = 1 - seed_noun = pick("spores","nodes","cuttings","seeds") - products = list(pick(typesof(/obj/item/weapon/reagent_containers/food/snacks/grown)-/obj/item/weapon/reagent_containers/food/snacks/grown)) - - set_trait(TRAIT_POTENCY,rand(5,30),200,0) - set_trait(TRAIT_PRODUCT_ICON,pick(plant_product_sprites)) - set_trait(TRAIT_PLANT_ICON,pick(plant_sprites)) - set_trait(TRAIT_PLANT_COLOUR,"#[get_random_colour(0,75,190)]") - set_trait(TRAIT_PRODUCT_COLOUR,"#[get_random_colour(0,75,190)]") - update_growth_stages() - - if(prob(20)) - set_trait(TRAIT_HARVEST_REPEAT,1) - - if(prob(15)) - if(prob(15)) - set_trait(TRAIT_JUICY,2) - else - set_trait(TRAIT_JUICY,1) - - if(prob(5)) - set_trait(TRAIT_STINGS,1) - - if(prob(5)) - set_trait(TRAIT_PRODUCES_POWER,1) - - if(prob(1)) - set_trait(TRAIT_EXPLOSIVE,1) - else if(prob(1)) - set_trait(TRAIT_TELEPORTING,1) - - if(prob(5)) - consume_gasses = list() - var/gas = pick("oxygen","nitrogen","phoron","carbon_dioxide") - consume_gasses[gas] = rand(3,9) - - if(prob(5)) - exude_gasses = list() - var/gas = pick("oxygen","nitrogen","phoron","carbon_dioxide") - exude_gasses[gas] = rand(3,9) - - chems = list() - if(prob(80)) - chems["nutriment"] = list(rand(1,10),rand(10,20)) - - var/additional_chems = rand(0,5) - - if(additional_chems) - var/list/possible_chems = list( - "bicaridine", - "hyperzine", - "cryoxadone", - "blood", - "water", - "potassium", - "plasticide", - "mutationtoxin", - "amutationtoxin", - "inaprovaline", - "space_drugs", - "paroxetine", - "mercury", - "sugar", - "radium", - "ryetalyn", - "alkysine", - "thermite", - "tramadol", - "cryptobiolin", - "dermaline", - "dexalin", - "phoron", - "synaptizine", - "impedrezene", - "hyronalin", - "peridaxon", - "toxin", - "rezadone", - "ethylredoxrazine", - "slimejelly", - "cyanide", - "mindbreaker", - "stoxin" - ) - - for(var/x=1;x<=additional_chems;x++) - if(!possible_chems.len) - break - var/new_chem = pick(possible_chems) - possible_chems -= new_chem - chems[new_chem] = list(rand(1,10),rand(10,20)) - - if(prob(90)) - set_trait(TRAIT_REQUIRES_NUTRIENTS,1) - set_trait(TRAIT_NUTRIENT_CONSUMPTION,rand(100)*0.1) - else - set_trait(TRAIT_REQUIRES_NUTRIENTS,0) - - if(prob(90)) - set_trait(TRAIT_REQUIRES_WATER,1) - set_trait(TRAIT_WATER_CONSUMPTION,rand(10)) - else - set_trait(TRAIT_REQUIRES_WATER,0) - - set_trait(TRAIT_IDEAL_HEAT, rand(100,400)) - set_trait(TRAIT_HEAT_TOLERANCE, rand(10,30)) - set_trait(TRAIT_IDEAL_LIGHT, rand(2,10)) - set_trait(TRAIT_LIGHT_TOLERANCE, rand(2,7)) - set_trait(TRAIT_TOXINS_TOLERANCE, rand(2,7)) - set_trait(TRAIT_PEST_TOLERANCE, rand(2,7)) - set_trait(TRAIT_WEED_TOLERANCE, rand(2,7)) - set_trait(TRAIT_LOWKPA_TOLERANCE, rand(10,50)) - set_trait(TRAIT_HIGHKPA_TOLERANCE,rand(100,300)) - - if(prob(5)) - set_trait(TRAIT_ALTER_TEMP,rand(-5,5)) - - if(prob(1)) - set_trait(TRAIT_IMMUTABLE,-1) - - var/carnivore_prob = rand(100) - if(carnivore_prob < 5) - set_trait(TRAIT_CARNIVOROUS,2) - else if(carnivore_prob < 10) - set_trait(TRAIT_CARNIVOROUS,1) - - if(prob(10)) - set_trait(TRAIT_PARASITE,1) - - var/vine_prob = rand(100) - if(vine_prob < 5) - set_trait(TRAIT_SPREAD,2) - else if(vine_prob < 10) - set_trait(TRAIT_SPREAD,1) - - if(prob(5)) - set_trait(TRAIT_BIOLUM,1) - set_trait(TRAIT_BIOLUM_COLOUR,"#[get_random_colour(0,75,190)]") - - set_trait(TRAIT_ENDURANCE,rand(60,100)) - set_trait(TRAIT_YIELD,rand(3,15)) - set_trait(TRAIT_MATURATION,rand(5,15)) - set_trait(TRAIT_PRODUCTION,get_trait(TRAIT_MATURATION)+rand(2,5)) - -//Returns a key corresponding to an entry in the global seed list. -/datum/seed/proc/get_mutant_variant() - if(!mutants || !mutants.len || get_trait(TRAIT_IMMUTABLE) > 0) return 0 - return pick(mutants) - -//Mutates the plant overall (randomly). -/datum/seed/proc/mutate(var/degree,var/turf/source_turf) - - if(!degree || get_trait(TRAIT_IMMUTABLE) > 0) return - - source_turf.visible_message("\The [display_name] quivers!") - - //This looks like shit, but it's a lot easier to read/change this way. - var/total_mutations = rand(1,1+degree) - for(var/i = 0;i\The [display_name] withers rapidly!") - if(1) - set_trait(TRAIT_NUTRIENT_CONSUMPTION,get_trait(TRAIT_NUTRIENT_CONSUMPTION)+rand(-(degree*0.1),(degree*0.1)),5,0) - set_trait(TRAIT_WATER_CONSUMPTION, get_trait(TRAIT_WATER_CONSUMPTION) +rand(-degree,degree),50,0) - set_trait(TRAIT_JUICY, !get_trait(TRAIT_JUICY)) - set_trait(TRAIT_STINGS, !get_trait(TRAIT_STINGS)) - if(2) - set_trait(TRAIT_IDEAL_HEAT, get_trait(TRAIT_IDEAL_HEAT) + (rand(-5,5)*degree),800,70) - set_trait(TRAIT_HEAT_TOLERANCE, get_trait(TRAIT_HEAT_TOLERANCE) + (rand(-5,5)*degree),800,70) - set_trait(TRAIT_LOWKPA_TOLERANCE, get_trait(TRAIT_LOWKPA_TOLERANCE)+ (rand(-5,5)*degree),80,0) - set_trait(TRAIT_HIGHKPA_TOLERANCE, get_trait(TRAIT_HIGHKPA_TOLERANCE)+(rand(-5,5)*degree),500,110) - set_trait(TRAIT_EXPLOSIVE,1) - if(3) - set_trait(TRAIT_IDEAL_LIGHT, get_trait(TRAIT_IDEAL_LIGHT)+(rand(-1,1)*degree),30,0) - set_trait(TRAIT_LIGHT_TOLERANCE, get_trait(TRAIT_LIGHT_TOLERANCE)+(rand(-2,2)*degree),10,0) - if(4) - set_trait(TRAIT_TOXINS_TOLERANCE, get_trait(TRAIT_TOXINS_TOLERANCE)+(rand(-2,2)*degree),10,0) - if(5) - set_trait(TRAIT_WEED_TOLERANCE, get_trait(TRAIT_WEED_TOLERANCE)+(rand(-2,2)*degree),10, 0) - if(prob(degree*5)) - set_trait(TRAIT_CARNIVOROUS, get_trait(TRAIT_CARNIVOROUS)+rand(-degree,degree),2, 0) - if(get_trait(TRAIT_CARNIVOROUS)) - source_turf.visible_message("\The [display_name] shudders hungrily.") - if(6) - set_trait(TRAIT_WEED_TOLERANCE, get_trait(TRAIT_WEED_TOLERANCE)+(rand(-2,2)*degree),10, 0) - if(prob(degree*5)) - set_trait(TRAIT_PARASITE,!get_trait(TRAIT_PARASITE)) - if(7) - if(get_trait(TRAIT_YIELD) != -1) - set_trait(TRAIT_YIELD, get_trait(TRAIT_YIELD)+(rand(-2,2)*degree),10,0) - if(8) - set_trait(TRAIT_ENDURANCE, get_trait(TRAIT_ENDURANCE)+(rand(-5,5)*degree),100,10) - set_trait(TRAIT_PRODUCTION, get_trait(TRAIT_PRODUCTION)+(rand(-1,1)*degree),10, 1) - set_trait(TRAIT_POTENCY, get_trait(TRAIT_POTENCY)+(rand(-20,20)*degree),200, 0) - if(prob(degree*5)) - set_trait(TRAIT_SPREAD, get_trait(TRAIT_SPREAD)+rand(-1,1),2, 0) - source_turf.visible_message("\The [display_name] spasms visibly, shifting in the tray.") - if(9) - set_trait(TRAIT_MATURATION, get_trait(TRAIT_MATURATION)+(rand(-1,1)*degree),30, 0) - if(prob(degree*5)) - set_trait(TRAIT_HARVEST_REPEAT, !get_trait(TRAIT_HARVEST_REPEAT)) - if(10) - if(prob(degree*2)) - set_trait(TRAIT_BIOLUM, !get_trait(TRAIT_BIOLUM)) - if(get_trait(TRAIT_BIOLUM)) - source_turf.visible_message("\The [display_name] begins to glow!") - if(prob(degree*2)) - set_trait(TRAIT_BIOLUM_COLOUR,"#[get_random_colour(0,75,190)]") - source_turf.visible_message("\The [display_name]'s glow changes colour!") - else - source_turf.visible_message("\The [display_name]'s glow dims...") - if(11) - set_trait(TRAIT_TELEPORTING,1) - - return - -//Mutates a specific trait/set of traits. -/datum/seed/proc/apply_gene(var/datum/plantgene/gene) - - if(!gene || !gene.values || get_trait(TRAIT_IMMUTABLE) > 0) return - - // Splicing products has some detrimental effects on yield and lifespan. - // We handle this before we do the rest of the looping, as normal traits don't really include lists. - if(gene.genetype == GENE_PRODUCTS) - for(var/trait in list(TRAIT_YIELD, TRAIT_ENDURANCE)) - if(get_trait(trait) > 0) set_trait(trait,get_trait(trait),null,1,0.85) - - if(!products) products = list() - products |= gene.values["[TRAIT_PRODUCTS]"] - - if(!chems) chems = list() - - var/list/gene_value = gene.values["[TRAIT_CHEMS]"] - for(var/rid in gene_value) - - var/list/gene_chem = gene_value[rid] - - if(!chems[rid]) - chems[rid] = gene_chem.Copy() - continue - - for(var/i=1;i<=gene_chem.len;i++) - - if(isnull(gene_chem[i])) gene_chem[i] = 0 - - if(chems[rid][i]) - chems[rid][i] = max(1,round((gene_chem[i] + chems[rid][i])/2)) - else - chems[rid][i] = gene_chem[i] - - var/list/new_gasses = gene.values["[TRAIT_EXUDE_GASSES]"] - if(islist(new_gasses)) - if(!exude_gasses) exude_gasses = list() - exude_gasses |= new_gasses - for(var/gas in exude_gasses) - exude_gasses[gas] = max(1,round(exude_gasses[gas]*0.8)) - - for(var/trait in gene.values) - set_trait(trait,gene.values["[trait]"]) - - update_growth_stages() - -//Returns a list of the desired trait values. -/datum/seed/proc/get_gene(var/genetype) - - if(!genetype) return 0 - - var/list/traits_to_copy - var/datum/plantgene/P = new() - P.genetype = genetype - P.values = list() - - switch(genetype) - if(GENE_PRODUCTS) - P.values["[TRAIT_PRODUCTS]"] = products - P.values["[TRAIT_CHEMS]"] = chems - P.values["[TRAIT_EXUDE_GASSES]"] = exude_gasses - traits_to_copy = list(TRAIT_ALTER_TEMP,TRAIT_POTENCY,TRAIT_HARVEST_REPEAT,TRAIT_PRODUCES_POWER,TRAIT_JUICY,TRAIT_PRODUCT_ICON,TRAIT_PLANT_ICON) - if(GENE_CONSUMPTION) - P.values["[TRAIT_CONSUME_GASSES]"] = consume_gasses - traits_to_copy = list(TRAIT_REQUIRES_NUTRIENTS,TRAIT_NUTRIENT_CONSUMPTION,TRAIT_REQUIRES_WATER,TRAIT_WATER_CONSUMPTION,TRAIT_CARNIVOROUS,TRAIT_PARASITE,TRAIT_STINGS) - if(GENE_ENVIRONMENT) - traits_to_copy = list(TRAIT_IDEAL_HEAT,TRAIT_HEAT_TOLERANCE,TRAIT_IDEAL_LIGHT,TRAIT_LIGHT_TOLERANCE,TRAIT_LOWKPA_TOLERANCE,TRAIT_HIGHKPA_TOLERANCE,TRAIT_EXPLOSIVE) - if(GENE_RESISTANCE) - traits_to_copy = list(TRAIT_TOXINS_TOLERANCE,TRAIT_PEST_TOLERANCE,TRAIT_WEED_TOLERANCE) - if(GENE_VIGOUR) - traits_to_copy = list(TRAIT_ENDURANCE,TRAIT_YIELD,TRAIT_SPREAD,TRAIT_MATURATION,TRAIT_PRODUCTION,TRAIT_TELEPORTING) - if(GENE_PIGMENT) - traits_to_copy = list(TRAIT_PLANT_COLOUR,TRAIT_PRODUCT_COLOUR,TRAIT_BIOLUM,TRAIT_BIOLUM_COLOUR) - - for(var/trait in traits_to_copy) - P.values["[trait]"] = get_trait(trait) - return (P ? P : 0) - -//Place the plant products at the feet of the user. -/datum/seed/proc/harvest(var/mob/user,var/yield_mod,var/harvest_sample,var/force_amount) - - if(!user) - return - - var/got_product - if(!isnull(products) && products.len && get_trait(TRAIT_YIELD) > 0) - got_product = 1 - - if(!force_amount && !got_product && !harvest_sample) - if(istype(user)) user << "You fail to harvest anything useful." - else - if(istype(user)) user << "You [harvest_sample ? "take a sample" : "harvest"] from the [display_name]." - - //This may be a new line. Update the global if it is. - if(name == "new line" || !(name in seed_types)) - uid = seed_types.len + 1 - name = "[uid]" - seed_types[name] = src - - if(harvest_sample) - var/obj/item/seeds/seeds = new(get_turf(user)) - seeds.seed_type = name - seeds.update_seed() - return - - var/total_yield = 0 - if(!isnull(force_amount)) - total_yield = force_amount - else - if(get_trait(TRAIT_YIELD) > -1) - if(isnull(yield_mod) || yield_mod < 1) - yield_mod = 0 - total_yield = get_trait(TRAIT_YIELD) - else - total_yield = get_trait(TRAIT_YIELD) + rand(yield_mod) - total_yield = max(1,total_yield) - - currently_querying = list() - for(var/i = 0;iThe pod disgorges [product]!") - handle_living_product(product) - if(istype(product,/mob/living/simple_animal/mushroom)) // Gross. - var/mob/living/simple_animal/mushroom/mush = product - mush.seed = src - -// When the seed in this machine mutates/is modified, the tray seed value -// is set to a new datum copied from the original. This datum won't actually -// be put into the global datum list until the product is harvested, though. -/datum/seed/proc/diverge(var/modified) - - if(get_trait(TRAIT_IMMUTABLE) > 0) return - - //Set up some basic information. - var/datum/seed/new_seed = new - new_seed.name = "new line" - new_seed.uid = 0 - new_seed.roundstart = 0 - new_seed.can_self_harvest = can_self_harvest - - //Copy over everything else. - if(products) new_seed.products = products.Copy() - if(mutants) new_seed.mutants = mutants.Copy() - if(chems) new_seed.chems = chems.Copy() - if(consume_gasses) new_seed.consume_gasses = consume_gasses.Copy() - if(exude_gasses) new_seed.exude_gasses = exude_gasses.Copy() - - new_seed.seed_name = "[(roundstart ? "[(modified ? "modified" : "mutant")] " : "")][seed_name]" - new_seed.display_name = "[(roundstart ? "[(modified ? "modified" : "mutant")] " : "")][display_name]" - new_seed.seed_noun = seed_noun - new_seed.traits = traits.Copy() - new_seed.update_growth_stages() - return new_seed - -/datum/seed/proc/update_growth_stages() - if(get_trait(TRAIT_PLANT_ICON)) - growth_stages = plant_sprites[get_trait(TRAIT_PLANT_ICON)] - else - growth_stages = 0 - -// Actual roundstart seed types after this point. // Chili plants/variants. /datum/seed/chili name = "chili" diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seed_packets.dm similarity index 100% rename from code/modules/hydroponics/seeds.dm rename to code/modules/hydroponics/seed_packets.dm diff --git a/code/modules/hydroponics/spread_plant.dm b/code/modules/hydroponics/spreading/spreading.dm similarity index 65% rename from code/modules/hydroponics/spread_plant.dm rename to code/modules/hydroponics/spreading/spreading.dm index 9130726789..e60b825278 100644 --- a/code/modules/hydroponics/spread_plant.dm +++ b/code/modules/hydroponics/spreading/spreading.dm @@ -1,5 +1,5 @@ #define DEFAULT_SEED "glowshroom" -#define VINE_GROWTH_STAGES 4 +#define VINE_GROWTH_STAGES 5 /proc/spacevine_infestation() spawn() //to stop the secrets panel hanging @@ -23,6 +23,7 @@ anchored = 1 opacity = 0 density = 0 + color = DEAD_PLANT_COLOUR /obj/effect/dead_plant/attackby() ..() @@ -37,7 +38,7 @@ density = 0 icon = 'icons/obj/hydroponics_growing.dmi' icon_state = "bush4-1" - layer = 2 + layer = 3 var/health = 10 var/max_health = 100 @@ -47,6 +48,7 @@ var/list/children = list() var/obj/effect/plant/parent + var/mob/living/buckled_mob var/datum/seed/seed var/floor = 0 var/spread_chance = 40 @@ -68,12 +70,11 @@ del(src) return - layer = rand(3,4) // Will display over pipes/machines at all times and mobs half the time. name = seed.display_name max_health = round(seed.get_trait(TRAIT_ENDURANCE)/2) if(seed.get_trait(TRAIT_SPREAD)==2) max_growth = VINE_GROWTH_STAGES - growth_threshold = round(max_health/VINE_GROWTH_STAGES) + growth_threshold = max_health/VINE_GROWTH_STAGES icon = 'icons/obj/hydroponics_vines.dmi' growth_type = 2 // Vines by default. if(seed.get_trait(TRAIT_CARNIVOROUS) == 2) @@ -85,7 +86,7 @@ growth_type = 4 // Mold else max_growth = seed.growth_stages - growth_threshold = round(max_health/seed.growth_stages) + growth_threshold = max_health/seed.growth_stages if(max_growth > 2 && prob(50)) max_growth-- //Ensure some variation in final sprite, makes the carpet of crap look less wonky. @@ -143,94 +144,20 @@ else icon_state = "[seed.get_trait(TRAIT_PLANT_ICON)]-[growth]" + layer = (growth == max_growth ? 4 : 3) + /obj/effect/plant/Del() + if(children && children.len) + die_off(null,1) processing_objects -= src ..() -/obj/effect/plant/proc/die_off(var/no_remains) - // Remove ourselves from our parent. - if(parent && parent.children) - parent.children -= src - // Kill off any of our children (and add an added bonus, other plants in this area) - for(var/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/plant in get_turf(src)) - plant.dead = 1 - plant.update_icon() - // Cause the plants around us to update. - if(children && children.len) - for(var/obj/effect/plant/child in children) - child.die_off() - for(var/obj/effect/plant/neighbor in view(1,src)) - neighbor.hibernating = 0 - if(!no_remains && !(locate(/obj/effect/dead_plant) in get_turf(src))) - var/obj/effect/dead_plant/plant_remains = new(get_turf(src)) - plant_remains.icon = src.icon - plant_remains.icon_state = src.icon_state - del(src) - /obj/effect/plant/proc/get_dist_to_parent(var/current_count) if(!parent) return current_count current_count++ return parent.get_dist_to_parent(current_count) -/obj/effect/plant/process() - - // Something is very wrong, kill ourselves. - if(!seed) - die_off() - - // Handle life. - var/turf/simulated/T = get_turf(src) - if(istype(T)) - health -= seed.handle_environment(T, T.return_air(),1) - if(health < max_health) - health += rand(3,5) - if(health > max_health) - health = max_health - refresh_icon() - - // Damaged, young hibernating or too far from parent, no chance of spreading. - if(health < (max_health/2) || hibernating || (parent && (get_dist_to_parent(0) > spread_distance))) - return - - // Count our neighbors and possible locations for spreading. - var/list/possible_locs = list() - var/count = 0 - for(var/turf/simulated/floor/floor in view(1,src)) - if((locate(/obj/effect/dead_plant) in floor.contents) || !floor.Enter(src) || floor.density) - continue - if(locate(/obj/effect/plant) in floor.contents) - count++ - continue - possible_locs |= floor - - //Entirely surrounded, try to spawn an actual plant. - if(count>=8 && prob(5)) - if(!(locate(/obj/machinery/portable_atmospherics/hydroponics/soil/invisible) in T.contents)) - var/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/new_plant = new(T,seed) - new_plant.age = seed.get_trait(TRAIT_MATURATION)-5 - new_plant.update_icon() - if(growth_type==0) //Vines do not become invisible. - invisibility = INVISIBILITY_MAXIMUM - - if(prob(spread_chance)) - for(var/i=1,i<=seed.get_trait(TRAIT_YIELD),i++) - if(!possible_locs.len) - break - if(prob(spread_into_adjacent)) - var/turf/target_turf = pick(possible_locs) - possible_locs -= target_turf - var/obj/effect/plant/child = new(target_turf, seed) - child.parent = get_root() - child.parent.children |= child - - /* - var/need_hibernate = 0 - if(need_hibernate) - hibernating = 1 - world << "[src] at [x],[y] is hibernating" - */ - /obj/effect/plant/proc/get_root() if(parent) return parent.get_root() @@ -303,4 +230,7 @@ /obj/effect/plant/proc/check_health() if(health <= 0) - die_off() \ No newline at end of file + die_off(1) + +/obj/effect/plant/proc/is_mature() + return (health < (max_health/3)) \ No newline at end of file diff --git a/code/modules/hydroponics/spreading/spreading_growth.dm b/code/modules/hydroponics/spreading/spreading_growth.dm new file mode 100644 index 0000000000..6d0957e650 --- /dev/null +++ b/code/modules/hydroponics/spreading/spreading_growth.dm @@ -0,0 +1,75 @@ +/obj/effect/plant/process() + + // Something is very wrong, kill ourselves. + if(!seed) + die_off() + + // Handle life. + var/turf/simulated/T = get_turf(src) + if(istype(T)) + health -= seed.handle_environment(T, T.return_air(),1) + if(health < max_health) + health += rand(3,5) + if(health > max_health) + health = max_health + refresh_icon() + + // Damaged, young hibernating or too far from parent, no chance of spreading. + if(is_mature() || hibernating || (parent && (get_dist_to_parent(0) > spread_distance))) + return + + // Count our neighbors and possible locations for spreading. + var/list/possible_locs = list() + var/count = 0 + for(var/turf/simulated/floor/floor in view(1,src)) + if((locate(/obj/effect/dead_plant) in floor.contents) || !floor.Enter(src) || floor.density) + continue + if(locate(/obj/effect/plant) in floor.contents) + count++ + continue + possible_locs |= floor + + //Entirely surrounded, try to spawn an actual plant. + if(count>=8) + if(!(locate(/obj/machinery/portable_atmospherics/hydroponics/soil/invisible) in T.contents)) + var/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/new_plant = new(T,seed) + new_plant.age = seed.get_trait(TRAIT_MATURATION)-1 + new_plant.update_icon() + if(growth_type==0) //Vines do not become invisible. + invisibility = INVISIBILITY_MAXIMUM + else + new_plant.layer = 4.1 + + if(prob(spread_chance)) + for(var/i=1,i<=seed.get_trait(TRAIT_YIELD),i++) + if(!possible_locs.len) + hibernating = 1 + world << "[src] at [x],[y] is hibernating" + break + if(prob(spread_into_adjacent)) + var/turf/target_turf = pick(possible_locs) + possible_locs -= target_turf + var/obj/effect/plant/child = new(target_turf, seed) + child.parent = get_root() + child.parent.children |= child + +/obj/effect/plant/proc/die_off(var/no_remains, var/no_del) + // Remove ourselves from our parent. + if(parent && parent.children) + parent.children -= src + // Kill off any of our children (and add an added bonus, other plants in this area) + for(var/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/plant in get_turf(src)) + plant.dead = 1 + plant.update_icon() + // Cause the plants around us to update. + if(children && children.len) + for(var/obj/effect/plant/child in children) + child.die_off() + for(var/obj/effect/plant/neighbor in view(1,src)) + neighbor.hibernating = 0 + if(!no_remains && !(locate(/obj/effect/dead_plant) in get_turf(src))) + var/obj/effect/dead_plant/plant_remains = new(get_turf(src)) + plant_remains.icon = src.icon + plant_remains.icon_state = src.icon_state + if(!no_del) + del(src) \ No newline at end of file diff --git a/code/modules/hydroponics/spreading/spreading_response.dm b/code/modules/hydroponics/spreading/spreading_response.dm new file mode 100644 index 0000000000..1d30c0bbf2 --- /dev/null +++ b/code/modules/hydroponics/spreading/spreading_response.dm @@ -0,0 +1,74 @@ +/obj/effect/plant/HasProximity(var/atom/movable/AM) + + hibernating = 0 + + if(!is_mature() || seed.get_trait(TRAIT_SPREAD) != 2) + return + + var/mob/living/M = AM + if(!istype(M)) + return + + if(!buckled_mob && !M.buckled && !M.anchored && prob(round(seed.get_trait(TRAIT_POTENCY)/2))) + entangle(M) + +/obj/effect/plant/attack_hand(mob/user as mob) + hibernating = 0 + manual_unbuckle(user) + +/obj/effect/plant/proc/trodden_on(var/mob/living/victim) + hibernating = 0 + world << "Blah." + if(!is_mature()) + return + var/mob/living/carbon/human/H = victim + if(!istype(H) || H.shoes) + return + seed.do_thorns(victim,src) + seed.do_sting(victim,src,pick("r_foot","l_foot","r_leg","l_leg")) + +/obj/effect/plant/proc/unbuckle() + if(buckled_mob) + if(buckled_mob.buckled == src) + buckled_mob.buckled = null + buckled_mob.anchored = initial(buckled_mob.anchored) + buckled_mob.update_canmove() + buckled_mob = null + return + +/obj/effect/plant/proc/manual_unbuckle(mob/user as mob) + if(buckled_mob) + if(prob(seed ? min(max(0,100 - seed.get_trait(TRAIT_POTENCY)/2),100) : 50)) + if(buckled_mob.buckled == src) + if(buckled_mob != user) + buckled_mob.visible_message(\ + "[user.name] frees [buckled_mob.name] from \the [src].",\ + "[user.name] frees you from \the [src].",\ + "You hear shredding and ripping.") + else + buckled_mob.visible_message(\ + "[buckled_mob.name] struggles free of \the [src].",\ + "You untangle \the [src] from around yourself.",\ + "You hear shredding and ripping.") + unbuckle() + else + var/text = pick("rip","tear","pull") + user.visible_message(\ + "[user.name] [text]s at \the [src].",\ + "You [text] at \the [src].",\ + "You hear shredding and ripping.") + return + +/obj/effect/plant/proc/entangle(var/mob/living/victim) + + if(buckled_mob) + return + + victim.buckled = src + victim.update_canmove() + buckled_mob = victim + + if(victim.loc != src.loc) + src.visible_message("Tendrils lash out from \the [src] and drag \the [victim] in!") + victim.loc = src.loc + victim << "Tendrils [pick("wind", "tangle", "tighten")] around you!" diff --git a/code/modules/hydroponics/hydro_tray.dm b/code/modules/hydroponics/trays/tray.dm similarity index 64% rename from code/modules/hydroponics/hydro_tray.dm rename to code/modules/hydroponics/trays/tray.dm index e8414b59da..6c6f0ca142 100644 --- a/code/modules/hydroponics/hydro_tray.dm +++ b/code/modules/hydroponics/trays/tray.dm @@ -174,133 +174,6 @@ else return 0 -/obj/machinery/portable_atmospherics/hydroponics/process() - - //Do this even if we're not ready for a plant cycle. - process_reagents() - - // Update values every cycle rather than every process() tick. - if(force_update) - force_update = 0 - else if(world.time < (lastcycle + cycledelay)) - return - lastcycle = world.time - - // Mutation level drops each main tick. - mutation_level -= rand(2,4) - - // Weeds like water and nutrients, there's a chance the weed population will increase. - // Bonus chance if the tray is unoccupied. - if(waterlevel > 10 && nutrilevel > 2 && prob(isnull(seed) ? 5 : 1)) - weedlevel += 1 * HYDRO_SPEED_MULTIPLIER - - // There's a chance for a weed explosion to happen if the weeds take over. - // Plants that are themselves weeds (weed_tolerance > 10) are unaffected. - if (weedlevel >= 10 && prob(10)) - if(!seed || weedlevel >= seed.get_trait(TRAIT_WEED_TOLERANCE)) - weed_invasion() - - // If there is no seed data (and hence nothing planted), - // or the plant is dead, process nothing further. - if(!seed || dead) - if(mechanical) update_icon() //Harvesting would fail to set alert icons properly. - return - - // Advance plant age. - if(prob(30)) age += 1 * HYDRO_SPEED_MULTIPLIER - - //Highly mutable plants have a chance of mutating every tick. - if(seed.get_trait(TRAIT_IMMUTABLE) == -1) - var/mut_prob = rand(1,100) - if(mut_prob <= 5) mutate(mut_prob == 1 ? 2 : 1) - - // Other plants also mutate if enough mutagenic compounds have been added. - if(!seed.get_trait(TRAIT_IMMUTABLE)) - if(prob(min(mutation_level,100))) - mutate((rand(100) < 15) ? 2 : 1) - mutation_level = 0 - - // Maintain tray nutrient and water levels. - if(seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) > 0 && nutrilevel > 0 && prob(25)) - nutrilevel -= max(0,seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) * HYDRO_SPEED_MULTIPLIER) - if(seed.get_trait(TRAIT_WATER_CONSUMPTION) > 0 && waterlevel > 0 && prob(25)) - waterlevel -= max(0,seed.get_trait(TRAIT_WATER_CONSUMPTION) * HYDRO_SPEED_MULTIPLIER) - - // Make sure the plant is not starving or thirsty. Adequate - // water and nutrients will cause a plant to become healthier. - var/healthmod = rand(1,3) * HYDRO_SPEED_MULTIPLIER - if(seed.get_trait(TRAIT_REQUIRES_NUTRIENTS) && prob(35)) - health += (nutrilevel < 2 ? -healthmod : healthmod) - if(seed.get_trait(TRAIT_REQUIRES_WATER) && prob(35)) - health += (waterlevel < 10 ? -healthmod : healthmod) - - // Check that pressure, heat and light are all within bounds. - // First, handle an open system or an unconnected closed system. - - var/turf/T = loc - var/datum/gas_mixture/environment - // If we're closed, take from our internal sources. - if(closed_system && (connected_port || holding)) - environment = air_contents - // If atmos input is not there, grab from turf. - if(!environment && istype(T)) environment = T.return_air() - if(!environment) return - - // Seed datum handles gasses, light and pressure. - health -= seed.handle_environment(T,environment) - - // If we're attached to a pipenet, then we should let the pipenet know we might have modified some gasses - if (closed_system && connected_port) - update_connected_network() - - // Toxin levels beyond the plant's tolerance cause damage, but - // toxins are sucked up each tick and slowly reduce over time. - if(toxins > 0) - var/toxin_uptake = max(1,round(toxins/10)) - if(toxins > seed.get_trait(TRAIT_TOXINS_TOLERANCE)) - health -= toxin_uptake - toxins -= toxin_uptake - - // Check for pests and weeds. - // Some carnivorous plants happily eat pests. - if(pestlevel > 0) - if(seed.get_trait(TRAIT_CARNIVOROUS)) - health += HYDRO_SPEED_MULTIPLIER - pestlevel -= HYDRO_SPEED_MULTIPLIER - else if (pestlevel >= seed.get_trait(TRAIT_PEST_TOLERANCE)) - health -= HYDRO_SPEED_MULTIPLIER - - // Some plants thrive and live off of weeds. - if(weedlevel > 0) - if(seed.get_trait(TRAIT_PARASITE)) - health += HYDRO_SPEED_MULTIPLIER - weedlevel -= HYDRO_SPEED_MULTIPLIER - else if (weedlevel >= seed.get_trait(TRAIT_WEED_TOLERANCE)) - health -= HYDRO_SPEED_MULTIPLIER - - // Handle life and death. - // When the plant dies, weeds thrive and pests die off. - check_health() - - // If enough time (in cycles, not ticks) has passed since the plant was harvested, we're ready to harvest again. - if(seed.products && seed.products.len && \ - (age > seed.get_trait(TRAIT_MATURATION)) && \ - ((age - lastproduce) > seed.get_trait(TRAIT_PRODUCTION)) && \ - (!harvest && !dead)) - - harvest = 1 - lastproduce = age - - if(prob(3)) // On each tick, there's a chance the pest population will increase - pestlevel += 0.1 * HYDRO_SPEED_MULTIPLIER - - // Some seeds will self-harvest if you don't keep a lid on them. - if(seed && seed.can_self_harvest && harvest && !closed_system && prob(5)) - harvest() - - check_health() - return - /obj/machinery/portable_atmospherics/hydroponics/proc/check_health() if(seed && !dead && health <= 0) die() @@ -415,82 +288,7 @@ check_health() return -//Refreshes the icon and sets the luminosity -/obj/machinery/portable_atmospherics/hydroponics/update_icon() - - overlays.Cut() - - // Updates the plant overlay. - if(!isnull(seed)) - - if(mechanical && health <= (seed.get_trait(TRAIT_ENDURANCE) / 2)) - overlays += "over_lowhealth3" - - if(dead) - var/ikey = "[seed.get_trait(TRAIT_PLANT_ICON)]-dead" - var/image/dead_overlay = plant_icon_cache["[ikey]"] - if(!dead_overlay) - dead_overlay = image('icons/obj/hydroponics_growing.dmi', "[ikey]") - overlays |= dead_overlay - else - if(!seed.growth_stages) - seed.update_growth_stages() - if(!seed.growth_stages) - world << "Seed type [seed.get_trait(TRAIT_PLANT_ICON)] cannot find a growth stage value." - return - var/overlay_stage = 1 - if(age >= seed.get_trait(TRAIT_MATURATION)) - overlay_stage = seed.growth_stages - lastproduce = age - else - overlay_stage = max(1,round(seed.get_trait(TRAIT_MATURATION) / seed.growth_stages)) - - var/ikey = "[seed.get_trait(TRAIT_PLANT_ICON)]-[overlay_stage]" - var/image/plant_overlay = plant_icon_cache["[ikey]-[seed.get_trait(TRAIT_PLANT_COLOUR)]"] - if(!plant_overlay) - plant_overlay = image('icons/obj/hydroponics_growing.dmi', "[ikey]") - plant_overlay.color = seed.get_trait(TRAIT_PLANT_COLOUR) - plant_icon_cache["[ikey]-[seed.get_trait(TRAIT_PLANT_COLOUR)]"] = plant_overlay - overlays |= plant_overlay - - if(harvest && overlay_stage == seed.growth_stages) - ikey = "[seed.get_trait(TRAIT_PRODUCT_ICON)]" - var/image/harvest_overlay = plant_icon_cache["product-[ikey]-[seed.get_trait(TRAIT_PLANT_COLOUR)]"] - if(!harvest_overlay) - harvest_overlay = image('icons/obj/hydroponics_products.dmi', "[ikey]") - harvest_overlay.color = seed.get_trait(TRAIT_PRODUCT_COLOUR) - plant_icon_cache["product-[ikey]-[seed.get_trait(TRAIT_PRODUCT_COLOUR)]"] = harvest_overlay - overlays |= harvest_overlay - - //Draw the cover. - if(closed_system) - overlays += "hydrocover" - - //Updated the various alert icons. - if(mechanical) - if(waterlevel <= 10) - overlays += "over_lowwater3" - if(nutrilevel <= 2) - overlays += "over_lownutri3" - if(weedlevel >= 5 || pestlevel >= 5 || toxins >= 40) - overlays += "over_alert3" - if(harvest) - overlays += "over_harvest3" - - // Update bioluminescence. - if(seed) - if(seed.get_trait(TRAIT_BIOLUM)) - SetLuminosity(round(seed.get_trait(TRAIT_POTENCY)/10)) - if(seed.get_trait(TRAIT_BIOLUM_COLOUR)) - l_color = seed.get_trait(TRAIT_BIOLUM_COLOUR) - else - l_color = null - return - - SetLuminosity(0) - return - - // If a weed growth is sufficient, this proc is called. +// If a weed growth is sufficient, this proc is called. /obj/machinery/portable_atmospherics/hydroponics/proc/weed_invasion() //Remove the seed if something is already planted. @@ -784,72 +582,3 @@ closed_system = !closed_system usr << "You [closed_system ? "close" : "open"] the tray's lid." update_icon() - -/obj/machinery/portable_atmospherics/hydroponics/soil - name = "soil" - icon_state = "soil" - density = 0 - use_power = 0 - mechanical = 0 - -/obj/machinery/portable_atmospherics/hydroponics/soil/attackby(var/obj/item/O as obj, var/mob/user as mob) - if(istype(O,/obj/item/weapon/tank)) - return - else - ..() - -/obj/machinery/portable_atmospherics/hydroponics/soil/New() - ..() - verbs -= /obj/machinery/portable_atmospherics/hydroponics/verb/close_lid - -/obj/machinery/portable_atmospherics/hydroponics/soil/can_label() - return 0 - -/obj/machinery/portable_atmospherics/hydroponics/soil/CanPass() - return 1 - -// This is a hack pending a proper rewrite of the plant controller. -// Icons for plants are generated as overlays, so setting it to invisible wouldn't work. -// Hence using a blank icon. -/obj/machinery/portable_atmospherics/hydroponics/soil/invisible - name = "plant" - icon = 'icons/obj/seeds.dmi' - icon_state = "blank" - -/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/New(var/newloc,var/datum/seed/newseed) - ..() - seed = newseed - dead = 0 - age = 1 - health = seed.get_trait(TRAIT_ENDURANCE) - lastcycle = world.time - pixel_y = rand(-5,5) - check_health() - -/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/remove_dead() - ..() - del(src) - -/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/harvest() - ..() - if(!seed) - del(src) - -/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/die() - del(src) - -/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/process() - if(!seed) - del(src) - return - else if(name=="plant") - name = seed.display_name - ..() - -/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/Del() - // Check if we're masking a decal that needs to be visible again. - for(var/obj/effect/plant/plant in get_turf(src)) - if(plant.invisibility == INVISIBILITY_MAXIMUM) - plant.invisibility = initial(plant.invisibility) - plant.die_off() - ..() \ No newline at end of file diff --git a/code/game/machinery/bees_apiary.dm b/code/modules/hydroponics/trays/tray_apiary.dm similarity index 100% rename from code/game/machinery/bees_apiary.dm rename to code/modules/hydroponics/trays/tray_apiary.dm diff --git a/code/modules/hydroponics/trays/tray_process.dm b/code/modules/hydroponics/trays/tray_process.dm new file mode 100644 index 0000000000..23662e7a59 --- /dev/null +++ b/code/modules/hydroponics/trays/tray_process.dm @@ -0,0 +1,125 @@ +/obj/machinery/portable_atmospherics/hydroponics/process() + + //Do this even if we're not ready for a plant cycle. + process_reagents() + + // Update values every cycle rather than every process() tick. + if(force_update) + force_update = 0 + else if(world.time < (lastcycle + cycledelay)) + return + lastcycle = world.time + + // Mutation level drops each main tick. + mutation_level -= rand(2,4) + + // Weeds like water and nutrients, there's a chance the weed population will increase. + // Bonus chance if the tray is unoccupied. + if(waterlevel > 10 && nutrilevel > 2 && prob(isnull(seed) ? 5 : 1)) + weedlevel += 1 * HYDRO_SPEED_MULTIPLIER + + // There's a chance for a weed explosion to happen if the weeds take over. + // Plants that are themselves weeds (weed_tolerance > 10) are unaffected. + if (weedlevel >= 10 && prob(10)) + if(!seed || weedlevel >= seed.get_trait(TRAIT_WEED_TOLERANCE)) + weed_invasion() + + // If there is no seed data (and hence nothing planted), + // or the plant is dead, process nothing further. + if(!seed || dead) + if(mechanical) update_icon() //Harvesting would fail to set alert icons properly. + return + + // Advance plant age. + if(prob(30)) age += 1 * HYDRO_SPEED_MULTIPLIER + + //Highly mutable plants have a chance of mutating every tick. + if(seed.get_trait(TRAIT_IMMUTABLE) == -1) + var/mut_prob = rand(1,100) + if(mut_prob <= 5) mutate(mut_prob == 1 ? 2 : 1) + + // Other plants also mutate if enough mutagenic compounds have been added. + if(!seed.get_trait(TRAIT_IMMUTABLE)) + if(prob(min(mutation_level,100))) + mutate((rand(100) < 15) ? 2 : 1) + mutation_level = 0 + + // Maintain tray nutrient and water levels. + if(seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) > 0 && nutrilevel > 0 && prob(25)) + nutrilevel -= max(0,seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) * HYDRO_SPEED_MULTIPLIER) + if(seed.get_trait(TRAIT_WATER_CONSUMPTION) > 0 && waterlevel > 0 && prob(25)) + waterlevel -= max(0,seed.get_trait(TRAIT_WATER_CONSUMPTION) * HYDRO_SPEED_MULTIPLIER) + + // Make sure the plant is not starving or thirsty. Adequate + // water and nutrients will cause a plant to become healthier. + var/healthmod = rand(1,3) * HYDRO_SPEED_MULTIPLIER + if(seed.get_trait(TRAIT_REQUIRES_NUTRIENTS) && prob(35)) + health += (nutrilevel < 2 ? -healthmod : healthmod) + if(seed.get_trait(TRAIT_REQUIRES_WATER) && prob(35)) + health += (waterlevel < 10 ? -healthmod : healthmod) + + // Check that pressure, heat and light are all within bounds. + // First, handle an open system or an unconnected closed system. + + var/turf/T = loc + var/datum/gas_mixture/environment + // If we're closed, take from our internal sources. + if(closed_system && (connected_port || holding)) + environment = air_contents + // If atmos input is not there, grab from turf. + if(!environment && istype(T)) environment = T.return_air() + if(!environment) return + + // Seed datum handles gasses, light and pressure. + health -= seed.handle_environment(T,environment) + + // If we're attached to a pipenet, then we should let the pipenet know we might have modified some gasses + if (closed_system && connected_port) + update_connected_network() + + // Toxin levels beyond the plant's tolerance cause damage, but + // toxins are sucked up each tick and slowly reduce over time. + if(toxins > 0) + var/toxin_uptake = max(1,round(toxins/10)) + if(toxins > seed.get_trait(TRAIT_TOXINS_TOLERANCE)) + health -= toxin_uptake + toxins -= toxin_uptake + + // Check for pests and weeds. + // Some carnivorous plants happily eat pests. + if(pestlevel > 0) + if(seed.get_trait(TRAIT_CARNIVOROUS)) + health += HYDRO_SPEED_MULTIPLIER + pestlevel -= HYDRO_SPEED_MULTIPLIER + else if (pestlevel >= seed.get_trait(TRAIT_PEST_TOLERANCE)) + health -= HYDRO_SPEED_MULTIPLIER + + // Some plants thrive and live off of weeds. + if(weedlevel > 0) + if(seed.get_trait(TRAIT_PARASITE)) + health += HYDRO_SPEED_MULTIPLIER + weedlevel -= HYDRO_SPEED_MULTIPLIER + else if (weedlevel >= seed.get_trait(TRAIT_WEED_TOLERANCE)) + health -= HYDRO_SPEED_MULTIPLIER + + // Handle life and death. + // When the plant dies, weeds thrive and pests die off. + check_health() + + // If enough time (in cycles, not ticks) has passed since the plant was harvested, we're ready to harvest again. + if(seed.products && seed.products.len && \ + (age > seed.get_trait(TRAIT_MATURATION)) && \ + ((age - lastproduce) > seed.get_trait(TRAIT_PRODUCTION)) && \ + (!harvest && !dead)) + harvest = 1 + lastproduce = age + + if(prob(3)) // On each tick, there's a chance the pest population will increase + pestlevel += 0.1 * HYDRO_SPEED_MULTIPLIER + + // Some seeds will self-harvest if you don't keep a lid on them. + if(seed && seed.can_self_harvest && harvest && !closed_system && prob(5)) + harvest() + + check_health() + return diff --git a/code/modules/hydroponics/trays/tray_reagents.dm b/code/modules/hydroponics/trays/tray_reagents.dm new file mode 100644 index 0000000000..940a6fb01a --- /dev/null +++ b/code/modules/hydroponics/trays/tray_reagents.dm @@ -0,0 +1,143 @@ + +/obj/item/weapon/plantspray + icon = 'icons/obj/hydroponics_machines.dmi' + item_state = "spray" + flags = TABLEPASS | FPRINT | NOBLUDGEON + slot_flags = SLOT_BELT + throwforce = 4 + w_class = 2.0 + throw_speed = 2 + throw_range = 10 + var/toxicity = 4 + var/pest_kill_str = 0 + var/weed_kill_str = 0 + +/obj/item/weapon/plantspray/weeds // -- Skie + + name = "weed-spray" + desc = "It's a toxic mixture, in spray form, to kill small weeds." + icon_state = "weedspray" + weed_kill_str = 6 + +/obj/item/weapon/plantspray/pests + name = "pest-spray" + desc = "It's some pest eliminator spray! Do not inhale!" + icon_state = "pestspray" + pest_kill_str = 6 + +/obj/item/weapon/plantspray/pests/old + name = "bottle of pestkiller" + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle16" + +/obj/item/weapon/plantspray/pests/old/carbaryl + name = "bottle of carbaryl" + icon_state = "bottle16" + toxicity = 4 + pest_kill_str = 2 + +/obj/item/weapon/plantspray/pests/old/lindane + name = "bottle of lindane" + icon_state = "bottle18" + toxicity = 6 + pest_kill_str = 4 + +/obj/item/weapon/plantspray/pests/old/phosmet + name = "bottle of phosmet" + icon_state = "bottle15" + toxicity = 8 + pest_kill_str = 7 + +/obj/item/weapon/minihoe // -- Numbers + name = "mini hoe" + desc = "It's used for removing weeds or scratching your back." + icon = 'icons/obj/weapons.dmi' + icon_state = "hoe" + item_state = "hoe" + flags = FPRINT | TABLEPASS | CONDUCT | NOBLUDGEON + force = 5.0 + throwforce = 7.0 + w_class = 2.0 + matter = list("metal" = 50) + attack_verb = list("slashed", "sliced", "cut", "clawed") + + +// ************************************* +// Weedkiller defines for hydroponics +// ************************************* + +/obj/item/weedkiller + name = "bottle of weedkiller" + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle16" + flags = FPRINT | TABLEPASS + var/toxicity = 0 + var/weed_kill_str = 0 + +/obj/item/weedkiller/triclopyr + name = "bottle of glyphosate" + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle16" + flags = FPRINT | TABLEPASS + toxicity = 4 + weed_kill_str = 2 + +/obj/item/weedkiller/lindane + name = "bottle of triclopyr" + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle18" + flags = FPRINT | TABLEPASS + toxicity = 6 + weed_kill_str = 4 + +/obj/item/weedkiller/D24 + name = "bottle of 2,4-D" + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle15" + flags = FPRINT | TABLEPASS + toxicity = 8 + weed_kill_str = 7 + + +// ************************************* +// Nutrient defines for hydroponics +// ************************************* + +/obj/item/weapon/reagent_containers/glass/fertilizer + name = "fertilizer bottle" + desc = "A small glass bottle. Can hold up to 10 units." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle16" + flags = FPRINT | TABLEPASS | OPENCONTAINER + possible_transfer_amounts = null + w_class = 2.0 + + var/fertilizer //Reagent contained, if any. + + //Like a shot glass! + amount_per_transfer_from_this = 10 + volume = 10 + +/obj/item/weapon/reagent_containers/glass/fertilizer/New() + ..() + + src.pixel_x = rand(-5.0, 5) + src.pixel_y = rand(-5.0, 5) + + if(fertilizer) + reagents.add_reagent(fertilizer,10) + +/obj/item/weapon/reagent_containers/glass/fertilizer/ez + name = "bottle of E-Z-Nutrient" + icon_state = "bottle16" + fertilizer = "eznutrient" + +/obj/item/weapon/reagent_containers/glass/fertilizer/l4z + name = "bottle of Left 4 Zed" + icon_state = "bottle18" + fertilizer = "left4zed" + +/obj/item/weapon/reagent_containers/glass/fertilizer/rh + name = "bottle of Robust Harvest" + icon_state = "bottle15" + fertilizer = "robustharvest" diff --git a/code/modules/hydroponics/trays/tray_soil.dm b/code/modules/hydroponics/trays/tray_soil.dm new file mode 100644 index 0000000000..087c8acd9d --- /dev/null +++ b/code/modules/hydroponics/trays/tray_soil.dm @@ -0,0 +1,68 @@ +/obj/machinery/portable_atmospherics/hydroponics/soil + name = "soil" + icon_state = "soil" + density = 0 + use_power = 0 + mechanical = 0 + +/obj/machinery/portable_atmospherics/hydroponics/soil/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(istype(O,/obj/item/weapon/tank)) + return + else + ..() + +/obj/machinery/portable_atmospherics/hydroponics/soil/New() + ..() + verbs -= /obj/machinery/portable_atmospherics/hydroponics/verb/close_lid + +/obj/machinery/portable_atmospherics/hydroponics/soil/can_label() + return 0 + +/obj/machinery/portable_atmospherics/hydroponics/soil/CanPass() + return 1 + +// This is a hack pending a proper rewrite of the plant controller. +// Icons for plants are generated as overlays, so setting it to invisible wouldn't work. +// Hence using a blank icon. +/obj/machinery/portable_atmospherics/hydroponics/soil/invisible + name = "plant" + icon = 'icons/obj/seeds.dmi' + icon_state = "blank" + +/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/New(var/newloc,var/datum/seed/newseed) + ..() + seed = newseed + dead = 0 + age = 1 + health = seed.get_trait(TRAIT_ENDURANCE) + lastcycle = world.time + pixel_y = rand(-5,5) + check_health() + +/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/remove_dead() + ..() + del(src) + +/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/harvest() + ..() + if(!seed) + del(src) + +/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/die() + del(src) + +/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/process() + if(!seed) + del(src) + return + else if(name=="plant") + name = seed.display_name + ..() + +/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/Del() + // Check if we're masking a decal that needs to be visible again. + for(var/obj/effect/plant/plant in get_turf(src)) + if(plant.invisibility == INVISIBILITY_MAXIMUM) + plant.invisibility = initial(plant.invisibility) + plant.die_off() + ..() diff --git a/code/modules/hydroponics/hydro_tools.dm b/code/modules/hydroponics/trays/tray_tools.dm similarity index 100% rename from code/modules/hydroponics/hydro_tools.dm rename to code/modules/hydroponics/trays/tray_tools.dm diff --git a/code/modules/hydroponics/trays/tray_update_icons.dm b/code/modules/hydroponics/trays/tray_update_icons.dm new file mode 100644 index 0000000000..c0ff8cb0f2 --- /dev/null +++ b/code/modules/hydroponics/trays/tray_update_icons.dm @@ -0,0 +1,74 @@ +//Refreshes the icon and sets the luminosity +/obj/machinery/portable_atmospherics/hydroponics/update_icon() + + overlays.Cut() + + // Updates the plant overlay. + if(!isnull(seed)) + + if(mechanical && health <= (seed.get_trait(TRAIT_ENDURANCE) / 2)) + overlays += "over_lowhealth3" + + if(dead) + var/ikey = "[seed.get_trait(TRAIT_PLANT_ICON)]-dead" + var/image/dead_overlay = plant_icon_cache["[ikey]"] + if(!dead_overlay) + dead_overlay = image('icons/obj/hydroponics_growing.dmi', "[ikey]") + dead_overlay.color = DEAD_PLANT_COLOUR + overlays |= dead_overlay + else + if(!seed.growth_stages) + seed.update_growth_stages() + if(!seed.growth_stages) + world << "Seed type [seed.get_trait(TRAIT_PLANT_ICON)] cannot find a growth stage value." + return + var/overlay_stage = 1 + if(age >= seed.get_trait(TRAIT_MATURATION)) + overlay_stage = seed.growth_stages + else + overlay_stage = max(1,round(seed.get_trait(TRAIT_MATURATION) / seed.growth_stages)) + + var/ikey = "[seed.get_trait(TRAIT_PLANT_ICON)]-[overlay_stage]" + var/image/plant_overlay = plant_icon_cache["[ikey]-[seed.get_trait(TRAIT_PLANT_COLOUR)]"] + if(!plant_overlay) + plant_overlay = image('icons/obj/hydroponics_growing.dmi', "[ikey]") + plant_overlay.color = seed.get_trait(TRAIT_PLANT_COLOUR) + plant_icon_cache["[ikey]-[seed.get_trait(TRAIT_PLANT_COLOUR)]"] = plant_overlay + overlays |= plant_overlay + + if(harvest && overlay_stage == seed.growth_stages) + ikey = "[seed.get_trait(TRAIT_PRODUCT_ICON)]" + var/image/harvest_overlay = plant_icon_cache["product-[ikey]-[seed.get_trait(TRAIT_PLANT_COLOUR)]"] + if(!harvest_overlay) + harvest_overlay = image('icons/obj/hydroponics_products.dmi', "[ikey]") + harvest_overlay.color = seed.get_trait(TRAIT_PRODUCT_COLOUR) + plant_icon_cache["product-[ikey]-[seed.get_trait(TRAIT_PRODUCT_COLOUR)]"] = harvest_overlay + overlays |= harvest_overlay + + //Draw the cover. + if(closed_system) + overlays += "hydrocover" + + //Updated the various alert icons. + if(mechanical) + if(waterlevel <= 10) + overlays += "over_lowwater3" + if(nutrilevel <= 2) + overlays += "over_lownutri3" + if(weedlevel >= 5 || pestlevel >= 5 || toxins >= 40) + overlays += "over_alert3" + if(harvest) + overlays += "over_harvest3" + + // Update bioluminescence. + if(seed) + if(seed.get_trait(TRAIT_BIOLUM)) + SetLuminosity(round(seed.get_trait(TRAIT_POTENCY)/10)) + if(seed.get_trait(TRAIT_BIOLUM_COLOUR)) + l_color = seed.get_trait(TRAIT_BIOLUM_COLOUR) + else + l_color = null + return + + SetLuminosity(0) + return \ No newline at end of file