mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-08-27 22:18:27 +01:00
Working on vines.
This commit is contained in:
@@ -47,10 +47,11 @@
|
||||
|
||||
for(var/rid in seed.chems)
|
||||
var/list/reagent_data = seed.chems[rid]
|
||||
var/rtotal = reagent_data[1]
|
||||
if(reagent_data.len > 1 && potency > 0)
|
||||
rtotal += round(potency/reagent_data[2])
|
||||
reagents.add_reagent(rid,max(1,rtotal))
|
||||
if(reagent_data && reagent_data.len)
|
||||
var/rtotal = reagent_data[1]
|
||||
if(reagent_data.len > 1 && potency > 0)
|
||||
rtotal += round(potency/reagent_data[2])
|
||||
reagents.add_reagent(rid,max(1,rtotal))
|
||||
update_desc()
|
||||
if(reagents.total_volume > 0)
|
||||
bitesize = 1+round(reagents.total_volume / 2, 1)
|
||||
@@ -119,7 +120,7 @@
|
||||
desc += " mushroom"
|
||||
else
|
||||
desc += " fruit"
|
||||
plant_controller.product_descs[seed.uid] = desc
|
||||
plant_controller.product_descs["[seed.uid]"] = desc
|
||||
desc += ". Delicious! Probably."
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/grown/update_icon()
|
||||
@@ -184,7 +185,7 @@
|
||||
del(src)
|
||||
return
|
||||
else if(istype(W, /obj/item/weapon/circular_saw) || istype(W, /obj/item/weapon/hatchet) || (istype(W, /obj/item/weapon/twohanded/fireaxe) && W:wielded) || istype(W, /obj/item/weapon/melee/energy))
|
||||
if(seed.get_trait(TRAIT_PRODUCT_ICON) == "mushroom7")
|
||||
if(seed.chems && !isnull(seed.chems["woodpulp"]))
|
||||
user.show_message("<span class='notice'>You make planks out of \the [src]!</span>", 1)
|
||||
for(var/i=0,i<2,i++)
|
||||
var/obj/item/stack/sheet/wood/NG = new (user.loc)
|
||||
|
||||
@@ -362,6 +362,7 @@
|
||||
|
||||
if(additional_chems)
|
||||
var/list/possible_chems = list(
|
||||
"woodpulp",
|
||||
"bicaridine",
|
||||
"hyperzine",
|
||||
"cryoxadone",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Attempts to offload processing for the spreading plants from the MC.
|
||||
// Processes vines/spreading plants.
|
||||
|
||||
#define PLANTS_PER_TICK 5
|
||||
#define PLANT_TICK_TIME 10
|
||||
#define PLANTS_PER_TICK 100
|
||||
#define PLANT_TICK_TIME 50
|
||||
|
||||
// Debug for testing seed genes.
|
||||
/client/proc/show_plant_genes()
|
||||
@@ -25,9 +25,8 @@ var/global/datum/controller/plants/plant_controller // Set in New().
|
||||
|
||||
var/plants_per_tick = PLANTS_PER_TICK
|
||||
var/plant_tick_time = PLANT_TICK_TIME
|
||||
|
||||
var/list/product_descs = list() // Stores generated fruit descs.
|
||||
var/list/next_plants = list() // All queued plants.
|
||||
var/list/plant_queue = list() // All queued plants.
|
||||
var/list/seeds = list() // All seed data stored here.
|
||||
var/list/gene_tag_masks = list() // Gene obfuscation for delicious trial and error goodness.
|
||||
var/list/plant_icon_cache = list() // Stores images of growth, fruits and seeds.
|
||||
@@ -107,6 +106,9 @@ var/global/datum/controller/plants/plant_controller // Set in New().
|
||||
if(seed.consume_gasses)
|
||||
seed.consume_gasses["phoron"] = null
|
||||
seed.consume_gasses["carbon_dioxide"] = null
|
||||
if(seed.chems && !isnull(seed.chems["pacid"]))
|
||||
seed.chems["pacid"] = null // Eating through the hull will make these plants completely inviable, albeit very dangerous.
|
||||
seed.chems -= null // Setting to null does not actually remove the entry, which is weird.
|
||||
seed.set_trait(TRAIT_IDEAL_HEAT,293)
|
||||
seed.set_trait(TRAIT_HEAT_TOLERANCE,20)
|
||||
seed.set_trait(TRAIT_IDEAL_LIGHT,8)
|
||||
@@ -125,19 +127,20 @@ var/global/datum/controller/plants/plant_controller // Set in New().
|
||||
sleep(plant_tick_time)
|
||||
else
|
||||
processed = 0
|
||||
var/list/plants = next_plants
|
||||
next_plants = list()
|
||||
for(var/x=0;x<plants_per_tick;x++)
|
||||
if(!plants.len)
|
||||
break
|
||||
sleep(-1)
|
||||
var/obj/effect/plant/plant = pick(plants)
|
||||
plants -= plant
|
||||
plant.process()
|
||||
processed++
|
||||
if(plants.len)
|
||||
next_plants |= plants
|
||||
sleep(plant_tick_time - processed)
|
||||
if(plant_queue.len)
|
||||
var/target_to_process = min(plant_queue.len,PLANT_TICK_TIME)
|
||||
for(var/x=0;x<target_to_process;x++)
|
||||
if(!plant_queue.len)
|
||||
break
|
||||
var/obj/effect/plant/plant = pick(plant_queue)
|
||||
if(!istype(plant))
|
||||
world << "<span class='danger'>Null or non-plant entry in plant controller queue.</span>"
|
||||
break
|
||||
plant_queue -= plant
|
||||
sleep(1) // Stagger processing out so previous tick can resolve (overlapping plant segments etc)
|
||||
plant.process()
|
||||
processed++
|
||||
sleep(max(1,(plant_tick_time-processed)))
|
||||
|
||||
/datum/controller/plants/proc/add_plant(var/obj/effect/plant/plant)
|
||||
next_plants |= plant
|
||||
plant_queue |= plant
|
||||
|
||||
@@ -443,6 +443,7 @@
|
||||
name = "towercap"
|
||||
seed_name = "tower cap"
|
||||
display_name = "tower caps"
|
||||
chems = list("woodpulp" = list(10,1))
|
||||
mutants = null
|
||||
|
||||
/datum/seed/mushroom/towercap/New()
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
|
||||
/obj/effect/dead_plant/attackby()
|
||||
..()
|
||||
for(var/obj/effect/plant/neighbor in view(1,src))
|
||||
neighbor.wake_up()
|
||||
for(var/obj/effect/plant/neighbor in range(1))
|
||||
neighbor.update_neighbors()
|
||||
del(src)
|
||||
|
||||
/obj/effect/plant
|
||||
@@ -50,13 +50,12 @@
|
||||
var/growth_type = 0
|
||||
var/max_growth = 0
|
||||
|
||||
var/list/children = list()
|
||||
var/list/neighbors = list()
|
||||
var/obj/effect/plant/parent
|
||||
var/datum/seed/seed
|
||||
var/floor = 0
|
||||
var/spread_chance = 40
|
||||
var/spread_distance = 3
|
||||
var/spread_into_adjacent = 60
|
||||
var/evolve_chance = 2
|
||||
var/last_tick = 0
|
||||
var/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/plant
|
||||
@@ -64,9 +63,14 @@
|
||||
/obj/effect/plant/single
|
||||
spread_chance = 0
|
||||
|
||||
/obj/effect/plant/New(var/newloc, var/datum/seed/newseed)
|
||||
/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.
|
||||
if(!plant_controller)
|
||||
@@ -102,22 +106,27 @@
|
||||
if(max_growth > 2 && prob(50))
|
||||
max_growth-- //Ensure some variation in final sprite, makes the carpet of crap look less wonky.
|
||||
|
||||
spread_into_adjacent = round(seed.get_trait(TRAIT_POTENCY)/2)
|
||||
spread_distance = ((growth_type>0) ? round(spread_into_adjacent/2) : round(spread_into_adjacent/15))
|
||||
spread_chance = round(spread_into_adjacent/2)
|
||||
spread_chance = seed.get_trait(TRAIT_POTENCY)
|
||||
spread_distance = ((growth_type>0) ? round(spread_chance*0.6) : round(spread_chance*0.3))
|
||||
|
||||
set_dir(calc_dir())
|
||||
update_icon()
|
||||
wake_up()
|
||||
last_tick = world.timeofday
|
||||
|
||||
spawn(1)
|
||||
plant_controller.add_plant(src)
|
||||
// Some plants eat through plating.
|
||||
if(!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()
|
||||
M.Translate(0,-(rand(12,14))) // should make the plant flush against the wall it's meant to be growing from.
|
||||
// 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)
|
||||
@@ -141,7 +150,13 @@
|
||||
SetLuminosity(0)
|
||||
|
||||
/obj/effect/plant/proc/refresh_icon()
|
||||
var/growth = min(max_growth,max(1,round(health/growth_threshold)))
|
||||
var/growth = min(max_growth,round(health/growth_threshold))
|
||||
var/at_fringe = get_dist(src,parent)
|
||||
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)
|
||||
@@ -155,24 +170,14 @@
|
||||
else
|
||||
icon_state = "[seed.get_trait(TRAIT_PLANT_ICON)]-[growth]"
|
||||
|
||||
layer = (growth == max_growth ? 4 : 3)
|
||||
|
||||
/obj/effect/plant/Del()
|
||||
if(children && children.len)
|
||||
die_off(null,1)
|
||||
..()
|
||||
|
||||
/obj/effect/plant/proc/get_dist_to_parent(var/current_count)
|
||||
if(!parent)
|
||||
return current_count
|
||||
current_count++
|
||||
return parent.get_dist_to_parent(current_count)
|
||||
|
||||
/obj/effect/plant/proc/get_root()
|
||||
if(parent)
|
||||
return parent.get_root()
|
||||
if(growth>2 && growth == max_growth)
|
||||
layer = 5
|
||||
opacity = 1
|
||||
if(!isnull(seed.chems["woodpulp"]))
|
||||
density = 1
|
||||
else
|
||||
return src
|
||||
layer = 3
|
||||
density = 0
|
||||
|
||||
/obj/effect/plant/proc/calc_dir(turf/location = loc)
|
||||
set background = 1
|
||||
@@ -209,6 +214,8 @@
|
||||
|
||||
/obj/effect/plant/attackby(var/obj/item/weapon/W, var/mob/user)
|
||||
|
||||
plant_controller.add_plant(src)
|
||||
|
||||
if(istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/weapon/scalpel))
|
||||
if(!seed)
|
||||
user << "There is nothing to take a sample from in \the [src]."
|
||||
@@ -240,7 +247,7 @@
|
||||
|
||||
/obj/effect/plant/proc/check_health()
|
||||
if(health <= 0)
|
||||
die_off(1)
|
||||
die_off()
|
||||
|
||||
/obj/effect/plant/proc/is_mature()
|
||||
return (health < (max_health/3))
|
||||
@@ -1,8 +1,31 @@
|
||||
#define NEIGHBOR_REFRESH_TIME 100
|
||||
|
||||
/obj/effect/plant/proc/update_neighbors()
|
||||
// Update our list of valid neighboring turfs.
|
||||
neighbors = list()
|
||||
for(var/turf/simulated/floor/floor in range(1,src))
|
||||
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(!isnull(seed.chems["pacid"]))
|
||||
spawn(rand(5,25)) floor.ex_act(3)
|
||||
continue
|
||||
else if(!floor.Enter(src))
|
||||
continue
|
||||
neighbors |= floor
|
||||
// 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
|
||||
|
||||
// Handle life.
|
||||
var/turf/simulated/T = get_turf(src)
|
||||
@@ -10,26 +33,13 @@
|
||||
health -= seed.handle_environment(T, T.return_air(),1)
|
||||
if(health < max_health)
|
||||
health += rand(3,5)
|
||||
refresh_icon()
|
||||
if(health > max_health)
|
||||
health = max_health
|
||||
refresh_icon()
|
||||
|
||||
if(buckled_mob)
|
||||
seed.do_sting(buckled_mob,src)
|
||||
if(seed.get_trait(TRAIT_CARNIVOROUS))
|
||||
seed.do_thorns(buckled_mob,src)
|
||||
|
||||
var/list/possible_locs = list()
|
||||
var/failed_turfs = 0
|
||||
|
||||
for(var/turf/simulated/floor/floor in range(1))
|
||||
if((locate(/obj/effect/plant) in floor.contents) || (locate(/obj/effect/dead_plant) in floor.contents) || floor.density)
|
||||
failed_turfs++
|
||||
if(floor.Enter(src))
|
||||
possible_locs |= floor
|
||||
|
||||
if(health == max_health && failed_turfs > 3 && !plant)
|
||||
else if(health == max_health && !plant)
|
||||
plant = new(T,seed)
|
||||
plant.dir = src.dir
|
||||
plant.transform = src.transform
|
||||
plant.age = seed.get_trait(TRAIT_MATURATION)-1
|
||||
plant.update_icon()
|
||||
if(growth_type==0) //Vines do not become invisible.
|
||||
@@ -37,42 +47,44 @@
|
||||
else
|
||||
plant.layer = layer + 0.1
|
||||
|
||||
if(possible_locs.len && prob(spread_chance))
|
||||
if(buckled_mob)
|
||||
seed.do_sting(buckled_mob,src)
|
||||
if(seed.get_trait(TRAIT_CARNIVOROUS))
|
||||
seed.do_thorns(buckled_mob,src)
|
||||
|
||||
if(world.time >= last_tick+NEIGHBOR_REFRESH_TIME)
|
||||
last_tick = world.time
|
||||
update_neighbors()
|
||||
|
||||
if(neighbors.len && prob(spread_chance))
|
||||
|
||||
for(var/i=1,i<=seed.get_trait(TRAIT_YIELD),i++)
|
||||
if(!possible_locs.len)
|
||||
break
|
||||
if(prob(spread_into_adjacent))
|
||||
var/turf/target_turf = pick(possible_locs)
|
||||
possible_locs -= target_turf
|
||||
var/obj/effect/plant/child = new(target_turf, seed)
|
||||
child.parent = get_root()
|
||||
child.parent.children |= child
|
||||
if(prob(spread_chance))
|
||||
sleep(rand(3,5))
|
||||
if(!neighbors.len)
|
||||
break
|
||||
var/turf/target_turf = pick(neighbors)
|
||||
var/obj/effect/plant/child = new(get_turf(src),seed,parent)
|
||||
spawn(1) // This should do a little bit of animation.
|
||||
child.loc = target_turf
|
||||
child.update_icon()
|
||||
// Update neighboring squares.
|
||||
for(var/obj/effect/plant/neighbor in range(1,target_turf))
|
||||
neighbor.neighbors -= target_turf
|
||||
|
||||
if(buckled_mob || health != max_health || possible_locs.len)
|
||||
wake_up() // We still need to process!
|
||||
|
||||
/obj/effect/plant/proc/wake_up()
|
||||
if(plant_controller)
|
||||
// We shouldn't have spawned if the controller doesn't exist.
|
||||
check_health()
|
||||
if(neighbors.len && health == max_health)
|
||||
plant_controller.add_plant(src)
|
||||
|
||||
/obj/effect/plant/proc/die_off(var/no_remains, var/no_del)
|
||||
// Remove ourselves from our parent.
|
||||
if(parent && parent.children)
|
||||
parent.children -= src
|
||||
// Kill off any of our children (and as an added bonus, other plants in this area)
|
||||
for(var/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/plant in get_turf(src))
|
||||
plant.dead = 1
|
||||
plant.update_icon()
|
||||
// Cause the plants around us to update.
|
||||
if(children && children.len)
|
||||
for(var/obj/effect/plant/child in children)
|
||||
child.die_off()
|
||||
for(var/obj/effect/plant/neighbor in view(1,src))
|
||||
neighbor.wake_up()
|
||||
/obj/effect/plant/proc/die_off()
|
||||
// Kill off our plant.
|
||||
if(plant) plant.die()
|
||||
// This turf is clear now, let our buddies know.
|
||||
var/turf/T = get_turf(src)
|
||||
for(var/obj/effect/plant/neighbor in range(1,src))
|
||||
neighbor.neighbors |= T
|
||||
plant_controller.add_plant(neighbor)
|
||||
spawn(1) if(src) del(src)
|
||||
|
||||
if(!no_remains && !(locate(/obj/effect/dead_plant) in get_turf(src)))
|
||||
var/obj/effect/dead_plant/plant_remains = new(get_turf(src))
|
||||
plant_remains.icon = src.icon
|
||||
plant_remains.icon_state = src.icon_state
|
||||
if(!no_del)
|
||||
del(src)
|
||||
#undef NEIGHBOR_REFRESH_TIME
|
||||
@@ -1,5 +1,5 @@
|
||||
/obj/effect/plant/HasProximity(var/atom/movable/AM)
|
||||
wake_up()
|
||||
|
||||
if(!is_mature() || seed.get_trait(TRAIT_SPREAD) != 2)
|
||||
return
|
||||
|
||||
@@ -11,11 +11,10 @@
|
||||
entangle(M)
|
||||
|
||||
/obj/effect/plant/attack_hand(mob/user as mob)
|
||||
wake_up()
|
||||
// Todo, cause damage.
|
||||
manual_unbuckle(user)
|
||||
|
||||
/obj/effect/plant/proc/trodden_on(var/mob/living/victim)
|
||||
wake_up()
|
||||
if(!is_mature())
|
||||
return
|
||||
var/mob/living/carbon/human/H = victim
|
||||
|
||||
@@ -521,7 +521,7 @@
|
||||
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>")
|
||||
user.visible_message("<span class='danger'>\The [user] attacks the [seed.display_name] with \the [O]!</span>")
|
||||
if(!dead)
|
||||
health -= O.force
|
||||
check_health()
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
/obj/machinery/portable_atmospherics/hydroponics/soil/CanPass()
|
||||
return 1
|
||||
|
||||
// This is a hack pending a proper rewrite of the plant controller.
|
||||
// Holder for vine plants.
|
||||
// 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
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/harvest()
|
||||
..()
|
||||
if(!seed)
|
||||
if(!seed) // Repeat harvests are a thing.
|
||||
del(src)
|
||||
|
||||
/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/die()
|
||||
@@ -62,5 +62,4 @@
|
||||
for(var/obj/effect/plant/plant in get_turf(src))
|
||||
if(plant.invisibility == INVISIBILITY_MAXIMUM)
|
||||
plant.invisibility = initial(plant.invisibility)
|
||||
plant.die_off()
|
||||
..()
|
||||
|
||||
@@ -192,6 +192,13 @@ datum
|
||||
M.resistances += self.data
|
||||
return
|
||||
|
||||
woodpulp
|
||||
name = "Wood Pulp"
|
||||
id = "woodpulp"
|
||||
description = "A mass of wood fibers."
|
||||
reagent_state = LIQUID
|
||||
color = "#B97A57"
|
||||
|
||||
#define WATER_LATENT_HEAT 19000 // How much heat is removed when applied to a hot turf, in J/unit (19000 makes 120 u of water roughly equivalent to 4L)
|
||||
water
|
||||
name = "Water"
|
||||
@@ -260,13 +267,13 @@ datum
|
||||
|
||||
reaction_mob(var/mob/living/M, var/method=TOUCH, var/volume)
|
||||
if (istype(M, /mob/living/carbon/slime))
|
||||
var/mob/living/carbon/slime/S = M
|
||||
var/mob/living/carbon/slime/S = M
|
||||
S.apply_water(volume)
|
||||
if(method == TOUCH && isliving(M))
|
||||
M.adjust_fire_stacks(-(volume / 10))
|
||||
if(M.fire_stacks <= 0)
|
||||
M.ExtinguishMob()
|
||||
return
|
||||
return
|
||||
|
||||
water/holywater
|
||||
name = "Holy Water"
|
||||
|
||||
Reference in New Issue
Block a user