Skip to content

Commit

Permalink
[MIRROR] Facehuggers dont sleep people + muzzle code exorcism [MDB IG…
Browse files Browse the repository at this point in the history
…NORE] (#4232)

* Facehuggers dont sleep people + muzzle code exorcism

* conflicts

* re-adds muzzle_ignore, adds it to a few emotes

---------

Co-authored-by: NovaBot <[email protected]>
Co-authored-by: jimmyl <[email protected]>
Co-authored-by: Fluffles <[email protected]>
  • Loading branch information
4 people authored Jul 5, 2024
1 parent 84eb872 commit eb495aa
Show file tree
Hide file tree
Showing 18 changed files with 133 additions and 60 deletions.
2 changes: 1 addition & 1 deletion code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
///Mob is trying to open the wires of a target [/atom], from /datum/wires/interactable(): (atom/target)
#define COMSIG_TRY_WIRES_INTERACT "try_wires_interact"
#define COMPONENT_CANT_INTERACT_WIRES (1<<0)
///Mob is trying to emote, from /datum/emote/proc/run_emote(): (key, params, type_override, intentional)
///Mob is trying to emote, from /datum/emote/proc/run_emote(): (key, params, type_override, intentional, emote)
#define COMSIG_MOB_PRE_EMOTED "mob_pre_emoted"
#define COMPONENT_CANT_EMOTE (1<<0)
#define COMSIG_MOB_EMOTED(emote_key) "mob_emoted_[emote_key]"
Expand Down
14 changes: 6 additions & 8 deletions code/__DEFINES/obj_flags.dm
Original file line number Diff line number Diff line change
Expand Up @@ -75,20 +75,18 @@
#define DANGEROUS_OBJECT (1<<10)
/// Clothes that use large icons, for applying the proper overlays like blood
#define LARGE_WORN_ICON (1<<11)
/// Clothes that block speech (i.e the muzzle). Can be applied to any clothing piece.
#define BLOCKS_SPEECH (1<<12)
/// prevents from placing on plasmaman helmet or modsuit hat holder
#define STACKABLE_HELMET_EXEMPT (1<<13)
#define STACKABLE_HELMET_EXEMPT (1<<12)
/// Prevents plasmamen from igniting when wearing this
#define PLASMAMAN_PREVENT_IGNITION (1<<14)
#define PLASMAMAN_PREVENT_IGNITION (1<<13)
/// Usable as casting clothes by wizards (matters for suits, glasses and headwear)
#define CASTING_CLOTHES (1<<15)
#define CASTING_CLOTHES (1<<14)
///Moths can't eat the clothing that has this flag.
#define INEDIBLE_CLOTHING (1<<16)
#define INEDIBLE_CLOTHING (1<<15)
/// Headgear/helmet allows internals
#define HEADINTERNALS (1<<17)
#define HEADINTERNALS (1<<16)
/// Prevents masks from getting adjusted from enabling internals
#define INTERNALS_ADJUST_EXEMPT (1<<18)
#define INTERNALS_ADJUST_EXEMPT (1<<17)

/// Integrity defines for clothing (not flags but close enough)
#define CLOTHING_PRISTINE 0 // We have no damage on the clothing
Expand Down
1 change: 0 additions & 1 deletion code/_globalvars/bitfields.dm
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ DEFINE_BITFIELD(car_traits, list(

DEFINE_BITFIELD(clothing_flags, list(
"ANTI_TINFOIL_MANEUVER" = ANTI_TINFOIL_MANEUVER,
"BLOCKS_SPEECH" = BLOCKS_SPEECH,
"BLOCK_GAS_SMOKE_EFFECT" = BLOCK_GAS_SMOKE_EFFECT,
"CASTING_CLOTHES" = CASTING_CLOTHES,
"GAS_FILTERING" = GAS_FILTERING,
Expand Down
4 changes: 4 additions & 0 deletions code/datums/components/knockoff.dm
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
/datum/component/knockoff/RegisterWithParent()
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equipped))
RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_dropped))
var/atom/movable/atom_parent = parent
var/mob/living/as_mob = atom_parent.loc
if(ismob(as_mob))
on_equipped(atom_parent, as_mob, as_mob.get_slot_by_item(atom_parent)) // lie a little

/datum/component/knockoff/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED))
Expand Down
52 changes: 52 additions & 0 deletions code/datums/elements/muffles_speech.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/datum/element/muffles_speech

