diff --git a/code/__DEFINES/assert.dm b/code/__DEFINES/assert.dm
new file mode 100644
index 0000000000..cff7810771
--- /dev/null
+++ b/code/__DEFINES/assert.dm
@@ -0,0 +1,13 @@
+#undef ASSERT
+
+/// Override BYOND's native ASSERT to optionally specify a message
+#define ASSERT(condition, message...) \
+ if (!(condition)) { \
+ CRASH(assertion_message(__FILE__, __LINE__, #condition, ##message)) \
+ }
+
+/proc/assertion_message(file, line, condition, message)
+ if (!isnull(message))
+ message = " - [message]"
+
+ return "[file]:[line]:Assertion failed: [condition][message]"
diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm
index 3abd79708f..de7eb672e8 100644
--- a/code/__DEFINES/atmospherics.dm
+++ b/code/__DEFINES/atmospherics.dm
@@ -23,6 +23,8 @@
#define T0C 273.15 // 0degC
#define T20C 293.15 // 20degC
+#define T90C 363.15 // 90degC
+#define T120C 393.15 // 120degC
#define TCMB 2.7 // -270.3degC
#define ICE_COLONY_TEMPERATURE 223 //-50degC
#define SOROKYNE_TEMPERATURE 223 // Same as Ice for now
diff --git a/code/__DEFINES/conflict.dm b/code/__DEFINES/conflict.dm
index 0820c709cd..d69f0891ff 100644
--- a/code/__DEFINES/conflict.dm
+++ b/code/__DEFINES/conflict.dm
@@ -109,6 +109,7 @@
#define SHOES_SLOWDOWN -1
#define SLOWDOWN_ARMOR_NONE 0
+#define SLOWDOWN_ARMOR_SUPER_LIGHT 0.10
#define SLOWDOWN_ARMOR_VERY_LIGHT 0.20
#define SLOWDOWN_ARMOR_LIGHT 0.35
#define SLOWDOWN_ARMOR_MEDIUM 0.55
diff --git a/code/__DEFINES/dcs/signals/atom/mob/living/signals_xeno.dm b/code/__DEFINES/dcs/signals/atom/mob/living/signals_xeno.dm
index f66c264fde..0027e6700b 100644
--- a/code/__DEFINES/dcs/signals/atom/mob/living/signals_xeno.dm
+++ b/code/__DEFINES/dcs/signals/atom/mob/living/signals_xeno.dm
@@ -42,6 +42,8 @@
#define COMSIG_XENO_STOP_MOMENTUM "xeno_stop_momentum"
/// Called whenever xeno should resume charge
#define COMSIG_XENO_START_CHARGING "xeno_start_charging"
+/// From /datum/action/xeno_action/onclick/charger_charge/proc/stop_momentum()
+#define COMSIG_XENO_STOPPED_CHARGING "xeno_stopped_charging"
// Used in resin_constructions.dm
// Checks whether the xeno can build a thick structure regardless of hive weeds
diff --git a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm
index b9e89bf441..529b2e9314 100644
--- a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm
+++ b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm
@@ -1,3 +1,5 @@
+///from base of mob/set_stat(): (new_stat, old_stat)
+#define COMSIG_MOB_STATCHANGE "mob_statchange"
/// From /obj/structure/machinery/door/airlock/proc/take_damage
#define COMSIG_MOB_DESTROY_AIRLOCK "mob_destroy_airlock"
@@ -132,3 +134,6 @@
/// From /mob/proc/say_dead(message)
#define COMSIG_DEAD_SPEAK "comsig_dead_speak"
#define COMPONENT_OVERRIDE_DEAD_SPEAK (1<<0)
+
+/// Cancels all running cloaking effects on target
+#define COMSIG_MOB_EFFECT_CLOAK_CANCEL "mob_effect_cloak_cancel"
diff --git a/code/__DEFINES/dcs/signals/atom/signals_atom.dm b/code/__DEFINES/dcs/signals/atom/signals_atom.dm
index 17915824a0..394e63bd6e 100644
--- a/code/__DEFINES/dcs/signals/atom/signals_atom.dm
+++ b/code/__DEFINES/dcs/signals/atom/signals_atom.dm
@@ -71,3 +71,6 @@
/// Called when an atom is mouse dropped on another atom, from /client/MouseDrop: (atom/dropped_onto)
#define COMSIG_ATOM_DROP_ON "atom_drop_on"
+
+/// Called when an atom has emp_act called on it, from /atom/emp_act: (severity)
+#define COMSIG_ATOM_EMP_ACT "atom_emp_act"
diff --git a/code/__DEFINES/dcs/signals/atom/signals_cell.dm b/code/__DEFINES/dcs/signals/atom/signals_cell.dm
new file mode 100644
index 0000000000..75e13d8bfd
--- /dev/null
+++ b/code/__DEFINES/dcs/signals/atom/signals_cell.dm
@@ -0,0 +1,26 @@
+/// (charge_amount)
+#define COMSIG_CELL_USE_CHARGE "cell_use_charge"
+ #define COMPONENT_CELL_NO_USE_CHARGE (1<<0)
+
+/// (charge_amount)
+#define COMSIG_CELL_ADD_CHARGE "cell_add_charge"
+
+#define COMSIG_CELL_START_TICK_DRAIN "cell_start_tick_drain"
+
+#define COMSIG_CELL_STOP_TICK_DRAIN "cell_stop_tick_drain"
+
+/// (mob/living/user)
+#define COMSIG_CELL_TRY_RECHARGING "cell_try_recharging"
+ #define COMPONENT_CELL_NO_RECHARGE (1<<0)
+
+#define COMSIG_CELL_OUT_OF_CHARGE "cell_out_of_charge"
+
+/// (charge_amount)
+#define COMSIG_CELL_CHECK_CHARGE "cell_check_charge"
+ #define COMPONENT_CELL_CHARGE_INSUFFICIENT (1<<0)
+
+#define COMSIG_CELL_TRY_INSERT_CELL "cell_try_insert_cell"
+ #define COMPONENT_CANCEL_CELL_INSERT (1<<0)
+
+/// (mob/living/user)
+#define COMSIG_CELL_REMOVE_CELL "cell_remove_cell"
diff --git a/code/__DEFINES/dcs/signals/atom/signals_obj.dm b/code/__DEFINES/dcs/signals/atom/signals_obj.dm
index 7e4436b3cf..90aa4bd984 100644
--- a/code/__DEFINES/dcs/signals/atom/signals_obj.dm
+++ b/code/__DEFINES/dcs/signals/atom/signals_obj.dm
@@ -26,3 +26,5 @@
/// from /obj/proc/afterbuckle()
#define COSMIG_OBJ_AFTER_BUCKLE "signal_obj_after_buckle"
+
+#define COMSIG_STRUCTURE_CRATE_SQUAD_LAUNCHED "structure_crate_squad_launched"
diff --git a/code/__DEFINES/dcs/signals/signals_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm
index 032a1891a8..c452176f91 100644
--- a/code/__DEFINES/dcs/signals/signals_global.dm
+++ b/code/__DEFINES/dcs/signals/signals_global.dm
@@ -60,8 +60,14 @@
#define COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING "!groundside_forsaken_handling"
/// From
-#define COMSIG_GLOB_YAUTJA_ARMORY_OPENED "yautja_armory_opened"
+#define COMSIG_GLOB_YAUTJA_ARMORY_OPENED "!yautja_armory_opened"
/// From /proc/biohazard_lockdown()
-#define COMSIG_GLOB_RESEARCH_LOCKDOWN "research_lockdown_closed"
-#define COMSIG_GLOB_RESEARCH_LIFT "research_lockdown_opened"
+#define COMSIG_GLOB_RESEARCH_LOCKDOWN "!research_lockdown_closed"
+#define COMSIG_GLOB_RESEARCH_LIFT "!research_lockdown_opened"
+
+/// From /obj/structure/machinery/power/fusion_engine/proc/set_overloading() : (set_overloading)
+#define COMSIG_GLOB_GENERATOR_SET_OVERLOADING "!generator_set_overloading"
+
+/// From /client/proc/rename_platoon()
+#define COMSIG_GLOB_PLATOON_NAME_CHANGE "platoon_name_change"
diff --git a/code/__DEFINES/equipment.dm b/code/__DEFINES/equipment.dm
index 96c0fc3738..77638ed568 100644
--- a/code/__DEFINES/equipment.dm
+++ b/code/__DEFINES/equipment.dm
@@ -80,10 +80,8 @@
#define CAN_DIG_SHRAPNEL (1<<11)
/// whether it has an animated icon state of "[icon_state]_on" to be used during surgeries.
#define ANIMATED_SURGICAL_TOOL (1<<12)
-/// The item goes on top of tables, instead of into them with the overlay system
-#define NOTABLEMERGE (1<<13)
/// Has heat source but isn't 'on fire' and thus can be stored
-#define IGNITING_ITEM (1<<14)
+#define IGNITING_ITEM (1<<13)
//==========================================================================================
diff --git a/code/__DEFINES/hijack.dm b/code/__DEFINES/hijack.dm
new file mode 100644
index 0000000000..85d4c227ae
--- /dev/null
+++ b/code/__DEFINES/hijack.dm
@@ -0,0 +1,13 @@
+#define EVACUATION_TYPE_NONE 0
+#define EVACUATION_TYPE_ADDITIVE 1
+#define EVACUATION_TYPE_MULTIPLICATIVE 2
+
+#define HIJACK_ANNOUNCE "ARES Emergency Procedures"
+#define XENO_HIJACK_ANNOUNCE "You sense something unusual..."
+
+#define EVACUATION_STATUS_NOT_INITIATED 0
+#define EVACUATION_STATUS_INITIATED 1
+
+#define HIJACK_OBJECTIVES_NOT_STARTED 0
+#define HIJACK_OBJECTIVES_STARTED 1
+#define HIJACK_OBJECTIVES_COMPLETE 2
diff --git a/code/__DEFINES/human.dm b/code/__DEFINES/human.dm
index ebf08f4957..4eab3d8592 100644
--- a/code/__DEFINES/human.dm
+++ b/code/__DEFINES/human.dm
@@ -11,9 +11,8 @@
/// this is added to human skin tone to get value of pale_max variable
#define HUMAN_MAX_PALENESS 30
-/// takes 40ds = 4s to strip someone.
-#define HUMAN_STRIP_DELAY 40
-#define POCKET_STRIP_DELAY 20
+#define HUMAN_STRIP_DELAY 5
+#define POCKET_STRIP_DELAY 5
///////////////////LIMB FLAGS///////////////////
diff --git a/code/__DEFINES/job.dm b/code/__DEFINES/job.dm
index 949f9385e8..e51c6f08ad 100644
--- a/code/__DEFINES/job.dm
+++ b/code/__DEFINES/job.dm
@@ -11,6 +11,7 @@
#define SQUAD_MARINE_CRYO "Foxtrot"
#define SQUAD_MARINE_INTEL "Intel"
#define SQUAD_SOF "SOF"
+#define SQUAD_CBRN "CBRN"
// Job name defines
#define JOB_SQUAD_MARINE "Rifleman"
diff --git a/code/__DEFINES/keybinding.dm b/code/__DEFINES/keybinding.dm
index 88f194bb33..764282d597 100644
--- a/code/__DEFINES/keybinding.dm
+++ b/code/__DEFINES/keybinding.dm
@@ -14,6 +14,7 @@
#define COMSIG_KB_ADMIN_INVISIMINTOGGLE_DOWN "keybinding_admin_invisimintoggle_down"
#define COMSIG_KB_ADMIN_DEADMIN_DOWN "keybinding_admin_deadmin_down"
#define COMSIG_KB_ADMIN_READMIN_DOWN "keybinding_admin_readmin_down"
+#define COMSIG_KB_ADMIN_MENTORSAY_DOWN "keybinding_admin_mentorsay_down"
//Carbon
#define COMSIG_KB_CARBON_HOLDRUNMOVEINTENT_DOWN "keybinding_carbon_holdrunmoveintent_down"
@@ -87,6 +88,7 @@
#define COMSIG_KB_HUMAN_WEAPON_UNLOAD "keybinding_human_weapon_unload"
#define COMSIG_KB_HUMAN_WEAPON_ATTACHMENT "keybinding_human_weapon_attachment"
#define COMSIG_KB_HUMAN_WEAPON_ATTACHMENT_RAIL "keybinding_human_weapon_attachment_rail"
+#define COMSIG_KB_HUMAN_WEAPON_SHOTGUN_TUBE "keybinding_human_weapon_shotgun_tube"
#define COMSIG_KB_HUMAN_WEAPON_TOGGLE_IFF "keybinding_human_weapon_toggle_iff"
diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index 3a043a753f..23b05a4d7b 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -1,4 +1,4 @@
-#define HEALTH_THRESHOLD_DEAD -400
+#define HEALTH_THRESHOLD_DEAD -200
#define HEALTH_THRESHOLD_CRIT -50
//Some mob defines below
diff --git a/code/__DEFINES/speech_channels.dm b/code/__DEFINES/speech_channels.dm
index 3f6e4720bd..5a9a74af8a 100644
--- a/code/__DEFINES/speech_channels.dm
+++ b/code/__DEFINES/speech_channels.dm
@@ -1,6 +1,7 @@
// Used to direct channels to speak into.
#define SAY_CHANNEL "Say"
#define COMMS_CHANNEL "Comms"
+#define WHISPER_CHANNEL "Whisper"
#define ME_CHANNEL "Me"
#define OOC_CHANNEL "OOC"
#define LOOC_CHANNEL "LOOC"
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index 0755faf975..edfee05953 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -109,36 +109,23 @@
// Subsystems shutdown in the reverse of the order they initialize in
// The numbers just define the ordering, they are meaningless otherwise.
-#define SS_INIT_TICKER_SPAWN 999
#define SS_INIT_INPUT 85
-#define SS_INIT_FAIL_TO_TOPIC 84
#define SS_INIT_TOPIC 83
#define SS_INIT_LOBBYART 82
-#define SS_INIT_RUST 30
#define SS_INIT_INFLUXDRIVER 28
-#define SS_INIT_SUPPLY_SHUTTLE 25
#define SS_INIT_GARBAGE 24
#define SS_INIT_EVENTS 23.5
-#define SS_INIT_JOB 23
+#define SS_INIT_HIJACK 22.6
#define SS_INIT_REDIS 22.5
#define SS_INIT_REAGENTS 22.1
#define SS_INIT_MAPPING 22
#define SS_INIT_NIGHTMARE 21.5
#define SS_INIT_TIMETRACK 21.1
#define SS_INIT_HUMANS 21
-#define SS_INIT_MAP 20
-#define SS_INIT_COMPONENT 19.5
#define SS_INIT_POWER 19
-#define SS_INIT_OBJECT 18
-#define SS_INIT_PIPENET 17.5
-#define SS_INIT_XENOARCH 17
-#define SS_INIT_MORE_INIT 16
-#define SS_INIT_AIR 15
-#define SS_INIT_TELEPORTER 13
#define SS_INIT_INFLUXMCSTATS 12
#define SS_INIT_INFLUXSTATS 11
#define SS_INIT_LIGHTING 10
-#define SS_INIT_DEFCON 9
#define SS_INIT_LAW 6
#define SS_INIT_FZ_TRANSITIONS 5
#define SS_INIT_PROJECTILES 4.1
@@ -152,12 +139,9 @@
#define SS_INIT_RADIO 2
#define SS_INIT_TIMER 100
#define SS_INIT_UNSPECIFIED 0
-#define SS_INIT_EMERGENCY_SHUTTLE -19
#define SS_INIT_ASSETS -20
#define SS_INIT_TICKER -21
#define SS_INIT_VOTE -23
-#define SS_INIT_FINISH -24
-#define SS_INIT_ADMIN -26
#define SS_INIT_DATABASE -27
#define SS_INIT_ENTITYMANAGER -28
#define SS_INIT_PLAYTIME -29
@@ -177,7 +161,6 @@
#define SS_PRIORITY_TICKER 200
#define SS_PRIORITY_XENO_AI 185
#define SS_PRIORITY_NIGHTMARE 180
-#define SS_PRIORITY_MAPVIEW 170
#define SS_PRIORITY_QUADTREE 160
#define SS_PRIORITY_CHAT 155
#define SS_PRIORITY_STATPANEL 154
@@ -196,20 +179,17 @@
#define SS_PRIORITY_VOTE 110
#define SS_PRIORITY_FAST_OBJECTS 105
#define SS_PRIORITY_OBJECTS 104
-#define SS_PRIORITY_FACEHUGGERS 100
#define SS_PRIORITY_DECORATOR 99
+#define SS_PRIORITY_HIJACK 97
#define SS_PRIORITY_POWER 95
#define SS_PRIORITY_EFFECTS 92
#define SS_PRIORITY_MACHINERY 90
#define SS_PRIORITY_FZ_TRANSITIONS 88
-#define SS_PRIORITY_PIPENET 85
#define SS_PRIORITY_ROUND_RECORDING 83
#define SS_PRIORITY_SHUTTLE 80
-#define SS_PRIORITY_TELEPORTER 75
#define SS_PRIORITY_EVENT 65
#define SS_PRIORITY_DISEASE 60
-#define SS_PRIORITY_FAST_MACHINERY 55
-#define SS_PRIORITY_MIDI 40
+#define SS_PRIORITY_DEFENSES 55
#define SS_PRIORITY_ENTITY 37
#define SS_PRIORITY_DEFCON 35
#define SS_PRIORITY_ACID_PILLAR 34
@@ -228,7 +208,6 @@
#define SS_PRIORITY_INFLUXSTATS 8
#define SS_PRIORITY_PLAYTIME 5
#define SS_PRIORITY_PERFLOGGING 4
-#define SS_PRIORITY_CORPSESPAWNER 3
#define SS_PRIORITY_GARBAGE 2
#define SS_PRIORITY_INACTIVITY 1
#define SS_PRIORITY_ADMIN 0
diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm
index d468d60441..0cc106ec9c 100644
--- a/code/__DEFINES/tgs.dm
+++ b/code/__DEFINES/tgs.dm
@@ -1,6 +1,6 @@
// tgstation-server DMAPI
-#define TGS_DMAPI_VERSION "6.6.1"
+#define TGS_DMAPI_VERSION "6.6.2"
// All functions and datums outside this document are subject to change with any version and should not be relied on.
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index ef500b6af9..af8af22ca7 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -1,22 +1,20 @@
-//shamelessly ripped from TG
#define SIGNAL_ADDTRAIT(trait_ref) "addtrait [trait_ref]"
#define SIGNAL_REMOVETRAIT(trait_ref) "removetrait [trait_ref]"
// trait accessor defines
-//here be dragons
#define ADD_TRAIT(target, trait, source) \
do { \
var/list/_L; \
- if (!target.status_traits) { \
- target.status_traits = list(); \
- _L = target.status_traits; \
+ if (!target._status_traits) { \
+ target._status_traits = list(); \
+ _L = target._status_traits; \
_L[trait] = list(source); \
SEND_SIGNAL(target, SIGNAL_ADDTRAIT(trait), trait); \
if(trait in GLOB.traits_with_elements){ \
target.AddElement(GLOB.traits_with_elements[trait]); \
} \
} else { \
- _L = target.status_traits; \
+ _L = target._status_traits; \
if (_L[trait]) { \
_L[trait] |= list(source); \
} else { \
@@ -30,16 +28,16 @@
} while (0)
#define REMOVE_TRAIT(target, trait, sources) \
do { \
- var/list/_L = target.status_traits; \
+ var/list/_L = target._status_traits; \
var/list/_S; \
if (sources && !islist(sources)) { \
_S = list(sources); \
} else { \
_S = sources\
}; \
- if (_L && _L[trait]) { \
+ if (_L?[trait]) { \
for (var/_T in _L[trait]) { \
- if ((!_S && (_T != TRAIT_SOURCE_QUIRK)) || (_T in _S)) { \
+ if ((!_S && (_T != ROUNDSTART_TRAIT)) || (_T in _S)) { \
_L[trait] -= _T \
} \
};\
@@ -51,13 +49,40 @@
} \
}; \
if (!length(_L)) { \
- target.status_traits = null \
+ target._status_traits = null \
+ }; \
+ } \
+ } while (0)
+#define REMOVE_TRAIT_NOT_FROM(target, trait, sources) \
+ do { \
+ var/list/_traits_list = target._status_traits; \
+ var/list/_sources_list; \
+ if (sources && !islist(sources)) { \
+ _sources_list = list(sources); \
+ } else { \
+ _sources_list = sources\
+ }; \
+ if (_traits_list?[trait]) { \
+ for (var/_trait_source in _traits_list[trait]) { \
+ if (!(_trait_source in _sources_list)) { \
+ _traits_list[trait] -= _trait_source \
+ } \
+ };\
+ if (!length(_traits_list[trait])) { \
+ _traits_list -= trait; \
+ SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(trait), trait); \
+ if(trait in GLOB.traits_with_elements) { \
+ target.RemoveElement(GLOB.traits_with_elements[trait]); \
+ } \
+ }; \
+ if (!length(_traits_list)) { \
+ target._status_traits = null \
}; \
} \
} while (0)
#define REMOVE_TRAITS_NOT_IN(target, sources) \
do { \
- var/list/_L = target.status_traits; \
+ var/list/_L = target._status_traits; \
var/list/_S = sources; \
if (_L) { \
for (var/_T in _L) { \
@@ -65,20 +90,20 @@
if (!length(_L[_T])) { \
_L -= _T; \
SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(_T), _T); \
- if(_T in GLOB.traits_with_elements) { \
- target.RemoveElement(GLOB.traits_with_elements[_T]); \
+ if(trait in GLOB.traits_with_elements) { \
+ target.RemoveElement(GLOB.traits_with_elements[trait]); \
}; \
};\
};\
if (!length(_L)) { \
- target.status_traits = null\
+ target._status_traits = null\
};\
}\
} while (0)
#define REMOVE_TRAITS_IN(target, sources) \
do { \
- var/list/_L = target.status_traits; \
+ var/list/_L = target._status_traits; \
var/list/_S = sources; \
if (sources && !islist(sources)) { \
_S = list(sources); \
@@ -97,40 +122,32 @@
};\
};\
if (!length(_L)) { \
- target.status_traits = null\
+ target._status_traits = null\
};\
}\
} while (0)
-/// Will 100% nuke a trait regardless of source. Preferably use this as little as possible
-#define REMOVE_TRAIT_ALLSOURCES(target, trait) \
- do { \
- var/list/_L = target.status_traits; \
- if (_L?[trait]) { \
- if (length(_L)) { \
- _L -= trait; \
- SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(trait), trait); \
- }; \
- else { \
- target.status_traits = null \
- }; \
- } \
- } while (0)
-
-#define HAS_TRAIT(target, trait) (target.status_traits ? (target.status_traits[trait] ? TRUE : FALSE) : FALSE)
-#define HAS_TRAIT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (source in target.status_traits[trait]) : FALSE) : FALSE)
-#define HAS_TRAIT_FROM_ONLY(target, trait, source) (\
- target.status_traits ?\
- (target.status_traits[trait] ?\
- ((source in target.status_traits[trait]) && (length(target.status_traits) == 1))\
- : FALSE)\
- : FALSE)
-#define HAS_TRAIT_NOT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (length(target.status_traits[trait] - source) > 0) : FALSE) : FALSE)
-
+#define HAS_TRAIT(target, trait) (target._status_traits?[trait] ? TRUE : FALSE)
+#define HAS_TRAIT_FROM(target, trait, source) (HAS_TRAIT(target, trait) && (source in target._status_traits[trait]))
+#define HAS_TRAIT_FROM_ONLY(target, trait, source) (HAS_TRAIT(target, trait) && (source in target._status_traits[trait]) && (length(target._status_traits[trait]) == 1))
+#define HAS_TRAIT_NOT_FROM(target, trait, source) (HAS_TRAIT(target, trait) && (length(target._status_traits[trait] - source) > 0))
+/// Returns a list of trait sources for this trait. Only useful for wacko cases and internal futzing
+/// You should not be using this
+#define GET_TRAIT_SOURCES(target, trait) (target._status_traits?[trait] || list())
+/// Returns the amount of sources for a trait. useful if you don't want to have a "thing counter" stuck around all the time
+#define COUNT_TRAIT_SOURCES(target, trait) length(GET_TRAIT_SOURCES(target, trait))
+/// A simple helper for checking traits in a mob's mind
+#define HAS_MIND_TRAIT(target, trait) (HAS_TRAIT(target, trait) || (target.mind ? HAS_TRAIT(target.mind, trait) : FALSE))
/// Example trait
// #define TRAIT_X "t_x"
+
//-- mob traits --
+/// Prevents voluntary movement.
+#define TRAIT_IMMOBILIZED "immobilized"
+/// Apply this to make a mob not dense, and remove it when you want it to no longer make them undense, other sorces of undesity will still apply. Always define a unique source when adding a new instance of this!
+#define TRAIT_UNDENSE "undense"
+
// SPECIES TRAITS
/// Knowledge of Yautja technology
#define TRAIT_YAUTJA_TECH "t_yautja_tech"
@@ -279,6 +296,8 @@ GLOBAL_LIST_INIT(mob_traits, list(
*/
GLOBAL_LIST_INIT(traits_by_type, list(
/mob = list(
+ "TRAIT_IMMOBILIZED" = TRAIT_IMMOBILIZED,
+ "TRAIT_UNDENSE" = TRAIT_UNDENSE,
"TRAIT_YAUTJA_TECH" = TRAIT_YAUTJA_TECH,
"TRAIT_SUPER_STRONG" = TRAIT_SUPER_STRONG,
"TRAIT_FOREIGN_BIO" = TRAIT_FOREIGN_BIO,
@@ -354,15 +373,17 @@ GLOBAL_LIST(trait_name_map)
/// Example trait source
// #define TRAIT_SOURCE_Y "t_s_y"
#define TRAIT_SOURCE_INHERENT "t_s_inherent"
+/// cannot be removed without admin intervention
+#define ROUNDSTART_TRAIT "roundstart"
//-- mob traits --
+///Status trait coming from lying down through update_canmove()
+#define LYING_TRAIT "lying"
///Status trait coming from species. .human/species_gain()
#define TRAIT_SOURCE_SPECIES "t_s_species"
///Status trait coming from the hive.
#define TRAIT_SOURCE_HIVE "t_s_hive"
///Status trait coming from being buckled.
#define TRAIT_SOURCE_BUCKLE "t_s_buckle"
-///Status trait coming from roundstart quirks (that don't exist yet). Unremovable by REMOVE_TRAIT
-#define TRAIT_SOURCE_QUIRK "t_s_quirk"
///Status trait coming from being assigned as [acting] squad leader.
#define TRAIT_SOURCE_SQUAD_LEADER "t_s_squad_leader"
///Status trait coming from their job
@@ -379,6 +400,8 @@ GLOBAL_LIST(trait_name_map)
#define TRAIT_SOURCE_ABILITY(ability) "t_s_ability_[ability]"
///Status trait forced by the xeno action charge
#define TRAIT_SOURCE_XENO_ACTION_CHARGE "t_s_xeno_action_charge"
+///Status trait coming from a xeno nest
+#define XENO_NEST_TRAIT "xeno_nest"
//-- structure traits --
///Status trait coming from being flipped or unflipped.
#define TRAIT_SOURCE_FLIP_TABLE "t_s_flip_table"
@@ -390,3 +413,14 @@ GLOBAL_LIST(trait_name_map)
//Status trait coming from clothing.
#define TRAIT_SOURCE_CLOTHING "t_s_clothing"
+
+/// traits associated with actively interacted machinery
+#define INTERACTION_TRAIT "interaction"
+/// trait effect related to active specialist gear
+#define SPECIALIST_GEAR_TRAIT "specialist_gear"
+/// traits associated with usage of snowflake dropship double seats
+#define DOUBLE_SEATS_TRAIT "double_seats"
+/// traits associated with xeno on-ground weeds
+#define XENO_WEED_TRAIT "xeno_weed"
+/// traits from chloroform usage
+#define CHLOROFORM_TRAIT "chloroform"
diff --git a/code/__DEFINES/vehicle.dm b/code/__DEFINES/vehicle.dm
index 9c66850857..8a16172299 100644
--- a/code/__DEFINES/vehicle.dm
+++ b/code/__DEFINES/vehicle.dm
@@ -53,5 +53,6 @@
#define VEHICLE_CLASS_LIGHT (1<<2) //light class armor (APC, tank)
#define VEHICLE_CLASS_MEDIUM (1<<3) //medium class armor (tank)
#define VEHICLE_CLASS_HEAVY (1<<4) //heavy class armor (tank)
-
-#define TANK_POPLOCK 90
+// Other vehicle flags
+/// Vehicle can bypass vehicle blockers, typically going further into maps than intended
+#define VEHICLE_BYPASS_BLOCKERS (1<<5)
diff --git a/code/__DEFINES/xeno.dm b/code/__DEFINES/xeno.dm
index 935f58f69c..c77dac05fc 100644
--- a/code/__DEFINES/xeno.dm
+++ b/code/__DEFINES/xeno.dm
@@ -662,7 +662,6 @@
#define FIRE_IMMUNITY_NO_DAMAGE (1<<0)
#define FIRE_IMMUNITY_NO_IGNITE (1<<1)
#define FIRE_IMMUNITY_XENO_FRENZY (1<<2)
-#define FIRE_VULNERABILITY (1<<3)
#define FIRE_MULTIPLIER_BASE 1
#define FIRE_MULTIPLIER_LOW 1.25
diff --git a/code/__HELPERS/job.dm b/code/__HELPERS/job.dm
index 43902b07cf..89fe687764 100644
--- a/code/__HELPERS/job.dm
+++ b/code/__HELPERS/job.dm
@@ -26,13 +26,6 @@
if(I.assignment in GLOB.joblist) return I.assignment
return "Unknown"
-/proc/FindNameFromID(mob/living/carbon/human/H)
- ASSERT(istype(H))
- var/obj/item/card/id/I = H.wear_id
- if(istype(I)) return I.registered_name
- I = H.get_active_hand()
- if(istype(I)) return I.registered_name
-
/proc/get_all_job_icons() return GLOB.joblist + list("Prisoner")//For all existing HUD icons
/obj/proc/GetJobName() //Used in secHUD icon generation
diff --git a/code/__HELPERS/traits.dm b/code/__HELPERS/traits.dm
new file mode 100644
index 0000000000..ba99b2e1e7
--- /dev/null
+++ b/code/__HELPERS/traits.dm
@@ -0,0 +1,43 @@
+#define TRAIT_CALLBACK_ADD(target, trait, source) CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(___TraitAdd), ##target, ##trait, ##source)
+#define TRAIT_CALLBACK_REMOVE(target, trait, source) CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(___TraitRemove), ##target, ##trait, ##source)
+
+///DO NOT USE ___TraitAdd OR ___TraitRemove as a replacement for ADD_TRAIT / REMOVE_TRAIT defines. To be used explicitly for callback.
+/proc/___TraitAdd(target,trait,source)
+ if(!target || !trait || !source)
+ return
+ if(islist(target))
+ for(var/i in target)
+ if(!isatom(i))
+ continue
+ var/atom/the_atom = i
+ ADD_TRAIT(the_atom,trait,source)
+ else if(isatom(target))
+ var/atom/the_atom2 = target
+ ADD_TRAIT(the_atom2,trait,source)
+
+///DO NOT USE ___TraitAdd OR ___TraitRemove as a replacement for ADD_TRAIT / REMOVE_TRAIT defines. To be used explicitly for callback.
+/proc/___TraitRemove(target,trait,source)
+ if(!target || !trait || !source)
+ return
+ if(islist(target))
+ for(var/i in target)
+ if(!isatom(i))
+ continue
+ var/atom/the_atom = i
+ REMOVE_TRAIT(the_atom,trait,source)
+ else if(isatom(target))
+ var/atom/the_atom2 = target
+ REMOVE_TRAIT(the_atom2,trait,source)
+
+
+/// Proc that handles adding multiple traits to a target via a list. Must have a common source and target.
+/datum/proc/add_traits(list/list_of_traits, source)
+ ASSERT(islist(list_of_traits), "Invalid arguments passed to add_traits! Invoked on [src] with [list_of_traits], source being [source].")
+ for(var/trait in list_of_traits)
+ ADD_TRAIT(src, trait, source)
+
+/// Proc that handles removing multiple traits from a target via a list. Must have a common source and target.
+/datum/proc/remove_traits(list/list_of_traits, source)
+ ASSERT(islist(list_of_traits), "Invalid arguments passed to remove_traits! Invoked on [src] with [list_of_traits], source being [source].")
+ for(var/trait in list_of_traits)
+ REMOVE_TRAIT(src, trait, source)
diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm
index 53dd40ff60..b85aa18fdb 100644
--- a/code/_globalvars/bitfields.dm
+++ b/code/_globalvars/bitfields.dm
@@ -166,7 +166,6 @@ DEFINE_BITFIELD(flags_item, list(
"ITEM_OVERRIDE_NORTHFACE" = ITEM_OVERRIDE_NORTHFACE,
"CAN_DIG_SHRAPNEL" = CAN_DIG_SHRAPNEL,
"ANIMATED_SURGICAL_TOOL" = ANIMATED_SURGICAL_TOOL,
- "NOTABLEMERGE" = NOTABLEMERGE,
"IGNITING_ITEM" = IGNITING_ITEM,
))
@@ -462,3 +461,11 @@ DEFINE_BITFIELD(vend_flags, list(
"VEND_FACTION_THEMES" = VEND_FACTION_THEMES,
"VEND_USE_VENDOR_FLAGS" = VEND_USE_VENDOR_FLAGS,
))
+
+DEFINE_BITFIELD(vehicle_flags, list(
+ "VEHICLE_CLASS_WEAK" = VEHICLE_CLASS_WEAK,
+ "VEHICLE_CLASS_LIGHT" = VEHICLE_CLASS_LIGHT,
+ "VEHICLE_CLASS_MEDIUM" = VEHICLE_CLASS_MEDIUM,
+ "VEHICLE_CLASS_HEAVY" = VEHICLE_CLASS_HEAVY,
+ "VEHICLE_BYPASS_BLOCKERS" = VEHICLE_BYPASS_BLOCKERS,
+))
diff --git a/code/_globalvars/global_lists.dm b/code/_globalvars/global_lists.dm
index 36058a44fc..1e1e9cefd5 100644
--- a/code/_globalvars/global_lists.dm
+++ b/code/_globalvars/global_lists.dm
@@ -1,6 +1,3 @@
-
-var/list/unansweredAhelps = list() //This feels inefficient, but I can't think of a better way. Stores the message indexed by CID
-
GLOBAL_LIST_EMPTY(PressFaxes)
GLOBAL_LIST_EMPTY(WYFaxes) //Departmental faxes
GLOBAL_LIST_EMPTY(USCMFaxes)
diff --git a/code/_globalvars/lists/object_lists.dm b/code/_globalvars/lists/object_lists.dm
index 0bbd63cdcf..7f56f863b6 100644
--- a/code/_globalvars/lists/object_lists.dm
+++ b/code/_globalvars/lists/object_lists.dm
@@ -32,3 +32,6 @@ GLOBAL_LIST_EMPTY_TYPED(all_active_defenses, /obj/structure/machinery/defenses)
GLOBAL_LIST_EMPTY_TYPED(lifeboat_almayer_docks, /obj/docking_port/stationary/lifeboat_dock)
GLOBAL_LIST_EMPTY_TYPED(lifeboat_doors, /obj/structure/machinery/door/airlock/multi_tile/almayer/dropshiprear/lifeboat/blastdoor)
+
+GLOBAL_LIST_EMPTY_TYPED(teleporters, /datum/teleporter)
+GLOBAL_LIST_EMPTY(teleporters_by_id)
diff --git a/code/_onclick/hud/ghost.dm b/code/_onclick/hud/ghost.dm
index a6754747a0..a99129d09b 100644
--- a/code/_onclick/hud/ghost.dm
+++ b/code/_onclick/hud/ghost.dm
@@ -48,6 +48,14 @@
var/mob/dead/observer/G = usr
G.reenter_corpse()
+/atom/movable/screen/ghost/toggle_huds
+ name = "Toggle HUDs"
+ icon_state = "ghost_hud_toggle"
+
+/atom/movable/screen/ghost/toggle_huds/Click()
+ var/client/client = usr.client
+ client.toggle_ghost_hud()
+
/datum/hud/ghost/New(mob/owner, ui_style='icons/mob/hud/human_white.dmi', ui_color, ui_alpha = 230)
. = ..()
var/atom/movable/screen/using
@@ -68,6 +76,9 @@
using.screen_loc = ui_ghost_slot4
static_inventory += using
+ using = new /atom/movable/screen/ghost/toggle_huds()
+ using.screen_loc = ui_ghost_slot5
+ static_inventory += using
/datum/hud/ghost/show_hud(version = 0, mob/viewmob)
// don't show this HUD if observing; show the HUD of the observee
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index b49bce4111..d114aff6b7 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -535,7 +535,7 @@
if(!user.hive.living_xeno_queen)
to_chat(user, SPAN_WARNING("Without a queen your psychic link is broken!"))
return FALSE
- if(user.burrow || user.is_mob_incapacitated() || user.buckled)
+ if(HAS_TRAIT(user, TRAIT_ABILITY_BURROWED) || user.is_mob_incapacitated() || user.buckled)
return FALSE
user.hive.mark_ui.update_all_data()
user.hive.mark_ui.open_mark_menu(user)
@@ -583,7 +583,7 @@
if(!user.hive.living_xeno_queen)
to_chat(user, SPAN_WARNING("Your hive doesn't have a living queen!"))
return FALSE
- if(user.burrow || user.is_mob_incapacitated() || user.buckled)
+ if(HAS_TRAIT(user, TRAIT_ABILITY_BURROWED) || user.is_mob_incapacitated() || user.buckled)
return FALSE
user.overwatch(user.hive.living_xeno_queen)
diff --git a/code/_onclick/human.dm b/code/_onclick/human.dm
index 0bfba04070..1ff0fe6102 100644
--- a/code/_onclick/human.dm
+++ b/code/_onclick/human.dm
@@ -103,7 +103,7 @@
if(xeno.stat != DEAD) // If the Xeno is alive, fight back
var/mob/living/carbon/carbon_user = user
if(!carbon_user || !carbon_user.ally_of_hivenumber(xeno.hivenumber))
- user.KnockDown(rand(xeno.caste.tacklestrength_min, xeno.caste.tacklestrength_max))
+ carbon_user.KnockDown(rand(xeno.caste.tacklestrength_min, xeno.caste.tacklestrength_max))
playsound(user.loc, 'sound/weapons/pierce.ogg', 25, TRUE)
user.visible_message(SPAN_WARNING("\The [user] tried to unstrap \the [back_item] from [xeno] but instead gets a tail swipe to the head!"))
return
diff --git a/code/_onclick/xeno.dm b/code/_onclick/xeno.dm
index 97ed1aa0b5..02b90b5cf4 100644
--- a/code/_onclick/xeno.dm
+++ b/code/_onclick/xeno.dm
@@ -3,7 +3,7 @@
*/
/mob/living/carbon/xenomorph/UnarmedAttack(atom/target, proximity, click_parameters, tile_attack = FALSE, ignores_resin = FALSE)
- if(lying || burrow) //No attacks while laying down
+ if(lying || HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) //No attacks while laying down
return FALSE
var/mob/alt
diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm
index 0066fee5d2..147f57fcb1 100644
--- a/code/controllers/configuration/configuration.dm
+++ b/code/controllers/configuration/configuration.dm
@@ -20,7 +20,6 @@
var/policy
var/static/regex/ic_filter_regex
- var/list/fail_to_topic_whitelisted_ips
var/is_loaded = FALSE
@@ -55,7 +54,6 @@
loadmaplist(CONFIG_GROUND_MAPS_FILE, GROUND_MAP)
loadmaplist(CONFIG_SHIP_MAPS_FILE, SHIP_MAP)
LoadChatFilter()
- LoadTopicRateWhitelist()
is_loaded = TRUE
@@ -337,18 +335,3 @@
/datum/controller/configuration/proc/DelayedMessageAdmins(text)
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(message_admins), text), 0)
-/datum/controller/configuration/proc/LoadTopicRateWhitelist()
- LAZYINITLIST(fail_to_topic_whitelisted_ips)
- if(!fexists("[directory]/topic_rate_limit_whitelist.txt"))
- log_config("Error 404: topic_rate_limit_whitelist.txt not found!")
- return
-
- log_config("Loading config file topic_rate_limit_whitelist.txt...")
-
- for(var/line in file2list("[directory]/topic_rate_limit_whitelist.txt"))
- if(!line)
- continue
- if(findtextEx(line, "#", 1, 2))
- continue
-
- fail_to_topic_whitelisted_ips[line] = 1
diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm
index 4e0fb9422c..4ff82381f9 100644
--- a/code/controllers/configuration/entries/general.dm
+++ b/code/controllers/configuration/entries/general.dm
@@ -612,3 +612,7 @@ This maintains a list of ip addresses that are able to bypass topic filtering.
protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED
/datum/config_entry/flag/guest_ban
+
+/datum/config_entry/string/playersave_path
+ config_entry_value = "data/player_saves"
+ protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED
diff --git a/code/controllers/subsystem/admin.dm b/code/controllers/subsystem/admin.dm
deleted file mode 100644
index 8aab64b048..0000000000
--- a/code/controllers/subsystem/admin.dm
+++ /dev/null
@@ -1,40 +0,0 @@
-SUBSYSTEM_DEF(admin)
- name = "Admin"
- wait = 5 MINUTES
- flags = SS_NO_INIT | SS_KEEP_TIMING
- runlevels = RUNLEVELS_DEFAULT|RUNLEVEL_LOBBY
- var/list/currentrun = list()
- var/times_repeated = 0
-
-/datum/controller/subsystem/admin/stat_entry(msg)
- msg = "P:[unansweredAhelps.len]"
- return ..()
-
-/datum/controller/subsystem/admin/fire(resumed = FALSE)
- if (!resumed)
- currentrun = unansweredAhelps.Copy()
-
- if(!currentrun.len)
- times_repeated = 0
- return
-
- var/msg = "Unheard Ahelps (Repeated [times_repeated] times):"
-
- while (currentrun.len)
- var/ahelp_msg = currentrun[currentrun.len]
- currentrun.len--
-
- if (!ahelp_msg)
- continue
-
- msg += unansweredAhelps[ahelp_msg] + "\n"
-
- if (MC_TICK_CHECK)
- return
-
- for(var/client/C in GLOB.admins)
- if(C && C.admin_holder && (C.admin_holder.rights & R_MOD))
- if(C.prefs.toggles_sound & SOUND_ADMINHELP)
- sound_to(C, 'sound/effects/adminhelp_new.ogg')
- to_chat(C, msg)
- times_repeated++
diff --git a/code/controllers/subsystem/communications.dm b/code/controllers/subsystem/communications.dm
index d4144c9f0e..e214b29836 100644
--- a/code/controllers/subsystem/communications.dm
+++ b/code/controllers/subsystem/communications.dm
@@ -107,6 +107,7 @@ var/const/MAX_FREQ = 1468 // ---------------------------------------------------
var/const/HC_FREQ = 1471
var/const/SOF_FREQ = 1472
var/const/PVST_FREQ = 1473
+var/const/CBRN_FREQ = 1474
//Ship department channels
var/const/SENTRY_FREQ = 1480
@@ -162,6 +163,7 @@ var/list/radiochannels = list(
SQUAD_MARINE_5 = ECHO_FREQ,
SQUAD_MARINE_CRYO = CRYO_FREQ,
SQUAD_SOF = SOF_FREQ,
+ SQUAD_CBRN = CBRN_FREQ,
RADIO_CHANNEL_ALAMO = DS1_FREQ,
RADIO_CHANNEL_NORMANDY = DS2_FREQ,
@@ -262,6 +264,7 @@ SUBSYSTEM_DEF(radio)
"[DELTA_FREQ]" = "deltaradio",
"[ECHO_FREQ]" = "echoradio",
"[CRYO_FREQ]" = "cryoradio",
+ "[CBRN_FREQ]" = "hcradio",
"[SOF_FREQ]" = "hcradio",
"[HC_FREQ]" = "hcradio",
"[PVST_FREQ]" = "pvstradio",
diff --git a/code/controllers/subsystem/disease.dm b/code/controllers/subsystem/disease.dm
index 25200cce11..b98187ca25 100644
--- a/code/controllers/subsystem/disease.dm
+++ b/code/controllers/subsystem/disease.dm
@@ -1,22 +1,19 @@
-var/list/active_diseases = list()
-
-
SUBSYSTEM_DEF(disease)
name = "Disease"
wait = 2 SECONDS
flags = SS_NO_INIT | SS_KEEP_TIMING
priority = SS_PRIORITY_DISEASE
- var/list/currentrun = list()
+ var/list/datum/disease/all_diseases = list()
+ var/list/datum/disease/currentrun = list()
/datum/controller/subsystem/disease/stat_entry(msg)
- msg = "P:[active_diseases.len]"
+ msg = "P:[all_diseases.len]"
return ..()
-
/datum/controller/subsystem/disease/fire(resumed = FALSE)
if (!resumed)
- currentrun = active_diseases.Copy()
+ currentrun = all_diseases.Copy()
while (currentrun.len)
var/datum/disease/D = currentrun[currentrun.len]
diff --git a/code/controllers/subsystem/fail_to_topic.dm b/code/controllers/subsystem/fail_to_topic.dm
deleted file mode 100644
index 45674683a4..0000000000
--- a/code/controllers/subsystem/fail_to_topic.dm
+++ /dev/null
@@ -1,81 +0,0 @@
-SUBSYSTEM_DEF(fail_to_topic)
- name = "Fail to Topic"
- init_order = SS_INIT_FAIL_TO_TOPIC
- flags = SS_BACKGROUND
- runlevels = ALL
-
- var/list/rate_limiting = list()
- var/list/fail_counts = list()
- var/list/active_bans = list()
- var/list/currentrun = list()
-
- var/rate_limit
- var/max_fails
- var/enabled = FALSE
-
-/datum/controller/subsystem/fail_to_topic/Initialize(timeofday)
- rate_limit = ((CONFIG_GET(number/topic_rate_limit)) SECONDS)
- max_fails = CONFIG_GET(number/topic_max_fails)
- enabled = CONFIG_GET(flag/topic_enabled)
-
- if (world.system_type == UNIX && enabled)
- enabled = FALSE
- WARNING("fail_to_topic subsystem disabled. UNIX is not supported.")
- return SS_INIT_NO_NEED
-
- if (!enabled)
- can_fire = FALSE
- return SS_INIT_NO_NEED
-
- return SS_INIT_SUCCESS
-
-/datum/controller/subsystem/fail_to_topic/fire(resumed = FALSE)
- if(!resumed)
- currentrun = rate_limiting.Copy()
- //cache for sanic speed (lists are references anyways)
- var/list/current_run = currentrun
-
- while(current_run.len)
- var/ip = current_run[current_run.len]
- var/last_attempt = current_run[ip]
- current_run.len--
-
- // last_attempt list housekeeping
- if(world.time - last_attempt > rate_limit)
- rate_limiting -= ip
- fail_counts -= ip
-
- if(MC_TICK_CHECK)
- return
-
-/datum/controller/subsystem/fail_to_topic/proc/IsRateLimited(ip)
- if(!enabled)
- return FALSE
-
- var/last_attempt = rate_limiting[ip]
-
- if (config.fail_to_topic_whitelisted_ips[ip])
- return FALSE
-
- if (active_bans[ip])
- return TRUE
-
- rate_limiting[ip] = world.time
-
- if (isnull(last_attempt))
- return FALSE
-
- if (world.time - last_attempt > rate_limit)
- fail_counts -= ip
- return FALSE
- else
- var/failures = fail_counts[ip]
-
- if (isnull(failures))
- fail_counts[ip] = 1
- return TRUE
- else if (failures > max_fails)
- return TRUE
- else
- fail_counts[ip] = failures + 1
- return TRUE
diff --git a/code/controllers/subsystem/fast_machinery.dm b/code/controllers/subsystem/fast_machinery.dm
deleted file mode 100644
index 8211b3b5e3..0000000000
--- a/code/controllers/subsystem/fast_machinery.dm
+++ /dev/null
@@ -1,27 +0,0 @@
-var/list/fast_machines = list()
-
-
-SUBSYSTEM_DEF(fast_machinery)
- name = "Fast Machinery"
- wait = 0.7 SECONDS
- priority = SS_PRIORITY_FAST_MACHINERY
- flags = SS_NO_INIT
- var/list/currentrun = list()
-
-/datum/controller/subsystem/fast_machinery/stat_entry(msg)
- msg = "FP:[fast_machines.len]"
- return ..()
-
-/datum/controller/subsystem/fast_machinery/fire(resumed = FALSE)
- if(!resumed)
- currentrun = fast_machines.Copy()
- while(currentrun.len)
- var/obj/structure/machinery/M = currentrun[currentrun.len]
- currentrun.len--
-
- if(QDELETED(M))
- continue
-
- M.process()
- if(MC_TICK_CHECK)
- return
diff --git a/code/controllers/subsystem/game_decorator.dm b/code/controllers/subsystem/game_decorator.dm
new file mode 100644
index 0000000000..dd53b647d1
--- /dev/null
+++ b/code/controllers/subsystem/game_decorator.dm
@@ -0,0 +1,35 @@
+// Essentially the same as decorators but that apply to the whole game state instead of individual atoms
+SUBSYSTEM_DEF(game_decorator)
+ name = "Game Decorator"
+ init_order = SS_INIT_DECORATOR
+ flags = SS_NO_FIRE
+
+/datum/controller/subsystem/game_decorator/Initialize()
+ . = ..()
+ for(var/decorator_type in subtypesof(/datum/game_decorator))
+ var/datum/game_decorator/decorator = new decorator_type()
+ if(!decorator.is_active_decor())
+ continue
+ if(!decorator.defer_decoration)
+ decorator.decorate()
+ CHECK_TICK
+
+ return SS_INIT_SUCCESS
+
+/datum/game_decorator
+ var/defer_decoration = TRUE //! So map decoration is done post-setup after nightmare and spawners
+
+/datum/game_decorator/New()
+ if(defer_decoration && is_active_decor())
+ RegisterSignal(SSdcs, COMSIG_GLOB_MODE_POSTSETUP, PROC_REF(defered_decoration))
+
+/datum/game_decorator/proc/is_active_decor()
+ return FALSE
+
+/datum/game_decorator/proc/defered_decoration(dcs)
+ SIGNAL_HANDLER
+ decorate()
+
+/datum/game_decorator/proc/decorate()
+ set waitfor = FALSE
+ return
diff --git a/code/controllers/subsystem/hijack.dm b/code/controllers/subsystem/hijack.dm
new file mode 100644
index 0000000000..55b5aa75ca
--- /dev/null
+++ b/code/controllers/subsystem/hijack.dm
@@ -0,0 +1,429 @@
+SUBSYSTEM_DEF(hijack)
+ name = "Hijack"
+ wait = 2 SECONDS
+ flags = SS_KEEP_TIMING
+ priority = SS_PRIORITY_HIJACK
+ init_order = SS_INIT_HIJACK
+
+ ///Required progress to evacuate safely via lifeboats
+ var/required_progress = 100
+
+ ///Current progress towards evacuating safely via lifeboats
+ var/current_progress = 0
+
+ /// How much progress is required to early launch
+ var/early_launch_required_progress = 25
+
+ ///The estimated time left to get to the safe evacuation point
+ var/estimated_time_left = 0
+
+ ///Areas that are marked as having progress, assoc list that is progress_area = boolean, the boolean indicating if it was progressing or not on the last fire()
+ var/list/area/progress_areas = list()
+
+ ///The areas that need cycled through currently
+ var/list/area/current_run = list()
+
+ ///The progress of the current run that needs to be added at the end of the current run
+ var/current_run_progress_additive = 0
+
+ ///Holds what the current_run_progress_additive should be multiplied by at the end of the current run
+ var/current_run_progress_multiplicative = 1
+
+ ///Holds the progress change from last run
+ var/last_run_progress_change = 0
+
+ ///Holds the next % point progress should be announced, increments on itself
+ var/announce_checkpoint = 25
+
+ ///What stage of evacuation we are currently on
+ var/evac_status = EVACUATION_STATUS_NOT_INITIATED
+
+ ///What stage of hijack are we currently on
+ var/hijack_status = HIJACK_OBJECTIVES_NOT_STARTED
+
+ ///Whether or not evacuation has been disabled by admins
+ var/evac_admin_denied = FALSE
+
+ /// If TRUE, self destruct has been unlocked and is possible with a hold of reactor
+ var/sd_unlocked = FALSE
+
+ /// Admin var to manually prevent self destruct from occurring
+ var/admin_sd_blocked = FALSE
+
+ /// Maximum amount of fusion generators that can be overloaded at once for a time benefit
+ var/maximum_overload_generators = 18
+
+ /// How many generators are currently overloaded
+ var/overloaded_generators = 0
+
+ /// How long the manual self destruct will take on the high end
+ var/sd_max_time = 15 MINUTES
+
+ /// How long the manual self destruct will take on the low end
+ var/sd_min_time = 5 MINUTES
+
+ /// How much time left until SD detonates
+ var/sd_time_remaining = 0
+
+ /// Roughly what % of the SD countdown remains
+ var/percent_completion_remaining = 100
+
+ /// If the engine room has been heated, occurs at 33% SD completion
+ var/engine_room_heated = FALSE
+
+ /// If the engine room has been superheated, occurs at 66% SD completion
+ var/engine_room_superheated = FALSE
+
+ /// If the self destruct has/is detonating
+ var/sd_detonated = FALSE
+
+ /// If a generator has ever been overloaded in the past this round
+ var/generator_ever_overloaded = FALSE
+
+ /// If ARES has announced the 50% point yet for SD
+ var/ares_sd_announced = FALSE
+
+/datum/controller/subsystem/hijack/Initialize(timeofday)
+ RegisterSignal(SSdcs, COMSIG_GLOB_GENERATOR_SET_OVERLOADING, PROC_REF(on_generator_overload))
+ return SS_INIT_SUCCESS
+
+/datum/controller/subsystem/hijack/stat_entry(msg)
+ if(!SSticker?.mode?.is_in_endgame)
+ msg = " Not Hijack"
+ return ..()
+
+ if(current_progress >= required_progress)
+ msg = " Complete"
+ return ..()
+
+ msg = " Progress: [current_progress]% | Last run: [last_run_progress_change]"
+ return ..()
+
+/datum/controller/subsystem/hijack/fire(resumed = FALSE)
+ if(!SSticker?.mode?.is_in_endgame)
+ return
+
+ if(hijack_status < HIJACK_OBJECTIVES_STARTED)
+ hijack_status = HIJACK_OBJECTIVES_STARTED
+
+ if(current_progress >= required_progress)
+ if(hijack_status < HIJACK_OBJECTIVES_COMPLETE)
+ hijack_status = HIJACK_OBJECTIVES_COMPLETE
+
+ if(sd_unlocked && overloaded_generators)
+ sd_time_remaining -= wait
+ if(!engine_room_heated && (sd_time_remaining <= (max((1 - round(overloaded_generators / maximum_overload_generators, 0.01)) * sd_max_time, sd_min_time) * 0.66)))
+ heat_engine_room()
+
+ if(!ares_sd_announced && (sd_time_remaining <= (max((1 - round(overloaded_generators / maximum_overload_generators, 0.01)) * sd_max_time, sd_min_time) * 0.5)))
+ announce_sd_halfway()
+
+ if(!engine_room_superheated && (sd_time_remaining <= (max((1 - round(overloaded_generators / maximum_overload_generators, 0.01)) * sd_max_time, sd_min_time) * 0.33)))
+ superheat_engine_room()
+
+ if((sd_time_remaining <= 0) && !sd_detonated)
+ detonate_sd()
+
+ return
+
+ if(!resumed)
+ current_run = progress_areas.Copy()
+
+ for(var/area/almayer/cycled_area as anything in current_run)
+ current_run -= cycled_area
+
+ if(progress_areas[cycled_area] != cycled_area.power_equip)
+ progress_areas[cycled_area] = !progress_areas[cycled_area]
+ announce_area_power_change(cycled_area)
+
+ if(progress_areas[cycled_area])
+ switch(cycled_area.hijack_evacuation_type)
+ if(EVACUATION_TYPE_ADDITIVE)
+ current_run_progress_additive += cycled_area.hijack_evacuation_weight
+ if(EVACUATION_TYPE_MULTIPLICATIVE)
+ current_run_progress_multiplicative *= cycled_area.hijack_evacuation_weight
+
+ if (MC_TICK_CHECK)
+ return
+
+ last_run_progress_change = current_run_progress_additive * current_run_progress_multiplicative
+ current_progress += last_run_progress_change
+
+ if(last_run_progress_change)
+ estimated_time_left = ((required_progress - current_progress) / last_run_progress_change) * wait
+ else
+ estimated_time_left = INFINITY
+
+ if(current_progress >= announce_checkpoint)
+ announce_progress()
+ announce_checkpoint += initial(announce_checkpoint)
+
+ current_run_progress_additive = 0
+ current_run_progress_multiplicative = 1
+
+///Called when the xeno dropship crashes into the Almayer and announces the current status of various objectives to marines
+/datum/controller/subsystem/hijack/proc/announce_status_on_crash()
+ var/message = ""
+
+ for(var/area/cycled_area as anything in progress_areas)
+ message += "[cycled_area] - [cycled_area.power_equip ? "Online" : "Offline"]\n"
+ progress_areas[cycled_area] = cycled_area.power_equip
+
+ message += "\nDue to low orbit, extra fuel is required for non-surface evacuations.\nMaintain fueling functionality for optimal evacuation conditions."
+
+ marine_announcement(message, HIJACK_ANNOUNCE)
+
+///Called when an area power status is changed to announce that it has been changed
+/datum/controller/subsystem/hijack/proc/announce_area_power_change(area/changed_area)
+ var/message = "[changed_area] - [changed_area.power_equip ? "Online" : "Offline"]"
+
+ marine_announcement(message, HIJACK_ANNOUNCE)
+
+///Called to announce to xenos the state of evacuation progression
+/datum/controller/subsystem/hijack/proc/announce_progress()
+ var/announce = announce_checkpoint / initial(announce_checkpoint)
+
+ var/marine_warning_areas = ""
+ var/xeno_warning_areas = ""
+
+ for(var/area/cycled_area as anything in progress_areas)
+ if(cycled_area.power_equip)
+ xeno_warning_areas += "[cycled_area], "
+ continue
+ marine_warning_areas += "[cycled_area], "
+
+ if(xeno_warning_areas)
+ xeno_warning_areas = copytext(xeno_warning_areas, 1, -2)
+
+ if(marine_warning_areas)
+ marine_warning_areas = copytext(marine_warning_areas, 1, -2)
+
+ var/datum/hive_status/hive
+ for(var/hivenumber in GLOB.hive_datum)
+ hive = GLOB.hive_datum[hivenumber]
+ if(!length(hive.totalXenos))
+ continue
+
+ switch(announce)
+ if(1)
+ xeno_announcement(SPAN_XENOANNOUNCE("The talls are a quarter of the way towards their goals. Disable the following areas: [xeno_warning_areas]"), hive.hivenumber, XENO_HIJACK_ANNOUNCE)
+ if(2)
+ xeno_announcement(SPAN_XENOANNOUNCE("The talls are half way towards their goals. Disable the following areas: [xeno_warning_areas]"), hive.hivenumber, XENO_HIJACK_ANNOUNCE)
+ if(3)
+ xeno_announcement(SPAN_XENOANNOUNCE("The talls are three quarters of the way towards their goals. Disable the following areas: [xeno_warning_areas]"), hive.hivenumber, XENO_HIJACK_ANNOUNCE)
+ if(4)
+ xeno_announcement(SPAN_XENOANNOUNCE("The talls have completed their goals!"), hive.hivenumber, XENO_HIJACK_ANNOUNCE)
+
+ switch(announce)
+ if(1)
+ marine_announcement("Emergency fuel replenishment at 25 percent. Lifeboat emergency early launch now available.[marine_warning_areas ? "\nTo increase speed restore power to the following areas: [marine_warning_areas]" : " All fueling areas operational."]", HIJACK_ANNOUNCE)
+ if(2)
+ marine_announcement("Emergency fuel replenishment at 50 percent.[marine_warning_areas ? "\nTo increase speed restore power to the following areas: [marine_warning_areas]" : " All fueling areas operational."]", HIJACK_ANNOUNCE)
+ if(3)
+ marine_announcement("Emergency fuel replenishment at 75 percent.[marine_warning_areas ? "\nTo increase speed restore power to the following areas: [marine_warning_areas]" : " All fueling areas operational."]", HIJACK_ANNOUNCE)
+ if(4)
+ marine_announcement("Emergency fuel replenishment at 100 percent. Safe utilization of lifeboats now possible.", HIJACK_ANNOUNCE)
+ if(!admin_sd_blocked)
+ addtimer(CALLBACK(src, PROC_REF(unlock_self_destruct)), 8 SECONDS)
+
+/// Passes the ETA for status panels
+/datum/controller/subsystem/hijack/proc/get_evac_eta()
+ switch(hijack_status)
+ if(HIJACK_OBJECTIVES_STARTED)
+ if(estimated_time_left == INFINITY)
+ return "Never"
+ return "[duration2text_sec(estimated_time_left)]"
+
+ if(HIJACK_OBJECTIVES_COMPLETE)
+ return "Complete"
+
+/datum/controller/subsystem/hijack/proc/get_sd_eta()
+ if(!sd_time_remaining)
+ return "Complete"
+
+ if(overloaded_generators <= 0)
+ return "Never"
+
+ return "[duration2text_sec(sd_time_remaining)]"
+
+//~~~~~~~~~~~~~~~~~~~~~~~~ EVAC STUFF ~~~~~~~~~~~~~~~~~~~~~~~~//
+
+/// Initiates evacuation by announcing and then prepping all lifepods/lifeboats
+/datum/controller/subsystem/hijack/proc/initiate_evacuation()
+ if(evac_status == EVACUATION_STATUS_NOT_INITIATED && !(evac_admin_denied & FLAGS_EVACUATION_DENY))
+ evac_status = EVACUATION_STATUS_INITIATED
+ ai_announcement("Attention. Emergency. All personnel must evacuate immediately.", 'sound/AI/evacuate.ogg')
+
+ for(var/obj/structure/machinery/status_display/cycled_status_display in machines)
+ if(is_mainship_level(cycled_status_display.z))
+ cycled_status_display.set_picture("evac")
+ for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile)
+ shuttle.prepare_evac()
+ activate_lifeboats()
+ return TRUE
+
+/// Cancels evacuation, tells lifepods/lifeboats and status_displays
+/datum/controller/subsystem/hijack/proc/cancel_evacuation()
+ if(evac_status == EVACUATION_STATUS_INITIATED)
+ evac_status = EVACUATION_STATUS_NOT_INITIATED
+ deactivate_lifeboats()
+ ai_announcement("Evacuation has been cancelled.", 'sound/AI/evacuate_cancelled.ogg')
+
+ for(var/obj/structure/machinery/status_display/cycled_status_display in machines)
+ if(is_mainship_level(cycled_status_display.z))
+ cycled_status_display.set_sec_level_picture()
+
+ for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile)
+ shuttle.cancel_evac()
+ return TRUE
+
+/// Opens the lifeboat doors and gets them ready to launch
+/datum/controller/subsystem/hijack/proc/activate_lifeboats()
+ for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks)
+ var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked()
+ if(lifeboat && lifeboat.available)
+ lifeboat.status = LIFEBOAT_ACTIVE
+ lifeboat_dock.open_dock()
+
+/// Turns off ability to manually take off lifeboats
+/datum/controller/subsystem/hijack/proc/deactivate_lifeboats()
+ for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks)
+ var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked()
+ if(lifeboat && lifeboat.available)
+ lifeboat.status = LIFEBOAT_INACTIVE
+
+
+/// Once refueling is done, marines can optionally hold SD for a time for a stalemate instead of a xeno minor
+/datum/controller/subsystem/hijack/proc/unlock_self_destruct()
+ sd_time_remaining = sd_max_time
+ sd_unlocked = TRUE
+ marine_announcement("Fuel reserves full. Manual detonation of fuel reserves by overloading the on-board fusion reactors now possible.", HIJACK_ANNOUNCE)
+
+/datum/controller/subsystem/hijack/proc/on_generator_overload(obj/structure/machinery/power/fusion_engine/source, new_overloading)
+ SIGNAL_HANDLER
+
+ if(!generator_ever_overloaded)
+ generator_ever_overloaded = TRUE
+ var/datum/hive_status/hive
+ for(var/hivenumber in GLOB.hive_datum)
+ hive = GLOB.hive_datum[hivenumber]
+ if(!length(hive.totalXenos))
+ continue
+
+ xeno_announcement(SPAN_XENOANNOUNCE("The talls may be attempting to take their ship down with them in Engineering, stop them!"), hive.hivenumber, XENO_HIJACK_ANNOUNCE)
+
+ adjust_generator_overload_count(new_overloading ? 1 : -1)
+
+/datum/controller/subsystem/hijack/proc/adjust_generator_overload_count(amount = 1)
+ var/generator_overload_percent = round(overloaded_generators / maximum_overload_generators, 0.01)
+ var/old_required_time = sd_min_time + ((1 - generator_overload_percent) * (sd_max_time - sd_min_time))
+ percent_completion_remaining = sd_time_remaining / old_required_time
+ overloaded_generators = clamp(overloaded_generators + amount, 0, maximum_overload_generators)
+ generator_overload_percent = round(overloaded_generators / maximum_overload_generators, 0.01)
+ var/new_required_time = sd_min_time + ((1 - generator_overload_percent) * (sd_max_time - sd_min_time))
+ sd_time_remaining = percent_completion_remaining * new_required_time
+
+/datum/controller/subsystem/hijack/proc/heat_engine_room()
+ engine_room_heated = TRUE
+ var/area/engine_room = GLOB.areas_by_type[/area/almayer/engineering/engine_core]
+ engine_room.firealert()
+ engine_room.temperature = T90C
+ for(var/mob/current_mob as anything in GLOB.mob_list)
+ var/area/mob_area = get_area(current_mob)
+ if(istype(mob_area, /area/almayer/engineering/engine_core))
+ to_chat(current_mob, SPAN_BOLDWARNING("You feel the heat of the room increase as the fusion engines whirr louder."))
+
+/datum/controller/subsystem/hijack/proc/superheat_engine_room()
+ engine_room_superheated = TRUE
+ var/area/engine_room = GLOB.areas_by_type[/area/almayer/engineering/engine_core]
+ engine_room.firealert()
+ engine_room.temperature = T120C //slowly deals burn at this temp
+ for(var/mob/current_mob as anything in GLOB.mob_list)
+ var/area/mob_area = get_area(current_mob)
+ if(istype(mob_area, /area/almayer/engineering/engine_core))
+ to_chat(current_mob, SPAN_BOLDWARNING("The room feels incredibly hot, you can't take much more of this!"))
+
+/datum/controller/subsystem/hijack/proc/announce_sd_halfway()
+ ares_sd_announced = TRUE
+ marine_announcement("ALERT: Fusion reactor meltdown has reached fifty percent.", HIJACK_ANNOUNCE)
+
+/datum/controller/subsystem/hijack/proc/detonate_sd()
+ set waitfor = FALSE
+ sd_detonated = TRUE
+ var/creak_picked = pick('sound/effects/creak1.ogg', 'sound/effects/creak2.ogg', 'sound/effects/creak3.ogg')
+ for(var/mob/current_mob as anything in GLOB.mob_list)
+ var/turf/current_turf = get_turf(current_mob)
+ if(!current_mob?.loc || !current_mob.client || !current_turf || !is_mainship_level(current_turf.z))
+ continue
+
+ to_chat(current_mob, SPAN_BOLDWARNING("The ship's deck worryingly creaks underneath you."))
+ playsound_client(current_mob.client, creak_picked, vol = 50)
+
+ sleep(7 SECONDS)
+ shakeship(2, 10, TRUE)
+
+ marine_announcement("ALERT: Fusion reactors dangerously overloaded. Runaway meltdown in reactor core imminent.", HIJACK_ANNOUNCE)
+ sleep(5 SECONDS)
+
+ var/sound_picked = pick('sound/theme/nuclear_detonation1.ogg','sound/theme/nuclear_detonation2.ogg')
+ for(var/client/player as anything in GLOB.clients)
+ playsound_client(player, sound_picked, 90)
+
+ var/list/alive_mobs = list() //Everyone who will be destroyed on the zlevel(s).
+ var/list/dead_mobs = list() //Everyone who only needs to see the cinematic.
+ for(var/mob/current_mob as anything in GLOB.mob_list) //This only does something cool for the people about to die, but should prove pretty interesting.
+ var/turf/current_turf = get_turf(current_mob)
+ if(!current_mob?.loc || !current_turf)
+ continue
+
+ if(current_mob.stat == DEAD)
+ dead_mobs |= current_mob
+ continue
+
+ if(is_mainship_level(current_turf.z))
+ alive_mobs |= current_mob
+ shake_camera(current_mob, 110, 4)
+
+
+ sleep(10 SECONDS)
+ /*Hardcoded for now, since this was never really used for anything else.
+ Would ideally use a better system for showing cutscenes.*/
+ var/atom/movable/screen/cinematic/explosion/explosive_cinematic = new()
+
+ for(var/mob/current_mob as anything in (alive_mobs + dead_mobs))
+ if(current_mob?.loc && current_mob.client)
+ current_mob.client.add_to_screen(explosive_cinematic) //They may have disconnected in the mean time.
+
+ sleep(1.5 SECONDS) //Extra 1.5 seconds to look at the ship.
+ flick("intro_nuke", explosive_cinematic)
+
+ sleep(3.5 SECONDS)
+ for(var/mob/current_mob as anything in alive_mobs)
+ var/turf/current_mob_turf = get_turf(current_mob)
+ if(!current_mob?.loc || !current_mob_turf) //Who knows, maybe they escaped, or don't exist anymore.
+ continue
+
+ if(is_mainship_level(current_mob_turf.z))
+ if(istype(current_mob.loc, /obj/structure/closet/secure_closet/freezer/fridge))
+ continue
+
+ current_mob.death(create_cause_data("nuclear explosion"))
+ else
+ current_mob.client.remove_from_screen(explosive_cinematic) //those who managed to escape the z level at last second shouldn't have their view obstructed.
+
+ flick("ship_destroyed", explosive_cinematic)
+ explosive_cinematic.icon_state = "summary_destroyed"
+
+ for(var/client/player as anything in GLOB.clients)
+ playsound_client(player, 'sound/effects/explosionfar.ogg', 90)
+
+
+ sleep(0.5 SECONDS)
+ if(SSticker.mode)
+ SSticker.mode.check_win()
+
+ if(!SSticker.mode) //Just a safety, just in case a mode isn't running, somehow.
+ to_world(SPAN_ROUNDBODY("Resetting in 30 seconds!"))
+ sleep(30 SECONDS)
+ log_game("Rebooting due to nuclear detonation.")
+ world.Reboot()
diff --git a/code/controllers/subsystem/htmlui.dm b/code/controllers/subsystem/htmlui.dm
deleted file mode 100644
index 5dc885abc6..0000000000
--- a/code/controllers/subsystem/htmlui.dm
+++ /dev/null
@@ -1,57 +0,0 @@
-// What in the name of god is this?
-// You'd think it'd be some form of process for the HTML interface module.
-// But it isn't?
-// It's some form of proc queue but ???
-// Does anything even *use* this?
-
-SUBSYSTEM_DEF(html_ui)
- name = "HTMLUI"
- wait = 1.7 SECONDS
- flags = SS_NO_INIT
- runlevels = RUNLEVELS_DEFAULT|RUNLEVEL_LOBBY
- var/list/update = list()
-
-/datum/controller/subsystem/html_ui/fire(resumed = FALSE)
- if (update.len)
- var/list/L = list()
- var/key
-
- for (var/datum/procqueue_item/item in update)
- key = "[item.ref]_[item.procname]"
-
- if (item.args)
- key += "("
- var/first = 1
- for (var/a in item.args)
- if (!first)
- key += ","
- key += "[a]"
- first = 0
- key += ")"
-
- if (!(key in L))
- if (item.args)
- call(item.ref, item.procname)(arglist(item.args))
- else
- call(item.ref, item.procname)()
-
- L.Add(key)
-
- update.Cut()
-
-
-/datum/controller/subsystem/html_ui/proc/queue(ref, procname, ...)
- var/datum/procqueue_item/item = new
- item.ref = ref
- item.procname = procname
-
- if (args.len > 2)
- item.args = args.Copy(3)
-
- update.Insert(1, item)
-
-
-/datum/procqueue_item
- var/ref
- var/procname
- var/list/args
diff --git a/code/controllers/subsystem/inactivity.dm b/code/controllers/subsystem/inactivity.dm
index 5edd4e8c52..6b85424440 100644
--- a/code/controllers/subsystem/inactivity.dm
+++ b/code/controllers/subsystem/inactivity.dm
@@ -17,7 +17,7 @@ SUBSYSTEM_DEF(inactivity)
return
for(var/client/current as anything in GLOB.clients)
- if(current.admin_holder && current.admin_holder.rights & R_ADMIN) //Skip admins.
+ if(current.admin_holder && current.admin_holder.rights & R_MOD) //Skip admins.
continue
if(current.is_afk(INACTIVITY_KICK))
if(!istype(current.mob, /mob/dead))
diff --git a/code/controllers/subsystem/interior.dm b/code/controllers/subsystem/interior.dm
index be12bdee1b..8fb7ffbfee 100644
--- a/code/controllers/subsystem/interior.dm
+++ b/code/controllers/subsystem/interior.dm
@@ -42,7 +42,7 @@ SUBSYSTEM_DEF(interior)
continue
if(x >= bounds[1].x && x <= bounds[2].x && y >= bounds[1].y && y <= bounds[2].y)
return current_interior
- return null
+ return
/// Checks if an atom is in an interior
/datum/controller/subsystem/interior/proc/in_interior(loc)
diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm
index 6f0f060305..913e5dcd50 100644
--- a/code/controllers/subsystem/mapping.dm
+++ b/code/controllers/subsystem/mapping.dm
@@ -6,10 +6,13 @@ SUBSYSTEM_DEF(mapping)
var/list/datum/map_config/configs
var/list/datum/map_config/next_map_configs
+ ///Name of all maps
var/list/map_templates = list()
-
+ ///Name of all shuttles
var/list/shuttle_templates = list()
var/list/all_shuttle_templates = list()
+ ///map_id of all tents
+ var/list/tent_type_templates = list()
var/list/areas_in_z = list()
@@ -201,6 +204,7 @@ SUBSYSTEM_DEF(mapping)
map_templates[T.name] = T
preloadShuttleTemplates()
+ preload_tent_templates()
/proc/generateMapList(filename)
. = list()
@@ -242,6 +246,11 @@ SUBSYSTEM_DEF(mapping)
all_shuttle_templates[item] = S
map_templates[S.shuttle_id] = S
+/datum/controller/subsystem/mapping/proc/preload_tent_templates()
+ for(var/template in subtypesof(/datum/map_template/tent))
+ var/datum/map_template/tent/new_tent = new template()
+ tent_type_templates[new_tent.map_id] = new_tent
+
/datum/controller/subsystem/mapping/proc/RequestBlockReservation(width, height, z, type = /datum/turf_reservation, turf_type_override)
UNTIL(initialized && !clearing_reserved_turfs)
var/datum/turf_reservation/reserve = new type
diff --git a/code/controllers/subsystem/midi.dm b/code/controllers/subsystem/midi.dm
deleted file mode 100644
index 158d67cf25..0000000000
--- a/code/controllers/subsystem/midi.dm
+++ /dev/null
@@ -1,45 +0,0 @@
-/datum/midi_record
- var/target
- var/midi
-
-SUBSYSTEM_DEF(midi)
- name = "Midi"
- wait = 2 SECONDS
- flags = SS_NO_INIT|SS_BACKGROUND
- runlevels = RUNLEVELS_DEFAULT|RUNLEVEL_LOBBY
- priority = SS_PRIORITY_MIDI
-
- var/list/datum/midi_record/prepped_midis = list()
-
- var/list/datum/midi_record/currentrun = list()
-
-
-/datum/controller/subsystem/midi/stat_entry(msg)
- msg = "MR:[prepped_midis.len]"
- return ..()
-
-
-/datum/controller/subsystem/midi/fire(resumed = FALSE)
- if (!resumed)
- currentrun = prepped_midis
- prepped_midis = list()
-
- while (currentrun.len)
- var/datum/midi_record/E = currentrun[currentrun.len]
- currentrun.len--
-
- if (!E)
- continue
-
- E.target << E.midi
-
- if (MC_TICK_CHECK)
- return
-
-/datum/controller/subsystem/midi/proc/queue(target, midi)
- if(!prepped_midis)
- prepped_midis = list()
- var/datum/midi_record/MR = new()
- MR.target = target
- MR.midi = midi
- prepped_midis.Add(MR)
diff --git a/code/controllers/subsystem/processing/defprocess.dm b/code/controllers/subsystem/processing/defprocess.dm
new file mode 100644
index 0000000000..3701a0617a
--- /dev/null
+++ b/code/controllers/subsystem/processing/defprocess.dm
@@ -0,0 +1,5 @@
+PROCESSING_SUBSYSTEM_DEF(defprocess)
+ name = "Defenses Processing"
+ priority = SS_PRIORITY_DEFENSES
+ flags = SS_NO_INIT
+ wait = 0.7 SECONDS
diff --git a/code/controllers/subsystem/smoke_system.dm b/code/controllers/subsystem/smoke_system.dm
deleted file mode 100644
index 2010687fcb..0000000000
--- a/code/controllers/subsystem/smoke_system.dm
+++ /dev/null
@@ -1,31 +0,0 @@
-var/list/active_smoke_effects = list()
-
-
-SUBSYSTEM_DEF(smoke_effects)
- name = "Smoke Effects"
- wait = 1 SECONDS
- flags = SS_NO_INIT | SS_KEEP_TIMING
- priority = SS_PRIORITY_OBJECTS
-
- var/list/currentrun = list()
-
-/datum/controller/subsystem/smoke_effects/stat_entry(msg)
- msg = "P:[active_smoke_effects.len]"
- return ..()
-
-
-/datum/controller/subsystem/smoke_effects/fire(resumed = FALSE)
- if(!resumed)
- currentrun = active_smoke_effects.Copy()
-
- while(currentrun.len)
- var/obj/effect/particle_effect/smoke/E = currentrun[currentrun.len]
- currentrun.len--
-
- if(!E || QDELETED(E))
- continue
-
- E.process()
-
- if(MC_TICK_CHECK)
- return
diff --git a/code/controllers/subsystem/stamina.dm b/code/controllers/subsystem/stamina.dm
deleted file mode 100644
index 84d5b4038c..0000000000
--- a/code/controllers/subsystem/stamina.dm
+++ /dev/null
@@ -1,25 +0,0 @@
-var/global/list/active_staminas = list()
-
-SUBSYSTEM_DEF(stamina)
- name = "Stamina"
- wait = 2 SECONDS
- priority = SS_PRIORITY_STAMINA
- flags = SS_NO_INIT
- var/list/currentrun = list()
-
-
-/datum/controller/subsystem/stamina/fire(resumed = FALSE)
- if (!resumed)
- currentrun = active_staminas.Copy()
-
- while (currentrun.len)
- var/datum/stamina/S = currentrun[currentrun.len]
- currentrun.len--
-
- if (!S || QDELETED(S))
- continue
-
- S.process()
-
- if (MC_TICK_CHECK)
- return
diff --git a/code/controllers/subsystem/stats_collector.dm b/code/controllers/subsystem/stats_collector.dm
deleted file mode 100644
index de66e3b2c6..0000000000
--- a/code/controllers/subsystem/stats_collector.dm
+++ /dev/null
@@ -1,17 +0,0 @@
-/// Collects simple round statistics periodically
-SUBSYSTEM_DEF(stats_collector)
- name = "Round Stats"
- wait = 30 SECONDS
- priority = SS_PRIORITY_PAGER_STATUS
- runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
- flags = SS_KEEP_TIMING | SS_NO_INIT
-
- var/stat_ticks = 0
- var/players_counter = 0
-
-/datum/controller/subsystem/stats_collector/fire(resumed = FALSE)
- players_counter += length(GLOB.clients)
- stat_ticks++
-
-/datum/controller/subsystem/stats_collector/proc/get_avg_players()
- return players_counter / stat_ticks
diff --git a/code/controllers/subsystem/teleporter.dm b/code/controllers/subsystem/teleporter.dm
deleted file mode 100644
index b753bdb0d5..0000000000
--- a/code/controllers/subsystem/teleporter.dm
+++ /dev/null
@@ -1,10 +0,0 @@
-// Master teleporter controller.
-SUBSYSTEM_DEF(teleporter)
- name = "Teleporter"
- wait = 5 SECONDS
- init_order = SS_INIT_TELEPORTER
- priority = SS_PRIORITY_TELEPORTER
- flags = SS_NO_FIRE|SS_NO_INIT
-
- var/list/teleporters_by_id = list() // Associative list of teleporters by ID, master list of teleporters to process
- var/list/teleporters = list() // Process list (identical contents to teleporters_by_id)
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index cfa415f15c..7fe2b56eba 100644
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -439,7 +439,7 @@ SUBSYSTEM_DEF(ticker)
/datum/controller/subsystem/ticker/proc/send_tip_of_the_round()
var/message
- var/tip_file = pick("strings/xenotips.txt", "strings/marinetips.txt", "strings/metatips.txt", 15;"strings/memetips.txt")
+ var/tip_file = pick("strings/marinetips.txt", "strings/metatips.txt", 15;"strings/memetips.txt")
var/list/tip_list = file2list(tip_file)
if(length(tip_file))
message = pick(tip_list)
diff --git a/code/controllers/subsystem/xenocon.dm b/code/controllers/subsystem/xenocon.dm
deleted file mode 100644
index d16e59bd98..0000000000
--- a/code/controllers/subsystem/xenocon.dm
+++ /dev/null
@@ -1,18 +0,0 @@
-SUBSYSTEM_DEF(xenocon)
- name = "XENOCON"
- wait = 5 SECONDS
- priority = SS_PRIORITY_INACTIVITY
- flags = SS_NO_INIT
- var/rewarded = FALSE
-
-/datum/controller/subsystem/xenocon/fire(resumed = FALSE)
- if(rewarded)
- return
-
- var/datum/hive_status/hive
- for(var/hivenumber in GLOB.hive_datum)
- hive = GLOB.hive_datum[hivenumber]
- if(hive.xenocon_points >= XENOCON_THRESHOLD)
- var/datum/emergency_call/em_call = new /datum/emergency_call/xenos/platoon()
- em_call.activate()
- rewarded = TRUE
diff --git a/code/datums/agents/tools/chloroform.dm b/code/datums/agents/tools/chloroform.dm
index 464533309b..c6e3320688 100644
--- a/code/datums/agents/tools/chloroform.dm
+++ b/code/datums/agents/tools/chloroform.dm
@@ -47,8 +47,8 @@
/obj/item/weapon/chloroform/proc/grab_stun(mob/living/M, mob/living/user)
M.anchored = TRUE
- M.frozen = TRUE
- M.density = FALSE
+ ADD_TRAIT(M, TRAIT_IMMOBILIZED, CHLOROFORM_TRAIT)
+ ADD_TRAIT(M, TRAIT_UNDENSE, CHLOROFORM_TRAIT)
M.able_to_speak = FALSE
M.update_canmove()
@@ -82,7 +82,8 @@
M.density = TRUE
M.able_to_speak = TRUE
M.layer = MOB_LAYER
- M.unfreeze()
+ REMOVE_TRAIT(M, TRAIT_IMMOBILIZED, CHLOROFORM_TRAIT)
+ REMOVE_TRAIT(M, TRAIT_UNDENSE, CHLOROFORM_TRAIT)
QDEL_NULL(mask_item)
diff --git a/code/datums/ammo/bullet/shotgun.dm b/code/datums/ammo/bullet/shotgun.dm
index 9504e3c1d1..d8a7248436 100644
--- a/code/datums/ammo/bullet/shotgun.dm
+++ b/code/datums/ammo/bullet/shotgun.dm
@@ -159,9 +159,8 @@
accurate_range = 8
max_range = 8
- damage = 90
- penetration = ARMOR_PENETRATION_TIER_4
- bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_6
+ damage = 60
+ bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_8
firing_freq_offset = SOUND_FREQ_LOW
//buckshot variant only used by the masterkey shotgun attachment.
@@ -196,7 +195,6 @@
accurate_range = 8
max_range = 8
damage = 90
- penetration = ARMOR_PENETRATION_TIER_4
firing_freq_offset = SOUND_FREQ_LOW
/*
diff --git a/code/datums/ammo/xeno.dm b/code/datums/ammo/xeno.dm
index 9d91920ac6..75c78298fe 100644
--- a/code/datums/ammo/xeno.dm
+++ b/code/datums/ammo/xeno.dm
@@ -37,7 +37,7 @@
neuro_callback = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(apply_neuro))
-/proc/apply_neuro(mob/M, power, insta_neuro)
+/proc/apply_neuro(mob/living/M, power, insta_neuro)
if(skillcheck(M, SKILL_ENDURANCE, SKILL_ENDURANCE_MAX) && !insta_neuro)
M.visible_message(SPAN_DANGER("[M] withstands the neurotoxin!"))
return //endurance 5 makes you immune to weak neurotoxin
@@ -69,7 +69,7 @@
M.adjust_effect(1 * power, WEAKEN) // KD them a bit more
M.visible_message(SPAN_DANGER("[M] falls prone."))
-/proc/apply_scatter_neuro(mob/M)
+/proc/apply_scatter_neuro(mob/living/M)
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(skillcheck(M, SKILL_ENDURANCE, SKILL_ENDURANCE_MAX))
@@ -317,7 +317,7 @@
shrapnel_type = /obj/item/shard/shrapnel/bone_chips
shrapnel_chance = 60
-/datum/ammo/xeno/bone_chips/on_hit_mob(mob/M, obj/projectile/P)
+/datum/ammo/xeno/bone_chips/on_hit_mob(mob/living/M, obj/projectile/P)
if(iscarbon(M))
var/mob/living/carbon/C = M
if((HAS_FLAG(C.status_flags, XENO_HOST) && HAS_TRAIT(C, TRAIT_NESTED)) || C.stat == DEAD)
@@ -347,7 +347,7 @@
damage = 10
shrapnel_chance = 0
-/datum/ammo/xeno/bone_chips/spread/runner/on_hit_mob(mob/M, obj/projectile/P)
+/datum/ammo/xeno/bone_chips/spread/runner/on_hit_mob(mob/living/M, obj/projectile/P)
if(iscarbon(M))
var/mob/living/carbon/C = M
if((HAS_FLAG(C.status_flags, XENO_HOST) && HAS_TRAIT(C, TRAIT_NESTED)) || C.stat == DEAD)
diff --git a/code/datums/components/autofire/autofire.dm b/code/datums/components/autofire/autofire.dm
index d052127eff..455fb70a9f 100644
--- a/code/datums/components/autofire/autofire.dm
+++ b/code/datums/components/autofire/autofire.dm
@@ -82,6 +82,8 @@
/datum/component/automatedfire/autofire/proc/initiate_shot()
SIGNAL_HANDLER
if(shooting)//if we are already shooting, it means the shooter is still on cooldown
+ if(bursting && (world.time > (next_fire + (burstfire_shot_delay * burst_shots_to_fire))))
+ hard_reset()
return
shooting = TRUE
process_shot()
diff --git a/code/datums/components/cell.dm b/code/datums/components/cell.dm
new file mode 100644
index 0000000000..81ef3733e2
--- /dev/null
+++ b/code/datums/components/cell.dm
@@ -0,0 +1,202 @@
+#define UNLIMITED_CHARGE -1
+#define UNLIMITED_DISTANCE -1
+
+/datum/component/cell
+ dupe_mode = COMPONENT_DUPE_UNIQUE
+ /// Maximum charge of the power cell, set to -1 for infinite charge
+ var/max_charge = 10000
+ /// Initial max charge of the power cell
+ var/initial_max_charge
+ /// Current charge of power cell
+ var/charge = 10000
+ /// If the component can be recharged by hitting its parent with a cell
+ var/hit_charge = FALSE
+ /// The maximum amount that can be recharged per tick when using a cell to recharge this component
+ var/max_recharge_tick = 400
+ /// If draining charge on process(), how much to drain per process call
+ var/charge_drain = 10
+ /// If the parent should show cell charge on examine
+ var/display_charge = TRUE
+ /// From how many tiles at the highest someone can examine the parent to see the charge
+ var/charge_examine_range = 1
+ /// If the component requires a cell to be inserted to work instead of having an integrated one
+ var/cell_insert = FALSE
+ /// Ref to an inserted cell. Should only be null if cell_insert is false
+ var/obj/item/cell/inserted_cell
+
+
+/datum/component/cell/Initialize(
+ max_charge = 10000,
+ hit_charge = FALSE,
+ max_recharge_tick = 400,
+ charge_drain = 10,
+ display_charge = TRUE,
+ charge_examine_range = 1,
+ cell_insert = FALSE,
+ )
+
+ . = ..()
+ if(!isatom(parent))
+ return COMPONENT_INCOMPATIBLE
+
+ src.max_charge = max_charge
+ charge = max_charge
+ src.hit_charge = hit_charge
+ src.max_recharge_tick = max_recharge_tick
+ src.charge_drain = charge_drain
+ src.display_charge = display_charge
+ src.charge_examine_range = charge_examine_range
+ src.cell_insert = cell_insert
+
+/datum/component/cell/Destroy(force, silent)
+ QDEL_NULL(inserted_cell)
+ return ..()
+
+
+/datum/component/cell/RegisterWithParent()
+ ..()
+ RegisterSignal(parent, list(COMSIG_PARENT_ATTACKBY, COMSIG_ITEM_ATTACKED), PROC_REF(on_object_hit))
+ RegisterSignal(parent, COMSIG_CELL_ADD_CHARGE, PROC_REF(add_charge))
+ RegisterSignal(parent, COMSIG_CELL_USE_CHARGE, PROC_REF(use_charge))
+ RegisterSignal(parent, COMSIG_CELL_CHECK_CHARGE, PROC_REF(has_charge))
+ RegisterSignal(parent, COMSIG_CELL_START_TICK_DRAIN, PROC_REF(start_drain))
+ RegisterSignal(parent, COMSIG_CELL_STOP_TICK_DRAIN, PROC_REF(stop_drain))
+ RegisterSignal(parent, COMSIG_CELL_REMOVE_CELL, PROC_REF(remove_cell))
+ RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine))
+ RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp))
+
+/datum/component/cell/process()
+ use_charge(null, charge_drain)
+
+/datum/component/cell/proc/on_emp(datum/source, severity)
+ SIGNAL_HANDLER
+
+ use_charge(null, round(max_charge / severity))
+
+/datum/component/cell/proc/start_drain(datum/source)
+ SIGNAL_HANDLER
+
+ START_PROCESSING(SSobj, src)
+
+/datum/component/cell/proc/stop_drain(datum/source)
+ SIGNAL_HANDLER
+
+ STOP_PROCESSING(SSobj, src)
+
+/datum/component/cell/proc/on_examine(datum/source, mob/examiner, list/examine_text)
+ SIGNAL_HANDLER
+
+ if(!display_charge)
+ return
+
+ if((charge_examine_range != UNLIMITED_DISTANCE) && get_dist(examiner, parent) > charge_examine_range)
+ return
+
+ examine_text += "A small gauge in the corner reads \"Power: [round(100 * charge / max_charge)]%\"."
+
+/datum/component/cell/proc/on_object_hit(datum/source, obj/item/cell/attack_obj, mob/living/attacker, params)
+ SIGNAL_HANDLER
+
+ if(!hit_charge || !istype(attack_obj))
+ return
+
+ if(!cell_insert)
+ INVOKE_ASYNC(src, PROC_REF(charge_from_cell), attack_obj, attacker)
+
+ else
+ insert_cell(attack_obj, attacker)
+
+ return COMPONENT_NO_AFTERATTACK|COMPONENT_CANCEL_ITEM_ATTACK
+
+/datum/component/cell/proc/insert_cell(obj/item/cell/power_cell, mob/living/user)
+ if(inserted_cell)
+ to_chat(user, SPAN_WARNING("There's already a power cell in [parent]!"))
+ return
+
+ if(SEND_SIGNAL(parent, COMSIG_CELL_TRY_INSERT_CELL) & COMPONENT_CANCEL_CELL_INSERT)
+ return
+
+ power_cell.drop_to_floor(user)
+ power_cell.forceMove(parent)
+ inserted_cell = power_cell
+ charge = power_cell.charge
+ max_charge = power_cell.maxcharge
+
+/datum/component/cell/proc/remove_cell(mob/living/user)
+ SIGNAL_HANDLER
+
+ user.put_in_hands(inserted_cell, TRUE)
+ to_chat(user, SPAN_NOTICE("You remove [inserted_cell] from [parent]."))
+ inserted_cell = null
+ max_charge = initial_max_charge
+ charge = 0
+
+/datum/component/cell/proc/charge_from_cell(obj/item/cell/power_cell, mob/living/user)
+ if(max_charge == UNLIMITED_CHARGE)
+ to_chat(user, SPAN_WARNING("[parent] doesn't need more power."))
+ return
+
+ while(charge < max_charge)
+ if(SEND_SIGNAL(parent, COMSIG_CELL_TRY_RECHARGING, user) & COMPONENT_CELL_NO_RECHARGE)
+ return
+
+ if(power_cell.charge <= 0)
+ to_chat(user, SPAN_WARNING("[power_cell] is completely dry."))
+ return
+
+ if(!do_after(user, 1 SECONDS, (INTERRUPT_ALL & (~INTERRUPT_MOVED)), BUSY_ICON_BUILD, power_cell, INTERRUPT_DIFF_LOC))
+ to_chat(user, SPAN_WARNING("You were interrupted."))
+ return
+
+ if(power_cell.charge <= 0)
+ return
+
+ var/to_transfer = min(max_recharge_tick, power_cell.charge, (max_charge - charge))
+ if(power_cell.use(to_transfer))
+ add_charge(null, to_transfer)
+ to_chat(user, "You transfer some power between [power_cell] and [parent]. The gauge now reads: [round(100 * charge / max_charge)]%.")
+
+/datum/component/cell/proc/add_charge(datum/source, charge_add = 0)
+ SIGNAL_HANDLER
+
+ if(max_charge == UNLIMITED_CHARGE)
+ return
+
+ if(!charge_add)
+ return
+
+ charge = clamp(charge + charge_add, 0, max_charge)
+
+/datum/component/cell/proc/use_charge(datum/source, charge_use = 0)
+ SIGNAL_HANDLER
+
+ if(max_charge == UNLIMITED_CHARGE)
+ return
+
+ if(!charge_use)
+ return
+
+ if(!charge)
+ return COMPONENT_CELL_NO_USE_CHARGE
+
+ charge = clamp(charge - charge_use, 0, max_charge)
+
+ if(!charge)
+ on_charge_empty()
+ return
+
+/datum/component/cell/proc/has_charge(datum/source, charge_amount = 0)
+ SIGNAL_HANDLER
+
+ if(!charge)
+ return COMPONENT_CELL_CHARGE_INSUFFICIENT
+
+ if(charge < charge_amount)
+ return COMPONENT_CELL_CHARGE_INSUFFICIENT
+
+/datum/component/cell/proc/on_charge_empty()
+ stop_drain()
+ SEND_SIGNAL(parent, COMSIG_CELL_OUT_OF_CHARGE)
+
+#undef UNLIMITED_CHARGE
+#undef UNLIMITED_DISTANCE
diff --git a/code/datums/components/crate_tag.dm b/code/datums/components/crate_tag.dm
new file mode 100644
index 0000000000..379df82a20
--- /dev/null
+++ b/code/datums/components/crate_tag.dm
@@ -0,0 +1,36 @@
+/datum/component/crate_tag
+ dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
+ /// The crate tag used for notifications and as label
+ var/name
+
+/datum/component/crate_tag/Initialize(name, obj/structure/closet/crate/masquarade_type)
+ var/obj/structure/closet/crate/crate = parent
+ if(!istype(crate))
+ return COMPONENT_INCOMPATIBLE
+ setup(name, masquarade_type)
+ RegisterSignal(parent, COMSIG_STRUCTURE_CRATE_SQUAD_LAUNCHED, PROC_REF(notify_squad))
+
+/datum/component/crate_tag/InheritComponent(datum/component/C, i_am_original, name, obj/structure/closet/crate/masquarade_type)
+ . = ..()
+ setup(name, masquarade_type)
+
+/datum/component/crate_tag/proc/setup(name, obj/structure/closet/crate/masquarade_type)
+ var/obj/structure/closet/crate/crate = parent
+ if(masquarade_type)
+ crate.name = initial(masquarade_type.name)
+ crate.desc = initial(masquarade_type.desc)
+ crate.icon_opened = initial(masquarade_type.icon_opened)
+ crate.icon_closed = initial(masquarade_type.icon_closed)
+ if(crate.opened)
+ crate.icon_state = crate.icon_opened
+ else
+ crate.icon_state = crate.icon_closed
+ if(name)
+ parent.AddComponent(/datum/component/label, name)
+ src.name = name // Keep it around additionally for notifications
+
+/// Handler to notify an overwatched squad that this crate has been dropped for them
+/datum/component/crate_tag/proc/notify_squad(datum/source, datum/squad/squad)
+ SIGNAL_HANDLER
+ squad.send_message("'[name]' supply drop incoming. Heads up!")
+ squad.send_maptext(name, "Incoming Supply Drop:")
diff --git a/code/datums/components/weed_food.dm b/code/datums/components/weed_food.dm
index ce6c17e0af..16be8665f5 100644
--- a/code/datums/components/weed_food.dm
+++ b/code/datums/components/weed_food.dm
@@ -259,7 +259,7 @@
active = FALSE
merged = TRUE
- parent_mob.density = FALSE
+ ADD_TRAIT(parent_mob, TRAIT_UNDENSE, XENO_WEED_TRAIT)
parent_mob.anchored = TRUE
parent_mob.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
parent_mob.plane = FLOOR_PLANE
diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm
index b60b20bc90..a2b060572b 100644
--- a/code/datums/datacore.dm
+++ b/code/datums/datacore.dm
@@ -7,6 +7,18 @@ GLOBAL_DATUM_INIT(data_core, /datum/datacore, new)
//This list tracks characters spawned in the world and cannot be modified in-game. Currently referenced by respawn_character().
var/locked[] = list()
+/datum/datacore/New()
+ . = ..()
+
+ RegisterSignal(SSdcs, COMSIG_GLOB_PLATOON_NAME_CHANGE, PROC_REF(rename_platoon))
+
+/datum/datacore/proc/rename_platoon(datum/source, new_name, old_name)
+ SIGNAL_HANDLER
+
+ for(var/datum/data/record/cycled_data_record in general)
+ if(cycled_data_record.fields["squad"] == old_name)
+ cycled_data_record.fields["squad"] = new_name
+
/datum/datacore/proc/get_manifest(monochrome, OOC, nonHTML)
var/list/cic = ROLES_CIC.Copy()
var/list/auxil = ROLES_AUXIL_SUPPORT.Copy()
@@ -133,6 +145,9 @@ GLOBAL_DATUM_INIT(data_core, /datum/datacore, new)
continue
dept_flags |= FLAG_SHOW_MARINES
squad_sublists[squad_name] = TRUE
+ ///If it is a real squad in the USCM squad list to prevent the crew manifest from breaking
+ if(!(squad_name in ROLES_SQUAD_ALL))
+ continue
LAZYSET(marines_by_squad[squad_name][real_rank], name, rank)
//here we fill manifest
diff --git a/code/datums/datum.dm b/code/datums/datum.dm
index b26c6afe4d..7d497785a7 100644
--- a/code/datums/datum.dm
+++ b/code/datums/datum.dm
@@ -19,8 +19,8 @@
/// Active timers with this datum as the target
var/list/active_timers
- /// Status traits attached.
- var/list/status_traits
+ /// Status traits attached to this datum. associative list of the form: list(trait name (string) = list(source1, source2, source3,...))
+ var/list/_status_traits
/**
* Components attached to this datum
diff --git a/code/datums/disease.dm b/code/datums/disease.dm
index 92986b668b..d2f466ebeb 100644
--- a/code/datums/disease.dm
+++ b/code/datums/disease.dm
@@ -131,7 +131,7 @@ var/list/diseases = typesof(/datum/disease) - /datum/disease
/datum/disease/process()
if(!holder)
- active_diseases -= src
+ SSdisease.all_diseases -= src
return
if(prob(65))
spread(holder)
@@ -176,7 +176,7 @@ var/list/diseases = typesof(/datum/disease) - /datum/disease
/datum/disease/New(process=TRUE)//process = 1 - adding the object to global list. List is processed by master controller.
cure_list = list(cure_id) // to add more cures, add more vars to this list in the actual disease's New()
if(process) // Viruses in list are considered active.
- active_diseases += src
+ SSdisease.all_diseases += src
initial_spread = spread
/datum/disease/proc/IsSame(datum/disease/D)
@@ -191,5 +191,5 @@ var/list/diseases = typesof(/datum/disease) - /datum/disease
/datum/disease/Destroy()
affected_mob = null
holder = null
- active_diseases -= src
+ SSdisease.all_diseases -= src
. = ..()
diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm
index 6440c97343..ad4703ba65 100644
--- a/code/datums/diseases/advance/advance.dm
+++ b/code/datums/diseases/advance/advance.dm
@@ -391,7 +391,7 @@ var/list/advance_cures = list(
D.AssignName(new_name)
D.Refresh()
- for(var/datum/disease/advance/AD in active_diseases)
+ for(var/datum/disease/advance/AD in SSdisease.all_diseases)
AD.Refresh()
for(var/mob/living/carbon/human/H in shuffle(GLOB.alive_mob_list.Copy()))
@@ -409,7 +409,7 @@ var/list/advance_cures = list(
/*
/mob/verb/test()
- for(var/datum/disease/D in active_diseases)
+ for(var/datum/disease/D in SSdisease.all_diseases)
to_chat(src, "[D.name] - [D.holder]")
*/
diff --git a/code/datums/diseases/black_goo.dm b/code/datums/diseases/black_goo.dm
index 38a26f3648..d4d9b6f509 100644
--- a/code/datums/diseases/black_goo.dm
+++ b/code/datums/diseases/black_goo.dm
@@ -211,6 +211,15 @@
. = ..()
reagents.add_reagent("antiZed", 30)
+/obj/item/reagent_container/glass/bottle/labeled_black_goo_cure
+ name = "\"Pathogen\" cure bottle"
+ desc = "The bottle has a biohazard symbol on the front, and has a label, designating its use against Agent A0-3959X.91–15, colloquially known as the \"Black Goo\"."
+ icon_state = "bottle20"
+
+/obj/item/reagent_container/glass/bottle/labeled_black_goo_cure/Initialize()
+ . = ..()
+ reagents.add_reagent("antiZed", 60)
+
/datum/language/zombie
name = "Zombie"
desc = "A growling, guttural method of communication, only Zombies seem to be capable of producing these sounds."
diff --git a/code/datums/effects/xeno_strains/boiler_trap.dm b/code/datums/effects/xeno_strains/boiler_trap.dm
index 61451391e8..1833b9641a 100644
--- a/code/datums/effects/xeno_strains/boiler_trap.dm
+++ b/code/datums/effects/xeno_strains/boiler_trap.dm
@@ -4,19 +4,17 @@
effect_name = "boiler trap"
duration = null
flags = INF_DURATION
- /// Ghetto flag indicating whether we actually placed the freeze or not, until we have an actual effects system
- var/freezer = FALSE
/datum/effects/boiler_trap/New(atom/A, mob/from, last_dmg_source, zone)
. = ..()
if(!QDELETED(src))
var/mob/M = affected_atom
- freezer = M.freeze()
+ ADD_TRAIT(M, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY(effect_name))
/datum/effects/boiler_trap/Destroy(force)
- if(ismob(affected_atom) && freezer)
+ if(ismob(affected_atom))
var/mob/M = affected_atom
- M.unfreeze()
+ REMOVE_TRAIT(M, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY(effect_name))
return ..()
/datum/effects/boiler_trap/validate_atom(atom/A)
@@ -29,7 +27,5 @@
. = ..()
if(!.) return FALSE
var/mob/M = affected_atom
- if(M.frozen) return TRUE
- if(!freezer)
- freezer = M.freeze()
+ ADD_TRAIT(M, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY(effect_name))
return TRUE
diff --git a/code/datums/emergency_calls/cbrn.dm b/code/datums/emergency_calls/cbrn.dm
new file mode 100644
index 0000000000..3a6b1c6406
--- /dev/null
+++ b/code/datums/emergency_calls/cbrn.dm
@@ -0,0 +1,80 @@
+/datum/emergency_call/cbrn
+ name = "CBRN (Squad)"
+ arrival_message = "A CBRN squad has been dispatched to your ship. Stand by."
+ objectives = "Handle the chemical, biological, radiological, or nuclear threat. Further orders may be provided."
+ mob_min = 3
+ mob_max = 5
+ max_heavies = 0
+ max_smartgunners = 0
+
+/datum/emergency_call/cbrn/create_member(datum/mind/new_mind, turf/override_spawn_loc)
+ var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point()
+
+ if(!istype(spawn_loc))
+ return //Didn't find a useable spawn point.
+
+ var/mob/living/carbon/human/mob = new(spawn_loc)
+ new_mind.transfer_to(mob, TRUE)
+
+ if(!leader && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(mob.client, JOB_SQUAD_LEADER, time_required_for_job))
+ leader = mob
+ arm_equipment(mob, /datum/equipment_preset/uscm/cbrn/leader, TRUE, TRUE)
+ to_chat(mob, SPAN_ROLE_HEADER("You are the CBRN Fireteam Leader!"))
+
+ else if(medics < max_medics && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(mob.client, JOB_SQUAD_MEDIC, time_required_for_job))
+ medics++
+ arm_equipment(mob, /datum/equipment_preset/uscm/cbrn/medic, TRUE, TRUE)
+ to_chat(mob, SPAN_ROLE_HEADER("You are the CBRN Squad Medic!"))
+
+ else if(engineers < max_engineers && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_ENGINEER) && check_timelock(mob.client, JOB_SQUAD_ENGI, time_required_for_job))
+ engineers++
+ arm_equipment(mob, /datum/equipment_preset/uscm/cbrn/engineer, TRUE, TRUE)
+ to_chat(mob, SPAN_ROLE_HEADER("You are the CBRN Squad Engineer!"))
+
+ else
+ arm_equipment(mob, /datum/equipment_preset/uscm/cbrn/standard, TRUE, TRUE)
+ to_chat(mob, SPAN_ROLE_HEADER("You are a CBRN Squad Rifleman!"))
+
+ to_chat(mob, SPAN_ROLE_BODY("You are a member of the USCM's CBRN. The CBRN is a force that specializes in handling chemical, biological, radiological, and nuclear threats."))
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), mob, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS)
+
+/datum/emergency_call/cbrn/ert
+ name = "CBRN (Distress)"
+ arrival_message = "Your distress signal has been received and we are dispatching the nearest CBRN squad to board with you now. Stand by."
+ probability = 10
+
+/datum/emergency_call/cbrn/ert/New()
+ ..()
+ objectives = "Investigate the distress signal aboard the [MAIN_SHIP_NAME]."
+
+/datum/emergency_call/cbrn/specialists
+ name = "CBRN (Specialists)"
+ mob_min = 2
+ mob_max = 5
+ max_engineers = 0
+ max_medics = 0
+
+/datum/emergency_call/cbrn/specialists/New()
+ var/cbrn_ship_name = "Unit [pick(nato_phonetic_alphabet)]-[rand(1, 99)]"
+ arrival_message = "[MAIN_SHIP_NAME], CBRN [cbrn_ship_name] has been dispatched. Follow all orders provided by [cbrn_ship_name]."
+ objectives = "You are a specialist team in [cbrn_ship_name] dispatched to quell a threat to [MAIN_SHIP_NAME]. Further orders may be provided."
+
+/datum/emergency_call/cbrn/specialists/create_member(datum/mind/new_mind, turf/override_spawn_loc)
+ var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point()
+
+ if(!istype(spawn_loc))
+ return //Didn't find a useable spawn point.
+
+ var/mob/living/carbon/human/mob = new(spawn_loc)
+ new_mind.transfer_to(mob, TRUE)
+
+ if(!leader && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(mob.client, JOB_SQUAD_LEADER, time_required_for_job))
+ leader = mob
+ arm_equipment(mob, /datum/equipment_preset/uscm/cbrn/specialist/lead, TRUE, TRUE)
+ to_chat(mob, SPAN_ROLE_HEADER("You are the CBRN Specialist Squad Leader!"))
+ else
+ arm_equipment(mob, /datum/equipment_preset/uscm/cbrn/specialist, TRUE, TRUE)
+ to_chat(mob, SPAN_ROLE_HEADER("You are a CBRN Specialist!"))
+
+ to_chat(mob, SPAN_ROLE_BODY("You are a member of the USCM's CBRN. The CBRN is a force that specializes in handling chemical, biological, radiological, and nuclear threats."))
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), mob, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS)
diff --git a/code/datums/emergency_calls/deathsquad.dm b/code/datums/emergency_calls/deathsquad.dm
index 0bfab8fbf2..1cd5bdef67 100644
--- a/code/datums/emergency_calls/deathsquad.dm
+++ b/code/datums/emergency_calls/deathsquad.dm
@@ -3,7 +3,7 @@
//Weyland-Yutani Deathsquad - W-Y Deathsquad. Event only
/datum/emergency_call/death
- name = "Weyland Whiteout Operators"
+ name = "Weyland Whiteout Operators (!DEATHSQUAD!)"
mob_max = 8
mob_min = 5
arrival_message = "'!`2*%slau#*jer t*h$em a!l%. le&*ve n(o^ w&*nes%6es.*v$e %#d ou^'"
@@ -18,41 +18,76 @@
// DEATH SQUAD--------------------------------------------------------------------------------
-/datum/emergency_call/death/create_member(datum/mind/M, turf/override_spawn_loc)
+/datum/emergency_call/death/create_member(datum/mind/player, turf/override_spawn_loc)
var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point()
if(!istype(spawn_loc))
return //Didn't find a useable spawn point.
- var/mob/living/carbon/human/H = new(spawn_loc)
- M.transfer_to(H, TRUE)
+ var/mob/living/carbon/human/person = new(spawn_loc)
+ player.transfer_to(person, TRUE)
- if(!leader && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(H.client, JOB_SQUAD_LEADER, time_required_for_job))
- leader = H
- to_chat(H, SPAN_ROLE_HEADER("You are the Whiteout Team Leader!"))
- to_chat(H, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
- arm_equipment(H, /datum/equipment_preset/pmc/w_y_whiteout/leader, TRUE, TRUE)
- else if(medics < max_medics && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(H.client, JOB_SQUAD_MEDIC, time_required_for_job))
+ if(!leader && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(person.client, JOB_SQUAD_LEADER, time_required_for_job))
+ leader = person
+ to_chat(person, SPAN_ROLE_HEADER("You are the Whiteout Team Leader!"))
+ to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
+ arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/leader, TRUE, TRUE)
+ else if(medics < max_medics && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(person.client, JOB_SQUAD_MEDIC, time_required_for_job))
medics++
- to_chat(H, SPAN_ROLE_HEADER("You are a Whiteout Team Medic!"))
- to_chat(H, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
- arm_equipment(H, /datum/equipment_preset/pmc/w_y_whiteout/medic, TRUE, TRUE)
- else if(heavies < max_heavies && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_SMARTGUNNER) && check_timelock(H.client, list(JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN), time_required_for_job))
+ to_chat(person, SPAN_ROLE_HEADER("You are a Whiteout Team Medic!"))
+ to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
+ arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/medic, TRUE, TRUE)
+ else if(heavies < max_heavies && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_SMARTGUNNER) && check_timelock(person.client, list(JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN), time_required_for_job))
heavies++
- to_chat(H, SPAN_ROLE_HEADER("You are a Whiteout Team Terminator!"))
- to_chat(H, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
- arm_equipment(H, /datum/equipment_preset/pmc/w_y_whiteout/terminator, TRUE, TRUE)
+ to_chat(person, SPAN_ROLE_HEADER("You are a Whiteout Team Terminator!"))
+ to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
+ arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/terminator, TRUE, TRUE)
else
- to_chat(H, SPAN_ROLE_HEADER("You are a Whiteout Team Operative!"))
- to_chat(H, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
- arm_equipment(H, /datum/equipment_preset/pmc/w_y_whiteout, TRUE, TRUE)
+ to_chat(person, SPAN_ROLE_HEADER("You are a Whiteout Team Operative!"))
+ to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
+ arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout, TRUE, TRUE)
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), H, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), person, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS)
+
+/datum/emergency_call/death/low_threat
+ name = "Weyland Whiteout Operators"
+
+// DEATH SQUAD--------------------------------------------------------------------------------
+/datum/emergency_call/death/low_threat/create_member(datum/mind/player, turf/override_spawn_loc)
+ var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point()
+
+ if(!istype(spawn_loc))
+ return //Didn't find a useable spawn point.
+
+ var/mob/living/carbon/human/person = new(spawn_loc)
+ player.transfer_to(person, TRUE)
+
+ if(!leader && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(person.client, JOB_SQUAD_LEADER, time_required_for_job))
+ leader = person
+ to_chat(person, SPAN_ROLE_HEADER("You are the Whiteout Team Leader!"))
+ to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
+ arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/low_threat/leader, TRUE, TRUE)
+ else if(medics < max_medics && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(person.client, JOB_SQUAD_MEDIC, time_required_for_job))
+ medics++
+ to_chat(person, SPAN_ROLE_HEADER("You are a Whiteout Team Medic!"))
+ to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
+ arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/low_threat/medic, TRUE, TRUE)
+ else if(heavies < max_heavies && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_SMARTGUNNER) && check_timelock(person.client, list(JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN), time_required_for_job))
+ heavies++
+ to_chat(person, SPAN_ROLE_HEADER("You are a Whiteout Team Terminator!"))
+ to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
+ arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/low_threat/terminator, TRUE, TRUE)
+ else
+ to_chat(person, SPAN_ROLE_HEADER("You are a Whiteout Team Operative!"))
+ to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
+ arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/low_threat, TRUE, TRUE)
+
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), person, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS)
//################################################################################################
// Marine commandos - USCM Deathsquad. Event only
/datum/emergency_call/marsoc
- name = "Marine Raider Strike Team"
+ name = "Marine Raider Strike Team (!DEATHSQUAD!)"
mob_max = 8
mob_min = 5
probability = 0
@@ -81,7 +116,7 @@
return
/datum/emergency_call/marsoc_covert
- name = "Marine Raider Operatives (Covert)"
+ name = "Marine Raider Operatives (!DEATHSQUAD! Covert)"
mob_max = 8
mob_min = 5
probability = 0
@@ -107,3 +142,27 @@
to_chat(H, SPAN_BOLDNOTICE("You are absolutely loyal to High Command and must follow their directives."))
to_chat(H, SPAN_BOLDNOTICE("Execute the mission assigned to you with extreme prejudice!"))
return
+
+
+/datum/emergency_call/marsoc/low_threat
+ name = "Marine Raider Operatives"
+
+/datum/emergency_call/marsoc/low_threat/create_member(datum/mind/MIND)
+
+ var/turf/spawn_loc = get_spawn_point()
+
+ if(!istype(spawn_loc))
+ return //Didn't find a useable spawn point.
+
+ var/mob/living/carbon/human/player = new(spawn_loc)
+ MIND.transfer_to(player, TRUE)
+ if(!leader && HAS_FLAG(player.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(player.client, JOB_SQUAD_LEADER, time_required_for_job)) //First one spawned is always the leader.
+ leader = player
+ to_chat(player, SPAN_WARNING(FONT_SIZE_BIG("You are a Marine Raider Team Leader, better than all the rest.")))
+ arm_equipment(player, /datum/equipment_preset/uscm/marsoc/low_threat/sl, TRUE, TRUE)
+ else
+ to_chat(player, SPAN_WARNING(FONT_SIZE_BIG("You are an elite Marine Raider, the best of the best.")))
+ arm_equipment(player, /datum/equipment_preset/uscm/marsoc/low_threat, TRUE, TRUE)
+ to_chat(player, SPAN_BOLDNOTICE("You are absolutely loyal to High Command and must follow their directives."))
+ to_chat(player, SPAN_BOLDNOTICE("Execute the mission assigned to you with extreme prejudice!"))
+ return
diff --git a/code/datums/emergency_calls/emergency_call.dm b/code/datums/emergency_calls/emergency_call.dm
index 4c3dfbbfac..9db46955a5 100644
--- a/code/datums/emergency_calls/emergency_call.dm
+++ b/code/datums/emergency_calls/emergency_call.dm
@@ -305,7 +305,7 @@
candidates = list()
if(arrival_message && announce_incoming)
- marine_announcement(arrival_message, "Intercepted Tranmission:")
+ marine_announcement(arrival_message, "Intercepted Transmission:")
/datum/emergency_call/proc/add_candidate(mob/M)
if(!M.client || (M.mind && (M.mind in candidates)) || istype(M, /mob/living/carbon/xenomorph))
diff --git a/code/datums/emergency_calls/upp_commando.dm b/code/datums/emergency_calls/upp_commando.dm
index 14c4af46c2..1bc2b59ba0 100644
--- a/code/datums/emergency_calls/upp_commando.dm
+++ b/code/datums/emergency_calls/upp_commando.dm
@@ -1,7 +1,7 @@
//UPP COMMANDOS
/datum/emergency_call/upp_commando
- name = "UPP Commandos"
+ name = "UPP Commandos (!DEATHSQUAD!)"
mob_max = 6
probability = 0
objectives = "Stealthily assault the ship. Use your silenced weapons, tranquilizers, and night vision to get the advantage on the enemy. Take out the power systems, comms and engine. Stick together and keep a low profile."
@@ -51,3 +51,29 @@
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), H, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS)
+/datum/emergency_call/upp_commando/low_threat
+ name = "UPP Commandos"
+
+/datum/emergency_call/upp_commando/create_member(datum/mind/mind, turf/override_spawn_loc)
+ var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point()
+
+ if(!istype(spawn_loc))
+ return //Didn't find a useable spawn point.
+
+ var/mob/living/carbon/human/person = new(spawn_loc)
+ mind.transfer_to(person, TRUE)
+
+ if(!leader && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(person.client, JOB_SQUAD_LEADER, time_required_for_job)) //First one spawned is always the leader.
+ leader = person
+ arm_equipment(person, /datum/equipment_preset/upp/commando/leader/low_threat, TRUE, TRUE)
+ to_chat(person, SPAN_ROLE_HEADER("You are a Commando Team Leader of the Union of Progressive People, a powerful socialist state that rivals the United Americas!"))
+ else if(medics < max_medics && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(person.client, JOB_SQUAD_MEDIC, time_required_for_job))
+ medics++
+ to_chat(person, SPAN_ROLE_HEADER("You are a Commando Medic of the Union of Progressive People, a powerful socialist state that rivals the United Americas!"))
+ arm_equipment(person, /datum/equipment_preset/upp/commando/medic/low_threat, TRUE, TRUE)
+ else
+ to_chat(person, SPAN_ROLE_HEADER("You are a Commando of the Union of Progressive People, a powerful socialist state that rivals the United Americas!"))
+ arm_equipment(person, /datum/equipment_preset/upp/commando/low_threat, TRUE, TRUE)
+ print_backstory(person)
+
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), person, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS)
diff --git a/code/datums/factions/uscm.dm b/code/datums/factions/uscm.dm
index fd97ea4ae3..2197d674c4 100644
--- a/code/datums/factions/uscm.dm
+++ b/code/datums/factions/uscm.dm
@@ -33,8 +33,9 @@
switch(squad.squad_type)
if("Platoon") marine_rk = "leader_a"
if("Team") marine_rk = "soctl_a"
-
current_human.langchat_styles = "langchat_bolded" // bold text for bold leaders
+ else if(squad.fireteam_leaders["SQ1"] == current_human || squad.fireteam_leaders["SQ2"] == current_human)
+ current_human.langchat_styles = "langchat_smaller_bolded"
else
current_human.langchat_styles = initial(current_human.langchat_styles)
@@ -189,6 +190,19 @@
if(JOB_CMB_OBS)
marine_rk = "obs"
icon_prefix = "cmb_"
+ // Check squad marines here too, for the unique ones
+ if(JOB_SQUAD_ENGI)
+ marine_rk = "engi"
+ if(JOB_SQUAD_MEDIC)
+ marine_rk = "med"
+ if(JOB_SQUAD_SPECIALIST)
+ marine_rk = "spec"
+ if(JOB_SQUAD_SMARTGUN)
+ marine_rk = "gun"
+ if(JOB_SQUAD_TEAM_LEADER)
+ marine_rk = "tl"
+ if(JOB_SQUAD_LEADER)
+ marine_rk = "leader"
if(marine_rk)
var/image/I = image('icons/mob/hud/marine_hud.dmi', current_human, "hudsquad")
diff --git a/code/datums/keybinding/communication.dm b/code/datums/keybinding/communication.dm
index 4164198d48..e1ba0ab5a3 100644
--- a/code/datums/keybinding/communication.dm
+++ b/code/datums/keybinding/communication.dm
@@ -32,7 +32,7 @@
/datum/keybinding/client/communication/whisper
hotkey_keys = list("Unbound")
classic_keys = list("Unbound")
- name = "Whisper"
+ name = WHISPER_CHANNEL
full_name = "IC Whisper"
keybind_signal = COMSIG_KB_CLIENT_WHISPER_DOWN
@@ -56,4 +56,4 @@
name = MENTOR_CHANNEL
full_name = "Mentor Say"
description = "Talk with other mentors."
- keybind_signal = COMSIG_KB_ADMIN_ASAY_DOWN
+ keybind_signal = COMSIG_KB_ADMIN_MENTORSAY_DOWN
diff --git a/code/datums/keybinding/human_combat.dm b/code/datums/keybinding/human_combat.dm
index 95b5c32d66..5458232918 100644
--- a/code/datums/keybinding/human_combat.dm
+++ b/code/datums/keybinding/human_combat.dm
@@ -192,3 +192,20 @@
COgun.toggle_iff(human)
return TRUE
*/
+
+/datum/keybinding/human/combat/toggle_shotgun_tube
+ hotkey_keys = list("Unbound")
+ classic_keys = list("Unbound")
+ name = "toggle_shotgun_tube"
+ full_name = "Toggle Shotgun Tube"
+ keybind_signal = COMSIG_KB_HUMAN_WEAPON_SHOTGUN_TUBE
+
+/datum/keybinding/human/combat/toggle_shotgun_tube/down(client/user)
+ . = ..()
+ if(.)
+ return
+ var/mob/living/carbon/human/human = user.mob
+ var/obj/item/weapon/gun/shotgun/pump/dual_tube/held_item = human.get_held_item()
+ if(istype(held_item))
+ held_item.toggle_tube()
+ return TRUE
diff --git a/code/datums/map_config.dm b/code/datums/map_config.dm
index 1f3c265ead..3bf5c601ce 100644
--- a/code/datums/map_config.dm
+++ b/code/datums/map_config.dm
@@ -87,12 +87,14 @@
/datum/equipment_preset/synth/survivor/janitor_synth,
/datum/equipment_preset/synth/survivor/chef_synth,
/datum/equipment_preset/synth/survivor/teacher_synth,
+ /datum/equipment_preset/synth/survivor/freelancer_synth,
+ /datum/equipment_preset/synth/survivor/trucker_synth,
/datum/equipment_preset/synth/survivor/bartender_synth,
/datum/equipment_preset/synth/survivor/detective_synth,
/datum/equipment_preset/synth/survivor/cmb_synth,
- /datum/equipment_preset/synth/survivor/security_synth,
- /datum/equipment_preset/synth/survivor/protection_synth,
- /datum/equipment_preset/synth/survivor/corporate_synth,
+ /datum/equipment_preset/synth/survivor/wy/security_synth,
+ /datum/equipment_preset/synth/survivor/wy/protection_synth,
+ /datum/equipment_preset/synth/survivor/wy/corporate_synth,
/datum/equipment_preset/synth/survivor/radiation_synth,
)
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index ecd3a26db4..fe59699fb9 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -20,6 +20,13 @@
src.ckey = ckey
player_entity = setup_player_entity(ckey)
+/datum/mind/Destroy()
+ current = null
+ original = null
+ ghost_mob = null
+ player_entity = null
+ return ..()
+
/datum/mind/proc/transfer_to(mob/living/new_character, force = FALSE)
if(QDELETED(new_character))
msg_admin_niche("[key]/[ckey] has tried to transfer to deleted [new_character].")
diff --git a/code/datums/mob_hud.dm b/code/datums/mob_hud.dm
index 65c5a47896..b0df9bca77 100644
--- a/code/datums/mob_hud.dm
+++ b/code/datums/mob_hud.dm
@@ -798,7 +798,7 @@ var/global/image/hud_icon_hudfocus
tag_holder.overlays += image('icons/mob/hud/hud.dmi', src, "prae_tag")
// Hacky, but works. Currently effects are hard to make with precise timings
- var/freeze_found = frozen
+ var/freeze_found = HAS_TRAIT(src, TRAIT_IMMOBILIZED) && !buckled && !lying
if (freeze_found)
freeze_holder.overlays += image('icons/mob/hud/hud.dmi', src, "xeno_freeze")
diff --git a/code/datums/stamina/_stamina.dm b/code/datums/stamina/_stamina.dm
index 36705e3be3..e233aaa816 100644
--- a/code/datums/stamina/_stamina.dm
+++ b/code/datums/stamina/_stamina.dm
@@ -37,13 +37,11 @@
current_stamina = Clamp(current_stamina - amount, 0, max_stamina)
if(current_stamina < max_stamina)
- if(!(src in active_staminas))
- active_staminas.Add(src)
-
+ START_PROCESSING(SSobj, src)
if(amount > 0)
apply_rest_period(STAMINA_REST_PERIOD)
else
- active_staminas.Remove(src)
+ STOP_PROCESSING(SSobj, src)
update_stamina_level()
diff --git a/code/datums/statistics/entities/caste_stats.dm b/code/datums/statistics/entities/caste_stats.dm
index 639e1b4a05..6bfc18d124 100644
--- a/code/datums/statistics/entities/caste_stats.dm
+++ b/code/datums/statistics/entities/caste_stats.dm
@@ -3,6 +3,10 @@
var/total_hits = 0
var/list/abilities_used = list() // types of /datum/entity/statistic, "tail sweep" = 10, "screech" = 2
+/datum/entity/player_stats/caste/Destroy(force)
+ . = ..()
+ QDEL_LIST_ASSOC_VAL(abilities_used)
+
/datum/entity/player_stats/caste/proc/setup_ability(ability)
if(!ability)
return
diff --git a/code/datums/statistics/entities/death_stats.dm b/code/datums/statistics/entities/death_stats.dm
index f0055ed871..369fcf3be6 100644
--- a/code/datums/statistics/entities/death_stats.dm
+++ b/code/datums/statistics/entities/death_stats.dm
@@ -140,16 +140,16 @@
new_death.detach()
return new_death
-/mob/living/carbon/human/track_mob_death(cause, cause_mob)
- . = ..(cause, cause_mob, job)
+/mob/living/carbon/human/track_mob_death(datum/cause_data/cause_data, turf/death_loc)
+ . = ..()
if(statistic_exempt || !mind)
return
var/datum/entity/player_stats/human/human_stats = mind.setup_human_stats()
if(human_stats && human_stats.death_list)
human_stats.death_list.Insert(1, .)
-/mob/living/carbon/xenomorph/track_mob_death(cause, cause_mob)
- var/datum/entity/statistic/death/new_death = ..(cause, cause_mob, caste_type)
+/mob/living/carbon/xenomorph/track_mob_death(datum/cause_data/cause_data, turf/death_loc)
+ var/datum/entity/statistic/death/new_death = ..()
if(!new_death)
return
new_death.is_xeno = TRUE // this was placed beneath the if below, which meant gibbing as a xeno wouldn't track properly in stats
diff --git a/code/datums/statistics/entities/human_stats.dm b/code/datums/statistics/entities/human_stats.dm
index 51b07867df..1e15aa1d16 100644
--- a/code/datums/statistics/entities/human_stats.dm
+++ b/code/datums/statistics/entities/human_stats.dm
@@ -5,10 +5,17 @@
var/total_shots = 0
var/total_shots_hit = 0
var/total_screams = 0
- var/datum/entity/weapon_stats/top_weapon = null // reference to /datum/entity/weapon_stats (like tac-shotty)
- var/list/weapon_stats_list = list() // list of types /datum/entity/weapon_stats
- var/list/job_stats_list = list() // list of types /datum/entity/job_stats
- var/list/datum/entity/statistic/medal/medal_list = list() // list of all medals earned
+ var/list/weapon_stats_list = list() //! indexed list of types /datum/entity/weapon_stats
+ var/list/job_stats_list = list() //! indexed list of types /datum/entity/job_stats
+ var/datum/entity/weapon_stats/top_weapon //! reference to /datum/entity/weapon_stats (like tac-shotty)
+ var/list/datum/entity/statistic/medal/medal_list = list() //! list of all medals earned
+
+/datum/entity/player_stats/human/Destroy(force)
+ . = ..()
+ QDEL_LIST_ASSOC_VAL(weapon_stats_list)
+ QDEL_LIST_ASSOC_VAL(job_stats_list)
+ QDEL_NULL(top_weapon)
+ QDEL_LIST(medal_list)
/datum/entity/player_stats/human/get_playtime(type)
if(!type)
diff --git a/code/datums/statistics/entities/job_stats.dm b/code/datums/statistics/entities/job_stats.dm
index ecde1c9420..199c2adb31 100644
--- a/code/datums/statistics/entities/job_stats.dm
+++ b/code/datums/statistics/entities/job_stats.dm
@@ -1,8 +1,8 @@
/datum/entity/player_stats/job
- var/name = null
- var/total_friendly_fire = null
- var/total_revives = null
- var/total_lives_saved = null
- var/total_shots = null
- var/total_shots_hit = null
- var/total_screams = null
+ var/name
+ var/total_friendly_fire
+ var/total_revives
+ var/total_lives_saved
+ var/total_shots
+ var/total_shots_hit
+ var/total_screams
diff --git a/code/datums/statistics/entities/panel_stats.dm b/code/datums/statistics/entities/panel_stats.dm
index d6e391e173..e507d5d81a 100644
--- a/code/datums/statistics/entities/panel_stats.dm
+++ b/code/datums/statistics/entities/panel_stats.dm
@@ -8,7 +8,7 @@
update_panel_data(round_statistics)
ui_interact(user)
-/datum/entity/player_entity/proc/ui_interact(mob/user, ui_key = "statistics", datum/nanoui/ui = null, force_open = 1)
+/datum/entity/player_entity/proc/ui_interact(mob/user, ui_key = "statistics", datum/nanoui/ui, force_open = 1)
data["menu"] = menu
data["subMenu"] = subMenu
data["dataMenu"] = dataMenu
diff --git a/code/datums/statistics/entities/player_entity.dm b/code/datums/statistics/entities/player_entity.dm
index 72f4d95d7a..f0b3d37ede 100644
--- a/code/datums/statistics/entities/player_entity.dm
+++ b/code/datums/statistics/entities/player_entity.dm
@@ -8,8 +8,8 @@
/datum/entity/player_entity
var/name
var/ckey // "cakey"
- var/list/datum/entity/player_stats = list()
- var/list/datum/entity/statistic/death/death_stats = list()
+ var/list/player_stats = list() //! Indeed list of /datum/entity/player_stats
+ var/list/death_stats = list() //! Indexed list of /datum/entity/statistic/death
var/menu = 0
var/subMenu = 0
var/dataMenu = 0
@@ -18,6 +18,11 @@
var/savefile_version
var/save_loaded = FALSE
+/datum/entity/player_entity/Destroy(force)
+ QDEL_LIST_ASSOC_VAL(player_stats)
+ QDEL_LIST_ASSOC_VAL(death_stats)
+ return ..()
+
/datum/entity/player_entity/proc/get_playtime(branch, type)
var/playtime = 0
if(player_stats["[branch]"])
diff --git a/code/datums/statistics/entities/player_stats.dm b/code/datums/statistics/entities/player_stats.dm
index b378d7c2ea..d9fbd3b11e 100644
--- a/code/datums/statistics/entities/player_stats.dm
+++ b/code/datums/statistics/entities/player_stats.dm
@@ -6,13 +6,21 @@
var/total_rounds_played = 0
var/steps_walked = 0
var/round_played = FALSE
- var/datum/entity/statistic/nemesis = null // "runner" = 3
+ var/datum/entity/statistic/nemesis // "runner" = 3
var/list/niche_stats = list() // list of type /datum/entity/statistic, "Total Executions" = number
var/list/humans_killed = list() // list of type /datum/entity/statistic, "jobname2" = number
var/list/xenos_killed = list() // list of type /datum/entity/statistic, "caste" = number
var/list/death_list = list() // list of type /datum/entity/death_stats
var/display_stat = TRUE
+/datum/entity/player_stats/Destroy(force)
+ QDEL_NULL(nemesis)
+ QDEL_LIST_ASSOC_VAL(niche_stats)
+ QDEL_LIST_ASSOC_VAL(humans_killed)
+ QDEL_LIST_ASSOC_VAL(xenos_killed)
+ QDEL_LIST_ASSOC_VAL(death_list)
+ return ..()
+
/datum/entity/player_stats/proc/get_playtime()
return total_playtime
diff --git a/code/datums/statistics/entities/round_stats.dm b/code/datums/statistics/entities/round_stats.dm
index 0e1fb6e387..baed6befa9 100644
--- a/code/datums/statistics/entities/round_stats.dm
+++ b/code/datums/statistics/entities/round_stats.dm
@@ -23,7 +23,7 @@
var/total_slashes = 0
// untracked data
- var/datum/entity/statistic/map/current_map = null // reference to current map
+ var/datum/entity/statistic/map/current_map // reference to current map
var/list/datum/entity/statistic/death/death_stats_list = list()
var/list/abilities_used = list() // types of /datum/entity/statistic, "tail sweep" = 10, "screech" = 2
@@ -37,8 +37,20 @@
var/list/job_stats_list = list() // list of types /datum/entity/job_stats
// nanoui data
- var/round_data[0]
- var/death_data[0]
+ var/list/round_data = list()
+ var/list/death_data = list()
+
+/datum/entity/statistic/round/Destroy(force)
+ . = ..()
+ QDEL_NULL(current_map)
+ QDEL_LIST(death_stats_list)
+ QDEL_LIST_ASSOC_VAL(abilities_used)
+ QDEL_LIST_ASSOC_VAL(final_participants)
+ QDEL_LIST_ASSOC_VAL(hijack_participants)
+ QDEL_LIST_ASSOC_VAL(total_deaths)
+ QDEL_LIST_ASSOC_VAL(caste_stats_list)
+ QDEL_LIST_ASSOC_VAL(weapon_stats_list)
+ QDEL_LIST_ASSOC_VAL(job_stats_list)
/datum/entity_meta/statistic_round
entity_type = /datum/entity/statistic/round
diff --git a/code/datums/statistics/entities/weapon_stats.dm b/code/datums/statistics/entities/weapon_stats.dm
index 0d8458c20d..9fff5c5144 100644
--- a/code/datums/statistics/entities/weapon_stats.dm
+++ b/code/datums/statistics/entities/weapon_stats.dm
@@ -1,16 +1,23 @@
/datum/entity/weapon_stats
- var/datum/entity/player = null // "deanthelis"
- var/list/niche_stats = list() // list of type /datum/entity/statistic, "Total Reloads" = number
- var/list/humans_killed = list() // list of type /datum/entity/statistic, "jobname2" = number
- var/list/xenos_killed = list() // list of type /datum/entity/statistic, "caste" = number
- var/name = null
+ var/datum/entity/player
+ var/list/niche_stats = list() //! Indexed list of /datum/entity/statistic, "Total Reloads" = number
+ var/list/humans_killed = list() //! Indexed list of /datum/entity/statistic, "jobname2" = number
+ var/list/xenos_killed = list() //! Indexed list of /datum/entity/statistic, "caste" = number
+ var/name
var/total_kills = 0
- var/total_hits = null
- var/total_shots = null
- var/total_shots_hit = null
- var/total_friendly_fire = null
+ var/total_hits
+ var/total_shots
+ var/total_shots_hit
+ var/total_friendly_fire
var/display_stat = TRUE
+/datum/entity/weapon_stats/Destroy(force)
+ player = null
+ QDEL_LIST_ASSOC_VAL(niche_stats)
+ QDEL_LIST_ASSOC_VAL(humans_killed)
+ QDEL_LIST_ASSOC_VAL(xenos_killed)
+ return ..()
+
/datum/entity/weapon_stats/proc/count_human_kill(job_name)
if(!job_name)
return
diff --git a/code/datums/statistics/entities/xeno_stats.dm b/code/datums/statistics/entities/xeno_stats.dm
index 9ed3272582..8fff4a2e5d 100644
--- a/code/datums/statistics/entities/xeno_stats.dm
+++ b/code/datums/statistics/entities/xeno_stats.dm
@@ -4,6 +4,12 @@
var/list/caste_stats_list = list() // list of types /datum/entity/player_stats/caste
var/list/datum/entity/statistic/medal/medal_list = list() // list of all royal jelly earned
+/datum/entity/player_stats/xeno/Destroy(force)
+ . = ..()
+ QDEL_NULL(top_caste)
+ QDEL_LIST_ASSOC_VAL(caste_stats_list)
+ QDEL_LIST(medal_list)
+
/datum/entity/player_stats/xeno/get_playtime(type)
if(!type || type == FACTION_XENOMORPH)
return ..()
diff --git a/code/game/area/almayer.dm b/code/game/area/almayer.dm
index 21ff397665..29c4fddfcb 100644
--- a/code/game/area/almayer.dm
+++ b/code/game/area/almayer.dm
@@ -12,6 +12,21 @@
ambience_exterior = AMBIENCE_ALMAYER
ceiling_muffle = FALSE
+ ///Whether this area is used for hijack evacuation progress
+ var/hijack_evacuation_area = FALSE
+
+ ///The weight this area gives towards hijack evacuation progress
+ var/hijack_evacuation_weight = 0
+
+ ///Whether this area is additive or multiplicative towards evacuation progress
+ var/hijack_evacuation_type = EVACUATION_TYPE_NONE
+
+/area/almayer/Initialize(mapload, ...)
+ . = ..()
+
+ if(hijack_evacuation_area)
+ SShijack.progress_areas[src] = power_equip
+
/area/shuttle/almayer/elevator_maintenance/upperdeck
name = "\improper Maintenance Elevator"
icon_state = "shuttle"
@@ -152,6 +167,9 @@
fake_zlevel = 2 // lowerdeck
soundscape_playlist = SCAPE_PL_ENG
soundscape_interval = 15
+ hijack_evacuation_area = TRUE
+ hijack_evacuation_weight = 0.2
+ hijack_evacuation_type = EVACUATION_TYPE_ADDITIVE
/area/almayer/engineering/starboard_atmos
name = "\improper Atmospherics Starboard"
@@ -175,6 +193,9 @@
name = "\improper Astronavigational Deck"
icon_state = "astronavigation"
fake_zlevel = 2 // lowerdeck
+ hijack_evacuation_area = TRUE
+ hijack_evacuation_weight = 1.1
+ hijack_evacuation_type = EVACUATION_TYPE_MULTIPLICATIVE
/area/almayer/shipboard/panic
name = "\improper Hangar Panic Room"
@@ -704,6 +725,9 @@
icon_state = "lifeboat_pump"
requires_power = 1
fake_zlevel = 1
+ hijack_evacuation_area = TRUE
+ hijack_evacuation_weight = 0.1
+ hijack_evacuation_type = EVACUATION_TYPE_ADDITIVE
/area/almayer/lifeboat_pumps/north1
name = "North West Lifeboat Fuel Pump"
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index d1115eb533..bce9693c45 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -20,6 +20,9 @@
var/list/flags_pass_temp
var/list/temp_flag_counter
+ var/list/flags_pass_temp_negative
+ var/list/negative_temp_flag_counter
+
// Temporary flags for what can pass through an atom
var/list/flags_can_pass_all_temp
var/list/flags_can_pass_front_temp
@@ -35,8 +38,11 @@
var/list/filter_data //For handling persistent filters
- // Base transform matrix
- var/matrix/base_transform = null
+ /// Base transform matrix, edited by admin tooling and such
+ var/matrix/base_transform
+ /// Last transform used before being compound with base_transform
+ /// This allows us to re-create transform if only base_transform changes
+ var/matrix/raw_transform
///Chemistry.
var/datum/reagents/reagents = null
@@ -118,7 +124,14 @@ directive is properly returned.
//===========================================================================
-
+// TODO make all atoms use set_density, do not rely on it at present
+///Setter for the `density` variable to append behavior related to its changing.
+/atom/proc/set_density(new_value)
+ SHOULD_CALL_PARENT(TRUE)
+ if(density == new_value)
+ return
+ . = density
+ density = new_value
//atmos procs
@@ -143,15 +156,27 @@ directive is properly returned.
if(loc)
return loc.return_gas()
-// Updates the atom's transform
-/atom/proc/apply_transform(matrix/M)
- if(!base_transform)
- transform = M
- return
+/// Updates the atom's transform compounding it with [/atom/var/base_transform]
+/atom/proc/apply_transform(matrix/new_transform, time = 0, easing = (EASE_IN|EASE_OUT))
+ var/matrix/base_copy
+ if(base_transform)
+ base_copy = matrix(base_transform)
+ else
+ base_copy = matrix()
+ raw_transform = matrix(new_transform) // Keep a copy to replay if needed
- var/matrix/base_copy = matrix(base_transform)
// Compose the base and applied transform in that order
- transform = base_copy.Multiply(M)
+ var/matrix/complete = base_copy.Multiply(raw_transform)
+
+ if(!time)
+ transform = complete
+ return
+ animate(src, transform = complete, time = time, easing = easing)
+
+/// Upates the base_transform which will be compounded with other transforms
+/atom/proc/update_base_transform(matrix/new_transform, time = 0)
+ base_transform = matrix(new_transform)
+ apply_transform(raw_transform, time)
/atom/proc/on_reagent_change()
return
@@ -185,7 +210,9 @@ directive is properly returned.
return
/atom/proc/emp_act(severity)
- return
+ SHOULD_CALL_PARENT(TRUE)
+
+ SEND_SIGNAL(src, COMSIG_ATOM_EMP_ACT, severity)
/atom/proc/in_contents_of(container)//can take class or object instance as argument
if(ispath(container))
@@ -225,8 +252,8 @@ directive is properly returned.
if(!examine_strings)
log_debug("Attempted to create an examine block with no strings! Atom : [src], user : [user]")
return
- to_chat(user, examine_block(examine_strings.Join("\n")))
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, examine_strings)
+ to_chat(user, examine_block(examine_strings.Join("\n")))
/atom/proc/get_examine_text(mob/user)
. = list()
@@ -436,6 +463,34 @@ Parameters are passed from New.
temp_flag_counter -= flag_str
flags_pass_temp &= ~flag
+/atom/proc/add_temp_negative_pass_flags(flags_to_add)
+ if (isnull(negative_temp_flag_counter))
+ negative_temp_flag_counter = list()
+
+ for (var/flag in GLOB.bitflags)
+ if(!(flags_to_add & flag))
+ continue
+ var/flag_str = "[flag]"
+ if (negative_temp_flag_counter[flag_str])
+ negative_temp_flag_counter[flag_str]++
+ else
+ negative_temp_flag_counter[flag_str] = 1
+ flags_pass_temp_negative |= flag
+
+/atom/proc/remove_temp_negative_pass_flags(flags_to_remove)
+ if (isnull(negative_temp_flag_counter))
+ return
+
+ for (var/flag in GLOB.bitflags)
+ if(!(flags_to_remove & flag))
+ continue
+ var/flag_str = "[flag]"
+ if (negative_temp_flag_counter[flag_str])
+ negative_temp_flag_counter[flag_str]--
+ if (negative_temp_flag_counter[flag_str] == 0)
+ negative_temp_flag_counter -= flag_str
+ flags_pass_temp_negative &= ~flag
+
// This proc is for initializing pass flags (allows for inheriting pass flags and list-based pass flags)
/atom/proc/initialize_pass_flags(datum/pass_flags_container/PF)
return
@@ -700,10 +755,9 @@ Parameters are passed from New.
usr.client.cmd_admin_emp(src)
if(href_list[VV_HK_MODIFY_TRANSFORM] && check_rights(R_VAREDIT))
- var/result = tgui_input_list(usr, "Choose the transformation to apply","Transform Mod", list("Scale","Translate","Rotate"))
+ var/result = tgui_input_list(usr, "Choose the transformation to apply","Transform Mod", list("Scale","Translate","Rotate", "Reflect X Axis", "Reflect Y Axis"))
if(!result)
return
- var/matrix/M = transform
if(!result)
return
switch(result)
@@ -712,19 +766,37 @@ Parameters are passed from New.
var/y = tgui_input_real_number(usr, "Choose y mod","Transform Mod")
if(isnull(x) || isnull(y))
return
- transform = M.Scale(x,y)
+ var/matrix/base_matrix = matrix(base_transform)
+ update_base_transform(base_matrix.Scale(x,y))
if("Translate")
var/x = tgui_input_real_number(usr, "Choose x mod (negative = left, positive = right)","Transform Mod")
var/y = tgui_input_real_number(usr, "Choose y mod (negative = down, positive = up)","Transform Mod")
if(isnull(x) || isnull(y))
return
- transform = M.Translate(x,y)
+ var/matrix/base_matrix = matrix(base_transform)
+ update_base_transform(base_matrix.Translate(x,y))
if("Rotate")
var/angle = tgui_input_real_number(usr, "Choose angle to rotate","Transform Mod")
if(isnull(angle))
return
- transform = M.Turn(angle)
-
+ var/matrix/base_matrix = matrix(base_transform)
+ update_base_transform(base_matrix.Turn(angle))
+ if("Reflect X Axis")
+ var/matrix/current = matrix(base_transform)
+ var/matrix/reflector = matrix()
+ reflector.a = -1
+ reflector.d = 0
+ reflector.b = 0
+ reflector.e = 1
+ update_base_transform(current * reflector)
+ if("Reflect Y Axis")
+ var/matrix/current = matrix(base_transform)
+ var/matrix/reflector = matrix()
+ reflector.a = 1
+ reflector.d = 0
+ reflector.b = 0
+ reflector.e = -1
+ update_base_transform(current * reflector)
SEND_SIGNAL(src, COMSIG_ATOM_VV_MODIFY_TRANSFORM)
if(href_list[VV_HK_AUTO_RENAME] && check_rights(R_VAREDIT))
diff --git a/code/game/gamemodes/cm_self_destruct.dm b/code/game/gamemodes/cm_self_destruct.dm
deleted file mode 100644
index 07c9c43a47..0000000000
--- a/code/game/gamemodes/cm_self_destruct.dm
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
-TODO
-Look into animation screen not showing on self-destruct and other weirdness
-Intergrate distress into this controller.
-Finish nanoui conversion for comm console.
-Make sure people who get nuked and wake up from SSD don't live.
-Add flashing lights to evac. //DEFERRED TO BETTER LIGHTING
-Finish the game mode announcement thing.
-Fix escape doors to work properly.
-*/
-
-/*
-How this works:
-
-First: All of the linking is done automatically on world start, so nothing needs to be done on that end other than making
-sure that objects are actually placed in the game world. If not, the game will error and let you know about it. But you
-don't need to modify variables or worry about area placement. It's all done for you.
-The rods, for example, configure the time per activation based on their number. Shuttles link their own machines via area.
-Nothing in this controller is linked to game mode, so it's stand alone, more or less, but it's best used during a game mode.
-Admins have a lot of tools in their disposal via the check antagonist panel, and devs can access the VV of this controller
-through that panel.
-
-Second: The communication console handles most of the IC triggers for activating these functions, the rest is handled elsewhere.
-Check communications.dm for that. shuttle_controller.dm handles the set up for the escape pods. escape_pods.dm handles most of the
-functions of the escape pods themselves. This file would likely need to be broken down into individual parts at some point in the
-future.
-
-Evacuation takes place when sufficient alert level is reaised and a distress beacon was launched. All of the evac pods come online
-and open their doors to allow entry inside. Characters may then get inside of the cryo units to before the shuttles automatically launch.
-If wanted, a nearby controller object may launch each individual shuttle early. Only three people may ride on a shuttle to escape,
-otherwise the launch will fail and the shuttle will become inoperable.
-Any launched shuttles are taken out of the game. If the evacuation is canceled, any persons inside of the cryo tubes will be ejected.
-They may temporarily open the door to exit if they are stuck inside after evac is canceled.
-
-When the self-destruct is enabled, the console comes online. This usually happens during an evacuation. Once the console is
-interacted with, it fires up the self-destruct sequence. Several rods rise and must be interacted with in order to arm the system.
-Once that happens, the console must be interacted with again to trigger the self-destruct. The self-destruct may also be
-canceled from the console.
-
-The self-destruct may also happen if a nuke is detonated on the ship's zlevel; if it is detonated elsewhere, the ship will not blow up.
-Regardless of where it's detonated, or how, a successful detonation will end the round or automatically restart the game.
-
-All of the necessary difines are stored under mode.dm in defines.
-*/
-
-var/global/datum/authority/branch/evacuation/EvacuationAuthority //This is initited elsewhere so that the world has a chance to load in.
-
-/datum/authority/branch/evacuation
- var/name = "Evacuation Authority"
- var/evac_time //Time the evacuation was initiated.
- var/evac_status = EVACUATION_STATUS_STANDING_BY //What it's doing now? It can be standing by, getting ready to launch, or finished.
-
- var/obj/structure/machinery/self_destruct/console/dest_master //The main console that does the brunt of the work.
- var/dest_rods[] //Slave devices to make the explosion work.
- var/dest_cooldown //How long it takes between rods, determined by the amount of total rods present.
- var/dest_index = 1 //What rod the thing is currently on.
- var/dest_status = NUKE_EXPLOSION_INACTIVE
- var/dest_started_at = 0
-
- var/flags_scuttle = NO_FLAGS
-
-/datum/authority/branch/evacuation/New()
- ..()
- dest_master = locate()
- if(!dest_master)
- log_debug("ERROR CODE SD1: could not find master self-destruct console")
- to_world(SPAN_DEBUG("ERROR CODE SD1: could not find master self-destruct console"))
- return FALSE
- dest_rods = new
- for(var/obj/structure/machinery/self_destruct/rod/I in dest_master.loc.loc) dest_rods += I
- if(!dest_rods.len)
- log_debug("ERROR CODE SD2: could not find any self-destruct rods")
- to_world(SPAN_DEBUG("ERROR CODE SD2: could not find any self-destruct rods"))
- QDEL_NULL(dest_master)
- return FALSE
- dest_cooldown = SELF_DESTRUCT_ROD_STARTUP_TIME / dest_rods.len
- dest_master.desc = "The main operating panel for a self-destruct system. It requires very little user input, but the final safety mechanism is manually unlocked.\nAfter the initial start-up sequence, [dest_rods.len] control rods must be armed, followed by manually flipping the detonation switch."
-
-/**
- * This proc returns the ship's z level list (or whatever specified),
- * when an evac/self-destruct happens.
- */
-/datum/authority/branch/evacuation/proc/get_affected_zlevels()
- //Nuke is not in progress, end the round on ship only.
- if(dest_status < NUKE_EXPLOSION_IN_PROGRESS && SSticker?.mode.is_in_endgame)
- . = SSmapping.levels_by_any_trait(list(ZTRAIT_MARINE_MAIN_SHIP))
- return
-
-//=========================================================================================
-//=========================================================================================
-//=====================================EVACUATION==========================================
-//=========================================================================================
-//=========================================================================================
-
-
-/datum/authority/branch/evacuation/proc/initiate_evacuation(force=0) //Begins the evacuation procedure.
- if(force || (evac_status == EVACUATION_STATUS_STANDING_BY && !(flags_scuttle & FLAGS_EVACUATION_DENY)))
- evac_time = world.time
- evac_status = EVACUATION_STATUS_INITIATING
- ai_announcement("Attention. Emergency. All personnel must evacuate immediately. You have [round(EVACUATION_ESTIMATE_DEPARTURE/60,1)] minute\s until departure.", 'sound/AI/evacuate.ogg')
- xeno_message_all("A wave of adrenaline ripples through the hive. The fleshy creatures are trying to escape!")
-
- for(var/obj/structure/machinery/status_display/SD in machines)
- if(is_mainship_level(SD.z))
- SD.set_picture("evac")
- for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile)
- shuttle.prepare_evac()
- activate_lifeboats()
- process_evacuation()
- return TRUE
-
-/datum/authority/branch/evacuation/proc/cancel_evacuation() //Cancels the evac procedure. Useful if admins do not want the marines leaving.
- if(evac_status == EVACUATION_STATUS_INITIATING)
- evac_time = null
- evac_status = EVACUATION_STATUS_STANDING_BY
- deactivate_lifeboats()
- ai_announcement("Evacuation has been cancelled.", 'sound/AI/evacuate_cancelled.ogg')
-
- if(get_security_level() == "red")
- for(var/obj/structure/machinery/status_display/SD in machines)
- if(is_mainship_level(SD.z))
- SD.set_picture("redalert")
-
- for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile)
- shuttle.cancel_evac()
- return TRUE
-
-/datum/authority/branch/evacuation/proc/begin_launch() //Launches the pods.
- if(evac_status == EVACUATION_STATUS_INITIATING)
- evac_status = EVACUATION_STATUS_IN_PROGRESS //Cannot cancel at this point. All shuttles are off.
- spawn() //One of the few times spawn() is appropriate. No need for a new proc.
- ai_announcement("WARNING: Evacuation order confirmed. Launching escape pods.", 'sound/AI/evacuation_confirmed.ogg')
- addtimer(CALLBACK(src, PROC_REF(launch_lifeboats)), 10 SECONDS) // giving some time to board lifeboats
-
- for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile)
- shuttle.evac_launch()
- sleep(50)
-
- sleep(300) //Sleep 30 more seconds to make sure everyone had a chance to leave.
- var/lifesigns = 0
- // lifesigns += P.passengers
- var/obj/docking_port/mobile/crashable/lifeboat/lifeboat1 = SSshuttle.getShuttle(MOBILE_SHUTTLE_LIFEBOAT_PORT)
- lifeboat1.check_for_survivors()
- lifesigns += lifeboat1.survivors
- var/obj/docking_port/mobile/crashable/lifeboat/lifeboat2 = SSshuttle.getShuttle(MOBILE_SHUTTLE_LIFEBOAT_STARBOARD)
- lifeboat2.check_for_survivors()
- lifesigns += lifeboat2.survivors
- ai_announcement("ATTENTION: Evacuation complete. Outbound lifesigns detected: [lifesigns ? lifesigns : "none"].", 'sound/AI/evacuation_complete.ogg')
- evac_status = EVACUATION_STATUS_COMPLETE
- return TRUE
-
-/datum/authority/branch/evacuation/proc/process_evacuation() //Process the timer.
- set background = 1
-
- spawn while(evac_status == EVACUATION_STATUS_INITIATING) //If it's not departing, no need to process.
- if(world.time >= evac_time + EVACUATION_AUTOMATIC_DEPARTURE) begin_launch()
- sleep(10) //One second.
-
-/datum/authority/branch/evacuation/proc/get_status_panel_eta()
- switch(evac_status)
- if(EVACUATION_STATUS_INITIATING)
- var/eta = EVACUATION_ESTIMATE_DEPARTURE
- . = "[(eta / 60) % 60]:[add_zero(num2text(eta % 60), 2)]"
- if(EVACUATION_STATUS_IN_PROGRESS) . = "NOW"
-
-// LIFEBOATS CORNER
-/datum/authority/branch/evacuation/proc/activate_lifeboats()
- for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks)
- var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked()
- if(lifeboat && lifeboat.available)
- lifeboat.status = LIFEBOAT_ACTIVE
- lifeboat_dock.open_dock()
-
-
-/datum/authority/branch/evacuation/proc/deactivate_lifeboats()
- for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks)
- var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked()
- if(lifeboat && lifeboat.available)
- lifeboat.status = LIFEBOAT_INACTIVE
-
-/datum/authority/branch/evacuation/proc/launch_lifeboats()
- for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks)
- var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked()
- if(lifeboat && lifeboat.available)
- lifeboat.evac_launch()
-
-//=========================================================================================
-//=========================================================================================
-//=====================================SELF DETRUCT========================================
-//=========================================================================================
-//=========================================================================================
-
-/datum/authority/branch/evacuation/proc/enable_self_destruct(force=0)
- if(force || (dest_status == NUKE_EXPLOSION_INACTIVE && !(flags_scuttle & FLAGS_SELF_DESTRUCT_DENY)))
- dest_status = NUKE_EXPLOSION_ACTIVE
- dest_master.lock_or_unlock()
- dest_started_at = world.time
- set_security_level(SEC_LEVEL_DELTA) //also activate Delta alert, to open the SD shutters.
- spawn(0)
- for(var/obj/structure/machinery/door/poddoor/shutters/almayer/D in machines)
- if(D.id == "sd_lockdown")
- D.open()
- return TRUE
-
-//Override is for admins bypassing normal player restrictions.
-/datum/authority/branch/evacuation/proc/cancel_self_destruct(override)
- if(dest_status == NUKE_EXPLOSION_ACTIVE)
- var/obj/structure/machinery/self_destruct/rod/I
- var/i
- for(i in EvacuationAuthority.dest_rods)
- I = i
- if(I.active_state == SELF_DESTRUCT_MACHINE_ARMED && !override)
- dest_master.state(SPAN_WARNING("WARNING: Unable to cancel detonation. Please disarm all control rods."))
- return FALSE
-
- dest_status = NUKE_EXPLOSION_INACTIVE
- dest_master.in_progress = 1
- dest_started_at = 0
- for(i in dest_rods)
- I = i
- if(I.active_state == SELF_DESTRUCT_MACHINE_ACTIVE || (I.active_state == SELF_DESTRUCT_MACHINE_ARMED && override)) I.lock_or_unlock(1)
- dest_master.lock_or_unlock(1)
- dest_index = 1
- ai_announcement("The emergency destruct system has been deactivated.", 'sound/AI/selfdestruct_deactivated.ogg')
- if(evac_status == EVACUATION_STATUS_STANDING_BY) //the evac has also been cancelled or was never started.
- set_security_level(SEC_LEVEL_RED, TRUE) //both SD and evac are inactive, lowering the security level.
- return TRUE
-
-/datum/authority/branch/evacuation/proc/initiate_self_destruct(override)
- if(dest_status < NUKE_EXPLOSION_IN_PROGRESS)
- var/obj/structure/machinery/self_destruct/rod/I
- var/i
- for(i in dest_rods)
- I = i
- if(I.active_state != SELF_DESTRUCT_MACHINE_ARMED && !override)
- dest_master.state(SPAN_WARNING("WARNING: Unable to trigger detonation. Please arm all control rods."))
- return FALSE
- dest_master.in_progress = !dest_master.in_progress
- for(i in EvacuationAuthority.dest_rods)
- I = i
- I.in_progress = 1
- ai_announcement("DANGER. DANGER. Self-destruct system activated. DANGER. DANGER. Self-destruct in progress. DANGER. DANGER.")
- trigger_self_destruct(,,override)
- return TRUE
-
-/datum/authority/branch/evacuation/proc/trigger_self_destruct(list/z_levels = SSmapping.levels_by_trait(ZTRAIT_MARINE_MAIN_SHIP), origin = dest_master, override = FALSE, end_type = NUKE_EXPLOSION_FINISHED, play_anim = TRUE, end_round = TRUE)
- set waitfor = 0
- if(dest_status < NUKE_EXPLOSION_IN_PROGRESS) //One more check for good measure, in case it's triggered through a bomb instead of the destruct mechanism/admin panel.
- dest_status = NUKE_EXPLOSION_IN_PROGRESS
- playsound(origin, 'sound/machines/Alarm.ogg', 75, 0, 30)
- world << pick('sound/theme/nuclear_detonation1.ogg','sound/theme/nuclear_detonation2.ogg')
-
- var/ship_status = 1
- for(var/i in z_levels)
- if(is_mainship_level(i))
- ship_status = 0 //Destroyed.
- break
-
- var/list/alive_mobs = list() //Everyone who will be destroyed on the zlevel(s).
- var/list/dead_mobs = list() //Everyone who only needs to see the cinematic.
- for(var/mob/current_mob as anything in GLOB.mob_list) //This only does something cool for the people about to die, but should prove pretty interesting.
- var/turf/current_turf = get_turf(current_mob)
- if(!current_mob || !current_mob.loc || !current_turf)
- continue //In case something changes when we sleep().
- if(current_mob.stat == DEAD)
- dead_mobs |= current_mob
- continue
- if(current_turf.z in z_levels)
- alive_mobs |= current_mob
- shake_camera(current_mob, 110, 4)
-
-
- sleep(100)
- /*Hardcoded for now, since this was never really used for anything else.
- Would ideally use a better system for showing cutscenes.*/
- var/atom/movable/screen/cinematic/explosion/C = new
-
- if(play_anim)
- for(var/mob/current_mob as anything in alive_mobs + dead_mobs)
- if(current_mob && current_mob.loc && current_mob.client)
- current_mob.client.add_to_screen(C) //They may have disconnected in the mean time.
-
- sleep(15) //Extra 1.5 seconds to look at the ship.
- flick(override ? "intro_override" : "intro_nuke", C)
- sleep(35)
- for(var/mob/current_mob in alive_mobs)
- if(current_mob && current_mob.loc) //Who knows, maybe they escaped, or don't exist anymore.
- var/turf/current_mob_turf = get_turf(current_mob)
- if(!current_mob_turf)
- continue
- if(current_mob_turf.z in z_levels)
- if(istype(current_mob.loc, /obj/structure/closet/secure_closet/freezer/fridge))
- continue
- current_mob.death(create_cause_data("nuclear explosion"))
- else
- if(play_anim)
- current_mob.client.remove_from_screen(C) //those who managed to escape the z level at last second shouldn't have their view obstructed.
- if(play_anim)
- flick(ship_status ? "ship_spared" : "ship_destroyed", C)
- C.icon_state = ship_status ? "summary_spared" : "summary_destroyed"
- world << sound('sound/effects/explosionfar.ogg')
-
- if(end_round)
- dest_status = end_type
-
- sleep(5)
- if(SSticker.mode)
- SSticker.mode.check_win()
-
- if(!SSticker.mode) //Just a safety, just in case a mode isn't running, somehow.
- to_world(SPAN_ROUNDBODY("Resetting in 30 seconds!"))
- sleep(300)
- log_game("Rebooting due to nuclear detonation.")
- world.Reboot()
- return TRUE
-
-/datum/authority/branch/evacuation/proc/process_self_destruct()
- set background = 1
-
- spawn while(dest_master && dest_master.loc && dest_master.active_state == SELF_DESTRUCT_MACHINE_ARMED && dest_status == NUKE_EXPLOSION_ACTIVE && dest_index <= dest_rods.len)
- var/obj/structure/machinery/self_destruct/rod/I = dest_rods[dest_index]
- if(world.time >= dest_cooldown + I.activate_time)
- I.lock_or_unlock() //Unlock it.
- if(++dest_index <= dest_rods.len)
- I = dest_rods[dest_index]//Start the next sequence.
- I.activate_time = world.time
- sleep(10) //Checks every second. Could integrate into another controller for better tracking.
-
-//Generic parent base for the self_destruct items.
-/obj/structure/machinery/self_destruct
- icon = 'icons/obj/structures/machinery/self_destruct.dmi'
- icon_state = "console_1"
- var/base_icon_state = "console"
- use_power = USE_POWER_NONE //Runs unpowered, may need to change later.
- density = FALSE
- anchored = TRUE //So it doesn't go anywhere.
- unslashable = TRUE
- unacidable = TRUE //Cannot C4 it either.
- mouse_opacity = FALSE //No need to click or interact with this initially.
- var/in_progress = 0 //Cannot interact with while it's doing something, like an animation.
- var/active_state = SELF_DESTRUCT_MACHINE_INACTIVE //What step of the process it's on.
-
-/obj/structure/machinery/self_destruct/Initialize(mapload, ...)
- . = ..()
- icon_state = "[base_icon_state]_1"
-
-/obj/structure/machinery/self_destruct/Destroy()
- . = ..()
- machines -= src
- operator = null
-
-/obj/structure/machinery/self_destruct/ex_act(severity)
- return FALSE
-
-/obj/structure/machinery/self_destruct/attack_hand()
- if(..() || in_progress)
- return FALSE //This check is backward, ugh.
- return TRUE
-
-//Add sounds.
-/obj/structure/machinery/self_destruct/proc/lock_or_unlock(lock)
- set waitfor = 0
- in_progress = 1
- flick("[base_icon_state]" + (lock? "_5" : "_2"),src)
- sleep(9)
- mouse_opacity = !mouse_opacity
- icon_state = "[base_icon_state]" + (lock? "_1" : "_3")
- in_progress = 0
- active_state = active_state > SELF_DESTRUCT_MACHINE_INACTIVE ? SELF_DESTRUCT_MACHINE_INACTIVE : SELF_DESTRUCT_MACHINE_ACTIVE
-
-/obj/structure/machinery/self_destruct/console
- name = "self-destruct control panel"
- icon_state = "console_1"
- base_icon_state = "console"
- req_one_access = list(ACCESS_MARINE_CO, ACCESS_MARINE_SENIOR)
-
-/obj/structure/machinery/self_destruct/console/Destroy()
- . = ..()
- EvacuationAuthority.dest_master = null
- EvacuationAuthority.dest_rods = null
-
-/obj/structure/machinery/self_destruct/console/lock_or_unlock(lock)
- playsound(src, 'sound/machines/hydraulics_1.ogg', 25, 1)
- ..()
-
-//TODO: Add sounds.
-/obj/structure/machinery/self_destruct/console/attack_hand(mob/user)
- if(inoperable())
- return
-
- tgui_interact(user)
-
-/obj/structure/machinery/self_destruct/console/tgui_interact(mob/user, datum/tgui/ui)
- ui = SStgui.try_update_ui(user, src, ui)
- if(!ui)
- ui = new(user, src, "SelfDestructConsole", name)
- ui.open()
-
-/obj/structure/machinery/sleep_console/ui_status(mob/user, datum/ui_state/state)
- . = ..()
- if(inoperable())
- return UI_CLOSE
-
-
-/obj/structure/machinery/self_destruct/console/ui_data(mob/user)
- var/list/data = list()
-
- data["dest_status"] = active_state
-
- return data
-
-/obj/structure/machinery/self_destruct/console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
- . = ..()
- if(.)
- return
-
- switch(action)
- if("dest_start")
- to_chat(usr, SPAN_NOTICE("You press a few keys on the panel."))
- to_chat(usr, SPAN_NOTICE("The system must be booting up the self-destruct sequence now."))
- playsound(src.loc, 'sound/items/rped.ogg', 25, TRUE)
- sleep(2 SECONDS)
- ai_announcement("Danger. The emergency destruct system is now activated. The ship will detonate in T-minus 20 minutes. Automatic detonation is unavailable. Manual detonation is required.", 'sound/AI/selfdestruct.ogg')
- active_state = SELF_DESTRUCT_MACHINE_ARMED //Arm it here so the process can execute it later.
- var/obj/structure/machinery/self_destruct/rod/I = EvacuationAuthority.dest_rods[EvacuationAuthority.dest_index]
- I.activate_time = world.time
- EvacuationAuthority.process_self_destruct()
- . = TRUE
-
- if("dest_trigger")
- EvacuationAuthority.initiate_self_destruct()
- . = TRUE
-
- if("dest_cancel")
- if(!allowed(usr))
- to_chat(usr, SPAN_WARNING("You don't have the necessary clearance to cancel the emergency destruct system!"))
- return
- EvacuationAuthority.cancel_self_destruct()
- . = TRUE
-
-/obj/structure/machinery/self_destruct/rod
- name = "self-destruct control rod"
- desc = "It is part of a complicated self-destruct sequence, but relatively simple to operate. Twist to arm or disarm."
- icon_state = "rod_1"
- base_icon_state = "rod"
- layer = BELOW_OBJ_LAYER
- var/activate_time
-
-/obj/structure/machinery/self_destruct/rod/Destroy()
- . = ..()
- if(EvacuationAuthority && EvacuationAuthority.dest_rods)
- EvacuationAuthority.dest_rods -= src
-
-/obj/structure/machinery/self_destruct/rod/lock_or_unlock(lock)
- playsound(src, 'sound/machines/hydraulics_2.ogg', 25, 1)
- ..()
- if(lock)
- activate_time = null
- density = FALSE
- layer = initial(layer)
- else
- density = TRUE
- layer = ABOVE_OBJ_LAYER
-
-/obj/structure/machinery/self_destruct/rod/attack_hand(mob/user)
- if(..())
- switch(active_state)
- if(SELF_DESTRUCT_MACHINE_ACTIVE)
- to_chat(user, SPAN_NOTICE("You twist and release the control rod, arming it."))
- playsound(src, 'sound/machines/switch.ogg', 25, 1)
- icon_state = "rod_4"
- active_state = SELF_DESTRUCT_MACHINE_ARMED
- if(SELF_DESTRUCT_MACHINE_ARMED)
- to_chat(user, SPAN_NOTICE("You twist and release the control rod, disarming it."))
- playsound(src, 'sound/machines/switch.ogg', 25, 1)
- icon_state = "rod_3"
- active_state = SELF_DESTRUCT_MACHINE_ACTIVE
- else to_chat(user, SPAN_WARNING("The control rod is not ready."))
diff --git a/code/game/gamemodes/colonialmarines/ai/colonialmarines_ai.dm b/code/game/gamemodes/colonialmarines/ai/colonialmarines_ai.dm
index 8d41f5282b..e15985db4d 100644
--- a/code/game/gamemodes/colonialmarines/ai/colonialmarines_ai.dm
+++ b/code/game/gamemodes/colonialmarines/ai/colonialmarines_ai.dm
@@ -33,16 +33,14 @@
return ..()
/datum/game_mode/colonialmarines/ai/pre_setup()
+ RegisterSignal(SSdcs, COMSIG_GLOB_XENO_SPAWN, PROC_REF(handle_xeno_spawn))
- //Hacky pre-setup shit since RoleAuthority sucks
- RoleAuthority.squads = list()
- RoleAuthority.squads_by_type = list()
- for(var/cycled_squad_type in squad_limit)
- var/datum/squad/cycled_squad = new cycled_squad_type()
- RoleAuthority.squads += cycled_squad
- RoleAuthority.squads_by_type[cycled_squad.type] = cycled_squad
+ for(var/datum/squad/squad in RoleAuthority.squads)
+ if(squad.type in squad_limit)
+ continue
- RegisterSignal(SSdcs, COMSIG_GLOB_XENO_SPAWN, PROC_REF(handle_xeno_spawn))
+ RoleAuthority.squads -= squad
+ RoleAuthority.squads_by_type -= squad.type
. = ..()
diff --git a/code/game/gamemodes/colonialmarines/colonialmarines.dm b/code/game/gamemodes/colonialmarines/colonialmarines.dm
index 62cea6b52d..8f0f4da2e1 100644
--- a/code/game/gamemodes/colonialmarines/colonialmarines.dm
+++ b/code/game/gamemodes/colonialmarines/colonialmarines.dm
@@ -294,29 +294,25 @@
if(SSticker.current_state != GAME_STATE_PLAYING)
return
- var/living_player_list[] = count_humans_and_xenos(EvacuationAuthority.get_affected_zlevels())
+ var/living_player_list[] = count_humans_and_xenos(get_affected_zlevels())
var/num_humans = living_player_list[1]
var/num_xenos = living_player_list[2]
if(force_end_at && world.time > force_end_at)
round_finished = MODE_INFESTATION_X_MINOR
- if(EvacuationAuthority.dest_status == NUKE_EXPLOSION_FINISHED)
- round_finished = MODE_GENERIC_DRAW_NUKE //Nuke went off, ending the round.
- if(EvacuationAuthority.dest_status == NUKE_EXPLOSION_GROUND_FINISHED)
- round_finished = MODE_INFESTATION_M_MINOR //Nuke went off, ending the round.
- if(EvacuationAuthority.dest_status < NUKE_EXPLOSION_IN_PROGRESS) //If the nuke ISN'T in progress. We do not want to end the round before it detonates.
- if(!num_humans && num_xenos) //No humans remain alive.
- round_finished = MODE_INFESTATION_X_MAJOR //Evacuation did not take place. Everyone died.
- else if(num_humans && !num_xenos)
- if(SSticker.mode && SSticker.mode.is_in_endgame)
- round_finished = MODE_INFESTATION_X_MINOR //Evacuation successfully took place.
- else
- SSticker.roundend_check_paused = TRUE
- round_finished = MODE_INFESTATION_M_MAJOR //Humans destroyed the xenomorphs.
- ares_conclude()
- addtimer(VARSET_CALLBACK(SSticker, roundend_check_paused, FALSE), MARINE_MAJOR_ROUND_END_DELAY)
- else if(!num_humans && !num_xenos)
- round_finished = MODE_INFESTATION_DRAW_DEATH //Both were somehow destroyed.
+
+ if(!num_humans && num_xenos) //No humans remain alive.
+ round_finished = MODE_INFESTATION_X_MAJOR //Evacuation did not take place. Everyone died.
+ else if(num_humans && !num_xenos)
+ if(SSticker.mode && SSticker.mode.is_in_endgame)
+ round_finished = MODE_INFESTATION_X_MINOR //Evacuation successfully took place.
+ else
+ SSticker.roundend_check_paused = TRUE
+ round_finished = MODE_INFESTATION_M_MAJOR //Humans destroyed the xenomorphs.
+ ares_conclude()
+ addtimer(VARSET_CALLBACK(SSticker, roundend_check_paused, FALSE), MARINE_MAJOR_ROUND_END_DELAY)
+ else if(!num_humans && !num_xenos)
+ round_finished = MODE_INFESTATION_DRAW_DEATH //Both were somehow destroyed.
/datum/game_mode/colonialmarines/check_queen_status(hivenumber)
set waitfor = 0
@@ -364,7 +360,7 @@
round_statistics.current_map.total_marine_victories++
round_statistics.current_map.total_marine_majors++
if(MODE_INFESTATION_X_MINOR)
- var/list/living_player_list = count_humans_and_xenos(EvacuationAuthority.get_affected_zlevels())
+ var/list/living_player_list = count_humans_and_xenos(get_affected_zlevels())
if(living_player_list[1] && !living_player_list[2]) // If Xeno Minor but Xenos are dead and Humans are alive, see which faction is the last standing
var/headcount = count_per_faction()
var/living = headcount["total_headcount"]
diff --git a/code/game/gamemodes/colonialmarines/whiskey_outpost.dm b/code/game/gamemodes/colonialmarines/whiskey_outpost.dm
index 2f46de7556..4484846cd7 100644
--- a/code/game/gamemodes/colonialmarines/whiskey_outpost.dm
+++ b/code/game/gamemodes/colonialmarines/whiskey_outpost.dm
@@ -152,9 +152,6 @@
spawn(0)
//Deleting Almayer, for performance!
SSitem_cleanup.delete_almayer()
- if(SSxenocon)
- //Don't need XENOCON
- SSxenocon.wait = 30 MINUTES
//PROCCESS
diff --git a/code/game/gamemodes/colonialmarines/xenovsxeno.dm b/code/game/gamemodes/colonialmarines/xenovsxeno.dm
index 5623295f19..a19c3e3582 100644
--- a/code/game/gamemodes/colonialmarines/xenovsxeno.dm
+++ b/code/game/gamemodes/colonialmarines/xenovsxeno.dm
@@ -79,9 +79,6 @@
spawn(0)
//Deleting Almayer, for performance!
SSitem_cleanup.delete_almayer()
- if(SSxenocon)
- //Don't need XENOCON
- SSxenocon.wait = 30 MINUTES
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
diff --git a/code/game/gamemodes/extended/infection.dm b/code/game/gamemodes/extended/infection.dm
index 04e0545361..a6b909022a 100644
--- a/code/game/gamemodes/extended/infection.dm
+++ b/code/game/gamemodes/extended/infection.dm
@@ -95,7 +95,7 @@
possible_survivors -= new_survivor //either we drafted a survivor, or we're skipping over someone, either or - remove them
/datum/game_mode/infection/check_win()
- var/living_player_list[] = count_humans_and_xenos(EvacuationAuthority.get_affected_zlevels())
+ var/list/living_player_list = count_humans_and_xenos(get_affected_zlevels())
var/num_humans = living_player_list[1]
var/zed = living_player_list[2]
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index f3c01c619b..823ba03f35 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -111,6 +111,10 @@ var/global/cas_tracking_id_increment = 0 //this var used to assign unique tracki
log_game("Server IP: [world.internet_address]:[world.port]")
return TRUE
+/datum/game_mode/proc/get_affected_zlevels()
+ if(is_in_endgame)
+ . = SSmapping.levels_by_any_trait(list(ZTRAIT_MARINE_MAIN_SHIP))
+ return
///process()
///Called by the gameticker
@@ -119,8 +123,7 @@ var/global/cas_tracking_id_increment = 0 //this var used to assign unique tracki
/datum/game_mode/proc/check_finished() //to be called by ticker
- if(EvacuationAuthority.dest_status == NUKE_EXPLOSION_FINISHED || EvacuationAuthority.dest_status == NUKE_EXPLOSION_GROUND_FINISHED )
- return TRUE
+ return
/datum/game_mode/proc/cleanup() //This is called when the round has ended but not the game, if any cleanup would be necessary in that case.
return
diff --git a/code/game/jobs/job/civilians/other/survivors.dm b/code/game/jobs/job/civilians/other/survivors.dm
index 747ec60d73..07598483b8 100644
--- a/code/game/jobs/job/civilians/other/survivors.dm
+++ b/code/game/jobs/job/civilians/other/survivors.dm
@@ -10,6 +10,8 @@
job_options = SURVIVOR_VARIANT_LIST
var/intro_text
var/story_text
+ /// Whether or not the survivor is an inherently hostile to marines.
+ var/hostile = FALSE
/datum/job/civilian/survivor/set_spawn_positions(count)
spawn_positions = Clamp((round(count * SURVIVOR_TO_TOTAL_SPAWN_RATIO)), 2, 8)
@@ -60,21 +62,29 @@
if(picked_spawner.story_text)
story_text = picked_spawner.story_text
-/datum/job/civilian/survivor/generate_entry_message(mob/living/carbon/human/H)
+ if(picked_spawner.hostile)
+ hostile = TRUE
+
+/datum/job/civilian/survivor/generate_entry_message(mob/living/carbon/human/survivor)
if(intro_text)
for(var/line in intro_text)
- to_chat(H, line)
+ to_chat(survivor, line)
else
- to_chat(H, "
You are a survivor!
")
- to_chat(H, SPAN_NOTICE(SSmapping.configs[GROUND_MAP].survivor_message))
- to_chat(H, SPAN_NOTICE("You are fully aware of the xenomorph threat and are able to use this knowledge as you see fit."))
- to_chat(H, SPAN_NOTICE("You are NOT aware of the marines or their intentions. "))
+ to_chat(survivor, "You are a survivor!
")
+ to_chat(survivor, SPAN_NOTICE(SSmapping.configs[GROUND_MAP].survivor_message))
+ to_chat(survivor, SPAN_NOTICE("You are fully aware of the xenomorph threat and are able to use this knowledge as you see fit."))
+ to_chat(survivor, SPAN_NOTICE("You are NOT aware of the marines or their intentions. "))
if(story_text)
- to_chat(H, story_text)
- H.mind.memory += story_text
+ to_chat(survivor, story_text)
+ survivor.mind.memory += story_text
+ else
+ tell_survivor_story(survivor)
+
+ if(hostile)
+ to_chat(survivor, SPAN_HIGHDANGER("You are HOSTILE to the USCM!"))
else
- tell_survivor_story(H)
+ to_chat(survivor, SPAN_XENOHIGHDANGER("You are NON-HOSTILE to the USCM!"))
/datum/job/civilian/survivor/proc/tell_survivor_story(mob/living/carbon/human/H)
var/list/survivor_story = list(
diff --git a/code/game/jobs/job/marine/squad_info.dm b/code/game/jobs/job/marine/squad_info.dm
index 6199c38c40..6a59ecf560 100644
--- a/code/game/jobs/job/marine/squad_info.dm
+++ b/code/game/jobs/job/marine/squad_info.dm
@@ -23,6 +23,7 @@
"primary" = primary_objective,
"secondary" = secondary_objective,
)
+ data["partial_squad_ref"] = copytext(REF(src), 2, 12)
return data
/datum/squad/proc/get_leadership(mob/user)
diff --git a/code/game/jobs/job/marine/squads.dm b/code/game/jobs/job/marine/squads.dm
index 23db6c1e8d..ad06315ba4 100644
--- a/code/game/jobs/job/marine/squads.dm
+++ b/code/game/jobs/job/marine/squads.dm
@@ -115,7 +115,6 @@
/datum/squad/marine
name = "Root"
- usable = TRUE
active = TRUE
faction = FACTION_MARINE
lead_icon = "leader"
@@ -128,6 +127,7 @@
radio_freq = ALPHA_FREQ
minimap_color = MINIMAP_SQUAD_ALPHA
use_stripe_overlay = FALSE
+ usable = TRUE
/datum/squad/marine/bravo
name = SQUAD_MARINE_2
@@ -210,6 +210,17 @@
roundstart = FALSE
locked = TRUE
+/datum/squad/marine/cbrn
+ name = SQUAD_CBRN
+ equipment_color = "#3B2A7B" //Chemical Corps Purple
+ chat_color = "#553EB2"
+ radio_freq = CBRN_FREQ
+ minimap_color = "#3B2A7B"
+
+ active = FALSE
+ roundstart = FALSE
+ locked = TRUE
+
//############################### UPP Squads
/datum/squad/upp
name = "Root"
@@ -295,6 +306,32 @@
RegisterSignal(SSdcs, COMSIG_GLOB_MODE_POSTSETUP, PROC_REF(setup_supply_drop_list))
+/datum/squad/marine/alpha/New()
+ . = ..()
+
+ RegisterSignal(SSdcs, COMSIG_GLOB_PLATOON_NAME_CHANGE, PROC_REF(rename_platoon))
+
+/datum/squad/marine/alpha/proc/rename_platoon(datum/source, new_name, old_name)
+ SIGNAL_HANDLER
+
+ name = new_name
+
+ for(var/mob/living/carbon/human/marine in marines_list)
+ if(!istype(marine.wear_id, /obj/item/card/id))
+ continue
+
+ var/obj/item/card/id/marine_card = marine.wear_id
+ var/datum/weakref/marine_card_registered = marine.wear_id.registered_ref
+
+ if(!istype(marine_card_registered))
+ continue
+
+ if(marine != marine_card_registered.resolve())
+ continue
+
+ marine_card.assignment = "[new_name] [marine.job]"
+ marine_card.name = "[marine_card.registered_name]'s ID Card ([marine_card.assignment])"
+
/datum/squad/proc/setup_supply_drop_list()
SIGNAL_HANDLER
@@ -715,6 +752,12 @@
if(fireteam == "SQ2")
H.wear_id.access += ACCESS_SQUAD_TWO
+ for(var/obj/item/device/radio/headset/cycled_headset in H)
+ if(!("Squad Sergeant" in cycled_headset.tracking_options))
+ continue
+
+ cycled_headset.locate_setting = cycled_headset.tracking_options["Squad Sergeant"]
+
/datum/squad/proc/unassign_fireteam(mob/living/carbon/human/H, upd_ui = TRUE)
fireteams[H.assigned_fireteam].Remove(H)
var/ft = H.assigned_fireteam
@@ -732,6 +775,12 @@
if(H.wear_id)
H.wear_id.access.Remove(ACCESS_SQUAD_ONE, ACCESS_SQUAD_TWO)
+ for(var/obj/item/device/radio/headset/cycled_headset in H)
+ if(!("Platoon Sergeant" in cycled_headset.tracking_options))
+ continue
+
+ cycled_headset.locate_setting = cycled_headset.tracking_options["Platoon Sergeant"]
+
/datum/squad/proc/assign_ft_leader(fireteam, mob/living/carbon/human/H, upd_ui = TRUE)
if(fireteam_leaders[fireteam])
unassign_ft_leader(fireteam, FALSE, FALSE)
@@ -743,6 +792,12 @@
if(H.stat == CONSCIOUS)
to_chat(H, FONT_SIZE_HUGE(SPAN_BLUE("You were assigned as [fireteam] Team Leader.")))
+ for(var/obj/item/device/radio/headset/cycled_headset in H)
+ if(!("Platoon Sergeant" in cycled_headset.tracking_options))
+ continue
+
+ cycled_headset.locate_setting = cycled_headset.tracking_options["Platoon Sergeant"]
+
/datum/squad/proc/unassign_ft_leader(fireteam, clear_group_id, upd_ui = TRUE)
if(!fireteam_leaders[fireteam])
return
diff --git a/code/game/jobs/role_authority.dm b/code/game/jobs/role_authority.dm
index 5aab13f68a..1e2e2ac6ed 100644
--- a/code/game/jobs/role_authority.dm
+++ b/code/game/jobs/role_authority.dm
@@ -524,9 +524,7 @@ I hope it's easier to tell what the heck this proc is even doing, unlike previou
new_human.sec_hud_set_ID()
new_human.hud_set_squad()
- for(var/obj/current_item in new_human.get_contents())
- SEND_SIGNAL(current_item, COMSIG_POST_SPAWN_UPDATE, new_human)
-
+ SEND_SIGNAL(new_human, COMSIG_POST_SPAWN_UPDATE)
SSround_recording.recorder.track_player(new_human)
//Find which squad has the least population. If all 4 squads are equal it should just use a random one
diff --git a/code/game/machinery/ARES/ARES_interface.dm b/code/game/machinery/ARES/ARES_interface.dm
index 64755897bc..0e45d5ee17 100644
--- a/code/game/machinery/ARES/ARES_interface.dm
+++ b/code/game/machinery/ARES/ARES_interface.dm
@@ -79,7 +79,7 @@
data["access_level"] = authentication
data["alert_level"] = security_level
- data["evac_status"] = EvacuationAuthority.evac_status
+ data["evac_status"] = SShijack.evac_status
data["worldtime"] = world.time
data["access_log"] = datacore.interface_access_list
@@ -397,12 +397,12 @@
playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
return FALSE
- if(EvacuationAuthority.flags_scuttle & FLAGS_EVACUATION_DENY)
+ if(SShijack.evac_admin_denied)
to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods."))
playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
return FALSE
- if(!EvacuationAuthority.initiate_evacuation())
+ if(!SShijack.initiate_evacuation())
to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!"))
playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
return FALSE
diff --git a/code/game/machinery/atmoalter/scrubber.dm b/code/game/machinery/atmoalter/scrubber.dm
index 0af38cacd7..1c240fb05d 100644
--- a/code/game/machinery/atmoalter/scrubber.dm
+++ b/code/game/machinery/atmoalter/scrubber.dm
@@ -18,16 +18,14 @@
PF.flags_can_pass_all = PASS_OVER|PASS_AROUND|PASS_UNDER
/obj/structure/machinery/portable_atmospherics/powered/scrubber/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
if(prob(50/severity))
on = !on
update_icon()
- ..(severity)
-
/obj/structure/machinery/portable_atmospherics/powered/scrubber/update_icon()
src.overlays = 0
diff --git a/code/game/machinery/bots/bots.dm b/code/game/machinery/bots/bots.dm
index 116753093f..912a607032 100644
--- a/code/game/machinery/bots/bots.dm
+++ b/code/game/machinery/bots/bots.dm
@@ -114,6 +114,7 @@
/obj/structure/machinery/bot/emp_act(severity)
+ . = ..()
var/was_on = on
stat |= EMPED
new /obj/effect/overlay/temp/emp_sparks (loc)
diff --git a/code/game/machinery/bots/mulebot.dm b/code/game/machinery/bots/mulebot.dm
index d82591994e..b88f824956 100644
--- a/code/game/machinery/bots/mulebot.dm
+++ b/code/game/machinery/bots/mulebot.dm
@@ -916,11 +916,11 @@
post_signal_multiple(control_freq, kv)
/obj/structure/machinery/bot/mulebot/emp_act(severity)
+ . = ..()
if (cell)
cell.emp_act(severity)
if(load)
load.emp_act(severity)
- ..()
/obj/structure/machinery/bot/mulebot/explode()
diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm
index ee83c430c2..8d4b27778c 100644
--- a/code/game/machinery/buttons.dm
+++ b/code/game/machinery/buttons.dm
@@ -1,15 +1,3 @@
-/obj/structure/machinery/driver_button
- name = "mass driver button"
- icon = 'icons/obj/objects.dmi'
- icon_state = "launcherbtt"
- desc = "A remote control switch for a mass driver."
- var/id = null
- var/active = 0
- anchored = TRUE
- use_power = USE_POWER_IDLE
- idle_power_usage = 2
- active_power_usage = 4
-
/obj/structure/machinery/ignition_switch
name = "ignition switch"
icon = 'icons/obj/objects.dmi'
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index d416c561fc..3b2a91eea3 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -35,6 +35,9 @@
var/colony_camera_mapload = TRUE
+ /// If this camera should have innate EMP-proofing
+ var/emp_proof = FALSE
+
/obj/structure/machinery/camera/Initialize(mapload, ...)
. = ..()
WireColorToFlag = randomCameraWires()
@@ -72,6 +75,7 @@
if(WEST) pixel_x = 27
/obj/structure/machinery/camera/emp_act(severity)
+ . = ..()
if(!isEmpProof())
if(prob(100/severity))
icon_state = "[initial(icon_state)]emp"
@@ -89,7 +93,6 @@
if(can_use())
cameranet.addCamera(src)
kick_viewers()
- ..()
/obj/structure/machinery/camera/ex_act(severity)
diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm
index b075808652..fc23282581 100644
--- a/code/game/machinery/camera/presets.dm
+++ b/code/game/machinery/camera/presets.dm
@@ -30,6 +30,7 @@
network = list(CAMERA_NET_LASER_TARGETS)
unslashable = TRUE
unacidable = TRUE
+ emp_proof = TRUE
/obj/structure/machinery/camera/laser_cam/Initialize(mapload, laser_name)
. = ..()
@@ -37,8 +38,6 @@
var/area/A = get_area(src)
c_tag = "[laser_name] ([A.name])"
-/obj/structure/machinery/camera/laser_cam/emp_act(severity)
- return //immune to EMPs, just in case
/obj/structure/machinery/camera/laser_cam/ex_act()
return
@@ -132,9 +131,7 @@
invisibility = 101 //fuck you init()
colony_camera_mapload = FALSE
-
-/obj/structure/machinery/camera/autoname/lz_camera/emp_act(severity)
- return //immune to EMPs, just in case
+ emp_proof = TRUE
/obj/structure/machinery/camera/autoname/lz_camera/ex_act()
return
@@ -144,7 +141,7 @@
/obj/structure/machinery/camera/proc/isEmpProof()
var/O = locate(/obj/item/stack/sheet/mineral/osmium) in assembly.upgrades
- return O
+ return O || emp_proof
/obj/structure/machinery/camera/proc/isXRay()
var/obj/item/stock_parts/scanning_module/O = locate(/obj/item/stock_parts/scanning_module) in assembly.upgrades
diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm
index fcd8c65e93..eb7a501fa0 100644
--- a/code/game/machinery/cell_charger.dm
+++ b/code/game/machinery/cell_charger.dm
@@ -80,11 +80,11 @@
return
/obj/structure/machinery/cell_charger/emp_act(severity)
+ . = ..()
if(inoperable())
return
if(charging)
charging.emp_act(severity)
- ..(severity)
/obj/structure/machinery/cell_charger/process()
diff --git a/code/game/machinery/computer/almayer_control.dm b/code/game/machinery/computer/almayer_control.dm
index 145d0d278c..fb9f7a0375 100644
--- a/code/game/machinery/computer/almayer_control.dm
+++ b/code/game/machinery/computer/almayer_control.dm
@@ -81,9 +81,9 @@
data["worldtime"] = world.time
- data["evac_status"] = EvacuationAuthority.evac_status
- if(EvacuationAuthority.evac_status == EVACUATION_STATUS_INITIATING)
- data["evac_eta"] = EvacuationAuthority.get_status_panel_eta()
+ data["evac_status"] = SShijack.evac_status
+ if(SShijack.evac_status == EVACUATION_STATUS_INITIATED)
+ data["evac_eta"] = SShijack.get_evac_eta()
if(!messagetitle.len)
data["messages"] = null
@@ -120,11 +120,11 @@
to_chat(usr, SPAN_WARNING("The ship must be under red alert in order to enact evacuation procedures."))
return FALSE
- if(EvacuationAuthority.flags_scuttle & FLAGS_EVACUATION_DENY)
+ if(SShijack.evac_admin_denied)
to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods."))
return FALSE
- if(!EvacuationAuthority.initiate_evacuation())
+ if(!SShijack.initiate_evacuation())
to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!"))
return FALSE
@@ -134,12 +134,10 @@
. = TRUE
if("evacuation_cancel")
- if(!EvacuationAuthority.cancel_evacuation())
+ if(!SShijack.cancel_evacuation())
to_chat(usr, SPAN_WARNING("You are unable to cancel the evacuation right now!"))
return FALSE
- addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/structure/machinery/computer/almayer_control, cancel_evac)), 4 SECONDS)
-
log_game("[key_name(usr)] has canceled the emergency evacuation.")
message_admins("[key_name_admin(usr)] has canceled the emergency evacuation.")
log_ares_security("Cancel Evacuation", "[usr] has cancelled the emergency evacuation.")
@@ -276,10 +274,3 @@
// end tgui interact \\
// end tgui \\
-
-/obj/structure/machinery/computer/almayer_control/proc/cancel_evac()
- if(EvacuationAuthority.evac_status == EVACUATION_STATUS_STANDING_BY)//nothing changed during the wait
- //if the self_destruct is active we try to cancel it (which includes lowering alert level to red)
- if(!EvacuationAuthority.cancel_self_destruct(1))
- //if SD wasn't active (likely canceled manually in the SD room), then we lower the alert level manually.
- set_security_level(SEC_LEVEL_RED, TRUE) //both SD and evac are inactive, lowering the security level.
diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm
index 8d35dd1b6a..1ac5a06738 100644
--- a/code/game/machinery/computer/arcade.dm
+++ b/code/game/machinery/computer/arcade.dm
@@ -165,8 +165,8 @@
return
/obj/structure/machinery/computer/arcade/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
var/empprize = null
var/num_of_prizes = 0
@@ -178,5 +178,3 @@
for(num_of_prizes; num_of_prizes > 0; num_of_prizes--)
empprize = pickweight(prizes)
new empprize(src.loc)
-
- ..(severity)
diff --git a/code/game/machinery/computer/camera_console.dm b/code/game/machinery/computer/camera_console.dm
index b5cfc856b0..b78f306162 100644
--- a/code/game/machinery/computer/camera_console.dm
+++ b/code/game/machinery/computer/camera_console.dm
@@ -354,8 +354,8 @@
exproof = TRUE
colony_camera_mapload = FALSE
-/obj/structure/machinery/computer/cameras/mortar/emp_act(severity)
- return FALSE
+/obj/structure/machinery/computer/cameras/mortar/set_broken()
+ return
/obj/structure/machinery/computer/cameras/dropship
name = "abstract dropship camera computer"
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
index d4d45de8db..3332577683 100644
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -138,11 +138,11 @@
to_chat(usr, SPAN_WARNING("The ship must be under delta alert in order to enact evacuation procedures."))
return FALSE
- if(EvacuationAuthority.flags_scuttle & FLAGS_EVACUATION_DENY)
+ if(SShijack.evac_admin_denied)
to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods."))
return FALSE
- if(!EvacuationAuthority.initiate_evacuation())
+ if(!SShijack.initiate_evacuation())
to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!"))
return FALSE
@@ -155,17 +155,10 @@
if("evacuation_cancel")
if(state == STATE_EVACUATION_CANCEL)
- if(!EvacuationAuthority.cancel_evacuation())
+ if(!SShijack.cancel_evacuation())
to_chat(usr, SPAN_WARNING("You are unable to cancel the evacuation right now!"))
return FALSE
- spawn(35)//some time between AI announcements for evac cancel and SD cancel.
- if(EvacuationAuthority.evac_status == EVACUATION_STATUS_STANDING_BY)//nothing changed during the wait
- //if the self_destruct is active we try to cancel it (which includes lowering alert level to red)
- if(!EvacuationAuthority.cancel_self_destruct(1))
- //if SD wasn't active (likely canceled manually in the SD room), then we lower the alert level manually.
- set_security_level(SEC_LEVEL_RED, TRUE) //both SD and evac are inactive, lowering the security level.
-
log_game("[key_name(usr)] has canceled the emergency evacuation.")
message_admins("[key_name_admin(usr)] has canceled the emergency evacuation.")
log_ares_security("Cancel Evacuation", "[usr] has cancelled the emergency evacuation.")
@@ -327,8 +320,8 @@
user.set_interaction(src)
var/dat = "Communications Console"
- if(EvacuationAuthority.evac_status == EVACUATION_STATUS_INITIATING)
- dat += "Evacuation in Progress\n
\nETA: [EvacuationAuthority.get_status_panel_eta()]
"
+ if(SShijack.evac_status == EVACUATION_STATUS_INITIATED)
+ dat += "Evacuation in Progress\n
\nETA: [SShijack.get_evac_eta()]
"
switch(state)
if(STATE_DEFAULT)
if(authenticated)
@@ -351,9 +344,11 @@
dat += "
Award a medal"
dat += "
Send Distress Beacon"
dat += "
Activate Self-Destruct"
- switch(EvacuationAuthority.evac_status)
- if(EVACUATION_STATUS_STANDING_BY) dat += "
Initiate emergency evacuation"
- if(EVACUATION_STATUS_INITIATING) dat += "
Cancel emergency evacuation"
+ switch(SShijack.evac_status)
+ if(EVACUATION_STATUS_NOT_INITIATED)
+ dat += "
Initiate emergency evacuation"
+ if(EVACUATION_STATUS_INITIATED)
+ dat += "
Cancel emergency evacuation"
else
dat += "
LOG IN"
@@ -408,20 +403,8 @@
if(STATE_ALERT_LEVEL)
dat += "Current alert level: [get_security_level()]
"
- if(security_level == SEC_LEVEL_DELTA)
- if(EvacuationAuthority.dest_status >= NUKE_EXPLOSION_ACTIVE)
- dat += SET_CLASS("The self-destruct mechanism is active. [EvacuationAuthority.evac_status != EVACUATION_STATUS_INITIATING ? "You have to manually deactivate the self-destruct mechanism." : ""]", INTERFACE_RED)
- dat += "
"
- switch(EvacuationAuthority.evac_status)
- if(EVACUATION_STATUS_INITIATING)
- dat += SET_CLASS("Evacuation initiated. Evacuate or rescind evacuation orders.", INTERFACE_RED)
- if(EVACUATION_STATUS_IN_PROGRESS)
- dat += SET_CLASS("Evacuation in progress.", INTERFACE_RED)
- if(EVACUATION_STATUS_COMPLETE)
- dat += SET_CLASS("Evacuation complete.", INTERFACE_RED)
- else
- dat += "Blue
"
- dat += "Green"
+ dat += "Blue
"
+ dat += "Green"
if(STATE_CONFIRM_LEVEL)
dat += "Current alert level: [get_security_level()]
"
diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm
index 304b24a14f..c335177962 100644
--- a/code/game/machinery/computer/computer.dm
+++ b/code/game/machinery/computer/computer.dm
@@ -31,8 +31,9 @@
return 1
/obj/structure/machinery/computer/emp_act(severity)
- if(prob(20/severity)) set_broken()
- ..()
+ . = ..()
+ if(prob(20/severity))
+ set_broken()
/obj/structure/machinery/computer/ex_act(severity)
diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm
index fe85599018..53efad3da8 100644
--- a/code/game/machinery/computer/medical.dm
+++ b/code/game/machinery/computer/medical.dm
@@ -483,8 +483,8 @@
return
/obj/structure/machinery/computer/med_data/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
for(var/datum/data/record/R as anything in GLOB.data_core.medical)
@@ -509,8 +509,6 @@
qdel(R)
continue
- ..(severity)
-
/obj/structure/machinery/computer/med_data/laptop
name = "Medical Laptop"
diff --git a/code/game/machinery/computer/pod.dm b/code/game/machinery/computer/pod.dm
index f6adaa8edd..7ec97874bb 100644
--- a/code/game/machinery/computer/pod.dm
+++ b/code/game/machinery/computer/pod.dm
@@ -1,158 +1,8 @@
-//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
-
-/obj/structure/machinery/computer/pod
- name = "Pod Launch Control"
- desc = "A control for launching pods. Some people prefer firing Mechas."
+// Legacy SS13 machinery turned into props
+/obj/structure/machinery/computer/pod/old
+ name = "DoorMex Control Computer"
+ desc = "A control for launching pods."
icon_state = "computer_generic"
density = TRUE
- circuit = /obj/item/circuitboard/computer/pod
- var/id = 1
- var/obj/structure/machinery/mass_driver/connected = null
- var/timing = 0
- var/time = 30
- var/title = "Mass Driver Controls"
+ circuit = /obj/item/circuitboard/computer/pod/old
processing = TRUE
-
-
-/obj/structure/machinery/computer/pod/New()
- ..()
- spawn( 5 )
- for(var/obj/structure/machinery/mass_driver/M in machines)
- if(M.id == id)
- connected = M
- return
- return
-
-
-/obj/structure/machinery/computer/pod/proc/alarm()
- if(inoperable())
- return
-
- if(!( connected ))
- to_chat(viewers(null, null), "Cannot locate mass driver connector. Cancelling firing sequence!")
- return
-
- for(var/obj/structure/machinery/door/poddoor/M in machines)
- if(M.id == id)
- M.open()
-
- sleep(20)
-
- for(var/obj/structure/machinery/mass_driver/M in machines)
- if(M.id == id)
- M.power = connected.power
- M.drive()
-
- sleep(50)
- for(var/obj/structure/machinery/door/poddoor/M in machines)
- if(M.id == id)
- M.close()
- return
- return
-
-/obj/structure/machinery/computer/pod/attack_remote(mob/user as mob)
- return attack_hand(user)
-
-/obj/structure/machinery/computer/pod/attack_hand(mob/user as mob)
- if(..())
- return
-
- var/dat = "[title]"
- user.set_interaction(src)
- if(connected)
- var/d2
- if(timing) //door controls do not need timers.
- d2 = "Stop Time Launch"
- else
- d2 = "Initiate Time Launch"
- var/second = time % 60
- var/minute = (time - second) / 60
- dat += "
\nTimer System: [d2]\nTime Left: [minute ? "[minute]:" : null][second] - - + +"
- var/temp = ""
- var/list/L = list( 0.25, 0.5, 1, 2, 4, 8, 16 )
- for(var/t in L)
- if(t == connected.power)
- temp += "[t] "
- else
- temp += "[t] "
- dat += "
\nPower Level: [temp]
\nFiring Sequence
\nTest Fire Driver
\nToggle Outer Door
"
- else
- dat += "
\nToggle Outer Door
"
- dat += "
Close"
- show_browser(user, dat, "computer", "size=400x500")
- add_fingerprint(usr)
- return
-
-
-/obj/structure/machinery/computer/pod/process()
- if(!..())
- return
- if(timing)
- if(time > 0)
- time = round(time) - 1
- else
- alarm()
- time = 0
- timing = 0
- updateDialog()
- return
-
-
-/obj/structure/machinery/computer/pod/Topic(href, href_list)
- if(..())
- return
- if((usr.contents.Find(src) || (in_range(src, usr) && istype(loc, /turf))) || (isRemoteControlling(usr)))
- usr.set_interaction(src)
- if(href_list["power"])
- var/t = text2num(href_list["power"])
- t = min(max(0.25, t), 16)
- if(connected)
- connected.power = t
- if(href_list["alarm"])
- alarm()
- if(href_list["drive"])
- for(var/obj/structure/machinery/mass_driver/M in machines)
- if(M.id == id)
- M.power = connected.power
- M.drive()
-
- if(href_list["time"])
- timing = text2num(href_list["time"])
- if(href_list["tp"])
- var/tp = text2num(href_list["tp"])
- time += tp
- time = min(max(round(time), 0), 120)
- if(href_list["door"])
- for(var/obj/structure/machinery/door/poddoor/M in machines)
- if(M.id == id)
- if(M.density)
- M.open()
- else
- M.close()
- updateUsrDialog()
- return
-
-
-
-/obj/structure/machinery/computer/pod/old
- name = "DoorMex Control Computer"
- title = "Door Controls"
-
-/obj/structure/machinery/computer/pod/old/syndicate
- name = "ProComp Executive IIc"
- desc = "The Syndicate operate on a tight budget. Operates external airlocks."
- icon_state = "syndicomp"
- title = "External Airlock Controls"
- req_access = list(ACCESS_ILLEGAL_PIRATE)
-
-/obj/structure/machinery/computer/pod/old/syndicate/attack_hand(mob/user as mob)
- if(!allowed(user))
- to_chat(user, SPAN_DANGER("Access Denied"))
- return
- else
- ..()
-
-/obj/structure/machinery/computer/pod/old/swf
- name = "Magix System IV"
- icon_state = "wizard"
- desc = "An arcane artifact that holds much magic. Running E-Knock 2.2: Sorceror's Edition"
diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm
index 8571189379..2d9a4a1dbe 100644
--- a/code/game/machinery/computer/security.dm
+++ b/code/game/machinery/computer/security.dm
@@ -524,8 +524,8 @@ What a mess.*/
return selection.fields["img"]
/obj/structure/machinery/computer/secure_data/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
for(var/datum/data/record/R in GLOB.data_core.security)
@@ -550,8 +550,6 @@ What a mess.*/
qdel(R)
continue
- ..(severity)
-
/obj/structure/machinery/computer/secure_data/detective_computer
icon = 'icons/obj/structures/machinery/computer.dmi'
icon_state = "messyfiles"
diff --git a/code/game/machinery/computer/skills.dm b/code/game/machinery/computer/skills.dm
index a20d344b53..60b5aa2329 100644
--- a/code/game/machinery/computer/skills.dm
+++ b/code/game/machinery/computer/skills.dm
@@ -347,8 +347,8 @@ What a mess.*/
return
/obj/structure/machinery/computer/skills/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
for(var/datum/data/record/R in GLOB.data_core.security)
@@ -373,4 +373,3 @@ What a mess.*/
qdel(R)
continue
- ..(severity)
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index e13b282cbc..cda3da5e2e 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -37,6 +37,16 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li
/obj/structure/machinery/computer/cryopod/alpha
cryotype = SQUAD_MARINE_1
+/obj/structure/machinery/computer/cryopod/alpha/Initialize()
+ . = ..()
+
+ RegisterSignal(SSdcs, COMSIG_GLOB_PLATOON_NAME_CHANGE, PROC_REF(rename_platoon))
+
+/obj/structure/machinery/computer/cryopod/alpha/proc/rename_platoon(datum/source, new_name, old_name)
+ SIGNAL_HANDLER
+
+ cryotype = new_name
+
/obj/structure/machinery/computer/cryopod/bravo
cryotype = SQUAD_MARINE_2
diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm
index 99996bea89..687882d9d7 100644
--- a/code/game/machinery/deployable.dm
+++ b/code/game/machinery/deployable.dm
@@ -65,6 +65,7 @@
return
/obj/structure/machinery/deployable/barrier/emp_act(severity)
+ . = ..()
if(inoperable())
return
if(prob(50/severity))
diff --git a/code/game/machinery/door_control.dm b/code/game/machinery/door_control.dm
index 8be8609d60..8b73588f1d 100644
--- a/code/game/machinery/door_control.dm
+++ b/code/game/machinery/door_control.dm
@@ -150,47 +150,6 @@
else
icon_state = initial(icon_state) + "0"
-/obj/structure/machinery/driver_button/attack_remote(mob/user as mob)
- return src.attack_hand(user)
-
-/obj/structure/machinery/driver_button/attackby(obj/item/W, mob/user as mob)
- return src.attack_hand(user)
-
-/obj/structure/machinery/driver_button/attack_hand(mob/user as mob)
-
- src.add_fingerprint(usr)
- if(inoperable())
- return
- if(active)
- return
- add_fingerprint(user)
-
- use_power(5)
-
- active = 1
- icon_state = "launcheract"
-
- for(var/obj/structure/machinery/door/poddoor/M in machines)
- if(M.id == src.id)
- INVOKE_ASYNC(M, TYPE_PROC_REF(/obj/structure/machinery/door, open))
-
- sleep(20)
-
- for(var/obj/structure/machinery/mass_driver/M in machines)
- if(M.id == src.id)
- M.drive()
-
- sleep(50)
-
- for(var/obj/structure/machinery/door/poddoor/M in machines)
- if(M.id == src.id)
- INVOKE_ASYNC(M, TYPE_PROC_REF(/obj/structure/machinery/door, close))
-
- icon_state = "launcherbtt"
- active = 0
-
- return
-
// Controls elevator railings
/obj/structure/machinery/door_control/railings
name = "railing controls"
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index b7257ff4e7..c6d9ddf3ef 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -866,3 +866,8 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list(
var/damage = xeno.melee_damage_upper * TAILSTAB_AIRLOCK_DAMAGE_MULTIPLIER
take_damage(damage, xeno)
return TAILSTAB_COOLDOWN_NORMAL
+
+/obj/structure/machinery/door/airlock/autoclose()
+ if(locked)
+ return
+ ..()
diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm
index b13138cd7c..7796ad74df 100644
--- a/code/game/machinery/doors/airlock_types.dm
+++ b/code/game/machinery/doors/airlock_types.dm
@@ -138,7 +138,6 @@
opacity = 0
assembly_type = /obj/structure/airlock_assembly/airlock_assembly_research
glass = 1
- heat_proof = 1
req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL)
/obj/structure/machinery/door/airlock/glass_mining/colony
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index a7d86d629b..99353a6688 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -1,4 +1,3 @@
-
/obj/structure/machinery/door
name = "\improper Door"
desc = "It opens and closes."
@@ -7,50 +6,43 @@
anchored = TRUE
opacity = TRUE
density = TRUE
- throwpass = 0
+ throwpass = FALSE
layer = DOOR_OPEN_LAYER
minimap_color = MINIMAP_DOOR
var/open_layer = DOOR_OPEN_LAYER
var/closed_layer = DOOR_CLOSED_LAYER
var/id = ""
+ var/width = 1
var/secondsElectrified = 0
- var/visible = 1
+ var/visible = TRUE
var/panel_open = FALSE
- var/operating = 0
- var/autoclose = 0
- var/glass = 0
- var/normalspeed = 1
- var/openspeed = 10 //How many seconds does it take to open it? Default 1 second. Use only if you have long door opening animations
- var/heat_proof = 0 // For glass airlocks/opacity firedoors
- var/air_properties_vary_with_direction = 0
- var/turf/filler //Fixes double door opacity issue
+ var/operating = FALSE
+ var/autoclose = FALSE
+ var/glass = FALSE
+ /// If FALSE it speeds up the autoclosing timing.
+ var/normalspeed = TRUE
+ /// Time to open/close airlock, default is 1 second.
+ var/openspeed = 1 SECONDS
+ /// Fixes multi_tile doors opacity issues.
+ var/list/filler_turfs = list() //Previously this was just var, because no one had forseen someone creating doors more than 2 tiles wide
/// Stops it being forced open through normal means (Hunters/Zombies/Aliens).
var/heavy = FALSE
/// Resistance to masterkey
var/masterkey_resist = FALSE
var/masterkey_mod = 0.1
-
-
- //Multi-tile doors
- dir = EAST
- var/width = 1
+ dir = EAST //So multitile doors are directioned properly
/obj/structure/machinery/door/Initialize(mapload, ...)
. = ..()
- if(density)
- layer = closed_layer
- update_flags_heat_protection(get_turf(src))
- else
- layer = open_layer
-
+ layer = density ? closed_layer : open_layer
handle_multidoor()
/obj/structure/machinery/door/Destroy()
. = ..()
- if(filler && width > 1)
- filler.set_opacity(0)// Ehh... let's hope there are no walls there. Must fix this
- filler = null
+ if(length(filler_turfs) && width > 1)
+ change_filler_opacity(0) // It still doesn't check for walls, might want to add checking that in the future
+ filler_turfs = null
density = FALSE
/obj/structure/machinery/door/initialize_pass_flags(datum/pass_flags_container/PF)
@@ -58,21 +50,41 @@
if (PF)
PF.flags_can_pass_all = NONE
+/// Also refreshes filler_turfs list.
+/obj/structure/machinery/door/proc/change_filler_opacity(new_opacity)
+ // I have no idea why do we null opacity first before... changing it
+ for(var/turf/filler_turf as anything in filler_turfs)
+ filler_turf.set_opacity(null)
+
+ filler_turfs = list()
+ for(var/turf/filler as anything in locate_filler_turfs())
+ filler.set_opacity(new_opacity)
+ filler_turfs += filler
+
+/// Updates collision box and opacity of multi_tile airlocks.
/obj/structure/machinery/door/proc/handle_multidoor()
if(width > 1)
if(dir in list(EAST, WEST))
bound_width = width * world.icon_size
bound_height = world.icon_size
- filler = get_step(src,EAST)
- filler.set_opacity(opacity)
else
bound_width = world.icon_size
bound_height = width * world.icon_size
- filler = get_step(src,NORTH)
- filler.set_opacity(opacity)
+ change_filler_opacity(opacity)
+
+/// Finds turfs which should be filler ones.
+/obj/structure/machinery/door/proc/locate_filler_turfs()
+ var/turf/filler_temp
+ var/list/located_turfs = list()
-//process()
- //return
+ for(var/i in 1 to width - 1)
+ if (dir in list(EAST, WEST))
+ filler_temp = locate(x + i, y, z)
+ else
+ filler_temp = locate(x, y + i, z)
+ if (filler_temp)
+ located_turfs += filler_temp
+ return located_turfs
/obj/structure/machinery/door/proc/borders_space()
for(var/turf/target in range(1, src))
@@ -81,7 +93,8 @@
return FALSE
/obj/structure/machinery/door/Collided(atom/movable/AM)
- if(panel_open || operating) return
+ if(panel_open || operating)
+ return
if(ismob(AM))
var/mob/M = AM
if(world.time - M.last_bumped <= openspeed) return //Can bump-open one airlock per second. This is to prevent shock spam.
@@ -89,12 +102,10 @@
if(!M.is_mob_restrained() && M.mob_size > MOB_SIZE_SMALL)
bumpopen(M)
return
-
if(istype(AM, /obj))
var/obj/O = AM
if(O.buckled_mob)
Collided(O.buckled_mob)
-
if(istype(AM, /obj/structure/machinery/bot))
var/obj/structure/machinery/bot/bot = AM
if(src.check_access(bot.botcard))
@@ -102,16 +113,17 @@
open()
return
-
/obj/structure/machinery/door/proc/bumpopen(mob/user as mob)
- if(operating) return
- src.add_fingerprint(user)
- if(!src.requiresID())
+ if(operating)
+ return
+ add_fingerprint(user)
+ if(!requiresID())
user = null
-
if(density)
- if(allowed(user)) open()
- else flick("door_deny", src)
+ if(allowed(user))
+ open()
+ else
+ flick("door_deny", src)
return
/obj/structure/machinery/door/attack_remote(mob/user)
@@ -124,9 +136,7 @@
add_fingerprint(user)
if(operating)
return
- if(!Adjacent(user))
- user = null //so allowed(user) always succeeds
- if(!requiresID())
+ if(!Adjacent(user) || !requiresID())
user = null //so allowed(user) always succeeds
if(allowed(user))
if(density)
@@ -137,64 +147,56 @@
if(density)
flick("door_deny", src)
-
/obj/structure/machinery/door/attackby(obj/item/I, mob/user)
if(!(I.flags_item & NOBLUDGEON))
try_to_activate_door(user)
- return 1
+ return TRUE
/obj/structure/machinery/door/emp_act(severity)
- if(prob(20/severity) && (istype(src,/obj/structure/machinery/door/airlock) || istype(src,/obj/structure/machinery/door/window)) )
+ . = ..()
+ if(prob(20/severity) && use_power)
open()
if(prob(40/severity))
if(secondsElectrified == 0)
secondsElectrified = -1
spawn(30 SECONDS)
secondsElectrified = 0
- ..()
-
/obj/structure/machinery/door/ex_act(severity)
- if(unacidable) return
+ if(unacidable)
+ return
if(density)
switch(severity)
if(0 to EXPLOSION_THRESHOLD_LOW)
if(prob(80))
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
- s.set_up(2, 1, src)
- s.start()
+ var/datum/effect_system/spark_spread/spark = new /datum/effect_system/spark_spread
+ spark.set_up(2, 1, src)
+ spark.start()
if(EXPLOSION_THRESHOLD_LOW to INFINITY)
qdel(src)
else
switch(severity)
if(0 to EXPLOSION_THRESHOLD_MEDIUM)
if(prob(80))
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
- s.set_up(2, 1, src)
- s.start()
+ var/datum/effect_system/spark_spread/spark = new /datum/effect_system/spark_spread
+ spark.set_up(2, 1, src)
+ spark.start()
else
qdel(src)
return
-
/obj/structure/machinery/door/get_explosion_resistance()
if(density)
if(unacidable)
- return 1000000
+ return 1000000 //Used for negation of explosions, should probably be made into define in the future
else
return EXPLOSION_THRESHOLD_LOW //this should exactly match the amount of damage needed to destroy the door
else
return 0
-
/obj/structure/machinery/door/update_icon()
- if(density)
- icon_state = "door1"
- else
- icon_state = "door0"
- return
-
+ icon_state = density ? "door1" : "door0"
/obj/structure/machinery/door/proc/do_animate(animation)
switch(animation)
@@ -212,7 +214,6 @@
flick("door_deny", src)
return
-
/obj/structure/machinery/door/proc/open(forced=0)
if(!density)
return TRUE
@@ -223,8 +224,8 @@
do_animate("opening")
icon_state = "door0"
set_opacity(FALSE)
- if(filler)
- filler.set_opacity(opacity)
+ if(length(filler_turfs))
+ change_filler_opacity(opacity)
addtimer(CALLBACK(src, PROC_REF(finish_open)), openspeed)
return TRUE
@@ -235,11 +236,9 @@
if(operating)
operating = FALSE
-
if(autoclose)
addtimer(CALLBACK(src, PROC_REF(autoclose)), normalspeed ? 150 + openspeed : 5)
-
/obj/structure/machinery/door/proc/close()
if(density)
return TRUE
@@ -256,22 +255,19 @@
update_icon()
if(visible && !glass)
set_opacity(TRUE)
- if(filler)
- filler.set_opacity(opacity)
+ if(length(filler_turfs))
+ change_filler_opacity(opacity)
operating = FALSE
/obj/structure/machinery/door/proc/requiresID()
return TRUE
-
-/obj/structure/machinery/door/proc/update_flags_heat_protection(turf/source)
-
-
+/// Used for overriding in airlocks
/obj/structure/machinery/door/proc/autoclose()
- var/obj/structure/machinery/door/airlock/A = src
- if(!A.density && !A.operating && !A.locked && !A.welded && A.autoclose)
+ if(!autoclose)
+ return
+ if(!density && !operating)
close()
- return
/obj/structure/machinery/door/Move(new_loc, new_dir)
. = ..()
@@ -279,15 +275,10 @@
if(dir in list(EAST, WEST))
bound_width = width * world.icon_size
bound_height = world.icon_size
- filler.set_opacity(0)
- filler = (get_step(src,EAST)) //Find new turf
- filler.set_opacity(opacity)
else
bound_width = world.icon_size
bound_height = width * world.icon_size
- filler.set_opacity(0)
- filler = (get_step(src,NORTH)) //Find new turf
- filler.set_opacity(opacity)
+ change_filler_opacity(opacity)
/obj/structure/machinery/door/attack_animal(mob/living/user)
. = ..()
@@ -318,6 +309,10 @@
return TRUE
+/obj/structure/machinery/door/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
+ . = ..()
+ // Yes, for a split second after departure you can see through rear dropship airlocks, but it's the simplest solution I could've think of
+ handle_multidoor()
/obj/structure/machinery/door/morgue
icon = 'icons/obj/structures/doors/doormorgue.dmi'
diff --git a/code/game/machinery/doors/multi_tile.dm b/code/game/machinery/doors/multi_tile.dm
index 65ecd67a43..ca21812816 100644
--- a/code/game/machinery/doors/multi_tile.dm
+++ b/code/game/machinery/doors/multi_tile.dm
@@ -13,7 +13,6 @@
/obj/structure/machinery/door/airlock/multi_tile/Initialize()
. = ..()
- handle_multidoor()
update_icon()
/obj/structure/machinery/door/airlock/multi_tile/glass
@@ -137,7 +136,6 @@
/obj/structure/window/framed/almayer,
/obj/structure/machinery/door/airlock,
)
- var/multi_filler = list()
/obj/structure/machinery/door/airlock/multi_tile/almayer/Initialize()
. = ..()
@@ -233,42 +231,6 @@
req_access = null
req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL)
-/obj/structure/machinery/door/airlock/multi_tile/almayer/handle_multidoor()
- . = ..()
- if(!(width > 1)) return //Bubblewrap
-
- update_filler_turfs()
-
-//We have to find these again since these doors are used on shuttles a lot so the turfs changes
-/obj/structure/machinery/door/airlock/multi_tile/almayer/proc/update_filler_turfs()
- for(var/turf/T in multi_filler)
- T.set_opacity(null)
-
- multi_filler = list()
- for(var/turf/T in get_filler_turfs())
- T.set_opacity(opacity)
- multi_filler += list(T)
-
-/obj/structure/machinery/door/airlock/multi_tile/proc/get_filler_turfs()
- . = list()
- for(var/i = 1, i < width, i++)
- if(dir in list(NORTH, SOUTH))
- var/turf/T = locate(x, y + i, z)
- if(T)
- . += list(T)
- else if(dir in list(EAST, WEST))
- var/turf/T = locate(x + i, y, z)
- if(T)
- . += list(T)
-
-/obj/structure/machinery/door/airlock/multi_tile/almayer/open()
- . = ..()
- update_filler_turfs()
-
-/obj/structure/machinery/door/airlock/multi_tile/almayer/close()
- . = ..()
- update_filler_turfs()
-
//------Dropship Cargo Doors -----//
/obj/structure/machinery/door/airlock/multi_tile/almayer/dropshiprear
diff --git a/code/game/machinery/doors/poddoor.dm b/code/game/machinery/doors/poddoor.dm
index 5a4fee7f23..d5e39ed79c 100644
--- a/code/game/machinery/doors/poddoor.dm
+++ b/code/game/machinery/doors/poddoor.dm
@@ -279,7 +279,7 @@
/obj/structure/machinery/door/poddoor/almayer
icon = 'icons/obj/structures/doors/blastdoors_shutters.dmi'
openspeed = 4 //shorter open animation.
- var/vehicle_resistant = FALSE
+ var/vehicle_resistant = TRUE
tiles_with = list(
/obj/structure/window/framed/almayer,
/obj/structure/machinery/door/airlock,
@@ -287,14 +287,18 @@
/obj/structure/machinery/door/poddoor/almayer/open
density = FALSE
+
/obj/structure/machinery/door/poddoor/almayer/blended
icon_state = "almayer_pdoor1"
base_icon_state = "almayer_pdoor"
+
/obj/structure/machinery/door/poddoor/almayer/blended/open
density = FALSE
+
/obj/structure/machinery/door/poddoor/almayer/blended/white
icon_state = "w_almayer_pdoor1"
base_icon_state = "w_almayer_pdoor"
+
/obj/structure/machinery/door/poddoor/almayer/blended/white/open
density = FALSE
@@ -318,4 +322,3 @@
/obj/structure/machinery/door/poddoor/almayer/planet_side_blastdoor
density = TRUE
opacity = TRUE
- vehicle_resistant = TRUE
diff --git a/code/game/machinery/doors/runed_sandstone.dm b/code/game/machinery/doors/runed_sandstone.dm
index 4bf66dfdc8..a6de7348dd 100644
--- a/code/game/machinery/doors/runed_sandstone.dm
+++ b/code/game/machinery/doors/runed_sandstone.dm
@@ -110,8 +110,8 @@
density = FALSE
update_icon()
set_opacity(0)
- if(filler)
- filler.set_opacity(opacity)
+ if(length(filler_turfs))
+ change_filler_opacity(opacity)
if(operating)
operating = FALSE
diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm
index 2b57fbd0a4..bd544c5c3f 100644
--- a/code/game/machinery/doors/windowdoor.dm
+++ b/code/game/machinery/doors/windowdoor.dm
@@ -11,7 +11,6 @@
flags_atom = ON_BORDER
opacity = FALSE
var/obj/item/circuitboard/airlock/electronics = null
- air_properties_vary_with_direction = 1
/obj/structure/machinery/door/window/Initialize()
. = ..()
diff --git a/code/game/machinery/fax_machine.dm b/code/game/machinery/fax_machine.dm
index 7bbc86681e..ff21671ed7 100644
--- a/code/game/machinery/fax_machine.dm
+++ b/code/game/machinery/fax_machine.dm
@@ -6,6 +6,7 @@ var/list/alldepartments = list()
#define DEPARTMENT_CMB "CMB Incident Command Center, Local Operations"
#define DEPARTMENT_PROVOST "USCM Provost Office"
#define DEPARTMENT_PRESS "Various Press Organizations"
+#define HIGHCOM_DEPARTMENTS list(DEPARTMENT_WY, DEPARTMENT_HC, DEPARTMENT_CMB, DEPARTMENT_PROVOST, DEPARTMENT_PRESS)
/obj/structure/machinery/faxmachine // why not fax_machine?
name = "\improper General Purpose Fax Machine"
@@ -319,10 +320,14 @@ var/list/alldepartments = list()
GLOB.fax_contents += faxcontents
+ var/scan_department = target_department
+ if(department in HIGHCOM_DEPARTMENTS)
+ scan_department = department
+
var/msg_admin = SPAN_STAFF_IC("[target_department]: [key_name(user, 1)] ")
msg_admin += "[CC_MARK(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_JMP_USER(user)] "
- switch(target_department)
+ switch(scan_department)
if(DEPARTMENT_HC)
GLOB.USCMFaxes.Add("\['[original_fax.name]' from [key_name(usr)], [scan] at [time2text(world.timeofday, "hh:mm:ss")]\] REPLY")
msg_admin += "(RPLY): "
diff --git a/code/game/machinery/fire_alarm.dm b/code/game/machinery/fire_alarm.dm
index fe1f80646c..dd7e0ee701 100644
--- a/code/game/machinery/fire_alarm.dm
+++ b/code/game/machinery/fire_alarm.dm
@@ -63,8 +63,9 @@ FIRE ALARM
return src.alarm()
/obj/structure/machinery/firealarm/emp_act(severity)
- if(prob(50/severity)) alarm()
- ..()
+ . = ..()
+ if(prob(50/severity))
+ alarm()
/obj/structure/machinery/firealarm/attackby(obj/item/held_object as obj, mob/user as mob)
src.add_fingerprint(user)
diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm
index 75d0de56de..cd59862a2e 100644
--- a/code/game/machinery/flasher.dm
+++ b/code/game/machinery/flasher.dm
@@ -84,12 +84,11 @@
/obj/structure/machinery/flasher/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
if(prob(75/severity))
flash()
- ..(severity)
/obj/structure/machinery/flasher/portable/HasProximity(atom/movable/AM as mob|obj)
if ((src.disable) || (src.last_flash && world.time < src.last_flash + 150))
diff --git a/code/game/machinery/fusion_engine.dm b/code/game/machinery/fusion_engine.dm
index 4158727e37..8e3097ef52 100644
--- a/code/game/machinery/fusion_engine.dm
+++ b/code/game/machinery/fusion_engine.dm
@@ -15,6 +15,7 @@
unacidable = TRUE //NOPE.jpg
anchored = TRUE
density = TRUE
+ power_machine = TRUE
var/power_gen_percent = 0 //50,000W at full capacity
var/buildstate = 0 //What state of building it are we on, 0-3, 1 is "broken", the default
@@ -24,7 +25,8 @@
var/obj/item/fuelCell/fusion_cell = new //Starts with a fuel cell loaded in. Maybe replace with the plasma tanks in the future and have it consume plasma? Possibly remove this later if it's irrelevent...
var/fuel_rate = 0 //Rate at which fuel is used. Based mostly on how long the generator has been running.
- power_machine = TRUE
+ /// If the generator is overloaded. Only possible during hijack once fuel is at 100%.
+ var/overloaded = FALSE
/obj/structure/machinery/power/fusion_engine/Initialize(mapload, ...)
. = ..()
@@ -35,11 +37,25 @@
/obj/structure/machinery/power/fusion_engine/Destroy()
QDEL_NULL(fusion_cell)
- . = ..()
+ return ..()
+/obj/structure/machinery/power/fusion_engine/attack_alien(mob/living/carbon/xenomorph/xeno)
+ if(!overloaded)
+ to_chat(xeno, SPAN_WARNING("You see no reason to attack [src]."))
+ return XENO_NO_DELAY_ACTION
+
+ xeno.animation_attack_on(src)
+ playsound(src, 'sound/effects/metalhit.ogg', 25, 1)
+ xeno.visible_message(SPAN_DANGER("[xeno] [xeno.slashes_verb] [src], stopping its overload process!"), \
+ SPAN_DANGER("You [xeno.slash_verb] [src], stopping its overload process!"), null, 5, CHAT_TYPE_XENO_COMBAT)
+ set_overloading(FALSE)
+ return XENO_ATTACK_ACTION
/obj/structure/machinery/power/fusion_engine/power_change()
- return
+ . = ..()
+ if(overloaded)
+ set_overloading(FALSE)
+ visible_message("[icon2html(src, viewers(src))] [src]'s overload suddenly ceases as primary power is lost.")
/obj/structure/machinery/power/fusion_engine/process()
if(!is_on || buildstate || !anchored || !powernet || !fusion_cell) //Default logic checking
@@ -60,9 +76,18 @@
stop_processing()
return FALSE
- if(!check_failure())
+ if(overloaded && prob(1)) // up to 18 generators at 1% every 3.5 seconds means that every ~21 seconds or so, one generator will make noise assuming all are overloaded
+ switch(rand(1, 2))
+ if(1)
+ visible_message("[icon2html(src, viewers(src))] [SPAN_NOTICE("[src] loudly hums.")]")
+ playsound(src, 'sound/machines/resource_node/node_idle.ogg', 60, TRUE)
+ if(2)
+ visible_message("[icon2html(src, viewers(src))] [SPAN_NOTICE("[src] makes a worrying hiss.")]")
+ playsound(src, 'sound/machines/hiss.ogg', 60, TRUE)
- if(power_gen_percent < 100) power_gen_percent++
+ if(!check_failure())
+ if(power_gen_percent < 100)
+ power_gen_percent++
switch(power_gen_percent) //Flavor text!
if(10)
@@ -96,6 +121,10 @@
to_chat(user, SPAN_NOTICE("Use a wrench to repair it."))
return FALSE
if(is_on)
+ if(overloaded)
+ to_chat(user, SPAN_WARNING("You can't shut off [src] while it's overloaded!"))
+ return
+
visible_message("[icon2html(src, viewers(src))] [SPAN_WARNING("[src] beeps softly and the humming stops as [usr] shuts off the generator.")]")
is_on = 0
power_gen_percent = 0
@@ -208,11 +237,18 @@
if(buildstate)
to_chat(user, SPAN_WARNING("You must repair the generator before working with its fuel cell."))
return
+
+ if(overloaded)
+ to_chat(user, SPAN_WARNING("You must restore the safeties on the generator before working with its fuel cell."))
+ return
+
if(is_on)
to_chat(user, SPAN_WARNING("You must turn off the generator before working with its fuel cell."))
return
+
if(!fusion_cell)
to_chat(user, SPAN_WARNING("There is no cell to remove."))
+
else
if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI))
user.visible_message(SPAN_WARNING("[user] fumbles around figuring out [src]'s fuel receptacle."),
@@ -232,23 +268,73 @@
fusion_cell = null
update_icon()
return TRUE
+
+ else if(HAS_TRAIT(O, TRAIT_TOOL_MULTITOOL))
+ if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI))
+ to_chat(user, SPAN_WARNING("You have no idea what to do with [src]."))
+ return
+
+ if(!overloaded)
+ if(!SShijack.sd_unlocked)
+ to_chat(user, SPAN_WARNING("You consider overloading [src]'s safeties, but you decide against it."))
+ return
+
+ if(inoperable())
+ to_chat(user, SPAN_WARNING("[src] needs to be working and have external power in order to overload it!"))
+ return
+
+ to_chat(user, SPAN_WARNING("You start overloading the safeties on [src]..."))
+ if(!do_after(user, 1.5 SECONDS, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
+ return
+
+ if(inoperable())
+ return
+
+ to_chat(user, SPAN_WARNING("You finish overloading the safeties on [src]."))
+ set_overloading(TRUE)
+ log_game("[key_name(user)] has overloaded a generator.")
+
+ else
+ to_chat(user, SPAN_WARNING("You start restoring the safeties on [src]..."))
+ if(!do_after(user, 1.5 SECONDS, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
+ return
+
+ if(inoperable())
+ return
+
+ to_chat(user, SPAN_WARNING("You finish restoring the safeties on [src]."))
+ log_game("[key_name(user)] has restored the safeties of a generator.")
+ set_overloading(FALSE)
+
+ return TRUE
+
else
return ..()
/obj/structure/machinery/power/fusion_engine/get_examine_text(mob/user)
. = ..()
- if(ishuman(user))
+ if(isxeno(user))
+ if(overloaded)
+ . += SPAN_INFO("You could attack this to stop the overload process.")
+
+ else if(ishuman(user))
if(buildstate)
. += SPAN_INFO("It's broken.")
switch(buildstate)
if(1)
- . += SPAN_INFO("Use a blowtorch, then wirecutters, then wrench to repair it.")
+ . += SPAN_INFO("Use a blowtorch, then wirecutters, then wrench to repair it.")
if(2)
- . += SPAN_INFO("Use a wirecutters, then wrench to repair it.")
+ . += SPAN_INFO("Use a wirecutters, then wrench to repair it.")
if(3)
- . += SPAN_INFO("Use a wrench to repair it.")
+ . += SPAN_INFO("Use a wrench to repair it.")
return FALSE
+ if(SShijack.sd_unlocked && skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI))
+ if(!overloaded)
+ . += SPAN_INFO("You could overload this with a multitool.")
+ else
+ . += SPAN_INFO("You could restore its safeties with a multitool.")
+
if(!is_on)
. += SPAN_INFO("It looks offline.")
else
@@ -274,18 +360,21 @@
switch(buildstate)
if(0)
if(fusion_cell)
- var/pstatus = is_on ? "on" : "off"
- switch(fusion_cell.get_fuel_percent())
- if(0 to 10)
- icon_state = "[pstatus]-10"
- if(10 to 25)
- icon_state = "[pstatus]-25"
- if(25 to 50)
- icon_state = "[pstatus]-50"
- if(50 to 75)
- icon_state = "[pstatus]-75"
- if(75 to INFINITY)
- icon_state = "[pstatus]-100"
+ if(overloaded)
+ icon_state = "overloaded"
+ else
+ var/pstatus = is_on ? "on" : "off"
+ switch(fusion_cell.get_fuel_percent())
+ if(0 to 10)
+ icon_state = "[pstatus]-10"
+ if(10 to 25)
+ icon_state = "[pstatus]-25"
+ if(25 to 50)
+ icon_state = "[pstatus]-50"
+ if(50 to 75)
+ icon_state = "[pstatus]-75"
+ if(75 to INFINITY)
+ icon_state = "[pstatus]-100"
else
icon_state = "off"
@@ -317,9 +406,13 @@
else
return 0
+/obj/structure/machinery/power/fusion_engine/proc/set_overloading(new_overloading)
+ if(overloaded == new_overloading)
+ return
-
-
+ overloaded = new_overloading
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_GENERATOR_SET_OVERLOADING, overloaded)
+ update_icon()
diff --git a/code/game/machinery/igniter.dm b/code/game/machinery/igniter.dm
index 33f75c50e3..d5a0505fca 100644
--- a/code/game/machinery/igniter.dm
+++ b/code/game/machinery/igniter.dm
@@ -105,11 +105,10 @@
return 1
/obj/structure/machinery/sparker/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
ignite()
- ..(severity)
/obj/structure/machinery/ignition_switch/attack_remote(mob/user as mob)
return attack_hand(user)
diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm
index 66eb038671..de61830c25 100644
--- a/code/game/machinery/lightswitch.dm
+++ b/code/game/machinery/lightswitch.dm
@@ -62,8 +62,7 @@
updateicon()
/obj/structure/machinery/light_switch/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
power_change()
- ..(severity)
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index f4ad7a63ba..66bf08afba 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -105,7 +105,7 @@ Class Procs:
var/list/component_parts //list of all the parts used to build it, if made from certain kinds of frames.
var/manual = 0
layer = OBJ_LAYER
- var/machine_processing = 0 // whether the machine is busy and requires process() calls in scheduler.
+ var/machine_processing = 0 // whether the machine is busy and requires process() calls in scheduler. // Please replace this by DF_ISPROCESSING in another refactor --fira
throwpass = 1
projectile_coverage = PROJECTILE_COVERAGE_MEDIUM
var/power_machine = FALSE //Whether the machine should process on power, or normal processor
@@ -175,10 +175,10 @@ Class Procs:
. += SPAN_WARNING("[msg]")
/obj/structure/machinery/emp_act(severity)
+ . = ..()
if(use_power && stat == 0)
use_power(7500/severity)
new /obj/effect/overlay/temp/emp_sparks (loc)
- ..()
/obj/structure/machinery/ex_act(severity)
diff --git a/code/game/machinery/magnet.dm b/code/game/machinery/magnet.dm
deleted file mode 100644
index 591cec1f5b..0000000000
--- a/code/game/machinery/magnet.dm
+++ /dev/null
@@ -1,421 +0,0 @@
-// Magnetic attractor, creates variable magnetic fields and attraction.
-// Can also be used to emit electron/proton beams to create a center of magnetism on another tile
-
-// tl;dr: it's magnets lol
-// This was created for firing ranges, but I suppose this could have other applications - Doohl
-
-/obj/structure/machinery/magnetic_module
-
- icon = 'icons/obj/objects.dmi'
- icon_state = "floor_magnet-f"
- name = "Electromagnetic Generator"
- desc = "A device that uses station power to create points of magnetic energy."
- level = 1 // underfloor
- layer = UNDERFLOOR_OBJ_LAYER
- anchored = TRUE
- use_power = USE_POWER_IDLE
- idle_power_usage = 50
-
- var/freq = 1449 // radio frequency
- var/electricity_level = 1 // intensity of the magnetic pull
- var/magnetic_field = 1 // the range of magnetic attraction
- var/code = 0 // frequency code, they should be different unless you have a group of magnets working together or something
- var/turf/center // the center of magnetic attraction
- var/on = 0
- var/pulling = 0
-
- // x, y modifiers to the center turf; (0, 0) is centered on the magnet, whereas (1, -1) is one tile right, one tile down
- var/center_x = 0
- var/center_y = 0
- var/max_dist = 20 // absolute value of center_x,y cannot exceed this integer
-
-/obj/structure/machinery/magnetic_module/Initialize(mapload, ...)
- . = ..()
-
- var/turf/T = loc
- hide(T.intact_tile)
- center = T
-
- SSradio.add_object(src, freq, RADIO_MAGNETS)
-
- INVOKE_ASYNC(src, PROC_REF(magnetic_process))
-
-/obj/structure/machinery/magnetic_module/Destroy()
- center = null
- SSradio.remove_object(src, freq)
- . = ..()
-
-
- // update the invisibility and icon
-/obj/structure/machinery/magnetic_module/hide(intact)
- invisibility = intact ? 101 : 0
- updateicon()
-
- // update the icon_state
-/obj/structure/machinery/magnetic_module/proc/updateicon()
- var/state="floor_magnet"
- var/onstate=""
- if(!on)
- onstate="0"
-
- if(invisibility)
- icon_state = "[state][onstate]-f" // if invisible, set icon to faded version
- // in case of being revealed by T-scanner
- else
- icon_state = "[state][onstate]"
-
-/obj/structure/machinery/magnetic_module/receive_signal(datum/signal/signal)
-
- var/command = signal.data["command"]
- var/modifier = signal.data["modifier"]
- var/signal_code = signal.data["code"]
- if(command && (signal_code == code))
-
- Cmd(command, modifier)
-
-
-
-/obj/structure/machinery/magnetic_module/proc/Cmd(command, modifier)
-
- if(command)
- switch(command)
- if("set-electriclevel")
- if(modifier) electricity_level = modifier
- if("set-magneticfield")
- if(modifier) magnetic_field = modifier
-
- if("add-elec")
- electricity_level++
- if(electricity_level > 12)
- electricity_level = 12
- if("sub-elec")
- electricity_level--
- if(electricity_level <= 0)
- electricity_level = 1
- if("add-mag")
- magnetic_field++
- if(magnetic_field > 4)
- magnetic_field = 4
- if("sub-mag")
- magnetic_field--
- if(magnetic_field <= 0)
- magnetic_field = 1
-
- if("set-x")
- if(modifier) center_x = modifier
- if("set-y")
- if(modifier) center_y = modifier
-
- if("N") // NORTH
- center_y++
- if("S") // SOUTH
- center_y--
- if("E") // EAST
- center_x++
- if("W") // WEST
- center_x--
- if("C") // CENTER
- center_x = 0
- center_y = 0
- if("R") // RANDOM
- center_x = rand(-max_dist, max_dist)
- center_y = rand(-max_dist, max_dist)
-
- if("set-code")
- if(modifier) code = modifier
- if("toggle-power")
- on = !on
-
- if(on)
- INVOKE_ASYNC(src, PROC_REF(magnetic_process))
-
-
-/obj/structure/machinery/magnetic_module/process()
- if(stat & NOPOWER)
- on = 0
-
- // Sanity checks:
- if(electricity_level <= 0)
- electricity_level = 1
- if(magnetic_field <= 0)
- magnetic_field = 1
-
-
- // Limitations:
- if(abs(center_x) > max_dist)
- center_x = max_dist
- if(abs(center_y) > max_dist)
- center_y = max_dist
- if(magnetic_field > 4)
- magnetic_field = 4
- if(electricity_level > 12)
- electricity_level = 12
-
- // Update power usage:
- if(on)
- use_power = USE_POWER_ACTIVE
- active_power_usage = electricity_level*15
- else
- use_power = USE_POWER_NONE
-
-
- // Overload conditions:
- /* // Eeeehhh kinda stupid
- if(on)
- if(electricity_level > 11)
- if(prob(electricity_level))
- explosion(loc, 0, 1, 2, 3) // ooo dat shit EXPLODES son
- spawn(2)
- qdel(src)
- */
-
- updateicon()
-
-
-/obj/structure/machinery/magnetic_module/proc/magnetic_process() // proc that actually does the pulling
- if(pulling) return
- while(on)
-
- pulling = 1
- center = locate(x+center_x, y+center_y, z)
- if(center)
- for(var/obj/M in orange(magnetic_field, center))
- if(!M.anchored && (M.flags_atom & CONDUCT))
- step_towards(M, center)
-
- for(var/mob/living/silicon/S in orange(magnetic_field, center))
- if(isAI(S)) continue
- step_towards(S, center)
-
- use_power(electricity_level * 5)
- sleep(13 - electricity_level)
-
- pulling = 0
-
-/obj/structure/machinery/magnetic_controller
- name = "Magnetic Control Console"
- icon = 'icons/obj/structures/machinery/airlock_machines.dmi' // uses an airlock machine icon, THINK GREEN HELP THE ENVIRONMENT - RECYCLING!
- icon_state = "airlock_control_standby"
- density = TRUE
- anchored = TRUE
- use_power = USE_POWER_IDLE
- idle_power_usage = 45
- var/frequency = 1449
- var/code = 0
- var/list/magnets = list()
- var/title = "Magnetic Control Console"
- var/autolink = 0 // if set to 1, can't probe for other magnets!
-
- var/pathpos = 1 // position in the path
- var/path = "NULL" // text path of the magnet
- var/speed = 1 // lowest = 1, highest = 10
- var/list/rpath = list() // real path of the magnet, used in iterator
-
- var/moving = 0 // 1 if scheduled to loop
- var/looping = 0 // 1 if looping
-
- var/datum/radio_frequency/radio_connection
-
-/obj/structure/machinery/magnetic_controller/Initialize(mapload, ...)
- . = ..()
- if(autolink)
- for(var/obj/structure/machinery/magnetic_module/M in machines)
- if(M.freq == frequency && M.code == code)
- magnets.Add(M)
-
- SSradio.add_object(src, frequency, RADIO_MAGNETS)
-
- if(path) // check for default path
- filter_path() // renders rpath
-
-/obj/structure/machinery/magnetic_controller/Destroy()
- QDEL_NULL_LIST(magnets)
- SSradio.remove_object(src, frequency)
- . = ..()
-
-
-/obj/structure/machinery/magnetic_controller/process()
- if(magnets.len == 0 && autolink)
- for(var/obj/structure/machinery/magnetic_module/M in machines)
- if(M.freq == frequency && M.code == code)
- magnets.Add(M)
-
-/obj/structure/machinery/magnetic_controller/attack_remote(mob/user as mob)
- return src.attack_hand(user)
-
-/obj/structure/machinery/magnetic_controller/attack_hand(mob/user as mob)
- if(inoperable())
- return
- user.set_interaction(src)
- var/dat = "Magnetic Control Console
"
- if(!autolink)
- dat += {"
- Frequency: [frequency]
- Code: [code]
- Probe Generators
- "}
-
- if(magnets.len >= 1)
-
- dat += "Magnets confirmed:
"
- var/i = 0
- for(var/obj/structure/machinery/magnetic_module/M in magnets)
- i++
- dat += " < \[[i]\] ([M.on ? "On":"Off"])|Electricity level: - [M.electricity_level] +; Magnetic field: - [M.magnetic_field] +
"
-
- dat += "
Speed: - [speed] +
"
- dat += "Path: {[path]}
"
- dat += "Moving: [moving ? "Enabled":"Disabled"]"
-
-
- show_browser(user, dat, name, "magnet", "size=400x500")
-
-/obj/structure/machinery/magnetic_controller/Topic(href, href_list)
- . = ..()
- if(.)
- return
- if(inoperable())
- return
- usr.set_interaction(src)
- src.add_fingerprint(usr)
-
- if(href_list["radio-op"])
-
- // Prepare signal beforehand, because this is a radio operation
- var/datum/signal/signal = new
- signal.transmission_method = 1 // radio transmission
- signal.source = src
- signal.frequency = frequency
- signal.data["code"] = code
-
- // Apply any necessary commands
- switch(href_list["radio-op"])
- if("togglepower")
- signal.data["command"] = "toggle-power"
-
- if("minuselec")
- signal.data["command"] = "sub-elec"
- if("pluselec")
- signal.data["command"] = "add-elec"
-
- if("minusmag")
- signal.data["command"] = "sub-mag"
- if("plusmag")
- signal.data["command"] = "add-mag"
-
-
- // Broadcast the signal
-
- radio_connection.post_signal(src, signal, filter = RADIO_MAGNETS)
-
- addtimer(CALLBACK(src, PROC_REF(updateUsrDialog)), 1)
-
- if(href_list["operation"])
- switch(href_list["operation"])
- if("plusspeed")
- speed ++
- if(speed > 10)
- speed = 10
- if("minusspeed")
- speed --
- if(speed <= 0)
- speed = 1
- if("setpath")
- var/newpath = copytext(sanitize(input(usr, "Please define a new path!",,path) as text|null),1,MAX_MESSAGE_LEN)
- if(newpath && newpath != "")
- moving = 0 // stop moving
- path = newpath
- pathpos = 1 // reset position
- filter_path() // renders rpath
-
- if("togglemoving")
- moving = !moving
- if(moving)
- INVOKE_ASYNC(src, PROC_REF(MagnetMove))
-
-
- updateUsrDialog()
-
-/obj/structure/machinery/magnetic_controller/proc/MagnetMove()
- if(looping) return
-
- while(moving && rpath.len >= 1)
-
- if(inoperable())
- break
-
- looping = 1
-
- // Prepare the radio signal
- var/datum/signal/signal = new
- signal.transmission_method = 1 // radio transmission
- signal.source = src
- signal.frequency = frequency
- signal.data["code"] = code
-
- if(pathpos > rpath.len) // if the position is greater than the length, we just loop through the list!
- pathpos = 1
-
- var/nextmove = uppertext(rpath[pathpos]) // makes it un-case-sensitive
-
- if(!(nextmove in list("N","S","E","W","C","R")))
- // N, S, E, W are directional
- // C is center
- // R is random (in magnetic field's bounds)
- qdel(signal)
- break // break the loop if the character located is invalid
-
- signal.data["command"] = nextmove
-
-
- pathpos++ // increase iterator
-
- // Broadcast the signal
- spawn()
- radio_connection.post_signal(src, signal, filter = RADIO_MAGNETS)
-
- if(speed == 10)
- sleep(1)
- else
- sleep(12-speed)
-
- looping = 0
-
-
-/obj/structure/machinery/magnetic_controller/proc/filter_path()
- // Generates the rpath variable using the path string, think of this as "string2list"
- // Doesn't use params2list() because of the akward way it stacks entities
- rpath = list() // clear rpath
- var/maximum_character = min( 50, length(path) ) // chooses the maximum length of the iterator. 50 max length
-
- for(var/i=1, i<=maximum_character, i++) // iterates through all characters in path
-
- var/nextchar = copytext(path, i, i+1) // find next character
-
- if(!(nextchar in list(";", "&", "*", " "))) // if char is a separator, ignore
- rpath += copytext(path, i, i+1) // else, add to list
-
- // there doesn't HAVE to be separators but it makes paths syntatically visible
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/code/game/machinery/mass_driver.dm b/code/game/machinery/mass_driver.dm
index d1e2fecce2..f1b0081e3a 100644
--- a/code/game/machinery/mass_driver.dm
+++ b/code/game/machinery/mass_driver.dm
@@ -1,5 +1,4 @@
-//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
-
+// Legacy SS13 machinery turned into a prop
/obj/structure/machinery/mass_driver
name = "mass driver"
desc = "Shoots things into space."
@@ -9,32 +8,3 @@
use_power = USE_POWER_IDLE
idle_power_usage = 2
active_power_usage = 50
-
- var/power = 1
- var/code = 1
- var/id = 1
- var/drive_range = 50 //this is mostly irrelevant since current mass drivers throw into space, but you could make a lower-range mass driver for interstation transport or something I guess.
-
-
-/obj/structure/machinery/mass_driver/proc/drive(amount)
- if(inoperable())
- return
- use_power(500)
- var/O_limit
- var/atom/target = get_edge_target_turf(src, dir)
- for(var/atom/movable/O in loc)
- if(!O.anchored)
- if(O_limit >= 20)
- for(var/mob/M in hearers(src, null))
- to_chat(M, SPAN_NOTICE(" The mass driver lets out a screech, it mustn't be able to handle any more items."))
- break
- use_power(500)
- INVOKE_ASYNC(O, TYPE_PROC_REF(/atom/movable, throw_atom), target, drive_range * power, 100/power)
- flick("mass_driver1", src)
- return
-
-/obj/structure/machinery/mass_driver/emp_act(severity)
- if(inoperable())
- return
- drive()
- ..(severity)
diff --git a/code/game/machinery/medical_pod/sleeper.dm b/code/game/machinery/medical_pod/sleeper.dm
index 35d9a44863..bf2abe246c 100644
--- a/code/game/machinery/medical_pod/sleeper.dm
+++ b/code/game/machinery/medical_pod/sleeper.dm
@@ -332,14 +332,13 @@
/obj/structure/machinery/medical_pod/sleeper/emp_act(severity)
+ . = ..()
if(filtering)
toggle_filter()
if(inoperable())
- ..(severity)
return
if(occupant)
go_out()
- ..()
/obj/structure/machinery/medical_pod/sleeper/proc/toggle_filter()
if(!occupant)
diff --git a/code/game/machinery/nuclearbomb.dm b/code/game/machinery/nuclearbomb.dm
index 743f53e4f0..28ebbecc75 100644
--- a/code/game/machinery/nuclearbomb.dm
+++ b/code/game/machinery/nuclearbomb.dm
@@ -394,7 +394,38 @@ var/bomb_set = FALSE
update_icon()
safety = TRUE
- EvacuationAuthority.trigger_self_destruct(list(z), src, FALSE, NUKE_EXPLOSION_GROUND_FINISHED, FALSE, end_round)
+ playsound(src, 'sound/machines/Alarm.ogg', 75, 0, 30)
+ world << pick('sound/theme/nuclear_detonation1.ogg','sound/theme/nuclear_detonation2.ogg')
+
+ var/list/alive_mobs = list() //Everyone who will be destroyed on the zlevel(s).
+ var/list/dead_mobs = list() //Everyone who only needs to see the cinematic.
+ for(var/mob/current_mob as anything in GLOB.mob_list)
+ if(!current_mob?.loc)
+ continue
+ if(current_mob.stat == DEAD)
+ dead_mobs |= current_mob
+ continue
+ var/turf/current_turf = get_turf(current_mob)
+ if(z == current_turf.z)
+ alive_mobs |= current_mob
+ shake_camera(current_mob, 110, 4)
+
+ for(var/mob/current_mob in alive_mobs)
+ if(current_mob && current_mob.loc)
+ var/turf/current_mob_turf = get_turf(current_mob)
+ if(z == current_mob_turf.z)
+ if(istype(current_mob.loc, /obj/structure/closet/secure_closet/freezer/fridge))
+ continue
+ current_mob.death(create_cause_data("nuclear explosion"))
+
+ for(var/mob/current_mob in (alive_mobs + dead_mobs))
+ if(current_mob && current_mob.loc)
+ var/turf/current_mob_turf = get_turf(current_mob)
+ if(z == current_mob_turf.z)
+ if(istype(current_mob.loc, /obj/structure/closet/secure_closet/freezer/fridge))
+ continue
+ for(var/obj/item/alien_embryo/embryo in current_mob)
+ qdel(embryo)
sleep(100)
cell_explosion(loc, 500, 150, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name)))
diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm
index c75360e075..72e311c6d8 100644
--- a/code/game/machinery/recharger.dm
+++ b/code/game/machinery/recharger.dm
@@ -218,20 +218,14 @@
update_icon()
/obj/structure/machinery/recharger/emp_act(severity)
+ . = ..()
if(inoperable() || !anchored)
- ..(severity)
return
-/*
- if(istype(charging, /obj/item/weapon/gun/energy))
- var/obj/item/weapon/gun/energy/E = charging
- if(E.power_supply)
- E.power_supply.emp_act(severity)
-*/
+
if(istype(charging, /obj/item/weapon/baton))
var/obj/item/weapon/baton/B = charging
if(B.bcell)
B.bcell.charge = 0
- ..(severity)
/obj/structure/machinery/recharger/update_icon() //we have an update_icon() in addition to the stuff in process to make it feel a tiny bit snappier.
src.overlays = 0
diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm
index 6444021288..56b782cd77 100644
--- a/code/game/machinery/rechargestation.dm
+++ b/code/game/machinery/rechargestation.dm
@@ -109,13 +109,12 @@
return
/obj/structure/machinery/recharge_station/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
if(occupant)
occupant.emp_act(severity)
go_out()
- ..(severity)
/obj/structure/machinery/recharge_station/update_icon()
..()
diff --git a/code/game/machinery/sentry_holder.dm b/code/game/machinery/sentry_holder.dm
index 5076bd03be..eecf8267cc 100644
--- a/code/game/machinery/sentry_holder.dm
+++ b/code/game/machinery/sentry_holder.dm
@@ -10,13 +10,12 @@
idle_power_usage = 1000
power_channel = 1
use_power = USE_POWER_IDLE
- machine_processing = 1
var/deployment_cooldown
var/turret_path = /obj/structure/machinery/defenses/sentry/premade/deployable // Path of the turret used
var/obj/structure/machinery/defenses/sentry/premade/deployable/deployed_turret
var/ox = 0
var/oy = 0
- var/ind = FALSE
+ var/require_red_alert = FALSE
/obj/structure/machinery/sentry_holder/Initialize()
. = ..()
@@ -36,34 +35,38 @@
. += "It's offline."
/obj/structure/machinery/sentry_holder/attack_hand(mob/user)
- if(deployed_turret)
- if(deployment_cooldown > world.time)
- to_chat(user, SPAN_WARNING("[src] is busy."))
- return //prevents spamming deployment/undeployment
- if(deployed_turret.loc == src) //not deployed
- if(stat & NOPOWER)
- to_chat(user, SPAN_WARNING("[src] is non-functional."))
- else
- to_chat(user, SPAN_NOTICE("You deploy [src]."))
- deploy_sentry()
- else
- to_chat(user, SPAN_NOTICE("You retract [src]."))
- undeploy_sentry()
- else
+ if(!deployed_turret)
to_chat(user, SPAN_WARNING("[src] is unresponsive."))
+ return
-/obj/structure/machinery/sentry_holder/process()
- if(stat & NOPOWER)
- if(deployed_turret)
- undeploy_sentry()
- ind = FALSE
- else
- icon_state = "sentry_system_destroyed"
- else
- update_use_power(USE_POWER_IDLE)
- if(!ind)
- deploy_sentry()
- ind = TRUE
+ if(deployment_cooldown > world.time)
+ to_chat(user, SPAN_WARNING("[src] is busy."))
+ return
+
+ if(deployed_turret.loc == src) //not deployed
+ if(stat & NOPOWER)
+ to_chat(user, SPAN_WARNING("[src] is non-functional."))
+ return
+
+ if(require_red_alert && (seclevel2num(get_security_level()) < SEC_LEVEL_RED))
+ to_chat(user, SPAN_WARNING("[src] can only be activated in emergencies."))
+ return
+
+ to_chat(user, SPAN_NOTICE("You deploy [src]."))
+ deploy_sentry()
+ return
+
+ to_chat(user, SPAN_NOTICE("You retract [src]."))
+ undeploy_sentry()
+ return
+
+/obj/structure/machinery/sentry_holder/update_use_power(new_use_power)
+ ..()
+
+ if(!(stat & NOPOWER))
+ return
+
+ undeploy_sentry()
/obj/structure/machinery/sentry_holder/proc/deploy_sentry()
if(!deployed_turret)
@@ -111,3 +114,6 @@
desc = "A box that deploys a sentry turret for protection of the residents in the area."
turret_path = /obj/structure/machinery/defenses/sentry/premade/deployable/colony
+/obj/structure/machinery/sentry_holder/almayer
+ turret_path = /obj/structure/machinery/defenses/sentry/premade/deployable/almayer
+ require_red_alert = TRUE
diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm
index aa51201ae1..dd45ad5978 100644
--- a/code/game/machinery/spaceheater.dm
+++ b/code/game/machinery/spaceheater.dm
@@ -40,12 +40,11 @@
/obj/structure/machinery/space_heater/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
if(cell)
cell.emp_act(severity)
- ..(severity)
/obj/structure/machinery/space_heater/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/cell))
diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm
index 6c6d2bda8b..79ead63215 100644
--- a/code/game/machinery/status_display.dm
+++ b/code/game/machinery/status_display.dm
@@ -78,7 +78,7 @@
return 1
if(STATUS_DISPLAY_TRANSFER_SHUTTLE_TIME) //emergency shuttle timer
message1 = "EVAC"
- message2 = EvacuationAuthority.get_status_panel_eta()
+ message2 = SShijack.get_evac_eta()
if(message2)
if(length(message2) > CHARS_PER_LINE) message2 = "Error"
update_display(message1, message2)
@@ -163,6 +163,15 @@
if(maptext)
maptext = ""
+/obj/structure/machinery/status_display/proc/set_sec_level_picture()
+ switch(security_level)
+ if(SEC_LEVEL_GREEN)
+ set_picture("default")
+ if(SEC_LEVEL_BLUE)
+ set_picture("bluealert")
+ if(SEC_LEVEL_RED, SEC_LEVEL_DELTA)
+ set_picture("redalert")
+
/obj/structure/machinery/ai_status_display
icon = 'icons/obj/structures/machinery/status_display.dmi'
icon_state = "frame"
@@ -179,11 +188,10 @@
var/emotion = "Neutral"
/obj/structure/machinery/ai_status_display/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
set_picture("ai_bsod")
- ..(severity)
/obj/structure/machinery/ai_status_display/proc/update()
if(mode==0) //Blank
diff --git a/code/game/machinery/telecomms/presets.dm b/code/game/machinery/telecomms/presets.dm
index d93304c663..510d488bb3 100644
--- a/code/game/machinery/telecomms/presets.dm
+++ b/code/game/machinery/telecomms/presets.dm
@@ -449,8 +449,7 @@ GLOBAL_LIST_EMPTY(all_static_telecomms_towers)
id = "CentComm Receiver"
network = "tcommsat"
autolinkers = list("receiverCent")
- freq_listening = list(WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ)
-
+ freq_listening = list(WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ, CBRN_FREQ)
//Buses
@@ -469,7 +468,7 @@ GLOBAL_LIST_EMPTY(all_static_telecomms_towers)
/obj/structure/machinery/telecomms/bus/preset_three
id = "Bus 3"
network = "tcommsat"
- freq_listening = list(SEC_FREQ, COMM_FREQ, WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, JTAC_FREQ, INTEL_FREQ, WY_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ)
+ freq_listening = list(SEC_FREQ, COMM_FREQ, WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, JTAC_FREQ, INTEL_FREQ, WY_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ, CBRN_FREQ)
autolinkers = list("processor3", "security", "command", "JTAC")
/obj/structure/machinery/telecomms/bus/preset_four
@@ -485,7 +484,7 @@ GLOBAL_LIST_EMPTY(all_static_telecomms_towers)
/obj/structure/machinery/telecomms/bus/preset_cent
id = "CentComm Bus"
network = "tcommsat"
- freq_listening = list(WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ)
+ freq_listening = list(WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ, CBRN_FREQ)
autolinkers = list("processorCent", "centcomm")
//Processors
@@ -550,7 +549,7 @@ GLOBAL_LIST_EMPTY(all_static_telecomms_towers)
/obj/structure/machinery/telecomms/server/presets/command
id = "Command Server"
- freq_listening = list(COMM_FREQ, WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, JTAC_FREQ, INTEL_FREQ, WY_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ)
+ freq_listening = list(COMM_FREQ, WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, JTAC_FREQ, INTEL_FREQ, WY_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ, CBRN_FREQ)
autolinkers = list("command")
/obj/structure/machinery/telecomms/server/presets/engineering
@@ -565,10 +564,9 @@ GLOBAL_LIST_EMPTY(all_static_telecomms_towers)
/obj/structure/machinery/telecomms/server/presets/centcomm
id = "CentComm Server"
- freq_listening = list(WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ)
+ freq_listening = list(WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ, CBRN_FREQ)
autolinkers = list("centcomm")
-
//Broadcasters
//--PRESET LEFT--//
diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm
index 255d70f458..8b8b12dfd1 100644
--- a/code/game/machinery/telecomms/telecomunications.dm
+++ b/code/game/machinery/telecomms/telecomunications.dm
@@ -93,13 +93,13 @@ GLOBAL_LIST_EMPTY_TYPED(telecomms_list, /obj/structure/machinery/telecomms)
update_state()
/obj/structure/machinery/telecomms/emp_act(severity)
+ . = ..()
if(prob(100/severity))
if(!(stat & EMPED))
stat |= EMPED
var/duration = (300 * 10)/severity
spawn(rand(duration - 20, duration + 20)) // Takes a long time for the machines to reboot.
stat &= ~EMPED
- ..()
/*
The receiver idles and receives messages from subspace-compatible radio equipment;
diff --git a/code/game/machinery/vending/cm_vending.dm b/code/game/machinery/vending/cm_vending.dm
index 56a4429146..03fe1c198b 100644
--- a/code/game/machinery/vending/cm_vending.dm
+++ b/code/game/machinery/vending/cm_vending.dm
@@ -140,9 +140,9 @@ GLOBAL_LIST_EMPTY(vending_products)
if(vend_dir_whitelist)
var/user_dir = get_dir(loc, user)
if(!(user_dir in vend_dir_whitelist))
- return turf
+ return get_turf(user)
var/turf/relative_turf = get_step(user, vend_dir)
- if(relative_turf.Adjacent(src))
+ if(relative_turf)
return relative_turf
return turf
@@ -443,7 +443,44 @@ GLOBAL_LIST_EMPTY(vending_products)
//------------TGUI PROCS---------------
/obj/structure/machinery/cm_vending/ui_data(mob/user)
- return vendor_user_ui_data(src, user)
+ if(vend_flags & VEND_LIMITED_INVENTORY)
+ return vendor_inventory_ui_data(user)
+
+ . = list()
+ var/list/ui_listed_products = get_listed_products(user)
+ // list format
+ // (
+ // name: str
+ // cost
+ // item reference
+ // allowed to buy flag
+ // item priority (mandatory/recommended/regular)
+ // )
+
+ var/list/stock_values = list()
+
+ var/mob/living/carbon/human/marine = user
+ var/points = 0
+
+ if(instanced_vendor_points)
+ points = available_points_to_display
+ else
+ if(use_snowflake_points)
+ points = marine.marine_snowflake_points
+ else if(use_points)
+ points = marine.marine_points
+
+ for (var/i in 1 to length(ui_listed_products))
+ var/list/myprod = ui_listed_products[i] //we take one list from listed_products
+ var/prod_available = FALSE
+ var/p_cost = myprod[2]
+ var/category = myprod[4]
+ if(points >= p_cost && (!category || ((category in marine.marine_buyable_categories) && (marine.marine_buyable_categories[category]))))
+ prod_available = TRUE
+ stock_values += list(prod_available)
+
+ .["stock_listing"] = stock_values
+ .["current_m_points"] = points
/obj/structure/machinery/cm_vending/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
@@ -530,7 +567,7 @@ GLOBAL_LIST_EMPTY(vending_products)
vend_fail()
return FALSE
- if(!handle_vend(src, itemspec, user))
+ if(!handle_vend(itemspec, user))
to_chat(user, SPAN_WARNING("You can't buy things from this category anymore."))
vend_fail()
return FALSE
@@ -548,7 +585,7 @@ GLOBAL_LIST_EMPTY(vending_products)
vend_fail()
return TRUE // one left and the player spam click during a lagspike.
- vendor_successful_vend(src, itemspec, user)
+ vendor_successful_vend(itemspec, user)
return TRUE
add_fingerprint(user)
@@ -784,7 +821,7 @@ GLOBAL_LIST_EMPTY(vending_products)
/obj/structure/machinery/cm_vending/gear/ui_static_data(mob/user)
. = ..(user)
.["vendor_type"] = "gear"
- .["displayed_categories"] = vendor_user_inventory_list(src, user)
+ .["displayed_categories"] = vendor_user_inventory_list(user)
//------------CLOTHING VENDORS---------------
//clothing vendors automatically put item on user. QoL at it's finest.
@@ -806,7 +843,7 @@ GLOBAL_LIST_EMPTY(vending_products)
/obj/structure/machinery/cm_vending/clothing/ui_static_data(mob/user)
. = ..(user)
.["vendor_type"] = "clothing"
- .["displayed_categories"] = vendor_user_inventory_list(src, user)
+ .["displayed_categories"] = vendor_user_inventory_list(user)
//------------SORTED VENDORS---------------
//22.06.2019 Modified ex-"marine_selector" system that doesn't use points by Jeser. In theory, should replace all vendors.
@@ -865,7 +902,7 @@ GLOBAL_LIST_EMPTY(vending_products)
/obj/structure/machinery/cm_vending/sorted/ui_static_data(mob/user)
. = ..(user)
.["vendor_type"] = "sorted"
- .["displayed_categories"] = vendor_user_inventory_list(src, user, null, 4)
+ .["displayed_categories"] = vendor_user_inventory_list(user, null, 4)
/obj/structure/machinery/cm_vending/sorted/MouseDrop_T(atom/movable/A, mob/user)
@@ -944,7 +981,7 @@ GLOBAL_LIST_EMPTY(vending_products)
/obj/structure/machinery/cm_vending/own_points/ui_static_data(mob/user)
. = ..(user)
.["vendor_type"] = "gear"
- .["displayed_categories"] = vendor_user_inventory_list(src, user)
+ .["displayed_categories"] = vendor_user_inventory_list(user)
//------------ESSENTIALS SETS AND RANDOM GEAR SPAWNER---------------
@@ -1070,7 +1107,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list(
//---helper procs
-/proc/vendor_user_inventory_list(vendor, mob/user, cost_index=2, priority_index=5)
+/obj/structure/machinery/cm_vending/proc/vendor_user_inventory_list(mob/user, cost_index=2, priority_index=5)
. = list()
// default list format
// (
@@ -1080,8 +1117,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list(
// allowed to buy flag
// item priority (mandatory/recommended/regular)
// )
- var/obj/structure/machinery/cm_vending/vending_machine = vendor
- var/list/ui_listed_products = vending_machine.get_listed_products(user)
+ var/list/ui_listed_products = get_listed_products(user)
for (var/i in 1 to length(ui_listed_products))
var/list/myprod = ui_listed_products[i] //we take one list from listed_products
@@ -1123,10 +1159,9 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list(
var/last_category = .[last_index]
last_category["items"] += list(display_item)
-/proc/vendor_inventory_ui_data(vendor, mob/user)
+/obj/structure/machinery/cm_vending/proc/vendor_inventory_ui_data(mob/user)
. = list()
- var/obj/structure/machinery/cm_vending/vending_machine = vendor
- var/list/ui_listed_products = vending_machine.get_listed_products(user)
+ var/list/ui_listed_products = get_listed_products(user)
var/list/ui_categories = list()
for (var/i in 1 to length(ui_listed_products))
@@ -1135,92 +1170,50 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list(
ui_categories += list(p_amount)
.["stock_listing"] = ui_categories
-/proc/vendor_user_ui_data(obj/structure/machinery/cm_vending/vending_machine, mob/user)
- if(vending_machine.vend_flags & VEND_LIMITED_INVENTORY)
- return vendor_inventory_ui_data(vending_machine, user)
-
- . = list()
- var/list/ui_listed_products = vending_machine.get_listed_products(user)
- // list format
- // (
- // name: str
- // cost
- // item reference
- // allowed to buy flag
- // item priority (mandatory/recommended/regular)
- // )
-
- var/list/stock_values = list()
-
- var/mob/living/carbon/human/marine = user
- var/points = 0
-
- if(vending_machine.instanced_vendor_points)
- points = vending_machine.available_points_to_display
- else
- if(vending_machine.use_snowflake_points)
- points = marine.marine_snowflake_points
- else if(vending_machine.use_points)
- points = marine.marine_points
-
- for (var/i in 1 to length(ui_listed_products))
- var/list/myprod = ui_listed_products[i] //we take one list from listed_products
- var/prod_available = FALSE
- var/p_cost = myprod[2]
- var/category = myprod[4]
- if(points >= p_cost && (!category || ((category in marine.marine_buyable_categories) && (marine.marine_buyable_categories[category]))))
- prod_available = TRUE
- stock_values += list(prod_available)
-
- .["stock_listing"] = stock_values
- .["current_m_points"] = points
-
-/proc/vendor_successful_vend(obj/structure/machinery/cm_vending/vendor, list/itemspec, mob/living/carbon/human/user)
- if(vendor.stat & IN_USE)
+/obj/structure/machinery/cm_vending/proc/vendor_successful_vend(list/itemspec, mob/living/carbon/human/user)
+ if(stat & IN_USE)
return
- vendor.stat |= IN_USE
+ stat |= IN_USE
- var/vend_flags = vendor.vend_flags
- var/turf/target_turf = vendor.get_appropriate_vend_turf(user)
+ var/turf/target_turf = get_appropriate_vend_turf(user)
if(LAZYLEN(itemspec)) //making sure it's not empty
- if(vendor.vend_delay)
- vendor.overlays.Cut()
- vendor.icon_state = "[initial(vendor.icon_state)]_vend"
- if(vendor.vend_sound)
- playsound(vendor.loc, vendor.vend_sound, 25, 1, 2) //heard only near vendor
- sleep(vendor.vend_delay)
+ if(vend_delay)
+ overlays.Cut()
+ icon_state = "[initial(icon_state)]_vend"
+ if(vend_sound)
+ playsound(loc, vend_sound, 25, 1, 2) //heard only near vendor
+ sleep(vend_delay)
var/prod_type = itemspec[3]
if(islist(prod_type))
for(var/each_type in prod_type)
- vendor_successful_vend_one(vendor, each_type, user, target_turf, itemspec[4] == MARINE_CAN_BUY_UNIFORM)
+ vendor_successful_vend_one(each_type, user, target_turf, itemspec[4] == MARINE_CAN_BUY_UNIFORM)
else
- vendor_successful_vend_one(vendor, prod_type, user, target_turf, itemspec[4] == MARINE_CAN_BUY_UNIFORM)
+ vendor_successful_vend_one(prod_type, user, target_turf, itemspec[4] == MARINE_CAN_BUY_UNIFORM)
if(vend_flags & VEND_LIMITED_INVENTORY)
itemspec[2]--
if(vend_flags & VEND_LOAD_AMMO_BOXES)
- vendor.update_derived_ammo_and_boxes(itemspec)
+ update_derived_ammo_and_boxes(itemspec)
else
to_chat(user, SPAN_WARNING("ERROR: itemspec is missing. Please report this to admins."))
sleep(15)
- vendor.stat &= ~IN_USE
- vendor.icon_state = initial(vendor.icon_state)
- vendor.update_icon()
+ stat &= ~IN_USE
+ icon_state = initial(icon_state)
+ update_icon()
-/proc/vendor_successful_vend_one(obj/structure/machinery/cm_vending/vendor, prod_type, mob/living/carbon/human/user, turf/target_turf, insignas_override)
+/obj/structure/machinery/cm_vending/proc/vendor_successful_vend_one(prod_type, mob/living/carbon/human/user, turf/target_turf, insignas_override)
var/obj/item/new_item
- var/vend_flags = vendor.vend_flags
if(ispath(prod_type, /obj/item))
if(ispath(prod_type, /obj/item/weapon/gun))
new_item = new prod_type(target_turf, TRUE)
else
if(prod_type == /obj/item/device/radio/headset/almayer/marine)
- prod_type = vendor.headset_type
+ prod_type = headset_type
else if(prod_type == /obj/item/clothing/gloves/marine)
- prod_type = vendor.gloves_type
+ prod_type = gloves_type
new_item = new prod_type(target_turf)
new_item.add_fingerprint(user)
else
@@ -1249,13 +1242,13 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list(
if(vend_flags & VEND_TO_HAND)
if(user.client?.prefs && (user.client?.prefs?.toggle_prefs & TOGGLE_VEND_ITEM_TO_HAND))
- if(vendor.Adjacent(user))
+ if(Adjacent(user))
user.put_in_any_hand_if_possible(new_item, disable_warning = TRUE)
new_item.post_vendor_spawn_hook(user)
-/proc/handle_vend(obj/structure/machinery/cm_vending/vendor, list/listed_products, mob/living/carbon/human/vending_human)
- if(vendor.vend_flags & VEND_USE_VENDOR_FLAGS)
+/obj/structure/machinery/cm_vending/proc/handle_vend(list/listed_products, mob/living/carbon/human/vending_human)
+ if(vend_flags & VEND_USE_VENDOR_FLAGS)
return TRUE
var/buying_category = listed_products[4]
if(buying_category)
@@ -1291,62 +1284,3 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list(
stat &= ~IN_USE
if(destroy)
qdel(src)
-
-//------------HACKING---------------
-
-//Hacking code from old vendors, in case someone will actually would like to add complex hacking in future. For now, simple access hacking I believe sufficient.
-/*
-/obj/structure/machinery/vending/proc/get_wire_descriptions()
- return list(
- VENDING_WIRE_EXTEND = "Inventory control computer",
- VENDING_WIRE_IDSCAN = "ID scanner",
- VENDING_WIRE_SHOCK = "Ground safety",
- VENDING_WIRE_SHOOT_INV = "Dispenser motor control"
- )
-
-/obj/structure/machinery/vending/proc/isWireCut(wire)
- return !(wires & getWireFlag(wire))
-
-/obj/structure/machinery/vending/proc/cut(wire)
- wires ^= getWireFlag(wire)
-
- switch(wire)
- if(VENDING_WIRE_EXTEND)
- src.extended_inventory = 0
- visible_message(SPAN_NOTICE("A weak yellow light turns off underneath \the [src]."))
- if(VENDING_WIRE_SHOCK)
- src.seconds_electrified = -1
- visible_message(SPAN_DANGER("Electric arcs shoot off from \the [src]!"))
- if (VENDING_WIRE_SHOOT_INV)
- if(!src.shoot_inventory)
- src.shoot_inventory = TRUE
- visible_message(SPAN_WARNING("\The [src] begins whirring noisily."))
-
-/obj/structure/machinery/vending/proc/mend(wire)
- wires |= getWireFlag(wire)
-
- switch(wire)
- if(VENDING_WIRE_EXTEND)
- src.extended_inventory = 1
- visible_message(SPAN_NOTICE("A weak yellow light turns on underneath \the [src]."))
- if(VENDING_WIRE_SHOCK)
- src.seconds_electrified = 0
- if (VENDING_WIRE_SHOOT_INV)
- src.shoot_inventory = FALSE
- visible_message(SPAN_NOTICE("\The [src] stops whirring."))
-
-/obj/structure/machinery/vending/proc/pulse(wire)
- switch(wire)
- if(VENDING_WIRE_EXTEND)
- src.extended_inventory = !src.extended_inventory
- visible_message(SPAN_NOTICE("A weak yellow light turns [extended_inventory ? "on" : "off"] underneath \the [src]."))
- if (VENDING_WIRE_SHOCK)
- src.seconds_electrified = 30
- visible_message(SPAN_DANGER("Electric arcs shoot off from \the [src]!"))
- if (VENDING_WIRE_SHOOT_INV)
- src.shoot_inventory = !src.shoot_inventory
- if(shoot_inventory)
- visible_message(SPAN_WARNING("\The [src] begins whirring noisily."))
- else
- visible_message(SPAN_NOTICE("\The [src] stops whirring."))
-*/
diff --git a/code/game/machinery/vending/vending_types.dm b/code/game/machinery/vending/vending_types.dm
index c109db25b3..a57bbfe7d2 100644
--- a/code/game/machinery/vending/vending_types.dm
+++ b/code/game/machinery/vending/vending_types.dm
@@ -412,6 +412,12 @@
/obj/item/device/camera_film = 10,
/obj/item/notepad = 5,
/obj/item/device/toner = 5,
+ /obj/item/paper/colonial_grunts = 15,
+ /obj/item/toy/dice/d20 = 10,
+ /obj/item/tool/pen = 10,
+ /obj/item/tool/pen/blue = 10,
+ /obj/item/tool/pen/red = 10,
+ /obj/item/tool/pen/fountain = 3,
)
contraband = list(/obj/item/toy/sword = 2)
@@ -433,5 +439,11 @@
/obj/item/toy/deck/uno = 15,
/obj/item/device/camera = 30,
/obj/item/device/toner = 15,
+ /obj/item/paper/colonial_grunts = 5,
+ /obj/item/toy/dice/d20 = 1,
+ /obj/item/tool/pen = 2,
+ /obj/item/tool/pen/blue = 2,
+ /obj/item/tool/pen/red = 2,
+ /obj/item/tool/pen/fountain = 30,
)
product_type = VENDOR_PRODUCT_TYPE_RECREATIONAL
diff --git a/code/game/machinery/vending/vendor_types/crew/synthetic.dm b/code/game/machinery/vending/vendor_types/crew/synthetic.dm
index bf96246e92..c912ae8ce3 100644
--- a/code/game/machinery/vending/vendor_types/crew/synthetic.dm
+++ b/code/game/machinery/vending/vendor_types/crew/synthetic.dm
@@ -102,7 +102,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth, list(
list("Surgical Drop Pouch", 0, /obj/item/clothing/accessory/storage/surg_vest/drop_green, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR),
list("Surgical Drop Pouch (Blue)", 0, /obj/item/clothing/accessory/storage/surg_vest/drop_blue, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR),
list("Surgical Drop Pouch (Black)", 0, /obj/item/clothing/accessory/storage/surg_vest/drop_black, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR),
- list("Tool Webbing", 0, /obj/item/clothing/accessory/storage/black_vest/tool_webbing, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR),
+ list("Tool Webbing", 0, /obj/item/clothing/accessory/storage/tool_webbing/equipped, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR),
list("Drop Pouch", 0, /obj/item/clothing/accessory/storage/droppouch, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR),
list("SHOES (CHOOSE 1)", 0, null, null, null),
diff --git a/code/game/machinery/vending/vendor_types/crew/vehicle_crew.dm b/code/game/machinery/vending/vendor_types/crew/vehicle_crew.dm
index 891a2a907b..d352936b54 100644
--- a/code/game/machinery/vending/vendor_types/crew/vehicle_crew.dm
+++ b/code/game/machinery/vending/vendor_types/crew/vehicle_crew.dm
@@ -55,8 +55,10 @@
SIGNAL_HANDLER
UnregisterSignal(SSdcs, COMSIG_GLOB_VEHICLE_ORDERED)
- selected_vehicle = "APC"
- available_categories &= ~(VEHICLE_ARMOR_AVAILABLE|VEHICLE_INTEGRAL_AVAILABLE) //APC lacks these, so we need to remove these flags to be able to access spare parts section
+ if(!selected_vehicle)
+ selected_vehicle = "APC" // The whole thing seems to be based upon the assumption you unlock tank as an override, defaulting to APC
+ if(selected_vehicle == "APC")
+ available_categories &= ~(VEHICLE_ARMOR_AVAILABLE|VEHICLE_INTEGRAL_AVAILABLE) //APC lacks these, so we need to remove these flags to be able to access spare parts section
/obj/structure/machinery/cm_vending/gear/vehicle_crew/get_listed_products(mob/user)
var/list/display_list = list()
diff --git a/code/game/machinery/vending/vendor_types/requisitions.dm b/code/game/machinery/vending/vendor_types/requisitions.dm
index 3baac270cd..3591a7caec 100644
--- a/code/game/machinery/vending/vendor_types/requisitions.dm
+++ b/code/game/machinery/vending/vendor_types/requisitions.dm
@@ -427,6 +427,9 @@
list("MASKS", -1, null, null, null),
list("Gas Mask", 20, /obj/item/clothing/mask/gas, VENDOR_ITEM_REGULAR),
list("Heat Absorbent Coif", 10, /obj/item/clothing/mask/rebreather/scarf, VENDOR_ITEM_REGULAR),
+
+ list("MISCELLANEOUS", -1, null, null),
+ list("Bedroll", 30, /obj/item/roller/bedroll, VENDOR_ITEM_REGULAR),
)
/obj/structure/machinery/cm_vending/sorted/uniform_supply/ui_state(mob/user)
diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_medic.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_medic.dm
index dd3700b3d5..eeb647273c 100644
--- a/code/game/machinery/vending/vendor_types/squad_prep/squad_medic.dm
+++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_medic.dm
@@ -118,6 +118,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_medic, list(
list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null),
list("Standard Marine Apparel", 0, list(/obj/item/clothing/under/marine/medic, /obj/item/clothing/shoes/marine/knife, /obj/item/clothing/gloves/marine, /obj/item/device/radio/headset/almayer/marine, /obj/item/clothing/head/helmet/marine/medic), MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY),
+ list("Combat Sterile Gloves", 0, /obj/item/clothing/gloves/marine/medical, MARINE_CAN_BUY_KIT, VENDOR_ITEM_REGULAR),
list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY),
list("ARMOR (CHOOSE 1)", 0, null, null, null),
diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm
index b48b4ee3f7..84eeaa2a15 100644
--- a/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm
+++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm
@@ -145,6 +145,7 @@
list("USCM Flair", round(scale * 15), /obj/item/prop/helmetgarb/flair_uscm, VENDOR_ITEM_REGULAR),
list("Solar Devils Shoulder Patch", round(scale * 15), /obj/item/clothing/accessory/patch/devils, VENDOR_ITEM_REGULAR),
list("USCM Shoulder Patch", round(scale * 15), /obj/item/clothing/accessory/patch, VENDOR_ITEM_REGULAR),
+ list("Bedroll", round(scale * 20), /obj/item/roller/bedroll, VENDOR_ITEM_REGULAR),
)
//--------------SQUAD SPECIFIC VERSIONS--------------
diff --git a/code/game/objects/effects/acid_hole.dm b/code/game/objects/effects/acid_hole.dm
index 1b320a9d26..207c6c9e25 100644
--- a/code/game/objects/effects/acid_hole.dm
+++ b/code/game/objects/effects/acid_hole.dm
@@ -53,11 +53,11 @@
playsound(src, "pry", 25, 1)
xeno_attack_delay(user)
- user.freeze()
+ ADD_TRAIT(user, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Acid hole"))
if(do_after(user, 60, INTERRUPT_ALL, BUSY_ICON_GENERIC) && !QDELETED(src) && holed_wall && !user.lying && istype(holed_wall))
holed_wall.take_damage(rand(2000,3500))
user.emote("roar")
- user.unfreeze()
+ REMOVE_TRAIT(user, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Acid hole"))
/obj/effect/acid_hole/proc/use_wall_hole(mob/user)
diff --git a/code/game/objects/effects/decals/posters.dm b/code/game/objects/effects/decals/posters.dm
index c688c4e6fb..7a8054efce 100644
--- a/code/game/objects/effects/decals/posters.dm
+++ b/code/game/objects/effects/decals/posters.dm
@@ -184,6 +184,12 @@
serial_number = pick(27,28,30,31)
.=..()
+/obj/structure/sign/poster/io
+ icon_state = "poster14"
+
+/obj/structure/sign/poster/io/Initialize()
+ serial_number = 14
+ . = ..()
////////////////
//Hero Posters//
////////////////
diff --git a/code/game/objects/effects/decals/warning_stripes.dm b/code/game/objects/effects/decals/warning_stripes.dm
index ce0802d72d..20c96c2ac7 100644
--- a/code/game/objects/effects/decals/warning_stripes.dm
+++ b/code/game/objects/effects/decals/warning_stripes.dm
@@ -91,6 +91,20 @@
/obj/effect/decal/sand_overlay/sand2/corner2
icon_state = "sand2_c"
+/obj/effect/decal/grass_overlay
+ name = "grass edge"
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ unacidable = TRUE
+ icon = 'icons/turf/floors/auto_strata_grass.dmi'
+ layer = TURF_LAYER
+
+/obj/effect/decal/grass_overlay/grass1
+ icon_state = "grass_outercorner"
+
+/obj/effect/decal/grass_overlay/grass1/inner
+ name = "grass edge"
+ icon_state = "grass_innercorner"
+
/obj/effect/decal/siding
name = "siding"
icon = 'icons/turf/floors/floors.dmi'
diff --git a/code/game/objects/effects/effect_system/smoke.dm b/code/game/objects/effects/effect_system/smoke.dm
index 78aa01b5da..b80f53b14d 100644
--- a/code/game/objects/effects/effect_system/smoke.dm
+++ b/code/game/objects/effects/effect_system/smoke.dm
@@ -31,13 +31,13 @@
amount = oldamount - 1
cause_data = new_cause_data
time_to_live += rand(-1,1)
- active_smoke_effects += src
+ START_PROCESSING(SSeffects, src)
/obj/effect/particle_effect/smoke/Destroy()
. = ..()
if(opacity)
set_opacity(0)
- active_smoke_effects -= src
+ STOP_PROCESSING(SSeffects, src)
cause_data = null
/obj/effect/particle_effect/smoke/initialize_pass_flags(datum/pass_flags_container/PF)
diff --git a/code/game/objects/effects/landmarks/freed_mob_spawner.dm b/code/game/objects/effects/landmarks/freed_mob_spawner.dm
index c0e34eed54..7841e99df2 100644
--- a/code/game/objects/effects/landmarks/freed_mob_spawner.dm
+++ b/code/game/objects/effects/landmarks/freed_mob_spawner.dm
@@ -6,7 +6,7 @@
/obj/effect/landmark/freed_mob_spawner/Initialize()
. = ..()
- spawn_freed_mob()
+ INVOKE_ASYNC(src, PROC_REF(spawn_freed_mob))
return INITIALIZE_HINT_QDEL
/obj/effect/landmark/freed_mob_spawner/Destroy()
diff --git a/code/game/objects/effects/landmarks/landmarks.dm b/code/game/objects/effects/landmarks/landmarks.dm
index 5f4a374ba3..1659c4ca6e 100644
--- a/code/game/objects/effects/landmarks/landmarks.dm
+++ b/code/game/objects/effects/landmarks/landmarks.dm
@@ -255,6 +255,8 @@
else
LAZYADD(GLOB.spawns_by_job[job], src)
+ RegisterSignal(SSdcs, COMSIG_GLOB_PLATOON_NAME_CHANGE, PROC_REF(rename_platoon))
+
/obj/effect/landmark/start/Destroy()
if(job)
if(squad)
@@ -263,6 +265,17 @@
LAZYREMOVE(GLOB.spawns_by_job[job], src)
return ..()
+/obj/effect/landmark/start/proc/rename_platoon(datum/source, new_name, old_name)
+ SIGNAL_HANDLER
+ if(squad != old_name)
+ return
+
+ LAZYREMOVE(GLOB.spawns_by_squad_and_job, squad)
+ squad = new_name
+ LAZYINITLIST(GLOB.spawns_by_squad_and_job)
+ LAZYINITLIST(GLOB.spawns_by_squad_and_job[squad])
+ LAZYADD(GLOB.spawns_by_squad_and_job[squad][job], src)
+
/obj/effect/landmark/start/AISloc
name = "AI"
@@ -385,6 +398,16 @@
name = "alpha late join"
squad = SQUAD_MARINE_1
+/obj/effect/landmark/late_join/alpha/Initialize(mapload, ...)
+ . = ..()
+
+ RegisterSignal(SSdcs, COMSIG_GLOB_PLATOON_NAME_CHANGE, PROC_REF(rename_platoon))
+
+/obj/effect/landmark/late_join/alpha/proc/rename_platoon(datum/source, new_name, old_name)
+ SIGNAL_HANDLER
+
+ squad = new_name
+
/obj/effect/landmark/late_join/bravo
name = "bravo late join"
squad = SQUAD_MARINE_2
diff --git a/code/game/objects/effects/landmarks/survivor_spawner.dm b/code/game/objects/effects/landmarks/survivor_spawner.dm
index fe4254982d..a53fead0d3 100644
--- a/code/game/objects/effects/landmarks/survivor_spawner.dm
+++ b/code/game/objects/effects/landmarks/survivor_spawner.dm
@@ -8,6 +8,8 @@
var/roundstart_damage_min = 0
var/roundstart_damage_max = 0
var/roundstart_damage_times = 1
+ /// Whether or not the spawner is for an inherently hostile survivor subtype.
+ var/hostile = FALSE
var/spawn_priority = LOWEST_SPAWN_PRIORITY
@@ -27,6 +29,7 @@
return TRUE
/obj/effect/landmark/survivor_spawner/lv624_crashed_clf
+ hostile = TRUE
equipment = /datum/equipment_preset/survivor/clf
synth_equipment = /datum/equipment_preset/clf/synth
intro_text = list("You are a survivor of a crash landing!
",\
@@ -40,6 +43,7 @@
spawn_priority = SPAWN_PRIORITY_HIGH
/obj/effect/landmark/survivor_spawner/lv624_crashed_clf_engineer
+ hostile = TRUE
equipment = /datum/equipment_preset/clf/engineer
synth_equipment = /datum/equipment_preset/clf/synth
intro_text = list("You are a survivor of a crash landing!
",\
@@ -53,6 +57,7 @@
spawn_priority = SPAWN_PRIORITY_VERY_HIGH
/obj/effect/landmark/survivor_spawner/lv624_crashed_clf_medic
+ hostile = TRUE
equipment = /datum/equipment_preset/clf/medic
synth_equipment = /datum/equipment_preset/clf/synth
intro_text = list("You are a survivor of a crash landing!
",\
diff --git a/code/game/objects/effects/spawners/random.dm b/code/game/objects/effects/spawners/random.dm
index a70fb5588f..d302e7794f 100644
--- a/code/game/objects/effects/spawners/random.dm
+++ b/code/game/objects/effects/spawners/random.dm
@@ -351,8 +351,7 @@
/obj/effect/spawner/random/gun/proc/spawn_weapon_on_floor(gunpath, ammopath, ammo_amount = 1)
- var/atom/spawnloc = src
- spawnloc = get_turf(spawnloc)
+ var/turf/spawnloc = get_turf(src)
var/obj/gun
var/obj/ammo
@@ -360,20 +359,20 @@
gun = new gunpath(spawnloc)
if(scatter)
var/direction = pick(alldirs)
- var/turf/T = get_step(gun, direction)
- if(!T || T.density)
+ var/turf/turf = get_step(gun, direction)
+ if(!turf || turf.density)
return
- gun.loc = T
+ gun.forceMove(turf)
if(ammopath)
for(var/i in 0 to ammo_amount-1)
ammo = new ammopath(spawnloc)
if(scatter)
for(i=0, i 1 || get_dist(user, H) > 1 || H.lying)
- return
- if (!istype(H))
- return
-
- if(!do_after(user, cuff_delay, INTERRUPT_ALL, BUSY_ICON_HOSTILE, H, INTERRUPT_MOVED, BUSY_ICON_GENERIC))
- return
-
- // TODO: apply handcuffs
-
/obj/item/handcuffs/get_mob_overlay(mob/user_mob, slot)
var/image/ret = ..()
diff --git a/code/game/objects/items/implants/implant.dm b/code/game/objects/items/implants/implant.dm
index d39b7e6754..e7ebe0391f 100644
--- a/code/game/objects/items/implants/implant.dm
+++ b/code/game/objects/items/implants/implant.dm
@@ -82,6 +82,7 @@ Implant Specifics:
"}
return dat
/obj/item/implant/tracking/emp_act(severity)
+ . = ..()
if (malfunction) //no, dawg, you can't malfunction while you are malfunctioning
return
malfunction = MALFUNCTION_TEMPORARY
@@ -216,6 +217,7 @@ Implant Specifics:
"}
return 1
/obj/item/implant/explosive/emp_act(severity)
+ . = ..()
if (malfunction)
return
malfunction = MALFUNCTION_TEMPORARY
@@ -307,6 +309,7 @@ the implant may become unstable and either pre-maturely inject the subject or si
return
/obj/item/implant/chem/emp_act(severity)
+ . = ..()
if (malfunction)
return
malfunction = MALFUNCTION_TEMPORARY
@@ -432,6 +435,7 @@ the implant may become unstable and either pre-maturely inject the subject or si
STOP_PROCESSING(SSobj, src)
/obj/item/implant/death_alarm/emp_act(severity) //for some reason alarms stop going off in case they are emp'd, even without this
+ . = ..()
if (malfunction) //so I'm just going to add a meltdown chance here
return
malfunction = MALFUNCTION_TEMPORARY
diff --git a/code/game/objects/items/implants/implantneurostim.dm b/code/game/objects/items/implants/implantneurostim.dm
index a46cc31a2c..544cf70147 100644
--- a/code/game/objects/items/implants/implantneurostim.dm
+++ b/code/game/objects/items/implants/implantneurostim.dm
@@ -105,6 +105,7 @@
/obj/item/implant/neurostim/emp_act(severity)
+ . = ..()
if (malfunction)
return
if (prob(80))
diff --git a/code/game/objects/items/props/helmetgarb.dm b/code/game/objects/items/props/helmetgarb.dm
index 72c49a0ea1..b20c567150 100644
--- a/code/game/objects/items/props/helmetgarb.dm
+++ b/code/game/objects/items/props/helmetgarb.dm
@@ -99,10 +99,8 @@
var/nvg_maxhealth = 125
var/nvg_health = 125
- var/nvg_maxcharge = 2500
- var/nvg_charge = 2500
- var/nvg_drain = 8 // has a 5 minute duration but byond may give it a couple of irl time due to lag
- var/infinite_charge = FALSE
+ /// How much charge the cell should have at most. -1 is infinite
+ var/cell_max_charge = 2500
var/activated = FALSE
var/nightvision = FALSE
@@ -117,6 +115,13 @@
var/mob/living/attached_mob
var/lighting_alpha = 100
+/obj/item/prop/helmetgarb/helmet_nvg/Initialize(mapload, ...)
+ . = ..()
+ if(shape != NVG_SHAPE_COSMETIC)
+ AddComponent(/datum/component/cell, cell_max_charge, TRUE, charge_drain = 8)
+ RegisterSignal(src, COMSIG_CELL_TRY_RECHARGING, PROC_REF(cell_try_recharge))
+ RegisterSignal(src, COMSIG_CELL_OUT_OF_CHARGE, PROC_REF(on_power_out))
+
/obj/item/prop/helmetgarb/helmet_nvg/on_enter_storage(obj/item/storage/internal/S)
..()
@@ -139,42 +144,30 @@
/obj/item/prop/helmetgarb/helmet_nvg/attackby(obj/item/A as obj, mob/user as mob)
- if(istype(A,/obj/item/cell))
- recharge(A, user)
-
if(HAS_TRAIT(A, TRAIT_TOOL_SCREWDRIVER))
repair(user)
else
..()
-/obj/item/prop/helmetgarb/helmet_nvg/proc/recharge(obj/item/cell/C, mob/user as mob)
+/obj/item/prop/helmetgarb/helmet_nvg/proc/cell_try_recharge(datum/source, mob/living/user)
+ SIGNAL_HANDLER
+
if(user.action_busy)
- return
+ return COMPONENT_CELL_NO_RECHARGE
+
if(src != user.get_inactive_hand())
- to_chat(user, SPAN_WARNING("You need to hold \the [src] in hand in order to recharge them."))
- return
+ to_chat(user, SPAN_WARNING("You need to hold [src] in hand in order to recharge them."))
+ return COMPONENT_CELL_NO_RECHARGE
+
if(shape == NVG_SHAPE_COSMETIC)
- to_chat(user, SPAN_WARNING("There is no connector for the power cell inside \the [src]."))
- return
+ to_chat(user, SPAN_WARNING("There is no connector for the power cell inside [src]."))
+ return COMPONENT_CELL_NO_RECHARGE
+
if(shape == NVG_SHAPE_BROKEN)
- to_chat(user, SPAN_WARNING("You need to repair \the [src] first."))
- return
- if(nvg_charge == nvg_maxcharge)
- to_chat(user, SPAN_WARNING("\The [src] are already fully charged."))
- return
+ to_chat(user, SPAN_WARNING("You need to repair [src] first."))
+ return COMPONENT_CELL_NO_RECHARGE
- while(nvg_charge < nvg_maxcharge)
- if(C.charge <= 0)
- to_chat(user, SPAN_WARNING("\The [C] is completely dry."))
- break
- if(!do_after(user, 1 SECONDS, (INTERRUPT_ALL & (~INTERRUPT_MOVED)), BUSY_ICON_BUILD, C, INTERRUPT_DIFF_LOC))
- to_chat(user, SPAN_WARNING("You were interrupted."))
- break
- var/to_transfer = min(400, C.charge, (nvg_maxcharge - nvg_charge))
- if(C.use(to_transfer))
- nvg_charge += to_transfer
- to_chat(user, "You transfer some power between \the [C] and \the [src]. The gauge now reads: [round(100.0*nvg_charge/nvg_maxcharge) ]%.")
/obj/item/prop/helmetgarb/helmet_nvg/proc/repair(mob/user as mob)
if(user.action_busy)
@@ -202,7 +195,6 @@
to_chat(user, "You successfully patch \the [src].")
nvg_maxhealth = 65
nvg_health = 65
- nvg_drain = initial(nvg_drain) * 2
return
else if(nvg_health == nvg_maxhealth)
@@ -244,9 +236,6 @@
else if(nvg_health_procent >= 0)
. += "They are falling apart."
- if (get_dist(user, src) <= 1 && (shape == NVG_SHAPE_FINE || shape == NVG_SHAPE_PATCHED))
- . += "A small gauge in the corner reads: Power: [round(100.0*nvg_charge/nvg_maxcharge) ]%."
-
/obj/item/prop/helmetgarb/helmet_nvg/on_exit_storage(obj/item/storage/S)
remove_attached_item()
return ..()
@@ -296,7 +285,7 @@
if(attached_mob != user && slot == WEAR_HEAD)
set_attached_mob(user)
- if(slot == WEAR_HEAD && !nightvision && activated && nvg_charge > 0 && shape > NVG_SHAPE_BROKEN)
+ if(slot == WEAR_HEAD && !nightvision && activated && !SEND_SIGNAL(src, COMSIG_CELL_CHECK_CHARGE) && shape > NVG_SHAPE_BROKEN)
enable_nvg(user)
else
remove_nvg()
@@ -319,7 +308,7 @@
attached_item.update_icon()
activation.update_button_icon()
- START_PROCESSING(SSobj, src)
+ SEND_SIGNAL(src, COMSIG_CELL_START_TICK_DRAIN)
/obj/item/prop/helmetgarb/helmet_nvg/proc/update_sight(mob/M)
@@ -353,20 +342,15 @@
attached_mob.update_sight()
- STOP_PROCESSING(SSobj, src)
+ SEND_SIGNAL(src, COMSIG_CELL_STOP_TICK_DRAIN)
/obj/item/prop/helmetgarb/helmet_nvg/process(delta_time)
- if(nvg_charge > 0 && !infinite_charge)
- nvg_charge = max(0, nvg_charge - nvg_drain * delta_time)
-
if(!attached_mob)
return PROCESS_KILL
- if(!activated || !attached_item || nvg_charge <= 0 || attached_mob.is_dead())
- if(activated && !attached_mob.is_dead())
- to_chat(attached_mob, SPAN_WARNING("\The [src] emit a low power warning and immediately shut down!"))
- remove_nvg()
+ if(!activated || !attached_item || attached_mob.is_dead())
+ on_power_out()
return
if(!attached_item.has_garb_overlay())
@@ -375,6 +359,13 @@
return
+/obj/item/prop/helmetgarb/helmet_nvg/proc/on_power_out(datum/source)
+ SIGNAL_HANDLER
+
+ if(activated && !attached_mob.is_dead())
+ to_chat(attached_mob, SPAN_WARNING("[src] emit a low power warning and immediately shut down!"))
+ remove_nvg()
+
/obj/item/prop/helmetgarb/helmet_nvg/ui_action_click(mob/owner, obj/item/holder)
toggle_nods(owner)
@@ -410,7 +401,7 @@
if(activated)
to_chat(user, SPAN_NOTICE("You flip the goggles down."))
icon_state = active_icon_state
- if(nvg_charge > 0 && user.head == attached_item && shape > NVG_SHAPE_BROKEN)
+ if(!SEND_SIGNAL(src, COMSIG_CELL_CHECK_CHARGE) && user.head == attached_item && shape > NVG_SHAPE_BROKEN)
enable_nvg(user)
else
icon_state = active_icon_state
@@ -462,7 +453,7 @@
/obj/item/prop/helmetgarb/helmet_nvg/marsoc //for Marine Raiders
name = "\improper Tactical M3 night vision goggles"
desc = "With an integrated self-recharging battery, nothing can stop you. Put them on your helmet and press the button and it's go-time."
- infinite_charge = TRUE
+ cell_max_charge = -1
#undef NVG_SHAPE_COSMETIC
#undef NVG_SHAPE_BROKEN
@@ -527,29 +518,38 @@
icon = 'icons/obj/items/items.dmi'
icon_state = "photo"
///The human who spawns with the photo
- var/mob/living/carbon/human/owner
+ var/datum/weakref/owner
+ ///The belonging human name
+ var/owner_name
+ ///The belonging human faction
+ var/owner_faction
///Text written on the back
var/scribble
-/obj/item/prop/helmetgarb/family_photo/Initialize(mapload, ...)
+/obj/item/prop/helmetgarb/family_photo/pickup(mob/user, silent)
. = ..()
- if(!mapload)
- RegisterSignal(src, COMSIG_POST_SPAWN_UPDATE, PROC_REF(set_owner))
+ if(!owner)
+ RegisterSignal(user, COMSIG_POST_SPAWN_UPDATE, PROC_REF(set_owner))
+
///Sets the owner of the family photo to the human it spawns with, needs var/source for signals
-/obj/item/prop/helmetgarb/family_photo/proc/set_owner(source = src, mob/living/carbon/human/user)
- UnregisterSignal(src, COMSIG_POST_SPAWN_UPDATE)
- owner = user
+/obj/item/prop/helmetgarb/family_photo/proc/set_owner(datum/source)
+ SIGNAL_HANDLER
+ UnregisterSignal(source, COMSIG_POST_SPAWN_UPDATE)
+ var/mob/living/carbon/human/user = source
+ owner = WEAKREF(user)
+ owner_name = user.name
+ owner_faction = user.faction
/obj/item/prop/helmetgarb/family_photo/get_examine_text(mob/user)
. = ..()
if(scribble)
. += "\"[scribble]\" is written on the back of the photo."
- if(user == owner)
+ if(user.weak_reference == owner)
. += "A photo of you and your family."
return
- if(user.faction == owner?.faction)
- . += "A photo of [owner] and their family."
+ if(user.faction == owner_faction)
+ . += "A photo of [owner_name] and their family."
return
. += "A photo of a family you do not know."
diff --git a/code/game/objects/items/reagent_containers/food/snacks.dm b/code/game/objects/items/reagent_containers/food/snacks.dm
index 2892eb1113..8aae33b5f2 100644
--- a/code/game/objects/items/reagent_containers/food/snacks.dm
+++ b/code/game/objects/items/reagent_containers/food/snacks.dm
@@ -74,6 +74,17 @@
C.overeat_cooldown = world.time + OVEREAT_TIME
if(M == user)//If you're eating it yourself
+
+ var/eat_time = (1.5 SECONDS)
+ if(user.buckled)
+ eat_time *= 0.25
+
+ if(user.action_busy)
+ return
+
+ if(!do_after(user, eat_time, INTERRUPT_ALL, BUSY_ICON_FRIENDLY))
+ return
+
if (fullness <= NUTRITION_VERYLOW)
to_chat(M, SPAN_WARNING("You hungrily chew out a piece of [src] and gobble it!"))
if (fullness > NUTRITION_VERYLOW && fullness <= NUTRITION_LOW)
@@ -91,7 +102,11 @@
SPAN_HELPFUL("[user] starts feeding you [src]."),
SPAN_NOTICE("[user] starts feeding [user == M ? "themselves" : "[M]"] [src]."))
- if(!do_after(user, 30, INTERRUPT_ALL, BUSY_ICON_FRIENDLY, M)) return
+ if(user.action_busy)
+ return
+
+ if(!do_after(user, (3 SECONDS), INTERRUPT_ALL, BUSY_ICON_FRIENDLY, M))
+ return
var/rgt_list_text = get_reagent_list_text()
diff --git a/code/game/objects/items/reagent_containers/glass/bottle.dm b/code/game/objects/items/reagent_containers/glass/bottle.dm
index dd857d391b..01eb751774 100644
--- a/code/game/objects/items/reagent_containers/glass/bottle.dm
+++ b/code/game/objects/items/reagent_containers/glass/bottle.dm
@@ -30,7 +30,7 @@
/obj/item/reagent_container/glass/bottle/Initialize()
. = ..()
if(!icon_state)
- icon_state = "bottle-[rand(1.4)]"
+ icon_state = "bottle-[rand(1,4)]"
/obj/item/reagent_container/glass/bottle/update_icon()
overlays.Cut()
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index d85e615bc1..3912e2d641 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -182,6 +182,11 @@ Also change the icon to reflect the amount of sheets, if possible.*/
to_chat(usr, SPAN_WARNING("The [R.title] cannot be built here!")) //might cause some friendly fire regarding other items like barbed wire, shouldn't be a problem?
return
+ var/obj/structure/tunnel/tunnel = locate(/obj/structure/tunnel) in usr.loc
+ if(tunnel)
+ to_chat(usr, SPAN_WARNING("The [R.title] cannot be constructed on a tunnel!"))
+ return
+
if((R.flags & RESULT_REQUIRES_SNOW) && !(istype(usr.loc, /turf/open/snow) || istype(usr.loc, /turf/open/auto_turf/snow)))
to_chat(usr, SPAN_WARNING("The [R.title] must be built on snow!"))
return
diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm
index 95c5f181cd..4c19cdd0dc 100644
--- a/code/game/objects/items/storage/backpack.dm
+++ b/code/game/objects/items/storage/backpack.dm
@@ -72,9 +72,9 @@
return FALSE
// Create their vis object if needed
- if(!xeno.backpack_icon_carrier)
- xeno.backpack_icon_carrier = new(null, xeno)
- xeno.vis_contents += xeno.backpack_icon_carrier
+ if(!xeno.backpack_icon_holder)
+ xeno.backpack_icon_holder = new(null, xeno)
+ xeno.vis_contents += xeno.backpack_icon_holder
target_mob.put_in_back(src)
return FALSE
@@ -670,6 +670,7 @@
RegisterSignal(H, COMSIG_GRENADE_PRE_PRIME, PROC_REF(cloak_grenade_callback))
RegisterSignal(H, COMSIG_HUMAN_EXTINGUISH, PROC_REF(wrapper_fizzle_camouflage))
+ RegisterSignal(H, COMSIG_MOB_EFFECT_CLOAK_CANCEL, PROC_REF(deactivate_camouflage))
camo_active = TRUE
ADD_TRAIT(H, TRAIT_CLOAKED, TRAIT_SOURCE_EQUIPMENT(WEAR_BACK))
@@ -699,12 +700,14 @@
deactivate_camouflage(wearer, TRUE, TRUE)
/obj/item/storage/backpack/marine/satchel/scout_cloak/proc/deactivate_camouflage(mob/living/carbon/human/H, anim = TRUE, forced)
+ SIGNAL_HANDLER
if(!istype(H))
return FALSE
UnregisterSignal(H, list(
COMSIG_GRENADE_PRE_PRIME,
- COMSIG_HUMAN_EXTINGUISH
+ COMSIG_HUMAN_EXTINGUISH,
+ COMSIG_MOB_EFFECT_CLOAK_CANCEL,
))
if(forced)
@@ -1039,6 +1042,10 @@
max_storage_space = 21
camo_alpha = 10
+/obj/item/storage/backpack/marine/satchel/scout_cloak/upp/weak
+ desc = "A thermo-optic camouflage cloak commonly used by UPP commando units. This one is less effective than normal."
+ actions_types = null
+
//----------TWE SECTION----------
/obj/item/storage/backpack/rmc
has_gamemode_skin = FALSE
diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm
index 6266f0eef7..4a3afa00f3 100644
--- a/code/game/objects/items/storage/boxes.dm
+++ b/code/game/objects/items/storage/boxes.dm
@@ -151,6 +151,7 @@
RegisterSignal(SSdcs, COMSIG_GLOB_MODE_PRESETUP, PROC_REF(handle_delete_clash_contents))
/obj/item/storage/box/flashbangs/proc/handle_delete_clash_contents()
+ SIGNAL_HANDLER
if(MODE_HAS_FLAG(MODE_FACTION_CLASH))
var/grenade_count = 0
var/grenades_desired = 4
diff --git a/code/game/objects/items/storage/pouch.dm b/code/game/objects/items/storage/pouch.dm
index 618356f44a..9bc30c105e 100644
--- a/code/game/objects/items/storage/pouch.dm
+++ b/code/game/objects/items/storage/pouch.dm
@@ -683,6 +683,18 @@
new /obj/item/reagent_container/hypospray/autoinjector/stimulant/redemption_stimulant(src)
new /obj/item/reagent_container/hypospray/autoinjector/stimulant/speed_stimulant(src)
+/obj/item/storage/pouch/medical/socmed/not_op/fill_preset_inventory()
+ new /obj/item/device/healthanalyzer(src)
+ new /obj/item/stack/medical/splint(src)
+ new /obj/item/stack/medical/advanced/bruise_pack(src)
+ new /obj/item/stack/medical/advanced/ointment(src)
+ new /obj/item/reagent_container/hypospray/autoinjector/bicaridine(src)
+ new /obj/item/reagent_container/hypospray/autoinjector/kelotane(src)
+ new /obj/item/reagent_container/hypospray/autoinjector/oxycodone(src)
+ new /obj/item/reagent_container/hypospray/autoinjector/emergency(src)
+ new /obj/item/reagent_container/hypospray/autoinjector/emergency(src)
+ new /obj/item/tool/extinguisher/mini(src)
+
/obj/item/storage/pouch/medical/socmed/dutch
name = "\improper Dutch's Medical Pouch"
desc = "A pouch bought from a black market trader by Dutch quite a few years ago. Rumoured to be stolen from secret USCM assets. Its contents have been slowly used up and replaced over the years."
@@ -833,6 +845,15 @@
new /obj/item/stack/medical/advanced/ointment(src)
new /obj/item/stack/medical/splint(src)
+/obj/item/storage/pouch/medkit/full/toxin/fill_preset_inventory()
+ new /obj/item/device/healthanalyzer(src)
+ new /obj/item/storage/pill_bottle/antitox(src)
+ new /obj/item/storage/pill_bottle/antitox(src)
+ new /obj/item/roller(src)
+ new /obj/item/stack/medical/splint(src)
+ new /obj/item/stack/medical/advanced/bruise_pack(src)
+ new /obj/item/stack/medical/advanced/ointment(src)
+
/obj/item/storage/pouch/pressurized_reagent_canister
name = "Pressurized Reagent Canister Pouch"
max_w_class = SIZE_SMALL
diff --git a/code/game/objects/items/storage/smartpack.dm b/code/game/objects/items/storage/smartpack.dm
index 8df079c92c..0b0fd05eac 100644
--- a/code/game/objects/items/storage/smartpack.dm
+++ b/code/game/objects/items/storage/smartpack.dm
@@ -144,7 +144,7 @@
immobile_form = FALSE
M.status_flags |= CANPUSH
M.anchored = FALSE
- M.unfreeze()
+ REMOVE_TRAIT(M, TRAIT_IMMOBILIZED, TRAIT_SOURCE_EQUIPMENT(WEAR_BACK))
..()
/obj/item/storage/backpack/marine/smartpack/attack_self(mob/user)
@@ -236,7 +236,7 @@
battery_charge -= IMMOBILE_COST
user.status_flags &= ~CANPUSH
user.anchored = TRUE
- user.frozen = TRUE
+ ADD_TRAIT(user, TRAIT_IMMOBILIZED, TRAIT_SOURCE_EQUIPMENT(WEAR_BACK))
to_chat(user, SPAN_DANGER("[name] beeps, \"You are anchored in place and cannot be moved.\""))
to_chat(user, SPAN_INFO("The current charge reads [battery_charge]/[SMARTPACK_MAX_POWER_STORED]"))
@@ -248,7 +248,7 @@
else
user.status_flags |= CANPUSH
user.anchored = FALSE
- user.unfreeze()
+ REMOVE_TRAIT(user, TRAIT_IMMOBILIZED, TRAIT_SOURCE_EQUIPMENT(WEAR_BACK))
to_chat(user, SPAN_DANGER("[name] beeps, \"You can now move again.\""))
user.remove_filter("synth_immobile_form")
diff --git a/code/game/objects/items/storage/storage.dm b/code/game/objects/items/storage/storage.dm
index e3fbe86c0e..6e7e891d6b 100644
--- a/code/game/objects/items/storage/storage.dm
+++ b/code/game/objects/items/storage/storage.dm
@@ -22,7 +22,7 @@
var/atom/movable/screen/storage/storage_start = null //storage UI
var/atom/movable/screen/storage/storage_continue = null
var/atom/movable/screen/storage/storage_end = null
- var/datum/item_storage_box/stored_ISB = null // This contains what previously was known as stored_start, stored_continue, and stored_end
+ var/datum/item_storage_box/stored_ISB //! This contains what previously was known as stored_start, stored_continue, and stored_end
var/atom/movable/screen/close/closer = null
var/foldable = null
var/use_sound = "rustle" //sound played when used. null for no sound.
@@ -212,16 +212,17 @@
if (storage_flags & STORAGE_SHOW_FULLNESS)
boxes.update_fullness(src)
-var/list/global/item_storage_box_cache = list()
+GLOBAL_LIST_EMPTY_TYPED(item_storage_box_cache, /datum/item_storage_box)
/datum/item_storage_box
- var/atom/movable/screen/storage/start = null
- var/atom/movable/screen/storage/continued = null
- var/atom/movable/screen/storage/end = null
- /// The index that indentifies me inside item_storage_box_cache
+ var/atom/movable/screen/storage/start
+ var/atom/movable/screen/storage/continued
+ var/atom/movable/screen/storage/end
+ /// The index that indentifies me inside GLOB.item_storage_box_cache
var/index
/datum/item_storage_box/New()
+ . = ..()
start = new()
start.icon_state = "stored_start"
continued = new()
@@ -233,7 +234,7 @@ var/list/global/item_storage_box_cache = list()
QDEL_NULL(start)
QDEL_NULL(continued)
QDEL_NULL(end)
- item_storage_box_cache[index] = null // Or would it be better to -= src?
+ GLOB.item_storage_box_cache -= index
return ..()
/obj/item/storage/proc/space_orient_objs(list/obj/item/display_contents)
@@ -271,7 +272,7 @@ var/list/global/item_storage_box_cache = list()
click_border_start.Add(startpoint)
click_border_end.Add(endpoint)
- if(!item_storage_box_cache[isb_index])
+ if(!GLOB.item_storage_box_cache[isb_index])
var/datum/item_storage_box/box = new()
var/matrix/M_start = matrix()
var/matrix/M_continue = matrix()
@@ -284,9 +285,9 @@ var/list/global/item_storage_box_cache = list()
box.continued.apply_transform(M_continue)
box.end.apply_transform(M_end)
box.index = isb_index
- item_storage_box_cache[isb_index] = box
+ GLOB.item_storage_box_cache[isb_index] = box
- var/datum/item_storage_box/ISB = item_storage_box_cache[isb_index]
+ var/datum/item_storage_box/ISB = GLOB.item_storage_box_cache[isb_index]
stored_ISB = ISB
storage_start.overlays += ISB.start
@@ -851,6 +852,7 @@ W is always an item. stop_warning prevents messaging. user may be null.**/
return ..()
/obj/item/storage/emp_act(severity)
+ . = ..()
if(!istype(src.loc, /mob/living))
for(var/obj/O in contents)
O.emp_act(severity)
diff --git a/code/game/objects/items/tools/misc_tools.dm b/code/game/objects/items/tools/misc_tools.dm
index 98dc89321d..0b4a7cc987 100644
--- a/code/game/objects/items/tools/misc_tools.dm
+++ b/code/game/objects/items/tools/misc_tools.dm
@@ -284,21 +284,24 @@
matter = list("metal" = 20, "gold" = 10)
var/static/list/colour_list = list("red", "blue", "green", "yellow", "purple", "pink", "brown", "black", "orange") // Can add more colors as required
var/current_colour_index = 1
- var/owner = "hard to read text"
+ var/owner_name
-/obj/item/tool/pen/fountain/Initialize(mapload, ...)
+/obj/item/tool/pen/fountain/pickup(mob/user, silent)
. = ..()
- if(!mapload)
- RegisterSignal(src, COMSIG_POST_SPAWN_UPDATE, PROC_REF(set_owner))
+ if(!owner_name)
+ RegisterSignal(user, COMSIG_POST_SPAWN_UPDATE, PROC_REF(set_owner))
///Sets the owner of the pen to who it spawns with, requires var/source for signals
-/obj/item/tool/pen/fountain/proc/set_owner(source = src, mob/living/carbon/human/user)
- UnregisterSignal(src, COMSIG_POST_SPAWN_UPDATE)
- owner = user
+/obj/item/tool/pen/fountain/proc/set_owner(datum/source)
+ SIGNAL_HANDLER
+ UnregisterSignal(source, COMSIG_POST_SPAWN_UPDATE)
+ var/mob/living/carbon/human/user = source
+ owner_name = user.name
/obj/item/tool/pen/fountain/get_examine_text(mob/user)
. = ..()
- . += "There's a laser engraving of [owner] on it."
+ if(owner_name)
+ . += "There's a laser engraving of [owner_name] on it."
/obj/item/tool/pen/fountain/attack_self(mob/living/carbon/human/user)
if(on)
diff --git a/code/game/objects/items/toys/cards.dm b/code/game/objects/items/toys/cards.dm
index b6e3bb558e..2debd83f9b 100644
--- a/code/game/objects/items/toys/cards.dm
+++ b/code/game/objects/items/toys/cards.dm
@@ -21,7 +21,6 @@
icon = 'icons/obj/items/playing_cards.dmi'
icon_state = "deck"
w_class = SIZE_TINY
- flags_item = NOTABLEMERGE
var/base_icon = "deck"
var/max_cards = 52
@@ -262,7 +261,6 @@
icon = 'icons/obj/items/playing_cards.dmi'
icon_state = "empty"
w_class = SIZE_TINY
- flags_item = NOTABLEMERGE
var/concealed = FALSE
var/pile_state = FALSE
diff --git a/code/game/objects/items/toys/toys.dm b/code/game/objects/items/toys/toys.dm
index 7a17904635..851f203c52 100644
--- a/code/game/objects/items/toys/toys.dm
+++ b/code/game/objects/items/toys/toys.dm
@@ -553,15 +553,15 @@
///Hexadecimal 0-F (0-15)
var/static/list/hexadecimal = list("0", "1", "2", "3" , "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")
-/obj/item/toy/plush/therapy/random_color/New(loc, ...)
+/obj/item/toy/plush/therapy/random_color/Initialize(mapload, ...)
. = ..()
var/color_code = "#[pick(hexadecimal)][pick(hexadecimal)][pick(hexadecimal)][pick(hexadecimal)][pick(hexadecimal)][pick(hexadecimal)]" //This is dumb and I hope theres a better way I'm missing
color = color_code
- desc = "A custom therapy plush, in a unique color. This one is labeled with \"#[color_code]\"."
+ desc = "A custom therapy plush, in a unique color."
/obj/item/toy/plush/random_plushie //Not using an effect so it can fit into storage from loadout
name = "random plush"
- desc = "You should not be seeing this"
+ desc = "This plush looks awfully standard and bland. Is it actually yours?"
/// Standard plushies for the spawner to pick from
var/list/plush_list = list(
/obj/item/toy/plush/farwa,
@@ -587,22 +587,32 @@
. = ..()
if(mapload) //Placed in mapping, will be randomized instantly on spawn
create_plushie()
- return
- RegisterSignal(src, COMSIG_POST_SPAWN_UPDATE, PROC_REF(create_plushie))
+ return INITIALIZE_HINT_QDEL
+
+/obj/item/toy/plush/random_plushie/pickup(mob/user, silent)
+ . = ..()
+ RegisterSignal(user, COMSIG_POST_SPAWN_UPDATE, PROC_REF(create_plushie))
///The randomizer picking and spawning a plushie on either the ground or in the humans backpack. Needs var/source due to signals
-/obj/item/toy/plush/random_plushie/proc/create_plushie(source = src, mob/living/user)
- UnregisterSignal(src, COMSIG_POST_SPAWN_UPDATE)
+/obj/item/toy/plush/random_plushie/proc/create_plushie(datum/source)
+ SIGNAL_HANDLER
+ if(source)
+ UnregisterSignal(source, COMSIG_POST_SPAWN_UPDATE)
+ var/turf/spawn_location = get_turf(src)
var/plush_list_variety = pick(60; plush_list, 40; therapy_plush_list)
var/random_plushie = pick(plush_list_variety)
- var/obj/item/toy/plush/plush = new random_plushie(get_turf(src)) //Starts on floor by default
+ var/obj/item/toy/plush/plush = new random_plushie(spawn_location) //Starts on floor by default
+ var/mob/living/carbon/human/user = source
if(!user) //If it didn't spawn on a humanoid
qdel(src)
return
+
var/obj/item/storage/backpack/storage = locate() in user //If the user has a backpack, put it there
if(storage?.can_be_inserted(plush, user, stop_messages = TRUE))
storage.attempt_item_insertion(plush, TRUE, user)
+ if(plush.loc == spawn_location) // Still on the ground
+ user.put_in_hands(plush, drop_on_fail = TRUE)
qdel(src)
//Admin plushies
diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm
index 6cb9f58aae..82fdf30f0f 100644
--- a/code/game/objects/items/weapons/stunbaton.dm
+++ b/code/game/objects/items/weapons/stunbaton.dm
@@ -197,9 +197,9 @@
return TRUE
/obj/item/weapon/baton/emp_act(severity)
+ . = ..()
if(bcell)
bcell.emp_act(severity) //let's not duplicate code everywhere if we don't have to please.
- ..()
//secborg stun baton module
/obj/item/weapon/baton/robot/attack_self(mob/user)
diff --git a/code/game/objects/prop.dm b/code/game/objects/prop.dm
index e59c24b30d..c067a9730e 100644
--- a/code/game/objects/prop.dm
+++ b/code/game/objects/prop.dm
@@ -11,6 +11,66 @@
w_class = SIZE_SMALL
garbage = TRUE
+/obj/item/prop/geiger_counter
+ name = "geiger counter"
+ desc = "A geiger counter measures the radiation it receives. This type automatically records and transfers any information it reads, provided it has a battery, with no user input required beyond being enabled."
+ icon = 'icons/obj/items/devices.dmi'
+ icon_state = "geiger"
+ item_state = ""
+ w_class = SIZE_SMALL
+ flags_equip_slot = SLOT_WAIST
+ ///Whether the geiger counter is on or off
+ var/toggled_on = FALSE
+ ///Iconstate of geiger counter when on
+ var/enabled_state = "geiger_on"
+ ///Iconstate of geiger counter when off
+ var/disabled_state = "geiger"
+ ///New battery it will spawn with
+ var/starting_battery = /obj/item/cell/crap
+ ///Battery inside geiger counter
+ var/obj/item/cell/battery //It doesn't drain the battery, but it has a battery for emergency use
+
+/obj/item/prop/geiger_counter/Initialize(mapload, ...)
+ . = ..()
+ if(!starting_battery)
+ return
+ battery = new starting_battery(src)
+
+/obj/item/prop/geiger_counter/Destroy()
+ . = ..()
+ if(battery)
+ qdel(battery)
+
+/obj/item/prop/geiger_counter/attack_self(mob/user)
+ . = ..()
+ toggled_on = !toggled_on
+ if(!battery)
+ to_chat(user, SPAN_NOTICE("[src] is missing a battery."))
+ return
+ to_chat(user, SPAN_NOTICE("You [toggled_on ? "enable" : "disable"] [src]."))
+ update_icon()
+
+/obj/item/prop/geiger_counter/attackby(obj/item/attacking_item, mob/user)
+ . = ..()
+ if(!HAS_TRAIT(attacking_item, TRAIT_TOOL_SCREWDRIVER) && !HAS_TRAIT(attacking_item, TRAIT_TOOL_CROWBAR))
+ return
+
+ if(!battery)
+ to_chat(user, SPAN_NOTICE("There is no battery for you to remove."))
+ return
+ to_chat(user, SPAN_NOTICE("You jam [battery] out of [src] with [attacking_item], prying it out irreversibly."))
+ user.put_in_hands(battery)
+ battery = null
+ update_icon()
+
+/obj/item/prop/geiger_counter/update_icon()
+ . = ..()
+
+ if(battery && toggled_on)
+ icon_state = enabled_state
+ return
+ icon_state = disabled_state
+
/obj/item/prop/tableflag
name = "United Americas table flag"
icon = 'icons/obj/items/items.dmi'
diff --git a/code/game/objects/structures/beacons/deployable_beacons.dm b/code/game/objects/structures/beacons/deployable_beacons.dm
index f355aa3ba7..bcff248eb7 100644
--- a/code/game/objects/structures/beacons/deployable_beacons.dm
+++ b/code/game/objects/structures/beacons/deployable_beacons.dm
@@ -20,11 +20,13 @@
visible_message(SPAN_NOTICE("[src] beeps quietly as it begins broadcasting preprogrammed signals."))
+ set_light(2, 1, beacon_light_color)
+
for(var/client/admin_client in GLOB.admins)
if((R_ADMIN|R_MOD) & admin_client.admin_holder.rights)
playsound_client(admin_client,'sound/effects/sos-morse-code.ogg',10)
- message_admins("[key_name(user)] has deployed [src]! [ADMIN_JMP_USER(user)]")
+ message_admins("[key_name(user)] has deployed [src]! [ADMIN_JMP(src)]")
/obj/structure/deployable_beacon/attackby(obj/item/attacking_item, mob/user)
if(!HAS_TRAIT(attacking_item, TRAIT_TOOL_MULTITOOL))
@@ -39,7 +41,18 @@
visible_message(SPAN_NOTICE("[src] gives a drone as it powers down and collapses into itself for easier carrying."))
var/obj/item/deployable_beacon/undeployed_beacon = new beacon_type()
- transfer_label_component(undeployed_beacon)
+
+ var/datum/component/label/src_label_component = GetComponent(/datum/component/label)
+ var/label_text
+ if(src_label_component)
+ label_text = src_label_component.label_name
+ src_label_component.remove_label()
+
+ undeployed_beacon.name = name
+ undeployed_beacon.desc = desc
+
+ if(label_text)
+ undeployed_beacon.AddComponent(/datum/component/label, label_text)
user.put_in_hands(undeployed_beacon)
diff --git a/code/game/objects/structures/blocker.dm b/code/game/objects/structures/blocker.dm
index 284daf0028..f85b1e65ff 100644
--- a/code/game/objects/structures/blocker.dm
+++ b/code/game/objects/structures/blocker.dm
@@ -105,9 +105,21 @@
/obj/structure/blocker/forcefield/vehicles
types = list(/obj/vehicle/)
+
+/obj/structure/blocker/forcefield/vehicles/handle_vehicle_bump(obj/vehicle/multitile/multitile_vehicle)
+ if(multitile_vehicle.vehicle_flags & VEHICLE_BYPASS_BLOCKERS)
+ return TRUE
+ return FALSE
+
/obj/structure/blocker/forcefield/multitile_vehicles
types = list(/obj/vehicle/multitile/)
+
+/obj/structure/blocker/forcefield/multitile_vehicles/handle_vehicle_bump(obj/vehicle/multitile/multitile_vehicle)
+ if(multitile_vehicle.vehicle_flags & VEHICLE_BYPASS_BLOCKERS)
+ return TRUE
+ return FALSE
+
/obj/structure/blocker/forcefield/human
types = list(/mob/living/carbon/human)
icon_state = "purple_line"
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm
index e290a23a61..331cb884bd 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm
@@ -30,6 +30,7 @@
return 0
/obj/structure/closet/secure_closet/emp_act(severity)
+ . = ..()
for(var/obj/O in src)
O.emp_act(severity)
if(!broken)
@@ -42,7 +43,6 @@
else
src.req_access = list()
src.req_access += pick(get_access(ACCESS_LIST_MARINE_MAIN))
- ..()
/obj/structure/closet/secure_closet/proc/togglelock(mob/living/user)
if(src.opened)
diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm
index 9f0417ccb3..119615ab7a 100644
--- a/code/game/objects/structures/crates_lockers/crates.dm
+++ b/code/game/objects/structures/crates_lockers/crates.dm
@@ -12,6 +12,19 @@
throwpass = 1 //prevents moving crates by hurling things at them
store_mobs = FALSE
var/rigged = 0
+ /// Types this crate can be made into
+ var/list/crate_customizing_types = list(
+ "Plain" = /obj/structure/closet/crate,
+ "Weapons" = /obj/structure/closet/crate/weapon,
+ "Supply" = /obj/structure/closet/crate/supply,
+ "Ammo" = /obj/structure/closet/crate/ammo,
+ "Construction" = /obj/structure/closet/crate/construction,
+ "Explosives" = /obj/structure/closet/crate/explosives,
+ "Alpha" = /obj/structure/closet/crate/alpha,
+ "Bravo" = /obj/structure/closet/crate/bravo,
+ "Charlie" = /obj/structure/closet/crate/charlie,
+ "Delta" = /obj/structure/closet/crate/delta,
+ )
/obj/structure/closet/crate/initialize_pass_flags(datum/pass_flags_container/PF)
..()
@@ -207,6 +220,7 @@
icon_state = "closed_freezer"
icon_opened = "open_freezer"
icon_closed = "closed_freezer"
+ crate_customizing_types = null
var/target_temp = T0C - 40
var/cooling_power = 40
diff --git a/code/game/objects/structures/crates_lockers/secure_crates.dm b/code/game/objects/structures/crates_lockers/secure_crates.dm
index a308c4c0a2..28a77e0c81 100644
--- a/code/game/objects/structures/crates_lockers/secure_crates.dm
+++ b/code/game/objects/structures/crates_lockers/secure_crates.dm
@@ -4,6 +4,7 @@
icon_state = "secure_locked_basic"
icon_opened = "secure_open_basic"
icon_closed = "secure_locked_basic"
+ crate_customizing_types = null
var/icon_locked = "secure_locked_basic"
var/icon_unlocked = "secure_unlocked_basic"
var/sparks = "securecratesparks"
@@ -86,6 +87,7 @@
..()
/obj/structure/closet/crate/secure/emp_act(severity)
+ . = ..()
for(var/obj/O in src)
O.emp_act(severity)
if(!broken && !opened && prob(50/severity))
@@ -105,7 +107,6 @@
else
src.req_access = list()
src.req_access += pick(get_access(ACCESS_LIST_MARINE_MAIN))
- ..()
//------------------------------------
diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm
index 5220e3d832..7b01243290 100644
--- a/code/game/objects/structures/flora.dm
+++ b/code/game/objects/structures/flora.dm
@@ -73,6 +73,7 @@ PLANT_CUT_MACHETE = 3 = Needs at least a machete to be cut down
addtimer(CALLBACK(src, PROC_REF(burn_up)), spread_time + 5 SECONDS)
/obj/structure/flora/proc/spread_fire()
+ SIGNAL_HANDLER
for(var/D in cardinal) //Spread fire
var/turf/T = get_step(src.loc, D)
if(T)
@@ -83,6 +84,7 @@ PLANT_CUT_MACHETE = 3 = Needs at least a machete to be cut down
new /obj/flamer_fire(T, create_cause_data("wildfire"))
/obj/structure/flora/proc/burn_up()
+ SIGNAL_HANDLER
new /obj/effect/decal/cleanable/dirt(loc)
if(center)
new /obj/effect/decal/cleanable/dirt(loc) //Produces more ash at the center
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index e719359ab4..6cd6a5cd03 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -173,6 +173,14 @@
return do_reinforced_wall(W, user)
if(STATE_DISPLACED)
if(HAS_TRAIT(W, TRAIT_TOOL_CROWBAR))
+ var/turf/open/floor = loc
+ if(!floor.allow_construction)
+ to_chat(user, SPAN_WARNING("The girder must be secured on a proper surface!"))
+ return
+ var/obj/structure/tunnel/tunnel = locate(/obj/structure/tunnel) in loc
+ if(tunnel)
+ to_chat(user, SPAN_WARNING("The girder cannot be secured on a tunnel!"))
+ return
playsound(loc, 'sound/items/Crowbar.ogg', 25, 1)
to_chat(user, SPAN_NOTICE("Now securing the girder..."))
if(!do_after(user, 40 * user.get_skill_duration_multiplier(SKILL_CONSTRUCTION), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm
index b05990725e..e203bfc67a 100644
--- a/code/game/objects/structures/morgue.dm
+++ b/code/game/objects/structures/morgue.dm
@@ -113,7 +113,7 @@
else
. = ..()
-/obj/structure/morgue/relaymove(mob/user)
+/obj/structure/morgue/relaymove(mob/living/user)
if(user.is_mob_incapacitated())
return
if(exit_stun)
diff --git a/code/game/objects/structures/signs.dm b/code/game/objects/structures/signs.dm
index 6c1582f112..765c717c6b 100644
--- a/code/game/objects/structures/signs.dm
+++ b/code/game/objects/structures/signs.dm
@@ -108,6 +108,11 @@
desc = "This banner depicts Delta Squad's motto. The Marines of Delta Squad adopted it after picking an old bomber movie for movie night a while back."
icon_state = "maximumeffort"
+/obj/structure/sign/banners/united_americas_flag
+ name = "\improper United Americas flag"
+ desc = "A flag of the United Americas. Inspires patriotism, fear, or revulsion depending on the viewer's political leanings."
+ icon_state = "ua_flag"
+
//=====================//
// SEMIOTIC STANDARD //
//===================//
@@ -571,7 +576,7 @@
/obj/structure/sign/ROsign
name = "\improper USCM Requisitions Office Guidelines"
- desc = " 1. You are not entitled to service or equipment. Attachments are a privilege, not a right.\n 2. You must be fully dressed to obtain service. Cyrosleep underwear is non-permissible.\n 3. The Requsitions Officer has the final say and the right to decline service. Only the Acting Commanding Officer may override their decisions.\n 4. Please treat your Requsitions staff with respect. They work hard."
+ desc = " 1. You are not entitled to service or equipment. Attachments are a privilege, not a right.\n 2. You must be fully dressed to obtain service. Cryosleep underwear is non-permissible.\n 3. The Quartermaster has the final say and the right to decline service. Only the Acting Commanding Officer may override their decisions.\n 4. Please treat your Requsitions staff with respect. They work hard."
icon_state = "roplaque"
/obj/structure/sign/prop1
diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm
index 7979994915..bc3b4ad7f4 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm
@@ -404,7 +404,17 @@ var/global/list/activated_medevac_stretchers = list()
//bedroll
/obj/structure/bed/bedroll
- name = "bedroll"
- desc = "bedroll"
+ name = "unfolded bedroll"
+ desc = "Perfect for those long missions, when there's nowhere else to sleep, you remembered to bring at least one thing of comfort."
+ icon = 'icons/monkey_icos.dmi'
icon_state = "bedroll_o"
+ buckling_y = 0
+ foldabletype = /obj/item/roller/bedroll
+ accepts_bodybag = FALSE
+
+/obj/item/roller/bedroll
+ name = "folded bedroll"
+ desc = "A standard issue USCMC bedroll, They've been in service for as long as you can remember. The tag on it states to unfold it before rest, but who needs rules anyway, right?"
icon = 'icons/monkey_icos.dmi'
+ icon_state = "bedroll"
+ rollertype = /obj/structure/bed/bedroll
diff --git a/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm b/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm
index 7a4274c2c1..6375fcd138 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm
@@ -53,7 +53,7 @@
current_mob.pixel_y = buckling_y["[dir]"]
current_mob.pixel_x = buckling_x["[dir]"]
current_mob.dir = turn(dir, 180)
- current_mob.density = FALSE
+ ADD_TRAIT(current_mob, TRAIT_UNDENSE, XENO_NEST_TRAIT)
pixel_y = buckling_y["[dir]"]
pixel_x = buckling_x["[dir]"]
if(dir == SOUTH)
@@ -67,7 +67,7 @@
current_mob.pixel_y = initial(buckled_mob.pixel_y)
current_mob.pixel_x = initial(buckled_mob.pixel_x)
- current_mob.density = !(current_mob.lying || current_mob.stat == DEAD)
+ REMOVE_TRAIT(current_mob, TRAIT_UNDENSE, XENO_NEST_TRAIT)
if(dir == SOUTH)
current_mob.layer = initial(current_mob.layer)
if(!ishuman(current_mob))
diff --git a/code/game/objects/structures/surface.dm b/code/game/objects/structures/surface.dm
index efc6900242..13a81af2dc 100644
--- a/code/game/objects/structures/surface.dm
+++ b/code/game/objects/structures/surface.dm
@@ -1,159 +1,20 @@
//Surface structures are structures that can have items placed on them
/obj/structure/surface
health = 100
- var/list/update_types = list(
- /obj/item/reagent_container/glass,
- /obj/item/storage,
- /obj/item/reagent_container/food/snacks
- )
- //add items there that behave like structures for whatever dumb reason
- var/list/blacklisted_item_types = list(
- /obj/item/device/radio/intercom,
- /obj/item/device/sentry_computer
- )
-/obj/structure/surface/Initialize()
- . = ..()
- return INITIALIZE_HINT_LATELOAD
-
-/obj/structure/surface/LateInitialize()
- attach_all()
- update_icon()
-
-/obj/structure/surface/Destroy()
- detach_all()
- . = ..()
-
-/obj/structure/surface/ex_act(severity, direction, datum/cause_data/cause_data)
- health -= severity
- if(health <= 0)
- var/location = get_turf(src)
- handle_debris(severity, direction)
- detach_all()
- for(var/obj/item/O in loc)
- O.explosion_throw(severity, direction)
- qdel(src)
- if(prob(66))
- create_shrapnel(location, rand(1,4), direction, , /datum/ammo/bullet/shrapnel/light, cause_data)
- return TRUE
-
-/obj/structure/surface/proc/attach_all()
- for(var/obj/item/O in loc)
- if(in_blacklist(O))
- continue
- attach_item(O, FALSE)
- draw_item_overlays()
-
-/obj/structure/surface/proc/in_blacklist(obj/item/O)
- for(var/allowed_type in blacklisted_item_types)
- if(istype(O, allowed_type))
- return TRUE
- return FALSE
-
-/obj/structure/surface/proc/attach_item(obj/item/O, update = TRUE)
- if(!O)
+/obj/structure/surface/attackby(obj/item/attacking_item, mob/user, click_data)
+ if(!user.drop_inv_item_to_loc(attacking_item, loc))
return
- if(O.luminosity) //it can't make light as an overlay
- return
- O.forceMove(src)
- RegisterSignal(O, COMSIG_ATOM_DECORATED, PROC_REF(decorate_update))
- if(update)
- draw_item_overlays()
-
-/obj/structure/surface/proc/detach_item(obj/item/O)
- O.scatter_item()
- UnregisterSignal(O, COMSIG_ATOM_DECORATED)
- draw_item_overlays()
- return
-
-/obj/structure/surface/proc/decorate_update(obj/item/O)
- SIGNAL_HANDLER
- draw_item_overlays()
-/obj/structure/surface/proc/detach_all()
- overlays.Cut()
- for(var/obj/item/O in contents)
- UnregisterSignal(O, COMSIG_ATOM_DECORATED)
- O.forceMove(loc)
+ auto_align(attacking_item, click_data)
+ user.next_move = world.time + 2
+ return TRUE
-/obj/structure/surface/proc/get_item(list/click_data)
- var/i = LAZYLEN(contents)
- if(!click_data)
- return
- if(i < 1)
- return FALSE
- for(i, i >= 1, i--)//starting from the end because that's where the topmost is
- var/obj/item/O = contents[i]
- var/bounds_x = text2num(click_data["icon-x"])-1 - O.pixel_x
- var/bounds_y = text2num(click_data["icon-y"])-1 - O.pixel_y
- if(bounds_x < 0 || bounds_y < 0)
- continue
- var/icon/I = icon(O.icon, O.icon_state)
- var/p = I.GetPixel(bounds_x, bounds_y)
- if(p)
- return O
- return FALSE
-
-/obj/structure/surface/proc/draw_item_overlays()
- overlays.Cut()
- for(var/obj/item/O in contents)
- var/image/I = image(O.icon)
- I.appearance = O.appearance
- I.appearance_flags |= RESET_COLOR
- I.overlays = O.overlays
- LAZYADD(overlays, I)
-
-/obj/structure/surface/clicked(mob/user, list/mods)
- if(mods["shift"] && !mods["middle"])
- var/obj/item/O = get_item(mods)
- if(!O)
- return ..()
- if(O.can_examine(user))
- O.examine(user)
- return TRUE
- ..()
-
-/obj/structure/surface/proc/try_to_open_container(mob/user, mods)
- if(!Adjacent(user))
- return
-
- if(ishuman(user) || isrobot(user))
- var/obj/item/O = get_item(mods)
- if(O && isstorage(O))
- var/obj/item/storage/S = O
- S.open(usr)
- return TRUE
-
-/obj/structure/surface/attack_hand(mob/user, click_data)
- . = ..()
- if(click_data && click_data["alt"])
- return
- var/obj/item/O = get_item(click_data)
- if(!O)
- return
- O.attack_hand(user)
- if(!LAZYISIN(contents, O))//in case attack_hand did not pick up the item
- detach_item(O)
-
-/obj/structure/surface/attackby(obj/item/W, mob/user, click_data)
- var/obj/item/O = get_item(click_data)
- if(!O || click_data["ctrl"])//holding the ctrl key will force it to place the object
- // Placing stuff on tables
- if(user.drop_inv_item_to_loc(W, loc))
- auto_align(W, click_data)
- user.next_move = world.time + 2
- return TRUE
- else if(!O.attackby(W, user))
- W.afterattack(O, user, TRUE)
- for(var/type in update_types)
- if(istype(O, type))
- draw_item_overlays()
-
-/obj/structure/surface/proc/auto_align(obj/item/W, click_data)
- if(!W.center_of_mass) // Clothing, material stacks, generally items with large sprites where exact placement would be unhandy.
- W.pixel_x = rand(-W.randpixel, W.randpixel)
- W.pixel_y = rand(-W.randpixel, W.randpixel)
- W.pixel_z = 0
+/obj/structure/surface/proc/auto_align(obj/item/new_item, click_data)
+ if(!new_item.center_of_mass) // Clothing, material stacks, generally items with large sprites where exact placement would be unhandy.
+ new_item.pixel_x = rand(-new_item.randpixel, new_item.randpixel)
+ new_item.pixel_y = rand(-new_item.randpixel, new_item.randpixel)
+ new_item.pixel_z = 0
return
if(!click_data)
@@ -169,16 +30,8 @@
var/cell_x = Clamp(round(mouse_x/CELLSIZE), 0, CELLS-1) // Ranging from 0 to CELLS-1
var/cell_y = Clamp(round(mouse_y/CELLSIZE), 0, CELLS-1)
- var/list/center = cached_key_number_decode(W.center_of_mass)
-
- W.pixel_x = (CELLSIZE * (cell_x + 0.5)) - center["x"]
- W.pixel_y = (CELLSIZE * (cell_y + 0.5)) - center["y"]
- W.pixel_z = 0
-
- if(!(W.flags_item & NOTABLEMERGE))
- attach_item(W)
+ var/list/center = cached_key_number_decode(new_item.center_of_mass)
-/obj/structure/surface/MouseDrop(atom/over)
- . = ..()
- if(over == usr && usr && usr.client && usr.client.lmb_last_mousedown_mods)
- return try_to_open_container(usr, usr.client.lmb_last_mousedown_mods)
+ new_item.pixel_x = (CELLSIZE * (cell_x + 0.5)) - center["x"]
+ new_item.pixel_y = (CELLSIZE * (cell_y + 0.5)) - center["y"]
+ new_item.pixel_z = 0
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index db3ce98339..8d6441293f 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -434,8 +434,6 @@
verbs -= /obj/structure/surface/table/verb/do_flip
verbs += /obj/structure/surface/table/proc/do_put
- detach_all()
-
var/list/targets = list(get_step(src, dir), get_step(src, turn(dir, 45)), get_step(src, turn(dir, -45)))
for(var/atom/movable/movable_on_table in get_turf(src))
if(!movable_on_table.anchored)
@@ -479,7 +477,6 @@
var/obj/structure/surface/table/T = locate() in get_step(src.loc,D)
if(T && T.flipped && T.dir == src.dir)
T.unflip()
- attach_all()
update_icon()
update_adjacent()
diff --git a/code/game/objects/structures/vulture_spotter.dm b/code/game/objects/structures/vulture_spotter.dm
index 50505ab239..44efd5ce84 100644
--- a/code/game/objects/structures/vulture_spotter.dm
+++ b/code/game/objects/structures/vulture_spotter.dm
@@ -92,7 +92,7 @@
user.lighting_alpha = 127
user.sync_lighting_plane_alpha()
user.overlay_fullscreen("vulture_spotter", /atom/movable/screen/fullscreen/vulture/spotter)
- user.freeze()
+ ADD_TRAIT(user, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Vulture spotter"))
user.status_flags |= IMMOBILE_ACTION
user.visible_message(SPAN_NOTICE("[user] looks through [src]."),SPAN_NOTICE("You look through [src], ready to go!"))
user.forceMove(loc)
@@ -105,7 +105,7 @@
/obj/structure/vulture_spotter_tripod/on_unset_interaction(mob/user)
user.status_flags &= ~IMMOBILE_ACTION
user.visible_message(SPAN_NOTICE("[user] looks up from [src]."),SPAN_NOTICE("You look up from [src]."))
- user.unfreeze()
+ REMOVE_TRAIT(user, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Vulture spotter"))
user.reset_view(null)
user.Move(get_step(src, reverse_direction(src.dir)))
user.client?.change_view(world_view_size, src)
diff --git a/code/game/supplyshuttle.dm b/code/game/supplyshuttle.dm
index 4cef619893..2e3a536536 100644
--- a/code/game/supplyshuttle.dm
+++ b/code/game/supplyshuttle.dm
@@ -328,7 +328,7 @@ var/datum/controller/supply/supply_controller = new()
M.count_niche_stat(STATISTICS_NICHE_CRATES)
playsound(C.loc,'sound/effects/bamf.ogg', 50, 1) //Ehh
- var/obj/structure/droppod/supply/pod = new()
+ var/obj/structure/droppod/supply/pod = new(null, C)
C.forceMove(pod)
pod.launch(T)
visible_message("[icon2html(src, viewers(src))] [SPAN_BOLDNOTICE("'[C.name]' supply drop launched! Another launch will be available in five minutes.")]")
@@ -1320,6 +1320,14 @@ var/datum/controller/supply/supply_controller = new()
/datum/vehicle_order/tank/has_vehicle_lock()
return
+/datum/vehicle_order/tank/broken
+ name = "Smashed M34A2 Longstreet Light Tank"
+ ordered_vehicle = /obj/effect/vehicle_spawner/tank/hull/broken
+
+/datum/vehicle_order/tank/plain
+ name = "M34A2 Longstreet Light Tank"
+ ordered_vehicle = /obj/effect/vehicle_spawner/tank
+
/datum/vehicle_order/apc
name = "M577 Armored Personnel Carrier"
ordered_vehicle = /obj/effect/vehicle_spawner/apc/decrepit
@@ -1332,18 +1340,19 @@ var/datum/controller/supply/supply_controller = new()
name = "M577-CMD Armored Personnel Carrier"
ordered_vehicle = /obj/effect/vehicle_spawner/apc_cmd/decrepit
+/datum/vehicle_order/apc/empty
+ name = "Barebones M577 Armored Personal Carrier"
+ ordered_vehicle = /obj/effect/vehicle_spawner/apc/unarmed/broken
+
/obj/structure/machinery/computer/supplycomp/vehicle/Initialize()
. = ..()
vehicles = list(
- /datum/vehicle_order/apc,
- /datum/vehicle_order/apc/med,
- /datum/vehicle_order/apc/cmd,
+ new /datum/vehicle_order/apc(),
+ new /datum/vehicle_order/apc/med(),
+ new /datum/vehicle_order/apc/cmd(),
)
- for(var/order as anything in vehicles)
- new order
-
if(!VehicleElevatorConsole)
VehicleElevatorConsole = src
@@ -1413,6 +1422,7 @@ var/datum/controller/supply/supply_controller = new()
return
if(!is_admin_level(SSshuttle.vehicle_elevator.z))
+ to_chat(usr, SPAN_WARNING("The elevator needs to be in the cargo bay dock to call a vehicle up. Ask someone to send it away."))
return
if(ismaintdrone(usr))
diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm
index a4781e1a66..a86ed37f06 100644
--- a/code/game/turfs/open.dm
+++ b/code/game/turfs/open.dm
@@ -185,6 +185,7 @@
name = "cave"
icon = 'icons/turf/floors/bigred.dmi'
icon_state = "mars_cave_1"
+ is_groundmap_turf = TRUE
/turf/open/mars_cave/Initialize(mapload, ...)
@@ -283,6 +284,7 @@
name = "ground dirt"
icon = 'icons/turf/ground_map.dmi'
icon_state = "desert"
+ is_groundmap_turf = TRUE
/turf/open/gm/attackby(obj/item/I, mob/user)
@@ -646,6 +648,7 @@
baseturfs = /turf/open/gm/riverdeep
supports_surgery = FALSE
minimap_color = MINIMAP_WATER
+ is_groundmap_turf = FALSE // Not real ground
/turf/open/gm/riverdeep/Initialize(mapload, ...)
@@ -724,6 +727,7 @@
allow_construction = FALSE
var/bushes_spawn = 1
var/plants_spawn = 1
+ is_groundmap_turf = TRUE
name = "wet grass"
desc = "Thick, long, wet grass."
icon = 'icons/turf/floors/jungle.dmi'
@@ -903,8 +907,6 @@
name = "floor"
icon_state = "floor"
icon = 'icons/turf/shuttle.dmi'
- allow_construction = FALSE
- supports_surgery = FALSE
/turf/open/shuttle/dropship
name = "floor"
diff --git a/code/game/turfs/walls/wall_types.dm b/code/game/turfs/walls/wall_types.dm
index 009eab0b6f..abd222f2ba 100644
--- a/code/game/turfs/walls/wall_types.dm
+++ b/code/game/turfs/walls/wall_types.dm
@@ -28,15 +28,23 @@
/obj/structure/machinery/cm_vending/sorted/cargo_guns/cargo/blend,
)
+ /// The type of wall decoration we use, to avoid the wall changing icon all the time
+ var/decoration_type
+
+/turf/closed/wall/almayer/Initialize(mapload, ...)
+ if(!special_icon && prob(20))
+ decoration_type = rand(0,3)
+ return ..()
+
/turf/closed/wall/almayer/update_icon()
- ..()
- if(special_icon)
- return
+ if(decoration_type == null)
+ return ..()
if(neighbors_list in list(EAST|WEST))
- var/r1 = rand(0,10) //Make a random chance for this to happen
- var/r2 = rand(0,3) // Which wall if we do choose it
- if(r1 >= 9)
- overlays += image(icon, icon_state = "almayer_deco_wall[r2]")
+ special_icon = TRUE
+ icon_state = "almayer_deco_wall[decoration_type]"
+ else // Wall connection was broken, return to normality
+ special_icon = FALSE
+ return ..()
/turf/closed/wall/almayer/take_damage(dam, mob/M)
var/damage_check = max(0, damage + dam)
diff --git a/code/game/world.dm b/code/game/world.dm
index 04a3433b5a..e67fca2856 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -71,8 +71,6 @@ var/list/reboot_sfx = file2list("config/reboot_sfx.txt")
RoleAuthority = new /datum/authority/branch/role()
to_world(SPAN_DANGER("\b Job setup complete"))
- if(!EvacuationAuthority) EvacuationAuthority = new
-
initiate_minimap_icons()
change_tick_lag(CONFIG_GET(number/ticklag))
@@ -174,11 +172,6 @@ var/world_topic_spam_protect_time = world.timeofday
response["response"] = "Payload too large"
return json_encode(response)
- if(SSfail_to_topic?.IsRateLimited(addr))
- response["statuscode"] = 429
- response["response"] = "Rate limited"
- return json_encode(response)
-
var/logging = CONFIG_GET(flag/log_world_topic)
var/topic_decoded = rustg_url_decode(T)
if(!rustg_json_is_valid(topic_decoded))
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 5042167023..38b63b9457 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -261,7 +261,7 @@
if("Remove")
if(!GLOB.trait_name_map)
GLOB.trait_name_map = generate_trait_name_map()
- for(var/trait in D.status_traits)
+ for(var/trait in D._status_traits)
var/name = GLOB.trait_name_map[trait] || trait
available_traits[name] = trait
@@ -282,7 +282,7 @@
if("All")
source = null
if("Specific")
- source = input("Source to be removed","Trait Remove/Add") as null|anything in sort_list(D.status_traits[chosen_trait])
+ source = input("Source to be removed","Trait Remove/Add") as null|anything in sort_list(D._status_traits[chosen_trait])
if(!source)
return
REMOVE_TRAIT(D,chosen_trait,source)
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index b706852d5d..c60555cb4e 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -115,6 +115,7 @@ var/list/admin_verbs_minor_event = list(
/datum/admins/proc/force_predator_round, //Force spawns a predator round.
/client/proc/adjust_predator_round,
/client/proc/cmd_admin_world_narrate, /*sends text to all players with no padding*/
+ /client/proc/cmd_admin_ground_narrate,
/client/proc/cmd_admin_atom_narrate,
/client/proc/cmd_admin_create_centcom_report, //Messages from USCM command/other factions.
/client/proc/cmd_admin_create_predator_report, //Predator ship AI report
@@ -328,6 +329,7 @@ var/list/roundstart_mod_verbs = list(
add_verb(src, /client/proc/togglebuildmodeself)
add_verb(src, /client/proc/toggle_game_master)
add_verb(src, /client/proc/toggle_join_xeno)
+ add_verb(src, /client/proc/game_master_rename_platoon)
if(CLIENT_HAS_RIGHTS(src, R_SERVER))
add_verb(src, admin_verbs_server)
if(CLIENT_HAS_RIGHTS(src, R_DEBUG))
@@ -359,6 +361,7 @@ var/list/roundstart_mod_verbs = list(
/client/proc/togglebuildmodeself,
/client/proc/toggle_game_master,
/client/proc/toggle_join_xeno,
+ /client/proc/game_master_rename_platoon,
admin_verbs_admin,
admin_verbs_ban,
admin_verbs_minor_event,
diff --git a/code/modules/admin/fax_templates.dm b/code/modules/admin/fax_templates.dm
index 91b23abb24..459ab675d3 100644
--- a/code/modules/admin/fax_templates.dm
+++ b/code/modules/admin/fax_templates.dm
@@ -1,11 +1,13 @@
/proc/generate_templated_fax(show_wy_logo, fax_header, fax_subject, addressed_to, message_body, sent_by, sent_title, sent_department)
+ var/datum/asset/asset = get_asset_datum(/datum/asset/simple/paper)
+
var/dat = ""
dat += "