Files
vgstation13/code/modules/clothing/clothing.dm
13spacemen 2754c2fd14 Cosmetic Tail Organs [NO WAGGING] (#36060)
* mob part bitflags in proper format, added tail part bitflag, hidetail clothing cover flag, reordered tail layer, added tail_underlimbs_layer for overlapping tails, limbs_layer for limbs placed under, tail_wagging + has_icon_skin_tone + tail_overlapped species anatomical flags, mutable_appearance() helper, made many suits cover tail, added tail wagging emote for species that can wag, made a species folder for species files, rewrote update_tail_showing(), character preview can show tails, vox tails are now separate from the body instead of being baked into the chest, vox tails will show slightly in north dir instead of being invisible

* added color defines, undid bitfield format change, wag emote is shorter and doesnt show text on stopping wag, vox tails have their own file and have better names, removed icon manipulation from tail updating, species can have own tail icon, made vox tail north sprites full/complete sprites

* wag emote no longer displays runechat, custom emotes can choose to not show runechat, restores old husk overlays

* limb_tail tail define, moved 2 tail species flags to organ level, added span define, tail is on organ level, added support for cosmetic organs, tail preview icon shows better, added tail support to common surgeries

* fix double tail organ, tail organ item only uses east sprite and is shifted to center it more

* removes tail wagging

* rename tail define, minor tweaks

* more checks, fix char preview issues, remove unused proc, frankensteins spawn with random kind of tail, repaired tajaran and unathi tails credit to falcon2346, robotail support, rambler will not spawn with tail, gibbing drops tails

* Update species.dm
2024-02-28 20:26:34 +00:00

1221 lines
41 KiB
Plaintext

/obj/item/clothing
name = "clothing"
sterility = 5
autoignition_temperature = AUTOIGNITION_FABRIC
w_type = RECYK_FABRIC
starting_materials = list(MAT_FABRIC = CC_PER_SHEET_FABRIC)
var/list/species_restricted = null //Only these species can wear this kit.
var/wizard_garb = 0 //Wearing this empowers a wizard.
var/gentling //If TRUE, prevents the wearer from casting wizard spells.
var/eyeprot = 0 //for head and eyewear
var/nearsighted_modifier = 0 //positive values impair vision(welding goggles), negative values improve vision(prescription glasses)
//temperatures in Kelvin. These default values won't affect protections in any way.
var/cold_breath_protection = 300 //that cloth protects its wearer's breath from cold air down to that temperature
var/hot_breath_protection = 300 //that cloth protects its wearer's breath from hot air up to that temperature
var/cold_speed_protection = 300 //that cloth allows its wearer to keep walking at normal speed at lower temperatures
var/list/obj/item/clothing/accessory/accessories = list()
var/hidecount = 0
var/extinguishingProb = 15
//Sound stuff
//sound_change flags are CLOTHING_SOUND_SCREAM and CLOTHING_SOUND_COUGH
//sound_priority are CLOTHING_SOUND_[level]_PRIORITY, replace [level] with LOW/MED/HIGH
var/list/sound_change //Clothing can change audible emotes, this will determine what is affected
var/sound_priority //The priority of the clothing when it comes to playing sounds, higher priority means it will always play first otherwise it will randomly pick
var/list/sound_file //The actual files to be played, it will pick from the list
var/list/sound_species_whitelist
var/list/sound_genders_allowed //Checks for what gender it is allowed to play the sound for
//used for dyeing
var/list/dyeable_parts = list()
var/list/dyed_parts = list()
var/cloth_layer
var/cloth_icon
var/dye_base_iconstate_override
var/dye_base_itemstate_override
// Hood stuff. Moved to base clothing so it can be used by both uniforms and suits
var/obj/item/clothing/head/hood // Headgear to be used as hood, if any.
// Doesn't actually need a 'icons/mob/head.dmi' sprite if the hood_up_icon_state
// already provides the visuals for that (eg: most wintercoats in wintercoat.dm)
var/is_hood_up = FALSE
var/hood_suit_name = "coat" // What to call these garments when talking hood stuff. eg: coat, robes, hoodie...
var/hood_down_icon_state = null // Defaults to the initial icon_state if not set
var/hood_up_icon_state = null // Defaults to the initial icon_state if not set
var/force_hood = FALSE // Automatically equips the hood when equipping the suit. Removing the hood will remove the suit.
var/auto_hood = FALSE // Automatically equips the hood when equipping the suit.
/obj/item/clothing/New()
if (hood)
hood.hood_suit = src
if (!force_hood)
actions_types |= list(/datum/action/item_action/toggle_hood)
if (wizard_garb)
hood.wizard_garb = TRUE
if (!hood_down_icon_state)
hood_down_icon_state = icon_state
if (!hood_up_icon_state)
hood_up_icon_state = icon_state
icon_state = hood_down_icon_state
..()
update_icon()
/obj/item/clothing/Destroy()
for(var/obj/item/clothing/accessory/A in accessories)
accessories.Remove(A)
qdel(A)
if (hood)
QDEL_NULL(hood)
..()
/obj/item/clothing/update_icon()
..()
overlays.len = 0
dynamic_overlay.len = 0
if (dyed_parts.len > 0)
if (!cloth_layer || !cloth_icon)
return
var/image/dyn_overlay_worn = image('icons/effects/32x32.dmi', src, "blank")
var/image/dyn_overlay_left = image('icons/effects/32x32.dmi', src, "blank")
var/image/dyn_overlay_right = image('icons/effects/32x32.dmi', src, "blank")
for (var/part in dyed_parts)
var/list/dye_data = dyed_parts[part]
var/dye_color = dye_data[1]
var/dye_alpha = dye_data[2]
var/_state = dye_base_iconstate_override
if (!_state)
_state = icon_state
var/image/object_overlay = image(icon, src, "[_state]-[part]")
object_overlay.appearance_flags = RESET_COLOR
object_overlay.color = dye_color
object_overlay.alpha = dye_alpha
overlays += object_overlay
var/image/worn_overlay = image(cloth_icon, src, "[_state]-[part]")
worn_overlay.appearance_flags = RESET_COLOR
worn_overlay.color = dye_color
worn_overlay.alpha = dye_alpha
dyn_overlay_worn.overlays += worn_overlay
_state = dye_base_itemstate_override
if (!_state)
_state = item_state
if (!_state)
_state = icon_state
var/image/left_overlay = image(inhand_states["left_hand"], src, "[_state]-[part]")
left_overlay.appearance_flags = RESET_COLOR
left_overlay.color = dye_color
left_overlay.alpha = dye_alpha
dyn_overlay_left.overlays += left_overlay
var/image/right_overlay = image(inhand_states["right_hand"], src, "[_state]-[part]")
right_overlay.appearance_flags = RESET_COLOR
right_overlay.color = dye_color
right_overlay.alpha = dye_alpha
dyn_overlay_right.overlays += right_overlay
dynamic_overlay["[cloth_layer]"] = dyn_overlay_worn
dynamic_overlay["[HAND_LAYER]-[GRASP_LEFT_HAND]"] = dyn_overlay_left
dynamic_overlay["[HAND_LAYER]-[GRASP_RIGHT_HAND]"] = dyn_overlay_right
/obj/item/clothing/can_quick_store(var/obj/item/I)
for(var/obj/item/clothing/accessory/storage/A in accessories)
if(A.hold && A.hold.can_be_inserted(I,1))
return 1
/obj/item/clothing/quick_store(var/obj/item/I,mob/user)
for(var/obj/item/clothing/accessory/storage/A in accessories)
if(A.hold && A.hold.handle_item_insertion(I,0))
return 1
/obj/item/clothing/CtrlClick(var/mob/user)
if(isturf(loc))
return ..()
if(isliving(user) && !user.incapacitated() && user.Adjacent(src) && accessories.len)
removeaccessory()
/obj/item/clothing/examine(mob/user)
..()
for(var/obj/item/clothing/accessory/A in accessories)
to_chat(user, "<span class='info'>\A [A] is clipped to it.</span>")
/obj/item/clothing/emp_act(severity)
for(var/obj/item/clothing/accessory/accessory in accessories)
accessory.emp_act(severity)
..()
/obj/item/clothing/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/clothing/accessory))
var/obj/item/clothing/accessory/A = I
if(check_accessory_overlap(A))
to_chat(user, "<span class='notice'>You cannot attach more accessories of this type to [src].</span>")
return
if(!A.can_attach_to(src))
to_chat(user, "<span class='notice'>\The [A] cannot be attached to [src].</span>")
return
if(user.drop_item(I, src))
to_chat(user, "<span class='notice'>You attach [A] to [src].</span>")
attach_accessory(A)
A.add_fingerprint(user)
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
H.update_inv_by_slot(slot_flags)
return 1
if(I.is_screwdriver(user))
for(var/obj/item/clothing/accessory/accessory in priority_accessories())
if(accessory.attackby(I, user))
return 1
for(var/obj/item/clothing/accessory/accessory in priority_accessories())
if(accessory.attackby(I, user))
return 1
..()
/obj/item/clothing/attack_hand(mob/user)
if(accessories.len && src.loc == user)
var/list/delayed = list()
for(var/obj/item/clothing/accessory/A in priority_accessories())
switch(A.on_accessory_interact(user, 0))
if(1)
return 1
if(-1)
delayed.Add(A)
else
continue
var/ignorecounter = 0
for(var/obj/item/clothing/accessory/A in delayed)
//if(A.ignoreinteract)
//ignorecounter += 1
ignorecounter += A.ignoreinteract
if(!(A.ignoreinteract) && A.on_accessory_interact(user, 1))
return 1
if(ignorecounter == accessories.len)
return ..()
return
return ..()
/obj/item/clothing/clean_act(var/cleanliness)
..()
if (cleanliness >= CLEANLINESS_BLEACH)
dyed_parts.len = 0
update_icon()
if (ismob(loc))
var/mob/M = loc
M.update_inv_hands()
/obj/item/clothing/proc/togglehood()
set name = "Toggle Hood"
set category = "Object"
set src in usr
if (!hood)
return
if(usr.incapacitated())
return
toggle_hood(usr)
/obj/item/clothing/proc/toggle_hood(var/mob/wearer, var/mob/user)
if(ismob(wearer))
if (user && (user!=wearer))
if(!is_hood_up && !wearer.get_item_by_slot(slot_head) && hood.mob_can_equip(wearer,slot_head))
to_chat(user, "You put their hood up.")
to_chat(wearer, "[user] puts your hood up.")
hoodup(wearer)
else if(wearer.get_item_by_slot(slot_head) == hood)
hooddown(wearer)
to_chat(user, "You put their hood down.")
to_chat(wearer, "[user] puts your hood down.")
else
to_chat(user, "You try to put their hood up, but there is something in the way.")
to_chat(wearer, "[user] tries in vain to put your hood up, but there is something in the way.")
return
else
if(!is_hood_up && !wearer.get_item_by_slot(slot_head) && hood.mob_can_equip(wearer,slot_head))
to_chat(wearer, "You put the hood up.")
hoodup(wearer)
else if(wearer.get_item_by_slot(slot_head) == hood)
hooddown(wearer)
to_chat(wearer, "You put the hood down.")
else
to_chat(wearer, "You try to put your hood up, but there is something in the way.")
return
wearer.update_inv_w_uniform()
else if (istype(wearer, /obj/structure/mannequin))
var/obj/structure/mannequin/mannequin = wearer
if(!is_hood_up && !mannequin.clothing[SLOT_MANNEQUIN_HEAD])
to_chat(user, "You put the hood up.")
hoodup(wearer)
else if(mannequin.clothing[SLOT_MANNEQUIN_HEAD] == hood)
hooddown(wearer)
to_chat(user, "You put the hood down.")
else
to_chat(user, "You try to put the hood up, but there is something in the way.")
return
/obj/item/clothing/proc/hoodup(var/atom/movable/AM)
if(istype(AM, /mob/living/carbon/human))
var/mob/living/carbon/human/H = AM
hood.dyed_parts = dyed_parts.Copy()
hood.color = color
hood.update_icon()
H.equip_to_slot(hood, slot_head)
icon_state = hood_up_icon_state
is_hood_up = TRUE
H.update_inv_w_uniform()
H.update_inv_wear_suit()
else if (istype(AM, /obj/structure/mannequin))
var/obj/structure/mannequin/M = AM
M.clothing[SLOT_MANNEQUIN_HEAD] = hood
hood.mannequin_equip(M,SLOT_MANNEQUIN_HEAD)
/obj/item/clothing/proc/hooddown(var/atom/movable/AM, var/unequip = 1)
if(istype(AM, /mob/living/carbon/human))
var/mob/living/carbon/human/H = AM
icon_state = hood_down_icon_state
if(unequip)
H.u_equip(H.head,0)
is_hood_up = FALSE
H.update_inv_w_uniform()
H.update_inv_wear_suit()
else if (istype(AM, /obj/structure/mannequin))
var/obj/structure/mannequin/M = AM
M.clothing[SLOT_MANNEQUIN_HEAD] = null
hood.mannequin_unequip(M)
/obj/item/clothing/mannequin_unequip(var/obj/structure/mannequin/mannequin)
if (hood && (mannequin.clothing[SLOT_MANNEQUIN_HEAD] == hood))
hooddown(mannequin)
/obj/item/clothing/dye_act(var/obj/structure/reagent_dispensers/cauldron/cauldron, var/mob/user)
if (clothing_flags & COLORS_OVERLAY)
var/dye_target = "full"
var/list/actual_parts = list()
var/list/choices = list("Full")
if (dyeable_parts.len > 0)
for (var/part in dyeable_parts)//doing some swapping so we get an easier list to read in-game
var/part_proper_name = dyeable_part_to_name[part]
choices += part_proper_name
actual_parts[part_proper_name] = part
dye_target = input("Which part do you want to dye?","Clothing Dyeing",1) as null|anything in choices
if (!dye_target)
return
to_chat(user, "<span class='notice'>You begin dyeing \the [src][(dye_target != "Full") ? "'s [dye_target]" : ""].</span>")
playsound(cauldron.loc, 'sound/effects/slosh.ogg', 25, 1)
if (do_after(user, cauldron, 30))
var/mixed_color = mix_color_from_reagents(cauldron.reagents.reagent_list, TRUE)
var/mixed_alpha = mix_alpha_from_reagents(cauldron.reagents.reagent_list)
if (mixed_color == "#FFFFFF")
mixed_color = "#FEFEFE" //null color prevention
if (!mixed_color)
var/silent = FALSE
for(var/datum/reagent/R in cauldron.reagents.reagent_list)
if (R.id == BLEACH || R.id == ACETONE)
silent = TRUE
to_chat(user, "<span class='notice'>You wash off \the [src]'s colors.</span>")
if (R.id == CLEANER)
silent = TRUE
to_chat(user, "<span class='notice'>You wash \the [src] clean.</span>")
R.reaction_obj(src, R.volume)
if (!silent)
to_chat(user, "<span class='warning'>It seems that there are no pigments among the reagents in the cauldron.</span>")
update_icon()
user.update_inv_hands()
return
if (dye_target == "Full" || choices.len <= 1)
dyed_parts.len = 0
color = BlendRGB(color, mixed_color, mixed_alpha/255)
else
dyed_parts -= dye_target//moving the new layer on top
dyed_parts[actual_parts[dye_target]] = list(mixed_color,mixed_alpha)//getting back the actual overlay name
update_icon()
user.update_inv_hands()
else
to_chat(user, "<span class='warning'>Can't dye that.</span>")
return TRUE
/obj/item/clothing/proc/attach_accessory(obj/item/clothing/accessory/accessory, mob/user)
accessories += accessory
accessory.forceMove(src)
accessory.on_attached(src)
update_verbs()
/obj/item/clothing/proc/priority_accessories()
if(!accessories.len)
return list()
var/list/unorg = accessories
var/list/prioritized = list()
for(var/obj/item/clothing/accessory/holster/H in accessories)
prioritized.Add(H)
for(var/obj/item/clothing/accessory/storage/S in accessories)
prioritized.Add(S)
for(var/obj/item/clothing/accessory/armband/A in accessories)
prioritized.Add(A)
prioritized |= unorg
return prioritized
/obj/item/clothing/proc/check_accessory_overlap(var/obj/item/clothing/accessory/accessory)
if(!accessory)
return
for(var/obj/item/clothing/accessory/A in accessories)
if(A.accessory_exclusion & accessory.accessory_exclusion)
return 1
/obj/item/clothing/proc/remove_accessory(mob/user, var/obj/item/clothing/accessory/accessory)
if(!accessory || !(accessory in accessories))
return
accessory.on_removed(user)
accessories.Remove(accessory)
if(ishuman(user))
var/mob/living/carbon/human/H = user
H.update_inv_by_slot(slot_flags)
update_verbs()
/obj/item/clothing/proc/get_accessory_by_exclusion(var/exclusion)
for(var/obj/item/clothing/accessory/A in accessories)
if(A.accessory_exclusion == exclusion)
return A
/obj/item/clothing/verb/removeaccessory()
set name = "Remove Accessory"
set category = "Object"
set src in usr
if(usr.incapacitated())
return
if(!accessories.len)
return
var/obj/item/clothing/accessory/A
if(accessories.len > 1)
A = input("Select an accessory to remove from [src]") as anything in accessories
else
A = accessories[1]
src.remove_accessory(usr,A)
/obj/item/clothing/proc/update_verbs()
if(accessories.len)
verbs |= /obj/item/clothing/verb/removeaccessory
else
verbs -= /obj/item/clothing/verb/removeaccessory
/obj/item/clothing/proc/is_worn_by(mob/user)
if(user.is_wearing_item(src))
return TRUE
return FALSE
/obj/item/clothing/New() //so sorry
..()
update_verbs()
//BS12: Species-restricted clothing check.
/obj/item/clothing/mob_can_equip(mob/M, slot, disable_warning = 0, automatic = 0)
. = ..() //Default return value. If 1, item can be equipped. If 0, it can't be.
if(!.)
return //Default return value is 0 - don't check for species
switch(role_check(M))
if(FALSE)
return CANNOT_EQUIP
if(ALWAYSTRUE)
return CAN_EQUIP
if(species_restricted && istype(M,/mob/living/carbon/human) && (slot != slot_l_store && slot != slot_r_store))
var/wearable = null
var/exclusive = null
var/mob/living/carbon/human/H = M
if("exclude" in species_restricted)
exclusive = 1
var/datum/species/base_species = H.species
if(!base_species)
return
var/base_species_can_wear = 1 //If the body's main species can wear this
if(exclusive)
if(!species_restricted.Find(base_species.name))
wearable = 1
else
base_species_can_wear = 0
else
if(species_restricted.Find(base_species.name))
wearable = 1
else
base_species_can_wear = 0
//Check ALL organs covered by the slot. If any of the organ's species can't wear this, return 0
for(var/datum/organ/external/OE in get_organs_by_slot(slot, H)) //Go through all organs covered by the item
if(!OE.species) //Species same as of the body
if(!base_species_can_wear) //And the body's species can't wear
wearable = 0
break
continue
if(exclusive)
if(!species_restricted.Find(OE.species.name))
wearable = 1
else
to_chat(M, "<span class='warning'>Your misshapen [OE.display_name] prevents you from wearing \the [src].</span>")
return CANNOT_EQUIP
else
if(species_restricted.Find(OE.species.name))
wearable = 1
else
to_chat(M, "<span class='warning'>Your misshapen [OE.display_name] prevents you from wearing \the [src].</span>")
return CANNOT_EQUIP
if(!wearable) //But we are a species that CAN'T wear it (sidenote: slots 15 and 16 are pockets)
to_chat(M, "<span class='warning'>Your species cannot wear [src].</span>")//Let us know
return CANNOT_EQUIP
//return ..()
/obj/item/clothing/proc/role_check(mob/user)
if(!user || !user.mind || !user.mind.antag_roles.len)
return TRUE //No roles to check
for(var/datum/role/R in get_list_of_elements(user.mind.antag_roles))
switch(R.can_wear(src))
if(ALWAYSTRUE)
return ALWAYSTRUE
if(FALSE)
return FALSE
if(TRUE)
continue
return TRUE //All roles true? Return true.
/obj/item/clothing/before_stripped(mob/wearer as mob, mob/stripper as mob, slot)
..()
if(slot == slot_w_uniform) //this will cause us to drop our belt, ID, and pockets!
for(var/slotID in list(slot_wear_id, slot_belt, slot_l_store, slot_r_store))
var/obj/item/I = wearer.get_item_by_slot(slotID)
if(I)
I.stripped(wearer, stripper)
/obj/item/clothing/become_defective()
if(!defective)
..()
for(var/A in armor)
armor[A] -= rand(armor[A]/3, armor[A])
/obj/item/clothing/attack(var/mob/living/M, var/mob/living/user, def_zone, var/originator = null)
if (!(iscarbon(user) && user.a_intent == I_HELP && (clothing_flags & CANEXTINGUISH) && ishuman(M) && M.on_fire))
..()
else
var/mob/living/carbon/human/target = M
if(isplasmaman(target)) // Cannot put out plasmamen, else they could just go around with a jumpsuit and not need a space suit.
visible_message("<span class='warning'>\The [user] attempts to put out the fire on \the [target], but plasmafires are too hot. It is no use.</span>")
else
visible_message("<span class='warning'>\The [user] attempts to put out the fire on \the [target] with \the [src].</span>")
if(prob(extinguishingProb))
M.ExtinguishMob()
visible_message("<span class='notice'>\The [user] puts out the fire on \the [target].</span>")
return
/obj/item/clothing/proc/offenseTackleBonus()
return
/obj/item/clothing/proc/defenseTackleBonus()
return
/obj/item/clothing/proc/rangeTackleBonus()
return
/* ========================================================================
EARS
======================================================================== */
//Ears: headsets, earmuffs and tiny objects
/obj/item/clothing/ears
name = "ears"
w_class = W_CLASS_TINY
throwforce = 2
slot_flags = SLOT_EARS
cloth_layer = EARS_LAYER
cloth_icon = 'icons/mob/ears.dmi'
starting_materials = list(MAT_FABRIC = 750)
/obj/item/clothing/ears/attack_hand(mob/user as mob)
if (!user)
return
if (src.loc != user || !istype(user,/mob/living/carbon/human))
..()
return
var/mob/living/carbon/human/H = user
if(H.ears != src)
..()
return
if(!canremove)
return
var/obj/item/clothing/ears/O = src
user.u_equip(src,0)
if (O)
user.put_in_hands(O)
O.add_fingerprint(user)
/obj/item/clothing/ears/earmuffs
name = "earmuffs"
desc = "Protects your hearing from both loud and quiet noises."
icon_state = "earmuffs"
item_state = "earmuffs"
slot_flags = SLOT_EARS
/* ========================================================================
GLOVES
======================================================================== */
/obj/item/clothing/gloves
name = "gloves"
gender = PLURAL //Carn: for grammarically correct text-parsing
w_class = W_CLASS_SMALL
icon = 'icons/obj/clothing/gloves.dmi'
inhand_states = list("left_hand" = 'icons/mob/in-hand/left/gloves.dmi', "right_hand" = 'icons/mob/in-hand/right/gloves.dmi')
siemens_coefficient = 0.50
sterility = 50
var/wired = 0
var/obj/item/weapon/cell/cell = 0
var/cant_remove_cell = FALSE
var/clipped = 0
body_parts_covered = HANDS
slot_flags = SLOT_GLOVES
attack_verb = list("challenges")
species_restricted = list("exclude","Unathi","Tajaran","Muton")
var/pickpocket = 0 //Master pickpocket?
var/bonus_knockout = 0 //Knockout chance is multiplied by (1 + bonus_knockout) and is capped at 1/2. 0 = 1/12 chance, 1 = 1/6 chance, 2 = 1/4 chance, 3 = 1/3 chance, etc.
var/damage_added = 0 //Added to unarmed damage, doesn't affect knockout chance
var/sharpness_added = 0 //Works like weapon sharpness for unarmed attacks, affects bleeding and limb severing.
var/hitsound_added = "punch" //The sound that plays for an unarmed attack while wearing these gloves.
var/attack_verb_override = "punches"
var/transfer_blood = 0
var/list/bloody_hands_data = list()
cloth_layer = GLOVES_LAYER
cloth_icon = 'icons/mob/hands.dmi'
starting_materials = list(MAT_FABRIC = 938)
/obj/item/clothing/gloves/get_cell()
return cell
/obj/item/clothing/gloves/emp_act(severity)
if(cell)
cell.charge -= 1000 / severity
if (cell.charge < 0)
cell.charge = 0
if(cell.reliability != 100 && prob(50/severity))
cell.reliability -= 10 / severity
..()
/obj/item/clothing/gloves/proc/dexterity_check(mob/user) //Set wearer's dexterity to the value returned by this proc. Doesn't override death or brain damage, and should always return 1 (unless intended otherwise)
return 1 //Setting this to 0 will make user NOT dexterious when wearing these gloves
// Called just before an attack_hand(), in mob/UnarmedAttack()
/obj/item/clothing/gloves/proc/Touch(var/atom/A, mob/user, proximity)
return 0 // return 1 to cancel attack_hand()
/obj/item/clothing/gloves/proc/get_damage_added()
return damage_added
/obj/item/clothing/gloves/proc/get_sharpness_added()
return sharpness_added
/obj/item/clothing/gloves/proc/get_hitsound_added()
return hitsound_added
/obj/item/clothing/gloves/proc/on_punch(mob/user, mob/victim)
return
/obj/item/clothing/gloves/proc/on_wearer_threw_item(mob/user, atom/target, atom/movable/thrown) //Called when the mob wearing the gloves successfully throws either something or nothing.
return
/* ========================================================================
HEAD
======================================================================== */
/obj/item/clothing/head
name = "head"
icon = 'icons/obj/clothing/hats.dmi'
body_parts_covered = HEAD
slot_flags = SLOT_HEAD
species_restricted = list("exclude","Muton")
var/gave_out_gifts = FALSE //for snowman animation
var/obj/item/clothing/head/on_top = null //for stacking
var/stack_depth = 0
var/vertical_offset = 0 //enables hats to go taller that the tile's boundaries
var/blood_overlay_type = "hat"
cloth_layer = HEAD_LAYER
cloth_icon = 'icons/mob/head.dmi'
starting_materials = list(MAT_FABRIC = 1875)
var/obj/item/clothing/hood_suit = null // the suit this hood belongs to
/obj/item/clothing/head/Destroy()
if(hood_suit)
hood_suit.hood = null
hood_suit = null
..()
/obj/item/clothing/head/pickup(var/mob/living/carbon/human/user)
if(hood_suit && istype(hood_suit) && (istype(hood_suit.loc, /obj/structure/mannequin)||(user.get_item_by_slot(slot_wear_suit) == hood_suit)||(user.get_item_by_slot(slot_w_uniform) == hood_suit)))
hood_suit.hooddown(user, unequip = 0)
user.drop_from_inventory(src)
forceMove(hood_suit)
if (hood_suit.force_hood)
user.u_equip(hood_suit)
user.put_in_hands(hood_suit)
else
to_chat(user, "You put the hood down.")
var/global/hatStacking = 0
var/global/maxStackDepth = 10
/client/proc/configHat()
set name = "Configure Hat Stacking"
set category = "Debug"
. = (alert("Allow hats to stack?",,"Yes","No")=="Yes")
if(.)
hatStacking = 1
else
hatStacking = 0
. = (input("Set stack limit. (1 to 100)"))
. = text2num(.)
if(isnum(.) && (. in 1 to 100))
maxStackDepth = .
else
to_chat(usr, "That wasn't a valid number.")
log_admin("[key_name(usr)] set hatStacking to [hatStacking].")
message_admins("[key_name(usr)] set hatStacking to [hatStacking].")
log_admin("[key_name(usr)] set maxStackDepth to [maxStackDepth].")
message_admins("[key_name(usr)] set maxStackDepth to [maxStackDepth].")
/obj/item/clothing/head/attackby(obj/item/W, mob/user)
if(hatStacking)
if(on_top)
on_top.attackby(W,user)
else if(istype(W,/obj/item/clothing/head) && !istype(W,/obj/item/clothing/head/helmet))
var/obj/item/clothing/head/hat = W
if(stack_depth >= maxStackDepth)
to_chat(user,"<span class='warning'>You cannot stack any higher than this!</span>")
else if(user.drop_item(W))
to_chat(user,"<span class='notice'>You add \the [hat] onto \the [src] and stack it in a towering pillar!</span>")
stack_depth++
hat.stack_depth = stack_depth
W.forceMove(src)
W.pixel_y += 4 * PIXEL_MULTIPLIER
vis_contents.Add(W)
on_top = hat
user.update_inv_head()
for(var/obj/item/clothing/head/above = on_top; above; above = above.on_top)
above.stack_depth = stack_depth
..()
/obj/item/clothing/head/attack_hand(mob/user)
if(on_top)
if(on_top.on_top)
on_top.attack_hand(user)
else
to_chat(user,"You remove \the [on_top] from the towering pillar.")
on_top.pixel_y = 0
stack_depth--
on_top.stack_depth = 0
user.put_in_hands(on_top)
vis_contents.Cut()
on_top = null
user.update_inv_head()
for(var/obj/item/clothing/head/above = on_top; above; above = above.on_top)
above.stack_depth = stack_depth
return
return ..()
/obj/item/clothing/head/description_hats()
var/list/hat_names = list()
for(var/obj/item/clothing/head/above = on_top; above; above = above.on_top)
hat_names += above.name
if(hat_names.len)
return " It is piled underneath a [english_list(hat_names)]."
/obj/item/clothing/head/proc/bite_action(mob/target)
return
/obj/item/proc/islightshielded() // So as to avoid unneeded casts.
return FALSE
/* ========================================================================
MASK
======================================================================== */
/obj/item/clothing/mask
name = "mask"
icon = 'icons/obj/clothing/masks.dmi'
body_parts_covered = MOUTH
slot_flags = SLOT_MASK
species_restricted = list("exclude","Muton")
var/can_flip = null
var/is_flipped = 1
var/ignore_flip = 0
actions_types = list(/datum/action/item_action/toggle_mask)
heat_conductivity = MASK_HEAT_CONDUCTIVITY
cloth_layer = FACEMASK_LAYER
cloth_icon = 'icons/mob/mask.dmi'
starting_materials = list(MAT_FABRIC = 938)
/datum/action/item_action/toggle_mask
name = "Toggle Mask"
/datum/action/item_action/toggle_mask/Trigger()
var/obj/item/clothing/mask/T = target
if(!istype(T))
return
T.togglemask()
/obj/item/clothing/mask/proc/togglemask()
if(ignore_flip)
return
else
if(usr.incapacitated())
return
if(!can_flip)
to_chat(usr, "You try pushing \the [src] out of the way, but it is very uncomfortable and you look like a fool. You push it back into place.")
return
if(src.is_flipped == 2)
src.icon_state = initial(icon_state)
gas_transfer_coefficient = initial(gas_transfer_coefficient)
permeability_coefficient = initial(permeability_coefficient)
sterility = initial(sterility)
flags = initial(flags)
body_parts_covered = initial(body_parts_covered)
to_chat(usr, "You push \the [src] back into place.")
src.is_flipped = 1
else
src.icon_state = "[initial(icon_state)]_up"
to_chat(usr, "You push \the [src] out of the way.")
gas_transfer_coefficient = null
permeability_coefficient = null
sterility = 0
flags = 0
src.is_flipped = 2
body_parts_covered &= ~(MOUTH|HEAD|BEARD|FACE)
update_icon()
usr.update_inv_wear_mask()
usr.update_hair()
usr.update_inv_glasses()
/obj/item/clothing/mask/New()
if(!can_flip /*&& !istype(/obj/item/clothing/mask/gas/voice)*/) //the voice changer has can_flip = 1 anyways but it's worth noting that it exists if anybody changes this in the future
actions_types = null
..()
/obj/item/clothing/mask/attack_self()
togglemask()
/* ========================================================================
SHOES
======================================================================== */
/obj/item/clothing/shoes
name = "shoes"
icon = 'icons/obj/clothing/shoes.dmi'
desc = "Comfortable-looking shoes."
gender = PLURAL //Carn: for grammarically correct text-parsing
var/obj/item/weapon/chain = null // handcuffs attached
var/bonus_kick_damage = 0
var/footprint_type = /obj/effect/decal/cleanable/blood/tracks/footprints //The type of footprint left by someone wearing these
var/mag_slow = MAGBOOTS_SLOWDOWN_HIGH //how slow are they when the magpulse is on?
siemens_coefficient = 0.9
body_parts_covered = FEET
slot_flags = SLOT_FEET
heat_conductivity = SHOE_HEAT_CONDUCTIVITY
permeability_coefficient = 0.50
sterility = 50
species_restricted = list("exclude","Unathi","Tajaran","Muton")
var/step_sound = ""
var/stepstaken = 1
var/modulo_steps = 2 //if stepstaken is a multiplier of modulo_steps, play the sound. Does not work if modulo_steps < 1
cloth_layer = SHOES_LAYER
cloth_icon = 'icons/mob/feet.dmi'
starting_materials = list(MAT_FABRIC = 1250)
var/luminous_paint = FALSE
/obj/item/clothing/shoes/proc/step_action()
stepstaken++
if(step_sound != "" && ishuman(loc))
var/mob/living/carbon/human/H = loc
switch(H.m_intent)
if("run")
if(stepstaken % modulo_steps == 0)
playsound(H, step_sound, 50, 1) // this will NEVER GET ANNOYING!
if("walk")
playsound(H, step_sound, 20, 1)
/obj/item/clothing/shoes/proc/on_kick(mob/living/user, mob/living/victim)
return
/obj/item/clothing/shoes/defenseTackleBonus()
if(clothing_flags & MAGPULSE)
return 40
//Called from human_defense.dm proc foot_impact
/obj/item/clothing/shoes/proc/impact_dampen(atom/source, var/damage)
return damage
/obj/item/clothing/shoes/kick_act(mob/living/carbon/human/user)
if(user.equip_to_slot_if_possible(src, slot_shoes))
user.visible_message("<span class='notice'>[user] kicks \the [src] and slips them on!</span>", "<span class='notice'>You kick \the [src] and slip them on!</span>")
else
..()
/obj/item/clothing/shoes/clean_blood()
. = ..()
track_blood = 0
blood_color = null
luminous_paint = FALSE
/obj/item/clothing/shoes/proc/togglemagpulse(var/mob/user = usr, var/override = FALSE)
if(!override)
if(user.isUnconscious())
return
if((clothing_flags & MAGPULSE))
clothing_flags &= ~(NOSLIP | MAGPULSE)
slowdown = NO_SLOWDOWN
return 0
else
clothing_flags |= (NOSLIP | MAGPULSE)
slowdown = mag_slow
return 1
/* ========================================================================
SUIT
======================================================================== */
/obj/item/clothing/suit
icon = 'icons/obj/clothing/suits.dmi'
name = "suit"
var/fire_resist = T0C+100
flags = FPRINT
allowed = list(/obj/item/weapon/tank/emergency_oxygen,/obj/item/weapon/tank/emergency_nitrogen,/obj/item/weapon/tank/emergency_plasma)
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0)
slot_flags = SLOT_OCLOTHING
heat_conductivity = ARMOUR_HEAT_CONDUCTIVITY
body_parts_covered = ARMS|LEGS|FULL_TORSO
var/blood_overlay_type = "suit"
species_restricted = list("exclude","Muton")
siemens_coefficient = 0.9
clothing_flags = CANEXTINGUISH
sterility = 30
cloth_layer = SUIT_LAYER
cloth_icon = 'icons/mob/suit.dmi'
starting_materials = list(MAT_FABRIC = CC_PER_SHEET_FABRIC)
/obj/item/clothing/suit/togglehood()
set name = "Toggle Hood"
set category = "Object"
set src in usr
if (!hood)
return
if(usr.incapacitated())
return
var/mob/living/carbon/human/user = usr
if(!istype(user))
return
if(user.get_item_by_slot(slot_wear_suit) != src)
to_chat(user, "You have to put the [hood_suit_name] on first.")
return
if(!is_hood_up && !user.get_item_by_slot(slot_head) && hood.mob_can_equip(user,slot_head))
to_chat(user, "You put the hood up.")
hoodup(user)
else if(user.get_item_by_slot(slot_head) == hood)
hooddown(user)
to_chat(user, "You put the hood down.")
else
to_chat(user, "You try to put your hood up, but there is something in the way.")
return
user.update_inv_wear_suit()
/obj/item/clothing/suit/attack_self()
if (hood && !force_hood)
togglehood()
/obj/item/clothing/equipped(var/mob/user, var/slot, hand_index = 0)
..()
if (hood && (force_hood || auto_hood) && !hand_index)
if (auto_hood && (user.get_item_by_slot(slot_head) && user.get_item_by_slot(slot_head) != hood))
return//we want to still be able to equip the suit even if the hood is blocked
hoodup(user)
/obj/item/clothing/unequipped(var/mob/living/carbon/human/user)
..()
if(hood && istype(user) && user.get_item_by_slot(slot_head) == hood)
hooddown(user)
/obj/item/clothing/mob_can_equip(mob/M, slot, disable_warning = 0, automatic = 0)
. = ..()
if (hood && force_hood && slot == slot_wear_suit)
if (M.get_item_by_slot(slot_head) && M.get_item_by_slot(slot_head) != hood)
to_chat(M, "You try to put the [hood_suit_name] on, but there is something in the way of its hood.")
return FALSE
else if (!hood.mob_can_equip(M, slot_head))
return FALSE
/obj/item/clothing/suit/proc/vine_protected()
return FALSE
/obj/item/clothing/suit/proc/Extinguish(var/mob/living/carbon/human/H)
return
/obj/item/clothing/suit/proc/regulate_temp_of_wearer(var/mob/living/carbon/human/H)
return
//Spacesuit
//Note: Everything in modules/clothing/spacesuits should have the entire suit grouped together.
// Meaning the the suit is defined directly after the corresponding helmet. Just like below!
/obj/item/clothing/head/helmet/space
name = "Space helmet"
icon_state = "space"
desc = "A special helmet designed for work in a hazardous, low-pressure environment."
pressure_resistance = 5 * ONE_ATMOSPHERE
item_state = "space"
inhand_states = list("left_hand" = 'icons/mob/in-hand/left/spacesuits.dmi', "right_hand" = 'icons/mob/in-hand/right/spacesuits.dmi')
permeability_coefficient = 0.01
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 50)
body_parts_covered = FULL_HEAD|HIDEHAIR
body_parts_visible_override = EYES
siemens_coefficient = 0.9
heat_conductivity = SPACESUIT_HEAT_CONDUCTIVITY
species_restricted = list("exclude","Diona","Muton")
eyeprot = 1
cold_breath_protection = 230
sterility = 100
species_fit = list(INSECT_SHAPED, VOX_SHAPED, GREY_SHAPED)
autoignition_temperature = 0
fire_fuel = 0
/obj/item/clothing/suit/space
name = "Space suit"
desc = "A suit that protects against low pressure environments. Has a big \"13\" on the back."
icon_state = "space"
item_state = "s_suit"
inhand_states = list("left_hand" = 'icons/mob/in-hand/left/spacesuits.dmi', "right_hand" = 'icons/mob/in-hand/right/spacesuits.dmi')
w_class = W_CLASS_LARGE//bulky item
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.02
flags = FPRINT
pressure_resistance = 5 * ONE_ATMOSPHERE
body_parts_covered = ARMS|LEGS|FULL_TORSO|FEET|HANDS|TAIL
allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank/)
slowdown = HARDSUIT_SLOWDOWN_BULKY
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 50)
siemens_coefficient = 0.9
species_restricted = list("exclude","Diona","Muton")
heat_conductivity = SPACESUIT_HEAT_CONDUCTIVITY
clothing_flags = CANEXTINGUISH
sterility = 100
species_fit = list(INSECT_SHAPED, VOX_SHAPED, GREY_SHAPED)
autoignition_temperature = 0
fire_fuel = 0
/* ========================================================================
UNIFORMS
======================================================================== */
/obj/item/clothing/under
icon = 'icons/obj/clothing/uniforms.dmi'
name = "under"
body_parts_covered = ARMS|LEGS|FULL_TORSO
permeability_coefficient = 0.90
flags = FPRINT
slot_flags = SLOT_ICLOTHING
heat_conductivity = JUMPSUIT_HEAT_CONDUCTIVITY
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0)
species_restricted = list("exclude","Muton")
var/has_sensor = 1 //For the crew computer 2 = unable to change mode
var/sensor_mode = 0
/*
1 = Report living/dead
2 = Report detailed damages
3 = Report location
*/
var/displays_id = 1
clothing_flags = CANEXTINGUISH
var/icon/jersey_overlays
cloth_layer = UNIFORM_LAYER
cloth_icon = 'icons/mob/uniform.dmi'
starting_materials = list(MAT_FABRIC = CC_PER_SHEET_FABRIC)
// Associative list of exact type -> number
var/list/jersey_numbers = list()
/obj/item/clothing/under/togglehood()
set name = "Toggle Hood"
set category = "Object"
set src in usr
if (!hood)
return
if(usr.incapacitated())
return
var/mob/living/carbon/human/user = usr
if(!istype(user))
return
if(user.get_item_by_slot(slot_w_uniform) != src)
to_chat(user, "You have to put the [hood_suit_name] on first.")
return
if(!is_hood_up && !user.get_item_by_slot(slot_head) && hood.mob_can_equip(user,slot_head))
to_chat(user, "You put the hood up.")
hoodup(user)
else if(user.get_item_by_slot(slot_head) == hood)
hooddown(user)
to_chat(user, "You put the hood down.")
else
to_chat(user, "You try to put your hood up, but there is something in the way.")
return
user.update_inv_w_uniform()
/obj/item/clothing/under/attack_self()
if (hood && !force_hood)
togglehood()
/obj/item/clothing/under/update_icon()
..()
if(jersey_overlays)
var/number = jersey_numbers[type]++ % 99
var/first_digit = num2text(round((number / 10) % 10))
var/second_digit = num2text(round(number % 10))
var/image/jersey_overlay = image(jersey_overlays, src, "[first_digit]-")
jersey_overlay.overlays += image(jersey_overlays, src, second_digit)
dynamic_overlay["[UNIFORM_LAYER]"] = jersey_overlay
/obj/item/clothing/under/examine(mob/user)
..()
var/mode
switch(src.sensor_mode)
if(0)
mode = "Its sensors appear to be disabled."
if(1)
mode = "Its binary life sensors appear to be enabled."
if(2)
mode = "Its vital tracker appears to be enabled."
if(3)
mode = "Its vital tracker and tracking beacon appear to be enabled."
to_chat(user, "<span class='info'>" + mode + "</span>")
/obj/item/clothing/under/emp_act(severity)
..()
sensor_mode = pick(0,1,2,3)
/obj/item/clothing/under/proc/set_sensors(mob/user as mob)
if(user.incapacitated())
return
if(has_sensor >= 2)
to_chat(user, "<span class='warning'>The controls are locked.</span>")
return 0
if(has_sensor <= 0)
to_chat(user, "<span class='warning'>This suit does not have any sensors.</span>")
return 0
var/list/modes = list("Off", "Binary sensors", "Vitals tracker", "Tracking beacon")
var/switchMode = input("Select a sensor mode:", "Suit Sensor Mode", modes[sensor_mode + 1]) in modes
if(user.incapacitated())
return
if(get_dist(user, src) > 1)
to_chat(user, "<span class='warning'>You have moved too far away.</span>")
return
sensor_mode = modes.Find(switchMode) - 1
if(is_holder_of(user, src))
switch(sensor_mode) //i'm sure there's a more compact way to write this but c'mon
if(0)
to_chat(user, "<span class='notice'>You disable your suit's remote sensing equipment.</span>")
if(1)
to_chat(user, "<span class='notice'>Your suit will now report whether you are live or dead.</span>")
if(2)
to_chat(user, "<span class='notice'>Your suit will now report your vital lifesigns.</span>")
if(3)
to_chat(user, "<span class='notice'>Your suit will now report your vital lifesigns as well as your coordinate position.</span>")
else
switch(sensor_mode)
if(0)
to_chat(user, "<span class='notice'>You disable the suit's remote sensing equipment.</span>")
if(1)
to_chat(user, "<span class='notice'>The suit sensors will now report whether the wearer is live or dead.</span>")
if(2)
to_chat(user, "<span class='notice'>The suit sensors will now report the wearer's vital lifesigns.</span>")
if(3)
to_chat(user, "<span class='notice'>The suit sensors will now report the wearer's vital lifesigns as well as their coordinate position.</span>")
return switchMode
/obj/item/clothing/under/verb/toggle()
set name = "Toggle Suit Sensors"
set category = "Object"
set src in usr
set_sensors(usr)
/obj/item/clothing/under/AltClick()
if(is_holder_of(usr, src))
set_sensors(usr)
else
return ..()
/datum/action/item_action/toggle_minimap
name = "Toggle Minimap"
/datum/action/item_action/toggle_minimap/Trigger()
var/obj/item/clothing/under/T = target
if(!istype(T))
return
for(var/obj/item/clothing/accessory/holomap_chip/HC in T.accessories)
HC.togglemap()
/datum/action/item_action/target_appearance/check_watch
name = "Check the Time"
/datum/action/item_action/target_appearance/check_watch/Trigger()
var/obj/item/clothing/accessory/wristwatch/W = target
if(!istype(W))
return
W.check_watch()
/obj/item/clothing/under/rank/New()
. = ..()
sensor_mode = pick(0, 1, 2, 3)
/* ========================================================================
BACK
======================================================================== */
/obj/item/clothing/back
name = "cape"
w_class = W_CLASS_SMALL
throwforce = 2
slot_flags = SLOT_BACK
starting_materials = list(MAT_FABRIC = CC_PER_SHEET_FABRIC)