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)