beeg commit

This commit is contained in:
Jerry Wester
2022-12-10 00:55:20 -07:00
parent b538ad721b
commit f7ac3c7624
73 changed files with 3502 additions and 533 deletions
+12
View File
@@ -214,5 +214,17 @@ GLOBAL_LIST_INIT(bitflags, list(
///Turns the dir by 180 degrees
#define DIRFLIP(d) turn(d, 180)
// timed_action_flags parameter for `/proc/do_after_mob`, `/proc/do_mob` and `/proc/do_after`
/// Can do the action even if mob moves location
#define IGNORE_USER_LOC_CHANGE (1<<0)
/// Can do the action even if the target moves location
#define IGNORE_TARGET_LOC_CHANGE (1<<1)
/// Can do the action even if the item is no longer being held
#define IGNORE_HELD_ITEM (1<<2)
/// Can do the action even if the mob is incapacitated (ex. handcuffed)
#define IGNORE_INCAPACITATED (1<<3)
/// Used to prevent important slowdowns from being abused by drugs like kronkaine
#define IGNORE_SLOWDOWNS (1<<4)
/// 33554431 (2^24 - 1) is the maximum value our bitflags can reach.
#define MAX_BITFLAG_DIGITS 8
+2
View File
@@ -474,6 +474,8 @@
#define COMSIG_ITEM_AFTERATTACK "item_afterattack" //from base of obj/item/afterattack(): (atom/target, mob/user, params)
#define COMSIG_ITEM_ALT_AFTERATTACK "item_alt_afterattack" //from base of obj/item/altafterattack(): (atom/target, mob/user, proximity, params)
#define COMSIG_ITEM_EQUIPPED "item_equip" //from base of obj/item/equipped(): (/mob/equipper, slot)
/// A mob has just unequipped an item.
#define COMSIG_MOB_UNEQUIPPED_ITEM "mob_unequipped_item"
// Do not grant actions on equip.
#define COMPONENT_NO_GRANT_ACTIONS 1
#define COMSIG_ITEM_DROPPED "item_drop" //from base of obj/item/dropped(): (mob/user)
@@ -0,0 +1,14 @@
/// From /datum/surgery/New(): (datum/surgery/surgery, surgery_location (body zone), obj/item/bodypart/targeted_limb)
#define COMSIG_MOB_SURGERY_STARTED "mob_surgery_started"
/// From /datum/surgery_step/success(): (datum/surgery_step/step, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results)
#define COMSIG_MOB_SURGERY_STEP_SUCCESS "mob_surgery_step_success"
/// From /obj/item/shockpaddles/proc/do_success(): (obj/item/shockpaddles/source)
#define COMSIG_DEFIBRILLATOR_SUCCESS "defib_success"
#define COMPONENT_DEFIB_STOP (1<<0)
/// From /datum/surgery/can_start(): (mob/source, datum/surgery/surgery, mob/living/patient)
#define COMSIG_SURGERY_STARTING "surgery_starting"
#define COMPONENT_CANCEL_SURGERY (1<<0)
#define COMPONENT_FORCE_SURGERY (1<<1)
@@ -1,3 +0,0 @@
/// from base of atom/movable/Process_Spacemove(): (movement_dir)
#define COMSIG_MOVABLE_SPACEMOVE "spacemove"
#define COMSIG_MOVABLE_STOP_SPACEMOVE (1<<0)
+29 -1
View File
@@ -1,7 +1,35 @@
//MODsuit signals
/// Called when a module is selected to be the active one from on_select()
/// Called when a module is selected to be the active one from on_select(obj/item/mod/module/module)
#define COMSIG_MOD_MODULE_SELECTED "mod_module_selected"
/// Called when a MOD deploys one or more of its parts.
#define COMSIG_MOD_DEPLOYED "mod_deployed"
/// Called when a MOD retracts one or more of its parts.
#define COMSIG_MOD_RETRACTED "mod_retracted"
/// Called when a MOD is finished toggling itself.
#define COMSIG_MOD_TOGGLED "mod_toggled"
/// Called when a MOD activation is called from toggle_activate(mob/user)
#define COMSIG_MOD_ACTIVATE "mod_activate"
/// Cancels the suit's activation
#define MOD_CANCEL_ACTIVATE (1 << 0)
/// Called when a MOD finishes having a module removed from it.
#define COMSIG_MOD_MODULE_REMOVED "mod_module_removed"
/// Called when a MOD finishes having a module added to it.
#define COMSIG_MOD_MODULE_ADDED "mod_module_added"
/// Called when a MOD is having modules removed from crowbar_act(mob/user, obj/crowbar)
#define COMSIG_MOD_MODULE_REMOVAL "mod_module_removal"
/// Cancels the removal of modules
#define MOD_CANCEL_REMOVAL (1 << 0)
/// Called when a module attempts to activate, however it does. At the end of checks so you can add some yourself, or work on trigger behavior (mob/user)
#define COMSIG_MODULE_TRIGGERED "mod_module_triggered"
/// Cancels activation, with no message. Include feedback on your cancel.
#define MOD_ABORT_USE (1<<0)
/// Called when a module activates, after all checks have passed and cooldown started.
#define COMSIG_MODULE_ACTIVATED "mod_module_activated"
/// Called when a module deactivates, after all checks have passed.
#define COMSIG_MODULE_DEACTIVATED "mod_module_deactivated"
/// Called when a module is used, after all checks have passed and cooldown started.
#define COMSIG_MODULE_USED "mod_module_used"
/// Called when the MODsuit wearer is set.
#define COMSIG_MOD_WEARER_SET "mod_wearer_set"
/// Called when the MODsuit wearer is unset.
#define COMSIG_MOD_WEARER_UNSET "mod_wearer_unset"
+11 -2
View File
@@ -2,7 +2,10 @@
#define DEFAULT_MAX_COMPLEXITY 15
/// Default cell drain per process on MODsuits
#define DEFAULT_CELL_DRAIN 5
#define DEFAULT_CHARGE_DRAIN 5
/// Default time for a part to seal
#define MOD_ACTIVATION_STEP_TIME (2 SECONDS)
/// Passive module, just acts when put in naturally.
#define MODULE_PASSIVE 0
@@ -14,18 +17,24 @@
#define MODULE_ACTIVE 3
//Defines used by the theme for clothing flags and similar
#define HELMET_LAYER "helmet_layer"
#define CONTROL_LAYER "control_layer"
#define HELMET_FLAGS "helmet_flags"
#define CHESTPLATE_FLAGS "chestplate_flags"
#define GAUNTLETS_FLAGS "gauntlets_flags"
#define BOOTS_FLAGS "boots_flags"
#define UNSEALED_LAYER "unsealed_layer"
#define UNSEALED_CLOTHING "unsealed_clothing"
#define SEALED_CLOTHING "sealed_clothing"
#define UNSEALED_INVISIBILITY "unsealed_invisibility"
#define SEALED_INVISIBILITY "sealed_invisibility"
#define UNSEALED_COVER "unsealed_cover"
#define SEALED_COVER "sealed_cover"
#define CAN_OVERSLOT "can_overslot"
//Defines used to override MOD clothing's icon and worn icon files in the skin.
#define MOD_ICON_OVERRIDE "mod_icon_override"
#define MOD_WORN_ICON_OVERRIDE "mod_worn_icon_override"
/// Global list of all /datum/mod_theme
GLOBAL_LIST_INIT(mod_themes, setup_mod_themes())
+1 -2
View File
@@ -160,6 +160,7 @@
#define TRAIT_CAPTAIN_METABOLISM "captain-metabolism"
/// Prevents plasmamen from self-igniting
#define TRAIT_NOSELFIGNITION "no_selfignition"
#define TRAIT_NOSELFIGNITION_HEAD_ONLY "no_selfignition_head_only"
/// Like antimagic, but doesn't block the user from casting
#define TRAIT_ANTIMAGIC_NO_SELFBLOCK "anti_magic_no_selfblock"
/// Gives us turf, mob and object vision through walls
@@ -229,8 +230,6 @@
#define TRAIT_AUTO_CATCH_ITEM "auto_catch_item"
#define TRAIT_CLOWN_MENTALITY "clown_mentality" // The future is now, clownman.
#define TRAIT_FREESPRINT "free_sprinting"
#define TRAIT_XRAY_VISION "xray_vision"
#define TRAIT_THERMAL_VISION "thermal_vision"
#define TRAIT_NO_TELEPORT "no-teleport" //you just can't
#define TRAIT_NO_INTERNALS "no-internals"
#define TRAIT_TOXIC_ALCOHOL "alcohol_intolerance"
@@ -557,7 +557,7 @@
/datum/crafting_recipe/mod_core
name = "MOD core"
result = /obj/item/mod/construction/core
tool_behaviors = list(TOOL_SCREWDRIVER)
tools = list(TOOL_SCREWDRIVER)
time = 10 SECONDS
reqs = list(/obj/item/stack/cable_coil = 5,
/obj/item/stack/rods = 2,
+1 -1
View File
@@ -369,7 +369,7 @@
//Tries to dump content
/datum/component/storage/proc/dump_content_at(atom/dest_object, mob/M)
var/atom/A = parent
var/atom/dump_destination = get_dumping_location(dest_object)
var/atom/dump_destination = dest_object.get_dumping_location(dest_object)
if(M.CanReach(A) && dump_destination && M.CanReach(dump_destination))
if(check_locked(null, M, TRUE))
to_chat(M, "<span class='warning'>[parent] seems to be locked!</span>")
-9
View File
@@ -348,21 +348,12 @@
/datum/preset_holoimage/engineer/rig
outfit_type = /datum/outfit/job/engineer/gloved/rig
/datum/preset_holoimage/engineer/mod
outfit_type = /datum/outfit/job/engineer/mod
/datum/preset_holoimage/engineer/ce
outfit_type = /datum/outfit/job/ce
/datum/preset_holoimage/engineer/ce/mod
outfit_type = /datum/outfit/job/ce/mod
/datum/preset_holoimage/engineer/ce/rig
outfit_type = /datum/outfit/job/engineer/gloved/rig
/datum/preset_holoimage/engineer/atmos/mod
outfit_type = /datum/outfit/job/atmos/mod
/datum/preset_holoimage/engineer/atmos
outfit_type = /datum/outfit/job/atmos
+28 -33
View File
@@ -105,8 +105,18 @@
*/
var/list/implants = null
///ID of the slot containing a gas tank
var/internals_slot = null
//skyrat edit
///Slot for underwear like boxers and panties
var/underwear = null
///Slot for socks, yes, the thing that usually goes before your shoes
var/socks = null
///Slot for the undershirt (which is quite a foreign concept to me) or bras
var/shirt = null
///Slot for the opposite ear.
var/ears_extra = null
///Slot for the part of your arms that isn't quite hands yet.
var/wrists = null
//
/// Should the toggle helmet proc be called on the helmet during equip
var/toggle_helmet = TRUE
@@ -144,15 +154,6 @@
//to be overridden for toggling internals, id binding, access etc
return
#define EQUIP_OUTFIT_ITEM(item_path, slot_name) if(##item_path) { \
H.equip_to_slot_or_del(SSwardrobe.provide_type(##item_path), ##slot_name, TRUE); \
var/obj/item/outfit_item = H.get_item_by_slot(##slot_name); \
if (outfit_item && outfit_item.type == ##item_path) { \
outfit_item.on_outfit_equip(H, visualsOnly, ##slot_name); \
} \
}
/**
* Equips all defined types and paths to the mob passed in
*
@@ -166,34 +167,31 @@
//Start with uniform,suit,backpack for additional slots
if(uniform)
EQUIP_OUTFIT_ITEM(uniform, ITEM_SLOT_ICLOTHING)
H.equip_to_slot_or_del(new uniform(H), ITEM_SLOT_ICLOTHING, TRUE)
if(suit)
EQUIP_OUTFIT_ITEM(suit, ITEM_SLOT_OCLOTHING)
H.equip_to_slot_or_del(new suit(H), ITEM_SLOT_OCLOTHING, TRUE)
if(belt)
EQUIP_OUTFIT_ITEM(belt, ITEM_SLOT_BELT)
H.equip_to_slot_or_del(new belt(H), ITEM_SLOT_BELT, TRUE)
if(gloves)
EQUIP_OUTFIT_ITEM(gloves, ITEM_SLOT_GLOVES)
H.equip_to_slot_or_del(new gloves(H), ITEM_SLOT_GLOVES, TRUE)
if(shoes)
EQUIP_OUTFIT_ITEM(shoes, ITEM_SLOT_FEET)
H.equip_to_slot_or_del(new shoes(H), ITEM_SLOT_FEET, TRUE)
if(head)
EQUIP_OUTFIT_ITEM(head, ITEM_SLOT_HEAD)
H.equip_to_slot_or_del(new head(H), ITEM_SLOT_HEAD, TRUE)
if(mask)
EQUIP_OUTFIT_ITEM(mask, ITEM_SLOT_MASK)
H.equip_to_slot_or_del(new mask(H), ITEM_SLOT_MASK, TRUE)
if(neck)
EQUIP_OUTFIT_ITEM(neck, ITEM_SLOT_NECK)
H.equip_to_slot_or_del(new neck(H), ITEM_SLOT_NECK, TRUE)
if(ears)
EQUIP_OUTFIT_ITEM(ears, ITEM_SLOT_EARS)
H.equip_to_slot_or_del(new ears(H), ITEM_SLOT_EARS, TRUE)
if(glasses)
EQUIP_OUTFIT_ITEM(glasses, ITEM_SLOT_EYES)
H.equip_to_slot_or_del(new glasses(H), ITEM_SLOT_EYES, TRUE)
if(back)
EQUIP_OUTFIT_ITEM(back, ITEM_SLOT_BACK)
H.equip_to_slot_or_del(new back(H), ITEM_SLOT_BACK, TRUE)
if(id)
EQUIP_OUTFIT_ITEM(id, ITEM_SLOT_ID)
H.equip_to_slot_or_del(new id(H), ITEM_SLOT_ID, TRUE)
if(suit_store)
EQUIP_OUTFIT_ITEM(suit_store, ITEM_SLOT_SUITSTORE)
if(undershirt)
H.undershirt = initial(undershirt.name)
H.equip_to_slot_or_del(new suit_store(H), ITEM_SLOT_SUITSTORE, TRUE)
if(accessory)
var/obj/item/clothing/under/U = H.w_uniform
@@ -209,9 +207,9 @@
if(!visualsOnly) // Items in pockets or backpack don't show up on mob's icon.
if(l_pocket)
EQUIP_OUTFIT_ITEM(l_pocket, ITEM_SLOT_LPOCKET)
H.equip_to_slot_or_del(l_pocket, ITEM_SLOT_LPOCKET, TRUE)
if(r_pocket)
EQUIP_OUTFIT_ITEM(r_pocket, ITEM_SLOT_RPOCKET)
H.equip_to_slot_or_del(r_pocket, ITEM_SLOT_RPOCKET, TRUE)
if(box)
if(!backpack_contents)
@@ -225,7 +223,7 @@
if(!isnum(number))//Default to 1
number = 1
for(var/i in 1 to number)
EQUIP_OUTFIT_ITEM(path, ITEM_SLOT_BACKPACK)
H.equip_to_slot_or_del(path, ITEM_SLOT_BACKPACK, TRUE)
post_equip(H, visualsOnly, preference_source)
@@ -242,9 +240,6 @@
H.update_body()
return TRUE
#undef EQUIP_OUTFIT_ITEM
/**
* Apply a fingerprint from the passed in human to all items in the outfit
*
+15 -11
View File
@@ -31,6 +31,8 @@
var/uv_cycles = 6
var/message_cooldown
var/breakout_time = 300
/// How fast it charges cells in a suit
var/charge_rate = 250
/obj/machinery/suit_storage_unit/standard_unit
suit_type = /obj/item/clothing/suit/space/eva
@@ -43,7 +45,7 @@
storage_type = /obj/item/tank/jetpack/oxygen/captain
/obj/machinery/suit_storage_unit/captainmod
mask_type = /obj/item/clothing/mask/gas/atmos/captain
mask_type = /obj/item/clothing/mask/gas/sechailer
storage_type = /obj/item/tank/jetpack/oxygen/captain
mod_type = /obj/item/mod/control/pre_equipped/magnate
@@ -58,11 +60,11 @@
/obj/machinery/suit_storage_unit/atmos
suit_type = /obj/item/clothing/suit/space/hardsuit/engine/atmos
mask_type = /obj/item/clothing/mask/gas/atmos
mask_type = /obj/item/clothing/mask/breath
storage_type = /obj/item/watertank/atmos
/obj/machinery/suit_storage_unit/atmosmod
mask_type = /obj/item/clothing/mask/gas/atmos
mask_type = /obj/item/clothing/mask/breath
storage_type = /obj/item/watertank/atmos
mod_type = /obj/item/mod/control/pre_equipped/atmospheric
@@ -332,7 +334,7 @@
things_to_clear += mask.GetAllContents()
if(mod)
things_to_clear += mod
things_to_clear += mod.get_all_contents()
things_to_clear += mod.GetAllContents()
if(storage)
things_to_clear += storage
things_to_clear += storage.GetAllContents()
@@ -352,13 +354,7 @@
/obj/machinery/suit_storage_unit/process(delta_time)
var/obj/item/stock_parts/cell/cell
if(suit)
if(!istype(suit))
return
if(!suit.cell)
return
cell = suit.cell
else if(mod)
if(mod)
if(!istype(mod))
return
if(!mod.cell)
@@ -370,6 +366,14 @@
use_power(charge_rate * delta_time)
cell.give(charge_rate * delta_time)
/obj/machinery/suit_storage_unit/proc/shock(mob/user, prb)
if(!prob(prb))
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(5, 1, src)
s.start()
if(electrocute_mob(user, src, src, 1, TRUE))
return 1
/obj/machinery/suit_storage_unit/relaymove(mob/user)
if(locked)
if(message_cooldown <= world.time)
+2 -2
View File
@@ -399,7 +399,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
if(throwing)
throwing.finalize(FALSE)
if(loc == user)
if(!allow_attack_hand_drop(user) || !user.temporarilyRemoveItemFromInventory(src))
if(!allow_attack_hand_drop(user) || !user.temporarilyRemoveItemFromInventory(I = src))
return
. = FALSE
@@ -428,7 +428,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
if(throwing)
throwing.finalize(FALSE)
if(loc == user)
if(!user.temporarilyRemoveItemFromInventory(src))
if(!allow_attack_hand_drop(user) || !user.temporarilyRemoveItemFromInventory(src))
return
pickup(user)
+6
View File
@@ -461,6 +461,8 @@
cooldown = TRUE
busy = FALSE
update_icon()
if(SEND_SIGNAL(src, COMSIG_DEFIBRILLATOR_SUCCESS) & COMPONENT_DEFIB_STOP)
return
if(req_defib)
defib.cooldowncheck(user)
else
@@ -514,6 +516,8 @@
cooldown = TRUE
busy = FALSE
update_icon()
if(SEND_SIGNAL(src, COMSIG_DEFIBRILLATOR_SUCCESS) & COMPONENT_DEFIB_STOP)
return
if(!req_defib)
recharge(60)
if(req_defib && (defib.cooldowncheck(user)))
@@ -632,6 +636,8 @@
defib.deductcharge(revivecost)
cooldown = 1
update_icon()
if(SEND_SIGNAL(src, COMSIG_DEFIBRILLATOR_SUCCESS) & COMPONENT_DEFIB_STOP)
return
if(req_defib)
defib.cooldowncheck(user)
else
+1 -7
View File
@@ -28,17 +28,11 @@
/obj/item/aicard/pre_attack(atom/target, mob/living/user, params)
if(AI) //AI is on the card, implies user wants to upload it.
var/our_ai = AI
target.transfer_ai(AI_TRANS_FROM_CARD, user, AI, src)
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, our_ai, "uploaded", src, "to [target].")
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)
log_combat(user, AI, "uploaded", src, "to [target].")
return TRUE
update_appearance() //Whatever happened, update the card's state (icon, name) to match.
return ..()
-1
View File
@@ -244,7 +244,6 @@
desc = "Three cores, perfect for any MODsuit construction! Naturally harvested™, of course."
cost = CARGO_CRATE_VALUE * 3
access = ACCESS_ROBOTICS
access_view = ACCESS_ROBOTICS
contains = list(/obj/item/mod/construction/core,
/obj/item/mod/construction/core,
/obj/item/mod/construction/core)
@@ -1,23 +0,0 @@
/// Switches between mouse buttons for MODsuit active modules
/datum/preference/choiced/mod_select
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "mod_select"
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/choiced/mod_select/init_possible_values()
return list(MIDDLE_CLICK, ALT_CLICK)
/datum/preference/choiced/mod_select/create_default_value()
return MIDDLE_CLICK
/datum/preference/choiced/mod_select/apply_to_client_updated(client/client, value)
if(!ishuman(client.mob))
return
var/mob/living/carbon/human/client_owner = client.mob
if(!istype(client_owner.back, /obj/item/mod/control))
return
var/obj/item/mod/control/mod = client_owner.back
if(!mod.selected_module)
return
UnregisterSignal(mod.wearer, mod.selected_module.used_signal)
mod.selected_module.update_signal(value)
+1
View File
@@ -337,6 +337,7 @@
on_item_dropped(I)
if(I.dropped(src) == ITEM_RELOCATED_BY_DROPPED)
return FALSE
SEND_SIGNAL(src, COMSIG_MOB_UNEQUIPPED_ITEM, I, force, newloc, no_move, invdrop, silent)
return TRUE
//This is a SAFE proc. Use this instead of equip_to_slot()!
@@ -305,6 +305,12 @@
update_inv_hands()
return
var/datum/component/storage/storage = equipped_back.GetComponent(/datum/component/storage)
if(istype(equipped_back, /obj/item/mod/control))
var/obj/item/mod/control/C = equipped_back
for(var/obj/item/mod/module/storage/S in C.modules)
if(S.stored)
equipped_back = S.stored
storage = S.stored.GetComponent(/datum/component/storage)
if(!storage)
if(!thing)
equipped_back.attack_hand(src)
@@ -1303,8 +1303,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(ITEM_SLOT_FEET)
if(H.shoes)
return FALSE
if((DIGITIGRADE in species_traits) && !(I.item_flags & IGNORE_DIGITIGRADE))
return FALSE
if(num_legs < 2)
return FALSE
if(DIGITIGRADE in species_traits)
+10 -2
View File
@@ -99,6 +99,13 @@
var/display_icon_override
var/emote_display = "Neutral" //text string of the current emote we set for the status displays, to prevent logins resetting it.
var/datum/robot_control/robot_control
/// Station alert datum for showing alerts UI
var/datum/station_alert/alert_control
///remember AI's last location
var/atom/lastloc
interaction_range = INFINITY
/mob/living/silicon/ai/Initialize(mapload, datum/ai_laws/L, mob/target_ai)
. = ..()
if(!target_ai) //If there is no player/brain inside.
@@ -177,9 +184,10 @@
QDEL_NULL(spark_system)
QDEL_NULL(malf_picker)
QDEL_NULL(doomsday_device)
QDEL_NULL(robot_control)
// TODO: Why these no work?
// QDEL_NULL(robot_control)
QDEL_NULL(aiMulti)
QDEL_NULL(alert_control)
// QDEL_NULL(alert_control)
malfhack = null
current = null
Bot = null
+54 -17
View File
@@ -3,28 +3,41 @@
icon_icon = 'icons/mob/actions/actions_mod.dmi'
check_flags = AB_CHECK_CONSCIOUS
var/obj/item/mod/control/mod
/// Whether this action is intended for the AI. Stuff breaks a lot if this is done differently.
var/ai_action = FALSE
/// Whether this action is intended for the inserted pAI. Stuff breaks a lot if this is done differently.
var/pai_action = FALSE
/datum/action/item_action/mod/New(Target)
..()
mod = Target
/datum/action/item_action/mod/Grant(mob/M)
if(owner)
Share(M)
if(!istype(Target, /obj/item/mod/control))
qdel(src)
return
..()
if(ai_action)
background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND
/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/Grant(mob/user)
mod = target
if(ai_action && user != mod.ai)
return
else if(!ai_action && user == mod.ai)
return
return ..()
/datum/action/item_action/mod/Remove(mob/user)
if(ai_action && mod && user != mod.ai)
return
else if(!ai_action && mod && user == mod.ai)
return
return ..()
/datum/action/item_action/mod/Trigger(trigger_flags)
if(!IsAvailable())
return FALSE
if(mod.malfunctioning && prob(75))
mod.balloon_alert(usr, "button malfunctions!")
return FALSE
return TRUE
/datum/action/item_action/mod/deploy
name = "Deploy MODsuit"
@@ -37,6 +50,12 @@
mod.choose_deploy(usr)
return TRUE
/datum/action/item_action/mod/deploy/ai
ai_action = TRUE
/datum/action/item_action/mod/deploy/pai
pai_action = TRUE
/datum/action/item_action/mod/activate
name = "Activate MODsuit"
desc = "Activate/Deactivate the MODsuit."
@@ -48,6 +67,12 @@
mod.toggle_activate(usr)
return TRUE
/datum/action/item_action/mod/activate/ai
ai_action = TRUE
/datum/action/item_action/mod/activate/pai
pai_action = TRUE
/datum/action/item_action/mod/module
name = "Toggle Module"
desc = "Toggle a MODsuit module."
@@ -59,6 +84,12 @@
mod.quick_module(usr)
return TRUE
/datum/action/item_action/mod/module/ai
ai_action = TRUE
/datum/action/item_action/mod/module/pai
pai_action = TRUE
/datum/action/item_action/mod/panel
name = "MODsuit Panel"
desc = "Open the MODsuit's panel."
@@ -69,3 +100,9 @@
return FALSE
mod.ui_interact(usr)
return TRUE
/datum/action/item_action/mod/panel/ai
ai_action = TRUE
/datum/action/item_action/mod/panel/pai
pai_action = TRUE
+29 -12
View File
@@ -1,4 +1,3 @@
#define MOD_ACTIVATION_STEP_TIME 2 SECONDS
#define MOD_ACTIVATION_STEP_FLAGS IGNORE_USER_LOC_CHANGE|IGNORE_TARGET_LOC_CHANGE|IGNORE_HELD_ITEM|IGNORE_INCAPACITATED
/// Creates a radial menu from which the user chooses parts of the suit to deploy/retract. Repeats until all parts are extended or retracted.
@@ -72,7 +71,8 @@
/obj/item/mod/control/proc/conceal(mob/user, part)
var/obj/item/piece = part
REMOVE_TRAIT(piece, TRAIT_NODROP, MOD_TRAIT)
wearer.transferItemToLoc(piece, src, force = TRUE)
if(wearer)
wearer.transferItemToLoc(piece, src, force = TRUE)
if(piece == gauntlets)
gauntlets.show_overslot()
if(piece == boots)
@@ -117,28 +117,36 @@
playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE)
return FALSE
for(var/obj/item/mod/module/module as anything in modules)
if(!module.active)
if(!module.active || module.allowed_inactive)
continue
module.on_deactivation()
activating = TRUE
to_chat(wearer, span_notice("MODsuit [active ? "shutting down" : "starting up"]."))
if(do_after(wearer, MOD_ACTIVATION_STEP_TIME, wearer, MOD_ACTIVATION_STEP_FLAGS))
if(do_after(wearer, MOD_ACTIVATION_STEP_TIME, target = wearer, required_mobility_flags = NONE))
to_chat(wearer, span_notice("[boots] [active ? "relax their grip on your legs" : "seal around your feet"]."))
playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
seal_part(boots, seal = !active)
if(do_after(wearer, MOD_ACTIVATION_STEP_TIME, wearer, MOD_ACTIVATION_STEP_FLAGS))
else
return toggle_activate_fail()
if(do_after(wearer, MOD_ACTIVATION_STEP_TIME, target = wearer, required_mobility_flags = NONE))
to_chat(wearer, span_notice("[gauntlets] [active ? "become loose around your fingers" : "tighten around your fingers and wrists"]."))
playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
seal_part(gauntlets, seal = !active)
if(do_after(wearer, MOD_ACTIVATION_STEP_TIME, wearer, MOD_ACTIVATION_STEP_FLAGS))
else
return toggle_activate_fail()
if(do_after(wearer, MOD_ACTIVATION_STEP_TIME, target = wearer, required_mobility_flags = NONE))
to_chat(wearer, span_notice("[chestplate] [active ? "releases your chest" : "cinches tightly against your chest"]."))
playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
seal_part(chestplate,seal = !active)
if(do_after(wearer, MOD_ACTIVATION_STEP_TIME, wearer, MOD_ACTIVATION_STEP_FLAGS))
else
return toggle_activate_fail()
if(do_after(wearer, MOD_ACTIVATION_STEP_TIME, target = wearer, required_mobility_flags = NONE))
to_chat(wearer, span_notice("[helmet] hisses [active ? "open" : "closed"]."))
playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
seal_part(helmet, seal = !active)
if(do_after(wearer, MOD_ACTIVATION_STEP_TIME, wearer, MOD_ACTIVATION_STEP_FLAGS))
else
return toggle_activate_fail()
if(do_after(wearer, MOD_ACTIVATION_STEP_TIME, target = wearer, required_mobility_flags = NONE))
to_chat(wearer, span_notice("Systems [active ? "shut down. Parts unsealed. Goodbye" : "started up. Parts sealed. Welcome"], [wearer]."))
if(ai)
to_chat(ai, span_notice("<b>SYSTEMS [active ? "DEACTIVATED. GOODBYE" : "ACTIVATED. WELCOME"]: \"[ai]\"</b>"))
@@ -148,9 +156,20 @@
SEND_SOUND(wearer, sound('sound/mecha/nominal.ogg',volume=50))
else
playsound(src, 'sound/machines/synth_no.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, frequency = 6000)
else
return toggle_activate_fail()
activating = FALSE
return TRUE
/obj/item/mod/control/proc/toggle_activate_fail()
seal_part(boots, seal = active)
seal_part(gauntlets, seal = active)
seal_part(chestplate,seal = active)
seal_part(helmet, seal = active)
to_chat(wearer, span_warning("[active ? "Shut down" : "Start up"] cancelled."))
activating = FALSE
return FALSE
///Seals or unseals the given part
/obj/item/mod/control/proc/seal_part(obj/item/clothing/part, seal)
if(seal)
@@ -165,18 +184,16 @@
part.clothing_flags &= ~part.visor_flags
part.heat_protection = NONE
part.cold_protection = NONE
part.icon_state = "[skin]-[initial(part.icon_state)][seal ? "-sealed" : ""]"
part.item_state = "[skin]-[initial(part.item_state)][seal ? "-sealed" : ""]"
if(part == boots)
boots.icon_state = "[skin]-boots[seal ? "-sealed" : ""]"
wearer.update_inv_shoes()
if(part == gauntlets)
gauntlets.icon_state = "[skin]-gauntlets[seal ? "-sealed" : ""]"
wearer.update_inv_gloves()
if(part == chestplate)
chestplate.icon_state = "[skin]-chestplate[seal ? "-sealed" : ""]"
wearer.update_inv_wear_suit()
wearer.update_inv_w_uniform()
if(part == helmet)
helmet.icon_state = "[skin]-helmet[seal ? "-sealed" : ""]"
if(seal)
helmet.alternate_worn_layer = null
else
+95 -5
View File
@@ -14,6 +14,8 @@
if(!do_after(user, 5 SECONDS, target = src))
balloon_alert(user, "interrupted!")
return
if(!ai)
return
intAI = ai
intAI.ai_restore_power()//So the AI initially has power.
intAI.control_disabled = TRUE
@@ -22,10 +24,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")
@@ -37,6 +36,9 @@
if(!intAI)
balloon_alert(user, "no AI in card!")
return
if(ai)
balloon_alert(user, "already has AI!")
return
if(intAI.deployed_shell) //Recall AI if shelled so it can be checked for a client
intAI.disconnect_shell()
if(intAI.stat || !intAI.client)
@@ -46,6 +48,8 @@
if(!do_after(user, 5 SECONDS, target = src))
balloon_alert(user, "interrupted!")
return
if(ai)
return
balloon_alert(user, "AI transferred to suit")
ai_enter_mod(intAI)
card.AI = null
@@ -63,14 +67,95 @@
for(var/datum/action/action as anything in actions)
action.Grant(new_ai)
/**
* Simple proc to insert the pAI into the MODsuit.
*
* user - The person trying to put the pAI into the MODsuit.
* card - The pAI card we're slotting in the MODsuit.
*/
/obj/item/mod/control/proc/insert_pai(mob/user, obj/item/paicard/card)
if(mod_pai)
balloon_alert(user, "pAI already installed!")
return
if(!card.pai || !card.pai.mind)
balloon_alert(user, "pAI unresponsive!")
return
balloon_alert(user, "transferring to suit...")
if(!do_after(user, 5 SECONDS, target = src))
balloon_alert(user, "interrupted!")
return FALSE
if(!user.transferItemToLoc(card, src))
return
mod_pai = card.pai
balloon_alert(user, "pAI transferred to suit")
balloon_alert(mod_pai, "transferred to a suit")
mod_pai.canholo = FALSE
mod_pai.remote_control = src
for(var/datum/action/action as anything in actions)
action.Grant(mod_pai)
return TRUE
/**
* Simple proc to extract the pAI from the MODsuit. It's the proc to call if you want to take it out,
* remove_pai() is there so atom_destruction() doesn't have any risk of sleeping.
*
* user - The person trying to take out the pAI from the MODsuit.
* forced - Whether or not we skip the checks and just eject the pAI. Defaults to FALSE.
* feedback - Whether to give feedback via balloon alerts or not. Defaults to TRUE.
*/
/obj/item/mod/control/proc/extract_pai(mob/user, forced = FALSE, feedback = TRUE)
if(!mod_pai)
if(user && feedback)
balloon_alert(user, "no pAI to remove!")
return
if(!forced)
if(!open)
if(user && feedback)
balloon_alert(user, "open the suit panel!")
return FALSE
if(!do_after(user, 5 SECONDS, target = src))
if(user && feedback)
balloon_alert(user, "interrupted!")
return FALSE
remove_pai(feedback)
if(feedback && user)
balloon_alert(user, "pAI removed from the suit")
/**
* Simple proc that handles the safe removal of the pAI from a MOD control unit.
*
* Arguments:
* * feedback - Whether or not we want to give balloon alert feedback to the mod_pai. Defaults to FALSE.
*/
/obj/item/mod/control/proc/remove_pai(feedback = FALSE)
var/turf/drop_off = get_turf(src)
if(drop_off) // In case there's no drop_off, the pAI will simply get deleted.
mod_pai.card.forceMove(drop_off)
for(var/datum/action/action as anything in actions)
if(action.owner == mod_pai)
action.Remove(mod_pai)
if(feedback)
balloon_alert(mod_pai, "removed from a suit")
mod_pai.remote_control = null
mod_pai.canholo = TRUE
mod_pai = null
#define MOVE_DELAY 2
#define WEARER_DELAY 1
#define LONE_DELAY 5
#define CELL_PER_STEP DEFAULT_CELL_DRAIN * 2.5
#define CELL_PER_STEP (DEFAULT_CHARGE_DRAIN * 2.5)
/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))
return FALSE
if(wearer && (wearer.pulledby?.grab_state || wearer.incapacitated() || wearer.stat))
return FALSE
var/timemodifier = MOVE_DELAY * (ISDIAGONALDIR(direction) ? SQRT_2 : 1) * (wearer ? WEARER_DELAY : LONE_DELAY)
COOLDOWN_START(src, cooldown_mod_move, movedelay * timemodifier + slowdown)
playsound(src, 'sound/mecha/mechmove01.ogg', 25, TRUE)
@@ -86,3 +171,8 @@
#undef WEARER_DELAY
#undef LONE_DELAY
#undef CELL_PER_STEP
/obj/item/mod/control/ui_state(mob/user)
if(user == mod_pai)
return GLOB.contained_state
return ..()
+28 -14
View File
@@ -1,9 +1,12 @@
/obj/item/clothing/head/helmet/space/mod
name = "MOD helmet"
desc = "A helmet for a MODsuit."
icon = 'icons/obj/mod.dmi'
icon = 'icons/obj/clothing/modsuit/mod_clothing.dmi'
mob_overlay_icon = 'icons/mob/clothing/modsuit/mod_clothing.dmi'
anthro_mob_worn_overlay = 'icons/mob/clothing/modsuit/mod_clothing.dmi'
taur_mob_worn_overlay = 'icons/mob/clothing/modsuit/mod_clothing.dmi'
icon_state = "helmet"
worn_icon = 'icons/mob/mod.dmi'
item_state = "helmet"
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 25, ACID = 25, WOUND = 10)
body_parts_covered = HEAD
heat_protection = HEAD
@@ -12,15 +15,16 @@
min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
clothing_flags = THICKMATERIAL
resistance_flags = NONE
flash_protect = FLASH_PROTECTION_NONE
clothing_flags = SNUG_FIT
flash_protect = 0
clothing_flags = NONE
flags_inv = HIDEFACIALHAIR
flags_cover = NONE
visor_flags = THICKMATERIAL|STOPSPRESSUREDAMAGE
visor_flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT
visor_flags_cover = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF
visor_flags_cover = HEADCOVERSMOUTH|HEADCOVERSEYES
var/alternate_layer = NECK_LAYER
var/obj/item/mod/control/mod
mutantrace_variation = STYLE_MUZZLE
/obj/item/clothing/head/helmet/space/mod/Destroy()
if(!QDELETED(mod))
@@ -32,9 +36,12 @@
/obj/item/clothing/suit/armor/mod
name = "MOD chestplate"
desc = "A chestplate for a MODsuit."
icon = 'icons/obj/mod.dmi'
icon = 'icons/obj/clothing/modsuit/mod_clothing.dmi'
mob_overlay_icon = 'icons/mob/clothing/modsuit/mod_clothing.dmi'
anthro_mob_worn_overlay = 'icons/mob/clothing/modsuit/mod_clothing.dmi'
taur_mob_worn_overlay = 'icons/mob/clothing/modsuit/mod_clothing.dmi'
icon_state = "chestplate"
worn_icon = 'icons/mob/mod.dmi'
item_state = "chestplate"
blood_overlay_type = "armor"
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 25, ACID = 25, WOUND = 10)
body_parts_covered = CHEST|GROIN
@@ -48,6 +55,7 @@
allowed = list(/obj/item/flashlight, /obj/item/tank/internals)
resistance_flags = NONE
var/obj/item/mod/control/mod
mutantrace_variation = STYLE_DIGITIGRADE|STYLE_SNEK_TAURIC|STYLE_PAW_TAURIC
/obj/item/clothing/suit/armor/mod/Destroy()
if(!QDELETED(mod))
@@ -59,9 +67,12 @@
/obj/item/clothing/gloves/mod
name = "MOD gauntlets"
desc = "A pair of gauntlets for a MODsuit."
icon = 'icons/obj/mod.dmi'
icon = 'icons/obj/clothing/modsuit/mod_clothing.dmi'
mob_overlay_icon = 'icons/mob/clothing/modsuit/mod_clothing.dmi'
anthro_mob_worn_overlay = 'icons/mob/clothing/modsuit/mod_clothing.dmi'
taur_mob_worn_overlay = 'icons/mob/clothing/modsuit/mod_clothing.dmi'
icon_state = "gauntlets"
worn_icon = 'icons/mob/mod.dmi'
item_state = "gauntlets"
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 25, ACID = 25, WOUND = 10)
body_parts_covered = HANDS|ARMS
heat_protection = HANDS|ARMS
@@ -86,15 +97,18 @@
if(!overslot)
return
if(!mod.wearer.equip_to_slot_if_possible(overslot, overslot.slot_flags, qdel_on_fail = FALSE, disable_warning = TRUE))
mod.wearer.dropItemToGround(overslot, force = TRUE, silent = TRUE)
mod.wearer.dropItemToGround(overslot, force = TRUE)
overslot = null
/obj/item/clothing/shoes/mod
name = "MOD boots"
desc = "A pair of boots for a MODsuit."
icon = 'icons/obj/mod.dmi'
icon = 'icons/obj/clothing/modsuit/mod_clothing.dmi'
mob_overlay_icon = 'icons/mob/clothing/modsuit/mod_clothing.dmi'
anthro_mob_worn_overlay = 'icons/mob/clothing/modsuit/mod_clothing.dmi'
taur_mob_worn_overlay = 'icons/mob/clothing/modsuit/mod_clothing.dmi'
icon_state = "boots"
worn_icon = 'icons/mob/mod.dmi'
item_state = "boots"
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 25, ACID = 25, WOUND = 10)
body_parts_covered = FEET|LEGS
heat_protection = FEET|LEGS
@@ -103,7 +117,7 @@
min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
clothing_flags = THICKMATERIAL
resistance_flags = NONE
item_flags = IGNORE_DIGITIGRADE
item_flags = NONE
var/obj/item/mod/control/mod
var/obj/item/clothing/overslot
@@ -119,5 +133,5 @@
if(!overslot)
return
if(!mod.wearer.equip_to_slot_if_possible(overslot, overslot.slot_flags, qdel_on_fail = FALSE, disable_warning = TRUE))
mod.wearer.dropItemToGround(overslot, force = TRUE, silent = TRUE)
mod.wearer.dropItemToGround(overslot, force = TRUE)
overslot = null
+7 -6
View File
@@ -1,6 +1,7 @@
/obj/item/mod/construction
desc = "A part used in MOD construction."
inhand_icon_state = "rack_parts"
icon = 'icons/obj/clothing/modsuit/mod_construction.dmi'
item_state = "rack_parts"
/obj/item/mod/construction/helmet
name = "MOD helmet"
@@ -20,7 +21,7 @@
/obj/item/mod/construction/core
name = "MOD core"
icon_state = "mod-core"
icon_state = "mod-core-standard"
desc = "Growing in the most lush, fertile areas of the planet Sprout, there is a crystal known as the Heartbloom. \
These rare, organic piezoelectric crystals are of incredible cultural significance to the artist castes of the Ethereals, \
owing to their appearance; which is exactly similar to that of an Ethereal's heart. \n\
@@ -29,7 +30,7 @@
/obj/item/mod/construction/broken_core
name = "broken MOD core"
icon_state = "mod-core-broken"
icon_state = "mod-core"
desc = "An internal power source for a Modular Outerwear Device. You don't seem to be able to source any power from this one, though."
/obj/item/mod/construction/broken_core/examine(mob/user)
@@ -46,7 +47,7 @@
/obj/item/mod/construction/armor
name = "MOD armor plates"
desc = "Armor plates used to finish a MOD."
icon_state = "standard-armor"
icon_state = "standard-plating"
var/datum/mod_theme/theme = /datum/mod_theme
/obj/item/mod/construction/armor/Initialize(mapload)
@@ -54,7 +55,7 @@
var/datum/mod_theme/used_theme = GLOB.mod_themes[theme]
name = "MOD [used_theme.name] armor plates"
desc = "[desc] [used_theme.desc]"
icon_state = "[used_theme.default_skin]-armor"
icon_state = "[used_theme.default_skin]-plating"
/obj/item/mod/construction/armor/engineering
theme = /datum/mod_theme/engineering
@@ -77,7 +78,7 @@
/obj/item/mod/paint
name = "MOD paint kit"
desc = "This kit will repaint your MODsuit to something unique."
icon = 'icons/obj/mod.dmi'
icon = 'icons/obj/clothing/modsuit/mod_construction.dmi'
icon_state = "paintkit"
#define START_STEP "start"
+28 -15
View File
@@ -2,15 +2,18 @@
/obj/item/mod
name = "Base MOD"
desc = "You should not see this, yell at a coder!"
icon = 'icons/obj/mod.dmi'
icon = 'icons/obj/clothing/modsuit/mod_clothing.dmi'
mob_overlay_icon = 'icons/mob/clothing/modsuit/mod_clothing.dmi'
anthro_mob_worn_overlay = 'icons/mob/clothing/modsuit/mod_clothing.dmi'
taur_mob_worn_overlay = 'icons/mob/clothing/modsuit/mod_clothing.dmi'
icon_state = "standard-control"
worn_icon = 'icons/mob/mod.dmi'
item_state = "standard-control"
/obj/item/mod/control
name = "MOD control unit"
desc = "The control unit of a Modular Outerwear Device, a powered, back-mounted suit that protects against various environments."
icon_state = "control"
inhand_icon_state = "mod_control"
item_state = "control"
w_class = WEIGHT_CLASS_BULKY
slot_flags = ITEM_SLOT_BACK
strip_delay = 10 SECONDS
@@ -48,7 +51,7 @@
/// How much module complexity this MOD is carrying.
var/complexity = 0
/// Power usage of the MOD.
var/cell_drain = DEFAULT_CELL_DRAIN
var/cell_drain = DEFAULT_CHARGE_DRAIN
/// Slowdown of the MOD when not active.
var/slowdown_inactive = 2
/// Slowdown of the MOD when active.
@@ -73,6 +76,8 @@
var/obj/item/mod/module/selected_module
/// AI mob inhabiting the MOD.
var/mob/living/silicon/ai/ai
/// pAI mob inhabiting the MOD.
var/mob/living/silicon/pai/mod_pai
/// Delay between moves as AI.
var/movedelay = 0
/// Cooldown for AI moves.
@@ -123,6 +128,7 @@
piece.permeability_coefficient = theme.permeability_coefficient
piece.siemens_coefficient = theme.siemens_coefficient
piece.icon_state = "[skin]-[initial(piece.icon_state)]"
piece.item_state = "[skin]-[initial(piece.item_state)]"
update_flags()
for(var/obj/item/mod/module/module as anything in initial_modules)
module = new module(src)
@@ -206,6 +212,7 @@
balloon_alert(carbon_user, "retract parts first!")
playsound(src, 'sound/machines/scanbuzz.ogg', 25, FALSE, SILENCED_SOUND_EXTRARANGE)
return FALSE
return ..()
/obj/item/mod/control/MouseDrop(atom/over_object)
if(src != wearer?.back || !istype(over_object, /atom/movable/screen/inventory/hand))
@@ -241,10 +248,22 @@
return
return ..()
/obj/item/mod/control/AltClick(mob/user)
if(seconds_electrified && cell?.charge)
if(shock(user))
return
if(!open)
for(var/obj/item/mod/module/storage/S in modules)
if(S.stored)
playsound(user, "rustle", 50, 1, -5)
SEND_SIGNAL(S.stored, COMSIG_TRY_STORAGE_SHOW, wearer, TRUE)
return
. = ..()
/obj/item/mod/control/screwdriver_act(mob/living/user, obj/item/screwdriver)
if(..())
return TRUE
if(active || activating || ai_controller)
if(active || activating)
balloon_alert(user, "deactivate suit first!")
playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE)
return FALSE
@@ -330,12 +349,6 @@
if(open)
return cell
/obj/item/mod/control/GetAccess()
if(ai_controller)
return req_access.Copy()
else
return ..()
/obj/item/mod/control/emag_act(mob/user)
locked = !locked
balloon_alert(user, "[locked ? "locked" : "unlocked"]")
@@ -363,12 +376,12 @@
conceal(null, part)
return ..()
/obj/item/mod/control/worn_overlays(mutable_appearance/standing, isinhands = FALSE, icon_file)
/obj/item/mod/control/worn_overlays(isinhands = FALSE, icon_file)
. = ..()
if(!active)
return
for(var/obj/item/mod/module/module as anything in modules)
var/list/module_icons = module.generate_worn_overlay(standing)
var/list/module_icons = module.generate_worn_overlay()
if(!length(module_icons))
continue
. += module_icons
@@ -394,8 +407,8 @@
var/used_category
if(part == helmet)
used_category = HELMET_FLAGS
helmet.alternate_worn_layer = used_skin[HELMET_LAYER]
helmet.alternate_layer = used_skin[HELMET_LAYER]
helmet.alternate_worn_layer = used_skin["HELMET_LAYER"]
helmet.alternate_layer = used_skin["HELMET_LAYER"]
if(part == chestplate)
used_category = CHESTPLATE_FLAGS
if(part == gauntlets)
+57 -57
View File
@@ -28,7 +28,7 @@
/// How much modules can the MOD carry without malfunctioning.
var/complexity_max = DEFAULT_MAX_COMPLEXITY
/// How much battery power the MOD uses by just being on
var/cell_drain = DEFAULT_CELL_DRAIN
var/cell_drain = DEFAULT_CHARGE_DRAIN
/// Slowdown of the MOD when not active.
var/slowdown_inactive = 1.25
/// Slowdown of the MOD when active.
@@ -44,11 +44,11 @@
"standard" = list(
HELMET_LAYER = NECK_LAYER,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT,
UNSEALED_CLOTHING = NONE,
SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR,
SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -67,10 +67,10 @@
"civilian" = list(
HELMET_LAYER = null,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL,
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT,
UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -102,11 +102,11 @@
"engineering" = list(
HELMET_LAYER = NECK_LAYER,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT,
UNSEALED_CLOTHING = NONE,
SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR,
SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -137,12 +137,12 @@
"atmospheric" = list(
HELMET_LAYER = NECK_LAYER,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT,
UNSEALED_CLOTHING = NONE,
SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDESNOUT,
SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR,
UNSEALED_COVER = HEADCOVERSMOUTH,
SEALED_COVER = HEADCOVERSEYES|PEPPERPROOF,
SEALED_COVER = HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -175,11 +175,11 @@
"advanced" = list(
HELMET_LAYER = NECK_LAYER,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT,
UNSEALED_CLOTHING = NONE,
SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR,
SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -204,17 +204,17 @@
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 50, BIO = 100, FIRE = 100, ACID = 75, WOUND = 15)
resistance_flags = FIRE_PROOF
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
cell_drain = DEFAULT_CELL_DRAIN * 2
cell_drain = DEFAULT_CHARGE_DRAIN * 2
complexity_max = DEFAULT_MAX_COMPLEXITY + 5
skins = list(
"mining" = list(
HELMET_LAYER = null,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL,
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT,
SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -237,18 +237,18 @@
desc = "A lightweight suit by DeForest Medical Corporation, allows for easier movement."
default_skin = "medical"
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 100, FIRE = 60, ACID = 75, WOUND = 10)
cell_drain = DEFAULT_CELL_DRAIN * 1.5
cell_drain = DEFAULT_CHARGE_DRAIN * 1.5
slowdown_inactive = 1
slowdown_active = 0.5
skins = list(
"medical" = list(
HELMET_LAYER = NECK_LAYER,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT,
UNSEALED_CLOTHING = NONE,
SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR,
SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -267,11 +267,11 @@
"corpsman" = list(
HELMET_LAYER = NECK_LAYER,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT,
UNSEALED_CLOTHING = NONE,
SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR,
SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -296,7 +296,7 @@
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 100, FIRE = 100, ACID = 100, WOUND = 10)
resistance_flags = FIRE_PROOF|ACID_PROOF
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
cell_drain = DEFAULT_CELL_DRAIN * 1.5
cell_drain = DEFAULT_CHARGE_DRAIN * 1.5
slowdown_inactive = 0.75
slowdown_active = 0.25
inbuilt_modules = list(/obj/item/mod/module/quick_carry/advanced)
@@ -304,11 +304,11 @@
"rescue" = list(
HELMET_LAYER = NECK_LAYER,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT,
UNSEALED_CLOTHING = NONE,
SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR,
SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -341,10 +341,10 @@
"research" = list(
HELMET_LAYER = null,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL,
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT,
UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -375,12 +375,12 @@
"security" = list(
HELMET_LAYER = null,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL,
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT,
SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE,
UNSEALED_COVER = HEADCOVERSMOUTH,
SEALED_COVER = HEADCOVERSEYES|PEPPERPROOF,
SEALED_COVER = HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -413,10 +413,10 @@
"safeguard" = list(
HELMET_LAYER = null,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL,
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT,
UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -449,11 +449,11 @@
"magnate" = list(
HELMET_LAYER = NECK_LAYER,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT,
UNSEALED_CLOTHING = NONE,
SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR,
SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -476,18 +476,18 @@
desc = "A suit by Honk Ltd. Protects against low humor environments. Most of the tech went to lower the power cost."
default_skin = "cosmohonk"
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 100, FIRE = 60, ACID = 30, WOUND = 5)
cell_drain = DEFAULT_CELL_DRAIN * 0.25
cell_drain = DEFAULT_CHARGE_DRAIN * 0.25
slowdown_inactive = 1.75
slowdown_active = 1.25
skins = list(
"cosmohonk" = list(
HELMET_LAYER = NECK_LAYER,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL,
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR,
SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -515,16 +515,16 @@
slowdown_inactive = 1
slowdown_active = 0.5
ui_theme = "syndicate"
inbuilt_modules = list(/obj/item/mod/module/armor_booster)
inbuilt_modules = list()
skins = list(
"syndicate" = list(
HELMET_LAYER = NECK_LAYER,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT,
UNSEALED_CLOTHING = NONE,
SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR,
SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -553,16 +553,16 @@
slowdown_inactive = 0.75
slowdown_active = 0.25
ui_theme = "syndicate"
inbuilt_modules = list(/obj/item/mod/module/armor_booster/elite)
inbuilt_modules = list()
skins = list(
"elite" = list(
HELMET_LAYER = null,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT,
UNSEALED_CLOTHING = NONE,
SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR,
SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -597,10 +597,10 @@
"enchanted" = list(
HELMET_LAYER = null,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL,
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT,
UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -633,10 +633,10 @@
"prototype" = list(
HELMET_LAYER = null,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL,
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT,
UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -668,11 +668,11 @@
"responsory" = list(
HELMET_LAYER = NECK_LAYER,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT,
UNSEALED_CLOTHING = NONE,
SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR,
SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -691,10 +691,10 @@
"inquisitory" = list(
HELMET_LAYER = null,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL,
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT,
UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -725,11 +725,11 @@
"apocryphal" = list(
HELMET_LAYER = null,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL,
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR,
SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -761,11 +761,11 @@
"corporate" = list(
HELMET_LAYER = null,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL,
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT,
SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -797,12 +797,12 @@
"debug" = list(
HELMET_LAYER = null,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL,
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT,
SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE,
UNSEALED_COVER = HEADCOVERSMOUTH,
SEALED_COVER = HEADCOVERSEYES|PEPPERPROOF,
SEALED_COVER = HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -828,20 +828,20 @@
resistance_flags = INDESTRUCTIBLE|LAVA_PROOF|FIRE_PROOF|UNACIDABLE|ACID_PROOF
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
complexity_max = 1000
cell_drain = DEFAULT_CELL_DRAIN * 0
cell_drain = DEFAULT_CHARGE_DRAIN * 0
slowdown_inactive = 0
slowdown_active = 0
skins = list(
"debug" = list(
HELMET_LAYER = null,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL|STOPSPRESSUREDAMAGE,
UNSEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT,
SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE,
UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCKS_SHOVE_KNOCKDOWN,
UNSEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE,
SEALED_INVISIBILITY = HIDEJUMPSUIT,
),
GAUNTLETS_FLAGS = list(
+16 -21
View File
@@ -20,12 +20,12 @@
/obj/item/mod/control/pre_equipped/advanced
theme = /datum/mod_theme/advanced
cell = /obj/item/stock_parts/cell/super
initial_modules = list(/obj/item/mod/module/storage/large_capacity, /obj/item/mod/module/welding, /obj/item/mod/module/rad_protection, /obj/item/mod/module/jetpack, /obj/item/mod/module/flashlight)
initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/rad_protection, /obj/item/mod/module/flashlight)
/obj/item/mod/control/pre_equipped/mining
theme = /datum/mod_theme/mining
cell = /obj/item/stock_parts/cell/high/plus
initial_modules = list(/obj/item/mod/module/storage/large_capacity, /obj/item/mod/module/welding, /obj/item/mod/module/orebag, /obj/item/mod/module/flashlight, /obj/item/mod/module/magboot, /obj/item/mod/module/drill)
initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/orebag, /obj/item/mod/module/flashlight, /obj/item/mod/module/magboot, /obj/item/mod/module/drill)
/obj/item/mod/control/pre_equipped/medical
theme = /datum/mod_theme/medical
@@ -34,12 +34,12 @@
/obj/item/mod/control/pre_equipped/rescue
theme = /datum/mod_theme/rescue
cell = /obj/item/stock_parts/cell/super
initial_modules = list(/obj/item/mod/module/storage/large_capacity, /obj/item/mod/module/flashlight, /obj/item/mod/module/health_analyzer, /obj/item/mod/module/injector)
initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/flashlight, /obj/item/mod/module/health_analyzer, /obj/item/mod/module/injector)
/obj/item/mod/control/pre_equipped/research
theme = /datum/mod_theme/research
cell = /obj/item/stock_parts/cell/super
initial_modules = list(/obj/item/mod/module/storage/large_capacity, /obj/item/mod/module/welding, /obj/item/mod/module/flashlight, /obj/item/mod/module/circuit, /obj/item/mod/module/t_ray)
initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/flashlight, /obj/item/mod/module/t_ray)
/obj/item/mod/control/pre_equipped/security
theme = /datum/mod_theme/security
@@ -48,42 +48,37 @@
/obj/item/mod/control/pre_equipped/safeguard
theme = /datum/mod_theme/safeguard
cell = /obj/item/stock_parts/cell/super
initial_modules = list(/obj/item/mod/module/storage/large_capacity, /obj/item/mod/module/welding, /obj/item/mod/module/flashlight, /obj/item/mod/module/jetpack, /obj/item/mod/module/holster)
initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/flashlight, /obj/item/mod/module/holster)
/obj/item/mod/control/pre_equipped/magnate
theme = /datum/mod_theme/magnate
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)
initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/holster)
/obj/item/mod/control/pre_equipped/traitor
theme = /datum/mod_theme/syndicate
cell = /obj/item/stock_parts/cell/super
initial_modules = list(/obj/item/mod/module/storage/syndicate, /obj/item/mod/module/welding, /obj/item/mod/module/tether, /obj/item/mod/module/pathfinder, /obj/item/mod/module/flashlight, /obj/item/mod/module/dna_lock)
initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/flashlight, /obj/item/mod/module/dna_lock)
/obj/item/mod/control/pre_equipped/nuclear
theme = /datum/mod_theme/syndicate
cell = /obj/item/stock_parts/cell/hyper
initial_modules = list(/obj/item/mod/module/storage/syndicate, /obj/item/mod/module/welding, /obj/item/mod/module/jetpack, /obj/item/mod/module/visor/thermal, /obj/item/mod/module/flashlight, /obj/item/mod/module/holster)
initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/visor/thermal, /obj/item/mod/module/flashlight, /obj/item/mod/module/holster)
/obj/item/mod/control/pre_equipped/elite
theme = /datum/mod_theme/elite
cell = /obj/item/stock_parts/cell/bluespace
initial_modules = list(/obj/item/mod/module/storage/syndicate, /obj/item/mod/module/welding, /obj/item/mod/module/emp_shield, /obj/item/mod/module/jetpack, /obj/item/mod/module/visor/thermal, /obj/item/mod/module/flashlight, /obj/item/mod/module/holster)
/obj/item/mod/control/pre_equipped/enchanted
theme = /datum/mod_theme/enchanted
cell = /obj/item/stock_parts/cell/crystal_cell/wizard
initial_modules = list(/obj/item/mod/module/storage/large_capacity, /obj/item/mod/module/energy_shield/wizard, /obj/item/mod/module/emp_shield)
initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/emp_shield, /obj/item/mod/module/visor/thermal, /obj/item/mod/module/flashlight, /obj/item/mod/module/holster)
/obj/item/mod/control/pre_equipped/prototype
theme = /datum/mod_theme/prototype
cell = /obj/item/stock_parts/cell/high/plus
initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/rad_protection, /obj/item/mod/module/flashlight, /obj/item/mod/module/tether)
initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/rad_protection, /obj/item/mod/module/flashlight)
/obj/item/mod/control/pre_equipped/responsory
theme = /datum/mod_theme/responsory
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/emp_shield, /obj/item/mod/module/flashlight, /obj/item/mod/module/holster)
initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/emp_shield, /obj/item/mod/module/flashlight, /obj/item/mod/module/holster)
var/insignia_type = /obj/item/mod/module/insignia
/obj/item/mod/control/pre_equipped/responsory/Initialize(mapload, new_theme, new_skin)
@@ -112,7 +107,7 @@
insignia_type = /obj/item/mod/module/insignia/chaplain
/obj/item/mod/control/pre_equipped/responsory/inquisitory
initial_modules = list(/obj/item/mod/module/storage/large_capacity, /obj/item/mod/module/anti_magic, /obj/item/mod/module/welding, /obj/item/mod/module/emp_shield, /obj/item/mod/module/flashlight, /obj/item/mod/module/holster)
initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/anti_magic, /obj/item/mod/module/welding, /obj/item/mod/module/emp_shield, /obj/item/mod/module/flashlight, /obj/item/mod/module/holster)
applied_skin = "inquisitory"
/obj/item/mod/control/pre_equipped/responsory/inquisitory/commander
@@ -130,22 +125,22 @@
/obj/item/mod/control/pre_equipped/apocryphal
theme = /datum/mod_theme/apocryphal
cell = /obj/item/stock_parts/cell/bluespace
initial_modules = list(/obj/item/mod/module/storage/bluespace, /obj/item/mod/module/welding, /obj/item/mod/module/emp_shield, /obj/item/mod/module/jetpack, /obj/item/mod/module/holster)
initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/emp_shield, /obj/item/mod/module/holster)
/obj/item/mod/control/pre_equipped/corporate
theme = /datum/mod_theme/corporate
cell = /obj/item/stock_parts/cell/bluespace
initial_modules = list(/obj/item/mod/module/storage/bluespace, /obj/item/mod/module/holster)
initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/holster)
/obj/item/mod/control/pre_equipped/debug
theme = /datum/mod_theme/debug
cell = /obj/item/stock_parts/cell/bluespace
initial_modules = list(/obj/item/mod/module/storage/bluespace, /obj/item/mod/module/welding, /obj/item/mod/module/flashlight, /obj/item/mod/module/bikehorn, /obj/item/mod/module/rad_protection, /obj/item/mod/module/tether, /obj/item/mod/module/injector) //one of every type of module, for testing if they all work correctly
initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/flashlight, /obj/item/mod/module/bikehorn, /obj/item/mod/module/rad_protection, /obj/item/mod/module/injector) //one of every type of module, for testing if they all work correctly
/obj/item/mod/control/pre_equipped/administrative
theme = /datum/mod_theme/administrative
cell = /obj/item/stock_parts/cell/infinite/abductor
initial_modules = list(/obj/item/mod/module/storage/bluespace, /obj/item/mod/module/welding, /obj/item/mod/module/stealth/ninja, /obj/item/mod/module/quick_carry/advanced, /obj/item/mod/module/magboot/advanced, /obj/item/mod/module/jetpack)
initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/quick_carry/advanced, /obj/item/mod/module/magboot/advanced)
//these exist for the prefs menu
/obj/item/mod/control/pre_equipped/syndicate_empty
+1 -1
View File
@@ -54,7 +54,7 @@
. = ..()
if(.)
return
if(!allowed(usr) && locked)
if(locked && !allowed(usr))
balloon_alert(usr, "insufficient access!")
playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE)
return
+121 -17
View File
@@ -1,5 +1,6 @@
/obj/item/mod/module
name = "MOD module"
icon = 'icons/obj/clothing/modsuit/mod_modules.dmi'
icon_state = "module"
/// If it can be removed
var/removable = TRUE
@@ -10,11 +11,11 @@
/// How much space it takes up in the MOD
var/complexity = 0
/// Power use when idle
var/idle_power_cost = DEFAULT_CELL_DRAIN * 0
var/idle_power_cost = DEFAULT_CHARGE_DRAIN * 0
/// Power use when active
var/active_power_cost = DEFAULT_CELL_DRAIN * 0
var/active_power_cost = DEFAULT_CHARGE_DRAIN * 0
/// Power use when used, we call it manually
var/use_power_cost = DEFAULT_CELL_DRAIN * 0
var/use_power_cost = DEFAULT_CHARGE_DRAIN * 0
/// ID used by their TGUI
var/tgui_id
/// Linked MODsuit
@@ -27,12 +28,20 @@
var/overlay_state_active
/// Overlay given to the user when the module is used, lasts until cooldown finishes
var/overlay_state_use
/// Icon file for the overlay.
var/overlay_icon_file = 'icons/mob/clothing/modsuit/mod_modules.dmi'
/// Does the overlay use the control unit's colors?
var/use_mod_colors = FALSE
/// What modules are we incompatible with?
var/list/incompatible_modules = list()
/// Cooldown after use
var/cooldown_time = 0
/// The mouse button needed to use this module
var/used_signal
/// If we're allowed to use this module while phased out.
var/allowed_in_phaseout = FALSE
/// If we're allowed to use this module while the suit is disabled.
var/allowed_inactive = FALSE
/// Timer for the cooldown
COOLDOWN_DECLARE(cooldown_timer)
@@ -55,7 +64,7 @@
/obj/item/mod/module/examine(mob/user)
. = ..()
if(HAS_TRAIT(user, TRAIT_DIAGNOSTIC_HUD))
if(user.hud_list[DIAG_HUD] && user.client.images & user.hud_list[DIAG_HUD])
. += span_notice("Complexity level: [complexity]")
/// Called from MODsuit's install() proc, so when the module is installed.
@@ -84,7 +93,9 @@
/// Called when the module is selected from the TGUI
/obj/item/mod/module/proc/on_select()
if(!mod.active || mod.activating || module_type == MODULE_PASSIVE)
if(((!mod.active || mod.activating) && !allowed_inactive) || module_type == MODULE_PASSIVE)
if(mod.wearer)
balloon_alert(mod.wearer, "not active!")
return
if(module_type != MODULE_USABLE)
if(active)
@@ -93,7 +104,7 @@
on_activation()
else
on_use()
SEND_SIGNAL(mod, COMSIG_MOD_MODULE_SELECTED)
SEND_SIGNAL(mod, COMSIG_MOD_MODULE_SELECTED, src)
/// Called when the module is activated
/obj/item/mod/module/proc/on_activation()
@@ -103,6 +114,10 @@
if(!mod.active || mod.activating || !mod.cell?.charge)
balloon_alert(mod.wearer, "unpowered!")
return FALSE
if(!allowed_in_phaseout && istype(mod.wearer.loc, /obj/effect/dummy/phased_mob))
//specifically a to_chat because the user is phased out.
to_chat(mod.wearer, span_warning("You cannot activate this right now."))
return FALSE
if(module_type == MODULE_ACTIVE)
if(mod.selected_module && !mod.selected_module.on_deactivation())
return
@@ -115,9 +130,8 @@
balloon_alert(mod.wearer, "can't extend [device]!")
return
else
var/used_button = mod.wearer.client?.prefs.read_preference(/datum/preference/choiced/mod_select) || MIDDLE_CLICK
update_signal(used_button)
balloon_alert(mod.wearer, "[src] activated, [used_button]-click to use")
update_signal()
balloon_alert(mod.wearer, "[src] activated, alt-click to use")
active = TRUE
COOLDOWN_START(src, cooldown_timer, cooldown_time)
mod.wearer.update_inv_back()
@@ -145,6 +159,10 @@
return FALSE
if(!check_power(use_power_cost))
return FALSE
if(!allowed_in_phaseout && istype(mod.wearer.loc, /obj/effect/dummy/phased_mob))
//specifically a to_chat because the user is phased out.
to_chat(mod.wearer, span_warning("You cannot activate this right now."))
return FALSE
COOLDOWN_START(src, cooldown_timer, cooldown_time)
addtimer(CALLBACK(mod.wearer, /mob.proc/update_inv_back), cooldown_time)
mod.wearer.update_inv_back()
@@ -228,8 +246,10 @@
qdel(src)
/// Generates an icon to be used for the suit's worn overlays
/obj/item/mod/module/proc/generate_worn_overlay(mutable_appearance/standing)
/obj/item/mod/module/proc/generate_worn_overlay()
. = list()
if(!mod.active)
return
var/used_overlay
if(overlay_state_use && !COOLDOWN_FINISHED(src, cooldown_timer))
used_overlay = overlay_state_use
@@ -239,14 +259,98 @@
used_overlay = overlay_state_inactive
else
return
var/mutable_appearance/module_icon = mutable_appearance('icons/mob/mod.dmi', used_overlay, layer = standing.layer + 0.1)
var/mutable_appearance/module_icon = mutable_appearance(overlay_icon_file, used_overlay)
if(!use_mod_colors)
module_icon.appearance_flags |= RESET_COLOR
. += module_icon
/// Updates the signal used by active modules to be activated
/obj/item/mod/module/proc/update_signal(value)
switch(value)
if(MIDDLE_CLICK)
mod.selected_module.used_signal = COMSIG_MOB_MIDDLECLICKON
if(ALT_CLICK)
mod.selected_module.used_signal = COMSIG_MOB_ALTCLICKON
/obj/item/mod/module/proc/update_signal()
mod.selected_module.used_signal = COMSIG_MOB_ALTCLICKON
RegisterSignal(mod.wearer, mod.selected_module.used_signal, /obj/item/mod/module.proc/on_special_click)
/obj/item/mod/module/anomaly_locked
name = "MOD anomaly locked module"
desc = "A form of a module, locked behind an anomalous core to function."
incompatible_modules = list(/obj/item/mod/module/anomaly_locked)
/// The core item the module runs off.
var/obj/item/assembly/signaler/anomaly/core
/// Accepted types of anomaly cores.
var/list/accepted_anomalies = list(/obj/item/assembly/signaler/anomaly)
/// If this one starts with a core in.
var/prebuilt = FALSE
/obj/item/mod/module/anomaly_locked/Initialize(mapload)
. = ..()
if(!prebuilt || !length(accepted_anomalies))
return
var/core_path = pick(accepted_anomalies)
core = new core_path(src)
update_icon_state()
/obj/item/mod/module/anomaly_locked/Destroy()
QDEL_NULL(core)
return ..()
/obj/item/mod/module/anomaly_locked/examine(mob/user)
. = ..()
if(!length(accepted_anomalies))
return
if(core)
. += span_notice("There is a [core.name] installed in it. You could remove it with a <b>screwdriver</b>...")
else
var/list/core_list = list()
for(var/path in accepted_anomalies)
var/atom/core_path = path
core_list += initial(core_path.name)
. += span_notice("You need to insert \a [english_list(core_list, and_text = " or ")] for this module to function.")
/obj/item/mod/module/anomaly_locked/on_select()
if(!core)
balloon_alert(mod.wearer, "no core!")
return
return ..()
/obj/item/mod/module/anomaly_locked/on_process(delta_time)
. = ..()
if(!core)
return FALSE
/obj/item/mod/module/anomaly_locked/on_active_process(delta_time)
if(!core)
return FALSE
return TRUE
/obj/item/mod/module/anomaly_locked/attackby(obj/item/item, mob/living/user, params)
if(item.type in accepted_anomalies)
if(core)
balloon_alert(user, "core already in!")
return
if(!user.transferItemToLoc(item, src))
return
core = item
balloon_alert(user, "core installed")
playsound(src, 'sound/machines/click.ogg', 30, TRUE)
update_icon_state()
else
return ..()
/obj/item/mod/module/anomaly_locked/screwdriver_act(mob/living/user, obj/item/tool)
. = ..()
if(!core)
balloon_alert(user, "no core!")
return
balloon_alert(user, "removing core...")
if(!do_after(user, 3 SECONDS, target = src))
balloon_alert(user, "interrupted!")
return
balloon_alert(user, "core removed")
core.forceMove(drop_location())
if(Adjacent(user) && !issilicon(user))
user.put_in_hands(core)
core = null
update_icon_state()
/obj/item/mod/module/anomaly_locked/update_icon_state()
icon_state = initial(icon_state) + (core ? "-core" : "")
return ..()
+3 -259
View File
@@ -1,259 +1,3 @@
/obj/item/mod/module
name = "MOD module"
icon_state = "module"
/// If it can be removed
var/removable = TRUE
/// If it's passive, togglable, usable or active
var/module_type = MODULE_PASSIVE
/// Is the module active
var/active = FALSE
/// How much space it takes up in the MOD
var/complexity = 0
/// Power use when idle
var/idle_power_cost = DEFAULT_CELL_DRAIN * 0
/// Power use when active
var/active_power_cost = DEFAULT_CELL_DRAIN * 0
/// Power use when used, we call it manually
var/use_power_cost = DEFAULT_CELL_DRAIN * 0
/// ID used by their TGUI
var/tgui_id
/// Linked MODsuit
var/obj/item/mod/control/mod
/// If we're an active module, what item are we?
var/obj/item/device
/// Overlay given to the user when the module is inactive
var/overlay_state_inactive
/// Overlay given to the user when the module is active
var/overlay_state_active
/// Overlay given to the user when the module is used, lasts until cooldown finishes
var/overlay_state_use
/// What modules are we incompatible with?
var/list/incompatible_modules = list()
/// Cooldown after use
var/cooldown_time = 0
/// The mouse button needed to use this module
var/used_signal
/// Timer for the cooldown
COOLDOWN_DECLARE(cooldown_timer)
/obj/item/mod/module/Initialize(mapload)
. = ..()
if(module_type != MODULE_ACTIVE)
return
if(ispath(device))
device = new device(src)
ADD_TRAIT(device, TRAIT_NODROP, MOD_TRAIT)
RegisterSignal(device, COMSIG_PARENT_PREQDELETED, .proc/on_device_deletion)
RegisterSignal(src, COMSIG_ATOM_EXITED, .proc/on_exit)
/obj/item/mod/module/Destroy()
mod?.uninstall(src)
if(device)
UnregisterSignal(device, COMSIG_PARENT_PREQDELETED)
QDEL_NULL(device)
return ..()
/obj/item/mod/module/examine(mob/user)
. = ..()
if(HAS_TRAIT(user, TRAIT_DIAGNOSTIC_HUD))
. += span_notice("Complexity level: [complexity]")
/// Called from MODsuit's install() proc, so when the module is installed.
/obj/item/mod/module/proc/on_install()
return
/// Called from MODsuit's uninstall() proc, so when the module is uninstalled.
/obj/item/mod/module/proc/on_uninstall()
return
/// Called when the MODsuit is activated
/obj/item/mod/module/proc/on_suit_activation()
return
/// Called when the MODsuit is deactivated
/obj/item/mod/module/proc/on_suit_deactivation()
return
/// Called when the MODsuit is equipped
/obj/item/mod/module/proc/on_equip()
return
/// Called when the MODsuit is unequipped
/obj/item/mod/module/proc/on_unequip()
return
/// Called when the module is selected from the TGUI
/obj/item/mod/module/proc/on_select()
if(!mod.active || mod.activating || module_type == MODULE_PASSIVE)
return
if(module_type != MODULE_USABLE)
if(active)
on_deactivation()
else
on_activation()
else
on_use()
SEND_SIGNAL(mod, COMSIG_MOD_MODULE_SELECTED)
/// Called when the module is activated
/obj/item/mod/module/proc/on_activation()
if(!COOLDOWN_FINISHED(src, cooldown_timer))
balloon_alert(mod.wearer, "on cooldown!")
return FALSE
if(!mod.active || mod.activating || !mod.cell?.charge)
balloon_alert(mod.wearer, "unpowered!")
return FALSE
if(module_type == MODULE_ACTIVE)
if(mod.selected_module && !mod.selected_module.on_deactivation())
return
mod.selected_module = src
if(device)
if(mod.wearer.put_in_hands(device))
balloon_alert(mod.wearer, "[device] extended")
RegisterSignal(mod.wearer, COMSIG_ATOM_EXITED, .proc/on_exit)
else
balloon_alert(mod.wearer, "can't extend [device]!")
return
else
var/used_button = mod.wearer.client?.prefs.read_preference(/datum/preference/choiced/mod_select) || MIDDLE_CLICK
update_signal(used_button)
balloon_alert(mod.wearer, "[src] activated, [used_button]-click to use")
active = TRUE
COOLDOWN_START(src, cooldown_timer, cooldown_time)
mod.wearer.update_inv_back()
return TRUE
/// Called when the module is deactivated
/obj/item/mod/module/proc/on_deactivation()
active = FALSE
if(module_type == MODULE_ACTIVE)
mod.selected_module = null
if(device)
mod.wearer.transferItemToLoc(device, src, TRUE)
balloon_alert(mod.wearer, "[device] retracted")
UnregisterSignal(mod.wearer, COMSIG_ATOM_EXITED)
else
balloon_alert(mod.wearer, "[src] deactivated")
UnregisterSignal(mod.wearer, used_signal)
used_signal = null
mod.wearer.update_inv_back()
return TRUE
/// Called when the module is used
/obj/item/mod/module/proc/on_use()
if(!COOLDOWN_FINISHED(src, cooldown_timer))
return FALSE
if(!check_power(use_power_cost))
return FALSE
COOLDOWN_START(src, cooldown_timer, cooldown_time)
addtimer(CALLBACK(mod.wearer, /mob.proc/update_inv_back), cooldown_time)
mod.wearer.update_inv_back()
return TRUE
/// Called when an activated module without a device is used
/obj/item/mod/module/proc/on_select_use(atom/target)
mod.wearer.face_atom(target)
if(!on_use())
return FALSE
return TRUE
/// Called when an activated module without a device is active and the user alt/middle-clicks
/obj/item/mod/module/proc/on_special_click(mob/source, atom/target)
SIGNAL_HANDLER
on_select_use(target)
return COMSIG_MOB_CANCEL_CLICKON
/// Called on the MODsuit's process
/obj/item/mod/module/proc/on_process(delta_time)
if(active)
if(!drain_power(active_power_cost * delta_time))
on_deactivation()
return FALSE
on_active_process(delta_time)
else
drain_power(idle_power_cost * delta_time)
return TRUE
/// Called on the MODsuit's process if it is an active module
/obj/item/mod/module/proc/on_active_process(delta_time)
return
/// Drains power from the suit cell
/obj/item/mod/module/proc/drain_power(amount)
if(!check_power(amount))
return FALSE
mod.cell.charge = max(0, mod.cell.charge - amount)
return TRUE
/obj/item/mod/module/proc/check_power(amount)
if(!mod.cell || (mod.cell.charge < amount))
return FALSE
return TRUE
/// Adds additional things to the MODsuit ui_data()
/obj/item/mod/module/proc/add_ui_data()
return list()
/// Creates a list of configuring options for this module
/obj/item/mod/module/proc/get_configuration()
return list()
/// Generates an element of the get_configuration list with a display name, type and value
/obj/item/mod/module/proc/add_ui_configuration(display_name, type, value, list/values)
return list("display_name" = display_name, "type" = type, "value" = value, "values" = values)
/// Receives configure edits from the TGUI and edits the vars
/obj/item/mod/module/proc/configure_edit(key, value)
return
/// Called when the device moves to a different place on active modules
/obj/item/mod/module/proc/on_exit(datum/source, atom/movable/part, direction)
SIGNAL_HANDLER
if(!active)
return
if(part.loc == src)
return
if(part.loc == mod.wearer)
return
if(part == device)
on_deactivation()
/// Called when the device gets deleted on active modules
/obj/item/mod/module/proc/on_device_deletion(datum/source)
SIGNAL_HANDLER
if(source == device)
device = null
qdel(src)
/// Generates an icon to be used for the suit's worn overlays
/obj/item/mod/module/proc/generate_worn_overlay(mutable_appearance/standing)
. = list()
var/used_overlay
if(overlay_state_use && !COOLDOWN_FINISHED(src, cooldown_timer))
used_overlay = overlay_state_use
else if(overlay_state_active && active)
used_overlay = overlay_state_active
else if(overlay_state_inactive)
used_overlay = overlay_state_inactive
else
return
var/mutable_appearance/module_icon = mutable_appearance('icons/mob/mod.dmi', used_overlay, layer = standing.layer + 0.1)
. += module_icon
/// Updates the signal used by active modules to be activated
/obj/item/mod/module/proc/update_signal(value)
switch(value)
if(MIDDLE_CLICK)
mod.selected_module.used_signal = COMSIG_MOB_MIDDLECLICKON
if(ALT_CLICK)
mod.selected_module.used_signal = COMSIG_MOB_ALTCLICKON
RegisterSignal(mod.wearer, mod.selected_module.used_signal, /obj/item/mod/module.proc/on_special_click)
icon_state = "magic_nullifier"
removable = FALSE
incompatible_modules = list(/obj/item/mod/module/anti_magic)
/obj/item/mod/module/anti_magic/on_suit_activation()
ADD_TRAIT(mod.wearer, TRAIT_ANTIMAGIC, MOD_TRAIT)
ADD_TRAIT(mod.wearer, TRAIT_HOLY, MOD_TRAIT)
@@ -288,8 +32,8 @@
module_type = MODULE_TOGGLE
// complexity = 3
complexity = 0
active_power_cost = DEFAULT_CELL_DRAIN*0.75
// use_power_cost = DEFAULT_CELL_DRAIN*3
active_power_cost = DEFAULT_CHARGE_DRAIN*0.75
// use_power_cost = DEFAULT_CHARGE_DRAIN*3
removable = FALSE
incompatible_modules = list(/obj/item/mod/module/kinesis)
cooldown_time = 0.5 SECONDS
@@ -324,7 +68,7 @@
incompatible_modules = list(/obj/item/mod/module/insignia)
overlay_state_inactive = "insignia"
/obj/item/mod/module/insignia/generate_worn_overlay(mutable_appearance/standing)
/obj/item/mod/module/insignia/generate_worn_overlay()
overlay_state_inactive = "[initial(overlay_state_inactive)]-[mod.skin]"
. = ..()
for(var/mutable_appearance/appearance as anything in .)
@@ -0,0 +1,154 @@
//Engineering modules for MODsuits
///Welding Protection - Makes the helmet protect from flashes and welding.
/obj/item/mod/module/welding
name = "MOD welding protection module"
desc = "A module installed into the visor of the suit, this projects a \
polarized, holographic overlay in front of the user's eyes. It's rated high enough for \
immunity against extremities such as spot and arc welding, solar eclipses, and handheld flashlights."
icon_state = "welding"
complexity = 1
incompatible_modules = list(/obj/item/mod/module/welding)
overlay_state_inactive = "module_welding"
/obj/item/mod/module/welding/on_suit_activation()
mod.helmet.flash_protect = 2
/obj/item/mod/module/welding/on_suit_deactivation(deleting = FALSE)
if(deleting)
return
mod.helmet.flash_protect = initial(mod.helmet.flash_protect)
///T-Ray Scan - Scans the terrain for undertile objects.
/obj/item/mod/module/t_ray
name = "MOD t-ray scan module"
desc = "A module installed into the visor of the suit, allowing the user to use a pulse of terahertz radiation \
to essentially echolocate things beneath the floor, mostly cables and pipes. \
A staple of atmospherics work, and counter-smuggling work."
icon_state = "tray"
module_type = MODULE_TOGGLE
complexity = 1
active_power_cost = DEFAULT_CHARGE_DRAIN * 0.5
incompatible_modules = list(/obj/item/mod/module/t_ray)
cooldown_time = 0.5 SECONDS
/// T-ray scan range.
var/range = 4
/obj/item/mod/module/t_ray/on_active_process(delta_time)
t_ray_scan(mod.wearer, 0.8 SECONDS, range)
///Magnetic Stability - Gives the user a slowdown but makes them negate gravity and be immune to slips.
/obj/item/mod/module/magboot
name = "MOD magnetic stability module"
desc = "These are powerful electromagnets fitted into the suit's boots, allowing users both \
excellent traction no matter the condition indoors, and to essentially hitch a ride on the exterior of a hull. \
However, these basic models do not feature computerized systems to automatically toggle them on and off, \
so numerous users report a certain stickiness to their steps."
icon_state = "magnet"
module_type = MODULE_TOGGLE
complexity = 2
active_power_cost = DEFAULT_CHARGE_DRAIN * 0.5
incompatible_modules = list(/obj/item/mod/module/magboot)
cooldown_time = 0.5 SECONDS
/// Slowdown added onto the suit.
var/slowdown_active = 0.5
/obj/item/mod/module/magboot/on_activation()
. = ..()
if(!.)
return
ADD_TRAIT(mod.wearer, TRAIT_NEGATES_GRAVITY, MOD_TRAIT)
ADD_TRAIT(mod.wearer, TRAIT_NOSLIPWATER, MOD_TRAIT)
mod.slowdown += slowdown_active
mod.wearer.update_gravity(mod.wearer.has_gravity())
mod.wearer.update_equipment_speed_mods()
/obj/item/mod/module/magboot/on_deactivation(display_message = TRUE, deleting = FALSE)
. = ..()
if(!.)
return
REMOVE_TRAIT(mod.wearer, TRAIT_NEGATES_GRAVITY, MOD_TRAIT)
REMOVE_TRAIT(mod.wearer, TRAIT_NOSLIPWATER, MOD_TRAIT)
mod.slowdown -= slowdown_active
mod.wearer.update_gravity(mod.wearer.has_gravity())
mod.wearer.update_equipment_speed_mods()
/obj/item/mod/module/magboot/advanced
name = "MOD advanced magnetic stability module"
removable = FALSE
complexity = 0
slowdown_active = 0
// No tether module, sorry!
///Radiation Protection - Protects the user from radiation, gives them a geiger counter and rad info in the panel.
/obj/item/mod/module/rad_protection
name = "MOD radiation protection module"
desc = "A module utilizing polymers and reflective shielding to protect the user against ionizing radiation."
icon_state = "radshield"
complexity = 2
idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.3
incompatible_modules = list(/obj/item/mod/module/rad_protection)
/obj/item/mod/module/rad_protection/on_suit_activation()
for(var/obj/item/part in mod.mod_parts)
armor[RAD] = 65
rad_flags = RAD_PROTECT_CONTENTS|RAD_NO_CONTAMINATE
/obj/item/mod/module/rad_protection/on_suit_deactivation(deleting = FALSE)
for(var/obj/item/part in mod.mod_parts)
armor[RAD] = 0
rad_flags = NONE
///Constructor - Lets you build quicker and create RCD holograms.
/obj/item/mod/module/constructor
name = "MOD constructor module"
desc = "This module entirely occupies the wearer's forearm, notably causing conflict with \
advanced arm servos meant to carry crewmembers. However, it contains the \
latest engineering schematics combined with inbuilt memory to help the user build walls."
icon_state = "constructor"
module_type = MODULE_USABLE
complexity = 2
idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.2
use_power_cost = DEFAULT_CHARGE_DRAIN * 2
incompatible_modules = list(/obj/item/mod/module/constructor, /obj/item/mod/module/quick_carry)
cooldown_time = 11 SECONDS
/obj/item/mod/module/constructor/on_suit_activation()
ADD_TRAIT(mod.wearer, TRAIT_QUICK_BUILD, MOD_TRAIT)
/obj/item/mod/module/constructor/on_suit_deactivation(deleting = FALSE)
REMOVE_TRAIT(mod.wearer, TRAIT_QUICK_BUILD, MOD_TRAIT)
///Mister - Sprays water over an area.
/obj/item/mod/module/mister
name = "MOD water mister module"
desc = "A module containing a mister, able to spray it over areas."
icon_state = "mister"
module_type = MODULE_ACTIVE
complexity = 2
active_power_cost = DEFAULT_CHARGE_DRAIN * 0.3
device = /obj/item/reagent_containers/spray/mister
incompatible_modules = list(/obj/item/mod/module/mister)
cooldown_time = 0.5 SECONDS
/// Volume of our reagent holder.
var/volume = 500
/obj/item/mod/module/mister/Initialize(mapload)
create_reagents(volume, OPENCONTAINER)
return ..()
///Resin Mister - Sprays resin over an area.
/obj/item/mod/module/mister/atmos
name = "MOD resin mister module"
desc = "An atmospheric resin mister, able to fix up areas quickly."
device = /obj/item/extinguisher/mini/nozzle/mod
volume = 250
/obj/item/mod/module/mister/atmos/Initialize(mapload)
. = ..()
reagents.add_reagent(/datum/reagent/water, volume)
/obj/item/extinguisher/mini/nozzle/mod
name = "MOD atmospheric mister"
desc = "An atmospheric resin mister with three modes, mounted as a module."
+339
View File
@@ -0,0 +1,339 @@
//General modules for MODsuits
///Storage - Adds a storage component to the suit.
/obj/item/mod/module/storage
name = "MOD storage containment module"
desc = "What amounts to a series of integrated storage compartments and specialized pockets installed across \
the surface of the suit, useful for storing various bits, and or bobs."
icon_state = "storage"
complexity = 3
incompatible_modules = list(/obj/item/mod/module/storage)
module_type = MODULE_USABLE
cooldown_time = 0.5 SECONDS
allowed_inactive = TRUE
/// Bag we have stored.
var/obj/item/storage/backpack/stored
/obj/item/mod/module/storage/attackby(obj/item/I, mob/user, params)
if(!istype(I, /obj/item/storage/backpack))
return ..()
var/obj/item/storage/backpack/B = I
if(stored)
balloon_alert(user, "backpack already installed!")
return
if(!user.transferItemToLoc(B, src))
return
stored = B
balloon_alert(user, "backpack installed")
playsound(src, 'sound/machines/click.ogg', 30, TRUE)
/obj/item/mod/module/storage/screwdriver_act(mob/living/user, obj/item/tool)
. = ..()
if(!stored)
balloon_alert(user, "no backpack!")
return
balloon_alert(user, "removing backpack...")
if(!do_after(user, 3 SECONDS, target = src))
balloon_alert(user, "interrupted!")
return
balloon_alert(user, "backpack removed")
stored.forceMove(drop_location())
if(Adjacent(user) && !issilicon(user))
user.put_in_hands(stored)
stored = null
/obj/item/mod/module/storage/on_use()
. = ..()
if(!.)
return
if(!stored)
var/obj/item/storage/backpack/holding = mod.wearer.get_active_held_item()
if(!holding)
balloon_alert(mod.wearer, "no backpack installed!")
return
if(mod.wearer.transferItemToLoc(holding, src, force = FALSE, silent = TRUE))
stored = holding
balloon_alert(mod.wearer, "backpack stored")
playsound(src, 'sound/weapons/revolverempty.ogg', 100, TRUE)
else if(mod.wearer.put_in_active_hand(stored, forced = FALSE, ignore_animation = TRUE))
balloon_alert(mod.wearer, "backpack retrieved")
playsound(src, 'sound/weapons/revolverempty.ogg', 100, TRUE)
else
balloon_alert(mod.wearer, "backpack storage full!")
/obj/item/mod/module/storage/Exited(atom/movable/gone, direction)
. = ..()
if(gone == stored)
stored = null
/obj/item/mod/module/storage/Destroy()
QDEL_NULL(stored)
return ..()
/// No Ion Jetpack
///Eating Apparatus - Lets the user eat/drink with the suit on.
/obj/item/mod/module/mouthhole
name = "MOD eating apparatus module"
desc = "A favorite by Miners, this modification to the helmet utilizes a nanotechnology barrier infront of the mouth \
to allow eating and drinking while retaining protection and atmosphere. However, it won't free you from masks, \
lets pepper spray pass through and it will do nothing to improve the taste of a goliath steak."
icon_state = "apparatus"
complexity = 1
incompatible_modules = list(/obj/item/mod/module/mouthhole)
overlay_state_inactive = "module_apparatus"
/// Former flags of the helmet.
var/former_flags = NONE
/// Former visor flags of the helmet.
var/former_visor_flags = NONE
/obj/item/mod/module/mouthhole/on_install()
former_flags = mod.helmet.flags_cover
former_visor_flags = mod.helmet.visor_flags_cover
mod.helmet.flags_cover &= ~HEADCOVERSMOUTH
mod.helmet.visor_flags_cover &= ~HEADCOVERSMOUTH
/obj/item/mod/module/mouthhole/on_uninstall(deleting = FALSE)
if(deleting)
return
mod.helmet.flags_cover |= former_flags
mod.helmet.visor_flags_cover |= former_visor_flags
///EMP Shield - Protects the suit from EMPs.
/obj/item/mod/module/emp_shield
name = "MOD EMP shield module"
desc = "A field inhibitor installed into the suit, protecting it against feedback such as \
electromagnetic pulses that would otherwise damage the electronic systems of the suit or it's modules. \
However, it will take from the suit's power to do so."
icon_state = "empshield"
complexity = 1
idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.3
incompatible_modules = list(/obj/item/mod/module/emp_shield)
/obj/item/mod/module/emp_shield/on_install()
mod.AddElement(/datum/element/empprotection, EMP_PROTECT_SELF|EMP_PROTECT_WIRES|EMP_PROTECT_CONTENTS)
/obj/item/mod/module/emp_shield/on_uninstall(deleting = FALSE)
mod.RemoveElement(/datum/element/empprotection, EMP_PROTECT_SELF|EMP_PROTECT_WIRES|EMP_PROTECT_CONTENTS)
/obj/item/mod/module/emp_shield/advanced
name = "MOD advanced EMP shield module"
desc = "An advanced field inhibitor installed into the suit, protecting it against feedback such as \
electromagnetic pulses that would otherwise damage the electronic systems of the suit or electronic devices on the wearer, \
including augmentations. However, it will take from the suit's power to do so."
complexity = 2
/obj/item/mod/module/emp_shield/advanced/on_suit_activation()
mod.wearer.AddElement(/datum/element/empprotection, EMP_PROTECT_SELF|EMP_PROTECT_CONTENTS)
/obj/item/mod/module/emp_shield/advanced/on_suit_deactivation(deleting)
mod.wearer.RemoveElement(/datum/element/empprotection, EMP_PROTECT_SELF|EMP_PROTECT_CONTENTS)
///Flashlight - Gives the suit a customizable flashlight.
/obj/item/mod/module/flashlight
name = "MOD flashlight module"
desc = "A simple pair of configurable flashlights installed on the left and right sides of the helmet, \
useful for providing light in a variety of ranges and colors. \
Some survivalists prefer the color green for their illumination, for reasons unknown."
icon_state = "flashlight"
module_type = MODULE_TOGGLE
complexity = 1
active_power_cost = DEFAULT_CHARGE_DRAIN * 0.3
incompatible_modules = list(/obj/item/mod/module/flashlight)
cooldown_time = 0.5 SECONDS
overlay_state_inactive = "module_light"
light_color = COLOR_WHITE
light_range = 4
light_power = 1
/// Charge drain per range amount.
var/base_power = DEFAULT_CHARGE_DRAIN * 0.1
/// Minimum range we can set.
var/min_range = 2
/// Maximum range we can set.
var/max_range = 5
/obj/item/mod/module/flashlight/on_activation()
. = ..()
if(!.)
return
mod.set_light(light_range, light_power, light_color)
active_power_cost = base_power * light_range
/obj/item/mod/module/flashlight/on_deactivation(display_message = TRUE, deleting = FALSE)
. = ..()
if(!.)
return
mod.set_light(0, 0)
/obj/item/mod/module/flashlight/on_process(delta_time)
active_power_cost = base_power * light_range
return ..()
/obj/item/mod/module/flashlight/generate_worn_overlay()
. = ..()
if(!active)
return
var/mutable_appearance/light_icon = mutable_appearance(overlay_icon_file, "module_light_on")
light_icon.appearance_flags = RESET_COLOR
light_icon.color = light_color
. += light_icon
/obj/item/mod/module/flashlight/get_configuration()
. = ..()
.["light_color"] = add_ui_configuration("Light Color", "color", light_color)
.["light_range"] = add_ui_configuration("Light Range", "number", light_range)
/obj/item/mod/module/flashlight/configure_edit(key, value)
switch(key)
if("light_color")
value = input(usr, "Pick new light color", "Flashlight Color") as color|null
if(!value)
return
var/list/hsl = rgb2hsl(hex2num(copytext(value,2,4)),hex2num(copytext(value,4,6)),hex2num(copytext(value,6,8)))
if(hsl[3] < 0.5)
balloon_alert(mod.wearer, "too dark!")
return
mod.set_light_color(value)
mod.wearer.regenerate_icons()
light_color = value
if("light_range")
mod.set_light_range(clamp(value, min_range, max_range))
light_range = clamp(value, min_range, max_range)
///Dispenser - Dispenses an item after a time passes.
/obj/item/mod/module/dispenser
name = "MOD burger dispenser module"
desc = "A rare piece of technology reverse-engineered from a prototype found in a Donk Corporation vessel. \
This can draw incredible amounts of power from the suit's charge to create edible organic matter in the \
palm of the wearer's glove; however, research seemed to have entirely stopped at burgers. \
Notably, all attempts to get it to dispense Earl Grey tea have failed."
icon_state = "dispenser"
module_type = MODULE_USABLE
complexity = 3
use_power_cost = DEFAULT_CHARGE_DRAIN * 2
incompatible_modules = list(/obj/item/mod/module/dispenser)
cooldown_time = 5 SECONDS
/// Path we dispense.
var/dispense_type = /obj/item/reagent_containers/food/snacks/burger/plain
/// Time it takes for us to dispense.
var/dispense_time = 0 SECONDS
/obj/item/mod/module/dispenser/on_use()
. = ..()
if(!.)
return
if(dispense_time && !do_after(mod.wearer, dispense_time, target = mod))
balloon_alert(mod.wearer, "interrupted!")
return FALSE
var/obj/item/dispensed = new dispense_type(mod.wearer.loc)
mod.wearer.put_in_hands(dispensed)
balloon_alert(mod.wearer, "[dispensed] dispensed")
playsound(src, 'sound/machines/click.ogg', 100, TRUE)
drain_power(use_power_cost)
return dispensed
///Longfall - Nullifies fall damage, removing charge instead.
/obj/item/mod/module/longfall
name = "MOD longfall module"
desc = "Useful for protecting both the suit and the wearer, \
utilizing commonplace systems to convert the possible damage from a fall into kinetic charge, \
as well as internal gyroscopes to ensure the user's safe falling. \
Useful for mining, monorail tracks, or even skydiving!"
icon_state = "longfall"
complexity = 1
use_power_cost = DEFAULT_CHARGE_DRAIN * 5
incompatible_modules = list(/obj/item/mod/module/longfall)
/obj/item/mod/module/longfall/on_suit_activation()
RegisterSignal(mod.wearer, COMSIG_LIVING_Z_IMPACT, .proc/z_impact_react)
/obj/item/mod/module/longfall/on_suit_deactivation(deleting = FALSE)
UnregisterSignal(mod.wearer, COMSIG_LIVING_Z_IMPACT)
/obj/item/mod/module/longfall/proc/z_impact_react(datum/source, levels, turf/fell_on)
if(!drain_power(use_power_cost*levels))
return
new /obj/effect/temp_visual/mook_dust(fell_on)
mod.wearer.Stun(levels * 1 SECONDS)
to_chat(mod.wearer, span_notice("[src] protects you from the damage!"))
return NO_Z_IMPACT_DAMAGE
///Thermal Regulator - Naw.
///DNA Lock - Prevents people without the set DNA from activating the suit.
/obj/item/mod/module/dna_lock
name = "MOD DNA lock module"
desc = "A module which engages with the various locks and seals tied to the suit's systems, \
enabling it to only be worn by someone corresponding with the user's exact DNA profile; \
however, this incredibly sensitive module is shorted out by EMPs. Luckily, cloning has been outlawed."
icon_state = "dnalock"
module_type = MODULE_USABLE
complexity = 2
use_power_cost = DEFAULT_CHARGE_DRAIN * 3
incompatible_modules = list(/obj/item/mod/module/dna_lock)
cooldown_time = 0.5 SECONDS
/// The DNA we lock with.
var/dna = null
/obj/item/mod/module/dna_lock/on_install()
RegisterSignal(mod, COMSIG_MOD_ACTIVATE, .proc/on_mod_activation)
RegisterSignal(mod, COMSIG_MOD_MODULE_REMOVAL, .proc/on_mod_removal)
RegisterSignal(mod, COMSIG_ATOM_EMP_ACT, .proc/on_emp)
RegisterSignal(mod, COMSIG_ATOM_EMAG_ACT, .proc/on_emag)
/obj/item/mod/module/dna_lock/on_uninstall(deleting = FALSE)
UnregisterSignal(mod, COMSIG_MOD_ACTIVATE)
UnregisterSignal(mod, COMSIG_MOD_MODULE_REMOVAL)
UnregisterSignal(mod, COMSIG_ATOM_EMP_ACT)
UnregisterSignal(mod, COMSIG_ATOM_EMAG_ACT)
/obj/item/mod/module/dna_lock/on_use()
. = ..()
if(!.)
return
dna = mod.wearer.dna.unique_enzymes
balloon_alert(mod.wearer, "dna updated")
drain_power(use_power_cost)
/obj/item/mod/module/dna_lock/emp_act(severity)
. = ..()
if(. & EMP_PROTECT_SELF)
return
on_emp(src, severity)
/obj/item/mod/module/dna_lock/emag_act(mob/user, obj/item/card/emag/emag_card)
. = ..()
on_emag(src, user, emag_card)
/obj/item/mod/module/dna_lock/proc/dna_check(mob/user)
if(!iscarbon(user))
return FALSE
var/mob/living/carbon/carbon_user = user
if(!dna || (carbon_user.has_dna() && carbon_user.dna.unique_enzymes == dna))
return TRUE
balloon_alert(user, "dna locked!")
return FALSE
/obj/item/mod/module/dna_lock/proc/on_emp(datum/source, severity)
SIGNAL_HANDLER
dna = null
/obj/item/mod/module/dna_lock/proc/on_emag(datum/source, mob/user, obj/item/card/emag/emag_card)
SIGNAL_HANDLER
dna = null
/obj/item/mod/module/dna_lock/proc/on_mod_activation(datum/source, mob/user)
SIGNAL_HANDLER
if(!dna_check(user))
return MOD_CANCEL_ACTIVATE
/obj/item/mod/module/dna_lock/proc/on_mod_removal(datum/source, mob/user)
SIGNAL_HANDLER
if(!dna_check(user))
return MOD_CANCEL_REMOVAL
///Sign Language Translator - I want, but no
+101
View File
@@ -0,0 +1,101 @@
//Maint modules for MODsuits
///Springlock Mechanism - Nope
///Rave Visor - Pointless
///Tanner - Maybe another time
///Balloon Blower - Blows a balloon.
/obj/item/mod/module/balloon
name = "MOD balloon blower module"
desc = "A strange module invented years ago by some ingenious mimes. It blows balloons."
icon_state = "bloon"
module_type = MODULE_USABLE
complexity = 1
use_power_cost = DEFAULT_CHARGE_DRAIN * 0.5
incompatible_modules = list(/obj/item/mod/module/balloon)
cooldown_time = 15 SECONDS
/obj/item/mod/module/balloon/on_use()
. = ..()
if(!.)
return
if(!do_after(mod.wearer, 10 SECONDS, target = mod))
return FALSE
mod.wearer.adjustOxyLoss(20)
playsound(src, 'sound/items/modsuit/inflate_bloon.ogg', 50, TRUE)
var/obj/item/toy/balloon/balloon = new(get_turf(src))
mod.wearer.put_in_hands(balloon)
drain_power(use_power_cost)
///Paper Dispenser - Dispenses (sometimes burning) paper sheets.
/obj/item/mod/module/paper_dispenser
name = "MOD paper dispenser module"
desc = "A simple module designed by the bureaucrats of Torch Bay. \
It dispenses 'warm, clean, and crisp sheets of paper' onto a nearby table. Usually."
icon_state = "paper_maker"
module_type = MODULE_USABLE
complexity = 1
use_power_cost = DEFAULT_CHARGE_DRAIN * 0.5
incompatible_modules = list(/obj/item/mod/module/paper_dispenser)
cooldown_time = 5 SECONDS
/// The total number of sheets created by this MOD. The more sheets, them more likely they set on fire.
var/num_sheets_dispensed = 0
/obj/item/mod/module/paper_dispenser/on_use()
. = ..()
if(!.)
return
if(!do_after(mod.wearer, 1 SECONDS, target = mod))
return FALSE
var/obj/item/paper/crisp_paper = new(get_turf(src))
crisp_paper.desc = "It's crisp and warm to the touch. Must be fresh."
var/obj/structure/table/nearby_table = locate() in range(1, mod.wearer)
playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE)
balloon_alert(mod.wearer, "dispensed paper[nearby_table ? " onto table":""]")
mod.wearer.put_in_hands(crisp_paper)
if(nearby_table)
mod.wearer.transferItemToLoc(crisp_paper, nearby_table.drop_location(), silent = FALSE)
// Up to a 30% chance to set the sheet on fire, +2% per sheet made
if(prob(min(num_sheets_dispensed * 2, 30)))
if(crisp_paper in mod.wearer.held_items)
mod.wearer.dropItemToGround(crisp_paper, force = TRUE)
crisp_paper.balloon_alert(mod.wearer, "PC LOAD LETTER!")
crisp_paper.visible_message(span_warning("[crisp_paper] bursts into flames, it's too crisp!"))
crisp_paper.fire_act(1000, 100)
drain_power(use_power_cost)
num_sheets_dispensed++
///Stamper - Extends a stamp that can switch between accept/deny modes.
/obj/item/mod/module/stamp
name = "MOD stamper module"
desc = "A module installed into the wrist of the suit, this functions as a high-power stamp, \
able to switch between accept and deny modes."
icon_state = "stamp"
module_type = MODULE_ACTIVE
complexity = 1
active_power_cost = DEFAULT_CHARGE_DRAIN * 0.3
device = /obj/item/stamp/mod
incompatible_modules = list(/obj/item/mod/module/stamp)
cooldown_time = 0.5 SECONDS
/obj/item/stamp/mod
name = "MOD electronic stamp"
desc = "A high-power stamp, able to switch between accept and deny mode when used."
/obj/item/stamp/mod/attack_self(mob/user, modifiers)
. = ..()
if(icon_state == "stamp-ok")
icon_state = "stamp-deny"
else
icon_state = "stamp-ok"
balloon_alert(user, "switched mode")
///Atrocinator - Perhaps another time
+208
View File
@@ -0,0 +1,208 @@
//Medical modules for MODsuits
#define HEALTH_SCAN "Health"
#define WOUND_SCAN "Wound"
#define CHEM_SCAN "Chemical"
///Health Analyzer - Gives the user a ranged health analyzer and their health status in the panel.
/obj/item/mod/module/health_analyzer
name = "MOD health analyzer module"
desc = "A module installed into the glove of the suit. This is a high-tech biological scanning suite, \
allowing the user indepth information on the vitals and injuries of others even at a distance, \
all with the flick of the wrist. Data is displayed in a convenient package on HUD in the helmet, \
but it's up to you to do something with it."
icon_state = "health"
module_type = MODULE_ACTIVE
complexity = 2
use_power_cost = DEFAULT_CHARGE_DRAIN
incompatible_modules = list(/obj/item/mod/module/health_analyzer)
cooldown_time = 0.5 SECONDS
tgui_id = "health_analyzer"
/// Scanning mode, changes how we scan something.
var/mode = HEALTH_SCAN
/// List of all scanning modes.
var/static/list/modes = list(HEALTH_SCAN, WOUND_SCAN, CHEM_SCAN)
/obj/item/mod/module/health_analyzer/add_ui_data()
. = ..()
.["userhealth"] = mod.wearer?.health || 0
.["usermaxhealth"] = mod.wearer?.getMaxHealth() || 0
.["userbrute"] = mod.wearer?.getBruteLoss() || 0
.["userburn"] = mod.wearer?.getFireLoss() || 0
.["usertoxin"] = mod.wearer?.getToxLoss() || 0
.["useroxy"] = mod.wearer?.getOxyLoss() || 0
/obj/item/mod/module/health_analyzer/on_select_use(atom/target)
. = ..()
if(!.)
return
if(!isliving(target) || !mod.wearer.can_read(src))
return
switch(mode)
if(HEALTH_SCAN)
healthscan(mod.wearer, target)
if(WOUND_SCAN)
woundscan(mod.wearer, target)
if(CHEM_SCAN)
chemscan(mod.wearer, target)
drain_power(use_power_cost)
/obj/item/mod/module/health_analyzer/get_configuration()
. = ..()
.["mode"] = add_ui_configuration("Scan Mode", "list", mode, modes)
/obj/item/mod/module/health_analyzer/configure_edit(key, value)
switch(key)
if("mode")
mode = value
#undef HEALTH_SCAN
#undef WOUND_SCAN
#undef CHEM_SCAN
///Quick Carry - Lets the user carry bodies quicker.
/obj/item/mod/module/quick_carry
name = "MOD quick carry module"
desc = "A suite of advanced servos, redirecting power from the suit's arms to help carry the wounded; \
or simply for fun. However, Nanotrasen has locked the module's ability to assist in hand-to-hand combat."
icon_state = "carry"
complexity = 1
idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.3
incompatible_modules = list(/obj/item/mod/module/quick_carry, /obj/item/mod/module/constructor)
/obj/item/mod/module/quick_carry/on_suit_activation()
ADD_TRAIT(mod.wearer, TRAIT_QUICKER_CARRY, MOD_TRAIT)
/obj/item/mod/module/quick_carry/on_suit_deactivation(deleting = FALSE)
REMOVE_TRAIT(mod.wearer, TRAIT_QUICKER_CARRY, MOD_TRAIT)
/obj/item/mod/module/quick_carry/advanced
name = "MOD advanced quick carry module"
removable = FALSE
complexity = 0
///Injector - Gives the suit an extendable large-capacity piercing syringe.
/obj/item/mod/module/injector
name = "MOD injector module"
desc = "A module installed into the wrist of the suit, this functions as a high-capacity syringe, \
with a tip fine enough to locate the emergency injection ports on any suit of armor, \
penetrating it with ease. Even yours."
icon_state = "injector"
module_type = MODULE_ACTIVE
complexity = 1
active_power_cost = DEFAULT_CHARGE_DRAIN * 0.3
device = /obj/item/reagent_containers/syringe/mod
incompatible_modules = list(/obj/item/mod/module/injector)
cooldown_time = 0.5 SECONDS
/obj/item/reagent_containers/syringe/mod
name = "MOD injector syringe"
desc = "A high-capacity syringe, with a tip fine enough to locate \
the emergency injection ports on any suit of armor, penetrating it with ease. Even yours."
icon_state = "mod_0"
base_icon_state = "mod"
amount_per_transfer_from_this = 30
possible_transfer_amounts = list(5, 10, 15, 20, 30)
volume = 30
proj_piercing = 1
///Organ Thrower
///Patrient Transport
///Defibrillator - Gives the suit an extendable pair of shock paddles.
/obj/item/mod/module/defibrillator
name = "MOD defibrillator module"
desc = "A module built into the gauntlets of the suit; commonly known as the 'Healing Hands' by medical professionals. \
The user places their palms above the patient. Onboard computers in the suit calculate the necessary voltage, \
and a modded targeting computer determines the best position for the user to push. \
Twenty five pounds of force are applied to the patient's skin. Shocks travel from the suit's gloves \
and counter-shock the heart, and the wearer returns to Medical a hero. Don't you even think about using it as a weapon; \
regulations on manufacture and software locks expressly forbid it."
icon_state = "defibrillator"
module_type = MODULE_ACTIVE
complexity = 2
use_power_cost = DEFAULT_CHARGE_DRAIN * 25
device = /obj/item/shockpaddles/mod
overlay_state_inactive = "module_defibrillator"
overlay_state_active = "module_defibrillator_active"
incompatible_modules = list(/obj/item/mod/module/defibrillator)
cooldown_time = 0.5 SECONDS
var/defib_cooldown = 5 SECONDS
/obj/item/mod/module/defibrillator/Initialize(mapload)
. = ..()
RegisterSignal(device, COMSIG_DEFIBRILLATOR_SUCCESS, .proc/on_defib_success)
/obj/item/mod/module/defibrillator/proc/on_defib_success(obj/item/shockpaddles/source)
drain_power(use_power_cost)
source.recharge(defib_cooldown)
return COMPONENT_DEFIB_STOP
/obj/item/shockpaddles/mod
name = "MOD defibrillator gauntlets"
req_defib = FALSE
icon_state = "defibgauntlets0"
item_state = "defibgauntlets0"
base_icon_state = "defibgauntlets"
/obj/item/mod/module/defibrillator/combat
name = "MOD combat defibrillator module"
desc = "A module built into the gauntlets of the suit; commonly known as the 'Healing Hands' by medical professionals. \
The user places their palms above the patient. Onboard computers in the suit calculate the necessary voltage, \
and a modded targeting computer determines the best position for the user to push. \
Twenty five pounds of force are applied to the patient's skin. Shocks travel from the suit's gloves \
and counter-shock the heart, and the wearer returns to Medical a hero. \
Interdyne Pharmaceutics marketed the domestic version of the Healing Hands as foolproof and unusable as a weapon. \
But when it came time to provide their operatives with usable medical equipment, they didn't hesitate to remove \
those in-built safeties. Operatives in the field can benefit from what they dub as 'Stun Gloves', able to apply shocks \
straight to a victims heart to disable them, or maybe even outright stop their heart with enough power."
complexity = 1
module_type = MODULE_ACTIVE
overlay_state_inactive = "module_defibrillator_combat"
overlay_state_active = "module_defibrillator_combat_active"
device = /obj/item/shockpaddles/syndicate/mod
defib_cooldown = 2.5 SECONDS
/obj/item/shockpaddles/syndicate/mod
name = "MOD combat defibrillator gauntlets"
req_defib = FALSE
icon_state = "syndiegauntlets0"
item_state = "syndiegauntlets0"
base_icon_state = "syndiegauntlets"
///Thread Ripper
///Surgical Processor - Lets you do advanced surgeries portably.
/obj/item/mod/module/surgical_processor
name = "MOD surgical processor module"
desc = "A module using an onboard surgical computer which can be connected to other computers to download and \
perform advanced surgeries on the go."
icon_state = "surgical_processor"
module_type = MODULE_ACTIVE
complexity = 2
active_power_cost = DEFAULT_CHARGE_DRAIN
device = /obj/item/surgical_processor/mod
incompatible_modules = list(/obj/item/mod/module/surgical_processor)
cooldown_time = 0.5 SECONDS
/obj/item/surgical_processor/mod
name = "MOD surgical processor"
/obj/item/mod/module/surgical_processor/preloaded
desc = "A module using an onboard surgical computer which can be connected to other computers to download and \
perform advanced surgeries on the go. This one came pre-loaded with some advanced surgeries."
device = /obj/item/surgical_processor/mod/preloaded
/obj/item/surgical_processor/mod/preloaded
advanced_surgeries = list(
/datum/surgery/advanced/pacify,
/datum/surgery/healing/combo/upgraded/femto,
/datum/surgery/advanced/brainwashing,
/datum/surgery/advanced/bioware/nerve_splicing,
/datum/surgery/advanced/bioware/nerve_grounding,
/datum/surgery/advanced/bioware/vein_threading,
/datum/surgery/advanced/bioware/muscled_veins,
/datum/surgery/advanced/bioware/ligament_hook,
/datum/surgery/advanced/bioware/ligament_reinforcement
)
+135
View File
@@ -0,0 +1,135 @@
//Science modules for MODsuits
///Reagent Scanner - Lets the user scan reagents.
/obj/item/mod/module/reagent_scanner
name = "MOD reagent scanner module"
desc = "A module based off research-oriented Nanotrasen HUDs, this is capable of scanning the contents of \
containers and projecting the information in an easy-to-read format on the wearer's display. \
It cannot detect flavors, so that's up to you."
icon_state = "scanner"
module_type = MODULE_TOGGLE
complexity = 1
active_power_cost = DEFAULT_CHARGE_DRAIN * 0.2
incompatible_modules = list(/obj/item/mod/module/reagent_scanner)
cooldown_time = 0.5 SECONDS
/obj/item/mod/module/reagent_scanner/on_activation()
. = ..()
if(!.)
return
ADD_TRAIT(mod.wearer, TRAIT_REAGENT_SCANNER, MOD_TRAIT)
/obj/item/mod/module/reagent_scanner/on_deactivation(display_message = TRUE, deleting = FALSE)
. = ..()
if(!.)
return
REMOVE_TRAIT(mod.wearer, TRAIT_REAGENT_SCANNER, MOD_TRAIT)
/obj/item/mod/module/reagent_scanner/advanced
name = "MOD advanced reagent scanner module"
complexity = 0
removable = FALSE
var/explosion_detection_dist = 21
var/had_research_scanner = FALSE
/obj/item/mod/module/reagent_scanner/advanced/on_activation()
. = ..()
if(!.)
return
had_research_scanner = mod.wearer.research_scanner
mod.wearer.research_scanner = TRUE
RegisterSignal(SSdcs, COMSIG_GLOB_EXPLOSION, .proc/sense_explosion)
/obj/item/mod/module/reagent_scanner/advanced/on_deactivation(display_message = TRUE, deleting = FALSE)
. = ..()
if(!.)
return
mod.wearer.research_scanner = had_research_scanner
had_research_scanner = FALSE
UnregisterSignal(SSdcs, COMSIG_GLOB_EXPLOSION)
/obj/item/mod/module/reagent_scanner/advanced/proc/sense_explosion(datum/source, turf/epicenter,
devastation_range, heavy_impact_range, light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range)
SIGNAL_HANDLER
var/turf/wearer_turf = get_turf(mod.wearer)
if(wearer_turf.z == epicenter.z)
return
if(get_dist(epicenter, wearer_turf) > explosion_detection_dist)
return
to_chat(mod.wearer, span_notice("Explosion detected! Epicenter: [devastation_range], Outer: [heavy_impact_range], Shock: [light_impact_range]"))
///Anti-Gravity - Makes the user weightless.
/obj/item/mod/module/anomaly_locked/antigrav
name = "MOD anti-gravity module"
desc = "A module that uses a gravitational core to make the user completely weightless."
icon_state = "antigrav"
module_type = MODULE_TOGGLE
complexity = 3
active_power_cost = DEFAULT_CHARGE_DRAIN * 0.7
incompatible_modules = list(/obj/item/mod/module/anomaly_locked)
cooldown_time = 0.5 SECONDS
accepted_anomalies = list(/obj/item/assembly/signaler/anomaly/grav)
/obj/item/mod/module/anomaly_locked/antigrav/on_activation()
. = ..()
if(!.)
return
if(mod.wearer.has_gravity())
new /obj/effect/temp_visual/mook_dust(get_turf(src))
mod.wearer.AddElement(/datum/element/forced_gravity, 0)
mod.wearer.update_gravity(mod.wearer.has_gravity())
playsound(src, 'sound/effects/gravhit.ogg', 50)
/obj/item/mod/module/anomaly_locked/antigrav/on_deactivation(display_message = TRUE, deleting = FALSE)
. = ..()
if(!.)
return
mod.wearer.RemoveElement(/datum/element/forced_gravity, 0)
mod.wearer.update_gravity(mod.wearer.has_gravity())
if(deleting)
return
if(mod.wearer.has_gravity())
new /obj/effect/temp_visual/mook_dust(get_turf(src))
playsound(src, 'sound/effects/gravhit.ogg', 50)
/obj/item/mod/module/anomaly_locked/antigrav/prebuilt
prebuilt = TRUE
///Teleporter - Lets the user teleport to a nearby location.
/obj/item/mod/module/anomaly_locked/teleporter
name = "MOD teleporter module"
desc = "A module that uses a bluespace core to let the user transport their particles elsewhere."
icon_state = "teleporter"
module_type = MODULE_ACTIVE
complexity = 3
use_power_cost = DEFAULT_CHARGE_DRAIN * 5
cooldown_time = 5 SECONDS
accepted_anomalies = list(/obj/item/assembly/signaler/anomaly/bluespace)
/// Time it takes to teleport
var/teleport_time = 3 SECONDS
/obj/item/mod/module/anomaly_locked/teleporter/on_select_use(atom/target)
. = ..()
if(!.)
return
var/turf/open/target_turf = get_turf(target)
if(!istype(target_turf) || is_blocked_turf(target_turf) || !(target_turf in view(mod.wearer)))
balloon_alert(mod.wearer, "invalid target!")
return
balloon_alert(mod.wearer, "teleporting...")
var/matrix/pre_matrix = matrix()
pre_matrix.Scale(4, 0.25)
var/matrix/post_matrix = matrix()
post_matrix.Scale(0.25, 4)
animate(mod.wearer, teleport_time, color = COLOR_CYAN, transform = pre_matrix.Multiply(mod.wearer.transform), easing = SINE_EASING|EASE_OUT)
if(!do_after(mod.wearer, teleport_time, target = mod))
balloon_alert(mod.wearer, "interrupted!")
animate(mod.wearer, teleport_time*0.1, color = null, transform = post_matrix.Multiply(mod.wearer.transform), easing = SINE_EASING|EASE_IN)
return
animate(mod.wearer, teleport_time*0.1, color = null, transform = post_matrix.Multiply(mod.wearer.transform), easing = SINE_EASING|EASE_IN)
if(!do_teleport(mod.wearer, target_turf, asoundin = 'sound/effects/phasein.ogg'))
return
drain_power(use_power_cost)
/obj/item/mod/module/anomaly_locked/teleporter/prebuilt
prebuilt = TRUE
@@ -0,0 +1,207 @@
//Security modules for MODsuits
///Cloaking - Lowers the user's visibility, can be interrupted by being touched or attacked.
/obj/item/mod/module/stealth
name = "MOD prototype cloaking module"
desc = "A complete retrofitting of the suit, this is a form of visual concealment tech employing esoteric technology \
to bend light around the user, as well as mimetic materials to make the surface of the suit match the \
surroundings based off sensor data. For some reason, this tech is rarely seen."
icon_state = "cloak"
module_type = MODULE_TOGGLE
complexity = 4
active_power_cost = DEFAULT_CHARGE_DRAIN * 2
use_power_cost = DEFAULT_CHARGE_DRAIN * 10
incompatible_modules = list(/obj/item/mod/module/stealth)
cooldown_time = 5 SECONDS
/// Whether or not the cloak turns off on bumping.
var/bumpoff = TRUE
/// The alpha applied when the cloak is on.
var/stealth_alpha = 50
/obj/item/mod/module/stealth/on_activation()
. = ..()
if(!.)
return
if(bumpoff)
RegisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP, .proc/unstealth)
RegisterSignal(mod.wearer, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/on_unarmed_attack)
RegisterSignal(mod.wearer, COMSIG_ATOM_BULLET_ACT, .proc/on_bullet_act)
RegisterSignal(mod.wearer, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_PARENT_ATTACKBY, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_HULK_ATTACK, COMSIG_ATOM_ATTACK_PAW), .proc/unstealth)
animate(mod.wearer, alpha = stealth_alpha, time = 1.5 SECONDS)
drain_power(use_power_cost)
/obj/item/mod/module/stealth/on_deactivation(display_message = TRUE, deleting = FALSE)
. = ..()
if(!.)
return
if(bumpoff)
UnregisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP)
UnregisterSignal(mod.wearer, list(COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_MOB_ITEM_ATTACK, COMSIG_PARENT_ATTACKBY, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_BULLET_ACT, COMSIG_ATOM_HULK_ATTACK, COMSIG_ATOM_ATTACK_PAW))
animate(mod.wearer, alpha = 255, time = 1.5 SECONDS)
/obj/item/mod/module/stealth/proc/unstealth(datum/source)
SIGNAL_HANDLER
to_chat(mod.wearer, span_warning("[src] gets discharged from contact!"))
do_sparks(2, TRUE, src)
drain_power(use_power_cost)
on_deactivation(display_message = TRUE, deleting = FALSE)
/obj/item/mod/module/stealth/proc/on_unarmed_attack(datum/source, atom/target)
SIGNAL_HANDLER
if(!isliving(target))
return
unstealth(source)
/obj/item/mod/module/stealth/proc/on_bullet_act(datum/source, obj/item/projectile/projectile)
SIGNAL_HANDLER
if(projectile.nodamage)
return
unstealth(source)
///Magnetic Harness - Automatically puts guns in your suit storage when you drop them.
/obj/item/mod/module/magnetic_harness
name = "MOD magnetic harness module"
desc = "Based off old TerraGov harness kits, this magnetic harness automatically attaches dropped guns back to the wearer."
icon_state = "mag_harness"
complexity = 2
use_power_cost = DEFAULT_CHARGE_DRAIN
incompatible_modules = list(/obj/item/mod/module/magnetic_harness)
/// Time before we activate the magnet.
var/magnet_delay = 0.8 SECONDS
/// The typecache of all guns we allow.
var/static/list/guns_typecache
/// The guns already allowed by the modsuit chestplate.
var/list/already_allowed_guns = list()
/obj/item/mod/module/magnetic_harness/Initialize(mapload)
. = ..()
if(!guns_typecache)
guns_typecache = typecacheof(list(/obj/item/gun/ballistic, /obj/item/gun/energy, /obj/item/gun/grenadelauncher, /obj/item/gun/chem, /obj/item/gun/syringe))
/obj/item/mod/module/magnetic_harness/on_install()
already_allowed_guns = guns_typecache & mod.chestplate.allowed
mod.chestplate.allowed |= guns_typecache
/obj/item/mod/module/magnetic_harness/on_uninstall(deleting = FALSE)
if(deleting)
return
mod.chestplate.allowed -= (guns_typecache - already_allowed_guns)
/obj/item/mod/module/magnetic_harness/on_suit_activation()
RegisterSignal(mod.wearer, COMSIG_MOB_UNEQUIPPED_ITEM, .proc/check_dropped_item)
/obj/item/mod/module/magnetic_harness/on_suit_deactivation(deleting = FALSE)
UnregisterSignal(mod.wearer, COMSIG_MOB_UNEQUIPPED_ITEM)
/obj/item/mod/module/magnetic_harness/proc/check_dropped_item(datum/source, obj/item/dropped_item, force, new_location)
SIGNAL_HANDLER
if(!is_type_in_typecache(dropped_item, guns_typecache))
return
if(new_location != get_turf(src))
return
addtimer(CALLBACK(src, .proc/pick_up_item, dropped_item), magnet_delay)
/obj/item/mod/module/magnetic_harness/proc/pick_up_item(obj/item/item)
if(!isturf(item.loc) || !item.Adjacent(mod.wearer))
return
if(!mod.wearer.equip_to_slot_if_possible(item, ITEM_SLOT_SUITSTORE, qdel_on_fail = FALSE, disable_warning = TRUE))
return
playsound(src, 'sound/items/modsuit/magnetic_harness.ogg', 50, TRUE)
balloon_alert(mod.wearer, "[item] reattached")
drain_power(use_power_cost)
///Pepper Shoulders
///Holster - Instantly holsters any not huge gun.
/obj/item/mod/module/holster
name = "MOD holster module"
desc = "Based off typical storage compartments, this system allows the suit to holster a \
standard firearm across its surface and allow for extremely quick retrieval. \
While some users prefer the chest, others the forearm for quick deployment, \
some law enforcement prefer the holster to extend from the thigh."
icon_state = "holster"
module_type = MODULE_USABLE
complexity = 2
incompatible_modules = list(/obj/item/mod/module/holster)
cooldown_time = 0.5 SECONDS
allowed_inactive = TRUE
/// Gun we have holstered.
var/obj/item/gun/holstered
/obj/item/mod/module/holster/on_use()
. = ..()
if(!.)
return
if(!holstered)
var/obj/item/gun/holding = mod.wearer.get_active_held_item()
if(!holding)
balloon_alert(mod.wearer, "nothing to holster!")
return
if(!istype(holding) || holding.w_class > WEIGHT_CLASS_BULKY)
balloon_alert(mod.wearer, "it doesn't fit!")
return
if(mod.wearer.transferItemToLoc(holding, src, force = FALSE, silent = TRUE))
holstered = holding
balloon_alert(mod.wearer, "weapon holstered")
playsound(src, 'sound/weapons/revolverempty.ogg', 100, TRUE)
else if(mod.wearer.put_in_active_hand(holstered, forced = FALSE, ignore_animation = TRUE))
balloon_alert(mod.wearer, "weapon drawn")
playsound(src, 'sound/weapons/revolverempty.ogg', 100, TRUE)
else
balloon_alert(mod.wearer, "holster full!")
/obj/item/mod/module/holster/on_uninstall(deleting = FALSE)
if(holstered)
holstered.forceMove(drop_location())
/obj/item/mod/module/holster/Exited(atom/movable/gone, direction)
. = ..()
if(gone == holstered)
holstered = null
/obj/item/mod/module/holster/Destroy()
QDEL_NULL(holstered)
return ..()
///Megaphone - Lets you speak loud.
/obj/item/mod/module/megaphone
name = "MOD megaphone module"
desc = "A microchip megaphone linked to a MODsuit, for very important purposes, like: loudness."
icon_state = "megaphone"
module_type = MODULE_TOGGLE
complexity = 1
use_power_cost = DEFAULT_CHARGE_DRAIN * 0.5
incompatible_modules = list(/obj/item/mod/module/megaphone)
cooldown_time = 0.5 SECONDS
/// List of spans we add to the speaker.
var/list/voicespan = list(SPAN_COMMAND)
/obj/item/mod/module/megaphone/on_activation()
. = ..()
if(!.)
return
RegisterSignal(mod.wearer, COMSIG_MOB_SAY, .proc/handle_speech)
/obj/item/mod/module/megaphone/on_deactivation(display_message = TRUE, deleting = FALSE)
. = ..()
if(!.)
return
UnregisterSignal(mod.wearer, COMSIG_MOB_SAY)
/obj/item/mod/module/megaphone/proc/handle_speech(datum/source, list/speech_args)
SIGNAL_HANDLER
speech_args[SPEECH_SPANS] |= voicespan
drain_power(use_power_cost)
///Criminal Capture
///Mirage grenade dispenser
///Projectile Dampener
///Active Sonar
@@ -0,0 +1,65 @@
//Service modules for MODsuits
///Bike Horn - Plays a bike horn sound.
/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 \
precisely deliver an almost lethal squeeze to... a bike horn, producing a significantly memorable sound."
icon_state = "bikehorn"
module_type = MODULE_USABLE
complexity = 1
use_power_cost = DEFAULT_CHARGE_DRAIN
incompatible_modules = list(/obj/item/mod/module/bikehorn)
cooldown_time = 1 SECONDS
/obj/item/mod/module/bikehorn/on_use()
. = ..()
if(!.)
return
playsound(src, 'sound/items/bikehorn.ogg', 100, FALSE)
drain_power(use_power_cost)
///Microwave Beam - Microwaves items instantly.
/obj/item/mod/module/microwave_beam
name = "MOD microwave beam module"
desc = "An oddly domestic device, this module is installed into the user's palm, \
hooking up with culinary scanners located in the helmet to blast food with precise microwave radiation, \
allowing them to cook food from a distance, with the greatest of ease. Not recommended for use against grapes."
icon_state = "microwave_beam"
module_type = MODULE_ACTIVE
complexity = 2
use_power_cost = DEFAULT_CHARGE_DRAIN * 5
incompatible_modules = list(/obj/item/mod/module/microwave_beam)
cooldown_time = 10 SECONDS
var/obj/machinery/microwave/microwave
/obj/item/mod/module/microwave_beam/Initialize(mapload)
microwave = new()
. = ..()
/obj/item/mod/module/microwave_beam/Destroy()
QDEL_NULL(microwave)
. = ..()
/obj/item/mod/module/microwave_beam/on_select_use(atom/target)
. = ..()
if(!.)
return
if(!isitem(target))
return
if(!isturf(target.loc))
balloon_alert(mod.wearer, "must be on the floor!")
return
var/obj/item/microwave_target = target
var/datum/effect_system/spark_spread/spark_effect = new()
spark_effect.set_up(2, 1, mod.wearer)
spark_effect.start()
mod.wearer.Beam(target,icon_state="lightning[rand(1,12)]", time = 5)
if(microwave_target.microwave_act(microwave))
playsound(src, 'sound/machines/microwave/microwave-end.ogg', 50, FALSE)
else
balloon_alert(mod.wearer, "can't be microwaved!")
var/datum/effect_system/spark_spread/spark_effect_two = new()
spark_effect_two.set_up(2, 1, microwave_target)
spark_effect_two.start()
drain_power(use_power_cost)
+174
View File
@@ -0,0 +1,174 @@
//Supply modules for MODsuits
///Internal GPS - Extends a GPS you can use.
/obj/item/mod/module/gps
name = "MOD internal GPS module"
desc = "This module uses common Nanotrasen technology to calculate the user's position anywhere in space, \
down to the exact coordinates. This information is fed to a central database viewable from the device itself, \
though using it to help people is up to you."
icon_state = "gps"
module_type = MODULE_USABLE
complexity = 1
use_power_cost = DEFAULT_CHARGE_DRAIN * 0.2
incompatible_modules = list(/obj/item/mod/module/gps)
cooldown_time = 0.5 SECONDS
allowed_inactive = TRUE
/obj/item/mod/module/gps/Initialize(mapload)
. = ..()
AddComponent(/datum/component/gps/item, "MOD0", state = GLOB.deep_inventory_state, overlay_state = FALSE)
/obj/item/mod/module/gps/on_use()
. = ..()
if(!.)
return
attack_self(mod.wearer)
///Hydraulic Clamp - Lets you pick up and drop crates.
/obj/item/mod/module/clamp
name = "MOD hydraulic clamp module"
desc = "A series of actuators installed into both arms of the suit, boasting a lifting capacity of almost a ton. \
However, this design has been locked by Nanotrasen to be primarily utilized for lifting various crates. \
A lot of people would say that loading cargo is a dull job, but you could not disagree more."
icon_state = "clamp"
module_type = MODULE_ACTIVE
complexity = 3
use_power_cost = DEFAULT_CHARGE_DRAIN
incompatible_modules = list(/obj/item/mod/module/clamp)
cooldown_time = 0.5 SECONDS
overlay_state_inactive = "module_clamp"
overlay_state_active = "module_clamp_on"
/// Time it takes to load a crate.
var/load_time = 3 SECONDS
/// The max amount of crates you can carry.
var/max_crates = 3
/// The crates stored in the module.
var/list/stored_crates = list()
/obj/item/mod/module/clamp/on_select_use(atom/target)
. = ..()
if(!.)
return
if(!mod.wearer.Adjacent(target))
return
if(istype(target, /obj/structure/closet/crate) || istype(target, /obj/structure/bigDelivery))
var/atom/movable/picked_crate = target
if(!check_crate_pickup(picked_crate))
return
playsound(src, 'sound/mecha/hydraulic.ogg', 25, TRUE)
if(!do_after(mod.wearer, load_time, target = target))
balloon_alert(mod.wearer, "interrupted!")
return
if(!check_crate_pickup(picked_crate))
return
stored_crates += picked_crate
picked_crate.forceMove(src)
balloon_alert(mod.wearer, "picked up [picked_crate]")
drain_power(use_power_cost)
else if(length(stored_crates))
var/turf/target_turf = get_turf(target)
if(is_blocked_turf(target_turf))
return
playsound(src, 'sound/mecha/hydraulic.ogg', 25, TRUE)
if(!do_after(mod.wearer, load_time, target = target))
balloon_alert(mod.wearer, "interrupted!")
return
if(is_blocked_turf(target_turf))
return
var/atom/movable/dropped_crate = pop(stored_crates)
dropped_crate.forceMove(target_turf)
balloon_alert(mod.wearer, "dropped [dropped_crate]")
drain_power(use_power_cost)
else
balloon_alert(mod.wearer, "invalid target!")
/obj/item/mod/module/clamp/on_suit_deactivation(deleting = FALSE)
if(deleting)
return
for(var/atom/movable/crate as anything in stored_crates)
crate.forceMove(drop_location())
stored_crates -= crate
/obj/item/mod/module/clamp/proc/check_crate_pickup(atom/movable/target)
if(length(stored_crates) >= max_crates)
balloon_alert(mod.wearer, "too many crates!")
return FALSE
for(var/mob/living/mob in target.GetAllContents())
if(mob.mob_size < MOB_SIZE_HUMAN)
continue
balloon_alert(mod.wearer, "crate too heavy!")
return FALSE
return TRUE
/obj/item/mod/module/clamp/loader
name = "MOD loader hydraulic clamp module"
icon_state = "clamp_loader"
complexity = 0
removable = FALSE
overlay_state_inactive = null
overlay_state_active = "module_clamp_loader"
load_time = 1 SECONDS
max_crates = 5
use_mod_colors = TRUE
///Drill - Lets you dig through rock and basalt.
/obj/item/mod/module/drill // TODO: Would be cooler with a built-in drill, but meh
name = "MOD pickaxe/drill storage module"
desc = "Provides a convenient storage compartment for pickaxes and drills."
icon_state = "drill"
complexity = 2
incompatible_modules = list(/obj/item/mod/module/drill)
cooldown_time = 0.5 SECONDS
allowed_inactive = TRUE
module_type = MODULE_USABLE
/// Pickaxe we have stored.
var/obj/item/pickaxe/stored
/obj/item/mod/module/drill/on_use()
. = ..()
if(!.)
return
if(!stored)
var/obj/item/pickaxe/holding = mod.wearer.get_active_held_item()
if(!holding)
balloon_alert(mod.wearer, "nothing to store!")
return
if(!istype(holding))
balloon_alert(mod.wearer, "it doesn't fit!")
return
if(mod.wearer.transferItemToLoc(holding, src, force = FALSE, silent = TRUE))
stored = holding
balloon_alert(mod.wearer, "mining instrument stored")
playsound(src, 'sound/weapons/revolverempty.ogg', 100, TRUE)
else if(mod.wearer.put_in_active_hand(stored, forced = FALSE, ignore_animation = TRUE))
balloon_alert(mod.wearer, "mining instrument retrieved")
playsound(src, 'sound/weapons/revolverempty.ogg', 100, TRUE)
else
balloon_alert(mod.wearer, "mining instrument storage full!")
/obj/item/mod/module/drill/on_uninstall(deleting = FALSE)
if(stored)
stored.forceMove(drop_location())
/obj/item/mod/module/drill/Exited(atom/movable/gone, direction)
. = ..()
if(gone == stored)
stored = null
/obj/item/mod/module/drill/Destroy()
QDEL_NULL(stored)
return ..()
/obj/item/mod/module/orebag // TODO
name = "MOD mining satchel storage module"
desc = "Provides a convenient storage department for a mining satchel."
icon_state = "ore"
module_type = MODULE_USABLE
complexity = 1
use_power_cost = DEFAULT_CHARGE_DRAIN * 0.2
incompatible_modules = list(/obj/item/mod/module/orebag)
cooldown_time = 0.5 SECONDS
allowed_inactive = TRUE
// Ash accretion looks cool, but can't be arsed to implement
// Same with sphere transformation
+91
View File
@@ -0,0 +1,91 @@
//Visor modules for MODsuits
///Base Visor - Adds a specific HUD and traits to you.
/obj/item/mod/module/visor
name = "MOD visor module"
desc = "A heads-up display installed into the visor of the suit. They say these also let you see behind you."
module_type = MODULE_TOGGLE
complexity = 2
active_power_cost = DEFAULT_CHARGE_DRAIN * 0.3
incompatible_modules = list(/obj/item/mod/module/visor)
cooldown_time = 0.5 SECONDS
/// The HUD type given by the visor.
var/hud_type
/// The traits given by the visor.
var/list/visor_traits = list()
/obj/item/mod/module/visor/on_activation()
. = ..()
if(!.)
return
if(hud_type)
var/datum/atom_hud/hud = GLOB.huds[hud_type]
hud.add_hud_to(mod.wearer)
for(var/trait in visor_traits)
ADD_TRAIT(mod.wearer, trait, MOD_TRAIT)
mod.wearer.update_sight()
/obj/item/mod/module/visor/on_deactivation(display_message = TRUE, deleting = FALSE)
. = ..()
if(!.)
return
if(hud_type)
var/datum/atom_hud/hud = GLOB.huds[hud_type]
hud.remove_hud_from(mod.wearer)
for(var/trait in visor_traits)
REMOVE_TRAIT(mod.wearer, trait, MOD_TRAIT)
mod.wearer.update_sight()
//Medical Visor - Gives you a medical HUD.
/obj/item/mod/module/visor/medhud
name = "MOD medical visor module"
desc = "A heads-up display installed into the visor of the suit. This cross-references suit sensor data with a modern \
biological scanning suite, allowing the user to visualize the current health of organic lifeforms, as well as \
access data such as patient files in a convenient readout. They say these also let you see behind you."
icon_state = "medhud_visor"
hud_type = DATA_HUD_MEDICAL_ADVANCED
//Diagnostic Visor - Gives you a diagnostic HUD.
/obj/item/mod/module/visor/diaghud
name = "MOD diagnostic visor module"
desc = "A heads-up display installed into the visor of the suit. This uses a series of advanced sensors to access data \
from advanced machinery, exosuits, and other devices, allowing the user to visualize current power levels \
and integrity of such. They say these also let you see behind you."
icon_state = "diaghud_visor"
hud_type = DATA_HUD_DIAGNOSTIC_ADVANCED
//Security Visor - Gives you a security HUD.
/obj/item/mod/module/visor/sechud
name = "MOD security visor module"
desc = "A heads-up display installed into the visor of the suit. This module is a heavily-retrofitted targeting system, \
plugged into various criminal databases to be able to view arrest records, command simple security-oriented robots, \
and generally know who to shoot. They say these also let you see behind you."
icon_state = "sechud_visor"
hud_type = DATA_HUD_SECURITY_ADVANCED
//Meson Visor - Gives you meson vision.
/obj/item/mod/module/visor/meson
name = "MOD meson visor module"
desc = "A heads-up display installed into the visor of the suit. This module is based off well-loved meson scanner \
technology, used by construction workers and miners across the galaxy to see basic structural and terrain layouts \
through walls, regardless of lighting conditions. They say these also let you see behind you."
icon_state = "meson_visor"
visor_traits = list(TRAIT_MESON_VISION)
//Thermal Visor - Gives you thermal vision.
/obj/item/mod/module/visor/thermal
name = "MOD thermal visor module"
desc = "A heads-up display installed into the visor of the suit. This uses a small IR scanner to detect and identify \
the thermal radiation output of objects near the user. While it can detect the heat output of even something as \
small as a rodent, it still produces irritating red overlay. They say these also let you see behind you."
icon_state = "thermal_visor"
visor_traits = list(TRAIT_THERMAL_VISION)
//Night Visor - Gives you night vision.
/obj/item/mod/module/visor/night
name = "MOD night visor module"
desc = "A heads-up display installed into the visor of the suit. Typical for both civilian and military applications, \
this allows the user to perceive their surroundings while in complete darkness, enhancing the view by tenfold; \
yet brightening everything into a spooky green glow. They say these also let you see behind you."
icon_state = "night_visor"
visor_traits = list(TRAIT_TRUE_NIGHT_VISION)
@@ -0,0 +1,392 @@
//MODsuit construction
/datum/design/mod_shell
name = "MOD Shell"
desc = "A 'Nakamura Engineering' designed shell for a Modular Suit."
id = "mod_shell"
build_type = MECHFAB
materials = list(/datum/material/iron = 10000, /datum/material/plasma = 5000)
construction_time = 25 SECONDS
build_path = /obj/item/mod/construction/shell
category = list("MODsuit Chassis")
/datum/design/mod_helmet
name = "MOD Helmet"
desc = "A 'Nakamura Engineering' designed helmet for a Modular Suit."
id = "mod_helmet"
build_type = MECHFAB
materials = list(/datum/material/iron = 5000)
construction_time = 10 SECONDS
build_path = /obj/item/mod/construction/helmet
category = list("MODsuit Chassis")
/datum/design/mod_chestplate
name = "MOD Chestplate"
desc = "A 'Nakamura Engineering' designed chestplate for a Modular Suit."
id = "mod_chestplate"
build_type = MECHFAB
materials = list(/datum/material/iron = 5000)
construction_time = 10 SECONDS
build_path = /obj/item/mod/construction/chestplate
category = list("MODsuit Chassis")
/datum/design/mod_gauntlets
name = "MOD Gauntlets"
desc = "'Nakamura Engineering' designed gauntlets for a Modular Suit."
id = "mod_gauntlets"
build_type = MECHFAB
materials = list(/datum/material/iron = 5000)
construction_time = 10 SECONDS
build_path = /obj/item/mod/construction/gauntlets
category = list("MODsuit Chassis")
/datum/design/mod_boots
name = "MOD Boots"
desc = "'Nakamura Engineering' designed boots for a Modular Suit."
id = "mod_boots"
build_type = MECHFAB
materials = list(/datum/material/iron = 5000)
construction_time = 10 SECONDS
build_path = /obj/item/mod/construction/boots
category = list("MODsuit Chassis")
/datum/design/mod_plating
name = "MOD External Plating"
desc = "External plating for a MODsuit."
id = "mod_plating_standard"
build_type = PROTOLATHE | MECHFAB
materials = list(/datum/material/iron = 6000, /datum/material/glass = 3000, /datum/material/plasma = 1000)
construction_time = 15 SECONDS
build_path = /obj/item/mod/construction/armor
category = list("MODsuit Chassis", "MODsuit Designs")
departmental_flags = DEPARTMENTAL_FLAG_ALL
research_icon = 'icons/obj/clothing/modsuit/mod_construction.dmi'
research_icon_state = "standard-plating"
/datum/design/mod_plating/New()
. = ..()
var/obj/item/mod/construction/armor/armor_type = build_path
var/datum/mod_theme/theme = GLOB.mod_themes[initial(armor_type.theme)]
desc = "External plating for a MODsuit. [theme.desc]"
/datum/design/mod_plating/engineering
name = "MOD Engineering Plating"
id = "mod_plating_engineering"
build_path = /obj/item/mod/construction/armor/engineering
materials = list(/datum/material/iron = 6000, /datum/material/gold = 2000, /datum/material/glass = 1000, /datum/material/plasma = 1000)
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
research_icon_state = "engineering-plating"
/datum/design/mod_plating/atmospheric
name = "MOD Atmospheric Plating"
id = "mod_plating_atmospheric"
build_path = /obj/item/mod/construction/armor/atmospheric
materials = list(/datum/material/iron = 6000, /datum/material/titanium = 2000, /datum/material/glass = 1000, /datum/material/plasma = 1000)
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
research_icon_state = "atmospheric-plating"
/datum/design/mod_plating/medical
name = "MOD Medical Plating"
id = "mod_plating_medical"
build_path = /obj/item/mod/construction/armor/medical
materials = list(/datum/material/iron = 6000, /datum/material/silver = 2000, /datum/material/glass = 1000, /datum/material/plasma = 1000)
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
research_icon_state = "medical-plating"
/datum/design/mod_plating/security
name = "MOD Security Plating"
id = "mod_plating_security"
build_path = /obj/item/mod/construction/armor/security
materials = list(/datum/material/iron = 6000, /datum/material/uranium = 2000, /datum/material/glass = 1000, /datum/material/plasma = 1000)
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
research_icon_state = "security-plating"
/datum/design/mod_plating/cosmohonk
name = "MOD Cosmohonk Plating"
id = "mod_plating_cosmohonk"
build_path = /obj/item/mod/construction/armor/cosmohonk
materials = list(/datum/material/iron = 6000, /datum/material/bananium = 2000, /datum/material/glass = 1000, /datum/material/plasma = 1000)
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_SERVICE
research_icon_state = "cosmohonk-plating"
/datum/design/mod_paint_kit
name = "MOD Paint Kit"
desc = "A paint kit for Modular Suits."
id = "mod_paint_kit"
build_type = PROTOLATHE | MECHFAB
materials = list(/datum/material/iron = 1000, /datum/material/plastic = 500)
construction_time = 5 SECONDS
build_path = /obj/item/mod/paint
category = list("MODsuit Modules", "MODsuit Designs")
//MODsuit modules
/datum/design/module
name = "MOD Module"
build_type = PROTOLATHE | MECHFAB
construction_time = 1 SECONDS
materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000)
build_path = /obj/item/mod/module
category = list("MODsuit Modules", "MODsuit Designs")
departmental_flags = DEPARTMENTAL_FLAG_ALL
/datum/design/module/New()
. = ..()
var/obj/item/mod/module/module = build_path
desc = "[initial(module.desc)] It uses [initial(module.complexity)] complexity."
/datum/design/module/mod_storage
name = "Storage Module"
id = "mod_storage"
materials = list(/datum/material/iron = 2500, /datum/material/glass = 500)
build_path = /obj/item/mod/module/storage
/datum/design/module/mod_visor_medhud
name = "Medical Visor Module"
id = "mod_visor_medhud"
materials = list(/datum/material/silver = 500, /datum/material/glass = 1000)
build_path = /obj/item/mod/module/visor/medhud
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
/datum/design/module/mod_visor_diaghud
name = "Diagnostic Visor Module"
id = "mod_visor_diaghud"
materials = list(/datum/material/gold = 500, /datum/material/glass = 1000)
build_path = /obj/item/mod/module/visor/diaghud
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
/datum/design/module/mod_visor_sechud
name = "Security Visor Module"
id = "mod_visor_sechud"
materials = list(/datum/material/titanium = 500, /datum/material/glass = 1000)
build_path = /obj/item/mod/module/visor/sechud
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
/datum/design/module/mod_visor_meson
name = "Meson Visor Module"
id = "mod_visor_meson"
materials = list(/datum/material/uranium = 500, /datum/material/glass = 1000)
build_path = /obj/item/mod/module/visor/meson
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
/datum/design/module/mod_visor_welding
name = "Welding Protection Module"
id = "mod_welding"
materials = list(/datum/material/iron = 500, /datum/material/glass = 1000)
build_path = /obj/item/mod/module/welding
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
/datum/design/module/mod_t_ray
name = "T-Ray Scanner Module"
id = "mod_t_ray"
materials = list(/datum/material/iron = 500, /datum/material/glass = 1000)
build_path = /obj/item/mod/module/t_ray
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
/datum/design/module/mod_health_analyzer
name = "Health Analyzer Module"
id = "mod_health_analyzer"
materials = list(/datum/material/iron = 500, /datum/material/glass = 1000)
build_path = /obj/item/mod/module/health_analyzer
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
/datum/design/module/mod_stealth
name = "Cloak Module"
id = "mod_stealth"
materials = list(/datum/material/iron = 1000, /datum/material/bluespace = 500)
build_path = /obj/item/mod/module/stealth
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
/datum/design/module/mod_magboot
name = "Magnetic Stabilizator Module"
id = "mod_magboot"
materials = list(/datum/material/iron = 1000, /datum/material/gold = 500)
build_path = /obj/item/mod/module/magboot
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
/datum/design/module/mod_mag_harness
name = "Magnetic Harness Module"
id = "mod_mag_harness"
materials = list(/datum/material/iron = 1500, /datum/material/silver = 500)
build_path = /obj/item/mod/module/magnetic_harness
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
/datum/design/module/mod_mouthhole
name = "Eating Apparatus Module"
id = "mod_mouthhole"
materials = list(/datum/material/iron = 1500)
build_path = /obj/item/mod/module/mouthhole
/datum/design/module/mod_rad_protection
name = "Radiation Protection Module"
id = "mod_rad_protection"
materials = list(/datum/material/iron = 1000, /datum/material/uranium = 1000)
build_path = /obj/item/mod/module/rad_protection
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
/datum/design/module/mod_emp_shield
name = "EMP Shield Module"
id = "mod_emp_shield"
materials = list(/datum/material/iron = 1000, /datum/material/plasma = 1000)
build_path = /obj/item/mod/module/emp_shield
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
/datum/design/module/mod_flashlight
name = "Flashlight Module"
id = "mod_flashlight"
materials = list(/datum/material/iron = 500, /datum/material/glass = 1000)
build_path = /obj/item/mod/module/flashlight
/datum/design/module/mod_reagent_scanner
name = "Reagent Scanner Module"
id = "mod_reagent_scanner"
materials = list(/datum/material/glass = 1000)
build_path = /obj/item/mod/module/reagent_scanner
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/module/mod_gps
name = "Internal GPS Module"
id = "mod_gps"
materials = list(/datum/material/iron = 500, /datum/material/glass = 500)
build_path = /obj/item/mod/module/gps
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_CARGO
/datum/design/module/mod_constructor
name = "Constructor Module"
id = "mod_constructor"
materials = list(/datum/material/iron = 1000, /datum/material/titanium = 500)
build_path = /obj/item/mod/module/constructor
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
/datum/design/module/mod_quick_carry
name = "Quick Carry Module"
id = "mod_quick_carry"
materials = list(/datum/material/iron = 1000, /datum/material/titanium = 500)
build_path = /obj/item/mod/module/quick_carry
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
/datum/design/module/mod_longfall
name = "Longfall Module"
id = "mod_longfall"
materials = list(/datum/material/iron = 1000)
build_path = /obj/item/mod/module/longfall
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_CARGO
/datum/design/module/mod_injector
name = "Injector Module"
id = "mod_injector"
materials = list(/datum/material/iron = 1000, /datum/material/diamond = 500)
build_path = /obj/item/mod/module/injector
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
/datum/design/module/mod_bikehorn
name = "Bike Horn Module"
id = "mod_bikehorn"
materials = list(/datum/material/plastic = 500, /datum/material/iron = 500)
build_path = /obj/item/mod/module/bikehorn
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_SERVICE
/datum/design/module/mod_microwave_beam
name = "Microwave Beam Module"
id = "mod_microwave_beam"
materials = list(/datum/material/iron = 1000, /datum/material/uranium = 500)
build_path = /obj/item/mod/module/microwave_beam
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_SERVICE
/datum/design/module/mod_clamp
name = "Crate Clamp Module"
id = "mod_clamp"
materials = list(/datum/material/iron = 2000)
build_path = /obj/item/mod/module/clamp
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_CARGO
/datum/design/module/mod_drill
name = "Drill Module"
id = "mod_drill"
materials = list(/datum/material/silver = 1000, /datum/material/iron = 2000)
build_path = /obj/item/mod/module/drill
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_CARGO
/datum/design/module/mod_orebag
name = "Ore Bag Module"
id = "mod_orebag"
materials = list(/datum/material/iron = 1500)
build_path = /obj/item/mod/module/orebag
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_CARGO
/datum/design/module/mod_dna_lock
name = "DNA Lock Module"
id = "mod_dna_lock"
materials = list(/datum/material/diamond = 500, /datum/material/glass = 1000)
build_path = /obj/item/mod/module/dna_lock
/datum/design/module/mister_atmos
name = "Resin Mister Module"
id = "mod_mister_atmos"
materials = list(/datum/material/glass = 1000, /datum/material/titanium = 1500)
build_path = /obj/item/mod/module/mister/atmos
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
/datum/design/module/mod_holster
name = "Holster Module"
id = "mod_holster"
materials = list(/datum/material/iron = 1500, /datum/material/glass = 500)
build_path = /obj/item/mod/module/holster
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
/datum/design/module/surgicalprocessor
name = "Surgical Processor Module"
id = "mod_surgicalprocessor"
materials = list(/datum/material/titanium = 250, /datum/material/glass = 1000, /datum/material/silver = 1500)
build_path = /obj/item/mod/module/surgical_processor
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
/datum/design/module/defibrillator
name = "Defibrillator Module"
id = "mod_defib"
materials = list(/datum/material/titanium = 250, /datum/material/diamond = 1000, /datum/material/silver = 1500)
build_path = /obj/item/mod/module/defibrillator
build_type = PROTOLATHE
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
//MODsuit anomalock modules
/datum/design/module/mod_antigrav
name = "Anti-Gravity Module"
id = "mod_antigrav"
materials = list(/datum/material/iron = 2500, /datum/material/glass = 2000, /datum/material/uranium = 2000)
build_path = /obj/item/mod/module/anomaly_locked/antigrav
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
/datum/design/module/mod_teleporter
name = "Teleporter Module"
id = "mod_teleporter"
materials = list(/datum/material/iron = 2500, /datum/material/glass = 2000, /datum/material/bluespace = 2000)
build_path = /obj/item/mod/module/anomaly_locked/teleporter
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
@@ -15,7 +15,8 @@
"Weapons",
"Ammo",
"Firing Pins",
"Computer Parts"
"Computer Parts",
"MODsuit Designs"
)
production_animation = "protolathe_n"
allowed_buildtypes = PROTOLATHE
+2 -1
View File
@@ -26,7 +26,8 @@
"Subspace Telecomms",
"Research Machinery",
"Misc. Machinery",
"Computer Parts"
"Computer Parts",
"MODsuit Designs"
)
console_link = FALSE
production_animation = "protolathe_n"
@@ -0,0 +1,123 @@
/datum/techweb_node/mod_basic
id = "mod"
starting_node = TRUE
display_name = "Basic Modular Suits"
description = "Specialized back mounted power suits with various different modules."
design_ids = list(
"mod_shell",
"mod_helmet",
"mod_chestplate",
"mod_gauntlets",
"mod_boots",
"mod_plating_standard",
"mod_storage",
"mod_welding",
"mod_mouthhole",
"mod_flashlight",
"mod_longfall",
)
/datum/techweb_node/mod_advanced
id = "mod_advanced"
display_name = "Advanced Modular Suits"
description = "More advanced modules, to improve modular suits."
prereq_ids = list("mod", "robotics")
design_ids = list(
"mod_visor_diaghud",
"mod_gps",
"mod_reagent_scanner",
"mod_clamp",
"mod_drill",
"mod_orebag",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
/datum/techweb_node/mod_engineering
id = "mod_engineering"
display_name = "Engineering Modular Suits"
description = "Engineering suits, for powered engineers."
prereq_ids = list("mod_advanced", "engineering")
design_ids = list(
"mod_plating_engineering",
"mod_visor_meson",
"mod_t_ray",
"mod_magboot",
"mod_constructor",
"mod_mister_atmos",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
/datum/techweb_node/mod_advanced_engineering
id = "mod_advanced_engineering"
display_name = "Advanced Engineering Modular Suits"
description = "Advanced Engineering suits, for advanced powered engineers."
prereq_ids = list("mod_engineering", "adv_engi")
design_ids = list(
"mod_plating_atmospheric",
"mod_rad_protection",
"mod_emp_shield",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3500)
/datum/techweb_node/mod_medical
id = "mod_medical"
display_name = "Medical Modular Suits"
description = "Medical suits for quick rescue purposes."
prereq_ids = list("mod_advanced", "biotech")
design_ids = list(
"mod_plating_medical",
"mod_visor_medhud",
"mod_health_analyzer",
"mod_quick_carry",
"mod_injector",
"mod_dna_lock",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
/datum/techweb_node/mod_advanced_medical
id = "mod_advanced_medical"
display_name = "Advanced Medical Modular Suits"
description = "Advanced medical suits for quicker rescue purposes."
prereq_ids = list("mod_medical", "adv_biotech")
design_ids = list(
"mod_defib",
"mod_surgicalprocessor",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3500)
/datum/techweb_node/mod_security
id = "mod_security"
display_name = "Security Modular Suits"
description = "Security suits for space crime handling."
prereq_ids = list("mod_advanced", "sec_basic")
design_ids = list(
"mod_plating_security",
"mod_visor_sechud",
"mod_stealth",
"mod_mag_harness",
"mod_holster",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
/datum/techweb_node/mod_entertainment
id = "mod_entertainment"
display_name = "Entertainment Modular Suits"
description = "Powered suits for protection against low-humor environments."
prereq_ids = list("mod_advanced", "clown")
design_ids = list(
"mod_plating_cosmohonk",
"mod_bikehorn",
"mod_microwave_beam",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
/datum/techweb_node/mod_anomaly
id = "mod_anomaly"
display_name = "Anomalock Modular Suits"
description = "Modules for modular suits that require anomaly cores to function."
prereq_ids = list("mod_advanced", "anomaly_research")
design_ids = list(
"mod_antigrav",
"mod_teleporter",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
+9
View File
@@ -68,6 +68,15 @@
var/obj/item/surgical_processor/SP = locate() in R.module.modules
if(SP)
advanced_surgeries |= SP.advanced_surgeries
else
var/obj/item/surgical_processor/SP
for(var/obj/item/surgical_processor/processor in user.held_items)
SP = processor
break
if(!SP)
SP = locate(/obj/item/surgical_processor) in get_turf(user)
if(SP)
advanced_surgeries |= SP.advanced_surgeries
var/turf/T = get_turf(patient)
var/obj/structure/table/optable/table = locate(/obj/structure/table/optable, T)
+3 -3
View File
@@ -817,7 +817,7 @@
mecha_flags &= ~SILICON_PILOT
AI.forceMove(card)
card.AI = AI
AI.controlled_mech = null
AI.controlled_equipment = null
AI.remote_control = null
to_chat(AI, "<span class='notice'>You have been downloaded to a mobile storage device. Wireless connection offline.</span>")
to_chat(user, "<span class='boldnotice'>Transfer successful</span>: [AI.name] ([rand(1000,9999)].exe) removed from [name] and stored within local memory.")
@@ -856,7 +856,7 @@
mecha_flags |= SILICON_PILOT
moved_inside(AI)
AI.cancel_camera()
AI.controlled_mech = src
AI.controlled_equipment = src
AI.remote_control = src
AI.mobility_flags = ALL //Much easier than adding AI checks! Be sure to set this back to 0 if you decide to allow an AI to leave a mech somehow.
if(interaction == AI_MECH_HACK)
@@ -1083,7 +1083,7 @@
AI.linked_core = null
return
to_chat(AI, "<span class='notice'>Returning to core...</span>")
AI.controlled_mech = null
AI.controlled_equipment = null
AI.remote_control = null
mob_container = AI
newloc = get_turf(AI.linked_core)
@@ -57,6 +57,8 @@
"Exosuit Equipment",
"Exosuit Ammunition",
"Cyborg Upgrade Modules",
"MODsuit Chassis",
"MODsuit Modules",
"Cybernetics",
"Implants",
"Control Interfaces",
@@ -35,7 +35,7 @@
AI.death() //The damage is not enough to kill the AI, but to be 'corrupted files' in need of repair.
AI.forceMove(src) //Put the dead AI inside the wreckage for recovery
add_overlay(mutable_appearance('icons/obj/projectiles.dmi', "green_laser")) //Overlay for the recovery beacon
AI.controlled_mech = null
AI.controlled_equipment = null
AI.remote_control = null
/obj/structure/mecha_wreckage/Destroy()
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+12 -3
View File
@@ -159,11 +159,11 @@
#include "code\__DEFINES\dcs\flags.dm"
#include "code\__DEFINES\dcs\helpers.dm"
#include "code\__DEFINES\dcs\signals.dm"
#include "code\__DEFINES\dcs\signals\signals_medical.dm"
#include "code\__DEFINES\dcs\signals\signals_mod.dm"
#include "code\__DEFINES\dcs\signals\signals_subsystem.dm"
#include "code\__DEFINES\dcs\signals\signals_atom\signals_atom_movable.dm"
#include "code\__DEFINES\dcs\signals\signals_atom\signals_atom_movement.dm"
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_carbon.dm"
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_living.dm"
#include "code\__DEFINES\mapping\maploader.dm"
#include "code\__DEFINES\material\worth.dm"
@@ -2022,7 +2022,6 @@
#include "code\modules\client\preferences_savefile.dm"
#include "code\modules\client\preferences_toggles.dm"
#include "code\modules\client\preferences_vr.dm"
#include "code\modules\client\preferences\mod_select.dm"
#include "code\modules\client\verbs\aooc.dm"
#include "code\modules\client\verbs\autobunker.dm"
#include "code\modules\client\verbs\etips.dm"
@@ -2963,13 +2962,21 @@
#include "code\modules\mod\mod_ai.dm"
#include "code\modules\mod\mod_clothes.dm"
#include "code\modules\mod\mod_construction.dm"
#include "code\modules\mod\mod_construction.dm"
#include "code\modules\mod\mod_control.dm"
#include "code\modules\mod\mod_theme.dm"
#include "code\modules\mod\mod_types.dm"
#include "code\modules\mod\mod_ui.dm"
#include "code\modules\mod\modules\_module.dm"
#include "code\modules\mod\modules\modules.dm"
#include "code\modules\mod\modules\modules_engineering.dm"
#include "code\modules\mod\modules\modules_general.dm"
#include "code\modules\mod\modules\modules_maint.dm"
#include "code\modules\mod\modules\modules_medical.dm"
#include "code\modules\mod\modules\modules_science.dm"
#include "code\modules\mod\modules\modules_security.dm"
#include "code\modules\mod\modules\modules_service.dm"
#include "code\modules\mod\modules\modules_supply.dm"
#include "code\modules\mod\modules\modules_visor.dm"
#include "code\modules\modular_computers\laptop_vendor.dm"
#include "code\modules\modular_computers\computers\_modular_computer_shared.dm"
#include "code\modules\modular_computers\computers\item\computer.dm"
@@ -3382,6 +3389,7 @@
#include "code\modules\research\designs\medical_designs.dm"
#include "code\modules\research\designs\mining_designs.dm"
#include "code\modules\research\designs\misc_designs.dm"
#include "code\modules\research\designs\mod_designs.dm"
#include "code\modules\research\designs\nanite_designs.dm"
#include "code\modules\research\designs\power_designs.dm"
#include "code\modules\research\designs\smelting_designs.dm"
@@ -3451,6 +3459,7 @@
#include "code\modules\research\techweb\nodes\mecha_nodes.dm"
#include "code\modules\research\techweb\nodes\medical_nodes.dm"
#include "code\modules\research\techweb\nodes\misc_nodes.dm"
#include "code\modules\research\techweb\nodes\mod_nodes.dm"
#include "code\modules\research\techweb\nodes\nanites_nodes.dm"
#include "code\modules\research\techweb\nodes\robotics_nodes.dm"
#include "code\modules\research\techweb\nodes\syndicate_nodes.dm"
+151
View File
@@ -0,0 +1,151 @@
import { useBackend } from '../backend';
import { Box, Stack, Section, ByondUi, Slider, Flex, Button } from '../components';
import { Window } from '../layouts';
import { capitalize } from 'common/string';
const colorToMatrix = (param) => {
switch (param) {
case 'red':
return [
1, 0, 0, 0, 0.25, 0.5, 0, 0, 0.25, 0, 0.5, 0, 0, 0, 0, 1, 0, 0, 0, 0,
];
case 'yellow':
return [
0.5, 0.5, 0, 0, 0.5, 0.5, 0, 0, 0.25, 0.25, 0.5, 0, 0, 0, 0, 1, 0, 0, 0,
0,
];
case 'green':
return [
0.5, 0.25, 0, 0, 0, 1, 0, 0, 0, 0.25, 0.5, 0, 0, 0, 0, 1, 0, 0, 0, 0,
];
case 'teal':
return [
0.25, 0.25, 0.25, 0, 0, 0.5, 0.5, 0, 0, 0.5, 0.5, 0, 0, 0, 0, 1, 0, 0,
0, 0,
];
case 'blue':
return [
0.25, 0, 0.25, 0, 0, 0.5, 0.25, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
];
case 'purple':
return [
0.5, 0, 0.5, 0, 0.25, 0.5, 0.25, 0, 0.5, 0, 0.5, 0, 0, 0, 0, 1, 0, 0, 0,
0,
];
}
};
const displayText = (param) => {
switch (param) {
case 'r':
return 'Red';
case 'g':
return 'Green';
case 'b':
return 'Blue';
}
};
export const MODpaint = (props, context) => {
const { act, data } = useBackend(context);
const { mapRef, currentColor } = data;
const [
[rr, rg, rb, ra],
[gr, gg, gb, ga],
[br, bg, bb, ba],
[ar, ag, ab, aa],
[cr, cg, cb, ca],
] = currentColor;
const presets = ['red', 'yellow', 'green', 'teal', 'blue', 'purple'];
const prefixes = ['r', 'g', 'b'];
return (
<Window width={600} height={365}>
<Window.Content>
<Stack fill>
<Stack.Item fill width="30%">
{[0, 1, 2].map((row) => (
<Section
key={row}
title={`${displayText(prefixes[row])} turns to:`}>
{[0, 1, 2].map((col) => (
<Flex key={col}>
<Flex.Item align="left" width="30%">
<Box inline textColor="label">
{`${displayText(prefixes[col])}:`}
</Box>
</Flex.Item>
<Flex.Item align="right" width="70%">
<Slider
inline
textAlign="right"
value={currentColor[row * 4 + col] * 100}
minValue={0}
maxValue={125}
step={1}
stepPixelSize={0.75}
format={(value) => `${value}%`}
onDrag={(e, value) => {
let retColor = currentColor;
retColor[row * 4 + col] = value / 100;
act('transition_color', { color: retColor });
}}
/>
</Flex.Item>
</Flex>
))}
</Section>
))}
</Stack.Item>
<Stack.Item width="25%">
<Section height="70%" title="Presets">
<Box textAlign="center">
{presets.map((preset) => (
<Button
key={preset}
height="50px"
width="50px"
color={preset}
tooltipPosition="top"
tooltip={capitalize(preset)}
onClick={() =>
act('transition_color', { color: colorToMatrix(preset) })}
/>
))}
</Box>
</Section>
<Section textAlign="center" fontSize="28px">
<Button
height="50px"
width="50px"
icon="question"
color="average"
tooltipPosition="top"
tooltip="This is a color matrix. Think of it as editing the image in 3 layers, red, green, and blue, rather than editing the final image like with RGB."
/>
<Button
height="50px"
width="50px"
icon="check"
color="good"
tooltipPosition="top"
tooltip="Confirm changes!"
onClick={() => act('confirm')}
/>
</Section>
</Stack.Item>
<Stack.Item width="45%">
<Section fill title="Preview">
<ByondUi
height="230px"
params={{
id: mapRef,
type: 'map',
}}
/>
</Section>
</Stack.Item>
</Stack>
</Window.Content>
</Window>
);
};
+752
View File
@@ -0,0 +1,752 @@
import { useBackend, useLocalState } from '../backend';
import { Button, ColorBox, LabeledList, ProgressBar, Section, Collapsible, Box, Icon, Stack, Table, Dimmer, NumberInput, Flex, AnimatedNumber, Dropdown } from '../components';
import { Window } from '../layouts';
const ConfigureNumberEntry = (props, context) => {
const { name, value, module_ref } = props;
const { act } = useBackend(context);
return (
<NumberInput
value={value}
minValue={-50}
maxValue={50}
stepPixelSize={5}
width="39px"
onChange={(e, value) =>
act('configure', {
'key': name,
'value': value,
'ref': module_ref,
})}
/>
);
};
const ConfigureBoolEntry = (props, context) => {
const { name, value, module_ref } = props;
const { act } = useBackend(context);
return (
<Button.Checkbox
checked={value}
onClick={() =>
act('configure', {
'key': name,
'value': !value,
'ref': module_ref,
})}
/>
);
};
const ConfigureColorEntry = (props, context) => {
const { name, value, module_ref } = props;
const { act } = useBackend(context);
return (
<>
<Button
icon="paint-brush"
onClick={() =>
act('configure', {
'key': name,
'ref': module_ref,
})}
/>
<ColorBox color={value} mr={0.5} />
</>
);
};
const ConfigureListEntry = (props, context) => {
const { name, value, values, module_ref } = props;
const { act } = useBackend(context);
return (
<Dropdown
displayText={value}
options={values}
onSelected={(value) =>
act('configure', {
'key': name,
'value': value,
'ref': module_ref,
})}
/>
);
};
const ConfigureDataEntry = (props, context) => {
const { name, display_name, type, value, values, module_ref } = props;
const configureEntryTypes = {
number: <ConfigureNumberEntry {...props} />,
bool: <ConfigureBoolEntry {...props} />,
color: <ConfigureColorEntry {...props} />,
list: <ConfigureListEntry {...props} />,
};
return (
<Box>
{display_name}: {configureEntryTypes[type]}
</Box>
);
};
const RadCounter = (props, context) => {
const { active, userradiated, usertoxins, usermaxtoxins, threatlevel }
= props;
return (
<Stack fill textAlign="center">
<Stack.Item grow>
<Section
title="Radiation Level"
color={active && userradiated ? 'bad' : 'good'}>
{active && userradiated ? 'IRRADIATED' : 'RADIATION-FREE'}
</Section>
</Stack.Item>
<Stack.Item grow>
<Section title="Toxins Level">
<ProgressBar
value={active ? usertoxins / usermaxtoxins : 0}
ranges={{
good: [-Infinity, 0.2],
average: [0.2, 0.5],
bad: [0.5, Infinity],
}}>
<AnimatedNumber value={usertoxins} />
</ProgressBar>
</Section>
</Stack.Item>
<Stack.Item grow>
<Section
title="Hazard Level"
color={active && threatlevel ? 'bad' : 'good'}
bold>
{active && threatlevel ? threatlevel : 0}
</Section>
</Stack.Item>
</Stack>
);
};
const HealthAnalyzer = (props, context) => {
const {
active,
userhealth,
usermaxhealth,
userbrute,
userburn,
usertoxin,
useroxy,
} = props;
return (
<>
<Section title="Health">
<ProgressBar
value={active ? userhealth / usermaxhealth : 0}
ranges={{
good: [0.5, Infinity],
average: [0.2, 0.5],
bad: [-Infinity, 0.2],
}}>
<AnimatedNumber value={active ? userhealth : 0} />
</ProgressBar>
</Section>
<Stack textAlign="center">
<Stack.Item grow>
<Section title="Brute">
<ProgressBar
value={active ? userbrute / usermaxhealth : 0}
ranges={{
good: [-Infinity, 0.2],
average: [0.2, 0.5],
bad: [0.5, Infinity],
}}>
<AnimatedNumber value={active ? userbrute : 0} />
</ProgressBar>
</Section>
</Stack.Item>
<Stack.Item grow>
<Section title="Burn">
<ProgressBar
value={active ? userburn / usermaxhealth : 0}
ranges={{
good: [-Infinity, 0.2],
average: [0.2, 0.5],
bad: [0.5, Infinity],
}}>
<AnimatedNumber value={active ? userburn : 0} />
</ProgressBar>
</Section>
</Stack.Item>
<Stack.Item grow>
<Section title="Toxin">
<ProgressBar
value={active ? usertoxin / usermaxhealth : 0}
ranges={{
good: [-Infinity, 0.2],
average: [0.2, 0.5],
bad: [0.5, Infinity],
}}>
<AnimatedNumber value={active ? usertoxin : 0} />
</ProgressBar>
</Section>
</Stack.Item>
<Stack.Item grow>
<Section title="Suffocation">
<ProgressBar
value={active ? useroxy / usermaxhealth : 0}
ranges={{
good: [-Infinity, 0.2],
average: [0.2, 0.5],
bad: [0.5, Infinity],
}}>
<AnimatedNumber value={active ? useroxy : 0} />
</ProgressBar>
</Section>
</Stack.Item>
</Stack>
</>
);
};
const StatusReadout = (props, context) => {
const {
active,
statustime,
statusid,
statushealth,
statusmaxhealth,
statusbrute,
statusburn,
statustoxin,
statusoxy,
statustemp,
statusnutrition,
statusfingerprints,
statusdna,
statusviruses,
} = props;
return (
<>
<Stack textAlign="center">
<Stack.Item grow>
<Section title="Operation Time">
{active ? statustime : '00:00:00'}
</Section>
</Stack.Item>
<Stack.Item grow>
<Section title="Operation Number">
{active ? statusid || '0' : '???'}
</Section>
</Stack.Item>
</Stack>
<Section title="Health">
<ProgressBar
value={active ? statushealth / statusmaxhealth : 0}
ranges={{
good: [0.5, Infinity],
average: [0.2, 0.5],
bad: [-Infinity, 0.2],
}}>
<AnimatedNumber value={active ? statushealth : 0} />
</ProgressBar>
</Section>
<Stack textAlign="center">
<Stack.Item grow>
<Section title="Brute">
<ProgressBar
value={active ? statusbrute / statusmaxhealth : 0}
ranges={{
good: [-Infinity, 0.2],
average: [0.2, 0.5],
bad: [0.5, Infinity],
}}>
<AnimatedNumber value={active ? statusbrute : 0} />
</ProgressBar>
</Section>
</Stack.Item>
<Stack.Item grow>
<Section title="Burn">
<ProgressBar
value={active ? statusburn / statusmaxhealth : 0}
ranges={{
good: [-Infinity, 0.2],
average: [0.2, 0.5],
bad: [0.5, Infinity],
}}>
<AnimatedNumber value={active ? statusburn : 0} />
</ProgressBar>
</Section>
</Stack.Item>
<Stack.Item grow>
<Section title="Toxin">
<ProgressBar
value={active ? statustoxin / statusmaxhealth : 0}
ranges={{
good: [-Infinity, 0.2],
average: [0.2, 0.5],
bad: [0.5, Infinity],
}}>
<AnimatedNumber value={statustoxin} />
</ProgressBar>
</Section>
</Stack.Item>
<Stack.Item grow>
<Section title="Suffocation">
<ProgressBar
value={active ? statusoxy / statusmaxhealth : 0}
ranges={{
good: [-Infinity, 0.2],
average: [0.2, 0.5],
bad: [0.5, Infinity],
}}>
<AnimatedNumber value={statusoxy} />
</ProgressBar>
</Section>
</Stack.Item>
</Stack>
<Stack textAlign="center">
<Stack.Item grow>
<Section title="Body Temperature">{active ? statustemp : 0}</Section>
</Stack.Item>
<Stack.Item grow>
<Section title="Nutrition Status">
{active ? statusnutrition : 0}
</Section>
</Stack.Item>
</Stack>
<Section title="DNA">
<LabeledList>
<LabeledList.Item label="Fingerprints">
{active ? statusfingerprints : '???'}
</LabeledList.Item>
<LabeledList.Item label="Unique Enzymes">
{active ? statusdna : '???'}
</LabeledList.Item>
</LabeledList>
</Section>
{!!active && !!statusviruses && (
<Section title="Diseases">
<Table>
<Table.Row header>
<Table.Cell textAlign="center">
<Button
color="transparent"
icon="signature"
tooltip="Name"
tooltipPosition="top"
/>
</Table.Cell>
<Table.Cell textAlign="center">
<Button
color="transparent"
icon="wind"
tooltip="Type"
tooltipPosition="top"
/>
</Table.Cell>
<Table.Cell textAlign="center">
<Button
color="transparent"
icon="bolt"
tooltip="Stage"
tooltipPosition="top"
/>
</Table.Cell>
<Table.Cell textAlign="center">
<Button
color="transparent"
icon="flask"
tooltip="Cure"
tooltipPosition="top"
/>
</Table.Cell>
</Table.Row>
{statusviruses.map((virus) => {
return (
<Table.Row key={virus.name}>
<Table.Cell textAlign="center">{virus.name}</Table.Cell>
<Table.Cell textAlign="center">{virus.type}</Table.Cell>
<Table.Cell textAlign="center">
{virus.stage}/{virus.maxstage}
</Table.Cell>
<Table.Cell textAlign="center">{virus.cure}</Table.Cell>
</Table.Row>
);
})}
</Table>
</Section>
)}
</>
);
};
const ID2MODULE = {
rad_counter: RadCounter,
health_analyzer: HealthAnalyzer,
status_readout: StatusReadout,
};
const LockedInterface = () => (
<Section align="center" fill>
<Icon color="red" name="exclamation-triangle" size={15} />
<Box fontSize="30px" color="red">
ERROR: INTERFACE UNRESPONSIVE
</Box>
</Section>
);
const LockedModule = (props, context) => {
const { act, data } = useBackend(context);
return (
<Dimmer>
<Stack>
<Stack.Item fontSize="16px" color="blue">
SUIT UNPOWERED
</Stack.Item>
</Stack>
</Dimmer>
);
};
const ConfigureScreen = (props, context) => {
const { configuration_data, module_ref } = props;
const configuration_keys = Object.keys(configuration_data);
return (
<Dimmer backgroundColor="rgba(0, 0, 0, 0.8)">
<Stack vertical>
{configuration_keys.map((key) => {
const data = configuration_data[key];
return (
<Stack.Item key={data.key}>
<ConfigureDataEntry
name={key}
display_name={data.display_name}
type={data.type}
value={data.value}
values={data.values}
module_ref={module_ref}
/>
</Stack.Item>
);
})}
<Stack.Item>
<Box>
<Button
fluid
onClick={props.onExit}
icon="times"
textAlign="center">
Exit
</Button>
</Box>
</Stack.Item>
</Stack>
</Dimmer>
);
};
const displayText = (param) => {
switch (param) {
case 1:
return 'Use';
case 2:
return 'Toggle';
case 3:
return 'Select';
}
};
const ParametersSection = (props, context) => {
const { act, data } = useBackend(context);
const {
active,
malfunctioning,
locked,
open,
selected_module,
complexity,
complexity_max,
wearer_name,
wearer_job,
AI,
} = data;
const status = malfunctioning
? 'Malfunctioning'
: active
? 'Active'
: 'Inactive';
return (
<Section title="Parameters">
<LabeledList>
<LabeledList.Item
label="Status"
buttons={
<Button
icon="power-off"
content={active ? 'Deactivate' : 'Activate'}
onClick={() => act('activate')}
/>
}>
{status}
</LabeledList.Item>
<LabeledList.Item
label="ID Lock"
buttons={
<Button
icon={locked ? 'lock-open' : 'lock'}
content={locked ? 'Unlock' : 'Lock'}
onClick={() => act('lock')}
/>
}>
{locked ? 'Locked' : 'Unlocked'}
</LabeledList.Item>
<LabeledList.Item label="Cover">
{open ? 'Open' : 'Closed'}
</LabeledList.Item>
<LabeledList.Item label="Selected Module">
{selected_module || 'None'}
</LabeledList.Item>
<LabeledList.Item label="Complexity">
{complexity} ({complexity_max})
</LabeledList.Item>
<LabeledList.Item label="Occupant">
{wearer_name}, {wearer_job}
</LabeledList.Item>
<LabeledList.Item label="Onboard AI">{AI || 'None'}</LabeledList.Item>
</LabeledList>
</Section>
);
};
const HardwareSection = (props, context) => {
const { act, data } = useBackend(context);
const {
active,
control,
helmet,
chestplate,
gauntlets,
boots,
cell,
charge,
} = data;
return (
<Section title="Hardware">
<Collapsible title="Parts">
<LabeledList>
<LabeledList.Item label="Control Unit">{control}</LabeledList.Item>
<LabeledList.Item label="Helmet">{helmet || 'None'}</LabeledList.Item>
<LabeledList.Item label="Chestplate">
{chestplate || 'None'}
</LabeledList.Item>
<LabeledList.Item label="Gauntlets">
{gauntlets || 'None'}
</LabeledList.Item>
<LabeledList.Item label="Boots">{boots || 'None'}</LabeledList.Item>
</LabeledList>
</Collapsible>
<Collapsible title="Cell">
{(cell && (
<LabeledList>
<LabeledList.Item label="Cell Type">{cell}</LabeledList.Item>
<LabeledList.Item label="Cell Charge">
<ProgressBar
value={charge / 100}
content={charge + '%'}
ranges={{
good: [0.6, Infinity],
average: [0.3, 0.6],
bad: [-Infinity, 0.3],
}}
/>
</LabeledList.Item>
</LabeledList>
)) || (
<Box color="bad" textAlign="center">
No Cell Detected
</Box>
)}
</Collapsible>
</Section>
);
};
const InfoSection = (props, context) => {
const { act, data } = useBackend(context);
const { active, modules } = data;
const info_modules = modules.filter((module) => !!module.id);
return (
<Section title="Info">
<Stack vertical>
{(info_modules.length !== 0
&& info_modules.map((module) => {
const Module = ID2MODULE[module.id];
return (
<Stack.Item key={module.ref}>
{!active && <LockedModule />}
<Module {...module} active={active} />
</Stack.Item>
);
})) || <Box textAlign="center">No Info Modules Detected</Box>}
</Stack>
</Section>
);
};
const ModuleSection = (props, context) => {
const { act, data } = useBackend(context);
const { complexity_max, modules } = data;
const [configureState, setConfigureState] = useLocalState(
context,
'module_configuration',
null
);
return (
<Section title="Modules" fill>
<Flex direction="column">
{(modules.length !== 0
&& modules.map((module) => {
return (
<Flex.Item key={module.ref}>
<Collapsible title={module.name}>
<Section>
{configureState === module.ref && (
<ConfigureScreen
configuration_data={module.configuration_data}
module_ref={module.ref}
onExit={() => setConfigureState(null)}
/>
)}
<Table>
<Table.Row header>
<Table.Cell textAlign="center">
<Button
color="transparent"
icon="save"
tooltip="Complexity"
tooltipPosition="top"
/>
</Table.Cell>
<Table.Cell textAlign="center">
<Button
color="transparent"
icon="plug"
tooltip="Idle Power Cost"
tooltipPosition="top"
/>
</Table.Cell>
<Table.Cell textAlign="center">
<Button
color="transparent"
icon="lightbulb"
tooltip="Active Power Cost"
tooltipPosition="top"
/>
</Table.Cell>
<Table.Cell textAlign="center">
<Button
color="transparent"
icon="bolt"
tooltip="Use Power Cost"
tooltipPosition="top"
/>
</Table.Cell>
<Table.Cell textAlign="center">
<Button
color="transparent"
icon="hourglass-half"
tooltip="Cooldown"
tooltipPosition="top"
/>
</Table.Cell>
<Table.Cell textAlign="center">
<Button
color="transparent"
icon="tasks"
tooltip="Actions"
tooltipPosition="top"
/>
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell textAlign="center">
{module.complexity}/{complexity_max}
</Table.Cell>
<Table.Cell textAlign="center">
{module.idle_power}
</Table.Cell>
<Table.Cell textAlign="center">
{module.active_power}
</Table.Cell>
<Table.Cell textAlign="center">
{module.use_power}
</Table.Cell>
<Table.Cell textAlign="center">
{(module.cooldown > 0 && module.cooldown / 10) || '0'}
/{module.cooldown_time / 10}s
</Table.Cell>
<Table.Cell textAlign="center">
<Button
onClick={() => act('select', { 'ref': module.ref })}
icon="bullseye"
selected={module.active}
tooltip={displayText(module.module_type)}
tooltipPosition="left"
disabled={!module.module_type}
/>
<Button
onClick={() => setConfigureState(module.ref)}
icon="cog"
selected={configureState === module.ref}
tooltip="Configure"
tooltipPosition="left"
disabled={module.configuration_data.length === 0}
/>
</Table.Cell>
</Table.Row>
</Table>
<Box>{module.description}</Box>
</Section>
</Collapsible>
</Flex.Item>
);
})) || (
<Flex.Item>
<Box textAlign="center">No Modules Detected</Box>
</Flex.Item>
)}
</Flex>
</Section>
);
};
export const MODsuit = (props, context) => {
const { act, data } = useBackend(context);
const { ui_theme, interface_break } = data;
return (
<Window
width={400}
height={525}
theme={ui_theme}
title="MOD Interface Panel"
resizable>
<Window.Content scrollable={!interface_break}>
{(!!interface_break && <LockedInterface />) || (
<Stack vertical fill>
<Stack.Item>
<ParametersSection />
</Stack.Item>
<Stack.Item>
<HardwareSection />
</Stack.Item>
<Stack.Item>
<InfoSection />
</Stack.Item>
<Stack.Item grow>
<ModuleSection />
</Stack.Item>
</Stack>
)}
</Window.Content>
</Window>
);
};