/datum/element/muffles_speech/Attach(datum/target)
. = ..()
if(!isitem(target))
return ELEMENT_INCOMPATIBLE

RegisterSignal(target, COMSIG_ITEM_EQUIPPED, PROC_REF(equipped))
RegisterSignal(target, COMSIG_ITEM_DROPPED, PROC_REF(dropped))

/datum/element/muffles_speech/Detach(datum/source)
. = ..()
UnregisterSignal(source, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED))

/datum/element/muffles_speech/proc/equipped(obj/item/source, mob/user, slot)
SIGNAL_HANDLER
if(source.slot_flags & slot)
RegisterSignal(user, COMSIG_MOB_SAY, PROC_REF(muzzle_talk))
RegisterSignal(user, COMSIG_MOB_PRE_EMOTED, PROC_REF(emote_override))

/datum/element/muffles_speech/proc/dropped(obj/item/source, mob/user)
SIGNAL_HANDLER
UnregisterSignal(user, list(COMSIG_MOB_PRE_EMOTED, COMSIG_MOB_SAY))

/datum/element/muffles_speech/proc/emote_override(mob/living/source, key, params, type_override, intentional, datum/emote/emote)
SIGNAL_HANDLER
// NOVA EDIT ADDITION: muzzle_ignore flag
if(emote.muzzle_ignore)
return NONE
// NOVA EDIT ADDITION END
if(!emote.hands_use_check && (emote.emote_type & EMOTE_AUDIBLE))
source.audible_message("makes a [pick("strong ", "weak ", "")]noise.", audible_message_flags = EMOTE_MESSAGE|ALWAYS_SHOW_SELF_MESSAGE)
return COMPONENT_CANT_EMOTE
return NONE

/datum/element/muffles_speech/proc/muzzle_talk(datum/source, list/speech_args)
SIGNAL_HANDLER

var/spoken_message = speech_args[SPEECH_MESSAGE]
if(spoken_message)
var/list/words = splittext(spoken_message, " ")
var/yell_suffix = copytext(spoken_message, findtext(spoken_message, "!"))
spoken_message = ""

for(var/ind = 1 to length(words))
var/new_word = ""
for(var/i = 1 to length(words[ind]) + rand(-1,1))
new_word += "m"
new_word += "f"
words[ind] = yell_suffix ? uppertext(new_word) : new_word
spoken_message = "[jointext(words, " ")][yell_suffix]"
speech_args[SPEECH_MESSAGE] = spoken_message
10 changes: 2 additions & 8 deletions code/datums/emotes.dm
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@
var/emote_type = EMOTE_VISIBLE
/// Checks if the mob can use its hands before performing the emote.
var/hands_use_check = FALSE
/// Will only work if the emote is EMOTE_AUDIBLE.
var/muzzle_ignore = FALSE
/// Types that are allowed to use that emote.
var/list/mob_type_allowed_typecache = /mob
/// Types that are NOT allowed to use that emote.
Expand Down Expand Up @@ -90,7 +88,7 @@
/datum/emote/proc/run_emote(mob/user, params, type_override, intentional = FALSE)
if(!can_run_emote(user, TRUE, intentional))
return FALSE
if(SEND_SIGNAL(user, COMSIG_MOB_PRE_EMOTED, key, params, type_override, intentional) & COMPONENT_CANT_EMOTE)
if(SEND_SIGNAL(user, COMSIG_MOB_PRE_EMOTED, key, params, type_override, intentional, src) & COMPONENT_CANT_EMOTE)
return TRUE // We don't return FALSE because the error output would be incorrect, provide your own if necessary.
var/msg = select_message_type(user, message, intentional)
if(params && message_param)
Expand Down Expand Up @@ -318,8 +316,6 @@
return .
var/mob/living/living_user = user

