diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 02e71c0f08f..365e3ade3f6 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -704,15 +704,13 @@ /obj/structure/closet/crate/necropolis/bubblegum/New() ..() - var/loot = rand(1,4) + var/loot = rand(1,3) switch(loot) if(1) - new /obj/item/weapon/antag_spawner/slaughter_demon(src) - if(2) new /obj/item/mayhem(src) - if(3) + if(2) new /obj/item/blood_contract(src) - if(4) + if(3) new /obj/item/weapon/gun/magic/staff/spellblade(src) /obj/item/blood_contract diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm index f961094c4c9..b64463f3b7c 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm @@ -9,15 +9,15 @@ Bubblegum's footsteps are heralded by shaking booms, proving its tremendous size It acts as a melee creature, chasing down and attacking its target while also using different attacks to augment its power that increase as it takes damage. -It often charges, dealing massive damage to anything unfortunate enough to be standing where it's aiming. -Whenever it isn't chasing something down, it will sink into nearby blood pools (if possible) and springs out of the closest one to its target. -To make this possible, it sprays streams of blood at random. -From these blood pools Bubblegum may summon slaughterlings - weak, low-damage minions designed to impede the target's progress. +It tries to strike at its target through any bloodpools under them; if it fails to do that, it will spray blood and then attempt to warp to a bloodpool near the target. +If it fails to warp to a target, it may summon up to 6 slaughterlings from the blood around it. +If it does not summon all 6 slaughterlings, it will instead charge at its target, dealing massive damage to anything it hits and spraying a stream of blood. +At half health, it will either charge three times or warp, then charge, instead of doing a single charge. When Bubblegum dies, it leaves behind a chest that can contain three things: - 1. A slaughter demon spawner - 2. A bottle that, when activated, drives everyone nearby into a frenzy - 3. A contract that marks for death the chosen target + 1. A bottle that, when activated, drives everyone nearby into a frenzy + 2. A contract that marks for death the chosen target + 3. A spellblade that can slice off limbs at range Difficulty: Hard @@ -45,6 +45,7 @@ Difficulty: Hard pixel_x = -32 del_on_death = 1 loot = list(/obj/structure/closet/crate/necropolis/bubblegum) + blood_volume = BLOOD_VOLUME_MAXIMUM //BLEED FOR ME var/charging = 0 medal_type = MEDAL_PREFIX score_type = BUBBLEGUM_SCORE @@ -57,6 +58,12 @@ Difficulty: Hard desc = "You're not quite sure how a signal can be bloody." invisibility = 100 +/mob/living/simple_animal/hostile/megafauna/bubblegum/adjustBruteLoss(amount) + if(amount > 0 && prob(33)) + var/obj/effect/decal/cleanable/blood/B = new /obj/effect/decal/cleanable/blood(loc) + B.bloodiness = 20 + . = ..() + /mob/living/simple_animal/hostile/megafauna/bubblegum/Life() ..() move_to_delay = Clamp(round((health/maxHealth) * 10), 5, 10) @@ -67,18 +74,21 @@ Difficulty: Hard return ranged_cooldown = world.time + ranged_cooldown_time - blood_warp() - - if(prob(25)) + var/warped = FALSE + if(!try_bloodattack()) addtimer(src, "blood_spray", 0) + warped = blood_warp() + if(warped && prob(100 - anger_modifier)) + return - else if(prob(5+anger_modifier/2)) - slaughterlings() - else - if(health > maxHealth/2 && !client) + if(prob(90 - anger_modifier) || slaughterlings()) + if(health > maxHealth * 0.5 || client) addtimer(src, "charge", 0) else - addtimer(src, "triple_charge", 0) + if(prob(70) || warped) + addtimer(src, "triple_charge", 0) + else + addtimer(src, "warp_charge", 0) /mob/living/simple_animal/hostile/megafauna/bubblegum/New() @@ -109,20 +119,22 @@ Difficulty: Hard ..() /mob/living/simple_animal/hostile/megafauna/bubblegum/Move() - if(!stat) - playsound(src.loc, 'sound/effects/meteorimpact.ogg', 200, 1, 2, 1) if(charging) PoolOrNew(/obj/effect/overlay/temp/decoy/fading, list(loc,src)) DestroySurroundings() . = ..() + if(!stat && .) + playsound(src, 'sound/effects/meteorimpact.ogg', 200, 1, 2, 1) if(charging) DestroySurroundings() +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/warp_charge() + blood_warp() + charge() + /mob/living/simple_animal/hostile/megafauna/bubblegum/proc/triple_charge() charge() - sleep(10) charge() - sleep(10) charge() /mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge() @@ -139,6 +151,7 @@ Difficulty: Hard sleep(5) throw_at(T, get_dist(src, T), 1, src, 0) charging = 0 + try_bloodattack() Goto(target, move_to_delay, minimum_distance) @@ -166,17 +179,132 @@ Difficulty: Hard charging = 0 +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_mobs_on_blood() + var/list/targets = ListTargets() + . = list() + for(var/mob/living/L in targets) + var/list/bloodpool = get_pools(get_turf(L), 0) + if(bloodpool.len && !faction_check(L)) + . += L + +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/try_bloodattack() + var/list/targets = get_mobs_on_blood() + if(targets.len) + addtimer(src, "bloodattack", 0, FALSE, targets) + + return TRUE + return FALSE + +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodattack(list/targets) + var/mob/living/target_one = pick_n_take(targets) + var/turf/target_one_turf = get_turf(target_one) + var/mob/living/target_two + if(targets.len) + target_two = pick_n_take(targets) + var/turf/target_two_turf = get_turf(target_two) + if(target_two.stat != CONSCIOUS || prob(10)) + PoolOrNew(/obj/effect/overlay/temp/bubblegum_hands/rightpaw, target_two_turf) + PoolOrNew(/obj/effect/overlay/temp/bubblegum_hands/rightthumb, target_two_turf) + bloodgrab(target_two_turf) + else + PoolOrNew(/obj/effect/overlay/temp/bubblegum_hands/rightsmack, target_two_turf) + bloodsmack(target_two_turf) + + var/list/pools = get_pools(get_turf(target_one), 0) + if(pools.len) + target_one_turf = get_turf(target_one) + if(target_one.stat != CONSCIOUS || prob(10)) + PoolOrNew(/obj/effect/overlay/temp/bubblegum_hands/leftpaw, target_one_turf) + PoolOrNew(/obj/effect/overlay/temp/bubblegum_hands/leftthumb, target_one_turf) + bloodgrab(target_one_turf) + else + PoolOrNew(/obj/effect/overlay/temp/bubblegum_hands/leftsmack, target_one_turf) + bloodsmack(target_one_turf) + + if(!target_two && target_one) + pools = get_pools(get_turf(target_one), 0) + if(pools.len) + target_one_turf = get_turf(target_one) + if(target_one.stat != CONSCIOUS || prob(10)) + PoolOrNew(/obj/effect/overlay/temp/bubblegum_hands/rightpaw, target_one_turf) + PoolOrNew(/obj/effect/overlay/temp/bubblegum_hands/rightthumb, target_one_turf) + bloodgrab(target_one_turf) + else + PoolOrNew(/obj/effect/overlay/temp/bubblegum_hands/rightsmack, target_one_turf) + bloodsmack(target_one_turf) + +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodsmack(turf/T) + sleep(2.5) + for(var/mob/living/L in T) + if(!faction_check(L)) + L << "[src] rends you!" + playsound(T, attack_sound, 100, 1, -1) + var/limb_to_hit = L.get_bodypart(pick("head", "chest", "r_arm", "l_arm", "r_leg", "l_leg")) + L.apply_damage(25, BRUTE, limb_to_hit, L.run_armor_check(limb_to_hit, "melee", null, null, armour_penetration)) + sleep(3) + +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodgrab(turf/T) + sleep(6) + for(var/mob/living/L in T) + if(!faction_check(L)) + L << "[src] drags you through the blood!" + playsound(T, 'sound/magic/enter_blood.ogg', 100, 1, -1) + var/turf/targetturf = get_step(src, dir) + L.forceMove(targetturf) + playsound(targetturf, 'sound/magic/exit_blood.ogg', 100, 1, -1) + if(L.stat != CONSCIOUS) + addtimer(src, "devour", 2, FALSE, L) + sleep(1) + +/obj/effect/overlay/temp/bubblegum_hands + icon = 'icons/effects/bubblegum.dmi' + duration = 9 + +/obj/effect/overlay/temp/bubblegum_hands/rightthumb + icon_state = "rightthumbgrab" + +/obj/effect/overlay/temp/bubblegum_hands/leftthumb + icon_state = "leftthumbgrab" + +/obj/effect/overlay/temp/bubblegum_hands/rightpaw + icon_state = "rightpawgrab" + layer = BELOW_MOB_LAYER + +/obj/effect/overlay/temp/bubblegum_hands/leftpaw + icon_state = "leftpawgrab" + layer = BELOW_MOB_LAYER + +/obj/effect/overlay/temp/bubblegum_hands/rightsmack + icon_state = "rightsmack" + +/obj/effect/overlay/temp/bubblegum_hands/leftsmack + icon_state = "leftsmack" + /mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_warp() + if(Adjacent(target)) + return FALSE + var/list/can_jaunt = get_pools(get_turf(src), 1) + if(!can_jaunt.len) + return FALSE + + var/list/pools = get_pools(get_turf(target), 2) + var/list/pools_to_remove = get_pools(get_turf(target), 1) + pools -= pools_to_remove + if(!pools.len) + return FALSE + + var/obj/effect/overlay/temp/decoy/DA = PoolOrNew(/obj/effect/overlay/temp/decoy, list(loc,src)) + DA.color = "#FF0000" + var/oldtransform = DA.transform + DA.transform = matrix()*2 + animate(DA, alpha = 255, color = initial(DA.color), transform = oldtransform, time = 5) + sleep(5) + qdel(DA) + var/obj/effect/decal/cleanable/blood/found_bloodpool - var/list/pools = list() - var/can_jaunt = FALSE - for(var/obj/effect/decal/cleanable/blood/nearby in view(src,2)) - can_jaunt = TRUE - break - if(!can_jaunt) - return - for(var/obj/effect/decal/cleanable/blood/nearby in view(get_turf(target),2)) - pools += nearby + pools = get_pools(get_turf(target), 2) + pools_to_remove = get_pools(get_turf(target), 1) + pools -= pools_to_remove if(pools.len) shuffle(pools) found_bloodpool = pick(pools) @@ -186,35 +314,56 @@ Difficulty: Hard forceMove(get_turf(found_bloodpool)) playsound(get_turf(src), 'sound/magic/exit_blood.ogg', 100, 1, -1) visible_message("And springs back out!") + return TRUE + return FALSE +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_pools(turf/T, range) + . = list() + for(var/obj/effect/decal/cleanable/blood/nearby in view(T, range)) + . += nearby /mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_spray() visible_message("[src] sprays a stream of gore!") - var/turf/E = get_edge_target_turf(src, src.dir) - var/range = 10 + var/range = 6 + round(anger_modifier * 0.4) var/turf/previousturf = get_turf(src) - for(var/turf/J in getline(src,E)) - if(!range) - break + var/turf/J = previousturf + var/targetdir = get_dir(src, target) + if(target.loc == loc) + targetdir = dir + face_atom(target) + new /obj/effect/decal/cleanable/blood(J) + for(var/i in 1 to range) + J = get_step(previousturf, targetdir) PoolOrNew(/obj/effect/overlay/temp/dir_setting/bloodsplatter, list(previousturf, get_dir(previousturf, J))) - if(!previousturf.CanAtmosPass(J)) + playsound(previousturf,'sound/effects/splat.ogg', 100, 1, -1) + if(!J || !previousturf.CanAtmosPass(J)) break - playsound(J,'sound/effects/splat.ogg', 100, 1, -1) - new /obj/effect/decal/cleanable/blood(J) - range-- + var/obj/effect/decal/cleanable/blood/B = new /obj/effect/decal/cleanable/blood(J) + B.bloodiness = 0 previousturf = J sleep(1) /mob/living/simple_animal/hostile/megafauna/bubblegum/proc/slaughterlings() visible_message("[src] summons a shoal of slaughterlings!") - for(var/obj/effect/decal/cleanable/blood/H in range(src, 10)) - if(prob(25)) - new /mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/slaughter(H.loc) + var/max_amount = 6 + for(var/H in get_pools(get_turf(src), 1)) + if(!max_amount) + break + max_amount-- + var/obj/effect/decal/cleanable/blood/B = H + new /mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/slaughter(B.loc) + return max_amount /mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/slaughter name = "slaughterling" desc = "Though not yet strong enough to create a true physical form, it's nonetheless determined to murder you." - faction = list("mining") + density = 0 + faction = list("mining", "boss") weather_immunities = list("lava","ash") +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/slaughter/CanPass(atom/movable/mover, turf/target, height = 0) + if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum)) + return 1 + return 0 + #undef MEDAL_PREFIX \ No newline at end of file diff --git a/icons/effects/bubblegum.dmi b/icons/effects/bubblegum.dmi new file mode 100644 index 00000000000..a53dd7d563a Binary files /dev/null and b/icons/effects/bubblegum.dmi differ