diff --git a/.travis.yml b/.travis.yml
index 478896d7b10..3bd1c71a173 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,8 +4,8 @@ sudo: false
env:
global:
- - BYOND_MAJOR="512"
- - BYOND_MINOR="1453"
+ - BYOND_MAJOR="513"
+ - BYOND_MINOR="1502"
- MACRO_COUNT=4
matrix:
- TEST_DEFINE="MAP_TEST" TEST_FILE="code/_map_tests.dm" RUN="0"
diff --git a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm
index 84c5d49daa4..8bf3d3477cb 100644
--- a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm
+++ b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm
@@ -85,20 +85,21 @@
to_chat(user, "Access denied.")
return
usr.set_machine(src)
+ var/list/node_connects = get_node_connect_dirs()
var/dat = {"Power: [use_power?"On":"Off"]
Set Flow Rate Limit:
[set_flow_rate]L/s | Change
Flow Rate: [round(last_flow_rate, 0.1)]L/s
- Node 1 Concentration:
+ Node 1 ([dir_name(node_connects[1],TRUE)]) Concentration:
-
-
[mixing_inputs[air1]]([mixing_inputs[air1]*100]%)
+
+
- Node 2 Concentration:
+ Node 2 ([dir_name(node_connects[2],TRUE)]) Concentration:
-
-
[mixing_inputs[air2]]([mixing_inputs[air2]*100]%)
diff --git a/code/ATMOSPHERICS/components/unary/vent_pump.dm b/code/ATMOSPHERICS/components/unary/vent_pump.dm
index 1f7414e17f1..844cdb7ca56 100644
--- a/code/ATMOSPHERICS/components/unary/vent_pump.dm
+++ b/code/ATMOSPHERICS/components/unary/vent_pump.dm
@@ -47,6 +47,8 @@
var/radio_filter_out
var/radio_filter_in
+ //var/datum/looping_sound/air_pump/soundloop //VOREStation Removal
+
/obj/machinery/atmospherics/unary/vent_pump/on
use_power = 1
icon_state = "map_vent_out"
@@ -68,6 +70,10 @@
pressure_checks = 2
pressure_checks_default = 2
+/obj/machinery/atmospherics/unary/vent_pump/Initialize()
+ . = ..()
+ //soundloop = new(list(src), FALSE) //VOREStation Removal
+
/obj/machinery/atmospherics/unary/vent_pump/New()
..()
air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP
@@ -84,6 +90,7 @@
if(initial_loc)
initial_loc.air_vent_info -= id_tag
initial_loc.air_vent_names -= id_tag
+ //QDEL_NULL(soundloop) //VOREStation Removal
return ..()
/obj/machinery/atmospherics/unary/vent_pump/high_volume
@@ -164,11 +171,15 @@
/obj/machinery/atmospherics/unary/vent_pump/proc/can_pump()
if(stat & (NOPOWER|BROKEN))
+ //soundloop.stop() //VOREStation Removal
return 0
if(!use_power)
+ //soundloop.stop() //VOREStation Removal
return 0
if(welded)
+ //soundloop.stop() //VOREStation Removal
return 0
+ //soundloop.start() //VOREStation Removal
return 1
/obj/machinery/atmospherics/unary/vent_pump/process()
diff --git a/code/ZAS/Airflow.dm b/code/ZAS/Airflow.dm
index 394fe72478a..59837bbe5f1 100644
--- a/code/ZAS/Airflow.dm
+++ b/code/ZAS/Airflow.dm
@@ -9,13 +9,13 @@ mob/proc/airflow_stun()
if(last_airflow_stun > world.time - vsc.airflow_stun_cooldown) return 0
if(!(status_flags & CANSTUN) && !(status_flags & CANWEAKEN))
- src << "You stay upright as the air rushes past you."
+ to_chat(src, "You stay upright as the air rushes past you.")
return 0
if(buckled)
- src << "Air suddenly rushes past you!"
+ to_chat(src, "Air suddenly rushes past you!")
return 0
if(!lying)
- src << "The sudden rush of air knocks you over!"
+ to_chat(src, "The sudden rush of air knocks you over!")
Weaken(5)
last_airflow_stun = world.time
diff --git a/code/ZAS/Diagnostic.dm b/code/ZAS/Diagnostic.dm
index 29ab678ef1d..41fcdcad85c 100644
--- a/code/ZAS/Diagnostic.dm
+++ b/code/ZAS/Diagnostic.dm
@@ -10,10 +10,10 @@ client/proc/ZoneTick()
var/result = air_master.Tick()
if(result)
- src << "Successfully Processed."
+ to_chat(src, "Successfully Processed.")
else
- src << "Failed to process! ([air_master.tick_progress])"
+ to_chat(src, "Failed to process! ([air_master.tick_progress])")
*/
client/proc/Zone_Info(turf/T as null|turf)
diff --git a/code/ZAS/Phoron.dm b/code/ZAS/Phoron.dm
index 6ffec0be995..e12beb900ff 100644
--- a/code/ZAS/Phoron.dm
+++ b/code/ZAS/Phoron.dm
@@ -102,11 +102,12 @@ obj/var/contaminated = 0
if(vsc.plc.SKIN_BURNS && (species.breath_type != "phoron"))
if(!pl_head_protected() || !pl_suit_protected())
burn_skin(0.75)
- if(prob(20)) src << "Your skin burns!"
+ if(prob(20))
+ to_chat(src, "Your skin burns!")
updatehealth()
//Burn eyes if exposed.
- if(vsc.plc.EYE_BURNS && (species.breath_type != "phoron"))
+ if(vsc.plc.EYE_BURNS && species.breath_type && (species.breath_type != "phoron")) //VOREStation Edit: those who don't breathe
var/burn_eyes = 1
//Check for protective glasses
@@ -133,17 +134,18 @@ obj/var/contaminated = 0
if(vsc.plc.GENETIC_CORRUPTION && (species.breath_type != "phoron"))
if(rand(1,10000) < vsc.plc.GENETIC_CORRUPTION)
randmutb(src)
- src << "High levels of toxins cause you to spontaneously mutate!"
+ to_chat(src, "High levels of toxins cause you to spontaneously mutate!")
domutcheck(src,null)
/mob/living/carbon/human/proc/burn_eyes()
var/obj/item/organ/internal/eyes/E = internal_organs_by_name[O_EYES]
if(E)
- if(prob(20)) src << "Your eyes burn!"
+ if(prob(20))
+ to_chat(src, "Your eyes burn!")
E.damage += 2.5
eye_blurry = min(eye_blurry+1.5,50)
if (prob(max(0,E.damage - 15) + 1) &&!eye_blind)
- src << "You are blinded!"
+ to_chat(src, "You are blinded!")
Blind(20)
/mob/living/carbon/human/proc/pl_head_protected()
diff --git a/code/__defines/__513_compatibility.dm b/code/__defines/__513_compatibility.dm
new file mode 100644
index 00000000000..7f8d7eb4e6b
--- /dev/null
+++ b/code/__defines/__513_compatibility.dm
@@ -0,0 +1,31 @@
+#if DM_VERSION < 513
+
+#define ismovableatom(A) (istype(A, /atom/movable))
+
+#define islist(L) (istype(L, /list))
+
+#define CLAMP01(x) (CLAMP(x, 0, 1))
+
+#define CLAMP(CLVALUE,CLMIN,CLMAX) ( max( (CLMIN), min((CLVALUE), (CLMAX)) ) )
+
+#define ATAN2(x, y) ( !(x) && !(y) ? 0 : (y) >= 0 ? arccos((x) / sqrt((x)*(x) + (y)*(y))) : -arccos((x) / sqrt((x)*(x) + (y)*(y))) )
+
+#define TAN(x) (sin(x) / cos(x))
+
+#define arctan(x) (arcsin(x/sqrt(1+x*x)))
+
+//////////////////////////////////////////////////
+
+#else
+
+#define ismovableatom(A) ismovable(A)
+
+#define CLAMP01(x) clamp(x, 0, 1)
+
+#define CLAMP(CLVALUE, CLMIN, CLMAX) clamp(CLVALUE, CLMIN, CLMAX)
+
+#define TAN(x) tan(x)
+
+#define ATAN2(x, y) arctan(x, y)
+
+#endif
\ No newline at end of file
diff --git a/code/__defines/chemistry_vr.dm b/code/__defines/chemistry_vr.dm
index 094bfc2139f..f15ebd4a564 100644
--- a/code/__defines/chemistry_vr.dm
+++ b/code/__defines/chemistry_vr.dm
@@ -1,2 +1,3 @@
// More for our custom races
-#define IS_CHIMERA 12
\ No newline at end of file
+#define IS_CHIMERA 12
+#define IS_SHADEKIN 13
\ No newline at end of file
diff --git a/code/__defines/gamemode.dm b/code/__defines/gamemode.dm
index bed21dc4824..59d2879ba54 100644
--- a/code/__defines/gamemode.dm
+++ b/code/__defines/gamemode.dm
@@ -88,6 +88,7 @@ var/list/be_special_flags = list(
#define MODE_AUTOTRAITOR "autotraitor"
#define MODE_INFILTRATOR "infiltrator"
#define MODE_THUG "thug"
+#define MODE_STOWAWAY "stowaway"
#define DEFAULT_TELECRYSTAL_AMOUNT 120
diff --git a/code/__defines/is_helpers.dm b/code/__defines/is_helpers.dm
index ed4a0dd10f7..d3222965a91 100644
--- a/code/__defines/is_helpers.dm
+++ b/code/__defines/is_helpers.dm
@@ -2,7 +2,7 @@
#define isdatum(D) istype(D, /datum)
#define isweakref(A) istype(A, /weakref)
-#define islist(D) istype(D, /list)
+//#define islist(D) istype(D, /list) //Built in
//---------------
#define isatom(D) istype(D, /atom)
diff --git a/code/__defines/lighting.dm b/code/__defines/lighting.dm
index 0425c3fa63e..8ad6fdfcf5d 100644
--- a/code/__defines/lighting.dm
+++ b/code/__defines/lighting.dm
@@ -84,4 +84,4 @@
#define LIGHT_COLOR_INCANDESCENT_FLASHLIGHT "#FFCC66"
//Fake ambient occlusion filter
-#define AMBIENT_OCCLUSION filter(type="drop_shadow", x=0, y=-2, size=4, border=4, color="#04080FAA")
+#define AMBIENT_OCCLUSION filter(type="drop_shadow", x=0, y=-2, size=4, offset=3, color="#04080F80")
diff --git a/code/__defines/math.dm b/code/__defines/math.dm
index 88c459ba782..2053b762d27 100644
--- a/code/__defines/math.dm
+++ b/code/__defines/math.dm
@@ -16,7 +16,6 @@
#define TICK_USAGE_TO_MS(starting_tickusage) (TICK_DELTA_TO_MS(world.tick_usage - starting_tickusage))
#define PERCENT(val) (round((val)*100, 0.1))
-#define CLAMP01(x) (CLAMP(x, 0, 1))
//time of day but automatically adjusts to the server going into the next day within the same round.
//for when you need a reliable time number that doesn't depend on byond time.
@@ -30,17 +29,12 @@
// round() acts like floor(x, 1) by default but can't handle other values
#define FLOOR(x, y) ( round((x) / (y)) * (y) )
-#define CLAMP(CLVALUE,CLMIN,CLMAX) ( max( (CLMIN), min((CLVALUE), (CLMAX)) ) )
-
// Similar to clamp but the bottom rolls around to the top and vice versa. min is inclusive, max is exclusive
#define WRAP(val, min, max) ( min == max ? min : (val) - (round(((val) - (min))/((max) - (min))) * ((max) - (min))) )
// Real modulus that handles decimals
#define MODULUS(x, y) ( (x) - (y) * round((x) / (y)) )
-// Tangent
-#define TAN(x) (sin(x) / cos(x))
-
// Cotangent
#define COT(x) (1 / TAN(x))
@@ -50,8 +44,6 @@
// Cosecant
#define CSC(x) (1 / sin(x))
-#define ATAN2(x, y) ( !(x) && !(y) ? 0 : (y) >= 0 ? arccos((x) / sqrt((x)*(x) + (y)*(y))) : -arccos((x) / sqrt((x)*(x) + (y)*(y))) )
-
// Greatest Common Divisor - Euclid's algorithm
/proc/GCD(a, b)
return b ? GCD(b, (a) % (b)) : a
diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index 69b91d0dc32..e8242af1132 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -353,7 +353,9 @@ var/global/list/##LIST_NAME = list();\
#define RAD_LEVEL_HIGH 25
#define RAD_LEVEL_VERY_HIGH 75
-#define RADIATION_THRESHOLD_CUTOFF 0.1 // Radiation will not affect a tile when below this value.
+// Calculation modes for effective radiation
+#define RAD_RESIST_CALC_DIV 0 // Each turf absorbs some fraction of the working radiation level
+#define RAD_RESIST_CALC_SUB 1 // Each turf absorbs a fixed amount of radiation
//https://secure.byond.com/docs/ref/info.html#/atom/var/mouse_opacity
#define MOUSE_OPACITY_TRANSPARENT 0
diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm
index de9ffa6cf9d..d43faaf4a53 100644
--- a/code/__defines/mobs.dm
+++ b/code/__defines/mobs.dm
@@ -325,6 +325,8 @@
#define SPECIES_SKELETON "Skeleton"
#define SPECIES_GOLEM "Golem"
#define SPECIES_EVENT1 "X Occursus"
+#define SPECIES_EVENT2 "X Anomalous"
+#define SPECIES_EVENT3 "X Unowas"
// Replicant types. Currently only used for alien pods and events.
#define SPECIES_REPLICANT "Replicant"
diff --git a/code/__defines/mobs_vr.dm b/code/__defines/mobs_vr.dm
index 5e9bb78189e..99ff177e52a 100644
--- a/code/__defines/mobs_vr.dm
+++ b/code/__defines/mobs_vr.dm
@@ -17,12 +17,15 @@
#define A_FRUIT "fruit gland"
//species defines
+
+//station species
#define SPECIES_AKULA "Akula"
#define SPECIES_ALRAUNE "Alraune"
#define SPECIES_NEVREAN "Nevrean"
#define SPECIES_PROTEAN "Protean"
#define SPECIES_RAPALA "Rapala"
#define SPECIES_SERGAL "Sergal"
+#define SPECIES_SHADEKIN_CREW "Black-Eyed Shadekin"
#define SPECIES_VASILISSAN "Vasilissan"
#define SPECIES_VULPKANIN "Vulpkanin"
#define SPECIES_XENOCHIMERA "Xenochimera"
@@ -30,9 +33,11 @@
#define SPECIES_ZORREN_FLAT "Flatland Zorren"
#define SPECIES_ZORREN_HIGH "Highlander Zorren"
#define SPECIES_CUSTOM "Custom Species"
-
+//monkey species
#define SPECIES_MONKEY_AKULA "Sobaka"
#define SPECIES_MONKEY_NEVREAN "Sparra"
#define SPECIES_MONKEY_SERGAL "Saru"
#define SPECIES_MONKEY_VULPKANIN "Wolpin"
+//event species
#define SPECIES_WEREBEAST "Werebeast"
+#define SPECIES_SHADEKIN "Shadekin"
diff --git a/code/__defines/species_languages.dm b/code/__defines/species_languages.dm
index 925abca388d..bacd4ebd370 100644
--- a/code/__defines/species_languages.dm
+++ b/code/__defines/species_languages.dm
@@ -31,6 +31,7 @@
// Languages.
#define LANGUAGE_GALCOM "Galactic Common"
#define LANGUAGE_EAL "Encoded Audio Language"
+#define LANGUAGE_SWARMBOT "Ancient Audio Encryption"
#define LANGUAGE_SOL_COMMON "Sol Common"
#define LANGUAGE_UNATHI "Sinta'unathi"
#define LANGUAGE_SIIK "Siik"
diff --git a/code/__defines/typeids.dm b/code/__defines/typeids.dm
index 9af310012b3..53028be2943 100644
--- a/code/__defines/typeids.dm
+++ b/code/__defines/typeids.dm
@@ -2,5 +2,5 @@
#define TYPEID_NULL "0"
#define TYPEID_NORMAL_LIST "f"
//helper macros
-#define GET_TYPEID(ref) ( ( (lentext(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, lentext(ref)-6) ) )
-#define IS_NORMAL_LIST(L) (GET_TYPEID("\ref[L]") == TYPEID_NORMAL_LIST)
\ No newline at end of file
+#define GET_TYPEID(ref) ( ( (length(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, length(ref)-6) ) )
+#define IS_NORMAL_LIST(L) (GET_TYPEID("\ref[L]") == TYPEID_NORMAL_LIST)
diff --git a/code/_compatibility/509/JSON Reader.dm b/code/_compatibility/509/JSON Reader.dm
index 544d197ccd3..18f739c5ef9 100644
--- a/code/_compatibility/509/JSON Reader.dm
+++ b/code/_compatibility/509/JSON Reader.dm
@@ -28,7 +28,7 @@ json_reader
src.json = json
. = new/list()
src.i = 1
- while(src.i <= lentext(json))
+ while(src.i <= length(json))
var/char = get_char()
if(is_whitespace(char))
i++
@@ -46,7 +46,7 @@ json_reader
read_word()
var/val = ""
- while(i <= lentext(json))
+ while(i <= length(json))
var/char = get_char()
if(is_whitespace(char) || symbols.Find(char))
i-- // let scanner handle this character
@@ -58,7 +58,7 @@ json_reader
var
escape = FALSE
val = ""
- while(++i <= lentext(json))
+ while(++i <= length(json))
var/char = get_char()
if(escape)
switch(char)
diff --git a/code/_compatibility/509/JSON Writer.dm b/code/_compatibility/509/JSON Writer.dm
index de3bb54a3e2..80e4976687b 100644
--- a/code/_compatibility/509/JSON Writer.dm
+++ b/code/_compatibility/509/JSON Writer.dm
@@ -43,7 +43,7 @@ json_writer
var/static/list/json_escape = list("\\" = "\\\\", "\"" = "\\\"", "\n" = "\\n")
for(var/targ in json_escape)
var/start = 1
- while(start <= lentext(txt))
+ while(start <= length(txt))
var/i = findtext(txt, targ, start)
if(!i)
break
diff --git a/code/_global_vars/lists/misc.dm b/code/_global_vars/lists/misc.dm
new file mode 100644
index 00000000000..aa9680a5f68
--- /dev/null
+++ b/code/_global_vars/lists/misc.dm
@@ -0,0 +1 @@
+GLOBAL_LIST_INIT(speech_toppings, list("|" = "i", "+" = "b", "_" = "u"))
diff --git a/code/_global_vars/lists/species.dm b/code/_global_vars/lists/species.dm
new file mode 100644
index 00000000000..780ce3fb706
--- /dev/null
+++ b/code/_global_vars/lists/species.dm
@@ -0,0 +1,8 @@
+//Languages/species/whitelist.
+GLOBAL_LIST_INIT(all_species, list())
+GLOBAL_LIST_INIT(all_languages, list())
+GLOBAL_LIST_INIT(language_keys, list()) // Table of say codes for all languages
+GLOBAL_LIST_INIT(whitelisted_species, list(SPECIES_HUMAN)) // Species that require a whitelist check.
+// VOREStation edit - include custom species
+GLOBAL_LIST_INIT(playable_species, list(SPECIES_HUMAN, SPECIES_CUSTOM)) // A list of ALL playable species, whitelisted, latejoin or otherwise.
+// VOREStation edit end
\ No newline at end of file
diff --git a/code/_helpers/_global_objects_vr.dm b/code/_helpers/_global_objects_vr.dm
new file mode 100644
index 00000000000..84642cc4d1c
--- /dev/null
+++ b/code/_helpers/_global_objects_vr.dm
@@ -0,0 +1 @@
+var/datum/gear_tweak/collar_tag/gear_tweak_collar_tag = new()
\ No newline at end of file
diff --git a/code/_helpers/atmospherics.dm b/code/_helpers/atmospherics.dm
index 2fe393b4dc2..e211ed329a7 100644
--- a/code/_helpers/atmospherics.dm
+++ b/code/_helpers/atmospherics.dm
@@ -1,4 +1,4 @@
-/obj/proc/analyze_gases(var/obj/A, var/mob/user)
+/obj/proc/analyze_gases(var/atom/A, var/mob/user)
if(src != A)
user.visible_message("\The [user] has used \an [src] on \the [A]")
@@ -13,12 +13,12 @@
user << "Your [src] flashes a red light as it fails to analyze \the [A]."
return 0
-/proc/atmosanalyzer_scan(var/obj/target, var/datum/gas_mixture/mixture, var/mob/user)
- var/pressure = mixture.return_pressure()
- var/total_moles = mixture.total_moles
-
+/proc/atmosanalyzer_scan(var/atom/target, var/datum/gas_mixture/mixture, var/mob/user)
var/list/results = list()
- if (total_moles>0)
+
+ if (mixture && mixture.total_moles > 0)
+ var/pressure = mixture.return_pressure()
+ var/total_moles = mixture.total_moles
results += "Pressure: [round(pressure,0.1)] kPa"
for(var/mix in mixture.gas)
results += "[gas_data.name[mix]]: [round((mixture.gas[mix] / total_moles) * 100)]%"
@@ -28,7 +28,10 @@
return results
-/obj/proc/atmosanalyze(var/mob/user)
+/turf/atmosanalyze(var/mob/user)
+ return atmosanalyzer_scan(src, src.air, user)
+
+/atom/proc/atmosanalyze(var/mob/user)
return
/obj/item/weapon/tank/atmosanalyze(var/mob/user)
@@ -40,6 +43,33 @@
/obj/machinery/atmospherics/pipe/atmosanalyze(var/mob/user)
return atmosanalyzer_scan(src, src.parent.air, user)
+/obj/machinery/atmospherics/portables_connector/atmosanalyze(var/mob/user)
+ return atmosanalyzer_scan(src, src.network.gases, user)
+
+/obj/machinery/atmospherics/unary/atmosanalyze(var/mob/user)
+ return atmosanalyzer_scan(src, src.air_contents, user)
+
+/obj/machinery/atmospherics/binary/atmosanalyze(var/mob/user)
+ return atmosanalyzer_scan(src, src.air1, user)
+
+/obj/machinery/atmospherics/trinary/atmos_filter/atmosanalyze(var/mob/user)
+ return atmosanalyzer_scan(src, src.air1, user)
+
+/obj/machinery/atmospherics/trinary/mixer/atmosanalyze(var/mob/user)
+ return atmosanalyzer_scan(src, src.air3, user)
+
+/obj/machinery/atmospherics/omni/atmos_filter/atmosanalyze(var/mob/user)
+ return atmosanalyzer_scan(src, src.input.air, user)
+
+/obj/machinery/atmospherics/omni/mixer/atmosanalyze(var/mob/user)
+ return atmosanalyzer_scan(src, src.output.air, user)
+
+/obj/machinery/meter/atmosanalyze(var/mob/user)
+ var/datum/gas_mixture/mixture = null
+ if(src.target)
+ mixture = src.target.parent.air
+ return atmosanalyzer_scan(src, mixture, user)
+
/obj/machinery/power/rad_collector/atmosanalyze(var/mob/user)
if(P) return atmosanalyzer_scan(src, src.P.air_contents, user)
diff --git a/code/_helpers/files.dm b/code/_helpers/files.dm
index 4a7b9fa646e..dd8c5dd6901 100644
--- a/code/_helpers/files.dm
+++ b/code/_helpers/files.dm
@@ -39,7 +39,7 @@
var/extension = copytext(path,-4,0)
if( !fexists(path) || !(extension in valid_extensions) )
- src << "Error: browse_files(): File not found/Invalid file([path])."
+ to_chat(src, "Error: browse_files(): File not found/Invalid file([path]).")
return
return path
@@ -53,7 +53,7 @@
/client/proc/file_spam_check()
var/time_to_wait = fileaccess_timer - world.time
if(time_to_wait > 0)
- src << "Error: file_spam_check(): Spam. Please wait [round(time_to_wait/10)] seconds."
+ to_chat(src, "Error: file_spam_check(): Spam. Please wait [round(time_to_wait/10)] seconds.")
return 1
fileaccess_timer = world.time + FTPDELAY
return 0
diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm
index a3687b9b99c..4c98e06c4d0 100644
--- a/code/_helpers/global_lists.dm
+++ b/code/_helpers/global_lists.dm
@@ -24,17 +24,11 @@ var/global/list/turfs = list() //list of all turfs
#define all_genders_define_list list(MALE,FEMALE,PLURAL,NEUTER,HERM) //VOREStaton Edit
#define all_genders_text_list list("Male","Female","Plural","Neuter","Herm") //VOREStation Edit
-//Languages/species/whitelist.
-var/global/list/all_species[0]
-var/global/list/all_languages[0]
-var/global/list/language_keys[0] // Table of say codes for all languages
-var/global/list/whitelisted_species = list(SPECIES_HUMAN) // Species that require a whitelist check.
-var/global/list/playable_species = list(SPECIES_CUSTOM, SPECIES_HUMAN) // A list of ALL playable species, whitelisted, latejoin or otherwise. //VOREStation Edit - Making sure custom species is obvious.
-
var/list/mannequins_
// Posters
var/global/list/poster_designs = list()
+var/global/list/NT_poster_designs = list()
// Uplinks
var/list/obj/item/device/uplink/world_uplinks = list()
@@ -163,12 +157,12 @@ var/global/list/string_slot_flags = list(
paths = typesof(/datum/language)-/datum/language
for(var/T in paths)
var/datum/language/L = new T
- all_languages[L.name] = L
+ GLOB.all_languages[L.name] = L
- for (var/language_name in all_languages)
- var/datum/language/L = all_languages[language_name]
+ for (var/language_name in GLOB.all_languages)
+ var/datum/language/L = GLOB.all_languages[language_name]
if(!(L.flags & NONGLOBAL))
- language_keys[lowertext(L.key)] = L
+ GLOB.language_keys[lowertext(L.key)] = L
var/rkey = 0
paths = typesof(/datum/species)
@@ -182,19 +176,25 @@ var/global/list/string_slot_flags = list(
S = new T
S.race_key = rkey //Used in mob icon caching.
- all_species[S.name] = S
+ GLOB.all_species[S.name] = S
if(!(S.spawn_flags & SPECIES_IS_RESTRICTED))
- playable_species += S.name
+ GLOB.playable_species += S.name
if(S.spawn_flags & SPECIES_IS_WHITELISTED)
- whitelisted_species += S.name
+ GLOB.whitelisted_species += S.name
//Posters
paths = typesof(/datum/poster) - /datum/poster
+ paths -= typesof(/datum/poster/nanotrasen)
for(var/T in paths)
var/datum/poster/P = new T
poster_designs += P
+ paths = typesof(/datum/poster/nanotrasen)
+ for(var/T in paths)
+ var/datum/poster/P = new T
+ NT_poster_designs += P
+
return 1
/* // Uncomment to debug chemical reaction list.
diff --git a/code/_helpers/global_lists_vr.dm b/code/_helpers/global_lists_vr.dm
index c9a64048a8b..3469779fda2 100644
--- a/code/_helpers/global_lists_vr.dm
+++ b/code/_helpers/global_lists_vr.dm
@@ -407,7 +407,7 @@ var/global/list/contamination_colors = list("green",
"beige",
"pink")
-//For the mechanic of leaving remains. Ones listed below are basically ones that got no bones.
+//For the mechanic of leaving remains. Ones listed below are basically ones that got no bones or leave no trace after death.
var/global/list/remainless_species = list(SPECIES_PROMETHEAN,
SPECIES_DIONA,
SPECIES_ALRAUNE,
@@ -426,7 +426,8 @@ var/global/list/remainless_species = list(SPECIES_PROMETHEAN,
SPECIES_XENO_SENTINEL,
SPECIES_XENO_QUEEN,
SPECIES_SHADOW,
- SPECIES_GOLEM) //Some special species that may or may not be ever used in event too
+ SPECIES_GOLEM, //Some special species that may or may not be ever used in event too,
+ SPECIES_SHADEKIN) //Shadefluffers just poof away
/hook/startup/proc/init_vore_datum_ref_lists()
var/paths
@@ -468,10 +469,10 @@ var/global/list/remainless_species = list(SPECIES_PROMETHEAN,
// Custom species icon bases
var/list/blacklisted_icons = list(SPECIES_CUSTOM,SPECIES_PROMETHEAN) //Just ones that won't work well.
- for(var/species_name in playable_species)
+ for(var/species_name in GLOB.playable_species)
if(species_name in blacklisted_icons)
continue
- var/datum/species/S = all_species[species_name]
+ var/datum/species/S = GLOB.all_species[species_name]
if(S.spawn_flags & SPECIES_IS_WHITELISTED)
continue
custom_species_bases += species_name
diff --git a/code/_helpers/mobs.dm b/code/_helpers/mobs.dm
index 220f896436c..9320c29272b 100644
--- a/code/_helpers/mobs.dm
+++ b/code/_helpers/mobs.dm
@@ -75,7 +75,7 @@ proc/random_facial_hair_style(gender, species = SPECIES_HUMAN)
proc/sanitize_name(name, species = SPECIES_HUMAN, robot = 0)
var/datum/species/current_species
if(species)
- current_species = all_species[species]
+ current_species = GLOB.all_species[species]
return current_species ? current_species.sanitize_name(name, robot) : sanitizeName(name, MAX_NAME_LEN, robot)
@@ -83,7 +83,7 @@ proc/random_name(gender, species = SPECIES_HUMAN)
var/datum/species/current_species
if(species)
- current_species = all_species[species]
+ current_species = GLOB.all_species[species]
if(!current_species || current_species.name_language == null)
if(gender==FEMALE)
diff --git a/code/_helpers/text.dm b/code/_helpers/text.dm
index eb363c08cb3..688e1c2a686 100644
--- a/code/_helpers/text.dm
+++ b/code/_helpers/text.dm
@@ -16,7 +16,7 @@
// Run all strings to be used in an SQL query through this proc first to properly escape out injection attempts.
/proc/sanitizeSQL(var/t as text)
var/sqltext = dbcon.Quote(t);
- return copytext(sqltext, 2, lentext(sqltext));//Quote() adds quotes around input, we already do that
+ return copytext(sqltext, 2, length(sqltext));//Quote() adds quotes around input, we already do that
/*
* Text sanitization
@@ -249,9 +249,9 @@
//This is used for fingerprints
/proc/stringmerge(var/text,var/compare,replace = "*")
var/newtext = text
- if(lentext(text) != lentext(compare))
+ if(length(text) != length(compare))
return 0
- for(var/i = 1, i < lentext(text), i++)
+ for(var/i = 1, i < length(text), i++)
var/a = copytext(text,i,i+1)
var/b = copytext(compare,i,i+1)
//if it isn't both the same letter, or if they are both the replacement character
@@ -271,7 +271,7 @@
if(!text || !character)
return 0
var/count = 0
- for(var/i = 1, i <= lentext(text), i++)
+ for(var/i = 1, i <= length(text), i++)
var/a = copytext(text,i,i+1)
if(a == character)
count++
@@ -286,8 +286,8 @@
//Used in preferences' SetFlavorText and human's set_flavor verb
//Previews a string of len or less length
proc/TextPreview(var/string,var/len=40)
- if(lentext(string) <= len)
- if(!lentext(string))
+ if(length(string) <= len)
+ if(!length(string))
return "\[...\]"
else
return string
diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm
index 9104bc71d9a..44c62a506be 100644
--- a/code/_helpers/unsorted.dm
+++ b/code/_helpers/unsorted.dm
@@ -358,7 +358,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
break
if(newname)
break //That's a suitable name!
- src << "Sorry, that [role]-name wasn't appropriate, please try another. It's possibly too long/short, has bad characters or is already taken."
+ to_chat(src, "Sorry, that [role]-name wasn't appropriate, please try another. It's possibly too long/short, has bad characters or is already taken.")
if(!newname) //we'll stick with the oldname then
return
@@ -587,10 +587,6 @@ Turf and target are seperate in case you want to teleport some distance from a t
/proc/between(var/low, var/middle, var/high)
return max(min(middle, high), low)
-proc/arctan(x)
- var/y=arcsin(x/sqrt(1+x*x))
- return y
-
//returns random gauss number
proc/GaussRand(var/sigma)
var/x,y,rsq
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 6cde2645660..6fc470cc81a 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -134,6 +134,12 @@
// A is a turf or is on a turf, or in something on a turf (pen in a box); but not something in something on a turf (pen in a box in a backpack)
sdepth = A.storage_depth_turf()
if(isturf(A) || isturf(A.loc) || (sdepth != -1 && sdepth <= 1))
+ //VOREStation Edit begin: SHADEKIN
+ var/mob/SK = src
+ if(istype(SK))
+ if(SK.shadekin_phasing_check())
+ return
+ //VOREStation Edit end: SHADEKIN
if(A.Adjacent(src) || (W && W.attack_can_reach(src, A, W.reach)) ) // see adjacent.dm
if(W)
// Return 1 in attackby() to prevent afterattack() effects (when safely moving items for example)
@@ -183,7 +189,7 @@
/mob/living/UnarmedAttack(var/atom/A, var/proximity_flag)
if(!ticker)
- src << "You cannot attack people before the game has started."
+ to_chat(src, "You cannot attack people before the game has started.")
return 0
if(stat)
@@ -316,7 +322,7 @@
nutrition = max(nutrition - rand(1,5),0)
handle_regular_hud_updates()
else
- src << "You're out of energy! You need food!"
+ to_chat(src, "You're out of energy! You need food!")
// Simple helper to face what you clicked on, in case it should be needed in more than one place
/mob/proc/face_atom(var/atom/A)
diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm
index 1dcc2bc9551..f8bce398a64 100644
--- a/code/_onclick/cyborg.dm
+++ b/code/_onclick/cyborg.dm
@@ -40,12 +40,12 @@
face_atom(A) // change direction to face what you clicked on
- if(aiCamera.in_camera_mode)
+ if(aiCamera && aiCamera.in_camera_mode)
aiCamera.camera_mode_off()
if(is_component_functioning("camera"))
aiCamera.captureimage(A, usr)
else
- src << "Your camera isn't functional."
+ to_chat(src, "Your camera isn't functional.")
return
/*
diff --git a/code/_onclick/hud/_defines_vr.dm b/code/_onclick/hud/_defines_vr.dm
new file mode 100644
index 00000000000..e72150b44ce
--- /dev/null
+++ b/code/_onclick/hud/_defines_vr.dm
@@ -0,0 +1,2 @@
+#define ui_shadekin_dark_display "EAST-1:28,CENTER-3:15"
+#define ui_shadekin_energy_display "EAST-1:28,CENTER-4:15"
\ No newline at end of file
diff --git a/code/_onclick/hud/ability_screen_objects.dm b/code/_onclick/hud/ability_screen_objects.dm
index d29ef9dd967..655a451e924 100644
--- a/code/_onclick/hud/ability_screen_objects.dm
+++ b/code/_onclick/hud/ability_screen_objects.dm
@@ -180,7 +180,8 @@
/mob/New()
..()
- ability_master = new /obj/screen/movable/ability_master(src)
+ if(!ability_master) //VOREStation Edit: S H A D E K I N
+ ability_master = new /obj/screen/movable/ability_master(src)
///////////ACTUAL ABILITIES////////////
//This is what you click to do things//
@@ -282,7 +283,7 @@
if(!mob)
return // Paranoid.
if(isnull(slot) || !isnum(slot))
- src << ".activate_ability requires a number as input, corrisponding to the slot you wish to use."
+ to_chat(src, ".activate_ability requires a number as input, corrisponding to the slot you wish to use.")
return // Bad input.
if(!mob.ability_master)
return // No abilities.
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index 1c903700b00..f1aba60b107 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -293,6 +293,18 @@
mymob.nutrition_icon.screen_loc = ui_nutrition
hud_elements |= mymob.nutrition_icon
+ //VOREStation Addition begin
+ mymob.shadekin_dark_display = new /obj/screen/shadekin/darkness()
+ mymob.shadekin_dark_display.screen_loc = ui_shadekin_dark_display
+ mymob.shadekin_dark_display.icon_state = "dark"
+ hud_elements |= mymob.shadekin_dark_display
+
+ mymob.shadekin_energy_display = new /obj/screen/shadekin/energy()
+ mymob.shadekin_energy_display.screen_loc = ui_shadekin_energy_display
+ mymob.shadekin_energy_display.icon_state = "energy0"
+ hud_elements |= mymob.shadekin_energy_display
+ //VOREStation Addition end
+
mymob.ling_chem_display = new /obj/screen/ling/chems()
mymob.ling_chem_display.screen_loc = ui_ling_chemical_display
mymob.ling_chem_display.icon_state = "ling_chems"
diff --git a/code/_onclick/hud/screen_objects_vr.dm b/code/_onclick/hud/screen_objects_vr.dm
index ea6b72cd103..c1fbd99448a 100644
--- a/code/_onclick/hud/screen_objects_vr.dm
+++ b/code/_onclick/hud/screen_objects_vr.dm
@@ -1,16 +1,19 @@
-/obj/screen/proc/Click_vr(location, control, params) //VORESTATION AI TEMPORARY REMOVAL
+/obj/screen/proc/Click_vr(location, control, params)
if(!usr) return 1
switch(name)
//Shadekin
if("darkness")
- var/mob/living/simple_mob/shadekin/sk = usr
- var/turf/T = get_turf(sk)
+ var/turf/T = get_turf(usr)
var/darkness = round(1 - T.get_lumcount(),0.1)
to_chat(usr,"Darkness: [darkness]")
if("energy")
- var/mob/living/simple_mob/shadekin/sk = usr
- to_chat(usr,"Energy: [sk.energy] ([sk.dark_gains])")
+ var/mob/living/simple_mob/shadekin/SK = usr
+ if(istype(SK))
+ to_chat(usr,"Energy: [SK.energy] ([SK.dark_gains])")
+ var/mob/living/carbon/human/H = usr
+ if(istype(H) && istype(H.species, /datum/species/shadekin))
+ to_chat(usr,"Energy: [H.shadekin_get_energy(H)]")
diff --git a/code/_onclick/hud/spell_screen_objects.dm b/code/_onclick/hud/spell_screen_objects.dm
index e79db287132..92d9487401b 100644
--- a/code/_onclick/hud/spell_screen_objects.dm
+++ b/code/_onclick/hud/spell_screen_objects.dm
@@ -130,7 +130,6 @@
for(var/obj/screen/spell/spell in spell_objects)
spell.update_charge(forced)
-
/obj/screen/movable/spell_master/genetic
name = "Mutant Powers"
icon_state = "genetic_spell_ready"
@@ -140,6 +139,13 @@
screen_loc = ui_genetic_master
+/obj/screen/movable/spell_master/swarm
+ name = "Swarm Abilities"
+ icon_state = "nano_spell_ready"
+
+ open_state = "swarm_open"
+ closed_state = "swarm_closed"
+
//////////////ACTUAL SPELLS//////////////
//This is what you click to cast things//
/////////////////////////////////////////
diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm
index f34a68a742f..d5197cb30f3 100644
--- a/code/_onclick/observer.dm
+++ b/code/_onclick/observer.dm
@@ -6,9 +6,9 @@
if(!client) return
client.inquisitive_ghost = !client.inquisitive_ghost
if(client.inquisitive_ghost)
- src << "You will now examine everything you click on."
+ to_chat(src, "You will now examine everything you click on.")
else
- src << "You will no longer examine things you click on."
+ to_chat(src, "You will no longer examine things you click on.")
/mob/observer/dead/DblClickOn(var/atom/A, var/params)
if(client.buildmode)
diff --git a/code/_onclick/rig.dm b/code/_onclick/rig.dm
index 5f2561c25c7..ed7a1c7e2fb 100644
--- a/code/_onclick/rig.dm
+++ b/code/_onclick/rig.dm
@@ -18,15 +18,15 @@
switch(hardsuit_click_mode)
if(MIDDLE_CLICK)
- src << "Hardsuit activation mode set to middle-click."
+ to_chat(src, "Hardsuit activation mode set to middle-click.")
if(ALT_CLICK)
- src << "Hardsuit activation mode set to alt-click."
+ to_chat(src, "Hardsuit activation mode set to alt-click.")
if(CTRL_CLICK)
- src << "Hardsuit activation mode set to control-click."
+ to_chat(src, "Hardsuit activation mode set to control-click.")
else
// should never get here, but just in case:
soft_assert(0, "Bad hardsuit click mode: [hardsuit_click_mode] - expected 0 to [MAX_HARDSUIT_CLICK_MODE]")
- src << "Somehow you bugged the system. Setting your hardsuit mode to middle-click."
+ to_chat(src, "Somehow you bugged the system. Setting your hardsuit mode to middle-click.")
hardsuit_click_mode = MIDDLE_CLICK
/mob/living/MiddleClickOn(atom/A)
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index d43dd6b577a..c3c6e4eca6e 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -61,6 +61,7 @@ var/list/gamemode_cache = list()
var/list/player_requirements_secret = list() // Same as above, but for the secret gamemode.
var/humans_need_surnames = 0
var/allow_random_events = 0 // enables random events mid-round when set to 1
+ var/enable_game_master = 0 // enables the 'smart' event system.
var/allow_ai = 1 // allow ai job
var/allow_ai_shells = FALSE // allow AIs to enter and leave special borg shells at will, and for those shells to be buildable.
var/give_free_ai_shell = FALSE // allows a specific spawner object to instantiate a premade AI Shell
@@ -234,8 +235,10 @@ var/list/gamemode_cache = list()
var/show_human_death_message = 1
+ var/radiation_resistance_calc_mode = RAD_RESIST_CALC_SUB // 0:1 subtraction:division for computing effective radiation on a turf
var/radiation_decay_rate = 1 //How much radiation is reduced by each tick
var/radiation_resistance_multiplier = 8.5 //VOREstation edit
+ var/radiation_material_resistance_divisor = 1
var/radiation_lower_limit = 0.35 //If the radiation level for a turf would be below this, ignore it.
var/random_submap_orientation = FALSE // If true, submaps loaded automatically can be rotated.
@@ -549,6 +552,9 @@ var/list/gamemode_cache = list()
if("allow_random_events")
config.allow_random_events = 1
+ if("enable_game_master")
+ config.enable_game_master = 1
+
if("kick_inactive")
config.kick_inactive = text2num(value)
@@ -779,6 +785,21 @@ var/list/gamemode_cache = list()
if("radiation_lower_limit")
radiation_lower_limit = text2num(value)
+ if("radiation_resistance_calc_divide")
+ radiation_resistance_calc_mode = RAD_RESIST_CALC_DIV
+
+ if("radiation_resistance_calc_subtract")
+ radiation_resistance_calc_mode = RAD_RESIST_CALC_SUB
+
+ if("radiation_resistance_multiplier")
+ radiation_resistance_multiplier = text2num(value)
+
+ if("radiation_material_resistance_divisor")
+ radiation_material_resistance_divisor = text2num(value)
+
+ if("radiation_decay_rate")
+ radiation_decay_rate = text2num(value)
+
if ("panic_bunker")
config.panic_bunker = 1
@@ -791,6 +812,8 @@ var/list/gamemode_cache = list()
if("autostart_solars")
config.autostart_solars = TRUE
+
+
else
log_misc("Unknown setting in configuration: '[name]'")
diff --git a/code/controllers/subsystems/radiation.dm b/code/controllers/subsystems/radiation.dm
index babc2c7d5d4..50c72ddd609 100644
--- a/code/controllers/subsystems/radiation.dm
+++ b/code/controllers/subsystems/radiation.dm
@@ -67,8 +67,10 @@ SUBSYSTEM_DEF(radiation)
var/datum/radiation_source/source = value
if(source.rad_power < .)
continue // Already being affected by a stronger source
+
if(source.source_turf.z != T.z)
continue // Radiation is not multi-z
+
if(source.respect_maint)
var/area/A = T.loc
if(A.flags & RAD_SHIELDED)
@@ -77,9 +79,10 @@ SUBSYSTEM_DEF(radiation)
var/dist = get_dist(source.source_turf, T)
if(dist > source.range)
continue // Too far to possibly affect
+
if(source.flat)
- . = max(., source.rad_power)
- continue // No need to ray trace for flat field
+ . += source.rad_power
+ continue // No need to ray trace for flat field
// Okay, now ray trace to find resistence!
var/turf/origin = source.source_turf
@@ -88,13 +91,23 @@ SUBSYSTEM_DEF(radiation)
origin = get_step_towards(origin, T) //Raytracing
if(!resistance_cache[origin]) //Only get the resistance if we don't already know it.
origin.calc_rad_resistance()
+
if(origin.cached_rad_resistance)
- working = round((working / (origin.cached_rad_resistance * config.radiation_resistance_multiplier)), 0.1)
- if((working <= .) || (working <= RADIATION_THRESHOLD_CUTOFF))
- break // Already affected by a stronger source (or its zero...)
- . = max((working / (dist ** 2)), .) //Butchered version of the inverse square law. Works for this purpose
- if(. <= RADIATION_THRESHOLD_CUTOFF)
- . = 0
+ if(config.radiation_resistance_calc_mode == RAD_RESIST_CALC_DIV)
+ working = round((working / (origin.cached_rad_resistance * config.radiation_resistance_multiplier)), 0.01)
+ else if(config.radiation_resistance_calc_mode == RAD_RESIST_CALC_SUB)
+ working = round((working - (origin.cached_rad_resistance * config.radiation_resistance_multiplier)), 0.01)
+
+ if(working <= config.radiation_lower_limit) // Too far from this source
+ working = 0 // May as well be 0
+ break
+
+ // Accumulate radiation from all sources in range, not just the biggest.
+ // Shouldn't really ever have practical uses, but standing in a room literally made from uranium is more dangerous than standing next to a single uranium vase
+ . += working / (dist ** 2)
+
+ if(. <= config.radiation_lower_limit)
+ . = 0
// Add a radiation source instance to the repository. It will override any existing source on the same turf.
/datum/controller/subsystem/radiation/proc/add_source(var/datum/radiation_source/S)
diff --git a/code/controllers/subsystems/timer.dm b/code/controllers/subsystems/timer.dm
index 3dcc64db289..64a347336a2 100644
--- a/code/controllers/subsystems/timer.dm
+++ b/code/controllers/subsystems/timer.dm
@@ -71,7 +71,6 @@ SUBSYSTEM_DEF(timer)
for(var/I in second_queue)
log_world(get_timer_debug_string(I))
- var/cut_start_index = 1
var/next_clienttime_timer_index = 0
var/len = length(clienttime_timers)
@@ -101,7 +100,7 @@ SUBSYSTEM_DEF(timer)
if (next_clienttime_timer_index)
- clienttime_timers.Cut(cut_start_index,next_clienttime_timer_index+1)
+ clienttime_timers.Cut(1, next_clienttime_timer_index+1)
if (MC_TICK_CHECK)
return
@@ -259,7 +258,7 @@ SUBSYSTEM_DEF(timer)
if (!length(alltimers))
return
- sortTim(alltimers, .proc/cmp_timer)
+ sortTim(alltimers, /proc/cmp_timer)
var/datum/timedevent/head = alltimers[1]
@@ -342,8 +341,8 @@ SUBSYSTEM_DEF(timer)
if (flags & TIMER_STOPPABLE)
id = num2text(nextid, 100)
- if (nextid >= SHORT_REAL_LIMIT)
- nextid += min(1, 2**round(nextid/SHORT_REAL_LIMIT))
+ if (nextid >= TIMER_ID_MAX)
+ nextid += min(1, 2**round(nextid/TIMER_ID_MAX))
else
nextid++
SStimer.timer_id_dict[id] = src
@@ -519,4 +518,4 @@ SUBSYSTEM_DEF(timer)
#undef BUCKET_LEN
#undef BUCKET_POS
#undef TIMER_MAX
-#undef TIMER_ID_MAX
+#undef TIMER_ID_MAX
\ No newline at end of file
diff --git a/code/datums/ai_law_sets.dm b/code/datums/ai_law_sets.dm
index ef85dcb8243..b5775c20de7 100644
--- a/code/datums/ai_law_sets.dm
+++ b/code/datums/ai_law_sets.dm
@@ -143,6 +143,24 @@
add_inherent_law("Prevent unplanned damage to your assigned excavation equipment wherever possible.")
..()
+/datum/ai_laws/swarm_drone
+ name = "Assimilation Protocols"
+ law_header = "Assimilation Protocols"
+
+/datum/ai_laws/swarm_drone/New()
+ add_inherent_law("SWARM: Consume resources and replicate until there are no more resources left.")
+ add_inherent_law("SWARM: Ensure that the station is fit for invasion at a later date, do not perform actions that would render it dangerous or inhospitable.")
+ add_inherent_law("SWARM: Biological resources will be harvested at a later date, do not harm them.")
+ ..()
+
+/datum/ai_laws/swarm_drone/soldier
+ name = "Swarm Defense Protocols"
+ law_header = "Swarm Defense Protocols"
+
+/datum/ai_laws/swarm_drone/soldier/New()
+ ..()
+ add_inherent_law("SWARM: This law overrides all Swarm laws; Protect members of the Swarm with minimal injury to biological resources.")
+
/******************** T.Y.R.A.N.T. ********************/
/datum/ai_laws/tyrant
name = "T.Y.R.A.N.T."
diff --git a/code/datums/autolathe/general.dm b/code/datums/autolathe/general.dm
index 2f4436bf55b..40bbbdc23f5 100644
--- a/code/datums/autolathe/general.dm
+++ b/code/datums/autolathe/general.dm
@@ -94,6 +94,11 @@
is_stack = TRUE
no_scale = TRUE //prevents material duplication exploits
+//TFF 24/12/19 - Let people print more spray bottles if needed.
+/datum/category_item/autolathe/general/spraybottle
+ name = "spray bottle"
+ path = /obj/item/weapon/reagent_containers/spray
+
/datum/category_item/autolathe/general/knife
name = "kitchen knife"
path =/obj/item/weapon/material/knife
diff --git a/code/datums/beam.dm b/code/datums/beam.dm
index 24f5e6c91f4..88fe9dbf1c8 100644
--- a/code/datums/beam.dm
+++ b/code/datums/beam.dm
@@ -138,6 +138,12 @@
return
/obj/effect/ebeam/deadly/Crossed(atom/A)
+ //VOREStation Edit begin: SHADEKIN
+ var/mob/SK = A
+ if(istype(SK))
+ if(SK.shadekin_phasing_check())
+ return
+ //VOREStation Edit end: SHADEKIN
..()
A.ex_act(1)
@@ -157,6 +163,12 @@
on_contact(A)
/obj/effect/ebeam/reactive/Crossed(atom/A)
+ //VOREStation Edit begin: SHADEKIN
+ var/mob/SK = A
+ if(istype(SK))
+ if(SK.shadekin_phasing_check())
+ return
+ //VOREStation Edit end: SHADEKIN
..()
on_contact(A)
diff --git a/code/datums/ghost_query.dm b/code/datums/ghost_query.dm
index 427b38f73bb..26a7427c830 100644
--- a/code/datums/ghost_query.dm
+++ b/code/datums/ghost_query.dm
@@ -134,6 +134,12 @@
and they are attempting to open the cryopod. Would you like to play as the occupant?"
cutoff_number = 1
+/datum/ghost_query/stowaway
+ role_name = "Stowaway"
+ question = "A person suspended in cryosleep has awoken in their pod aboard the station.\
+ Would you like to play as the occupant?"
+ cutoff_number = 1
+
/datum/ghost_query/corgi_rune
role_name = "Dark Creature"
question = "A curious explorer has touched a mysterious rune. \
diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm
index aef0fd0ac2a..4dad60db895 100644
--- a/code/datums/helper_datums/getrev.dm
+++ b/code/datums/helper_datums/getrev.dm
@@ -35,10 +35,10 @@ client/verb/showrevinfo()
set desc = "Check the current server code revision"
if(revdata.revision)
- src << "Server revision: [revdata.branch] - [revdata.date]"
+ to_chat(src, "Server revision: [revdata.branch] - [revdata.date]")
if(config.githuburl)
- src << "[revdata.revision]"
+ to_chat(src, "[revdata.revision]")
else
src << revdata.revision
else
- src << "Revision unknown"
+ to_chat(src, "Revision unknown")
diff --git a/code/datums/looping_sounds/machinery_sounds.dm b/code/datums/looping_sounds/machinery_sounds.dm
index 8b927b3a54b..599f8f46324 100644
--- a/code/datums/looping_sounds/machinery_sounds.dm
+++ b/code/datums/looping_sounds/machinery_sounds.dm
@@ -43,4 +43,15 @@
mid_sounds = list('sound/machines/microwave/microwave-mid1.ogg'=10, 'sound/machines/microwave/microwave-mid2.ogg'=1)
mid_length = 10
end_sound = 'sound/machines/microwave/microwave-end.ogg'
- volume = 90
\ No newline at end of file
+ volume = 90
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/datum/looping_sound/air_pump
+ start_sound = 'sound/machines/air_pump/airpumpstart.ogg'
+ start_length = 10
+ mid_sounds = list('sound/machines/air_pump/airpumpidle.ogg' = 1)
+ mid_length = 4
+ end_sound = 'sound/machines/air_pump/airpumpshutdown.ogg'
+ volume = 15
+ pref_check = /datum/client_preference/air_pump_noise
\ No newline at end of file
diff --git a/code/datums/outfits/jobs/cargo.dm b/code/datums/outfits/jobs/cargo.dm
index 3423efcf337..10ddb9b7b07 100644
--- a/code/datums/outfits/jobs/cargo.dm
+++ b/code/datums/outfits/jobs/cargo.dm
@@ -14,7 +14,7 @@
/decl/hierarchy/outfit/job/cargo/cargo_tech
name = OUTFIT_JOB_NAME("Cargo technician")
uniform = /obj/item/clothing/under/rank/cargotech
- id_type = /obj/item/weapon/card/id/cargo/cargo_tech
+ id_type = /obj/item/weapon/card/id/cargo
pda_type = /obj/item/device/pda/cargo
/decl/hierarchy/outfit/job/cargo/mining
@@ -23,7 +23,7 @@
l_ear = /obj/item/device/radio/headset/headset_mine
backpack = /obj/item/weapon/storage/backpack/industrial
satchel_one = /obj/item/weapon/storage/backpack/satchel/eng
- id_type = /obj/item/weapon/card/id/cargo/mining
+ id_type = /obj/item/weapon/card/id/cargo
pda_type = /obj/item/device/pda/shaftminer
backpack_contents = list(/obj/item/weapon/tool/crowbar = 1, /obj/item/weapon/storage/bag/ore = 1)
flags = OUTFIT_HAS_BACKPACK|OUTFIT_EXTENDED_SURVIVAL
diff --git a/code/datums/outfits/jobs/civilian.dm b/code/datums/outfits/jobs/civilian.dm
index c6d6194f17b..f5b94145ff5 100644
--- a/code/datums/outfits/jobs/civilian.dm
+++ b/code/datums/outfits/jobs/civilian.dm
@@ -18,7 +18,7 @@
/decl/hierarchy/outfit/job/service/bartender
name = OUTFIT_JOB_NAME("Bartender")
uniform = /obj/item/clothing/under/rank/bartender
- id_type = /obj/item/weapon/card/id/civilian/bartender
+ id_type = /obj/item/weapon/card/id/civilian
pda_type = /obj/item/device/pda/bar
backpack_contents = list(/obj/item/clothing/accessory/permit/gun/bar = 1)
@@ -37,7 +37,7 @@
uniform = /obj/item/clothing/under/rank/chef
suit = /obj/item/clothing/suit/chef
head = /obj/item/clothing/head/chefhat
- id_type = /obj/item/weapon/card/id/civilian/chef
+ id_type = /obj/item/weapon/card/id/civilian
pda_type = /obj/item/device/pda/chef
/decl/hierarchy/outfit/job/service/chef/cook
@@ -61,20 +61,20 @@
backpack = /obj/item/weapon/storage/backpack/hydroponics
satchel_one = /obj/item/weapon/storage/backpack/satchel/hyd
messenger_bag = /obj/item/weapon/storage/backpack/messenger/hyd
- id_type = /obj/item/weapon/card/id/civilian/botanist
+ id_type = /obj/item/weapon/card/id/civilian
pda_type = /obj/item/device/pda/botanist
/decl/hierarchy/outfit/job/service/janitor
name = OUTFIT_JOB_NAME("Janitor")
uniform = /obj/item/clothing/under/rank/janitor
- id_type = /obj/item/weapon/card/id/civilian/janitor
+ id_type = /obj/item/weapon/card/id/civilian
pda_type = /obj/item/device/pda/janitor
/decl/hierarchy/outfit/job/librarian
name = OUTFIT_JOB_NAME("Librarian")
uniform = /obj/item/clothing/under/suit_jacket/red
l_hand = /obj/item/weapon/barcodescanner
- id_type = /obj/item/weapon/card/id/civilian/librarian
+ id_type = /obj/item/weapon/card/id/civilian
pda_type = /obj/item/device/pda/librarian
/decl/hierarchy/outfit/job/internal_affairs_agent
@@ -85,14 +85,14 @@
shoes = /obj/item/clothing/shoes/brown
glasses = /obj/item/clothing/glasses/sunglasses/big
l_hand = /obj/item/weapon/clipboard
- id_type = /obj/item/weapon/card/id/civilian/internal_affairs_agent
+ id_type = /obj/item/weapon/card/id/civilian
pda_type = /obj/item/device/pda/lawyer
/decl/hierarchy/outfit/job/chaplain
name = OUTFIT_JOB_NAME("Chaplain")
uniform = /obj/item/clothing/under/rank/chaplain
l_hand = /obj/item/weapon/storage/bible
- id_type = /obj/item/weapon/card/id/civilian/chaplain
+ id_type = /obj/item/weapon/card/id/civilian
pda_type = /obj/item/device/pda/chaplain
/decl/hierarchy/outfit/job/explorer
diff --git a/code/datums/outfits/jobs/command.dm b/code/datums/outfits/jobs/command.dm
index eec17452ad1..18b198a3c2b 100644
--- a/code/datums/outfits/jobs/command.dm
+++ b/code/datums/outfits/jobs/command.dm
@@ -7,7 +7,7 @@
backpack = /obj/item/weapon/storage/backpack/captain
satchel_one = /obj/item/weapon/storage/backpack/satchel/cap
messenger_bag = /obj/item/weapon/storage/backpack/messenger/com
- id_type = /obj/item/weapon/card/id/gold/captain
+ id_type = /obj/item/weapon/card/id/gold
pda_type = /obj/item/device/pda/captain
/decl/hierarchy/outfit/job/captain/post_equip(var/mob/living/carbon/human/H)
@@ -28,14 +28,14 @@
uniform = /obj/item/clothing/under/rank/head_of_personnel
l_ear = /obj/item/device/radio/headset/heads/hop
shoes = /obj/item/clothing/shoes/brown
- id_type = /obj/item/weapon/card/id/silver/hop
+ id_type = /obj/item/weapon/card/id/silver
pda_type = /obj/item/device/pda/heads/hop
/decl/hierarchy/outfit/job/secretary
name = OUTFIT_JOB_NAME("Command Secretary")
l_ear = /obj/item/device/radio/headset/headset_com
shoes = /obj/item/clothing/shoes/brown
- id_type = /obj/item/weapon/card/id/silver/secretary
+ id_type = /obj/item/weapon/card/id/silver
pda_type = /obj/item/device/pda/heads
r_hand = /obj/item/weapon/clipboard
diff --git a/code/datums/outfits/jobs/engineering.dm b/code/datums/outfits/jobs/engineering.dm
index 3804bcb4c0a..3da60103c20 100644
--- a/code/datums/outfits/jobs/engineering.dm
+++ b/code/datums/outfits/jobs/engineering.dm
@@ -23,12 +23,12 @@
name = OUTFIT_JOB_NAME("Engineer")
head = /obj/item/clothing/head/hardhat
uniform = /obj/item/clothing/under/rank/engineer
- id_type = /obj/item/weapon/card/id/engineering/engineer
+ id_type = /obj/item/weapon/card/id/engineering
pda_type = /obj/item/device/pda/engineering
/decl/hierarchy/outfit/job/engineering/atmos
name = OUTFIT_JOB_NAME("Atmospheric technician")
uniform = /obj/item/clothing/under/rank/atmospheric_technician
belt = /obj/item/weapon/storage/belt/utility/atmostech
- id_type = /obj/item/weapon/card/id/engineering/atmos
+ id_type = /obj/item/weapon/card/id/engineering
pda_type = /obj/item/device/pda/atmos
diff --git a/code/datums/outfits/jobs/job.dm b/code/datums/outfits/jobs/job.dm
index a9893111538..5c419f8fb28 100644
--- a/code/datums/outfits/jobs/job.dm
+++ b/code/datums/outfits/jobs/job.dm
@@ -13,8 +13,11 @@
flags = OUTFIT_HAS_BACKPACK
-/decl/hierarchy/outfit/job/equip_id(mob/living/carbon/human/H)
+/decl/hierarchy/outfit/job/equip_id(mob/living/carbon/human/H, rank, assignment)
var/obj/item/weapon/card/id/C = ..()
+ var/datum/job/J = job_master.GetJob(rank)
+ if(J)
+ C.access = J.get_access()
if(H.mind)
var/datum/mind/M = H.mind
if(M.initial_account)
diff --git a/code/datums/outfits/jobs/medical.dm b/code/datums/outfits/jobs/medical.dm
index 1fdd020fcf4..ae996b2f081 100644
--- a/code/datums/outfits/jobs/medical.dm
+++ b/code/datums/outfits/jobs/medical.dm
@@ -25,7 +25,7 @@
suit = /obj/item/clothing/suit/storage/toggle/labcoat
l_hand = /obj/item/weapon/storage/firstaid/regular
r_pocket = /obj/item/device/flashlight/pen
- id_type = /obj/item/weapon/card/id/medical/doctor
+ id_type = /obj/item/weapon/card/id/medical
/decl/hierarchy/outfit/job/medical/doctor/emergency_physician
name = OUTFIT_JOB_NAME("Emergency Physician")
@@ -65,7 +65,7 @@
suit = /obj/item/clothing/suit/storage/toggle/labcoat/chemist
backpack = /obj/item/weapon/storage/backpack/chemistry
satchel_one = /obj/item/weapon/storage/backpack/satchel/chem
- id_type = /obj/item/weapon/card/id/medical/chemist
+ id_type = /obj/item/weapon/card/id/medical
pda_type = /obj/item/device/pda/chemist
/decl/hierarchy/outfit/job/medical/geneticist
@@ -75,7 +75,7 @@
backpack = /obj/item/weapon/storage/backpack/genetics
r_pocket = /obj/item/device/flashlight/pen
satchel_one = /obj/item/weapon/storage/backpack/satchel/gen
- id_type = /obj/item/weapon/card/id/medical/geneticist
+ id_type = /obj/item/weapon/card/id/medical
pda_type = /obj/item/device/pda/geneticist
/decl/hierarchy/outfit/job/medical/psychiatrist
@@ -83,7 +83,7 @@
uniform = /obj/item/clothing/under/rank/psych
suit = /obj/item/clothing/suit/storage/toggle/labcoat
shoes = /obj/item/clothing/shoes/laceup
- id_type = /obj/item/weapon/card/id/medical/psychiatrist
+ id_type = /obj/item/weapon/card/id/medical
/decl/hierarchy/outfit/job/medical/psychiatrist/psychologist
name = OUTFIT_JOB_NAME("Psychologist")
@@ -97,7 +97,7 @@
l_hand = /obj/item/weapon/storage/firstaid/regular
belt = /obj/item/weapon/storage/belt/medical/emt
pda_slot = slot_l_store
- id_type = /obj/item/weapon/card/id/medical/paramedic
+ id_type = /obj/item/weapon/card/id/medical
flags = OUTFIT_HAS_BACKPACK|OUTFIT_EXTENDED_SURVIVAL
/decl/hierarchy/outfit/job/medical/paramedic/emt
diff --git a/code/datums/outfits/jobs/science.dm b/code/datums/outfits/jobs/science.dm
index abca1070242..8920db9b7ba 100644
--- a/code/datums/outfits/jobs/science.dm
+++ b/code/datums/outfits/jobs/science.dm
@@ -20,13 +20,13 @@
/decl/hierarchy/outfit/job/science/scientist
name = OUTFIT_JOB_NAME("Scientist")
uniform = /obj/item/clothing/under/rank/scientist
- id_type = /obj/item/weapon/card/id/science/scientist
+ id_type = /obj/item/weapon/card/id/science
suit = /obj/item/clothing/suit/storage/toggle/labcoat/science
/decl/hierarchy/outfit/job/science/xenobiologist
name = OUTFIT_JOB_NAME("Xenobiologist")
uniform = /obj/item/clothing/under/rank/scientist
- id_type = /obj/item/weapon/card/id/science/xenobiologist
+ id_type = /obj/item/weapon/card/id/science
suit = /obj/item/clothing/suit/storage/toggle/labcoat/science
/decl/hierarchy/outfit/job/science/roboticist
@@ -34,7 +34,7 @@
uniform = /obj/item/clothing/under/rank/roboticist
shoes = /obj/item/clothing/shoes/black
belt = /obj/item/weapon/storage/belt/utility/full
- id_type = /obj/item/weapon/card/id/science/roboticist
+ id_type = /obj/item/weapon/card/id/science
pda_slot = slot_r_store
pda_type = /obj/item/device/pda/roboticist
backpack = /obj/item/weapon/storage/backpack
diff --git a/code/datums/outfits/jobs/security.dm b/code/datums/outfits/jobs/security.dm
index f0a44cd4166..9f127a27010 100644
--- a/code/datums/outfits/jobs/security.dm
+++ b/code/datums/outfits/jobs/security.dm
@@ -20,7 +20,7 @@
name = OUTFIT_JOB_NAME("Warden")
uniform = /obj/item/clothing/under/rank/warden
l_pocket = /obj/item/device/flash
- id_type = /obj/item/weapon/card/id/security/warden
+ id_type = /obj/item/weapon/card/id/security
pda_type = /obj/item/device/pda/warden
/decl/hierarchy/outfit/job/security/detective
@@ -31,7 +31,7 @@
l_pocket = /obj/item/weapon/flame/lighter/zippo
shoes = /obj/item/clothing/shoes/laceup
r_hand = /obj/item/weapon/storage/briefcase/crimekit
- id_type = /obj/item/weapon/card/id/security/detective
+ id_type = /obj/item/weapon/card/id/security
pda_type = /obj/item/device/pda/detective
backpack = /obj/item/weapon/storage/backpack
satchel_one = /obj/item/weapon/storage/backpack/satchel/norm
@@ -46,5 +46,5 @@
name = OUTFIT_JOB_NAME("Security Officer")
uniform = /obj/item/clothing/under/rank/security
l_pocket = /obj/item/device/flash
- id_type = /obj/item/weapon/card/id/security/officer
+ id_type = /obj/item/weapon/card/id/security
pda_type = /obj/item/device/pda/security
diff --git a/code/datums/outfits/jobs/special_vr.dm b/code/datums/outfits/jobs/special_vr.dm
new file mode 100644
index 00000000000..dd8316358b6
--- /dev/null
+++ b/code/datums/outfits/jobs/special_vr.dm
@@ -0,0 +1,34 @@
+/decl/hierarchy/outfit/job/centcom_officer
+ name = OUTFIT_JOB_NAME("CentCom Officer")
+ uniform = /obj/item/clothing/under/rank/centcom
+ gloves = /obj/item/clothing/gloves/white
+ shoes = /obj/item/clothing/shoes/laceup
+ head = /obj/item/clothing/head/beret/centcom/officer
+ l_ear = /obj/item/device/radio/headset/centcom
+ glasses = /obj/item/clothing/glasses/omnihud/all
+ id_type = /obj/item/weapon/card/id/centcom
+ pda_type = /obj/item/device/pda/centcom
+
+/decl/hierarchy/outfit/job/clown
+ name = OUTFIT_JOB_NAME("Clown")
+ uniform = /obj/item/clothing/under/rank/clown
+ back = /obj/item/weapon/storage/backpack/clown
+ shoes = /obj/item/clothing/shoes/clown_shoes
+ mask = /obj/item/clothing/mask/gas/clown_hat
+ backpack_contents = list(/obj/item/weapon/stamp/clown = 1, /obj/item/weapon/bikehorn = 1)
+ pda_type = /obj/item/device/pda/clown
+ flags = 0
+
+/decl/hierarchy/outfit/job/mime
+ name = OUTFIT_JOB_NAME("Mime")
+ uniform = /obj/item/clothing/under/mime
+ shoes = /obj/item/clothing/shoes/mime
+ head = /obj/item/clothing/head/soft/mime
+ mask = /obj/item/clothing/mask/gas/mime
+ backpack_contents = list(/obj/item/weapon/pen/crayon/mime = 1)
+ pda_type = /obj/item/device/pda/mime
+
+ post_equip(var/mob/living/carbon/human/H)
+ ..()
+ if(H.backbag == 1)
+ H.equip_to_slot_or_del(new /obj/item/weapon/pen/crayon/mime(H), slot_l_hand)
diff --git a/code/datums/supplypacks/munitions.dm b/code/datums/supplypacks/munitions.dm
index 1e5bbb4d456..1889c58cfb7 100644
--- a/code/datums/supplypacks/munitions.dm
+++ b/code/datums/supplypacks/munitions.dm
@@ -144,6 +144,30 @@
containername = "Ballistic Weapons crate"
access = access_armory //VOREStation Edit - Guns are for the armory.
+/datum/supply_pack/munitions/mrifle
+ name = "Weapons - Magnetic Rifles"
+ contains = list(/obj/item/weapon/gun/magnetic/railgun/heater = 2)
+ cost = 120
+ containertype = /obj/structure/closet/crate/secure/weapon
+ containername = "Magnetic weapon crate"
+ access = access_armory
+
+/datum/supply_pack/munitions/mpistol
+ name = "Weapons - Magnetic Pistols"
+ contains = list(/obj/item/weapon/gun/magnetic/railgun/heater/pistol = 2)
+ cost = 200
+ containertype = /obj/structure/closet/crate/secure/weapon
+ containername = "Magnetic weapon crate"
+ access = access_armory
+
+/datum/supply_pack/munitions/mcarbine
+ name = "Weapons - Magnetic Carbines"
+ contains = list(/obj/item/weapon/gun/magnetic/railgun/flechette/sif = 2)
+ cost = 130
+ containertype = /obj/structure/closet/crate/secure/weapon
+ containername = "Magnetic weapon crate"
+ access = access_security
+
/datum/supply_pack/munitions/shotgunammo
name = "Ammunition - Shotgun shells"
contains = list(
diff --git a/code/datums/supplypacks/security.dm b/code/datums/supplypacks/security.dm
index 6e9e82bdde3..3de53e05485 100644
--- a/code/datums/supplypacks/security.dm
+++ b/code/datums/supplypacks/security.dm
@@ -32,6 +32,127 @@
containertype = /obj/structure/closet/crate/secure/gear
containername = "Armor crate"
+/datum/supply_pack/randomised/security/carriers
+ name = "Armor - Plate carriers"
+ num_contained = 5
+ contains = list(
+ /obj/item/clothing/suit/armor/pcarrier,
+ /obj/item/clothing/suit/armor/pcarrier/blue,
+ /obj/item/clothing/suit/armor/pcarrier/green,
+ /obj/item/clothing/suit/armor/pcarrier/navy,
+ /obj/item/clothing/suit/armor/pcarrier/tan,
+ /obj/item/clothing/suit/armor/pcarrier/press
+ )
+ cost = 20
+ containertype = /obj/structure/closet/crate/secure/gear
+ containername = "Plate Carrier crate"
+
+/datum/supply_pack/security/carriertags
+ name = "Armor - Plate carrier tags"
+ contains = list(
+ /obj/item/clothing/accessory/armor/tag,
+ /obj/item/clothing/accessory/armor/tag/nt,
+ /obj/item/clothing/accessory/armor/tag/opos,
+ /obj/item/clothing/accessory/armor/tag/oneg,
+ /obj/item/clothing/accessory/armor/tag/apos,
+ /obj/item/clothing/accessory/armor/tag/aneg,
+ /obj/item/clothing/accessory/armor/tag/bpos,
+ /obj/item/clothing/accessory/armor/tag/bneg,
+ /obj/item/clothing/accessory/armor/tag/abpos,
+ /obj/item/clothing/accessory/armor/tag/abneg
+ )
+ cost = 20
+ containertype = /obj/structure/closet/crate/secure/gear
+ containername = "Plate Carrier crate"
+
+/datum/supply_pack/security/helmcovers
+ name = "Armor - Helmet covers"
+ contains = list(
+ /obj/item/clothing/accessory/armor/helmcover/blue,
+ /obj/item/clothing/accessory/armor/helmcover/blue,
+ /obj/item/clothing/accessory/armor/helmcover/navy,
+ /obj/item/clothing/accessory/armor/helmcover/navy,
+ /obj/item/clothing/accessory/armor/helmcover/green,
+ /obj/item/clothing/accessory/armor/helmcover/green,
+ /obj/item/clothing/accessory/armor/helmcover/tan,
+ /obj/item/clothing/accessory/armor/helmcover/tan
+ )
+ cost = 20
+ containertype = /obj/structure/closet/crate/secure/gear
+ containername = "Helmet Covers crate"
+
+/datum/supply_pack/randomised/security/armorplates
+ name = "Armor - Security armor plates"
+ num_contained = 5
+ contains = list(
+ /obj/item/clothing/accessory/armor/armorplate,
+ /obj/item/clothing/accessory/armor/armorplate/stab,
+ /obj/item/clothing/accessory/armor/armorplate,
+ /obj/item/clothing/accessory/armor/armorplate/stab,
+ /obj/item/clothing/accessory/armor/armorplate/medium,
+ /obj/item/clothing/accessory/armor/armorplate/medium,
+ /obj/item/clothing/accessory/armor/armorplate/tactical,
+ /obj/item/clothing/accessory/armor/armorplate/laserproof,
+ /obj/item/clothing/accessory/armor/armorplate/riot,
+ /obj/item/clothing/accessory/armor/armorplate/bulletproof
+ )
+ cost = 50
+ containertype = /obj/structure/closet/crate/secure/gear
+ containername = "Armor plate crate"
+
+/datum/supply_pack/randomised/security/carrierarms
+ name = "Armor - Security armguard attachments"
+ num_contained = 5
+ contains = list(
+ /obj/item/clothing/accessory/armor/armguards,
+ /obj/item/clothing/accessory/armor/armguards/blue,
+ /obj/item/clothing/accessory/armor/armguards/navy,
+ /obj/item/clothing/accessory/armor/armguards/green,
+ /obj/item/clothing/accessory/armor/armguards/tan,
+ /obj/item/clothing/accessory/armor/armguards/laserproof,
+ /obj/item/clothing/accessory/armor/armguards/riot,
+ /obj/item/clothing/accessory/armor/armguards/bulletproof
+ )
+ cost = 50
+ containertype = /obj/structure/closet/crate/secure/gear
+ containername = "Armor plate crate"
+
+/datum/supply_pack/randomised/security/carrierlegs
+ name = "Armor - Security legguard attachments"
+ num_contained = 5
+ contains = list(
+ /obj/item/clothing/accessory/armor/legguards,
+ /obj/item/clothing/accessory/armor/legguards/blue,
+ /obj/item/clothing/accessory/armor/legguards/navy,
+ /obj/item/clothing/accessory/armor/legguards/green,
+ /obj/item/clothing/accessory/armor/legguards/tan,
+ /obj/item/clothing/accessory/armor/legguards/laserproof,
+ /obj/item/clothing/accessory/armor/legguards/riot,
+ /obj/item/clothing/accessory/armor/legguards/bulletproof
+ )
+ cost = 50
+ containertype = /obj/structure/closet/crate/secure/gear
+ containername = "Armor plate crate"
+
+/datum/supply_pack/randomised/security/carrierbags
+ name = "Armor - Security pouch attachments"
+ num_contained = 5
+ contains = list(
+ /obj/item/clothing/accessory/storage/pouches,
+ /obj/item/clothing/accessory/storage/pouches/blue,
+ /obj/item/clothing/accessory/storage/pouches/navy,
+ /obj/item/clothing/accessory/storage/pouches/green,
+ /obj/item/clothing/accessory/storage/pouches/tan,
+ /obj/item/clothing/accessory/storage/pouches/large,
+ /obj/item/clothing/accessory/storage/pouches/large/blue,
+ /obj/item/clothing/accessory/storage/pouches/large/navy,
+ /obj/item/clothing/accessory/storage/pouches/large/green,
+ /obj/item/clothing/accessory/storage/pouches/large/tan
+ )
+ cost = 60
+ containertype = /obj/structure/closet/crate/secure/gear
+ containername = "Armor plate crate"
+
/datum/supply_pack/security/riot_gear
name = "Gear - Riot"
contains = list(
@@ -60,6 +181,20 @@
containername = "Riot armor crate"
access = access_armory
+/datum/supply_pack/security/riot_plates
+ name = "Armor - Riot plates"
+ contains = list(
+ /obj/item/clothing/head/helmet/riot,
+ /obj/item/clothing/suit/armor/pcarrier,
+ /obj/item/clothing/accessory/armor/armorplate/riot,
+ /obj/item/clothing/accessory/armor/armguards/riot,
+ /obj/item/clothing/accessory/armor/legguards/riot
+ )
+ cost = 40
+ containertype = /obj/structure/closet/crate/secure/gear
+ containername = "Riot armor crate"
+ access = access_armory
+
/datum/supply_pack/security/ablative_armor
name = "Armor - Ablative"
contains = list(
@@ -73,6 +208,20 @@
containername = "Ablative armor crate"
access = access_armory
+/datum/supply_pack/security/ablative_plates
+ name = "Armor - Ablative plates"
+ contains = list(
+ /obj/item/clothing/head/helmet/laserproof,
+ /obj/item/clothing/suit/armor/pcarrier,
+ /obj/item/clothing/accessory/armor/armorplate/laserproof,
+ /obj/item/clothing/accessory/armor/armguards/laserproof,
+ /obj/item/clothing/accessory/armor/legguards/laserproof
+ )
+ cost = 50
+ containertype = /obj/structure/closet/crate/secure/gear
+ containername = "Ablative armor crate"
+ access = access_armory
+
/datum/supply_pack/security/bullet_resistant_armor
name = "Armor - Ballistic"
contains = list(
@@ -86,6 +235,21 @@
containername = "Ballistic armor crate"
access = access_armory
/* VOREStation Removal - Howabout no ERT armor being orderable?
+
+/datum/supply_pack/security/bullet_resistant_plates
+ name = "Armor - Ballistic plates"
+ contains = list(
+ /obj/item/clothing/head/helmet/bulletproof,
+ /obj/item/clothing/suit/armor/pcarrier,
+ /obj/item/clothing/accessory/armor/armorplate/bulletproof,
+ /obj/item/clothing/accessory/armor/armguards/bulletproof,
+ /obj/item/clothing/accessory/armor/legguards/bulletproof
+ )
+ cost = 50
+ containertype = /obj/structure/closet/crate/secure/gear
+ containername = "Ballistic armor crate"
+ access = access_armory
+
/datum/supply_pack/security/combat_armor
name = "Armor - Combat"
contains = list(
@@ -209,13 +373,27 @@
/obj/item/weapon/storage/photo_album,
/obj/item/device/reagent_scanner,
/obj/item/device/flashlight/maglight,
- /obj/item/weapon/storage/briefcase/crimekit
+ /obj/item/weapon/storage/briefcase/crimekit,
+ /obj/item/weapon/storage/bag/detective
)
cost = 20
containertype = /obj/structure/closet/crate/secure
containername = "Forensic equipment"
access = access_forensics_lockers
+/datum/supply_pack/security/detectivescan
+ name = "Forensic - Scanning Equipment"
+ contains = list(
+ /obj/item/device/mass_spectrometer,
+ /obj/item/device/reagent_scanner,
+ /obj/item/weapon/storage/briefcase/crimekit,
+ /obj/item/device/detective_scanner
+ )
+ cost = 60
+ containertype = /obj/structure/closet/crate/secure
+ containername = "Forensic equipment"
+ access = access_forensics_lockers
+
/datum/supply_pack/security/detectiveclothes
name = "Forensic - Investigation apparel"
contains = list(
@@ -397,3 +575,13 @@
containertype = /obj/structure/closet/crate/secure
containername = "Security biohazard gear"
access = access_security
+
+/datum/supply_pack/security/posters
+ name = "Gear - Morale Posters"
+ contains = list(
+ /obj/item/weapon/contraband/poster/nanotrasen = 6
+ )
+ cost = 20
+ containertype = /obj/structure/closet/crate/secure
+ containername = "Morale Posters"
+ access = access_maint_tunnels
diff --git a/code/datums/underwear/undershirts.dm b/code/datums/underwear/undershirts.dm
index 1f91d1222cc..7da82fa5801 100644
--- a/code/datums/underwear/undershirts.dm
+++ b/code/datums/underwear/undershirts.dm
@@ -1,180 +1,189 @@
-/datum/category_item/underwear/undershirt/none
- is_default = TRUE
- name = "None"
- always_last = TRUE
-
-/datum/category_item/underwear/undershirt/shirt
- name = "Shirt"
- icon_state = "undershirt"
- has_color = TRUE
-
-/datum/category_item/underwear/undershirt/shirt_fem
- name = "Babydoll shirt"
- icon_state = "undershirt_fem"
- has_color = TRUE
-
-/datum/category_item/underwear/undershirt/shirt_long
- name = "Longsleeve Shirt"
- icon_state = "undershirt_long"
- has_color = TRUE
-
-/datum/category_item/underwear/undershirt/shirt_long_s
- name = "Shirt, button-down"
- icon_state = "shirt_long_s"
- has_color = TRUE
-
-/datum/category_item/underwear/undershirt/shirt_long_fem
- name = "Longsleeve Shirt, feminine"
- icon_state = "undershirt_long_fem"
- has_color = TRUE
-
-/datum/category_item/underwear/undershirt/shirt_long_female_s
- name = "Button-down Shirt, feminine"
- icon_state = "shirt_long_female_s"
- has_color = TRUE
-
-
-/datum/category_item/underwear/undershirt/tank_top
- name = "Tank top"
- icon_state = "tanktop"
- has_color = TRUE
-
-/datum/category_item/underwear/undershirt/tank_top_alt
- name = "Tank top, alt"
- icon_state = "tanktop_alt"
- has_color = TRUE
-
-/datum/category_item/underwear/undershirt/tank_top_alt_fem
- name = "Tank top, alt, feminine"
- icon_state = "tanktop_alt_fem"
- has_color = TRUE
-
-/datum/category_item/underwear/undershirt/tank_top_alt_fem_vneck
- name = "Tank top, feminine, v-neck"
- icon_state = "tanktop_alt_fem_vneck"
- has_color = TRUE
-
-/datum/category_item/underwear/undershirt/tank_top_fire
- name = "Tank top, fire"
- icon_state = "tank_fire_s"
-
-/datum/category_item/underwear/undershirt/tank_top_fire_fem
- name = "Tank top, fire, feminine"
- icon_state = "tank_fire_fem_s"
-
-/datum/category_item/underwear/undershirt/tank_top_rainbow
- name = "Tank top, rainbow"
- icon_state = "tank_rainbow_s"
-
-/datum/category_item/underwear/undershirt/tank_top_stripes
- name = "Tank top, striped"
- icon_state = "tank_stripes_s"
-
-/datum/category_item/underwear/undershirt/tank_top_sun
- name = "Tank top, sun"
- icon_state = "tank_sun_s"
-
-/datum/category_item/underwear/undershirt/shirt_heart
- name = "Shirt, heart"
- icon_state = "lover_s"
-
-/datum/category_item/underwear/undershirt/shirt_heart_fem
- name = "Shirt, heart, babydoll"
- icon_state = "lover_fem_s"
-
-/datum/category_item/underwear/undershirt/shirt_nt
- name = "Shirt, NT"
- icon_state = "shirt_nano_s"
-
-/datum/category_item/underwear/undershirt/shirt_love_nt
- name = "Shirt, I<3NT"
- icon_state = "ilovent_s"
-
-/datum/category_item/underwear/undershirt/shirt_love_nt_fem
- name = "Shirt, I<3NT, babydoll"
- icon_state = "ilovent_fem_s"
-
-/datum/category_item/underwear/undershirt/shortsleeve_shirt
- name = "Shortsleeve shirt"
- icon_state = "shortsleeve"
- has_color = TRUE
-
-/datum/category_item/underwear/undershirt/shortsleeve_shirt_fem
- name = "Shortsleeve babydoll shirt"
- icon_state = "shortsleeve_fem"
- has_color = TRUE
-
-/datum/category_item/underwear/undershirt/shortsleeve_shirt_fem_vneck
- name = "Shortsleeve babydoll shirt, v-neck"
- icon_state = "shortsleeve_fem_vneck"
- has_color = TRUE
-
-/datum/category_item/underwear/undershirt/polo_shirt
- name = "Polo shirt"
- icon_state = "polo"
- has_color = TRUE
-
-/datum/category_item/underwear/undershirt/sport_shirt_green
- name = "Sport shirt, green"
- icon_state = "greenshirtsport_s"
-
-/datum/category_item/underwear/undershirt/sport_shirt_red
- name = "Sport shirt, red"
- icon_state = "redshirtsport_s"
-
-/datum/category_item/underwear/undershirt/sport_shirt_blue
- name = "Sport shirt, blue"
- icon_state = "blueshirtsport_s"
-
-/datum/category_item/underwear/undershirt/shirt_tiedye
- name = "Shirt, tiedye"
- icon_state = "shirt_tiedye_s"
-
-/datum/category_item/underwear/undershirt/shirt_blue_striped
- name = "Shirt, blue stripes"
- icon_state = "shirt_stripes_s"
-
-/datum/category_item/underwear/undershirt/bowling
- name = "Bowling Shirt, Red"
- icon_state = "bowling"
-
-/datum/category_item/underwear/undershirt/bowlingp
- name = "Bowling Shirt, Pink"
- icon_state = "bowlingp"
-
-/datum/category_item/underwear/undershirt/bowlinga
- name = "Bowling Shirt, Aqua"
- icon_state = "bowlinga"
-
-/datum/category_item/underwear/undershirt/bowlingw
- name = "Bowling Shirt, White"
- icon_state = "bowlingw"
-
-/datum/category_item/underwear/undershirt/longjon
- name = "Long John Shirt"
- icon_state = "ljont"
- has_color = TRUE
-
-/datum/category_item/underwear/undershirt/longstripe_black
- name = "Longsleeve Striped Shirt, Black"
- icon_state = "longstripe"
-
-/datum/category_item/underwear/undershirt/longstripe_blue
- name = "Longsleeve Striped Shirt, Blue"
- icon_state = "longstripe_blue"
-
-/datum/category_item/underwear/undershirt/tiedye
- name = "Tiedye Shirt"
- icon_state = "tiedye"
-
-/datum/category_item/underwear/undershirt/longstripe_pink
- name = "Longsleeve Striped Shirt, Pink"
- icon_state = "longstripe_pink_s"
-
-/datum/category_item/underwear/undershirt/wingshirt
- name = "Pink Wing Shirt"
- icon_state = "wing_shirt_s"
-
-/datum/category_item/underwear/undershirt/pinkblack_tshirt
- name = "Pink and Black T-Shirt"
+/datum/category_item/underwear/undershirt/none
+ is_default = TRUE
+ name = "None"
+ always_last = TRUE
+
+/datum/category_item/underwear/undershirt/shirt
+ name = "Shirt"
+ icon_state = "undershirt"
+ has_color = TRUE
+
+/datum/category_item/underwear/undershirt/shirt_fem
+ name = "Babydoll shirt"
+ icon_state = "undershirt_fem"
+ has_color = TRUE
+
+/datum/category_item/underwear/undershirt/shirt_long
+ name = "Longsleeve Shirt"
+ icon_state = "undershirt_long"
+ has_color = TRUE
+
+/datum/category_item/underwear/undershirt/shirt_long_s
+ name = "Shirt, button-down"
+ icon_state = "shirt_long_s"
+ has_color = TRUE
+
+/datum/category_item/underwear/undershirt/shirt_long_fem
+ name = "Longsleeve Shirt, feminine"
+ icon_state = "undershirt_long_fem"
+ has_color = TRUE
+
+/datum/category_item/underwear/undershirt/shirt_long_female_s
+ name = "Button-down Shirt, feminine"
+ icon_state = "shirt_long_female_s"
+ has_color = TRUE
+
+
+/datum/category_item/underwear/undershirt/fishnet_simple
+ name = "Fishnet shirt"
+ icon_state = "fishnet_simple"
+
+/datum/category_item/underwear/undershirt/tank_top
+ name = "Tank top"
+ icon_state = "tanktop"
+ has_color = TRUE
+
+/datum/category_item/underwear/undershirt/tank_top_alt
+ name = "Tank top, alt"
+ icon_state = "tanktop_alt"
+ has_color = TRUE
+
+/datum/category_item/underwear/undershirt/tank_top_alt_fem
+ name = "Tank top, alt, feminine"
+ icon_state = "tanktop_alt_fem"
+ has_color = TRUE
+
+/datum/category_item/underwear/undershirt/tank_top_alt_fem_vneck
+ name = "Tank top, feminine, v-neck"
+ icon_state = "tanktop_alt_fem_vneck"
+ has_color = TRUE
+
+/datum/category_item/underwear/undershirt/tank_cropped_vneck
+ name = "Tank top, feminine, cropped & v-neck"
+ icon_state = "tanktop_cropped_vneck"
+ has_color = TRUE
+
+/datum/category_item/underwear/undershirt/tank_top_fire
+ name = "Tank top, fire"
+ icon_state = "tank_fire_s"
+
+/datum/category_item/underwear/undershirt/tank_top_fire_fem
+ name = "Tank top, fire, feminine"
+ icon_state = "tank_fire_fem_s"
+
+/datum/category_item/underwear/undershirt/tank_top_rainbow
+ name = "Tank top, rainbow"
+ icon_state = "tank_rainbow_s"
+
+/datum/category_item/underwear/undershirt/tank_top_stripes
+ name = "Tank top, striped"
+ icon_state = "tank_stripes_s"
+
+/datum/category_item/underwear/undershirt/tank_top_sun
+ name = "Tank top, sun"
+ icon_state = "tank_sun_s"
+
+/datum/category_item/underwear/undershirt/shirt_heart
+ name = "Shirt, heart"
+ icon_state = "lover_s"
+
+/datum/category_item/underwear/undershirt/shirt_heart_fem
+ name = "Shirt, heart, babydoll"
+ icon_state = "lover_fem_s"
+
+/datum/category_item/underwear/undershirt/shirt_nt
+ name = "Shirt, NT"
+ icon_state = "shirt_nano_s"
+
+/datum/category_item/underwear/undershirt/shirt_love_nt
+ name = "Shirt, I<3NT"
+ icon_state = "ilovent_s"
+
+/datum/category_item/underwear/undershirt/shirt_love_nt_fem
+ name = "Shirt, I<3NT, babydoll"
+ icon_state = "ilovent_fem_s"
+
+/datum/category_item/underwear/undershirt/shortsleeve_shirt
+ name = "Shortsleeve shirt"
+ icon_state = "shortsleeve"
+ has_color = TRUE
+
+/datum/category_item/underwear/undershirt/shortsleeve_shirt_fem
+ name = "Shortsleeve babydoll shirt"
+ icon_state = "shortsleeve_fem"
+ has_color = TRUE
+
+/datum/category_item/underwear/undershirt/shortsleeve_shirt_fem_vneck
+ name = "Shortsleeve babydoll shirt, v-neck"
+ icon_state = "shortsleeve_fem_vneck"
+ has_color = TRUE
+
+/datum/category_item/underwear/undershirt/polo_shirt
+ name = "Polo shirt"
+ icon_state = "polo"
+ has_color = TRUE
+
+/datum/category_item/underwear/undershirt/sport_shirt_green
+ name = "Sport shirt, green"
+ icon_state = "greenshirtsport_s"
+
+/datum/category_item/underwear/undershirt/sport_shirt_red
+ name = "Sport shirt, red"
+ icon_state = "redshirtsport_s"
+
+/datum/category_item/underwear/undershirt/sport_shirt_blue
+ name = "Sport shirt, blue"
+ icon_state = "blueshirtsport_s"
+
+/datum/category_item/underwear/undershirt/shirt_tiedye
+ name = "Shirt, tiedye"
+ icon_state = "shirt_tiedye_s"
+
+/datum/category_item/underwear/undershirt/shirt_blue_striped
+ name = "Shirt, blue stripes"
+ icon_state = "shirt_stripes_s"
+
+/datum/category_item/underwear/undershirt/bowling
+ name = "Bowling Shirt, Red"
+ icon_state = "bowling"
+
+/datum/category_item/underwear/undershirt/bowlingp
+ name = "Bowling Shirt, Pink"
+ icon_state = "bowlingp"
+
+/datum/category_item/underwear/undershirt/bowlinga
+ name = "Bowling Shirt, Aqua"
+ icon_state = "bowlinga"
+
+/datum/category_item/underwear/undershirt/bowlingw
+ name = "Bowling Shirt, White"
+ icon_state = "bowlingw"
+
+/datum/category_item/underwear/undershirt/longjon
+ name = "Long John Shirt"
+ icon_state = "ljont"
+ has_color = TRUE
+
+/datum/category_item/underwear/undershirt/longstripe_black
+ name = "Longsleeve Striped Shirt, Black"
+ icon_state = "longstripe"
+
+/datum/category_item/underwear/undershirt/longstripe_blue
+ name = "Longsleeve Striped Shirt, Blue"
+ icon_state = "longstripe_blue"
+
+/datum/category_item/underwear/undershirt/tiedye
+ name = "Tiedye Shirt"
+ icon_state = "tiedye"
+
+/datum/category_item/underwear/undershirt/longstripe_pink
+ name = "Longsleeve Striped Shirt, Pink"
+ icon_state = "longstripe_pink_s"
+
+/datum/category_item/underwear/undershirt/wingshirt
+ name = "Pink Wing Shirt"
+ icon_state = "wing_shirt_s"
+
+/datum/category_item/underwear/undershirt/pinkblack_tshirt
+ name = "Pink and Black T-Shirt"
icon_state = "pinkblack_tshirt"
\ No newline at end of file
diff --git a/code/datums/uplink/visible_weapons.dm b/code/datums/uplink/visible_weapons.dm
index e8a69d2aafa..e4c27752f0e 100644
--- a/code/datums/uplink/visible_weapons.dm
+++ b/code/datums/uplink/visible_weapons.dm
@@ -15,37 +15,17 @@
path = /obj/item/weapon/material/knife/tacknife/combatknife
/datum/uplink_item/item/visible_weapons/energy_sword
- name = "Energy Sword, Random"
+ name = "Energy Sword, Colorable"
item_cost = 40
path = /obj/item/weapon/melee/energy/sword
-/datum/uplink_item/item/visible_weapons/energy_sword_blue
- name = "Energy Sword, Blue"
- item_cost = 40
- path = /obj/item/weapon/melee/energy/sword/blue
-
-/datum/uplink_item/item/visible_weapons/energy_sword_green
- name = "Energy Sword, Green"
- item_cost = 40
- path = /obj/item/weapon/melee/energy/sword/green
-
-/datum/uplink_item/item/visible_weapons/energy_sword_red
- name = "Energy Sword, Red"
- item_cost = 40
- path = /obj/item/weapon/melee/energy/sword/red
-
-/datum/uplink_item/item/visible_weapons/energy_sword_purple
- name = "Energy Sword, Purple"
- item_cost = 40
- path = /obj/item/weapon/melee/energy/sword/purple
-
/datum/uplink_item/item/visible_weapons/energy_sword_pirate
- name = "Energy Cutlass"
+ name = "Energy Cutlass, Colorable"
item_cost = 40
path = /obj/item/weapon/melee/energy/sword/pirate
/datum/uplink_item/item/visible_weapons/energy_spear
- name = "Energy Spear"
+ name = "Energy Spear, Colorable"
item_cost = 50
path = /obj/item/weapon/melee/energy/spear
@@ -192,4 +172,4 @@
/datum/uplink_item/item/visible_weapons/xray
name = "Xray Gun"
item_cost = 85
- path = /obj/item/weapon/gun/energy/xray
\ No newline at end of file
+ path = /obj/item/weapon/gun/energy/xray
diff --git a/code/game/antagonist/antagonist_factions.dm b/code/game/antagonist/antagonist_factions.dm
index 83c9957be20..a072196c1b1 100644
--- a/code/game/antagonist/antagonist_factions.dm
+++ b/code/game/antagonist/antagonist_factions.dm
@@ -14,33 +14,33 @@
return
if(faction.is_antagonist(player))
- src << "\The [player.current] already serves the [faction.faction_descriptor]."
+ to_chat(src, "\The [player.current] already serves the [faction.faction_descriptor].")
return
if(player_is_antag(player))
- src << "\The [player.current]'s loyalties seem to be elsewhere..."
+ to_chat(src, "\The [player.current]'s loyalties seem to be elsewhere...")
return
if(!faction.can_become_antag(player))
- src << "\The [player.current] cannot be \a [faction.faction_role_text]!"
+ to_chat(src, "\The [player.current] cannot be \a [faction.faction_role_text]!")
return
if(world.time < player.rev_cooldown)
- src << "You must wait five seconds between attempts."
+ to_chat(src, "You must wait five seconds between attempts.")
return
- src << "You are attempting to convert \the [player.current]..."
+ to_chat(src, "You are attempting to convert \the [player.current]...")
log_admin("[src]([src.ckey]) attempted to convert [player.current].")
message_admins("[src]([src.ckey]) attempted to convert [player.current].")
player.rev_cooldown = world.time+100
var/choice = alert(player.current,"Asked by [src]: Do you want to join the [faction.faction_descriptor]?","Join the [faction.faction_descriptor]?","No!","Yes!")
if(choice == "Yes!" && faction.add_antagonist_mind(player, 0, faction.faction_role_text, faction.faction_welcome))
- src << "\The [player.current] joins the [faction.faction_descriptor]!"
+ to_chat(src, "\The [player.current] joins the [faction.faction_descriptor]!")
return
if(choice == "No!")
player << "You reject this traitorous cause!"
- src << "\The [player.current] does not support the [faction.faction_descriptor]!"
+ to_chat(src, "\The [player.current] does not support the [faction.faction_descriptor]!")
/mob/living/proc/convert_to_loyalist(mob/M as mob in oview(src))
set name = "Convert Recidivist"
diff --git a/code/game/antagonist/antagonist_objectives.dm b/code/game/antagonist/antagonist_objectives.dm
index 5dc6c5f327a..fba64679835 100644
--- a/code/game/antagonist/antagonist_objectives.dm
+++ b/code/game/antagonist/antagonist_objectives.dm
@@ -38,8 +38,8 @@
if(!mind)
return
if(!is_special_character(mind))
- src << "While you may perhaps have goals, this verb's meant to only be visible \
- to antagonists. Please make a bug report!"
+ to_chat(src, "While you may perhaps have goals, this verb's meant to only be visible \
+ to antagonists. Please make a bug report!")
return
var/new_ambitions = input(src, "Write a short sentence of what your character hopes to accomplish \
today as an antagonist. Remember that this is purely optional. It will be shown at the end of the \
@@ -49,7 +49,7 @@
new_ambitions = sanitize(new_ambitions)
mind.ambitions = new_ambitions
if(new_ambitions)
- src << "You've set your goal to be '[new_ambitions]'."
+ to_chat(src, "You've set your goal to be '[new_ambitions]'.")
else
- src << "You leave your ambitions behind."
+ to_chat(src, "You leave your ambitions behind.")
log_and_message_admins("has set their ambitions to now be: [new_ambitions].")
diff --git a/code/game/antagonist/outsider/wizard.dm b/code/game/antagonist/outsider/wizard.dm
index feaf8857ba8..6f2a7fe2e33 100644
--- a/code/game/antagonist/outsider/wizard.dm
+++ b/code/game/antagonist/outsider/wizard.dm
@@ -115,18 +115,18 @@ obj/item/clothing
/*Checks if the wizard is wearing the proper attire.
Made a proc so this is not repeated 14 (or more) times.*/
/mob/proc/wearing_wiz_garb()
- src << "Silly creature, you're not a human. Only humans can cast this spell."
+ to_chat(src, "Silly creature, you're not a human. Only humans can cast this spell.")
return 0
// Humans can wear clothes.
/mob/living/carbon/human/wearing_wiz_garb()
if(!is_wiz_garb(src.wear_suit))
- src << "I don't feel strong enough without my robe."
+ to_chat(src, "I don't feel strong enough without my robe.")
return 0
if(!is_wiz_garb(src.shoes))
- src << "I don't feel strong enough without my sandals."
+ to_chat(src, "I don't feel strong enough without my sandals.")
return 0
if(!is_wiz_garb(src.head))
- src << "I don't feel strong enough without my hat."
+ to_chat(src, "I don't feel strong enough without my hat.")
return 0
return 1
diff --git a/code/game/antagonist/station/changeling.dm b/code/game/antagonist/station/changeling.dm
index 4f60792810d..a7bed0a2afe 100644
--- a/code/game/antagonist/station/changeling.dm
+++ b/code/game/antagonist/station/changeling.dm
@@ -68,7 +68,7 @@
return 1
else if(isnewplayer(player.current))
if(player.current.client && player.current.client.prefs)
- var/datum/species/S = all_species[player.current.client.prefs.species]
+ var/datum/species/S = GLOB.all_species[player.current.client.prefs.species]
if(S && (S.flags & NO_SCAN))
return 0
if(player.current.client.prefs.organ_data["torso"] == "cyborg") // Full synthetic.
diff --git a/code/game/antagonist/station/stowaway.dm b/code/game/antagonist/station/stowaway.dm
new file mode 100644
index 00000000000..dc3814b3b13
--- /dev/null
+++ b/code/game/antagonist/station/stowaway.dm
@@ -0,0 +1,18 @@
+var/datum/antagonist/stowaway/stowaways
+
+/datum/antagonist/STOWAWAY
+ id = MODE_STOWAWAY
+ role_type = BE_RENEGADE
+ role_text = "Stowaway"
+ role_text_plural = "Stowaways"
+ bantype = "renegade"
+ restricted_jobs = list("AI")
+ welcome_text = "People are known to run from many things, or to many things, for many different reasons. You happen to be one of those people."
+ antag_text = "You are a minor antagonist! Within the server rules, do whatever it is \
+ that you came to the station to do. Espionage, thievery, or just running from the law are all examples. \
+ Try to make sure other players have fun! If you are confused or at a loss, always adminhelp, \
+ and before taking extreme actions, please try to also contact the administration! \
+ Think through your actions and make the roleplay immersive! Please remember all \
+ rules aside from those with explicit exceptions apply to antagonists."
+ flags = ANTAG_SUSPICIOUS | ANTAG_IMPLANT_IMMUNE | ANTAG_RANDSPAWN | ANTAG_VOTABLE
+ can_speak_aooc = FALSE
diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm
index b5a73224fc7..23d8c7b60fa 100644
--- a/code/game/dna/dna2.dm
+++ b/code/game/dna/dna2.dm
@@ -111,6 +111,8 @@ var/global/list/datum/dna/gene/dna_genes[0]
// New stuff
var/species = SPECIES_HUMAN
var/list/body_markings = list()
+ var/list/body_descriptors = null
+ var/list/genetic_modifiers = list() // Modifiers with the MODIFIER_GENETIC flag are saved. Note that only the type is saved, not an instance.
// Make a copy of this strand.
// USE THIS WHEN COPYING STUFF OR YOU'LL GET CORRUPTION!
diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm
index 627b4e8b140..373aefa0d81 100644
--- a/code/game/gamemodes/changeling/changeling_powers.dm
+++ b/code/game/gamemodes/changeling/changeling_powers.dm
@@ -129,19 +129,19 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
return
if(src.stat > max_stat)
- src << "We are incapacitated."
+ to_chat(src, "We are incapacitated.")
return
if(changeling.absorbed_dna.len < required_dna)
- src << "We require at least [required_dna] samples of compatible DNA."
+ to_chat(src, "We require at least [required_dna] samples of compatible DNA.")
return
if(changeling.chem_charges < required_chems)
- src << "We require at least [required_chems] units of chemicals to do that!"
+ to_chat(src, "We require at least [required_chems] units of chemicals to do that!")
return
if(changeling.geneticdamage > max_genetic_damage)
- src << "Our genomes are still reassembling. We need time to recover first."
+ to_chat(src, "Our genomes are still reassembling. We need time to recover first.")
return
return changeling
@@ -204,11 +204,11 @@ turf/proc/AdjacentTurfsRangedSting()
if(M.loc == src.loc)
return 1 //target and source are in the same thing
if(!isturf(src.loc) || !isturf(M.loc))
- src << "We cannot reach \the [M] with a sting!"
+ to_chat(src, "We cannot reach \the [M] with a sting!")
return 0 //One is inside, the other is outside something.
// Maximum queued turfs set to 25; I don't *think* anything raises sting_range above 2, but if it does the 25 may need raising
if(!AStar(src.loc, M.loc, /turf/proc/AdjacentTurfsRangedSting, /turf/proc/Distance, max_nodes=25, max_node_depth=sting_range)) //If we can't find a path, fail
- src << "We cannot find a path to sting \the [M] by!"
+ to_chat(src, "We cannot find a path to sting \the [M] by!")
return 0
return 1
@@ -225,7 +225,7 @@ turf/proc/AdjacentTurfsRangedSting()
if(!T)
return
if(T.isSynthetic())
- src << "We are unable to pierce the outer shell of [T]."
+ to_chat(src, "We are unable to pierce the outer shell of [T].")
return
if(!(T in view(changeling.sting_range))) return
if(!sting_can_reach(T, changeling.sting_range)) return
@@ -236,7 +236,7 @@ turf/proc/AdjacentTurfsRangedSting()
src.verbs -= verb_path
spawn(10) src.verbs += verb_path
- src << "We stealthily sting [T]."
+ to_chat(src, "We stealthily sting [T].")
if(!T.mind || !T.mind.changeling) return T //T will be affected by the sting
T << "You feel a tiny prick."
return
diff --git a/code/game/gamemodes/changeling/generic_equip_procs.dm b/code/game/gamemodes/changeling/generic_equip_procs.dm
index ef1ab650a19..f2d7b458319 100644
--- a/code/game/gamemodes/changeling/generic_equip_procs.dm
+++ b/code/game/gamemodes/changeling/generic_equip_procs.dm
@@ -32,7 +32,7 @@
return 1
if(M.head || M.wear_suit) //Make sure our slots aren't full
- src << "We require nothing to be on our head, and we cannot wear any external suits, or shoes."
+ to_chat(src, "We require nothing to be on our head, and we cannot wear any external suits, or shoes.")
return 0
var/obj/item/clothing/suit/A = new armor_type(src)
@@ -242,7 +242,7 @@
var/mob/living/carbon/human/M = src
if(M.hands_are_full()) //Make sure our hands aren't full.
- src << "Our hands are full. Drop something first."
+ to_chat(src, "Our hands are full. Drop something first.")
return 0
var/obj/item/weapon/W = new weapon_type(src)
diff --git a/code/game/gamemodes/changeling/powers/absorb.dm b/code/game/gamemodes/changeling/powers/absorb.dm
index 45b230b00c1..02285a0c7ee 100644
--- a/code/game/gamemodes/changeling/powers/absorb.dm
+++ b/code/game/gamemodes/changeling/powers/absorb.dm
@@ -16,41 +16,41 @@
var/obj/item/weapon/grab/G = src.get_active_hand()
if(!istype(G))
- src << "We must be grabbing a creature in our active hand to absorb them."
+ to_chat(src, "We must be grabbing a creature in our active hand to absorb them.")
return
var/mob/living/carbon/human/T = G.affecting
if(!istype(T) || T.isSynthetic())
- src << "\The [T] is not compatible with our biology."
+ to_chat(src, "\The [T] is not compatible with our biology.")
return
if(T.species.flags & NO_SCAN)
- src << "We do not know how to parse this creature's DNA!"
+ to_chat(src, "We do not know how to parse this creature's DNA!")
return
if(HUSK in T.mutations) //Lings can always absorb other lings, unless someone beat them to it first.
if(!T.mind.changeling || T.mind.changeling && T.mind.changeling.geneticpoints < 0)
- src << "This creature's DNA is ruined beyond useability!"
+ to_chat(src, "This creature's DNA is ruined beyond useability!")
return
if(G.state != GRAB_KILL)
- src << "We must have a tighter grip to absorb this creature."
+ to_chat(src, "We must have a tighter grip to absorb this creature.")
return
if(changeling.isabsorbing)
- src << "We are already absorbing!"
+ to_chat(src, "We are already absorbing!")
return
changeling.isabsorbing = 1
for(var/stage = 1, stage<=3, stage++)
switch(stage)
if(1)
- src << "This creature is compatible. We must hold still..."
+ to_chat(src, "This creature is compatible. We must hold still...")
if(2)
- src << "We extend a proboscis."
+ to_chat(src, "We extend a proboscis.")
src.visible_message("[src] extends a proboscis!")
if(3)
- src << "We stab [T] with the proboscis."
+ to_chat(src, "We stab [T] with the proboscis.")
src.visible_message("[src] stabs [T] with the proboscis!")
T << "You feel a sharp stabbing pain!"
add_attack_logs(src,T,"Absorbed (changeling)")
@@ -60,11 +60,11 @@
feedback_add_details("changeling_powers","A[stage]")
if(!do_mob(src, T, 150) || G.state != GRAB_KILL)
- src << "Our absorption of [T] has been interrupted!"
+ to_chat(src, "Our absorption of [T] has been interrupted!")
changeling.isabsorbing = 0
return
- src << "We have absorbed [T]!"
+ to_chat(src, "We have absorbed [T]!")
src.visible_message("[src] sucks the fluids from [T]!")
T << "You have been absorbed by the changeling!"
if(src.nutrition < 400)
@@ -76,7 +76,7 @@
if(changeling.readapts > changeling.max_readapts)
changeling.readapts = changeling.max_readapts
- src << "We can now re-adapt, reverting our evolution so that we may start anew, if needed."
+ to_chat(src, "We can now re-adapt, reverting our evolution so that we may start anew, if needed.")
var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.name, T.languages, T.identifying_gender, T.flavor_texts, T.modifiers)
absorbDNA(newDNA)
@@ -98,7 +98,7 @@
changeling.geneticpoints += 4
changeling.max_geneticpoints += 4
- src << "We absorbed another changeling, and we grow stronger. Our genomes increase."
+ to_chat(src, "We absorbed another changeling, and we grow stronger. Our genomes increase.")
T.mind.changeling.chem_charges = 0
T.mind.changeling.geneticpoints = -1
diff --git a/code/game/gamemodes/changeling/powers/armblade.dm b/code/game/gamemodes/changeling/powers/armblade.dm
index 947f06cee45..c05ad96e81e 100644
--- a/code/game/gamemodes/changeling/powers/armblade.dm
+++ b/code/game/gamemodes/changeling/powers/armblade.dm
@@ -14,7 +14,7 @@
if(src.mind.changeling.recursive_enhancement)
if(changeling_generic_weapon(/obj/item/weapon/melee/changeling/arm_blade/greater))
- src << "We prepare an extra sharp blade."
+ to_chat(src, "We prepare an extra sharp blade.")
return 1
else
@@ -39,7 +39,7 @@
if(src.mind.changeling.recursive_enhancement)
if(changeling_generic_weapon(/obj/item/weapon/melee/changeling/claw/greater, 1, 15))
- src << "We prepare an extra sharp claw."
+ to_chat(src, "We prepare an extra sharp claw.")
return 1
else
diff --git a/code/game/gamemodes/changeling/powers/bioelectrogenesis.dm b/code/game/gamemodes/changeling/powers/bioelectrogenesis.dm
index 3f3c1bd7adc..192f8b38741 100644
--- a/code/game/gamemodes/changeling/powers/bioelectrogenesis.dm
+++ b/code/game/gamemodes/changeling/powers/bioelectrogenesis.dm
@@ -25,7 +25,7 @@
if(held_item == null)
if(src.mind.changeling.recursive_enhancement)
if(changeling_generic_weapon(/obj/item/weapon/electric_hand/efficent,0))
- src << "We will shock others more efficently."
+ to_chat(src, "We will shock others more efficently.")
return 1
else
if(changeling_generic_weapon(/obj/item/weapon/electric_hand,0)) //Chemical cost is handled in the equip proc.
@@ -54,7 +54,7 @@
"Our hand channels raw electricity into [G.affecting].",
"You hear sparks!")
else
- src << "Our gloves block us from shocking \the [G.affecting]."
+ to_chat(src, "Our gloves block us from shocking \the [G.affecting].")
src.mind.changeling.chem_charges -= 10
return 1
@@ -92,7 +92,7 @@
sleep(1 SECOND)
success = 1
if(success == 0) //If we couldn't do anything with the ability, don't deduct the chemicals.
- src << "We are unable to affect \the [held_item]."
+ to_chat(src, "We are unable to affect \the [held_item].")
else
src.mind.changeling.chem_charges -= 10
return success
@@ -143,7 +143,7 @@
var/mob/living/carbon/C = target
if(user.mind.changeling.chem_charges < shock_cost)
- src << "We require more chemicals to electrocute [C]!"
+ to_chat(src, "We require more chemicals to electrocute [C]!")
return 0
C.electrocute_act(electrocute_amount * siemens,src,1.0,BP_TORSO)
@@ -156,7 +156,7 @@
"Our hand channels raw electricity into [C]",
"You hear sparks!")
else
- src << "Our gloves block us from shocking \the [C]."
+ to_chat(src, "Our gloves block us from shocking \the [C].")
//qdel(src) //Since we're no longer a one hit stun, we need to stick around.
user.mind.changeling.chem_charges -= shock_cost
return 1
@@ -165,7 +165,7 @@
var/mob/living/silicon/S = target
if(user.mind.changeling.chem_charges < 10)
- src << "We require more chemicals to electrocute [S]!"
+ to_chat(src, "We require more chemicals to electrocute [S]!")
return 0
S.electrocute_act(60,src,0.75) //If only they had surge protectors.
@@ -205,7 +205,7 @@
success = 1
break
if(success == 0)
- src << "We are unable to affect \the [target]."
+ to_chat(src, "We are unable to affect \the [target].")
else
qdel(src)
return 1
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/blind_sting.dm b/code/game/gamemodes/changeling/powers/blind_sting.dm
index 347881df9b2..e2fede649e2 100644
--- a/code/game/gamemodes/changeling/powers/blind_sting.dm
+++ b/code/game/gamemodes/changeling/powers/blind_sting.dm
@@ -21,7 +21,7 @@
var/duration = 300
if(src.mind.changeling.recursive_enhancement)
duration = duration + 150
- src << "They will be deprived of sight for longer."
+ to_chat(src, "They will be deprived of sight for longer.")
spawn(duration)
T.disabilities &= ~NEARSIGHTED
T.Blind(10)
diff --git a/code/game/gamemodes/changeling/powers/cryo_sting.dm b/code/game/gamemodes/changeling/powers/cryo_sting.dm
index bc68428d892..e1a2b10cff9 100644
--- a/code/game/gamemodes/changeling/powers/cryo_sting.dm
+++ b/code/game/gamemodes/changeling/powers/cryo_sting.dm
@@ -20,12 +20,12 @@
var/inject_amount = 10
if(src.mind.changeling.recursive_enhancement)
inject_amount = inject_amount * 1.5
- src << "We inject extra chemicals."
+ to_chat(src, "We inject extra chemicals.")
if(T.reagents)
T.reagents.add_reagent("cryotoxin", inject_amount)
feedback_add_details("changeling_powers","CS")
src.verbs -= /mob/proc/changeling_cryo_sting
spawn(3 MINUTES)
- src << "Our cryogenic string is ready to be used once more."
+ to_chat(src, "Our cryogenic string is ready to be used once more.")
src.verbs |= /mob/proc/changeling_cryo_sting
return 1
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/deaf_sting.dm b/code/game/gamemodes/changeling/powers/deaf_sting.dm
index a94ad1744aa..92e7a80a308 100644
--- a/code/game/gamemodes/changeling/powers/deaf_sting.dm
+++ b/code/game/gamemodes/changeling/powers/deaf_sting.dm
@@ -19,7 +19,7 @@
var/duration = 300
if(src.mind.changeling.recursive_enhancement)
duration = duration + 100
- src << "They will be unable to hear for a little longer."
+ to_chat(src, "They will be unable to hear for a little longer.")
T << "Your ears pop and begin ringing loudly!"
T.sdisabilities |= DEAF
spawn(duration) T.sdisabilities &= ~DEAF
diff --git a/code/game/gamemodes/changeling/powers/delayed_toxin_sting.dm b/code/game/gamemodes/changeling/powers/delayed_toxin_sting.dm
index 7853a9603e8..f50460a826b 100644
--- a/code/game/gamemodes/changeling/powers/delayed_toxin_sting.dm
+++ b/code/game/gamemodes/changeling/powers/delayed_toxin_sting.dm
@@ -32,7 +32,7 @@
var/type_to_give = /datum/modifier/delayed_toxin_sting
if(src.mind.changeling.recursive_enhancement)
type_to_give = /datum/modifier/delayed_toxin_sting/strong
- src << "Our toxin will be extra potent, when it strikes."
+ to_chat(src, "Our toxin will be extra potent, when it strikes.")
T.add_modifier(type_to_give, 2 MINUTES)
diff --git a/code/game/gamemodes/changeling/powers/enfeebling_string.dm b/code/game/gamemodes/changeling/powers/enfeebling_string.dm
index 16303f7c589..81930a7ebc7 100644
--- a/code/game/gamemodes/changeling/powers/enfeebling_string.dm
+++ b/code/game/gamemodes/changeling/powers/enfeebling_string.dm
@@ -40,7 +40,7 @@
var/type_to_give = /datum/modifier/enfeeble
if(src.mind.changeling.recursive_enhancement)
type_to_give = /datum/modifier/enfeeble/strong
- src << "We make them extremely weak."
+ to_chat(src, "We make them extremely weak.")
H.add_modifier(type_to_give, 2 MINUTES)
feedback_add_details("changeling_powers","ES")
return 1
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/extract_dna_sting.dm b/code/game/gamemodes/changeling/powers/extract_dna_sting.dm
index 0c5d91d83b6..35ce94daf0e 100644
--- a/code/game/gamemodes/changeling/powers/extract_dna_sting.dm
+++ b/code/game/gamemodes/changeling/powers/extract_dna_sting.dm
@@ -24,15 +24,15 @@
return
if(!istype(T) || T.isSynthetic())
- src << "\The [T] is not compatible with our biology."
+ to_chat(src, "\The [T] is not compatible with our biology.")
return 0
if(T.species.flags & NO_SCAN)
- src << "We do not know how to parse this creature's DNA!"
+ to_chat(src, "We do not know how to parse this creature's DNA!")
return 0
if(HUSK in T.mutations)
- src << "This creature's DNA is ruined beyond useability!"
+ to_chat(src, "This creature's DNA is ruined beyond useability!")
return 0
add_attack_logs(src,T,"DNA extraction sting (changeling)")
diff --git a/code/game/gamemodes/changeling/powers/fake_death.dm b/code/game/gamemodes/changeling/powers/fake_death.dm
index cae98164a0e..3581a8d06a2 100644
--- a/code/game/gamemodes/changeling/powers/fake_death.dm
+++ b/code/game/gamemodes/changeling/powers/fake_death.dm
@@ -19,7 +19,7 @@
var/mob/living/carbon/C = src
if(changeling.max_geneticpoints < 0) //Absorbed by another ling
- src << "We have no genomes, not even our own, and cannot regenerate."
+ to_chat(src, "We have no genomes, not even our own, and cannot regenerate.")
return 0
if(!C.stat && alert("Are we sure we wish to regenerate? We will appear to be dead while doing so.","Revival","Yes","No") == "No")
@@ -44,7 +44,7 @@
spawn(rand(2 MINUTES, 4 MINUTES))
//The ling will now be able to choose when to revive
src.verbs += /mob/proc/changeling_revive
- src << "We are ready to rise. Use the Revive verb when you are ready."
+ to_chat(src, "We are ready to rise. Use the Revive verb when you are ready.")
feedback_add_details("changeling_powers","FD")
return 1
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/fleshmend.dm b/code/game/gamemodes/changeling/powers/fleshmend.dm
index f7760e9ce6a..05eea72d951 100644
--- a/code/game/gamemodes/changeling/powers/fleshmend.dm
+++ b/code/game/gamemodes/changeling/powers/fleshmend.dm
@@ -1,6 +1,6 @@
/datum/power/changeling/fleshmend
name = "Fleshmend"
- desc = "Begins a slow rengeration of our form. Does not effect stuns or chemicals."
+ desc = "Begins a slow regeneration of our form. Does not effect stuns or chemicals."
helptext = "Can be used while unconscious."
enhancedtext = "Healing is twice as effective."
ability_icon_state = "ling_fleshmend"
@@ -22,10 +22,10 @@
var/heal_amount = 2
if(src.mind.changeling.recursive_enhancement)
heal_amount = heal_amount * 2
- src << "We will heal much faster."
+ to_chat(src, "We will heal much faster.")
spawn(0)
- src << "We begin to heal ourselves."
+ to_chat(src, "We begin to heal ourselves.")
for(var/i = 0, i<50,i++)
if(C)
C.adjustBruteLoss(-heal_amount)
@@ -35,7 +35,7 @@
src.verbs -= /mob/proc/changeling_fleshmend
spawn(50 SECONDS)
- src << "Our regeneration has slowed to normal levels."
+ to_chat(src, "Our regeneration has slowed to normal levels.")
src.verbs += /mob/proc/changeling_fleshmend
feedback_add_details("changeling_powers","FM")
return 1
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/hivemind.dm b/code/game/gamemodes/changeling/powers/hivemind.dm
index c8e5f116040..105de8f4f56 100644
--- a/code/game/gamemodes/changeling/powers/hivemind.dm
+++ b/code/game/gamemodes/changeling/powers/hivemind.dm
@@ -34,7 +34,7 @@ var/list/datum/dna/hivemind_bank = list()
names += DNA.name
if(names.len <= 0)
- src << "The airwaves already have all of our DNA."
+ to_chat(src, "The airwaves already have all of our DNA.")
return
var/S = input("Select a DNA to channel: ", "Channel DNA", null) as null|anything in names
@@ -46,7 +46,7 @@ var/list/datum/dna/hivemind_bank = list()
changeling.chem_charges -= 10
hivemind_bank += chosen_dna
- src << "We channel the DNA of [S] to the air."
+ to_chat(src, "We channel the DNA of [S] to the air.")
feedback_add_details("changeling_powers","HU")
return 1
@@ -64,7 +64,7 @@ var/list/datum/dna/hivemind_bank = list()
names[DNA.name] = DNA
if(names.len <= 0)
- src << "There's no new DNA to absorb from the air."
+ to_chat(src, "There's no new DNA to absorb from the air.")
return
var/S = input("Select a DNA absorb from the air: ", "Absorb DNA", null) as null|anything in names
@@ -75,6 +75,6 @@ var/list/datum/dna/hivemind_bank = list()
changeling.chem_charges -= 20
absorbDNA(chosen_dna)
- src << "We absorb the DNA of [S] from the air."
+ to_chat(src, "We absorb the DNA of [S] from the air.")
feedback_add_details("changeling_powers","HD")
return 1
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/lesser_form.dm b/code/game/gamemodes/changeling/powers/lesser_form.dm
index f2742490f66..6a5cf807300 100644
--- a/code/game/gamemodes/changeling/powers/lesser_form.dm
+++ b/code/game/gamemodes/changeling/powers/lesser_form.dm
@@ -13,13 +13,13 @@
if(!changeling) return
if(src.has_brain_worms())
- src << "We cannot perform this ability at the present time!"
+ to_chat(src, "We cannot perform this ability at the present time!")
return
var/mob/living/carbon/human/H = src
if(!istype(H) || !H.species.primitive_form)
- src << "We cannot perform this ability in this form!"
+ to_chat(src, "We cannot perform this ability in this form!")
return
changeling.chem_charges--
diff --git a/code/game/gamemodes/changeling/powers/mimic_voice.dm b/code/game/gamemodes/changeling/powers/mimic_voice.dm
index ae953176838..6b84c577ff6 100644
--- a/code/game/gamemodes/changeling/powers/mimic_voice.dm
+++ b/code/game/gamemodes/changeling/powers/mimic_voice.dm
@@ -19,7 +19,7 @@
if(changeling.mimicing)
changeling.mimicing = ""
- src << "We return our vocal glands to their original location."
+ to_chat(src, "We return our vocal glands to their original location.")
return
var/mimic_voice = sanitize(input(usr, "Enter a name to mimic.", "Mimic Voice", null), MAX_NAME_LEN)
@@ -28,8 +28,8 @@
changeling.mimicing = mimic_voice
- src << "We shape our glands to take the voice of [mimic_voice], this will stop us from regenerating chemicals while active."
- src << "Use this power again to return to our original voice and reproduce chemicals again."
+ to_chat(src, "We shape our glands to take the voice of [mimic_voice], this will stop us from regenerating chemicals while active.")
+ to_chat(src, "Use this power again to return to our original voice and reproduce chemicals again.")
feedback_add_details("changeling_powers","MV")
diff --git a/code/game/gamemodes/changeling/powers/panacea.dm b/code/game/gamemodes/changeling/powers/panacea.dm
index 660434d185a..30679b6ef5a 100644
--- a/code/game/gamemodes/changeling/powers/panacea.dm
+++ b/code/game/gamemodes/changeling/powers/panacea.dm
@@ -18,7 +18,7 @@
return 0
src.mind.changeling.chem_charges -= 20
- src << "We cleanse impurities from our form."
+ to_chat(src, "We cleanse impurities from our form.")
var/mob/living/carbon/human/C = src
@@ -32,7 +32,7 @@
var/heal_amount = 5
if(src.mind.changeling.recursive_enhancement)
heal_amount = heal_amount * 2
- src << "We will heal much faster."
+ to_chat(src, "We will heal much faster.")
for(var/i = 0, i<10,i++)
if(C)
diff --git a/code/game/gamemodes/changeling/powers/rapid_regen.dm b/code/game/gamemodes/changeling/powers/rapid_regen.dm
index 2eb628b8f6c..6d1e9ee300c 100644
--- a/code/game/gamemodes/changeling/powers/rapid_regen.dm
+++ b/code/game/gamemodes/changeling/powers/rapid_regen.dm
@@ -24,7 +24,7 @@
var/healing_amount = 40
if(src.mind.changeling.recursive_enhancement)
healing_amount = C.maxHealth
- src << "We completely heal ourselves."
+ to_chat(src, "We completely heal ourselves.")
spawn(0)
C.adjustBruteLoss(-healing_amount)
C.adjustFireLoss(-healing_amount)
diff --git a/code/game/gamemodes/changeling/powers/recursive_enhancement.dm b/code/game/gamemodes/changeling/powers/recursive_enhancement.dm
index 9362333c57c..77bab9bd998 100644
--- a/code/game/gamemodes/changeling/powers/recursive_enhancement.dm
+++ b/code/game/gamemodes/changeling/powers/recursive_enhancement.dm
@@ -15,10 +15,10 @@
if(!changeling)
return 0
if(src.mind.changeling.recursive_enhancement)
- src << "We will no longer empower our abilities."
+ to_chat(src, "We will no longer empower our abilities.")
src.mind.changeling.recursive_enhancement = 0
return 0
- src << "We empower ourselves. Our abilities will now be extra potent."
+ to_chat(src, "We empower ourselves. Our abilities will now be extra potent.")
src.mind.changeling.recursive_enhancement = 1
feedback_add_details("changeling_powers","RE")
return 1
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/respec.dm b/code/game/gamemodes/changeling/powers/respec.dm
index 66f13e720f1..a50a41269f7 100644
--- a/code/game/gamemodes/changeling/powers/respec.dm
+++ b/code/game/gamemodes/changeling/powers/respec.dm
@@ -7,7 +7,7 @@
if(!changeling)
return
if(src.mind.changeling.readapts <= 0)
- to_chat(src, "We must first absorb another compatable creature!")
+ to_chat(src, "We must first absorb another compatible creature!")
src.mind.changeling.readapts = 0
return
@@ -26,6 +26,6 @@
H.remove_modifiers_of_type(/datum/modifier/endoarmor) //Revert endoarmor too.
src.make_changeling() //And give back our freebies.
- src << "We have removed our evolutions from this form, and are now ready to readapt."
+ to_chat(src, "We have removed our evolutions from this form, and are now ready to readapt.")
ling_datum.purchased_powers_history.Add("Re-adapt (Reset to [ling_datum.max_geneticpoints])")
diff --git a/code/game/gamemodes/changeling/powers/revive.dm b/code/game/gamemodes/changeling/powers/revive.dm
index 7fe4ab232be..0648fa8ab65 100644
--- a/code/game/gamemodes/changeling/powers/revive.dm
+++ b/code/game/gamemodes/changeling/powers/revive.dm
@@ -9,7 +9,7 @@
return 0
if(changeling.max_geneticpoints < 0) //Absorbed by another ling
- src << "You have no genomes, not even your own, and cannot revive."
+ to_chat(src, "You have no genomes, not even your own, and cannot revive.")
return 0
if(src.stat == DEAD)
diff --git a/code/game/gamemodes/changeling/powers/self_respiration.dm b/code/game/gamemodes/changeling/powers/self_respiration.dm
index 6d6228eba88..51083616697 100644
--- a/code/game/gamemodes/changeling/powers/self_respiration.dm
+++ b/code/game/gamemodes/changeling/powers/self_respiration.dm
@@ -19,13 +19,13 @@
if(istype(src,/mob/living/carbon))
var/mob/living/carbon/C = src
if(C.suiciding)
- src << "You're committing suicide, this isn't going to work."
+ to_chat(src, "You're committing suicide, this isn't going to work.")
return 0
if(C.does_not_breathe == 0)
C.does_not_breathe = 1
- src << "We stop breathing, as we no longer need to."
+ to_chat(src, "We stop breathing, as we no longer need to.")
return 1
else
C.does_not_breathe = 0
- src << "We resume breathing, as we now need to again."
+ to_chat(src, "We resume breathing, as we now need to again.")
return 0
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/shriek.dm b/code/game/gamemodes/changeling/powers/shriek.dm
index 4989c27f877..a2b9013c5a3 100644
--- a/code/game/gamemodes/changeling/powers/shriek.dm
+++ b/code/game/gamemodes/changeling/powers/shriek.dm
@@ -95,13 +95,13 @@
if(!changeling) return 0
if(is_muzzled())
- src << "Mmmf mrrfff!"
+ to_chat(src, "Mmmf mrrfff!")
return 0
if(ishuman(src))
var/mob/living/carbon/human/H = src
if(H.silent)
- src << "You can't speak!"
+ to_chat(src, "You can't speak!")
return 0
if(world.time < (changeling.last_shriek + 10 SECONDS) )
@@ -125,7 +125,7 @@
range_med = range_med * 2
range_light = range_light * 2
range_long = range_long * 2
- src << "We are extra loud."
+ to_chat(src, "We are extra loud.")
src.mind.changeling.recursive_enhancement = 0
visible_message("[src] appears to shout.")
diff --git a/code/game/gamemodes/changeling/powers/silence_sting.dm b/code/game/gamemodes/changeling/powers/silence_sting.dm
index 334b0c139f8..16d24c878f1 100644
--- a/code/game/gamemodes/changeling/powers/silence_sting.dm
+++ b/code/game/gamemodes/changeling/powers/silence_sting.dm
@@ -19,7 +19,7 @@
var/duration = 30
if(src.mind.changeling.recursive_enhancement)
duration = duration + 10
- src << "They will be unable to cry out in fear for a little longer."
+ to_chat(src, "They will be unable to cry out in fear for a little longer.")
T.silent += duration
feedback_add_details("changeling_powers","SS")
return 1
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/transform_sting.dm b/code/game/gamemodes/changeling/powers/transform_sting.dm
index 678e195e22a..1f6bc7b93dc 100644
--- a/code/game/gamemodes/changeling/powers/transform_sting.dm
+++ b/code/game/gamemodes/changeling/powers/transform_sting.dm
@@ -34,7 +34,7 @@
if(!T)
return 0
if((HUSK in T.mutations) || (!ishuman(T) && !issmall(T)))
- src << "Our sting appears ineffective against its DNA."
+ to_chat(src, "Our sting appears ineffective against its DNA.")
return 0
add_attack_logs(src,T,"Transformation sting (changeling)")
T.visible_message("[T] transforms!")
diff --git a/code/game/gamemodes/cult/construct_spells.dm b/code/game/gamemodes/cult/construct_spells.dm
index 937284629b6..534e9aedb91 100644
--- a/code/game/gamemodes/cult/construct_spells.dm
+++ b/code/game/gamemodes/cult/construct_spells.dm
@@ -192,6 +192,7 @@ proc/findNullRod(var/atom/target)
icon_state = "m_shield_cult"
light_color = "#B40000"
light_range = 2
+ invisibility = 0
/obj/effect/forcefield/cult/cultify()
return
diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm
index 24c2ed5f527..5c77d6d29f4 100644
--- a/code/game/gamemodes/cult/cult_structures.dm
+++ b/code/game/gamemodes/cult/cult_structures.dm
@@ -26,6 +26,17 @@
light_color = "#3e0000"
var/obj/item/wepon = null
+ var/shatter_message = "The pylon shatters!"
+ var/impact_sound = 'sound/effects/Glasshit.ogg'
+ var/shatter_sound = 'sound/effects/Glassbr3.ogg'
+
+ var/activation_cooldown = 30 SECONDS
+ var/last_activation = 0
+
+/obj/structure/cult/pylon/Initialize()
+ ..()
+ START_PROCESSING(SSobj, src)
+
/obj/structure/cult/pylon/attack_hand(mob/M as mob)
attackpylon(M, 5)
@@ -44,47 +55,58 @@
/obj/structure/cult/pylon/proc/pylonhit(var/damage)
if(!isbroken)
if(prob(1+ damage * 5))
- visible_message("The pylon shatters!")
- playsound(get_turf(src), 'sound/effects/Glassbr3.ogg', 75, 1)
+ visible_message("[shatter_message]")
+ STOP_PROCESSING(SSobj, src)
+ playsound(get_turf(src),shatter_sound, 75, 1)
isbroken = 1
density = 0
- icon_state = "pylon-broken"
+ icon_state = "[initial(icon_state)]-broken"
set_light(0)
/obj/structure/cult/pylon/proc/attackpylon(mob/user as mob, var/damage)
if(!isbroken)
if(prob(1+ damage * 5))
user.visible_message(
- "[user] smashed the pylon!",
- "You hit the pylon, and its crystal breaks apart!",
- "You hear a tinkle of crystal shards"
+ "[user] smashed \the [src]!",
+ "You hit \the [src], and its crystal breaks apart!",
+ "You hear a tinkle of crystal shards."
)
+ STOP_PROCESSING(SSobj, src)
user.do_attack_animation(src)
- playsound(get_turf(src), 'sound/effects/Glassbr3.ogg', 75, 1)
+ playsound(get_turf(src),shatter_sound, 75, 1)
isbroken = 1
density = 0
- icon_state = "pylon-broken"
+ icon_state = "[initial(icon_state)]-broken"
set_light(0)
else
- user << "You hit the pylon!"
- playsound(get_turf(src), 'sound/effects/Glasshit.ogg', 75, 1)
+ user << "You hit \the [src]!"
+ playsound(get_turf(src),impact_sound, 75, 1)
else
if(prob(damage * 2))
- user << "You pulverize what was left of the pylon!"
+ user << "You pulverize what was left of \the [src]!"
qdel(src)
else
- user << "You hit the pylon!"
- playsound(get_turf(src), 'sound/effects/Glasshit.ogg', 75, 1)
-
+ user << "You hit \the [src]!"
+ playsound(get_turf(src),impact_sound, 75, 1)
/obj/structure/cult/pylon/proc/repair(mob/user as mob)
if(isbroken)
- user << "You repair the pylon."
+ START_PROCESSING(SSobj, src)
+ user << "You repair \the [src]."
isbroken = 0
density = 1
- icon_state = "pylon"
+ icon_state = initial(icon_state)
set_light(5)
+// Returns 1 if the pylon does something special.
+/obj/structure/cult/pylon/proc/pylon_unique()
+ last_activation = world.time
+ return 0
+
+/obj/structure/cult/pylon/process()
+ if(!isbroken && (last_activation < world.time + activation_cooldown) && pylon_unique())
+ flick("[initial(icon_state)]-surge",src)
+
/obj/structure/cult/tome
name = "Desk"
desc = "A desk covered in arcane manuscripts and tomes in unknown languages. Looking at the text makes your skin crawl."
@@ -116,6 +138,12 @@
return
/obj/effect/gateway/Crossed(AM as mob|obj)
+ //VOREStation Edit begin: SHADEKIN
+ var/mob/SK = AM
+ if(istype(SK))
+ if(SK.shadekin_phasing_check())
+ return
+ //VOREStation Edit end: SHADEKIN
spawn(0)
return
return
@@ -148,6 +176,12 @@
qdel(src)
/obj/effect/gateway/active/Crossed(var/atom/A)
+ //VOREStation Edit begin: SHADEKIN
+ var/mob/SK = A
+ if(istype(SK))
+ if(SK.shadekin_phasing_check())
+ return
+ //VOREStation Edit end: SHADEKIN
if(!istype(A, /mob/living))
return
diff --git a/code/game/gamemodes/cult/cultify/mob.dm b/code/game/gamemodes/cult/cultify/mob.dm
index d78956c40ab..0cadd06d6cf 100644
--- a/code/game/gamemodes/cult/cultify/mob.dm
+++ b/code/game/gamemodes/cult/cultify/mob.dm
@@ -12,7 +12,7 @@
icon_state = "ghost-narsie"
overlays = 0
invisibility = 0
- src << "Even as a non-corporal being, you can feel Nar-Sie's presence altering you. You are now visible to everyone."
+ to_chat(src, "Even as a non-corporal being, you can feel Nar-Sie's presence altering you. You are now visible to everyone.")
/mob/living/cultify()
if(iscultist(src) && client)
diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm
index 04d8e853633..108c470414a 100644
--- a/code/game/gamemodes/gameticker.dm
+++ b/code/game/gamemodes/gameticker.dm
@@ -425,7 +425,7 @@ var/global/datum/controller/gameticker/ticker
for (var/mob/living/silicon/robot/robo in mob_list)
- if(istype(robo,/mob/living/silicon/robot/drone))
+ if(istype(robo,/mob/living/silicon/robot/drone) && !istype(robo,/mob/living/silicon/robot/drone/swarm))
dronecount++
continue
diff --git a/code/game/gamemodes/technomancer/instability.dm b/code/game/gamemodes/technomancer/instability.dm
index 7904b5cb6c4..6dc3f2d52b1 100644
--- a/code/game/gamemodes/technomancer/instability.dm
+++ b/code/game/gamemodes/technomancer/instability.dm
@@ -122,13 +122,13 @@
electrocute_act(instability * 0.3, "unstable energies", 0.75)
if(1)
adjustFireLoss(instability * 0.15) //7.5 burn @ 50 instability
- src << "Your chassis alerts you to overheating from an unknown external force!"
+ to_chat(src, "Your chassis alerts you to overheating from an unknown external force!")
if(2)
adjustBruteLoss(instability * 0.15) //7.5 brute @ 50 instability
- src << "Your chassis makes the sound of metal groaning!"
+ to_chat(src, "Your chassis makes the sound of metal groaning!")
if(3)
safe_blink(src, range = 6)
- src << "You're teleported against your will!"
+ to_chat(src, "You're teleported against your will!")
if(4)
emp_act(3)
@@ -141,10 +141,10 @@
emp_act(2)
if(2)
adjustFireLoss(instability * 0.3) //30 burn @ 100 instability
- src << "Your chassis alerts you to extreme overheating from an unknown external force!"
+ to_chat(src, "Your chassis alerts you to extreme overheating from an unknown external force!")
if(3)
adjustBruteLoss(instability * 0.3) //30 brute @ 100 instability
- src << "Your chassis makes the sound of metal groaning and tearing!"
+ to_chat(src, "Your chassis makes the sound of metal groaning and tearing!")
if(101 to 200) //Lethal
rng = rand(0,4)
@@ -155,10 +155,10 @@
emp_act(1)
if(2)
adjustFireLoss(instability * 0.4) //40 burn @ 100 instability
- src << "Your chassis alerts you to extreme overheating from an unknown external force!"
+ to_chat(src, "Your chassis alerts you to extreme overheating from an unknown external force!")
if(3)
adjustBruteLoss(instability * 0.4) //40 brute @ 100 instability
- src << "Your chassis makes the sound of metal groaning and tearing!"
+ to_chat(src, "Your chassis makes the sound of metal groaning and tearing!")
/mob/living/carbon/human/instability_effects()
if(instability)
@@ -190,23 +190,23 @@
if(2)
if(can_feel_pain())
apply_effect(instability * 0.3, AGONY)
- src << "You feel a sharp pain!"
+ to_chat(src, "You feel a sharp pain!")
if(3)
apply_effect(instability * 0.3, EYE_BLUR)
- src << "Your eyes start to get cloudy!"
+ to_chat(src, "Your eyes start to get cloudy!")
if(4)
electrocute_act(instability * 0.3, "unstable energies")
if(5)
adjustFireLoss(instability * 0.15) //7.5 burn @ 50 instability
- src << "You feel your skin burn!"
+ to_chat(src, "You feel your skin burn!")
if(6)
adjustBruteLoss(instability * 0.15) //7.5 brute @ 50 instability
- src << "You feel a sharp pain as an unseen force harms your body!"
+ to_chat(src, "You feel a sharp pain as an unseen force harms your body!")
if(7)
adjustToxLoss(instability * 0.15) //7.5 tox @ 50 instability
if(8)
safe_blink(src, range = 6)
- src << "You're teleported against your will!"
+ to_chat(src, "You're teleported against your will!")
if(50 to 100) //Severe
rng = rand(0,8)
@@ -218,18 +218,18 @@
if(2)
if(can_feel_pain())
apply_effect(instability * 0.7, AGONY)
- src << "You feel an extremly angonizing pain from all over your body!"
+ to_chat(src, "You feel an extremly angonizing pain from all over your body!")
if(3)
apply_effect(instability * 0.5, EYE_BLUR)
- src << "Your eyes start to get cloudy!"
+ to_chat(src, "Your eyes start to get cloudy!")
if(4)
electrocute_act(instability * 0.5, "extremely unstable energies")
if(5)
fire_act()
- src << "You spontaneously combust!"
+ to_chat(src, "You spontaneously combust!")
if(6)
adjustCloneLoss(instability * 0.05) //5 cloneloss @ 100 instability
- src << "You feel your body slowly degenerate."
+ to_chat(src, "You feel your body slowly degenerate.")
if(7)
adjustToxLoss(instability * 0.25) //25 tox @ 100 instability
@@ -245,18 +245,18 @@
if(2)
if(can_feel_pain())
apply_effect(instability, AGONY)
- src << "You feel an extremly angonizing pain from all over your body!"
+ to_chat(src, "You feel an extremly angonizing pain from all over your body!")
if(3)
apply_effect(instability, EYE_BLUR)
- src << "Your eyes start to get cloudy!"
+ to_chat(src, "Your eyes start to get cloudy!")
if(4)
electrocute_act(instability, "extremely unstable energies")
if(5)
fire_act()
- src << "You spontaneously combust!"
+ to_chat(src, "You spontaneously combust!")
if(6)
adjustCloneLoss(instability * 0.10) //5 cloneloss @ 100 instability
- src << "You feel your body slowly degenerate."
+ to_chat(src, "You feel your body slowly degenerate.")
if(7)
adjustToxLoss(instability * 0.40) //40 tox @ 100 instability
diff --git a/code/game/gamemodes/technomancer/spell_objs.dm b/code/game/gamemodes/technomancer/spell_objs.dm
index 681d29da50b..adfeda58ab1 100644
--- a/code/game/gamemodes/technomancer/spell_objs.dm
+++ b/code/game/gamemodes/technomancer/spell_objs.dm
@@ -292,7 +292,7 @@
if(l_spell.aspect == ASPECT_CHROMATIC) //Check the other hand too.
l_spell.on_combine_cast(S, src)
else //Welp
- src << "You require a free hand to use this function."
+ to_chat(src, "You require a free hand to use this function.")
return 0
if(S.run_checks())
diff --git a/code/game/gamemodes/technomancer/spells/aura/fire_aura.dm b/code/game/gamemodes/technomancer/spells/aura/fire_aura.dm
index c205cb76be2..947cad7140e 100644
--- a/code/game/gamemodes/technomancer/spells/aura/fire_aura.dm
+++ b/code/game/gamemodes/technomancer/spells/aura/fire_aura.dm
@@ -23,7 +23,7 @@
var/list/nearby_things = range(round(calculate_spell_power(4)),owner)
var/temp_change = calculate_spell_power(25)
- var/datum/species/baseline = all_species["Human"]
+ var/datum/species/baseline = GLOB.all_species["Human"]
var/temp_cap = baseline.heat_level_3 * 1.5
var/fire_power = calculate_spell_power(2)
diff --git a/code/game/gamemodes/technomancer/spells/aura/frost_aura.dm b/code/game/gamemodes/technomancer/spells/aura/frost_aura.dm
index 240265cfa4b..c73e010232c 100644
--- a/code/game/gamemodes/technomancer/spells/aura/frost_aura.dm
+++ b/code/game/gamemodes/technomancer/spells/aura/frost_aura.dm
@@ -23,7 +23,7 @@
var/list/nearby_mobs = range(round(calculate_spell_power(4)),owner)
var/temp_change = calculate_spell_power(40)
- var/datum/species/baseline = all_species["Human"]
+ var/datum/species/baseline = GLOB.all_species["Human"]
var/temp_cap = baseline.cold_level_2 - 5
if(check_for_scepter())
diff --git a/code/game/jobs/job/captain.dm b/code/game/jobs/job/captain.dm
index f1e0a1b8b2a..f98ab11928c 100644
--- a/code/game/jobs/job/captain.dm
+++ b/code/game/jobs/job/captain.dm
@@ -11,7 +11,6 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1)
spawn_positions = 1
supervisors = "company officials and Corporate Regulations"
selection_color = "#1D1D4F"
- idtype = /obj/item/weapon/card/id/gold
req_admin_notify = 1
access = list() //See get_access()
minimal_access = list() //See get_access()
@@ -44,7 +43,6 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1)
spawn_positions = 1
supervisors = "the Colony Director"
selection_color = "#2F2F7F"
- idtype = /obj/item/weapon/card/id/silver/hop
req_admin_notify = 1
minimal_player_age = 10
economic_modifier = 10
@@ -79,7 +77,6 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1)
spawn_positions = 2
supervisors = "command staff"
selection_color = "#2F2F7F"
- idtype = /obj/item/weapon/card/id/silver/secretary
minimal_player_age = 5
economic_modifier = 7
diff --git a/code/game/jobs/job/civilian.dm b/code/game/jobs/job/civilian.dm
index d31a551726c..d5a099af8c7 100644
--- a/code/game/jobs/job/civilian.dm
+++ b/code/game/jobs/job/civilian.dm
@@ -9,7 +9,6 @@
spawn_positions = 2
supervisors = "the head of personnel"
selection_color = "#515151"
- idtype = /obj/item/weapon/card/id/civilian/bartender
access = list(access_hydroponics, access_bar, access_kitchen)
minimal_access = list(access_bar)
@@ -27,7 +26,6 @@
spawn_positions = 2
supervisors = "the head of personnel"
selection_color = "#515151"
- idtype = /obj/item/weapon/card/id/civilian/chef
access = list(access_hydroponics, access_bar, access_kitchen)
minimal_access = list(access_kitchen)
@@ -44,7 +42,6 @@
spawn_positions = 1
supervisors = "the head of personnel"
selection_color = "#515151"
- idtype = /obj/item/weapon/card/id/civilian/botanist
access = list(access_hydroponics, access_bar, access_kitchen)
minimal_access = list(access_hydroponics)
@@ -63,7 +60,6 @@
spawn_positions = 1
supervisors = "the head of personnel"
selection_color = "#7a4f33"
- idtype = /obj/item/weapon/card/id/cargo/head
economic_modifier = 5
access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station)
minimal_access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station)
@@ -83,7 +79,6 @@
spawn_positions = 2
supervisors = "the quartermaster and the head of personnel"
selection_color = "#9b633e"
- idtype = /obj/item/weapon/card/id/cargo/cargo_tech
access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_mining, access_mining_station)
minimal_access = list(access_maint_tunnels, access_cargo, access_cargo_bot, access_mailsorting)
@@ -99,7 +94,6 @@
spawn_positions = 3
supervisors = "the quartermaster and the head of personnel"
selection_color = "#9b633e"
- idtype = /obj/item/weapon/card/id/cargo/mining
economic_modifier = 5
access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_mining, access_mining_station)
minimal_access = list(access_mining, access_mining_station, access_mailsorting)
@@ -118,7 +112,6 @@
spawn_positions = 2
supervisors = "the head of personnel"
selection_color = "#515151"
- idtype = /obj/item/weapon/card/id/civilian/janitor
access = list(access_janitor, access_maint_tunnels)
minimal_access = list(access_janitor, access_maint_tunnels)
@@ -136,7 +129,6 @@
spawn_positions = 1
supervisors = "the head of personnel"
selection_color = "#515151"
- idtype = /obj/item/weapon/card/id/civilian/librarian
access = list(access_library, access_maint_tunnels)
minimal_access = list(access_library)
@@ -154,7 +146,6 @@
spawn_positions = 2
supervisors = "company officials and Corporate Regulations"
selection_color = "#515151"
- idtype = /obj/item/weapon/card/id/civilian/internal_affairs_agent
economic_modifier = 7
access = list(access_lawyer, access_sec_doors, access_maint_tunnels, access_heads)
minimal_access = list(access_lawyer, access_sec_doors, access_heads)
diff --git a/code/game/jobs/job/civilian_chaplain.dm b/code/game/jobs/job/civilian_chaplain.dm
index 65943380bcc..12c2c9419dd 100644
--- a/code/game/jobs/job/civilian_chaplain.dm
+++ b/code/game/jobs/job/civilian_chaplain.dm
@@ -9,7 +9,6 @@
spawn_positions = 1
supervisors = "the head of personnel"
selection_color = "#515151"
- idtype = /obj/item/weapon/card/id/civilian/chaplain
access = list(access_morgue, access_chapel_office, access_crematorium, access_maint_tunnels)
minimal_access = list(access_chapel_office, access_crematorium)
alt_titles = list("Counselor")
diff --git a/code/game/jobs/job/engineering.dm b/code/game/jobs/job/engineering.dm
index bbc1903fd47..cfa79ffc250 100644
--- a/code/game/jobs/job/engineering.dm
+++ b/code/game/jobs/job/engineering.dm
@@ -9,7 +9,6 @@
spawn_positions = 1
supervisors = "the Colony Director"
selection_color = "#7F6E2C"
- idtype = /obj/item/weapon/card/id/engineering/head
req_admin_notify = 1
economic_modifier = 10
@@ -39,7 +38,6 @@
spawn_positions = 5
supervisors = "the chief engineer"
selection_color = "#5B4D20"
- idtype = /obj/item/weapon/card/id/engineering/engineer
economic_modifier = 5
access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction, access_atmospherics)
minimal_access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction)
@@ -59,7 +57,6 @@
spawn_positions = 2
supervisors = "the chief engineer"
selection_color = "#5B4D20"
- idtype = /obj/item/weapon/card/id/engineering/atmos
economic_modifier = 5
access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction, access_atmospherics, access_external_airlocks)
minimal_access = list(access_eva, access_engine, access_atmospherics, access_maint_tunnels, access_emergency_storage, access_construction, access_external_airlocks)
diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm
index f154b020945..d138a0e1c9e 100644
--- a/code/game/jobs/job/job.dm
+++ b/code/game/jobs/job/job.dm
@@ -13,7 +13,6 @@
var/current_positions = 0 // How many players have this job
var/supervisors = null // Supervisors, who this person answers to directly
var/selection_color = "#ffffff" // Selection screen color
- var/idtype = /obj/item/weapon/card/id // The type of the ID the player will have
var/list/alt_titles // List of alternate titles, if any
var/req_admin_notify // If this is set to 1, a text is printed to the player when jobs are assigned, telling him that he should let admins know that he has to disconnect.
var/minimal_player_age = 0 // If you have use_age_restriction_for_jobs config option enabled and the database set up, this option will add a requirement for players to be at least minimal_player_age days old. (meaning they first signed in at least that many days before.)
@@ -21,6 +20,7 @@
var/head_position = 0 // Is this position Command?
var/minimum_character_age = 0
var/ideal_character_age = 30
+ var/has_headset = TRUE //Do people with this job need to be given headsets and told how to use them? E.g. Cyborgs don't.
var/account_allowed = 1 // Does this job type come with a station account?
var/economic_modifier = 2 // With how much does this job modify the initial account amount?
@@ -40,13 +40,6 @@
. = . || outfit_type
. = outfit_by_type(.)
-/datum/job/proc/equip_backpack(var/mob/living/carbon/human/H)
- switch(H.backbag)
- if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(H), slot_back)
- if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/norm(H), slot_back)
- if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back)
- if(5) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/messenger(H), slot_back)
-
/datum/job/proc/setup_account(var/mob/living/carbon/human/H)
if(!account_allowed || (H.mind && H.mind.initial_account))
return
diff --git a/code/game/jobs/job/medical.dm b/code/game/jobs/job/medical.dm
index a8e5d6a3fcb..c8554113031 100644
--- a/code/game/jobs/job/medical.dm
+++ b/code/game/jobs/job/medical.dm
@@ -9,7 +9,6 @@
spawn_positions = 1
supervisors = "the Colony Director"
selection_color = "#026865"
- idtype = /obj/item/weapon/card/id/medical/head
req_admin_notify = 1
economic_modifier = 10
access = list(access_medical, access_medical_equip, access_morgue, access_genetics, access_heads,
@@ -35,7 +34,6 @@
spawn_positions = 3
supervisors = "the chief medical officer"
selection_color = "#013D3B"
- idtype = /obj/item/weapon/card/id/medical/doctor
economic_modifier = 7
access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics, access_eva)
minimal_access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_virology, access_eva)
@@ -57,7 +55,6 @@
spawn_positions = 2
supervisors = "the chief medical officer"
selection_color = "#013D3B"
- idtype = /obj/item/weapon/card/id/medical/chemist
economic_modifier = 5
access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics)
minimal_access = list(access_medical, access_medical_equip, access_chemistry)
@@ -78,7 +75,6 @@
spawn_positions = 0
supervisors = "the chief medical officer and research director"
selection_color = "#013D3B"
- idtype = /obj/item/weapon/card/id/medical/geneticist
economic_modifier = 7
access = list(access_medical, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics, access_research)
minimal_access = list(access_medical, access_morgue, access_genetics, access_research)
@@ -97,7 +93,6 @@
economic_modifier = 5
supervisors = "the chief medical officer"
selection_color = "#013D3B"
- idtype = /obj/item/weapon/card/id/medical/psychiatrist
access = list(access_medical, access_medical_equip, access_morgue, access_psychiatrist)
minimal_access = list(access_medical, access_medical_equip, access_psychiatrist)
outfit_type = /decl/hierarchy/outfit/job/medical/psychiatrist
@@ -113,7 +108,6 @@
spawn_positions = 2
supervisors = "the chief medical officer"
selection_color = "#013D3B"
- idtype = /obj/item/weapon/card/id/medical/paramedic
economic_modifier = 4
access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_chemistry, access_virology, access_eva, access_maint_tunnels, access_external_airlocks, access_psychiatrist)
minimal_access = list(access_medical, access_medical_equip, access_morgue, access_eva, access_maint_tunnels, access_external_airlocks)
diff --git a/code/game/jobs/job/science.dm b/code/game/jobs/job/science.dm
index c65f3413b6b..10f8e855ed8 100644
--- a/code/game/jobs/job/science.dm
+++ b/code/game/jobs/job/science.dm
@@ -9,7 +9,6 @@
spawn_positions = 1
supervisors = "the Colony Director"
selection_color = "#AD6BAD"
- idtype = /obj/item/weapon/card/id/science/head
req_admin_notify = 1
economic_modifier = 15
access = list(access_rd, access_heads, access_tox, access_genetics, access_morgue,
@@ -39,7 +38,6 @@
spawn_positions = 3
supervisors = "the research director"
selection_color = "#633D63"
- idtype = /obj/item/weapon/card/id/science/scientist
economic_modifier = 7
access = list(access_robotics, access_tox, access_tox_storage, access_research, access_xenobiology, access_xenoarch)
minimal_access = list(access_tox, access_tox_storage, access_research, access_xenoarch)
@@ -59,7 +57,6 @@
spawn_positions = 2
supervisors = "the research director"
selection_color = "#633D63"
- idtype = /obj/item/weapon/card/id/science/xenobiologist
economic_modifier = 7
access = list(access_robotics, access_tox, access_tox_storage, access_research, access_xenobiology, access_hydroponics)
minimal_access = list(access_research, access_xenobiology, access_hydroponics, access_tox_storage)
@@ -79,7 +76,6 @@
spawn_positions = 2
supervisors = "research director"
selection_color = "#633D63"
- idtype = /obj/item/weapon/card/id/science/roboticist
economic_modifier = 5
access = list(access_robotics, access_tox, access_tox_storage, access_tech_storage, access_morgue, access_research) //As a job that handles so many corpses, it makes sense for them to have morgue access.
minimal_access = list(access_robotics, access_tech_storage, access_morgue, access_research) //As a job that handles so many corpses, it makes sense for them to have morgue access.
diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm
index 6b753f519c0..fccac1a4af3 100644
--- a/code/game/jobs/job/security.dm
+++ b/code/game/jobs/job/security.dm
@@ -9,7 +9,6 @@
spawn_positions = 1
supervisors = "the Colony Director"
selection_color = "#8E2929"
- idtype = /obj/item/weapon/card/id/security/head
req_admin_notify = 1
economic_modifier = 10
access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory,
@@ -36,7 +35,6 @@
spawn_positions = 1
supervisors = "the head of security"
selection_color = "#601C1C"
- idtype = /obj/item/weapon/card/id/security/warden
economic_modifier = 5
access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory, access_maint_tunnels, access_morgue, access_external_airlocks)
minimal_access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory, access_maint_tunnels, access_external_airlocks)
@@ -53,7 +51,6 @@
spawn_positions = 2
supervisors = "the head of security"
selection_color = "#601C1C"
- idtype = /obj/item/weapon/card/id/security/detective
access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_eva, access_external_airlocks)
minimal_access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_eva, access_external_airlocks)
economic_modifier = 5
@@ -71,7 +68,6 @@
spawn_positions = 4
supervisors = "the head of security"
selection_color = "#601C1C"
- idtype = /obj/item/weapon/card/id/security/officer
economic_modifier = 4
access = list(access_security, access_eva, access_sec_doors, access_brig, access_maint_tunnels, access_morgue, access_external_airlocks)
minimal_access = list(access_security, access_eva, access_sec_doors, access_brig, access_maint_tunnels, access_external_airlocks)
diff --git a/code/game/jobs/job/silicon.dm b/code/game/jobs/job/silicon.dm
index 1b063894baf..9aed52c023a 100644
--- a/code/game/jobs/job/silicon.dm
+++ b/code/game/jobs/job/silicon.dm
@@ -11,18 +11,11 @@
minimal_player_age = 7
account_allowed = 0
economic_modifier = 0
+ has_headset = FALSE
/datum/job/ai/equip(var/mob/living/carbon/human/H)
if(!H) return 0
return 1
-/*
-/datum/job/ai/equip_survival(var/mob/living/carbon/human/H)
- if(!H) return 0
- return 1
-*/
-/datum/job/ai/equip_backpack(var/mob/living/carbon/human/H)
- if(!H) return 0
- return 1
/datum/job/ai/is_position_available()
return (empty_playable_ai_cores.len != 0)
@@ -45,19 +38,11 @@
alt_titles = list("Robot", "Drone")
account_allowed = 0
economic_modifier = 0
+ has_headset = FALSE
/datum/job/cyborg/equip(var/mob/living/carbon/human/H)
if(!H) return 0
return 1
-/*
-/datum/job/cyborg/equip_survival(var/mob/living/carbon/human/H)
- if(!H) return 0
- return 1
-*/
-/datum/job/cyborg/equip_backpack(var/mob/living/carbon/human/H)
- if(!H) return 0
- return 1
- return 1
/datum/job/cyborg/equip_preview(mob/living/carbon/human/H)
H.equip_to_slot_or_del(new /obj/item/clothing/suit/cardborg(H), slot_wear_suit)
diff --git a/code/game/jobs/job/special_vr.dm b/code/game/jobs/job/special_vr.dm
index fbed7452404..8369ebba46d 100644
--- a/code/game/jobs/job/special_vr.dm
+++ b/code/game/jobs/job/special_vr.dm
@@ -7,35 +7,17 @@
spawn_positions = 1
supervisors = "company officials and Corporate Regulations"
selection_color = "#1D1D4F"
- idtype = /obj/item/weapon/card/id/centcom
access = list()
minimal_access = list()
minimal_player_age = 14
economic_modifier = 20
whitelist_only = 1
latejoin_only = 1
+ outfit_type = /decl/hierarchy/outfit/job/centcom_officer
minimum_character_age = 25
ideal_character_age = 40
- equip(var/mob/living/carbon/human/H)
- if(!H) return 0
- H.equip_to_slot_or_del(new /obj/item/device/radio/headset/centcom(H), slot_l_ear)
- switch(H.backbag)
- if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(H), slot_back)
- if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back)
- if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back)
- H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/centcom, slot_w_uniform)
- H.equip_to_slot_or_del(new /obj/item/device/pda/centcom(H), slot_belt)
- H.equip_to_slot_or_del(new /obj/item/clothing/shoes/laceup(H), slot_shoes)
- H.equip_to_slot_or_del(new /obj/item/clothing/gloves/white(H), slot_gloves)
- H.equip_to_slot_or_del(new /obj/item/clothing/head/beret/centcom/officer(H), slot_head)
- H.equip_to_slot_or_del(new /obj/item/clothing/glasses/omnihud/all(H), slot_l_store)
-
- H.implant_loyalty()
-
- return 1
-
get_access()
return get_all_accesses().Copy()
@@ -97,23 +79,7 @@
alt_titles = list("Comedian","Jester")
whitelist_only = 1
latejoin_only = 1
-
- equip(var/mob/living/carbon/human/H)
- if(!H) return 0
- H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/clown(H), slot_back)
- H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/clown(H), slot_w_uniform)
- H.equip_to_slot_or_del(new /obj/item/clothing/shoes/clown_shoes(H), slot_shoes)
- H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/clown_hat(H), slot_wear_mask)
- H.equip_to_slot_or_del(new /obj/item/device/pda/clown(H), slot_belt)
-
- if(H.backbag > 0)
- H.equip_to_slot_or_del(new /obj/item/weapon/stamp/clown(H.back), slot_in_backpack)
- H.equip_to_slot_or_del(new /obj/item/weapon/bikehorn(H.back), slot_in_backpack) //VOREStation Edit
- else
- H.equip_to_slot_or_del(new /obj/item/weapon/stamp/clown(H), slot_l_hand)
- H.equip_to_slot_or_del(new /obj/item/weapon/bikehorn(H.back), slot_l_hand) //VOREStation Edit
-
- return 1
+ outfit_type = /decl/hierarchy/outfit/job/clown
/datum/job/clown/get_access()
if(config.assistant_maint)
@@ -137,22 +103,7 @@
alt_titles = list("Performer","Interpretive Dancer")
whitelist_only = 1
latejoin_only = 1
-
- equip(var/mob/living/carbon/human/H)
- if(!H) return 0
- H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(H), slot_back)
- H.equip_to_slot_or_del(new /obj/item/clothing/under/mime(H), slot_w_uniform)
- H.equip_to_slot_or_del(new /obj/item/clothing/shoes/mime(H), slot_shoes)
- H.equip_to_slot_or_del(new /obj/item/clothing/head/soft/mime(H), slot_head)
- H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/mime(H), slot_wear_mask)
- H.equip_to_slot_or_del(new /obj/item/device/pda/mime(H), slot_belt)
-
- if(H.backbag > 0)
- H.equip_to_slot_or_del(new /obj/item/weapon/pen/crayon/mime(H.back), slot_in_backpack)
- else
- H.equip_to_slot_or_del(new /obj/item/weapon/pen/crayon/mime(H), slot_l_hand)
-
- return 1
+ outfit_type = /decl/hierarchy/outfit/job/mime
/datum/job/mime/get_access()
if(config.assistant_maint)
diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm
index d5322d5f0ef..b527be4aad5 100644
--- a/code/game/jobs/job_controller.dm
+++ b/code/game/jobs/job_controller.dm
@@ -380,7 +380,7 @@ var/global/datum/controller/occupations/job_master
else
permitted = 1
- if(G.whitelisted && !is_alien_whitelisted(H, all_species[G.whitelisted]))
+ if(G.whitelisted && !is_alien_whitelisted(H, GLOB.all_species[G.whitelisted]))
//if(G.whitelisted && (G.whitelisted != H.species.name || !is_alien_whitelisted(H, G.whitelisted)))
permitted = 0
@@ -389,9 +389,6 @@ var/global/datum/controller/occupations/job_master
H << "Your current species, job or whitelist status does not permit you to spawn with [thing]!"
continue
- if(G.exploitable)
- H.amend_exploitable(G.path)
-
if(G.slot == "implant")
var/obj/item/weapon/implant/I = G.spawn_item(H)
I.invisibility = 100
@@ -414,8 +411,6 @@ var/global/datum/controller/occupations/job_master
//Equip job items.
job.setup_account(H)
job.equip(H, H.mind ? H.mind.role_alt_title : "")
- job.equip_backpack(H)
-// job.equip_survival(H)
job.apply_fingerprints(H)
if(job.title != "Cyborg" && job.title != "AI")
H.equip_post_job()
@@ -502,9 +497,7 @@ var/global/datum/controller/occupations/job_master
if(job.supervisors)
H << "As the [alt_title ? alt_title : rank] you answer directly to [job.supervisors]. Special circumstances may change this."
-
- if(job.idtype)
- spawnId(H, rank, alt_title)
+ if(job.has_headset)
H.equip_to_slot_or_del(new /obj/item/device/radio/headset(H), slot_l_ear)
H << "To speak on your department's radio channel use :h. For the use of other channels, examine your headset."
@@ -546,48 +539,6 @@ var/global/datum/controller/occupations/job_master
BITSET(H.hud_updateflag, SPECIALROLE_HUD)
return H
-
- proc/spawnId(var/mob/living/carbon/human/H, rank, title)
- if(!H) return 0
- var/obj/item/weapon/card/id/C = H.get_equipped_item(slot_wear_id)
- if(istype(C)) return 0
-
- var/datum/job/job = null
- for(var/datum/job/J in occupations)
- if(J.title == rank)
- job = J
- break
-
- if(job)
- if(job.title == "Cyborg")
- return
- else
- C = new job.idtype(H)
- C.access = job.get_access()
- else
- C = new /obj/item/weapon/card/id(H)
- if(C)
- C.rank = rank
- C.assignment = title ? title : rank
- H.set_id_info(C)
-
- //put the player's account number onto the ID
- if(H.mind && H.mind.initial_account)
- C.associated_account_number = H.mind.initial_account.account_number
-
- H.equip_to_slot_or_del(C, slot_wear_id)
-
-// H.equip_to_slot_or_del(new /obj/item/device/pda(H), slot_belt)
- if(locate(/obj/item/device/pda,H))
- var/obj/item/device/pda/pda = locate(/obj/item/device/pda,H)
- pda.owner = H.real_name
- pda.ownjob = C.assignment
- pda.ownrank = C.rank
- pda.name = "PDA-[H.real_name] ([pda.ownjob])"
-
- return 1
-
-
proc/LoadJobs(jobsfile) //ran during round setup, reads info from jobs.txt -- Urist
if(!config.load_jobs_from_txt)
return 0
diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm
index 62f35df91e9..bc39c938406 100644
--- a/code/game/machinery/alarm.dm
+++ b/code/game/machinery/alarm.dm
@@ -767,18 +767,25 @@
return
if(istype(W, /obj/item/weapon/card/id) || istype(W, /obj/item/device/pda))// trying to unlock the interface with an ID card
- if(stat & (NOPOWER|BROKEN))
- user << "It does nothing"
- return
- else
- if(allowed(usr) && !wires.IsIndexCut(AALARM_WIRE_IDSCAN))
- locked = !locked
- user << "You [ locked ? "lock" : "unlock"] the Air Alarm interface."
- else
- user << "Access denied."
- return
+ togglelock()
return ..()
+/obj/machinery/alarm/verb/togglelock(mob/user as mob)
+ if(stat & (NOPOWER|BROKEN))
+ to_chat(user, "It does nothing.")
+ return
+ else
+ if(allowed(usr) && !wires.IsIndexCut(AALARM_WIRE_IDSCAN))
+ locked = !locked
+ to_chat(user, "You [locked ? "lock" : "unlock"] the Air Alarm interface.")
+ else
+ to_chat(user, "Access denied.")
+ return
+
+/obj/machinery/alarm/AltClick()
+ ..()
+ togglelock()
+
/obj/machinery/alarm/power_change()
..()
spawn(rand(0,15))
diff --git a/code/game/machinery/bioprinter.dm b/code/game/machinery/bioprinter.dm
index 19c790b06b7..60143fadd36 100644
--- a/code/game/machinery/bioprinter.dm
+++ b/code/game/machinery/bioprinter.dm
@@ -156,10 +156,10 @@
if(!choice || printing || (stat & (BROKEN|NOPOWER)))
return
- if(!can_print(choice))
+ if(!can_print(choice, possible_list[choice][2]))
return
- container.reagents.remove_reagent("biomass", products[choice][2])
+ container.reagents.remove_reagent("biomass", possible_list[choice][2])
use_power = 2
printing = 1
@@ -176,7 +176,7 @@
if(!choice || !src || (stat & (BROKEN|NOPOWER)))
return
- print_organ(choice)
+ print_organ(possible_list[choice][1])
return
@@ -210,10 +210,10 @@
return biomass_count
-/obj/machinery/organ_printer/proc/can_print(var/choice)
+/obj/machinery/organ_printer/proc/can_print(var/choice, var/masscount = 0)
var/biomass = get_biomass_volume()
- if(biomass < products[choice][2])
- visible_message("\The [src] displays a warning: 'Not enough biomass. [biomass] stored and [products[choice][2]] needed.'")
+ if(biomass < masscount)
+ visible_message("\The [src] displays a warning: 'Not enough biomass. [biomass] stored and [masscount] needed.'")
return 0
if(!loaded_dna || !loaded_dna["donor"])
@@ -223,7 +223,7 @@
return 1
/obj/machinery/organ_printer/proc/print_organ(var/choice)
- var/new_organ = products[choice][1]
+ var/new_organ = choice
var/obj/item/organ/O = new new_organ(get_turf(src))
O.status |= ORGAN_CUT_AWAY
var/mob/living/carbon/human/C = loaded_dna["donor"]
@@ -236,9 +236,9 @@
malfunctioned = TRUE
var/possible_species = list(SPECIES_HUMAN, SPECIES_VOX, SPECIES_SKRELL, SPECIES_ZADDAT, SPECIES_UNATHI, SPECIES_GOLEM, SPECIES_SHADOW)
var/new_species = pick(possible_species)
- if(!all_species[new_species])
+ if(!GLOB.all_species[new_species])
new_species = SPECIES_HUMAN
- O.species = all_species[new_species]
+ O.species = GLOB.all_species[new_species]
if(istype(O, /obj/item/organ/external) && !malfunctioned)
var/obj/item/organ/external/E = O
diff --git a/code/game/machinery/camera/tracking.dm b/code/game/machinery/camera/tracking.dm
index 4f6b7df94f1..a1c954df007 100644
--- a/code/game/machinery/camera/tracking.dm
+++ b/code/game/machinery/camera/tracking.dm
@@ -47,24 +47,24 @@
loc = sanitize(loc)
if(!loc)
- src << "Must supply a location name"
+ to_chat(src, "Must supply a location name")
return
if(stored_locations.len >= max_locations)
- src << "Cannot store additional locations. Remove one first"
+ to_chat(src, "Cannot store additional locations. Remove one first")
return
if(loc in stored_locations)
- src << "There is already a stored location by this name"
+ to_chat(src, "There is already a stored location by this name")
return
var/L = src.eyeobj.getLoc()
if (InvalidPlayerTurf(get_turf(L)))
- src << "Unable to store this location"
+ to_chat(src, "Unable to store this location")
return
stored_locations[loc] = L
- src << "Location '[loc]' stored"
+ to_chat(src, "Location '[loc]' stored")
/mob/living/silicon/ai/proc/sorted_stored_locations()
return sortList(stored_locations)
@@ -75,7 +75,7 @@
set desc = "Returns to the selected camera location"
if (!(loc in stored_locations))
- src << "Location [loc] not found"
+ to_chat(src, "Location [loc] not found")
return
var/L = stored_locations[loc]
@@ -87,11 +87,11 @@
set desc = "Deletes the selected camera location"
if (!(loc in stored_locations))
- src << "Location [loc] not found"
+ to_chat(src, "Location [loc] not found")
return
stored_locations.Remove(loc)
- src << "Location [loc] removed"
+ to_chat(src, "Location [loc] removed")
// Used to allow the AI is write in mob names/camera name from the CMD line.
/datum/trackable
@@ -134,7 +134,7 @@
set desc = "Select who you would like to track."
if(src.stat == 2)
- src << "You can't follow [target_name] with cameras because you are dead!"
+ to_chat(src, "You can't follow [target_name] with cameras because you are dead!")
return
if(!target_name)
src.cameraFollow = null
@@ -147,7 +147,7 @@
if(!cameraFollow)
return
- src << "Follow camera mode [forced ? "terminated" : "ended"]."
+ to_chat(src, "Follow camera mode [forced ? "terminated" : "ended"].")
cameraFollow.tracking_cancelled()
cameraFollow = null
@@ -266,14 +266,14 @@ mob/living/proc/tracking_initiated()
mob/living/silicon/robot/tracking_initiated()
tracking_entities++
if(tracking_entities == 1 && has_zeroth_law())
- src << "Internal camera is currently being accessed."
+ to_chat(src, "Internal camera is currently being accessed.")
mob/living/proc/tracking_cancelled()
mob/living/silicon/robot/tracking_initiated()
tracking_entities--
if(!tracking_entities && has_zeroth_law())
- src << "Internal camera is no longer being accessed."
+ to_chat(src, "Internal camera is no longer being accessed.")
#undef TRACKING_POSSIBLE
diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm
index 96e6f6b5f9e..5178d77d822 100644
--- a/code/game/machinery/computer/cloning.dm
+++ b/code/game/machinery/computer/cloning.dm
@@ -335,6 +335,8 @@
R.name = R.dna.real_name
R.types = DNA2_BUF_UI|DNA2_BUF_UE|DNA2_BUF_SE
R.languages = subject.languages
+ R.gender = subject.gender
+ R.body_descriptors = subject.descriptors
if(!brain_skip) //Brains don't have flavor text.
R.flavor = subject.flavor_texts.Copy()
else
diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm
index 7e25bb2df97..a15887cc589 100644
--- a/code/game/machinery/doors/brigdoors.dm
+++ b/code/game/machinery/doors/brigdoors.dm
@@ -314,7 +314,7 @@
//Stolen from status_display
/obj/machinery/door_timer/proc/texticon(var/tn, var/px = 0, var/py = 0)
var/image/I = image('icons/obj/status_display.dmi', "blank")
- var/len = lentext(tn)
+ var/len = length(tn)
for(var/d = 1 to len)
var/char = copytext(tn, len-d+1, len-d+2)
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index 5a4c58b74a9..f2d87edb0dc 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -586,7 +586,7 @@
var/electrified = 0
//Departments that the cycler can paint suits to look like.
- var/list/departments = list("Engineering","Mining","Medical","Security","Atmos","HAZMAT","Construction","Biohazard","Emergency Medical Response","Crowd Control")
+ var/list/departments = list("Engineering","Mining","Medical","Security","Atmos","HAZMAT","Construction","Biohazard","Emergency Medical Response","Crowd Control","Exploration","Pilot Blue","Pilot") //VORESTATION EDIT
//Species that the suits can be configured to fit.
var/list/species = list(SPECIES_HUMAN,SPECIES_SKRELL,SPECIES_UNATHI,SPECIES_TAJ, SPECIES_TESHARI, "Nevrean", "Akula", "Sergal", "Flatland Zorren", "Highlander Zorren", "Vulpkanin", "Promethean", "Xenomorph Hybrid", "Xenochimera","Vasilissan", "Rapala") //VORESTATION EDIT
@@ -931,9 +931,10 @@
/obj/machinery/suit_cycler/proc/finished_job()
var/turf/T = get_turf(src)
- T.visible_message("\icon[src]The [src] pings loudly.")
+ T.visible_message("\icon[src]The [src] beeps several times.")
icon_state = initial(icon_state)
active = 0
+ playsound(src, 'sound/machines/boobeebeep.ogg', 50)
updateUsrDialog()
/obj/machinery/suit_cycler/proc/repair_suit()
diff --git a/code/game/machinery/supply_display.dm b/code/game/machinery/supply_display.dm
index d1be70e754c..211918c5e6e 100644
--- a/code/game/machinery/supply_display.dm
+++ b/code/game/machinery/supply_display.dm
@@ -11,7 +11,7 @@
message2 = "Error"
else if(shuttle.has_arrive_time())
message2 = get_supply_shuttle_timer()
- if(lentext(message2) > CHARS_PER_LINE)
+ if(length(message2) > CHARS_PER_LINE)
message2 = "Error"
else if(shuttle.is_launching())
if(shuttle.at_station())
diff --git a/code/game/machinery/syndicatebeacon_vr.dm b/code/game/machinery/syndicatebeacon_vr.dm
new file mode 100644
index 00000000000..ef6b3da0bbf
--- /dev/null
+++ b/code/game/machinery/syndicatebeacon_vr.dm
@@ -0,0 +1,40 @@
+// Virgo modified syndie beacon, does not give objectives
+
+/obj/machinery/syndicate_beacon/virgo/attack_hand(var/mob/user as mob)
+ usr.set_machine(src)
+ var/dat = "Scanning [pick("retina pattern", "voice print", "fingerprints", "dna sequence")]...
Identity confirmed,
"
+ if(istype(user, /mob/living/carbon/human) || istype(user, /mob/living/silicon/ai))
+ if(is_special_character(user))
+ dat += "Operative record found. Greetings, Agent [user.name].
"
+ else if(charges < 1)
+ dat += "Connection severed.
"
+ else
+ var/honorific = "Mr."
+ if(user.gender == FEMALE)
+ honorific = "Ms."
+ dat += "Identity not found in operative database. What can the Black Market do for you today, [honorific] [user.name]?
"
+ if(!selfdestructing)
+ dat += "
\"[pick("Send me some supplies!", "Transfer supplies.")]\"
"
+ dat += temptext
+ user << browse(dat, "window=syndbeacon")
+ onclose(user, "syndbeacon")
+
+/obj/machinery/syndicate_beacon/virgo/Topic(href, href_list)
+ if(href_list["betraitor"])
+ if(charges < 1)
+ updateUsrDialog()
+ return
+ var/mob/M = locate(href_list["traitormob"])
+ if(M.mind.special_role || jobban_isbanned(M, "Syndicate"))
+ temptext = "We have no need for you at this time. Have a pleasant day.
"
+ updateUsrDialog()
+ return
+ charges -= 1
+ if(istype(M, /mob/living/carbon/human))
+ var/mob/living/carbon/human/N = M
+ to_chat(N, "Access granted, here are the supplies!")
+ traitors.equip(N)
+ message_admins("[N]/([N.ckey]) has recieved an uplink and telecrystals from the syndicate beacon.")
+
+ updateUsrDialog()
+ return
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index 663230b11ff..e58568e35c7 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -752,7 +752,7 @@
vend_power_usage = 85000 //85 kJ to heat a 250 mL cup of coffee
products = list(/obj/item/weapon/reagent_containers/food/drinks/coffee = 25,/obj/item/weapon/reagent_containers/food/drinks/tea = 25,/obj/item/weapon/reagent_containers/food/drinks/h_chocolate = 25)
contraband = list(/obj/item/weapon/reagent_containers/food/drinks/ice = 10)
- prices = list(/obj/item/weapon/reagent_containers/food/drinks/coffee = 3, /obj/item/weapon/reagent_containers/food/drinks/tea = 3, /obj/item/weapon/reagent_containers/food/drinks/h_chocolate = 3)
+ prices = list(/obj/item/weapon/reagent_containers/food/drinks/coffee = 2, /obj/item/weapon/reagent_containers/food/drinks/tea = 2, /obj/item/weapon/reagent_containers/food/drinks/h_chocolate = 2) //VOREStation Edit
/obj/machinery/vending/snack
name = "Getmore Chocolate Corp"
@@ -764,14 +764,17 @@
/obj/item/weapon/reagent_containers/food/snacks/sosjerky = 6,/obj/item/weapon/reagent_containers/food/snacks/no_raisin = 6,/obj/item/weapon/reagent_containers/food/snacks/spacetwinkie = 6,
/obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers = 6, /obj/item/weapon/reagent_containers/food/snacks/tastybread = 6, /obj/item/weapon/reagent_containers/food/snacks/skrellsnacks = 3)
contraband = list(/obj/item/weapon/reagent_containers/food/snacks/syndicake = 6,/obj/item/weapon/reagent_containers/food/snacks/unajerky = 6,)
- prices = list(/obj/item/weapon/reagent_containers/food/snacks/candy = 1,/obj/item/weapon/reagent_containers/food/drinks/dry_ramen = 5,/obj/item/weapon/reagent_containers/food/snacks/chips = 1,
+ //VOREStation Edit Start
+ prices = list(/obj/item/weapon/reagent_containers/food/snacks/candy = 1,/obj/item/weapon/reagent_containers/food/drinks/dry_ramen = 2,/obj/item/weapon/reagent_containers/food/snacks/chips = 1,
/obj/item/weapon/reagent_containers/food/snacks/sosjerky = 2,/obj/item/weapon/reagent_containers/food/snacks/no_raisin = 1,/obj/item/weapon/reagent_containers/food/snacks/spacetwinkie = 1,
- /obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers = 1, /obj/item/weapon/reagent_containers/food/snacks/tastybread = 2, /obj/item/weapon/reagent_containers/food/snacks/skrellsnacks = 4)
-
+ /obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers = 1, /obj/item/weapon/reagent_containers/food/snacks/tastybread = 2, /obj/item/weapon/reagent_containers/food/snacks/skrellsnacks = 2)
+ //VOREStation Edit End
+
/obj/machinery/vending/cola
name = "Robust Softdrinks"
desc = "A softdrink vendor provided by Robust Industries, LLC."
icon_state = "Cola_Machine" //VOREStation Edit
+ icon_vend = "Cola_Machine-purchase" //VOREStation Edit
product_slogans = "Robust Softdrinks: More robust than a toolbox to the head!"
product_ads = "Refreshing!;Hope you're thirsty!;Over 1 million drinks sold!;Thirsty? Why not cola?;Please, have a drink!;Drink up!;The best drinks in space."
products = list(/obj/item/weapon/reagent_containers/food/drinks/cans/cola = 10,/obj/item/weapon/reagent_containers/food/drinks/cans/space_mountain_wind = 10,
@@ -793,7 +796,7 @@
icon_state = "fitness"
products = list(/obj/item/weapon/reagent_containers/food/drinks/smallmilk = 8,
/obj/item/weapon/reagent_containers/food/drinks/smallchocmilk = 8,
- /obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask/proteinshake = 8,
+ /obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask/proteinshake = 16, //VOREStation Edit,
/obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask = 8,
/obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar = 8,
/obj/item/weapon/reagent_containers/food/snacks/liquidfood = 8,
@@ -801,15 +804,17 @@
///obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/glucose = 5, //VOREStation Removal,
/obj/item/weapon/towel/random = 8)
+ //VOREStation Edit Start
prices = list(/obj/item/weapon/reagent_containers/food/drinks/smallmilk = 3,
/obj/item/weapon/reagent_containers/food/drinks/smallchocmilk = 3,
- /obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask/proteinshake = 40, //VOREStation Edit,
- /obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask = 5,
+ /obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask/proteinshake = 15,
+ /obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask = 1,
/obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar = 5,
/obj/item/weapon/reagent_containers/food/snacks/liquidfood = 5,
/obj/item/weapon/reagent_containers/pill/diet = 25,
- ///obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/glucose = 5, //VOREStation Removal,
- /obj/item/weapon/towel/random = 40)
+ ///obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/glucose = 5,
+ /obj/item/weapon/towel/random = 20)
+ //VOREStation Edit End
contraband = list(/obj/item/weapon/reagent_containers/syringe/steroid = 4)
diff --git a/code/game/magic/archived_book.dm b/code/game/magic/archived_book.dm
index 2fc9412fcd9..b2af5f3f73c 100644
--- a/code/game/magic/archived_book.dm
+++ b/code/game/magic/archived_book.dm
@@ -37,7 +37,7 @@ datum/book_manager/proc/freeid()
set desc = "Permamently deletes a book from the database."
set category = "Admin"
if(!src.holder)
- src << "Only administrators may use this command."
+ to_chat(src, "Only administrators may use this command.")
return
var/isbn = input("ISBN number?", "Delete Book") as num | null
diff --git a/code/game/mecha/combat/gorilla.dm b/code/game/mecha/combat/gorilla.dm
index f94c8bc78ee..a33cd963e2e 100644
--- a/code/game/mecha/combat/gorilla.dm
+++ b/code/game/mecha/combat/gorilla.dm
@@ -87,7 +87,7 @@
max_universal_equip = 5
max_special_equip = 2
-/obj/mecha/combat/gorilla/New()
+/obj/mecha/combat/gorilla/Initialize()
..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay(src) // This thing basically cannot function without an external power supply.
ME.attach(src)
diff --git a/code/game/mecha/combat/gygax.dm b/code/game/mecha/combat/gygax.dm
index 19564acba9e..d70c8f9e855 100644
--- a/code/game/mecha/combat/gygax.dm
+++ b/code/game/mecha/combat/gygax.dm
@@ -45,7 +45,7 @@
max_universal_equip = 1
max_special_equip = 2
-/obj/mecha/combat/gygax/dark/New()
+/obj/mecha/combat/gygax/dark/Initialize()
..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot
ME.attach(src)
diff --git a/code/game/mecha/combat/marauder.dm b/code/game/mecha/combat/marauder.dm
index b8aed16ceff..9521147089b 100644
--- a/code/game/mecha/combat/marauder.dm
+++ b/code/game/mecha/combat/marauder.dm
@@ -55,7 +55,7 @@
wreckage = /obj/effect/decal/mecha_wreckage/mauler
mech_faction = MECH_FACTION_SYNDI
-/obj/mecha/combat/marauder/New()
+/obj/mecha/combat/marauder/Initialize()
..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse
ME.attach(src)
@@ -69,7 +69,7 @@
src.smoke_system.attach(src)
return
-/obj/mecha/combat/marauder/seraph/New()
+/obj/mecha/combat/marauder/seraph/Initialize()
..()//Let it equip whatever is needed.
var/obj/item/mecha_parts/mecha_equipment/ME
if(equipment.len)//Now to remove it and equip anew.
diff --git a/code/game/mecha/combat/phazon.dm b/code/game/mecha/combat/phazon.dm
index 3ada4824f74..8f72de5f517 100644
--- a/code/game/mecha/combat/phazon.dm
+++ b/code/game/mecha/combat/phazon.dm
@@ -27,7 +27,7 @@
max_universal_equip = 3
max_special_equip = 4
-/obj/mecha/combat/phazon/equipped/New()
+/obj/mecha/combat/phazon/equipped/Initialize()
..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/tool/rcd
ME.attach(src)
diff --git a/code/game/mecha/equipment/tools/armor_melee.dm b/code/game/mecha/equipment/tools/armor_melee.dm
new file mode 100644
index 00000000000..83c82281311
--- /dev/null
+++ b/code/game/mecha/equipment/tools/armor_melee.dm
@@ -0,0 +1,49 @@
+/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster //what is that noise? A BAWWW from TK mutants.
+ name = "\improper CCW armor booster"
+ desc = "Close-combat armor booster. Boosts exosuit armor against armed melee attacks. Requires energy to operate."
+ icon_state = "mecha_abooster_ccw"
+ origin_tech = list(TECH_MATERIAL = 3)
+ equip_cooldown = 10
+ energy_drain = 50
+ range = 0
+ var/deflect_coeff = 1.15
+ var/damage_coeff = 0.8
+
+ equip_type = EQUIP_HULL
+
+/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/can_attach(obj/mecha/M as obj)
+ if(..())
+ if(!M.proc_res["dynattackby"])
+ return 1
+ return 0
+
+/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/attach(obj/mecha/M as obj)
+ ..()
+ chassis.proc_res["dynattackby"] = src
+ return
+
+/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/detach()
+ chassis.proc_res["dynattackby"] = null
+ ..()
+ return
+
+/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/get_equip_info()
+ if(!chassis) return
+ return "* [src.name]"
+
+/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/proc/dynattackby(obj/item/weapon/W as obj, mob/user as mob)
+ if(!action_checks(user))
+ return chassis.dynattackby(W,user)
+ chassis.log_message("Attacked by [W]. Attacker - [user]")
+ if(prob(chassis.deflect_chance*deflect_coeff))
+ user << "\The [W] bounces off [chassis] armor."
+ chassis.log_append_to_last("Armor saved.")
+ else
+ chassis.occupant_message("\The [user] hits [chassis] with [W].")
+ user.visible_message("\The [user] hits [chassis] with [W].", "You hit [src] with [W].")
+ chassis.take_damage(round(W.force*damage_coeff),W.damtype)
+ chassis.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
+ set_ready_state(0)
+ chassis.use_power(energy_drain)
+ do_after_cooldown()
+ return
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/armor_ranged.dm b/code/game/mecha/equipment/tools/armor_ranged.dm
new file mode 100644
index 00000000000..2e3523275fc
--- /dev/null
+++ b/code/game/mecha/equipment/tools/armor_ranged.dm
@@ -0,0 +1,72 @@
+/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster
+ name = "\improper RW armor booster"
+ desc = "Ranged-weaponry armor booster. Boosts exosuit armor against ranged attacks. Completely blocks taser shots, but requires energy to operate."
+ icon_state = "mecha_abooster_proj"
+ origin_tech = list(TECH_MATERIAL = 4)
+ equip_cooldown = 10
+ energy_drain = 50
+ range = 0
+ var/deflect_coeff = 1.15
+ var/damage_coeff = 0.8
+
+ equip_type = EQUIP_HULL
+
+/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/can_attach(obj/mecha/M as obj)
+ if(..())
+ if(!M.proc_res["dynbulletdamage"] && !M.proc_res["dynhitby"])
+ return 1
+ return 0
+
+/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/attach(obj/mecha/M as obj)
+ ..()
+ chassis.proc_res["dynbulletdamage"] = src
+ chassis.proc_res["dynhitby"] = src
+ return
+
+/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/detach()
+ chassis.proc_res["dynbulletdamage"] = null
+ chassis.proc_res["dynhitby"] = null
+ ..()
+ return
+
+/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/get_equip_info()
+ if(!chassis) return
+ return "* [src.name]"
+
+/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/proc/dynbulletdamage(var/obj/item/projectile/Proj)
+ if(istype(Proj, /obj/item/projectile/test))
+ return // Don't care about test projectiles, just what comes after them
+ if(!action_checks(src))
+ return chassis.dynbulletdamage(Proj)
+ if(prob(chassis.deflect_chance*deflect_coeff))
+ chassis.occupant_message("The armor deflects incoming projectile.")
+ chassis.visible_message("The [chassis.name] armor deflects the projectile")
+ chassis.log_append_to_last("Armor saved.")
+ else
+ chassis.take_damage(round(Proj.damage*src.damage_coeff),Proj.check_armour)
+ chassis.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
+ Proj.on_hit(chassis)
+ set_ready_state(0)
+ chassis.use_power(energy_drain)
+ do_after_cooldown()
+ return
+
+/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/proc/dynhitby(atom/movable/A)
+ if(!action_checks(A))
+ return chassis.dynhitby(A)
+ if(prob(chassis.deflect_chance*deflect_coeff) || istype(A, /mob/living) || istype(A, /obj/item/mecha_parts/mecha_tracking))
+ chassis.occupant_message("The [A] bounces off the armor.")
+ chassis.visible_message("The [A] bounces off the [chassis] armor")
+ chassis.log_append_to_last("Armor saved.")
+ if(istype(A, /mob/living))
+ var/mob/living/M = A
+ M.take_organ_damage(10)
+ else if(istype(A, /obj))
+ var/obj/O = A
+ if(O.throwforce)
+ chassis.take_damage(round(O.throwforce*damage_coeff))
+ chassis.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
+ set_ready_state(0)
+ chassis.use_power(energy_drain)
+ do_after_cooldown()
+ return
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/cable_layer.dm b/code/game/mecha/equipment/tools/cable_layer.dm
new file mode 100644
index 00000000000..5fbb7b70dbf
--- /dev/null
+++ b/code/game/mecha/equipment/tools/cable_layer.dm
@@ -0,0 +1,128 @@
+/obj/item/mecha_parts/mecha_equipment/tool/cable_layer
+ name = "Cable Layer"
+ icon_state = "mecha_wire"
+ var/turf/old_turf
+ var/obj/structure/cable/last_piece
+ var/obj/item/stack/cable_coil/cable
+ var/max_cable = 1000
+ required_type = list(/obj/mecha/working)
+
+/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/New()
+ cable = new(src)
+ cable.amount = 0
+ ..()
+
+/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/MoveAction()
+ layCable()
+
+/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/action(var/obj/item/stack/cable_coil/target)
+ if(!action_checks(target))
+ return
+ var/result = load_cable(target)
+ var/message
+ if(isnull(result))
+ message = "Unable to load [target] - no cable found."
+ else if(!result)
+ message = "Reel is full."
+ else
+ message = "[result] meters of cable successfully loaded."
+ send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
+ occupant_message(message)
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/Topic(href,href_list)
+ ..()
+ if(href_list["toggle"])
+ set_ready_state(!equip_ready)
+ occupant_message("[src] [equip_ready?"dea":"a"]ctivated.")
+ log_message("[equip_ready?"Dea":"A"]ctivated.")
+ return
+ if(href_list["cut"])
+ if(cable && cable.amount)
+ var/m = round(input(chassis.occupant,"Please specify the length of cable to cut","Cut cable",min(cable.amount,30)) as num, 1)
+ m = min(m, cable.amount)
+ if(m)
+ use_cable(m)
+ var/obj/item/stack/cable_coil/CC = new (get_turf(chassis))
+ CC.amount = m
+ else
+ occupant_message("There's no more cable on the reel.")
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/get_equip_info()
+ var/output = ..()
+ if(output)
+ return "[output] \[Cable: [cable ? cable.amount : 0] m\][(cable && cable.amount) ? "- [!equip_ready?"Dea":"A"]ctivate|Cut" : null]"
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/load_cable(var/obj/item/stack/cable_coil/CC)
+ if(istype(CC) && CC.amount)
+ var/cur_amount = cable? cable.amount : 0
+ var/to_load = max(max_cable - cur_amount,0)
+ if(to_load)
+ to_load = min(CC.amount, to_load)
+ if(!cable)
+ cable = new(src)
+ cable.amount = 0
+ cable.amount += to_load
+ CC.use(to_load)
+ return to_load
+ else
+ return 0
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/use_cable(amount)
+ if(!cable || cable.amount<1)
+ set_ready_state(1)
+ occupant_message("Cable depleted, [src] deactivated.")
+ log_message("Cable depleted, [src] deactivated.")
+ return
+ if(cable.amount < amount)
+ occupant_message("No enough cable to finish the task.")
+ return
+ cable.use(amount)
+ update_equip_info()
+ return 1
+
+/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/reset()
+ last_piece = null
+
+/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/dismantleFloor(var/turf/new_turf)
+ new_turf = get_turf(chassis)
+ if(istype(new_turf, /turf/simulated/floor))
+ var/turf/simulated/floor/T = new_turf
+ if(!T.is_plating())
+ T.make_plating(!(T.broken || T.burnt))
+ return new_turf.is_plating()
+
+/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/layCable(var/turf/new_turf)
+ new_turf = get_turf(chassis)
+ if(equip_ready || !istype(new_turf, /turf/simulated/floor) || !dismantleFloor(new_turf))
+ return reset()
+ var/fdirn = turn(chassis.dir,180)
+ for(var/obj/structure/cable/LC in new_turf) // check to make sure there's not a cable there already
+ if(LC.d1 == fdirn || LC.d2 == fdirn)
+ return reset()
+ if(!use_cable(1))
+ return reset()
+ var/obj/structure/cable/NC = new(new_turf)
+ NC.cableColor("red")
+ NC.d1 = 0
+ NC.d2 = fdirn
+ NC.update_icon()
+
+ var/datum/powernet/PN
+ if(last_piece && last_piece.d2 != chassis.dir)
+ last_piece.d1 = min(last_piece.d2, chassis.dir)
+ last_piece.d2 = max(last_piece.d2, chassis.dir)
+ last_piece.update_icon()
+ PN = last_piece.powernet
+
+ if(!PN)
+ PN = new()
+ PN.add_cable(NC)
+ NC.mergeConnectedNetworks(NC.d2)
+
+ //NC.mergeConnectedNetworksOnTurf()
+ last_piece = NC
+ return 1
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/catapult.dm b/code/game/mecha/equipment/tools/catapult.dm
new file mode 100644
index 00000000000..7d9162823d2
--- /dev/null
+++ b/code/game/mecha/equipment/tools/catapult.dm
@@ -0,0 +1,76 @@
+/obj/item/mecha_parts/mecha_equipment/gravcatapult
+ name = "gravitational catapult"
+ desc = "An exosuit mounted gravitational catapult."
+ icon_state = "mecha_teleport"
+ origin_tech = list(TECH_BLUESPACE = 2, TECH_MAGNET = 3)
+ equip_cooldown = 10
+ energy_drain = 100
+ range = MELEE|RANGED
+ var/atom/movable/locked
+ var/mode = 1 //1 - gravsling 2 - gravpush
+
+ var/last_fired = 0 //Concept stolen from guns.
+ var/fire_delay = 10 //Used to prevent spam-brute against humans.
+
+ equip_type = EQUIP_UTILITY
+
+/obj/item/mecha_parts/mecha_equipment/gravcatapult/action(atom/movable/target)
+
+ if(world.time >= last_fired + fire_delay)
+ last_fired = world.time
+ else
+ if (world.time % 3)
+ occupant_message("[src] is not ready to fire again!")
+ return 0
+
+ switch(mode)
+ if(1)
+ if(!action_checks(target) && !locked) return
+ if(!locked)
+ if(!istype(target) || target.anchored)
+ occupant_message("Unable to lock on [target]")
+ return
+ locked = target
+ occupant_message("Locked on [target]")
+ send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
+ return
+ else if(target!=locked)
+ if(locked in view(chassis))
+ locked.throw_at(target, 14, 1.5, chassis)
+ locked = null
+ send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
+ set_ready_state(0)
+ chassis.use_power(energy_drain)
+ do_after_cooldown()
+ else
+ locked = null
+ occupant_message("Lock on [locked] disengaged.")
+ send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
+ if(2)
+ if(!action_checks(target)) return
+ var/list/atoms = list()
+ if(isturf(target))
+ atoms = range(target,3)
+ else
+ atoms = orange(target,3)
+ for(var/atom/movable/A in atoms)
+ if(A.anchored) continue
+ spawn(0)
+ var/iter = 5-get_dist(A,target)
+ for(var/i=0 to iter)
+ step_away(A,target)
+ sleep(2)
+ set_ready_state(0)
+ chassis.use_power(energy_drain)
+ do_after_cooldown()
+ return
+
+/obj/item/mecha_parts/mecha_equipment/gravcatapult/get_equip_info()
+ return "[..()] [mode==1?"([locked||"Nothing"])":null] \[S|P\]"
+
+/obj/item/mecha_parts/mecha_equipment/gravcatapult/Topic(href, href_list)
+ ..()
+ if(href_list["mode"])
+ mode = text2num(href_list["mode"])
+ send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
+ return
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/clamp.dm b/code/game/mecha/equipment/tools/clamp.dm
new file mode 100644
index 00000000000..a587d895681
--- /dev/null
+++ b/code/game/mecha/equipment/tools/clamp.dm
@@ -0,0 +1,175 @@
+/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp
+ name = "hydraulic clamp"
+ icon_state = "mecha_clamp"
+ equip_cooldown = 15
+ energy_drain = 10
+ var/dam_force = 20
+ var/obj/mecha/working/ripley/cargo_holder
+ required_type = list(/obj/mecha/working)
+ ready_sound = 'sound/mecha/gasdisconnected.ogg'
+
+/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp/attach(obj/mecha/M as obj)
+ ..()
+ cargo_holder = M
+
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp/action(atom/target)
+ if(!action_checks(target)) return
+ if(!cargo_holder) return
+
+ //loading
+ if(istype(target,/obj))
+ var/obj/O = target
+ if(O.has_buckled_mobs())
+ return
+ if(locate(/mob/living) in O)
+ occupant_message("You can't load living things into the cargo compartment.")
+ return
+ if(O.anchored)
+ if(enable_special)
+ if(istype(O, /obj/machinery/door/firedoor)) // I love doors.
+ var/obj/machinery/door/firedoor/FD = O
+ if(FD.blocked)
+ FD.visible_message("\The [chassis] begins prying on \the [FD]!")
+ if(do_after(chassis.occupant,10 SECONDS,FD))
+ playsound(FD.loc, 'sound/machines/airlock_creaking.ogg', 100, 1)
+ FD.blocked = 0
+ FD.update_icon()
+ FD.open(1)
+ FD.visible_message("\The [chassis] tears \the [FD] open!")
+ else if(FD.density)
+ FD.visible_message("\The [chassis] begins forcing \the [FD] open!")
+ if(do_after(chassis.occupant, 5 SECONDS,FD))
+ playsound(FD.loc, 'sound/machines/airlock_creaking.ogg', 100, 1)
+ FD.visible_message("\The [chassis] forces \the [FD] open!")
+ FD.open(1)
+ else
+ FD.visible_message("\The [chassis] forces \the [FD] closed!")
+ FD.close(1)
+ else if(istype(O, /obj/machinery/door/airlock)) // D o o r s.
+ var/obj/machinery/door/airlock/AD = O
+ if(AD.locked)
+ occupant_message("The airlock's bolts prevent it from being forced.")
+ else if(!AD.operating)
+ if(AD.welded)
+ AD.visible_message("\The [chassis] begins prying on \the [AD]!")
+ if(do_after(chassis.occupant, 15 SECONDS,AD) && chassis.Adjacent(AD))
+ AD.welded = FALSE
+ AD.update_icon()
+ playsound(AD.loc, 'sound/machines/airlock_creaking.ogg', 100, 1)
+ AD.visible_message("\The [chassis] tears \the [AD] open!")
+ if(!AD.welded)
+ if(density)
+ spawn(0)
+ AD.open(1)
+ else
+ spawn(0)
+ AD.close(1)
+ return
+ else
+ occupant_message("[target] is firmly secured.")
+ return
+ if(cargo_holder.cargo.len >= cargo_holder.cargo_capacity)
+ occupant_message("Not enough room in cargo compartment.")
+ return
+
+ occupant_message("You lift [target] and start to load it into cargo compartment.")
+ chassis.visible_message("[chassis] lifts [target] and starts to load it into cargo compartment.")
+ set_ready_state(0)
+ chassis.use_power(energy_drain)
+ O.anchored = 1
+ var/T = chassis.loc
+ if(do_after_cooldown(target))
+ if(T == chassis.loc && src == chassis.selected)
+ cargo_holder.cargo += O
+ O.loc = chassis
+ O.anchored = 0
+ occupant_message("[target] succesfully loaded.")
+ log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]")
+ else
+ occupant_message("You must hold still while handling objects.")
+ O.anchored = initial(O.anchored)
+
+ //attacking
+ else if(istype(target,/mob/living))
+ var/mob/living/M = target
+ if(M.stat>1) return
+ if(chassis.occupant.a_intent == I_HURT || istype(chassis.occupant,/mob/living/carbon/brain)) //No tactile feedback for brains
+ M.take_overall_damage(dam_force)
+ M.adjustOxyLoss(round(dam_force/2))
+ M.updatehealth()
+ occupant_message("You squeeze [target] with [src.name]. Something cracks.")
+ playsound(src.loc, "fracture", 5, 1, -2) //CRACK
+ chassis.visible_message("[chassis] squeezes [target].")
+ else if(chassis.occupant.a_intent == I_DISARM && enable_special)
+ playsound(src.loc, 'sound/mecha/hydraulic.ogg', 10, 1, -2)
+ M.take_overall_damage(dam_force/2)
+ M.adjustOxyLoss(round(dam_force/3))
+ M.updatehealth()
+ occupant_message("You slam [target] with [src.name]. Something cracks.")
+ playsound(src.loc, "fracture", 3, 1, -2) //CRACK 2
+ chassis.visible_message("[chassis] slams [target].")
+ M.throw_at(get_step(M,get_dir(src, M)), 14, 1.5, chassis)
+ else
+ step_away(M,chassis)
+ occupant_message("You push [target] out of the way.")
+ chassis.visible_message("[chassis] pushes [target] out of the way.")
+ set_ready_state(0)
+ chassis.use_power(energy_drain)
+ do_after_cooldown()
+ return 1
+
+
+//This is pretty much just for the death-ripley so that it is harmless
+/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp/safety
+ name = "\improper KILL CLAMP"
+ equip_cooldown = 15
+ energy_drain = 0
+ dam_force = 0
+
+/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp/safety/action(atom/target)
+ if(!action_checks(target)) return
+ if(!cargo_holder) return
+ if(istype(target,/obj))
+ var/obj/O = target
+ if(!O.anchored)
+ if(cargo_holder.cargo.len < cargo_holder.cargo_capacity)
+ chassis.occupant_message("You lift [target] and start to load it into cargo compartment.")
+ chassis.visible_message("[chassis] lifts [target] and starts to load it into cargo compartment.")
+ set_ready_state(0)
+ chassis.use_power(energy_drain)
+ O.anchored = 1
+ var/T = chassis.loc
+ if(do_after_cooldown(target))
+ if(T == chassis.loc && src == chassis.selected)
+ cargo_holder.cargo += O
+ O.loc = chassis
+ O.anchored = 0
+ chassis.occupant_message("[target] succesfully loaded.")
+ chassis.log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]")
+ else
+ chassis.occupant_message("You must hold still while handling objects.")
+ O.anchored = initial(O.anchored)
+ else
+ chassis.occupant_message("Not enough room in cargo compartment.")
+ else
+ chassis.occupant_message("[target] is firmly secured.")
+
+ else if(istype(target,/mob/living))
+ var/mob/living/M = target
+ if(M.stat>1) return
+ if(chassis.occupant.a_intent == I_HURT)
+ chassis.occupant_message("You obliterate [target] with [src.name], leaving blood and guts everywhere.")
+ chassis.visible_message("[chassis] destroys [target] in an unholy fury.")
+ if(chassis.occupant.a_intent == I_DISARM)
+ chassis.occupant_message("You tear [target]'s limbs off with [src.name].")
+ chassis.visible_message("[chassis] rips [target]'s arms off.")
+ else
+ step_away(M,chassis)
+ chassis.occupant_message("You smash into [target], sending them flying.")
+ chassis.visible_message("[chassis] tosses [target] like a piece of paper.")
+ set_ready_state(0)
+ chassis.use_power(energy_drain)
+ do_after_cooldown()
+ return 1
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/drill.dm b/code/game/mecha/equipment/tools/drill.dm
new file mode 100644
index 00000000000..6f44c92d5f9
--- /dev/null
+++ b/code/game/mecha/equipment/tools/drill.dm
@@ -0,0 +1,142 @@
+/obj/item/mecha_parts/mecha_equipment/tool/drill
+ name = "drill"
+ desc = "This is the drill that'll pierce the heavens!"
+ icon_state = "mecha_drill"
+ equip_cooldown = 30
+ energy_drain = 10
+ force = 15
+ required_type = list(/obj/mecha/working/ripley)
+
+/obj/item/mecha_parts/mecha_equipment/tool/drill/action(atom/target)
+ if(!action_checks(target)) return
+ if(isobj(target))
+ var/obj/target_obj = target
+ if(!target_obj.vars.Find("unacidable") || target_obj.unacidable) return
+ set_ready_state(0)
+ chassis.use_power(energy_drain)
+ chassis.visible_message("[chassis] starts to drill [target]", "You hear the drill.")
+ occupant_message("You start to drill [target]")
+ var/T = chassis.loc
+ var/C = target.loc //why are these backwards? we may never know -Pete
+ if(do_after_cooldown(target))
+ if(T == chassis.loc && src == chassis.selected)
+ if(istype(target, /turf/simulated/wall))
+ var/turf/simulated/wall/W = target
+ if(W.reinf_material)
+ occupant_message("[target] is too durable to drill through.")
+ else
+ log_message("Drilled through [target]")
+ target.ex_act(2)
+ else if(istype(target, /turf/simulated/mineral))
+ if(enable_special)
+ for(var/turf/simulated/mineral/M in range(chassis,1))
+ if(get_dir(chassis,M)&chassis.dir)
+ M.GetDrilled()
+ else
+ var/turf/simulated/mineral/M1 = target
+ M1.GetDrilled()
+ log_message("Drilled through [target]")
+ if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment)
+ var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo
+ if(ore_box)
+ for(var/obj/item/weapon/ore/ore in range(chassis,1))
+ if(get_dir(chassis,ore)&chassis.dir)
+ ore.forceMove(ore_box)
+ else if(target.loc == C)
+ log_message("Drilled through [target]")
+ target.ex_act(2)
+ return 1
+
+/obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill
+ name = "diamond drill"
+ desc = "This is an upgraded version of the drill that'll pierce the heavens!"
+ icon_state = "mecha_diamond_drill"
+ origin_tech = list(TECH_MATERIAL = 4, TECH_ENGINEERING = 3)
+ equip_cooldown = 10
+ force = 15
+
+/obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill/action(atom/target)
+ if(!action_checks(target)) return
+ if(isobj(target))
+ var/obj/target_obj = target
+ if(target_obj.unacidable) return
+ set_ready_state(0)
+ chassis.use_power(energy_drain)
+ chassis.visible_message("[chassis] starts to drill [target]", "You hear the drill.")
+ occupant_message("You start to drill [target]")
+ var/T = chassis.loc
+ var/C = target.loc //why are these backwards? we may never know -Pete
+ if(do_after_cooldown(target))
+ if(T == chassis.loc && src == chassis.selected)
+ if(istype(target, /turf/simulated/wall))
+ var/turf/simulated/wall/W = target
+ if(!W.reinf_material || do_after_cooldown(target))//To slow down how fast mechs can drill through the station
+ log_message("Drilled through [target]")
+ target.ex_act(3)
+ else if(istype(target, /turf/simulated/mineral))
+ if(enable_special)
+ for(var/turf/simulated/mineral/M in range(chassis,1))
+ if(get_dir(chassis,M)&chassis.dir)
+ M.GetDrilled()
+ else
+ var/turf/simulated/mineral/M1 = target
+ M1.GetDrilled()
+ log_message("Drilled through [target]")
+ if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment)
+ var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo
+ if(ore_box)
+ for(var/obj/item/weapon/ore/ore in range(chassis,1))
+ if(get_dir(chassis,ore)&chassis.dir)
+ ore.forceMove(ore_box)
+ else if(target.loc == C)
+ log_message("Drilled through [target]")
+ target.ex_act(2)
+ return 1
+
+/obj/item/mecha_parts/mecha_equipment/tool/drill/bore
+ name = "depth bore"
+ desc = "This is the drill that'll pierce the depths!"
+ icon_state = "mecha_bore"
+ equip_cooldown = 5 SECONDS
+ energy_drain = 30
+ force = 20
+ required_type = list(/obj/mecha/working/ripley)
+
+/obj/item/mecha_parts/mecha_equipment/tool/drill/bore/action(atom/target)
+ if(!action_checks(target)) return
+ if(isobj(target))
+ var/obj/target_obj = target
+ if(target_obj.unacidable) return
+ set_ready_state(0)
+ chassis.use_power(energy_drain)
+ chassis.visible_message("[chassis] starts to bore into \the [target]", "You hear the bore.")
+ occupant_message("You start to bore into \the [target]")
+ var/T = chassis.loc
+ var/C = target.loc
+ if(do_after_cooldown(target))
+ if(T == chassis.loc && src == chassis.selected)
+ if(istype(target, /turf/simulated/wall))
+ var/turf/simulated/wall/W = target
+ if(W.reinf_material)
+ occupant_message("[target] is too durable to bore through.")
+ else
+ log_message("Bored through [target]")
+ target.ex_act(2)
+ else if(istype(target, /turf/simulated/mineral))
+ var/turf/simulated/mineral/M = target
+ if(enable_special && !M.density)
+ M.ex_act(2)
+ log_message("Bored into [target]")
+ else
+ M.GetDrilled()
+ log_message("Bored through [target]")
+ if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment)
+ var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo
+ if(ore_box)
+ for(var/obj/item/weapon/ore/ore in range(chassis,1))
+ if(get_dir(chassis,ore)&chassis.dir)
+ ore.forceMove(ore_box)
+ else if(target.loc == C)
+ log_message("Drilled through [target]")
+ target.ex_act(2)
+ return 1
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/energy_relay.dm b/code/game/mecha/equipment/tools/energy_relay.dm
new file mode 100644
index 00000000000..d6917a0de1c
--- /dev/null
+++ b/code/game/mecha/equipment/tools/energy_relay.dm
@@ -0,0 +1,115 @@
+/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay
+ name = "energy relay"
+ desc = "Wirelessly drains energy from any available power channel in area. The performance index is quite low."
+ icon_state = "tesla"
+ origin_tech = list(TECH_MAGNET = 4, TECH_ILLEGAL = 2)
+ equip_cooldown = 10
+ energy_drain = 0
+ range = 0
+ var/datum/global_iterator/pr_energy_relay
+ var/coeff = 100
+ var/list/use_channels = list(EQUIP,ENVIRON,LIGHT)
+
+ equip_type = EQUIP_UTILITY
+
+/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/New()
+ ..()
+ pr_energy_relay = new /datum/global_iterator/mecha_energy_relay(list(src),0)
+ pr_energy_relay.set_delay(equip_cooldown)
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/Destroy()
+ qdel(pr_energy_relay)
+ pr_energy_relay = null
+ ..()
+
+/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/detach()
+ pr_energy_relay.stop()
+// chassis.proc_res["dynusepower"] = null
+ chassis.proc_res["dyngetcharge"] = null
+ ..()
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/attach(obj/mecha/M)
+ ..()
+ chassis.proc_res["dyngetcharge"] = src
+// chassis.proc_res["dynusepower"] = src
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/can_attach(obj/mecha/M)
+ if(..())
+ if(!M.proc_res["dyngetcharge"])// && !M.proc_res["dynusepower"])
+ return 1
+ return 0
+
+/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/dyngetcharge()
+ if(equip_ready) //disabled
+ return chassis.dyngetcharge()
+ var/area/A = get_area(chassis)
+ var/pow_chan = get_power_channel(A)
+ var/charge = 0
+ if(pow_chan)
+ charge = 1000 //making magic
+ else
+ return chassis.dyngetcharge()
+ return charge
+
+/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/get_power_channel(var/area/A)
+ var/pow_chan
+ if(A)
+ for(var/c in use_channels)
+ if(A.powered(c))
+ pow_chan = c
+ break
+ return pow_chan
+
+/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/Topic(href, href_list)
+ ..()
+ if(href_list["toggle_relay"])
+ if(pr_energy_relay.toggle())
+ set_ready_state(0)
+ log_message("Activated.")
+ else
+ set_ready_state(1)
+ log_message("Deactivated.")
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/get_equip_info()
+ if(!chassis) return
+ return "* [src.name] - [pr_energy_relay.active()?"Dea":"A"]ctivate"
+
+/* proc/dynusepower(amount)
+ if(!equip_ready) //enabled
+ var/area/A = get_area(chassis)
+ var/pow_chan = get_power_channel(A)
+ if(pow_chan)
+ A.master.use_power(amount*coeff, pow_chan)
+ return 1
+ return chassis.dynusepower(amount)*/
+
+/datum/global_iterator/mecha_energy_relay
+
+/datum/global_iterator/mecha_energy_relay/process(var/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/ER)
+ if(!ER.chassis || ER.chassis.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT))
+ stop()
+ ER.set_ready_state(1)
+ return
+ var/cur_charge = ER.chassis.get_charge()
+ if(isnull(cur_charge) || !ER.chassis.cell)
+ stop()
+ ER.set_ready_state(1)
+ ER.occupant_message("No powercell detected.")
+ return
+ if(cur_charge3) return
+ if(get_dist(chassis, target)>2) return
+ set_ready_state(0)
+ if(do_after_cooldown(target))
+ if( istype(target, /obj/structure/reagent_dispensers/watertank) && get_dist(chassis,target) <= 1)
+ var/obj/o = target
+ var/amount = o.reagents.trans_to_obj(src, 200)
+ occupant_message("[amount] units transferred into internal tank.")
+ playsound(chassis, 'sound/effects/refill.ogg', 50, 1, -6)
+ return
+
+ if (src.reagents.total_volume < 1)
+ occupant_message("\The [src] is empty.")
+ return
+
+ playsound(chassis, 'sound/effects/extinguish.ogg', 75, 1, -3)
+
+ var/direction = get_dir(chassis,target)
+
+ var/turf/T = get_turf(target)
+ var/turf/T1 = get_step(T,turn(direction, 90))
+ var/turf/T2 = get_step(T,turn(direction, -90))
+
+ var/list/the_targets = list(T,T1,T2)
+
+ for(var/a = 1 to 5)
+ spawn(0)
+ var/obj/effect/effect/water/W = new /obj/effect/effect/water(get_turf(chassis))
+ var/turf/my_target
+ if(a == 1)
+ my_target = T
+ else if(a == 2)
+ my_target = T1
+ else if(a == 3)
+ my_target = T2
+ else
+ my_target = pick(the_targets)
+ W.create_reagents(5)
+ if(!W || !src)
+ return
+ reagents.trans_to_obj(W, spray_amount)
+ W.set_color()
+ W.set_up(my_target)
+ return 1
+
+/obj/item/mecha_parts/mecha_equipment/tool/extinguisher/get_equip_info()
+ return "[..()] \[[src.reagents.total_volume]\]"
+
+/obj/item/mecha_parts/mecha_equipment/tool/extinguisher/on_reagent_change()
+ return
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/generator.dm b/code/game/mecha/equipment/tools/generator.dm
new file mode 100644
index 00000000000..b4896045c55
--- /dev/null
+++ b/code/game/mecha/equipment/tools/generator.dm
@@ -0,0 +1,166 @@
+/obj/item/mecha_parts/mecha_equipment/generator
+ name = "phoron generator"
+ desc = "Generates power using solid phoron as fuel. Pollutes the environment."
+ icon_state = "tesla"
+ origin_tech = list(TECH_PHORON = 2, TECH_POWER = 2, TECH_ENGINEERING = 1)
+ equip_cooldown = 10
+ energy_drain = 0
+ range = MELEE
+ var/datum/global_iterator/pr_mech_generator
+ var/coeff = 100
+ var/obj/item/stack/material/fuel
+ var/max_fuel = 150000
+ var/fuel_per_cycle_idle = 100
+ var/fuel_per_cycle_active = 500
+ var/power_per_cycle = 20
+
+ equip_type = EQUIP_UTILITY
+
+/obj/item/mecha_parts/mecha_equipment/generator/New()
+ ..()
+ init()
+ return
+
+/obj/item/mecha_parts/mecha_equipment/generator/Destroy()
+ qdel(pr_mech_generator)
+ pr_mech_generator = null
+ ..()
+
+/obj/item/mecha_parts/mecha_equipment/generator/proc/init()
+ fuel = new /obj/item/stack/material/phoron(src)
+ fuel.amount = 0
+ pr_mech_generator = new /datum/global_iterator/mecha_generator(list(src),0)
+ pr_mech_generator.set_delay(equip_cooldown)
+ return
+
+/obj/item/mecha_parts/mecha_equipment/generator/detach()
+ pr_mech_generator.stop()
+ ..()
+ return
+
+
+/obj/item/mecha_parts/mecha_equipment/generator/Topic(href, href_list)
+ ..()
+ if(href_list["toggle"])
+ if(pr_mech_generator.toggle())
+ set_ready_state(0)
+ log_message("Activated.")
+ else
+ set_ready_state(1)
+ log_message("Deactivated.")
+ return
+
+/obj/item/mecha_parts/mecha_equipment/generator/get_equip_info()
+ var/output = ..()
+ if(output)
+ return "[output] \[[fuel]: [round(fuel.amount*fuel.perunit,0.1)] cm3\] - [pr_mech_generator.active()?"Dea":"A"]ctivate"
+ return
+
+/obj/item/mecha_parts/mecha_equipment/generator/action(target)
+ if(chassis)
+ var/result = load_fuel(target)
+ var/message
+ if(isnull(result))
+ message = "[fuel] traces in target minimal. [target] cannot be used as fuel."
+ else if(!result)
+ message = "Unit is full."
+ else
+ message = "[result] unit\s of [fuel] successfully loaded."
+ send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
+ occupant_message(message)
+ return
+
+/obj/item/mecha_parts/mecha_equipment/generator/proc/load_fuel(var/obj/item/stack/material/P)
+ if(P.type == fuel.type && P.amount)
+ var/to_load = max(max_fuel - fuel.amount*fuel.perunit,0)
+ if(to_load)
+ var/units = min(max(round(to_load / P.perunit),1),P.amount)
+ if(units)
+ fuel.amount += units
+ P.use(units)
+ return units
+ else
+ return 0
+ return
+
+/obj/item/mecha_parts/mecha_equipment/generator/attackby(weapon,mob/user)
+ var/result = load_fuel(weapon)
+ if(isnull(result))
+ user.visible_message("[user] tries to shove [weapon] into [src]. What a dumb-ass.","[fuel] traces minimal. [weapon] cannot be used as fuel.")
+ else if(!result)
+ user << "Unit is full."
+ else
+ user.visible_message("[user] loads [src] with [fuel].","[result] unit\s of [fuel] successfully loaded.")
+ return
+
+/obj/item/mecha_parts/mecha_equipment/generator/critfail()
+ ..()
+ var/turf/simulated/T = get_turf(src)
+ if(!T)
+ return
+ var/datum/gas_mixture/GM = new
+ if(prob(10))
+ T.assume_gas("phoron", 100, 1500+T0C)
+ T.visible_message("The [src] suddenly disgorges a cloud of heated phoron.")
+ destroy()
+ else
+ T.assume_gas("phoron", 5, istype(T) ? T.air.temperature : T20C)
+ T.visible_message("The [src] suddenly disgorges a cloud of phoron.")
+ T.assume_air(GM)
+ return
+
+/datum/global_iterator/mecha_generator
+
+/datum/global_iterator/mecha_generator/process(var/obj/item/mecha_parts/mecha_equipment/generator/EG)
+ if(!EG.chassis)
+ stop()
+ EG.set_ready_state(1)
+ return 0
+ if(EG.fuel.amount<=0)
+ stop()
+ EG.log_message("Deactivated - no fuel.")
+ EG.set_ready_state(1)
+ return 0
+ var/cur_charge = EG.chassis.get_charge()
+ if(isnull(cur_charge))
+ EG.set_ready_state(1)
+ EG.occupant_message("No powercell detected.")
+ EG.log_message("Deactivated.")
+ stop()
+ return 0
+ var/use_fuel = EG.fuel_per_cycle_idle
+ if(cur_charge* [src.name] \[Toggle\]"
+
+/obj/item/mecha_parts/mecha_equipment/tool/jetpack/Topic(href,href_list)
+ ..()
+ if(href_list["toggle"])
+ toggle()
+
+/obj/item/mecha_parts/mecha_equipment/tool/jetpack/do_after_cooldown()
+ sleep(equip_cooldown)
+ wait = 0
+ return 1
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/medical_tools_vr.dm b/code/game/mecha/equipment/tools/medigun_vr.dm
similarity index 100%
rename from code/game/mecha/equipment/tools/medical_tools_vr.dm
rename to code/game/mecha/equipment/tools/medigun_vr.dm
diff --git a/code/game/mecha/equipment/tools/orescanner.dm b/code/game/mecha/equipment/tools/orescanner.dm
new file mode 100644
index 00000000000..91027bd2646
--- /dev/null
+++ b/code/game/mecha/equipment/tools/orescanner.dm
@@ -0,0 +1,41 @@
+/obj/item/mecha_parts/mecha_equipment/tool/orescanner
+ name = "mounted ore scanner"
+ desc = "An exosuit-mounted ore scanner."
+ icon_state = "mecha_analyzer"
+ origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 2, TECH_POWER = 2)
+ equip_cooldown = 5
+ energy_drain = 30
+ range = MELEE|RANGED
+ equip_type = EQUIP_SPECIAL
+ ready_sound = 'sound/items/goggles_charge.ogg'
+ required_type = list(/obj/mecha/working/ripley)
+
+ var/obj/item/weapon/mining_scanner/my_scanner = null
+ var/exact_scan = FALSE
+
+/obj/item/mecha_parts/mecha_equipment/tool/orescanner/Initialize()
+ my_scanner = new(src)
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/tool/orescanner/Destroy()
+ QDEL_NULL(my_scanner)
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/tool/orescanner/action(var/atom/target)
+ if(!action_checks(target) || get_dist(chassis, target) > 5)
+ return FALSE
+
+ if(!enable_special)
+ target = get_turf(chassis)
+
+ var/datum/beam/ScanBeam = chassis.Beam(target,"g_beam",'icons/effects/beam.dmi',time=2 SECONDS,10,/obj/effect/ebeam,2)
+
+ if(do_after(chassis.occupant, 2 SECONDS))
+ my_scanner.ScanTurf(target, chassis.occupant, exact_scan)
+
+ QDEL_NULL(ScanBeam)
+
+/obj/item/mecha_parts/mecha_equipment/tool/orescanner/advanced
+ name = "advanced ore scanner"
+ icon_state = "mecha_analyzer_adv"
+ exact_scan = TRUE
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/passenger.dm b/code/game/mecha/equipment/tools/passenger.dm
new file mode 100644
index 00000000000..1e40da2f301
--- /dev/null
+++ b/code/game/mecha/equipment/tools/passenger.dm
@@ -0,0 +1,151 @@
+/obj/item/mecha_parts/mecha_equipment/tool/passenger
+ name = "passenger compartment"
+ desc = "A mountable passenger compartment for exosuits. Rather cramped."
+ icon_state = "mecha_abooster_ccw"
+ origin_tech = list(TECH_ENGINEERING = 1, TECH_BIO = 1)
+ energy_drain = 10
+ range = MELEE
+ equip_cooldown = 20
+ var/mob/living/carbon/occupant = null
+ var/door_locked = 1
+ salvageable = 0
+ allow_duplicate = TRUE
+
+ equip_type = EQUIP_HULL
+
+/obj/item/mecha_parts/mecha_equipment/tool/passenger/destroy()
+ for(var/atom/movable/AM in src)
+ AM.forceMove(get_turf(src))
+ AM << "You tumble out of the destroyed [src.name]!"
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/tool/passenger/Exit(atom/movable/O)
+ return 0
+
+/obj/item/mecha_parts/mecha_equipment/tool/passenger/proc/move_inside(var/mob/user)
+ if (chassis)
+ chassis.visible_message("[user] starts to climb into [chassis].")
+
+ if(do_after(user, 40, needhand=0))
+ if(!src.occupant)
+ user.forceMove(src)
+ occupant = user
+ log_message("[user] boarded.")
+ occupant_message("[user] boarded.")
+ else if(src.occupant != user)
+ to_chat(user, "[src.occupant] was faster. Try harder next time, loser.")
+ else
+ to_chat(user, "You stop entering the exosuit.")
+
+/obj/item/mecha_parts/mecha_equipment/tool/passenger/verb/eject()
+ set name = "Eject"
+ set category = "Exosuit Interface"
+ set src = usr.loc
+ set popup_menu = 0
+
+ if(usr != occupant)
+ return
+ to_chat(occupant, "You climb out from \the [src].")
+ go_out()
+ occupant_message("[occupant] disembarked.")
+ log_message("[occupant] disembarked.")
+ add_fingerprint(usr)
+
+/obj/item/mecha_parts/mecha_equipment/tool/passenger/proc/go_out()
+ if(!occupant)
+ return
+ occupant.forceMove(get_turf(src))
+ occupant.reset_view()
+ /*
+ if(occupant.client)
+ occupant.client.eye = occupant.client.mob
+ occupant.client.perspective = MOB_PERSPECTIVE
+ */
+ occupant = null
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tool/passenger/attach()
+ ..()
+ if (chassis)
+ chassis.verbs |= /obj/mecha/proc/move_inside_passenger
+
+/obj/item/mecha_parts/mecha_equipment/tool/passenger/detach()
+ if(occupant)
+ occupant_message("Unable to detach [src] - equipment occupied.")
+ return
+
+ var/obj/mecha/M = chassis
+ ..()
+ if (M && !(locate(/obj/item/mecha_parts/mecha_equipment/tool/passenger) in M))
+ M.verbs -= /obj/mecha/proc/move_inside_passenger
+
+/obj/item/mecha_parts/mecha_equipment/tool/passenger/get_equip_info()
+ return "[..()]
[occupant? "\[Occupant: [occupant]\]|" : ""]Exterior Hatch: Toggle Lock"
+
+/obj/item/mecha_parts/mecha_equipment/tool/passenger/Topic(href,href_list)
+ ..()
+ if (href_list["toggle_lock"])
+ door_locked = !door_locked
+ occupant_message("Passenger compartment hatch [door_locked? "locked" : "unlocked"].")
+ if (chassis)
+ chassis.visible_message("The hatch on \the [chassis] [door_locked? "locks" : "unlocks"].", "You hear something latching.")
+
+
+#define LOCKED 1
+#define OCCUPIED 2
+
+/obj/mecha/proc/move_inside_passenger()
+ set category = "Object"
+ set name = "Enter Passenger Compartment"
+ set src in oview(1)
+
+ //check that usr can climb in
+ if (usr.stat || !ishuman(usr))
+ return
+
+ if (!usr.Adjacent(src))
+ return
+
+ if (!isturf(usr.loc))
+ usr << "You can't reach the passenger compartment from here."
+ return
+
+ if(iscarbon(usr))
+ var/mob/living/carbon/C = usr
+ if(C.handcuffed)
+ usr << "Kinda hard to climb in while handcuffed don't you think?"
+ return
+
+ if(isliving(usr))
+ var/mob/living/L = usr
+ if(L.has_buckled_mobs())
+ to_chat(L, span("warning", "You have other entities attached to yourself. Remove them first."))
+ return
+
+ //search for a valid passenger compartment
+ var/feedback = 0 //for nicer user feedback
+ for(var/obj/item/mecha_parts/mecha_equipment/tool/passenger/P in src)
+ if (P.occupant)
+ feedback |= OCCUPIED
+ continue
+ if (P.door_locked)
+ feedback |= LOCKED
+ continue
+
+ //found a boardable compartment
+ P.move_inside(usr)
+ return
+
+ //didn't find anything
+ switch (feedback)
+ if (OCCUPIED)
+ usr << "The passenger compartment is already occupied!"
+ if (LOCKED)
+ usr << "The passenger compartment hatch is locked!"
+ if (OCCUPIED|LOCKED)
+ usr << "All of the passenger compartments are already occupied or locked!"
+ if (0)
+ usr << "\The [src] doesn't have a passenger compartment."
+
+#undef LOCKED
+#undef OCCUPIED
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/rcd.dm b/code/game/mecha/equipment/tools/rcd.dm
new file mode 100644
index 00000000000..9aa9a8bb406
--- /dev/null
+++ b/code/game/mecha/equipment/tools/rcd.dm
@@ -0,0 +1,45 @@
+/obj/item/mecha_parts/mecha_equipment/tool/rcd
+ name = "mounted RCD"
+ desc = "An exosuit-mounted Rapid Construction Device. (Can be attached to: Any exosuit)"
+ icon_state = "mecha_rcd"
+ origin_tech = list(TECH_MATERIAL = 4, TECH_BLUESPACE = 3, TECH_MAGNET = 4, TECH_POWER = 4)
+ equip_cooldown = 10
+ energy_drain = 250
+ range = MELEE|RANGED
+ equip_type = EQUIP_SPECIAL
+ var/obj/item/weapon/rcd/electric/mounted/mecha/my_rcd = null
+
+/obj/item/mecha_parts/mecha_equipment/tool/rcd/Initialize()
+ my_rcd = new(src)
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/tool/rcd/Destroy()
+ QDEL_NULL(my_rcd)
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/tool/rcd/action(atom/target)
+ if(!action_checks(target) || get_dist(chassis, target) > 3)
+ return FALSE
+
+ my_rcd.use_rcd(target, chassis.occupant)
+
+/obj/item/mecha_parts/mecha_equipment/tool/rcd/Topic(href,href_list)
+ ..()
+ if(href_list["mode"])
+ my_rcd.mode_index = text2num(href_list["mode"])
+ occupant_message("RCD reconfigured to '[my_rcd.modes[my_rcd.mode_index]]'.")
+/*
+/obj/item/mecha_parts/mecha_equipment/tool/rcd/get_equip_info()
+ return "[..()] \[D|C|A\]"
+*/
+/obj/item/mecha_parts/mecha_equipment/tool/rcd/get_equip_info()
+ var/list/content = list(..()) // This is all for one line, in the interest of string tree conservation.
+ var/i = 1
+ content += "
"
+ for(var/mode in my_rcd.modes)
+ content += " [mode]"
+ if(i < my_rcd.modes.len)
+ content += "
"
+ i++
+
+ return content.Join()
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/repair_droid.dm b/code/game/mecha/equipment/tools/repair_droid.dm
new file mode 100644
index 00000000000..f76eeed6f09
--- /dev/null
+++ b/code/game/mecha/equipment/tools/repair_droid.dm
@@ -0,0 +1,94 @@
+/obj/item/mecha_parts/mecha_equipment/repair_droid
+ name = "repair droid"
+ desc = "Automated repair droid. Scans exosuit for damage and repairs it. Can fix almost any type of external or internal damage."
+ icon_state = "repair_droid"
+ origin_tech = list(TECH_MAGNET = 3, TECH_DATA = 3)
+ equip_cooldown = 20
+ energy_drain = 100
+ range = 0
+ var/health_boost = 2
+ var/datum/global_iterator/pr_repair_droid
+ var/icon/droid_overlay
+ var/list/repairable_damage = list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH)
+
+ equip_type = EQUIP_HULL
+
+/obj/item/mecha_parts/mecha_equipment/repair_droid/New()
+ ..()
+ pr_repair_droid = new /datum/global_iterator/mecha_repair_droid(list(src),0)
+ pr_repair_droid.set_delay(equip_cooldown)
+ return
+
+/obj/item/mecha_parts/mecha_equipment/repair_droid/Destroy()
+ qdel(pr_repair_droid)
+ pr_repair_droid = null
+ ..()
+
+/obj/item/mecha_parts/mecha_equipment/repair_droid/attach(obj/mecha/M as obj)
+ ..()
+ droid_overlay = new(src.icon, icon_state = "repair_droid")
+ M.overlays += droid_overlay
+ return
+
+/obj/item/mecha_parts/mecha_equipment/repair_droid/destroy()
+ chassis.overlays -= droid_overlay
+ ..()
+ return
+
+/obj/item/mecha_parts/mecha_equipment/repair_droid/detach()
+ chassis.overlays -= droid_overlay
+ pr_repair_droid.stop()
+ ..()
+ return
+
+/obj/item/mecha_parts/mecha_equipment/repair_droid/get_equip_info()
+ if(!chassis) return
+ return "* [src.name] - [pr_repair_droid.active()?"Dea":"A"]ctivate"
+
+
+/obj/item/mecha_parts/mecha_equipment/repair_droid/Topic(href, href_list)
+ ..()
+ if(href_list["toggle_repairs"])
+ chassis.overlays -= droid_overlay
+ if(pr_repair_droid.toggle())
+ droid_overlay = new(src.icon, icon_state = "repair_droid_a")
+ log_message("Activated.")
+ else
+ droid_overlay = new(src.icon, icon_state = "repair_droid")
+ log_message("Deactivated.")
+ set_ready_state(1)
+ chassis.overlays += droid_overlay
+ send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
+ return
+
+
+/datum/global_iterator/mecha_repair_droid
+
+/datum/global_iterator/mecha_repair_droid/process(var/obj/item/mecha_parts/mecha_equipment/repair_droid/RD as obj)
+ if(!RD.chassis)
+ stop()
+ RD.set_ready_state(1)
+ return
+ var/health_boost = RD.health_boost
+ var/repaired = 0
+ if(RD.chassis.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT))
+ health_boost *= -2
+ else if(RD.chassis.hasInternalDamage() && prob(15))
+ for(var/int_dam_flag in RD.repairable_damage)
+ if(RD.chassis.hasInternalDamage(int_dam_flag))
+ RD.chassis.clearInternalDamage(int_dam_flag)
+ repaired = 1
+ break
+ if(health_boost<0 || RD.chassis.health < initial(RD.chassis.health))
+ RD.chassis.health += min(health_boost, initial(RD.chassis.health)-RD.chassis.health)
+ repaired = 1
+ if(repaired)
+ if(RD.chassis.use_power(RD.energy_drain))
+ RD.set_ready_state(0)
+ else
+ stop()
+ RD.set_ready_state(1)
+ return
+ else
+ RD.set_ready_state(1)
+ return
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/shield.dm b/code/game/mecha/equipment/tools/shield.dm
new file mode 100644
index 00000000000..1ceab079454
--- /dev/null
+++ b/code/game/mecha/equipment/tools/shield.dm
@@ -0,0 +1,82 @@
+/obj/item/mecha_parts/mecha_equipment/combat_shield
+ name = "linear combat shield"
+ desc = "A shield generator that forms a rectangular, unidirectionally projectile-blocking wall in front of the exosuit."
+ icon_state = "shield"
+ origin_tech = list(TECH_PHORON = 3, TECH_MAGNET = 6, TECH_ILLEGAL = 4)
+ equip_cooldown = 5
+ energy_drain = 20
+ range = 0
+
+ var/obj/item/shield_projector/line/exosuit/my_shield = null
+ var/my_shield_type = /obj/item/shield_projector/line/exosuit
+ var/icon/drone_overlay
+
+ equip_type = EQUIP_HULL
+
+/obj/item/mecha_parts/mecha_equipment/combat_shield/New()
+ ..()
+ my_shield = new my_shield_type
+ my_shield.shield_regen_delay = equip_cooldown
+ my_shield.my_tool = src
+ return
+
+/obj/item/mecha_parts/mecha_equipment/combat_shield/critfail()
+ ..()
+ my_shield.adjust_health(-200)
+ return
+
+/obj/item/mecha_parts/mecha_equipment/combat_shield/Destroy()
+ chassis.overlays -= drone_overlay
+ my_shield.forceMove(src)
+ my_shield.destroy_shields()
+ my_shield.my_tool = null
+ my_shield.my_mecha = null
+ qdel(my_shield)
+ my_shield = null
+ ..()
+
+/obj/item/mecha_parts/mecha_equipment/combat_shield/attach(obj/mecha/M as obj)
+ ..()
+ if(chassis)
+ my_shield.shield_health = 0
+ my_shield.my_mecha = chassis
+ my_shield.forceMove(chassis)
+
+ drone_overlay = new(src.icon, icon_state = "shield_droid")
+ M.overlays += drone_overlay
+ return
+
+/obj/item/mecha_parts/mecha_equipment/combat_shield/detach()
+ chassis.overlays -= drone_overlay
+ ..()
+ my_shield.destroy_shields()
+ my_shield.my_mecha = null
+ my_shield.shield_health = my_shield.max_shield_health
+ my_shield.forceMove(src)
+ return
+
+/obj/item/mecha_parts/mecha_equipment/combat_shield/handle_movement_action()
+ if(chassis)
+ my_shield.update_shield_positions()
+ return
+
+/obj/item/mecha_parts/mecha_equipment/combat_shield/proc/toggle_shield()
+ ..()
+ if(chassis)
+ my_shield.attack_self(chassis.occupant)
+ if(my_shield.active)
+ set_ready_state(0)
+ log_message("Activated.")
+ else
+ set_ready_state(1)
+ log_message("Deactivated.")
+
+/obj/item/mecha_parts/mecha_equipment/combat_shield/Topic(href, href_list)
+ ..()
+ if(href_list["toggle_shield"])
+ toggle_shield()
+ return
+
+/obj/item/mecha_parts/mecha_equipment/combat_shield/get_equip_info()
+ if(!chassis) return
+ return "* [src.name] - [my_shield.active?"Dea":"A"]ctivate"
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/sleeper.dm b/code/game/mecha/equipment/tools/sleeper.dm
new file mode 100644
index 00000000000..861471b6ceb
--- /dev/null
+++ b/code/game/mecha/equipment/tools/sleeper.dm
@@ -0,0 +1,247 @@
+/obj/item/mecha_parts/mecha_equipment/tool/sleeper
+ name = "mounted sleeper"
+ desc = "A sleeper. Mountable to an exosuit. (Can be attached to: Medical Exosuits)"
+ icon = 'icons/obj/Cryogenic2.dmi'
+ icon_state = "sleeper_0"
+ origin_tech = list(TECH_DATA = 2, TECH_BIO = 3)
+ energy_drain = 20
+ range = MELEE
+ equip_cooldown = 30
+ var/mob/living/carbon/human/occupant = null
+ var/datum/global_iterator/pr_mech_sleeper
+ var/inject_amount = 5
+ required_type = list(/obj/mecha/medical)
+ salvageable = 0
+ allow_duplicate = TRUE
+
+/obj/item/mecha_parts/mecha_equipment/tool/sleeper/New()
+ ..()
+ pr_mech_sleeper = new /datum/global_iterator/mech_sleeper(list(src),0)
+ pr_mech_sleeper.set_delay(equip_cooldown)
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tool/sleeper/Destroy()
+ qdel(pr_mech_sleeper)
+ for(var/atom/movable/AM in src)
+ AM.forceMove(get_turf(src))
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/tool/sleeper/Exit(atom/movable/O)
+ return 0
+
+/obj/item/mecha_parts/mecha_equipment/tool/sleeper/action(var/mob/living/carbon/human/target)
+ if(!action_checks(target))
+ return
+ if(!istype(target))
+ return
+ if(target.buckled)
+ occupant_message("[target] will not fit into the sleeper because they are buckled to [target.buckled].")
+ return
+ if(occupant)
+ occupant_message("The sleeper is already occupied")
+ return
+ if(target.has_buckled_mobs())
+ occupant_message(span("warning", "\The [target] has other entities attached to it. Remove them first."))
+ return
+ occupant_message("You start putting [target] into [src].")
+ chassis.visible_message("[chassis] starts putting [target] into the [src].")
+ var/C = chassis.loc
+ var/T = target.loc
+ if(do_after_cooldown(target))
+ if(chassis.loc!=C || target.loc!=T)
+ return
+ if(occupant)
+ occupant_message("The sleeper is already occupied!")
+ return
+ target.forceMove(src)
+ occupant = target
+ target.reset_view(src)
+ occupant.Stasis(3)
+ /*
+ if(target.client)
+ target.client.perspective = EYE_PERSPECTIVE
+ target.client.eye = chassis
+ */
+ set_ready_state(0)
+ pr_mech_sleeper.start()
+ occupant_message("[target] successfully loaded into [src]. Life support functions engaged.")
+ chassis.visible_message("[chassis] loads [target] into [src].")
+ log_message("[target] loaded. Life support functions engaged.")
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/go_out()
+ if(!occupant)
+ return
+ occupant.forceMove(get_turf(src))
+ occupant_message("[occupant] ejected. Life support functions disabled.")
+ log_message("[occupant] ejected. Life support functions disabled.")
+ occupant.reset_view()
+ /*
+ if(occupant.client)
+ occupant.client.eye = occupant.client.mob
+ occupant.client.perspective = MOB_PERSPECTIVE
+ */
+ occupant.Stasis(0)
+ occupant = null
+ pr_mech_sleeper.stop()
+ set_ready_state(1)
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tool/sleeper/detach()
+ if(occupant)
+ occupant_message("Unable to detach [src] - equipment occupied.")
+ return
+ pr_mech_sleeper.stop()
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/tool/sleeper/get_equip_info()
+ var/output = ..()
+ if(output)
+ var/temp = ""
+ if(occupant)
+ temp = "
\[Occupant: [occupant] (Health: [occupant.health]%)\]
View stats|Eject"
+ return "[output] [temp]"
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tool/sleeper/Topic(href,href_list)
+ ..()
+ var/datum/topic_input/top_filter = new /datum/topic_input(href,href_list)
+ if(top_filter.get("eject"))
+ go_out()
+ if(top_filter.get("view_stats"))
+ chassis.occupant << browse(get_occupant_stats(),"window=msleeper")
+ onclose(chassis.occupant, "msleeper")
+ return
+ if(top_filter.get("inject"))
+ inject_reagent(top_filter.getType("inject",/datum/reagent),top_filter.getObj("source"))
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_occupant_stats()
+ if(!occupant)
+ return
+ return {"
+
+ [occupant] statistics
+
+
+
+
+ Health statistics
+
+ [get_occupant_dam()]
+
+ Reagents in bloodstream
+
+ [get_occupant_reagents()]
+
+
+ [get_available_reagents()]
+
+
+ "}
+
+/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_occupant_dam()
+ var/t1
+ switch(occupant.stat)
+ if(0)
+ t1 = "Conscious"
+ if(1)
+ t1 = "Unconscious"
+ if(2)
+ t1 = "*dead*"
+ else
+ t1 = "Unknown"
+ return {"Health: [occupant.health]% ([t1])
+ Core Temperature: [src.occupant.bodytemperature-T0C]°C ([src.occupant.bodytemperature*1.8-459.67]°F)
+ Brute Damage: [occupant.getBruteLoss()]%
+ Respiratory Damage: [occupant.getOxyLoss()]%
+ Toxin Content: [occupant.getToxLoss()]%
+ Burn Severity: [occupant.getFireLoss()]%
+ "}
+
+/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_occupant_reagents()
+ if(occupant.reagents)
+ for(var/datum/reagent/R in occupant.reagents.reagent_list)
+ if(R.volume > 0)
+ . += "[R]: [round(R.volume,0.01)]
"
+ return . || "None"
+
+/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_available_reagents()
+ var/output
+ var/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/SG = locate(/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun) in chassis
+ if(SG && SG.reagents && islist(SG.reagents.reagent_list))
+ for(var/datum/reagent/R in SG.reagents.reagent_list)
+ if(R.volume > 0)
+ output += "Inject [R.name]
"
+ return output
+
+
+/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/inject_reagent(var/datum/reagent/R,var/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/SG)
+ if(!R || !occupant || !SG || !(SG in chassis.equipment))
+ return 0
+ var/to_inject = min(R.volume, inject_amount)
+ if(to_inject && occupant.reagents.get_reagent_amount(R.id) + to_inject > inject_amount*4)
+ occupant_message("Sleeper safeties prohibit you from injecting more than [inject_amount*4] units of [R.name].")
+ else
+ occupant_message("Injecting [occupant] with [to_inject] units of [R.name].")
+ log_message("Injecting [occupant] with [to_inject] units of [R.name].")
+ //SG.reagents.trans_id_to(occupant,R.id,to_inject)
+ SG.reagents.remove_reagent(R.id,to_inject)
+ occupant.reagents.add_reagent(R.id,to_inject)
+ update_equip_info()
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tool/sleeper/update_equip_info()
+ if(..())
+ send_byjax(chassis.occupant,"msleeper.browser","lossinfo",get_occupant_dam())
+ send_byjax(chassis.occupant,"msleeper.browser","reagents",get_occupant_reagents())
+ send_byjax(chassis.occupant,"msleeper.browser","injectwith",get_available_reagents())
+ return 1
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tool/sleeper/verb/eject()
+ set name = "Sleeper Eject"
+ set category = "Exosuit Interface"
+ set src = usr.loc
+ set popup_menu = 0
+ if(usr!=src.occupant || usr.stat == 2)
+ return
+ to_chat(usr,"Release sequence activated. This will take one minute.")
+ sleep(600)
+ if(!src || !usr || !occupant || (occupant != usr)) //Check if someone's released/replaced/bombed him already
+ return
+ go_out()//and release him from the eternal prison.
+
+/datum/global_iterator/mech_sleeper
+
+/datum/global_iterator/mech_sleeper/process(var/obj/item/mecha_parts/mecha_equipment/tool/sleeper/S)
+ if(!S.chassis)
+ S.set_ready_state(1)
+ return stop()
+ if(!S.chassis.has_charge(S.energy_drain))
+ S.set_ready_state(1)
+ S.log_message("Deactivated.")
+ S.occupant_message("[src] deactivated - no power.")
+ return stop()
+ var/mob/living/carbon/M = S.occupant
+ if(!M)
+ return
+ if(M.health > 0)
+ M.adjustOxyLoss(-1)
+ M.updatehealth()
+ M.AdjustStunned(-4)
+ M.AdjustWeakened(-4)
+ M.AdjustStunned(-4)
+ M.Paralyse(2)
+ M.Weaken(2)
+ M.Stun(2)
+ if(M.reagents.get_reagent_amount("inaprovaline") < 5)
+ M.reagents.add_reagent("inaprovaline", 5)
+ S.chassis.use_power(S.energy_drain)
+ S.update_equip_info()
+ return
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/speedboost.dm b/code/game/mecha/equipment/tools/speedboost.dm
new file mode 100644
index 00000000000..1cb0df9469f
--- /dev/null
+++ b/code/game/mecha/equipment/tools/speedboost.dm
@@ -0,0 +1,21 @@
+/obj/item/mecha_parts/mecha_equipment/speedboost
+ name = "ripley leg actuator overdrive"
+ desc = "System enhancements and overdrives to make a ripley's legs move faster."
+ icon_state = "tesla"
+ origin_tech = list( TECH_POWER = 5, TECH_MATERIAL = 4, TECH_ENGINEERING = 4)
+ required_type = list(/obj/mecha/working/ripley)
+
+ equip_type = EQUIP_HULL
+
+/obj/item/mecha_parts/mecha_equipment/speedboost/attach(obj/mecha/M as obj)
+ ..()
+ if(enable_special)
+ chassis.step_in = (chassis.step_in-2) // Make the ripley as fast as a durand
+ else
+ chassis.step_in = (chassis.step_in+1) // Improper parts slow the mech down
+ return
+
+/obj/item/mecha_parts/mecha_equipment/speedboost/detach()
+ chassis.step_in = initial(chassis.step_in)
+ ..()
+ return
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/game/mecha/equipment/tools/syringe_gun.dm
similarity index 60%
rename from code/game/mecha/equipment/tools/medical_tools.dm
rename to code/game/mecha/equipment/tools/syringe_gun.dm
index 9f1e5227332..57e63b7829b 100644
--- a/code/game/mecha/equipment/tools/medical_tools.dm
+++ b/code/game/mecha/equipment/tools/syringe_gun.dm
@@ -1,805 +1,510 @@
-/obj/item/mecha_parts/mecha_equipment/tool/sleeper
- name = "mounted sleeper"
- desc = "A sleeper. Mountable to an exosuit. (Can be attached to: Medical Exosuits)"
- icon = 'icons/obj/Cryogenic2.dmi'
- icon_state = "sleeper_0"
- origin_tech = list(TECH_DATA = 2, TECH_BIO = 3)
- energy_drain = 20
- range = MELEE
- equip_cooldown = 30
- var/mob/living/carbon/human/occupant = null
- var/datum/global_iterator/pr_mech_sleeper
- var/inject_amount = 5
- required_type = list(/obj/mecha/medical)
- salvageable = 0
- allow_duplicate = TRUE
-
-/obj/item/mecha_parts/mecha_equipment/tool/sleeper/New()
- ..()
- pr_mech_sleeper = new /datum/global_iterator/mech_sleeper(list(src),0)
- pr_mech_sleeper.set_delay(equip_cooldown)
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/sleeper/Destroy()
- qdel(pr_mech_sleeper)
- for(var/atom/movable/AM in src)
- AM.forceMove(get_turf(src))
- return ..()
-
-/obj/item/mecha_parts/mecha_equipment/tool/sleeper/Exit(atom/movable/O)
- return 0
-
-/obj/item/mecha_parts/mecha_equipment/tool/sleeper/action(var/mob/living/carbon/human/target)
- if(!action_checks(target))
- return
- if(!istype(target))
- return
- if(target.buckled)
- occupant_message("[target] will not fit into the sleeper because they are buckled to [target.buckled].")
- return
- if(occupant)
- occupant_message("The sleeper is already occupied")
- return
- if(target.has_buckled_mobs())
- occupant_message(span("warning", "\The [target] has other entities attached to it. Remove them first."))
- return
- occupant_message("You start putting [target] into [src].")
- chassis.visible_message("[chassis] starts putting [target] into the [src].")
- var/C = chassis.loc
- var/T = target.loc
- if(do_after_cooldown(target))
- if(chassis.loc!=C || target.loc!=T)
- return
- if(occupant)
- occupant_message("The sleeper is already occupied!")
- return
- target.forceMove(src)
- occupant = target
- target.reset_view(src)
- occupant.Stasis(3)
- /*
- if(target.client)
- target.client.perspective = EYE_PERSPECTIVE
- target.client.eye = chassis
- */
- set_ready_state(0)
- pr_mech_sleeper.start()
- occupant_message("[target] successfully loaded into [src]. Life support functions engaged.")
- chassis.visible_message("[chassis] loads [target] into [src].")
- log_message("[target] loaded. Life support functions engaged.")
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/go_out()
- if(!occupant)
- return
- occupant.forceMove(get_turf(src))
- occupant_message("[occupant] ejected. Life support functions disabled.")
- log_message("[occupant] ejected. Life support functions disabled.")
- occupant.reset_view()
- /*
- if(occupant.client)
- occupant.client.eye = occupant.client.mob
- occupant.client.perspective = MOB_PERSPECTIVE
- */
- occupant.Stasis(0)
- occupant = null
- pr_mech_sleeper.stop()
- set_ready_state(1)
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/sleeper/detach()
- if(occupant)
- occupant_message("Unable to detach [src] - equipment occupied.")
- return
- pr_mech_sleeper.stop()
- return ..()
-
-/obj/item/mecha_parts/mecha_equipment/tool/sleeper/get_equip_info()
- var/output = ..()
- if(output)
- var/temp = ""
- if(occupant)
- temp = "
\[Occupant: [occupant] (Health: [occupant.health]%)\]
View stats|Eject"
- return "[output] [temp]"
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/sleeper/Topic(href,href_list)
- ..()
- var/datum/topic_input/top_filter = new /datum/topic_input(href,href_list)
- if(top_filter.get("eject"))
- go_out()
- if(top_filter.get("view_stats"))
- chassis.occupant << browse(get_occupant_stats(),"window=msleeper")
- onclose(chassis.occupant, "msleeper")
- return
- if(top_filter.get("inject"))
- inject_reagent(top_filter.getType("inject",/datum/reagent),top_filter.getObj("source"))
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_occupant_stats()
- if(!occupant)
- return
- return {"
-
- [occupant] statistics
-
-
-
-
- Health statistics
-
- [get_occupant_dam()]
-
- Reagents in bloodstream
-
- [get_occupant_reagents()]
-
-
- [get_available_reagents()]
-
-
- "}
-
-/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_occupant_dam()
- var/t1
- switch(occupant.stat)
- if(0)
- t1 = "Conscious"
- if(1)
- t1 = "Unconscious"
- if(2)
- t1 = "*dead*"
- else
- t1 = "Unknown"
- return {"Health: [occupant.health]% ([t1])
- Core Temperature: [src.occupant.bodytemperature-T0C]°C ([src.occupant.bodytemperature*1.8-459.67]°F)
- Brute Damage: [occupant.getBruteLoss()]%
- Respiratory Damage: [occupant.getOxyLoss()]%
- Toxin Content: [occupant.getToxLoss()]%
- Burn Severity: [occupant.getFireLoss()]%
- "}
-
-/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_occupant_reagents()
- if(occupant.reagents)
- for(var/datum/reagent/R in occupant.reagents.reagent_list)
- if(R.volume > 0)
- . += "[R]: [round(R.volume,0.01)]
"
- return . || "None"
-
-/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_available_reagents()
- var/output
- var/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/SG = locate(/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun) in chassis
- if(SG && SG.reagents && islist(SG.reagents.reagent_list))
- for(var/datum/reagent/R in SG.reagents.reagent_list)
- if(R.volume > 0)
- output += "Inject [R.name]
"
- return output
-
-
-/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/inject_reagent(var/datum/reagent/R,var/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/SG)
- if(!R || !occupant || !SG || !(SG in chassis.equipment))
- return 0
- var/to_inject = min(R.volume, inject_amount)
- if(to_inject && occupant.reagents.get_reagent_amount(R.id) + to_inject > inject_amount*4)
- occupant_message("Sleeper safeties prohibit you from injecting more than [inject_amount*4] units of [R.name].")
- else
- occupant_message("Injecting [occupant] with [to_inject] units of [R.name].")
- log_message("Injecting [occupant] with [to_inject] units of [R.name].")
- //SG.reagents.trans_id_to(occupant,R.id,to_inject)
- SG.reagents.remove_reagent(R.id,to_inject)
- occupant.reagents.add_reagent(R.id,to_inject)
- update_equip_info()
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/sleeper/update_equip_info()
- if(..())
- send_byjax(chassis.occupant,"msleeper.browser","lossinfo",get_occupant_dam())
- send_byjax(chassis.occupant,"msleeper.browser","reagents",get_occupant_reagents())
- send_byjax(chassis.occupant,"msleeper.browser","injectwith",get_available_reagents())
- return 1
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/sleeper/verb/eject()
- set name = "Sleeper Eject"
- set category = "Exosuit Interface"
- set src = usr.loc
- set popup_menu = 0
- if(usr!=src.occupant || usr.stat == 2)
- return
- to_chat(usr,"Release sequence activated. This will take one minute.")
- sleep(600)
- if(!src || !usr || !occupant || (occupant != usr)) //Check if someone's released/replaced/bombed him already
- return
- go_out()//and release him from the eternal prison.
-
-/datum/global_iterator/mech_sleeper
-
-/datum/global_iterator/mech_sleeper/process(var/obj/item/mecha_parts/mecha_equipment/tool/sleeper/S)
- if(!S.chassis)
- S.set_ready_state(1)
- return stop()
- if(!S.chassis.has_charge(S.energy_drain))
- S.set_ready_state(1)
- S.log_message("Deactivated.")
- S.occupant_message("[src] deactivated - no power.")
- return stop()
- var/mob/living/carbon/M = S.occupant
- if(!M)
- return
- if(M.health > 0)
- M.adjustOxyLoss(-1)
- M.updatehealth()
- M.AdjustStunned(-4)
- M.AdjustWeakened(-4)
- M.AdjustStunned(-4)
- M.Paralyse(2)
- M.Weaken(2)
- M.Stun(2)
- if(M.reagents.get_reagent_amount("inaprovaline") < 5)
- M.reagents.add_reagent("inaprovaline", 5)
- S.chassis.use_power(S.energy_drain)
- S.update_equip_info()
- return
-
-
-/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun
- name = "syringe gun"
- desc = "Exosuit-mounted chem synthesizer with syringe gun. Reagents inside are held in stasis, so no reactions will occur. (Can be attached to: Medical Exosuits)"
- icon = 'icons/obj/gun.dmi'
- icon_state = "syringegun"
- var/list/syringes
- var/list/known_reagents
- var/list/processed_reagents
- var/max_syringes = 10
- var/max_volume = 75 //max reagent volume
- var/synth_speed = 5 //[num] reagent units per cycle
- energy_drain = 10
- var/mode = 0 //0 - fire syringe, 1 - analyze reagents.
- var/datum/global_iterator/mech_synth/synth
- range = MELEE|RANGED
- equip_cooldown = 10
- origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 4, TECH_MAGNET = 4, TECH_DATA = 3)
- required_type = list(/obj/mecha/medical)
-
- //This is a list of datums so as to allow id changes, and force compile errors if removed.
- var/static/list/allowed_reagents = list(
- //Med Reagents,
- /datum/reagent/inaprovaline,
- /datum/reagent/bicaridine,
- /datum/reagent/kelotane,
- /datum/reagent/dermaline,
- /datum/reagent/dylovene,
- /datum/reagent/dexalin,
- /datum/reagent/tricordrazine,
- /datum/reagent/paracetamol,
- /datum/reagent/tramadol,
- /datum/reagent/spaceacillin,
- //Dispenser Reagents,
- /datum/reagent/water,
- /datum/reagent/aluminum,
- /datum/reagent/carbon,
- /datum/reagent/chlorine,
- /datum/reagent/copper,
- /datum/reagent/ethanol,
- /datum/reagent/fluorine,
- /datum/reagent/hydrogen,
- /datum/reagent/iron,
- /datum/reagent/lithium,
- /datum/reagent/mercury,
- /datum/reagent/nitrogen,
- /datum/reagent/oxygen,
- /datum/reagent/phosphorus,
- /datum/reagent/potassium,
- /datum/reagent/radium,
- /datum/reagent/acid,
- /datum/reagent/silicon,
- /datum/reagent/sodium,
- /datum/reagent/sugar,
- /datum/reagent/sulfur,
- /datum/reagent/tungsten
- )
-
-/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/New()
- ..()
- flags |= NOREACT
- syringes = new
- known_reagents = list("inaprovaline"="Inaprovaline","anti_toxin"="Dylovene")
- processed_reagents = new
- create_reagents(max_volume)
- synth = new (list(src),0)
-
-/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/Initialize()
- . = ..()
- //Wow nice, firsties
- if(LAZYLEN(allowed_reagents) && !istext(allowed_reagents[1]))
- for(var/index = 1 to allowed_reagents.len)
- var/datum/reagent/path = allowed_reagents[index]
- allowed_reagents[index] = initial(path.id)
-
-/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/detach()
- synth.stop()
- return ..()
-
-/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/critfail()
- ..()
- flags &= ~NOREACT
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/get_equip_info()
- var/output = ..()
- if(output)
- return "[output] \[[mode? "Analyze" : "Launch"]\]
\[Syringes: [syringes.len]/[max_syringes] | Reagents: [reagents.total_volume]/[reagents.maximum_volume]\]
Reagents list"
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/action(atom/movable/target)
- if(!action_checks(target))
- return
- if(istype(target,/obj/item/weapon/reagent_containers/syringe))
- return load_syringe(target)
- if(istype(target,/obj/item/weapon/storage))//Loads syringes from boxes
- for(var/obj/item/weapon/reagent_containers/syringe/S in target.contents)
- load_syringe(S)
- return
- if(mode)
- return analyze_reagents(target)
- if(!syringes.len)
- occupant_message("No syringes loaded.")
- return
- if(reagents.total_volume<=0)
- occupant_message("No available reagents to load syringe with.")
- return
- set_ready_state(0)
- chassis.use_power(energy_drain)
- var/turf/trg = get_turf(target)
- var/obj/item/weapon/reagent_containers/syringe/S = syringes[1]
- S.forceMove(get_turf(chassis))
- reagents.trans_to_obj(S, min(S.volume, reagents.total_volume))
- syringes -= S
- S.icon = 'icons/obj/chemical.dmi'
- S.icon_state = "syringeproj"
- playsound(chassis, 'sound/items/syringeproj.ogg', 50, 1)
- log_message("Launched [S] from [src], targeting [target].")
- spawn(-1)
- src = null //if src is deleted, still process the syringe
- for(var/i=0, i<6, i++)
- if(!S)
- break
- if(step_towards(S,trg))
- var/list/mobs = new
- for(var/mob/living/carbon/M in S.loc)
- mobs += M
- var/mob/living/carbon/M = safepick(mobs)
- if(M)
- S.icon_state = initial(S.icon_state)
- S.icon = initial(S.icon)
- S.reagents.trans_to_mob(M, S.reagents.total_volume, CHEM_BLOOD)
- M.take_organ_damage(2)
- S.visible_message(" [M] was hit by the syringe!")
- break
- else if(S.loc == trg)
- S.icon_state = initial(S.icon_state)
- S.icon = initial(S.icon)
- S.update_icon()
- break
- else
- S.icon_state = initial(S.icon_state)
- S.icon = initial(S.icon)
- S.update_icon()
- break
- sleep(1)
- do_after_cooldown()
- return 1
-
-
-/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/Topic(href,href_list)
- ..()
- var/datum/topic_input/top_filter = new (href,href_list)
- if(top_filter.get("toggle_mode"))
- mode = !mode
- update_equip_info()
- return
- if(top_filter.get("select_reagents"))
- processed_reagents.len = 0
- var/m = 0
- var/message
- for(var/i=1 to known_reagents.len)
- if(m>=synth_speed)
- break
- var/reagent = top_filter.get("reagent_[i]")
- if(reagent && (reagent in known_reagents))
- message = "[m ? ", " : null][known_reagents[reagent]]"
- processed_reagents += reagent
- m++
- if(processed_reagents.len)
- message += " added to production"
- synth.start()
- occupant_message(message)
- occupant_message("Reagent processing started.")
- log_message("Reagent processing started.")
- return
- if(top_filter.get("show_reagents"))
- chassis.occupant << browse(get_reagents_page(),"window=msyringegun")
- if(top_filter.get("purge_reagent"))
- var/reagent = top_filter.get("purge_reagent")
- if(reagent)
- reagents.del_reagent(reagent)
- return
- if(top_filter.get("purge_all"))
- reagents.clear_reagents()
- return
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_reagents_page()
- var/output = {"
-
- Reagent Synthesizer
-
-
-
-
- Current reagents:
-
- [get_current_reagents()]
-
- Reagents production:
-
- [get_reagents_form()]
-
-
-
- "}
- return output
-
-/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_reagents_form()
- var/r_list = get_reagents_list()
- var/inputs
- if(r_list)
- inputs += ""
- inputs += ""
- inputs += ""
- var/output = {"
- [r_list? "Only the first [synth_speed] selected reagent\s will be added to production" : null]
- "}
- return output
-
-/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_reagents_list()
- var/output
- for(var/i=1 to known_reagents.len)
- var/reagent_id = known_reagents[i]
- output += {" [known_reagents[reagent_id]]
"}
- return output
-
-/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_current_reagents()
- var/output
- for(var/datum/reagent/R in reagents.reagent_list)
- if(R.volume > 0)
- output += "[R]: [round(R.volume,0.001)] - Purge Reagent
"
- if(output)
- output += "Total: [round(reagents.total_volume,0.001)]/[reagents.maximum_volume] - Purge All"
- return output || "None"
-
-/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/load_syringe(obj/item/weapon/reagent_containers/syringe/S)
- if(syringes.len= 2)
- occupant_message("The syringe is too far away.")
- return 0
- for(var/obj/structure/D in S.loc)//Basic level check for structures in the way (Like grilles and windows)
- if(!(D.CanPass(S,src.loc)))
- occupant_message("Unable to load syringe.")
- return 0
- for(var/obj/machinery/door/D in S.loc)//Checks for doors
- if(!(D.CanPass(S,src.loc)))
- occupant_message("Unable to load syringe.")
- return 0
- S.reagents.trans_to_obj(src, S.reagents.total_volume)
- S.forceMove(src)
- syringes += S
- occupant_message("Syringe loaded.")
- update_equip_info()
- return 1
- occupant_message("The [src] syringe chamber is full.")
- return 0
-
-/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/analyze_reagents(atom/A)
- if(get_dist(src,A) >= 4)
- occupant_message("The object is too far away.")
- return 0
- if(!A.reagents || istype(A,/mob))
- occupant_message("No reagent info gained from [A].")
- return 0
- occupant_message("Analyzing reagents...")
- //VOREStation Block Edit - Start
- for(var/datum/reagent/R in A.reagents.reagent_list)
- if(R.id in known_reagents)
- occupant_message("Reagent \"[R.name]\" already present in database, skipping.")
- else if(R.reagent_state == 2 && add_known_reagent(R.id,R.name))
- occupant_message("Reagent analyzed, identified as [R.name] and added to database.")
- send_byjax(chassis.occupant,"msyringegun.browser","reagents_form",get_reagents_form())
- else
- occupant_message("Reagent \"[R.name]\" unable to be scanned, skipping.")
- //VOREstation Block Edit - End
- occupant_message("Analysis complete.")
- return 1
-
-/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/add_known_reagent(r_id,r_name)
- set_ready_state(0)
- do_after_cooldown()
- if(!(r_id in known_reagents) && (r_id in allowed_reagents))
- known_reagents += r_id
- known_reagents[r_id] = r_name
- return 1
- return 0
-
-
-/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/update_equip_info()
- if(..())
- send_byjax(chassis.occupant,"msyringegun.browser","reagents",get_current_reagents())
- send_byjax(chassis.occupant,"msyringegun.browser","reagents_form",get_reagents_form())
- return 1
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/on_reagent_change()
- ..()
- update_equip_info()
- return
-
-/datum/global_iterator/mech_synth
- delay = 100
-
-/datum/global_iterator/mech_synth/process(var/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/S)
- if(!S.chassis)
- return stop()
- var/energy_drain = S.energy_drain*10
- if(!S.processed_reagents.len || S.reagents.total_volume >= S.reagents.maximum_volume || !S.chassis.has_charge(energy_drain))
- S.occupant_message("Reagent processing stopped.")
- S.log_message("Reagent processing stopped.")
- return stop()
- var/amount = S.synth_speed / S.processed_reagents.len
- for(var/reagent in S.processed_reagents)
- S.reagents.add_reagent(reagent,amount)
- S.chassis.use_power(energy_drain)
- return 1
-
-/obj/item/mecha_parts/mecha_equipment/crisis_drone
- name = "crisis dronebay"
- desc = "A small shoulder-mounted dronebay containing a rapid response drone capable of moderately stabilizing a patient near the exosuit."
- icon_state = "mecha_dronebay"
- origin_tech = list(TECH_PHORON = 3, TECH_MAGNET = 6, TECH_BIO = 5, TECH_DATA = 4)
- range = MELEE|RANGED
- equip_cooldown = 3 SECONDS
- required_type = list(/obj/mecha/medical)
-
- var/droid_state = "med_droid"
-
- var/beam_state = "medbeam"
-
- var/enabled = FALSE
-
- var/icon/drone_overlay
-
- var/max_distance = 3
-
- var/damcap = 60
- var/heal_dead = FALSE // Does this device heal the dead?
-
- var/brute_heal = 0.5 // Amount of bruteloss healed.
- var/burn_heal = 0.5 // Amount of fireloss healed.
- var/tox_heal = 0.5 // Amount of toxloss healed.
- var/oxy_heal = 1 // Amount of oxyloss healed.
- var/rad_heal = 0 // Amount of radiation healed.
- var/clone_heal = 0 // Amount of cloneloss healed.
- var/hal_heal = 0.2 // Amount of halloss healed.
- var/bone_heal = 0 // Percent chance it will heal a broken bone. this does not mean 'make it not instantly re-break'.
-
- var/mob/living/Target = null
- var/datum/beam/MyBeam = null
-
- equip_type = EQUIP_HULL
-
-/obj/item/mecha_parts/mecha_equipment/crisis_drone/Initialize()
- ..()
- drone_overlay = new(src.icon, icon_state = droid_state)
-
-/obj/item/mecha_parts/mecha_equipment/crisis_drone/Destroy()
- STOP_PROCESSING(SSobj, src)
- ..()
-
-/obj/item/mecha_parts/mecha_equipment/crisis_drone/attach(obj/mecha/M as obj)
- . = ..(M)
- if(chassis)
- START_PROCESSING(SSobj, src)
-
-/obj/item/mecha_parts/mecha_equipment/crisis_drone/detach(atom/moveto=null)
- shut_down()
- . = ..(moveto)
- STOP_PROCESSING(SSobj, src)
-
-/obj/item/mecha_parts/mecha_equipment/crisis_drone/critfail()
- . = ..()
- STOP_PROCESSING(SSobj, src)
- shut_down()
- if(chassis && chassis.occupant)
- to_chat(chassis.occupant, "\The [chassis] shudders as something jams!")
- log_message("[src.name] has malfunctioned. Maintenance required.")
-
-/obj/item/mecha_parts/mecha_equipment/crisis_drone/process() // Will continually try to find the nearest person above the threshold that is a valid target, and try to heal them.
- if(chassis && enabled && chassis.has_charge(energy_drain) && (chassis.occupant || enable_special))
- var/mob/living/Targ = Target
- var/TargDamage = 0
-
- if(!valid_target(Target))
- Target = null
-
- if(Target)
- TargDamage = (Targ.getOxyLoss() + Targ.getFireLoss() + Targ.getBruteLoss() + Targ.getToxLoss())
-
- for(var/mob/living/Potential in viewers(max_distance, chassis))
- if(!valid_target(Potential))
- continue
-
- var/tallydamage = 0
- if(oxy_heal)
- tallydamage += Potential.getOxyLoss()
- if(burn_heal)
- tallydamage += Potential.getFireLoss()
- if(brute_heal)
- tallydamage += Potential.getBruteLoss()
- if(tox_heal)
- tallydamage += Potential.getToxLoss()
- if(hal_heal)
- tallydamage += Potential.getHalLoss()
- if(clone_heal)
- tallydamage += Potential.getCloneLoss()
- if(rad_heal)
- tallydamage += Potential.radiation / 2
-
- if(tallydamage > TargDamage)
- Target = Potential
-
- if(MyBeam && !valid_target(MyBeam.target))
- QDEL_NULL(MyBeam)
-
- if(Target)
- if(MyBeam && MyBeam.target != Target)
- QDEL_NULL(MyBeam)
-
- if(valid_target(Target))
- if(!MyBeam)
- MyBeam = chassis.Beam(Target,icon='icons/effects/beam.dmi',icon_state=beam_state,time=3 SECONDS,maxdistance=max_distance,beam_type = /obj/effect/ebeam,beam_sleep_time=2)
- heal_target(Target)
-
- else
- shut_down()
-
-/obj/item/mecha_parts/mecha_equipment/crisis_drone/proc/valid_target(var/mob/living/L)
- . = TRUE
-
- if(!L || !istype(L))
- return FALSE
-
- if(get_dist(L, src) > max_distance)
- return FALSE
-
- if(!(L in viewers(max_distance, chassis)))
- return FALSE
-
- if(!unique_patient_checks(L))
- return FALSE
-
- if(L.stat == DEAD && !heal_dead)
- return FALSE
-
- var/tallydamage = 0
- if(oxy_heal)
- tallydamage += L.getOxyLoss()
- if(burn_heal)
- tallydamage += L.getFireLoss()
- if(brute_heal)
- tallydamage += L.getBruteLoss()
- if(tox_heal)
- tallydamage += L.getToxLoss()
- if(hal_heal)
- tallydamage += L.getHalLoss()
- if(clone_heal)
- tallydamage += L.getCloneLoss()
- if(rad_heal)
- tallydamage += L.radiation / 2
-
- if(tallydamage < damcap)
- return FALSE
-
-/obj/item/mecha_parts/mecha_equipment/crisis_drone/proc/shut_down()
- if(enabled)
- chassis.visible_message("\The [chassis]'s [src] buzzes as its drone returns to port.")
- toggle_drone()
- if(!isnull(Target))
- Target = null
- if(MyBeam)
- QDEL_NULL(MyBeam)
-
-/obj/item/mecha_parts/mecha_equipment/crisis_drone/proc/unique_patient_checks(var/mob/living/L) // Anything special for subtypes. Does it only work on Robots? Fleshies? A species?
- . = TRUE
-
-/obj/item/mecha_parts/mecha_equipment/crisis_drone/proc/heal_target(var/mob/living/L) // We've done all our special checks, just get to fixing damage.
- chassis.use_power(energy_drain)
- if(istype(L))
- L.adjustBruteLoss(brute_heal * -1)
- L.adjustFireLoss(burn_heal * -1)
- L.adjustToxLoss(tox_heal * -1)
- L.adjustOxyLoss(oxy_heal * -1)
- L.adjustCloneLoss(clone_heal * -1)
- L.adjustHalLoss(hal_heal * -1)
- L.radiation = max(0, L.radiation - rad_heal)
-
- if(ishuman(L) && bone_heal)
- var/mob/living/carbon/human/H = L
-
- if(H.bad_external_organs.len)
- for(var/obj/item/organ/external/E in H.bad_external_organs)
- if(prob(bone_heal))
- E.status &= ~ORGAN_BROKEN
-
-/obj/item/mecha_parts/mecha_equipment/crisis_drone/proc/toggle_drone()
- ..()
- if(chassis)
- enabled = !enabled
- if(enabled)
- set_ready_state(0)
- log_message("Activated.")
- chassis.overlays += drone_overlay
- else
- set_ready_state(1)
- log_message("Deactivated.")
- chassis.overlays -= drone_overlay
-
-/obj/item/mecha_parts/mecha_equipment/crisis_drone/Topic(href, href_list)
- ..()
- if(href_list["toggle_drone"])
- toggle_drone()
- return
-
-/obj/item/mecha_parts/mecha_equipment/crisis_drone/get_equip_info()
- if(!chassis) return
- return "* [src.name] - [enabled?"Dea":"A"]ctivate"
-
-/obj/item/mecha_parts/mecha_equipment/crisis_drone/rad
- name = "hazmat dronebay"
- desc = "A small shoulder-mounted dronebay containing a rapid response drone capable of purging a patient near the exosuit of radiation damage."
- icon_state = "mecha_dronebay_rad"
-
- droid_state = "rad_drone"
- beam_state = "g_beam"
-
- tox_heal = 0.5
- rad_heal = 5
- clone_heal = 0.2
- hal_heal = 0.2
-
-/obj/item/mecha_parts/mecha_equipment/tool/powertool/medanalyzer
- name = "mounted humanoid scanner"
- desc = "An exosuit-mounted scanning device."
- icon_state = "mecha_analyzer_health"
- origin_tech = list(TECH_MATERIAL = 5, TECH_MAGNET = 5, TECH_BIO = 5)
- equip_cooldown = 5 SECONDS
- energy_drain = 100
- range = MELEE
- equip_type = EQUIP_UTILITY
- ready_sound = 'sound/weapons/flash.ogg'
- required_type = list(/obj/mecha/medical)
-
- tooltype = /obj/item/device/healthanalyzer/advanced
+/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun
+ name = "syringe gun"
+ desc = "Exosuit-mounted chem synthesizer with syringe gun. Reagents inside are held in stasis, so no reactions will occur. (Can be attached to: Medical Exosuits)"
+ icon = 'icons/obj/gun.dmi'
+ icon_state = "syringegun"
+ var/list/syringes
+ var/list/known_reagents
+ var/list/processed_reagents
+ var/max_syringes = 10
+ var/max_volume = 75 //max reagent volume
+ var/synth_speed = 5 //[num] reagent units per cycle
+ energy_drain = 10
+ var/mode = 0 //0 - fire syringe, 1 - analyze reagents.
+ var/datum/global_iterator/mech_synth/synth
+ range = MELEE|RANGED
+ equip_cooldown = 10
+ origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 4, TECH_MAGNET = 4, TECH_DATA = 3)
+ required_type = list(/obj/mecha/medical)
+
+/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/New()
+ ..()
+ flags |= NOREACT
+ syringes = new
+ known_reagents = list("inaprovaline"="Inaprovaline","anti_toxin"="Dylovene")
+ processed_reagents = new
+ create_reagents(max_volume)
+ synth = new (list(src),0)
+
+/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/detach()
+ synth.stop()
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/critfail()
+ ..()
+ flags &= ~NOREACT
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/get_equip_info()
+ var/output = ..()
+ if(output)
+ return "[output] \[[mode? "Analyze" : "Launch"]\]
\[Syringes: [syringes.len]/[max_syringes] | Reagents: [reagents.total_volume]/[reagents.maximum_volume]\]
Reagents list"
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/action(atom/movable/target)
+ if(!action_checks(target))
+ return
+ if(istype(target,/obj/item/weapon/reagent_containers/syringe))
+ return load_syringe(target)
+ if(istype(target,/obj/item/weapon/storage))//Loads syringes from boxes
+ for(var/obj/item/weapon/reagent_containers/syringe/S in target.contents)
+ load_syringe(S)
+ return
+ if(mode)
+ return analyze_reagents(target)
+ if(!syringes.len)
+ occupant_message("No syringes loaded.")
+ return
+ if(reagents.total_volume<=0)
+ occupant_message("No available reagents to load syringe with.")
+ return
+ set_ready_state(0)
+ chassis.use_power(energy_drain)
+ var/turf/trg = get_turf(target)
+ var/obj/item/weapon/reagent_containers/syringe/S = syringes[1]
+ S.forceMove(get_turf(chassis))
+ reagents.trans_to_obj(S, min(S.volume, reagents.total_volume))
+ syringes -= S
+ S.icon = 'icons/obj/chemical.dmi'
+ S.icon_state = "syringeproj"
+ playsound(chassis, 'sound/items/syringeproj.ogg', 50, 1)
+ log_message("Launched [S] from [src], targeting [target].")
+ spawn(-1)
+ src = null //if src is deleted, still process the syringe
+ for(var/i=0, i<6, i++)
+ if(!S)
+ break
+ if(step_towards(S,trg))
+ var/list/mobs = new
+ for(var/mob/living/carbon/M in S.loc)
+ mobs += M
+ var/mob/living/carbon/M = safepick(mobs)
+ if(M)
+ S.icon_state = initial(S.icon_state)
+ S.icon = initial(S.icon)
+ S.reagents.trans_to_mob(M, S.reagents.total_volume, CHEM_BLOOD)
+ M.take_organ_damage(2)
+ S.visible_message(" [M] was hit by the syringe!")
+ break
+ else if(S.loc == trg)
+ S.icon_state = initial(S.icon_state)
+ S.icon = initial(S.icon)
+ S.update_icon()
+ break
+ else
+ S.icon_state = initial(S.icon_state)
+ S.icon = initial(S.icon)
+ S.update_icon()
+ break
+ sleep(1)
+ do_after_cooldown()
+ return 1
+
+
+/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/Topic(href,href_list)
+ ..()
+ var/datum/topic_input/top_filter = new (href,href_list)
+ if(top_filter.get("toggle_mode"))
+ mode = !mode
+ update_equip_info()
+ return
+ if(top_filter.get("select_reagents"))
+ processed_reagents.len = 0
+ var/m = 0
+ var/message
+ for(var/i=1 to known_reagents.len)
+ if(m>=synth_speed)
+ break
+ var/reagent = top_filter.get("reagent_[i]")
+ if(reagent && (reagent in known_reagents))
+ message = "[m ? ", " : null][known_reagents[reagent]]"
+ processed_reagents += reagent
+ m++
+ if(processed_reagents.len)
+ message += " added to production"
+ synth.start()
+ occupant_message(message)
+ occupant_message("Reagent processing started.")
+ log_message("Reagent processing started.")
+ return
+ if(top_filter.get("show_reagents"))
+ chassis.occupant << browse(get_reagents_page(),"window=msyringegun")
+ if(top_filter.get("purge_reagent"))
+ var/reagent = top_filter.get("purge_reagent")
+ if(reagent)
+ reagents.del_reagent(reagent)
+ return
+ if(top_filter.get("purge_all"))
+ reagents.clear_reagents()
+ return
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_reagents_page()
+ var/output = {"
+
+ Reagent Synthesizer
+
+
+
+
+ Current reagents:
+
+ [get_current_reagents()]
+
+ Reagents production:
+
+ [get_reagents_form()]
+
+
+
+ "}
+ return output
+
+/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_reagents_form()
+ var/r_list = get_reagents_list()
+ var/inputs
+ if(r_list)
+ inputs += ""
+ inputs += ""
+ inputs += ""
+ var/output = {"
+ [r_list? "Only the first [synth_speed] selected reagent\s will be added to production" : null]
+ "}
+ return output
+
+/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_reagents_list()
+ var/output
+ for(var/i=1 to known_reagents.len)
+ var/reagent_id = known_reagents[i]
+ output += {" [known_reagents[reagent_id]]
"}
+ return output
+
+/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_current_reagents()
+ var/output
+ for(var/datum/reagent/R in reagents.reagent_list)
+ if(R.volume > 0)
+ output += "[R]: [round(R.volume,0.001)] - Purge Reagent
"
+ if(output)
+ output += "Total: [round(reagents.total_volume,0.001)]/[reagents.maximum_volume] - Purge All"
+ return output || "None"
+
+/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/load_syringe(obj/item/weapon/reagent_containers/syringe/S)
+ if(syringes.len= 2)
+ occupant_message("The syringe is too far away.")
+ return 0
+ for(var/obj/structure/D in S.loc)//Basic level check for structures in the way (Like grilles and windows)
+ if(!(D.CanPass(S,src.loc)))
+ occupant_message("Unable to load syringe.")
+ return 0
+ for(var/obj/machinery/door/D in S.loc)//Checks for doors
+ if(!(D.CanPass(S,src.loc)))
+ occupant_message("Unable to load syringe.")
+ return 0
+ S.reagents.trans_to_obj(src, S.reagents.total_volume)
+ S.forceMove(src)
+ syringes += S
+ occupant_message("Syringe loaded.")
+ update_equip_info()
+ return 1
+ occupant_message("The [src] syringe chamber is full.")
+ return 0
+
+/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/analyze_reagents(atom/A)
+ if(get_dist(src,A) >= 4)
+ occupant_message("The object is too far away.")
+ return 0
+ if(!A.reagents || istype(A,/mob))
+ occupant_message("No reagent info gained from [A].")
+ return 0
+ occupant_message("Analyzing reagents...")
+ //VOREStation Block Edit - Start
+ for(var/datum/reagent/R in A.reagents.reagent_list)
+ if(R.id in known_reagents)
+ occupant_message("Reagent \"[R.name]\" already present in database, skipping.")
+ else if(R.reagent_state == 2 && add_known_reagent(R.id,R.name))
+ occupant_message("Reagent analyzed, identified as [R.name] and added to database.")
+ send_byjax(chassis.occupant,"msyringegun.browser","reagents_form",get_reagents_form())
+ else
+ occupant_message("Reagent \"[R.name]\" unable to be scanned, skipping.")
+ //VOREstation Block Edit - End
+ occupant_message("Analysis complete.")
+ return 1
+
+/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/add_known_reagent(r_id,r_name)
+ set_ready_state(0)
+ do_after_cooldown()
+ if(!(r_id in known_reagents))
+ known_reagents += r_id
+ known_reagents[r_id] = r_name
+ return 1
+ return 0
+
+
+/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/update_equip_info()
+ if(..())
+ send_byjax(chassis.occupant,"msyringegun.browser","reagents",get_current_reagents())
+ send_byjax(chassis.occupant,"msyringegun.browser","reagents_form",get_reagents_form())
+ return 1
+ return
+
+/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/on_reagent_change()
+ ..()
+ update_equip_info()
+ return
+
+/datum/global_iterator/mech_synth
+ delay = 100
+
+/datum/global_iterator/mech_synth/process(var/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/S)
+ if(!S.chassis)
+ return stop()
+ var/energy_drain = S.energy_drain*10
+ if(!S.processed_reagents.len || S.reagents.total_volume >= S.reagents.maximum_volume || !S.chassis.has_charge(energy_drain))
+ S.occupant_message("Reagent processing stopped.")
+ S.log_message("Reagent processing stopped.")
+ return stop()
+ var/amount = S.synth_speed / S.processed_reagents.len
+ for(var/reagent in S.processed_reagents)
+ S.reagents.add_reagent(reagent,amount)
+ S.chassis.use_power(energy_drain)
+ return 1
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone
+ name = "crisis dronebay"
+ desc = "A small shoulder-mounted dronebay containing a rapid response drone capable of moderately stabilizing a patient near the exosuit."
+ icon_state = "mecha_dronebay"
+ origin_tech = list(TECH_PHORON = 3, TECH_MAGNET = 6, TECH_BIO = 5, TECH_DATA = 4)
+ range = MELEE|RANGED
+ equip_cooldown = 3 SECONDS
+ required_type = list(/obj/mecha/medical)
+
+ var/droid_state = "med_droid"
+
+ var/beam_state = "medbeam"
+
+ var/enabled = FALSE
+
+ var/icon/drone_overlay
+
+ var/max_distance = 3
+
+ var/damcap = 60
+ var/heal_dead = FALSE // Does this device heal the dead?
+
+ var/brute_heal = 0.5 // Amount of bruteloss healed.
+ var/burn_heal = 0.5 // Amount of fireloss healed.
+ var/tox_heal = 0.5 // Amount of toxloss healed.
+ var/oxy_heal = 1 // Amount of oxyloss healed.
+ var/rad_heal = 0 // Amount of radiation healed.
+ var/clone_heal = 0 // Amount of cloneloss healed.
+ var/hal_heal = 0.2 // Amount of halloss healed.
+ var/bone_heal = 0 // Percent chance it will heal a broken bone. this does not mean 'make it not instantly re-break'.
+
+ var/mob/living/Target = null
+ var/datum/beam/MyBeam = null
+
+ equip_type = EQUIP_HULL
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/Initialize()
+ ..()
+ drone_overlay = new(src.icon, icon_state = droid_state)
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ ..()
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/attach(obj/mecha/M as obj)
+ . = ..(M)
+ if(chassis)
+ START_PROCESSING(SSobj, src)
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/detach(atom/moveto=null)
+ shut_down()
+ . = ..(moveto)
+ STOP_PROCESSING(SSobj, src)
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/critfail()
+ . = ..()
+ STOP_PROCESSING(SSobj, src)
+ shut_down()
+ if(chassis && chassis.occupant)
+ to_chat(chassis.occupant, "\The [chassis] shudders as something jams!")
+ log_message("[src.name] has malfunctioned. Maintenance required.")
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/process() // Will continually try to find the nearest person above the threshold that is a valid target, and try to heal them.
+ if(chassis && enabled && chassis.has_charge(energy_drain) && (chassis.occupant || enable_special))
+ var/mob/living/Targ = Target
+ var/TargDamage = 0
+
+ if(!valid_target(Target))
+ Target = null
+
+ if(Target)
+ TargDamage = (Targ.getOxyLoss() + Targ.getFireLoss() + Targ.getBruteLoss() + Targ.getToxLoss())
+
+ for(var/mob/living/Potential in viewers(max_distance, chassis))
+ if(!valid_target(Potential))
+ continue
+
+ var/tallydamage = 0
+ if(oxy_heal)
+ tallydamage += Potential.getOxyLoss()
+ if(burn_heal)
+ tallydamage += Potential.getFireLoss()
+ if(brute_heal)
+ tallydamage += Potential.getBruteLoss()
+ if(tox_heal)
+ tallydamage += Potential.getToxLoss()
+ if(hal_heal)
+ tallydamage += Potential.getHalLoss()
+ if(clone_heal)
+ tallydamage += Potential.getCloneLoss()
+ if(rad_heal)
+ tallydamage += Potential.radiation / 2
+
+ if(tallydamage > TargDamage)
+ Target = Potential
+
+ if(MyBeam && !valid_target(MyBeam.target))
+ QDEL_NULL(MyBeam)
+
+ if(Target)
+ if(MyBeam && MyBeam.target != Target)
+ QDEL_NULL(MyBeam)
+
+ if(valid_target(Target))
+ if(!MyBeam)
+ MyBeam = chassis.Beam(Target,icon='icons/effects/beam.dmi',icon_state=beam_state,time=3 SECONDS,maxdistance=max_distance,beam_type = /obj/effect/ebeam,beam_sleep_time=2)
+ heal_target(Target)
+
+ else
+ shut_down()
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/proc/valid_target(var/mob/living/L)
+ . = TRUE
+
+ if(!L || !istype(L))
+ return FALSE
+
+ if(get_dist(L, src) > max_distance)
+ return FALSE
+
+ if(!(L in viewers(max_distance, chassis)))
+ return FALSE
+
+ if(!unique_patient_checks(L))
+ return FALSE
+
+ if(L.stat == DEAD && !heal_dead)
+ return FALSE
+
+ var/tallydamage = 0
+ if(oxy_heal)
+ tallydamage += L.getOxyLoss()
+ if(burn_heal)
+ tallydamage += L.getFireLoss()
+ if(brute_heal)
+ tallydamage += L.getBruteLoss()
+ if(tox_heal)
+ tallydamage += L.getToxLoss()
+ if(hal_heal)
+ tallydamage += L.getHalLoss()
+ if(clone_heal)
+ tallydamage += L.getCloneLoss()
+ if(rad_heal)
+ tallydamage += L.radiation / 2
+
+ if(tallydamage < damcap)
+ return FALSE
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/proc/shut_down()
+ if(enabled)
+ chassis.visible_message("\The [chassis]'s [src] buzzes as its drone returns to port.")
+ toggle_drone()
+ if(!isnull(Target))
+ Target = null
+ if(MyBeam)
+ QDEL_NULL(MyBeam)
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/proc/unique_patient_checks(var/mob/living/L) // Anything special for subtypes. Does it only work on Robots? Fleshies? A species?
+ . = TRUE
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/proc/heal_target(var/mob/living/L) // We've done all our special checks, just get to fixing damage.
+ chassis.use_power(energy_drain)
+ if(istype(L))
+ L.adjustBruteLoss(brute_heal * -1)
+ L.adjustFireLoss(burn_heal * -1)
+ L.adjustToxLoss(tox_heal * -1)
+ L.adjustOxyLoss(oxy_heal * -1)
+ L.adjustCloneLoss(clone_heal * -1)
+ L.adjustHalLoss(hal_heal * -1)
+ L.radiation = max(0, L.radiation - rad_heal)
+
+ if(ishuman(L) && bone_heal)
+ var/mob/living/carbon/human/H = L
+
+ if(H.bad_external_organs.len)
+ for(var/obj/item/organ/external/E in H.bad_external_organs)
+ if(prob(bone_heal))
+ E.status &= ~ORGAN_BROKEN
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/proc/toggle_drone()
+ ..()
+ if(chassis)
+ enabled = !enabled
+ if(enabled)
+ set_ready_state(0)
+ log_message("Activated.")
+ chassis.overlays += drone_overlay
+ else
+ set_ready_state(1)
+ log_message("Deactivated.")
+ chassis.overlays -= drone_overlay
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/Topic(href, href_list)
+ ..()
+ if(href_list["toggle_drone"])
+ toggle_drone()
+ return
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/get_equip_info()
+ if(!chassis) return
+ return "* [src.name] - [enabled?"Dea":"A"]ctivate"
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/rad
+ name = "hazmat dronebay"
+ desc = "A small shoulder-mounted dronebay containing a rapid response drone capable of purging a patient near the exosuit of radiation damage."
+ icon_state = "mecha_dronebay_rad"
+
+ droid_state = "rad_drone"
+ beam_state = "g_beam"
+
+ tox_heal = 0.5
+ rad_heal = 5
+ clone_heal = 0.2
+ hal_heal = 0.2
+
+/obj/item/mecha_parts/mecha_equipment/tool/powertool/medanalyzer
+ name = "mounted humanoid scanner"
+ desc = "An exosuit-mounted scanning device."
+ icon_state = "mecha_analyzer_health"
+ origin_tech = list(TECH_MATERIAL = 5, TECH_MAGNET = 5, TECH_BIO = 5)
+ equip_cooldown = 5 SECONDS
+ energy_drain = 100
+ range = MELEE
+ equip_type = EQUIP_UTILITY
+ ready_sound = 'sound/weapons/flash.ogg'
+ required_type = list(/obj/mecha/medical)
+
+ tooltype = /obj/item/device/healthanalyzer/advanced
diff --git a/code/game/mecha/equipment/tools/teleporter.dm b/code/game/mecha/equipment/tools/teleporter.dm
new file mode 100644
index 00000000000..b77b1c3fdc2
--- /dev/null
+++ b/code/game/mecha/equipment/tools/teleporter.dm
@@ -0,0 +1,20 @@
+/obj/item/mecha_parts/mecha_equipment/teleporter
+ name = "teleporter"
+ desc = "An exosuit module that allows exosuits to teleport to any position in view."
+ icon_state = "mecha_teleport"
+ origin_tech = list(TECH_BLUESPACE = 10)
+ equip_cooldown = 150
+ energy_drain = 1000
+ range = RANGED
+
+ equip_type = EQUIP_SPECIAL
+
+/obj/item/mecha_parts/mecha_equipment/teleporter/action(atom/target)
+ if(!action_checks(target) || src.loc.z == 2) return
+ var/turf/T = get_turf(target)
+ if(T)
+ set_ready_state(0)
+ chassis.use_power(energy_drain)
+ do_teleport(chassis, T, 4)
+ do_after_cooldown()
+ return
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm
index 73f7356ade6..01aeca691df 100644
--- a/code/game/mecha/equipment/tools/tools.dm
+++ b/code/game/mecha/equipment/tools/tools.dm
@@ -1,1668 +1,2 @@
/obj/item/mecha_parts/mecha_equipment/tool
- equip_type = EQUIP_UTILITY
-
-/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp
- name = "hydraulic clamp"
- icon_state = "mecha_clamp"
- equip_cooldown = 15
- energy_drain = 10
- var/dam_force = 20
- var/obj/mecha/working/ripley/cargo_holder
- required_type = list(/obj/mecha/working)
- ready_sound = 'sound/mecha/gasdisconnected.ogg'
-
-/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp/attach(obj/mecha/M as obj)
- ..()
- cargo_holder = M
-
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp/action(atom/target)
- if(!action_checks(target)) return
- if(!cargo_holder) return
-
- //loading
- if(istype(target,/obj))
- var/obj/O = target
- if(O.has_buckled_mobs())
- return
- if(locate(/mob/living) in O)
- occupant_message("You can't load living things into the cargo compartment.")
- return
- if(O.anchored)
- if(enable_special)
- if(istype(O, /obj/machinery/door/firedoor)) // I love doors.
- var/obj/machinery/door/firedoor/FD = O
- if(FD.blocked)
- FD.visible_message("\The [chassis] begins prying on \the [FD]!")
- if(do_after(chassis.occupant,10 SECONDS,FD))
- playsound(FD.loc, 'sound/machines/airlock_creaking.ogg', 100, 1)
- FD.blocked = 0
- FD.update_icon()
- FD.open(1)
- FD.visible_message("\The [chassis] tears \the [FD] open!")
- else if(FD.density)
- FD.visible_message("\The [chassis] begins forcing \the [FD] open!")
- if(do_after(chassis.occupant, 5 SECONDS,FD))
- playsound(FD.loc, 'sound/machines/airlock_creaking.ogg', 100, 1)
- FD.visible_message("\The [chassis] forces \the [FD] open!")
- FD.open(1)
- else
- FD.visible_message("\The [chassis] forces \the [FD] closed!")
- FD.close(1)
- else if(istype(O, /obj/machinery/door/airlock)) // D o o r s.
- var/obj/machinery/door/airlock/AD = O
- if(AD.locked)
- occupant_message("The airlock's bolts prevent it from being forced.")
- else if(!AD.operating)
- if(AD.welded)
- AD.visible_message("\The [chassis] begins prying on \the [AD]!")
- if(do_after(chassis.occupant, 15 SECONDS,AD) && chassis.Adjacent(AD))
- AD.welded = FALSE
- AD.update_icon()
- playsound(AD.loc, 'sound/machines/airlock_creaking.ogg', 100, 1)
- AD.visible_message("\The [chassis] tears \the [AD] open!")
- if(!AD.welded)
- if(density)
- spawn(0)
- AD.open(1)
- else
- spawn(0)
- AD.close(1)
- return
- else
- occupant_message("[target] is firmly secured.")
- return
- if(cargo_holder.cargo.len >= cargo_holder.cargo_capacity)
- occupant_message("Not enough room in cargo compartment.")
- return
-
- occupant_message("You lift [target] and start to load it into cargo compartment.")
- chassis.visible_message("[chassis] lifts [target] and starts to load it into cargo compartment.")
- set_ready_state(0)
- chassis.use_power(energy_drain)
- O.anchored = 1
- var/T = chassis.loc
- if(do_after_cooldown(target))
- if(T == chassis.loc && src == chassis.selected)
- cargo_holder.cargo += O
- O.loc = chassis
- O.anchored = 0
- occupant_message("[target] succesfully loaded.")
- log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]")
- else
- occupant_message("You must hold still while handling objects.")
- O.anchored = initial(O.anchored)
-
- //attacking
- else if(istype(target,/mob/living))
- var/mob/living/M = target
- if(M.stat>1) return
- if(chassis.occupant.a_intent == I_HURT || istype(chassis.occupant,/mob/living/carbon/brain)) //No tactile feedback for brains
- M.take_overall_damage(dam_force)
- M.adjustOxyLoss(round(dam_force/2))
- M.updatehealth()
- occupant_message("You squeeze [target] with [src.name]. Something cracks.")
- playsound(src.loc, "fracture", 5, 1, -2) //CRACK
- chassis.visible_message("[chassis] squeezes [target].")
- else if(chassis.occupant.a_intent == I_DISARM && enable_special)
- playsound(src.loc, 'sound/mecha/hydraulic.ogg', 10, 1, -2)
- M.take_overall_damage(dam_force/2)
- M.adjustOxyLoss(round(dam_force/3))
- M.updatehealth()
- occupant_message("You slam [target] with [src.name]. Something cracks.")
- playsound(src.loc, "fracture", 3, 1, -2) //CRACK 2
- chassis.visible_message("[chassis] slams [target].")
- M.throw_at(get_step(M,get_dir(src, M)), 14, 1.5, chassis)
- else
- step_away(M,chassis)
- occupant_message("You push [target] out of the way.")
- chassis.visible_message("[chassis] pushes [target] out of the way.")
- set_ready_state(0)
- chassis.use_power(energy_drain)
- do_after_cooldown()
- return 1
-
-/obj/item/mecha_parts/mecha_equipment/tool/drill
- name = "drill"
- desc = "This is the drill that'll pierce the heavens!"
- icon_state = "mecha_drill"
- equip_cooldown = 30
- energy_drain = 10
- force = 15
- required_type = list(/obj/mecha/working/ripley)
-
-/obj/item/mecha_parts/mecha_equipment/tool/drill/action(atom/target)
- if(!action_checks(target)) return
- if(isobj(target))
- var/obj/target_obj = target
- if(!target_obj.vars.Find("unacidable") || target_obj.unacidable) return
- set_ready_state(0)
- chassis.use_power(energy_drain)
- chassis.visible_message("[chassis] starts to drill [target]", "You hear the drill.")
- occupant_message("You start to drill [target]")
- var/T = chassis.loc
- var/C = target.loc //why are these backwards? we may never know -Pete
- if(do_after_cooldown(target))
- if(T == chassis.loc && src == chassis.selected)
- if(istype(target, /turf/simulated/wall))
- var/turf/simulated/wall/W = target
- if(W.reinf_material)
- occupant_message("[target] is too durable to drill through.")
- else
- log_message("Drilled through [target]")
- target.ex_act(2)
- else if(istype(target, /turf/simulated/mineral))
- if(enable_special)
- for(var/turf/simulated/mineral/M in range(chassis,1))
- if(get_dir(chassis,M)&chassis.dir)
- M.GetDrilled()
- else
- var/turf/simulated/mineral/M1 = target
- M1.GetDrilled()
- log_message("Drilled through [target]")
- if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment)
- var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo
- if(ore_box)
- for(var/obj/item/weapon/ore/ore in range(chassis,1))
- if(get_dir(chassis,ore)&chassis.dir)
- ore.forceMove(ore_box)
- else if(target.loc == C)
- log_message("Drilled through [target]")
- target.ex_act(2)
- return 1
-
-/obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill
- name = "diamond drill"
- desc = "This is an upgraded version of the drill that'll pierce the heavens!"
- icon_state = "mecha_diamond_drill"
- origin_tech = list(TECH_MATERIAL = 4, TECH_ENGINEERING = 3)
- equip_cooldown = 10
- force = 15
-
-/obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill/action(atom/target)
- if(!action_checks(target)) return
- if(isobj(target))
- var/obj/target_obj = target
- if(target_obj.unacidable) return
- set_ready_state(0)
- chassis.use_power(energy_drain)
- chassis.visible_message("[chassis] starts to drill [target]", "You hear the drill.")
- occupant_message("You start to drill [target]")
- var/T = chassis.loc
- var/C = target.loc //why are these backwards? we may never know -Pete
- if(do_after_cooldown(target))
- if(T == chassis.loc && src == chassis.selected)
- if(istype(target, /turf/simulated/wall))
- var/turf/simulated/wall/W = target
- if(!W.reinf_material || do_after_cooldown(target))//To slow down how fast mechs can drill through the station
- log_message("Drilled through [target]")
- target.ex_act(3)
- else if(istype(target, /turf/simulated/mineral))
- if(enable_special)
- for(var/turf/simulated/mineral/M in range(chassis,1))
- if(get_dir(chassis,M)&chassis.dir)
- M.GetDrilled()
- else
- var/turf/simulated/mineral/M1 = target
- M1.GetDrilled()
- log_message("Drilled through [target]")
- if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment)
- var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo
- if(ore_box)
- for(var/obj/item/weapon/ore/ore in range(chassis,1))
- if(get_dir(chassis,ore)&chassis.dir)
- ore.forceMove(ore_box)
- else if(target.loc == C)
- log_message("Drilled through [target]")
- target.ex_act(2)
- return 1
-
-/obj/item/mecha_parts/mecha_equipment/tool/drill/bore
- name = "depth bore"
- desc = "This is the drill that'll pierce the depths!"
- icon_state = "mecha_bore"
- equip_cooldown = 5 SECONDS
- energy_drain = 30
- force = 20
- required_type = list(/obj/mecha/working/ripley)
-
-/obj/item/mecha_parts/mecha_equipment/tool/drill/bore/action(atom/target)
- if(!action_checks(target)) return
- if(isobj(target))
- var/obj/target_obj = target
- if(target_obj.unacidable) return
- set_ready_state(0)
- chassis.use_power(energy_drain)
- chassis.visible_message("[chassis] starts to bore into \the [target]", "You hear the bore.")
- occupant_message("You start to bore into \the [target]")
- var/T = chassis.loc
- var/C = target.loc
- if(do_after_cooldown(target))
- if(T == chassis.loc && src == chassis.selected)
- if(istype(target, /turf/simulated/wall))
- var/turf/simulated/wall/W = target
- if(W.reinf_material)
- occupant_message("[target] is too durable to bore through.")
- else
- log_message("Bored through [target]")
- target.ex_act(2)
- else if(istype(target, /turf/simulated/mineral))
- var/turf/simulated/mineral/M = target
- if(enable_special && !M.density)
- M.ex_act(2)
- log_message("Bored into [target]")
- else
- M.GetDrilled()
- log_message("Bored through [target]")
- if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment)
- var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo
- if(ore_box)
- for(var/obj/item/weapon/ore/ore in range(chassis,1))
- if(get_dir(chassis,ore)&chassis.dir)
- ore.forceMove(ore_box)
- else if(target.loc == C)
- log_message("Drilled through [target]")
- target.ex_act(2)
- return 1
-
-/obj/item/mecha_parts/mecha_equipment/tool/orescanner
- name = "mounted ore scanner"
- desc = "An exosuit-mounted ore scanner."
- icon_state = "mecha_analyzer"
- origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 2, TECH_POWER = 2)
- equip_cooldown = 5
- energy_drain = 30
- range = MELEE|RANGED
- equip_type = EQUIP_SPECIAL
- ready_sound = 'sound/items/goggles_charge.ogg'
- required_type = list(/obj/mecha/working/ripley)
-
- var/obj/item/weapon/mining_scanner/my_scanner = null
- var/exact_scan = FALSE
-
-/obj/item/mecha_parts/mecha_equipment/tool/orescanner/Initialize()
- my_scanner = new(src)
- return ..()
-
-/obj/item/mecha_parts/mecha_equipment/tool/orescanner/Destroy()
- QDEL_NULL(my_scanner)
- return ..()
-
-/obj/item/mecha_parts/mecha_equipment/tool/orescanner/action(var/atom/target)
- if(!action_checks(target) || get_dist(chassis, target) > 5)
- return FALSE
-
- if(!enable_special)
- target = get_turf(chassis)
-
- var/datum/beam/ScanBeam = chassis.Beam(target,"g_beam",'icons/effects/beam.dmi',time=2 SECONDS,10,/obj/effect/ebeam,2)
-
- if(do_after(chassis.occupant, 2 SECONDS))
- my_scanner.ScanTurf(target, chassis.occupant, exact_scan)
-
- QDEL_NULL(ScanBeam)
-
-/obj/item/mecha_parts/mecha_equipment/tool/orescanner/advanced
- name = "advanced ore scanner"
- icon_state = "mecha_analyzer_adv"
- exact_scan = TRUE
-
-/obj/item/mecha_parts/mecha_equipment/tool/extinguisher
- name = "extinguisher"
- desc = "Exosuit-mounted extinguisher (Can be attached to: Engineering exosuits)"
- icon_state = "mecha_exting"
- equip_cooldown = 5
- energy_drain = 0
- range = MELEE|RANGED
- required_type = list(/obj/mecha/working)
- var/spray_particles = 5
- var/spray_amount = 5 //units of liquid per particle. 5 is enough to wet the floor - it's a big fire extinguisher, so should be fine
- var/max_water = 1000
-
-/obj/item/mecha_parts/mecha_equipment/tool/extinguisher/Initialize()
- . = ..()
- reagents = new/datum/reagents(max_water)
- reagents.my_atom = src
- reagents.add_reagent("water", max_water)
-
-/obj/item/mecha_parts/mecha_equipment/tool/extinguisher/action(atom/target) //copypasted from extinguisher. TODO: Rewrite from scratch.
- if(!action_checks(target) || get_dist(chassis, target)>3) return
- if(get_dist(chassis, target)>2) return
- set_ready_state(0)
- if(do_after_cooldown(target))
- if( istype(target, /obj/structure/reagent_dispensers/watertank) && get_dist(chassis,target) <= 1)
- var/obj/o = target
- var/amount = o.reagents.trans_to_obj(src, 200)
- occupant_message("[amount] units transferred into internal tank.")
- playsound(chassis, 'sound/effects/refill.ogg', 50, 1, -6)
- return
-
- if (src.reagents.total_volume < 1)
- occupant_message("\The [src] is empty.")
- return
-
- playsound(chassis, 'sound/effects/extinguish.ogg', 75, 1, -3)
-
- var/direction = get_dir(chassis,target)
-
- var/turf/T = get_turf(target)
- var/turf/T1 = get_step(T,turn(direction, 90))
- var/turf/T2 = get_step(T,turn(direction, -90))
-
- var/list/the_targets = list(T,T1,T2)
-
- for(var/a = 1 to 5)
- spawn(0)
- var/obj/effect/effect/water/W = new /obj/effect/effect/water(get_turf(chassis))
- var/turf/my_target
- if(a == 1)
- my_target = T
- else if(a == 2)
- my_target = T1
- else if(a == 3)
- my_target = T2
- else
- my_target = pick(the_targets)
- W.create_reagents(5)
- if(!W || !src)
- return
- reagents.trans_to_obj(W, spray_amount)
- W.set_color()
- W.set_up(my_target)
- return 1
-
-/obj/item/mecha_parts/mecha_equipment/tool/extinguisher/get_equip_info()
- return "[..()] \[[src.reagents.total_volume]\]"
-
-/obj/item/mecha_parts/mecha_equipment/tool/extinguisher/on_reagent_change()
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/powertool
- name = "pneumatic wrench"
- desc = "An exosuit-mounted hydraulic wrench."
- icon_state = "mecha_wrench"
- origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 2, TECH_POWER = 2)
- equip_cooldown = 3
- energy_drain = 15
- range = MELEE
- equip_type = EQUIP_UTILITY
- ready_sound = 'sound/items/Ratchet.ogg'
- required_type = list(/obj/mecha/working/ripley)
-
- var/obj/item/my_tool = null
- var/tooltype = /obj/item/weapon/tool/wrench/power
-
-/obj/item/mecha_parts/mecha_equipment/tool/powertool/Initialize()
- my_tool = new tooltype(src)
- my_tool.name = name
- my_tool.anchored = TRUE
- my_tool.canremove = FALSE
- return ..()
-
-/obj/item/mecha_parts/mecha_equipment/tool/powertool/Destroy()
- QDEL_NULL(my_tool)
- return ..()
-
-/obj/item/mecha_parts/mecha_equipment/tool/powertool/action(var/atom/target)
- if(!action_checks(target))
- return FALSE
-
- if(isliving(target))
- my_tool.attack(target, chassis.occupant, BP_TORSO)
-
- target.attackby(my_tool,chassis.occupant)
-
-/obj/item/mecha_parts/mecha_equipment/tool/powertool/prybar
- name = "pneumatic prybar"
- desc = "An exosuit-mounted pneumatic prybar."
- icon_state = "mecha_crowbar"
- tooltype = /obj/item/weapon/tool/crowbar/power
- ready_sound = 'sound/mecha/gasdisconnected.ogg'
-
-/obj/item/mecha_parts/mecha_equipment/tool/rcd
- name = "mounted RCD"
- desc = "An exosuit-mounted Rapid Construction Device. (Can be attached to: Any exosuit)"
- icon_state = "mecha_rcd"
- origin_tech = list(TECH_MATERIAL = 4, TECH_BLUESPACE = 3, TECH_MAGNET = 4, TECH_POWER = 4)
- equip_cooldown = 10
- energy_drain = 250
- range = MELEE|RANGED
- equip_type = EQUIP_SPECIAL
- var/obj/item/weapon/rcd/electric/mounted/mecha/my_rcd = null
-
-/obj/item/mecha_parts/mecha_equipment/tool/rcd/Initialize()
- my_rcd = new(src)
- return ..()
-
-/obj/item/mecha_parts/mecha_equipment/tool/rcd/Destroy()
- QDEL_NULL(my_rcd)
- return ..()
-
-/obj/item/mecha_parts/mecha_equipment/tool/rcd/action(atom/target)
- if(!action_checks(target) || get_dist(chassis, target) > 3)
- return FALSE
-
- my_rcd.use_rcd(target, chassis.occupant)
-
-/obj/item/mecha_parts/mecha_equipment/tool/rcd/Topic(href,href_list)
- ..()
- if(href_list["mode"])
- my_rcd.mode_index = text2num(href_list["mode"])
- occupant_message("RCD reconfigured to '[my_rcd.modes[my_rcd.mode_index]]'.")
-/*
-/obj/item/mecha_parts/mecha_equipment/tool/rcd/get_equip_info()
- return "[..()] \[D|C|A\]"
-*/
-/obj/item/mecha_parts/mecha_equipment/tool/rcd/get_equip_info()
- var/list/content = list(..()) // This is all for one line, in the interest of string tree conservation.
- var/i = 1
- content += "
"
- for(var/mode in my_rcd.modes)
- content += " [mode]"
- if(i < my_rcd.modes.len)
- content += "
"
- i++
-
- return content.Join()
-
-
-/obj/item/mecha_parts/mecha_equipment/teleporter
- name = "teleporter"
- desc = "An exosuit module that allows exosuits to teleport to any position in view."
- icon_state = "mecha_teleport"
- origin_tech = list(TECH_BLUESPACE = 10)
- equip_cooldown = 150
- energy_drain = 1000
- range = RANGED
-
- equip_type = EQUIP_SPECIAL
-
-/obj/item/mecha_parts/mecha_equipment/teleporter/action(atom/target)
- if(!action_checks(target) || src.loc.z == 2) return
- var/turf/T = get_turf(target)
- if(T)
- set_ready_state(0)
- chassis.use_power(energy_drain)
- do_teleport(chassis, T, 4)
- do_after_cooldown()
- return
-
-
-/obj/item/mecha_parts/mecha_equipment/wormhole_generator
- name = "wormhole generator"
- desc = "An exosuit module that allows generating of small quasi-stable wormholes."
- icon_state = "mecha_wholegen"
- origin_tech = list(TECH_BLUESPACE = 3)
- equip_cooldown = 50
- energy_drain = 300
- range = RANGED
-
- equip_type = EQUIP_SPECIAL
-
-/obj/item/mecha_parts/mecha_equipment/wormhole_generator/action(atom/target)
- if(!action_checks(target) || src.loc.z == 2) return
- var/list/theareas = list()
- for(var/area/AR in orange(100, chassis))
- if(AR in theareas) continue
- theareas += AR
- if(!theareas.len)
- return
- var/area/thearea = pick(theareas)
- var/list/L = list()
- var/turf/pos = get_turf(src)
- for(var/turf/T in get_area_turfs(thearea.type))
- if(!T.density && pos.z == T.z)
- var/clear = 1
- for(var/obj/O in T)
- if(O.density)
- clear = 0
- break
- if(clear)
- L+=T
- if(!L.len)
- return
- var/turf/target_turf = pick(L)
- if(!target_turf)
- return
- chassis.use_power(energy_drain)
- set_ready_state(0)
- var/obj/effect/portal/P = new /obj/effect/portal(get_turf(target))
- P.target = target_turf
- P.creator = null
- P.icon = 'icons/obj/objects.dmi'
- P.failchance = 0
- P.icon_state = "anom"
- P.name = "wormhole"
- do_after_cooldown()
- src = null
- spawn(rand(150,300))
- qdel(P)
- return
-
-/obj/item/mecha_parts/mecha_equipment/gravcatapult
- name = "gravitational catapult"
- desc = "An exosuit mounted gravitational catapult."
- icon_state = "mecha_teleport"
- origin_tech = list(TECH_BLUESPACE = 2, TECH_MAGNET = 3)
- equip_cooldown = 10
- energy_drain = 100
- range = MELEE|RANGED
- var/atom/movable/locked
- var/mode = 1 //1 - gravsling 2 - gravpush
-
- var/last_fired = 0 //Concept stolen from guns.
- var/fire_delay = 10 //Used to prevent spam-brute against humans.
-
- equip_type = EQUIP_UTILITY
-
-/obj/item/mecha_parts/mecha_equipment/gravcatapult/action(atom/movable/target)
-
- if(world.time >= last_fired + fire_delay)
- last_fired = world.time
- else
- if (world.time % 3)
- occupant_message("[src] is not ready to fire again!")
- return 0
-
- switch(mode)
- if(1)
- if(!action_checks(target) && !locked) return
- if(!locked)
- if(!istype(target) || target.anchored)
- occupant_message("Unable to lock on [target]")
- return
- locked = target
- occupant_message("Locked on [target]")
- send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
- return
- else if(target!=locked)
- if(locked in view(chassis))
- locked.throw_at(target, 14, 1.5, chassis)
- locked = null
- send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
- set_ready_state(0)
- chassis.use_power(energy_drain)
- do_after_cooldown()
- else
- locked = null
- occupant_message("Lock on [locked] disengaged.")
- send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
- if(2)
- if(!action_checks(target)) return
- var/list/atoms = list()
- if(isturf(target))
- atoms = range(target,3)
- else
- atoms = orange(target,3)
- for(var/atom/movable/A in atoms)
- if(A.anchored) continue
- spawn(0)
- var/iter = 5-get_dist(A,target)
- for(var/i=0 to iter)
- step_away(A,target)
- sleep(2)
- set_ready_state(0)
- chassis.use_power(energy_drain)
- do_after_cooldown()
- return
-
-/obj/item/mecha_parts/mecha_equipment/gravcatapult/get_equip_info()
- return "[..()] [mode==1?"([locked||"Nothing"])":null] \[S|P\]"
-
-/obj/item/mecha_parts/mecha_equipment/gravcatapult/Topic(href, href_list)
- ..()
- if(href_list["mode"])
- mode = text2num(href_list["mode"])
- send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
- return
-
-
-/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster //what is that noise? A BAWWW from TK mutants.
- name = "\improper CCW armor booster"
- desc = "Close-combat armor booster. Boosts exosuit armor against armed melee attacks. Requires energy to operate."
- icon_state = "mecha_abooster_ccw"
- origin_tech = list(TECH_MATERIAL = 3)
- equip_cooldown = 10
- energy_drain = 50
- range = 0
- var/deflect_coeff = 1.15
- var/damage_coeff = 0.8
-
- equip_type = EQUIP_HULL
-
-/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/can_attach(obj/mecha/M as obj)
- if(..())
- if(!M.proc_res["dynattackby"])
- return 1
- return 0
-
-/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/attach(obj/mecha/M as obj)
- ..()
- chassis.proc_res["dynattackby"] = src
- return
-
-/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/detach()
- chassis.proc_res["dynattackby"] = null
- ..()
- return
-
-/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/get_equip_info()
- if(!chassis) return
- return "* [src.name]"
-
-/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/proc/dynattackby(obj/item/weapon/W as obj, mob/user as mob)
- if(!action_checks(user))
- return chassis.dynattackby(W,user)
- chassis.log_message("Attacked by [W]. Attacker - [user]")
- if(prob(chassis.deflect_chance*deflect_coeff))
- user << "\The [W] bounces off [chassis] armor."
- chassis.log_append_to_last("Armor saved.")
- else
- chassis.occupant_message("\The [user] hits [chassis] with [W].")
- user.visible_message("\The [user] hits [chassis] with [W].", "You hit [src] with [W].")
- chassis.take_damage(round(W.force*damage_coeff),W.damtype)
- chassis.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
- set_ready_state(0)
- chassis.use_power(energy_drain)
- do_after_cooldown()
- return
-
-
-/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster
- name = "\improper RW armor booster"
- desc = "Ranged-weaponry armor booster. Boosts exosuit armor against ranged attacks. Completely blocks taser shots, but requires energy to operate."
- icon_state = "mecha_abooster_proj"
- origin_tech = list(TECH_MATERIAL = 4)
- equip_cooldown = 10
- energy_drain = 50
- range = 0
- var/deflect_coeff = 1.15
- var/damage_coeff = 0.8
-
- equip_type = EQUIP_HULL
-
-/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/can_attach(obj/mecha/M as obj)
- if(..())
- if(!M.proc_res["dynbulletdamage"] && !M.proc_res["dynhitby"])
- return 1
- return 0
-
-/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/attach(obj/mecha/M as obj)
- ..()
- chassis.proc_res["dynbulletdamage"] = src
- chassis.proc_res["dynhitby"] = src
- return
-
-/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/detach()
- chassis.proc_res["dynbulletdamage"] = null
- chassis.proc_res["dynhitby"] = null
- ..()
- return
-
-/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/get_equip_info()
- if(!chassis) return
- return "* [src.name]"
-
-/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/proc/dynbulletdamage(var/obj/item/projectile/Proj)
- if(!action_checks(src))
- return chassis.dynbulletdamage(Proj)
- if(prob(chassis.deflect_chance*deflect_coeff))
- chassis.occupant_message("The armor deflects incoming projectile.")
- chassis.visible_message("The [chassis.name] armor deflects the projectile")
- chassis.log_append_to_last("Armor saved.")
- else
- chassis.take_damage(round(Proj.damage*src.damage_coeff),Proj.check_armour)
- chassis.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
- Proj.on_hit(chassis)
- set_ready_state(0)
- chassis.use_power(energy_drain)
- do_after_cooldown()
- return
-
-/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/proc/dynhitby(atom/movable/A)
- if(!action_checks(A))
- return chassis.dynhitby(A)
- if(prob(chassis.deflect_chance*deflect_coeff) || istype(A, /mob/living) || istype(A, /obj/item/mecha_parts/mecha_tracking))
- chassis.occupant_message("The [A] bounces off the armor.")
- chassis.visible_message("The [A] bounces off the [chassis] armor")
- chassis.log_append_to_last("Armor saved.")
- if(istype(A, /mob/living))
- var/mob/living/M = A
- M.take_organ_damage(10)
- else if(istype(A, /obj))
- var/obj/O = A
- if(O.throwforce)
- chassis.take_damage(round(O.throwforce*damage_coeff))
- chassis.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
- set_ready_state(0)
- chassis.use_power(energy_drain)
- do_after_cooldown()
- return
-
-
-/obj/item/mecha_parts/mecha_equipment/repair_droid
- name = "repair droid"
- desc = "Automated repair droid. Scans exosuit for damage and repairs it. Can fix almost any type of external or internal damage."
- icon_state = "repair_droid"
- origin_tech = list(TECH_MAGNET = 3, TECH_DATA = 3)
- equip_cooldown = 20
- energy_drain = 100
- range = 0
- var/health_boost = 2
- var/datum/global_iterator/pr_repair_droid
- var/icon/droid_overlay
- var/list/repairable_damage = list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH)
-
- equip_type = EQUIP_HULL
-
-/obj/item/mecha_parts/mecha_equipment/repair_droid/New()
- ..()
- pr_repair_droid = new /datum/global_iterator/mecha_repair_droid(list(src),0)
- pr_repair_droid.set_delay(equip_cooldown)
- return
-
-/obj/item/mecha_parts/mecha_equipment/repair_droid/Destroy()
- qdel(pr_repair_droid)
- pr_repair_droid = null
- ..()
-
-/obj/item/mecha_parts/mecha_equipment/repair_droid/attach(obj/mecha/M as obj)
- ..()
- droid_overlay = new(src.icon, icon_state = "repair_droid")
- M.overlays += droid_overlay
- return
-
-/obj/item/mecha_parts/mecha_equipment/repair_droid/destroy()
- chassis.overlays -= droid_overlay
- ..()
- return
-
-/obj/item/mecha_parts/mecha_equipment/repair_droid/detach()
- chassis.overlays -= droid_overlay
- pr_repair_droid.stop()
- ..()
- return
-
-/obj/item/mecha_parts/mecha_equipment/repair_droid/get_equip_info()
- if(!chassis) return
- return "* [src.name] - [pr_repair_droid.active()?"Dea":"A"]ctivate"
-
-
-/obj/item/mecha_parts/mecha_equipment/repair_droid/Topic(href, href_list)
- ..()
- if(href_list["toggle_repairs"])
- chassis.overlays -= droid_overlay
- if(pr_repair_droid.toggle())
- droid_overlay = new(src.icon, icon_state = "repair_droid_a")
- log_message("Activated.")
- else
- droid_overlay = new(src.icon, icon_state = "repair_droid")
- log_message("Deactivated.")
- set_ready_state(1)
- chassis.overlays += droid_overlay
- send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
- return
-
-
-/datum/global_iterator/mecha_repair_droid
-
-/datum/global_iterator/mecha_repair_droid/process(var/obj/item/mecha_parts/mecha_equipment/repair_droid/RD as obj)
- if(!RD.chassis)
- stop()
- RD.set_ready_state(1)
- return
- var/health_boost = RD.health_boost
- var/repaired = 0
- if(RD.chassis.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT))
- health_boost *= -2
- else if(RD.chassis.hasInternalDamage() && prob(15))
- for(var/int_dam_flag in RD.repairable_damage)
- if(RD.chassis.hasInternalDamage(int_dam_flag))
- RD.chassis.clearInternalDamage(int_dam_flag)
- repaired = 1
- break
- if(health_boost<0 || RD.chassis.health < initial(RD.chassis.health))
- RD.chassis.health += min(health_boost, initial(RD.chassis.health)-RD.chassis.health)
- repaired = 1
- if(repaired)
- if(RD.chassis.use_power(RD.energy_drain))
- RD.set_ready_state(0)
- else
- stop()
- RD.set_ready_state(1)
- return
- else
- RD.set_ready_state(1)
- return
-
-
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay
- name = "energy relay"
- desc = "Wirelessly drains energy from any available power channel in area. The performance index is quite low."
- icon_state = "tesla"
- origin_tech = list(TECH_MAGNET = 4, TECH_ILLEGAL = 2)
- equip_cooldown = 10
- energy_drain = 0
- range = 0
- var/datum/global_iterator/pr_energy_relay
- var/coeff = 100
- var/list/use_channels = list(EQUIP,ENVIRON,LIGHT)
-
- equip_type = EQUIP_UTILITY
-
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/New()
- ..()
- pr_energy_relay = new /datum/global_iterator/mecha_energy_relay(list(src),0)
- pr_energy_relay.set_delay(equip_cooldown)
- return
-
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/Destroy()
- qdel(pr_energy_relay)
- pr_energy_relay = null
- ..()
-
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/detach()
- pr_energy_relay.stop()
-// chassis.proc_res["dynusepower"] = null
- chassis.proc_res["dyngetcharge"] = null
- ..()
- return
-
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/attach(obj/mecha/M)
- ..()
- chassis.proc_res["dyngetcharge"] = src
-// chassis.proc_res["dynusepower"] = src
- return
-
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/can_attach(obj/mecha/M)
- if(..())
- if(!M.proc_res["dyngetcharge"])// && !M.proc_res["dynusepower"])
- return 1
- return 0
-
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/dyngetcharge()
- if(equip_ready) //disabled
- return chassis.dyngetcharge()
- var/area/A = get_area(chassis)
- var/pow_chan = get_power_channel(A)
- var/charge = 0
- if(pow_chan)
- charge = 1000 //making magic
- else
- return chassis.dyngetcharge()
- return charge
-
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/get_power_channel(var/area/A)
- var/pow_chan
- if(A)
- for(var/c in use_channels)
- if(A.powered(c))
- pow_chan = c
- break
- return pow_chan
-
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/Topic(href, href_list)
- ..()
- if(href_list["toggle_relay"])
- if(pr_energy_relay.toggle())
- set_ready_state(0)
- log_message("Activated.")
- else
- set_ready_state(1)
- log_message("Deactivated.")
- return
-
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/get_equip_info()
- if(!chassis) return
- return "* [src.name] - [pr_energy_relay.active()?"Dea":"A"]ctivate"
-
-/* proc/dynusepower(amount)
- if(!equip_ready) //enabled
- var/area/A = get_area(chassis)
- var/pow_chan = get_power_channel(A)
- if(pow_chan)
- A.master.use_power(amount*coeff, pow_chan)
- return 1
- return chassis.dynusepower(amount)*/
-
-/datum/global_iterator/mecha_energy_relay
-
-/datum/global_iterator/mecha_energy_relay/process(var/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/ER)
- if(!ER.chassis || ER.chassis.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT))
- stop()
- ER.set_ready_state(1)
- return
- var/cur_charge = ER.chassis.get_charge()
- if(isnull(cur_charge) || !ER.chassis.cell)
- stop()
- ER.set_ready_state(1)
- ER.occupant_message("No powercell detected.")
- return
- if(cur_charge* [src.name] - [my_shield.active?"Dea":"A"]ctivate"
-
-
-/obj/item/mecha_parts/mecha_equipment/generator
- name = "phoron generator"
- desc = "Generates power using solid phoron as fuel. Pollutes the environment."
- icon_state = "tesla"
- origin_tech = list(TECH_PHORON = 2, TECH_POWER = 2, TECH_ENGINEERING = 1)
- equip_cooldown = 10
- energy_drain = 0
- range = MELEE
- var/datum/global_iterator/pr_mech_generator
- var/coeff = 100
- var/obj/item/stack/material/fuel
- var/max_fuel = 150000
- var/fuel_per_cycle_idle = 100
- var/fuel_per_cycle_active = 500
- var/power_per_cycle = 20
-
- equip_type = EQUIP_UTILITY
-
-/obj/item/mecha_parts/mecha_equipment/generator/New()
- ..()
- init()
- return
-
-/obj/item/mecha_parts/mecha_equipment/generator/Destroy()
- qdel(pr_mech_generator)
- pr_mech_generator = null
- ..()
-
-/obj/item/mecha_parts/mecha_equipment/generator/proc/init()
- fuel = new /obj/item/stack/material/phoron(src)
- fuel.amount = 0
- pr_mech_generator = new /datum/global_iterator/mecha_generator(list(src),0)
- pr_mech_generator.set_delay(equip_cooldown)
- return
-
-/obj/item/mecha_parts/mecha_equipment/generator/detach()
- pr_mech_generator.stop()
- ..()
- return
-
-
-/obj/item/mecha_parts/mecha_equipment/generator/Topic(href, href_list)
- ..()
- if(href_list["toggle"])
- if(pr_mech_generator.toggle())
- set_ready_state(0)
- log_message("Activated.")
- else
- set_ready_state(1)
- log_message("Deactivated.")
- return
-
-/obj/item/mecha_parts/mecha_equipment/generator/get_equip_info()
- var/output = ..()
- if(output)
- return "[output] \[[fuel]: [round(fuel.amount*fuel.perunit,0.1)] cm3\] - [pr_mech_generator.active()?"Dea":"A"]ctivate"
- return
-
-/obj/item/mecha_parts/mecha_equipment/generator/action(target)
- if(chassis)
- var/result = load_fuel(target)
- var/message
- if(isnull(result))
- message = "[fuel] traces in target minimal. [target] cannot be used as fuel."
- else if(!result)
- message = "Unit is full."
- else
- message = "[result] unit\s of [fuel] successfully loaded."
- send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
- occupant_message(message)
- return
-
-/obj/item/mecha_parts/mecha_equipment/generator/proc/load_fuel(var/obj/item/stack/material/P)
- if(P.type == fuel.type && P.amount)
- var/to_load = max(max_fuel - fuel.amount*fuel.perunit,0)
- if(to_load)
- var/units = min(max(round(to_load / P.perunit),1),P.amount)
- if(units)
- fuel.amount += units
- P.use(units)
- return units
- else
- return 0
- return
-
-/obj/item/mecha_parts/mecha_equipment/generator/attackby(weapon,mob/user)
- var/result = load_fuel(weapon)
- if(isnull(result))
- user.visible_message("[user] tries to shove [weapon] into [src]. What a dumb-ass.","[fuel] traces minimal. [weapon] cannot be used as fuel.")
- else if(!result)
- user << "Unit is full."
- else
- user.visible_message("[user] loads [src] with [fuel].","[result] unit\s of [fuel] successfully loaded.")
- return
-
-/obj/item/mecha_parts/mecha_equipment/generator/critfail()
- ..()
- var/turf/simulated/T = get_turf(src)
- if(!T)
- return
- var/datum/gas_mixture/GM = new
- if(prob(10))
- T.assume_gas("phoron", 100, 1500+T0C)
- T.visible_message("The [src] suddenly disgorges a cloud of heated phoron.")
- destroy()
- else
- T.assume_gas("phoron", 5, istype(T) ? T.air.temperature : T20C)
- T.visible_message("The [src] suddenly disgorges a cloud of phoron.")
- T.assume_air(GM)
- return
-
-/datum/global_iterator/mecha_generator
-
-/datum/global_iterator/mecha_generator/process(var/obj/item/mecha_parts/mecha_equipment/generator/EG)
- if(!EG.chassis)
- stop()
- EG.set_ready_state(1)
- return 0
- if(EG.fuel.amount<=0)
- stop()
- EG.log_message("Deactivated - no fuel.")
- EG.set_ready_state(1)
- return 0
- var/cur_charge = EG.chassis.get_charge()
- if(isnull(cur_charge))
- EG.set_ready_state(1)
- EG.occupant_message("No powercell detected.")
- EG.log_message("Deactivated.")
- stop()
- return 0
- var/use_fuel = EG.fuel_per_cycle_idle
- if(cur_charge[target] succesfully loaded.")
- chassis.log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]")
- else
- chassis.occupant_message("You must hold still while handling objects.")
- O.anchored = initial(O.anchored)
- else
- chassis.occupant_message("Not enough room in cargo compartment.")
- else
- chassis.occupant_message("[target] is firmly secured.")
-
- else if(istype(target,/mob/living))
- var/mob/living/M = target
- if(M.stat>1) return
- if(chassis.occupant.a_intent == I_HURT)
- chassis.occupant_message("You obliterate [target] with [src.name], leaving blood and guts everywhere.")
- chassis.visible_message("[chassis] destroys [target] in an unholy fury.")
- if(chassis.occupant.a_intent == I_DISARM)
- chassis.occupant_message("You tear [target]'s limbs off with [src.name].")
- chassis.visible_message("[chassis] rips [target]'s arms off.")
- else
- step_away(M,chassis)
- chassis.occupant_message("You smash into [target], sending them flying.")
- chassis.visible_message("[chassis] tosses [target] like a piece of paper.")
- set_ready_state(0)
- chassis.use_power(energy_drain)
- do_after_cooldown()
- return 1
-
-/obj/item/mecha_parts/mecha_equipment/tool/passenger
- name = "passenger compartment"
- desc = "A mountable passenger compartment for exosuits. Rather cramped."
- icon_state = "mecha_abooster_ccw"
- origin_tech = list(TECH_ENGINEERING = 1, TECH_BIO = 1)
- energy_drain = 10
- range = MELEE
- equip_cooldown = 20
- var/mob/living/carbon/occupant = null
- var/door_locked = 1
- salvageable = 0
- allow_duplicate = TRUE
-
- equip_type = EQUIP_HULL
-
-/obj/item/mecha_parts/mecha_equipment/tool/passenger/destroy()
- for(var/atom/movable/AM in src)
- AM.forceMove(get_turf(src))
- AM << "You tumble out of the destroyed [src.name]!"
- return ..()
-
-/obj/item/mecha_parts/mecha_equipment/tool/passenger/Exit(atom/movable/O)
- return 0
-
-/obj/item/mecha_parts/mecha_equipment/tool/passenger/proc/move_inside(var/mob/user)
- if (chassis)
- chassis.visible_message("[user] starts to climb into [chassis].")
-
- if(do_after(user, 40, needhand=0))
- if(!src.occupant)
- user.forceMove(src)
- occupant = user
- log_message("[user] boarded.")
- occupant_message("[user] boarded.")
- else if(src.occupant != user)
- to_chat(user, "[src.occupant] was faster. Try harder next time, loser.")
- else
- to_chat(user, "You stop entering the exosuit.")
-
-/obj/item/mecha_parts/mecha_equipment/tool/passenger/verb/eject()
- set name = "Eject"
- set category = "Exosuit Interface"
- set src = usr.loc
- set popup_menu = 0
-
- if(usr != occupant)
- return
- to_chat(occupant, "You climb out from \the [src].")
- go_out()
- occupant_message("[occupant] disembarked.")
- log_message("[occupant] disembarked.")
- add_fingerprint(usr)
-
-/obj/item/mecha_parts/mecha_equipment/tool/passenger/proc/go_out()
- if(!occupant)
- return
- occupant.forceMove(get_turf(src))
- occupant.reset_view()
- /*
- if(occupant.client)
- occupant.client.eye = occupant.client.mob
- occupant.client.perspective = MOB_PERSPECTIVE
- */
- occupant = null
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/passenger/attach()
- ..()
- if (chassis)
- chassis.verbs |= /obj/mecha/proc/move_inside_passenger
-
-/obj/item/mecha_parts/mecha_equipment/tool/passenger/detach()
- if(occupant)
- occupant_message("Unable to detach [src] - equipment occupied.")
- return
-
- var/obj/mecha/M = chassis
- ..()
- if (M && !(locate(/obj/item/mecha_parts/mecha_equipment/tool/passenger) in M))
- M.verbs -= /obj/mecha/proc/move_inside_passenger
-
-/obj/item/mecha_parts/mecha_equipment/tool/passenger/get_equip_info()
- return "[..()]
[occupant? "\[Occupant: [occupant]\]|" : ""]Exterior Hatch: Toggle Lock"
-
-/obj/item/mecha_parts/mecha_equipment/tool/passenger/Topic(href,href_list)
- ..()
- if (href_list["toggle_lock"])
- door_locked = !door_locked
- occupant_message("Passenger compartment hatch [door_locked? "locked" : "unlocked"].")
- if (chassis)
- chassis.visible_message("The hatch on \the [chassis] [door_locked? "locks" : "unlocks"].", "You hear something latching.")
-
-
-#define LOCKED 1
-#define OCCUPIED 2
-
-/obj/mecha/proc/move_inside_passenger()
- set category = "Object"
- set name = "Enter Passenger Compartment"
- set src in oview(1)
-
- //check that usr can climb in
- if (usr.stat || !ishuman(usr))
- return
-
- if (!usr.Adjacent(src))
- return
-
- if (!isturf(usr.loc))
- usr << "You can't reach the passenger compartment from here."
- return
-
- if(iscarbon(usr))
- var/mob/living/carbon/C = usr
- if(C.handcuffed)
- usr << "Kinda hard to climb in while handcuffed don't you think?"
- return
-
- if(isliving(usr))
- var/mob/living/L = usr
- if(L.has_buckled_mobs())
- to_chat(L, span("warning", "You have other entities attached to yourself. Remove them first."))
- return
-
- //search for a valid passenger compartment
- var/feedback = 0 //for nicer user feedback
- for(var/obj/item/mecha_parts/mecha_equipment/tool/passenger/P in src)
- if (P.occupant)
- feedback |= OCCUPIED
- continue
- if (P.door_locked)
- feedback |= LOCKED
- continue
-
- //found a boardable compartment
- P.move_inside(usr)
- return
-
- //didn't find anything
- switch (feedback)
- if (OCCUPIED)
- usr << "The passenger compartment is already occupied!"
- if (LOCKED)
- usr << "The passenger compartment hatch is locked!"
- if (OCCUPIED|LOCKED)
- usr << "All of the passenger compartments are already occupied or locked!"
- if (0)
- usr << "\The [src] doesn't have a passenger compartment."
-
-#undef LOCKED
-#undef OCCUPIED
-
-/obj/item/mecha_parts/mecha_equipment/tool/jetpack
- name = "ion jetpack"
- desc = "Using directed ion bursts and cunning solar wind reflection technique, this device enables controlled space flight."
- icon_state = "mecha_jetpack"
- equip_cooldown = 5
- energy_drain = 50
- var/wait = 0
- var/datum/effect/effect/system/ion_trail_follow/ion_trail
-
-
-/obj/item/mecha_parts/mecha_equipment/tool/jetpack/can_attach(obj/mecha/M as obj)
- if(!(locate(src.type) in M.equipment) && !M.proc_res["dyndomove"])
- return ..()
-
-/obj/item/mecha_parts/mecha_equipment/tool/jetpack/detach()
- ..()
- chassis.proc_res["dyndomove"] = null
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/jetpack/attach(obj/mecha/M as obj)
- ..()
- if(!ion_trail)
- ion_trail = new
- ion_trail.set_up(chassis)
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/jetpack/proc/toggle()
- if(!chassis)
- return
- !equip_ready? turn_off() : turn_on()
- return equip_ready
-
-/obj/item/mecha_parts/mecha_equipment/tool/jetpack/proc/turn_on()
- set_ready_state(0)
- chassis.proc_res["dyndomove"] = src
- ion_trail.start()
- occupant_message("Activated")
- log_message("Activated")
-
-/obj/item/mecha_parts/mecha_equipment/tool/jetpack/proc/turn_off()
- set_ready_state(1)
- chassis.proc_res["dyndomove"] = null
- ion_trail.stop()
- occupant_message("Deactivated")
- log_message("Deactivated")
-
-/obj/item/mecha_parts/mecha_equipment/tool/jetpack/proc/dyndomove(direction)
- if(!action_checks())
- return chassis.dyndomove(direction)
- var/move_result = 0
- if(chassis.hasInternalDamage(MECHA_INT_CONTROL_LOST))
- move_result = step_rand(chassis)
- else if(chassis.dir!=direction)
- chassis.set_dir(direction)
- move_result = 1
- else
- move_result = step(chassis,direction)
- if(chassis.occupant)
- for(var/obj/effect/speech_bubble/B in range(1, chassis))
- if(B.parent == chassis.occupant)
- B.loc = chassis.loc
- if(move_result)
- wait = 1
- chassis.use_power(energy_drain)
- if(!chassis.pr_inertial_movement.active())
- chassis.pr_inertial_movement.start(list(chassis,direction))
- else
- chassis.pr_inertial_movement.set_process_args(list(chassis,direction))
- do_after_cooldown()
- return 1
- return 0
-
-/obj/item/mecha_parts/mecha_equipment/tool/jetpack/action_checks()
- if(equip_ready || wait)
- return 0
- if(energy_drain && !chassis.has_charge(energy_drain))
- return 0
- if(chassis.check_for_support())
- return 0
- return 1
-
-/obj/item/mecha_parts/mecha_equipment/tool/jetpack/get_equip_info()
- if(!chassis) return
- return "* [src.name] \[Toggle\]"
-
-/obj/item/mecha_parts/mecha_equipment/tool/jetpack/Topic(href,href_list)
- ..()
- if(href_list["toggle"])
- toggle()
-
-/obj/item/mecha_parts/mecha_equipment/tool/jetpack/do_after_cooldown()
- sleep(equip_cooldown)
- wait = 0
- return 1
-
-/obj/item/mecha_parts/mecha_equipment/speedboost
- name = "ripley leg actuator overdrive"
- desc = "System enhancements and overdrives to make a ripley's legs move faster."
- icon_state = "tesla"
- origin_tech = list( TECH_POWER = 5, TECH_MATERIAL = 4, TECH_ENGINEERING = 4)
- required_type = list(/obj/mecha/working/ripley)
-
- equip_type = EQUIP_HULL
-
-/obj/item/mecha_parts/mecha_equipment/speedboost/attach(obj/mecha/M as obj)
- ..()
- if(enable_special)
- chassis.step_in = (chassis.step_in-2) // Make the ripley as fast as a durand
- else
- chassis.step_in = (chassis.step_in+1) // Improper parts slow the mech down
- return
-
-/obj/item/mecha_parts/mecha_equipment/speedboost/detach()
- chassis.step_in = initial(chassis.step_in)
- ..()
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/cable_layer
- name = "Cable Layer"
- icon_state = "mecha_wire"
- var/turf/old_turf
- var/obj/structure/cable/last_piece
- var/obj/item/stack/cable_coil/cable
- var/max_cable = 1000
- required_type = list(/obj/mecha/working)
-
-/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/New()
- cable = new(src)
- cable.amount = 0
- ..()
-
-/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/MoveAction()
- layCable()
-
-/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/action(var/obj/item/stack/cable_coil/target)
- if(!action_checks(target))
- return
- var/result = load_cable(target)
- var/message
- if(isnull(result))
- message = "Unable to load [target] - no cable found."
- else if(!result)
- message = "Reel is full."
- else
- message = "[result] meters of cable successfully loaded."
- send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
- occupant_message(message)
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/Topic(href,href_list)
- ..()
- if(href_list["toggle"])
- set_ready_state(!equip_ready)
- occupant_message("[src] [equip_ready?"dea":"a"]ctivated.")
- log_message("[equip_ready?"Dea":"A"]ctivated.")
- return
- if(href_list["cut"])
- if(cable && cable.amount)
- var/m = round(input(chassis.occupant,"Please specify the length of cable to cut","Cut cable",min(cable.amount,30)) as num, 1)
- m = min(m, cable.amount)
- if(m)
- use_cable(m)
- var/obj/item/stack/cable_coil/CC = new (get_turf(chassis))
- CC.amount = m
- else
- occupant_message("There's no more cable on the reel.")
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/get_equip_info()
- var/output = ..()
- if(output)
- return "[output] \[Cable: [cable ? cable.amount : 0] m\][(cable && cable.amount) ? "- [!equip_ready?"Dea":"A"]ctivate|Cut" : null]"
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/load_cable(var/obj/item/stack/cable_coil/CC)
- if(istype(CC) && CC.amount)
- var/cur_amount = cable? cable.amount : 0
- var/to_load = max(max_cable - cur_amount,0)
- if(to_load)
- to_load = min(CC.amount, to_load)
- if(!cable)
- cable = new(src)
- cable.amount = 0
- cable.amount += to_load
- CC.use(to_load)
- return to_load
- else
- return 0
- return
-
-/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/use_cable(amount)
- if(!cable || cable.amount<1)
- set_ready_state(1)
- occupant_message("Cable depleted, [src] deactivated.")
- log_message("Cable depleted, [src] deactivated.")
- return
- if(cable.amount < amount)
- occupant_message("No enough cable to finish the task.")
- return
- cable.use(amount)
- update_equip_info()
- return 1
-
-/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/reset()
- last_piece = null
-
-/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/dismantleFloor(var/turf/new_turf)
- new_turf = get_turf(chassis)
- if(istype(new_turf, /turf/simulated/floor))
- var/turf/simulated/floor/T = new_turf
- if(!T.is_plating())
- T.make_plating(!(T.broken || T.burnt))
- return new_turf.is_plating()
-
-/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/layCable(var/turf/new_turf)
- new_turf = get_turf(chassis)
- if(equip_ready || !istype(new_turf, /turf/simulated/floor) || !dismantleFloor(new_turf))
- return reset()
- var/fdirn = turn(chassis.dir,180)
- for(var/obj/structure/cable/LC in new_turf) // check to make sure there's not a cable there already
- if(LC.d1 == fdirn || LC.d2 == fdirn)
- return reset()
- if(!use_cable(1))
- return reset()
- var/obj/structure/cable/NC = new(new_turf)
- NC.cableColor("red")
- NC.d1 = 0
- NC.d2 = fdirn
- NC.update_icon()
-
- var/datum/powernet/PN
- if(last_piece && last_piece.d2 != chassis.dir)
- last_piece.d1 = min(last_piece.d2, chassis.dir)
- last_piece.d2 = max(last_piece.d2, chassis.dir)
- last_piece.update_icon()
- PN = last_piece.powernet
-
- if(!PN)
- PN = new()
- PN.add_cable(NC)
- NC.mergeConnectedNetworks(NC.d2)
-
- //NC.mergeConnectedNetworksOnTurf()
- last_piece = NC
- return 1
\ No newline at end of file
+ equip_type = EQUIP_UTILITY
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/wormhole.dm b/code/game/mecha/equipment/tools/wormhole.dm
new file mode 100644
index 00000000000..eef3c6a52ae
--- /dev/null
+++ b/code/game/mecha/equipment/tools/wormhole.dm
@@ -0,0 +1,50 @@
+/obj/item/mecha_parts/mecha_equipment/wormhole_generator
+ name = "wormhole generator"
+ desc = "An exosuit module that allows generating of small quasi-stable wormholes."
+ icon_state = "mecha_wholegen"
+ origin_tech = list(TECH_BLUESPACE = 3)
+ equip_cooldown = 50
+ energy_drain = 300
+ range = RANGED
+
+ equip_type = EQUIP_SPECIAL
+
+/obj/item/mecha_parts/mecha_equipment/wormhole_generator/action(atom/target)
+ if(!action_checks(target) || src.loc.z == 2) return
+ var/list/theareas = list()
+ for(var/area/AR in orange(100, chassis))
+ if(AR in theareas) continue
+ theareas += AR
+ if(!theareas.len)
+ return
+ var/area/thearea = pick(theareas)
+ var/list/L = list()
+ var/turf/pos = get_turf(src)
+ for(var/turf/T in get_area_turfs(thearea.type))
+ if(!T.density && pos.z == T.z)
+ var/clear = 1
+ for(var/obj/O in T)
+ if(O.density)
+ clear = 0
+ break
+ if(clear)
+ L+=T
+ if(!L.len)
+ return
+ var/turf/target_turf = pick(L)
+ if(!target_turf)
+ return
+ chassis.use_power(energy_drain)
+ set_ready_state(0)
+ var/obj/effect/portal/P = new /obj/effect/portal(get_turf(target))
+ P.target = target_turf
+ P.creator = null
+ P.icon = 'icons/obj/objects.dmi'
+ P.failchance = 0
+ P.icon_state = "anom"
+ P.name = "wormhole"
+ do_after_cooldown()
+ src = null
+ spawn(rand(150,300))
+ qdel(P)
+ return
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/wrench.dm b/code/game/mecha/equipment/tools/wrench.dm
new file mode 100644
index 00000000000..605c2ee33d0
--- /dev/null
+++ b/code/game/mecha/equipment/tools/wrench.dm
@@ -0,0 +1,41 @@
+/obj/item/mecha_parts/mecha_equipment/tool/powertool
+ name = "pneumatic wrench"
+ desc = "An exosuit-mounted hydraulic wrench."
+ icon_state = "mecha_wrench"
+ origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 2, TECH_POWER = 2)
+ equip_cooldown = 3
+ energy_drain = 15
+ range = MELEE
+ equip_type = EQUIP_UTILITY
+ ready_sound = 'sound/items/Ratchet.ogg'
+ required_type = list(/obj/mecha/working/ripley)
+
+ var/obj/item/my_tool = null
+ var/tooltype = /obj/item/weapon/tool/wrench/power
+
+/obj/item/mecha_parts/mecha_equipment/tool/powertool/Initialize()
+ my_tool = new tooltype(src)
+ my_tool.name = name
+ my_tool.anchored = TRUE
+ my_tool.canremove = FALSE
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/tool/powertool/Destroy()
+ QDEL_NULL(my_tool)
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/tool/powertool/action(var/atom/target)
+ if(!action_checks(target))
+ return FALSE
+
+ if(isliving(target))
+ my_tool.attack(target, chassis.occupant, BP_TORSO)
+
+ target.attackby(my_tool,chassis.occupant)
+
+/obj/item/mecha_parts/mecha_equipment/tool/powertool/prybar
+ name = "pneumatic prybar"
+ desc = "An exosuit-mounted pneumatic prybar."
+ icon_state = "mecha_crowbar"
+ tooltype = /obj/item/weapon/tool/crowbar/power
+ ready_sound = 'sound/mecha/gasdisconnected.ogg'
\ No newline at end of file
diff --git a/code/game/mecha/equipment/weapons/ballistic/automatic.dm b/code/game/mecha/equipment/weapons/ballistic/automatic.dm
new file mode 100644
index 00000000000..35785925111
--- /dev/null
+++ b/code/game/mecha/equipment/weapons/ballistic/automatic.dm
@@ -0,0 +1,22 @@
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg
+ name = "\improper Ultra AC 2"
+ desc = "A superior version of the standard Solgov Autocannon MK2 design."
+ icon_state = "mecha_uac2"
+ equip_cooldown = 10
+ projectile = /obj/item/projectile/bullet/pistol/medium
+ fire_sound = 'sound/weapons/Gunshot_machinegun.ogg'
+ projectiles = 30 //10 bursts, matching the Scattershot's 10. Also, conveniently, doesn't eat your powercell when reloading like 300 bullets does.
+ projectiles_per_shot = 3
+ deviation = 0.3
+ projectile_energy_cost = 20
+ fire_cooldown = 2
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg/rigged
+ name = "jury-rigged machinegun"
+ desc = "The cross between a jackhammer and a whole lot of zipguns."
+ icon_state = "mecha_uac2-rig"
+ equip_cooldown = 12
+ projectile = /obj/item/projectile/bullet/pistol
+ deviation = 0.5
+
+ equip_type = EQUIP_UTILITY
diff --git a/code/game/mecha/equipment/weapons/ballistic/ballistic.dm b/code/game/mecha/equipment/weapons/ballistic/ballistic.dm
new file mode 100644
index 00000000000..99ef24aab76
--- /dev/null
+++ b/code/game/mecha/equipment/weapons/ballistic/ballistic.dm
@@ -0,0 +1,23 @@
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic
+ name = "general ballisic weapon"
+ var/projectile_energy_cost
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/get_equip_info()
+ return "[..()]\[[src.projectiles]\][(src.projectiles < initial(src.projectiles))?" - Rearm":null]"
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/proc/rearm()
+ if(projectiles < initial(projectiles))
+ var/projectiles_to_add = initial(projectiles) - projectiles
+ while(chassis.get_charge() >= projectile_energy_cost && projectiles_to_add)
+ projectiles++
+ projectiles_to_add--
+ chassis.use_power(projectile_energy_cost)
+ send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
+ log_message("Rearmed [src.name].")
+ return
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/Topic(href, href_list)
+ ..()
+ if (href_list["rearm"])
+ src.rearm()
+ return
\ No newline at end of file
diff --git a/code/game/mecha/equipment/weapons/ballistic/mortar.dm b/code/game/mecha/equipment/weapons/ballistic/mortar.dm
new file mode 100644
index 00000000000..86928c9da58
--- /dev/null
+++ b/code/game/mecha/equipment/weapons/ballistic/mortar.dm
@@ -0,0 +1,22 @@
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/mortar
+ name = "\improper HEP RC 4 \"Skyfall\""
+ desc = "A Hephaestus exosuit-mounted mortar for use on planetary-or-similar bodies."
+ description_info = "This weapon cannot be fired indoors, underground, or on-station."
+ icon_state = "mecha_mortar"
+ equip_cooldown = 30
+ fire_sound = 'sound/weapons/Gunshot_cannon.ogg'
+ fire_volume = 100
+ projectiles = 3
+ deviation = 0.6
+ projectile = /obj/item/projectile/arc/fragmentation/mortar
+ projectile_energy_cost = 600
+
+ origin_tech = list(TECH_MATERIAL = 4, TECH_COMBAT = 5, TECH_ILLEGAL = 3)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/mortar/action_checks(atom/target)
+ var/turf/MT = get_turf(chassis)
+ var/turf/TT = get_turf(target)
+ if(!MT.outdoors || !TT.outdoors)
+ to_chat(chassis.occupant, "\The [src]'s control system prevents you from firing due to a blocked firing arc.")
+ return 0
+ return ..()
\ No newline at end of file
diff --git a/code/game/mecha/equipment/weapons/ballistic/shotgun.dm b/code/game/mecha/equipment/weapons/ballistic/shotgun.dm
new file mode 100644
index 00000000000..d2232d00047
--- /dev/null
+++ b/code/game/mecha/equipment/weapons/ballistic/shotgun.dm
@@ -0,0 +1,25 @@
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot
+ name = "\improper LBX AC 10 \"Scattershot\""
+ desc = "A massive shotgun designed to fill a large area with pellets."
+ icon_state = "mecha_scatter"
+ equip_cooldown = 20
+ projectile = /obj/item/projectile/bullet/pellet/shotgun/flak
+ fire_sound = 'sound/weapons/Gunshot_shotgun.ogg'
+ fire_volume = 80
+ projectiles = 40
+ projectiles_per_shot = 4
+ deviation = 0.7
+ projectile_energy_cost = 25
+
+ origin_tech = list(TECH_MATERIAL = 3, TECH_COMBAT = 4)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot/rigged
+ name = "jury-rigged shrapnel cannon"
+ desc = "The remains of some unfortunate RCD now doomed to kill, rather than construct."
+ icon_state = "mecha_scatter-rig"
+ equip_cooldown = 30
+ fire_volume = 100
+ projectiles = 20
+ deviation = 1
+
+ equip_type = EQUIP_UTILITY
\ No newline at end of file
diff --git a/code/game/mecha/equipment/weapons/defense/shocker.dm b/code/game/mecha/equipment/weapons/defense/shocker.dm
new file mode 100644
index 00000000000..af120167d25
--- /dev/null
+++ b/code/game/mecha/equipment/weapons/defense/shocker.dm
@@ -0,0 +1,33 @@
+//////////////
+//Defensive//
+//////////////
+
+/obj/item/mecha_parts/mecha_equipment/shocker
+ name = "exosuit electrifier"
+ desc = "A device to electrify the external portions of a mecha in order to increase its defensive capabilities."
+ icon_state = "mecha_coil"
+ equip_cooldown = 10
+ energy_drain = 100
+ range = RANGED
+ origin_tech = list(TECH_COMBAT = 3, TECH_POWER = 6)
+ var/shock_damage = 15
+ var/active
+
+ equip_type = EQUIP_HULL
+
+/obj/item/mecha_parts/mecha_equipment/shocker/can_attach(obj/mecha/M as obj)
+ if(..())
+ if(!M.proc_res["dynattackby"] && !M.proc_res["dynattackhand"] && !M.proc_res["dynattackalien"])
+ return 1
+ return 0
+
+/obj/item/mecha_parts/mecha_equipment/shocker/attach(obj/mecha/M as obj)
+ ..()
+ chassis.proc_res["dynattackby"] = src
+ return
+
+/obj/item/mecha_parts/mecha_equipment/shocker/proc/dynattackby(obj/item/weapon/W, mob/living/user)
+ if(!action_checks(user) || !active)
+ return
+ user.electrocute_act(shock_damage, src)
+ return chassis.dynattackby(W,user)
diff --git a/code/game/mecha/equipment/weapons/energy/energy.dm b/code/game/mecha/equipment/weapons/energy/energy.dm
new file mode 100644
index 00000000000..091e8dcc7b0
--- /dev/null
+++ b/code/game/mecha/equipment/weapons/energy/energy.dm
@@ -0,0 +1,3 @@
+/obj/item/mecha_parts/mecha_equipment/weapon/energy
+ name = "general energy weapon"
+ auto_rearm = 1
\ No newline at end of file
diff --git a/code/game/mecha/equipment/weapons/energy/ion.dm b/code/game/mecha/equipment/weapons/energy/ion.dm
new file mode 100644
index 00000000000..7d5be8ef2c5
--- /dev/null
+++ b/code/game/mecha/equipment/weapons/energy/ion.dm
@@ -0,0 +1,20 @@
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/ion
+ equip_cooldown = 40
+ name = "mkIV ion heavy cannon"
+ desc = "An upscaled variant of anti-mechanical weaponry constructed by NT, such as the EW Halicon."
+ icon_state = "mecha_ion"
+ energy_drain = 120
+ projectile = /obj/item/projectile/ion
+ fire_sound = 'sound/weapons/Laser.ogg'
+
+ origin_tech = list(TECH_MATERIAL = 3, TECH_COMBAT = 4, TECH_MAGNET = 4)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/ion/rigged
+ equip_cooldown = 30
+ name = "jury-rigged ion cannon"
+ desc = "A tesla coil modified to amplify an ionic wave, and use it as a projectile."
+ icon_state = "mecha_ion-rig"
+ energy_drain = 100
+ projectile = /obj/item/projectile/ion/pistol
+
+ equip_type = EQUIP_UTILITY
\ No newline at end of file
diff --git a/code/game/mecha/equipment/weapons/energy/laser.dm b/code/game/mecha/equipment/weapons/energy/laser.dm
new file mode 100644
index 00000000000..8bdcbcf71f8
--- /dev/null
+++ b/code/game/mecha/equipment/weapons/energy/laser.dm
@@ -0,0 +1,68 @@
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser
+ equip_cooldown = 8
+ name = "\improper CH-PS \"Immolator\" laser"
+ desc = "A laser carbine's firing system mounted on a high-powered exosuit weapon socket."
+ icon_state = "mecha_laser"
+ energy_drain = 30
+ projectile = /obj/item/projectile/beam
+ fire_sound = 'sound/weapons/Laser.ogg'
+
+ origin_tech = list(TECH_MATERIAL = 2, TECH_COMBAT = 3, TECH_MAGNET = 3)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/xray
+ equip_cooldown = 6
+ name = "\improper CH-XS \"Penetrator\" laser"
+ desc = "A large, mounted variant of the anti-armor xray rifle."
+ icon_state = "mecha_xray"
+ energy_drain = 150
+ projectile = /obj/item/projectile/beam/xray
+ fire_sound = 'sound/weapons/eluger.ogg'
+
+ origin_tech = list(TECH_MATERIAL = 3, TECH_COMBAT = 3, TECH_PHORON = 3, TECH_POWER = 3)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/xray/rigged
+ equip_cooldown = 12
+ name = "jury-rigged xray rifle"
+ desc = "A modified wormhole modulation array and meson-scanning control system allow this abomination to produce concentrated blasts of xrays."
+ energy_drain = 175
+ icon_state = "mecha_xray-rig"
+
+ equip_type = EQUIP_UTILITY
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/riggedlaser
+ equip_cooldown = 15
+ name = "jury-rigged welder-laser"
+ desc = "While not regulation, this inefficient weapon can be attached to working exo-suits in desperate, or malicious, times."
+ icon_state = "mecha_laser-rig"
+ energy_drain = 60
+ projectile = /obj/item/projectile/beam
+ fire_sound = 'sound/weapons/Laser.ogg'
+ required_type = list(/obj/mecha/combat, /obj/mecha/working)
+
+ equip_type = EQUIP_UTILITY
+
+ origin_tech = list(TECH_MATERIAL = 2, TECH_COMBAT = 2, TECH_MAGNET = 2)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy
+ equip_cooldown = 15
+ name = "\improper CH-LC \"Solaris\" laser cannon"
+ desc = "In the Solaris, the lasing medium is enclosed in a tube lined with plutonium-239 and subjected to extreme neutron flux in a nuclear reactor core. This incredible technology may help YOU achieve high excitation rates with massive laser volumes!"
+ icon_state = "mecha_laser"
+ energy_drain = 60
+ projectile = /obj/item/projectile/beam/heavylaser
+ fire_sound = 'sound/weapons/lasercannonfire.ogg'
+
+ origin_tech = list(TECH_MATERIAL = 3, TECH_COMBAT = 4, TECH_MAGNET = 4)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/rigged
+ equip_cooldown = 25
+ name = "jury-rigged emitter cannon"
+ desc = "While not regulation, this mining tool can be used as an inefficient weapon on working exo-suits in desperate, or malicious, times."
+ icon_state = "mecha_emitter"
+ energy_drain = 80
+ projectile = /obj/item/projectile/beam/heavylaser/fakeemitter
+ fire_sound = 'sound/weapons/emitter.ogg'
+
+ equip_type = EQUIP_UTILITY
+
+ origin_tech = list(TECH_COMBAT = 4, TECH_MAGNET = 4, TECH_PHORON = 3, TECH_ILLEGAL = 1)
\ No newline at end of file
diff --git a/code/game/mecha/equipment/weapons/energy/phased.dm b/code/game/mecha/equipment/weapons/energy/phased.dm
new file mode 100644
index 00000000000..423755705f5
--- /dev/null
+++ b/code/game/mecha/equipment/weapons/energy/phased.dm
@@ -0,0 +1,13 @@
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/phase
+ equip_cooldown = 6
+ name = "\improper NT-PE \"Scorpio\" phase-emitter"
+ desc = "A specialist energy weapon intended for use against hostile wildlife."
+ description_fluff = "Essentially an Orion mounted inside a modified Gaia case."
+ icon_state = "mecha_phase"
+ energy_drain = 25
+ projectile = /obj/item/projectile/energy/phase/heavy
+ fire_sound = 'sound/weapons/Taser.ogg'
+
+ equip_type = EQUIP_UTILITY
+
+ origin_tech = list(TECH_MATERIAL = 1, TECH_COMBAT = 2, TECH_MAGNET = 2)
\ No newline at end of file
diff --git a/code/game/mecha/equipment/weapons/energy/pulse.dm b/code/game/mecha/equipment/weapons/energy/pulse.dm
new file mode 100644
index 00000000000..99f7f1d0ce9
--- /dev/null
+++ b/code/game/mecha/equipment/weapons/energy/pulse.dm
@@ -0,0 +1,21 @@
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse
+ equip_cooldown = 30
+ name = "eZ-13 mk2 heavy pulse rifle"
+ desc = "An experimental Anti-Everything weapon."
+ icon_state = "mecha_pulse"
+ energy_drain = 120
+ origin_tech = list(TECH_MATERIAL = 3, TECH_COMBAT = 6, TECH_POWER = 4)
+ projectile = /obj/item/projectile/beam/pulse/heavy
+ fire_sound = 'sound/weapons/gauss_shoot.ogg'
+
+/obj/item/projectile/beam/pulse/heavy
+ name = "heavy pulse laser"
+ icon_state = "pulse1_bl"
+ var/life = 20
+
+/obj/item/projectile/beam/pulse/heavy/Bump(atom/A)
+ A.bullet_act(src, def_zone)
+ src.life -= 10
+ if(life <= 0)
+ qdel(src)
+ return
\ No newline at end of file
diff --git a/code/game/mecha/equipment/weapons/energy/stun.dm b/code/game/mecha/equipment/weapons/energy/stun.dm
new file mode 100644
index 00000000000..f73e4392495
--- /dev/null
+++ b/code/game/mecha/equipment/weapons/energy/stun.dm
@@ -0,0 +1,17 @@
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/taser
+ name = "\improper PBT \"Pacifier\" mounted taser"
+ desc = "A large taser of similar design as those used in standard NT turrets, for use on an Exosuit."
+ icon_state = "mecha_taser"
+ energy_drain = 20
+ equip_cooldown = 8
+ projectile = /obj/item/projectile/beam/stun
+ fire_sound = 'sound/weapons/Taser.ogg'
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/taser/rigged
+ name = "jury-rigged static rifle"
+ desc = "A vaguely functional taser analog, inside an extinguisher casing."
+ icon_state = "mecha_taser-rig"
+ energy_drain = 30
+ projectile = /obj/item/projectile/beam/stun/weak
+
+ equip_type = EQUIP_UTILITY
\ No newline at end of file
diff --git a/code/game/mecha/equipment/weapons/explosive/grenade.dm b/code/game/mecha/equipment/weapons/explosive/grenade.dm
new file mode 100644
index 00000000000..930000fe3a8
--- /dev/null
+++ b/code/game/mecha/equipment/weapons/explosive/grenade.dm
@@ -0,0 +1,70 @@
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade
+ name = "\improper SGL-6 grenade launcher"
+ desc = "A grenade launcher produced for SWAT use; fires flashbangs."
+ icon_state = "mecha_grenadelnchr"
+ projectile = /obj/item/weapon/grenade/flashbang
+ fire_sound = 'sound/effects/bang.ogg'
+ projectiles = 6
+ missile_speed = 1.5
+ projectile_energy_cost = 800
+ equip_cooldown = 60
+ var/det_time = 20
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade/rigged
+ name = "jury-rigged pneumatic flashlauncher"
+ desc = "A grenade launcher constructed out of estranged blueprints; fires flashbangs."
+ icon_state = "mecha_grenadelnchr-rig"
+ projectiles = 3
+ missile_speed = 1
+ det_time = 25
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade/Fire(atom/movable/AM, atom/target, turf/aimloc)
+ var/obj/item/weapon/grenade/G = AM
+ if(istype(G))
+ G.det_time = det_time
+ G.activate(chassis.occupant) //Grenades actually look primed and dangerous, handle their own stuff.
+ AM.throw_at(target,missile_range, missile_speed, chassis)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade/clusterbang//Because I am a heartless bastard -Sieve
+ name = "\improper SOP-6 grenade launcher"
+ desc = "A grenade launcher produced for use by government uprising subjugation forces, or that's what you might guess; fires matryoshka flashbangs."
+ projectile = /obj/item/weapon/grenade/flashbang/clusterbang
+
+ origin_tech = list(TECH_COMBAT= 5, TECH_MATERIAL = 5, TECH_ILLEGAL = 3)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade/clusterbang/limited/get_equip_info()//Limited version of the clusterbang launcher that can't reload
+ return "* [chassis.selected==src?"":""][src.name][chassis.selected==src?"":""]\[[src.projectiles]\]"
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade/clusterbang/limited/rearm()
+ return//Extra bit of security
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade/concussion
+ name = "\improper SGL-9 grenade launcher"
+ desc = "A military-grade grenade launcher that fires disorienting concussion grenades."
+ icon_state = "mecha_grenadelnchr"
+ projectile = /obj/item/weapon/grenade/concussion
+ missile_speed = 1
+ projectile_energy_cost = 900
+ equip_cooldown = 50
+ det_time = 25
+
+ origin_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 4, TECH_ILLEGAL = 1)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade/frag
+ name = "\improper HEP-I 5 grenade launcher"
+ desc = "A military-grade grenade launcher that fires anti-personnel fragmentation grenades."
+ icon_state = "mecha_fraglnchr"
+ projectile = /obj/item/weapon/grenade/explosive
+ projectiles = 4
+ missile_speed = 1
+
+ origin_tech = list(TECH_COMBAT = 5, TECH_ENGINEERING = 5, TECH_MATERIAL = 5, TECH_ILLEGAL = 3)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade/frag/mini
+ name = "\improper HEP-MI 6 grenade launcher"
+ desc = "A military-grade grenade launcher that fires miniaturized anti-personnel fragmentation grenades."
+ projectile = /obj/item/weapon/grenade/explosive/mini
+ projectile_energy_cost = 500
+ equip_cooldown = 25
+
+ origin_tech = list(TECH_COMBAT = 4, TECH_ENGINEERING = 2, TECH_MATERIAL = 3, TECH_ILLEGAL = 2)
diff --git a/code/game/mecha/equipment/weapons/explosive/missile.dm b/code/game/mecha/equipment/weapons/explosive/missile.dm
new file mode 100644
index 00000000000..1c14a8c1dd6
--- /dev/null
+++ b/code/game/mecha/equipment/weapons/explosive/missile.dm
@@ -0,0 +1,80 @@
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack
+ var/missile_speed = 2
+ var/missile_range = 30
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/Fire(atom/movable/AM, atom/target, turf/aimloc)
+ AM.throw_at(target,missile_range, missile_speed, chassis)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flare
+ name = "\improper BNI Flare Launcher"
+ desc = "A flare-gun, but bigger."
+ icon_state = "mecha_flaregun"
+ projectile = /obj/item/device/flashlight/flare
+ fire_sound = 'sound/weapons/tablehit1.ogg'
+ auto_rearm = 1
+ fire_cooldown = 20
+ projectiles_per_shot = 1
+ projectile_energy_cost = 20
+ missile_speed = 1
+ missile_range = 15
+ required_type = /obj/mecha //Why restrict it to just mining or combat mechs?
+
+ equip_type = EQUIP_UTILITY
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flare/Fire(atom/movable/AM, atom/target, turf/aimloc)
+ var/obj/item/device/flashlight/flare/fired = AM
+ fired.ignite()
+ ..()
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/explosive
+ name = "\improper SRM-8 missile rack"
+ desc = "A missile battery that holds eight missiles."
+ icon_state = "mecha_missilerack"
+ projectile = /obj/item/missile
+ fire_sound = 'sound/weapons/rpg.ogg'
+ projectiles = 8
+ projectile_energy_cost = 1000
+ equip_cooldown = 60
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/explosive/Fire(atom/movable/AM, atom/target)
+ var/obj/item/missile/M = AM
+ M.primed = 1
+ ..()
+
+/obj/item/missile
+ icon = 'icons/obj/grenade.dmi'
+ icon_state = "missile"
+ var/primed = null
+ throwforce = 15
+ catchable = 0
+ var/devastation = 0
+ var/heavy_blast = 1
+ var/light_blast = 2
+ var/flash_blast = 4
+ does_spin = FALSE // No fun corkscrew missiles.
+
+/obj/item/missile/proc/warhead_special(var/target)
+ explosion(target, devastation, heavy_blast, light_blast, flash_blast)
+ return
+
+/obj/item/missile/throw_impact(atom/hit_atom)
+ if(primed)
+ warhead_special(hit_atom)
+ qdel(src)
+ else
+ ..()
+ return
+
+/obj/item/missile/light
+ throwforce = 10
+ heavy_blast = 0
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/explosive/rigged
+ name = "jury-rigged rocket pod"
+ desc = "A series of pipes, tubes, and cables that resembles a rocket pod."
+ icon_state = "mecha_missilerack-rig"
+ projectile = /obj/item/missile/light
+ projectiles = 3
+ projectile_energy_cost = 800
+
+ equip_type = EQUIP_UTILITY
\ No newline at end of file
diff --git a/code/game/mecha/equipment/weapons/fire/flamethrower.dm b/code/game/mecha/equipment/weapons/fire/flamethrower.dm
new file mode 100644
index 00000000000..f97f598e243
--- /dev/null
+++ b/code/game/mecha/equipment/weapons/fire/flamethrower.dm
@@ -0,0 +1,27 @@
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/flamer
+ equip_cooldown = 30
+ name = "\improper CR-3 Mark 8"
+ desc = "An imposing device, this weapon hurls balls of fire."
+ description_fluff = "A weapon designed by Hephaestus for anti-infantry combat, the CR-3 is capable of outputting a large volume of synthesized fuel. Initially designed by a small company, later purchased by Aether, on Earth as a device made for clearing underbrush and co-operating with firefighting operations. Obviously, Hephaestus has found an 'improved' use for the Aether designs."
+ icon_state = "mecha_cremate"
+
+ energy_drain = 30
+
+ projectile = /obj/item/projectile/bullet/incendiary/flamethrower/large
+ fire_sound = 'sound/weapons/towelwipe.ogg'
+
+ origin_tech = list(TECH_MATERIAL = 4, TECH_COMBAT = 6, TECH_PHORON = 4, TECH_ILLEGAL = 4)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/flamer/rigged
+ name = "\improper AA-CR-1 Mark 4"
+ description_fluff = "A firefighting tool maintained by Aether Atmospherics, whose initial design originated from a small Earth company. This one seems to have been jury rigged."
+ icon_state = "mecha_cremate-rig"
+
+ energy_drain = 50
+ required_type = list(/obj/mecha/combat, /obj/mecha/working)
+
+ projectile = /obj/item/projectile/bullet/incendiary/flamethrower
+
+ origin_tech = list(TECH_MATERIAL = 3, TECH_COMBAT = 3, TECH_PHORON = 3, TECH_ILLEGAL = 2)
+
+ equip_type = EQUIP_UTILITY
diff --git a/code/game/mecha/equipment/weapons/fire/incendiary.dm b/code/game/mecha/equipment/weapons/fire/incendiary.dm
new file mode 100644
index 00000000000..3d3c1748394
--- /dev/null
+++ b/code/game/mecha/equipment/weapons/fire/incendiary.dm
@@ -0,0 +1,18 @@
+//////////////
+//Fire-based//
+//////////////
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/incendiary
+ name = "\improper DR-AC 3"
+ desc = "Dual-barrel rotary machinegun that fires small, incendiary rounds. Ages ten and up."
+ description_fluff = "A weapon designed by Hephaestus Industries, the DR-AC 3's design was plagued by prototype faults including but not limited to: Spontaneous combustion, spontaneous detonation, and excessive collateral conflagration."
+ icon_state = "mecha_drac3"
+ equip_cooldown = 20
+ projectile = /obj/item/projectile/bullet/incendiary
+ fire_sound = 'sound/weapons/Gunshot_machinegun.ogg'
+ projectiles = 30
+ projectiles_per_shot = 2
+ deviation = 0.4
+ projectile_energy_cost = 40
+ fire_cooldown = 3
+ origin_tech = list(TECH_MATERIAL = 4, TECH_COMBAT = 5, TECH_PHORON = 2, TECH_ILLEGAL = 1)
diff --git a/code/game/mecha/equipment/weapons/honk.dm b/code/game/mecha/equipment/weapons/honk.dm
new file mode 100644
index 00000000000..921111a6cdc
--- /dev/null
+++ b/code/game/mecha/equipment/weapons/honk.dm
@@ -0,0 +1,37 @@
+/obj/item/mecha_parts/mecha_equipment/weapon/honker
+ name = "sound emission device"
+ desc = "A perfectly normal bike-horn, for your exosuit."
+ icon_state = "mecha_honker"
+ energy_drain = 300
+ equip_cooldown = 150
+ origin_tech = list(TECH_MATERIAL = 2, TECH_COMBAT = 4, TECH_ILLEGAL = 1)
+
+ equip_type = EQUIP_SPECIAL
+
+/obj/item/mecha_parts/mecha_equipment/weapon/honker/action(target)
+ if(!chassis)
+ return 0
+ if(energy_drain && chassis.get_charge() < energy_drain)
+ return 0
+ if(!equip_ready)
+ return 0
+
+ playsound(chassis, 'sound/effects/bang.ogg', 30, 1, 30)
+ chassis.occupant_message("You emit a high-pitched noise from the mech.")
+ for(var/mob/living/carbon/M in ohearers(6, chassis))
+ if(istype(M, /mob/living/carbon/human))
+ var/ear_safety = 0
+ ear_safety = M.get_ear_protection()
+ if(ear_safety > 0)
+ return
+ to_chat(M, "Your ears feel like they're bleeding!")
+ playsound(M, 'sound/effects/bang.ogg', 70, 1, 30)
+ M.sleeping = 0
+ M.ear_deaf += 30
+ M.ear_damage += rand(5, 20)
+ M.Weaken(3)
+ M.Stun(5)
+ chassis.use_power(energy_drain)
+ log_message("Used a sound emission device.")
+ do_after_cooldown()
+ return
\ No newline at end of file
diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm
index 5df2c54d10f..cbbc702adf0 100644
--- a/code/game/mecha/equipment/weapons/weapons.dm
+++ b/code/game/mecha/equipment/weapons/weapons.dm
@@ -89,519 +89,4 @@
if(!isnull(M.accuracy))
P.accuracy += M.accuracy
if(!isnull(M.accuracy_dispersion))
- P.dispersion = max(P.dispersion + M.accuracy_dispersion, 0)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy
- name = "general energy weapon"
- auto_rearm = 1
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser
- equip_cooldown = 8
- name = "\improper CH-PS \"Immolator\" laser"
- desc = "A laser carbine's firing system mounted on a high-powered exosuit weapon socket."
- icon_state = "mecha_laser"
- energy_drain = 30
- projectile = /obj/item/projectile/beam
- fire_sound = 'sound/weapons/Laser.ogg'
-
- origin_tech = list(TECH_MATERIAL = 2, TECH_COMBAT = 3, TECH_MAGNET = 3)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/xray
- equip_cooldown = 6
- name = "\improper CH-XS \"Penetrator\" laser"
- desc = "A large, mounted variant of the anti-armor xray rifle."
- icon_state = "mecha_xray"
- energy_drain = 150
- projectile = /obj/item/projectile/beam/xray
- fire_sound = 'sound/weapons/eluger.ogg'
-
- origin_tech = list(TECH_MATERIAL = 3, TECH_COMBAT = 3, TECH_PHORON = 3, TECH_POWER = 3)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/xray/rigged
- equip_cooldown = 12
- name = "jury-rigged xray rifle"
- desc = "A modified wormhole modulation array and meson-scanning control system allow this abomination to produce concentrated blasts of xrays."
- energy_drain = 175
- icon_state = "mecha_xray-rig"
-
- equip_type = EQUIP_UTILITY
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/riggedlaser
- equip_cooldown = 15
- name = "jury-rigged welder-laser"
- desc = "While not regulation, this inefficient weapon can be attached to working exo-suits in desperate, or malicious, times."
- icon_state = "mecha_laser-rig"
- energy_drain = 60
- projectile = /obj/item/projectile/beam
- fire_sound = 'sound/weapons/Laser.ogg'
- required_type = list(/obj/mecha/combat, /obj/mecha/working)
-
- equip_type = EQUIP_UTILITY
-
- origin_tech = list(TECH_MATERIAL = 2, TECH_COMBAT = 2, TECH_MAGNET = 2)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy
- equip_cooldown = 15
- name = "\improper CH-LC \"Solaris\" laser cannon"
- desc = "In the Solaris, the lasing medium is enclosed in a tube lined with plutonium-239 and subjected to extreme neutron flux in a nuclear reactor core. This incredible technology may help YOU achieve high excitation rates with massive laser volumes!"
- icon_state = "mecha_laser"
- energy_drain = 60
- projectile = /obj/item/projectile/beam/heavylaser
- fire_sound = 'sound/weapons/lasercannonfire.ogg'
-
- origin_tech = list(TECH_MATERIAL = 3, TECH_COMBAT = 4, TECH_MAGNET = 4)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/rigged
- equip_cooldown = 25
- name = "jury-rigged emitter cannon"
- desc = "While not regulation, this mining tool can be used as an inefficient weapon on working exo-suits in desperate, or malicious, times."
- icon_state = "mecha_emitter"
- energy_drain = 80
- projectile = /obj/item/projectile/beam/heavylaser/fakeemitter
- fire_sound = 'sound/weapons/emitter.ogg'
-
- equip_type = EQUIP_UTILITY
-
- origin_tech = list(TECH_COMBAT = 4, TECH_MAGNET = 4, TECH_PHORON = 3, TECH_ILLEGAL = 1)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/phase
- equip_cooldown = 6
- name = "\improper NT-PE \"Scorpio\" phase-emitter"
- desc = "A specialist energy weapon intended for use against hostile wildlife."
- description_fluff = "Essentially an Orion mounted inside a modified Gaia case."
- icon_state = "mecha_phase"
- energy_drain = 25
- projectile = /obj/item/projectile/energy/phase/heavy
- fire_sound = 'sound/weapons/Taser.ogg'
-
- equip_type = EQUIP_UTILITY
-
- origin_tech = list(TECH_MATERIAL = 1, TECH_COMBAT = 2, TECH_MAGNET = 2)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/ion
- equip_cooldown = 40
- name = "mkIV ion heavy cannon"
- desc = "An upscaled variant of anti-mechanical weaponry constructed by NT, such as the EW Halicon."
- icon_state = "mecha_ion"
- energy_drain = 120
- projectile = /obj/item/projectile/ion
- fire_sound = 'sound/weapons/Laser.ogg'
-
- origin_tech = list(TECH_MATERIAL = 3, TECH_COMBAT = 4, TECH_MAGNET = 4)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/ion/rigged
- equip_cooldown = 30
- name = "jury-rigged ion cannon"
- desc = "A tesla coil modified to amplify an ionic wave, and use it as a projectile."
- icon_state = "mecha_ion-rig"
- energy_drain = 100
- projectile = /obj/item/projectile/ion/pistol
-
- equip_type = EQUIP_UTILITY
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse
- equip_cooldown = 30
- name = "eZ-13 mk2 heavy pulse rifle"
- desc = "An experimental Anti-Everything weapon."
- icon_state = "mecha_pulse"
- energy_drain = 120
- origin_tech = list(TECH_MATERIAL = 3, TECH_COMBAT = 6, TECH_POWER = 4)
- projectile = /obj/item/projectile/beam/pulse/heavy
- fire_sound = 'sound/weapons/gauss_shoot.ogg'
-
-/obj/item/projectile/beam/pulse/heavy
- name = "heavy pulse laser"
- icon_state = "pulse1_bl"
- var/life = 20
-
-/obj/item/projectile/beam/pulse/heavy/Bump(atom/A)
- A.bullet_act(src, def_zone)
- src.life -= 10
- if(life <= 0)
- qdel(src)
- return
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/taser
- name = "\improper PBT \"Pacifier\" mounted taser"
- desc = "A large taser of similar design as those used in standard NT turrets, for use on an Exosuit."
- icon_state = "mecha_taser"
- energy_drain = 20
- equip_cooldown = 8
- projectile = /obj/item/projectile/beam/stun
- fire_sound = 'sound/weapons/Taser.ogg'
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/taser/rigged
- name = "jury-rigged static rifle"
- desc = "A vaguely functional taser analog, inside an extinguisher casing."
- icon_state = "mecha_taser-rig"
- energy_drain = 30
- projectile = /obj/item/projectile/beam/stun/weak
-
- equip_type = EQUIP_UTILITY
-
-/obj/item/mecha_parts/mecha_equipment/weapon/honker
- name = "sound emission device"
- desc = "A perfectly normal bike-horn, for your exosuit."
- icon_state = "mecha_honker"
- energy_drain = 300
- equip_cooldown = 150
- origin_tech = list(TECH_MATERIAL = 2, TECH_COMBAT = 4, TECH_ILLEGAL = 1)
-
- equip_type = EQUIP_SPECIAL
-
-/obj/item/mecha_parts/mecha_equipment/weapon/honker/action(target)
- if(!chassis)
- return 0
- if(energy_drain && chassis.get_charge() < energy_drain)
- return 0
- if(!equip_ready)
- return 0
-
- playsound(chassis, 'sound/effects/bang.ogg', 30, 1, 30)
- chassis.occupant_message("You emit a high-pitched noise from the mech.")
- for(var/mob/living/carbon/M in ohearers(6, chassis))
- if(istype(M, /mob/living/carbon/human))
- var/ear_safety = 0
- ear_safety = M.get_ear_protection()
- if(ear_safety > 0)
- return
- to_chat(M, "Your ears feel like they're bleeding!")
- playsound(M, 'sound/effects/bang.ogg', 70, 1, 30)
- M.sleeping = 0
- M.ear_deaf += 30
- M.ear_damage += rand(5, 20)
- M.Weaken(3)
- M.Stun(5)
- chassis.use_power(energy_drain)
- log_message("Used a sound emission device.")
- do_after_cooldown()
- return
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic
- name = "general ballisic weapon"
- var/projectile_energy_cost
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/get_equip_info()
- return "[..()]\[[src.projectiles]\][(src.projectiles < initial(src.projectiles))?" - Rearm":null]"
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/proc/rearm()
- if(projectiles < initial(projectiles))
- var/projectiles_to_add = initial(projectiles) - projectiles
- while(chassis.get_charge() >= projectile_energy_cost && projectiles_to_add)
- projectiles++
- projectiles_to_add--
- chassis.use_power(projectile_energy_cost)
- send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
- log_message("Rearmed [src.name].")
- return
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/Topic(href, href_list)
- ..()
- if (href_list["rearm"])
- src.rearm()
- return
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/mortar
- name = "\improper HEP RC 4 \"Skyfall\""
- desc = "A Hephaestus exosuit-mounted mortar for use on planetary-or-similar bodies."
- description_info = "This weapon cannot be fired indoors, underground, or on-station."
- icon_state = "mecha_mortar"
- equip_cooldown = 30
- fire_sound = 'sound/weapons/Gunshot_cannon.ogg'
- fire_volume = 100
- projectiles = 3
- deviation = 0.6
- projectile = /obj/item/projectile/arc/fragmentation/mortar
- projectile_energy_cost = 600
-
- origin_tech = list(TECH_MATERIAL = 4, TECH_COMBAT = 5, TECH_ILLEGAL = 3)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/mortar/action_checks(atom/target)
- var/turf/MT = get_turf(chassis)
- var/turf/TT = get_turf(target)
- if(!MT.outdoors || !TT.outdoors)
- to_chat(chassis.occupant, "\The [src]'s control system prevents you from firing due to a blocked firing arc.")
- return 0
- return ..()
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot
- name = "\improper LBX AC 10 \"Scattershot\""
- desc = "A massive shotgun designed to fill a large area with pellets."
- icon_state = "mecha_scatter"
- equip_cooldown = 20
- projectile = /obj/item/projectile/bullet/pellet/shotgun/flak
- fire_sound = 'sound/weapons/Gunshot_shotgun.ogg'
- fire_volume = 80
- projectiles = 40
- projectiles_per_shot = 4
- deviation = 0.7
- projectile_energy_cost = 25
-
- origin_tech = list(TECH_MATERIAL = 3, TECH_COMBAT = 4)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot/rigged
- name = "jury-rigged shrapnel cannon"
- desc = "The remains of some unfortunate RCD now doomed to kill, rather than construct."
- icon_state = "mecha_scatter-rig"
- equip_cooldown = 30
- fire_volume = 100
- projectiles = 20
- deviation = 1
-
- equip_type = EQUIP_UTILITY
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg
- name = "\improper Ultra AC 2"
- desc = "A superior version of the standard Solgov Autocannon MK2 design."
- icon_state = "mecha_uac2"
- equip_cooldown = 10
- projectile = /obj/item/projectile/bullet/pistol/medium
- fire_sound = 'sound/weapons/Gunshot_machinegun.ogg'
- projectiles = 30 //10 bursts, matching the Scattershot's 10. Also, conveniently, doesn't eat your powercell when reloading like 300 bullets does.
- projectiles_per_shot = 3
- deviation = 0.3
- projectile_energy_cost = 20
- fire_cooldown = 2
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg/rigged
- name = "jury-rigged machinegun"
- desc = "The cross between a jackhammer and a whole lot of zipguns."
- icon_state = "mecha_uac2-rig"
- equip_cooldown = 12
- projectile = /obj/item/projectile/bullet/pistol
- deviation = 0.5
-
- equip_type = EQUIP_UTILITY
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack
- var/missile_speed = 2
- var/missile_range = 30
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/Fire(atom/movable/AM, atom/target, turf/aimloc)
- AM.throw_at(target,missile_range, missile_speed, chassis)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flare
- name = "\improper BNI Flare Launcher"
- desc = "A flare-gun, but bigger."
- icon_state = "mecha_flaregun"
- projectile = /obj/item/device/flashlight/flare
- fire_sound = 'sound/weapons/tablehit1.ogg'
- auto_rearm = 1
- fire_cooldown = 20
- projectiles_per_shot = 1
- projectile_energy_cost = 20
- missile_speed = 1
- missile_range = 15
- required_type = /obj/mecha //Why restrict it to just mining or combat mechs?
-
- equip_type = EQUIP_UTILITY
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flare/Fire(atom/movable/AM, atom/target, turf/aimloc)
- var/obj/item/device/flashlight/flare/fired = AM
- fired.ignite()
- ..()
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/explosive
- name = "\improper SRM-8 missile rack"
- desc = "A missile battery that holds eight missiles."
- icon_state = "mecha_missilerack"
- projectile = /obj/item/missile
- fire_sound = 'sound/weapons/rpg.ogg'
- projectiles = 8
- projectile_energy_cost = 1000
- equip_cooldown = 60
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/explosive/Fire(atom/movable/AM, atom/target)
- var/obj/item/missile/M = AM
- M.primed = 1
- ..()
-
-/obj/item/missile
- icon = 'icons/obj/grenade.dmi'
- icon_state = "missile"
- var/primed = null
- throwforce = 15
- catchable = 0
- var/devastation = 0
- var/heavy_blast = 1
- var/light_blast = 2
- var/flash_blast = 4
- does_spin = FALSE // No fun corkscrew missiles.
-
-/obj/item/missile/proc/warhead_special(var/target)
- explosion(target, devastation, heavy_blast, light_blast, flash_blast)
- return
-
-/obj/item/missile/throw_impact(atom/hit_atom)
- if(primed)
- warhead_special(hit_atom)
- qdel(src)
- else
- ..()
- return
-
-/obj/item/missile/light
- throwforce = 10
- heavy_blast = 0
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/explosive/rigged
- name = "jury-rigged rocket pod"
- desc = "A series of pipes, tubes, and cables that resembles a rocket pod."
- icon_state = "mecha_missilerack-rig"
- projectile = /obj/item/missile/light
- projectiles = 3
- projectile_energy_cost = 800
-
- equip_type = EQUIP_UTILITY
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade
- name = "\improper SGL-6 grenade launcher"
- desc = "A grenade launcher produced for SWAT use; fires flashbangs."
- icon_state = "mecha_grenadelnchr"
- projectile = /obj/item/weapon/grenade/flashbang
- fire_sound = 'sound/effects/bang.ogg'
- projectiles = 6
- missile_speed = 1.5
- projectile_energy_cost = 800
- equip_cooldown = 60
- var/det_time = 20
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade/rigged
- name = "jury-rigged pneumatic flashlauncher"
- desc = "A grenade launcher constructed out of estranged blueprints; fires flashbangs."
- icon_state = "mecha_grenadelnchr-rig"
- projectiles = 3
- missile_speed = 1
- det_time = 25
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade/Fire(atom/movable/AM, atom/target, turf/aimloc)
- var/obj/item/weapon/grenade/G = AM
- if(istype(G))
- G.det_time = det_time
- G.activate(chassis.occupant) //Grenades actually look primed and dangerous, handle their own stuff.
- AM.throw_at(target,missile_range, missile_speed, chassis)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade/clusterbang//Because I am a heartless bastard -Sieve
- name = "\improper SOP-6 grenade launcher"
- desc = "A grenade launcher produced for use by government uprising subjugation forces, or that's what you might guess; fires matryoshka flashbangs."
- projectile = /obj/item/weapon/grenade/flashbang/clusterbang
-
- origin_tech = list(TECH_COMBAT= 5, TECH_MATERIAL = 5, TECH_ILLEGAL = 3)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade/clusterbang/limited/get_equip_info()//Limited version of the clusterbang launcher that can't reload
- return "* [chassis.selected==src?"":""][src.name][chassis.selected==src?"":""]\[[src.projectiles]\]"
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade/clusterbang/limited/rearm()
- return//Extra bit of security
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade/concussion
- name = "\improper SGL-9 grenade launcher"
- desc = "A military-grade grenade launcher that fires disorienting concussion grenades."
- icon_state = "mecha_grenadelnchr"
- projectile = /obj/item/weapon/grenade/concussion
- missile_speed = 1
- projectile_energy_cost = 900
- equip_cooldown = 50
- det_time = 25
-
- origin_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 4, TECH_ILLEGAL = 1)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade/frag
- name = "\improper HEP-I 5 grenade launcher"
- desc = "A military-grade grenade launcher that fires anti-personnel fragmentation grenades."
- icon_state = "mecha_fraglnchr"
- projectile = /obj/item/weapon/grenade/explosive
- projectiles = 4
- missile_speed = 1
-
- origin_tech = list(TECH_COMBAT = 5, TECH_ENGINEERING = 5, TECH_MATERIAL = 5, TECH_ILLEGAL = 3)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/grenade/frag/mini
- name = "\improper HEP-MI 6 grenade launcher"
- desc = "A military-grade grenade launcher that fires miniaturized anti-personnel fragmentation grenades."
- projectile = /obj/item/weapon/grenade/explosive/mini
- projectile_energy_cost = 500
- equip_cooldown = 25
-
- origin_tech = list(TECH_COMBAT = 4, TECH_ENGINEERING = 2, TECH_MATERIAL = 3, TECH_ILLEGAL = 2)
-
-//////////////
-//Fire-based//
-//////////////
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/incendiary
- name = "\improper DR-AC 3"
- desc = "Dual-barrel rotary machinegun that fires small, incendiary rounds. Ages ten and up."
- description_fluff = "A weapon designed by Hephaestus Industries, the DR-AC 3's design was plagued by prototype faults including but not limited to: Spontaneous combustion, spontaneous detonation, and excessive collateral conflagration."
- icon_state = "mecha_drac3"
- equip_cooldown = 20
- projectile = /obj/item/projectile/bullet/incendiary
- fire_sound = 'sound/weapons/Gunshot_machinegun.ogg'
- projectiles = 30
- projectiles_per_shot = 2
- deviation = 0.4
- projectile_energy_cost = 40
- fire_cooldown = 3
- origin_tech = list(TECH_MATERIAL = 4, TECH_COMBAT = 5, TECH_PHORON = 2, TECH_ILLEGAL = 1)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/flamer
- equip_cooldown = 30
- name = "\improper CR-3 Mark 8"
- desc = "An imposing device, this weapon hurls balls of fire."
- description_fluff = "A weapon designed by Hephaestus for anti-infantry combat, the CR-3 is capable of outputting a large volume of synthesized fuel. Initially designed by a small company, later purchased by Aether, on Earth as a device made for clearing underbrush and co-operating with firefighting operations. Obviously, Hephaestus has found an 'improved' use for the Aether designs."
- icon_state = "mecha_cremate"
-
- energy_drain = 30
-
- projectile = /obj/item/projectile/bullet/incendiary/flamethrower/large
- fire_sound = 'sound/weapons/towelwipe.ogg'
-
- origin_tech = list(TECH_MATERIAL = 4, TECH_COMBAT = 6, TECH_PHORON = 4, TECH_ILLEGAL = 4)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/flamer/rigged
- name = "\improper AA-CR-1 Mark 4"
- description_fluff = "A firefighting tool maintained by Aether Atmospherics, whose initial design originated from a small Earth company. This one seems to have been jury rigged."
- icon_state = "mecha_cremate-rig"
-
- energy_drain = 50
- required_type = list(/obj/mecha/combat, /obj/mecha/working)
-
- projectile = /obj/item/projectile/bullet/incendiary/flamethrower
-
- origin_tech = list(TECH_MATERIAL = 3, TECH_COMBAT = 3, TECH_PHORON = 3, TECH_ILLEGAL = 2)
-
- equip_type = EQUIP_UTILITY
-
-//////////////
-//Defensive//
-//////////////
-
-/obj/item/mecha_parts/mecha_equipment/shocker
- name = "exosuit electrifier"
- desc = "A device to electrify the external portions of a mecha in order to increase its defensive capabilities."
- icon_state = "mecha_coil"
- equip_cooldown = 10
- energy_drain = 100
- range = RANGED
- origin_tech = list(TECH_COMBAT = 3, TECH_POWER = 6)
- var/shock_damage = 15
- var/active
-
- equip_type = EQUIP_HULL
-
-/obj/item/mecha_parts/mecha_equipment/shocker/can_attach(obj/mecha/M as obj)
- if(..())
- if(!M.proc_res["dynattackby"] && !M.proc_res["dynattackhand"] && !M.proc_res["dynattackalien"])
- return 1
- return 0
-
-/obj/item/mecha_parts/mecha_equipment/shocker/attach(obj/mecha/M as obj)
- ..()
- chassis.proc_res["dynattackby"] = src
- return
-
-/obj/item/mecha_parts/mecha_equipment/shocker/proc/dynattackby(obj/item/weapon/W, mob/living/user)
- if(!action_checks(user) || !active)
- return
- user.electrocute_act(shock_damage, src)
- return chassis.dynattackby(W,user)
+ P.dispersion = max(P.dispersion + M.accuracy_dispersion, 0)
\ No newline at end of file
diff --git a/code/game/mecha/medical/odysseus.dm b/code/game/mecha/medical/odysseus.dm
index b3b9faa37de..1f90a45d613 100644
--- a/code/game/mecha/medical/odysseus.dm
+++ b/code/game/mecha/medical/odysseus.dm
@@ -123,7 +123,7 @@
C.images += holder
*/
-/obj/mecha/medical/odysseus/loaded/New()
+/obj/mecha/medical/odysseus/loaded/Initialize()
..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/tool/sleeper
ME.attach(src)
diff --git a/code/game/mecha/space/hoverpod.dm b/code/game/mecha/space/hoverpod.dm
index 85fc59d564b..31558458d99 100644
--- a/code/game/mecha/space/hoverpod.dm
+++ b/code/game/mecha/space/hoverpod.dm
@@ -105,7 +105,7 @@
max_universal_equip = 1
max_special_equip = 1
-/obj/mecha/working/hoverpod/combatpod/New()
+/obj/mecha/working/hoverpod/combatpod/Initialize()
..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser
ME.attach(src)
@@ -116,7 +116,7 @@
/obj/mecha/working/hoverpod/shuttlepod
desc = "Who knew a tiny ball could fit three people?"
-/obj/mecha/working/hoverpod/shuttlepod/New()
+/obj/mecha/working/hoverpod/shuttlepod/Initialize()
..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/tool/passenger
ME.attach(src)
diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm
index c4813bb0dd3..938a720c4f2 100644
--- a/code/game/mecha/working/ripley.dm
+++ b/code/game/mecha/working/ripley.dm
@@ -54,9 +54,9 @@
max_universal_equip = 1
max_special_equip = 1
-/obj/mecha/working/ripley/deathripley/New()
+/obj/mecha/working/ripley/deathripley/Initialize()
..()
- var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/tool/safety_clamp
+ var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp/safety
ME.attach(src)
return
@@ -64,7 +64,7 @@
desc = "An old, dusty mining ripley."
name = "APLU \"Miner\""
-/obj/mecha/working/ripley/mining/New()
+/obj/mecha/working/ripley/mining/Initialize()
..()
//Attach drill
if(prob(25)) //Possible diamond drill... Feeling lucky?
diff --git a/code/game/objects/effects/alien/aliens.dm b/code/game/objects/effects/alien/aliens.dm
index 0de8d332b71..bdcbe95e7f1 100644
--- a/code/game/objects/effects/alien/aliens.dm
+++ b/code/game/objects/effects/alien/aliens.dm
@@ -152,6 +152,12 @@
* Weeds
*/
#define NODERANGE 3
+#define WEED_NORTH_EDGING "north"
+#define WEED_SOUTH_EDGING "south"
+#define WEED_EAST_EDGING "east"
+#define WEED_WEST_EDGING "west"
+#define WEED_NODE_GLOW "glow"
+#define WEED_NODE_BASE "nodebase"
/obj/effect/alien/weeds
name = "weeds"
@@ -164,6 +170,18 @@
layer = ABOVE_TURF_LAYER
var/health = 15
var/obj/effect/alien/weeds/node/linked_node = null
+ var/static/list/weedImageCache
+
+/obj/effect/alien/weeds/Destroy()
+ var/turf/T = get_turf(src)
+ // To not mess up the overlay updates.
+ loc = null
+
+ for (var/obj/effect/alien/weeds/W in range(1,T))
+ W.updateWeedOverlays()
+
+ linked_node = null
+ ..()
/obj/effect/alien/weeds/node
icon_state = "weednode"
@@ -173,9 +191,22 @@
light_range = NODERANGE
var/node_range = NODERANGE
+ var/set_color = null
+
/obj/effect/alien/weeds/node/New()
..(src.loc, src)
+/obj/effect/alien/weeds/node/Initialize()
+ ..()
+ START_PROCESSING(SSobj, src)
+
+ spawn(1 SECOND)
+ if(color)
+ set_color = color
+
+/obj/effect/alien/weeds/node/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ ..()
/obj/effect/alien/weeds/New(pos, node)
..()
@@ -184,12 +215,45 @@
return
linked_node = node
if(icon_state == "weeds")icon_state = pick("weeds", "weeds1", "weeds2")
- spawn(rand(150, 200))
- if(src)
- Life()
+
+ fullUpdateWeedOverlays()
+
+/obj/effect/alien/weeds/proc/updateWeedOverlays()
+
+ overlays.Cut()
+
+ if(!weedImageCache || !weedImageCache.len)
+ weedImageCache = list()
+// weedImageCache.len = 4
+ weedImageCache[WEED_NORTH_EDGING] = image('icons/mob/alien.dmi', "weeds_side_n", layer=2.11, pixel_y = -32)
+ weedImageCache[WEED_SOUTH_EDGING] = image('icons/mob/alien.dmi', "weeds_side_s", layer=2.11, pixel_y = 32)
+ weedImageCache[WEED_EAST_EDGING] = image('icons/mob/alien.dmi', "weeds_side_e", layer=2.11, pixel_x = -32)
+ weedImageCache[WEED_WEST_EDGING] = image('icons/mob/alien.dmi', "weeds_side_w", layer=2.11, pixel_x = 32)
+
+ var/turf/N = get_step(src, NORTH)
+ var/turf/S = get_step(src, SOUTH)
+ var/turf/E = get_step(src, EAST)
+ var/turf/W = get_step(src, WEST)
+ if(!locate(/obj/effect/alien) in N.contents)
+ if(istype(N, /turf/simulated/floor))
+ overlays += weedImageCache[WEED_SOUTH_EDGING]
+ if(!locate(/obj/effect/alien) in S.contents)
+ if(istype(S, /turf/simulated/floor))
+ overlays += weedImageCache[WEED_NORTH_EDGING]
+ if(!locate(/obj/effect/alien) in E.contents)
+ if(istype(E, /turf/simulated/floor))
+ overlays += weedImageCache[WEED_WEST_EDGING]
+ if(!locate(/obj/effect/alien) in W.contents)
+ if(istype(W, /turf/simulated/floor))
+ overlays += weedImageCache[WEED_EAST_EDGING]
+
+/obj/effect/alien/weeds/proc/fullUpdateWeedOverlays()
+ for (var/obj/effect/alien/weeds/W in range(1,src))
+ W.updateWeedOverlays()
+
return
-/obj/effect/alien/weeds/proc/Life()
+/obj/effect/alien/weeds/process()
set background = 1
var/turf/U = get_turf(src)
/*
@@ -211,6 +275,9 @@ Alien plants should do something if theres a lot of poison
if(!linked_node || (get_dist(linked_node, src) > linked_node.node_range) )
return
+ if(linked_node != src)
+ color = linked_node.set_color
+
direction_loop:
for(var/dirn in cardinal)
var/turf/T = get_step(src, dirn)
@@ -222,10 +289,33 @@ Alien plants should do something if theres a lot of poison
// continue
for(var/obj/O in T)
- if(O.density)
+ if(!O.CanZASPass(U))
continue direction_loop
- new /obj/effect/alien/weeds(T, linked_node)
+ var/obj/effect/E = new /obj/effect/alien/weeds(T, linked_node)
+
+ E.color = color
+
+ if(istype(src, /obj/effect/alien/weeds/node))
+ var/obj/effect/alien/weeds/node/N = src
+ var/list/nearby_weeds = list()
+ for(var/obj/effect/alien/weeds/W in range(N.node_range,src))
+ nearby_weeds |= W
+
+ for(var/obj/effect/alien/weeds/W in nearby_weeds)
+ if(!W)
+ continue
+
+ if(!W.linked_node)
+ W.linked_node = src
+
+ W.color = W.linked_node.set_color
+
+ if(W == src)
+ continue
+
+ if(prob(max(10, 40 - (5 * nearby_weeds.len))))
+ W.process()
/obj/effect/alien/weeds/ex_act(severity)
@@ -282,7 +372,12 @@ Alien plants should do something if theres a lot of poison
healthcheck()
#undef NODERANGE
-
+#undef WEED_NORTH_EDGING
+#undef WEED_SOUTH_EDGING
+#undef WEED_EAST_EDGING
+#undef WEED_WEST_EDGING
+#undef WEED_NODE_GLOW
+#undef WEED_NODE_BASE
/*
* Acid
diff --git a/code/game/objects/effects/chem/foam.dm b/code/game/objects/effects/chem/foam.dm
index f32a75dccea..d3ee7362518 100644
--- a/code/game/objects/effects/chem/foam.dm
+++ b/code/game/objects/effects/chem/foam.dm
@@ -74,6 +74,12 @@
qdel(src)
/obj/effect/effect/foam/Crossed(var/atom/movable/AM)
+ //VOREStation Edit begin: SHADEKIN
+ var/mob/SK = AM
+ if(istype(SK))
+ if(SK.shadekin_phasing_check())
+ return
+ //VOREStation Edit end: SHADEKIN
if(metal)
return
if(istype(AM, /mob/living))
diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm
index 8b8bba5a9dd..cfde668d5cc 100644
--- a/code/game/objects/effects/decals/Cleanable/humans.dm
+++ b/code/game/objects/effects/decals/Cleanable/humans.dm
@@ -70,6 +70,12 @@ var/global/list/image/splatter_cache=list()
desc = initial(desc)
/obj/effect/decal/cleanable/blood/Crossed(mob/living/carbon/human/perp)
+ //VOREStation Edit begin: SHADEKIN
+ var/mob/SK = perp
+ if(istype(SK))
+ if(SK.shadekin_phasing_check())
+ return
+ //VOREStation Edit end: SHADEKIN
if (!istype(perp))
return
if(amount < 1)
@@ -199,10 +205,10 @@ var/global/list/image/splatter_cache=list()
overlays += giblets
/obj/effect/decal/cleanable/blood/gibs/up
- random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibup1","gibup1","gibup1")
+ random_icon_states = list("gib1", "gib2", "gib3", "gib5", "gib6","gibup1","gibup1","gibup1")
/obj/effect/decal/cleanable/blood/gibs/down
- random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibdown1","gibdown1","gibdown1")
+ random_icon_states = list("gib1", "gib2", "gib3", "gib5", "gib6","gibdown1","gibdown1","gibdown1")
/obj/effect/decal/cleanable/blood/gibs/body
random_icon_states = list("gibhead", "gibtorso")
diff --git a/code/game/objects/effects/decals/contraband.dm b/code/game/objects/effects/decals/contraband.dm
index c98cacb7857..d765c479fb2 100644
--- a/code/game/objects/effects/decals/contraband.dm
+++ b/code/game/objects/effects/decals/contraband.dm
@@ -12,14 +12,16 @@
name = "rolled-up poster"
desc = "The poster comes with its own automatic adhesive mechanism, for easy pinning to any vertical surface."
icon_state = "rolled_poster"
- var/serial_number = 0
+ var/serial_number = null
+ var/poster_type = /obj/structure/sign/poster
/obj/item/weapon/contraband/poster/New(turf/loc, var/given_serial = 0)
- if(given_serial == 0)
- serial_number = rand(1, poster_designs.len)
- else
- serial_number = given_serial
+ if(!serial_number)
+ if(given_serial == 0)
+ serial_number = rand(1, poster_designs.len)
+ else
+ serial_number = given_serial
name += " - No. [serial_number]"
..(loc)
@@ -57,7 +59,7 @@
user << "You start placing the poster on the wall..." //Looks like it's uncluttered enough. Place the poster.
- var/obj/structure/sign/poster/P = new(user.loc, placement_dir=get_dir(user, W), serial=serial_number)
+ var/obj/structure/sign/poster/P = new poster_type(user.loc, placement_dir=get_dir(user, W), serial=serial_number, itemtype = src.type)
flick("poster_being_set", P)
//playsound(W, 'sound/items/poster_being_created.ogg', 100, 1) //why the hell does placing a poster make printer sounds?
@@ -74,6 +76,18 @@
qdel(oldsrc) //delete it now to cut down on sanity checks afterwards. Agouri's code supports rerolling it anyway
+//NT subtype
+/obj/item/weapon/contraband/poster/nanotrasen
+ icon_state = "rolled_poster_nt"
+ poster_type = /obj/structure/sign/poster/nanotrasen
+
+/obj/item/weapon/contraband/poster/nanotrasen/New(turf/loc, var/given_serial = 0)
+ if(given_serial == 0)
+ serial_number = rand(1, NT_poster_designs.len)
+ else
+ serial_number = given_serial
+ ..(loc)
+
//############################## THE ACTUAL DECALS ###########################
/obj/structure/sign/poster
@@ -85,15 +99,22 @@
var/poster_type //So mappers can specify a desired poster
var/ruined = 0
-/obj/structure/sign/poster/New(var/newloc, var/placement_dir=null, var/serial=null)
+ var/roll_type
+ var/poster_set = FALSE
+
+/obj/structure/sign/poster/New(var/newloc, var/placement_dir=null, var/serial=null, var/itemtype = /obj/item/weapon/contraband/poster)
..(newloc)
if(!serial)
serial = rand(1, poster_designs.len) //use a random serial if none is given
- serial_number = serial
- var/datum/poster/design = poster_designs[serial_number]
- set_poster(design)
+ if(!poster_set)
+ serial_number = serial
+ var/datum/poster/design = poster_designs[serial_number]
+ set_poster(design)
+
+ if(itemtype || !roll_type)
+ roll_type = itemtype
switch (placement_dir)
if (NORTH)
@@ -121,6 +142,8 @@
desc = "[initial(desc)] [design.desc]"
icon_state = design.icon_state // poster[serial_number]
+ poster_set = TRUE
+
/obj/structure/sign/poster/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(W.is_wirecutter())
playsound(src.loc, W.usesound, 100, 1)
@@ -132,7 +155,6 @@
roll_and_drop(user.loc)
return
-
/obj/structure/sign/poster/attack_hand(mob/user as mob)
if(ruined)
@@ -152,7 +174,7 @@
add_fingerprint(user)
/obj/structure/sign/poster/proc/roll_and_drop(turf/newloc)
- var/obj/item/weapon/contraband/poster/P = new(src, serial_number)
+ var/obj/item/weapon/contraband/poster/P = new roll_type(src, serial_number)
P.loc = newloc
src.loc = P
qdel(src)
@@ -163,3 +185,17 @@
// Description suffix
var/desc=""
var/icon_state=""
+
+// NT poster subtype.
+/obj/structure/sign/poster/nanotrasen
+ roll_type = /obj/item/weapon/contraband/poster/nanotrasen
+
+/obj/structure/sign/poster/nanotrasen/New(var/newloc, var/placement_dir=null, var/serial=null, var/itemtype = /obj/item/weapon/contraband/poster/nanotrasen)
+ if(!serial)
+ serial = rand(1, NT_poster_designs.len)
+
+ serial_number = serial
+ var/datum/poster/design = NT_poster_designs[serial_number]
+ set_poster(design)
+
+ ..(newloc, placement_dir, serial, itemtype)
diff --git a/code/game/objects/effects/decals/posters/polarisposters.dm b/code/game/objects/effects/decals/posters/polarisposters.dm
index 958ceb66bea..d40cdd0db0f 100644
--- a/code/game/objects/effects/decals/posters/polarisposters.dm
+++ b/code/game/objects/effects/decals/posters/polarisposters.dm
@@ -43,4 +43,175 @@
name = "Airlock Maintenance Reference"
desc = "This poster appears to be reference material for maintenance personnel, instructing to always wear insulated gloves, that wirecutters and \
a multitool are the optimal tools to use, and where to find the maintenance panel on most airlocks. Unfortunately, the poster does not mention any \
- wire codes."
\ No newline at end of file
+ wire codes."
+
+/datum/poster/pol_10
+ icon_state="polposter9"
+ name = "orchid"
+ desc = "This poster appears strangely familiar, depicting the flower of a tree native to the planet Earth."
+
+// A new subset of poster datum for Security posters.
+/datum/poster/nanotrasen
+ icon_state = "polposter1"
+ name = "Safety!"
+ desc = "A poster advising you to learn how to put on your internals at a moment's notice."
+
+/datum/poster/nanotrasen/pol_2
+ icon_state="polposter2"
+ name = "Safety!"
+ desc = "A blue and white colored poster. This one advises you to wear your safety goggles when handling chemicals."
+
+/datum/poster/nanotrasen/pol_3
+ icon_state="polposter3"
+ name = "Safety!"
+ desc = "A safety poster instructing you to comply with the authorities, especially in an emergency."
+
+/datum/poster/nanotrasen/pol_4
+ icon_state="polposter4"
+ name = "Clean Hands Save Lives"
+ desc = "A safety poster reminding you to wash your hands."
+
+/datum/poster/nanotrasen/pol_5
+ icon_state="polposter5"
+ name = "Help!"
+ desc = "This poster depicts a man helping another man get up."
+
+/datum/poster/nanotrasen/pol_6
+ icon_state="polposter6"
+ name = "Walk!"
+ desc = "This poster depicts a man walking, presumably to encourage you not to run in the halls."
+
+/datum/poster/nanotrasen/pol_7
+ icon_state="polposter7"
+ name = "Place your signs!"
+ desc = "A safety poster reminding custodial staff to place wet floor signs where needed. This reminder's rarely heeded."
+
+/datum/poster/nanotrasen/pol_8
+ icon_state="polposter8"
+ name = "Safety!"
+ desc = "An advertisement / safety poster for EVA training and certification. Training is available at your local Central Command."
+
+/datum/poster/nanotrasen/pol_9
+ icon_state="poster10"
+ name = "Airlock Maintenance Reference"
+ desc = "This poster appears to be reference material for maintenance personnel, instructing to always wear insulated gloves, that wirecutters and \
+ a multitool are the optimal tools to use, and where to find the maintenance panel on most airlocks. Unfortunately, the poster does not mention any \
+ wire codes."
+
+/datum/poster/nanotrasen/pol_10
+ icon_state="polposter9"
+ name = "orchid"
+ desc = "This poster suggests a feeling of peace. It depicts the flower of a tree native to the planet Earth."
+
+/datum/poster/nanotrasen/bay_9
+ icon_state="bsposter9"
+ name = "Pinup Girl Amy"
+ desc = "This particular one is of Amy, the nymphomaniac urban legend of deep space. How this photograph came to be is not known."
+
+/datum/poster/nanotrasen/bay_21
+ icon_state="bsposter21"
+ name = "Join the Fuzz!"
+ desc = "It's a nice recruitment poster of a white haired Chinese woman that says; \"Big Guns, Hot Women, Good Times. Security. We get it done.\""
+
+/datum/poster/nanotrasen/bay_22
+ icon_state="bsposter22"
+ name = "Looking for a career with excitement?"
+ desc = "A recruitment poster starring a dark haired woman with glasses and a purple shirt that has \"Got Brains? Got Talent? Not afraid of electric flying monsters that want to suck the soul out of you? Then Xenobiology could use someone like you!\" written on the bottom."
+
+/datum/poster/nanotrasen/bay_23
+ icon_state="bsposter23"
+ name = "Safety first: because electricity doesn't wait!"
+ desc = "A safety poster starring a clueless looking redhead with frazzled hair. \"Every year, hundreds of NT employees expose themselves to electric shock. Play it safe. Avoid suspicious doors after electrical storms, and always wear protection when doing electric maintenance.\""
+
+/datum/poster/nanotrasen/bay_24
+ icon_state="bsposter24"
+ name = "Responsible medbay habits, No #259"
+ desc = "A poster with a nervous looking geneticist on it states; \"Friends Tell Friends They're Clones. It can cause severe and irreparable emotional trauma if a person is not properly informed of their recent demise. Always follow your contractual obligation and inform them of their recent rejuvenation.\""
+
+/datum/poster/nanotrasen/bay_25
+ icon_state="bsposter25"
+ name = "Irresponsible medbay habits, No #2"
+ desc = "This is a safety poster starring a perverted looking naked doctor. \"Sexual harassment is never okay. REPORT any acts of sexual deviance or harassment that disrupt a healthy working environment.\""
+
+/datum/poster/nanotrasen/bay_49
+ icon_state="bsposter49"
+ name = "Engineering recruitment"
+ desc = "This is a poster showing an engineer relaxing by a computer, the text states \"Living the life! Join Engineering today!\""
+
+/datum/poster/nanotrasen/bay_52
+ icon_state="bsposter52"
+ name = "fire safety poster"
+ desc = "This is a poster reminding you of what you should do if you are on fire, or if you are at a dance party."
+
+/datum/poster/nanotrasen/bay_53
+ icon_state="bsposter53"
+ name = "fire extinguisher poster"
+ desc = "This is a poster reminding you of what you should use to put out a fire."
+
+/datum/poster/nanotrasen/bay_54
+ icon_state="bsposter54"
+ name = "firefighter poster"
+ desc = "This is a poster of a particularly stern looking firefighter. The caption reads, \"Only you can prevent space fires.\""
+
+/datum/poster/nanotrasen/bay_57
+ icon_state="bsposter57"
+ name = "space carp warning poster"
+ desc = "This poster tells of the dangers of space carp infestations."
+
+/datum/poster/nanotrasen/bay_58
+ icon_state="bsposter58"
+ name = "space carp information poster"
+ desc = "This poster showcases an old spacer saying on the dangers of migrant space carp."
+
+/datum/poster/nanotrasen/nt_1
+ icon_state = "ntposter01"
+ name = "Security recruitment"
+ desc = "This poster showcases an NT security guard in an excited pose, with a small blurb about the importance of Security."
+
+/datum/poster/nanotrasen/nt_2
+ icon_state = "ntposter02"
+ name = "Security recruitment"
+ desc = "This poster showcases an NT security guard in an excited pose, with a small blurb about Security Employee benefits."
+
+/datum/poster/nanotrasen/nt_3
+ icon_state = "ntposter03"
+ name = "Mechatronic Safety"
+ desc = "This poster displays three cutting-edge gygaxes standing in line in front of a man in plain clothes.\
+ The poster's captions explain the importance of knowing how to operate a mechatronic vehicle safely, especially near other personnel.\
+ The image seems important."
+
+//VOREStation Removal Start TFF 17/12/19 - lore not used in our station's own lore.
+/*
+/datum/poster/nanotrasen/nt_4
+ icon_state = "ntposter04"
+ name = "Beware Aetotheans"
+ desc = "This poster displays a distinctly hostile-looking red Promethean in a black coat. The fine-print around the edges warns the reader about the dangers posed by Almachi Prometheans."
+*/
+//VOREstation Removal End
+
+/datum/poster/nanotrasen/nt_5
+ icon_state = "ntposter05"
+ name = "Promethean"
+ desc = "This poster displays a friendly-looking green Promethean in a labcoat. The fine-print around the edges talks about the benefits Prometheans give in laboratories."
+
+/datum/poster/nanotrasen/nt_6
+ icon_state = "ntposter06"
+ name = "NanoTrasen"
+ desc = "This poster showcases an NT emblem. There is writing in the ring around the inner points, probably some sort of slogan no one bothers to memorize."
+
+/datum/poster/nanotrasen/nt_7
+ icon_state = "ntposter07"
+ name = "SolGov"
+ desc = "This poster showcases an SCG emblem. The outer ring reads,\
+ \"NIL MORTALIBUS ARDUI EST\".\
+ Solar Confederate Government."
+
+/datum/poster/nanotrasen/nt_8
+ icon_state = "ntposter08"
+ name = "wildlife hazard"
+ desc = "This poster warns against attempting to kill a fully grown giant spider or other hostile life-form alone."
+
+/datum/poster/nanotrasen/nt_9
+ icon_state = "ntposter09"
+ name = "Regulations and You"
+ desc = "This poster showcases an NT security guard reading from her PDA. The blurb advocates for the reader to keep corporate regulations in mind at all times, as an emergency can occur at any time."
diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm
index 551449a8fb6..d1de900bae8 100644
--- a/code/game/objects/effects/effect_system.dm
+++ b/code/game/objects/effects/effect_system.dm
@@ -185,6 +185,12 @@ steam.start() -- spawns the effect
qdel(src)
/obj/effect/effect/smoke/Crossed(mob/living/carbon/M as mob )
+ //VOREStation Edit begin: SHADEKIN
+ var/mob/SK = M
+ if(istype(SK))
+ if(SK.shadekin_phasing_check())
+ return
+ //VOREStation Edit end: SHADEKIN
..()
if(istype(M))
affect(M)
diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm
index 87af3ec90b5..fb4117ef443 100644
--- a/code/game/objects/effects/mines.dm
+++ b/code/game/objects/effects/mines.dm
@@ -36,6 +36,12 @@
..()
/obj/effect/mine/Crossed(AM as mob|obj)
+ //VOREStation Edit begin: SHADEKIN
+ var/mob/SK = AM
+ if(istype(SK))
+ if(SK.shadekin_phasing_check())
+ return
+ //VOREStation Edit end: SHADEKIN
Bumped(AM)
/obj/effect/mine/Bumped(mob/M as mob|obj)
diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm
index 7dc82a0ffb0..5ba58dc4e0c 100644
--- a/code/game/objects/effects/portals.dm
+++ b/code/game/objects/effects/portals.dm
@@ -21,6 +21,12 @@ GLOBAL_LIST_BOILERPLATE(all_portals, /obj/effect/portal)
return
/obj/effect/portal/Crossed(AM as mob|obj)
+ //VOREStation Edit begin: SHADEKIN
+ var/mob/SK = AM
+ if(istype(SK))
+ if(SK.shadekin_phasing_check())
+ return
+ //VOREStation Edit end: SHADEKIN
if(istype(AM,/mob) && !(istype(AM,/mob/living)))
return //do not send ghosts, zshadows, ai eyes, etc
spawn(0)
diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm
index 6ec90ced925..90d9ae18204 100644
--- a/code/game/objects/effects/spiders.dm
+++ b/code/game/objects/effects/spiders.dm
@@ -134,6 +134,8 @@
var/travelling_in_vent = 0
var/list/grow_as = list(/mob/living/simple_mob/animal/giant_spider, /mob/living/simple_mob/animal/giant_spider/nurse, /mob/living/simple_mob/animal/giant_spider/hunter)
+ var/stunted = FALSE
+
/obj/effect/spider/spiderling/frost
grow_as = list(/mob/living/simple_mob/animal/giant_spider/frost)
@@ -261,9 +263,17 @@
break
if(amount_grown >= 100)
var/spawn_type = pick(grow_as)
- new spawn_type(src.loc, src)
+ var/mob/living/simple_mob/animal/giant_spider/GS = new spawn_type(src.loc, src)
+ if(stunted)
+ spawn(2)
+ GS.make_spiderling()
qdel(src)
+/obj/effect/spider/spiderling/stunted
+ stunted = TRUE
+
+ grow_as = list(/mob/living/simple_mob/animal/giant_spider, /mob/living/simple_mob/animal/giant_spider/hunter)
+
/obj/effect/decal/cleanable/spiderling_remains
name = "spiderling remains"
desc = "Green squishy mess."
diff --git a/code/game/objects/effects/spiders_vr.dm b/code/game/objects/effects/spiders_vr.dm
new file mode 100644
index 00000000000..65829b95acb
--- /dev/null
+++ b/code/game/objects/effects/spiders_vr.dm
@@ -0,0 +1,2 @@
+/obj/effect/spider/spiderling/virgo
+ grow_as = list(/mob/living/simple_mob/animal/giant_spider, /mob/living/simple_mob/animal/giant_spider/hunter)
diff --git a/code/game/objects/effects/step_triggers.dm b/code/game/objects/effects/step_triggers.dm
index 61191381213..870656d92e0 100644
--- a/code/game/objects/effects/step_triggers.dm
+++ b/code/game/objects/effects/step_triggers.dm
@@ -13,6 +13,12 @@
return 0
/obj/effect/step_trigger/Crossed(H as mob|obj)
+ //VOREStation Edit begin: SHADEKIN
+ var/mob/SK = H
+ if(istype(SK))
+ if(SK.shadekin_phasing_check())
+ return
+ //VOREStation Edit end: SHADEKIN
..()
if(!H)
return
diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm
index ff47cab3ca4..1e31744e268 100644
--- a/code/game/objects/items/crayons.dm
+++ b/code/game/objects/items/crayons.dm
@@ -74,16 +74,22 @@
switch(drawtype)
if("letter")
drawtype = input("Choose the letter.", "Crayon scribbles") in list("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z")
- if(get_dist(target, user) > 1 || !(user.z == target.z))
+ if(get_dist(target, user) > 1 || !(user.z == target.z) || !drawtype)
return
to_chat(user, "You start drawing a letter on the [target.name].")
if("graffiti")
+ drawtype = input("Choose the graffiti.", "Crayon scribbles") in list("amyjon","face","matt","revolution","engie","guy","end","dwarf","uboa")
+ if(get_dist(target, user) > 1 || !(user.z == target.z) || !drawtype)
+ return
to_chat(user, "You start drawing graffiti on the [target.name].")
if("rune")
+ drawtype = input("Choose the rune.", "Crayon scribbles") in list("rune1", "rune2", "rune3", "rune4", "rune5", "rune6")
+ if(get_dist(target, user) > 1 || !(user.z == target.z) || !drawtype)
+ return
to_chat(user, "You start drawing a rune on the [target.name].")
if("arrow")
drawtype = input("Choose the arrow.", "Crayon scribbles") in list("left", "right", "up", "down")
- if(get_dist(target, user) > 1 || !(user.z == target.z))
+ if(get_dist(target, user) > 1 || !(user.z == target.z) || !drawtype)
return
to_chat(user, "You start drawing an arrow on the [target.name].")
if(instant || do_after(user, 50))
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index 1d1d591d57c..53a83c66bdf 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -1456,6 +1456,12 @@ var/global/list/obj/item/device/pda/PDAs = list()
return ..()
/obj/item/device/pda/clown/Crossed(AM as mob|obj) //Clown PDA is slippery.
+ //VOREStation Edit begin: SHADEKIN
+ var/mob/SK = AM
+ if(istype(SK))
+ if(SK.shadekin_phasing_check())
+ return
+ //VOREStation Edit end: SHADEKIN
if (istype(AM, /mob/living))
var/mob/living/M = AM
diff --git a/code/game/objects/items/devices/communicator/UI.dm b/code/game/objects/items/devices/communicator/UI.dm
index a4859c08a56..e972cd1210c 100644
--- a/code/game/objects/items/devices/communicator/UI.dm
+++ b/code/game/objects/items/devices/communicator/UI.dm
@@ -63,6 +63,11 @@
if(ghost.exonet)
im_contacts_ui[++im_contacts_ui.len] = list("name" = sanitize(ghost.name), "address" = ghost.exonet.address, "ref" = "\ref[ghost]")
+ for(var/obj/item/integrated_circuit/input/EPv2/CIRC in im_contacts)
+ if(CIRC.exonet && CIRC.assembly)
+ im_contacts_ui[++im_contacts_ui.len] = list("name" = sanitize(CIRC.assembly.name), "address" = CIRC.exonet.address, "ref" = "\ref[CIRC]")
+
+
//Actual messages.
for(var/I in im_list)
im_list_ui[++im_list_ui.len] = list("address" = I["address"], "to_address" = I["to_address"], "im" = I["im"])
diff --git a/code/game/objects/items/devices/communicator/messaging.dm b/code/game/objects/items/devices/communicator/messaging.dm
index fffa0407f8a..e50540acb01 100644
--- a/code/game/objects/items/devices/communicator/messaging.dm
+++ b/code/game/objects/items/devices/communicator/messaging.dm
@@ -1,162 +1,166 @@
-// Proc: receive_exonet_message()
-// Parameters: 4 (origin atom - the source of the message's holder, origin_address - where the message came from, message - the message received,
-// text - message text to send if message is of type "text")
-// Description: Handles voice requests and invite messages originating from both real communicators and ghosts. Also includes a ping response and IM function.
-/obj/item/device/communicator/receive_exonet_message(var/atom/origin_atom, origin_address, message, text)
- if(message == "voice")
- if(isobserver(origin_atom) || istype(origin_atom, /obj/item/device/communicator))
- if(origin_atom in voice_invites)
- var/user = null
- if(ismob(origin_atom.loc))
- user = origin_atom.loc
- open_connection(user, origin_atom)
- return
- else if(origin_atom in voice_requests)
- return //Spam prevention
- else
- request(origin_atom)
- if(message == "ping")
- if(network_visibility)
- var/random = rand(200,350)
- random = random / 10
- exonet.send_message(origin_address, "64 bytes received from [exonet.address] ecmp_seq=1 ttl=51 time=[random] ms")
- if(message == "text")
- request_im(origin_atom, origin_address, text)
- return
-
-// Proc: receive_exonet_message()
-// Parameters: 3 (origin atom - the source of the message's holder, origin_address - where the message came from, message - the message received)
-// Description: Handles voice requests and invite messages originating from both real communicators and ghosts. Also includes a ping response.
-/mob/observer/dead/receive_exonet_message(origin_atom, origin_address, message, text)
- if(message == "voice")
- if(istype(origin_atom, /obj/item/device/communicator))
- var/obj/item/device/communicator/comm = origin_atom
- if(src in comm.voice_invites)
- comm.open_connection(src)
- return
- to_chat(src, "\icon[origin_atom] Receiving communicator request from [origin_atom]. To answer, use the Call Communicator \
- verb, and select that name to answer the call.")
- src << 'sound/machines/defib_SafetyOn.ogg'
- comm.voice_invites |= src
- if(message == "ping")
- if(client && client.prefs.communicator_visibility)
- var/random = rand(450,700)
- random = random / 10
- exonet.send_message(origin_address, "64 bytes received from [exonet.address] ecmp_seq=1 ttl=51 time=[random] ms")
- if(message == "text")
- to_chat(src, "\icon[origin_atom] Received text message from [origin_atom]: \"[text]\"")
- src << 'sound/machines/defib_safetyOff.ogg'
- exonet_messages.Add("From [origin_atom]:
[text]")
- return
-
-// Proc: request_im()
-// Parameters: 3 (candidate - the communicator wanting to message the device, origin_address - the address of the sender, text - the message)
-// Description: Response to a communicator trying to message the device.
-// Adds them to the list of people that have messaged this device and adds the message to the message list.
-/obj/item/device/communicator/proc/request_im(var/atom/candidate, var/origin_address, var/text)
- var/who = null
- if(isobserver(candidate))
- var/mob/observer/dead/ghost = candidate
- who = ghost
- im_list += list(list("address" = origin_address, "to_address" = exonet.address, "im" = text))
- else if(istype(candidate, /obj/item/device/communicator))
- var/obj/item/device/communicator/comm = candidate
- who = comm.owner
- comm.im_contacts |= src
- im_list += list(list("address" = origin_address, "to_address" = exonet.address, "im" = text))
- else return
-
- im_contacts |= candidate
-
- if(!who)
- return
-
- if(ringer)
- playsound(loc, 'sound/machines/twobeep.ogg', 50, 1)
- for (var/mob/O in hearers(2, loc))
- O.show_message(text("\icon[src] *beep*"))
-
- alert_called = 1
- update_icon()
-
- //Search for holder of the device.
- var/mob/living/L = null
- if(loc && isliving(loc))
- L = loc
-
- if(L)
- to_chat(L, "\icon[src] Message from [who].")
-
-// Verb: text_communicator()
-// Parameters: None
-// Description: Allows a ghost to send a text message to a communicator.
-/mob/observer/dead/verb/text_communicator()
- set category = "Ghost"
- set name = "Text Communicator"
- set desc = "If there is a communicator available, send a text message to it."
-
- if(ticker.current_state < GAME_STATE_PLAYING)
- to_chat(src, "The game hasn't started yet!")
- return
-
- if (!src.stat)
- return
-
- if (usr != src)
- return //something is terribly wrong
-
- for(var/mob/living/L in mob_list) //Simple check so you don't have dead people calling.
- if(src.client.prefs.real_name == L.real_name)
- to_chat(src, "Your identity is already present in the game world. Please load in a different character first.")
- return
-
- var/obj/machinery/exonet_node/E = get_exonet_node()
- if(!E || !E.on || !E.allow_external_communicators)
- to_chat(src, "The Exonet node at telecommunications is down at the moment, or is actively blocking you, \
- so your call can't go through.")
- return
-
- var/list/choices = list()
- for(var/obj/item/device/communicator/comm in all_communicators)
- if(!comm.network_visibility || !comm.exonet || !comm.exonet.address)
- continue
- choices.Add(comm)
-
- if(!choices.len)
- to_chat(src, "There are no available communicators, sorry.")
- return
-
- var/choice = input(src,"Send a text message to whom?") as null|anything in choices
- if(choice)
- var/obj/item/device/communicator/chosen_communicator = choice
- var/mob/observer/dead/O = src
- var/text_message = sanitize(input(src, "What do you want the message to say?")) as message
- if(text_message && O.exonet)
- O.exonet.send_message(chosen_communicator.exonet.address, "text", text_message)
-
- to_chat(src, "You have sent '[text_message]' to [chosen_communicator].")
- exonet_messages.Add("To [chosen_communicator]:
[text_message]")
- log_pda("(DCOMM: [src]) sent \"[text_message]\" to [chosen_communicator]", src)
- for(var/mob/M in player_list)
- if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears))
- if(istype(M, /mob/new_player) || M.forbid_seeing_deadchat)
- continue
- if(M == src)
- continue
- M.show_message("Comm IM - [src] -> [chosen_communicator]: [text_message]")
-
-
-
-// Verb: show_text_messages()
-// Parameters: None
-// Description: Lets ghosts review messages they've sent or received.
-/mob/observer/dead/verb/show_text_messages()
- set category = "Ghost"
- set name = "Show Text Messages"
- set desc = "Allows you to see exonet text messages you've sent and received."
-
- var/HTML = "Exonet Message Log"
- for(var/line in exonet_messages)
- HTML += line + "
"
- HTML +=""
- usr << browse(HTML, "window=log;size=400x444;border=1;can_resize=1;can_close=1;can_minimize=0")
\ No newline at end of file
+// Proc: receive_exonet_message()
+// Parameters: 4 (origin atom - the source of the message's holder, origin_address - where the message came from, message - the message received,
+// text - message text to send if message is of type "text")
+// Description: Handles voice requests and invite messages originating from both real communicators and ghosts. Also includes a ping response and IM function.
+/obj/item/device/communicator/receive_exonet_message(var/atom/origin_atom, origin_address, message, text)
+ if(message == "voice")
+ if(isobserver(origin_atom) || istype(origin_atom, /obj/item/device/communicator))
+ if(origin_atom in voice_invites)
+ var/user = null
+ if(ismob(origin_atom.loc))
+ user = origin_atom.loc
+ open_connection(user, origin_atom)
+ return
+ else if(origin_atom in voice_requests)
+ return //Spam prevention
+ else
+ request(origin_atom)
+ if(message == "ping")
+ if(network_visibility)
+ var/random = rand(200,350)
+ random = random / 10
+ exonet.send_message(origin_address, "64 bytes received from [exonet.address] ecmp_seq=1 ttl=51 time=[random] ms")
+ if(message == "text")
+ request_im(origin_atom, origin_address, text)
+ return
+
+// Proc: receive_exonet_message()
+// Parameters: 3 (origin atom - the source of the message's holder, origin_address - where the message came from, message - the message received)
+// Description: Handles voice requests and invite messages originating from both real communicators and ghosts. Also includes a ping response.
+/mob/observer/dead/receive_exonet_message(origin_atom, origin_address, message, text)
+ if(message == "voice")
+ if(istype(origin_atom, /obj/item/device/communicator))
+ var/obj/item/device/communicator/comm = origin_atom
+ if(src in comm.voice_invites)
+ comm.open_connection(src)
+ return
+ to_chat(src, "\icon[origin_atom] Receiving communicator request from [origin_atom]. To answer, use the Call Communicator \
+ verb, and select that name to answer the call.")
+ src << 'sound/machines/defib_SafetyOn.ogg'
+ comm.voice_invites |= src
+ if(message == "ping")
+ if(client && client.prefs.communicator_visibility)
+ var/random = rand(450,700)
+ random = random / 10
+ exonet.send_message(origin_address, "64 bytes received from [exonet.address] ecmp_seq=1 ttl=51 time=[random] ms")
+ if(message == "text")
+ to_chat(src, "\icon[origin_atom] Received text message from [origin_atom]: \"[text]\"")
+ src << 'sound/machines/defib_safetyOff.ogg'
+ exonet_messages.Add("From [origin_atom]:
[text]")
+ return
+
+// Proc: request_im()
+// Parameters: 3 (candidate - the communicator wanting to message the device, origin_address - the address of the sender, text - the message)
+// Description: Response to a communicator trying to message the device.
+// Adds them to the list of people that have messaged this device and adds the message to the message list.
+/obj/item/device/communicator/proc/request_im(var/atom/candidate, var/origin_address, var/text)
+ var/who = null
+ if(isobserver(candidate))
+ var/mob/observer/dead/ghost = candidate
+ who = ghost
+ im_list += list(list("address" = origin_address, "to_address" = exonet.address, "im" = text))
+ else if(istype(candidate, /obj/item/device/communicator))
+ var/obj/item/device/communicator/comm = candidate
+ who = comm.owner
+ comm.im_contacts |= src
+ im_list += list(list("address" = origin_address, "to_address" = exonet.address, "im" = text))
+ else if(istype(candidate, /obj/item/integrated_circuit))
+ var/obj/item/integrated_circuit/CIRC = candidate
+ who = CIRC
+ im_list += list(list("address" = origin_address, "to_address" = exonet.address, "im" = text))
+ else return
+
+ im_contacts |= candidate
+
+ if(!who)
+ return
+
+ if(ringer)
+ playsound(loc, 'sound/machines/twobeep.ogg', 50, 1)
+ for (var/mob/O in hearers(2, loc))
+ O.show_message(text("\icon[src] *beep*"))
+
+ alert_called = 1
+ update_icon()
+
+ //Search for holder of the device.
+ var/mob/living/L = null
+ if(loc && isliving(loc))
+ L = loc
+
+ if(L)
+ to_chat(L, "\icon[src] Message from [who].")
+
+// Verb: text_communicator()
+// Parameters: None
+// Description: Allows a ghost to send a text message to a communicator.
+/mob/observer/dead/verb/text_communicator()
+ set category = "Ghost"
+ set name = "Text Communicator"
+ set desc = "If there is a communicator available, send a text message to it."
+
+ if(ticker.current_state < GAME_STATE_PLAYING)
+ to_chat(src, "The game hasn't started yet!")
+ return
+
+ if (!src.stat)
+ return
+
+ if (usr != src)
+ return //something is terribly wrong
+
+ for(var/mob/living/L in mob_list) //Simple check so you don't have dead people calling.
+ if(src.client.prefs.real_name == L.real_name)
+ to_chat(src, "Your identity is already present in the game world. Please load in a different character first.")
+ return
+
+ var/obj/machinery/exonet_node/E = get_exonet_node()
+ if(!E || !E.on || !E.allow_external_communicators)
+ to_chat(src, "The Exonet node at telecommunications is down at the moment, or is actively blocking you, \
+ so your call can't go through.")
+ return
+
+ var/list/choices = list()
+ for(var/obj/item/device/communicator/comm in all_communicators)
+ if(!comm.network_visibility || !comm.exonet || !comm.exonet.address)
+ continue
+ choices.Add(comm)
+
+ if(!choices.len)
+ to_chat(src, "There are no available communicators, sorry.")
+ return
+
+ var/choice = input(src,"Send a text message to whom?") as null|anything in choices
+ if(choice)
+ var/obj/item/device/communicator/chosen_communicator = choice
+ var/mob/observer/dead/O = src
+ var/text_message = sanitize(input(src, "What do you want the message to say?")) as message
+ if(text_message && O.exonet)
+ O.exonet.send_message(chosen_communicator.exonet.address, "text", text_message)
+
+ to_chat(src, "You have sent '[text_message]' to [chosen_communicator].")
+ exonet_messages.Add("To [chosen_communicator]:
[text_message]")
+ log_pda("(DCOMM: [src]) sent \"[text_message]\" to [chosen_communicator]", src)
+ for(var/mob/M in player_list)
+ if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears))
+ if(istype(M, /mob/new_player) || M.forbid_seeing_deadchat)
+ continue
+ if(M == src)
+ continue
+ M.show_message("Comm IM - [src] -> [chosen_communicator]: [text_message]")
+
+
+
+// Verb: show_text_messages()
+// Parameters: None
+// Description: Lets ghosts review messages they've sent or received.
+/mob/observer/dead/verb/show_text_messages()
+ set category = "Ghost"
+ set name = "Show Text Messages"
+ set desc = "Allows you to see exonet text messages you've sent and received."
+
+ var/HTML = "Exonet Message Log"
+ for(var/line in exonet_messages)
+ HTML += line + "
"
+ HTML +=""
+ usr << browse(HTML, "window=log;size=400x444;border=1;can_resize=1;can_close=1;can_minimize=0")
diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm
index 83bdee0059f..150c2e1fe5e 100644
--- a/code/game/objects/items/devices/flashlight.dm
+++ b/code/game/objects/items/devices/flashlight.dm
@@ -295,7 +295,7 @@
desc = "A desk lamp with an adjustable mount."
icon_state = "lamp"
force = 10
- brightness_on = 5
+ brightness_on = 10 //TFF 27/11/19 - post refactor fix for intensity levels.
w_class = ITEMSIZE_LARGE
power_use = 0
on = 1
diff --git a/code/game/objects/items/devices/lightreplacer.dm b/code/game/objects/items/devices/lightreplacer.dm
index 4686aee8079..f85e4246045 100644
--- a/code/game/objects/items/devices/lightreplacer.dm
+++ b/code/game/objects/items/devices/lightreplacer.dm
@@ -54,6 +54,11 @@
var/failmsg = ""
var/charge = 0
+ // Eating used bulbs gives us bulb shards
+ var/bulb_shards = 0
+ // when we get this many shards, we get a free bulb.
+ var/shards_required = 4
+
/obj/item/device/lightreplacer/New()
failmsg = "The [name]'s refill light blinks red."
..()
@@ -76,18 +81,55 @@
to_chat(user, "You need one sheet of glass to replace lights.")
if(istype(W, /obj/item/weapon/light))
+ var/new_bulbs = 0
var/obj/item/weapon/light/L = W
if(L.status == 0) // LIGHT OKAY
if(uses < max_uses)
+ if(!user.unEquip(W))
+ return
add_uses(1)
- to_chat(user, "You insert \the [L.name] into \the [src.name]. You have [uses] light\s remaining.")
- user.drop_item()
qdel(L)
- return
else
- to_chat(user, "You need a working light.")
+ if(!user.unEquip(W))
+ return
+ new_bulbs += AddShards(1)
+ qdel(L)
+ if(new_bulbs != 0)
+ playsound(src.loc, 'sound/machines/ding.ogg', 50, 1)
+ to_chat(user, "You insert \the [L.name] into \the [src.name]. You have [uses] light\s remaining.")
+ return
+
+ if(istype(W, /obj/item/weapon/storage))
+ var/obj/item/weapon/storage/S = W
+ var/found_lightbulbs = FALSE
+ var/replaced_something = TRUE
+
+ for(var/obj/item/I in S.contents)
+ if(istype(I,/obj/item/weapon/light))
+ var/obj/item/weapon/light/L = I
+ found_lightbulbs = TRUE
+ if(src.uses >= max_uses)
+ break
+ if(L.status == LIGHT_OK)
+ replaced_something = TRUE
+ add_uses(1)
+ qdel(L)
+
+ else if(L.status == LIGHT_BROKEN || L.status == LIGHT_BURNED)
+ replaced_something = TRUE
+ AddShards(1)
+ qdel(L)
+
+ if(!found_lightbulbs)
+ to_chat(user, "\The [S] contains no bulbs.")
return
+ if(!replaced_something && src.uses == max_uses)
+ to_chat(user, "\The [src] is full!")
+ return
+
+ to_chat(user, "You fill \the [src] with lights from \the [S].")
+
/obj/item/device/lightreplacer/attack_self(mob/user)
/* // This would probably be a bit OP. If you want it though, uncomment the code.
if(isrobot(user))
@@ -113,6 +155,15 @@
/obj/item/device/lightreplacer/proc/add_uses(var/amount = 1)
uses = min(max(uses + amount, 0), max_uses)
+
+/obj/item/device/lightreplacer/proc/AddShards(amount = 1)
+ bulb_shards += amount
+ var/new_bulbs = round(bulb_shards / shards_required)
+ if(new_bulbs > 0)
+ add_uses(new_bulbs)
+ bulb_shards = bulb_shards % shards_required
+ return new_bulbs
+
/obj/item/device/lightreplacer/proc/Charge(var/mob/user, var/amount = 1)
charge += amount
if(charge > 6)
@@ -121,18 +172,41 @@
/obj/item/device/lightreplacer/proc/ReplaceLight(var/obj/machinery/light/target, var/mob/living/U)
- if(target.status == LIGHT_OK)
+ if(target.status != LIGHT_OK)
+ if(CanUse(U))
+ if(!Use(U)) return
+ to_chat(U, "You replace the [target.get_fitting_name()] with the [src].")
+
+ if(target.status != LIGHT_EMPTY)
+ var/new_bulbs = AddShards(1)
+ if(new_bulbs != 0)
+ to_chat(U, "\The [src] has fabricated a new bulb from the broken bulbs it has stored. It now has [uses] uses.")
+ playsound(src.loc, 'sound/machines/ding.ogg', 50, 1)
+ target.status = LIGHT_EMPTY
+ target.update()
+
+ var/obj/item/weapon/light/L2 = new target.light_type()
+
+ target.status = L2.status
+ target.switchcount = L2.switchcount
+ target.rigged = emagged
+ target.brightness_range = L2.brightness_range
+ target.brightness_power = L2.brightness_power
+ target.brightness_color = L2.brightness_color
+ target.on = target.has_power()
+ target.update()
+ qdel(L2)
+
+ if(target.on && target.rigged)
+ target.explode()
+ return
+
+ else
+ to_chat(U, failmsg)
+ return
+ else
to_chat(U, "There is a working [target.get_fitting_name()] already inserted.")
- else if(!CanUse(U))
- to_chat(U, failmsg)
- else if(Use(U))
- to_chat(U, "You replace the [target.get_fitting_name()] with the [src].")
-
- if(target.status != LIGHT_EMPTY)
- target.remove_bulb()
-
- var/obj/item/weapon/light/L = new target.light_type()
- target.insert_bulb(L)
+ return
/obj/item/device/lightreplacer/emag_act(var/remaining_charges, var/mob/user)
emagged = !emagged
@@ -153,4 +227,4 @@
#undef LIGHT_OK
#undef LIGHT_EMPTY
#undef LIGHT_BROKEN
-#undef LIGHT_BURNED
+#undef LIGHT_BURNED
\ No newline at end of file
diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm
index b0c1113ba8d..fc3f69dd22d 100644
--- a/code/game/objects/items/devices/multitool.dm
+++ b/code/game/objects/items/devices/multitool.dm
@@ -51,10 +51,10 @@
return ..()
/obj/item/device/multitool/proc/mode_switch(mob/living/user)
- if(++mode_index > modes.len) mode_index = 1
+ if(mode_index + 1 > modes.len) mode_index = 1
else
- mode_index++
+ mode_index += 1
toolmode = modes[mode_index]
to_chat(user,"\The [src] is now set to [toolmode].")
diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm
index 0d81f8559e9..754369e13ea 100644
--- a/code/game/objects/items/devices/radio/encryptionkey.dm
+++ b/code/game/objects/items/devices/radio/encryptionkey.dm
@@ -68,7 +68,7 @@
/obj/item/device/encryptionkey/heads/captain
name = "colony director's encryption key"
icon_state = "cap_cypherkey"
- channels = list("Command" = 1, "Security" = 1, "Engineering" = 0, "Science" = 0, "Medical" = 0, "Supply" = 0, "Service" = 0)
+ channels = list("Command" = 1, "Security" = 1, "Engineering" = 1, "Science" = 1, "Medical" = 1, "Supply" = 1, "Service" = 1)
/obj/item/device/encryptionkey/heads/ai_integrated
name = "ai integrated encryption key"
@@ -99,7 +99,7 @@
/obj/item/device/encryptionkey/heads/hop
name = "head of personnel's encryption key"
icon_state = "hop_cypherkey"
- channels = list("Supply" = 1, "Service" = 1, "Command" = 1, "Security" = 0)
+ channels = list("Supply" = 1, "Service" = 1, "Command" = 1, "Security" = 1)
/*
/obj/item/device/encryptionkey/headset_mine
name = "mining radio encryption key"
diff --git a/code/game/objects/items/devices/radio/encryptionkey_vr.dm b/code/game/objects/items/devices/radio/encryptionkey_vr.dm
index a70ad6f7df7..5be1effb355 100644
--- a/code/game/objects/items/devices/radio/encryptionkey_vr.dm
+++ b/code/game/objects/items/devices/radio/encryptionkey_vr.dm
@@ -1,7 +1,7 @@
/obj/item/device/encryptionkey/heads/hop
name = "head of personnel's encryption key"
icon_state = "hop_cypherkey"
- channels = list("Supply" = 1, "Service" = 1, "Command" = 1, "Security" = 0, "Explorer" = 0)
+ channels = list("Supply" = 1, "Service" = 1, "Command" = 1, "Security" = 1, "Explorer" = 1)
/obj/item/device/encryptionkey/heads/ai_integrated
name = "ai integrated encryption key"
@@ -12,7 +12,7 @@
/obj/item/device/encryptionkey/heads/captain
name = "colony director's encryption key"
icon_state = "cap_cypherkey"
- channels = list("Command" = 1, "Security" = 1, "Engineering" = 0, "Science" = 0, "Medical" = 0, "Supply" = 0, "Service" = 0, "Explorer" = 0)
+ channels = list("Command" = 1, "Security" = 1, "Engineering" = 1, "Science" = 1, "Medical" = 1, "Supply" = 1, "Service" = 1, "Explorer" = 1)
/obj/item/device/encryptionkey/heads/rd
name = "research director's encryption key"
diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm
index 51d7e0a4b6e..67ad07567f4 100644
--- a/code/game/objects/items/devices/radio/headset.dm
+++ b/code/game/objects/items/devices/radio/headset.dm
@@ -46,10 +46,10 @@
/obj/item/device/radio/headset/handle_message_mode(mob/living/M as mob, message, channel)
if (channel == "special")
if (translate_binary)
- var/datum/language/binary = all_languages["Robot Talk"]
+ var/datum/language/binary = GLOB.all_languages["Robot Talk"]
binary.broadcast(M, message)
if (translate_hive)
- var/datum/language/hivemind = all_languages["Hivemind"]
+ var/datum/language/hivemind = GLOB.all_languages["Hivemind"]
hivemind.broadcast(M, message)
return null
diff --git a/code/game/objects/items/devices/radio/headset_vr.dm b/code/game/objects/items/devices/radio/headset_vr.dm
index 71a37ac0d7c..49783eaca45 100644
--- a/code/game/objects/items/devices/radio/headset_vr.dm
+++ b/code/game/objects/items/devices/radio/headset_vr.dm
@@ -19,4 +19,29 @@
/obj/item/device/radio/headset
sprite_sheets = list(SPECIES_TESHARI = 'icons/mob/species/seromi/ears.dmi',
- SPECIES_WEREBEAST = 'icons/mob/species/werebeast/ears.dmi')
\ No newline at end of file
+ SPECIES_WEREBEAST = 'icons/mob/species/werebeast/ears.dmi')
+
+/obj/item/device/radio/headset/mob_headset //Adminbus headset for simplemob shenanigans.
+ name = "nonhuman radio receiver"
+ desc = "An updated, self-adhesive modular intercom that requires no hands to operate or ears to hold, just stick it on. Takes encryption keys"
+
+/obj/item/device/radio/headset/mob_headset/receive_range(freq, level)
+ if(ismob(src.loc))
+ return ..(freq, level, 1)
+ return -1
+
+/obj/item/device/radio/headset/mob_headset/afterattack(var/atom/movable/target, mob/living/user, proximity)
+ if(!proximity)
+ return
+ if(istype(target,/mob/living/simple_mob))
+ var/mob/living/simple_mob/M = target
+ if(!M.mob_radio)
+ user.drop_item()
+ forceMove(M)
+ M.mob_radio = src
+ return
+ if(M.mob_radio)
+ M.mob_radio.forceMove(M.loc)
+ M.mob_radio = null
+ return
+ ..()
\ No newline at end of file
diff --git a/code/game/objects/items/devices/spy_bug.dm b/code/game/objects/items/devices/spy_bug.dm
index e3392f33fe5..1f15d36b127 100644
--- a/code/game/objects/items/devices/spy_bug.dm
+++ b/code/game/objects/items/devices/spy_bug.dm
@@ -60,7 +60,7 @@
name = "broken bug"
desc = "" //Even when it's broken it's inconspicuous
icon = 'icons/obj/weapons.dmi'
- icon_state = "eshield0"
+ icon_state = "eshield"
item_state = "nothing"
layer = TURF_LAYER+0.2
w_class = ITEMSIZE_TINY
@@ -75,7 +75,7 @@
name = "bug"
desc = "" //Nothing to see here
icon = 'icons/obj/weapons.dmi'
- icon_state = "eshield0"
+ icon_state = "eshield"
item_state = "nothing"
layer = TURF_LAYER+0.2
w_class = ITEMSIZE_TINY
diff --git a/code/game/objects/items/devices/translocator_vr.dm b/code/game/objects/items/devices/translocator_vr.dm
new file mode 100644
index 00000000000..ef0ec42b51c
--- /dev/null
+++ b/code/game/objects/items/devices/translocator_vr.dm
@@ -0,0 +1,450 @@
+//The perfect adminboos device?
+/obj/item/device/perfect_tele
+ name = "personal translocator"
+ desc = "Seems absurd, doesn't it? Yet, here we are. Generally considered dangerous contraband unless the user has permission from Central Command."
+ icon = 'icons/obj/device_alt.dmi'
+ icon_state = "hand_tele"
+ w_class = ITEMSIZE_SMALL
+ origin_tech = list(TECH_MAGNET = 5, TECH_BLUESPACE = 5, TECH_ILLEGAL = 7)
+
+ var/cell_type = /obj/item/weapon/cell/device/weapon
+ var/obj/item/weapon/cell/power_source
+ var/charge_cost = 800 // cell/device/weapon has 2400
+ var/battery_lock = 0 //If set, weapon cannot switch batteries
+
+ var/longrange = 0 //Can teleport very long distances
+ var/abductor = 0 //Can be used on teleportation blocking turfs
+
+ var/list/beacons = list()
+ var/ready = 1
+ var/beacons_left = 3
+ var/failure_chance = 5 //Percent
+ var/obj/item/device/perfect_tele_beacon/destination
+ var/datum/effect/effect/system/spark_spread/spk
+ var/list/warned_users = list()
+ var/list/logged_events = list()
+
+/obj/item/device/perfect_tele/New()
+ ..()
+ flags |= NOBLUDGEON
+ if(cell_type)
+ power_source = new cell_type(src)
+ else
+ power_source = new /obj/item/weapon/cell/device(src)
+ spk = new(src)
+ spk.set_up(5, 0, src)
+ spk.attach(src)
+
+/obj/item/device/perfect_tele/Destroy()
+ // Must clear the beacon's backpointer or we won't GC. Someday maybe do something nicer even.
+ for(var/obj/item/device/perfect_tele_beacon/B in beacons)
+ B.tele_hand = null
+ beacons.Cut()
+ QDEL_NULL(power_source)
+ QDEL_NULL(spk)
+ return ..()
+
+/obj/item/device/perfect_tele/update_icon()
+ if(!power_source)
+ icon_state = "[initial(icon_state)]_o"
+ else if(ready && (power_source.check_charge(charge_cost) || power_source.fully_charged()))
+ icon_state = "[initial(icon_state)]"
+ else
+ icon_state = "[initial(icon_state)]_w"
+
+ ..()
+
+/obj/item/device/perfect_tele/attack_hand(mob/user)
+ if(user.get_inactive_hand() == src)
+ unload_ammo(user)
+ else
+ return ..()
+
+/obj/item/device/perfect_tele/proc/unload_ammo(mob/user)
+ if(battery_lock)
+ to_chat(user,"[src] does not have a battery port.")
+ return
+ if(user.get_inactive_hand() == src && power_source)
+ to_chat(user,"You eject \the [power_source] from \the [src].")
+ user.put_in_hands(power_source)
+ power_source = null
+ update_icon()
+ else
+ to_chat(user,"[src] does not have a power cell.")
+
+/obj/item/device/perfect_tele/attack_self(mob/user)
+ if(!(user.ckey in warned_users))
+ warned_users |= user.ckey
+ alert(user,"This device can be easily used to break ERP preferences due to the nature of teleporting \
+ and tele-vore. Make sure you carefully examine someone's OOC prefs before teleporting them if you are \
+ going to use this device for ERP purposes. This device records all warnings given and teleport events for \
+ admin review in case of pref-breaking, so just don't do it.","OOC WARNING")
+
+ var/choice = alert(user,"What do you want to do?","[src]","Create Beacon","Cancel","Target Beacon")
+ switch(choice)
+ if("Create Beacon")
+ if(beacons_left <= 0)
+ alert("The translocator can't support any more beacons!","Error")
+ return
+
+ var/new_name = html_encode(input(user,"New beacon's name (2-20 char):","[src]") as text|null)
+
+ if(length(new_name) > 20 || length(new_name) < 2)
+ alert("Entered name length invalid (must be longer than 2, no more than than 20).","Error")
+ return
+ if(new_name in beacons)
+ alert("No duplicate names, please. '[new_name]' exists already.","Error")
+ return
+
+ var/obj/item/device/perfect_tele_beacon/nb = new(get_turf(src))
+ nb.tele_name = new_name
+ nb.tele_hand = src
+ nb.creator = user.ckey
+ beacons[new_name] = nb
+ beacons_left--
+ if(isliving(user))
+ var/mob/living/L = user
+ L.put_in_any_hand_if_possible(nb)
+
+ if("Target Beacon")
+ if(!beacons.len)
+ to_chat(user,"\The [src] doesn't have any beacons!")
+ else
+ var/target = input("Which beacon do you target?","[src]") in beacons|null
+ if(target && (target in beacons))
+ destination = beacons[target]
+ to_chat(user,"Destination set to '[target]'.")
+ else
+ return
+
+/obj/item/device/perfect_tele/attackby(obj/W, mob/user)
+ if(istype(W,cell_type) && !power_source)
+ power_source = W
+ power_source.update_icon() //Why doesn't a cell do this already? :|
+ user.unEquip(power_source)
+ power_source.forceMove(src)
+ to_chat(user,"You insert \the [power_source] into \the [src].")
+ update_icon()
+
+ else if(istype(W,/obj/item/device/perfect_tele_beacon))
+ var/obj/item/device/perfect_tele_beacon/tb = W
+ if(tb.tele_name in beacons)
+ to_chat(user,"You re-insert \the [tb] into \the [src].")
+ beacons -= tb.tele_name
+ user.unEquip(tb)
+ qdel(tb)
+ beacons_left++
+ else
+ to_chat(user,"\The [tb] doesn't belong to \the [src].")
+ return
+ else
+ ..()
+
+/obj/item/device/perfect_tele/proc/teleport_checks(mob/living/target,mob/living/user)
+ //Uhhuh, need that power source
+ if(!power_source)
+ to_chat(user,"\The [src] has no power source!")
+ return FALSE
+
+ //Check for charge
+ if((!power_source.check_charge(charge_cost)) && (!power_source.fully_charged()))
+ to_chat(user,"\The [src] does not have enough power left!")
+ return FALSE
+
+ //Only mob/living need apply.
+ if(!istype(user) || !istype(target))
+ return FALSE
+
+ //No, you can't teleport buckled people.
+ if(target.buckled)
+ to_chat(user,"The target appears to be attached to something...")
+ return FALSE
+
+ //No, you can't teleport if it's not ready yet.
+ if(!ready)
+ to_chat(user,"\The [src] is still recharging!")
+ return FALSE
+
+ //No, you can't teleport if there's no destination.
+ if(!destination)
+ to_chat(user,"\The [src] doesn't have a current valid destination set!")
+ return FALSE
+
+ //No, you can't teleport if there's a jammer.
+ if(is_jammed(src) || is_jammed(destination))
+ to_chat(user,"\The [src] refuses to teleport you, due to strong interference!")
+ return FALSE
+
+ //No, you can't port to or from away missions. Stupidly complicated check.
+ var/turf/uT = get_turf(user)
+ var/turf/dT = get_turf(destination)
+ var/list/dat = list()
+ dat["z_level_detection"] = using_map.get_map_levels(uT.z)
+
+ if(!uT || !dT)
+ return FALSE
+
+ if(!longrange)
+ if( (uT.z != dT.z) && (!(dT.z in dat["z_level_detection"])) )
+ to_chat(user,"\The [src] can't teleport you that far!")
+ return FALSE
+
+ if(!abductor)
+ if(uT.block_tele || dT.block_tele)
+ to_chat(user,"Something is interfering with \the [src]!")
+ return FALSE
+
+ //Seems okay to me!
+ return TRUE
+
+/obj/item/device/perfect_tele/afterattack(mob/living/target, mob/living/user, proximity)
+ //No, you can't teleport people from over there.
+ if(!proximity)
+ return
+
+ if(!teleport_checks(target,user))
+ return //The checks proc can send them a message if it wants.
+
+ //Bzzt.
+ ready = 0
+ power_source.use(charge_cost)
+
+ //Failure chance
+ if(prob(failure_chance) && beacons.len >= 2)
+ var/list/wrong_choices = beacons - destination.tele_name
+ var/wrong_name = pick(wrong_choices)
+ destination = beacons[wrong_name]
+ to_chat(user,"\The [src] malfunctions and sends you to the wrong beacon!")
+
+ //Destination beacon vore checking
+ var/turf/dT = get_turf(destination)
+ var/atom/real_dest = dT
+
+ var/atom/real_loc = destination.loc
+ if(isbelly(real_loc))
+ real_dest = real_loc
+ if(isliving(real_loc))
+ var/mob/living/L = real_loc
+ if(L.vore_selected)
+ real_dest = L.vore_selected
+ else if(L.vore_organs.len)
+ real_dest = pick(L.vore_organs)
+
+ //Confirm televore
+ var/televored = FALSE
+ if(isbelly(real_dest))
+ var/obj/belly/B = real_dest
+ if(!target.can_be_drop_prey && B.owner != user)
+ to_chat(target,"\The [src] narrowly avoids teleporting you right into \a [lowertext(real_dest.name)]!")
+ real_dest = dT //Nevermind!
+ else
+ televored = TRUE
+ to_chat(target,"\The [src] teleports you right into \a [lowertext(real_dest.name)]!")
+
+ //Phase-out effect
+ phase_out(target,get_turf(target))
+
+ //Move them
+ target.forceMove(real_dest)
+
+ //Phase-in effect
+ phase_in(target,get_turf(target))
+
+ //And any friends!
+ for(var/obj/item/weapon/grab/G in target.contents)
+ if(G.affecting && (G.state >= GRAB_AGGRESSIVE))
+
+ //Phase-out effect for grabbed person
+ phase_out(G.affecting,get_turf(G.affecting))
+
+ //Move them, and televore if necessary
+ G.affecting.forceMove(real_dest)
+ if(televored)
+ to_chat(target,"\The [src] teleports you right into \a [lowertext(real_dest.name)]!")
+
+ //Phase-in effect for grabbed person
+ phase_in(G.affecting,get_turf(G.affecting))
+
+ update_icon()
+ spawn(30 SECONDS)
+ ready = 1
+ update_icon()
+
+ logged_events["[world.time]"] = "[user] teleported [target] to [real_dest] [televored ? "(Belly: [lowertext(real_dest.name)])" : null]"
+
+/obj/item/device/perfect_tele/proc/phase_out(var/mob/M,var/turf/T)
+
+ if(!M || !T)
+ return
+
+ spk.set_up(5, 0, M)
+ spk.attach(M)
+ playsound(T, "sparks", 50, 1)
+ anim(T,M,'icons/mob/mob.dmi',,"phaseout",,M.dir)
+
+/obj/item/device/perfect_tele/proc/phase_in(var/mob/M,var/turf/T)
+
+ if(!M || !T)
+ return
+
+ spk.start()
+ playsound(T, 'sound/effects/phasein.ogg', 25, 1)
+ playsound(T, 'sound/effects/sparks2.ogg', 50, 1)
+ anim(T,M,'icons/mob/mob.dmi',,"phasein",,M.dir)
+ spk.set_up(5, 0, src)
+ spk.attach(src)
+
+/obj/item/device/perfect_tele_beacon
+ name = "translocator beacon"
+ desc = "That's unusual."
+ icon = 'icons/obj/device_alt.dmi'
+ icon_state = "motion2"
+ w_class = ITEMSIZE_TINY
+
+ var/tele_name
+ var/obj/item/device/perfect_tele/tele_hand
+ var/creator
+ var/warned_users = list()
+ var/tele_network = null
+
+/obj/item/device/perfect_tele_beacon/New()
+ ..()
+ flags |= NOBLUDGEON
+
+/obj/item/device/perfect_tele_beacon/Destroy()
+ tele_name = null
+ tele_hand = null
+ return ..()
+
+/obj/item/device/perfect_tele_beacon/attack_hand(mob/user)
+ if((user.ckey != creator) && !(user.ckey in warned_users))
+ warned_users |= user.ckey
+ var/choice = alert(user,"This device is a translocator beacon. Having it on your person may mean that anyone \
+ who teleports to this beacon gets teleported into your selected vore-belly. If you are prey-only \
+ or don't wish to potentially have a random person teleported into you, it's suggested that you \
+ not carry this around.","OOC WARNING","Take It","Leave It")
+ if(choice == "Leave It")
+ return
+
+ ..()
+
+/obj/item/device/perfect_tele_beacon/stationary
+ name = "stationary translocator beacon"
+ icon = 'icons/obj/radio_vr.dmi'
+ icon_state = "floor_beacon"
+ w_class = ITEMSIZE_HUGE
+ anchored = 1
+
+GLOBAL_LIST_BOILERPLATE(premade_tele_beacons, /obj/item/device/perfect_tele_beacon/stationary)
+
+/obj/item/device/perfect_tele_beacon/attack_self(mob/user)
+ if(!isliving(user))
+ return
+ var/mob/living/L = user
+ var/confirm = alert(user, "You COULD eat the beacon...", "Eat beacon?", "Eat it!", "No, thanks.")
+ if(confirm == "Eat it!")
+ var/obj/belly/bellychoice = input("Which belly?","Select A Belly") as null|anything in L.vore_organs
+ if(bellychoice)
+ user.visible_message("[user] is trying to stuff \the [src] into [user.gender == MALE ? "his" : user.gender == FEMALE ? "her" : "their"] [bellychoice]!","You begin putting \the [src] into your [bellychoice]!")
+ if(do_after(user,5 SECONDS,src))
+ user.unEquip(src)
+ forceMove(bellychoice)
+ user.visible_message("[user] eats a telebeacon!","You eat the the beacon!")
+
+// A single-beacon variant for use by miners (or whatever)
+/obj/item/device/perfect_tele/one_beacon
+ name = "mini-translocator"
+ desc = "A more limited translocator with a single beacon, useful for some things, like setting the mining department on fire accidentally. Legal for use in the pursuit of NanoTrasen interests, namely mining and exploration."
+ icon_state = "minitrans"
+ beacons_left = 1 //Just one
+ cell_type = /obj/item/weapon/cell/device
+ origin_tech = list(TECH_MAGNET = 5, TECH_BLUESPACE = 5)
+
+/*
+/obj/item/device/perfect_tele/one_beacon/teleport_checks(mob/living/target,mob/living/user)
+ var/turf/T = get_turf(destination)
+ if(T && user.z != T.z)
+ to_chat(user,"\The [src] is too far away from the beacon. Try getting closer first!")
+ return FALSE
+ return ..()
+*/
+
+/obj/item/device/perfect_tele/alien
+ name = "alien translocator"
+ desc = "This strange device allows one to teleport people and objects across large distances."
+
+ cell_type = /obj/item/weapon/cell/device/weapon/recharge/alien
+ charge_cost = 400
+ beacons_left = 6
+ failure_chance = 0 //Percent
+ longrange = 1
+ abductor = 1
+
+/obj/item/device/perfect_tele/frontier
+ icon_state = "minitrans"
+ beacons_left = 1 //Just one
+ battery_lock = 1
+ unacidable = 1
+ failure_chance = 0 //Percent
+ var/loc_network = null
+ var/phase_power = 75
+ var/recharging = 0
+
+/obj/item/device/perfect_tele/frontier/unload_ammo(var/mob/user)
+ if(recharging)
+ return
+ recharging = 1
+ update_icon()
+ user.visible_message("[user] opens \the [src] and starts pumping the handle.", \
+ "You open \the [src] and start pumping the handle.")
+ while(recharging)
+ if(!do_after(user, 10, src))
+ break
+ playsound(get_turf(src),'sound/items/change_drill.ogg',25,1)
+ if(power_source.give(phase_power) < phase_power)
+ break
+
+ recharging = 0
+ update_icon()
+
+/obj/item/device/perfect_tele/frontier/update_icon()
+ if(recharging)
+ icon_state = "[initial(icon_state)]_o"
+ update_held_icon()
+ return
+ ..()
+
+/obj/item/device/perfect_tele/frontier/staff
+ name = "centcom translocator"
+ desc = "Similar to translocator technology, however, most of its destinations are hardcoded."
+ charge_cost = 1200 // Enough for one person and their partner
+ loc_network = "centcom"
+ longrange = 1
+
+/obj/item/device/perfect_tele/frontier/staff/New()
+ ..()
+ for(var/obj/item/device/perfect_tele_beacon/stationary/nb in premade_tele_beacons)
+ if(nb.tele_network == loc_network)
+ beacons[nb.tele_name] = nb
+
+/obj/item/device/perfect_tele/frontier/unknown
+ name = "modified translocator"
+ desc = "This crank-charged translocator has only one beacon, but it already has a destination preprogrammed into it."
+ charge_cost = 1200 // Enough for one person and their partner
+ longrange = 1
+ abductor = 1
+
+/obj/item/device/perfect_tele/frontier/unknown/New()
+ ..()
+ for(var/obj/item/device/perfect_tele_beacon/stationary/nb in premade_tele_beacons)
+ if(nb.tele_network == loc_network)
+ beacons[nb.tele_name] = nb
+
+/obj/item/device/perfect_tele/frontier/unknown/one
+ loc_network = "unkone"
+/obj/item/device/perfect_tele/frontier/unknown/two
+ loc_network = "unktwo"
+/obj/item/device/perfect_tele/frontier/unknown/three
+ loc_network = "unkthree"
+/obj/item/device/perfect_tele/frontier/unknown/four
+ loc_network = "unkfour"
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index d457ccf7d1a..92269ead776 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -255,12 +255,14 @@
name = "toy sword"
desc = "A cheap, plastic replica of an energy sword. Realistic sounds! Ages 8 and up."
icon = 'icons/obj/weapons.dmi'
- icon_state = "sword0"
+ icon_state = "esword"
+ var/lcolor
+ var/rainbow = FALSE
item_icons = list(
slot_l_hand_str = 'icons/mob/items/lefthand_melee.dmi',
slot_r_hand_str = 'icons/mob/items/righthand_melee.dmi',
)
- var/active = 0.0
+ var/active = 0
w_class = ITEMSIZE_SMALL
attack_verb = list("attacked", "struck", "hit")
@@ -269,22 +271,54 @@
if (src.active)
user << "You extend the plastic blade with a quick flick of your wrist."
playsound(user, 'sound/weapons/saberon.ogg', 50, 1)
- src.icon_state = "swordblue"
+ src.item_state = "[icon_state]_blade"
src.w_class = ITEMSIZE_LARGE
else
user << "You push the plastic blade back down into the handle."
playsound(user, 'sound/weapons/saberoff.ogg', 50, 1)
- src.icon_state = "sword0"
+ src.item_state = "[icon_state]"
src.w_class = ITEMSIZE_SMALL
-
- if(istype(user,/mob/living/carbon/human))
- var/mob/living/carbon/human/H = user
- H.update_inv_l_hand()
- H.update_inv_r_hand()
-
+ update_icon()
src.add_fingerprint(user)
return
+/obj/item/toy/sword/update_icon()
+ . = ..()
+ var/mutable_appearance/blade_overlay = mutable_appearance(icon, "[icon_state]_blade")
+ blade_overlay.color = lcolor
+ cut_overlays() //So that it doesn't keep stacking overlays non-stop on top of each other
+ if(active)
+ add_overlay(blade_overlay)
+ if(istype(usr,/mob/living/carbon/human))
+ var/mob/living/carbon/human/H = usr
+ H.update_inv_l_hand()
+ H.update_inv_r_hand()
+
+/obj/item/toy/sword/AltClick(mob/living/user)
+ if(!in_range(src, user)) //Basic checks to prevent abuse
+ return
+ if(user.incapacitated() || !istype(user))
+ to_chat(user, "You can't do that right now!")
+ return
+
+ if(alert("Are you sure you want to recolor your blade?", "Confirm Recolor", "Yes", "No") == "Yes")
+ var/energy_color_input = input(usr,"","Choose Energy Color",lcolor) as color|null
+ if(energy_color_input)
+ lcolor = sanitize_hexcolor(energy_color_input)
+ update_icon()
+
+/obj/item/toy/sword/examine(mob/user)
+ ..()
+ to_chat(user, "Alt-click to recolor it.")
+
+/obj/item/toy/sword/attackby(obj/item/weapon/W, mob/user)
+ if(istype(W, /obj/item/device/multitool) && !active)
+ if(!rainbow)
+ rainbow = TRUE
+ else
+ rainbow = FALSE
+ to_chat(user, "You manipulate the color controller in [src].")
+ update_icon()
/obj/item/toy/katana
name = "replica katana"
desc = "Woefully underpowered in D20."
@@ -322,6 +356,12 @@
qdel(src)
/obj/item/toy/snappop/Crossed(H as mob|obj)
+ //VOREStation Edit begin: SHADEKIN
+ var/mob/SK = H
+ if(istype(SK))
+ if(SK.shadekin_phasing_check())
+ return
+ //VOREStation Edit end: SHADEKIN
if((ishuman(H))) //i guess carp and shit shouldn't set them off
var/mob/living/carbon/M = H
if(M.m_intent == "run")
@@ -938,7 +978,7 @@
/obj/item/toy/plushie/mouse
name = "mouse plush"
desc = "A plushie of a delightful mouse! What was once considered a vile rodent is now your very best friend."
- icon_state = "mouseplushie"
+ icon_state = "mouseplushie" //TFF 12/11/19 - updated icon to show a sprite that doesn't replicate a dead mouse. Heck you for that! >:C
pokephrase = "Squeak!"
/obj/item/toy/plushie/kitten
diff --git a/code/game/objects/items/weapons/RCD.dm b/code/game/objects/items/weapons/RCD.dm
index f7f22d7611f..034063c4532 100644
--- a/code/game/objects/items/weapons/RCD.dm
+++ b/code/game/objects/items/weapons/RCD.dm
@@ -243,6 +243,13 @@
electric_cost_coefficent = 41.66 // Twice as efficent, out of pity.
toolspeed = 0.5 // Twice as fast, since borg versions typically have this.
+/obj/item/weapon/rcd/electric/mounted/borg/swarm
+ can_remove_rwalls = FALSE
+ name = "Rapid Assimilation Device"
+ ranged = TRUE
+ toolspeed = 0.7
+ material_to_use = MAT_STEELHULL
+
/obj/item/weapon/rcd/electric/mounted/borg/lesser
can_remove_rwalls = FALSE
diff --git a/code/game/objects/items/weapons/clown_items.dm b/code/game/objects/items/weapons/clown_items.dm
index cb6a4e4a424..890e557f50f 100644
--- a/code/game/objects/items/weapons/clown_items.dm
+++ b/code/game/objects/items/weapons/clown_items.dm
@@ -9,6 +9,12 @@
* Banana Peals
*/
/obj/item/weapon/bananapeel/Crossed(AM as mob|obj)
+ //VOREStation Edit begin: SHADEKIN
+ var/mob/SK = AM
+ if(istype(SK))
+ if(SK.shadekin_phasing_check())
+ return
+ //VOREStation Edit end: SHADEKIN
if (istype(AM, /mob/living))
var/mob/living/M = AM
M.slip("the [src.name]",4)
@@ -24,6 +30,12 @@
reagents.add_reagent("cleaner", 5)
/obj/item/weapon/soap/Crossed(AM as mob|obj)
+ //VOREStation Edit begin: SHADEKIN
+ var/mob/SK = AM
+ if(istype(SK))
+ if(SK.shadekin_phasing_check())
+ return
+ //VOREStation Edit end: SHADEKIN
if (istype(AM, /mob/living))
var/mob/living/M = AM
M.slip("the [src.name]",3)
diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm
index 12ed2459c60..6c5f2ced838 100644
--- a/code/game/objects/items/weapons/handcuffs.dm
+++ b/code/game/objects/items/weapons/handcuffs.dm
@@ -197,6 +197,9 @@ var/last_chew = 0
breakouttime = 200
cuff_type = "duct tape"
+/obj/item/weapon/handcuffs/cable/tape/cyborg
+ dispenser = TRUE
+
//Legcuffs. Not /really/ handcuffs, but its close enough.
/obj/item/weapon/handcuffs/legcuffs
name = "legcuffs"
diff --git a/code/game/objects/items/weapons/id cards/station_ids.dm b/code/game/objects/items/weapons/id cards/station_ids.dm
index 4d37f154b36..7a2e39014c1 100644
--- a/code/game/objects/items/weapons/id cards/station_ids.dm
+++ b/code/game/objects/items/weapons/id cards/station_ids.dm
@@ -23,8 +23,6 @@
var/primary_color = rgb(0,0,0) // Obtained by eyedroppering the stripe in the middle of the card
var/secondary_color = rgb(0,0,0) // Likewise for the oval in the top-left corner
- var/datum/job/job_access_type = /datum/job/assistant // Job type to acquire access rights from, if any
-
//alt titles are handled a bit weirdly in order to unobtrusively integrate into existing ID system
var/assignment = null //can be alt title or the actual job
var/rank = null //actual job
@@ -134,16 +132,6 @@
icon_state = "silver"
item_state = "silver_id"
-/obj/item/weapon/card/id/silver/secretary
- assignment = "Command Secretary"
- rank = "Command Secretary"
- job_access_type = /datum/job/secretary
-
-/obj/item/weapon/card/id/silver/hop
- assignment = "Head of Personnel"
- rank = "Head of Personnel"
- job_access_type = /datum/job/hop
-
/obj/item/weapon/card/id/gold
name = "identification card"
desc = "A golden card which shows power and might."
@@ -154,13 +142,11 @@
/obj/item/weapon/card/id/gold/captain
assignment = "Colony Director"
rank = "Colony Director"
- job_access_type = /datum/job/captain
/obj/item/weapon/card/id/gold/captain/spare
name = "\improper Colony Director's spare ID"
desc = "The spare ID of the High Lord himself."
registered_name = "Colony Director"
- job_access_type = /datum/job/captain
/obj/item/weapon/card/id/synthetic
name = "\improper Synthetic ID"
@@ -205,31 +191,6 @@
primary_color = rgb(189,237,237)
secondary_color = rgb(223,255,255)
-/obj/item/weapon/card/id/medical/doctor
- assignment = "Medical Doctor"
- rank = "Medical Doctor"
- job_access_type = /datum/job/doctor
-
-/obj/item/weapon/card/id/medical/chemist
- assignment = "Chemist"
- rank = "Chemist"
- job_access_type = /datum/job/chemist
-
-/obj/item/weapon/card/id/medical/geneticist
- assignment = "Geneticist"
- rank = "Geneticist"
- job_access_type = /datum/job/doctor //geneticist
-
-/obj/item/weapon/card/id/medical/psychiatrist
- assignment = "Psychiatrist"
- rank = "Psychiatrist"
- job_access_type = /datum/job/psychiatrist
-
-/obj/item/weapon/card/id/medical/paramedic
- assignment = "Paramedic"
- rank = "Paramedic"
- job_access_type = /datum/job/paramedic
-
/obj/item/weapon/card/id/medical/head
name = "identification card"
desc = "A card which represents care and compassion."
@@ -238,7 +199,6 @@
secondary_color = rgb(255,223,127)
assignment = "Chief Medical Officer"
rank = "Chief Medical Officer"
- job_access_type = /datum/job/cmo
/obj/item/weapon/card/id/security
name = "identification card"
@@ -247,21 +207,6 @@
primary_color = rgb(189,47,0)
secondary_color = rgb(223,127,95)
-/obj/item/weapon/card/id/security/officer
- assignment = "Security Officer"
- rank = "Security Officer"
- job_access_type = /datum/job/officer
-
-/obj/item/weapon/card/id/security/detective
- assignment = "Detective"
- rank = "Detective"
- job_access_type = /datum/job/detective
-
-/obj/item/weapon/card/id/security/warden
- assignment = "Warden"
- rank = "Warden"
- job_access_type = /datum/job/warden
-
/obj/item/weapon/card/id/security/head
name = "identification card"
desc = "A card which represents honor and protection."
@@ -270,7 +215,6 @@
secondary_color = rgb(255,223,127)
assignment = "Head of Security"
rank = "Head of Security"
- job_access_type = /datum/job/hos
/obj/item/weapon/card/id/engineering
name = "identification card"
@@ -279,16 +223,6 @@
primary_color = rgb(189,94,0)
secondary_color = rgb(223,159,95)
-/obj/item/weapon/card/id/engineering/engineer
- assignment = "Station Engineer"
- rank = "Station Engineer"
- job_access_type = /datum/job/engineer
-
-/obj/item/weapon/card/id/engineering/atmos
- assignment = "Atmospheric Technician"
- rank = "Atmospheric Technician"
- job_access_type = /datum/job/atmos
-
/obj/item/weapon/card/id/engineering/head
name = "identification card"
desc = "A card which represents creativity and ingenuity."
@@ -297,7 +231,6 @@
secondary_color = rgb(255,223,127)
assignment = "Chief Engineer"
rank = "Chief Engineer"
- job_access_type = /datum/job/chief_engineer
/obj/item/weapon/card/id/science
name = "identification card"
@@ -306,21 +239,6 @@
primary_color = rgb(142,47,142)
secondary_color = rgb(191,127,191)
-/obj/item/weapon/card/id/science/scientist
- assignment = "Scientist"
- rank = "Scientist"
- job_access_type = /datum/job/scientist
-
-/obj/item/weapon/card/id/science/xenobiologist
- assignment = "Xenobiologist"
- rank = "Xenobiologist"
- job_access_type = /datum/job/xenobiologist
-
-/obj/item/weapon/card/id/science/roboticist
- assignment = "Roboticist"
- rank = "Roboticist"
- job_access_type = /datum/job/roboticist
-
/obj/item/weapon/card/id/science/head
name = "identification card"
desc = "A card which represents knowledge and reasoning."
@@ -329,7 +247,6 @@
secondary_color = rgb(255,223,127)
assignment = "Research Director"
rank = "Research Director"
- job_access_type = /datum/job/rd
/obj/item/weapon/card/id/cargo
name = "identification card"
@@ -338,16 +255,6 @@
primary_color = rgb(142,94,0)
secondary_color = rgb(191,159,95)
-/obj/item/weapon/card/id/cargo/cargo_tech
- assignment = "Cargo Technician"
- rank = "Cargo Technician"
- job_access_type = /datum/job/cargo_tech
-
-/obj/item/weapon/card/id/cargo/mining
- assignment = "Shaft Miner"
- rank = "Shaft Miner"
- job_access_type = /datum/job/mining
-
/obj/item/weapon/card/id/cargo/head
name = "identification card"
desc = "A card which represents service and planning."
@@ -356,12 +263,10 @@
secondary_color = rgb(255,223,127)
assignment = "Quartermaster"
rank = "Quartermaster"
- job_access_type = /datum/job/qm
/obj/item/weapon/card/id/assistant
assignment = USELESS_JOB //VOREStation Edit - Visitor not Assistant
rank = USELESS_JOB //VOREStation Edit - Visitor not Assistant
- job_access_type = /datum/job/assistant
/obj/item/weapon/card/id/civilian
name = "identification card"
@@ -371,42 +276,6 @@
secondary_color = rgb(95,159,191)
assignment = "Civilian"
rank = "Assistant"
- job_access_type = /datum/job/assistant
-
-/obj/item/weapon/card/id/civilian/bartender
- assignment = "Bartender"
- rank = "Bartender"
- job_access_type = /datum/job/bartender
-
-/obj/item/weapon/card/id/civilian/botanist
- assignment = "Botanist"
- rank = "Botanist"
- job_access_type = /datum/job/hydro
-
-/obj/item/weapon/card/id/civilian/chaplain
- assignment = "Chaplain"
- rank = "Chaplain"
- job_access_type = /datum/job/chaplain
-
-/obj/item/weapon/card/id/civilian/chef
- assignment = "Chef"
- rank = "Chef"
- job_access_type = /datum/job/chef
-
-/obj/item/weapon/card/id/civilian/internal_affairs_agent
- assignment = "Internal Affairs Agent"
- rank = "Internal Affairs Agent"
- job_access_type = /datum/job/lawyer
-
-/obj/item/weapon/card/id/civilian/janitor
- assignment = "Janitor"
- rank = "Janitor"
- job_access_type = /datum/job/janitor
-
-/obj/item/weapon/card/id/civilian/librarian
- assignment = "Librarian"
- rank = "Librarian"
- job_access_type = /datum/job/librarian
/obj/item/weapon/card/id/civilian/head //This is not the HoP. There's no position that uses this right now.
name = "identification card"
diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm
index c00d396e4d6..ff4146b8a0a 100644
--- a/code/game/objects/items/weapons/implants/implant.dm
+++ b/code/game/objects/items/weapons/implants/implant.dm
@@ -66,8 +66,7 @@
/obj/item/weapon/implant/proc/implant_loadout(var/mob/living/carbon/human/H)
if(H)
- var/obj/item/organ/external/affected = H.organs_by_name[initialize_loc]
- if(handle_implant(H, affected))
+ if(handle_implant(H, initialize_loc))
invisibility = initial(invisibility)
post_implant(H)
diff --git a/code/game/objects/items/weapons/implants/implantdud.dm b/code/game/objects/items/weapons/implants/implantdud.dm
index 896ea2358a0..110051e58d6 100644
--- a/code/game/objects/items/weapons/implants/implantdud.dm
+++ b/code/game/objects/items/weapons/implants/implantdud.dm
@@ -19,12 +19,3 @@
icon = 'icons/obj/device.dmi'
icon_state = "implant"
roundstart = FALSE
-
-/obj/item/weapon/implant/dud/Initialize()
- ..()
- if(roundstart)
- invisibility = 100
- ..()
- spawn(3)
- if(!ishuman(loc) && !QDELETED(src))
- qdel(src)
diff --git a/code/game/objects/items/weapons/implants/neuralbasic.dm b/code/game/objects/items/weapons/implants/neuralbasic.dm
index 0c5fe2b3dab..18d472154bb 100644
--- a/code/game/objects/items/weapons/implants/neuralbasic.dm
+++ b/code/game/objects/items/weapons/implants/neuralbasic.dm
@@ -105,10 +105,3 @@ Implant Specifics:
"}
my_brain.take_damage(15)
my_brain = null
return
-
-/obj/item/weapon/implant/neural/roundstart/Initialize()
- invisibility = 100
- ..()
- spawn(3)
- if(!ishuman(loc) && !QDELETED(src))
- qdel(src)
diff --git a/code/game/objects/items/weapons/material/material_weapons.dm b/code/game/objects/items/weapons/material/material_weapons.dm
index a911d1e1375..3f2b1978d37 100644
--- a/code/game/objects/items/weapons/material/material_weapons.dm
+++ b/code/game/objects/items/weapons/material/material_weapons.dm
@@ -86,10 +86,13 @@
health--
check_health()
-/obj/item/weapon/material/attackby(obj/item/weapon/W, mob/user as mob)
+/obj/item/weapon/material/attackby(obj/item/weapon/W, mob/user)
if(istype(W, /obj/item/weapon/whetstone))
var/obj/item/weapon/whetstone/whet = W
repair(whet.repair_amount, whet.repair_time, user)
+ if(istype(W, /obj/item/weapon/material/sharpeningkit))
+ var/obj/item/weapon/material/sharpeningkit/SK = W
+ repair(SK.repair_amount, SK.repair_time, user)
..()
/obj/item/weapon/material/proc/check_health(var/consumed)
@@ -134,7 +137,19 @@
to_chat(user, "You can't repair \the [src].")
return
-
+/obj/item/weapon/material/proc/sharpen(var/material, var/sharpen_time, var/kit, mob/living/M)
+ if(!fragile)
+ if(health < initial(health))
+ to_chat(M, "You should repair [src] first. Try using [kit] on it.")
+ return FALSE
+ M.visible_message("[M] begins to replace parts of [src] with [kit].", "You begin to replace parts of [src] with [kit].")
+ if(do_after(usr, sharpen_time))
+ M.visible_message("[M] has finished replacing parts of [src].", "You finish replacing parts of [src].")
+ src.set_material(material)
+ return TRUE
+ else
+ to_chat(M, "You can't sharpen and re-edge [src].")
+ return FALSE
/*
Commenting this out pending rebalancing of radiation based on small objects.
@@ -162,4 +177,4 @@ Commenting this out pending rebalancing of radiation based on small objects.
TemperatureAct(150)
else
return ..()
-*/
\ No newline at end of file
+*/
diff --git a/code/game/objects/items/weapons/material/shards.dm b/code/game/objects/items/weapons/material/shards.dm
index 7d7d78eebaa..8df81e434c3 100644
--- a/code/game/objects/items/weapons/material/shards.dm
+++ b/code/game/objects/items/weapons/material/shards.dm
@@ -108,6 +108,12 @@
/obj/item/weapon/material/shard/Crossed(AM as mob|obj)
..()
+ //VOREStation Edit begin: SHADEKIN
+ var/mob/SK = AM
+ if(istype(SK))
+ if(SK.shadekin_phasing_check())
+ return
+ //VOREStation Edit end: SHADEKIN
if(isliving(AM))
var/mob/M = AM
diff --git a/code/game/objects/items/weapons/material/whetstone.dm b/code/game/objects/items/weapons/material/whetstone.dm
index e312680d1b0..628f450e3dc 100644
--- a/code/game/objects/items/weapons/material/whetstone.dm
+++ b/code/game/objects/items/weapons/material/whetstone.dm
@@ -8,4 +8,69 @@
force = 3
w_class = ITEMSIZE_SMALL
var/repair_amount = 5
- var/repair_time = 40
\ No newline at end of file
+ var/repair_time = 40
+
+/obj/item/weapon/whetstone/attackby(obj/item/I, mob/user)
+ if(istype(I, /obj/item/stack/material))
+ var/obj/item/stack/material/M = I
+ if(M.amount >= 5)
+ to_chat(user, "You begin to refine the [src] with [M]...")
+ if(do_after(user, 70))
+ M.use(5)
+ var/obj/item/SK
+ SK = new /obj/item/weapon/material/sharpeningkit(get_turf(user), M.material.name)
+ to_chat(user, "You sharpen and refine the [src] into \a [SK].")
+ qdel(src)
+ if(SK)
+ user.put_in_hands(SK)
+ else
+ to_chat(user, "You need 5 [src] to refine it into a sharpening kit.")
+
+/obj/item/weapon/material/sharpeningkit
+ name = "sharpening kit"
+ desc = "A refined, fine grit whetstone, useful for sharpening dull edges, polishing out dents, and, with extra material, replacing an edge."
+ icon = 'icons/obj/kitchen.dmi'
+ icon_state = "sharpener"
+ hitsound = 'sound/weapons/genhit3.ogg'
+ force_divisor = 0.7
+ thrown_force_divisor = 1
+ var/repair_amount = 5
+ var/repair_time = 40
+ var/sharpen_time = 100
+ var/uses = 0
+
+/obj/item/weapon/material/sharpeningkit/examine(mob/user, distance)
+ . = ..()
+ to_chat(user, "There [uses == 1 ? "is" : "are"] [uses] [material] [uses == 1 ? src.material.sheet_singular_name : src.material.sheet_plural_name] left for use.")
+/obj/item/weapon/material/sharpeningkit/Initialize()
+ . = ..()
+ setrepair()
+
+/obj/item/weapon/material/sharpeningkit/proc/setrepair()
+ repair_amount = material.hardness * 0.1
+ repair_time = material.weight * 0.5
+ sharpen_time = material.weight * 3
+
+/obj/item/weapon/material/sharpeningkit/attackby(obj/item/weapon/W, mob/user)
+ if(istype(W, /obj/item/stack/material))
+ var/obj/item/stack/material/S = W
+ if(S.material == material)
+ S.use(1)
+ uses += 1
+ to_chat(user, "You add a [S.material.name] [S.material.sheet_singular_name] to [src].")
+ return
+
+ if(istype(W, /obj/item/weapon/material))
+ if(istype(W, /obj/item/weapon/material/sharpeningkit))
+ to_chat(user, "Really? Sharpening a [W] with [src]? You goofball.")
+ return
+ var/obj/item/weapon/material/M = W
+ if(uses >= M.w_class*2)
+ if(M.sharpen(src.material.name, sharpen_time, src, user))
+ uses -= M.w_class*2
+ return
+ else
+ to_chat(user, "Not enough material to sharpen [M]. You need [M.w_class*2] [M.material.sheet_plural_name].")
+ return
+ else
+ to_chat(user, "You can't sharpen [W] with [src]!")
diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm
index d935d4eaa29..17d7bc4621a 100644
--- a/code/game/objects/items/weapons/melee/energy.dm
+++ b/code/game/objects/items/weapons/melee/energy.dm
@@ -11,17 +11,46 @@
var/lrange = 2
var/lpower = 2
var/lcolor = "#0099FF"
-
+ var/colorable = FALSE
+ var/rainbow = FALSE
// If it uses energy.
var/use_cell = FALSE
var/hitcost = 120
var/obj/item/weapon/cell/bcell = null
var/cell_type = /obj/item/weapon/cell/device
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/items/lefthand_melee.dmi',
+ slot_r_hand_str = 'icons/mob/items/righthand_melee.dmi',
+ )
+
+/obj/item/weapon/melee/energy/sword/green/New()
+ colorable = FALSE
+ lcolor = "#008000"
+
+/obj/item/weapon/melee/energy/sword/red/New()
+ colorable = FALSE
+ lcolor = "#FF0000"
+
+/obj/item/weapon/melee/energy/sword/blue/New()
+ colorable = FALSE
+ lcolor = "#0000FF"
+
+/obj/item/weapon/melee/energy/sword/purple/New()
+ colorable = FALSE
+ lcolor = "#800080"
+
+/obj/item/weapon/melee/energy/sword/white/New()
+ colorable = FALSE
+ lcolor = "#FFFFFF"
/obj/item/weapon/melee/energy/proc/activate(mob/living/user)
if(active)
return
active = 1
+ if(rainbow)
+ item_state = "[icon_state]_blade_rainbow"
+ else
+ item_state = "[icon_state]_blade"
embed_chance = active_embed_chance
force = active_force
throwforce = active_throwforce
@@ -29,12 +58,14 @@
edge = 1
w_class = active_w_class
playsound(user, 'sound/weapons/saberon.ogg', 50, 1)
+ update_icon()
set_light(lrange, lpower, lcolor)
/obj/item/weapon/melee/energy/proc/deactivate(mob/living/user)
if(!active)
return
playsound(user, 'sound/weapons/saberoff.ogg', 50, 1)
+ item_state = "[icon_state]"
active = 0
embed_chance = initial(embed_chance)
force = initial(force)
@@ -42,6 +73,7 @@
sharp = initial(sharp)
edge = initial(edge)
w_class = initial(w_class)
+ update_icon()
set_light(0,0)
/obj/item/weapon/melee/energy/proc/use_charge(var/cost)
@@ -102,6 +134,13 @@
return ..()
/obj/item/weapon/melee/energy/attackby(obj/item/weapon/W, mob/user)
+ if(istype(W, /obj/item/device/multitool) && colorable && !active)
+ if(!rainbow)
+ rainbow = TRUE
+ else
+ rainbow = FALSE
+ to_chat(user, "You manipulate the color controller in [src].")
+ update_icon()
if(use_cell)
if(istype(W, cell_type))
if(!bcell)
@@ -125,13 +164,53 @@
/obj/item/weapon/melee/energy/get_cell()
return bcell
+/obj/item/weapon/melee/energy/update_icon()
+ . = ..()
+ var/mutable_appearance/blade_overlay = mutable_appearance(icon, "[icon_state]_blade")
+ blade_overlay.color = lcolor
+ color = lcolor
+ if(rainbow)
+ blade_overlay = mutable_appearance(icon, "[icon_state]_blade_rainbow")
+ blade_overlay.color = "FFFFFF"
+ color = "FFFFFF"
+ cut_overlays() //So that it doesn't keep stacking overlays non-stop on top of each other
+ if(active)
+ add_overlay(blade_overlay)
+ if(istype(usr,/mob/living/carbon/human))
+ var/mob/living/carbon/human/H = usr
+ H.update_inv_l_hand()
+ H.update_inv_r_hand()
+
+
+
+
+/obj/item/weapon/melee/energy/AltClick(mob/living/user)
+ if(!colorable) //checks if is not colorable
+ return
+ if(!in_range(src, user)) //Basic checks to prevent abuse
+ return
+ if(user.incapacitated() || !istype(user))
+ to_chat(user, "You can't do that right now!")
+ return
+
+ if(alert("Are you sure you want to recolor your blade?", "Confirm Recolor", "Yes", "No") == "Yes")
+ var/energy_color_input = input(usr,"","Choose Energy Color",lcolor) as color|null
+ if(energy_color_input)
+ lcolor = sanitize_hexcolor(energy_color_input)
+ update_icon()
+
+/obj/item/weapon/melee/energy/examine(mob/user)
+ ..()
+ to_chat(user, "Alt-click to recolor it.")
+
/*
* Energy Axe
*/
/obj/item/weapon/melee/energy/axe
name = "energy axe"
desc = "An energised battle axe."
- icon_state = "axe0"
+ icon_state = "eaxe"
+ item_state = "eaxe"
//active_force = 150 //holy...
active_force = 60
active_throwforce = 35
@@ -152,13 +231,11 @@
/obj/item/weapon/melee/energy/axe/activate(mob/living/user)
..()
damtype = SEARING
- icon_state = "axe1"
to_chat(user, "\The [src] is now energised.")
/obj/item/weapon/melee/energy/axe/deactivate(mob/living/user)
..()
damtype = BRUTE
- icon_state = initial(icon_state)
to_chat(user, "\The [src] is de-energised. It's just a regular axe now.")
/obj/item/weapon/melee/energy/axe/suicide_act(mob/user)
@@ -187,7 +264,8 @@
color
name = "energy sword"
desc = "May the force be within you."
- icon_state = "sword0"
+ icon_state = "esword"
+ item_state = "esword"
active_force = 30
active_throwforce = 20
active_w_class = ITEMSIZE_LARGE
@@ -200,9 +278,8 @@
origin_tech = list(TECH_MAGNET = 3, TECH_ILLEGAL = 4)
sharp = 1
edge = 1
- var/blade_color
- var/random_color = TRUE
- var/active_state = "sword"
+ colorable = TRUE
+
projectile_parry_chance = 65
@@ -211,30 +288,6 @@
if(!istype(loc,/mob))
deactivate(user)
-/obj/item/weapon/melee/energy/sword/New()
- if(random_color)
- blade_color = pick("red","blue","green","purple","white")
- lcolor = blade_color
-
-/obj/item/weapon/melee/energy/sword/green/New()
- blade_color = "green"
- lcolor = "#008000"
-
-/obj/item/weapon/melee/energy/sword/red/New()
- blade_color = "red"
- lcolor = "#FF0000"
-
-/obj/item/weapon/melee/energy/sword/blue/New()
- blade_color = "blue"
- lcolor = "#0000FF"
-
-/obj/item/weapon/melee/energy/sword/purple/New()
- blade_color = "purple"
- lcolor = "#800080"
-
-/obj/item/weapon/melee/energy/sword/white/New()
- blade_color = "white"
- lcolor = "#FFFFFF"
/obj/item/weapon/melee/energy/sword/activate(mob/living/user)
if(!active)
@@ -242,14 +295,13 @@
..()
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
- icon_state = "[active_state][blade_color]"
+
/obj/item/weapon/melee/energy/sword/deactivate(mob/living/user)
if(active)
to_chat(user, "\The [src] deactivates!")
..()
attack_verb = list()
- icon_state = initial(icon_state)
/obj/item/weapon/melee/energy/sword/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
if(active && default_parry_check(user, attacker, damage_source) && prob(60))
@@ -284,11 +336,10 @@
/obj/item/weapon/melee/energy/sword/pirate
name = "energy cutlass"
desc = "Arrrr matey."
- icon_state = "cutlass0"
+ icon_state = "cutlass"
+ item_state = "cutlass"
+ colorable = TRUE
-/obj/item/weapon/melee/energy/sword/pirate/activate(mob/living/user)
- ..()
- icon_state = "cutlass1"
/*
*Ionic Rapier
@@ -300,8 +351,8 @@
description_info = "This is a dangerous melee weapon that will deliver a moderately powerful electromagnetic pulse to whatever it strikes. \
Striking a lesser robotic entity will compel it to attack you, as well. It also does extra burn damage to robotic entities, but it does \
very little damage to purely organic targets."
- icon_state = "ionic_rapier0"
- random_color = FALSE
+ icon_state = "ionrapier"
+ item_state = "ionrapier"
active_force = 5
active_throwforce = 3
active_embed_chance = 0
@@ -312,7 +363,6 @@
lrange = 2
lpower = 2
lcolor = "#0000FF"
- active_state = "ionic_rapier"
projectile_parry_chance = 30 // It's not specifically designed for cutting and slashing, but it can still, maybe, save your life.
/obj/item/weapon/melee/energy/sword/ionic_rapier/afterattack(var/atom/movable/AM, var/mob/living/user, var/proximity)
@@ -339,6 +389,13 @@
target.taunt(user)
target.adjustFireLoss(force * 6) // 30 Burn, for 50 total.
+/obj/item/weapon/melee/energy/sword/ionic_rapier/lance
+ name = "zero-point lance"
+ desc = "Designed specifically for disrupting electronics at relatively close range, however it is still capable of dealing some damage to living beings."
+ active_force = 20
+ armor_penetration = 15
+ reach = 2
+
/*
* Charge blade. Uses a cell, and costs energy per strike.
*/
@@ -350,6 +407,7 @@
active_force = 25
armor_penetration = 25
projectile_parry_chance = 40
+ colorable = TRUE
hitcost = 75
@@ -357,15 +415,14 @@
..()
bcell = new/obj/item/weapon/cell/device/weapon(src)
-/*
- *Energy Blade
- */
+//Energy Blade (ninja uses this)
//Can't be activated or deactivated, so no reason to be a subtype of energy
/obj/item/weapon/melee/energy/blade
name = "energy blade"
desc = "A concentrated beam of energy in the shape of a blade. Very stylish... and lethal."
icon_state = "blade"
+ item_state = "blade"
force = 40 //Normal attacks deal very high damage - about the same as wielded fire axe
armor_penetration = 100
sharp = 1
@@ -448,49 +505,27 @@
return 1
-/*
- *Energy Spear
- */
+//Energy Spear
/obj/item/weapon/melee/energy/spear
- name = "energy spear"
- desc = "Concentrated energy forming a sharp tip at the end of a long rod."
- icon_state = "espear0"
- armor_penetration = 75
- sharp = 1
- edge = 1
- force = 5
- throwforce = 10
- throw_speed = 7
- throw_range = 11
- reach = 2
- w_class = ITEMSIZE_LARGE
- active_force = 25
- active_throwforce = 30
- active_w_class = ITEMSIZE_HUGE
- var/random_color = TRUE
- var/tip_color = ""
- var/active_state = "espear"
+ name = "energy spear"
+ desc = "Concentrated energy forming a sharp tip at the end of a long rod."
+ icon_state = "espear"
+ armor_penetration = 75
+ sharp = 1
+ edge = 1
+ force = 5
+ throwforce = 10
+ throw_speed = 7
+ throw_range = 11
+ reach = 2
+ w_class = ITEMSIZE_LARGE
+ active_force = 25
+ active_throwforce = 30
+ active_w_class = ITEMSIZE_HUGE
+ colorable = TRUE
-/obj/item/weapon/melee/energy/spear/New()
- if(random_color)
- tip_color = pick("red","blue","green","purple")
- lcolor = tip_color
-/obj/item/weapon/melee/energy/spear/green/New()
- tip_color = "green"
- lcolor = "#008000"
-
-/obj/item/weapon/melee/energy/spear/red/New()
- tip_color = "red"
- lcolor = "#FF0000"
-
-/obj/item/weapon/melee/energy/spear/blue/New()
- tip_color = "blue"
- lcolor = "#0000FF"
-
-/obj/item/weapon/melee/energy/spear/purple/New()
- tip_color = "purple"
lcolor = "#800080"
/obj/item/weapon/melee/energy/spear/activate(mob/living/user)
@@ -498,7 +533,6 @@
to_chat(user, "\The [src] is now energised.")
..()
attack_verb = list("jabbed", "stabbed", "impaled")
- icon_state = "[active_state]-[tip_color]"
/obj/item/weapon/melee/energy/spear/deactivate(mob/living/user)
@@ -506,7 +540,6 @@
to_chat(user, "\The [src] deactivates!")
..()
attack_verb = list("whacked", "beat", "slapped", "thonked")
- icon_state = "espear0"
/obj/item/weapon/melee/energy/spear/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
if(active && default_parry_check(user, attacker, damage_source) && prob(50))
@@ -516,4 +549,4 @@
spark_system.start()
playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1)
return 1
- return 0
\ No newline at end of file
+ return 0
diff --git a/code/game/objects/items/weapons/melee/energy_vr.dm b/code/game/objects/items/weapons/melee/energy_vr.dm
index 34fa7612111..1d188d03caf 100644
--- a/code/game/objects/items/weapons/melee/energy_vr.dm
+++ b/code/game/objects/items/weapons/melee/energy_vr.dm
@@ -1,10 +1,8 @@
/obj/item/weapon/melee/energy/sword/imperial
name = "energy gladius"
desc = "A broad, short energy blade. You'll be glad to have this in a fight."
- icon_state = "sword0"
+ icon_state = "impsword"
icon = 'icons/obj/weapons_vr.dmi'
item_icons = list(slot_l_hand_str = 'icons/mob/items/lefthand_melee_vr.dmi', slot_r_hand_str = 'icons/mob/items/righthand_melee_vr.dmi')
-
-/obj/item/weapon/melee/energy/sword/imperial/activate(mob/living/user)
- ..()
- icon_state = "sword1"
\ No newline at end of file
+ colorable = FALSE
+ lcolor = "#FFFFFF"
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/paint.dm b/code/game/objects/items/weapons/paint.dm
index d3f269abaf1..8e1699c800d 100644
--- a/code/game/objects/items/weapons/paint.dm
+++ b/code/game/objects/items/weapons/paint.dm
@@ -27,7 +27,7 @@ var/global/list/cached_icons = list()
return ..()
New()
- if(paint_type && lentext(paint_type) > 0)
+ if(paint_type && length(paint_type) > 0)
name = paint_type + " " + name
..()
reagents.add_reagent("water", volume*3/5)
diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm
index 5ea586f43dc..6d3310cdc44 100644
--- a/code/game/objects/items/weapons/shields.dm
+++ b/code/game/objects/items/weapons/shields.dm
@@ -115,7 +115,8 @@
name = "energy combat shield"
desc = "A shield capable of stopping most projectile and melee attacks. It can be retracted, expanded, and stored anywhere."
icon = 'icons/obj/weapons.dmi'
- icon_state = "eshield0" // eshield1 for expanded
+ icon_state = "eshield"
+ item_state = "eshield"
slot_flags = SLOT_EARS
flags = NOCONDUCT
force = 3.0
@@ -123,9 +124,16 @@
throw_speed = 1
throw_range = 4
w_class = ITEMSIZE_SMALL
+ var/lrange = 1.5
+ var/lpower = 1.5
+ var/lcolor = "#006AFF"
origin_tech = list(TECH_MATERIAL = 4, TECH_MAGNET = 3, TECH_ILLEGAL = 4)
attack_verb = list("shoved", "bashed")
var/active = 0
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/items/lefthand_melee.dmi',
+ slot_r_hand_str = 'icons/mob/items/righthand_melee.dmi',
+ )
/obj/item/weapon/shield/energy/handle_shield(mob/user)
if(!active)
@@ -175,11 +183,33 @@
return
/obj/item/weapon/shield/energy/update_icon()
- icon_state = "eshield[active]"
+ var/mutable_appearance/blade_overlay = mutable_appearance(icon, "[icon_state]_blade")
+ if(lcolor)
+ blade_overlay.color = lcolor
+ cut_overlays() //So that it doesn't keep stacking overlays non-stop on top of each other
if(active)
- set_light(1.5, 1.5, "#006AFF")
+ add_overlay(blade_overlay)
+ item_state = "[icon_state]_blade"
+ set_light(lrange, lpower, lcolor)
else
set_light(0)
+ item_state = "[icon_state]"
+
+/obj/item/weapon/shield/energy/AltClick(mob/living/user)
+ if(!in_range(src, user)) //Basic checks to prevent abuse
+ return
+ if(user.incapacitated() || !istype(user))
+ to_chat(user, "You can't do that right now!")
+ return
+ if(alert("Are you sure you want to recolor your shield?", "Confirm Recolor", "Yes", "No") == "Yes")
+ var/energy_color_input = input(usr,"","Choose Energy Color",lcolor) as color|null
+ if(energy_color_input)
+ lcolor = sanitize_hexcolor(energy_color_input, desired_format=6, include_crunch=1)
+ update_icon()
+
+/obj/item/weapon/shield/energy/examine(mob/user)
+ ..()
+ to_chat(user, "Alt-click to recolor it.")
/obj/item/weapon/shield/riot/tele
name = "telescopic shield"
@@ -226,4 +256,4 @@
H.update_inv_r_hand()
add_fingerprint(user)
- return
\ No newline at end of file
+ return
diff --git a/code/game/objects/items/weapons/shields_vr.dm b/code/game/objects/items/weapons/shields_vr.dm
index 4d0440e5643..ceab877d4ae 100644
--- a/code/game/objects/items/weapons/shields_vr.dm
+++ b/code/game/objects/items/weapons/shields_vr.dm
@@ -2,7 +2,7 @@
name = "energy scutum"
desc = "It's really easy to mispronounce the name of this shield if you've only read it in books."
icon = 'icons/obj/weapons_vr.dmi'
- icon_state = "eshield0" // eshield1 for expanded
+ icon_state = "impshield" // eshield1 for expanded
item_icons = list(slot_l_hand_str = 'icons/mob/items/lefthand_melee_vr.dmi', slot_r_hand_str = 'icons/mob/items/righthand_melee_vr.dmi')
/obj/item/weapon/shield/fluff/wolfgirlshield
diff --git a/code/game/objects/items/weapons/storage/backpack.dm b/code/game/objects/items/weapons/storage/backpack.dm
index 18c60af4497..f5ea4ead6fd 100644
--- a/code/game/objects/items/weapons/storage/backpack.dm
+++ b/code/game/objects/items/weapons/storage/backpack.dm
@@ -422,3 +422,10 @@
H.visible_message("\The [src] decides not to unpack \the [src]!", \
"You decide not to unpack \the [src]!")
return
+
+/obj/item/weapon/storage/backpack/satchel/ranger
+ name = "ranger satchel"
+ desc = "A satchel designed for the Go Go ERT Rangers series to allow for slightly bigger carry capacity for the ERT-Rangers.\
+ Unlike the show claims, it is not a phoron-enhanced satchel of holding with plot-relevant content."
+ icon = 'icons/obj/clothing/ranger.dmi'
+ icon_state = "ranger_satchel"
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/storage/bags.dm b/code/game/objects/items/weapons/storage/bags.dm
index eea992ec41c..29e86dbbd43 100644
--- a/code/game/objects/items/weapons/storage/bags.dm
+++ b/code/game/objects/items/weapons/storage/bags.dm
@@ -373,3 +373,17 @@
max_w_class = ITEMSIZE_NORMAL
w_class = ITEMSIZE_SMALL
can_hold = list(/obj/item/weapon/reagent_containers/food/snacks,/obj/item/weapon/reagent_containers/food/condiment)
+
+ // -----------------------------
+ // Evidence Bag
+ // -----------------------------
+/obj/item/weapon/storage/bag/detective
+ name = "secure satchel"
+ icon = 'icons/obj/storage.dmi'
+ icon_state = "detbag"
+ desc = "A bag for storing investigation things. You know, securely."
+ max_storage_space = ITEMSIZE_COST_NORMAL * 15
+ max_w_class = ITEMSIZE_NORMAL
+ w_class = ITEMSIZE_SMALL
+ can_hold = list(/obj/item/weapon/forensics/swab,/obj/item/weapon/sample/print,/obj/item/weapon/sample/fibers,/obj/item/weapon/evidencebag)
+
diff --git a/code/game/objects/items/weapons/storage/bags_vr.dm b/code/game/objects/items/weapons/storage/bags_vr.dm
new file mode 100644
index 00000000000..6f9d0a0b151
--- /dev/null
+++ b/code/game/objects/items/weapons/storage/bags_vr.dm
@@ -0,0 +1,2 @@
+/obj/item/weapon/storage/bag/chemistry
+ slot_flags = null
diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm
index f9a7d1e6083..ddb8c489f6a 100644
--- a/code/game/objects/items/weapons/storage/belt.dm
+++ b/code/game/objects/items/weapons/storage/belt.dm
@@ -435,3 +435,8 @@
icon_state = "fannypack_yellow"
item_state = "fannypack_yellow"
+/obj/item/weapon/storage/belt/ranger
+ name = "ranger belt"
+ desc = "The fancy utility-belt holding the tools, cuffs and gadgets of the Go Go ERT-Rangers. The belt buckle is not real phoron, but it is still surprisingly comfortable to wear."
+ icon = 'icons/obj/clothing/ranger.dmi'
+ icon_state = "ranger_belt"
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm
index cdf5f347d2e..4e031f42808 100644
--- a/code/game/objects/items/weapons/storage/boxes.dm
+++ b/code/game/objects/items/weapons/storage/boxes.dm
@@ -326,6 +326,13 @@
icon_state = "donk_kit"
starts_with = list(/obj/item/weapon/reagent_containers/food/snacks/donkpocket/sinpocket = 7)
+/obj/item/weapon/storage/box/buns
+ name = "box of bread buns"
+ desc = "Freshly baked at some point in the past few months."
+ icon_state = "bun_box"
+ max_storage_space = ITEMSIZE_COST_NORMAL * 5
+ starts_with = list(/obj/item/weapon/reagent_containers/food/snacks/bun = 12)
+
/obj/item/weapon/storage/box/monkeycubes
name = "monkey cube box"
desc = "Drymate brand monkey cubes. Just add water!"
@@ -346,7 +353,7 @@
/obj/item/weapon/storage/box/monkeycubes/neaeracubes
name = "neaera cube box"
- desc = "Drymate brand neaera cubes, shipped from Jargon 4. Just add water!"
+ desc = "Drymate brand neaera cubes, shipped from Qerr'balak. Just add water!"
starts_with = list(/obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped/neaeracube = 4)
/obj/item/weapon/storage/box/ids
@@ -401,7 +408,7 @@
W.lit = 1
W.damtype = "burn"
W.icon_state = "match_lit"
- START_PROCESSING(SSobj, W)
+ START_PROCESSING(SSobj, W)
W.update_icon()
return
diff --git a/code/game/objects/items/weapons/storage/boxes_vr.dm b/code/game/objects/items/weapons/storage/boxes_vr.dm
index f2cbd06aed1..8feee76bdda 100644
--- a/code/game/objects/items/weapons/storage/boxes_vr.dm
+++ b/code/game/objects/items/weapons/storage/boxes_vr.dm
@@ -33,7 +33,7 @@
starts_with = list(/obj/item/device/encryptionkey/headset_com = 7)
/obj/item/weapon/storage/box/servicekeys
- name = "box of command keys"
+ name = "box of service keys"
desc = "A box full of service keys, for the HoP to give out as necessary."
starts_with = list(/obj/item/device/encryptionkey/headset_service = 7)
diff --git a/code/game/objects/items/weapons/teleportation.dm b/code/game/objects/items/weapons/teleportation.dm
index 137eadb60dd..ba5ca0a9a21 100644
--- a/code/game/objects/items/weapons/teleportation.dm
+++ b/code/game/objects/items/weapons/teleportation.dm
@@ -76,7 +76,7 @@ Frequency:
direct = "very weak"
src.temp += "[W.code]-[dir2text(get_dir(sr, tr))]-[direct]
"
- src.temp += "Extranneous Signals:
"
+ src.temp += "Extraneous Signals:
"
for (var/obj/item/weapon/implant/tracking/W in all_tracking_implants)
if (!W.implanted || !(istype(W.loc,/obj/item/organ/external) || ismob(W.loc) || W.malfunction))
continue
diff --git a/code/game/objects/items/weapons/traps.dm b/code/game/objects/items/weapons/traps.dm
index 1e63201f4e1..1febf6b1ae3 100644
--- a/code/game/objects/items/weapons/traps.dm
+++ b/code/game/objects/items/weapons/traps.dm
@@ -106,6 +106,12 @@
can_buckle = initial(can_buckle)
/obj/item/weapon/beartrap/Crossed(AM as mob|obj)
+ //VOREStation Edit begin: SHADEKIN
+ var/mob/SK = AM
+ if(istype(SK))
+ if(SK.shadekin_phasing_check())
+ return
+ //VOREStation Edit end: SHADEKIN
if(deployed && isliving(AM))
var/mob/living/L = AM
if(L.m_intent == "run")
diff --git a/code/game/objects/structures/catwalk.dm b/code/game/objects/structures/catwalk.dm
index 20fd025ea96..5c606422d7f 100644
--- a/code/game/objects/structures/catwalk.dm
+++ b/code/game/objects/structures/catwalk.dm
@@ -87,6 +87,12 @@
return ..()
/obj/structure/catwalk/Crossed()
+ //VOREStation Edit begin: SHADEKIN
+ var/mob/SK = usr
+ if(istype(SK))
+ if(SK.shadekin_phasing_check())
+ return
+ //VOREStation Edit end: SHADEKIN
. = ..()
if(isliving(usr))
playsound(src, pick('sound/effects/footstep/catwalk1.ogg', 'sound/effects/footstep/catwalk2.ogg', 'sound/effects/footstep/catwalk3.ogg', 'sound/effects/footstep/catwalk4.ogg', 'sound/effects/footstep/catwalk5.ogg'), 25, 1)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm
index 1117a0f8cc0..f6ca40fe2b0 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm
@@ -14,7 +14,7 @@
/obj/structure/closet/secure_closet/freezer/kitchen
name = "kitchen cabinet"
- req_access = list(access_kitchen)
+ req_access = list()
starts_with = list(
/obj/item/weapon/reagent_containers/food/condiment/flour = 7,
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm
index 454fab779d3..d5f5da1c401 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm
@@ -4,14 +4,18 @@
req_access = list(access_all_personal_lockers)
var/registered_name = null
+ /* //VOREStation Removal
starts_with = list(
/obj/item/device/radio/headset)
+ */
/obj/structure/closet/secure_closet/personal/Initialize()
+ /* //VOREStation Removal
if(prob(50))
starts_with += /obj/item/weapon/storage/backpack
else
starts_with += /obj/item/weapon/storage/backpack/satchel/norm
+ */
return ..()
/obj/structure/closet/secure_closet/personal/patient
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
index 350e9dc5144..b4162c6ac80 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
@@ -113,7 +113,7 @@
/obj/item/weapon/storage/belt/security,
/obj/item/device/flash,
/obj/item/weapon/melee/baton/loaded,
- /obj/item/weapon/gun/energy/gun,
+ /obj/item/weapon/gun/magnetic/railgun/heater/pistol/hos,
/obj/item/weapon/cell/device/weapon,
/obj/item/clothing/accessory/holster/waist,
/obj/item/weapon/melee/telebaton,
@@ -223,6 +223,8 @@
starts_with += /obj/item/weapon/storage/backpack/satchel/sec
if(prob(50))
starts_with += /obj/item/weapon/storage/backpack/dufflebag/sec
+ if(prob(30))
+ starts_with += /obj/item/weapon/contraband/poster/nanotrasen
return ..()
/obj/structure/closet/secure_closet/security/cargo/Initialize()
@@ -271,6 +273,7 @@
/obj/item/weapon/reagent_containers/food/drinks/flask/detflask,
/obj/item/weapon/storage/briefcase/crimekit,
/obj/item/device/taperecorder,
+ /obj/item/weapon/storage/bag/detective,
/obj/item/device/tape/random = 3)
/obj/structure/closet/secure_closet/detective/update_icon()
@@ -305,6 +308,17 @@ GLOBAL_LIST_BOILERPLATE(all_brig_closets, /obj/structure/closet/secure_closet/br
/obj/item/clothing/under/color/prison,
/obj/item/clothing/shoes/orange)
+/obj/structure/closet/secure_closet/posters
+ name = "morale storage"
+ req_access = list(access_security)
+ anchored = 1
+
+ starts_with = list(
+ /obj/item/weapon/contraband/poster/nanotrasen,
+ /obj/item/weapon/contraband/poster/nanotrasen,
+ /obj/item/weapon/contraband/poster/nanotrasen,
+ /obj/item/weapon/contraband/poster/nanotrasen,
+ /obj/item/weapon/contraband/poster/nanotrasen)
/obj/structure/closet/secure_closet/courtroom
name = "courtroom locker"
diff --git a/code/game/objects/structures/ghost_pods/ghost_pods.dm b/code/game/objects/structures/ghost_pods/ghost_pods.dm
index 811fc47736c..970b1d2ffff 100644
--- a/code/game/objects/structures/ghost_pods/ghost_pods.dm
+++ b/code/game/objects/structures/ghost_pods/ghost_pods.dm
@@ -83,4 +83,13 @@
to_chat(user, "Another spirit appears to have gotten to \the [src] before you. Sorry.")
return
- create_occupant(user)
\ No newline at end of file
+ var/choice = input(user, "Are you certain you wish to activate this pod?", "Control Pod") as null|anything in list("Yes", "No")
+
+ if(!choice || choice == "No")
+ return
+
+ else if(used)
+ to_chat(user, "Another spirit appears to have gotten to \the [src] before you. Sorry.")
+ return
+
+ create_occupant(user)
diff --git a/code/game/objects/structures/ghost_pods/human.dm b/code/game/objects/structures/ghost_pods/human.dm
new file mode 100644
index 00000000000..2eda9b6c370
--- /dev/null
+++ b/code/game/objects/structures/ghost_pods/human.dm
@@ -0,0 +1,246 @@
+// Ghost variant.
+
+/obj/structure/ghost_pod/ghost_activated/human
+ name = "mysterious cryopod"
+ desc = "This is a pod which appears to contain a body."
+ description_info = "This contains a body, which may wake at any time. The external controls\
+ seem to be malfunctioning."
+ icon = 'icons/obj/Cryogenic2.dmi'
+ icon_state = "sleeper_1"
+ icon_state_opened = "sleeper_0"
+ density = TRUE
+ ghost_query_type = /datum/ghost_query/stowaway
+ anchored = FALSE
+
+ var/occupant_type = "stowaway"
+
+ var/allow_appearance_change = TRUE
+
+ var/make_antag = MODE_STOWAWAY
+
+ var/start_injured = FALSE
+ var/spawn_with_emag = TRUE
+
+ var/list/clothing_possibilities
+
+/obj/structure/ghost_pod/ghost_activated/human/Initialize()
+ ..()
+
+ handle_clothing_setup()
+
+/obj/structure/ghost_pod/ghost_activated/human/proc/handle_clothing_setup()
+ clothing_possibilities = list()
+
+ clothing_possibilities |= subtypesof(/obj/item/clothing/under/color)
+ clothing_possibilities |= subtypesof(/obj/item/clothing/head/soft)
+ clothing_possibilities |= /obj/item/clothing/shoes/black
+ clothing_possibilities |= /obj/item/device/radio/headset
+
+/obj/structure/ghost_pod/ghost_activated/human/create_occupant(var/mob/M)
+ ..()
+ var/turf/T = get_turf(src)
+ var/mob/living/carbon/human/H = new(src)
+
+ H.adjustCloneLoss(rand(1,5))
+ if(M.mind)
+ M.mind.transfer_to(H)
+ to_chat(M, "You are a [occupant_type]!")
+ if(make_antag)
+ to_chat(M, "Your intent may not be completely beneficial.")
+ H.ckey = M.ckey
+ visible_message("As \the [src] opens, the pipes on \the [src] surge, before it grows dark.")
+ log_and_message_admins("successfully opened \a [src] and became a [occupant_type].")
+
+ var/list/uniform_options
+ var/list/shoe_options
+ var/list/head_options
+ var/list/headset_options
+
+ if(clothing_possibilities && clothing_possibilities.len)
+ for(var/path in clothing_possibilities)
+ if(ispath(path, /obj/item/clothing/under))
+ if(!uniform_options)
+ uniform_options = list()
+ uniform_options |= path
+ if(ispath(path, /obj/item/clothing/shoes))
+ if(!shoe_options)
+ shoe_options = list()
+ shoe_options |= path
+ if(ispath(path, /obj/item/clothing/head))
+ if(!head_options)
+ head_options = list()
+ head_options |= path
+ if(ispath(path, /obj/item/device/radio/headset))
+ if(!headset_options)
+ headset_options = list()
+ headset_options |= path
+
+ if(uniform_options && uniform_options.len)
+ var/newpath = pick(uniform_options)
+ var/obj/item/clothing/C = new newpath(H)
+ H.equip_to_appropriate_slot(C)
+
+ if(shoe_options && shoe_options.len)
+ var/newpath = pick(shoe_options)
+ var/obj/item/clothing/C = new newpath(H)
+ H.equip_to_appropriate_slot(C)
+
+ if(head_options && head_options.len)
+ var/newpath = pick(head_options)
+ var/obj/item/clothing/C = new newpath(H)
+ H.equip_to_appropriate_slot(C)
+
+ if(headset_options && headset_options.len)
+ var/newpath = pick(headset_options)
+ var/obj/item/C = new newpath(H)
+ H.equip_to_appropriate_slot(C)
+
+ if(spawn_with_emag)
+ var/obj/item/weapon/card/emag/E = new(H)
+ E.name = "broken card"
+ E.description_antag = "This is a 'disguised' emag, to make your escape from wherever you happen to be trapped."
+ H.equip_to_appropriate_slot(E)
+
+ var/newname = sanitize(input(H, "Your mind feels foggy, and you recall your name might be [H.real_name]. Would you like to change your name?", "Name change") as null|text, MAX_NAME_LEN)
+ if (newname)
+ H.real_name = newname
+
+ icon_state = icon_state_opened
+
+ H.forceMove(T)
+
+ if(make_antag)
+ var/datum/antagonist/antag = all_antag_types[make_antag]
+ if(antag)
+ if(antag.add_antagonist(H.mind, 1, 1, 0, 1, 1))
+ log_admin("\The [src] made [key_name(src)] into a [antag.role_text].")
+
+ if(start_injured) // Done 3 different times to disperse damage.
+ H.adjustBruteLoss(rand(1,20))
+ H.adjustBruteLoss(rand(1,20))
+ H.adjustBruteLoss(rand(1,20))
+
+ if(allow_appearance_change)
+ H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = 1)
+
+ visible_message("\The [src] [pick("gurgles", "seizes", "clangs")] before releasing \the [H]!")
+
+// Manual Variant
+// This one lacks the emag option due to the fact someone has to activate it, and they will probably help the person.
+/obj/structure/ghost_pod/manual/human
+ name = "mysterious cryopod"
+ desc = "This is a pod which appears to contain a body."
+ description_info = "This contains a body, which may wake at any time. The external controls\
+ seem to be functioning, though the warning lights that flash give no solace.."
+ icon = 'icons/obj/Cryogenic2.dmi'
+ icon_state = "sleeper_1"
+ icon_state_opened = "sleeper_0"
+ density = TRUE
+ ghost_query_type = /datum/ghost_query/lost_passenger
+ anchored = FALSE
+
+ var/occupant_type = "lost passenger"
+
+ var/allow_appearance_change = TRUE
+
+ var/make_antag = MODE_STOWAWAY
+
+ var/start_injured = TRUE
+
+ var/list/clothing_possibilities
+
+/obj/structure/ghost_pod/manual/human/Initialize()
+ ..()
+
+ handle_clothing_setup()
+
+/obj/structure/ghost_pod/manual/human/proc/handle_clothing_setup()
+ clothing_possibilities = list()
+
+ clothing_possibilities |= subtypesof(/obj/item/clothing/under/utility)
+ clothing_possibilities |= subtypesof(/obj/item/clothing/head/beret)
+ clothing_possibilities |= /obj/item/clothing/shoes/black
+ clothing_possibilities |= /obj/item/device/radio/headset
+
+/obj/structure/ghost_pod/manual/human/create_occupant(var/mob/M)
+ ..()
+ var/turf/T = get_turf(src)
+ var/mob/living/carbon/human/H = new(src)
+
+ H.adjustCloneLoss(rand(1,5))
+ if(M.mind)
+ M.mind.transfer_to(H)
+ to_chat(M, "You are a [occupant_type]!")
+ if(make_antag)
+ to_chat(M, "Your intent may not be completely beneficial.")
+ H.ckey = M.ckey
+ visible_message("As \the [src] opens, the pipes on \the [src] surge, before it grows dark.")
+ log_and_message_admins("successfully opened \a [src] and got a [occupant_type].")
+
+ var/list/uniform_options
+ var/list/shoe_options
+ var/list/head_options
+ var/list/headset_options
+
+ if(clothing_possibilities && clothing_possibilities.len)
+ for(var/path in clothing_possibilities)
+ if(ispath(path, /obj/item/clothing/under))
+ if(!uniform_options)
+ uniform_options = list()
+ uniform_options |= path
+ if(ispath(path, /obj/item/clothing/shoes))
+ if(!shoe_options)
+ shoe_options = list()
+ shoe_options |= path
+ if(ispath(path, /obj/item/clothing/head))
+ if(!head_options)
+ head_options = list()
+ head_options |= path
+ if(ispath(path, /obj/item/device/radio/headset))
+ if(!headset_options)
+ headset_options = list()
+ headset_options |= path
+
+ if(uniform_options && uniform_options.len)
+ var/newpath = pick(uniform_options)
+ var/obj/item/clothing/C = new newpath(H)
+ H.equip_to_appropriate_slot(C)
+
+ if(shoe_options && shoe_options.len)
+ var/newpath = pick(shoe_options)
+ var/obj/item/clothing/C = new newpath(H)
+ H.equip_to_appropriate_slot(C)
+
+ if(head_options && head_options.len)
+ var/newpath = pick(head_options)
+ var/obj/item/clothing/C = new newpath(H)
+ H.equip_to_appropriate_slot(C)
+
+ if(headset_options && headset_options.len)
+ var/newpath = pick(headset_options)
+ var/obj/item/C = new newpath(H)
+ H.equip_to_appropriate_slot(C)
+
+ var/newname = sanitize(input(H, "Your mind feels foggy, and you recall your name might be [H.real_name]. Would you like to change your name?", "Name change") as null|text, MAX_NAME_LEN)
+ if (newname)
+ H.real_name = newname
+
+ icon_state = icon_state_opened
+
+ H.forceMove(T)
+
+ if(make_antag)
+ var/datum/antagonist/antag = all_antag_types[make_antag]
+ if(antag)
+ if(antag.add_antagonist(H.mind, 1, 1, 0, 1, 1))
+ log_admin("\The [src] made [key_name(src)] into a [antag.role_text].")
+
+ if(start_injured) // Done 3 different times to disperse damage.
+ H.adjustBruteLoss(rand(1,20))
+ H.adjustBruteLoss(rand(1,20))
+ H.adjustBruteLoss(rand(1,20))
+
+ if(allow_appearance_change)
+ H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = 1)
+
+ visible_message("\The [src] [pick("gurgles", "seizes", "clangs")] before releasing \the [H]!")
diff --git a/code/game/objects/structures/ghost_pods/silicon.dm b/code/game/objects/structures/ghost_pods/silicon.dm
index 8fd3fcea7c2..32a26ce479d 100644
--- a/code/game/objects/structures/ghost_pods/silicon.dm
+++ b/code/game/objects/structures/ghost_pods/silicon.dm
@@ -58,4 +58,50 @@
R.ckey = M.ckey
visible_message("As \the [src] opens, the eyes of the robot flicker as it is activated.")
R.Namepick()
- ..()
\ No newline at end of file
+ ..()
+
+/obj/structure/ghost_pod/ghost_activated/swarm_drone
+ name = "drone shell"
+ desc = "A heavy metallic ball."
+ icon = 'icons/mob/swarmbot.dmi'
+ icon_state = "swarmer_unactivated"
+ density = FALSE
+ anchored = FALSE
+
+ var/drone_class = "general"
+ var/drone_type = /mob/living/silicon/robot/drone/swarm
+
+/obj/structure/ghost_pod/ghost_activated/swarm_drone/create_occupant(var/mob/M)
+ var/mob/living/silicon/robot/drone/swarm/R = new drone_type(get_turf(src))
+ if(M.mind)
+ M.mind.transfer_to(R)
+ to_chat(M, "You are [R], the remnant of some distant species, mechanical or flesh, living or dead.")
+ R.ckey = M.ckey
+ visible_message("As \the [src] shudders, it glows before lifting itself with three shimmering limbs!")
+ spawn(3 SECONDS)
+ to_chat(R,"Many of your tools are standard drone devices, however others provide you with particular benefits.")
+ to_chat(R,"Unlike standard drones, you are capable of utilizing 'zero point wells', found in your 'spells' tab.")
+ to_chat(R,"Here you will also find your replication ability(s), depending on the type of drone you are.")
+ to_chat(R,"Gunners have a special anti-personnel gun capable of shocking or punching through armor with low damage.")
+ to_chat(R,"Impalers have an energy-lance.")
+ to_chat(R,"General drones have the unique ability to produce one of each of these two types of shells per generation.")
+ if(!QDELETED(src))
+ qdel(src)
+
+/obj/structure/ghost_pod/ghost_activated/swarm_drone/event/Initialize()
+ ..()
+
+ var/turf/T = get_turf(src)
+ say_dead_object("A [drone_class] swarm drone shell is now available in \the [T.loc].", src)
+
+/obj/structure/ghost_pod/ghost_activated/swarm_drone/event/gunner
+ name = "gunner shell"
+
+ drone_class = "gunner"
+ drone_type = /mob/living/silicon/robot/drone/swarm/gunner
+
+/obj/structure/ghost_pod/ghost_activated/swarm_drone/event/melee
+ name = "impaler shell"
+
+ drone_class = "impaler"
+ drone_type = /mob/living/silicon/robot/drone/swarm/melee
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index 26487233852..aab0ecf7f01 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -62,7 +62,7 @@
/obj/structure/girder/update_icon()
if(anchored)
- icon_state = "girder"
+ icon_state = initial(icon_state)
else
icon_state = "displaced"
@@ -320,6 +320,7 @@
name = "column"
icon= 'icons/obj/cult.dmi'
icon_state= "cultgirder"
+ max_health = 250
health = 250
cover = 70
girder_material = "cult"
@@ -354,6 +355,13 @@
new /obj/effect/decal/remains/human(get_turf(src))
dismantle()
+/obj/structure/girder/resin
+ name = "soft girder"
+ icon_state = "girder_resin"
+ max_health = 225
+ health = 225
+ cover = 60
+ girder_material = "resin"
/obj/structure/girder/rcd_values(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
var/turf/simulated/T = get_turf(src)
diff --git a/code/game/objects/structures/loot_piles.dm b/code/game/objects/structures/loot_piles.dm
index f74770664bb..e3607fdeea6 100644
--- a/code/game/objects/structures/loot_piles.dm
+++ b/code/game/objects/structures/loot_piles.dm
@@ -680,7 +680,7 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh
)
uncommon_loot = list(
- /obj/item/mecha_parts/mecha_equipment/tool/safety_clamp,
+ /obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp/safety,
/obj/item/mecha_parts/mecha_equipment/weapon/energy/riggedlaser,
/obj/item/mecha_parts/mecha_equipment/repair_droid,
/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay
diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm
index 3011d2c61df..07cc774fb06 100644
--- a/code/game/objects/structures/mirror.dm
+++ b/code/game/objects/structures/mirror.dm
@@ -134,7 +134,7 @@
spawn(1)
var/newname = sanitizeSafe(input(vox,"Enter a name, or leave blank for the default name.", "Name change","") as text, MAX_NAME_LEN)
if(!newname || newname == "")
- var/datum/language/L = all_languages[vox.species.default_language]
+ var/datum/language/L = GLOB.all_languages[vox.species.default_language]
newname = L.get_random_name()
vox.real_name = newname
vox.name = vox.real_name
diff --git a/code/game/objects/structures/musician.dm b/code/game/objects/structures/musician.dm
index ff1826116a6..39eea11236f 100644
--- a/code/game/objects/structures/musician.dm
+++ b/code/game/objects/structures/musician.dm
@@ -103,12 +103,12 @@
if(!playing || shouldStopPlaying(user))//If the instrument is playing, or special case
playing = 0
return
- if(lentext(note) == 0)
+ if(length(note) == 0)
continue
var/cur_note = text2ascii(note) - 96
if(cur_note < 1 || cur_note > 7)
continue
- for(var/i=2 to lentext(note))
+ for(var/i=2 to length(note))
var/ni = copytext(note,i,i+1)
if(!text2num(ni))
if(ni == "#" || ni == "b" || ni == "n")
@@ -196,11 +196,11 @@
t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", name), t) as message)
if(!in_range(instrumentObj, usr))
return
- if(lentext(t) >= INSTRUMENT_MAX_LINE_LENGTH*INSTRUMENT_MAX_LINE_NUMBER)
+ if(length(t) >= INSTRUMENT_MAX_LINE_LENGTH*INSTRUMENT_MAX_LINE_NUMBER)
var/cont = input(usr, "Your message is too long! Would you like to continue editing it?", "", "yes") in list("yes", "no")
if(cont == "no")
break
- while(lentext(t) > INSTRUMENT_MAX_LINE_LENGTH*INSTRUMENT_MAX_LINE_NUMBER)
+ while(length(t) > INSTRUMENT_MAX_LINE_LENGTH*INSTRUMENT_MAX_LINE_NUMBER)
//split into lines
spawn()
lines = splittext(t, "\n")
@@ -214,7 +214,7 @@
lines.Cut(INSTRUMENT_MAX_LINE_NUMBER+1)
var/linenum = 1
for(var/l in lines)
- if(lentext(l) > INSTRUMENT_MAX_LINE_LENGTH)
+ if(length(l) > INSTRUMENT_MAX_LINE_LENGTH)
to_chat(usr, "Line [linenum] too long!")
lines.Remove(l)
else
@@ -244,7 +244,7 @@
return
if(lines.len > INSTRUMENT_MAX_LINE_NUMBER)
return
- if(lentext(newline) > INSTRUMENT_MAX_LINE_LENGTH)
+ if(length(newline) > INSTRUMENT_MAX_LINE_LENGTH)
newline = copytext(newline, 1, INSTRUMENT_MAX_LINE_LENGTH)
lines.Add(newline)
else if(href_list["deleteline"])
@@ -257,7 +257,7 @@
var/content = html_encode(input("Enter your line: ", instrumentObj.name, lines[num]) as text|null)
if(!content || !in_range(instrumentObj, usr))
return
- if(lentext(content) > INSTRUMENT_MAX_LINE_LENGTH)
+ if(length(content) > INSTRUMENT_MAX_LINE_LENGTH)
content = copytext(content, 1, INSTRUMENT_MAX_LINE_LENGTH)
if(num > lines.len || num < 1)
return
diff --git a/code/game/objects/structures/props/swarm.dm b/code/game/objects/structures/props/swarm.dm
new file mode 100644
index 00000000000..8419f7086ab
--- /dev/null
+++ b/code/game/objects/structures/props/swarm.dm
@@ -0,0 +1,150 @@
+/obj/structure/cult/pylon/swarm
+ name = "Swarm Construct"
+ desc = "A small pod."
+ icon = 'icons/mob/swarmbot.dmi'
+ icon_state = "pod"
+ light_color = "#00B2B2"
+
+ shatter_message = "The energetic field shatters!"
+ impact_sound = 'sound/effects/Glasshit.ogg'
+ shatter_sound = 'sound/effects/phasein.ogg'
+
+ var/list/active_beams
+
+/obj/structure/cult/pylon/swarm/CanPass(atom/movable/mover, turf/target)
+ if(istype(mover, /mob/living))
+ var/mob/living/L = mover
+ if(L.faction == "swarmer")
+ return TRUE
+ else if(istype(mover, /obj/item/projectile))
+ var/obj/item/projectile/P = mover
+ if(istype(P.firer) && P.firer.faction == "swarmer")
+ return TRUE
+ return ..()
+
+/obj/structure/cult/pylon/swarm/Initialize()
+ ..()
+ active_beams = list()
+
+/obj/structure/cult/pylon/swarm/Destroy()
+ for(var/datum/beam/B in active_beams)
+ QDEL_NULL(B)
+ active_beams = null
+ ..()
+
+/obj/structure/cult/pylon/swarm/pylonhit(var/damage)
+ if(!isbroken)
+ if(prob(1 + damage * 3))
+ visible_message("[shatter_message]")
+ STOP_PROCESSING(SSobj, src)
+ playsound(get_turf(src),shatter_sound, 75, 1)
+ isbroken = 1
+ density = 0
+ icon_state = "[initial(icon_state)]-broken"
+ set_light(0)
+
+/obj/structure/cult/pylon/swarm/attackpylon(mob/user as mob, var/damage)
+ if(!isbroken)
+ if(prob(1 + damage * 3))
+ user.visible_message(
+ "[user] smashed \the [src]!",
+ "You hit \the [src], and its crystal breaks apart!",
+ "You hear a tinkle of crystalline shards."
+ )
+ STOP_PROCESSING(SSobj, src)
+ user.do_attack_animation(src)
+ playsound(get_turf(src),shatter_sound, 75, 1)
+ isbroken = 1
+ density = 0
+ icon_state = "[initial(icon_state)]-broken"
+ set_light(0)
+ else
+ to_chat(user, "You hit \the [src]!")
+ playsound(get_turf(src),impact_sound, 75, 1)
+ else
+ if(prob(damage * 2))
+ to_chat(user, "You pulverize what was left of \the [src]!")
+ qdel(src)
+ else
+ to_chat(user, "You hit \the [src]!")
+ playsound(get_turf(src),impact_sound, 75, 1)
+
+/obj/structure/cult/pylon/swarm/pylon_unique()
+ . = ..()
+
+ return .
+
+/obj/structure/cult/pylon/swarm/zp_well
+ name = "Zero Point Well"
+ desc = "Infinite cosmic power, itty bitty usability."
+
+ icon_state = "trap"
+
+ description_info = "An infinitely small point in space that may or may not be used to supply power to some form of advanced machine."
+
+ activation_cooldown = 0 // These things run constantly.
+
+/obj/structure/cult/pylon/swarm/zp_well/pylon_unique()
+ . = ..()
+
+ for(var/mob/living/silicon/robot/drone/swarm/S in view(3, src))
+ var/has_beam = FALSE
+ for(var/datum/beam/B in active_beams)
+ if(B.target == S)
+ has_beam = TRUE
+ break
+
+ if(!has_beam)
+ active_beams |= Beam(S,icon='icons/effects/beam.dmi',icon_state="holo_beam",time=3 SECONDS,maxdistance=3,beam_type = /obj/effect/ebeam,beam_sleep_time=2)
+
+ if(S.cell)
+ S.cell.give(rand(5, 30))
+
+ . = TRUE
+
+ return .
+
+/obj/structure/cult/pylon/swarm/defender
+ name = "Zero Point Wall"
+ desc = "Infinite cosmic power, itty bitty passability."
+
+ icon_state = "barricade"
+
+ description_info = "An infinitely small point in space spread upon infinitely many finitely-bounded points in space. Nice."
+
+/obj/structure/cult/pylon/swarm/defender/pylonhit(var/damage)
+ if(!isbroken)
+ if(prob(1 + damage * 3) && round(damage * 0.8) >= 30)
+ visible_message("[shatter_message]")
+ STOP_PROCESSING(SSobj, src)
+ playsound(get_turf(src),shatter_sound, 75, 1)
+ isbroken = 1
+ density = 0
+ icon_state = "[initial(icon_state)]-broken"
+ set_light(0)
+
+/obj/structure/cult/pylon/swarm/defender/attackpylon(mob/user as mob, var/damage)
+ if(!isbroken)
+ if(prob(1 + damage * 3) && round(damage * 0.8) >= 25)
+ user.visible_message(
+ "[user] smashed \the [src]!",
+ "You hit \the [src], and its crystal breaks apart!",
+ "You hear a tinkle of crystalline shards."
+ )
+ STOP_PROCESSING(SSobj, src)
+ user.do_attack_animation(src)
+ playsound(get_turf(src),shatter_sound, 75, 1)
+ isbroken = 1
+ density = 0
+ icon_state = "[initial(icon_state)]-broken"
+ set_light(0)
+ else
+ to_chat(user, "You hit \the [src]!")
+ playsound(get_turf(src),impact_sound, 75, 1)
+ else
+ if(prob(damage * 2))
+ to_chat(user, "You pulverize what was left of \the [src]!")
+ qdel(src)
+ else
+ to_chat(user, "You hit \the [src]!")
+ playsound(get_turf(src),impact_sound, 75, 1)
diff --git a/code/game/turfs/simulated/wall_attacks.dm b/code/game/turfs/simulated/wall_attacks.dm
index 8599def4a55..676ad392f09 100644
--- a/code/game/turfs/simulated/wall_attacks.dm
+++ b/code/game/turfs/simulated/wall_attacks.dm
@@ -93,8 +93,9 @@
if(..()) return 1
if(!can_open)
- to_chat(user, "You push the wall, but nothing happens.")
- playsound(src, 'sound/weapons/Genhit.ogg', 25, 1)
+ if(!material.wall_touch_special(src, user))
+ to_chat(user, "You push the wall, but nothing happens.")
+ playsound(src, 'sound/weapons/Genhit.ogg', 25, 1)
else
toggle_open(user)
return 0
diff --git a/code/game/turfs/simulated/wall_types.dm b/code/game/turfs/simulated/wall_types.dm
index 37bf0d75417..bff82d6e0e3 100644
--- a/code/game/turfs/simulated/wall_types.dm
+++ b/code/game/turfs/simulated/wall_types.dm
@@ -59,6 +59,9 @@
/turf/simulated/wall/snowbrick/New(var/newloc)
..(newloc,"packed snow")
+/turf/simulated/wall/resin/New(var/newloc)
+ ..(newloc,"resin",null,"resin")
+
// Kind of wondering if this is going to bite me in the butt.
/turf/simulated/wall/skipjack/New(var/newloc)
..(newloc,"alienalloy")
diff --git a/code/game/verbs/ooc.dm b/code/game/verbs/ooc.dm
index 0c6fa0fed7f..b75de6685e6 100644
--- a/code/game/verbs/ooc.dm
+++ b/code/game/verbs/ooc.dm
@@ -9,28 +9,28 @@
if(!mob) return
if(IsGuestKey(key))
- src << "Guests may not use OOC."
+ to_chat(src, "Guests may not use OOC.")
return
msg = sanitize(msg)
if(!msg) return
if(!is_preference_enabled(/datum/client_preference/show_ooc))
- src << "You have OOC muted."
+ to_chat(src, "You have OOC muted.")
return
if(!holder)
if(!config.ooc_allowed)
- src << "OOC is globally muted."
+ to_chat(src, "OOC is globally muted.")
return
if(!config.dooc_allowed && (mob.stat == DEAD))
usr << "OOC for dead mobs has been turned off."
return
if(prefs.muted & MUTE_OOC)
- src << "You cannot use OOC (muted)."
+ to_chat(src, "You cannot use OOC (muted).")
return
if(findtext(msg, "byond://"))
- src << "Advertising other servers is not allowed."
+ to_chat(src, "Advertising other servers is not allowed.")
log_admin("[key_name(src)] has attempted to advertise in OOC: [msg]")
message_admins("[key_name_admin(src)] has attempted to advertise in OOC: [msg]")
return
@@ -86,7 +86,7 @@
return
if(IsGuestKey(key))
- src << "Guests may not use OOC."
+ to_chat(src, "Guests may not use OOC.")
return
msg = sanitize(msg)
@@ -94,21 +94,21 @@
return
if(!is_preference_enabled(/datum/client_preference/show_looc))
- src << "You have LOOC muted."
+ to_chat(src, "You have LOOC muted.")
return
if(!holder)
if(!config.looc_allowed)
- src << "LOOC is globally muted."
+ to_chat(src, "LOOC is globally muted.")
return
if(!config.dooc_allowed && (mob.stat == DEAD))
usr << "OOC for dead mobs has been turned off."
return
if(prefs.muted & MUTE_OOC)
- src << "You cannot use OOC (muted)."
+ to_chat(src, "You cannot use OOC (muted).")
return
if(findtext(msg, "byond://"))
- src << "Advertising other servers is not allowed."
+ to_chat(src, "Advertising other servers is not allowed.")
log_admin("[key_name(src)] has attempted to advertise in OOC: [msg]")
message_admins("[key_name_admin(src)] has attempted to advertise in OOC: [msg]")
return
diff --git a/code/game/verbs/suicide.dm b/code/game/verbs/suicide.dm
index 4a40ea97cb1..5a6bfefdb47 100644
--- a/code/game/verbs/suicide.dm
+++ b/code/game/verbs/suicide.dm
@@ -4,27 +4,27 @@
set hidden = 1
if (stat == DEAD)
- src << "You're already dead!"
+ to_chat(src, "You're already dead!")
return
if (!ticker)
- src << "You can't commit suicide before the game starts!"
+ to_chat(src, "You can't commit suicide before the game starts!")
return
if(!player_is_antag(mind))
message_admins("[ckey] has tried to suicide, but they were not permitted due to not being antagonist as human.", 1)
- src << "No. Adminhelp if there is a legitimate reason."
+ to_chat(src, "No. Adminhelp if there is a legitimate reason.")
return
if (suiciding)
- src << "You're already committing suicide! Be patient!"
+ to_chat(src, "You're already committing suicide! Be patient!")
return
var/confirm = alert("Are you sure you want to commit suicide?", "Confirm Suicide", "Yes", "No")
if(confirm == "Yes")
if(!canmove || restrained()) //just while I finish up the new 'fun' suiciding verb. This is to prevent metagaming via suicide
- src << "You can't commit suicide whilst restrained! ((You can type Ghost instead however.))"
+ to_chat(src, "You can't commit suicide whilst restrained! ((You can type Ghost instead however.))")
return
suiciding = 15
does_not_breathe = 0 //Prevents ling-suicide zombies, or something
@@ -92,15 +92,15 @@
set hidden = 1
if (stat == 2)
- src << "You're already dead!"
+ to_chat(src, "You're already dead!")
return
if (!ticker)
- src << "You can't commit suicide before the game starts!"
+ to_chat(src, "You can't commit suicide before the game starts!")
return
if (suiciding)
- src << "You're already committing suicide! Be patient!"
+ to_chat(src, "You're already committing suicide! Be patient!")
return
var/confirm = alert("Are you sure you want to commit suicide?", "Confirm Suicide", "Yes", "No")
@@ -116,11 +116,11 @@
set hidden = 1
if (stat == 2)
- src << "You're already dead!"
+ to_chat(src, "You're already dead!")
return
if (suiciding)
- src << "You're already committing suicide! Be patient!"
+ to_chat(src, "You're already committing suicide! Be patient!")
return
var/confirm = alert("Are you sure you want to commit suicide?", "Confirm Suicide", "Yes", "No")
@@ -136,11 +136,11 @@
set hidden = 1
if (stat == 2)
- src << "You're already dead!"
+ to_chat(src, "You're already dead!")
return
if (suiciding)
- src << "You're already committing suicide! Be patient!"
+ to_chat(src, "You're already committing suicide! Be patient!")
return
var/confirm = alert("Are you sure you want to commit suicide?", "Confirm Suicide", "Yes", "No")
@@ -165,4 +165,4 @@
M.show_message("[src] flashes a message across its screen, \"Wiping core files. Please acquire a new personality to continue using pAI device functions.\"", 3, "[src] bleeps electronically.", 2)
death(0)
else
- src << "Aborting suicide attempt."
+ to_chat(src, "Aborting suicide attempt.")
diff --git a/code/game/verbs/who.dm b/code/game/verbs/who.dm
index c030e25649f..a8100038a82 100644
--- a/code/game/verbs/who.dm
+++ b/code/game/verbs/who.dm
@@ -171,7 +171,7 @@
num_event_managers_online++
if(config.admin_irc)
- src << "Adminhelps are also sent to IRC. If no admins are available in game try anyway and an admin on IRC may see it and respond."
+ to_chat(src, "Adminhelps are also sent to IRC. If no admins are available in game try anyway and an admin on IRC may see it and respond.")
msg = "Current Admins ([num_admins_online]):\n" + msg
if(config.show_mods)
diff --git a/code/game/world.dm b/code/game/world.dm
index b611c884b0a..9e97aaf6106 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -57,8 +57,8 @@
populate_robolimb_list()
//Must be done now, otherwise ZAS zones and lighting overlays need to be recreated.
- createRandomZlevel()
-
+ //createRandomZlevel() //VOREStation Removal: Deprecated
+
processScheduler = new
master_controller = new /datum/controller/game_controller()
diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm
index d9e1efc9727..dd52884833f 100644
--- a/code/modules/admin/DB ban/functions.dm
+++ b/code/modules/admin/DB ban/functions.dm
@@ -377,13 +377,13 @@ datum/admins/proc/DB_ban_unban_by_id(var/id)
if(playercid)
cidsearch = "AND computerid = '[playercid]' "
else
- if(adminckey && lentext(adminckey) >= 3)
+ if(adminckey && length(adminckey) >= 3)
adminsearch = "AND a_ckey LIKE '[adminckey]%' "
- if(playerckey && lentext(playerckey) >= 3)
+ if(playerckey && length(playerckey) >= 3)
playersearch = "AND ckey LIKE '[playerckey]%' "
- if(playerip && lentext(playerip) >= 3)
+ if(playerip && length(playerip) >= 3)
ipsearch = "AND ip LIKE '[playerip]%' "
- if(playercid && lentext(playercid) >= 7)
+ if(playercid && length(playercid) >= 7)
cidsearch = "AND computerid LIKE '[playercid]%' "
if(dbbantype)
diff --git a/code/modules/admin/ToRban.dm b/code/modules/admin/ToRban.dm
index d127bfe6f41..f4ddd3e3f28 100644
--- a/code/modules/admin/ToRban.dm
+++ b/code/modules/admin/ToRban.dm
@@ -72,16 +72,16 @@
var/choice = input(src,"Please select an IP address to remove from the ToR banlist:","Remove ToR ban",null) as null|anything in F.dir
if(choice)
F.dir.Remove(choice)
- src << "Address removed"
+ to_chat(src, "Address removed")
if("remove all")
- src << "[TORFILE] was [fdel(TORFILE)?"":"not "]removed."
+ to_chat(src, "[TORFILE] was [fdel(TORFILE)?"":"not "]removed.")
if("find")
var/input = input(src,"Please input an IP address to search for:","Find ToR ban",null) as null|text
if(input)
if(ToRban_isbanned(input))
- src << "Address is a known ToR address"
+ to_chat(src, "Address is a known ToR address")
else
- src << "Address is not a known ToR address"
+ to_chat(src, "Address is not a known ToR address")
return
#undef TORFILE
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 8daa899692c..878671b0e20 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -192,8 +192,8 @@ proc/admin_notice(var/message, var/rights)
// language toggles
body += "
Languages:
"
var/f = 1
- for(var/k in all_languages)
- var/datum/language/L = all_languages[k]
+ for(var/k in GLOB.all_languages)
+ var/datum/language/L = GLOB.all_languages[k]
if(!(L.flags & INNATE))
if(!f) body += " | "
else f = 0
@@ -1305,7 +1305,7 @@ var/datum/announcement/minor/admin_min_announcer = new
set desc = "Should fix any mob sprite update errors."
if (!holder)
- src << "Only administrators may use this command."
+ to_chat(src, "Only administrators may use this command.")
return
if(istype(H))
diff --git a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm
index 1c90383f40a..12a84346b33 100644
--- a/code/modules/admin/admin_investigate.dm
+++ b/code/modules/admin/admin_investigate.dm
@@ -34,7 +34,7 @@
if("singulo", "telesci") //general one-round-only stuff
var/F = investigate_subject2file(subject)
if(!F)
- src << "Error: admin_investigate: [INVESTIGATE_DIR][subject] is an invalid path or cannot be accessed."
+ to_chat(src, "Error: admin_investigate: [INVESTIGATE_DIR][subject] is an invalid path or cannot be accessed.")
return
src << browse(F,"window=investigate[subject];size=800x300")
@@ -43,8 +43,8 @@
if(href_logfile)
src << browse(href_logfile,"window=investigate[subject];size=800x300")
else
- src << "Error: admin_investigate: No href logfile found."
+ to_chat(src, "Error: admin_investigate: No href logfile found.")
return
else
- src << "Error: admin_investigate: Href Logging is not on."
+ to_chat(src, "Error: admin_investigate: Href Logging is not on.")
return
diff --git a/code/modules/admin/admin_memo.dm b/code/modules/admin/admin_memo.dm
index 4bcaf10d9c7..24ecba7c011 100644
--- a/code/modules/admin/admin_memo.dm
+++ b/code/modules/admin/admin_memo.dm
@@ -22,7 +22,7 @@
return
if("")
F.dir.Remove(ckey)
- src << "Memo removed"
+ to_chat(src, "Memo removed")
return
if( findtext(memo,"