[MIRROR] You can now move and talk through statues and mannequins (#26414)

You can now move and talk through statues and mannequins (#81188)

## About The Pull Request

I recently played a game where I rotated my skeleton model while
rotating my own character at the same time and it being in sync gave me
the realization on how cool it would be if the Coroner was able to
simply control the skeleton body.

I find skeleton displays very funny and I want to see more funny things
happen with them, so I thought this would be a good place to start, with
the benefits that it also works on mannequins and statues too so they
aren't left out.

Basically, while it is unanchored, if you have a statue/mannequin
grabbed, it will change its direction as you do, and speak the same
words you do. Your own messages can only be heard if the person is
directly next to you, revealing that it was you talking through it all
along.

I was originally gonna add this to the simple rotation component but
moved off when I decided to add talking through it, I left in the code
improvements I made to the component though since it is one of the
oldest components and hasn't been touched in a while.

Video demonstration (before I added the person also talking, just ignore
that missing)

https://github.com/tgstation/tgstation/assets/53777086/27242fc3-9649-418d-95cb-b31619319e97

While fixing the Toilet bong's rotation stuff I noticed a lot of it
wasn't up to proper code standards so I went over it and fixed issues I
had with it. It now doesn't give text saying you found something nasty
to species that still likes mice (like flypeople), and fixed its update
appearance to match the codebase standard set by the introduction of
``update_appearance`` many years ago.

## Why It's Good For The Game

It's a funny small idea I had and got inspired to add, it's a niche
mechanic that I think fits the aesthetic I am going for with Coroner and
also give a funny interaction with the human-like inanimate objects.

## Changelog

🆑
fix: Species that can eat mice don't get disgusted from seeing one in
the toilet bong.
add: Grabbing an unwrenched statue/mannequin/skeleton model will now
move its direction as you move yours, and you can talk through it.
/🆑

Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
This commit is contained in:
SkyratBot
2024-02-09 00:53:36 +01:00
committed by GitHub
co-authored by John Willard
parent 5938e8085a
commit bca65962e5
13 changed files with 171 additions and 101 deletions
+1 -1
View File
@@ -64,6 +64,7 @@
icon_state = "mannequin_[material]_[body_type == FEMALE ? "female" : "male"]"
AddElement(/datum/element/strippable, GLOB.strippable_mannequin_items)
AddComponent(/datum/component/simple_rotation, ROTATION_IGNORE_ANCHORED)
AddComponent(/datum/component/marionette)
update_appearance()
/obj/structure/mannequin/Destroy()
@@ -202,7 +203,6 @@
name = "skeleton model"
desc = "Not to knock over."
material = MANNEQUIN_SKELETON
anchored = TRUE
obj_flags = UNIQUE_RENAME
starting_items = list(
/obj/item/clothing/glasses/eyepatch,
+51 -56
View File
@@ -3,29 +3,28 @@
desc = "A repurposed toilet with re-arranged piping and an attached flamethrower. Why would anyone build this?"
icon = 'icons/obj/watercloset.dmi'
icon_state = "toiletbong"
base_icon_state = "toiletbong"
density = FALSE
anchored = TRUE
var/emagged = FALSE
var/smokeradius = 1
var/mutable_appearance/weed_overlay
/obj/structure/toiletbong/Initialize(mapload)
. = ..()
create_storage()
AddComponent(/datum/component/simple_rotation, AfterRotation = CALLBACK(src, PROC_REF(AfterRotation)))
AddComponent(/datum/component/simple_rotation, post_rotation = CALLBACK(src, PROC_REF(post_rotation)))
create_storage(max_total_storage = 100, max_slots = 12, canhold = /obj/item/food)
atom_storage.attack_hand_interact = FALSE
atom_storage.rustle_sound = FALSE
atom_storage.animated = FALSE
weed_overlay = mutable_appearance('icons/obj/watercloset.dmi', "toiletbong_overlay")
weed_overlay = mutable_appearance('icons/obj/watercloset.dmi', "[base_icon_state]_overlay")
START_PROCESSING(SSobj, src)
/obj/structure/toiletbong/update_icon()
/obj/structure/toiletbong/update_overlays()
. = ..()
cut_overlays()
if (LAZYLEN(contents))
add_overlay(weed_overlay)
. += weed_overlay
/obj/structure/toiletbong/attack_hand(mob/living/carbon/user)
. = ..()
@@ -36,47 +35,44 @@
user.balloon_alert(user, "it's empty!")
return
user.visible_message(span_boldnotice("[user] takes a huge drag on the [src]."))
if (do_after(user, 2 SECONDS, target = src))
var/turf/toiletbong_location = loc
toiletbong_location.hotspot_expose(1000, 5)
for (var/obj/item/item in contents)
if (item.resistance_flags & INDESTRUCTIBLE)
user.balloon_alert(user, "[item.name] is blocking the pipes!")
continue
playsound(src, 'sound/items/modsuit/flamethrower.ogg', 50)
var/datum/effect_system/fluid_spread/smoke/chem/smoke_machine/puff = new
puff.set_up(smokeradius, holder = src, location = user, carry = item.reagents, efficiency = 20)
puff.start()
if (prob(5) && !emagged)
if(islizard(user))
user.balloon_alert(user, "a hidden treat!")
user.visible_message(span_danger("[user] fishes a mouse out of the pipes."))
else
to_chat(user, span_userdanger("There was something disgusting in the pipes!"))
user.visible_message(span_danger("[user] spits out a mouse."))
user.adjust_disgust(50)
user.vomit(VOMIT_CATEGORY_DEFAULT)
var/mob/living/spawned_mob = new /mob/living/basic/mouse(get_turf(user))
spawned_mob.faction |= "[REF(user)]"
if(prob(50))
for(var/j in 1 to rand(1, 3))
step(spawned_mob, pick(NORTH,SOUTH,EAST,WEST))
qdel(item)
if(!emagged)
break
update_icon()
if (!do_after(user, 2 SECONDS, target = src))
return
var/turf/toiletbong_location = loc
toiletbong_location.hotspot_expose(1000, 5)
for (var/obj/item/item in contents)
if (item.resistance_flags & INDESTRUCTIBLE)
user.balloon_alert(user, "[item.name] is blocking the pipes!")
continue
playsound(src, 'sound/items/modsuit/flamethrower.ogg', 50)
var/datum/effect_system/fluid_spread/smoke/chem/smoke_machine/puff = new
puff.set_up(smokeradius, holder = src, location = user, carry = item.reagents, efficiency = 20)
puff.start()
if (prob(5) && !(obj_flags & EMAGGED))
if(user.get_liked_foodtypes() & GORE)
user.balloon_alert(user, "a hidden treat!")
user.visible_message(span_danger("[user] fishes a mouse out of the pipes."))
else
to_chat(user, span_userdanger("There was something disgusting in the pipes!"))
user.visible_message(span_danger("[user] spits out a mouse."))
user.adjust_disgust(50)
user.vomit(VOMIT_CATEGORY_DEFAULT)
var/mob/living/spawned_mob = new /mob/living/basic/mouse(get_turf(user))
spawned_mob.faction |= "[REF(user)]"
if(prob(50))
for(var/j in 1 to rand(1, 3))
step(spawned_mob, pick(NORTH,SOUTH,EAST,WEST))
qdel(item)
if(!(obj_flags & EMAGGED))
break
update_appearance(UPDATE_ICON)
/obj/structure/toiletbong/wrench_act(mob/living/user, obj/item/tool)
tool.play_tool_sound(src)
if(anchored)
to_chat(user, span_notice("You begin unsecuring the [src]."))
anchored = FALSE
else
to_chat(user, span_notice("You secure the [src] to the floor."))
anchored = TRUE
return TRUE
..()
default_unfasten_wrench(user, tool)
return ITEM_INTERACT_SUCCESS
/obj/structure/toiletbong/proc/AfterRotation(mob/user, degrees)
///Called in the simple rotation's post_rotation callback, playing a sound cue to players.
/obj/structure/toiletbong/proc/post_rotation(mob/user, degrees)
playsound(src, 'sound/items/deconstruct.ogg', 50)
/obj/structure/toiletbong/crowbar_act(mob/living/user, obj/item/tool)
@@ -94,18 +90,17 @@
return TRUE
/obj/structure/toiletbong/emag_act(mob/user, obj/item/card/emag/emag_card)
if(obj_flags & EMAGGED)
return FALSE
obj_flags |= EMAGGED
smokeradius = 2
playsound(src, 'sound/effects/fish_splash.ogg', 50)
user.balloon_alert(user, "whoops!")
if(!emagged)
emagged = TRUE
smokeradius = 2
balloon_alert(user, "toilet broke")
if (emag_card)
to_chat(user, span_boldwarning("The [emag_card] falls into the toilet. You fish it back out. Looks like you broke the toilet."))
return TRUE
return FALSE
balloon_alert(user, "toilet broke")
if (emag_card)
to_chat(user, span_boldwarning("The [emag_card] falls into the toilet. You fish it back out. Looks like you broke the toilet."))
return TRUE
/obj/structure/toiletbong/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/card/emag))
/obj/structure/toiletbong/attackby(obj/item/attacking_item, mob/user, params)
if(istype(attacking_item, /obj/item/card/emag))
return
. = ..()
return ..()
@@ -15,7 +15,7 @@
/obj/structure/c_transit_tube/Initialize(mapload)
. = ..()
AddComponent(/datum/component/simple_rotation, AfterRotation = CALLBACK(src, PROC_REF(AfterRotation)))
AddComponent(/datum/component/simple_rotation, post_rotation = CALLBACK(src, PROC_REF(post_rotation)))
/obj/structure/c_transit_tube/proc/can_wrench_in_loc(mob/user)
var/turf/source_turf = get_turf(loc)
@@ -27,7 +27,7 @@
return FALSE
return TRUE
/obj/structure/c_transit_tube/proc/AfterRotation(mob/user, degrees)
/obj/structure/c_transit_tube/proc/post_rotation(mob/user, degrees)
if(flipped_build_type && degrees == ROTATION_FLIP)
setDir(turn(dir, degrees)) //Turn back we don't actually flip
flipped = !flipped
+2 -2
View File
@@ -67,7 +67,7 @@
flags_1 |= ALLOW_DARK_PAINTS_1
RegisterSignal(src, COMSIG_OBJ_PAINTED, PROC_REF(on_painted))
AddElement(/datum/element/atmos_sensitive, mapload)
AddComponent(/datum/component/simple_rotation, ROTATION_NEEDS_ROOM, AfterRotation = CALLBACK(src, PROC_REF(AfterRotation)))
AddComponent(/datum/component/simple_rotation, ROTATION_NEEDS_ROOM, post_rotation = CALLBACK(src, PROC_REF(post_rotation)))
var/static/list/loc_connections = list(
COMSIG_ATOM_EXIT = PROC_REF(on_exit),
@@ -358,7 +358,7 @@
dropped_debris += new /obj/item/stack/rods(location, (fulltile ? 2 : 1))
return dropped_debris
/obj/structure/window/proc/AfterRotation(mob/user, degrees)
/obj/structure/window/proc/post_rotation(mob/user, degrees)
air_update_turf(TRUE, FALSE)
/obj/structure/window/proc/on_painted(obj/structure/window/source, mob/user, obj/item/toy/crayon/spraycan/spraycan, is_dark_color)