diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 699fbc544ef..96245eaf787 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -29174,7 +29174,9 @@
/obj/item/mod/construction/core{
pixel_y = 4
},
-/obj/structure/closet/crate,
+/obj/structure/closet/crate/science{
+ name = "MOD core crate"
+ },
/turf/open/floor/iron/dark,
/area/science/robotics/lab)
"icG" = (
diff --git a/code/__DEFINES/exosuit_fab.dm b/code/__DEFINES/exosuit_fab.dm
index f49f68bd0f3..8a8a6ad65c8 100644
--- a/code/__DEFINES/exosuit_fab.dm
+++ b/code/__DEFINES/exosuit_fab.dm
@@ -30,3 +30,18 @@
#define EXOSUIT_MODULE_COMBAT EXOSUIT_MODULE_GYGAX | EXOSUIT_MODULE_HONK | EXOSUIT_MODULE_DURAND | EXOSUIT_MODULE_PHAZON
/// Module is compatible with "Medical" Exosuit modelsm - Odysseus
#define EXOSUIT_MODULE_MEDICAL EXOSUIT_MODULE_ODYSSEUS
+
+/// Module is standard in use
+#define MODULE_GENERAL "General"
+/// Module is preferred for engineering uses
+#define MODULE_ENGINEERING "Engineering"
+/// Module is preferred for medical uses
+#define MODULE_MEDICAL "Medical"
+/// Module is preferred for science uses
+#define MODULE_SCIENCE "Science"
+/// Module is preferred for security uses
+#define MODULE_SECURITY "Security"
+/// Module is preferred for supply uses
+#define MODULE_SUPPLY "Supply"
+/// Module is preferred for service uses
+#define MODULE_SERVICE "Service"
diff --git a/code/datums/components/fullauto.dm b/code/datums/components/fullauto.dm
index b0341d9bd13..3dc1dbd4e2c 100644
--- a/code/datums/components/fullauto.dm
+++ b/code/datums/components/fullauto.dm
@@ -117,7 +117,7 @@
if(get_dist(source.mob, _target) < 2) //Adjacent clicking.
return
- if(isnull(location)) //Clicking on a screen object.
+ if(isnull(location) || istype(_target, /atom/movable/screen)) //Clicking on a screen object.
if(_target.plane != CLICKCATCHER_PLANE) //The clickcatcher is a special case. We want the click to trigger then, under it.
return //If we click and drag on our worn backpack, for example, we want it to open instead.
_target = params_to_turf(modifiers["screen-loc"], get_turf(source.eye), source)
diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm
index 5e06898bac8..66cb976738e 100644
--- a/code/game/objects/items/devices/aicard.dm
+++ b/code/game/objects/items/devices/aicard.dm
@@ -33,13 +33,14 @@
target.transfer_ai(AI_TRANS_FROM_CARD, user, AI, src)
if(!AI)
log_combat(user, our_ai, "uploaded", src, "to [target].")
+ update_appearance()
return TRUE
else //No AI on the card, therefore the user wants to download one.
target.transfer_ai(AI_TRANS_TO_CARD, user, null, src)
if(AI)
log_combat(user, AI, "carded", src)
+ update_appearance()
return TRUE
- update_appearance() //Whatever happened, update the card's state (icon, name) to match.
return ..()
/obj/item/aicard/update_icon_state()
diff --git a/code/modules/antagonists/nukeop/clownop.dm b/code/modules/antagonists/nukeop/clownop.dm
index 8ccd6347596..4930ff2ef04 100644
--- a/code/modules/antagonists/nukeop/clownop.dm
+++ b/code/modules/antagonists/nukeop/clownop.dm
@@ -70,6 +70,7 @@
back = /obj/item/mod/control/pre_equipped/syndicate_empty
mask = /obj/item/clothing/mask/gas/clown_hat
+ uniform = /obj/item/clothing/under/syndicate
/datum/outfit/clown_operative/post_equip(mob/living/carbon/human/H, visualsOnly)
var/obj/item/mod/module/armor_booster/booster = locate() in H.back
@@ -81,6 +82,7 @@
back = /obj/item/mod/control/pre_equipped/syndicate_empty/elite
mask = /obj/item/clothing/mask/gas/clown_hat
+ uniform = /obj/item/clothing/under/syndicate
/datum/outfit/clown_operative_elite/post_equip(mob/living/carbon/human/H, visualsOnly)
var/obj/item/mod/module/armor_booster/elite/booster = locate() in H.back
diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm
index 604e4d0f7f4..b72a433df85 100644
--- a/code/modules/antagonists/nukeop/nukeop.dm
+++ b/code/modules/antagonists/nukeop/nukeop.dm
@@ -173,6 +173,7 @@
name = "Nuclear Operative (Preview only)"
back = /obj/item/mod/control/pre_equipped/syndicate_empty
+ uniform = /obj/item/clothing/under/syndicate
/datum/outfit/nuclear_operative/post_equip(mob/living/carbon/human/H, visualsOnly)
var/obj/item/mod/module/armor_booster/booster = locate() in H.back
@@ -183,6 +184,7 @@
name = "Nuclear Operative (Elite, Preview only)"
back = /obj/item/mod/control/pre_equipped/syndicate_empty/elite
+ uniform = /obj/item/clothing/under/syndicate
l_hand = /obj/item/modular_computer/tablet/nukeops
r_hand = /obj/item/shield/energy
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 8ebc09848de..732c7a1a08c 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -173,11 +173,11 @@
/mob/living/carbon/human/proc/get_thermal_protection()
var/thermal_protection = 0 //Simple check to estimate how protected we are against multiple temperatures
if(wear_suit)
- if(wear_suit.max_heat_protection_temperature >= FIRE_SUIT_MAX_TEMP_PROTECT)
- thermal_protection += (wear_suit.max_heat_protection_temperature*0.7)
+ if((wear_suit.heat_protection & CHEST) && (wear_suit.max_heat_protection_temperature >= FIRE_SUIT_MAX_TEMP_PROTECT))
+ thermal_protection += (wear_suit.max_heat_protection_temperature * 0.7)
if(head)
- if(head.max_heat_protection_temperature >= FIRE_HELM_MAX_TEMP_PROTECT)
- thermal_protection += (head.max_heat_protection_temperature*THERMAL_PROTECTION_HEAD)
+ if((head.heat_protection & HEAD) && (head.max_heat_protection_temperature >= FIRE_HELM_MAX_TEMP_PROTECT))
+ thermal_protection += (head.max_heat_protection_temperature * THERMAL_PROTECTION_HEAD)
thermal_protection = round(thermal_protection)
return thermal_protection
diff --git a/code/modules/mob/living/init_signals.dm b/code/modules/mob/living/init_signals.dm
index 8e1fcbe5219..78be2badfb5 100644
--- a/code/modules/mob/living/init_signals.dm
+++ b/code/modules/mob/living/init_signals.dm
@@ -109,7 +109,10 @@
/mob/living/proc/on_forced_standing_trait_loss(datum/source)
SIGNAL_HANDLER
- if(resting || HAS_TRAIT(src, TRAIT_FLOORED))
+ if(HAS_TRAIT(src, TRAIT_FLOORED))
+ on_fall()
+ set_lying_down()
+ else if(resting)
set_lying_down()
/// Called when [TRAIT_HANDS_BLOCKED] is added to the mob.
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 1132f45ea84..0446c624b25 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -575,7 +575,6 @@
/mob/living/proc/set_lying_down(new_lying_angle)
set_body_position(LYING_DOWN)
-
/// Proc to append behavior related to lying down.
/mob/living/proc/on_lying_down(new_lying_angle)
if(layer == initial(layer)) //to avoid things like hiding larvas.
diff --git a/code/modules/mod/mod_actions.dm b/code/modules/mod/mod_actions.dm
index 2c27879e798..70d753561eb 100644
--- a/code/modules/mod/mod_actions.dm
+++ b/code/modules/mod/mod_actions.dm
@@ -2,29 +2,30 @@
background_icon_state = "bg_tech_blue"
icon_icon = 'icons/mob/actions/actions_mod.dmi'
check_flags = AB_CHECK_CONSCIOUS
+ /// Whether this action is intended for the AI. Stuff breaks a lot if this is done differently.
+ var/ai_action = FALSE
+ /// The MODsuit linked to this action
var/obj/item/mod/control/mod
/datum/action/item_action/mod/New(Target)
..()
mod = Target
+ if(ai_action)
+ background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND
-/datum/action/item_action/mod/Grant(mob/M)
- if(owner)
- Share(M)
+/datum/action/item_action/mod/Grant(mob/user)
+ if(ai_action && user != mod.ai)
return
- ..()
+ else if(!ai_action && user == mod.ai)
+ return
+ return ..()
-/datum/action/item_action/mod/Remove(mob/M)
- var/mob_to_grant
- for(var/datum/weakref/reference as anything in sharers)
- var/mob/freeloader = reference.resolve()
- if(!freeloader)
- continue
- mob_to_grant = freeloader
- break
- ..()
- if(mob_to_grant)
- Grant(mob_to_grant)
+/datum/action/item_action/mod/Remove(mob/user)
+ if(ai_action && user != mod.ai)
+ return
+ else if(!ai_action && user == mod.ai)
+ return
+ return ..()
/datum/action/item_action/mod/deploy
name = "Deploy MODsuit"
@@ -37,6 +38,9 @@
mod.choose_deploy(usr)
return TRUE
+/datum/action/item_action/mod/deploy/ai
+ ai_action = TRUE
+
/datum/action/item_action/mod/activate
name = "Activate MODsuit"
desc = "Activate/Deactivate the MODsuit."
@@ -48,6 +52,9 @@
mod.toggle_activate(usr)
return TRUE
+/datum/action/item_action/mod/activate/ai
+ ai_action = TRUE
+
/datum/action/item_action/mod/module
name = "Toggle Module"
desc = "Toggle a MODsuit module."
@@ -59,6 +66,9 @@
mod.quick_module(usr)
return TRUE
+/datum/action/item_action/mod/module/ai
+ ai_action = TRUE
+
/datum/action/item_action/mod/panel
name = "MODsuit Panel"
desc = "Open the MODsuit's panel."
@@ -69,3 +79,6 @@
return FALSE
mod.ui_interact(usr)
return TRUE
+
+/datum/action/item_action/mod/panel/ai
+ ai_action = TRUE
diff --git a/code/modules/mod/mod_ai.dm b/code/modules/mod/mod_ai.dm
index f470fb8046c..26bf7607b34 100644
--- a/code/modules/mod/mod_ai.dm
+++ b/code/modules/mod/mod_ai.dm
@@ -22,10 +22,7 @@
intAI.forceMove(card)
card.AI = intAI
for(var/datum/action/action as anything in actions)
- if(action.owner == intAI)
- action.Remove(intAI)
- else
- action.Unshare(intAI)
+ action.Remove(intAI)
intAI.controlled_equipment = null
intAI.remote_control = null
balloon_alert(intAI, "transferred to a card")
@@ -67,6 +64,7 @@
#define WEARER_DELAY 1
#define LONE_DELAY 5
#define CELL_PER_STEP DEFAULT_CELL_DRAIN * 2.5
+#define AI_FALL_TIME 1 SECONDS
/obj/item/mod/control/relaymove(mob/user, direction)
if((!active && wearer) || !cell || cell.charge < CELL_PER_STEP || user != ai || !COOLDOWN_FINISHED(src, cooldown_mod_move) || (wearer?.pulledby?.grab_state > GRAB_PASSIVE))
@@ -75,6 +73,9 @@
COOLDOWN_START(src, cooldown_mod_move, movedelay * timemodifier + slowdown)
playsound(src, 'sound/mecha/mechmove01.ogg', 25, TRUE)
cell.charge = max(0, cell.charge - CELL_PER_STEP)
+ if(wearer)
+ ADD_TRAIT(wearer, TRAIT_FORCED_STANDING, MOD_TRAIT)
+ addtimer(CALLBACK(src, .proc/ai_fall), AI_FALL_TIME, TIMER_UNIQUE | TIMER_OVERRIDE)
if(ismovable(wearer?.loc))
return wearer.loc.relaymove(wearer, direction)
if(wearer && !wearer.Process_Spacemove(direction))
@@ -86,3 +87,54 @@
#undef WEARER_DELAY
#undef LONE_DELAY
#undef CELL_PER_STEP
+
+/obj/item/mod/control/proc/ai_fall()
+ if(!wearer)
+ return
+ REMOVE_TRAIT(wearer, TRAIT_FORCED_STANDING, MOD_TRAIT)
+
+/obj/item/mod/ai_minicard
+ name = "AI mini-card"
+ desc = "A small card designed to eject dead AIs. You could use an intellicard to recover it."
+ icon = 'icons/obj/aicards.dmi'
+ icon_state = "minicard"
+ var/datum/weakref/stored_ai
+
+/obj/item/mod/ai_minicard/Initialize(mapload, mob/living/silicon/ai/ai)
+ . = ..()
+ if(!ai)
+ return
+ ai.apply_damage(150, BURN)
+ INVOKE_ASYNC(ai, /mob/living/silicon/ai.proc/death)
+ ai.forceMove(src)
+ stored_ai = WEAKREF(ai)
+ icon_state = "minicard-filled"
+
+/obj/item/mod/ai_minicard/Destroy()
+ QDEL_NULL(stored_ai)
+ return ..()
+
+/obj/item/mod/ai_minicard/examine(mob/user)
+ . = ..()
+ . += span_notice("You see [stored_ai.resolve() || "no AI"] stored inside.")
+
+/obj/item/mod/ai_minicard/transfer_ai(interaction, mob/user, mob/living/silicon/ai/intAI, obj/item/aicard/card)
+ . = ..()
+ if(!.)
+ return
+ if(interaction != AI_TRANS_TO_CARD)
+ return
+ var/mob/living/silicon/ai/ai = stored_ai.resolve()
+ if(!ai)
+ balloon_alert(user, "no AI!")
+ return
+ balloon_alert(user, "transferring to card...")
+ if(!do_after(user, 5 SECONDS, target = src) || !ai)
+ balloon_alert(user, "interrupted!")
+ return
+ icon_state = "minicard"
+ ai.forceMove(card)
+ card.AI = ai
+ ai.notify_ghost_cloning("You have been recovered from the wreckage!", source = card)
+ balloon_alert(user, "AI transferred to card")
+ stored_ai = null
diff --git a/code/modules/mod/mod_clothes.dm b/code/modules/mod/mod_clothes.dm
index 37045015d66..917a6bf5707 100644
--- a/code/modules/mod/mod_clothes.dm
+++ b/code/modules/mod/mod_clothes.dm
@@ -29,6 +29,9 @@
QDEL_NULL(mod)
return ..()
+/obj/item/clothing/head/helmet/space/mod/atom_destruction(damage_flag)
+ return mod.atom_destruction(damage_flag)
+
/obj/item/clothing/suit/armor/mod
name = "MOD chestplate"
desc = "A chestplate for a MODsuit."
@@ -56,6 +59,9 @@
QDEL_NULL(mod)
return ..()
+/obj/item/clothing/suit/armor/mod/atom_destruction(damage_flag)
+ return mod.atom_destruction(damage_flag)
+
/obj/item/clothing/gloves/mod
name = "MOD gauntlets"
desc = "A pair of gauntlets for a MODsuit."
@@ -80,8 +86,12 @@
QDEL_NULL(mod)
return ..()
-/// Replaces these gloves on the wearer with the overslot ones
+/obj/item/clothing/gloves/mod/atom_destruction(damage_flag)
+ overslot.forceMove(drop_location())
+ overslot = null
+ return mod.atom_destruction(damage_flag)
+/// Replaces these gloves on the wearer with the overslot ones
/obj/item/clothing/gloves/mod/proc/show_overslot()
if(!overslot)
return
@@ -114,6 +124,11 @@
QDEL_NULL(mod)
return ..()
+/obj/item/clothing/shoes/mod/atom_destruction(damage_flag)
+ overslot.forceMove(drop_location())
+ overslot = null
+ return mod.atom_destruction(damage_flag)
+
/// Replaces these shoes on the wearer with the overslot ones
/obj/item/clothing/shoes/mod/proc/show_overslot()
if(!overslot)
diff --git a/code/modules/mod/mod_control.dm b/code/modules/mod/mod_control.dm
index 8ca7dc8573f..ef3da163ae6 100644
--- a/code/modules/mod/mod_control.dm
+++ b/code/modules/mod/mod_control.dm
@@ -16,7 +16,16 @@
strip_delay = 10 SECONDS
slowdown = 2
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 25, ACID = 25, WOUND = 10)
- actions_types = list(/datum/action/item_action/mod/deploy, /datum/action/item_action/mod/activate, /datum/action/item_action/mod/module, /datum/action/item_action/mod/panel)
+ actions_types = list(
+ /datum/action/item_action/mod/deploy,
+ /datum/action/item_action/mod/activate,
+ /datum/action/item_action/mod/panel,
+ /datum/action/item_action/mod/module,
+ /datum/action/item_action/mod/deploy/ai,
+ /datum/action/item_action/mod/activate/ai,
+ /datum/action/item_action/mod/panel/ai,
+ /datum/action/item_action/mod/module/ai,
+ )
resistance_flags = NONE
max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT
min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
@@ -165,6 +174,41 @@
QDEL_NULL(cell)
return ..()
+/obj/item/mod/control/atom_destruction(damage_flag)
+ for(var/obj/item/mod/module/module as anything in modules)
+ for(var/obj/item/item in module)
+ item.forceMove(drop_location())
+ if(ai)
+ ai.controlled_equipment = null
+ ai.remote_control = null
+ for(var/datum/action/action as anything in actions)
+ if(action.owner == ai)
+ action.Remove(ai)
+ new /obj/item/mod/ai_minicard(drop_location(), ai)
+ return ..()
+
+/obj/item/mod/control/examine(mob/user)
+ . = ..()
+ if(active)
+ . += span_notice("Cell power: [cell ? "[round(cell.percent(), 1)]%" : "No cell"].")
+ . += span_notice("Selected module: [selected_module || "None"].")
+ if(!open && !active)
+ . += span_notice("You could put it on your back to turn it on.")
+ . += span_notice("You could open the cover with a screwdriver.")
+ else if(open)
+ . += span_notice("You could close the cover with a screwdriver.")
+ . += span_notice("You could use modules on it to install them.")
+ . += span_notice("You could remove modules with a crowbar.")
+ . += span_notice("You could update the access with an ID.")
+ if(cell)
+ . += span_notice("You could remove the cell with an empty hand.")
+ else
+ . += span_notice("You could use a cell on it to install one.")
+ if(ai)
+ . += span_notice("You could remove [ai] with an intellicard")
+ else
+ . += span_notice("You could install an AI with an intellicard.")
+
/obj/item/mod/control/process(delta_time)
if(seconds_electrified > MACHINE_NOT_ELECTRIFIED)
seconds_electrified--
@@ -248,13 +292,13 @@
balloon_alert(user, "deactivate suit first!")
playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE)
return FALSE
- balloon_alert(user, "[open ? "closing" : "opening"] panel...")
+ balloon_alert(user, "[open ? "closing" : "opening"] cover...")
screwdriver.play_tool_sound(src, 100)
if(screwdriver.use_tool(src, user, 1 SECONDS))
if(active || activating)
balloon_alert(user, "deactivate suit first!")
screwdriver.play_tool_sound(src, 100)
- balloon_alert(user, "panel [open ? "closed" : "opened"]")
+ balloon_alert(user, "cover [open ? "closed" : "opened"]")
open = !open
else
balloon_alert(user, "interrupted!")
@@ -263,7 +307,7 @@
/obj/item/mod/control/crowbar_act(mob/living/user, obj/item/crowbar)
. = ..()
if(!open)
- balloon_alert(user, "open the panel first!")
+ balloon_alert(user, "open the cover first!")
playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE)
return FALSE
if(!allowed(user))
@@ -290,14 +334,14 @@
/obj/item/mod/control/attackby(obj/item/attacking_item, mob/living/user, params)
if(istype(attacking_item, /obj/item/mod/module))
if(!open)
- balloon_alert(user, "open the panel first!")
+ balloon_alert(user, "open the cover first!")
playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE)
return FALSE
install(attacking_item, user)
return TRUE
else if(istype(attacking_item, /obj/item/stock_parts/cell))
if(!open)
- balloon_alert(user, "open the panel first!")
+ balloon_alert(user, "open the cover first!")
playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE)
return FALSE
if(cell)
@@ -342,13 +386,15 @@
/obj/item/mod/control/emp_act(severity)
. = ..()
- to_chat(wearer, span_notice("[severity > 1 ? "Light" : "Strong"] electromagnetic pulse detected!"))
- if(!active || !wearer || . & EMP_PROTECT_CONTENTS)
+ if(!active || !wearer)
return
- selected_module = null
+ to_chat(wearer, span_notice("[severity > 1 ? "Light" : "Strong"] electromagnetic pulse detected!"))
+ if(. & EMP_PROTECT_CONTENTS)
+ return
+ selected_module.on_deactivation()
wearer.apply_damage(10 / severity, BURN, spread_damage=TRUE)
to_chat(wearer, span_danger("You feel [src] heat up from the EMP, burning you slightly."))
- if (wearer.stat < UNCONSCIOUS && prob(10))
+ if(wearer.stat < UNCONSCIOUS && prob(10))
wearer.emote("scream")
/obj/item/mod/control/on_outfit_equip(mob/living/carbon/human/outfit_wearer, visuals_only, item_slot)
@@ -377,6 +423,7 @@
wearer = user
RegisterSignal(wearer, COMSIG_ATOM_EXITED, .proc/on_exit)
RegisterSignal(wearer, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, .proc/on_borg_charge)
+ RegisterSignal(src, COMSIG_ITEM_PRE_UNEQUIP, .proc/on_unequip)
update_cell_alert()
for(var/obj/item/mod/module/module as anything in modules)
module.on_equip()
@@ -385,9 +432,17 @@
for(var/obj/item/mod/module/module as anything in modules)
module.on_unequip()
UnregisterSignal(wearer, list(COMSIG_ATOM_EXITED, COMSIG_PROCESS_BORGCHARGER_OCCUPANT))
+ UnregisterSignal(src, COMSIG_ITEM_PRE_UNEQUIP)
wearer.clear_alert("mod_charge")
wearer = null
+/obj/item/mod/control/proc/on_unequip()
+ SIGNAL_HANDLER
+
+ for(var/obj/item/part in mod_parts)
+ if(part.loc != src)
+ return COMPONENT_ITEM_BLOCK_UNEQUIP
+
/obj/item/mod/control/proc/update_flags()
var/list/used_skin = theme.skins[skin]
for(var/obj/item/clothing/part as anything in mod_parts)
@@ -420,17 +475,21 @@
continue
display_names[module.name] = REF(module)
var/image/module_image = image(icon = module.icon, icon_state = module.icon_state)
+ if(module == selected_module)
+ module_image.underlays += image(icon = 'icons/hud/radial.dmi', icon_state = "module_selected")
+ else if(module.active)
+ module_image.underlays += image(icon = 'icons/hud/radial.dmi', icon_state = "module_active")
items += list(module.name = module_image)
if(!length(items))
return
- var/pick = show_radial_menu(user, src, items, custom_check = FALSE, require_near = TRUE)
+ var/pick = show_radial_menu(user, src, items, custom_check = FALSE, require_near = TRUE, tooltips = TRUE)
if(!pick)
return
var/module_reference = display_names[pick]
- var/obj/item/mod/module/selected_module = locate(module_reference) in modules
- if(!istype(selected_module) || user.incapacitated())
+ var/obj/item/mod/module/picked_module = locate(module_reference) in modules
+ if(!istype(picked_module) || user.incapacitated())
return
- selected_module.on_select()
+ picked_module.on_select()
/obj/item/mod/control/proc/paint(mob/user, obj/item/paint)
if(length(theme.skins) <= 1)
@@ -557,3 +616,4 @@
if(!cell)
return
cell.give(amount)
+ update_cell_alert()
diff --git a/code/modules/mod/mod_theme.dm b/code/modules/mod/mod_theme.dm
index 174cc1bab32..2b0af4223c0 100644
--- a/code/modules/mod/mod_theme.dm
+++ b/code/modules/mod/mod_theme.dm
@@ -529,7 +529,6 @@
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
- SEALED_INVISIBILITY = HIDEJUMPSUIT,
),
GAUNTLETS_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm
index af482e50f43..2ca2f791c7d 100644
--- a/code/modules/mod/mod_types.dm
+++ b/code/modules/mod/mod_types.dm
@@ -55,6 +55,10 @@
cell = /obj/item/stock_parts/cell/hyper
initial_modules = list(/obj/item/mod/module/storage/large_capacity, /obj/item/mod/module/welding, /obj/item/mod/module/holster, /obj/item/mod/module/pathfinder)
+/obj/item/mod/control/pre_equipped/cosmohonk
+ theme = /datum/mod_theme/cosmohonk
+ initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/bikehorn)
+
/obj/item/mod/control/pre_equipped/traitor
theme = /datum/mod_theme/syndicate
cell = /obj/item/stock_parts/cell/super
diff --git a/code/modules/mod/modules/modules.dm b/code/modules/mod/modules/modules.dm
index db59418a810..0ff9b5f48c0 100644
--- a/code/modules/mod/modules/modules.dm
+++ b/code/modules/mod/modules/modules.dm
@@ -513,6 +513,8 @@
range = 10
hitsound = 'sound/weapons/batonextend.ogg'
hitsound_wall = 'sound/weapons/batonextend.ogg'
+ suppressed = SUPPRESSED_VERY
+ hit_threshhold = LATTICE_LAYER
var/line
/obj/projectile/tether/fire(setAngle)
@@ -1061,6 +1063,11 @@
playsound(src, 'sound/mecha/hydraulic.ogg', 25, TRUE)
drain_power(use_power_cost)
+/obj/item/mod/module/clamp/on_uninstall()
+ for(var/atom/movable/crate as anything in stored_crates)
+ crate.forceMove(drop_location())
+ stored_crates -= crate
+
/obj/item/mod/module/bikehorn
name = "MOD bike horn module"
desc = "A shoulder-mounted piece of heavy sonic artillery, this module uses the finest femto-manipulator technology to \
@@ -1163,7 +1170,7 @@
if(!.)
return
for(var/obj/item/ore as anything in ores)
- ore.forceMove(mod.drop_location())
+ ore.forceMove(drop_location())
ores -= ore
drain_power(use_power_cost)
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 1d4264c9b13..a28b3c47520 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -68,6 +68,9 @@
/// number of times we've pierced something. Incremented BEFORE bullet_act and on_hit proc!
var/pierces = 0
+ /// If objects are below this layer, we pass through them
+ var/hit_threshhold = PROJECTILE_HIT_THRESHHOLD_LAYER
+
var/speed = 0.8 //Amount of deciseconds it takes for projectile to travel
var/Angle = 0
var/original_angle = 0 //Angle at firing
@@ -495,7 +498,7 @@
if(!isliving(target))
if(isturf(target)) // non dense turfs
return FALSE
- if(target.layer < PROJECTILE_HIT_THRESHHOLD_LAYER)
+ if(target.layer < hit_threshhold)
return FALSE
else if(!direct_target) // non dense objects do not get hit unless specifically clicked
return FALSE
diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm
index babd4407d2f..99e9d8fc280 100644
--- a/code/modules/research/designs/mechfabricator_designs.dm
+++ b/code/modules/research/designs/mechfabricator_designs.dm
@@ -1093,6 +1093,7 @@
materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000)
build_path = /obj/item/mod/module
category = list("MOD Modules")
+ var/department_type = MODULE_GENERAL
/datum/design/module/New()
. = ..()
@@ -1110,24 +1111,28 @@
id = "mod_visor_medhud"
materials = list(/datum/material/silver = 500, /datum/material/glass = 1000)
build_path = /obj/item/mod/module/visor/medhud
+ department_type = MODULE_MEDICAL
/datum/design/module/mod_visor_diaghud
name = "MOD Module: Diagnostic Visor"
id = "mod_visor_diaghud"
materials = list(/datum/material/gold = 500, /datum/material/glass = 1000)
build_path = /obj/item/mod/module/visor/diaghud
+ department_type = MODULE_SCIENCE
/datum/design/module/mod_visor_sechud
name = "MOD Module: Security Visor"
id = "mod_visor_sechud"
materials = list(/datum/material/titanium = 500, /datum/material/glass = 1000)
build_path = /obj/item/mod/module/visor/sechud
+ department_type = MODULE_SECURITY
/datum/design/module/mod_visor_meson
name = "MOD Module: Meson Visor"
id = "mod_visor_meson"
materials = list(/datum/material/uranium = 500, /datum/material/glass = 1000)
build_path = /obj/item/mod/module/visor/meson
+ department_type = MODULE_SUPPLY
/datum/design/module/mod_visor_welding
name = "MOD Module: Welding Protection"
@@ -1140,18 +1145,21 @@
id = "mod_t_ray"
materials = list(/datum/material/iron = 500, /datum/material/glass = 1000)
build_path = /obj/item/mod/module/t_ray
+ department_type = MODULE_ENGINEERING
/datum/design/module/mod_health_analyzer
name = "MOD Module: Health Analyzer"
id = "mod_health_analyzer"
materials = list(/datum/material/iron = 500, /datum/material/glass = 1000)
build_path = /obj/item/mod/module/health_analyzer
+ department_type = MODULE_MEDICAL
/datum/design/module/mod_stealth
name = "MOD Module: Cloak"
id = "mod_stealth"
materials = list(/datum/material/iron = 1000, /datum/material/bluespace = 500)
build_path = /obj/item/mod/module/stealth
+ department_type = MODULE_SECURITY
/datum/design/module/mod_jetpack
name = "MOD Module: Ion Jetpack"
@@ -1164,18 +1172,21 @@
id = "mod_magboot"
materials = list(/datum/material/iron = 1000, /datum/material/gold = 500)
build_path = /obj/item/mod/module/magboot
+ department_type = MODULE_ENGINEERING
/datum/design/module/mod_holster
name = "MOD Module: Holster"
id = "mod_holster"
materials = list(/datum/material/iron = 1500, /datum/material/glass = 500)
build_path = /obj/item/mod/module/holster
+ department_type = MODULE_SECURITY
/datum/design/module/mod_tether
name = "MOD Module: Emergency Tether"
id = "mod_tether"
materials = list(/datum/material/iron = 1000, /datum/material/silver = 500)
build_path = /obj/item/mod/module/tether
+ department_type = MODULE_ENGINEERING
/datum/design/module/mod_mouthhole
name = "MOD Module: Eating Apparatus"
@@ -1188,6 +1199,7 @@
id = "mod_rad_protection"
materials = list(/datum/material/iron = 1000, /datum/material/uranium = 1000)
build_path = /obj/item/mod/module/rad_protection
+ department_type = MODULE_ENGINEERING
/datum/design/module/mod_emp_shield
name = "MOD Module: EMP Shield"
@@ -1206,24 +1218,28 @@
id = "mod_reagent_scanner"
materials = list(/datum/material/glass = 1000)
build_path = /obj/item/mod/module/reagent_scanner
+ department_type = MODULE_MEDICAL
/datum/design/module/mod_gps
name = "MOD Module: Internal GPS"
id = "mod_gps"
materials = list(/datum/material/iron = 500, /datum/material/glass = 500)
build_path = /obj/item/mod/module/gps
+ department_type = MODULE_SUPPLY
/datum/design/module/mod_constructor
name = "MOD Module: Constructor"
id = "mod_constructor"
materials = list(/datum/material/iron = 1000, /datum/material/titanium = 500)
build_path = /obj/item/mod/module/constructor
+ department_type = MODULE_ENGINEERING
/datum/design/module/mod_quick_carry
name = "MOD Module: Quick Carry"
id = "mod_quick_carry"
materials = list(/datum/material/iron = 1000, /datum/material/titanium = 500)
build_path = /obj/item/mod/module/quick_carry
+ department_type = MODULE_MEDICAL
/datum/design/module/mod_longfall
name = "MOD Module: Longfall"
@@ -1242,42 +1258,49 @@
id = "mod_injector"
materials = list(/datum/material/iron = 1000, /datum/material/diamond = 500)
build_path = /obj/item/mod/module/injector
+ department_type = MODULE_MEDICAL
/datum/design/module/mod_microwave_beam
name = "MOD Module: Microwave Beam"
id = "mod_microwave_beam"
materials = list(/datum/material/iron = 1000, /datum/material/uranium = 500)
build_path = /obj/item/mod/module/microwave_beam
+ department_type = MODULE_SERVICE
/datum/design/module/mod_bikehorn
name = "MOD Module: Bike Horn"
id = "mod_bikehorn"
materials = list(/datum/material/plastic = 500, /datum/material/iron = 500)
build_path = /obj/item/mod/module/bikehorn
+ department_type = MODULE_SERVICE
/datum/design/module/mod_clamp
name = "MOD Module: Crate Clamp"
id = "mod_clamp"
materials = list(/datum/material/iron = 2000)
build_path = /obj/item/mod/module/clamp
+ department_type = MODULE_SUPPLY
/datum/design/module/mod_drill
name = "MOD Module: Drill"
id = "mod_drill"
materials = list(/datum/material/silver = 1000, /datum/material/iron = 2000)
build_path = /obj/item/mod/module/drill
+ department_type = MODULE_SUPPLY
/datum/design/module/mod_orebag
name = "MOD Module: Ore Bag"
id = "mod_orebag"
materials = list(/datum/material/iron = 1500)
build_path = /obj/item/mod/module/orebag
+ department_type = MODULE_SUPPLY
/datum/design/module/mod_organ_thrower
name = "MOD Module: Organ Thrower"
id = "mod_organ_thrower"
materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000)
build_path = /obj/item/mod/module/organ_thrower
+ department_type = MODULE_MEDICAL
/datum/design/module/mod_pathfinder
name = "MOD Module: Pathfinder"
@@ -1296,6 +1319,7 @@
id = "mod_circuit"
materials = list(/datum/material/glass = 2000)
build_path = /obj/item/mod/module/circuit
+ department_type = MODULE_SCIENCE
/datum/design/module/mod_plasma_stabilizer
name = "MOD Module: Plasma Stabilizer"
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index 9ce890c9399..4248ca44725 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -1451,8 +1451,6 @@
prereq_ids = list("robotics")
design_ids = list(
"mod_visor_diaghud",
- "mod_stealth",
- "mod_holster",
"mod_gps",
"mod_reagent_scanner",
"mod_clamp",
diff --git a/code/modules/ruins/spaceruin_code/oldstation.dm b/code/modules/ruins/spaceruin_code/oldstation.dm
index a3a6371ad75..3efca0798de 100644
--- a/code/modules/ruins/spaceruin_code/oldstation.dm
+++ b/code/modules/ruins/spaceruin_code/oldstation.dm
@@ -118,7 +118,7 @@
var/list/overlays = ..()
if(machine_stat & (NOPOWER|BROKEN))
return overlays
- overlays += busy ? "red" : "green"
+ overlays += (busy || !mod_unit) ? "red" : "green"
return overlays
/obj/machinery/mod_installer/proc/start_process()
@@ -144,9 +144,13 @@
human_occupant.update_action_buttons(TRUE)
playsound(src, 'sound/machines/ping.ogg', 30, FALSE)
if(!human_occupant.dropItemToGround(human_occupant.wear_suit) || !human_occupant.dropItemToGround(human_occupant.head))
- open_machine()
+ finish_completion()
return
mod_unit.quick_activation()
+ finish_completion()
+
+/obj/machinery/mod_installer/proc/finish_completion()
+ mod_unit = null
open_machine()
/obj/machinery/mod_installer/open_machine()
diff --git a/code/modules/vehicles/mecha/mech_fabricator.dm b/code/modules/vehicles/mecha/mech_fabricator.dm
index 6d74c2dde8c..f3eca75411f 100644
--- a/code/modules/vehicles/mecha/mech_fabricator.dm
+++ b/code/modules/vehicles/mecha/mech_fabricator.dm
@@ -42,10 +42,10 @@
/// Reference to a remote material inventory, such as an ore silo.
var/datum/component/remote_materials/rmat
-
+
/// A list of part sets used for TGUI static data. Updated on Init() and syncing with the R&D console.
var/list/final_sets = list()
-
+
/// A list of individual parts used for TGUI static data. Updated on Init() and syncing with the R&D console.
var/list/buildable_parts = list()
@@ -176,6 +176,9 @@
else if(ispath(built_item, /obj/item/borg_restart_board))
sub_category += "All Cyborgs" //Otherwise the restart board shows in the "parts" category, which seems dumb
+ else if(istype(D, /datum/design/module))
+ var/datum/design/module/module_design = D
+ sub_category = list(module_design.department_type)
var/list/part = list(
"name" = D.name,
diff --git a/icons/hud/radial.dmi b/icons/hud/radial.dmi
index 1ddd75a137c..35311aa29e6 100644
Binary files a/icons/hud/radial.dmi and b/icons/hud/radial.dmi differ
diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi
index a96d0deedb5..9f1e81d550e 100644
Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ
diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi
index 4d5b242cd21..d1343f77000 100644
Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ
diff --git a/icons/mob/mod.dmi b/icons/mob/mod.dmi
index c8083addffa..3781faaf80b 100644
Binary files a/icons/mob/mod.dmi and b/icons/mob/mod.dmi differ
diff --git a/icons/obj/aicards.dmi b/icons/obj/aicards.dmi
index 87c296980bb..892a0adb672 100644
Binary files a/icons/obj/aicards.dmi and b/icons/obj/aicards.dmi differ
diff --git a/icons/obj/mod.dmi b/icons/obj/mod.dmi
index 003fb23cf60..652543ec4b7 100644
Binary files a/icons/obj/mod.dmi and b/icons/obj/mod.dmi differ