diff --git a/code/__DEFINES/dcs/signals/signals_clothing.dm b/code/__DEFINES/dcs/signals/signals_clothing.dm index b48acbf97e937a..03b695aca4c3e1 100644 --- a/code/__DEFINES/dcs/signals/signals_clothing.dm +++ b/code/__DEFINES/dcs/signals/signals_clothing.dm @@ -1,6 +1,21 @@ // /obj/item/clothing /// (/obj/item/clothing, visor_state) - When a clothing gets it's visor toggled. #define COMSIG_CLOTHING_VISOR_TOGGLE "clothing_visor_toggle" -// /obj/item/clothing -/// Sent when mobs try to equip clothing on others through attacking -#define COMSIG_CLOTHING_ATTACK_EQUIP "clothing_attack_equip" +/// From an undersuit being adjusted: () +#define COMSIG_CLOTHING_UNDER_ADJUSTED "clothing_under_adjusted" + +// Accessory sending to clothing +/// /obj/item/clothing/accessory/successful_attach : (obj/item/clothing/under/attached_to) +/// The accessory, at the point of signal sent, is in the clothing's accessory list / loc +#define COMSIG_CLOTHING_ACCESSORY_ATTACHED "clothing_accessory_pinned" +/// /obj/item/clothing/accessory/detach : (obj/item/clothing/under/detach_from) +/// The accessory, at the point of signal sent, is no longer in the accessory list but may still be in the loc +#define COMSIG_CLOTHING_ACCESSORY_DETACHED "clothing_accessory_unpinned" + +// To accessories themselves +/// /obj/item/clothing/accessory/successful_attach : (obj/item/clothing/under/attached_to) +/// The accessory, at the point of signal sent, is in the clothing's accessory list / loc +#define COMSIG_ACCESSORY_ATTACHED "accessory_pinned" +/// /obj/item/clothing/accessory/detach : (obj/item/clothing/under/detach_from) +/// The accessory, at the point of signal sent, is no longer in the accessory list but may still be in the loc +#define COMSIG_ACCESSORY_DETACHED "accessory_unpinned" diff --git a/code/datums/mood_events/generic_positive_events.dm b/code/datums/mood_events/generic_positive_events.dm index d1376437a075c2..ba4252d30ae3d7 100644 --- a/code/datums/mood_events/generic_positive_events.dm +++ b/code/datums/mood_events/generic_positive_events.dm @@ -194,8 +194,8 @@ timeout = 3 MINUTES /datum/mood_event/hope_lavaland - description = "What a peculiar emblem. It makes me feel hopeful for my future." - mood_change = 10 + description = "What a peculiar emblem. It makes me feel hopeful for my future." + mood_change = 6 /datum/mood_event/confident_mane description = "I'm feeling confident with a head full of hair." diff --git a/code/datums/quirks/negative_quirks.dm b/code/datums/quirks/negative_quirks.dm index 77328dfce103cd..08393519a5dcc4 100644 --- a/code/datums/quirks/negative_quirks.dm +++ b/code/datums/quirks/negative_quirks.dm @@ -968,8 +968,7 @@ medical_record_text = "Patient's immune system responds violently to [allergy_string]" var/mob/living/carbon/human/human_holder = quirk_holder - var/obj/item/clothing/accessory/allergy_dogtag/dogtag = new(get_turf(human_holder)) - dogtag.display = allergy_string + var/obj/item/clothing/accessory/dogtag/allergy/dogtag = new(get_turf(human_holder), allergy_string) give_item_to_holder(dogtag, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS), flavour_text = "Make sure medical staff can see this...") diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index bec2556aa55a17..55ef354012045a 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -239,19 +239,24 @@ FAN HUDs! For identifying other fans on-sight. /mob/living/carbon/human/proc/fan_hud_set_fandom() var/image/holder = hud_list[FAN_HUD] - var/icon/I = icon(icon, icon_state, dir) - holder.pixel_y = I.Height() - world.icon_size + var/icon/hud_icon = icon(icon, icon_state, dir) + holder.pixel_y = hud_icon.Height() - world.icon_size holder.icon_state = "hudfan_no" - var/obj/item/clothing/under/U = get_item_by_slot(ITEM_SLOT_ICLOTHING) - if(!U) + + var/obj/item/clothing/under/undershirt = w_uniform + if(!istype(undershirt)) set_hud_image_inactive(FAN_HUD) return - if(istype(U.attached_accessory, /obj/item/clothing/accessory/mime_fan_pin)) - holder.icon_state = "mime_fan_pin" + for(var/accessory in undershirt.attached_accessories) + if(istype(accessory, /obj/item/clothing/accessory/mime_fan_pin)) + holder.icon_state = "mime_fan_pin" + break + + if(istype(accessory, /obj/item/clothing/accessory/clown_enjoyer_pin)) + holder.icon_state = "clown_enjoyer_pin" + break - else if(istype(U.attached_accessory, /obj/item/clothing/accessory/clown_enjoyer_pin)) - holder.icon_state = "clown_enjoyer_pin" set_hud_image_active(FAN_HUD) return diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm index 83c1717fc4485b..fdb212266c3097 100644 --- a/code/game/machinery/washing_machine.dm +++ b/code/game/machinery/washing_machine.dm @@ -293,7 +293,7 @@ GLOBAL_LIST_INIT(dye_registry, list( if(.) var/obj/item/clothing/under/U = . can_adjust = initial(U.can_adjust) - if(!can_adjust && adjusted) //we deadjust the uniform if it's now unadjustable + if(!can_adjust && adjusted == ALT_STYLE) //we deadjust the uniform if it's now unadjustable toggle_jumpsuit_adjust() /obj/item/clothing/head/mob_holder/machine_wash(obj/machinery/washing_machine/washer) diff --git a/code/modules/clothing/suits/_suits.dm b/code/modules/clothing/suits/_suits.dm index 621d77f29079ab..0e9efa5b3fb94f 100644 --- a/code/modules/clothing/suits/_suits.dm +++ b/code/modules/clothing/suits/_suits.dm @@ -33,14 +33,16 @@ if(GET_ATOM_BLOOD_DNA_LENGTH(src)) . += mutable_appearance('icons/effects/blood.dmi', "[blood_overlay_type]blood") - var/mob/living/carbon/human/M = loc - if(!ishuman(M) || !M.w_uniform) + var/mob/living/carbon/human/wearer = loc + if(!ishuman(wearer) || !wearer.w_uniform) return - var/obj/item/clothing/under/U = M.w_uniform - if(istype(U) && U.attached_accessory) - var/obj/item/clothing/accessory/A = U.attached_accessory - if(A.above_suit) - . += U.accessory_overlay + var/obj/item/clothing/under/undershirt = wearer.w_uniform + if(!istype(undershirt) || !LAZYLEN(undershirt.attached_accessories)) + return + + var/obj/item/clothing/accessory/displayed = undershirt.attached_accessories[1] + if(displayed.above_suit) + . += undershirt.accessory_overlay /obj/item/clothing/suit/update_clothes_damaged_state(damaged_state = CLOTHING_DAMAGED) ..() diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm index 8e461d959cc0a4..04873edd2268e1 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -11,15 +11,35 @@ drop_sound = 'sound/items/handling/cloth_drop.ogg' pickup_sound = 'sound/items/handling/cloth_pickup.ogg' limb_integrity = 30 + + /// Has this undersuit been freshly laundered and, as such, imparts a mood bonus for wearing + var/freshly_laundered = FALSE + + // Alt style handling + /// Can this suit be adjustd up or down to an alt style + var/can_adjust = TRUE + /// If adjusted what style are we currently using? + var/adjusted = NORMAL_STYLE + /// For adjusted/rolled-down jumpsuits. FALSE = exposes chest and arms, TRUE = exposes arms only + var/alt_covers_chest = FALSE /// The variable containing the flags for how the woman uniform cropping is supposed to interact with the sprite. var/female_sprite_flags = FEMALE_UNIFORM_FULL - var/has_sensor = HAS_SENSORS // For the crew computer + + // Sensor handling + /// Does this undersuit have suit sensors in general + var/has_sensor = HAS_SENSORS + /// Does this undersuit spawn with a random sensor value var/random_sensor = TRUE + /// What is the active sensor mode of this udnersuit var/sensor_mode = NO_SENSORS - var/can_adjust = TRUE - var/adjusted = NORMAL_STYLE - var/alt_covers_chest = FALSE // for adjusted/rolled-down jumpsuits, FALSE = exposes chest and arms, TRUE = exposes arms only - var/obj/item/clothing/accessory/attached_accessory + + // Accessory handling (Can be componentized eventually) + /// The max number of accessories we can have on this suit. + var/max_number_of_accessories = 5 + /// A list of all accessories attached to us. + var/list/obj/item/clothing/accessory/attached_accessories + /// The overlay of the accessory we're demonstrating. Only index 1 will show up. + /// This is the overlay on the MOB, not the item itself. var/mutable_appearance/accessory_overlay supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION @@ -33,32 +53,32 @@ //make the sensor mode favor higher levels, except coords. sensor_mode = pick(SENSOR_VITALS, SENSOR_VITALS, SENSOR_VITALS, SENSOR_LIVING, SENSOR_LIVING, SENSOR_COORDS, SENSOR_COORDS, SENSOR_OFF) register_context() + AddElement(/datum/element/update_icon_updates_onmob, flags = ITEM_SLOT_ICLOTHING|ITEM_SLOT_OCLOTHING, body = TRUE) /obj/item/clothing/under/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) - var/screentip_change = FALSE + . = NONE if(isnull(held_item) && has_sensor == HAS_SENSORS) context[SCREENTIP_CONTEXT_RMB] = "Toggle suit sensors" - screentip_change = TRUE + . = CONTEXTUAL_SCREENTIP_SET + + if(istype(held_item, /obj/item/clothing/accessory) && length(attached_accessories) < max_number_of_accessories) + context[SCREENTIP_CONTEXT_LMB] = "Attach accessory" + . = CONTEXTUAL_SCREENTIP_SET - if(istype(held_item, /obj/item/clothing/accessory) && !attached_accessory) - var/obj/item/clothing/accessory/accessory = held_item - if(accessory.can_attach_accessory(src, user)) - context[SCREENTIP_CONTEXT_LMB] = "Attach accessory" - screentip_change = TRUE + if(LAZYLEN(attached_accessories)) + context[SCREENTIP_CONTEXT_ALT_RMB] = "Remove accessory" + . = CONTEXTUAL_SCREENTIP_SET if(istype(held_item, /obj/item/stack/cable_coil) && has_sensor == BROKEN_SENSORS) context[SCREENTIP_CONTEXT_LMB] = "Repair suit sensors" - screentip_change = TRUE + . = CONTEXTUAL_SCREENTIP_SET - if(attached_accessory) - context[SCREENTIP_CONTEXT_ALT_LMB] = "Remove accessory" - screentip_change = TRUE - else if(can_adjust) - context[SCREENTIP_CONTEXT_ALT_LMB] = adjusted == ALT_STYLE ? "Wear normally" : "Wear casually" - screentip_change = TRUE + if(can_adjust && adjusted != DIGITIGRADE_STYLE) + context[SCREENTIP_CONTEXT_ALT_LMB] = "Wear [adjusted == ALT_STYLE ? "normally" : "casually"]" + . = CONTEXTUAL_SCREENTIP_SET - return screentip_change ? CONTEXTUAL_SCREENTIP_SET : NONE + return . /obj/item/clothing/under/worn_overlays(mutable_appearance/standing, isinhands = FALSE) . = ..() @@ -72,15 +92,18 @@ if(accessory_overlay) . += accessory_overlay -/obj/item/clothing/under/attackby(obj/item/I, mob/user, params) - if((has_sensor == BROKEN_SENSORS) && istype(I, /obj/item/stack/cable_coil)) - var/obj/item/stack/cable_coil/C = I - C.use(1) +/obj/item/clothing/under/attackby(obj/item/attacking_item, mob/user, params) + if(has_sensor == BROKEN_SENSORS && istype(attacking_item, /obj/item/stack/cable_coil)) + var/obj/item/stack/cable_coil/cabling = attacking_item + to_chat(user, span_notice("You repair the suit sensors on [src] with [cabling].")) + cabling.use(1) has_sensor = HAS_SENSORS - to_chat(user,span_notice("You repair the suit sensors on [src] with [C].")) return TRUE - if(!attach_accessory(I, user)) - return ..() + + if(istype(attacking_item, /obj/item/clothing/accessory)) + return attach_accessory(attacking_item, user) + + return ..() /obj/item/clothing/under/attack_hand_secondary(mob/user, params) . = ..() @@ -91,65 +114,53 @@ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN /obj/item/clothing/under/update_clothes_damaged_state(damaged_state = CLOTHING_DAMAGED) - ..() - if(ismob(loc)) - var/mob/M = loc - M.update_worn_undersuit() + . = ..() if(damaged_state == CLOTHING_SHREDDED && has_sensor > NO_SENSORS) has_sensor = BROKEN_SENSORS else if(damaged_state == CLOTHING_PRISTINE && has_sensor == BROKEN_SENSORS) has_sensor = HAS_SENSORS + update_appearance() /obj/item/clothing/under/emp_act(severity) . = ..() if(. & EMP_PROTECT_SELF) return - if(has_sensor > NO_SENSORS) - if(severity <= EMP_HEAVY) - has_sensor = BROKEN_SENSORS - if(ismob(loc)) - var/mob/M = loc - to_chat(M,span_warning("[src]'s sensors short out!")) - else - sensor_mode = pick(SENSOR_OFF, SENSOR_OFF, SENSOR_OFF, SENSOR_LIVING, SENSOR_LIVING, SENSOR_VITALS, SENSOR_VITALS, SENSOR_COORDS) - if(ismob(loc)) - var/mob/M = loc - to_chat(M,span_warning("The sensors on the [src] change rapidly!")) - if(ishuman(loc)) - var/mob/living/carbon/human/ooman = loc - if(ooman.w_uniform == src) - ooman.update_suit_sensors() + if(has_sensor == NO_SENSORS || has_sensor == BROKEN_SENSORS) + return + + if(severity <= EMP_HEAVY) + has_sensor = BROKEN_SENSORS + if(ismob(loc)) + var/mob/M = loc + to_chat(M,span_warning("[src]'s sensors short out!")) + + else + sensor_mode = pick(SENSOR_OFF, SENSOR_OFF, SENSOR_OFF, SENSOR_LIVING, SENSOR_LIVING, SENSOR_VITALS, SENSOR_VITALS, SENSOR_COORDS) + if(ismob(loc)) + var/mob/M = loc + to_chat(M,span_warning("The sensors on the [src] change rapidly!")) + + if(ishuman(loc)) + var/mob/living/carbon/human/ooman = loc + if(ooman.w_uniform == src) + ooman.update_suit_sensors() /obj/item/clothing/under/visual_equipped(mob/user, slot) - ..() - if(adjusted) - adjusted = NORMAL_STYLE - female_sprite_flags = initial(female_sprite_flags) - if(!alt_covers_chest) - body_parts_covered |= CHEST + . = ..() + if(adjusted == ALT_STYLE) + adjust_to_normal() if((supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION) && ishuman(user)) - var/mob/living/carbon/human/H = user - if(H.dna.species.bodytype & BODYTYPE_DIGITIGRADE) + var/mob/living/carbon/human/wearer = user + if(wearer.dna.species.bodytype & BODYTYPE_DIGITIGRADE) adjusted = DIGITIGRADE_STYLE - H.update_worn_undersuit() - - if(attached_accessory && !(slot & ITEM_SLOT_HANDS) && ishuman(user)) - var/mob/living/carbon/human/H = user - attached_accessory.on_uniform_equip(src, user) - H.fan_hud_set_fandom() - if(attached_accessory.above_suit) - H.update_worn_oversuit() - -/obj/item/clothing/under/dropped(mob/user) - if(attached_accessory) - attached_accessory.on_uniform_dropped(src, user) - if(ishuman(user)) - var/mob/living/carbon/human/H = user - H.fan_hud_set_fandom() - if(attached_accessory.above_suit) - H.update_worn_oversuit() + update_appearance() + +/obj/item/clothing/under/equipped(mob/living/user, slot) ..() + if((slot & ITEM_SLOT_ICLOTHING) && freshly_laundered) + freshly_laundered = FALSE + user.add_mood_event("fresh_laundry", /datum/mood_event/fresh_laundry) /mob/living/carbon/human/update_suit_sensors() . = ..() @@ -165,78 +176,98 @@ /mob/living/carbon/human/dummy/update_sensor_list() return -/obj/item/clothing/under/proc/attach_accessory(obj/item/tool, mob/user, notifyAttach = 1) - . = FALSE - if(!istype(tool, /obj/item/clothing/accessory)) +// End suit sensor handling + +/// Attach the passed accessory to the clothing item +/obj/item/clothing/under/proc/attach_accessory(obj/item/clothing/accessory/accessory, mob/living/user, attach_message = TRUE) + if(!istype(accessory)) return - var/obj/item/clothing/accessory/accessory = tool - if(attached_accessory) + if(length(attached_accessories) >= max_number_of_accessories) if(user) - to_chat(user, span_warning("[src] already has an accessory.")) + balloon_alert(user, "too many accessories!") return - if(!accessory.can_attach_accessory(src, user)) //Make sure the suit has a place to put the accessory. + if(!accessory.can_attach_accessory(src, user)) return if(user && !user.temporarilyRemoveItemFromInventory(accessory)) return if(!accessory.attach(src, user)) return - . = TRUE - if(user && notifyAttach) - to_chat(user, span_notice("You attach [accessory] to [src].")) + LAZYADD(attached_accessories, accessory) + accessory.forceMove(src) + // Allow for accessories to react to the acccessory list now + accessory.successful_attach(src) - var/accessory_color = attached_accessory.icon_state - accessory_overlay = mutable_appearance(attached_accessory.worn_icon, "[accessory_color]") - accessory_overlay.alpha = attached_accessory.alpha - accessory_overlay.color = attached_accessory.color + if(user && attach_message) + balloon_alert(user, "accessory attached") + + if(isnull(accessory_overlay)) + create_accessory_overlay() update_appearance() - if(!ishuman(loc)) - return + return TRUE - var/mob/living/carbon/human/holder = loc - holder.update_worn_undersuit() - holder.update_worn_oversuit() - holder.fan_hud_set_fandom() +/// Removes (pops) the topmost accessory from the accessories list and puts it in the user's hands if supplied +/obj/item/clothing/under/proc/pop_accessory(mob/living/user, attach_message = TRUE) + var/obj/item/clothing/accessory/popped_accessory = attached_accessories[1] + remove_accessory(popped_accessory) -/obj/item/clothing/under/proc/remove_accessory(mob/user) - . = FALSE - if(!isliving(user)) - return - if(!can_use(user)) + if(!user) return - if(!attached_accessory) - return + user.put_in_hands(popped_accessory) + if(attach_message) + popped_accessory.balloon_alert(user, "accessory removed") - . = TRUE - var/obj/item/clothing/accessory/accessory = attached_accessory - attached_accessory.detach(src, user) - if(user.put_in_hands(accessory)) - to_chat(user, span_notice("You detach [accessory] from [src].")) - else - to_chat(user, span_notice("You detach [accessory] from [src] and it falls on the floor.")) +/// Removes the passed accesory from our accessories list +/obj/item/clothing/under/proc/remove_accessory(obj/item/clothing/accessory/removed) + if(removed == attached_accessories[1]) + accessory_overlay = null + + // Remove it from the list before detaching + LAZYREMOVE(attached_accessories, removed) + removed.detach(src) + + if(isnull(accessory_overlay) && LAZYLEN(attached_accessories)) + create_accessory_overlay() update_appearance() - if(!ishuman(loc)) - return - var/mob/living/carbon/human/holder = loc - holder.update_worn_undersuit() - holder.update_worn_oversuit() - holder.fan_hud_set_fandom() +/// Handles creating the worn overlay mutable appearance +/// Only the first accessory attached is displayed (currently) +/obj/item/clothing/under/proc/create_accessory_overlay() + var/obj/item/clothing/accessory/prime_accessory = attached_accessories[1] + accessory_overlay = mutable_appearance(prime_accessory.worn_icon, prime_accessory.icon_state) + accessory_overlay.alpha = prime_accessory.alpha + accessory_overlay.color = prime_accessory.color +/obj/item/clothing/under/Exited(atom/movable/gone, direction) + . = ..() + // If one of our accessories was moved out, handle it + if(gone in attached_accessories) + remove_accessory(gone) + +/// Helper to remove all attachments to the passed location +/obj/item/clothing/under/proc/dump_attachments(atom/drop_to = drop_location()) + for(var/obj/item/clothing/accessory/worn_accessory as anything in attached_accessories) + remove_accessory(worn_accessory) + worn_accessory.forceMove(drop_to) + +/obj/item/clothing/under/atom_destruction(damage_flag) + dump_attachments() + return ..() + +/obj/item/clothing/under/Destroy() + QDEL_LAZYLIST(attached_accessories) + return ..() /obj/item/clothing/under/examine(mob/user) . = ..() if(can_adjust) - if(adjusted == ALT_STYLE) - . += "Alt-click on [src] to wear it normally." - else - . += "Alt-click on [src] to wear it casually." - if (has_sensor == BROKEN_SENSORS) - . += "Its sensors appear to be shorted out." + . += "Alt-click on [src] to wear it [adjusted == ALT_STYLE ? "normally" : "casually"]." + if(has_sensor == BROKEN_SENSORS) + . += "Its sensors appear to be shorted out. You could repair it with some cabling." else if(has_sensor > NO_SENSORS) switch(sensor_mode) if(SENSOR_OFF) @@ -247,48 +278,34 @@ . += "Its vital tracker appears to be enabled." if(SENSOR_COORDS) . += "Its vital tracker and tracking beacon appear to be enabled." - if(attached_accessory) - . += "\A [attached_accessory] is attached to it." + if(LAZYLEN(attached_accessories)) + var/list/accessories = list_accessories_with_icon(user) + . += "It has [english_list(accessories)] attached." + . += "Alt-Right-Click to remove [attached_accessories[1]]." + +/// Helper to list out all accessories with an icon besides it, for use in examine +/obj/item/clothing/under/proc/list_accessories_with_icon(mob/user) + var/list/all_accessories = list() + for(var/obj/item/clothing/accessory/attached as anything in attached_accessories) + all_accessories += attached.get_examine_string(user) + + return all_accessories /obj/item/clothing/under/verb/toggle() set name = "Adjust Suit Sensors" set category = "Object" set src in usr var/mob/user_mob = usr - if (isdead(user_mob)) - return - if (!can_use(user_mob)) - return - if(has_sensor == LOCKED_SENSORS) - to_chat(user_mob, "The controls are locked.") - return - if(has_sensor == BROKEN_SENSORS) - to_chat(user_mob, "The sensors have shorted out!") - return - if(has_sensor <= NO_SENSORS) - to_chat(user_mob, "This suit does not have any sensors.") + if(!can_toggle_sensors(user_mob)) return var/list/modes = list("Off", "Binary vitals", "Exact vitals", "Tracking beacon") var/switchMode = tgui_input_list(user_mob, "Select a sensor mode", "Suit Sensors", modes, modes[sensor_mode + 1]) if(isnull(switchMode)) return - - if (!can_use(user_mob)) //make sure they didn't hold the window open. - return - if(get_dist(user_mob, src) > 1) - to_chat(user_mob, span_warning("You have moved too far away!")) + if(!can_toggle_sensors(user_mob)) return - if(has_sensor == LOCKED_SENSORS) - to_chat(user_mob, "The controls are locked.") - return - if(has_sensor == BROKEN_SENSORS) - to_chat(user_mob, "The sensors have shorted out!") - return - if(has_sensor <= NO_SENSORS) - to_chat(user_mob, "This suit does not have any sensors.") - return sensor_mode = modes.Find(switchMode) - 1 if (loc == user_mob) switch(sensor_mode) @@ -306,80 +323,116 @@ if(H.w_uniform == src) H.update_suit_sensors() +/// Checks if the toggler is allowed to toggle suit sensors currently +/obj/item/clothing/under/proc/can_toggle_sensors(mob/toggler) + if(!can_use(toggler) || toggler.stat == DEAD) //make sure they didn't hold the window open. + return FALSE + if(get_dist(toggler, src) > 1) + balloon_alert(toggler, "too far!") + return FALSE + + switch(has_sensor) + if(LOCKED_SENSORS) + balloon_alert(toggler, "sensor controls locked!") + return FALSE + if(BROKEN_SENSORS) + balloon_alert(toggler, "sensors shorted!") + return FALSE + if(NO_SENSORS) + balloon_alert(toggler, "no sensors to ajdust!") + return FALSE + + return TRUE + /obj/item/clothing/under/AltClick(mob/user) . = ..() if(.) return + if(!can_adjust) + balloon_alert(user, "can't be adjusted!") + return + if(!can_use(user)) + return + rolldown() + +/obj/item/clothing/under/alt_click_secondary(mob/user) + . = ..() + if(.) + return + + if(!LAZYLEN(attached_accessories)) + balloon_alert(user, "no accessories to remove!") + return if(!user.can_perform_action(src, NEED_DEXTERITY)) return - if(attached_accessory) - remove_accessory(user) - else - rolldown() + + pop_accessory(user) /obj/item/clothing/under/verb/jumpsuit_adjust() set name = "Adjust Jumpsuit Style" set category = null set src in usr - rolldown() -/obj/item/clothing/under/proc/rolldown() - if(!can_use(usr)) - return if(!can_adjust) - to_chat(usr, span_warning("You cannot wear this suit any differently!")) + balloon_alert(usr, "can't be adjusted!") + return + if(!can_use(usr)) return + rolldown() + +/obj/item/clothing/under/proc/rolldown() if(toggle_jumpsuit_adjust()) to_chat(usr, span_notice("You adjust the suit to wear it more casually.")) else to_chat(usr, span_notice("You adjust the suit back to normal.")) - if(ishuman(usr)) - var/mob/living/carbon/human/H = usr - H.update_worn_undersuit() - H.update_body() + update_appearance() + +/// Helper to toggle the jumpsuit style, if possible +/// Returns the new state /obj/item/clothing/under/proc/toggle_jumpsuit_adjust() - if(adjusted == DIGITIGRADE_STYLE) - return - adjusted = !adjusted - if(adjusted) - if(alt_covers_chest) //For snowflake suits that do NOT expose the chest. //MONKESTATION EDIT + switch(adjusted) + if(DIGITIGRADE_STYLE) return - if(!(female_sprite_flags & FEMALE_UNIFORM_TOP_ONLY)) - female_sprite_flags = NO_FEMALE_UNIFORM - if(!alt_covers_chest) // for the special snowflake suits that expose the chest when adjusted (and also the arms, realistically) - body_parts_covered &= ~CHEST - body_parts_covered &= ~ARMS - else - female_sprite_flags = initial(female_sprite_flags) - if(!alt_covers_chest) - body_parts_covered |= CHEST - body_parts_covered |= ARMS - if(!LAZYLEN(damage_by_parts)) - return adjusted - for(var/zone in list(BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) // ugly check to make sure we don't reenable protection on a disabled part - if(damage_by_parts[zone] > limb_integrity) - body_parts_covered &= body_zone2cover_flags(zone) - return adjusted -/obj/item/clothing/under/rank - dying_key = DYE_REGISTRY_UNDER + if(NORMAL_STYLE) + adjust_to_alt() -/obj/item/clothing/under/proc/dump_attachment() - if(!attached_accessory) - return - var/atom/drop_location = drop_location() - attached_accessory.transform *= 2 - attached_accessory.pixel_x -= 8 - attached_accessory.pixel_y += 8 - if(drop_location) - attached_accessory.forceMove(drop_location) - cut_overlays() - attached_accessory = null - accessory_overlay = null - update_appearance() + if(ALT_STYLE) + adjust_to_normal() -/obj/item/clothing/under/rank/atom_destruction(damage_flag) - dump_attachment() + SEND_SIGNAL(src, COMSIG_CLOTHING_UNDER_ADJUSTED) + return adjusted + +/// Helper to reset to normal jumpsuit state +/obj/item/clothing/under/proc/adjust_to_normal() + adjusted = NORMAL_STYLE + female_sprite_flags = initial(female_sprite_flags) + if(!alt_covers_chest) + body_parts_covered |= CHEST + body_parts_covered |= ARMS + if(LAZYLEN(damage_by_parts)) + // ugly check to make sure we don't reenable protection on a disabled part + for(var/zone in list(BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) + if(damage_by_parts[zone] > limb_integrity) + body_parts_covered &= body_zone2cover_flags(zone) + +/// Helper to adjust to alt jumpsuit state +/obj/item/clothing/under/proc/adjust_to_alt() + adjusted = ALT_STYLE + if(alt_covers_chest) //For snowflake suits that do NOT expose the chest. //MONKESTATION EDIT + return + if(!(female_sprite_flags & FEMALE_UNIFORM_TOP_ONLY)) + female_sprite_flags = NO_FEMALE_UNIFORM + if(!alt_covers_chest) // for the special snowflake suits that expose the chest when adjusted (and also the arms, realistically) + body_parts_covered &= ~CHEST + body_parts_covered &= ~ARMS + +/obj/item/clothing/under/can_use(mob/user) + if(ismob(user) && !user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING)) + return FALSE return ..() + +/obj/item/clothing/under/rank + dying_key = DYE_REGISTRY_UNDER diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm deleted file mode 100755 index a10cabfaf06549..00000000000000 --- a/code/modules/clothing/under/accessories.dm +++ /dev/null @@ -1,505 +0,0 @@ -/obj/item/clothing/accessory //Ties moved to neck slot items, but as there are still things like medals and armbands, this accessory system is being kept as-is - name = "Accessory" - desc = "Something has gone wrong!" - icon = 'icons/obj/clothing/accessories.dmi' - worn_icon = 'icons/mob/clothing/accessories.dmi' - icon_state = "plasma" - inhand_icon_state = "" //no inhands - slot_flags = 0 - w_class = WEIGHT_CLASS_SMALL - /// Whether or not the accessory displays through suits and the like. - var/above_suit = TRUE - /// TRUE if shown as a small icon in corner, FALSE if overlayed - var/minimize_when_attached = TRUE - /// What equipment slot the accessory attaches to. - var/attachment_slot = CHEST - -/obj/item/clothing/accessory/proc/can_attach_accessory(obj/item/clothing/U, mob/user) - if(!attachment_slot || (U && U.body_parts_covered & attachment_slot)) - return TRUE - if(user) - to_chat(user, span_warning("There doesn't seem to be anywhere to put [src]...")) - -/obj/item/clothing/accessory/proc/attach(obj/item/clothing/under/U, user) - if(atom_storage) - if(U.atom_storage) - return FALSE - U.clone_storage(atom_storage) - U.atom_storage.set_real_location(src) - U.attached_accessory = src - forceMove(U) - layer = FLOAT_LAYER - plane = FLOAT_PLANE - if(minimize_when_attached) - transform *= 0.5 //halve the size so it doesn't overpower the under - pixel_x += 8 - pixel_y -= 8 - U.add_overlay(src) - - U.set_armor(U.get_armor().add_other_armor(get_armor())) - - if(isliving(user)) - on_uniform_equip(U, user) - - return TRUE - -/obj/item/clothing/accessory/proc/detach(obj/item/clothing/under/U, user) - if(U.atom_storage && U.atom_storage.real_location?.resolve() == src) - QDEL_NULL(U.atom_storage) - - U.set_armor(U.get_armor().subtract_other_armor(get_armor())) - - if(isliving(user)) - on_uniform_dropped(U, user) - - if(minimize_when_attached) - transform *= 2 - pixel_x -= 8 - pixel_y += 8 - layer = initial(layer) - SET_PLANE_IMPLICIT(src, initial(plane)) - U.cut_overlays() - U.attached_accessory = null - U.accessory_overlay = null - - -/obj/item/clothing/accessory/proc/on_uniform_equip(obj/item/clothing/under/U, user) - return - -/obj/item/clothing/accessory/proc/on_uniform_dropped(obj/item/clothing/under/U, user) - return - -/obj/item/clothing/accessory/attack_self_secondary(mob/user) - if(user.can_perform_action(src, NEED_DEXTERITY)) - above_suit = !above_suit - to_chat(user, "[src] will be worn [above_suit ? "above" : "below"] your suit.") - return - - return ..() - -/obj/item/clothing/accessory/examine(mob/user) - . = ..() - . += span_notice("\The [src] can be attached to a uniform. Alt-click to remove it once attached.") - . += span_notice("\The [src] can be worn above or below your suit. Right-click to toggle.") - -/obj/item/clothing/accessory/waistcoat - name = "waistcoat" - desc = "For some classy, murderous fun." - icon_state = "waistcoat" - inhand_icon_state = "wcoat" - lefthand_file = 'icons/mob/inhands/clothing/suits_lefthand.dmi' - righthand_file = 'icons/mob/inhands/clothing/suits_righthand.dmi' - minimize_when_attached = FALSE - attachment_slot = null - greyscale_config = /datum/greyscale_config/waistcoat - greyscale_config_worn = /datum/greyscale_config/waistcoat_worn - greyscale_colors = "#414344" - flags_1 = IS_PLAYER_COLORABLE_1 - -/obj/item/clothing/accessory/vest_sheriff - name = "sheriff vest" - desc = "Now you just have to pick your favourite deputy." - icon_state = "vest_sheriff" - lefthand_file = 'icons/mob/inhands/clothing/suits_lefthand.dmi' - righthand_file = 'icons/mob/inhands/clothing/suits_righthand.dmi' - inhand_icon_state = "vest_sheriff" - minimize_when_attached = TRUE - attachment_slot = null - -/obj/item/clothing/accessory/maidcorset - name = "maid corset" - desc = "The final touch that holds it all together." - icon_state = "maidcorset" - inhand_icon_state = "maidapron" - lefthand_file = 'icons/mob/inhands/clothing/suits_lefthand.dmi' - righthand_file = 'icons/mob/inhands/clothing/suits_righthand.dmi' - minimize_when_attached = FALSE - attachment_slot = null - -/obj/item/clothing/accessory/maidapron - name = "maid apron" - desc = "The best part of a maid costume." - icon_state = "maidapron" - inhand_icon_state = "maidapron" - lefthand_file = 'icons/mob/inhands/clothing/suits_lefthand.dmi' - righthand_file = 'icons/mob/inhands/clothing/suits_righthand.dmi' - minimize_when_attached = FALSE - attachment_slot = null - -////////// -//Medals// -////////// - -/obj/item/clothing/accessory/medal - name = "bronze medal" - desc = "A bronze medal." - icon_state = "bronze" - custom_materials = list(/datum/material/iron=HALF_SHEET_MATERIAL_AMOUNT) - resistance_flags = FIRE_PROOF - var/medaltype = "medal" //Sprite used for medalbox - var/commended = FALSE - -//Pinning medals on people -/obj/item/clothing/accessory/medal/attack(mob/living/carbon/human/M, mob/living/user) - if(ishuman(M) && !(user.istate & ISTATE_HARM)) - - if(M.wear_suit) - if((M.wear_suit.flags_inv & HIDEJUMPSUIT)) //Check if the jumpsuit is covered - to_chat(user, span_warning("Medals can only be pinned on jumpsuits.")) - return - - if(M.w_uniform) - var/obj/item/clothing/under/U = M.w_uniform - var/delay = 20 - if(user == M) - delay = 0 - else - user.visible_message(span_notice("[user] is trying to pin [src] on [M]'s chest."), \ - span_notice("You try to pin [src] on [M]'s chest.")) - var/input - if(!commended && user != M) - input = tgui_input_text(user, "Reason for this commendation? It will be recorded by Nanotrasen.", "Commendation", max_length = 140) - if(do_after(user, delay, target = M)) - if(U.attach_accessory(src, user, 0)) //Attach it, do not notify the user of the attachment - if(user == M) - to_chat(user, span_notice("You attach [src] to [U].")) - else - user.visible_message(span_notice("[user] pins \the [src] on [M]'s chest."), \ - span_notice("You pin \the [src] on [M]'s chest.")) - if(input) - SSblackbox.record_feedback("associative", "commendation", 1, list("commender" = "[user.real_name]", "commendee" = "[M.real_name]", "medal" = "[src]", "reason" = input)) - GLOB.commendations += "[user.real_name] awarded [M.real_name] the [name]! \n- [input]" - commended = TRUE - desc += "
The inscription reads: [input] - [user.real_name]" - M.log_message("was given the following commendation by [key_name(user)]: [input]", LOG_GAME, color = "green") - message_admins("[key_name_admin(M)] was given the following commendation by [key_name_admin(user)]: [input]") - add_memory_in_range(M, 7, /datum/memory/received_medal, protagonist = M, deuteragonist = user, medal_type = src, medal_text = input) - - else - to_chat(user, span_warning("Medals can only be pinned on jumpsuits!")) - else - ..() - -/obj/item/clothing/accessory/medal/conduct - name = "distinguished conduct medal" - desc = "A bronze medal awarded for distinguished conduct. Whilst a great honor, this is the most basic award given by Nanotrasen. It is often awarded by a captain to a member of his crew." - -/obj/item/clothing/accessory/medal/bronze_heart - name = "bronze heart medal" - desc = "A bronze heart-shaped medal awarded for sacrifice. It is often awarded posthumously or for severe injury in the line of duty." - icon_state = "bronze_heart" - -/obj/item/clothing/accessory/medal/ribbon - name = "ribbon" - desc = "A ribbon" - icon_state = "cargo" - -/obj/item/clothing/accessory/medal/ribbon/cargo - name = "\"cargo tech of the shift\" award" - desc = "An award bestowed only upon those cargotechs who have exhibited devotion to their duty in keeping with the highest traditions of Cargonia." - -/obj/item/clothing/accessory/medal/silver - name = "silver medal" - desc = "A silver medal." - icon_state = "silver" - medaltype = "medal-silver" - custom_materials = list(/datum/material/silver=HALF_SHEET_MATERIAL_AMOUNT) - -/obj/item/clothing/accessory/medal/silver/valor - name = "medal of valor" - desc = "A silver medal awarded for acts of exceptional valor." - -/obj/item/clothing/accessory/medal/silver/security - name = "robust security award" - desc = "An award for distinguished combat and sacrifice in defence of Nanotrasen's commercial interests. Often awarded to security staff." - -/obj/item/clothing/accessory/medal/silver/excellence - name = "\proper the head of personnel award for outstanding achievement in the field of excellence" - desc = "Nanotrasen's dictionary defines excellence as \"the quality or condition of being excellent\". This is awarded to those rare crewmembers who fit that definition." - -/obj/item/clothing/accessory/medal/silver/bureaucracy - name = "\improper Excellence in Bureaucracy Medal" - desc = "Awarded for exemplary managerial services rendered while under contract with Nanotrasen." - -/obj/item/clothing/accessory/medal/gold - name = "gold medal" - desc = "A prestigious golden medal." - icon_state = "gold" - medaltype = "medal-gold" - custom_materials = list(/datum/material/gold=HALF_SHEET_MATERIAL_AMOUNT) - -/obj/item/clothing/accessory/medal/med_medal - name = "exemplary performance medal" - desc = "A medal awarded to those who have shown distinguished conduct, performance, and initiative within the medical department." - icon_state = "med_medal" - -/obj/item/clothing/accessory/medal/med_medal2 - name = "excellence in medicine medal" - desc = "A medal awarded to those who have shown legendary performance, competence, and initiative beyond all expectations within the medical department." - icon_state = "med_medal2" - -/obj/item/clothing/accessory/medal/gold/captain - name = "medal of captaincy" - desc = "A golden medal awarded exclusively to those promoted to the rank of captain. It signifies the codified responsibilities of a captain to Nanotrasen, and their undisputable authority over their crew." - resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF - -/obj/item/clothing/accessory/medal/gold/heroism - name = "medal of exceptional heroism" - desc = "An extremely rare golden medal awarded only by CentCom. To receive such a medal is the highest honor and as such, very few exist. This medal is almost never awarded to anybody but commanders." - -/obj/item/clothing/accessory/medal/plasma - name = "plasma medal" - desc = "An eccentric medal made of plasma." - icon_state = "plasma" - medaltype = "medal-plasma" - armor_type = /datum/armor/medal_plasma - custom_materials = list(/datum/material/plasma=HALF_SHEET_MATERIAL_AMOUNT) - -/datum/armor/medal_plasma - fire = -10 - -/obj/item/clothing/accessory/medal/plasma/Initialize(mapload) - . = ..() - AddElement(/datum/element/atmos_sensitive, mapload) - -/obj/item/clothing/accessory/medal/plasma/should_atmos_process(datum/gas_mixture/air, exposed_temperature) - return exposed_temperature > 300 - -/obj/item/clothing/accessory/medal/plasma/atmos_expose(datum/gas_mixture/air, exposed_temperature) - atmos_spawn_air("plasma=20;TEMP=[exposed_temperature]") - visible_message(span_danger("\The [src] bursts into flame!"), span_userdanger("Your [src] bursts into flame!")) - qdel(src) - -/obj/item/clothing/accessory/medal/plasma/nobel_science - name = "nobel sciences award" - desc = "A plasma medal which represents significant contributions to the field of science or engineering." - - - -//////////// -//Armbands// -//////////// - -/obj/item/clothing/accessory/armband - name = "red armband" - desc = "A fancy red armband!" - icon_state = "redband" - attachment_slot = null - -/obj/item/clothing/accessory/armband/deputy - name = "security deputy armband" - desc = "An armband, worn by personnel authorized to act as a deputy of station security." - -/obj/item/clothing/accessory/armband/cargo - name = "cargo bay guard armband" - desc = "An armband, worn by the station's security forces to display which department they're assigned to. This one is brown." - icon_state = "cargoband" - -/obj/item/clothing/accessory/armband/engine - name = "engineering guard armband" - desc = "An armband, worn by the station's security forces to display which department they're assigned to. This one is orange with a reflective strip!" - icon_state = "engieband" - -/obj/item/clothing/accessory/armband/science - name = "science guard armband" - desc = "An armband, worn by the station's security forces to display which department they're assigned to. This one is purple." - icon_state = "rndband" - -/obj/item/clothing/accessory/armband/hydro - name = "hydroponics guard armband" - desc = "An armband, worn by the station's security forces to display which department they're assigned to. This one is green and blue." - icon_state = "hydroband" - -/obj/item/clothing/accessory/armband/med - name = "medical guard armband" - desc = "An armband, worn by the station's security forces to display which department they're assigned to. This one is white." - icon_state = "medband" - -/obj/item/clothing/accessory/armband/medblue - name = "medical guard armband" - desc = "An armband, worn by the station's security forces to display which department they're assigned to. This one is white and blue." - icon_state = "medblueband" - -////////////// -//OBJECTION!// -////////////// - -/obj/item/clothing/accessory/lawyers_badge - name = "attorney's badge" - desc = "Fills you with the conviction of JUSTICE. Lawyers tend to want to show it to everyone they meet." - icon_state = "lawyerbadge" - -/obj/item/clothing/accessory/lawyers_badge/attack_self(mob/user) - if(prob(1)) - user.say("The testimony contradicts the evidence!", forced = "attorney's badge") - user.visible_message(span_notice("[user] shows [user.p_their()] attorney's badge."), span_notice("You show your attorney's badge.")) - -/obj/item/clothing/accessory/lawyers_badge/on_uniform_equip(obj/item/clothing/under/U, mob/living/user) - RegisterSignal(user, COMSIG_LIVING_SLAM_TABLE, PROC_REF(table_slam)) - user.bubble_icon = "lawyer" - -/obj/item/clothing/accessory/lawyers_badge/on_uniform_dropped(obj/item/clothing/under/U, mob/living/user) - UnregisterSignal(user, COMSIG_LIVING_SLAM_TABLE) - user.bubble_icon = initial(user.bubble_icon) - -/obj/item/clothing/accessory/lawyers_badge/proc/table_slam(mob/living/source, obj/structure/table/the_table) - SIGNAL_HANDLER - INVOKE_ASYNC(src, PROC_REF(handle_table_slam), source) - -/obj/item/clothing/accessory/lawyers_badge/proc/handle_table_slam(mob/living/user) - user.say("Objection!!", spans = list(SPAN_YELL), forced=TRUE) - -//////////////// -//HA HA! NERD!// -//////////////// -/obj/item/clothing/accessory/pocketprotector - name = "pocket protector" - desc = "Can protect your clothing from ink stains, but you'll look like a nerd if you're using one." - icon_state = "pocketprotector" - -/obj/item/clothing/accessory/pocketprotector/Initialize(mapload) - . = ..() - - create_storage(storage_type = /datum/storage/pockets/pocketprotector) - -/obj/item/clothing/accessory/pocketprotector/detach(obj/item/clothing/under/U, user) - var/drop_loc = drop_location() - for(var/atom/movable/held as anything in src) - held.forceMove(drop_loc) - return ..() - -/obj/item/clothing/accessory/pocketprotector/full/Initialize(mapload) - . = ..() - - new /obj/item/pen/red(src) - new /obj/item/pen(src) - new /obj/item/pen/blue(src) - -/obj/item/clothing/accessory/pocketprotector/cosmetology/Initialize(mapload) - . = ..() - for(var/i in 1 to 3) - new /obj/item/lipstick/random(src) - -//////////////// -//REAL BIG FAN// -//////////////// - -/obj/item/clothing/accessory/clown_enjoyer_pin - name = "\improper Clown Pin" - desc = "A pin to show off your appreciation for clowns and clowning!" - icon_state = "clown_enjoyer_pin" - -/obj/item/clothing/accessory/clown_enjoyer_pin/on_uniform_equip(obj/item/clothing/under/U, user) - var/mob/living/L = user - if(HAS_TRAIT(L, TRAIT_CLOWN_ENJOYER)) - L.add_mood_event("clown_enjoyer_pin", /datum/mood_event/clown_enjoyer_pin) - -/obj/item/clothing/accessory/clown_enjoyer_pin/on_uniform_dropped(obj/item/clothing/under/U, user) - var/mob/living/L = user - if(HAS_TRAIT(L, TRAIT_CLOWN_ENJOYER)) - L.clear_mood_event("clown_enjoyer_pin") - -/obj/item/clothing/accessory/mime_fan_pin - name = "\improper Mime Pin" - desc = "A pin to show off your appreciation for mimes and miming!" - icon_state = "mime_fan_pin" - -/obj/item/clothing/accessory/mime_fan_pin/on_uniform_equip(obj/item/clothing/under/U, user) - var/mob/living/L = user - if(HAS_TRAIT(L, TRAIT_MIME_FAN)) - L.add_mood_event("mime_fan_pin", /datum/mood_event/mime_fan_pin) - -/obj/item/clothing/accessory/mime_fan_pin/on_uniform_dropped(obj/item/clothing/under/U, user) - var/mob/living/L = user - if(HAS_TRAIT(L, TRAIT_MIME_FAN)) - L.clear_mood_event("mime_fan_pin") - -//////////////// -//OONGA BOONGA// -//////////////// - -/obj/item/clothing/accessory/talisman - name = "bone talisman" - desc = "A hunter's talisman, some say the old gods smile on those who wear it." - icon_state = "talisman" - armor_type = /datum/armor/accessory_talisman - attachment_slot = null - -/datum/armor/accessory_talisman - melee = 5 - bullet = 5 - laser = 5 - energy = 5 - bomb = 20 - bio = 20 - acid = 25 - -/obj/item/clothing/accessory/skullcodpiece - name = "skull codpiece" - desc = "A skull shaped ornament, intended to protect the important things in life." - icon_state = "skull" - armor_type = /datum/armor/accessory_skullcodpiece - attachment_slot = GROIN - -/datum/armor/accessory_skullcodpiece - melee = 5 - bullet = 5 - laser = 5 - energy = 5 - bomb = 20 - bio = 20 - acid = 25 - -/obj/item/clothing/accessory/skilt - name = "Sinew Skirt" - desc = "For the last time. IT'S A KILT not a skirt." - icon_state = "skilt" - minimize_when_attached = FALSE - armor_type = /datum/armor/accessory_skilt - attachment_slot = GROIN - -/datum/armor/accessory_skilt - melee = 5 - bullet = 5 - laser = 5 - energy = 5 - bomb = 20 - bio = 20 - acid = 25 - -/obj/item/clothing/accessory/allergy_dogtag - name = "Allergy dogtag" - desc = "Dogtag with a list of your allergies" - icon_state = "allergy" - minimize_when_attached = TRUE - attachment_slot = CHEST - ///Display message - var/display - -/obj/item/clothing/accessory/allergy_dogtag/examine(mob/user) - . = ..() - . += "The dogtag has a listing of allergies : [display]" - -/obj/item/clothing/accessory/allergy_dogtag/on_uniform_equip(obj/item/clothing/under/U, user) - . = ..() - RegisterSignal(U,COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) - -/obj/item/clothing/accessory/allergy_dogtag/on_uniform_dropped(obj/item/clothing/under/U, user) - . = ..() - UnregisterSignal(U,COMSIG_ATOM_EXAMINE) - -///What happens when we examine the uniform -/obj/item/clothing/accessory/allergy_dogtag/proc/on_examine(datum/source, mob/user, list/examine_list) - SIGNAL_HANDLER - examine_list += "The dogtag has a listing of allergies : [display]" - -/obj/item/clothing/accessory/deaf_pin - name = "deaf personnel pin" - desc = "Indicates that the wearer is deaf." - icon_state = "deaf_pin" - -///Awarded for being dutiful and extinguishing the debt from the "Indebted" quirk. -/obj/item/clothing/accessory/debt_payer_pin - name = "debt payer pin" - desc = "I've paid my debt and all I've got was this pin." - icon_state = "debt_payer_pin" diff --git a/code/modules/clothing/under/accessories/_accessories.dm b/code/modules/clothing/under/accessories/_accessories.dm new file mode 100644 index 00000000000000..89f1008479aaf9 --- /dev/null +++ b/code/modules/clothing/under/accessories/_accessories.dm @@ -0,0 +1,185 @@ +/** + * Clothing accessories. + * + * These items can be slotted onto an undershirt to provide a bit of flair. + * + * These should be very light on their effects. Armor should be avoided entirely. + * + * Multiple accessories can be equipped on a mob, and only the firstmost one is shown on their sprite. + * The rest are still shown on examine, but this may create unfair circumstances when you can't examine someone. + */ +/obj/item/clothing/accessory + name = "Accessory" + desc = "Something has gone wrong!" + icon = 'icons/obj/clothing/accessories.dmi' + worn_icon = 'icons/mob/clothing/accessories.dmi' + icon_state = "plasma" + inhand_icon_state = "" //no inhands + slot_flags = NONE + w_class = WEIGHT_CLASS_SMALL + /// Whether or not the accessory displays through suits and the like. + var/above_suit = TRUE + /// TRUE if shown as a small icon in corner, FALSE if overlayed + var/minimize_when_attached = TRUE + /// What equipment slot the accessory attaches to. + /// If NONE, can always attach, while if supplied, can only attach if the clothing covers this slot. + var/attachment_slot = CHEST + +/obj/item/clothing/accessory/Initialize(mapload) + . = ..() + register_context() + +/** + * Can we be attached to the passed clothing article? + */ +/obj/item/clothing/accessory/proc/can_attach_accessory(obj/item/clothing/under/attach_to, mob/living/user) + if(!istype(attach_to)) + CRASH("[type] - can_attach_accessory called with an invalid item to attach to. (got: [attach_to])") + + if(atom_storage && attach_to.atom_storage) + if(user) + attach_to.balloon_alert(user, "isn't compatible!") + return FALSE + + if(attachment_slot && !(attach_to.body_parts_covered & attachment_slot)) + if(user) + attach_to.balloon_alert(user, "can't attach there!") + return FALSE + + return TRUE + +/** + * Actually attach this accessory to the passed clothing article. + * + * The accessory is not yet within the clothing's loc at this point, this hapens after success. + */ +/obj/item/clothing/accessory/proc/attach(obj/item/clothing/under/attach_to, mob/living/attacher) + SHOULD_CALL_PARENT(TRUE) + + if(atom_storage) + attach_to.clone_storage(atom_storage) + attach_to.atom_storage.set_real_location(src) + + var/num_other_accessories = LAZYLEN(attach_to.attached_accessories) + layer = FLOAT_LAYER + clamp(attach_to.max_number_of_accessories - num_other_accessories, 0, 10) + plane = FLOAT_PLANE + + if(minimize_when_attached) + transform *= 0.5 + pixel_x += 8 + pixel_y += (-8 + LAZYLEN(attach_to.attached_accessories) * 2) + + RegisterSignal(attach_to, COMSIG_ITEM_EQUIPPED, PROC_REF(on_uniform_equipped)) + RegisterSignal(attach_to, COMSIG_ITEM_DROPPED, PROC_REF(on_uniform_dropped)) + RegisterSignal(attach_to, COMSIG_CLOTHING_UNDER_ADJUSTED, PROC_REF(on_uniform_adjusted)) + RegisterSignal(attach_to, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_uniform_update)) + + return TRUE + +/// Called after attach is completely successful and the accessory is in the clothing's loc +/obj/item/clothing/accessory/proc/successful_attach(obj/item/clothing/under/attached_to) + SHOULD_CALL_PARENT(TRUE) + + // Do on-equip effects if we're already equipped + var/mob/worn_on = attached_to.loc + if(istype(worn_on)) + on_uniform_equipped(attached_to, worn_on, worn_on.get_slot_by_item(attached_to)) + + SEND_SIGNAL(src, COMSIG_ACCESSORY_ATTACHED, attached_to) + SEND_SIGNAL(attached_to, COMSIG_CLOTHING_ACCESSORY_ATTACHED, src) + +/** + * Detach this accessory from the passed clothing article + * + * We may have exited the clothing's loc at this point + */ +/obj/item/clothing/accessory/proc/detach(obj/item/clothing/under/detach_from) + SHOULD_CALL_PARENT(TRUE) + + if(IS_WEAKREF_OF(src, detach_from.atom_storage?.real_location)) + // Ensure void items do not stick around + atom_storage.close_all() + detach_from.atom_storage.close_all() + // And clean up the storage we made + QDEL_NULL(detach_from.atom_storage) + + UnregisterSignal(detach_from, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED, COMSIG_CLOTHING_UNDER_ADJUSTED, COMSIG_ATOM_UPDATE_OVERLAYS)) + var/mob/dropped_from = detach_from.loc + if(istype(dropped_from)) + on_uniform_dropped(detach_from, dropped_from) + + SEND_SIGNAL(src, COMSIG_ACCESSORY_DETACHED, detach_from) + SEND_SIGNAL(detach_from, COMSIG_CLOTHING_ACCESSORY_DETACHED, src) + + if(minimize_when_attached) + transform *= 2 + // just randomize position + pixel_x = rand(4, -4) + pixel_y = rand(4, -4) + + layer = initial(layer) + SET_PLANE_IMPLICIT(src, initial(plane)) + return TRUE + +/// Signal proc for [COMSIG_ITEM_EQUIPPED] on the uniform we're pinned to +/obj/item/clothing/accessory/proc/on_uniform_equipped(obj/item/clothing/under/source, mob/living/user, slot) + SIGNAL_HANDLER + + if(!(slot & source.slot_flags)) + return + + accessory_equipped(source, user) + +/// Signal proc for [COMSIG_ITEM_DROPPED] on the uniform we're pinned to +/obj/item/clothing/accessory/proc/on_uniform_dropped(obj/item/clothing/under/source, mob/living/user) + SIGNAL_HANDLER + + accessory_dropped(source, user) + user.update_clothing(ITEM_SLOT_ICLOTHING|ITEM_SLOT_OCLOTHING) + +/// Called when the uniform this accessory is pinned to is equipped in a valid slot +/obj/item/clothing/accessory/proc/accessory_equipped(obj/item/clothing/under/clothes, mob/living/user) + return + +/// Called when the uniform this accessory is pinned to is dropped +/obj/item/clothing/accessory/proc/accessory_dropped(obj/item/clothing/under/clothes, mob/living/user) + return + +/// Signal proc for [COMSIG_CLOTHING_UNDER_ADJUSTED] on the uniform we're pinned to +/// Checks if we can no longer be attached to the uniform, and if so, drops us +/obj/item/clothing/accessory/proc/on_uniform_adjusted(obj/item/clothing/under/source) + SIGNAL_HANDLER + + if(can_attach_accessory(source)) + return + + source.remove_accessory(src) + forceMove(source.drop_location()) + source.visible_message(span_warning("[src] falls off of [source]!")) + +/// Signal proc for [COMSIG_ATOM_UPDATE_OVERLAYS] on the uniform we're pinned to to add our overlays to the inventory icon +/obj/item/clothing/accessory/proc/on_uniform_update(obj/item/source, list/overlays) + SIGNAL_HANDLER + + overlays |= src + +/obj/item/clothing/accessory/attack_self_secondary(mob/user) + . = ..() + if(.) + return + if(user.can_perform_action(src, NEED_DEXTERITY)) + above_suit = !above_suit + balloon_alert(user, "wearing [above_suit ? "above" : "below"] suits") + return TRUE + +/obj/item/clothing/accessory/examine(mob/user) + . = ..() + . += "It can be attached to a uniform." + . += "It can be worn above or below your suit. Right-click to toggle." + +/obj/item/clothing/accessory/add_context(atom/source, list/context, obj/item/held_item, mob/user) + if(!isnull(held_item)) + return NONE + + context[SCREENTIP_CONTEXT_RMB] = "Wear [above_suit ? "below" : "above"] suit" + return CONTEXTUAL_SCREENTIP_SET diff --git a/code/modules/clothing/under/accessories/armbands.dm b/code/modules/clothing/under/accessories/armbands.dm new file mode 100644 index 00000000000000..fb26192561182e --- /dev/null +++ b/code/modules/clothing/under/accessories/armbands.dm @@ -0,0 +1,40 @@ +// Armbands, which go around a sleeve of a shirt. +/obj/item/clothing/accessory/armband + name = "red armband" + desc = "A fancy red armband!" + icon_state = "redband" + attachment_slot = NONE + +/obj/item/clothing/accessory/armband/deputy + name = "security deputy armband" + desc = "An armband, worn by personnel authorized to act as a deputy of station security." + +/obj/item/clothing/accessory/armband/cargo + name = "cargo bay guard armband" + desc = "An armband, worn by the station's security forces to display which department they're assigned to. This one is brown." + icon_state = "cargoband" + +/obj/item/clothing/accessory/armband/engine + name = "engineering guard armband" + desc = "An armband, worn by the station's security forces to display which department they're assigned to. This one is orange with a reflective strip!" + icon_state = "engieband" + +/obj/item/clothing/accessory/armband/science + name = "science guard armband" + desc = "An armband, worn by the station's security forces to display which department they're assigned to. This one is purple." + icon_state = "rndband" + +/obj/item/clothing/accessory/armband/hydro + name = "hydroponics guard armband" + desc = "An armband, worn by the station's security forces to display which department they're assigned to. This one is green and blue." + icon_state = "hydroband" + +/obj/item/clothing/accessory/armband/med + name = "medical guard armband" + desc = "An armband, worn by the station's security forces to display which department they're assigned to. This one is white." + icon_state = "medband" + +/obj/item/clothing/accessory/armband/medblue + name = "medical guard armband" + desc = "An armband, worn by the station's security forces to display which department they're assigned to. This one is white and blue." + icon_state = "medblueband" diff --git a/code/modules/clothing/under/accessories/badges.dm b/code/modules/clothing/under/accessories/badges.dm new file mode 100644 index 00000000000000..f5c68023128bd9 --- /dev/null +++ b/code/modules/clothing/under/accessories/badges.dm @@ -0,0 +1,205 @@ +// Badges, pins, and other very small items that slot onto a shirt. +/obj/item/clothing/accessory/lawyers_badge + name = "attorney's badge" + desc = "Fills you with the conviction of JUSTICE. Lawyers tend to want to show it to everyone they meet." + icon_state = "lawyerbadge" + +/obj/item/clothing/accessory/lawyers_badge/interact(mob/user) + . = ..() + if(prob(1)) + user.say("The testimony contradicts the evidence!", forced = "[src]") + user.visible_message(span_notice("[user] shows [user.p_their()] attorney's badge."), span_notice("You show your attorney's badge.")) + +/obj/item/clothing/accessory/lawyers_badge/accessory_equipped(obj/item/clothing/under/clothes, mob/living/user) + RegisterSignal(user, COMSIG_LIVING_SLAM_TABLE, PROC_REF(table_slam)) + user.bubble_icon = "lawyer" + +/obj/item/clothing/accessory/lawyers_badge/accessory_dropped(obj/item/clothing/under/clothes, mob/living/user) + UnregisterSignal(user, COMSIG_LIVING_SLAM_TABLE) + user.bubble_icon = initial(user.bubble_icon) + +/obj/item/clothing/accessory/lawyers_badge/proc/table_slam(mob/living/source, obj/structure/table/the_table) + SIGNAL_HANDLER + + ASYNC + source.say("Objection!!", spans = list(SPAN_YELL), forced = "[src]") + +/obj/item/clothing/accessory/clown_enjoyer_pin + name = "\improper Clown Pin" + desc = "A pin to show off your appreciation for clowns and clowning!" + icon_state = "clown_enjoyer_pin" + +/obj/item/clothing/accessory/clown_enjoyer_pin/can_attach_accessory(obj/item/clothing/under/attach_to, mob/living/user) + . = ..() + if(!.) + return + if(locate(/obj/item/clothing/accessory/mime_fan_pin) in attach_to.attached_accessories) + if(user) + attach_to.balloon_alert(user, "can't pick both sides!") + return FALSE + return TRUE + +/obj/item/clothing/accessory/clown_enjoyer_pin/accessory_equipped(obj/item/clothing/under/clothes, mob/living/user) + if(HAS_TRAIT(user, TRAIT_CLOWN_ENJOYER)) + user.add_mood_event("clown_enjoyer_pin", /datum/mood_event/clown_enjoyer_pin) + if(ishuman(user)) + var/mob/living/carbon/human/human_equipper = user + human_equipper.fan_hud_set_fandom() + +/obj/item/clothing/accessory/clown_enjoyer_pin/accessory_dropped(obj/item/clothing/under/clothes, mob/living/user) + user.clear_mood_event("clown_enjoyer_pin") + if(ishuman(user)) + var/mob/living/carbon/human/human_equipper = user + human_equipper.fan_hud_set_fandom() + +/obj/item/clothing/accessory/mime_fan_pin + name = "\improper Mime Pin" + desc = "A pin to show off your appreciation for mimes and miming!" + icon_state = "mime_fan_pin" + +/obj/item/clothing/accessory/mime_fan_pin/can_attach_accessory(obj/item/clothing/under/attach_to, mob/living/user) + . = ..() + if(!.) + return + if(locate(/obj/item/clothing/accessory/clown_enjoyer_pin) in attach_to.attached_accessories) + if(user) + attach_to.balloon_alert(user, "can't pick both sides!") + return FALSE + return TRUE + +/obj/item/clothing/accessory/mime_fan_pin/accessory_equipped(obj/item/clothing/under/clothes, mob/living/user) + if(HAS_TRAIT(user, TRAIT_MIME_FAN)) + user.add_mood_event("mime_fan_pin", /datum/mood_event/mime_fan_pin) + if(ishuman(user)) + var/mob/living/carbon/human/human_equipper = user + human_equipper.fan_hud_set_fandom() + +/obj/item/clothing/accessory/mime_fan_pin/accessory_dropped(obj/item/clothing/under/clothes, mob/living/user) + user.clear_mood_event("mime_fan_pin") + if(ishuman(user)) + var/mob/living/carbon/human/human_equipper = user + human_equipper.fan_hud_set_fandom() + +/obj/item/clothing/accessory/pocketprotector + name = "pocket protector" + desc = "Can protect your clothing from ink stains, but you'll look like a nerd if you're using one." + icon_state = "pocketprotector" + +/obj/item/clothing/accessory/pocketprotector/Initialize(mapload) + . = ..() + create_storage(storage_type = /datum/storage/pockets/pocketprotector) + +/obj/item/clothing/accessory/pocketprotector/can_attach_accessory(obj/item/clothing/under/attach_to, mob/living/user) + . = ..() + if(!.) + return + + if(!isnull(attach_to.atom_storage)) + if(user) + attach_to.balloon_alert(user, "not compatible!") + return FALSE + return TRUE + +/obj/item/clothing/accessory/pocketprotector/full + +/obj/item/clothing/accessory/pocketprotector/full/Initialize(mapload) + . = ..() + new /obj/item/pen/red(src) + new /obj/item/pen(src) + new /obj/item/pen/blue(src) + +/obj/item/clothing/accessory/pocketprotector/cosmetology + +/obj/item/clothing/accessory/pocketprotector/cosmetology/Initialize(mapload) + . = ..() + for(var/i in 1 to 3) + new /obj/item/lipstick/random(src) + +/obj/item/clothing/accessory/dogtag + name = "Dogtag" + desc = "Can't wear a collar, but this is fine?" + icon_state = "allergy" + attachment_slot = NONE // actually NECK but that doesn't make sense + /// What message is displayed when our dogtags / its clothes / its wearer is examined + var/display = "Nothing!" + +/obj/item/clothing/accessory/dogtag/examine(mob/user) + . = ..() + . += display + +// Examining the clothes will display the examine message of the dogtag +/obj/item/clothing/accessory/dogtag/attach(obj/item/clothing/under/attach_to, mob/living/attacher) + . = ..() + if(!.) + return + RegisterSignal(attach_to, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + +/obj/item/clothing/accessory/dogtag/detach(obj/item/clothing/under/detach_from) + . = ..() + UnregisterSignal(detach_from, COMSIG_ATOM_EXAMINE) + +// Double examining the person wearing the clothes will display the examine message of the dogtag +/obj/item/clothing/accessory/dogtag/accessory_equipped(obj/item/clothing/under/clothes, mob/living/user) + RegisterSignal(user, COMSIG_ATOM_EXAMINE_MORE, PROC_REF(on_examine)) + +/obj/item/clothing/accessory/dogtag/accessory_dropped(obj/item/clothing/under/clothes, mob/living/user) + UnregisterSignal(user, COMSIG_ATOM_EXAMINE_MORE) + +/// Adds the examine message to the clothes and mob. +/obj/item/clothing/accessory/dogtag/proc/on_examine(datum/source, mob/user, list/examine_list) + SIGNAL_HANDLER + + // Only show the examine message if we're close (2 tiles) + if(!IN_GIVEN_RANGE(get_turf(user), get_turf(src), 2)) + return + + if(ismob(source)) + // Examining a mob wearing the clothes, wearing the dogtag will also show the message + examine_list += "A dogtag is hanging around [source.p_their()] neck: [display]" + else + examine_list += "A dogtag is attached to [source]: [display]" + +/obj/item/clothing/accessory/dogtag/allergy + name = "Allergy dogtag" + desc = "A dogtag with a listing of allergies." + +/obj/item/clothing/accessory/dogtag/allergy/Initialize(mapload, allergy_string) + . = ..() + if(allergy_string) + display = span_notice("The dogtag has a listing of allergies: [allergy_string]") + else + display = span_notice("The dogtag is all scratched up.") + +/// Reskins for the pride pin accessory, mapped by display name to icon state +GLOBAL_LIST_INIT(pride_pin_reskins, list( + "Rainbow Pride" = "pride", + "Bisexual Pride" = "pride_bi", + "Pansexual Pride" = "pride_pan", + "Asexual Pride" = "pride_ace", + "Non-binary Pride" = "pride_enby", + "Transgender Pride" = "pride_trans", + "Intersex Pride" = "pride_intersex", + "Lesbian Pride" = "pride_lesbian", +)) + +/obj/item/clothing/accessory/pride + name = "pride pin" + desc = "A Nanotrasen Diversity & Inclusion Center-sponsored holographic pin to show off your pride, reminding the crew of their unwavering commitment to equity, diversity, and inclusion!" + icon_state = "pride" + obj_flags = UNIQUE_RENAME + infinite_reskin = TRUE + +/obj/item/clothing/accessory/pride/Initialize(mapload) + . = ..() + unique_reskin = GLOB.pride_pin_reskins + +///Awarded for being dutiful and extinguishing the debt from the "Indebted" quirk. +/obj/item/clothing/accessory/debt_payer_pin + name = "debt payer pin" + desc = "I've paid my debt and all I've got was this pin." + icon_state = "debt_payer_pin" + +/obj/item/clothing/accessory/deaf_pin + name = "deaf personnel pin" + desc = "Indicates that the wearer is deaf." + icon_state = "deaf_pin" diff --git a/code/modules/clothing/under/accessories/medals.dm b/code/modules/clothing/under/accessories/medals.dm new file mode 100644 index 00000000000000..01f134fa1ba0f0 --- /dev/null +++ b/code/modules/clothing/under/accessories/medals.dm @@ -0,0 +1,140 @@ +/obj/item/clothing/accessory/medal + name = "bronze medal" + desc = "A bronze medal." + icon_state = "bronze" + custom_materials = list(/datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT) + resistance_flags = FIRE_PROOF + /// Sprite used for medalbox + var/medaltype = "medal" + /// Has this been use for a commendation? + var/commended = FALSE + +// If someone adds SHOULD_NOT_SLEEP anywhere up the chain, this will need to be reworked +/obj/item/clothing/accessory/medal/attach(obj/item/clothing/under/attach_to, mob/living/attacher) + if(isnull(attacher)) + // Do normal attach + return ..() + + var/mob/living/distinguished = attach_to.loc + if(!istype(distinguished) || distinguished == attacher) + // Do normal attach + return ..() + + // Do a do_after before we attach, and allow us to include a commendation message. + attacher.visible_message( + span_notice("[attacher] is trying to pin [src] on [distinguished]'s chest."), + span_notice("You try to pin [src] on [distinguished]'s chest."), + ) + + var/input + if(!commended) + input = tgui_input_text(attacher, "Reason for this commendation? It will be recorded by Nanotrasen.", "Commendation", max_length = 140) + + if(!do_after(attacher, 2 SECONDS, distinguished)) + return FALSE + + attacher.visible_message( + span_notice("[attacher] pins [src] on [distinguished]'s chest."), + span_notice("You pin [src] on [distinguished]'s chest."), + ) + if(!input) + return FALSE + + commended = TRUE + SSblackbox.record_feedback("associative", "commendation", 1, list("commender" = "[attacher.real_name]", "commendee" = "[distinguished.real_name]", "medal" = "[src]", "reason" = input)) + GLOB.commendations += "[attacher.real_name] awarded [distinguished.real_name] the [name]! \n- [input]" + desc += "
The inscription reads: [input] - [attacher.real_name]" + distinguished.log_message("was given the following commendation by [key_name(attacher)]: [input]", LOG_GAME, color = "green") + message_admins("[key_name_admin(distinguished)] was given the following commendation by [key_name_admin(attacher)]: [input]") + add_memory_in_range(distinguished, 7, /datum/memory/received_medal, protagonist = distinguished, deuteragonist = attacher, medal_type = src, medal_text = input) + return ..() + +/obj/item/clothing/accessory/medal/conduct + name = "distinguished conduct medal" + desc = "A bronze medal awarded for distinguished conduct. Whilst a great honor, this is the most basic award given by Nanotrasen. It is often awarded by a captain to a member of his crew." + +/obj/item/clothing/accessory/medal/bronze_heart + name = "bronze heart medal" + desc = "A bronze heart-shaped medal awarded for sacrifice. It is often awarded posthumously or for severe injury in the line of duty." + icon_state = "bronze_heart" + +/obj/item/clothing/accessory/medal/ribbon + name = "ribbon" + desc = "A ribbon" + icon_state = "cargo" + +/obj/item/clothing/accessory/medal/ribbon/cargo + name = "\"cargo tech of the shift\" award" + desc = "An award bestowed only upon those cargotechs who have exhibited devotion to their duty in keeping with the highest traditions of Cargonia." + +/obj/item/clothing/accessory/medal/silver + name = "silver medal" + desc = "A silver medal." + icon_state = "silver" + medaltype = "medal-silver" + custom_materials = list(/datum/material/silver = HALF_SHEET_MATERIAL_AMOUNT) + +/obj/item/clothing/accessory/medal/silver/valor + name = "medal of valor" + desc = "A silver medal awarded for acts of exceptional valor." + +/obj/item/clothing/accessory/medal/silver/security + name = "robust security award" + desc = "An award for distinguished combat and sacrifice in defence of Nanotrasen's commercial interests. Often awarded to security staff." + +/obj/item/clothing/accessory/medal/silver/excellence + name = "\proper the head of personnel award for outstanding achievement in the field of excellence" + desc = "Nanotrasen's dictionary defines excellence as \"the quality or condition of being excellent\". This is awarded to those rare crewmembers who fit that definition." + +/obj/item/clothing/accessory/medal/silver/bureaucracy + name = "\improper Excellence in Bureaucracy Medal" + desc = "Awarded for exemplary managerial services rendered while under contract with Nanotrasen." + +/obj/item/clothing/accessory/medal/gold + name = "gold medal" + desc = "A prestigious golden medal." + icon_state = "gold" + medaltype = "medal-gold" + custom_materials = list(/datum/material/gold = HALF_SHEET_MATERIAL_AMOUNT) + +/obj/item/clothing/accessory/medal/med_medal + name = "exemplary performance medal" + desc = "A medal awarded to those who have shown distinguished conduct, performance, and initiative within the medical department." + icon_state = "med_medal" + +/obj/item/clothing/accessory/medal/med_medal2 + name = "excellence in medicine medal" + desc = "A medal awarded to those who have shown legendary performance, competence, and initiative beyond all expectations within the medical department." + icon_state = "med_medal2" + +/obj/item/clothing/accessory/medal/gold/captain + name = "medal of captaincy" + desc = "A golden medal awarded exclusively to those promoted to the rank of captain. It signifies the codified responsibilities of a captain to Nanotrasen, and their undisputable authority over their crew." + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF + +/obj/item/clothing/accessory/medal/gold/heroism + name = "medal of exceptional heroism" + desc = "An extremely rare golden medal awarded only by CentCom. To receive such a medal is the highest honor and as such, very few exist. This medal is almost never awarded to anybody but commanders." + +/obj/item/clothing/accessory/medal/plasma + name = "plasma medal" + desc = "An eccentric medal made of plasma." + icon_state = "plasma" + medaltype = "medal-plasma" + custom_materials = list(/datum/material/plasma = HALF_SHEET_MATERIAL_AMOUNT) + +/obj/item/clothing/accessory/medal/plasma/Initialize(mapload) + . = ..() + AddElement(/datum/element/atmos_sensitive, mapload) + +/obj/item/clothing/accessory/medal/plasma/should_atmos_process(datum/gas_mixture/air, exposed_temperature) + return exposed_temperature > 300 + +/obj/item/clothing/accessory/medal/plasma/atmos_expose(datum/gas_mixture/air, exposed_temperature) + atmos_spawn_air("plasma=20;TEMP=[exposed_temperature]") + visible_message(span_danger("\The [src] bursts into flame!"), span_userdanger("Your [src] bursts into flame!")) + qdel(src) + +/obj/item/clothing/accessory/medal/plasma/nobel_science + name = "nobel sciences award" + desc = "A plasma medal which represents significant contributions to the field of science or engineering." diff --git a/code/modules/clothing/under/accessories/tribal.dm b/code/modules/clothing/under/accessories/tribal.dm new file mode 100644 index 00000000000000..ad55b26fa89fdb --- /dev/null +++ b/code/modules/clothing/under/accessories/tribal.dm @@ -0,0 +1,19 @@ +// Tribal undershirt accessories, made from bone or sinew. +/obj/item/clothing/accessory/talisman + name = "bone talisman" + desc = "A hunter's talisman, some say the old gods smile on those who wear it." + icon_state = "talisman" + attachment_slot = NONE + +/obj/item/clothing/accessory/skullcodpiece + name = "skull codpiece" + desc = "A skull shaped ornament, intended to protect the important things in life." + icon_state = "skull" + attachment_slot = GROIN + +/obj/item/clothing/accessory/skilt + name = "Sinew Skirt" + desc = "For the last time. IT'S A KILT not a skirt." + icon_state = "skilt" + minimize_when_attached = FALSE + attachment_slot = GROIN diff --git a/code/modules/clothing/under/accessories/vests.dm b/code/modules/clothing/under/accessories/vests.dm new file mode 100644 index 00000000000000..a6603941dd08d8 --- /dev/null +++ b/code/modules/clothing/under/accessories/vests.dm @@ -0,0 +1,44 @@ +// Accessories that mostly or entirely cover a shirt. +/obj/item/clothing/accessory/waistcoat + name = "waistcoat" + desc = "For some classy, murderous fun." + icon_state = "waistcoat" + inhand_icon_state = "wcoat" + lefthand_file = 'icons/mob/inhands/clothing/suits_lefthand.dmi' + righthand_file = 'icons/mob/inhands/clothing/suits_righthand.dmi' + minimize_when_attached = FALSE + attachment_slot = NONE + greyscale_config = /datum/greyscale_config/waistcoat + greyscale_config_worn = /datum/greyscale_config/waistcoat_worn + greyscale_colors = "#414344" + flags_1 = IS_PLAYER_COLORABLE_1 + +/obj/item/clothing/accessory/vest_sheriff + name = "sheriff vest" + desc = "Now you just have to pick your favourite deputy." + icon_state = "vest_sheriff" + lefthand_file = 'icons/mob/inhands/clothing/suits_lefthand.dmi' + righthand_file = 'icons/mob/inhands/clothing/suits_righthand.dmi' + inhand_icon_state = "vest_sheriff" + minimize_when_attached = TRUE + attachment_slot = NONE + +/obj/item/clothing/accessory/maidcorset + name = "maid corset" + desc = "The final touch that holds it all together." + icon_state = "maidcorset" + inhand_icon_state = "maidapron" + lefthand_file = 'icons/mob/inhands/clothing/suits_lefthand.dmi' + righthand_file = 'icons/mob/inhands/clothing/suits_righthand.dmi' + minimize_when_attached = FALSE + attachment_slot = NONE + +/obj/item/clothing/accessory/maidapron + name = "maid apron" + desc = "The best part of a maid costume." + icon_state = "maidapron" + inhand_icon_state = "maidapron" + lefthand_file = 'icons/mob/inhands/clothing/suits_lefthand.dmi' + righthand_file = 'icons/mob/inhands/clothing/suits_righthand.dmi' + minimize_when_attached = FALSE + attachment_slot = NONE diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm index df3c48f9883f77..085225e34f3799 100644 --- a/code/modules/holodeck/computer.dm +++ b/code/modules/holodeck/computer.dm @@ -327,9 +327,9 @@ GLOBAL_LIST_INIT(typecache_holodeck_linked_floorcheck_ok, typecacheof(list(/turf for(var/atom/movable/atom_contents as anything in holo_atom) //make sure that things inside of a holoitem are moved outside before destroying it atom_contents.forceMove(target_turf) - if(istype(holo_atom, /obj/item/clothing/under/rank)) + if(istype(holo_atom, /obj/item/clothing/under)) var/obj/item/clothing/under/holo_clothing = holo_atom - holo_clothing.dump_attachment() + holo_clothing.dump_attachments() if(!silent) visible_message(span_notice("[holo_atom] fades away!")) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index f0f402d9228d10..8ea15e6f16289f 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -27,13 +27,14 @@ //uniform if(w_uniform && !(obscured & ITEM_SLOT_ICLOTHING) && !(w_uniform.item_flags & EXAMINE_SKIP)) //accessory - var/accessory_msg + var/accessory_message = "" if(istype(w_uniform, /obj/item/clothing/under)) - var/obj/item/clothing/under/U = w_uniform - if(U.attached_accessory) - accessory_msg += " with [icon2html(U.attached_accessory, user)] \a [U.attached_accessory]" + var/obj/item/clothing/under/undershirt = w_uniform + var/list/accessories = undershirt.list_accessories_with_icon(user) + if(length(accessories)) + accessory_message = " with [english_list(accessories)] attached" - . += "[t_He] [t_is] wearing [w_uniform.get_examine_string(user)][accessory_msg]." + . += "[t_He] [t_is] wearing [w_uniform.get_examine_string(user)][accessory_message]." //head if(head && !(obscured & ITEM_SLOT_HEAD) && !(head.item_flags & EXAMINE_SKIP)) . += "[t_He] [t_is] wearing [head.get_examine_string(user)] on [t_his] head." diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm index b4f171a10cebfb..0693daeb6f415e 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm @@ -184,15 +184,11 @@ icon_state = "hope" resistance_flags = FIRE_PROOF -/obj/item/clothing/accessory/pandora_hope/on_uniform_equip(obj/item/clothing/under/U, user) - var/mob/living/L = user - if(L?.mind) - L.add_mood_event("hope_lavaland", /datum/mood_event/hope_lavaland) - -/obj/item/clothing/accessory/pandora_hope/on_uniform_dropped(obj/item/clothing/under/U, user) - var/mob/living/L = user - if(L?.mind) - L.clear_mood_event("hope_lavaland") +/obj/item/clothing/accessory/pandora_hope/accessory_equipped(obj/item/clothing/under/clothes, mob/living/user) + user.add_mood_event("hope_lavaland", /datum/mood_event/hope_lavaland) + +/obj/item/clothing/accessory/pandora_hope/accessory_dropped(obj/item/clothing/under/clothes, mob/living/user) + user.clear_mood_event("hope_lavaland") #undef SINGULAR_SHOT #undef MAGIC_BOX diff --git a/icons/mob/clothing/accessories.dmi b/icons/mob/clothing/accessories.dmi index c51d64a625df06..dbe0275bc8c0ca 100644 Binary files a/icons/mob/clothing/accessories.dmi and b/icons/mob/clothing/accessories.dmi differ diff --git a/icons/obj/clothing/accessories.dmi b/icons/obj/clothing/accessories.dmi index 05a4a886a9bcdd..f130b71d329540 100644 Binary files a/icons/obj/clothing/accessories.dmi and b/icons/obj/clothing/accessories.dmi differ diff --git a/monkestation/code/modules/clothing/under/_under.dm b/monkestation/code/modules/clothing/under/_under.dm new file mode 100644 index 00000000000000..0cf4a471e76c7a --- /dev/null +++ b/monkestation/code/modules/clothing/under/_under.dm @@ -0,0 +1,32 @@ + +/obj/item/clothing/under + /// A weak reference to the current accessory that's providing armor. + var/datum/weakref/current_armored_accessory + +/obj/item/clothing/under/proc/refresh_armor() + SIGNAL_HANDLER + var/obj/item/clothing/accessory/armored_accesory = current_armored_accessory?.resolve() + if(armored_accesory) + set_armor(get_armor().subtract_other_armor(armored_accesory.get_armor())) + current_armored_accessory = null + for(var/obj/item/clothing/accessory/accessory as anything in attached_accessories) + if(QDELETED(accessory)) + continue + var/datum/armor/armor = accessory.get_armor() + if(!armor || istype(armor, /datum/armor/none)) + continue + set_armor(get_armor().add_other_armor(accessory.get_armor())) + current_armored_accessory = WEAKREF(accessory) + return + +/obj/item/clothing/under/attach_accessory(obj/item/clothing/accessory/accessory, mob/living/user, attach_message = TRUE) + . = ..() + if(!.) + return + RegisterSignal(accessory, COMSIG_QDELETING, PROC_REF(refresh_armor)) + refresh_armor() + +/obj/item/clothing/under/remove_accessory(obj/item/clothing/accessory/removed) + . = ..() + UnregisterSignal(removed, COMSIG_QDELETING) + refresh_armor() diff --git a/monkestation/code/modules/clothing/under/accessories/medals.dm b/monkestation/code/modules/clothing/under/accessories/medals.dm new file mode 100644 index 00000000000000..d3b2619ec9cb92 --- /dev/null +++ b/monkestation/code/modules/clothing/under/accessories/medals.dm @@ -0,0 +1,6 @@ + +/obj/item/clothing/accessory/medal/plasma + armor_type = /datum/armor/medal_plasma + +/datum/armor/medal_plasma + fire = -10 diff --git a/monkestation/code/modules/clothing/under/accessories/tribal.dm b/monkestation/code/modules/clothing/under/accessories/tribal.dm new file mode 100644 index 00000000000000..fb197fba32cc1b --- /dev/null +++ b/monkestation/code/modules/clothing/under/accessories/tribal.dm @@ -0,0 +1,35 @@ +/obj/item/clothing/accessory/talisman + armor_type = /datum/armor/accessory_talisman + +/datum/armor/accessory_talisman + melee = 5 + bullet = 5 + laser = 5 + energy = 5 + bomb = 20 + bio = 20 + acid = 25 + +/obj/item/clothing/accessory/skullcodpiece + armor_type = /datum/armor/accessory_skullcodpiece + +/datum/armor/accessory_skullcodpiece + melee = 5 + bullet = 5 + laser = 5 + energy = 5 + bomb = 20 + bio = 20 + acid = 25 + +/obj/item/clothing/accessory/skilt + armor_type = /datum/armor/accessory_skilt + +/datum/armor/accessory_skilt + melee = 5 + bullet = 5 + laser = 5 + energy = 5 + bomb = 20 + bio = 20 + acid = 25 diff --git a/tgstation.dme b/tgstation.dme index 9a1b8e81c4ceea..cef1effec27f76 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3451,7 +3451,6 @@ #include "code\modules\clothing\suits\wintercoats.dm" #include "code\modules\clothing\suits\wiz_robe.dm" #include "code\modules\clothing\under\_under.dm" -#include "code\modules\clothing\under\accessories.dm" #include "code\modules\clothing\under\color.dm" #include "code\modules\clothing\under\costume.dm" #include "code\modules\clothing\under\ethereal.dm" @@ -3462,6 +3461,12 @@ #include "code\modules\clothing\under\suits.dm" #include "code\modules\clothing\under\syndicate.dm" #include "code\modules\clothing\under\trek.dm" +#include "code\modules\clothing\under\accessories\_accessories.dm" +#include "code\modules\clothing\under\accessories\armbands.dm" +#include "code\modules\clothing\under\accessories\badges.dm" +#include "code\modules\clothing\under\accessories\medals.dm" +#include "code\modules\clothing\under\accessories\tribal.dm" +#include "code\modules\clothing\under\accessories\vests.dm" #include "code\modules\clothing\under\jobs\cargo.dm" #include "code\modules\clothing\under\jobs\centcom.dm" #include "code\modules\clothing\under\jobs\command.dm" @@ -6118,8 +6123,11 @@ #include "monkestation\code\modules\clothing\suits\coats.dm" #include "monkestation\code\modules\clothing\suits\costume.dm" #include "monkestation\code\modules\clothing\suits\toggles.dm" +#include "monkestation\code\modules\clothing\under\_under.dm" #include "monkestation\code\modules\clothing\under\costume.dm" #include "monkestation\code\modules\clothing\under\undersuit.dm" +#include "monkestation\code\modules\clothing\under\accessories\medals.dm" +#include "monkestation\code\modules\clothing\under\accessories\tribal.dm" #include "monkestation\code\modules\clothing\under\civilian\clown_mime.dm" #include "monkestation\code\modules\clothing\under\civilian\rank.dm" #include "monkestation\code\modules\clothing\~donator\clothing.dm"