if(!muzzle_ignore && user.is_muzzled() && emote_type & EMOTE_AUDIBLE)
return "makes a [pick("strong ", "weak ", "")]noise."
if(HAS_MIND_TRAIT(user, TRAIT_MIMING) && message_mime)
. = message_mime
if(isalienadult(user) && message_alien)
Expand Down Expand Up @@ -406,9 +402,7 @@
* Returns a bool about whether or not the user should play a sound when performing the emote.
*/
/datum/emote/proc/should_play_sound(mob/user, intentional = FALSE)
if(emote_type & EMOTE_AUDIBLE && !muzzle_ignore)
if(user.is_muzzled())
return FALSE
if(emote_type & EMOTE_AUDIBLE && !hands_use_check)
if(HAS_TRAIT(user, TRAIT_MUTE))
return FALSE
if(ishuman(user))
Expand Down
9 changes: 6 additions & 3 deletions code/modules/clothing/masks/muzzle.dm
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
inhand_icon_state = "blindfold"
lefthand_file = 'icons/mob/inhands/clothing/glasses_lefthand.dmi'
righthand_file = 'icons/mob/inhands/clothing/glasses_righthand.dmi'
clothing_flags = BLOCKS_SPEECH
flags_cover = MASKCOVERSMOUTH
w_class = WEIGHT_CLASS_SMALL
equip_delay_other = 20

/obj/item/clothing/mask/muzzle/Initialize(mapload)
. = ..()
AddElement(/datum/element/muffles_speech)

/obj/item/clothing/mask/muzzle/attack_paw(mob/user, list/modifiers)
if(iscarbon(user))
var/mob/living/carbon/carbon_user = user
Expand All @@ -26,7 +29,7 @@
lefthand_file = 'icons/mob/inhands/clothing/masks_lefthand.dmi'
righthand_file = 'icons/mob/inhands/clothing/masks_righthand.dmi'
body_parts_covered = NONE
clothing_flags = MASKINTERNALS | BLOCKS_SPEECH
clothing_flags = MASKINTERNALS
armor_type = /datum/armor/muzzle_breath
equip_delay_other = 25 // my sprite has 4 straps, a-la a head harness. takes a while to equip, longer than a muzzle

Expand All @@ -37,7 +40,7 @@
worn_icon_state = "tape_piece_worn"
inhand_icon_state = null
w_class = WEIGHT_CLASS_TINY
clothing_flags = INEDIBLE_CLOTHING|BLOCKS_SPEECH
clothing_flags = INEDIBLE_CLOTHING
equip_delay_other = 40
strip_delay = 40
greyscale_config = /datum/greyscale_config/tape_piece
Expand Down
3 changes: 2 additions & 1 deletion code/modules/mob/living/carbon/alien/adult/alien_powers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,8 @@ Doesn't work on other aliens/AI.*/
plasma_cost = 50

/datum/action/cooldown/alien/acid/neurotoxin/IsAvailable(feedback = FALSE)
if(owner.is_muzzled())
var/mob/living/carbon/as_carbon = owner
if(istype(as_carbon) && as_carbon.is_mouth_covered(ITEM_SLOT_MASK))
return FALSE
if(!isturf(owner.loc))
return FALSE
Expand Down
1 change: 1 addition & 0 deletions code/modules/mob/living/carbon/alien/alien.dm
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
return pick (list("xltrails_1", "xltrails2"))
else
return pick (list("xttrails_1", "xttrails2"))

