Files
d5931c5ffe Adds an universal object health system. (#21266)
https://www.youtube.com/watch?v=ZpUYjpKg9KY

As per title. The goal is to add health to most objects in the game and
thus allow them to be dynamically destructible, while also avoiding
shitcode like each structure having its own snowflake health update
proc.

---------

Signed-off-by: Matt Atlas <mattiathebest2000@hotmail.it>
Co-authored-by: Matt Atlas <liermattia@gmail.com>
Co-authored-by: SleepyGemmy <99297919+SleepyGemmy@users.noreply.github.com>
2026-04-16 23:22:08 +00:00

130 lines
3.8 KiB
Plaintext

#define NEIGHBOR_REFRESH_TIME 100
/obj/effect/plant/proc/get_cardinal_neighbors()
var/list/cardinal_neighbors = list()
for(var/check_dir in GLOB.cardinals)
var/turf/simulated/T = get_step(get_turf(src), check_dir)
if(istype(T))
cardinal_neighbors |= T
return cardinal_neighbors
/obj/effect/plant/proc/update_neighbors()
// Update our list of valid neighboring turfs.
neighbors = list()
for(var/turf/simulated/floor in get_cardinal_neighbors())
if(get_dist(parent, floor) > spread_distance)
continue
if((locate(/obj/effect/plant) in floor.contents) || (locate(/obj/effect/dead_plant) in floor.contents) )
continue
if(floor.density)
if(seed && seed.chems[/singleton/reagent/acid/polyacid])
addtimer(CALLBACK(floor, TYPE_PROC_REF(/atom, ex_act), 3), rand(5, 25))
continue
if(!Adjacent(floor) || !floor.Enter(src))
continue
neighbors |= floor
if (neighbors.len)
SSplants.add_plant(src)
// Update all of our friends.
var/turf/T = get_turf(src)
for(var/obj/effect/plant/neighbor in range(1,src))
neighbor.neighbors -= T
/obj/effect/plant/process()
// Something is very wrong, kill ourselves.
if(!seed)
die_off()
return 0
for(var/obj/effect/smoke/chem/smoke in view(1, src))
if(smoke.reagents.has_reagent(/singleton/reagent/toxin/plantbgone))
die_off()
return
// Handle life.
var/turf/simulated/T = get_turf(src)
if(istype(T))
health -= seed.handle_environment(T,T.return_air(),null,1)
if(health < maxhealth)
health += rand(3,5)
refresh_icon()
if(health > maxhealth)
health = maxhealth
else if(health == maxhealth && !plant)
plant = new(T,seed)
plant.dir = src.dir
plant.transform = src.transform
plant.age = GET_SEED_TRAIT(seed, TRAIT_MATURATION)-1
plant.update_icon()
if(growth_type==0) //Vines do not become invisible.
set_invisibility(INVISIBILITY_MAXIMUM)
else
plant.layer = layer + 0.1
if(buckled)
seed.do_sting(buckled,src)
if(GET_SEED_TRAIT(seed, TRAIT_CARNIVOROUS))
seed.do_thorns(buckled,src)
if(world.time >= last_tick+NEIGHBOR_REFRESH_TIME)
last_tick = world.time
update_neighbors()
if(sampled)
//Should be between 2-7 for given the default range of values for TRAIT_PRODUCTION
var/chance
if(!GET_SEED_TRAIT(seed, TRAIT_PRODUCTION))
chance = 1
else
chance = max(1, round(30/GET_SEED_TRAIT(seed, TRAIT_PRODUCTION)))
if(prob(chance))
sampled = 0
if(is_mature() && neighbors.len && prob(spread_chance))
//spread to 1-3 adjacent turfs depending on yield trait.
var/max_spread = between(1, round(GET_SEED_TRAIT(seed, TRAIT_YIELD)*3/14), 3)
do_spread(spread_chance, max_spread)
// We shouldn't have spawned if the controller doesn't exist.
check_health()
if(neighbors.len || health != maxhealth || buckled || !is_mature())
SSplants.add_plant(src)
/obj/effect/plant/proc/do_spread(spread_chance, max_spread)
set waitfor = FALSE
for(var/i in 1 to max_spread)
if(prob(spread_chance))
sleep(rand(3,5))
if(!neighbors.len)
return
var/turf/target_turf = pick(neighbors)
var/obj/effect/plant/child = new(get_turf(src),seed,parent)
// This should do a little bit of animation.
addtimer(CALLBACK(src, PROC_REF(do_move), target_turf, child), 1)
// Update neighboring squares.
for(var/obj/effect/plant/neighbor in range(1,target_turf))
neighbor.neighbors -= target_turf
/obj/effect/plant/proc/do_move(turf/target, obj/effect/plant/child)
child.forceMove(target)
child.queue_icon_update()
/obj/effect/plant/proc/die_off()
// Kill off our plant.
if(plant) plant.die()
// This turf is clear now, let our buddies know.
for(var/turf/simulated/check_turf in get_cardinal_neighbors())
if(!istype(check_turf))
continue
for(var/obj/effect/plant/neighbor in check_turf.contents)
neighbor.neighbors |= check_turf
SSplants.add_plant(neighbor)
qdel(src)
#undef NEIGHBOR_REFRESH_TIME