From db9d9fc647668144c980ad9fc2e357178b555354 Mon Sep 17 00:00:00 2001 From: FalseIncarnate Date: Sat, 9 May 2015 06:00:24 -0400 Subject: [PATCH 1/7] Botany / Xenobotany Update Largely a port of https://github.com/Baystation12/Baystation12/pull/8038 (Credit to Zuhayr for his hard work on botany) Breakdown of the port: - Plant traits have been expanded drastically - You want a bio-luminescent tomato that explodes into a cloud of acid when thrown or stepped on? Or maybe a corn vine that entangles people and injects them with mannitol and it's harvests that can be used as a battery? Totally possible. - Adds new random seeds! Replaces the egg-plant seed in the exotic seeds crate from cargo with 2 of these. - Literally random, they have randomly generated stats, chemicals, and traits. Great for researching, and/or wasting cargo's supply points. - Plant analyzers can now print off the last scan they recorded, meaning you can distribute copies of the report to validate your claims of having the dankest weed on station. - Potatoes, carrots, watermelons, soybeans, and pumpkins can all be sliced/diced/carved with ANY sharp object, such as knives, hatchets, glass shards, and e-swords. - This should give the chef a bit more room to make it look like he actually is doing the work by slicing up fries by hand. The processor still also works. - New reagent: Wood Pulp - Currently has no use in recipes, but any plant with this reagent in it can be chopped into planks with a hatchet. Did someone order some Ambrosia Deus planks? - Also, vines with woodpulp are dense. You have been warned. Now onto the stuff I did in addition to the stuff from Bay. - Fixed typos where plasma was mistakenly called "phoron" in the port. (Sorry bay) - Replaced bay's botany mutation chances with our tiered mutation system. - Re-re-added tobacco, space tobacco, tea aspera, tea astra, coffee arabica, and coffee robusta. - Re-enabled the rolling of joints - Made it possible to hand-roll cigarettes from tobacco / space tobacco. (A requested / promised addition) - Just like with joints, it will inherit any chems in the tobacco, has the same reagent capacity as a joint, but looks and smokes like a cig (lasts as long as the cigarettes) with a different name/description to differentiate it from pre-made cigs. - Corn can now be juiced in the grinder, in addition to grinding it. Grinding corn will result in it's contained reagents (like corn starch), while juicing corn will result in corn oil. - Re-added the additional plant analyzer information when scanning trays (displays age, weed level, etc) Also cleaned up the recipes_microwave.dm file, removing the commented out recipes that were distributed to the other machines during the Kitchen Overhaul. Shortens the file a bit and makes it more readable. I probably forgot stuff, so I will add things as I remember them / they get pointed out. --- code/__HELPERS/unsorted.dm | 14 +- code/controllers/master_controller.dm | 2 +- code/datums/recipe.dm | 77 +- code/datums/supplypacks.dm | 4 +- code/defines/obj/weapon.dm | 4 +- code/game/atoms.dm | 4 + .../atmoalter/portable_atmospherics.dm | 8 + code/game/machinery/kitchen/juicer.dm | 37 +- code/game/machinery/kitchen/microwave.dm | 1 + code/game/machinery/kitchen/processor.dm | 14 +- code/game/machinery/seed_extractor.dm | 4 +- .../objects/effects/decals/Cleanable/misc.dm | 10 + code/game/objects/effects/effect_system.dm | 51 +- code/game/objects/items/random_items.dm | 4 +- .../objects/items/weapons/cigs_lighters.dm | 12 +- .../game/objects/items/weapons/hydroponics.dm | 3 +- code/modules/food/candy_maker.dm | 1 + code/modules/food/grill_new.dm | 1 + code/modules/food/oven_new.dm | 1 + code/modules/food/recipes_microwave.dm | 757 +------ code/modules/food/recipes_oven.dm | 102 +- code/modules/hydroponics/_hydro_setup.dm | 58 + code/modules/hydroponics/grown.dm | 394 ++++ code/modules/hydroponics/grown_inedible.dm | 174 +- code/modules/hydroponics/grown_predefined.dm | 40 + code/modules/hydroponics/seed.dm | 743 ++++++ code/modules/hydroponics/seed_controller.dm | 150 ++ code/modules/hydroponics/seed_datums.dm | 1998 +++++++---------- code/modules/hydroponics/seed_machines.dm | 39 +- code/modules/hydroponics/seed_mobs.dm | 32 +- .../hydroponics/{seeds.dm => seed_packets.dm} | 106 +- code/modules/hydroponics/seed_storage.dm | 245 ++ .../hydroponics/spreading/spreading.dm | 262 +++ .../hydroponics/spreading/spreading_growth.dm | 106 + .../spreading/spreading_response.dm | 78 + .../hydroponics/trays/tray.dm} | 720 +++--- code/modules/hydroponics/trays/tray_apiary.dm | 240 ++ .../modules/hydroponics/trays/tray_process.dm | 124 + .../hydroponics/trays/tray_reagents.dm | 126 ++ code/modules/hydroponics/trays/tray_soil.dm | 67 + .../{hydro_tools.dm => trays/tray_tools.dm} | 288 +-- .../hydroponics/trays/tray_update_icons.dm | 84 + code/modules/hydroponics/vines.dm | 386 ---- .../simple_animal/friendly/farm_animals.dm | 30 +- code/modules/reagents/Chemistry-Machinery.dm | 72 +- code/modules/reagents/Chemistry-Reagents.dm | 10 + code/modules/reagents/newchem/toxins.dm | 2 +- code/setup.dm | 2 + code/world.dm | 1 + icons/obj/cigarettes.dmi | Bin 10203 -> 10200 bytes icons/obj/clothing/masks.dmi | Bin 22317 -> 22621 bytes icons/obj/hydroponics_growing.dmi | Bin 0 -> 16762 bytes icons/obj/hydroponics_machines.dmi | Bin 0 -> 14407 bytes icons/obj/hydroponics_products.dmi | Bin 0 -> 8652 bytes icons/obj/hydroponics_vines.dmi | Bin 0 -> 18093 bytes icons/obj/seeds.dmi | Bin 17404 -> 7330 bytes icons/obj/seeds_OLD.dmi | Bin 0 -> 17623 bytes paradise.dme | 26 +- 58 files changed, 4431 insertions(+), 3283 deletions(-) create mode 100644 code/modules/hydroponics/_hydro_setup.dm create mode 100644 code/modules/hydroponics/grown.dm create mode 100644 code/modules/hydroponics/grown_predefined.dm create mode 100644 code/modules/hydroponics/seed.dm create mode 100644 code/modules/hydroponics/seed_controller.dm rename code/modules/hydroponics/{seeds.dm => seed_packets.dm} (65%) create mode 100644 code/modules/hydroponics/seed_storage.dm create mode 100644 code/modules/hydroponics/spreading/spreading.dm create mode 100644 code/modules/hydroponics/spreading/spreading_growth.dm create mode 100644 code/modules/hydroponics/spreading/spreading_response.dm rename code/{game/machinery/hydroponics.dm => modules/hydroponics/trays/tray.dm} (53%) create mode 100644 code/modules/hydroponics/trays/tray_apiary.dm 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} (53%) create mode 100644 code/modules/hydroponics/trays/tray_update_icons.dm delete mode 100644 code/modules/hydroponics/vines.dm create mode 100644 icons/obj/hydroponics_growing.dmi create mode 100644 icons/obj/hydroponics_machines.dmi create mode 100644 icons/obj/hydroponics_products.dmi create mode 100644 icons/obj/hydroponics_vines.dmi create mode 100644 icons/obj/seeds_OLD.dmi diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index c269df248b5..f3e125f31dd 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1670,4 +1670,16 @@ atom/proc/GetTypeInAllContents(typepath) if(prob(chance)) step(AM, pick(alldirs)) chance = max(chance - (initial_chance / steps), 0) - steps-- \ No newline at end of file + steps-- + +/proc/get_random_colour(var/simple, var/lower, var/upper) + var/colour + if(simple) + colour = pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF")) + else + for(var/i=1;i<=3;i++) + var/temp_col = "[num2hex(rand(lower,upper))]" + if(length(temp_col )<2) + temp_col = "0[temp_col]" + colour += temp_col + return colour diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm index c1f46efe5ad..1cf1997259e 100644 --- a/code/controllers/master_controller.dm +++ b/code/controllers/master_controller.dm @@ -120,7 +120,7 @@ datum/controller/game_controller/proc/setup_objects() //Set up roundstart seed list. - populate_seed_list() + //populate_seed_list() world << "\red \b Initializations complete." sleep(-1) diff --git a/code/datums/recipe.dm b/code/datums/recipe.dm index 0f7dcd15b4a..aa21efd793e 100644 --- a/code/datums/recipe.dm +++ b/code/datums/recipe.dm @@ -34,11 +34,12 @@ * */ /datum/recipe - var/list/reagents // example: = list("berryjuice" = 5) // do not list same reagent twice - var/list/items // example: =list(/obj/item/weapon/crowbar, /obj/item/weapon/welder) // place /foo/bar before /foo - var/result //example: = /obj/item/weapon/reagent_containers/food/snacks/donut/normal - var/time = 100 // 1/10 part of second - var/byproduct //example: = /obj/item/weapon/kitchen/mould // byproduct to return, such as a mould or trash + var/list/reagents // example: = list("berryjuice" = 5) // do not list same reagent twice + var/list/items // example: = list(/obj/item/weapon/crowbar, /obj/item/weapon/welder) // place /foo/bar before /foo + var/list/fruit // example: = list("fruit" = 3) + var/result // example: = /obj/item/weapon/reagent_containers/food/snacks/donut/normal + var/time = 100 // 1/10 part of second + var/byproduct // example: = /obj/item/weapon/kitchen/mould // byproduct to return, such as a mould or trash /datum/recipe/proc/check_reagents(var/datum/reagents/avail_reagents) //1=precisely, 0=insufficiently, -1=superfluous @@ -54,25 +55,44 @@ return -1 return . -/datum/recipe/proc/check_items(var/obj/container as obj) //1=precisely, 0=insufficiently, -1=superfluous - if (!items) - if (locate(/obj/) in container) - return -1 - else - return 1 +/datum/recipe/proc/check_fruit(var/obj/container) . = 1 - var/list/checklist = items.Copy() - for (var/obj/O in container) - var/found = 0 - for (var/type in checklist) - if (istype(O,type)) - checklist-=type - found = 1 - break - if (!found) + if(fruit && fruit.len) + var/list/checklist = list() + // You should trust Copy(). + checklist = fruit.Copy() + for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in container) + if(!G.seed || !G.seed.kitchen_tag || isnull(checklist[G.seed.kitchen_tag])) + continue + checklist[G.seed.kitchen_tag]-- + for(var/ktag in checklist) + if(!isnull(checklist[ktag])) + if(checklist[ktag] < 0) + . = 0 + else if(checklist[ktag] > 0) + . = -1 + break + return . + +/datum/recipe/proc/check_items(var/obj/container as obj) + . = 1 + if (items && items.len) + var/list/checklist = list() + checklist = items.Copy() // You should really trust Copy + for(var/obj/O in container) + if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/grown)) + continue // Fruit is handled in check_fruit(). + var/found = 0 + for(var/i = 1; i < checklist.len+1; i++) + var/item_type = checklist[i] + if (istype(O,item_type)) + checklist.Cut(i, i+1) + found = 1 + break + if (!found) + . = 0 + if (checklist.len) . = -1 - if (checklist.len) - return 0 return . //general version @@ -101,22 +121,19 @@ exact = -1 var/list/datum/recipe/possible_recipes = new for (var/datum/recipe/recipe in avaiable_recipes) - if (recipe.check_reagents(obj.reagents)==exact && recipe.check_items(obj)==exact) + if (recipe.check_reagents(obj.reagents)==exact && recipe.check_items(obj)==exact && recipe.check_fruit(obj)==exact) possible_recipes+=recipe if (possible_recipes.len==0) return null else if (possible_recipes.len==1) return possible_recipes[1] else //okay, let's select the most complicated recipe - var/r_count = 0 - var/i_count = 0 + var/highest_count = 0 . = possible_recipes[1] for (var/datum/recipe/recipe in possible_recipes) - var/N_i = (recipe.items)?(recipe.items.len):0 - var/N_r = (recipe.reagents)?(recipe.reagents.len):0 - if (N_i > i_count || (N_i== i_count && N_r > r_count )) - r_count = N_r - i_count = N_i + var/count = ((recipe.items)?(recipe.items.len):0) + ((recipe.reagents)?(recipe.reagents.len):0) + ((recipe.fruit)?(recipe.fruit.len):0) + if (count >= highest_count) + highest_count = count . = recipe return . diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm index 8d0d0b77859..e707d5e9349 100644 --- a/code/datums/supplypacks.dm +++ b/code/datums/supplypacks.dm @@ -910,7 +910,9 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine /obj/item/seeds/amanitamycelium, /obj/item/seeds/reishimycelium, /obj/item/seeds/bananaseed, - /obj/item/seeds/eggyseed) + /obj/item/seeds/random, + /obj/item/seeds/random, + ) cost = 15 containername = "exotic seeds crate" diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm index 2462c13c2a7..d4560ed0a4a 100644 --- a/code/defines/obj/weapon.dm +++ b/code/defines/obj/weapon.dm @@ -583,8 +583,8 @@ /obj/item/weapon/scythe/afterattack(atom/A, mob/user as mob, proximity) if(!proximity) return - if(istype(A, /obj/effect/plantsegment)) - for(var/obj/effect/plantsegment/B in orange(A,1)) + if(istype(A, /obj/effect/plant)) + for(var/obj/effect/plant/B in orange(A,1)) if(prob(80)) qdel(B) qdel(A) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 108c4c8b2f6..20d49ce6c91 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -241,6 +241,10 @@ its easier to just keep the beam vertical. /atom/proc/relaymove() return +/atom/proc/set_dir(new_dir) + . = new_dir != dir + dir = new_dir + /atom/proc/ex_act() return diff --git a/code/game/machinery/atmoalter/portable_atmospherics.dm b/code/game/machinery/atmoalter/portable_atmospherics.dm index ed56300120d..1be7ef4b3c3 100644 --- a/code/game/machinery/atmoalter/portable_atmospherics.dm +++ b/code/game/machinery/atmoalter/portable_atmospherics.dm @@ -67,6 +67,14 @@ return 1 + update_connected_network() + if(!connected_port) + return + + var/datum/pipe_network/network = connected_port.return_network(src) + if (network) + network.update = 1 + disconnect() if(!connected_port) return 0 diff --git a/code/game/machinery/kitchen/juicer.dm b/code/game/machinery/kitchen/juicer.dm index 86d59679f76..bf963ea3c0d 100644 --- a/code/game/machinery/kitchen/juicer.dm +++ b/code/game/machinery/kitchen/juicer.dm @@ -10,17 +10,21 @@ idle_power_usage = 5 active_power_usage = 100 var/obj/item/weapon/reagent_containers/beaker = null - var/global/list/allowed_items = list ( - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato = "tomatojuice", - /obj/item/weapon/reagent_containers/food/snacks/grown/carrot = "carrotjuice", - /obj/item/weapon/reagent_containers/food/snacks/grown/berries = "berryjuice", - /obj/item/weapon/reagent_containers/food/snacks/grown/banana = "banana", - /obj/item/weapon/reagent_containers/food/snacks/grown/potato = "potato", - /obj/item/weapon/reagent_containers/food/snacks/grown/lemon = "lemonjuice", - /obj/item/weapon/reagent_containers/food/snacks/grown/orange = "orangejuice", - /obj/item/weapon/reagent_containers/food/snacks/grown/lime = "limejuice", + var/global/list/allowed_items = list( /obj/item/weapon/reagent_containers/food/snacks/watermelonslice = "watermelonjuice", - /obj/item/weapon/reagent_containers/food/snacks/grown/poisonberries = "poisonberryjuice", + /obj/item/weapon/reagent_containers/food/snacks/grown = "water", + ) + + var/global/list/allowed_tags = list ( + "tomato" = "tomatojuice", + "carrot" = "carrotjuice", + "berries" = "berryjuice", + "banana" = "banana", + "potato" = "potato", + "lemon" = "lemonjuice", + "orange" = "orangejuice", + "lime" = "limejuice", + "poisonberries" = "poisonberryjuice", ) /obj/machinery/juicer/New() @@ -132,10 +136,15 @@ beaker = null update_icon() -/obj/machinery/juicer/proc/get_juice_id(var/obj/item/weapon/reagent_containers/food/snacks/grown/O) - for (var/i in allowed_items) - if (istype(O, i)) - return allowed_items[i] +/obj/machinery/juicer/proc/get_juice_id(var/obj/item/weapon/reagent_containers/food/snacks/O) + if (istype(O, /obj/item/weapon/reagent_containers/food/snacks/watermelonslice)) + return "watermelonjuice" + else if(istype(O, /obj.item/weapon/reagent_containers/food/snacks/grown)) + var/obj/item/weapon/reagent_containers/food/snacks/grown/G = O + for(var/i in allowed_tags) + if(G.seed.kitchen_tag == allowed_tags[i]) + return allowed_tags[i] + return "water" /obj/machinery/juicer/proc/get_juice_amount(var/obj/item/weapon/reagent_containers/food/snacks/grown/O) if (!istype(O)) diff --git a/code/game/machinery/kitchen/microwave.dm b/code/game/machinery/kitchen/microwave.dm index aaeef39d8d6..17b260747dd 100644 --- a/code/game/machinery/kitchen/microwave.dm +++ b/code/game/machinery/kitchen/microwave.dm @@ -43,6 +43,7 @@ acceptable_reagents |= reagent if (recipe.items) max_n_of_items = max(max_n_of_items,recipe.items.len) + acceptable_items |= /obj/item/weapon/reagent_containers/food/snacks/grown component_parts = list() component_parts += new /obj/item/weapon/circuitboard/microwave(null) diff --git a/code/game/machinery/kitchen/processor.dm b/code/game/machinery/kitchen/processor.dm index 0fe8596d380..9cc323b8b25 100644 --- a/code/game/machinery/kitchen/processor.dm +++ b/code/game/machinery/kitchen/processor.dm @@ -34,19 +34,19 @@ output = /obj/item/weapon/reagent_containers/food/snacks/meatball /datum/food_processor_process/potato - input = /obj/item/weapon/reagent_containers/food/snacks/grown/potato + input = "potato" output = /obj/item/weapon/reagent_containers/food/snacks/fries /datum/food_processor_process/carrot - input = /obj/item/weapon/reagent_containers/food/snacks/grown/carrot + input = "carrot" output = /obj/item/weapon/reagent_containers/food/snacks/carrotfries /datum/food_processor_process/soybeans - input = /obj/item/weapon/reagent_containers/food/snacks/grown/soybeans + input = "soybeans" output = /obj/item/weapon/reagent_containers/food/snacks/soydope /datum/food_processor_process/wheat - input = /obj/item/weapon/reagent_containers/food/snacks/grown/wheat + input = "wheat" output = /obj/item/weapon/reagent_containers/food/snacks/flour /datum/food_processor_process/spaghetti @@ -111,7 +111,11 @@ /obj/machinery/processor/proc/select_recipe(var/X) for (var/Type in typesof(/datum/food_processor_process) - /datum/food_processor_process - /datum/food_processor_process/mob) var/datum/food_processor_process/P = new Type() - if (!istype(X, P.input)) + if(istype(X, /obj/item/weapon/reagent_containers/food/snacks/grown)) + var/obj/item/weapon/reagent_containers/food/snacks/grown/G = X + if(G.seed.kitchen_tag != P.input) + continue + else if (!istype(X, P.input)) continue return P return 0 diff --git a/code/game/machinery/seed_extractor.dm b/code/game/machinery/seed_extractor.dm index f2e45ccdc41..6934ee0ac6c 100644 --- a/code/game/machinery/seed_extractor.dm +++ b/code/game/machinery/seed_extractor.dm @@ -16,10 +16,10 @@ obj/machinery/seed_extractor/attackby(var/obj/item/O as obj, var/mob/user as mob var/datum/seed/new_seed_type if(istype(O, /obj/item/weapon/grown)) var/obj/item/weapon/grown/F = O - new_seed_type = seed_types[F.plantname] + new_seed_type = plant_controller.seeds[F.plantname] else var/obj/item/weapon/reagent_containers/food/snacks/grown/F = O - new_seed_type = seed_types[F.plantname] + new_seed_type = plant_controller.seeds[F.plantname] if(new_seed_type) user << "You extract some seeds from [O]." diff --git a/code/game/objects/effects/decals/Cleanable/misc.dm b/code/game/objects/effects/decals/Cleanable/misc.dm index bc73b6689b4..5e70291404b 100644 --- a/code/game/objects/effects/decals/Cleanable/misc.dm +++ b/code/game/objects/effects/decals/Cleanable/misc.dm @@ -171,6 +171,16 @@ icon = 'icons/effects/tomatodecal.dmi' random_icon_states = list("smashed_pie") +/obj/effect/decal/cleanable/fruit_smudge + name = "smudge" + desc = "Some kind of fruit smear." + density = 0 + anchored = 1 + layer = 2 + icon = 'icons/effects/blood.dmi' + icon_state = "mfloor1" + random_icon_states = list("mfloor1", "mfloor2", "mfloor3", "mfloor4", "mfloor5", "mfloor6", "mfloor7") + /obj/effect/decal/cleanable/fungus name = "space fungus" desc = "A fungal growth. Looks pretty nasty." diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index d5d3555e12d..93e017d4ef4 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -423,6 +423,28 @@ steam.start() -- spawns the effect return +// Spores +/datum/effect/effect/system/chem_smoke_spread/spores + var/datum/seed/seed + +/datum/effect/effect/system/chem_smoke_spread/spores/New(seed_name) + if(seed_name && plant_controller) + seed = plant_controller.seeds[seed_name] + if(!seed) + del(src) + ..() + + + +/datum/effect/effect/system/chem_smoke_spread/New() + ..() + chemholder = new/obj() + var/datum/reagents/R = new/datum/reagents(500) + chemholder.reagents = R + R.my_atom = chemholder + + + /datum/effect/effect/system/chem_smoke_spread var/total_smoke = 0 // To stop it being spammed and lagging! var/direction @@ -460,16 +482,20 @@ steam.start() -- spawns the effect var/where = "[A.name] | [location.x], [location.y]" var/whereLink = "[where]" - if(carry.my_atom.fingerprintslast) - var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast) - var/more = "" - if(M) - more = "(?)" - msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", 0, 1) - log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].") + if(carry && carry.my_atom) + if(carry.my_atom.fingerprintslast) + var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast) + var/more = "" + if(M) + more = "(?)" + msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", 0, 1) + log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].") + else + msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink]). No associated key.", 0, 1) + log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.") else - msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink]). No associated key.", 0, 1) - log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.") + msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink]). No associated key. CODERS: carry.my_atom may be null.", 0, 1) + log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key. CODERS: carry.my_atom may be null.") start(effect_range = 2) var/i = 0 @@ -482,6 +508,13 @@ steam.start() -- spawns the effect var/mob/living/carbon/C = A if(!(C.wear_mask && (C.internals != null || C.wear_mask.flags & BLOCK_GAS_SMOKE_EFFECT))) chemholder.reagents.copy_to(C, chemholder.reagents.total_volume) + if(istype(A, /obj/machinery/portable_atmospherics/hydroponics)) + var/obj/machinery/portable_atmospherics/hydroponics/tray = A + chemholder.reagents.copy_to(tray, chemholder.reagents.total_volume) + if(istype(A, /obj/effect/plant)) + var/obj/effect/plant/plant = A + if(chemholder.reagents.has_reagent("atrazine")) + plant.die_off() qdel(smokeholder) for(i=0, i 20) diff --git a/code/game/objects/items/random_items.dm b/code/game/objects/items/random_items.dm index 0bbd8ba35aa..e19a9af8cff 100644 --- a/code/game/objects/items/random_items.dm +++ b/code/game/objects/items/random_items.dm @@ -198,7 +198,7 @@ B.desc = "Looks like the label fell off." // B.identify_probability = 0 - +/* /obj/structure/closet/crate/bin/flowers name = "flower barrel" desc = "A bin full of fresh flowers for the bereaved." @@ -211,7 +211,6 @@ AM.pixel_x = rand(-10,10) AM.pixel_y = rand(-5,5) - /obj/structure/closet/crate/bin/plants name = "plant barrel" desc = "Caution: Contents may contain vitamins and minerals. It is recommended that you deep fry them before eating." @@ -234,6 +233,7 @@ var/obj/O = new ptype(src) O.pixel_x = rand(-10,10) O.pixel_y = rand(-5,5) +*/ /obj/structure/closet/secure_closet/random_drinks name = "Unlabelled Booze" diff --git a/code/game/objects/items/weapons/cigs_lighters.dm b/code/game/objects/items/weapons/cigs_lighters.dm index aacdc9c6e37..9ec5123a7b8 100644 --- a/code/game/objects/items/weapons/cigs_lighters.dm +++ b/code/game/objects/items/weapons/cigs_lighters.dm @@ -245,6 +245,16 @@ CIGARETTE PACKETS ARE IN FANCY.DM src.pixel_x = rand(-5.0, 5) src.pixel_y = rand(-5.0, 5) +/obj/item/clothing/mask/cigarette/handroll + name = "hand-rolled cigarette" + desc = "A roll of tobacco and nicotine, freshly rolled by hand." + icon_state = "hr_cigoff" + item_state = "hr_cigoff" + icon_on = "hr_cigon" //Note - these are in masks.dmi not in cigarette.dmi + icon_off = "hr_cigoff" + type_butt = /obj/item/weapon/cigbutt + chem_volume = 50 + //////////// // CIGARS // //////////// @@ -498,7 +508,7 @@ obj/item/weapon/rollingpaper name = "rolling paper" desc = "A thin piece of paper used to make fine smokeables." icon = 'icons/obj/cigarettes.dmi' - icon_state = "cig paper" + icon_state = "cig_paper" w_class = 1 diff --git a/code/game/objects/items/weapons/hydroponics.dm b/code/game/objects/items/weapons/hydroponics.dm index a32f7d6d152..9b34938d480 100644 --- a/code/game/objects/items/weapons/hydroponics.dm +++ b/code/game/objects/items/weapons/hydroponics.dm @@ -146,7 +146,7 @@ if(!user.gloves) user << "\red The [name] burns your bare hand!" user.adjustFireLoss(rand(1,5)) - +/* /* * Nettle */ @@ -237,3 +237,4 @@ new /obj/item/clothing/mask/cigarette/pipe/cobpipe (user.loc) del(src) return +*/ \ No newline at end of file diff --git a/code/modules/food/candy_maker.dm b/code/modules/food/candy_maker.dm index cfe59a95209..269c2fcc33b 100644 --- a/code/modules/food/candy_maker.dm +++ b/code/modules/food/candy_maker.dm @@ -43,6 +43,7 @@ acceptable_reagents |= reagent if (recipe.items) max_n_of_items = max(max_n_of_items,recipe.items.len) + acceptable_items |= /obj/item/weapon/reagent_containers/food/snacks/grown component_parts = list() component_parts += new /obj/item/weapon/circuitboard/candy_maker(null) diff --git a/code/modules/food/grill_new.dm b/code/modules/food/grill_new.dm index 757b5a4ca58..6fcd5e3a31a 100644 --- a/code/modules/food/grill_new.dm +++ b/code/modules/food/grill_new.dm @@ -44,6 +44,7 @@ acceptable_reagents |= reagent if (recipe.items) max_n_of_items = max(max_n_of_items,recipe.items.len) + acceptable_items |= /obj/item/weapon/reagent_containers/food/snacks/grown component_parts = list() component_parts += new /obj/item/weapon/circuitboard/grill(null) diff --git a/code/modules/food/oven_new.dm b/code/modules/food/oven_new.dm index 4fe0f79b396..1b0c3559cf0 100644 --- a/code/modules/food/oven_new.dm +++ b/code/modules/food/oven_new.dm @@ -44,6 +44,7 @@ acceptable_reagents |= reagent if (recipe.items) max_n_of_items = max(max_n_of_items,recipe.items.len) + acceptable_items |= /obj/item/weapon/reagent_containers/food/snacks/grown component_parts = list() component_parts += new /obj/item/weapon/circuitboard/oven(null) diff --git a/code/modules/food/recipes_microwave.dm b/code/modules/food/recipes_microwave.dm index 71c04ed3851..27c47f30fde 100644 --- a/code/modules/food/recipes_microwave.dm +++ b/code/modules/food/recipes_microwave.dm @@ -2,37 +2,6 @@ // see code/datums/recipe.dm - -/* -/datum/recipe/microwave/telebacon - items = list( - /obj/item/weapon/reagent_containers/food/snacks/meat, - /obj/item/device/assembly/signaler - ) - result = /obj/item/weapon/reagent_containers/food/snacks/telebacon - - -/datum/recipe/microwave/syntitelebacon - items = list( - /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, - /obj/item/device/assembly/signaler - ) - result = /obj/item/weapon/reagent_containers/food/snacks/telebacon - -/datum/recipe/microwave/bun - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough - ) - result = /obj/item/weapon/reagent_containers/food/snacks/bun - -/datum/recipe/microwave/friedegg - reagents = list("sodiumchloride" = 1, "blackpepper" = 1) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/egg - ) - result = /obj/item/weapon/reagent_containers/food/snacks/friedegg -*/ - /datum/recipe/microwave/boiledegg reagents = list("water" = 5) items = list( @@ -41,24 +10,13 @@ result = /obj/item/weapon/reagent_containers/food/snacks/boiledegg /datum/recipe/microwave/dionaroast + fruit = list("apple" = 1) reagents = list("facid" = 5) //It dissolves the carapace. Still poisonous, though. items = list( /obj/item/weapon/holder/diona, - /obj/item/weapon/reagent_containers/food/snacks/grown/apple ) result = /obj/item/weapon/reagent_containers/food/snacks/dionaroast - -/* -/datum/recipe/microwave/bananaphone - reagents = list("psilocybin" = 5) //Trippin' balls, man. - items = list( - /obj/item/weapon/reagent_containers/food/snacks/grown/banana, - /obj/item/device/radio - ) - result = /obj/item/weapon/reagent_containers/food/snacks/bananaphone -*/ - /datum/recipe/microwave/jellydonut reagents = list("berryjuice" = 5, "sugar" = 5) items = list( @@ -203,16 +161,6 @@ ) result = /obj/item/weapon/reagent_containers/food/snacks/hotdog -/* -/datum/recipe/microwave/waffles - reagents = list("sugar" = 10) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough - ) - result = /obj/item/weapon/reagent_containers/food/snacks/waffles -*/ - /datum/recipe/microwave/donkpocket items = list( /obj/item/weapon/reagent_containers/food/snacks/dough, @@ -226,91 +174,20 @@ ) result = /obj/item/weapon/reagent_containers/food/snacks/warmdonkpocket - -/* -/datum/recipe/microwave/meatbread - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/meat, - /obj/item/weapon/reagent_containers/food/snacks/meat, - /obj/item/weapon/reagent_containers/food/snacks/meat, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/meatbread - -/datum/recipe/microwave/syntibread - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, - /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, - /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/meatbread - -/datum/recipe/microwave/xenomeatbread - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/xenomeat, - /obj/item/weapon/reagent_containers/food/snacks/xenomeat, - /obj/item/weapon/reagent_containers/food/snacks/xenomeat, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/xenomeatbread - -/datum/recipe/microwave/bananabread - reagents = list("milk" = 5, "sugar" = 15) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/grown/banana, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/bananabread - -/datum/recipe/microwave/omelette - items = list( - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/omelette - -/datum/recipe/microwave/muffin - reagents = list("milk" = 5, "sugar" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/muffin -*/ - /datum/recipe/microwave/eggplantparm + fruit = list("eggplant" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/grown/eggplant ) result = /obj/item/weapon/reagent_containers/food/snacks/eggplantparm /datum/recipe/microwave/soylenviridians + fruit = list("soybeans" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/flour, /obj/item/weapon/reagent_containers/food/snacks/flour, /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/grown/soybeans ) result = /obj/item/weapon/reagent_containers/food/snacks/soylenviridians @@ -324,91 +201,6 @@ ) result = /obj/item/weapon/reagent_containers/food/snacks/soylentgreen -/* -/datum/recipe/microwave/carrotcake - reagents = list("milk" = 5, "sugar" = 15) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/grown/carrot, - /obj/item/weapon/reagent_containers/food/snacks/grown/carrot, - /obj/item/weapon/reagent_containers/food/snacks/grown/carrot, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/carrotcake - -/datum/recipe/microwave/cheesecake - reagents = list("milk" = 5, "sugar" = 15) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesecake - -/datum/recipe/microwave/plaincake - reagents = list("milk" = 5, "sugar" = 15) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/plaincake - -/datum/recipe/microwave/meatpie - items = list( - /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/meat, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/meatpie - -/datum/recipe/microwave/tofupie - items = list( - /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/tofu, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/tofupie - -/datum/recipe/microwave/xemeatpie - items = list( - /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/xenomeat, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/xemeatpie - -/datum/recipe/microwave/pie - reagents = list("sugar" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/grown/banana, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/pie - -/datum/recipe/microwave/cherrypie - reagents = list("sugar" = 10) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/grown/cherries, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/cherrypie - -/datum/recipe/microwave/berryclafoutis - items = list( - /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/grown/berries, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/berryclafoutis - -/datum/recipe/microwave/wingfangchu - reagents = list("soysauce" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/xenomeat, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/wingfangchu -*/ - /datum/recipe/microwave/chaosdonut reagents = list("frostoil" = 5, "capsaicin" = 5, "sugar" = 5) items = list( @@ -416,61 +208,6 @@ ) result = /obj/item/weapon/reagent_containers/food/snacks/donut/chaos -/* -/datum/recipe/microwave/human/kabob - items = list( - /obj/item/stack/rods, - /obj/item/weapon/reagent_containers/food/snacks/meat/human, - /obj/item/weapon/reagent_containers/food/snacks/meat/human, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/human/kabob - -/datum/recipe/microwave/monkeykabob - items = list( - /obj/item/stack/rods, - /obj/item/weapon/reagent_containers/food/snacks/meat/monkey, - /obj/item/weapon/reagent_containers/food/snacks/meat/monkey, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/monkeykabob - -/datum/recipe/microwave/syntikabob - items = list( - /obj/item/stack/rods, - /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, - /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/monkeykabob - -/datum/recipe/microwave/tofukabob - items = list( - /obj/item/stack/rods, - /obj/item/weapon/reagent_containers/food/snacks/tofu, - /obj/item/weapon/reagent_containers/food/snacks/tofu, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/tofukabob - -/datum/recipe/microwave/tofubread - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/tofu, - /obj/item/weapon/reagent_containers/food/snacks/tofu, - /obj/item/weapon/reagent_containers/food/snacks/tofu, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/tofubread - -/datum/recipe/microwave/loadedbakedpotato - items = list( - /obj/item/weapon/reagent_containers/food/snacks/grown/potato, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/loadedbakedpotato -*/ - /datum/recipe/microwave/cheesyfries items = list( /obj/item/weapon/reagent_containers/food/snacks/fries, @@ -479,138 +216,25 @@ result = /obj/item/weapon/reagent_containers/food/snacks/cheesyfries /datum/recipe/microwave/cubancarp + fruit = list("chili" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/grown/chili, /obj/item/weapon/reagent_containers/food/snacks/carpmeat, ) result = /obj/item/weapon/reagent_containers/food/snacks/cubancarp /datum/recipe/microwave/popcorn - items = list( - /obj/item/weapon/reagent_containers/food/snacks/grown/corn - ) + fruit = list("corn" = 1) result = /obj/item/weapon/reagent_containers/food/snacks/popcorn -/* -/datum/recipe/microwave/cookie - reagents = list("milk" = 5, "sugar" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/chocolatebar, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/cookie - -/datum/recipe/microwave/fortunecookie - reagents = list("sugar" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/doughslice, - /obj/item/weapon/paper, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/fortunecookie - make_food(var/obj/container as obj) - var/obj/item/weapon/paper/paper = locate() in container - paper.loc = null //prevent deletion - var/obj/item/weapon/reagent_containers/food/snacks/fortunecookie/being_cooked = ..(container) - paper.loc = being_cooked - being_cooked.trash = paper //so the paper is left behind as trash without special-snowflake(TM Nodrak) code ~carn - return being_cooked - check_items(var/obj/container as obj) - . = ..() - if (.) - var/obj/item/weapon/paper/paper = locate() in container - if (!paper.info) - return 0 - return . - -/datum/recipe/microwave/meatsteak - reagents = list("sodiumchloride" = 1, "blackpepper" = 1) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/meat - ) - result = /obj/item/weapon/reagent_containers/food/snacks/meatsteak - -/datum/recipe/microwave/syntisteak - reagents = list("sodiumchloride" = 1, "blackpepper" = 1) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh - ) - result = /obj/item/weapon/reagent_containers/food/snacks/meatsteak - -/datum/recipe/microwave/pizzamargherita - items = list( - /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/margherita - -/datum/recipe/microwave/meatpizza - items = list( - /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/meat, - /obj/item/weapon/reagent_containers/food/snacks/meat, - /obj/item/weapon/reagent_containers/food/snacks/meat, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatpizza - -/datum/recipe/microwave/syntipizza - items = list( - /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, - /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, - /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatpizza - -/datum/recipe/microwave/mushroompizza - items = list( - /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/mushroompizza - -/datum/recipe/microwave/vegetablepizza - items = list( - /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/grown/eggplant, - /obj/item/weapon/reagent_containers/food/snacks/grown/carrot, - /obj/item/weapon/reagent_containers/food/snacks/grown/corn, - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/vegetablepizza -*/ - /datum/recipe/microwave/spacylibertyduff reagents = list("water" = 5, "vodka" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/libertycap, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/libertycap, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/libertycap, - ) + fruit = list("libertycap" = 3) result = /obj/item/weapon/reagent_containers/food/snacks/spacylibertyduff /datum/recipe/microwave/amanitajelly reagents = list("water" = 5, "vodka" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/amanita, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/amanita, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/amanita, - ) + fruit = list("amanita" = 3) result = /obj/item/weapon/reagent_containers/food/snacks/amanitajelly make_food(var/obj/container as obj) var/obj/item/weapon/reagent_containers/food/snacks/amanitajelly/being_cooked = ..(container) @@ -619,28 +243,21 @@ /datum/recipe/microwave/meatballsoup reagents = list("water" = 10) + fruit = list("potato" = 1, "carrot" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/meatball , - /obj/item/weapon/reagent_containers/food/snacks/grown/carrot, - /obj/item/weapon/reagent_containers/food/snacks/grown/potato, ) result = /obj/item/weapon/reagent_containers/food/snacks/meatballsoup /datum/recipe/microwave/vegetablesoup reagents = list("water" = 10) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/grown/carrot, - /obj/item/weapon/reagent_containers/food/snacks/grown/corn, - /obj/item/weapon/reagent_containers/food/snacks/grown/eggplant, - /obj/item/weapon/reagent_containers/food/snacks/grown/potato, - ) + fruit = list("carrot" = 1, "corn" = 1, "eggplant" = 1, "potato" = 1) result = /obj/item/weapon/reagent_containers/food/snacks/vegetablesoup /datum/recipe/microwave/nettlesoup reagents = list("water" = 10) + fruit = list("nettle" = 1, "potato" = 1) items = list( - /obj/item/weapon/grown/nettle, - /obj/item/weapon/reagent_containers/food/snacks/grown/potato, /obj/item/weapon/reagent_containers/food/snacks/egg, ) result = /obj/item/weapon/reagent_containers/food/snacks/nettlesoup @@ -650,37 +267,19 @@ result= /obj/item/weapon/reagent_containers/food/snacks/wishsoup /datum/recipe/microwave/hotchili + fruit = list("chili" = 1, "tomato" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/meat, - /obj/item/weapon/reagent_containers/food/snacks/grown/chili, - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, ) result = /obj/item/weapon/reagent_containers/food/snacks/hotchili /datum/recipe/microwave/coldchili + fruit = list("icechili" = 1, "tomato" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/meat, - /obj/item/weapon/reagent_containers/food/snacks/grown/icepepper, - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, ) result = /obj/item/weapon/reagent_containers/food/snacks/coldchili -/* -/datum/recipe/microwave/amanita_pie - items = list( - /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/amanita, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/amanita_pie - -/datum/recipe/microwave/plump_pie - items = list( - /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/plumphelmet, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/plump_pie -*/ - /datum/recipe/microwave/spellburger items = list( /obj/item/weapon/reagent_containers/food/snacks/monkeyburger, @@ -706,45 +305,21 @@ result = /obj/item/weapon/reagent_containers/food/snacks/bigbiteburger /datum/recipe/microwave/enchiladas + fruit = list("chili" = 2, "corn" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/cutlet, - /obj/item/weapon/reagent_containers/food/snacks/grown/chili, - /obj/item/weapon/reagent_containers/food/snacks/grown/chili, - /obj/item/weapon/reagent_containers/food/snacks/grown/corn, ) result = /obj/item/weapon/reagent_containers/food/snacks/enchiladas -/* -/datum/recipe/microwave/creamcheesebread - items = list( - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/creamcheesebread -*/ - /datum/recipe/microwave/monkeysdelight reagents = list("sodiumchloride" = 1, "blackpepper" = 1) + fruit = list("banana" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/flour, /obj/item/weapon/reagent_containers/food/snacks/monkeycube, - /obj/item/weapon/reagent_containers/food/snacks/grown/banana, ) result = /obj/item/weapon/reagent_containers/food/snacks/monkeysdelight -/* -/datum/recipe/microwave/baguette - reagents = list("sodiumchloride" = 1, "blackpepper" = 1) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/baguette -*/ - /datum/recipe/microwave/fishandchips items = list( /obj/item/weapon/reagent_containers/food/snacks/fries, @@ -752,25 +327,6 @@ ) result = /obj/item/weapon/reagent_containers/food/snacks/fishandchips -/* -/datum/recipe/microwave/birthdaycake - reagents = list("milk" = 5, "sugar" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/clothing/head/cakehat - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/birthdaycake - -/datum/recipe/microwave/bread - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/egg - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/bread -*/ - /datum/recipe/microwave/sandwich items = list( /obj/item/weapon/reagent_containers/food/snacks/meatsteak, @@ -784,45 +340,17 @@ items = list( /obj/item/weapon/reagent_containers/food/snacks/sandwich ) - result = /obj/item/weapon/reagent_containers/food/snacks/toastedsandwich - -/* -/datum/recipe/microwave/grilledcheese - items = list( - /obj/item/weapon/reagent_containers/food/snacks/breadslice, - /obj/item/weapon/reagent_containers/food/snacks/breadslice, - /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/grilledcheese -*/ /datum/recipe/microwave/tomatosoup reagents = list("water" = 10) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, - ) + fruit = list("tomato" = 2) result = /obj/item/weapon/reagent_containers/food/snacks/tomatosoup -/* -/datum/recipe/microwave/rofflewaffles - reagents = list("psilocybin" = 5, "sugar" = 10) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/rofflewaffles -*/ - /datum/recipe/microwave/stew reagents = list("water" = 10) + fruit = list("tomato" = 1, "potato" = 1, "carrot" = 1, "eggplant" = 1, "mushroom" = 1) items = list( - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, /obj/item/weapon/reagent_containers/food/snacks/meat, - /obj/item/weapon/reagent_containers/food/snacks/grown/potato, - /obj/item/weapon/reagent_containers/food/snacks/grown/carrot, - /obj/item/weapon/reagent_containers/food/snacks/grown/eggplant, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom, ) result = /obj/item/weapon/reagent_containers/food/snacks/stew @@ -851,20 +379,13 @@ result = /obj/item/weapon/reagent_containers/food/snacks/milosoup /datum/recipe/microwave/stewedsoymeat + fruit = list("carrot" = 1, "tomato" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/soydope, /obj/item/weapon/reagent_containers/food/snacks/soydope, - /obj/item/weapon/reagent_containers/food/snacks/grown/carrot, - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, ) result = /obj/item/weapon/reagent_containers/food/snacks/stewedsoymeat -/*/datum/recipe/microwave/spagetti We have the processor now - items = list( - /obj/item/weapon/reagent_containers/food/snacks/doughslice - ) - result= /obj/item/weapon/reagent_containers/food/snacks/spagetti*/ - /datum/recipe/microwave/boiledspagetti reagents = list("water" = 5) items = list( @@ -882,10 +403,9 @@ /datum/recipe/microwave/pastatomato reagents = list("water" = 5) + fruit = list("tomato" = 2) items = list( /obj/item/weapon/reagent_containers/food/snacks/spagetti, - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, ) result = /obj/item/weapon/reagent_containers/food/snacks/pastatomato @@ -918,11 +438,11 @@ /datum/recipe/microwave/superbiteburger reagents = list("sodiumchloride" = 5, "blackpepper" = 5) + fruit = list("tomato" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/bigbiteburger, /obj/item/weapon/reagent_containers/food/snacks/dough, /obj/item/weapon/reagent_containers/food/snacks/meat, - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, /obj/item/weapon/reagent_containers/food/snacks/boiledegg, ) @@ -930,31 +450,9 @@ /datum/recipe/microwave/candiedapple reagents = list("water" = 5, "sugar" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/grown/apple - ) + fruit = list("apple" = 1) result = /obj/item/weapon/reagent_containers/food/snacks/candiedapple -/* -/datum/recipe/microwave/applepie - items = list( - /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/grown/apple, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/applepie - -/datum/recipe/microwave/applecake - reagents = list("milk" = 5, "sugar" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/grown/apple, - /obj/item/weapon/reagent_containers/food/snacks/grown/apple, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/applecake -*/ - /datum/recipe/microwave/slimeburger reagents = list("slimejelly" = 5) items = list( @@ -993,70 +491,9 @@ ) result = /obj/item/weapon/reagent_containers/food/snacks/jellysandwich/cherry -/* -/datum/recipe/microwave/orangecake - reagents = list("milk" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/grown/orange, - /obj/item/weapon/reagent_containers/food/snacks/grown/orange, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/orangecake - -/datum/recipe/microwave/limecake - reagents = list("milk" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/grown/lime, - /obj/item/weapon/reagent_containers/food/snacks/grown/lime, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/limecake - -/datum/recipe/microwave/lemoncake - reagents = list("milk" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/grown/lemon, - /obj/item/weapon/reagent_containers/food/snacks/grown/lemon, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/lemoncake - -/datum/recipe/microwave/chocolatecake - reagents = list("milk" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/chocolatebar, - /obj/item/weapon/reagent_containers/food/snacks/chocolatebar, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/chocolatecake -*/ - /datum/recipe/microwave/bloodsoup reagents = list("blood" = 10) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/grown/bloodtomato, - /obj/item/weapon/reagent_containers/food/snacks/grown/bloodtomato, - ) + fruit = list("bloodtomato" = 2) result = /obj/item/weapon/reagent_containers/food/snacks/bloodsoup /datum/recipe/microwave/slimesoup @@ -1066,8 +503,8 @@ /datum/recipe/microwave/clownstears reagents = list("water" = 10) + fruit = list("banana" = 1) items = list( - /obj/item/weapon/reagent_containers/food/snacks/grown/banana, /obj/item/weapon/ore/clown, ) result = /obj/item/weapon/reagent_containers/food/snacks/clownstears @@ -1083,21 +520,6 @@ reagents = list("toxin" = 5) result = /obj/item/weapon/reagent_containers/food/snacks/mint -/* -/datum/recipe/microwave/braincake - reagents = list("milk" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/brain - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/braincake -*/ - /datum/recipe/microwave/chocolateegg items = list( /obj/item/weapon/reagent_containers/food/snacks/egg, @@ -1105,24 +527,6 @@ ) result = /obj/item/weapon/reagent_containers/food/snacks/chocolateegg -/* -/datum/recipe/microwave/sausage - items = list( - /obj/item/weapon/reagent_containers/food/snacks/meatball, - /obj/item/weapon/reagent_containers/food/snacks/cutlet, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sausage - -/datum/recipe/microwave/fishfingers - items = list( - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/carpmeat, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/fishfingers -*/ - /datum/recipe/microwave/mysterysoup reagents = list("water" = 10) items = list( @@ -1133,69 +537,27 @@ ) result = /obj/item/weapon/reagent_containers/food/snacks/mysterysoup -/* -/datum/recipe/microwave/pumpkinpie - reagents = list("milk" = 5, "sugar" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/grown/pumpkin, - /obj/item/weapon/reagent_containers/food/snacks/egg, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pumpkinpie - -/datum/recipe/microwave/plumphelmetbiscuit - reagents = list("water" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/plumphelmet, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/plumphelmetbiscuit -*/ - /datum/recipe/microwave/mushroomsoup reagents = list("water" = 5, "milk" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/chanterelle, - ) + fruit = list("mushroom" = 1) result = /obj/item/weapon/reagent_containers/food/snacks/mushroomsoup /datum/recipe/microwave/chawanmushi reagents = list("water" = 5, "soysauce" = 5) + fruit = list("mushroom" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/egg, /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/chanterelle, ) result = /obj/item/weapon/reagent_containers/food/snacks/chawanmushi /datum/recipe/microwave/beetsoup reagents = list("water" = 10) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/grown/whitebeet, - /obj/item/weapon/reagent_containers/food/snacks/grown/cabbage, - ) + fruit = list("whitebeet" = 1, "cabbage" = 1) result = /obj/item/weapon/reagent_containers/food/snacks/beetsoup -/* -/datum/recipe/microwave/appletart - reagents = list("sugar" = 5, "milk" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/grown/goldapple, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/appletart -*/ - /datum/recipe/microwave/herbsalad - items = list( - /obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiavulgaris, - /obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiavulgaris, - /obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiavulgaris, - /obj/item/weapon/reagent_containers/food/snacks/grown/apple, - ) + fruit = list("ambrosia" = 3, "apple" = 1) result = /obj/item/weapon/reagent_containers/food/snacks/herbsalad make_food(var/obj/container as obj) var/obj/item/weapon/reagent_containers/food/snacks/herbsalad/being_cooked = ..(container) @@ -1203,20 +565,12 @@ return being_cooked /datum/recipe/microwave/aesirsalad - items = list( - /obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiadeus, - /obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiadeus, - /obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiadeus, - /obj/item/weapon/reagent_containers/food/snacks/grown/goldapple, - ) + fruit = list("ambrosiadeus" = 3, "goldapple" = 1) result = /obj/item/weapon/reagent_containers/food/snacks/aesirsalad /datum/recipe/microwave/validsalad + fruit = list("ambrosia" = 3, "potato" = 1) items = list( - /obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiavulgaris, - /obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiavulgaris, - /obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiavulgaris, - /obj/item/weapon/reagent_containers/food/snacks/grown/potato, /obj/item/weapon/reagent_containers/food/snacks/meatball, ) result = /obj/item/weapon/reagent_containers/food/snacks/validsalad @@ -1225,31 +579,19 @@ being_cooked.reagents.del_reagent("toxin") return being_cooked -/* -/datum/recipe/microwave/cracker - reagents = list("sodiumchloride" = 1) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/doughslice - ) - result = /obj/item/weapon/reagent_containers/food/snacks/cracker -*/ - ////////////////////////////FOOD ADDITTIONS/////////////////////////////// /datum/recipe/microwave/wrap reagents = list("soysauce" = 10) + fruit = list("cabbage" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/friedegg, - /obj/item/weapon/reagent_containers/food/snacks/grown/cabbage, ) result = /obj/item/weapon/reagent_containers/food/snacks/wrap /datum/recipe/microwave/beans reagents = list("ketchup" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/grown/soybeans, - /obj/item/weapon/reagent_containers/food/snacks/grown/soybeans, - ) + fruit = list("soybeans" = 2) result = /obj/item/weapon/reagent_containers/food/snacks/beans /datum/recipe/microwave/benedict @@ -1262,10 +604,10 @@ /datum/recipe/microwave/meatbun reagents = list("soysauce" = 5) + fruit = list("cabbage" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/dough, /obj/item/weapon/reagent_containers/food/snacks/meatball, - /obj/item/weapon/reagent_containers/food/snacks/grown/cabbage, ) result = /obj/item/weapon/reagent_containers/food/snacks/meatbun @@ -1284,23 +626,12 @@ ) result = /obj/item/weapon/reagent_containers/food/snacks/notasandwich -/* -/datum/recipe/microwave/sugarcookie - reagents = list("sugar" = 5) - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/egg, - ) - result = /obj/item/weapon/reagent_containers/food/snacks/sugarcookie -*/ - /datum/recipe/microwave/friedbanana + reagents = list("sugar" = 10, "cornoil" = 5) + fruit = list("banana" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/grown/banana ) - /obj/item/weapon/ - reagents = list("sugar" = 10, "cornoil" = 5) result = /obj/item/weapon/reagent_containers/food/snacks/friedbanana /datum/recipe/microwave/stuffing @@ -1361,34 +692,12 @@ ) result = /obj/item/weapon/reagent_containers/food/snacks/taco -/* -/datum/recipe/microwave/bun - items = list( - /obj/item/weapon/reagent_containers/food/snacks/dough - ) - result = /obj/item/weapon/reagent_containers/food/snacks/bun - -/datum/recipe/microwave/flatbread - items = list( - /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough - ) - result = /obj/item/weapon/reagent_containers/food/snacks/flatbread -*/ - /datum/recipe/microwave/meatball items = list( /obj/item/weapon/reagent_containers/food/snacks/rawmeatball ) result = /obj/item/weapon/reagent_containers/food/snacks/meatball -/* -/datum/recipe/microwave/cutlet - items = list( - /obj/item/weapon/reagent_containers/food/snacks/rawcutlet - ) - result = /obj/item/weapon/reagent_containers/food/snacks/cutlet -*/ - /datum/recipe/microwave/fries items = list( /obj/item/weapon/reagent_containers/food/snacks/rawsticks diff --git a/code/modules/food/recipes_oven.dm b/code/modules/food/recipes_oven.dm index 298636c8820..c9b1703dc54 100644 --- a/code/modules/food/recipes_oven.dm +++ b/code/modules/food/recipes_oven.dm @@ -51,11 +51,11 @@ /datum/recipe/oven/bananabread reagents = list("milk" = 5, "sugar" = 15) + fruit = list("banana" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/dough, /obj/item/weapon/reagent_containers/food/snacks/dough, /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/grown/banana, ) result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/bananabread @@ -68,13 +68,11 @@ /datum/recipe/oven/carrotcake reagents = list("milk" = 5, "sugar" = 15) + fruit = list("carrot" = 3) items = list( /obj/item/weapon/reagent_containers/food/snacks/dough, /obj/item/weapon/reagent_containers/food/snacks/dough, /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/grown/carrot, - /obj/item/weapon/reagent_containers/food/snacks/grown/carrot, - /obj/item/weapon/reagent_containers/food/snacks/grown/carrot, ) result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/carrotcake @@ -121,24 +119,24 @@ /datum/recipe/oven/pie reagents = list("sugar" = 5) + fruit = list("banana" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/grown/banana, ) result = /obj/item/weapon/reagent_containers/food/snacks/pie /datum/recipe/oven/cherrypie reagents = list("sugar" = 10) + fruit = list("cherries" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/grown/cherries, ) result = /obj/item/weapon/reagent_containers/food/snacks/cherrypie /datum/recipe/oven/berryclafoutis + fruit = list("berries" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/grown/berries, ) result = /obj/item/weapon/reagent_containers/food/snacks/berryclafoutis @@ -157,8 +155,8 @@ result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/tofubread /datum/recipe/oven/loadedbakedpotato + fruit = list("potato" = 1) items = list( - /obj/item/weapon/reagent_containers/food/snacks/grown/potato, /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, ) result = /obj/item/weapon/reagent_containers/food/snacks/loadedbakedpotato @@ -194,73 +192,65 @@ return . /datum/recipe/oven/pizzamargherita + fruit = list("tomato" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, ) result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/margherita /datum/recipe/oven/meatpizza + fruit = list("tomato" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, /obj/item/weapon/reagent_containers/food/snacks/meat, /obj/item/weapon/reagent_containers/food/snacks/meat, /obj/item/weapon/reagent_containers/food/snacks/meat, /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, ) result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatpizza /datum/recipe/oven/syntipizza + fruit = list("tomato" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, ) result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatpizza /datum/recipe/oven/mushroompizza + fruit = list("mushroom" = 5, "tomato" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom, /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, ) result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/mushroompizza /datum/recipe/oven/vegetablepizza + fruit = list("eggplant" = 1, "carrot" = 1, "corn" = 1, "tomato" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/grown/eggplant, - /obj/item/weapon/reagent_containers/food/snacks/grown/carrot, - /obj/item/weapon/reagent_containers/food/snacks/grown/corn, - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato, /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, ) result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/vegetablepizza /datum/recipe/oven/amanita_pie + fruit = list("amanita" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/amanita, ) result = /obj/item/weapon/reagent_containers/food/snacks/amanita_pie /datum/recipe/oven/plump_pie + fruit = list("plumphelmet" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/plumphelmet, ) result = /obj/item/weapon/reagent_containers/food/snacks/plump_pie @@ -300,74 +290,58 @@ result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/bread /datum/recipe/oven/applepie + fruit = list("apple" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, - /obj/item/weapon/reagent_containers/food/snacks/grown/apple, ) result = /obj/item/weapon/reagent_containers/food/snacks/applepie /datum/recipe/oven/applecake reagents = list("milk" = 5, "sugar" = 5) + fruit = list("apple" = 2) items = list( /obj/item/weapon/reagent_containers/food/snacks/dough, /obj/item/weapon/reagent_containers/food/snacks/dough, /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/grown/apple, - /obj/item/weapon/reagent_containers/food/snacks/grown/apple, ) result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/applecake /datum/recipe/oven/orangecake reagents = list("milk" = 5) + fruit = list("orange" = 2) items = list( - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/grown/orange, - /obj/item/weapon/reagent_containers/food/snacks/grown/orange, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, ) result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/orangecake /datum/recipe/oven/limecake reagents = list("milk" = 5) + fruit = list("lime" = 2) items = list( - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/grown/lime, - /obj/item/weapon/reagent_containers/food/snacks/grown/lime, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, ) result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/limecake /datum/recipe/oven/lemoncake reagents = list("milk" = 5) + fruit = list("lemon" = 2) items = list( - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/grown/lemon, - /obj/item/weapon/reagent_containers/food/snacks/grown/lemon, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, ) result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/lemoncake /datum/recipe/oven/chocolatecake reagents = list("milk" = 5) items = list( - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, /obj/item/weapon/reagent_containers/food/snacks/chocolatebar, /obj/item/weapon/reagent_containers/food/snacks/chocolatebar, ) @@ -376,33 +350,29 @@ /datum/recipe/oven/braincake reagents = list("milk" = 5) items = list( - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/egg, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/reagent_containers/food/snacks/dough, /obj/item/organ/brain ) result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/braincake /datum/recipe/oven/pumpkinpie reagents = list("milk" = 5, "sugar" = 5) + fruit = list("pumpkin" = 1) items = list( - /obj/item/weapon/reagent_containers/food/snacks/flour, - /obj/item/weapon/reagent_containers/food/snacks/grown/pumpkin, - /obj/item/weapon/reagent_containers/food/snacks/egg, + /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, ) result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pumpkinpie /datum/recipe/oven/appletart reagents = list("sugar" = 5, "milk" = 5) + fruit = list("goldapple" = 1) items = list( /obj/item/weapon/reagent_containers/food/snacks/flour, /obj/item/weapon/reagent_containers/food/snacks/flour, /obj/item/weapon/reagent_containers/food/snacks/flour, /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/weapon/reagent_containers/food/snacks/grown/goldapple, ) result = /obj/item/weapon/reagent_containers/food/snacks/appletart diff --git a/code/modules/hydroponics/_hydro_setup.dm b/code/modules/hydroponics/_hydro_setup.dm new file mode 100644 index 00000000000..a3fd4604a66 --- /dev/null +++ b/code/modules/hydroponics/_hydro_setup.dm @@ -0,0 +1,58 @@ +//Misc +#define DEAD_PLANT_COLOUR "#C2A180" + +// Definitions for genes (trait groupings) +#define GENE_BIOCHEMISTRY "biochemistry" +#define GENE_HARDINESS "hardiness" +#define GENE_ENVIRONMENT "environment" +#define GENE_METABOLISM "metabolism" +#define GENE_STRUCTURE "appearance" +#define GENE_DIET "diet" +#define GENE_PIGMENT "pigment" +#define GENE_OUTPUT "output" +#define GENE_ATMOSPHERE "atmosphere" +#define GENE_VIGOUR "vigour" +#define GENE_FRUIT "fruit" +#define GENE_SPECIAL "special" + +#define ALL_GENES list(GENE_BIOCHEMISTRY,GENE_HARDINESS,GENE_ENVIRONMENT,GENE_METABOLISM,GENE_STRUCTURE,GENE_DIET,GENE_PIGMENT,GENE_OUTPUT,GENE_ATMOSPHERE,GENE_VIGOUR,GENE_FRUIT,GENE_SPECIAL) + +//Definitions for traits (individual descriptors) +#define TRAIT_CHEMS 1 +#define TRAIT_EXUDE_GASSES 2 +#define TRAIT_ALTER_TEMP 3 +#define TRAIT_POTENCY 4 +#define TRAIT_HARVEST_REPEAT 5 +#define TRAIT_PRODUCES_POWER 6 +#define TRAIT_JUICY 7 +#define TRAIT_PRODUCT_ICON 8 +#define TRAIT_PLANT_ICON 0 +#define TRAIT_CONSUME_GASSES 10 +#define TRAIT_REQUIRES_NUTRIENTS 11 +#define TRAIT_NUTRIENT_CONSUMPTION 12 +#define TRAIT_REQUIRES_WATER 13 +#define TRAIT_WATER_CONSUMPTION 14 +#define TRAIT_CARNIVOROUS 15 +#define TRAIT_PARASITE 16 +#define TRAIT_STINGS 17 +#define TRAIT_IDEAL_HEAT 18 +#define TRAIT_HEAT_TOLERANCE 19 +#define TRAIT_IDEAL_LIGHT 20 +#define TRAIT_LIGHT_TOLERANCE 21 +#define TRAIT_LOWKPA_TOLERANCE 22 +#define TRAIT_HIGHKPA_TOLERANCE 23 +#define TRAIT_EXPLOSIVE 24 +#define TRAIT_TOXINS_TOLERANCE 25 +#define TRAIT_PEST_TOLERANCE 26 +#define TRAIT_WEED_TOLERANCE 27 +#define TRAIT_ENDURANCE 28 +#define TRAIT_YIELD 29 +#define TRAIT_SPREAD 30 +#define TRAIT_MATURATION 31 +#define TRAIT_PRODUCTION 32 +#define TRAIT_TELEPORTING 33 +#define TRAIT_PLANT_COLOUR 34 +#define TRAIT_PRODUCT_COLOUR 35 +#define TRAIT_BIOLUM 36 +#define TRAIT_BIOLUM_COLOUR 37 +#define TRAIT_IMMUTABLE 38 \ No newline at end of file diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm new file mode 100644 index 00000000000..056edc02d6f --- /dev/null +++ b/code/modules/hydroponics/grown.dm @@ -0,0 +1,394 @@ +//Grown foods. +/obj/item/weapon/reagent_containers/food/snacks/grown + + name = "fruit" + icon = 'icons/obj/hydroponics_products.dmi' + icon_state = "blank" + desc = "Nutritious! Probably." + + var/plantname + var/datum/seed/seed + var/potency = -1 + +/obj/item/weapon/reagent_containers/food/snacks/grown/New(newloc,planttype) + + ..() + if(!dried_type) + dried_type = type + src.pixel_x = rand(-5.0, 5) + src.pixel_y = rand(-5.0, 5) + + // Fill the object up with the appropriate reagents. + if(planttype) + plantname = planttype + + if(!plantname) + return + + if(!plant_controller) + sleep(250) // ugly hack, should mean roundstart plants are fine. + if(!plant_controller) + world << "Plant controller does not exist and [src] requires it. Aborting." + del(src) + return + + seed = plant_controller.seeds[plantname] + + if(!seed) + return + + name = "[seed.seed_name]" + + update_icon() + + if(!seed.chems) + return + + potency = seed.get_trait(TRAIT_POTENCY) + + for(var/rid in seed.chems) + var/list/reagent_data = seed.chems[rid] + if(reagent_data && reagent_data.len) + var/rtotal = reagent_data[1] + if(reagent_data.len > 1 && potency > 0) + rtotal += round(potency/reagent_data[2]) + reagents.add_reagent(rid,max(1,rtotal)) + update_desc() + if(reagents.total_volume > 0) + bitesize = 1+round(reagents.total_volume / 2, 1) + +/obj/item/weapon/reagent_containers/food/snacks/grown/proc/update_desc() + + if(!seed) + return + if(!plant_controller) + sleep(250) // ugly hack, should mean roundstart plants are fine. + if(!plant_controller) + world << "Plant controller does not exist and [src] requires it. Aborting." + del(src) + return + + if(plant_controller.product_descs["[seed.uid]"]) + desc = plant_controller.product_descs["[seed.uid]"] + else + var/list/descriptors = list() + if(reagents.has_reagent("sugar") || reagents.has_reagent("cherryjelly") || reagents.has_reagent("honey") || reagents.has_reagent("berryjuice")) + descriptors |= "sweet" + if(reagents.has_reagent("anti_toxin")) + descriptors |= "astringent" + if(reagents.has_reagent("frostoil")) + descriptors |= "numbing" + if(reagents.has_reagent("nutriment")) + descriptors |= "nutritious" + if(reagents.has_reagent("condensedcapsaicin") || reagents.has_reagent("capsaicin")) + descriptors |= "spicy" + if(reagents.has_reagent("coco")) + descriptors |= "bitter" + if(reagents.has_reagent("orangejuice") || reagents.has_reagent("lemonjuice") || reagents.has_reagent("limejuice")) + descriptors |= "sweet-sour" + if(reagents.has_reagent("radium") || reagents.has_reagent("uranium")) + descriptors |= "radioactive" + if(reagents.has_reagent("amatoxin") || reagents.has_reagent("toxin")) + descriptors |= "poisonous" + if(reagents.has_reagent("psilocybin") || reagents.has_reagent("space_drugs")) + descriptors |= "hallucinogenic" + if(reagents.has_reagent("bicaridine")) + descriptors |= "medicinal" + if(reagents.has_reagent("gold")) + descriptors |= "shiny" + if(reagents.has_reagent("lube")) + descriptors |= "slippery" + if(reagents.has_reagent("pacid") || reagents.has_reagent("sacid")) + descriptors |= "acidic" + if(seed.get_trait(TRAIT_JUICY)) + descriptors |= "juicy" + if(seed.get_trait(TRAIT_STINGS)) + descriptors |= "stinging" + if(seed.get_trait(TRAIT_TELEPORTING)) + descriptors |= "glowing" + if(seed.get_trait(TRAIT_EXPLOSIVE)) + descriptors |= "bulbous" + + var/descriptor_num = rand(2,4) + var/descriptor_count = descriptor_num + desc = "A" + while(descriptors.len && descriptor_num > 0) + var/chosen = pick(descriptors) + descriptors -= chosen + desc += "[(descriptor_count>1 && descriptor_count!=descriptor_num) ? "," : "" ] [chosen]" + descriptor_num-- + if(seed.seed_noun == "spores") + desc += " mushroom" + else + desc += " fruit" + plant_controller.product_descs["[seed.uid]"] = desc + desc += ". Delicious! Probably." + +/obj/item/weapon/reagent_containers/food/snacks/grown/update_icon() + if(!seed || !plant_controller || !plant_controller.plant_icon_cache) + return + overlays.Cut() + var/image/plant_icon + var/icon_key = "fruit-[seed.get_trait(TRAIT_PRODUCT_ICON)]-[seed.get_trait(TRAIT_PRODUCT_COLOUR)]-[seed.get_trait(TRAIT_PLANT_COLOUR)]" + if(plant_controller.plant_icon_cache[icon_key]) + plant_icon = plant_controller.plant_icon_cache[icon_key] + else + plant_icon = image('icons/obj/hydroponics_products.dmi',"blank") + var/image/fruit_base = image('icons/obj/hydroponics_products.dmi',"[seed.get_trait(TRAIT_PRODUCT_ICON)]-product") + fruit_base.color = "[seed.get_trait(TRAIT_PRODUCT_COLOUR)]" + plant_icon.overlays |= fruit_base + if("[seed.get_trait(TRAIT_PRODUCT_ICON)]-leaf" in icon_states('icons/obj/hydroponics_products.dmi')) + var/image/fruit_leaves = image('icons/obj/hydroponics_products.dmi',"[seed.get_trait(TRAIT_PRODUCT_ICON)]-leaf") + fruit_leaves.color = "[seed.get_trait(TRAIT_PLANT_COLOUR)]" + plant_icon.overlays |= fruit_leaves + plant_controller.plant_icon_cache[icon_key] = plant_icon + overlays |= plant_icon + +/obj/item/weapon/reagent_containers/food/snacks/grown/Crossed(var/mob/living/M) + if(seed && seed.get_trait(TRAIT_JUICY) == 2) + if(istype(M)) + + if(M.buckled) + return + + if(istype(M,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + if(H.shoes && H.shoes.flags & NOSLIP) + return + + M.stop_pulling() + M << "You slipped on the [name]!" + playsound(src.loc, 'sound/misc/slip.ogg', 50, 1, -3) + M.Stun(8) + M.Weaken(5) + seed.thrown_at(src,M) + sleep(-1) + if(src) del(src) + return + +/obj/item/weapon/reagent_containers/food/snacks/grown/throw_impact(atom/hit_atom) + ..() + if(seed) seed.thrown_at(src,hit_atom) + +/obj/item/weapon/reagent_containers/food/snacks/grown/attackby(var/obj/item/weapon/W, var/mob/user) + + if(seed) + if(seed.get_trait(TRAIT_PRODUCES_POWER) && istype(W, /obj/item/stack/cable_coil)) + var/obj/item/stack/cable_coil/C = W + if(C.use(5)) + //TODO: generalize this. + user << "You add some cable to the [src.name] and slide it inside the battery casing." + var/obj/item/weapon/stock_parts/cell/potato/pocell = new /obj/item/weapon/stock_parts/cell/potato(get_turf(user)) + if(src.loc == user && !(user.l_hand && user.r_hand) && istype(user,/mob/living/carbon/human)) + user.put_in_hands(pocell) + pocell.maxcharge = src.potency * 10 + pocell.charge = pocell.maxcharge + del(src) + return + else if(W.sharp) + if(seed.kitchen_tag == "pumpkin") // Ugggh these checks are awful. + user.show_message("You carve a face into [src]!", 1) + new /obj/item/clothing/head/hardhat/pumpkinhead (user.loc) + del(src) + return + else if(seed.kitchen_tag == "potato") + user << "You slice \the [src] into sticks." + new /obj/item/weapon/reagent_containers/food/snacks/rawsticks(get_turf(src)) + del(src) + return + else if(seed.kitchen_tag == "carrot") + user << "You slice \the [src] into sticks." + new /obj/item/weapon/reagent_containers/food/snacks/carrotfries(get_turf(src)) + del(src) + return + else if(seed.kitchen_tag == "watermelon") + user << "You slice \the [src] into large slices." + for(var/i=0,i<5,i++) + new /obj/item/weapon/reagent_containers/food/snacks/watermelonslice(get_turf(src)) + del(src) + return + else if(seed.kitchen_tag == "soybeans") + user << "You roughly chop up \the [src]." + new /obj/item/weapon/reagent_containers/food/snacks/soydope(get_turf(src)) + del(src) + return + else if(seed.chems) + if(istype(W,/obj/item/weapon/hatchet) && !isnull(seed.chems["woodpulp"])) + user.show_message("You make planks out of \the [src]!", 1) + for(var/i=0,i<2,i++) + var/obj/item/stack/sheet/wood/NG = new (user.loc) + NG.color = seed.get_trait(TRAIT_PRODUCT_COLOUR) + for (var/obj/item/stack/sheet/wood/G in user.loc) + if(G==NG) + continue + if(G.amount>=G.max_amount) + continue + G.attackby(NG, user) + user << "You add the newly-formed wood to the stack. It now contains [NG.amount] planks." + del(src) + return + else if(istype(W, /obj/item/weapon/rollingpaper)) + if(seed.kitchen_tag == "ambrosia" || seed.kitchen_tag == "ambrosiadeus" || seed.kitchen_tag == "tobacco" || seed.kitchen_tag == "stobacco") + user.unEquip(W) + if(seed.kitchen_tag == "ambrosia") + var/obj/item/clothing/mask/cigarette/joint/J = new /obj/item/clothing/mask/cigarette/joint(user.loc) + J.chem_volume = src.reagents.total_volume + src.reagents.trans_to(J, J.chem_volume) + del(W) + user.put_in_active_hand(J) + else if(seed.kitchen_tag == "ambrosiadeus") + var/obj/item/clothing/mask/cigarette/joint/deus/J = new /obj/item/clothing/mask/cigarette/joint/deus(user.loc) + J.chem_volume = src.reagents.total_volume + src.reagents.trans_to(J, J.chem_volume) + del(W) + user.put_in_active_hand(J) + else if(seed.kitchen_tag == "tobacco" || seed.kitchen_tag == "stobacco") + var/obj/item/clothing/mask/cigarette/handroll/J = new /obj/item/clothing/mask/cigarette/handroll(user.loc) + J.chem_volume = src.reagents.total_volume + src.reagents.trans_to(J, J.chem_volume) + del(W) + user.put_in_active_hand(J) + user << "\blue You roll the [src] into a rolling paper." + del(src) + else + user << "\red You can't roll a smokable from the [src]." + + ..() + +/obj/item/weapon/reagent_containers/food/snacks/grown/attack(var/mob/living/carbon/M, var/mob/user, var/def_zone) + if(user == M) + return ..() + + if(user.a_intent == "hurt") + + // This is being copypasted here because reagent_containers (WHY DOES FOOD DESCEND FROM THAT) overrides it completely. + // TODO: refactor all food paths to be less horrible and difficult to work with in this respect. ~Z + if(!istype(M) || (can_operate(M) && do_surgery(M,user,src))) return 0 + + user.lastattacked = M + M.lastattacker = user + user.attack_log += "\[[time_stamp()]\] Attacked [M.name] ([M.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" + M.attack_log += "\[[time_stamp()]\] Attacked by [user.name] ([user.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" + msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] attacked [M.name] ([M.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" ) + + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/hit = H.attacked_by(src, user, def_zone) + if(hit && hitsound) + playsound(loc, hitsound, 50, 1, -1) + return hit + else + if(attack_verb.len) + user.visible_message("[M] has been [pick(attack_verb)] with [src] by [user]!") + else + user.visible_message("[M] has been attacked with [src] by [user]!") + + if (hitsound) + playsound(loc, hitsound, 50, 1, -1) + switch(damtype) + if("brute") + M.take_organ_damage(force) + if(prob(33)) + var/turf/simulated/location = get_turf(M) + if(istype(location)) location.add_blood_floor(M) + if("fire") + if (!(RESIST_COLD in M.mutations)) + M.take_organ_damage(0, force) + M.updatehealth() + + if(seed && seed.get_trait(TRAIT_STINGS)) + if(!reagents || reagents.total_volume <= 0) + return + reagents.remove_any(rand(1,3)) + seed.thrown_at(src,M) + sleep(-1) + if(!src) + return + if(prob(35)) + if(user) + user << "\The [src] has fallen to bits." + //user.drop_from_inventory(src) + del(src) + + add_fingerprint(user) + return 1 + + else + ..() + +/obj/item/weapon/reagent_containers/food/snacks/grown/attack_self(mob/user as mob) + + if(!seed) + return + + if(istype(user.loc,/turf/space)) + return + + if(user.a_intent == "hurt") + user.visible_message("\The [user] squashes \the [src]!") + seed.thrown_at(src,user) + sleep(-1) + if(src) del(src) + return + + if(seed.kitchen_tag == "grass") + user.show_message("You make a grass tile out of \the [src]!", 1) + for(var/i=0,i<2,i++) + var/obj/item/stack/tile/grass/G = new (user.loc) + G.color = seed.get_trait(TRAIT_PRODUCT_COLOUR) + for (var/obj/item/stack/tile/grass/NG in user.loc) + if(G==NG) + continue + if(NG.amount>=NG.max_amount) + continue + NG.attackby(G, user) + user << "You add the newly-formed grass to the stack. It now contains [G.amount] tiles." + del(src) + return + + if(seed.get_trait(TRAIT_SPREAD) > 0) + user << "You plant the [src.name]." + new /obj/machinery/portable_atmospherics/hydroponics/soil/invisible(get_turf(user),src.seed) + new /obj/effect/plant(get_turf(user), src.seed) + del(src) + return + + /* + if(seed.kitchen_tag) + switch(seed.kitchen_tag) + if("shand") + var/obj/item/stack/medical/bruise_pack/tajaran/poultice = new /obj/item/stack/medical/bruise_pack/tajaran(user.loc) + poultice.heal_brute = potency + user << "You mash the leaves into a poultice." + del(src) + return + if("mtear") + var/obj/item/stack/medical/ointment/tajaran/poultice = new /obj/item/stack/medical/ointment/tajaran(user.loc) + poultice.heal_burn = potency + user << "You mash the petals into a poultice." + del(src) + return + */ + +/obj/item/weapon/reagent_containers/food/snacks/grown/pickup(mob/user) + ..() + if(!seed) + return + if(seed.get_trait(TRAIT_BIOLUM)) + user.SetLuminosity(user.luminosity + seed.get_trait(TRAIT_BIOLUM)) + SetLuminosity(0) + if(seed.get_trait(TRAIT_STINGS)) + var/mob/living/carbon/human/H = user + if(istype(H) && H.gloves) + return + if(!reagents || reagents.total_volume <= 0) + return + 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")) + +/obj/item/weapon/reagent_containers/food/snacks/grown/dropped(mob/user) + ..() + if(seed && seed.get_trait(TRAIT_BIOLUM)) + user.SetLuminosity(user.luminosity - seed.get_trait(TRAIT_BIOLUM)) + SetLuminosity(seed.get_trait(TRAIT_BIOLUM)) diff --git a/code/modules/hydroponics/grown_inedible.dm b/code/modules/hydroponics/grown_inedible.dm index a7cb080602b..8c23033a586 100644 --- a/code/modules/hydroponics/grown_inedible.dm +++ b/code/modules/hydroponics/grown_inedible.dm @@ -8,7 +8,7 @@ var/plantname var/potency = 1 -/obj/item/weapon/grown/New() +/obj/item/weapon/grown/New(newloc,planttype) ..() @@ -17,112 +17,20 @@ R.my_atom = src //Handle some post-spawn var stuff. - spawn(1) - // Fill the object up with the appropriate reagents. - if(!isnull(plantname)) - var/datum/seed/S = seed_types[plantname] - if(!S || !S.chems) - return - - potency = S.potency - - for(var/rid in S.chems) - var/list/reagent_data = S.chems[rid] - var/rtotal = reagent_data[1] - if(reagent_data.len > 1 && potency > 0) - rtotal += round(potency/reagent_data[2]) - reagents.add_reagent(rid,max(1,rtotal)) - -/obj/item/weapon/grown/proc/changePotency(newValue) //-QualityVan - potency = newValue - -/obj/item/weapon/grown/log - name = "towercap" - name = "tower-cap log" - desc = "It's better than bad, it's good!" - icon = 'icons/obj/harvest.dmi' - icon_state = "logs" - force = 5 - throwforce = 5 - w_class = 3.0 - throw_speed = 3 - throw_range = 3 - origin_tech = "materials=1" - attack_verb = list("bashed", "battered", "bludgeoned", "whacked") - - attackby(obj/item/weapon/W as obj, mob/user as mob, params) - if(istype(W, /obj/item/weapon/circular_saw) || istype(W, /obj/item/weapon/hatchet) || (istype(W, /obj/item/weapon/twohanded/fireaxe) && W:wielded) || istype(W, /obj/item/weapon/melee/energy)) - user.show_message("You make planks out of \the [src]!", 1) - for(var/i=0,i<2,i++) - var/obj/item/stack/sheet/wood/NG = new (user.loc) - for (var/obj/item/stack/sheet/wood/G in user.loc) - if(G==NG) - continue - if(G.amount>=G.max_amount) - continue - G.attackby(NG, user, params) - usr << "You add the newly-formed wood to the stack. It now contains [NG.amount] planks." - del(src) + if(planttype) + plantname = planttype + var/datum/seed/S = plant_controller.seeds[plantname] + if(!S || !S.chems) return -/obj/item/weapon/grown/sunflower // FLOWER POWER! - plantname = "sunflowers" - name = "sunflower" - desc = "It's beautiful! A certain person might beat you to death if you trample these." - icon = 'icons/obj/harvest.dmi' - icon_state = "sunflower" - damtype = "fire" - force = 0 - throwforce = 1 - w_class = 1.0 - throw_speed = 1 - throw_range = 3 + potency = S.get_trait(TRAIT_POTENCY) -/obj/item/weapon/grown/sunflower/attack(mob/M as mob, mob/user as mob) - M << " [user] smacks you with a sunflower!FLOWER POWER" - user << " Your sunflower's FLOWER POWER strikes [M]" - -/obj/item/weapon/grown/nettle // -- Skie - plantname = "nettle" - desc = "It's probably not wise to touch it with bare hands..." - icon = 'icons/obj/weapons.dmi' - name = "nettle" - icon_state = "nettle" - damtype = "fire" - force = 15 - throwforce = 1 - w_class = 2.0 - throw_speed = 1 - throw_range = 3 - origin_tech = "combat=1" - New() - ..() - spawn(5) - force = round((5+potency/5), 1) - -/obj/item/weapon/grown/nettle/pickup(mob/living/carbon/human/user as mob) - if(!user.gloves) - user << "\red The nettle burns your bare hand!" - if(istype(user, /mob/living/carbon/human)) - var/organ = ((user.hand ? "l_":"r_") + "arm") - var/obj/item/organ/external/affecting = user.get_organ(organ) - if(affecting.take_damage(0,force)) - user.UpdateDamageIcon() - else - user.take_organ_damage(0,force) - -/obj/item/weapon/grown/nettle/afterattack(atom/A as mob|obj, mob/user as mob, proximity) - if(!proximity) return - if(force > 0) - force -= rand(1,(force/3)+1) // When you whack someone with it, leaves fall off - playsound(loc, 'sound/weapons/bladeslice.ogg', 50, 1, -1) - else - usr << "All the leaves have fallen off the nettle from violent whacking." - del(src) - -/obj/item/weapon/grown/nettle/changePotency(newValue) //-QualityVan - potency = newValue - force = round((5+potency/5), 1) + for(var/rid in S.chems) + var/list/reagent_data = S.chems[rid] + var/rtotal = reagent_data[1] + if(reagent_data.len > 1 && potency > 0) + rtotal += round(potency/reagent_data[2]) + reagents.add_reagent(rid,max(1,rtotal)) /obj/item/weapon/grown/deathnettle // -- Skie plantname = "deathnettle" @@ -147,53 +55,10 @@ viewers(user) << "\red [user] is eating some of the [src.name]! It looks like \he's trying to commit suicide." return (BRUTELOSS|TOXLOSS) -/obj/item/weapon/grown/deathnettle/pickup(mob/living/carbon/human/user as mob) - if(!user.gloves) - if(istype(user, /mob/living/carbon/human)) - var/organ = ((user.hand ? "l_":"r_") + "arm") - var/obj/item/organ/external/affecting = user.get_organ(organ) - if(affecting.take_damage(0,force)) - user.UpdateDamageIcon() - else - user.take_organ_damage(0,force) - if(prob(50)) - user.Paralyse(5) - user << "\red You are stunned by the Deathnettle when you try picking it up!" - -/obj/item/weapon/grown/deathnettle/attack(mob/living/carbon/M as mob, mob/user as mob) - if(!..()) return - if(istype(M, /mob/living)) - M << "\red You are stunned by the powerful acid of the Deathnettle!" - - M.attack_log += text("\[[time_stamp()]\] Had the [src.name] used on them by [user.name] ([user.ckey])") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] on [M.name] ([M.ckey])") - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] used the [src.name] on [M.name] ([M.ckey]) (JMP)") - - playsound(loc, 'sound/weapons/bladeslice.ogg', 50, 1, -1) - - M.eye_blurry += force/7 - if(prob(20)) - M.Paralyse(force/6) - M.Weaken(force/15) - M.drop_item() - -/obj/item/weapon/grown/deathnettle/afterattack(atom/A as mob|obj, mob/user as mob, proximity) - if(!proximity) return - if (force > 0) - force -= rand(1,(force/3)+1) // When you whack someone with it, leaves fall off - - else - usr << "All the leaves have fallen off the deathnettle from violent whacking." - del(src) - -/obj/item/weapon/grown/deathnettle/changePotency(newValue) //-QualityVan - potency = newValue - force = round((5+potency/2.5), 1) - /obj/item/weapon/corncob name = "corn cob" desc = "A reminder of meals gone by." - icon = 'icons/obj/harvest.dmi' + icon = 'icons/obj/trash.dmi' icon_state = "corncob" item_state = "corncob" w_class = 2.0 @@ -201,10 +66,21 @@ throw_speed = 4 throw_range = 20 -/obj/item/weapon/corncob/attackby(obj/item/weapon/W as obj, mob/user as mob, params) +/obj/item/weapon/corncob/attackby(obj/item/weapon/W as obj, mob/user as mob) ..() if(istype(W, /obj/item/weapon/circular_saw) || istype(W, /obj/item/weapon/hatchet) || istype(W, /obj/item/weapon/kitchen/utensil/knife) || istype(W, /obj/item/weapon/kitchenknife) || istype(W, /obj/item/weapon/kitchenknife/ritual)) user << "You use [W] to fashion a pipe out of the corn cob!" new /obj/item/clothing/mask/cigarette/pipe/cobpipe (user.loc) del(src) return + +/obj/item/weapon/bananapeel + name = "banana peel" + desc = "A peel from a banana." + icon = 'icons/obj/items.dmi' + icon_state = "banana_peel" + item_state = "banana_peel" + w_class = 2.0 + throwforce = 0 + throw_speed = 4 + throw_range = 20 diff --git a/code/modules/hydroponics/grown_predefined.dm b/code/modules/hydroponics/grown_predefined.dm new file mode 100644 index 00000000000..682ce791e91 --- /dev/null +++ b/code/modules/hydroponics/grown_predefined.dm @@ -0,0 +1,40 @@ +// Predefined types for placing on the map. + +/obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/libertycap + plantname = "libertycap" + +/obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiavulgaris + plantname = "ambrosia" + +/obj/item/weapon/reagent_containers/food/snacks/grown/tomato + plantname = "tomato" + +/obj/item/weapon/reagent_containers/food/snacks/grown/carrot + plantname = "carrot" + +/obj/item/weapon/reagent_containers/food/snacks/grown/berries + plantname = "berries" + +/obj/item/weapon/reagent_containers/food/snacks/grown/banana + plantname = "banana" + +/obj/item/weapon/reagent_containers/food/snacks/grown/chili + plantname = "chili" + +/obj/item/weapon/reagent_containers/food/snacks/grown/lemon + plantname = "lemon" + +/obj/item/weapon/reagent_containers/food/snacks/grown/cherries + plantname = "cherry" + +/obj/item/weapon/reagent_containers/food/snacks/grown/orange + plantname = "orange" + +/obj/item/weapon/reagent_containers/food/snacks/grown/corn + plantname = "corn" + +/obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/amanita + plantname = "amanita" + +/obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiadeus + plantname = "ambrosiadeus" \ No newline at end of file diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm new file mode 100644 index 00000000000..abb67db4615 --- /dev/null +++ b/code/modules/hydroponics/seed.dm @@ -0,0 +1,743 @@ +/datum/plantgene + var/genetype // Label used when applying trait. + var/list/values // Values to copy into the target seed datum. + +/datum/seed + //Tracking. + var/uid // Unique identifier. + var/name // Index for global list. + var/seed_name // Plant name for seed packet. + var/seed_noun = "seeds" // Descriptor for packet. + var/display_name // Prettier name. + var/roundstart // If set, seed will not display variety number. + var/mysterious // Only used for the random seed packets. + var/can_self_harvest = 0 // Mostly used for living mobs. + var/growth_stages = 0 // Number of stages the plant passes through before it is mature. + var/list/traits = list() // Initialized in New() + var/list/mutants // Possible predefined mutant varieties, if any. + var/list/chems // Chemicals that plant produces in products/injects into victim. + var/list/consume_gasses // The plant will absorb these gasses during its life. + var/list/exude_gasses // The plant will exude these gasses during its life. + var/kitchen_tag // Used by the reagent grinder. + var/trash_type // Garbage item produced when eaten. + var/splat_type = /obj/effect/decal/cleanable/fruit_smudge // Graffiti decal. + var/has_mob_product + +/datum/seed/New() + + set_trait(TRAIT_IMMUTABLE, 0) // If set, plant will never mutate. If -1, plant is highly mutable. + set_trait(TRAIT_HARVEST_REPEAT, 0) // If 1, this plant will fruit repeatedly. + set_trait(TRAIT_PRODUCES_POWER, 0) // Can be used to make a battery. + set_trait(TRAIT_JUICY, 0) // When thrown, causes a splatter decal. + set_trait(TRAIT_EXPLOSIVE, 0) // When thrown, acts as a grenade. + set_trait(TRAIT_CARNIVOROUS, 0) // 0 = none, 1 = eat pests in tray, 2 = eat living things (when a vine). + set_trait(TRAIT_PARASITE, 0) // 0 = no, 1 = gain health from weed level. + set_trait(TRAIT_STINGS, 0) // Can cause damage/inject reagents when thrown or handled. + set_trait(TRAIT_YIELD, 0) // Amount of product. + set_trait(TRAIT_SPREAD, 0) // 0 limits plant to tray, 1 = creepers, 2 = vines. + set_trait(TRAIT_MATURATION, 0) // Time taken before the plant is mature. + set_trait(TRAIT_PRODUCTION, 0) // Time before harvesting can be undertaken again. + set_trait(TRAIT_TELEPORTING, 0) // Uses the bluespace tomato effect. + set_trait(TRAIT_BIOLUM, 0) // Plant is bioluminescent. + set_trait(TRAIT_ALTER_TEMP, 0) // If set, the plant will periodically alter local temp by this amount. + set_trait(TRAIT_PRODUCT_ICON, 0) // Icon to use for fruit coming from this plant. + set_trait(TRAIT_PLANT_ICON, 0) // Icon to use for the plant growing in the tray. + set_trait(TRAIT_PRODUCT_COLOUR, 0) // Colour to apply to product icon. + set_trait(TRAIT_BIOLUM_COLOUR, 0) // The colour of the plant's radiance. + set_trait(TRAIT_POTENCY, 1) // General purpose plant strength value. + set_trait(TRAIT_REQUIRES_NUTRIENTS, 1) // The plant can starve. + set_trait(TRAIT_REQUIRES_WATER, 1) // The plant can become dehydrated. + set_trait(TRAIT_WATER_CONSUMPTION, 3) // Plant drinks this much per tick. + set_trait(TRAIT_LIGHT_TOLERANCE, 5) // Departure from ideal that is survivable. + set_trait(TRAIT_TOXINS_TOLERANCE, 5) // Resistance to poison. + set_trait(TRAIT_PEST_TOLERANCE, 5) // Threshold for pests to impact health. + set_trait(TRAIT_WEED_TOLERANCE, 5) // Threshold for weeds to impact health. + set_trait(TRAIT_IDEAL_LIGHT, 8) // Preferred light level in luminosity. + set_trait(TRAIT_HEAT_TOLERANCE, 20) // Departure from ideal that is survivable. + set_trait(TRAIT_LOWKPA_TOLERANCE, 25) // Low pressure capacity. + set_trait(TRAIT_ENDURANCE, 100) // Maximum plant HP when growing. + set_trait(TRAIT_HIGHKPA_TOLERANCE, 200) // High pressure capacity. + set_trait(TRAIT_IDEAL_HEAT, 293) // Preferred temperature in Kelvin. + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25) // Plant eats this much per tick. + set_trait(TRAIT_PLANT_COLOUR, "#46B543") // Colour of the plant icon. + + spawn(5) + sleep(-1) + update_growth_stages() + +/datum/seed/proc/get_trait(var/trait) + return traits["[trait]"] + +/datum/seed/proc/set_trait(var/trait,var/nval,var/ubound,var/lbound, var/degrade) + if(!isnull(degrade)) nval *= degrade + if(!isnull(ubound)) nval = min(nval,ubound) + if(!isnull(lbound)) nval = max(nval,lbound) + traits["[trait]"] = nval + +/datum/seed/proc/create_spores(var/turf/T, var/obj/item/thrown) + if(!T) + return + if(!istype(T)) + T = get_turf(T) + if(!T) + return + + var/datum/reagents/R = new/datum/reagents(100) + R.my_atom = thrown + if(chems.len) + for(var/rid in chems) + var/injecting = min(5,max(1,get_trait(TRAIT_POTENCY)/3)) + R.add_reagent(rid,injecting) + + var/datum/effect/effect/system/chem_smoke_spread/S = new() + S.attach(T) + S.set_up(R, round(get_trait(TRAIT_POTENCY)/4), 0, T) + 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_trait(TRAIT_CARNIVOROUS)) + return + + if(!istype(target)) + if(istype(target, /mob/living/simple_animal/mouse) || istype(target, /mob/living/simple_animal/lizard)) + new /obj/effect/decal/cleanable/blood/splatter(get_turf(target)) + del(target) + return + + + if(!target_limb) target_limb = pick("l_foot","r_foot","l_leg","r_leg","l_hand","r_hand","l_arm", "r_arm","head","chest","groin") + var/obj/item/organ/external/affecting = target.get_organ(target_limb) + var/damage = 0 + + if(get_trait(TRAIT_CARNIVOROUS)) + if(get_trait(TRAIT_CARNIVOROUS) == 2) + if(affecting) + target << "\The [fruit]'s thorns pierce your [affecting.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.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) + + var/body_coverage = HEAD|HEADCOVERSMOUTH|HEADCOVERSEYES|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 + + 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)) + + create_spores(origin_turf, thrown) + + 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/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_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)/5))/exude_gasses.len))) + */ + + // Handle light requirements. + if(!light_supplied) + var/area/A = get_area(current_turf) + if(A) + if(A.lighting_use_dynamic) + light_supplied = max(0,min(10,current_turf.lighting_lumcount)-5) + else + light_supplied = 5 + if(light_supplied) + if(abs(light_supplied - 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") + + set_trait(TRAIT_POTENCY,rand(5,30),200,0) + set_trait(TRAIT_PRODUCT_ICON,pick(plant_controller.plant_product_sprites)) + set_trait(TRAIT_PLANT_ICON,pick(plant_controller.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","plasma","carbon_dioxide") + consume_gasses[gas] = rand(3,9) + + if(prob(5)) + exude_gasses = list() + var/gas = pick("oxygen","nitrogen","plasma","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( + "woodpulp", + "styptic_powder", + "methamphetamine", + "cryoxadone", + "blood", + "water", + "potassium", + "plasticide", + "mutationtoxin", + "amutationtoxin", + "epinephrine", + "space_drugs", + "salglu_solution", + "mercury", + "sugar", + "radium", + "mutadone", + "mannitol", + "thermite", + "sal_acid", + "atropine", + "omnizine", + "salbutamol", + "plasma", + "synaptizine", + "haloperidol", + "potass_iodide", + "mitocholide", + "toxin", + "rezadone", + "antihol", + "slimejelly", + "cyanide", + "lsd", + "morphine" + ) + + 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(25)/25) + 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. + switch(gene.genetype) + if(GENE_BIOCHEMISTRY) + 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(!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) + has_mob_product = gene.values["mob_product"] + gene.values["mob_product"] = null + + 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_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) + 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["mob_product"] = has_mob_product + 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) + if(GENE_STRUCTURE) + traits_to_copy = list(TRAIT_PLANT_ICON,TRAIT_PRODUCT_ICON,TRAIT_HARVEST_REPEAT) + if(GENE_FRUIT) + traits_to_copy = list(TRAIT_STINGS,TRAIT_EXPLOSIVE,TRAIT_JUICY) + if(GENE_SPECIAL) + traits_to_copy = list(TRAIT_TELEPORTING) + + 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 + + if(!force_amount && get_trait(TRAIT_YIELD) == 0 && !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 plant_controller.seeds)) + uid = plant_controller.seeds.len + 1 + name = "[uid]" + plant_controller.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_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) + +// 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 + new_seed.kitchen_tag = kitchen_tag + new_seed.trash_type = trash_type + new_seed.has_mob_product = has_mob_product + //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_trait(TRAIT_PLANT_ICON)) + growth_stages = plant_controller.plant_sprites[get_trait(TRAIT_PLANT_ICON)] + else + growth_stages = 0 diff --git a/code/modules/hydroponics/seed_controller.dm b/code/modules/hydroponics/seed_controller.dm new file mode 100644 index 00000000000..6a329b9d974 --- /dev/null +++ b/code/modules/hydroponics/seed_controller.dm @@ -0,0 +1,150 @@ +// Attempts to offload processing for the spreading plants from the MC. +// Processes vines/spreading plants. + +#define PLANTS_PER_TICK 500 // Cap on number of plant segments processed. +#define PLANT_TICK_TIME 75 // Number of ticks between the plant processor cycling. + +// 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(!plant_controller || !plant_controller.gene_tag_masks) + usr << "Gene masks not set." + return + + for(var/mask in plant_controller.gene_tag_masks) + usr << "[mask]: [plant_controller.gene_tag_masks[mask]]" + +var/global/datum/controller/plants/plant_controller // Set in New(). + +/datum/controller/plants + + var/plants_per_tick = PLANTS_PER_TICK + var/plant_tick_time = PLANT_TICK_TIME + var/list/product_descs = list() // Stores generated fruit descs. + var/list/plant_queue = list() // All queued plants. + var/list/seeds = list() // All seed data stored here. + var/list/gene_tag_masks = list() // Gene obfuscation for delicious trial and error goodness. + var/list/plant_icon_cache = list() // Stores images of growth, fruits and seeds. + var/list/plant_sprites = list() // List of all harvested product sprites. + var/list/plant_product_sprites = list() // List of all growth sprites plus number of growth stages. + //var/processing = 0 // Off/on. + +/datum/controller/plants/New() + if(plant_controller && plant_controller != src) + log_debug("Rebuilding plant controller.") + del(plant_controller) + plant_controller = src + setup() + process() + +// 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. +/datum/controller/plants/proc/setup() + + // 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] 0) return 0 - return pick(mutants) - -//Mutates the plant overall (randomly). -/datum/seed/proc/mutate(var/degree,var/turf/source_turf) - - if(!degree || immutable > 0) return - - source_turf.visible_message("\blue \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;ichanges colour!") - else - source_turf.visible_message("\blue \The [display_name]'s glow dims...") - if(11) - if(prob(degree*2)) - flowers = !flowers - if(flowers) - source_turf.visible_message("\blue \The [display_name] sprouts a bevy of flowers!") - if(prob(degree*2)) - flower_colour = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]" - source_turf.visible_message("\blue \The [display_name]'s flowers changes colour!") - else - source_turf.visible_message("\blue \The [display_name]'s flowers wither and fall off.") - return - -//Mutates a specific trait/set of traits. -/datum/seed/proc/apply_gene(var/datum/plantgene/gene) - - if(!gene || !gene.values || immutable > 0) return - - switch(gene.genetype) - - //Splicing products has some detrimental effects on yield and lifespan. - if("products") - - if(gene.values.len < 6) return - - yield = round(yield*0.5) - endurance = round(endurance*0.5) - lifespan = round(lifespan*0.8) - - if(!products) products = list() - products |= gene.values[1] - - if(!chems) chems = list() - for(var/rid in gene.values[2]) - var/existing_chem - for(var/chem in chems) - if(rid == chem) - existing_chem = 1 - break - - if(existing_chem) - chems[rid][1] = max(1,round((chems[rid][1]+gene.values[2][rid][1])/2)) - chems[rid][2] = max(1,round((chems[rid][2]+gene.values[2][rid][2])/2)) - else - chems[rid] = gene.values[2][rid] - - var/list/new_gasses = gene.values[3] - if(istype(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)) - - alter_temp = gene.values[4] - potency = gene.values[5] - harvest_repeat = gene.values[6] - - if("consumption") - - if(gene.values.len < 7) return - - consume_gasses = gene.values[1] - requires_nutrients = gene.values[2] - nutrient_consumption = gene.values[3] - requires_water = gene.values[4] - water_consumption = gene.values[5] - carnivorous = gene.values[6] - parasite = gene.values[7] - - if("environment") - - if(gene.values.len < 6) return - - ideal_heat = gene.values[1] - heat_tolerance = gene.values[2] - ideal_light = gene.values[3] - light_tolerance = gene.values[4] - lowkpa_tolerance = gene.values[5] - highkpa_tolerance = gene.values[6] - - if("resistance") - - if(gene.values.len < 3) return - - toxins_tolerance = gene.values[1] - pest_tolerance = gene.values[2] - weed_tolerance = gene.values[3] - - if("vigour") - - if(gene.values.len < 6) return - - endurance = gene.values[1] - yield = gene.values[2] - lifespan = gene.values[3] - spread = gene.values[4] - maturation = gene.values[5] - production = gene.values[6] - - if("flowers") - - if(gene.values.len < 7) return - - product_icon = gene.values[1] - product_colour = gene.values[2] - biolum = gene.values[3] - biolum_colour = gene.values[4] - flowers = gene.values[5] - flower_icon = gene.values[6] - flower_colour = gene.values[7] - -//Returns a list of the desired trait values. -/datum/seed/proc/get_gene(var/genetype) - - if(!genetype) return 0 - - var/datum/plantgene/P = new() - P.genetype = genetype - - switch(genetype) - if("products") - P.values = list( - (products ? products : 0), - (chems ? chems : 0), - (exude_gasses ? exude_gasses : 0), - (alter_temp ? alter_temp : 0), - (potency ? potency : 0), - (harvest_repeat ? harvest_repeat : 0) - ) - - if("consumption") - P.values = list( - (consume_gasses ? consume_gasses : 0), - (requires_nutrients ? requires_nutrients : 0), - (nutrient_consumption ? nutrient_consumption : 0), - (requires_water ? requires_water : 0), - (water_consumption ? water_consumption : 0), - (carnivorous ? carnivorous : 0), - (parasite ? parasite : 0) - ) - - if("environment") - P.values = list( - (ideal_heat ? ideal_heat : 0), - (heat_tolerance ? heat_tolerance : 0), - (ideal_light ? ideal_light : 0), - (light_tolerance ? light_tolerance : 0), - (lowkpa_tolerance ? lowkpa_tolerance : 0), - (highkpa_tolerance ? highkpa_tolerance : 0) - ) - - if("resistance") - P.values = list( - (toxins_tolerance ? toxins_tolerance : 0), - (pest_tolerance ? pest_tolerance : 0), - (weed_tolerance ? weed_tolerance : 0) - ) - - if("vigour") - P.values = list( - (endurance ? endurance : 0), - (yield ? yield : 0), - (lifespan ? lifespan : 0), - (spread ? spread : 0), - (maturation ? maturation : 0), - (production ? production : 0) - ) - - if("flowers") - P.values = list( - (product_icon ? product_icon : 0), - (product_colour ? product_colour : 0), - (biolum ? biolum : 0), - (biolum_colour ? biolum_colour : 0), - (flowers ? flowers : 0), - (flower_icon ? flower_icon : 0), - (flower_colour ? flower_colour : 0) - ) - - 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) - if(!user) - return - - var/got_product - if(!isnull(products) && products.len && yield > 0) - got_product = 1 - - if(!got_product) - user << "\red You fail to harvest anything useful." - else - 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 - if(isnull(yield_mod) || yield_mod < 1) - yield_mod = 0 - total_yield = yield - else - total_yield = max(1,rand(yield_mod,yield_mod+yield)) - - currently_querying = list() - 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 - - //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.requires_nutrients = requires_nutrients - new_seed.nutrient_consumption = nutrient_consumption - new_seed.requires_water = requires_water - new_seed.water_consumption = water_consumption - new_seed.ideal_heat = ideal_heat - new_seed.heat_tolerance = heat_tolerance - new_seed.ideal_light = ideal_light - new_seed.light_tolerance = light_tolerance - new_seed.toxins_tolerance = toxins_tolerance - new_seed.lowkpa_tolerance = lowkpa_tolerance - new_seed.highkpa_tolerance = highkpa_tolerance - new_seed.pest_tolerance = pest_tolerance - new_seed.weed_tolerance = weed_tolerance - new_seed.endurance = endurance - new_seed.yield = yield - new_seed.lifespan = lifespan - new_seed.maturation = maturation - new_seed.production = production - new_seed.growth_stages = growth_stages - new_seed.harvest_repeat = harvest_repeat - new_seed.potency = potency - new_seed.spread = spread - new_seed.carnivorous = carnivorous - new_seed.parasite = parasite - new_seed.plant_icon = plant_icon - new_seed.product_icon = product_icon - new_seed.product_colour = product_colour - new_seed.packet_icon = packet_icon - new_seed.biolum = biolum - new_seed.biolum_colour = biolum_colour - new_seed.flowers = flowers - new_seed.flower_icon = flower_icon - new_seed.alter_temp = alter_temp - - return new_seed - -// Actual roundstart seed types after this point. // Chili plants/variants. /datum/seed/chili - name = "chili" seed_name = "chili" display_name = "chili plants" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/chili) chems = list("capsaicin" = list(3,5), "nutriment" = list(1,25)) - mutants = list("icechili", "ghostchili") - packet_icon = "seed-chili" - plant_icon = "chili" - harvest_repeat = 1 + mutants = list("icechili") + kitchen_tag = "chili" - lifespan = 20 - maturation = 5 - production = 5 - yield = 4 - potency = 20 +/datum/seed/chili/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,20) + set_trait(TRAIT_PRODUCT_ICON,"chili") + set_trait(TRAIT_PRODUCT_COLOUR,"#ED3300") + set_trait(TRAIT_PLANT_ICON,"bush2") /datum/seed/chili/ice name = "icechili" seed_name = "ice pepper" display_name = "ice-pepper plants" mutants = null - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/icepepper) chems = list("frostoil" = list(3,5), "nutriment" = list(1,50)) - packet_icon = "seed-icepepper" - plant_icon = "chiliice" + kitchen_tag = "icechili" - maturation = 4 - production = 4 - -/datum/seed/chili/ghost - name = "ghostchili" - seed_name = "ghost chili pepper" - display_name = "ghost chili pepper plants" - mutants = null - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/ghost_chilli) - chems = list("capsaicin" = list(8,2), "condensedcapsaicin" = list(4,4), "nutriment" = list(1,25)) - packet_icon = "seed-chilighost" - plant_icon = "chilighost" - growth_stages = 6 - - maturation = 10 - production = 10 - yield = 3 +/datum/seed/chili/ice/New() + ..() + set_trait(TRAIT_MATURATION,4) + set_trait(TRAIT_PRODUCTION,4) + set_trait(TRAIT_PRODUCT_COLOUR,"#00EDC6") // Berry plants/variants. /datum/seed/berry name = "berries" seed_name = "berry" display_name = "berry bush" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/berries) mutants = list("glowberries","poisonberries") - packet_icon = "seed-berry" - plant_icon = "berry" - harvest_repeat = 1 chems = list("nutriment" = list(1,10)) + kitchen_tag = "berries" - lifespan = 20 - maturation = 5 - production = 5 - yield = 2 - potency = 10 +/datum/seed/berry/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_JUICY,1) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"berry") + set_trait(TRAIT_PRODUCT_COLOUR,"#FA1616") + set_trait(TRAIT_PLANT_ICON,"bush") /datum/seed/berry/glow name = "glowberries" seed_name = "glowberry" display_name = "glowberry bush" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/glowberries) mutants = null - packet_icon = "seed-glowberry" - plant_icon = "glowberry" chems = list("nutriment" = list(1,10), "uranium" = list(3,5)) - lifespan = 30 - maturation = 5 - production = 5 - yield = 2 - potency = 10 +/datum/seed/berry/glow/New() + ..() + set_trait(TRAIT_SPREAD,1) + set_trait(TRAIT_BIOLUM,1) + set_trait(TRAIT_BIOLUM_COLOUR,"#006622") + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_COLOUR,"c9fa16") /datum/seed/berry/poison name = "poisonberries" seed_name = "poison berry" display_name = "poison berry bush" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/poisonberries) mutants = list("deathberries") - packet_icon = "seed-poisonberry" - plant_icon = "poisonberry" chems = list("nutriment" = list(1), "toxin" = list(3,5)) + kitchen_tag = "poisonberries" + +/datum/seed/berry/poison/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#6DC961") /datum/seed/berry/poison/death name = "deathberries" seed_name = "death berry" display_name = "death berry bush" mutants = null - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/deathberries) - packet_icon = "seed-deathberry" - plant_icon = "deathberry" chems = list("nutriment" = list(1), "toxin" = list(3,3), "lexorin" = list(1,5)) - yield = 3 - potency = 50 +/datum/seed/berry/poison/death/New() + ..() + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,50) + set_trait(TRAIT_PRODUCT_COLOUR,"#7A5454") // Nettles/variants. /datum/seed/nettle name = "nettle" seed_name = "nettle" display_name = "nettles" - products = list(/obj/item/weapon/grown/nettle) mutants = list("deathnettle") - packet_icon = "seed-nettle" - plant_icon = "nettle" - harvest_repeat = 1 chems = list("nutriment" = list(1,50), "sacid" = list(0,1)) - lifespan = 30 - maturation = 6 - production = 6 - yield = 4 - potency = 10 - growth_stages = 5 + kitchen_tag = "nettle" + +/datum/seed/nettle/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_STINGS,1) + set_trait(TRAIT_PLANT_ICON,"bush5") + set_trait(TRAIT_PRODUCT_ICON,"nettles") + set_trait(TRAIT_PRODUCT_COLOUR,"#728A54") /datum/seed/nettle/death name = "deathnettle" seed_name = "death nettle" display_name = "death nettles" - products = list(/obj/item/weapon/grown/deathnettle) mutants = null - packet_icon = "seed-deathnettle" - plant_icon = "deathnettle" chems = list("nutriment" = list(1,50), "facid" = list(0,1)) + kitchen_tag = "deathnettle" - maturation = 8 - yield = 2 +/datum/seed/nettle/death/New() + ..() + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_PRODUCT_COLOUR,"#8C5030") + set_trait(TRAIT_PLANT_COLOUR,"#634941") //Tomatoes/variants. /datum/seed/tomato name = "tomato" seed_name = "tomato" display_name = "tomato plant" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/tomato) mutants = list("bluetomato","bloodtomato") - packet_icon = "seed-tomato" - plant_icon = "tomato" - harvest_repeat = 1 chems = list("nutriment" = list(1,10)) + kitchen_tag = "tomato" - lifespan = 25 - maturation = 8 - production = 6 - yield = 2 - potency = 10 +/datum/seed/tomato/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_JUICY,1) + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"tomato") + set_trait(TRAIT_PRODUCT_COLOUR,"#D10000") + set_trait(TRAIT_PLANT_ICON,"bush3") /datum/seed/tomato/blood name = "bloodtomato" seed_name = "blood tomato" display_name = "blood tomato plant" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/bloodtomato) - mutants = list("killertomato") - packet_icon = "seed-bloodtomato" - plant_icon = "bloodtomato" + mutants = list("killer") chems = list("nutriment" = list(1,10), "blood" = list(1,5)) + splat_type = /obj/effect/decal/cleanable/blood/splatter + kitchen_tag = "bloodtomato" - yield = 3 +/datum/seed/tomato/blood/New() + ..() + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_PRODUCT_COLOUR,"#FF0000") /datum/seed/tomato/killer name = "killertomato" seed_name = "killer tomato" display_name = "killer tomato plant" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/killertomato) mutants = null - packet_icon = "seed-killertomato" - plant_icon = "killertomato" + can_self_harvest = 1 + has_mob_product = /mob/living/simple_animal/tomato - yield = 2 - growth_stages = 2 +/datum/seed/tomato/killer/New() + ..() + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_PRODUCT_COLOUR,"#A86747") /datum/seed/tomato/blue name = "bluetomato" seed_name = "blue tomato" display_name = "blue tomato plant" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/bluetomato) mutants = list("bluespacetomato") - packet_icon = "seed-bluetomato" - plant_icon = "bluetomato" chems = list("nutriment" = list(1,20), "lube" = list(1,5)) +/datum/seed/tomato/blue/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#4D86E8") + set_trait(TRAIT_PLANT_COLOUR,"#070AAD") + /datum/seed/tomato/blue/teleport name = "bluespacetomato" seed_name = "bluespace tomato" display_name = "bluespace tomato plant" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/bluespacetomato) mutants = null - packet_icon = "seed-bluespacetomato" - plant_icon = "bluespacetomato" - chems = list("nutriment" = list(1,20), "singulo" = list(1,5)) + chems = list("nutriment" = list(1,20), "singulo" = list(10,5)) + +/datum/seed/tomato/blue/teleport/New() + ..() + set_trait(TRAIT_TELEPORTING,1) + set_trait(TRAIT_PRODUCT_COLOUR,"#00E5FF") + set_trait(TRAIT_BIOLUM,1) + set_trait(TRAIT_BIOLUM_COLOUR,"#4DA4A8") //Eggplants/varieties. /datum/seed/eggplant name = "eggplant" seed_name = "eggplant" display_name = "eggplants" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/eggplant) mutants = list("realeggplant") - packet_icon = "seed-eggplant" - plant_icon = "eggplant" - harvest_repeat = 1 chems = list("nutriment" = list(1,10)) + kitchen_tag = "eggplant" - lifespan = 25 - maturation = 6 - production = 6 - yield = 2 - potency = 20 - -/datum/seed/eggplant/eggs - name = "realeggplant" - seed_name = "egg-plant" - display_name = "egg-plants" - products = list(/obj/item/weapon/reagent_containers/food/snacks/egg) - mutants = null - packet_icon = "seed-eggy" - plant_icon = "eggy" - - lifespan = 75 - production = 12 +/datum/seed/eggplant/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,20) + set_trait(TRAIT_PRODUCT_ICON,"eggplant") + set_trait(TRAIT_PRODUCT_COLOUR,"#892694") + set_trait(TRAIT_PLANT_ICON,"bush4") //Apples/varieties. - /datum/seed/apple name = "apple" seed_name = "apple" display_name = "apple tree" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/apple) mutants = list("poisonapple","goldapple") - packet_icon = "seed-apple" - plant_icon = "apple" - harvest_repeat = 1 chems = list("nutriment" = list(1,10)) + kitchen_tag = "apple" - lifespan = 55 - maturation = 6 - production = 6 - yield = 5 - potency = 10 +/datum/seed/apple/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"apple") + set_trait(TRAIT_PRODUCT_COLOUR,"#FF540A") + set_trait(TRAIT_PLANT_ICON,"tree2") /datum/seed/apple/poison name = "poisonapple" mutants = null - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/apple/poisoned) chems = list("cyanide" = list(1,5)) /datum/seed/apple/gold name = "goldapple" seed_name = "golden apple" display_name = "gold apple tree" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/goldapple) mutants = null - packet_icon = "seed-goldapple" - plant_icon = "goldapple" chems = list("nutriment" = list(1,10), "gold" = list(1,5)) + kitchen_tag = "goldapple" - maturation = 10 - production = 10 - yield = 3 +/datum/seed/apple/gold/New() + ..() + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,10) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_PRODUCT_COLOUR,"#FFDD00") + set_trait(TRAIT_PLANT_COLOUR,"#D6B44D") //Ambrosia/varieties. /datum/seed/ambrosia name = "ambrosia" seed_name = "ambrosia vulgaris" display_name = "ambrosia vulgaris" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiavulgaris) mutants = list("ambrosiadeus") - packet_icon = "seed-ambrosiavulgaris" - plant_icon = "ambrosiavulgaris" - harvest_repeat = 1 chems = list("nutriment" = list(1), "thc" = list(1,8), "silver_sulfadiazine" = list(1,8,1), "styptic_powder" = list(1,10,1), "toxin" = list(1,10)) + kitchen_tag = "ambrosia" - lifespan = 60 - maturation = 6 - production = 6 - yield = 6 - potency = 5 +/datum/seed/ambrosia/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_POTENCY,5) + set_trait(TRAIT_PRODUCT_ICON,"ambrosia") + set_trait(TRAIT_PRODUCT_COLOUR,"#9FAD55") + set_trait(TRAIT_PLANT_ICON,"ambrosia") /datum/seed/ambrosia/deus name = "ambrosiadeus" seed_name = "ambrosia deus" display_name = "ambrosia deus" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiadeus) mutants = null - packet_icon = "seed-ambrosiadeus" - plant_icon = "ambrosiadeus" chems = list("nutriment" = list(1), "styptic_powder" = list(1,8), "synaptizine" = list(1,8,1), "methamphetamine" = list(1,10,1), "thc" = list(1,10)) + kitchen_tag = "ambrosiadeus" + +//Tobacco/varieties +/datum/seed/tobacco + name = "tobacco" + seed_name = "tobacco" + display_name = "tobacco" + mutants = list("stobacco") + chems = list("nutriment" = list(1,40), "nicotine" = list(1,40)) + kitchen_tag = "tobacco" + +/datum/seed/tobacco/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"leaf") + set_trait(TRAIT_PRODUCT_COLOUR,"#9FAD55") + set_trait(TRAIT_PLANT_ICON,"bush7") + +/datum/seed/tobacco/space + name = "stobacco" + seed_name = "space tobacco" + display_name = "space tobacco" + mutants = null + chems = list("nutriment" = list(1,40), "nicotine" = list(1,20), "epinephrine" = list(1,30)) + kitchen_tag = "stobacco" + +/datum/seed/tobacco/space/New() + ..() + set_trait(TRAIT_YIELD, 4) + set_trait(TRAIT_POTENCY, 5) + set_trait(TRAIT_PRODUCT_COLOUR,"#A3F0AD") + set_trait(TRAIT_PLANT_COLOUR,"#2A9C61") + +//Tea/varieties +/datum/seed/teaaspera + name = "teaaspera" + seed_name = "tea aspera" + display_name = "tea aspera" + mutants = list("teaastra") + chems = list("teapowder" = list(1,20), "charcoal" = list(1,30)) + +/datum/seed/teaaspera/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"leaf2") + set_trait(TRAIT_PRODUCT_COLOUR,"#9FAD55") + set_trait(TRAIT_PLANT_ICON,"tree6") + +/datum/seed/teaastra + name = "teaastra" + seed_name = "tea astra" + display_name = "tea astra" + chems = list("teapowder" = list(1,20), "haloperidol" = list(1,30)) + +/datum/seed/teaastra/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"leaf2") + set_trait(TRAIT_PRODUCT_COLOUR,"#A3F0AD") + set_trait(TRAIT_PLANT_COLOUR,"#2A9C61") + set_trait(TRAIT_PLANT_ICON,"tree6") + +//Coffee/varieties +/datum/seed/coffeea + name = "coffeea" + seed_name = "coffee arabica" + display_name = "coffee arabica" + mutants = list("coffeer") + chems = list("coffeepowder" = list(1,20), "synaptizine" = list(1,40)) + kitchen_tag = "coffeea" + +/datum/seed/coffeea/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"coffee") + set_trait(TRAIT_PRODUCT_COLOUR,"#ED0000") + set_trait(TRAIT_PLANT_ICON,"bush8") + +/datum/seed/coffeer + name = "coffeer" + seed_name = "coffee robusta" + display_name = "coffee robusta" + chems = list("coffeepowder" = list(1,20), "synaptizine" = list(1,20), "methamphetamine" = list(1,40)) + kitchen_tag = "coffeer" + +/datum/seed/coffeer/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"coffee") + set_trait(TRAIT_PRODUCT_COLOUR,"#A22043") + set_trait(TRAIT_PLANT_ICON,"bush8") //Mushrooms/varieties. /datum/seed/mushroom @@ -758,824 +411,841 @@ proc/populate_seed_list() seed_name = "chanterelle" seed_noun = "spores" display_name = "chanterelle mushrooms" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/chanterelle) mutants = list("reishi","amanita","plumphelmet") - packet_icon = "mycelium-chanter" - plant_icon = "chanter" chems = list("nutriment" = list(1,25), "fungus" = list(1,10)) + splat_type = /obj/effect/plant + kitchen_tag = "mushroom" - lifespan = 35 - maturation = 7 - production = 1 - yield = 5 - potency = 1 - growth_stages = 3 +/datum/seed/mushroom/New() + ..() + set_trait(TRAIT_MATURATION,7) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_POTENCY,1) + set_trait(TRAIT_PRODUCT_ICON,"mushroom4") + set_trait(TRAIT_PRODUCT_COLOUR,"#DBDA72") + set_trait(TRAIT_PLANT_COLOUR,"#D9C94E") + set_trait(TRAIT_PLANT_ICON,"mushroom") /datum/seed/mushroom/mold name = "mold" seed_name = "brown mold" display_name = "brown mold" - products = null mutants = null - //mutants = list("wallrot") //TBD. - plant_icon = "mold" - lifespan = 50 - maturation = 10 - yield = -1 +/datum/seed/mushroom/mold/New() + ..() + set_trait(TRAIT_SPREAD,1) + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_YIELD,-1) + set_trait(TRAIT_PRODUCT_ICON,"mushroom5") + set_trait(TRAIT_PRODUCT_COLOUR,"#7A5F20") + set_trait(TRAIT_PLANT_COLOUR,"#7A5F20") + set_trait(TRAIT_PLANT_ICON,"mushroom9") /datum/seed/mushroom/plump name = "plumphelmet" seed_name = "plump helmet" display_name = "plump helmet mushrooms" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/plumphelmet) mutants = list("walkingmushroom","towercap") - packet_icon = "mycelium-plump" - plant_icon = "plump" chems = list("nutriment" = list(2,10)) + kitchen_tag = "plumphelmet" - lifespan = 25 - maturation = 8 - yield = 4 - potency = 0 +/datum/seed/mushroom/plump/New() + ..() + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,0) + set_trait(TRAIT_PRODUCT_ICON,"mushroom10") + set_trait(TRAIT_PRODUCT_COLOUR,"#B57BB0") + set_trait(TRAIT_PLANT_COLOUR,"#9E4F9D") + set_trait(TRAIT_PLANT_ICON,"mushroom2") + +/datum/seed/mushroom/plump/walking + name = "walkingmushroom" + seed_name = "walking mushroom" + display_name = "walking mushrooms" + mutants = null + can_self_harvest = 1 + has_mob_product = /mob/living/simple_animal/hostile/mushroom + +/datum/seed/mushroom/plump/walking/New() + ..() + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_YIELD,1) + set_trait(TRAIT_PRODUCT_COLOUR,"#FAC0F2") + set_trait(TRAIT_PLANT_COLOUR,"#C4B1C2") /datum/seed/mushroom/hallucinogenic name = "reishi" seed_name = "reishi" display_name = "reishi" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/reishi) mutants = list("libertycap","glowshroom") - packet_icon = "mycelium-reishi" - plant_icon = "reishi" chems = list("nutriment" = list(1,50), "psilocybin" = list(3,5)) - maturation = 10 - production = 5 - yield = 4 - potency = 15 - growth_stages = 4 +/datum/seed/mushroom/hallucinogenic/New() + ..() + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,15) + set_trait(TRAIT_PRODUCT_ICON,"mushroom11") + set_trait(TRAIT_PRODUCT_COLOUR,"#FFB70F") + set_trait(TRAIT_PLANT_COLOUR,"#F58A18") + set_trait(TRAIT_PLANT_ICON,"mushroom6") /datum/seed/mushroom/hallucinogenic/strong name = "libertycap" seed_name = "liberty cap" display_name = "liberty cap mushrooms" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/libertycap) mutants = null - packet_icon = "mycelium-liberty" - plant_icon = "liberty" chems = list("nutriment" = list(1), "morphine" = list(3,3), "space_drugs" = list(1,25)) + kitchen_tag = "libertycap" - lifespan = 25 - production = 1 - potency = 15 - growth_stages = 3 +/datum/seed/mushroom/hallucinogenic/strong/New() + ..() + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_POTENCY,15) + set_trait(TRAIT_PRODUCT_ICON,"mushroom8") + set_trait(TRAIT_PRODUCT_COLOUR,"#F2E550") + set_trait(TRAIT_PLANT_COLOUR,"#D1CA82") + set_trait(TRAIT_PLANT_ICON,"mushroom3") /datum/seed/mushroom/poison name = "amanita" seed_name = "fly amanita" display_name = "fly amanita mushrooms" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/amanita) mutants = list("destroyingangel","plastic") - packet_icon = "mycelium-amanita" - plant_icon = "amanita" chems = list("nutriment" = list(1), "amanitin" = list(3,3), "psilocybin" = list(1,25)) + kitchen_tag = "amanita" - lifespan = 50 - maturation = 10 - production = 5 - yield = 4 - potency = 10 +/datum/seed/mushroom/poison/New() + ..() + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"mushroom") + set_trait(TRAIT_PRODUCT_COLOUR,"#FF4545") + set_trait(TRAIT_PLANT_COLOUR,"#E0DDBA") + set_trait(TRAIT_PLANT_ICON,"mushroom4") /datum/seed/mushroom/poison/death name = "destroyingangel" seed_name = "destroying angel" display_name = "destroying angel mushrooms" mutants = null - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/angel) - packet_icon = "mycelium-angel" - plant_icon = "angel" chems = list("nutriment" = list(1,50), "amanitin" = list(13,3), "psilocybin" = list(1,25)) - maturation = 12 - yield = 2 - potency = 35 +/datum/seed/mushroom/poison/death/New() + ..() + set_trait(TRAIT_MATURATION,12) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,35) + set_trait(TRAIT_PRODUCT_ICON,"mushroom3") + set_trait(TRAIT_PRODUCT_COLOUR,"#EDE8EA") + set_trait(TRAIT_PLANT_COLOUR,"#E6D8DD") + set_trait(TRAIT_PLANT_ICON,"mushroom5") /datum/seed/mushroom/towercap name = "towercap" seed_name = "tower cap" display_name = "tower caps" + chems = list("woodpulp" = list(10,1)) mutants = null - products = list(/obj/item/weapon/grown/log) - packet_icon = "mycelium-tower" - plant_icon = "towercap" - lifespan = 80 - maturation = 15 +/datum/seed/mushroom/towercap/New() + ..() + set_trait(TRAIT_MATURATION,15) + set_trait(TRAIT_PRODUCT_ICON,"mushroom7") + set_trait(TRAIT_PRODUCT_COLOUR,"#79A36D") + set_trait(TRAIT_PLANT_COLOUR,"#857F41") + set_trait(TRAIT_PLANT_ICON,"mushroom8") /datum/seed/mushroom/glowshroom name = "glowshroom" seed_name = "glowshroom" display_name = "glowshrooms" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/glowshroom) mutants = null - packet_icon = "mycelium-glowshroom" - plant_icon = "glowshroom" chems = list("radium" = list(1,20)) - lifespan = 120 - maturation = 15 - yield = 3 - potency = 30 - growth_stages = 4 - biolum = 1 - biolum_colour = "#006622" - -/datum/seed/mushroom/walking - name = "walkingmushroom" - seed_name = "walking mushroom" - display_name = "walking mushrooms" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/mushroom/walkingmushroom) - mutants = null - packet_icon = "mycelium-walkingmushroom" - plant_icon = "walkingmushroom" - chems = list("nutriment" = list(2,10)) - - lifespan = 30 - maturation = 5 - yield = 1 - potency = 0 - growth_stages = 3 +/datum/seed/mushroom/glowshroom/New() + ..() + set_trait(TRAIT_SPREAD,1) + set_trait(TRAIT_MATURATION,15) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,30) + set_trait(TRAIT_BIOLUM,1) + set_trait(TRAIT_BIOLUM_COLOUR,"#006622") + set_trait(TRAIT_PRODUCT_ICON,"mushroom2") + set_trait(TRAIT_PRODUCT_COLOUR,"#DDFAB6") + set_trait(TRAIT_PLANT_COLOUR,"#EFFF8A") + set_trait(TRAIT_PLANT_ICON,"mushroom7") /datum/seed/mushroom/plastic name = "plastic" seed_name = "plastellium" display_name = "plastellium" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/plastellium) mutants = null - packet_icon = "mycelium-plast" - plant_icon = "plastellium" chems = list("plasticide" = list(1,10)) - lifespan = 15 - maturation = 5 - production = 6 - yield = 6 - potency = 20 +/datum/seed/mushroom/plastic/New() + ..() + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_POTENCY,20) + set_trait(TRAIT_PRODUCT_ICON,"mushroom6") + set_trait(TRAIT_PRODUCT_COLOUR,"#E6E6E6") + set_trait(TRAIT_PLANT_COLOUR,"#E6E6E6") + set_trait(TRAIT_PLANT_ICON,"mushroom10") //Flowers/varieties /datum/seed/flower name = "harebells" seed_name = "harebell" display_name = "harebells" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/harebell) - packet_icon = "seed-harebell" - plant_icon = "harebell" chems = list("nutriment" = list(1,20)) - lifespan = 100 - maturation = 7 - production = 1 - yield = 2 - growth_stages = 4 +/datum/seed/flower/New() + ..() + set_trait(TRAIT_MATURATION,7) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_PRODUCT_ICON,"flower5") + set_trait(TRAIT_PRODUCT_COLOUR,"#C492D6") + set_trait(TRAIT_PLANT_COLOUR,"#6B8C5E") + set_trait(TRAIT_PLANT_ICON,"flower") /datum/seed/flower/poppy name = "poppies" seed_name = "poppy" display_name = "poppies" - packet_icon = "seed-poppy" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/poppy) - plant_icon = "poppy" chems = list("nutriment" = list(1,20), "styptic_powder" = list(1,10)) + kitchen_tag = "poppy" - lifespan = 25 - potency = 20 - maturation = 8 - production = 6 - yield = 6 - growth_stages = 3 +/datum/seed/flower/poppy/New() + ..() + set_trait(TRAIT_POTENCY,20) + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_PRODUCT_ICON,"flower3") + set_trait(TRAIT_PRODUCT_COLOUR,"#B33715") + set_trait(TRAIT_PLANT_ICON,"flower3") /datum/seed/flower/sunflower name = "sunflowers" seed_name = "sunflower" display_name = "sunflowers" - packet_icon = "seed-sunflower" - mutants = list("moonflower", "novaflower") - products = list(/obj/item/weapon/grown/sunflower) - plant_icon = "sunflower" - lifespan = 25 - maturation = 6 - growth_stages = 3 - -/datum/seed/flower/moonflower - name = "moonflowers" - seed_name = "moonflower" - display_name = "moonflowers" - packet_icon = "seed-moonflower" - mutants = null - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/moonflower) - plant_icon = "moonflower" - chems = list("nutriment" = list(1,50), "moonshine" = list(1,10)) - - lifespan = 25 - maturation = 6 - growth_stages = 3 - -/datum/seed/flower/novaflower - name = "novaflowers" - seed_name = "novaflower" - display_name = "novaflowers" - packet_icon = "seed-novaflower" - mutants = null - products = list(/obj/item/weapon/grown/novaflower) - plant_icon = "novaflower" - - lifespan = 25 - maturation = 6 - growth_stages = 3 +/datum/seed/flower/sunflower/New() + ..() + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCT_ICON,"flower2") + set_trait(TRAIT_PRODUCT_COLOUR,"#FFF700") + set_trait(TRAIT_PLANT_ICON,"flower2") //Grapes/varieties /datum/seed/grapes name = "grapes" seed_name = "grape" display_name = "grapevines" - packet_icon = "seed-grapes" mutants = list("greengrapes") - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/grapes) - plant_icon = "grape" - harvest_repeat = 1 chems = list("nutriment" = list(1,10), "sugar" = list(1,5)) - lifespan = 50 - maturation = 3 - production = 5 - yield = 4 - potency = 10 +/datum/seed/grapes/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"grapes") + set_trait(TRAIT_PRODUCT_COLOUR,"#BB6AC4") + set_trait(TRAIT_PLANT_COLOUR,"#378F2E") + set_trait(TRAIT_PLANT_ICON,"vine") /datum/seed/grapes/green name = "greengrapes" seed_name = "green grape" display_name = "green grapevines" - packet_icon = "seed-greengrapes" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/greengrapes) mutants = null - plant_icon = "greengrape" - chems = list("nutriment" = list(1,10)) + chems = list("nutriment" = list(1,10), "silver_sulfadiazine" = list(3,5)) -//Soybeans/varieties -/datum/seed/soybean - name = "soybean" - seed_name = "soybean" - display_name = "soybeans" - packet_icon = "seed-soybean" - mutants = list("koibean") - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/soybeans) - plant_icon = "soybean" - harvest_repeat = 1 - chems = list("nutriment" = list(1,20), "soybeanoil" = list(1,20)) - - lifespan = 25 - maturation = 4 - production = 4 - yield = 3 - potency = 5 - -/datum/seed/soybean/koi - name = "koibean" - seed_name = "koibean" - display_name = "koi beans" - packet_icon = "seed-koibean" - mutants = null - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/koibeans) - plant_icon = "soybean" - harvest_repeat = 1 - chems = list("nutriment" = list(1,30), "carpotoxin" = list(1,20)) - - lifespan = 25 - maturation = 4 - production = 4 - yield = 3 - potency = 5 - -//Tobacco/varieties -/datum/seed/tobacco - name = "tobacco" - seed_name = "tobacco" - display_name = "tobacco" - packet_icon = "seed-tobacco" - mutants = list("stobacco") - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/tobacco) - plant_icon = "tobacco" - harvest_repeat = 1 - chems = list("nutriment" = list(1,40), "nicotine" = list(1,40)) - - lifespan = 25 - maturation = 5 - production = 5 - yield = 6 - potency = 10 - growth_stages = 3 - -/datum/seed/tobacco/space - name = "stobacco" - seed_name = "space tobacco" - display_name = "space tobacco" - packet_icon = "seed-stobacco" - mutants = null - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/tobacco/space) - plant_icon = "stobacco" - harvest_repeat = 1 - chems = list("nutriment" = list(1,40), "nicotine" = list(1,20), "epinephrine" = list(1,30)) - - lifespan = 25 - maturation = 5 - production = 5 - yield = 4 - potency = 5 - growth_stages = 3 - -//Tea/varieties -/datum/seed/teaaspera - name = "teaaspera" - seed_name = "tea aspera" - display_name = "tea aspera" - packet_icon = "seed-teaaspera" - mutants = list("teaastra") - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/teaaspera) - plant_icon = "teaaspera" - harvest_repeat = 1 - chems = list("teapowder" = list(1,20), "charcoal" = list(1,30)) - - lifespan = 30 - maturation = 5 - production = 5 - yield = 6 - potency = 10 - growth_stages = 5 - -/datum/seed/teaastra - name = "teaastra" - seed_name = "tea astra" - display_name = "tea astra" - packet_icon = "seed-teaastra" - mutants = null - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/teaastra) - plant_icon = "teaastra" - harvest_repeat = 1 - chems = list("teapowder" = list(1,20), "haloperidol" = list(1,30)) - - lifespan = 30 - maturation = 5 - production = 5 - yield = 6 - potency = 10 - growth_stages = 5 - -//Coffee/varieties -/datum/seed/coffeea - name = "coffeea" - seed_name = "coffee arabica" - display_name = "coffee arabica" - packet_icon = "seed-coffeea" - mutants = list("coffeer") - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/coffeea) - plant_icon = "coffeea" - harvest_repeat = 1 - chems = list("coffeepowder" = list(1,20), "synaptizine" = list(1,40)) - - lifespan = 30 - maturation = 5 - production = 5 - yield = 6 - potency = 10 - growth_stages = 5 - -/datum/seed/coffeer - name = "coffeer" - seed_name = "coffee robusta" - display_name = "coffee robusta" - mutants = null - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/coffeer) - plant_icon = "coffeer" - harvest_repeat = 1 - chems = list("coffeepowder" = list(1,20), "synaptizine" = list(1,20), "methamphetamine" = list(1,40)) - - lifespan = 30 - maturation = 5 - production = 5 - yield = 4 - potency = 10 - growth_stages = 5 +/datum/seed/grapes/green/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"42ed2f") //Everything else /datum/seed/peanuts name = "peanut" seed_name = "peanut" display_name = "peanut vines" - packet_icon = "seed-peanut" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/peanut) - plant_icon = "peanut" - harvest_repeat = 1 chems = list("nutriment" = list(1,10)) - lifespan = 55 - maturation = 6 - production = 6 - yield = 6 - potency = 10 +/datum/seed/peanuts/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"potato") + set_trait(TRAIT_PRODUCT_COLOUR,"#C4AE7A") + set_trait(TRAIT_PLANT_ICON,"bush2") /datum/seed/cabbage name = "cabbage" seed_name = "cabbage" display_name = "cabbages" - packet_icon = "seed-cabbage" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/cabbage) - plant_icon = "cabbage" - harvest_repeat = 1 chems = list("nutriment" = list(1,10)) + kitchen_tag = "cabbage" - lifespan = 50 - maturation = 3 - production = 5 - yield = 4 - potency = 10 - growth_stages = 1 - -/datum/seed/shand - name = "shand" - seed_name = "S'randar's hand" - display_name = "S'randar's hand leaves" - packet_icon = "seed-shand" - products = list(/obj/item/stack/medical/bruise_pack/tajaran) - plant_icon = "shand" - chems = list("styptic_powder" = list(0,10)) - - lifespan = 50 - maturation = 3 - production = 5 - yield = 4 - potency = 10 - growth_stages = 3 - -/datum/seed/mtear - name = "mtear" - seed_name = "Messa's tear" - display_name = "Messa's tear leaves" - packet_icon = "seed-mtear" - products = list(/obj/item/stack/medical/ointment/tajaran) - plant_icon = "mtear" - chems = list("honey" = list(1,10), "silver_sulfadiazine" = list(3,5)) - - lifespan = 50 - maturation = 3 - production = 5 - yield = 4 - potency = 10 - growth_stages = 3 +/datum/seed/cabbage/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"cabbage") + set_trait(TRAIT_PRODUCT_COLOUR,"#84BD82") + set_trait(TRAIT_PLANT_COLOUR,"#6D9C6B") + set_trait(TRAIT_PLANT_ICON,"vine2") /datum/seed/banana name = "banana" seed_name = "banana" display_name = "banana tree" - packet_icon = "seed-banana" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/banana) - plant_icon = "banana" - harvest_repeat = 1 - chems = list("banana" = list(1,10)) + chems = list("banana" = list(10,10)) + trash_type = /obj/item/weapon/bananapeel + kitchen_tag = "banana" - lifespan = 50 - maturation = 6 - production = 6 - yield = 3 +/datum/seed/banana/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_PRODUCT_ICON,"bananas") + set_trait(TRAIT_PRODUCT_COLOUR,"#FFEC1F") + set_trait(TRAIT_PLANT_COLOUR,"#69AD50") + set_trait(TRAIT_PLANT_ICON,"tree4") /datum/seed/corn name = "corn" seed_name = "corn" display_name = "ears of corn" - packet_icon = "seed-corn" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/corn) - plant_icon = "corn" chems = list("nutriment" = list(1,10), "corn_starch" = list(3,5)) + kitchen_tag = "corn" + trash_type = /obj/item/weapon/corncob - lifespan = 25 - maturation = 8 - production = 6 - yield = 3 - potency = 20 - growth_stages = 3 +/datum/seed/corn/New() + ..() + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,20) + set_trait(TRAIT_PRODUCT_ICON,"corn") + set_trait(TRAIT_PRODUCT_COLOUR,"#FFF23B") + set_trait(TRAIT_PLANT_COLOUR,"#87C969") + set_trait(TRAIT_PLANT_ICON,"corn") /datum/seed/potato name = "potato" seed_name = "potato" display_name = "potatoes" - packet_icon = "seed-potato" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/potato) - plant_icon = "potato" chems = list("nutriment" = list(1,10)) + kitchen_tag = "potato" - lifespan = 30 - maturation = 10 - production = 1 - yield = 4 - potency = 10 - growth_stages = 4 +/datum/seed/potato/New() + ..() + set_trait(TRAIT_PRODUCES_POWER,1) + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"potato") + set_trait(TRAIT_PRODUCT_COLOUR,"#D4CAB4") + set_trait(TRAIT_PLANT_ICON,"bush2") + +/datum/seed/soybean + name = "soybean" + seed_name = "soybean" + display_name = "soybeans" + chems = list("nutriment" = list(1,20), "soybeanoil" = list(1,20)) + kitchen_tag = "soybeans" + +/datum/seed/soybean/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,4) + set_trait(TRAIT_PRODUCTION,4) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,5) + set_trait(TRAIT_PRODUCT_ICON,"bean") + set_trait(TRAIT_PRODUCT_COLOUR,"#EBE7C0") + set_trait(TRAIT_PLANT_ICON,"stalk") /datum/seed/wheat name = "wheat" seed_name = "wheat" display_name = "wheat stalks" - packet_icon = "seed-wheat" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/wheat) - plant_icon = "wheat" chems = list("nutriment" = list(1,25)) + kitchen_tag = "wheat" - lifespan = 25 - maturation = 6 - production = 1 - yield = 4 - potency = 5 +/datum/seed/wheat/New() + ..() + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,5) + set_trait(TRAIT_PRODUCT_ICON,"wheat") + set_trait(TRAIT_PRODUCT_COLOUR,"#DBD37D") + set_trait(TRAIT_PLANT_COLOUR,"#BFAF82") + set_trait(TRAIT_PLANT_ICON,"stalk2") /datum/seed/rice name = "rice" seed_name = "rice" display_name = "rice stalks" - packet_icon = "seed-rice" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/ricestalk) - plant_icon = "rice" chems = list("nutriment" = list(1,25)) + kitchen_tag = "rice" - lifespan = 25 - maturation = 6 - production = 1 - yield = 4 - potency = 5 - growth_stages = 4 +/datum/seed/rice/New() + ..() + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,5) + set_trait(TRAIT_PRODUCT_ICON,"rice") + set_trait(TRAIT_PRODUCT_COLOUR,"#D5E6D1") + set_trait(TRAIT_PLANT_COLOUR,"#8ED17D") + set_trait(TRAIT_PLANT_ICON,"stalk2") /datum/seed/carrots name = "carrot" seed_name = "carrot" display_name = "carrots" - packet_icon = "seed-carrot" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/carrot) - plant_icon = "carrot" chems = list("nutriment" = list(1,20), "oculine" = list(3,5)) + kitchen_tag = "carrot" - lifespan = 25 - maturation = 10 - production = 1 - yield = 5 - potency = 10 - growth_stages = 3 +/datum/seed/carrots/New() + ..() + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"carrot") + set_trait(TRAIT_PRODUCT_COLOUR,"#FFDB4A") + set_trait(TRAIT_PLANT_ICON,"carrot") /datum/seed/weeds name = "weeds" seed_name = "weed" display_name = "weeds" - packet_icon = "seed-ambrosiavulgaris" - plant_icon = "weeds" - lifespan = 100 - maturation = 5 - production = 1 - yield = -1 - potency = -1 - growth_stages = 4 - immutable = -1 +/datum/seed/weeds/New() + ..() + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,-1) + set_trait(TRAIT_POTENCY,-1) + set_trait(TRAIT_IMMUTABLE,-1) + set_trait(TRAIT_PRODUCT_ICON,"flower4") + set_trait(TRAIT_PRODUCT_COLOUR,"#FCEB2B") + set_trait(TRAIT_PLANT_COLOUR,"#59945A") + set_trait(TRAIT_PLANT_ICON,"bush6") /datum/seed/whitebeets name = "whitebeet" seed_name = "white-beet" display_name = "white-beets" - packet_icon = "seed-whitebeet" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/whitebeet) - plant_icon = "whitebeet" chems = list("nutriment" = list(0,20), "sugar" = list(1,5)) + kitchen_tag = "whitebeet" - lifespan = 60 - maturation = 6 - production = 6 - yield = 6 - potency = 10 +/datum/seed/whitebeets/New() + ..() + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"carrot2") + set_trait(TRAIT_PRODUCT_COLOUR,"#EEF5B0") + set_trait(TRAIT_PLANT_COLOUR,"#4D8F53") + set_trait(TRAIT_PLANT_ICON,"carrot2") /datum/seed/sugarcane name = "sugarcane" seed_name = "sugarcane" display_name = "sugarcanes" - packet_icon = "seed-sugarcane" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/sugarcane) - plant_icon = "sugarcane" - harvest_repeat = 1 chems = list("sugar" = list(4,5)) - lifespan = 60 - maturation = 3 - production = 6 - yield = 4 - potency = 10 - growth_stages = 3 +/datum/seed/sugarcane/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"stalk") + set_trait(TRAIT_PRODUCT_COLOUR,"#B4D6BD") + set_trait(TRAIT_PLANT_COLOUR,"#6BBD68") + set_trait(TRAIT_PLANT_ICON,"stalk3") /datum/seed/watermelon name = "watermelon" seed_name = "watermelon" display_name = "watermelon vine" - packet_icon = "seed-watermelon" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/watermelon) - plant_icon = "watermelon" - harvest_repeat = 1 chems = list("nutriment" = list(1,6)) + kitchen_tag = "watermelon" - lifespan = 50 - maturation = 6 - production = 6 - yield = 3 - potency = 1 +/datum/seed/watermelon/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_JUICY,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,1) + set_trait(TRAIT_PRODUCT_ICON,"vine") + set_trait(TRAIT_PRODUCT_COLOUR,"#326B30") + set_trait(TRAIT_PLANT_COLOUR,"#257522") + set_trait(TRAIT_PLANT_ICON,"vine2") /datum/seed/pumpkin name = "pumpkin" seed_name = "pumpkin" display_name = "pumpkin vine" - packet_icon = "seed-pumpkin" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/pumpkin) - plant_icon = "pumpkin" - harvest_repeat = 1 chems = list("nutriment" = list(1,6)) + kitchen_tag = "pumpkin" - lifespan = 50 - maturation = 6 - production = 6 - yield = 3 - potency = 10 - growth_stages = 3 +/datum/seed/pumpkin/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"vine") + set_trait(TRAIT_PRODUCT_COLOUR,"#B4D4B9") + set_trait(TRAIT_PLANT_COLOUR,"#BAE8C1") + set_trait(TRAIT_PLANT_ICON,"vine2") -/datum/seed/lime +/datum/seed/citrus name = "lime" seed_name = "lime" display_name = "lime trees" - packet_icon = "seed-lime" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/lime) - plant_icon = "lime" - harvest_repeat = 1 chems = list("nutriment" = list(1,20)) + kitchen_tag = "lime" - lifespan = 55 - maturation = 6 - production = 6 - yield = 4 - potency = 15 +/datum/seed/citrus/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_JUICY,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,15) + set_trait(TRAIT_PRODUCT_ICON,"treefruit") + set_trait(TRAIT_PRODUCT_COLOUR,"#3AF026") + set_trait(TRAIT_PLANT_ICON,"tree") -/datum/seed/lemon +/datum/seed/citrus/lemon name = "lemon" seed_name = "lemon" display_name = "lemon trees" - packet_icon = "seed-lemon" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/lemon) - plant_icon = "lemon" - harvest_repeat = 1 chems = list("nutriment" = list(1,20)) + kitchen_tag = "lemon" - lifespan = 55 - maturation = 6 - production = 6 - yield = 4 - potency = 10 +/datum/seed/citrus/lemon/New() + ..() + set_trait(TRAIT_PRODUCES_POWER,1) + set_trait(TRAIT_PRODUCT_COLOUR,"#F0E226") -/datum/seed/orange +/datum/seed/citrus/orange name = "orange" seed_name = "orange" display_name = "orange trees" - packet_icon = "seed-orange" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/orange) - plant_icon = "orange" - harvest_repeat = 1 + kitchen_tag = "orange" chems = list("nutriment" = list(1,20)) - lifespan = 60 - maturation = 6 - production = 6 - yield = 5 - potency = 1 +/datum/seed/citrus/orange/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#FFC20A") /datum/seed/grass name = "grass" seed_name = "grass" display_name = "grass" - packet_icon = "seed-grass" - products = list(/obj/item/stack/tile/grass) - plant_icon = "grass" - harvest_repeat = 1 + chems = list("nutriment" = list(1,20)) + kitchen_tag = "grass" - lifespan = 60 - maturation = 2 - production = 5 - yield = 5 - growth_stages = 2 +/datum/seed/grass/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,2) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_PRODUCT_ICON,"grass") + set_trait(TRAIT_PRODUCT_COLOUR,"#09FF00") + set_trait(TRAIT_PLANT_COLOUR,"#07D900") + set_trait(TRAIT_PLANT_ICON,"grass") /datum/seed/cocoa name = "cocoa" seed_name = "cacao" display_name = "cacao tree" - packet_icon = "seed-cocoapod" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/cocoapod) - plant_icon = "cocoapod" - harvest_repeat = 1 chems = list("nutriment" = list(1,10), "coco" = list(4,5)) - lifespan = 20 - maturation = 5 - production = 5 - yield = 2 - potency = 10 - growth_stages = 5 +/datum/seed/cocoa/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"treefruit") + set_trait(TRAIT_PRODUCT_COLOUR,"#CCA935") + set_trait(TRAIT_PLANT_ICON,"tree2") /datum/seed/cherries name = "cherry" seed_name = "cherry" seed_noun = "pits" display_name = "cherry tree" - packet_icon = "seed-cherry" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/cherries) - plant_icon = "cherry" - harvest_repeat = 1 chems = list("nutriment" = list(1,15), "sugar" = list(1,15)) + kitchen_tag = "cherries" - lifespan = 35 - maturation = 5 - production = 5 - yield = 3 - potency = 10 - growth_stages = 5 +/datum/seed/cherries/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_JUICY,1) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"cherry") + set_trait(TRAIT_PRODUCT_COLOUR,"#A80000") + set_trait(TRAIT_PLANT_ICON,"tree2") + set_trait(TRAIT_PLANT_COLOUR,"#2F7D2D") /datum/seed/kudzu name = "kudzu" seed_name = "kudzu" display_name = "kudzu vines" - packet_icon = "seed-kudzu" - products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/kudzupod) - plant_icon = "kudzu" - product_colour = "#96D278" chems = list("nutriment" = list(1,50), "charcoal" = list(1,25)) - lifespan = 20 - maturation = 6 - production = 6 - yield = 4 - potency = 10 - growth_stages = 4 - spread = 2 +/datum/seed/kudzu/New() + ..() + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_SPREAD,2) + set_trait(TRAIT_PRODUCT_ICON,"treefruit") + set_trait(TRAIT_PRODUCT_COLOUR,"#96D278") + set_trait(TRAIT_PLANT_COLOUR,"#6F7A63") + set_trait(TRAIT_PLANT_ICON,"vine2") /datum/seed/diona name = "diona" seed_name = "diona" seed_noun = "nodes" display_name = "replicant pods" - packet_icon = "seed-replicapod" - products = list(/mob/living/carbon/monkey/diona) - plant_icon = "replicapod" - product_requires_player = 1 - immutable = 1 + can_self_harvest = 1 + has_mob_product = /mob/living/carbon/monkey/diona - lifespan = 50 - endurance = 8 - maturation = 5 - production = 10 - yield = 1 - potency = 30 +/datum/seed/diona/New() + ..() + set_trait(TRAIT_IMMUTABLE,1) + set_trait(TRAIT_ENDURANCE,8) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,10) + set_trait(TRAIT_YIELD,1) + set_trait(TRAIT_POTENCY,30) + set_trait(TRAIT_PRODUCT_ICON,"diona") + set_trait(TRAIT_PRODUCT_COLOUR,"#799957") + set_trait(TRAIT_PLANT_COLOUR,"#66804B") + set_trait(TRAIT_PLANT_ICON,"alien4") /datum/seed/clown name = "clown" seed_name = "clown" seed_noun = "pods" display_name = "laughing clowns" - packet_icon = "seed-replicapod" - products = list(/mob/living/simple_animal/hostile/retaliate/clown) - plant_icon = "replicapod" - product_requires_player = 1 + can_self_harvest = 1 + has_mob_product = /mob/living/simple_animal/hostile/retaliate/clown - lifespan = 100 - endurance = 8 - maturation = 1 - production = 1 - yield = 10 - potency = 30 +/datum/seed/clown/New() + ..() + set_trait(TRAIT_ENDURANCE,8) + set_trait(TRAIT_MATURATION,1) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,10) + set_trait(TRAIT_POTENCY,30) + set_trait(TRAIT_PRODUCT_ICON,"diona") + set_trait(TRAIT_PRODUCT_COLOUR,"#799957") + set_trait(TRAIT_PLANT_COLOUR,"#66804B") + set_trait(TRAIT_PLANT_ICON,"alien4") + +/datum/seed/shand + name = "shand" + seed_name = "S'randar's hand" + display_name = "S'randar's hand leaves" + chems = list("styptic_powder" = list(0,10)) + kitchen_tag = "shand" + +/datum/seed/shand/New() + ..() + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"alien3") + set_trait(TRAIT_PRODUCT_COLOUR,"#378C61") + set_trait(TRAIT_PLANT_COLOUR,"#378C61") + set_trait(TRAIT_PLANT_ICON,"tree5") + +/datum/seed/mtear + name = "mtear" + seed_name = "Messa's tear" + display_name = "Messa's tear leaves" + chems = list("honey" = list(1,10), "silver_sulfadiazine" = list(3,5)) + kitchen_tag = "mtear" + +/datum/seed/mtear/New() + ..() + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"alien4") + set_trait(TRAIT_PRODUCT_COLOUR,"#4CC5C7") + set_trait(TRAIT_PLANT_COLOUR,"#4CC789") + set_trait(TRAIT_PLANT_ICON,"bush7") + +/datum/seed/telriis + name = "telriis" + seed_name = "telriis" + display_name = "telriis grass" + chems = list("wine" = list(1,5), "toxin" = list(1,5), "nutriment" = list(1,6)) + +/datum/seed/telriis/New() + ..() + set_trait(TRAIT_PLANT_ICON,"telriis") + set_trait(TRAIT_ENDURANCE,50) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,5) + +/datum/seed/thaadra + name = "thaadra" + seed_name = "thaa'dra" + display_name = "thaa'dra lichen" + chems = list("frostoil" = list(1,5),"nutriment" = list(1,5)) + +/datum/seed/thaadra/New() + ..() + set_trait(TRAIT_PLANT_ICON,"thaadra") + set_trait(TRAIT_ENDURANCE,10) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,9) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,5) + +/datum/seed/jurlmah + name = "jurlmah" + seed_name = "jurl'mah" + display_name = "jurl'mah reeds" + chems = list("serotrotium" = list(1,5),"nutriment" = list(1,5)) + +/datum/seed/jurlmah/New() + ..() + set_trait(TRAIT_PLANT_ICON,"jurlmah") + set_trait(TRAIT_ENDURANCE,12) + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_PRODUCTION,9) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,10) + +/datum/seed/amauri + name = "amauri" + seed_name = "amauri" + display_name = "amauri plant" + chems = list("condensedcapsaicin" = list(1,5),"nutriment" = list(1,5)) + +/datum/seed/amauri/New() + ..() + set_trait(TRAIT_PLANT_ICON,"amauri") + set_trait(TRAIT_ENDURANCE,10) + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_PRODUCTION,9) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + +/datum/seed/gelthi + name = "gelthi" + seed_name = "gelthi" + display_name = "gelthi plant" + chems = list("morphine" = list(1,5),"capsaicin" = list(1,5),"nutriment" = list(1,5)) + +/datum/seed/gelthi/New() + ..() + set_trait(TRAIT_PLANT_ICON,"gelthi") + set_trait(TRAIT_ENDURANCE,15) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,1) + +/datum/seed/vale + name = "vale" + seed_name = "vale" + display_name = "vale bush" + chems = list("sal_acid" = list(1,5),"salbutamol" = list(1,2),"nutriment"= list(1,5)) + +/datum/seed/vale/New() + ..() + set_trait(TRAIT_PLANT_ICON,"vale") + set_trait(TRAIT_ENDURANCE,15) + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_PRODUCTION,10) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,3) + +/datum/seed/surik + name = "surik" + seed_name = "surik" + display_name = "surik vine" + chems = list("haloperidol" = list(1,3),"synaptizine" = list(1,2),"nutriment" = list(1,5)) + +/datum/seed/surik/New() + ..() + set_trait(TRAIT_PLANT_ICON,"surik") + set_trait(TRAIT_ENDURANCE,18) + set_trait(TRAIT_MATURATION,7) + set_trait(TRAIT_PRODUCTION,7) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,3) /datum/seed/test name = "test" - seed_name = "testing" - seed_noun = "data" - display_name = "runtimes" - packet_icon = "seed-replicapod" - products = list(/mob/living/simple_animal/cat/Runtime) - plant_icon = "replicapod" + seed_name = "test" + display_name = "test trees" + chems = list("omnizine" = list(1,20)) - requires_nutrients = 0 - nutrient_consumption = 0 - requires_water = 0 - water_consumption = 0 - pest_tolerance = 11 - weed_tolerance = 11 - lifespan = 1000 - endurance = 100 - maturation = 1 - production = 1 - yield = 1 - potency = 1 \ No newline at end of file +/datum/seed/test/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_JUICY,1) + set_trait(TRAIT_MATURATION,1) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,15) + set_trait(TRAIT_PRODUCT_ICON,"treefruit") + set_trait(TRAIT_PRODUCT_COLOUR,"#BB6AC4") + set_trait(TRAIT_PLANT_ICON,"tree") + set_trait(TRAIT_EXPLOSIVE, 1) diff --git a/code/modules/hydroponics/seed_machines.dm b/code/modules/hydroponics/seed_machines.dm index e2416733cc3..cce982372c0 100644 --- a/code/modules/hydroponics/seed_machines.dm +++ b/code/modules/hydroponics/seed_machines.dm @@ -1,7 +1,7 @@ /obj/item/weapon/disk/botany name = "flora data disk" desc = "A small disk used for carrying data on plant genetics." - icon = 'icons/obj/hydroponics.dmi' + icon = 'icons/obj/hydroponics_machines.dmi' icon_state = "disk" w_class = 1.0 @@ -16,7 +16,7 @@ /obj/item/weapon/disk/botany/attack_self(var/mob/user as mob) if(genes.len) var/choice = alert(user, "Are you sure you want to wipe the disk?", "Xenobotany Data", "No", "Yes") - if(src && user && genes && choice == "Yes") + if(src && user && genes && choice && choice == "Yes" && user.Adjacent(get_turf(src))) user << "You wipe the disk data." name = initial(name) desc = initial(name) @@ -33,7 +33,7 @@ new /obj/item/weapon/disk/botany(src) /obj/machinery/botany - icon = 'icons/obj/hydroponics.dmi' + icon = 'icons/obj/hydroponics_machines.dmi' icon_state = "hydrotray3" density = 1 anchored = 1 @@ -44,7 +44,7 @@ var/open = 0 var/active = 0 - var/action_time = 100 + var/action_time = 5 var/last_action = 0 var/eject_disk = 0 var/failed_task = 0 @@ -58,9 +58,6 @@ if(world.time > last_action + action_time) finished_task() -/obj/machinery/botany/attack_paw(mob/user as mob) - return attack_hand(user) - /obj/machinery/botany/attack_ai(mob/user as mob) return attack_hand(user) @@ -82,13 +79,13 @@ visible_message("\icon[src] [src] beeps and spits out [loaded_disk].") loaded_disk = null -/obj/machinery/botany/attackby(obj/item/weapon/W as obj, mob/user as mob, params) +/obj/machinery/botany/attackby(obj/item/weapon/W as obj, mob/user as mob) if(istype(W,/obj/item/seeds)) if(seed) user << "There is already a seed loaded." - + return var/obj/item/seeds/S =W - if(S.seed && S.seed.immutable > 0) + if(S.seed && S.seed.get_trait(TRAIT_IMMUTABLE) > 0) user << "That seed is not compatible with our genetics technology." else user.drop_item(W) @@ -99,7 +96,7 @@ if(istype(W,/obj/item/weapon/screwdriver)) open = !open - user << "\blue You [open ? "open" : "close"] the maintenance panel." + user << "You [open ? "open" : "close"] the maintenance panel." return if(open) @@ -147,8 +144,8 @@ var/list/data = list() var/list/geneMasks[0] - for(var/gene_tag in gene_tag_masks) - geneMasks.Add(list(list("tag" = gene_tag, "mask" = gene_tag_masks[gene_tag]))) + for(var/gene_tag in plant_controller.gene_tag_masks) + geneMasks.Add(list(list("tag" = gene_tag, "mask" = plant_controller.gene_tag_masks[gene_tag]))) data["geneMasks"] = geneMasks data["activity"] = active @@ -189,10 +186,10 @@ if(!seed) return seed.loc = get_turf(src) - if(seed.seed.name == "new line" || isnull(seed_types[seed.seed.name])) - seed.seed.uid = seed_types.len + 1 + if(seed.seed.name == "new line" || isnull(plant_controller.seeds[seed.seed.name])) + seed.seed.uid = plant_controller.seeds.len + 1 seed.seed.name = "[seed.seed.uid]" - seed_types[seed.seed.name] = seed.seed + plant_controller.seeds[seed.seed.name] = seed.seed seed.update_seed() visible_message("\icon[src] [src] beeps and spits out [seed].") @@ -245,8 +242,8 @@ if(!genetics.roundstart) loaded_disk.genesource += " (variety #[genetics.uid])" - loaded_disk.name += " ([gene_tag_masks[href_list["get_gene"]]], #[genetics.uid])" - loaded_disk.desc += " The label reads \'gene [gene_tag_masks[href_list["get_gene"]]], sampled from [genetics.display_name]\'." + loaded_disk.name += " ([plant_controller.gene_tag_masks[href_list["get_gene"]]], #[genetics.uid])" + loaded_disk.desc += " The label reads \'gene [plant_controller.gene_tag_masks[href_list["get_gene"]]], sampled from [genetics.display_name]\'." eject_disk = 1 degradation += rand(20,60) @@ -291,7 +288,7 @@ for(var/datum/plantgene/P in loaded_disk.genes) if(data["locus"] != "") data["locus"] += ", " - data["locus"] += "[gene_tag_masks[P.genetype]]" + data["locus"] += "[plant_controller.gene_tag_masks[P.genetype]]" else data["disk"] = 0 @@ -321,7 +318,7 @@ last_action = world.time active = 1 - if(!isnull(seed_types[seed.seed.name])) + if(!isnull(plant_controller.seeds[seed.seed.name])) seed.seed = seed.seed.diverge(1) seed.seed_type = seed.seed.name seed.update_seed() @@ -335,4 +332,4 @@ seed.modified += rand(5,10) usr.set_machine(src) - src.add_fingerprint(usr) \ No newline at end of file + src.add_fingerprint(usr) diff --git a/code/modules/hydroponics/seed_mobs.dm b/code/modules/hydroponics/seed_mobs.dm index 4bef08248bc..8b240124550 100644 --- a/code/modules/hydroponics/seed_mobs.dm +++ b/code/modules/hydroponics/seed_mobs.dm @@ -1,5 +1,4 @@ /datum/seed - var/product_requires_player // If yes, product will ask for a player among the ghosts. var/list/currently_querying // Used to avoid asking the same ghost repeatedly. // The following procs are used to grab players for mobs produced by a seed (mostly for dionaea). @@ -7,25 +6,26 @@ /* if(!host || !istype(host)) return - if(product_requires_player) - spawn(0) - request_player(host) - spawn(75) - if(!host.ckey && !host.client) - host.death() // This seems redundant, but a lot of mobs don't - host.stat = 2 // handle death() properly. Better safe than etc. - host.visible_message("\red [host] is malformed and unable to survive. It expires pitifully, leaving behind some seeds.") + spawn(0) + request_player(host) + if(istype(host,/mob/living/simple_animal)) + return + spawn(75) + if(!host.ckey && !host.client) + host.death() // This seems redundant, but a lot of mobs don't + host.stat = 2 // handle death() properly. Better safe than etc. + host.visible_message("[host] is malformed and unable to survive. It expires pitifully, leaving behind some seeds.") - var/total_yield = rand(1,3) - for(var/j = 0;j<=total_yield;j++) - var/obj/item/seeds/S = new(get_turf(host)) - S.seed_type = name - S.update_seed() + var/total_yield = rand(1,3) + for(var/j = 0;j<=total_yield;j++) + var/obj/item/seeds/S = new(get_turf(host)) + S.seed_type = name + S.update_seed() /datum/seed/proc/request_player(var/mob/living/host) if(!host) return for(var/mob/dead/observer/O in player_list) - if(jobban_isbanned(O, "Dionaea") || (!is_alien_whitelisted(src, "Diona") && config.usealienwhitelist)) + if(jobban_isbanned(O, "Dionaea")) continue if(O.client) if(O.client.prefs.be_special & BE_PLANT && !(O.client in currently_querying)) @@ -69,7 +69,7 @@ host << "\green You awaken slowly, stirring into sluggish motion as the air caresses you." // This is a hack, replace with some kind of species blurb proc. - if(istype(host,/mob/living/carbon/monkey/diona)) + if(istype(host,/mob/living/carbon/alien/diona)) host << "You are [host], one of a race of drifting interstellar plantlike creatures that sometimes share their seeds with human traders." host << "Too much darkness will send you into shock and starve you, but light will help you heal." diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seed_packets.dm similarity index 65% rename from code/modules/hydroponics/seeds.dm rename to code/modules/hydroponics/seed_packets.dm index a572b2c8d19..3a2afb74f2a 100644 --- a/code/modules/hydroponics/seeds.dm +++ b/code/modules/hydroponics/seed_packets.dm @@ -1,8 +1,10 @@ +var/global/list/plant_seed_sprites = list() + //Seed packet object/procs. /obj/item/seeds name = "packet of seeds" icon = 'icons/obj/seeds.dmi' - icon_state = "seed" + icon_state = "blank" w_class = 2.0 var/seed_type @@ -10,26 +12,57 @@ var/modified = 0 /obj/item/seeds/New() + while(!plant_controller) + sleep(30) update_seed() ..() //Grabs the appropriate seed datum from the global list. /obj/item/seeds/proc/update_seed() - if(!seed && seed_type && !isnull(seed_types) && seed_types[seed_type]) - seed = seed_types[seed_type] + if(!seed && seed_type && !isnull(plant_controller.seeds) && plant_controller.seeds[seed_type]) + seed = plant_controller.seeds[seed_type] update_appearance() //Updates strings and icon appropriately based on seed datum. /obj/item/seeds/proc/update_appearance() if(!seed) return - icon_state = seed.packet_icon - src.name = "packet of [seed.seed_name] [seed.seed_noun]" - src.desc = "It has a picture of [seed.display_name] on the front." -/obj/item/seeds/examine() - ..() + // Update icon. + overlays.Cut() + var/is_seeds = ((seed.seed_noun in list("seeds","pits","nodes")) ? 1 : 0) + var/image/seed_mask + var/seed_base_key = "base-[is_seeds ? seed.get_trait(TRAIT_PLANT_COLOUR) : "spores"]" + if(plant_seed_sprites[seed_base_key]) + seed_mask = plant_seed_sprites[seed_base_key] + else + seed_mask = image('icons/obj/seeds.dmi',"[is_seeds ? "seed" : "spore"]-mask") + if(is_seeds) // Spore glass bits aren't coloured. + seed_mask.color = seed.get_trait(TRAIT_PLANT_COLOUR) + plant_seed_sprites[seed_base_key] = seed_mask + + var/image/seed_overlay + var/seed_overlay_key = "[seed.get_trait(TRAIT_PRODUCT_ICON)]-[seed.get_trait(TRAIT_PRODUCT_COLOUR)]" + if(plant_seed_sprites[seed_overlay_key]) + seed_overlay = plant_seed_sprites[seed_overlay_key] + else + seed_overlay = image('icons/obj/seeds.dmi',"[seed.get_trait(TRAIT_PRODUCT_ICON)]") + seed_overlay.color = seed.get_trait(TRAIT_PRODUCT_COLOUR) + plant_seed_sprites[seed_overlay_key] = seed_overlay + + overlays |= seed_mask + overlays |= seed_overlay + + if(is_seeds) + src.name = "packet of [seed.seed_name] [seed.seed_noun]" + src.desc = "It has a picture of [seed.display_name] on the front." + else + src.name = "sample of [seed.seed_name] [seed.seed_noun]" + src.desc = "It's labelled as coming from [seed.display_name]." + +/obj/item/seeds/examine(mob/user) + ..(user) if(seed && !seed.roundstart) - usr << "It's tagged as variety #[seed.uid]." + user << "It's tagged as variety #[seed.uid]." /obj/item/seeds/cutting name = "cuttings" @@ -39,12 +72,17 @@ ..() src.name = "packet of [seed.seed_name] cuttings" +/obj/item/seeds/random + seed_type = null + +/obj/item/seeds/random/New() + seed = plant_controller.create_random_seed() + seed_type = seed.name + update_seed() + /obj/item/seeds/replicapod seed_type = "diona" -/obj/item/seeds/poppyseed - seed_type = "poppies" - /obj/item/seeds/chiliseed seed_type = "chili" @@ -81,9 +119,6 @@ /obj/item/seeds/eggplantseed seed_type = "eggplant" -/obj/item/seeds/eggyseed - seed_type = "realeggplant" - /obj/item/seeds/bloodtomatoseed seed_type = "bloodtomato" @@ -114,9 +149,6 @@ /obj/item/seeds/soyaseed seed_type = "soybean" -/obj/item/seeds/koiseed - seed_type = "koibean" - /obj/item/seeds/wheatseed seed_type = "wheat" @@ -222,11 +254,38 @@ /obj/item/seeds/cherryseed seed_type = "cherry" +/obj/item/seeds/tobaccoseed + seed_type = "tobacco" + /obj/item/seeds/kudzuseed seed_type = "kudzu" -/obj/item/seeds/tobaccoseed - seed_type = "tobacco" +/obj/item/seeds/jurlmah + seed_type = "jurlmah" + +/obj/item/seeds/amauri + seed_type = "amauri" + +/obj/item/seeds/gelthi + seed_type = "gelthi" + +/obj/item/seeds/vale + seed_type = "vale" + +/obj/item/seeds/surik + seed_type = "surik" + +/obj/item/seeds/telriis + seed_type = "telriis" + +/obj/item/seeds/thaadra + seed_type = "thaadra" + +/obj/item/seeds/clown + seed_type = "clown" + +/obj/item/seeds/test + seed_type = "test" /obj/item/seeds/stobaccoseed seed_type = "stobacco" @@ -242,10 +301,3 @@ /obj/item/seeds/coffeerseed seed_type = "coffeer" - -/obj/item/seeds/moonflowerseed - seed_type = "moonflower" - -/obj/item/seeds/novaflowerseed - seed_type = "novaflower" - diff --git a/code/modules/hydroponics/seed_storage.dm b/code/modules/hydroponics/seed_storage.dm new file mode 100644 index 00000000000..e64ad1e8131 --- /dev/null +++ b/code/modules/hydroponics/seed_storage.dm @@ -0,0 +1,245 @@ +/datum/seed_pile + var/name + var/amount + var/datum/seed/seed_type // Keeps track of what our seed is + var/list/obj/item/seeds/seeds = list() // Tracks actual objects contained in the pile + var/ID + +/datum/seed_pile/New(var/obj/item/seeds/O, var/ID) + name = O.name + amount = 1 + seed_type = O.seed + seeds += O + src.ID = ID + +/datum/seed_pile/proc/matches(var/obj/item/seeds/O) + if (O.seed == seed_type) + return 1 + return 0 + +/obj/machinery/seed_storage + name = "Seed storage" + desc = "It stores, sorts, and dispenses seeds." + icon = 'icons/obj/vending.dmi' + icon_state = "seeds" + density = 1 + anchored = 1 + use_power = 1 + idle_power_usage = 100 + + var/initialized = 0 // Map-placed ones break if seeds are loaded right at the start of the round, so we do it on the first interaction + var/list/datum/seed_pile/piles = list() + var/list/starting_seeds = list() + var/list/scanner = list() // What properties we can view + +/obj/machinery/seed_storage/random // This is mostly for testing, but I guess admins could spawn it + name = "Random seed storage" + scanner = list("stats", "produce", "soil", "temperature", "light") + starting_seeds = list(/obj/item/seeds/random = 50) + +/obj/machinery/seed_storage/garden + name = "Garden seed storage" + scanner = list("stats") + starting_seeds = list(/obj/item/seeds/appleseed = 3, /obj/item/seeds/bananaseed = 3, /obj/item/seeds/berryseed = 3, /obj/item/seeds/cabbageseed = 3, /obj/item/seeds/carrotseed = 3, /obj/item/seeds/chantermycelium = 3, /obj/item/seeds/cherryseed = 3, /obj/item/seeds/chiliseed = 3, /obj/item/seeds/cocoapodseed = 3, /obj/item/seeds/cornseed = 3, /obj/item/seeds/eggplantseed = 3, /obj/item/seeds/grapeseed = 3, /obj/item/seeds/grassseed = 3, /obj/item/seeds/replicapod = 3, /obj/item/seeds/lemonseed = 3, /obj/item/seeds/limeseed = 3, /obj/item/seeds/mtearseed = 2, /obj/item/seeds/orangeseed = 3, /obj/item/seeds/peanutseed = 3, /obj/item/seeds/plumpmycelium = 3, /obj/item/seeds/poppyseed = 3, /obj/item/seeds/potatoseed = 3, /obj/item/seeds/pumpkinseed = 3, /obj/item/seeds/riceseed = 3, /obj/item/seeds/soyaseed = 3, /obj/item/seeds/sugarcaneseed = 3, /obj/item/seeds/sunflowerseed = 3, /obj/item/seeds/shandseed = 2, /obj/item/seeds/tobaccoseed = 3, /obj/item/seeds/tomatoseed = 3, /obj/item/seeds/towermycelium = 3, /obj/item/seeds/watermelonseed = 3, /obj/item/seeds/wheatseed = 3, /obj/item/seeds/whitebeetseed = 3) + +/obj/machinery/seed_storage/xenobotany + name = "Xenobotany seed storage" + scanner = list("stats", "produce", "soil", "temperature", "light") + starting_seeds = list(/obj/item/seeds/ambrosiavulgarisseed = 3, /obj/item/seeds/appleseed = 3, /obj/item/seeds/amanitamycelium = 2, /obj/item/seeds/bananaseed = 3, /obj/item/seeds/berryseed = 3, /obj/item/seeds/cabbageseed = 3, /obj/item/seeds/carrotseed = 3, /obj/item/seeds/chantermycelium = 3, /obj/item/seeds/cherryseed = 3, /obj/item/seeds/chiliseed = 3, /obj/item/seeds/cocoapodseed = 3, /obj/item/seeds/cornseed = 3, /obj/item/seeds/replicapod = 3, /obj/item/seeds/eggplantseed = 3, /obj/item/seeds/glowshroom = 2, /obj/item/seeds/grapeseed = 3, /obj/item/seeds/grassseed = 3, /obj/item/seeds/lemonseed = 3, /obj/item/seeds/libertymycelium = 2, /obj/item/seeds/limeseed = 3, /obj/item/seeds/mtearseed = 2, /obj/item/seeds/nettleseed = 2, /obj/item/seeds/orangeseed = 3, /obj/item/seeds/peanutseed = 3, /obj/item/seeds/plastiseed = 3, /obj/item/seeds/plumpmycelium = 3, /obj/item/seeds/poppyseed = 3, /obj/item/seeds/potatoseed = 3, /obj/item/seeds/pumpkinseed = 3, /obj/item/seeds/reishimycelium = 2, /obj/item/seeds/riceseed = 3, /obj/item/seeds/soyaseed = 3, /obj/item/seeds/sugarcaneseed = 3, /obj/item/seeds/sunflowerseed = 3, /obj/item/seeds/shandseed = 2, /obj/item/seeds/tobaccoseed = 3, /obj/item/seeds/tomatoseed = 3, /obj/item/seeds/towermycelium = 3, /obj/item/seeds/watermelonseed = 3, /obj/item/seeds/wheatseed = 3, /obj/item/seeds/whitebeetseed = 3) + +/obj/machinery/seed_storage/attack_hand(mob/user as mob) + user.set_machine(src) + interact(user) + +/obj/machinery/seed_storage/interact(mob/user as mob) + if (..()) + return + + if (!initialized) + for(var/typepath in starting_seeds) + var/amount = starting_seeds[typepath] + if(isnull(amount)) amount = 1 + + for (var/i = 1 to amount) + var/O = new typepath + add(O) + initialized = 1 + + var/dat = "

