Files
CHOMPStation2/code/modules/hydroponics/spreading/spreading.dm
2020-05-18 13:31:54 -04:00

317 lines
8.6 KiB
Plaintext

#define DEFAULT_SEED "glowshroom"
#define VINE_GROWTH_STAGES 5
/proc/spacevine_infestation(var/potency_min=70, var/potency_max=100, var/maturation_min=5, var/maturation_max=15)
spawn() //to stop the secrets panel hanging
var/list/turf/simulated/floor/turfs = list() //list of all the empty floor turfs in the hallway areas
for(var/areapath in typesof(/area/hallway))
var/area/A = locate(areapath)
for(var/turf/simulated/floor/F in A.contents)
if(!F.check_density())
turfs += F
if(turfs.len) //Pick a turf to spawn at if we can
var/turf/simulated/floor/T = pick(turfs)
var/datum/seed/seed = plant_controller.create_random_seed(1)
seed.set_trait(TRAIT_SPREAD,2) // So it will function properly as vines.
seed.set_trait(TRAIT_POTENCY,rand(potency_min, potency_max)) // 70-100 potency will help guarantee a wide spread and powerful effects.
seed.set_trait(TRAIT_MATURATION,rand(maturation_min, maturation_max))
seed.display_name = "strange plants" //more thematic for the vine infestation event
//make vine zero start off fully matured
var/obj/effect/plant/vine = new(T,seed)
vine.health = vine.max_health
vine.mature_time = 0
vine.process()
message_admins("<span class='notice'>Event: Spacevines spawned at [T.loc] ([T.x],[T.y],[T.z])</span>")
return
message_admins("<span class='notice'>Event: Spacevines failed to find a viable turf.</span>")
/obj/effect/dead_plant
anchored = 1
opacity = 0
density = 0
color = DEAD_PLANT_COLOUR
/obj/effect/dead_plant/attack_hand()
qdel(src)
/obj/effect/dead_plant/attackby()
..()
for(var/obj/effect/plant/neighbor in range(1))
neighbor.update_neighbors()
qdel(src)
/obj/effect/plant
name = "plant"
anchored = 1
can_buckle = 1
opacity = 0
density = 0
icon = 'icons/obj/hydroponics_growing.dmi'
icon_state = "bush4-1"
pass_flags = PASSTABLE
mouse_opacity = 2
var/health = 10
var/max_health = 100
var/growth_threshold = 0
var/growth_type = 0
var/max_growth = 0
var/list/neighbors = list()
var/obj/effect/plant/parent
var/datum/seed/seed
var/sampled = 0
var/floor = 0
var/spread_chance = 40
var/spread_distance = 3
var/evolve_chance = 2
var/mature_time //minimum maturation time
var/last_tick = 0
var/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/plant
/obj/effect/plant/Destroy()
if(seed.get_trait(TRAIT_SPREAD)==2)
unsense_proximity(callback = .HasProximity, center = get_turf(src))
plant_controller.remove_plant(src)
for(var/obj/effect/plant/neighbor in range(1,src))
plant_controller.add_plant(neighbor)
return ..()
/obj/effect/plant/single
spread_chance = 0
/obj/effect/plant/New(var/newloc, var/datum/seed/newseed, var/obj/effect/plant/newparent)
..()
if(!newparent)
parent = src
else
parent = newparent
if(!plant_controller)
sleep(250) // ugly hack, should mean roundstart plants are fine. TODO initialize perhaps?
if(!plant_controller)
to_world("<span class='danger'>Plant controller does not exist and [src] requires it. Aborting.</span>")
qdel(src)
return
if(!istype(newseed))
newseed = plant_controller.seeds[DEFAULT_SEED]
seed = newseed
if(!seed)
qdel(src)
return
name = seed.display_name
max_health = round(seed.get_trait(TRAIT_ENDURANCE)/2)
if(seed.get_trait(TRAIT_SPREAD)==2)
sense_proximity(callback = .HasProximity) // Grabby
max_growth = VINE_GROWTH_STAGES
growth_threshold = max_health/VINE_GROWTH_STAGES
icon = 'icons/obj/hydroponics_vines.dmi'
growth_type = 2 // Vines by default.
if(seed.get_trait(TRAIT_CARNIVOROUS) >= 2)
growth_type = 1 // WOOOORMS.
else if(!(seed.seed_noun in list("seeds","pits")))
if(seed.seed_noun == "nodes")
growth_type = 3 // Biomass
else
growth_type = 4 // Mold
else
max_growth = seed.growth_stages
growth_threshold = max_health/seed.growth_stages
if(max_growth > 2 && prob(50))
max_growth-- //Ensure some variation in final sprite, makes the carpet of crap look less wonky.
mature_time = world.time + seed.get_trait(TRAIT_MATURATION) + 15 //prevent vines from maturing until at least a few seconds after they've been created.
spread_chance = seed.get_trait(TRAIT_POTENCY)
spread_distance = ((growth_type>0) ? round(spread_chance*0.6) : round(spread_chance*0.3))
update_icon()
// Plants will sometimes be spawned in the turf adjacent to the one they need to end up in, for the sake of correct dir/etc being set.
/obj/effect/plant/proc/finish_spreading()
set_dir(calc_dir())
update_icon()
plant_controller.add_plant(src)
//Some plants eat through plating.
if(islist(seed.chems) && !isnull(seed.chems["pacid"]))
var/turf/T = get_turf(src)
T.ex_act(prob(80) ? 3 : 2)
/obj/effect/plant/update_icon()
//TODO: should really be caching this.
refresh_icon()
if(growth_type == 0 && !floor)
src.transform = null
var/matrix/M = matrix()
// should make the plant flush against the wall it's meant to be growing from.
M.Translate(0,-(rand(12,14)))
switch(dir)
if(WEST)
M.Turn(90)
if(NORTH)
M.Turn(180)
if(EAST)
M.Turn(270)
src.transform = M
var/icon_colour = seed.get_trait(TRAIT_PLANT_COLOUR)
if(icon_colour)
color = icon_colour
// Apply colour and light from seed datum.
if(seed.get_trait(TRAIT_BIOLUM))
var/clr
if(seed.get_trait(TRAIT_BIOLUM_COLOUR))
clr = seed.get_trait(TRAIT_BIOLUM_COLOUR)
set_light(1+round(seed.get_trait(TRAIT_POTENCY)/20), l_color = clr)
return
else
set_light(0)
/obj/effect/plant/proc/refresh_icon()
var/growth = min(max_growth,round(health/growth_threshold))
var/at_fringe = get_dist(src,parent)
if(spread_distance > 5)
if(at_fringe >= (spread_distance-3))
max_growth--
if(at_fringe >= (spread_distance-2))
max_growth--
max_growth = max(1,max_growth)
if(growth_type > 0)
switch(growth_type)
if(1)
icon_state = "worms"
if(2)
icon_state = "vines-[growth]"
if(3)
icon_state = "mass-[growth]"
if(4)
icon_state = "mold-[growth]"
else
icon_state = "[seed.get_trait(TRAIT_PLANT_ICON)]-[growth]"
if(growth>2 && growth == max_growth)
plane = ABOVE_PLANE
set_opacity(1)
if(!isnull(seed.chems["woodpulp"]))
density = 1
else
reset_plane_and_layer()
density = 0
/obj/effect/plant/proc/calc_dir()
set background = 1
var/turf/T = get_turf(src)
if(!istype(T)) return
var/direction = 16
for(var/wallDir in cardinal)
var/turf/newTurf = get_step(T,wallDir)
if(newTurf.density)
direction |= wallDir
for(var/obj/effect/plant/shroom in T.contents)
if(shroom == src)
continue
if(shroom.floor) //special
direction &= ~16
else
direction &= ~shroom.dir
var/list/dirList = list()
for(var/i=1,i<=16,i <<= 1)
if(direction & i)
dirList += i
if(dirList.len)
var/newDir = pick(dirList)
if(newDir == 16)
floor = 1
newDir = 1
return newDir
floor = 1
return 1
/obj/effect/plant/attackby(var/obj/item/weapon/W, var/mob/user)
user.setClickCooldown(user.get_attack_speed(W))
plant_controller.add_plant(src)
if(W.is_wirecutter() || istype(W, /obj/item/weapon/surgical/scalpel))
if(sampled)
to_chat(user, "<span class='warning'>\The [src] has already been sampled recently.</span>")
return
if(!is_mature())
to_chat(user, "<span class='warning'>\The [src] is not mature enough to yield a sample yet.</span>")
return
if(!seed)
to_chat(user, "<span class='warning'>There is nothing to take a sample from.</span>")
return
if(sampled)
to_chat(user, "<span class='danger'>You cannot take another sample from \the [src].</span>")
return
if(prob(70))
sampled = 1
seed.harvest(user,0,1)
health -= (rand(3,5)*5)
sampled = 1
else
..()
if(W.force)
health -= W.force
check_health()
//handles being overrun by vines - note that attacker_parent may be null in some cases
/obj/effect/plant/proc/vine_overrun(datum/seed/attacker_seed, obj/effect/plant/attacker_parent)
var/aggression = 0
aggression += (attacker_seed.get_trait(TRAIT_CARNIVOROUS) - seed.get_trait(TRAIT_CARNIVOROUS))
aggression += (attacker_seed.get_trait(TRAIT_SPREAD) - seed.get_trait(TRAIT_SPREAD))
var/resiliance
if(is_mature())
resiliance = 0
switch(seed.get_trait(TRAIT_ENDURANCE))
if(30 to 70)
resiliance = 1
if(70 to 95)
resiliance = 2
if(95 to INFINITY)
resiliance = 3
else
resiliance = -2
if(seed.get_trait(TRAIT_ENDURANCE) >= 50)
resiliance = -1
aggression -= resiliance
if(aggression > 0)
health -= aggression*5
check_health()
/obj/effect/plant/ex_act(severity)
switch(severity)
if(1.0)
die_off()
return
if(2.0)
if (prob(50))
die_off()
return
if(3.0)
if (prob(5))
die_off()
return
else
return
/obj/effect/plant/proc/check_health()
if(health <= 0)
die_off()
/obj/effect/plant/proc/is_mature()
return (health >= (max_health/3) && world.time > mature_time)