Files
S.P.L.U.R.T-Station-13/code/modules/events/spacevine.dm

594 lines
17 KiB
Plaintext

/datum/round_event_control/spacevine
name = "Spacevine"
typepath = /datum/round_event/spacevine
weight = 15
max_occurrences = 3
min_players = 10
/datum/round_event/spacevine/start()
var/list/turfs = list() //list of all the empty floor turfs in the hallway areas
var/obj/structure/spacevine/SV = new()
for(var/area/hallway/A in world)
for(var/turf/F in A)
if(F.Enter(SV))
turfs += F
qdel(SV)
if(turfs.len) //Pick a turf to spawn at if we can
var/turf/T = pick(turfs)
new /datum/spacevine_controller(T) //spawn a controller at turf
/datum/spacevine_mutation
var/name = ""
var/severity = 1
var/hue
var/quality
/datum/spacevine_mutation/proc/add_mutation_to_vinepiece(obj/structure/spacevine/holder)
holder.mutations |= src
holder.add_atom_colour(hue, FIXED_COLOUR_PRIORITY)
/datum/spacevine_mutation/proc/process_mutation(obj/structure/spacevine/holder)
return
/datum/spacevine_mutation/proc/process_temperature(obj/structure/spacevine/holder, temp, volume)
return
/datum/spacevine_mutation/proc/on_birth(obj/structure/spacevine/holder)
return
/datum/spacevine_mutation/proc/on_grow(obj/structure/spacevine/holder)
return
/datum/spacevine_mutation/proc/on_death(obj/structure/spacevine/holder)
return
/datum/spacevine_mutation/proc/on_hit(obj/structure/spacevine/holder, mob/hitter, obj/item/I, expected_damage)
. = expected_damage
/datum/spacevine_mutation/proc/on_cross(obj/structure/spacevine/holder, mob/crosser)
return
/datum/spacevine_mutation/proc/on_chem(obj/structure/spacevine/holder, datum/reagent/R)
return
/datum/spacevine_mutation/proc/on_eat(obj/structure/spacevine/holder, mob/living/eater)
return
/datum/spacevine_mutation/proc/on_spread(obj/structure/spacevine/holder, turf/target)
return
/datum/spacevine_mutation/proc/on_buckle(obj/structure/spacevine/holder, mob/living/buckled)
return
/datum/spacevine_mutation/proc/on_explosion(severity, target, obj/structure/spacevine/holder)
return
/datum/spacevine_mutation/space_covering
name = "space protective"
hue = "#aa77aa"
quality = POSITIVE
/datum/spacevine_mutation/space_covering
var/static/list/coverable_turfs
/datum/spacevine_mutation/space_covering/New()
. = ..()
if(!coverable_turfs)
coverable_turfs = typecacheof(list(/turf/open/space)) - /turf/open/space/transit
/datum/spacevine_mutation/space_covering/on_grow(obj/structure/spacevine/holder)
process_mutation(holder)
/datum/spacevine_mutation/space_covering/process_mutation(obj/structure/spacevine/holder)
var/turf/T = get_turf(holder)
if(is_type_in_typecache(T, coverable_turfs))
var/currtype = T.type
T.ChangeTurf(/turf/open/floor/vines)
T.baseturf = currtype
/datum/spacevine_mutation/space_covering/on_death(obj/structure/spacevine/holder)
var/turf/T = get_turf(holder)
if(istype(T, /turf/open/floor/vines))
T.ChangeTurf(T.baseturf)
/datum/spacevine_mutation/bluespace
name = "bluespace"
hue = "#3333ff"
quality = MINOR_NEGATIVE
/datum/spacevine_mutation/bluespace/on_spread(obj/structure/spacevine/holder, turf/target)
if(holder.energy > 1 && !locate(/obj/structure/spacevine) in target)
holder.master.spawn_spacevine_piece(target, holder)
/datum/spacevine_mutation/light
name = "light"
hue = "#ffff00"
quality = POSITIVE
severity = 4
/datum/spacevine_mutation/light/on_grow(obj/structure/spacevine/holder)
if(holder.energy)
holder.set_light(severity, 0.3)
/datum/spacevine_mutation/toxicity
name = "toxic"
hue = "#ff00ff"
severity = 10
quality = NEGATIVE
/datum/spacevine_mutation/toxicity/on_cross(obj/structure/spacevine/holder, mob/living/crosser)
if(issilicon(crosser))
return
if(prob(severity) && istype(crosser) && !isvineimmune(crosser))
to_chat(crosser, "<span class='alert'>You accidently touch the vine and feel a strange sensation.</span>")
crosser.adjustToxLoss(5)
/datum/spacevine_mutation/toxicity/on_eat(obj/structure/spacevine/holder, mob/living/eater)
if(!isvineimmune(eater))
eater.adjustToxLoss(5)
/datum/spacevine_mutation/explosive //OH SHIT IT CAN CHAINREACT RUN!!!
name = "explosive"
hue = "#ff0000"
quality = NEGATIVE
severity = 2
/datum/spacevine_mutation/explosive/on_explosion(explosion_severity, target, obj/structure/spacevine/holder)
if(explosion_severity < 3)
qdel(holder)
else
. = 1
QDEL_IN(holder, 5)
/datum/spacevine_mutation/explosive/on_death(obj/structure/spacevine/holder, mob/hitter, obj/item/I)
explosion(holder.loc, 0, 0, severity, 0, 0)
/datum/spacevine_mutation/fire_proof
name = "fire proof"
hue = "#ff8888"
quality = MINOR_NEGATIVE
/datum/spacevine_mutation/fire_proof/process_temperature(obj/structure/spacevine/holder, temp, volume)
return 1
/datum/spacevine_mutation/fire_proof/on_hit(obj/structure/spacevine/holder, mob/hitter, obj/item/I, expected_damage)
if(I && I.damtype == "fire")
. = 0
else
. = expected_damage
/datum/spacevine_mutation/vine_eating
name = "vine eating"
hue = "#ff7700"
quality = MINOR_NEGATIVE
/datum/spacevine_mutation/vine_eating/on_spread(obj/structure/spacevine/holder, turf/target)
var/obj/structure/spacevine/prey = locate() in target
if(prey && !prey.mutations.Find(src)) //Eat all vines that are not of the same origin
qdel(prey)
/datum/spacevine_mutation/aggressive_spread //very OP, but im out of other ideas currently
name = "aggressive spreading"
hue = "#333333"
severity = 3
quality = NEGATIVE
/datum/spacevine_mutation/aggressive_spread/on_spread(obj/structure/spacevine/holder, turf/target)
target.ex_act(severity, null, src) // vine immunity handled at /mob/ex_act
/datum/spacevine_mutation/aggressive_spread/on_buckle(obj/structure/spacevine/holder, mob/living/buckled)
buckled.ex_act(severity, null, src)
/datum/spacevine_mutation/transparency
name = "transparent"
hue = ""
quality = POSITIVE
/datum/spacevine_mutation/transparency/on_grow(obj/structure/spacevine/holder)
holder.set_opacity(0)
holder.alpha = 125
/datum/spacevine_mutation/oxy_eater
name = "oxygen consuming"
hue = "#ffff88"
severity = 3
quality = NEGATIVE
/datum/spacevine_mutation/oxy_eater/process_mutation(obj/structure/spacevine/holder)
var/turf/open/floor/T = holder.loc
if(istype(T))
var/datum/gas_mixture/GM = T.air
if(!GM.gases["o2"])
return
GM.gases["o2"][MOLES] -= severity * holder.energy
GM.garbage_collect()
/datum/spacevine_mutation/nitro_eater
name = "nitrogen consuming"
hue = "#8888ff"
severity = 3
quality = NEGATIVE
/datum/spacevine_mutation/nitro_eater/process_mutation(obj/structure/spacevine/holder)
var/turf/open/floor/T = holder.loc
if(istype(T))
var/datum/gas_mixture/GM = T.air
if(!GM.gases["n2"])
return
GM.gases["n2"][MOLES] -= severity * holder.energy
GM.garbage_collect()
/datum/spacevine_mutation/carbondioxide_eater
name = "CO2 consuming"
hue = "#00ffff"
severity = 3
quality = POSITIVE
/datum/spacevine_mutation/carbondioxide_eater/process_mutation(obj/structure/spacevine/holder)
var/turf/open/floor/T = holder.loc
if(istype(T))
var/datum/gas_mixture/GM = T.air
if(!GM.gases["co2"])
return
GM.gases["co2"][MOLES] -= severity * holder.energy
GM.garbage_collect()
/datum/spacevine_mutation/plasma_eater
name = "toxins consuming"
hue = "#ffbbff"
severity = 3
quality = POSITIVE
/datum/spacevine_mutation/plasma_eater/process_mutation(obj/structure/spacevine/holder)
var/turf/open/floor/T = holder.loc
if(istype(T))
var/datum/gas_mixture/GM = T.air
if(!GM.gases["plasma"])
return
GM.gases["plasma"][MOLES] -= severity * holder.energy
GM.garbage_collect()
/datum/spacevine_mutation/thorns
name = "thorny"
hue = "#666666"
severity = 10
quality = NEGATIVE
/datum/spacevine_mutation/thorns/on_cross(obj/structure/spacevine/holder, mob/living/crosser)
if(prob(severity) && istype(crosser) && !isvineimmune(holder))
var/mob/living/M = crosser
M.adjustBruteLoss(5)
to_chat(M, "<span class='alert'>You cut yourself on the thorny vines.</span>")
/datum/spacevine_mutation/thorns/on_hit(obj/structure/spacevine/holder, mob/living/hitter, obj/item/I, expected_damage)
if(prob(severity) && istype(hitter) && !isvineimmune(holder))
var/mob/living/M = hitter
M.adjustBruteLoss(5)
to_chat(M, "<span class='alert'>You cut yourself on the thorny vines.</span>")
. = expected_damage
/datum/spacevine_mutation/woodening
name = "hardened"
hue = "#997700"
quality = NEGATIVE
/datum/spacevine_mutation/woodening/on_grow(obj/structure/spacevine/holder)
if(holder.energy)
holder.density = 1
holder.max_integrity = 100
holder.obj_integrity = holder.max_integrity
/datum/spacevine_mutation/woodening/on_hit(obj/structure/spacevine/holder, mob/living/hitter, obj/item/I, expected_damage)
if(I.is_sharp())
. = expected_damage * 0.5
else
. = expected_damage
/datum/spacevine_mutation/flowering
name = "flowering"
hue = "#0A480D"
quality = NEGATIVE
severity = 10
/datum/spacevine_mutation/flowering/on_grow(obj/structure/spacevine/holder)
if(holder.energy == 2 && prob(severity) && !locate(/obj/structure/alien/resin/flower_bud_enemy) in range(5,holder))
new/obj/structure/alien/resin/flower_bud_enemy(get_turf(holder))
/datum/spacevine_mutation/flowering/on_cross(obj/structure/spacevine/holder, mob/living/crosser)
if(prob(25))
holder.entangle(crosser)
// SPACE VINES (Note that this code is very similar to Biomass code)
/obj/structure/spacevine
name = "space vines"
desc = "An extremely expansionistic species of vine."
icon = 'icons/effects/spacevines.dmi'
icon_state = "Light1"
anchored = 1
density = 0
layer = SPACEVINE_LAYER
mouse_opacity = 2 //Clicking anywhere on the turf is good enough
pass_flags = PASSTABLE | PASSGRILLE
max_integrity = 50
var/energy = 0
var/datum/spacevine_controller/master = null
var/list/mutations = list()
/obj/structure/spacevine/Initialize()
..()
add_atom_colour("#ffffff", FIXED_COLOUR_PRIORITY)
/obj/structure/spacevine/examine(mob/user)
..()
var/text = "This one is a"
if(mutations.len)
for(var/A in mutations)
var/datum/spacevine_mutation/SM = A
text += " [SM.name]"
else
text += " normal"
text += " vine."
to_chat(user, text)
/obj/structure/spacevine/Destroy()
for(var/datum/spacevine_mutation/SM in mutations)
SM.on_death(src)
if(master)
master.VineDestroyed(src)
mutations = list()
set_opacity(0)
if(has_buckled_mobs())
unbuckle_all_mobs(force=1)
return ..()
/obj/structure/spacevine/proc/on_chem_effect(datum/reagent/R)
var/override = 0
for(var/datum/spacevine_mutation/SM in mutations)
override += SM.on_chem(src, R)
if(!override && istype(R, /datum/reagent/toxin/plantbgone))
if(prob(50))
qdel(src)
/obj/structure/spacevine/proc/eat(mob/eater)
var/override = 0
for(var/datum/spacevine_mutation/SM in mutations)
override += SM.on_eat(src, eater)
if(!override)
qdel(src)
/obj/structure/spacevine/attackby(obj/item/weapon/W, mob/user, params)
if(istype(W, /obj/item/weapon/scythe))
user.changeNext_move(CLICK_CD_MELEE)
for(var/obj/structure/spacevine/B in orange(1,src))
B.take_damage(W.force * 4, BRUTE, "melee", 1)
return
else
return ..()
/obj/structure/spacevine/attacked_by(obj/item/I, mob/living/user)
var/damage_dealt = I.force
if(I.is_sharp())
damage_dealt *= 4
if(I.damtype == BURN)
damage_dealt *= 4
for(var/datum/spacevine_mutation/SM in mutations)
damage_dealt = SM.on_hit(src, user, I, damage_dealt) //on_hit now takes override damage as arg and returns new value for other mutations to permutate further
take_damage(damage_dealt, I.damtype, "melee", 1)
/obj/structure/spacevine/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
switch(damage_type)
if(BRUTE)
if(damage_amount)
playsound(src, 'sound/weapons/slash.ogg', 50, 1)
else
playsound(src, 'sound/weapons/tap.ogg', 50, 1)
if(BURN)
playsound(src.loc, 'sound/items/welder.ogg', 100, 1)
/obj/structure/spacevine/Crossed(mob/crosser)
if(isliving(crosser))
for(var/datum/spacevine_mutation/SM in mutations)
SM.on_cross(src, crosser)
/obj/structure/spacevine/attack_hand(mob/user)
for(var/datum/spacevine_mutation/SM in mutations)
SM.on_hit(src, user)
user_unbuckle_mob(user, user)
/obj/structure/spacevine/attack_paw(mob/living/user)
for(var/datum/spacevine_mutation/SM in mutations)
SM.on_hit(src, user)
user_unbuckle_mob(user,user)
/obj/structure/spacevine/attack_alien(mob/living/user)
eat(user)
/datum/spacevine_controller
var/list/obj/structure/spacevine/vines
var/list/growth_queue
var/spread_multiplier = 5
var/spread_cap = 30
var/list/vine_mutations_list
var/mutativeness = 1
/datum/spacevine_controller/New(turf/location, list/muts, potency, production)
vines = list()
growth_queue = list()
spawn_spacevine_piece(location, null, muts)
START_PROCESSING(SSobj, src)
vine_mutations_list = list()
init_subtypes(/datum/spacevine_mutation/, vine_mutations_list)
if(potency != null)
mutativeness = potency / 10
if(production != null)
spread_cap *= production / 5
spread_multiplier /= production / 5
/datum/spacevine_controller/vv_get_dropdown()
. = ..()
. += "---"
.["Delete Vines"] = "?_src_=\ref[src];purge_vines=1"
/datum/spacevine_controller/Topic(href, href_list)
if(..() || !check_rights(R_ADMIN, FALSE))
return
if(href_list["purge_vines"])
if(alert(usr, "Are you sure you want to delete this spacevine cluster?", "Delete Vines", "Yes", "No") != "Yes")
return
DeleteVines()
/datum/spacevine_controller/proc/DeleteVines() //this is kill
QDEL_LIST(vines) //this will also qdel us
/datum/spacevine_controller/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/datum/spacevine_controller/proc/spawn_spacevine_piece(turf/location, obj/structure/spacevine/parent, list/muts)
var/obj/structure/spacevine/SV = new(location)
growth_queue += SV
vines += SV
SV.master = src
if(muts && muts.len)
for(var/datum/spacevine_mutation/M in muts)
M.add_mutation_to_vinepiece(SV)
return
if(parent)
SV.mutations |= parent.mutations
var/parentcolor = parent.atom_colours[FIXED_COLOUR_PRIORITY]
SV.add_atom_colour(parentcolor, FIXED_COLOUR_PRIORITY)
if(prob(mutativeness))
var/datum/spacevine_mutation/randmut = pick(vine_mutations_list - SV.mutations)
randmut.add_mutation_to_vinepiece(SV)
for(var/datum/spacevine_mutation/SM in SV.mutations)
SM.on_birth(SV)
location.Entered(SV)
/datum/spacevine_controller/proc/VineDestroyed(obj/structure/spacevine/S)
S.master = null
vines -= S
growth_queue -= S
if(!vines.len)
var/obj/item/seeds/kudzu/KZ = new(S.loc)
KZ.mutations |= S.mutations
KZ.set_potency(mutativeness * 10)
KZ.set_production((spread_cap / initial(spread_cap)) * 5)
qdel(src)
/datum/spacevine_controller/process()
if(!LAZYLEN(vines))
qdel(src) //space vines exterminated. Remove the controller
return
if(!growth_queue)
qdel(src) //Sanity check
return
var/length = 0
length = min( spread_cap , max( 1 , vines.len / spread_multiplier ) )
var/i = 0
var/list/obj/structure/spacevine/queue_end = list()
for(var/obj/structure/spacevine/SV in growth_queue)
if(QDELETED(SV))
continue
i++
queue_end += SV
growth_queue -= SV
for(var/datum/spacevine_mutation/SM in SV.mutations)
SM.process_mutation(SV)
if(SV.energy < 2) //If tile isn't fully grown
if(prob(20))
SV.grow()
else //If tile is fully grown
SV.entangle_mob()
//if(prob(25))
SV.spread()
if(i >= length)
break
growth_queue = growth_queue + queue_end
/obj/structure/spacevine/proc/grow()
if(!energy)
src.icon_state = pick("Med1", "Med2", "Med3")
energy = 1
set_opacity(1)
else
src.icon_state = pick("Hvy1", "Hvy2", "Hvy3")
energy = 2
for(var/datum/spacevine_mutation/SM in mutations)
SM.on_grow(src)
/obj/structure/spacevine/proc/entangle_mob()
if(!has_buckled_mobs() && prob(25))
for(var/mob/living/V in src.loc)
entangle(V)
if(has_buckled_mobs())
break //only capture one mob at a time
/obj/structure/spacevine/proc/entangle(mob/living/V)
if(!V || isvineimmune(V))
return
for(var/datum/spacevine_mutation/SM in mutations)
SM.on_buckle(src, V)
if((V.stat != DEAD) && (V.buckled != src)) //not dead or captured
to_chat(V, "<span class='danger'>The vines [pick("wind", "tangle", "tighten")] around you!</span>")
buckle_mob(V, 1)
/obj/structure/spacevine/proc/spread()
var/direction = pick(GLOB.cardinals)
var/turf/stepturf = get_step(src,direction)
for(var/datum/spacevine_mutation/SM in mutations)
SM.on_spread(src, stepturf)
stepturf = get_step(src,direction) //in case turf changes, to make sure no runtimes happen
if(!locate(/obj/structure/spacevine, stepturf))
if(stepturf.Enter(src))
if(master)
master.spawn_spacevine_piece(stepturf, src)
/obj/structure/spacevine/ex_act(severity, target)
if(istype(target, type)) //if its agressive spread vine dont do anything
return
var/i
for(var/datum/spacevine_mutation/SM in mutations)
i += SM.on_explosion(severity, target, src)
if(!i && prob(100/severity))
qdel(src)
/obj/structure/spacevine/temperature_expose(null, temp, volume)
var/override = 0
for(var/datum/spacevine_mutation/SM in mutations)
override += SM.process_temperature(src, temp, volume)
if(!override)
qdel(src)
/obj/structure/spacevine/CanPass(atom/movable/mover, turf/target, height=0)
if(isvineimmune(mover))
. = TRUE
else
. = ..()
/proc/isvineimmune(atom/A)
. = FALSE
if(isliving(A))
var/mob/living/M = A
if(("vines" in M.faction) || ("plants" in M.faction))
. = TRUE