[MIRROR] Refactors plant traits to use signals + autodocs a lot of plant gene stuff and better vars all over (#3343)

* Refactors plant traits to use signals + autodocs a lot of plant gene stuff and better vars all over (#56841)

Refactors plant traits to use signals instead of looped proc-calls copy-pasted on both types of plant.

Comments / autodocs a lot of the plant genes and their procs.

Renamed a bunch of vars to be more descriptive.

* Refactors plant traits to use signals + autodocs a lot of plant gene stuff and better vars all over

Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
This commit is contained in:
SkyratBot
2021-02-13 10:13:30 +00:00
committed by GitHub
co-authored by MrMelbert
parent 1a442b07d6
commit 455a36a3a8
6 changed files with 460 additions and 285 deletions
+6 -2
View File
@@ -816,8 +816,12 @@
//Plants / Plant Traits
///called when an action causes a plant to be squashed - slipping, throwing, attack_self.
#define COMSIG_PLANT_SQUASH "plant_squash"
///called when a plant with slippery skin is slipped on (mob/victim)
#define COMSIG_PLANT_ON_SLIP "plant_on_slip"
///called when a plant with liquid contents is squashed on (atom/target)
#define COMSIG_PLANT_ON_SQUASH "plant_on_squash"
///called when a plant grows in a tray (obj/machinery/hydroponics)
#define COMSIG_PLANT_ON_GROW "plant_on_grow"
//Gibs
+4 -34
View File
@@ -45,8 +45,9 @@
make_dryable()
for(var/datum/plant_gene/trait/T in seed.genes)
T.on_new(src, loc)
// Go through all traits in their genes and call on_new_plant from them.
for(var/datum/plant_gene/trait/trait in seed.genes)
trait.on_new_plant(src, loc)
. = ..() //Only call it here because we want all the genes and shit to be applied before we add edibility. God this code is a mess.
@@ -64,53 +65,22 @@
eatverbs = eatverbs,\
bite_consumption = bite_consumption_mod ? 1 + round(max_volume / bite_consumption_mod) : bite_consumption,\
microwaved_type = microwaved_type,\
junkiness = junkiness,\
on_consume = CALLBACK(src, .proc/OnConsume))
junkiness = junkiness)
/obj/item/food/grown/proc/make_dryable()
AddElement(/datum/element/dryable, type)
/obj/item/food/grown/examine(user)
. = ..()
if(seed)
for(var/datum/plant_gene/trait/T in seed.genes)
if(T.examine_line)
. += T.examine_line
/obj/item/food/grown/attackby(obj/item/O, mob/user, params)
..()
if (istype(O, /obj/item/plant_analyzer))
var/obj/item/plant_analyzer/plant_analyzer = O
to_chat(user, plant_analyzer.scan_plant(src))
else
if(seed)
for(var/datum/plant_gene/trait/T in seed.genes)
T.on_attackby(src, O, user)
/obj/item/food/grown/MakeLeaveTrash()
if(trash_type)
AddElement(/datum/element/food_trash, trash_type, FOOD_TRASH_OPENABLE, /obj/item/food/grown/.proc/generate_trash)
return
// Various gene procs
/obj/item/food/grown/attack_self(mob/user)
SEND_SIGNAL(src, COMSIG_PLANT_SQUASH, user)
..()
/obj/item/food/grown/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(!..()) //was it caught by a mob?
if(seed)
for(var/datum/plant_gene/trait/T in seed.genes)
T.on_throw_impact(src, hit_atom)
/obj/item/food/grown/proc/OnConsume(mob/living/eater, mob/living/feeder)
if(iscarbon(usr))
if(seed)
for(var/datum/plant_gene/trait/T in seed.genes)
T.on_consume(src, usr)
///Callback for bonus behavior for generating trash of grown food.
/obj/item/food/grown/proc/generate_trash(atom/location)
return new trash_type(location, seed)
+3 -12
View File
@@ -23,8 +23,9 @@
pixel_y = base_pixel_y + rand(-5, 5)
if(seed)
for(var/datum/plant_gene/trait/T in seed.genes)
T.on_new(src, loc)
// Go through all traits in their genes and call on_new_plant from them.
for(var/datum/plant_gene/trait/trait in seed.genes)
trait.on_new_plant(src, loc)
if(istype(src, seed.product)) // no adding reagents if it is just a trash item
seed.prepare_result(src)
@@ -38,21 +39,11 @@
to_chat(user, plant_analyzer.scan_plant(src))
return
/obj/item/grown/attack_self(mob/user)
SEND_SIGNAL(src, COMSIG_PLANT_SQUASH, user)
..()
/obj/item/grown/proc/add_juice()
if(reagents)
return TRUE
return FALSE
/obj/item/grown/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(!..()) //was it caught by a mob?
if(seed)
for(var/datum/plant_gene/trait/T in seed.genes)
T.on_throw_impact(src, hit_atom)
/obj/item/grown/microwave_act(obj/machinery/microwave/M)
return
+2 -4
View File
@@ -288,10 +288,8 @@
update_icon()
if(myseed && prob(5 * (11-myseed.production)))
for(var/g in myseed.genes)
if(istype(g, /datum/plant_gene/trait))
var/datum/plant_gene/trait/selectedtrait = g
selectedtrait.on_grow(src)
SEND_SIGNAL(myseed, COMSIG_PLANT_ON_GROW, src)
return
/obj/machinery/hydroponics/update_icon()
+414 -208
View File
@@ -33,9 +33,6 @@
G.mutability_flags = mutability_flags
return G
/datum/plant_gene/proc/apply_vars(obj/item/seeds/S) // currently used for fire resist, can prob. be further refactored
return
// Core plant genes store 5 main variables: lifespan, endurance, production, yield, potency
/datum/plant_gene/core
var/value
@@ -200,71 +197,90 @@
/// Traits that affect the grown product.
/datum/plant_gene/trait
/// The rate at which this trait affects something.
var/rate = 0.05
/// Bonus lines displayed on examine.
var/examine_line = ""
/// Must be set and equal for any two traits of the same type
/// Traits that share this ID cannot be placed on the same plant.
var/trait_id
/// Flags that modify the final product.
var/trait_flags
/// A blacklist of seeds that a trait cannot be attached to.
var/list/obj/item/seeds/seed_blacklist
/datum/plant_gene/trait/Copy()
var/datum/plant_gene/trait/G = ..()
G.rate = rate
return G
/datum/plant_gene/trait/can_add(obj/item/seeds/S)
/*
* Checks if we can add the trait to the seed in question.
*
* source_seed - the seed genes we're adding the trait too
*/
/datum/plant_gene/trait/can_add(obj/item/seeds/source_seed)
if(!..())
return FALSE
for(var/datum/plant_gene/trait/R in S.genes)
if(trait_id && R.trait_id == trait_id)
for(var/obj/item/seeds/found_seed as anything in seed_blacklist)
if(istype(source_seed, found_seed))
return FALSE
if(type == R.type)
for(var/datum/plant_gene/trait/trait in source_seed.genes)
if(trait_id && trait.trait_id == trait_id)
return FALSE
if(type == trait.type)
return FALSE
return TRUE
/datum/plant_gene/trait/proc/on_new(obj/item/food/grown/G, newloc)
return
/*
* on_new_plant is called for every plant trait on an /obj/item/grown or /obj/item/food/grown when initialized.
*
* our_plant - the source plant being created
* newloc - the loc of the plant
*/
/datum/plant_gene/trait/proc/on_new_plant(obj/item/our_plant, newloc)
// Plants should always have seeds, but if a non-plant sneaks in or a plant with nulled seed, cut it out
if(isnull(our_plant.get_plant_seed()))
stack_trace("[our_plant] ([our_plant.type]) has a nulled seed value")
return FALSE
/datum/plant_gene/trait/proc/on_consume(obj/item/food/grown/G, mob/living/carbon/target)
return
// Add on any bonus lines on examine
if(examine_line)
RegisterSignal(our_plant, COMSIG_PARENT_EXAMINE, .proc/examine)
/datum/plant_gene/trait/proc/on_slip(obj/item/food/grown/G, mob/living/carbon/target)
return
return TRUE
/datum/plant_gene/trait/proc/on_squash(obj/item/food/grown/G, atom/target)
return
/*
* on_new_seed is called when seed genes are initialized on the /obj/seed.
*
* new_seed - the seed being created
*/
/datum/plant_gene/trait/proc/on_new_seed(obj/item/seeds/new_seed)
return TRUE
/datum/plant_gene/trait/proc/on_attackby(obj/item/food/grown/G, obj/item/I, mob/user)
return
/// Add on any unique examine text to the plant's examine text.
/datum/plant_gene/trait/proc/examine(obj/item/our_plant, mob/examiner, list/examine_list)
SIGNAL_HANDLER
/datum/plant_gene/trait/proc/on_throw_impact(obj/item/food/grown/G, atom/target)
return
///This proc triggers when the tray processes and a roll is sucessful, the success chance scales with production.
/datum/plant_gene/trait/proc/on_grow(obj/machinery/hydroponics/H)
return
examine_list += examine_line
/// Allows the plant to be squashed when thrown or slipped on, leaving a colored mess and trash type item behind.
/datum/plant_gene/trait/squash
// Allows the plant to be squashed when thrown or slipped on, leaving a colored mess and trash type item behind.
// Also splashes everything in target turf with reagents and applies other trait effects (teleporting, etc) to the target by on_squash.
// For code, see grown.dm
name = "Liquid Contents"
examine_line = "<span class='info'>It has a lot of liquid contents inside.</span>"
trait_id = THROW_IMPACT_ID
// Register a signal that our plant can be squashed on add.
/datum/plant_gene/trait/squash/on_new(obj/item/food/grown/our_plant, newloc)
/datum/plant_gene/trait/squash/on_new_plant(obj/item/food/grown/our_plant, newloc)
. = ..()
RegisterSignal(our_plant, COMSIG_PLANT_SQUASH, .proc/squash_plant)
if(!.)
return
// Squash the plant on slip.
/datum/plant_gene/trait/squash/on_slip(obj/item/food/grown/our_plant, mob/living/carbon/target)
SEND_SIGNAL(our_plant, COMSIG_PLANT_SQUASH, target)
// Squash the plant on thrown impact.
/datum/plant_gene/trait/squash/on_throw_impact(obj/item/food/grown/our_plant, atom/target)
SEND_SIGNAL(our_plant, COMSIG_PLANT_SQUASH, target)
RegisterSignal(our_plant, COMSIG_PLANT_ON_SLIP, .proc/squash_plant)
RegisterSignal(our_plant, COMSIG_MOVABLE_IMPACT, .proc/squash_plant)
RegisterSignal(our_plant, COMSIG_ITEM_ATTACK_SELF, .proc/squash_plant)
/*
* Signal proc to squash the plant this trait belongs to, causing a smudge, exposing the target to reagents, and deleting it,
@@ -292,10 +308,7 @@
misc_smudge.color = "#82b900"
our_plant.visible_message("<span class='warning'>[our_plant] is squashed.</span>","<span class='hear'>You hear a smack.</span>")
var/obj/item/seeds/seed = our_plant.get_plant_seed()
if(seed)
for(var/datum/plant_gene/trait/trait in seed.genes)
trait.on_squash(our_plant, target)
SEND_SIGNAL(our_plant, COMSIG_PLANT_ON_SQUASH, target)
our_plant.reagents?.expose(our_turf)
for(var/things in our_turf)
@@ -303,278 +316,450 @@
qdel(our_plant)
/*
* Makes plant slippery, unless it has a grown-type trash. Then the trash gets slippery.
* Applies other trait effects (teleporting, etc) to the target by signal.
*/
/datum/plant_gene/trait/slip
// Makes plant slippery, unless it has a grown-type trash. Then the trash gets slippery.
// Applies other trait effects (teleporting, etc) to the target by on_slip.
name = "Slippery Skin"
rate = 1.6
examine_line = "<span class='info'>It has a very slippery skin.</span>"
/datum/plant_gene/trait/slip/on_new(obj/item/food/grown/G, newloc)
..()
if(istype(G) && ispath(G.trash_type, /obj/item/grown))
/datum/plant_gene/trait/slip/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
var/obj/item/seeds/seed = G.get_plant_seed()
var/stun_len = seed.potency * rate
if(!istype(G, /obj/item/grown/bananapeel) && (!G.reagents || !G.reagents.has_reagent(/datum/reagent/lube)))
var/obj/item/food/grown/grown_plant = our_plant
if(istype(grown_plant) && ispath(grown_plant.trash_type, /obj/item/grown))
return
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
var/stun_len = our_seed.potency * rate
if(!istype(our_plant, /obj/item/grown/bananapeel) && (!our_plant.reagents || !our_plant.reagents.has_reagent(/datum/reagent/lube)))
stun_len /= 3
G.AddComponent(/datum/component/slippery, min(stun_len,140), NONE, CALLBACK(src, .proc/handle_slip, G))
our_plant.AddComponent(/datum/component/slippery, min(stun_len, 140), NONE, CALLBACK(src, .proc/handle_slip, our_plant))
/datum/plant_gene/trait/slip/proc/handle_slip(obj/item/food/grown/G, mob/M)
for(var/datum/plant_gene/trait/T in G.seed.genes)
T.on_slip(G, M)
/// On slip, sends a signal that our plant was slipped on out.
/datum/plant_gene/trait/slip/proc/handle_slip(obj/item/food/grown/our_plant, mob/slipped_target)
SEND_SIGNAL(our_plant, COMSIG_PLANT_ON_SLIP, slipped_target)
/*
* Cell recharging trait. Charges all mob's power cells to (potency*rate)% mark when eaten.
* Generates sparks on squash.
* Small (potency * rate) chance to shock squish or slip target for (potency * rate) damage.
* Also affects plant batteries see capatative cell production datum
*/
/datum/plant_gene/trait/cell_charge
// Cell recharging trait. Charges all mob's power cells to (potency*rate)% mark when eaten.
// Generates sparks on squash.
// Small (potency*rate*5) chance to shock squish or slip target for (potency*rate*5) damage.
// Also affects plant batteries see capatative cell production datum
name = "Electrical Activity"
rate = 0.2
/datum/plant_gene/trait/cell_charge/on_slip(obj/item/food/grown/G, mob/living/carbon/C)
var/power = G.seed.potency*rate
if(prob(power))
C.electrocute_act(round(power), G, 1, SHOCK_NOGLOVES)
/datum/plant_gene/trait/cell_charge/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
if(our_seed.get_gene(/datum/plant_gene/trait/squash))
// If we have the squash gene, let that handle slipping
RegisterSignal(our_plant, COMSIG_PLANT_ON_SQUASH, .proc/zap_target)
else
RegisterSignal(our_plant, COMSIG_PLANT_ON_SLIP, .proc/zap_target)
RegisterSignal(our_plant, COMSIG_FOOD_EATEN, .proc/recharge_cells)
/*
* Zaps the target with a stunning shock.
*
* our_plant - our source plant, shocking the target
* target - the atom being zapped by our plant
*/
/datum/plant_gene/trait/cell_charge/proc/zap_target(obj/item/our_plant, atom/target)
SIGNAL_HANDLER
/datum/plant_gene/trait/cell_charge/on_squash(obj/item/food/grown/G, atom/target)
if(iscarbon(target))
var/mob/living/carbon/C = target
var/power = G.seed.potency*rate
var/mob/living/carbon/target_carbon = target
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
var/power = our_seed.potency * rate
if(prob(power))
C.electrocute_act(round(power), G, 1, SHOCK_NOGLOVES)
/datum/plant_gene/trait/cell_charge/on_consume(obj/item/food/grown/G, mob/living/carbon/target)
if(!G.reagents.total_volume)
var/batteries_recharged = 0
for(var/obj/item/stock_parts/cell/C in target.GetAllContents())
var/newcharge = min(G.seed.potency*0.01*C.maxcharge, C.maxcharge)
if(C.charge < newcharge)
C.charge = newcharge
if(isobj(C.loc))
var/obj/O = C.loc
O.update_icon() //update power meters and such
C.update_icon()
batteries_recharged = 1
if(batteries_recharged)
to_chat(target, "<span class='notice'>Your batteries are recharged!</span>")
target_carbon.electrocute_act(round(power), our_plant, 1, SHOCK_NOGLOVES)
/*
* Recharges every cell the person is holding for a bit based on plant potency.
*
* our_plant - our source plant, that we consumed to charge the cells
* eater - the mob that bit the plant
* feeder - the mob that feed the eater the plant
*/
/datum/plant_gene/trait/cell_charge/proc/recharge_cells(obj/item/our_plant, mob/living/eater, mob/feeder)
SIGNAL_HANDLER
to_chat(eater, "<span class='notice'>You feel energized as you bite into [our_plant].</span>")
var/batteries_recharged = FALSE
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
for(var/obj/item/stock_parts/cell/found_cell in eater.GetAllContents())
var/newcharge = min(our_seed.potency * 0.01 * found_cell.maxcharge, found_cell.maxcharge)
if(found_cell.charge < newcharge)
found_cell.charge = newcharge
if(isobj(found_cell.loc))
var/obj/cell_location = found_cell.loc
cell_location.update_icon() //update power meters and such
found_cell.update_icon()
batteries_recharged = TRUE
if(batteries_recharged)
to_chat(eater, "<span class='notice'>Your batteries are recharged!</span>")
/*
* Makes the plant glow. Makes the plant in tray glow, too.
* Adds (1.4 + potency * rate) light range and (potency * (rate + 0.01)) light_power to products.
*/
/datum/plant_gene/trait/glow
// Makes plant glow. Makes plant in tray glow too.
// Adds 1 + potency*rate light range and potency*(rate + 0.01) light_power to products.
name = "Bioluminescence"
rate = 0.03
examine_line = "<span class='info'>It emits a soft glow.</span>"
trait_id = GLOW_ID
var/glow_color = "#C3E381"
/datum/plant_gene/trait/glow/proc/glow_range(obj/item/seeds/S)
return 1.4 + S.potency*rate
/datum/plant_gene/trait/glow/proc/glow_range(obj/item/seeds/seed)
return 1.4 + seed.potency * rate
/datum/plant_gene/trait/glow/proc/glow_power(obj/item/seeds/S)
return max(S.potency*(rate + 0.01), 0.1)
/datum/plant_gene/trait/glow/proc/glow_power(obj/item/seeds/seed)
return max(seed.potency * (rate + 0.01), 0.1)
/datum/plant_gene/trait/glow/on_new(obj/item/food/grown/G, newloc)
/datum/plant_gene/trait/glow/on_new_plant(obj/item/our_plant, newloc)
. = ..()
G.light_system = MOVABLE_LIGHT
G.AddComponent(/datum/component/overlay_lighting, glow_range(G.seed), glow_power(G.seed), glow_color)
if(!.)
return
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
our_plant.light_system = MOVABLE_LIGHT
our_plant.AddComponent(/datum/component/overlay_lighting, glow_range(our_seed), glow_power(our_seed), glow_color)
/*
* Makes plant emit darkness. (Purple-ish shadows)
* Adds - (potency * (rate * 0.2)) light power to products.
*/
/datum/plant_gene/trait/glow/shadow
//makes plant emit slightly purple shadows
//adds -potency*(rate*0.2) light power to products
name = "Shadow Emission"
rate = 0.04
glow_color = "#AAD84B"
/datum/plant_gene/trait/glow/shadow/glow_power(obj/item/seeds/S)
return -max(S.potency*(rate*0.2), 0.2)
/datum/plant_gene/trait/glow/shadow/glow_power(obj/item/seeds/seed)
return -max(seed.potency*(rate*0.2), 0.2)
/// Colored versions of bioluminescence.
/// White
/datum/plant_gene/trait/glow/white
name = "White Bioluminescence"
glow_color = "#FFFFFF"
/// Red
/datum/plant_gene/trait/glow/red
//Colored versions of bioluminescence.
name = "Red Bioluminescence"
glow_color = "#FF3333"
/// Yellow (not the disgusting glowshroom yellow hopefully)
/datum/plant_gene/trait/glow/yellow
//not the disgusting glowshroom yellow hopefully
name = "Yellow Bioluminescence"
glow_color = "#FFFF66"
/// Green (oh no, now i'm radioactive)
/datum/plant_gene/trait/glow/green
//oh no, now i'm radioactive
name = "Green Bioluminescence"
glow_color = "#99FF99"
/// Blue (the best one)
/datum/plant_gene/trait/glow/blue
//the best one
name = "Blue Bioluminescence"
glow_color = "#6699FF"
/// Purple (did you know that notepad++ doesnt think bioluminescence is a word) (was the person who wrote this using notepad++ for dm?)
/datum/plant_gene/trait/glow/purple
//did you know that notepad++ doesnt think bioluminescence is a word
name = "Purple Bioluminescence"
glow_color = "#D966FF"
// Pink (gay tide station pride)
/datum/plant_gene/trait/glow/pink
//gay tide station pride
name = "Pink Bioluminescence"
glow_color = "#FFB3DA"
/*
* Makes plant teleport people when squashed or slipped on.
* Teleport radius is roughly potency / 10.
*/
/datum/plant_gene/trait/teleport
// Makes plant teleport people when squashed or slipped on.
// Teleport radius is calculated as max(round(potency*rate), 1)
name = "Bluespace Activity"
rate = 0.1
/datum/plant_gene/trait/teleport/on_squash(obj/item/food/grown/G, atom/target)
/datum/plant_gene/trait/teleport/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
if(our_seed.get_gene(/datum/plant_gene/trait/squash))
// If we have the squash gene, let that handle slipping
RegisterSignal(our_plant, COMSIG_PLANT_ON_SQUASH, .proc/squash_teleport)
else
RegisterSignal(our_plant, COMSIG_PLANT_ON_SLIP, .proc/slip_teleport)
/*
* When squashed, makes the target teleport.
*
* our_plant - our plant, being squashed, and teleporting the target
* target - the atom targeted by the squash
*/
/datum/plant_gene/trait/teleport/proc/squash_teleport(obj/item/our_plant, atom/target)
SIGNAL_HANDLER
if(isliving(target))
var/teleport_radius = max(round(G.seed.potency / 10), 1)
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
var/teleport_radius = max(round(our_seed.potency / 10), 1)
var/turf/T = get_turf(target)
new /obj/effect/decal/cleanable/molten_object(T) //Leave a pile of goo behind for dramatic effect...
do_teleport(target, T, teleport_radius, channel = TELEPORT_CHANNEL_BLUESPACE)
/datum/plant_gene/trait/teleport/on_slip(obj/item/food/grown/G, mob/living/carbon/C)
var/teleport_radius = max(round(G.seed.potency / 10), 1)
var/turf/T = get_turf(C)
to_chat(C, "<span class='warning'>You slip through spacetime!</span>")
do_teleport(C, T, teleport_radius, channel = TELEPORT_CHANNEL_BLUESPACE)
/*
* When slipped on, makes the target teleport and either teleport the source again or delete it.
*
* our_plant - our plant being slipped on
* target - the carbon targeted that was slipped and was teleported
*/
/datum/plant_gene/trait/teleport/proc/slip_teleport(obj/item/our_plant, mob/living/carbon/target)
SIGNAL_HANDLER
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
var/teleport_radius = max(round(our_seed.potency / 10), 1)
var/turf/T = get_turf(target)
to_chat(target, "<span class='warning'>You slip through spacetime!</span>")
do_teleport(target, T, teleport_radius, channel = TELEPORT_CHANNEL_BLUESPACE)
if(prob(50))
do_teleport(G, T, teleport_radius, channel = TELEPORT_CHANNEL_BLUESPACE)
do_teleport(our_plant, T, teleport_radius, channel = TELEPORT_CHANNEL_BLUESPACE)
else
new /obj/effect/decal/cleanable/molten_object(T) //Leave a pile of goo behind for dramatic effect...
qdel(G)
qdel(our_plant)
/**
* A plant trait that causes the plant's capacity to double.
*
* When harvested, the plant's individual capacity is set to double it's default.
* However, the plant is also going to be limited to half as many products from yield, so 2 yield will only produce 1 plant as a result.
* However, the plant's maximum yield is also halved, only up to 5.
*/
/datum/plant_gene/trait/maxchem
// 2x to max reagents volume.
name = "Densified Chemicals"
rate = 2
trait_flags = TRAIT_HALVES_YIELD
/datum/plant_gene/trait/maxchem/on_new(obj/item/food/grown/G, newloc)
..()
G.max_volume *= rate
/datum/plant_gene/trait/maxchem/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
var/obj/item/food/grown/grown_plant = our_plant
if(istype(grown_plant, /obj/item/food/grown))
//Grown foods use the edible component so we need to change their max_volume var
grown_plant.max_volume *= rate
else
//Grown inedibles however just use a reagents holder, so.
our_plant.reagents?.maximum_volume *= rate
/// Allows a plant to be harvested multiple times.
/datum/plant_gene/trait/repeated_harvest
name = "Perennial Growth"
/// Don't allow replica pods to be multi harvested, please.
seed_blacklist = list(/obj/item/seeds/replicapod)
/datum/plant_gene/trait/repeated_harvest/can_add(obj/item/seeds/S)
if(!..())
return FALSE
if(istype(S, /obj/item/seeds/replicapod))
return FALSE
return TRUE
/*
* Allows a plant to be turned into a battery when cabling is applied.
* 100 potency plants are made into 2 mj batteries.
* Plants with electrical activity has their capacities massively increased (up to 40 mj at 100 potency)
*/
/datum/plant_gene/trait/battery
name = "Capacitive Cell Production"
/datum/plant_gene/trait/battery/on_attackby(obj/item/food/grown/G, obj/item/I, mob/user)
if(istype(I, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = I
if(C.use(5))
to_chat(user, "<span class='notice'>You add some cable to [G] and slide it inside the battery encasing.</span>")
var/obj/item/stock_parts/cell/potato/pocell = new /obj/item/stock_parts/cell/potato(user.loc)
pocell.icon_state = G.icon_state
pocell.maxcharge = G.seed.potency * 20
/datum/plant_gene/trait/battery/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
// The secret of potato supercells!
var/datum/plant_gene/trait/cell_charge/CG = G.seed.get_gene(/datum/plant_gene/trait/cell_charge)
if(CG) // Cell charge max is now 40MJ or otherwise known as 400KJ (Same as bluespace power cells)
pocell.maxcharge *= CG.rate*100
pocell.charge = pocell.maxcharge
pocell.name = "[G.name] battery"
pocell.desc = "A rechargeable plant-based power cell. This one has a rating of [DisplayEnergy(pocell.maxcharge)], and you should not swallow it."
RegisterSignal(our_plant, COMSIG_PARENT_ATTACKBY, .proc/make_battery)
if(G.reagents.has_reagent(/datum/reagent/toxin/plasma, 2))
pocell.rigged = TRUE
/*
* When a plant with this gene is hit (attackby) with cables, we turn it into a battery.
*
* our_plant - our plant being hit
* hit_item - the item we're hitting the plant with
* user - the person hitting the plant with an item
*/
/datum/plant_gene/trait/battery/proc/make_battery(obj/item/our_plant, obj/item/hit_item, mob/user)
SIGNAL_HANDLER
qdel(G)
else
to_chat(user, "<span class='warning'>You need five lengths of cable to make a [G] battery!</span>")
if(!istype(hit_item, /obj/item/stack/cable_coil))
return
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
var/obj/item/stack/cable_coil/cabling = hit_item
if(!cabling.use(5))
to_chat(user, "<span class='warning'>You need five lengths of cable to make a [our_plant] battery!</span>")
return
to_chat(user, "<span class='notice'>You add some cable to [our_plant] and slide it inside the battery encasing.</span>")
var/obj/item/stock_parts/cell/potato/pocell = new /obj/item/stock_parts/cell/potato(user.loc)
pocell.icon_state = our_plant.icon_state
pocell.maxcharge = our_seed.potency * 20
// The secret of potato supercells!
var/datum/plant_gene/trait/cell_charge/electrical_gene = our_seed.get_gene(/datum/plant_gene/trait/cell_charge)
if(electrical_gene) // Cell charge max is now 40MJ or otherwise known as 400KJ (Same as bluespace power cells)
pocell.maxcharge *= (electrical_gene.rate * 100)
pocell.charge = pocell.maxcharge
pocell.name = "[our_plant.name] battery"
pocell.desc = "A rechargeable plant-based power cell. This one has a rating of [DisplayEnergy(pocell.maxcharge)], and you should not swallow it."
if(our_plant.reagents.has_reagent(/datum/reagent/toxin/plasma, 2))
pocell.rigged = TRUE
qdel(our_plant)
/*
* Injects a number of chemicals from the plant when you throw it at someone or they slip on it.
* At 0 potency it can inject 1 unit of its chemicals, while at 100 potency it can inject 20 units.
*/
/datum/plant_gene/trait/stinging
name = "Hypodermic Prickles"
examine_line = "<span class='info'>It's quite prickley.</span>"
/datum/plant_gene/trait/stinging/on_slip(obj/item/food/grown/G, atom/target)
on_throw_impact(G, target)
/datum/plant_gene/trait/stinging/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
/datum/plant_gene/trait/stinging/on_throw_impact(obj/item/food/grown/G, atom/target)
if(isliving(target) && G.reagents && G.reagents.total_volume)
var/mob/living/L = target
if(L.reagents && L.can_inject())
var/injecting_amount = max(1, G.seed.potency*0.2) // Minimum of 1, max of 20
G.reagents.trans_to(L, injecting_amount, methods = INJECT)
to_chat(target, "<span class='danger'>You are pricked by [G]!</span>")
log_combat(G, L, "pricked and attempted to inject reagents from [G] to [L]. Last touched by: [G.fingerprintslast].")
RegisterSignal(our_plant, COMSIG_PLANT_ON_SLIP, .proc/prickles_inject)
RegisterSignal(our_plant, COMSIG_MOVABLE_IMPACT, .proc/prickles_inject)
/*
* Injects a target with a number of reagents from our plant.
*
* our_plant - our plant that's injecting someone
* target - the atom being hit on thrown or slipping on our plant
*/
/datum/plant_gene/trait/stinging/proc/prickles_inject(obj/item/our_plant, atom/target)
if(isliving(target) && our_plant.reagents?.total_volume)
var/mob/living/living_target = target
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
if(living_target.reagents && living_target.can_inject())
var/injecting_amount = max(1, our_seed.potency * 0.2) // Minimum of 1, max of 20
our_plant.reagents.trans_to(living_target, injecting_amount, methods = INJECT)
to_chat(target, "<span class='danger'>You are pricked by [our_plant]!</span>")
log_combat(our_plant, living_target, "pricked and attempted to inject reagents from [our_plant] to [living_target]. Last touched by: [our_plant.fingerprintslast].")
/// Explodes into reagent-filled smoke when squashed.
/datum/plant_gene/trait/smoke
name = "Gaseous Decomposition"
/datum/plant_gene/trait/smoke/on_squash(obj/item/food/grown/G, atom/target)
var/datum/effect_system/smoke_spread/chem/S = new
var/splat_location = get_turf(target)
var/smoke_amount = round(sqrt(G.seed.potency * 0.1), 1)
S.attach(splat_location)
S.set_up(G.reagents, smoke_amount, splat_location, 0)
S.start()
G.reagents.clear_reagents()
/datum/plant_gene/trait/smoke/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
/datum/plant_gene/trait/fire_resistance // Lavaland
RegisterSignal(our_plant, COMSIG_PLANT_ON_SQUASH, .proc/make_smoke)
/*
* Makes a cloud of reagent smoke.
*
* our_plant - our plant being squashed and smoked
* target - the atom the plant was squashed on
*/
/datum/plant_gene/trait/smoke/proc/make_smoke(obj/item/our_plant, atom/target)
SIGNAL_HANDLER
var/datum/effect_system/smoke_spread/chem/smoke = new ()
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
var/splat_location = get_turf(target)
var/smoke_amount = round(sqrt(our_seed.potency * 0.1), 1)
smoke.attach(splat_location)
smoke.set_up(our_plant.reagents, smoke_amount, splat_location, 0)
smoke.start()
our_plant.reagents.clear_reagents()
/// Makes the plant and its seeds fireproof. From lavaland plants.
/datum/plant_gene/trait/fire_resistance
name = "Fire Resistance"
/datum/plant_gene/trait/fire_resistance/apply_vars(obj/item/seeds/S)
if(!(S.resistance_flags & FIRE_PROOF))
S.resistance_flags |= FIRE_PROOF
/datum/plant_gene/trait/fire_resistance/on_new_seed(obj/item/seeds/new_seed)
if(!(new_seed.resistance_flags & FIRE_PROOF))
new_seed.resistance_flags |= FIRE_PROOF
/datum/plant_gene/trait/fire_resistance/on_new(obj/item/food/grown/G, newloc)
if(!(G.resistance_flags & FIRE_PROOF))
G.resistance_flags |= FIRE_PROOF
/datum/plant_gene/trait/fire_resistance/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
///Invasive spreading lets the plant jump to other trays, the spreading plant won't replace plants of the same type.
if(!(our_plant.resistance_flags & FIRE_PROOF))
our_plant.resistance_flags |= FIRE_PROOF
/// Invasive spreading lets the plant jump to other trays, and the spreading plant won't replace plants of the same type.
/datum/plant_gene/trait/invasive
name = "Invasive Spreading"
/datum/plant_gene/trait/invasive/on_grow(obj/machinery/hydroponics/our_tray)
/datum/plant_gene/trait/invasive/on_new_seed(obj/item/seeds/new_seed)
. = ..()
if(!.)
return FALSE
RegisterSignal(new_seed, COMSIG_PLANT_ON_GROW, .proc/try_spread)
return TRUE
/*
* Attempt to find an adjacent tray we can spread to.
*
* our_seed - our plant's seed, what spreads to other trays
* our_tray - the hydroponics tray we're currently in
*/
/datum/plant_gene/trait/invasive/proc/try_spread(obj/item/seeds/our_seed, obj/machinery/hydroponics/our_tray)
SIGNAL_HANDLER
for(var/step_dir in GLOB.alldirs)
var/obj/machinery/hydroponics/spread_tray = locate() in get_step(our_tray, step_dir)
if(spread_tray && prob(15))
if(!our_tray.Adjacent(spread_tray))
continue //Don't spread through things we can't go through.
if(spread_tray.myseed) // Check if there's another seed in the next tray.
if(spread_tray.myseed.type == our_tray.myseed.type && !spread_tray.dead)
continue // It should not destroy its own kind.
spread_tray.visible_message("<span class='warning'>The [spread_tray.myseed.plantname] is overtaken by [our_tray.myseed.plantname]!</span>")
QDEL_NULL(spread_tray.myseed)
spread_tray.myseed = our_tray.myseed.Copy()
spread_tray.age = 0
spread_tray.dead = FALSE
spread_tray.plant_health = spread_tray.myseed.endurance
spread_tray.lastcycle = world.time
spread_tray.harvest = FALSE
spread_tray.weedlevel = 0 // Reset
spread_tray.pestlevel = 0 // Reset
spread_tray.update_icon()
spread_tray.visible_message("<span class='warning'>The [our_tray.myseed.plantname] spreads!</span>")
if(spread_tray.myseed)
spread_tray.name = "[initial(spread_tray.name)] ([spread_tray.myseed.plantname])"
else
spread_tray.name = initial(spread_tray.name)
spread_seed(spread_tray, our_tray)
/*
* Actually spread the plant to the tray we found in try_spread.
*
* target_tray - the tray we're spreading to
* origin_tray - the tray we're currently in
*/
/datum/plant_gene/trait/invasive/proc/spread_seed(obj/machinery/hydroponics/target_tray, obj/machinery/hydroponics/origin_tray)
if(target_tray.myseed) // Check if there's another seed in the next tray.
if(target_tray.myseed.type == origin_tray.myseed.type && !target_tray.dead)
return FALSE // It should not destroy its own kind.
target_tray.visible_message("<span class='warning'>The [target_tray.myseed.plantname] is overtaken by [origin_tray.myseed.plantname]!</span>")
QDEL_NULL(target_tray.myseed)
target_tray.myseed = origin_tray.myseed.Copy()
target_tray.age = 0
target_tray.dead = FALSE
target_tray.plant_health = target_tray.myseed.endurance
target_tray.lastcycle = world.time
target_tray.harvest = FALSE
target_tray.weedlevel = 0 // Reset
target_tray.pestlevel = 0 // Reset
target_tray.update_icon()
target_tray.visible_message("<span class='warning'>The [origin_tray.myseed.plantname] spreads!</span>")
if(target_tray.myseed)
target_tray.name = "[initial(target_tray.name)] ([target_tray.myseed.plantname])"
else
target_tray.name = initial(target_tray.name)
return TRUE
/**
* A plant trait that causes the plant's food reagents to ferment instead.
@@ -606,20 +791,27 @@
name = "Hallucinatory Feedback"
/// Sounds that play when this trait triggers
var/list/sounds = list('sound/items/SitcomLaugh1.ogg', 'sound/items/SitcomLaugh2.ogg', 'sound/items/SitcomLaugh3.ogg')
/// Whether or not we can trigger. (If we have a trash type it'll trigger on that instead)
var/can_trigger = TRUE
/datum/plant_gene/trait/plant_laughter/on_new(obj/item/food/grown/G, newloc)
..()
if(istype(G) && ispath(G.trash_type, /obj/item/grown))
can_trigger = FALSE
/datum/plant_gene/trait/plant_laughter/on_slip(obj/item/food/grown/G, atom/target)
if(!can_trigger)
/datum/plant_gene/trait/plant_laughter/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
G.audible_message("<span_class='notice'>[G] lets out burst of laughter.</span>")
playsound(G, pick(sounds), 100, FALSE, SHORT_RANGE_SOUND_EXTRARANGE)
var/obj/item/food/grown/grown_plant = our_plant
if(istype(grown_plant) && ispath(grown_plant.trash_type, /obj/item/grown))
return
RegisterSignal(our_plant, COMSIG_PLANT_ON_SLIP, .proc/laughter)
/*
* Play a sound effect from our plant.
*
* our_plant - the source plant that was slipped on
* target - the atom that slipped on the plant
*/
/datum/plant_gene/trait/plant_laughter/proc/laughter(obj/item/our_plant, atom/target)
our_plant.audible_message("<span_class='notice'>[our_plant] lets out burst of laughter.</span>")
playsound(our_plant, pick(sounds), 100, FALSE, SHORT_RANGE_SOUND_EXTRARANGE)
/**
* A plant trait that causes the plant to gain aesthetic googly eyes.
@@ -630,24 +822,33 @@
name = "Oculary Mimicry"
var/mutable_appearance/googly
/datum/plant_gene/trait/eyes/on_new(obj/item/food/grown/G, newloc)
/datum/plant_gene/trait/eyes/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
googly = mutable_appearance('icons/obj/hydroponics/harvest.dmi', "eyes")
googly.appearance_flags = RESET_COLOR
G.add_overlay(googly)
our_plant.add_overlay(googly)
/// Makes the plant embed on thrown impact.
/datum/plant_gene/trait/sticky
name = "Prickly Adhesion"
examine_line = "<span class='info'>It's quite sticky.</span>"
trait_id = THROW_IMPACT_ID
/datum/plant_gene/trait/sticky/on_new(obj/item/food/grown/G, newloc)
/datum/plant_gene/trait/sticky/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(G.seed.get_gene(/datum/plant_gene/trait/stinging))
G.embedding = EMBED_POINTY
if(!.)
return
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
if(our_seed.get_gene(/datum/plant_gene/trait/stinging))
our_plant.embedding = EMBED_POINTY
else
G.embedding = EMBED_HARMLESS
G.updateEmbedding()
G.throwforce = (G.seed.potency/20)
our_plant.embedding = EMBED_HARMLESS
our_plant.updateEmbedding()
our_plant.throwforce = (our_seed.potency/20)
/**
* This trait automatically heats up the plant's chemical contents when harvested.
@@ -667,19 +868,24 @@
trait_id = TEMP_CHANGE_ID
trait_flags = TRAIT_HALVES_YIELD
/// Plant type traits. Incompatible with one another.
/datum/plant_gene/trait/plant_type // Parent type
name = "you shouldn't see this"
trait_id = PLANT_TYPE_ID
/// Weeds don't get annoyed by weeds in their tray.
/datum/plant_gene/trait/plant_type/weed_hardy
name = "Weed Adaptation"
/// Mushrooms need less light and have a minimum yield.
/datum/plant_gene/trait/plant_type/fungal_metabolism
name = "Fungal Vitality"
/// Currently unused and does nothing. Appears in strange seeds.
/datum/plant_gene/trait/plant_type/alien_properties
name ="?????"
/// Plant doesn't get annoyed by pests in their tray.
/datum/plant_gene/trait/plant_type/carnivory
name = "Obligate Carnivory"
+31 -25
View File
@@ -62,7 +62,7 @@
///Determines if the plant should be allowed to mutate early at 30+ instability.
var/seed_flags = MUTATE_EARLY
/obj/item/seeds/Initialize(mapload, nogenes = 0)
/obj/item/seeds/Initialize(mapload, nogenes = FALSE)
. = ..()
pixel_x = base_pixel_x + rand(-8, 8)
pixel_y = base_pixel_y + rand(-8, 8)
@@ -88,10 +88,14 @@
genes += new /datum/plant_gene/core/potency(potency)
genes += new /datum/plant_gene/core/instability(instability)
for(var/p in genes)
if(ispath(p))
genes -= p
genes += new p
for(var/plant_gene in genes)
if(ispath(plant_gene))
genes -= plant_gene
genes += new plant_gene
// Go through all traits in their genes and call on_new_seed from them.
for(var/datum/plant_gene/trait/traits in genes)
traits.on_new_seed(src)
for(var/reag_id in reagents_add)
genes += new /datum/plant_gene/reagent(reag_id, reagents_add[reag_id])
@@ -106,27 +110,29 @@
. += "<span class='notice'>- [G.get_name()] -</span>"
/obj/item/seeds/proc/Copy()
var/obj/item/seeds/S = new type(null, 1)
var/obj/item/seeds/copy_seed = new type(null, TRUE)
// Copy all the stats
S.lifespan = lifespan
S.endurance = endurance
S.maturation = maturation
S.production = production
S.yield = yield
S.potency = potency
S.instability = instability
S.weed_rate = weed_rate
S.weed_chance = weed_chance
S.name = name
S.plantname = plantname
S.desc = desc
S.productdesc = productdesc
S.genes = list()
for(var/g in genes)
var/datum/plant_gene/G = g
S.genes += G.Copy()
S.reagents_add = reagents_add.Copy() // Faster than grabbing the list from genes.
return S
copy_seed.lifespan = lifespan
copy_seed.endurance = endurance
copy_seed.maturation = maturation
copy_seed.production = production
copy_seed.yield = yield
copy_seed.potency = potency
copy_seed.instability = instability
copy_seed.weed_rate = weed_rate
copy_seed.weed_chance = weed_chance
copy_seed.name = name
copy_seed.plantname = plantname
copy_seed.desc = desc
copy_seed.productdesc = productdesc
copy_seed.genes = list()
for(var/datum/plant_gene/plant_genes in genes)
copy_seed.genes += plant_genes.Copy()
for(var/datum/plant_gene/trait/traits in genes)
traits.on_new_seed(copy_seed)
copy_seed.reagents_add = reagents_add.Copy() // Faster than grabbing the list from genes.
return copy_seed
/obj/item/seeds/proc/get_gene(typepath)
return (locate(typepath) in genes)