diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index eee0c736662..6ecc676ab9b 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -307,6 +307,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \ new/datum/stack_recipe("display case chassis", /obj/structure/displaycase_chassis, 5, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ new/datum/stack_recipe("wooden buckler", /obj/item/shield/buckler, 20, time = 4 SECONDS, category = CAT_EQUIPMENT), \ new/datum/stack_recipe("apiary", /obj/structure/beebox, 40, time = 5 SECONDS, category = CAT_TOOLS),\ + new/datum/stack_recipe("mannequin", /obj/structure/mannequin/wood, 25, time = 5 SECONDS, one_per_turf = TRUE, category = CAT_ENTERTAINMENT), \ new/datum/stack_recipe("tiki mask", /obj/item/clothing/mask/gas/tiki_mask, 2, category = CAT_CLOTHING), \ new/datum/stack_recipe("smoking pipe", /obj/item/clothing/mask/cigarette/pipe, 2, category = CAT_CLOTHING), \ new/datum/stack_recipe("honey frame", /obj/item/honey_frame, 5, time = 1 SECONDS, category = CAT_TOOLS),\ @@ -730,6 +731,7 @@ GLOBAL_LIST_INIT(plastic_recipes, list( new /datum/stack_recipe("water bottle", /obj/item/reagent_containers/cup/glass/waterbottle/empty, category = CAT_CONTAINERS), \ new /datum/stack_recipe("large water bottle", /obj/item/reagent_containers/cup/glass/waterbottle/large/empty, 3, category = CAT_CONTAINERS), \ new /datum/stack_recipe("colo cups", /obj/item/reagent_containers/cup/glass/colocup, 1, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("mannequin", /obj/structure/mannequin/plastic, 25, time = 5 SECONDS, one_per_turf = TRUE, category = CAT_ENTERTAINMENT), \ new /datum/stack_recipe("wet floor sign", /obj/item/clothing/suit/caution, 2, category = CAT_EQUIPMENT), \ new /datum/stack_recipe("warning cone", /obj/item/clothing/head/cone, 2, category = CAT_EQUIPMENT), \ new /datum/stack_recipe("blank wall sign", /obj/item/sign, 1, category = CAT_FURNITURE))) diff --git a/code/game/objects/structures/mannequin.dm b/code/game/objects/structures/mannequin.dm new file mode 100644 index 00000000000..05e2aa84d0e --- /dev/null +++ b/code/game/objects/structures/mannequin.dm @@ -0,0 +1,276 @@ +#define MANNEQUIN_WOOD "wood" +#define MANNEQUIN_PLASTIC "plastic" + +/// A mannequin! A structure that can display clothing on itself. +/obj/structure/mannequin + name = "mannequin" + desc = "Oh, so this is a dress-up game now." + icon = 'icons/mob/species/human/mannequin.dmi' + icon_state = "mannequin_wood_male" + density = TRUE + resistance_flags = FLAMMABLE + appearance_flags = KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE|LONG_GLIDE + mouse_drag_pointer = MOUSE_ACTIVE_POINTER + pixel_y = 3 + base_pixel_y = 3 + layer = ABOVE_MOB_LAYER + plane = ABOVE_GAME_PLANE + /// Which body type we use, male or female? + var/body_type + /// Material we're used of, wood or plastic? + var/material + /// String for the underwear we use. + var/underwear_name + /// String for the undershirt we use. + var/undershirt_name + /// String for the socks we use. + var/socks_name + /// Static list of slot flags we have clothing slots for. + var/static/list/slot_flags = list( + ITEM_SLOT_HEAD, + ITEM_SLOT_EYES, + ITEM_SLOT_EARS, + ITEM_SLOT_MASK, + ITEM_SLOT_NECK, + ITEM_SLOT_BACK, + ITEM_SLOT_BELT, + ITEM_SLOT_ID, + ITEM_SLOT_ICLOTHING, + ITEM_SLOT_OCLOTHING, + ITEM_SLOT_GLOVES, + ITEM_SLOT_FEET, + ) + /// Assoc list of all item slots (turned to strings) to the items they hold. + var/list/worn_items = list() + +/obj/structure/mannequin/Initialize(mapload) + . = ..() + for(var/slot_flag in slot_flags) + worn_items["[slot_flag]"] = null + if(!body_type) + body_type = pick(MALE, FEMALE) + if(!material) + material = pick("wood", "plastic") + icon_state = "mannequin_[material]_[body_type == FEMALE ? "female" : "male"]" + AddElement(/datum/element/strippable, GLOB.strippable_mannequin_items) + AddComponent(/datum/component/simple_rotation, ROTATION_IGNORE_ANCHORED) + update_appearance() + +/obj/structure/mannequin/Destroy() + QDEL_LIST_ASSOC_VAL(worn_items) + return ..() + +/obj/structure/mannequin/atom_destruction(damage_flag) + for(var/slot_flag in worn_items) + var/obj/item/worn_item = worn_items[slot_flag] + if(worn_item) + worn_item.forceMove(drop_location()) + return ..() + +/obj/structure/mannequin/Exited(atom/movable/gone, direction) + . = ..() + for(var/slot_flag in worn_items) + if(worn_items[slot_flag] == gone) + worn_items[slot_flag] = null + update_appearance() + +/obj/structure/mannequin/wrench_act(mob/living/user, obj/item/tool) + . = ..() + default_unfasten_wrench(user, tool) + return TOOL_ACT_TOOLTYPE_SUCCESS + +/obj/structure/mannequin/update_overlays() + . = ..() + var/mutable_appearance/pedestal = mutable_appearance(icon, "pedestal_[material]") + pedestal.pixel_y = -3 + . += pedestal + var/datum/sprite_accessory/underwear/underwear = GLOB.underwear_list[underwear_name] + if(underwear) + if(body_type == FEMALE && underwear.gender == MALE) + . += wear_female_version(underwear.icon_state, underwear.icon, BODY_LAYER, FEMALE_UNIFORM_FULL) + else + . += mutable_appearance(underwear.icon, underwear.icon_state, -BODY_LAYER) + var/datum/sprite_accessory/undershirt/undershirt = GLOB.undershirt_list[undershirt_name] + if(undershirt) + if(body_type == FEMALE) + . += wear_female_version(undershirt.icon_state, undershirt.icon, BODY_LAYER) + else + . += mutable_appearance(undershirt.icon, undershirt.icon_state, -BODY_LAYER) + var/datum/sprite_accessory/socks/socks = GLOB.socks_list[socks_name] + if(socks) + . += mutable_appearance(socks.icon, socks.icon_state, -BODY_LAYER) + for(var/slot_flag in worn_items) + var/obj/item/worn_item = worn_items[slot_flag] + if(!worn_item) + continue + var/default_layer = 0 + var/default_icon = null + var/female_icon = NO_FEMALE_UNIFORM + switch(text2num(slot_flag)) //this kinda sucks because build worn icon kinda sucks + if(ITEM_SLOT_HEAD) + default_layer = HEAD_LAYER + default_icon = 'icons/mob/clothing/head/default.dmi' + if(ITEM_SLOT_EYES) + default_layer = GLASSES_LAYER + default_icon = 'icons/mob/clothing/eyes.dmi' + if(ITEM_SLOT_EARS) + default_layer = EARS_LAYER + default_icon = 'icons/mob/clothing/ears.dmi' + if(ITEM_SLOT_MASK) + default_layer = FACEMASK_LAYER + default_icon = 'icons/mob/clothing/mask.dmi' + if(ITEM_SLOT_NECK) + default_layer = NECK_LAYER + default_icon = 'icons/mob/clothing/neck.dmi' + if(ITEM_SLOT_BACK) + default_layer = BACK_LAYER + default_icon = 'icons/mob/clothing/back.dmi' + if(ITEM_SLOT_BELT) + default_layer = BELT_LAYER + default_icon = 'icons/mob/clothing/belt.dmi' + if(ITEM_SLOT_ID) + default_layer = ID_LAYER + default_icon = 'icons/mob/clothing/id.dmi' + if(ITEM_SLOT_ICLOTHING) + default_layer = UNIFORM_LAYER + default_icon = DEFAULT_UNIFORM_FILE + if(body_type == FEMALE && istype(worn_item, /obj/item/clothing/under)) + var/obj/item/clothing/under/worn_jumpsuit = worn_item + female_icon = worn_jumpsuit.female_sprite_flags + if(ITEM_SLOT_OCLOTHING) + default_layer = SUIT_LAYER + default_icon = DEFAULT_SUIT_FILE + if(ITEM_SLOT_GLOVES) + default_layer = GLOVES_LAYER + default_icon = 'icons/mob/clothing/hands.dmi' + if(ITEM_SLOT_FEET) + default_layer = SHOES_LAYER + default_icon = DEFAULT_SHOES_FILE + . += worn_item.build_worn_icon(default_layer, default_icon, female_uniform = female_icon) + +/obj/structure/mannequin/attack_hand_secondary(mob/user, list/modifiers) + . = ..() + if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) + return + var/choice = tgui_input_list(user, "Underwear, Undershirt, or Socks?", "Changing", list("Underwear","Undershirt","Socks")) + if(!Adjacent(user)) + return + switch(choice) + if("Underwear") + var/new_undies = tgui_input_list(user, "Select the mannequin's underwear", "Changing", GLOB.underwear_list) + if(new_undies) + underwear_name = new_undies + if("Undershirt") + var/new_undershirt = tgui_input_list(user, "Select the mannequin's undershirt", "Changing", GLOB.undershirt_list) + if(new_undershirt) + undershirt_name = new_undershirt + if("Socks") + var/new_socks = tgui_input_list(user, "Select the mannequin's socks", "Changing", GLOB.socks_list) + if(new_socks) + socks_name = new_socks + update_appearance() + +/obj/structure/mannequin/wood + material = MANNEQUIN_WOOD + +/obj/structure/mannequin/plastic + material = MANNEQUIN_PLASTIC + +GLOBAL_LIST_INIT(strippable_mannequin_items, create_strippable_list(list( + /datum/strippable_item/mannequin_slot/head, + /datum/strippable_item/mannequin_slot/eyes, + /datum/strippable_item/mannequin_slot/ears, + /datum/strippable_item/mannequin_slot/mask, + /datum/strippable_item/mannequin_slot/neck, + /datum/strippable_item/mannequin_slot/back, + /datum/strippable_item/mannequin_slot/belt, + /datum/strippable_item/mannequin_slot/id, + /datum/strippable_item/mannequin_slot/uniform, + /datum/strippable_item/mannequin_slot/suit, + /datum/strippable_item/mannequin_slot/gloves, + /datum/strippable_item/mannequin_slot/feet, +))) + +/datum/strippable_item/mannequin_slot + /// The ITEM_SLOT_* to equip to. + var/item_slot + +/datum/strippable_item/mannequin_slot/get_item(atom/source) + var/obj/structure/mannequin/mannequin_source = source + return istype(mannequin_source) ? mannequin_source.worn_items["[item_slot]"] : null + +/datum/strippable_item/mannequin_slot/try_equip(atom/source, obj/item/equipping, mob/user) + . = ..() + if(!.) + return FALSE + if(!(equipping.slot_flags & item_slot)) + to_chat(user, span_warning("[equipping] won't fit!")) + return FALSE + return TRUE + +/datum/strippable_item/mannequin_slot/finish_equip(atom/source, obj/item/equipping, mob/user) + var/obj/structure/mannequin/mannequin_source = source + if(!istype(mannequin_source)) + return + if(!user.transferItemToLoc(equipping, mannequin_source) || QDELETED(equipping)) + return + mannequin_source.worn_items["[item_slot]"] = equipping + mannequin_source.update_appearance() + +/datum/strippable_item/mannequin_slot/finish_unequip(atom/source, mob/user) + var/obj/structure/mannequin/mannequin_source = source + if(!istype(mannequin_source)) + return + var/obj/item/unequipped = mannequin_source.worn_items["[item_slot]"] + user.put_in_hands(unequipped) + +/datum/strippable_item/mannequin_slot/head + key = STRIPPABLE_ITEM_HEAD + item_slot = ITEM_SLOT_HEAD + +/datum/strippable_item/mannequin_slot/eyes + key = STRIPPABLE_ITEM_EYES + item_slot = ITEM_SLOT_EYES + +/datum/strippable_item/mannequin_slot/ears + key = STRIPPABLE_ITEM_EARS + item_slot = ITEM_SLOT_EARS + +/datum/strippable_item/mannequin_slot/mask + key = STRIPPABLE_ITEM_MASK + item_slot = ITEM_SLOT_MASK + +/datum/strippable_item/mannequin_slot/neck + key = STRIPPABLE_ITEM_NECK + item_slot = ITEM_SLOT_NECK + +/datum/strippable_item/mannequin_slot/back + key = STRIPPABLE_ITEM_BACK + item_slot = ITEM_SLOT_BACK + +/datum/strippable_item/mannequin_slot/belt + key = STRIPPABLE_ITEM_BELT + item_slot = ITEM_SLOT_BELT + +/datum/strippable_item/mannequin_slot/id + key = STRIPPABLE_ITEM_ID + item_slot = ITEM_SLOT_ID + +/datum/strippable_item/mannequin_slot/uniform + key = STRIPPABLE_ITEM_JUMPSUIT + item_slot = ITEM_SLOT_ICLOTHING + +/datum/strippable_item/mannequin_slot/suit + key = STRIPPABLE_ITEM_SUIT + item_slot = ITEM_SLOT_OCLOTHING + +/datum/strippable_item/mannequin_slot/gloves + key = STRIPPABLE_ITEM_GLOVES + item_slot = ITEM_SLOT_GLOVES + +/datum/strippable_item/mannequin_slot/feet + key = STRIPPABLE_ITEM_FEET + item_slot = ITEM_SLOT_FEET + +#undef MANNEQUIN_WOOD +#undef MANNEQUIN_PLASTIC diff --git a/icons/mob/species/human/mannequin.dmi b/icons/mob/species/human/mannequin.dmi new file mode 100644 index 00000000000..b08b50b73c5 Binary files /dev/null and b/icons/mob/species/human/mannequin.dmi differ diff --git a/tgstation.dme b/tgstation.dme index ad6f875ff42..3b64dfaf78f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2107,6 +2107,7 @@ #include "code\game\objects\structures\life_candle.dm" #include "code\game\objects\structures\loom.dm" #include "code\game\objects\structures\maintenance.dm" +#include "code\game\objects\structures\mannequin.dm" #include "code\game\objects\structures\memorial.dm" #include "code\game\objects\structures\mineral_doors.dm" #include "code\game\objects\structures\mirror.dm"