diff --git a/code/__DEFINES/color/colors.dm b/code/__DEFINES/color/colors.dm
index 836ec7d119..cc11a1aeaa 100644
--- a/code/__DEFINES/color/colors.dm
+++ b/code/__DEFINES/color/colors.dm
@@ -123,6 +123,8 @@
#define COLOR_THEME_OPERATIVE "#B8221F"
#define COLOR_THEME_GLASS "#75A4C4"
#define COLOR_THEME_CLOCKWORK "#CFBA47"
+#define COLOR_THEME_TRASENKNOX "#3ce375"
+#define COLOR_THEME_DETECTIVE "#c7b08b"
#define COLOR_THEME_LITEWEB "#226611"
///Colors for eigenstates
diff --git a/code/__DEFINES/hud.dm b/code/__DEFINES/hud.dm
index 88cba1c449..9c161c0a5f 100644
--- a/code/__DEFINES/hud.dm
+++ b/code/__DEFINES/hud.dm
@@ -7,3 +7,6 @@
#define ui_borg_pda_send "CENTER+5:21,SOUTH:5" // To the right of the alert panel
#define ui_borg_pda_log "CENTER+6:21,SOUTH:5"
+
+/// The filter name for the hover outline
+#define HOVER_OUTLINE_FILTER "hover_outline"
diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm
index 63e0c0a0f9..40c2b38036 100644
--- a/code/__HELPERS/type2type.dm
+++ b/code/__HELPERS/type2type.dm
@@ -701,6 +701,12 @@
return 'modular_citadel/icons/ui/screen_operative.dmi'
if('icons/mob/screen_clockwork.dmi')
return 'modular_citadel/icons/ui/screen_clockwork.dmi'
+ if('icons/mob/screen_glass.dmi')
+ return 'modular_citadel/icons/ui/screen_glass.dmi'
+ if('icons/mob/screen_trasenknox.dmi')
+ return 'modular_citadel/icons/ui/screen_trasenknox.dmi'
+ if('icons/mob/screen_detective.dmi')
+ return 'modular_citadel/icons/ui/screen_detective.dmi'
if('modular_sand/icons/mob/screen_liteweb.dmi')
return 'modular_sand/icons/mob/screen_liteweb.dmi'
else
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index 593fa1a411..285134d3f9 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -11,7 +11,10 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
"Plasmafire" = 'icons/mob/screen_plasmafire.dmi',
"Slimecore" = 'icons/mob/screen_slimecore.dmi',
"Operative" = 'icons/mob/screen_operative.dmi',
+ "Glass" = 'icons/mob/screen_glass.dmi',
"Clockwork" = 'icons/mob/screen_clockwork.dmi',
+ "Trasen-Knox" = 'icons/mob/screen_trasenknox.dmi',
+ "Detective" = 'icons/mob/screen_detective.dmi',
"Liteweb" = 'modular_sand/icons/mob/screen_liteweb.dmi'
))
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index eac3ab807b..d1303a06e7 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -358,11 +358,11 @@
using.hud = src
hotkeybuttons += using
- using = new /atom/movable/screen/rest()
- using.icon = ui_style
- using.screen_loc = ui_pull_resist
- using.hud = src
- static_inventory += using
+ rest_icon = new /atom/movable/screen/rest()
+ rest_icon.icon = ui_style
+ rest_icon.screen_loc = ui_pull_resist
+ rest_icon.hud = src
+ static_inventory += rest_icon
//END OF CIT CHANGES
using = new /atom/movable/screen/human/toggle()
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index 2b27915ac7..e74d7fad4a 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -154,9 +154,8 @@
if(!icon_empty)
icon_empty = icon_state
- if(!hud?.mymob || !slot_id || !icon_full)
- return ..()
- icon_state = hud.mymob.get_item_by_slot(slot_id) ? icon_full : icon_empty
+ if(hud?.mymob && slot_id && icon_full)
+ icon_state = hud.mymob.get_item_by_slot(slot_id) ? icon_full : icon_empty
return ..()
/atom/movable/screen/inventory/proc/add_overlays()
@@ -207,7 +206,7 @@
. += blocked_overlay
if(held_index == hud.mymob.active_hand_index)
- . += "hand_active"
+ . += (held_index % 2) ? "lhandactive" : "rhandactive"
/atom/movable/screen/inventory/hand/Click(location, control, params)
@@ -411,6 +410,7 @@
name = "rest"
icon = 'icons/mob/screen_midnight.dmi'
icon_state = "act_rest"
+ base_icon_state = "act_rest"
plane = HUD_PLANE
/atom/movable/screen/rest/Click()
@@ -422,10 +422,7 @@
var/mob/living/user = hud?.mymob
if(!istype(user))
return ..()
- if(!user.resting)
- icon_state = "act_rest"
- else
- icon_state = "act_rest0"
+ icon_state = "[base_icon_state][user.resting ? 0 : null]"
return ..()
/atom/movable/screen/throw_catch
diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm
index 3ed3e521e4..8e9124c306 100644
--- a/code/datums/components/crafting/crafting.dm
+++ b/code/datums/components/crafting/crafting.dm
@@ -1,17 +1,13 @@
/datum/component/personal_crafting/Initialize()
if(ismob(parent))
- RegisterSignal(parent, COMSIG_MOB_CLIENT_LOGIN, .proc/create_mob_button)
+ RegisterSignal(parent, COMSIG_MOB_HUD_CREATED, .proc/create_mob_button)
-/datum/component/personal_crafting/proc/create_mob_button(mob/user, client/CL)
+/datum/component/personal_crafting/proc/create_mob_button(mob/user)
var/datum/hud/H = user.hud_used
- for(var/huds in H.static_inventory)
- if(istype(huds, /atom/movable/screen/craft))
- return
- //We don't want to be stacking multiple crafting huds on relogs
var/atom/movable/screen/craft/C = new()
C.icon = H.ui_style
H.static_inventory += C
- CL.screen += C
+ user.client.screen += C
RegisterSignal(C, COMSIG_CLICK, .proc/component_ui_interact)
/datum/component/personal_crafting
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 03833833cd..b45272e1f3 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -1377,6 +1377,11 @@
if(filter_data && filter_data[name])
return filters[filter_data.Find(name)]
+/// Returns the indice in filters of the given filter name.
+/// If it is not found, returns null.
+/atom/proc/get_filter_index(name)
+ return filter_data?.Find(name)
+
/atom/proc/remove_filter(name_or_names)
if(!filter_data)
return
diff --git a/code/game/objects/effects/decals/misc.dm b/code/game/objects/effects/decals/misc.dm
index 752a5dff2c..fe216c0623 100644
--- a/code/game/objects/effects/decals/misc.dm
+++ b/code/game/objects/effects/decals/misc.dm
@@ -1,18 +1,3 @@
-/obj/effect/temp_visual/point
- name = "pointer"
- icon = 'icons/mob/screen_gen.dmi'
- icon_state = "arrow"
- layer = POINT_LAYER
- duration = 25
-
-/obj/effect/temp_visual/point/Initialize(mapload, set_invis = 0)
- . = ..()
- var/atom/old_loc = loc
- loc = get_turf(src) // We don't want to actualy trigger anything when it moves
- pixel_x = old_loc.pixel_x
- pixel_y = old_loc.pixel_y
- invisibility = set_invis
-
//Used by spraybottles.
/obj/effect/decal/chempuff
name = "chemicals"
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 5f519e1cc9..efd9b4b370 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -931,13 +931,13 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
/obj/item/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params)
. = ..()
- remove_filter("hover_outline") //get rid of the hover effect in case the mouse exit isn't called if someone drags and drops an item and somthing goes wrong
+ remove_filter(HOVER_OUTLINE_FILTER) //get rid of the hover effect in case the mouse exit isn't called if someone drags and drops an item and somthing goes wrong
/obj/item/MouseExited(location, control, params)
SEND_SIGNAL(src, COMSIG_ITEM_MOUSE_EXIT, location, control, params)
deltimer(usr.client.tip_timer) //delete any in-progress timer if the mouse is moved off the item before it finishes
closeToolTip(usr)
- remove_filter("hover_outline")
+ remove_filter(HOVER_OUTLINE_FILTER)
/obj/item/proc/apply_outline(outline_color = null)
if(get(src, /mob) != usr || QDELETED(src) || isobserver(usr)) //cancel if the item isn't in an inventory, is being deleted, or if the person hovering is a ghost (so that people spectating you don't randomly make your items glow)
@@ -959,6 +959,10 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
outline_color = COLOR_THEME_CLOCKWORK //if you want free gbp go fix the fact that clockwork's tooltip css is glass'
if("glass")
outline_color = COLOR_THEME_GLASS
+ if("trasen-knox")
+ outline_color = COLOR_THEME_TRASENKNOX
+ if("detective")
+ outline_color = COLOR_THEME_DETECTIVE
if("liteweb")
outline_color = COLOR_THEME_LITEWEB
else //this should never happen, hopefully
@@ -966,7 +970,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
if(color)
outline_color = COLOR_WHITE //if the item is recolored then the outline will be too, let's make the outline white so it becomes the same color instead of some ugly mix of the theme and the tint
- add_filter("hover_outline", 1, list("type" = "outline", "size" = 1, "color" = outline_color))
+ add_filter(HOVER_OUTLINE_FILTER, 1, list("type" = "outline", "size" = 1, "color" = outline_color))
// Called when a mob tries to use the item as a tool.
// Handles most checks.
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 6b9d1e8018..defdfd6402 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -217,6 +217,7 @@
/obj/item/stack/medical/gauze/cyborg
custom_materials = null
is_cyborg = TRUE
+ source = /datum/robot_energy_storage/medical
cost = 250
/obj/item/stack/medical/suture
@@ -441,6 +442,7 @@
/obj/item/stack/medical/bone_gel/cyborg
custom_materials = null
is_cyborg = TRUE
+ source = /datum/robot_energy_storage/medical
cost = 250
/obj/item/stack/medical/aloe
diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm
index e05e7cb50e..24e12848c6 100644
--- a/code/game/objects/items/stacks/rods.dm
+++ b/code/game/objects/items/stacks/rods.dm
@@ -40,7 +40,7 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \
/obj/item/stack/rods/update_icon_state()
var/amount = get_amount()
- if(amount <= 5)
+ if(amount <= 5 && amount >= 1)
icon_state = "rods-[amount]"
else
icon_state = "rods"
@@ -78,11 +78,8 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \
/obj/item/stack/rods/cyborg
custom_materials = null
is_cyborg = TRUE
- cost = 250
-
-/obj/item/stack/rods/cyborg/ComponentInitialize()
- . = ..()
- AddElement(/datum/element/update_icon_blocker)
+ source = /datum/robot_energy_storage/medical
+ cost = MINERAL_MATERIAL_AMOUNT * 0.125
/obj/item/stack/rods/ten
amount = 10
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index 1eb49f350c..929b572e06 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -52,7 +52,8 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
/obj/item/stack/sheet/glass/cyborg
custom_materials = null
is_cyborg = TRUE
- cost = 500
+ source = /datum/robot_energy_storage/glass
+ cost = MINERAL_MATERIAL_AMOUNT * 0.25
/obj/item/stack/sheet/glass/fifty
amount = 50
@@ -179,9 +180,15 @@ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \
/obj/item/stack/sheet/rglass/cyborg
custom_materials = null
is_cyborg = TRUE
- var/datum/robot_energy_storage/glasource
- var/metcost = 250
- var/glacost = 500
+ source = /datum/robot_energy_storage/metal
+ var/datum/robot_energy_storage/glasource = /datum/robot_energy_storage/glass
+ var/metcost = MINERAL_MATERIAL_AMOUNT * 0.125
+ var/glacost = MINERAL_MATERIAL_AMOUNT * 0.25
+
+/obj/item/stack/sheet/rglass/cyborg/prepare_estorage(obj/item/robot_module/module)
+ . = ..()
+ if(glasource)
+ glasource = module.get_or_create_estorage(glasource)
/obj/item/stack/sheet/rglass/cyborg/get_amount()
return min(round(source.energy / metcost), round(glasource.energy / glacost))
@@ -189,10 +196,12 @@ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \
/obj/item/stack/sheet/rglass/cyborg/use(used, transfer = FALSE) // Requires special checks, because it uses two storages
source.use_charge(used * metcost)
glasource.use_charge(used * glacost)
+ update_icon()
/obj/item/stack/sheet/rglass/cyborg/add(amount)
source.add_charge(amount * metcost)
glasource.add_charge(amount * glacost)
+ update_icon()
/obj/item/stack/sheet/rglass/get_main_recipes()
. = ..()
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index b7debdd57b..78fb004211 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -166,7 +166,8 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \
/obj/item/stack/sheet/metal/cyborg
custom_materials = null
is_cyborg = TRUE
- cost = 500
+ source = /datum/robot_energy_storage/metal
+ cost = MINERAL_MATERIAL_AMOUNT * 0.25
/obj/item/stack/sheet/metal/get_main_recipes()
. = ..()
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 275cd4492c..982ad5f34a 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -42,6 +42,12 @@
var/matter_amount = 0
/obj/item/stack/Initialize(mapload, new_amount, merge = TRUE)
+ if(is_cyborg)
+ if(!istype(loc, /obj/item/robot_module))
+ stack_trace("Cyborg stack created outside of a robot module, deleting.")
+ return INITIALIZE_HINT_QDEL
+ prepare_estorage(loc)
+
if(new_amount != null)
amount = new_amount
while(amount > max_amount)
@@ -383,7 +389,9 @@
if(check && zero_amount())
return FALSE
if (is_cyborg)
- return source.use_charge(used * cost)
+ . = source.use_charge(used * cost)
+ update_icon()
+ return
if (amount < used)
return FALSE
amount -= used
@@ -583,3 +591,12 @@
/obj/item/stack/microwave_act(obj/machinery/microwave/M)
if(istype(M) && M.dirty < 100)
M.dirty += amount
+
+/obj/item/stack/proc/prepare_estorage(obj/item/robot_module/module)
+ if(source)
+ source = module.get_or_create_estorage(source)
+
+/obj/item/stack/Moved(old_loc, dir)
+ . = ..()
+ if(isturf(loc))
+ update_icon()
diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm
index 8b49f8838e..66f5e3c43b 100644
--- a/code/game/objects/items/stacks/tiles/tile_types.dm
+++ b/code/game/objects/items/stacks/tiles/tile_types.dm
@@ -538,7 +538,8 @@
/obj/item/stack/tile/plasteel/cyborg
custom_materials = null // All other Borg versions of items have no Metal or Glass - RR
is_cyborg = TRUE
- cost = 125
+ source = /datum/robot_energy_storage/metal
+ cost = MINERAL_MATERIAL_AMOUNT * 0.0625
/obj/item/stack/tile/material
name = "floor tile"
diff --git a/code/game/objects/items/stacks/wrap.dm b/code/game/objects/items/stacks/wrap.dm
index c969e2d1d4..953d69dcf7 100644
--- a/code/game/objects/items/stacks/wrap.dm
+++ b/code/game/objects/items/stacks/wrap.dm
@@ -40,6 +40,12 @@
resistance_flags = FLAMMABLE
grind_results = list(/datum/reagent/cellulose = 5)
+/obj/item/stack/packageWrap/cyborg
+ custom_materials = null
+ is_cyborg = TRUE
+ source = /datum/robot_energy_storage/wrapping_paper
+ cost = 1
+
/obj/item/stack/packageWrap/suicide_act(mob/living/user)
user.visible_message("[user] begins wrapping [user.p_them()]self in \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
if(use(3))
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 2fcfcad871..91580e1577 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -2769,8 +2769,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/pickedui = input(user, "Choose your UI style.", "Character Preference", UI_style) as null|anything in GLOB.available_ui_styles
if(pickedui)
UI_style = pickedui
- if (parent && parent.mob && parent.mob.hud_used)
- parent.mob.hud_used.update_ui_style(ui_style2icon(UI_style))
+ if (pickedui && parent && parent.mob && parent.mob.hud_used)
+ QDEL_NULL(parent.mob.hud_used)
+ parent.mob.create_mob_hud()
+ parent.mob.hud_used.show_hud(1, parent.mob)
if("pda_style")
var/pickedPDAStyle = input(user, "Choose your PDA style.", "Character Preference", pda_style) as null|anything in GLOB.pda_styles
if(pickedPDAStyle)
@@ -3219,7 +3221,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
outline_enabled = !outline_enabled
if("outline_color")
var/pickedOutlineColor = input(user, "Choose your outline color.", "General Preference", outline_color) as color|null
- if(pickedOutlineColor != pickedOutlineColor)
+ if(pickedOutlineColor != outline_color)
outline_color = pickedOutlineColor // nullable
if("screentip_pref")
var/choice = input(user, "Choose your screentip preference", "Screentipping?", screentip_pref) as null|anything in GLOB.screentip_pref_options
diff --git a/code/modules/mining/equipment/marker_beacons.dm b/code/modules/mining/equipment/marker_beacons.dm
index d8e54ae322..3ec466dad4 100644
--- a/code/modules/mining/equipment/marker_beacons.dm
+++ b/code/modules/mining/equipment/marker_beacons.dm
@@ -31,6 +31,12 @@ GLOBAL_LIST_INIT(marker_beacon_colors, list(
/obj/item/stack/marker_beacon/thirty //and they're bought in stacks of 1, 10, or 30
amount = 30
+/obj/item/stack/marker_beacon/cyborg
+ is_cyborg = TRUE
+ custom_materials = null
+ source = /datum/robot_energy_storage/beacon
+ cost = 1
+
/obj/item/stack/marker_beacon/Initialize(mapload)
. = ..()
update_icon()
diff --git a/code/modules/mob/living/living_mobility.dm b/code/modules/mob/living/living_mobility.dm
index 6f5337fc11..ddc1cf6ce6 100644
--- a/code/modules/mob/living/living_mobility.dm
+++ b/code/modules/mob/living/living_mobility.dm
@@ -16,6 +16,7 @@
/mob/living/proc/update_resting(update_mobility = TRUE)
if(update_mobility)
update_mobility()
+ update_rest_hud_icon()
//Force mob to rest, does NOT do stamina damage.
//It's really not recommended to use this proc to give feedback, hence why silent is defaulting to true.
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index f34dca623b..bbbb242452 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -86,7 +86,7 @@
if(!(m in R.held_items))
. += m
-/obj/item/robot_module/proc/get_or_create_estorage(var/storage_type)
+/obj/item/robot_module/proc/get_or_create_estorage(storage_type)
for(var/datum/robot_energy_storage/S in storages)
if(istype(S, storage_type))
return S
@@ -95,42 +95,9 @@
/* /obj/item/robot_module/proc/add_module(obj/item/I, nonstandard, requires_rebuild)
rad_flags |= RAD_NO_CONTAMINATE
- if(istype(I, /obj/item/stack))
- var/obj/item/stack/S = I
-
- if(is_type_in_list(S, list(/obj/item/stack/sheet/metal, /obj/item/stack/rods, /obj/item/stack/tile/plasteel)))
- if(S.custom_materials?.len && S.custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)])
- S.cost = S.custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)] * 0.25
- S.source = get_or_create_estorage(/datum/robot_energy_storage/metal)
-
- else if(istype(S, /obj/item/stack/sheet/glass))
- S.cost = 500
- S.source = get_or_create_estorage(/datum/robot_energy_storage/glass)
-
- else if(istype(S, /obj/item/stack/sheet/rglass/cyborg))
- var/obj/item/stack/sheet/rglass/cyborg/G = S
- G.source = get_or_create_estorage(/datum/robot_energy_storage/metal)
- G.glasource = get_or_create_estorage(/datum/robot_energy_storage/glass)
-
- else if(istype(S, /obj/item/stack/medical))
- S.cost = 250
- S.source = get_or_create_estorage(/datum/robot_energy_storage/medical)
-
- else if(istype(S, /obj/item/stack/cable_coil))
- S.cost = 1
- S.source = get_or_create_estorage(/datum/robot_energy_storage/wire)
-
- else if(istype(S, /obj/item/stack/marker_beacon))
- S.cost = 1
- S.source = get_or_create_estorage(/datum/robot_energy_storage/beacon)
-
- else if(istype(S, /obj/item/stack/packageWrap))
- S.cost = 1
- S.source = get_or_create_estorage(/datum/robot_energy_storage/wrapping_paper)
-
- if(S && S.source)
- S.set_custom_materials(null)
- S.is_cyborg = 1
+ var/obj/item/stack/S = I
+ if(istype(I, /obj/item/stack) && !S.is_cyborg) // Now handled in the type itself
+ stack_trace("Non-cyborg variant of /obj/item/stack added to a cyborg's modules.")
if(I.loc != src)
I.forceMove(src)
@@ -994,9 +961,9 @@
/obj/item/gps/cyborg,
/obj/item/gripper/mining,
/obj/item/cyborg_clamp,
- /obj/item/stack/marker_beacon,
+ /obj/item/stack/marker_beacon/cyborg,
/obj/item/destTagger,
- /obj/item/stack/packageWrap,
+ /obj/item/stack/packageWrap/cyborg,
/obj/item/card/id/miningborg)
emag_modules = list(/obj/item/borg/stun)
ratvar_modules = list(
@@ -1121,7 +1088,7 @@
/obj/item/surgicaldrill,
/obj/item/scalpel,
/obj/item/bonesetter,
- /obj/item/stack/medical/bone_gel,
+ /obj/item/stack/medical/bone_gel/cyborg,
/obj/item/melee/transforming/energy/sword/cyborg/saw,
/obj/item/roller/robo,
/obj/item/card/emag,
@@ -1255,7 +1222,7 @@
/obj/item/surgicaldrill,
/obj/item/scalpel,
/obj/item/bonesetter,
- /obj/item/stack/medical/bone_gel,
+ /obj/item/stack/medical/bone_gel/cyborg,
/obj/item/melee/transforming/energy/sword/cyborg/saw,
/obj/item/roller/robo,
/obj/item/stack/medical/gauze/cyborg,
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index f6402cda87..35b4189401 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -391,57 +391,6 @@
var/msg = "[src] makes eye contact with you."
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, examined_mob, msg), 3)
-/**
- * Point at an atom
- *
- * mob verbs are faster than object verbs. See
- * [this byond forum post](https://secure.byond.com/forum/?post=1326139&page=2#comment8198716)
- * for why this isn't atom/verb/pointed()
- *
- * note: ghosts can point, this is intended
- *
- * visible_message will handle invisibility properly
- *
- * overridden here and in /mob/dead/observer for different point span classes and sanity checks
- */
-/mob/verb/pointed(atom/A as mob|obj|turf in fov_view(), params = "" as text)
- set name = "Point To"
- set category = "Object"
-
- if(!src || !isturf(src.loc) || !(A in view(src.loc)))
- return FALSE
- if(istype(A, /obj/effect/temp_visual/point))
- return FALSE
-
- var/turf/tile = get_turf(A)
- if (!tile)
- return FALSE
-
- var/turf/our_tile = get_turf(src)
- var/obj/visual = new /obj/effect/temp_visual/point(our_tile, invisibility)
-
- /// Set position
- var/final_x = (tile.x - our_tile.x) * world.icon_size + A.pixel_x
- var/final_y = (tile.y - our_tile.y) * world.icon_size + A.pixel_y
- var/list/click_params = params2list(params)
- if(length(click_params) && click_params["screen-loc"])
- var/list/actual_view = getviewsize(client ? client.view : world.view)
- var/list/split_coords = splittext(click_params["screen-loc"], ",")
- final_x = (text2num(splittext(split_coords[1], ":")[1]) - actual_view[1] / 2) * world.icon_size + (text2num(splittext(split_coords[1], ":")[2]) - world.icon_size)
- final_y = (text2num(splittext(split_coords[2], ":")[1]) - actual_view[2] / 2) * world.icon_size + (text2num(splittext(split_coords[2], ":")[2]) - world.icon_size)
- //
-
- /// Set rotation
- var/matrix/rotated_matrix = new()
- rotated_matrix.TurnTo(0, Get_Pixel_Angle(-final_y, -final_x))
- visual.transform = rotated_matrix
- //
-
- animate(visual, pixel_x = final_x, pixel_y = final_y, time = 1.7, easing = EASE_OUT)
- SEND_SIGNAL(src, COMSIG_MOB_POINTED, A)
-
- return TRUE
-
/mob/proc/can_resist()
return FALSE //overridden in living.dm
diff --git a/code/modules/point/point.dm b/code/modules/point/point.dm
new file mode 100644
index 0000000000..4b78abf9ff
--- /dev/null
+++ b/code/modules/point/point.dm
@@ -0,0 +1,128 @@
+#define POINT_TIME (2.5 SECONDS)
+
+/**
+ * Point at an atom
+ *
+ * Intended to enable and standardise the pointing animation for all atoms
+ *
+ * Not intended as a replacement for the mob verb
+ */
+/atom/movable/proc/point_at(atom/pointed_atom, params)
+ if(!isturf(loc))
+ return
+
+ if (pointed_atom in src)
+ create_point_bubble(pointed_atom)
+ return
+
+ var/turf/tile = get_turf(pointed_atom)
+ if (!tile)
+ return
+
+ var/turf/our_tile = get_turf(src)
+ var/obj/visual = new /obj/effect/temp_visual/point(our_tile, invisibility)
+
+ /// Set position
+ var/final_x = (tile.x - our_tile.x) * world.icon_size + pointed_atom.pixel_x
+ var/final_y = (tile.y - our_tile.y) * world.icon_size + pointed_atom.pixel_y
+ var/list/click_params = params2list(params)
+ if(length(click_params) && click_params["screen-loc"] && ismob(src))
+ var/mob/user = src
+ var/list/actual_view = getviewsize(user.client ? user.client.view : world.view)
+ var/list/split_coords = splittext(click_params["screen-loc"], ",")
+ final_x = (text2num(splittext(split_coords[1], ":")[1]) - actual_view[1] / 2) * world.icon_size + (text2num(splittext(split_coords[1], ":")[2]) - world.icon_size)
+ final_y = (text2num(splittext(split_coords[2], ":")[1]) - actual_view[2] / 2) * world.icon_size + (text2num(splittext(split_coords[2], ":")[2]) - world.icon_size)
+ //
+
+ /// Set rotation
+ var/matrix/rotated_matrix = new()
+ rotated_matrix.TurnTo(0, Get_Pixel_Angle(-final_y, -final_x))
+ visual.transform = rotated_matrix
+ //
+
+ animate(visual, pixel_x = final_x, pixel_y = final_y, time = 1.7, easing = EASE_OUT)
+
+/atom/movable/proc/create_point_bubble(atom/pointed_atom)
+ var/obj/effect/thought_bubble_effect = new
+
+ var/mutable_appearance/thought_bubble = mutable_appearance(
+ 'icons/effects/effects.dmi',
+ "thought_bubble",
+ layer = POINT_LAYER,
+ appearance_flags = KEEP_APART,
+ )
+
+ var/mutable_appearance/pointed_atom_appearance = new(pointed_atom.appearance)
+ pointed_atom_appearance.blend_mode = BLEND_INSET_OVERLAY
+ pointed_atom_appearance.plane = thought_bubble.plane
+ pointed_atom_appearance.layer = FLOAT_LAYER
+ pointed_atom_appearance.pixel_x = 0
+ pointed_atom_appearance.pixel_y = 0
+ thought_bubble.overlays += pointed_atom_appearance
+
+ var/hover_outline_index = pointed_atom.get_filter_index(HOVER_OUTLINE_FILTER)
+ if (!isnull(hover_outline_index))
+ pointed_atom_appearance.filters.Cut(hover_outline_index, hover_outline_index + 1)
+
+ thought_bubble.pixel_x = 16
+ thought_bubble.pixel_y = 32
+ thought_bubble.alpha = 200
+ thought_bubble.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+
+ var/mutable_appearance/point_visual = mutable_appearance(
+ 'icons/mob/screen_gen.dmi',
+ "arrow",
+ plane = thought_bubble.plane,
+ )
+
+ thought_bubble.overlays += point_visual
+
+ // vis_contents is used to preserve mouse opacity
+ thought_bubble_effect.appearance = thought_bubble
+ vis_contents += thought_bubble_effect
+
+ QDEL_IN(thought_bubble_effect, POINT_TIME)
+
+/obj/effect/temp_visual/point
+ name = "pointer"
+ icon = 'icons/mob/screen_gen.dmi'
+ icon_state = "arrow"
+ layer = POINT_LAYER
+ duration = POINT_TIME
+
+/obj/effect/temp_visual/point/Initialize(mapload, set_invis = 0)
+ . = ..()
+ var/atom/old_loc = loc
+ abstract_move(get_turf(src))
+ pixel_x = old_loc.pixel_x
+ pixel_y = old_loc.pixel_y
+ invisibility = set_invis
+
+#undef POINT_TIME
+
+/**
+ * Point at an atom
+ *
+ * mob verbs are faster than object verbs. See
+ * [this byond forum post](https://secure.byond.com/forum/?post=1326139&page=2#comment8198716)
+ * for why this isn't atom/verb/pointed()
+ *
+ * note: ghosts can point, this is intended
+ *
+ * visible_message will handle invisibility properly
+ *
+ * overridden here and in /mob/dead/observer for different point span classes and sanity checks
+ */
+/mob/verb/pointed(atom/target as mob|obj|turf in fov_view(), params as text)
+ set name = "Point To"
+ set category = "Object"
+
+ if(client && !(target in view(client.view, src)))
+ return FALSE
+ if(istype(target, /obj/effect/temp_visual/point))
+ return FALSE
+
+ point_at(target, params)
+
+ SEND_SIGNAL(src, COMSIG_MOB_POINTED, target)
+ return TRUE
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 725482117b..c1439e773c 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -517,6 +517,7 @@ By design, d1 is the smallest direction and d2 is the highest
/obj/item/stack/cable_coil/cyborg
is_cyborg = TRUE
custom_materials = null
+ source = /datum/robot_energy_storage/wire
cost = 1
/obj/item/stack/cable_coil/cyborg/attack_self(mob/user)
diff --git a/code/modules/tooltip/tooltip.html b/code/modules/tooltip/tooltip.html
index 8d3c6f272d..75a79f544d 100644
--- a/code/modules/tooltip/tooltip.html
+++ b/code/modules/tooltip/tooltip.html
@@ -80,12 +80,21 @@
.slimecore .wrap {border-color: #18640E;}
.slimecore .content {color: #6EA161; border-color: #11450B; background-color: #354E35;}
- .operative .wrap {border-color: #1E0101;}
- .operative .content {color: #FFFFFF; border-color: #750000; background-color: #350000;}
+ .operative .wrap {border-color: #13121b;}
+ .operative .content {color: #b01232; border-color: #13121b; background-color: #282831;}
.clockwork .wrap {border-color: #170800;}
.clockwork .content {color: #B18B25; border-color: #000000; background-color: #5F380E;}
+ .glass .wrap {border-color: #273844;}
+ .glass .content {color: #5b7588; border-color: #273844; background-color: #1f252b;}
+
+ .trasen-knox .wrap {border-color: #998e81;}
+ .trasen-knox .content {color: #3ce375; border-color: #998e81; background-color: #1e1d21;}
+
+ .detective .wrap {border-color: #2c0F0c;}
+ .detective .content {color: #c7b08b; border-color: #2c0F0c; background-color: #221c1a;}
+
.liteweb .wrap {border-color: #001100;}
.liteweb .content {color: #007700; border-color: #002200; background-color: #003300;}
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index be99d57a3d..8334c83224 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/mob/screen_alien.dmi b/icons/mob/screen_alien.dmi
index fe23a59dfd..96d0e96fe0 100644
Binary files a/icons/mob/screen_alien.dmi and b/icons/mob/screen_alien.dmi differ
diff --git a/icons/mob/screen_clockwork.dmi b/icons/mob/screen_clockwork.dmi
index 268fed4094..1a3da0a625 100644
Binary files a/icons/mob/screen_clockwork.dmi and b/icons/mob/screen_clockwork.dmi differ
diff --git a/icons/mob/screen_detective.dmi b/icons/mob/screen_detective.dmi
new file mode 100644
index 0000000000..dfe74600af
Binary files /dev/null and b/icons/mob/screen_detective.dmi differ
diff --git a/icons/mob/screen_glass.dmi b/icons/mob/screen_glass.dmi
new file mode 100644
index 0000000000..e913494e33
Binary files /dev/null and b/icons/mob/screen_glass.dmi differ
diff --git a/icons/mob/screen_midnight.dmi b/icons/mob/screen_midnight.dmi
index 3d89504272..6c84b074e6 100644
Binary files a/icons/mob/screen_midnight.dmi and b/icons/mob/screen_midnight.dmi differ
diff --git a/icons/mob/screen_operative.dmi b/icons/mob/screen_operative.dmi
index d51022b98a..89a39274d1 100644
Binary files a/icons/mob/screen_operative.dmi and b/icons/mob/screen_operative.dmi differ
diff --git a/icons/mob/screen_plasmafire.dmi b/icons/mob/screen_plasmafire.dmi
index f251b8b167..78ebfb2c2a 100644
Binary files a/icons/mob/screen_plasmafire.dmi and b/icons/mob/screen_plasmafire.dmi differ
diff --git a/icons/mob/screen_retro.dmi b/icons/mob/screen_retro.dmi
index e57cefa83e..44dc7bb5c4 100644
Binary files a/icons/mob/screen_retro.dmi and b/icons/mob/screen_retro.dmi differ
diff --git a/icons/mob/screen_slimecore.dmi b/icons/mob/screen_slimecore.dmi
index 01831250b8..df9d7b0eb6 100644
Binary files a/icons/mob/screen_slimecore.dmi and b/icons/mob/screen_slimecore.dmi differ
diff --git a/icons/mob/screen_trasenknox.dmi b/icons/mob/screen_trasenknox.dmi
new file mode 100644
index 0000000000..70cb09b146
Binary files /dev/null and b/icons/mob/screen_trasenknox.dmi differ
diff --git a/modular_citadel/icons/ui/screen_detective.dmi b/modular_citadel/icons/ui/screen_detective.dmi
new file mode 100644
index 0000000000..ef012d3e84
Binary files /dev/null and b/modular_citadel/icons/ui/screen_detective.dmi differ
diff --git a/modular_citadel/icons/ui/screen_glass.dmi b/modular_citadel/icons/ui/screen_glass.dmi
new file mode 100644
index 0000000000..d03ba9edae
Binary files /dev/null and b/modular_citadel/icons/ui/screen_glass.dmi differ
diff --git a/modular_citadel/icons/ui/screen_operative.dmi b/modular_citadel/icons/ui/screen_operative.dmi
index 5e8abb5431..0f9173091b 100644
Binary files a/modular_citadel/icons/ui/screen_operative.dmi and b/modular_citadel/icons/ui/screen_operative.dmi differ
diff --git a/modular_citadel/icons/ui/screen_trasenknox.dmi b/modular_citadel/icons/ui/screen_trasenknox.dmi
new file mode 100644
index 0000000000..ef418fdf94
Binary files /dev/null and b/modular_citadel/icons/ui/screen_trasenknox.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 7dd3834451..379eb1867b 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -3199,6 +3199,7 @@
#include "code\modules\plumbing\plumbers\reaction_chamber.dm"
#include "code\modules\plumbing\plumbers\splitters.dm"
#include "code\modules\plumbing\plumbers\synthesizer.dm"
+#include "code\modules\point\point.dm"
#include "code\modules\pool\pool_controller.dm"
#include "code\modules\pool\pool_drain.dm"
#include "code\modules\pool\pool_effects.dm"