Seed storage contents

" + if (piles.len == 0) + dat += "No seeds" + else + dat += "" + dat += "" + if ("stats" in scanner) + dat += "" + if ("temperature" in scanner) + dat += "" + if ("light" in scanner) + dat += "" + if ("soil" in scanner) + dat += "" + dat += "" + for (var/datum/seed_pile/S in piles) + var/datum/seed/seed = S.seed_type + if(!seed) + continue + dat += "" + dat += "" + dat += "" + if ("stats" in scanner) + dat += "" + if(seed.get_trait(TRAIT_HARVEST_REPEAT)) + dat += "" + else + dat += "" + if ("temperature" in scanner) + dat += "" + if ("light" in scanner) + dat += "" + if ("soil" in scanner) + if(seed.get_trait(TRAIT_REQUIRES_NUTRIENTS)) + if(seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) < 0.05) + dat += "" + else if(seed.get_trait(TRAIT_REQUIRES_NUTRIENTS) > 0.2) + dat += "" + else + dat += "" + else + dat += "" + if(seed.get_trait(TRAIT_REQUIRES_WATER)) + if(seed.get_trait(TRAIT_WATER_CONSUMPTION) < 1) + dat += "" + else if(seed.get_trait(TRAIT_WATER_CONSUMPTION) > 5) + dat += "" + else + dat += "" + else + dat += "" + + dat += "" + dat += "" + dat += "" + dat += "" + dat += "
NameVarietyEYMPrPtHarvestTempLightNutriWaterNotesAmount
[seed.seed_name]#[seed.uid][seed.get_trait(TRAIT_ENDURANCE)][seed.get_trait(TRAIT_YIELD)][seed.get_trait(TRAIT_MATURATION)][seed.get_trait(TRAIT_PRODUCTION)][seed.get_trait(TRAIT_POTENCY)]MultipleSingle[seed.get_trait(TRAIT_IDEAL_HEAT)] K[seed.get_trait(TRAIT_IDEAL_LIGHT)] LLowHighNormNoLowHighNormNo" + switch(seed.get_trait(TRAIT_CARNIVOROUS)) + if(1) + dat += "CARN " + if(2) + dat += "CARN " + switch(seed.get_trait(TRAIT_SPREAD)) + if(1) + dat += "VINE " + if(2) + dat += "VINE " + if ("pressure" in scanner) + if(seed.get_trait(TRAIT_LOWKPA_TOLERANCE) < 20) + dat += "LP " + if(seed.get_trait(TRAIT_HIGHKPA_TOLERANCE) > 220) + dat += "HP " + if ("temperature" in scanner) + if(seed.get_trait(TRAIT_HEAT_TOLERANCE) > 30) + dat += "TEMRES " + else if(seed.get_trait(TRAIT_HEAT_TOLERANCE) < 10) + dat += "TEMSEN " + if ("light" in scanner) + if(seed.get_trait(TRAIT_LIGHT_TOLERANCE) > 10) + dat += "LIGRES " + else if(seed.get_trait(TRAIT_LIGHT_TOLERANCE) < 3) + dat += "LIGSEN " + if(seed.get_trait(TRAIT_TOXINS_TOLERANCE) < 3) + dat += "TOXSEN " + else if(seed.get_trait(TRAIT_TOXINS_TOLERANCE) > 6) + dat += "TOXRES " + if(seed.get_trait(TRAIT_PEST_TOLERANCE) < 3) + dat += "PESTSEN " + else if(seed.get_trait(TRAIT_PEST_TOLERANCE) > 6) + dat += "PESTRES " + if(seed.get_trait(TRAIT_WEED_TOLERANCE) < 3) + dat += "WEEDSEN " + else if(seed.get_trait(TRAIT_WEED_TOLERANCE) > 6) + dat += "WEEDRES " + if(seed.get_trait(TRAIT_PARASITE)) + dat += "PAR " + if ("temperature" in scanner) + if(seed.get_trait(TRAIT_ALTER_TEMP) > 0) + dat += "TEMP+ " + if(seed.get_trait(TRAIT_ALTER_TEMP) < 0) + dat += "TEMP- " + if(seed.get_trait(TRAIT_BIOLUM)) + dat += "LUM " + dat += "[S.amount]Vend Purge
" + + user << browse(dat, "window=seedstorage") + onclose(user, "seedstorage") + +/obj/machinery/seed_storage/Topic(var/href, var/list/href_list) + if (..()) + return + var/task = href_list["task"] + var/ID = text2num(href_list["id"]) + + for (var/datum/seed_pile/N in piles) + if (N.ID == ID) + if (task == "vend") + var/obj/O = pick(N.seeds) + if (O) + --N.amount + N.seeds -= O + if (N.amount <= 0 || N.seeds.len <= 0) + piles -= N + del(N) + O.loc = src.loc + else + piles -= N + del(N) + else if (task == "purge") + for (var/obj/O in N.seeds) + del(O) + piles -= N + del(N) + break + updateUsrDialog() + +/obj/machinery/seed_storage/attackby(var/obj/item/O as obj, var/mob/user as mob) + if (istype(O, /obj/item/seeds)) + add(O) + user.visible_message("[user] puts \the [O.name] into \the [src].", "You put \the [O] into \the [src].") + return + else if (istype(O, /obj/item/weapon/storage/bag/plants)) + var/obj/item/weapon/storage/P = O + var/loaded = 0 + for(var/obj/item/seeds/G in P.contents) + ++loaded + add(G) + if (loaded) + user.visible_message("[user] puts the seeds from \the [O.name] into \the [src].", "You put the seeds from \the [O.name] into \the [src].") + else + user << "There are no seeds in \the [O.name]." + return + else if(istype(O, /obj/item/weapon/wrench)) + playsound(loc, 'sound/items/Ratchet.ogg', 50, 1) + anchored = !anchored + user << "You [anchored ? "wrench" : "unwrench"] \the [src]." + +/obj/machinery/seed_storage/proc/add(var/obj/item/seeds/O as obj) + if (istype(O.loc, /mob)) + var/mob/user = O.loc + user.drop_item(O) + else if(istype(O.loc,/obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = O.loc + S.remove_from_storage(O, src) + + O.loc = src + var/newID = 0 + + for (var/datum/seed_pile/N in piles) + if (N.matches(O)) + ++N.amount + N.seeds += (O) + return + else if(N.ID >= newID) + newID = N.ID + 1 + + piles += new /datum/seed_pile(O, newID) + return diff --git a/code/modules/hydroponics/spreading/spreading.dm b/code/modules/hydroponics/spreading/spreading.dm new file mode 100644 index 00000000000..d4bd00c9c05 --- /dev/null +++ b/code/modules/hydroponics/spreading/spreading.dm @@ -0,0 +1,262 @@ +#define DEFAULT_SEED "glowshroom" +#define VINE_GROWTH_STAGES 5 + +/proc/spacevine_infestation() + spawn() //to stop the secrets panel hanging + var/list/turf/simulated/floor/turfs = list() //list of all the empty floor turfs in the hallway areas + for(var/areapath in typesof(/area/hallway)) + var/area/A = locate(areapath) + for(var/area/B in A.related) + for(var/turf/simulated/floor/F in B.contents) + if(!F.contents.len) + turfs += F + + if(turfs.len) //Pick a turf to spawn at if we can + var/turf/simulated/floor/T = pick(turfs) + var/datum/seed/seed = plant_controller.create_random_seed(1) + seed.set_trait(TRAIT_SPREAD,2) // So it will function properly as vines. + seed.set_trait(TRAIT_POTENCY,rand(70,100)) // Guarantee a wide spread and powerful effects. + new /obj/effect/plant(T,seed) + message_admins("Event: Spacevines spawned at [T.loc] ([T.x],[T.y],[T.z])") + +/obj/effect/dead_plant + anchored = 1 + opacity = 0 + density = 0 + color = DEAD_PLANT_COLOUR + +/obj/effect/dead_plant/attack_hand() + del(src) + +/obj/effect/dead_plant/attackby() + ..() + for(var/obj/effect/plant/neighbor in range(1)) + neighbor.update_neighbors() + del(src) + +/obj/effect/plant + name = "plant" + anchored = 1 + opacity = 0 + density = 0 + icon = 'icons/obj/hydroponics_growing.dmi' + icon_state = "bush4-1" + layer = 3 + pass_flags = PASSTABLE + + var/health = 10 + var/max_health = 100 + var/growth_threshold = 0 + var/growth_type = 0 + var/max_growth = 0 + + var/list/neighbors = list() + var/obj/effect/plant/parent + var/datum/seed/seed + var/floor = 0 + var/spread_chance = 40 + var/spread_distance = 3 + var/evolve_chance = 2 + var/last_tick = 0 + var/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/plant + + var/mob/living/buckled_mob = null + var/movable = 0 + +/obj/effect/plant/Del() + if(plant_controller) + plant_controller.remove_plant(src) + for(var/obj/effect/plant/neighbor in range(1,src)) + plant_controller.add_plant(neighbor) + ..() +/obj/effect/plant/single + spread_chance = 0 + +/obj/effect/plant/New(var/newloc, var/datum/seed/newseed, var/obj/effect/plant/newparent) + ..() + + if(!newparent) + parent = src + else + parent = newparent + + if(!plant_controller) + sleep(250) // ugly hack, should mean roundstart plants are fine. + if(!plant_controller) + world << "Plant controller does not exist and [src] requires it. Aborting." + del(src) + return + + if(!istype(newseed)) + newseed = plant_controller.seeds[DEFAULT_SEED] + seed = newseed + if(!seed) + del(src) + return + + 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 = max_health/VINE_GROWTH_STAGES + icon = 'icons/obj/hydroponics_vines.dmi' + growth_type = 2 // Vines by default. + if(seed.get_trait(TRAIT_CARNIVOROUS) == 2) + growth_type = 1 // WOOOORMS. + else if(!(seed.seed_noun in list("seeds","pits"))) + if(seed.seed_noun == "nodes") + growth_type = 3 // Biomass + else + growth_type = 4 // Mold + else + max_growth = 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. + + spread_chance = seed.get_trait(TRAIT_POTENCY) * 4 + spread_distance = ((growth_type>0) ? round(spread_chance*0.6) : round(spread_chance*0.3)) + update_icon() + + spawn(1) // Plants will sometimes be spawned in the turf adjacent to the one they need to end up in, for the sake of correct dir/etc being set. + set_dir(calc_dir()) + update_icon() + plant_controller.add_plant(src) + // Some plants eat through plating. + if(!isnull(seed.chems["facid"])) + var/turf/T = get_turf(src) + T.ex_act(prob(80) ? 3 : 2) + +/obj/effect/plant/update_icon() + //TODO: should really be caching this. + refresh_icon() + if(growth_type == 0 && !floor) + src.transform = null + var/matrix/M = matrix() + // should make the plant flush against the wall it's meant to be growing from. + M.Translate(0,-(rand(12,14))) + switch(dir) + if(WEST) + M.Turn(90) + if(NORTH) + M.Turn(180) + if(EAST) + M.Turn(270) + src.transform = M + var/icon_colour = seed.get_trait(TRAIT_PLANT_COLOUR) + if(icon_colour) + color = icon_colour + // Apply colour and light from seed datum. + if(seed.get_trait(TRAIT_BIOLUM)) + SetLuminosity(1+round(seed.get_trait(TRAIT_POTENCY)/20)) + if(seed.get_trait(TRAIT_BIOLUM_COLOUR)) + l_color = seed.get_trait(TRAIT_BIOLUM_COLOUR) + else + l_color = null + return + else + SetLuminosity(0) + +/obj/effect/plant/proc/refresh_icon() + var/growth = min(max_growth,round(health/growth_threshold)) + var/at_fringe = get_dist(src,parent) + if(spread_distance > 5) + if(at_fringe >= (spread_distance-3)) + max_growth-- + if(at_fringe >= (spread_distance-2)) + max_growth-- + max_growth = max(1,max_growth) + if(growth_type > 0) + switch(growth_type) + if(1) + icon_state = "worms" + if(2) + icon_state = "vines-[growth]" + if(3) + icon_state = "mass-[growth]" + if(4) + icon_state = "mold-[growth]" + else + icon_state = "[seed.get_trait(TRAIT_PLANT_ICON)]-[growth]" + + if(growth>2 && growth == max_growth) + layer = 5 + opacity = 1 + if(!isnull(seed.chems["woodpulp"])) + density = 1 + else + layer = 3 + density = 0 + +/obj/effect/plant/proc/calc_dir(turf/location = loc) + set background = 1 + var/direction = 16 + + for(var/wallDir in cardinal) + var/turf/newTurf = get_step(location,wallDir) + if(newTurf.density) + direction |= wallDir + + for(var/obj/effect/plant/shroom in location) + if(shroom == src) + continue + if(shroom.floor) //special + direction &= ~16 + else + direction &= ~shroom.dir + + var/list/dirList = list() + + for(var/i=1,i<=16,i <<= 1) + if(direction & i) + dirList += i + + if(dirList.len) + var/newDir = pick(dirList) + if(newDir == 16) + floor = 1 + newDir = 1 + return newDir + + floor = 1 + return 1 + +/obj/effect/plant/attackby(var/obj/item/weapon/W, var/mob/user) + + plant_controller.add_plant(src) + + if(istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/weapon/scalpel)) + if(!seed) + user << "There is nothing to take a sample from." + return + seed.harvest(user,0,1) + health -= (rand(3,5)*10) + else + ..() + if(W.force) + health -= W.force + check_health() + +/obj/effect/plant/ex_act(severity) + switch(severity) + if(1.0) + die_off() + return + if(2.0) + if (prob(50)) + die_off() + return + if(3.0) + if (prob(5)) + die_off() + return + else + return + +/obj/effect/plant/proc/check_health() + if(health <= 0) + die_off() + +/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 00000000000..cdd06639a1c --- /dev/null +++ b/code/modules/hydroponics/spreading/spreading_growth.dm @@ -0,0 +1,106 @@ +#define NEIGHBOR_REFRESH_TIME 100 + +/obj/effect/plant/proc/get_cardinal_neighbors() + var/list/cardinal_neighbors = list() + for(var/check_dir in cardinal) + var/turf/simulated/T = get_step(get_turf(src), check_dir) + if(istype(T)) + cardinal_neighbors |= T + return cardinal_neighbors + +/obj/effect/plant/proc/update_neighbors() + // Update our list of valid neighboring turfs. + neighbors = list() + for(var/turf/simulated/floor in get_cardinal_neighbors()) + if(get_dist(parent, floor) > spread_distance) + continue + if((locate(/obj/effect/plant) in floor.contents) || (locate(/obj/effect/dead_plant) in floor.contents) ) + continue + if(floor.density) + if(!isnull(seed.chems["pacid"])) + spawn(rand(5,25)) floor.ex_act(3) + continue + if(!Adjacent(floor) || !floor.Enter(src)) + continue + neighbors |= floor + // Update all of our friends. + var/turf/T = get_turf(src) + for(var/obj/effect/plant/neighbor in range(1,src)) + neighbor.neighbors -= T + +/obj/effect/plant/process() + + // Something is very wrong, kill ourselves. + if(!seed) + die_off() + return 0 + + /* MOVED INTO code\game\objects\effects\effect_system.dm + for(var/obj/effect/effect/smoke/chem/smoke in view(1, src)) + if(smoke.reagents.has_reagent("plantbgone")) + die_off() + return + */ + + // Handle life. + var/turf/simulated/T = get_turf(src) + if(istype(T)) + health -= seed.handle_environment(T,T.return_air(),null,1) + if(health < max_health) + health += rand(3,5) + refresh_icon() + if(health > max_health) + health = max_health + else if(health == max_health && !plant) + plant = new(T,seed) + plant.dir = src.dir + plant.transform = src.transform + plant.age = seed.get_trait(TRAIT_MATURATION)-1 + plant.update_icon() + if(growth_type==0) //Vines do not become invisible. + invisibility = INVISIBILITY_MAXIMUM + else + plant.layer = layer + 0.1 + + if(buckled_mob) + seed.do_sting(buckled_mob,src) + if(seed.get_trait(TRAIT_CARNIVOROUS)) + seed.do_thorns(buckled_mob,src) + + if(world.time >= last_tick+NEIGHBOR_REFRESH_TIME) + last_tick = world.time + update_neighbors() + + if(is_mature() && neighbors.len && prob(spread_chance)) + for(var/i=1,i<=seed.get_trait(TRAIT_YIELD),i++) + if(prob(spread_chance)) + sleep(rand(3,5)) + if(!neighbors.len) + break + var/turf/target_turf = pick(neighbors) + var/obj/effect/plant/child = new(get_turf(src),seed,parent) + spawn(1) // This should do a little bit of animation. + child.loc = target_turf + child.update_icon() + // Update neighboring squares. + for(var/obj/effect/plant/neighbor in range(1,target_turf)) + neighbor.neighbors -= target_turf + + // We shouldn't have spawned if the controller doesn't exist. + check_health() + if(neighbors.len || health != max_health) + plant_controller.add_plant(src) + +/obj/effect/plant/proc/die_off() + // Kill off our plant. + if(plant) plant.die() + // This turf is clear now, let our buddies know. + for(var/turf/simulated/check_turf in get_cardinal_neighbors()) + if(!istype(check_turf)) + continue + for(var/obj/effect/plant/neighbor in check_turf.contents) + neighbor.neighbors |= check_turf + plant_controller.add_plant(neighbor) + spawn(1) if(src) del(src) + +#undef NEIGHBOR_REFRESH_TIME \ 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 00000000000..d175fdda221 --- /dev/null +++ b/code/modules/hydroponics/spreading/spreading_response.dm @@ -0,0 +1,78 @@ +/obj/effect/plant/HasProximity(var/atom/movable/AM) + + 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 && (M.small || prob(round(seed.get_trait(TRAIT_POTENCY)/2)))) + entangle(M) + +/obj/effect/plant/attack_hand(mob/user as mob) + // Todo, cause damage. + manual_unbuckle(user) + +/obj/effect/plant/proc/trodden_on(var/mob/living/victim) + 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 + + if(!Adjacent(victim)) + return + + victim.buckled = src + victim.update_canmove() + buckled_mob = victim + if(!victim.anchored && !victim.buckled && victim.loc != get_turf(src)) + var/can_grab = 1 + if(istype(victim, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = victim + if(istype(H.shoes, /obj/item/clothing/shoes/magboots) && (H.shoes.flags & NOSLIP)) + can_grab = 0 + if(can_grab) + 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/game/machinery/hydroponics.dm b/code/modules/hydroponics/trays/tray.dm similarity index 53% rename from code/game/machinery/hydroponics.dm rename to code/modules/hydroponics/trays/tray.dm index d5fb43f4d97..958f69beee2 100644 --- a/code/game/machinery/hydroponics.dm +++ b/code/modules/hydroponics/trays/tray.dm @@ -1,14 +1,14 @@ -#define HYDRO_SPEED_MULTIPLIER 1 - /obj/machinery/portable_atmospherics/hydroponics name = "hydroponics tray" - icon = 'icons/obj/hydroponics.dmi' + icon = 'icons/obj/hydroponics_machines.dmi' icon_state = "hydrotray3" density = 1 anchored = 1 flags = OPENCONTAINER + volume = 100 - var/draw_warnings = 1 //Set to 0 to stop it from drawing the alert lights. + var/mechanical = 1 // Set to 0 to stop it from drawing the alert lights. + var/base_name = "tray" // Plant maintenance vars. var/waterlevel = 100 // Water level (max 100) @@ -16,17 +16,19 @@ var/nutrilevel = 10 // Nutrient level (max 10) var/maxnutri = 10 var/pestlevel = 0 // Pests (max 10) - var/weedlevel = 0 // Weeds (max 10)s + var/weedlevel = 0 // Weeds (max 10) // Tray state vars. var/dead = 0 // Is it dead? var/harvest = 0 // Is it ready to harvest? var/age = 0 // Current plant age + var/sampled = 0 // Have we taken a sample? // Harvest/mutation mods. var/yield_mod = 0 // Modifier to yield var/mutation_mod = 0 // Modifier to mutation chance var/toxins = 0 // Toxicity in the tray? + var/tray_light = 1 // Supplied lighting. // Mechanical concerns. var/health = 0 // Plant health. @@ -35,6 +37,8 @@ var/cycledelay = 150 // Delay per cycle. var/closed_system // If set, the tray will attempt to take atmos from a pipe. var/force_update // Set this to bypass the cycle time check. + var/obj/temp_chem_holder // Something to hold reagents during process_reagents() + var/labelled // Seed details/line data. var/datum/seed/seed = null // The currently planted seed @@ -46,12 +50,12 @@ // with cycle information under 'mechanical concerns' at some point. var/global/list/toxic_reagents = list( "charcoal" = -2, - "toxin" = 2, + "toxin" = 2, "fluorine" = 2.5, "chlorine" = 1.5, "sacid" = 1.5, "facid" = 3, - "atrazine" = 3, + "atrazine" = 3, "cryoxadone" = -3, "radium" = 2 ) @@ -76,7 +80,7 @@ "sugar" = 2, "sacid" = -2, "facid" = -4, - "atrazine" = -8, + "atrazine" = -8, "adminordrazine" = -5 ) var/global/list/pestkiller_reagents = list( @@ -89,7 +93,7 @@ "adminordrazine" = 1, "milk" = 0.9, "beer" = 0.7, - "flourine" = -0.5, + "fluorine" = -0.5, "chlorine" = -0.5, "phosphorus" = -0.5, "water" = 1, @@ -98,22 +102,23 @@ // Beneficial reagents also have values for modifying yield_mod and mut_mod (in that order). var/global/list/beneficial_reagents = list( - "beer" = list( -0.05, 0, 0 ), - "fluorine" = list( -2, 0, 0 ), - "chlorine" = list( -1, 0, 0 ), - "phosphorus" = list( -0.75, 0, 0 ), - "sodawater" = list( 0.1, 0, 0 ), - "sacid" = list( -1, 0, 0 ), - "facid" = list( -2, 0, 0 ), - "atrazine" = list( -2, 0, 0.2 ), - "cryoxadone" = list( 3, 0, 0 ), - "ammonia" = list( 0.5, 0, 0 ), - "diethylamine" = list( 1, 0, 0 ), - "nutriment" = list( 0.25, 0.15, 0 ), - "radium" = list( -1.5, 0, 0.2 ), - "adminordrazine" = list( 1, 1, 1 ), - "robustharvest" = list( 0, 0.2, 0 ), - "left4zed" = list( 0, 0, 0.2 ) + // "reagent" = list(health, yield_Mod, mut_mod), + "beer" = list( -0.05, 0, 0 ), + "fluorine" = list( -2, 0, 0 ), + "chlorine" = list( -1, 0, 0 ), + "phosphorus" = list( -0.75, 0, 0 ), + "sodawater" = list( 0.1, 0, 0 ), + "sacid" = list( -1, 0, 0 ), + "facid" = list( -2, 0, 0 ), + "atrazine" = list( -2, 0, 0.2), + "cryoxadone" = list( 3, 0, 0 ), + "ammonia" = list( 0.5, 0, 0 ), + "diethylamine" = list( 1, 0, 0 ), + "nutriment" = list( 0.25, 0.15, 0 ), + "radium" = list( -1.5, 0, 0.2), + "adminordrazine" = list( 1, 1, 1 ), + "robustharvest" = list( 0, 0.2, 0 ), + "left4zed" = list( 0, 0, 0.2) ) //--FalseIncarnate @@ -126,6 +131,31 @@ ) //--FalseIncarnate +/obj/machinery/portable_atmospherics/hydroponics/AltClick() + if(mechanical && !usr.stat && !usr.lying && Adjacent(usr)) + close_lid(usr) + return + return ..() + +/obj/machinery/portable_atmospherics/hydroponics/proc/attack_generic(var/mob/user) + if(istype(user,/mob/living/carbon/monkey/diona)) + var/mob/living/carbon/monkey/diona/nymph = user + + if(nymph.stat == DEAD || nymph.paralysis || nymph.weakened || nymph.stunned || nymph.restrained()) + return + + if(weedlevel > 0) + nymph.reagents.add_reagent("nutriment", weedlevel) + weedlevel = 0 + nymph.visible_message("[nymph] begins rooting through [src], ripping out weeds and eating them noisily.","You begin rooting through [src], ripping out weeds and eating them noisily.") + else if(nymph.nutrition > 100 && nutrilevel < 10) + nymph.nutrition -= ((10-nutrilevel)*5) + nutrilevel = 10 + nymph.visible_message("[nymph] secretes a trickle of green liquid, refilling [src].","You secrete a trickle of green liquid, refilling [src].") + else + nymph.visible_message("[nymph] rolls around in [src] for a bit.","You roll around in [src] for a bit.") + return + /obj/machinery/portable_atmospherics/hydroponics/New() ..() @@ -136,6 +166,9 @@ component_parts += new /obj/item/weapon/stock_parts/console_screen(src) RefreshParts() + temp_chem_holder = new() + temp_chem_holder.create_reagents(10) + create_reagents(200) connect() update_icon() @@ -163,7 +196,7 @@ /obj/machinery/portable_atmospherics/hydroponics/bullet_act(var/obj/item/projectile/Proj) //Don't act on seeds like dionaea that shouldn't change. - if(seed && seed.immutable > 0) + if(seed && seed.get_trait(TRAIT_IMMUTABLE) > 0) return //--FalseIncarnate @@ -186,162 +219,17 @@ 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 - - // 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) ? 6 : 3)) - 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_tolernace > 10) are unaffected. - if (weedlevel >= 10 && prob(10)) - if(!seed || weedlevel >= seed.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) - return - - // Advance plant age. - if(prob(25)) age += 1 * HYDRO_SPEED_MULTIPLIER - - //Highly mutable plants have a chance of mutating every tick. - if(seed.immutable == -1) - var/mut_prob = rand(1,100) - if(mut_prob <= 5) mutate(mut_prob == 1 ? 2 : 1) - - // Maintain tray nutrient and water levels. - if(seed.nutrient_consumption > 0 && nutrilevel > 0 && prob(25)) - nutrilevel -= max(0,seed.nutrient_consumption * HYDRO_SPEED_MULTIPLIER) - if(seed.water_consumption > 0 && waterlevel > 0 && prob(25)) - waterlevel -= max(0,seed.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.requires_nutrients && prob(35)) - health += (nutrilevel < 2 ? -healthmod : healthmod) - if(seed.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) - if(istype(T)) - environment = T.return_air() - - if(!environment) return - -/* - // Handle gas consumption. - if(seed.consume_gasses && seed.consume_gasses.len) - var/missing_gas = 0 - for(var/gas in seed.consume_gasses) - if(environment && environment.gas && environment.gas[gas] && \ - environment.gas[gas] >= seed.consume_gasses[gas]) - environment.adjust_gas(gas,-seed.consume_gasses[gas],1) - else - missing_gas++ - - if(missing_gas > 0) - health -= missing_gas * HYDRO_SPEED_MULTIPLIER - - // Process it. - var/pressure = environment.return_pressure() - if(pressure < seed.lowkpa_tolerance || pressure > seed.highkpa_tolerance) - health -= healthmod - - if(abs(environment.temperature - seed.ideal_heat) > seed.heat_tolerance) - health -= healthmod - - // Handle gas production. - if(seed.exude_gasses && seed.exude_gasses.len) - for(var/gas in seed.exude_gasses) - environment.adjust_gas(gas, max(1,round((seed.exude_gasses[gas]*seed.potency)/seed.exude_gasses.len))) - -*/ - - // Handle light requirements. - var/area/A = T.loc - if(A) - var/light_available - if(A.lighting_use_dynamic) - light_available = max(0,min(10,T.lighting_lumcount)-5) - else - light_available = 5 - if(abs(light_available - seed.ideal_light) > seed.light_tolerance) - health -= healthmod - - // 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.toxins_tolerance) - health -= toxin_uptake - toxins -= toxin_uptake - - // Check for pests and weeds. - // Some carnivorous plants happily eat pests. - if(pestlevel > 0) - if(seed.carnivorous) - health += HYDRO_SPEED_MULTIPLIER - pestlevel -= HYDRO_SPEED_MULTIPLIER - else if (pestlevel >= seed.pest_tolerance) - health -= HYDRO_SPEED_MULTIPLIER - - // Some plants thrive and live off of weeds. - if(weedlevel > 0) - if(seed.parasite) - health += HYDRO_SPEED_MULTIPLIER - weedlevel -= HYDRO_SPEED_MULTIPLIER - else if (weedlevel >= seed.weed_tolerance) - health -= HYDRO_SPEED_MULTIPLIER - - // Handle life and death. - // If the plant is too old, it loses health fast. - if(age > seed.lifespan) - health -= rand(3,5) * HYDRO_SPEED_MULTIPLIER - - // When the plant dies, weeds thrive and pests die off. - if(health <= 0) - dead = 1 - harvest = 0 - weedlevel += 1 * HYDRO_SPEED_MULTIPLIER - pestlevel = 0 - - // If enough time (in cycles, not ticks) has passed since the plant was harvested, we're ready to harvest again. - else if(seed.products && seed.products.len && age > seed.production && \ - (age - lastproduce) > seed.production && (!harvest && !dead)) - harvest = 1 - lastproduce = age - - if(prob(3)) // On each tick, there's a chance the pest population will increase - pestlevel += 1 * HYDRO_SPEED_MULTIPLIER - +/obj/machinery/portable_atmospherics/hydroponics/proc/check_health() + if(seed && !dead && health <= 0) + die() check_level_sanity() update_icon() - return + +/obj/machinery/portable_atmospherics/hydroponics/proc/die() + dead = 1 + harvest = 0 + weedlevel += 1 * HYDRO_SPEED_MULTIPLIER + pestlevel = 0 //Process reagents being input into the tray. /obj/machinery/portable_atmospherics/hydroponics/proc/process_reagents() @@ -351,8 +239,16 @@ if(reagents.total_volume <= 0) return - for(var/datum/reagent/R in reagents.reagent_list) +/* I have plans for this at a later date, so it's just being commented out for now --FalseIncarnate + reagents.trans_to(temp_chem_holder, min(reagents.total_volume,rand(1,3))) + + for(var/datum/reagent/R in temp_chem_holder.reagents.reagent_list) + + var/reagent_total = temp_chem_holder.reagents.get_reagent_amount(R.id) +*/ + + for(var/datum/reagent/R in reagents.reagent_list) var/reagent_total = reagents.get_reagent_amount(R.id) @@ -361,14 +257,14 @@ if(toxic_reagents[R.id]) toxins += toxic_reagents[R.id] * reagent_total if(weedkiller_reagents[R.id]) - weedlevel += weedkiller_reagents[R.id] * reagent_total + weedlevel -= weedkiller_reagents[R.id] * reagent_total if(pestkiller_reagents[R.id]) pestlevel += pestkiller_reagents[R.id] * reagent_total // Beneficial reagents have a few impacts along with health buffs. if(beneficial_reagents[R.id]) - health += beneficial_reagents[R.id][1] * reagent_total - yield_mod = min(100, yield_mod + (beneficial_reagents[R.id][2] * reagent_total)) + health += beneficial_reagents[R.id][1] * reagent_total + yield_mod = min(100, yield_mod + (beneficial_reagents[R.id][2] * reagent_total)) mutation_mod += beneficial_reagents[R.id][3] * reagent_total // Mutagen is distinct from the previous types and mostly has a chance of proccing a mutation. @@ -392,7 +288,7 @@ //--FalseIncarnate - // Handle nutrient refilling + // Handle nutrient refilling. if(nutrient_reagents[R.id]) nutrilevel += nutrient_reagents[R.id] * reagent_total @@ -403,42 +299,43 @@ water_added += water_input waterlevel += water_input + // Water dilutes toxin level. if(water_added > 0) toxins -= round(water_added/4) +// temp_chem_holder.reagents.clear_reagents() reagents.clear_reagents() - check_level_sanity() - update_icon() + check_health() //Harvests the product of a plant. /obj/machinery/portable_atmospherics/hydroponics/proc/harvest(var/mob/user) //Harvest the product of the plant, - if(!seed || !harvest || !user) + if(!seed || !harvest) return if(closed_system) - user << "You can't harvest from the plant while the lid is shut." + if(user) user << "You can't harvest from the plant while the lid is shut." return - seed.harvest(user,yield_mod) - //Increases harvest count for round-end score - //Currently per-plant (not per-item) harvested - // --FalseIncarnate - score_stuffharvested++ + if(user) + seed.harvest(user,yield_mod) + else + seed.harvest(get_turf(src),yield_mod) // Reset values. harvest = 0 lastproduce = age - if(!seed.harvest_repeat) + if(!seed.get_trait(TRAIT_HARVEST_REPEAT)) yield_mod = 0 seed = null dead = 0 age = 0 + sampled = 0 + mutation_mod = 0 - check_level_sanity() - update_icon() + check_health() return //Clears out a dead plant. @@ -451,101 +348,36 @@ seed = null dead = 0 - user << "You remove the dead plant from the [src]." - check_level_sanity() - update_icon() + sampled = 0 + age = 0 + yield_mod = 0 + mutation_mod = 0 + + user << "You remove the dead plant." + 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(draw_warnings && health <= (seed.endurance / 2)) - overlays += "over_lowhealth3" - - if(dead) - overlays += "[seed.plant_icon]-dead" - else if(harvest) - overlays += "[seed.plant_icon]-harvest" - else if(age < seed.maturation) - - var/t_growthstate - if(age >= seed.maturation) - t_growthstate = seed.growth_stages - else - t_growthstate = round(seed.maturation / seed.growth_stages) - - overlays += "[seed.plant_icon]-grow[t_growthstate]" - lastproduce = age - else - overlays += "[seed.plant_icon]-grow[seed.growth_stages]" - - //Draw the cover. - if(closed_system) - overlays += "hydrocover" - - //Updated the various alert icons. - if(draw_warnings) - 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.biolum) - SetLuminosity(round(seed.potency/10)) - if(seed.biolum_colour) - l_color = seed.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. if(seed) seed = null - seed = seed_types[pick(list("reishi","nettles","amanita","mushrooms","plumphelmet","towercap","harebells","weeds"))] + seed = plant_controller.seeds[pick(list("reishi","nettles","amanita","mushrooms","plumphelmet","towercap","harebells","weeds"))] if(!seed) return //Weed does not exist, someone fucked up. dead = 0 age = 0 - health = seed.endurance + health = seed.get_trait(TRAIT_ENDURANCE) lastcycle = world.time harvest = 0 weedlevel = 0 pestlevel = 0 + sampled = 0 update_icon() - visible_message("\blue [src] has been overtaken by [seed.display_name].") + visible_message("[src] has been overtaken by [seed.display_name].") return -/obj/machinery/portable_atmospherics/hydroponics/proc/check_level_sanity() - //Make sure various values are sane. - if(seed) - health = max(0,min(seed.endurance,health)) - else - health = 0 - dead = 0 - - nutrilevel = max(0,min(nutrilevel,maxnutri)) - waterlevel = max(0,min(waterlevel,maxwater)) - pestlevel = max(0,min(pestlevel,10)) - weedlevel = max(0,min(weedlevel,10)) - toxins = max(0,min(toxins,10)) - /obj/machinery/portable_atmospherics/hydroponics/proc/mutate(var/severity) // No seed, no mutations. @@ -561,20 +393,19 @@ Tier 4 has a higher chance of causing a species shift (if possible), and will ALWAYS cause a stat mutation if it does not shift species Tier 4 also has a low chance to cause a SECOND stat mutation when it does not shift species All mutation chances are increased by the mutation_mod value. Mutation_mod is not transferred into seeds/harvests, and is reset when the plant dies - */ switch(severity) //Reagent Tiers if(1) //Tier 1 if(prob(20+mutation_mod)) //Low chance of stat mutation - if(!isnull(seed_types[seed.name])) + if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() seed.mutate(1,get_turf(src)) return if(2) //Tier 2 if(prob(60+mutation_mod)) //Higher chance of stat mutation - if(!isnull(seed_types[seed.name])) + if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() seed.mutate(1,get_turf(src)) return @@ -583,12 +414,12 @@ if(seed.mutants. && seed.mutants.len) //Check if current seed/plant has mutant species mutate_species() else //No mutant species, mutate stats instead - if(!isnull(seed_types[seed.name])) + if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() seed.mutate(1,get_turf(src)) return else //Failed to shift, mutate stats instead - if(!isnull(seed_types[seed.name])) + if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() seed.mutate(1,get_turf(src)) return @@ -597,38 +428,38 @@ if(seed.mutants. && seed.mutants.len) //Check if current seed/plant has mutant species mutate_species() else //No mutant species, mutate stats instead - if(!isnull(seed_types[seed.name])) + if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() seed.mutate(1,get_turf(src)) if(prob(20+mutation_mod)) //Low chance for second stat mutation - if(!isnull(seed_types[seed.name])) + if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() seed.mutate(1,get_turf(src)) return else //Failed to shift, mutate stats instead - if(!isnull(seed_types[seed.name])) + if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() seed.mutate(1,get_turf(src)) if(prob(20+mutation_mod)) //Low chance for second stat mutation - if(!isnull(seed_types[seed.name])) + if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() seed.mutate(1,get_turf(src)) return //Floral Somatoray Tiers if("F1") //Random Stat Tier if(prob(80+mutation_mod)) //EVEN Higher chance of stat mutation - if(!isnull(seed_types[seed.name])) + if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() seed.mutate(1,get_turf(src)) return if("F2") //Yield Tier if(prob(40+mutation_mod)) //Medium chance of Yield stat mutation - if(!isnull(seed_types[seed.name])) + if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() - if(seed.immutable <= 0 && seed.yield != -1) //Check if the plant can be mutated and has a yield to mutate - seed.yield = seed.yield + rand(-2, 2) //Randomly adjust yield - if(seed.yield < 0) //If yield would drop below 0 after adjustment, set to 0 to allow further attempts - seed.yield = 0 + if(seed.get_trait(TRAIT_IMMUTABLE) <= 0 && seed.get_trait(TRAIT_YIELD) != -1) //Check if the plant can be mutated and has a yield to mutate + seed.set_trait(TRAIT_YIELD, (seed.get_trait(TRAIT_YIELD) + rand(-2, 2))) //Randomly adjust yield + if(seed.get_trait(TRAIT_YIELD) < 0) //If yield would drop below 0 after adjustment, set to 0 to allow further attempts + seed.set_trait(TRAIT_YIELD, 0) return /* code references @@ -642,19 +473,57 @@ //--FalseIncarnate +/obj/machinery/portable_atmospherics/hydroponics/verb/remove_label() + + set name = "Remove Label" + set category = "Object" + set src in view(1) + + if(labelled) + usr << "You remove the label." + labelled = null + update_icon() + else + usr << "There is no label to remove." + return + +/obj/machinery/portable_atmospherics/hydroponics/verb/set_light() + set name = "Set Light" + set category = "Object" + set src in view(1) + + var/new_light = input("Specify a light level.") as null|anything in list(0,1,2,3,4,5,6,7,8,9,10) + if(new_light) + tray_light = new_light + usr << "You set the tray to a light level of [tray_light] lumens." + +/obj/machinery/portable_atmospherics/hydroponics/proc/check_level_sanity() + //Make sure various values are sane. + if(seed) + health = max(0,min(seed.get_trait(TRAIT_ENDURANCE),health)) + else + health = 0 + dead = 0 + + nutrilevel = max(0,min(nutrilevel,10)) + waterlevel = max(0,min(waterlevel,100)) + pestlevel = max(0,min(pestlevel,10)) + weedlevel = max(0,min(weedlevel,10)) + toxins = max(0,min(toxins,10)) + /obj/machinery/portable_atmospherics/hydroponics/proc/mutate_species() var/previous_plant = seed.display_name var/newseed = seed.get_mutant_variant() - if(newseed in seed_types) - seed = seed_types[newseed] + if(newseed in plant_controller.seeds) + seed = plant_controller.seeds[newseed] else return dead = 0 //mutate(1) age = 0 - health = seed.endurance + health = seed.get_trait(TRAIT_ENDURANCE) lastcycle = world.time harvest = 0 weedlevel = 0 @@ -664,7 +533,8 @@ return -/obj/machinery/portable_atmospherics/hydroponics/attackby(var/obj/item/O as obj, var/mob/user as mob, params) + +/obj/machinery/portable_atmospherics/hydroponics/attackby(var/obj/item/O as obj, var/mob/user as mob) if(exchange_parts(user, O)) return @@ -692,35 +562,32 @@ process_reagents() update_icon() - //Check if container is one of the botany sprays (defined in hydro_tools.dm) + //Check if container is one of the plantsprays (defined in tray_reagents.dm) else if(istype(O, /obj/item/weapon/plantspray)) - //Check if spray is pest-spray - if(istype(O, /obj/item/weapon/plantspray/pests)) - var/obj/item/weapon/plantspray/P = O - user.drop_item(O) - toxins += P.toxicity - pestlevel -= P.pest_kill_str - weedlevel -= P.weed_kill_str - user << "You spray [src] with [O]." - playsound(loc, 'sound/effects/spray3.ogg', 50, 1, -6) - del(O) + var/obj/item/weapon/plantspray/P = O + user.drop_item(O) + toxins += P.toxicity + pestlevel -= P.pest_kill_str + weedlevel -= P.weed_kill_str + user << "You spray [src] with [O]." + playsound(loc, 'sound/effects/spray3.ogg', 50, 1, -6) + del(O) - check_level_sanity() - update_icon() + check_level_sanity() + update_icon() - //Check if spray is weed-spray (un-obtainable, fixed for possible repurposing?) - else if(istype(O, /obj/item/weapon/plantspray/weeds)) - var/obj/item/weapon/plantspray/W = O - user.drop_item(O) - toxins += W.toxicity - pestlevel -= W.pest_kill_str - weedlevel -= W.weed_kill_str - user << "You spray [src] with [O]." - playsound(loc, 'sound/effects/spray3.ogg', 50, 1, -6) - del(O) + //Check if spray is weedkiller (defined in tray_reagents.dm, un-obtainable currently) + else if(istype(O, /obj/item/weedkiller)) + var/obj/item/weedkiller/W = O + user.drop_item(O) + toxins += W.toxicity + weedlevel -= W.weed_kill_str + user << "You spray [src] with [O]." + playsound(loc, 'sound/effects/spray3.ogg', 50, 1, -6) + del(O) - check_level_sanity() - update_icon() + check_level_sanity() + update_icon() //Check if container is any spray container else if (istype(O, /obj/item/weapon/reagent_containers/spray)) @@ -739,35 +606,47 @@ else user << "There's nothing in [src] to spray!" - else if(istype(O, /obj/item/weapon/screwdriver) && unwrenchable) //THIS NEED TO BE DONE DIFFERENTLY, SOMEONE REFACTOR THE TRAY CODE ALREADY - if(anchored) - if(anchored == 2) - playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) - anchored = 1 - user << "You unscrew the [src]'s hoses." - panel_open = 0 + else if(istype(O, /obj/item/weapon/screwdriver) && unwrenchable) //THIS NEED TO BE DONE DIFFERENTLY, SOMEONE REFACTOR THE TRAY CODE ALREADY + if(anchored) + if(anchored == 2) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + anchored = 1 + user << "You unscrew the [src]'s hoses." + panel_open = 0 - else if(anchored == 1) - playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) - anchored = 2 - user << "You screw in the [src]'s hoses." - panel_open = 1 + else if(anchored == 1) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + anchored = 2 + user << "You screw in the [src]'s hoses." + panel_open = 1 - for(var/obj/machinery/portable_atmospherics/hydroponics/h in range(1,src)) - spawn() - h.update_icon() + for(var/obj/machinery/portable_atmospherics/hydroponics/h in range(1,src)) + spawn() + h.update_icon() - //Held item is not an open container, check to see if it can be used (this code was already here) --FalseIncarnate if(istype(O, /obj/item/weapon/wirecutters) || istype(O, /obj/item/weapon/scalpel)) if(!seed) user << "There is nothing to take a sample from in \the [src]." return - seed.harvest(user,yield_mod,1) - health -= (rand(1,5)*10) - check_level_sanity() + if(sampled) + user << "You have already sampled from this plant." + return + if(dead) + user << "The plant is dead." + return + + // Create a sample. + seed.harvest(user,yield_mod,1) + health -= (rand(3,5)*10) + + if(prob(30)) + sampled = 1 + + // Bookkeeping. + check_health() force_update = 1 process() @@ -781,14 +660,14 @@ if(seed) return ..() else - user << "There's no plant in the tray to inject." + user << "There's no plant to inject." return 1 else if(seed) //Leaving this in in case we want to extract from plants later. user << "You can't get any extract out of this plant." else - user << "There's nothing in the tray to draw something from." + user << "There's nothing to draw something from." return 1 else if (istype(O, /obj/item/seeds)) @@ -804,42 +683,28 @@ return user << "You plant the [S.seed.seed_name] [S.seed.seed_noun]." - - if(S.seed.spread == 1) - msg_admin_attack("[key_name(user)][isAntag(user) ? "(ANTAG)" : ""] has planted a creeper packet.") - var/obj/effect/plant_controller/creeper/PC = new(get_turf(src)) - if(PC) - PC.seed = S.seed - else if(S.seed.spread == 2) - msg_admin_attack("[key_name(user)][isAntag(user) ? "(ANTAG)" : ""] has planted a spreading vine packet.") - var/obj/effect/plant_controller/PC = new(get_turf(src)) - if(PC) - PC.seed = S.seed - else - seed = S.seed //Grab the seed datum. - dead = 0 - age = 1 - //Snowflakey, maybe move this to the seed datum - health = (istype(S, /obj/item/seeds/cutting) ? round(seed.endurance/rand(2,5)) : seed.endurance) - - lastcycle = world.time + seed = S.seed //Grab the seed datum. + dead = 0 + age = 1 + //Snowflakey, maybe move this to the seed datum + health = (istype(S, /obj/item/seeds/cutting) ? round(seed.get_trait(TRAIT_ENDURANCE)/rand(2,5)) : seed.get_trait(TRAIT_ENDURANCE)) + lastcycle = world.time del(O) - check_level_sanity() - update_icon() + check_health() else - user << "\red \The [src] already has seeds in it!" + user << "\The [src] already has seeds in it!" else if (istype(O, /obj/item/weapon/minihoe)) // The minihoe - //var/deweeding + if(weedlevel > 0) - user.visible_message("\red [user] starts uprooting the weeds.", "\red You remove the weeds from the [src].") + user.visible_message("[user] starts uprooting the weeds.", "You remove the weeds from the [src].") weedlevel = 0 update_icon() else - user << "\red This plot is completely devoid of weeds. It doesn't need uprooting." + user << "This plot is completely devoid of weeds. It doesn't need uprooting." else if (istype(O, /obj/item/weapon/storage/bag/plants)) @@ -851,7 +716,7 @@ return S.handle_item_insertion(G, 1) - else if(istype(O, /obj/item/weapon/wrench)) + else if(mechanical && istype(O, /obj/item/weapon/wrench)) //If there's a connector here, the portable_atmospherics setup can handle it. if(locate(/obj/machinery/atmospherics/portables_connector/) in loc) @@ -864,7 +729,7 @@ else if(istype(O, /obj/item/apiary)) if(seed) - user << "\red [src] is already occupied!" + user << "[src] is already occupied!" else user.drop_item() del(O) @@ -874,15 +739,18 @@ A.icon_state = src.icon_state A.hydrotray_type = src.type del(src) + else if(O && O.force && seed) + user.visible_message("\The [seed.display_name] has been attacked by [user] with \the [O]!") + if(!dead) + health -= O.force + check_health() return /obj/machinery/portable_atmospherics/hydroponics/attack_tk(mob/user as mob) - - if(harvest) - harvest(user) - - else if(dead) + if(dead) remove_dead(user) + else if(harvest) + harvest(user) /obj/machinery/portable_atmospherics/hydroponics/attack_hand(mob/user as mob) @@ -894,35 +762,50 @@ else if(dead) remove_dead(user) - else - if(seed && !dead) - usr << "[src] has \blue [seed.display_name] \black planted." - if(health <= (seed.endurance / 2)) - usr << "The plant looks \red unhealthy." +/obj/machinery/portable_atmospherics/hydroponics/examine() + + ..() + + if(!seed) + usr << "[src] is empty." + return + + usr << "[seed.display_name] are growing here." + + if(!Adjacent(usr)) + return + + usr << "Water: [round(waterlevel,0.1)]/100" + usr << "Nutrient: [round(nutrilevel,0.1)]/10" + + if(weedlevel >= 5) + usr << "\The [src] is infested with weeds!" + if(pestlevel >= 5) + usr << "\The [src] is infested with tiny worms!" + + if(dead) + usr << "The plant is dead." + else if(health <= (seed.get_trait(TRAIT_ENDURANCE)/ 2)) + usr << "The plant looks unhealthy." + + if(mechanical) + var/turf/T = loc + var/datum/gas_mixture/environment + + if(closed_system && (connected_port || holding)) + environment = air_contents + + if(!environment) + if(istype(T)) + environment = T.return_air() + + if(!environment) //We're in a crate or nullspace, bail out. + return + + var/light_string + if(closed_system && mechanical) + light_string = "that the internal lights are set to [tray_light] lumens" else - usr << "[src] is empty." - usr << "Water: [round(waterlevel,0.1)]/[maxwater]" - usr << "Nutrient: [round(nutrilevel,0.1)]/[maxnutri]" - if(weedlevel >= 5) - usr << "[src] is \red filled with weeds!" - if(pestlevel >= 5) - usr << "[src] is \red filled with tiny worms!" - - if(!istype(src,/obj/machinery/portable_atmospherics/hydroponics/soil)) - - var/turf/T = loc - var/datum/gas_mixture/environment - - if(closed_system && (connected_port || holding)) - environment = air_contents - - if(!environment) - if(istype(T)) - environment = T.return_air() - - if(!environment) //We're in a crate or nullspace, bail out. - return - var/area/A = T.loc var/light_available if(A) @@ -930,45 +813,20 @@ light_available = max(0,min(10,T.lighting_lumcount)-5) else light_available = 5 + light_string = "a light level of [light_available] lumens" - usr << "The tray's sensor suite is reporting a light level of [light_available] lumens and a temperature of [environment.temperature]K." + usr << "The tray's sensor suite is reporting [light_string] and a temperature of [environment.temperature]K." -/obj/machinery/portable_atmospherics/hydroponics/verb/close_lid() +/obj/machinery/portable_atmospherics/hydroponics/verb/close_lid_verb() set name = "Toggle Tray Lid" set category = "Object" set src in view(1) + close_lid(usr) - if(!usr || usr.stat || usr.restrained()) +/obj/machinery/portable_atmospherics/hydroponics/proc/close_lid(var/mob/living/user) + if(!user || user.stat || user.restrained()) return closed_system = !closed_system - usr << "You [closed_system ? "close" : "open"] the tray's lid." - if(closed_system) - flags &= ~OPENCONTAINER - else - flags |= OPENCONTAINER - + user << "You [closed_system ? "close" : "open"] the tray's lid." update_icon() - -/obj/machinery/portable_atmospherics/hydroponics/soil - name = "soil" - icon = 'icons/obj/hydroponics.dmi' - icon_state = "soil" - density = 0 - use_power = 0 - draw_warnings = 0 - -/obj/machinery/portable_atmospherics/hydroponics/soil/attackby(var/obj/item/O as obj, var/mob/user as mob, params) - if(istype(O, /obj/item/weapon/shovel)) - user << "You clear up [src]!" - del(src) - else if(istype(O,/obj/item/weapon/shovel) || istype(O,/obj/item/weapon/tank)) - return - else - ..() - -/obj/machinery/portable_atmospherics/hydroponics/soil/New() - ..() - verbs -= /obj/machinery/portable_atmospherics/hydroponics/verb/close_lid - -#undef HYDRO_SPEED_MULTIPLIER diff --git a/code/modules/hydroponics/trays/tray_apiary.dm b/code/modules/hydroponics/trays/tray_apiary.dm new file mode 100644 index 00000000000..f2098e7481c --- /dev/null +++ b/code/modules/hydroponics/trays/tray_apiary.dm @@ -0,0 +1,240 @@ +//http://www.youtube.com/watch?v=-1GadTfGFvU +//i could have done these as just an ordinary plant, but fuck it - there would have been too much snowflake code + +/obj/machinery/apiary + name = "apiary tray" + icon = 'icons/obj/hydroponics_machines.dmi' + icon_state = "hydrotray3" + density = 1 + anchored = 1 + var/nutrilevel = 0 + var/yieldmod = 1 + var/mut = 1 + var/toxic = 0 + var/dead = 0 + var/health = -1 + var/maxhealth = 100 + var/lastcycle = 0 + var/cycledelay = 100 + var/harvestable_honey = 0 + var/beezeez = 0 + var/swarming = 0 + + var/bees_in_hive = 0 + var/list/owned_bee_swarms = list() + var/hydrotray_type = /obj/machinery/portable_atmospherics/hydroponics + +//overwrite this after it's created if the apiary needs a custom machinery sprite +/obj/machinery/apiary/New() + ..() + overlays += image('icons/obj/apiary_bees_etc.dmi', icon_state="apiary") + +/obj/machinery/apiary/bullet_act(var/obj/item/projectile/Proj) //Works with the Somatoray to modify plant variables. + if(istype(Proj ,/obj/item/projectile/energy/floramut)) + mut++ + else if(istype(Proj ,/obj/item/projectile/energy/florayield)) + if(!yieldmod) + yieldmod += 1 + //world << "Yield increased by 1, from 0, to a total of [myseed.yield]" + else if (prob(1/(yieldmod * yieldmod) *100))//This formula gives you diminishing returns based on yield. 100% with 1 yield, decreasing to 25%, 11%, 6, 4, 2... + yieldmod += 1 + //world << "Yield increased by 1, to a total of [myseed.yield]" + else + ..() + return + +/obj/machinery/apiary/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(istype(O, /obj/item/queen_bee)) + if(health > 0) + user << "\red There is already a queen in there." + else + health = 10 + nutrilevel += 10 + user.drop_item() + del(O) + user << "\blue You carefully insert the queen into [src], she gets busy making a hive." + bees_in_hive = 0 + else if(istype(O, /obj/item/beezeez)) + beezeez += 100 + nutrilevel += 10 + user.drop_item() + if(health > 0) + user << "\blue You insert [O] into [src]. A relaxed humming appears to pick up." + else + user << "\blue You insert [O] into [src]. Now it just needs some bees." + del(O) + else if(istype(O, /obj/item/weapon/minihoe)) + if(health > 0) + user << "\red You begin to dislodge the apiary from the tray, the bees don't like that." + angry_swarm(user) + else + user << "\blue You begin to dislodge the dead apiary from the tray." + if(do_after(user, 50)) + new hydrotray_type(src.loc) + new /obj/item/apiary(src.loc) + user << "\red You dislodge the apiary from the tray." + del(src) + else if(istype(O, /obj/item/weapon/bee_net)) + var/obj/item/weapon/bee_net/N = O + if(N.caught_bees > 0) + user << "\blue You empty the bees into the apiary." + bees_in_hive += N.caught_bees + N.caught_bees = 0 + else + user << "\blue There are no more bees in the net." + else if(istype(O, /obj/item/weapon/reagent_containers/glass)) + var/obj/item/weapon/reagent_containers/glass/G = O + if(harvestable_honey > 0) + if(health > 0) + user << "\red You begin to harvest the honey. The bees don't seem to like it." + angry_swarm(user) + else + user << "\blue You begin to harvest the honey." + if(do_after(user,50)) + G.reagents.add_reagent("honey",harvestable_honey) + harvestable_honey = 0 + user << "\blue You successfully harvest the honey." + else + user << "\blue There is no honey left to harvest." + else + angry_swarm(user) + ..() + +/obj/machinery/apiary/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group || (height==0)) return 1 + + if(istype(mover) && mover.checkpass(PASSTABLE)) + return 1 + else + return 0 + +/obj/machinery/apiary/process() + + if(swarming > 0) + swarming -= 1 + if(swarming <= 0) + for(var/mob/living/simple_animal/bee/B in src.loc) + bees_in_hive += B.strength + del(B) + else if(bees_in_hive < 10) + for(var/mob/living/simple_animal/bee/B in src.loc) + bees_in_hive += B.strength + del(B) + + if(world.time > (lastcycle + cycledelay)) + lastcycle = world.time + if(health < 0) + return + + //magical bee formula + if(beezeez > 0) + beezeez -= 1 + + nutrilevel += 2 + health += 1 + toxic = max(0, toxic - 1) + + //handle nutrients + nutrilevel -= bees_in_hive / 10 + owned_bee_swarms.len / 5 + if(nutrilevel > 0) + bees_in_hive += 1 * yieldmod + if(health < maxhealth) + health++ + else + //nutrilevel is less than 1, so we're effectively subtracting here + health += max(nutrilevel - 1, round(-health / 2)) + bees_in_hive += max(nutrilevel - 1, round(-bees_in_hive / 2)) + if(owned_bee_swarms.len) + var/mob/living/simple_animal/bee/B = pick(owned_bee_swarms) + B.target_turf = get_turf(src) + + //clear out some toxins + if(toxic > 0) + toxic -= 1 + health -= 1 + + if(health <= 0) + return + + //make a bit of honey + if(harvestable_honey < 50) + harvestable_honey += 0.5 + + //make some new bees + if(bees_in_hive >= 10 && prob(bees_in_hive * 10)) + var/mob/living/simple_animal/bee/B = new(get_turf(src), src) + owned_bee_swarms.Add(B) + B.mut = mut + B.toxic = toxic + bees_in_hive -= 1 + + //find some plants, harvest + for(var/obj/machinery/portable_atmospherics/hydroponics/H in view(7, src)) + if(H.seed && !H.dead && prob(owned_bee_swarms.len * 10)) + src.nutrilevel++ + H.nutrilevel++ + if(mut < H.mutation_mod - 1) + mut = H.mutation_mod - 1 + else if(mut > H.mutation_mod - 1) + H.mutation_mod = mut + + //flowers give us pollen (nutrients) +/* - All plants should be giving nutrients to the hive. + if(H.myseed.type == /obj/item/seeds/harebell || H.myseed.type == /obj/item/seeds/sunflowerseed) + src.nutrilevel++ + H.nutrilevel++ +*/ + //have a few beneficial effects on nearby plants + if(prob(10)) + H.lastcycle -= 5 + if(prob(10)) + H.seed.set_trait(TRAIT_ENDURANCE,max(H.seed.get_trait(TRAIT_ENDURANCE)*1.5,H.seed.get_trait(TRAIT_ENDURANCE)+1)) + if(H.toxins && prob(10)) + H.toxins = min(0, H.toxins - 1) + toxic++ + +/obj/machinery/apiary/proc/die() + if(owned_bee_swarms.len) + var/mob/living/simple_animal/bee/B = pick(owned_bee_swarms) + B.target_turf = get_turf(src) + B.strength -= 1 + if(B.strength <= 0) + del(B) + else if(B.strength <= 5) + B.icon_state = "bees[B.strength]" + bees_in_hive = 0 + health = 0 + +/obj/machinery/apiary/proc/angry_swarm(var/mob/M) + for(var/mob/living/simple_animal/bee/B in owned_bee_swarms) + B.feral = 25 + B.target_mob = M + + swarming = 25 + + while(bees_in_hive > 0) + var/spawn_strength = bees_in_hive + if(bees_in_hive >= 5) + spawn_strength = 6 + + var/mob/living/simple_animal/bee/B = new(get_turf(src), src) + B.target_mob = M + B.strength = spawn_strength + B.feral = 25 + B.mut = mut + B.toxic = toxic + bees_in_hive -= spawn_strength + +/obj/machinery/apiary/verb/harvest_honeycomb() + set src in oview(1) + set name = "Harvest honeycomb" + set category = "Object" + + while(health > 15) + health -= 15 + var/obj/item/weapon/reagent_containers/food/snacks/honeycomb/H = new(src.loc) + if(toxic > 0) + H.reagents.add_reagent("toxin", toxic) + + usr << "\blue You harvest the honeycomb from the hive. There is a wild buzzing!" + angry_swarm(usr) diff --git a/code/modules/hydroponics/trays/tray_process.dm b/code/modules/hydroponics/trays/tray_process.dm new file mode 100644 index 00000000000..d16ca75cc97 --- /dev/null +++ b/code/modules/hydroponics/trays/tray_process.dm @@ -0,0 +1,124 @@ +/obj/machinery/portable_atmospherics/hydroponics/process() + + /* MOVED INTO code\game\objects\effects\effect_system.dm + // Handle nearby smoke if any. + for(var/obj/effect/effect/smoke/chem/smoke in view(1, src)) + if(smoke.reagents.total_volume) + smoke.reagents.copy_to(src, 5) + */ + + //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 + + // 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) + + // 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. + if(mechanical && closed_system) + health -= seed.handle_environment(T,environment,tray_light) + else + 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((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 00000000000..5e5cb819b98 --- /dev/null +++ b/code/modules/hydroponics/trays/tray_reagents.dm @@ -0,0 +1,126 @@ + +/obj/item/weapon/plantspray + icon = 'icons/obj/hydroponics_machines.dmi' + item_state = "spray" + flags = OPENCONTAINER | 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 + + +// ************************************* +// Weedkiller defines for hydroponics +// ************************************* + +/obj/item/weedkiller + name = "bottle of weedkiller" + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle16" + flags = OPENCONTAINER | NOBLUDGEON + var/toxicity = 0 + var/weed_kill_str = 0 + +/obj/item/weedkiller/triclopyr + name = "bottle of glyphosate" + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle16" + toxicity = 4 + weed_kill_str = 2 + +/obj/item/weedkiller/lindane + name = "bottle of triclopyr" + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle18" + toxicity = 6 + weed_kill_str = 4 + +/obj/item/weedkiller/D24 + name = "bottle of 2,4-D" + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle15" + 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 = 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 00000000000..ff8e3e23df0 --- /dev/null +++ b/code/modules/hydroponics/trays/tray_soil.dm @@ -0,0 +1,67 @@ +/obj/machinery/portable_atmospherics/hydroponics/soil + name = "soil" + icon_state = "soil" + density = 0 + use_power = 0 + mechanical = 0 + tray_light = 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_verb + verbs -= /obj/machinery/portable_atmospherics/hydroponics/verb/remove_label + verbs -= /obj/machinery/portable_atmospherics/hydroponics/verb/set_light + +/obj/machinery/portable_atmospherics/hydroponics/soil/CanPass() + return 1 + +// Holder for vine plants. +// 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) // Repeat harvests are a thing. + 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) + ..() diff --git a/code/modules/hydroponics/hydro_tools.dm b/code/modules/hydroponics/trays/tray_tools.dm similarity index 53% rename from code/modules/hydroponics/hydro_tools.dm rename to code/modules/hydroponics/trays/tray_tools.dm index 70cf1f9cf4b..df21cfa90d6 100644 --- a/code/modules/hydroponics/hydro_tools.dm +++ b/code/modules/hydroponics/trays/tray_tools.dm @@ -9,8 +9,38 @@ icon = 'icons/obj/device.dmi' icon_state = "hydro" item_state = "analyzer" + var/form_title + var/last_data + +/obj/item/device/analyzer/plant_analyzer/proc/print_report_verb() + set name = "Print Plant Report" + set category = "Object" + set src = usr + + if(usr.stat || usr.restrained() || usr.lying) + return + print_report(usr) + +/obj/item/device/analyzer/plant_analyzer/Topic(href, href_list) + if(..()) + return + if(href_list["print"]) + print_report(usr) + +/obj/item/device/analyzer/plant_analyzer/proc/print_report(var/mob/living/user) + if(!last_data) + user << "There is no scan data to print." + return + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(get_turf(src)) + P.name = "paper - [form_title]" + P.info = "[last_data]" + if(istype(user,/mob/living/carbon/human) && !(user.l_hand && user.r_hand)) + user.put_in_hands(P) + user.visible_message("\The [src] spits out a piece of paper.") + return /obj/item/device/analyzer/plant_analyzer/attack_self(mob/user as mob) + print_report(user) return 0 /obj/item/device/analyzer/plant_analyzer/afterattack(obj/target, mob/user, flag) @@ -29,16 +59,18 @@ var/tray_mutation_mod //mutation modifier of the tray //--FalseIncarnate - if(istype(target,/obj/item/weapon/reagent_containers/food/snacks/grown)) + if(istype(target,/obj/structure/table)) + return ..() + else if(istype(target,/obj/item/weapon/reagent_containers/food/snacks/grown)) var/obj/item/weapon/reagent_containers/food/snacks/grown/G = target - grown_seed = seed_types[G.plantname] + grown_seed = plant_controller.seeds[G.plantname] grown_reagents = G.reagents else if(istype(target,/obj/item/weapon/grown)) var/obj/item/weapon/grown/G = target - grown_seed = seed_types[G.plantname] + grown_seed = plant_controller.seeds[G.plantname] grown_reagents = G.reagents else if(istype(target,/obj/item/seeds)) @@ -66,21 +98,21 @@ grown_reagents = H.reagents if(!grown_seed) - user << "\red [src] can tell you nothing about [target]." + user << "[src] can tell you nothing about \the [target]." return - var/dat = "

