Merge branch 'master' into departmentalclothes

This commit is contained in:
faaaay
2021-07-15 20:06:30 +01:00
committed by GitHub
63 changed files with 2915 additions and 2594 deletions
File diff suppressed because it is too large Load Diff
@@ -1603,7 +1603,7 @@
"evB" = (/obj/machinery/door/window/eastleft{dir = 2; name = "Monkey Pen"; req_one_access_txt = "9"},/obj/machinery/atmospherics/components/unary/vent_pump/on/layer3{name = "air vent"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{name = "scrubbers pipe"},/turf/open/floor/grass,/area/medical/genetics)
"evI" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 9},/turf/closed/wall/r_wall,/area/science/mixing)
"evK" = (/obj/machinery/light{pixel_y = -1},/turf/open/floor/plasteel,/area/security/prison)
"evQ" = (/obj/effect/turf_decal/tile/neutral{dir = 4},/obj/effect/turf_decal/tile/neutral{dir = 1},/turf/open/floor/plasteel/dark,/area/security/brig)
"evQ" = (/obj/effect/turf_decal/tile/neutral{dir = 4},/obj/effect/turf_decal/tile/neutral{dir = 1},/obj/machinery/computer/lore_terminal/security,/turf/open/floor/plasteel/dark,/area/security/brig)
"evR" = (/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/incinerator_output{dir = 8},/turf/open/floor/engine,/area/maintenance/disposal/incinerator)
"evT" = (/obj/structure/cable{icon_state = "0-4"},/obj/machinery/power/apc{areastring = "/area/maintenance/solars/port/aft"; dir = 8; name = "Port Quarter Solar APC"; pixel_x = -25; pixel_y = 3},/turf/open/floor/plating,/area/maintenance/solars/port/aft)
"evV" = (/obj/structure/trash_pile,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/open/floor/plasteel/dark,/area/maintenance/fore)
@@ -3526,7 +3526,7 @@
"jUE" = (/obj/effect/turf_decal/loading_area{dir = 1; icon_state = "drain"; name = "drain"},/obj/effect/turf_decal/tile/purple{dir = 8},/turf/open/floor/plasteel/white/corner,/area/hallway/primary/aft)
"jUP" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{dir = 8; name = "air supply pipe"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{dir = 4; name = "scrubbers pipe"},/obj/structure/cable{icon_state = "4-8"},/obj/structure/cable{icon_state = "1-4"},/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/cable{icon_state = "2-4"},/turf/open/floor/plasteel/white,/area/medical/genetics)
"jUT" = (/obj/structure/table,/obj/item/stack/ore/iron,/turf/open/floor/plating,/area/maintenance/starboard)
"jUU" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{dir = 6; name = "air supply pipe"},/turf/open/floor/plasteel/dark,/area/security/prison)
"jUU" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{dir = 6; name = "air supply pipe"},/obj/machinery/computer/lore_terminal/security,/turf/open/floor/plasteel/dark,/area/security/prison)
"jUY" = (/turf/open/floor/plating/asteroid/layenia,/area/layenia/cloudlayer)
"jVg" = (/obj/structure/railing{dir = 8},/turf/open/floor/plasteel/dark,/area/hallway/primary/starboard)
"jVq" = (/obj/effect/spawner/structure/window,/obj/machinery/door/firedoor,/turf/open/floor/plating,/area/medical/chemistry)
@@ -4361,7 +4361,7 @@
"mwm" = (/obj/machinery/atmospherics/pipe/manifold/general/visible{dir = 8},/obj/effect/turf_decal/stripes/line{dir = 8},/obj/effect/turf_decal/tile/neutral{dir = 1},/obj/effect/turf_decal/tile/neutral,/obj/effect/turf_decal/tile/neutral{dir = 4},/obj/effect/turf_decal/tile/neutral{dir = 8},/obj/effect/landmark/start/scientist,/turf/open/floor/plasteel/dark,/area/science/mixing)
"mwz" = (/obj/machinery/door/airlock/maintenance{name = "Bar Maintenance"; req_access_txt = "25"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{name = "scrubbers pipe"},/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{name = "air supply pipe"},/obj/structure/cable{icon_state = "1-2"},/obj/structure/disposalpipe/segment,/turf/open/floor/plasteel/dark,/area/maintenance/fore/secondary)
"mwC" = (/obj/effect/turf_decal/tile/blue{dir = 8},/obj/effect/turf_decal/tile/blue{dir = 1},/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{name = "air supply pipe"},/obj/structure/disposalpipe/segment{dir = 4},/obj/item/radio/intercom{frequency = 1485; name = "Station Intercom (Medbay)"; pixel_x = -30},/turf/open/floor/plasteel/white,/area/medical/sleeper)
"mwT" = (/obj/effect/turf_decal/tile/red{dir = 1},/obj/effect/turf_decal/tile/red{dir = 4},/obj/effect/turf_decal/tile/neutral{dir = 8},/obj/effect/turf_decal/tile/neutral,/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer1{name = "air scrubber"},/turf/open/floor/plasteel/dark/side,/area/security/main)
"mwT" = (/obj/effect/turf_decal/tile/red{dir = 1},/obj/effect/turf_decal/tile/red{dir = 4},/obj/effect/turf_decal/tile/neutral{dir = 8},/obj/effect/turf_decal/tile/neutral,/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer1{name = "air scrubber"},/obj/machinery/computer/lore_terminal/security,/turf/open/floor/plasteel/dark/side,/area/security/main)
"mwV" = (/turf/open/floor/plasteel/stairs/medium,/area/hallway/primary/port)
"mxe" = (/obj/structure/closet/secure_closet/detective,/turf/open/floor/wood,/area/security/detectives_office)
"mxg" = (/obj/machinery/light{pixel_y = -1},/turf/open/chasm/cloud,/area/layenia/cloudlayer)
@@ -8537,7 +8537,7 @@
"xxr" = (/obj/effect/turf_decal/stripes/line,/obj/docking_port/stationary/random{dir = 2; id = "pod_lavaland4"; name = "lavaland"},/turf/open/indestructible/concrete,/area/layenia/cloudlayer)
"xxA" = (/turf/open/floor/plasteel/yellowsiding{dir = 4},/area/maintenance/fore)
"xxF" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{dir = 8; name = "air supply pipe"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{dir = 4; name = "scrubbers pipe"},/turf/open/floor/plasteel,/area/security/main)
"xxL" = (/obj/effect/turf_decal/tile/red{dir = 4},/obj/effect/turf_decal/tile/red{dir = 1},/obj/machinery/computer/lore_terminal,/turf/open/floor/plasteel{icon_state = "floor_plate"},/area/security/brig)
"xxL" = (/obj/effect/turf_decal/tile/red{dir = 4},/obj/effect/turf_decal/tile/red{dir = 1},/obj/machinery/computer/lore_terminal/security,/turf/open/floor/plasteel{icon_state = "floor_plate"},/area/security/brig)
"xxU" = (/obj/item/twohanded/required/fuel_rod,/obj/effect/turf_decal/stripes/line{dir = 4},/turf/open/pool,/area/engine/engineering/reactor_core)
"xxV" = (/obj/structure/closet/secure_closet/medical1,/obj/effect/turf_decal/stripes/line{dir = 1},/obj/machinery/light{pixel_y = -1},/turf/open/floor/plasteel/dark,/area/gateway)
"xxW" = (/turf/open/floor/plasteel/stairs/medium{dir = 4},/area/security/main)
+1 -3
View File
@@ -7,12 +7,10 @@ SUBSYSTEM_DEF(vis_overlays)
var/list/vis_overlay_cache
var/list/unique_vis_overlays
var/list/currentrun
var/datum/callback/rotate_cb
/datum/controller/subsystem/vis_overlays/Initialize()
vis_overlay_cache = list()
unique_vis_overlays = list()
rotate_cb = CALLBACK(src, .proc/rotate_vis_overlay)
return ..()
/datum/controller/subsystem/vis_overlays/fire(resumed = FALSE)
@@ -57,7 +55,7 @@ SUBSYSTEM_DEF(vis_overlays)
if(!thing.managed_vis_overlays)
thing.managed_vis_overlays = list(overlay)
RegisterSignal(thing, COMSIG_ATOM_DIR_CHANGE, rotate_cb)
RegisterSignal(thing, COMSIG_ATOM_DIR_CHANGE, .proc/rotate_vis_overlay)
else
thing.managed_vis_overlays += overlay
+1 -1
View File
@@ -1,6 +1,6 @@
#define DYNAMIC_DEFAULT_CHAOS 1.0 //The default chaos value for low pop low vote rounds
#define DYNAMIC_VOTE_NORMALIZATION 8 //If there are fewer than this many votes, the average will be skewed towards the default
#define DYNAMIC_NONVOTER_FACTOR 0.6 // 1 means they count for a full vote
#define DYNAMIC_NONVOTER_FACTOR 1 // 1 means they count for a full vote
#define DYNAMIC_NONVOTER_VALUE 1.5 // The chaos value that non-voters should account for.
SUBSYSTEM_DEF(vote)
+315 -318
View File
@@ -1,318 +1,315 @@
/datum/component
var/dupe_mode = COMPONENT_DUPE_HIGHLANDER
var/dupe_type
var/datum/parent
//only set to true if you are able to properly transfer this component
//At a minimum RegisterWithParent and UnregisterFromParent should be used
//Make sure you also implement PostTransfer for any post transfer handling
var/can_transfer = FALSE
/datum/component/New(datum/P, ...)
parent = P
var/list/arguments = args.Copy(2)
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
qdel(src, TRUE, TRUE)
CRASH("Incompatible [type] assigned to a [P.type]! args: [json_encode(arguments)]")
_JoinParent(P)
/datum/component/proc/_JoinParent()
var/datum/P = parent
//lazy init the parent's dc list
var/list/dc = P.datum_components
if(!dc)
P.datum_components = dc = list()
//set up the typecache
var/our_type = type
for(var/I in _GetInverseTypeList(our_type))
var/test = dc[I]
if(test) //already another component of this type here
var/list/components_of_type
if(!length(test))
components_of_type = list(test)
dc[I] = components_of_type
else
components_of_type = test
if(I == our_type) //exact match, take priority
var/inserted = FALSE
for(var/J in 1 to components_of_type.len)
var/datum/component/C = components_of_type[J]
if(C.type != our_type) //but not over other exact matches
components_of_type.Insert(J, I)
inserted = TRUE
break
if(!inserted)
components_of_type += src
else //indirect match, back of the line with ya
components_of_type += src
else //only component of this type, no list
dc[I] = src
RegisterWithParent()
// If you want/expect to be moving the component around between parents, use this to register on the parent for signals
/datum/component/proc/RegisterWithParent()
return
/datum/component/proc/Initialize(...)
return
/datum/component/Destroy(force=FALSE, silent=FALSE)
if(!force && parent)
_RemoveFromParent()
if(!silent)
SEND_SIGNAL(parent, COMSIG_COMPONENT_REMOVING, src)
parent = null
return ..()
/datum/component/proc/_RemoveFromParent()
var/datum/P = parent
var/list/dc = P.datum_components
for(var/I in _GetInverseTypeList())
var/list/components_of_type = dc[I]
if(length(components_of_type)) //
var/list/subtracted = components_of_type - src
if(subtracted.len == 1) //only 1 guy left
dc[I] = subtracted[1] //make him special
else
dc[I] = subtracted
else //just us
dc -= I
if(!dc.len)
P.datum_components = null
UnregisterFromParent()
/datum/component/proc/UnregisterFromParent()
return
/datum/proc/RegisterSignal(datum/target, sig_type_or_types, proc_or_callback, override = FALSE)
if(QDELETED(src) || QDELETED(target))
return
var/list/procs = signal_procs
if(!procs)
signal_procs = procs = list()
if(!procs[target])
procs[target] = list()
var/list/lookup = target.comp_lookup
if(!lookup)
target.comp_lookup = lookup = list()
if(!istype(proc_or_callback, /datum/callback)) //if it wasnt a callback before, it is now
proc_or_callback = CALLBACK(src, proc_or_callback)
var/list/sig_types = islist(sig_type_or_types) ? sig_type_or_types : list(sig_type_or_types)
for(var/sig_type in sig_types)
if(!override && procs[target][sig_type])
stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning")
procs[target][sig_type] = proc_or_callback
if(!lookup[sig_type]) // Nothing has registered here yet
lookup[sig_type] = src
else if(lookup[sig_type] == src) // We already registered here
continue
else if(!length(lookup[sig_type])) // One other thing registered here
lookup[sig_type] = list(lookup[sig_type]=TRUE)
lookup[sig_type][src] = TRUE
else // Many other things have registered here
lookup[sig_type][src] = TRUE
signal_enabled = TRUE
/datum/proc/UnregisterSignal(datum/target, sig_type_or_types)
if(!target)
CRASH("[src] tried to unregister a signal without having a target.")
var/list/lookup = target.comp_lookup
if(!signal_procs || !signal_procs[target] || !lookup)
return
if(!islist(sig_type_or_types))
sig_type_or_types = list(sig_type_or_types)
for(var/sig in sig_type_or_types)
switch(length(lookup[sig]))
if(2)
lookup[sig] = (lookup[sig]-src)[1]
if(1)
stack_trace("[target] ([target.type]) somehow has single length list inside comp_lookup")
if(src in lookup[sig])
lookup -= sig
if(!length(lookup))
target.comp_lookup = null
break
if(0)
lookup -= sig
if(!length(lookup))
target.comp_lookup = null
break
else
lookup[sig] -= src
signal_procs[target] -= sig_type_or_types
if(!signal_procs[target].len)
signal_procs -= target
/datum/component/proc/InheritComponent(datum/component/C, i_am_original)
return
/datum/component/proc/PreTransfer()
return
/datum/component/proc/PostTransfer()
return COMPONENT_INCOMPATIBLE //Do not support transfer by default as you must properly support it
/datum/component/proc/_GetInverseTypeList(our_type = type)
//we can do this one simple trick
var/current_type = parent_type
. = list(our_type, current_type)
//and since most components are root level + 1, this won't even have to run
while (current_type != /datum/component)
current_type = type2parent(current_type)
. += current_type
/datum/proc/_SendSignal(sigtype, list/arguments)
var/target = comp_lookup[sigtype]
if(!length(target))
var/datum/C = target
if(!C.signal_enabled)
return NONE
var/datum/callback/CB = C.signal_procs[src][sigtype]
return CB.InvokeAsync(arglist(arguments))
. = NONE
for(var/I in target)
var/datum/C = I
if(!C.signal_enabled)
continue
var/datum/callback/CB = C.signal_procs[src][sigtype]
. |= CB.InvokeAsync(arglist(arguments))
/datum/proc/GetComponent(c_type)
var/list/dc = datum_components
if(!dc)
return null
. = dc[c_type]
if(length(.))
return .[1]
/datum/proc/GetExactComponent(c_type)
var/list/dc = datum_components
if(!dc)
return null
var/datum/component/C = dc[c_type]
if(C)
if(length(C))
C = C[1]
if(C.type == c_type)
return C
return null
/datum/proc/GetComponents(c_type)
var/list/dc = datum_components
if(!dc)
return null
. = dc[c_type]
if(!length(.))
return list(.)
/datum/proc/AddComponent(new_type, ...)
var/datum/component/nt = new_type
var/dm = initial(nt.dupe_mode)
var/dt = initial(nt.dupe_type)
var/datum/component/old_comp
var/datum/component/new_comp
if(ispath(nt))
if(nt == /datum/component)
CRASH("[nt] attempted instantiation!")
if(!isnum(dm))
CRASH("[nt]: Invalid dupe_mode ([dm])!")
if(dt && !ispath(dt))
CRASH("[nt]: Invalid dupe_type ([dt])!")
else
new_comp = nt
nt = new_comp.type
args[1] = src
if(dm != COMPONENT_DUPE_ALLOWED)
if(!dt)
old_comp = GetExactComponent(nt)
else
old_comp = GetComponent(dt)
if(old_comp)
switch(dm)
if(COMPONENT_DUPE_UNIQUE)
if(!new_comp)
new_comp = new nt(arglist(args))
if(!QDELETED(new_comp))
old_comp.InheritComponent(new_comp, TRUE)
QDEL_NULL(new_comp)
if(COMPONENT_DUPE_HIGHLANDER)
if(!new_comp)
new_comp = new nt(arglist(args))
if(!QDELETED(new_comp))
new_comp.InheritComponent(old_comp, FALSE)
QDEL_NULL(old_comp)
if(COMPONENT_DUPE_UNIQUE_PASSARGS)
if(!new_comp)
var/list/arguments = args.Copy(2)
old_comp.InheritComponent(null, TRUE, arguments)
else
old_comp.InheritComponent(new_comp, TRUE)
else if(!new_comp)
new_comp = new nt(arglist(args)) // There's a valid dupe mode but there's no old component, act like normal
else if(!new_comp)
new_comp = new nt(arglist(args)) // Dupes are allowed, act like normal
if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy
SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_comp)
return new_comp
return old_comp
/datum/proc/LoadComponent(component_type, ...)
. = GetComponent(component_type)
if(!.)
return AddComponent(arglist(args))
/datum/component/proc/RemoveComponent()
if(!parent)
return
var/datum/old_parent = parent
PreTransfer()
_RemoveFromParent()
parent = null
SEND_SIGNAL(old_parent, COMSIG_COMPONENT_REMOVING, src)
/datum/proc/TakeComponent(datum/component/target)
if(!target || target.parent == src)
return
if(target.parent)
target.RemoveComponent()
target.parent = src
var/result = target.PostTransfer()
switch(result)
if(COMPONENT_INCOMPATIBLE)
var/c_type = target.type
qdel(target)
CRASH("Incompatible [c_type] transfer attempt to a [type]!")
if(target == AddComponent(target))
target._JoinParent()
/datum/proc/TransferComponents(datum/target)
var/list/dc = datum_components
if(!dc)
return
var/comps = dc[/datum/component]
if(islist(comps))
for(var/datum/component/I in comps)
if(I.can_transfer)
target.TakeComponent(I)
else
var/datum/component/C = comps
if(C.can_transfer)
target.TakeComponent(comps)
/datum/component/ui_host()
return parent
/datum/component
var/dupe_mode = COMPONENT_DUPE_HIGHLANDER
var/dupe_type
var/datum/parent
//only set to true if you are able to properly transfer this component
//At a minimum RegisterWithParent and UnregisterFromParent should be used
//Make sure you also implement PostTransfer for any post transfer handling
var/can_transfer = FALSE
/datum/component/New(datum/P, ...)
parent = P
var/list/arguments = args.Copy(2)
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
qdel(src, TRUE, TRUE)
CRASH("Incompatible [type] assigned to a [P.type]! args: [json_encode(arguments)]")
_JoinParent(P)
/datum/component/proc/_JoinParent()
var/datum/P = parent
//lazy init the parent's dc list
var/list/dc = P.datum_components
if(!dc)
P.datum_components = dc = list()
//set up the typecache
var/our_type = type
for(var/I in _GetInverseTypeList(our_type))
var/test = dc[I]
if(test) //already another component of this type here
var/list/components_of_type
if(!length(test))
components_of_type = list(test)
dc[I] = components_of_type
else
components_of_type = test
if(I == our_type) //exact match, take priority
var/inserted = FALSE
for(var/J in 1 to components_of_type.len)
var/datum/component/C = components_of_type[J]
if(C.type != our_type) //but not over other exact matches
components_of_type.Insert(J, I)
inserted = TRUE
break
if(!inserted)
components_of_type += src
else //indirect match, back of the line with ya
components_of_type += src
else //only component of this type, no list
dc[I] = src
RegisterWithParent()
// If you want/expect to be moving the component around between parents, use this to register on the parent for signals
/datum/component/proc/RegisterWithParent()
return
/datum/component/proc/Initialize(...)
return
/datum/component/Destroy(force=FALSE, silent=FALSE)
if(!force && parent)
_RemoveFromParent()
if(!silent)
SEND_SIGNAL(parent, COMSIG_COMPONENT_REMOVING, src)
parent = null
return ..()
/datum/component/proc/_RemoveFromParent()
var/datum/P = parent
var/list/dc = P.datum_components
for(var/I in _GetInverseTypeList())
var/list/components_of_type = dc[I]
if(length(components_of_type)) //
var/list/subtracted = components_of_type - src
if(subtracted.len == 1) //only 1 guy left
dc[I] = subtracted[1] //make him special
else
dc[I] = subtracted
else //just us
dc -= I
if(!dc.len)
P.datum_components = null
UnregisterFromParent()
/datum/component/proc/UnregisterFromParent()
return
/datum/proc/RegisterSignal(datum/target, sig_type_or_types, proctype, override = FALSE)
if(QDELETED(src) || QDELETED(target))
return
var/list/procs = signal_procs
if(!procs)
signal_procs = procs = list()
if(!procs[target])
procs[target] = list()
var/list/lookup = target.comp_lookup
if(!lookup)
target.comp_lookup = lookup = list()
var/list/sig_types = islist(sig_type_or_types) ? sig_type_or_types : list(sig_type_or_types)
for(var/sig_type in sig_types)
if(!override && procs[target][sig_type])
stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning")
procs[target][sig_type] = proctype
if(!lookup[sig_type]) // Nothing has registered here yet
lookup[sig_type] = src
else if(lookup[sig_type] == src) // We already registered here
continue
else if(!length(lookup[sig_type])) // One other thing registered here
lookup[sig_type] = list(lookup[sig_type]=TRUE)
lookup[sig_type][src] = TRUE
else // Many other things have registered here
lookup[sig_type][src] = TRUE
signal_enabled = TRUE
/datum/proc/UnregisterSignal(datum/target, sig_type_or_types)
if(!target)
CRASH("[src] tried to unregister a signal without having a target.")
var/list/lookup = target.comp_lookup
if(!signal_procs || !signal_procs[target] || !lookup)
return
if(!islist(sig_type_or_types))
sig_type_or_types = list(sig_type_or_types)
for(var/sig in sig_type_or_types)
switch(length(lookup[sig]))
if(2)
lookup[sig] = (lookup[sig]-src)[1]
if(1)
stack_trace("[target] ([target.type]) somehow has single length list inside comp_lookup")
if(src in lookup[sig])
lookup -= sig
if(!length(lookup))
target.comp_lookup = null
break
if(0)
lookup -= sig
if(!length(lookup))
target.comp_lookup = null
break
else
lookup[sig] -= src
signal_procs[target] -= sig_type_or_types
if(!signal_procs[target].len)
signal_procs -= target
/datum/component/proc/InheritComponent(datum/component/C, i_am_original)
return
/datum/component/proc/PreTransfer()
return
/datum/component/proc/PostTransfer()
return COMPONENT_INCOMPATIBLE //Do not support transfer by default as you must properly support it
/datum/component/proc/_GetInverseTypeList(our_type = type)
//we can do this one simple trick
var/current_type = parent_type
. = list(our_type, current_type)
//and since most components are root level + 1, this won't even have to run
while (current_type != /datum/component)
current_type = type2parent(current_type)
. += current_type
/datum/proc/_SendSignal(sigtype, list/arguments)
var/target = comp_lookup[sigtype]
if(!length(target))
var/datum/C = target
if(!C.signal_enabled)
return NONE
var/proctype = C.signal_procs[src][sigtype]
return NONE | CallAsync(C, proctype, arguments)
. = NONE
for(var/I in target)
var/datum/C = I
if(!C.signal_enabled)
continue
var/proctype = C.signal_procs[src][sigtype]
. |= CallAsync(C, proctype, arguments)
// The type arg is casted so initial works, you shouldn't be passing a real instance into this
/datum/proc/GetComponent(datum/component/c_type)
if(initial(c_type.dupe_mode) == COMPONENT_DUPE_ALLOWED)
stack_trace("GetComponent was called to get a component of which multiple copies could be on an object. This can easily break and should be changed. Type: \[[c_type]\]")
var/list/dc = datum_components
if(!dc)
return null
. = dc[c_type]
if(length(.))
return .[1]
/datum/proc/GetExactComponent(c_type)
var/list/dc = datum_components
if(!dc)
return null
var/datum/component/C = dc[c_type]
if(C)
if(length(C))
C = C[1]
if(C.type == c_type)
return C
return null
/datum/proc/GetComponents(c_type)
var/list/dc = datum_components
if(!dc)
return null
. = dc[c_type]
if(!length(.))
return list(.)
/datum/proc/AddComponent(new_type, ...)
var/datum/component/nt = new_type
var/dm = initial(nt.dupe_mode)
var/dt = initial(nt.dupe_type)
var/datum/component/old_comp
var/datum/component/new_comp
if(ispath(nt))
if(nt == /datum/component)
CRASH("[nt] attempted instantiation!")
else
new_comp = nt
nt = new_comp.type
args[1] = src
if(dm != COMPONENT_DUPE_ALLOWED)
if(!dt)
old_comp = GetExactComponent(nt)
else
old_comp = GetComponent(dt)
if(old_comp)
switch(dm)
if(COMPONENT_DUPE_UNIQUE)
if(!new_comp)
new_comp = new nt(arglist(args))
if(!QDELETED(new_comp))
old_comp.InheritComponent(new_comp, TRUE)
QDEL_NULL(new_comp)
if(COMPONENT_DUPE_HIGHLANDER)
if(!new_comp)
new_comp = new nt(arglist(args))
if(!QDELETED(new_comp))
new_comp.InheritComponent(old_comp, FALSE)
QDEL_NULL(old_comp)
if(COMPONENT_DUPE_UNIQUE_PASSARGS)
if(!new_comp)
var/list/arguments = args.Copy(2)
old_comp.InheritComponent(null, TRUE, arguments)
else
old_comp.InheritComponent(new_comp, TRUE)
else if(!new_comp)
new_comp = new nt(arglist(args)) // There's a valid dupe mode but there's no old component, act like normal
else if(!new_comp)
new_comp = new nt(arglist(args)) // Dupes are allowed, act like normal
if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy
SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_comp)
return new_comp
return old_comp
/datum/proc/LoadComponent(component_type, ...)
. = GetComponent(component_type)
if(!.)
return AddComponent(arglist(args))
/datum/component/proc/RemoveComponent()
if(!parent)
return
var/datum/old_parent = parent
PreTransfer()
_RemoveFromParent()
parent = null
SEND_SIGNAL(old_parent, COMSIG_COMPONENT_REMOVING, src)
/datum/proc/TakeComponent(datum/component/target)
if(!target || target.parent == src)
return
if(target.parent)
target.RemoveComponent()
target.parent = src
var/result = target.PostTransfer()
switch(result)
if(COMPONENT_INCOMPATIBLE)
var/c_type = target.type
qdel(target)
CRASH("Incompatible [c_type] transfer attempt to a [type]!")
if(target == AddComponent(target))
target._JoinParent()
/datum/proc/TransferComponents(datum/target)
var/list/dc = datum_components
if(!dc)
return
var/comps = dc[/datum/component]
if(islist(comps))
for(var/datum/component/I in comps)
if(I.can_transfer)
target.TakeComponent(I)
else
var/datum/component/C = comps
if(C.can_transfer)
target.TakeComponent(comps)
/datum/component/ui_host()
return parent
+1 -1
View File
@@ -1,11 +1,11 @@
/datum/component/wearertargeting/earprotection
signals = list(COMSIG_CARBON_SOUNDBANG)
mobtype = /mob/living/carbon
proctype = .proc/reducebang
/datum/component/wearertargeting/earprotection/Initialize(_valid_slots)
. = ..()
valid_slots = _valid_slots
callback = CALLBACK(src, .proc/reducebang)
/datum/component/wearertargeting/earprotection/proc/reducebang(datum/source, list/reflist)
reflist[1]--
-2
View File
@@ -261,8 +261,6 @@
if(the_event.timeout)
addtimer(CALLBACK(src, .proc/clear_event, null, category), the_event.timeout, TIMER_UNIQUE|TIMER_OVERRIDE)
return the_event
/datum/component/mood/proc/clear_event(datum/source, category)
var/datum/mood_event/event = mood_events[category]
if(!event)
+4 -9
View File
@@ -1,8 +1,7 @@
/datum/component/orbiter
can_transfer = TRUE
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
var/list/orbiters
var/datum/callback/orbiter_spy
var/datum/callback/orbited_spy
//radius: range to orbit at, radius of the circle formed by orbiting (in pixels)
//clockwise: whether you orbit clockwise or anti clockwise
@@ -14,8 +13,6 @@
return COMPONENT_INCOMPATIBLE
orbiters = list()
orbiter_spy = CALLBACK(src, .proc/orbiter_move_react)
orbited_spy = CALLBACK(src, .proc/move_react)
var/atom/master = parent
master.orbiters = src
@@ -25,7 +22,7 @@
/datum/component/orbiter/RegisterWithParent()
var/atom/target = parent
while(ismovableatom(target))
RegisterSignal(target, COMSIG_MOVABLE_MOVED, orbited_spy)
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/move_react)
target = target.loc
RegisterSignal(parent, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, .proc/orbiter_glide_size_update)
@@ -44,8 +41,6 @@
for(var/i in orbiters)
end_orbit(i)
orbiters = null
QDEL_NULL(orbiter_spy)
QDEL_NULL(orbited_spy)
return ..()
/datum/component/orbiter/InheritComponent(datum/component/orbiter/newcomp, original, list/arguments)
@@ -69,7 +64,7 @@
orbiter.orbiting.end_orbit(orbiter)
orbiters[orbiter] = TRUE
orbiter.orbiting = src
RegisterSignal(orbiter, COMSIG_MOVABLE_MOVED, orbiter_spy)
RegisterSignal(orbiter, COMSIG_MOVABLE_MOVED, .proc/orbiter_move_react)
var/matrix/initial_transform = matrix(orbiter.transform)
orbiters[orbiter] = initial_transform
@@ -137,7 +132,7 @@
if(orbited?.loc && orbited.loc != newturf) // We want to know when anything holding us moves too
var/atom/target = orbited.loc
while(ismovableatom(target))
RegisterSignal(target, COMSIG_MOVABLE_MOVED, orbited_spy, TRUE)
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/move_react, TRUE)
target = target.loc
var/atom/curloc = master.loc
+39
View File
@@ -0,0 +1,39 @@
//This component applies a customizable drop_shadow filter to its wearer when they toggle combat mode on or off. This can stack.
/datum/component/wearertargeting/phantomthief
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
signals = list(COMSIG_COMBAT_TOGGLED)
proctype = .proc/handlefilterstuff
var/filter_x
var/filter_y
var/filter_size
var/filter_border
var/filter_color
/datum/component/wearertargeting/phantomthief/Initialize(_x = -2, _y = 0, _size = 0, _border = 0, _color = "#E62111", list/_valid_slots = list(SLOT_GLASSES))
. = ..()
if(. == COMPONENT_INCOMPATIBLE)
return
filter_x = _x
filter_y = _y
filter_size = _size
filter_border = _border
filter_color = _color
valid_slots = _valid_slots
/datum/component/wearertargeting/phantomthief/proc/handlefilterstuff(datum/source, mob/user, combatmodestate)
if(istype(user))
var/thefilter = filter(type = "drop_shadow", x = filter_x, y = filter_y, size = filter_size, border = filter_border, color = filter_color)
if(!combatmodestate)
user.filters -= thefilter
else
user.filters += thefilter
/datum/component/wearertargeting/phantomthief/proc/stripdesiredfilter(mob/user)
if(istype(user))
var/thefilter = filter(type = "drop_shadow", x = filter_x, y = filter_y, size = filter_size, border = filter_border, color = filter_color)
user.filters -= thefilter
/datum/component/wearertargeting/phantomthief/on_drop(datum/source, mob/user)
. = ..()
stripdesiredfilter(user)
-33
View File
@@ -1,33 +0,0 @@
// This should only be used by non components trying to listen to a signal
// If you use this inside a component I will replace your eyes with lemons ~ninjanomnom
/datum/component/redirect
dupe_mode = COMPONENT_DUPE_ALLOWED
var/list/signals
var/datum/callback/turfchangeCB
/datum/component/redirect/Initialize(list/_signals, flags=NONE)
//It's not our job to verify the right signals are registered here, just do it.
if(!LAZYLEN(_signals))
return COMPONENT_INCOMPATIBLE
if(flags & REDIRECT_TRANSFER_WITH_TURF && isturf(parent))
// If they also want to listen to the turf change then we need to set it up so both callbacks run
if(_signals[COMSIG_TURF_CHANGE])
turfchangeCB = _signals[COMSIG_TURF_CHANGE]
if(!istype(turfchangeCB))
. = COMPONENT_INCOMPATIBLE
CRASH("Redirect components must be given instanced callbacks, not proc paths.")
_signals[COMSIG_TURF_CHANGE] = CALLBACK(src, .proc/turf_change)
signals = _signals
/datum/component/redirect/RegisterWithParent()
for(var/signal in signals)
RegisterSignal(parent, signal, signals[signal])
/datum/component/redirect/UnregisterFromParent()
UnregisterSignal(parent, signals)
/datum/component/redirect/proc/turf_change(datum/source, path, new_baseturfs, flags, list/transfers)
transfers += src
return turfchangeCB?.InvokeAsync(arglist(args))
+3 -7
View File
@@ -3,7 +3,7 @@
/datum/component/wearertargeting
var/list/valid_slots = list()
var/list/signals = list()
var/datum/callback/callback = CALLBACK(GLOBAL_PROC, .proc/pass)
var/proctype = .proc/pass
var/mobtype = /mob/living
/datum/component/wearertargeting/Initialize()
@@ -14,13 +14,9 @@
/datum/component/wearertargeting/proc/on_equip(datum/source, mob/equipper, slot)
if((slot in valid_slots) && istype(equipper, mobtype))
RegisterSignal(equipper, signals, callback, TRUE)
RegisterSignal(equipper, signals, proctype, TRUE)
else
UnregisterSignal(equipper, signals)
/datum/component/wearertargeting/proc/on_drop(datum/source, mob/user)
UnregisterSignal(user, signals)
/datum/component/wearertargeting/Destroy()
QDEL_NULL(callback) //is likely to ourselves.
return ..()
UnregisterSignal(user, signals)
+206 -206
View File
@@ -1,206 +1,206 @@
/datum/component/wet_floor
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
can_transfer = TRUE
var/highest_strength = TURF_DRY
var/lube_flags = NONE //why do we have this?
var/list/time_left_list //In deciseconds.
var/static/mutable_appearance/permafrost_overlay = mutable_appearance('icons/effects/water.dmi', "ice_floor")
var/static/mutable_appearance/ice_overlay = mutable_appearance('icons/turf/overlays.dmi', "snowfloor")
var/static/mutable_appearance/water_overlay = mutable_appearance('icons/effects/water.dmi', "wet_floor_static")
var/static/mutable_appearance/generic_turf_overlay = mutable_appearance('icons/effects/water.dmi', "wet_static")
var/current_overlay
var/permanent = FALSE
var/last_process = 0
/datum/component/wet_floor/InheritComponent(datum/newcomp, orig, argslist)
if(!newcomp) //We are getting passed the arguments of a would-be new component, but not a new component
add_wet(arglist(argslist))
else //We are being passed in a full blown component
var/datum/component/wet_floor/WF = newcomp //Lets make an assumption
if(WF.gc()) //See if it's even valid, still. Also does LAZYLEN and stuff for us.
CRASH("Wet floor component tried to inherit another, but the other was able to garbage collect while being inherited! What a waste of time!")
return
for(var/i in WF.time_left_list)
add_wet(text2num(i), WF.time_left_list[i])
/datum/component/wet_floor/Initialize(strength, duration_minimum, duration_add, duration_maximum, _permanent = FALSE)
if(!isopenturf(parent))
return COMPONENT_INCOMPATIBLE
add_wet(strength, duration_minimum, duration_add, duration_maximum)
permanent = _permanent
if(!permanent)
START_PROCESSING(SSwet_floors, src)
addtimer(CALLBACK(src, .proc/gc, TRUE), 1) //GC after initialization.
last_process = world.time
/datum/component/wet_floor/RegisterWithParent()
RegisterSignal(parent, COMSIG_TURF_IS_WET, .proc/is_wet)
RegisterSignal(parent, COMSIG_TURF_MAKE_DRY, .proc/dry)
/datum/component/wet_floor/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_TURF_IS_WET, COMSIG_TURF_MAKE_DRY))
/datum/component/wet_floor/Destroy()
STOP_PROCESSING(SSwet_floors, src)
var/turf/T = parent
qdel(T.GetComponent(/datum/component/slippery))
if(istype(T)) //If this is false there is so many things wrong with it.
T.cut_overlay(current_overlay)
else
stack_trace("Warning: Wet floor component wasn't on a turf when being destroyed! This is really bad!")
return ..()
/datum/component/wet_floor/proc/update_overlay()
var/intended
if(!istype(parent, /turf/open/floor))
intended = generic_turf_overlay
else
switch(highest_strength)
if(TURF_WET_PERMAFROST)
intended = permafrost_overlay
if(TURF_WET_ICE)
intended = ice_overlay
else
intended = water_overlay
if(current_overlay != intended)
var/turf/T = parent
T.cut_overlay(current_overlay)
T.add_overlay(intended)
current_overlay = intended
/datum/component/wet_floor/proc/AfterSlip(mob/living/L)
if(highest_strength == TURF_WET_LUBE)
L.confused = max(L.confused, 8)
/datum/component/wet_floor/proc/update_flags()
var/intensity
lube_flags = NONE
switch(highest_strength)
if(TURF_WET_WATER)
intensity = 60
lube_flags = NO_SLIP_WHEN_WALKING
if(TURF_WET_LUBE)
intensity = 80
lube_flags = SLIDE | GALOSHES_DONT_HELP
if(TURF_WET_ICE)
intensity = 120
lube_flags = SLIDE | GALOSHES_DONT_HELP
if(TURF_WET_PERMAFROST)
intensity = 120
lube_flags = SLIDE_ICE | GALOSHES_DONT_HELP
else
qdel(parent.GetComponent(/datum/component/slippery))
return
var/datum/component/slippery/S = parent.LoadComponent(/datum/component/slippery, NONE, CALLBACK(src, .proc/AfterSlip))
S.intensity = intensity
S.lube_flags = lube_flags
/datum/component/wet_floor/proc/dry(datum/source, strength = TURF_WET_WATER, immediate = FALSE, duration_decrease = INFINITY)
for(var/i in time_left_list)
if(text2num(i) <= strength)
time_left_list[i] = max(0, time_left_list[i] - duration_decrease)
if(immediate)
check()
/datum/component/wet_floor/proc/max_time_left()
. = 0
for(var/i in time_left_list)
. = max(., time_left_list[i])
/datum/component/wet_floor/process()
var/turf/open/T = parent
var/diff = world.time - last_process
var/decrease = 0
var/t = T.GetTemperature()
switch(t)
if(-INFINITY to T0C)
add_wet(TURF_WET_ICE, max_time_left()) //Water freezes into ice!
if(T0C to T0C + 100)
decrease = ((T.air.temperature - T0C) / SSwet_floors.temperature_coeff) * (diff / SSwet_floors.time_ratio)
if(T0C + 100 to INFINITY)
decrease = INFINITY
decrease = max(0, decrease)
if((is_wet() & TURF_WET_ICE) && t > T0C) //Ice melts into water!
for(var/obj/O in T.contents)
if(O.obj_flags & FROZEN)
O.make_unfrozen()
add_wet(TURF_WET_WATER, max_time_left())
dry(null, TURF_WET_ICE)
dry(null, ALL, FALSE, decrease)
check()
last_process = world.time
/datum/component/wet_floor/proc/update_strength()
highest_strength = 0 //Not bitflag.
for(var/i in time_left_list)
highest_strength = max(highest_strength, text2num(i))
/datum/component/wet_floor/proc/is_wet()
. = 0
for(var/i in time_left_list)
. |= text2num(i)
/datum/component/wet_floor/PreTransfer()
var/turf/O = parent
O.cut_overlay(current_overlay)
//That turf is no longer slippery, we're out of here
//Slippery components don't transfer due to callbacks
qdel(O.GetComponent(/datum/component/slippery))
/datum/component/wet_floor/PostTransfer()
if(!isopenturf(parent))
return COMPONENT_INCOMPATIBLE
var/turf/T = parent
T.add_overlay(current_overlay)
//Make sure to add/update any slippery component on the new turf (update_flags calls LoadComponent)
update_flags()
//NB it's possible we get deleted after this, due to inherit
/datum/component/wet_floor/proc/add_wet(type, duration_minimum = 0, duration_add = 0, duration_maximum = MAXIMUM_WET_TIME, _permanent = FALSE)
var/static/list/allowed_types = list(TURF_WET_WATER, TURF_WET_LUBE, TURF_WET_ICE, TURF_WET_PERMAFROST)
if(duration_minimum <= 0 || !type)
return FALSE
if(type in allowed_types)
return _do_add_wet(type, duration_minimum, duration_add, duration_maximum)
else
. = NONE
for(var/i in allowed_types)
if(!(type & i))
continue
. |= _do_add_wet(i, duration_minimum, duration_add, duration_maximum)
if(_permanent)
permanent = TRUE
STOP_PROCESSING(SSwet_floors, src)
/datum/component/wet_floor/proc/_do_add_wet(type, duration_minimum, duration_add, duration_maximum)
var/time = 0
if(LAZYACCESS(time_left_list, "[type]"))
time = CLAMP(LAZYACCESS(time_left_list, "[type]") + duration_add, duration_minimum, duration_maximum)
else
time = min(duration_minimum, duration_maximum)
LAZYSET(time_left_list, "[type]", time)
check(TRUE)
return TRUE
/datum/component/wet_floor/proc/gc(on_init = FALSE)
if(!LAZYLEN(time_left_list))
if(on_init)
var/turf/T = parent
stack_trace("Warning: Wet floor component gc'd right after initialization! What a waste of time and CPU! Type = [T? T.type : "ERROR - NO PARENT"], Location = [istype(T)? AREACOORD(T) : "ERROR - INVALID PARENT"].")
qdel(src)
return TRUE
return FALSE
/datum/component/wet_floor/proc/check(force_update = FALSE)
var/changed = FALSE
for(var/i in time_left_list)
if(time_left_list[i] <= 0)
time_left_list -= i
changed = TRUE
if(changed || force_update)
update_strength()
update_overlay()
update_flags()
gc()
/datum/component/wet_floor
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
can_transfer = TRUE
var/highest_strength = TURF_DRY
var/lube_flags = NONE //why do we have this?
var/list/time_left_list //In deciseconds.
var/static/mutable_appearance/permafrost_overlay = mutable_appearance('icons/effects/water.dmi', "ice_floor")
var/static/mutable_appearance/ice_overlay = mutable_appearance('icons/turf/overlays.dmi', "snowfloor")
var/static/mutable_appearance/water_overlay = mutable_appearance('icons/effects/water.dmi', "wet_floor_static")
var/static/mutable_appearance/generic_turf_overlay = mutable_appearance('icons/effects/water.dmi', "wet_static")
var/current_overlay
var/permanent = FALSE
var/last_process = 0
/datum/component/wet_floor/InheritComponent(datum/newcomp, orig, argslist)
if(!newcomp) //We are getting passed the arguments of a would-be new component, but not a new component
add_wet(arglist(argslist))
else //We are being passed in a full blown component
var/datum/component/wet_floor/WF = newcomp //Lets make an assumption
if(WF.gc()) //See if it's even valid, still. Also does LAZYLEN and stuff for us.
CRASH("Wet floor component tried to inherit another, but the other was able to garbage collect while being inherited! What a waste of time!")
return
for(var/i in WF.time_left_list)
add_wet(text2num(i), WF.time_left_list[i])
/datum/component/wet_floor/Initialize(strength, duration_minimum, duration_add, duration_maximum, _permanent = FALSE)
if(!isopenturf(parent))
return COMPONENT_INCOMPATIBLE
add_wet(strength, duration_minimum, duration_add, duration_maximum)
permanent = _permanent
if(!permanent)
START_PROCESSING(SSwet_floors, src)
addtimer(CALLBACK(src, .proc/gc, TRUE), 1) //GC after initialization.
last_process = world.time
/datum/component/wet_floor/RegisterWithParent()
RegisterSignal(parent, COMSIG_TURF_IS_WET, .proc/is_wet)
RegisterSignal(parent, COMSIG_TURF_MAKE_DRY, .proc/dry)
/datum/component/wet_floor/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_TURF_IS_WET, COMSIG_TURF_MAKE_DRY))
/datum/component/wet_floor/Destroy()
STOP_PROCESSING(SSwet_floors, src)
var/turf/T = parent
qdel(T.GetComponent(/datum/component/slippery))
if(istype(T)) //If this is false there is so many things wrong with it.
T.cut_overlay(current_overlay)
else
stack_trace("Warning: Wet floor component wasn't on a turf when being destroyed! This is really bad!")
return ..()
/datum/component/wet_floor/proc/update_overlay()
var/intended
if(!istype(parent, /turf/open/floor))
intended = generic_turf_overlay
else
switch(highest_strength)
if(TURF_WET_PERMAFROST)
intended = permafrost_overlay
if(TURF_WET_ICE)
intended = ice_overlay
else
intended = water_overlay
if(current_overlay != intended)
var/turf/T = parent
T.cut_overlay(current_overlay)
T.add_overlay(intended)
current_overlay = intended
/datum/component/wet_floor/proc/AfterSlip(mob/living/L)
if(highest_strength == TURF_WET_LUBE)
L.confused = max(L.confused, 8)
/datum/component/wet_floor/proc/update_flags()
var/intensity
lube_flags = NONE
switch(highest_strength)
if(TURF_WET_WATER)
intensity = 60
lube_flags = NO_SLIP_WHEN_WALKING
if(TURF_WET_LUBE)
intensity = 80
lube_flags = SLIDE | GALOSHES_DONT_HELP
if(TURF_WET_ICE)
intensity = 120
lube_flags = SLIDE | GALOSHES_DONT_HELP
if(TURF_WET_PERMAFROST)
intensity = 120
lube_flags = SLIDE_ICE | GALOSHES_DONT_HELP
else
qdel(parent.GetComponent(/datum/component/slippery))
return
var/datum/component/slippery/S = parent.LoadComponent(/datum/component/slippery, NONE, CALLBACK(src, .proc/AfterSlip))
S.intensity = intensity
S.lube_flags = lube_flags
/datum/component/wet_floor/proc/dry(datum/source, strength = TURF_WET_WATER, immediate = FALSE, duration_decrease = INFINITY)
for(var/i in time_left_list)
if(text2num(i) <= strength)
time_left_list[i] = max(0, time_left_list[i] - duration_decrease)
if(immediate)
check()
/datum/component/wet_floor/proc/max_time_left()
. = 0
for(var/i in time_left_list)
. = max(., time_left_list[i])
/datum/component/wet_floor/process()
var/turf/open/T = parent
var/diff = world.time - last_process
var/decrease = 0
var/t = T.GetTemperature()
switch(t)
if(-INFINITY to T0C)
add_wet(TURF_WET_ICE, max_time_left()) //Water freezes into ice!
if(T0C to T0C + 100)
decrease = ((T.air.temperature - T0C) / SSwet_floors.temperature_coeff) * (diff / SSwet_floors.time_ratio)
if(T0C + 100 to INFINITY)
decrease = INFINITY
decrease = max(0, decrease)
if((is_wet() & TURF_WET_ICE) && t > T0C) //Ice melts into water!
for(var/obj/O in T.contents)
if(O.obj_flags & FROZEN)
O.make_unfrozen()
add_wet(TURF_WET_WATER, max_time_left())
dry(null, TURF_WET_ICE)
dry(null, ALL, FALSE, decrease)
check()
last_process = world.time
/datum/component/wet_floor/proc/update_strength()
highest_strength = 0 //Not bitflag.
for(var/i in time_left_list)
highest_strength = max(highest_strength, text2num(i))
/datum/component/wet_floor/proc/is_wet()
. = 0
for(var/i in time_left_list)
. |= text2num(i)
/datum/component/wet_floor/PreTransfer()
var/turf/O = parent
O.cut_overlay(current_overlay)
//That turf is no longer slippery, we're out of here
//Slippery components don't transfer due to callbacks
qdel(O.GetComponent(/datum/component/slippery))
/datum/component/wet_floor/PostTransfer()
if(!isopenturf(parent))
return COMPONENT_INCOMPATIBLE
var/turf/T = parent
T.add_overlay(current_overlay)
//Make sure to add/update any slippery component on the new turf (update_flags calls LoadComponent)
update_flags()
//NB it's possible we get deleted after this, due to inherit
/datum/component/wet_floor/proc/add_wet(type, duration_minimum = 0, duration_add = 0, duration_maximum = MAXIMUM_WET_TIME, _permanent = FALSE)
var/static/list/allowed_types = list(TURF_WET_WATER, TURF_WET_LUBE, TURF_WET_ICE, TURF_WET_PERMAFROST)
if(duration_minimum <= 0 || !type)
return FALSE
if(type in allowed_types)
return _do_add_wet(type, duration_minimum, duration_add, duration_maximum)
else
. = NONE
for(var/i in allowed_types)
if(!(type & i))
continue
. |= _do_add_wet(i, duration_minimum, duration_add, duration_maximum)
if(_permanent)
permanent = TRUE
STOP_PROCESSING(SSwet_floors, src)
/datum/component/wet_floor/proc/_do_add_wet(type, duration_minimum, duration_add, duration_maximum)
var/time = 0
if(LAZYACCESS(time_left_list, "[type]"))
time = CLAMP(LAZYACCESS(time_left_list, "[type]") + duration_add, duration_minimum, duration_maximum)
else
time = min(duration_minimum, duration_maximum)
LAZYSET(time_left_list, "[type]", time)
check(TRUE)
return TRUE
/datum/component/wet_floor/proc/gc(on_init = FALSE)
if(!LAZYLEN(time_left_list))
if(on_init)
var/turf/T = parent
stack_trace("Warning: Wet floor component gc'd right after initialization! What a waste of time and CPU! Type = [T? T.type : "ERROR - NO PARENT"], Location = [istype(T)? AREACOORD(T) : "ERROR - INVALID PARENT"].")
qdel(src)
return TRUE
return FALSE
/datum/component/wet_floor/proc/check(force_update = FALSE)
var/changed = FALSE
for(var/i in time_left_list)
if(time_left_list[i] <= 0)
time_left_list -= i
changed = TRUE
if(changed || force_update)
update_strength()
update_overlay()
update_flags()
gc()
+2 -4
View File
@@ -5,7 +5,6 @@
alert_type = /obj/screen/alert/status_effect/freon
var/icon/cube
var/can_melt = TRUE
var/datum/weakref/redirect_component
/obj/screen/alert/status_effect/freon
name = "Frozen Solid"
@@ -13,7 +12,7 @@
icon_state = "frozen"
/datum/status_effect/freon/on_apply()
redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/owner_resist))))
RegisterSignal(owner, COMSIG_LIVING_RESIST, .proc/owner_resist)
if(!owner.stat)
to_chat(owner, "<span class='userdanger'>You become frozen in a cube!</span>")
cube = icon('icons/effects/freeze.dmi', "ice_cube")
@@ -40,8 +39,7 @@
owner.cut_overlay(cube)
owner.adjust_bodytemperature(100)
owner.update_canmove()
qdel(redirect_component.resolve())
redirect_component = null
UnregisterSignal(owner, COMSIG_LIVING_RESIST)
/datum/status_effect/freon/watcher
duration = 8
@@ -376,10 +376,11 @@
typepath = /datum/round_event/ghost_role/operative
required_enemies = list(0,0,0,0,0,0,0,0,0,0)
weight = 0 //This is changed in nuclearbomb.dm
occurances_max = 1
occurances_max = 0 //Turned off. For now.
requirements = list(10,10,10,10,10,10,10,10,10,10) //SECURE THAT DISK
cost = 50
chaos_min = 0.5
chaos_min = 3
map_blacklist = list("LayeniaStation.dmm")
/datum/dynamic_ruleset/event/operative/get_weight()
var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control
+112 -112
View File
@@ -1,112 +1,112 @@
/datum/proximity_monitor
var/atom/host //the atom we are tracking
var/atom/hasprox_receiver //the atom that will receive HasProximity calls.
var/atom/last_host_loc
var/list/checkers //list of /obj/effect/abstract/proximity_checkers
var/current_range
var/ignore_if_not_on_turf //don't check turfs in range if the host's loc isn't a turf
var/datum/component/movement_tracker
/datum/proximity_monitor/New(atom/_host, range, _ignore_if_not_on_turf = TRUE)
checkers = list()
last_host_loc = _host.loc
ignore_if_not_on_turf = _ignore_if_not_on_turf
current_range = range
SetHost(_host)
/datum/proximity_monitor/proc/SetHost(atom/H,atom/R)
if(R)
hasprox_receiver = R
else if(hasprox_receiver == host) //Default case
hasprox_receiver = H
host = H
last_host_loc = host.loc
if(movement_tracker)
QDEL_NULL(movement_tracker)
movement_tracker = host.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/HandleMove)))
SetRange(current_range,TRUE)
/datum/proximity_monitor/Destroy()
host = null
last_host_loc = null
hasprox_receiver = null
QDEL_LIST(checkers)
QDEL_NULL(movement_tracker)
return ..()
/datum/proximity_monitor/proc/HandleMove()
var/atom/_host = host
var/atom/new_host_loc = _host.loc
if(last_host_loc != new_host_loc)
last_host_loc = new_host_loc //hopefully this won't cause GC issues with containers
var/curr_range = current_range
SetRange(curr_range, TRUE)
if(curr_range)
testing("HasProx: [host] -> [host]")
hasprox_receiver.HasProximity(host) //if we are processing, we're guaranteed to be a movable
/datum/proximity_monitor/proc/SetRange(range, force_rebuild = FALSE)
if(!force_rebuild && range == current_range)
return FALSE
. = TRUE
current_range = range
var/list/checkers_local = checkers
var/old_checkers_len = checkers_local.len
var/atom/_host = host
var/atom/loc_to_use = ignore_if_not_on_turf ? _host.loc : get_turf(_host)
if(!isturf(loc_to_use)) //only check the host's loc
if(range)
var/obj/effect/abstract/proximity_checker/pc
if(old_checkers_len)
pc = checkers_local[old_checkers_len]
--checkers_local.len
QDEL_LIST(checkers_local)
else
pc = new(loc_to_use, src)
checkers_local += pc //only check the host's loc
return
var/list/turfs = RANGE_TURFS(range, loc_to_use)
var/turfs_len = turfs.len
var/old_checkers_used = min(turfs_len, old_checkers_len)
//reuse what we can
for(var/I in 1 to old_checkers_len)
if(I <= old_checkers_used)
var/obj/effect/abstract/proximity_checker/pc = checkers_local[I]
pc.forceMove(turfs[I])
else
qdel(checkers_local[I]) //delete the leftovers
if(old_checkers_len < turfs_len)
//create what we lack
for(var/I in (old_checkers_used + 1) to turfs_len)
checkers_local += new /obj/effect/abstract/proximity_checker(turfs[I], src)
else
checkers_local.Cut(old_checkers_used + 1, old_checkers_len)
/obj/effect/abstract/proximity_checker
invisibility = INVISIBILITY_ABSTRACT
anchored = TRUE
var/datum/proximity_monitor/monitor
/obj/effect/abstract/proximity_checker/Initialize(mapload, datum/proximity_monitor/_monitor)
. = ..()
if(_monitor)
monitor = _monitor
else
stack_trace("proximity_checker created without host")
return INITIALIZE_HINT_QDEL
/obj/effect/abstract/proximity_checker/Destroy()
monitor = null
return ..()
/obj/effect/abstract/proximity_checker/Crossed(atom/movable/AM)
set waitfor = FALSE
monitor?.hasprox_receiver.HasProximity(AM)
/datum/proximity_monitor
var/atom/host //the atom we are tracking
var/atom/hasprox_receiver //the atom that will receive HasProximity calls.
var/atom/last_host_loc
var/list/checkers //list of /obj/effect/abstract/proximity_checkers
var/current_range
var/ignore_if_not_on_turf //don't check turfs in range if the host's loc isn't a turf
/datum/proximity_monitor/New(atom/_host, range, _ignore_if_not_on_turf = TRUE)
checkers = list()
last_host_loc = _host.loc
ignore_if_not_on_turf = _ignore_if_not_on_turf
current_range = range
SetHost(_host)
/datum/proximity_monitor/proc/SetHost(atom/H,atom/R)
if(H == host)
return
if(host)
UnregisterSignal(host, COMSIG_MOVABLE_MOVED)
if(R)
hasprox_receiver = R
else if(hasprox_receiver == host) //Default case
hasprox_receiver = H
host = H
RegisterSignal(host, COMSIG_MOVABLE_MOVED, .proc/HandleMove)
last_host_loc = host.loc
SetRange(current_range,TRUE)
/datum/proximity_monitor/Destroy()
host = null
last_host_loc = null
hasprox_receiver = null
QDEL_LIST(checkers)
return ..()
/datum/proximity_monitor/proc/HandleMove()
var/atom/_host = host
var/atom/new_host_loc = _host.loc
if(last_host_loc != new_host_loc)
last_host_loc = new_host_loc //hopefully this won't cause GC issues with containers
var/curr_range = current_range
SetRange(curr_range, TRUE)
if(curr_range)
testing("HasProx: [host] -> [host]")
hasprox_receiver.HasProximity(host) //if we are processing, we're guaranteed to be a movable
/datum/proximity_monitor/proc/SetRange(range, force_rebuild = FALSE)
if(!force_rebuild && range == current_range)
return FALSE
. = TRUE
current_range = range
var/list/checkers_local = checkers
var/old_checkers_len = checkers_local.len
var/atom/_host = host
var/atom/loc_to_use = ignore_if_not_on_turf ? _host.loc : get_turf(_host)
if(!isturf(loc_to_use)) //only check the host's loc
if(range)
var/obj/effect/abstract/proximity_checker/pc
if(old_checkers_len)
pc = checkers_local[old_checkers_len]
--checkers_local.len
QDEL_LIST(checkers_local)
else
pc = new(loc_to_use, src)
checkers_local += pc //only check the host's loc
return
var/list/turfs = RANGE_TURFS(range, loc_to_use)
var/turfs_len = turfs.len
var/old_checkers_used = min(turfs_len, old_checkers_len)
//reuse what we can
for(var/I in 1 to old_checkers_len)
if(I <= old_checkers_used)
var/obj/effect/abstract/proximity_checker/pc = checkers_local[I]
pc.forceMove(turfs[I])
else
qdel(checkers_local[I]) //delete the leftovers
if(old_checkers_len < turfs_len)
//create what we lack
for(var/I in (old_checkers_used + 1) to turfs_len)
checkers_local += new /obj/effect/abstract/proximity_checker(turfs[I], src)
else
checkers_local.Cut(old_checkers_used + 1, old_checkers_len)
/obj/effect/abstract/proximity_checker
invisibility = INVISIBILITY_ABSTRACT
anchored = TRUE
var/datum/proximity_monitor/monitor
/obj/effect/abstract/proximity_checker/Initialize(mapload, datum/proximity_monitor/_monitor)
. = ..()
if(_monitor)
monitor = _monitor
else
stack_trace("proximity_checker created without host")
return INITIALIZE_HINT_QDEL
/obj/effect/abstract/proximity_checker/Destroy()
monitor = null
return ..()
/obj/effect/abstract/proximity_checker/Crossed(atom/movable/AM)
set waitfor = FALSE
monitor?.hasprox_receiver.HasProximity(AM)
+10 -12
View File
@@ -20,8 +20,8 @@
var/ghetto = FALSE
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
var/datum/component/mobhook
var/datum/radial_menu/persistent/wiring_gui_menu
var/mob/listeningTo
/obj/item/twohanded/rcl/attackby(obj/item/W, mob/user)
if(istype(W, /obj/item/stack/cable_coil))
@@ -86,7 +86,7 @@
/obj/item/twohanded/rcl/Destroy()
QDEL_NULL(loaded)
last = null
QDEL_NULL(mobhook)
listeningTo = null
QDEL_NULL(wiring_gui_menu)
return ..()
@@ -141,9 +141,8 @@
/obj/item/twohanded/rcl/dropped(mob/wearer)
..()
if(mobhook)
active = FALSE
QDEL_NULL(mobhook)
UnregisterSignal(wearer, COMSIG_MOVABLE_MOVED)
listeningTo = null
last = null
/obj/item/twohanded/rcl/attack_self(mob/user)
@@ -158,13 +157,12 @@
break
obj/item/twohanded/rcl/proc/getMobhook(mob/to_hook)
if(to_hook)
if(mobhook && mobhook.parent != to_hook)
QDEL_NULL(mobhook)
if (!mobhook)
mobhook = to_hook.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/trigger)))
else
QDEL_NULL(mobhook)
if(listeningTo == to_hook)
return
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
RegisterSignal(to_hook, COMSIG_MOVABLE_MOVED, .proc/trigger)
listeningTo = to_hook
/obj/item/twohanded/rcl/proc/trigger(mob/user)
if(active)
+12 -18
View File
@@ -39,7 +39,6 @@
/obj/item/defibrillator/loaded/Initialize() //starts with hicap
. = ..()
paddles = make_paddles()
cell = new(src)
update_icon()
return
@@ -204,8 +203,8 @@
var/M = get(paddles, /mob)
remove_paddles(M)
QDEL_NULL(paddles)
. = ..()
update_icon()
QDEL_NULL(cell)
return ..()
/obj/item/defibrillator/proc/deductcharge(chrgdeductamt)
if(cell)
@@ -246,7 +245,6 @@
/obj/item/defibrillator/compact/loaded/Initialize()
. = ..()
paddles = make_paddles()
cell = new(src)
update_icon()
@@ -258,7 +256,6 @@
/obj/item/defibrillator/compact/combat/loaded/Initialize()
. = ..()
paddles = make_paddles()
cell = new /obj/item/stock_parts/cell/infinite(src)
update_icon()
@@ -293,31 +290,28 @@
var/grab_ghost = FALSE
var/tlimit = DEFIB_TIME_LIMIT * 10
var/datum/component/mobhook
var/mob/listeningTo
/obj/item/twohanded/shockpaddles/equipped(mob/user, slot)
. = ..()
if(req_defib)
if (mobhook && mobhook.parent != user)
QDEL_NULL(mobhook)
if (!mobhook)
mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/check_range)))
if(!req_defib)
return
RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/check_range)
/obj/item/twohanded/shockpaddles/Moved()
. = ..()
check_range()
/obj/item/twohanded/shockpaddles/proc/check_range()
if(!req_defib)
if(!req_defib || !defib)
return
if(!in_range(src,defib))
var/mob/living/L = loc
if(istype(L))
to_chat(L, "<span class='warning'>[defib]'s paddles overextend and come out of your hands!</span>")
L.temporarilyRemoveItemFromInventory(src,TRUE)
else
visible_message("<span class='notice'>[src] snap back into [defib].</span>")
snap_back()
snap_back()
/obj/item/twohanded/shockpaddles/proc/recharge(var/time)
if(req_defib || !time)
@@ -358,14 +352,14 @@
/obj/item/twohanded/shockpaddles/dropped(mob/user)
if(!req_defib)
return ..()
if (mobhook)
QDEL_NULL(mobhook)
if(user)
UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
var/obj/item/twohanded/offhand/O = user.get_inactive_held_item()
if(istype(O))
O.unwield()
to_chat(user, "<span class='notice'>The paddles snap back into the main unit.</span>")
snap_back()
if(user != loc)
to_chat(user, "<span class='notice'>The paddles snap back into the main unit.</span>")
snap_back()
return unwield(user)
/obj/item/twohanded/shockpaddles/proc/snap_back()
@@ -205,21 +205,25 @@
obj_flags |= EMAGGED
/obj/item/geiger_counter/cyborg
var/datum/component/mobhook
var/mob/listeningTo
/obj/item/geiger_counter/cyborg/equipped(mob/user)
. = ..()
if (mobhook && mobhook.parent != user)
QDEL_NULL(mobhook)
if (!mobhook)
mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_ATOM_RAD_ACT = CALLBACK(src, .proc/redirect_rad_act)))
if(listeningTo == user)
return
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_ATOM_RAD_ACT)
RegisterSignal(user, COMSIG_ATOM_RAD_ACT, .proc/redirect_rad_act)
listeningTo = user
/obj/item/geiger_counter/cyborg/proc/redirect_rad_act(datum/source, amount)
rad_act(amount)
/obj/item/geiger_counter/cyborg/dropped()
. = ..()
QDEL_NULL(mobhook)
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_ATOM_RAD_ACT)
listeningTo = null
#undef RAD_LEVEL_NORMAL
#undef RAD_LEVEL_MODERATE
@@ -48,4 +48,10 @@
icon_state = "clustaur"
item_state = "clustaur"
deliveryamt = 5
spawner_type = /obj/item/reagent_containers/glass/beaker/waterbottle/wataur
spawner_type = /obj/item/reagent_containers/glass/beaker/waterbottle/wataur
/obj/item/grenade/spawnergrenade/mimics
desc = "Months after their first arrival, compression tests were already successful and thus Kinaris created the first mimic bioweapon, a simple payload to quickly release a cluster of them."
name = "mimic delivery grenade"
spawner_type = /mob/living/simple_animal/hostile/hs13mimic
deliveryamt = 10
+1 -1
View File
@@ -29,7 +29,7 @@
. = ..()
START_PROCESSING(SSprocessing, src)
GLOB.poi_list += src
AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_POST_THROW = CALLBACK(src, .proc/move_gracefully)))
RegisterSignal(src, COMSIG_MOVABLE_POST_THROW, .proc/move_gracefully)
/obj/item/his_grace/Destroy()
STOP_PROCESSING(SSprocessing, src)
@@ -223,6 +223,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
new/datum/stack_recipe("coffin", /obj/structure/closet/crate/coffin, 5, time = 15, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("book case", /obj/structure/bookcase, 4, time = 15, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("drying rack", /obj/machinery/smartfridge/drying_rack, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("sauna oven", /obj/structure/sauna_oven, 30, time = 15, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("dog bed", /obj/structure/bed/dogbed, 10, time = 10, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("dresser", /obj/structure/dresser, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("ore box", /obj/structure/ore_box, 4, time = 50, one_per_turf = TRUE, on_floor = TRUE),\
@@ -900,4 +901,4 @@ GLOBAL_LIST_INIT(plaswood_recipes, list ( \
return ..()
/obj/item/stack/sheet/mineral/plaswood/fifty
amount = 50
amount = 50
+441 -439
View File
@@ -1,439 +1,441 @@
/*
* These absorb the functionality of the plant bag, ore satchel, etc
* They use the use_to_pickup, quick_gather, and quick_empty functions
* that were already defined in weapon/storage, but which had been
* re-implemented in other classes.
*
* Contains:
* Trash Bag
* Mining Satchel
* Plant Bag
* Sheet Snatcher
* Book Bag
* Biowaste Bag
*
* -Sayu
*/
// Generic non-item
/obj/item/storage/bag
slot_flags = ITEM_SLOT_BELT
/obj/item/storage/bag/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.allow_quick_gather = TRUE
STR.allow_quick_empty = TRUE
STR.display_numerical_stacking = TRUE
STR.click_gather = TRUE
// -----------------------------
// Trash bag
// -----------------------------
/obj/item/storage/bag/trash
name = "trash bag"
desc = "It's the heavy-duty black polymer kind. Time to take out the trash!"
icon = 'icons/obj/janitor.dmi'
icon_state = "trashbag"
item_state = "trashbag"
lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
w_class = WEIGHT_CLASS_BULKY
var/insertable = TRUE
/obj/item/storage/bag/trash/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_SMALL
STR.max_combined_w_class = 30
STR.max_items = 30
STR.cant_hold = typecacheof(list(/obj/item/disk/nuclear))
/obj/item/storage/bag/trash/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] puts [src] over [user.p_their()] head and starts chomping at the insides! Disgusting!</span>")
playsound(loc, 'sound/items/eatfood.ogg', 50, 1, -1)
return (TOXLOSS)
/obj/item/storage/bag/trash/update_icon()
if(contents.len == 0)
icon_state = "[initial(icon_state)]"
else if(contents.len < 12)
icon_state = "[initial(icon_state)]1"
else if(contents.len < 21)
icon_state = "[initial(icon_state)]2"
else icon_state = "[initial(icon_state)]3"
/obj/item/storage/bag/trash/cyborg
insertable = FALSE
/obj/item/storage/bag/trash/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J)
if(insertable)
J.put_in_cart(src, user)
J.mybag=src
J.update_icon()
else
to_chat(user, "<span class='warning'>You are unable to fit your [name] into the [J.name].</span>")
return
/obj/item/storage/bag/trash/bluespace
name = "trash bag of holding"
desc = "The latest and greatest in custodial convenience, a trashbag that is capable of holding vast quantities of garbage."
icon_state = "bluetrashbag"
item_flags = NO_MAT_REDEMPTION
/obj/item/storage/bag/trash/bluespace/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 60
STR.max_items = 60
/obj/item/storage/bag/trash/bluespace/cyborg
insertable = FALSE
// -----------------------------
// Mining Satchel
// -----------------------------
/obj/item/storage/bag/ore
name = "mining satchel"
desc = "This little bugger can be used to store and transport ores."
icon = 'icons/obj/mining.dmi'
icon_state = "satchel"
slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_POCKET
w_class = WEIGHT_CLASS_NORMAL
component_type = /datum/component/storage/concrete/stack
var/spam_protection = FALSE //If this is TRUE, the holder won't receive any messages when they fail to pick up ore through crossing it
var/datum/component/mobhook
/obj/item/storage/bag/ore/ComponentInitialize()
. = ..()
var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
STR.allow_quick_empty = TRUE
STR.can_hold = typecacheof(list(/obj/item/stack/ore))
STR.max_w_class = WEIGHT_CLASS_HUGE
STR.max_combined_stack_amount = 50
/obj/item/storage/bag/ore/equipped(mob/user)
. = ..()
if (mobhook && mobhook.parent != user)
QDEL_NULL(mobhook)
if (!mobhook)
mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/Pickup_ores)))
/obj/item/storage/bag/ore/dropped()
. = ..()
if (mobhook)
QDEL_NULL(mobhook)
/obj/item/storage/bag/ore/proc/Pickup_ores(mob/living/user)
var/show_message = FALSE
var/obj/structure/ore_box/box
var/turf/tile = user.loc
if (!isturf(tile))
return
if (istype(user.pulling, /obj/structure/ore_box))
box = user.pulling
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
if(STR)
for(var/A in tile)
if (!is_type_in_typecache(A, STR.can_hold))
continue
if (box)
user.transferItemToLoc(A, box)
show_message = TRUE
else if(SEND_SIGNAL(src, COMSIG_TRY_STORAGE_INSERT, A, user, TRUE))
show_message = TRUE
else
if(!spam_protection)
to_chat(user, "<span class='warning'>Your [name] is full and can't hold any more!</span>")
spam_protection = TRUE
continue
if(show_message)
playsound(user, "rustle", 50, TRUE)
if (box)
user.visible_message("<span class='notice'>[user] offloads the ores beneath [user.p_them()] into [box].</span>", \
"<span class='notice'>You offload the ores beneath you into your [box].</span>")
else
user.visible_message("<span class='notice'>[user] scoops up the ores beneath [user.p_them()].</span>", \
"<span class='notice'>You scoop up the ores beneath you with your [name].</span>")
spam_protection = FALSE
/obj/item/storage/bag/ore/cyborg
name = "cyborg mining satchel"
/obj/item/storage/bag/ore/cyborg/ComponentInitialize()
. = ..()
var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
STR.allow_quick_empty = TRUE
STR.can_hold = typecacheof(list(/obj/item/stack/ore))
STR.max_w_class = WEIGHT_CLASS_HUGE
STR.max_combined_stack_amount = 150
/obj/item/storage/bag/ore/large
name = "large mining satchel"
desc = "This bag can hold three times the ore in many small pockets. Shockingly foldable and compact for its volume."
/obj/item/storage/bag/ore/large/ComponentInitialize()
. = ..()
var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
STR.allow_quick_empty = TRUE
STR.can_hold = typecacheof(list(/obj/item/stack/ore))
STR.max_w_class = WEIGHT_CLASS_HUGE
STR.max_combined_stack_amount = 150
/obj/item/storage/bag/ore/holding //miners, your messiah has arrived
name = "mining satchel of holding"
desc = "A revolution in convenience, this satchel allows for huge amounts of ore storage. It's been outfitted with anti-malfunction safety measures."
icon_state = "satchel_bspace"
/obj/item/storage/bag/ore/holding/ComponentInitialize()
. = ..()
var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
STR.max_items = INFINITY
STR.max_combined_w_class = INFINITY
STR.max_combined_stack_amount = INFINITY
// -----------------------------
// Plant bag
// -----------------------------
/obj/item/storage/bag/plants
name = "plant bag"
icon = 'icons/obj/hydroponics/equipment.dmi'
icon_state = "plantbag"
w_class = WEIGHT_CLASS_TINY
resistance_flags = FLAMMABLE
/obj/item/storage/bag/plants/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.max_combined_w_class = 100
STR.max_items = 100
STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/grown, /obj/item/seeds, /obj/item/grown, /obj/item/reagent_containers/honeycomb))
////////
/obj/item/storage/bag/plants/portaseeder
name = "portable seed extractor"
desc = "For the enterprising botanist on the go. Less efficient than the stationary model, it creates one seed per plant."
icon_state = "portaseeder"
/obj/item/storage/bag/plants/portaseeder/verb/dissolve_contents()
set name = "Activate Seed Extraction"
set category = "Object"
set desc = "Activate to convert your plants into plantable seeds."
if(usr.stat || !usr.canmove || usr.restrained())
return
for(var/obj/item/O in contents)
seedify(O, 1)
// -----------------------------
// Sheet Snatcher
// -----------------------------
// Because it stacks stacks, this doesn't operate normally.
// However, making it a storage/bag allows us to reuse existing code in some places. -Sayu
/obj/item/storage/bag/sheetsnatcher
name = "sheet snatcher"
desc = "A patented Kinaris storage system designed for any kind of mineral sheet."
icon = 'icons/obj/mining.dmi'
icon_state = "sheetsnatcher"
var/capacity = 300; //the number of sheets it can carry.
w_class = WEIGHT_CLASS_NORMAL
component_type = /datum/component/storage/concrete/stack
/obj/item/storage/bag/sheetsnatcher/ComponentInitialize()
. = ..()
var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
STR.allow_quick_empty = TRUE
STR.can_hold = typecacheof(list(/obj/item/stack/sheet))
STR.cant_hold = typecacheof(list(/obj/item/stack/sheet/mineral/sandstone, /obj/item/stack/sheet/mineral/wood))
STR.max_combined_stack_amount = 300
// -----------------------------
// Sheet Snatcher (Cyborg)
// -----------------------------
/obj/item/storage/bag/sheetsnatcher/borg
name = "sheet snatcher 9000"
desc = ""
capacity = 500//Borgs get more because >specialization
/obj/item/storage/bag/sheetsnatcher/borg/ComponentInitialize()
. = ..()
var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
STR.max_combined_stack_amount = 500
// -----------------------------
// Book bag
// -----------------------------
/obj/item/storage/bag/books
name = "book bag"
desc = "A bag for books."
icon = 'icons/obj/library.dmi'
icon_state = "bookbag"
w_class = WEIGHT_CLASS_BULKY //Bigger than a book because physics
resistance_flags = FLAMMABLE
/obj/item/storage/bag/books/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.max_combined_w_class = 21
STR.max_items = 7
STR.display_numerical_stacking = FALSE
STR.can_hold = typecacheof(list(/obj/item/book, /obj/item/storage/book, /obj/item/spellbook))
/*
* Trays - Agouri
*/
/obj/item/storage/bag/tray
name = "tray"
icon = 'icons/obj/food/containers.dmi'
icon_state = "tray"
desc = "A metal tray to lay food on."
force = 5
throwforce = 10
throw_speed = 3
throw_range = 5
w_class = WEIGHT_CLASS_BULKY
flags_1 = CONDUCT_1
materials = list(MAT_METAL=3000)
/obj/item/storage/bag/tray/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 15 //I want my sushi god damn it
STR.insert_preposition = "on"
STR.can_hold = typecacheof(list(
/obj/item/reagent_containers/food,
/obj/item/kitchen,
/obj/item/storage/box/donkpockets))
/obj/item/storage/bag/tray/pre_attack(atom/A, mob/living/user, params)
if(istype(A, /obj/structure/table) && user.a_intent == INTENT_HELP) //I want my tray god damn it
if(user.transferItemToLoc(src, get_turf(A)))
var/list/click_params = params2list(params)
if(!click_params || !click_params["icon-x"] || !click_params["icon-y"])
return
pixel_x = CLAMP(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2)
pixel_y = CLAMP(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)
return
..()
/obj/item/storage/bag/tray/attack(mob/living/M, mob/living/user)
. = ..()
// Drop all the things. All of them.
var/list/obj/item/oldContents = contents.Copy()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.quick_empty()
// Make each item scatter a bit
for(var/obj/item/I in oldContents)
spawn()
for(var/i = 1, i <= rand(1,2), i++)
if(I)
step(I, pick(NORTH,SOUTH,EAST,WEST))
sleep(rand(2,4))
if(prob(50))
playsound(M, 'sound/items/trayhit1.ogg', 50, 1)
else
playsound(M, 'sound/items/trayhit2.ogg', 50, 1)
if(ishuman(M) || ismonkey(M))
if(prob(10))
M.Knockdown(40)
update_icon()
/obj/item/storage/bag/tray/update_icon()
cut_overlays()
for(var/obj/item/I in contents)
var/mutable_appearance/MA = new (I) //I want my icons god damn it
MA.pixel_x = rand(-6, 6)
MA.pixel_y = rand(-6, 6)
add_overlay(MA)
/obj/item/storage/bag/tray/Entered()
. = ..()
update_icon()
/obj/item/storage/bag/tray/Exited()
. = ..()
update_icon()
/*
* Chemistry bag
*/
/obj/item/storage/bag/chemistry
name = "chemistry bag"
icon = 'icons/obj/chemical.dmi'
icon_state = "bag"
desc = "A bag for storing pills, patches, and bottles."
w_class = WEIGHT_CLASS_TINY
resistance_flags = FLAMMABLE
/obj/item/storage/bag/chemistry/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 200
STR.max_items = 50
STR.insert_preposition = "in"
STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/syringe/dart, /obj/item/reagent_containers/chem_pack))
/*
* Biowaste bag (mostly for xenobiologists)
*/
/obj/item/storage/bag/bio
name = "bio bag"
icon = 'icons/obj/chemical.dmi'
icon_state = "biobag"
desc = "A bag for the safe transportation and disposal of biowaste and other biological materials."
w_class = WEIGHT_CLASS_TINY
resistance_flags = FLAMMABLE
/obj/item/storage/bag/bio/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 200
STR.max_items = 25
STR.insert_preposition = "in"
STR.can_hold = typecacheof(list(/obj/item/slime_extract, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/blood, /obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/food/snacks/deadmouse, /obj/item/reagent_containers/food/snacks/monkeycube))
/obj/item/storage/bag/bio/holding
name = "bio bag of holding"
icon = 'icons/obj/chemical.dmi'
icon_state = "bspace_biobag"
desc = "A bag for the safe transportation and disposal of biowaste and other biological materials."
/obj/item/storage/bag/bio/holding/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = INFINITY
STR.max_items = 100
/*
* Construction bag (for engineering, holds stock parts and electronics)
*/
/obj/item/storage/bag/construction
name = "construction bag"
icon = 'icons/obj/tools.dmi'
icon_state = "construction_bag"
desc = "A bag for storing small construction components."
w_class = WEIGHT_CLASS_TINY
resistance_flags = FLAMMABLE
/obj/item/storage/bag/construction/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 100
STR.max_items = 50
STR.max_w_class = WEIGHT_CLASS_SMALL
STR.insert_preposition = "in"
STR.can_hold = typecacheof(list(/obj/item/stack/ore/bluespace_crystal, /obj/item/assembly, /obj/item/stock_parts, /obj/item/reagent_containers/glass/beaker, /obj/item/stack/cable_coil, /obj/item/circuitboard, /obj/item/electronics))
/*
* These absorb the functionality of the plant bag, ore satchel, etc
* They use the use_to_pickup, quick_gather, and quick_empty functions
* that were already defined in weapon/storage, but which had been
* re-implemented in other classes.
*
* Contains:
* Trash Bag
* Mining Satchel
* Plant Bag
* Sheet Snatcher
* Book Bag
* Biowaste Bag
*
* -Sayu
*/
// Generic non-item
/obj/item/storage/bag
slot_flags = ITEM_SLOT_BELT
/obj/item/storage/bag/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.allow_quick_gather = TRUE
STR.allow_quick_empty = TRUE
STR.display_numerical_stacking = TRUE
STR.click_gather = TRUE
// -----------------------------
// Trash bag
// -----------------------------
/obj/item/storage/bag/trash
name = "trash bag"
desc = "It's the heavy-duty black polymer kind. Time to take out the trash!"
icon = 'icons/obj/janitor.dmi'
icon_state = "trashbag"
item_state = "trashbag"
lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
w_class = WEIGHT_CLASS_BULKY
var/insertable = TRUE
/obj/item/storage/bag/trash/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_SMALL
STR.max_combined_w_class = 30
STR.max_items = 30
STR.cant_hold = typecacheof(list(/obj/item/disk/nuclear))
/obj/item/storage/bag/trash/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] puts [src] over [user.p_their()] head and starts chomping at the insides! Disgusting!</span>")
playsound(loc, 'sound/items/eatfood.ogg', 50, 1, -1)
return (TOXLOSS)
/obj/item/storage/bag/trash/update_icon()
if(contents.len == 0)
icon_state = "[initial(icon_state)]"
else if(contents.len < 12)
icon_state = "[initial(icon_state)]1"
else if(contents.len < 21)
icon_state = "[initial(icon_state)]2"
else icon_state = "[initial(icon_state)]3"
/obj/item/storage/bag/trash/cyborg
insertable = FALSE
/obj/item/storage/bag/trash/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J)
if(insertable)
J.put_in_cart(src, user)
J.mybag=src
J.update_icon()
else
to_chat(user, "<span class='warning'>You are unable to fit your [name] into the [J.name].</span>")
return
/obj/item/storage/bag/trash/bluespace
name = "trash bag of holding"
desc = "The latest and greatest in custodial convenience, a trashbag that is capable of holding vast quantities of garbage."
icon_state = "bluetrashbag"
item_flags = NO_MAT_REDEMPTION
/obj/item/storage/bag/trash/bluespace/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 60
STR.max_items = 60
/obj/item/storage/bag/trash/bluespace/cyborg
insertable = FALSE
// -----------------------------
// Mining Satchel
// -----------------------------
/obj/item/storage/bag/ore
name = "mining satchel"
desc = "This little bugger can be used to store and transport ores."
icon = 'icons/obj/mining.dmi'
icon_state = "satchel"
slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_POCKET
w_class = WEIGHT_CLASS_NORMAL
component_type = /datum/component/storage/concrete/stack
var/spam_protection = FALSE //If this is TRUE, the holder won't receive any messages when they fail to pick up ore through crossing it
var/mob/listeningTo
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
/obj/item/storage/bag/ore/ComponentInitialize()
. = ..()
var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
STR.allow_quick_empty = TRUE
STR.can_hold = typecacheof(list(/obj/item/stack/ore))
STR.max_w_class = WEIGHT_CLASS_HUGE
STR.max_combined_stack_amount = 50
/obj/item/storage/bag/ore/equipped(mob/user)
. = ..()
if(listeningTo == user)
return
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/Pickup_ores)
listeningTo = user
/obj/item/storage/bag/ore/dropped()
. = ..()
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
listeningTo = null
/obj/item/storage/bag/ore/proc/Pickup_ores(mob/living/user)
var/show_message = FALSE
var/obj/structure/ore_box/box
var/turf/tile = user.loc
if (!isturf(tile))
return
if (istype(user.pulling, /obj/structure/ore_box))
box = user.pulling
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
if(STR)
for(var/A in tile)
if (!is_type_in_typecache(A, STR.can_hold))
continue
if (box)
user.transferItemToLoc(A, box)
show_message = TRUE
else if(SEND_SIGNAL(src, COMSIG_TRY_STORAGE_INSERT, A, user, TRUE))
show_message = TRUE
else
if(!spam_protection)
to_chat(user, "<span class='warning'>Your [name] is full and can't hold any more!</span>")
spam_protection = TRUE
continue
if(show_message)
playsound(user, "rustle", 50, TRUE)
if (box)
user.visible_message("<span class='notice'>[user] offloads the ores beneath [user.p_them()] into [box].</span>", \
"<span class='notice'>You offload the ores beneath you into your [box].</span>")
else
user.visible_message("<span class='notice'>[user] scoops up the ores beneath [user.p_them()].</span>", \
"<span class='notice'>You scoop up the ores beneath you with your [name].</span>")
spam_protection = FALSE
/obj/item/storage/bag/ore/cyborg
name = "cyborg mining satchel"
/obj/item/storage/bag/ore/cyborg/ComponentInitialize()
. = ..()
var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
STR.allow_quick_empty = TRUE
STR.can_hold = typecacheof(list(/obj/item/stack/ore))
STR.max_w_class = WEIGHT_CLASS_HUGE
STR.max_combined_stack_amount = 150
/obj/item/storage/bag/ore/large
name = "large mining satchel"
desc = "This bag can hold three times the ore in many small pockets. Shockingly foldable and compact for its volume."
/obj/item/storage/bag/ore/large/ComponentInitialize()
. = ..()
var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
STR.allow_quick_empty = TRUE
STR.can_hold = typecacheof(list(/obj/item/stack/ore))
STR.max_w_class = WEIGHT_CLASS_HUGE
STR.max_combined_stack_amount = 150
/obj/item/storage/bag/ore/holding //miners, your messiah has arrived
name = "mining satchel of holding"
desc = "A revolution in convenience, this satchel allows for huge amounts of ore storage. It's been outfitted with anti-malfunction safety measures."
icon_state = "satchel_bspace"
/obj/item/storage/bag/ore/holding/ComponentInitialize()
. = ..()
var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
STR.max_items = INFINITY
STR.max_combined_w_class = INFINITY
STR.max_combined_stack_amount = INFINITY
// -----------------------------
// Plant bag
// -----------------------------
/obj/item/storage/bag/plants
name = "plant bag"
icon = 'icons/obj/hydroponics/equipment.dmi'
icon_state = "plantbag"
w_class = WEIGHT_CLASS_TINY
resistance_flags = FLAMMABLE
/obj/item/storage/bag/plants/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.max_combined_w_class = 100
STR.max_items = 100
STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/grown, /obj/item/seeds, /obj/item/grown, /obj/item/reagent_containers/honeycomb))
////////
/obj/item/storage/bag/plants/portaseeder
name = "portable seed extractor"
desc = "For the enterprising botanist on the go. Less efficient than the stationary model, it creates one seed per plant."
icon_state = "portaseeder"
/obj/item/storage/bag/plants/portaseeder/verb/dissolve_contents()
set name = "Activate Seed Extraction"
set category = "Object"
set desc = "Activate to convert your plants into plantable seeds."
if(usr.stat || !usr.canmove || usr.restrained())
return
for(var/obj/item/O in contents)
seedify(O, 1)
// -----------------------------
// Sheet Snatcher
// -----------------------------
// Because it stacks stacks, this doesn't operate normally.
// However, making it a storage/bag allows us to reuse existing code in some places. -Sayu
/obj/item/storage/bag/sheetsnatcher
name = "sheet snatcher"
desc = "A patented Kinaris storage system designed for any kind of mineral sheet."
icon = 'icons/obj/mining.dmi'
icon_state = "sheetsnatcher"
var/capacity = 300; //the number of sheets it can carry.
w_class = WEIGHT_CLASS_NORMAL
component_type = /datum/component/storage/concrete/stack
/obj/item/storage/bag/sheetsnatcher/ComponentInitialize()
. = ..()
var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
STR.allow_quick_empty = TRUE
STR.can_hold = typecacheof(list(/obj/item/stack/sheet))
STR.cant_hold = typecacheof(list(/obj/item/stack/sheet/mineral/sandstone, /obj/item/stack/sheet/mineral/wood))
STR.max_combined_stack_amount = 300
// -----------------------------
// Sheet Snatcher (Cyborg)
// -----------------------------
/obj/item/storage/bag/sheetsnatcher/borg
name = "sheet snatcher 9000"
desc = ""
capacity = 500//Borgs get more because >specialization
/obj/item/storage/bag/sheetsnatcher/borg/ComponentInitialize()
. = ..()
var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
STR.max_combined_stack_amount = 500
// -----------------------------
// Book bag
// -----------------------------
/obj/item/storage/bag/books
name = "book bag"
desc = "A bag for books."
icon = 'icons/obj/library.dmi'
icon_state = "bookbag"
w_class = WEIGHT_CLASS_BULKY //Bigger than a book because physics
resistance_flags = FLAMMABLE
/obj/item/storage/bag/books/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.max_combined_w_class = 21
STR.max_items = 7
STR.display_numerical_stacking = FALSE
STR.can_hold = typecacheof(list(/obj/item/book, /obj/item/storage/book, /obj/item/spellbook))
/*
* Trays - Agouri
*/
/obj/item/storage/bag/tray
name = "serving tray"
icon = 'icons/obj/food/containers.dmi'
icon_state = "tray"
desc = "A metal tray to lay food on."
force = 5
throwforce = 10
throw_speed = 3
throw_range = 5
w_class = WEIGHT_CLASS_BULKY
flags_1 = CONDUCT_1
materials = list(MAT_METAL=3000)
/obj/item/storage/bag/tray/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL //Allows stuff such as Bowls, and normal sized foods, to fit.
STR.can_hold = typecacheof(list(
/obj/item/reagent_containers/food,
/obj/item/reagent_containers/glass,
/obj/item/clothing/mask/cigarette,
/obj/item/storage/fancy,
/obj/item/storage/box/matches,
/obj/item/trash,
/obj/item/lighter,
/obj/item/rollingpaper,
/obj/item/kitchen,
/obj/item/organ,
)) //Should cover: Bottles, Beakers, Bowls, Booze, Glasses, Food, Food Containers, Food Trash, Organs, Tobacco Products, Lighters, and Kitchen Tools.
STR.insert_preposition = "on"
STR.max_items = 10
/obj/item/storage/bag/tray/attack(mob/living/M, mob/living/user)
. = ..()
// Drop all the things. All of them.
var/list/obj/item/oldContents = contents.Copy()
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_QUICK_EMPTY)
// Make each item scatter a bit
for(var/obj/item/I in oldContents)
INVOKE_ASYNC(src, .proc/do_scatter, I)
if(prob(50))
playsound(M, 'sound/items/trayhit1.ogg', 50, TRUE)
else
playsound(M, 'sound/items/trayhit2.ogg', 50, TRUE)
if(ishuman(M))
if(prob(10))
M.Knockdown(40)
update_icon()
/obj/item/storage/bag/tray/proc/do_scatter(obj/item/I)
for(var/i in 1 to rand(1,2))
if(I)
step(I, pick(NORTH,SOUTH,EAST,WEST))
sleep(rand(2,4))
/obj/item/storage/bag/tray/update_overlays()
. = ..()
for(var/obj/item/I in contents)
var/mutable_appearance/I_copy = new(I)
I_copy.plane = FLOAT_PLANE
I_copy.layer = FLOAT_LAYER
. += I_copy
/obj/item/storage/bag/tray/Entered()
. = ..()
update_icon()
/obj/item/storage/bag/tray/Exited()
. = ..()
update_icon()
/*
* Chemistry bag
*/
/obj/item/storage/bag/chemistry
name = "chemistry bag"
icon = 'icons/obj/chemical.dmi'
icon_state = "bag"
desc = "A bag for storing pills, patches, and bottles."
w_class = WEIGHT_CLASS_TINY
resistance_flags = FLAMMABLE
/obj/item/storage/bag/chemistry/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 200
STR.max_items = 50
STR.insert_preposition = "in"
STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/syringe/dart, /obj/item/reagent_containers/chem_pack))
/*
* Biowaste bag (mostly for xenobiologists)
*/
/obj/item/storage/bag/bio
name = "bio bag"
icon = 'icons/obj/chemical.dmi'
icon_state = "biobag"
desc = "A bag for the safe transportation and disposal of biowaste and other biological materials."
w_class = WEIGHT_CLASS_TINY
resistance_flags = FLAMMABLE
/obj/item/storage/bag/bio/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 200
STR.max_items = 25
STR.insert_preposition = "in"
STR.can_hold = typecacheof(list(/obj/item/slime_extract, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/blood, /obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/food/snacks/deadmouse, /obj/item/reagent_containers/food/snacks/monkeycube))
/obj/item/storage/bag/bio/holding
name = "bio bag of holding"
icon = 'icons/obj/chemical.dmi'
icon_state = "bspace_biobag"
desc = "A bag for the safe transportation and disposal of biowaste and other biological materials."
/obj/item/storage/bag/bio/holding/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = INFINITY
STR.max_items = 100
/*
* Construction bag (for engineering, holds stock parts and electronics)
*/
/obj/item/storage/bag/construction
name = "construction bag"
icon = 'icons/obj/tools.dmi'
icon_state = "construction_bag"
desc = "A bag for storing small construction components."
w_class = WEIGHT_CLASS_TINY
resistance_flags = FLAMMABLE
/obj/item/storage/bag/construction/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 100
STR.max_items = 50
STR.max_w_class = WEIGHT_CLASS_SMALL
STR.insert_preposition = "in"
STR.can_hold = typecacheof(list(/obj/item/stack/ore/bluespace_crystal, /obj/item/assembly, /obj/item/stock_parts, /obj/item/reagent_containers/glass/beaker, /obj/item/stack/cable_coil, /obj/item/circuitboard, /obj/item/electronics))
+9 -6
View File
@@ -849,18 +849,20 @@
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
var/datum/component/mobhook
var/mob/listeningTo
var/zoom_out_amt = 6
var/zoom_amt = 10
/obj/item/twohanded/binoculars/Destroy()
listeningTo = null
return ..()
/obj/item/twohanded/binoculars/wield(mob/user)
. = ..()
if(!wielded)
return
if(QDELETED(mobhook))
mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/unwield)))
else
user.TakeComponent(mobhook)
RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/unwield)
listeningTo = user
user.visible_message("[user] holds [src] up to [user.p_their()] eyes.","You hold [src] up to your eyes.")
item_state = "binoculars_wielded"
user.regenerate_icons()
@@ -884,7 +886,8 @@
/obj/item/twohanded/binoculars/unwield(mob/user)
. = ..()
mobhook.RemoveComponent()
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
listeningTo = null
user.visible_message("[user] lowers [src].","You lower [src].")
item_state = "binoculars"
user.regenerate_icons()
+1 -1
View File
@@ -271,7 +271,7 @@
icon_state = "sandstone"
mineral = /obj/item/stack/sheet/mineral/sandstone
walltype = /turf/closed/wall/mineral/sandstone
canSmoothWith = list(/obj/structure/falsewall/sandstone, /turf/closed/wall/mineral/sandstone)
canSmoothWith = list(/obj/structure/falsewall/sandstone, /turf/closed/wall/mineral/sandstone, /obj/structure/window/fulltile)
/obj/structure/falsewall/wood
name = "wooden wall"
+8
View File
@@ -271,6 +271,14 @@
icon = 'icons/obj/statuelarge.dmi'
icon_state = "venus"
/obj/structure/statue/sandstone/abs
max_integrity = 300
anchored = TRUE
name = "ancient statue"
desc = "An ancient statue, representing one of the gods. It almost seems like it's alive."
icon = 'icons/obj/statue_egypty.dmi'
icon_state = "abs"
/////////////////////snow/////////////////////////////////////////
/obj/structure/statue/snow
+3 -1
View File
@@ -516,7 +516,9 @@
/obj/machinery/door/airlock/hatch,
/obj/machinery/door/airlock/engineering/glass/critical,
/obj/machinery/door/airlock/atmos,
/obj/machinery/door/airlock/highsecurity,)
/obj/machinery/door/airlock/highsecurity,
/turf/closed/wall/mineral/sandstone,
/obj/structure/falsewall/sandstone,)
// canSmoothWith = list(/obj/structure/window/fulltile, /obj/structure/window/reinforced/fulltile, /obj/structure/window/reinforced/tinted/fulltile, /obj/structure/window/plasma/fulltile, /obj/structure/window/plasma/reinforced/fulltile)
glass_amount = 2
@@ -260,3 +260,29 @@
icon = 'icons/obj/clockwork_objects.dmi'
icon_state = "clockwork_floor"
floor_tile = /obj/item/stack/tile/bronze
/turf/open/floor/concrete/
name = "concrete"
icon = 'icons/turf/floors.dmi'
icon_state = "concrete"
baseturfs = /turf/open/floor/plating/asteroid
/turf/open/floor/concrete/smooth
icon_state = "concrete2"
/turf/open/floor/cobble/side
icon_state = "cobble_side"
/turf/open/floor/cobble/corner
icon_state = "cobble_corner"
/turf/open/floor/cobble
name = "cobblestone path"
desc = "A simple but beautiful path made of various sized stones."
icon = 'icons/turf/floors.dmi'
icon_state = "cobble"
baseturfs = /turf/open/floor/plating/asteroid
footstep = FOOTSTEP_FLOOR
barefootstep = FOOTSTEP_HARD_BAREFOOT
clawfootstep = FOOTSTEP_HARD_CLAW
heavyfootstep = FOOTSTEP_GENERIC_HEAVY
@@ -49,7 +49,7 @@
icon_state = "sandstone"
sheet_type = /obj/item/stack/sheet/mineral/sandstone
explosion_block = 0
canSmoothWith = list(/turf/closed/wall/mineral/sandstone, /obj/structure/falsewall/sandstone)
canSmoothWith = list(/turf/closed/wall/mineral/sandstone, /obj/structure/falsewall/sandstone, /obj/structure/window/fulltile)
/turf/closed/wall/mineral/uranium
article = "a"
+1 -1
View File
@@ -107,7 +107,7 @@
if(text2num(duration) > 0)
expires = " The ban is for [duration] minutes and expires on [expiration] (server time)."
else
expires = " The is a permanent ban."
expires = " This is a permanent ban."
var/desc = "\nReason: You, or another user of this computer or connection ([pkey]) is banned from playing here. The ban reason is:\n[reason]\nThis ban (BanID #[banid]) was applied by [akey] on [bantime] during round ID [ban_round_id], [expires]"
@@ -110,7 +110,7 @@
if(!user.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE))
to_chat(user, "<span class='danger'>AUTHENTICATION FAILURE. ACCESS DENIED.</span>")
return FALSE
if(!user.onSyndieBase())
if(!user.onSyndieBase() && !user.mind.has_antag_datum(/datum/antagonist/nukeop/lone,TRUE))
to_chat(user, "<span class='warning'>[src] is out of range! It can only be used at your base!</span>")
return FALSE
return TRUE
@@ -31,7 +31,6 @@ the new instance inside the host to be updated to the template's stats.
var/browser_open = FALSE
var/mob/living/following_host
var/datum/component/redirect/move_listener
var/list/disease_instances
var/list/hosts //this list is associative, affected_mob -> disease_instance
var/datum/disease/advance/sentient_disease/disease_template
@@ -260,16 +259,10 @@ the new instance inside the host to be updated to the template's stats.
refresh_adaptation_menu()
/mob/camera/disease/proc/set_following(mob/living/L)
if(following_host)
UnregisterSignal(following_host, COMSIG_MOVABLE_MOVED)
RegisterSignal(L, COMSIG_MOVABLE_MOVED, .proc/follow_mob)
following_host = L
if(!move_listener)
move_listener = L.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/follow_mob)))
else
if(L)
L.TakeComponent(move_listener)
if(QDELING(move_listener))
move_listener = null
else
QDEL_NULL(move_listener)
follow_mob()
/mob/camera/disease/proc/follow_next(reverse = FALSE)
@@ -12,8 +12,8 @@
disease_flags = CURABLE
permeability_mod = 1
severity = DISEASE_SEVERITY_DANGEROUS
var/finalstage = 0 //Because we're spawning off the cure in the final stage, we need to check if we've done the final stage's effects.
var/datum/mood_event/revenant_blight/depression
var/finalstage = FALSE //Because we're spawning off the cure in the final stage, we need to check if we've done the final stage's effects.
var/depression = FALSE
/datum/disease/revblight/cure()
if(affected_mob)
@@ -44,7 +44,8 @@
affected_mob.emote("pale")
if(3)
if(!depression)
depression = SEND_SIGNAL(affected_mob, COMSIG_ADD_MOOD_EVENT, "rev_blight", /datum/mood_event/revenant_blight)
SEND_SIGNAL(affected_mob, COMSIG_ADD_MOOD_EVENT, "rev_blight", /datum/mood_event/revenant_blight)
depression = TRUE
SEND_SIGNAL(affected_mob, COMSIG_DECREASE_SANITY, 0.12, SANITY_CRAZY)
if(prob(10))
affected_mob.emote(pick("pale","shiver"))
+239 -235
View File
@@ -1,235 +1,239 @@
/obj/item/assembly/infra
name = "infrared emitter"
desc = "Emits a visible or invisible beam and is triggered when the beam is interrupted."
icon_state = "infrared"
materials = list(MAT_METAL=1000, MAT_GLASS=500)
is_position_sensitive = TRUE
var/on = FALSE
var/visible = FALSE
var/maxlength = 8
var/list/obj/effect/beam/i_beam/beams
var/olddir = 0
var/datum/component/redirect/listener
var/hearing_range = 3
/obj/item/assembly/infra/Initialize()
. = ..()
beams = list()
START_PROCESSING(SSobj, src)
/obj/item/assembly/infra/ComponentInitialize()
. = ..()
AddComponent(
/datum/component/simple_rotation,
ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_FLIP | ROTATION_VERBS,
null,
null,
CALLBACK(src,.proc/after_rotation)
)
/obj/item/assembly/infra/proc/after_rotation()
refreshBeam()
/obj/item/assembly/infra/Destroy()
STOP_PROCESSING(SSobj, src)
QDEL_NULL(listener)
QDEL_LIST(beams)
. = ..()
/obj/item/assembly/infra/examine(mob/user)
. = ..()
. += "<span class='notice'>The infrared trigger is [on?"on":"off"].</span>"
/obj/item/assembly/infra/activate()
if(!..())
return FALSE//Cooldown check
on = !on
refreshBeam()
update_icon()
return TRUE
/obj/item/assembly/infra/toggle_secure()
secured = !secured
if(secured)
START_PROCESSING(SSobj, src)
refreshBeam()
else
QDEL_LIST(beams)
STOP_PROCESSING(SSobj, src)
update_icon()
return secured
/obj/item/assembly/infra/update_icon()
cut_overlays()
attached_overlays = list()
if(on)
add_overlay("infrared_on")
attached_overlays += "infrared_on"
if(visible && secured)
add_overlay("infrared_visible")
attached_overlays += "infrared_visible"
if(holder)
holder.update_icon()
return
/obj/item/assembly/infra/dropped()
. = ..()
if(holder)
holder_movement() //sync the dir of the device as well if it's contained in a TTV or an assembly holder
else
refreshBeam()
/obj/item/assembly/infra/process()
if(!on || !secured)
refreshBeam()
return
/obj/item/assembly/infra/proc/refreshBeam()
QDEL_LIST(beams)
if(throwing || !on || !secured)
return
if(holder)
if(holder.master) //incase the sensor is part of an assembly that's contained in another item, such as a single tank bomb
if(!holder.master.IsSpecialAssembly() || !isturf(holder.master.loc))
return
else if(!isturf(holder.loc)) //else just check where the holder is
return
else if(!isturf(loc)) //or just where the fuck we are in general
return
var/turf/T = get_turf(src)
var/_dir = dir
var/turf/_T = get_step(T, _dir)
if(_T)
for(var/i in 1 to maxlength)
var/obj/effect/beam/i_beam/I = new(T)
if(istype(holder, /obj/item/assembly_holder))
var/obj/item/assembly_holder/assembly_holder = holder
I.icon_state = "[initial(I.icon_state)]_[(assembly_holder.a_left == src) ? "l":"r"]" //Sync the offset of the beam with the position of the sensor.
else if(istype(holder, /obj/item/transfer_valve))
I.icon_state = "[initial(I.icon_state)]_ttv"
I.density = TRUE
if(!I.Move(_T))
qdel(I)
switchListener(_T)
break
I.density = FALSE
beams += I
I.master = src
I.setDir(_dir)
I.invisibility = visible? 0 : INVISIBILITY_ABSTRACT
T = _T
_T = get_step(_T, _dir)
CHECK_TICK
/obj/item/assembly/infra/on_detach()
. = ..()
if(!.)
return
refreshBeam()
/obj/item/assembly/infra/attack_hand()
. = ..()
refreshBeam()
/obj/item/assembly/infra/Moved()
var/t = dir
. = ..()
setDir(t)
/obj/item/assembly/infra/throw_at()
. = ..()
olddir = dir
/obj/item/assembly/infra/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
. = ..()
if(!olddir)
return
setDir(olddir)
olddir = null
/obj/item/assembly/infra/proc/trigger_beam(atom/movable/AM, turf/location)
refreshBeam()
switchListener(location)
if(!secured || !on || next_activate > world.time)
return FALSE
pulse(FALSE)
audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*", null, hearing_range)
for(var/CHM in get_hearers_in_view(hearing_range, src))
if(ismob(CHM))
var/mob/LM = CHM
LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
next_activate = world.time + 30
/obj/item/assembly/infra/proc/switchListener(turf/newloc)
QDEL_NULL(listener)
listener = newloc.AddComponent(/datum/component/redirect, list(COMSIG_ATOM_EXITED = CALLBACK(src, .proc/check_exit)))
/obj/item/assembly/infra/proc/check_exit(datum/source, atom/movable/offender)
if(QDELETED(src))
return
if(offender == src || istype(offender,/obj/effect/beam/i_beam))
return
if (offender && isitem(offender))
var/obj/item/I = offender
if (I.item_flags & ABSTRACT)
return
return refreshBeam()
/obj/item/assembly/infra/ui_interact(mob/user)//TODO: change this this to the wire control panel
. = ..()
if(is_secured(user))
user.set_machine(src)
var/dat = "<TT><B>Infrared Laser</B></TT>"
dat += "<BR><B>Status</B>: [on ? "<A href='?src=[REF(src)];state=0'>On</A>" : "<A href='?src=[REF(src)];state=1'>Off</A>"]"
dat += "<BR><B>Visibility</B>: [visible ? "<A href='?src=[REF(src)];visible=0'>Visible</A>" : "<A href='?src=[REF(src)];visible=1'>Invisible</A>"]"
dat += "<BR><BR><A href='?src=[REF(src)];refresh=1'>Refresh</A>"
dat += "<BR><BR><A href='?src=[REF(src)];close=1'>Close</A>"
user << browse(dat, "window=infra")
onclose(user, "infra")
return
/obj/item/assembly/infra/Topic(href, href_list)
..()
if(usr.incapacitated() || !in_range(loc, usr))
usr << browse(null, "window=infra")
onclose(usr, "infra")
return
if(href_list["state"])
on = !(on)
update_icon()
refreshBeam()
if(href_list["visible"])
visible = !(visible)
update_icon()
refreshBeam()
if(href_list["close"])
usr << browse(null, "window=infra")
return
if(usr)
attack_self(usr)
/obj/item/assembly/infra/setDir()
. = ..()
refreshBeam()
/***************************IBeam*********************************/
/obj/effect/beam/i_beam
name = "infrared beam"
icon = 'icons/obj/projectiles.dmi'
icon_state = "ibeam"
var/obj/item/assembly/infra/master
anchored = TRUE
density = FALSE
pass_flags = PASSTABLE|PASSGLASS|PASSGRILLE|LETPASSTHROW
/obj/effect/beam/i_beam/Crossed(atom/movable/AM as mob|obj)
if(istype(AM, /obj/effect/beam))
return
if (isitem(AM))
var/obj/item/I = AM
if (I.item_flags & ABSTRACT)
return
master.trigger_beam(AM, get_turf(src))
/obj/item/assembly/infra
name = "infrared emitter"
desc = "Emits a visible or invisible beam and is triggered when the beam is interrupted."
icon_state = "infrared"
materials = list(MAT_METAL=1000, MAT_GLASS=500)
is_position_sensitive = TRUE
var/on = FALSE
var/visible = FALSE
var/maxlength = 8
var/list/obj/effect/beam/i_beam/beams
var/olddir = 0
var/turf/listeningTo
var/hearing_range = 3
/obj/item/assembly/infra/Initialize()
. = ..()
beams = list()
START_PROCESSING(SSobj, src)
/obj/item/assembly/infra/ComponentInitialize()
. = ..()
AddComponent(
/datum/component/simple_rotation,
ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_FLIP | ROTATION_VERBS,
null,
null,
CALLBACK(src,.proc/after_rotation)
)
/obj/item/assembly/infra/proc/after_rotation()
refreshBeam()
/obj/item/assembly/infra/Destroy()
STOP_PROCESSING(SSobj, src)
listeningTo = null
QDEL_LIST(beams)
. = ..()
/obj/item/assembly/infra/examine(mob/user)
. = ..()
. += "<span class='notice'>The infrared trigger is [on?"on":"off"].</span>"
/obj/item/assembly/infra/activate()
if(!..())
return FALSE//Cooldown check
on = !on
refreshBeam()
update_icon()
return TRUE
/obj/item/assembly/infra/toggle_secure()
secured = !secured
if(secured)
START_PROCESSING(SSobj, src)
refreshBeam()
else
QDEL_LIST(beams)
STOP_PROCESSING(SSobj, src)
update_icon()
return secured
/obj/item/assembly/infra/update_icon()
cut_overlays()
attached_overlays = list()
if(on)
add_overlay("infrared_on")
attached_overlays += "infrared_on"
if(visible && secured)
add_overlay("infrared_visible")
attached_overlays += "infrared_visible"
if(holder)
holder.update_icon()
return
/obj/item/assembly/infra/dropped()
. = ..()
if(holder)
holder_movement() //sync the dir of the device as well if it's contained in a TTV or an assembly holder
else
refreshBeam()
/obj/item/assembly/infra/process()
if(!on || !secured)
refreshBeam()
return
/obj/item/assembly/infra/proc/refreshBeam()
QDEL_LIST(beams)
if(throwing || !on || !secured)
return
if(holder)
if(holder.master) //incase the sensor is part of an assembly that's contained in another item, such as a single tank bomb
if(!holder.master.IsSpecialAssembly() || !isturf(holder.master.loc))
return
else if(!isturf(holder.loc)) //else just check where the holder is
return
else if(!isturf(loc)) //or just where the fuck we are in general
return
var/turf/T = get_turf(src)
var/_dir = dir
var/turf/_T = get_step(T, _dir)
if(_T)
for(var/i in 1 to maxlength)
var/obj/effect/beam/i_beam/I = new(T)
if(istype(holder, /obj/item/assembly_holder))
var/obj/item/assembly_holder/assembly_holder = holder
I.icon_state = "[initial(I.icon_state)]_[(assembly_holder.a_left == src) ? "l":"r"]" //Sync the offset of the beam with the position of the sensor.
else if(istype(holder, /obj/item/transfer_valve))
I.icon_state = "[initial(I.icon_state)]_ttv"
I.density = TRUE
if(!I.Move(_T))
qdel(I)
switchListener(_T)
break
I.density = FALSE
beams += I
I.master = src
I.setDir(_dir)
I.invisibility = visible? 0 : INVISIBILITY_ABSTRACT
T = _T
_T = get_step(_T, _dir)
CHECK_TICK
/obj/item/assembly/infra/on_detach()
. = ..()
if(!.)
return
refreshBeam()
/obj/item/assembly/infra/attack_hand()
. = ..()
refreshBeam()
/obj/item/assembly/infra/Moved()
var/t = dir
. = ..()
setDir(t)
/obj/item/assembly/infra/throw_at()
. = ..()
olddir = dir
/obj/item/assembly/infra/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
. = ..()
if(!olddir)
return
setDir(olddir)
olddir = null
/obj/item/assembly/infra/proc/trigger_beam(atom/movable/AM, turf/location)
refreshBeam()
switchListener(location)
if(!secured || !on || next_activate > world.time)
return FALSE
pulse(FALSE)
audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*", null, hearing_range)
for(var/CHM in get_hearers_in_view(hearing_range, src))
if(ismob(CHM))
var/mob/LM = CHM
LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
next_activate = world.time + 30
/obj/item/assembly/infra/proc/switchListener(turf/newloc)
if(listeningTo == newloc)
return
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_ATOM_EXITED)
RegisterSignal(newloc, COMSIG_ATOM_EXITED, .proc/check_exit)
listeningTo = newloc
/obj/item/assembly/infra/proc/check_exit(datum/source, atom/movable/offender)
if(QDELETED(src))
return
if(offender == src || istype(offender,/obj/effect/beam/i_beam))
return
if (offender && isitem(offender))
var/obj/item/I = offender
if (I.item_flags & ABSTRACT)
return
return refreshBeam()
/obj/item/assembly/infra/ui_interact(mob/user)//TODO: change this this to the wire control panel
. = ..()
if(is_secured(user))
user.set_machine(src)
var/dat = "<TT><B>Infrared Laser</B></TT>"
dat += "<BR><B>Status</B>: [on ? "<A href='?src=[REF(src)];state=0'>On</A>" : "<A href='?src=[REF(src)];state=1'>Off</A>"]"
dat += "<BR><B>Visibility</B>: [visible ? "<A href='?src=[REF(src)];visible=0'>Visible</A>" : "<A href='?src=[REF(src)];visible=1'>Invisible</A>"]"
dat += "<BR><BR><A href='?src=[REF(src)];refresh=1'>Refresh</A>"
dat += "<BR><BR><A href='?src=[REF(src)];close=1'>Close</A>"
user << browse(dat, "window=infra")
onclose(user, "infra")
return
/obj/item/assembly/infra/Topic(href, href_list)
..()
if(usr.incapacitated() || !in_range(loc, usr))
usr << browse(null, "window=infra")
onclose(usr, "infra")
return
if(href_list["state"])
on = !(on)
update_icon()
refreshBeam()
if(href_list["visible"])
visible = !(visible)
update_icon()
refreshBeam()
if(href_list["close"])
usr << browse(null, "window=infra")
return
if(usr)
attack_self(usr)
/obj/item/assembly/infra/setDir()
. = ..()
refreshBeam()
/***************************IBeam*********************************/
/obj/effect/beam/i_beam
name = "infrared beam"
icon = 'icons/obj/projectiles.dmi'
icon_state = "ibeam"
var/obj/item/assembly/infra/master
anchored = TRUE
density = FALSE
pass_flags = PASSTABLE|PASSGLASS|PASSGRILLE|LETPASSTHROW
/obj/effect/beam/i_beam/Crossed(atom/movable/AM as mob|obj)
if(istype(AM, /obj/effect/beam))
return
if (isitem(AM))
var/obj/item/I = AM
if (I.item_flags & ABSTRACT)
return
master.trigger_beam(AM, get_turf(src))
+43 -43
View File
@@ -1,43 +1,43 @@
/obj/item/clothing/gloves
name = "gloves"
gender = PLURAL //Carn: for grammarically correct text-parsing
w_class = WEIGHT_CLASS_SMALL
icon = 'icons/obj/clothing/gloves.dmi'
siemens_coefficient = 0.5
body_parts_covered = HANDS
slot_flags = ITEM_SLOT_GLOVES
attack_verb = list("challenged")
var/transfer_prints = FALSE
var/transfer_blood = 0
strip_delay = 20
equip_delay_other = 40
/obj/item/clothing/gloves/ComponentInitialize()
. = ..()
AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, /obj/item/clothing/gloves/clean_blood)))
/obj/item/clothing/gloves/clean_blood(datum/source, strength)
. = ..()
transfer_blood = 0
/obj/item/clothing/gloves/suicide_act(mob/living/carbon/user)
user.visible_message("<span class='suicide'>\the [src] are forcing [user]'s hands around [user.p_their()] neck! It looks like the gloves are possessed!</span>")
return OXYLOSS
/obj/item/clothing/gloves/worn_overlays(isinhands = FALSE)
. = list()
if(!isinhands)
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedgloves")
if(blood_DNA)
. += mutable_appearance('icons/effects/blood.dmi', "bloodyhands", color = blood_DNA_to_color())
/obj/item/clothing/gloves/update_clothes_damaged_state(damaging = TRUE)
..()
if(ismob(loc))
var/mob/M = loc
M.update_inv_gloves()
// Called just before an attack_hand(), in mob/UnarmedAttack()
/obj/item/clothing/gloves/proc/Touch(atom/A, proximity)
return FALSE // return TRUE to cancel attack_hand()
/obj/item/clothing/gloves
name = "gloves"
gender = PLURAL //Carn: for grammarically correct text-parsing
w_class = WEIGHT_CLASS_SMALL
icon = 'icons/obj/clothing/gloves.dmi'
siemens_coefficient = 0.5
body_parts_covered = HANDS
slot_flags = ITEM_SLOT_GLOVES
attack_verb = list("challenged")
var/transfer_prints = FALSE
var/transfer_blood = 0
strip_delay = 20
equip_delay_other = 40
/obj/item/clothing/gloves/ComponentInitialize()
. = ..()
RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /obj/item/clothing/gloves/clean_blood)
/obj/item/clothing/gloves/clean_blood(datum/source, strength)
. = ..()
transfer_blood = 0
/obj/item/clothing/gloves/suicide_act(mob/living/carbon/user)
user.visible_message("<span class='suicide'>\the [src] are forcing [user]'s hands around [user.p_their()] neck! It looks like the gloves are possessed!</span>")
return OXYLOSS
/obj/item/clothing/gloves/worn_overlays(isinhands = FALSE)
. = list()
if(!isinhands)
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedgloves")
if(blood_DNA)
. += mutable_appearance('icons/effects/blood.dmi', "bloodyhands", color = blood_DNA_to_color())
/obj/item/clothing/gloves/update_clothes_damaged_state(damaging = TRUE)
..()
if(ismob(loc))
var/mob/M = loc
M.update_inv_gloves()
// Called just before an attack_hand(), in mob/UnarmedAttack()
/obj/item/clothing/gloves/proc/Touch(atom/A, proximity)
return FALSE // return TRUE to cancel attack_hand()
+113 -113
View File
@@ -1,113 +1,113 @@
/obj/item/clothing/shoes
name = "shoes"
icon = 'icons/obj/clothing/shoes.dmi'
desc = "Comfortable-looking shoes."
gender = PLURAL //Carn: for grammarically correct text-parsing
var/chained = 0
body_parts_covered = FEET
slot_flags = ITEM_SLOT_FEET
permeability_coefficient = 0.5
slowdown = SHOES_SLOWDOWN
var/blood_state = BLOOD_STATE_NOT_BLOODY
var/list/bloody_shoes = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0)
var/offset = 0
var/equipped_before_drop = FALSE
//CITADEL EDIT Enables digitigrade shoe styles
var/adjusted = NORMAL_STYLE
mutantrace_variation = MUTANTRACE_VARIATION
var/last_bloodtype = "" //used to track the last bloodtype to have graced these shoes; makes for better performing footprint shenanigans
var/last_blood_DNA = "" //same as last one
/obj/item/clothing/shoes/ComponentInitialize()
. = ..()
AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, /obj/item/clothing/shoes/clean_blood)))
/obj/item/clothing/shoes/suicide_act(mob/living/carbon/user)
if(rand(2)>1)
user.visible_message("<span class='suicide'>[user] begins tying \the [src] up waaay too tightly! It looks like [user.p_theyre()] trying to commit suicide!</span>")
var/obj/item/bodypart/l_leg = user.get_bodypart(BODY_ZONE_L_LEG)
var/obj/item/bodypart/r_leg = user.get_bodypart(BODY_ZONE_R_LEG)
if(l_leg)
l_leg.dismember()
playsound(user,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1)
if(r_leg)
r_leg.dismember()
playsound(user,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1)
return BRUTELOSS
else//didnt realize this suicide act existed (was in miscellaneous.dm) and didnt want to remove it, so made it a 50/50 chance. Why not!
user.visible_message("<span class='suicide'>[user] is bashing [user.p_their()] own head in with [src]! Ain't that a kick in the head?</span>")
for(var/i = 0, i < 3, i++)
sleep(3)
playsound(user, 'sound/weapons/genhit2.ogg', 50, 1)
return(BRUTELOSS)
/obj/item/clothing/shoes/transfer_blood_dna(list/blood_dna, diseases)
..()
if(blood_dna.len)
last_bloodtype = blood_dna[blood_dna[blood_dna.len]]//trust me this works
last_blood_DNA = blood_dna[blood_dna.len]
/obj/item/clothing/shoes/worn_overlays(isinhands = FALSE)
. = list()
if(!isinhands)
var/bloody = FALSE
if(blood_DNA)
bloody = TRUE
else
bloody = bloody_shoes[BLOOD_STATE_BLOOD]
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedshoe")
if(bloody)
if(adjusted == NORMAL_STYLE)
. += mutable_appearance('icons/effects/blood.dmi', "shoeblood", color = blood_DNA_to_color())
else
. += mutable_appearance('modular_citadel/icons/mob/digishoes.dmi', "shoeblood", color = blood_DNA_to_color())
/obj/item/clothing/shoes/equipped(mob/user, slot)
. = ..()
if(mutantrace_variation && ishuman(user))
var/mob/living/carbon/human/H = user
if(DIGITIGRADE in H.dna.species.species_traits)
adjusted = ALT_STYLE
H.update_inv_shoes()
else if(adjusted == ALT_STYLE)
adjusted = NORMAL_STYLE
H.update_inv_shoes()
if(offset && slot_flags & slotdefine2slotbit(slot))
user.pixel_y += offset
worn_y_dimension -= (offset * 2)
user.update_inv_shoes()
equipped_before_drop = TRUE
/obj/item/clothing/shoes/proc/restore_offsets(mob/user)
equipped_before_drop = FALSE
user.pixel_y -= offset
worn_y_dimension = world.icon_size
/obj/item/clothing/shoes/dropped(mob/user)
if(offset && equipped_before_drop)
restore_offsets(user)
. = ..()
/obj/item/clothing/shoes/update_clothes_damaged_state(damaging = TRUE)
..()
if(ismob(loc))
var/mob/M = loc
M.update_inv_shoes()
/obj/item/clothing/shoes/clean_blood(datum/source, strength)
. = ..()
bloody_shoes = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0)
blood_state = BLOOD_STATE_NOT_BLOODY
if(ismob(loc))
var/mob/M = loc
M.update_inv_shoes()
/obj/item/proc/negates_gravity()
return FALSE
/obj/item/clothing/shoes
name = "shoes"
icon = 'icons/obj/clothing/shoes.dmi'
desc = "Comfortable-looking shoes."
gender = PLURAL //Carn: for grammarically correct text-parsing
var/chained = 0
body_parts_covered = FEET
slot_flags = ITEM_SLOT_FEET
permeability_coefficient = 0.5
slowdown = SHOES_SLOWDOWN
var/blood_state = BLOOD_STATE_NOT_BLOODY
var/list/bloody_shoes = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0)
var/offset = 0
var/equipped_before_drop = FALSE
//CITADEL EDIT Enables digitigrade shoe styles
var/adjusted = NORMAL_STYLE
mutantrace_variation = MUTANTRACE_VARIATION
var/last_bloodtype = "" //used to track the last bloodtype to have graced these shoes; makes for better performing footprint shenanigans
var/last_blood_DNA = "" //same as last one
/obj/item/clothing/shoes/ComponentInitialize()
. = ..()
RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /obj/item/clothing/shoes/clean_blood)
/obj/item/clothing/shoes/suicide_act(mob/living/carbon/user)
if(rand(2)>1)
user.visible_message("<span class='suicide'>[user] begins tying \the [src] up waaay too tightly! It looks like [user.p_theyre()] trying to commit suicide!</span>")
var/obj/item/bodypart/l_leg = user.get_bodypart(BODY_ZONE_L_LEG)
var/obj/item/bodypart/r_leg = user.get_bodypart(BODY_ZONE_R_LEG)
if(l_leg)
l_leg.dismember()
playsound(user,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1)
if(r_leg)
r_leg.dismember()
playsound(user,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1)
return BRUTELOSS
else//didnt realize this suicide act existed (was in miscellaneous.dm) and didnt want to remove it, so made it a 50/50 chance. Why not!
user.visible_message("<span class='suicide'>[user] is bashing [user.p_their()] own head in with [src]! Ain't that a kick in the head?</span>")
for(var/i = 0, i < 3, i++)
sleep(3)
playsound(user, 'sound/weapons/genhit2.ogg', 50, 1)
return(BRUTELOSS)
/obj/item/clothing/shoes/transfer_blood_dna(list/blood_dna, diseases)
..()
if(blood_dna.len)
last_bloodtype = blood_dna[blood_dna[blood_dna.len]]//trust me this works
last_blood_DNA = blood_dna[blood_dna.len]
/obj/item/clothing/shoes/worn_overlays(isinhands = FALSE)
. = list()
if(!isinhands)
var/bloody = FALSE
if(blood_DNA)
bloody = TRUE
else
bloody = bloody_shoes[BLOOD_STATE_BLOOD]
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedshoe")
if(bloody)
if(adjusted == NORMAL_STYLE)
. += mutable_appearance('icons/effects/blood.dmi', "shoeblood", color = blood_DNA_to_color())
else
. += mutable_appearance('modular_citadel/icons/mob/digishoes.dmi', "shoeblood", color = blood_DNA_to_color())
/obj/item/clothing/shoes/equipped(mob/user, slot)
. = ..()
if(mutantrace_variation && ishuman(user))
var/mob/living/carbon/human/H = user
if(DIGITIGRADE in H.dna.species.species_traits)
adjusted = ALT_STYLE
H.update_inv_shoes()
else if(adjusted == ALT_STYLE)
adjusted = NORMAL_STYLE
H.update_inv_shoes()
if(offset && slot_flags & slotdefine2slotbit(slot))
user.pixel_y += offset
worn_y_dimension -= (offset * 2)
user.update_inv_shoes()
equipped_before_drop = TRUE
/obj/item/clothing/shoes/proc/restore_offsets(mob/user)
equipped_before_drop = FALSE
user.pixel_y -= offset
worn_y_dimension = world.icon_size
/obj/item/clothing/shoes/dropped(mob/user)
if(offset && equipped_before_drop)
restore_offsets(user)
. = ..()
/obj/item/clothing/shoes/update_clothes_damaged_state(damaging = TRUE)
..()
if(ismob(loc))
var/mob/M = loc
M.update_inv_shoes()
/obj/item/clothing/shoes/clean_blood(datum/source, strength)
. = ..()
bloody_shoes = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0)
blood_state = BLOOD_STATE_NOT_BLOODY
if(ismob(loc))
var/mob/M = loc
M.update_inv_shoes()
/obj/item/proc/negates_gravity()
return FALSE
+14 -11
View File
@@ -604,7 +604,6 @@
armor = list("melee" = 30, "bullet" = 5, "laser" = 5, "energy" = 0, "bomb" = 50, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 75)
item_color = "ancient"
resistance_flags = FIRE_PROOF
var/datum/component/mobhook
/obj/item/clothing/suit/space/hardsuit/ancient
name = "prototype RIG hardsuit"
@@ -616,7 +615,7 @@
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ancient
resistance_flags = FIRE_PROOF
var/footstep = 1
var/datum/component/mobhook
var/mob/listeningTo
/obj/item/clothing/suit/space/hardsuit/ancient/mason
name = "M.A.S.O.N RIG"
@@ -673,20 +672,24 @@
/obj/item/clothing/suit/space/hardsuit/ancient/equipped(mob/user, slot)
. = ..()
if (slot == SLOT_WEAR_SUIT)
if (mobhook && mobhook.parent != user)
QDEL_NULL(mobhook)
if (!mobhook)
mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_mob_move)))
else
QDEL_NULL(mobhook)
if(slot != SLOT_WEAR_SUIT)
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
return
if(listeningTo == user)
return
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/on_mob_move)
listeningTo = user
/obj/item/clothing/suit/space/hardsuit/ancient/dropped()
. = ..()
QDEL_NULL(mobhook)
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
/obj/item/clothing/suit/space/hardsuit/ancient/Destroy()
QDEL_NULL(mobhook) // mobhook is not our component
listeningTo = null
return ..()
/////////////SHIELDED//////////////////////////////////
+9 -5
View File
@@ -283,7 +283,7 @@
var/field_type = /datum/proximity_monitor/advanced/debug
var/operating = FALSE
var/datum/proximity_monitor/advanced/current = null
var/datum/component/mobhook
var/mob/listeningTo
/obj/item/multitool/field_debug/Initialize()
. = ..()
@@ -292,7 +292,7 @@
/obj/item/multitool/field_debug/Destroy()
STOP_PROCESSING(SSobj, src)
QDEL_NULL(current)
QDEL_NULL(mobhook)
listeningTo = null
return ..()
/obj/item/multitool/field_debug/proc/setup_debug_field()
@@ -303,16 +303,20 @@
/obj/item/multitool/field_debug/attack_self(mob/user)
operating = !operating
to_chat(user, "You turn [src] [operating? "on":"off"].")
QDEL_NULL(mobhook)
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
listeningTo = null
if(!istype(current) && operating)
mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_mob_move)))
RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/on_mob_move)
listeningTo = user
setup_debug_field()
else if(!operating)
QDEL_NULL(current)
/obj/item/multitool/field_debug/dropped()
. = ..()
QDEL_NULL(mobhook)
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
listeningTo = null
/obj/item/multitool/field_debug/proc/on_mob_move()
check_turf(get_turf(src))
+1 -1
View File
@@ -138,7 +138,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
Show()
/obj/effect/hallucination/simple/Destroy()
if(target.client)
if(target && target.client)
target.client.images.Remove(current_image)
active = FALSE
return ..()
@@ -29,7 +29,7 @@
. = ..()
AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, /mob/living/carbon/human/clean_blood)))
RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /mob/living/carbon/human/clean_blood)
/mob/living/carbon/human/ComponentInitialize()
File diff suppressed because it is too large Load Diff
@@ -200,7 +200,8 @@
pH = 11
/datum/reagent/toxin/mindbreaker/on_mob_life(mob/living/carbon/M)
M.hallucination += 5
if(!M.has_quirk(/datum/quirk/insanity))
M.hallucination += 5
return ..()
/datum/reagent/toxin/plantbgone
@@ -64,10 +64,9 @@
var/interrupted = FALSE
var/mob/target
var/icon/bluespace
var/datum/weakref/redirect_component
/datum/status_effect/slimerecall/on_apply()
redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/resistField))))
RegisterSignal(owner, COMSIG_LIVING_RESIST, .proc/resistField)
to_chat(owner, "<span class='danger'>You feel a sudden tug from an unknown force, and feel a pull to bluespace!</span>")
to_chat(owner, "<span class='notice'>Resist if you wish avoid the force!</span>")
bluespace = icon('icons/effects/effects.dmi',"chronofield")
@@ -77,9 +76,9 @@
/datum/status_effect/slimerecall/proc/resistField()
interrupted = TRUE
owner.remove_status_effect(src)
/datum/status_effect/slimerecall/on_remove()
qdel(redirect_component.resolve())
redirect_component = null
UnregisterSignal(owner, COMSIG_LIVING_RESIST)
owner.cut_overlay(bluespace)
if(interrupted || !ismob(target))
to_chat(owner, "<span class='warning'>The bluespace tug fades away, and you feel that the force has passed you by.</span>")
@@ -98,10 +97,9 @@
duration = -1 //Will remove self when block breaks.
alert_type = /obj/screen/alert/status_effect/freon/stasis
var/obj/structure/ice_stasis/cube
var/datum/weakref/redirect_component
/datum/status_effect/frozenstasis/on_apply()
redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/breakCube))))
RegisterSignal(owner, COMSIG_LIVING_RESIST, .proc/breakCube)
cube = new /obj/structure/ice_stasis(get_turf(owner))
owner.forceMove(cube)
owner.status_flags |= GODMODE
@@ -118,8 +116,7 @@
if(cube)
qdel(cube)
owner.status_flags &= ~GODMODE
qdel(redirect_component.resolve())
redirect_component = null
UnregisterSignal(owner, COMSIG_LIVING_RESIST)
/datum/status_effect/slime_clone
id = "slime_cloned"
@@ -24,8 +24,6 @@
circuit = /obj/item/circuitboard/computer/xenobiology
var/datum/action/innate/hotkey_help/hotkey_help
var/datum/component/redirect/listener
var/obj/machinery/monkey_recycler/connected_recycler
var/list/stored_slimes
var/obj/item/slimepotion/slime/current_potion
@@ -41,7 +39,7 @@
. = ..()
hotkey_help = new
stored_slimes = list()
listener = AddComponent(/datum/component/redirect, list(COMSIG_ATOM_CONTENTS_DEL = CALLBACK(src, .proc/on_contents_del)))
RegisterSignal(src, COMSIG_ATOM_CONTENTS_DEL, .proc/on_contents_del)
for(var/obj/machinery/monkey_recycler/recycler in GLOB.monkey_recyclers)
if(get_area(src) == get_area(recycler))
connected_recycler = recycler
+10 -1
View File
@@ -254,7 +254,8 @@
var/static/regex/clap_words = regex("clap|applaud")
var/static/regex/honk_words = regex("ho+nk") //hooooooonk
var/static/regex/multispin_words = regex("like a record baby|right round")
var/static/regex/orgasm_words = regex("cum|orgasm|climax|squirt|heyo") //CITADEL CHANGE
var/static/regex/family_friendly_words = regex("family") //Hyper change
//var/static/regex/orgasm_words = regex("cum|orgasm|climax|squirt|heyo") //CITADEL CHANGE
var/static/regex/dab_words = regex("dab|mood") //CITADEL CHANGE
var/static/regex/snap_words = regex("snap") //CITADEL CHANGE
var/static/regex/bwoink_words = regex("what the fuck are you doing|bwoink|hey you got a moment?") //CITADEL CHANGE
@@ -572,6 +573,7 @@
var/mob/living/L = V
L.SpinAnimation(speed = 10, loops = 5)
/* Yeah nah fam.
//CITADEL CHANGES
//ORGASM
else if((findtext(message, orgasm_words)))
@@ -580,6 +582,13 @@
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
H.mob_climax(forced_climax=TRUE)
*/
else if((findtext(message, family_friendly_words)))
cooldown = COOLDOWN_MEME
for(var/V in listeners)
var/mob/living/M = V
M.say(pick("You don't turn your back on family.","...Even when they do."))
SEND_SOUND(M, sound('hyperstation/sound/misc/family.ogg',volume=75))
//DAB
else if((findtext(message, dab_words)))
+13 -13
View File
@@ -1,13 +1,13 @@
//include unit test files in this module in this ifdef
//Keep this sorted alphabetically
#ifdef UNIT_TESTS
#include "anchored_mobs.dm"
#include "component_tests.dm"
#include "reagent_id_typos.dm"
#include "reagent_recipe_collisions.dm"
#include "spawn_humans.dm"
#include "subsystem_init.dm"
#include "timer_sanity.dm"
#include "unit_test.dm"
#endif
//include unit test files in this module in this ifdef
//Keep this sorted alphabetically
#ifdef UNIT_TESTS
#include "anchored_mobs.dm"
#include "component_tests.dm"
#include "reagent_id_typos.dm"
#include "reagent_recipe_collisions.dm"
#include "spawn_humans.dm"
#include "subsystem_init.dm"
#include "timer_sanity.dm"
#include "unit_test.dm"
#endif
@@ -0,0 +1,12 @@
/datum/unit_test/component_duping/Run()
var/list/bad_dms = list()
var/list/bad_dts = list()
for(var/t in typesof(/datum/component))
var/datum/component/comp = t
if(!isnum(initial(comp.dupe_mode)))
bad_dms += t
var/dupe_type = initial(comp.dupe_type)
if(dupe_type && !ispath(dupe_type))
bad_dts += t
if(length(bad_dms) || length(bad_dts))
Fail("Components with invalid dupe modes: ([bad_dms.Join(",")]) ||| Components with invalid dupe types: ([bad_dts.Join(",")])")
@@ -1,7 +1,7 @@
GLOBAL_DATUM_INIT(lore_terminal_controller, /datum/lore_controller, new)
/obj/machinery/computer/lore_terminal
name = "Staff Seegson info-link terminal"
name = "Staff info-link terminal"
desc = "A small CRT display with an inbuilt microcomputer which is loaded with an extensive database. These terminals contain eveyrthing from information about historical events to instruction manuals for common ship appliances."
icon = 'nsv13/icons/obj/computers.dmi'
icon_state = "terminal"
@@ -9,16 +9,21 @@ GLOBAL_DATUM_INIT(lore_terminal_controller, /datum/lore_controller, new)
density = FALSE
anchored = TRUE
idle_power_usage = 15
var/access_tag = "ntcommon" //Every subtype of this type will be readable by this console. Use this for away terms as seen here \/
var/access_tag = "kncommon" //Every subtype of this type will be readable by this console. Use this for away terms as seen here \/
var/list/entries = list() //Every entry that we've got.
var/in_use = FALSE //Stops sound spam
var/datum/looping_sound/computer_click/soundloop
/obj/machinery/computer/lore_terminal/command //Put sensitive information on this one
name = "Command Seegson info-link terminal"
access_tag = "ntcommand"
name = "Command info-link terminal"
access_tag = "kncommand"
req_access = list(ACCESS_HEADS)
/obj/machinery/computer/lore_terminal/security
name = "Security info-link terminal"
access_tag = "knsecurity"
req_access = list(ACCESS_SECURITY)
/obj/machinery/computer/lore_terminal/awaymission //Example for having a terminal preloaded with only a set list of files.
access_tag = "awaymission_default"
@@ -201,12 +206,12 @@ SPECIAL KEYS RESPOND AS FOLLOWS:
name = "new_employees_memo.mail"
title = "Intercepted message"
path = "lore_entries/welcome.txt"
access_tag = "ntcommon"
access_tag = "kncommon"
/datum/lore_entry/all
name = "nuclear_authdisk_instructions.mail"
title = "Handling the Nuclear Authentication Disk and You!"
content = "SYSADMIN -> allcrew@seegnet.kin. RE: The Nuclear Authentication Disk. ` Greetings staff members! We're aware of the questions you have in regards to the Nuclear Authentication disk. The disk itself contains the codes needed to unlock nuclear devices used in a Nuclear Emergency and trigger a station self-destruction sequence. ` It is the duty of every member of this crew to take responsibility for the disk in the off chance that station command is currently absent. ` Don't leave it lying in the Captain's office. ` Keep it in movement to prevent Syndicate triangulation devices from functioning. ` If the disk location is unknown, look for a red pinpointer, the Head of Security and the Captain should always have one in their offices or lockers. These will help you locate the disk. ` If the disk is in enemy hands, call all hands on deck immediately and order a red alert. ` ` Protect the disk with your life, for the lives of the station's crew depend on it. Stay safe through vigilance."
content = "SYSADMIN -> allcrew@seegnet.kin. RE: The Nuclear Authentication Disk. ` Greetings staff members! We're aware of the questions you have in regards to the Nuclear Authentication disk. The disk itself contains the codes needed to unlock nuclear devices used in a Nuclear Emergency and trigger a station self-destruction sequence. ` It is the duty of every member of this crew to take responsibility for the disk in the off chance that station command is currently absent. ` Even though Layenia itself is a mobile facility and prevents Disk Triangulation in most circumstances, it is still important to hold onto the disk even when not needed- it is a good formality and keeps things secure! ` If the disk location is unknown, look for a red pinpointer, the Head of Security and the Captain should always have one in their offices or lockers. These will help you locate the disk. ` If the disk is in enemy hands, call all hands on deck immediately and order a red alert. ` ` Protect the disk with your life, for the lives of the station's crew depend on it. Stay safe through vigilance."
access_tag = "all"
/datum/lore_entry/all/meltdown_proceedures
@@ -217,7 +222,7 @@ SPECIAL KEYS RESPOND AS FOLLOWS:
/datum/lore_entry/command
name = "command_memo.mail"
title = "Intercepted Message"
access_tag = "ntcommand"
access_tag = "kncommand"
classified = "Restricted"
content = "SYSADMIN -> command@seegnet.kin. RE: Orientation. ` Greetings station command staff, congratulations on your placement! It is now company policy to attend all briefings as issued by centcom staff. Please speak to your centcom officer for clarification on the new procedures."
@@ -238,3 +243,54 @@ SPECIAL KEYS RESPOND AS FOLLOWS:
/datum/lore_entry/away_example/weapons_log
name = "weapon_systems_dump2259/11/25.txt"
content = "Life support systems terminated. Railgun system status: A6E3. Torpedo system status: ~@##6#6#^^6 -=File Access Terminated=-"
/datum/lore_entry/security
name = "usage_and_terms.memo"
title = "Usage and Terms"
access_tag = "knsecurity"
path = "lore_entries/security/usageandterms.txt"
/datum/lore_entry/security/introduction
name = "introduction.memo"
title = "Security Introduction"
path = "lore_entries/security/introduction.txt"
/datum/lore_entry/security/basicgearandyou
name = "gearbasics.memo"
title = "Basic Gear and You"
path = "lore_entries/security/basicgearandyou.txt"
/datum/lore_entry/security/advancedgearandyou
name = "gearadvanced.memo"
title = "Advanced Gear and You"
path = "lore_entries/security/advancedgearandyou.txt"
/datum/lore_entry/security/defensivegearandyou
name = "geardefensive.memo"
title = "Defensive Gear and You"
path = "lore_entries/security/defensivegearandyou.txt"
/datum/lore_entry/security/sop
name = "standard_operating_procedure.txt"
title = "Standard Operating Procedure"
path = "lore_entries/security/wip.txt"
/datum/lore_entry/security/lowcrime
name = "low_infractions.txt"
title = "Minor Infractions"
path = "lore_entries/security/wip.txt"
/datum/lore_entry/security/mediumcrime
name = "medium_infractions.txt"
title = "Medium-risk Infractions"
path = "lore_entries/security/wip.txt"
/datum/lore_entry/security/highcrime
name = "high_infractions.txt"
title = "Dangerous Infractions"
path = "lore_entries/security/wip.txt"
/datum/lore_entry/security/deltacrime
name = "delta_infractions.txt"
title = "Zealot-class Notice and Warning"
path = "lore_entries/security/wip.txt"
@@ -0,0 +1,120 @@
#define SAUNA_H2O_TEMP T20C + 20
#define SAUNA_LOG_FUEL 150
#define SAUNA_PAPER_FUEL 5
#define SAUNA_MAXIMUM_FUEL 3000
#define SAUNA_WATER_PER_WATER_UNIT 5
/obj/structure/sauna_oven
name = "sauna oven"
desc = "A modest sauna oven with rocks. Add some fuel, pour some water and enjoy the moment."
icon = 'hyperstation/icons/obj/structures/sauna_oven.dmi'
icon_state = "sauna_oven"
density = TRUE
anchored = TRUE
resistance_flags = FIRE_PROOF
var/lit = FALSE
var/fuel_amount = 0
var/water_amount = 0
/obj/structure/sauna_oven/examine(mob/user)
. = ..()
. += "<span class='notice'>The rocks are [water_amount ? "moist" : "dry"].</span>"
. += "<span class='notice'>There's [fuel_amount ? "some fuel" : "no fuel"] in the oven.</span>"
/obj/structure/sauna_oven/Destroy()
if(lit)
STOP_PROCESSING(SSobj, src)
return ..()
/obj/structure/sauna_oven/attack_hand(mob/user)
. = ..()
if(.)
return
if(lit)
lit = FALSE
STOP_PROCESSING(SSobj, src)
user.visible_message("<span class='notice'>[user] turns on [src].</span>", "<span class='notice'>You turn on [src].</span>")
else if (fuel_amount)
lit = TRUE
START_PROCESSING(SSobj, src)
user.visible_message("<span class='notice'>[user] turns off [src].</span>", "<span class='notice'>You turn off [src].</span>")
update_icon()
/obj/structure/sauna_oven/update_overlays()
. = ..()
if(lit)
. += "sauna_oven_on_overlay"
/obj/structure/sauna_oven/update_icon()
..()
icon_state = "[lit ? "sauna_oven_on" : initial(icon_state)]"
/obj/structure/sauna_oven/attackby(obj/item/T, mob/user)
if(T.tool_behaviour == TOOL_WRENCH)
to_chat(user, "<span class='notice'>You begin to deconstruct [src].</span>")
if(T.use_tool(src, user, 60, volume=50))
to_chat(user, "<span class='notice'>You successfully deconstructed [src].</span>")
new /obj/item/stack/sheet/mineral/wood(get_turf(src), 30)
qdel(src)
return TRUE
else if(istype(T, /obj/item/reagent_containers))
var/obj/item/reagent_containers/reagent_container = T
if(!reagent_container.is_open_container())
return ..()
if(reagent_container.reagents.has_reagent(/datum/reagent/water))
reagent_container.reagents.remove_reagent(/datum/reagent/water, 5)
user.visible_message("<span class='notice'>[user] pours some \
water into [src].</span>", "<span class='notice'>You pour \
some water to [src].</span>")
water_amount += 5 * SAUNA_WATER_PER_WATER_UNIT
return TRUE
else
to_chat(user, "<span class='warning'>There's no water in [reagent_container]</span>")
return FALSE
else if(istype(T, /obj/item/stack/sheet/mineral/wood))
var/obj/item/stack/sheet/mineral/wood/wood = T
if(fuel_amount > SAUNA_MAXIMUM_FUEL)
to_chat(user, "<span class='warning'>You can't fit any more of [T] in [src]!</span>")
return FALSE
fuel_amount += SAUNA_LOG_FUEL * wood.amount
wood.use(wood.amount)
user.visible_message("<span class='notice'>[user] tosses some \
wood into [src].</span>", "<span class='notice'>You add \
some fuel to [src].</span>")
return TRUE
else if(istype(T, /obj/item/paper_bin))
var/obj/item/paper_bin/paper_bin = T
user.visible_message("<span class='notice'>[user] throws [T] into \
[src].</span>", "<span class='notice'>You add [T] to [src].\
</span>")
fuel_amount += SAUNA_PAPER_FUEL * paper_bin.total_paper
qdel(paper_bin)
return TRUE
else if(istype(T, /obj/item/paper))
user.visible_message("<span class='notice'>[user] throws [T] into \
[src].</span>", "<span class='notice'>You throw [T] into [src].\
</span>")
fuel_amount += SAUNA_PAPER_FUEL
qdel(T)
return TRUE
return ..()
/obj/structure/sauna_oven/process()
if(water_amount)
water_amount--
var/turf/pos = get_turf(src)
if(pos)
pos.atmos_spawn_air("water_vapor=10;TEMP=[SAUNA_H2O_TEMP]")
fuel_amount--
if(fuel_amount <= 0)
lit = FALSE
STOP_PROCESSING(SSobj, src)
update_icon()
#undef SAUNA_H2O_TEMP
#undef SAUNA_LOG_FUEL
#undef SAUNA_PAPER_FUEL
#undef SAUNA_MAXIMUM_FUEL
#undef SAUNA_WATER_PER_WATER_UNIT
+42 -21
View File
@@ -35,7 +35,7 @@ Icons, maybe?
/datum/status_effect/leash_pet
id = "leashed"
status_type = STATUS_EFFECT_UNIQUE
var/datum/weakref/redirect_component
var/mob/redirect_component
alert_type = /obj/screen/alert/status_effect/leash_pet
/obj/screen/alert/status_effect/leash_pet
@@ -45,7 +45,9 @@ Icons, maybe?
/datum/status_effect/leash_pet/on_apply()
redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/owner_resist))))
//redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/owner_resist))))
RegisterSignal(owner, COMSIG_LIVING_RESIST, .proc/owner_resist)
redirect_component = owner
if(!owner.stat)
to_chat(owner, "<span class='userdanger'>You have been leashed!</span>")
return ..()
@@ -80,9 +82,9 @@ Icons, maybe?
var/leash_used = 0 //A flag to see if the leash has been used yet, because for some reason picking up an unused leash is weird
var/mob/living/leash_pet = "null" //Variable to store our pet later
var/mob/living/leash_master = "null" //And our master too
var/datum/component/mobhook_leash_pet
var/datum/component/mobhook_leash_master //Needed to watch for these entities to move
var/datum/component/mobhook_leash_freepet
var/mob/mobhook_leash_pet
var/mob/mobhook_leash_master //Needed to watch for these entities to move
var/mob/mobhook_leash_freepet
var/leash_location[3] //Three digit list for us to store coordinates later
//Called when someone is clicked with the leash
@@ -101,8 +103,12 @@ Icons, maybe?
user.apply_status_effect(/datum/status_effect/leash_dom) //Is the leasher
leash_pet = C //Save pet reference for later
leash_master = user //Save dom reference for later
mobhook_leash_pet = leash_pet.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_pet_move)))
mobhook_leash_master = leash_master.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_master_move)))
//mobhook_leash_pet = leash_pet.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_pet_move)))
RegisterSignal(leash_pet, COMSIG_MOVABLE_MOVED, .proc/on_pet_move)
mobhook_leash_pet = leash_pet
//mobhook_leash_master = leash_master.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_master_move)))
RegisterSignal(leash_master, COMSIG_MOVABLE_MOVED, .proc/on_master_move)
mobhook_leash_master = leash_master
leash_used = 1
if(!leash_pet.has_status_effect(/datum/status_effect/leash_dom)) //Add slowdown if the pet didn't leash themselves
leash_pet.add_movespeed_modifier(MOVESPEED_ID_LEASH, multiplicative_slowdown = 5)
@@ -126,9 +132,12 @@ Icons, maybe?
leash_pet.remove_status_effect(/datum/status_effect/leash_pet)
if(!leash_pet.has_status_effect(/datum/status_effect/leash_pet)) //If there is no pet, there is no dom. Loop breaks.
QDEL_NULL(mobhook_leash_master)
QDEL_NULL(mobhook_leash_pet)
QDEL_NULL(mobhook_leash_freepet)
//QDEL_NULL(mobhook_leash_master)
UnregisterSignal(mobhook_leash_master, COMSIG_MOVABLE_MOVED)
//QDEL_NULL(mobhook_leash_pet)
UnregisterSignal(mobhook_leash_pet, COMSIG_MOVABLE_MOVED)
//QDEL_NULL(mobhook_leash_freepet)
UnregisterSignal(mobhook_leash_freepet, COMSIG_MOVABLE_MOVED)
if(leash_pet.has_status_effect(/datum/status_effect/leash_freepet))
leash_pet.remove_status_effect(/datum/status_effect/leash_freepet)
if(leash_pet.has_movespeed_modifier(MOVESPEED_ID_LEASH))
@@ -183,7 +192,8 @@ Icons, maybe?
if(leash_pet == leash_master) //Pet is the master
return
if(!leash_pet.has_status_effect(/datum/status_effect/leash_pet))
QDEL_NULL(mobhook_leash_master) //Probably redundant, but it's nice to be safe
//QDEL_NULL(mobhook_leash_master) //Probably redundant, but it's nice to be safe
UnregisterSignal(mobhook_leash_master, COMSIG_MOVABLE_MOVED)
leash_master.remove_status_effect(/datum/status_effect/leash_dom)
return
@@ -252,8 +262,10 @@ Icons, maybe?
leash_pet.remove_status_effect(/datum/status_effect/leash_pet)
leash_pet.remove_movespeed_modifier(MOVESPEED_ID_LEASH)
leash_master.remove_status_effect(/datum/status_effect/leash_dom)
QDEL_NULL(mobhook_leash_master)
QDEL_NULL(mobhook_leash_pet)
//QDEL_NULL(mobhook_leash_master)
UnregisterSignal(mobhook_leash_master, COMSIG_MOVABLE_MOVED)
//QDEL_NULL(mobhook_leash_pet)
UnregisterSignal(mobhook_leash_pet, COMSIG_MOVABLE_MOVED)
leash_pet = "null"
leash_master = "null"
leash_used = 0
@@ -267,7 +279,8 @@ Icons, maybe?
return
//Make sure the pet is still a pet
if(!leash_pet.has_status_effect(/datum/status_effect/leash_pet))
QDEL_NULL(mobhook_leash_pet) //Probably redundant, but it's nice to be safe
//QDEL_NULL(mobhook_leash_pet) //Probably redundant, but it's nice to be safe
UnregisterSignal(mobhook_leash_pet, COMSIG_MOVABLE_MOVED)
return
//The pet has escaped. There is no DOM. GO PET RUN.
@@ -356,8 +369,10 @@ Icons, maybe?
leash_pet.adjustOxyLoss(5)
leash_pet.remove_status_effect(/datum/status_effect/leash_pet)
leash_pet.remove_status_effect(/datum/status_effect/leash_freepet)
QDEL_NULL(mobhook_leash_pet)
QDEL_NULL(mobhook_leash_freepet)
//QDEL_NULL(mobhook_leash_pet)
UnregisterSignal(mobhook_leash_pet, COMSIG_MOVABLE_MOVED)
//QDEL_NULL(mobhook_leash_freepet)
UnregisterSignal(mobhook_leash_freepet, COMSIG_MOVABLE_MOVED)
leash_pet = "null"
leash_used = 0
@@ -375,10 +390,13 @@ Icons, maybe?
viewing.show_message("<span class='notice'>[leash_master] has dropped the leash.</span>", 1)
//DOM HAS DROPPED LEASH. PET IS FREE. SCP HAS BREACHED CONTAINMENT.
leash_pet.remove_movespeed_modifier(MOVESPEED_ID_LEASH)
mobhook_leash_freepet = leash_pet.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_freepet_move)))
//mobhook_leash_freepet = leash_pet.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_freepet_move)))
RegisterSignal(leash_pet, COMSIG_MOVABLE_MOVED, .proc/on_freepet_move)
mobhook_leash_freepet = leash_pet
leash_master.remove_status_effect(/datum/status_effect/leash_dom) //No dom with no leash. We will get a new dom if the leash is picked back up.
leash_master = "null"
QDEL_NULL(mobhook_leash_master)
//QDEL_NULL(mobhook_leash_master)
UnregisterSignal(mobhook_leash_master, COMSIG_MOVABLE_MOVED)
/obj/item/leash/equipped(mob/user)
. = ..()
@@ -392,9 +410,12 @@ Icons, maybe?
leash_master = "null"
return
leash_master.apply_status_effect(/datum/status_effect/leash_dom)
mobhook_leash_master = leash_master.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_master_move)))
//mobhook_leash_master = leash_master.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_master_move)))
RegisterSignal(leash_master, COMSIG_MOVABLE_MOVED, .proc/on_master_move)
mobhook_leash_master = leash_master
leash_pet.remove_status_effect(/datum/status_effect/leash_freepet)
QDEL_NULL(mobhook_leash_freepet)
//QDEL_NULL(mobhook_leash_freepet)
UnregisterSignal(mobhook_leash_freepet, COMSIG_MOVABLE_MOVED)
leash_pet.add_movespeed_modifier(MOVESPEED_ID_LEASH, multiplicative_slowdown = 5)
/datum/crafting_recipe/leash
@@ -403,4 +424,4 @@ Icons, maybe?
time = 40
reqs = list(/obj/item/stack/sheet/metal = 1,
/obj/item/stack/sheet/cloth = 3)
category = CAT_MISC
category = CAT_MISC
Binary file not shown.

