/obj/structure/biohazard_blob anchored = TRUE var/datum/biohazard_blob_controller/our_controller var/blob_type /obj/structure/biohazard_blob/Destroy() our_controller = null playsound(src.loc, 'sound/effects/splat.ogg', 30, TRUE) return ..() /obj/structure/biohazard_blob/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) switch(damage_type) if(BRUTE) playsound(loc, 'sound/effects/attackblob.ogg', 100, TRUE) if(BURN) playsound(loc, 'sound/items/welder.ogg', 100, TRUE) /obj/structure/biohazard_blob/Initialize(mapload, passed_blob_type) . = ..() if(passed_blob_type) blob_type = passed_blob_type switch(blob_type) if(BIO_BLOB_TYPE_FUNGUS) color = "#A85" if(BIO_BLOB_TYPE_FIRE) color = "#C50" resistance_flags = FIRE_PROOF if(BIO_BLOB_TYPE_EMP) color = "#0B9" if(BIO_BLOB_TYPE_TOXIC) color = "#480" resistance_flags = UNACIDABLE | ACID_PROOF /obj/structure/biohazard_blob/structure density = TRUE /datum/looping_sound/core_heartbeat mid_length = 3 SECONDS mid_sounds = list('modular_skyrat/master_files/sound/effects/heart_beat_loop3.ogg'=1) volume = 20 #define CORE_RETALIATION_COOLDOWN 30 SECONDS /obj/structure/biohazard_blob/structure/core name = "glowing core" icon = 'modular_skyrat/modules/biohazard_blob/icons/blob_core.dmi' icon_state = "blob_core" layer = TABLE_LAYER light_range = 2 light_power = 1 light_color = LIGHT_COLOR_LAVA max_integrity = 450 var/datum/looping_sound/core_heartbeat/soundloop var/next_retaliation = 0 /obj/structure/biohazard_blob/structure/core/fungus blob_type = BIO_BLOB_TYPE_FUNGUS /obj/structure/biohazard_blob/structure/core/fire blob_type = BIO_BLOB_TYPE_FIRE /obj/structure/biohazard_blob/structure/core/emp blob_type = BIO_BLOB_TYPE_EMP /obj/structure/biohazard_blob/structure/core/toxic blob_type = BIO_BLOB_TYPE_TOXIC /obj/structure/biohazard_blob/structure/core/Initialize() if(!blob_type) blob_type = pick(ALL_BIO_BLOB_TYPES) . = ..() new /datum/biohazard_blob_controller(src, blob_type) soundloop = new(list(src), TRUE) update_overlays() /obj/structure/biohazard_blob/structure/core/Destroy() if(our_controller) our_controller.CoreDeath() our_controller.our_core = null soundloop.stop() QDEL_NULL(soundloop) return ..() /obj/structure/biohazard_blob/structure/core/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir) if(damage_amount > 10 && world.time > next_retaliation && prob(40)) if(our_controller) our_controller.CoreRetaliated() next_retaliation = world.time + CORE_RETALIATION_COOLDOWN //The core should try and seal the room its in, to prevent ranged cheese? //Add maybe a melee attack too? var/turf/my_turf = get_turf(src) switch(blob_type) if(BIO_BLOB_TYPE_FUNGUS) visible_message("The [src] emitts a cloud!") var/datum/reagents/R = new/datum/reagents(300) R.my_atom = src R.add_reagent(/datum/reagent/cordycepsspores, 50) var/datum/effect_system/smoke_spread/chem/smoke = new() smoke.set_up(R, 5) smoke.attach(src) smoke.start() if(BIO_BLOB_TYPE_FIRE) visible_message("The [src] puffs a cloud of flames!") my_turf.atmos_spawn_air("o2=20;plasma=20;TEMP=600") if(BIO_BLOB_TYPE_EMP) visible_message("The [src] sends out electrical discharges!") if(prob(50)) empulse(src, 3, 4) for(var/mob/living/M in get_hearers_in_view(3, my_turf)) if(M.flash_act(affect_silicon = 1)) M.Paralyze(20) M.Knockdown(20) M.soundbang_act(1, 20, 10, 5) else do_sparks(3, TRUE, src) tesla_zap(src, 4, 10000, ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE) if(BIO_BLOB_TYPE_TOXIC) visible_message("The [src] spews out foam!") var/datum/reagents/R = new/datum/reagents(300) R.my_atom = src R.add_reagent(/datum/reagent/toxin, 30) var/datum/effect_system/foam_spread/foam = new foam.set_up(40, my_turf, R) foam.start() return ..() /obj/structure/biohazard_blob/structure/core/update_overlays() . = ..() SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays) SSvis_overlays.add_vis_overlay(src, icon, "blob_core_overlay", layer, plane, dir, alpha) SSvis_overlays.add_vis_overlay(src, icon, "blob_core_overlay", 0, EMISSIVE_PLANE, dir, alpha) var/obj/effect/overlay/vis/overlay1 = managed_vis_overlays[1] var/obj/effect/overlay/vis/overlay2 = managed_vis_overlays[2] overlay1.appearance_flags = PIXEL_SCALE | TILE_BOUND | RESET_COLOR overlay2.appearance_flags = PIXEL_SCALE | TILE_BOUND | RESET_COLOR #undef CORE_RETALIATION_COOLDOWN /obj/structure/biohazard_blob/resin name = "mold" desc = "It looks like mold, but it seems alive." icon = 'modular_skyrat/modules/biohazard_blob/icons/blob_resin.dmi' icon_state = "blob_floor" density = FALSE plane = FLOOR_PLANE layer = ABOVE_NORMAL_TURF_LAYER max_integrity = 50 var/blooming = FALSE //Are we a floor resin? If not then we're a wall resin var/floor = TRUE /obj/structure/biohazard_blob/resin/Initialize(mapload, passed_blob_type) . = ..() switch(blob_type) if(BIO_BLOB_TYPE_FUNGUS) desc += " It looks like it's rotting." if(BIO_BLOB_TYPE_FIRE) desc += " It feels hot to the touch." if(BIO_BLOB_TYPE_EMP) desc += " You can notice small sparks travelling in the vines." if(BIO_BLOB_TYPE_TOXIC) desc += " It feels damp and smells of rat poison." /obj/structure/biohazard_blob/resin/update_overlays() . = ..() SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays) if(blooming) SSvis_overlays.add_vis_overlay(src, icon, "[icon_state]_overlay", layer, plane, dir, alpha) SSvis_overlays.add_vis_overlay(src, icon, "[icon_state]_overlay", 0, EMISSIVE_PLANE, dir, alpha) var/obj/effect/overlay/vis/overlay1 = managed_vis_overlays[1] var/obj/effect/overlay/vis/overlay2 = managed_vis_overlays[2] overlay1.appearance_flags = PIXEL_SCALE | TILE_BOUND | RESET_COLOR overlay2.appearance_flags = PIXEL_SCALE | TILE_BOUND | RESET_COLOR /obj/structure/biohazard_blob/resin/proc/CalcDir() var/direction = 16 var/turf/location = loc for(var/wallDir in GLOB.cardinals) var/turf/newTurf = get_step(location,wallDir) if(newTurf && newTurf.density) direction |= wallDir for(var/obj/structure/biohazard_blob/resin/tomato in location) if(tomato == src) continue if(tomato.floor) //special direction &= ~16 else direction &= ~tomato.dir var/list/dirList = list() for(var/i=1,i<=16,i <<= 1) if(direction & i) dirList += i if(dirList.len) var/newDir = pick(dirList) if(newDir == 16) setDir(pick(GLOB.cardinals)) else floor = FALSE setDir(newDir) switch(dir) //offset to make it be on the wall rather than on the floor if(NORTH) pixel_y = 32 if(SOUTH) pixel_y = -32 if(EAST) pixel_x = 32 if(WEST) pixel_x = -32 icon_state = "blob_wall" plane = GAME_PLANE layer = ABOVE_NORMAL_TURF_LAYER if(prob(7)) blooming = TRUE set_light(2, 1, LIGHT_COLOR_LAVA) update_overlays() /obj/structure/biohazard_blob/resin/Destroy() if(our_controller) our_controller.ActivateAdjacentResin(get_turf(src)) our_controller.all_resin -= src our_controller.active_resin -= src return ..() #define BLOB_BULB_ALPHA 100 /obj/structure/biohazard_blob/structure/bulb name = "empty bulb" density = TRUE icon = 'modular_skyrat/modules/biohazard_blob/icons/blob_bulb.dmi' icon_state = "blob_bulb_empty" density = FALSE layer = TABLE_LAYER light_range = 2 light_power = 1 light_color = LIGHT_COLOR_LAVA var/is_full = FALSE var/list/registered_turfs = list() max_integrity = 100 /obj/structure/biohazard_blob/structure/bulb/Initialize() . = ..() make_full() for(var/t in get_adjacent_open_turfs(src)) registered_turfs += t RegisterSignal(t, COMSIG_ATOM_ENTERED, .proc/proximity_trigger) /obj/structure/biohazard_blob/structure/bulb/proc/proximity_trigger(datum/source, atom/movable/AM) if(!isliving(AM)) return var/mob/living/L = AM if(!(MOLD_FACTION in L.faction)) discharge() /obj/structure/biohazard_blob/structure/bulb/proc/make_full() //Called by a timer, check if we exist if(QDELETED(src)) return is_full = TRUE name = "filled bulb" icon_state = "blob_bulb_full" set_light(2,1,LIGHT_COLOR_LAVA) density = TRUE update_overlays() /obj/structure/biohazard_blob/structure/bulb/proc/discharge() if(!is_full) return var/turf/T = get_turf(src) visible_message("The [src] ruptures!") switch(blob_type) if(BIO_BLOB_TYPE_FUNGUS) var/datum/reagents/R = new/datum/reagents(300) R.my_atom = src R.add_reagent(/datum/reagent/cordycepsspores, 50) var/datum/effect_system/smoke_spread/chem/smoke = new() smoke.set_up(R, 5) smoke.attach(src) smoke.start() if(BIO_BLOB_TYPE_FIRE) T.atmos_spawn_air("o2=20;plasma=20;TEMP=600") if(BIO_BLOB_TYPE_EMP) if(prob(50)) empulse(src, 3, 4) for(var/mob/living/M in get_hearers_in_view(3, T)) if(M.flash_act(affect_silicon = 1)) M.Paralyze(20) M.Knockdown(20) M.soundbang_act(1, 20, 10, 5) else tesla_zap(src, 4, 10000, ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE) if(BIO_BLOB_TYPE_TOXIC) var/datum/reagents/R = new/datum/reagents(300) R.my_atom = src R.add_reagent(/datum/reagent/toxin, 30) var/datum/effect_system/foam_spread/foam = new foam.set_up(40, T, R) foam.start() is_full = FALSE name = "empty bulb" icon_state = "blob_bulb_empty" playsound(src, 'sound/effects/bamf.ogg', 100, TRUE) set_light(0) update_overlays() density = FALSE addtimer(CALLBACK(src, .proc/make_full), 150 SECONDS, TIMER_UNIQUE|TIMER_NO_HASH_WAIT) /obj/structure/biohazard_blob/structure/bulb/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir) discharge() . = ..() /obj/structure/biohazard_blob/structure/bulb/Destroy() if(our_controller) our_controller.other_structures -= src for(var/t in registered_turfs) UnregisterSignal(t, COMSIG_ATOM_ENTERED) registered_turfs = null return ..() /obj/structure/biohazard_blob/structure/bulb/update_overlays() . = ..() SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays) if(is_full) SSvis_overlays.add_vis_overlay(src, icon, "blob_bulb_overlay", layer, plane, dir, BLOB_BULB_ALPHA) SSvis_overlays.add_vis_overlay(src, icon, "blob_bulb_overlay", 0, EMISSIVE_PLANE, dir, alpha) var/obj/effect/overlay/vis/overlay1 = managed_vis_overlays[1] var/obj/effect/overlay/vis/overlay2 = managed_vis_overlays[2] overlay1.appearance_flags = PIXEL_SCALE | TILE_BOUND | RESET_COLOR overlay2.appearance_flags = PIXEL_SCALE | TILE_BOUND | RESET_COLOR #undef BLOB_BULB_ALPHA /obj/structure/biohazard_blob/structure/wall name = "mold wall" desc = "Looks like some kind of thick resin." icon = 'icons/obj/smooth_structures/alien/resin_wall.dmi' icon_state = "resin_wall-0" base_icon_state = "resin_wall" opacity = TRUE smoothing_flags = SMOOTH_BITMASK smoothing_groups = list(SMOOTH_GROUP_ALIEN_RESIN) canSmoothWith = list(SMOOTH_GROUP_ALIEN_RESIN) max_integrity = 200 CanAtmosPass = ATMOS_PASS_DENSITY /obj/structure/biohazard_blob/wall/Destroy() if(our_controller) our_controller.ActivateAdjacentResin(get_turf(src)) our_controller.other_structures -= src return ..() /obj/structure/biohazard_blob/structure/spawner name = "hatchery" density = FALSE icon = 'modular_skyrat/modules/biohazard_blob/icons/blob_spawner.dmi' icon_state = "blob_spawner" density = FALSE layer = LOW_OBJ_LAYER max_integrity = 150 var/monster_types = list() var/max_spawns = 1 var/spawn_cooldown = 600 //In deciseconds /obj/structure/biohazard_blob/structure/spawner/Destroy() if(our_controller) our_controller.other_structures -= src return ..() /obj/structure/biohazard_blob/structure/spawner/Initialize() . = ..() switch(blob_type) if(BIO_BLOB_TYPE_FUNGUS) monster_types = list(/mob/living/simple_animal/hostile/biohazard_blob/diseased_rat) max_spawns = 2 spawn_cooldown = 500 if(BIO_BLOB_TYPE_FIRE) monster_types = list(/mob/living/simple_animal/hostile/biohazard_blob/oil_shambler) if(BIO_BLOB_TYPE_EMP) monster_types = list(/mob/living/simple_animal/hostile/biohazard_blob/electric_mosquito) max_spawns = 2 spawn_cooldown = 500 if(BIO_BLOB_TYPE_TOXIC) monster_types = list(/mob/living/simple_animal/hostile/poison/giant_spider) //Laziness AddComponent(/datum/component/spawner, monster_types, spawn_cooldown, list(MOLD_FACTION), "emerges from", max_spawns)