Plant data for [target]

" - user.visible_message("\blue [user] runs the scanner over [target].") + form_title = "[grown_seed.seed_name] (#[grown_seed.uid])" + var/dat = "

Plant data for [form_title]

" + user.visible_message("[user] runs the scanner over \the [target].") dat += "

General Data

" dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" //--FalseIncarnate //Tray-specific stats like Age and Mutation Modifier, not shown if target was not a hydroponics tray or soil @@ -105,29 +137,26 @@ dat += "

Other Data

" - if(grown_seed.harvest_repeat) + if(grown_seed.get_trait(TRAIT_HARVEST_REPEAT)) dat += "This plant can be harvested repeatedly.
" - if(grown_seed.immutable == -1) + if(grown_seed.get_trait(TRAIT_IMMUTABLE) == -1) dat += "This plant is highly mutable.
" - else if(grown_seed.immutable > 0) + else if(grown_seed.get_trait(TRAIT_IMMUTABLE) > 0) dat += "This plant does not possess genetics that are alterable.
" - if(grown_seed.products && grown_seed.products.len) - dat += "The mature plant will produce [grown_seed.products.len == 1 ? "fruit" : "[grown_seed.products.len] varieties of fruit"].
" - - if(grown_seed.requires_nutrients) - if(grown_seed.nutrient_consumption < 0.05) + if(grown_seed.get_trait(TRAIT_REQUIRES_NUTRIENTS)) + if(grown_seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) < 0.05) dat += "It consumes a small amount of nutrient fluid.
" - else if(grown_seed.nutrient_consumption > 0.2) + else if(grown_seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) > 0.2) dat += "It requires a heavy supply of nutrient fluid.
" else dat += "It requires a supply of nutrient fluid.
" - if(grown_seed.requires_water) - if(grown_seed.water_consumption < 1) + if(grown_seed.get_trait(TRAIT_REQUIRES_WATER)) + if(grown_seed.get_trait(TRAIT_WATER_CONSUMPTION) < 1) dat += "It requires very little water.
" - else if(grown_seed.water_consumption > 5) + else if(grown_seed.get_trait(TRAIT_WATER_CONSUMPTION) > 5) dat += "It requires a large amount of water.
" else dat += "It requires a stable supply of water.
" @@ -135,120 +164,84 @@ if(grown_seed.mutants && grown_seed.mutants.len) dat += "It exhibits a high degree of potential subspecies shift.
" - dat += "It thrives in a temperature of [grown_seed.ideal_heat] Kelvin." + dat += "It thrives in a temperature of [grown_seed.get_trait(TRAIT_IDEAL_HEAT)] Kelvin." - if(grown_seed.lowkpa_tolerance < 20) + if(grown_seed.get_trait(TRAIT_LOWKPA_TOLERANCE) < 20) dat += "
It is well adapted to low pressure levels." - if(grown_seed.highkpa_tolerance > 220) + if(grown_seed.get_trait(TRAIT_HIGHKPA_TOLERANCE) > 220) dat += "
It is well adapted to high pressure levels." - if(grown_seed.heat_tolerance > 30) + if(grown_seed.get_trait(TRAIT_HEAT_TOLERANCE) > 30) dat += "
It is well adapted to a range of temperatures." - else if(grown_seed.heat_tolerance < 10) + else if(grown_seed.get_trait(TRAIT_HEAT_TOLERANCE) < 10) dat += "
It is very sensitive to temperature shifts." - dat += "
It thrives in a light level of [grown_seed.ideal_light] lumen[grown_seed.ideal_light == 1 ? "" : "s"]." + dat += "
It thrives in a light level of [grown_seed.get_trait(TRAIT_IDEAL_LIGHT)] lumen[grown_seed.get_trait(TRAIT_IDEAL_LIGHT) == 1 ? "" : "s"]." - if(grown_seed.light_tolerance > 10) + if(grown_seed.get_trait(TRAIT_LIGHT_TOLERANCE) > 10) dat += "
It is well adapted to a range of light levels." - else if(grown_seed.light_tolerance < 3) + else if(grown_seed.get_trait(TRAIT_LIGHT_TOLERANCE) < 3) dat += "
It is very sensitive to light level shifts." - if(grown_seed.toxins_tolerance < 3) + if(grown_seed.get_trait(TRAIT_TOXINS_TOLERANCE) < 3) dat += "
It is highly sensitive to toxins." - else if(grown_seed.toxins_tolerance > 6) + else if(grown_seed.get_trait(TRAIT_TOXINS_TOLERANCE) > 6) dat += "
It is remarkably resistant to toxins." - if(grown_seed.pest_tolerance < 3) + if(grown_seed.get_trait(TRAIT_PEST_TOLERANCE) < 3) dat += "
It is highly sensitive to pests." - else if(grown_seed.pest_tolerance > 6) + else if(grown_seed.get_trait(TRAIT_PEST_TOLERANCE) > 6) dat += "
It is remarkably resistant to pests." - if(grown_seed.weed_tolerance < 3) + if(grown_seed.get_trait(TRAIT_WEED_TOLERANCE) < 3) dat += "
It is highly sensitive to weeds." - else if(grown_seed.weed_tolerance > 6) + else if(grown_seed.get_trait(TRAIT_WEED_TOLERANCE) > 6) dat += "
It is remarkably resistant to weeds." - switch(grown_seed.spread) + switch(grown_seed.get_trait(TRAIT_SPREAD)) if(1) - dat += "
It is capable of growing beyond the confines of a tray." + dat += "
It is able to be planted outside of a tray." if(2) dat += "
It is a robust and vigorous vine that will spread rapidly." - switch(grown_seed.carnivorous) + switch(grown_seed.get_trait(TRAIT_CARNIVOROUS)) if(1) dat += "
It is carniovorous and will eat tray pests for sustenance." if(2) dat += "
It is carnivorous and poses a significant threat to living things around it." - if(grown_seed.parasite) + if(grown_seed.get_trait(TRAIT_PARASITE)) dat += "
It is capable of parisitizing and gaining sustenance from tray weeds." - if(grown_seed.alter_temp) - dat += "
It will periodically alter the local temperature by [grown_seed.alter_temp] degrees Kelvin." + if(grown_seed.get_trait(TRAIT_ALTER_TEMP)) + dat += "
It will periodically alter the local temperature by [grown_seed.get_trait(TRAIT_ALTER_TEMP)] degrees Kelvin." - if(grown_seed.biolum) - dat += "
It is [grown_seed.biolum_colour ? "bio-luminescent" : "bio-luminescent"]." - if(grown_seed.flowers) - dat += "
It has [grown_seed.flower_colour ? "flowers" : "flowers"]." + if(grown_seed.get_trait(TRAIT_BIOLUM)) + dat += "
It is [grown_seed.get_trait(TRAIT_BIOLUM_COLOUR) ? "bio-luminescent" : "bio-luminescent"]." + + if(grown_seed.get_trait(TRAIT_PRODUCES_POWER)) + dat += "
The fruit will function as a battery if prepared appropriately." + + if(grown_seed.get_trait(TRAIT_STINGS)) + dat += "
The fruit is covered in stinging spines." + + if(grown_seed.get_trait(TRAIT_JUICY) == 1) + dat += "
The fruit is soft-skinned and juicy." + else if(grown_seed.get_trait(TRAIT_JUICY) == 2) + dat += "
The fruit is excessively juicy." + + if(grown_seed.get_trait(TRAIT_EXPLOSIVE)) + dat += "
The fruit is internally unstable." + + if(grown_seed.get_trait(TRAIT_TELEPORTING)) + dat += "
The fruit is temporal/spatially unstable." if(dat) + last_data = dat + dat += "

\[print report\]" user << browse(dat,"window=plant_analyzer") return -// ************************************* -// Hydroponics Tools -// ************************************* - -/obj/item/weapon/plantspray - icon = 'icons/obj/hydroponics.dmi' - item_state = "spray" - flags = OPENCONTAINER | 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 = 2 - -/obj/item/weapon/plantspray/pests - name = "pest-spray" - desc = "It's some pest eliminator spray! Do not inhale!" - icon_state = "pestspray" - pest_kill_str = 2 - -/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." @@ -259,85 +252,9 @@ force = 5.0 throwforce = 7.0 w_class = 2.0 + m_amt = 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" - var/toxicity = 0 - var/weed_kill_str = 0 - -/obj/item/weedkiller/triclopyr - name = "bottle of glyphosate" - icon = 'icons/obj/chemical.dmi' - icon_state = "bottle16" - toxicity = 4 - weed_kill_str = 2 - -/obj/item/weedkiller/lindane - name = "bottle of triclopyr" - icon = 'icons/obj/chemical.dmi' - icon_state = "bottle18" - toxicity = 6 - weed_kill_str = 4 - -/obj/item/weedkiller/D24 - name = "bottle of 2,4-D" - icon = 'icons/obj/chemical.dmi' - icon_state = "bottle15" - 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 = 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" - //Hatchets and things to kill kudzu /obj/item/weapon/hatchet name = "hatchet" @@ -368,6 +285,15 @@ icon_state = "unathiknife" attack_verb = list("ripped", "torn", "cut") +/obj/item/weapon/hatchet/tacknife + name = "tactical knife" + desc = "You'd be killing loads of people if this was Medal of Valor: Heroes of Nyx." + icon = 'icons/obj/weapons.dmi' + icon_state = "tacknife" + item_state = "knife" + attack_verb = list("stabbed", "chopped", "cut") + + /obj/item/weapon/scythe icon_state = "scythe0" name = "scythe" @@ -384,8 +310,8 @@ /obj/item/weapon/scythe/afterattack(atom/A, mob/user as mob, proximity) if(!proximity) return - if(istype(A, /obj/effect/plantsegment)) - for(var/obj/effect/plantsegment/B in orange(A,1)) + if(istype(A, /obj/effect/plant)) + for(var/obj/effect/plant/B in orange(A,1)) if(prob(80)) - del B + B.die_off(1) del A \ No newline at end of file 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 00000000000..61e19632ea1 --- /dev/null +++ b/code/modules/hydroponics/trays/tray_update_icons.dm @@ -0,0 +1,84 @@ +//Refreshes the icon and sets the luminosity +/obj/machinery/portable_atmospherics/hydroponics/update_icon() + // Update name. + if(seed) + if(mechanical) + name = "[base_name] (#[seed.uid])" + else + name = "[seed.seed_name]" + else + name = initial(name) + + if(labelled) + name += " ([labelled])" + + 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_controller.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 + var/maturation = round(seed.get_trait(TRAIT_MATURATION)/seed.growth_stages) + overlay_stage = maturation ? max(1,round(age/maturation)) : 1 + var/ikey = "[seed.get_trait(TRAIT_PLANT_ICON)]-[overlay_stage]" + var/image/plant_overlay = plant_controller.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_controller.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_controller.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_controller.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 diff --git a/code/modules/hydroponics/vines.dm b/code/modules/hydroponics/vines.dm deleted file mode 100644 index 35d321789e0..00000000000 --- a/code/modules/hydroponics/vines.dm +++ /dev/null @@ -1,386 +0,0 @@ -// SPACE VINES (Note that this code is very similar to Biomass code) -/obj/effect/plantsegment - name = "space vines" - desc = "An extremely expansionistic species of vine." - icon = 'icons/effects/spacevines.dmi' - icon_state = "Light1" - anchored = 1 - density = 0 - layer = 5 - pass_flags = PASSTABLE | PASSGRILLE - - // Vars used by vines with seed data. - var/age = 0 - var/lastproduce = 0 - var/harvest = 0 - var/list/chems - var/plant_damage_noun = "Thorns" - var/limited_growth = 0 - - // Life vars/ - var/energy = 0 - var/obj/effect/plant_controller/master = null - var/mob/living/buckled_mob - var/datum/seed/seed - -/obj/effect/plantsegment/New() - return - -/obj/effect/plantsegment/Del() - if(master) - master.vines -= src - master.growth_queue -= src - ..() - -/obj/effect/plantsegment/attackby(obj/item/weapon/W as obj, mob/user as mob, params) - if (!W || !user || !W.type) return - switch(W.type) - if(/obj/item/weapon/circular_saw) del src - if(/obj/item/weapon/kitchen/utensil/knife) del src - if(/obj/item/weapon/scalpel) del src - if(/obj/item/weapon/twohanded/fireaxe) del src - if(/obj/item/weapon/hatchet) del src - if(/obj/item/weapon/melee/energy) del src - - // Less effective weapons - if(/obj/item/weapon/wirecutters) - if(prob(25)) del src - if(/obj/item/weapon/shard) - if(prob(25)) del src - - // Weapons with subtypes - else - if(istype(W, /obj/item/weapon/melee/energy/sword)) del src - else if(istype(W, /obj/item/weapon/weldingtool)) - var/obj/item/weapon/weldingtool/WT = W - if(WT.remove_fuel(0, user)) del src - else - manual_unbuckle(user) - return - // Plant-b-gone damage is handled in its entry in chemistry-reagents.dm - ..() - - -/obj/effect/plantsegment/attack_hand(mob/user as mob) - - if(user.a_intent == "help" && seed && harvest) - seed.harvest(user,1) - harvest = 0 - lastproduce = age - update() - return - - manual_unbuckle(user) - - -/obj/effect/plantsegment/attack_paw(mob/user as mob) - manual_unbuckle(user) - -/obj/effect/plantsegment/proc/unbuckle() - if(buckled_mob) - if(buckled_mob.buckled == src) //this is probably unneccesary, but it doesn't hurt - buckled_mob.buckled = null - buckled_mob.anchored = initial(buckled_mob.anchored) - buckled_mob.update_canmove() - buckled_mob = null - return - -/obj/effect/plantsegment/proc/manual_unbuckle(mob/user as mob) - if(buckled_mob) - if(prob(seed ? min(max(0,100 - seed.potency),100) : 50)) - if(buckled_mob.buckled == src) - if(buckled_mob != user) - buckled_mob.visible_message(\ - "[user.name] frees [buckled_mob.name] from [src].",\ - "[user.name] frees you from [src].",\ - "You hear shredding and ripping.") - else - buckled_mob.visible_message(\ - "[buckled_mob.name] struggles free of [src].",\ - "You untangle [src] from around yourself.",\ - "You hear shredding and ripping.") - unbuckle() - else - var/text = pick("rips","tears","pulls") - user.visible_message(\ - "[user.name] [text] at [src].",\ - "You [text] at [src].",\ - "You hear shredding and ripping.") - return - -/obj/effect/plantsegment/proc/grow() - - if(!energy) - src.icon_state = pick("Med1", "Med2", "Med3") - energy = 1 - - //Low-lying creepers do not block vision or grow thickly. - if(limited_growth) - energy = 2 - return - - src.opacity = 1 - layer = 5 - else if(!limited_growth) - src.icon_state = pick("Hvy1", "Hvy2", "Hvy3") - energy = 2 - -/obj/effect/plantsegment/proc/entangle_mob() - - if(limited_growth) - return - - if(prob(seed ? seed.potency : 25)) - - if(!buckled_mob) - var/mob/living/carbon/V = locate() in src.loc - if(V && (V.stat != DEAD) && (V.buckled != src)) // If mob exists and is not dead or captured. - V.buckled = src - V.loc = src.loc - V.update_canmove() - src.buckled_mob = V - V << "The vines [pick("wind", "tangle", "tighten")] around you!" - - // FEED ME, SEYMOUR. - if(buckled_mob && seed && (buckled_mob.stat != DEAD)) //Don't bother with a dead mob. - - var/mob/living/M = buckled_mob - if(!istype(M)) return - var/mob/living/carbon/human/H = buckled_mob - - // Drink some blood/cause some brute. - if(seed.carnivorous == 2) - buckled_mob << "\The [src] pierces your flesh greedily!" - - var/damage = rand(round(seed.potency/2),seed.potency) - if(!istype(H)) - H.adjustBruteLoss(damage) - return - - var/obj/item/organ/external/affecting = H.get_organ(pick("l_foot","r_foot","l_leg","r_leg","l_hand","r_hand","l_arm", "r_arm","head","chest","groin")) - - if(affecting) - affecting.take_damage(damage, 0) - if(affecting.parent) - affecting.parent.add_autopsy_data("[plant_damage_noun]", damage) - else - H.adjustBruteLoss(damage) - - H.UpdateDamageIcon() - H.updatehealth() - - // Inject some chems. - if(seed.chems && seed.chems.len && istype(H)) - H << "You feel something seeping into your skin!" - for(var/rid in seed.chems) - var/injecting = min(5,max(1,seed.potency/5)) - H.reagents.add_reagent(rid,injecting) - -/obj/effect/plantsegment/proc/update() - if(!seed) return - - // Update bioluminescence. - if(seed.biolum) - SetLuminosity(1+round(seed.potency/10)) - if(seed.biolum_colour) - l_color = seed.biolum_colour - else - l_color = null - return - else - SetLuminosity(0) - - // Update flower/product overlay. - overlays.Cut() - if(age >= seed.maturation) - if(prob(20) && seed.products && seed.products.len && !harvest && ((age-lastproduce) > seed.production)) - harvest = 1 - lastproduce = age - - if(harvest) - var/image/fruit_overlay = image('icons/obj/hydroponics.dmi',"") - if(seed.product_colour) - fruit_overlay.color = seed.product_colour - overlays += fruit_overlay - - if(seed.flowers) - var/image/flower_overlay = image('icons/obj/hydroponics.dmi',"[seed.flower_icon]") - if(seed.flower_colour) - flower_overlay.color = seed.flower_colour - overlays += flower_overlay - -/obj/effect/plantsegment/proc/spread() - var/direction = pick(cardinal) - var/step = get_step(src,direction) - if(istype(step,/turf/simulated/floor)) - var/turf/simulated/floor/F = step - if(!locate(/obj/effect/plantsegment,F)) - if(F.Enter(src)) - if(master) - master.spawn_piece( F ) - -// Explosion damage. -/obj/effect/plantsegment/ex_act(severity) - switch(severity) - if(1.0) - die() - return - if(2.0) - if (prob(90)) - die() - return - if(3.0) - if (prob(50)) - die() - return - return - -// Hotspots kill vines. -/obj/effect/plantsegment/fire_act(null, temp, volume) - del src - -/obj/effect/plantsegment/proc/die() - if(seed && harvest) - seed.harvest(src,1) - del(src) - -/obj/effect/plantsegment/proc/life() - - if(!seed) - return - - if(prob(30)) - age++ - - var/turf/T = loc - var/datum/gas_mixture/environment - if(T) environment = T.return_air() - - if(!environment) - return - - var/pressure = environment.return_pressure() - if(pressure < seed.lowkpa_tolerance || pressure > seed.highkpa_tolerance) - die() - return - - if(abs(environment.temperature - seed.ideal_heat) > seed.heat_tolerance) - die() - return - - var/area/A = T.loc - if(A) - var/light_available - if(A.lighting_use_dynamic) - light_available = max(0,min(10,T.lighting_lumcount)-5) - else - light_available = 5 - if(abs(light_available - seed.ideal_light) > seed.light_tolerance) - die() - return - -/obj/effect/plant_controller - - //What this does is that instead of having the grow minimum of 1, required to start growing, the minimum will be 0, - //meaning if you get the spacevines' size to something less than 20 plots, it won't grow anymore. - - var/list/obj/effect/plantsegment/vines = list() - var/list/growth_queue = list() - var/reached_collapse_size - var/reached_slowdown_size - var/datum/seed/seed - - var/collapse_limit = 250 - var/slowdown_limit = 30 - var/limited_growth = 0 - -/obj/effect/plant_controller/creeper - collapse_limit = 6 - slowdown_limit = 3 - limited_growth = 1 - -/obj/effect/plant_controller/New() - if(!istype(src.loc,/turf/simulated/floor)) - del(src) - - spawn(0) - spawn_piece(src.loc) - - processing_objects.Add(src) - -/obj/effect/plant_controller/Del() - processing_objects.Remove(src) - ..() - -/obj/effect/plant_controller/proc/spawn_piece(var/turf/location) - var/obj/effect/plantsegment/SV = new(location) - SV.limited_growth = src.limited_growth - growth_queue += SV - vines += SV - SV.master = src - if(seed) - SV.seed = seed - SV.name = "[seed.seed_name] vines" - SV.update() - -/obj/effect/plant_controller/process() - - // Space vines exterminated. Remove the controller - if(!vines) - del(src) - return - - // Sanity check. - if(!growth_queue) - del(src) - return - - // Check if we're too big for our own good. - if(vines.len >= (seed ? seed.potency * collapse_limit : 250) && !reached_collapse_size) - reached_collapse_size = 1 - if(vines.len >= (seed ? seed.potency * slowdown_limit : 30) && !reached_slowdown_size ) - reached_slowdown_size = 1 - - var/length = 0 - if(reached_collapse_size) - length = 0 - else if(reached_slowdown_size) - if(prob(seed ? seed.potency : 25)) - length = 1 - else - length = 0 - else - length = 1 - - length = min(30, max(length, vines.len/5)) - - // Update as many pieces of vine as we're allowed to. - // Append updated vines to the end of the growth queue. - var/i = 0 - var/list/obj/effect/plantsegment/queue_end = list() - for(var/obj/effect/plantsegment/SV in growth_queue) - i++ - queue_end += SV - growth_queue -= SV - - SV.life() - - if(SV.energy < 2) //If tile isn't fully grown - var/chance - if(seed) - chance = limited_growth ? round(seed.potency/2,1) : seed.potency - else - chance = 20 - - if(prob(chance)) - SV.grow() - - else if(!seed || !limited_growth) //If tile is fully grown and not just a creeper. - SV.entangle_mob() - - SV.update() - SV.spread() - if(i >= length) - break - - growth_queue = growth_queue + queue_end \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm index 20c1259b857..dfeef3b004e 100644 --- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm +++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm @@ -46,8 +46,8 @@ if(udder && prob(5)) udder.add_reagent("milk", rand(5, 10)) - if(locate(/obj/effect/plantsegment) in loc) - var/obj/effect/plantsegment/SV = locate(/obj/effect/plantsegment) in loc + if(locate(/obj/effect/plant) in loc) + var/obj/effect/plant/SV = locate(/obj/effect/plant) in loc del(SV) if(prob(10)) say("Nom") @@ -56,7 +56,7 @@ for(var/direction in shuffle(list(1,2,4,8,5,6,9,10))) var/step = get_step(src, direction) if(step) - if(locate(/obj/effect/plantsegment) in step) + if(locate(/obj/effect/plant) in step) Move(step) /mob/living/simple_animal/hostile/retaliate/goat/Retaliate() @@ -66,8 +66,8 @@ /mob/living/simple_animal/hostile/retaliate/goat/Move() ..() if(!stat) - if(locate(/obj/effect/plantsegment) in loc) - var/obj/effect/plantsegment/SV = locate(/obj/effect/plantsegment) in loc + if(locate(/obj/effect/plant) in loc) + var/obj/effect/plant/SV = locate(/obj/effect/plant) in loc del(SV) if(prob(10)) say("Nom") @@ -231,15 +231,19 @@ var/global/chicken_count = 0 chicken_count -= 1 /mob/living/simple_animal/chicken/attackby(var/obj/item/O as obj, var/mob/user as mob, params) - if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/grown/wheat)) //feedin' dem chickens - if(!stat && eggsleft < 8) - user.visible_message("\blue [user] feeds [O] to [name]! It clucks happily.","\blue You feed [O] to [name]! It clucks happily.") - user.drop_item() - del(O) - eggsleft += rand(1, 4) - //world << eggsleft + if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/grown)) //feedin' dem chickens + var/obj/item/weapon/reagent_containers/food/snacks/grown/G = O + if(G.seed.kitchen_tag == "wheat") + if(!stat && eggsleft < 8) + user.visible_message("\blue [user] feeds [O] to [name]! It clucks happily.","\blue You feed [O] to [name]! It clucks happily.") + user.drop_item() + del(O) + eggsleft += rand(1, 4) + //world << eggsleft + else + user << "\blue [name] doesn't seem hungry!" else - user << "\blue [name] doesn't seem hungry!" + user << "\blue [name] doesn't seem interested in [O]!" else ..() diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm index 289c388b17b..b3ee7bb18a5 100644 --- a/code/modules/reagents/Chemistry-Machinery.dm +++ b/code/modules/reagents/Chemistry-Machinery.dm @@ -1008,19 +1008,8 @@ /obj/item/stack/sheet/mineral/clown = list("banana" = 20), /obj/item/stack/sheet/mineral/silver = list("silver" = 20), /obj/item/stack/sheet/mineral/gold = list("gold" = 20), - /obj/item/weapon/grown/nettle = list("sacid" = 0), - /obj/item/weapon/grown/deathnettle = list("facid" = 0), /obj/item/weapon/grown/novaflower = list("capsaicin" = 0), - //Blender Stuff - /obj/item/weapon/reagent_containers/food/snacks/grown/soybeans = list("soymilk" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato = list("ketchup" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/corn = list("cornoil" = 0), - ///obj/item/weapon/reagent_containers/food/snacks/grown/wheat = list("flour" = -5), - /obj/item/weapon/reagent_containers/food/snacks/grown/ricestalk = list("rice" = -5), - /obj/item/weapon/reagent_containers/food/snacks/grown/cherries = list("cherryjelly" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/plastellium = list("plasticide" = 5), - //archaeology! /obj/item/weapon/rocksliver = list("ground_rock" = 50), @@ -1032,20 +1021,33 @@ /obj/item/weapon/reagent_containers/food = list() ) - var/list/juice_items = list ( + var/list/blend_tags = list ( + "nettle" = list("sacid" = 0), + "deathnettle" = list("facid" = 0), + "soybeans" = list("soymilk" = 0), + "tomato" = list("ketchup" = 0), + ///obj/item/weapon/reagent_containers/food/snacks/grown/wheat = list("flour" = -5), + "ricestalk" = list("rice" = -5), + "cherries" = list("cherryjelly" = 0), + "plastellium" = list("plasticide" = 5), + ) - //Juicer Stuff - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato = list("tomatojuice" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/carrot = list("carrotjuice" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/berries = list("berryjuice" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/banana = list("banana" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/potato = list("potato" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/lemon = list("lemonjuice" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/orange = list("orangejuice" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/lime = list("limejuice" = 0), + var/list/juice_items = list ( /obj/item/weapon/reagent_containers/food/snacks/watermelonslice = list("watermelonjuice" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/poisonberries = list("poisonberryjuice" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/grapes = list("grapejuice" = 0), + ) + + var/list/juice_tags = list ( + "tomato" = list("tomatojuice" = 0), + "carrot" = list("carrotjuice" = 0), + "berries" = list("berryjuice" = 0), + "banana" = list("banana" = 0), + "potato" = list("potato" = 0), + "lemon" = list("lemonjuice" = 0), + "orange" = list("orangejuice" = 0), + "lime" = list("limejuice" = 0), + "poisonberries" = list("poisonberryjuice" = 0), + "grapes" = list("grapejuice" = 0), + "corn" = list("cornoil" = 0), ) @@ -1223,10 +1225,20 @@ return blend_items[i] /obj/machinery/reagentgrinder/proc/get_allowed_juice_by_id(var/obj/item/weapon/reagent_containers/food/snacks/O) - for(var/i in juice_items) + for(var/i in juice_tags) if(istype(O, i)) return juice_items[i] +/obj/machinery/reagentgrinder/proc/get_allowed_snack_by_tag(var/obj/item/weapon/reagent_containers/food/snacks/grown/O) + for(var/i in blend_tags) + if(O.seed.kitchen_tag == i) + return blend_tags[i] + +/obj/machinery/reagentgrinder/proc/get_allowed_juice_by_tag(var/obj/item/weapon/reagent_containers/food/snacks/grown/O) + for(var/i in juice_tags) + if(O.seed.kitchen_tag == i) + return juice_tags[i] + /obj/machinery/reagentgrinder/proc/get_grownweapon_amount(var/obj/item/weapon/grown/O) if (!istype(O)) return 5 @@ -1263,7 +1275,11 @@ if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) break - var/allowed = get_allowed_juice_by_id(O) + var/allowed = null + if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/grown)) + allowed = get_allowed_juice_by_tag(O) + else + allowed = get_allowed_juice_by_id(O) if(isnull(allowed)) break @@ -1296,7 +1312,11 @@ if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) break - var/allowed = get_allowed_snack_by_id(O) + var/allowed = null + if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/grown)) + allowed = get_allowed_snack_by_tag(O) + else + allowed = get_allowed_snack_by_id(O) if(isnull(allowed)) break diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm index 8766271a170..e60befb5006 100644 --- a/code/modules/reagents/Chemistry-Reagents.dm +++ b/code/modules/reagents/Chemistry-Reagents.dm @@ -202,6 +202,16 @@ datum return */ + // Ported from Bay as part of the Botany Update + // Allows you to make planks from any plant that has this reagent in it. + // Also vines with this reagent are considered dense. + woodpulp + name = "Wood Pulp" + id = "woodpulp" + description = "A mass of wood fibers." + reagent_state = LIQUID + color = "#B97A57" + water name = "Water" id = "water" diff --git a/code/modules/reagents/newchem/toxins.dm b/code/modules/reagents/newchem/toxins.dm index b2779e42e4c..9cfa220198b 100644 --- a/code/modules/reagents/newchem/toxins.dm +++ b/code/modules/reagents/newchem/toxins.dm @@ -585,7 +585,7 @@ datum/reagent/atrazine/reaction_obj(var/obj/O, var/volume) alien_weeds.healthcheck() else if(istype(O,/obj/effect/glowshroom)) //even a small amount is enough to kill it del(O) - else if(istype(O,/obj/effect/plantsegment)) + else if(istype(O,/obj/effect/plant)) if(prob(50)) del(O) //Kills kudzu too. // Damage that is done to growing plants is separately at code/game/machinery/hydroponics at obj/item/hydroponics diff --git a/code/setup.dm b/code/setup.dm index f629ab3b14f..d4308bb1a66 100644 --- a/code/setup.dm +++ b/code/setup.dm @@ -964,6 +964,8 @@ var/list/hit_appends = list("-OOF", "-ACK", "-UGH", "-HRNK", "-HURGH", "-GLORF") #define STATUS_DISABLED 0 // RED Visability #define STATUS_CLOSE -1 // Close the interface +#define HYDRO_SPEED_MULTIPLIER 1 + #define NANO_IGNORE_DISTANCE 1 //Click cooldowns, in tenths of a second diff --git a/code/world.dm b/code/world.dm index e890c6164eb..0ed1f72ced8 100644 --- a/code/world.dm +++ b/code/world.dm @@ -41,6 +41,7 @@ sleep_offline = 1 + plant_controller = new() // Create robolimbs for chargen. populate_robolimb_list() diff --git a/icons/obj/cigarettes.dmi b/icons/obj/cigarettes.dmi index 89f3d1bdac8581da7bd27c5c32e76cc48286491a..7b6275972c056b5968538857c7d1073088702dcc 100644 GIT binary patch delta 523 zcmV+m0`&dcPuNe8B!B37R9JLGWpiV4X>fFDZ*Bkpc$}5j&u)T15C-rwJjFz>q*1i? z#HCr&c+giME3C4We}SbfZ{LFnovpR=dDG;#ntU@bvvYdgzU>aA_Pg-IbiHkAN@)GG z2!l_XyMhv0#bHnwdoJAdOYgKZl+Y}*=T>JI<7Q!y+pedCmVaSz>U3qUpKs+7r!h`f zI9=oP8K)bZE<{>smlbJg@5H(agWQyQq=e!qj^f`3hx+c(n?E@YT@Bh}^993HmsQid z(@>W98T07Ro2qrAcu0XQs?Y{iXnQKOIThNP3T;e@!j0VpG!@={wcfFDZ*Bkpc$}5j!EVAZ3*q|O;*{&xfE3rN4++L_YJ>UF&(wOOa{#`m^6Q$fpz zS(<#UOqireWqnTt&41J6;B{-RpKs+Hr#Vg+ zI9=lO5vNZ$or$#7p{#d}y%XyqO)Asq3l)@Sd6xe?IGpbuz4?><;Lo7lcb_oa>89=a za2T2fKV$y;^QLv-A|6s;iz>81722K(ZBB)@ra~K2p>3(qrY!Ao=d?3^=X7}zx$pKv zAO4O$sk_j-E`Lx#&)NJbyK`Kw2-k91xRz_fwOk;sO1MnbKt%bRV{p%8IkEJPj{43P&$L*#+s5P4ucL>?Fr zk(cAY&TsU_6lrt?f^SX{N0%V@1{HC14T5h{5x*PzlvZ0sYO_wi0J2bRPv4dAYybct N07*naRI?odyCvst`)>dM diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi index 7df20eeb250e397d0bbbe55ff3b666931e1b2bba..09247ec05ea6de68e707a5a86392cab33b457049 100644 GIT binary patch delta 2995 zcma)8c`)0H7EXfNMQg26q)M*V(q68emZ-HFw6v%#wHC2P6#1#0s-@NvT&|^r>O-j7 z_o9~8PVIH=d&ClHo_A;7oA=Ls^JdPRIe&aJ-<)s0`OYbS51#n|PUHh@nJ$1ppa{D^ z3_&1>?2CtweGv{mC~p@}Ul+6o2!zEKrnh=b%d$ld?wK-eInbrq^)b?bks$#=7(-fp$VOdaS({sd5&;qckGfOU;OwHD%VRt>WIA5*;lUZ;X2x;trsMOgO~F|8vst4@ z9A6@@K3;?FI$fm>x{t(ODKC)Byrrp;cg-?pIVeKRiBRVA8K~I3&Q)9ilY$7beKe9w zWf{9sme49HkvRTt-sNj*Q0s6$i<9@MoPomdlF*vFN#xAx+8_Kp!rmeg(au^0MJK2_BIfsd?=r7$`X8%a ze$ch__C%0!qQ~14myC{VNgl6Qp*Y$rEjKNKqy6`zsztu1zTX6rC((LeLIb^*>QgAO zj3To=!Y0d*J3u2<1i-yJgQm_rFgk|p4TMstgM6m6Qyre>UK-?%6gGSJzAbrXsXM_` zSOeD)1r^@?Nez_ng+ig=5yy7$S8F=AC%oU*H-UAJzP{Tc{OET59UUY4(TQ5V9c~b(MKi#5cSm5z}7hvw}D4c>AjpvIIfv!g7mlNQ`)=cmXm> zlWU9C-j&0hjX$0hzY6T>G2%OVlid9_Cx=|7FRb>$cM&JflaA`OqwVX|?Ekr*(i|w$SyF9jcxpL(|ztE&Wl)C`fpP8HUmz*;c z4>KwGQ7s0t_3)6ES5k5r?C+2Gi(sVf=YD$NW35cj-rKG9$AM=(A(hd0`LN zQ>*Tmax%BWfi{J;14h>c6mXWo0-|Rz3uUXY7-E!qRno@?9^A8dBI&} ze5LoKzTG_Z=wJM~&FlUVq3(42{QMyRu`;yy9V5*3Wic*iU^!905Vm#MfQRDCmg>~< zqSf#P!lTmvVT<6Kl!NI}e{gZ~q z#zyw}gK*Xp)q&l@V}h}e#V59{lYd9Er(4(We z8?%a9$bq>H$!IYN8^Mx$Pp9i0f{3Swgpe>?0zBbz!S{iGW`dJXN;h-(a~Jr zjbqo{3*{l&3iL89F(UcJmYkaGd17td=wJq+)^ySdVWeePsL8sUdquH-iqmx-GQ;)B z1J9IiBiIbmtcV2C9v=IyPq8RV+Az-=G0%zVUCB3xjI&CFuJY&{&UiDhdG>T#YXFaA ze%>CsYr(PJ3$(Yl8+G284%vRL=39mAGbX<{CY_$JMxra9wM8ZN&4FxveYyK*W%33( zRqQ#lK_;W`D=JW)o+O2xw)fV2~@ef5ka3{lD{js_Dk< zuX<^H%f7;pLs_%`k>>w*?4JYYK-Sh4l~gji+ltGDf-nz*&|0Pnp9wjlC+3 zDUfaOo|DwlhB~mNK|^mW0ToU``R}yJ;@`WV^&ihhkrW;7OWiBS%H0wy*NBys`4s+W zlj?=1NqQ3G|J<~1-k<{uTUfqxwO~sFZ$>m+!0j&Q-<&!cqg2%MqT-^Yg!9)Nq^E6! Jc&}+2`cKW(&aVIf delta 2689 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 I!pQ%>0mKhwK>z>% literal 0 HcmV?d00001 diff --git a/icons/obj/hydroponics_products.dmi b/icons/obj/hydroponics_products.dmi new file mode 100644 index 0000000000000000000000000000000000000000..b02a15b309a8d2d2d75894551105f1a72533530e GIT binary patch literal 8652 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 literal 0 HcmV?d00001 diff --git a/icons/obj/hydroponics_vines.dmi b/icons/obj/hydroponics_vines.dmi new file mode 100644 index 0000000000000000000000000000000000000000..2bad94b350dc2c77ab7c3ca60bd816aee1c4bf0c GIT binary patch literal 18093 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 literal 17404 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 E0~^BL>;M1& diff --git a/icons/obj/seeds_OLD.dmi b/icons/obj/seeds_OLD.dmi new file mode 100644 index 0000000000000000000000000000000000000000..98eb6e2292bc20d7a08d613bad744c4d0f88f189 GIT binary patch literal 17623 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≧@h`` zW+yTUTVKBfP!N>|7Sz2z5O_o+M_|gfW^D;*^~KRthvl_l@Ey(ryH=M> z3L|4p2U0qbcd6qHadH2KmW%@Yvt;tsJI;#CoO`2p2{;yB|2lOh#p$ftv z<4erU96nj9Us>{V%*xmuI}|%kU#3$18Ewq?{Zb( zsRG%Lj!6~$UJ)4fSj{ojiVDQby^@seFGq+TrHh5J1oJF#RlGwQ(LBfVmGIQU!dY*$ ziUBn?GYp<*+WZ`MjJp?FZY%gLW)Wo9a2d_Vg*tXkj^h+S@-A^wtnU{qNR*ooUi$(! zVBp&71-Ez>NsFFT&eCIiC@?V>M0?Nyi-yw{X1g;G3fJH71@wHX+%ZOu-qh zVV8vyO{RaC9tq3(m#ZEu1x};h$z=R2*QSO*MJsRK}A&A>vr z_ok3lf|naX)9|EsOw=aZrv*tlOZqz3~_nP~8 zM@+wmARopFGOjn+zZtweCT?Kq_ZilgjYNNyE;{=Q+sDiSh4?K#r8QpOzVU})(a!9C zMEI>o>p4<(V(fFMB$%Ft1~`&y`gC(f;kxcy3;hjXU({Bb)&ak%{}`lFjTQ8{pd!MD zoDXL@%w^1h7GH``FSThk)ylDxgP5tizISqd>X%H?3vPjDf@!wCp+-|vbnGbp6>9`b zB0Uo;jYB0b^Ho1AZQ!vRcN#sh0Y=)vimuk;c`aG1P(jSAN10l)xdNlG!1iju1H(rW zSe2x&pUTS1O>g?rLPwqCO=bt*ZLuf$`E0RA7uai6I{1~=BzW3?NsJhxo=eJFpU$7nPYfj z-nt}dq*q~Yfes0@QY{6M>c|?smJog=DRz<6V1rS?$CKq>BcJ?qQUZxuk5~qBus^G~ z1A>`F#zQsTv!^N+l+-RY7RBaR8MBd0>kH)4ayk5jB&PMM*Eot$-g_)T>mBUCSJ3O@ z4`Rl$<5Dt_vL&r%0aqyKp0xP3mpI7yF9Z~RFO*mcLpU}W>zDmr>zyQ%5Q(Mhr7uBu zNYO>_RDUX|iGA{GUZ!HbfxLJty+snn@!y*HeTSsb_hy1$$a{r~sdBdhZuuNFZvcKe zhU1&l*V)weZ<}mmd9Ns;CkS(pn7|V7%mx`hhxRG-sBFT$c_PoiUh`DkTCJzzjw-uk zQ%mmV`eW6Ov*BcJIMvr3QKKdOdD6w13s?dmHgj+Kiu%&U?-T3A|-1U(aS}1M=Q2uM?l8!IZ)>GuqiIjd*5mORk7uc^zoRK zcaIX6!+WlX_ccf1t^pRIzim<|G73WOr65wWz;rzZ-$H!G$<(VX4YRXP&^6uF<)5=B ziL=tw2dM5x^fy`+;#g&!7rFaDy-*RoqHGE33*{05*bYF7P3r97K#k?LDp+Fj5LqDz za`VgF&%;XWY35zAF*&=80`&z>XZW@{f)xnbKyK$!*=t6GB)W(X=68|Cy|)q8(G?`yV2VTc@#avkxen^Gj{P-zY^Txkd-+5LbuuPp3)90h><0 zrkOjhZExE9V2h^H=j9K#-`jZ8pz> Date: Sat, 9 May 2015 05:43:47 -0700 Subject: [PATCH 2/7] Water_act system - for all your watery needs This is the first commit of the Water_act system for monkey cubes, showers, and mobs. The idea of the system is to outsource the effects of water to the object/mob being affected instead of a bunch of snowflake code. --- code/game/atoms_movable.dm | 2 ++ code/game/objects/structures/watercloset.dm | 24 +++++++++++++++---- code/modules/mob/living/carbon/carbon.dm | 1 - .../mob/living/carbon/human/human_defense.dm | 5 ++++ code/modules/mob/living/living_defense.dm | 4 ++++ .../reagent_containers/food/snacks.dm | 3 +++ 6 files changed, 34 insertions(+), 5 deletions(-) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index dcbe4e4462e..b34f3412a5d 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -282,3 +282,5 @@ /atom/movable/proc/canSingulothPull(var/obj/machinery/singularity/singulo) return 1 +/atom/movable/proc/water_act(var/volume, var/temperature, var/source) //amount of water acting : temperature of water in kelvin : object that called it (for shennagins) + return 1 \ No newline at end of file diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index 2fdd133801b..2081f911325 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -146,8 +146,10 @@ if (M.loc == loc) wash(M) check_heat(M) + M.water_act(100, convertHeat(), src) for (var/atom/movable/G in src.loc) G.clean_blood() + G.water_act(100, convertHeat(), src) /obj/machinery/shower/attackby(obj/item/I as obj, mob/user as mob, params) if(I.type == /obj/item/device/analyzer) @@ -163,6 +165,8 @@ if("boiling") watertemp = "normal" user.visible_message("[user] adjusts the shower with the [I].", "You adjust the shower with the [I].") + if(on) + I.water_act(100, convertHeat(), src) /obj/machinery/shower/update_icon() //this is terribly unreadable, but basically it makes the shower mist up overlays.Cut() //once it's been on for a while, in addition to handling the water overlay. @@ -201,10 +205,21 @@ mobpresent -= 1 ..() +/obj/machinery/shower/proc/convertHeat() + switch(watertemp) + if("boiling") + return 340.15 + if("normal") + return 310.15 + if("freezing") + return 230.15 + //Yes, showers are super powerful as far as washing goes. /obj/machinery/shower/proc/wash(atom/movable/O as obj|mob) if(!on) return + O.water_act(100, convertHeat(), src) + if(isliving(O)) var/mob/living/L = O L.ExtinguishMob() @@ -298,17 +313,16 @@ var/mob/living/carbon/C = M if(watertemp == "freezing") - C.bodytemperature = max(80, C.bodytemperature - 80) + //C.bodytemperature = max(80, C.bodytemperature - 80) C << "The water is freezing!" return if(watertemp == "boiling") - C.bodytemperature = min(500, C.bodytemperature + 35) + //C.bodytemperature = min(500, C.bodytemperature + 35) C.adjustFireLoss(5) C << "The water is searing!" return - /obj/item/weapon/bikehorn/rubberducky name = "rubber ducky" desc = "Rubber ducky you're so fine, you make bathtime lots of fuuun. Rubber ducky I'm awfully fooooond of yooooouuuu~" //thanks doohl @@ -372,7 +386,9 @@ user.visible_message("\blue [user] fills the [RG] using \the [src].","\blue You fill the [RG] using \the [src].") return - else if (istype(O, /obj/item/weapon/melee/baton)) + O.water_act(20,310.15,src) + + if (istype(O, /obj/item/weapon/melee/baton)) var/obj/item/weapon/melee/baton/B = O if (B.bcell.charge > 0 && B.status == 1) flick("baton_active", src) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 683228e97e8..5da86e83455 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -92,7 +92,6 @@ mob/living return return - /mob/living/carbon/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0, var/def_zone = null) if(status_flags & GODMODE) //godmode return 0 diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 3ff64431933..d8d12108b20 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -488,3 +488,8 @@ emp_act ..() return + +/mob/living/carbon/human/water_act(volume, temperature) + ..() + if(temperature >= 330) bodytemperature = bodytemperature + (temperature - bodytemperature) + if(temperature <= 280) bodytemperature = bodytemperature - (bodytemperature - temperature) \ No newline at end of file diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index b61d58223c6..aff6a6d415e 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -238,6 +238,10 @@ //Mobs on Fire end +/mob/living/water_act(volume, temperature) + if(volume >= 20) fire_stacks -= 0.5 + if(volume >= 50) fire_stacks -= 1 + //This is called when the mob is thrown into a dense turf /mob/living/proc/turf_collision(var/turf/T, var/speed) src.take_organ_damage(speed*5) diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm index 8cc0229c548..6d332a5cbc1 100644 --- a/code/modules/reagents/reagent_containers/food/snacks.dm +++ b/code/modules/reagents/reagent_containers/food/snacks.dm @@ -1722,6 +1722,9 @@ M.gib() ..() + water_act(volume, temperature) + if(volume >= 5) return Expand() + proc/Expand() for(var/mob/M in viewers(src,7)) M << "\red \The [src] expands!" From 5549925516e1d5efd2bf23751b9c2c4a25379396 Mon Sep 17 00:00:00 2001 From: Tigercat2000 Date: Sat, 9 May 2015 12:07:05 -0700 Subject: [PATCH 3/7] Autogibber + Minor patches This replaces the old autogibber with a spawnable version that is actually an automatic gibber. This also fixes a few minor issues I did not notice before with the gibber code. Namely, overlays getting messed up. The gibber will now spit out things inside of it 1 by 1 instead of all at once. --- code/game/machinery/kitchen/gibber.dm | 127 +++++++++++++++++++++++--- 1 file changed, 114 insertions(+), 13 deletions(-) diff --git a/code/game/machinery/kitchen/gibber.dm b/code/game/machinery/kitchen/gibber.dm index 60a4d3d094f..af98ded7bd5 100644 --- a/code/game/machinery/kitchen/gibber.dm +++ b/code/game/machinery/kitchen/gibber.dm @@ -14,10 +14,96 @@ var/gib_throw_dir = WEST // Direction to spit meat and gibs in. Defaults to west. var/gibtime = 40 // Time from starting until meat appears + var/list/victims = list() + use_power = 1 idle_power_usage = 2 active_power_usage = 500 +//gibs anything that stands on it's input + +/obj/machinery/gibber/autogibber + var/acceptdir = NORTH + var/turf/lturf + +/obj/machinery/gibber/autogibber/New() + ..() + spawn(5) + var/turf/T = get_step(src, acceptdir) + if(istype(T)) + lturf = T + +/obj/machinery/gibber/autogibber/process() + if(!lturf || occupant || locked || dirty || operating) + return + + for(var/mob/living/carbon/human/H in lturf) + if(istype(H) && H.loc == lturf) + visible_message({"\The [src] states, "Food detected!""}) + sleep(30) + if(H.loc == lturf) //still standing there + if(force_move_into_gibber(H)) + ejectclothes(occupant) + cleanbay() + startgibbing(null, 1) + break + +/obj/machinery/gibber/autogibber/proc/force_move_into_gibber(var/mob/living/carbon/human/victim) + if(!istype(victim)) return 0 + visible_message("\The [victim.name] gets sucked into \the [src]!") + + if(victim.client) + victim.client.perspective = EYE_PERSPECTIVE + victim.client.eye = src + + victim.loc = src + src.occupant = victim + + update_icon() + feedinTopanim() + return 1 + +/obj/machinery/gibber/autogibber/proc/ejectclothes(var/mob/living/carbon/human/H) + if(!istype(H)) return 0 + if(H != occupant) return 0 //only using H as a shortcut to typecast + for(var/obj/O in H) + if(istype(O,/obj/item/clothing)) //clothing gets skipped to avoid cleaning out shit + continue + if(istype(O,/obj/item/weapon/implant)) + var/obj/item/weapon/implant/I = O + if(I.implanted) + continue + if(istype(O,/obj/item/organ)) + continue + if(O.flags & NODROP) + qdel(O) //they are already dead by now + H.unEquip(O) + O.loc = src.loc + O.throw_at(get_edge_target_turf(src,gib_throw_dir),rand(1,5),15) + sleep(1) + + for(var/obj/item/clothing/C in H) + if(C.flags & NODROP) + qdel(C) + H.unEquip(C) + C.loc = src.loc + C.throw_at(get_edge_target_turf(src,gib_throw_dir),rand(1,5),15) + sleep(1) + + visible_message("\The [src] spits out \the [H.name]'s possessions!") + +/obj/machinery/gibber/autogibber/proc/cleanbay() + var/spats = 0 //keeps track of how many items get spit out. Don't show a message if none are found. + for(var/obj/O in src) + if(istype(O)) + O.loc = src.loc + O.throw_at(get_edge_target_turf(src,gib_throw_dir),rand(1,5),15) + spats++ + sleep(1) + if(spats) + visible_message("\The [src] spits out more possessions!") + +/* //auto-gibs anything that bumps into it /obj/machinery/gibber/autogibber var/turf/input_plate @@ -46,7 +132,7 @@ if(M.loc == input_plate) M.loc = src M.gib() - +*/ /obj/machinery/gibber/New() ..() @@ -233,9 +319,18 @@ sleep(1) + overlays -= feedee + overlays -= gibberoverlay src.layer = 3 -/obj/machinery/gibber/proc/startgibbing(mob/user as mob) +/obj/machinery/gibber/proc/startgibbing(var/mob/user, var/UserOverride=0) + if(!istype(user) && !UserOverride) + log_debug("Some shit just went down with the gibber at X[x], Y[y], Z[z] with an invalid user. (JMP)") + return + + if(UserOverride) + msg_admin_attack("[occupant] ([occupant.ckey]) was gibbed by an autogibber (\the [src]) at (JMP)") + if(src.operating) return @@ -266,16 +361,20 @@ new /obj/effect/decal/cleanable/blood/gibs(src) - src.occupant.attack_log += "\[[time_stamp()]\] Was gibbed by [user]/[user.ckey]" //One shall not simply gib a mob unnoticed! - user.attack_log += "\[[time_stamp()]\] Gibbed [src.occupant]/[src.occupant.ckey]" + if(!UserOverride) + src.occupant.attack_log += "\[[time_stamp()]\] Was gibbed by [user]/[user.ckey]" //One shall not simply gib a mob unnoticed! + user.attack_log += "\[[time_stamp()]\] Gibbed [src.occupant]/[src.occupant.ckey]" - if(src.occupant.ckey) - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] gibbed [src.occupant] ([src.occupant.ckey]) (JMP)") + if(src.occupant.ckey) + msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] gibbed [src.occupant] ([src.occupant.ckey]) (JMP)") - if(!iscarbon(user)) - src.occupant.LAssailant = null - else - src.occupant.LAssailant = user + if(!iscarbon(user)) + src.occupant.LAssailant = null + else + src.occupant.LAssailant = user + + if(UserOverride) //this looks ugly but it's better than a copy-pasted startgibbing proc override + occupant.attack_log += "\[[time_stamp()]\] Was gibbed by an autogibber (\the [src])" src.occupant.emote("scream") playsound(src.loc, 'sound/effects/gib.ogg', 50, 1) @@ -283,6 +382,8 @@ src.occupant.death(1) src.occupant.ghostize() + victims += "\[[time_stamp()]\] [occupant.name] ([occupant.ckey]) killed." + del(src.occupant) spawn(src.gibtime) @@ -293,12 +394,12 @@ for (var/obj/item/thing in contents) //Meat is spawned inside the gibber and thrown out afterwards. thing.loc = get_turf(thing) // Drop it onto the turf for throwing. thing.throw_at(get_edge_target_turf(src,gib_throw_dir),rand(1,5),15) // Being pelted with bits of meat and bone would hurt. + sleep(1) for (var/obj/effect/gibs in contents) //throw out the gibs too gibs.loc = get_turf(gibs) //drop onto turf for throwing gibs.throw_at(get_edge_target_turf(src,gib_throw_dir),rand(1,5),15) + sleep(1) src.operating = 0 - update_icon() - - + update_icon() \ No newline at end of file From 597b15b85051777cde21da8e631fd9f017a33f8d Mon Sep 17 00:00:00 2001 From: Tigercat2000 Date: Sat, 9 May 2015 12:28:54 -0700 Subject: [PATCH 4/7] Gibber: More logging, Autogibber fix This commit adds the user name and ckey (where applicable) to the gibber victim list. victims = /list (1) - [12:27:52] unknown () killed by The unknown (tigercat2000) = null victims = /list (1) - [12:26:56] Shadow Larkens (tigercat2000) killed by Autogibbing = null This commit also fixes admin-vareditting the autogibber direction, it will actually update it's linked turf now. --- code/game/machinery/kitchen/gibber.dm | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/code/game/machinery/kitchen/gibber.dm b/code/game/machinery/kitchen/gibber.dm index af98ded7bd5..b9ab86027ce 100644 --- a/code/game/machinery/kitchen/gibber.dm +++ b/code/game/machinery/kitchen/gibber.dm @@ -24,6 +24,7 @@ /obj/machinery/gibber/autogibber var/acceptdir = NORTH + var/lastacceptdir = NORTH var/turf/lturf /obj/machinery/gibber/autogibber/New() @@ -37,6 +38,13 @@ if(!lturf || occupant || locked || dirty || operating) return + if(acceptdir != lastacceptdir) + lturf = null + lastacceptdir = acceptdir + var/turf/T = get_step(src, acceptdir) + if(istype(T)) + lturf = T + for(var/mob/living/carbon/human/H in lturf) if(istype(H) && H.loc == lturf) visible_message({"\The [src] states, "Food detected!""}) @@ -379,11 +387,10 @@ src.occupant.emote("scream") playsound(src.loc, 'sound/effects/gib.ogg', 50, 1) + victims += "\[[time_stamp()]\] [occupant.name] ([occupant.ckey]) killed by [UserOverride ? "Autogibbing" : "[user] ([user.ckey])"]" //have to do this before ghostizing src.occupant.death(1) src.occupant.ghostize() - victims += "\[[time_stamp()]\] [occupant.name] ([occupant.ckey]) killed." - del(src.occupant) spawn(src.gibtime) From 2ac1304df5e76ede45b6fd82795fb710f2e13d87 Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Sun, 10 May 2015 05:59:03 -0400 Subject: [PATCH 5/7] Health Analyzer Name Fix --- code/modules/research/designs/medical_designs.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index ab00accccca..37d524c689c 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -46,7 +46,7 @@ category = list("Medical") /datum/design/healthanalyzer - name = "Health Analyzer Upgrade" + name = "Health Analyzer" desc = "A hand-held body scanner able to distinguish vital signs of the subject." id = "healthanalyzer" req_tech = list("biotech" = 2, "magnets" = 2) From 27442f95392e6e4900a1cfec793f6f3fbb190974 Mon Sep 17 00:00:00 2001 From: Tigercat2000 Date: Sun, 10 May 2015 05:39:26 -0700 Subject: [PATCH 6/7] Water_act: Wetlevel for carbon mobs All carbon mobs have a new variable called wetness, which is increased upon water_act's that have a volume over 10, and is decreased every 22~ cycles of mob_master. This variable currently does absolutely nothing but change their examine text. --- code/game/objects/effects/effect_system.dm | 3 +++ code/game/objects/structures/watercloset.dm | 1 + code/modules/mob/living/carbon/alien/alien.dm | 4 ++++ .../mob/living/carbon/alien/humanoid/life.dm | 3 +++ code/modules/mob/living/carbon/carbon_defenses.dm | 5 +++++ code/modules/mob/living/carbon/carbon_defines.dm | 3 ++- code/modules/mob/living/carbon/human/examine.dm | 12 ++++++++++++ .../mob/living/carbon/human/human_defense.dm | 2 +- code/modules/mob/living/carbon/human/life.dm | 7 +++++++ code/modules/mob/living/carbon/metroid/examine.dm | 14 ++++++++++++++ code/modules/mob/living/carbon/metroid/life.dm | 7 +++++++ code/modules/mob/living/carbon/monkey/examine.dm | 14 ++++++++++++++ code/modules/mob/living/carbon/monkey/life.dm | 10 +++++++++- 13 files changed, 82 insertions(+), 3 deletions(-) diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index d5d3555e12d..26d669038ba 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -79,6 +79,9 @@ would spawn and follow the beaker, even if it is carried or thrown. /obj/effect/effect/water/Bump(atom/A) if(reagents) reagents.reaction(A) + if(istype(A,/atom/movable)) + var/atom/movable/AM = A + AM.water_act(life, 310.15, src) return ..() diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index 2081f911325..76c6715b0da 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -308,6 +308,7 @@ check_heat(C) /obj/machinery/shower/proc/check_heat(mob/M as mob) + M.water_act(100, convertHeat(), src) //convenience if(!on || watertemp == "normal") return if(iscarbon(M)) var/mob/living/carbon/C = M diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index 6e5dcdc3dea..a2e7be0928d 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -152,6 +152,10 @@ bodytemperature += BODYTEMP_HEATING_MAX //If you're on fire, you heat up! return +/mob/living/carbon/alien/proc/handle_wetness() + if(mob_master.current_cycle%20==2) //dry off a bit once every 20 ticks or so + wetlevel = max(wetlevel - 1,0) + return /mob/living/carbon/alien/IsAdvancedToolUser() return has_fine_manipulation diff --git a/code/modules/mob/living/carbon/alien/humanoid/life.dm b/code/modules/mob/living/carbon/alien/humanoid/life.dm index eda8df77ee7..9ecf410a4d3 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/life.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/life.dm @@ -53,6 +53,9 @@ //Handle being on fire handle_fire() + //Decrease wetness over time + handle_wetness() + //Status updates, death etc. handle_regular_status_updates() update_canmove() diff --git a/code/modules/mob/living/carbon/carbon_defenses.dm b/code/modules/mob/living/carbon/carbon_defenses.dm index fddbd0d3cda..ab1c27ca2ee 100644 --- a/code/modules/mob/living/carbon/carbon_defenses.dm +++ b/code/modules/mob/living/carbon/carbon_defenses.dm @@ -14,4 +14,9 @@ visible_message("[src] catches [I]!") throw_mode_off() return + ..() + +/mob/living/carbon/water_act(volume, temperature, source) + if(volume > 10) //anything over 10 volume will make the mob wetter. + wetlevel = min(wetlevel + 1,5) ..() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index f9b61a3bd10..b6852c8a8dc 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -20,4 +20,5 @@ var/pulse = PULSE_NORM //current pulse level - var/heart_attack = 0 \ No newline at end of file + var/heart_attack = 0 + var/wetlevel = 0 //how wet the mob is \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index fac498d9219..00ec9e67181 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -231,6 +231,18 @@ if(fire_stacks < 0) msg += "[t_He] looks a little soaked.\n" + switch(wetlevel) + if(1) + msg += "[t_He] looks a bit damp.\n" + if(2) + msg += "[t_He] looks a little bit wet.\n" + if(3) + msg += "[t_He] looks wet.\n" + if(4) + msg += "[t_He] looks very wet.\n" + if(5) + msg += "[t_He] looks absolutely soaked.\n" + if(nutrition < 100) msg += "[t_He] [t_is] severely malnourished.\n" else if(nutrition >= 500) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index d8d12108b20..c2498a5a740 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -489,7 +489,7 @@ emp_act return -/mob/living/carbon/human/water_act(volume, temperature) +/mob/living/carbon/human/water_act(volume, temperature, source) ..() if(temperature >= 330) bodytemperature = bodytemperature + (temperature - bodytemperature) if(temperature <= 280) bodytemperature = bodytemperature - (bodytemperature - temperature) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 71226aa8bfb..ec2e253e100 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -108,6 +108,9 @@ var/global/list/brutefireloss_overlays = list("1" = image("icon" = 'icons/mob/sc //Check if we're on fire handle_fire() + //Decrease wetness over time + handle_wetness() + //stuff in the stomach handle_stomach() @@ -547,6 +550,10 @@ var/global/list/brutefireloss_overlays = list("1" = image("icon" = 'icons/mob/sc return //END FIRE CODE + proc/handle_wetness() + if(mob_master.current_cycle%20==2) //dry off a bit once every 20 ticks or so + wetlevel = max(wetlevel - 1,0) + return /* proc/adjust_body_temperature(current, loc_temp, boost) diff --git a/code/modules/mob/living/carbon/metroid/examine.dm b/code/modules/mob/living/carbon/metroid/examine.dm index f8fc23ad2e9..38087b35795 100644 --- a/code/modules/mob/living/carbon/metroid/examine.dm +++ b/code/modules/mob/living/carbon/metroid/examine.dm @@ -32,6 +32,20 @@ if(10) msg += "It is radiating with massive levels of electrical activity!\n" + msg += "" + switch(wetlevel) + if(1) + msg += "It looks a bit damp.\n" + if(2) + msg += "It looks a little bit wet.\n" + if(3) + msg += "It looks wet.\n" + if(4) + msg += "It looks very wet.\n" + if(5) + msg += "It looks absolutely soaked.\n" + msg += "" + msg += "*---------*" usr << msg return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/metroid/life.dm b/code/modules/mob/living/carbon/metroid/life.dm index 8b11c8a1b2f..afcb48726bd 100644 --- a/code/modules/mob/living/carbon/metroid/life.dm +++ b/code/modules/mob/living/carbon/metroid/life.dm @@ -42,6 +42,8 @@ handle_regular_status_updates() // Status updates, death etc. + handle_wetness() + /mob/living/carbon/slime/proc/AIprocess() // the master AI process if(AIproc || stat == DEAD || client) return @@ -285,6 +287,11 @@ else Evolve() +/mob/living/carbon/slime/proc/handle_wetness() + if(mob_master.current_cycle%20==2) //dry off a bit once every 20 ticks or so + wetlevel = max(wetlevel - 1,0) + return + /mob/living/carbon/slime/proc/handle_targets() if(Tempstun) if(!Victim) // not while they're eating! diff --git a/code/modules/mob/living/carbon/monkey/examine.dm b/code/modules/mob/living/carbon/monkey/examine.dm index 5cbb5c6c7ce..9c9d0ef5082 100644 --- a/code/modules/mob/living/carbon/monkey/examine.dm +++ b/code/modules/mob/living/carbon/monkey/examine.dm @@ -40,6 +40,20 @@ msg += "It isn't responding to anything around it; it seems to be asleep.\n" msg += "" + msg += "" + switch(wetlevel) + if(1) + msg += "It looks a bit damp.\n" + if(2) + msg += "It looks a little bit wet.\n" + if(3) + msg += "It looks wet.\n" + if(4) + msg += "It looks very wet.\n" + if(5) + msg += "It looks absolutely soaked.\n" + msg += "" + if (src.digitalcamo) msg += "It is repulsively uncanny!\n" diff --git a/code/modules/mob/living/carbon/monkey/life.dm b/code/modules/mob/living/carbon/monkey/life.dm index 1a3bfc3f05a..cc1808ff6c5 100644 --- a/code/modules/mob/living/carbon/monkey/life.dm +++ b/code/modules/mob/living/carbon/monkey/life.dm @@ -62,6 +62,9 @@ //Check if we're on fire handle_fire() + //Decrease wetness over time + handle_wetness() + //Status updates, death etc. handle_regular_status_updates() update_canmove() @@ -660,4 +663,9 @@ return adjustFireLoss(6) return - //END FIRE CODE \ No newline at end of file + //END FIRE CODE + + proc/handle_wetness() + if(mob_master.current_cycle%20==2) //dry off a bit once every 20 ticks or so + wetlevel = max(wetlevel - 1,0) + return \ No newline at end of file From 6cda382c5e343fda04615ae7cfc7fd356e20dd0e Mon Sep 17 00:00:00 2001 From: Robertha89 Date: Sun, 10 May 2015 17:10:17 +0200 Subject: [PATCH 7/7] Adds service radio to ai Fixes an oversight. --- code/modules/mob/living/silicon/ai/laws.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/mob/living/silicon/ai/laws.dm b/code/modules/mob/living/silicon/ai/laws.dm index 8e8ceb33c3f..c8670539eae 100755 --- a/code/modules/mob/living/silicon/ai/laws.dm +++ b/code/modules/mob/living/silicon/ai/laws.dm @@ -67,6 +67,7 @@ if("Engineering") prefix = ":e " if("Security") prefix = ":s " if("Supply") prefix = ":u " + if("Service") prefix = ":z " if("Binary") prefix = ":b " if("Holopad") prefix = ":h " else prefix = "" @@ -158,4 +159,4 @@ list += {"
Channel: [src.lawchannel]
"} list += {"State Laws"} - usr << browse(list, "window=laws") \ No newline at end of file + usr << browse(list, "window=laws")

Endurance[grown_seed.endurance]
Yield[grown_seed.yield]
Lifespan[grown_seed.lifespan]
Maturation time[grown_seed.maturation]
Production time[grown_seed.production]
Potency[grown_seed.potency]
Endurance[grown_seed.get_trait(TRAIT_ENDURANCE)]
Yield[grown_seed.get_trait(TRAIT_YIELD)]
Maturation time[grown_seed.get_trait(TRAIT_MATURATION)]
Production time[grown_seed.get_trait(TRAIT_PRODUCTION)]
Potency[grown_seed.get_trait(TRAIT_POTENCY)]