Hypospray and ICSpawning ports (#27279)

* Hypospray Port

The fancy new GAG enabled hyposprays.

* [MIRROR] ICSpawning Module: Quirks, Loadout, and BST RPED buff

Ports CliffracerX's work which allows quirks and/or loadout items when using the ICSpawning (ctrl+clicking a ghost)

* oops

got rid of that accidental absolute nested path thingy. (I think)
This commit is contained in:
Nidvex250
2024-04-20 17:07:14 +02:00
committed by GitHub
parent fbf8779dfa
commit 5da39ab9ee
23 changed files with 1007 additions and 127 deletions
+4 -4
View File
@@ -36,10 +36,10 @@ GLOBAL_LIST_INIT(reagent_containers, list(
/obj/item/reagent_containers/pill/patch/style
)),
// SKYRAT EDIT ADDITION START
CAT_HYPOS = list(
/obj/item/reagent_containers/cup/vial/small,
/obj/item/reagent_containers/cup/vial/large,
),
CAT_HYPOS = typecacheof(list(
/obj/item/reagent_containers/cup/vial/small/style,
/obj/item/reagent_containers/cup/vial/large/style,
)),
CAT_DARTS = typecacheof(list(
/obj/item/reagent_containers/syringe/smartdart
)),
+3 -3
View File
@@ -385,7 +385,7 @@
//name = "the hypospray" // ORIGINAL
name = "the Chief Medical Officer's hypospray" // SKYRAT EDIT CHANGE
//targetitem = /obj/item/reagent_containers/hypospray/cmo // ORIGINAL
targetitem = /obj/item/hypospray/mkii/cmo // SKYRAT EDIT CHANGE
targetitem = /obj/item/hypospray/mkii/deluxe/cmo // SKYRAT EDIT CHANGE
excludefromjob = list(JOB_CHIEF_MEDICAL_OFFICER)
item_owner = list(JOB_CHIEF_MEDICAL_OFFICER)
exists_on_map = TRUE
@@ -393,8 +393,8 @@
steal_hint = "The Chief Medical Officer's personal medical injector. \
Usually found amongst their medical supplies on their person, in their belt, or otherwise in their locker."
/obj/item/hypospray/mkii/cmo/add_stealing_item_objective() // SKYRAT EDIT CHANGE
return add_item_to_steal(src, /obj/item/hypospray/mkii/cmo) // SKYRAT EDIT CHANGE
/obj/item/hypospray/mkii/deluxe/cmo/add_stealing_item_objective() // SKYRAT EDIT CHANGE
return add_item_to_steal(src, /obj/item/hypospray/mkii/deluxe/cmo) // SKYRAT EDIT CHANGE
/datum/objective_item/steal/nukedisc
name = "the nuclear authentication disk"
+1
View File
@@ -257,6 +257,7 @@
/obj/item/hemostat,
/obj/item/holosign_creator/medical,
/obj/item/hypospray/mkii, //SKYRAT EDIT ADDITION - HYPOSPRAYS
/obj/item/storage/hypospraykit/, //SKYRAT EDIT ADDITION - HYPOSPRAYS
/obj/item/implant,
/obj/item/implantcase,
/obj/item/implanter,
@@ -102,7 +102,7 @@
// Traitor steal objective
//new /obj/item/reagent_containers/hypospray/cmo(src) - ORIGINAL
new /obj/item/storage/hypospraykit/cmo(src) //SKYRAT EDIT ADDITION - New Hyposprays
new /obj/item/storage/hypospraykit/cmo/preloaded(src) //SKYRAT EDIT ADDITION - New Hyposprays
/obj/structure/closet/secure_closet/animal
name = "animal control locker"
@@ -1489,6 +1489,21 @@ digi
name = "Wargame Hologram Projector"
icon_file = 'modular_skyrat/modules/wargame_projectors/icons/projectors_and_holograms.dmi'
json_config = 'modular_skyrat/modules/GAGS/json_configs/wargame_holoprojector/projector.json'
/datum/greyscale_config/hypokit
name = "Hypospray Kit"
icon_file = 'modular_skyrat/modules/hyposprays/icons/hypokits.dmi'
json_config = 'modular_skyrat/modules/GAGS/json_configs/items/hypokit.json'
/datum/greyscale_config/hypospray_mkii
name = "Hypospray Mk. II"
icon_file = 'modular_skyrat/modules/hyposprays/icons/hyposprays.dmi'
json_config = 'modular_skyrat/modules/GAGS/json_configs/items/hypospray.json'
/datum/greyscale_config/hypovial
name = "Hypovial"
icon_file = 'modular_skyrat/modules/hyposprays/icons/vials.dmi'
json_config = 'modular_skyrat/modules/GAGS/json_configs/items/hypovial.json'
// Evil primitive catgirl clothing
@@ -0,0 +1,41 @@
{
"custom-mini": [
{
"type": "icon_state",
"icon_state": "standard-box",
"blend_mode": "overlay"
},
{
"type": "icon_state",
"icon_state": "standard-face",
"blend_mode": "overlay",
"color_ids": [ 1 ]
}
],
"deluxe-custom-mini": [
{
"type": "icon_state",
"icon_state": "deluxe-box-normal",
"blend_mode": "overlay"
},
{
"type": "icon_state",
"icon_state": "deluxe-face",
"blend_mode": "overlay",
"color_ids": [ 1 ]
}
],
"tactical-custom-mini": [
{
"type": "icon_state",
"icon_state": "deluxe-box-tactical",
"blend_mode": "overlay"
},
{
"type": "icon_state",
"icon_state": "deluxe-face",
"blend_mode": "overlay",
"color_ids": [ 1 ]
}
]
}
@@ -0,0 +1,78 @@
{
"hypo2_normal": [
{
"type": "icon_state",
"icon_state": "hypo2_normal",
"blend_mode": "overlay"
},
{
"type": "icon_state",
"icon_state": "hypo2_accent1",
"blend_mode": "overlay",
"color_ids": [ 1 ]
},
{
"type": "icon_state",
"icon_state": "hypo2_accent2",
"blend_mode": "overlay",
"color_ids": [ 2 ]
}
],
"hypo2_deluxe": [
{
"type": "icon_state",
"icon_state": "hypo2_deluxe",
"blend_mode": "overlay"
},
{
"type": "icon_state",
"icon_state": "hypo2_accent1",
"blend_mode": "overlay",
"color_ids": [ 1 ]
},
{
"type": "icon_state",
"icon_state": "hypo2_accent2",
"blend_mode": "overlay",
"color_ids": [ 2 ]
}
],
"hypo2_cmo": [
{
"type": "icon_state",
"icon_state": "hypo2_cmo",
"blend_mode": "overlay"
},
{
"type": "icon_state",
"icon_state": "hypo2_accent1",
"blend_mode": "overlay",
"color_ids": [ 1 ]
},
{
"type": "icon_state",
"icon_state": "hypo2_accent2",
"blend_mode": "overlay",
"color_ids": [ 2 ]
}
],
"hypo2_tactical": [
{
"type": "icon_state",
"icon_state": "hypo2_tactical",
"blend_mode": "overlay"
},
{
"type": "icon_state",
"icon_state": "hypo2_accent1",
"blend_mode": "overlay",
"color_ids": [ 1 ]
},
{
"type": "icon_state",
"icon_state": "hypo2_accent2",
"blend_mode": "overlay",
"color_ids": [ 2 ]
}
]
}
@@ -0,0 +1,28 @@
{
"hypovial": [
{
"type": "icon_state",
"icon_state": "hypovial-glass",
"blend_mode": "overlay"
},
{
"type": "icon_state",
"icon_state": "hypovial-body",
"blend_mode": "overlay",
"color_ids": [ 1 ]
}
],
"hypoviallarge": [
{
"type": "icon_state",
"icon_state": "hypoviallarge-glass",
"blend_mode": "overlay"
},
{
"type": "icon_state",
"icon_state": "hypoviallarge-body",
"blend_mode": "overlay",
"color_ids": [ 1 ]
}
]
}
@@ -194,6 +194,10 @@
/datum/armament_entry/company_import/deforest/equipment/medigun_upgrade
item_type = /obj/item/device/custom_kit/medigun_fastcharge
cost = PAYCHECK_COMMAND * 2
/datum/armament_entry/company_import/deforest/equipment/hypospray_upgrade
item_type = /obj/item/device/custom_kit/deluxe_hypo2
cost = PAYCHECK_COMMAND * 2
/datum/armament_entry/company_import/deforest/equipment/afad
item_type = /obj/item/gun/medbeam/afad
@@ -1,21 +1,128 @@
/datum/design/hypoviallarge
name = "Large Hypovial"
id = "large_hypovial"
build_type = AUTOLATHE | PROTOLATHE
/datum/design/hypovial
name = "Hypovial"
id = "hypovial"
build_type = AUTOLATHE | PROTOLATHE | AWAY_LATHE
materials = list(
/datum/material/iron = SHEET_MATERIAL_AMOUNT,
/datum/material/glass = SHEET_MATERIAL_AMOUNT * 0.5,
/datum/material/iron = SHEET_MATERIAL_AMOUNT * 0.5,
)
build_path = /obj/item/reagent_containers/cup/vial/large
build_path = /obj/item/reagent_containers/cup/vial/small
category = list(
RND_CATEGORY_INITIAL,
RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_MEDICAL,
)
departmental_flags = DEPARTMENT_BITFLAG_MEDICAL
/datum/techweb_node/basic_medical/New()
design_ids += list(
"hypovial",
)
return ..()
/// Large hypovials
/datum/design/hypovial/large
name = "Large Hypovial"
id = "large_hypovial"
materials = list(
/datum/material/glass = SHEET_MATERIAL_AMOUNT,
/datum/material/iron = SHEET_MATERIAL_AMOUNT * 0.5,
)
build_path = /obj/item/reagent_containers/cup/vial/large
/datum/design/hypokit
name = "Hypospray Kit"
id = "hypokit"
build_type = PROTOLATHE | AWAY_LATHE
materials = list(
/datum/material/plastic = SHEET_MATERIAL_AMOUNT * 3,
/datum/material/iron = SHEET_MATERIAL_AMOUNT,
)
build_path = /obj/item/storage/hypospraykit/empty
category = list(
RND_CATEGORY_INITIAL,
RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_MEDICAL,
)
departmental_flags = DEPARTMENT_BITFLAG_MEDICAL
/datum/techweb_node/biotech/New()
design_ids += list(
"large_hypovial",
"hypokit",
)
return ..()
/// Hyposprays
/datum/design/hypokit/deluxe
name = "Deluxe Hypospray Kit"
id = "hypokit_deluxe"
materials = list(
/datum/material/plastic = SHEET_MATERIAL_AMOUNT * 6,
/datum/material/iron = SHEET_MATERIAL_AMOUNT * 3,
/datum/material/silver = SHEET_MATERIAL_AMOUNT * 1,
)
build_path = /obj/item/storage/hypospraykit/cmo/empty
/datum/design/hypomkii
name = "MkII Hypospray"
id = "hypomkii"
build_type = PROTOLATHE | AWAY_LATHE
materials = list(
/datum/material/plastic = SHEET_MATERIAL_AMOUNT * 5,
/datum/material/glass = SHEET_MATERIAL_AMOUNT * 3,
/datum/material/silver = SHEET_MATERIAL_AMOUNT,
)
build_path = /obj/item/hypospray/mkii
category = list(
RND_CATEGORY_INITIAL,
RND_CATEGORY_TOOLS + RND_SUBCATEGORY_TOOLS_MEDICAL,
)
departmental_flags = DEPARTMENT_BITFLAG_MEDICAL
/datum/techweb_node/adv_biotech/New()
design_ids += list(
"hypokit_deluxe",
"hypomkii",
)
return ..()
/datum/design/hypomkii/deluxe
name = "MkII Hypospray Upgrade Kit"
id = "hypomkii_deluxe"
build_type = PROTOLATHE | AWAY_LATHE
materials = list(
/datum/material/plastic = SHEET_MATERIAL_AMOUNT * 8,
/datum/material/glass = SHEET_MATERIAL_AMOUNT * 4,
/datum/material/silver = SHEET_MATERIAL_AMOUNT * 2,
)
build_path = /obj/item/device/custom_kit/deluxe_hypo2
category = list(
RND_CATEGORY_INITIAL,
RND_CATEGORY_TOOLS + RND_SUBCATEGORY_TOOLS_MEDICAL,
)
departmental_flags = DEPARTMENT_BITFLAG_MEDICAL
/datum/techweb_node/alien_bio/New()
design_ids += list(
"hypomkii_deluxe",
)
return ..()
// Tarkon and similar get enough to work with, but if they want deluxe kits/hypos they still need to trade with the station for 'em.
/datum/techweb_node/oldstation_surgery/New()
design_ids += list(
"hypokit",
"hypomkii",
)
return ..()
/// For reasons unknown, pens are included as an autolathe design here, in the hypospray module of all places.
/// I'm not touching this unless a maint asks me to because it feels weird and haunted, like the picture of a potato that bricks Source if you remove it.
/datum/design/pen
name = "Pen"
id = "pen"
build_type = AUTOLATHE
build_type = AUTOLATHE | AWAY_LATHE
materials = list(
/datum/material/iron = SMALL_MATERIAL_AMOUNT,
/datum/material/glass = SMALL_MATERIAL_AMOUNT,
@@ -24,4 +131,4 @@
category = list(
RND_CATEGORY_INITIAL,
RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_MISC,
)
)
@@ -1,31 +1,41 @@
/obj/item/storage/hypospraykit
name = "hypospray kit"
desc = "It's a kit containing a hypospray and specific treatment chemical-filled vials."
desc = "A hypospray kit with foam insets for hypovials and a mounting point on the bottom."
icon = 'modular_skyrat/modules/hyposprays/icons/hypokits.dmi'
icon_state = "firstaid-mini"
worn_icon_state = "healthanalyzer" // Get a better sprite later
inhand_icon_state = "medkit"
greyscale_config = /datum/greyscale_config/hypokit
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
// Small hypokits can be pocketed, but don't have much storage.
w_class = WEIGHT_CLASS_SMALL
slot_flags = ITEM_SLOT_BELT
throw_speed = 3
throw_range = 7
var/empty = FALSE
var/current_case = "firstaid"
var/static/list/case_designs
var/static/list/cmo_case_designs
var/cmo_case = FALSE
var/static/list/case_designs_xl
var/is_xl = FALSE
/// Tracks if a hypospray is attached to the case or not.
var/obj/item/hypospray/mkii/attached_hypo
//Code to give hypospray kits selectable paterns.
/obj/item/storage/hypospraykit/examine(mob/living/user)
. = ..()
. += span_notice("Ctrl-Shift-Click to reskin this")
if(attached_hypo)
. += span_notice("[attached_hypo] is mounted on the bottom. Alt-Right-Click to take it off.")
else
. += span_notice("Right-Click with a hypospray to mount it.")
/obj/item/storage/hypospraykit/Initialize(mapload)
. = ..()
if(!length(case_designs))
populate_case_designs()
atom_storage.max_slots = 12
atom_storage.max_slots = 7
atom_storage.can_hold = typecacheof(list(
/obj/item/hypospray/mkii,
/obj/item/reagent_containers/cup/vial
@@ -35,11 +45,26 @@
/obj/item/storage/hypospraykit/Destroy()
// a large block to stop the CI Gods smiting us & taking extra steps to try and force the CMO hypo to drop smartly
var/atom/drop_loc = drop_location(src)
if(QDELETED(drop_loc))
drop_loc = get_turf(src)
if(QDELETED(drop_loc))
QDEL_NULL(attached_hypo)
return ..()
// so long as it found a place to drop, run through and try to drop any indestructible items we contain
for(var/obj/item in contents)
if(QDELING(loc))
if(item.resistance_flags & INDESTRUCTIBLE) // Because we're not supposed to delete stuff that are indestructible, but I'm too lazy to do something more complex upstream now. Later, maybe.
item.forceMove(get_turf(src))
. = ..()
if(item.resistance_flags & INDESTRUCTIBLE)
atom_storage.remove_single(null, item, drop_loc, TRUE)
// this also includes attached hypos - if indestructible, shunt it out, otherwise qdel it, and in all cases make sure we drop the ref & unregister the signal
if(attached_hypo)
if(attached_hypo.resistance_flags & INDESTRUCTIBLE)
attached_hypo.forceMove(drop_loc)
else
QDEL_NULL(attached_hypo)
attached_hypo = null
UnregisterSignal(attached_hypo, COMSIG_QDELETING)
return ..()
/obj/item/storage/hypospraykit/proc/populate_case_designs()
@@ -48,12 +73,65 @@
"brute" = image(icon = src.icon, icon_state = "brute-mini"),
"burn" = image(icon = src.icon, icon_state = "burn-mini"),
"toxin" = image(icon = src.icon, icon_state = "toxin-mini"),
"rad" = image(icon = src.icon, icon_state = "rad-mini"),
"purple" = image(icon = src.icon, icon_state = "purple-mini"),
"oxy" = image(icon = src.icon, icon_state = "oxy-mini"))
cmo_case_designs = list(
"tactical" = image(icon= src.icon, icon_state = "tactical-mini"))
cmo_case_designs += case_designs
"oxy" = image(icon = src.icon, icon_state = "oxy-mini"),
"advanced" = image(icon = src.icon, icon_state = "advanced-mini"),
"buffs" = image(icon = src.icon, icon_state = "buffs-mini"),
"custom" = image(icon = src.icon, icon_state = "standard-gags-mini"))
case_designs_xl = list(
"cmo" = image(icon = src.icon, icon_state = "cmo-mini"),
"emt" = image(icon = src.icon, icon_state = "emt-mini"),
"tactical" = image(icon = src.icon, icon_state = "tactical-mini"),
"deluxe-custom" = image(icon = src.icon, icon_state = "deluxe-gags-normal-mini"),
"tactical-custom" = image(icon = src.icon, icon_state = "deluxe-gags-tactical-mini"))
/obj/item/storage/hypospraykit/update_overlays()
. = ..()
if(attached_hypo)
if(attached_hypo.greyscale_colors != null) //it's one of the GAGS variants
var/mutable_appearance/hypo_overlay = mutable_appearance(initial(icon), attached_hypo.icon_state)
. += hypo_overlay
var/list/split_colors = splittext(attached_hypo.greyscale_colors, "#")
var/mutable_appearance/hypo_overlay_acc1 = mutable_appearance(initial(icon), "hypo2_accent1")
hypo_overlay_acc1.color = "#[split_colors[2]]"
. += hypo_overlay_acc1
var/mutable_appearance/hypo_overlay_acc2 = mutable_appearance(initial(icon), "hypo2_accent2")
hypo_overlay_acc2.color = "#[split_colors[3]]"
. += hypo_overlay_acc2
else
var/mutable_appearance/hypo_overlay = mutable_appearance(initial(icon), attached_hypo.icon_state)
. += hypo_overlay
/obj/item/storage/hypospraykit/attackby_secondary(obj/item/weapon, mob/user, params)
if(istype(weapon, /obj/item/hypospray/mkii))
if(attached_hypo != null)
balloon_alert(user, "Mount point full! Remove [attached_hypo] first!")
else
weapon.moveToNullspace()
attached_hypo = weapon
RegisterSignal(weapon, COMSIG_QDELETING, PROC_REF(on_attached_hypo_qdel))
balloon_alert(user, "Attached [attached_hypo].")
update_appearance()
// This stops atom_storage from hogging your right-click and opening the inventory.
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ..()
/obj/item/storage/hypospraykit/alt_click_secondary(mob/user)
if(attached_hypo != null)
if(user.put_in_hands(attached_hypo))
balloon_alert(user, "Removed [attached_hypo].")
UnregisterSignal(attached_hypo, COMSIG_QDELETING)
attached_hypo = null
update_appearance()
// Ditto here.
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
else
balloon_alert(user, "Couldn't pull the hypo!")
return ..()
/obj/item/storage/hypospraykit/proc/on_attached_hypo_qdel()
if(attached_hypo)
attached_hypo = null
update_appearance()
/obj/item/storage/hypospraykit/update_icon_state()
. = ..()
@@ -62,14 +140,27 @@
/obj/item/storage/hypospraykit/proc/case_menu(mob/user)
if(.)
return
var/casetype = cmo_case_designs
if(!src.cmo_case)
casetype = case_designs
var/choice = show_radial_menu(user, src , casetype, custom_check = CALLBACK(src, PROC_REF(check_menu), user), radius = 42, require_near = TRUE)
var/list/designs = case_designs
if(is_xl)
designs = case_designs_xl
var/choice = show_radial_menu(user, src, designs, custom_check = CALLBACK(src, PROC_REF(check_menu), user), radius = 42, require_near = TRUE)
if(!choice)
return FALSE
current_case = choice
update_icon()
if(findtext(current_case, "custom"))
var/atom/fake_atom = src
var/list/allowed_configs = list()
var/config = initial(fake_atom.greyscale_config)
allowed_configs += "[config]"
if(greyscale_colors == null)
greyscale_colors = "#00AAFF"
var/datum/greyscale_modify_menu/menu = new(src, usr, allowed_configs)
menu.ui_interact(usr)
else //restore normal icon
icon = initial(icon)
greyscale_colors = null
/obj/item/storage/hypospraykit/proc/check_menu(mob/user)
if(!istype(user))
@@ -84,40 +175,95 @@
//END OF HYPOSPRAY CASE MENU CODE
/obj/item/storage/hypospraykit/empty
desc = "A hypospray kit with general use vials."
/obj/item/storage/hypospraykit/empty/PopulateContents()
/obj/item/storage/hypospraykit/PopulateContents()
if(empty)
return
new /obj/item/hypospray/mkii(src)
/obj/item/storage/hypospraykit/empty
empty = TRUE
/// Deluxe hypokit: more storage, but you can't pocket it.
/obj/item/storage/hypospraykit/cmo
name = "deluxe hypospray kit"
desc = "A kit containing a deluxe hypospray and vials."
icon_state = "tactical-mini"
inhand_icon_state = "medkit-tactical"
current_case = "tactical"
cmo_case = TRUE
desc = "An extended hypospray kit with foam insets for hypovials & a mounting point on the bottom."
icon_state = "cmo-mini"
current_case = "cmo"
is_xl = TRUE
w_class = WEIGHT_CLASS_NORMAL
/obj/item/storage/hypospraykit/cmo/Initialize(mapload)
. = ..()
atom_storage.max_slots = 21
atom_storage.max_total_storage = 28 //keeps a wiggle room of 7 just in case size weirdness happens
/obj/item/storage/hypospraykit/cmo/PopulateContents()
if(empty)
return
new /obj/item/hypospray/mkii/cmo(src)
new /obj/item/hypospray/mkii/deluxe/cmo(src)
/obj/item/storage/hypospraykit/cmo/empty
desc = "An extended hypospray kit with foam insets for hypovials & a mounting point on the bottom."
icon_state = "emt-mini"
current_case = "emt"
empty = TRUE
/// Preloaded version: this is what goes in the locker.
/obj/item/storage/hypospraykit/cmo/preloaded
name = "CMO's deluxe hypospray kit"
desc = "The CMO's precious extended hypospray kit, preloaded with a deluxe hypospray & a handful of vials. Retains the usual insets and mounting point of smaller hypokits."
/obj/item/storage/hypospraykit/cmo/preloaded/PopulateContents()
if(empty)
return
new /obj/item/hypospray/mkii/deluxe/cmo(src)
new /obj/item/reagent_containers/cup/vial/large/deluxe(src)
new /obj/item/reagent_containers/cup/vial/large/multiver(src)
new /obj/item/reagent_containers/cup/vial/large/salglu(src)
new /obj/item/reagent_containers/cup/vial/large/synthflesh(src)
/// Combat hypokit
/obj/item/storage/hypospraykit/cmo/combat
name = "combat hypospray kit"
desc = "A larger tactical hypospray kit containing a combat-focused deluxe hypospray and vials."
icon_state = "tactical-mini"
current_case = "tactical"
/obj/item/storage/hypospraykit/cmo/combat/PopulateContents()
if(empty)
return
new /obj/item/hypospray/mkii/deluxe/cmo/combat(src)
new /obj/item/reagent_containers/cup/vial/large/advbrute(src)
new /obj/item/reagent_containers/cup/vial/large/advburn(src)
new /obj/item/reagent_containers/cup/vial/large/advtox(src)
new /obj/item/reagent_containers/cup/vial/large/advoxy(src)
new /obj/item/reagent_containers/cup/vial/large/advcrit(src)
new /obj/item/reagent_containers/cup/vial/large/advomni(src)
new /obj/item/reagent_containers/cup/vial/large/numbing(src)
/// Boxes of empty hypovials, coming in every style.
/obj/item/storage/box/vials
name = "box of hypovials"
/obj/item/storage/box/vials/PopulateContents()
for(var/i in 1 to 7)
new /obj/item/reagent_containers/cup/vial/small( src )
for(var/vialpath in subtypesof(/obj/item/reagent_containers/cup/vial/small/style))
new vialpath(src)
// Ditto, just large vials.
/obj/item/storage/box/vials/deluxe
name = "box of deluxe hypovials"
/obj/item/storage/box/vials/deluxe/PopulateContents()
for(var/vialpath in subtypesof(/obj/item/reagent_containers/cup/vial/large/style))
new vialpath(src)
// A box of small hypospray kits, pre-skinned to each variant to remind people what styles are available.
/obj/item/storage/box/hypospray
name = "box of hypospray kits"
/obj/item/storage/box/hypospray/PopulateContents()
for(var/i in 1 to 4)
new /obj/item/storage/hypospraykit/empty(src)
var/list/case_designs = list("firstaid", "brute", "burn", "toxin", "oxy", "advanced", "buffs")
for(var/label in case_designs)
var/obj/item/storage/hypospraykit/newkit = new /obj/item/storage/hypospraykit(src)
newkit.current_case = label
newkit.update_icon_state()
@@ -20,18 +20,18 @@
name = "hypospray mk.II"
icon_state = "hypo2"
icon = 'modular_skyrat/modules/hyposprays/icons/hyposprays.dmi'
desc = "A new development from DeForest Medical, this hypospray takes 60-unit vials as the drug supply for easy swapping."
greyscale_config = /datum/greyscale_config/hypospray_mkii
desc = "A new development from DeForest Medical, this hypospray takes 50-unit vials as the drug supply for easy swapping."
w_class = WEIGHT_CLASS_TINY
var/list/allowed_containers = list(/obj/item/reagent_containers/cup/vial/small)
/// Is the hypospray only able to use small vials. Relates to the loaded overlays
var/small_only = TRUE
/// Inject or spray?
var/mode = HYPO_INJECT
/// The presently-inserted vial.
var/obj/item/reagent_containers/cup/vial/vial
/// If the Hypospray starts with a vial, which vial does it start with?
var/start_vial
/// Does the Hypospray start with a vial?
var/spawnwithvial = FALSE
/// Time taken to inject others
var/inject_wait = WAIT_INJECT
@@ -46,54 +46,86 @@
var/quickload = TRUE
/// Does it penetrate clothing?
var/penetrates = null
/// Used for GAGS-ified hypos.
var/gags_bodystate = "hypo2_normal"
/obj/item/hypospray/mkii/cmo
/obj/item/hypospray/mkii/deluxe
name = "hypospray mk.II deluxe"
allowed_containers = list(/obj/item/reagent_containers/cup/vial/small, /obj/item/reagent_containers/cup/vial/large)
icon_state = "cmo2"
desc = "The deluxe hypospray can take larger 120-unit vials. It also acts faster and can deliver more reagents per spray."
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
start_vial = /obj/item/reagent_containers/cup/vial/large/deluxe
spawnwithvial = TRUE
icon_state = "bighypo2"
gags_bodystate = "hypo2_deluxe"
desc = "The deluxe DeForest Mk. II hypospray, able to take both 100u and 50u vials."
small_only = FALSE
// Deluxe hypo upgrade Kit
/obj/item/device/custom_kit/deluxe_hypo2
name = "DeForest Mk. II Hypospray Deluxe Bodykit"
desc = "Upgrades the DeForest Mk. II Hypospray to support larger vials."
// don't tinker with a loaded (medi)gun. fool
from_obj = /obj/item/hypospray/mkii
to_obj = /obj/item/hypospray/mkii/deluxe
/obj/item/device/custom_kit/deluxe_hypo2/pre_convert_check(obj/target_obj, mob/user)
var/obj/item/hypospray/mkii/our_hypo = target_obj
if(our_hypo.type in subtypesof(/obj/item/hypospray/mkii/))
balloon_alert(user, "only works on basic mk. ii hypos!")
return FALSE
if(our_hypo.vial != null)
balloon_alert(user, "unload the vial first!")
return FALSE
return TRUE
/obj/item/hypospray/mkii/deluxe/cmo
name = "CMO's deluxe hypospray mk.II"
icon_state = "cmo2"
gags_bodystate = "hypo2_cmo"
desc = "The CMO's prized deluxe hypospray, able to take both 100u and 50u vials, acting faster and able to deliver more reagents per spray."
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
inject_wait = DELUXE_WAIT_INJECT
spray_wait = DELUXE_WAIT_SPRAY
spray_self = DELUXE_SELF_SPRAY
inject_self = DELUXE_SELF_INJECT
penetrates = INJECT_CHECK_PENETRATE_THICK
/obj/item/hypospray/mkii/deluxe/cmo/combat
name = "combat-grade hypospray mk.II"
icon_state = "combat2"
gags_bodystate = "hypo2_tactical"
desc = "A variant of the deluxe hypospray, able to take both 100u and 50u vials, with overcharged applicators and an armor-piercing tip."
// Made non-indestructible since this is typically an admin spawn. still robust though!
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
inject_wait = COMBAT_WAIT_INJECT
spray_wait = COMBAT_WAIT_SPRAY
spray_self = COMBAT_SELF_INJECT
inject_self = COMBAT_SELF_SPRAY
penetrates = INJECT_CHECK_PENETRATE_THICK
/obj/item/hypospray/mkii/Initialize(mapload)
. = ..()
if(!spawnwithvial)
update_appearance()
return
if(start_vial)
vial = new start_vial
update_appearance()
AddElement(/datum/element/update_icon_updates_onmob)
/obj/item/hypospray/mkii/update_overlays()
. = ..()
if(!vial)
return
if(!vial.reagents.total_volume)
return
var/vial_spritetype = "chem-color"
if(!small_only)
vial_spritetype += "[vial.type_suffix]"
if(vial.reagents.total_volume)
var/vial_spritetype = "chem-color"
if(!small_only)
vial_spritetype += "[vial.type_suffix]"
else
vial_spritetype += "-s"
var/mutable_appearance/chem_loaded = mutable_appearance(initial(icon), vial_spritetype)
chem_loaded.color = vial.chem_color
. += chem_loaded
if(vial.greyscale_colors != null)
var/mutable_appearance/vial_overlay = mutable_appearance(initial(icon), "[vial.icon_state]-body")
vial_overlay.color = vial.greyscale_colors
. += vial_overlay
var/mutable_appearance/vial_overlay_glass = mutable_appearance(initial(icon), "[vial.icon_state]-glass")
. += vial_overlay_glass
else
vial_spritetype += "-s"
var/mutable_appearance/chem_loaded = mutable_appearance('modular_skyrat/modules/hyposprays/icons/hyposprays.dmi', vial_spritetype)
chem_loaded.color = vial.chem_color
. += chem_loaded
/obj/item/hypospray/mkii/update_icon_state()
. = ..()
var/icon_suffix = "-s"
if(!small_only && vial)
icon_suffix = vial.type_suffix //Sets the suffix used to the correspoding vial.
icon_state = "[initial(icon_state)][vial ? "[icon_suffix]" : ""]"
var/mutable_appearance/vial_overlay = mutable_appearance(initial(icon), vial.icon_state)
. += vial_overlay
/obj/item/hypospray/mkii/examine(mob/user)
. = ..()
@@ -101,6 +133,26 @@
. += "[vial] has [vial.reagents.total_volume]u remaining."
else
. += "It has no vial loaded in."
. += span_notice("Ctrl-Shift-Click to change up the colors or reset them.")
/obj/item/hypospray/mkii/CtrlShiftClick(mob/user, obj/item/I)
var/choice = tgui_input_list(user, "GAGSify the hypo or reset to default?", "Fashion", list("GAGS", "Nope"))
if(choice == "GAGS")
icon_state = gags_bodystate
//choices go here
var/atom/fake_atom = src
var/list/allowed_configs = list()
var/config = initial(fake_atom.greyscale_config)
allowed_configs += "[config]"
if(greyscale_colors == null)
greyscale_colors = "#00AAFF#FFAA00"
var/datum/greyscale_modify_menu/menu = new(src, usr, allowed_configs)
menu.ui_interact(usr)
else
icon_state = initial(icon_state)
icon = initial(icon)
greyscale_colors = null
/obj/item/hypospray/mkii/proc/unload_hypo(obj/item/hypo, mob/user)
if((istype(hypo, /obj/item/reagent_containers/cup/vial)))
@@ -218,13 +270,13 @@
if(injectee != user)
injectee.visible_message(span_danger("[user] is trying to [fp_verb] [injectee] with [src]!"), \
span_userdanger("[user] is trying to [fp_verb] you with [src]!"))
var/selected_wait_time
if(target == user)
selected_wait_time = (mode == HYPO_INJECT) ? inject_self : spray_self
else
selected_wait_time = (mode == HYPO_INJECT) ? inject_wait : spray_wait
if(!do_after(user, selected_wait_time, injectee, extra_checks = CALLBACK(injectee, /mob/living/proc/can_inject, user, user.zone_selected, penetrates)))
return
if(!vial.reagents.total_volume)
@@ -279,4 +331,4 @@
#undef COMBAT_WAIT_SPRAY
#undef COMBAT_WAIT_INJECT
#undef COMBAT_SELF_SPRAY
#undef COMBAT_SELF_INJECT
#undef COMBAT_SELF_INJECT
@@ -3,37 +3,74 @@
desc = "You probably shouldn't be seeing this. Shout at a coder."
icon = 'modular_skyrat/modules/hyposprays/icons/vials.dmi'
icon_state = "hypovial"
greyscale_config = /datum/greyscale_config/hypovial
fill_icon_state = "hypovial_fill"
spillable = FALSE
volume = 10
/// The suffix of the overlay texture that the hypovial uses when loading textures.
var/type_suffix = "-s"
possible_transfer_amounts = list(1,2,5,10)
fill_icon_thresholds = list(10, 25, 50, 75, 100)
var/chem_color //Used for hypospray overlay
var/chem_color = "#FFFFFF" //Used for hypospray overlay
var/type_suffix = "-s"
fill_icon = 'modular_skyrat/modules/hyposprays/icons/hypospray_fillings.dmi'
current_skin = "hypovial"
unique_reskin = list(
"Sterile" = "hypovial",
"Generic" = "hypovial-generic",
"Brute" = "hypovial-brute",
"Burn" = "hypovial-burn",
"Toxin" = "hypovial-tox",
"Oxyloss" = "hypovial-oxy",
"Crit" = "hypovial-crit",
"Buff" = "hypovial-buff",
"Custom" = "hypovial-custom",
)
/obj/item/reagent_containers/cup/vial/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_OBJ_RESKIN, PROC_REF(on_reskin))
/obj/item/reagent_containers/cup/vial/Destroy(force)
. = ..()
UnregisterSignal(src, COMSIG_OBJ_RESKIN)
/obj/item/reagent_containers/cup/vial/examine(mob/user)
. = ..()
. += span_notice("Ctrl-Shift-Click to reskin or set a custom color.")
/obj/item/reagent_containers/cup/vial/CtrlShiftClick(mob/user, obj/item/I)
current_skin = null
icon_state = initial(icon_state)
icon = initial(icon)
greyscale_colors = null
reskin_obj(user)
/obj/item/reagent_containers/cup/vial/proc/on_reskin()
if(current_skin == "Custom")
icon_state = unique_reskin["Sterile"]
current_skin = unique_reskin["Sterile"]
var/atom/fake_atom = src
var/list/allowed_configs = list()
var/config = initial(fake_atom.greyscale_config)
allowed_configs += "[config]"
if(greyscale_colors == null)
greyscale_colors = "#FFFF00"
var/datum/greyscale_modify_menu/menu = new(src, usr, allowed_configs)
menu.ui_interact(usr)
else
icon_state = unique_reskin[current_skin]
/obj/item/reagent_containers/cup/vial/update_overlays()
. = ..()
if(!fill_icon_thresholds)
return
if(reagents.total_volume)
var/fill_name = fill_icon_state? fill_icon_state : icon_state
var/fill_overlay = 10
switch(round((reagents.total_volume / volume)*100))
if(1 to 24)
fill_overlay = 10
if(25 to 49)
fill_overlay = 25
if(50 to 74)
fill_overlay = 50
if(75 to 89)
fill_overlay = 75
if(89 to 100)
fill_overlay = 100
var/mutable_appearance/filling = mutable_appearance('modular_skyrat/modules/hyposprays/icons/hypospray_fillings.dmi', "[fill_name][fill_overlay]")
filling.color = mix_color_from_reagents(reagents.reagent_list)
chem_color = filling.color
. += filling
// Search the overlays for the fill overlay from reagent_containers, and nudge its layer down to have it look correct.
chem_color = "#FFFFFF"
var/list/generated_overlays = .
for(var/added_overlay in generated_overlays)
if(istype(added_overlay, /mutable_appearance))
var/mutable_appearance/overlay_image = added_overlay
if(findtext(overlay_image.icon_state, fill_icon_state) != 0)
overlay_image.layer = layer - 0.01
chem_color = overlay_image.color
/obj/item/reagent_containers/cup/vial/Initialize(mapload)
. = ..()
@@ -49,28 +86,120 @@
volume = 50
possible_transfer_amounts = list(1,2,5,10,15,25,50)
/obj/item/reagent_containers/cup/vial/small/style
icon_state = "hypovial"
//Styles
/obj/item/reagent_containers/cup/vial/small/style/generic
icon_state = "hypovial-generic"
/obj/item/reagent_containers/cup/vial/small/style/brute
icon_state = "hypovial-brute"
/obj/item/reagent_containers/cup/vial/small/style/burn
icon_state = "hypovial-burn"
/obj/item/reagent_containers/cup/vial/small/style/toxin
icon_state = "hypovial-tox"
/obj/item/reagent_containers/cup/vial/small/style/oxy
icon_state = "hypovial-oxy"
/obj/item/reagent_containers/cup/vial/small/style/crit
icon_state = "hypovial-crit"
/obj/item/reagent_containers/cup/vial/small/style/buff
icon_state = "hypovial-buff"
//Fit in CMO hypo only
/obj/item/reagent_containers/cup/vial/large
name = "large hypovial"
icon_state = "hypoviallarge"
fill_icon_state = "hypoviallarge_fill"
current_skin = "hypoviallarge"
desc = "A large, 100u capacity vial that fits only in the most deluxe hyposprays."
volume = 100
type_suffix = "-l"
possible_transfer_amounts = list(1,2,5,10,20,30,40,50,100)
type_suffix = "-l"
unique_reskin = list(
"Sterile" = "hypoviallarge",
"Generic" = "hypoviallarge-generic",
"Brute" = "hypoviallarge-brute",
"Burn" = "hypoviallarge-burn",
"Toxin" = "hypoviallarge-tox",
"Oxyloss" = "hypoviallarge-oxy",
"Crit" = "hypoviallarge-crit",
"Buff" = "hypoviallarge-buff",
"Custom" = "hypoviallarge-custom",
)
/obj/item/reagent_containers/cup/vial/large/style/
icon_state = "hypoviallarge"
//Styles
/obj/item/reagent_containers/cup/vial/large/style/generic
icon_state = "hypoviallarge-generic"
/obj/item/reagent_containers/cup/vial/large/style/brute
icon_state = "hypoviallarge-brute"
/obj/item/reagent_containers/cup/vial/large/style/burn
icon_state = "hypoviallarge-burn"
/obj/item/reagent_containers/cup/vial/large/style/toxin
icon_state = "hypoviallarge-tox"
/obj/item/reagent_containers/cup/vial/large/style/oxy
icon_state = "hypoviallarge-oxy"
/obj/item/reagent_containers/cup/vial/large/style/crit
icon_state = "hypoviallarge-crit"
/obj/item/reagent_containers/cup/vial/large/style/buff
icon_state = "hypoviallarge-buff"
//Hypos that are in the CMO's kit round start
/obj/item/reagent_containers/cup/vial/large/deluxe
name = "deluxe hypovial"
icon_state = "hypoviallarge-buff"
list_reagents = list(/datum/reagent/medicine/omnizine = 15, /datum/reagent/medicine/leporazine = 15, /datum/reagent/medicine/atropine = 15)
/obj/item/reagent_containers/cup/vial/large/salglu
name = "large green hypovial (salglu)"
icon_state = "hypoviallarge-oxy"
list_reagents = list(/datum/reagent/medicine/salglu_solution = 50)
/obj/item/reagent_containers/cup/vial/large/synthflesh
name = "large orange hypovial (synthflesh)"
icon_state = "hypoviallarge-crit"
list_reagents = list(/datum/reagent/medicine/c2/synthflesh = 50)
/obj/item/reagent_containers/cup/vial/large/multiver
name = "large black hypovial (multiver)"
icon_state = "hypoviallarge-tox"
list_reagents = list(/datum/reagent/medicine/c2/multiver = 50)
//Some bespoke helper types for preloaded combat medkits.
/obj/item/reagent_containers/cup/vial/large/advbrute
name = "Brute Heal"
icon_state = "hypoviallarge-brute"
list_reagents = list(/datum/reagent/medicine/c2/libital = 50, /datum/reagent/medicine/sal_acid = 50)
/obj/item/reagent_containers/cup/vial/large/advburn
name = "Burn Heal"
icon_state = "hypoviallarge-burn"
list_reagents = list(/datum/reagent/medicine/c2/aiuri = 50, /datum/reagent/medicine/oxandrolone = 50)
/obj/item/reagent_containers/cup/vial/large/advtox
name = "Toxin Heal"
icon_state = "hypoviallarge-tox"
list_reagents = list(/datum/reagent/medicine/pen_acid = 100)
/obj/item/reagent_containers/cup/vial/large/advoxy
name = "Oxy Heal"
icon_state = "hypoviallarge-oxy"
list_reagents = list(/datum/reagent/medicine/c2/tirimol = 50, /datum/reagent/medicine/salbutamol = 50)
/obj/item/reagent_containers/cup/vial/large/advcrit
name = "Crit Heal"
icon_state = "hypoviallarge-crit"
list_reagents = list(/datum/reagent/medicine/atropine = 100)
/obj/item/reagent_containers/cup/vial/large/advomni
name = "All-Heal"
icon_state = "hypoviallarge-buff"
list_reagents = list(/datum/reagent/medicine/regen_jelly = 100)
/obj/item/reagent_containers/cup/vial/large/numbing
name = "Numbing"
icon_state = "hypoviallarge-generic"
list_reagents = list(/datum/reagent/medicine/mine_salve = 50, /datum/reagent/medicine/morphine = 50)
@@ -1,3 +1,3 @@
/obj/machinery/vending/drugs/Initialize(mapload)
products[/obj/item/storage/hypospraykit/empty] = 5
products[/obj/item/storage/hypospraykit] = 5
. = ..()
Binary file not shown.

