mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-10 09:54:52 +00:00
Merge remote-tracking branch 'citadel/master' into backend_sync
This commit is contained in:
@@ -136,3 +136,6 @@
|
|||||||
|
|
||||||
// paintings
|
// paintings
|
||||||
#define VV_HK_REMOVE_PAINTING "remove_painting"
|
#define VV_HK_REMOVE_PAINTING "remove_painting"
|
||||||
|
|
||||||
|
//outfits
|
||||||
|
#define VV_HK_TO_OUTFIT_EDITOR "outfit_editor"
|
||||||
|
|||||||
@@ -1051,7 +1051,7 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
//For creating consistent icons for human looking simple animals
|
//For creating consistent icons for human looking simple animals
|
||||||
/proc/get_flat_human_icon(icon_id, datum/job/J, datum/preferences/prefs, dummy_key, showDirs = GLOB.cardinals, outfit_override = null)
|
/proc/get_flat_human_icon(icon_id, datum/job/J, datum/preferences/prefs, dummy_key, showDirs = GLOB.cardinals, outfit_override = null, no_anim = FALSE)
|
||||||
var/static/list/humanoid_icon_cache = list()
|
var/static/list/humanoid_icon_cache = list()
|
||||||
if(!icon_id || !humanoid_icon_cache[icon_id])
|
if(!icon_id || !humanoid_icon_cache[icon_id])
|
||||||
var/mob/living/carbon/human/dummy/body = generate_or_wait_for_human_dummy(dummy_key)
|
var/mob/living/carbon/human/dummy/body = generate_or_wait_for_human_dummy(dummy_key)
|
||||||
@@ -1065,10 +1065,9 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
|
|||||||
|
|
||||||
|
|
||||||
var/icon/out_icon = icon('icons/effects/effects.dmi', "nothing")
|
var/icon/out_icon = icon('icons/effects/effects.dmi', "nothing")
|
||||||
for(var/D in showDirs)
|
|
||||||
body.setDir(D)
|
|
||||||
COMPILE_OVERLAYS(body)
|
COMPILE_OVERLAYS(body)
|
||||||
var/icon/partial = getFlatIcon(body)
|
for(var/D in showDirs)
|
||||||
|
var/icon/partial = getFlatIcon(body, defdir = D, no_anim = no_anim)
|
||||||
out_icon.Insert(partial,dir=D)
|
out_icon.Insert(partial,dir=D)
|
||||||
|
|
||||||
humanoid_icon_cache[icon_id] = out_icon
|
humanoid_icon_cache[icon_id] = out_icon
|
||||||
|
|||||||
@@ -329,11 +329,12 @@
|
|||||||
uni_identity = generate_uni_identity()
|
uni_identity = generate_uni_identity()
|
||||||
unique_enzymes = generate_unique_enzymes()
|
unique_enzymes = generate_unique_enzymes()
|
||||||
|
|
||||||
/datum/dna/proc/initialize_dna(newblood_type)
|
/datum/dna/proc/initialize_dna(newblood_type, skip_index = FALSE)
|
||||||
if(newblood_type)
|
if(newblood_type)
|
||||||
blood_type = newblood_type
|
blood_type = newblood_type
|
||||||
unique_enzymes = generate_unique_enzymes()
|
unique_enzymes = generate_unique_enzymes()
|
||||||
uni_identity = generate_uni_identity()
|
uni_identity = generate_uni_identity()
|
||||||
|
if(!skip_index) //I hate this
|
||||||
generate_dna_blocks()
|
generate_dna_blocks()
|
||||||
features = random_features(species?.id, holder?.gender)
|
features = random_features(species?.id, holder?.gender)
|
||||||
|
|
||||||
|
|||||||
@@ -1,71 +1,185 @@
|
|||||||
|
/**
|
||||||
|
* # Outfit datums
|
||||||
|
*
|
||||||
|
* This is a clean system of applying outfits to mobs, if you need to equip someone in a uniform
|
||||||
|
* this is the way to do it cleanly and properly.
|
||||||
|
*
|
||||||
|
* You can also specify an outfit datum on a job to have it auto equipped to the mob on join
|
||||||
|
*
|
||||||
|
* /mob/living/carbon/human/proc/equipOutfit(outfit) is the mob level proc to equip an outfit
|
||||||
|
* and you pass it the relevant datum outfit
|
||||||
|
*
|
||||||
|
* outfits can also be saved as json blobs downloadable by a client and then can be uploaded
|
||||||
|
* by that user to recreate the outfit, this is used by admins to allow for custom event outfits
|
||||||
|
* that can be restored at a later date
|
||||||
|
*/
|
||||||
/datum/outfit
|
/datum/outfit
|
||||||
|
///Name of the outfit (shows up in the equip admin verb)
|
||||||
var/name = "Naked"
|
var/name = "Naked"
|
||||||
|
|
||||||
var/uniform = null
|
/// Type path of item to go in the idcard slot
|
||||||
var/suit = null
|
|
||||||
var/toggle_helmet = TRUE
|
|
||||||
var/back = null
|
|
||||||
var/belt = null
|
|
||||||
var/gloves = null
|
|
||||||
var/shoes = null
|
|
||||||
var/head = null
|
|
||||||
var/mask = null
|
|
||||||
var/neck = null
|
|
||||||
var/ears = null
|
|
||||||
var/glasses = null
|
|
||||||
var/id = null
|
var/id = null
|
||||||
var/l_pocket = null
|
|
||||||
var/r_pocket = null
|
/// Type path of item to go in uniform slot
|
||||||
|
var/uniform = null
|
||||||
|
|
||||||
|
/// Type path of item to go in suit slot
|
||||||
|
var/suit = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type path of item to go in suit storage slot
|
||||||
|
*
|
||||||
|
* (make sure it's valid for that suit)
|
||||||
|
*/
|
||||||
var/suit_store = null
|
var/suit_store = null
|
||||||
var/r_hand = null
|
|
||||||
|
/// Type path of item to go in back slot
|
||||||
|
var/back = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list of items that should go in the backpack of the user
|
||||||
|
*
|
||||||
|
* Format of this list should be: list(path=count,otherpath=count)
|
||||||
|
*/
|
||||||
|
var/list/backpack_contents = null
|
||||||
|
|
||||||
|
/// Type path of item to go in belt slot
|
||||||
|
var/belt = null
|
||||||
|
|
||||||
|
/// Type path of item to go in ears slot
|
||||||
|
var/ears = null
|
||||||
|
|
||||||
|
/// Type path of item to go in the glasses slot
|
||||||
|
var/glasses = null
|
||||||
|
|
||||||
|
/// Type path of item to go in gloves slot
|
||||||
|
var/gloves = null
|
||||||
|
|
||||||
|
/// Type path of item to go in head slot
|
||||||
|
var/head = null
|
||||||
|
|
||||||
|
/// Type path of item to go in mask slot
|
||||||
|
var/mask = null
|
||||||
|
|
||||||
|
/// Type path of item to go in neck slot
|
||||||
|
var/neck = null
|
||||||
|
|
||||||
|
/// Type path of item to go in shoes slot
|
||||||
|
var/shoes = null
|
||||||
|
|
||||||
|
/// Type path of item for left pocket slot
|
||||||
|
var/l_pocket = null
|
||||||
|
|
||||||
|
/// Type path of item for right pocket slot
|
||||||
|
var/r_pocket = null
|
||||||
|
|
||||||
|
///Type path of item to go in the right hand
|
||||||
var/l_hand = null
|
var/l_hand = null
|
||||||
var/internals_slot = null //ID of slot containing a gas tank
|
|
||||||
var/list/backpack_contents = null // In the list(path=count,otherpath=count) format
|
//Type path of item to go in left hand
|
||||||
var/box // Internals box. Will be inserted at the start of backpack_contents
|
var/r_hand = null
|
||||||
var/list/implants = null
|
|
||||||
|
/// Any clothing accessory item
|
||||||
var/accessory = null
|
var/accessory = null
|
||||||
|
|
||||||
var/can_be_admin_equipped = TRUE // Set to FALSE if your outfit requires runtime parameters
|
/// Internals box. Will be inserted at the start of backpack_contents
|
||||||
var/list/chameleon_extras //extra types for chameleon outfit changes, mostly guns
|
var/box
|
||||||
|
|
||||||
|
/**
|
||||||
|
* extra types for chameleon outfit changes, mostly guns
|
||||||
|
*
|
||||||
|
* Format of this list is (typepath, typepath, typepath)
|
||||||
|
*
|
||||||
|
* These are all added and returns in the list for get_chamelon_diguise_info proc
|
||||||
|
*/
|
||||||
|
var/list/chameleon_extras
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any implants the mob should start implanted with
|
||||||
|
*
|
||||||
|
* Format of this list is (typepath, typepath, typepath)
|
||||||
|
*/
|
||||||
|
var/list/implants = null
|
||||||
|
|
||||||
|
///ID of the slot containing a gas tank
|
||||||
|
var/internals_slot = null
|
||||||
|
|
||||||
|
/// Should the toggle helmet proc be called on the helmet during equip
|
||||||
|
var/toggle_helmet = TRUE
|
||||||
|
|
||||||
|
/// Any undershirt. While on humans it is a string, here we use paths to stay consistent with the rest of the equips.
|
||||||
|
var/datum/sprite_accessory/undershirt = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called at the start of the equip proc
|
||||||
|
*
|
||||||
|
* Override to change the value of the slots depending on client prefs, species and
|
||||||
|
* other such sources of change
|
||||||
|
*
|
||||||
|
* Extra Arguments
|
||||||
|
* * visualsOnly true if this is only for display (in the character setup screen)
|
||||||
|
*
|
||||||
|
* If visualsOnly is true, you can omit any work that doesn't visually appear on the character sprite
|
||||||
|
*/
|
||||||
/datum/outfit/proc/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
/datum/outfit/proc/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
||||||
//to be overridden for customization depending on client prefs,species etc
|
//to be overridden for customization depending on client prefs,species etc
|
||||||
return
|
return
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called after the equip proc has finished
|
||||||
|
*
|
||||||
|
* All items are on the mob at this point, use this proc to toggle internals
|
||||||
|
* fiddle with id bindings and accesses etc
|
||||||
|
*
|
||||||
|
* Extra Arguments
|
||||||
|
* * visualsOnly true if this is only for display (in the character setup screen)
|
||||||
|
*
|
||||||
|
* If visualsOnly is true, you can omit any work that doesn't visually appear on the character sprite
|
||||||
|
*/
|
||||||
/datum/outfit/proc/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
/datum/outfit/proc/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
||||||
//to be overridden for toggling internals, id binding, access etc
|
//to be overridden for toggling internals, id binding, access etc
|
||||||
return
|
return
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equips all defined types and paths to the mob passed in
|
||||||
|
*
|
||||||
|
* Extra Arguments
|
||||||
|
* * visualsOnly true if this is only for display (in the character setup screen)
|
||||||
|
*
|
||||||
|
* If visualsOnly is true, you can omit any work that doesn't visually appear on the character sprite
|
||||||
|
*/
|
||||||
/datum/outfit/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
/datum/outfit/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
||||||
pre_equip(H, visualsOnly, preference_source)
|
pre_equip(H, visualsOnly, preference_source)
|
||||||
|
|
||||||
//Start with uniform,suit,backpack for additional slots
|
//Start with uniform,suit,backpack for additional slots
|
||||||
if(uniform)
|
if(uniform)
|
||||||
H.equip_to_slot_or_del(new uniform(H),SLOT_W_UNIFORM)
|
H.equip_to_slot_or_del(new uniform(H), SLOT_W_UNIFORM, TRUE)
|
||||||
if(suit)
|
if(suit)
|
||||||
H.equip_to_slot_or_del(new suit(H),SLOT_WEAR_SUIT)
|
H.equip_to_slot_or_del(new suit(H), SLOT_WEAR_SUIT, TRUE)
|
||||||
if(back)
|
if(back)
|
||||||
H.equip_to_slot_or_del(new back(H),SLOT_BACK)
|
H.equip_to_slot_or_del(new back(H), SLOT_BACK, TRUE)
|
||||||
if(belt)
|
if(belt)
|
||||||
H.equip_to_slot_or_del(new belt(H),SLOT_BELT)
|
H.equip_to_slot_or_del(new belt(H), SLOT_BELT, TRUE)
|
||||||
if(gloves)
|
if(gloves)
|
||||||
H.equip_to_slot_or_del(new gloves(H),SLOT_GLOVES)
|
H.equip_to_slot_or_del(new gloves(H), SLOT_GLOVES, TRUE)
|
||||||
if(shoes)
|
if(shoes)
|
||||||
H.equip_to_slot_or_del(new shoes(H),SLOT_SHOES)
|
H.equip_to_slot_or_del(new shoes(H), SLOT_SHOES, TRUE)
|
||||||
if(head)
|
if(head)
|
||||||
H.equip_to_slot_or_del(new head(H),SLOT_HEAD)
|
H.equip_to_slot_or_del(new head(H), SLOT_HEAD, TRUE)
|
||||||
if(mask)
|
if(mask)
|
||||||
H.equip_to_slot_or_del(new mask(H),SLOT_WEAR_MASK)
|
H.equip_to_slot_or_del(new mask(H), SLOT_WEAR_MASK, TRUE)
|
||||||
if(neck)
|
if(neck)
|
||||||
H.equip_to_slot_or_del(new neck(H),SLOT_NECK)
|
H.equip_to_slot_or_del(new neck(H), SLOT_NECK, TRUE)
|
||||||
if(ears)
|
if(ears)
|
||||||
H.equip_to_slot_or_del(new ears(H),SLOT_EARS)
|
H.equip_to_slot_or_del(new ears(H), SLOT_EARS, TRUE)
|
||||||
if(glasses)
|
if(glasses)
|
||||||
H.equip_to_slot_or_del(new glasses(H),SLOT_GLASSES)
|
H.equip_to_slot_or_del(new glasses(H), SLOT_GLASSES, TRUE)
|
||||||
if(id)
|
if(id)
|
||||||
H.equip_to_slot_or_del(new id(H),SLOT_WEAR_ID)
|
H.equip_to_slot_or_del(new id(H), SLOT_WEAR_ID, TRUE)
|
||||||
if(suit_store)
|
if(suit_store)
|
||||||
H.equip_to_slot_or_del(new suit_store(H),SLOT_S_STORE)
|
H.equip_to_slot_or_del(new suit_store(H), SLOT_S_STORE, TRUE)
|
||||||
|
if(undershirt)
|
||||||
|
H.undershirt = initial(undershirt.name)
|
||||||
|
|
||||||
if(accessory)
|
if(accessory)
|
||||||
var/obj/item/clothing/under/U = H.w_uniform
|
var/obj/item/clothing/under/U = H.w_uniform
|
||||||
@@ -81,9 +195,9 @@
|
|||||||
|
|
||||||
if(!visualsOnly) // Items in pockets or backpack don't show up on mob's icon.
|
if(!visualsOnly) // Items in pockets or backpack don't show up on mob's icon.
|
||||||
if(l_pocket)
|
if(l_pocket)
|
||||||
H.equip_to_slot_or_del(new l_pocket(H),SLOT_L_STORE)
|
H.equip_to_slot_or_del(new l_pocket(H), SLOT_L_STORE, TRUE)
|
||||||
if(r_pocket)
|
if(r_pocket)
|
||||||
H.equip_to_slot_or_del(new r_pocket(H),SLOT_R_STORE)
|
H.equip_to_slot_or_del(new r_pocket(H), SLOT_R_STORE, TRUE)
|
||||||
|
|
||||||
if(box)
|
if(box)
|
||||||
if(!backpack_contents)
|
if(!backpack_contents)
|
||||||
@@ -97,7 +211,7 @@
|
|||||||
if(!isnum(number))//Default to 1
|
if(!isnum(number))//Default to 1
|
||||||
number = 1
|
number = 1
|
||||||
for(var/i in 1 to number)
|
for(var/i in 1 to number)
|
||||||
H.equip_to_slot_or_del(new path(H),SLOT_IN_BACKPACK)
|
H.equip_to_slot_or_del(new path(H), SLOT_IN_BACKPACK, TRUE)
|
||||||
|
|
||||||
if(!H.head && toggle_helmet && istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit))
|
if(!H.head && toggle_helmet && istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit))
|
||||||
var/obj/item/clothing/suit/space/hardsuit/HS = H.wear_suit
|
var/obj/item/clothing/suit/space/hardsuit/HS = H.wear_suit
|
||||||
@@ -112,55 +226,178 @@
|
|||||||
H.update_action_buttons_icon()
|
H.update_action_buttons_icon()
|
||||||
if(implants)
|
if(implants)
|
||||||
for(var/implant_type in implants)
|
for(var/implant_type in implants)
|
||||||
var/obj/item/implant/I = new implant_type
|
var/obj/item/implant/I = new implant_type(H)
|
||||||
I.implant(H, null, TRUE)
|
I.implant(H, null, TRUE)
|
||||||
|
|
||||||
H.update_body()
|
H.update_body()
|
||||||
return TRUE
|
return TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a fingerprint from the passed in human to all items in the outfit
|
||||||
|
*
|
||||||
|
* Used for forensics setup when the mob is first equipped at roundstart
|
||||||
|
* essentially calls add_fingerprint to every defined item on the human
|
||||||
|
*
|
||||||
|
*/
|
||||||
/datum/outfit/proc/apply_fingerprints(mob/living/carbon/human/H)
|
/datum/outfit/proc/apply_fingerprints(mob/living/carbon/human/H)
|
||||||
if(!istype(H))
|
if(!istype(H))
|
||||||
return
|
return
|
||||||
if(H.back)
|
if(H.back)
|
||||||
H.back.add_fingerprint(H,1) //The 1 sets a flag to ignore gloves
|
H.back.add_fingerprint(H, ignoregloves = TRUE)
|
||||||
for(var/obj/item/I in H.back.contents)
|
for(var/obj/item/I in H.back.contents)
|
||||||
I.add_fingerprint(H,1)
|
I.add_fingerprint(H, ignoregloves = TRUE)
|
||||||
if(H.wear_id)
|
if(H.wear_id)
|
||||||
H.wear_id.add_fingerprint(H,1)
|
H.wear_id.add_fingerprint(H, ignoregloves = TRUE)
|
||||||
if(H.w_uniform)
|
if(H.w_uniform)
|
||||||
H.w_uniform.add_fingerprint(H,1)
|
H.w_uniform.add_fingerprint(H, ignoregloves = TRUE)
|
||||||
if(H.wear_suit)
|
if(H.wear_suit)
|
||||||
H.wear_suit.add_fingerprint(H,1)
|
H.wear_suit.add_fingerprint(H, ignoregloves = TRUE)
|
||||||
if(H.wear_mask)
|
if(H.wear_mask)
|
||||||
H.wear_mask.add_fingerprint(H,1)
|
H.wear_mask.add_fingerprint(H, ignoregloves = TRUE)
|
||||||
if(H.wear_neck)
|
if(H.wear_neck)
|
||||||
H.wear_neck.add_fingerprint(H,1)
|
H.wear_neck.add_fingerprint(H, ignoregloves = TRUE)
|
||||||
if(H.head)
|
if(H.head)
|
||||||
H.head.add_fingerprint(H,1)
|
H.head.add_fingerprint(H, ignoregloves = TRUE)
|
||||||
if(H.shoes)
|
if(H.shoes)
|
||||||
H.shoes.add_fingerprint(H,1)
|
H.shoes.add_fingerprint(H, ignoregloves = TRUE)
|
||||||
if(H.gloves)
|
if(H.gloves)
|
||||||
H.gloves.add_fingerprint(H,1)
|
H.gloves.add_fingerprint(H, ignoregloves = TRUE)
|
||||||
if(H.ears)
|
if(H.ears)
|
||||||
H.ears.add_fingerprint(H,1)
|
H.ears.add_fingerprint(H, ignoregloves = TRUE)
|
||||||
if(H.glasses)
|
if(H.glasses)
|
||||||
H.glasses.add_fingerprint(H,1)
|
H.glasses.add_fingerprint(H, ignoregloves = TRUE)
|
||||||
if(H.belt)
|
if(H.belt)
|
||||||
H.belt.add_fingerprint(H,1)
|
H.belt.add_fingerprint(H, ignoregloves = TRUE)
|
||||||
for(var/obj/item/I in H.belt.contents)
|
for(var/obj/item/I in H.belt.contents)
|
||||||
I.add_fingerprint(H,1)
|
I.add_fingerprint(H, ignoregloves = TRUE)
|
||||||
if(H.s_store)
|
if(H.s_store)
|
||||||
H.s_store.add_fingerprint(H,1)
|
H.s_store.add_fingerprint(H, ignoregloves = TRUE)
|
||||||
if(H.l_store)
|
if(H.l_store)
|
||||||
H.l_store.add_fingerprint(H,1)
|
H.l_store.add_fingerprint(H, ignoregloves = TRUE)
|
||||||
if(H.r_store)
|
if(H.r_store)
|
||||||
H.r_store.add_fingerprint(H,1)
|
H.r_store.add_fingerprint(H, ignoregloves = TRUE)
|
||||||
for(var/obj/item/I in H.held_items)
|
for(var/obj/item/I in H.held_items)
|
||||||
I.add_fingerprint(H,1)
|
I.add_fingerprint(H, ignoregloves = TRUE)
|
||||||
return 1
|
return TRUE
|
||||||
|
|
||||||
|
/// Return a list of all the types that are required to disguise as this outfit type
|
||||||
/datum/outfit/proc/get_chameleon_disguise_info()
|
/datum/outfit/proc/get_chameleon_disguise_info()
|
||||||
var/list/types = list(uniform, suit, back, belt, gloves, shoes, head, mask, neck, ears, glasses, id, l_pocket, r_pocket, suit_store, r_hand, l_hand)
|
var/list/types = list(uniform, suit, back, belt, gloves, shoes, head, mask, neck, ears, glasses, id, l_pocket, r_pocket, suit_store, r_hand, l_hand)
|
||||||
types += chameleon_extras
|
types += chameleon_extras
|
||||||
listclearnulls(types)
|
listclearnulls(types)
|
||||||
return types
|
return types
|
||||||
|
|
||||||
|
/// Return a json list of this outfit
|
||||||
|
/datum/outfit/proc/get_json_data()
|
||||||
|
. = list()
|
||||||
|
.["outfit_type"] = type
|
||||||
|
.["name"] = name
|
||||||
|
.["uniform"] = uniform
|
||||||
|
.["suit"] = suit
|
||||||
|
.["toggle_helmet"] = toggle_helmet
|
||||||
|
.["back"] = back
|
||||||
|
.["belt"] = belt
|
||||||
|
.["gloves"] = gloves
|
||||||
|
.["shoes"] = shoes
|
||||||
|
.["head"] = head
|
||||||
|
.["mask"] = mask
|
||||||
|
.["neck"] = neck
|
||||||
|
.["ears"] = ears
|
||||||
|
.["glasses"] = glasses
|
||||||
|
.["id"] = id
|
||||||
|
.["l_pocket"] = l_pocket
|
||||||
|
.["r_pocket"] = r_pocket
|
||||||
|
.["suit_store"] = suit_store
|
||||||
|
.["r_hand"] = r_hand
|
||||||
|
.["l_hand"] = l_hand
|
||||||
|
.["internals_slot"] = internals_slot
|
||||||
|
.["backpack_contents"] = backpack_contents
|
||||||
|
.["box"] = box
|
||||||
|
.["implants"] = implants
|
||||||
|
.["accessory"] = accessory
|
||||||
|
|
||||||
|
/// Copy most vars from another outfit to this one
|
||||||
|
/datum/outfit/proc/copy_from(datum/outfit/target)
|
||||||
|
name = target.name
|
||||||
|
uniform = target.uniform
|
||||||
|
suit = target.suit
|
||||||
|
toggle_helmet = target.toggle_helmet
|
||||||
|
back = target.back
|
||||||
|
belt = target.belt
|
||||||
|
gloves = target.gloves
|
||||||
|
shoes = target.shoes
|
||||||
|
head = target.head
|
||||||
|
mask = target.mask
|
||||||
|
neck = target.neck
|
||||||
|
ears = target.ears
|
||||||
|
glasses = target.glasses
|
||||||
|
id = target.id
|
||||||
|
l_pocket = target.l_pocket
|
||||||
|
r_pocket = target.r_pocket
|
||||||
|
suit_store = target.suit_store
|
||||||
|
r_hand = target.r_hand
|
||||||
|
l_hand = target.l_hand
|
||||||
|
internals_slot = target.internals_slot
|
||||||
|
backpack_contents = target.backpack_contents
|
||||||
|
box = target.box
|
||||||
|
implants = target.implants
|
||||||
|
accessory = target.accessory
|
||||||
|
|
||||||
|
/// Prompt the passed in mob client to download this outfit as a json blob
|
||||||
|
/datum/outfit/proc/save_to_file(mob/admin)
|
||||||
|
var/stored_data = get_json_data()
|
||||||
|
var/json = json_encode(stored_data)
|
||||||
|
//Kinda annoying but as far as i can tell you need to make actual file.
|
||||||
|
var/f = file("data/TempOutfitUpload")
|
||||||
|
fdel(f)
|
||||||
|
WRITE_FILE(f,json)
|
||||||
|
admin << ftp(f,"[name].json")
|
||||||
|
|
||||||
|
/// Create an outfit datum from a list of json data
|
||||||
|
/datum/outfit/proc/load_from(list/outfit_data)
|
||||||
|
//This could probably use more strict validation
|
||||||
|
name = outfit_data["name"]
|
||||||
|
uniform = text2path(outfit_data["uniform"])
|
||||||
|
suit = text2path(outfit_data["suit"])
|
||||||
|
toggle_helmet = outfit_data["toggle_helmet"]
|
||||||
|
back = text2path(outfit_data["back"])
|
||||||
|
belt = text2path(outfit_data["belt"])
|
||||||
|
gloves = text2path(outfit_data["gloves"])
|
||||||
|
shoes = text2path(outfit_data["shoes"])
|
||||||
|
head = text2path(outfit_data["head"])
|
||||||
|
mask = text2path(outfit_data["mask"])
|
||||||
|
neck = text2path(outfit_data["neck"])
|
||||||
|
ears = text2path(outfit_data["ears"])
|
||||||
|
glasses = text2path(outfit_data["glasses"])
|
||||||
|
id = text2path(outfit_data["id"])
|
||||||
|
l_pocket = text2path(outfit_data["l_pocket"])
|
||||||
|
r_pocket = text2path(outfit_data["r_pocket"])
|
||||||
|
suit_store = text2path(outfit_data["suit_store"])
|
||||||
|
r_hand = text2path(outfit_data["r_hand"])
|
||||||
|
l_hand = text2path(outfit_data["l_hand"])
|
||||||
|
internals_slot = outfit_data["internals_slot"]
|
||||||
|
var/list/backpack = outfit_data["backpack_contents"]
|
||||||
|
backpack_contents = list()
|
||||||
|
for(var/item in backpack)
|
||||||
|
var/itype = text2path(item)
|
||||||
|
if(itype)
|
||||||
|
backpack_contents[itype] = backpack[item]
|
||||||
|
box = text2path(outfit_data["box"])
|
||||||
|
var/list/impl = outfit_data["implants"]
|
||||||
|
implants = list()
|
||||||
|
for(var/I in impl)
|
||||||
|
var/imptype = text2path(I)
|
||||||
|
if(imptype)
|
||||||
|
implants += imptype
|
||||||
|
accessory = text2path(outfit_data["accessory"])
|
||||||
|
return TRUE
|
||||||
|
|
||||||
|
/datum/outfit/vv_get_dropdown()
|
||||||
|
. = ..()
|
||||||
|
VV_DROPDOWN_OPTION("", "---")
|
||||||
|
VV_DROPDOWN_OPTION(VV_HK_TO_OUTFIT_EDITOR, "Outfit Editor")
|
||||||
|
|
||||||
|
/datum/outfit/vv_do_topic(list/href_list)
|
||||||
|
. = ..()
|
||||||
|
if(href_list[VV_HK_TO_OUTFIT_EDITOR])
|
||||||
|
usr.client.open_outfit_editor(src)
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ GLOBAL_PROTECT(admin_verbs_ban)
|
|||||||
GLOBAL_LIST_INIT(admin_verbs_sounds, list(/client/proc/play_local_sound, /client/proc/play_sound, /client/proc/manual_play_web_sound, /client/proc/set_round_end_sound))
|
GLOBAL_LIST_INIT(admin_verbs_sounds, list(/client/proc/play_local_sound, /client/proc/play_sound, /client/proc/manual_play_web_sound, /client/proc/set_round_end_sound))
|
||||||
GLOBAL_PROTECT(admin_verbs_sounds)
|
GLOBAL_PROTECT(admin_verbs_sounds)
|
||||||
GLOBAL_LIST_INIT(admin_verbs_fun, list(
|
GLOBAL_LIST_INIT(admin_verbs_fun, list(
|
||||||
/client/proc/cmd_admin_dress,
|
/client/proc/cmd_select_equipment,
|
||||||
/client/proc/cmd_admin_gib_self,
|
/client/proc/cmd_admin_gib_self,
|
||||||
/client/proc/drop_bomb,
|
/client/proc/drop_bomb,
|
||||||
/client/proc/set_dynex_scale,
|
/client/proc/set_dynex_scale,
|
||||||
@@ -232,7 +232,7 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
|||||||
/client/proc/play_local_sound,
|
/client/proc/play_local_sound,
|
||||||
/client/proc/play_sound,
|
/client/proc/play_sound,
|
||||||
/client/proc/set_round_end_sound,
|
/client/proc/set_round_end_sound,
|
||||||
/client/proc/cmd_admin_dress,
|
/client/proc/cmd_select_equipment,
|
||||||
/client/proc/cmd_admin_gib_self,
|
/client/proc/cmd_admin_gib_self,
|
||||||
/client/proc/drop_bomb,
|
/client/proc/drop_bomb,
|
||||||
/client/proc/drop_dynex_bomb,
|
/client/proc/drop_dynex_bomb,
|
||||||
|
|||||||
196
code/modules/admin/outfit_editor.dm
Normal file
196
code/modules/admin/outfit_editor.dm
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
|
||||||
|
/client/proc/open_outfit_editor(datum/outfit/target)
|
||||||
|
var/datum/outfit_editor/ui = new(usr, target)
|
||||||
|
ui.ui_interact(usr)
|
||||||
|
|
||||||
|
#define OUTFIT_EDITOR_NAME "Outfit-O-Tron 9000"
|
||||||
|
/datum/outfit_editor
|
||||||
|
var/client/owner
|
||||||
|
|
||||||
|
var/dummy_key
|
||||||
|
|
||||||
|
var/datum/outfit/drip
|
||||||
|
|
||||||
|
/datum/outfit_editor/New(user, datum/outfit/target)
|
||||||
|
owner = CLIENT_FROM_VAR(user)
|
||||||
|
|
||||||
|
if(ispath(target))
|
||||||
|
drip = new /datum/outfit
|
||||||
|
drip.copy_from(new target)
|
||||||
|
else if(istype(target))
|
||||||
|
drip = target
|
||||||
|
else
|
||||||
|
drip = new /datum/outfit
|
||||||
|
drip.name = "New Outfit"
|
||||||
|
|
||||||
|
/datum/outfit_editor/ui_state(mob/user)
|
||||||
|
return GLOB.admin_state
|
||||||
|
|
||||||
|
/datum/outfit_editor/ui_status(mob/user, datum/ui_state/state)
|
||||||
|
if(QDELETED(drip))
|
||||||
|
return UI_CLOSE
|
||||||
|
return ..()
|
||||||
|
|
||||||
|
/datum/outfit_editor/ui_close(mob/user)
|
||||||
|
clear_human_dummy(dummy_key)
|
||||||
|
qdel(src)
|
||||||
|
|
||||||
|
/datum/outfit_editor/proc/init_dummy()
|
||||||
|
dummy_key = "outfit_editor_[owner]"
|
||||||
|
generate_dummy_lookalike(dummy_key, owner.mob)
|
||||||
|
unset_busy_human_dummy(dummy_key)
|
||||||
|
|
||||||
|
/datum/outfit_editor/ui_interact(mob/user, datum/tgui/ui)
|
||||||
|
ui = SStgui.try_update_ui(user, src, ui)
|
||||||
|
if(!ui)
|
||||||
|
ui = new(user, src, "OutfitEditor", OUTFIT_EDITOR_NAME)
|
||||||
|
ui.open()
|
||||||
|
ui.set_autoupdate(FALSE)
|
||||||
|
|
||||||
|
/datum/outfit_editor/proc/entry(data)
|
||||||
|
if(ispath(data, /obj/item))
|
||||||
|
var/obj/item/item = data
|
||||||
|
return list(
|
||||||
|
"path" = item,
|
||||||
|
"name" = initial(item.name),
|
||||||
|
"desc" = initial(item.desc),
|
||||||
|
// at this point initializing the item is probably faster tbh
|
||||||
|
"sprite" = icon2base64(icon(initial(item.icon), initial(item.icon_state))),
|
||||||
|
)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
/datum/outfit_editor/proc/serialize_outfit()
|
||||||
|
var/list/outfit_slots = drip.get_json_data()
|
||||||
|
. = list()
|
||||||
|
for(var/key in outfit_slots)
|
||||||
|
var/val = outfit_slots[key]
|
||||||
|
. += list("[key]" = entry(val))
|
||||||
|
|
||||||
|
/datum/outfit_editor/ui_data(mob/user)
|
||||||
|
var/list/data = list()
|
||||||
|
|
||||||
|
data["outfit"] = serialize_outfit()
|
||||||
|
data["saveable"] = !GLOB.custom_outfits.Find(drip)
|
||||||
|
|
||||||
|
if(!dummy_key)
|
||||||
|
init_dummy()
|
||||||
|
var/icon/dummysprite = get_flat_human_icon(null,
|
||||||
|
dummy_key = dummy_key,
|
||||||
|
showDirs = list(SOUTH),
|
||||||
|
outfit_override = drip)
|
||||||
|
data["dummy64"] = icon2base64(dummysprite)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
/datum/outfit_editor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||||
|
if(..())
|
||||||
|
return
|
||||||
|
. = TRUE
|
||||||
|
|
||||||
|
var/slot = params["slot"]
|
||||||
|
switch(action)
|
||||||
|
if("click")
|
||||||
|
choose_item(slot)
|
||||||
|
if("ctrlClick")
|
||||||
|
choose_any_item(slot)
|
||||||
|
if("clear")
|
||||||
|
if(drip.vars.Find(slot))
|
||||||
|
drip.vars[slot] = null
|
||||||
|
|
||||||
|
if("rename")
|
||||||
|
var/newname = stripped_input(owner, "What do you want to name this outfit?", OUTFIT_EDITOR_NAME)
|
||||||
|
if(newname)
|
||||||
|
drip.name = newname
|
||||||
|
if("save")
|
||||||
|
GLOB.custom_outfits |= drip
|
||||||
|
SStgui.update_user_uis(owner.mob)
|
||||||
|
if("delete")
|
||||||
|
GLOB.custom_outfits -= drip
|
||||||
|
SStgui.update_user_uis(owner.mob)
|
||||||
|
if("vv")
|
||||||
|
owner.debug_variables(drip)
|
||||||
|
|
||||||
|
|
||||||
|
/datum/outfit_editor/proc/set_item(slot, obj/item/choice)
|
||||||
|
if(!choice)
|
||||||
|
return
|
||||||
|
if(!ispath(choice))
|
||||||
|
alert(owner, "Invalid item", OUTFIT_EDITOR_NAME, "oh no")
|
||||||
|
return
|
||||||
|
if(initial(choice.icon_state) == null) //hacky check copied from experimentor code
|
||||||
|
var/msg = "Warning: This item's icon_state is null, indicating it is very probably not actually a usable item."
|
||||||
|
if(alert(owner, msg, OUTFIT_EDITOR_NAME, "Use it anyway", "Cancel") != "Use it anyway")
|
||||||
|
return
|
||||||
|
|
||||||
|
if(drip.vars.Find(slot))
|
||||||
|
drip.vars[slot] = choice
|
||||||
|
|
||||||
|
/datum/outfit_editor/proc/choose_any_item(slot)
|
||||||
|
var/obj/item/choice = pick_closest_path(FALSE)
|
||||||
|
|
||||||
|
if(!choice)
|
||||||
|
return
|
||||||
|
|
||||||
|
set_item(slot, choice)
|
||||||
|
|
||||||
|
//this proc will try to give a good selection of items that the user can choose from
|
||||||
|
//it does *not* give a selection of all items that can fit in a slot because lag;
|
||||||
|
//most notably the hand and pocket slots because they accept pretty much anything
|
||||||
|
//also stuff that fits in the belt and back slots are scattered pretty much all over the place
|
||||||
|
/datum/outfit_editor/proc/choose_item(slot)
|
||||||
|
var/list/options = list()
|
||||||
|
|
||||||
|
switch(slot)
|
||||||
|
if("head")
|
||||||
|
options = typesof(/obj/item/clothing/head)
|
||||||
|
if("glasses")
|
||||||
|
options = typesof(/obj/item/clothing/glasses)
|
||||||
|
if("ears")
|
||||||
|
options = typesof(/obj/item/radio/headset)
|
||||||
|
|
||||||
|
if("neck")
|
||||||
|
options = typesof(/obj/item/clothing/neck)
|
||||||
|
if("mask")
|
||||||
|
options = typesof(/obj/item/clothing/mask)
|
||||||
|
|
||||||
|
if("uniform")
|
||||||
|
options = typesof(/obj/item/clothing/under)
|
||||||
|
if("suit")
|
||||||
|
options = typesof(/obj/item/clothing/suit)
|
||||||
|
if("gloves")
|
||||||
|
options = typesof(/obj/item/clothing/gloves)
|
||||||
|
|
||||||
|
if("suit_store")
|
||||||
|
var/obj/item/clothing/suit/suit = drip.suit
|
||||||
|
if(suit)
|
||||||
|
suit = new suit //initial() doesn't like lists
|
||||||
|
options = suit.allowed
|
||||||
|
if(!options.len) //nothing will happen, but don't let the user think it's broken
|
||||||
|
to_chat(owner, "<span class='warning'>No options available for the current suit.</span>")
|
||||||
|
|
||||||
|
if("belt")
|
||||||
|
options = typesof(/obj/item/storage/belt)
|
||||||
|
if("id")
|
||||||
|
options = typesof(/obj/item/card/id)
|
||||||
|
|
||||||
|
if("l_hand")
|
||||||
|
choose_any_item(slot)
|
||||||
|
if("back")
|
||||||
|
options = typesof(/obj/item/storage/backpack)
|
||||||
|
if("r_hand")
|
||||||
|
choose_any_item(slot)
|
||||||
|
|
||||||
|
if("l_pocket")
|
||||||
|
choose_any_item(slot)
|
||||||
|
if("shoes")
|
||||||
|
options = typesof(/obj/item/clothing/shoes)
|
||||||
|
if("r_pocket")
|
||||||
|
choose_any_item(slot)
|
||||||
|
|
||||||
|
if(length(options))
|
||||||
|
set_item(slot, tgui_input_list(owner, "Choose an item", OUTFIT_EDITOR_NAME, options))
|
||||||
|
|
||||||
|
|
||||||
|
#undef OUTFIT_EDITOR_NAME
|
||||||
73
code/modules/admin/outfit_manager.dm
Normal file
73
code/modules/admin/outfit_manager.dm
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/client/proc/outfit_manager()
|
||||||
|
set category = "Debug"
|
||||||
|
set name = "Outfit Manager"
|
||||||
|
|
||||||
|
if(!check_rights(R_DEBUG))
|
||||||
|
return
|
||||||
|
var/datum/outfit_manager/ui = new(usr)
|
||||||
|
ui.ui_interact(usr)
|
||||||
|
|
||||||
|
|
||||||
|
/datum/outfit_manager
|
||||||
|
var/client/owner
|
||||||
|
|
||||||
|
/datum/outfit_manager/New(user)
|
||||||
|
owner = CLIENT_FROM_VAR(user)
|
||||||
|
|
||||||
|
/datum/outfit_manager/ui_state(mob/user)
|
||||||
|
return GLOB.admin_state
|
||||||
|
|
||||||
|
/datum/outfit_manager/ui_close(mob/user)
|
||||||
|
qdel(src)
|
||||||
|
|
||||||
|
/datum/outfit_manager/ui_interact(mob/user, datum/tgui/ui)
|
||||||
|
ui = SStgui.try_update_ui(user, src, ui)
|
||||||
|
if(!ui)
|
||||||
|
ui = new(user, src, "OutfitManager")
|
||||||
|
ui.open()
|
||||||
|
|
||||||
|
/datum/outfit_manager/proc/entry(datum/outfit/outfit)
|
||||||
|
var/vv = FALSE
|
||||||
|
var/datum/outfit/varedit/varoutfit = outfit
|
||||||
|
if(istype(varoutfit))
|
||||||
|
vv = length(varoutfit.vv_values)
|
||||||
|
return list(
|
||||||
|
"name" = "[outfit.name] [vv ? "(VV)" : ""]",
|
||||||
|
"ref" = REF(outfit),
|
||||||
|
)
|
||||||
|
|
||||||
|
/datum/outfit_manager/ui_data(mob/user)
|
||||||
|
var/list/data = list()
|
||||||
|
|
||||||
|
var/list/outfits = list()
|
||||||
|
for(var/datum/outfit/custom_outfit in GLOB.custom_outfits)
|
||||||
|
outfits += list(entry(custom_outfit))
|
||||||
|
data["outfits"] = outfits
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
/datum/outfit_manager/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||||
|
if(..())
|
||||||
|
return
|
||||||
|
. = TRUE
|
||||||
|
|
||||||
|
switch(action)
|
||||||
|
if("new")
|
||||||
|
owner.open_outfit_editor(new /datum/outfit)
|
||||||
|
if("load")
|
||||||
|
owner.holder.load_outfit(owner.mob)
|
||||||
|
if("copy")
|
||||||
|
var/datum/outfit/outfit = tgui_input_list(owner, "Pick an outfit to copy from", "Outfit Manager", subtypesof(/datum/outfit))
|
||||||
|
if(ispath(outfit))
|
||||||
|
owner.open_outfit_editor(new outfit)
|
||||||
|
|
||||||
|
var/datum/outfit/target_outfit = locate(params["outfit"])
|
||||||
|
if(!istype(target_outfit))
|
||||||
|
return
|
||||||
|
switch(action) //wow we're switching through action again this is horrible optimization smh
|
||||||
|
if("edit")
|
||||||
|
owner.open_outfit_editor(target_outfit)
|
||||||
|
if("save")
|
||||||
|
owner.holder.save_outfit(owner.mob, target_outfit)
|
||||||
|
if("delete")
|
||||||
|
owner.holder.delete_outfit(owner.mob, target_outfit)
|
||||||
32
code/modules/admin/outfits.dm
Normal file
32
code/modules/admin/outfits.dm
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||||
|
|
||||||
|
/datum/admins/proc/save_outfit(mob/admin, datum/outfit/O)
|
||||||
|
O.save_to_file(admin)
|
||||||
|
SStgui.update_user_uis(admin)
|
||||||
|
|
||||||
|
/datum/admins/proc/delete_outfit(mob/admin, datum/outfit/O)
|
||||||
|
GLOB.custom_outfits -= O
|
||||||
|
qdel(O)
|
||||||
|
to_chat(admin,"<span class='notice'>Outfit deleted.</span>")
|
||||||
|
SStgui.update_user_uis(admin)
|
||||||
|
|
||||||
|
/datum/admins/proc/load_outfit(mob/admin)
|
||||||
|
var/outfit_file = input("Pick outfit json file:", "File") as null|file
|
||||||
|
if(!outfit_file)
|
||||||
|
return
|
||||||
|
var/filedata = file2text(outfit_file)
|
||||||
|
var/json = json_decode(filedata)
|
||||||
|
if(!json)
|
||||||
|
to_chat(admin,"<span class='warning'>JSON decode error.</span>")
|
||||||
|
return
|
||||||
|
var/otype = text2path(json["outfit_type"])
|
||||||
|
if(!ispath(otype,/datum/outfit))
|
||||||
|
to_chat(admin,"<span class='warning'>Malformed/Outdated file.</span>")
|
||||||
|
return
|
||||||
|
var/datum/outfit/O = new otype
|
||||||
|
if(!O.load_from(json))
|
||||||
|
to_chat(admin,"<span class='warning'>Malformed/Outdated file.</span>")
|
||||||
|
return
|
||||||
|
GLOB.custom_outfits += O
|
||||||
|
SStgui.update_user_uis(admin)
|
||||||
|
|
||||||
@@ -484,74 +484,52 @@
|
|||||||
set name = "Test Areas (ALL)"
|
set name = "Test Areas (ALL)"
|
||||||
cmd_admin_areatest(FALSE)
|
cmd_admin_areatest(FALSE)
|
||||||
|
|
||||||
/client/proc/cmd_admin_dress(mob/M in GLOB.mob_list)
|
|
||||||
set category = "Admin.Events"
|
|
||||||
set name = "Select equipment"
|
|
||||||
if(!(ishuman(M) || isobserver(M)))
|
|
||||||
alert("Invalid mob")
|
|
||||||
return
|
|
||||||
|
|
||||||
var/dresscode = robust_dress_shop()
|
|
||||||
|
|
||||||
if(!dresscode)
|
|
||||||
return
|
|
||||||
|
|
||||||
var/delete_pocket
|
|
||||||
var/mob/living/carbon/human/H
|
|
||||||
if(isobserver(M))
|
|
||||||
H = M.change_mob_type(/mob/living/carbon/human, null, null, TRUE)
|
|
||||||
else
|
|
||||||
H = M
|
|
||||||
if(alert("Drop Items in Pockets? No will delete them.", "Robust quick dress shop", "Yes", "No") == "No")
|
|
||||||
delete_pocket = TRUE
|
|
||||||
|
|
||||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Select Equipment") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
|
||||||
for (var/obj/item/I in H.get_equipped_items(delete_pocket))
|
|
||||||
qdel(I)
|
|
||||||
if(dresscode != "Naked")
|
|
||||||
H.equipOutfit(dresscode)
|
|
||||||
|
|
||||||
H.regenerate_icons()
|
|
||||||
|
|
||||||
log_admin("[key_name(usr)] changed the equipment of [key_name(H)] to [dresscode].")
|
|
||||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] changed the equipment of [ADMIN_LOOKUPFLW(H)] to [dresscode].</span>")
|
|
||||||
|
|
||||||
/client/proc/robust_dress_shop()
|
/client/proc/robust_dress_shop()
|
||||||
var/list/outfits = list("Cancel","Naked","Custom","As Job...")
|
|
||||||
var/list/paths = subtypesof(/datum/outfit) - typesof(/datum/outfit/job)
|
var/list/baseoutfits = list("Naked","Custom","As Job...", "As Plasmaman...")
|
||||||
|
var/list/outfits = list()
|
||||||
|
var/list/paths = subtypesof(/datum/outfit) - typesof(/datum/outfit/job) - typesof(/datum/outfit/plasmaman)
|
||||||
|
|
||||||
for(var/path in paths)
|
for(var/path in paths)
|
||||||
var/datum/outfit/O = path //not much to initalize here but whatever
|
var/datum/outfit/O = path //not much to initalize here but whatever
|
||||||
if(initial(O.can_be_admin_equipped))
|
|
||||||
outfits[initial(O.name)] = path
|
outfits[initial(O.name)] = path
|
||||||
|
|
||||||
var/dresscode = input("Select outfit", "Robust quick dress shop") as null|anything in outfits
|
var/dresscode = input("Select outfit", "Robust quick dress shop") as null|anything in baseoutfits + sortList(outfits)
|
||||||
if (isnull(dresscode))
|
if (isnull(dresscode))
|
||||||
return
|
return
|
||||||
|
|
||||||
if (outfits[dresscode])
|
if (outfits[dresscode])
|
||||||
dresscode = outfits[dresscode]
|
dresscode = outfits[dresscode]
|
||||||
|
|
||||||
if(dresscode == "Cancel")
|
|
||||||
return
|
|
||||||
|
|
||||||
if (dresscode == "As Job...")
|
if (dresscode == "As Job...")
|
||||||
var/list/job_paths = subtypesof(/datum/outfit/job)
|
var/list/job_paths = subtypesof(/datum/outfit/job)
|
||||||
var/list/job_outfits = list()
|
var/list/job_outfits = list()
|
||||||
for(var/path in job_paths)
|
for(var/path in job_paths)
|
||||||
var/datum/outfit/O = path
|
var/datum/outfit/O = path
|
||||||
if(initial(O.can_be_admin_equipped))
|
|
||||||
job_outfits[initial(O.name)] = path
|
job_outfits[initial(O.name)] = path
|
||||||
|
|
||||||
dresscode = input("Select job equipment", "Robust quick dress shop") as null|anything in job_outfits
|
dresscode = input("Select job equipment", "Robust quick dress shop") as null|anything in sortList(job_outfits)
|
||||||
dresscode = job_outfits[dresscode]
|
dresscode = job_outfits[dresscode]
|
||||||
if(isnull(dresscode))
|
if(isnull(dresscode))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if (dresscode == "As Plasmaman...")
|
||||||
|
var/list/plasmaman_paths = typesof(/datum/outfit/plasmaman)
|
||||||
|
var/list/plasmaman_outfits = list()
|
||||||
|
for(var/path in plasmaman_paths)
|
||||||
|
var/datum/outfit/O = path
|
||||||
|
plasmaman_outfits[initial(O.name)] = path
|
||||||
|
|
||||||
|
dresscode = input("Select plasmeme equipment", "Robust quick dress shop") as null|anything in sortList(plasmaman_outfits)
|
||||||
|
dresscode = plasmaman_outfits[dresscode]
|
||||||
|
if(isnull(dresscode))
|
||||||
|
return
|
||||||
|
|
||||||
if (dresscode == "Custom")
|
if (dresscode == "Custom")
|
||||||
var/list/custom_names = list()
|
var/list/custom_names = list()
|
||||||
for(var/datum/outfit/D in GLOB.custom_outfits)
|
for(var/datum/outfit/D in GLOB.custom_outfits)
|
||||||
custom_names[D.name] = D
|
custom_names[D.name] = D
|
||||||
var/selected_name = input("Select outfit", "Robust quick dress shop") as null|anything in custom_names
|
var/selected_name = input("Select outfit", "Robust quick dress shop") as null|anything in sortList(custom_names)
|
||||||
dresscode = custom_names[selected_name]
|
dresscode = custom_names[selected_name]
|
||||||
if(isnull(dresscode))
|
if(isnull(dresscode))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -879,8 +879,6 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
|||||||
message_admins("[ADMIN_LOOKUPFLW(usr)] [N.timing ? "activated" : "deactivated"] a nuke at [ADMIN_VERBOSEJMP(N)].")
|
message_admins("[ADMIN_LOOKUPFLW(usr)] [N.timing ? "activated" : "deactivated"] a nuke at [ADMIN_VERBOSEJMP(N)].")
|
||||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Nuke", "[N.timing]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Nuke", "[N.timing]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||||
|
|
||||||
GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
|
||||||
|
|
||||||
/client/proc/create_outfits()
|
/client/proc/create_outfits()
|
||||||
set category = "Debug"
|
set category = "Debug"
|
||||||
set name = "Create Custom Outfit"
|
set name = "Create Custom Outfit"
|
||||||
|
|||||||
227
code/modules/admin/verbs/selectequipment.dm
Normal file
227
code/modules/admin/verbs/selectequipment.dm
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
/client/proc/cmd_select_equipment(mob/target in GLOB.mob_list)
|
||||||
|
set category = "Admin.Events"
|
||||||
|
set name = "Select equipment"
|
||||||
|
|
||||||
|
|
||||||
|
var/datum/select_equipment/ui = new(usr, target)
|
||||||
|
ui.ui_interact(usr)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the datum housing the select equipment UI.
|
||||||
|
*
|
||||||
|
* You may notice some oddities about the way outfits are passed to the UI and vice versa here.
|
||||||
|
* That's because it handles both outfit typepaths (for normal outfits) *and* outfit objects (for custom outfits).
|
||||||
|
*
|
||||||
|
* Custom outfits need to be objects as they're created in runtime.
|
||||||
|
* "Then just handle the normal outfits as objects too and simplify the handling" - you may say.
|
||||||
|
* There are about 300 outfit types at the time of writing this. Initializing all of these to objects would be a huge waste.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/datum/select_equipment
|
||||||
|
var/client/user
|
||||||
|
var/mob/target_mob
|
||||||
|
|
||||||
|
var/dummy_key
|
||||||
|
|
||||||
|
//static list to share all the outfit typepaths between all instances of this datum.
|
||||||
|
var/static/list/cached_outfits
|
||||||
|
|
||||||
|
//a typepath if the selected outfit is a normal outfit;
|
||||||
|
//an object if the selected outfit is a custom outfit
|
||||||
|
var/datum/outfit/selected_outfit = /datum/outfit
|
||||||
|
//serializable string for the UI to keep track of which outfit is selected
|
||||||
|
var/selected_identifier = "/datum/outfit"
|
||||||
|
|
||||||
|
/datum/select_equipment/New(_user, mob/target)
|
||||||
|
user = CLIENT_FROM_VAR(_user)
|
||||||
|
|
||||||
|
if(!ishuman(target) && !isobserver(target))
|
||||||
|
alert("Invalid mob")
|
||||||
|
return
|
||||||
|
target_mob = target
|
||||||
|
|
||||||
|
/datum/select_equipment/ui_interact(mob/user, datum/tgui/ui)
|
||||||
|
ui = SStgui.try_update_ui(user, src, ui)
|
||||||
|
if(!ui)
|
||||||
|
ui = new(user, src, "SelectEquipment", "Select Equipment")
|
||||||
|
ui.open()
|
||||||
|
ui.set_autoupdate(FALSE)
|
||||||
|
|
||||||
|
/datum/select_equipment/ui_state(mob/user)
|
||||||
|
return GLOB.admin_state
|
||||||
|
|
||||||
|
/datum/select_equipment/ui_status(mob/user, datum/ui_state/state)
|
||||||
|
if(QDELETED(target_mob))
|
||||||
|
return UI_CLOSE
|
||||||
|
return ..()
|
||||||
|
|
||||||
|
/datum/select_equipment/ui_close(mob/user)
|
||||||
|
clear_human_dummy(dummy_key)
|
||||||
|
qdel(src)
|
||||||
|
|
||||||
|
/datum/select_equipment/proc/init_dummy()
|
||||||
|
dummy_key = "selectequipmentUI_[target_mob]"
|
||||||
|
generate_dummy_lookalike(dummy_key, target_mob)
|
||||||
|
unset_busy_human_dummy(dummy_key)
|
||||||
|
return
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Packs up data about an outfit as an assoc list to send to the UI as an outfit entry.
|
||||||
|
*
|
||||||
|
* Args:
|
||||||
|
* * category (string) - The tab it will be under
|
||||||
|
*
|
||||||
|
* * identifier (typepath or ref) - This will sent this back to ui_act to preview or spawn in an outfit.
|
||||||
|
* * Must be unique between all entries.
|
||||||
|
*
|
||||||
|
* * name (string) - Will be the text on the button
|
||||||
|
*
|
||||||
|
* * priority (bool)(optional) - If True, the UI will sort the entry to the top, right below favorites.
|
||||||
|
*
|
||||||
|
* * custom_entry (bool)(optional) - Send the identifier with a "ref" keyword instead of "path",
|
||||||
|
* * for the UI to tell apart custom outfits from normal ones.
|
||||||
|
*
|
||||||
|
* Returns (list) An outfit entry
|
||||||
|
*/
|
||||||
|
|
||||||
|
/datum/select_equipment/proc/outfit_entry(category, identifier, name, priority=FALSE, custom_entry=FALSE)
|
||||||
|
if(custom_entry)
|
||||||
|
return list("category" = category, "ref" = identifier, "name" = name, "priority" = priority)
|
||||||
|
return list("category" = category, "path" = identifier, "name" = name, "priority" = priority)
|
||||||
|
|
||||||
|
/datum/select_equipment/proc/make_outfit_entries(category="General", list/outfit_list)
|
||||||
|
var/list/entries = list()
|
||||||
|
for(var/path as anything in outfit_list)
|
||||||
|
var/datum/outfit/outfit = path
|
||||||
|
entries += list(outfit_entry(category, path, initial(outfit.name)))
|
||||||
|
return entries
|
||||||
|
|
||||||
|
//GLOB.custom_outfits lists outfit *objects* so we'll need to do some custom handling for it
|
||||||
|
/datum/select_equipment/proc/make_custom_outfit_entries(list/outfit_list)
|
||||||
|
var/list/entries = list()
|
||||||
|
for(var/datum/outfit/outfit as anything in outfit_list)
|
||||||
|
entries += list(outfit_entry("Custom", REF(outfit), outfit.name, custom_entry=TRUE)) //it's either this or special handling on the UI side
|
||||||
|
return entries
|
||||||
|
|
||||||
|
/datum/select_equipment/ui_data(mob/user)
|
||||||
|
var/list/data = list()
|
||||||
|
if(!dummy_key)
|
||||||
|
init_dummy()
|
||||||
|
|
||||||
|
var/icon/dummysprite = get_flat_human_icon(null,
|
||||||
|
dummy_key = dummy_key,
|
||||||
|
outfit_override = selected_outfit,
|
||||||
|
no_anim = TRUE)
|
||||||
|
data["icon64"] = icon2base64(dummysprite)
|
||||||
|
data["name"] = target_mob
|
||||||
|
|
||||||
|
var/datum/preferences/prefs = user?.client?.prefs
|
||||||
|
data["favorites"] = list()
|
||||||
|
if(prefs)
|
||||||
|
data["favorites"] = prefs.favorite_outfits
|
||||||
|
|
||||||
|
var/list/custom
|
||||||
|
custom += make_custom_outfit_entries(GLOB.custom_outfits)
|
||||||
|
data["custom_outfits"] = custom
|
||||||
|
data["current_outfit"] = selected_identifier
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
/datum/select_equipment/ui_static_data(mob/user)
|
||||||
|
var/list/data = list()
|
||||||
|
if(!cached_outfits)
|
||||||
|
cached_outfits = list()
|
||||||
|
cached_outfits += list(outfit_entry("General", /datum/outfit, "Naked", priority=TRUE))
|
||||||
|
cached_outfits += make_outfit_entries("General", subtypesof(/datum/outfit) - typesof(/datum/outfit/job) - typesof(/datum/outfit/plasmaman))
|
||||||
|
cached_outfits += make_outfit_entries("Jobs", typesof(/datum/outfit/job))
|
||||||
|
cached_outfits += make_outfit_entries("Plasmamen Outfits", typesof(/datum/outfit/plasmaman))
|
||||||
|
|
||||||
|
data["outfits"] = cached_outfits
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
/datum/select_equipment/proc/resolve_outfit(text)
|
||||||
|
|
||||||
|
var/path = text2path(text)
|
||||||
|
if(ispath(path, /datum/outfit))
|
||||||
|
return path
|
||||||
|
|
||||||
|
else //don't bail yet - could be a custom outfit
|
||||||
|
var/datum/outfit/custom_outfit = locate(text)
|
||||||
|
if(istype(custom_outfit))
|
||||||
|
return custom_outfit
|
||||||
|
|
||||||
|
|
||||||
|
/datum/select_equipment/ui_act(action, params)
|
||||||
|
if(..())
|
||||||
|
return
|
||||||
|
. = TRUE
|
||||||
|
switch(action)
|
||||||
|
if("preview")
|
||||||
|
var/datum/outfit/new_outfit = resolve_outfit(params["path"])
|
||||||
|
|
||||||
|
if(ispath(new_outfit)) //got a typepath - that means we're dealing with a normal outfit
|
||||||
|
selected_identifier = new_outfit //these are keyed by type
|
||||||
|
//by the way, no, they can't be keyed by name because many of them have duplicate names
|
||||||
|
|
||||||
|
else if(istype(new_outfit)) //got an initialized object - means it's a custom outfit
|
||||||
|
selected_identifier = REF(new_outfit) //and the outfit will be keyed by its ref (cause its type will always be /datum/outfit)
|
||||||
|
|
||||||
|
else //we got nothing and should bail
|
||||||
|
return
|
||||||
|
|
||||||
|
selected_outfit = new_outfit
|
||||||
|
|
||||||
|
if("applyoutfit")
|
||||||
|
var/datum/outfit/new_outfit = resolve_outfit(params["path"])
|
||||||
|
if(new_outfit && ispath(new_outfit)) //initialize it
|
||||||
|
new_outfit = new new_outfit
|
||||||
|
if(!istype(new_outfit))
|
||||||
|
return
|
||||||
|
user.admin_apply_outfit(target_mob, new_outfit)
|
||||||
|
|
||||||
|
if("customoutfit")
|
||||||
|
user.outfit_manager()
|
||||||
|
|
||||||
|
if("togglefavorite")
|
||||||
|
var/datum/outfit/outfit_path = resolve_outfit(params["path"])
|
||||||
|
if(!ispath(outfit_path)) //we do *not* want custom outfits (i.e objects) here, they're not even persistent
|
||||||
|
return
|
||||||
|
|
||||||
|
if(user.prefs.favorite_outfits.Find(outfit_path)) //already there, remove it
|
||||||
|
user.prefs.favorite_outfits -= outfit_path
|
||||||
|
else //not there, add it
|
||||||
|
user.prefs.favorite_outfits += outfit_path
|
||||||
|
user.prefs.save_preferences()
|
||||||
|
|
||||||
|
/client/proc/admin_apply_outfit(mob/target, dresscode)
|
||||||
|
if(!ishuman(target) && !isobserver(target))
|
||||||
|
alert("Invalid mob")
|
||||||
|
return
|
||||||
|
|
||||||
|
if(!dresscode)
|
||||||
|
return
|
||||||
|
|
||||||
|
var/delete_pocket
|
||||||
|
var/mob/living/carbon/human/human_target
|
||||||
|
if(isobserver(target))
|
||||||
|
human_target = target.change_mob_type(/mob/living/carbon/human, delete_old_mob = TRUE)
|
||||||
|
else
|
||||||
|
human_target = target
|
||||||
|
if(human_target.l_store || human_target.r_store || human_target.s_store) //saves a lot of time for admins and coders alike
|
||||||
|
if(alert("Drop Items in Pockets? No will delete them.", "Robust quick dress shop", "Yes", "No") == "No")
|
||||||
|
delete_pocket = TRUE
|
||||||
|
|
||||||
|
SSblackbox.record_feedback("tally", "admin_verb", 1, "Select Equipment") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||||
|
for(var/obj/item/item in human_target.get_equipped_items(delete_pocket))
|
||||||
|
qdel(item)
|
||||||
|
if(dresscode != "Naked")
|
||||||
|
human_target.equipOutfit(dresscode)
|
||||||
|
|
||||||
|
human_target.regenerate_icons()
|
||||||
|
|
||||||
|
log_admin("[key_name(usr)] changed the equipment of [key_name(human_target)] to [dresscode].")
|
||||||
|
message_admins("<span class='adminnotice'>[key_name_admin(usr)] changed the equipment of [ADMIN_LOOKUPFLW(human_target)] to [dresscode].</span>")
|
||||||
|
|
||||||
|
return dresscode
|
||||||
@@ -227,6 +227,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
|||||||
var/persistent_scars = TRUE
|
var/persistent_scars = TRUE
|
||||||
///If we want to broadcast deadchat connect/disconnect messages
|
///If we want to broadcast deadchat connect/disconnect messages
|
||||||
var/broadcast_login_logout = TRUE
|
var/broadcast_login_logout = TRUE
|
||||||
|
///What outfit typepaths we've favorited in the SelectEquipment menu
|
||||||
|
var/list/favorite_outfits = list()
|
||||||
/// We have 5 slots for persistent scars, if enabled we pick a random one to load (empty by default) and scars at the end of the shift if we survived as our original person
|
/// We have 5 slots for persistent scars, if enabled we pick a random one to load (empty by default) and scars at the end of the shift if we survived as our original person
|
||||||
var/list/scars_list = list("1" = "", "2" = "", "3" = "", "4" = "", "5" = "")
|
var/list/scars_list = list("1" = "", "2" = "", "3" = "", "4" = "", "5" = "")
|
||||||
/// Which of the 5 persistent scar slots we randomly roll to load for this round, if enabled. Actually rolled in [/datum/preferences/proc/load_character(slot)]
|
/// Which of the 5 persistent scar slots we randomly roll to load for this round, if enabled. Actually rolled in [/datum/preferences/proc/load_character(slot)]
|
||||||
|
|||||||
@@ -385,6 +385,15 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
|||||||
S["auto_ooc"] >> auto_ooc
|
S["auto_ooc"] >> auto_ooc
|
||||||
S["no_tetris_storage"] >> no_tetris_storage
|
S["no_tetris_storage"] >> no_tetris_storage
|
||||||
|
|
||||||
|
//favorite outfits
|
||||||
|
S["favorite_outfits"] >> favorite_outfits
|
||||||
|
|
||||||
|
var/list/parsed_favs = list()
|
||||||
|
for(var/typetext in favorite_outfits)
|
||||||
|
var/datum/outfit/path = text2path(typetext)
|
||||||
|
if(ispath(path)) //whatever typepath fails this check probably doesn't exist anymore
|
||||||
|
parsed_favs += path
|
||||||
|
favorite_outfits = uniqueList(parsed_favs)
|
||||||
|
|
||||||
//try to fix any outdated data if necessary
|
//try to fix any outdated data if necessary
|
||||||
if(needs_update >= 0)
|
if(needs_update >= 0)
|
||||||
@@ -434,6 +443,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
|||||||
no_tetris_storage = sanitize_integer(no_tetris_storage, 0, 1, initial(no_tetris_storage))
|
no_tetris_storage = sanitize_integer(no_tetris_storage, 0, 1, initial(no_tetris_storage))
|
||||||
key_bindings = sanitize_islist(key_bindings, list())
|
key_bindings = sanitize_islist(key_bindings, list())
|
||||||
modless_key_bindings = sanitize_islist(modless_key_bindings, list())
|
modless_key_bindings = sanitize_islist(modless_key_bindings, list())
|
||||||
|
favorite_outfits = SANITIZE_LIST(favorite_outfits)
|
||||||
|
|
||||||
verify_keybindings_valid() // one of these days this will runtime and you'll be glad that i put it in a different proc so no one gets their saves wiped
|
verify_keybindings_valid() // one of these days this will runtime and you'll be glad that i put it in a different proc so no one gets their saves wiped
|
||||||
|
|
||||||
@@ -535,6 +545,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
|||||||
WRITE_FILE(S["pda_skin"], pda_skin)
|
WRITE_FILE(S["pda_skin"], pda_skin)
|
||||||
WRITE_FILE(S["key_bindings"], key_bindings)
|
WRITE_FILE(S["key_bindings"], key_bindings)
|
||||||
WRITE_FILE(S["modless_key_bindings"], modless_key_bindings)
|
WRITE_FILE(S["modless_key_bindings"], modless_key_bindings)
|
||||||
|
WRITE_FILE(S["favorite_outfits"], favorite_outfits)
|
||||||
|
|
||||||
//citadel code
|
//citadel code
|
||||||
WRITE_FILE(S["screenshake"], screenshake)
|
WRITE_FILE(S["screenshake"], screenshake)
|
||||||
|
|||||||
@@ -83,7 +83,6 @@
|
|||||||
standard_outfit_options = list()
|
standard_outfit_options = list()
|
||||||
for(var/path in subtypesof(/datum/outfit/job))
|
for(var/path in subtypesof(/datum/outfit/job))
|
||||||
var/datum/outfit/O = path
|
var/datum/outfit/O = path
|
||||||
if(initial(O.can_be_admin_equipped))
|
|
||||||
standard_outfit_options[initial(O.name)] = path
|
standard_outfit_options[initial(O.name)] = path
|
||||||
sortTim(standard_outfit_options, /proc/cmp_text_asc)
|
sortTim(standard_outfit_options, /proc/cmp_text_asc)
|
||||||
outfit_options = standard_outfit_options
|
outfit_options = standard_outfit_options
|
||||||
|
|||||||
@@ -24,7 +24,12 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
|
|||||||
/mob/living/carbon/human/dummy/proc/wipe_state()
|
/mob/living/carbon/human/dummy/proc/wipe_state()
|
||||||
delete_equipment()
|
delete_equipment()
|
||||||
icon_render_key = null
|
icon_render_key = null
|
||||||
cut_overlays()
|
cut_overlays(TRUE)
|
||||||
|
|
||||||
|
/mob/living/carbon/human/dummy/setup_human_dna()
|
||||||
|
create_dna(src)
|
||||||
|
randomize_human(src)
|
||||||
|
dna.initialize_dna(skip_index = TRUE) //Skip stuff that requires full round init.
|
||||||
|
|
||||||
//Inefficient pooling/caching way.
|
//Inefficient pooling/caching way.
|
||||||
GLOBAL_LIST_EMPTY(human_dummy_list)
|
GLOBAL_LIST_EMPTY(human_dummy_list)
|
||||||
@@ -42,13 +47,48 @@ GLOBAL_LIST_EMPTY(dummy_mob_list)
|
|||||||
D = new
|
D = new
|
||||||
GLOB.human_dummy_list[slotkey] = D
|
GLOB.human_dummy_list[slotkey] = D
|
||||||
GLOB.dummy_mob_list += D
|
GLOB.dummy_mob_list += D
|
||||||
|
else
|
||||||
|
D.regenerate_icons() //they were cut in wipe_state()
|
||||||
D.in_use = TRUE
|
D.in_use = TRUE
|
||||||
return D
|
return D
|
||||||
|
|
||||||
/proc/unset_busy_human_dummy(slotnumber)
|
/proc/generate_dummy_lookalike(slotkey, mob/target)
|
||||||
if(!slotnumber)
|
if(!istype(target))
|
||||||
|
return generate_or_wait_for_human_dummy(slotkey)
|
||||||
|
|
||||||
|
var/mob/living/carbon/human/dummy/copycat = generate_or_wait_for_human_dummy(slotkey)
|
||||||
|
|
||||||
|
if(iscarbon(target))
|
||||||
|
var/mob/living/carbon/carbon_target = target
|
||||||
|
carbon_target.dna.transfer_identity(copycat, transfer_SE = TRUE)
|
||||||
|
|
||||||
|
if(ishuman(target))
|
||||||
|
var/mob/living/carbon/human/human_target = target
|
||||||
|
human_target.copy_clothing_prefs(copycat)
|
||||||
|
|
||||||
|
copycat.updateappearance(icon_update=TRUE, mutcolor_update=TRUE, mutations_overlay_update=TRUE)
|
||||||
|
else
|
||||||
|
//even if target isn't a carbon, if they have a client we can make the
|
||||||
|
//dummy look like what their human would look like based on their prefs
|
||||||
|
target?.client?.prefs?.copy_to(copycat, icon_updates=TRUE, roundstart_checks=FALSE)
|
||||||
|
|
||||||
|
return copycat
|
||||||
|
|
||||||
|
/proc/unset_busy_human_dummy(slotkey)
|
||||||
|
if(!slotkey)
|
||||||
return
|
return
|
||||||
var/mob/living/carbon/human/dummy/D = GLOB.human_dummy_list[slotnumber]
|
var/mob/living/carbon/human/dummy/D = GLOB.human_dummy_list[slotkey]
|
||||||
if(istype(D))
|
if(istype(D))
|
||||||
D.wipe_state()
|
D.wipe_state()
|
||||||
D.in_use = FALSE
|
D.in_use = FALSE
|
||||||
|
|
||||||
|
/proc/clear_human_dummy(slotkey)
|
||||||
|
if(!slotkey)
|
||||||
|
return
|
||||||
|
|
||||||
|
var/mob/living/carbon/human/dummy/dummy = GLOB.human_dummy_list[slotkey]
|
||||||
|
|
||||||
|
GLOB.human_dummy_list -= slotkey
|
||||||
|
if(istype(dummy))
|
||||||
|
GLOB.dummy_mob_list -= dummy
|
||||||
|
qdel(dummy)
|
||||||
|
|||||||
@@ -14,10 +14,7 @@
|
|||||||
//initialize limbs first
|
//initialize limbs first
|
||||||
create_bodyparts()
|
create_bodyparts()
|
||||||
|
|
||||||
//initialize dna. for spawned humans; overwritten by other code
|
setup_human_dna()
|
||||||
create_dna(src)
|
|
||||||
randomize_human(src)
|
|
||||||
dna.initialize_dna()
|
|
||||||
|
|
||||||
if(dna.species)
|
if(dna.species)
|
||||||
set_species(dna.species.type)
|
set_species(dna.species.type)
|
||||||
@@ -36,6 +33,11 @@
|
|||||||
RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /atom.proc/clean_blood)
|
RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /atom.proc/clean_blood)
|
||||||
GLOB.human_list += src
|
GLOB.human_list += src
|
||||||
|
|
||||||
|
/mob/living/carbon/human/proc/setup_human_dna()
|
||||||
|
//initialize dna. for spawned humans; overwritten by other code
|
||||||
|
create_dna(src)
|
||||||
|
randomize_human(src)
|
||||||
|
dna.initialize_dna()
|
||||||
|
|
||||||
/mob/living/carbon/human/ComponentInitialize()
|
/mob/living/carbon/human/ComponentInitialize()
|
||||||
. = ..()
|
. = ..()
|
||||||
|
|||||||
@@ -176,3 +176,9 @@
|
|||||||
|
|
||||||
/mob/living/carbon/human/get_biological_state()
|
/mob/living/carbon/human/get_biological_state()
|
||||||
return dna.species.get_biological_state()
|
return dna.species.get_biological_state()
|
||||||
|
|
||||||
|
///copies over clothing preferences like underwear to another human
|
||||||
|
/mob/living/carbon/human/proc/copy_clothing_prefs(mob/living/carbon/human/destination)
|
||||||
|
destination.underwear = underwear
|
||||||
|
destination.undershirt = undershirt
|
||||||
|
destination.socks = socks
|
||||||
|
|||||||
5
html/changelogs/AutoChangeLog-pr-14642.yml
Normal file
5
html/changelogs/AutoChangeLog-pr-14642.yml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
author: "Trigg, stylemistake and SandPoot"
|
||||||
|
delete-after: True
|
||||||
|
changes:
|
||||||
|
- admin: "Admins just got a new TGUI Select Equipment menu
|
||||||
|
tweak: Prevents the window from creating sprites for any animated version there might be. (this guarantees consistant sprite size/amount)"
|
||||||
@@ -1416,6 +1416,9 @@
|
|||||||
#include "code\modules\admin\ipintel.dm"
|
#include "code\modules\admin\ipintel.dm"
|
||||||
#include "code\modules\admin\IsBanned.dm"
|
#include "code\modules\admin\IsBanned.dm"
|
||||||
#include "code\modules\admin\NewBan.dm"
|
#include "code\modules\admin\NewBan.dm"
|
||||||
|
#include "code\modules\admin\outfit_editor.dm"
|
||||||
|
#include "code\modules\admin\outfit_manager.dm"
|
||||||
|
#include "code\modules\admin\outfits.dm"
|
||||||
#include "code\modules\admin\permissionedit.dm"
|
#include "code\modules\admin\permissionedit.dm"
|
||||||
#include "code\modules\admin\player_panel.dm"
|
#include "code\modules\admin\player_panel.dm"
|
||||||
#include "code\modules\admin\sound_emitter.dm"
|
#include "code\modules\admin\sound_emitter.dm"
|
||||||
@@ -1456,6 +1459,7 @@
|
|||||||
#include "code\modules\admin\verbs\randomverbs.dm"
|
#include "code\modules\admin\verbs\randomverbs.dm"
|
||||||
#include "code\modules\admin\verbs\reestablish_db_connection.dm"
|
#include "code\modules\admin\verbs\reestablish_db_connection.dm"
|
||||||
#include "code\modules\admin\verbs\secrets.dm"
|
#include "code\modules\admin\verbs\secrets.dm"
|
||||||
|
#include "code\modules\admin\verbs\selectequipment.dm"
|
||||||
#include "code\modules\admin\verbs\shuttlepanel.dm"
|
#include "code\modules\admin\verbs\shuttlepanel.dm"
|
||||||
#include "code\modules\admin\verbs\spawnobjasmob.dm"
|
#include "code\modules\admin\verbs\spawnobjasmob.dm"
|
||||||
#include "code\modules\admin\verbs\tripAI.dm"
|
#include "code\modules\admin\verbs\tripAI.dm"
|
||||||
|
|||||||
@@ -173,6 +173,7 @@ export const sortBy = (...iterateeFns) => array => {
|
|||||||
|
|
||||||
export const sort = sortBy();
|
export const sort = sortBy();
|
||||||
|
|
||||||
|
<<<<<<< HEAD:tgui/packages/common/collections.ts
|
||||||
/**
|
/**
|
||||||
* Returns a range of numbers from start to end, exclusively.
|
* Returns a range of numbers from start to end, exclusively.
|
||||||
* For example, range(0, 5) will return [0, 1, 2, 3, 4].
|
* For example, range(0, 5) will return [0, 1, 2, 3, 4].
|
||||||
@@ -180,6 +181,8 @@ export const sort = sortBy();
|
|||||||
export const range = (start: number, end: number): number[] =>
|
export const range = (start: number, end: number): number[] =>
|
||||||
new Array(end - start).fill(null).map((_, index) => index + start);
|
new Array(end - start).fill(null).map((_, index) => index + start);
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> citadel/master:tgui/packages/common/collections.js
|
||||||
/**
|
/**
|
||||||
* A fast implementation of reduce.
|
* A fast implementation of reduce.
|
||||||
*/
|
*/
|
||||||
@@ -254,6 +257,8 @@ type Zip<T extends unknown[][]> = {
|
|||||||
[I in keyof T]: T[I] extends (infer U)[] ? U : never;
|
[I in keyof T]: T[I] extends (infer U)[] ? U : never;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
|
export const uniq = uniqBy();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an array of grouped elements, the first of which contains
|
* Creates an array of grouped elements, the first of which contains
|
||||||
* the first elements of the given arrays, the second of which contains
|
* the first elements of the given arrays, the second of which contains
|
||||||
|
|||||||
Reference in New Issue
Block a user