/datum/plantgene /// Label used when applying trait. var/genetype /// Values to copy into the target seed datum. var/list/values /datum/seed //Tracking. /// Unique identifier var/uid /// Index for global list var/name /// Plant name for seed packet var/seed_name /// Descriptor for packet var/seed_noun = SEED_NOUN_SEEDS /// Prettier name var/display_name /// If set, seed will not display variety number var/roundstart /// Only used for the random seed packets. var/mysterious /// Mostly used for living mobs var/can_self_harvest = 0 /// Number of stages the plant passes through before it is mature var/growth_stages = 0 /// Initialized in New() var/list/traits = list() /// Possible predefined mutant varieties, if any var/list/mutants /// Chemicals that plant produces in products/injects into victim var/list/chems /// The plant will absorb these gasses during its life var/list/consume_gasses /// The plant will exude these gasses during its life var/list/exude_gasses /// Used by the reagent grinder var/kitchen_tag /// Garbage item produced when eaten var/trash_type /// Graffiti decal var/splat_type = /obj/effect/decal/cleanable/fruit_smudge var/product_type = /obj/item/reagent_containers/food/snacks/grown /// If set, overrides the description of the product (What the produce looks like for example) var/product_desc /// If set, overrides the extended scription of the product (Useful to describe the 'lore') var/product_desc_extended /// The base percentage chance the plant will grow per each process(). var/base_growth_speed = 10 /// The boost to the base growth speed applied to the plant if within temperature preferences. var/temperature_growth_boost = 20 /// The boost to the base growth speed applied to the plant if within light preferences. var/light_growth_boost = 5 var/force_layer var/hydrotray_only /datum/seed/proc/setup_traits() /datum/seed/New() SET_SEED_TRAIT(src, TRAIT_SPOROUS, 0) SET_SEED_TRAIT(src, TRAIT_IMMUTABLE, 0) SET_SEED_TRAIT(src, TRAIT_HARVEST_REPEAT, 0) SET_SEED_TRAIT(src, TRAIT_PRODUCES_POWER, 0) SET_SEED_TRAIT(src, TRAIT_JUICY, 0) SET_SEED_TRAIT(src, TRAIT_EXPLOSIVE, 0) SET_SEED_TRAIT(src, TRAIT_CARNIVOROUS, 0) SET_SEED_TRAIT(src, TRAIT_PARASITE, 0) SET_SEED_TRAIT(src, TRAIT_STINGS, 0) SET_SEED_TRAIT(src, TRAIT_YIELD, 0) SET_SEED_TRAIT(src, TRAIT_SPREAD, 0) SET_SEED_TRAIT(src, TRAIT_MATURATION, 0) SET_SEED_TRAIT(src, TRAIT_PRODUCTION, 0) SET_SEED_TRAIT(src, TRAIT_TELEPORTING, 0) SET_SEED_TRAIT(src, TRAIT_BIOLUM, 0) SET_SEED_TRAIT(src, TRAIT_ALTER_TEMP, 0) SET_SEED_TRAIT(src, TRAIT_PRODUCT_ICON, 0) SET_SEED_TRAIT(src, TRAIT_PLANT_ICON, 0) SET_SEED_TRAIT(src, TRAIT_PRODUCT_COLOUR, 0) SET_SEED_TRAIT(src, TRAIT_BIOLUM_COLOUR, 0) SET_SEED_TRAIT(src, TRAIT_BIOLUM_PWR, 1) SET_SEED_TRAIT(src, TRAIT_POTENCY, 1) SET_SEED_TRAIT(src, TRAIT_REQUIRES_NUTRIENTS, 1) SET_SEED_TRAIT(src, TRAIT_REQUIRES_WATER, 1) SET_SEED_TRAIT(src, TRAIT_WATER_CONSUMPTION, 3) SET_SEED_TRAIT(src, TRAIT_LIGHT_TOLERANCE, 2.5) // Plants will begin to die if the light levels are 2.5 or more lumens from their ideal. SET_SEED_TRAIT(src, TRAIT_TOXINS_TOLERANCE, 5) SET_SEED_TRAIT(src, TRAIT_PEST_TOLERANCE, 5) SET_SEED_TRAIT(src, TRAIT_WEED_TOLERANCE, 5) SET_SEED_TRAIT(src, TRAIT_IDEAL_LIGHT, IDEAL_LIGHT_TEMPERATE) SET_SEED_TRAIT(src, TRAIT_HEAT_TOLERANCE, 12) // Plants will begin to die if they're twelve or more degrees from their ideal temperature. SET_SEED_TRAIT(src, TRAIT_LOWKPA_TOLERANCE, 25) // Plants survive all the way down to a quarter of an atmosphere! SET_SEED_TRAIT(src, TRAIT_ENDURANCE, 100) SET_SEED_TRAIT(src, TRAIT_HIGHKPA_TOLERANCE, 200) SET_SEED_TRAIT(src, TRAIT_IDEAL_HEAT, IDEAL_HEAT_TEMPERATE) SET_SEED_TRAIT(src, TRAIT_NUTRIENT_CONSUMPTION, 0.25) SET_SEED_TRAIT(src, TRAIT_PLANT_COLOUR, "#46B543") SET_SEED_TRAIT(src, TRAIT_LARGE, 0) SET_SEED_TRAIT(src, TRAIT_HEAT_PREFERENCE, 5) // By default, plants grow faster in a temperature within five degrees of their ideal. SET_SEED_TRAIT(src, TRAIT_LIGHT_PREFERENCE, 1.5) // Similarly, they grow faster under lumens within 1.5 of their ideal. setup_traits() update_growth_stages() /datum/seed/proc/create_spores(var/turf/T) if(!T) return if(!istype(T)) T = get_turf(T) if(!T) return var/datum/reagents/R = new/datum/reagents(100) if(chems.len) for(var/rid in chems) var/injecting = max(1,GET_SEED_TRAIT(src, TRAIT_POTENCY)/5) R.add_reagent(rid,injecting) var/datum/effect/effect/system/smoke_spread/chem/spores/S = new(name) S.attach(T) S.set_up(R, round(GET_SEED_TRAIT(src, TRAIT_POTENCY)/4), 0, T, 40) S.start() /// Does brute damage to a target. /datum/seed/proc/do_thorns(var/mob/living/carbon/human/target, var/obj/item/fruit, var/target_limb) if(!GET_SEED_TRAIT(src, TRAIT_CARNIVOROUS)) return if(!istype(target)) if(israt(target)) new /obj/effect/decal/remains/rat(get_turf(target)) qdel(target) else if(istype(target, /mob/living/simple_animal/lizard)) new /obj/effect/decal/remains/lizard(get_turf(target)) qdel(target) return if(!target_limb) target_limb = pick(BP_L_FOOT,BP_R_FOOT,BP_L_LEG,BP_R_LEG,BP_L_HAND,BP_R_HAND,BP_L_ARM, BP_R_ARM,BP_HEAD,BP_CHEST,BP_GROIN) var/obj/item/organ/external/affecting = target.get_organ(target_limb) var/damage = 0 if(GET_SEED_TRAIT(src, TRAIT_CARNIVOROUS)) if(GET_SEED_TRAIT(src, TRAIT_CARNIVOROUS) == 2) if(affecting) to_chat(target, SPAN_DANGER("\The [fruit]'s thorns pierce your [affecting.name] greedily!")) else to_chat(target, SPAN_DANGER("\The [fruit]'s thorns pierce your flesh greedily!")) damage = GET_SEED_TRAIT(src, TRAIT_POTENCY)/2 else if(affecting) to_chat(target, SPAN_DANGER("\The [fruit]'s thorns dig deeply into your [affecting.name]!")) else to_chat(target, SPAN_DANGER("\The [fruit]'s thorns dig deeply into your flesh!")) damage = GET_SEED_TRAIT(src, 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_SEED_TRAIT(src, TRAIT_STINGS)) return if(chems && chems.len) var/body_coverage = HEAD|FACE|EYES|UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS for(var/obj/item/clothing/clothes in target) if(target.l_hand == clothes|| target.r_hand == clothes) continue body_coverage &= ~(clothes.body_parts_covered) if(!body_coverage) return to_chat(target, SPAN_DANGER("You are stung by \the [fruit]!")) for(var/rid in chems) var/injecting = min(5,max(1,GET_SEED_TRAIT(src, 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 && !(locate(/obj/effect/plant) in T)) 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_SEED_TRAIT(src, TRAIT_BIOLUM)) var/pwr if(GET_SEED_TRAIT(src, TRAIT_BIOLUM_PWR) == 0) pwr = GET_SEED_TRAIT(src, TRAIT_BIOLUM) else pwr = GET_SEED_TRAIT(src, TRAIT_BIOLUM_PWR) var/clr if(GET_SEED_TRAIT(src, TRAIT_BIOLUM_COLOUR)) clr = GET_SEED_TRAIT(src, TRAIT_BIOLUM_COLOUR) splat.set_light(GET_SEED_TRAIT(src, TRAIT_POTENCY)/10, pwr, clr) addtimer(CALLBACK(splat, TYPE_PROC_REF(/atom, set_light), 0), rand(3 MINUTES, 5 MINUTES)) var/flesh_colour = GET_SEED_TRAIT(src, TRAIT_FLESH_COLOUR) if(!flesh_colour) flesh_colour = GET_SEED_TRAIT(src, TRAIT_PRODUCT_COLOUR) if(flesh_colour) splat.color = GET_SEED_TRAIT(src, 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_SEED_TRAIT(src, 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_SEED_TRAIT(src, TRAIT_EXPLOSIVE)) create_spores(origin_turf) var/flood_dist = min(10,max(1,GET_SEED_TRAIT(src, 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 GLOB.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) if(origin_turf) origin_turf.visible_message(SPAN_DANGER("The [thrown.name] explodes!")) qdel(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_SEED_TRAIT(src, TRAIT_JUICY) && splatted) splatter(origin_turf,thrown) if(origin_turf) origin_turf.visible_message(SPAN_DANGER("The [thrown.name] splatters against [target]!")) qdel(thrown) if(GET_SEED_TRAIT(src, TRAIT_TELEPORTING)) var/outer_teleport_radius = GET_SEED_TRAIT(src, TRAIT_POTENCY)/5 var/inner_teleport_radius = GET_SEED_TRAIT(src, 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) var/turf/picked = get_turf(pick(turfs)) var/obj/effect/portal/P = new /obj/effect/portal(get_turf(target)) P.set_target(picked) P.creator = null /// Checks the plant's environment. If anything is improper, adds to a value that will ultimately be used to damage the plant. /datum/seed/proc/handle_environment(var/turf/current_turf, var/datum/gas_mixture/environment, var/light_supplied, 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_SEED_TRAIT(src, TRAIT_LOWKPA_TOLERANCE)|| pressure > GET_SEED_TRAIT(src, TRAIT_HIGHKPA_TOLERANCE)) health_change += rand(1,3) * HYDRO_SPEED_MULTIPLIER // We take the absolute value of the environment's temperature minus the ideal heat - closer to 0 is better, in this case. // If that value is greater than the heat tolerance, we apply some damage to the plant. if(check_heat_tolerances(environment)) 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_SEED_TRAIT(src, TRAIT_POTENCY)/5))/exude_gasses.len))) // Handle light requirements. if(!light_supplied) light_supplied = current_turf.get_lumcount(0, 3) * 10 if(light_supplied) if(check_light_tolerances(light_supplied)) health_change += rand(1,3) * HYDRO_SPEED_MULTIPLIER return health_change /// Returns true if a plant is outside their light tolerances, otherwise false. /datum/seed/proc/check_light_tolerances(var/light_supplied) if(abs(light_supplied - GET_SEED_TRAIT(src, TRAIT_IDEAL_LIGHT)) > GET_SEED_TRAIT(src, TRAIT_LIGHT_TOLERANCE)) return TRUE return FALSE /// Returns true if a plant is outside their heat tolerances, otherwise false. /datum/seed/proc/check_heat_tolerances(var/datum/gas_mixture/environment) if(abs(environment.temperature - GET_SEED_TRAIT(src, TRAIT_IDEAL_HEAT)) > GET_SEED_TRAIT(src, TRAIT_HEAT_TOLERANCE)) return TRUE return FALSE /// Returns true if a plant is in their light preferences, otherwise false. /datum/seed/proc/check_light_preferences(var/light_supplied) if(abs(light_supplied - GET_SEED_TRAIT(src, TRAIT_IDEAL_LIGHT)) < GET_SEED_TRAIT(src, TRAIT_LIGHT_PREFERENCE)) return TRUE return FALSE /// Returns true if a plant is in their heat preferences, otherwise false. /datum/seed/proc/check_heat_preferences(var/datum/gas_mixture/environment) if(abs(environment.temperature - GET_SEED_TRAIT(src, TRAIT_IDEAL_HEAT)) < GET_SEED_TRAIT(src, TRAIT_HEAT_PREFERENCE)) return TRUE return FALSE /// Checks the preferences of the seed, and returns the percentage chance for growth to occur. Called in tray_process. /datum/seed/proc/get_probability_of_growth(var/turf/current_turf, var/datum/gas_mixture/environment, var/light_supplied, var/check_only) // By standard, the probability of growth is only the base. This rises if growing conditions are within their preferences. // This is intended to motivate the use of atmospheric equipment to more viably grow plants with irregular preferences. // You *can* grow plants outside of their preferences without them dying so long as it's within their tolerance, but it'll be pretty slow. var/return_probability = base_growth_speed // Handle light requirements. if(!light_supplied) light_supplied = current_turf.get_lumcount(0, 3) * 10 // Are we within the preference zone for temperature? If so, add to the chance of growth. if(check_heat_preferences(environment)) return_probability += temperature_growth_boost // Same for light! if(check_light_preferences(light_supplied)) return_probability += light_growth_boost return return_probability /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) return impact /datum/seed/proc/generate_name() var/prefix = "" var/name = "" if(prob(50)) //start with a prefix. //These are various plant/mushroom genuses. //I realize these might not be entirely accurate, but it could facilitate RP. var/list/possible_prefixes if(seed_noun == SEED_NOUN_CUTTINGS || seed_noun == SEED_NOUN_SEEDS || (seed_noun == SEED_NOUN_NODES && prob(50))) possible_prefixes = list("amelanchier", "saskatoon", "magnolia", "angiosperma", "osmunda", "scabiosa", "spigelia", "psydrax", "chastetree", "strychnos", "treebine", "caper", "justica", "ragwortus", "everlasting", "combretum", "loganiaceae", "gelsemium", "logania", "sabadilla", "neuburgia", "canthium", "rytigynia", "chaste", "vitex", "cissus", "capparis", "senecio", "curry", "cycad", "liverwort", "charophyta", "glaucophyte", "pinidae", "vascular", "embryophyte", "lillopsida") else possible_prefixes = list("bisporus", "bitorquis", "campestris", "crocodilinus", "agaricus", "armillaria", "matsutake", "mellea", "ponderosa", "auricularia", "auricala", "polytricha", "boletus", "badius", "edulis", "mirabilis", "zelleri", "calvatia", "gigantea", "clitopilis", "prumulus", "entoloma", "abortivum", "suillus", "tuber", "aestivum", "volvacea", "delica", "russula", "rozites") possible_prefixes |= list("butter", "shad", "sugar", "june", "wild", "rigus", "curry", "hard", "soft", "dark", "brick", "stone", "red", "brown", "black", "white", "paper", "slippery", "honey", "bitter") prefix = pick(possible_prefixes) var/num = rand(2,5) var/list/possible_name = list("rhon", "cus", "quam", "met", "eget", "was", "reg", "zor", "fra", "rat", "sho", "ghen", "pa", "eir", "lip", "sum", "lor", "em", "tem", "por", "invi", "dunt", "ut", "la", "bore", "mag", "na", "al", "i", "qu", "yam", "er", "at", "sed", "di", "am", "vol", "up", "tua", "at", "ve", "ro", "eos", "et", "ac", "cus") for(var/i in 1 to num) var/syl = pick(possible_name) possible_name -= syl name += syl if(prefix) name = "[prefix] [name]" seed_name = name display_name = name display_name = "[name] plant" /// Creates a random seed. MAKE SURE THE LINE HAS DIVERGED BEFORE THIS IS CALLED. /datum/seed/proc/randomize(var/list/native_gases = list(GAS_OXYGEN, GAS_NITROGEN, GAS_CO2, GAS_HYDROGEN)) roundstart = FALSE mysterious = TRUE seed_noun = pick(SEED_NOUN_SEEDS, SEED_NOUN_PITS, SEED_NOUN_NODES, SEED_NOUN_CUTTINGS) SET_SEED_TRAIT_BOUNDED(src, TRAIT_POTENCY, rand(5,30), 200, 0, 1) SET_SEED_TRAIT(src, TRAIT_PRODUCT_ICON, pick(SSplants.plant_product_sprites)) SET_SEED_TRAIT(src, TRAIT_PLANT_ICON, pick(SSplants.plant_sprites)) SET_SEED_TRAIT(src, TRAIT_PLANT_COLOUR, get_random_colour(0,75,190)) SET_SEED_TRAIT(src, TRAIT_PRODUCT_COLOUR, get_random_colour(0,75,190)) update_growth_stages() if(prob(20)) SET_SEED_TRAIT(src, TRAIT_HARVEST_REPEAT, 1) if(prob(15)) if(prob(15)) SET_SEED_TRAIT(src, TRAIT_JUICY, 2) else SET_SEED_TRAIT(src, TRAIT_JUICY, 1) if(prob(5)) SET_SEED_TRAIT(src, TRAIT_STINGS, 1) if(prob(5)) SET_SEED_TRAIT(src, TRAIT_PRODUCES_POWER, 1) if(prob(1)) SET_SEED_TRAIT(src, TRAIT_EXPLOSIVE, 1) else if(prob(1)) SET_SEED_TRAIT(src, TRAIT_TELEPORTING, 1) if(prob(5)) consume_gasses = list() var/gas = pick_n_take(native_gases) consume_gasses[gas] = rand(3,9) if(prob(5)) exude_gasses = list() var/gas = pick_n_take(native_gases) exude_gasses[gas] = rand(3,9) chems = list() if(prob(80)) chems[/singleton/reagent/nutriment] = list(rand(1,10),rand(10,20)) var/additional_chems = rand(0,5) if(additional_chems) var/list/possible_chems = list( /singleton/reagent/acetone, /singleton/reagent/alkysine, /singleton/reagent/bicaridine, /singleton/reagent/butazoline, /singleton/reagent/blood, /singleton/reagent/cryoxadone, /singleton/reagent/drugs/cryptobiolin, /singleton/reagent/toxin/cyanide, /singleton/reagent/dermaline, /singleton/reagent/dexalin, /singleton/reagent/ethylredoxrazine, /singleton/reagent/hydrazine, /singleton/reagent/hyperzine, /singleton/reagent/hyronalin, /singleton/reagent/drugs/impedrezene, /singleton/reagent/mercury, /singleton/reagent/drugs/mindbreaker, /singleton/reagent/inaprovaline, /singleton/reagent/peridaxon, /singleton/reagent/toxin/plasticide, /singleton/reagent/potassium, /singleton/reagent/radium, /singleton/reagent/rezadone, /singleton/reagent/ryetalyn, /singleton/reagent/slimejelly, /singleton/reagent/drugs/mms, /singleton/reagent/soporific, /singleton/reagent/sugar, /singleton/reagent/synaptizine, /singleton/reagent/thermite, /singleton/reagent/toxin, /singleton/reagent/mortaphenyl, /singleton/reagent/water, /singleton/reagent/woodpulp, /singleton/reagent/drugs/ambrosia_extract, /singleton/reagent/drugs/skrell_nootropic, /singleton/reagent/toxin/berserk ) 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_SEED_TRAIT(src, TRAIT_REQUIRES_NUTRIENTS, 1) SET_SEED_TRAIT(src, TRAIT_NUTRIENT_CONSUMPTION, rand(25)/25) else SET_SEED_TRAIT(src, TRAIT_REQUIRES_NUTRIENTS, 0) if(prob(90)) SET_SEED_TRAIT(src, TRAIT_REQUIRES_WATER, 1) SET_SEED_TRAIT(src, TRAIT_WATER_CONSUMPTION, rand(10)) else SET_SEED_TRAIT(src, TRAIT_REQUIRES_WATER, 0) SET_SEED_TRAIT(src, TRAIT_IDEAL_HEAT, rand(100,400)) SET_SEED_TRAIT(src, TRAIT_HEAT_TOLERANCE, rand(10,30)) SET_SEED_TRAIT(src, TRAIT_IDEAL_LIGHT, rand(2,10)) SET_SEED_TRAIT(src, TRAIT_LIGHT_TOLERANCE, rand(2,7)) SET_SEED_TRAIT(src, TRAIT_TOXINS_TOLERANCE, rand(2,7)) SET_SEED_TRAIT(src, TRAIT_PEST_TOLERANCE, rand(2,7)) SET_SEED_TRAIT(src, TRAIT_WEED_TOLERANCE, rand(2,7)) SET_SEED_TRAIT(src, TRAIT_LOWKPA_TOLERANCE, rand(10,50)) SET_SEED_TRAIT(src, TRAIT_HIGHKPA_TOLERANCE, rand(100,300)) if(prob(5)) SET_SEED_TRAIT(src, TRAIT_ALTER_TEMP, rand(-5,5)) if(prob(1)) SET_SEED_TRAIT(src, TRAIT_IMMUTABLE, -1) var/carnivore_prob = rand(100) if(carnivore_prob < 5) SET_SEED_TRAIT(src, TRAIT_CARNIVOROUS, 2) else if(carnivore_prob < 10) SET_SEED_TRAIT(src, TRAIT_CARNIVOROUS, 1) if(prob(10)) SET_SEED_TRAIT(src, TRAIT_PARASITE, 1) var/vine_prob = rand(100) if(vine_prob < 5) SET_SEED_TRAIT(src, TRAIT_SPREAD, 2) else if(vine_prob < 10) SET_SEED_TRAIT(src, TRAIT_SPREAD, 1) if(prob(5)) SET_SEED_TRAIT(src, TRAIT_BIOLUM, 1) SET_SEED_TRAIT(src, TRAIT_BIOLUM_COLOUR, get_random_colour(0,75,190)) if(prob(5)) SET_SEED_TRAIT(src, TRAIT_BIOLUM_PWR, rand(0,-5)-rand()) else SET_SEED_TRAIT(src, TRAIT_BIOLUM_PWR, rand(0,5)+rand()) if(prob(5)) SET_SEED_TRAIT(src, TRAIT_SPOROUS, 1) SET_SEED_TRAIT(src, TRAIT_ENDURANCE, rand(60,100)) SET_SEED_TRAIT(src, TRAIT_YIELD, rand(3,15)) SET_SEED_TRAIT(src, TRAIT_MATURATION, rand(5,15)) SET_SEED_TRAIT(src, TRAIT_PRODUCTION, GET_SEED_TRAIT(src, TRAIT_MATURATION)+rand(2,5)) generate_name() /// Returns a key corresponding to an entry in the global seed list. /datum/seed/proc/get_mutant_variant() if(!mutants || !mutants.len || GET_SEED_TRAIT(src, 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_SEED_TRAIT(src, TRAIT_IMMUTABLE) > 0) return source_turf.visible_message(SPAN_NOTICE("\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]'s glow changes colour!") else source_turf.visible_message(SPAN_NOTICE("\The [display_name]'s glow dims...")) if(11) SET_SEED_TRAIT(src, 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_SEED_TRAIT(src, 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. switch(gene.genetype) if(GENE_BIOCHEMISTRY) for(var/trait in list(TRAIT_YIELD, TRAIT_ENDURANCE)) if(GET_SEED_TRAIT(src, trait) > 0) SET_SEED_TRAIT_BOUNDED(src, trait, GET_SEED_TRAIT(src, trait), null, 1, 0.85) 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)) gene.values["[TRAIT_EXUDE_GASSES]"] = null gene.values["[TRAIT_CHEMS]"] = null if(GENE_DIET) var/list/new_gasses = gene.values["[TRAIT_CONSUME_GASSES]"] consume_gasses |= new_gasses gene.values["[TRAIT_CONSUME_GASSES]"] = null if(GENE_METABOLISM) product_type = gene.values["product_type"] gene.values["product_type"] = null for(var/trait in gene.values) SET_SEED_TRAIT(src, 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_BIOCHEMISTRY) P.values["[TRAIT_CHEMS]"] = chems P.values["[TRAIT_EXUDE_GASSES]"] = exude_gasses traits_to_copy = list(TRAIT_POTENCY) if(GENE_OUTPUT) traits_to_copy = list(TRAIT_PRODUCES_POWER,TRAIT_BIOLUM, TRAIT_BIOLUM_PWR) if(GENE_ATMOSPHERE) traits_to_copy = list(TRAIT_HEAT_TOLERANCE,TRAIT_LOWKPA_TOLERANCE,TRAIT_HIGHKPA_TOLERANCE) if(GENE_HARDINESS) traits_to_copy = list(TRAIT_TOXINS_TOLERANCE,TRAIT_PEST_TOLERANCE,TRAIT_WEED_TOLERANCE,TRAIT_ENDURANCE) if(GENE_METABOLISM) P.values["product_type"] = product_type traits_to_copy = list(TRAIT_REQUIRES_NUTRIENTS,TRAIT_REQUIRES_WATER,TRAIT_ALTER_TEMP) if(GENE_VIGOUR) traits_to_copy = list(TRAIT_PRODUCTION,TRAIT_MATURATION,TRAIT_YIELD,TRAIT_SPREAD) if(GENE_DIET) P.values["[TRAIT_CONSUME_GASSES]"] = consume_gasses traits_to_copy = list(TRAIT_CARNIVOROUS,TRAIT_PARASITE,TRAIT_NUTRIENT_CONSUMPTION,TRAIT_WATER_CONSUMPTION) if(GENE_ENVIRONMENT) traits_to_copy = list(TRAIT_IDEAL_HEAT,TRAIT_IDEAL_LIGHT,TRAIT_LIGHT_TOLERANCE) if(GENE_PIGMENT) traits_to_copy = list(TRAIT_PLANT_COLOUR,TRAIT_PRODUCT_COLOUR,TRAIT_BIOLUM_COLOUR,TRAIT_LEAVES_COLOUR) if(GENE_STRUCTURE) traits_to_copy = list(TRAIT_PLANT_ICON,TRAIT_PRODUCT_ICON,TRAIT_HARVEST_REPEAT, TRAIT_SPOROUS, TRAIT_LARGE) if(GENE_FRUIT) traits_to_copy = list(TRAIT_STINGS,TRAIT_EXPLOSIVE,TRAIT_FLESH_COLOUR,TRAIT_JUICY) if(GENE_SPECIAL) traits_to_copy = list(TRAIT_TELEPORTING) for(var/trait in traits_to_copy) P.values["[trait]"] = GET_SEED_TRAIT(src, 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,var/stunted_status = FALSE) if(!user) return if(!force_amount && GET_SEED_TRAIT(src, TRAIT_YIELD) == 0 && !harvest_sample) if(istype(user)) to_chat(user, SPAN_DANGER("You fail to harvest anything useful.")) else if(istype(user)) to_chat(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 SSplants.seeds)) uid = SSplants.seeds.len + 1 name = "[uid]" SSplants.seeds[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_SEED_TRAIT(src, TRAIT_YIELD) > -1) if(isnull(yield_mod) || yield_mod < 1) yield_mod = 0 total_yield = GET_SEED_TRAIT(src, TRAIT_YIELD) else total_yield = GET_SEED_TRAIT(src, TRAIT_YIELD) + rand(yield_mod) total_yield = max(1,total_yield) // If the plant is stunted, you get half the yield. if(stunted_status) total_yield *= 0.5 for(var/i = 0;i 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 new_seed.kitchen_tag = kitchen_tag new_seed.trash_type = trash_type new_seed.product_type = product_type //Copy over everything else. 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_SEED_TRAIT(src, TRAIT_PLANT_ICON)) growth_stages = SSplants.plant_sprites[GET_SEED_TRAIT(src, TRAIT_PLANT_ICON)] else growth_stages = 0 /datum/seed/proc/get_growth_type() SHOULD_NOT_SLEEP(TRUE) SHOULD_BE_PURE(TRUE) if(GET_SEED_TRAIT(src, TRAIT_SPREAD) == 2) switch(seed_noun) if(SEED_NOUN_CUTTINGS) return GROWTH_WORMS if(SEED_NOUN_NODES) return GROWTH_BIOMASS if(SEED_NOUN_SPORES) return GROWTH_MOLD else return GROWTH_VINES return 0 /** * A list of seed icons, to avoid regenerating images like there's no tomorrow * * Only access this by using the `SEED_ICON_CACHE_KEY` macro * * The structure is an associative list with the result of `SEED_ICON_CACHE_KEY` as the key * and an `/image` as the value */ GLOBAL_LIST_INIT(seed_icon_cache, list()) ///Generates a text hash that works as the key for the `seed_icon_cache` GLOB list #define SEED_ICON_CACHE_KEY(file, state, color, leaves_overlay) "[file]|||[state]|||[color]|||[leaves_overlay]" /datum/seed/proc/get_icon(growth_stage) SHOULD_NOT_SLEEP(TRUE) RETURN_TYPE(/image) if(isnull(growth_stage)) crash_with("No growth stage was supplied when getting the icon!") /* Setup a bunch of shit that should have been done in a very different way but alas */ //The icon of the plant var/icon_trait = GET_SEED_TRAIT(src, TRAIT_PLANT_ICON) //The type of growth var/growth_type = get_growth_type() //If it's a vine var/is_vine = (GET_SEED_TRAIT(src, TRAIT_SPREAD) == 2) //If the icon is a large one var/is_large_icon = GET_SEED_TRAIT(src, TRAIT_LARGE) //The color of the leaves, if any var/leaves_color = GET_SEED_TRAIT(src, TRAIT_LEAVES_COLOUR) /* The part where we select what to request */ //Pick what file we want var/icon_file_to_request if(is_vine) icon_file_to_request = 'icons/obj/hydroponics_vines.dmi' else if(is_large_icon) icon_file_to_request = 'icons/obj/hydroponics_large.dmi' else icon_file_to_request = 'icons/obj/hydroponics_growing.dmi' //Pick what icon state to request var/icon_state_to_request = (is_vine) ? "[growth_type]-[growth_stage]" : "[icon_trait]-[growth_stage]" //Pick the color to assign to the image var/color_to_request = GET_SEED_TRAIT(src, TRAIT_PLANT_COLOUR) //The leaves color overlay to request var/leaves_overlay_to_request = (leaves_color) ? "[icon_trait]-[growth_stage]-leaves" : null /* Find or generate the image and return it */ //See if we have this in our cache if(SEED_ICON_CACHE_KEY(icon_file_to_request, icon_state_to_request, color_to_request, leaves_overlay_to_request) in GLOB.seed_icon_cache) return GLOB.seed_icon_cache[SEED_ICON_CACHE_KEY(icon_file_to_request, icon_state_to_request, color_to_request, leaves_overlay_to_request)] //No luck, it's not in the cache, time to generate it else //Check that there's a valid icon state we can use, abort otherwise var/valid_icon_states = icon_states(icon_file_to_request, 2) if(!(icon_state_to_request in valid_icon_states)) crash_with("A seed icon was requested with an invalid icon state! Icon file: [icon_file_to_request] ---- Icon state: [icon_state_to_request]") var/image/generated_image = image(icon_file_to_request, icon_state_to_request) //Assign the requested generated_image.color = color_to_request //If it's a large icon, offset it if(is_large_icon) generated_image.pixel_x = -8 generated_image.pixel_y = -16 //If leaves are requested, add them as overlays if(leaves_overlay_to_request) var/image/leaves_image = image(icon_file_to_request, leaves_overlay_to_request) leaves_image.color = leaves_color leaves_image.appearance_flags = RESET_COLOR //Add ourself as overlays to the generated image generated_image.AddOverlays(leaves_image) //Store the image in the cache, so we won't have to keep generating it GLOB.seed_icon_cache[SEED_ICON_CACHE_KEY(icon_file_to_request, icon_state_to_request, color_to_request, leaves_overlay_to_request)] = generated_image //Return the image return generated_image #undef SEED_ICON_CACHE_KEY