diff --git a/code/__HELPERS/honkerblast.dm b/code/__HELPERS/honkerblast.dm new file mode 100644 index 00000000000..bd05d07417a --- /dev/null +++ b/code/__HELPERS/honkerblast.dm @@ -0,0 +1,47 @@ +///Unleashes a honkerblast similar to the honkmech weapon, but with more granular control. +/proc/honkerblast(atom/origin, light_range = 1, medium_range = 0, heavy_range = 0) + var/origin_turf = get_turf(origin) + var/list/lightly_honked = list() + var/list/properly_honked = list() + var/list/severely_honked = list() + + playsound(origin_turf, 'sound/items/airhorn.ogg', 100, TRUE) + + for(var/mob/living/carbon/victim as anything in hearers(max(light_range, medium_range, heavy_range), origin_turf)) + if(!victim.can_hear()) + continue + var/distance = get_dist(origin_turf, victim.loc) + if(distance <= heavy_range) + severely_honked += victim + else if(distance <= medium_range) + properly_honked += victim + else if(distance <= light_range) + lightly_honked += victim + + for(var/mob/living/carbon/victim in severely_honked) + victim.Unconscious(40) + victim.Stun(100) + victim.stuttering += 15 + victim.Jitter(500) + var/obj/item/organ/ears/ears = victim.getorganslot(ORGAN_SLOT_EARS) + ears?.adjustEarDamage(10, 15) + to_chat(victim, "HONK") + var/obj/item/clothing/shoes/victim_shoes = victim.get_item_by_slot(ITEM_SLOT_FEET) + if(!victim_shoes?.can_be_tied) + continue + victim_shoes.adjust_laces(SHOES_KNOTTED) + + for(var/mob/living/carbon/victim in properly_honked) + victim.Paralyze(20) + victim.Stun(50) + victim.Jitter(250) + var/obj/item/organ/ears/ears = victim.getorganslot(ORGAN_SLOT_EARS) + ears?.adjustEarDamage(7, 10) + to_chat(victim, "HONK") + + for(var/mob/living/carbon/victim in lightly_honked) + victim.Knockdown(20) + victim.Jitter(100) + var/obj/item/organ/ears/ears = victim.getorganslot(ORGAN_SLOT_EARS) + ears?.adjustEarDamage(4, 5) + to_chat(victim, "HONK") diff --git a/code/modules/hydroponics/grown/banana.dm b/code/modules/hydroponics/grown/banana.dm index bdc8693b5fe..a40d6b9dbfc 100644 --- a/code/modules/hydroponics/grown/banana.dm +++ b/code/modules/hydroponics/grown/banana.dm @@ -144,3 +144,34 @@ /obj/item/grown/bananapeel/specialpeel/ComponentInitialize() . = ..() AddComponent(/datum/component/slippery, 40) + +/obj/item/food/grown/banana/bunch + name = "banana bunch" + desc = "Am exquisite bunch of bananas. The almost otherwordly plumpness steers the mind any discening entertainer towards the divine." + icon_state = "banana_bunch" + bite_consumption_mod = 4 + var/is_ripening = FALSE + +/obj/item/food/grown/banana/bunch/Initialize(mapload, obj/item/seeds/new_seed) + . = ..() + reagents.add_reagent(/datum/reagent/consumable/monkey_energy, 10) + reagents.add_reagent(/datum/reagent/consumable/banana, 10) + +/obj/item/food/grown/banana/bunch/proc/start_ripening() + if(is_ripening) + return + playsound(src, 'sound/effects/fuse.ogg', 80) + + animate(src, time = 1, pixel_z = 12, easing = ELASTIC_EASING) + animate(time = 1, pixel_z = 0, easing = BOUNCE_EASING) + addtimer(CALLBACK(src, .proc/explosive_ripening), 3 SECONDS) + for(var/i in 1 to 32) + animate(color = (i % 2) ? "#ffffff": "#ff6739", time = 1, easing = QUAD_EASING) + +/obj/item/food/grown/banana/bunch/proc/explosive_ripening() + honkerblast(src, light_range = 3, medium_range = 1) + for(var/mob/shook_boi in range(6, loc)) + shake_camera(shook_boi, 3, 5) + var/obj/effect/decal/cleanable/food/plant_smudge/banana_smudge = new(loc) + banana_smudge.color = "#ffe02f" + qdel(src) diff --git a/code/modules/language/language_holder.dm b/code/modules/language/language_holder.dm index cff14f2eb25..006178b6604 100644 --- a/code/modules/language/language_holder.dm +++ b/code/modules/language/language_holder.dm @@ -389,6 +389,11 @@ Key procs spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), /datum/language/shadowtongue = list(LANGUAGE_ATOM)) +/datum/language_holder/clown + understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/monkey = list(LANGUAGE_ATOM)) + spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/monkey = list(LANGUAGE_ATOM)) /datum/language_holder/empty understood_languages = list() spoken_languages = list() diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm index 46ed13fb4f5..5e849e96d34 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm @@ -28,15 +28,13 @@ environment_smash = ENVIRONMENT_SMASH_NONE del_on_death = 1 loot = list(/obj/effect/mob_spawn/corpse/human/clown) - + initial_language_holder = /datum/language_holder/clown atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) minbodytemp = 270 maxbodytemp = 370 unsuitable_atmos_damage = 10 unsuitable_heat_damage = 15 footstep_type = FOOTSTEP_MOB_SHOE - var/banana_time = 0 // If there's no time set it won't spawn. - var/banana_type = /obj/item/grown/bananapeel var/attack_reagent /mob/living/simple_animal/hostile/retaliate/clown/Initialize(mapload) @@ -48,20 +46,12 @@ ..() playsound(loc, 'sound/items/bikehorn.ogg', 50, TRUE) -/mob/living/simple_animal/hostile/retaliate/clown/Life(delta_time = SSMOBS_DT, times_fired) - . = ..() - if(!banana_time || banana_time >= world.time) - return - banana_time = world.time + rand(30,60) - if(!isturf(loc)) - return - var/list/reachable_turfs = list() - for(var/turf/adjacent_turf in RANGE_TURFS(1, loc)) - if(adjacent_turf == loc || !CanReach(adjacent_turf)) - continue - reachable_turfs += adjacent_turf - if(length(reachable_turfs)) - new banana_type(pick(reachable_turfs)) +/mob/living/simple_animal/hostile/retaliate/clown/AttackingTarget(atom/attacked_target) + if(!istype(attacked_target, /obj/item/food/grown/banana/bunch)) + return ..() + var/obj/item/food/grown/banana/bunch/unripe_bunch = attacked_target + unripe_bunch.start_ripening() + log_combat(src, attacked_target, "honksposivley ripened") /mob/living/simple_animal/hostile/retaliate/clown/lube name = "Living Lube" @@ -94,9 +84,92 @@ emote_see = list("honks", "bites into the banana", "plucks a banana off its head", "photosynthesizes") maxHealth = 120 health = 120 - speed = -10 + speed = -1 loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap, /obj/item/seeds/banana) - banana_time = 20 + ///Our peel dropping ability + var/datum/action/cooldown/rustle/banana_rustle + ///Our banana bunch spawning ability + var/datum/action/cooldown/exquisite_bunch/banana_bunch + +/mob/living/simple_animal/hostile/retaliate/clown/banana/Initialize(mapload) + . = ..() + banana_rustle = new() + banana_rustle.Grant(src) + banana_bunch = new() + banana_bunch.Grant(src) + +/mob/living/simple_animal/hostile/retaliate/clown/banana/Destroy() + . = ..() + QDEL_NULL(banana_rustle) + QDEL_NULL(banana_bunch) + +///drops peels around the mob when activated +/datum/action/cooldown/rustle + name = "Rustle" + desc = "Shake loose a few banana peels." + cooldown_time = 8 SECONDS + button_icon_state = "rustle" + icon_icon = 'icons/mob/actions/actions_clown.dmi' + background_icon_state = "bg_nature" + ///which type of peel to spawn + var/banana_type = /obj/item/grown/bananapeel + ///How many peels to spawn + var/peel_amount = 3 + +/datum/action/cooldown/rustle/Activate(atom/target) + . = ..() + var/list/reachable_turfs = list() + for(var/turf/adjacent_turf in RANGE_TURFS(1, owner.loc)) + if(adjacent_turf == owner.loc || !owner.CanReach(adjacent_turf) || !isopenturf(adjacent_turf)) + continue + reachable_turfs += adjacent_turf + + var/peels_to_spawn = min(peel_amount, reachable_turfs.len) + for(var/i in 1 to peels_to_spawn) + new banana_type(pick_n_take(reachable_turfs)) + playsound(owner, 'sound/creatures/clown/clownana_rustle.ogg', 100) + animate(owner, time = 1, pixel_x = 6, easing = CUBIC_EASING | EASE_OUT) + animate(time = 2, pixel_x = -8, easing = CUBIC_EASING) + animate(time = 1, pixel_x = 0, easing = CUBIC_EASING | EASE_IN) + StartCooldown() + +///spawns a plumb bunch of bananas imbued with mystical power. +/datum/action/cooldown/exquisite_bunch + name = "Exquisite Bunch" + desc = "Pluck your finest bunch of bananas from your head. This bunch is especially nutrious to monkeykind. A gentle tap will trigger an explosive ripening process." + icon_icon = 'icons/obj/hydroponics/harvest.dmi' + cooldown_time = 60 SECONDS + button_icon_state = "banana_bunch" + background_icon_state = "bg_nature" + ///If we are currently activating our ability. + var/activating = FALSE + +/datum/action/cooldown/exquisite_bunch/Trigger(trigger_flags, atom/target) + if(activating) + return + var/bunch_turf = get_step(owner.loc, owner.dir) + if(!bunch_turf) + return + if(!owner.CanReach(bunch_turf) || !isopenturf(bunch_turf)) + owner.balloon_alert("can't do that here!") + return + activating = TRUE + if(!do_after(owner, 1 SECONDS)) + activating = FALSE + return + playsound(owner, 'sound/creatures/clown/hehe.ogg', 100) + if(!do_after(owner, 1 SECONDS)) + activating = FALSE + return + activating = FALSE + return ..() + +/datum/action/cooldown/exquisite_bunch/Activate(atom/target) + . = ..() + new /obj/item/food/grown/banana/bunch(get_step(owner.loc, owner.dir)) + playsound(owner, 'sound/items/bikehorn.ogg', 60) + addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, owner, 'sound/creatures/clown/hohoho.ogg', 100, 1), 1 SECONDS) + StartCooldown() /mob/living/simple_animal/hostile/retaliate/clown/honkling name = "Honkling" @@ -111,7 +184,6 @@ attack_verb_continuous = "cheers up" attack_verb_simple = "cheer up" loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap, /obj/item/seeds/banana/bluespace) - banana_type = /obj/item/grown/bananapeel attack_reagent = /datum/reagent/consumable/laughter /mob/living/simple_animal/hostile/retaliate/clown/fleshclown diff --git a/icons/mob/actions/actions_clown.dmi b/icons/mob/actions/actions_clown.dmi new file mode 100644 index 00000000000..8b94c24abe4 Binary files /dev/null and b/icons/mob/actions/actions_clown.dmi differ diff --git a/icons/mob/actions/backgrounds.dmi b/icons/mob/actions/backgrounds.dmi index 7628c646b9f..6b80090e8a1 100644 Binary files a/icons/mob/actions/backgrounds.dmi and b/icons/mob/actions/backgrounds.dmi differ diff --git a/icons/obj/hydroponics/harvest.dmi b/icons/obj/hydroponics/harvest.dmi index 0213f65ae06..684ef81a5db 100644 Binary files a/icons/obj/hydroponics/harvest.dmi and b/icons/obj/hydroponics/harvest.dmi differ diff --git a/sound/attributions.txt b/sound/attributions.txt index 926df333912..e177646b780 100644 --- a/sound/attributions.txt +++ b/sound/attributions.txt @@ -23,6 +23,7 @@ champagne_pop.ogg is credited to ultradust on freesound https://freesound.org/pe can_open.ogg adapted from https://freesound.org/people/MaxDemianAGL/sounds/130031/ can_shake.ogg adapted from https://freesound.org/people/mcmast/sounds/456703/ -splatter.ogg adapted from https://freesound.org/people/Rocktopus/sounds/233418/ +splatter.ogg adapted from https://freesound.org/people/Rocktopus/sounds/233418/ +hohoho.ogg and hehe.ogg are cut from a recording by Nanakisan on freesound: https://freesound.org/people/Nanakisan/sounds/253534/ mbox_full.ogg and mbox_end.ogg make use of The Ragtime Drummer by James Lent, in the public domain diff --git a/sound/creatures/clown/clownana_rustle.ogg b/sound/creatures/clown/clownana_rustle.ogg new file mode 100644 index 00000000000..611d322a31e Binary files /dev/null and b/sound/creatures/clown/clownana_rustle.ogg differ diff --git a/sound/creatures/clown/hehe.ogg b/sound/creatures/clown/hehe.ogg new file mode 100644 index 00000000000..11c6b59f7fe Binary files /dev/null and b/sound/creatures/clown/hehe.ogg differ diff --git a/sound/creatures/clown/hohoho.ogg b/sound/creatures/clown/hohoho.ogg new file mode 100644 index 00000000000..4efe059a13b Binary files /dev/null and b/sound/creatures/clown/hohoho.ogg differ diff --git a/tgstation.dme b/tgstation.dme index 2fe0ea870c8..74ff5d33712 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -276,6 +276,7 @@ #include "code\__HELPERS\guid.dm" #include "code\__HELPERS\heap.dm" #include "code\__HELPERS\hearted.dm" +#include "code\__HELPERS\honkerblast.dm" #include "code\__HELPERS\icon_smoothing.dm" #include "code\__HELPERS\icons.dm" #include "code\__HELPERS\jatum.dm"