After

Width:  |  Height:  |  Size: 902 B

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

@@ -0,0 +1 @@
SYSADMIN -> security@frontier.infolink.kin. Advanced Gear and You ` When threats start to intensify, standard gear may not work. As Layenia station is a recycled facility from NT subsystems, you don't have access to Holostasis Projectors and Blaze Javelins- however, there should be some noteworthy items in the armory should the threat level support it. ` ` DRAGnet ` A strong, versatile tool which is capable of teleporting those left within it's field once the charge is complete. This mode is semi-useless, however, it has an alternative fire which shoots an energy snare and trap. If it directly hits someone, it knocks them down and ties their legs together, making movement difficult. If it misses, it will deploy a trap on the ground that will snare anyone who steps on it, even yourself. Caution advised; please remember that this item may not work on animals and silicons. ` ` Blaster carbine ` An outdated and unreliable laser weapon to the likes of Kinaris's own, however it serves it's own purpose in light engagements. It's main firing mode is a disabler bolt of energy that is capable of slowly draining the stamina of a target. The alternate fire mode heats up the lasers intensely, causing them to be that much more lethal and burning. Avoid using this mode when unnecessary. Needs to be recharged after energy capacity is lost. ` ` Blaster rifle ` Similar to the carbine, this is a very old model of laser weaponry. However, it lacks a nonlethal option and has only one lethal firing mode. Because of this, it has a higher energy capacity and damage rate. Needs to be recharged after energy capacity is lost. ` ` Riot shotgun ` A pump-action shotgun that is not automatic. Load a round in, rack the shotgun, turn off the safety, and fire. Ammo types can be nonlethal beanbag slugs, which still do a slight amount of bruising, but aim to disable effectively with sheer stopping power compared to it's lethal counterpart. This weapon has a maximum ammo capacity of 6 at a time. Not to be confused with automatic combat shotguns, which don't need to be racked after it's been fired. ` ` Riot armor and shields ` A very bulky suit that is capable of stopping most blunt force in it's tracks. Best used with a shield, but it overall slows the wearer down. Not very worth it; you'd be better off trying not to tank damage. ` ` Reflector vest ` A worn vest with a toggle that is capable of reflecting energy projectiles from once they came. Ensure that the toggle is turned on, and the vest is applied properly. This will not protect against ballistics and melee. ` ` Ion rifle ` A bulky weapon that is capable of shooting ionized energy blasts that can disrupt mechanical subsystems and disable them in an area of effect. This is especially effective against cyborgs and mechs, as well as an augmented crew member. Otherwise, this may cause a lot of damage to the station itself. ` ` Security temperature gun ` A single-fire weapon that can blast either freezing-cold or blazing-hot waves of energy onto a target. This is especially effective against animals that struggle against extreme temperatures, such as using the cold mode on a slime. Be wary that it is lethal.
@@ -0,0 +1 @@
SYSADMIN -> security@frontier.infolink.kin. Basic Gear and You ` Not only must an SSP know what mindset to be in, they must also recognize the effects of their gear and items, as well as when they're needed. This section will cover some items, and how they can be useful given certain circumstances. Note that Layenia Station is using much older, and has access to less state-of-the-art technology, as it is using recycled Nanotrasen subsystems. ` ` Handcuffs ` A tool utilized for restraining criminals on the wrists. Apply on both wrists, fasten and lock. These should only be used when transporting prisoners, NOT when they're in a cell. Can only be applied on creatures with applicable limbs. ` ` Flash ` A device with a bright bulb, used to temporarily disorient visuals, both on cyborgs and living creatures. While harmless, extended use may result in eye damage. Using in hand will result in an area of flash, while using against another will flash that specific being. Useless against anything with flash protection ` ` Pepperspray ` A small nozzle used to spray irritant chemicals, most effective when used on the eyes of a living being who is not wearing eye protection. Otherwise, this item services as nothing more than an irritating spray. Can be refilled. ` ` Stunbaton ` An electrically charged rod with a prod on the end, which can be activated to deal incredible amounts of stamina drain. This is your primary melee-ranged tool, which should be applied to criminals approximately four times (size may vary, or until target is exhausted) followed up by handcuffing. Do not hit harmfully with this without just cause; requires a recharge after frequent use, and can be upgraded with better power cells. ` ` Flashbang ` A chemical payload that will prime upon activation, and will explode into a disorienting blast after a few seconds. Requires flash and ear protection to completely nullify it's effects, but being too close can override that. This is a prime tool for crowd control, and should only be used when it's absolutely necessary. Effective for dispersing crowds. ` ` Taser ` A handheld sidearm that is capable of launching an electric volt of energy which can temporarily stun and disarm most attackers via electric shock to the muscles. It can have it's firing mode switched to a disabler mode, which is capable of draining the stamina of the target, without the stun. Use only on creatures that aren't immune.
@@ -0,0 +1 @@
SYSADMIN - > security@frontier.infolink.kin Defensive Gear and You ` Sometimes, situations may call for a more defensive approach, especially when asset protection is kept in-mind. Layenia has access to some light defensive armaments within the station; it is not equipped with defensive battery cannons on the exterior. ` ` Barrier grenade ` These grenades are capable of deploying a barrier on it's location after explosion. The barrier itself cannot be clambered over, and can take quite a beating before it goes down. Effective for narrowing passageways. ` ` Portable flasher ` A bulky unit which can be bolted to the floor with a wrench, and will flash any fast-moving personnel within it's radius. Will not flash if people are walking by it. ` ` Security holobarrier projector ` A handheld device which can project a hardlight barrier- three total- at a location of choosing. It can be dispelled easily with the same device as well.
+1
View File
@@ -0,0 +1 @@
SYSADMIN -> security@frontier.infolink.kin. Introduction ` The act of securing and protection any Kinaris asset is not an easy one. Difficulty can range from monotanous and dreary, to outright hellish and overwhelming. It is a SSP's job to ensure that regardless of circumstance, they are both mentally and physically equipped to deal with any situation that may come up. This section will cover the very basics of what you need to know to be educated in the instance of standard security work. ` To act as a SSP, the first step would be to think like one. Sentient Security Personnel are equipped with a plethora of both resources and gear to apprehend criminals, as well an array of support from the station and heads alike. Do not betray your station's trust. Your job as an SSP should be- above all- securing peace. Before anything, you should always consider the outcome of your actions, and others' as well. A responsible SSP would understand when a good time to use a baton is, and when words will allow a better outcome. Lack of this proper resolve may result in uneasiness around your workplace, both from your team and those you are to protect. This is not only grounds for demotion when abuse is repeated, but may result in an abusive SSP's inevitable lynching. These effects can snowball into much worse; so ensure that you and your team are well-communicative, and are proper in terms of gear use and protocol. Catch problems at the source. Think like a proper SSP. ` Following up a proper mindset, it is important to note the infinite complexity that situations may involve themselves in. A responsible SSP will always keep in mind truths and lies when proposed with a situation, and must acknowledge that their guess can be wrong as well. Following Kinaris Security Protocol to the letter may also be problematic, due to the malleable nature that people can involve themselves within. Leeway is important to give when necessary, and a firm hand provided otherwise. Know when to apply proper protocol, and when to give leeway.
+1
View File
@@ -0,0 +1 @@
SYSADMIN -> security@frontier.infolink.kin. Usage and Terms ` This specific protocol terminal refers to the processes and operation of Sentient Security Personnel (SSP) in regards to their workplace and behavior within reasonable operating conditions. The usage of this terminal is for both educational and referral purposes. Punishments given out by SSP should be based upon the data within this terminal. Note that these should be a baseline, and following to the letter may or may not be preffered. Case-by-case basis analysis is encouraged.
+1
View File
@@ -0,0 +1 @@
SYSADMIN -> security@frontier.infolink.kin. Unauthorized Access ` File is currently undergoing approval via your local Central Command authority. Please seek previous methods for this specific file.
@@ -1,49 +0,0 @@
//This component applies a customizable drop_shadow filter to its wearer when they toggle combat mode on or off. This can stack.
/datum/component/phantomthief
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
var/filter_x
var/filter_y
var/filter_size
var/filter_border
var/filter_color
var/datum/component/redirect/combattoggle_redir
/datum/component/phantomthief/Initialize(_x = -2, _y = 0, _size = 0, _border = 0, _color = "#E62111")
filter_x = _x
filter_y = _y
filter_size = _size
filter_border = _border
filter_color = _color
RegisterSignal(parent, COMSIG_COMBAT_TOGGLED, .proc/handlefilterstuff)
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/OnEquipped)
RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/OnDropped)
/datum/component/phantomthief/proc/handlefilterstuff(mob/user, combatmodestate)
if(istype(user))
var/thefilter = filter(type = "drop_shadow", x = filter_x, y = filter_y, size = filter_size, border = filter_border, color = filter_color)
if(!combatmodestate)
user.filters -= thefilter
else
user.filters += thefilter
/datum/component/phantomthief/proc/stripdesiredfilter(mob/user)
if(istype(user))
var/thefilter = filter(type = "drop_shadow", x = filter_x, y = filter_y, size = filter_size, border = filter_border, color = filter_color)
user.filters -= thefilter
/datum/component/phantomthief/proc/OnEquipped(mob/user, slot)
if(!istype(user))
return
if(!combattoggle_redir)
combattoggle_redir = user.AddComponent(/datum/component/redirect, list(COMSIG_COMBAT_TOGGLED = CALLBACK(src, .proc/handlefilterstuff)))
/datum/component/phantomthief/proc/OnDropped(mob/user)
if(!istype(user))
return
if(combattoggle_redir)
QDEL_NULL(combattoggle_redir)
stripdesiredfilter(user)
@@ -201,7 +201,6 @@
var/enthrallGender //Use master or mistress
var/mental_capacity //Higher it is, lower the cooldown on commands, capacity reduces with resistance.
var/datum/weakref/redirect_component //resistance
var/distancelist = list(2,1.5,1,0.8,0.6,0.5,0.4,0.3,0.2) //Distance multipliers
@@ -231,7 +230,7 @@
master = get_mob_by_key(enthrallID)
//if(M.ckey == enthrallID)
// owner.remove_status_effect(src)//At the moment, a user can enthrall themselves, toggle this back in if that should be removed.
redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/owner_resist)))) //Do resistance calc if resist is pressed#
RegisterSignal(owner, COMSIG_LIVING_RESIST, .proc/owner_resist) //Do resistance calc if resist is pressed#
RegisterSignal(owner, COMSIG_MOVABLE_HEAR, .proc/owner_hear)
//var/obj/item/organ/brain/B = M.getorganslot(ORGAN_SLOT_BRAIN) //removing this, may cause some issues unsure.
mental_capacity = 500 - M.getOrganLoss(ORGAN_SLOT_BRAIN)//It's their brain!
@@ -570,8 +569,7 @@
SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing2")
SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing3")
SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing4")
qdel(redirect_component.resolve())
redirect_component = null
UnregisterSignal(M, COMSIG_LIVING_RESIST)
UnregisterSignal(owner, COMSIG_MOVABLE_HEAR)
REMOVE_TRAIT(owner, TRAIT_PACIFISM, "MKUltra")
to_chat(owner, "<span class='big redtext'><i>You're now free of [master]'s influence, and fully independent!'</i></span>")
@@ -6,19 +6,18 @@
icon_state = "s-ninja"
item_state = "s-ninja"
/obj/item/clothing/glasses/phantomthief/Initialize()
/obj/item/clothing/glasses/phantomthief/ComponentInitialize()
. = ..()
AddComponent(/datum/component/phantomthief)
AddComponent(/datum/component/wearertargeting/phantomthief)
/obj/item/clothing/glasses/phantomthief/syndicate
name = "suspicious plastic mask"
desc = "A cheap, bulky, Syndicate-branded plastic face mask. You have to break in to break out."
var/nextadrenalinepop
var/datum/component/redirect/combattoggle_redir
/obj/item/clothing/glasses/phantomthief/syndicate/examine(user)
/obj/item/clothing/glasses/phantomthief/syndicate/examine(mob/user)
. = ..()
if(combattoggle_redir)
if(user.get_item_by_slot(SLOT_GLASSES) == src)
if(world.time >= nextadrenalinepop)
. += "<span class='notice'>The built-in adrenaline injector is ready for use.</span>"
else
@@ -34,12 +33,12 @@
. = ..()
if(!istype(user))
return
if(!combattoggle_redir)
combattoggle_redir = user.AddComponent(/datum/component/redirect, list(COMSIG_COMBAT_TOGGLED = CALLBACK(src, .proc/injectadrenaline)))
if(slot != SLOT_GLASSES)
return
RegisterSignal(user, COMSIG_COMBAT_TOGGLED, .proc/injectadrenaline)
/obj/item/clothing/glasses/phantomthief/syndicate/dropped(mob/user)
. = ..()
if(!istype(user))
return
if(combattoggle_redir)
QDEL_NULL(combattoggle_redir)
UnregisterSignal(user, COMSIG_COMBAT_TOGGLED)
+3 -3
View File
@@ -380,12 +380,12 @@
#include "code\datums\components\ntnet_interface.dm"
#include "code\datums\components\orbiter.dm"
#include "code\datums\components\paintable.dm"
#include "code\datums\components\phantomthief.dm"
#include "code\datums\components\rad_insulation.dm"
#include "code\datums\components\radioactive.dm"
#include "code\datums\components\remote_materials.dm"
#include "code\datums\components\riding.dm"
#include "code\datums\components\rotation.dm"
#include "code\datums\components\signal_redirect.dm"
#include "code\datums\components\sizzle.dm"
#include "code\datums\components\slippery.dm"
#include "code\datums\components\spawner.dm"
@@ -3071,6 +3071,7 @@
#include "hyperstation\code\game\objects\items\cosmetics.dm"
#include "hyperstation\code\game\objects\items\storage\big_bag.dm"
#include "hyperstation\code\game\objects\structures\ghost_role_spawners.dm"
#include "hyperstation\code\game\objects\structures\sauna_oven.dm"
#include "hyperstation\code\gamemode\traitor_lewd.dm"
#include "hyperstation\code\gamemode\traitor_thief.dm"
#include "hyperstation\code\gamemode\werewolf\werewolf.dm"
@@ -3124,8 +3125,8 @@
#include "hyperstation\code\modules\power\reactor\rbmk.dm"
#include "hyperstation\code\modules\power\reactor\reactor_cargo.dm"
#include "hyperstation\code\modules\reagents\chemistry\reagents\food_reagents.dm"
#include "hyperstation\code\modules\reagents\chemistry\reagents\medicine_reagents.dm"
#include "hyperstation\code\modules\reagents\chemistry\reagents\hydroponics_reactions.dm"
#include "hyperstation\code\modules\reagents\chemistry\reagents\medicine_reagents.dm"
#include "hyperstation\code\modules\reagents\chemistry\recipes\medicine.dm"
#include "hyperstation\code\modules\resize\resize_action.dm"
#include "hyperstation\code\modules\resize\resizing.dm"
@@ -3169,7 +3170,6 @@
#include "modular_citadel\code\controllers\configuration\entries\general.dm"
#include "modular_citadel\code\controllers\subsystem\job.dm"
#include "modular_citadel\code\datums\components\material_container.dm"
#include "modular_citadel\code\datums\components\phantomthief.dm"
#include "modular_citadel\code\datums\components\souldeath.dm"
#include "modular_citadel\code\datums\mood_events\chem_events.dm"
#include "modular_citadel\code\datums\mood_events\generic_negative_events.dm"