Before

Width:  |  Height:  |  Size: 988 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 584 B

After

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

+6 -2
View File
@@ -1,4 +1,4 @@
https://github.com/Skyrat-SS13/Skyrat-tg/pull/1929
Original PR: https://github.com/Skyrat-SS13/Skyrat-tg/pull/1929
## Title: Hyposprays
@@ -11,7 +11,10 @@ Gives Medical back its Hyposprays. Oldbase stuff is good.
### TG Proc Changes:
- CMO's locker now contains a new object, the CMO's Hypospray Kit. Old Hypospray has been commented out.
- Medical Doctor and Paramedic jobs now spawn with a standard Hypospray kit in backpack_contents
- Chemistry lockers now contain two boxes of Standard Hypospray Kits.
- Medical belts can carry the Mk II Hyposprays, vials, and Hypospray Kits.
- Adds CAT_HYPOS to ``code/_globalvars/lists/reagents.dm`` to allow vials to be printed from chem dispensers.
- Bluespace technicans get combat hypospray kits for QOL and testing.
### Defines:
@@ -41,3 +44,4 @@ Gives Medical back its Hyposprays. Oldbase stuff is good.
### Credits:
ShadeAware - Porting
CliffracerX - Tweaks & new sprites
@@ -36,6 +36,12 @@
if(!give_return)
return
var/addquirks
if(character_option == "Selected Character")
addquirks = tgui_input_list(src, "Include quirks?", "Quirky", list("Quirks & Loadout", "Quirks Only", "Loadout Only", "Neither"))
if(!addquirks)
return
var/turf/current_turf = get_turf(user)
var/mob/living/carbon/human/spawned_player = new(user)
@@ -44,10 +50,20 @@
spawned_player.name = user.name
spawned_player.real_name = user.real_name
var/mob/living/carbon/human/H = spawned_player
user.client?.prefs.safe_transfer_prefs_to(H)
H.dna.update_dna_identity()
var/mob/living/carbon/human/player_as_human = spawned_player
user.client?.prefs.safe_transfer_prefs_to(player_as_human)
if(addquirks == "Quirks & Loadout" || addquirks == "Loadout Only")
if(dresscode == "Naked")
player_as_human.equip_outfit_and_loadout(new /datum/outfit(), user.client?.prefs)
else
player_as_human.equip_outfit_and_loadout(dresscode, user.client?.prefs)
else if(dresscode != "Naked")
spawned_player.equipOutfit(dresscode)
if(addquirks == "Quirks & Loadout" || addquirks == "Quirks Only")
SSquirks.AssignQuirks(player_as_human, user.client)
player_as_human.dna.update_dna_identity()
else if(dresscode != "Naked")
spawned_player.equipOutfit(dresscode)
QDEL_IN(user, 1)
if (teleport_option == "Bluespace")
@@ -62,9 +78,6 @@
var/datum/action/cooldown/spell/return_back/return_spell = new(spawned_player)
return_spell.Grant(spawned_player)
if(dresscode != "Naked")
spawned_player.equipOutfit(dresscode)
switch(teleport_option)
if("Bluespace")
spawned_player.forceMove(current_turf)
@@ -91,8 +104,9 @@
var/list/paths = subtypesof(/datum/outfit) - typesof(/datum/outfit/job) - typesof(/datum/outfit/plasmaman)
for(var/path in paths)
var/datum/outfit/O = path //not much to initalize here but whatever
outfits[initial(O.name)] = path
// Get the datum from the path so we can grab its name.
var/datum/outfit/path_as_outfit = path
outfits[initial(path_as_outfit.name)] = path
var/dresscode = tgui_input_list(src, "Select outfit", "Robust quick dress shop", baseoutfits + sort_list(outfits))
@@ -128,11 +142,11 @@
if (dresscode == "Custom")
var/list/custom_names = list()
for(var/datum/outfit/D in GLOB.custom_outfits)
custom_names[D.name] = D
for(var/datum/outfit/req_outfit in GLOB.custom_outfits)
custom_names[req_outfit.name] = req_outfit
var/selected_name = input("Select outfit", "Robust quick dress shop") as null|anything in sort_list(custom_names)
dresscode = custom_names[selected_name]
if(isnull(dresscode))
return
return dresscode
return dresscode
@@ -36,6 +36,16 @@
shoes = /obj/item/clothing/shoes/combat/debug
id = /obj/item/card/id/advanced/debug/bst
box = /obj/item/storage/box/debugtools
backpack_contents = list(
/obj/item/melee/energy/axe = 1,
/obj/item/storage/part_replacer/bluespace/tier4/bst = 1,
/obj/item/gun/magic/wand/resurrection/debug = 1,
/obj/item/gun/magic/wand/death/debug = 1,
/obj/item/debug/human_spawner = 1,
/obj/item/debug/omnitool = 1,
/obj/item/storage/box/stabilized = 1,
/obj/item/storage/hypospraykit/cmo/combat = 1,
)
/datum/outfit/admin/bst //Debug objs plus modsuit
name = "Bluespace Tech (MODsuit)"
@@ -44,3 +54,243 @@
shoes = /obj/item/clothing/shoes/combat/debug
id = /obj/item/card/id/advanced/debug/bst
box = /obj/item/storage/box/debugtools
backpack_contents = list(
/obj/item/melee/energy/axe = 1,
/obj/item/storage/part_replacer/bluespace/tier4/bst = 1,
/obj/item/gun/magic/wand/resurrection/debug = 1,
/obj/item/gun/magic/wand/death/debug = 1,
/obj/item/debug/human_spawner = 1,
/obj/item/debug/omnitool = 1,
/obj/item/storage/box/stabilized = 1,
/obj/item/storage/hypospraykit/cmo/combat = 1,
)
/obj/item/storage/part_replacer/bluespace/tier4/bst
name = "\improper Bluespace Tech RPED"
desc = "A specialized bluespace RPED for technicians that can manufacture stock parts on the fly. Alt-Right-Click to manufacture parts, change settings, or clear its internal storage."
/// Whether or not auto-clear is enabled
var/auto_clear = TRUE
/// List of valid types for pick_stock_part().
var/static/list/valid_stock_part_types = list(
/obj/item/circuitboard/machine,
/obj/item/stock_parts,
/obj/item/reagent_containers/cup/beaker,
)
/obj/item/storage/part_replacer/bluespace/tier4/bst/Initialize(mapload)
. = ..()
atom_storage.max_slots = 1000
atom_storage.max_total_storage = 20000
/// An extension to the default RPED part replacement action - if you don't have the requisite parts in the RPED already, it will spawn T4 versions to use.
/obj/item/storage/part_replacer/bluespace/tier4/bst/part_replace_action(obj/attacked_object, mob/living/user)
// We start with setting up a list of the current contents of the RPED when using auto-clear. This is used to detect new items after upgrades are applied & remove them.
var/list/old_contents = list()
var/list/inv_grab = atom_storage.return_inv(FALSE)
if(auto_clear)
old_contents = atom_storage.return_inv(FALSE)
// Once old_contents has been initialized, if needed, we check if the target object is a machine frame.
var/obj/structure/frame/attacked_frame = attacked_object
if(istype(attacked_frame, /obj/structure/frame/machine))
var/obj/structure/frame/machine/machine_frame = attacked_frame
var/obj/item/circuitboard/machine/circuit = machine_frame.circuit
// Prioritize using the circuit's components list first, if present, to maintain consistency.
if(istype(circuit))
spawn_parts_for_components(user, circuit.req_components)
else if(machine_frame.req_components)
spawn_parts_for_components(user, machine_frame.req_components)
else
// It's not a machine frame, so let's check if it's a regular machine.
if(ismachinery(attacked_object) && !istype(attacked_object, /obj/machinery/computer))
var/obj/machinery/attacked_machinery = attacked_object
var/obj/item/circuitboard/machine/circuit = attacked_machinery.circuit
// If it is, we need to use the circuit's components; there's no good way to get required components off of an already-built machine.
if(istype(circuit))
spawn_parts_for_components(user, circuit.req_components)
. = ..()
// If auto-clear is in use,
if(auto_clear)
inv_grab.Cut()
inv_grab = atom_storage.return_inv(FALSE)
for(var/obj/item/stored_item in inv_grab)
if(!(stored_item in old_contents))
qdel(stored_item)
/// A bespoke proc for spawning in parts
/obj/item/storage/part_replacer/bluespace/tier4/bst/proc/spawn_parts_for_components(mob/living/user, list/required_components)
// Since req_components in machineboards can list item types *OR* /datum/stock_part subtypes this gets a little complicated.
var/list/subtypes = list()
for(var/req_component in required_components)
// Start off noting how many the recipe calls for, a counter for how many matching parts have been found, and generating a list of subtypes for use in later checks.
var/parts_amount_required = required_components[req_component]
var/found_matching = 0
subtypes = typesof(req_component)
if(!parts_amount_required)
continue
/// Then, check if the requested component is an object subtype - this means it's probably either materials (e.g, cables) or non-stock_part subtypes like beakers.
if(ispath(req_component, /obj/item))
// If it's a stack, it needs special treatment.
if(ispath(req_component, /obj/item/stack))
// Stacks generate the matching count based on how many matching stacks are in the RPED's inventory with sufficient count.
// To find stacks inside the RPED, we search its contents for anything that's a subtype of /obj/item/stack.
for(var/obj/stored_item in contents)
var/obj/item/stack/stored_item_as_stack = stored_item
if(istype(stored_item_as_stack))
// If a stack item is found, we check if it's in the typesof list for the current requested component, and if so, mark its count.
if(stored_item_as_stack.type in subtypes)
found_matching += stored_item_as_stack.amount
// If there's enough, we can return early.
if(found_matching >= parts_amount_required)
break
// If there's not enough left, spawn enough of the appropriate type that there will be. Stacks' Initialialize accepts an amount for the newly-spawned stack to have, and will auto-split as needed.
if(found_matching < parts_amount_required)
atom_storage.attempt_insert(new req_component(src, parts_amount_required - found_matching), user, TRUE)
continue
else
// It's not a stack, which means now we have to count how many matching items are present.
for(var/obj/stored_item in contents)
if(stored_item.type in subtypes)
found_matching += 1
// If there's enough, we can break - no need to spawn extras.
if(found_matching >= parts_amount_required)
break
// If there's still not enough, we're going to have to spawn enough in manually.
if(found_matching < parts_amount_required)
for(var/i in 1 to parts_amount_required - found_matching)
atom_storage.attempt_insert(new req_component(src), user, TRUE)
continue
/// If it's not an obj, then it's a subtype of /datum/stock_part - or *should be*, anyway.
else if(ispath(req_component, /datum/stock_part))
var/datum/stock_part/part_type = new req_component()
var/base_type = part_type.physical_object_base_type
// Specific machines sometimes call for specific tiers of part; give them precisely what they ask for, just in case.
if(part_type.tier > 1)
base_type = part_type.physical_object_type
// Search to see if we have enough of that exact item, and if not, we'll spawn more.
for(var/obj/stored_item in contents)
if(stored_item.type == base_type)
found_matching += 1
// If there's enough, we can return early.
if(found_matching >= parts_amount_required)
break
// If there's still not enough, we're going to have to spawn enough in manually.
if(found_matching < parts_amount_required)
for(var/i in 1 to parts_amount_required - found_matching)
atom_storage.attempt_insert(new base_type(src), user, TRUE)
continue
else
// For everything else, just make sure we have enough valid items of the stock part's subtypes.
subtypes = typesof(base_type)
for(var/obj/stored_item in contents)
if(stored_item.type in subtypes)
found_matching += 1
// If there's enough, we can return early.
if(found_matching >= parts_amount_required)
break
// If there's still not enough, we're going to have to spawn enough in manually.
if(found_matching < parts_amount_required)
// Reset the subtypes list so we can pick the highest tier of part available.
subtypes = typesof(req_component)
var/highest_tier = 0
// Search those subtypes for the highest. This SHOULD only ever go up to 4, but that's on the assumption upstream doesn't change it.
for(var/subtype_path in subtypes)
var/datum/stock_part/sub_part = new subtype_path()
if(sub_part.tier > highest_tier)
highest_tier = sub_part.tier
base_type = sub_part.physical_object_type
// Once the best component has been found, fill in enough remaining.
for(var/i in 1 to parts_amount_required - found_matching)
atom_storage.attempt_insert(new base_type(src), user, TRUE)
continue
// If it's not a /datum/stock_part subtype either, something has gone wrong and devs should probably be alerted.
if(found_matching < parts_amount_required)
to_chat(user, span_notice("Something went wrong manufacturing [req_component]. Alert the devs, and let them know what machine it was!"))
/// BSTs' special Bluespace RPED can manufacture parts on Alt-RMB, either cables, glass, machine boards, or stock parts.
/obj/item/storage/part_replacer/bluespace/tier4/bst/alt_click_secondary(mob/user)
// Ask the user what they want to make, or if they want to clear the storage.
var/spawn_selection = tgui_input_list(user, "Pick a part, or clear storage", "RPED Manufacture", list("Clear All Items", "Toggle Auto-Clear", "Cables", "Glass", "Spare T4s", "Machine Board", "Stock Part", "Beaker"))
// If they didn't cancel out of the list selection, we do things. Clear-all removes all items, auto-clear destroys left-overs after upgrades, and everything else is pretty self-explanatory.
// Machine boards and stock parts use a recursive subtype selector.
if(isnull(spawn_selection))
return
else if(spawn_selection == "Clear All Items")
var/list/inv_grab = atom_storage.return_inv(FALSE)
for(var/obj/item/stored_item in inv_grab)
qdel(stored_item)
else if(spawn_selection == "Toggle Auto-Clear")
auto_clear = !auto_clear
to_chat(user, span_notice("The RPED will now [(auto_clear ? "destroy" : "keep")] items left-over after upgrades."))
else if(spawn_selection == "Cables")
atom_storage.attempt_insert(new /obj/item/stack/cable_coil(src), user, TRUE)
else if(spawn_selection == "Glass")
atom_storage.attempt_insert(new /obj/item/stack/sheet/glass/fifty(src), user, TRUE)
else if(spawn_selection == "Spare T4s")
for(var/i in 1 to 10)
atom_storage.attempt_insert(new /obj/item/stock_parts/capacitor/quadratic(src), user, TRUE)
atom_storage.attempt_insert(new /obj/item/stock_parts/scanning_module/triphasic(src), user, TRUE)
atom_storage.attempt_insert(new /obj/item/stock_parts/servo/femto(src), user, TRUE)
atom_storage.attempt_insert(new /obj/item/stock_parts/micro_laser/quadultra(src), user, TRUE)
atom_storage.attempt_insert(new /obj/item/stock_parts/matter_bin/bluespace(src), user, TRUE)
atom_storage.attempt_insert(new /obj/item/stock_parts/cell/bluespace(src), user, TRUE)
else
var/subtype
if(spawn_selection == "Machine Board")
subtype = /obj/item/circuitboard/machine
else if(spawn_selection == "Stock Part")
subtype = /obj/item/stock_parts
else if(spawn_selection == "Beaker")
subtype = /obj/item/reagent_containers/cup/beaker
if(subtype)
pick_stock_part(user, FALSE, subtype)
/// A bespoke proc for picking a subtype to spawn in a relatively user-friendly way.
/obj/item/storage/part_replacer/bluespace/tier4/bst/proc/pick_stock_part(mob/user, recurse, subtype)
// Sanity check: make sure it's actually an item, and not an atom, machine, or whatever else someone might try to feed it down the line.
if(!is_path_in_list(subtype, valid_stock_part_types))
return
// Stores a list of pretty type names : actual paths.
var/list/items_temp = list()
// Grab the initial list of paths, NOT INCLUDING this specific path.
var/list/paths = subtypesof(subtype)
// Simplistic check to only list top-level subtypes.
var/list/top_level_subtypes_only = list()
for(var/datum/subtype_path as anything in paths)
if(initial(subtype_path.parent_type) != subtype)
continue
top_level_subtypes_only += subtype_path
paths = top_level_subtypes_only
// With all sub-subtypes removed, initialize the list of valid, spawnable items & their pretty names - and if this is a recursion, include the original subtype.
if(recurse)
paths += subtype
for(var/path in paths)
var/obj/path_as_obj = path
// Generates a pretty list of item names & paths, including notes for those with subtypes. When browsing subtypes, the parent won't have the (# more) note added.
if(length(subtypesof(path)))
if(path == subtype)
items_temp["[initial(path_as_obj.name)]: [path]"] = path
else
items_temp["[initial(path_as_obj.name)] (+[length(subtypesof(path))] more): [path]"] = path
else
items_temp["[initial(path_as_obj.name)]: [path]"] = path
// Finally, once the listed is generated, ask the user what they want to spawn.
var/target_item = tgui_input_list(user, "Select Subtype", "RPED Manufacture", sort_list(items_temp))
if(target_item)
// If they select something, and the name:path binding is valid, then either spawn it, OR, if it has subtypes, and isn't the parent type, recurse to let them pick a subtype.
if(items_temp[target_item])
var/the_item = items_temp[target_item]
if(length(subtypesof(the_item)) && the_item != subtype)
pick_stock_part(user, TRUE, the_item)
else
for(var/i in 1 to 25)
atom_storage.attempt_insert(new the_item(src), user, TRUE)
@@ -38,8 +38,7 @@ GLOBAL_LIST_INIT(loadout_pocket_items, generate_loadout_items(/datum/loadout_ite
id_card.forceMove(wallet)
if(equipper.back)
var/list/backpack_stuff = list()
equipper.back.atom_storage?.return_inv(backpack_stuff, FALSE)
var/list/backpack_stuff = equipper.back.atom_storage?.return_inv(FALSE)
for(var/obj/item/thing in backpack_stuff)
if(wallet.contents.len >= 3)
break
@@ -117,6 +116,10 @@ GLOBAL_LIST_INIT(loadout_pocket_items, generate_loadout_items(/datum/loadout_ite
name = "Personal AI Device"
item_path = /obj/item/pai_card
/datum/loadout_item/pocket_items/link_scryer
name = "MODlink Scryer"
item_path = /obj/item/clothing/neck/link_scryer/loaded
/datum/loadout_item/pocket_items/cigarettes
name = "Cigarette Pack"
item_path = /obj/item/storage/fancy/cigarettes
@@ -201,6 +204,14 @@ GLOBAL_LIST_INIT(loadout_pocket_items, generate_loadout_items(/datum/loadout_ite
name = "First-Aid Kit"
item_path = /obj/item/storage/medkit/regular
/datum/loadout_item/pocket_items/deforest_cheesekit
name = "Civil Defense Medical Kit"
item_path = /obj/item/storage/medkit/civil_defense/stocked
/datum/loadout_item/pocket_items/deforest_frontiermedkit
name = "Frontier Medical Kit"
item_path = /obj/item/storage/medkit/frontier/stocked
/datum/loadout_item/pocket_items/ingredients
name = "Wildcard Ingredient Box"
item_path = /obj/item/storage/box/ingredients/wildcard
@@ -311,4 +322,4 @@ GLOBAL_LIST_INIT(loadout_pocket_items, generate_loadout_items(/datum/loadout_ite
/datum/loadout_item/pocket_items/donator/vape
name = "E-Cigarette"
item_path = /obj/item/clothing/mask/vape
item_path = /obj/item/clothing/mask/vape
@@ -45,7 +45,7 @@
/obj/item/mod/control/pre_equipped/safeguard, \
/obj/item/gun/energy/cell_loaded/medigun/cmo, \
/obj/item/defibrillator/compact/loaded, \
/obj/item/storage/hypospraykit/cmo, \
/obj/item/storage/hypospraykit/cmo/preloaded, \
/obj/item/mod/control/pre_equipped/rescue, \
/obj/item/gun/ballistic/rifle/boltaction/sporterized, \
/obj/item/clothing/glasses/hud/gun_permit/sunglasses, \