mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-12 00:27:31 +01:00
00ccf0c6b5
# Conflicts: # .github/CODEOWNERS # .github/workflows/compile_changelogs.yml # .github/workflows/stale.yml # SQL/database_changelog.md # _maps/map_files/CatwalkStation/CatwalkStation_2023.dmm # code/__DEFINES/atom_hud.dm # code/__DEFINES/inventory.dm # code/__DEFINES/mobs.dm # code/__DEFINES/species_clothing_paths.dm # code/__DEFINES/subsystems.dm # code/__DEFINES/surgery.dm # code/__HELPERS/global_lists.dm # code/_globalvars/lists/maintenance_loot.dm # code/_globalvars/traits/_traits.dm # code/controllers/subsystem/minor_mapping.dm # code/controllers/subsystem/processing/quirks.dm # code/controllers/subsystem/shuttle.dm # code/datums/components/palette.dm # code/datums/components/surgery_initiator.dm # code/datums/diseases/advance/advance.dm # code/datums/hud.dm # code/datums/mood.dm # code/datums/mutations/chameleon.dm # code/datums/quirks/negative_quirks/nyctophobia.dm # code/datums/status_effects/debuffs/debuffs.dm # code/datums/status_effects/debuffs/drunk.dm # code/datums/status_effects/debuffs/slime/slime_leech.dm # code/datums/weather/weather.dm # code/game/data_huds.dm # code/game/objects/items.dm # code/game/objects/items/devices/scanners/health_analyzer.dm # code/game/objects/items/frog_statue.dm # code/game/objects/items/rcd/RLD.dm # code/game/objects/items/robot/items/hypo.dm # code/game/objects/items/stacks/medical.dm # code/game/objects/items/stacks/wrap.dm # code/game/objects/items/storage/garment.dm # code/game/objects/items/tools/medical/defib.dm # code/game/objects/items/weaponry.dm # code/game/objects/items/weaponry/melee/misc.dm # code/game/objects/structures/crates_lockers/closets/secure/security.dm # code/game/objects/structures/curtains.dm # code/game/objects/structures/dresser.dm # code/game/objects/structures/girders.dm # code/game/objects/structures/maintenance.dm # code/game/objects/structures/mirror.dm # code/modules/admin/greyscale_modify_menu.dm # code/modules/admin/verbs/light_debug.dm # code/modules/antagonists/ashwalker/ashwalker.dm # code/modules/antagonists/heretic/knowledge/starting_lore.dm # code/modules/antagonists/ninja/ninjaDrainAct.dm # code/modules/art/paintings.dm # code/modules/client/preferences.dm # code/modules/client/verbs/ooc.dm # code/modules/clothing/head/wig.dm # code/modules/events/disease_outbreak.dm # code/modules/holodeck/holo_effect.dm # code/modules/jobs/job_types/head_of_security.dm # code/modules/jobs/job_types/security_officer.dm # code/modules/library/skill_learning/generic_skillchips/point.dm # code/modules/mining/lavaland/ash_flora.dm # code/modules/mining/lavaland/mining_loot/megafauna/ash_drake.dm # code/modules/mob/dead/new_player/new_player.dm # code/modules/mob/living/basic/guardian/guardian.dm # code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm # code/modules/mob/living/carbon/carbon.dm # code/modules/mob/living/carbon/human/human.dm # code/modules/mob/living/carbon/human/human_defines.dm # code/modules/mob/living/carbon/life.dm # code/modules/mob/living/living.dm # code/modules/mob/living/living_defines.dm # code/modules/mob/mob.dm # code/modules/mob_spawn/ghost_roles/mining_roles.dm # code/modules/mod/mod_control.dm # code/modules/mod/modules/modules_general.dm # code/modules/modular_computers/computers/item/computer_ui.dm # code/modules/paperwork/paper.dm # code/modules/paperwork/paperbin.dm # code/modules/power/lighting/light.dm # code/modules/projectiles/guns/energy/kinetic_accelerator.dm # code/modules/projectiles/projectile.dm # code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm # code/modules/reagents/chemistry/reagents/food_reagents.dm # code/modules/reagents/chemistry/reagents/other_reagents.dm # code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm # code/modules/research/xenobiology/crossbreeding/_clothing.dm # code/modules/research/xenobiology/crossbreeding/prismatic.dm # code/modules/surgery/advanced/brainwashing.dm # code/modules/surgery/advanced/lobotomy.dm # code/modules/surgery/amputation.dm # code/modules/surgery/blood_filter.dm # code/modules/surgery/bodyparts/_bodyparts.dm # code/modules/surgery/brain_surgery.dm # code/modules/surgery/cavity_implant.dm # code/modules/surgery/coronary_bypass.dm # code/modules/surgery/gastrectomy.dm # code/modules/surgery/healing.dm # code/modules/surgery/limb_augmentation.dm # code/modules/surgery/organ_manipulation.dm # code/modules/surgery/revival.dm # code/modules/surgery/sleeper_protocol.dm # code/modules/surgery/surgery_helpers.dm # code/modules/surgery/surgery_step.dm # code/modules/unit_tests/_unit_tests.dm # code/modules/unit_tests/designs.dm # code/modules/unit_tests/icon_state_worn.dm # code/modules/unit_tests/screenshots/screenshot_antag_icons_cultist.png # code/modules/unit_tests/screenshots/screenshot_antag_icons_headrevolutionary.png # code/modules/unit_tests/screenshots/screenshot_antag_icons_provocateur.png # code/modules/unit_tests/screenshots/screenshot_husk_body.png # code/modules/unit_tests/screenshots/screenshot_husk_body_missing_limbs.png # icons/map_icons/clothing/head/_head.dmi # icons/map_icons/clothing/shoes.dmi # icons/map_icons/items/_item.dmi # icons/mob/huds/hud.dmi # icons/mob/inhands/64x64_lefthand.dmi # icons/mob/inhands/64x64_righthand.dmi # icons/obj/machines/computer.dmi # tgui/packages/tgui/interfaces/OperatingComputer.jsx # tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/MainPage.tsx # tgui/packages/tgui/interfaces/PreferencesMenu/types.ts # tgui/packages/tgui/interfaces/SurgeryInitiator.tsx # tools/icon_cutter/check.py
663 lines
25 KiB
Plaintext
663 lines
25 KiB
Plaintext
// ********************************************************
|
|
// Here's all the seeds (plants) that can be used in hydro
|
|
// ********************************************************
|
|
|
|
/obj/item/seeds
|
|
icon = 'icons/obj/service/hydroponics/seeds.dmi'
|
|
icon_state = "seed" // Unknown plant seed - these shouldn't exist in-game.
|
|
worn_icon_state = "seed"
|
|
abstract_type = /obj/item/seeds
|
|
w_class = WEIGHT_CLASS_TINY
|
|
resistance_flags = FLAMMABLE
|
|
obj_flags = UNIQUE_RENAME
|
|
/// Name of plant when planted.
|
|
var/plantname = "Plants"
|
|
/// A type path. The thing that is created when the plant is harvested.
|
|
var/obj/item/product
|
|
///Describes the product on the product path.
|
|
var/productdesc
|
|
/// Used to update icons. Should match the name in the sprites unless all icon_* are overridden.
|
|
var/species = ""
|
|
///the file that stores the sprites of the growing plant from this seed.
|
|
var/growing_icon = 'icons/obj/service/hydroponics/growing.dmi'
|
|
/// Used to override grow icon (default is `"[species]-grow"`). You can use one grow icon for multiple closely related plants with it.
|
|
var/icon_grow
|
|
/// Used to override dead icon (default is `"[species]-dead"`). You can use one dead icon for multiple closely related plants with it.
|
|
var/icon_dead
|
|
/// Used to override harvest icon (default is `"[species]-harvest"`). If null, plant will use `[icon_grow][growthstages]`.
|
|
var/icon_harvest
|
|
/// Used to offset the plant sprite so that it appears at proper height in the tray
|
|
var/plant_icon_offset = 8
|
|
/// How long before the plant begins to take damage from age.
|
|
var/lifespan = 25
|
|
/// Amount of health the plant has.
|
|
var/endurance = 15
|
|
/// Used to determine which sprite to switch to when growing.
|
|
var/maturation = 6
|
|
/// Changes the amount of time needed for a plant to become harvestable.
|
|
var/production = 6
|
|
/// Amount of growns created per harvest. If is -1, the plant/shroom/weed is never meant to be harvested.
|
|
var/yield = 3
|
|
/// The 'power' of a plant. Generally effects the amount of reagent in a plant, also used in other ways.
|
|
var/potency = 10
|
|
/// Amount of growth sprites the plant has.
|
|
var/growthstages = 6
|
|
// Chance that a plant will mutate in each stage of its life.
|
|
var/instability = 5
|
|
/// How rare the plant is. Used for giving points to cargo when shipping off to CentCom.
|
|
var/rarity = 0
|
|
/// The type of plants that this plant can mutate into.
|
|
var/list/mutatelist
|
|
/// Starts as a list of paths, is converted to a list of types on init. Plant gene datums are stored here, see plant_genes.dm for more info.
|
|
var/list/genes = list()
|
|
/// A list of reagents to add to product.
|
|
var/list/reagents_add
|
|
// Format: /datum/reagent/type = potency multiplier
|
|
// Stronger reagents must always come first to avoid being displaced by weaker ones.
|
|
// Total amount of any reagent in plant is calculated by formula: max(round(potency * multiplier), 1)
|
|
///If the chance below passes, then this many weeds sprout during growth
|
|
var/weed_rate = 1
|
|
///Percentage chance per tray update to grow weeds
|
|
var/weed_chance = 5
|
|
///How many grafts or cuttings have been taken from this plant.
|
|
var/grafts_taken = 0
|
|
///Type-path of trait to be applied when grafting a plant.
|
|
var/datum/plant_gene/graft_gene = /datum/plant_gene/trait/repeated_harvest
|
|
///Determines if the plant should be allowed to mutate early at 30+ instability.
|
|
var/seed_flags = MUTATE_EARLY
|
|
|
|
/obj/item/seeds/Initialize(mapload, nogenes = FALSE)
|
|
. = ..()
|
|
pixel_x = base_pixel_x + rand(-8, 8)
|
|
pixel_y = base_pixel_y + rand(-8, 8)
|
|
|
|
if(!icon_grow)
|
|
icon_grow = "[species]-grow"
|
|
|
|
if(!icon_dead)
|
|
icon_dead = "[species]-dead"
|
|
|
|
if(!icon_harvest && !get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism) && yield != -1)
|
|
icon_harvest = "[species]-harvest"
|
|
|
|
if(!nogenes)
|
|
// START Bubber edit
|
|
genes += new /datum/plant_gene/core/lifespan(lifespan)
|
|
genes += new /datum/plant_gene/core/endurance(endurance)
|
|
genes += new /datum/plant_gene/core/weed_rate(weed_rate)
|
|
genes += new /datum/plant_gene/core/weed_chance(weed_chance)
|
|
if(yield != -1)
|
|
genes += new /datum/plant_gene/core/yield(yield)
|
|
genes += new /datum/plant_gene/core/production(production)
|
|
if(potency != -1)
|
|
genes += new /datum/plant_gene/core/potency(potency)
|
|
genes += new /datum/plant_gene/core/instability(instability)
|
|
// END Bubber edit
|
|
for(var/plant_gene in genes)
|
|
if(ispath(plant_gene))
|
|
genes -= plant_gene
|
|
genes += new plant_gene
|
|
|
|
// Go through all traits in their genes and call on_new_seed from them.
|
|
for(var/datum/plant_gene/trait/traits in genes)
|
|
traits.on_new_seed(src)
|
|
|
|
for(var/reag_id in reagents_add)
|
|
genes += new /datum/plant_gene/reagent(reag_id, reagents_add[reag_id])
|
|
reagents_from_genes() //quality coding
|
|
|
|
var/static/list/hovering_item_typechecks = list(
|
|
/obj/item/plant_analyzer = list(
|
|
SCREENTIP_CONTEXT_LMB = "Scan seed stats",
|
|
SCREENTIP_CONTEXT_RMB = "Scan seed chemicals"
|
|
),
|
|
)
|
|
|
|
AddElement(/datum/element/contextual_screentip_item_typechecks, hovering_item_typechecks)
|
|
|
|
/obj/item/seeds/Destroy()
|
|
// No AS ANYTHING here, because the list/genes could have typepaths in it.
|
|
for(var/datum/plant_gene/gene in genes)
|
|
gene.on_removed(src)
|
|
qdel(gene)
|
|
|
|
genes.Cut()
|
|
return ..()
|
|
|
|
/obj/item/seeds/examine(mob/user)
|
|
. = ..()
|
|
. += span_notice("Use a pen on it to rename it or change its description.")
|
|
if(reagents_add && user.can_see_reagents())
|
|
. += span_notice("- Plant Reagents -")
|
|
for(var/datum/plant_gene/reagent/reagent_gene in genes)
|
|
. += span_notice("- [reagent_gene.get_name()] -")
|
|
|
|
/// Copy all the variables from one seed to a new instance of the same seed and return it.
|
|
/obj/item/seeds/proc/Copy()
|
|
var/obj/item/seeds/copy_seed = new type(null, TRUE)
|
|
// Copy all the stats
|
|
copy_seed.lifespan = lifespan
|
|
copy_seed.endurance = endurance
|
|
copy_seed.maturation = maturation
|
|
copy_seed.production = production
|
|
copy_seed.yield = yield
|
|
copy_seed.potency = potency
|
|
copy_seed.instability = instability
|
|
copy_seed.weed_rate = weed_rate
|
|
copy_seed.weed_chance = weed_chance
|
|
copy_seed.name = name
|
|
copy_seed.plantname = plantname
|
|
copy_seed.desc = desc
|
|
copy_seed.productdesc = productdesc
|
|
copy_seed.genes = list()
|
|
for(var/datum/plant_gene/gene in genes)
|
|
var/datum/plant_gene/copied_gene = gene.Copy()
|
|
copy_seed.genes += copied_gene
|
|
copied_gene.on_new_seed(copy_seed)
|
|
|
|
copy_seed.reagents_add = reagents_add.Copy() // Faster than grabbing the list from genes.
|
|
return copy_seed
|
|
|
|
/obj/item/seeds/proc/get_gene(typepath)
|
|
return (locate(typepath) in genes)
|
|
|
|
/obj/item/seeds/proc/reagents_from_genes()
|
|
reagents_add = list()
|
|
for(var/datum/plant_gene/reagent/R in genes)
|
|
reagents_add[R.reagent_id] = R.rate
|
|
|
|
/obj/item/seeds/proc/mutate(lifemut = 2, endmut = 5, productmut = 1, yieldmut = 2, potmut = 25, wrmut = 2, wcmut = 5, traitmut = 0, stabmut = 3)
|
|
adjust_lifespan(rand(-lifemut,lifemut))
|
|
adjust_endurance(rand(-endmut,endmut))
|
|
adjust_production(rand(-productmut,productmut))
|
|
adjust_yield(rand(-yieldmut,yieldmut))
|
|
adjust_potency(rand(-potmut,potmut))
|
|
adjust_instability(rand(-stabmut,stabmut))
|
|
adjust_weed_rate(rand(-wrmut, wrmut))
|
|
adjust_weed_chance(rand(-wcmut, wcmut))
|
|
if(prob(traitmut))
|
|
if(prob(50))
|
|
add_random_traits(1, 1)
|
|
else
|
|
add_random_reagents(1, 1)
|
|
|
|
|
|
|
|
/obj/item/seeds/bullet_act(obj/projectile/proj) //Works with the Somatoray to modify plant variables.
|
|
if(!istype(proj, /obj/projectile/energy/flora/yield))
|
|
return ..()
|
|
var/rating = 1
|
|
if(istype(loc, /obj/machinery/hydroponics))
|
|
var/obj/machinery/hydroponics/H = loc
|
|
rating = H.rating
|
|
if(yield == 0)//Oh god don't divide by zero you'll doom us all.
|
|
adjust_yield(1 * rating)
|
|
else if(prob(1/(yield * yield) * 100))//This formula gives you diminishing returns based on yield. 100% with 1 yield, decreasing to 25%, 11%, 6, 4, 2...
|
|
adjust_yield(1 * rating)
|
|
return BULLET_ACT_HIT
|
|
|
|
// Harvest procs
|
|
/obj/item/seeds/proc/getYield()
|
|
var/return_yield = yield
|
|
var/obj/machinery/hydroponics/parent = loc
|
|
// Handle hydroponics malus for soil lovers like rootcrops.
|
|
if(!(parent.tray_flags & SOIL) && get_gene(/datum/plant_gene/trait/soil_lover))
|
|
return_yield *= SOIL_LOVER_HYDRO_YIELD_MALUS
|
|
// Determine if the plant should get a yield bonus from bee pollination.
|
|
for(var/datum/plant_gene/trait/trait in genes)
|
|
if(trait.trait_flags & TRAIT_NO_POLLINATION)
|
|
return return_yield
|
|
|
|
if(istype(loc, /obj/machinery/hydroponics))
|
|
if(parent.yieldmod == 0)
|
|
return_yield = min(return_yield, 1)//1 if above zero, 0 otherwise
|
|
else
|
|
return_yield *= (parent.yieldmod)
|
|
|
|
return round(return_yield)
|
|
|
|
|
|
/obj/item/seeds/proc/harvest(mob/user)
|
|
///Reference to the tray/soil the seeds are planted in.
|
|
var/obj/machinery/hydroponics/parent = loc //for ease of access
|
|
///Count used for creating the correct amount of results to the harvest.
|
|
var/t_amount = 0
|
|
///List of plants all harvested from the same batch.
|
|
var/list/result = list()
|
|
///Tile of the harvester to deposit the growables.
|
|
var/output_loc = parent.Adjacent(user) ? user.drop_location() : parent.drop_location() //needed for TK
|
|
///Name of the grown products.
|
|
var/product_name
|
|
///The Number of products produced by the plant, typically the yield. Modified by certain traits.
|
|
var/product_count = getYield()
|
|
|
|
while(t_amount < product_count)
|
|
var/obj/item/food/grown/t_prod
|
|
if(instability >= 30 && (seed_flags & MUTATE_EARLY) && LAZYLEN(mutatelist) && prob(instability/3))
|
|
var/obj/item/seeds/mutated_seed = pick(mutatelist)
|
|
t_prod = initial(mutated_seed.product)
|
|
if(!t_prod)
|
|
continue
|
|
mutated_seed = new mutated_seed
|
|
for(var/datum/plant_gene/trait/trait in parent.myseed.genes)
|
|
if((trait.mutability_flags & PLANT_GENE_MUTATABLE) && trait.can_add(mutated_seed))
|
|
mutated_seed.genes += trait.Copy()
|
|
t_prod = new t_prod(output_loc, new_seed = mutated_seed)
|
|
t_prod.transform = initial(t_prod.transform)
|
|
t_prod.transform *= TRANSFORM_USING_VARIABLE(t_prod.seed.potency, 100) + 0.5
|
|
ADD_TRAIT(t_prod, TRAIT_PLANT_WILDMUTATE, INNATE_TRAIT)
|
|
t_amount++
|
|
if(t_prod.seed)
|
|
t_prod.seed.set_instability(round(instability * 0.5))
|
|
continue
|
|
else
|
|
// Create a descendent seed so we can modify our offspring before creating a grown from it.
|
|
var/obj/item/seeds/descendent_seed = Copy()
|
|
// Cuck potency if a soil lover such as a root crop is grown in water.
|
|
if(!(parent.tray_flags & SOIL) && get_gene(/datum/plant_gene/trait/soil_lover))
|
|
descendent_seed.set_potency(round(potency * RANDOM_DECIMAL(SOIL_LOVER_HYDRO_POTENCY_MIN, SOIL_LOVER_HYDRO_POTENCY_MAX)))
|
|
|
|
t_prod = new product(output_loc, new_seed = descendent_seed)
|
|
if(parent.myseed.plantname != initial(parent.myseed.plantname))
|
|
t_prod.name = LOWER_TEXT(parent.myseed.plantname)
|
|
if(productdesc)
|
|
t_prod.desc = productdesc
|
|
t_prod.seed.name = parent.myseed.name
|
|
t_prod.seed.desc = parent.myseed.desc
|
|
t_prod.seed.plantname = parent.myseed.plantname
|
|
result.Add(t_prod) // User gets a consumable
|
|
if(!t_prod)
|
|
return
|
|
t_amount++
|
|
product_name = parent.myseed.plantname
|
|
if(product_count >= 1)
|
|
SSblackbox.record_feedback("tally", "food_harvested", product_count, product_name)
|
|
parent.update_tray(user, product_count)
|
|
|
|
return result
|
|
|
|
/**
|
|
* This is where plant chemical products are handled.
|
|
*
|
|
* Individually, the formula for individual amounts of chemicals is Potency * the chemical production %, rounded to the fullest 1.
|
|
* Specific chem handling is also handled here, like bloodtype, food taste within nutriment, and the auto-distilling/autojuicing traits.
|
|
* This is where chemical reactions can occur, and the heating / cooling traits effect the reagent container.
|
|
*/
|
|
/obj/item/seeds/proc/prepare_result(obj/item/T)
|
|
if(!T.reagents)
|
|
CRASH("[T] has no reagents.")
|
|
var/reagent_max = 0
|
|
for(var/rid in reagents_add)
|
|
reagent_max += reagents_add[rid]
|
|
if(IS_EDIBLE(T) || istype(T, /obj/item/grown))
|
|
var/obj/item/food/grown/grown_edible = T
|
|
var/reagent_purity = get_reagent_purity()
|
|
for(var/rid in reagents_add)
|
|
var/reagent_overflow_mod = reagents_add[rid]
|
|
if(reagent_max > 1)
|
|
reagent_overflow_mod = (reagents_add[rid]/ reagent_max)
|
|
var/edible_vol = grown_edible.reagents ? grown_edible.reagents.maximum_volume : 0
|
|
var/amount = max(1, round((edible_vol)*(potency/100) * reagent_overflow_mod, 1)) //the plant will always have at least 1u of each of the reagents in its reagent production traits
|
|
var/list/data
|
|
if(rid == /datum/reagent/blood) // Hack to make blood in plants always O-
|
|
data = list("blood_type" = get_blood_type(BLOOD_TYPE_O_MINUS))
|
|
if(istype(grown_edible) && (rid == /datum/reagent/consumable/nutriment || rid == /datum/reagent/consumable/nutriment/vitamin))
|
|
data = grown_edible.tastes // apple tastes of apple.
|
|
T.reagents.add_reagent(rid, amount, data, added_purity = reagent_purity)
|
|
|
|
//Handles the juicing trait, swaps nutriment and vitamins for that species various juices if they exist. Mutually exclusive with distilling.
|
|
if(get_gene(/datum/plant_gene/trait/juicing) && grown_edible.juice_typepath())
|
|
grown_edible.juice(juicer = FALSE) //we pass FALSE & not null because Byond default args will subtitute it with the default value
|
|
else if(get_gene(/datum/plant_gene/trait/brewing))
|
|
grown_edible.ferment()
|
|
|
|
/// The number of nutriments we have inside of our plant, for use in our heating / cooling genes
|
|
var/num_nutriment = T.reagents.get_reagent_amount(/datum/reagent/consumable/nutriment)
|
|
|
|
// Heats up the plant's contents by 25 kelvin per 1 unit of nutriment. Mutually exclusive with cooling.
|
|
if(get_gene(/datum/plant_gene/trait/chem_heating))
|
|
T.visible_message(span_notice("[T] releases freezing air, consuming its nutriments to heat its contents."))
|
|
T.reagents.remove_reagent(/datum/reagent/consumable/nutriment, num_nutriment)
|
|
T.reagents.chem_temp = min(1000, (T.reagents.chem_temp + num_nutriment * 25))
|
|
T.reagents.handle_reactions()
|
|
playsound(T.loc, 'sound/effects/wounds/sizzle2.ogg', 5)
|
|
// Cools down the plant's contents by 5 kelvin per 1 unit of nutriment. Mutually exclusive with heating.
|
|
else if(get_gene(/datum/plant_gene/trait/chem_cooling))
|
|
T.visible_message(span_notice("[T] releases a blast of hot air, consuming its nutriments to cool its contents."))
|
|
T.reagents.remove_reagent(/datum/reagent/consumable/nutriment, num_nutriment)
|
|
T.reagents.chem_temp = max(3, (T.reagents.chem_temp + num_nutriment * -5))
|
|
T.reagents.handle_reactions()
|
|
playsound(T.loc, 'sound/effects/space_wind.ogg', 50)
|
|
|
|
/// Returns reagent purity based on seed stats
|
|
/obj/item/seeds/proc/get_reagent_purity()
|
|
var/purity_from_lifespan = lifespan / 400 //up to +25% for lifespan
|
|
var/purity_from_endurance = endurance / 400 //up to +25% for endurance
|
|
var/purity_from_instability = rand(-instability, instability) / 400 //up to +-25% at random for instability
|
|
var/result_purity = clamp(0.5 + purity_from_lifespan + purity_from_endurance + purity_from_instability, 0, 1) //50% base + stats
|
|
return result_purity
|
|
|
|
/// Setters procs ///
|
|
|
|
/**
|
|
* Adjusts seed yield up or down according to adjustamt. (Max 10)
|
|
*/
|
|
/obj/item/seeds/proc/adjust_yield(adjustamt)
|
|
if(yield == -1) // Unharvestable shouldn't suddenly turn harvestable
|
|
return
|
|
|
|
var/max_yield = MAX_PLANT_YIELD
|
|
var/min_yield = 0
|
|
for(var/datum/plant_gene/trait/trait in genes)
|
|
if(trait.trait_flags & TRAIT_HALVES_YIELD)
|
|
max_yield = round(max_yield/2)
|
|
break
|
|
if(get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
|
|
min_yield = FUNGAL_METAB_YIELD_MIN
|
|
|
|
yield = clamp(yield + adjustamt, min_yield, max_yield)
|
|
|
|
/**
|
|
* Adjusts seed lifespan up or down according to adjustamt. (Max 100)
|
|
*/
|
|
/obj/item/seeds/proc/adjust_lifespan(adjustamt)
|
|
lifespan = clamp(lifespan + adjustamt, 10, MAX_PLANT_LIFESPAN)
|
|
|
|
/**
|
|
* Adjusts seed endurance up or down according to adjustamt. (Max 100)
|
|
*/
|
|
/obj/item/seeds/proc/adjust_endurance(adjustamt)
|
|
endurance = clamp(endurance + adjustamt, MIN_PLANT_ENDURANCE, MAX_PLANT_ENDURANCE)
|
|
|
|
/**
|
|
* Adjusts seed production seed up or down according to adjustamt. (Max 10)
|
|
*/
|
|
/obj/item/seeds/proc/adjust_production(adjustamt)
|
|
if(yield == -1)
|
|
return
|
|
production = clamp(production + adjustamt, 1, MAX_PLANT_PRODUCTION)
|
|
|
|
/**
|
|
* Adjusts seed potency up or down according to adjustamt. (Max 100)
|
|
*/
|
|
/obj/item/seeds/proc/adjust_potency(adjustamt)
|
|
if(potency == -1)
|
|
return
|
|
potency = clamp(potency + adjustamt, 0, MAX_PLANT_POTENCY)
|
|
|
|
/**
|
|
* Adjusts seed instability up or down according to adjustamt. (Max 100)
|
|
*/
|
|
/obj/item/seeds/proc/adjust_instability(adjustamt)
|
|
if(instability == -1)
|
|
return
|
|
instability = clamp(instability + adjustamt, 0, MAX_PLANT_INSTABILITY)
|
|
|
|
/**
|
|
* Adjusts seed weed grwoth speed up or down according to adjustamt. (Max 10)
|
|
*/
|
|
/obj/item/seeds/proc/adjust_weed_rate(adjustamt)
|
|
weed_rate = clamp(weed_rate + adjustamt, 0, MAX_PLANT_WEEDRATE)
|
|
|
|
/**
|
|
* Adjusts seed weed chance up or down according to adjustamt. (Max 67%)
|
|
*/
|
|
/obj/item/seeds/proc/adjust_weed_chance(adjustamt)
|
|
weed_chance = clamp(weed_chance + adjustamt, 0, MAX_PLANT_WEEDCHANCE)
|
|
|
|
//Directly setting stats
|
|
|
|
/**
|
|
* Sets the plant's yield stat to the value of adjustamt. (Max 10, or 5 with some traits)
|
|
*/
|
|
/obj/item/seeds/proc/set_yield(adjustamt)
|
|
if(yield == -1) // Unharvestable shouldn't suddenly turn harvestable
|
|
return
|
|
|
|
var/max_yield = MAX_PLANT_YIELD
|
|
var/min_yield = 0
|
|
for(var/datum/plant_gene/trait/trait in genes)
|
|
if(trait.trait_flags & TRAIT_HALVES_YIELD)
|
|
max_yield = round(max_yield/2)
|
|
break
|
|
if(get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
|
|
min_yield = FUNGAL_METAB_YIELD_MIN
|
|
|
|
yield = clamp(adjustamt, min_yield, max_yield)
|
|
|
|
/**
|
|
* Sets the plant's lifespan stat to the value of adjustamt. (Max 100)
|
|
*/
|
|
/obj/item/seeds/proc/set_lifespan(adjustamt)
|
|
lifespan = clamp(adjustamt, 10, MAX_PLANT_LIFESPAN)
|
|
|
|
/**
|
|
* Sets the plant's endurance stat to the value of adjustamt. (Max 100)
|
|
*/
|
|
/obj/item/seeds/proc/set_endurance(adjustamt)
|
|
endurance = clamp(adjustamt, MIN_PLANT_ENDURANCE, MAX_PLANT_ENDURANCE)
|
|
|
|
/**
|
|
* Sets the plant's production stat to the value of adjustamt. (Max 10)
|
|
*/
|
|
/obj/item/seeds/proc/set_production(adjustamt)
|
|
if(yield == -1)
|
|
return
|
|
production = clamp(adjustamt, 1, MAX_PLANT_PRODUCTION)
|
|
|
|
/**
|
|
* Sets the plant's potency stat to the value of adjustamt. (Max 100)
|
|
*/
|
|
/obj/item/seeds/proc/set_potency(adjustamt)
|
|
if(potency == -1)
|
|
return
|
|
potency = clamp(adjustamt, 0, MAX_PLANT_POTENCY)
|
|
|
|
/**
|
|
* Sets the plant's instability stat to the value of adjustamt. (Max 100)
|
|
*/
|
|
/obj/item/seeds/proc/set_instability(adjustamt)
|
|
if(instability == -1)
|
|
return
|
|
instability = clamp(adjustamt, 0, MAX_PLANT_INSTABILITY)
|
|
|
|
/**
|
|
* Sets the plant's weed production rate to the value of adjustamt. (Max 10)
|
|
*/
|
|
/obj/item/seeds/proc/set_weed_rate(adjustamt)
|
|
weed_rate = clamp(adjustamt, 0, MAX_PLANT_WEEDRATE)
|
|
|
|
/**
|
|
* Sets the plant's weed growth percentage to the value of adjustamt. (Max 67%)
|
|
*/
|
|
/obj/item/seeds/proc/set_weed_chance(adjustamt)
|
|
weed_chance = clamp(adjustamt, 0, MAX_PLANT_WEEDCHANCE)
|
|
|
|
/**
|
|
* Override for seeds with unique text for their analyzer. (No newlines at the start or end of unique text!)
|
|
* Returns null if no unique data
|
|
* Return an assoc list (label = text) to add a new line to the analyzer
|
|
* Return an assoc list (label = list(text = tooltip, text = tooltip)) to add a new collapsible section to the analyzer
|
|
*/
|
|
/obj/item/seeds/proc/get_unique_analyzer_data()
|
|
return null
|
|
|
|
/**
|
|
* Override for seeds with special chem reactions.
|
|
*/
|
|
/obj/item/seeds/proc/on_chem_reaction(datum/reagents/reagents)
|
|
return
|
|
|
|
/obj/item/seeds/nameformat(input, user)
|
|
plantname = input
|
|
return "[LOWER_TEXT(input)]"
|
|
|
|
/obj/item/seeds/descformat(input, mob/living/user)
|
|
. = input
|
|
if(product && !productdesc)
|
|
productdesc = initial(product.desc)
|
|
var/newproductdesc = tgui_input_text(user, "Write a new product description", "Product Description", productdesc, max_length = MAX_DESC_LEN)
|
|
if(isnull(newproductdesc))
|
|
return
|
|
if(!user.can_perform_action(src))
|
|
return
|
|
productdesc = newproductdesc
|
|
|
|
/obj/item/seeds/rename_reset()
|
|
plantname = initial(plantname)
|
|
productdesc = initial(productdesc)
|
|
|
|
/obj/item/seeds/proc/randomize_stats()
|
|
set_lifespan(rand(25, 60))
|
|
set_endurance(rand(15, 35))
|
|
set_production(rand(2, 10))
|
|
set_yield(rand(1, 10))
|
|
set_potency(rand(10, 35))
|
|
set_weed_rate(rand(1, 10))
|
|
set_weed_chance(rand(5, 100))
|
|
maturation = rand(6, 12)
|
|
|
|
/obj/item/seeds/proc/add_random_reagents(lower = 0, upper = 2)
|
|
var/amount_random_reagents = rand(lower, upper)
|
|
for(var/i in 1 to amount_random_reagents)
|
|
var/random_amount = rand(4, 15) * 0.01 // this must be multiplied by 0.01, otherwise, it will not properly associate
|
|
var/datum/plant_gene/reagent/R = new(get_random_reagent_id(), random_amount)
|
|
if(R.can_add(src))
|
|
if(!R.try_upgrade_gene(src))
|
|
genes += R
|
|
else
|
|
qdel(R)
|
|
reagents_from_genes()
|
|
|
|
/obj/item/seeds/proc/add_random_traits(lower = 0, upper = 2)
|
|
var/amount_random_traits = rand(lower, upper)
|
|
for(var/i in 1 to amount_random_traits)
|
|
var/random_trait = pick(subtypesof(/datum/plant_gene/trait))
|
|
var/datum/plant_gene/trait/picked_random_trait = new random_trait
|
|
if((picked_random_trait.mutability_flags & PLANT_GENE_MUTATABLE) && picked_random_trait.can_add(src))
|
|
genes += picked_random_trait
|
|
else
|
|
qdel(picked_random_trait)
|
|
|
|
/obj/item/seeds/proc/add_random_plant_type(normal_plant_chance = 75)
|
|
if(prob(normal_plant_chance))
|
|
var/random_plant_type = pick(subtypesof(/datum/plant_gene/trait/plant_type))
|
|
var/datum/plant_gene/trait/plant_type/P = new random_plant_type
|
|
if(P.can_add(src))
|
|
genes += P
|
|
else
|
|
qdel(P)
|
|
|
|
/obj/item/seeds/proc/remove_random_reagents(lower = 0, upper = 2)
|
|
var/amount_random_reagents = rand(lower, upper)
|
|
for(var/i in 1 to amount_random_reagents)
|
|
var/datum/reagent/chemical = pick(reagents_add)
|
|
qdel(chemical)
|
|
|
|
/**
|
|
* Creates a graft from this plant.
|
|
*
|
|
* Creates a new graft from this plant.
|
|
* Passes this plant to the new graft so it can make a copy.
|
|
* Returns the created graft.
|
|
*/
|
|
/obj/item/seeds/proc/create_graft()
|
|
var/obj/item/graft/snip = new(loc, src)
|
|
return snip
|
|
|
|
/**
|
|
* Applies a graft to this plant.
|
|
*
|
|
* Adds the graft trait to this plant if possible.
|
|
* Increases plant stats by 2/3 of the grafts stats to a maximum of 100 (10 for yield).
|
|
* Returns TRUE if the graft could apply its trait successfully, FALSE if it fails to apply the trait.
|
|
* NOTE even if the graft fails to apply the trait it still adjusts the plant's stats and reagents.
|
|
*
|
|
* Arguments:
|
|
* - [snip][/obj/item/graft]: The graft being used applied to this plant.
|
|
*/
|
|
/obj/item/seeds/proc/apply_graft(obj/item/graft/snip)
|
|
var/datum/plant_gene/new_trait = snip.plant_dna.graft_gene || /datum/plant_gene/trait/repeated_harvest
|
|
new_trait = new new_trait()
|
|
if(new_trait?.can_add(src))
|
|
genes += new_trait
|
|
else
|
|
new_trait = null
|
|
|
|
// Adjust stats based on graft stats
|
|
set_lifespan(round(max(lifespan, (lifespan + (2/3)*(snip.plant_dna.lifespan - lifespan)))))
|
|
set_endurance(round(max(endurance, (endurance + (2/3)*(snip.plant_dna.endurance - endurance)))))
|
|
set_production(round(max(production, (production + (2/3)*(snip.plant_dna.production - production)))))
|
|
set_weed_rate(round(max(weed_rate, (weed_rate + (2/3)*(snip.plant_dna.weed_rate - weed_rate)))))
|
|
set_weed_chance(round(max(weed_chance, (weed_chance+ (2/3)*(snip.plant_dna.weed_chance - weed_chance)))))
|
|
set_yield(round(max(yield, (yield + (2/3)*(snip.plant_dna.yield - yield)))))
|
|
|
|
// Add in any reagents, too.
|
|
reagents_from_genes()
|
|
// Return the new trait so the tray can know we were successful and display its name.
|
|
return new_trait
|
|
|
|
/*
|
|
* Both `/item/food/grown` and `/item/grown` implement a seed variable which tracks
|
|
* plant statistics, genes, traits, etc. This proc gets the seed for either grown food or
|
|
* grown inedibles and returns it, or returns null if it's not a plant.
|
|
*
|
|
* Returns an `/obj/item/seeds` ref for grown foods or grown inedibles.
|
|
* - returned seed CAN be null in weird cases but in all applications it SHOULD NOT be.
|
|
* Returns null if it is not a plant.
|
|
*/
|
|
/obj/item/proc/get_plant_seed()
|
|
return null
|
|
|
|
/obj/item/food/grown/get_plant_seed()
|
|
return seed
|
|
|
|
/obj/item/grown/get_plant_seed()
|
|
return seed
|
|
|
|
/obj/item/seeds/proc/perform_reagent_pollination(obj/item/seeds/donor)
|
|
var/list/datum/plant_gene/reagent/valid_reagents = list()
|
|
for(var/datum/plant_gene/reagent/donor_reagent in donor.genes)
|
|
var/repeated = FALSE
|
|
for(var/datum/plant_gene/reagent/receptor_reagent in genes)
|
|
if(donor_reagent.reagent_id == receptor_reagent.reagent_id)
|
|
if(receptor_reagent.rate < donor_reagent.rate)
|
|
receptor_reagent.rate = donor_reagent.rate
|
|
// sucessful pollination/upgrade, we stop here.
|
|
reagents_from_genes()
|
|
return
|
|
else
|
|
repeated = TRUE
|
|
break
|
|
|
|
if(!repeated)
|
|
valid_reagents += donor_reagent
|
|
|
|
if(length(valid_reagents))
|
|
// pick a valid reagent that our receptor seed don't have and add the gene to it
|
|
var/datum/plant_gene/reagent/selected_reagent = pick(valid_reagents)
|
|
genes += selected_reagent.Copy()
|
|
reagents_from_genes()
|
|
|
|
/// Returns a mutable appearance to be used as an overlay for the plant in hydro trays.
|
|
/obj/item/seeds/proc/get_tray_overlay(age, status, tray_offset)
|
|
var/mutable_appearance/plant_overlay = mutable_appearance(growing_icon, layer = OBJ_LAYER + 0.01)
|
|
switch(status)
|
|
if(HYDROTRAY_PLANT_DEAD)
|
|
plant_overlay.icon_state = icon_dead
|
|
if(HYDROTRAY_PLANT_HARVESTABLE)
|
|
plant_overlay.icon_state = icon_harvest || "[icon_grow][growthstages]"
|
|
else
|
|
var/t_growthstate = clamp(round((age / maturation) * growthstages), 1, growthstages)
|
|
plant_overlay.icon_state = "[icon_grow][t_growthstate]"
|
|
plant_overlay.pixel_z = plant_icon_offset + tray_offset
|
|
return plant_overlay
|
|
|
|
/// Called when the seed is set in a tray
|
|
/obj/item/seeds/proc/on_planted(obj/machinery/hydroponics/parent)
|
|
return
|
|
|
|
/// Called when the seed is removed from a tray - possibly from being harvested, possibly from being uprooted
|
|
/obj/item/seeds/proc/on_unplanted(obj/machinery/hydroponics/parent)
|
|
return
|