Many botany QoL changes. (#25031)

* Many botany QoL changes.

* Give observers a plant analyzer.

* Hooks should be executable.

* Upgraded Seed Extractor GUI.

* Left-align seed extractor, more efficient icon sending.

* tgui rebuild

* Apply suggestions from code review

Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>

* 's' properly

---------

Co-authored-by: FunnyMan3595 (Charlie Nolan) <funnyman@google.com>
Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
This commit is contained in:
Charlie Nolan
2024-04-15 19:58:09 +00:00
committed by GitHub
co-authored by Burzah FunnyMan3595
parent 0b838dc3c4
commit a881e11c86
28 changed files with 756 additions and 304 deletions
+19 -9
View File
@@ -29,6 +29,13 @@
var/list/product_list = list()
/// The [/datum/design]'s categories which can be produced by this machine and can be uploaded via a disk.
var/static/list/categories = list("Food", "Botany Chemicals", "Organic Materials", "Leather and Cloth")
var/static/list/acceptable_items = typecacheof(list(
/obj/item/seeds,
/obj/item/food/snacks/grown,
/obj/item/grown,
/obj/item/food/snacks/grown/ash_flora,
/obj/item/food/snacks/honeycomb))
/obj/machinery/biogenerator/Initialize(mapload)
. = ..()
@@ -127,11 +134,12 @@
return
var/obj/item/storage/bag/plants/PB = O
for(var/obj/item/food/snacks/grown/G in PB.contents)
for(var/obj/item/P in PB.contents)
// No need to filter here, because plant bags should have the same list of acceptable items we do.
if(length(stored_plants) >= max_storable_plants)
break
PB.remove_from_storage(G, src)
stored_plants += G
PB.remove_from_storage(P, src)
stored_plants += P
if(length(stored_plants) < max_storable_plants)
to_chat(user, "<span class='info'>You empty [PB] into [src].</span>")
@@ -141,7 +149,7 @@
SStgui.update_uis(src)
return TRUE
else if(istype(O, /obj/item/food/snacks/grown))
else if(is_type_in_typecache(O, acceptable_items))
if(length(stored_plants) >= max_storable_plants)
to_chat(user, "<span class='warning'>[src] can't hold any more plants!</span>")
return
@@ -266,15 +274,17 @@
update_icon(UPDATE_ICON_STATE)
var/plants_processed = length(stored_plants)
var/new_biomass = 0
for(var/obj/plant as anything in stored_plants)
var/plant_biomass = plant.reagents.get_reagent_amount("nutriment") + plant.reagents.get_reagent_amount("plantmatter")
biomass += max(plant_biomass, 0.1) * 10 * productivity
var/plant_biomass = plant.reagents?.get_reagent_amount("nutriment") + plant.reagents?.get_reagent_amount("plantmatter")
new_biomass += max(plant_biomass, 0.1)
qdel(plant)
biomass += new_biomass * 10 * productivity
stored_plants.Cut()
playsound(loc, 'sound/machines/blender.ogg', 50, 1)
playsound(loc, 'sound/machines/blender.ogg', 50, TRUE)
use_power(plants_processed * 150)
addtimer(CALLBACK(src, PROC_REF(end_processing)), (plants_processed * 5) / productivity)
addtimer(CALLBACK(src, PROC_REF(end_processing)), min(20 SECONDS, new_biomass))
/obj/machinery/biogenerator/proc/end_processing()
processing = FALSE
@@ -340,7 +350,7 @@
for(var/R in D.make_reagents)
container.reagents.add_reagent(R, D.make_reagents[R] * amount)
// Creating all other items, such as monkey cubes or nutriment bottles.
// Creating all other items, such as monkey cubes or nutrient bottles.
else
if(!check_cost(D, amount))
return
+118 -10
View File
@@ -21,6 +21,7 @@
var/max_endurance = 10 // IMPT: ALSO AFFECTS LIFESPAN
var/min_weed_chance = 67
var/min_weed_rate = 10
var/seeds_for_bulk_core = 5
/obj/machinery/plantgenes/Initialize(mapload)
. = ..()
@@ -73,14 +74,32 @@
min_weed_rate = FLOOR(10-weed_rate_mod, 1) // 7,5,2,0 Clamps at 0 and 10 You want this low
min_weed_chance = 67-(ML.rating*16) // 48,35,19,3 Clamps at 0 and 67 You want this low
var/total_rating = 0
for(var/obj/item/stock_parts/S in component_parts)
total_rating += S.rating
switch(clamp(total_rating, 1, 12))
if(1 to 3)
seeds_for_bulk_core = 5
if(4 to 6)
seeds_for_bulk_core = 4
if(7 to 9)
seeds_for_bulk_core = 3
if(10 to 11)
seeds_for_bulk_core = 2
else
seeds_for_bulk_core = 1
for(var/obj/item/circuitboard/plantgenes/vaultcheck in component_parts)
if(istype(vaultcheck, /obj/item/circuitboard/plantgenes/vault)) // TRAIT_DUMB BOTANY TUTS
total_rating = 12
max_potency = 100
max_yield = 10
min_production = 1
max_endurance = 100
min_weed_chance = 0
min_weed_rate = 0
seeds_for_bulk_core = 1
/obj/machinery/plantgenes/update_icon_state()
if((stat & (BROKEN|NOPOWER)))
@@ -205,9 +224,7 @@
data["disk"] = list()
if(disk)
var/disk_name = "Empty Disk"
if(disk.gene)
disk_name = disk.gene.get_name()
var/disk_name = disk.ui_name
if(disk.read_only)
disk_name = "[disk_name] (Read Only)"
var/can_insert = FALSE
@@ -217,7 +234,8 @@
"name" = disk_name,
"can_insert" = can_insert,
"can_extract" = !disk.read_only,
"is_core" = istype(disk?.gene, /datum/plant_gene/core)
"is_core" = istype(disk?.gene, /datum/plant_gene/core),
"is_bulk_core" = disk?.is_bulk_core && (disk.seeds_needed <= disk.seeds_scanned)
)
data["modal"] = ui_modal_data(src)
@@ -266,12 +284,22 @@
seed.variant_prompt(user, src)
// uses the default byond prompt, but it works
if("bulk_extract_core")
var/dat = "Are you sure you want to extract all core genes from the [seed]? The sample will be destroyed in the process!"
var/prev_seeds = 0
if(disk.is_bulk_core && disk.core_matches(seed))
prev_seeds = disk.seeds_scanned
if(seeds_for_bulk_core > prev_seeds + 1)
var/remaining = seeds_for_bulk_core - prev_seeds - 1
dat += " This device needs [seeds_for_bulk_core] samples to produce a usable core gene disk. You will need [remaining] more sample[ remaining > 1 ? "s" : ""] with identical core genes."
ui_modal_boolean(src, action, dat, yes_text = "Extract", no_text = "Cancel", delegate = PROC_REF(bulk_extract_core))
if("extract")
var/dat = "Are you sure you want to extract [target.get_name()] gene from the [seed]? The sample will be destroyed in process!"
if(istype(target, /datum/plant_gene/core))
var/datum/plant_gene/core/core_gene = target
var/genemod_var = core_gene.get_genemod_variable(src) // polymorphism my beloved
if((core_gene.use_max && core_gene.value < genemod_var) || (!core_gene.use_max && core_gene.value > genemod_var))
var/gene_name = lowertext(core_gene.name)
dat += " This device's extraction capabilities are currently limited to [genemod_var] [gene_name]. \
@@ -279,6 +307,9 @@
ui_modal_boolean(src, action, dat, yes_text = "Extract", no_text = "Cancel", delegate = PROC_REF(gene_extract))
if("bulk_replace_core")
ui_modal_boolean(src, action, "Are you sure you want to replace ALL core genes of the [seed]?" , yes_text = "Replace", no_text = "Cancel", delegate = PROC_REF(bulk_replace_core))
if("replace")
ui_modal_boolean(src, action, "Are you sure you want to replace [target.get_name()] gene with [disk.gene.get_name()]?", yes_text = "Replace", no_text = "Cancel", delegate = PROC_REF(gene_replace))
@@ -286,7 +317,7 @@
ui_modal_boolean(src, action, "Are you sure you want to remove [target.get_name()] gene from the [seed]" , yes_text = "Remove", no_text = "Cancel", delegate = PROC_REF(gene_remove))
if("insert")
if(!istype(disk.gene, /datum/plant_gene/core) && disk.gene.can_add(seed))
if(!istype(disk.gene, /datum/plant_gene/core) && !disk.is_bulk_core && disk.gene.can_add(seed))
seed.genes += disk.gene.Copy()
if(istype(disk.gene, /datum/plant_gene/reagent))
seed.reagents_from_genes()
@@ -308,6 +339,7 @@
/obj/machinery/plantgenes/proc/gene_extract()
if(!disk || disk.read_only)
return
disk.is_bulk_core = FALSE
disk.gene = target.Copy()
if(istype(disk.gene, /datum/plant_gene/core))
var/datum/plant_gene/core/core_gene = disk.gene
@@ -324,7 +356,7 @@
target = null
/obj/machinery/plantgenes/proc/gene_replace()
if(!disk?.gene)
if(!disk?.gene || disk.is_bulk_core)
return
if(!istype(target, /datum/plant_gene/core))
return
@@ -338,6 +370,43 @@
update_genes()
target = null
/obj/machinery/plantgenes/proc/bulk_extract_core()
if(!disk || disk.read_only)
return
disk.seeds_needed = seeds_for_bulk_core
if(disk.core_matches(seed))
disk.seeds_scanned += 1
else
disk.seeds_scanned = 1
disk.is_bulk_core = TRUE
disk.gene = null
disk.core_genes = list()
for(var/datum/plant_gene/core/gene in core_genes)
var/datum/plant_gene/core/C = gene.Copy()
disk.core_genes += C
disk.update_name()
QDEL_NULL(seed)
update_icon(UPDATE_OVERLAYS)
update_genes()
target = null
/obj/machinery/plantgenes/proc/bulk_replace_core()
if(!disk?.is_bulk_core)
return
if(disk.seeds_scanned < disk.seeds_needed)
return
for(var/datum/plant_gene/gene in seed.genes)
if(istype(gene, /datum/plant_gene/core))
seed.genes -= gene
for(var/datum/plant_gene/core/gene in disk.core_genes)
var/datum/plant_gene/core/C = gene.Copy()
seed.genes += C
C.apply_stat(seed)
repaint_seed()
update_genes()
target = null
/obj/machinery/plantgenes/proc/insert_seed(obj/item/seeds/S)
if(!istype(S) || seed)
return
@@ -386,9 +455,18 @@
desc = "A disk for storing plant genetic data."
icon_state = "datadisk_hydro"
materials = list(MAT_METAL=30, MAT_GLASS=10)
var/datum/plant_gene/gene
var/ui_name = "Empty Disk"
var/is_bulk_core = FALSE
var/read_only = 0 //Well, it's still a floppy disk
// For single genes
var/datum/plant_gene/gene
// For bulk core genes
var/list/core_genes = list()
var/seeds_scanned = 0
var/seeds_needed = 5
/obj/item/disk/plantgene/New()
..()
update_icon(UPDATE_OVERLAYS)
@@ -406,11 +484,41 @@
. = ..()
if(HAS_TRAIT(src, TRAIT_CMAGGED))
name = "nuclear authentication disk"
ui_name = "nuclear authentication disk?"
return
if(gene)
name = "[gene.get_name()] (Plant Data Disk)"
if(!is_bulk_core && gene)
name = "[gene.get_name()] (plant data disk)"
ui_name = "[gene.get_name()]"
else if(is_bulk_core)
name = ""
if(seeds_scanned < seeds_needed)
name += "[round(seeds_scanned/seeds_needed*100,1)]% of "
name += "Core gene set "
ui_name = "Core "
for(var/i in 1 to length(core_genes))
if(i > 1)
name += "/"
ui_name += "/"
var/datum/plant_gene/core/core_gene = core_genes[i]
name += "[core_gene.value]"
ui_name += "[core_gene.value]"
name += " (plant data disk)"
if(seeds_scanned < seeds_needed)
ui_name += " ([round(seeds_scanned / seeds_needed * 100, 1)]%)"
else
name = "plant data disk"
ui_name = "Empty Disk"
/obj/item/disk/plantgene/proc/core_matches(obj/item/seeds/seed)
if(!is_bulk_core)
return FALSE
for(var/datum/plant_gene/core/gene in core_genes)
var/datum/plant_gene/core/seed_gene = seed.get_gene(gene.type)
if(gene.value != seed_gene.value)
return FALSE
return TRUE
/obj/item/disk/plantgene/update_desc()
. = ..()
+22 -13
View File
@@ -92,19 +92,7 @@
return ..()
if(istype(O, /obj/item/plant_analyzer))
var/msg = "<span class='info'>This is \a <span class='name'>[src].</span>\n"
if(seed)
msg += seed.get_analyzer_text()
var/reag_txt = ""
if(seed)
for(var/reagent_id in seed.reagents_add)
var/datum/reagent/R = GLOB.chemical_reagents_list[reagent_id]
var/amt = reagents.get_reagent_amount(reagent_id)
reag_txt += "\n<span class='info'>- [R.name]: [amt]</span>"
if(reag_txt)
msg += reag_txt
to_chat(user, msg)
send_plant_details(user)
else
if(seed)
for(var/datum/plant_gene/trait/T in seed.genes)
@@ -217,3 +205,24 @@
if(seed.get_gene(/datum/plant_gene/trait/glow/shadow))
return
set_light(0)
/obj/item/food/snacks/grown/proc/send_plant_details(mob/user)
var/msg = "<span class='info'>This is \a </span><span class='name'>[src].</span>\n"
if(seed)
msg += seed.get_analyzer_text()
var/reag_txt = ""
if(seed)
for(var/reagent_id in seed.reagents_add)
var/datum/reagent/R = GLOB.chemical_reagents_list[reagent_id]
var/amt = reagents.get_reagent_amount(reagent_id)
reag_txt += "\n<span class='info'>- [R.name]: [amt]</span>"
if(reag_txt)
msg += reag_txt
to_chat(user, msg)
/obj/item/food/snacks/grown/attack_ghost(mob/dead/observer/user)
if(!istype(user)) // Make sure user is actually an observer. Revenents also use attack_ghost, but do not have the toggle plant analyzer var.
return
if(user.plant_analyzer)
send_plant_details(user)
+5 -8
View File
@@ -17,15 +17,12 @@
/obj/item/seeds/starthistle/harvest(mob/user)
var/obj/machinery/hydroponics/parent = loc
var/seed_count = yield
if(prob(getYield() * 20))
seed_count++
var/output_loc = parent.Adjacent(user) ? user.loc : parent.loc
for(var/i in 1 to seed_count)
var/obj/item/seeds/starthistle/harvestseeds = Copy()
harvestseeds.forceMove(output_loc)
var/output_loc = parent.Adjacent(user) ? user.loc : parent.loc
for(var/i in 1 to getYield())
var/obj/item/seeds/starthistle/harvestseeds = Copy()
harvestseeds.forceMove(output_loc)
parent.update_tray()
parent.update_tray(user)
// Lettuce
/obj/item/seeds/lettuce
+15 -6
View File
@@ -39,12 +39,7 @@
/obj/item/grown/attackby(obj/item/O, mob/user, params)
..()
if(istype(O, /obj/item/plant_analyzer))
var/msg = "<span class='info'>This is \a <span class='name'>[src]</span>\n"
if(seed)
msg += seed.get_analyzer_text()
msg += "</span>"
to_chat(usr, msg)
return
send_plant_details(user)
/obj/item/grown/proc/add_juice()
if(reagents)
@@ -69,3 +64,17 @@
if(seed.get_gene(/datum/plant_gene/trait/glow/shadow))
return
set_light(0)
/obj/item/grown/proc/send_plant_details(mob/user)
var/msg = "<span class='info'>This is \a </span><span class='name'>[src]</span>\n"
if(seed)
msg += seed.get_analyzer_text()
msg += "</span>"
to_chat(usr, msg)
return
/obj/item/grown/attack_ghost(mob/dead/observer/user)
if(!istype(user)) // Make sure user is actually an observer. Revenents also use attack_ghost, but do not have the toggle plant analyzer var.
return
if(user.plant_analyzer)
send_plant_details(user)
+10 -4
View File
@@ -288,24 +288,30 @@
/obj/item/reagent_containers/glass/bottle/nutrient/ez
name = "jug of E-Z-Nutrient"
desc = "Contains a fertilizer that causes mild mutations with each harvest."
desc = "Contains a basic fertilizer with no special traits."
icon = 'icons/obj/chemical.dmi'
icon_state = "plastic_jug_ez"
list_reagents = list("eznutriment" = 80)
list_reagents = list("eznutrient" = 80)
/obj/item/reagent_containers/glass/bottle/nutrient/mut
name = "jug of Mutrient"
desc = "Contains a fertilizer that causes mild mutations with each harvest."
icon_state = "plastic_jug_mut"
list_reagents = list("mutrient" = 80)
/obj/item/reagent_containers/glass/bottle/nutrient/l4z
name = "jug of Left 4 Zed"
desc = "Contains a fertilizer that limits plant yields to no more than one and causes significant mutations in plants."
icon = 'icons/obj/chemical.dmi'
icon_state = "plastic_jug_l4z"
list_reagents = list("left4zednutriment" = 80)
list_reagents = list("left4zednutrient" = 80)
/obj/item/reagent_containers/glass/bottle/nutrient/rh
name = "jug of Robust Harvest"
desc = "Contains a fertilizer that increases the yield of a plant by 30% while causing no mutations."
icon = 'icons/obj/chemical.dmi'
icon_state = "plastic_jug_rh"
list_reagents = list("robustharvestnutriment" = 80)
list_reagents = list("robustharvestnutrient" = 80)
/obj/item/reagent_containers/glass/bottle/nutrient/empty
icon = 'icons/obj/chemical.dmi'
+97 -52
View File
@@ -5,31 +5,54 @@
density = TRUE
anchored = TRUE
pixel_y = 8
var/waterlevel = 100 //The amount of water in the tray (max 100)
var/maxwater = 100 //The maximum amount of water in the tray
var/nutrilevel = 10 //The amount of nutrient in the tray (max 10)
var/maxnutri = 10 //The maximum nutrient of water in the tray
var/pestlevel = 0 //The amount of pests in the tray (max 10)
var/weedlevel = 0 //The amount of weeds in the tray (max 10)
var/yieldmod = 1 //Nutriment's effect on yield
var/mutmod = 1 //Nutriment's effect on mutations
var/toxic = 0 //Toxicity in the tray?
var/age = 0 //Current age
var/dead = FALSE //Is it dead?
var/plant_health //Its health
var/lastproduce = 0 //Last time it was harvested
var/lastcycle = 0 //Used for timing of cycles.
var/cycledelay = 200 //About 10 seconds / cycle
var/harvest = FALSE //Ready to harvest?
var/obj/item/seeds/myseed = null //The currently planted seed
/// The amount of water in the tray (max 100)
var/waterlevel = 100
/// The maximum amount of water in the tray
var/maxwater = 100
/// The amount of nutrient in the tray (max 10)
var/nutrilevel = 10
/// The maximum nutrient of water in the tray
var/maxnutri = 10
/// The amount of pests in the tray (max 10)
var/pestlevel = 0
/// The amount of weeds in the tray (max 10)
var/weedlevel = 0
/// Nutrient in use
var/datum/reagent/plantnutrient/nutrient = /datum/reagent/plantnutrient/eznutrient
/// Nutrient's effect on yield
var/yieldmod = 1
/// Nutrient's effect on mutations
var/mutmod = 1
/// Toxicity in the tray
var/toxic = 0
/// Current age
var/age = 0
/// Is it dead?
var/dead = FALSE
/// Its health
var/plant_health
/// Last time it was harvested
var/lastproduce = 0
/// Used for timing of cycles.
var/lastcycle = 0
/// Amount of time per plant cycle
var/cycledelay = 20 SECONDS
/// Ready to harvest?
var/harvest = FALSE
/// The currently planted seed
var/obj/item/seeds/myseed = null
var/rating = 1
var/wrenchable = TRUE
var/lid_closed = FALSE
var/recent_bee_visit = FALSE //Have we been visited by a bee recently, so bees dont overpollinate one plant
var/using_irrigation = FALSE //If the tray is connected to other trays via irrigation hoses
var/self_sufficiency_req = 20 //Required total dose to make a self-sufficient hydro tray. 1:1 with earthsblood.
/// Have we been visited by a bee recently, so bees dont overpollinate one plant
var/recent_bee_visit = FALSE
/// If the tray is connected to other trays via irrigation hoses
var/using_irrigation = FALSE
/// Required total dose to make a self-sufficient hydro tray. 1:1 with earthsblood.
var/self_sufficiency_req = 20
var/self_sufficiency_progress = 0
var/self_sustaining = FALSE //If the tray generates nutrients and water on its own
/// If the tray generates nutrients and water on its own
var/self_sustaining = FALSE
hud_possible = list (PLANT_NUTRIENT_HUD, PLANT_WATER_HUD, PLANT_STATUS_HUD, PLANT_HEALTH_HUD, PLANT_TOXIN_HUD, PLANT_PEST_HUD, PLANT_WEED_HUD)
/obj/machinery/hydroponics/Initialize(mapload)
@@ -178,6 +201,12 @@
if(lightAmt < 4)
adjustHealth(-2 / rating)
//Weed overtaking////////////////////////////////////////////////////////
if(weedlevel >= 10 && prob(50)) // At this point the plant is kind of fucked. Weeds can overtake the plant spot.
if(!myseed.get_gene(/datum/plant_gene/trait/plant_type/weed_hardy) && !myseed.get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism)) // If a normal plant
weedinvasion()
needs_update = 1
//Water//////////////////////////////////////////////////////////////////
// Drink random amount of water
adjustWater(-rand(1,6) / rating)
@@ -228,7 +257,7 @@
// Harvest code
if(age > myseed.production && (age - lastproduce) >= myseed.production && (!harvest && !dead))
nutrimentMutation()
nutrientMutation()
if(myseed && myseed.yield != -1) // Unharvestable shouldn't be harvested
harvest = TRUE
plant_hud_set_status()
@@ -237,22 +266,16 @@
if(prob(5)) // On each tick, there's a 5 percent chance the pest population will increase
adjustPests(1 / rating)
else
if(weedlevel >= 10 && prob(50))
weedinvasion() // Weed invasion into empty tray
needs_update = 1
if(waterlevel > 10 && nutrilevel > 0 && prob(10)) // If there's no plant, the percentage chance is 10%
adjustWeeds(1 / rating)
// Weeeeeeeeeeeeeeedddssss
if(weedlevel >= 10 && prob(50)) // At this point the plant is kind of fucked. Weeds can overtake the plant spot.
if(myseed)
if(!myseed.get_gene(/datum/plant_gene/trait/plant_type/weed_hardy) && !myseed.get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism)) // If a normal plant
weedinvasion()
else
weedinvasion() // Weed invasion into empty tray
needs_update = 1
if(needs_update)
update_state()
return
/obj/machinery/hydroponics/proc/nutrimentMutation()
/obj/machinery/hydroponics/proc/nutrientMutation()
if(mutmod == 0)
return
if(mutmod == 1)
@@ -524,21 +547,30 @@
adjustHealth(-round(reagents.get_reagent_amount("radium") * 1))
adjustToxic(round(reagents.get_reagent_amount("radium") * 3)) // Radium is harsher (OOC: also easier to produce)
// Nutriments
if(reagents.has_reagent("eznutriment", 1))
// Nutrients
if(reagents.has_reagent("eznutrient", 1))
nutrient = /datum/reagent/plantnutrient/eznutrient
yieldmod = 1
mutmod = 0
adjustNutri(round(reagents.get_reagent_amount("eznutrient") * 1))
if(reagents.has_reagent("mutrient", 1))
nutrient = /datum/reagent/plantnutrient/mut
yieldmod = 1
mutmod = 1
adjustNutri(round(reagents.get_reagent_amount("eznutriment") * 1))
adjustNutri(round(reagents.get_reagent_amount("mutrient") * 1))
if(reagents.has_reagent("left4zednutriment", 1))
if(reagents.has_reagent("left4zednutrient", 1))
nutrient = /datum/reagent/plantnutrient/left4zednutrient
yieldmod = 0
mutmod = 2
adjustNutri(round(reagents.get_reagent_amount("left4zednutriment") * 1))
adjustNutri(round(reagents.get_reagent_amount("left4zednutrient") * 1))
if(reagents.has_reagent("robustharvestnutriment", 1))
if(reagents.has_reagent("robustharvestnutrient", 1))
nutrient = /datum/reagent/plantnutrient/robustharvestnutrient
yieldmod = 1.3
mutmod = 0
adjustNutri(round(reagents.get_reagent_amount("robustharvestnutriment") *1 ))
adjustNutri(round(reagents.get_reagent_amount("robustharvestnutrient") *1 ))
//Fish Water is both an excellent fertilizer and waters
@@ -800,19 +832,7 @@
to_chat(user, "<span class='warning'>[src] already has seeds in it!</span>")
else if(istype(O, /obj/item/plant_analyzer))
if(myseed)
to_chat(user, "*** <B>[myseed.plantname]</B> ***") //Carn: now reports the plants growing, not the seeds.
to_chat(user, "- Plant Age: <span class='notice'>[age]</span>")
var/list/text_string = myseed.get_analyzer_text()
if(text_string)
to_chat(user, text_string)
else
to_chat(user, "<B>No plant found.</B>")
to_chat(user, "- Weed level: <span class='notice'>[weedlevel] / 10</span>")
to_chat(user, "- Pest level: <span class='notice'>[pestlevel] / 10</span>")
to_chat(user, "- Toxicity level: <span class='notice'>[toxic] / 100</span>")
to_chat(user, "- Water level: <span class='notice'>[waterlevel] / [maxwater]</span>")
to_chat(user, "- Nutrition level: <span class='notice'>[nutrilevel] / [maxnutri]</span>")
send_plant_details(user)
else if(istype(O, /obj/item/cultivator))
if(weedlevel > 0)
@@ -1021,3 +1041,28 @@
if(reagent_source) // If the source wasn't composted and destroyed
reagent_source.update_icon()
/obj/machinery/hydroponics/proc/send_plant_details(mob/user)
if(myseed)
to_chat(user, "*** <b>[myseed.plantname]</b> ***")
to_chat(user, "- Plant Age: <span class='notice'>[age]</span>")
var/next_harvest = (age <= myseed.maturation ? myseed.maturation : lastproduce) + myseed.production
to_chat(user, "- Next Harvest At: <span class='notice'>[next_harvest]</span>")
var/list/text_string = myseed.get_analyzer_text()
if(text_string)
to_chat(user, text_string)
else
to_chat(user, "<b>No plant found.</b>")
to_chat(user, "- Weed level: <span class='notice'>[weedlevel] / 10</span>")
to_chat(user, "- Pest level: <span class='notice'>[pestlevel] / 10</span>")
to_chat(user, "- Toxicity level: <span class='notice'>[toxic] / 100</span>")
to_chat(user, "- Water level: <span class='notice'>[waterlevel] / [maxwater]</span>")
to_chat(user, "- Nutrition level: <span class='notice'>[nutrilevel] / [maxnutri]</span>")
to_chat(user, "&nbsp;&nbsp;Nutrient: <span class='notice'>[initial(nutrient.name)]<br>&nbsp;&nbsp;[initial(nutrient.description)]</span>")
/obj/machinery/hydroponics/attack_ghost(mob/dead/observer/user)
if(!istype(user)) // Make sure user is actually an observer. Revenents also use attack_ghost, but do not have the toggle plant analyzer var.
return
if(user.plant_analyzer)
send_plant_details(user)
+6 -4
View File
@@ -134,14 +134,17 @@
/obj/machinery/seed_extractor/ui_data(mob/user)
var/list/data = list()
data["icons"] = list()
data["seeds"] = list()
for(var/datum/seed_pile/O in piles)
var/obj/item/I = O.path
var/icon/base64icon = GLOB.seeds_cached_base64_icons["[initial(I.icon)][initial(I.icon_state)]"]
if(!base64icon)
base64icon = icon2base64(icon(initial(I.icon), initial(I.icon_state), SOUTH, 1))
GLOB.seeds_cached_base64_icons["[initial(I.icon)][initial(I.icon_state)]"] = base64icon
data["icons"]["[initial(I.icon)][initial(I.icon_state)]"] = base64icon
var/list/seed_info = list(
"image" = "[base64icon]",
"image" = "[initial(I.icon)][initial(I.icon_state)]",
"id" = O.id,
"name" = O.name,
"variant" = O.variant,
@@ -153,9 +156,8 @@
"potency" = O.potency,
"amount" = O.amount,
)
data["stored_seeds"] += list(seed_info)
data["seeds"] += list(seed_info)
data["vend_amount"] = vend_amount
return data
/obj/machinery/seed_extractor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
@@ -164,7 +166,7 @@
. = FALSE
switch(action)
if("vend")
vend_seed(params["seedid"], params["seedvariant"], vend_amount)
vend_seed(params["seed_id"], params["seed_variant"], params["vend_amount"])
add_fingerprint(usr)
. = TRUE
if("set_vend_amount")
+9 -3
View File
@@ -40,8 +40,8 @@
/obj/item/seeds/New(loc, nogenes = 0)
..()
pixel_x = rand(-8, 8)
pixel_y = rand(-8, 8)
pixel_x = rand(-6, 6)
pixel_y = rand(-6, 6)
if(!icon_grow)
icon_grow = "[species]-grow"
@@ -132,8 +132,8 @@
/obj/item/seeds/proc/getYield()
var/return_yield = yield
var/obj/machinery/hydroponics/parent = loc
if(istype(loc, /obj/machinery/hydroponics))
var/obj/machinery/hydroponics/parent = loc
if(parent.yieldmod == 0)
return_yield = min(return_yield, 1) // 1 if above zero, 0 otherwise
else
@@ -418,3 +418,9 @@
genes += P
else
qdel(P)
/obj/item/seeds/attack_ghost(mob/dead/observer/user)
if(!istype(user)) // Make sure user is actually an observer. Revenents also use attack_ghost, but do not have the toggle plant analyzer var.
return
if(user.plant_analyzer)
to_chat(user, get_analyzer_text())
@@ -36,6 +36,8 @@ GLOBAL_DATUM_INIT(ghost_crew_monitor, /datum/ui_module/crew_monitor/ghost, new)
var/health_scan = FALSE //does the ghost have health scanner mode on? by default it should be off
///toggle for ghost gas analyzer
var/gas_analyzer = FALSE
///toggle for ghost plant analyzer
var/plant_analyzer = FALSE
var/datum/orbit_menu/orbit_menu
/// The "color" their runechat would have had
var/alive_runechat_color = "#FFFFFF"
@@ -585,6 +587,18 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
to_chat(src, "<span class='notice'>Gas Analyzer enabled. Click on a pipe to analyze.</span>")
gas_analyzer = TRUE
/mob/dead/observer/verb/toggle_plant_anaylzer()
set name = "Toggle Plant Analyzer"
set desc = "Toggles wether you can anaylze plants and seeds on click"
set category = "Ghost"
if(plant_analyzer)
to_chat(src, "<span class='notice'>Plant Analyzer disabled.</span>")
plant_analyzer = FALSE
else
to_chat(src, "<span class='notice'>Plant Analyzer enabled. Click on a plant or seed to analyze.</span>")
plant_analyzer = TRUE
/mob/dead/observer/verb/analyze_air()
set name = "Analyze Air"
set category = "Ghost"
@@ -9,7 +9,7 @@ emp_act
/mob/living/carbon/human/bullet_act(obj/item/projectile/P, def_zone)
if(!dna.species.bullet_act(P, src))
if(!dna.species.bullet_act(P, src, def_zone))
add_attack_logs(P.firer, src, "hit by [P.type] but got deflected by species '[dna.species]'")
P.reflect_back(src) //It has to be here, not on species. Why? Who knows. Testing showed me no reason why it doesn't work on species, and neither did tracing. It has to be here, or it gets qdel'd by bump.
return -1
@@ -111,24 +111,22 @@
H.adjustBruteLoss(2)
..()
/datum/species/diona/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H)
switch(P.type)
if(/obj/item/projectile/energy/floramut)
if(prob(15))
H.rad_act(rand(30, 80))
H.Weaken(10 SECONDS)
H.visible_message("<span class='warning'>[H] writhes in pain as [H.p_their()] vacuoles boil.</span>", "<span class='userdanger'>You writhe in pain as your vacuoles boil!</span>", "<span class='italics'>You hear the crunching of leaves.</span>")
if(prob(80))
randmutb(H)
domutcheck(H)
else
randmutg(H)
domutcheck(H)
else
H.adjustFireLoss(rand(5, 15))
H.show_message("<span class='warning'>The radiation beam singes you!</span>")
if(/obj/item/projectile/energy/florayield)
H.set_nutrition(min(H.nutrition + 30, NUTRITION_LEVEL_FULL))
/datum/species/diona/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H, def_zone)
if(istype(P, /obj/item/projectile/energy/floramut))
P.nodamage = TRUE
H.Weaken(1 SECONDS)
if(prob(80))
randmutb(H)
else
randmutg(H)
H.visible_message("[H] writhes for a moment as [H.p_their()] nymphs squirm and mutate.", "All of you squirm uncomfortably for a moment as you feel your genes changing.")
else if(istype(P, /obj/item/projectile/energy/florayield))
P.nodamage = TRUE
var/obj/item/organ/external/organ = H.get_organ(check_zone(def_zone))
if(!organ)
organ = H.get_organ("chest")
organ.heal_damage(5, 5)
H.visible_message("[H] seems invogorated as [P] hits [H.p_their()] [organ.name].", "Your [organ.name] greedily absorbs [P].")
return TRUE
/// Same name and everything; we want the same limitations on them; we just want their regeneration to kick in at all times and them to have special factions
@@ -71,6 +71,13 @@
selfcharge = TRUE
can_holster = TRUE
/obj/item/gun/energy/floragun/pre_attack(atom/A, mob/living/user, params)
if(istype(A, /obj/machinery/hydroponics))
// Calling afterattack from pre_attack looks stupid, but afterattack with proximity FALSE is what makes the gun fire, and we're returning FALSE to cancel the melee attack.
afterattack(A, user, FALSE, params)
return FALSE
return ..()
// Meteor Gun //
/obj/item/gun/energy/meteorgun
name = "meteor gun"
@@ -145,18 +145,17 @@
/obj/item/projectile/energy/floramut
name = "alpha somatoray"
icon_state = "energy"
damage = 0
damage_type = TOX
nodamage = 1
damage = 3
damage_type = CLONE
impact_effect_type = /obj/effect/temp_visual/impact_effect/green_laser
flag = "energy"
/obj/item/projectile/energy/florayield
name = "beta somatoray"
icon_state = "energy2"
damage = 0
damage_type = TOX
nodamage = 1
damage = 3
damage_type = CLONE
impact_effect_type = /obj/effect/temp_visual/impact_effect/green_laser
flag = "energy"
/obj/item/projectile/energy/mindflayer
@@ -61,9 +61,10 @@
dispensable_reagents = list(
"mutagen",
"saltpetre",
"eznutriment",
"left4zednutriment",
"robustharvestnutriment",
"eznutrient",
"mutrient",
"left4zednutrient",
"robustharvestnutrient",
"water",
"atrazine",
"pestkiller",
@@ -608,9 +609,10 @@
dispensable_reagents = list(
"mutagen",
"saltpetre",
"eznutriment",
"left4zednutriment",
"robustharvestnutriment",
"eznutrient",
"mutrient",
"left4zednutrient",
"robustharvestnutrient",
"water",
"atrazine",
"pestkiller",
@@ -591,40 +591,48 @@
//////////////////////////////////Hydroponics stuff///////////////////////////////
/datum/reagent/plantnutriment
name = "Generic nutriment"
id = "plantnutriment"
description = "Some kind of nutriment. You can't really tell what it is. You should probably report it, along with how you obtained it."
/datum/reagent/plantnutrient
name = "Generic nutrient"
id = "plantnutrient"
description = "Some kind of nutrient. You can't really tell what it is. You should probably report it, along with how you obtained it."
color = "#000000" // RBG: 0, 0, 0
var/tox_prob = 0
taste_description = "puke"
/datum/reagent/plantnutriment/on_mob_life(mob/living/M)
/datum/reagent/plantnutrient/on_mob_life(mob/living/M)
var/update_flags = STATUS_UPDATE_NONE
if(prob(tox_prob))
update_flags |= M.adjustToxLoss(1*REAGENTS_EFFECT_MULTIPLIER, FALSE)
return ..() | update_flags
/datum/reagent/plantnutriment/eznutriment
/datum/reagent/plantnutrient/eznutrient
name = "E-Z-Nutrient"
id = "eznutriment"
description = "Cheap and extremely common type of plant nutriment."
color = "#376400" // RBG: 50, 100, 0
tox_prob = 10
id = "eznutrient"
description = "Cheap and boring nutrition for plants."
color = "#504700" // RBG: 80, 70, 0
tox_prob = 5
taste_description = "obscurity and toil"
/datum/reagent/plantnutriment/left4zednutriment
/datum/reagent/plantnutrient/mut
name = "Mutrient"
id = "mutrient"
description = "Plant nutrient designed to trigger mild genetic drift."
color = "#376400" // RBG: 50, 100, 0
tox_prob = 10
taste_description = "change"
/datum/reagent/plantnutrient/left4zednutrient
name = "Left 4 Zed"
id = "left4zednutriment"
description = "Unstable nutriment that makes plants mutate more often than usual."
id = "left4zednutrient"
description = "Unstable nutrient that makes plants mutate strongly at the cost of minimal yield."
color = "#2A1680" // RBG: 42, 128, 22
tox_prob = 25
taste_description = "evolution"
/datum/reagent/plantnutriment/robustharvestnutriment
/datum/reagent/plantnutrient/robustharvestnutrient
name = "Robust Harvest"
id = "robustharvestnutriment"
description = "Very potent nutriment that prevents plants from mutating."
id = "robustharvestnutrient"
description = "Very potent nutrient that increases yield."
color = "#9D9D00" // RBG: 157, 157, 0
tox_prob = 15
taste_description = "bountifulness"
@@ -1028,7 +1028,7 @@
name = "Islay Whiskey"
id = "islaywhiskey"
result = "islaywhiskey"
required_reagents = list("eznutriment" = 1, "whiskey" = 1, "nutriment" = 1)
required_reagents = list("eznutrient" = 1, "whiskey" = 1, "nutriment" = 1)
result_amount = 3
mix_sound = 'sound/goonstation/misc/drinkfizz.ogg'
@@ -99,6 +99,14 @@
build_path = /obj/item/reagent_containers/glass/bottle/nutrient/ez
category = list("initial","Botany Chemicals")
/datum/design/mut_nut
name = "Mutrient"
id = "mut_nut"
build_type = BIOGENERATOR
materials = list(MAT_BIOMASS = 15)
build_path = /obj/item/reagent_containers/glass/bottle/nutrient/mut
category = list("initial", "Botany Chemicals")
/datum/design/l4z_nut
name = "Left 4 Zed"
id = "l4z_nut"