From ed2d89976b2f82534b64fa2ad1065d389c90a0db Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Thu, 25 Feb 2021 14:34:48 +0100 Subject: [PATCH] [MIRROR] Completely refactors glowshroom spreading and makes them self-decay faster (#3633) * Completely refactors glowshroom spreading and makes them self-decay faster (#56981) * Completely refactors glowshroom spreading and makes them self-decay faster Co-authored-by: Qustinnus --- code/__DEFINES/botany.dm | 3 - code/_globalvars/misc.dm | 2 + code/game/objects/effects/glowshroom.dm | 211 +++++++++++++----------- 3 files changed, 113 insertions(+), 103 deletions(-) diff --git a/code/__DEFINES/botany.dm b/code/__DEFINES/botany.dm index 80872245e2b..0614a4fa46d 100644 --- a/code/__DEFINES/botany.dm +++ b/code/__DEFINES/botany.dm @@ -40,6 +40,3 @@ /// -- Flags for traits. -- /// Caps the plant's yield at 5 instead of 10. #define TRAIT_HALVES_YIELD (1<<0) - -/// Define for how much endurance a glowcap loses per spread -#define GLOWCAP_ENDURANCE_SPREAD_COST 20 diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm index 66f306a8619..e0e6ed945c8 100644 --- a/code/_globalvars/misc.dm +++ b/code/_globalvars/misc.dm @@ -29,3 +29,5 @@ GLOBAL_LIST_EMPTY(poll_options) GLOBAL_PROTECT(poll_options) GLOBAL_VAR_INIT(internal_tick_usage, 0.2 * world.tick_lag) + +GLOBAL_VAR_INIT(glowshrooms, 0) diff --git a/code/game/objects/effects/glowshroom.dm b/code/game/objects/effects/glowshroom.dm index c1e07acc6eb..75450c71d9a 100644 --- a/code/game/objects/effects/glowshroom.dm +++ b/code/game/objects/effects/glowshroom.dm @@ -1,5 +1,6 @@ -//separate dm since hydro is getting bloated already - +#define GLOWSHROOM_SPREAD_BASE_DIMINISH_FACTOR 10 +#define GLOWSHROOM_SPREAD_DIMINISH_FACTOR_PER_GLOWSHROOM 0.2 +#define GLOWSHROOM_BASE_INTEGRITY 60 /obj/structure/glowshroom name = "glowshroom" desc = "Mycena Bregprox, a species of mushroom that glows in the dark." @@ -9,21 +10,28 @@ icon = 'icons/obj/lighting.dmi' icon_state = "glowshroom" //replaced in New layer = ABOVE_NORMAL_TURF_LAYER - /// Time interval between glowshroom "spreads" - var/delay_spread = 2 MINUTES - /// Time interval between glowshroom decay checks - var/delay_decay = 30 SECONDS + max_integrity = GLOWSHROOM_BASE_INTEGRITY + ///Cooldown for when next to try to spread. + COOLDOWN_DECLARE(spread_cooldown) + /// Min time interval between glowshroom "spreads" + var/min_delay_spread = 20 SECONDS + /// Max time interval between glowshroom "spreads" + var/max_delay_spread = 30 SECONDS /// Boolean to indicate if the shroom is on the floor/wall var/floor = 0 /// Mushroom generation number var/generation = 1 /// Chance to spread into adjacent tiles (0-100) - var/spreadIntoAdjacentChance = 75 + var/spread_into_adjacent_chance = 75 + ///Amount of decay when decay happens on process. + var/idle_decay_min = 1 + ///Amount of decay when decay happens on process + var/idle_decay_max = 2 + ///Amount of percentage decay affects endurance.max_integrity = + var/endurance_decay_rate = 0.1 /// Internal seed of the glowshroom, stats are stored here var/obj/item/seeds/myseed = /obj/item/seeds/glowshroom - /// If we fail to spread this many times we stop trying to spread - var/max_failed_spreads = 5 /// Turfs where the glowshroom cannot spread to var/static/list/blacklisted_glowshroom_turfs = typecacheof(list( /turf/open/lava, @@ -53,33 +61,28 @@ * * Arguments: * * newseed - Seed of the shroom - * * mutate_stats - If the plant needs to mutate their stats - * * spread - If the plant is a result of spreading, reduce its stats */ -/obj/structure/glowshroom/Initialize(mapload, obj/item/seeds/newseed, mutate_stats, spread) + + +/obj/structure/glowshroom/Initialize(mapload, obj/item/seeds/newseed) . = ..() + GLOB.glowshrooms++ if(newseed) - myseed = newseed.Copy() + myseed = newseed myseed.forceMove(src) else myseed = new myseed(src) - if(spread) - myseed.adjust_potency(-round(myseed.potency * 0.25)) // Reduce potency of the little mushie if it's spreading - if(mutate_stats) //baby mushrooms have different stats :3 - myseed.adjust_potency(rand(-4,3)) - myseed.adjust_yield(rand(-3,2)) - myseed.adjust_production(rand(-3,3)) - myseed.adjust_endurance(myseed.endurance + rand(-3,2)) - if(myseed.production >= 1) //In case production is varedited to -1 or less which would cause unlimited or negative delay. - delay_spread = delay_spread - (11 - myseed.production) * 100 //Because lower production speed stat gives faster production speed, which should give faster mushroom spread. Range 200-1100 deciseconds. + + modify_max_integrity(GLOWSHROOM_BASE_INTEGRITY + ((100 - GLOWSHROOM_BASE_INTEGRITY) / 100 * myseed.endurance)) //goes up to 100 with peak endurance + var/datum/plant_gene/trait/glow/G = myseed.get_gene(/datum/plant_gene/trait/glow) if(ispath(G)) // Seeds were ported to initialize so their genes are still typepaths here, luckily their initializer is smart enough to handle us doing this myseed.genes -= G G = new G myseed.genes += G set_light(G.glow_range(myseed), G.glow_power(myseed), G.glow_color) - setDir(CalcDir()) + setDir(calc_dir()) base_icon_state = initial(icon_state) if(!floor) switch(dir) //offset to make it be on the wall rather than on the floor @@ -95,9 +98,14 @@ else //if on the floor, glowshroom on-floor sprite icon_state = base_icon_state + COOLDOWN_START(src, spread_cooldown, rand(min_delay_spread, max_delay_spread)) - addtimer(CALLBACK(src, .proc/Spread), delay_spread, TIMER_UNIQUE|TIMER_NO_HASH_WAIT) - addtimer(CALLBACK(src, .proc/Decay), delay_decay, TIMER_UNIQUE|TIMER_NO_HASH_WAIT) + START_PROCESSING(SSobj, src) + +/obj/structure/glowshroom/Destroy() + . = ..() + GLOB.glowshrooms-- + STOP_PROCESSING(SSobj, src) /obj/structure/glowshroom/ComponentInitialize() . = ..() @@ -107,90 +115,79 @@ * Causes glowshroom spreading across the floor/walls. */ +/obj/structure/glowshroom/process(delta_time) + if(COOLDOWN_FINISHED(src, spread_cooldown)) + COOLDOWN_START(src, spread_cooldown, rand(min_delay_spread, max_delay_spread)) + Spread() + + Decay(rand(idle_decay_min, idle_decay_max) * delta_time) + + + /obj/structure/glowshroom/proc/Spread() - - //We could be deleted at any point and the timers might not be cleaned up - if(QDELETED(src)) - return - var/turf/ownturf = get_turf(src) if(!TURF_SHARES(ownturf)) //If we are in a 1x1 room - addtimer(CALLBACK(src, .proc/Spread), delay_spread, TIMER_UNIQUE|TIMER_NO_HASH_WAIT) return //Deal with it not now - var/shrooms_planted = 0 - var/list/possibleLocs = list() + var/list/possible_locs = list() //Lets collect a list of possible viewable turfs BEFORE we iterate for yield so we don't call view multiple //times when there's no real chance of the viewable range changing, really you could do this once on item //spawn and most people probably would not notice. - for(var/turf/open/floor/earth in view(3,src)) + for(var/turf/open/floor/earth in oview(2,src)) if(is_type_in_typecache(earth, blacklisted_glowshroom_turfs)) continue if(!TURF_SHARES(earth)) continue - possibleLocs += earth + possible_locs += earth //Lets not even try to spawn again if somehow we have ZERO possible locations - if(!possibleLocs.len) + if(!possible_locs.len) return + var/chance_generation = 100 * (NUM_E ** -((GLOWSHROOM_SPREAD_BASE_DIMINISH_FACTOR + GLOWSHROOM_SPREAD_DIMINISH_FACTOR_PER_GLOWSHROOM * GLOB.glowshrooms) / myseed.potency * (generation - 1))) //https://www.desmos.com/calculator/istvjvcelz + for(var/i in 1 to myseed.yield) - var/chance_stats = ((myseed.potency + myseed.endurance * 2) * 0.2) // Chance of generating a new mushroom based on stats - var/chance_generation = (100 / (generation * generation)) // This formula gives you diminishing returns based on generation. 100% with 1st gen, decreasing to 25%, 11%, 6, 4, 2... + if(!prob(chance_generation)) + continue + var/spreads_into_adjacent = prob(spread_into_adjacent_chance) + var/turf/new_loc = null - // Whatever is the higher chance we use it (this is really stupid as the diminishing returns are effectively pointless???) - if(prob(max(chance_stats, chance_generation))) - var/spreadsIntoAdjacent = prob(spreadIntoAdjacentChance) - var/turf/newLoc = null - - //Try three random locations to spawn before giving up tradeoff - //between running view(1, earth) on every single collected possibleLoc - //and failing to spread if we get 3 bad picks, which should only be a problem - //if there's a lot of glow shroom clustered about - for(var/Potato in 1 to 3) - var/turf/possibleLoc = pick(possibleLocs) - if(spreadsIntoAdjacent || !locate(/obj/structure/glowshroom) in view(1,possibleLoc)) - newLoc = possibleLoc - break - - //We failed to find any location, skip trying to yield - if(newLoc == null) + //Try three random locations to spawn before giving up tradeoff + //between running view(1, earth) on every single collected possibleLoc + //and failing to spread if we get 3 bad picks, which should only be a problem + //if there's a lot of glow shroom clustered about + for(var/iterator in 1 to 3) + var/turf/possibleLoc = pick(possible_locs) + if(spreads_into_adjacent || !locate(/obj/structure/glowshroom) in view(1,possibleLoc)) + new_loc = possibleLoc break - var/shroomCount = 0 //hacky - var/placeCount = 1 - for(var/obj/structure/glowshroom/shroom in newLoc) - shroomCount++ - for(var/wallDir in GLOB.cardinals) - var/turf/isWall = get_step(newLoc,wallDir) - if(isWall.density) - placeCount++ - if(shroomCount >= placeCount) - continue + //We failed to find any location, skip trying to yield + if(new_loc == null) + break - Decay(TRUE, GLOWCAP_ENDURANCE_SPREAD_COST) // Decay before spawning new mushrooms to reduce their endurance - if(QDELETED(src)) //Decay can end us - return - var/obj/structure/glowshroom/child = new type(newLoc, myseed, TRUE, TRUE) - child.generation = generation + 1 - shrooms_planted++ - if(!shrooms_planted) - max_failed_spreads-- + var/shroom_count = 0 + var/place_count = 1 + for(var/obj/structure/glowshroom/shroom in new_loc) + shroom_count++ + for(var/wall_dir in GLOB.cardinals) + var/turf/potential_wall = get_step(new_loc,wall_dir) + if(potential_wall.density) + place_count++ + if(shroom_count >= place_count) + continue - //if we didn't get all possible shrooms planted or we haven't failed to spread at least 5 times then try to spread again later - if( (shrooms_planted <= myseed.yield) && (max_failed_spreads >= 0) ) - myseed.adjust_yield(-shrooms_planted) - //Lets make this a unique hash - addtimer(CALLBACK(src, .proc/Spread), delay_spread, TIMER_UNIQUE|TIMER_NO_HASH_WAIT) + var/obj/structure/glowshroom/child = new type(new_loc, newseed = myseed.Copy()) + child.generation = generation + 1 -/obj/structure/glowshroom/proc/CalcDir(turf/location = loc) +/obj/structure/glowshroom/proc/calc_dir(turf/location = loc) var/direction = 16 - for(var/wallDir in GLOB.cardinals) - var/turf/newTurf = get_step(location,wallDir) - if(newTurf.density) - direction |= wallDir + for(var/wall_dir in GLOB.cardinals) + var/turf/new_turf = get_step(location,wall_dir) + if(new_turf.density) + direction |= wall_dir for(var/obj/structure/glowshroom/shroom in location) if(shroom == src) @@ -200,37 +197,31 @@ else direction &= ~shroom.dir - var/list/dirList = list() + var/list/dir_list = list() for(var/i=1,i<=16,i <<= 1) if(direction & i) - dirList += i + dir_list += i - if(dirList.len) - var/newDir = pick(dirList) - if(newDir == 16) + if(dir_list.len) + var/new_dir = pick(dir_list) + if(new_dir == 16) floor = 1 - newDir = 1 - return newDir + new_dir = 1 + return new_dir floor = 1 return 1 /** - * Causes the glowshroom to decay by decreasing its endurance. + * Causes the glowshroom to decay by decreasing its endurance, destroying it when it gets too low. * * Arguments: - * * spread - Boolean to indicate if the decay is due to spreading or natural decay. * * amount - Amount of endurance to be reduced due to spread decay. */ -/obj/structure/glowshroom/proc/Decay(spread, amount) - if (spread) // Decay due to spread - myseed.adjust_endurance(-amount) - else // Timed decay - myseed.adjust_endurance(-1) - if (myseed.endurance > MIN_PLANT_ENDURANCE) - addtimer(CALLBACK(src, .proc/Decay), delay_decay, TIMER_UNIQUE|TIMER_NO_HASH_WAIT) // Recall decay timer - return +/obj/structure/glowshroom/proc/Decay(amount) + myseed.adjust_endurance(-amount * endurance_decay_rate) + take_damage(amount) if (myseed.endurance <= MIN_PLANT_ENDURANCE) // Plant is gone qdel(src) @@ -250,3 +241,23 @@ I.desc = "Looks like this was \an [src] some time ago." qdel(src) return TRUE + +/obj/structure/glowshroom/extreme/Initialize(mapload, obj/item/seeds/newseed) + . = ..() + if(generation == 1) + myseed.potency = 100 + myseed.endurance = 100 + myseed.yield = 10 + +/obj/structure/glowshroom/medium/Initialize(mapload, obj/item/seeds/newseed) + . = ..() + if(generation == 1) + myseed.potency = 50 + myseed.endurance = 50 + myseed.yield = 5 + + + +#undef GLOWSHROOM_SPREAD_BASE_DIMINISH_FACTOR +#undef GLOWSHROOM_SPREAD_DIMINISH_FACTOR_PER_GLOWSHROOM +#undef GLOWSHROOM_BASE_INTEGRITY