diff --git a/_maps/map_files/Delta/delta.dmm b/_maps/map_files/Delta/delta.dmm
index 171e1ffde1a..a8fefed799d 100644
--- a/_maps/map_files/Delta/delta.dmm
+++ b/_maps/map_files/Delta/delta.dmm
@@ -112194,17 +112194,6 @@
/obj/effect/decal/warning_stripes/west,
/turf/simulated/floor/plasteel,
/area/shuttle/escape)
-"dTU" = (
-/obj/docking_port/stationary{
- dir = 8;
- dwidth = 3;
- height = 5;
- id = "sit_scimaint";
- name = "Cyberiad Science Maint";
- width = 11
- },
-/turf/space,
-/area/space/nearstation)
"dTV" = (
/obj/machinery/power/solar{
name = "Aft Starboard Solar Panel"
@@ -170544,7 +170533,7 @@ aaa
aaa
aaa
aaa
-dTU
+aaa
aaa
aaa
aaa
diff --git a/_maps/map_files/RandomZLevels/evil_santa.dmm b/_maps/map_files/RandomZLevels/evil_santa.dmm
index ff5d4df54b9..0a92eaa1b29 100644
--- a/_maps/map_files/RandomZLevels/evil_santa.dmm
+++ b/_maps/map_files/RandomZLevels/evil_santa.dmm
@@ -650,7 +650,7 @@
/area/awaymission/challenge/start)
"bT" = (
/obj/structure/dispenser/oxygen{
- oxygentanks = 9
+ starting_oxygen_tanks = 9
},
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/turf/simulated/floor/plasteel,
diff --git a/_maps/map_files/RandomZLevels/moonoutpost19.dmm b/_maps/map_files/RandomZLevels/moonoutpost19.dmm
index affcac8c979..26ff48b4d88 100644
--- a/_maps/map_files/RandomZLevels/moonoutpost19.dmm
+++ b/_maps/map_files/RandomZLevels/moonoutpost19.dmm
@@ -2432,7 +2432,7 @@
})
"dy" = (
/obj/structure/dispenser/oxygen{
- oxygentanks = 9
+ starting_oxygen_tanks = 9
},
/obj/machinery/light/small{
active_power_usage = 0;
diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
deleted file mode 100644
index c9691c195b8..00000000000
--- a/code/__DEFINES/components.dm
+++ /dev/null
@@ -1,291 +0,0 @@
-#define SEND_SIGNAL(target, sigtype, arguments...) ( !target.comp_lookup || !target.comp_lookup[sigtype] ? NONE : target._SendSignal(sigtype, list(target, ##arguments)) )
-
-#define SEND_GLOBAL_SIGNAL(sigtype, arguments...) ( SEND_SIGNAL(SSdcs, sigtype, ##arguments) )
-
-//shorthand
-#define GET_COMPONENT_FROM(varname, path, target) var##path/##varname = ##target.GetComponent(##path)
-#define GET_COMPONENT(varname, path) GET_COMPONENT_FROM(varname, path, src)
-
-#define COMPONENT_INCOMPATIBLE 1
-
-// How multiple components of the exact same type are handled in the same datum
-
-#define COMPONENT_DUPE_HIGHLANDER 0 //old component is deleted (default)
-#define COMPONENT_DUPE_ALLOWED 1 //duplicates allowed
-#define COMPONENT_DUPE_UNIQUE 2 //new component is deleted
-#define COMPONENT_DUPE_UNIQUE_PASSARGS 4 //old component is given the initialization args of the new
-
-// All signals. Format:
-// When the signal is called: (signal arguments)
-// All signals send the source datum of the signal as the first argument
-
-// global signals
-// These are signals which can be listened to by any component on any parent
-// start global signals with "!", this used to be necessary but now it's just a formatting choice
-#define COMSIG_GLOB_NEW_Z "!new_z" //from base of datum/controller/subsystem/mapping/proc/add_new_zlevel(): (list/args)
-#define COMSIG_GLOB_VAR_EDIT "!var_edit" //called after a successful var edit somewhere in the world: (list/args)
-#define COMSIG_GLOB_MOB_CREATED "!mob_created" //mob was created somewhere : (mob)
-#define COMSIG_GLOB_MOB_DEATH "!mob_death" //mob died somewhere : (mob , gibbed)
-
-//////////////////////////////////////////////////////////////////
-
-// /datum signals
-#define COMSIG_COMPONENT_ADDED "component_added" //when a component is added to a datum: (/datum/component)
-#define COMSIG_COMPONENT_REMOVING "component_removing" //before a component is removed from a datum because of RemoveComponent: (/datum/component)
-#define COMSIG_PARENT_PREQDELETED "parent_preqdeleted" //before a datum's Destroy() is called: (force), returning a nonzero value will cancel the qdel operation
-#define COMSIG_PARENT_QDELETING "parent_qdeleting" //just before a datum's Destroy() is called: (force), at this point none of the other components chose to interrupt qdel and Destroy will be called
-#define COMSIG_TOPIC "handle_topic" //generic topic handler (usr, href_list)
-
-// /atom signals
-#define COMSIG_PARENT_ATTACKBY "atom_attackby" //from base of atom/attackby(): (/obj/item, /mob/living, params)
- #define COMPONENT_NO_AFTERATTACK 1 //Return this in response if you don't want afterattack to be called
-#define COMSIG_ATOM_HULK_ATTACK "hulk_attack" //from base of atom/attack_hulk(): (/mob/living/carbon/human)
-#define COMSIG_PARENT_EXAMINE "atom_examine" //from base of atom/examine(): (/mob, result)
-#define COMSIG_ATOM_GET_EXAMINE_NAME "atom_examine_name" //from base of atom/get_examine_name(): (/mob, list/overrides)
- //Positions for overrides list
- #define EXAMINE_POSITION_ARTICLE 1
- #define EXAMINE_POSITION_BEFORE 2
- //End positions
- #define COMPONENT_EXNAME_CHANGED 1
-#define COMSIG_ATOM_ENTERED "atom_entered" //from base of atom/Entered(): (atom/movable/entering, /atom)
-#define COMSIG_ATOM_EXITED "atom_exited" //from base of atom/Exited(): (atom/movable/exiting, atom/newloc)
-#define COMSIG_ATOM_EXIT "atom_exit" //from base of atom/Exit(): (/atom/movable/exiting, /atom/newloc)
- #define COMPONENT_ATOM_BLOCK_EXIT 1
-#define COMSIG_ATOM_EX_ACT "atom_ex_act" //from base of atom/ex_act(): (severity, target)
-#define COMSIG_ATOM_EMP_ACT "atom_emp_act" //from base of atom/emp_act(): (severity)
-#define COMSIG_ATOM_FIRE_ACT "atom_fire_act" //from base of atom/fire_act(): (exposed_temperature, exposed_volume)
-#define COMSIG_ATOM_BULLET_ACT "atom_bullet_act" //from base of atom/bullet_act(): (/obj/item/projectile, def_zone)
-#define COMSIG_ATOM_BLOB_ACT "atom_blob_act" //from base of atom/blob_act(): (/obj/structure/blob)
-#define COMSIG_ATOM_ACID_ACT "atom_acid_act" //from base of atom/acid_act(): (acidpwr, acid_volume)
-#define COMSIG_ATOM_EMAG_ACT "atom_emag_act" //from base of atom/emag_act(): ()
-#define COMSIG_ATOM_RAD_ACT "atom_rad_act" //from base of atom/rad_act(intensity)
-#define COMSIG_ATOM_NARSIE_ACT "atom_narsie_act" //from base of atom/narsie_act(): ()
-#define COMSIG_ATOM_RATVAR_ACT "atom_ratvar_act" //from base of atom/ratvar_act(): ()
-#define COMSIG_ATOM_RCD_ACT "atom_rcd_act" //from base of atom/rcd_act(): (/mob, /obj/item/construction/rcd, passed_mode)
-#define COMSIG_ATOM_SING_PULL "atom_sing_pull" //from base of atom/singularity_pull(): (S, current_size)
-#define COMSIG_ATOM_SET_LIGHT "atom_set_light" //from base of atom/set_light(): (l_range, l_power, l_color)
-#define COMSIG_ATOM_DIR_CHANGE "atom_dir_change" //from base of atom/setDir(): (old_dir, new_dir)
-#define COMSIG_ATOM_CONTENTS_DEL "atom_contents_del" //from base of atom/handle_atom_del(): (atom/deleted)
-#define COMSIG_ATOM_HAS_GRAVITY "atom_has_gravity" //from base of atom/has_gravity(): (turf/location, list/forced_gravities)
-#define COMSIG_ATOM_RAD_PROBE "atom_rad_probe" //from proc/get_rad_contents(): ()
- #define COMPONENT_BLOCK_RADIATION 1
-#define COMSIG_ATOM_RAD_CONTAMINATING "atom_rad_contam" //from base of datum/radiation_wave/radiate(): (strength)
- #define COMPONENT_BLOCK_CONTAMINATION 1
-#define COMSIG_ATOM_RAD_WAVE_PASSING "atom_rad_wave_pass" //from base of datum/radiation_wave/check_obstructions(): (datum/radiation_wave, width)
- #define COMPONENT_RAD_WAVE_HANDLED 1
-#define COMSIG_ATOM_CANREACH "atom_can_reach" //from internal loop in atom/movable/proc/CanReach(): (list/next)
- #define COMPONENT_BLOCK_REACH 1
-#define COMSIG_ATOM_SCREWDRIVER_ACT "atom_screwdriver_act" //from base of atom/screwdriver_act(): (mob/living/user, obj/item/I)
-/////////////////
-#define COMSIG_ATOM_ATTACK_GHOST "atom_attack_ghost" //from base of atom/attack_ghost(): (mob/dead/observer/ghost)
-#define COMSIG_ATOM_ATTACK_HAND "atom_attack_hand" //from base of atom/attack_hand(): (mob/user)
-#define COMSIG_ATOM_ATTACK_PAW "atom_attack_paw" //from base of atom/attack_paw(): (mob/user)
- #define COMPONENT_NO_ATTACK_HAND 1 //works on all 3.
-/////////////////
-
-#define COMSIG_ENTER_AREA "enter_area" //from base of area/Entered(): (/area)
-#define COMSIG_EXIT_AREA "exit_area" //from base of area/Exited(): (/area)
-
-#define COMSIG_CLICK "atom_click" //from base of atom/Click(): (location, control, params, mob/user)
-#define COMSIG_CLICK_SHIFT "shift_click" //from base of atom/ShiftClick(): (/mob)
-#define COMSIG_CLICK_CTRL "ctrl_click" //from base of atom/CtrlClickOn(): (/mob)
-#define COMSIG_CLICK_ALT "alt_click" //from base of atom/AltClick(): (/mob)
-#define COMSIG_CLICK_CTRL_SHIFT "ctrl_shift_click" //from base of atom/CtrlShiftClick(/mob)
-#define COMSIG_MOUSEDROP_ONTO "mousedrop_onto" //from base of atom/MouseDrop(): (/atom/over, /mob/user)
- #define COMPONENT_NO_MOUSEDROP 1
-#define COMSIG_MOUSEDROPPED_ONTO "mousedropped_onto" //from base of atom/MouseDrop_T: (/atom/from, /mob/user)
-
-// /area signals
-#define COMSIG_AREA_ENTERED "area_entered" //from base of area/Entered(): (atom/movable/M)
-#define COMSIG_AREA_EXITED "area_exited" //from base of area/Exited(): (atom/movable/M)
-
-// /turf signals
-#define COMSIG_TURF_CHANGE "turf_change" //from base of turf/ChangeTurf(): (path, list/new_baseturfs, flags, list/transferring_comps)
-#define COMSIG_TURF_HAS_GRAVITY "turf_has_gravity" //from base of atom/has_gravity(): (atom/asker, list/forced_gravities)
-
-// /atom/movable signals
-#define COMSIG_MOVABLE_MOVED "movable_moved" //from base of atom/movable/Moved(): (/atom, dir)
-#define COMSIG_MOVABLE_CROSS "movable_cross" //from base of atom/movable/Cross(): (/atom/movable)
-#define COMSIG_MOVABLE_CROSSED "movable_crossed" //from base of atom/movable/Crossed(): (/atom/movable)
-#define COMSIG_CROSSED_MOVABLE "crossed_movable" //when we cross over something (calling Crossed() on that atom)
-#define COMSIG_MOVABLE_UNCROSSED "movable_uncrossed" //from base of atom/movable/Uncrossed(): (/atom/movable)
-#define COMSIG_MOVABLE_UNCROSS "movable_uncross" //from base of atom/movable/Uncross(): (/atom/movable)
- #define COMPONENT_MOVABLE_BLOCK_UNCROSS 1
-#define COMSIG_MOVABLE_BUMP "movable_bump" //from base of atom/movable/Bump(): (/atom)
-#define COMSIG_MOVABLE_IMPACT "movable_impact" //from base of atom/movable/throw_impact(): (/atom/hit_atom, /datum/thrownthing/throwingdatum)
-#define COMSIG_MOVABLE_IMPACT_ZONE "item_impact_zone" //from base of mob/living/hitby(): (mob/living/target, hit_zone)
-#define COMSIG_MOVABLE_BUCKLE "buckle" //from base of atom/movable/buckle_mob(): (mob, force)
-#define COMSIG_MOVABLE_UNBUCKLE "unbuckle" //from base of atom/movable/unbuckle_mob(): (mob, force)
-#define COMSIG_MOVABLE_PRE_THROW "movable_pre_throw" //from base of atom/movable/throw_at(): (list/args)
- #define COMPONENT_CANCEL_THROW 1
-#define COMSIG_MOVABLE_POST_THROW "movable_post_throw" //from base of atom/movable/throw_at(): (datum/thrownthing, spin)
-#define COMSIG_MOVABLE_Z_CHANGED "movable_ztransit" //from base of atom/movable/onTransitZ(): (old_z, new_z)
-#define COMSIG_MOVABLE_HEAR "movable_hear" //from base of atom/movable/Hear(): (message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
-#define COMSIG_MOVABLE_DISPOSING "movable_disposing" //called when the movable is added to a disposal holder object for disposal movement: (obj/structure/disposalholder/holder, obj/machinery/disposal/source)
-
-// /mob signals
-#define COMSIG_MOB_DEATH "mob_death" //from base of mob/death(): (gibbed)
-#define COMSIG_MOB_CLICKON "mob_clickon" //from base of mob/clickon(): (atom/A, params)
- #define COMSIG_MOB_CANCEL_CLICKON 1
-#define COMSIG_MOB_ALLOWED "mob_allowed" //from base of obj/allowed(mob/M): (/obj) returns bool, if TRUE the mob has id access to the obj
-#define COMSIG_MOB_RECEIVE_MAGIC "mob_receive_magic" //from base of mob/anti_magic_check(): (magic, holy, protection_sources)
- #define COMPONENT_BLOCK_MAGIC 1
-#define COMSIG_MOB_HUD_CREATED "mob_hud_created" //from base of mob/create_mob_hud(): ()
-#define COMSIG_MOB_ATTACK_HAND "mob_attack_hand" //from base of
-#define COMSIG_MOB_ITEM_ATTACK "mob_item_attack" //from base of /obj/item/attack(): (mob/M, mob/user)
-#define COMSIG_MOB_ITEM_AFTERATTACK "mob_item_afterattack" //from base of obj/item/afterattack(): (atom/target, mob/user, proximity_flag, click_parameters)
-#define COMSIG_MOB_ATTACK_RANGED "mob_attack_ranged" //from base of mob/RangedAttack(): (atom/A, params)
-#define COMSIG_MOB_THROW "mob_throw" //from base of /mob/throw_item(): (atom/target)
-#define COMSIG_MOB_UPDATE_SIGHT "mob_update_sight" //from base of /mob/update_sight(): ()
-
-// /mob/living signals
-#define COMSIG_LIVING_RESIST "living_resist" //from base of mob/living/resist() (/mob/living)
-#define COMSIG_LIVING_IGNITED "living_ignite" //from base of mob/living/IgniteMob() (/mob/living)
-#define COMSIG_LIVING_EXTINGUISHED "living_extinguished" //from base of mob/living/ExtinguishMob() (/mob/living)
-#define COMSIG_LIVING_ELECTROCUTE_ACT "living_electrocute_act" //from base of mob/living/electrocute_act(): (shock_damage)
-#define COMSIG_LIVING_MINOR_SHOCK "living_minor_shock" //sent by stuff like stunbatons and tasers: ()
-
-//ALL OF THESE DO NOT TAKE INTO ACCOUNT WHETHER AMOUNT IS 0 OR LOWER AND ARE SENT REGARDLESS!
-#define COMSIG_LIVING_STATUS_STUN "living_stun" //from base of mob/living/Stun() (amount, update, ignore)
-#define COMSIG_LIVING_STATUS_KNOCKDOWN "living_knockdown" //from base of mob/living/Knockdown() (amount, update, ignore)
-#define COMSIG_LIVING_STATUS_PARALYZE "living_paralyze" //from base of mob/living/Paralyze() (amount, update, ignore)
-#define COMSIG_LIVING_STATUS_IMMOBILIZE "living_immobilize" //from base of mob/living/Immobilize() (amount, update, ignore)
-#define COMSIG_LIVING_STATUS_UNCONSCIOUS "living_unconscious" //from base of mob/living/Unconscious() (amount, update, ignore)
-#define COMSIG_LIVING_STATUS_SLEEP "living_sleeping" //from base of mob/living/Sleeping() (amount, update, ignore)
- #define COMPONENT_NO_STUN 1 //For all of them
-
-// /mob/living/carbon signals
-#define COMSIG_CARBON_SOUNDBANG "carbon_soundbang" //from base of mob/living/carbon/soundbang_act(): (list(intensity))
-
-// /mob/living/simple_animal/hostile signals
-#define COMSIG_HOSTILE_ATTACKINGTARGET "hostile_attackingtarget"
- #define COMPONENT_HOSTILE_NO_ATTACK 1
-
-// /obj signals
-#define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct" //from base of obj/deconstruct(): (disassembled)
-#define COMSIG_OBJ_SETANCHORED "obj_setanchored" //called in /obj/structure/setAnchored(): (value)
-#define COMSIG_OBJ_UPDATE_ICON "obj_update_icon" //called in /obj/update_icon()
-
-
-// /obj/item signals
-#define COMSIG_ITEM_ATTACK "item_attack" //from base of obj/item/attack(): (/mob/living/target, /mob/living/user)
-#define COMSIG_ITEM_ATTACK_SELF "item_attack_self" //from base of obj/item/attack_self(): (/mob)
- #define COMPONENT_NO_INTERACT 1
-#define COMSIG_ITEM_ATTACK_OBJ "item_attack_obj" //from base of obj/item/attack_obj(): (/obj, /mob)
- #define COMPONENT_NO_ATTACK_OBJ 1
-#define COMSIG_ITEM_PRE_ATTACK "item_pre_attack" //from base of obj/item/pre_attack(): (atom/target, mob/user, params)
- #define COMPONENT_NO_ATTACK 1
-#define COMSIG_ITEM_AFTERATTACK "item_afterattack" //from base of obj/item/afterattack(): (atom/target, mob/user, params)
-#define COMSIG_ITEM_EQUIPPED "item_equip" //from base of obj/item/equipped(): (/mob/equipper, slot)
-#define COMSIG_ITEM_DROPPED "item_drop" //from base of obj/item/dropped(): (mob/user)
-#define COMSIG_ITEM_PICKUP "item_pickup" //from base of obj/item/pickup(): (/mob/taker)
-#define COMSIG_ITEM_ATTACK_ZONE "item_attack_zone" //from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone)
-#define COMSIG_ITEM_IMBUE_SOUL "item_imbue_soul" //return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/targeted/lichdom/cast(): (mob/user)
-#define COMSIG_ITEM_HIT_REACT "item_hit_react" //from base of obj/item/hit_reaction(): (list/args)
-
-// /obj/item/clothing signals
-#define COMSIG_SHOES_STEP_ACTION "shoes_step_action" //from base of obj/item/clothing/shoes/proc/step_action(): ()
-
-// /obj/item/implant signals
-#define COMSIG_IMPLANT_ACTIVATED "implant_activated" //from base of /obj/item/implant/proc/activate(): ()
-#define COMSIG_IMPLANT_IMPLANTING "implant_implanting" //from base of /obj/item/implant/proc/implant(): (list/args)
- #define COMPONENT_STOP_IMPLANTING 1
-#define COMSIG_IMPLANT_OTHER "implant_other" //called on already installed implants when a new one is being added in /obj/item/implant/proc/implant(): (list/args, obj/item/implant/new_implant)
- //#define COMPONENT_STOP_IMPLANTING 1 //The name makes sense for both
- #define COMPONENT_DELETE_NEW_IMPLANT 2
- #define COMPONENT_DELETE_OLD_IMPLANT 4
-#define COMSIG_IMPLANT_EXISTING_UPLINK "implant_uplink_exists" //called on implants being implanted into someone with an uplink implant: (datum/component/uplink)
- //This uses all return values of COMSIG_IMPLANT_OTHER
-
-// /obj/item/pda signals
-#define COMSIG_PDA_CHANGE_RINGTONE "pda_change_ringtone" //called on pda when the user changes the ringtone: (mob/living/user, new_ringtone)
- #define COMPONENT_STOP_RINGTONE_CHANGE 1
-
-// /obj/item/radio signals
-#define COMSIG_RADIO_NEW_FREQUENCY "radio_new_frequency" //called from base of /obj/item/radio/proc/set_frequency(): (list/args)
-
-// /obj/item/pen signals
-#define COMSIG_PEN_ROTATED "pen_rotated" //called after rotation in /obj/item/pen/attack_self(): (rotation, mob/living/carbon/user)
-
-
-// /mob/living/carbon/human signals
-#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack" //from mob/living/carbon/human/UnarmedAttack(): (atom/target)
-#define COMSIG_HUMAN_MELEE_UNARMED_ATTACKBY "human_melee_unarmed_attackby" //from mob/living/carbon/human/UnarmedAttack(): (mob/living/carbon/human/attacker)
-#define COMSIG_HUMAN_DISARM_HIT "human_disarm_hit" //Hit by successful disarm attack (mob/living/carbon/human/attacker,zone_targeted)
-
-// /datum/species signals
-#define COMSIG_SPECIES_GAIN "species_gain" //from datum/species/on_species_gain(): (datum/species/new_species, datum/species/old_species)
-#define COMSIG_SPECIES_LOSS "species_loss" //from datum/species/on_species_loss(): (datum/species/lost_species)
-
-/*******Component Specific Signals*******/
-//Janitor
-#define COMSIG_TURF_IS_WET "check_turf_wet" //(): Returns bitflags of wet values.
-#define COMSIG_TURF_MAKE_DRY "make_turf_try" //(max_strength, immediate, duration_decrease = INFINITY): Returns bool.
-#define COMSIG_COMPONENT_CLEAN_ACT "clean_act" //called on an object to clean it of cleanables. Usualy with soap: (num/strength)
-
-//Food
-#define COMSIG_FOOD_EATEN "food_eaten" //from base of obj/item/reagent_containers/food/snacks/attack(): (mob/living/eater, mob/feeder)
-
-//Mood
-#define COMSIG_ADD_MOOD_EVENT "add_mood" //Called when you send a mood event from anywhere in the code.
-#define COMSIG_CLEAR_MOOD_EVENT "clear_mood" //Called when you clear a mood event from anywhere in the code.
-
-//NTnet
-#define COMSIG_COMPONENT_NTNET_RECEIVE "ntnet_receive" //called on an object by its NTNET connection component on receive. (sending_id(number), sending_netname(text), data(datum/netdata))
-
-//Nanites
-#define COMSIG_HAS_NANITES "has_nanites" //() returns TRUE if nanites are found
-#define COMSIG_NANITE_GET_PROGRAMS "nanite_get_programs" //(list/nanite_programs) - makes the input list a copy the nanites' program list
-#define COMSIG_NANITE_SET_VOLUME "nanite_set_volume" //(amount) Sets current nanite volume to the given amount
-#define COMSIG_NANITE_ADJUST_VOLUME "nanite_adjust" //(amount) Adjusts nanite volume by the given amount
-#define COMSIG_NANITE_SET_MAX_VOLUME "nanite_set_max_volume" //(amount) Sets maximum nanite volume to the given amount
-#define COMSIG_NANITE_SET_CLOUD "nanite_set_cloud" //(amount(0-100)) Sets cloud ID to the given amount
-#define COMSIG_NANITE_SET_SAFETY "nanite_set_safety" //(amount) Sets safety threshold to the given amount
-#define COMSIG_NANITE_SET_REGEN "nanite_set_regen" //(amount) Sets regeneration rate to the given amount
-#define COMSIG_NANITE_SIGNAL "nanite_signal" //(code(1-9999)) Called when sending a nanite signal to a mob.
-#define COMSIG_NANITE_SCAN "nanite_scan" //(mob/user, full_scan) - sends to chat a scan of the nanites to the user, returns TRUE if nanites are detected
-#define COMSIG_NANITE_UI_DATA "nanite_ui_data" //(list/data, scan_level) - adds nanite data to the given data list - made for ui_data procs
-#define COMSIG_NANITE_ADD_PROGRAM "nanite_add_program" //(datum/nanite_program/new_program, datum/nanite_program/source_program) Called when adding a program to a nanite component
- #define COMPONENT_PROGRAM_INSTALLED 1 //Installation successful
- #define COMPONENT_PROGRAM_NOT_INSTALLED 2 //Installation failed, but there are still nanites
-#define COMSIG_NANITE_SYNC "nanite_sync" //(datum/component/nanites, full_overwrite, copy_activation) Called to sync the target's nanites to a given nanite component
-
-// /datum/component/storage signals
-#define COMSIG_CONTAINS_STORAGE "is_storage" //() - returns bool.
-#define COMSIG_TRY_STORAGE_INSERT "storage_try_insert" //(obj/item/inserting, mob/user, silent, force) - returns bool
-#define COMSIG_TRY_STORAGE_SHOW "storage_show_to" //(mob/show_to, force) - returns bool.
-#define COMSIG_TRY_STORAGE_HIDE_FROM "storage_hide_from" //(mob/hide_from) - returns bool
-#define COMSIG_TRY_STORAGE_HIDE_ALL "storage_hide_all" //returns bool
-#define COMSIG_TRY_STORAGE_SET_LOCKSTATE "storage_lock_set_state" //(newstate)
-#define COMSIG_IS_STORAGE_LOCKED "storage_get_lockstate" //() - returns bool. MUST CHECK IF STORAGE IS THERE FIRST!
-#define COMSIG_TRY_STORAGE_TAKE_TYPE "storage_take_type" //(type, atom/destination, amount = INFINITY, check_adjacent, force, mob/user, list/inserted) - returns bool - type can be a list of types.
-#define COMSIG_TRY_STORAGE_FILL_TYPE "storage_fill_type" //(type, amount = INFINITY, force = FALSE) //don't fuck this up. Force will ignore max_items, and amount is normally clamped to max_items.
-#define COMSIG_TRY_STORAGE_TAKE "storage_take_obj" //(obj, new_loc, force = FALSE) - returns bool
-#define COMSIG_TRY_STORAGE_QUICK_EMPTY "storage_quick_empty" //(loc) - returns bool - if loc is null it will dump at parent location.
-#define COMSIG_TRY_STORAGE_RETURN_INVENTORY "storage_return_inventory" //(list/list_to_inject_results_into, recursively_search_inside_storages = TRUE)
-#define COMSIG_TRY_STORAGE_CAN_INSERT "storage_can_equip" //(obj/item/insertion_candidate, mob/user, silent) - returns bool
-
-// /datum/action signals
-#define COMSIG_ACTION_TRIGGER "action_trigger" //from base of datum/action/proc/Trigger(): (datum/action)
- #define COMPONENT_ACTION_BLOCK_TRIGGER 1
-
-/*******Non-Signal Component Related Defines*******/
-
-//Redirection component init flags
-#define REDIRECT_TRANSFER_WITH_TURF 1
-
-//Arch
-#define ARCH_PROB "probability" //Probability for each item
-#define ARCH_MAXDROP "max_drop_amount" //each item's max drop amount
-
-//Ouch my toes!
-#define CALTROP_BYPASS_SHOES 1
-#define CALTROP_IGNORE_WALKERS 2
-
-//Xenobio hotkeys
-#define COMSIG_XENO_SLIME_CLICK_CTRL "xeno_slime_click_ctrl" //from slime CtrlClickOn(): (/mob)
-#define COMSIG_XENO_SLIME_CLICK_ALT "xeno_slime_click_alt" //from slime AltClickOn(): (/mob)
-#define COMSIG_XENO_SLIME_CLICK_SHIFT "xeno_slime_click_shift" //from slime ShiftClickOn(): (/mob)
-#define COMSIG_XENO_TURF_CLICK_SHIFT "xeno_turf_click_shift" //from turf ShiftClickOn(): (/mob)
-#define COMSIG_XENO_TURF_CLICK_CTRL "xeno_turf_click_alt" //from turf AltClickOn(): (/mob)
-#define COMSIG_XENO_MONKEY_CLICK_CTRL "xeno_monkey_click_ctrl" //from monkey CtrlClickOn(): (/mob)
diff --git a/code/__DEFINES/dcs/flags.dm b/code/__DEFINES/dcs/flags.dm
new file mode 100644
index 00000000000..128c9f19387
--- /dev/null
+++ b/code/__DEFINES/dcs/flags.dm
@@ -0,0 +1,41 @@
+/// Return this from `/datum/component/Initialize` or `datum/component/OnTransfer` to have the component be deleted if it's applied to an incorrect type.
+/// `parent` must not be modified if this is to be returned.
+/// This will be noted in the runtime logs
+#define COMPONENT_INCOMPATIBLE 1
+/// Returned in PostTransfer to prevent transfer, similar to `COMPONENT_INCOMPATIBLE`
+#define COMPONENT_NOTRANSFER 2
+
+/// Return value to cancel attaching
+#define ELEMENT_INCOMPATIBLE 1
+
+// /datum/element flags
+/// Causes the detach proc to be called when the host object is being deleted
+#define ELEMENT_DETACH (1 << 0)
+/**
+ * Only elements created with the same arguments given after `id_arg_index` share an element instance
+ * The arguments are the same when the text and number values are the same and all other values have the same ref
+ */
+#define ELEMENT_BESPOKE (1 << 1)
+
+// How multiple components of the exact same type are handled in the same datum
+/// old component is deleted (default)
+#define COMPONENT_DUPE_HIGHLANDER 0
+/// duplicates allowed
+#define COMPONENT_DUPE_ALLOWED 1
+/// new component is deleted
+#define COMPONENT_DUPE_UNIQUE 2
+/// old component is given the initialization args of the new
+#define COMPONENT_DUPE_UNIQUE_PASSARGS 4
+/// each component of the same type is consulted as to whether the duplicate should be allowed
+#define COMPONENT_DUPE_SELECTIVE 5
+
+//Redirection component init flags
+#define REDIRECT_TRANSFER_WITH_TURF 1
+
+//Arch
+#define ARCH_PROB "probability" //Probability for each item
+#define ARCH_MAXDROP "max_drop_amount" //each item's max drop amount
+
+//Ouch my toes!
+#define CALTROP_BYPASS_SHOES 1
+#define CALTROP_IGNORE_WALKERS 2
diff --git a/code/__DEFINES/dcs/helpers.dm b/code/__DEFINES/dcs/helpers.dm
new file mode 100644
index 00000000000..144e94f1fe0
--- /dev/null
+++ b/code/__DEFINES/dcs/helpers.dm
@@ -0,0 +1,15 @@
+/// Used to trigger signals and call procs registered for that signal
+/// The datum hosting the signal is automaticaly added as the first argument
+/// Returns a bitfield gathered from all registered procs
+/// Arguments given here are packaged in a list and given to _SendSignal
+#define SEND_SIGNAL(target, sigtype, arguments...) ( !target.comp_lookup || !target.comp_lookup[sigtype] ? NONE : target._SendSignal(sigtype, list(target, ##arguments)) )
+
+#define SEND_GLOBAL_SIGNAL(sigtype, arguments...) ( SEND_SIGNAL(SSdcs, sigtype, ##arguments) )
+
+/// A wrapper for _AddElement that allows us to pretend we're using normal named arguments
+#define AddElement(arguments...) _AddElement(list(##arguments))
+/// A wrapper for _RemoveElement that allows us to pretend we're using normal named arguments
+#define RemoveElement(arguments...) _RemoveElement(list(##arguments))
+
+/// A wrapper for _AddComponent that allows us to pretend we're using normal named arguments
+#define AddComponent(arguments...) _AddComponent(list(##arguments))
diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
new file mode 100644
index 00000000000..10aa1718dda
--- /dev/null
+++ b/code/__DEFINES/dcs/signals.dm
@@ -0,0 +1,728 @@
+// All signals. Format:
+// When the signal is called: (signal arguments)
+// All signals send the source datum of the signal as the first argument
+
+// global signals
+// These are signals which can be listened to by any component on any parent
+// start global signals with "!", this used to be necessary but now it's just a formatting choice
+
+///from base of datum/controller/subsystem/mapping/proc/add_new_zlevel(): (list/args)
+#define COMSIG_GLOB_NEW_Z "!new_z"
+/// called after a successful var edit somewhere in the world: (list/args)
+#define COMSIG_GLOB_VAR_EDIT "!var_edit"
+/// called after an explosion happened : (epicenter, devastation_range, heavy_impact_range, light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range)
+#define COMSIG_GLOB_EXPLOSION "!explosion"
+/// mob was created somewhere : (mob)
+#define COMSIG_GLOB_MOB_CREATED "!mob_created"
+/// mob died somewhere : (mob , gibbed)
+#define COMSIG_GLOB_MOB_DEATH "!mob_death"
+/// global living say plug - use sparingly: (mob/speaker , message)
+#define COMSIG_GLOB_LIVING_SAY_SPECIAL "!say_special"
+/// called by datum/cinematic/play() : (datum/cinematic/new_cinematic)
+#define COMSIG_GLOB_PLAY_CINEMATIC "!play_cinematic"
+ #define COMPONENT_GLOB_BLOCK_CINEMATIC (1<<0)
+/// ingame button pressed (/obj/machinery/button/button)
+#define COMSIG_GLOB_BUTTON_PRESSED "!button_pressed"
+
+/// signals from globally accessible objects
+
+///from SSsun when the sun changes position : (azimuth)
+#define COMSIG_SUN_MOVED "sun_moved"
+
+//////////////////////////////////////////////////////////////////
+
+// /datum signals
+/// when a component is added to a datum: (/datum/component)
+#define COMSIG_COMPONENT_ADDED "component_added"
+/// before a component is removed from a datum because of RemoveComponent: (/datum/component)
+#define COMSIG_COMPONENT_REMOVING "component_removing"
+/// before a datum's Destroy() is called: (force), returning a nonzero value will cancel the qdel operation
+#define COMSIG_PARENT_PREQDELETED "parent_preqdeleted"
+/// just before a datum's Destroy() is called: (force), at this point none of the other components chose to interrupt qdel and Destroy will be called
+#define COMSIG_PARENT_QDELETING "parent_qdeleting"
+/// generic topic handler (usr, href_list)
+#define COMSIG_TOPIC "handle_topic"
+
+/// fires on the target datum when an element is attached to it (/datum/element)
+#define COMSIG_ELEMENT_ATTACH "element_attach"
+/// fires on the target datum when an element is attached to it (/datum/element)
+#define COMSIG_ELEMENT_DETACH "element_detach"
+
+// /atom signals
+///from base of atom/proc/Initialize(): sent any time a new atom is created
+#define COMSIG_ATOM_CREATED "atom_created"
+//from SSatoms InitAtom - Only if the atom was not deleted or failed initialization
+#define COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE "atom_init_success"
+///from base of atom/attackby(): (/obj/item, /mob/living, params)
+#define COMSIG_PARENT_ATTACKBY "atom_attackby"
+///Return this in response if you don't want afterattack to be called
+ #define COMPONENT_NO_AFTERATTACK (1<<0)
+///from base of atom/attack_hulk(): (/mob/living/carbon/human)
+#define COMSIG_ATOM_HULK_ATTACK "hulk_attack"
+///from base of atom/animal_attack(): (/mob/user)
+#define COMSIG_ATOM_ATTACK_ANIMAL "attack_animal"
+///from base of atom/examine(): (/mob)
+#define COMSIG_PARENT_EXAMINE "atom_examine"
+///from base of atom/get_examine_name(): (/mob, list/overrides)
+#define COMSIG_ATOM_GET_EXAMINE_NAME "atom_examine_name"
+ //Positions for overrides list
+ #define EXAMINE_POSITION_ARTICLE (1<<0)
+ #define EXAMINE_POSITION_BEFORE (1<<1)
+ //End positions
+ #define COMPONENT_EXNAME_CHANGED (1<<0)
+///from base of atom/update_icon(): ()
+#define COMSIG_ATOM_UPDATE_ICON "atom_update_icon"
+ #define COMSIG_ATOM_NO_UPDATE_ICON_STATE (1<<0)
+ #define COMSIG_ATOM_NO_UPDATE_OVERLAYS (1<<1)
+///from base of atom/update_overlays(): (list/new_overlays)
+#define COMSIG_ATOM_UPDATE_OVERLAYS "atom_update_overlays"
+///from base of atom/update_icon(): (signalOut, did_anything)
+#define COMSIG_ATOM_UPDATED_ICON "atom_updated_icon"
+///from base of atom/Entered(): (atom/movable/entering, /atom)
+#define COMSIG_ATOM_ENTERED "atom_entered"
+///from base of atom/Exit(): (/atom/movable/exiting, /atom/newloc)
+#define COMSIG_ATOM_EXIT "atom_exit"
+ #define COMPONENT_ATOM_BLOCK_EXIT (1<<0)
+///from base of atom/Exited(): (atom/movable/exiting, atom/newloc)
+#define COMSIG_ATOM_EXITED "atom_exited"
+///from base of atom/Bumped(): (/atom/movable)
+#define COMSIG_ATOM_BUMPED "atom_bumped"
+///from base of atom/ex_act(): (severity, target)
+#define COMSIG_ATOM_EX_ACT "atom_ex_act"
+///from base of atom/emp_act(): (severity)
+#define COMSIG_ATOM_EMP_ACT "atom_emp_act"
+///from base of atom/fire_act(): (exposed_temperature, exposed_volume)
+#define COMSIG_ATOM_FIRE_ACT "atom_fire_act"
+///from base of atom/bullet_act(): (/obj/projectile, def_zone)
+#define COMSIG_ATOM_BULLET_ACT "atom_bullet_act"
+///from base of atom/blob_act(): (/obj/structure/blob)
+#define COMSIG_ATOM_BLOB_ACT "atom_blob_act"
+///from base of atom/acid_act(): (acidpwr, acid_volume)
+#define COMSIG_ATOM_ACID_ACT "atom_acid_act"
+///from base of atom/emag_act(): (/mob/user)
+#define COMSIG_ATOM_EMAG_ACT "atom_emag_act"
+///from base of atom/rad_act(intensity)
+#define COMSIG_ATOM_RAD_ACT "atom_rad_act"
+///from base of atom/narsie_act(): ()
+#define COMSIG_ATOM_NARSIE_ACT "atom_narsie_act"
+///from base of atom/rcd_act(): (/mob, /obj/item/construction/rcd, passed_mode)
+#define COMSIG_ATOM_RCD_ACT "atom_rcd_act"
+///from base of atom/singularity_pull(): (S, current_size)
+#define COMSIG_ATOM_SING_PULL "atom_sing_pull"
+///from obj/machinery/bsa/full/proc/fire(): ()
+#define COMSIG_ATOM_BSA_BEAM "atom_bsa_beam_pass"
+ #define COMSIG_ATOM_BLOCKS_BSA_BEAM (1<<0)
+///from base of atom/set_light(): (l_range, l_power, l_color)
+#define COMSIG_ATOM_SET_LIGHT "atom_set_light"
+///from base of atom/setDir(): (old_dir, new_dir)
+#define COMSIG_ATOM_DIR_CHANGE "atom_dir_change"
+///from base of atom/handle_atom_del(): (atom/deleted)
+#define COMSIG_ATOM_CONTENTS_DEL "atom_contents_del"
+///from base of atom/has_gravity(): (turf/location, list/forced_gravities)
+#define COMSIG_ATOM_HAS_GRAVITY "atom_has_gravity"
+///from proc/get_rad_contents(): ()
+#define COMSIG_ATOM_RAD_PROBE "atom_rad_probe"
+ #define COMPONENT_BLOCK_RADIATION (1<<0)
+///from base of datum/radiation_wave/radiate(): (strength)
+#define COMSIG_ATOM_RAD_CONTAMINATING "atom_rad_contam"
+ #define COMPONENT_BLOCK_CONTAMINATION (1<<0)
+///from base of datum/radiation_wave/check_obstructions(): (datum/radiation_wave, width)
+#define COMSIG_ATOM_RAD_WAVE_PASSING "atom_rad_wave_pass"
+ #define COMPONENT_RAD_WAVE_HANDLED (1<<0)
+///from internal loop in atom/movable/proc/CanReach(): (list/next)
+#define COMSIG_ATOM_CANREACH "atom_can_reach"
+ #define COMPONENT_BLOCK_REACH (1<<0)
+///from base of atom/screwdriver_act(): (mob/living/user, obj/item/I)
+#define COMSIG_ATOM_SCREWDRIVER_ACT "atom_screwdriver_act"
+///from base of atom/wrench_act(): (mob/living/user, obj/item/I)
+#define COMSIG_ATOM_WRENCH_ACT "atom_wrench_act"
+///from base of atom/multitool_act(): (mob/living/user, obj/item/I)
+#define COMSIG_ATOM_MULTITOOL_ACT "atom_multitool_act"
+///from base of atom/welder_act(): (mob/living/user, obj/item/I)
+#define COMSIG_ATOM_WELDER_ACT "atom_welder_act"
+///from base of atom/wirecutter_act(): (mob/living/user, obj/item/I)
+#define COMSIG_ATOM_WIRECUTTER_ACT "atom_wirecutter_act"
+///from base of atom/crowbar_act(): (mob/living/user, obj/item/I)
+#define COMSIG_ATOM_CROWBAR_ACT "atom_crowbar_act"
+///from base of atom/analyser_act(): (mob/living/user, obj/item/I)
+#define COMSIG_ATOM_ANALYSER_ACT "atom_analyser_act"
+ #define COMPONENT_BLOCK_TOOL_ATTACK (1<<0)
+///called when teleporting into a protected turf: (channel, turf/origin)
+#define COMSIG_ATOM_INTERCEPT_TELEPORT "intercept_teleport"
+ #define COMPONENT_BLOCK_TELEPORT (1<<0)
+///called when an atom is added to the hearers on get_hearers_in_view(): (list/processing_list, list/hearers)
+#define COMSIG_ATOM_HEARER_IN_VIEW "atom_hearer_in_view"
+///called when an atom starts orbiting another atom: (atom)
+#define COMSIG_ATOM_ORBIT_BEGIN "atom_orbit_begin"
+///called when an atom stops orbiting another atom: (atom)
+#define COMSIG_ATOM_ORBIT_STOP "atom_orbit_stop"
+/////////////////
+///from base of atom/attack_ghost(): (mob/dead/observer/ghost)
+#define COMSIG_ATOM_ATTACK_GHOST "atom_attack_ghost"
+///from base of atom/attack_hand(): (mob/user)
+#define COMSIG_ATOM_ATTACK_HAND "atom_attack_hand"
+///from base of atom/attack_paw(): (mob/user)
+#define COMSIG_ATOM_ATTACK_PAW "atom_attack_paw"
+ #define COMPONENT_NO_ATTACK_HAND (1<<0) //works on all 3.
+//This signal return value bitflags can be found in __DEFINES/misc.dm
+
+///called for each movable in a turf contents on /turf/zImpact(): (atom/movable/A, levels)
+#define COMSIG_ATOM_INTERCEPT_Z_FALL "movable_intercept_z_impact"
+///called on a movable (NOT living) when someone starts pulling it (atom/movable/puller, state, force)
+#define COMSIG_ATOM_START_PULL "movable_start_pull"
+///called on /living when someone starts pulling it (atom/movable/puller, state, force)
+#define COMSIG_LIVING_START_PULL "living_start_pull"
+
+/////////////////
+
+///from base of area/Entered(): (/area)
+#define COMSIG_ENTER_AREA "enter_area"
+///from base of area/Exited(): (/area)
+#define COMSIG_EXIT_AREA "exit_area"
+///from base of atom/Click(): (location, control, params, mob/user)
+#define COMSIG_CLICK "atom_click"
+///from base of atom/ShiftClick(): (/mob)
+#define COMSIG_CLICK_SHIFT "shift_click"
+ #define COMPONENT_ALLOW_EXAMINATE (1<<0) //Allows the user to examinate regardless of client.eye.
+///from base of atom/CtrlClickOn(): (/mob)
+#define COMSIG_CLICK_CTRL "ctrl_click"
+///from base of atom/AltClick(): (/mob)
+#define COMSIG_CLICK_ALT "alt_click"
+///from base of atom/CtrlShiftClick(/mob)
+#define COMSIG_CLICK_CTRL_SHIFT "ctrl_shift_click"
+///from base of atom/MouseDrop(): (/atom/over, /mob/user)
+#define COMSIG_MOUSEDROP_ONTO "mousedrop_onto"
+ #define COMPONENT_NO_MOUSEDROP (1<<0)
+///from base of atom/MouseDrop_T: (/atom/from, /mob/user)
+#define COMSIG_MOUSEDROPPED_ONTO "mousedropped_onto"
+
+// /area signals
+
+///from base of area/Entered(): (atom/movable/M)
+#define COMSIG_AREA_ENTERED "area_entered"
+///from base of area/Exited(): (atom/movable/M)
+#define COMSIG_AREA_EXITED "area_exited"
+
+// /turf signals
+
+///from base of turf/ChangeTurf(): (path, list/new_baseturfs, flags, list/transferring_comps)
+#define COMSIG_TURF_CHANGE "turf_change"
+///from base of atom/has_gravity(): (atom/asker, list/forced_gravities)
+#define COMSIG_TURF_HAS_GRAVITY "turf_has_gravity"
+///from base of turf/New(): (turf/source, direction)
+#define COMSIG_TURF_MULTIZ_NEW "turf_multiz_new"
+
+// /atom/movable signals
+
+///from base of atom/movable/Moved(): (/atom)
+#define COMSIG_MOVABLE_PRE_MOVE "movable_pre_move"
+ #define COMPONENT_MOVABLE_BLOCK_PRE_MOVE (1<<0)
+///from base of atom/movable/Moved(): (/atom, dir)
+#define COMSIG_MOVABLE_MOVED "movable_moved"
+///from base of atom/movable/Cross(): (/atom/movable)
+#define COMSIG_MOVABLE_CROSS "movable_cross"
+///from base of atom/movable/Crossed(): (/atom/movable)
+#define COMSIG_MOVABLE_CROSSED "movable_crossed"
+///when we cross over something (calling Crossed() on that atom)
+#define COMSIG_CROSSED_MOVABLE "crossed_movable"
+///from base of atom/movable/Uncross(): (/atom/movable)
+#define COMSIG_MOVABLE_UNCROSS "movable_uncross"
+ #define COMPONENT_MOVABLE_BLOCK_UNCROSS (1<<0)
+///from base of atom/movable/Uncrossed(): (/atom/movable)
+#define COMSIG_MOVABLE_UNCROSSED "movable_uncrossed"
+///from base of atom/movable/Bump(): (/atom)
+#define COMSIG_MOVABLE_BUMP "movable_bump"
+///from base of atom/movable/throw_impact(): (/atom/hit_atom, /datum/thrownthing/throwingdatum)
+#define COMSIG_MOVABLE_IMPACT "movable_impact"
+ #define COMPONENT_MOVABLE_IMPACT_FLIP_HITPUSH (1<<0) //if true, flip if the impact will push what it hits
+ #define COMPONENT_MOVABLE_IMPACT_NEVERMIND (1<<1) //return true if you destroyed whatever it was you're impacting and there won't be anything for hitby() to run on
+///from base of mob/living/hitby(): (mob/living/target, hit_zone)
+#define COMSIG_MOVABLE_IMPACT_ZONE "item_impact_zone"
+///from base of atom/movable/buckle_mob(): (mob, force)
+#define COMSIG_MOVABLE_BUCKLE "buckle"
+///from base of atom/movable/unbuckle_mob(): (mob, force)
+#define COMSIG_MOVABLE_UNBUCKLE "unbuckle"
+///from base of atom/movable/throw_at(): (list/args)
+#define COMSIG_MOVABLE_PRE_THROW "movable_pre_throw"
+ #define COMPONENT_CANCEL_THROW (1<<0)
+///from base of atom/movable/throw_at(): (datum/thrownthing, spin)
+#define COMSIG_MOVABLE_POST_THROW "movable_post_throw"
+///from base of atom/movable/onTransitZ(): (old_z, new_z)
+#define COMSIG_MOVABLE_Z_CHANGED "movable_ztransit"
+///called when the movable is placed in an unaccessible area, used for stationloving: ()
+#define COMSIG_MOVABLE_SECLUDED_LOCATION "movable_secluded"
+///from base of atom/movable/Hear(): (proc args list(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode))
+#define COMSIG_MOVABLE_HEAR "movable_hear"
+ #define HEARING_MESSAGE 1
+ #define HEARING_SPEAKER 2
+// #define HEARING_LANGUAGE 3
+ #define HEARING_RAW_MESSAGE 4
+ /* #define HEARING_RADIO_FREQ 5
+ #define HEARING_SPANS 6
+ #define HEARING_MESSAGE_MODE 7 */
+
+///called when the movable is added to a disposal holder object for disposal movement: (obj/structure/disposalholder/holder, obj/machinery/disposal/source)
+#define COMSIG_MOVABLE_DISPOSING "movable_disposing"
+
+// /mob signals
+
+///from base of /mob/Login(): ()
+#define COMSIG_MOB_LOGIN "mob_login"
+///from base of /mob/Logout(): ()
+#define COMSIG_MOB_LOGOUT "mob_logout"
+///from base of mob/death(): (gibbed)
+#define COMSIG_MOB_DEATH "mob_death"
+///from base of mob/set_stat(): (new_stat)
+#define COMSIG_MOB_STATCHANGE "mob_statchange"
+///from base of mob/clickon(): (atom/A, params)
+#define COMSIG_MOB_CLICKON "mob_clickon"
+///from base of mob/MiddleClickOn(): (atom/A)
+#define COMSIG_MOB_MIDDLECLICKON "mob_middleclickon"
+///from base of mob/AltClickOn(): (atom/A)
+#define COMSIG_MOB_ALTCLICKON "mob_altclickon"
+ #define COMSIG_MOB_CANCEL_CLICKON (1<<0)
+
+///from base of obj/allowed(mob/M): (/obj) returns bool, if TRUE the mob has id access to the obj
+#define COMSIG_MOB_ALLOWED "mob_allowed"
+///from base of mob/anti_magic_check(): (mob/user, magic, holy, tinfoil, chargecost, self, protection_sources)
+#define COMSIG_MOB_RECEIVE_MAGIC "mob_receive_magic"
+ #define COMPONENT_BLOCK_MAGIC (1<<0)
+///from base of mob/create_mob_hud(): ()
+#define COMSIG_MOB_HUD_CREATED "mob_hud_created"
+///from base of atom/attack_hand(): (mob/user)
+#define COMSIG_MOB_ATTACK_HAND "mob_attack_hand"
+///from base of /obj/item/attack(): (mob/M, mob/user)
+#define COMSIG_MOB_ITEM_ATTACK "mob_item_attack"
+ #define COMPONENT_ITEM_NO_ATTACK (1<<0)
+///from base of /mob/living/proc/apply_damage(): (damage, damagetype, def_zone)
+#define COMSIG_MOB_APPLY_DAMGE "mob_apply_damage"
+///from base of obj/item/afterattack(): (atom/target, mob/user, proximity_flag, click_parameters)
+#define COMSIG_MOB_ITEM_AFTERATTACK "mob_item_afterattack"
+///from base of obj/item/attack_qdeleted(): (atom/target, mob/user, proxiumity_flag, click_parameters)
+#define COMSIG_MOB_ITEM_ATTACK_QDELETED "mob_item_attack_qdeleted"
+///from base of mob/RangedAttack(): (atom/A, params)
+#define COMSIG_MOB_ATTACK_RANGED "mob_attack_ranged"
+///from base of /mob/throw_item(): (atom/target)
+#define COMSIG_MOB_THROW "mob_throw"
+///from base of /mob/verb/examinate(): (atom/target)
+#define COMSIG_MOB_EXAMINATE "mob_examinate"
+///from base of /mob/update_sight(): ()
+#define COMSIG_MOB_UPDATE_SIGHT "mob_update_sight"
+////from /mob/living/say(): ()
+#define COMSIG_MOB_SAY "mob_say"
+ #define COMPONENT_UPPERCASE_SPEECH (1<<0)
+ // used to access COMSIG_MOB_SAY argslist
+ #define SPEECH_MESSAGE 1
+ // #define SPEECH_BUBBLE_TYPE 2
+ #define SPEECH_SPANS 3
+ /* #define SPEECH_SANITIZE 4
+ #define SPEECH_LANGUAGE 5
+ #define SPEECH_IGNORE_SPAM 6
+ #define SPEECH_FORCED 7 */
+
+///from /mob/say_dead(): (mob/speaker, message)
+#define COMSIG_MOB_DEADSAY "mob_deadsay"
+ #define MOB_DEADSAY_SIGNAL_INTERCEPT (1<<0)
+///from /mob/living/emote(): ()
+#define COMSIG_MOB_EMOTE "mob_emote"
+///from base of mob/swap_hand(): (obj/item)
+#define COMSIG_MOB_SWAP_HANDS "mob_swap_hands"
+ #define COMPONENT_BLOCK_SWAP (1<<0)
+
+// /mob/living signals
+
+///from base of mob/living/resist() (/mob/living)
+#define COMSIG_LIVING_RESIST "living_resist"
+///from base of mob/living/IgniteMob() (/mob/living)
+#define COMSIG_LIVING_IGNITED "living_ignite"
+///from base of mob/living/ExtinguishMob() (/mob/living)
+#define COMSIG_LIVING_EXTINGUISHED "living_extinguished"
+///from base of mob/living/electrocute_act(): (shock_damage, source, siemens_coeff, flags)
+#define COMSIG_LIVING_ELECTROCUTE_ACT "living_electrocute_act"
+///sent when items with siemen coeff. of 0 block a shock: (power_source, source, siemens_coeff, dist_check)
+#define COMSIG_LIVING_SHOCK_PREVENTED "living_shock_prevented"
+///sent by stuff like stunbatons and tasers: ()
+#define COMSIG_LIVING_MINOR_SHOCK "living_minor_shock"
+///from base of mob/living/revive() (full_heal, admin_revive)
+#define COMSIG_LIVING_REVIVE "living_revive"
+///from base of /mob/living/regenerate_limbs(): (noheal, excluded_limbs)
+#define COMSIG_LIVING_REGENERATE_LIMBS "living_regen_limbs"
+///from base of /obj/item/bodypart/proc/attach_limb(): (new_limb, special) allows you to fail limb attachment
+#define COMSIG_LIVING_ATTACH_LIMB "living_attach_limb"
+ #define COMPONENT_NO_ATTACH (1<<0)
+///sent from borg recharge stations: (amount, repairs)
+#define COMSIG_PROCESS_BORGCHARGER_OCCUPANT "living_charge"
+///sent when a mob/login() finishes: (client)
+#define COMSIG_MOB_CLIENT_LOGIN "comsig_mob_client_login"
+///sent from borg mobs to itself, for tools to catch an upcoming destroy() due to safe decon (rather than detonation)
+#define COMSIG_BORG_SAFE_DECONSTRUCT "borg_safe_decon"
+
+//ALL OF THESE DO NOT TAKE INTO ACCOUNT WHETHER AMOUNT IS 0 OR LOWER AND ARE SENT REGARDLESS!
+
+///from base of mob/living/Stun() (amount, update, ignore)
+#define COMSIG_LIVING_STATUS_STUN "living_stun"
+///from base of mob/living/Knockdown() (amount, update, ignore)
+#define COMSIG_LIVING_STATUS_KNOCKDOWN "living_knockdown"
+///from base of mob/living/Paralyze() (amount, update, ignore)
+#define COMSIG_LIVING_STATUS_PARALYZE "living_paralyze"
+///from base of mob/living/Immobilize() (amount, update, ignore)
+#define COMSIG_LIVING_STATUS_IMMOBILIZE "living_immobilize"
+///from base of mob/living/Unconscious() (amount, update, ignore)
+#define COMSIG_LIVING_STATUS_UNCONSCIOUS "living_unconscious"
+///from base of mob/living/Sleeping() (amount, update, ignore)
+#define COMSIG_LIVING_STATUS_SLEEP "living_sleeping"
+ #define COMPONENT_NO_STUN (1<<0) //For all of them
+///from base of /mob/living/can_track(): (mob/user)
+#define COMSIG_LIVING_CAN_TRACK "mob_cantrack"
+ #define COMPONENT_CANT_TRACK (1<<0)
+
+// /mob/living/carbon signals
+
+///from base of mob/living/carbon/soundbang_act(): (list(intensity))
+#define COMSIG_CARBON_SOUNDBANG "carbon_soundbang"
+///from /item/organ/proc/Insert() (/obj/item/organ/)
+#define COMSIG_CARBON_GAIN_ORGAN "carbon_gain_organ"
+///from /item/organ/proc/Remove() (/obj/item/organ/)
+#define COMSIG_CARBON_LOSE_ORGAN "carbon_lose_organ"
+///from /mob/living/carbon/doUnEquip(obj/item/I, force, newloc, no_move, invdrop, silent)
+#define COMSIG_CARBON_EQUIP_HAT "carbon_equip_hat"
+///from /mob/living/carbon/doUnEquip(obj/item/I, force, newloc, no_move, invdrop, silent)
+#define COMSIG_CARBON_UNEQUIP_HAT "carbon_unequip_hat"
+///defined twice, in carbon and human's topics, fired when interacting with a valid embedded_object to pull it out (mob/living/carbon/target, /obj/item, /obj/item/bodypart/L)
+#define COMSIG_CARBON_EMBED_RIP "item_embed_start_rip"
+///called when removing a given item from a mob, from mob/living/carbon/remove_embedded_object(mob/living/carbon/target, /obj/item)
+#define COMSIG_CARBON_EMBED_REMOVAL "item_embed_remove_safe"
+
+// /mob/living/simple_animal/hostile signals
+#define COMSIG_HOSTILE_ATTACKINGTARGET "hostile_attackingtarget"
+ #define COMPONENT_HOSTILE_NO_ATTACK (1<<0)
+
+// /obj signals
+
+///from base of obj/deconstruct(): (disassembled)
+#define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct"
+///called in /obj/structure/setAnchored(): (value)
+#define COMSIG_OBJ_SETANCHORED "obj_setanchored"
+///from base of code/game/machinery
+#define COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH "obj_default_unfasten_wrench"
+///from base of /turf/proc/levelupdate(). (intact) true to hide and false to unhide
+#define COMSIG_OBJ_HIDE "obj_hide"
+///called in /obj/update_icon()
+#define COMSIG_OBJ_UPDATE_ICON "obj_update_icon"
+
+// /obj/machinery signals
+
+///from /obj/machinery/obj_break(damage_flag): (damage_flag)
+#define COMSIG_MACHINERY_BROKEN "machinery_broken"
+///from base power_change() when power is lost
+#define COMSIG_MACHINERY_POWER_LOST "machinery_power_lost"
+///from base power_change() when power is restored
+#define COMSIG_MACHINERY_POWER_RESTORED "machinery_power_restored"
+
+// /obj/item signals
+
+///from base of obj/item/attack(): (/mob/living/target, /mob/living/user)
+#define COMSIG_ITEM_ATTACK "item_attack"
+///from base of obj/item/attack_self(): (/mob)
+#define COMSIG_ITEM_ATTACK_SELF "item_attack_self"
+ #define COMPONENT_NO_INTERACT (1<<0)
+///from base of obj/item/attack_obj(): (/obj, /mob)
+#define COMSIG_ITEM_ATTACK_OBJ "item_attack_obj"
+ #define COMPONENT_NO_ATTACK_OBJ (1<<0)
+///from base of obj/item/pre_attack(): (atom/target, mob/user, params)
+#define COMSIG_ITEM_PRE_ATTACK "item_pre_attack"
+ #define COMPONENT_NO_ATTACK (1<<0)
+///from base of obj/item/afterattack(): (atom/target, mob/user, params)
+#define COMSIG_ITEM_AFTERATTACK "item_afterattack"
+///from base of obj/item/attack_qdeleted(): (atom/target, mob/user, params)
+#define COMSIG_ITEM_ATTACK_QDELETED "item_attack_qdeleted"
+///from base of obj/item/equipped(): (/mob/equipper, slot)
+#define COMSIG_ITEM_EQUIPPED "item_equip"
+///from base of obj/item/dropped(): (mob/user)
+#define COMSIG_ITEM_DROPPED "item_drop"
+///from base of obj/item/pickup(): (/mob/taker)
+#define COMSIG_ITEM_PICKUP "item_pickup"
+///from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone)
+#define COMSIG_ITEM_ATTACK_ZONE "item_attack_zone"
+///return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/targeted/lichdom/cast(): (mob/user)
+#define COMSIG_ITEM_IMBUE_SOUL "item_imbue_soul"
+///called before marking an object for retrieval, checked in /obj/effect/proc_holder/spell/targeted/summonitem/cast() : (mob/user)
+#define COMSIG_ITEM_MARK_RETRIEVAL "item_mark_retrieval"
+ #define COMPONENT_BLOCK_MARK_RETRIEVAL (1<<0)
+///from base of obj/item/hit_reaction(): (list/args)
+#define COMSIG_ITEM_HIT_REACT "item_hit_react"
+///called on item when crossed by something (): (/atom/movable, mob/living/crossed)
+#define COMSIG_ITEM_WEARERCROSSED "wearer_crossed"
+///called on item when microwaved (): (obj/machinery/microwave/M)
+#define COMSIG_ITEM_MICROWAVE_ACT "microwave_act"
+///from base of item/sharpener/attackby(): (amount, max)
+#define COMSIG_ITEM_SHARPEN_ACT "sharpen_act"
+ #define COMPONENT_BLOCK_SHARPEN_APPLIED (1<<0)
+ #define COMPONENT_BLOCK_SHARPEN_BLOCKED (1<<1)
+ #define COMPONENT_BLOCK_SHARPEN_ALREADY (1<<2)
+ #define COMPONENT_BLOCK_SHARPEN_MAXED (1<<3)
+///from base of [/obj/item/proc/tool_check_callback]: (mob/living/user)
+#define COMSIG_TOOL_IN_USE "tool_in_use"
+///from base of [/obj/item/proc/tool_start_check]: (mob/living/user)
+#define COMSIG_TOOL_START_USE "tool_start_use"
+///from [/obj/item/proc/disableEmbedding]:
+#define COMSIG_ITEM_DISABLE_EMBED "item_disable_embed"
+///from [/obj/effect/mine/proc/triggermine]:
+#define COMSIG_MINE_TRIGGERED "minegoboom"
+
+// /obj/item signals for economy
+///called when an item is sold by the exports subsystem
+#define COMSIG_ITEM_SOLD "item_sold"
+///called when a wrapped up structure is opened by hand
+#define COMSIG_STRUCTURE_UNWRAPPED "structure_unwrapped"
+#define COMSIG_ITEM_UNWRAPPED "item_unwrapped"
+///called when a wrapped up item is opened by hand
+ #define COMSIG_ITEM_SPLIT_VALUE (1<<0)
+///called when getting the item's exact ratio for cargo's profit.
+#define COMSIG_ITEM_SPLIT_PROFIT "item_split_profits"
+///called when getting the item's exact ratio for cargo's profit, without selling the item.
+#define COMSIG_ITEM_SPLIT_PROFIT_DRY "item_split_profits_dry"
+
+// /obj/item/clothing signals
+
+///from base of obj/item/clothing/shoes/proc/step_action(): ()
+#define COMSIG_SHOES_STEP_ACTION "shoes_step_action"
+///from base of /obj/item/clothing/suit/space/proc/toggle_spacesuit(): (obj/item/clothing/suit/space/suit)
+#define COMSIG_SUIT_SPACE_TOGGLE "suit_space_toggle"
+
+// /obj/item/implant signals
+///from base of /obj/item/implant/proc/activate(): ()
+#define COMSIG_IMPLANT_ACTIVATED "implant_activated"
+///from base of /obj/item/implant/proc/implant(): (list/args)
+#define COMSIG_IMPLANT_IMPLANTING "implant_implanting"
+ #define COMPONENT_STOP_IMPLANTING (1<<0)
+///called on already installed implants when a new one is being added in /obj/item/implant/proc/implant(): (list/args, obj/item/implant/new_implant)
+#define COMSIG_IMPLANT_OTHER "implant_other"
+ //#define COMPONENT_STOP_IMPLANTING (1<<0) //The name makes sense for both
+ #define COMPONENT_DELETE_NEW_IMPLANT (1<<1)
+ #define COMPONENT_DELETE_OLD_IMPLANT (1<<2)
+///called on implants being implanted into someone with an uplink implant: (datum/component/uplink)
+#define COMSIG_IMPLANT_EXISTING_UPLINK "implant_uplink_exists"
+ //This uses all return values of COMSIG_IMPLANT_OTHER
+
+// /obj/item/pda signals
+
+///called on pda when the user changes the ringtone: (mob/living/user, new_ringtone)
+#define COMSIG_PDA_CHANGE_RINGTONE "pda_change_ringtone"
+ #define COMPONENT_STOP_RINGTONE_CHANGE (1<<0)
+#define COMSIG_PDA_CHECK_DETONATE "pda_check_detonate"
+ #define COMPONENT_PDA_NO_DETONATE (1<<0)
+
+// /obj/item/radio signals
+
+///called from base of /obj/item/radio/proc/set_frequency(): (list/args)
+#define COMSIG_RADIO_NEW_FREQUENCY "radio_new_frequency"
+
+// /obj/item/pen signals
+
+///called after rotation in /obj/item/pen/attack_self(): (rotation, mob/living/carbon/user)
+#define COMSIG_PEN_ROTATED "pen_rotated"
+
+// /obj/item/gun signals
+
+///called in /obj/item/gun/process_fire (user, target, params, zone_override)
+#define COMSIG_MOB_FIRED_GUN "mob_fired_gun"
+
+// /obj/item/grenade signals
+
+///called in /obj/item/gun/process_fire (user, target, params, zone_override)
+#define COMSIG_GRENADE_PRIME "grenade_prime"
+///called in /obj/item/gun/process_fire (user, target, params, zone_override)
+#define COMSIG_GRENADE_ARMED "grenade_armed"
+
+// /obj/projectile signals (sent to the firer)
+
+///from base of /obj/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle)
+#define COMSIG_PROJECTILE_SELF_ON_HIT "projectile_self_on_hit"
+///from base of /obj/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle)
+#define COMSIG_PROJECTILE_ON_HIT "projectile_on_hit"
+///from base of /obj/projectile/proc/fire(): (obj/projectile, atom/original_target)
+#define COMSIG_PROJECTILE_BEFORE_FIRE "projectile_before_fire"
+///from the base of /obj/projectile/proc/fire(): ()
+#define COMSIG_PROJECTILE_FIRE "projectile_fire"
+///sent to targets during the process_hit proc of projectiles
+#define COMSIG_PROJECTILE_PREHIT "com_proj_prehit"
+///sent to targets during the process_hit proc of projectiles
+#define COMSIG_PROJECTILE_RANGE_OUT "projectile_range_out"
+///sent when trying to force an embed (mainly for projectiles, only used in the embed element)
+#define COMSIG_EMBED_TRY_FORCE "item_try_embed"
+
+///sent to targets during the process_hit proc of projectiles
+#define COMSIG_PELLET_CLOUD_INIT "pellet_cloud_init"
+
+// /obj/mecha signals
+
+///sent from mecha action buttons to the mecha they're linked to
+#define COMSIG_MECHA_ACTION_ACTIVATE "mecha_action_activate"
+
+// /mob/living/carbon/human signals
+
+///from mob/living/carbon/human/UnarmedAttack(): (atom/target, proximity)
+#define COMSIG_HUMAN_EARLY_UNARMED_ATTACK "human_early_unarmed_attack"
+///from mob/living/carbon/human/UnarmedAttack(): (atom/target, proximity)
+#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack"
+///from mob/living/carbon/human/UnarmedAttack(): (mob/living/carbon/human/attacker)
+#define COMSIG_HUMAN_MELEE_UNARMED_ATTACKBY "human_melee_unarmed_attackby"
+///Hit by successful disarm attack (mob/living/carbon/human/attacker,zone_targeted)
+#define COMSIG_HUMAN_DISARM_HIT "human_disarm_hit"
+///Whenever EquipRanked is called, called after job is set
+#define COMSIG_JOB_RECEIVED "job_received"
+
+// /datum/species signals
+
+///from datum/species/on_species_gain(): (datum/species/new_species, datum/species/old_species)
+#define COMSIG_SPECIES_GAIN "species_gain"
+///from datum/species/on_species_loss(): (datum/species/lost_species)
+#define COMSIG_SPECIES_LOSS "species_loss"
+
+// /datum/song signals
+
+///sent to the instrument when a song starts playing
+#define COMSIG_SONG_START "song_start"
+///sent to the instrument when a song stops playing
+#define COMSIG_SONG_END "song_end"
+
+/*******Component Specific Signals*******/
+//Janitor
+
+///(): Returns bitflags of wet values.
+#define COMSIG_TURF_IS_WET "check_turf_wet"
+///(max_strength, immediate, duration_decrease = INFINITY): Returns bool.
+#define COMSIG_TURF_MAKE_DRY "make_turf_try"
+///called on an object to clean it of cleanables. Usualy with soap: (num/strength)
+#define COMSIG_COMPONENT_CLEAN_ACT "clean_act"
+
+//Creamed
+
+///called when you wash your face at a sink: (num/strength)
+#define COMSIG_COMPONENT_CLEAN_FACE_ACT "clean_face_act"
+
+//Food
+
+///from base of obj/item/reagent_containers/food/snacks/attack(): (mob/living/eater, mob/feeder)
+#define COMSIG_FOOD_EATEN "food_eaten"
+
+//Gibs
+
+///from base of /obj/effect/decal/cleanable/blood/gibs/streak(): (list/directions, list/diseases)
+#define COMSIG_GIBS_STREAK "gibs_streak"
+
+//Mood
+
+///called when you send a mood event from anywhere in the code.
+#define COMSIG_ADD_MOOD_EVENT "add_mood"
+///Mood event that only RnD members listen for
+#define COMSIG_ADD_MOOD_EVENT_RND "RND_add_mood"
+///called when you clear a mood event from anywhere in the code.
+#define COMSIG_CLEAR_MOOD_EVENT "clear_mood"
+
+//NTnet
+
+///called on an object by its NTNET connection component on receive. (sending_id(number), sending_netname(text), data(datum/netdata))
+#define COMSIG_COMPONENT_NTNET_RECEIVE "ntnet_receive"
+
+//Nanites
+
+///() returns TRUE if nanites are found
+#define COMSIG_HAS_NANITES "has_nanites"
+///() returns TRUE if nanites have stealth
+#define COMSIG_NANITE_IS_STEALTHY "nanite_is_stealthy"
+///() deletes the nanite component
+#define COMSIG_NANITE_DELETE "nanite_delete"
+///(list/nanite_programs) - makes the input list a copy the nanites' program list
+#define COMSIG_NANITE_GET_PROGRAMS "nanite_get_programs"
+///(amount) Returns nanite amount
+#define COMSIG_NANITE_GET_VOLUME "nanite_get_volume"
+///(amount) Sets current nanite volume to the given amount
+#define COMSIG_NANITE_SET_VOLUME "nanite_set_volume"
+///(amount) Adjusts nanite volume by the given amount
+#define COMSIG_NANITE_ADJUST_VOLUME "nanite_adjust"
+///(amount) Sets maximum nanite volume to the given amount
+#define COMSIG_NANITE_SET_MAX_VOLUME "nanite_set_max_volume"
+///(amount(0-100)) Sets cloud ID to the given amount
+#define COMSIG_NANITE_SET_CLOUD "nanite_set_cloud"
+///(method) Modify cloud sync status. Method can be toggle, enable or disable
+#define COMSIG_NANITE_SET_CLOUD_SYNC "nanite_set_cloud_sync"
+///(amount) Sets safety threshold to the given amount
+#define COMSIG_NANITE_SET_SAFETY "nanite_set_safety"
+///(amount) Sets regeneration rate to the given amount
+#define COMSIG_NANITE_SET_REGEN "nanite_set_regen"
+///(code(1-9999)) Called when sending a nanite signal to a mob.
+#define COMSIG_NANITE_SIGNAL "nanite_signal"
+///(comm_code(1-9999), comm_message) Called when sending a nanite comm signal to a mob.
+#define COMSIG_NANITE_COMM_SIGNAL "nanite_comm_signal"
+///(mob/user, full_scan) - sends to chat a scan of the nanites to the user, returns TRUE if nanites are detected
+#define COMSIG_NANITE_SCAN "nanite_scan"
+///(list/data, scan_level) - adds nanite data to the given data list - made for ui_data procs
+#define COMSIG_NANITE_UI_DATA "nanite_ui_data"
+///(datum/nanite_program/new_program, datum/nanite_program/source_program) Called when adding a program to a nanite component
+#define COMSIG_NANITE_ADD_PROGRAM "nanite_add_program"
+ ///Installation successful
+ #define COMPONENT_PROGRAM_INSTALLED (1<<0)
+ ///Installation failed, but there are still nanites
+ #define COMPONENT_PROGRAM_NOT_INSTALLED (1<<1)
+///(datum/component/nanites, full_overwrite, copy_activation) Called to sync the target's nanites to a given nanite component
+#define COMSIG_NANITE_SYNC "nanite_sync"
+
+// /datum/component/storage signals
+
+///() - returns bool.
+#define COMSIG_CONTAINS_STORAGE "is_storage"
+///(obj/item/inserting, mob/user, silent, force) - returns bool
+#define COMSIG_TRY_STORAGE_INSERT "storage_try_insert"
+///(mob/show_to, force) - returns bool.
+#define COMSIG_TRY_STORAGE_SHOW "storage_show_to"
+///(mob/hide_from) - returns bool
+#define COMSIG_TRY_STORAGE_HIDE_FROM "storage_hide_from"
+///returns bool
+#define COMSIG_TRY_STORAGE_HIDE_ALL "storage_hide_all"
+///(newstate)
+#define COMSIG_TRY_STORAGE_SET_LOCKSTATE "storage_lock_set_state"
+///() - returns bool. MUST CHECK IF STORAGE IS THERE FIRST!
+#define COMSIG_IS_STORAGE_LOCKED "storage_get_lockstate"
+///(type, atom/destination, amount = INFINITY, check_adjacent, force, mob/user, list/inserted) - returns bool - type can be a list of types.
+#define COMSIG_TRY_STORAGE_TAKE_TYPE "storage_take_type"
+///(type, amount = INFINITY, force = FALSE). Force will ignore max_items, and amount is normally clamped to max_items.
+#define COMSIG_TRY_STORAGE_FILL_TYPE "storage_fill_type"
+///(obj, new_loc, force = FALSE) - returns bool
+#define COMSIG_TRY_STORAGE_TAKE "storage_take_obj"
+///(loc) - returns bool - if loc is null it will dump at parent location.
+#define COMSIG_TRY_STORAGE_QUICK_EMPTY "storage_quick_empty"
+///(list/list_to_inject_results_into, recursively_search_inside_storages = TRUE)
+#define COMSIG_TRY_STORAGE_RETURN_INVENTORY "storage_return_inventory"
+///(obj/item/insertion_candidate, mob/user, silent) - returns bool
+#define COMSIG_TRY_STORAGE_CAN_INSERT "storage_can_equip"
+
+// /datum/component/two_handed signals
+
+///from base of datum/component/two_handed/proc/wield(mob/living/carbon/user): (/mob/user)
+#define COMSIG_TWOHANDED_WIELD "twohanded_wield"
+ #define COMPONENT_TWOHANDED_BLOCK_WIELD (1<<0)
+///from base of datum/component/two_handed/proc/unwield(mob/living/carbon/user): (/mob/user)
+#define COMSIG_TWOHANDED_UNWIELD "twohanded_unwield"
+
+// /datum/action signals
+
+///from base of datum/action/proc/Trigger(): (datum/action)
+#define COMSIG_ACTION_TRIGGER "action_trigger"
+ #define COMPONENT_ACTION_BLOCK_TRIGGER (1<<0)
+
+//Xenobio hotkeys
+
+///from slime CtrlClickOn(): (/mob)
+#define COMSIG_XENO_SLIME_CLICK_CTRL "xeno_slime_click_ctrl"
+///from slime AltClickOn(): (/mob)
+#define COMSIG_XENO_SLIME_CLICK_ALT "xeno_slime_click_alt"
+///from slime ShiftClickOn(): (/mob)
+#define COMSIG_XENO_SLIME_CLICK_SHIFT "xeno_slime_click_shift"
+///from turf ShiftClickOn(): (/mob)
+#define COMSIG_XENO_TURF_CLICK_SHIFT "xeno_turf_click_shift"
+///from turf AltClickOn(): (/mob)
+#define COMSIG_XENO_TURF_CLICK_CTRL "xeno_turf_click_alt"
+///from monkey CtrlClickOn(): (/mob)
+#define COMSIG_XENO_MONKEY_CLICK_CTRL "xeno_monkey_click_ctrl"
diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm
index cec707b8196..23ac017f1ec 100644
--- a/code/__DEFINES/inventory.dm
+++ b/code/__DEFINES/inventory.dm
@@ -5,6 +5,3 @@
#define WEIGHT_CLASS_BULKY 4 //Items that can be weilded or equipped but not stored in an inventory, ex: Defibrillator, Backpack, Space Suits
#define WEIGHT_CLASS_HUGE 5 //Usually represents objects that require two hands to operate, ex: Shotgun, Two Handed Melee Weapons
#define WEIGHT_CLASS_GIGANTIC 6 //Essentially means it cannot be picked up or placed in an inventory, ex: Mech Parts, Safe
-
-#define TV_TRIP "trip"
-#define TV_SLIP "slip"
diff --git a/code/__DEFINES/job.dm b/code/__DEFINES/job.dm
index d72628e2cb7..349d1b246be 100644
--- a/code/__DEFINES/job.dm
+++ b/code/__DEFINES/job.dm
@@ -51,7 +51,7 @@
#define JOB_CLOWN (1<<11)
#define JOB_MIME (1<<12)
#define JOB_CIVILIAN (1<<13)
-
+#define JOB_EXPLORER (1<<14)
#define JOBCAT_KARMA (1<<3)
diff --git a/code/__HELPERS/traits.dm b/code/__HELPERS/traits.dm
index ee6c5d10fe0..352a6fa3680 100644
--- a/code/__HELPERS/traits.dm
+++ b/code/__HELPERS/traits.dm
@@ -65,6 +65,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_WATERBREATH "waterbreathing"
#define TRAIT_BLOODCRAWL "bloodcrawl"
#define TRAIT_BLOODCRAWL_EAT "bloodcrawl_eat"
+#define TRAIT_JESTER "jester"
// common trait sources
#define ROUNDSTART_TRAIT "roundstart" //cannot be removed without admin intervention
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index aa130bb3ca9..80852f25c3f 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -2038,3 +2038,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
tX = Clamp(origin.x + text2num(tX) - round(actual_view[1] / 2) - 1, 1, world.maxx)
tY = Clamp(origin.y + text2num(tY) - round(actual_view[2] / 2) - 1, 1, world.maxy)
return locate(tX, tY, tZ)
+
+/proc/CallAsync(datum/source, proctype, list/arguments)
+ set waitfor = FALSE
+ return call(source, proctype)(arglist(arguments))
diff --git a/code/controllers/subsystem/dcs.dm b/code/controllers/subsystem/dcs.dm
new file mode 100644
index 00000000000..09dea24071f
--- /dev/null
+++ b/code/controllers/subsystem/dcs.dm
@@ -0,0 +1,53 @@
+PROCESSING_SUBSYSTEM_DEF(dcs)
+ name = "Datum Component System"
+ flags = SS_NO_INIT
+
+ var/list/elements_by_type = list()
+
+/datum/controller/subsystem/processing/dcs/Recover()
+ comp_lookup = SSdcs.comp_lookup
+
+/datum/controller/subsystem/processing/dcs/proc/GetElement(list/arguments)
+ var/datum/element/eletype = arguments[1]
+ var/element_id = eletype
+
+ if(!ispath(eletype, /datum/element))
+ CRASH("Attempted to instantiate [eletype] as a /datum/element")
+
+ if(initial(eletype.element_flags) & ELEMENT_BESPOKE)
+ element_id = GetIdFromArguments(arguments)
+
+ . = elements_by_type[element_id]
+ if(.)
+ return
+ . = elements_by_type[element_id] = new eletype
+
+/****
+ * Generates an id for bespoke elements when given the argument list
+ * Generating the id here is a bit complex because we need to support named arguments
+ * Named arguments can appear in any order and we need them to appear after ordered arguments
+ * We assume that no one will pass in a named argument with a value of null
+ **/
+/datum/controller/subsystem/processing/dcs/proc/GetIdFromArguments(list/arguments)
+ var/datum/element/eletype = arguments[1]
+ var/list/fullid = list("[eletype]")
+ var/list/named_arguments = list()
+ for(var/i in initial(eletype.id_arg_index) to length(arguments))
+ var/key = arguments[i]
+ var/value
+ if(istext(key))
+ value = arguments[key]
+ if(!(istext(key) || isnum(key)))
+ key = "\ref[key]"
+ key = "[key]" // Key is stringified so numbers dont break things
+ if(!isnull(value))
+ if(!(istext(value) || isnum(value)))
+ value = "\ref[value]"
+ named_arguments["[key]"] = value
+ else
+ fullid += "[key]"
+
+ if(length(named_arguments))
+ named_arguments = sortList(named_arguments)
+ fullid += named_arguments
+ return list2params(fullid)
diff --git a/code/datums/action.dm b/code/datums/action.dm
index b7af84e9ddf..c1802da47c1 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -339,7 +339,7 @@
/datum/action/item_action/remove_tape/Trigger(attack_self = FALSE)
if(..())
- GET_COMPONENT_FROM(DT, /datum/component/ducttape, target)
+ var/datum/component/ducttape/DT = target.GetComponent(/datum/component/ducttape)
DT.remove_tape(target, usr)
/datum/action/item_action/toggle_jetpack
diff --git a/code/datums/components/README.md b/code/datums/components/README.md
index 9d06a255dd7..03f7d3a5875 100644
--- a/code/datums/components/README.md
+++ b/code/datums/components/README.md
@@ -2,134 +2,8 @@
## Concept
-Loosely adapted from /vg/. This is an entity component system for adding behaviours to datums when inheritance doesn't quite cut it. By using signals and events instead of direct inheritance, you can inject behaviours without hacky overloads. It requires a different method of thinking, but is not hard to use correctly. If a behaviour can have application across more than one thing. Make it generic, make it a component. Atom/mob/obj event? Give it a signal, and forward it's arguments with a `SEND_SIGNAL` call. Now every component that want's to can also know about this happening.
+Loosely adapted from /vg/. This is an entity component system for adding behaviours to datums when inheritance doesn't quite cut it. By using signals and events instead of direct inheritance, you can inject behaviours without hacky overloads. It requires a different method of thinking, but is not hard to use correctly. If a behaviour can have application across more than one thing. Make it generic, make it a component. Atom/mob/obj event? Give it a signal, and forward it's arguments with a `SendSignal()` call. Now every component that want's to can also know about this happening.
-### In the code
+See [this thread](https://tgstation13.org/phpBB/viewtopic.php?f=5&t=22674) for an introduction to the system as a whole.
-#### Slippery things
-
-At the time of this writing, every object that is slippery overrides atom/Crossed does some checks, then slips the mob. Instead of all those Crossed overrides they could add a slippery component to all these objects. And have the checks in one proc that is run by the Crossed event
-
-#### Powercells
-
-A lot of objects have powercells. The `get_cell()` proc was added to give generic access to the cell var if it had one. This is just a specific use case of `GetComponent()`
-
-#### Radios
-
-The radio object as it is should not exist, given that more things use the _concept_ of radios rather than the object itself. The actual function of the radio can exist in a component which all the things that use it (Request consoles, actual radios, the SM shard) can add to themselves.
-
-#### Standos
-
-Stands have a lot of procs which mimic mob procs. Rather than inserting hooks for all these procs in overrides, the same can be accomplished with signals
-
-## API
-
-### Defines
-
-1. `COMPONENT_INCOMPATIBLE` Return this from `/datum/component/Initialize` or `datum/component/OnTransfer` to have the component be deleted if it's applied to an incorrect type. `parent` must not be modified if this is to be returned. This will be noted in the runtime logs
-
-### Vars
-
-1. `/datum/var/list/datum_components` (private)
- * Lazy associated list of type -> component/list of components.
-1. `/datum/var/list/comp_lookup` (private)
- * Lazy associated list of signal -> registree/list of registrees
-1. `/datum/var/list/signal_procs` (private)
- * Associated lazy list of signals -> `/datum/callback`s that will be run when the parent datum receives that signal
-1. `/datum/var/signal_enabled` (protected, boolean)
- * If the datum is signal enabled. If not, it will not react to signals
- * `FALSE` by default, set to `TRUE` when a signal is registered
-1. `/datum/component/var/dupe_mode` (protected, enum)
- * How duplicate component types are handled when added to the datum.
- * `COMPONENT_DUPE_HIGHLANDER` (default): Old component will be deleted, new component will first have `/datum/component/proc/InheritComponent(datum/component/old, FALSE)` on it
- * `COMPONENT_DUPE_ALLOWED`: The components will be treated as separate, `GetComponent()` will return the first added
- * `COMPONENT_DUPE_UNIQUE`: New component will be deleted, old component will first have `/datum/component/proc/InheritComponent(datum/component/new, TRUE)` on it
- * `COMPONENT_DUPE_UNIQUE_PASSARGS`: New component will never exist and instead its initialization arguments will be passed on to the old component.
-1. `/datum/component/var/dupe_type` (protected, type)
- * Definition of a duplicate component type
- * `null` means exact match on `type` (default)
- * Any other type means that and all subtypes
-1. `/datum/component/var/datum/parent` (protected, read-only)
- * The datum this component belongs to
- * Never `null` in child procs
-1. `report_signal_origin` (protected, boolean)
- * If `TRUE`, will invoke the callback when signalled with the signal type as the first argument.
- * `FALSE` by default.
-
-### Procs
-
-1. `/datum/proc/GetComponent(component_type(type)) -> datum/component?` (public, final)
- * Returns a reference to a component of component_type if it exists in the datum, null otherwise
-1. `/datum/proc/GetComponents(component_type(type)) -> list` (public, final)
- * Returns a list of references to all components of component_type that exist in the datum
-1. `/datum/proc/GetExactComponent(component_type(type)) -> datum/component?` (public, final)
- * Returns a reference to a component whose type MATCHES component_type if that component exists in the datum, null otherwise
-1. `GET_COMPONENT(varname, component_type)` OR `GET_COMPONENT_FROM(varname, component_type, src)`
- * Shorthand for `var/component_type/varname = src.GetComponent(component_type)`
-1. `SEND_SIGNAL(target, sigtype, ...)` (public, final)
- * Use to send signals to target datum
- * Extra arguments are to be specified in the signal definition
- * Returns a bitflag with signal specific information assembled from all activated components
- * Arguments are packaged in a list and handed off to _SendSignal()
-1. `/datum/proc/AddComponent(component_type(type), ...) -> datum/component` (public, final)
- * Creates an instance of `component_type` in the datum and passes `...` to its `Initialize()` call
- * Sends the `COMSIG_COMPONENT_ADDED` signal to the datum
- * All components a datum owns are deleted with the datum
- * Returns the component that was created. Or the old component in a dupe situation where `COMPONENT_DUPE_UNIQUE` was set
- * If this tries to add an component to an incompatible type, the component will be deleted and the result will be `null`. This is very unperformant, try not to do it
- * Properly handles duplicate situations based on the `dupe_mode` var
-1. `/datum/proc/LoadComponent(component_type(type), ...) -> datum/component` (public, final)
- * Equivalent to calling `GetComponent(component_type)` where, if the result would be `null`, returns `AddComponent(component_type, ...)` instead
-1. `/datum/proc/ComponentActivated(datum/component/C)` (abstract, async)
- * Called on a component's `parent` after a signal received causes it to activate. `src` is the parameter
- * Will only be called if a component's callback returns `TRUE`
-1. `/datum/proc/TakeComponent(datum/component/C)` (public, final)
- * Properly transfers ownership of a component from one datum to another
- * Signals `COMSIG_COMPONENT_REMOVING` on the parent
- * Called on the datum you want to own the component with another datum's component
-1. `/datum/proc/_SendSignal(signal, list/arguments)` (private, final)
- * Handles most of the actual signaling procedure
- * Will runtime if used on datums with an empty component list
-1. `/datum/proc/RegisterSignal(datum/target, signal(string/list of strings), proc_ref(type), override(boolean))` (protected, final)
- * If signal is a list it will be as if RegisterSignal was called for each of the entries with the same following arguments
- * Makes the datum listen for the specified `signal` on it's `parent` datum.
- * When that signal is received `proc_ref` will be called on the component, along with associated arguments
- * Example proc ref: `.proc/OnEvent`
- * If a previous registration is overwritten by the call, a runtime occurs. Setting `override` to TRUE prevents this
- * These callbacks run asyncronously
- * Returning `TRUE` from these callbacks will trigger a `TRUE` return from the `SendSignal()` that initiated it
-1. `/datum/component/New(datum/parent, ...)` (private, final)
- * Runs internal setup for the component
- * Extra arguments are passed to `Initialize()`
-1. `/datum/component/Initialize(...)` (abstract, no-sleep)
- * Called by `New()` with the same argments excluding `parent`
- * Component does not exist in `parent`'s `datum_components` list yet, although `parent` is set and may be used
- * Signals will not be received while this function is running
- * Component may be deleted after this function completes without being attached
- * Do not call `qdel(src)` from this function
-1. `/datum/component/Destroy(force(bool), silent(bool))` (virtual, no-sleep)
- * Sends the `COMSIG_COMPONENT_REMOVING` signal to the parent datum if the `parent` isn't being qdeleted
- * Properly removes the component from `parent` and cleans up references
- * Setting `force` makes it not check for and remove the component from the parent
- * Setting `silent` deletes the component without sending a `COMSIG_COMPONENT_REMOVING` signal
-1. `/datum/component/proc/InheritComponent(datum/component/C, i_am_original(boolean))` (abstract, no-sleep)
- * Called on a component when a component of the same type was added to the same parent
- * See `/datum/component/var/dupe_mode`
- * `C`'s type will always be the same of the called component
-1. `/datum/component/proc/AfterComponentActivated()` (abstract, async)
- * Called on a component that was activated after it's `parent`'s `ComponentActivated()` is called
-1. `/datum/component/proc/OnTransfer(datum/new_parent)` (abstract, no-sleep)
- * Called before `new_parent` is assigned to `parent` in `TakeComponent()`
- * Allows the component to react to ownership transfers
-1. `/datum/component/proc/_RemoveFromParent()` (private, final)
- * Clears `parent` and removes the component from it's component list
-1. `/datum/component/proc/_JoinParent` (private, final)
- * Tries to add the component to it's `parent`s `datum_components` list
-1. `/datum/component/proc/RegisterWithParent` (abstract, no-sleep)
- * Used to register the signals that should be on the `parent` object
- * Use this if you plan on the component transfering between parents
-1. `/datum/component/proc/UnregisterFromParent` (abstract, no-sleep)
- * Counterpart to `RegisterWithParent()`
- * Used to unregister the signals that should only be on the `parent` object
-
-### See/Define signals and their arguments in __DEFINES\components.dm
+### See/Define signals and their arguments in [__DEFINES\dcs\signals.dm](../../__DEFINES/dcs/signals.dm)
diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm
index e733ca78d2b..f895b8d81b1 100644
--- a/code/datums/components/_component.dm
+++ b/code/datums/components/_component.dm
@@ -1,21 +1,87 @@
+/**
+ * # Component
+ *
+ * The component datum
+ *
+ * A component should be a single standalone unit
+ * of functionality, that works by receiving signals from it's parent
+ * object to provide some single functionality (i.e a slippery component)
+ * that makes the object it's attached to cause people to slip over.
+ * Useful when you want shared behaviour independent of type inheritance
+ */
/datum/component
+ /**
+ * Defines how duplicate existing components are handled when added to a datum
+ *
+ * See [COMPONENT_DUPE_*][COMPONENT_DUPE_ALLOWED] definitions for available options
+ */
var/dupe_mode = COMPONENT_DUPE_HIGHLANDER
+
+ /**
+ * The type to check for duplication
+ *
+ * `null` means exact match on `type` (default)
+ *
+ * Any other type means that and all subtypes
+ */
var/dupe_type
+
+ /// The datum this components belongs to
var/datum/parent
- //only set to true if you are able to properly transfer this component
- //At a minimum RegisterWithParent and UnregisterFromParent should be used
- //Make sure you also implement PostTransfer for any post transfer handling
+
+ /**
+ * Only set to true if you are able to properly transfer this component
+ *
+ * At a minimum [RegisterWithParent][/datum/component/proc/RegisterWithParent] and [UnregisterFromParent][/datum/component/proc/UnregisterFromParent] should be used
+ *
+ * Make sure you also implement [PostTransfer][/datum/component/proc/PostTransfer] for any post transfer handling
+ */
var/can_transfer = FALSE
-/datum/component/New(datum/P, ...)
- parent = P
- var/list/arguments = args.Copy(2)
+/**
+ * Create a new component.
+ *
+ * Additional arguments are passed to [Initialize()][/datum/component/proc/Initialize]
+ *
+ * Arguments:
+ * * datum/P the parent datum this component reacts to signals from
+ */
+/datum/component/New(list/raw_args)
+ parent = raw_args[1]
+ var/list/arguments = raw_args.Copy(2)
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
+ stack_trace("Incompatible [type] assigned to a [parent.type]! args: [json_encode(arguments)]")
qdel(src, TRUE, TRUE)
- CRASH("Incompatible [type] assigned to a [P.type]! args: [json_encode(arguments)]")
+ return
- _JoinParent(P)
+ _JoinParent(parent)
+/**
+ * Called during component creation with the same arguments as in new excluding parent.
+ *
+ * Do not call `qdel(src)` from this function, `return COMPONENT_INCOMPATIBLE` instead
+ */
+/datum/component/proc/Initialize(...)
+ return
+
+/**
+ * Properly removes the component from `parent` and cleans up references
+ *
+ * Arguments:
+ * * force - makes it not check for and remove the component from the parent
+ * * silent - deletes the component without sending a [COMSIG_COMPONENT_REMOVING] signal
+ */
+/datum/component/Destroy(force=FALSE, silent=FALSE)
+ if(!force && parent)
+ _RemoveFromParent()
+ if(!silent)
+ SEND_SIGNAL(parent, COMSIG_COMPONENT_REMOVING, src)
+ parent = null
+ return ..()
+
+/**
+ * Internal proc to handle behaviour of components when joining a parent
+ */
/datum/component/proc/_JoinParent()
var/datum/P = parent
//lazy init the parent's dc list
@@ -51,21 +117,9 @@
RegisterWithParent()
-// If you want/expect to be moving the component around between parents, use this to register on the parent for signals
-/datum/component/proc/RegisterWithParent()
- return
-
-/datum/component/proc/Initialize(...)
- return
-
-/datum/component/Destroy(force=FALSE, silent=FALSE)
- if(!force && parent)
- _RemoveFromParent()
- if(!silent)
- SEND_SIGNAL(parent, COMSIG_COMPONENT_REMOVING, src)
- parent = null
- return ..()
-
+/**
+ * Internal proc to handle behaviour when being removed from a parent
+ */
/datum/component/proc/_RemoveFromParent()
var/datum/P = parent
var/list/dc = P.datum_components
@@ -84,10 +138,41 @@
UnregisterFromParent()
+/**
+ * Register the component with the parent object
+ *
+ * Use this proc to register with your parent object
+ *
+ * Overridable proc that's called when added to a new parent
+ */
+/datum/component/proc/RegisterWithParent()
+ return
+
+/**
+ * Unregister from our parent object
+ *
+ * Use this proc to unregister from your parent object
+ *
+ * Overridable proc that's called when removed from a parent
+ * *
+ */
/datum/component/proc/UnregisterFromParent()
return
-/datum/proc/RegisterSignal(datum/target, sig_type_or_types, proc_or_callback, override = FALSE)
+/**
+ * Register to listen for a signal from the passed in target
+ *
+ * This sets up a listening relationship such that when the target object emits a signal
+ * the source datum this proc is called upon, will recieve a callback to the given proctype
+ * Return values from procs registered must be a bitfield
+ *
+ * Arguments:
+ * * datum/target The target to listen for signals from
+ * * sig_type_or_types Either a string signal name, or a list of signal names (strings)
+ * * proctype The proc to call back when the signal is emitted
+ * * override If a previous registration exists you must explicitly set this
+ */
+/datum/proc/RegisterSignal(datum/target, sig_type_or_types, proctype, override = FALSE)
if(QDELETED(src) || QDELETED(target))
return
@@ -100,15 +185,12 @@
if(!lookup)
target.comp_lookup = lookup = list()
- if(!istype(proc_or_callback, /datum/callback)) //if it wasnt a callback before, it is now
- proc_or_callback = CALLBACK(src, proc_or_callback)
-
var/list/sig_types = islist(sig_type_or_types) ? sig_type_or_types : list(sig_type_or_types)
for(var/sig_type in sig_types)
if(!override && procs[target][sig_type])
stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning")
- procs[target][sig_type] = proc_or_callback
+ procs[target][sig_type] = proctype
if(!lookup[sig_type]) // Nothing has registered here yet
lookup[sig_type] = src
@@ -122,6 +204,17 @@
signal_enabled = TRUE
+/**
+ * Stop listening to a given signal from target
+ *
+ * Breaks the relationship between target and source datum, removing the callback when the signal fires
+ *
+ * Doesn't care if a registration exists or not
+ *
+ * Arguments:
+ * * datum/target Datum to stop listening to signals from
+ * * sig_typeor_types Signal string key or list of signal keys to stop listening to specifically
+ */
/datum/proc/UnregisterSignal(datum/target, sig_type_or_types)
var/list/lookup = target.comp_lookup
if(!signal_procs || !signal_procs[target] || !lookup)
@@ -129,6 +222,8 @@
if(!islist(sig_type_or_types))
sig_type_or_types = list(sig_type_or_types)
for(var/sig in sig_type_or_types)
+ if(!signal_procs[target][sig])
+ continue
switch(length(lookup[sig]))
if(2)
lookup[sig] = (lookup[sig]-src)[1]
@@ -151,41 +246,96 @@
if(!signal_procs[target].len)
signal_procs -= target
+/**
+ * Called on a component when a component of the same type was added to the same parent
+ *
+ * See [/datum/component/var/dupe_mode]
+ *
+ * `C`'s type will always be the same of the called component
+ */
/datum/component/proc/InheritComponent(datum/component/C, i_am_original)
return
+
+/**
+ * Called on a component when a component of the same type was added to the same parent with [COMPONENT_DUPE_SELECTIVE]
+ *
+ * See [/datum/component/var/dupe_mode]
+ *
+ * `C`'s type will always be the same of the called component
+ *
+ * return TRUE if you are absorbing the component, otherwise FALSE if you are fine having it exist as a duplicate component
+ */
+/datum/component/proc/CheckDupeComponent(datum/component/C, ...)
+ return
+
+
+/**
+ * Callback Just before this component is transferred
+ *
+ * Use this to do any special cleanup you might need to do before being deregged from an object
+ */
/datum/component/proc/PreTransfer()
return
+/**
+ * Callback Just after a component is transferred
+ *
+ * Use this to do any special setup you need to do after being moved to a new object
+ *
+ * Do not call `qdel(src)` from this function, `return COMPONENT_INCOMPATIBLE` instead
+ */
/datum/component/proc/PostTransfer()
return COMPONENT_INCOMPATIBLE //Do not support transfer by default as you must properly support it
+/**
+ * Internal proc to create a list of our type and all parent types
+ */
/datum/component/proc/_GetInverseTypeList(our_type = type)
//we can do this one simple trick
var/current_type = parent_type
. = list(our_type, current_type)
//and since most components are root level + 1, this won't even have to run
- while(current_type != /datum/component)
+ while (current_type != /datum/component)
current_type = type2parent(current_type)
. += current_type
+/**
+ * Internal proc to handle most all of the signaling procedure
+ *
+ * Will runtime if used on datums with an empty component list
+ *
+ * Use the [SEND_SIGNAL] define instead
+ */
/datum/proc/_SendSignal(sigtype, list/arguments)
var/target = comp_lookup[sigtype]
if(!length(target))
var/datum/C = target
if(!C.signal_enabled)
return NONE
- var/datum/callback/CB = C.signal_procs[src][sigtype]
- return CB.InvokeAsync(arglist(arguments))
+ var/proctype = C.signal_procs[src][sigtype]
+ return NONE | CallAsync(C, proctype, arguments)
. = NONE
for(var/I in target)
var/datum/C = I
if(!C.signal_enabled)
continue
- var/datum/callback/CB = C.signal_procs[src][sigtype]
- . |= CB.InvokeAsync(arglist(arguments))
+ var/proctype = C.signal_procs[src][sigtype]
+ . |= CallAsync(C, proctype, arguments)
-/datum/proc/GetComponent(c_type)
+// The type arg is casted so initial works, you shouldn't be passing a real instance into this
+/**
+ * Return any component assigned to this datum of the given type
+ *
+ * This will throw an error if it's possible to have more than one component of that type on the parent
+ *
+ * Arguments:
+ * * datum/component/c_type The typepath of the component you want to get a reference to
+ */
+/datum/proc/GetComponent(datum/component/c_type)
+ RETURN_TYPE(c_type)
+ if(initial(c_type.dupe_mode) == COMPONENT_DUPE_ALLOWED || initial(c_type.dupe_mode) == COMPONENT_DUPE_SELECTIVE)
+ stack_trace("GetComponent was called to get a component of which multiple copies could be on an object. This can easily break and should be changed. Type: \[[c_type]\]")
var/list/dc = datum_components
if(!dc)
return null
@@ -193,7 +343,19 @@
if(length(.))
return .[1]
-/datum/proc/GetExactComponent(c_type)
+// The type arg is casted so initial works, you shouldn't be passing a real instance into this
+/**
+ * Return any component assigned to this datum of the exact given type
+ *
+ * This will throw an error if it's possible to have more than one component of that type on the parent
+ *
+ * Arguments:
+ * * datum/component/c_type The typepath of the component you want to get a reference to
+ */
+/datum/proc/GetExactComponent(datum/component/c_type)
+ RETURN_TYPE(c_type)
+ if(initial(c_type.dupe_mode) == COMPONENT_DUPE_ALLOWED || initial(c_type.dupe_mode) == COMPONENT_DUPE_SELECTIVE)
+ stack_trace("GetComponent was called to get a component of which multiple copies could be on an object. This can easily break and should be changed. Type: \[[c_type]\]")
var/list/dc = datum_components
if(!dc)
return null
@@ -205,6 +367,12 @@
return C
return null
+/**
+ * Get all components of a given type that are attached to this datum
+ *
+ * Arguments:
+ * * c_type The component type path
+ */
/datum/proc/GetComponents(c_type)
var/list/dc = datum_components
if(!dc)
@@ -213,7 +381,19 @@
if(!length(.))
return list(.)
-/datum/proc/AddComponent(new_type, ...)
+/**
+ * Creates an instance of `new_type` in the datum and attaches to it as parent
+ *
+ * Sends the [COMSIG_COMPONENT_ADDED] signal to the datum
+ *
+ * Returns the component that was created. Or the old component in a dupe situation where [COMPONENT_DUPE_UNIQUE] was set
+ *
+ * If this tries to add a component to an incompatible type, the component will be deleted and the result will be `null`. This is very unperformant, try not to do it
+ *
+ * Properly handles duplicate situations based on the `dupe_mode` var
+ */
+/datum/proc/_AddComponent(list/raw_args)
+ var/new_type = raw_args[1]
var/datum/component/nt = new_type
var/dm = initial(nt.dupe_mode)
var/dt = initial(nt.dupe_type)
@@ -228,7 +408,7 @@
new_comp = nt
nt = new_comp.type
- args[1] = src
+ raw_args[1] = src
if(dm != COMPONENT_DUPE_ALLOWED)
if(!dt)
@@ -239,37 +419,62 @@
switch(dm)
if(COMPONENT_DUPE_UNIQUE)
if(!new_comp)
- new_comp = new nt(arglist(args))
+ new_comp = new nt(raw_args)
if(!QDELETED(new_comp))
old_comp.InheritComponent(new_comp, TRUE)
QDEL_NULL(new_comp)
if(COMPONENT_DUPE_HIGHLANDER)
if(!new_comp)
- new_comp = new nt(arglist(args))
+ new_comp = new nt(raw_args)
if(!QDELETED(new_comp))
new_comp.InheritComponent(old_comp, FALSE)
QDEL_NULL(old_comp)
if(COMPONENT_DUPE_UNIQUE_PASSARGS)
if(!new_comp)
- var/list/arguments = args.Copy(2)
- old_comp.InheritComponent(null, TRUE, arguments)
+ var/list/arguments = raw_args.Copy(2)
+ arguments.Insert(1, null, TRUE)
+ old_comp.InheritComponent(arglist(arguments))
else
old_comp.InheritComponent(new_comp, TRUE)
+ if(COMPONENT_DUPE_SELECTIVE)
+ var/list/arguments = raw_args.Copy()
+ arguments[1] = new_comp
+ var/make_new_component = TRUE
+ for(var/i in GetComponents(new_type))
+ var/datum/component/C = i
+ if(C.CheckDupeComponent(arglist(arguments)))
+ make_new_component = FALSE
+ QDEL_NULL(new_comp)
+ break
+ if(!new_comp && make_new_component)
+ new_comp = new nt(raw_args)
else if(!new_comp)
- new_comp = new nt(arglist(args)) // There's a valid dupe mode but there's no old component, act like normal
+ new_comp = new nt(raw_args) // There's a valid dupe mode but there's no old component, act like normal
else if(!new_comp)
- new_comp = new nt(arglist(args)) // Dupes are allowed, act like normal
+ new_comp = new nt(raw_args) // Dupes are allowed, act like normal
if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy
SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_comp)
return new_comp
return old_comp
+/**
+ * Get existing component of type, or create it and return a reference to it
+ *
+ * Use this if the item needs to exist at the time of this call, but may not have been created before now
+ *
+ * Arguments:
+ * * component_type The typepath of the component to create or return
+ * * ... additional arguments to be passed when creating the component if it does not exist
+ */
/datum/proc/LoadComponent(component_type, ...)
. = GetComponent(component_type)
if(!.)
- return AddComponent(arglist(args))
+ return _AddComponent(args)
+/**
+ * Removes the component from parent, ends up with a null parent
+ */
/datum/component/proc/RemoveComponent()
if(!parent)
return
@@ -279,6 +484,14 @@
parent = null
SEND_SIGNAL(old_parent, COMSIG_COMPONENT_REMOVING, src)
+/**
+ * Transfer this component to another parent
+ *
+ * Component is taken from source datum
+ *
+ * Arguments:
+ * * datum/component/target Target datum to transfer to
+ */
/datum/proc/TakeComponent(datum/component/target)
if(!target || target.parent == src)
return
@@ -295,6 +508,14 @@
if(target == AddComponent(target))
target._JoinParent()
+/**
+ * Transfer all components to target
+ *
+ * All components from source datum are taken
+ *
+ * Arguments:
+ * * /datum/target the target to move the components to
+ */
/datum/proc/TransferComponents(datum/target)
var/list/dc = datum_components
if(!dc)
@@ -309,5 +530,8 @@
if(C.can_transfer)
target.TakeComponent(comps)
+/**
+ * Return the object that is the host of any UI's that this component has
+ */
/datum/component/nano_host()
return parent
diff --git a/code/datums/components/decal.dm b/code/datums/components/decal.dm
index 6a0f686b13a..876cf0c0507 100644
--- a/code/datums/components/decal.dm
+++ b/code/datums/components/decal.dm
@@ -7,7 +7,7 @@
var/first_dir // This only stores the dir arg from init
-/datum/component/decal/Initialize(_icon, _icon_state, _dir, _cleanable=CLEAN_GOD, _color, _layer=TURF_LAYER, _description, _alpha=255)
+/datum/component/decal/Initialize(_icon, _icon_state, _dir, _cleanable = CLEAN_GOD, _color, _layer = TURF_LAYER, _description, _alpha = 255)
if(!isatom(parent) || !generate_appearance(_icon, _icon_state, _dir, _layer, _color, _alpha))
return COMPONENT_INCOMPATIBLE
first_dir = _dir
diff --git a/code/datums/components/edit_complainer.dm b/code/datums/components/edit_complainer.dm
new file mode 100644
index 00000000000..35bb05ca791
--- /dev/null
+++ b/code/datums/components/edit_complainer.dm
@@ -0,0 +1,23 @@
+// This is just a bit of fun while making an example for global signal
+/datum/component/edit_complainer
+ var/list/say_lines
+
+/datum/component/edit_complainer/Initialize(list/text)
+ if(!ismovableatom(parent))
+ return COMPONENT_INCOMPATIBLE
+
+ var/static/list/default_lines = list(
+ "CentComm's profligacy frays another thread.",
+ "Another tug at the weave.",
+ "Who knows when the stresses will finally shatter the form?",
+ "Even now a light shines through the cracks.",
+ "CentComm once more twists knowledge beyond its authority.",
+ "There is an uncertain air in the mansus.",
+ )
+ say_lines = text || default_lines
+
+ RegisterSignal(SSdcs, COMSIG_GLOB_VAR_EDIT, .proc/var_edit_react)
+
+/datum/component/edit_complainer/proc/var_edit_react(datum/source, list/arguments)
+ var/atom/movable/master = parent
+ master.atom_say(pick(say_lines))
diff --git a/code/datums/components/jestosterone.dm b/code/datums/components/jestosterone.dm
deleted file mode 100644
index f37f1f03efb..00000000000
--- a/code/datums/components/jestosterone.dm
+++ /dev/null
@@ -1,5 +0,0 @@
-/datum/component/jestosterone
- var/mind_type //Is the affected mob a clown / mime?
-
-/datum/component/jestosterone/Initialize(mind_type_arg)
- mind_type = mind_type_arg
diff --git a/code/datums/components/label.dm b/code/datums/components/label.dm
index 26cb99c7e3c..c6d0c595ebb 100644
--- a/code/datums/components/label.dm
+++ b/code/datums/components/label.dm
@@ -32,12 +32,12 @@
This proc will fire after the parent is hit by a hand labeler which is trying to apply another label.
Since the parent already has a label, it will remove the old one from the parent's name, and apply the new one.
*/
-/datum/component/label/InheritComponent(datum/component/label/new_comp , i_am_original, list/arguments)
+/datum/component/label/InheritComponent(datum/component/label/new_comp , i_am_original, _label_name)
remove_label()
if(new_comp)
label_name = new_comp.label_name
else
- label_name = arguments[1]
+ label_name = _label_name
apply_label()
/**
diff --git a/code/datums/components/slippery.dm b/code/datums/components/slippery.dm
new file mode 100644
index 00000000000..3e505eb0a8a
--- /dev/null
+++ b/code/datums/components/slippery.dm
@@ -0,0 +1,56 @@
+/**
+ * # Slip Component
+ *
+ * This is a component that can be applied to any movable atom (mob or obj).
+ *
+ * While the atom has this component, any human mob that walks over it will have a chance to slip.
+ * Duration, tiles moved, and so on, depend on what variables are passed in when the component is added.
+ *
+ */
+/datum/component/slippery
+ /// Text that gets displayed in the slip proc, i.e. "user slips on [description]"
+ var/description
+ /// The amount of stun to apply after slip.
+ var/stun
+ /// The amount of weaken to apply after slip.
+ var/weaken
+ /// The chance that walking over the parent will slip you.
+ var/slip_chance
+ /// The amount of tiles someone will be moved after slip.
+ var/slip_tiles
+ /// TRUE If this slip can be avoided by walking.
+ var/walking_is_safe
+ /// TRUE if having no slip shoes makes you immune to this slip.
+ var/noslip_is_immune
+ /// The verb that players will see when someone slips on the parent. In the form of "You [slip_verb]ped on".
+ var/slip_verb
+
+/datum/component/slippery/Initialize(_description, _stun = 0, _weaken = 0, _slip_chance = 100, _slip_tiles = 0, _walking_is_safe = TRUE, _noslip_is_immune = TRUE, _slip_verb = "slip")
+ if(!isatom(parent))
+ return COMPONENT_INCOMPATIBLE
+
+ description = _description
+ stun = max(0, _stun)
+ weaken = max(0, _weaken)
+ slip_chance = max(0, _slip_chance)
+ slip_tiles = max(0, _slip_tiles)
+ walking_is_safe = _walking_is_safe
+ noslip_is_immune = _noslip_is_immune
+ slip_verb = _slip_verb
+
+/datum/component/slippery/RegisterWithParent()
+ RegisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_ATOM_ENTERED), .proc/Slip)
+
+/datum/component/slippery/UnregisterFromParent()
+ UnregisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_ATOM_ENTERED))
+
+/**
+ Called whenever the parent recieves either the `MOVABLE_CROSSED` signal or the `ATOM_ENTERED` signal.
+
+ Calls the `victim`'s `slip()` proc with the component's variables as arguments.
+ Additionally calls the parent's `after_slip()` proc on the `victim`.
+*/
+/datum/component/slippery/proc/Slip(datum/source, mob/living/carbon/human/victim)
+ if(istype(victim) && prob(slip_chance) && victim.slip(description, stun, weaken, slip_tiles, walking_is_safe, noslip_is_immune, slip_verb))
+ var/atom/movable/owner = parent
+ owner.after_slip(victim)
diff --git a/code/datums/components/waddling.dm b/code/datums/components/waddling.dm
deleted file mode 100644
index a1f538e4dd7..00000000000
--- a/code/datums/components/waddling.dm
+++ /dev/null
@@ -1,15 +0,0 @@
-/datum/component/waddling
- dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
-
-/datum/component/waddling/Initialize()
- if(!isliving(parent))
- return COMPONENT_INCOMPATIBLE
- RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), .proc/Waddle)
-
-/datum/component/waddling/proc/Waddle()
- var/mob/living/L = parent
- if(L.incapacitated() || L.lying)
- return
- animate(L, pixel_z = 4, time = 0)
- animate(pixel_z = 0, transform = turn(matrix(), pick(-12, 0, 12)), time=2)
- animate(pixel_z = 0, transform = matrix(), time = 0)
diff --git a/code/datums/elements/_element.dm b/code/datums/elements/_element.dm
new file mode 100644
index 00000000000..46a295f90be
--- /dev/null
+++ b/code/datums/elements/_element.dm
@@ -0,0 +1,55 @@
+/**
+ * A holder for simple behaviour that can be attached to many different types
+ *
+ * Only one element of each type is instanced during game init.
+ * Otherwise acts basically like a lightweight component.
+ */
+/datum/element
+ /// Option flags for element behaviour
+ var/element_flags = NONE
+ /**
+ * The index of the first attach argument to consider for duplicate elements
+ *
+ * Is only used when flags contains [ELEMENT_BESPOKE]
+ *
+ * This is infinity so you must explicitly set this
+ */
+ var/id_arg_index = INFINITY
+
+/// Activates the functionality defined by the element on the given target datum
+/datum/element/proc/Attach(datum/target)
+ SHOULD_CALL_PARENT(1)
+ if(type == /datum/element)
+ return ELEMENT_INCOMPATIBLE
+ SEND_SIGNAL(target, COMSIG_ELEMENT_ATTACH, src)
+ if(element_flags & ELEMENT_DETACH)
+ RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/Detach, override = TRUE)
+
+/// Deactivates the functionality defines by the element on the given datum
+/datum/element/proc/Detach(datum/source, force)
+ SEND_SIGNAL(source, COMSIG_ELEMENT_DETACH, src)
+ SHOULD_CALL_PARENT(1)
+ UnregisterSignal(source, COMSIG_PARENT_QDELETING)
+
+/datum/element/Destroy(force)
+ if(!force)
+ return QDEL_HINT_LETMELIVE
+ SSdcs.elements_by_type -= type
+ return ..()
+
+//DATUM PROCS
+
+/// Finds the singleton for the element type given and attaches it to src
+/datum/proc/_AddElement(list/arguments)
+ var/datum/element/ele = SSdcs.GetElement(arguments)
+ arguments[1] = src
+ if(ele.Attach(arglist(arguments)) == ELEMENT_INCOMPATIBLE)
+ CRASH("Incompatible [arguments[1]] assigned to a [type]! args: [json_encode(args)]")
+
+/**
+ * Finds the singleton for the element type given and detaches it from src
+ * You only need additional arguments beyond the type if you're using [ELEMENT_BESPOKE]
+ */
+/datum/proc/_RemoveElement(list/arguments)
+ var/datum/element/ele = SSdcs.GetElement(arguments)
+ ele.Detach(src)
diff --git a/code/datums/elements/waddling.dm b/code/datums/elements/waddling.dm
new file mode 100644
index 00000000000..6abe75b3923
--- /dev/null
+++ b/code/datums/elements/waddling.dm
@@ -0,0 +1,25 @@
+/datum/element/waddling
+
+/datum/element/waddling/Attach(datum/target)
+ . = ..()
+ if(!ismovableatom(target))
+ return ELEMENT_INCOMPATIBLE
+ if(isliving(target))
+ RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/LivingWaddle)
+ else
+ RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/Waddle)
+
+/datum/element/waddling/Detach(datum/source, force)
+ . = ..()
+ UnregisterSignal(source, COMSIG_MOVABLE_MOVED)
+
+/datum/element/waddling/proc/LivingWaddle(mob/living/target)
+ if(target.incapacitated() || target.lying)
+ return
+ Waddle(target)
+
+/datum/element/waddling/proc/Waddle(atom/movable/target)
+ animate(target, pixel_z = 4, time = 0)
+ var/prev_trans = matrix(target.transform)
+ animate(pixel_z = 0, transform = turn(target.transform, pick(-12, 0, 12)), time = 2)
+ animate(pixel_z = 0, transform = prev_trans, time = 0)
diff --git a/code/datums/status_effects/status_effect.dm b/code/datums/status_effects/status_effect.dm
index 74abf104465..2580b1c9935 100644
--- a/code/datums/status_effects/status_effect.dm
+++ b/code/datums/status_effects/status_effect.dm
@@ -5,7 +5,7 @@
/datum/status_effect
var/id = "effect" //Used for screen alerts.
var/duration = -1 //How long the status effect lasts in DECISECONDS. Enter -1 for an effect that never ends unless removed through some means.
- var/tick_interval = 10 //How many deciseconds between ticks, approximately. Leave at 10 for every second.
+ var/tick_interval = 10 //How many deciseconds between ticks, approximately. Leave at 10 for every second. Setting this to -1 will stop processing if duration is also unlimited.
var/mob/living/owner //The mob affected by the status effect.
var/status_type = STATUS_EFFECT_UNIQUE //How many of the effect can be on one mob, and what happens when you try to add another
var/on_remove_on_mob_delete = FALSE //if we call on_remove() when the mob is deleted
@@ -31,7 +31,8 @@
var/obj/screen/alert/status_effect/A = owner.throw_alert(id, alert_type)
A.attached_effect = src //so the alert can reference us, if it needs to
linked_alert = A //so we can reference the alert, if we need to
- START_PROCESSING(SSfastprocess, src)
+ if(duration > 0 || initial(tick_interval) > 0) //don't process if we don't care
+ START_PROCESSING(SSfastprocess, src)
return TRUE
/datum/status_effect/Destroy()
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 365e06aca4b..abd224e409b 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -395,6 +395,17 @@
/atom/proc/get_spooked()
return
+/**
+ Base proc, intended to be overriden.
+
+ This should only be called from one place: inside the slippery component.
+ Called after a human mob slips on this atom.
+
+ If you want the person who slipped to have something special done to them, put it here.
+*/
+/atom/proc/after_slip(mob/living/carbon/human/H)
+ return
+
/atom/proc/add_hiddenprint(mob/living/M as mob)
if(isnull(M)) return
if(isnull(M.key)) return
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 9f2a0e09aee..abf878f9812 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -333,7 +333,6 @@
SSspacedrift.processing[src] = src
return 1
-
//called when src is thrown into hit_atom
/atom/movable/proc/throw_impact(atom/hit_atom, throwingdatum)
set waitfor = 0
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index bedc3c4809b..0da5d8a3a0a 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -399,6 +399,9 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
if(!steal_target)
return 1 // Free Objective
+ if(!owner.current)
+ return FALSE
+
var/list/all_items = owner.current.GetAllContents()
for(var/obj/I in all_items)
diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm
index a30799f08b9..d5c5089c8af 100644
--- a/code/game/jobs/job/job.dm
+++ b/code/game/jobs/job/job.dm
@@ -51,6 +51,7 @@
var/disabilities_allowed = 1
var/transfer_allowed = TRUE // If false, ID computer will always discourage transfers to this job, even if player is eligible
+ var/hidden_from_job_prefs = FALSE // if true, job preferences screen never shows this job.
var/admin_only = 0
var/spawn_ert = 0
diff --git a/code/game/jobs/job/support.dm b/code/game/jobs/job/support.dm
index d0064300b62..f2b8cf31671 100644
--- a/code/game/jobs/job/support.dm
+++ b/code/game/jobs/job/support.dm
@@ -450,3 +450,24 @@
/obj/item/storage/box/lip_stick = 1,
/obj/item/storage/box/barber = 1
)
+
+/datum/job/explorer
+ title = "Explorer"
+ flag = JOB_EXPLORER
+ department_flag = JOBCAT_SUPPORT
+ total_positions = 0
+ spawn_positions = 0
+ supervisors = "the head of personnel"
+ selection_color = "#dddddd"
+ access = list(ACCESS_MAINT_TUNNELS, ACCESS_GATEWAY, ACCESS_EVA, ACCESS_EXTERNAL_AIRLOCKS)
+ minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_GATEWAY, ACCESS_EVA, ACCESS_EXTERNAL_AIRLOCKS)
+ outfit = /datum/outfit/job/explorer
+ hidden_from_job_prefs = TRUE
+
+/datum/outfit/job/explorer
+ // This outfit is never used, because there are no slots for this job.
+ // To get it, you have to go to the HOP and ask for a transfer to it.
+ name = "Explorer"
+ jobtype = /datum/job/explorer
+ uniform = /obj/item/clothing/under/color/random
+ shoes = /obj/item/clothing/shoes/black
diff --git a/code/game/jobs/jobs.dm b/code/game/jobs/jobs.dm
index 8ff6b58e5c4..81cc54aa3c3 100644
--- a/code/game/jobs/jobs.dm
+++ b/code/game/jobs/jobs.dm
@@ -58,7 +58,8 @@ GLOBAL_LIST_INIT(support_positions, list(
"Barber",
"Magistrate",
"Nanotrasen Representative",
- "Blueshield"
+ "Blueshield",
+ "Explorer"
))
GLOBAL_LIST_INIT(supply_positions, list(
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index 78367327a0c..7a0c2483b40 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -38,7 +38,7 @@
var/list/categories = list("Tools", "Electronics", "Construction", "Communication", "Security", "Machinery", "Medical", "Miscellaneous", "Dinnerware", "Imported")
/obj/machinery/autolathe/New()
- AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS), 0, TRUE, null, null, CALLBACK(src, .proc/AfterMaterialInsert))
+ AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS), _show_on_examine=TRUE, _after_insert=CALLBACK(src, .proc/AfterMaterialInsert))
..()
component_parts = list()
component_parts += new /obj/item/circuitboard/autolathe(null)
@@ -66,7 +66,7 @@
/obj/machinery/autolathe/Destroy()
QDEL_NULL(wires)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.retrieve_all()
return ..()
@@ -87,7 +87,7 @@
ui.open()
/obj/machinery/autolathe/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/data[0]
data["screen"] = screen
data["total_amount"] = materials.total_amount
@@ -138,7 +138,7 @@
/obj/machinery/autolathe/proc/design_cost_data(datum/design/D)
var/list/data = list()
var/coeff = get_coeff(D)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/has_metal = 1
if(D.materials[MAT_METAL] && (materials.amount(MAT_METAL) < (D.materials[MAT_METAL] / coeff)))
has_metal = 0
@@ -152,7 +152,7 @@
return data
/obj/machinery/autolathe/proc/queue_data(list/data)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/temp_metal = materials.amount(MAT_METAL)
var/temp_glass = materials.amount(MAT_GLASS)
data["processing"] = being_built.len ? get_processing_line() : null
@@ -288,7 +288,7 @@
//multiplier checks : only stacks can have one and its value is 1, 10 ,25 or max_multiplier
var/multiplier = text2num(href_list["multiplier"])
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/max_multiplier = min(design_last_ordered.maxstack, design_last_ordered.materials[MAT_METAL] ?round(materials.amount(MAT_METAL)/design_last_ordered.materials[MAT_METAL]):INFINITY,design_last_ordered.materials[MAT_GLASS]?round(materials.amount(MAT_GLASS)/design_last_ordered.materials[MAT_GLASS]):INFINITY)
var/is_stack = ispath(design_last_ordered.build_path, /obj/item/stack)
@@ -342,7 +342,7 @@
for(var/obj/item/stock_parts/matter_bin/MB in component_parts)
tot_rating += MB.rating
tot_rating *= 25000
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.max_amount = tot_rating * 3
for(var/obj/item/stock_parts/manipulator/M in component_parts)
prod_coeff += M.rating - 1
@@ -355,7 +355,7 @@
desc = initial(desc)+"\nIt's building \a [initial(D.name)]."
var/is_stack = ispath(D.build_path, /obj/item/stack)
var/coeff = get_coeff(D)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/metal_cost = D.materials[MAT_METAL]
var/glass_cost = D.materials[MAT_GLASS]
var/power = max(2000, (metal_cost+glass_cost)*multiplier/5)
@@ -387,7 +387,7 @@
return 0
var/coeff = get_coeff(D)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/metal_amount = materials.amount(MAT_METAL)
if(custom_metal)
metal_amount = custom_metal
diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm
index adc4175a45d..993a1c5cbaa 100644
--- a/code/game/machinery/computer/buildandrepair.dm
+++ b/code/game/machinery/computer/buildandrepair.dm
@@ -45,7 +45,6 @@
var/list/req_components = null
var/powernet = null
var/list/records = null
- var/frame_desc = null
var/contain_parts = 1
toolspeed = 1
usesound = 'sound/items/deconstruct.ogg'
@@ -64,7 +63,7 @@
var/atom/A = B
if(!ispath(A))
continue
- nice_list += list("[req_components[A]] [initial(A.name)]")
+ nice_list += list("[req_components[A]] [initial(A.name)]\s")
. += "Required components: [english_list(nice_list)]."
/obj/item/circuitboard/message_monitor
diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm
index 40005f8fd12..978ba25b8d3 100644
--- a/code/game/machinery/computer/card.dm
+++ b/code/game/machinery/computer/card.dm
@@ -25,7 +25,8 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
/datum/job/ntnavyofficer,
/datum/job/ntspecops,
/datum/job/civilian,
- /datum/job/syndicateofficer
+ /datum/job/syndicateofficer,
+ /datum/job/explorer // blacklisted so that HOPs don't try prioritizing it, then wonder why that doesn't work
)
// Jobs that appear in the list, and you can prioritize, but not open/close slots for
var/list/blacklisted_partial = list(
diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm
index 92db2f4a419..96863c3e54d 100644
--- a/code/game/machinery/constructable_frame.dm
+++ b/code/game/machinery/constructable_frame.dm
@@ -218,7 +218,7 @@
//Machine Frame Circuit Boards
/*Common Parts: Parts List: Ignitor, Timer, Infra-red laser, Infra-red sensor, t_scanner, Capacitor, Valve, sensor unit,
-micro-manipulator, console screen, beaker, Microlaser, matter bin, power cells.
+micro-manipulator, glass sheets, beaker, Microlaser, matter bin, power cells.
Note: Once everything is added to the public areas, will add MAT_METAL and MAT_GLASS to circuit boards since autolathe won't be able
to destroy them and players will be able to make replacements.
*/
@@ -226,7 +226,6 @@ to destroy them and players will be able to make replacements.
name = "circuit board (Booze-O-Mat Vendor)"
board_type = "machine"
origin_tech = "programming=1"
- frame_desc = "Requires 1 Resupply Canister."
build_path = /obj/machinery/vending/boozeomat
req_components = list(/obj/item/vending_refill/boozeomat = 1)
@@ -282,7 +281,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/power/smes
board_type = "machine"
origin_tech = "programming=3;powerstorage=3;engineering=3"
- frame_desc = "Requires 5 pieces of cable, 5 Power Cells and 1 Capacitor."
req_components = list(
/obj/item/stack/cable_coil = 5,
/obj/item/stock_parts/cell = 5,
@@ -321,7 +319,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/atmospherics/unary/cold_sink/freezer
board_type = "machine"
origin_tech = "programming=3;plasmatech=3"
- frame_desc = "Requires 2 Matter Bins, 2 Micro Lasers, 1 piece of cable and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/matter_bin = 2,
/obj/item/stock_parts/micro_laser = 2,
@@ -346,7 +343,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/recharger
board_type = "machine"
origin_tech = "powerstorage=3;materials=2"
- frame_desc = "Requires 1 Capacitor"
req_components = list(/obj/item/stock_parts/capacitor = 1)
/obj/item/circuitboard/snow_machine
@@ -354,7 +350,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/snow_machine
board_type = "machine"
origin_tech = "programming=2;materials=2"
- frame_desc = "Requires 1 Matter Bin and 1 Micro Laser."
req_components = list(
/obj/item/stock_parts/matter_bin = 1,
/obj/item/stock_parts/micro_laser = 1)
@@ -364,7 +359,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/biogenerator
board_type = "machine"
origin_tech = "programming=2;biotech=3;materials=3"
- frame_desc = "Requires 1 Matter Bin, 1 Manipulator, 1 piece of cable and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/matter_bin = 1,
/obj/item/stock_parts/manipulator = 1,
@@ -376,7 +370,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/plantgenes
board_type = "machine"
origin_tech = "programming=3;biotech=3"
- frame_desc = "Requires 1 Manipulator, 1 Micro Laser, 1 Console Screen, and 1 Scanning Module."
req_components = list(
/obj/item/stock_parts/manipulator = 1,
/obj/item/stock_parts/micro_laser = 1,
@@ -390,7 +383,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/seed_extractor
board_type = "machine"
origin_tech = "programming=1"
- frame_desc = "Requires 1 Matter Bin and 1 Manipulator."
req_components = list(
/obj/item/stock_parts/matter_bin = 1,
/obj/item/stock_parts/manipulator = 1)
@@ -400,7 +392,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/hydroponics/constructable
board_type = "machine"
origin_tech = "programming=1;biotech=2"
- frame_desc = "Requires 2 Matter Bins, 1 Manipulator, and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/matter_bin = 2,
/obj/item/stock_parts/manipulator = 1,
@@ -411,7 +402,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/kitchen_machine/microwave
board_type = "machine"
origin_tech = "programming=2;magnets=2"
- frame_desc = "Requires 1 Micro Laser, 2 pieces of cable and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/micro_laser = 1,
/obj/item/stack/cable_coil = 2,
@@ -422,7 +412,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/kitchen_machine/oven
board_type = "machine"
origin_tech = "programming=2;magnets=2"
- frame_desc = "Requires 2 Micro Lasers, 5 pieces of cable and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/micro_laser = 2,
/obj/item/stack/cable_coil = 5,
@@ -433,7 +422,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/kitchen_machine/grill
board_type = "machine"
origin_tech = "programming=2;magnets=2"
- frame_desc = "Requires 2 Micro Lasers, 5 pieces of cable and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/micro_laser = 2,
/obj/item/stack/cable_coil = 5,
@@ -444,7 +432,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/kitchen_machine/candy_maker
board_type = "machine"
origin_tech = "programming=2;magnets=2"
- frame_desc = "Requires 1 Manipulator, 5 pieces of cable and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/manipulator = 1,
/obj/item/stack/cable_coil = 5,
@@ -455,7 +442,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/cooker/deepfryer
board_type = "machine"
origin_tech = "programming=1"
- frame_desc = "Requires 2 Micro Lasers and 5 pieces of cable."
req_components = list(
/obj/item/stock_parts/micro_laser = 2,
/obj/item/stack/cable_coil = 5)
@@ -568,7 +554,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/chem_dispenser
board_type = "machine"
origin_tech = "materials=4;programming=4;plasmatech=4;biotech=3"
- frame_desc = "Requires 2 Matter Bins, 1 Capacitor, 1 Manipulator, 1 Console Screen, and 1 Power Cell."
req_components = list( /obj/item/stock_parts/matter_bin = 2,
/obj/item/stock_parts/capacitor = 1,
/obj/item/stock_parts/manipulator = 1,
@@ -609,7 +594,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/chem_heater
board_type = "machine"
origin_tech = "programming=2;engineering=2;biotech=2"
- frame_desc = "Requires 1 Micro Laser and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/micro_laser = 1,
/obj/item/stack/sheet/glass = 1)
@@ -619,7 +603,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/reagentgrinder/empty
board_type = "machine"
origin_tech = "materials=2;engineering=2;biotech=2"
- frame_desc = "Requires 2 Manipulators and 1 Matter Bin."
req_components = list(
/obj/item/stock_parts/manipulator = 2,
/obj/item/stock_parts/matter_bin = 1)
@@ -640,7 +623,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/r_n_d/destructive_analyzer
board_type = "machine"
origin_tech = "magnets=2;engineering=2;programming=2"
- frame_desc = "Requires 1 Scanning Module, 1 Manipulator, and 1 Micro-Laser."
req_components = list(
/obj/item/stock_parts/scanning_module = 1,
/obj/item/stock_parts/manipulator = 1,
@@ -651,7 +633,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/autolathe
board_type = "machine"
origin_tech = "engineering=2;programming=2"
- frame_desc = "Requires 3 Matter Bins, 1 Manipulator, and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/matter_bin = 3,
/obj/item/stock_parts/manipulator = 1,
@@ -662,7 +643,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/r_n_d/protolathe
board_type = "machine"
origin_tech = "engineering=2;programming=2"
- frame_desc = "Requires 2 Matter Bins, 2 Manipulators, and 2 Beakers."
req_components = list(
/obj/item/stock_parts/matter_bin = 2,
/obj/item/stock_parts/manipulator = 2,
@@ -681,7 +661,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/r_n_d/circuit_imprinter
board_type = "machine"
origin_tech = "engineering=2;programming=2"
- frame_desc = "Requires 1 Matter Bin, 1 Manipulator, and 2 Beakers."
req_components = list(
/obj/item/stock_parts/matter_bin = 1,
/obj/item/stock_parts/manipulator = 1,
@@ -692,7 +671,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/power/port_gen/pacman
board_type = "machine"
origin_tech = "programming=2;powerstorage=3;plasmatech=3;engineering=3"
- frame_desc = "Requires 1 Matter Bin, 1 Micro-Laser, 2 Pieces of Cable, and 1 Capacitor."
req_components = list(
/obj/item/stock_parts/matter_bin = 1,
/obj/item/stock_parts/micro_laser = 1,
@@ -714,7 +692,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/r_n_d/server
board_type = "machine"
origin_tech = "programming=3"
- frame_desc = "Requires 2 pieces of cable, and 1 Scanning Module."
req_components = list(
/obj/item/stack/cable_coil = 2,
/obj/item/stock_parts/scanning_module = 1)
@@ -724,7 +701,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/mecha_part_fabricator
board_type = "machine"
origin_tech = "programming=2;engineering=2"
- frame_desc = "Requires 2 Matter Bins, 1 Manipulator, 1 Micro-Laser and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/matter_bin = 2,
/obj/item/stock_parts/manipulator = 1,
@@ -736,7 +712,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/mecha_part_fabricator/spacepod
board_type = "machine"
origin_tech = "programming=2;engineering=2"
- frame_desc = "Requires 2 Matter Bins, 1 Manipulators, 1 Micro-Lasers, and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/matter_bin = 2,
/obj/item/stock_parts/manipulator = 1,
@@ -749,7 +724,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/clonepod
board_type = "machine"
origin_tech = "programming=2;biotech=2"
- frame_desc = "Requires 2 Manipulator, 2 Scanning Module, 2 pieces of cable and 1 Console Screen."
req_components = list(
/obj/item/stack/cable_coil = 2,
/obj/item/stock_parts/scanning_module = 2,
@@ -761,7 +735,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/dna_scannernew
board_type = "machine"
origin_tech = "programming=2;biotech=2"
- frame_desc = "Requires 1 Scanning Module, 1 Manipulator, 1 Micro-Laser, 2 pieces of cable and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/scanning_module = 1,
/obj/item/stock_parts/manipulator = 1,
@@ -774,7 +747,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/mech_bay_recharge_port
board_type = "machine"
origin_tech = "programming=3;powerstorage=3;engineering=3"
- frame_desc = "Requires 1 piece of cable and 5 Capacitors."
req_components = list(
/obj/item/stack/cable_coil = 1,
/obj/item/stock_parts/capacitor = 5)
@@ -784,7 +756,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/teleport/hub
board_type = "machine"
origin_tech = "programming=3;engineering=4;bluespace=4;materials=4"
- frame_desc = "Requires 3 Bluespace Crystals and 1 Matter Bin."
req_components = list(
/obj/item/stack/ore/bluespace_crystal = 3,
/obj/item/stock_parts/matter_bin = 1)
@@ -794,7 +765,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/teleport/station
board_type = "machine"
origin_tech = "programming=4;engineering=4;bluespace=4;plasmatech=3"
- frame_desc = "Requires 2 Bluespace Crystals, 2 Capacitors and 1 Console Screen."
req_components = list(
/obj/item/stack/ore/bluespace_crystal = 2,
/obj/item/stock_parts/capacitor = 2,
@@ -805,7 +775,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/teleport/perma
board_type = "machine"
origin_tech = "programming=3;engineering=4;bluespace=4;materials=4"
- frame_desc = "Requires 3 Bluespace Crystals and 1 Matter Bin."
req_components = list(
/obj/item/stack/ore/bluespace_crystal = 3,
/obj/item/stock_parts/matter_bin = 1)
@@ -825,7 +794,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/telepad
board_type = "machine"
origin_tech = "programming=4;engineering=3;plasmatech=4;bluespace=4"
- frame_desc = "Requires 2 Bluespace Crystals, 1 Capacitor, 1 piece of cable and 1 Console Screen."
req_components = list(
/obj/item/stack/ore/bluespace_crystal = 2,
/obj/item/stock_parts/capacitor = 1,
@@ -837,7 +805,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/quantumpad
board_type = "machine"
origin_tech = "programming=3;engineering=3;plasmatech=3;bluespace=4"
- frame_desc = "Requires 1 Bluespace Crystal, 1 Capacitor, 1 piece of cable and 1 Manipulator."
req_components = list(
/obj/item/stack/ore/bluespace_crystal = 1,
/obj/item/stock_parts/capacitor = 1,
@@ -849,7 +816,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/sleeper
board_type = "machine"
origin_tech = "programming=3;biotech=2;engineering=3"
- frame_desc = "Requires 1 Matter Bin, 1 Manipulator, 1 piece of cable and 2 Console Screens."
req_components = list(
/obj/item/stock_parts/matter_bin = 1,
/obj/item/stock_parts/manipulator = 1,
@@ -870,7 +836,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/bodyscanner
board_type = "machine"
origin_tech = "programming=3;biotech=2;engineering=3"
- frame_desc = "Requires 1 Scanning Module, 2 pieces of cable and 2 Console Screens."
req_components = list(
/obj/item/stock_parts/scanning_module = 1,
/obj/item/stack/cable_coil = 2,
@@ -881,7 +846,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/atmospherics/unary/cryo_cell
board_type = "machine"
origin_tech = "programming=4;biotech=3;engineering=4;plasmatech=3"
- frame_desc = "Requires 1 Matter Bin, 1 piece of cable and 4 Console Screens."
req_components = list(
/obj/item/stock_parts/matter_bin = 1,
/obj/item/stack/cable_coil = 1,
@@ -892,7 +856,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/recharge_station
board_type = "machine"
origin_tech = "powerstorage=3;engineering=3"
- frame_desc = "Requires 2 Capacitors, 1 Power Cell and 1 Manipulator."
req_components = list(
/obj/item/stock_parts/capacitor = 2,
/obj/item/stock_parts/cell = 1,
@@ -904,7 +867,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/tcomms/relay
board_type = "machine"
origin_tech = "programming=2;engineering=2;bluespace=2"
- frame_desc = "Requires 2 Manipulators and 2 Cable Coil."
req_components = list(/obj/item/stock_parts/manipulator = 2, /obj/item/stack/cable_coil = 2)
/obj/item/circuitboard/tcomms/core
@@ -912,7 +874,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/tcomms/core
board_type = "machine"
origin_tech = "programming=2;engineering=2"
- frame_desc = "Requires 2 Manipulators and 2 Cable Coil."
req_components = list(/obj/item/stock_parts/manipulator = 2, /obj/item/stack/cable_coil = 2)
// End telecomms circuit boards
/obj/item/circuitboard/ore_redemption
@@ -983,7 +944,6 @@ to destroy them and players will be able to make replacements.
board_type = "machine"
origin_tech = "programming=1" //This stuff is pretty much the absolute basis of programming, so it's mostly useless for research
req_components = list(/obj/item/stack/cable_coil = 1)
-
var/list/names_paths = list(
"NOT Gate" = /obj/machinery/logic_gate/not,
"OR Gate" = /obj/machinery/logic_gate/or,
diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm
index fc758d446f9..8d842179db5 100644
--- a/code/game/machinery/doors/brigdoors.dm
+++ b/code/game/machinery/doors/brigdoors.dm
@@ -338,10 +338,9 @@
F.flash()
if(href_list["release"])
- var/obj/machinery/door_timer/T = locate(href_list["release"])
if(timing)
- T.timer_end()
- T.Radio.autosay("Timer stopped manually from cell control.", T.name, "Security", list(z))
+ timer_end()
+ Radio.autosay("Timer stopped manually from cell control.", name, "Security", list(z))
ui_interact(usr)
if(href_list["prisoner_name"])
diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm
index 081a48c3da1..e4e37ae1bcb 100644
--- a/code/game/machinery/recycler.dm
+++ b/code/game/machinery/recycler.dm
@@ -19,8 +19,7 @@
var/item_recycle_sound = 'sound/machines/recycler.ogg'
/obj/machinery/recycler/New()
- AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS, MAT_PLASMA, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_URANIUM, MAT_BANANIUM, MAT_TRANQUILLITE, MAT_TITANIUM, MAT_PLASTIC, MAT_BLUESPACE), 0,
- TRUE, null, null, null, TRUE)
+ AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS, MAT_PLASMA, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_URANIUM, MAT_BANANIUM, MAT_TRANQUILLITE, MAT_TITANIUM, MAT_PLASTIC, MAT_BLUESPACE), 0, TRUE, null, null, null, TRUE)
..()
component_parts = list()
component_parts += new /obj/item/circuitboard/recycler(null)
@@ -37,7 +36,7 @@
mat_mod *= 50000
for(var/obj/item/stock_parts/manipulator/M in component_parts)
amt_made = 25 * M.rating //% of materials salvaged
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.max_amount = mat_mod
amount_produced = min(100, amt_made)
@@ -135,7 +134,7 @@
/obj/machinery/recycler/proc/recycle_item(obj/item/I)
I.forceMove(loc)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/material_amount = materials.get_item_material_amount(I)
if(!material_amount)
qdel(I)
diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm
index 43937ab1111..61ba683ad18 100644
--- a/code/game/mecha/equipment/tools/other_tools.dm
+++ b/code/game/mecha/equipment/tools/other_tools.dm
@@ -206,6 +206,7 @@
/obj/item/mecha_parts/mecha_equipment/repair_droid/detach()
chassis.overlays -= droid_overlay
STOP_PROCESSING(SSobj, src)
+ return ..()
/obj/item/mecha_parts/mecha_equipment/repair_droid/get_equip_info()
if(!chassis) return
diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index 90256fe5d2a..7d8537c7910 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -38,9 +38,7 @@
)
/obj/machinery/mecha_part_fabricator/New()
- var/datum/component/material_container/materials = AddComponent(/datum/component/material_container,
- list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TRANQUILLITE, MAT_TITANIUM, MAT_BLUESPACE), 0,
- FALSE, /obj/item/stack, CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
+ var/datum/component/material_container/materials = AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TRANQUILLITE, MAT_TITANIUM, MAT_BLUESPACE), 0, FALSE, /obj/item/stack, CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
materials.precise_insertion = TRUE
..()
component_parts = list()
@@ -65,7 +63,7 @@
RefreshParts()
/obj/machinery/mecha_part_fabricator/Destroy()
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.retrieve_all()
return ..()
@@ -75,7 +73,7 @@
//maximum stocking amount (default 300000, 600000 at T4)
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
T += M.rating
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.max_amount = (200000 + (T*50000))
//resources adjustment coefficient (1 -> 0.85 -> 0.7 -> 0.55)
@@ -118,7 +116,7 @@
/obj/machinery/mecha_part_fabricator/proc/output_available_resources()
var/output
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
for(var/mat_id in materials.materials)
var/datum/material/M = materials.materials[mat_id]
output += "[M.name]: [M.amount] cm³"
@@ -139,7 +137,7 @@
/obj/machinery/mecha_part_fabricator/proc/check_resources(datum/design/D)
if(D.reagents_list.len) // No reagents storage - no reagent designs.
return FALSE
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
if(materials.has_materials(get_resources_w_coeff(D)))
return TRUE
return FALSE
@@ -149,7 +147,7 @@
desc = "It's building \a [initial(D.name)]."
var/list/res_coef = get_resources_w_coeff(D)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.use_amount(res_coef)
overlays += "fab-active"
use_power = ACTIVE_POWER_USE
@@ -414,7 +412,7 @@
break
if(href_list["remove_mat"] && href_list["material"])
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.retrieve_sheets(text2num(href_list["remove_mat"]), href_list["material"])
updateUsrDialog()
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index fba55ba0557..ab6ebe6a0fe 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -98,15 +98,6 @@ GLOBAL_DATUM_INIT(fire_overlay, /image, image("icon" = 'icons/goonstation/effect
var/icon_override = null //Used to override hardcoded clothing dmis in human clothing proc.
var/sprite_sheets_obj = null //Used to override hardcoded clothing inventory object dmis in human clothing proc.
- var/trip_verb = TV_TRIP
- var/trip_chance = 0
-
- var/trip_stun = 0
- var/trip_weaken = 0
- var/trip_any = FALSE
- var/trip_walksafe = TRUE
- var/trip_tiles = 0
-
//Tooltip vars
var/in_inventory = FALSE //is this item equipped into an inventory slot or hand of a mob?
var/tip_timer = 0
@@ -606,16 +597,6 @@ GLOBAL_DATUM_INIT(fire_overlay, /image, image("icon" = 'icons/goonstation/effect
/obj/item/proc/is_equivalent(obj/item/I)
return I == src
-/obj/item/Crossed(atom/movable/AM, oldloc)
- . = ..()
- if(prob(trip_chance) && ishuman(AM))
- var/mob/living/carbon/human/H = AM
- on_trip(H)
-
-/obj/item/proc/on_trip(mob/living/carbon/human/H)
- if(H.slip(src, trip_stun, trip_weaken, trip_tiles, trip_walksafe, trip_any, trip_verb))
- return TRUE
-
/obj/item/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
return
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index 8e51a6760b7..21795fb738c 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -1023,6 +1023,18 @@ obj/item/toy/cards/deck/syndicate/black
name = "orange fox plushie"
icon_state = "orangefox"
+/obj/item/toy/plushie/orange_fox/grump
+ name = "grumpy fox"
+ desc = "An ancient plushie that seems particularly grumpy."
+
+/obj/item/toy/plushie/orange_fox/grump/ComponentInitialize()
+ . = ..()
+ var/static/list/grumps = list("Ahh, yes, you're so clever, var editing that.", "Really?", "If you make a runtime with var edits, it's your own damn fault.",
+ "Don't you dare post issues on the git when you don't even know how this works.", "Was that necessary?", "Ohhh, setting admin edited var must be your favorite pastime!",
+ "Oh, so you have time to var edit, but you don't have time to ban that greytider?", "Oh boy, is this another one of those 'events'?", "Seriously, just stop.", "You do realize this is incurring proc call overhead.",
+ "Congrats, you just left a reference with your dirty client and now that thing you edited will never garbage collect properly.", "Is it that time of day, again, for unecessary adminbus?")
+ AddComponent(/datum/component/edit_complainer, grumps)
+
/obj/item/toy/plushie/coffee_fox
name = "coffee fox plushie"
icon_state = "coffeefox"
@@ -1087,6 +1099,21 @@ obj/item/toy/cards/deck/syndicate/black
return
..()
+/obj/item/toy/plushie/ipcplushie
+ name = "IPC plushie"
+ desc = "An adorable IPC plushie, straight from New Canaan. Arguably more durable than the real deal. Toaster functionality included."
+ icon_state = "plushie_ipc"
+ item_state = "plushie_ipc"
+
+/obj/item/toy/plushie/ipcplushie/attackby(obj/item/B, mob/user, params)
+ if(istype(B, /obj/item/reagent_containers/food/snacks/breadslice))
+ new /obj/item/reagent_containers/food/snacks/toast(get_turf(loc))
+ to_chat(user, " You insert bread into the toaster. ")
+ playsound(loc, 'sound/machines/ding.ogg', 50, 1)
+ qdel(B)
+ else
+ return ..()
+
//New generation TG plushies
/obj/item/toy/plushie/lizardplushie
@@ -1117,15 +1144,15 @@ obj/item/toy/cards/deck/syndicate/black
* Foam Armblade
*/
- /obj/item/toy/foamblade
- name = "foam armblade"
- desc = "it says \"Sternside Changs #1 fan\" on it. "
- icon = 'icons/obj/toy.dmi'
- icon_state = "foamblade"
- item_state = "arm_blade"
- attack_verb = list("pricked", "absorbed", "gored")
- w_class = WEIGHT_CLASS_SMALL
- resistance_flags = FLAMMABLE
+/obj/item/toy/foamblade
+ name = "foam armblade"
+ desc = "it says \"Sternside Changs #1 fan\" on it. "
+ icon = 'icons/obj/toy.dmi'
+ icon_state = "foamblade"
+ item_state = "arm_blade"
+ attack_verb = list("pricked", "absorbed", "gored")
+ w_class = WEIGHT_CLASS_SMALL
+ resistance_flags = FLAMMABLE
/*
* Toy/fake flash
diff --git a/code/game/objects/items/weapons/grenades/clowngrenade.dm b/code/game/objects/items/weapons/grenades/clowngrenade.dm
index cfb2e1cad3d..1dcf250dfe4 100644
--- a/code/game/objects/items/weapons/grenades/clowngrenade.dm
+++ b/code/game/objects/items/weapons/grenades/clowngrenade.dm
@@ -13,22 +13,12 @@
/obj/item/grenade/clown_grenade/prime()
..()
playsound(src.loc, 'sound/items/bikehorn.ogg', 25, -3)
- /*
- for(var/turf/simulated/floor/T in view(affected_area, src.loc))
- if(prob(75))
- banana(T)
- */
var/i = 0
var/number = 0
for(var/direction in GLOB.alldirs)
for(i = 0; i < 2; i++)
number++
var/obj/item/grown/bananapeel/traitorpeel/peel = new /obj/item/grown/bananapeel/traitorpeel(get_turf(src.loc))
- /* var/direction = pick(alldirs)
- var/spaces = pick(1;150, 2)
- var/a = 0
- for(a = 0; a < spaces; a++)
- step(peel,direction)*/
var/a = 1
if(number & 2)
for(a = 1; a <= 2; a++)
@@ -39,21 +29,17 @@
qdel(src)
return
-/obj/item/grown/bananapeel/traitorpeel
- trip_stun = 0
- trip_weaken = 7
- trip_tiles = 4
- trip_walksafe = FALSE
-
- trip_chance = 100
-
-
-/obj/item/grown/bananapeel/traitorpeel/on_trip(mob/living/carbon/human/H)
+/obj/item/grown/bananapeel/traitorpeel/New(newloc, obj/item/seeds/new_seed)
. = ..()
- if(.)
- to_chat(H, "Your feet feel like they're on fire!")
- H.take_overall_damage(0, rand(2,8))
- H.take_organ_damage(2) // Was 5 -- TLE
+ // The reason this AddComponent is here and not in ComponentInitialize() is because if it's put there, it will be ran before the parent New proc for /grown types.
+ // And then be overriden by the generic component placed onto it by the `/datum/plant_gene/trait/slip`.
+ AddComponent(/datum/component/slippery, src, 0, 7, 100, 4, FALSE)
+
+/obj/item/grown/bananapeel/traitorpeel/after_slip(mob/living/carbon/human/H)
+ to_chat(H, "Your feet feel like they're on fire!")
+ H.take_overall_damage(0, rand(2,8))
+ H.take_organ_damage(2)
+ return ..()
/obj/item/grown/bananapeel/traitorpeel/throw_impact(atom/hit_atom)
var/burned = rand(1,3)
diff --git a/code/game/objects/items/weapons/soap.dm b/code/game/objects/items/weapons/soap.dm
index 62f65b5a6cc..cb220ff9565 100644
--- a/code/game/objects/items/weapons/soap.dm
+++ b/code/game/objects/items/weapons/soap.dm
@@ -11,15 +11,11 @@
throw_speed = 4
throw_range = 20
discrete = 1
-
- trip_stun = 4
- trip_weaken = 2
- trip_chance = 100
- trip_walksafe = FALSE
- trip_verb = TV_SLIP
-
var/cleanspeed = 50 //slower than mop
+/obj/item/soap/ComponentInitialize()
+ AddComponent(/datum/component/slippery, src, 4, 2, 100, 0, FALSE)
+
/obj/item/soap/afterattack(atom/target, mob/user, proximity)
if(!proximity) return
//I couldn't feasibly fix the overlay bugs caused by cleaning items we are wearing.
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm
index df7e1384ed9..7eab5858772 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm
@@ -55,7 +55,7 @@
new /obj/item/radio/headset( src )
/obj/structure/closet/secure_closet/personal/attackby(obj/item/W, mob/user, params)
- if(!istype(W, /obj/item/card/id))
+ if(opened || !istype(W, /obj/item/card/id))
return ..()
if(broken)
diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm
index 854bc18ce00..692d15d79ec 100644
--- a/code/game/objects/structures/tank_dispenser.dm
+++ b/code/game/objects/structures/tank_dispenser.dm
@@ -1,3 +1,5 @@
+#define MAX_TANK_STORAGE 10
+
/obj/structure/dispenser
name = "tank storage unit"
desc = "A simple yet bulky storage device for gas tanks. Has room for up to ten oxygen tanks, and ten plasma tanks."
@@ -5,29 +7,51 @@
icon_state = "dispenser"
density = 1
anchored = 1.0
- var/oxygentanks = 10
- var/plasmatanks = 10
- var/list/oxytanks = list() //sorry for the similar var names
- var/list/platanks = list()
+ var/starting_oxygen_tanks = MAX_TANK_STORAGE // The starting amount of oxygen tanks the dispenser gets when it's spawned
+ var/starting_plasma_tanks = MAX_TANK_STORAGE // Starting amount of plasma tanks
+ var/list/stored_oxygen_tanks = list() // List of currently stored oxygen tanks
+ var/list/stored_plasma_tanks = list() // And plasma tanks
/obj/structure/dispenser/oxygen
- plasmatanks = 0
+ starting_plasma_tanks = 0
/obj/structure/dispenser/plasma
- oxygentanks = 0
+ starting_oxygen_tanks = 0
/obj/structure/dispenser/New()
..()
+ initialize_tanks()
update_icon()
+/obj/structure/dispenser/Destroy()
+ QDEL_LIST(stored_plasma_tanks)
+ QDEL_LIST(stored_oxygen_tanks)
+ return ..()
+
+/obj/structure/dispenser/proc/initialize_tanks()
+ for(var/I in 1 to starting_plasma_tanks)
+ var/obj/item/tank/plasma/P = new(src)
+ stored_plasma_tanks.Add(P)
+
+ for(var/I in 1 to starting_oxygen_tanks)
+ var/obj/item/tank/oxygen/O = new(src)
+ stored_oxygen_tanks.Add(O)
+
/obj/structure/dispenser/update_icon()
- overlays.Cut()
- switch(oxygentanks)
- if(1 to 3) overlays += "oxygen-[oxygentanks]"
- if(4 to INFINITY) overlays += "oxygen-4"
- switch(plasmatanks)
- if(1 to 4) overlays += "plasma-[plasmatanks]"
- if(5 to INFINITY) overlays += "plasma-5"
+ cut_overlays()
+ var/oxy_tank_amount = LAZYLEN(stored_oxygen_tanks)
+ switch(oxy_tank_amount)
+ if(1 to 3)
+ overlays += "oxygen-[oxy_tank_amount]"
+ if(4 to INFINITY)
+ overlays += "oxygen-4"
+
+ var/pla_tank_amount = LAZYLEN(stored_plasma_tanks)
+ switch(pla_tank_amount)
+ if(1 to 4)
+ overlays += "plasma-[pla_tank_amount]"
+ if(5 to INFINITY)
+ overlays += "plasma-5"
/obj/structure/dispenser/attack_hand(mob/user)
if(..())
@@ -38,7 +62,7 @@
/obj/structure/dispenser/attack_ghost(mob/user)
ui_interact(user)
-/obj/structure/dispenser/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state)
+/obj/structure/dispenser/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, master_ui = null, datum/topic_state/state = GLOB.default_state)
user.set_machine(src)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
@@ -47,35 +71,19 @@
/obj/structure/dispenser/ui_data(user)
var/list/data = list()
- data["o_tanks"] = oxygentanks
- data["p_tanks"] = plasmatanks
+ data["o_tanks"] = LAZYLEN(stored_oxygen_tanks)
+ data["p_tanks"] = LAZYLEN(stored_plasma_tanks)
return data
/obj/structure/dispenser/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/tank/oxygen) || istype(I, /obj/item/tank/air) || istype(I, /obj/item/tank/anesthetic))
- if(oxygentanks < 10)
- user.drop_item()
- I.forceMove(src)
- oxytanks.Add(I)
- oxygentanks++
- update_icon()
- to_chat(user, "You put [I] in [src].")
- else
- to_chat(user, "[src] is full.")
- SSnanoui.update_uis(src)
+ try_insert_tank(user, stored_oxygen_tanks, I)
return
+
if(istype(I, /obj/item/tank/plasma))
- if(plasmatanks < 10)
- user.drop_item()
- I.forceMove(src)
- platanks.Add(I)
- plasmatanks++
- update_icon()
- to_chat(user, "You put [I] in [src].")
- else
- to_chat(user, "[src] is full.")
- SSnanoui.update_uis(src)
+ try_insert_tank(user, stored_plasma_tanks, I)
return
+
if(istype(I, /obj/item/wrench))
if(anchored)
to_chat(user, "You lean down and unwrench [src].")
@@ -88,40 +96,55 @@
/obj/structure/dispenser/Topic(href, href_list)
if(..())
- return 1
+ return TRUE
if(Adjacent(usr))
usr.set_machine(src)
+
+ // The oxygen tank button
if(href_list["oxygen"])
- if(oxygentanks > 0)
- var/obj/item/tank/oxygen/O
- if(oxytanks.len == oxygentanks)
- O = oxytanks[1]
- oxytanks.Remove(O)
- else
- O = new /obj/item/tank/oxygen(loc)
- O.loc = loc
- to_chat(usr, "You take [O] out of [src].")
- oxygentanks--
- update_icon()
+ try_remove_tank(usr, stored_oxygen_tanks)
+
+ // The plasma tank button
if(href_list["plasma"])
- if(plasmatanks > 0)
- var/obj/item/tank/plasma/P
- if(platanks.len == plasmatanks)
- P = platanks[1]
- platanks.Remove(P)
- else
- P = new /obj/item/tank/plasma(loc)
- P.loc = loc
- to_chat(usr, "You take [P] out of [src].")
- plasmatanks--
- update_icon()
+ try_remove_tank(usr, stored_plasma_tanks)
+
add_fingerprint(usr)
updateUsrDialog()
- SSnanoui.update_uis(src)
+ SSnanoui.try_update_ui(usr, src)
else
SSnanoui.close_user_uis(usr,src)
- return 1
+ return TRUE
+
+/// Called when the user clicks on the oxygen or plasma tank UI buttons, and tries to withdraw a tank.
+/obj/structure/dispenser/proc/try_remove_tank(mob/living/user, list/tank_list)
+ if(!LAZYLEN(tank_list))
+ return // There are no tanks left to withdraw.
+
+ var/obj/item/tank/T = tank_list[1]
+ tank_list.Remove(T)
+
+ if(!user.put_in_hands(T))
+ T.forceMove(loc) // If the user's hands are full, place it on the tile of the dispenser.
+
+ to_chat(user, "You take [T] out of [src].")
+ update_icon()
+
+/// Called when the user clicks on the dispenser with a tank. Tries to insert the tank into the dispenser, and updates the UI if successful.
+/obj/structure/dispenser/proc/try_insert_tank(mob/living/user, list/tank_list, obj/item/tank/T)
+ if(LAZYLEN(tank_list) >= MAX_TANK_STORAGE)
+ to_chat(user, "[src] is full.")
+ return
+
+ if(!user.drop_item()) // Antidrop check
+ to_chat(user, "[T] is stuck to your hand!")
+ return
+
+ T.forceMove(src)
+ tank_list.Add(T)
+ update_icon()
+ to_chat(user, "You put [T] in [src].")
+ SSnanoui.try_update_ui(user, src)
/obj/structure/tank_dispenser/deconstruct(disassembled = TRUE)
if(!(flags & NODECONSTRUCT))
@@ -130,3 +153,5 @@
I.forceMove(loc)
new /obj/item/stack/sheet/metal(loc, 2)
qdel(src)
+
+#undef MAX_TANK_STORAGE
diff --git a/code/modules/admin/verbs/modifyvariables.dm b/code/modules/admin/verbs/modifyvariables.dm
index 0474629dea0..079446b0994 100644
--- a/code/modules/admin/verbs/modifyvariables.dm
+++ b/code/modules/admin/verbs/modifyvariables.dm
@@ -627,6 +627,7 @@ GLOBAL_LIST_INIT(VVpixelmovement, list("step_x", "step_y", "step_size", "bound_h
if(!O.vv_edit_var(variable, var_new))
to_chat(src, "Your edit was rejected by the object.")
return
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_VAR_EDIT, args)
log_world("### VarEdit by [src]: [O.type] [variable]=[html_encode("[var_new]")]")
log_admin("[key_name(src)] modified [original_name]'s [variable] to [var_new]")
var/msg = "[key_name_admin(src)] modified [original_name]'s [variable] to [var_new]"
diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm
index 569ecd3e3ff..7b3133c0103 100644
--- a/code/modules/client/preference/preferences.dm
+++ b/code/modules/client/preference/preferences.dm
@@ -624,6 +624,9 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
if(job.admin_only)
continue
+ if(job.hidden_from_job_prefs)
+ continue
+
index += 1
if((index >= limit) || (job.title in splitJobs))
if((index < limit) && (lastJob != null))
diff --git a/code/modules/clothing/shoes/magboots.dm b/code/modules/clothing/shoes/magboots.dm
index 916cb8e89d4..129b07af36e 100644
--- a/code/modules/clothing/shoes/magboots.dm
+++ b/code/modules/clothing/shoes/magboots.dm
@@ -73,16 +73,15 @@ obj/item/clothing/shoes/magboots/syndie/advance //For the Syndicate Strike Team
shoe_sound = "clownstep"
origin_tech = "magnets=4;syndicate=2"
var/enabled_waddle = TRUE
- var/datum/component/waddle
/obj/item/clothing/shoes/magboots/clown/equipped(mob/user, slot)
. = ..()
if(slot == slot_shoes && enabled_waddle)
- waddle = user.AddComponent(/datum/component/waddling)
+ user.AddElement(/datum/element/waddling)
/obj/item/clothing/shoes/magboots/clown/dropped(mob/user)
. = ..()
- QDEL_NULL(waddle)
+ user.RemoveElement(/datum/element/waddling)
/obj/item/clothing/shoes/magboots/clown/CtrlClick(mob/living/user)
if(!isliving(user))
diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm
index 6858355f876..962cfed80c5 100644
--- a/code/modules/clothing/shoes/miscellaneous.dm
+++ b/code/modules/clothing/shoes/miscellaneous.dm
@@ -71,16 +71,15 @@
var/footstep = 1 //used for squeeks whilst walking
shoe_sound = "clownstep"
var/enabled_waddle = TRUE
- var/datum/component/waddle
/obj/item/clothing/shoes/clown_shoes/equipped(mob/user, slot)
. = ..()
if(slot == slot_shoes && enabled_waddle)
- waddle = user.AddComponent(/datum/component/waddling)
+ user.AddElement(/datum/element/waddling)
/obj/item/clothing/shoes/clown_shoes/dropped(mob/user)
. = ..()
- QDEL_NULL(waddle)
+ user.RemoveElement(/datum/element/waddling)
/obj/item/clothing/shoes/clown_shoes/CtrlClick(mob/living/user)
if(!isliving(user))
diff --git a/code/modules/food_and_drinks/food/foods/bread.dm b/code/modules/food_and_drinks/food/foods/bread.dm
index d888a532c01..55255658233 100644
--- a/code/modules/food_and_drinks/food/foods/bread.dm
+++ b/code/modules/food_and_drinks/food/foods/bread.dm
@@ -166,6 +166,15 @@
list_reagents = list("nutriment" = 2, "vitamin" = 2)
tastes = list("bread" = 2)
+/obj/item/reagent_containers/food/snacks/toast
+ name = "Toast"
+ desc = "Yeah! Toast!"
+ icon_state = "toast"
+ filling_color = "#B2580E"
+ bitesize = 3
+ list_reagents = list("nutriment" = 3)
+ tastes = list("toast" = 2)
+
/obj/item/reagent_containers/food/snacks/jelliedtoast
name = "Jellied Toast"
desc = "A slice of bread covered with delicious jam."
@@ -198,3 +207,5 @@
trash = /obj/item/trash/waffles
filling_color = "#E6DEB5"
list_reagents = list("nutriment" = 8, "vitamin" = 1)
+
+
diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm
index d86f6f8f4c5..f4a6a18e417 100644
--- a/code/modules/hydroponics/grown.dm
+++ b/code/modules/hydroponics/grown.dm
@@ -160,11 +160,11 @@
T.on_cross(src, AM)
..()
-/obj/item/reagent_containers/food/snacks/grown/on_trip(mob/living/carbon/human/H)
- . = ..()
- if(. && seed)
- for(var/datum/plant_gene/trait/T in seed.genes)
- T.on_slip(src, H)
+/obj/item/reagent_containers/food/snacks/grown/after_slip(mob/living/carbon/human/H)
+ if(!seed)
+ return
+ for(var/datum/plant_gene/trait/T in seed.genes)
+ T.on_slip(src, H)
// Glow gene procs
/obj/item/reagent_containers/food/snacks/grown/generate_trash(atom/location)
diff --git a/code/modules/hydroponics/grown/banana.dm b/code/modules/hydroponics/grown/banana.dm
index dc78ff71335..0552f78ee92 100644
--- a/code/modules/hydroponics/grown/banana.dm
+++ b/code/modules/hydroponics/grown/banana.dm
@@ -118,12 +118,10 @@
/obj/item/grown/bananapeel/specialpeel //used by /obj/item/clothing/shoes/clown_shoes/banana_shoes
name = "synthesized banana peel"
desc = "A synthetic banana peel."
- trip_stun = 2
- trip_weaken = 2
- trip_chance = 100
- trip_walksafe = FALSE
- trip_verb = TV_SLIP
-/obj/item/grown/bananapeel/specialpeel/on_trip(mob/living/carbon/human/H)
- if(..())
- qdel(src)
+/obj/item/grown/bananapeel/specialpeel/ComponentInitialize()
+ AddComponent(/datum/component/slippery, src, 2, 2, 100, 0, FALSE)
+
+/obj/item/grown/bananapeel/specialpeel/after_slip(mob/living/carbon/human/H)
+ . = ..()
+ qdel(src)
diff --git a/code/modules/hydroponics/growninedible.dm b/code/modules/hydroponics/growninedible.dm
index 14a4b42ca5f..13263b4cc75 100644
--- a/code/modules/hydroponics/growninedible.dm
+++ b/code/modules/hydroponics/growninedible.dm
@@ -57,11 +57,11 @@
T.on_cross(src, AM)
..()
-/obj/item/grown/on_trip(mob/living/carbon/human/H)
- . = ..()
- if(. && seed)
- for(var/datum/plant_gene/trait/T in seed.genes)
- T.on_slip(src, H)
+/obj/item/grown/after_slip(mob/living/carbon/human/H)
+ if(!seed)
+ return
+ for(var/datum/plant_gene/trait/T in seed.genes)
+ T.on_slip(src, H)
/obj/item/grown/throw_impact(atom/hit_atom)
if(!..()) //was it caught by a mob?
diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm
index d20413d6331..19209a680ad 100644
--- a/code/modules/hydroponics/plant_genes.dm
+++ b/code/modules/hydroponics/plant_genes.dm
@@ -217,11 +217,7 @@
stun_len = min(stun_len, 7) // No fun allowed
- G.trip_stun = stun_len
- G.trip_weaken = stun_len
- G.trip_chance = 100
- G.trip_verb = TV_SLIP
- G.trip_walksafe = FALSE
+ G.AddComponent(/datum/component/slippery, G, stun_len, stun_len, 100, 0, FALSE)
/datum/plant_gene/trait/cell_charge
// Cell recharging trait. Charges all mob's power cells to (potency*rate)% mark when eaten.
diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm
index f21978db625..4af48e7050a 100644
--- a/code/modules/mining/equipment/kinetic_crusher.dm
+++ b/code/modules/mining/equipment/kinetic_crusher.dm
@@ -65,6 +65,8 @@
user.drop_l_hand()
return
var/datum/status_effect/crusher_damage/C = target.has_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
+ if(!C)
+ C = target.apply_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
var/target_health = target.health
..()
for(var/t in trophies)
@@ -101,6 +103,8 @@
if(!CM || CM.hammer_synced != src || !L.remove_status_effect(STATUS_EFFECT_CRUSHERMARK))
return
var/datum/status_effect/crusher_damage/C = L.has_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
+ if(!C)
+ C = L.apply_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
var/target_health = L.health
for(var/t in trophies)
var/obj/item/crusher_trophy/T = t
diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm
index 50cb7d09801..579df861c19 100644
--- a/code/modules/mining/machine_processing.dm
+++ b/code/modules/mining/machine_processing.dm
@@ -98,7 +98,7 @@
/obj/machinery/mineral/processing_unit/Destroy()
CONSOLE = null
QDEL_NULL(files)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.retrieve_all()
return ..()
@@ -120,7 +120,7 @@
CONSOLE.updateUsrDialog()
/obj/machinery/mineral/processing_unit/proc/process_ore(obj/item/stack/ore/O)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/material_amount = materials.get_item_material_amount(O)
if(!materials.has_space(material_amount))
unload_mineral(O)
@@ -132,7 +132,7 @@
/obj/machinery/mineral/processing_unit/proc/get_machine_data()
var/dat = "Smelter control console