Deadchat Plays SS13: Ghost Control of Mobs (#20600)

* Add dchat control

* adds human support, cleans other things up

* Bit of cleanup

* actually use the item

* minor proc ref mistake, laugh at this user

* evil tg strings

* Renames defines, adds vv menu item for it

* Improve anarchy message formatting

* don't go to_chatting tesla energy balls

* aa review

* Minor cleanups, replace some emotes

* Addressing some reviews

* Incorporate some checks for deadchat mutes/prefs
This commit is contained in:
Luc
2023-05-21 13:33:11 -04:00
committed by GitHub
parent 73510a18ab
commit d8ddda378b
13 changed files with 511 additions and 1 deletions
+2
View File
@@ -216,6 +216,8 @@
if(GLOB.configuration.general.enable_auto_mute && !check_rights(R_ADMIN, 0) && last_message == message)
last_message_count++
if(SEND_SIGNAL(mob, COMSIG_MOB_AUTOMUTE_CHECK, src, last_message, mute_type) & WAIVE_AUTOMUTE_CHECK)
return FALSE
if(last_message_count >= SPAM_TRIGGER_AUTOMUTE)
to_chat(src, "<span class='danger'>You have exceeded the spam filter limit for identical messages. An auto-mute was applied.</span>")
cmd_admin_mute(mob, mute_type, 1)
+13
View File
@@ -102,3 +102,16 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
T.ex_act(EXPLODE_HEAVY)
if(loc == destination)
qdel(src)
/obj/effect/immovablerod/deadchat_plays(mode = DEADCHAT_DEMOCRACY_MODE, cooldown = 6 SECONDS)
return AddComponent(/datum/component/deadchat_control/immovable_rod, mode, list(), cooldown)
/**
* Rod will walk towards edge turf in the specified direction.
*
* Arguments:
* * direction - The direction to walk the rod towards: NORTH, SOUTH, EAST, WEST.
*/
/obj/effect/immovablerod/proc/walk_in_direction(direction)
destination = get_edge_target_turf(src, direction)
walk_towards(src, destination)
@@ -2065,3 +2065,83 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
set category = "IC"
update_flavor_text()
// Behavior for deadchat control
/mob/living/carbon/human/proc/dchat_emote()
var/list/possible_emotes = list("scream", "clap", "snap", "crack", "dap", "burp")
emote(pick(possible_emotes))
/mob/living/carbon/human/proc/dchat_attack()
var/turf/ahead = get_turf(get_step(src, dir))
var/mob/living/victim = locate(/mob/living) in ahead
var/in_hand = get_active_hand()
if(victim)
victim.attacked_by(in_hand, src, BODY_ZONE_CHEST)
return
var/obj/structure/other_victim = locate(/obj/structure) in ahead
if(other_victim)
do_attack_animation(other_victim, used_item = in_hand)
other_victim.attacked_by(in_hand, src)
return
visible_message("<span class='warning'>[src] swings [isnull(in_hand) ? "[p_their()] fists" : in_hand] wildly!")
/mob/living/carbon/human/proc/dchat_pickup()
var/turf/ahead = get_step(src, dir)
var/obj/item/thing = locate(/obj/item) in ahead
if(!thing)
return
var/old_loc = thing.loc
var/obj/item/in_hand = get_active_hand()
if(in_hand)
visible_message("<span class='notice'>[src] drops [in_hand] and picks up [thing] instead!</span>")
unEquip(in_hand)
in_hand.forceMove(old_loc)
else
visible_message("<span class='notice'>[src] picks up [thing]!</span>")
put_in_active_hand(thing)
/mob/living/carbon/human/proc/dchat_throw()
var/in_hand = get_active_hand()
if(!in_hand)
visible_message("<span class='notice'>[src] makes a throwing motion!</span>")
return
var/atom/possible_target
var/cur_turf = get_turf(src)
for(var/i in 1 to 5)
cur_turf = get_step(cur_turf, dir)
possible_target = locate(/mob/living) in cur_turf
if(possible_target)
break
possible_target = locate(/obj/structure) in cur_turf
if(possible_target)
break
if(!possible_target)
throw_item(cur_turf)
else
throw_item(possible_target)
/mob/living/carbon/human/proc/dchat_shove()
var/turf/ahead = get_turf(get_step(src, dir))
var/mob/living/carbon/human/H = locate(/mob/living/carbon/human) in ahead
if(!H)
visible_message("<span class='notice'>[src] tries to shove something away!</span>")
return
dna?.species.disarm(src, H)
/mob/living/carbon/human/deadchat_plays(mode = DEADCHAT_DEMOCRACY_MODE, cooldown = 7 SECONDS)
var/list/inputs = list(
"emote" = CALLBACK(src, PROC_REF(dchat_emote)),
"attack" = CALLBACK(src, PROC_REF(dchat_attack)),
"pickup" = CALLBACK(src, PROC_REF(dchat_pickup)),
"throw" = CALLBACK(src, PROC_REF(dchat_throw)),
"disarm" = CALLBACK(src, PROC_REF(dchat_shove)),
)
AddComponent(/datum/component/deadchat_control/cardinal_movement, mode, inputs, cooldown)
@@ -105,6 +105,48 @@
..(gibbed)
regenerate_icons()
/mob/living/simple_animal/pet/dog/corgi/deadchat_plays(mode = DEADCHAT_ANARCHY_MODE, cooldown = 12 SECONDS)
. = AddComponent(/datum/component/deadchat_control/cardinal_movement, mode, list(
"speak" = CALLBACK(src, PROC_REF(handle_automated_speech), TRUE),
"wear_hat" = CALLBACK(src, PROC_REF(find_new_hat)),
"drop_hat" = CALLBACK(src, PROC_REF(drop_hat)),
"spin" = CALLBACK(src, TYPE_PROC_REF(/mob, emote), "spin")), cooldown, CALLBACK(src, PROC_REF(end_dchat_plays)))
if(. == COMPONENT_INCOMPATIBLE)
return
stop_automated_movement = TRUE
///Deadchat plays command that picks a new hat for Ian.
/mob/living/simple_animal/pet/dog/corgi/proc/find_new_hat()
if(!isturf(loc))
return
var/list/possible_headwear = list()
for(var/obj/item/item in loc)
if(ispath(item.dog_fashion, /datum/dog_fashion/head))
possible_headwear += item
if(!length(possible_headwear))
for(var/obj/item/item in orange(1))
if(ispath(item.dog_fashion, /datum/dog_fashion/head) && Adjacent(item))
possible_headwear += item
if(!length(possible_headwear))
return
if(inventory_head)
inventory_head.forceMove(drop_location())
inventory_head = null
place_on_head(pick(possible_headwear))
visible_message("<span class='notice'>[src] puts [inventory_head] on [p_their()] own head, somehow.</span>")
///Deadchat plays command that drops the current hat off Ian.
/mob/living/simple_animal/pet/dog/corgi/proc/drop_hat()
if(!inventory_head)
return
visible_message("<span class='notice'>[src] vigorously shakes [p_their()] head, dropping [inventory_head] to the ground.</span>")
inventory_head.forceMove(drop_location())
inventory_head = null
update_corgi_fluff()
regenerate_icons()
/mob/living/simple_animal/pet/dog/corgi/show_inv(mob/user)
if(user.incapacitated() || !Adjacent(user))
return
@@ -635,3 +635,14 @@
/mob/living/simple_animal/proc/npc_safe(mob/user)
return FALSE
/mob/living/simple_animal/deadchat_plays(mode = DEADCHAT_ANARCHY_MODE, cooldown = 12 SECONDS)
. = AddComponent(/datum/component/deadchat_control/cardinal_movement, mode, list(), cooldown, CALLBACK(src, PROC_REF(end_dchat_plays)))
if(. == COMPONENT_INCOMPATIBLE)
return
stop_automated_movement = TRUE
/mob/living/simple_animal/proc/end_dchat_plays()
stop_automated_movement = FALSE
+2
View File
@@ -62,6 +62,8 @@
if(client.handle_spam_prevention(message, MUTE_DEADCHAT))
return
if(SEND_SIGNAL(src, COMSIG_MOB_DEADSAY, message) & MOB_DEADSAY_SIGNAL_INTERCEPT)
return
if(message in USABLE_DEAD_EMOTES)
emote(copytext(message, 2), intentional = TRUE)
@@ -522,3 +522,20 @@
projectile_angle += angle_to_projectile / (distance ** 2)
P.damage += 10 / distance
P.set_angle(projectile_angle)
/obj/singularity/proc/end_deadchat_plays()
move_self = TRUE
/obj/singularity/deadchat_plays(mode = DEADCHAT_DEMOCRACY_MODE, cooldown = 12 SECONDS)
. = AddComponent(/datum/component/deadchat_control/cardinal_movement, mode, list(), cooldown, CALLBACK(src, TYPE_PROC_REF(/atom/movable, stop_deadchat_plays)))
if(. == COMPONENT_INCOMPATIBLE)
return
move_self = FALSE
/obj/singularity/deadchat_controlled/Initialize(mapload, starting_energy)
. = ..()
deadchat_plays(mode = DEADCHAT_DEMOCRACY_MODE)