diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm
index af366683570..b177d7a7aaf 100644
--- a/code/modules/flufftext/Hallucination.dm
+++ b/code/modules/flufftext/Hallucination.dm
@@ -269,51 +269,59 @@ Gunshots/explosions/opening doors/less rare audio (done)
px = -32
/obj/effect/hallucination/oh_yeah
- var/turf/simulated/wall/wall
- var/obj/effect/hallucination/simple/bubblegum/bubblegum = null
+ var/obj/effect/hallucination/simple/bubblegum/bubblegum
var/image/fakebroken
var/image/fakerune
-/obj/effect/hallucination/oh_yeah/New(loc, mob/living/carbon/T)
+/obj/effect/hallucination/oh_yeah/New(loc, mob/living/carbon/C)
+ set waitfor = FALSE
..()
- target = T
- for(var/turf/simulated/wall/W in range(7,target))
+ target = C
+ var/turf/simulated/wall/wall
+ for(var/turf/simulated/wall/W in range(7, target))
wall = W
break
- if(wall)
- fakebroken = image('icons/turf/floors.dmi', wall, "plating", layer = TURF_LAYER)
- var/turf/landing = get_turf(target)
- var/turf/landing_image_turf = get_step(landing, SOUTHWEST) //the icon is 3x3
- fakerune = image('icons/effects/96x96.dmi', landing_image_turf, "landing", layer = ABOVE_OPEN_TURF_LAYER)
- fakebroken.override = TRUE
- if(target.client)
- target.client.images |= fakebroken
- target.client.images |= fakerune
- target.playsound_local(wall,'sound/effects/meteorimpact.ogg', 150, 1)
- bubblegum = new(wall, target)
- sleep(10) //ominous wait
- var/charged = FALSE //only get hit once
- while(get_turf(bubblegum) != landing && target)
- bubblegum.forceMove(get_step_towards(bubblegum, landing))
- bubblegum.setDir(get_dir(bubblegum, landing))
- target.playsound_local(get_turf(bubblegum), 'sound/effects/meteorimpact.ogg', 150, 1)
- shake_camera(target, 2, 1)
- if(bubblegum.Adjacent(target) && !charged)
- charged = TRUE
- target.Weaken(4)
- target.adjustStaminaLoss(40)
- step_away(target, bubblegum)
- shake_camera(target, 4, 3)
- target.visible_message("[target] jumps backwards, falling on the ground!","[bubblegum] slams into you!")
- sleep(2)
- sleep(30)
- qdel(bubblegum)
+ if(!wall)
+ qdel(src)
+ return
+
+ fakebroken = image('icons/turf/floors.dmi', wall, "plating", layer = TURF_LAYER)
+ var/turf/landing = get_turf(target)
+ var/turf/landing_image_turf = get_step(landing, SOUTHWEST) //the icon is 3x3
+ fakerune = image('icons/effects/96x96.dmi', landing_image_turf, "landing", layer = ABOVE_OPEN_TURF_LAYER)
+ fakebroken.override = TRUE
+ if(target.client)
+ target.client.images |= fakebroken
+ target.client.images |= fakerune
+ target.playsound_local(wall,'sound/effects/meteorimpact.ogg', 150, 1)
+ bubblegum = new(wall, target)
+ addtimer(CALLBACK(src, .proc/bubble_attack, landing), 10)
+
+/obj/effect/hallucination/oh_yeah/proc/bubble_attack(turf/landing)
+ var/charged = FALSE //only get hit once
+ while(get_turf(bubblegum) != landing && target && target.stat != DEAD)
+ bubblegum.forceMove(get_step_towards(bubblegum, landing))
+ bubblegum.setDir(get_dir(bubblegum, landing))
+ target.playsound_local(get_turf(bubblegum), 'sound/effects/meteorimpact.ogg', 150, 1)
+ shake_camera(target, 2, 1)
+ if(bubblegum.Adjacent(target) && !charged)
+ charged = TRUE
+ target.Weaken(4)
+ target.adjustStaminaLoss(40)
+ step_away(target, bubblegum)
+ shake_camera(target, 4, 3)
+ target.visible_message("[target] jumps backwards, falling on the ground!", "[bubblegum] slams into you!")
+ sleep(2)
+ sleep(30)
qdel(src)
/obj/effect/hallucination/oh_yeah/Destroy()
if(target.client)
target.client.images.Remove(fakebroken)
target.client.images.Remove(fakerune)
+ QDEL_NULL(fakebroken)
+ QDEL_NULL(fakerune)
+ QDEL_NULL(bubblegum)
return ..()
/obj/effect/hallucination/singularity_scare
diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm
index 762df8d3b8b..71a3ae3e87c 100644
--- a/code/modules/mob/living/carbon/human/human_damage.dm
+++ b/code/modules/mob/living/carbon/human/human_damage.dm
@@ -328,7 +328,7 @@ This function restores all organs.
return 0
-/mob/living/carbon/human/proc/get_organ(zone)
+/mob/living/carbon/human/get_organ(zone)
if(!zone)
zone = "chest"
if(zone in list("eyes", "mouth"))
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 43274952362..66799ffc6c6 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
@@ -1,3 +1,8 @@
+#define BUBBLEGUM_SMASH (health <= maxHealth * 0.5) // angery
+#define BUBBLEGUM_CAN_ENRAGE (enrage_till + (enrage_time * 2) <= world.time)
+#define BUBBLEGUM_IS_ENRAGED (enrage_till > world.time)
+
+
/*
BUBBLEGUM
@@ -5,14 +10,16 @@ BUBBLEGUM
Bubblegum spawns randomly wherever a lavaland creature is able to spawn. It is the most powerful slaughter demon in existence.
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 acts as a melee creature, chasing down and attacking its target while also using different attacks to augment its power
-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.
+It leaves blood trails behind wherever it goes, its clones do as well.
+It tries to strike at its target through any bloodpools under them; if it fails to do that.
+If it does warp it will enter an enraged state, becoming immune to all projectiles, becoming much faster, and dealing damage and knockback to anything that gets in the cloud around it.
+It may summon clones charging from all sides, one of these charges being bubblegum himself.
+It can charge at its target, and also heavily damaging anything directly hit in the charge.
+If at half health it will start to charge from all sides with clones.
-When Bubblegum dies, it leaves behind a chest that can contain three things:
+When Bubblegum dies, it leaves behind a H.E.C.K. mining suit as well as a chest that can contain three things:
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
@@ -37,19 +44,31 @@ Difficulty: Hard
armour_penetration = 40
melee_damage_lower = 40
melee_damage_upper = 40
- speed = 1
- move_to_delay = 10
- ranged = 1
+ speed = 5
+ move_to_delay = 5
+ retreat_distance = 5
+ minimum_distance = 5
+ rapid_melee = 8 // every 1/4 second
+ melee_queue_distance = 20 // as far as possible really, need this because of blood warp
+ ranged = TRUE
pixel_x = -32
- del_on_death = 1
+ del_on_death = TRUE
crusher_loot = list(/obj/structure/closet/crate/necropolis/bubblegum/crusher)
loot = list(/obj/structure/closet/crate/necropolis/bubblegum)
- var/charging = 0
+ blood_volume = BLOOD_VOLUME_MAXIMUM //BLEED FOR ME
+ var/charging = FALSE
+ var/enrage_till = 0
+ var/enrage_time = 70
+ var/revving_charge = FALSE
internal_type = /obj/item/gps/internal/bubblegum
medal_type = BOSS_MEDAL_BUBBLEGUM
score_type = BUBBLEGUM_SCORE
deathmessage = "sinks into a pool of blood, fleeing the battle. You've won, for now... "
death_sound = 'sound/misc/enter_blood.ogg'
+ attack_action_types = list(/datum/action/innate/megafauna_attack/triple_charge,
+ /datum/action/innate/megafauna_attack/hallucination_charge,
+ /datum/action/innate/megafauna_attack/hallucination_surround,
+ /datum/action/innate/megafauna_attack/blood_warp)
/obj/item/gps/internal/bubblegum
icon_state = null
@@ -57,54 +76,6 @@ 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(25))
- var/obj/effect/decal/cleanable/blood/gibs/bubblegum/B = new /obj/effect/decal/cleanable/blood/gibs/bubblegum(loc)
- if(prob(40))
- step(B, pick(cardinal))
- else
- B.dir = pick(cardinal)
- . = ..()
-
-/obj/effect/decal/cleanable/blood/gibs/bubblegum
- name = "thick blood"
- desc = "Thick, splattered blood."
- random_icon_states = list("gib3", "gib5", "gib6")
- amount = 20
-
-/obj/effect/decal/cleanable/blood/gibs/bubblegum/can_bloodcrawl_in()
- return TRUE
-
-/mob/living/simple_animal/hostile/megafauna/bubblegum/Life(seconds, times_fired)
- ..()
- move_to_delay = Clamp((health/maxHealth) * 10, 5, 10)
-
-/mob/living/simple_animal/hostile/megafauna/bubblegum/OpenFire()
- anger_modifier = Clamp(((maxHealth - health)/60),0,20)
- if(charging)
- return
- ranged_cooldown = world.time + ranged_cooldown_time
-
- var/warped = FALSE
- if(!try_bloodattack())
- spawn(0)
- blood_spray()
- warped = blood_warp()
- if(warped && prob(100 - anger_modifier))
- return
-
- if(prob(90 - anger_modifier) || slaughterlings())
- if(health > maxHealth * 0.5)
- spawn(0)
- charge()
- else
- if(prob(70) || warped)
- spawn(0)
- triple_charge()
- else
- spawn(0)
- warp_charge()
-
/mob/living/simple_animal/hostile/megafauna/bubblegum/Initialize(mapload)
. = ..()
if(true_spawn)
@@ -112,88 +83,118 @@ Difficulty: Hard
if(B != src)
qdel(src) //There can be only one
return
- var/obj/effect/proc_holder/spell/bloodcrawl/bloodspell = new
- AddSpell(bloodspell)
- if(istype(loc, /obj/effect/dummy/slaughter))
- bloodspell.phased = 1
-/mob/living/simple_animal/hostile/megafauna/bubblegum/do_attack_animation(atom/A, visual_effect_icon, used_item, no_effect, end_pixel_y)
- if(!charging)
- ..()
+/datum/action/innate/megafauna_attack/triple_charge
+ name = "Triple Charge"
+ icon_icon = 'icons/mob/actions/actions.dmi'
+ button_icon_state = "sniper_zoom"
+ chosen_message = "You are now triple charging at the target you click on."
+ chosen_attack_num = 1
-/mob/living/simple_animal/hostile/megafauna/bubblegum/AttackingTarget()
- if(!charging)
- return ..()
+/datum/action/innate/megafauna_attack/hallucination_charge
+ name = "Hallucination Charge"
+ icon_icon = 'icons/effects/bubblegum.dmi'
+ button_icon_state = "smack ya one"
+ chosen_message = "You are now charging with hallucinations at the target you click on."
+ chosen_attack_num = 2
-/mob/living/simple_animal/hostile/megafauna/bubblegum/Goto(target, delay, minimum_distance)
- if(!charging)
- ..()
+/datum/action/innate/megafauna_attack/hallucination_surround
+ name = "Surround Target"
+ icon_icon = 'icons/turf/walls/wall.dmi'
+ button_icon_state = "wall"
+ chosen_message = "You are now surrounding the target you click on with hallucinations."
+ chosen_attack_num = 3
-/mob/living/simple_animal/hostile/megafauna/bubblegum/MoveToTarget(list/possible_targets)
- if(!charging)
- ..()
+/datum/action/innate/megafauna_attack/blood_warp
+ name = "Blood Warp"
+ icon_icon = 'icons/effects/blood.dmi'
+ button_icon_state = "floor1"
+ chosen_message = "You are now warping to blood around your clicked position."
+ chosen_attack_num = 4
-/mob/living/simple_animal/hostile/megafauna/bubblegum/Move()
+/mob/living/simple_animal/hostile/megafauna/bubblegum/OpenFire()
if(charging)
- new /obj/effect/temp_visual/decoy/fading(loc, src)
- DestroySurroundings()
- . = ..()
- if(!stat && .)
- playsound(src, 'sound/effects/meteorimpact.ogg', 200, 1, 2, 1)
- if(charging)
- DestroySurroundings()
+ return
-/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/warp_charge()
- blood_warp()
- charge()
+ anger_modifier = Clamp(((maxHealth - health)/60),0,20)
+ enrage_time = initial(enrage_time) * Clamp(anger_modifier / 20, 0.5, 1)
+ ranged_cooldown = world.time + 50
+
+ if(client)
+ switch(chosen_attack)
+ if(1)
+ triple_charge()
+ if(2)
+ hallucination_charge()
+ if(3)
+ surround_with_hallucinations()
+ if(4)
+ blood_warp()
+ return
+
+ if(!try_bloodattack() || prob(25 + anger_modifier))
+ blood_warp()
+
+ if(!BUBBLEGUM_SMASH)
+ triple_charge()
+ else
+ if(prob(50 + anger_modifier))
+ hallucination_charge()
+ else
+ surround_with_hallucinations()
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/triple_charge()
- charge()
- charge()
- charge()
+ charge(delay = 6)
+ charge(delay = 4)
+ charge(delay = 2)
+ SetRecoveryTime(15)
-/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge()
- var/turf/T = get_turf(target)
- if(!T || T == loc)
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/hallucination_charge()
+ if(!BUBBLEGUM_SMASH || prob(33))
+ hallucination_charge_around(times = 6, delay = 8)
+ SetRecoveryTime(10)
+ else
+ hallucination_charge_around(times = 4, delay = 9)
+ hallucination_charge_around(times = 4, delay = 8)
+ hallucination_charge_around(times = 4, delay = 7)
+ triple_charge()
+ SetRecoveryTime(20)
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/surround_with_hallucinations()
+ for(var/i = 1 to 5)
+ INVOKE_ASYNC(src, .proc/hallucination_charge_around, 2, 8, 2, 0, 4)
+ if(ismob(target))
+ charge(delay = 6)
+ else
+ SLEEP_CHECK_DEATH(6)
+ SetRecoveryTime(20)
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge(atom/chargeat = target, delay = 3, chargepast = 2)
+ if(!chargeat)
return
- new /obj/effect/temp_visual/dragon_swoop(T)
- charging = 1
+ var/chargeturf = get_turf(chargeat)
+ if(!chargeturf)
+ return
+ var/dir = get_dir(src, chargeturf)
+ var/turf/T = get_ranged_target_turf(chargeturf, dir, chargepast)
+ if(!T)
+ return
+ new /obj/effect/temp_visual/dragon_swoop/bubblegum(T)
+ charging = TRUE
+ revving_charge = TRUE
DestroySurroundings()
walk(src, 0)
- dir = get_dir(src, T)
- var/obj/effect/temp_visual/decoy/D = new /obj/effect/temp_visual/decoy(loc, src)
- animate(D, alpha = 0, color = "#FF0000", transform = matrix()*2, time = 5)
- sleep(5)
- throw_at(T, get_dist(src, T), 1, src, 0)
- charging = 0
+ setDir(dir)
+ var/obj/effect/temp_visual/decoy/D = new /obj/effect/temp_visual/decoy(loc,src)
+ animate(D, alpha = 0, color = "#FF0000", transform = matrix()*2, time = 3)
+ SLEEP_CHECK_DEATH(delay)
+ revving_charge = FALSE
+ var/movespeed = 0.7
+ walk_towards(src, T, movespeed)
+ SLEEP_CHECK_DEATH(get_dist(src, T) * movespeed)
+ walk(src, 0) // cancel the movement
try_bloodattack()
- if(target)
- Goto(target, move_to_delay, minimum_distance)
-
-
-/mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A)
- if(charging)
- if(isturf(A) || isobj(A) && A.density)
- A.ex_act(2)
- DestroySurroundings()
- ..()
-
-/mob/living/simple_animal/hostile/megafauna/bubblegum/throw_impact(atom/A)
- if(!charging)
- return ..()
-
- else if(isliving(A))
- var/mob/living/L = A
- L.visible_message("[src] slams into [L]!", "[src] slams into you!")
- L.apply_damage(40, BRUTE)
- playsound(get_turf(L), 'sound/effects/meteorimpact.ogg', 100, 1)
- shake_camera(L, 4, 3)
- shake_camera(src, 2, 3)
- var/throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(L, src)))
- L.throw_at(throwtarget, 3)
-
- charging = 0
-
+ charging = FALSE
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_mobs_on_blood()
var/list/targets = ListTargets()
@@ -206,9 +207,7 @@ Difficulty: Hard
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/try_bloodattack()
var/list/targets = get_mobs_on_blood()
if(targets.len)
- spawn(0)
- bloodattack(targets, prob(50))
-
+ INVOKE_ASYNC(src, .proc/bloodattack, targets, prob(50))
return TRUE
return FALSE
@@ -249,14 +248,14 @@ Difficulty: Hard
new /obj/effect/temp_visual/bubblegum_hands/rightsmack(T)
else
new /obj/effect/temp_visual/bubblegum_hands/leftsmack(T)
- sleep(2.5)
+ SLEEP_CHECK_DEATH(4)
for(var/mob/living/L in T)
if(!faction_check_mob(L))
to_chat(L, "[src] rends you!")
- playsound(T, attack_sound, 100, 1, -1)
- var/limb_to_hit = 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)
+ playsound(T, attack_sound, 100, TRUE, -1)
+ var/limb_to_hit = L.get_organ(pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG))
+ L.apply_damage(10, BRUTE, limb_to_hit, L.run_armor_check(limb_to_hit, "melee", null, null, armour_penetration))
+ SLEEP_CHECK_DEATH(3)
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodgrab(turf/T, handedness)
if(handedness)
@@ -265,18 +264,221 @@ Difficulty: Hard
else
new /obj/effect/temp_visual/bubblegum_hands/leftpaw(T)
new /obj/effect/temp_visual/bubblegum_hands/leftthumb(T)
- sleep(6)
+ SLEEP_CHECK_DEATH(6)
for(var/mob/living/L in T)
if(!faction_check_mob(L))
- to_chat(L, "[src] drags you through the blood!")
- playsound(T, 'sound/misc/enter_blood.ogg', 100, 1, -1)
- var/turf/targetturf = get_step(src, dir)
- L.forceMove(targetturf)
- playsound(targetturf, 'sound/misc/exit_blood.ogg', 100, 1, -1)
if(L.stat != CONSCIOUS)
- spawn(2)
- devour(L)
- sleep(1)
+ to_chat(L, "[src] drags you through the blood!")
+ playsound(T, 'sound/misc/enter_blood.ogg', 100, TRUE, -1)
+ var/turf/targetturf = get_step(src, dir)
+ L.forceMove(targetturf)
+ playsound(targetturf, 'sound/misc/exit_blood.ogg', 100, TRUE, -1)
+ addtimer(CALLBACK(src, .proc/devour, L), 2)
+ SLEEP_CHECK_DEATH(1)
+
+/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), 5)
+ var/list/pools_to_remove = get_pools(get_turf(target), 4)
+ pools -= pools_to_remove
+ if(!pools.len)
+ return FALSE
+
+ var/obj/effect/temp_visual/decoy/DA = new /obj/effect/temp_visual/decoy(loc,src)
+ DA.color = "#FF0000"
+ var/oldtransform = DA.transform
+ DA.transform = matrix()*2
+ animate(DA, alpha = 255, color = initial(DA.color), transform = oldtransform, time = 3)
+ SLEEP_CHECK_DEATH(3)
+ qdel(DA)
+
+ var/obj/effect/decal/cleanable/blood/found_bloodpool
+ pools = get_pools(get_turf(target), 5)
+ pools_to_remove = get_pools(get_turf(target), 4)
+ pools -= pools_to_remove
+ if(pools.len)
+ shuffle_inplace(pools)
+ found_bloodpool = pick(pools)
+ if(found_bloodpool)
+ visible_message("[src] sinks into the blood...")
+ playsound(get_turf(src), 'sound/misc/enter_blood.ogg', 100, TRUE, -1)
+ forceMove(get_turf(found_bloodpool))
+ playsound(get_turf(src), 'sound/misc/exit_blood.ogg', 100, TRUE, -1)
+ visible_message("And springs back out!")
+ blood_enrage()
+ return TRUE
+ return FALSE
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/be_aggressive()
+ if(BUBBLEGUM_IS_ENRAGED)
+ return TRUE
+ if(isliving(target))
+ var/mob/living/livingtarget = target
+ return (livingtarget.stat != CONSCIOUS || livingtarget.lying)
+ return FALSE
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_retreat_distance()
+ return (be_aggressive() ? null : initial(retreat_distance))
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_minimum_distance()
+ return (be_aggressive() ? 1 : initial(minimum_distance))
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/update_approach()
+ retreat_distance = get_retreat_distance()
+ minimum_distance = get_minimum_distance()
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_enrage()
+ if(!BUBBLEGUM_CAN_ENRAGE)
+ return FALSE
+ enrage_till = world.time + enrage_time
+ update_approach()
+ change_move_delay(3.75)
+ var/newcolor = rgb(149, 10, 10)
+ add_atom_colour(newcolor, TEMPORARY_COLOUR_PRIORITY)
+ var/datum/callback/cb = CALLBACK(src, .proc/blood_enrage_end)
+ addtimer(cb, enrage_time)
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_enrage_end(newcolor = rgb(149, 10, 10))
+ update_approach()
+ change_move_delay()
+ remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, newcolor)
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/change_move_delay(newmove = initial(move_to_delay))
+ move_to_delay = newmove
+ speed = move_to_delay
+ handle_automated_action() // need to recheck movement otherwise move_to_delay won't update until the next checking aka will be wrong speed for a bit
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_pools(turf/T, range)
+ . = list()
+ for(var/obj/effect/decal/cleanable/nearby in view(T, range))
+ if(nearby.can_bloodcrawl_in())
+ . += nearby
+
+/obj/effect/decal/cleanable/blood/bubblegum
+ bloodiness = 0
+
+/obj/effect/decal/cleanable/blood/bubblegum/can_bloodcrawl_in()
+ return TRUE
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/hallucination_charge_around(times = 4, delay = 6, chargepast = 0, useoriginal = 1, radius)
+ var/startingangle = rand(1, 360)
+ if(!target)
+ return
+ var/turf/chargeat = get_turf(target)
+ var/srcplaced = FALSE
+ if(!radius)
+ radius = times
+ for(var/i = 1 to times)
+ var/ang = (startingangle + 360/times * i)
+ if(!chargeat)
+ return
+ var/turf/place = locate(chargeat.x + cos(ang) * radius, chargeat.y + sin(ang) * radius, chargeat.z)
+ if(!place)
+ continue
+ if(!nest || nest && nest.parent && get_dist(nest.parent, place) <= nest_range)
+ if(!srcplaced && useoriginal)
+ forceMove(place)
+ srcplaced = TRUE
+ continue
+ var/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/B = new /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination(loc)
+ B.forceMove(place)
+ INVOKE_ASYNC(B, .proc/charge, chargeat, delay, chargepast)
+ if(useoriginal)
+ charge(chargeat, delay, chargepast)
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/adjustBruteLoss(amount, updating_health = TRUE)
+ . = ..()
+ if(. > 0 && prob(25))
+ var/obj/effect/decal/cleanable/blood/gibs/bubblegum/B = new /obj/effect/decal/cleanable/blood/gibs/bubblegum(loc)
+ if(prob(40))
+ step(B, pick(cardinal))
+ else
+ B.setDir(pick(cardinal))
+
+/obj/effect/decal/cleanable/blood/gibs/bubblegum
+ name = "thick blood"
+ desc = "Thick, splattered blood."
+ random_icon_states = list("gib3", "gib5", "gib6")
+ bloodiness = 20
+
+/obj/effect/decal/cleanable/blood/gibs/bubblegum/can_bloodcrawl_in()
+ return TRUE
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/do_attack_animation(atom/A, visual_effect_icon)
+ if(!charging)
+ ..()
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/AttackingTarget()
+ if(!charging)
+ . = ..()
+ if(.)
+ recovery_time = world.time + 20 // can only attack melee once every 2 seconds but rapid_melee gives higher priority
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/bullet_act(obj/item/projectile/P)
+ if(BUBBLEGUM_IS_ENRAGED)
+ visible_message("[src] deflects the projectile; [p_they()] can't be hit with ranged weapons while enraged!", "You deflect the projectile!")
+ playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 300, TRUE)
+ return
+ ..()
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/ex_act(severity, target)
+ if(severity >= EXPLODE_LIGHT)
+ return
+ severity = EXPLODE_LIGHT // puny mortals
+ return ..()
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/CanPass(atom/movable/mover, turf/target)
+ if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination))
+ return TRUE
+ return ..()
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/Goto(target, delay, minimum_distance)
+ if(!charging)
+ ..()
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/MoveToTarget(list/possible_targets)
+ if(!charging)
+ ..()
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/Move()
+ update_approach()
+ if(revving_charge)
+ return FALSE
+ if(charging)
+ new /obj/effect/temp_visual/decoy/fading(loc,src)
+ DestroySurroundings()
+ ..()
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/Moved(atom/OldLoc, Dir, Forced = FALSE)
+ if(Dir)
+ new /obj/effect/decal/cleanable/blood/bubblegum(loc)
+ if(charging)
+ DestroySurroundings()
+ playsound(src, 'sound/effects/meteorimpact.ogg', 200, TRUE, 2, TRUE)
+ return ..()
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A)
+ if(charging)
+ if(isturf(A) || isobj(A) && A.density)
+ A.ex_act(EXPLODE_HEAVY)
+ DestroySurroundings()
+ if(isliving(A))
+ var/mob/living/L = A
+ L.visible_message("[src] slams into [L]!", "[src] tramples you into the ground!")
+ forceMove(get_turf(L))
+ L.apply_damage(istype(src, /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination) ? 15 : 30, BRUTE)
+ playsound(get_turf(L), 'sound/effects/meteorimpact.ogg', 100, TRUE)
+ shake_camera(L, 4, 3)
+ shake_camera(src, 2, 3)
+ ..()
+
+/obj/effect/temp_visual/dragon_swoop/bubblegum
+ duration = 10
/obj/effect/temp_visual/bubblegum_hands
icon = 'icons/effects/bubblegum.dmi'
@@ -290,11 +492,11 @@ Difficulty: Hard
/obj/effect/temp_visual/bubblegum_hands/rightpaw
icon_state = "rightpawgrab"
- layer = MOB_LAYER - 0.1
+ layer = BELOW_MOB_LAYER
/obj/effect/temp_visual/bubblegum_hands/leftpaw
icon_state = "leftpawgrab"
- layer = MOB_LAYER - 0.1
+ layer = BELOW_MOB_LAYER
/obj/effect/temp_visual/bubblegum_hands/rightsmack
icon_state = "rightsmack"
@@ -302,94 +504,48 @@ Difficulty: Hard
/obj/effect/temp_visual/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
+/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination
+ name = "bubblegum's hallucination"
+ desc = "Is that really just a hallucination?"
+ health = 1
+ maxHealth = 1
+ alpha = 127.5
+ crusher_loot = null
+ loot = null
+ medal_type = null
+ score_type = null
+ deathmessage = "Explodes into a pool of blood!"
+ death_sound = 'sound/effects/splat.ogg'
+ true_spawn = 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
+/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Initialize(mapload)
+ . = ..()
+ toggle_ai(AI_OFF)
- var/obj/effect/temp_visual/decoy/DA = new /obj/effect/temp_visual/decoy(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)
+/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/charge(atom/chargeat = target, delay = 3, chargepast = 2)
+ ..()
+ qdel(src)
- var/obj/effect/decal/cleanable/blood/found_bloodpool
- 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)
- if(found_bloodpool)
- visible_message("[src] sinks into the blood...")
- playsound(get_turf(src), 'sound/misc/enter_blood.ogg', 100, 1, -1)
- forceMove(get_turf(found_bloodpool))
- playsound(get_turf(src), 'sound/misc/exit_blood.ogg', 100, 1, -1)
- visible_message("And springs back out!")
+/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Destroy()
+ new /obj/effect/decal/cleanable/blood(get_turf(src))
+ . = ..()
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/CanPass(atom/movable/mover, turf/target)
+ if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum)) // hallucinations should not be stopping bubblegum or eachother
return TRUE
- return FALSE
+ return ..()
-/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_pools(turf/T, range)
- . = list()
- for(var/obj/effect/decal/cleanable/nearby in view(T, range))
- if(nearby.can_bloodcrawl_in())
- . += nearby
+/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Life()
+ return
-/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_spray()
- visible_message("[src] sprays a stream of gore!")
- var/range = 6 + round(anger_modifier * 0.4)
- var/turf/previousturf = get_turf(src)
- 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/bubblegum(J)
- for(var/i in 1 to range)
- J = get_step(previousturf, targetdir)
- new /obj/effect/temp_visual/dir_setting/bloodsplatter(previousturf, get_dir(previousturf, J))
- playsound(previousturf,'sound/effects/splat.ogg', 100, 1, -1)
- if(!J || !previousturf.CanAtmosPass(J))
- break
- new /obj/effect/decal/cleanable/blood/bubblegum(J)
- previousturf = J
- sleep(1)
+/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/adjustBruteLoss(amount, updating_health = TRUE)
+ return
-/obj/effect/decal/cleanable/blood/bubblegum
- amount = 0
+/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/OpenFire()
+ return
-/obj/effect/decal/cleanable/blood/bubblegum/can_bloodcrawl_in()
- return TRUE
+/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/AttackingTarget()
+ return
-/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/slaughterlings()
- visible_message("[src] summons a shoal of slaughterlings!")
- 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."
- 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
+/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/try_bloodattack()
+ return
\ No newline at end of file
diff --git a/code/modules/surgery/organs/helpers.dm b/code/modules/surgery/organs/helpers.dm
index fb1167edb01..91bba8d4a1b 100644
--- a/code/modules/surgery/organs/helpers.dm
+++ b/code/modules/surgery/organs/helpers.dm
@@ -10,6 +10,9 @@
/mob/proc/get_int_organ_tag(tag) //is it a brain, is it a brain_tumor?
return
+/mob/living/proc/get_organ(zone)
+ return
+
/mob/living/carbon/get_int_organ(typepath)
return (locate(typepath) in internal_organs)