From 728cb3cffa781ee5e335905d3dc8c667b7dfc107 Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Wed, 18 Feb 2015 14:34:23 +1030 Subject: [PATCH] Working on vines. --- code/game/turfs/simulated/walls.dm | 3 +- code/modules/hydroponics/grown.dm | 13 +- code/modules/hydroponics/seed.dm | 1 + code/modules/hydroponics/seed_controller.dm | 39 +++--- code/modules/hydroponics/seed_datums.dm | 1 + .../hydroponics/spreading/spreading.dm | 69 ++++++----- .../hydroponics/spreading/spreading_growth.dm | 114 ++++++++++-------- .../spreading/spreading_response.dm | 5 +- code/modules/hydroponics/trays/tray.dm | 2 +- code/modules/hydroponics/trays/tray_soil.dm | 5 +- code/modules/reagents/Chemistry-Reagents.dm | 11 +- 11 files changed, 147 insertions(+), 116 deletions(-) diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 720f880cf99..80c872bcfcc 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -51,7 +51,8 @@ /turf/simulated/wall/ChangeTurf(var/newtype) for(var/obj/effect/E in src) if(E.name == "Wallrot") del E - for(var/obj/effect/plant/plant in range(1)) plant.wake_up() + for(var/obj/effect/plant/plant in range(1)) + plant.update_neighbors() ..(newtype) //Appearance diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index f81f2ba260d..b893c6dec83 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -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("You make planks out of \the [src]!", 1) for(var/i=0,i<2,i++) var/obj/item/stack/sheet/wood/NG = new (user.loc) diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm index 64475a7f468..b401db24f91 100644 --- a/code/modules/hydroponics/seed.dm +++ b/code/modules/hydroponics/seed.dm @@ -362,6 +362,7 @@ if(additional_chems) var/list/possible_chems = list( + "woodpulp", "bicaridine", "hyperzine", "cryoxadone", diff --git a/code/modules/hydroponics/seed_controller.dm b/code/modules/hydroponics/seed_controller.dm index 7d6784fb03e..d41794e546b 100644 --- a/code/modules/hydroponics/seed_controller.dm +++ b/code/modules/hydroponics/seed_controller.dm @@ -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;xNull or non-plant entry in plant controller queue." + 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 diff --git a/code/modules/hydroponics/seed_datums.dm b/code/modules/hydroponics/seed_datums.dm index 4dcd661f4e2..561210537dd 100644 --- a/code/modules/hydroponics/seed_datums.dm +++ b/code/modules/hydroponics/seed_datums.dm @@ -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() diff --git a/code/modules/hydroponics/spreading/spreading.dm b/code/modules/hydroponics/spreading/spreading.dm index fc46a9a7285..45fcd0d721b 100644 --- a/code/modules/hydroponics/spreading/spreading.dm +++ b/code/modules/hydroponics/spreading/spreading.dm @@ -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)) \ No newline at end of file diff --git a/code/modules/hydroponics/spreading/spreading_growth.dm b/code/modules/hydroponics/spreading/spreading_growth.dm index 213f3381abf..e671663ebae 100644 --- a/code/modules/hydroponics/spreading/spreading_growth.dm +++ b/code/modules/hydroponics/spreading/spreading_growth.dm @@ -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) \ No newline at end of file +#undef NEIGHBOR_REFRESH_TIME \ No newline at end of file diff --git a/code/modules/hydroponics/spreading/spreading_response.dm b/code/modules/hydroponics/spreading/spreading_response.dm index 0f7cfea948b..ccf74e4ef71 100644 --- a/code/modules/hydroponics/spreading/spreading_response.dm +++ b/code/modules/hydroponics/spreading/spreading_response.dm @@ -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 diff --git a/code/modules/hydroponics/trays/tray.dm b/code/modules/hydroponics/trays/tray.dm index acb501b850b..85ff1188681 100644 --- a/code/modules/hydroponics/trays/tray.dm +++ b/code/modules/hydroponics/trays/tray.dm @@ -521,7 +521,7 @@ A.hydrotray_type = src.type del(src) else if(O.force && seed) - user.visible_message("\The [src] attacks the [seed.display_name] with \the [O]!") + user.visible_message("\The [user] attacks the [seed.display_name] with \the [O]!") if(!dead) health -= O.force check_health() diff --git a/code/modules/hydroponics/trays/tray_soil.dm b/code/modules/hydroponics/trays/tray_soil.dm index abcf137e39f..d3a82ba383a 100644 --- a/code/modules/hydroponics/trays/tray_soil.dm +++ b/code/modules/hydroponics/trays/tray_soil.dm @@ -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() ..() diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm index 8beb66777c8..aba8573ded5 100644 --- a/code/modules/reagents/Chemistry-Reagents.dm +++ b/code/modules/reagents/Chemistry-Reagents.dm @@ -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"