/*----------------------------------------
Proc: AddInfectionImages()
Des: Gives the client of the alien an image on each infected mob.
Expand Down
60 changes: 47 additions & 13 deletions code/modules/mob/living/carbon/alien/special/facehugger.dm
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@
layer = MOB_LAYER
max_integrity = 100
item_flags = XENOMORPH_HOLDABLE
special_desc_requirement = EXAMINE_CHECK_JOB //NOVA EDIT
special_desc_jobs = list("Scientist, Research Director") //NOVA EDIT
special_desc = "This alien is an extremely dangerous life form capable of creating a xenomorph. You would know well not to approach without full body biological protection." //NOVA EDIT
// NOVA EDIT ADDITION START: job-restricted examine text
special_desc_requirement = EXAMINE_CHECK_JOB
special_desc_jobs = list("Scientist, Research Director")
special_desc = "This alien is an extremely dangerous life form capable of creating a xenomorph. You would know well not to approach without full body biological protection."
// NOVA EDIT ADDITION END
slowdown = 2
var/stat = CONSCIOUS //UNCONSCIOUS is the idle state in this case

var/sterile = FALSE
Expand All @@ -42,6 +45,7 @@
)
AddElement(/datum/element/connect_loc, loc_connections)
AddElement(/datum/element/atmos_sensitive, mapload)
AddElement(/datum/element/muffles_speech)

RegisterSignal(src, COMSIG_LIVING_TRYING_TO_PULL, PROC_REF(react_to_mob))

Expand Down Expand Up @@ -125,7 +129,7 @@

/obj/item/clothing/mask/facehugger/proc/valid_to_attach(mob/living/hit_mob)
// valid targets: carbons except aliens and devils
// facehugger state early exit checks
// facehugger state early exit checks (Note: Melbert does not want dead people to be huggable)
if(stat != CONSCIOUS)
return FALSE
if(attached)
Expand Down Expand Up @@ -174,22 +178,25 @@
log_combat(target, src, "was facehugged by")
return TRUE // time for a smoke

/obj/item/clothing/mask/facehugger/proc/Attach(mob/living/M)
if(!valid_to_attach(M))
/obj/item/clothing/mask/facehugger/proc/Attach(mob/living/victim)
if(!valid_to_attach(victim))
return

if(victim.stat < UNCONSCIOUS) //sorry bro you gotta be awake
victim.say("AAAA!!") //triggers muffled speech and also visual feedback i guess
// early returns and validity checks done: attach.
attached++
//ensure we detach once we no longer need to be attached
addtimer(CALLBACK(src, PROC_REF(detach)), MAX_IMPREGNATION_TIME)


if(!sterile)
M.take_bodypart_damage(strength,0) //done here so that humans in helmets take damage
M.Unconscious(MAX_IMPREGNATION_TIME/0.3) //something like 25 ticks = 20 seconds with the default settings

victim.take_bodypart_damage(strength,0) //done here so that humans in helmets take damage
if(real && !sterile)
victim.Knockdown(5 SECONDS)
GoIdle() //so it doesn't jump the people that tear it off

addtimer(CALLBACK(src, PROC_REF(Impregnate), M), rand(MIN_IMPREGNATION_TIME, MAX_IMPREGNATION_TIME))
addtimer(CALLBACK(src, PROC_REF(Impregnate), victim), rand(MIN_IMPREGNATION_TIME, MAX_IMPREGNATION_TIME))

/obj/item/clothing/mask/facehugger/proc/detach()
attached = 0
Expand Down Expand Up @@ -252,6 +259,29 @@

visible_message(span_danger("[src] curls up into a ball!"))

// chest maybe because getting slammed in the chest would knock it off your face while dead
AddComponent(/datum/component/knockoff, knockoff_chance = 40, target_zones = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST), slots_knockoffable = slot_flags)

/obj/item/clothing/mask/facehugger/allow_attack_hand_drop(mob/living/carbon/human/user)
if(!real || sterile || user.get_organ_by_type(/obj/item/organ/internal/body_egg/alien_embryo))
return ..()
if(istype(user) && ishuman(loc) && stat != DEAD)
if(user == loc && user.get_item_by_slot(slot_flags) == src)
to_chat(user, span_userdanger("[src] is latched on too tight! Get help or wait for it to let go!"))
return FALSE
return ..()

/obj/item/clothing/mask/facehugger/mouse_drop_dragged(atom/over, mob/user, src_location, over_location, params)
var/mob/living/carbon/human/wearer = loc
if(!istype(wearer) || user != wearer)
return
if(!real || sterile || user.get_organ_by_type(/obj/item/organ/internal/body_egg/alien_embryo))
return ..()
if(wearer.get_item_by_slot(slot_flags) == src && stat != DEAD)
to_chat(user, span_userdanger("[src] is latched on too tight! Get help or wait for it to let go!"))
return
return ..()

/proc/CanHug(mob/living/M)
if(!istype(M))
return FALSE
Expand All @@ -270,10 +300,13 @@
/obj/item/clothing/mask/facehugger/lamarr
name = "Lamarr"
desc = "The Research Director's pet, a domesticated and debeaked xenomorph facehugger. Friendly, but may still try to couple with your head."
special_desc_requirement = EXAMINE_CHECK_ROLE //NOVA EDIT
special_desc_roles = list("ROLE_ALIEN") //NOVA EDIT
special_desc = "This young one has been cruelly mutilated. It lacks the capability to fill a host with our sisters." //NOVA EDIT
// NOVA EDIT ADDITION START: job-restricted examine text
special_desc_requirement = EXAMINE_CHECK_ROLE
special_desc_roles = list("ROLE_ALIEN")
special_desc = "This young one has been cruelly mutilated. It lacks the capability to fill a host with our sisters."
// NOVA EDIT ADDITION END
sterile = TRUE
slowdown = 1.5 //lamarr is too fat after being fed in captivity to effectively slow people down or something

/obj/item/clothing/mask/facehugger/dead
icon_state = "facehugger_dead"
Expand All @@ -293,6 +326,7 @@
real = FALSE
sterile = TRUE
tint = 3 //Makes it feel more authentic when it latches on
slowdown = 0

/obj/item/clothing/mask/facehugger/toy/Die()
return
Expand Down
7 changes: 0 additions & 7 deletions code/modules/mob/living/carbon/carbon.dm
Original file line number Diff line number Diff line change
Expand Up @@ -234,13 +234,6 @@
. = ..()
loc.handle_fall(src)//it's loc so it doesn't call the mob's handle_fall which does nothing

/mob/living/carbon/is_muzzled()
for (var/obj/item/clothing/clothing in get_equipped_items())
if(clothing.clothing_flags & BLOCKS_SPEECH)
return TRUE
return FALSE


/mob/living/carbon/resist_buckle()
if(!HAS_TRAIT(src, TRAIT_RESTRAINED))
buckled.user_unbuckle_mob(src, src)
Expand Down
2 changes: 0 additions & 2 deletions code/modules/mob/living/carbon/emote.dm
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
key = "clap"
key_third_person = "claps"
message = "claps."
muzzle_ignore = TRUE
hands_use_check = TRUE
emote_type = EMOTE_AUDIBLE | EMOTE_VISIBLE
audio_cooldown = 5 SECONDS
Expand Down Expand Up @@ -189,7 +188,6 @@
message_param = "snaps their fingers at %t."
emote_type = EMOTE_AUDIBLE | EMOTE_VISIBLE
hands_use_check = TRUE
muzzle_ignore = TRUE

/datum/emote/living/carbon/snap/get_sound(mob/living/user)
if(ishuman(user))
Expand Down
2 changes: 1 addition & 1 deletion code/modules/mob/living/living_defense.dm
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@

if(!user.get_bodypart(BODY_ZONE_HEAD))
return FALSE
if(user.is_muzzled() || user.is_mouth_covered(ITEM_SLOT_MASK))
if(user.is_mouth_covered(ITEM_SLOT_MASK))
to_chat(user, span_warning("You can't bite with your mouth covered!"))
return FALSE

Expand Down
4 changes: 0 additions & 4 deletions code/modules/mob/mob.dm
Original file line number Diff line number Diff line change
Expand Up @@ -942,10 +942,6 @@
set category = null
return

///Is the mob muzzled (default false)
/mob/proc/is_muzzled()
return FALSE

/// Adds this list to the output to the stat browser
/mob/proc/get_status_tab_items()
. = list("") //we want to offset unique stuff from standard stuff
Expand Down
3 changes: 0 additions & 3 deletions code/modules/mob/mob_say.dm
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,6 @@
if(!allow_mimes && HAS_MIND_TRAIT(src, TRAIT_MIMING))
return FALSE

if(is_muzzled())
return FALSE

return ..()

///Speak as a dead person (ghost etc)
Expand Down
Loading

0 comments on commit eb495aa

Please sign in to comment.