) to immediately create and call InvokeAsync
-
- PROC TYPEPATH SHORTCUTS (these operate on paths, not types, so to these shortcuts, datum is NOT a parent of atom, etc...)
-
- global proc while in another global proc:
- .procname
- Example:
- CALLBACK(GLOBAL_PROC, .some_proc_here)
-
- proc defined on current(src) object (when in a /proc/ and not an override) OR overridden at src or any of it's parents:
- .procname
- Example:
- CALLBACK(src, .some_proc_here)
-
-
- when the above doesn't apply:
- .proc/procname
- Example:
- CALLBACK(src, .proc/some_proc_here)
-
- proc defined on a parent of a some type:
- /some/type/.proc/some_proc_here
-
-
-
- Other wise you will have to do the full typepath of the proc (/type/of/thing/proc/procname)
-
-*/
-
+/**
+ *# Callback Datums
+ *A datum that holds a proc to be called on another object, used to track proccalls to other objects
+ *
+ * ## USAGE
+ *
+ * ```
+ * var/datum/callback/C = new(object|null, /proc/type/path|"procstring", arg1, arg2, ... argn)
+ * var/timerid = addtimer(C, time, timertype)
+ * you can also use the compiler define shorthand
+ * var/timerid = addtimer(CALLBACK(object|null, /proc/type/path|procstring, arg1, arg2, ... argn), time, timertype)
+ * ```
+ *
+ * Note: proc strings can only be given for datum proc calls, global procs must be proc paths
+ *
+ * Also proc strings are strongly advised against because they don't compile error if the proc stops existing
+ *
+ * In some cases you can provide a shortform of the procname, see the proc typepath shortcuts documentation below
+ *
+ * ## INVOKING THE CALLBACK
+ *`var/result = C.Invoke(args, to, add)` additional args are added after the ones given when the callback was created
+ *
+ * `var/result = C.InvokeAsync(args, to, add)` Asyncronous - returns . on the first sleep then continues on in the background
+ * after the sleep/block ends, otherwise operates normally.
+ *
+ * ## PROC TYPEPATH SHORTCUTS
+ * (these operate on paths, not types, so to these shortcuts, datum is NOT a parent of atom, etc...)
+ *
+ * ### global proc while in another global proc:
+ * .procname
+ *
+ * `CALLBACK(GLOBAL_PROC, .some_proc_here)`
+ *
+ * ### proc defined on current(src) object (when in a /proc/ and not an override) OR overridden at src or any of it's parents:
+ * .procname
+ *
+ * `CALLBACK(src, .some_proc_here)`
+ *
+ * ### when the above doesn't apply:
+ *.proc/procname
+ *
+ * `CALLBACK(src, .proc/some_proc_here)`
+ *
+ *
+ * proc defined on a parent of a some type
+ *
+ * `/some/type/.proc/some_proc_here`
+ *
+ * Otherwise you must always provide the full typepath of the proc (/type/of/thing/proc/procname)
+ */
/datum/callback
+
+ ///The object we will be calling the proc on
var/datum/object = GLOBAL_PROC
+ ///The proc we will be calling on the object
var/delegate
+ ///A list of arguments to pass into the proc
var/list/arguments
+ ///A weak reference to the user who triggered this callback
var/datum/weakref/user
+/**
+ * Create a new callback datum
+ *
+ * Arguments
+ * * thingtocall the object to call the proc on
+ * * proctocall the proc to call on the target object
+ * * ... an optional list of extra arguments to pass to the proc
+ */
/datum/callback/New(thingtocall, proctocall, ...)
if (thingtocall)
object = thingtocall
@@ -58,7 +75,14 @@
arguments = args.Copy(3)
if(usr)
user = WEAKREF(usr)
-
+/**
+ * Immediately Invoke proctocall on thingtocall, with waitfor set to false
+ *
+ * Arguments:
+ * * thingtocall Object to call on
+ * * proctocall Proc to call on that object
+ * * ... optional list of arguments to pass as arguments to the proc being called
+ */
/world/proc/ImmediateInvokeAsync(thingtocall, proctocall, ...)
set waitfor = FALSE
@@ -72,6 +96,14 @@
else
call(thingtocall, proctocall)(arglist(calling_arguments))
+/**
+ * Invoke this callback
+ *
+ * Calls the registered proc on the registered object, if the user ref
+ * can be resolved it also inclues that as an arg
+ *
+ * If the datum being called on is varedited, the call is wrapped via WrapAdminProcCall
+ */
/datum/callback/proc/Invoke(...)
if(!usr)
var/datum/weakref/W = user
@@ -97,7 +129,14 @@
return call(delegate)(arglist(calling_arguments))
return call(object, delegate)(arglist(calling_arguments))
-//copy and pasted because fuck proc overhead
+/**
+ * Invoke this callback async (waitfor=false)
+ *
+ * Calls the registered proc on the registered object, if the user ref
+ * can be resolved it also inclues that as an arg
+ *
+ * If the datum being called on is varedited, the call is wrapped via WrapAdminProcCall
+ */
/datum/callback/proc/InvokeAsync(...)
set waitfor = FALSE
@@ -125,7 +164,9 @@
return call(delegate)(arglist(calling_arguments))
return call(object, delegate)(arglist(calling_arguments))
-
+/**
+ Helper datum for the select callbacks proc
+ */
/datum/callback_select
var/list/finished
var/pendingcount
@@ -150,15 +191,17 @@
if (savereturn)
finished[index] = rtn
-
-
-
-//runs a list of callbacks asynchronously, returning once all of them return.
-//callbacks can be repeated.
-//callbacks-args is an optional list of argument lists, in the same order as the callbacks,
-// the inner lists will be sent to the callbacks when invoked() as additional args.
-//can optionly save and return a list of return values, in the same order as the original list of callbacks
-//resolution is the number of byond ticks between checks.
+/**
+ * Runs a list of callbacks asyncronously, returning only when all have finished
+ *
+ * Callbacks can be repeated, to call it multiple times
+ *
+ * Arguments:
+ * * list/callbacks the list of callbacks to be called
+ * * list/callback_args the list of lists of arguments to pass into each callback
+ * * savereturns Optionally save and return the list of returned values from each of the callbacks
+ * * resolution The number of byond ticks between each time you check if all callbacks are complete
+ */
/proc/callback_select(list/callbacks, list/callback_args, savereturns = TRUE, resolution = 1)
if (!callbacks)
return
@@ -178,3 +221,5 @@
sleep(resolution*world.tick_lag)
return CS.finished
+/proc/___callbacknew(typepath, arguments)
+ new typepath(arglist(arguments))
diff --git a/code/datums/components/nanites.dm b/code/datums/components/nanites.dm
index 89c4deb2e9..e1c96121c7 100644
--- a/code/datums/components/nanites.dm
+++ b/code/datums/components/nanites.dm
@@ -37,6 +37,7 @@
/datum/component/nanites/RegisterWithParent()
. = ..()
RegisterSignal(parent, COMSIG_HAS_NANITES, .proc/confirm_nanites)
+ RegisterSignal(parent, COMSIG_NANITE_IS_STEALTHY, .proc/check_stealth)
RegisterSignal(parent, COMSIG_NANITE_UI_DATA, .proc/nanite_ui_data)
RegisterSignal(parent, COMSIG_NANITE_GET_PROGRAMS, .proc/get_programs)
RegisterSignal(parent, COMSIG_NANITE_SET_VOLUME, .proc/set_volume)
@@ -57,10 +58,12 @@
RegisterSignal(parent, COMSIG_LIVING_MINOR_SHOCK, .proc/on_minor_shock)
RegisterSignal(parent, COMSIG_SPECIES_GAIN, .proc/check_viable_biotype)
RegisterSignal(parent, COMSIG_NANITE_SIGNAL, .proc/receive_signal)
+ RegisterSignal(parent, COMSIG_NANITE_COMM_SIGNAL, .proc/receive_comm_signal)
/datum/component/nanites/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, list(COMSIG_HAS_NANITES,
+ COMSIG_NANITE_IS_STEALTHY,
COMSIG_NANITE_UI_DATA,
COMSIG_NANITE_GET_PROGRAMS,
COMSIG_NANITE_SET_VOLUME,
@@ -79,7 +82,8 @@
COMSIG_LIVING_MINOR_SHOCK,
COMSIG_MOVABLE_HEAR,
COMSIG_SPECIES_GAIN,
- COMSIG_NANITE_SIGNAL))
+ COMSIG_NANITE_SIGNAL,
+ COMSIG_NANITE_COMM_SIGNAL))
/datum/component/nanites/Destroy()
STOP_PROCESSING(SSnanites, src)
@@ -188,6 +192,9 @@
var/datum/nanite_program/NP = X
NP.on_minor_shock()
+/datum/component/nanites/proc/check_stealth(datum/source)
+ return stealth
+
/datum/component/nanites/proc/on_death(datum/source, gibbed)
for(var/X in programs)
var/datum/nanite_program/NP = X
@@ -198,6 +205,12 @@
var/datum/nanite_program/NP = X
NP.receive_signal(code, source)
+/datum/component/nanites/proc/receive_comm_signal(datum/source, comm_code, comm_message, comm_source = "an unidentified source")
+ for(var/X in programs)
+ if(istype(X, /datum/nanite_program/triggered/comm))
+ var/datum/nanite_program/triggered/comm/NP = X
+ NP.receive_comm_signal(comm_code, comm_message, comm_source)
+
/datum/component/nanites/proc/check_viable_biotype()
if(!(MOB_ORGANIC in host_mob.mob_biotypes) && !(MOB_UNDEAD in host_mob.mob_biotypes))
qdel(src) //bodytype no longer sustains nanites
diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm
index 5caa491e4c..e387acbd0b 100644
--- a/code/datums/datumvars.dm
+++ b/code/datums/datumvars.dm
@@ -96,7 +96,6 @@
CLONE:[M.getCloneLoss()]
BRAIN:[M.getOrganLoss(ORGAN_SLOT_BRAIN)]
STAMINA:[M.getStaminaLoss()]
- AROUSAL:[M.getArousalLoss()]
"}
if(GLOB.Debug2)
atomsnowflake += {"
@@ -1359,9 +1358,6 @@
if("stamina")
L.adjustStaminaLoss(amount)
newamt = L.getStaminaLoss()
- if("arousal")
- L.adjustArousalLoss(amount)
- newamt = L.getArousalLoss()
if("heart")
L.adjustOrganLoss(ORGAN_SLOT_HEART, amount)
newamt = L.getOrganLoss(ORGAN_SLOT_HEART)
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 42f18b8ebb..464ea37d02 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -132,12 +132,8 @@
//CIT CHANGE - makes arousal update when transfering bodies
if(isliving(new_character)) //New humans and such are by default enabled arousal. Let's always use the new mind's prefs.
var/mob/living/L = new_character
- if(L.client && L.client.prefs)
- L.canbearoused = L.client.prefs.arousable //Technically this should make taking over a character mean the body gain the new minds setting...
- L.update_arousal_hud() //Removes the old icon
- if (L.client.prefs.auto_ooc)
- if (L.client.prefs.chat_toggles & CHAT_OOC)
- L.client.prefs.chat_toggles ^= CHAT_OOC
+ if(L.client && L.client.prefs & L.client.prefs.auto_ooc & L.client.prefs.chat_toggles & CHAT_OOC)
+ DISABLE_BITFIELD(L.client.prefs.chat_toggles,CHAT_OOC)
SEND_SIGNAL(src, COMSIG_MIND_TRANSFER, new_character, old_character)
SEND_SIGNAL(new_character, COMSIG_MOB_ON_NEW_MIND)
diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm
index a6e4c8ed4f..0b9b02af75 100644
--- a/code/datums/mood_events/generic_negative_events.dm
+++ b/code/datums/mood_events/generic_negative_events.dm
@@ -239,7 +239,14 @@
mood_change = -3
timeout = 1000
+/datum/mood_event/nanite_sadness
+ description = "+++++++HAPPINESS SUPPRESSION+++++++\n"
+ mood_change = -7
/datum/mood_event/daylight_2
description = "I have been scorched by the unforgiving rays of the sun.\n"
mood_change = -6
timeout = 1200
+
+/datum/mood_event/nanite_sadness/add_effects(message)
+ description = "+++++++[message]+++++++\n"
+
diff --git a/code/datums/mood_events/generic_positive_events.dm b/code/datums/mood_events/generic_positive_events.dm
index 98a8eade59..1e9a53cf57 100644
--- a/code/datums/mood_events/generic_positive_events.dm
+++ b/code/datums/mood_events/generic_positive_events.dm
@@ -142,6 +142,16 @@
mood_change = 2
timeout = 15 MINUTES
+/datum/mood_event/nanite_happiness
+ description = "+++++++HAPPINESS ENHANCEMENT+++++++\n"
+ mood_change = 7
+
+/datum/mood_event/nanite_happiness/add_effects(message)
+ description = "+++++++[message]+++++++\n"
+
+/datum/mood_event/area
+ description = "" //Fill this out in the area
+ mood_change = 0
//Power gamer stuff below
/datum/mood_event/drankblood
description = "I have fed greedly from that which nourishes me.\n"
diff --git a/code/datums/traits/neutral.dm b/code/datums/traits/neutral.dm
index 8be3174f50..d19efe486d 100644
--- a/code/datums/traits/neutral.dm
+++ b/code/datums/traits/neutral.dm
@@ -92,19 +92,10 @@
name = "Nymphomania"
desc = "You're always feeling a bit in heat. Also, you get aroused faster than usual."
value = 0
- mob_trait = TRAIT_NYMPHO
+ mob_trait = TRAIT_PERMABONER
gain_text = "You are feeling extra wild."
lose_text = "You don't feel that burning sensation anymore."
-/datum/quirk/libido/add()
- quirk_holder.min_arousal = 16
- quirk_holder.arousal_rate = 3
-
-/datum/quirk/libido/remove()
- if(quirk_holder)
- quirk_holder.min_arousal = initial(quirk_holder.min_arousal)
- quirk_holder.arousal_rate = initial(quirk_holder.arousal_rate)
-
/datum/quirk/maso
name = "Masochism"
desc = "You are aroused by pain."
@@ -113,15 +104,6 @@
gain_text = "You desire to be hurt."
lose_text = "Pain has become less exciting for you."
-/datum/quirk/exhibitionism
- name = "Exhibitionism"
- desc = "You don't mind showing off your bare body to strangers, in fact you find it quite satistying."
- value = 0
- medical_record_text = "Patient has been diagnosed with exhibitionistic disorder."
- mob_trait = TRAIT_EXHIBITIONIST
- gain_text = "You feel like exposing yourself to the world."
- lose_text = "Indecent exposure doesn't sound as charming to you anymore."
-
/datum/quirk/coldblooded
name = "Cold-blooded"
desc = "Your body doesn't create its own internal heat, requiring external heat regulation."
diff --git a/code/game/area/Space_Station_13_areas.dm b/code/game/area/Space_Station_13_areas.dm
index f26cfc4cdc..ad4c0c232d 100644
--- a/code/game/area/Space_Station_13_areas.dm
+++ b/code/game/area/Space_Station_13_areas.dm
@@ -259,6 +259,9 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
//Hallway
+/area/hallway
+ nightshift_public_area = NIGHTSHIFT_AREA_PUBLIC
+
/area/hallway/primary/aft
name = "Aft Primary Hallway"
icon_state = "hallA"
@@ -404,14 +407,17 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
name = "Dormitories"
icon_state = "Sleep"
safe = TRUE
+ nightshift_public_area = NIGHTSHIFT_AREA_RECREATION
/area/crew_quarters/dorms/male
name = "Male Dorm"
icon_state = "Sleep"
+ nightshift_public_area = NIGHTSHIFT_AREA_NONE
/area/crew_quarters/dorms/female
name = "Female Dorm"
icon_state = "Sleep"
+ nightshift_public_area = NIGHTSHIFT_AREA_NONE
/area/crew_quarters/rehab_dome
name = "Rehabilitation Dome"
@@ -448,26 +454,32 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
/area/crew_quarters/locker
name = "Locker Room"
icon_state = "locker"
+ nightshift_public_area = NIGHTSHIFT_AREA_RECREATION
/area/crew_quarters/lounge
name = "Lounge"
icon_state = "yellow"
+ nightshift_public_area = NIGHTSHIFT_AREA_RECREATION
/area/crew_quarters/fitness
name = "Fitness Room"
icon_state = "fitness"
+ nightshift_public_area = NIGHTSHIFT_AREA_RECREATION
/area/crew_quarters/fitness/recreation
name = "Recreation Area"
icon_state = "fitness"
+ nightshift_public_area = NIGHTSHIFT_AREA_RECREATION
/area/crew_quarters/cafeteria
name = "Cafeteria"
icon_state = "cafeteria"
+ nightshift_public_area = NIGHTSHIFT_AREA_RECREATION
/area/crew_quarters/cafeteria/lunchroom
name = "Lunchroom"
icon_state = "cafeteria"
+ nightshift_public_area = NIGHTSHIFT_AREA_RECREATION
/area/crew_quarters/kitchen
name = "Kitchen"
@@ -480,6 +492,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
/area/crew_quarters/bar
name = "Bar"
icon_state = "bar"
+ nightshift_public_area = NIGHTSHIFT_AREA_RECREATION
/area/crew_quarters/bar/atrium
name = "Atrium"
@@ -518,6 +531,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
name = "Library"
icon_state = "library"
flags_1 = NONE
+ nightshift_public_area = NIGHTSHIFT_AREA_RECREATION
/area/library/lounge
name = "Library Lounge"
@@ -527,6 +541,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
name = "Abandoned Library"
icon_state = "library"
flags_1 = NONE
+ nightshift_public_area = NIGHTSHIFT_AREA_NONE
/area/chapel
icon_state = "chapel"
@@ -534,12 +549,14 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
flags_1 = NONE
clockwork_warp_allowed = FALSE
clockwork_warp_fail = "The consecration here prevents you from warping in."
+ nightshift_public_area = NIGHTSHIFT_AREA_RECREATION
/area/chapel/main
name = "Chapel"
/area/chapel/main/monastery
name = "Monastery"
+ nightshift_public_area = NIGHTSHIFT_AREA_NONE
/area/chapel/office
name = "Chapel Office"
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index f65ea98cab..2d256aad27 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -63,6 +63,8 @@
var/xenobiology_compatible = FALSE //Can the Xenobio management console transverse this area by default?
var/list/canSmoothWithAreas //typecache to limit the areas that atoms in this area can smooth with
+ var/nightshift_public_area = NIGHTSHIFT_AREA_NONE //considered a public area for nightshift
+
/*Adding a wizard area teleport list because motherfucking lag -- Urist*/
/*I am far too lazy to make it a proper list of areas so I'll just make it run the usual telepot routine at the start of the game*/
GLOBAL_LIST_EMPTY(teleportlocs)
diff --git a/code/game/machinery/turnstile.dm b/code/game/machinery/turnstile.dm
index 1fd78056d4..9bc5193bbb 100644
--- a/code/game/machinery/turnstile.dm
+++ b/code/game/machinery/turnstile.dm
@@ -19,7 +19,7 @@
return TRUE
/obj/machinery/turnstile/bullet_act(obj/item/projectile/P, def_zone)
- return -1 //Pass through!
+ return BULLET_ACT_FORCE_PIERCE //Pass through!
/obj/machinery/turnstile/proc/allowed_access(var/mob/B)
if(B.pulledby && ismob(B.pulledby))
diff --git a/code/game/objects/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm
index 953b8b1f00..71c394a404 100644
--- a/code/game/objects/effects/spawners/lootdrop.dm
+++ b/code/game/objects/effects/spawners/lootdrop.dm
@@ -378,3 +378,11 @@
/obj/item/circuitboard/computer/apc_control,
/obj/item/circuitboard/computer/robotics
)
+
+/obj/effect/spawner/lootdrop/keg
+ name = "random keg spawner"
+ lootcount = 1
+ loot = list(/obj/structure/reagent_dispensers/keg/mead = 5,
+ /obj/structure/reagent_dispensers/keg/aphro = 2,
+ /obj/structure/reagent_dispensers/keg/aphro/strong = 2,
+ /obj/structure/reagent_dispensers/keg/gargle = 1)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 2bf039218b..78dde8d206 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -10,6 +10,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/item_state = null
var/lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
var/righthand_file = 'icons/mob/inhands/items_righthand.dmi'
+ var/list/alternate_screams = list() //REEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
//Dimensions of the icon file used when this item is worn, eg: hats.dmi
//eg: 32x32 sprite, 64x64 sprite, etc.
diff --git a/modular_citadel/code/game/objects/items/balls.dm b/code/game/objects/items/balls.dm
similarity index 99%
rename from modular_citadel/code/game/objects/items/balls.dm
rename to code/game/objects/items/balls.dm
index 79552bff6d..59b47bacbd 100644
--- a/modular_citadel/code/game/objects/items/balls.dm
+++ b/code/game/objects/items/balls.dm
@@ -89,4 +89,4 @@
resistance_flags = ACID_PROOF
/datum/action/item_action/squeeze
- name = "Squeak!"
\ No newline at end of file
+ name = "Squeak!"
diff --git a/modular_citadel/code/game/objects/items/boombox.dm b/code/game/objects/items/boombox.dm
similarity index 100%
rename from modular_citadel/code/game/objects/items/boombox.dm
rename to code/game/objects/items/boombox.dm
diff --git a/code/game/objects/items/cardboard_cutouts.dm b/code/game/objects/items/cardboard_cutouts.dm
index f3ed99b132..2daf6f0c0b 100644
--- a/code/game/objects/items/cardboard_cutouts.dm
+++ b/code/game/objects/items/cardboard_cutouts.dm
@@ -74,6 +74,7 @@
playsound(src, 'sound/weapons/slice.ogg', 50, 1)
if(prob(P.damage))
push_over()
+ return BULLET_ACT_HIT
/obj/item/cardboard_cutout/proc/change_appearance(obj/item/toy/crayon/crayon, mob/living/user)
if(!crayon || !user)
diff --git a/code/game/objects/items/chrono_eraser.dm b/code/game/objects/items/chrono_eraser.dm
index 911a07c288..2dcb495701 100644
--- a/code/game/objects/items/chrono_eraser.dm
+++ b/code/game/objects/items/chrono_eraser.dm
@@ -242,7 +242,7 @@
if(Pgun && istype(Pgun))
Pgun.field_connect(src)
else
- return 0
+ return BULLET_ACT_HIT
/obj/effect/chrono_field/assume_air()
return 0
diff --git a/code/game/objects/items/devices/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm
index dffbb46cbb..c4ffa9f0ff 100644
--- a/code/game/objects/items/devices/chameleonproj.dm
+++ b/code/game/objects/items/devices/chameleonproj.dm
@@ -146,7 +146,7 @@
master.disrupt()
/obj/effect/dummy/chameleon/bullet_act()
- ..()
+ . = ..()
master.disrupt()
/obj/effect/dummy/chameleon/relaymove(mob/user, direction)
diff --git a/code/game/objects/items/devices/radio/electropack.dm b/code/game/objects/items/devices/radio/electropack.dm
index 6aee67f2ee..d5cf6daabb 100644
--- a/code/game/objects/items/devices/radio/electropack.dm
+++ b/code/game/objects/items/devices/radio/electropack.dm
@@ -144,3 +144,80 @@ Code:
user << browse(dat, "window=radio")
onclose(user, "radio")
return
+
+/obj/item/electropack/shockcollar
+ name = "shock collar"
+ desc = "A reinforced metal collar. It seems to have some form of wiring near the front. Strange.."
+ icon = 'modular_citadel/icons/obj/clothing/cit_neck.dmi'
+ alternate_worn_icon = 'modular_citadel/icons/mob/citadel/neck.dmi'
+ icon_state = "shockcollar"
+ item_state = "shockcollar"
+ body_parts_covered = NECK
+ slot_flags = ITEM_SLOT_NECK | ITEM_SLOT_DENYPOCKET //no more pocket shockers
+ w_class = WEIGHT_CLASS_SMALL
+ strip_delay = 60
+ equip_delay_other = 60
+ materials = list(MAT_METAL=5000, MAT_GLASS=2000)
+
+ var/tagname = null
+
+/datum/design/electropack/shockcollar
+ name = "Shockcollar"
+ id = "shockcollar"
+ build_type = AUTOLATHE
+ build_path = /obj/item/electropack/shockcollar
+ materials = list(MAT_METAL=5000, MAT_GLASS=2000)
+ category = list("hacked", "Misc")
+
+/obj/item/electropack/shockcollar/attack_hand(mob/user)
+ if(loc == user && user.get_item_by_slot(SLOT_NECK))
+ to_chat(user, "The collar is fastened tight! You'll need help taking this off!")
+ return
+ return ..()
+
+/obj/item/electropack/shockcollar/receive_signal(datum/signal/signal)
+ if(!signal || signal.data["code"] != code)
+ return
+
+ if(isliving(loc) && on)
+ if(shock_cooldown == TRUE)
+ return
+ shock_cooldown = TRUE
+ addtimer(VARSET_CALLBACK(src, shock_cooldown, FALSE), 100)
+ var/mob/living/L = loc
+ step(L, pick(GLOB.cardinals))
+
+ to_chat(L, "You feel a sharp shock from the collar!")
+ var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
+ s.set_up(3, 1, L)
+ s.start()
+
+ L.Knockdown(100)
+
+ if(master)
+ master.receive_signal()
+ return
+
+/obj/item/electropack/shockcollar/attackby(obj/item/W, mob/user, params) //moves it here because on_click is being bad
+ if(istype(W, /obj/item/pen))
+ var/t = input(user, "Would you like to change the name on the tag?", "Name your new pet", tagname ? tagname : "Spot") as null|text
+ if(t)
+ tagname = copytext(sanitize(t), 1, MAX_NAME_LEN)
+ name = "[initial(name)] - [tagname]"
+ else
+ return ..()
+
+/obj/item/electropack/shockcollar/ui_interact(mob/user) //on_click calls this
+ var/dat = {"
+
+Frequency/Code for shock collar:
+Frequency:
+[format_frequency(src.frequency)]
+Set
+Code:
+[src.code]
+Set
+"}
+ user << browse(dat, "window=radio")
+ onclose(user, "radio")
+ return
diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm
index cc009b5fc2..e26b9dd845 100644
--- a/code/game/objects/items/devices/radio/encryptionkey.dm
+++ b/code/game/objects/items/devices/radio/encryptionkey.dm
@@ -92,7 +92,13 @@
/obj/item/encryptionkey/heads/hop
name = "\proper the head of personnel's encryption key"
icon_state = "hop_cypherkey"
- channels = list(RADIO_CHANNEL_SUPPLY = 1, RADIO_CHANNEL_SERVICE = 1, RADIO_CHANNEL_COMMAND = 1)
+ channels = list(RADIO_CHANNEL_SERVICE = 1, RADIO_CHANNEL_COMMAND = 1)
+
+/obj/item/encryptionkey/heads/qm
+ name = "\proper the quartermaster's encryption key"
+ desc = "An encryption key for a radio headset. Channels are as follows: :u - supply, :c - command."
+ icon_state = "hop_cypherkey"
+ channels = list(RADIO_CHANNEL_SUPPLY = 1, RADIO_CHANNEL_COMMAND = 1)
/obj/item/encryptionkey/headset_cargo
name = "supply radio encryption key"
diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm
index 13cd30561a..8c6666085e 100644
--- a/code/game/objects/items/devices/radio/headset.dm
+++ b/code/game/objects/items/devices/radio/headset.dm
@@ -206,6 +206,12 @@ GLOBAL_LIST_INIT(channel_tokens, list(
icon_state = "com_headset"
keyslot = new /obj/item/encryptionkey/heads/hop
+/obj/item/radio/headset/heads/qm
+ name = "\proper the quartermaster's headset"
+ desc = "The headset of the king (or queen) of paperwork."
+ icon_state = "com_headset"
+ keyslot = new /obj/item/encryptionkey/heads/qm
+
/obj/item/radio/headset/headset_cargo
name = "supply radio headset"
desc = "A headset used by the QM and his slaves."
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 3b296e5773..57c5a22de0 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -466,7 +466,7 @@ SLIME SCANNER
msg += "Subject is not addicted to any reagents.\n"
var/datum/reagent/impure/fermiTox/F = M.reagents.has_reagent(/datum/reagent/impure/fermiTox)
- if(istype(F))
+ if(istype(F,/datum/reagent/impure/fermiTox))
switch(F.volume)
if(5 to 10)
msg += "Subject contains a low amount of toxic isomers.\n"
diff --git a/code/game/objects/items/grenades/grenade.dm b/code/game/objects/items/grenades/grenade.dm
index 4f3dab803d..033ea9e791 100644
--- a/code/game/objects/items/grenades/grenade.dm
+++ b/code/game/objects/items/grenades/grenade.dm
@@ -122,3 +122,6 @@
owner.visible_message("[attack_text] hits [owner]'s [src], setting it off! What a shot!")
prime()
return TRUE //It hit the grenade, not them
+
+/obj/item/proc/grenade_prime_react(obj/item/grenade/nade)
+ return
diff --git a/code/game/objects/items/latexballoon.dm b/code/game/objects/items/latexballoon.dm
index 11be6b88e9..ef5b7b6cba 100644
--- a/code/game/objects/items/latexballoon.dm
+++ b/code/game/objects/items/latexballoon.dm
@@ -40,8 +40,10 @@
if (prob(50))
qdel(src)
-/obj/item/latexballon/bullet_act()
- burst()
+/obj/item/latexballon/bullet_act(obj/item/projectile/P)
+ if(!P.nodamage)
+ burst()
+ return ..()
/obj/item/latexballon/temperature_expose(datum/gas_mixture/air, temperature, volume)
if(temperature > T0C+100)
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index 4242fb6c4b..fde14a85d9 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -358,7 +358,8 @@
/obj/item/melee/supermatter_sword/bullet_act(obj/item/projectile/P)
visible_message("[P] smacks into [src] and rapidly flashes to ash.",\
"You hear a loud crack as you are washed with a wave of heat.")
- consume_everything()
+ consume_everything(P)
+ return BULLET_ACT_HIT
/obj/item/melee/supermatter_sword/suicide_act(mob/user)
user.visible_message("[user] touches [src]'s blade. It looks like [user.p_theyre()] tired of waiting for the radiation to kill [user.p_them()]!")
diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm
index 7f7780d3a4..acfc1353b9 100644
--- a/code/game/objects/items/robot/ai_upgrades.dm
+++ b/code/game/objects/items/robot/ai_upgrades.dm
@@ -9,8 +9,10 @@
icon_state = "datadisk3"
-/obj/item/malf_upgrade/afterattack(mob/living/silicon/ai/AI, mob/user)
+/obj/item/malf_upgrade/afterattack(mob/living/silicon/ai/AI, mob/user, proximity)
. = ..()
+ if(!proximity)
+ return
if(!istype(AI))
return
if(AI.malf_picker)
@@ -18,7 +20,11 @@
to_chat(AI, "[user] has attempted to upgrade you with combat software that you already possess. You gain 50 points to spend on Malfunction Modules instead.")
else
to_chat(AI, "[user] has upgraded you with combat software!")
+ to_chat(AI, "Your current laws and objectives remain unchanged.") //this unlocks malf powers, but does not give the license to plasma flood
AI.add_malf_picker()
+ AI.hack_software = TRUE
+ log_game("[key_name(user)] has upgraded [key_name(AI)] with a [src].")
+ message_admins("[ADMIN_LOOKUPFLW(user)] has upgraded [ADMIN_LOOKUPFLW(AI)] with a [src].")
to_chat(user, "You upgrade [AI]. [src] is consumed in the process.")
qdel(src)
@@ -26,12 +32,14 @@
//Lipreading
/obj/item/surveillance_upgrade
name = "surveillance software upgrade"
- desc = "A software package that will allow an artificial intelligence to 'hear' from its cameras via lip reading."
+ desc = "An illegal software package that will allow an artificial intelligence to 'hear' from its cameras via lip reading and hidden microphones."
icon = 'icons/obj/module.dmi'
icon_state = "datadisk3"
-/obj/item/surveillance_upgrade/afterattack(mob/living/silicon/ai/AI, mob/user)
+/obj/item/surveillance_upgrade/afterattack(mob/living/silicon/ai/AI, mob/user, proximity)
. = ..()
+ if(!proximity)
+ return
if(!istype(AI))
return
if(AI.eyeobj)
@@ -39,4 +47,6 @@
to_chat(AI, "[user] has upgraded you with surveillance software!")
to_chat(AI, "Via a combination of hidden microphones and lip reading software, you are able to use your cameras to listen in on conversations.")
to_chat(user, "You upgrade [AI]. [src] is consumed in the process.")
+ log_game("[key_name(user)] has upgraded [key_name(AI)] with a [src].")
+ message_admins("[ADMIN_LOOKUPFLW(user)] has upgraded [ADMIN_LOOKUPFLW(AI)] with a [src].")
qdel(src)
diff --git a/code/game/objects/items/shooting_range.dm b/code/game/objects/items/shooting_range.dm
index 256e84973d..2f40604719 100644
--- a/code/game/objects/items/shooting_range.dm
+++ b/code/game/objects/items/shooting_range.dm
@@ -60,7 +60,7 @@
#define DECALTYPE_BULLET 2
/obj/item/target/clown/bullet_act(obj/item/projectile/P)
- ..()
+ . = ..()
playsound(src.loc, 'sound/items/bikehorn.ogg', 50, 1)
/obj/item/target/bullet_act(obj/item/projectile/P)
@@ -89,8 +89,8 @@
else
bullet_hole.icon_state = "dent"
add_overlay(bullet_hole)
- return
- return -1
+ return BULLET_ACT_HIT
+ return BULLET_ACT_FORCE_PIERCE
#undef DECALTYPE_SCORCH
#undef DECALTYPE_BULLET
diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm
index 3ae0a4bd17..f34fc6a9a3 100644
--- a/code/game/objects/items/stunbaton.dm
+++ b/code/game/objects/items/stunbaton.dm
@@ -223,6 +223,46 @@
if(!iscyborg(loc))
deductcharge(1000 / severity, TRUE, FALSE)
+/obj/item/melee/baton/stunsword
+ name = "stunsword"
+ desc = "not actually sharp, this sword is functionally identical to a stunbaton"
+ icon = 'modular_citadel/icons/obj/stunsword.dmi'
+ icon_state = "stunsword"
+ item_state = "sword"
+ lefthand_file = 'modular_citadel/icons/mob/inhands/stunsword_left.dmi'
+ righthand_file = 'modular_citadel/icons/mob/inhands/stunsword_right.dmi'
+
+/obj/item/melee/baton/stunsword/get_belt_overlay()
+ if(istype(loc, /obj/item/storage/belt/sabre))
+ return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "stunsword")
+ return ..()
+
+/obj/item/melee/baton/stunsword/get_worn_belt_overlay(icon_file)
+ return mutable_appearance(icon_file, "-stunsword")
+
+/obj/item/ssword_kit
+ name = "stunsword kit"
+ desc = "a modkit for making a stunbaton into a stunsword"
+ icon = 'icons/obj/vending_restock.dmi'
+ icon_state = "refill_donksoft"
+ var/product = /obj/item/melee/baton/stunsword //what it makes
+ var/list/fromitem = list(/obj/item/melee/baton, /obj/item/melee/baton/loaded) //what it needs
+ afterattack(obj/O, mob/user as mob)
+ if(istype(O, product))
+ to_chat(user,"[O] is already modified!")
+ else if(O.type in fromitem) //makes sure O is the right thing
+ var/obj/item/melee/baton/B = O
+ if(!B.cell) //checks for a powercell in the baton. If there isn't one, continue. If there is, warn the user to take it out
+ new product(usr.loc) //spawns the product
+ user.visible_message("[user] modifies [O]!","You modify the [O]!")
+ qdel(O) //Gets rid of the baton
+ qdel(src) //gets rid of the kit
+
+ else
+ to_chat(user,"Remove the powercell first!") //We make this check because the stunsword starts without a battery.
+ else
+ to_chat(user, " You can't modify [O] with this kit!")
+
//Makeshift stun baton. Replacement for stun gloves.
/obj/item/melee/baton/cattleprod
name = "stunprod"
@@ -249,5 +289,6 @@
sparkler?.activate()
. = ..()
+
#undef STUNBATON_CHARGE_LENIENCY
#undef STUNBATON_DEPLETION_RATE
diff --git a/code/game/objects/structures/holosign.dm b/code/game/objects/structures/holosign.dm
index 69ad9f1567..617f42ed29 100644
--- a/code/game/objects/structures/holosign.dm
+++ b/code/game/objects/structures/holosign.dm
@@ -106,6 +106,7 @@
take_damage(10, BRUTE, "melee", 1) //Tasers aren't harmful.
if(istype(P, /obj/item/projectile/beam/disabler))
take_damage(5, BRUTE, "melee", 1) //Disablers aren't harmful.
+ return BULLET_ACT_HIT
/obj/structure/holosign/barrier/medical
name = "\improper PENLITE holobarrier"
@@ -152,6 +153,7 @@
/obj/structure/holosign/barrier/cyborg/hacked/bullet_act(obj/item/projectile/P)
take_damage(P.damage, BRUTE, "melee", 1) //Yeah no this doesn't get projectile resistance.
+ return BULLET_ACT_HIT
/obj/structure/holosign/barrier/cyborg/hacked/proc/cooldown()
shockcd = FALSE
diff --git a/code/game/objects/structures/reflector.dm b/code/game/objects/structures/reflector.dm
index cde60e15c1..5cc2315352 100644
--- a/code/game/objects/structures/reflector.dm
+++ b/code/game/objects/structures/reflector.dm
@@ -64,15 +64,15 @@
var/ploc = get_turf(P)
if(!finished || !allowed_projectile_typecache[P.type] || !(P.dir in GLOB.cardinals))
return ..()
- if(auto_reflect(P, pdir, ploc, pangle) != -1)
+ if(auto_reflect(P, pdir, ploc, pangle) != BULLET_ACT_FORCE_PIERCE)
return ..()
- return -1
+ return BULLET_ACT_FORCE_PIERCE
/obj/structure/reflector/proc/auto_reflect(obj/item/projectile/P, pdir, turf/ploc, pangle)
P.ignore_source_check = TRUE
P.range = P.decayedRange
P.decayedRange = max(P.decayedRange--, 0)
- return -1
+ return BULLET_ACT_FORCE_PIERCE
/obj/structure/reflector/attackby(obj/item/W, mob/user, params)
if(admin)
diff --git a/code/game/objects/structures/statues.dm b/code/game/objects/structures/statues.dm
index 5e6b35ba4f..9a6b24b472 100644
--- a/code/game/objects/structures/statues.dm
+++ b/code/game/objects/structures/statues.dm
@@ -124,7 +124,7 @@
message_admins("Plasma statue ignited by [Proj]. No known firer, in [ADMIN_VERBOSEJMP(T)]")
log_game("Plasma statue ignited by [Proj] in [AREACOORD(T)]. No known firer.")
PlasmaBurn(2500)
- ..()
+ return ..()
/obj/structure/statue/plasma/attackby(obj/item/W, mob/user, params)
if(W.get_temperature() > 300 && !QDELETED(src))//If the temperature of the object is over 300, then ignite
diff --git a/code/game/objects/structures/target_stake.dm b/code/game/objects/structures/target_stake.dm
index b69b98ceaa..9dcfec43bf 100644
--- a/code/game/objects/structures/target_stake.dm
+++ b/code/game/objects/structures/target_stake.dm
@@ -71,6 +71,5 @@
/obj/structure/target_stake/bullet_act(obj/item/projectile/P)
if(pinned_target)
- pinned_target.bullet_act(P)
- else
- ..()
+ return pinned_target.bullet_act(P)
+ return ..()
diff --git a/code/game/turfs/simulated/wall/mineral_walls.dm b/code/game/turfs/simulated/wall/mineral_walls.dm
index 9962f72d4a..be46d124ea 100644
--- a/code/game/turfs/simulated/wall/mineral_walls.dm
+++ b/code/game/turfs/simulated/wall/mineral_walls.dm
@@ -120,7 +120,7 @@
PlasmaBurn(2500)
else if(istype(Proj, /obj/item/projectile/ion))
PlasmaBurn(500)
- ..()
+ return ..()
/turf/closed/wall/mineral/wood
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index e81b3d1062..d8434f986c 100755
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -224,14 +224,20 @@
for(var/i in contents)
if(i == mover || i == mover.loc) // Multi tile objects and moving out of other objects
continue
+ if(QDELETED(mover))
+ break
var/atom/movable/thing = i
- if(thing.Cross(mover))
- continue
- if(!firstbump || ((thing.layer > firstbump.layer || thing.flags_1 & ON_BORDER_1) && !(firstbump.flags_1 & ON_BORDER_1)))
- firstbump = thing
+ if(!thing.Cross(mover))
+ if(CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE))
+ mover.Bump(thing)
+ continue
+ else
+ if(!firstbump || ((thing.layer > firstbump.layer || thing.flags_1 & ON_BORDER_1) && !(firstbump.flags_1 & ON_BORDER_1)))
+ firstbump = thing
if(firstbump)
- mover.Bump(firstbump)
- return FALSE
+ if(!QDELETED(mover))
+ mover.Bump(firstbump)
+ return CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE)
return TRUE
/turf/Exit(atom/movable/mover, atom/newloc)
@@ -239,13 +245,16 @@
if(!.)
return FALSE
for(var/i in contents)
+ if(QDELETED(mover))
+ break
if(i == mover)
continue
var/atom/movable/thing = i
if(!thing.Uncross(mover, newloc))
if(thing.flags_1 & ON_BORDER_1)
mover.Bump(thing)
- return FALSE
+ if(!CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE))
+ return FALSE
/turf/Entered(atom/movable/AM)
..()
@@ -563,3 +572,8 @@
//Should return new turf
/turf/proc/Melt()
return ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
+
+/turf/bullet_act(obj/item/projectile/P)
+ . = ..()
+ if(. != BULLET_ACT_FORCE_PIERCE)
+ . = BULLET_ACT_TURF
diff --git a/code/game/world.dm b/code/game/world.dm
index 5e7629fbb4..df0eba70cd 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -34,10 +34,12 @@ GLOBAL_LIST(topic_status_cache)
#endif
load_admins()
+ load_mentors()
LoadVerbs(/datum/verbs/menu)
if(CONFIG_GET(flag/usewhitelist))
load_whitelist()
LoadBans()
+ initialize_global_loadout_items()
reload_custom_roundstart_items_list()//Cit change - loads donator items. Remind me to remove when I port over bay's loadout system
GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000
@@ -49,8 +51,6 @@ GLOBAL_LIST(topic_status_cache)
if(NO_INIT_PARAMETER in params)
return
- cit_initialize()
-
Master.Initialize(10, FALSE, TRUE)
if(TEST_RUN_PARAMETER in params)
diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm
index b2ab5caef8..49c34f4d1f 100644
--- a/code/modules/antagonists/changeling/powers/mutations.dm
+++ b/code/modules/antagonists/changeling/powers/mutations.dm
@@ -345,13 +345,13 @@
/obj/item/projectile/tentacle/on_hit(atom/target, blocked = FALSE)
var/mob/living/carbon/human/H = firer
if(blocked >= 100)
- return 0
+ return BULLET_ACT_BLOCK
if(isitem(target))
var/obj/item/I = target
if(!I.anchored)
to_chat(firer, "You pull [I] right into your grasp.")
H.put_in_hands(I) //Because throwing it is goofy as fuck and unreliable. If you land the tentacle despite the penalties to accuracy, you should have your reward.
- . = 1
+ . = BULLET_ACT_HIT
else if(isliving(target))
var/mob/living/L = target
@@ -366,7 +366,7 @@
if(INTENT_HELP)
C.visible_message("[L] is pulled by [H]'s tentacle!","A tentacle grabs you and pulls you towards [H]!")
C.throw_at(get_step_towards(H,C), 8, 2)
- return 1
+ return BULLET_ACT_HIT
if(INTENT_DISARM)
var/obj/item/I = C.get_active_held_item()
@@ -374,27 +374,27 @@
if(C.dropItemToGround(I))
C.visible_message("[I] is yanked off [C]'s hand by [src]!","A tentacle pulls [I] away from you!")
on_hit(I) //grab the item as if you had hit it directly with the tentacle
- return 1
+ return BULLET_ACT_HIT
else
to_chat(firer, "You can't seem to pry [I] off [C]'s hands!")
- return 0
+ return BULLET_ACT_BLOCK
else
to_chat(firer, "[C] has nothing in hand to disarm!")
- return 0
+ return BULLET_ACT_HIT
if(INTENT_GRAB)
C.visible_message("[L] is grabbed by [H]'s tentacle!","A tentacle grabs you and pulls you towards [H]!")
C.throw_at(get_step_towards(H,C), 8, 2, H, TRUE, TRUE, callback=CALLBACK(src, .proc/tentacle_grab, H, C))
- return 1
+ return BULLET_ACT_HIT
if(INTENT_HARM)
C.visible_message("[L] is thrown towards [H] by a tentacle!","A tentacle grabs you and throws you towards [H]!")
C.throw_at(get_step_towards(H,C), 8, 2, H, TRUE, TRUE, callback=CALLBACK(src, .proc/tentacle_stab, H, C))
- return 1
+ return BULLET_ACT_HIT
else
L.visible_message("[L] is pulled by [H]'s tentacle!","A tentacle grabs you and pulls you towards [H]!")
L.throw_at(get_step_towards(H,L), 8, 2)
- . = 1
+ . = BULLET_ACT_HIT
/obj/item/projectile/tentacle/Destroy()
qdel(chain)
diff --git a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm
index a27f911163..eb7f83735d 100644
--- a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm
+++ b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm
@@ -319,9 +319,9 @@
L.dust()
else
if(!GLOB.ratvar_awakens && L.stat == CONSCIOUS)
- vitality_drained = L.adjustToxLoss(1)
+ vitality_drained = L.adjustToxLoss(1, forced = TRUE)
else
- vitality_drained = L.adjustToxLoss(1.5)
+ vitality_drained = L.adjustToxLoss(1.5, forced = TRUE)
if(vitality_drained)
GLOB.clockwork_vitality += vitality_drained
else
diff --git a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm
index 9f2ddfda47..ee1a1233d2 100644
--- a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm
+++ b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm
@@ -182,7 +182,7 @@
if(isliving(target))
var/mob/living/L = target
if(is_servant_of_ratvar(L) || L.stat || L.has_status_effect(STATUS_EFFECT_KINDLE))
- return
+ return BULLET_ACT_HIT
var/atom/O = L.anti_magic_check()
playsound(L, 'sound/magic/fireball.ogg', 50, TRUE, frequency = 1.25)
if(O)
diff --git a/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm b/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm
index 311f552467..6591343116 100644
--- a/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm
+++ b/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm
@@ -97,7 +97,7 @@
/mob/living/simple_animal/hostile/clockwork/marauder/bullet_act(obj/item/projectile/P)
if(deflect_projectile(P))
- return
+ return BULLET_ACT_BLOCK
return ..()
/mob/living/simple_animal/hostile/clockwork/marauder/proc/deflect_projectile(obj/item/projectile/P)
diff --git a/code/modules/antagonists/clockcult/clock_structures/reflector.dm b/code/modules/antagonists/clockcult/clock_structures/reflector.dm
index 34ad051d19..364409d39e 100644
--- a/code/modules/antagonists/clockcult/clock_structures/reflector.dm
+++ b/code/modules/antagonists/clockcult/clock_structures/reflector.dm
@@ -31,7 +31,7 @@
if(auto_reflect(P, P.dir, get_turf(P), P.Angle) != -1)
return ..()
- return -1
+ return BULLET_ACT_FORCE_PIERCE
/obj/structure/destructible/clockwork/reflector/proc/auto_reflect(obj/item/projectile/P, pdir, turf/ploc, pangle)
diff --git a/code/modules/atmospherics/machinery/pipes/simple.dm b/code/modules/atmospherics/machinery/pipes/simple.dm
index dbe67a1594..7cab3c23dc 100644
--- a/code/modules/atmospherics/machinery/pipes/simple.dm
+++ b/code/modules/atmospherics/machinery/pipes/simple.dm
@@ -35,7 +35,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/general/visible
level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER
-
+
/obj/machinery/atmospherics/pipe/simple/general/visible/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -58,7 +58,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
-
+
/obj/machinery/atmospherics/pipe/simple/scrubbers
name="scrubbers pipe"
pipe_color=rgb(255,0,0)
@@ -77,7 +77,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
-
+
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden
level = PIPE_HIDDEN_LEVEL
@@ -90,7 +90,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
-
+
/obj/machinery/atmospherics/pipe/simple/supply
name="air supply pipe"
pipe_color=rgb(0,0,255)
@@ -99,7 +99,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/supply/visible
level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER
-
+
/obj/machinery/atmospherics/pipe/simple/supply/visible/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -122,7 +122,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
-
+
/obj/machinery/atmospherics/pipe/simple/supplymain
name="main air supply pipe"
pipe_color=rgb(130,43,255)
@@ -141,7 +141,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
-
+
/obj/machinery/atmospherics/pipe/simple/supplymain/hidden
level = PIPE_HIDDEN_LEVEL
@@ -154,7 +154,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
-
+
/obj/machinery/atmospherics/pipe/simple/yellow
pipe_color=rgb(255,198,0)
color=rgb(255,198,0)
@@ -172,7 +172,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
-
+
/obj/machinery/atmospherics/pipe/simple/yellow/hidden
level = PIPE_HIDDEN_LEVEL
@@ -185,7 +185,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
-
+
/obj/machinery/atmospherics/pipe/simple/cyan
pipe_color=rgb(0,255,249)
color=rgb(0,255,249)
@@ -193,7 +193,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/cyan/visible
level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER
-
+
/obj/machinery/atmospherics/pipe/simple/cyan/visible/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -206,7 +206,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/cyan/hidden
level = PIPE_HIDDEN_LEVEL
-
+
/obj/machinery/atmospherics/pipe/simple/cyan/hidden/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -224,7 +224,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/green/visible
level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER
-
+
/obj/machinery/atmospherics/pipe/simple/green/visible/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -237,7 +237,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/green/hidden
level = PIPE_HIDDEN_LEVEL
-
+
/obj/machinery/atmospherics/pipe/simple/green/hidden/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -255,7 +255,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/orange/visible
level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER
-
+
/obj/machinery/atmospherics/pipe/simple/orange/visible/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -268,7 +268,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/orange/hidden
level = PIPE_HIDDEN_LEVEL
-
+
/obj/machinery/atmospherics/pipe/simple/orange/hidden/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -286,7 +286,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/purple/visible
level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER
-
+
/obj/machinery/atmospherics/pipe/simple/purple/visible/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -309,7 +309,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
-
+
/obj/machinery/atmospherics/pipe/simple/dark
pipe_color=rgb(69,69,69)
color=rgb(69,69,69)
@@ -317,7 +317,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/dark/visible
level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER
-
+
/obj/machinery/atmospherics/pipe/simple/dark/visible/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -340,7 +340,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
-
+
/obj/machinery/atmospherics/pipe/simple/violet
pipe_color=rgb(64,0,128)
color=rgb(64,0,128)
@@ -348,7 +348,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/violet/visible
level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER
-
+
/obj/machinery/atmospherics/pipe/simple/violet/visible/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -371,7 +371,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
-
+
/obj/machinery/atmospherics/pipe/simple/brown
pipe_color=rgb(178,100,56)
color=rgb(178,100,56)
@@ -379,7 +379,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/brown/visible
level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER
-
+
/obj/machinery/atmospherics/pipe/simple/brown/visible/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
diff --git a/code/modules/cargo/exports.dm b/code/modules/cargo/exports.dm
index 51c4864034..fca10ac01c 100644
--- a/code/modules/cargo/exports.dm
+++ b/code/modules/cargo/exports.dm
@@ -24,7 +24,8 @@ Credit dupes that require a lot of manual work shouldn't be removed, unless they
var/list/exported_atoms = list()//names of atoms sold/deleted by export
var/list/total_amount = list() //export instance => total count of sold objects of its type, only exists if any were sold
var/list/total_value = list() //export instance => total value of sold objects
- var/list/total_reagents = list()//export reagents => into the total vaule of the object sold
+ var/list/reagents_volume = list()//export reagents => into the total volume of the object sold
+ var/list/reagents_value = list()//export reagents => into the reagent type total value.
// external_report works as "transaction" object, pass same one in if you're doing more than one export in single go
/proc/export_item_and_contents(atom/movable/AM, allowed_categories = EXPORT_CARGO, apply_elastic = TRUE, delete_unsold = TRUE, dry_run=FALSE, datum/export_report/external_report)
@@ -49,8 +50,12 @@ Credit dupes that require a lot of manual work shouldn't be removed, unless they
report.exported_atoms += " [thing.name]"
break
if(thing.reagents)
- for(var/datum/reagent/R in thing.reagents.reagent_list)
- report.total_reagents[R] += R.volume
+ for(var/A in thing.reagents.reagent_list)
+ var/datum/reagent/R = A
+ if(!R.value)
+ continue
+ report.reagents_volume[R.name] += R.volume
+ report.reagents_value[R.name] += R.volume * R.value
if(!dry_run && (sold || delete_unsold))
if(ismob(thing))
thing.investigate_log("deleted through cargo export",INVESTIGATE_CARGO)
diff --git a/code/modules/cargo/packs/engineering.dm b/code/modules/cargo/packs/engineering.dm
index f09c9e429d..ea90255bce 100644
--- a/code/modules/cargo/packs/engineering.dm
+++ b/code/modules/cargo/packs/engineering.dm
@@ -73,6 +73,17 @@
crate_name = "atmospherics hardsuit"
crate_type = /obj/structure/closet/crate/secure/engineering
+/datum/supply_pack/engineering/radhardsuit
+ name = "Radiation Hardsuit"
+ desc = "The Singulo is loose? Do you need to do a few changes to its containment and don't want to spent the rest of the shift under the shower? Get this Radiation Hardsuit! It protect from radiations and space only."
+ cost = 3500
+ access = ACCESS_ENGINE
+ contains = list(/obj/item/tank/internals/air,
+ /obj/item/clothing/mask/gas,
+ /obj/item/clothing/suit/space/hardsuit/engine/rad)
+ crate_name = "radiation hardsuit"
+ crate_type = /obj/structure/closet/crate/secure/engineering
+
/datum/supply_pack/engineering/industrialrcd
name = "Industrial RCD"
desc = "An industrial RCD in case the station has gone through more then one meteor storm and the CE needs to bring out the somthing a bit more reliable. Does not contain spare ammo for the industrial RCD or any other RCD models."
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 7b7cf3413e..546268b5c7 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -1007,6 +1007,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "Forced Feminization: [(cit_toggles & FORCED_FEM) ? "Allowed" : "Disallowed"]
"
dat += "Forced Masculinization: [(cit_toggles & FORCED_MASC) ? "Allowed" : "Disallowed"]
"
dat += "Lewd Hypno: [(cit_toggles & HYPNO) ? "Allowed" : "Disallowed"]
"
+ dat += "Bimbofication: [(cit_toggles & BIMBOFICATION) ? "Allowed" : "Disallowed"]
"
dat += ""
dat +=""
dat += "Other content prefs"
@@ -1015,6 +1016,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "Hypno: [(cit_toggles & NEVER_HYPNO) ? "Disallowed" : "Allowed"] "
dat += "Aphrodisiacs: [(cit_toggles & NO_APHRO) ? "Disallowed" : "Allowed"] "
dat += "Ass Slapping: [(cit_toggles & NO_ASS_SLAP) ? "Disallowed" : "Allowed"] "
+ dat += ""
dat += " "
@@ -2234,6 +2236,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("ass_slap")
cit_toggles ^= NO_ASS_SLAP
+
+ if("bimbo")
+ cit_toggles ^= BIMBOFICATION
//END CITADEL EDIT
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index 2472cbef78..08ecefb91f 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -109,10 +109,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
else if(current_version < 23) // we are fixing a gamebreaking bug.
job_preferences = list() //It loaded null from nonexistant savefile field.
- if(current_version < 24 && S["feature_exhibitionist"])
- var/datum/quirk/exhibitionism/E
- var/quirk_name = initial(E.name)
- all_quirks += quirk_name
if(current_version < 25)
var/digi
S["feature_lizard_legs"] >> digi
@@ -543,6 +539,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
ENABLE_BITFIELD(cit_toggles,NO_ASS_SLAP)
all_quirks -= V
+ if(features["meat_type"] == "Inesct")
+ features["meat_type"] = "Insect"
cit_character_pref_load(S)
return 1
diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm
index 07014c8a0a..696ff1346c 100644
--- a/code/modules/clothing/head/misc.dm
+++ b/code/modules/clothing/head/misc.dm
@@ -178,6 +178,7 @@
icon_state = "xenos"
item_state = "xenos_helm"
desc = "A helmet made out of chitinous alien hide."
+ alternate_screams = list('sound/voice/hiss6.ogg')
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT
/obj/item/clothing/head/fedora
@@ -421,4 +422,4 @@
name = "security cowboy hat"
desc = "A security cowboy hat, perfect for any true lawman"
icon_state = "cowboyhat_sec"
- item_state= "cowboyhat_sec"
\ No newline at end of file
+ item_state= "cowboyhat_sec"
diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm
index 1000decc87..bb2014db5c 100644
--- a/code/modules/clothing/head/misc_special.dm
+++ b/code/modules/clothing/head/misc_special.dm
@@ -86,6 +86,7 @@
desc = "Perfect for winter in Siberia, da?"
icon_state = "ushankadown"
item_state = "ushankadown"
+ alternate_screams = list('sound/voice/human/cyka1.ogg', 'sound/voice/human/cheekibreeki.ogg')
flags_inv = HIDEEARS|HIDEHAIR
var/earflaps = 1
cold_protection = HEAD
@@ -164,6 +165,7 @@
icon_state = "cardborg_h"
item_state = "cardborg_h"
flags_cover = HEADCOVERSEYES
+ alternate_screams = list('modular_citadel/sound/voice/scream_silicon.ogg')
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT
dog_fashion = /datum/dog_fashion/head/cardborg
diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm
index 984c19e202..c04f581425 100644
--- a/code/modules/clothing/spacesuits/hardsuit.dm
+++ b/code/modules/clothing/spacesuits/hardsuit.dm
@@ -203,6 +203,31 @@
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/engine/atmos
+ //Radiation
+/obj/item/clothing/head/helmet/space/hardsuit/engine/rad
+ name = "radiation hardsuit helmet"
+ desc = "A special helmet that protects against radiation and space. Not much else unfortunately."
+ icon_state = "cespace_helmet"
+ item_state = "nothing"
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 0, "acid" = 0)
+ item_color = "engineering"
+ resistance_flags = FIRE_PROOF
+ rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
+ actions_types = list()
+
+/obj/item/clothing/suit/space/hardsuit/engine/rad
+ name = "radiation hardsuit"
+ desc = "A special suit that protects against radiation and space. Not much else unfortunately."
+ icon_state = "hardsuit-rad"
+ item_state = "nothing"
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 0, "acid" = 0)
+ helmettype = /obj/item/clothing/head/helmet/space/hardsuit/engine/rad
+ resistance_flags = FIRE_PROOF
+ rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
+ mutantrace_variation = NONE
+
+/obj/item/clothing/head/helmet/space/hardsuit/engine/rad/attack_self()
+ return //Sprites required for flashlight
//Chief Engineer's hardsuit
/obj/item/clothing/head/helmet/space/hardsuit/engine/elite
diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm
index bfffe15721..c9c3d1ff39 100644
--- a/code/modules/clothing/spacesuits/miscellaneous.dm
+++ b/code/modules/clothing/spacesuits/miscellaneous.dm
@@ -434,7 +434,7 @@ Contains:
strip_delay = 65
/obj/item/clothing/suit/space/fragile/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- if(!torn && prob(50))
+ if(!torn && prob(50) && damage >= 5)
to_chat(owner, "[src] tears from the damage, breaking the air-tight seal!")
clothing_flags &= ~STOPSPRESSUREDAMAGE
name = "torn [src]."
diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm
index 195c9440e1..127d2e4f04 100644
--- a/code/modules/clothing/suits/miscellaneous.dm
+++ b/code/modules/clothing/suits/miscellaneous.dm
@@ -826,6 +826,22 @@
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
real = FALSE
+/obj/item/clothing/suit/hooded/wintercoat/durathread
+ name = "durathread winter coat"
+ desc = "The one coat to rule them all. Extremely durable while providing the utmost comfort."
+ icon_state = "coatdurathread"
+ item_state = "coatdurathread"
+ armor = list("melee" = 15, "bullet" = 8, "laser" = 25, "energy" = 5, "bomb" = 12, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 50)
+ hoodtype = /obj/item/clothing/head/hooded/winterhood/durathread
+
+/obj/item/clothing/suit/hooded/wintercoat/durathread/Initialize()
+ . = ..()
+ allowed = GLOB.security_wintercoat_allowed
+
+/obj/item/clothing/head/hooded/winterhood/durathread
+ icon_state = "winterhood_durathread"
+ armor = list("melee" = 20, "bullet" = 8, "laser" = 15, "energy" = 8, "bomb" = 25, "bio" = 10, "rad" = 15, "fire" = 75, "acid" = 37)
+
/obj/item/clothing/suit/spookyghost
name = "spooky ghost"
diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm
index 06aa5aeb0c..a2081851e1 100644
--- a/code/modules/clothing/under/miscellaneous.dm
+++ b/code/modules/clothing/under/miscellaneous.dm
@@ -471,6 +471,7 @@
name = "white sundress"
desc = "Makes you want to frolic in a field of lillies."
icon_state = "sundress_white"
+ item_state = "sundress"
item_color = "sundress_white"
body_parts_covered = CHEST|GROIN
fitted = FEMALE_UNIFORM_TOP
@@ -527,6 +528,16 @@
item_color = "assistant_formal"
can_adjust = FALSE
+/obj/item/clothing/under/staffassistant
+ name = "staff assistant's jumpsuit"
+ desc = "It's a generic grey jumpsuit. That's about what assistants are worth, anyway."
+ icon = 'goon/icons/obj/item_js_rank.dmi'
+ alternate_worn_icon = 'goon/icons/mob/worn_js_rank.dmi'
+ icon_state = "assistant"
+ item_state = "gy_suit"
+ item_color = "assistant"
+ mutantrace_variation = NONE
+
/obj/item/clothing/under/blacktango
name = "black tango dress"
desc = "Filled with Latin fire."
@@ -580,7 +591,7 @@
icon_state = "flower_dress"
item_state = "sailordress"
item_color = "flower_dress"
- body_parts_covered = CHEST|GROIN
+ body_parts_covered = CHEST|GROIN|LEGS
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
@@ -605,9 +616,8 @@
/obj/item/clothing/under/croptop
name = "crop top"
desc = "We've saved money by giving you half a shirt!"
- icon_state = "sailor_dress"
- item_state = "sailordress"
- item_color = "sailor_dress"
+ icon_state = "croptop"
+ item_color = "croptop"
body_parts_covered = CHEST|GROIN|ARMS
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
diff --git a/code/modules/crafting/recipes/recipes_clothing.dm b/code/modules/crafting/recipes/recipes_clothing.dm
index 8cb35df9d1..26de5f380d 100644
--- a/code/modules/crafting/recipes/recipes_clothing.dm
+++ b/code/modules/crafting/recipes/recipes_clothing.dm
@@ -159,6 +159,14 @@
always_availible = TRUE
category = CAT_CLOTHING
+/datum/crafting_recipe/durathread_wintercoat
+ name = "Durathread Winter Coat"
+ result = /obj/item/clothing/suit/hooded/wintercoat/durathread
+ reqs = list(/obj/item/stack/sheet/durathread = 12,
+ /obj/item/stack/sheet/leather = 10)
+ time = 70
+ category = CAT_CLOTHING
+
/datum/crafting_recipe/wintercoat_cosmic
name = "Cosmic Winter Coat"
result = /obj/item/clothing/suit/hooded/wintercoat/cosmic
diff --git a/code/modules/hydroponics/gene_modder.dm b/code/modules/hydroponics/gene_modder.dm
index 1aa9bb86e2..78b638a5f6 100644
--- a/code/modules/hydroponics/gene_modder.dm
+++ b/code/modules/hydroponics/gene_modder.dm
@@ -234,8 +234,8 @@
dat += " | | [G.get_name()] | "
if(can_extract && G.mutability_flags & PLANT_GENE_EXTRACTABLE)
dat += "Extract"
- if(G.mutability_flags & PLANT_GENE_REMOVABLE)
- dat += "Remove"
+ if(G.mutability_flags & PLANT_GENE_REMOVABLE)
+ dat += "Remove"
dat += " |
"
dat += ""
else
diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm
index 5bc3fb0b60..2d0d2c5282 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -90,6 +90,7 @@
return ..()
if(istype(Proj , /obj/item/projectile/energy/floramut))
mutate()
+ return BULLET_ACT_HIT
else if(istype(Proj , /obj/item/projectile/energy/florayield))
return myseed.bullet_act(Proj)
else
diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm
index 9a0085eb3d..c28ae3b4c5 100644
--- a/code/modules/hydroponics/seeds.dm
+++ b/code/modules/hydroponics/seeds.dm
@@ -145,6 +145,7 @@ obj/item/seeds/proc/is_gene_forbidden(typepath)
adjust_yield(1 * rating)
else if(prob(1/(yield * yield) * 100))//This formula gives you diminishing returns based on yield. 100% with 1 yield, decreasing to 25%, 11%, 6, 4, 2...
adjust_yield(1 * rating)
+ return BULLET_ACT_HIT
else
return ..()
diff --git a/code/modules/integrated_electronics/subtypes/input.dm b/code/modules/integrated_electronics/subtypes/input.dm
index 46f8017b10..4f9afd9ed5 100644
--- a/code/modules/integrated_electronics/subtypes/input.dm
+++ b/code/modules/integrated_electronics/subtypes/input.dm
@@ -1310,34 +1310,3 @@
set_pin_data(IC_OUTPUT, 2, regurgitated_contents)
push_data()
activate_pin(2)
-
-//Degens
-/obj/item/integrated_circuit/input/bonermeter
- name = "bonermeter"
- desc = "Detects the target's arousal and various statistics about the target's arousal levels. Invasive!"
- icon_state = "medscan"
- complexity = 4
- inputs = list("target" = IC_PINTYPE_REF)
- outputs = list(
- "current arousal" = IC_PINTYPE_NUMBER,
- "minimum arousal" = IC_PINTYPE_NUMBER,
- "maximum arousal" = IC_PINTYPE_NUMBER,
- "can be aroused" = IC_PINTYPE_BOOLEAN
- )
- activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT)
- spawn_flags = IC_SPAWN_RESEARCH
- power_draw_per_use = 40
-
-/obj/item/integrated_circuit/input/bonermeter/do_work()
-
- var/mob/living/L = get_pin_data_as_type(IC_INPUT, 1, /mob/living)
-
- if(!istype(L) || !L.Adjacent(get_turf(src)) ) //Invalid input
- return
-
- set_pin_data(IC_OUTPUT, 1, L.getArousalLoss())
- set_pin_data(IC_OUTPUT, 2, L.min_arousal)
- set_pin_data(IC_OUTPUT, 3, L.max_arousal)
- set_pin_data(IC_OUTPUT, 4, L.canbearoused)
- push_data()
- activate_pin(2)
\ No newline at end of file
diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers/_mapping_helpers.dm
similarity index 59%
rename from code/modules/mapping/mapping_helpers.dm
rename to code/modules/mapping/mapping_helpers/_mapping_helpers.dm
index a7f84fd71f..99184b1c3e 100644
--- a/code/modules/mapping/mapping_helpers.dm
+++ b/code/modules/mapping/mapping_helpers/_mapping_helpers.dm
@@ -1,90 +1,4 @@
//Landmarks and other helpers which speed up the mapping process and reduce the number of unique instances/subtypes of items/turf/ect
-
-
-
-/obj/effect/baseturf_helper //Set the baseturfs of every turf in the /area/ it is placed.
- name = "baseturf editor"
- icon = 'icons/effects/mapping_helpers.dmi'
- icon_state = ""
-
- var/list/baseturf_to_replace
- var/baseturf
-
- layer = POINT_LAYER
-
-/obj/effect/baseturf_helper/Initialize()
- . = ..()
- return INITIALIZE_HINT_LATELOAD
-
-/obj/effect/baseturf_helper/LateInitialize()
- if(!baseturf_to_replace)
- baseturf_to_replace = typecacheof(list(/turf/open/space,/turf/baseturf_bottom))
- else if(!length(baseturf_to_replace))
- baseturf_to_replace = list(baseturf_to_replace = TRUE)
- else if(baseturf_to_replace[baseturf_to_replace[1]] != TRUE) // It's not associative
- var/list/formatted = list()
- for(var/i in baseturf_to_replace)
- formatted[i] = TRUE
- baseturf_to_replace = formatted
-
- var/area/our_area = get_area(src)
- for(var/i in get_area_turfs(our_area, z))
- replace_baseturf(i)
-
- qdel(src)
-
-/obj/effect/baseturf_helper/proc/replace_baseturf(turf/thing)
- var/list/baseturf_cache = thing.baseturfs
- if(length(baseturf_cache))
- for(var/i in baseturf_cache)
- if(baseturf_to_replace[i])
- baseturf_cache -= i
- if(!baseturf_cache.len)
- thing.assemble_baseturfs(baseturf)
- else
- thing.PlaceOnBottom(null, baseturf)
- else if(baseturf_to_replace[thing.baseturfs])
- thing.assemble_baseturfs(baseturf)
- else
- thing.PlaceOnBottom(null, baseturf)
-
-/obj/effect/baseturf_helper/space
- name = "space baseturf editor"
- baseturf = /turf/open/space
-
-/obj/effect/baseturf_helper/asteroid
- name = "asteroid baseturf editor"
- baseturf = /turf/open/floor/plating/asteroid
-
-/obj/effect/baseturf_helper/asteroid/airless
- name = "asteroid airless baseturf editor"
- baseturf = /turf/open/floor/plating/asteroid/airless
-
-/obj/effect/baseturf_helper/asteroid/basalt
- name = "asteroid basalt baseturf editor"
- baseturf = /turf/open/floor/plating/asteroid/basalt
-
-/obj/effect/baseturf_helper/asteroid/snow
- name = "asteroid snow baseturf editor"
- baseturf = /turf/open/floor/plating/asteroid/snow
-
-/obj/effect/baseturf_helper/beach/sand
- name = "beach sand baseturf editor"
- baseturf = /turf/open/floor/plating/beach/sand
-
-/obj/effect/baseturf_helper/beach/water
- name = "water baseturf editor"
- baseturf = /turf/open/floor/plating/beach/water
-
-/obj/effect/baseturf_helper/lava
- name = "lava baseturf editor"
- baseturf = /turf/open/lava/smooth
-
-/obj/effect/baseturf_helper/lava_land/surface
- name = "lavaland baseturf editor"
- baseturf = /turf/open/lava/smooth/lava_land_surface
-
-
/obj/effect/mapping_helpers
icon = 'icons/effects/mapping_helpers.dmi'
icon_state = ""
@@ -94,7 +8,6 @@
..()
return late ? INITIALIZE_HINT_LATELOAD : INITIALIZE_HINT_QDEL
-
//airlock helpers
/obj/effect/mapping_helpers/airlock
layer = DOOR_HELPER_LAYER
diff --git a/code/modules/mapping/mapping_helpers/baseturf.dm b/code/modules/mapping/mapping_helpers/baseturf.dm
new file mode 100644
index 0000000000..f4bd0d7c7f
--- /dev/null
+++ b/code/modules/mapping/mapping_helpers/baseturf.dm
@@ -0,0 +1,82 @@
+/obj/effect/baseturf_helper //Set the baseturfs of every turf in the /area/ it is placed.
+ name = "baseturf editor"
+ icon = 'icons/effects/mapping_helpers.dmi'
+ icon_state = ""
+
+ var/list/baseturf_to_replace
+ var/baseturf
+
+ layer = POINT_LAYER
+
+/obj/effect/baseturf_helper/Initialize()
+ . = ..()
+ return INITIALIZE_HINT_LATELOAD
+
+/obj/effect/baseturf_helper/LateInitialize()
+ if(!baseturf_to_replace)
+ baseturf_to_replace = typecacheof(list(/turf/open/space,/turf/baseturf_bottom))
+ else if(!length(baseturf_to_replace))
+ baseturf_to_replace = list(baseturf_to_replace = TRUE)
+ else if(baseturf_to_replace[baseturf_to_replace[1]] != TRUE) // It's not associative
+ var/list/formatted = list()
+ for(var/i in baseturf_to_replace)
+ formatted[i] = TRUE
+ baseturf_to_replace = formatted
+
+ var/area/our_area = get_area(src)
+ for(var/i in get_area_turfs(our_area, z))
+ replace_baseturf(i)
+
+ qdel(src)
+
+/obj/effect/baseturf_helper/proc/replace_baseturf(turf/thing)
+ var/list/baseturf_cache = thing.baseturfs
+ if(length(baseturf_cache))
+ for(var/i in baseturf_cache)
+ if(baseturf_to_replace[i])
+ baseturf_cache -= i
+ if(!baseturf_cache.len)
+ thing.assemble_baseturfs(baseturf)
+ else
+ thing.PlaceOnBottom(null, baseturf)
+ else if(baseturf_to_replace[thing.baseturfs])
+ thing.assemble_baseturfs(baseturf)
+ else
+ thing.PlaceOnBottom(null, baseturf)
+
+/obj/effect/baseturf_helper/space
+ name = "space baseturf editor"
+ baseturf = /turf/open/space
+
+/obj/effect/baseturf_helper/asteroid
+ name = "asteroid baseturf editor"
+ baseturf = /turf/open/floor/plating/asteroid
+
+/obj/effect/baseturf_helper/asteroid/airless
+ name = "asteroid airless baseturf editor"
+ baseturf = /turf/open/floor/plating/asteroid/airless
+
+/obj/effect/baseturf_helper/asteroid/basalt
+ name = "asteroid basalt baseturf editor"
+ baseturf = /turf/open/floor/plating/asteroid/basalt
+
+/obj/effect/baseturf_helper/asteroid/snow
+ name = "asteroid snow baseturf editor"
+ baseturf = /turf/open/floor/plating/asteroid/snow
+
+/obj/effect/baseturf_helper/beach/sand
+ name = "beach sand baseturf editor"
+ baseturf = /turf/open/floor/plating/beach/sand
+
+/obj/effect/baseturf_helper/beach/water
+ name = "water baseturf editor"
+ baseturf = /turf/open/floor/plating/beach/water
+
+/obj/effect/baseturf_helper/lava
+ name = "lava baseturf editor"
+ baseturf = /turf/open/lava/smooth
+
+/obj/effect/baseturf_helper/lava_land/surface
+ name = "lavaland baseturf editor"
+ baseturf = /turf/open/lava/smooth/lava_land_surface
+
diff --git a/code/modules/mapping/mapping_helpers/network_builder/_network_builder.dm b/code/modules/mapping/mapping_helpers/network_builder/_network_builder.dm
new file mode 100644
index 0000000000..78a835cffa
--- /dev/null
+++ b/code/modules/mapping/mapping_helpers/network_builder/_network_builder.dm
@@ -0,0 +1,43 @@
+//Builds networks like power cables/atmos lines/etc
+//Just a holder parent type for now..
+/obj/effect/mapping_helpers/network_builder
+ /// set var to true to not del on lateload
+ var/custom_spawned = FALSE
+
+ icon = 'icons/effects/mapping_helpers.dmi'
+
+ late = TRUE
+ /// what directions we know connections are in
+ var/list/network_directions = list()
+
+/obj/effect/mapping_helpers/network_builder/Initialize(mapload)
+ . = ..()
+ to_chat(world, "DEBUG: Initializing [COORD(src)]")
+ var/conflict = check_duplicates()
+ if(conflict)
+ stack_trace("WARNING: [type] network building helper found check_duplicates() conflict [conflict] in its location.!")
+ return INITIALIZE_HINT_QDEL
+ if(!mapload)
+ if(GLOB.Debug2)
+ custom_spawned = TRUE
+ return INITIALIZE_HINT_NORMAL
+ else
+ return INITIALIZE_HINT_QDEL
+ return INITIALIZE_HINT_LATELOAD
+
+/// How this works: On LateInitialize, detect all directions that this should be applicable to, and do what it needs to do, and then inform all network builders in said directions that it's been around since it won't be around afterwards.
+/obj/effect/mapping_helpers/network_builder/LateInitialize()
+ to_chat(world, "DEBUG: LateInitializing [COORD(src)]")
+ scan_directions()
+ build_network()
+ if(!custom_spawned)
+ qdel(src)
+
+/obj/effect/mapping_helpers/network_builder/proc/check_duplicates()
+ CRASH("Base abstract network builder tried to check duplicates.")
+
+/obj/effect/mapping_helpers/network_builder/proc/scan_directions()
+ CRASH("Base abstract network builder tried to scan directions.")
+
+/obj/effect/mapping_helpers/network_builder/proc/build_network()
+ CRASH("Base abstract network builder tried to build network.")
diff --git a/code/modules/mapping/mapping_helpers/network_builder/atmos_pipe.dm b/code/modules/mapping/mapping_helpers/network_builder/atmos_pipe.dm
new file mode 100644
index 0000000000..1983bab3b6
--- /dev/null
+++ b/code/modules/mapping/mapping_helpers/network_builder/atmos_pipe.dm
@@ -0,0 +1,96 @@
+/* Automatically places pipes on init based on any pipes connecting to it and adjacent helpers. Only supports cardinals.
+ * Conflicts with ANY PIPE ON ITS LAYER, as well as atmos network build helpers on the same layer, as well as any pipe on all layers. Do those manually.
+*/
+/obj/effect/mapping_helpers/network_builder/atmos_pipe
+ name = "atmos pipe autobuilder"
+ icon_state = "atmospipebuilder"
+
+ /// Layer to put our pipes on
+ var/pipe_layer = PIPING_LAYER_DEFAULT
+
+ /// Color to set our pipes to
+ var/pipe_color
+
+ /// Whether or not pipes we make are visible
+ var/visible_pipes = FALSE
+
+ color = null
+
+/obj/effect/mapping_helpers/network_builder/atmos_pipe/check_duplicates()
+ for(var/obj/effect/mapping_helpers/network_builder/atmos_pipe/other in loc)
+ if(other == src)
+ continue
+ if(other.pipe_layer == pipe_layer)
+ return other
+ for(var/obj/machinery/atmospherics/A in loc)
+ if(A.pipe_flags & PIPING_ALL_LAYER)
+ return A
+ if(A.piping_layer == pipe_layer)
+ return A
+ return FALSE
+
+/// Scans directions, sets network_directions to have every direction that we can link to. If there's another power cable builder detected, make sure they know we're here by adding us to their cable directions list before we're deleted.
+/obj/effect/mapping_helpers/network_builder/atmos_pipe/scan_directions()
+ var/turf/T
+ for(var/i in GLOB.cardinals)
+ if(i in network_directions)
+ continue //we're already set, that means another builder set us.
+ T = get_step(loc, i)
+ if(!T)
+ continue
+ var/found = FALSE
+ for(var/obj/effect/mapping_helpers/network_builder/atmos_pipe/other in T)
+ if(other.pipe_layer == pipe_layer)
+ network_directions += i
+ other.network_directions += turn(i, 180)
+ found = TRUE
+ break
+ if(found)
+ continue
+ for(var/obj/machinery/atmospherics/A in T)
+ if((A.piping_layer == pipe_layer) && (A.initialize_directions & turn(i, 180)))
+ network_directions += i
+ break
+ return network_directions
+
+/// Directions should only ever have cardinals.
+/obj/effect/mapping_helpers/network_builder/atmos_pipe/build_network()
+ if(length(network_directions) <= 1)
+ return
+ var/obj/machinery/atmospherics/pipe/built
+ switch(length(network_directions))
+ if(2) //straight pipe
+ built = new /obj/machinery/atmospherics/pipe/simple(loc)
+ var/d1 = network_directions[1]
+ var/d2 = network_directions[2]
+ var/combined = d1 | d2
+ if(combined in GLOB.diagonals)
+ built.setDir(combined)
+ else
+ built.setDir(d1)
+ if(3) //manifold
+ var/list/missing = network_directions ^ GLOB.cardinals
+ missing = missing[1]
+ built = new /obj/machinery/atmospherics/pipe/manifold(loc)
+ built.setDir(missing)
+ if(4) //4 way manifold
+ built = new /obj/machinery/atmospherics/pipe/manifold4w(loc)
+ built.SetInitDirections()
+ built.on_construction(pipe_color, pipe_layer)
+ built.hide(!visible_pipes)
+
+/obj/effect/mapping_helpers/network_builder/atmos_pipe/distro
+ name = "distro line autobuilder"
+ pipe_layer = PIPING_LAYER_MIN
+ pixel_x = -PIPING_LAYER_P_X
+ pixel_y = -PIPING_LAYER_P_Y
+ pipe_color = rgb(130,43,255)
+ color = rgb(130,43,255)
+
+/obj/effect/mapping_helpers/network_builder/atmos_pipe/scrubbers
+ name = "scrubbers line autobuilder"
+ pipe_layer = PIPING_LAYER_MAX
+ pixel_x = PIPING_LAYER_P_X
+ pixel_y = PIPING_LAYER_P_Y
+ pipe_color = rgb(255,0,0)
+ color = rgb(255,0,0)
diff --git a/code/modules/mapping/mapping_helpers/network_builder/power_cables.dm b/code/modules/mapping/mapping_helpers/network_builder/power_cables.dm
new file mode 100644
index 0000000000..5385045618
--- /dev/null
+++ b/code/modules/mapping/mapping_helpers/network_builder/power_cables.dm
@@ -0,0 +1,189 @@
+#define NO_KNOT 0
+#define KNOT_AUTO 1
+#define KNOT_FORCED 2
+
+/// Automatically links on init to power cables and other cable builder helpers. Only supports cardinals.
+/obj/effect/mapping_helpers/network_builder/power_cable
+ name = "power line autobuilder"
+ icon_state = "powerlinebuilder"
+
+ color = "#ff0000"
+
+ /// Whether or not we forcefully make a knot
+ var/knot = NO_KNOT
+
+ /// cable color as from GLOB.cable_colors
+ var/cable_color = "red"
+
+/obj/effect/mapping_helpers/network_builder/power_cable/check_duplicates()
+ var/obj/structure/cable/C = locate() in loc
+ if(C)
+ return C
+ for(var/obj/effect/mapping_helpers/network_builder/power_cable/other in loc)
+ if(other == src)
+ continue
+ return other
+
+/// Scans directions, sets network_directions to have every direction that we can link to. If there's another power cable builder detected, make sure they know we're here by adding us to their cable directions list before we're deleted.
+/obj/effect/mapping_helpers/network_builder/power_cable/scan_directions()
+ var/turf/T
+ for(var/i in GLOB.cardinals)
+ if(i in network_directions)
+ continue //we're already set, that means another builder set us.
+ T = get_step(loc, i)
+ if(!T)
+ continue
+ var/obj/effect/mapping_helpers/network_builder/power_cable/other = locate() in T
+ if(other)
+ network_directions += i
+ other.network_directions += turn(i, 180)
+ continue
+ for(var/obj/structure/cable/C in T)
+ if(C.d1 == turn(i, 180) || C.d2 == turn(i, 180))
+ network_directions += i
+ continue
+ return network_directions
+
+/// Directions should only ever have cardinals.
+/obj/effect/mapping_helpers/network_builder/power_cable/build_network()
+ if(!length(network_directions))
+ return
+ else if(length(network_directions) == 1)
+ new /obj/structure/cable(loc, cable_color, NONE, network_directions[1])
+ else
+ if(knot == KNOT_FORCED)
+ for(var/d in network_directions)
+ new /obj/structure/cable(loc, cable_color, NONE, d)
+ else
+ var/do_knot = (knot == KNOT_FORCED) || ((knot == KNOT_AUTO) && should_auto_knot())
+ var/dirs = length(network_directions)
+ for(var/i in 1 to dirs - 1)
+ var/li = (i == 1)? dirs : (i - 1)
+ var/d1 = network_directions[i]
+ var/d2 = network_directions[li]
+ if(d1 > d2) //this is ugly please help me
+ d1 = network_directions[li]
+ d2 = network_directions[i]
+ new /obj/structure/cable(loc, cable_color, d1, d2)
+ if(do_knot)
+ new /obj/structure/cable(loc, cable_color, NONE, network_directions[i])
+ do_knot = FALSE
+
+/obj/effect/mapping_helpers/network_builder/power_cable/proc/should_auto_knot()
+ return (locate(/obj/machinery/power/terminal) in loc)
+
+/obj/effect/mapping_helpers/network_builder/power_cable/knot
+ icon_state = "powerlinebuilderknot"
+ knot = KNOT_FORCED
+
+/obj/effect/mapping_helpers/network_builder/power_cable/auto
+ icon_state = "powerlinebuilderauto"
+ knot = KNOT_AUTO
+
+// Red
+/obj/effect/mapping_helpers/network_builder/power_cable/red
+ color = "#ff0000"
+ cable_color = "red"
+
+/obj/effect/mapping_helpers/network_builder/power_cable/red/knot
+ icon_state = "powerlinebuilderknot"
+ knot = KNOT_FORCED
+
+/obj/effect/mapping_helpers/network_builder/power_cable/red/auto
+ icon_state = "powerlinebuilderauto"
+ knot = KNOT_AUTO
+
+// White
+/obj/effect/mapping_helpers/network_builder/power_cable/white
+ color = "#ffffff"
+ cable_color = "white"
+
+/obj/effect/mapping_helpers/network_builder/power_cable/white/knot
+ icon_state = "powerlinebuilderknot"
+ knot = KNOT_FORCED
+
+/obj/effect/mapping_helpers/network_builder/power_cable/white/auto
+ icon_state = "powerlinebuilderauto"
+ knot = KNOT_AUTO
+
+// Cyan
+/obj/effect/mapping_helpers/network_builder/power_cable/cyan
+ color = "#00ffff"
+ cable_color = "cyan"
+
+/obj/effect/mapping_helpers/network_builder/power_cable/cyan/knot
+ icon_state = "powerlinebuilderknot"
+ knot = KNOT_FORCED
+
+/obj/effect/mapping_helpers/network_builder/power_cable/cyan/auto
+ icon_state = "powerlinebuilderauto"
+ knot = KNOT_AUTO
+
+// Orange
+/obj/effect/mapping_helpers/network_builder/power_cable/orange
+ color = "#ff8000"
+ cable_color = "orange"
+
+/obj/effect/mapping_helpers/network_builder/power_cable/orange/knot
+ icon_state = "powerlinebuilderknot"
+ knot = KNOT_FORCED
+
+/obj/effect/mapping_helpers/network_builder/power_cable/orange/auto
+ icon_state = "powerlinebuilderauto"
+ knot = KNOT_AUTO
+
+// Pink
+/obj/effect/mapping_helpers/network_builder/power_cable/pink
+ color = "#ff3cc8"
+ cable_color = "pink"
+
+/obj/effect/mapping_helpers/network_builder/power_cable/pink/knot
+ icon_state = "powerlinebuilderknot"
+ knot = KNOT_FORCED
+
+/obj/effect/mapping_helpers/network_builder/power_cable/pink/auto
+ icon_state = "powerlinebuilderauto"
+ knot = KNOT_AUTO
+
+// Blue
+/obj/effect/mapping_helpers/network_builder/power_cable/blue
+ color = "#1919c8"
+ cable_color = "blue"
+
+/obj/effect/mapping_helpers/network_builder/power_cable/blue/knot
+ icon_state = "powerlinebuilderknot"
+ knot = KNOT_FORCED
+
+/obj/effect/mapping_helpers/network_builder/power_cable/blue/auto
+ icon_state = "powerlinebuilderauto"
+ knot = KNOT_AUTO
+
+// Green
+/obj/effect/mapping_helpers/network_builder/power_cable/green
+ color = "#00aa00"
+ cable_color = "green"
+
+/obj/effect/mapping_helpers/network_builder/power_cable/green/knot
+ icon_state = "powerlinebuilderknot"
+ knot = KNOT_FORCED
+
+/obj/effect/mapping_helpers/network_builder/power_cable/green/auto
+ icon_state = "powerlinebuilderauto"
+ knot = KNOT_AUTO
+
+// Yellow
+/obj/effect/mapping_helpers/network_builder/power_cable/yellow
+ color = "#ffff00"
+ cable_color = "yellow"
+
+/obj/effect/mapping_helpers/network_builder/power_cable/yellow/knot
+ icon_state = "powerlinebuilderknot"
+ knot = KNOT_FORCED
+
+/obj/effect/mapping_helpers/network_builder/power_cable/yellow/auto
+ icon_state = "powerlinebuilderauto"
+ knot = KNOT_AUTO
+
+#undef NO_KNOT
+#undef KNOT_AUTO
+#undef KNOT_FORCED
diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm
index 29a835ddde..1c83c70d95 100644
--- a/code/modules/mining/ores_coins.dm
+++ b/code/modules/mining/ores_coins.dm
@@ -250,7 +250,7 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
/obj/item/twohanded/required/gibtonite/bullet_act(obj/item/projectile/P)
GibtoniteReaction(P.firer)
- ..()
+ return ..()
/obj/item/twohanded/required/gibtonite/ex_act()
GibtoniteReaction(null, 1)
diff --git a/code/modules/mob/living/bloodcrawl.dm b/code/modules/mob/living/bloodcrawl.dm
index 4ed539adc2..e8a9b50e98 100644
--- a/code/modules/mob/living/bloodcrawl.dm
+++ b/code/modules/mob/living/bloodcrawl.dm
@@ -14,7 +14,7 @@
/obj/effect/dummy/phased_mob/slaughter/ex_act()
return
/obj/effect/dummy/phased_mob/slaughter/bullet_act()
- return
+ return BULLET_ACT_FORCE_PIERCE
/obj/effect/dummy/phased_mob/slaughter/singularity_act()
return
diff --git a/code/modules/mob/living/carbon/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm
index d893108bcd..5bffc4e276 100644
--- a/code/modules/mob/living/carbon/damage_procs.dm
+++ b/code/modules/mob/living/carbon/damage_procs.dm
@@ -41,9 +41,6 @@
update_damage_overlays()
else
adjustStaminaLoss(damage_amount, forced = forced)
- //citadel code
- if(AROUSAL)
- adjustArousalLoss(damage_amount)
return TRUE
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index c5d3ec18f9..2fc4cd8805 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -51,7 +51,7 @@
if(prob(mind.martial_art.dodge_chance))
var/dodgemessage = pick("dodges under the projectile!","dodges to the right of the projectile!","jumps over the projectile!")
visible_message("[src] [dodgemessage]", "You dodge the projectile!")
- return -1
+ return BULLET_ACT_BLOCK
if(mind.martial_art && !incapacitated(FALSE, TRUE) && mind.martial_art.can_use(src) && mind.martial_art.deflection_chance) //Some martial arts users can deflect projectiles!
if(prob(mind.martial_art.deflection_chance))
if(!lying && dna && !dna.check_mutation(HULK)) //But only if they're not lying down, and hulks can't do it
@@ -60,12 +60,10 @@
else
visible_message("[src] deflects the projectile!", "You deflect the projectile!")
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1)
- if(!mind.martial_art.reroute_deflection)
- return FALSE
- else
+ if(mind.martial_art.reroute_deflection)
P.firer = src
P.setAngle(rand(0, 360))//SHING
- return FALSE
+ return BULLET_ACT_FORCE_PIERCE
return ..()
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 821a3472e4..7507067597 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -39,10 +39,6 @@
//Stuff jammed in your limbs hurts
handle_embedded_objects()
- if(stat != DEAD)
- //process your dick energy
- handle_arousal(times_fired)
-
//Update our name based on whether our face is obscured/disfigured
name = get_visible_name()
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 5b8173b6ba..3357cc9ffe 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -323,12 +323,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
for(var/datum/disease/A in C.diseases)
A.cure(FALSE)
-//CITADEL EDIT
- if(NOAROUSAL in species_traits)
- C.canbearoused = FALSE
- else
- if(C.client)
- C.canbearoused = C.client.prefs.arousable
if(ishuman(C))
var/mob/living/carbon/human/H = C
if(NOGENITALS in H.dna.species.species_traits)
@@ -1586,10 +1580,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
"You slap [user == target ? "yourself" : "\the [target]"] in the face! ",\
"You hear a slap."
)
- if (!HAS_TRAIT(target, TRAIT_NYMPHO))
- stop_wagging_tail(target)
user.do_attack_animation(target, ATTACK_EFFECT_FACE_SLAP)
user.adjustStaminaLossBuffered(3)
+ if (!HAS_TRAIT(target, TRAIT_PERMABONER))
+ stop_wagging_tail(target)
return FALSE
else if(aim_for_groin && (target == user || target.lying || same_dir) && (target_on_help || target_restrained || target_aiming_for_groin))
if(target.client?.prefs.cit_toggles & NO_ASS_SLAP)
@@ -1597,19 +1591,17 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
return FALSE
user.do_attack_animation(target, ATTACK_EFFECT_ASS_SLAP)
user.adjustStaminaLossBuffered(3)
+ target.adjust_arousal(20,maso = TRUE)
+ if (ishuman(target) && HAS_TRAIT(target, TRAIT_MASO) && target.has_dna() && prob(10))
+ target.mob_climax(forced_climax=TRUE)
+ if (!HAS_TRAIT(target, TRAIT_PERMABONER))
+ stop_wagging_tail(target)
playsound(target.loc, 'sound/weapons/slap.ogg', 50, 1, -1)
user.visible_message(\
"\The [user] slaps \the [target]'s ass!",\
"You slap [user == target ? "your" : "\the [target]'s"] ass!",\
"You hear a slap."
- )
- if (target.canbearoused)
- target.adjustArousalLoss(5)
- if (target.getArousalLoss() >= 100 && ishuman(target) && HAS_TRAIT(target, TRAIT_MASO) && target.has_dna())
- target.mob_climax(forced_climax=TRUE)
- if (!HAS_TRAIT(target, TRAIT_NYMPHO))
- stop_wagging_tail(target)
-
+ )
return FALSE
else if(attacker_style && attacker_style.disarm_act(user,target))
return 1
@@ -1962,10 +1954,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(BP)
if(damage > 0 ? BP.receive_damage(damage_amount, 0) : BP.heal_damage(abs(damage_amount), 0))
H.update_damage_overlays()
- if(HAS_TRAIT(H, TRAIT_MASO))
- H.adjustArousalLoss(damage_amount, 0)
- if (H.getArousalLoss() >= 100 && ishuman(H) && H.has_dna())
- H.mob_climax(forced_climax=TRUE)
+ if(HAS_TRAIT(H, TRAIT_MASO) && prob(damage_amount))
+ H.mob_climax(forced_climax=TRUE)
else//no bodypart, we deal damage with a more general method.
H.adjustBruteLoss(damage_amount)
@@ -1996,8 +1986,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(BRAIN)
var/damage_amount = forced ? damage : damage * hit_percent * H.physiology.brain_mod
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, damage_amount)
- if(AROUSAL) //Citadel edit - arousal
- H.adjustArousalLoss(damage * hit_percent)
return 1
/datum/species/proc/on_hit(obj/item/projectile/P, mob/living/carbon/human/H)
@@ -2010,7 +1998,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
/datum/species/proc/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H)
// called before a projectile hit
- return 0
+ return
/////////////
//BREATHING//
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index 3dad8449df..98c3f269dc 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -360,8 +360,8 @@
playsound(H, 'sound/effects/shovel_dig.ogg', 70, 1)
H.visible_message("The [P.name] sinks harmlessly in [H]'s sandy body!", \
"The [P.name] sinks harmlessly in [H]'s sandy body!")
- return 2
- return 0
+ return BULLET_ACT_BLOCK
+ return ..()
//Reflects lasers and resistant to burn damage, but very vulnerable to brute damage. Shatters on death.
/datum/species/golem/glass
@@ -397,8 +397,8 @@
var/turf/target = get_turf(P.starting)
// redirect the projectile
P.preparePixelProjectile(locate(CLAMP(target.x + new_x, 1, world.maxx), CLAMP(target.y + new_y, 1, world.maxy), H.z), H)
- return -1
- return 0
+ return BULLET_ACT_FORCE_PIERCE
+ return ..()
//Teleports when hit or when it wants to
/datum/species/golem/bluespace
diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
index fa2fd1c858..a0291631dc 100644
--- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
@@ -60,8 +60,8 @@
if(light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD)
H.visible_message("[H] dances in the shadows, evading [P]!")
playsound(T, "bullet_miss", 75, 1)
- return -1
- return 0
+ return BULLET_ACT_FORCE_PIERCE
+ return ..()
/datum/species/shadow/nightmare/check_roundstart_eligible()
return FALSE
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 61e68b50ec..ea9e6be78b 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -516,7 +516,6 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
if(bufferedstam && world.time > stambufferregentime)
var/drainrate = max((bufferedstam*(bufferedstam/(5)))*0.1,1)
bufferedstam = max(bufferedstam - drainrate, 0)
- adjustStaminaLoss(drainrate*0.5)
//END OF CIT CHANGES
var/restingpwr = 1 + 4 * resting
diff --git a/code/modules/mob/living/carbon/monkey/combat.dm b/code/modules/mob/living/carbon/monkey/combat.dm
index 56ef4fe24a..6eb4868202 100644
--- a/code/modules/mob/living/carbon/monkey/combat.dm
+++ b/code/modules/mob/living/carbon/monkey/combat.dm
@@ -403,7 +403,7 @@
if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
if(!Proj.nodamage && Proj.damage < src.health && isliving(Proj.firer))
retaliate(Proj.firer)
- ..()
+ return ..()
/mob/living/carbon/monkey/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE)
if(istype(AM, /obj/item))
diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm
index 45d9c80a35..abcb0589ae 100644
--- a/code/modules/mob/living/damage_procs.dm
+++ b/code/modules/mob/living/damage_procs.dm
@@ -110,7 +110,7 @@
/mob/living/proc/apply_effects(stun = 0, knockdown = 0, unconscious = 0, irradiate = 0, slur = 0, stutter = 0, eyeblur = 0, drowsy = 0, blocked = FALSE, stamina = 0, jitter = 0, kd_stamoverride, kd_stammax)
if(blocked >= 100)
- return 0
+ return BULLET_ACT_BLOCK
if(stun)
apply_effect(stun, EFFECT_STUN, blocked)
if(knockdown)
@@ -131,7 +131,7 @@
apply_damage(stamina, STAMINA, null, blocked)
if(jitter)
apply_effect(jitter, EFFECT_JITTER, blocked)
- return 1
+ return BULLET_ACT_HIT
/mob/living/proc/getBruteLoss()
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 4c67922c18..fbb483fadb 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -34,7 +34,7 @@
return FALSE
/mob/living/proc/on_hit(obj/item/projectile/P)
- return
+ return BULLET_ACT_HIT
/mob/living/proc/check_shields(atom/AM, damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0)
var/block_chance_modifier = round(damage / -3)
@@ -76,16 +76,16 @@
/mob/living/bullet_act(obj/item/projectile/P, def_zone)
if(P.original != src || P.firer != src) //try to block or reflect the bullet, can't do so when shooting oneself
if(reflect_bullet_check(P, def_zone))
- return -1 // complete projectile permutation
+ return BULLET_ACT_FORCE_PIERCE // complete projectile permutation
if(check_shields(P, P.damage, "the [P.name]", PROJECTILE_ATTACK, P.armour_penetration))
P.on_hit(src, 100, def_zone)
- return 2
+ return BULLET_ACT_BLOCK
var/armor = run_armor_check(def_zone, P.flag, null, null, P.armour_penetration, null)
if(!P.nodamage)
apply_damage(P.damage, P.damage_type, def_zone, armor)
if(P.dismemberment)
check_projectile_dismemberment(P, def_zone)
- return P.on_hit(src, armor)
+ return P.on_hit(src, armor) ? BULLET_ACT_HIT : BULLET_ACT_BLOCK
/mob/living/proc/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
return 0
diff --git a/code/modules/mob/living/living_movement.dm b/code/modules/mob/living/living_movement.dm
index 93bb9d1f8d..e0ea6350d7 100644
--- a/code/modules/mob/living/living_movement.dm
+++ b/code/modules/mob/living/living_movement.dm
@@ -2,6 +2,21 @@
. = ..()
update_turf_movespeed(loc)
+/mob/living/CanPass(atom/movable/mover, turf/target)
+ if((mover.pass_flags & PASSMOB))
+ return TRUE
+ if(istype(mover, /obj/item/projectile))
+ var/obj/item/projectile/P = mover
+ return !P.can_hit_target(src, P.permutated, src == P.original, TRUE)
+ if(mover.throwing)
+ return (!density || lying)
+ if(buckled == mover)
+ return TRUE
+ if(ismob(mover))
+ if (mover in buckled_mobs)
+ return TRUE
+ return (!mover.density || !density || lying || (mover.throwing && mover.throwing.thrower == src && !ismob(mover)))
+
/mob/living/toggle_move_intent()
. = ..()
update_move_intent_slowdown()
diff --git a/code/modules/mob/living/silicon/ai/ai_defense.dm b/code/modules/mob/living/silicon/ai/ai_defense.dm
index 97d26f672a..2bcb3c9b5a 100644
--- a/code/modules/mob/living/silicon/ai/ai_defense.dm
+++ b/code/modules/mob/living/silicon/ai/ai_defense.dm
@@ -42,9 +42,8 @@
/mob/living/silicon/ai/bullet_act(obj/item/projectile/Proj)
- ..(Proj)
+ . = ..()
updatehealth()
- return 2
/mob/living/silicon/ai/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0)
return // no eyes, no flashing
diff --git a/code/modules/mob/living/silicon/pai/pai_defense.dm b/code/modules/mob/living/silicon/pai/pai_defense.dm
index c727e100d8..05b2bc77ba 100644
--- a/code/modules/mob/living/silicon/pai/pai_defense.dm
+++ b/code/modules/mob/living/silicon/pai/pai_defense.dm
@@ -55,7 +55,7 @@
if(P.stun)
fold_in(force = TRUE)
visible_message("The electrically-charged projectile disrupts [src]'s holomatrix, forcing [src] to fold in!")
- . = ..()
+ return ..()
/mob/living/silicon/pai/stripPanelUnequip(obj/item/what, mob/who, where) //prevents stripping
to_chat(src, "Your holochassis stutters and warps intensely as you attempt to interact with the object, forcing you to cease lest the field fail.")
diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm
index 7e06c66eff..e7b252a248 100644
--- a/code/modules/mob/living/silicon/robot/robot_defense.dm
+++ b/code/modules/mob/living/silicon/robot/robot_defense.dm
@@ -184,8 +184,7 @@
adjustBruteLoss(30)
/mob/living/silicon/robot/bullet_act(obj/item/projectile/P, def_zone)
- ..()
+ . = ..()
updatehealth()
if(prob(75) && P.damage > 0)
spark_system.start()
- return 2
diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm
index ca8ad25713..4cd8dd47e4 100644
--- a/code/modules/mob/living/silicon/silicon_defense.dm
+++ b/code/modules/mob/living/silicon/silicon_defense.dm
@@ -129,7 +129,7 @@
unbuckle_mob(M)
M.visible_message("[M] is knocked off of [src] by the [P]!")
P.on_hit(src)
- return 2
+ return BULLET_ACT_HIT
/mob/living/silicon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash/static)
if(affect_silicon)
diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm
index ad8dfc4900..f4feab8824 100644
--- a/code/modules/mob/living/simple_animal/animal_defense.dm
+++ b/code/modules/mob/living/simple_animal/animal_defense.dm
@@ -114,7 +114,7 @@
return
apply_damage(Proj.damage, Proj.damage_type)
Proj.on_hit(src)
- return 0
+ return BULLET_ACT_HIT
/mob/living/simple_animal/ex_act(severity, target, origin)
if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src))
diff --git a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm
index 03afecc66f..a5d36b5ba9 100644
--- a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm
+++ b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm
@@ -21,7 +21,7 @@
/mob/living/simple_animal/bot/secbot/grievous/bullet_act(obj/item/projectile/P)
visible_message("[src] deflects [P] with its energy swords!")
playsound(src, 'sound/weapons/blade1.ogg', 50, TRUE)
- return FALSE
+ return BULLET_ACT_BLOCK
/mob/living/simple_animal/bot/secbot/grievous/Crossed(atom/movable/AM)
..()
diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
index 6d1c844231..f77f3b7d1a 100644
--- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
@@ -210,7 +210,7 @@ Auto Patrol[]"},
if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
if(!Proj.nodamage && Proj.damage < src.health && ishuman(Proj.firer))
retaliate(Proj.firer)
- ..()
+ return ..()
/mob/living/simple_animal/bot/ed209/handle_automated_action()
if(!..())
@@ -510,11 +510,9 @@ Auto Patrol[]"},
spawn(100)
disabled = 0
icon_state = "[lasercolor]ed2091"
- return 1
- else
- ..(Proj)
- else
- ..(Proj)
+ return BULLET_ACT_HIT
+ return ..()
+ return ..()
/mob/living/simple_animal/bot/ed209/bluetag
lasercolor = "b"
diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm
index 3fcbff26db..5b9915d1bf 100644
--- a/code/modules/mob/living/simple_animal/bot/honkbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm
@@ -139,7 +139,7 @@ Maintenance panel panel is [open ? "opened" : "closed"]"},
/mob/living/simple_animal/bot/honkbot/bullet_act(obj/item/projectile/Proj)
if((istype(Proj,/obj/item/projectile/beam)) || (istype(Proj,/obj/item/projectile/bullet) && (Proj.damage_type == BURN))||(Proj.damage_type == BRUTE) && (!Proj.nodamage && Proj.damage < health && ishuman(Proj.firer)))
retaliate(Proj.firer)
- ..()
+ return ..()
/mob/living/simple_animal/bot/honkbot/UnarmedAttack(atom/A)
if(!on)
diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
index 911758a5ed..714046aa8e 100644
--- a/code/modules/mob/living/simple_animal/bot/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -152,7 +152,7 @@
/mob/living/simple_animal/bot/mulebot/bullet_act(obj/item/projectile/Proj)
. = ..()
- if(. && !QDELETED(src)) //Got hit and not blown up yet.
+ if(. == BULLET_ACT_HIT && !QDELETED(src)) //Got hit and not blown up yet.)
if(prob(50) && !isnull(load))
unload(0)
if(prob(25))
diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
index ea1bbdbaa8..3186b4602c 100644
--- a/code/modules/mob/living/simple_animal/bot/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -205,7 +205,7 @@ Auto Patrol: []"},
if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
if(!Proj.nodamage && Proj.damage < src.health && ishuman(Proj.firer))
retaliate(Proj.firer)
- ..()
+ return ..()
/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A)
diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm
index 736524496f..ed9c94a534 100644
--- a/code/modules/mob/living/simple_animal/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs.dm
@@ -167,9 +167,9 @@
new_angle_s -= 360
P.setAngle(new_angle_s)
- return -1 // complete projectile permutation
+ return BULLET_ACT_FORCE_PIERCE // complete projectile permutation
- return (..(P))
+ return ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index c2c9f5a71f..1ad07b3203 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -117,7 +117,7 @@ Difficulty: Very Hard
var/random_y = rand(0, 72)
AT.pixel_y += random_y
- ..()
+ return ..()
/mob/living/simple_animal/hostile/megafauna/colossus/proc/enrage(mob/living/L)
if(ishuman(L))
@@ -395,7 +395,7 @@ Difficulty: Very Hard
..()
/obj/machinery/anomalous_crystal/bullet_act(obj/item/projectile/P, def_zone)
- ..()
+ . = ..()
if(istype(P, /obj/item/projectile/magic))
ActivationReaction(P.firer, ACTIVATE_MAGIC, P.damage_type)
return
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm
index 51919dad24..e4046138cd 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm
@@ -98,7 +98,7 @@ IGNORE_PROC_IF_NOT_TARGET(attack_slime)
/mob/living/simple_animal/hostile/asteroid/curseblob/bullet_act(obj/item/projectile/Proj)
if(Proj.firer != set_target)
- return
+ return BULLET_ACT_FORCE_PIERCE
return ..()
/mob/living/simple_animal/hostile/asteroid/curseblob/attacked_by(obj/item/I, mob/living/L)
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm
index a2b342ab1b..c02f0c46c7 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm
@@ -75,7 +75,7 @@
/mob/living/simple_animal/hostile/asteroid/goldgrub/bullet_act(obj/item/projectile/P)
visible_message("The [P.name] was repelled by [name]'s girth!")
- return
+ return BULLET_ACT_BLOCK
/mob/living/simple_animal/hostile/asteroid/goldgrub/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
vision_range = 9
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm
index 03d2365016..f40e1c0093 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm
@@ -43,7 +43,7 @@
if(P.damage < 30 && P.damage_type != BRUTE)
P.damage = (P.damage / 3)
visible_message("[P] has a reduced effect on [src]!")
- ..()
+ return ..()
/mob/living/simple_animal/hostile/asteroid/hitby(atom/movable/AM)//No floor tiling them to death, wiseguy
if(istype(AM, /obj/item))
diff --git a/code/modules/mob/living/simple_animal/hostile/mushroom.dm b/code/modules/mob/living/simple_animal/hostile/mushroom.dm
index 8727652103..991baee7d8 100644
--- a/code/modules/mob/living/simple_animal/hostile/mushroom.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mushroom.dm
@@ -179,9 +179,10 @@
if(T.throwforce)
Bruise()
-/mob/living/simple_animal/hostile/mushroom/bullet_act()
- ..()
- Bruise()
+/mob/living/simple_animal/hostile/mushroom/bullet_act(obj/item/projectile/P)
+ . = ..()
+ if(!P.nodamage)
+ Bruise()
/mob/living/simple_animal/hostile/mushroom/harvest()
var/counter
diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
index 0faee34f85..96a75f6b4f 100644
--- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm
+++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
@@ -128,13 +128,10 @@
return ..()
/mob/living/simple_animal/hostile/syndicate/melee/bullet_act(obj/item/projectile/Proj)
- if(!Proj)
- return
if(prob(25))
return ..()
- else
- visible_message("[src] blocks [Proj] with its shield!")
- return 0
+ visible_message("[src] blocks [Proj] with its shield!")
+ return BULLET_ACT_BLOCK
/mob/living/simple_animal/hostile/syndicate/melee/sword/space
icon_state = "syndicate_space_sword"
diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm
index 68d08aabd2..f6b29b95aa 100644
--- a/code/modules/mob/living/simple_animal/parrot.dm
+++ b/code/modules/mob/living/simple_animal/parrot.dm
@@ -337,7 +337,7 @@
//Bullets
/mob/living/simple_animal/parrot/bullet_act(obj/item/projectile/Proj)
- ..()
+ . = ..()
if(!stat && !client)
if(parrot_state == PARROT_PERCH)
parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched
@@ -347,7 +347,6 @@
//parrot_been_shot += 5
icon_state = icon_living
drop_held_item(0)
- return
/*
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index 107a6eed38..63d776d6e4 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -220,15 +220,12 @@
return ..() //Heals them
/mob/living/simple_animal/slime/bullet_act(obj/item/projectile/Proj)
- if(!Proj)
- return
attacked += 10
if((Proj.damage_type == BURN))
adjustBruteLoss(-abs(Proj.damage)) //fire projectiles heals slimes.
Proj.on_hit(src)
- else
- ..(Proj)
- return 0
+ return BULLET_ACT_BLOCK
+ return ..()
/mob/living/simple_animal/slime/emp_act(severity)
. = ..()
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index acb55e143a..3893f690e2 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -508,6 +508,10 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0)
usr << browse(text("[][]", name, replacetext(flavor_text, "\n", "
")), text("window=[];size=500x200", name))
onclose(usr, "[name]")
+ if(href_list["flavor2_more"])
+ usr << browse(text("[][]", name, replacetext(flavor_text_2, "\n", "
")), text("window=[];size=500x200", name))
+ onclose(usr, "[name]")
+
if(href_list["flavor_change"])
update_flavor_text()
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index f61d65146e..41aaaac1c9 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -1,15 +1,3 @@
-/mob/CanPass(atom/movable/mover, turf/target)
- if((mover.pass_flags & PASSMOB))
- return TRUE
- if(istype(mover, /obj/item/projectile) || mover.throwing)
- return (!density || lying)
- if(buckled == mover)
- return TRUE
- if(ismob(mover))
- if (mover in buckled_mobs)
- return TRUE
- return (!mover.density || !density || lying || (mover.throwing && mover.throwing.thrower == src && !ismob(mover)))
-
//DO NOT USE THIS UNLESS YOU ABSOLUTELY HAVE TO. THIS IS BEING PHASED OUT FOR THE MOVESPEED MODIFICATION SYSTEM.
//See mob_movespeed.dm
/mob/proc/movement_delay() //update /living/movement_delay() if you change this
diff --git a/code/modules/mob/say_vr.dm b/code/modules/mob/say_vr.dm
index a387dcb1d2..a130152b4c 100644
--- a/code/modules/mob/say_vr.dm
+++ b/code/modules/mob/say_vr.dm
@@ -51,7 +51,7 @@
if(length(msg) <= 40)
return "[html_encode(msg)]"
else
- return "[html_encode(copytext(msg, 1, 37))]... More..."
+ return "[html_encode(copytext(msg, 1, 37))]... More..."
/mob/proc/get_top_level_mob()
diff --git a/code/modules/modular_computers/computers/machinery/modular_computer.dm b/code/modules/modular_computers/computers/machinery/modular_computer.dm
index a988003b67..39b2c45d99 100644
--- a/code/modules/modular_computers/computers/machinery/modular_computer.dm
+++ b/code/modules/modular_computers/computers/machinery/modular_computer.dm
@@ -158,4 +158,5 @@
// "Brute" damage mostly damages the casing.
/obj/machinery/modular_computer/bullet_act(obj/item/projectile/Proj)
if(cpu)
- cpu.bullet_act(Proj)
+ return cpu.bullet_act(Proj)
+ return ..()
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index c7e82a94c2..ca5e4ed53a 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -98,6 +98,7 @@
var/force_update = 0
var/emergency_lights = FALSE
var/nightshift_lights = FALSE
+ var/nightshift_requires_auth = FALSE
var/last_nightshift_switch = 0
var/update_state = -1
var/update_overlay = -1
@@ -241,6 +242,7 @@
update_icon()
make_terminal()
+ update_nightshift_auth_requirement()
addtimer(CALLBACK(src, .proc/update), 5)
@@ -862,6 +864,7 @@
/obj/machinery/power/apc/ui_data(mob/user)
var/list/data = list(
"locked" = locked && !(integration_cog && is_servant_of_ratvar(user)) && !hasSiliconAccessInArea(user,area),
+ "lock_nightshift" = nightshift_requires_auth,
"failTime" = failure_timer,
"isOperating" = operating,
"externalPower" = main_status,
@@ -973,10 +976,21 @@
. = UI_INTERACTIVE
/obj/machinery/power/apc/ui_act(action, params)
- if (action == "hijack" && can_use(usr, 1))
+ if(..() || !can_use(usr, 1))
+ return
+ if(failure_timer)
+ if(action == "reboot")
+ failure_timer = 0
+ update_icon()
+ update()
+ if (action == "hijack" && can_use(usr, 1)) //don't need auth for hijack button
hijack(usr)
return
- if(..() || !can_use(usr, 1) || (locked && !hasSiliconAccessInArea(usr,area) && !usr.has_unlimited_silicon_privilege && !failure_timer && !(integration_cog && (is_servant_of_ratvar(usr)))))
+ var/authorized = (!locked || usr.has_unlimited_silicon_privilege || hasSiliconAccessInArea(usr,area) || (integration_cog && (is_servant_of_ratvar(usr))))
+ if((action == "toggle_nightshift") && (!nightshift_requires_auth || authorized))
+ toggle_nightshift_lights()
+ return TRUE
+ if(!authorized)
return
switch(action)
if("lock")
@@ -986,22 +1000,19 @@
else
locked = !locked
update_icon()
- . = TRUE
+ return TRUE
if("cover")
coverlocked = !coverlocked
- . = TRUE
+ return TRUE
if("breaker")
toggle_breaker()
- . = TRUE
- if("toggle_nightshift")
- toggle_nightshift_lights()
- . = TRUE
+ return TRUE
if("charge")
chargemode = !chargemode
if(!chargemode)
charging = APC_NOT_CHARGING
update_icon()
- . = TRUE
+ return TRUE
if("channel")
if(params["eqp"])
equipment = setsubsystem(text2num(params["eqp"]))
@@ -1015,24 +1026,23 @@
environ = setsubsystem(text2num(params["env"]))
update_icon()
update()
- . = TRUE
+ return TRUE
if("overload")
if(usr.has_unlimited_silicon_privilege || hasSiliconAccessInArea(usr,area))
overload_lighting()
- . = TRUE
+ return TRUE
if("hack")
if(get_malf_status(usr))
malfhack(usr)
+ return TRUE
if("occupy")
if(get_malf_status(usr))
malfoccupy(usr)
+ return TRUE
if("deoccupy")
if(get_malf_status(usr))
malfvacate()
- if("reboot")
- failure_timer = 0
- update_icon()
- update()
+ return TRUE
if("emergency_lighting")
emergency_lights = !emergency_lights
for(var/obj/machinery/light/L in area)
@@ -1055,7 +1065,7 @@
INVOKE_ASYNC(D,/obj/machinery/door.proc/hostile_lockdown,usr, FALSE)
addtimer(CALLBACK(D,/obj/machinery/door.proc/disable_lockdown, FALSE), 30 SECONDS)
cell.charge -= cell.maxcharge*celluse
- return 1
+ return TRUE
/obj/machinery/power/apc/proc/toggle_breaker()
if(!is_operational() || failure_timer)
@@ -1486,6 +1496,8 @@
/obj/machinery/power/apc/proc/set_nightshift(on)
set waitfor = FALSE
+ if(nightshift_lights == on)
+ return
nightshift_lights = on
for(var/obj/machinery/light/L in area)
if(L.nightshift_allowed)
@@ -1500,6 +1512,18 @@
L.update(FALSE)
CHECK_TICK
+/obj/machinery/power/apc/proc/update_nightshift_auth_requirement()
+ nightshift_requires_auth = nightshift_toggle_requires_auth()
+
+/obj/machinery/power/apc/proc/nightshift_toggle_requires_auth()
+ if(!area)
+ return FALSE
+ var/configured_level = CONFIG_GET(number/night_shift_public_areas_only)
+ var/our_level = area.nightshift_public_area
+ var/public_requires_auth = CONFIG_GET(flag/nightshift_toggle_public_requires_auth)
+ var/normal_requires_auth = CONFIG_GET(flag/nightshift_toggle_requires_auth)
+ return (configured_level && our_level && ((our_level <= configured_level)? public_requires_auth : normal_requires_auth))
+
#undef UPSTATE_CELL_IN
#undef UPSTATE_OPENED1
#undef UPSTATE_OPENED2
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index b1c2d225ee..cee9a17ebf 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -79,13 +79,17 @@ By design, d1 is the smallest direction and d2 is the highest
color = "#ffffff"
// the power cable object
-/obj/structure/cable/Initialize(mapload, param_color)
+/obj/structure/cable/Initialize(mapload, param_color, _d1, _d2)
. = ..()
- // ensure d1 & d2 reflect the icon_state for entering and exiting cable
- var/dash = findtext(icon_state, "-")
- d1 = text2num( copytext( icon_state, 1, dash ) )
- d2 = text2num( copytext( icon_state, dash+1 ) )
+ if(isnull(_d1) || isnull(_d2))
+ // ensure d1 & d2 reflect the icon_state for entering and exiting cable
+ var/dash = findtext(icon_state, "-")
+ d1 = text2num( copytext( icon_state, 1, dash ) )
+ d2 = text2num( copytext( icon_state, dash+1 ) )
+ else
+ d1 = _d1
+ d2 = _d2
var/turf/T = get_turf(src) // hide if turf is not intact
if(level==1)
diff --git a/code/modules/power/rtg.dm b/code/modules/power/rtg.dm
index 9dca8f3124..45d1c0fc00 100644
--- a/code/modules/power/rtg.dm
+++ b/code/modules/power/rtg.dm
@@ -74,7 +74,7 @@
addtimer(CALLBACK(GLOBAL_PROC, .proc/explosion, get_turf(src), 2, 3, 4, 8), 100) // Not a normal explosion.
/obj/machinery/power/rtg/abductor/bullet_act(obj/item/projectile/Proj)
- ..()
+ . = ..()
if(!going_kaboom && istype(Proj) && !Proj.nodamage && ((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE)))
message_admins("[ADMIN_LOOKUPFLW(Proj.firer)] triggered an Abductor Core explosion at [AREACOORD(src)] via projectile.")
log_game("[key_name(Proj.firer)] triggered an Abductor Core explosion at [AREACOORD(src)] via projectile.")
diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index d622336925..a14a6d76bc 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -113,7 +113,8 @@
/obj/singularity/bullet_act(obj/item/projectile/P)
- return 0 //Will there be an impact? Who knows. Will we see it? No.
+ qdel(P)
+ return BULLET_ACT_HIT //Will there be an impact? Who knows. Will we see it? No.
/obj/singularity/Bump(atom/A)
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index 68ffcb909a..ee93767a0c 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -521,7 +521,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
has_been_powered = TRUE
else if(takes_damage)
damage += Proj.damage * config_bullet_energy
- return FALSE
+ return BULLET_ACT_HIT
/obj/machinery/power/supermatter_crystal/singularity_act()
var/gain = 100
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 19fdfd2b7e..531c6082b0 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -37,7 +37,6 @@
var/burst_spread = 0 //Spread induced by the gun itself during burst fire per iteration. Only checked if spread is 0.
var/randomspread = 1 //Set to 0 for shotguns. This is used for weapons that don't fire all their bullets at once.
var/inaccuracy_modifier = 1
- var/pb_knockback = 0
lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi'
@@ -126,10 +125,6 @@
if(message)
if(pointblank)
user.visible_message("[user] fires [src] point blank at [pbtarget]!", null, null, COMBAT_MESSAGE_RANGE)
- if(pb_knockback > 0)
- var/atom/throw_target = get_edge_target_turf(pbtarget, user.dir)
- pbtarget.throw_at(throw_target, pb_knockback, 2)
-
else
user.visible_message("[user] fires [src]!", null, null, COMBAT_MESSAGE_RANGE)
diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm
index 7fb4a8232e..bcb212a031 100644
--- a/code/modules/projectiles/guns/ballistic/automatic.dm
+++ b/code/modules/projectiles/guns/ballistic/automatic.dm
@@ -267,7 +267,6 @@
fire_delay = 0
pin = /obj/item/firing_pin/implant/pindicate
actions_types = list()
- pb_knockback = 2
/obj/item/gun/ballistic/automatic/shotgun/bulldog/unrestricted
pin = /obj/item/firing_pin
diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm
index 31a5131804..c2206fcea8 100644
--- a/code/modules/projectiles/guns/ballistic/revolver.dm
+++ b/code/modules/projectiles/guns/ballistic/revolver.dm
@@ -273,7 +273,6 @@
"Maple" = "dshotgun-l",
"Rosewood" = "dshotgun-p"
)
- pb_knockback = 3 // it's a super shotgun!
/obj/item/gun/ballistic/revolver/doublebarrel/attackby(obj/item/A, mob/user, params)
..()
diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm
index deec187f88..571525d8f0 100644
--- a/code/modules/projectiles/guns/ballistic/shotgun.dm
+++ b/code/modules/projectiles/guns/ballistic/shotgun.dm
@@ -12,8 +12,6 @@
var/recentpump = 0 // to prevent spammage
weapon_weight = WEAPON_MEDIUM
- pb_knockback = 2
-
/obj/item/gun/ballistic/shotgun/attackby(obj/item/A, mob/user, params)
. = ..()
if(.)
diff --git a/code/modules/projectiles/guns/ballistic/toy.dm b/code/modules/projectiles/guns/ballistic/toy.dm
index 8f9bc13583..8b358832b0 100644
--- a/code/modules/projectiles/guns/ballistic/toy.dm
+++ b/code/modules/projectiles/guns/ballistic/toy.dm
@@ -56,7 +56,6 @@
item_flags = NONE
casing_ejector = FALSE
can_suppress = FALSE
- pb_knockback = 0
/obj/item/gun/ballistic/shotgun/toy/process_chamber(empty_chamber = 0)
..()
diff --git a/code/modules/projectiles/guns/misc/beam_rifle.dm b/code/modules/projectiles/guns/misc/beam_rifle.dm
index 7aa85db246..c53e28ea29 100644
--- a/code/modules/projectiles/guns/misc/beam_rifle.dm
+++ b/code/modules/projectiles/guns/misc/beam_rifle.dm
@@ -569,4 +569,4 @@
/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/on_hit()
qdel(src)
- return FALSE
+ return BULLET_ACT_HIT
diff --git a/code/modules/projectiles/guns/misc/blastcannon.dm b/code/modules/projectiles/guns/misc/blastcannon.dm
index 6c685ebe89..1c8d519ba8 100644
--- a/code/modules/projectiles/guns/misc/blastcannon.dm
+++ b/code/modules/projectiles/guns/misc/blastcannon.dm
@@ -114,7 +114,7 @@
icon_state = "blastwave"
damage = 0
nodamage = FALSE
- forcedodge = TRUE
+ movement_type = FLYING | UNSTOPPABLE
var/heavyr = 0
var/mediumr = 0
var/lightr = 0
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 31eb34a4e1..cc778bcf05 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -11,15 +11,16 @@
item_flags = ABSTRACT
pass_flags = PASSTABLE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ movement_type = FLYING
hitsound = 'sound/weapons/pierce.ogg'
var/hitsound_wall = ""
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/def_zone = "" //Aiming at
var/atom/movable/firer = null//Who shot it
- var/atom/fired_from = null // the atom that the projectile was fired from (gun, turret)
+ var/atom/fired_from = null // the atom that the projectile was fired from (gun, turret) var/suppressed = FALSE //Attack message
var/suppressed = FALSE //Attack message
- var/candink = FALSE //Can this projectile play the dink sound when hitting the head?
+ var/candink = FALSE //Can this projectile play the dink sound when hitting the head? var/yo = null
var/yo = null
var/xo = null
var/atom/original = null // the original target clicked
@@ -84,7 +85,8 @@
var/flag = "bullet" //Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb
var/projectile_type = /obj/item/projectile
var/range = 50 //This will de-increment every step. When 0, it will deletze the projectile.
- var/decayedRange
+ var/decayedRange //stores original range
+ var/reflect_range_decrease = 5 //amount of original range that falls off when reflecting, so it doesn't go forever
var/is_reflectable = FALSE // Can it be reflected or not?
//Effects
var/stun = 0
@@ -99,11 +101,12 @@
var/drowsy = 0
var/stamina = 0
var/jitter = 0
- var/forcedodge = 0 //to pass through everything
var/dismemberment = 0 //The higher the number, the greater the bonus to dismembering. 0 will not dismember at all.
var/impact_effect_type //what type of impact effect to show when hitting something
var/log_override = FALSE //is this type spammed enough to not log? (KAs)
+ var/temporary_unstoppable_movement = FALSE
+
/obj/item/projectile/Initialize()
. = ..()
permutated = list()
@@ -152,12 +155,12 @@
W.add_dent(WALL_DENT_SHOT, hitx, hity)
- return 0
+ return BULLET_ACT_HIT
if(!isliving(target))
if(impact_effect_type && !hitscan)
new impact_effect_type(target_loca, hitx, hity)
- return 0
+ return BULLET_ACT_HIT
var/mob/living/L = target
@@ -185,7 +188,6 @@
C.bleed(damage)
else
L.add_splatter_floor(target_loca)
-
else if(impact_effect_type && !hitscan)
new impact_effect_type(target_loca, hitx, hity)
@@ -235,24 +237,20 @@
beam_segments[beam_index] = null
/obj/item/projectile/Bump(atom/A)
+ var/turf/T = get_turf(A)
if(trajectory && check_ricochet(A) && check_ricochet_flag(A) && ricochets < ricochets_max)
var/datum/point/pcache = trajectory.copy_to()
ricochets++
if(A.handle_ricochet(src))
on_ricochet(A)
ignore_source_check = TRUE
- range = initial(range)
+ decayedRange = max(0, decayedRange - reflect_range_decrease)
+ range = decayedRange
if(hitscan)
store_hitscan_collision(pcache)
return TRUE
- if(firer && !ignore_source_check)
- if(A == firer || (A == firer.loc && ismecha(A))) //cannot shoot yourself or your mech
- trajectory_ignore_forcemove = TRUE
- forceMove(get_turf(A))
- trajectory_ignore_forcemove = FALSE
- return FALSE
- var/distance = get_dist(get_turf(A), starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
+ var/distance = get_dist(T, starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use.
if(isturf(A) && hitsound_wall)
@@ -261,51 +259,66 @@
volume = 5
playsound(loc, hitsound_wall, volume, 1, -1)
- var/turf/target_turf = get_turf(A)
+ return process_hit(T, select_target(T, A))
- if(!prehit(A))
- if(forcedodge)
- trajectory_ignore_forcemove = TRUE
- forceMove(target_turf)
- trajectory_ignore_forcemove = FALSE
- return FALSE
+#define QDEL_SELF 1 //Delete if we're not UNSTOPPABLE flagged non-temporarily
+#define DO_NOT_QDEL 2 //Pass through.
+#define FORCE_QDEL 3 //Force deletion.
- var/permutation = A.bullet_act(src, def_zone) // searches for return value, could be deleted after run so check A isn't null
- if(permutation == -1 || forcedodge)// the bullet passes through a dense object!
- trajectory_ignore_forcemove = TRUE
- forceMove(target_turf)
- trajectory_ignore_forcemove = FALSE
- if(A)
- permutated.Add(A)
- return FALSE
- else
- var/atom/alt = select_target(A)
- if(alt)
- if(!prehit(alt))
- return FALSE
- alt.bullet_act(src, def_zone)
- qdel(src)
- return TRUE
+/obj/item/projectile/proc/process_hit(turf/T, atom/target, qdel_self, hit_something = FALSE) //probably needs to be reworked entirely when pixel movement is done.
+ if(QDELETED(src) || !T || !target) //We're done, nothing's left.
+ if((qdel_self == FORCE_QDEL) || ((qdel_self == QDEL_SELF) && !temporary_unstoppable_movement && !CHECK_BITFIELD(movement_type, UNSTOPPABLE)))
+ qdel(src)
+ return hit_something
+ permutated |= target //Make sure we're never hitting it again. If we ever run into weirdness with piercing projectiles needing to hit something multiple times.. well.. that's a to-do.
+ if(!prehit(target))
+ return process_hit(T, select_target(T), qdel_self, hit_something) //Hit whatever else we can since that didn't work.
+ var/result = target.bullet_act(src, def_zone)
+ if(result == BULLET_ACT_FORCE_PIERCE)
+ if(!CHECK_BITFIELD(movement_type, UNSTOPPABLE))
+ temporary_unstoppable_movement = TRUE
+ ENABLE_BITFIELD(movement_type, UNSTOPPABLE)
+ return process_hit(T, select_target(T), qdel_self, TRUE) //Hit whatever else we can since we're piercing through but we're still on the same tile.
+ else if(result == BULLET_ACT_TURF) //We hit the turf but instead we're going to also hit something else on it.
+ return process_hit(T, select_target(T), QDEL_SELF, TRUE)
+ else //Whether it hit or blocked, we're done!
+ qdel_self = QDEL_SELF
+ hit_something = TRUE
+ if((qdel_self == FORCE_QDEL) || ((qdel_self == QDEL_SELF) && !temporary_unstoppable_movement && !CHECK_BITFIELD(movement_type, UNSTOPPABLE)))
+ qdel(src)
+ return hit_something
-/obj/item/projectile/proc/select_target(atom/A) //Selects another target from a wall if we hit a wall.
- if(!A || !A.density || (A.flags_1 & ON_BORDER_1) || ismob(A) || A == original) //if we hit a dense non-border obj or dense turf then we also hit one of the mobs or machines/structures on that tile.
- return
- var/turf/T = get_turf(A)
- if(original in T)
+#undef QDEL_SELF
+#undef DO_NOT_QDEL
+#undef FORCE_QDEL
+
+/obj/item/projectile/proc/select_target(turf/T, atom/target) //Select a target from a turf.
+ if((original in T) && can_hit_target(original, permutated, TRUE, TRUE))
return original
- var/list/mob/possible_mobs = typecache_filter_list(T, GLOB.typecache_mob) - A
+ if(target && can_hit_target(target, permutated, target == original, TRUE))
+ return target
+ var/list/mob/living/possible_mobs = typecache_filter_list(T, GLOB.typecache_mob)
var/list/mob/mobs = list()
- for(var/i in possible_mobs)
- var/mob/M = i
- if(M.lying)
+ for(var/mob/living/M in possible_mobs)
+ if(!can_hit_target(M, permutated, M == original, TRUE))
continue
mobs += M
var/mob/M = safepick(mobs)
if(M)
return M.lowest_buckled_mob()
- var/obj/O = safepick(typecache_filter_list(T, GLOB.typecache_machine_or_structure) - A)
+ var/list/obj/possible_objs = typecache_filter_list(T, GLOB.typecache_machine_or_structure)
+ var/list/obj/objs = list()
+ for(var/obj/O in possible_objs)
+ if(!can_hit_target(O, permutated, O == original, TRUE))
+ continue
+ objs += O
+ var/obj/O = safepick(objs)
if(O)
return O
+ //Nothing else is here that we can hit, hit the turf if we haven't.
+ if(!(T in permutated) && can_hit_target(T, permutated, T == original, TRUE))
+ return T
+ //Returns null if nothing at all was found.
/obj/item/projectile/proc/check_ricochet()
if(prob(ricochet_chance))
@@ -332,7 +345,7 @@
var/turf/ending = return_predicted_turf_after_moves(moves, forced_angle)
return getline(current, ending)
-/obj/item/projectile/Process_Spacemove(var/movement_dir = 0)
+/obj/item/projectile/Process_Spacemove(movement_dir = 0)
return TRUE //Bullets don't drift in space
/obj/item/projectile/process()
@@ -360,8 +373,7 @@
/obj/item/projectile/proc/fire(angle, atom/direct_target)
if(fired_from)
- SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_BEFORE_FIRE, src, original)
- //If no angle needs to resolve it from xo/yo!
+ SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_BEFORE_FIRE, src, original) //If no angle needs to resolve it from xo/yo!
if(!log_override && firer && original)
log_combat(firer, original, "fired at", src, "from [get_area_name(src, TRUE)]")
if(direct_target)
@@ -498,8 +510,6 @@
else if(T != loc)
step_towards(src, T)
hitscan_last = loc
- if(can_hit_target(original, permutated))
- Bump(original)
if(!hitscanning && !forcemoved)
pixel_x = trajectory.return_px() - trajectory.mpx * trajectory_multiplier * SSprojectiles.global_iterations_per_move
pixel_y = trajectory.return_py() - trajectory.mpy * trajectory_multiplier * SSprojectiles.global_iterations_per_move
@@ -528,8 +538,28 @@
homing_offset_y = -homing_offset_y
//Returns true if the target atom is on our current turf and above the right layer
-/obj/item/projectile/proc/can_hit_target(atom/target, var/list/passthrough)
- return (target && ((target.layer >= PROJECTILE_HIT_THRESHHOLD_LAYER) || ismob(target)) && (loc == get_turf(target)) && (!(target in passthrough)))
+//If direct target is true it's the originally clicked target.
+/obj/item/projectile/proc/can_hit_target(atom/target, list/passthrough, direct_target = FALSE, ignore_loc = FALSE)
+ if(QDELETED(target))
+ return FALSE
+ if(!ignore_source_check && firer)
+ var/mob/M = firer
+ if((target == firer) || ((target == firer.loc) && ismecha(firer.loc)) || (target in firer.buckled_mobs) || (istype(M) && (M.buckled == target)))
+ return FALSE
+ if(!ignore_loc && (loc != target.loc))
+ return FALSE
+ if(target in passthrough)
+ return FALSE
+ if(target.density) //This thing blocks projectiles, hit it regardless of layer/mob stuns/etc.
+ return TRUE
+ if(!isliving(target))
+ if(target.layer < PROJECTILE_HIT_THRESHHOLD_LAYER)
+ return FALSE
+ else
+ var/mob/living/L = target
+ if(!direct_target && !L.density)
+ return FALSE
+ return TRUE
//Spread is FORCED!
/obj/item/projectile/proc/preparePixelProjectile(atom/target, atom/source, params, spread = 0)
@@ -591,9 +621,20 @@
return list(angle, p_x, p_y)
/obj/item/projectile/Crossed(atom/movable/AM) //A mob moving on a tile with a projectile is hit by it.
- ..()
- if(isliving(AM) && (AM.density || AM == original) && !(src.pass_flags & PASSMOB))
- Bump(AM)
+ . = ..()
+ if(isliving(AM) && !(pass_flags & PASSMOB))
+ var/mob/living/L = AM
+ if(can_hit_target(L, permutated, (AM == original)))
+ Bump(AM)
+
+/obj/item/projectile/Move(atom/newloc, dir = NONE)
+ . = ..()
+ if(.)
+ if(temporary_unstoppable_movement)
+ temporary_unstoppable_movement = FALSE
+ DISABLE_BITFIELD(movement_type, UNSTOPPABLE)
+ if(fired && can_hit_target(original, permutated, TRUE))
+ Bump(original)
/obj/item/projectile/Destroy()
if(hitscan)
diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm
index d984217f8c..fd79a52906 100644
--- a/code/modules/projectiles/projectile/beams.dm
+++ b/code/modules/projectiles/projectile/beams.dm
@@ -107,8 +107,8 @@
/obj/item/projectile/beam/pulse/heavy/on_hit(atom/target, blocked = FALSE)
life -= 10
if(life > 0)
- . = -1
- ..()
+ . = BULLET_ACT_FORCE_PIERCE
+ return ..()
/obj/item/projectile/beam/emitter
name = "emitter beam"
@@ -207,4 +207,4 @@
. = ..()
if(isopenturf(target) || istype(target, /turf/closed/indestructible))//shrunk floors wouldnt do anything except look weird, i-walls shouldnt be bypassable
return
- target.AddComponent(/datum/component/shrink, shrink_time)
\ No newline at end of file
+ target.AddComponent(/datum/component/shrink, shrink_time)
diff --git a/code/modules/projectiles/projectile/bullets/dart_syringe.dm b/code/modules/projectiles/projectile/bullets/dart_syringe.dm
index 9d60f72de0..3f418df75b 100644
--- a/code/modules/projectiles/projectile/bullets/dart_syringe.dm
+++ b/code/modules/projectiles/projectile/bullets/dart_syringe.dm
@@ -15,7 +15,7 @@
if(M.can_inject(null, FALSE, def_zone, piercing)) // Pass the hit zone to see if it can inject by whether it hit the head or the body.
..()
if(skip == TRUE)
- return
+ return BULLET_ACT_HIT
reagents.reaction(M, INJECT)
reagents.trans_to(M, reagents.total_volume)
return TRUE
@@ -27,7 +27,7 @@
..(target, blocked)
DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT)
reagents.handle_reactions()
- return TRUE
+ return BULLET_ACT_HIT
/obj/item/projectile/bullet/dart/metalfoam/Initialize()
. = ..()
@@ -70,11 +70,11 @@
target.visible_message("\The [src] beeps!")
to_chat("You feel a tiny prick as a smartdart embeds itself in you with a beep.")
- return TRUE
+ return BULLET_ACT_HIT
else
blocked = 100
target.visible_message("\The [src] was deflected!", \
"You see a [src] bounce off you, booping sadly!")
target.visible_message("\The [src] fails to land on target!")
- return TRUE
+ return BULLET_ACT_BLOCK
diff --git a/code/modules/projectiles/projectile/bullets/dnainjector.dm b/code/modules/projectiles/projectile/bullets/dnainjector.dm
index 3bfe2add01..22e9d28ab6 100644
--- a/code/modules/projectiles/projectile/bullets/dnainjector.dm
+++ b/code/modules/projectiles/projectile/bullets/dnainjector.dm
@@ -12,7 +12,7 @@
if(M.can_inject(null, FALSE, def_zone, FALSE))
if(injector.inject(M, firer))
QDEL_NULL(injector)
- return TRUE
+ return BULLET_ACT_HIT
else
blocked = 100
target.visible_message("\The [src] was deflected!", \
diff --git a/code/modules/projectiles/projectile/bullets/grenade.dm b/code/modules/projectiles/projectile/bullets/grenade.dm
index 3e01f167f6..16305c233f 100644
--- a/code/modules/projectiles/projectile/bullets/grenade.dm
+++ b/code/modules/projectiles/projectile/bullets/grenade.dm
@@ -9,4 +9,4 @@
/obj/item/projectile/bullet/a40mm/on_hit(atom/target, blocked = FALSE)
..()
explosion(target, -1, 0, 2, 1, 0, flame_range = 3)
- return TRUE
+ return BULLET_ACT_HIT
diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm
index ed9478e0ee..02ec167b80 100644
--- a/code/modules/projectiles/projectile/bullets/shotgun.dm
+++ b/code/modules/projectiles/projectile/bullets/shotgun.dm
@@ -53,7 +53,7 @@
/obj/item/projectile/bullet/shotgun_frag12/on_hit(atom/target, blocked = FALSE)
..()
explosion(target, -1, 0, 1)
- return TRUE
+ return BULLET_ACT_HIT
/obj/item/projectile/bullet/pellet
var/tile_dropoff = 0.75
diff --git a/code/modules/projectiles/projectile/bullets/sniper.dm b/code/modules/projectiles/projectile/bullets/sniper.dm
index 6519421284..bea5dbc140 100644
--- a/code/modules/projectiles/projectile/bullets/sniper.dm
+++ b/code/modules/projectiles/projectile/bullets/sniper.dm
@@ -34,7 +34,7 @@
icon_state = "gauss"
name = "penetrator round"
damage = 60
- forcedodge = TRUE
+ movement_type = FLYING | UNSTOPPABLE
dismemberment = 0 //It goes through you cleanly.
knockdown = 0
breakthings = FALSE
diff --git a/code/modules/projectiles/projectile/bullets/special.dm b/code/modules/projectiles/projectile/bullets/special.dm
index 0d3ed847d8..a0414d8a9c 100644
--- a/code/modules/projectiles/projectile/bullets/special.dm
+++ b/code/modules/projectiles/projectile/bullets/special.dm
@@ -3,7 +3,7 @@
/obj/item/projectile/bullet/honker
damage = 0
knockdown = 60
- forcedodge = TRUE
+ movement_type = FLYING | UNSTOPPABLE
nodamage = TRUE
candink = FALSE
hitsound = 'sound/items/bikehorn.ogg'
diff --git a/code/modules/projectiles/projectile/energy/net_snare.dm b/code/modules/projectiles/projectile/energy/net_snare.dm
index c8333a811c..22eaadb1e0 100644
--- a/code/modules/projectiles/projectile/energy/net_snare.dm
+++ b/code/modules/projectiles/projectile/energy/net_snare.dm
@@ -15,7 +15,7 @@
var/turf/Tloc = get_turf(target)
if(!locate(/obj/effect/nettingportal) in Tloc)
new /obj/effect/nettingportal(Tloc)
- ..()
+ return ..()
/obj/item/projectile/energy/net/on_range()
do_sparks(1, TRUE, src)
@@ -69,7 +69,7 @@
else if(iscarbon(target))
var/obj/item/restraints/legcuffs/beartrap/B = new /obj/item/restraints/legcuffs/beartrap/energy(get_turf(target))
B.Crossed(target)
- ..()
+ return ..()
/obj/item/projectile/energy/trap/on_range()
new /obj/item/restraints/legcuffs/beartrap/energy(loc)
@@ -91,7 +91,7 @@
var/obj/item/restraints/legcuffs/beartrap/B = new /obj/item/restraints/legcuffs/beartrap/energy/cyborg(get_turf(target))
B.Crossed(target)
QDEL_IN(src, 10)
- ..()
+ return ..()
/obj/item/projectile/energy/trap/cyborg/on_range()
do_sparks(1, TRUE, src)
diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm
index 791db320a2..7608e5f4a8 100644
--- a/code/modules/projectiles/projectile/magic.dm
+++ b/code/modules/projectiles/projectile/magic.dm
@@ -17,7 +17,7 @@
var/mob/M = target
if(M.anti_magic_check())
M.visible_message("[src] vanishes on contact with [target]!")
- return
+ return BULLET_ACT_BLOCK
M.death(0)
/obj/item/projectile/magic/resurrection
@@ -31,10 +31,10 @@
. = ..()
if(isliving(target))
if(target.hellbound)
- return
+ return BULLET_ACT_BLOCK
if(target.anti_magic_check())
target.visible_message("[src] vanishes on contact with [target]!")
- return
+ return BULLET_ACT_BLOCK
if(iscarbon(target))
var/mob/living/carbon/C = target
C.regenerate_limbs()
@@ -60,7 +60,7 @@
var/mob/M = target
if(M.anti_magic_check())
M.visible_message("[src] fizzles on contact with [target]!")
- return
+ return BULLET_ACT_BLOCK
var/teleammount = 0
var/teleloc = target
if(!isturf(target))
@@ -116,7 +116,7 @@
if(M.anti_magic_check())
M.visible_message("[src] fizzles on contact with [M]!")
qdel(src)
- return
+ return BULLET_ACT_BLOCK
wabbajack(change)
qdel(src)
@@ -264,7 +264,7 @@
/obj/item/projectile/magic/animate/on_hit(atom/target, blocked = FALSE)
target.animate_atom_living(firer)
- ..()
+ . = ..()
/atom/proc/animate_atom_living(var/mob/living/owner = null)
if((isitem(src) || isstructure(src)) && !is_type_in_list(src, GLOB.protected_objects))
@@ -315,7 +315,7 @@
if(M.anti_magic_check())
M.visible_message("[src] vanishes on contact with [target]!")
qdel(src)
- return
+ return BULLET_ACT_BLOCK
. = ..()
/obj/item/projectile/magic/arcane_barrage
@@ -334,7 +334,7 @@
if(M.anti_magic_check())
M.visible_message("[src] vanishes on contact with [target]!")
qdel(src)
- return
+ return BULLET_ACT_BLOCK
. = ..()
@@ -460,7 +460,7 @@
if(M.anti_magic_check())
visible_message("[src] fizzles on contact with [target]!")
qdel(src)
- return
+ return BULLET_ACT_BLOCK
tesla_zap(src, tesla_range, tesla_power, tesla_flags)
qdel(src)
@@ -487,7 +487,7 @@
var/mob/living/M = target
if(M.anti_magic_check())
visible_message("[src] vanishes into smoke on contact with [target]!")
- return
+ return BULLET_ACT_BLOCK
M.take_overall_damage(0,10) //between this 10 burn, the 10 brute, the explosion brute, and the onfire burn, your at about 65 damage if you stop drop and roll immediately
var/turf/T = get_turf(target)
explosion(T, -1, exp_heavy, exp_light, exp_flash, 0, flame_range = exp_fire)
@@ -504,7 +504,7 @@
if(ismob(target))
var/mob/living/M = target
if(M.anti_magic_check())
- return
+ return BULLET_ACT_BLOCK
var/turf/T = get_turf(target)
for(var/i=0, i<50, i+=10)
addtimer(CALLBACK(GLOBAL_PROC, .proc/explosion, T, -1, exp_heavy, exp_light, exp_flash, FALSE, FALSE, exp_fire), i)
@@ -518,11 +518,11 @@
/obj/item/projectile/magic/nuclear/on_hit(target)
if(used)
- return
+ return BULLET_ACT_HIT
new/obj/effect/temp_visual/slugboom(get_turf(src))
if(ismob(target))
if(target == victim)
- return
+ return BULLET_ACT_FORCE_PIERCE
used = 1
visible_message("[victim] slams into [target] with explosive force!")
explosion(src, 2, 3, 4, -1, TRUE, FALSE, 5)
@@ -531,8 +531,9 @@
victim.take_overall_damage(30,30)
victim.Knockdown(60)
explosion(src, -1, -1, -1, -1, FALSE, FALSE, 5)
+ return BULLET_ACT_HIT
/obj/item/projectile/magic/nuclear/Destroy()
for(var/atom/movable/AM in contents)
AM.forceMove(get_turf(src))
- . = ..()
\ No newline at end of file
+ . = ..()
diff --git a/code/modules/projectiles/projectile/special/curse.dm b/code/modules/projectiles/projectile/special/curse.dm
index 0464f93cd3..062623689b 100644
--- a/code/modules/projectiles/projectile/special/curse.dm
+++ b/code/modules/projectiles/projectile/special/curse.dm
@@ -12,7 +12,7 @@
knockdown = 20
speed = 2
range = 16
- forcedodge = TRUE
+ movement_type = FLYING | UNSTOPPABLE
var/datum/beam/arm
var/handedness = 0
@@ -28,7 +28,7 @@
/obj/item/projectile/curse_hand/prehit(atom/target)
if(target == original)
- forcedodge = FALSE
+ DISABLE_BITFIELD(movement_type, UNSTOPPABLE)
else if(!isturf(target))
return FALSE
return ..()
@@ -37,7 +37,7 @@
if(arm)
arm.End()
arm = null
- if(forcedodge)
+ if(CHECK_BITFIELD(movement_type, UNSTOPPABLE))
playsound(src, 'sound/effects/curse3.ogg', 25, 1, -1)
var/turf/T = get_step(src, dir)
new/obj/effect/temp_visual/dir_setting/curse/hand(T, dir, handedness)
diff --git a/code/modules/projectiles/projectile/special/ion.dm b/code/modules/projectiles/projectile/special/ion.dm
index 231b4de021..ae0888d3df 100644
--- a/code/modules/projectiles/projectile/special/ion.dm
+++ b/code/modules/projectiles/projectile/special/ion.dm
@@ -6,15 +6,12 @@
nodamage = 1
flag = "energy"
impact_effect_type = /obj/effect/temp_visual/impact_effect/ion
+ var/emp_radius = 1
/obj/item/projectile/ion/on_hit(atom/target, blocked = FALSE)
..()
- empulse(target, 1, 1)
- return TRUE
+ empulse(target, emp_radius, emp_radius)
+ return BULLET_ACT_HIT
/obj/item/projectile/ion/weak
-
-/obj/item/projectile/ion/weak/on_hit(atom/target, blocked = FALSE)
- ..()
- empulse(target, 0, 0)
- return TRUE
+ emp_radius = 0
diff --git a/code/modules/projectiles/projectile/special/plasma.dm b/code/modules/projectiles/projectile/special/plasma.dm
index 3a9ce24674..33559fa92c 100644
--- a/code/modules/projectiles/projectile/special/plasma.dm
+++ b/code/modules/projectiles/projectile/special/plasma.dm
@@ -29,7 +29,7 @@
mine_range--
range++
if(range > 0)
- return -1
+ return BULLET_ACT_FORCE_PIERCE
/obj/item/projectile/plasma/adv
damage = 28
diff --git a/code/modules/projectiles/projectile/special/rocket.dm b/code/modules/projectiles/projectile/special/rocket.dm
index 03d85665d5..0cee20dd53 100644
--- a/code/modules/projectiles/projectile/special/rocket.dm
+++ b/code/modules/projectiles/projectile/special/rocket.dm
@@ -6,7 +6,7 @@
/obj/item/projectile/bullet/gyro/on_hit(atom/target, blocked = FALSE)
..()
explosion(target, -1, 0, 2)
- return TRUE
+ return BULLET_ACT_HIT
/obj/item/projectile/bullet/a84mm
name ="\improper HEDP rocket"
@@ -28,7 +28,7 @@
if(issilicon(target))
var/mob/living/silicon/S = target
S.take_overall_damage(anti_armour_damage*0.75, anti_armour_damage*0.25)
- return TRUE
+ return BULLET_ACT_HIT
/obj/item/projectile/bullet/a84mm_he
name ="\improper HE missile"
@@ -43,4 +43,4 @@
explosion(target, 0, 1, 2, 4)
else
explosion(target, 0, 0, 2, 4)
- return TRUE
\ No newline at end of file
+ return BULLET_ACT_HIT
\ No newline at end of file
diff --git a/code/modules/projectiles/projectile/special/wormhole.dm b/code/modules/projectiles/projectile/special/wormhole.dm
index 0832f0cc76..aaf9f542d3 100644
--- a/code/modules/projectiles/projectile/special/wormhole.dm
+++ b/code/modules/projectiles/projectile/special/wormhole.dm
@@ -25,5 +25,5 @@
/obj/item/projectile/beam/wormhole/on_hit(atom/target)
if(!gun)
qdel(src)
- return
+ return BULLET_ACT_BLOCK
gun.create_portal(src, get_turf(src))
diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm
index d8a2b90b9e..0fa86ac496 100644
--- a/code/modules/reagents/chemistry/machinery/chem_master.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_master.dm
@@ -434,11 +434,11 @@
state = "Gas"
var/const/P = 3 //The number of seconds between life ticks
var/T = initial(R.metabolization_rate) * (60 / P)
- var/datum/chemical_reaction/Rcr = get_chemical_reaction(R.type)
+ var/datum/chemical_reaction/Rcr = get_chemical_reaction(R)
if(Rcr && Rcr.FermiChem)
fermianalyze = TRUE
var/pHpeakCache = (Rcr.OptimalpHMin + Rcr.OptimalpHMax)/2
- var/datum/reagent/targetReagent = beaker.reagents.has_reagent(R.type)
+ var/datum/reagent/targetReagent = beaker.reagents.has_reagent(R)
if(!targetReagent)
CRASH("Tried to find a reagent that doesn't exist in the chem_master!")
@@ -463,9 +463,9 @@
var/T = initial(R.metabolization_rate) * (60 / P)
if(istype(R, /datum/reagent/fermi))
fermianalyze = TRUE
- var/datum/chemical_reaction/Rcr = get_chemical_reaction(R.type)
+ var/datum/chemical_reaction/Rcr = get_chemical_reaction(R)
var/pHpeakCache = (Rcr.OptimalpHMin + Rcr.OptimalpHMax)/2
- var/datum/reagent/targetReagent = reagents.has_reagent(R.type)
+ var/datum/reagent/targetReagent = reagents.has_reagent(R)
if(!targetReagent)
CRASH("Tried to find a reagent that doesn't exist in the chem_master!")
@@ -483,7 +483,7 @@
/obj/machinery/chem_master/proc/end_fermi_reaction()//Ends any reactions upon moving.
- if(beaker.reagents.fermiIsReacting)
+ if(beaker && beaker.reagents.fermiIsReacting)
beaker.reagents.fermiEnd()
/obj/machinery/chem_master/proc/isgoodnumber(num)
diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
index 6460bfed78..6a191bd2ab 100644
--- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
@@ -901,7 +901,12 @@
M.emote("nya")
if(prob(20))
to_chat(M, "[pick("Headpats feel nice.", "Backrubs would be nice.", "Mew")]")
- M.adjustArousalLoss(5)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ var/list/adjusted = H.adjust_arousal(5,aphro = TRUE)
+ for(var/g in adjusted)
+ var/obj/item/organ/genital/G = g
+ to_chat(M, "You feel like playing with your [G.name]!")
..()
/datum/reagent/consumable/monkey_energy
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index dbede29e5f..ccc966e7e4 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -60,7 +60,7 @@
B = new(T)
if(data["blood_DNA"])
B.blood_DNA[data["blood_DNA"]] = data["blood_type"]
- if(!B.reagents)
+ if(B.reagents)
B.reagents.add_reagent(type, reac_volume)
B.update_icon()
@@ -2127,5 +2127,11 @@
M.emote("nya")
if(prob(20))
to_chat(M, "[pick("Headpats feel nice.", "The feeling of a hairball...", "Backrubs would be nice.", "Whats behind those doors?")]")
- M.adjustArousalLoss(2)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ var/list/adjusted = H.adjust_arousal(2,aphro = TRUE)
+ for(var/g in adjusted)
+ var/obj/item/organ/genital/G = g
+ to_chat(M, "You feel like playing with your [G.name]!")
+
..()
diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm
index d4c71ebb44..26b39fb3b0 100644
--- a/code/modules/reagents/chemistry/recipes/others.dm
+++ b/code/modules/reagents/chemistry/recipes/others.dm
@@ -222,7 +222,6 @@
/datum/chemical_reaction/mix_virus
name = "Mix Virus"
id = "mixvirus"
- results = list(/datum/reagent/blood = 1)
required_reagents = list(/datum/reagent/consumable/virus_food = 1)
required_catalysts = list(/datum/reagent/blood = 1)
var/level_min = 1
@@ -234,8 +233,8 @@
if(B && B.data)
var/datum/disease/advance/D = locate(/datum/disease/advance) in B.data["viruses"]
if(D)
- D.Evolve(level_min, level_max)
-
+ for(var/i in 1 to min(created_volume, 5))
+ D.Evolve(level_min, level_max)
/datum/chemical_reaction/mix_virus/mix_virus_2
@@ -326,19 +325,18 @@
level_max = 8
/datum/chemical_reaction/mix_virus/rem_virus
-
name = "Devolve Virus"
id = "remvirus"
required_reagents = list(/datum/reagent/medicine/synaptizine = 1)
required_catalysts = list(/datum/reagent/blood = 1)
/datum/chemical_reaction/mix_virus/rem_virus/on_reaction(datum/reagents/holder, created_volume)
-
var/datum/reagent/blood/B = locate(/datum/reagent/blood) in holder.reagent_list
if(B && B.data)
var/datum/disease/advance/D = locate(/datum/disease/advance) in B.data["viruses"]
if(D)
- D.Devolve()
+ for(var/i in 1 to min(created_volume, 5))
+ D.Devolve()
/datum/chemical_reaction/mix_virus/neuter_virus
name = "Neuter Virus"
@@ -347,14 +345,12 @@
required_catalysts = list(/datum/reagent/blood = 1)
/datum/chemical_reaction/mix_virus/neuter_virus/on_reaction(datum/reagents/holder, created_volume)
-
var/datum/reagent/blood/B = locate(/datum/reagent/blood) in holder.reagent_list
if(B && B.data)
var/datum/disease/advance/D = locate(/datum/disease/advance) in B.data["viruses"]
if(D)
- D.Neuter()
-
-
+ for(var/i in 1 to min(created_volume, 5))
+ D.Neuter()
////////////////////////////////// foam and foam precursor ///////////////////////////////////////////////////
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index 132c34c9f8..321b63da1e 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -128,8 +128,7 @@
target.visible_message("[M] has been splashed with something!", \
"[M] has been splashed with something!")
for(var/datum/reagent/A in reagents.reagent_list)
- R += A.type + " ("
- R += num2text(A.volume) + "),"
+ R += "[A.type] ([A.volume]),"
if(thrownby)
log_combat(thrownby, M, "splashed", R)
diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm
index da8eb3846d..edaa5ce269 100644
--- a/code/modules/reagents/reagent_containers/spray.dm
+++ b/code/modules/reagents/reagent_containers/spray.dm
@@ -199,6 +199,9 @@
amount_per_transfer_from_this = 5
list_reagents = list(/datum/reagent/consumable/condensedcapsaicin = 40)
+/obj/item/reagent_containers/spray/pepper/empty // for techfab printing
+ list_reagents = null
+
/obj/item/reagent_containers/spray/pepper/suicide_act(mob/living/carbon/user)
user.visible_message("[user] begins huffing \the [src]! It looks like [user.p_theyre()] getting a dirty high!")
return OXYLOSS
diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm
index 2e0c5b7619..1c87c1901c 100644
--- a/code/modules/reagents/reagent_dispenser.dm
+++ b/code/modules/reagents/reagent_dispenser.dm
@@ -125,7 +125,7 @@
boom()
/obj/structure/reagent_dispensers/fueltank/bullet_act(obj/item/projectile/P)
- ..()
+ . = ..()
if(!QDELETED(src)) //wasn't deleted by the projectile's effects.
if(!P.nodamage && ((P.damage_type == BURN) || (P.damage_type == BRUTE)))
var/boom_message = "[ADMIN_LOOKUPFLW(P.firer)] triggered a fueltank explosion via projectile."
diff --git a/code/modules/research/designs/autolathe_desings/autolathe_designs_electronics.dm b/code/modules/research/designs/autolathe_desings/autolathe_designs_electronics.dm
index 5b247efe74..4ca780620d 100644
--- a/code/modules/research/designs/autolathe_desings/autolathe_designs_electronics.dm
+++ b/code/modules/research/designs/autolathe_desings/autolathe_designs_electronics.dm
@@ -54,7 +54,7 @@
/datum/design/desttagger
name = "Destination Tagger"
id = "desttagger"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 250, MAT_GLASS = 125)
build_path = /obj/item/destTagger
category = list("initial", "Electronics")
@@ -62,7 +62,7 @@
/datum/design/handlabeler
name = "Hand Labeler"
id = "handlabel"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 150, MAT_GLASS = 125)
build_path = /obj/item/hand_labeler
category = list("initial", "Electronics")
@@ -73,4 +73,4 @@
build_type = AUTOLATHE
materials = list(MAT_GLASS = 20)
build_path = /obj/item/stock_parts/cell/emergency_light
- category = list("initial", "Electronics")
\ No newline at end of file
+ category = list("initial", "Electronics")
diff --git a/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm b/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm
index 27852b2798..0d303c3968 100644
--- a/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm
+++ b/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm
@@ -68,66 +68,74 @@
/datum/design/scalpel
name = "Scalpel"
id = "scalpel"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 4000, MAT_GLASS = 1000)
build_path = /obj/item/scalpel
- category = list("initial", "Medical")
+ category = list("initial", "Medical","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/circular_saw
name = "Circular Saw"
id = "circular_saw"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 10000, MAT_GLASS = 6000)
build_path = /obj/item/circular_saw
- category = list("initial", "Medical")
+ category = list("initial", "Medical","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/surgicaldrill
name = "Surgical Drill"
id = "surgicaldrill"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 10000, MAT_GLASS = 6000)
build_path = /obj/item/surgicaldrill
- category = list("initial", "Medical")
+ category = list("initial", "Medical","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/retractor
name = "Retractor"
id = "retractor"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 6000, MAT_GLASS = 3000)
build_path = /obj/item/retractor
- category = list("initial", "Medical")
+ category = list("initial", "Medical","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/cautery
name = "Cautery"
id = "cautery"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 2500, MAT_GLASS = 750)
build_path = /obj/item/cautery
- category = list("initial", "Medical")
+ category = list("initial", "Medical","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/hemostat
name = "Hemostat"
id = "hemostat"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 5000, MAT_GLASS = 2500)
build_path = /obj/item/hemostat
- category = list("initial", "Medical")
+ category = list("initial", "Medical","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/beaker
name = "Beaker"
id = "beaker"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_GLASS = 500)
build_path = /obj/item/reagent_containers/glass/beaker
- category = list("initial", "Medical")
+ category = list("initial", "Medical","Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SERVICE | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/large_beaker
name = "Large Beaker"
id = "large_beaker"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_GLASS = 2500)
build_path = /obj/item/reagent_containers/glass/beaker/large
- category = list("initial", "Medical")
+ category = list("initial", "Medical","Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SERVICE | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/healthanalyzer
name = "Health Analyzer"
@@ -141,10 +149,11 @@
/datum/design/pillbottle
name = "Pill Bottle"
id = "pillbottle"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 20, MAT_GLASS = 100)
build_path = /obj/item/storage/pill_bottle
- category = list("initial", "Medical")
+ category = list("initial", "Medical","Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
/datum/design/syringe
name = "Syringe"
@@ -165,15 +174,17 @@
/datum/design/hypovialsmall
name = "Hypovial"
id = "hypovial"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 500)
build_path = /obj/item/reagent_containers/glass/bottle/vial/small
- category = list("initial","Medical")
+ category = list("initial","Medical","Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
/datum/design/hypoviallarge
name = "Large Hypovial"
id = "large_hypovial"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 2500)
build_path = /obj/item/reagent_containers/glass/bottle/vial/large
- category = list("initial","Medical")
+ category = list("initial","Medical","Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
diff --git a/code/modules/research/designs/autolathe_desings/autolathe_designs_tcomms_and_misc.dm b/code/modules/research/designs/autolathe_desings/autolathe_designs_tcomms_and_misc.dm
index 29d28b7132..a0af3d8b1e 100644
--- a/code/modules/research/designs/autolathe_desings/autolathe_designs_tcomms_and_misc.dm
+++ b/code/modules/research/designs/autolathe_desings/autolathe_designs_tcomms_and_misc.dm
@@ -68,58 +68,65 @@
/datum/design/pipe_painter
name = "Pipe Painter"
id = "pipe_painter"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 5000, MAT_GLASS = 2000)
build_path = /obj/item/pipe_painter
- category = list("initial", "Misc")
+ category = list("initial", "Misc","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
/datum/design/airlock_painter
name = "Airlock Painter"
id = "airlock_painter"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 50, MAT_GLASS = 50)
build_path = /obj/item/airlock_painter
- category = list("initial", "Misc")
+ category = list("initial", "Misc","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
/datum/design/cultivator
name = "Cultivator"
id = "cultivator"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL=50)
build_path = /obj/item/cultivator
- category = list("initial","Misc")
+ category = list("initial","Misc","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_SERVICE
/datum/design/plant_analyzer
name = "Plant Analyzer"
id = "plant_analyzer"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 30, MAT_GLASS = 20)
build_path = /obj/item/plant_analyzer
- category = list("initial","Misc")
+ category = list("initial","Misc","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_SERVICE
/datum/design/shovel
name = "Shovel"
id = "shovel"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 50)
build_path = /obj/item/shovel
- category = list("initial","Misc")
+ category = list("initial","Misc","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_SERVICE | DEPARTMENTAL_FLAG_CARGO
/datum/design/spade
name = "Spade"
id = "spade"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 50)
build_path = /obj/item/shovel/spade
- category = list("initial","Misc")
+ category = list("initial","Misc","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_SERVICE
/datum/design/hatchet
name = "Hatchet"
id = "hatchet"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 15000)
build_path = /obj/item/hatchet
- category = list("initial","Misc")
+ category = list("initial","Misc","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_SERVICE
/datum/design/recorder
name = "Universal Recorder"
@@ -220,10 +227,10 @@
/datum/design/packageWrap
name = "Package Wrapping"
id = "packagewrap"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 200, MAT_GLASS = 200)
build_path = /obj/item/stack/packageWrap
- category = list("initial", "Misc")
+ category = list("initial", "Misc","Equipment")
maxstack = 30
/datum/design/holodisk
@@ -248,4 +255,4 @@
build_type = AUTOLATHE
materials = list(MAT_METAL = 300, MAT_GLASS = 150)
build_path = /obj/item/key/collar
- category = list("initial", "Misc")
\ No newline at end of file
+ category = list("initial", "Misc")
diff --git a/code/modules/research/designs/autolathe_desings/autolathe_designs_tools.dm b/code/modules/research/designs/autolathe_desings/autolathe_designs_tools.dm
index 0300658a84..c413f546f0 100644
--- a/code/modules/research/designs/autolathe_desings/autolathe_designs_tools.dm
+++ b/code/modules/research/designs/autolathe_desings/autolathe_designs_tools.dm
@@ -7,18 +7,20 @@
/datum/design/bucket
name = "Bucket"
id = "bucket"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 200)
build_path = /obj/item/reagent_containers/glass/bucket
- category = list("initial","Tools")
+ category = list("initial","Tools","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_SERVICE
/datum/design/crowbar
name = "Pocket Crowbar"
id = "crowbar"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 50)
build_path = /obj/item/crowbar
- category = list("initial","Tools")
+ category = list("initial","Tools","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/flashlight
name = "Flashlight"
@@ -63,10 +65,11 @@
/datum/design/tscanner
name = "T-Ray Scanner"
id = "tscanner"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 150)
build_path = /obj/item/t_scanner
- category = list("initial","Tools")
+ category = list("initial","Tools","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
/datum/design/weldingtool
name = "Welding Tool"
@@ -74,7 +77,8 @@
build_type = AUTOLATHE
materials = list(MAT_METAL = 70, MAT_GLASS = 20)
build_path = /obj/item/weldingtool
- category = list("initial","Tools")
+ category = list("initial","Tools","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/mini_weldingtool
name = "Emergency Welding Tool"
@@ -87,26 +91,28 @@
/datum/design/screwdriver
name = "Screwdriver"
id = "screwdriver"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 75)
build_path = /obj/item/screwdriver
- category = list("initial","Tools")
-
+ category = list("initial","Tools","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/wirecutters
name = "Wirecutters"
id = "wirecutters"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 80)
build_path = /obj/item/wirecutters
- category = list("initial","Tools")
+ category = list("initial","Tools","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/wrench
name = "Wrench"
id = "wrench"
- build_type = AUTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(MAT_METAL = 150)
build_path = /obj/item/wrench
- category = list("initial","Tools")
+ category = list("initial","Tools","Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/welding_helmet
name = "Welding Helmet"
@@ -122,8 +128,9 @@
build_type = AUTOLATHE
materials = list(MAT_METAL = 10, MAT_GLASS = 5)
build_path = /obj/item/stack/cable_coil/random
- category = list("initial","Tools")
+ category = list("initial","Tools","Tool Designs")
maxstack = 30
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/toolbox
name = "Toolbox"
diff --git a/code/modules/research/designs/bluespace_designs.dm b/code/modules/research/designs/bluespace_designs.dm
index 064e672d37..84fe526cd8 100644
--- a/code/modules/research/designs/bluespace_designs.dm
+++ b/code/modules/research/designs/bluespace_designs.dm
@@ -53,7 +53,7 @@
materials = list(MAT_DIAMOND = 1500, MAT_PLASMA = 1500)
build_path = /obj/item/stack/ore/bluespace_crystal/artificial
category = list("Bluespace Designs")
- departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
+ departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING
/datum/design/telesci_gps
name = "GPS Device"
diff --git a/code/modules/research/designs/electronics_designs.dm b/code/modules/research/designs/electronics_designs.dm
index f9af852eba..82fd71d895 100644
--- a/code/modules/research/designs/electronics_designs.dm
+++ b/code/modules/research/designs/electronics_designs.dm
@@ -23,6 +23,16 @@
category = list("Electronics")
departmental_flags = DEPARTMENTAL_FLAG_ALL
+/datum/design/ai_cam_upgrade
+ name = "AI Surveillance Software Update"
+ desc = "A software package that will allow an artificial intelligence to 'hear' from its cameras via lip reading."
+ id = "ai_cam_upgrade"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_GLASS = 5000, MAT_GOLD = 15000, MAT_SILVER = 15000, MAT_DIAMOND = 20000, MAT_PLASMA = 10000)
+ build_path = /obj/item/surveillance_upgrade
+ category = list("Electronics")
+ departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
+
///////////////////////////////////
//////////Nanite Devices///////////
///////////////////////////////////
@@ -36,6 +46,16 @@
category = list("Electronics")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
+/datum/design/nanite_comm_remote
+ name = "Nanite Communication Remote"
+ desc = "Allows for the construction of a nanite communication remote."
+ id = "nanite_comm_remote"
+ build_type = PROTOLATHE
+ materials = list(MAT_GLASS = 500, MAT_METAL = 500)
+ build_path = /obj/item/nanite_remote/comm
+ category = list("Electronics")
+ departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
+
/datum/design/nanite_scanner
name = "Nanite Scanner"
desc = "Allows for the construction of a nanite scanner."
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index f2ded3a57b..99cb5bf8ab 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -162,16 +162,6 @@
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
-/datum/design/holobarrier_med
- name = "PENLITE holobarrier projector"
- desc = "PENLITE holobarriers, a device that halts individuals with malicious diseases."
- build_type = PROTOLATHE
- build_path = /obj/item/holosign_creator/medical
- materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 100) //a hint of silver since it can troll 2 antags (bad viros and sentient disease)
- id = "holobarrier_med"
- category = list("Medical Designs")
- departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
-
/datum/design/healthanalyzer_advanced
name = "Advanced Health Analyzer"
desc = "A hand-held body scanner able to distinguish vital signs of the subject with high accuracy."
@@ -182,6 +172,16 @@
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+/datum/design/medspray
+ name = "Medical Spray"
+ desc = "A medical spray bottle, designed for precision application, with an unscrewable cap."
+ id = "medspray"
+ build_path = /obj/item/reagent_containers/medspray
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 2500, MAT_GLASS = 500)
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
/datum/design/medicalkit
name = "Empty Medkit"
desc = "A plastic medical kit for storging medical items."
@@ -217,7 +217,7 @@
desc = "Produce additional disks for storing genetic data."
id = "cloning_disk"
build_type = PROTOLATHE
- materials = list(MAT_METAL = 300, MAT_GLASS = 100, MAT_SILVER=50)
+ materials = list(MAT_METAL = 300, MAT_GLASS = 100, MAT_SILVER = 50)
build_path = /obj/item/disk/data
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
@@ -238,6 +238,7 @@
/datum/design/defibrillator
name = "Defibrillator"
+ desc = "A portable defibrillator, used for resuscitating recently deceased crew."
id = "defibrillator"
build_type = PROTOLATHE
build_path = /obj/item/defibrillator
@@ -257,10 +258,10 @@
/datum/design/defib_heal
name = "Defibrillator Healing disk"
- desc = "An upgrade which increases the healing power of the defibrillator"
+ desc = "An upgrade which increases the healing power of the defibrillator."
id = "defib_heal"
build_type = PROTOLATHE
- materials = list(MAT_METAL=16000, MAT_GLASS = 18000, MAT_GOLD = 6000, MAT_SILVER = 6000)
+ materials = list(MAT_METAL = 16000, MAT_GLASS = 18000, MAT_GOLD = 6000, MAT_SILVER = 6000)
build_path = /obj/item/disk/medical/defib_heal
construction_time = 10
category = list("Misc")
@@ -268,10 +269,10 @@
/datum/design/defib_shock
name = "Defibrillator Anti-Shock Disk"
- desc = "A safety upgrade that guarantees only the patient will get shocked"
+ desc = "A safety upgrade that guarantees only the patient will get shocked."
id = "defib_shock"
build_type = PROTOLATHE
- materials = list(MAT_METAL=16000, MAT_GLASS = 18000, MAT_GOLD = 6000, MAT_SILVER = 6000)
+ materials = list(MAT_METAL = 16000, MAT_GLASS = 18000, MAT_GOLD = 6000, MAT_SILVER = 6000)
build_path = /obj/item/disk/medical/defib_shock
construction_time = 10
category = list("Misc")
@@ -279,10 +280,10 @@
/datum/design/defib_decay
name = "Defibrillator Body-Decay Extender Disk"
- desc = "An upgrade allowing the defibrillator to work on more decayed bodies"
+ desc = "An upgrade allowing the defibrillator to work on more decayed bodies."
id = "defib_decay"
build_type = PROTOLATHE
- materials = list(MAT_METAL=16000, MAT_GLASS = 18000, MAT_GOLD = 16000, MAT_SILVER = 6000, MAT_TITANIUM = 2000)
+ materials = list(MAT_METAL = 16000, MAT_GLASS = 18000, MAT_GOLD = 16000, MAT_SILVER = 6000, MAT_TITANIUM = 2000)
build_path = /obj/item/disk/medical/defib_decay
construction_time = 10
category = list("Misc")
@@ -290,15 +291,23 @@
/datum/design/defib_speed
name = "Defibrillator Fast Charge Disk"
- desc = "An upgrade to the defibrillator capacitors, which let it charge faster"
+ desc = "An upgrade to the defibrillator's capacitors, which lets it charge faster."
id = "defib_speed"
build_type = PROTOLATHE
build_path = /obj/item/disk/medical/defib_speed
- materials = list(MAT_METAL=16000, MAT_GLASS = 8000, MAT_GOLD = 26000, MAT_SILVER = 26000)
+ materials = list(MAT_METAL = 16000, MAT_GLASS = 8000, MAT_GOLD = 26000, MAT_SILVER = 26000)
construction_time = 10
category = list("Misc")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+/datum/design/defibrillator_compact
+ name = "Compact Defibrillator"
+ desc = "A compact defibrillator that can be worn on a belt."
+ id = "defibrillator_compact"
+ build_type = PROTOLATHE
+ build_path = /obj/item/defibrillator/compact
+ materials = list(MAT_METAL = 16000, MAT_GLASS = 8000, MAT_SILVER = 6000, MAT_GOLD = 3000)
+
/////////////////////////////////////////
//////////Cybernetic Implants////////////
/////////////////////////////////////////
@@ -595,115 +604,6 @@
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
-/////////////////////
-//Adv Surgery Tools//
-/////////////////////
-
-/datum/design/drapes
- name = "Plastic Drapes"
- desc = "A large surgery drape made of plastic."
- id = "drapes"
- build_type = PROTOLATHE
- materials = list(MAT_PLASTIC = 2500)
- build_path = /obj/item/surgical_drapes
- category = list("Medical Designs")
- departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
-
-/datum/design/retractor_adv
- name = "Advanced Retractor"
- desc = "An almagation of rods and gears, able to function as both a surgical clamp and retractor. "
- id = "retractor_adv"
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 1500, MAT_GOLD = 1000)
- build_path = /obj/item/retractor/advanced
- category = list("Medical Designs")
- departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
-
-/datum/design/surgicaldrill_adv
- name = "Surgical Laser Drill"
- desc = "It projects a high power laser used for medical applications."
- id = "surgicaldrill_adv"
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 2500, MAT_GLASS = 2500, MAT_SILVER = 6000, MAT_GOLD = 5500, MAT_DIAMOND = 3500)
- build_path = /obj/item/surgicaldrill/advanced
- category = list("Medical Designs")
- departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
-
-/datum/design/scalpel_adv
- name = "Laser Scalpel"
- desc = "An advanced scalpel which uses laser technology to cut."
- id = "scalpel_adv"
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 1500, MAT_GLASS = 1500, MAT_SILVER = 4000, MAT_GOLD = 2500)
- build_path = /obj/item/scalpel/advanced
- category = list("Medical Designs")
- departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
-
-
-/////////////////////////////////////////
-//////////Alien Surgery Tools////////////
-/////////////////////////////////////////
-
-/datum/design/alienscalpel
- name = "Alien Scalpel"
- desc = "An advanced scalpel obtained through Abductor technology."
- id = "alien_scalpel"
- build_path = /obj/item/scalpel/alien
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 2000, MAT_SILVER = 1500, MAT_PLASMA = 500, MAT_TITANIUM = 1500)
- category = list("Medical Designs")
- departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
-
-/datum/design/alienhemostat
- name = "Alien Hemostat"
- desc = "An advanced hemostat obtained through Abductor technology."
- id = "alien_hemostat"
- build_path = /obj/item/hemostat/alien
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 2000, MAT_SILVER = 1500, MAT_PLASMA = 500, MAT_TITANIUM = 1500)
- category = list("Medical Designs")
- departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
-
-/datum/design/alienretractor
- name = "Alien Retractor"
- desc = "An advanced retractor obtained through Abductor technology."
- id = "alien_retractor"
- build_path = /obj/item/retractor/alien
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 2000, MAT_SILVER = 1500, MAT_PLASMA = 500, MAT_TITANIUM = 1500)
- category = list("Medical Designs")
- departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
-
-/datum/design/aliensaw
- name = "Alien Circular Saw"
- desc = "An advanced surgical saw obtained through Abductor technology."
- id = "alien_saw"
- build_path = /obj/item/circular_saw/alien
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 10000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 1500)
- category = list("Medical Designs")
- departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
-
-/datum/design/aliendrill
- name = "Alien Drill"
- desc = "An advanced drill obtained through Abductor technology."
- id = "alien_drill"
- build_path = /obj/item/surgicaldrill/alien
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 10000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 1500)
- category = list("Medical Designs")
- departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
-
-/datum/design/aliencautery
- name = "Alien Cautery"
- desc = "An advanced cautery obtained through Abductor technology."
- id = "alien_cautery"
- build_path = /obj/item/cautery/alien
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 2000, MAT_SILVER = 1500, MAT_PLASMA = 500, MAT_TITANIUM = 1500)
- category = list("Medical Designs")
- departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
-
/datum/design/cybernetic_ears
name = "Cybernetic Ears"
desc = "A pair of cybernetic ears."
diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm
index b18db566af..54a7af8f8c 100644
--- a/code/modules/research/designs/misc_designs.dm
+++ b/code/modules/research/designs/misc_designs.dm
@@ -257,7 +257,7 @@
departmental_flags = DEPARTMENTAL_FLAG_SERVICE
/datum/design/roastingstick
- name = "Advanced roasting stick"
+ name = "Advanced Roasting Stick"
desc = "A roasting stick for cooking sausages in exotic ovens."
id = "roastingstick"
build_type = PROTOLATHE
@@ -267,7 +267,7 @@
departmental_flags = DEPARTMENTAL_FLAG_SERVICE
/datum/design/locator
- name = "Bluespace locator"
+ name = "Bluespace Locator"
desc = "Used to track portable teleportation beacons and targets with embedded tracking implants."
id = "locator"
build_type = PROTOLATHE
@@ -276,6 +276,15 @@
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+/datum/design/donksoft_refill
+ name = "Donksoft Toy Vendor Refill"
+ desc = "A refill canister for Donksoft Toy Vendors."
+ id = "donksoft_refill"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 25000, MAT_GLASS = 15000, MAT_PLASMA = 20000, MAT_GOLD = 10000, MAT_SILVER = 10000)
+ build_path = /obj/item/vending_refill/donksoft
+ category = list("Equipment")
+
/////////////////////////////////////////
////////////Janitor Designs//////////////
/////////////////////////////////////////
@@ -320,8 +329,28 @@
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_SERVICE
+/datum/design/spraybottle
+ name = "Spray Bottle"
+ desc = "A spray bottle, with an unscrewable top."
+ id = "spraybottle"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 3000, MAT_GLASS = 200)
+ build_path = /obj/item/reagent_containers/spray
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_SERVICE
+
+/datum/design/beartrap
+ name = "Bear Trap"
+ desc = "A trap used to catch space bears and other legged creatures."
+ id = "beartrap"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_TITANIUM = 1000)
+ build_path = /obj/item/restraints/legcuffs/beartrap
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_SERVICE
+
/////////////////////////////////////////
-////////////Holosign Designs//////////////
+////////////Holosign Designs/////////////
/////////////////////////////////////////
/datum/design/holosign
@@ -384,141 +413,20 @@
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+/datum/design/holobarrier_med
+ name = "PENLITE holobarrier projector"
+ desc = "PENLITE holobarriers, a device that halts individuals with malicious diseases."
+ build_type = PROTOLATHE
+ build_path = /obj/item/holosign_creator/medical
+ materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 100) //a hint of silver since it can troll 2 antags (bad viros and sentient disease)
+ id = "holobarrier_med"
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
///////////////////////////////
////////////Tools//////////////
///////////////////////////////
-/datum/design/rcd_upgrade/frames
- name = "RCD frames designs upgrade"
- desc = "Adds the computer frame and machine frame to the RCD."
- id = "rcd_upgrade_frames"
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 5000, MAT_GLASS = 2500, MAT_SILVER = 1500, MAT_TITANIUM = 2000)
- build_path = /obj/item/rcd_upgrade/frames
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/rcd_upgrade/simple_circuits
- name = "RCD simple circuits designs upgrade"
- desc = "Adds the simple circuits to the RCD."
- id = "rcd_upgrade_simple_circuits"
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 5000, MAT_GLASS = 2500, MAT_SILVER = 1500, MAT_TITANIUM = 2000)
- build_path = /obj/item/rcd_upgrade/simple_circuits
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/exwelder
- name = "Experimental Welding Tool"
- desc = "An experimental welder capable of self-fuel generation."
- id = "exwelder"
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 1000, MAT_GLASS = 500, MAT_PLASMA = 1500, MAT_URANIUM = 200)
- build_path = /obj/item/weldingtool/experimental
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/handdrill
- name = "Hand Drill"
- desc = "A small electric hand drill with an interchangeable screwdriver and bolt bit"
- id = "handdrill"
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 3500, MAT_SILVER = 1500, MAT_TITANIUM = 2500)
- build_path = /obj/item/screwdriver/power
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/jawsoflife
- name = "Jaws of Life"
- desc = "A small, compact Jaws of Life with an interchangeable pry jaws and cutting jaws"
- id = "jawsoflife" // added one more requirment since the Jaws of Life are a bit OP
- build_path = /obj/item/crowbar/power
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 4500, MAT_SILVER = 2500, MAT_TITANIUM = 3500)
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/rcd_loaded
- name = "Rapid Construction Device"
- desc = "A tool that can construct and deconstruct walls, airlocks and floors on the fly."
- id = "rcd_loaded"
- build_type = PROTOLATHE
- materials = list(MAT_METAL = MINERAL_MATERIAL_AMOUNT, MAT_GLASS = MINERAL_MATERIAL_AMOUNT) // costs more than what it did in the autolathe, this one comes loaded.
- build_path = /obj/item/construction/rcd/loaded
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/rpd
- name = "Rapid Pipe Dispenser"
- desc = "A tool that can construct and deconstruct pipes on the fly."
- id = "rpd"
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 75000, MAT_GLASS = 37500)
- build_path = /obj/item/pipe_dispenser
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/alienwrench
- name = "Alien Wrench"
- desc = "An advanced wrench obtained through Abductor technology."
- id = "alien_wrench"
- build_path = /obj/item/wrench/abductor
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/alienwirecutters
- name = "Alien Wirecutters"
- desc = "Advanced wirecutters obtained through Abductor technology."
- id = "alien_wirecutters"
- build_path = /obj/item/wirecutters/abductor
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/alienscrewdriver
- name = "Alien Screwdriver"
- desc = "An advanced screwdriver obtained through Abductor technology."
- id = "alien_screwdriver"
- build_path = /obj/item/screwdriver/abductor
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/aliencrowbar
- name = "Alien Crowbar"
- desc = "An advanced crowbar obtained through Abductor technology."
- id = "alien_crowbar"
- build_path = /obj/item/crowbar/abductor
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/alienwelder
- name = "Alien Welding Tool"
- desc = "An advanced welding tool obtained through Abductor technology."
- id = "alien_welder"
- build_path = /obj/item/weldingtool/abductor
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 5000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/alienmultitool
- name = "Alien Multitool"
- desc = "An advanced multitool obtained through Abductor technology."
- id = "alien_multitool"
- build_path = /obj/item/multitool/abductor
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 5000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
/datum/design/quantum_keycard
name = "Quantum Keycard"
desc = "Allows for the construction of a quantum keycard."
@@ -550,7 +458,7 @@
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/////////////////////////////////////////
-////////////Armour///////////////////////
+/////////////////Armour//////////////////
/////////////////////////////////////////
/datum/design/reactive_armour
@@ -564,7 +472,71 @@
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING
/////////////////////////////////////////
-////////////Meteor///////////////////////
+/////////////Security////////////////////
+/////////////////////////////////////////
+
+/datum/design/seclite
+ name = "Seclite"
+ desc = "A robust flashlight used by security."
+ id = "seclite"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 2500)
+ build_path = /obj/item/flashlight/seclite
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
+/datum/design/detective_scanner
+ name = "Forensic Scanner"
+ desc = "Used to remotely scan objects and biomass for DNA and fingerprints. Can print a report of the findings."
+ id = "detective_scanner"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_GLASS = 1000, MAT_GOLD = 2500, MAT_SILVER = 2000)
+ build_path = /obj/item/detective_scanner
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
+/datum/design/pepperspray
+ name = "Pepper Spray"
+ desc = "Manufactured by UhangInc, used to blind and down an opponent quickly. Printed pepper sprays do not contain reagents."
+ id = "pepperspray"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_GLASS = 1000)
+ build_path = /obj/item/reagent_containers/spray/pepper/empty
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
+/datum/design/bola_energy
+ name = "Energy Bola"
+ desc = "A specialized hard-light bola designed to ensnare fleeing criminals and aid in arrests."
+ id = "bola_energy"
+ build_type = PROTOLATHE
+ materials = list(MAT_SILVER = 500, MAT_PLASMA = 500, MAT_TITANIUM = 500)
+ build_path = /obj/item/restraints/legcuffs/bola/energy
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
+/datum/design/zipties
+ name = "Zipties"
+ desc = "Plastic, disposable zipties that can be used to restrain temporarily but are destroyed after use."
+ id = "zipties"
+ build_type = PROTOLATHE
+ materials = list(MAT_PLASTIC = 250)
+ build_path = /obj/item/restraints/handcuffs/cable/zipties
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
+/datum/design/evidencebag
+ name = "Evidence Bag"
+ desc = "An empty evidence bag."
+ id = "evidencebag"
+ build_type = PROTOLATHE
+ materials = list(MAT_PLASTIC = 100)
+ build_path = /obj/item/evidencebag
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
+/////////////////////////////////////////
+/////////////////Meteors/////////////////
/////////////////////////////////////////
/datum/design/meteor_defence
diff --git a/code/modules/research/designs/nanite_designs.dm b/code/modules/research/designs/nanite_designs.dm
index 09fe1d9c9b..13668ba570 100644
--- a/code/modules/research/designs/nanite_designs.dm
+++ b/code/modules/research/designs/nanite_designs.dm
@@ -380,7 +380,7 @@
name = "Mind Control"
desc = "The nanites imprint an absolute directive onto the host's brain while they're active."
id = "mindcontrol_nanites"
- program_type = /datum/nanite_program/mind_control
+ program_type = /datum/nanite_program/triggered/comm/mind_control
category = list("Weaponized Nanites")
////////////////////SUPPRESSION NANITES//////////////////////////////////////
@@ -445,21 +445,35 @@
name = "Skull Echo"
desc = "The nanites echo a synthesized message inside the host's skull."
id = "voice_nanites"
- program_type = /datum/nanite_program/triggered/voice
+ program_type = /datum/nanite_program/triggered/comm/voice
category = list("Suppression Nanites")
/datum/design/nanites/speech
name = "Forced Speech"
desc = "The nanites force the host to say a pre-programmed sentence when triggered."
id = "speech_nanites"
- program_type = /datum/nanite_program/triggered/speech
+ program_type = /datum/nanite_program/triggered/comm/speech
category = list("Suppression Nanites")
/datum/design/nanites/hallucination
name = "Hallucination"
desc = "The nanites make the host see and hear things that aren't real."
id = "hallucination_nanites"
- program_type = /datum/nanite_program/triggered/hallucination
+ program_type = /datum/nanite_program/triggered/comm/hallucination
+ category = list("Suppression Nanites")
+
+/datum/design/nanites/good_mood
+ name = "Happiness Enhancer"
+ desc = "The nanites synthesize serotonin inside the host's brain, creating an artificial sense of happiness."
+ id = "good_mood_nanites"
+ program_type = /datum/nanite_program/good_mood
+ category = list("Suppression Nanites")
+
+/datum/design/nanites/bad_mood
+ name = "Happiness Suppressor"
+ desc = "The nanites suppress the production of serotonin inside the host's brain, creating an artificial state of depression."
+ id = "bad_mood_nanites"
+ program_type = /datum/nanite_program/bad_mood
category = list("Suppression Nanites")
////////////////////SENSOR NANITES//////////////////////////////////////
diff --git a/code/modules/research/designs/smelting_designs.dm b/code/modules/research/designs/smelting_designs.dm
index c2cbb5685e..64dcb5f754 100644
--- a/code/modules/research/designs/smelting_designs.dm
+++ b/code/modules/research/designs/smelting_designs.dm
@@ -68,4 +68,4 @@
materials = list(MAT_METAL = 4000, MAT_PLASMA = 4000)
build_path = /obj/item/stack/sheet/mineral/abductor
category = list("Stock Parts")
- departmental_flags = DEPARTMENTAL_FLAG_CARGO | DEPARTMENTAL_FLAG_SCIENCE
+ departmental_flags = DEPARTMENTAL_FLAG_CARGO | DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING
diff --git a/code/modules/research/designs/tool_designs.dm b/code/modules/research/designs/tool_designs.dm
new file mode 100644
index 0000000000..300fe6c68a
--- /dev/null
+++ b/code/modules/research/designs/tool_designs.dm
@@ -0,0 +1,246 @@
+/////////////////////////////////////////
+/////////////////Tools///////////////////
+/////////////////////////////////////////
+
+/datum/design/rcd_upgrade/frames
+ name = "RCD frames designs upgrade"
+ desc = "Adds the computer frame and machine frame to the RCD."
+ id = "rcd_upgrade_frames"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_GLASS = 2500, MAT_SILVER = 1500, MAT_TITANIUM = 2000)
+ build_path = /obj/item/rcd_upgrade/frames
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/rcd_upgrade/simple_circuits
+ name = "RCD simple circuits designs upgrade"
+ desc = "Adds the simple circuits to the RCD."
+ id = "rcd_upgrade_simple_circuits"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_GLASS = 2500, MAT_SILVER = 1500, MAT_TITANIUM = 2000)
+ build_path = /obj/item/rcd_upgrade/simple_circuits
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/rcd_loaded
+ name = "Rapid Construction Device"
+ desc = "A tool that can construct and deconstruct walls, airlocks and floors on the fly."
+ id = "rcd_loaded"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = MINERAL_MATERIAL_AMOUNT, MAT_GLASS = MINERAL_MATERIAL_AMOUNT) // costs more than what it did in the autolathe, this one comes loaded.
+ build_path = /obj/item/construction/rcd/loaded
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/rpd
+ name = "Rapid Pipe Dispenser"
+ desc = "A tool that can construct and deconstruct pipes on the fly."
+ id = "rpd"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 75000, MAT_GLASS = 37500)
+ build_path = /obj/item/pipe_dispenser
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/handdrill
+ name = "Hand Drill"
+ desc = "A small electric hand drill with an interchangeable screwdriver and bolt bit"
+ id = "handdrill"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 3500, MAT_SILVER = 1500, MAT_TITANIUM = 2500)
+ build_path = /obj/item/screwdriver/power
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/jawsoflife
+ name = "Jaws of Life"
+ desc = "A small, compact Jaws of Life with an interchangeable pry jaws and cutting jaws"
+ id = "jawsoflife" // added one more requirment since the Jaws of Life are a bit OP
+ build_path = /obj/item/crowbar/power
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 4500, MAT_SILVER = 2500, MAT_TITANIUM = 3500)
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/exwelder
+ name = "Experimental Welding Tool"
+ desc = "An experimental welder capable of self-fuel generation."
+ id = "exwelder"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 1000, MAT_GLASS = 500, MAT_PLASMA = 1500, MAT_URANIUM = 200)
+ build_path = /obj/item/weldingtool/experimental
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING
+
+/////////////////////////////////////////
+//////////////Alien Tools////////////////
+/////////////////////////////////////////
+
+/datum/design/alienwrench
+ name = "Alien Wrench"
+ desc = "An advanced wrench obtained through Abductor technology."
+ id = "alien_wrench"
+ build_path = /obj/item/wrench/abductor
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/alienwirecutters
+ name = "Alien Wirecutters"
+ desc = "Advanced wirecutters obtained through Abductor technology."
+ id = "alien_wirecutters"
+ build_path = /obj/item/wirecutters/abductor
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/alienscrewdriver
+ name = "Alien Screwdriver"
+ desc = "An advanced screwdriver obtained through Abductor technology."
+ id = "alien_screwdriver"
+ build_path = /obj/item/screwdriver/abductor
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/aliencrowbar
+ name = "Alien Crowbar"
+ desc = "An advanced crowbar obtained through Abductor technology."
+ id = "alien_crowbar"
+ build_path = /obj/item/crowbar/abductor
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/alienwelder
+ name = "Alien Welding Tool"
+ desc = "An advanced welding tool obtained through Abductor technology."
+ id = "alien_welder"
+ build_path = /obj/item/weldingtool/abductor
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 5000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/alienmultitool
+ name = "Alien Multitool"
+ desc = "An advanced multitool obtained through Abductor technology."
+ id = "alien_multitool"
+ build_path = /obj/item/multitool/abductor
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 5000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/////////////////////////////////////////
+/////////Alien Surgical Tools////////////
+/////////////////////////////////////////
+
+/datum/design/alienscalpel
+ name = "Alien Scalpel"
+ desc = "An advanced scalpel obtained through Abductor technology."
+ id = "alien_scalpel"
+ build_path = /obj/item/scalpel/alien
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 2000, MAT_SILVER = 1500, MAT_PLASMA = 500, MAT_TITANIUM = 1500)
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
+/datum/design/alienhemostat
+ name = "Alien Hemostat"
+ desc = "An advanced hemostat obtained through Abductor technology."
+ id = "alien_hemostat"
+ build_path = /obj/item/hemostat/alien
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 2000, MAT_SILVER = 1500, MAT_PLASMA = 500, MAT_TITANIUM = 1500)
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
+/datum/design/alienretractor
+ name = "Alien Retractor"
+ desc = "An advanced retractor obtained through Abductor technology."
+ id = "alien_retractor"
+ build_path = /obj/item/retractor/alien
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 2000, MAT_SILVER = 1500, MAT_PLASMA = 500, MAT_TITANIUM = 1500)
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
+/datum/design/aliensaw
+ name = "Alien Circular Saw"
+ desc = "An advanced surgical saw obtained through Abductor technology."
+ id = "alien_saw"
+ build_path = /obj/item/circular_saw/alien
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 10000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 1500)
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
+/datum/design/aliendrill
+ name = "Alien Drill"
+ desc = "An advanced drill obtained through Abductor technology."
+ id = "alien_drill"
+ build_path = /obj/item/surgicaldrill/alien
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 10000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 1500)
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
+/datum/design/aliencautery
+ name = "Alien Cautery"
+ desc = "An advanced cautery obtained through Abductor technology."
+ id = "alien_cautery"
+ build_path = /obj/item/cautery/alien
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 2000, MAT_SILVER = 1500, MAT_PLASMA = 500, MAT_TITANIUM = 1500)
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
+
+//////////////////////
+//Adv. Surgery Tools//
+//////////////////////
+
+/datum/design/drapes
+ name = "Plastic Drapes"
+ desc = "A large surgery drape made of plastic."
+ id = "drapes"
+ build_type = PROTOLATHE
+ materials = list(MAT_PLASTIC = 2500)
+ build_path = /obj/item/surgical_drapes
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/retractor_adv
+ name = "Advanced Retractor"
+ desc = "An almagation of rods and gears, able to function as both a surgical clamp and retractor. "
+ id = "retractor_adv"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 1500, MAT_GOLD = 1000)
+ build_path = /obj/item/retractor/advanced
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/surgicaldrill_adv
+ name = "Surgical Laser Drill"
+ desc = "It projects a high power laser used for medical applications."
+ id = "surgicaldrill_adv"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 2500, MAT_GLASS = 2500, MAT_SILVER = 6000, MAT_GOLD = 5500, MAT_DIAMOND = 3500)
+ build_path = /obj/item/surgicaldrill/advanced
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/scalpel_adv
+ name = "Laser Scalpel"
+ desc = "An advanced scalpel which uses laser technology to cut."
+ id = "scalpel_adv"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 1500, MAT_GLASS = 1500, MAT_SILVER = 4000, MAT_GOLD = 2500)
+ build_path = /obj/item/scalpel/advanced
+ category = list("Tool Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
diff --git a/code/modules/research/machinery/protolathe.dm b/code/modules/research/machinery/protolathe.dm
index 2467def64e..684f27ccad 100644
--- a/code/modules/research/machinery/protolathe.dm
+++ b/code/modules/research/machinery/protolathe.dm
@@ -9,6 +9,7 @@
"Bluespace Designs",
"Stock Parts",
"Equipment",
+ "Tool Designs",
"Mining Designs",
"Electronics",
"Weapons",
@@ -21,4 +22,4 @@
/obj/machinery/rnd/production/protolathe/disconnect_console()
linked_console.linked_lathe = null
- ..()
\ No newline at end of file
+ ..()
diff --git a/code/modules/research/machinery/techfab.dm b/code/modules/research/machinery/techfab.dm
index 0e809fa0e1..885f27c2cb 100644
--- a/code/modules/research/machinery/techfab.dm
+++ b/code/modules/research/machinery/techfab.dm
@@ -9,6 +9,7 @@
"Bluespace Designs",
"Stock Parts",
"Equipment",
+ "Tool Designs",
"Mining Designs",
"Electronics",
"Weapons",
@@ -31,4 +32,4 @@
production_animation = "protolathe_n"
requires_console = FALSE
consoleless_interface = TRUE
- allowed_buildtypes = PROTOLATHE | IMPRINTER
\ No newline at end of file
+ allowed_buildtypes = PROTOLATHE | IMPRINTER
diff --git a/code/modules/research/nanites/nanite_programs/healing.dm b/code/modules/research/nanites/nanite_programs/healing.dm
index ad48b64baa..df439e4496 100644
--- a/code/modules/research/nanites/nanite_programs/healing.dm
+++ b/code/modules/research/nanites/nanite_programs/healing.dm
@@ -3,7 +3,7 @@
/datum/nanite_program/regenerative
name = "Accelerated Regeneration"
desc = "The nanites boost the host's natural regeneration, increasing their healing speed. Does not consume nanites if the host is unharmed."
- use_rate = 2.5
+ use_rate = 0.5
rogue_types = list(/datum/nanite_program/necrotic)
/datum/nanite_program/regenerative/check_conditions()
@@ -23,11 +23,11 @@
if(!parts.len)
return
for(var/obj/item/bodypart/L in parts)
- if(L.heal_damage(1/parts.len, 1/parts.len))
+ if(L.heal_damage(0.5/parts.len, 0.5/parts.len, null, BODYPART_ORGANIC))
host_mob.update_damage_overlays()
else
- host_mob.adjustBruteLoss(-1, TRUE)
- host_mob.adjustFireLoss(-1, TRUE)
+ host_mob.adjustBruteLoss(-0.5, TRUE)
+ host_mob.adjustFireLoss(-0.5, TRUE)
/datum/nanite_program/temperature
name = "Temperature Adjustment"
@@ -112,7 +112,7 @@
/datum/nanite_program/repairing
name = "Mechanical Repair"
desc = "The nanites fix damage in the host's mechanical limbs."
- use_rate = 0.5 //much more efficient than organic healing
+ use_rate = 0.5
rogue_types = list(/datum/nanite_program/necrotic)
/datum/nanite_program/repairing/check_conditions()
@@ -137,13 +137,13 @@
return
var/update = FALSE
for(var/obj/item/bodypart/L in parts)
- if(L.heal_damage(1/parts.len, 1/parts.len, only_robotic = TRUE, only_organic = FALSE))
+ if(L.heal_damage(1.5/parts.len, 1.5/parts.len, null, BODYPART_ROBOTIC)) //much faster than organic healing
update = TRUE
if(update)
host_mob.update_damage_overlays()
else
- host_mob.adjustBruteLoss(-1, TRUE)
- host_mob.adjustFireLoss(-1, TRUE)
+ host_mob.adjustBruteLoss(-1.5, TRUE)
+ host_mob.adjustFireLoss(-1.5, TRUE)
/datum/nanite_program/purging_advanced
name = "Selective Blood Purification"
diff --git a/code/modules/research/nanites/nanite_programs/suppression.dm b/code/modules/research/nanites/nanite_programs/suppression.dm
index a6225fd337..ad5706f88c 100644
--- a/code/modules/research/nanites/nanite_programs/suppression.dm
+++ b/code/modules/research/nanites/nanite_programs/suppression.dm
@@ -114,7 +114,19 @@
. = ..()
host_mob.cure_fakedeath("nanites")
-/datum/nanite_program/triggered/speech
+//Can receive transmissions from a nanite communication remote for customized messages
+/datum/nanite_program/triggered/comm
+ var/comm_code = 0
+ var/comm_message = ""
+
+/datum/nanite_program/triggered/comm/proc/receive_comm_signal(signal_comm_code, comm_message, comm_source)
+ if(!activated || !comm_code)
+ return
+ if(signal_comm_code == comm_code)
+ host_mob.investigate_log("'s [name] nanite program was messaged by [comm_source] with comm code [signal_comm_code] and message '[comm_message]'.", INVESTIGATE_NANITES)
+ trigger(comm_message)
+
+/datum/nanite_program/triggered/comm/speech
name = "Forced Speech"
desc = "The nanites force the host to say a pre-programmed sentence when triggered."
unique = FALSE
@@ -122,10 +134,10 @@
trigger_cooldown = 20
rogue_types = list(/datum/nanite_program/brain_misfire, /datum/nanite_program/brain_decay)
- extra_settings = list("Sentence")
+ extra_settings = list("Sentence","Comm Code")
var/sentence = ""
-/datum/nanite_program/triggered/speech/set_extra_setting(user, setting)
+/datum/nanite_program/triggered/comm/speech/set_extra_setting(user, setting)
if(setting == "Sentence")
var/new_sentence = stripped_input(user, "Choose the sentence that the host will be forced to say.", "Sentence", sentence, MAX_MESSAGE_LEN)
if(!new_sentence)
@@ -133,23 +145,34 @@
if(copytext(new_sentence, 1, 2) == "*") //emotes are abusable, like surrender
return
sentence = new_sentence
+ if(setting == "Comm Code")
+ var/new_code = input(user, "Set the communication code (1-9999) or set to 0 to disable external signals.", name, null) as null|num
+ if(isnull(new_code))
+ return
+ comm_code = CLAMP(round(new_code, 1), 0, 9999)
-/datum/nanite_program/triggered/speech/get_extra_setting(setting)
+/datum/nanite_program/triggered/comm/speech/get_extra_setting(setting)
if(setting == "Sentence")
return sentence
+ if(setting == "Comm Code")
+ return comm_code
-/datum/nanite_program/triggered/speech/copy_extra_settings_to(datum/nanite_program/triggered/speech/target)
+/datum/nanite_program/triggered/comm/speech/copy_extra_settings_to(datum/nanite_program/triggered/comm/speech/target)
target.sentence = sentence
+ target.comm_code = comm_code
-/datum/nanite_program/triggered/speech/trigger()
+/datum/nanite_program/triggered/comm/speech/trigger(comm_message)
if(!..())
return
+ var/sent_message = comm_message
+ if(!comm_message)
+ sent_message = sentence
if(host_mob.stat == DEAD)
return
to_chat(host_mob, "You feel compelled to speak...")
- host_mob.say(sentence, forced = "nanite speech")
+ host_mob.say(sent_message, forced = "nanite speech")
-/datum/nanite_program/triggered/voice
+/datum/nanite_program/triggered/comm/voice
name = "Skull Echo"
desc = "The nanites echo a synthesized message inside the host's skull."
unique = FALSE
@@ -157,44 +180,62 @@
trigger_cooldown = 20
rogue_types = list(/datum/nanite_program/brain_misfire, /datum/nanite_program/brain_decay)
- extra_settings = list("Message")
+ extra_settings = list("Message","Comm Code")
var/message = ""
-/datum/nanite_program/triggered/voice/set_extra_setting(user, setting)
+/datum/nanite_program/triggered/comm/voice/set_extra_setting(user, setting)
if(setting == "Message")
var/new_message = stripped_input(user, "Choose the message sent to the host.", "Message", message, MAX_MESSAGE_LEN)
if(!new_message)
return
message = new_message
+ if(setting == "Comm Code")
+ var/new_code = input(user, "Set the communication code (1-9999) or set to 0 to disable external signals.", name, null) as null|num
+ if(isnull(new_code))
+ return
+ comm_code = CLAMP(round(new_code, 1), 0, 9999)
-/datum/nanite_program/triggered/voice/get_extra_setting(setting)
+/datum/nanite_program/triggered/comm/voice/get_extra_setting(setting)
if(setting == "Message")
return message
+ if(setting == "Comm Code")
+ return comm_code
-/datum/nanite_program/triggered/voice/copy_extra_settings_to(datum/nanite_program/triggered/voice/target)
+/datum/nanite_program/triggered/comm/voice/copy_extra_settings_to(datum/nanite_program/triggered/comm/voice/target)
target.message = message
+ target.comm_code = comm_code
-/datum/nanite_program/triggered/voice/trigger()
+/datum/nanite_program/triggered/comm/voice/trigger(comm_message)
if(!..())
return
+ var/sent_message = comm_message
+ if(!comm_message)
+ sent_message = message
if(host_mob.stat == DEAD)
return
- to_chat(host_mob, "You hear a strange, robotic voice in your head... \"[message]\"")
+ to_chat(host_mob, "You hear a strange, robotic voice in your head... \"[sent_message]\"")
-/datum/nanite_program/triggered/hallucination
+/datum/nanite_program/triggered/comm/hallucination
name = "Hallucination"
desc = "The nanites make the host hallucinate something when triggered."
trigger_cost = 4
trigger_cooldown = 80
unique = FALSE
rogue_types = list(/datum/nanite_program/brain_misfire)
- extra_settings = list("Hallucination Type")
+ extra_settings = list("Hallucination Type", "Comm Code")
var/hal_type
var/hal_details
-/datum/nanite_program/triggered/hallucination/trigger()
+/datum/nanite_program/triggered/comm/hallucination/trigger(comm_message)
if(!..())
return
+
+ if(comm_message && (hal_type != "Message")) //Triggered via comm remote, but not set to a message hallucination
+ return
+ var/sent_message = comm_message //Comm remotes can send custom hallucination messages for the chat hallucination
+ if(!sent_message)
+ sent_message = hal_details
+
if(!iscarbon(host_mob))
return
var/mob/living/carbon/C = host_mob
@@ -203,7 +244,7 @@
else
switch(hal_type)
if("Message")
- new /datum/hallucination/chat(C, TRUE, null, hal_details)
+ new /datum/hallucination/chat(C, TRUE, null, sent_message)
if("Battle")
new /datum/hallucination/battle(C, TRUE, hal_details)
if("Sound")
@@ -223,7 +264,13 @@
if("Plasma Flood")
new /datum/hallucination/fake_flood(C, TRUE)
-/datum/nanite_program/triggered/hallucination/set_extra_setting(user, setting)
+/datum/nanite_program/triggered/comm/hallucination/set_extra_setting(user, setting)
+ if(setting == "Comm Code")
+ var/new_code = input(user, "(Only for Message) Set the communication code (1-9999) or set to 0 to disable external signals.", name, null) as null|num
+ if(isnull(new_code))
+ return
+ comm_code = CLAMP(round(new_code, 1), 0, 9999)
+
if(setting == "Hallucination Type")
var/list/possible_hallucinations = list("Random","Message","Battle","Sound","Weird Sound","Station Message","Health","Alert","Fire","Shock","Plasma Flood")
var/hal_type_choice = input("Choose the hallucination type", name) as null|anything in possible_hallucinations
@@ -299,13 +346,76 @@
if("Plasma Flood")
hal_type = "Plasma Flood"
-/datum/nanite_program/triggered/hallucination/get_extra_setting(setting)
+/datum/nanite_program/triggered/comm/hallucination/get_extra_setting(setting)
if(setting == "Hallucination Type")
if(!hal_type)
return "Random"
else
return hal_type
+ if(setting == "Comm Code")
+ return comm_code
-/datum/nanite_program/triggered/hallucination/copy_extra_settings_to(datum/nanite_program/triggered/hallucination/target)
+/datum/nanite_program/triggered/comm/hallucination/copy_extra_settings_to(datum/nanite_program/triggered/comm/hallucination/target)
target.hal_type = hal_type
- target.hal_details = hal_details
\ No newline at end of file
+ target.hal_details = hal_details
+ target.comm_code = comm_code
+
+/datum/nanite_program/good_mood
+ name = "Happiness Enhancer"
+ desc = "The nanites synthesize serotonin inside the host's brain, creating an artificial sense of happiness."
+ use_rate = 0.1
+ rogue_types = list(/datum/nanite_program/brain_decay)
+ extra_settings = list("Mood Message")
+ var/message = "HAPPINESS ENHANCEMENT"
+
+/datum/nanite_program/good_mood/set_extra_setting(user, setting)
+ if(setting == "Mood Message")
+ var/new_message = stripped_input(user, "Choose the message visible on the mood effect.", "Message", message, MAX_NAME_LEN)
+ if(!new_message)
+ return
+ message = new_message
+
+/datum/nanite_program/good_mood/get_extra_setting(setting)
+ if(setting == "Mood Message")
+ return message
+
+/datum/nanite_program/good_mood/copy_extra_settings_to(datum/nanite_program/good_mood/target)
+ target.message = message
+
+/datum/nanite_program/good_mood/enable_passive_effect()
+ . = ..()
+ SEND_SIGNAL(host_mob, COMSIG_ADD_MOOD_EVENT, "nanite_happy", /datum/mood_event/nanite_happiness, message)
+
+/datum/nanite_program/good_mood/disable_passive_effect()
+ . = ..()
+ SEND_SIGNAL(host_mob, COMSIG_CLEAR_MOOD_EVENT, "nanite_happy")
+
+/datum/nanite_program/bad_mood
+ name = "Happiness Suppressor"
+ desc = "The nanites suppress the production of serotonin inside the host's brain, creating an artificial state of depression."
+ use_rate = 0.1
+ rogue_types = list(/datum/nanite_program/brain_decay)
+ extra_settings = list("Mood Message")
+ var/message = "HAPPINESS SUPPRESSION"
+
+/datum/nanite_program/bad_mood/set_extra_setting(user, setting)
+ if(setting == "Mood Message")
+ var/new_message = stripped_input(user, "Choose the message visible on the mood effect.", "Message", message, MAX_NAME_LEN)
+ if(!new_message)
+ return
+ message = new_message
+
+/datum/nanite_program/bad_mood/get_extra_setting(setting)
+ if(setting == "Mood Message")
+ return message
+
+/datum/nanite_program/bad_mood/copy_extra_settings_to(datum/nanite_program/bad_mood/target)
+ target.message = message
+
+/datum/nanite_program/bad_mood/enable_passive_effect()
+ . = ..()
+ SEND_SIGNAL(host_mob, COMSIG_ADD_MOOD_EVENT, "nanite_sadness", /datum/mood_event/nanite_sadness, message)
+
+/datum/nanite_program/bad_mood/disable_passive_effect()
+ . = ..()
+ SEND_SIGNAL(host_mob, COMSIG_CLEAR_MOOD_EVENT, "nanite_sadness")
diff --git a/code/modules/research/nanites/nanite_programs/utility.dm b/code/modules/research/nanites/nanite_programs/utility.dm
index 3db482d989..46f5de168f 100644
--- a/code/modules/research/nanites/nanite_programs/utility.dm
+++ b/code/modules/research/nanites/nanite_programs/utility.dm
@@ -6,6 +6,7 @@
rogue_types = list(/datum/nanite_program/toxic)
extra_settings = list("Program Overwrite","Cloud Overwrite")
+ var/pulse_cooldown = 0
var/sync_programs = TRUE
var/sync_overwrite = FALSE
var/overwrite_cloud = FALSE
@@ -67,12 +68,16 @@
target.sync_overwrite = sync_overwrite
/datum/nanite_program/viral/active_effect()
+ if(world.time < pulse_cooldown)
+ return
for(var/mob/M in orange(host_mob, 5))
- if(prob(5))
- if(sync_programs)
- SEND_SIGNAL(M, COMSIG_NANITE_SYNC, nanites, sync_overwrite)
- if(overwrite_cloud)
- SEND_SIGNAL(M, COMSIG_NANITE_SET_CLOUD, set_cloud)
+ if(SEND_SIGNAL(M, COMSIG_NANITE_IS_STEALTHY))
+ continue
+ if(sync_programs)
+ SEND_SIGNAL(M, COMSIG_NANITE_SYNC, nanites, sync_overwrite)
+ if(overwrite_cloud)
+ SEND_SIGNAL(M, COMSIG_NANITE_SET_CLOUD, set_cloud)
+ pulse_cooldown = world.time + 75
/datum/nanite_program/monitoring
name = "Monitoring"
@@ -197,6 +202,15 @@
return
SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, code, source)
+/datum/nanite_program/relay/proc/relay_comm_signal(comm_code, relay_code, comm_message)
+ if(!activated)
+ return
+ if(!host_mob)
+ return
+ if(relay_code != relay_channel)
+ return
+ SEND_SIGNAL(host_mob, COMSIG_NANITE_COMM_SIGNAL, comm_code, comm_message)
+
/datum/nanite_program/metabolic_synthesis
name = "Metabolic Synthesis"
desc = "The nanites use the metabolic cycle of the host to speed up their replication rate, using their extra nutrition as fuel."
@@ -248,26 +262,27 @@
resulting in an extremely infective strain of nanites."
use_rate = 1.50
rogue_types = list(/datum/nanite_program/aggressive_replication, /datum/nanite_program/necrotic)
+ var/spread_cooldown = 0
/datum/nanite_program/spreading/active_effect()
- if(prob(10))
- var/list/mob/living/target_hosts = list()
- var/turf/T = get_turf(host_mob)
- for(var/mob/living/L in range(5, host_mob))
- if(!(MOB_ORGANIC in L.mob_biotypes) && !(MOB_UNDEAD in L.mob_biotypes))
- continue
- if(!disease_air_spread_walk(T, get_turf(L)))
- continue
- target_hosts += L
- target_hosts -= host_mob
- if(!target_hosts.len)
- return
- var/mob/living/infectee = pick(target_hosts)
- if(prob(100 - (infectee.get_permeability_protection() * 100)))
- //this will potentially take over existing nanites!
- infectee.AddComponent(/datum/component/nanites, 10)
- SEND_SIGNAL(infectee, COMSIG_NANITE_SYNC, nanites)
- infectee.investigate_log("[key_name(infectee)] was infected by spreading nanites by [key_name(host_mob)]", INVESTIGATE_NANITES)
+ if(spread_cooldown < world.time)
+ return
+ spread_cooldown = world.time + 50
+ var/list/mob/living/target_hosts = list()
+ for(var/mob/living/L in oview(5, host_mob))
+ if(!prob(25))
+ continue
+ if(!(L.mob_biotypes & (MOB_ORGANIC|MOB_UNDEAD)))
+ continue
+ target_hosts += L
+ if(!target_hosts.len)
+ return
+ var/mob/living/infectee = pick(target_hosts)
+ if(prob(100 - (infectee.get_permeability_protection() * 100)))
+ //this will potentially take over existing nanites!
+ infectee.AddComponent(/datum/component/nanites, 10)
+ SEND_SIGNAL(infectee, COMSIG_NANITE_SYNC, nanites)
+ infectee.investigate_log("was infected by spreading nanites by [key_name(host_mob)] at [AREACOORD(infectee)].", INVESTIGATE_NANITES)
/datum/nanite_program/mitosis
name = "Mitosis"
diff --git a/code/modules/research/nanites/nanite_programs/weapon.dm b/code/modules/research/nanites/nanite_programs/weapon.dm
index 4f29398e91..f634b2088c 100644
--- a/code/modules/research/nanites/nanite_programs/weapon.dm
+++ b/code/modules/research/nanites/nanite_programs/weapon.dm
@@ -160,40 +160,55 @@
/datum/nanite_program/cryo/active_effect()
host_mob.adjust_bodytemperature(-rand(15,25), 50)
-/datum/nanite_program/mind_control
+/datum/nanite_program/triggered/comm/mind_control
name = "Mind Control"
- desc = "The nanites imprint an absolute directive onto the host's brain while they're active."
- use_rate = 3
+ desc = "The nanites imprint an absolute directive onto the host's brain for one minute when triggered."
+ trigger_cost = 30
+ trigger_cooldown = 1800
rogue_types = list(/datum/nanite_program/brain_decay, /datum/nanite_program/brain_misfire)
- extra_settings = list("Directive")
- var/cooldown = 0 //avoids spam when nanites are running low
+ extra_settings = list("Directive","Comm Code")
var/directive = "..."
-/datum/nanite_program/mind_control/set_extra_setting(user, setting)
+/datum/nanite_program/triggered/comm/mind_control/set_extra_setting(user, setting)
if(setting == "Directive")
var/new_directive = stripped_input(user, "Choose the directive to imprint with mind control.", "Directive", directive, MAX_MESSAGE_LEN)
if(!new_directive)
return
directive = new_directive
+ if(setting == "Comm Code")
+ var/new_code = input(user, "Set the communication code (1-9999) or set to 0 to disable external signals.", name, null) as null|num
+ if(isnull(new_code))
+ return
+ comm_code = CLAMP(round(new_code, 1), 0, 9999)
-/datum/nanite_program/mind_control/get_extra_setting(setting)
+/datum/nanite_program/triggered/comm/mind_control/get_extra_setting(setting)
if(setting == "Directive")
return directive
+ if(setting == "Comm Code")
+ return comm_code
-/datum/nanite_program/mind_control/copy_extra_settings_to(datum/nanite_program/mind_control/target)
+/datum/nanite_program/triggered/comm/mind_control/copy_extra_settings_to(datum/nanite_program/triggered/comm/mind_control/target)
target.directive = directive
+ target.comm_code = comm_code
-/datum/nanite_program/mind_control/enable_passive_effect()
- if(world.time < cooldown)
+/datum/nanite_program/triggered/comm/mind_control/trigger(comm_message)
+ if(!..())
return
- . = ..()
- brainwash(host_mob, directive)
+ if(host_mob.stat == DEAD)
+ return
+ var/sent_directive = comm_message
+ if(!comm_message)
+ sent_directive = directive
+ brainwash(host_mob, sent_directive)
log_game("A mind control nanite program brainwashed [key_name(host_mob)] with the objective '[directive]'.")
+ addtimer(CALLBACK(src, .proc/end_brainwashing), 600)
-/datum/nanite_program/mind_control/disable_passive_effect()
- . = ..()
+/datum/nanite_program/triggered/comm/mind_control/proc/end_brainwashing()
if(host_mob.mind && host_mob.mind.has_antag_datum(/datum/antagonist/brainwashed))
host_mob.mind.remove_antag_datum(/datum/antagonist/brainwashed)
log_game("[key_name(host_mob)] is no longer brainwashed by nanites.")
- cooldown = world.time + 450
+
+/datum/nanite_program/triggered/comm/mind_control/disable_passive_effect()
+ . = ..()
+ end_brainwashing()
diff --git a/code/modules/research/nanites/nanite_remote.dm b/code/modules/research/nanites/nanite_remote.dm
index a7c8533521..e10d8f8c4b 100644
--- a/code/modules/research/nanites/nanite_remote.dm
+++ b/code/modules/research/nanites/nanite_remote.dm
@@ -168,6 +168,109 @@
. = TRUE
+/obj/item/nanite_remote/comm
+ name = "nanite communication remote"
+ desc = "A device that can send text messages to specific programs."
+ icon_state = "nanite_comm_remote"
+ var/comm_code = 0
+ var/comm_message = ""
+
+/obj/item/nanite_remote/comm/afterattack(atom/target, mob/user, etc)
+ switch(mode)
+ if(REMOTE_MODE_OFF)
+ return
+ if(REMOTE_MODE_SELF)
+ to_chat(user, "You activate [src], signaling the nanites in your bloodstream.")
+ signal_mob(user, comm_code, comm_message)
+ if(REMOTE_MODE_TARGET)
+ if(isliving(target) && (get_dist(target, get_turf(src)) <= 7))
+ to_chat(user, "You activate [src], signaling the nanites inside [target].")
+ signal_mob(target, code, comm_message, key_name(user))
+ if(REMOTE_MODE_AOE)
+ to_chat(user, "You activate [src], signaling the nanites inside every host around you.")
+ for(var/mob/living/L in view(user, 7))
+ signal_mob(L, code, comm_message, key_name(user))
+ if(REMOTE_MODE_RELAY)
+ to_chat(user, "You activate [src], signaling all connected relay nanites.")
+ signal_relay(code, relay_code, comm_message, key_name(user))
+
+/obj/item/nanite_remote/comm/signal_mob(mob/living/M, code, source)
+ SEND_SIGNAL(M, COMSIG_NANITE_COMM_SIGNAL, comm_code, comm_message)
+
+/obj/item/nanite_remote/comm/signal_relay(code, relay_code, source)
+ for(var/X in SSnanites.nanite_relays)
+ var/datum/nanite_program/relay/N = X
+ N.relay_comm_signal(comm_code, relay_code, comm_message)
+
+/obj/item/nanite_remote/comm/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
+ SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "nanite_comm_remote", name, 420, 800, master_ui, state)
+ ui.open()
+
+/obj/item/nanite_remote/comm/ui_data()
+ var/list/data = list()
+ data["comm_code"] = comm_code
+ data["relay_code"] = relay_code
+ data["comm_message"] = comm_message
+ data["mode"] = mode
+ data["locked"] = locked
+ data["saved_settings"] = saved_settings
+
+ return data
+
+/obj/item/nanite_remote/comm/ui_act(action, params)
+ if(..())
+ return
+ switch(action)
+ if("set_comm_code")
+ if(locked)
+ return
+ var/new_code = input("Set comm code (0000-9999):", name, code) as null|num
+ if(!isnull(new_code))
+ new_code = CLAMP(round(new_code, 1),0,9999)
+ comm_code = new_code
+ . = TRUE
+ if("set_message")
+ if(locked)
+ return
+ var/new_message = stripped_input(usr, "Set the message (Max 300 characters):", "Set Message", null , 300)
+ if(!new_message)
+ return
+ comm_message = new_message
+ . = TRUE
+ if("comm_save")
+ if(locked)
+ return
+ var/code_name = stripped_input(usr, "Set the setting name", "Set Name", null , 15)
+ if(!code_name)
+ return
+ var/new_save = list()
+ new_save["id"] = last_id + 1
+ last_id++
+ new_save["name"] = code_name
+ new_save["code"] = comm_code
+ new_save["mode"] = mode
+ new_save["relay_code"] = relay_code
+ new_save["message"] = comm_message
+
+ saved_settings += list(new_save)
+ . = TRUE
+ if("comm_load")
+ var/code_id = params["save_id"]
+ var/list/setting
+ for(var/list/X in saved_settings)
+ if(X["id"] == text2num(code_id))
+ setting = X
+ break
+ if(setting)
+ comm_code = setting["code"]
+ mode = setting["mode"]
+ relay_code = setting["relay_code"]
+ comm_message = setting["message"]
+ . = TRUE
+
+
#undef REMOTE_MODE_OFF
#undef REMOTE_MODE_SELF
#undef REMOTE_MODE_TARGET
diff --git a/code/modules/research/nanites/program_disks.dm b/code/modules/research/nanites/program_disks.dm
index f780f40932..6444ebc025 100644
--- a/code/modules/research/nanites/program_disks.dm
+++ b/code/modules/research/nanites/program_disks.dm
@@ -142,4 +142,10 @@
program_type = /datum/nanite_program/researchplus
/obj/item/disk/nanite_program/reduced_diagnostics
- program_type = /datum/nanite_program/reduced_diagnostics
\ No newline at end of file
+ program_type = /datum/nanite_program/reduced_diagnostics
+
+/obj/item/disk/nanite_program/good_mood
+ program_type = /datum/nanite_program/good_mood
+
+/obj/item/disk/nanite_program/bad_mood
+ program_type = /datum/nanite_program/bad_mood
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index b6a1105cf4..74f07e4ce3 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -8,9 +8,9 @@
display_name = "Basic Research Technology"
description = "NT default research technologies."
// Default research tech, prevents bricking
- design_ids = list("basic_matter_bin", "basic_cell", "basic_scanning", "basic_capacitor", "basic_micro_laser", "micro_mani",
+ design_ids = list("basic_matter_bin", "basic_cell", "basic_scanning", "basic_capacitor", "basic_micro_laser", "micro_mani", "desttagger", "handlabel", "packagewrap",
"destructive_analyzer", "circuit_imprinter", "experimentor", "rdconsole", "design_disk", "tech_disk", "rdserver", "rdservercontrol", "mechfab",
- "space_heater", "xlarge_beaker", "sec_beanbag", "sec_rshot", "sec_bshot", "sec_slug", "sec_Islug", "sec_dart", "sec_38", "sec_38lethal",
+ "space_heater", "beaker", "large_beaker", "bucket", "xlarge_beaker", "sec_beanbag", "sec_rshot", "sec_bshot", "sec_slug", "sec_Islug", "sec_dart", "sec_38", "sec_38lethal",
"rglass","plasteel","plastitanium","plasmaglass","plasmareinforcedglass","titaniumglass","plastitaniumglass")
/datum/techweb_node/mmi
@@ -71,7 +71,7 @@
display_name = "Biological Technology"
description = "What makes us tick." //the MC, silly!
prereq_ids = list("base")
- design_ids = list("medicalkit", "chem_heater", "chem_master", "chem_dispenser", "sleeper", "vr_sleeper", "pandemic", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "blood_bag", "bloodbankgen", "telescopiciv")
+ design_ids = list("medicalkit", "chem_heater", "chem_master", "chem_dispenser", "sleeper", "vr_sleeper", "pandemic", "defibrillator", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "blood_bag", "bloodbankgen", "telescopiciv", "medspray")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -80,7 +80,7 @@
display_name = "Advanced Biotechnology"
description = "Advanced Biotechnology"
prereq_ids = list("biotech")
- design_ids = list("piercesyringe", "crewpinpointer", "smoke_machine", "plasmarefiller", "limbgrower", "defibrillator", "meta_beaker", "healthanalyzer_advanced","harvester","holobarrier_med","smartdartgun","medicinalsmartdart", "pHmeter")
+ design_ids = list("piercesyringe", "crewpinpointer", "smoke_machine", "plasmarefiller", "limbgrower", "meta_beaker", "healthanalyzer_advanced", "harvester", "holobarrier_med", "detective_scanner", "defibrillator_compact", "smartdartgun", "medicinalsmartdart", "pHmeter")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -595,6 +595,15 @@
export_price = 5000
////////////////////////Tools////////////////////////
+/datum/techweb_node/basic_tools
+ id = "basic_tools"
+ display_name = "Basic Tools"
+ description = "Basic mechanical, electronic, surgical and botanical tools."
+ prereq_ids = list("base")
+ design_ids = list("screwdriver", "wrench", "wirecutters", "crowbar", "multitool", "welding_tool", "tscanner", "analyzer", "cable_coil", "pipe_painter", "airlock_painter", "scalpel", "circular_saw", "surgicaldrill", "retractor", "cautery", "hemostat", "cultivator", "plant_analyzer", "shovel", "spade", "hatchet")
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 500)
+ export_price = 5000
+
/datum/techweb_node/basic_mining
id = "basic_mining"
display_name = "Mining Technology"
@@ -618,7 +627,7 @@
display_name = "Advanced Sanitation Technology"
description = "Clean things better, faster, stronger, and harder!"
prereq_ids = list("adv_engi")
- design_ids = list("advmop", "buffer", "light_replacer")
+ design_ids = list("advmop", "buffer", "light_replacer", "spraybottle", "beartrap")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1750) // No longer has its bag
export_price = 5000
@@ -640,6 +649,15 @@
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2750)
export_price = 5000
+/datum/techweb_node/sec_basic
+ id = "sec_basic"
+ display_name = "Basic Security Equipment"
+ description = "Standard equipment used by security."
+ design_ids = list("seclite", "pepperspray", "bola_energy", "zipties", "evidencebag")
+ prereq_ids = list("base")
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 750)
+ export_price = 5000
+
/////////////////////////weaponry tech/////////////////////////
/datum/techweb_node/weaponry
id = "weaponry"
@@ -958,7 +976,7 @@
display_name = "Basic Nanite Programming"
description = "The basics of nanite construction and programming."
prereq_ids = list("datatheory","robotics")
- design_ids = list("nanite_disk","nanite_remote","nanite_scanner",\
+ design_ids = list("nanite_disk","nanite_remote","nanite_comm_remote","nanite_scanner",\
"nanite_chamber","public_nanite_chamber","nanite_chamber_control","nanite_programmer","nanite_program_hub","nanite_cloud_control",\
"relay_nanites", "monitoring_nanites", "access_nanites", "repairing_nanites","sensor_nanite_volume", "repeater_nanites", "relay_repeater_nanites","red_diag_nanites")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
@@ -997,7 +1015,7 @@
display_name = "Neural Nanite Programming"
description = "Nanite programs affecting nerves and brain matter."
prereq_ids = list("nanite_bio")
- design_ids = list("nervous_nanites", "brainheal_nanites", "paralyzing_nanites", "stun_nanites", "selfscan_nanites")
+ design_ids = list("nervous_nanites", "brainheal_nanites", "paralyzing_nanites", "stun_nanites", "selfscan_nanites","good_mood_nanites","bad_mood_nanites")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -1081,7 +1099,7 @@
display_name = "Illegal Technology"
description = "Dangerous research used to create dangerous objects."
prereq_ids = list("adv_engi", "adv_weaponry", "explosive_weapons")
- design_ids = list("decloner", "borg_syndicate_module", "suppressor", "largecrossbow", "donksofttoyvendor", "syndiesleeper")
+ design_ids = list("decloner", "borg_syndicate_module", "ai_cam_upgrade", "suppressor", "largecrossbow", "donksofttoyvendor", "donksoft_refill", "syndiesleeper")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 10000)
export_price = 5000
hidden = TRUE
diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm
index 2ac6df7668..0db05cb83d 100644
--- a/code/modules/shuttle/supply.dm
+++ b/code/modules/shuttle/supply.dm
@@ -166,13 +166,12 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
msg += export_text + "\n"
SSshuttle.points += ex.total_value[E]
- for(var/datum/reagent/R in ex.total_reagents)
- var/amount = ex.total_reagents[R]
- var/value = amount*R.value
- if(!value)
- continue
- msg += "[value] credits: received [amount]u of [R.name].\n"
+ for(var/chem in ex.reagents_value)
+ var/value = ex.reagents_value[chem]
+ msg += "[value] credits: received [ex.reagents_volume[chem]]u of [chem].\n"
SSshuttle.points += value
+ msg = copytext(msg, 1, MAX_MESSAGE_LEN)
+
SSshuttle.centcom_message = msg
investigate_log("Shuttle contents sold for [SSshuttle.points - presale_points] credits. Contents: [ex.exported_atoms || "none."] Message: [SSshuttle.centcom_message || "none."]", INVESTIGATE_CARGO)
diff --git a/code/modules/spells/spell_types/ethereal_jaunt.dm b/code/modules/spells/spell_types/ethereal_jaunt.dm
index 9d1274edef..a9d5f21abc 100644
--- a/code/modules/spells/spell_types/ethereal_jaunt.dm
+++ b/code/modules/spells/spell_types/ethereal_jaunt.dm
@@ -99,5 +99,6 @@
/obj/effect/dummy/phased_mob/spell_jaunt/ex_act(blah)
return
+
/obj/effect/dummy/phased_mob/spell_jaunt/bullet_act(blah)
- return
\ No newline at end of file
+ return BULLET_ACT_FORCE_PIERCE
\ No newline at end of file
diff --git a/code/modules/spells/spell_types/shadow_walk.dm b/code/modules/spells/spell_types/shadow_walk.dm
index 8dbb6d6532..b32c8c16c6 100644
--- a/code/modules/spells/spell_types/shadow_walk.dm
+++ b/code/modules/spells/spell_types/shadow_walk.dm
@@ -91,7 +91,7 @@
return
/obj/effect/dummy/phased_mob/shadow/bullet_act()
- return
+ return BULLET_ACT_FORCE_PIERCE
/obj/effect/dummy/phased_mob/shadow/singularity_act()
return
diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm
index 161461d099..6dc1d1b6ce 100644
--- a/code/modules/surgery/organs/vocal_cords.dm
+++ b/code/modules/surgery/organs/vocal_cords.dm
@@ -578,7 +578,8 @@
cooldown = COOLDOWN_MEME
for(var/V in listeners)
var/mob/living/carbon/human/H = V
- if(H.canbearoused && H.has_dna() && HAS_TRAIT(H, TRAIT_NYMPHO)) // probably a redundant check but for good measure
+
+ if(H.client && H.client.prefs && H.client.prefs.cit_toggles & HYPNO) // probably a redundant check but for good measure
H.mob_climax(forced_climax=TRUE)
//DAB
@@ -807,7 +808,7 @@
E.enthrallTally += (power_multiplier*(((length(message))/200) + 1)) //encourage players to say more than one word.
else
E.enthrallTally += power_multiplier*1.25 //thinking about it, I don't know how this can proc
- if(L.canbearoused && E.lewd)
+ if(E.lewd)
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "[E.enthrallGender] is so nice to listen to."), 5)
E.cooldown += 1
@@ -821,8 +822,6 @@
continue
if (E.lewd)
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "[E.enthrallGender] has praised me!!"), 5)
- if(HAS_TRAIT(L, TRAIT_NYMPHO))
- L.adjustArousalLoss(2*power_multiplier)
if(HAS_TRAIT(L, TRAIT_MASO))
E.enthrallTally -= power_multiplier
E.resistanceTally += power_multiplier
@@ -845,7 +844,9 @@
continue
if (E.lewd)
if(HAS_TRAIT(L, TRAIT_MASO))
- L.adjustArousalLoss(3*power_multiplier)
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ H.adjust_arousal(3*power_multiplier,maso = TRUE)
descmessage += "And yet, it feels so good..!" //I don't really understand masco, is this the right sort of thing they like?
E.enthrallTally += power_multiplier
E.resistanceTally -= power_multiplier
@@ -1001,16 +1002,6 @@
if(160 to INFINITY)
speaktrigger += "I feel like I'm on the brink of losing my mind, "
- //horny
- if(HAS_TRAIT(H, TRAIT_NYMPHO) && H.canbearoused && E.lewd)
- switch(H.getArousalLoss())
- if(40 to 60)
- speaktrigger += "I'm feeling a little horny, "
- if(60 to 80)
- speaktrigger += "I'm feeling horny, "
- if(80 to INFINITY)
- speaktrigger += "I'm really, really horny, "
-
//collar
if(istype(H.wear_neck, /obj/item/clothing/neck/petcollar) && E.lewd)
speaktrigger += "I love the collar you gave me, "
@@ -1111,11 +1102,10 @@
var/mob/living/carbon/human/H = V
var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
if(E.phase > 1)
- if(HAS_TRAIT(H, TRAIT_NYMPHO) && H.canbearoused && E.lewd) // probably a redundant check but for good measure
+ if(E.lewd) // probably a redundant check but for good measure
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "Your [E.enthrallGender] pushes you over the limit, overwhelming your body with pleasure."), 5)
H.mob_climax(forced_climax=TRUE)
H.SetStun(20)
- H.setArousalLoss(H.min_arousal)
E.resistanceTally = 0 //makes resistance 0, but resets arousal, resistance buildup is faster unaroused (massively so).
E.enthrallTally += power_multiplier
E.cooldown += 6
diff --git a/code/modules/vending/clothesmate.dm b/code/modules/vending/clothesmate.dm
index 4bd21ea7f2..0b1d8e1072 100644
--- a/code/modules/vending/clothesmate.dm
+++ b/code/modules/vending/clothesmate.dm
@@ -154,8 +154,9 @@
/obj/item/clothing/suit/jacket/letterman_syndie = 5,
/obj/item/clothing/under/jabroni = 2,
/obj/item/clothing/suit/vapeshirt = 2,
- /obj/item/clothing/under/geisha = 4,,
- /obj/item/clothing/under/keyholesweater = 3)
+ /obj/item/clothing/under/geisha = 4,
+ /obj/item/clothing/under/keyholesweater = 3,
+ /obj/item/clothing/under/staffassistant = 5)
premium = list(/obj/item/clothing/under/suit_jacket/checkered = 4,
/obj/item/clothing/head/mailman = 2,
/obj/item/clothing/under/rank/mailman = 2,
diff --git a/code/modules/vore/eating/voreitems.dm b/code/modules/vore/eating/voreitems.dm
index 05ab1e5f8b..4e6bdaa1e0 100644
--- a/code/modules/vore/eating/voreitems.dm
+++ b/code/modules/vore/eating/voreitems.dm
@@ -21,6 +21,7 @@
range = 2
/obj/item/projectile/sickshot/on_hit(var/atom/movable/target, var/blocked = 0)
+ . = ..()
if(iscarbon(target))
var/mob/living/carbon/H = target
if(prob(5))
@@ -28,7 +29,7 @@
H.release_vore_contents()
H.visible_message("[H] contracts strangely, spewing out contents on the floor!", \
"You spew out everything inside you on the floor!")
- return
+ return BULLET_ACT_HIT
////////////////////////// Anti-Noms Drugs //////////////////////////
diff --git a/code/modules/vore/resizing/sizegun_vr.dm b/code/modules/vore/resizing/sizegun_vr.dm
index 8295f32cfa..156b220df3 100644
--- a/code/modules/vore/resizing/sizegun_vr.dm
+++ b/code/modules/vore/resizing/sizegun_vr.dm
@@ -42,7 +42,8 @@
impact_type = /obj/effect/projectile/xray/impact
/obj/item/projectile/beam/shrinklaser/on_hit(var/atom/target, var/blocked = 0)
- if(istype(target, /mob/living))
+ . = ..()
+ if(isliving(target))
var/mob/living/M = target
switch(M.size_multiplier)
if(SIZESCALE_HUGE to INFINITY)
@@ -54,7 +55,7 @@
if((0 - INFINITY) to SIZESCALE_NORMAL)
M.sizescale(SIZESCALE_TINY)
M.update_transform()
- return 1
+ return BULLET_ACT_HIT
/obj/item/projectile/beam/growlaser
name = "growth beam"
@@ -68,7 +69,8 @@
impact_type = /obj/effect/projectile/laser_blue/impact
/obj/item/projectile/beam/growlaser/on_hit(var/atom/target, var/blocked = 0)
- if(istype(target, /mob/living))
+ . = ..()
+ if(isliving(target))
var/mob/living/M = target
switch(M.size_multiplier)
if(SIZESCALE_BIG to SIZESCALE_HUGE)
@@ -80,7 +82,7 @@
if((0 - INFINITY) to SIZESCALE_TINY)
M.sizescale(SIZESCALE_SMALL)
M.update_transform()
- return 1
+ return BULLET_ACT_HIT
*/
datum/design/sizeray
@@ -108,7 +110,8 @@ datum/design/sizeray
icon_state="laser"
/obj/item/projectile/sizeray/shrinkray/on_hit(var/atom/target, var/blocked = 0)
- if(istype(target, /mob/living))
+ . = ..()
+ if(isliving(target))
var/mob/living/M = target
switch(M.size_multiplier)
if(SIZESCALE_HUGE to INFINITY)
@@ -120,10 +123,11 @@ datum/design/sizeray
if((0 - INFINITY) to SIZESCALE_NORMAL)
M.sizescale(SIZESCALE_TINY)
M.update_transform()
- return 1
+ return BULLET_ACT_
/obj/item/projectile/sizeray/growthray/on_hit(var/atom/target, var/blocked = 0)
- if(istype(target, /mob/living))
+ . = ..()
+ if(isliving(target))
var/mob/living/M = target
switch(M.size_multiplier)
if(SIZESCALE_BIG to SIZESCALE_HUGE)
@@ -135,7 +139,7 @@ datum/design/sizeray
if((0 - INFINITY) to SIZESCALE_TINY)
M.sizescale(SIZESCALE_SMALL)
M.update_transform()
- return 1
+ return BULLET_ACT_HIT
/obj/item/ammo_casing/energy/laser/growthray
projectile_type = /obj/item/projectile/sizeray/growthray
diff --git a/config/game_options.txt b/config/game_options.txt
index 060d782dbe..b8b89de17c 100644
--- a/config/game_options.txt
+++ b/config/game_options.txt
@@ -560,6 +560,15 @@ ROUNDSTART_TRAITS
## Enable night shifts ##
#ENABLE_NIGHT_SHIFTS
+## Makes night shifts only affect in-code public-flagged areas. Nightshifts hit the level as defined in __DEFINES/misc.dm that this is set to and anything below. ##
+NIGHT_SHIFT_PUBLIC_AREAS_ONLY 1
+
+## Nightshift toggles REQUIRE APC authorization ##
+#NIGHTSHIFT_TOGGLE_REQUIRES_AUTH
+
+## Nightshift toggles in public areas REQUIRE APC authorization ##
+NIGHTSHIFT_TOGGLE_PUBLIC_REQUIRES_AUTH
+
## Enable randomized shift start times##
#RANDOMIZE_SHIFT_TIME
diff --git a/goon/icons/mob/worn_js_rank.dmi b/goon/icons/mob/worn_js_rank.dmi
new file mode 100644
index 0000000000..8235c3ff3d
Binary files /dev/null and b/goon/icons/mob/worn_js_rank.dmi differ
diff --git a/goon/icons/obj/item_js_rank.dmi b/goon/icons/obj/item_js_rank.dmi
new file mode 100644
index 0000000000..b61e07a155
Binary files /dev/null and b/goon/icons/obj/item_js_rank.dmi differ
diff --git a/html/changelogs/AutoChangeLog-pr-10125.yml b/html/changelogs/AutoChangeLog-pr-10125.yml
new file mode 100644
index 0000000000..951b69ccb3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10125.yml
@@ -0,0 +1,5 @@
+author: "Kevinz000"
+delete-after: True
+changes:
+ - bugfix: "Fixes successful projectile hits also striking another atom on the same turf should the first one be not the target the projectile was meant for."
+ - rscdel: "Removes infinite reflector loops."
diff --git a/html/changelogs/AutoChangeLog-pr-10347.yml b/html/changelogs/AutoChangeLog-pr-10347.yml
new file mode 100644
index 0000000000..c0508aa279
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10347.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - balance: "The stamina buffer no longer uses stamina while recharging."
diff --git a/html/changelogs/AutoChangeLog-pr-10375.yml b/html/changelogs/AutoChangeLog-pr-10375.yml
new file mode 100644
index 0000000000..7d0cc2bf44
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10375.yml
@@ -0,0 +1,5 @@
+author: "r4d6"
+delete-after: True
+changes:
+ - rscadd: "Added a Radiation Hardsuit"
+ - rscadd: "Added a Radiation Hardsuit crate"
diff --git a/html/changelogs/AutoChangeLog-pr-10417.yml b/html/changelogs/AutoChangeLog-pr-10417.yml
new file mode 100644
index 0000000000..31ac154ac9
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10417.yml
@@ -0,0 +1,7 @@
+author: "kevinz000"
+delete-after: True
+changes:
+ - config: "Added a few more nightshift config entries"
+ - rscadd: "nightshift_public_area variable in areas to determine how public an area is."
+ - rscadd: "NIGHT_SHIFT_PUBLIC_AREAS_ONLY config entry allows the server to be configured to only nightshift areas of that level and below (so areas that are more public)"
+ - rscadd: "Config entries added for requiring authorizations to toggle nightshift. Defaults to only requiring on public areas as determined by above"
diff --git a/html/changelogs/AutoChangeLog-pr-10454.yml b/html/changelogs/AutoChangeLog-pr-10454.yml
new file mode 100644
index 0000000000..d89603959e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10454.yml
@@ -0,0 +1,4 @@
+author: "Commandersand"
+delete-after: True
+changes:
+ - bugfix: "fixed some clothnig sprites"
diff --git a/html/changelogs/AutoChangeLog-pr-10456.yml b/html/changelogs/AutoChangeLog-pr-10456.yml
new file mode 100644
index 0000000000..4c94455e47
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10456.yml
@@ -0,0 +1,12 @@
+author: "Putnam"
+delete-after: True
+changes:
+ - rscdel: "Arousal damage is gone, and with it the arousal damage heart on the UI."
+ - rscdel: "As exhibitionist relied on arousal damage, that's gone too."
+ - rscdel: "Bonermeter and electronic stimulation circuit modules are gone."
+ - rscdel: "Masturbation is no longer an option in the climax menu. It was identical to climax alone in every way but text. Emote it out."
+ - rscadd: "Arousal on genitals can now be displayed manually, on a case-by-case basis."
+ - rscadd: "\"Climax alone\" and \"climax with partner\" now only display to the people directly involved in the interaction.
+rework: Catnip tea, catnip, crocin, hexacrocin, camphor, hexacamphor all had functions or bits of functions reworked."
+ - tweak: "\"Climax with partner\" now requires consent from both parties--it can no longer be used on mindless mobs, and it asks the mob getting climaxed with if they consent first."
+ - tweak: "A lot of MKUltra behaviors have been moved to hypno checks or removed due to reliance on maso/nympho/exhib."
diff --git a/html/changelogs/AutoChangeLog-pr-10530.yml b/html/changelogs/AutoChangeLog-pr-10530.yml
new file mode 100644
index 0000000000..16cc66adb9
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10530.yml
@@ -0,0 +1,4 @@
+author: "kappa-sama"
+delete-after: True
+changes:
+ - code_imp: "modular citadel loses some files"
diff --git a/html/changelogs/AutoChangeLog-pr-10531.yml b/html/changelogs/AutoChangeLog-pr-10531.yml
new file mode 100644
index 0000000000..6c1125a687
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10531.yml
@@ -0,0 +1,6 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - rscadd: "Seed packs now have RnD points inside them"
+ - rscadd: "New tips that reflect the now use seed packs have for Rnd / Chems affect on plants"
+ - code_imp: "Made the research file look nice rather then an eye harming list"
diff --git a/html/changelogs/AutoChangeLog-pr-10535.yml b/html/changelogs/AutoChangeLog-pr-10535.yml
new file mode 100644
index 0000000000..db37120317
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10535.yml
@@ -0,0 +1,4 @@
+author: "Hatterhat"
+delete-after: True
+changes:
+ - rscadd: "A shipment of Staff Assistant jumpsuits from the Goon-operated stations appear to have made their way into your loadout selections - and into the contraband list from ClothesMates..."
diff --git a/html/changelogs/AutoChangeLog-pr-10538.yml b/html/changelogs/AutoChangeLog-pr-10538.yml
new file mode 100644
index 0000000000..01119f886f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10538.yml
@@ -0,0 +1,4 @@
+author: "Putnam3145"
+delete-after: True
+changes:
+ - bugfix: "Chemistry not :b:roke"
diff --git a/html/changelogs/AutoChangeLog-pr-10549.yml b/html/changelogs/AutoChangeLog-pr-10549.yml
new file mode 100644
index 0000000000..11a770945d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10549.yml
@@ -0,0 +1,4 @@
+author: "Seris02"
+delete-after: True
+changes:
+ - rscadd: "durathread winter coats from hyper station"
diff --git a/html/changelogs/AutoChangeLog-pr-10557.yml b/html/changelogs/AutoChangeLog-pr-10557.yml
new file mode 100644
index 0000000000..f5b37f6cee
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10557.yml
@@ -0,0 +1,4 @@
+author: "timothyteakettle"
+delete-after: True
+changes:
+ - bugfix: "fixed not being able to remove trait genes without a disk being inserted into the dna manipulator"
diff --git a/html/changelogs/AutoChangeLog-pr-10558.yml b/html/changelogs/AutoChangeLog-pr-10558.yml
new file mode 100644
index 0000000000..09186767f3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10558.yml
@@ -0,0 +1,4 @@
+author: "DeltaFire15"
+delete-after: True
+changes:
+ - bugfix: "Vitality matrixes now correctly succ slimes"
diff --git a/html/changelogs/AutoChangeLog-pr-10563.yml b/html/changelogs/AutoChangeLog-pr-10563.yml
new file mode 100644
index 0000000000..5efc4cfdb1
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10563.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - bugfix: "Fixed fragile space suits breaking from weak and non-damaging \"weapons\" (such as the Sord, toys and foam darts)."
diff --git a/html/changelogs/AutoChangeLog-pr-10567.yml b/html/changelogs/AutoChangeLog-pr-10567.yml
new file mode 100644
index 0000000000..9d73d1d947
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10567.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Sanitized cargo export messages for reagents."
diff --git a/html/changelogs/AutoChangeLog-pr-10569.yml b/html/changelogs/AutoChangeLog-pr-10569.yml
new file mode 100644
index 0000000000..0b9cb0b992
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10569.yml
@@ -0,0 +1,5 @@
+author: "keronshb"
+delete-after: True
+changes:
+ - rscadd: "Ports the special nanite remote, mood programs, and research generating nanites"
+ - balance: "rebalances some nanites"
diff --git a/html/changelogs/AutoChangeLog-pr-10570.yml b/html/changelogs/AutoChangeLog-pr-10570.yml
new file mode 100644
index 0000000000..9eaf2168a8
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10570.yml
@@ -0,0 +1,4 @@
+author: "kevinz000"
+delete-after: True
+changes:
+ - code_imp: "Mapping helpers added for power cables and atmos pipes."
diff --git a/html/changelogs/AutoChangeLog-pr-10579.yml b/html/changelogs/AutoChangeLog-pr-10579.yml
new file mode 100644
index 0000000000..c428c0109d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10579.yml
@@ -0,0 +1,4 @@
+author: "r4d6"
+delete-after: True
+changes:
+ - rscadd: "Added more Cyborg Landmarks"
diff --git a/html/changelogs/AutoChangeLog-pr-10582.yml b/html/changelogs/AutoChangeLog-pr-10582.yml
new file mode 100644
index 0000000000..2024088fb8
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10582.yml
@@ -0,0 +1,4 @@
+author: "Putnam3145"
+delete-after: True
+changes:
+ - bugfix: "temporary flavor text now pops up properly"
diff --git a/html/changelogs/AutoChangeLog-pr-10584.yml b/html/changelogs/AutoChangeLog-pr-10584.yml
new file mode 100644
index 0000000000..e2c9f93ac8
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10584.yml
@@ -0,0 +1,4 @@
+author: "AffectedArc07"
+delete-after: True
+changes:
+ - code_imp: "Line ending CI works now"
diff --git a/html/changelogs/AutoChangeLog-pr-10591.yml b/html/changelogs/AutoChangeLog-pr-10591.yml
new file mode 100644
index 0000000000..ac8504ec9c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10591.yml
@@ -0,0 +1,4 @@
+author: "kevinz000"
+delete-after: True
+changes:
+ - rscdel: "Blood duplication is gone, but viruses now react up to 5 times, 1 time per unit, for virus mix."
diff --git a/icons/effects/mapping_helpers.dmi b/icons/effects/mapping_helpers.dmi
index dec83046b9..e3cc3865b2 100644
Binary files a/icons/effects/mapping_helpers.dmi and b/icons/effects/mapping_helpers.dmi differ
diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi
index 6bba2fc7fb..f8785ae2f7 100644
Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ
diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi
index dec1c372b5..28211b6240 100644
Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ
diff --git a/icons/mob/suit_digi.dmi b/icons/mob/suit_digi.dmi
index a0f6e6ab08..a9898262a8 100644
Binary files a/icons/mob/suit_digi.dmi and b/icons/mob/suit_digi.dmi differ
diff --git a/icons/mob/uniform.dmi b/icons/mob/uniform.dmi
index 778b718fe6..7cc6b8e762 100644
Binary files a/icons/mob/uniform.dmi and b/icons/mob/uniform.dmi differ
diff --git a/icons/mob/uniform_digi.dmi b/icons/mob/uniform_digi.dmi
index 9173a3ceaa..5b5c7ceb6e 100644
Binary files a/icons/mob/uniform_digi.dmi and b/icons/mob/uniform_digi.dmi differ
diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi
index f94106dd55..a79ca3be45 100644
Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ
diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi
index 6831c17e56..be091c596d 100644
Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ
diff --git a/icons/obj/clothing/uniforms.dmi b/icons/obj/clothing/uniforms.dmi
index e6474e7899..89f9a6fd93 100644
Binary files a/icons/obj/clothing/uniforms.dmi and b/icons/obj/clothing/uniforms.dmi differ
diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi
index 4cb7e02e03..71fceba8b4 100644
Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ
diff --git a/modular_citadel/code/_onclick/hud/stamina.dm b/modular_citadel/code/_onclick/hud/stamina.dm
index 184e3add24..0515b9d762 100644
--- a/modular_citadel/code/_onclick/hud/stamina.dm
+++ b/modular_citadel/code/_onclick/hud/stamina.dm
@@ -11,7 +11,7 @@
/obj/screen/staminas/Click(location,control,params)
if(isliving(usr))
var/mob/living/L = usr
- to_chat(L, "You have [L.getStaminaLoss()] stamina loss.
Your stamina buffer can take [L.stambuffer] stamina loss, and will use 50% of that stamina loss when recharging.
Your stamina buffer is [(L.stambuffer*(100/L.stambuffer))-(L.bufferedstam*(100/L.stambuffer))]% full.")
+ to_chat(L, "You have [L.getStaminaLoss()] stamina loss.
Your stamina buffer can take [L.stambuffer] stamina loss, and recharges at no cost.
Your stamina buffer is [(L.stambuffer*(100/L.stambuffer))-(L.bufferedstam*(100/L.stambuffer))]% full.")
/obj/screen/staminas/update_icon_state()
var/mob/living/carbon/user = hud?.mymob
diff --git a/modular_citadel/code/datums/status_effects/chems.dm b/modular_citadel/code/datums/status_effects/chems.dm
index 4449ca801a..89086ab1e5 100644
--- a/modular_citadel/code/datums/status_effects/chems.dm
+++ b/modular_citadel/code/datums/status_effects/chems.dm
@@ -268,10 +268,6 @@
RegisterSignal(owner, COMSIG_LIVING_RESIST, .proc/owner_resist) //Do resistance calc if resist is pressed#
RegisterSignal(owner, COMSIG_MOVABLE_HEAR, .proc/owner_hear)
mental_capacity = 500 - M.getOrganLoss(ORGAN_SLOT_BRAIN)//It's their brain!
- var/mob/living/carbon/human/H = owner
- if(H)//Prefs
- if(!H.canbearoused)
- H.client?.prefs.cit_toggles &= ~HYPNO
lewd = (owner.client?.prefs.cit_toggles & HYPNO) && (master.client?.prefs.cit_toggles & HYPNO)
var/message = "[(lewd ? "I am a good pet for [enthrallGender]." : "[master] is a really inspirational person!")]"
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "enthrall", /datum/mood_event/enthrall, message)
@@ -625,8 +621,6 @@
//Speak (Forces player to talk)
if (lowertext(customTriggers[trigger][1]) == "speak")//trigger2
var/saytext = "Your mouth moves on it's own before you can even catch it."
- if(HAS_TRAIT(C, TRAIT_NYMPHO))
- saytext += " You find yourself fully believing in the validity of what you just said and don't think to question it."
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "[saytext]"), 5)
addtimer(CALLBACK(C, /atom/movable/proc/say, "[customTriggers[trigger][2]]"), 5)
log_game("FERMICHEM: MKULTRA: [owner] ckey: [owner.key] has been forced to say: \"[customTriggers[trigger][2]]\" from previous trigger.")
@@ -639,8 +633,9 @@
//Shocking truth!
else if (lowertext(customTriggers[trigger]) == "shock")
- if (C.canbearoused && lewd)
- C.adjustArousalLoss(5)
+ if (lewd && ishuman(C))
+ var/mob/living/carbon/human/H = C
+ H.adjust_arousal(5)
C.jitteriness += 100
C.stuttering += 25
C.Knockdown(60)
@@ -649,13 +644,11 @@
//wah intensifies wah-rks
else if (lowertext(customTriggers[trigger]) == "cum")//aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- if (HAS_TRAIT(C, TRAIT_NYMPHO) && lewd)
- if (C.getArousalLoss() > 80)
- C.mob_climax(forced_climax=TRUE)
- C.SetStun(10)//We got your stun effects in somewhere, Kev.
- else
- C.adjustArousalLoss(10)
- to_chat(C, "You feel a surge of arousal!")
+ if (lewd)
+ if(ishuman(C))
+ var/mob/living/carbon/human/H = C
+ H.mob_climax(forced_climax=TRUE)
+ C.SetStun(10)//We got your stun effects in somewhere, Kev.
else
C.throw_at(get_step_towards(hearing_args[HEARING_SPEAKER],C), 3, 1) //cut this if it's too hard to get working
@@ -734,16 +727,13 @@
if(prob(5))
M.emote("me",1,"squints, shaking their head for a moment.")//shows that you're trying to resist sometimes
deltaResist *= 1.5
- //nymphomania
- if (M.canbearoused && HAS_TRAIT(M, TRAIT_NYMPHO))//I'm okay with this being removed.
- deltaResist*= 0.5-(((2/200)*M.arousalloss)/1)//more aroused you are, the weaker resistance you can give, the less you are, the more you gain. (+/- 0.5)
//chemical resistance, brain and annaphros are the key to undoing, but the subject has to to be willing to resist.
if (owner.reagents.has_reagent(/datum/reagent/medicine/mannitol))
deltaResist *= 1.25
if (owner.reagents.has_reagent(/datum/reagent/medicine/neurine))
deltaResist *= 1.5
- if (!(owner.client?.prefs.cit_toggles & NO_APHRO) && M.canbearoused && lewd)
+ if (!(owner.client?.prefs.cit_toggles & NO_APHRO) && lewd)
if (owner.reagents.has_reagent(/datum/reagent/drug/anaphrodisiac))
deltaResist *= 1.5
if (owner.reagents.has_reagent(/datum/reagent/drug/anaphrodisiacplus))
diff --git a/modular_citadel/code/game/objects/effects/spawner/spawners.dm b/modular_citadel/code/game/objects/effects/spawner/spawners.dm
deleted file mode 100644
index b6fbeef4c9..0000000000
--- a/modular_citadel/code/game/objects/effects/spawner/spawners.dm
+++ /dev/null
@@ -1,7 +0,0 @@
-/obj/effect/spawner/lootdrop/keg
- name = "random keg spawner"
- lootcount = 1
- loot = list(/obj/structure/reagent_dispensers/keg/mead = 5,
- /obj/structure/reagent_dispensers/keg/aphro = 2,
- /obj/structure/reagent_dispensers/keg/aphro/strong = 2,
- /obj/structure/reagent_dispensers/keg/gargle = 1)
\ No newline at end of file
diff --git a/modular_citadel/code/game/objects/items.dm b/modular_citadel/code/game/objects/items.dm
deleted file mode 100644
index dba460414e..0000000000
--- a/modular_citadel/code/game/objects/items.dm
+++ /dev/null
@@ -1,15 +0,0 @@
-/obj/item
- var/list/alternate_screams = list() //REEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
-
-// lazy for screaming.
-/obj/item/clothing/head/xenos
- alternate_screams = list('sound/voice/hiss6.ogg')
-
-/obj/item/clothing/head/cardborg
- alternate_screams = list('modular_citadel/sound/voice/scream_silicon.ogg')
-
-/obj/item/clothing/head/ushanka
- alternate_screams = list('sound/voice/human/cyka1.ogg', 'sound/voice/human/cheekibreeki.ogg')
-
-/obj/item/proc/grenade_prime_react(obj/item/grenade/nade)
- return
\ No newline at end of file
diff --git a/modular_citadel/code/game/objects/items/devices/radio/encryptionkey.dm b/modular_citadel/code/game/objects/items/devices/radio/encryptionkey.dm
deleted file mode 100644
index 5e3d7318cf..0000000000
--- a/modular_citadel/code/game/objects/items/devices/radio/encryptionkey.dm
+++ /dev/null
@@ -1,10 +0,0 @@
-/obj/item/encryptionkey/heads/qm
- name = "\proper the quartermaster's encryption key"
- desc = "An encryption key for a radio headset. Channels are as follows: :u - supply, :c - command."
- icon_state = "hop_cypherkey"
- channels = list("Supply" = 1, "Command" = 1)
-
-/obj/item/encryptionkey/heads/hop
- desc = "An encryption key for a radio headset. Channels are as follows: :v - service, :c - command."
- channels = list("Service" = 1, "Command" = 1)
-
diff --git a/modular_citadel/code/game/objects/items/devices/radio/headset.dm b/modular_citadel/code/game/objects/items/devices/radio/headset.dm
deleted file mode 100644
index 3d1b36f645..0000000000
--- a/modular_citadel/code/game/objects/items/devices/radio/headset.dm
+++ /dev/null
@@ -1,10 +0,0 @@
-/obj/item/radio/headset/heads/qm
- name = "\proper the quartermaster's headset"
- desc = "The headset of the king (or queen) of paperwork.\nChannels are as follows: :u - supply, :c - command."
- icon_state = "com_headset"
- keyslot = new /obj/item/encryptionkey/heads/qm
-
-/obj/item/radio/headset/heads/hop
- desc = "The headset of the guy who will one day be captain.\nChannels are as follows: :v - service, :c - command."
- keyslot = new /obj/item/encryptionkey/heads/hop
-
diff --git a/modular_citadel/code/game/objects/items/devices/radio/shockcollar.dm b/modular_citadel/code/game/objects/items/devices/radio/shockcollar.dm
deleted file mode 100644
index 94bf1ba30a..0000000000
--- a/modular_citadel/code/game/objects/items/devices/radio/shockcollar.dm
+++ /dev/null
@@ -1,77 +0,0 @@
-/obj/item/electropack/shockcollar
- name = "shock collar"
- desc = "A reinforced metal collar. It seems to have some form of wiring near the front. Strange.."
- icon = 'modular_citadel/icons/obj/clothing/cit_neck.dmi'
- alternate_worn_icon = 'modular_citadel/icons/mob/citadel/neck.dmi'
- icon_state = "shockcollar"
- item_state = "shockcollar"
- body_parts_covered = NECK
- slot_flags = ITEM_SLOT_NECK | ITEM_SLOT_DENYPOCKET //no more pocket shockers
- w_class = WEIGHT_CLASS_SMALL
- strip_delay = 60
- equip_delay_other = 60
- materials = list(MAT_METAL=5000, MAT_GLASS=2000)
-
- var/tagname = null
-
-/datum/design/electropack/shockcollar
- name = "Shockcollar"
- id = "shockcollar"
- build_type = AUTOLATHE
- build_path = /obj/item/electropack/shockcollar
- materials = list(MAT_METAL=5000, MAT_GLASS=2000)
- category = list("hacked", "Misc")
-
-/obj/item/electropack/shockcollar/attack_hand(mob/user)
- if(loc == user && user.get_item_by_slot(SLOT_NECK))
- to_chat(user, "The collar is fastened tight! You'll need help taking this off!")
- return
- return ..()
-
-/obj/item/electropack/shockcollar/receive_signal(datum/signal/signal)
- if(!signal || signal.data["code"] != code)
- return
-
- if(isliving(loc) && on)
- if(shock_cooldown == TRUE)
- return
- shock_cooldown = TRUE
- addtimer(VARSET_CALLBACK(src, shock_cooldown, FALSE), 100)
- var/mob/living/L = loc
- step(L, pick(GLOB.cardinals))
-
- to_chat(L, "You feel a sharp shock from the collar!")
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
- s.set_up(3, 1, L)
- s.start()
-
- L.Knockdown(100)
-
- if(master)
- master.receive_signal()
- return
-
-/obj/item/electropack/shockcollar/attackby(obj/item/W, mob/user, params) //moves it here because on_click is being bad
- if(istype(W, /obj/item/pen))
- var/t = input(user, "Would you like to change the name on the tag?", "Name your new pet", tagname ? tagname : "Spot") as null|text
- if(t)
- tagname = copytext(sanitize(t), 1, MAX_NAME_LEN)
- name = "[initial(name)] - [tagname]"
- else
- return ..()
-
-/obj/item/electropack/shockcollar/ui_interact(mob/user) //on_click calls this
- var/dat = {"
-
-Frequency/Code for shock collar:
-Frequency:
-[format_frequency(src.frequency)]
-Set
-
-Code:
-[src.code]
-Set
-"}
- user << browse(dat, "window=radio")
- onclose(user, "radio")
- return
diff --git a/modular_citadel/code/game/objects/items/stunsword.dm b/modular_citadel/code/game/objects/items/stunsword.dm
deleted file mode 100644
index 7a5398f7d2..0000000000
--- a/modular_citadel/code/game/objects/items/stunsword.dm
+++ /dev/null
@@ -1,41 +0,0 @@
-/obj/item/melee/baton/stunsword
- name = "stunsword"
- desc = "not actually sharp, this sword is functionally identical to a stunbaton"
- icon = 'modular_citadel/icons/obj/stunsword.dmi'
- icon_state = "stunsword"
- item_state = "sword"
- lefthand_file = 'modular_citadel/icons/mob/inhands/stunsword_left.dmi'
- righthand_file = 'modular_citadel/icons/mob/inhands/stunsword_right.dmi'
-
-/obj/item/melee/baton/stunsword/get_belt_overlay()
- if(istype(loc, /obj/item/storage/belt/sabre))
- return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "stunsword")
- return ..()
-
-/obj/item/melee/baton/stunsword/get_worn_belt_overlay(icon_file)
- return mutable_appearance(icon_file, "-stunsword")
-
-/obj/item/ssword_kit
- name = "stunsword kit"
- desc = "a modkit for making a stunbaton into a stunsword"
- icon = 'icons/obj/vending_restock.dmi'
- icon_state = "refill_donksoft"
- var/product = /obj/item/melee/baton/stunsword //what it makes
- var/list/fromitem = list(/obj/item/melee/baton, /obj/item/melee/baton/loaded) //what it needs
- afterattack(obj/O, mob/user as mob)
- if(istype(O, product))
- to_chat(user,"[O] is already modified!")
- else if(O.type in fromitem) //makes sure O is the right thing
- var/obj/item/melee/baton/B = O
- if(!B.cell) //checks for a powercell in the baton. If there isn't one, continue. If there is, warn the user to take it out
- new product(usr.loc) //spawns the product
- user.visible_message("[user] modifies [O]!","You modify the [O]!")
- qdel(O) //Gets rid of the baton
- qdel(src) //gets rid of the kit
-
- else
- to_chat(user,"Remove the powercell first!") //We make this check because the stunsword starts without a battery.
- else
- to_chat(user, " You can't modify [O] with this kit!")
-
-
diff --git a/modular_citadel/code/init.dm b/modular_citadel/code/init.dm
deleted file mode 100644
index a85c3a249c..0000000000
--- a/modular_citadel/code/init.dm
+++ /dev/null
@@ -1,5 +0,0 @@
-//init file stolen from hippie
-
-/proc/cit_initialize()
- load_mentors()
- initialize_global_loadout_items()
diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm
index ed28185bb7..3361707b04 100644
--- a/modular_citadel/code/modules/arousal/arousal.dm
+++ b/modular_citadel/code/modules/arousal/arousal.dm
@@ -1,17 +1,8 @@
-//Mob vars
/mob/living
- var/arousalloss = 0 //How aroused the mob is.
- var/min_arousal = AROUSAL_MINIMUM_DEFAULT //The lowest this mobs arousal will get. default = 0
- var/max_arousal = AROUSAL_MAXIMUM_DEFAULT //The highest this mobs arousal will get. default = 100
- var/arousal_rate = AROUSAL_START_VALUE //The base rate that arousal will increase in this mob.
- var/arousal_loss_rate = AROUSAL_START_VALUE //How easily arousal can be relieved for this mob.
- var/canbearoused = FALSE //Mob-level disabler for arousal. Starts off and can be enabled as features are added for different mob types.
var/mb_cd_length = 5 SECONDS //5 second cooldown for masturbating because fuck spam.
var/mb_cd_timer = 0 //The timer itself
/mob/living/carbon/human
- canbearoused = TRUE
-
var/saved_underwear = ""//saves their underwear so it can be toggled later
var/saved_undershirt = ""
var/saved_socks = ""
@@ -21,8 +12,6 @@
//Species vars
/datum/species
- var/arousal_gain_rate = AROUSAL_START_VALUE //Rate at which this species becomes aroused
- var/arousal_lose_rate = AROUSAL_START_VALUE //Multiplier for how easily arousal can be relieved
var/list/cum_fluids = list("semen")
var/list/milk_fluids = list("milk")
var/list/femcum_fluids = list("femcum")
@@ -52,130 +41,26 @@
update_body()
-/mob/living/proc/handle_arousal(times_fired)
- return
-/mob/living/carbon/handle_arousal(times_fired)
- if(!canbearoused || !dna)
- return
- var/datum/species/S = dna.species
- if(!S || (times_fired % 36) || !getArousalLoss() >= max_arousal)//Totally stolen from breathing code. Do this every 36 ticks.
- return
- var/our_loss = arousal_rate * S.arousal_gain_rate
- if(HAS_TRAIT(src, TRAIT_EXHIBITIONIST) && client)
- var/amt_nude = 0
+/mob/living/carbon/human/proc/adjust_arousal(strength,aphro = FALSE,maso = FALSE) // returns all genitals that were adjust
+ var/list/obj/item/organ/genital/genit_list = list()
+ if(!client?.prefs.arousable || (aphro && (client?.prefs.cit_toggles & NO_APHRO)) || (maso && !HAS_TRAIT(src, TRAIT_MASO)))
+ return // no adjusting made here
+ if(strength>0)
for(var/obj/item/organ/genital/G in internal_organs)
- if(G.is_exposed())
- amt_nude++
- if(amt_nude)
- var/watchers = 0
- for(var/mob/living/L in view(src))
- if(L.client && !L.stat && !L.eye_blind && (src in view(L)))
- watchers++
- if(watchers)
- our_loss += (amt_nude * watchers) + S.arousal_gain_rate
- adjustArousalLoss(our_loss)
-
-/mob/living/proc/getArousalLoss()
- return arousalloss
-
-/mob/living/proc/adjustArousalLoss(amount, updating_arousal=1)
- if(status_flags & GODMODE || !canbearoused)
- return FALSE
- arousalloss = CLAMP(arousalloss + amount, min_arousal, max_arousal)
- if(updating_arousal)
- updatearousal()
-
-/mob/living/proc/setArousalLoss(amount, updating_arousal=1)
- if(status_flags & GODMODE || !canbearoused)
- return FALSE
- arousalloss = CLAMP(amount, min_arousal, max_arousal)
- if(updating_arousal)
- updatearousal()
-
-/mob/living/proc/getPercentAroused()
- var/percentage = ((100 / max_arousal) * arousalloss)
- return percentage
-
-/mob/living/proc/isPercentAroused(percentage)//returns true if the mob's arousal (measured in a percent of 100) is greater than the arg percentage.
- if(!isnum(percentage) || percentage > 100 || percentage < 0)
- CRASH("Provided percentage is invalid")
- if(getPercentAroused() >= percentage)
- return TRUE
- return FALSE
-
-//H U D//
-/mob/living/proc/updatearousal()
- update_arousal_hud()
-
-/mob/living/carbon/updatearousal()
- . = ..()
- for(var/obj/item/organ/genital/G in internal_organs)
- if(istype(G))
- var/datum/sprite_accessory/S
- switch(G.type)
- if(/obj/item/organ/genital/penis)
- S = GLOB.cock_shapes_list[G.shape]
- if(/obj/item/organ/genital/testicles)
- S = GLOB.balls_shapes_list[G.shape]
- if(/obj/item/organ/genital/vagina)
- S = GLOB.vagina_shapes_list[G.shape]
- if(/obj/item/organ/genital/breasts)
- S = GLOB.breasts_shapes_list[G.shape]
- if(S?.alt_aroused)
- G.aroused_state = isPercentAroused(G.aroused_amount)
- else
- G.aroused_state = FALSE
- G.update_appearance()
-
-/mob/living/proc/update_arousal_hud()
- return FALSE
-
-/mob/living/carbon/human/update_arousal_hud()
- if(!client || !(hud_used?.arousal))
- return FALSE
- if(!canbearoused)
- hud_used.arousal.icon_state = ""
- return FALSE
+ if(!G.aroused_state && prob(strength*G.sensitivity))
+ G.set_aroused_state(TRUE)
+ G.update_appearance()
+ if(G.aroused_state)
+ genit_list += G
else
- var/value = FLOOR(getPercentAroused(), 10)
- hud_used.arousal.icon_state = "arousal[value]"
- return TRUE
-
-/obj/screen/arousal
- name = "arousal"
- icon_state = "arousal0"
- icon = 'modular_citadel/icons/obj/genitals/hud.dmi'
- screen_loc = ui_arousal
-
-/obj/screen/arousal/Click()
- if(!isliving(usr))
- return FALSE
- var/mob/living/M = usr
- if(M.canbearoused)
- M.mob_climax()
- return TRUE
- else
- to_chat(M, "Arousal is disabled. Feature is unavailable.")
-
-
-/mob/living/proc/mob_climax(forced_climax = FALSE)//This is just so I can test this shit without being forced to add actual content to get rid of arousal. Will be a very basic proc for a while.
- set name = "Masturbate"
- set category = "IC"
- if(canbearoused && !restrained() && !stat)
- if(mb_cd_timer <= world.time)
- //start the cooldown even if it fails
- mb_cd_timer = world.time + mb_cd_length
- if(getArousalLoss() >= 33)//one third of average max_arousal or greater required
- visible_message("[src] starts masturbating!", \
- "You start masturbating.")
- if(do_after(src, 30, target = src))
- visible_message("[src] relieves [p_them()]self!", \
- "You have relieved yourself.")
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm)
- setArousalLoss(min_arousal)
- else
- to_chat(src, "You aren't aroused enough for that.")
+ for(var/obj/item/organ/genital/G in internal_organs)
+ if(G.aroused_state && prob(strength*G.sensitivity))
+ G.set_aroused_state(FALSE)
+ G.update_appearance()
+ if(G.aroused_state)
+ genit_list += G
+ return genit_list
/obj/item/organ/genital/proc/climaxable(mob/living/carbon/human/H, silent = FALSE) //returns the fluid source (ergo reagents holder) if found.
if(CHECK_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION))
@@ -189,48 +74,25 @@
/mob/living/carbon/human/proc/do_climax(datum/reagents/R, atom/target, obj/item/organ/genital/G, spill = TRUE)
if(!G)
return
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm)
- setArousalLoss(min_arousal)
if(!target || !R)
return
var/turfing = isturf(target)
- if(spill & R.total_volume >= 5)
+ if(spill && R.total_volume >= 5)
R.reaction(turfing ? target : target.loc, TOUCH, 1, 0)
if(!turfing)
R.trans_to(target, R.total_volume * (spill ? G.fluid_transfer_factor : 1))
R.clear_reagents()
-//These are various procs that we'll use later, split up for readability instead of having one, huge proc.
-//For all of these, we assume the arguments given are proper and have been checked beforehand.
-/mob/living/carbon/human/proc/mob_masturbate(obj/item/organ/genital/G, mb_time = 30) //Masturbation, keep it gender-neutral
- var/datum/reagents/fluid_source = G.climaxable(src)
- if(!fluid_source)
- return
- var/obj/item/organ/genital/PP = CHECK_BITFIELD(G.genital_flags, MASTURBATE_LINKED_ORGAN) ? G.linked_organ : G
- if(!PP)
- to_chat(src, "You shudder, unable to cum with your [name].")
- if(mb_time)
- visible_message("[src] starts to [G.masturbation_verb] [p_their()] [G.name].", \
- "You start to [G.masturbation_verb] your [G.name].")
- if(!do_after(src, mb_time, target = src) || !G.climaxable(src, TRUE))
- return
- visible_message("[src] orgasms, [PP.orgasm_verb][isturf(loc) ? " onto [loc]" : ""] with [p_their()] [PP.name]!", \
- "You orgasm, [PP.orgasm_verb][isturf(loc) ? " onto [loc]" : ""] with your [PP.name].")
- do_climax(fluid_source, loc, G)
-
/mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/G, mb_time = 30) //This is used for forced orgasms and other hands-free climaxes
var/datum/reagents/fluid_source = G.climaxable(src, TRUE)
if(!fluid_source)
- visible_message("[src] shudders, their [G.name] unable to cum.", \
- "Your [G.name] cannot cum, giving no relief.")
+ to_chat(src,"Your [G.name] cannot cum.")
return
if(mb_time) //as long as it's not instant, give a warning
- visible_message("[src] looks like they're about to cum.", \
- "You feel yourself about to orgasm.")
+ to_chat(src,"You feel yourself about to orgasm.")
if(!do_after(src, mb_time, target = src) || !G.climaxable(src, TRUE))
return
- visible_message("[src] orgasms[isturf(loc) ? " onto [loc]" : ""], using [p_their()] [G.name]!", \
- "You climax[isturf(loc) ? " onto [loc]" : ""] with your [G.name].")
+ to_chat(src,"You climax[isturf(loc) ? " onto [loc]" : ""] with your [G.name].")
do_climax(fluid_source, loc, G)
/mob/living/carbon/human/proc/mob_climax_partner(obj/item/organ/genital/G, mob/living/L, spillage = TRUE, mb_time = 30) //Used for climaxing with any living thing
@@ -238,48 +100,30 @@
if(!fluid_source)
return
if(mb_time) //Skip warning if this is an instant climax.
- visible_message("[src] is about to climax with [L]!", \
- "You're about to climax with [L]!")
+ to_chat(src,"You're about to climax with [L]!")
+ to_chat(L,"[src] is about to climax with you!")
if(!do_after(src, mb_time, target = src) || !in_range(src, L) || !G.climaxable(src, TRUE))
return
if(spillage)
- visible_message("[src] climaxes with [L], overflowing and spilling, using [p_their()] [G.name]!", \
- "You orgasm with [L], spilling out of them, using your [G.name].")
+ to_chat(src,"You orgasm with [L], spilling out of them, using your [G.name].")
+ to_chat(L,"[src] climaxes with you, overflowing and spilling, using [p_their()] [G.name]!")
else //knots and other non-spilling orgasms
- visible_message("[src] climaxes with [L], [p_their()] [G.name] spilling nothing!", \
- "You ejaculate with [L], your [G.name] spilling nothing.")
+ to_chat(src,"You climax with [L], your [G.name] spilling nothing.")
+ to_chat(L,"[src] climaxes with you, [p_their()] [G.name] spilling nothing!")
SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm)
do_climax(fluid_source, spillage ? loc : L, G, spillage)
-
/mob/living/carbon/human/proc/mob_fill_container(obj/item/organ/genital/G, obj/item/reagent_containers/container, mb_time = 30) //For beaker-filling, beware the bartender
var/datum/reagents/fluid_source = G.climaxable(src)
if(!fluid_source)
return
if(mb_time)
- visible_message("[src] starts to [G.masturbation_verb] their [G.name] over [container].", \
- "You start to [G.masturbation_verb] your [G.name] over [container].")
+ to_chat(src,"You start to [G.masturbation_verb] your [G.name] over [container].")
if(!do_after(src, mb_time, target = src) || !in_range(src, container) || !G.climaxable(src, TRUE))
return
- visible_message("[src] uses [p_their()] [G.name] to fill [container]!", \
- "You used your [G.name] to fill [container].")
+ to_chat(src,"You used your [G.name] to fill [container].")
do_climax(fluid_source, container, G, FALSE)
-/mob/living/carbon/human/proc/pick_masturbate_genitals(silent = FALSE)
- var/list/genitals_list
- var/list/worn_stuff = get_equipped_items()
-
- for(var/obj/item/organ/genital/G in internal_organs)
- if(CHECK_BITFIELD(G.genital_flags, CAN_MASTURBATE_WITH) && G.is_exposed(worn_stuff)) //filter out what you can't masturbate with
- if(CHECK_BITFIELD(G.genital_flags, MASTURBATE_LINKED_ORGAN) && !G.linked_organ)
- continue
- LAZYADD(genitals_list, G)
- if(LAZYLEN(genitals_list))
- var/obj/item/organ/genital/ret_organ = input(src, "with what?", "Masturbate", null) as null|obj in genitals_list
- return ret_organ
- else if(!silent)
- to_chat(src, "You cannot masturbate without available genitals.")
-
/mob/living/carbon/human/proc/pick_climax_genitals(silent = FALSE)
var/list/genitals_list
var/list/worn_stuff = get_equipped_items()
@@ -301,6 +145,8 @@
partners += pulledby
//Now we got both of them, let's check if they're proper
for(var/mob/living/L in partners)
+ if(!L.client || !L.mind) // can't consent, not a partner
+ partners -= L
if(iscarbon(L))
var/mob/living/carbon/C = L
if(!C.exposed_genitals.len && !C.is_groin_exposed() && !C.is_chest_exposed()) //Nothing through_clothing, no proper partner.
@@ -312,7 +158,9 @@
return //No one left.
var/mob/living/target = input(src, "With whom?", "Sexual partner", null) as null|anything in partners //pick one, default to null
if(target && in_range(src, target))
- return target
+ var/consenting = input(target, "Do you want [src] to climax with you?","Climax mechanics","No") in list("Yes","No")
+ if(consenting == "Yes")
+ return target
/mob/living/carbon/human/proc/pick_climax_container(silent = FALSE)
var/list/containers_list = list()
@@ -349,13 +197,13 @@
return TRUE
//Here's the main proc itself
-/mob/living/carbon/human/mob_climax(forced_climax=FALSE) //Forced is instead of the other proc, makes you cum if you have the tools for it, ignoring restraints
+/mob/living/carbon/human/proc/mob_climax(forced_climax=FALSE) //Forced is instead of the other proc, makes you cum if you have the tools for it, ignoring restraints
if(mb_cd_timer > world.time)
if(!forced_climax) //Don't spam the message to the victim if forced to come too fast
to_chat(src, "You need to wait [DisplayTimeText((mb_cd_timer - world.time), TRUE)] before you can do that again!")
return
- if(!canbearoused || !has_dna())
+ if(!client?.prefs.arousable || !has_dna())
return
if(stat == DEAD)
if(!forced_climax)
@@ -398,32 +246,19 @@
if(stat == UNCONSCIOUS) //No sleep-masturbation, you're unconscious.
to_chat(src, "You must be conscious to do that!")
return
- if(getArousalLoss() < 33) //flat number instead of percentage
- to_chat(src, "You aren't aroused enough for that!")
- return
//Ok, now we check what they want to do.
- var/choice = input(src, "Select sexual activity", "Sexual activity:") as null|anything in list("Masturbate", "Climax alone", "Climax with partner", "Fill container")
+ var/choice = input(src, "Select sexual activity", "Sexual activity:") as null|anything in list("Climax alone","Climax with partner", "Fill container")
if(!choice)
return
switch(choice)
- if("Masturbate")
- if(!available_rosie_palms())
- return
- //We got hands, let's pick an organ
- var/obj/item/organ/genital/picked_organ = pick_masturbate_genitals()
- if(picked_organ && available_rosie_palms(TRUE))
- mob_masturbate(picked_organ)
- return
-
if("Climax alone")
if(!available_rosie_palms())
return
var/obj/item/organ/genital/picked_organ = pick_climax_genitals()
if(picked_organ && available_rosie_palms(TRUE))
mob_climax_outside(picked_organ)
-
if("Climax with partner")
//We need no hands, we can be restrained and so on, so let's pick an organ
var/obj/item/organ/genital/picked_organ = pick_climax_genitals()
@@ -433,7 +268,6 @@
var/spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as null|anything in list("Yes", "No")
if(spillage && in_range(src, partner))
mob_climax_partner(picked_organ, partner, spillage == "Yes" ? TRUE : FALSE)
-
if("Fill container")
//We'll need hands and no restraints.
if(!available_rosie_palms(FALSE, /obj/item/reagent_containers))
@@ -447,4 +281,10 @@
if(fluid_container && available_rosie_palms(TRUE, /obj/item/reagent_containers))
mob_fill_container(picked_organ, fluid_container)
- mb_cd_timer = world.time + mb_cd_length
\ No newline at end of file
+ mb_cd_timer = world.time + mb_cd_length
+
+/mob/living/carbon/human/verb/climax_verb()
+ set category = "IC"
+ set name = "Climax"
+ set desc = "Lets you choose a couple ways to ejaculate."
+ mob_climax()
diff --git a/modular_citadel/code/modules/arousal/genitals.dm b/modular_citadel/code/modules/arousal/genitals.dm
index d5daf24f8a..a16617ba3f 100644
--- a/modular_citadel/code/modules/arousal/genitals.dm
+++ b/modular_citadel/code/modules/arousal/genitals.dm
@@ -2,10 +2,12 @@
color = "#fcccb3"
w_class = WEIGHT_CLASS_NORMAL
var/shape = "human"
- var/sensitivity = AROUSAL_START_VALUE
+ var/sensitivity = 1 // wow if this were ever used that'd be cool but it's not but i'm keeping it for my unshit code
var/genital_flags //see citadel_defines.dm
var/masturbation_verb = "masturbate"
var/orgasm_verb = "cumming" //present continous
+ var/arousal_verb = "You feel aroused"
+ var/unarousal_verb = "You no longer feel aroused"
var/fluid_transfer_factor = 0 //How much would a partner get in them if they climax using this?
var/size = 2 //can vary between num or text, just used in icon_state strings
var/datum/reagent/fluid_id = null
@@ -14,7 +16,6 @@
var/fluid_rate = CUM_RATE
var/fluid_mult = 1
var/aroused_state = FALSE //Boolean used in icon_state strings
- var/aroused_amount = 50 //This is a num from 0 to 100 for arousal percentage for when to use arousal state icons.
var/obj/item/organ/genital/linked_organ
var/linked_organ_slot //used for linking an apparatus' organ to its other half on update_link().
var/layer_index = GENITAL_LAYER_INDEX //Order should be very important. FIRST vagina, THEN testicles, THEN penis, as this affects the order they are rendered in.
@@ -38,6 +39,11 @@
Remove(owner, TRUE)//this should remove references to it, so it can be GCd correctly
return ..()
+/obj/item/organ/genital/proc/set_aroused_state(new_state)
+ if(!((HAS_TRAIT(owner,TRAIT_PERMABONER) && !new_state) || HAS_TRAIT(owner,TRAIT_NEVERBONER) && new_state))
+ aroused_state = new_state
+ return aroused_state
+
/obj/item/organ/genital/proc/update(removing = FALSE)
if(QDELETED(src))
return
@@ -90,11 +96,9 @@
set desc = "Allows you to toggle which genitals should show through clothes or not."
var/list/genital_list = list()
- for(var/obj/item/organ/O in internal_organs)
- if(isgenital(O))
- var/obj/item/organ/genital/G = O
- if(!CHECK_BITFIELD(G.genital_flags, GENITAL_INTERNAL))
- genital_list += G
+ for(var/obj/item/organ/genital/G in internal_organs)
+ if(!CHECK_BITFIELD(G.genital_flags, GENITAL_INTERNAL))
+ genital_list += G
if(!genital_list.len) //There is nothing to expose
return
//Full list of exposable genitals created
@@ -105,6 +109,39 @@
picked_organ.toggle_visibility(picked_visibility)
return
+/mob/living/carbon/verb/toggle_arousal_state()
+ set category = "IC"
+ set name = "Toggle genital arousal"
+ set desc = "Allows you to toggle which genitals are showing signs of arousal."
+ var/list/genital_list = list()
+ for(var/obj/item/organ/genital/G in internal_organs)
+ var/datum/sprite_accessory/S
+ switch(G.type)
+ if(/obj/item/organ/genital/penis)
+ S = GLOB.cock_shapes_list[G.shape]
+ if(/obj/item/organ/genital/testicles)
+ S = GLOB.balls_shapes_list[G.shape]
+ if(/obj/item/organ/genital/vagina)
+ S = GLOB.vagina_shapes_list[G.shape]
+ if(/obj/item/organ/genital/breasts)
+ S = GLOB.breasts_shapes_list[G.shape]
+ if(S?.alt_aroused)
+ genital_list += G
+ if(!genital_list.len) //There's nothing that can show arousal
+ return
+ var/obj/item/organ/genital/picked_organ
+ picked_organ = input(src, "Choose which genitalia to toggle arousal on", "Set genital arousal", null) in genital_list
+ if(picked_organ)
+ var/original_state = picked_organ.aroused_state
+ picked_organ.set_aroused_state(!picked_organ.aroused_state)
+ if(original_state != picked_organ.aroused_state)
+ to_chat(src,"[picked_organ.aroused_state ? picked_organ.arousal_verb : picked_organ.unarousal_verb].")
+ else
+ to_chat(src,"You can't make that genital [picked_organ.aroused_state ? "unaroused" : "aroused"]!")
+ picked_organ.update_appearance()
+ return
+
+
/obj/item/organ/genital/proc/modify_size(modifier, min = -INFINITY, max = INFINITY)
fluid_max_volume += modifier*2.5
fluid_rate += modifier/10
@@ -233,7 +270,7 @@
//Checks to see if organs are new on the mob, and changes their colours so that they don't get crazy colours.
/mob/living/carbon/human/proc/emergent_genital_call()
- if(!canbearoused)
+ if(!client.prefs.arousable)
return FALSE
var/organCheck = locate(/obj/item/organ/genital) in internal_organs
diff --git a/modular_citadel/code/modules/arousal/organs/breasts.dm b/modular_citadel/code/modules/arousal/organs/breasts.dm
index 73d03eff3b..d1f1a08ea8 100644
--- a/modular_citadel/code/modules/arousal/organs/breasts.dm
+++ b/modular_citadel/code/modules/arousal/organs/breasts.dm
@@ -11,6 +11,8 @@
shape = "pair"
genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_FUID_PRODUCTION
masturbation_verb = "massage"
+ arousal_verb = "Your breasts start feeling sensitive"
+ unarousal_verb = "Your breasts no longer feel sensitive"
orgasm_verb = "leaking"
fluid_transfer_factor = 0.5
var/static/list/breast_values = list("a" = 1, "b" = 2, "c" = 3, "d" = 4, "e" = 5, "f" = 6, "g" = 7, "h" = 8, "i" = 9, "j" = 10, "k" = 11, "l" = 12, "m" = 13, "n" = 14, "o" = 15, "huge" = 16, "flat" = 0)
diff --git a/modular_citadel/code/modules/arousal/organs/penis.dm b/modular_citadel/code/modules/arousal/organs/penis.dm
index 408d6521d0..c6d3c764ac 100644
--- a/modular_citadel/code/modules/arousal/organs/penis.dm
+++ b/modular_citadel/code/modules/arousal/organs/penis.dm
@@ -6,6 +6,8 @@
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_PENIS
masturbation_verb = "stroke"
+ arousal_verb = "You pop a boner"
+ unarousal_verb = "Your boner goes down"
genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH
linked_organ_slot = ORGAN_SLOT_TESTICLES
fluid_transfer_factor = 0.5
@@ -26,7 +28,7 @@
..()
/obj/item/organ/genital/penis/update_size(modified = FALSE)
- if(length < 0)//I don't actually know what round() does to negative numbers, so to be safe!!
+ if(length <= 0)//I don't actually know what round() does to negative numbers, so to be safe!!
if(owner)
to_chat(owner, "You feel your tallywacker shrinking away from your body as your groin flattens out!")
QDEL_IN(src, 1)
diff --git a/modular_citadel/code/modules/arousal/organs/testicles.dm b/modular_citadel/code/modules/arousal/organs/testicles.dm
index a911eefe01..e5b34926de 100644
--- a/modular_citadel/code/modules/arousal/organs/testicles.dm
+++ b/modular_citadel/code/modules/arousal/organs/testicles.dm
@@ -6,6 +6,8 @@
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_TESTICLES
size = BALLS_SIZE_MIN
+ arousal_verb = "Your balls ache a little"
+ unarousal_verb = "Your balls finally stop aching, again"
linked_organ_slot = ORGAN_SLOT_PENIS
genital_flags = CAN_MASTURBATE_WITH|MASTURBATE_LINKED_ORGAN|GENITAL_FUID_PRODUCTION
var/size_name = "average"
diff --git a/modular_citadel/code/modules/arousal/organs/vagina.dm b/modular_citadel/code/modules/arousal/organs/vagina.dm
index 0df954fd79..31d116b48e 100644
--- a/modular_citadel/code/modules/arousal/organs/vagina.dm
+++ b/modular_citadel/code/modules/arousal/organs/vagina.dm
@@ -8,6 +8,8 @@
size = 1 //There is only 1 size right now
genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH
masturbation_verb = "finger"
+ arousal_verb = "You feel wetness on your crotch."
+ unarousal_verb = "You no longer feel wet."
fluid_transfer_factor = 0.1 //Yes, some amount is exposed to you, go get your AIDS
layer_index = VAGINA_LAYER_INDEX
var/cap_length = 8//D E P T H (cap = capacity)
diff --git a/modular_citadel/code/modules/arousal/toys/dildos.dm b/modular_citadel/code/modules/arousal/toys/dildos.dm
index 964c9964ad..58245c0c5f 100644
--- a/modular_citadel/code/modules/arousal/toys/dildos.dm
+++ b/modular_citadel/code/modules/arousal/toys/dildos.dm
@@ -5,8 +5,7 @@
name = "dildo"
desc = "Floppy!"
icon = 'modular_citadel/icons/obj/genitals/dildo.dmi'
- damtype = AROUSAL
- force = 5
+ force = 0
hitsound = 'sound/weapons/tap.ogg'
throwforce = 0
icon_state = "dildo_knotted_2"
diff --git a/modular_citadel/code/modules/client/loadout/_service.dm b/modular_citadel/code/modules/client/loadout/_service.dm
index 86823f5661..e5910d3d5d 100644
--- a/modular_citadel/code/modules/client/loadout/_service.dm
+++ b/modular_citadel/code/modules/client/loadout/_service.dm
@@ -1,7 +1,7 @@
/datum/gear/greytidestationwide
- name = "Grey jumpsuit"
+ name = "Staff Assistant's jumpsuit"
category = SLOT_W_UNIFORM
- path = /obj/item/clothing/under/color/grey
+ path = /obj/item/clothing/under/staffassistant
restricted_roles = list("Assistant")
/datum/gear/neetsuit
diff --git a/modular_citadel/code/modules/client/preferences.dm b/modular_citadel/code/modules/client/preferences.dm
index eef8664fbb..4e7cb2972f 100644
--- a/modular_citadel/code/modules/client/preferences.dm
+++ b/modular_citadel/code/modules/client/preferences.dm
@@ -49,10 +49,9 @@
if(L[slot_to_string(slot)] < DEFAULT_SLOT_AMT)
return TRUE
-datum/preferences/copy_to(mob/living/carbon/human/character, icon_updates = 1)
+/datum/preferences/copy_to(mob/living/carbon/human/character, icon_updates = 1)
..()
character.give_genitals(TRUE)
character.flavor_text = features["flavor_text"] //Let's update their flavor_text at least initially
- character.canbearoused = arousable
if(icon_updates)
character.update_genitals()
diff --git a/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm b/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm
deleted file mode 100644
index 547c1a5768..0000000000
--- a/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm
+++ /dev/null
@@ -1,53 +0,0 @@
-/obj/item/integrated_circuit/manipulation/electric_stimulator
- name = "electronic stimulation module"
- desc = "Used to induce sexual stimulation in a target via electricity."
- icon_state = "power_relay"
- extended_desc = "The circuit accepts a reference to a person, as well as a number representing the strength of the shock, and upon activation, attempts to stimulate them to orgasm. The number ranges from -35 to 35, with negative numbers reducing arousal and positive numbers increasing it by that amount."
- complexity = 15
- size = 2
- inputs = list("target" = IC_PINTYPE_REF, "strength" = IC_PINTYPE_NUMBER)
- outputs = list("arousal gain"=IC_PINTYPE_NUMBER)
- activators = list("fire" = IC_PINTYPE_PULSE_IN, "on success" = IC_PINTYPE_PULSE_OUT, "on fail" = IC_PINTYPE_PULSE_OUT, "on orgasm" = IC_PINTYPE_PULSE_OUT)
- spawn_flags = IC_SPAWN_RESEARCH
- power_draw_per_use = 500
- cooldown_per_use = 50
- ext_cooldown = 25
-
-/obj/item/integrated_circuit/manipulation/electric_stimulator/do_work()
- set_pin_data(IC_OUTPUT, 1, 0)
- var/mob/living/M = get_pin_data_as_type(IC_INPUT, 1, /mob/living)
- if(!check_target(M))
- return
-
- var/arousal_gain = CLAMP(get_pin_data(IC_INPUT, 2),-35,35)
- set_pin_data(IC_OUTPUT, 1, arousal_gain)
-
- if(ismob(M) && M.canbearoused && arousal_gain != 0)
- var/orgasm = FALSE
- if(arousal_gain > 0)
- if(M.getArousalLoss() >= 100 && ishuman(M) && M.has_dna())
- var/mob/living/carbon/human/H = M
- var/orgasm_message = pick("A sharp pulse of electricity pushes you to orgasm!", "You feel a jolt of electricity force you into orgasm!")
- H.visible_message("\The [assembly] electrodes shock [H]!", "[orgasm_message]")
- playsound(src, "sound/effects/light_flicker.ogg", 30, 1)
- H.mob_climax(forced_climax=TRUE)
- orgasm = TRUE
- else
- M.adjustArousalLoss(arousal_gain)
- var/stimulate_message = pick("You feel a sharp warming tingle of electricity through your body!", "A burst of arousing electricity flows through your body!")
- M.visible_message("\The [assembly] electrodes shock [M]!", "[stimulate_message]")
-
- else
- var/stimulate_message = pick("You feel a dull prickle of electricity through your body!", "A burst of dull electricity flows through your body!")
- M.visible_message("\The [assembly] electrodes shock [M]!", "[stimulate_message]")
- M.adjustArousalLoss(arousal_gain)
-
- playsound(src, "sound/effects/light_flicker.ogg", 30, 1)
- push_data()
- activate_pin(2)
- if(orgasm) activate_pin(4)
-
- else
- visible_message("\The [assembly] electrodes fail to shock [M]!")
- push_data()
- activate_pin(3)
diff --git a/modular_citadel/code/modules/projectiles/guns/ballistic/handguns.dm b/modular_citadel/code/modules/projectiles/guns/ballistic/handguns.dm
index 10ab3901d9..98d2efc4ea 100644
--- a/modular_citadel/code/modules/projectiles/guns/ballistic/handguns.dm
+++ b/modular_citadel/code/modules/projectiles/guns/ballistic/handguns.dm
@@ -66,6 +66,7 @@ obj/item/projectile/bullet/c10mm/soporific
knockdown = 0
/obj/item/projectile/bullet/c10mm/soporific/on_hit(atom/target, blocked = FALSE)
+ . = ..()
if((blocked != 100) && isliving(target))
var/mob/living/L = target
L.blur_eyes(6)
@@ -73,7 +74,6 @@ obj/item/projectile/bullet/c10mm/soporific
L.Sleeping(300)
else
L.adjustStaminaLoss(25)
- return 1
/obj/item/ammo_casing/c10mm/soporific
name = ".10mm soporific bullet casing"
diff --git a/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon.dm b/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon.dm
index 8ee00bef06..9779b47b15 100644
--- a/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon.dm
+++ b/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon.dm
@@ -355,7 +355,7 @@
damage = 10
armour_penetration = 10
stamina = 10
- forcedodge = TRUE
+ movement_type = FLYING | UNSTOPPABLE
range = 6
light_range = 1
light_color = LIGHT_COLOR_RED
@@ -363,14 +363,14 @@
/obj/item/projectile/bullet/mags/hyper/inferno
icon_state = "magjectile-large"
stamina = 0
- forcedodge = FALSE
+ movement_type = FLYING | UNSTOPPABLE
range = 25
light_range = 4
/obj/item/projectile/bullet/mags/hyper/inferno/on_hit(atom/target, blocked = FALSE)
..()
explosion(target, -1, 1, 2, 4, 5)
- return 1
+ return BULLET_ACT_HIT
///ammo casings///
@@ -436,7 +436,7 @@
icon = 'modular_citadel/icons/obj/guns/cit_guns.dmi'
icon_state = "magjectile-toy"
name = "lasertag magbolt"
- forcedodge = TRUE //for penetration memes
+ movement_type = FLYING | UNSTOPPABLE //for penetration memes
range = 5 //so it isn't super annoying
light_range = 2
light_color = LIGHT_COLOR_YELLOW
diff --git a/modular_citadel/code/modules/projectiles/guns/ballistic/spinfusor.dm b/modular_citadel/code/modules/projectiles/guns/ballistic/spinfusor.dm
index b70858c9af..9e965ec7a7 100644
--- a/modular_citadel/code/modules/projectiles/guns/ballistic/spinfusor.dm
+++ b/modular_citadel/code/modules/projectiles/guns/ballistic/spinfusor.dm
@@ -9,7 +9,7 @@
/obj/item/projectile/bullet/spinfusor/on_hit(atom/target, blocked = FALSE) //explosion to emulate the spinfusor's AOE
..()
explosion(target, -1, -1, 2, 0, -1)
- return 1
+ return BULLET_ACT_HIT
/obj/item/ammo_casing/caseless/spinfusor
name = "spinfusor disk"
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm
index 0985b758c6..86325faa91 100644
--- a/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm
@@ -308,8 +308,6 @@ Creating a chem with a low purity will make you permanently fall in love with so
SSblackbox.record_feedback("tally", "fermi_chem", 1, "Times people have bonded")
else
if(get_dist(M, love) < 8)
- if(HAS_TRAIT(M, TRAIT_NYMPHO)) //Add this back when merged/updated.
- M.adjustArousalLoss(5)
var/message = "[(lewd?"I'm next to my crush..! Eee!":"I'm making friends with [love]!")]"
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "InLove", /datum/mood_event/InLove, message)
SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "MissingLove")
diff --git a/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm b/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm
index b907c27329..32474263c4 100644
--- a/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm
+++ b/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm
@@ -97,14 +97,18 @@
color = "#FFADFF"//PINK, rgb(255, 173, 255)
/datum/reagent/drug/aphrodisiac/on_mob_life(mob/living/M)
- if(M && M.canbearoused && !(M.client?.prefs.cit_toggles & NO_APHRO))
- if(prob(33))
- M.adjustArousalLoss(2)
- if(prob(5))
+ if(M && M.client?.prefs.arousable && !(M.client?.prefs.cit_toggles & NO_APHRO))
+ if((prob(min(current_cycle/2,5))))
M.emote(pick("moan","blush"))
- if(prob(5))
+ if(prob(min(current_cycle/4,10)))
var/aroused_message = pick("You feel frisky.", "You're having trouble suppressing your urges.", "You feel in the mood.")
to_chat(M, "[aroused_message]")
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ var/list/genits = H.adjust_arousal(current_cycle, aphro = TRUE) // redundant but should still be here
+ for(var/g in genits)
+ var/obj/item/organ/genital/G = g
+ to_chat(M, "[G.arousal_verb]!")
..()
/datum/reagent/drug/aphrodisiacplus
@@ -118,21 +122,26 @@
overdose_threshold = 20
/datum/reagent/drug/aphrodisiacplus/on_mob_life(mob/living/M)
- if(M && M.canbearoused && !(M.client?.prefs.cit_toggles & NO_APHRO))
- if(prob(33))
- M.adjustArousalLoss(6)//not quite six times as powerful, but still considerably more powerful.
+ if(M && M.client?.prefs.arousable && !(M.client?.prefs.cit_toggles & NO_APHRO))
if(prob(5))
- if(M.getArousalLoss() > 75)
+ if(prob(current_cycle))
M.say(pick("Hnnnnngghh...", "Ohh...", "Mmnnn..."))
else
M.emote(pick("moan","blush"))
if(prob(5))
var/aroused_message
- if(M.getArousalLoss() > 90)
+ if(current_cycle>25)
aroused_message = pick("You need to fuck someone!", "You're bursting with sexual tension!", "You can't get sex off your mind!")
else
aroused_message = pick("You feel a bit hot.", "You feel strong sexual urges.", "You feel in the mood.", "You're ready to go down on someone.")
to_chat(M, "[aroused_message]")
+ REMOVE_TRAIT(M,TRAIT_NEVERBONER,APHRO_TRAIT)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ var/list/genits = H.adjust_arousal(100, aphro = TRUE) // redundant but should still be here
+ for(var/g in genits)
+ var/obj/item/organ/genital/G = g
+ to_chat(M, "[G.arousal_verb]!")
..()
/datum/reagent/drug/aphrodisiacplus/addiction_act_stage2(mob/living/M)
@@ -150,15 +159,11 @@
..()
/datum/reagent/drug/aphrodisiacplus/overdose_process(mob/living/M)
- if(M && M.canbearoused && !(M.client?.prefs.cit_toggles & NO_APHRO) && prob(33))
- if(prob(5) && M.getArousalLoss() >= 100 && ishuman(M) && M.has_dna())
- if(prob(5)) //Less spam
- to_chat(M, "Your libido is going haywire!")
- if(M.min_arousal < 50)
- M.min_arousal += 1
- if(M.min_arousal < M.max_arousal)
- M.min_arousal += 1
- M.adjustArousalLoss(2)
+ if(M && M.client?.prefs.arousable && !(M.client?.prefs.cit_toggles & NO_APHRO) && prob(33))
+ if(prob(5) && ishuman(M) && M.has_dna() && (M.client?.prefs.cit_toggles & BIMBOFICATION))
+ if(!HAS_TRAIT(M,TRAIT_PERMABONER))
+ to_chat(M, "Your libido is going haywire!")
+ ADD_TRAIT(M,TRAIT_PERMABONER,APHRO_TRAIT)
..()
/datum/reagent/drug/anaphrodisiac
@@ -171,8 +176,12 @@
reagent_state = SOLID
/datum/reagent/drug/anaphrodisiac/on_mob_life(mob/living/M)
- if(M && M.canbearoused && prob(33))
- M.adjustArousalLoss(-2)
+ if(M && M.client?.prefs.arousable && prob(16))
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ var/list/genits = H.adjust_arousal(-100, aphro = TRUE)
+ if(genits.len)
+ to_chat(M, "You no longer feel aroused.")
..()
/datum/reagent/drug/anaphrodisiacplus
@@ -184,17 +193,20 @@
overdose_threshold = 20
/datum/reagent/drug/anaphrodisiacplus/on_mob_life(mob/living/M)
- if(M && M.canbearoused && prob(33))
- M.adjustArousalLoss(-4)
+ if(M && M.client?.prefs.arousable)
+ REMOVE_TRAIT(M,TRAIT_PERMABONER,APHRO_TRAIT)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ var/list/genits = H.adjust_arousal(-100, aphro = TRUE)
+ if(genits.len)
+ to_chat(M, "You no longer feel aroused.")
+
..()
/datum/reagent/drug/anaphrodisiacplus/overdose_process(mob/living/M)
- if(M && M.canbearoused && prob(33))
- if(M.min_arousal > 0)
- M.min_arousal -= 1
- if(M.min_arousal > 50)
- M.min_arousal -= 1
- M.adjustArousalLoss(-2)
+ if(M && M.client?.prefs.arousable && prob(5))
+ to_chat(M, "You feel like you'll never feel aroused again...")
+ ADD_TRAIT(M,TRAIT_NEVERBONER,APHRO_TRAIT)
..()
//recipes
diff --git a/strings/tips.txt b/strings/tips.txt
index e9c1350469..f396b3f542 100644
--- a/strings/tips.txt
+++ b/strings/tips.txt
@@ -55,7 +55,8 @@ As a Scientist, you can disable anomalies by scanning them with an analyzer, the
As a Scientist, researchable stock parts can seriously improve the efficiency and speed of machines around the station. In some cases, it can even unlock new functions.
As a Scientist, you can generate research points by letting the tachyon-doppler array record increasingly large explosions.
As a Scientist, getting drunk just enough will speed up research. Skol!
-As a Scientist, you can get points by placing slime cores into the deconstructive analyzer! This even works with crossbred slime cores.
+As a Scientist, you can get points by placing slime cores into the destructive analyzer! This even works with crossbred slime cores.
+As a Scientist, work with botanists to get different types of seeds, as each type of seed can be used in the destructive analyzer for a small amount of Rnd type points!
As a Roboticist, keep an ear out for anomaly announcements. If you get your hands on an anomaly core, you can build a Phazon mech!
As a Roboticist, you can repair your cyborgs with a welding tool. If they have taken burn damage from lasers, you can remove their battery, expose the wiring with a screwdriver and replace their wires with a cable coil.
As a Roboticist, you can reset a cyborg's module by cutting and mending the reset wire with a wire cutter.
diff --git a/tgstation.dme b/tgstation.dme
index a86250cb4a..c89fff456c 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -835,9 +835,11 @@
#include "code\game\objects\items\AI_modules.dm"
#include "code\game\objects\items\airlock_painter.dm"
#include "code\game\objects\items\apc_frame.dm"
+#include "code\game\objects\items\balls.dm"
#include "code\game\objects\items\blueprints.dm"
#include "code\game\objects\items\body_egg.dm"
#include "code\game\objects\items\bodybag.dm"
+#include "code\game\objects\items\boombox.dm"
#include "code\game\objects\items\candle.dm"
#include "code\game\objects\items\cardboard_cutouts.dm"
#include "code\game\objects\items\cards_ids.dm"
@@ -2011,11 +2013,15 @@
#include "code\modules\lighting\lighting_turf.dm"
#include "code\modules\mapping\dmm_suite.dm"
#include "code\modules\mapping\map_template.dm"
-#include "code\modules\mapping\mapping_helpers.dm"
#include "code\modules\mapping\preloader.dm"
#include "code\modules\mapping\reader.dm"
#include "code\modules\mapping\ruins.dm"
#include "code\modules\mapping\verify.dm"
+#include "code\modules\mapping\mapping_helpers\_mapping_helpers.dm"
+#include "code\modules\mapping\mapping_helpers\baseturf.dm"
+#include "code\modules\mapping\mapping_helpers\network_builder\_network_builder.dm"
+#include "code\modules\mapping\mapping_helpers\network_builder\atmos_pipe.dm"
+#include "code\modules\mapping\mapping_helpers\network_builder\power_cables.dm"
#include "code\modules\mapping\space_management\multiz_helpers.dm"
#include "code\modules\mapping\space_management\space_level.dm"
#include "code\modules\mapping\space_management\space_reservation.dm"
@@ -2750,6 +2756,7 @@
#include "code\modules\research\designs\smelting_designs.dm"
#include "code\modules\research\designs\stock_parts_designs.dm"
#include "code\modules\research\designs\telecomms_designs.dm"
+#include "code\modules\research\designs\tool_designs.dm"
#include "code\modules\research\designs\weapon_designs.dm"
#include "code\modules\research\designs\autolathe_desings\autolathe_designs_construction.dm"
#include "code\modules\research\designs\autolathe_desings\autolathe_designs_electronics.dm"
@@ -3074,7 +3081,6 @@
#include "interface\interface.dm"
#include "interface\menu.dm"
#include "interface\stylesheet.dm"
-#include "modular_citadel\code\init.dm"
#include "modular_citadel\code\__HELPERS\list2list.dm"
#include "modular_citadel\code\__HELPERS\lists.dm"
#include "modular_citadel\code\__HELPERS\mobs.dm"
@@ -3089,15 +3095,7 @@
#include "modular_citadel\code\datums\status_effects\debuffs.dm"
#include "modular_citadel\code\game\machinery\wishgranter.dm"
#include "modular_citadel\code\game\objects\cit_screenshake.dm"
-#include "modular_citadel\code\game\objects\items.dm"
-#include "modular_citadel\code\game\objects\effects\spawner\spawners.dm"
#include "modular_citadel\code\game\objects\effects\temporary_visuals\souldeath.dm"
-#include "modular_citadel\code\game\objects\items\balls.dm"
-#include "modular_citadel\code\game\objects\items\boombox.dm"
-#include "modular_citadel\code\game\objects\items\stunsword.dm"
-#include "modular_citadel\code\game\objects\items\devices\radio\encryptionkey.dm"
-#include "modular_citadel\code\game\objects\items\devices\radio\headset.dm"
-#include "modular_citadel\code\game\objects\items\devices\radio\shockcollar.dm"
#include "modular_citadel\code\modules\admin\admin.dm"
#include "modular_citadel\code\modules\admin\chat_commands.dm"
#include "modular_citadel\code\modules\admin\holder2.dm"
@@ -3145,7 +3143,6 @@
#include "modular_citadel\code\modules\custom_loadout\custom_items.dm"
#include "modular_citadel\code\modules\custom_loadout\load_to_mob.dm"
#include "modular_citadel\code\modules\custom_loadout\read_from_file.dm"
-#include "modular_citadel\code\modules\integrated_electronics\subtypes\manipulation.dm"
#include "modular_citadel\code\modules\mentor\follow.dm"
#include "modular_citadel\code\modules\mentor\mentor.dm"
#include "modular_citadel\code\modules\mentor\mentor_memo.dm"
diff --git a/tgui/src/interfaces/apc.ract b/tgui/src/interfaces/apc.ract
index 6448e4e277..a046cbbd71 100644
--- a/tgui/src/interfaces/apc.ract
+++ b/tgui/src/interfaces/apc.ract
@@ -132,7 +132,7 @@
- {{#if data.locked && !data.siliconUser}}
+ {{#if data.locked && !data.siliconUser && data.lock_nightshift}}
{{data.nightshiftLights ? "Enabled" : "Disabled"}}
{{else}}
{{data.nightshiftLights ? "Enabled" : "Disabled"}}
diff --git a/tgui/src/interfaces/nanite_comm_remote.ract b/tgui/src/interfaces/nanite_comm_remote.ract
new file mode 100644
index 0000000000..9cdc5fb7f3
--- /dev/null
+++ b/tgui/src/interfaces/nanite_comm_remote.ract
@@ -0,0 +1,41 @@
+
+{{#if data.locked}}
+ The interface is locked.
+{{else}}
+ Lock Interface
+ Save Current Setting
+
+ {{data.comm_code}}
+ Set
+
+
+ {{data.comm_message}}
+
+ Set
+
+ {{#if data.mode == "Relay"}}
+
+ {{data.relay_code}}
+ Set
+
+ {{/if}}
+
+ {{data.mode}}
+
+ Off
+ Local
+ Targeted
+ Area
+ Relay
+
+{{/if}}
+
+
+ {{#each data.saved_settings}}
+ {{name}}
+ {{#if !data.locked}}
+ Remove
+ {{/if}}
+
+ {{/each}}
+
diff --git a/tools/travis/check_line_endings.py b/tools/travis/check_line_endings.py
index 3ee7baf7aa..fbbbc41426 100644
--- a/tools/travis/check_line_endings.py
+++ b/tools/travis/check_line_endings.py
@@ -7,8 +7,8 @@ import glob
WINDOWS_NEWLINE = b'\r\n'
FILES_TO_READ = []
-FILES_TO_READ.extend(glob.glob(r"**\*.dm", recursive=True))
-FILES_TO_READ.extend(glob.glob(r"**\*.dmm", recursive=True))
+FILES_TO_READ.extend(glob.glob(r"**/*.dm", recursive=True))
+FILES_TO_READ.extend(glob.glob(r"**/*.dmm", recursive=True))
FILES_TO_READ.extend(glob.glob(r"*.dme"))
#for i in FILES_TO_READ:
# if os.path.isdir(i):