mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 10:12:45 +00:00
855 lines
26 KiB
Plaintext
855 lines
26 KiB
Plaintext
/obj/machinery/portable_atmospherics/hydroponics
|
|
name = "hydroponics tray"
|
|
icon = 'icons/obj/hydroponics_machines.dmi'
|
|
icon_state = "hydrotray3"
|
|
density = 1
|
|
anchored = 1
|
|
flags = OPENCONTAINER
|
|
volume = 100
|
|
|
|
var/mechanical = 1 // Set to 0 to stop it from drawing the alert lights.
|
|
|
|
// Plant maintenance vars.
|
|
var/waterlevel = 100 // Water (max 100)
|
|
var/nutrilevel = 10 // Nutrient (max 10)
|
|
var/pestlevel = 0 // Pests (max 10)
|
|
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 wa 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/mutation_level = 0 // When it hits 100, the plant mutates.
|
|
|
|
// Mechanical concerns.
|
|
var/health = 0 // Plant health.
|
|
var/lastproduce = 0 // Last time tray was harvested
|
|
var/lastcycle = 0 // Cycle timing/tracking var.
|
|
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()
|
|
|
|
// Seed details/line data.
|
|
var/datum/seed/seed = null // The currently planted seed
|
|
|
|
// Reagent information for process(), consider moving this to a controller along
|
|
// with cycle information under 'mechanical concerns' at some point.
|
|
var/global/list/toxic_reagents = list(
|
|
"anti_toxin" = -2,
|
|
"toxin" = 2,
|
|
"fluorine" = 2.5,
|
|
"chlorine" = 1.5,
|
|
"sacid" = 1.5,
|
|
"pacid" = 3,
|
|
"plantbgone" = 3,
|
|
"cryoxadone" = -3,
|
|
"radium" = 2
|
|
)
|
|
var/global/list/nutrient_reagents = list(
|
|
"milk" = 0.1,
|
|
"beer" = 0.25,
|
|
"phosphorus" = 0.1,
|
|
"sugar" = 0.1,
|
|
"sodawater" = 0.1,
|
|
"ammonia" = 1,
|
|
"diethylamine" = 2,
|
|
"nutriment" = 1,
|
|
"adminordrazine" = 1,
|
|
"eznutrient" = 1,
|
|
"robustharvest" = 1,
|
|
"left4zed" = 1
|
|
)
|
|
var/global/list/weedkiller_reagents = list(
|
|
"fluorine" = -4,
|
|
"chlorine" = -3,
|
|
"phosphorus" = -2,
|
|
"sugar" = 2,
|
|
"sacid" = -2,
|
|
"pacid" = -4,
|
|
"plantbgone" = -8,
|
|
"adminordrazine" = -5
|
|
)
|
|
var/global/list/pestkiller_reagents = list(
|
|
"sugar" = 2,
|
|
"diethylamine" = -2,
|
|
"adminordrazine" = -5
|
|
)
|
|
var/global/list/water_reagents = list(
|
|
"water" = 1,
|
|
"adminordrazine" = 1,
|
|
"milk" = 0.9,
|
|
"beer" = 0.7,
|
|
"fluorine" = -0.5,
|
|
"chlorine" = -0.5,
|
|
"phosphorus" = -0.5,
|
|
"water" = 1,
|
|
"sodawater" = 1,
|
|
)
|
|
|
|
// 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 ),
|
|
"pacid" = list( -2, 0, 0 ),
|
|
"plantbgone" = list( -2, 0, 0.2 ),
|
|
"cryoxadone" = list( 3, 0, 0 ),
|
|
"ammonia" = list( 0.5, 0, 0 ),
|
|
"diethylamine" = list( 1, 0, 0 ),
|
|
"nutriment" = list( 0.5, 0.1, 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 )
|
|
)
|
|
|
|
// Mutagen list specifies minimum value for the mutation to take place, rather
|
|
// than a bound as the lists above specify.
|
|
var/global/list/mutagenic_reagents = list(
|
|
"radium" = 8,
|
|
"mutagen" = 15
|
|
)
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/attack_generic(var/mob/user)
|
|
if(istype(user,/mob/living/carbon/alien/diona))
|
|
var/mob/living/carbon/alien/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("<font color='blue'><b>[nymph]</b> begins rooting through [src], ripping out weeds and eating them noisily.</font>","<font color='blue'>You begin rooting through [src], ripping out weeds and eating them noisily.</font>")
|
|
else if(nymph.nutrition > 100 && nutrilevel < 10)
|
|
nymph.nutrition -= ((10-nutrilevel)*5)
|
|
nutrilevel = 10
|
|
nymph.visible_message("<font color='blue'><b>[nymph]</b> secretes a trickle of green liquid, refilling [src].</font>","<font color='blue'>You secrete a trickle of green liquid, refilling [src].</font>")
|
|
else
|
|
nymph.visible_message("<font color='blue'><b>[nymph]</b> rolls around in [src] for a bit.</font>","<font color='blue'>You roll around in [src] for a bit.</font>")
|
|
return
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/proc/can_label()
|
|
return 1
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/New()
|
|
..()
|
|
temp_chem_holder = new()
|
|
temp_chem_holder.create_reagents(10)
|
|
create_reagents(200)
|
|
connect()
|
|
update_icon()
|
|
|
|
/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.get_trait(TRAIT_IMMUTABLE) > 0)
|
|
return
|
|
|
|
//Override for somatoray projectiles.
|
|
if(istype(Proj ,/obj/item/projectile/energy/floramut) && prob(20))
|
|
mutate(1)
|
|
return
|
|
else if(istype(Proj ,/obj/item/projectile/energy/florayield) && prob(20))
|
|
yield_mod = min(10,yield_mod+rand(1,2))
|
|
return
|
|
|
|
..()
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/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/portable_atmospherics/hydroponics/process()
|
|
|
|
//Do this even if we're not ready for a plant cycle.
|
|
process_reagents()
|
|
|
|
// Update values every cycle rather than every process() tick.
|
|
if(force_update)
|
|
force_update = 0
|
|
else if(world.time < (lastcycle + cycledelay))
|
|
return
|
|
lastcycle = world.time
|
|
|
|
// Mutation level drops each main tick.
|
|
mutation_level -= rand(2,4)
|
|
|
|
// Weeds like water and nutrients, there's a chance the weed population will increase.
|
|
// Bonus chance if the tray is unoccupied.
|
|
if(waterlevel > 10 && nutrilevel > 2 && prob(isnull(seed) ? 5 : 1))
|
|
weedlevel += 1 * HYDRO_SPEED_MULTIPLIER
|
|
|
|
// There's a chance for a weed explosion to happen if the weeds take over.
|
|
// Plants that are themselves weeds (weed_tolerance > 10) are unaffected.
|
|
if (weedlevel >= 10 && prob(10))
|
|
if(!seed || weedlevel >= seed.get_trait(TRAIT_WEED_TOLERANCE))
|
|
weed_invasion()
|
|
|
|
// If there is no seed data (and hence nothing planted),
|
|
// or the plant is dead, process nothing further.
|
|
if(!seed || dead)
|
|
if(mechanical) update_icon() //Harvesting would fail to set alert icons properly.
|
|
return
|
|
|
|
// Advance plant age.
|
|
if(prob(30)) age += 1 * HYDRO_SPEED_MULTIPLIER
|
|
|
|
//Highly mutable plants have a chance of mutating every tick.
|
|
if(seed.get_trait(TRAIT_IMMUTABLE) == -1)
|
|
var/mut_prob = rand(1,100)
|
|
if(mut_prob <= 5) mutate(mut_prob == 1 ? 2 : 1)
|
|
|
|
// Other plants also mutate if enough mutagenic compounds have been added.
|
|
if(!seed.get_trait(TRAIT_IMMUTABLE))
|
|
if(prob(min(mutation_level,100)))
|
|
mutate((rand(100) < 15) ? 2 : 1)
|
|
mutation_level = 0
|
|
|
|
// Maintain tray nutrient and water levels.
|
|
if(seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) > 0 && nutrilevel > 0 && prob(25))
|
|
nutrilevel -= max(0,seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) * HYDRO_SPEED_MULTIPLIER)
|
|
if(seed.get_trait(TRAIT_WATER_CONSUMPTION) > 0 && waterlevel > 0 && prob(25))
|
|
waterlevel -= max(0,seed.get_trait(TRAIT_WATER_CONSUMPTION) * HYDRO_SPEED_MULTIPLIER)
|
|
|
|
// Make sure the plant is not starving or thirsty. Adequate
|
|
// water and nutrients will cause a plant to become healthier.
|
|
var/healthmod = rand(1,3) * HYDRO_SPEED_MULTIPLIER
|
|
if(seed.get_trait(TRAIT_REQUIRES_NUTRIENTS) && prob(35))
|
|
health += (nutrilevel < 2 ? -healthmod : healthmod)
|
|
if(seed.get_trait(TRAIT_REQUIRES_WATER) && prob(35))
|
|
health += (waterlevel < 10 ? -healthmod : healthmod)
|
|
|
|
// Check that pressure, heat and light are all within bounds.
|
|
// First, handle an open system or an unconnected closed system.
|
|
|
|
var/turf/T = loc
|
|
var/datum/gas_mixture/environment
|
|
// If we're closed, take from our internal sources.
|
|
if(closed_system && (connected_port || holding))
|
|
environment = air_contents
|
|
// If atmos input is not there, grab from turf.
|
|
if(!environment && istype(T)) environment = T.return_air()
|
|
if(!environment) return
|
|
|
|
// Seed datum handles gasses, light and pressure.
|
|
health -= seed.handle_environment(T,environment)
|
|
|
|
// If we're attached to a pipenet, then we should let the pipenet know we might have modified some gasses
|
|
if (closed_system && connected_port)
|
|
update_connected_network()
|
|
|
|
// Toxin levels beyond the plant's tolerance cause damage, but
|
|
// toxins are sucked up each tick and slowly reduce over time.
|
|
if(toxins > 0)
|
|
var/toxin_uptake = max(1,round(toxins/10))
|
|
if(toxins > seed.get_trait(TRAIT_TOXINS_TOLERANCE))
|
|
health -= toxin_uptake
|
|
toxins -= toxin_uptake
|
|
|
|
// Check for pests and weeds.
|
|
// Some carnivorous plants happily eat pests.
|
|
if(pestlevel > 0)
|
|
if(seed.get_trait(TRAIT_CARNIVOROUS))
|
|
health += HYDRO_SPEED_MULTIPLIER
|
|
pestlevel -= HYDRO_SPEED_MULTIPLIER
|
|
else if (pestlevel >= seed.get_trait(TRAIT_PEST_TOLERANCE))
|
|
health -= HYDRO_SPEED_MULTIPLIER
|
|
|
|
// Some plants thrive and live off of weeds.
|
|
if(weedlevel > 0)
|
|
if(seed.get_trait(TRAIT_PARASITE))
|
|
health += HYDRO_SPEED_MULTIPLIER
|
|
weedlevel -= HYDRO_SPEED_MULTIPLIER
|
|
else if (weedlevel >= seed.get_trait(TRAIT_WEED_TOLERANCE))
|
|
health -= HYDRO_SPEED_MULTIPLIER
|
|
|
|
// Handle life and death.
|
|
// When the plant dies, weeds thrive and pests die off.
|
|
check_health()
|
|
|
|
// If enough time (in cycles, not ticks) has passed since the plant was harvested, we're ready to harvest again.
|
|
if(seed.products && seed.products.len && \
|
|
(age > seed.get_trait(TRAIT_MATURATION)) && \
|
|
((age - lastproduce) > seed.get_trait(TRAIT_PRODUCTION)) && \
|
|
(!harvest && !dead))
|
|
|
|
harvest = 1
|
|
lastproduce = age
|
|
|
|
if(prob(3)) // On each tick, there's a chance the pest population will increase
|
|
pestlevel += 0.1 * HYDRO_SPEED_MULTIPLIER
|
|
|
|
// Some seeds will self-harvest if you don't keep a lid on them.
|
|
if(seed && seed.can_self_harvest && harvest && !closed_system && prob(5))
|
|
harvest()
|
|
|
|
check_health()
|
|
return
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/proc/check_health()
|
|
if(seed && !dead && health <= 0)
|
|
die()
|
|
check_level_sanity()
|
|
update_icon()
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/proc/die()
|
|
dead = 1
|
|
mutation_level = 0
|
|
harvest = 0
|
|
weedlevel += 1 * HYDRO_SPEED_MULTIPLIER
|
|
pestlevel = 0
|
|
|
|
//Process reagents being input into the tray.
|
|
/obj/machinery/portable_atmospherics/hydroponics/proc/process_reagents()
|
|
|
|
if(!reagents) return
|
|
|
|
if(reagents.total_volume <= 0)
|
|
return
|
|
|
|
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)
|
|
|
|
if(seed && !dead)
|
|
//Handle some general level adjustments.
|
|
if(toxic_reagents[R.id])
|
|
toxins += toxic_reagents[R.id] * reagent_total
|
|
if(weedkiller_reagents[R.id])
|
|
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 += 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.
|
|
if(mutagenic_reagents[R.id])
|
|
mutation_level += reagent_total*mutagenic_reagents[R.id]+mutation_mod
|
|
|
|
// Handle nutrient refilling.
|
|
if(nutrient_reagents[R.id])
|
|
nutrilevel += nutrient_reagents[R.id] * reagent_total
|
|
|
|
// Handle water and water refilling.
|
|
var/water_added = 0
|
|
if(water_reagents[R.id])
|
|
var/water_input = water_reagents[R.id] * reagent_total
|
|
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()
|
|
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)
|
|
return
|
|
|
|
if(closed_system)
|
|
if(user) user << "You can't harvest from the plant while the lid is shut."
|
|
return
|
|
|
|
if(user)
|
|
seed.harvest(user,yield_mod)
|
|
else
|
|
seed.harvest(get_turf(src),yield_mod)
|
|
|
|
// Reset values.
|
|
harvest = 0
|
|
lastproduce = age
|
|
|
|
if(!seed.get_trait(TRAIT_HARVEST_REPEAT))
|
|
yield_mod = 0
|
|
seed = null
|
|
dead = 0
|
|
age = 0
|
|
sampled = 0
|
|
mutation_mod = 0
|
|
|
|
check_health()
|
|
return
|
|
|
|
//Clears out a dead plant.
|
|
/obj/machinery/portable_atmospherics/hydroponics/proc/remove_dead(var/mob/user)
|
|
if(!user || !dead) return
|
|
|
|
if(closed_system)
|
|
user << "You can't remove the dead plant while the lid is shut."
|
|
return
|
|
|
|
seed = null
|
|
dead = 0
|
|
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(mechanical && health <= (seed.get_trait(TRAIT_ENDURANCE) / 2))
|
|
overlays += "over_lowhealth3"
|
|
|
|
if(dead)
|
|
var/ikey = "[seed.get_trait(TRAIT_PLANT_ICON)]-dead"
|
|
var/image/dead_overlay = plant_icon_cache["[ikey]"]
|
|
if(!dead_overlay)
|
|
dead_overlay = image('icons/obj/hydroponics_growing.dmi', "[ikey]")
|
|
overlays |= dead_overlay
|
|
else
|
|
if(!seed.growth_stages)
|
|
seed.update_growth_stages()
|
|
if(!seed.growth_stages)
|
|
world << "<span class='danger'>Seed type [seed.get_trait(TRAIT_PLANT_ICON)] cannot find a growth stage value.</span>"
|
|
return
|
|
var/overlay_stage = 1
|
|
if(age >= seed.get_trait(TRAIT_MATURATION))
|
|
overlay_stage = seed.growth_stages
|
|
lastproduce = age
|
|
else
|
|
overlay_stage = max(1,round(seed.get_trait(TRAIT_MATURATION) / seed.growth_stages))
|
|
|
|
var/ikey = "[seed.get_trait(TRAIT_PLANT_ICON)]-[overlay_stage]"
|
|
var/image/plant_overlay = plant_icon_cache["[ikey]-[seed.get_trait(TRAIT_PLANT_COLOUR)]"]
|
|
if(!plant_overlay)
|
|
plant_overlay = image('icons/obj/hydroponics_growing.dmi', "[ikey]")
|
|
plant_overlay.color = seed.get_trait(TRAIT_PLANT_COLOUR)
|
|
plant_icon_cache["[ikey]-[seed.get_trait(TRAIT_PLANT_COLOUR)]"] = plant_overlay
|
|
overlays |= plant_overlay
|
|
|
|
if(harvest && overlay_stage == seed.growth_stages)
|
|
ikey = "[seed.get_trait(TRAIT_PRODUCT_ICON)]"
|
|
var/image/harvest_overlay = plant_icon_cache["product-[ikey]-[seed.get_trait(TRAIT_PLANT_COLOUR)]"]
|
|
if(!harvest_overlay)
|
|
harvest_overlay = image('icons/obj/hydroponics_products.dmi', "[ikey]")
|
|
harvest_overlay.color = seed.get_trait(TRAIT_PRODUCT_COLOUR)
|
|
plant_icon_cache["product-[ikey]-[seed.get_trait(TRAIT_PRODUCT_COLOUR)]"] = harvest_overlay
|
|
overlays |= harvest_overlay
|
|
|
|
//Draw the cover.
|
|
if(closed_system)
|
|
overlays += "hydrocover"
|
|
|
|
//Updated the various alert icons.
|
|
if(mechanical)
|
|
if(waterlevel <= 10)
|
|
overlays += "over_lowwater3"
|
|
if(nutrilevel <= 2)
|
|
overlays += "over_lownutri3"
|
|
if(weedlevel >= 5 || pestlevel >= 5 || toxins >= 40)
|
|
overlays += "over_alert3"
|
|
if(harvest)
|
|
overlays += "over_harvest3"
|
|
|
|
// Update bioluminescence.
|
|
if(seed)
|
|
if(seed.get_trait(TRAIT_BIOLUM))
|
|
SetLuminosity(round(seed.get_trait(TRAIT_POTENCY)/10))
|
|
if(seed.get_trait(TRAIT_BIOLUM_COLOUR))
|
|
l_color = seed.get_trait(TRAIT_BIOLUM_COLOUR)
|
|
else
|
|
l_color = null
|
|
return
|
|
|
|
SetLuminosity(0)
|
|
return
|
|
|
|
// If a weed growth is sufficient, this proc is called.
|
|
/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"))]
|
|
if(!seed) return //Weed does not exist, someone fucked up.
|
|
|
|
dead = 0
|
|
age = 0
|
|
health = seed.get_trait(TRAIT_ENDURANCE)
|
|
lastcycle = world.time
|
|
harvest = 0
|
|
weedlevel = 0
|
|
pestlevel = 0
|
|
sampled = 0
|
|
update_icon()
|
|
visible_message("<span class='notice'>[src] has been overtaken by [seed.display_name].</span>")
|
|
|
|
return
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/proc/mutate(var/severity)
|
|
|
|
// No seed, no mutations.
|
|
if(!seed)
|
|
return
|
|
|
|
// Check if we should even bother working on the current seed datum.
|
|
if(seed.mutants. && seed.mutants.len && severity > 1)
|
|
mutate_species()
|
|
return
|
|
|
|
// We need to make sure we're not modifying one of the global seed datums.
|
|
// If it's not in the global list, then no products of the line have been
|
|
// harvested yet and it's safe to assume it's restricted to this tray.
|
|
if(!isnull(seed_types[seed.name]))
|
|
seed = seed.diverge()
|
|
seed.mutate(severity,get_turf(src))
|
|
|
|
return
|
|
|
|
/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
|
|
|
|
mutation_level = max(0,min(mutation_level,100))
|
|
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]
|
|
else
|
|
return
|
|
|
|
dead = 0
|
|
mutate(1)
|
|
age = 0
|
|
health = seed.get_trait(TRAIT_ENDURANCE)
|
|
lastcycle = world.time
|
|
harvest = 0
|
|
weedlevel = 0
|
|
|
|
update_icon()
|
|
visible_message("<span class='danger'>The </span><span class='notice'>[previous_plant]</span><span class='danger'> has suddenly mutated into </span><span class='notice'>[seed.display_name]!</span>")
|
|
|
|
return
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
|
|
|
if (O.is_open_container())
|
|
return 0
|
|
|
|
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
|
|
|
|
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()
|
|
|
|
return
|
|
|
|
else if(istype(O, /obj/item/weapon/reagent_containers/syringe))
|
|
|
|
var/obj/item/weapon/reagent_containers/syringe/S = O
|
|
|
|
if (S.mode == 1)
|
|
if(seed)
|
|
return ..()
|
|
else
|
|
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 to draw something from."
|
|
return 1
|
|
|
|
else if (istype(O, /obj/item/seeds))
|
|
|
|
if(!seed)
|
|
|
|
var/obj/item/seeds/S = O
|
|
user.drop_item(O)
|
|
|
|
if(!S.seed)
|
|
user << "The packet seems to be empty. You throw it away."
|
|
del(O)
|
|
return
|
|
|
|
user << "You plant the [S.seed.seed_name] [S.seed.seed_noun]."
|
|
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_health()
|
|
|
|
else
|
|
user << "<span class='danger'>\The [src] already has seeds in it!</span>"
|
|
|
|
else if (istype(O, /obj/item/weapon/minihoe)) // The minihoe
|
|
|
|
if(weedlevel > 0)
|
|
user.visible_message("<span class='danger'>[user] starts uprooting the weeds.</span>", "<span class='danger'>You remove the weeds from the [src].</span>")
|
|
weedlevel = 0
|
|
update_icon()
|
|
else
|
|
user << "<span class='danger'>This plot is completely devoid of weeds. It doesn't need uprooting.</span>"
|
|
|
|
else if (istype(O, /obj/item/weapon/storage/bag/plants))
|
|
|
|
attack_hand(user)
|
|
|
|
var/obj/item/weapon/storage/bag/plants/S = O
|
|
for (var/obj/item/weapon/reagent_containers/food/snacks/grown/G in locate(user.x,user.y,user.z))
|
|
if(!S.can_be_inserted(G))
|
|
return
|
|
S.handle_item_insertion(G, 1)
|
|
|
|
else if ( istype(O, /obj/item/weapon/plantspray) )
|
|
|
|
var/obj/item/weapon/plantspray/spray = O
|
|
user.drop_item(O)
|
|
toxins += spray.toxicity
|
|
pestlevel -= spray.pest_kill_str
|
|
weedlevel -= spray.weed_kill_str
|
|
user << "You spray [src] with [O]."
|
|
playsound(loc, 'sound/effects/spray3.ogg', 50, 1, -6)
|
|
del(O)
|
|
check_health()
|
|
|
|
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)
|
|
return ..()
|
|
|
|
playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
|
|
anchored = !anchored
|
|
user << "You [anchored ? "wrench" : "unwrench"] \the [src]."
|
|
|
|
else if(istype(O, /obj/item/apiary))
|
|
|
|
if(seed)
|
|
user << "<span class='danger'>[src] is already occupied!</span>"
|
|
else
|
|
user.drop_item()
|
|
del(O)
|
|
|
|
var/obj/machinery/apiary/A = new(src.loc)
|
|
A.icon = src.icon
|
|
A.icon_state = src.icon_state
|
|
A.hydrotray_type = src.type
|
|
del(src)
|
|
else if(O.force && seed)
|
|
user.visible_message("<span class='danger'>\The [src] attacks the [seed.display_name] with \the [O]!</span>")
|
|
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)
|
|
remove_dead(user)
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/attack_hand(mob/user as mob)
|
|
|
|
if(istype(usr,/mob/living/silicon))
|
|
return
|
|
|
|
if(harvest)
|
|
harvest(user)
|
|
else if(dead)
|
|
remove_dead(user)
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/examine()
|
|
|
|
..()
|
|
|
|
if(!Adjacent(usr))
|
|
return
|
|
|
|
if(seed)
|
|
usr << "[src] has <span class='notice'>[seed.display_name]</span> planted."
|
|
if(dead)
|
|
usr << "<span class='danger'>The plant is dead.</span>"
|
|
else if(health <= (seed.get_trait(TRAIT_ENDURANCE)/ 2))
|
|
usr << "The plant looks <span class='danger'>unhealthy</span>."
|
|
else
|
|
usr << "[src] is empty."
|
|
usr << "Water: [round(waterlevel,0.1)]/100"
|
|
usr << "Nutrient: [round(nutrilevel,0.1)]/10"
|
|
|
|
if(weedlevel >= 5)
|
|
usr << "[src] is <span class='danger'>infested with weeds</span>!"
|
|
if(pestlevel >= 5)
|
|
usr << "[src] is <span class='danger'>infested with tiny worms</span>!"
|
|
|
|
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/area/A = T.loc
|
|
var/light_available
|
|
if(A)
|
|
if(A.lighting_use_dynamic)
|
|
light_available = max(0,min(10,T.lighting_lumcount)-5)
|
|
else
|
|
light_available = 5
|
|
|
|
usr << "The tray's sensor suite is reporting a light level of [light_available] lumens and a temperature of [environment.temperature]K."
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/verb/close_lid()
|
|
set name = "Toggle Tray Lid"
|
|
set category = "Object"
|
|
set src in view(1)
|
|
|
|
if(!usr || usr.stat || usr.restrained())
|
|
return
|
|
|
|
closed_system = !closed_system
|
|
usr << "You [closed_system ? "close" : "open"] the tray's lid."
|
|
update_icon()
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/soil
|
|
name = "soil"
|
|
icon_state = "soil"
|
|
density = 0
|
|
use_power = 0
|
|
mechanical = 0
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/soil/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
|
if(istype(O,/obj/item/weapon/tank))
|
|
return
|
|
else
|
|
..()
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/soil/New()
|
|
..()
|
|
verbs -= /obj/machinery/portable_atmospherics/hydroponics/verb/close_lid
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/soil/can_label()
|
|
return 0
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/soil/CanPass()
|
|
return 1
|
|
|
|
// This is a hack pending a proper rewrite of the plant controller.
|
|
// Icons for plants are generated as overlays, so setting it to invisible wouldn't work.
|
|
// Hence using a blank icon.
|
|
/obj/machinery/portable_atmospherics/hydroponics/soil/invisible
|
|
name = "plant"
|
|
icon = 'icons/obj/seeds.dmi'
|
|
icon_state = "blank"
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/New(var/newloc,var/datum/seed/newseed)
|
|
..()
|
|
seed = newseed
|
|
dead = 0
|
|
age = 1
|
|
health = seed.get_trait(TRAIT_ENDURANCE)
|
|
lastcycle = world.time
|
|
pixel_y = rand(-5,5)
|
|
check_health()
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/remove_dead()
|
|
..()
|
|
del(src)
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/harvest()
|
|
..()
|
|
if(!seed)
|
|
del(src)
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/die()
|
|
del(src)
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/process()
|
|
if(!seed)
|
|
del(src)
|
|
return
|
|
else if(name=="plant")
|
|
name = seed.display_name
|
|
..()
|
|
|
|
/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/Del()
|
|
// Check if we're masking a decal that needs to be visible again.
|
|
for(var/obj/effect/plant/plant in get_turf(src))
|
|
if(plant.invisibility == INVISIBILITY_MAXIMUM)
|
|
plant.invisibility = initial(plant.invisibility)
|
|
plant.die_off()
|
|
..() |