Files
Aurora.3/code/datums/outfits/outfit.dm
T
SparkyandGitHub 32a63d39a8 Clip-On Radios (#19164)
Adds Clip-On Radios, which can be equipped to both ear or wrist slots,
always appearing on the body, clipped onto your uniform or jacket.
2024-05-22 09:09:35 +00:00

649 lines
20 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// General outfit abstraction.
/// To be used for both a mob's outfit (for a ghostspawner, ship/station job, corpse),
/// where the outfit is applied to the mob.
/// But also for "standalone" outfits (just items spawned in a locker, on the floor),
/// where the outfit items are "spilled" onto the floor (not all items, does not spawn IDs for example).
/obj/outfit
name = "Naked"
icon = 'icons/effects/map_effects.dmi'
icon_state = "outfit"
/// If spilling onto the floor, prob chance for the item to spill.
var/spill_prob = 98
/// If spilling onto the floor, if true, items to spill will be shuffled.
var/spill_shuffle = TRUE
var/collect_not_del = FALSE
//The following vars can either be a path or a list of paths
//If a list of paths is supplied a random item from that list is selected
var/uniform = null
var/suit = null
var/back = null // Mutually exclusive with and will override backpack choices below. Use for RIGs, tanks, etc.
var/belt = null
var/gloves = null
var/wrist = null
var/shoes = null
var/head = null
var/mask = null
var/l_ear = null
var/r_ear = null
var/glasses = null
var/l_pocket = null
var/r_pocket = null
var/suit_store = null
var/accessory = null
var/suit_accessory = null
// species specific item paths, in the form of
// thing = list(SPECIES_NAME = /type/path/here)
// if no path is found, the default fallback (var without the species_ prefix) will be used
var/list/species_head
var/list/species_suit
var/list/species_gloves
var/list/species_shoes
//The following vars must be paths
var/l_hand = null
var/r_hand = null
var/id = null
var/pda = null
var/radio = null
// Must be paths, used to allow player-pref backpack choice
var/allow_backbag_choice = FALSE
var/backpack = /obj/item/storage/backpack
var/backpack_faction
var/satchel = /obj/item/storage/backpack/satchel
var/satchel_faction
var/satchel_alt = /obj/item/storage/backpack/satchel/leather
var/satchel_alt_faction
var/dufflebag = /obj/item/storage/backpack/duffel
var/dufflebag_faction
var/messengerbag = /obj/item/storage/backpack/messenger
var/messengerbag_faction
var/rucksack = /obj/item/storage/backpack/rucksack
var/rucksack_faction
var/pocketbook = /obj/item/storage/backpack/satchel/pocketbook
var/pocketbook_faction
var/allow_pda_choice = FALSE
var/tab_pda = /obj/item/modular_computer/handheld/pda/civilian
var/tablet = /obj/item/modular_computer/handheld/preset/civilian
var/wristbound = /obj/item/modular_computer/handheld/wristbound/preset/pda/civilian
var/allow_headset_choice = FALSE
var/headset = /obj/item/device/radio/headset
var/bowman = /obj/item/device/radio/headset/alt
var/double_headset = /obj/item/device/radio/headset/alt/double
var/wrist_radio = /obj/item/device/radio/headset/wrist
var/clipon_radio = /obj/item/device/radio/headset/wrist/clip
var/id_iff = IFF_DEFAULT // when spawning in, the ID will be set to this iff, preventing friendly fire
var/internals_slot = null //ID of slot containing a gas tank
var/list/backpack_contents = list() //In the list(path=count,otherpath=count) format
var/list/accessory_contents = list()
var/list/belt_contents = list() //In the list(path=count,otherpath=count) format
var/list/implants = null //A list of implants that should be implanted
var/list/spells = list() // A list of spells to grant
/obj/outfit/Initialize(mapload, ...)
. = ..()
// if loc is not null, means the outfit was mapped in or spawned manually
if(loc!=null)
spill()
/// Spawn the items on the loc turf.
/// Delete self later.
/obj/outfit/proc/spill()
// get a list of item types to spawn
var/list/items = list(
uniform,
suit,
back,
belt,
gloves,
wrist,
shoes,
head,
mask,
l_ear,
r_ear,
glasses,
l_pocket,
r_pocket,
suit_store,
accessory,
suit_accessory,
l_hand,
r_hand,
pda,
radio,
backpack,
)
// add contents to the list
for(var/c in backpack_contents)
items += c
for(var/c in accessory_contents)
items += c
for(var/c in belt_contents)
items += c
// shuffle
if(spill_shuffle)
items = shuffle(items)
// go over each item
for(var/i in items)
if(i && prob(spill_prob))
spill_item(i)
// and finally delete self
qdel(src)
/obj/outfit/proc/spill_item(var/path)
if(islist(path))
path = pick(path)
if(path && ispath(path))
new path(loc)
/obj/outfit/proc/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
//to be overriden for customization depending on client prefs,species etc
if(allow_backbag_choice)
switch(H.backbag)
if (OUTFIT_NOTHING)
back = null
if (OUTFIT_BACKPACK)
switch(H.backbag_style)
if (OUTFIT_JOBSPECIFIC)
back = backpack
if (OUTFIT_GENERIC)
back = /obj/item/storage/backpack
if (OUTFIT_FACTIONSPECIFIC)
back = backpack_faction ? backpack_faction : backpack // some may not have faction specific; fall back on job backpack if needed
if (OUTFIT_SATCHEL)
switch(H.backbag_style)
if (OUTFIT_JOBSPECIFIC)
back = satchel
if (OUTFIT_GENERIC)
back = /obj/item/storage/backpack/satchel
if (OUTFIT_FACTIONSPECIFIC)
back = satchel_faction ? satchel_faction : satchel
if (OUTFIT_SATCHEL_ALT) // Leather Satchel
switch(H.backbag_style)
if (OUTFIT_JOBSPECIFIC)
back = satchel_alt
if (OUTFIT_GENERIC)
back = /obj/item/storage/backpack/satchel/leather
if (OUTFIT_FACTIONSPECIFIC)
back = satchel_alt_faction ? satchel_alt_faction : satchel_alt
if (OUTFIT_DUFFELBAG)
switch(H.backbag_style)
if (OUTFIT_JOBSPECIFIC)
back = dufflebag
if (OUTFIT_GENERIC)
back = /obj/item/storage/backpack/duffel
if (OUTFIT_FACTIONSPECIFIC)
back = dufflebag_faction ? dufflebag_faction : dufflebag
if (OUTFIT_MESSENGERBAG)
switch(H.backbag_style)
if (OUTFIT_JOBSPECIFIC)
back = messengerbag
if (OUTFIT_GENERIC)
back = /obj/item/storage/backpack/messenger
if (OUTFIT_FACTIONSPECIFIC)
back = messengerbag_faction ? messengerbag_faction : messengerbag
if (OUTFIT_RUCKSACK)
switch(H.backbag_style)
if (OUTFIT_JOBSPECIFIC)
back = rucksack
if (OUTFIT_GENERIC)
back = /obj/item/storage/backpack/rucksack
if (OUTFIT_FACTIONSPECIFIC)
back = rucksack_faction ? rucksack_faction : rucksack
if (OUTFIT_POCKETBOOK)
switch(H.backbag_style)
if (OUTFIT_JOBSPECIFIC)
back = pocketbook
if (OUTFIT_GENERIC)
back = /obj/item/storage/backpack/satchel/pocketbook
if (OUTFIT_FACTIONSPECIFIC)
back = pocketbook_faction ? pocketbook_faction : pocketbook
else
back = backpack //Department backpack
if (H.backbag_color >= 2) // if theres a color switch em out for a recolorable one
switch (H.backbag)
if (OUTFIT_POCKETBOOK)
back = /obj/item/storage/backpack/satchel/pocketbook/recolorable
if (OUTFIT_RUCKSACK)
back = /obj/item/storage/backpack/rucksack/recolorable
if (OUTFIT_SATCHEL_ALT)
back = /obj/item/storage/backpack/satchel/leather/recolorable
if(back)
if(islist(back))
back = pick(back)
var/obj/item/storage/backpack/B = new back(H)
if (H.backbag == OUTFIT_SATCHEL_ALT || H.backbag == OUTFIT_RUCKSACK || H.backbag == OUTFIT_POCKETBOOK)
switch (H.backbag_color)
if (OUTFIT_NOTHING)
B.color = null
if (OUTFIT_BLUE)
B.color = "#2f4f81"
if (OUTFIT_GREEN)
B.color = "#353727"
if (OUTFIT_NAVY)
B.color = "#2a303b"
if (OUTFIT_TAN)
B.color = "#524a3e"
if (OUTFIT_KHAKI)
B.color = "#baa481"
if (OUTFIT_BLACK)
B.color = "#212121"
if (OUTFIT_OLIVE)
B.color = "#544f3d"
if (OUTFIT_AUBURN)
B.color = "#512828"
if (OUTFIT_BROWN)
B.color = "#3d2711"
else
B.color = null
switch(H.backbag_strap)
if(OUTFIT_NOTHING)
B.alpha_mask = "hidden"
if(OUTFIT_THIN)
B.alpha_mask = "thin"
if(OUTFIT_NORMAL)
B.alpha_mask = "normal"
if(OUTFIT_THICK)
B.alpha_mask = null
if(isvaurca(H, TRUE))
H.equip_or_collect(B, slot_r_hand)
else
H.equip_or_collect(B, slot_back)
var/datum/callback/radio_callback
if(allow_headset_choice)
switch(H.headset_choice)
if (OUTFIT_NOTHING)
l_ear = null
if (OUTFIT_BOWMAN)
l_ear = bowman
if (OUTFIT_DOUBLE)
l_ear = double_headset
if (OUTFIT_WRISTRAD, OUTFIT_THIN_WRISTRAD)
l_ear = null
wrist = wrist_radio
if(H.headset_choice == OUTFIT_THIN_WRISTRAD)
radio_callback = CALLBACK(src, PROC_REF(turn_into_thinset))
if(OUTFIT_CLIPON)
l_ear = null
wrist = clipon_radio
else
l_ear = headset //Department headset
if(l_ear)
equip_item(H, l_ear, slot_l_ear, callback = radio_callback)
else if (wrist)
equip_item(H, wrist, slot_wrists, callback = radio_callback)
/obj/outfit/proc/turn_into_thinset(var/obj/item/device/radio/headset/wrist/radio)
if(istype(radio))
radio.icon_state = replacetext(radio.icon_state, "wrist", "thin")
radio.item_state = replacetext(radio.item_state, "wrist", "thin")
// Used to equip an item to the mob. Mainly to prevent copypasta for collect_not_del.
//override_collect temporarily allows equip_or_collect without enabling it for the job. Mostly used to prevent weirdness with hand equips when the player is missing one
/obj/outfit/proc/equip_item(mob/living/carbon/human/H, path, slot, var/override_collect = FALSE, var/item_color, var/datum/callback/callback)
var/obj/item/I
if(isnum(path)) //Check if parameter is not numeric. Must be a path, list of paths or name of a gear datum
CRASH("Outfit [name] - Parameter path: [path] is numeric.")
if(islist(path)) //If its a list, select a random item
var/itempath = pick(path)
I = new itempath(H)
else if(gear_datums[path]) //If its something else, we´ll check if its a gearpath and try to spawn it
var/datum/gear/G = gear_datums[path]
I = G.spawn_random()
else
I = new path(H) //As fallback treat it as a path
if(I && callback)
callback.Invoke(I)
if(collect_not_del || override_collect)
H.equip_or_collect(I, slot)
else
H.equip_to_slot_or_del(I, slot)
/obj/outfit/proc/equip_uniform_accessory(mob/living/carbon/human/H)
if(!H)
return
if(islist(accessory))
accessory = pick(accessory)
var/obj/item/clothing/under/U = H.get_equipped_item(slot_w_uniform)
if(U)
var/obj/item/clothing/accessory/A = new accessory
U.attach_accessory(H, A)
if(!accessory_contents.len)
return
if(istype(A, /obj/item/clothing/accessory/storage))
var/obj/item/clothing/accessory/storage/S = A
for(var/v in accessory_contents)
var/number = accessory_contents[v]
for(var/i in 1 to number)
var/obj/item/I = new v
S.hold.insert_into_storage(I)
else if(istype(A, /obj/item/clothing/accessory/holster))
var/obj/item/clothing/accessory/holster/holster = A
var/w_type = accessory_contents[1]
var/obj/item/W = new w_type(H.loc)
if(W)
holster.holster(W, H)
/obj/outfit/proc/equip_suit_accessory(mob/living/carbon/human/H)
if(!H)
return
var/obj/item/clothing/suit/S = H.get_equipped_item(slot_wear_suit)
if(S)
var/obj/item/clothing/accessory/A = new suit_accessory
S.attach_accessory(H, A)
/**
* This proc handles actions done after the outfit was equipped,
* eg. toggling internals, personalizations or similar
*
* This process can and does sleep, and should never be waited upon, but only invoked asyncronously (`INVOKE_ASYNC`)
*/
/obj/outfit/proc/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
//to be overriden for changing items post equip (such as toggeling internals, ...)
/obj/outfit/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE)
SHOULD_NOT_SLEEP(TRUE)
//Start with uniform,suit,backpack for additional slots
if(back)
equip_item(H, back, slot_back)
if(uniform)
equip_item(H, uniform, slot_w_uniform)
if(accessory)
equip_uniform_accessory(H)
var/got_suit = FALSE
if(length(species_suit))
var/path = species_suit[H.species.name]
if(path)
got_suit = TRUE
equip_item(H, path, slot_wear_suit)
if(suit_accessory)
equip_suit_accessory(H)
if(suit && !got_suit)
equip_item(H, suit, slot_wear_suit)
if(suit_accessory)
equip_suit_accessory(H)
if(belt)
equip_item(H, belt, slot_belt)
var/got_gloves = FALSE
if(length(species_gloves))
var/path = species_gloves[H.species.name]
if(path)
got_gloves = TRUE
equip_item(H, path, slot_gloves)
if(gloves && !got_gloves)
equip_item(H, gloves, slot_gloves)
if(wrist)
equip_item(H, wrist, slot_wrists)
var/got_shoes = FALSE
if(length(species_shoes))
var/path = species_shoes[H.species.name]
if(path)
got_shoes = TRUE
equip_item(H, path, slot_shoes)
if(shoes && !got_shoes)
equip_item(H, shoes, slot_shoes)
var/got_head = FALSE
if(length(species_head))
var/path = species_head[H.species.name]
if(path)
got_head = TRUE
equip_item(H, path, slot_head)
if(head && !got_head)
equip_item(H, head, slot_head)
if(mask)
equip_item(H, mask, slot_wear_mask)
if(l_ear)
equip_item(H, l_ear, slot_l_ear)
if(r_ear)
equip_item(H, r_ear, slot_r_ear)
if(glasses)
equip_item(H, glasses, slot_glasses)
if(suit_store)
equip_item(H, suit_store, slot_s_store)
//Hand equips. If person is missing an arm or hand it attempts to put it in the other hand.
//Override_collect should attempt to collect any items that can't be equipped regardless of collect_not_del settings for the outfit.
if(l_hand)
var/obj/item/organ/external/O
O = H.organs_by_name[BP_L_HAND]
if(!O || !O.is_usable())
equip_item(H, l_hand, slot_r_hand, override_collect = TRUE)
else
equip_item(H, l_hand, slot_l_hand, override_collect = TRUE)
if(r_hand)
var/obj/item/organ/external/O
O = H.organs_by_name[BP_R_HAND]
if(!O || !O.is_usable())
equip_item(H, r_hand, slot_l_hand, override_collect = TRUE)
else
equip_item(H, r_hand, slot_r_hand, override_collect = TRUE)
if(allow_pda_choice)
switch(H.pda_choice)
if (OUTFIT_NOTHING)
pda = null
if (OUTFIT_TABLET)
pda = tablet
if (OUTFIT_WRISTBOUND)
pda = wristbound
else
pda = tab_pda
if(pda && !visualsOnly)
var/obj/item/I = new pda(H)
switch(H.pda_choice)
if(OUTFIT_TAB_PDA)
I.desc_extended += "For its many years of service, this model has held a virtual monopoly for PDA models for NanoTrasen. The secret? A lapel pin affixed to the back."
if(OUTFIT_PDA_OLD)
I.icon = 'icons/obj/pda_old.dmi'
I.desc_extended += "Nicknamed affectionately as the 'Brick', PDA enthusiasts rejoice with the return of an old favorite, retrofitted to new modular computing standards."
if(OUTFIT_PDA_RUGGED)
I.icon = 'icons/obj/pda_rugged.dmi'
I.desc_extended += "EVA enthusiasts and owners of fat fingers just LOVE the huge tactile buttons provided by this model. Prone to butt-dialing, but don't let that hold you back."
if(OUTFIT_PDA_SLATE)
I.icon = 'icons/obj/pda_slate.dmi'
I.desc_extended += "A bet between an engineer and a disgruntled scientist, it turns out you CAN make a PDA out of an atmospherics scanner. Also, probably don't tell management, just enjoy."
if(OUTFIT_PDA_SMART)
I.icon = 'icons/obj/pda_smart.dmi'
I.desc_extended += "NanoTrasen originally designed this as a portable media player. Unfortunately, Royalty-free and corporate-approved ukulele isn't particularly popular."
I.update_icon()
if(!H.wrists && H.pda_choice == OUTFIT_WRISTBOUND)
H.equip_or_collect(I, slot_wrists)
else
H.equip_or_collect(I, slot_wear_id)
if(!visualsOnly) // Items in pockets or backpack don't show up on mob's icon.
if(l_pocket)
equip_item(H, l_pocket, slot_l_store)
if(r_pocket)
equip_item(H, r_pocket, slot_r_store)
if(H.back) // you would think, right
for(var/path in backpack_contents)
var/number = backpack_contents[path]
for(var/i in 1 to number)
H.equip_or_collect(new path(H), slot_in_backpack)
else
var/obj/item/storage/storage_item
if(!H.l_hand)
storage_item = new /obj/item/storage/bag/plasticbag(H)
H.equip_to_slot_or_del(storage_item, slot_l_hand)
if(!storage_item && !H.r_hand)
storage_item = new /obj/item/storage/bag/plasticbag(H)
H.equip_to_slot_or_del(storage_item, slot_r_hand)
if(storage_item)
for(var/path in backpack_contents)
var/number = backpack_contents[path]
for(var/i in 1 to number)
storage_item.handle_item_insertion(new path(H.loc), TRUE)
for(var/path in belt_contents)
var/number = belt_contents[path]
for(var/i in 1 to number)
H.equip_or_collect(new path(H), slot_in_belt)
if(id)
var/obj/item/modular_computer/personal_computer
if(istype(H.wear_id, /obj/item/modular_computer))
personal_computer = H.wear_id
else if(istype(H.wrists, /obj/item/modular_computer))
personal_computer = H.wrists
var/obj/item/ID = new id(H)
imprint_idcard(H, ID)
if(personal_computer?.card_slot)
addtimer(CALLBACK(src, PROC_REF(register_pda), personal_computer, ID), 2 SECOND)
else
H.equip_or_collect(ID, slot_wear_id)
INVOKE_ASYNC(src, PROC_REF(post_equip), H, visualsOnly)
if(!visualsOnly)
apply_fingerprints(H)
if(implants)
for(var/implant_type in implants)
var/obj/item/implant/I = new implant_type(H)
if(I.implanted(H))
I.forceMove(H)
I.imp_in = H
I.implanted = 1
var/obj/item/organ/external/affected = H.get_organ(BP_HEAD)
affected.implants += I
I.part = affected
if(spells)
for(var/spell in spells)
var/spell/new_spell = new spell
H.add_spell(new_spell)
if(spells[spell] > 1)
for(var/i = 1 to spells[spell])
new_spell.empower_spell()
H.update_body()
return 1
// this proc takes all the scattered voidsuit pieces and reassembles them into one piece
/obj/outfit/proc/organize_voidsuit(mob/living/carbon/human/H, var/add_magboots = TRUE)
var/obj/item/tank/T = H.s_store
H.unEquip(T, TRUE)
var/obj/item/clothing/suit/space/void/VS = H.wear_suit
H.unEquip(VS, TRUE)
var/obj/item/clothing/head/helmet/VH = H.head
H.unEquip(VH, TRUE, VS)
VS.helmet = VH
T.forceMove(VS)
VS.tank = T
if(add_magboots)
var/obj/item/clothing/shoes/magboots/M = new /obj/item/clothing/shoes/magboots(VH)
VS.boots = M
H.equip_to_slot_if_possible(VS, slot_wear_suit)
/obj/outfit/proc/apply_fingerprints(mob/living/carbon/human/H)
if(!istype(H))
return
if(H.back)
H.back.add_fingerprint(H, 1) //The 1 sets a flag to ignore gloves
for(var/obj/item/I in H.back.contents)
I.add_fingerprint(H, 1)
if(H.wear_id)
H.wear_id.add_fingerprint(H, 1)
if(H.w_uniform)
H.w_uniform.add_fingerprint(H, 1)
if(H.wear_suit)
H.wear_suit.add_fingerprint(H, 1)
if(H.wear_mask)
H.wear_mask.add_fingerprint(H, 1)
if(H.head)
H.head.add_fingerprint(H, 1)
if(H.shoes)
H.shoes.add_fingerprint(H, 1)
if(H.gloves)
H.gloves.add_fingerprint(H, 1)
if(H.wrists)
H.wrists.add_fingerprint(H, 1)
if(H.l_ear)
H.l_ear.add_fingerprint(H, 1)
if(H.r_ear)
H.r_ear.add_fingerprint(H, 1)
if(H.glasses)
H.glasses.add_fingerprint(H, 1)
if(H.belt)
H.belt.add_fingerprint(H, 1)
for(var/obj/item/I in H.belt.contents)
I.add_fingerprint(H, 1)
if(H.s_store)
H.s_store.add_fingerprint(H, 1)
if(H.l_store)
H.l_store.add_fingerprint(H, 1)
if(H.r_store)
H.r_store.add_fingerprint(H, 1)
return 1
/obj/outfit/proc/imprint_idcard(mob/living/carbon/human/H, obj/item/card/id/C)
if(istype(C))
C.access = get_id_access(H)
C.rank = get_id_rank(H)
C.assignment = get_id_assignment(H)
addtimer(CALLBACK(H, TYPE_PROC_REF(/mob, set_id_info), C), 1 SECOND) // Delay a moment to allow an icon update to happen.
if(H.mind && H.mind.initial_account)
C.associated_account_number = H.mind.initial_account.account_number
/obj/outfit/proc/register_pda(obj/item/modular_computer/P, obj/item/card/id/I)
if(!P.card_slot)
return
P.card_slot.insert_id(I)
if(P.card_slot.stored_card && !P.hidden)
P.set_autorun("ntnrc_client")
P.enable_computer(null, TRUE) // passing null because we don't want the UI to open
P.minimize_program()
/obj/outfit/proc/get_id_access(mob/living/carbon/human/H)
return list()
/obj/outfit/proc/get_id_assignment(mob/living/carbon/human/H, var/ignore_suffix = FALSE)
. = GetAssignment(H)
if (. && . != "Unassigned" && H?.mind?.selected_faction && !ignore_suffix)
if (H.mind.selected_faction.title_suffix)
. += " ([H.mind.selected_faction.title_suffix])"
/obj/outfit/proc/get_id_rank(mob/living/carbon/human/H)
return GetAssignment(H)