diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 61a8a9c5c2..6986135058 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -62631,18 +62631,16 @@
/turf/open/floor/plating,
/area/science/mixing)
"czs" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
/obj/effect/turf_decal/stripes/line{
dir = 8
},
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 10
+ },
/turf/open/floor/plasteel/white,
/area/science/mixing)
"czt" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
+/obj/machinery/atmospherics/components/unary/vent_pump/on,
/turf/open/floor/plasteel/white,
/area/science/mixing)
"czu" = (
@@ -63208,23 +63206,24 @@
/obj/effect/turf_decal/stripes/line{
dir = 8
},
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 5
+ },
/turf/open/floor/plasteel/white,
/area/science/mixing)
"cAy" = (
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
- dir = 4
- },
/obj/structure/cable/yellow{
icon_state = "4-8"
},
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
/turf/open/floor/plasteel/white,
/area/science/mixing)
"cAz" = (
/obj/structure/cable/yellow{
icon_state = "4-8"
},
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
- dir = 2
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
},
/turf/open/floor/plasteel/white,
/area/science/mixing)
@@ -80364,13 +80363,13 @@
/turf/open/floor/circuit,
/area/science/robotics/mechbay)
"dDA" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
/obj/structure/cable/yellow{
icon_state = "4-8"
},
/obj/effect/landmark/event_spawn,
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
/turf/open/floor/plasteel/white,
/area/science/mixing)
"dDB" = (
@@ -112665,7 +112664,7 @@ cvS
cwR
crQ
cyB
-czu
+czy
cAz
cBt
cCu
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index f86277e5c3..addeca8739 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -4,7 +4,14 @@
#define islist(L) (istype(L, /list))
+#if DM_VERSION >= 512
+#define in_range(source, user) (get_dist(source, user) <= 1 && (get_step(source, 0)?:z) == (get_step(user, 0)?:z))
+#if DM_VERSION > 512
+#warn Remove this check.
+#endif
+#else
#define in_range(source, user) (get_dist(source, user) <= 1)
+#endif
#define ismovableatom(A) (istype(A, /atom/movable))
diff --git a/code/_onclick/adjacent.dm b/code/_onclick/adjacent.dm
index b831a8cbcb..ddff0b6bd3 100644
--- a/code/_onclick/adjacent.dm
+++ b/code/_onclick/adjacent.dm
@@ -1,104 +1,104 @@
-/*
- Adjacency proc for determining touch range
-
- This is mostly to determine if a user can enter a square for the purposes of touching something.
- Examples include reaching a square diagonally or reaching something on the other side of a glass window.
-
- This is calculated by looking for border items, or in the case of clicking diagonally from yourself, dense items.
- This proc will NOT notice if you are trying to attack a window on the other side of a dense object in its turf. There is a window helper for that.
-
- Note that in all cases the neighbor is handled simply; this is usually the user's mob, in which case it is up to you
- to check that the mob is not inside of something
-*/
-/atom/proc/Adjacent(atom/neighbor) // basic inheritance, unused
- return 0
-
-// Not a sane use of the function and (for now) indicative of an error elsewhere
-/area/Adjacent(var/atom/neighbor)
- CRASH("Call to /area/Adjacent(), unimplemented proc")
-
-
-/*
- Adjacency (to turf):
- * If you are in the same turf, always true
- * If you are vertically/horizontally adjacent, ensure there are no border objects
- * If you are diagonally adjacent, ensure you can pass through at least one of the mutually adjacent square.
- * Passing through in this case ignores anything with the LETPASSTHROW pass flag, such as tables, racks, and morgue trays.
-*/
-/turf/Adjacent(atom/neighbor, atom/target = null, atom/movable/mover = null)
- var/turf/T0 = get_turf(neighbor)
-
- if(T0 == src) //same turf
- return 1
-
- if(get_dist(src,T0) > 1) //too far
- return 0
-
- // Non diagonal case
- if(T0.x == x || T0.y == y)
- // Check for border blockages
- return T0.ClickCross(get_dir(T0,src), border_only = 1, target_atom = target, mover = mover) && src.ClickCross(get_dir(src,T0), border_only = 1, target_atom = target, mover = mover)
-
- // Diagonal case
- var/in_dir = get_dir(T0,src) // eg. northwest (1+8) = 9 (00001001)
- var/d1 = in_dir&3 // eg. north (1+8)&3 (0000 0011) = 1 (0000 0001)
- var/d2 = in_dir&12 // eg. west (1+8)&12 (0000 1100) = 8 (0000 1000)
-
- for(var/d in list(d1,d2))
- if(!T0.ClickCross(d, border_only = 1, target_atom = target, mover = mover))
- continue // could not leave T0 in that direction
-
- var/turf/T1 = get_step(T0,d)
- if(!T1 || T1.density)
- continue
- if(!T1.ClickCross(get_dir(T1,src), border_only = 0, target_atom = target, mover = mover) || !T1.ClickCross(get_dir(T1,T0), border_only = 0, target_atom = target, mover = mover))
- continue // couldn't enter or couldn't leave T1
-
- if(!src.ClickCross(get_dir(src,T1), border_only = 1, target_atom = target, mover = mover))
- continue // could not enter src
-
- return 1 // we don't care about our own density
-
- return 0
-
-/*
- Adjacency (to anything else):
- * Must be on a turf
-*/
-/atom/movable/Adjacent(var/atom/neighbor)
- if(neighbor == loc)
- return TRUE
- if(!isturf(loc))
- return FALSE
- if(loc.Adjacent(neighbor,target = neighbor, mover = src))
- return TRUE
- return FALSE
-
-// This is necessary for storage items not on your person.
-/obj/item/Adjacent(var/atom/neighbor, var/recurse = 1)
- if(neighbor == loc)
- return 1
- if(isitem(loc))
- if(recurse > 0)
- return loc.Adjacent(neighbor,recurse - 1)
- return 0
- return ..()
-
-/*
- This checks if you there is uninterrupted airspace between that turf and this one.
- This is defined as any dense ON_BORDER_1 object, or any dense object without LETPASSTHROW.
- The border_only flag allows you to not objects (for source and destination squares)
-*/
-/turf/proc/ClickCross(target_dir, border_only, target_atom = null, atom/movable/mover = null)
- for(var/obj/O in src)
- if((mover && O.CanPass(mover,get_step(src,target_dir))) || (!mover && !O.density))
- continue
- if(O == target_atom || O == mover || (O.pass_flags & LETPASSTHROW)) //check if there's a dense object present on the turf
- continue // LETPASSTHROW is used for anything you can click through (or the firedoor special case, see above)
-
- if( O.flags_1&ON_BORDER_1) // windows are on border, check them first
- if( O.dir & target_dir || O.dir & (O.dir-1) ) // full tile windows are just diagonals mechanically
- return 0 //O.dir&(O.dir-1) is false for any cardinal direction, but true for diagonal ones
- else if( !border_only ) // dense, not on border, cannot pass over
- return 0
- return 1
+/*
+ Adjacency proc for determining touch range
+
+ This is mostly to determine if a user can enter a square for the purposes of touching something.
+ Examples include reaching a square diagonally or reaching something on the other side of a glass window.
+
+ This is calculated by looking for border items, or in the case of clicking diagonally from yourself, dense items.
+ This proc will NOT notice if you are trying to attack a window on the other side of a dense object in its turf. There is a window helper for that.
+
+ Note that in all cases the neighbor is handled simply; this is usually the user's mob, in which case it is up to you
+ to check that the mob is not inside of something
+*/
+/atom/proc/Adjacent(atom/neighbor) // basic inheritance, unused
+ return 0
+
+// Not a sane use of the function and (for now) indicative of an error elsewhere
+/area/Adjacent(var/atom/neighbor)
+ CRASH("Call to /area/Adjacent(), unimplemented proc")
+
+
+/*
+ Adjacency (to turf):
+ * If you are in the same turf, always true
+ * If you are vertically/horizontally adjacent, ensure there are no border objects
+ * If you are diagonally adjacent, ensure you can pass through at least one of the mutually adjacent square.
+ * Passing through in this case ignores anything with the LETPASSTHROW pass flag, such as tables, racks, and morgue trays.
+*/
+/turf/Adjacent(atom/neighbor, atom/target = null, atom/movable/mover = null)
+ var/turf/T0 = get_turf(neighbor)
+
+ if(T0 == src) //same turf
+ return TRUE
+
+ if(get_dist(src, T0) > 1 || z != T0.z) //too far
+ return FALSE
+
+ // Non diagonal case
+ if(T0.x == x || T0.y == y)
+ // Check for border blockages
+ return T0.ClickCross(get_dir(T0,src), border_only = 1, target_atom = target, mover = mover) && src.ClickCross(get_dir(src,T0), border_only = 1, target_atom = target, mover = mover)
+
+ // Diagonal case
+ var/in_dir = get_dir(T0,src) // eg. northwest (1+8) = 9 (00001001)
+ var/d1 = in_dir&3 // eg. north (1+8)&3 (0000 0011) = 1 (0000 0001)
+ var/d2 = in_dir&12 // eg. west (1+8)&12 (0000 1100) = 8 (0000 1000)
+
+ for(var/d in list(d1,d2))
+ if(!T0.ClickCross(d, border_only = 1, target_atom = target, mover = mover))
+ continue // could not leave T0 in that direction
+
+ var/turf/T1 = get_step(T0,d)
+ if(!T1 || T1.density)
+ continue
+ if(!T1.ClickCross(get_dir(T1,src), border_only = 0, target_atom = target, mover = mover) || !T1.ClickCross(get_dir(T1,T0), border_only = 0, target_atom = target, mover = mover))
+ continue // couldn't enter or couldn't leave T1
+
+ if(!src.ClickCross(get_dir(src,T1), border_only = 1, target_atom = target, mover = mover))
+ continue // could not enter src
+
+ return 1 // we don't care about our own density
+
+ return 0
+
+/*
+ Adjacency (to anything else):
+ * Must be on a turf
+*/
+/atom/movable/Adjacent(var/atom/neighbor)
+ if(neighbor == loc)
+ return TRUE
+ if(!isturf(loc))
+ return FALSE
+ if(loc.Adjacent(neighbor,target = neighbor, mover = src))
+ return TRUE
+ return FALSE
+
+// This is necessary for storage items not on your person.
+/obj/item/Adjacent(var/atom/neighbor, var/recurse = 1)
+ if(neighbor == loc)
+ return 1
+ if(isitem(loc))
+ if(recurse > 0)
+ return loc.Adjacent(neighbor,recurse - 1)
+ return 0
+ return ..()
+
+/*
+ This checks if you there is uninterrupted airspace between that turf and this one.
+ This is defined as any dense ON_BORDER_1 object, or any dense object without LETPASSTHROW.
+ The border_only flag allows you to not objects (for source and destination squares)
+*/
+/turf/proc/ClickCross(target_dir, border_only, target_atom = null, atom/movable/mover = null)
+ for(var/obj/O in src)
+ if((mover && O.CanPass(mover,get_step(src,target_dir))) || (!mover && !O.density))
+ continue
+ if(O == target_atom || O == mover || (O.pass_flags & LETPASSTHROW)) //check if there's a dense object present on the turf
+ continue // LETPASSTHROW is used for anything you can click through (or the firedoor special case, see above)
+
+ if( O.flags_1&ON_BORDER_1) // windows are on border, check them first
+ if( O.dir & target_dir || O.dir & (O.dir-1) ) // full tile windows are just diagonals mechanically
+ return 0 //O.dir&(O.dir-1) is false for any cardinal direction, but true for diagonal ones
+ else if( !border_only ) // dense, not on border, cannot pass over
+ return 0
+ return 1
diff --git a/code/datums/antagonists/datum_traitor.dm b/code/datums/antagonists/datum_traitor.dm
index 80487f69e8..420dae4650 100644
--- a/code/datums/antagonists/datum_traitor.dm
+++ b/code/datums/antagonists/datum_traitor.dm
@@ -301,11 +301,11 @@
var/TC_uses = 0
var/uplink_true = FALSE
var/purchases = ""
- for(var/datum/component/uplink/H in GLOB.uplinks)
- if(H.owner && H.owner == owner.key)
- TC_uses += H.purchase_log.total_spent
- uplink_true = TRUE
- purchases += H.purchase_log.generate_render(FALSE)
+ var/datum/uplink_purchase_log/H = GLOB.uplink_purchase_logs_by_key[owner.key]
+ if(H)
+ TC_uses = H.total_spent
+ uplink_true = TRUE
+ purchases += H.generate_render(FALSE)
var/objectives_text = ""
if(objectives.len)//If the traitor had no objectives, don't need to process this.
diff --git a/code/datums/antagonists/nukeop.dm b/code/datums/antagonists/nukeop.dm
index 441098aabd..99d273ac97 100644
--- a/code/datums/antagonists/nukeop.dm
+++ b/code/datums/antagonists/nukeop.dm
@@ -303,14 +303,10 @@
var/TC_uses = 0
for(var/I in members)
var/datum/mind/syndicate = I
- for(var/U in GLOB.uplinks)
- var/datum/component/uplink/H = U
- if(H.owner == syndicate.key)
- TC_uses += H.purchase_log.total_spent
- if(H.purchase_log)
- purchases += H.purchase_log.generate_render(show_key = FALSE)
- else
- stack_trace("WARNING: Nuke Op uplink with no purchase_log Owner: [H.owner]")
+ var/datum/uplink_purchase_log/H = GLOB.uplink_purchase_logs_by_key[syndicate.key]
+ if(H)
+ TC_uses += H.total_spent
+ purchases += H.generate_render(show_key = FALSE)
text += printplayerlist(members)
text += "
"
text += "(Syndicates used [TC_uses] TC) [purchases]"
diff --git a/code/datums/components/squeek.dm b/code/datums/components/squeek.dm
index 7b9a7866ca..7a362f0391 100644
--- a/code/datums/components/squeek.dm
+++ b/code/datums/components/squeek.dm
@@ -24,7 +24,8 @@
if(use_delay_override)
use_delay = use_delay_override
- RegisterSignal(list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_BLOB_ACT, COMSIG_ATOM_HULK_ATTACK, COMSIG_PARENT_ATTACKBY, COMSIG_MOVABLE_CROSSED, COMSIG_MOVABLE_COLLIDE, COMSIG_MOVABLE_IMPACT, COMSIG_ITEM_ATTACK, COMSIG_ITEM_ATTACK_OBJ), .proc/play_squeak)
+ RegisterSignal(list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_BLOB_ACT, COMSIG_ATOM_HULK_ATTACK, COMSIG_PARENT_ATTACKBY, COMSIG_MOVABLE_COLLIDE, COMSIG_MOVABLE_IMPACT, COMSIG_ITEM_ATTACK, COMSIG_ITEM_ATTACK_OBJ), .proc/play_squeak)
+ RegisterSignal(COMSIG_MOVABLE_CROSSED, .proc/play_squeak_turf)
RegisterSignal(COMSIG_ITEM_ATTACK_SELF, .proc/use_squeak)
RegisterSignal(COMSIG_SHOES_STEP_ACTION, .proc/step_squeak)
@@ -42,6 +43,11 @@
else
steps++
+/datum/component/squeak/proc/play_squeak_turf()
+ var/atom/current_parent = parent
+ if(isturf(current_parent.loc))
+ play_squeak()
+
/datum/component/squeak/proc/use_squeak()
if(last_use + use_delay < world.time)
last_use = world.time
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index 3d3d929c81..d34c800716 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -201,9 +201,6 @@
var/obj/item/stack/N = new being_built.build_path(A, multiplier)
N.update_icon()
N.autolathe_crafted(src)
- for(var/obj/item/stack/S in (A.contents - N))
- if(istype(S, N.merge_type))
- N.merge(S)
else
for(var/i=1, i<=multiplier, i++)
var/obj/item/new_item = new being_built.build_path(A)
diff --git a/code/game/objects/effects/decals/crayon.dm b/code/game/objects/effects/decals/crayon.dm
index baad713675..b9a7701960 100644
--- a/code/game/objects/effects/decals/crayon.dm
+++ b/code/game/objects/effects/decals/crayon.dm
@@ -4,6 +4,7 @@
icon = 'icons/effects/crayondecal.dmi'
icon_state = "rune1"
gender = NEUTER
+ mergeable_decal = FALSE
var/do_icon_rotate = TRUE
var/rotation = 0
var/paint_colour = "#FFFFFF"
diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm
index 54dff5abd2..0759656423 100644
--- a/code/game/objects/items/crayons.dm
+++ b/code/game/objects/items/crayons.dm
@@ -240,7 +240,7 @@
out += a
return jointext(out,"")
-/obj/item/toy/crayon/afterattack(atom/target, mob/user, proximity)
+/obj/item/toy/crayon/afterattack(atom/target, mob/user, proximity, params)
if(!proximity || !check_allowed_items(target))
return
@@ -289,6 +289,14 @@
else
graf_rot = 0
+ var/list/click_params = params2list(params)
+ var/clickx
+ var/clicky
+
+ if(click_params && click_params["icon-x"] && click_params["icon-y"])
+ clickx = CLAMP(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2)
+ clicky = CLAMP(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)
+
if(!instant)
to_chat(user, "You start drawing a [temp] on the [target.name]...")
@@ -317,6 +325,8 @@
if(PAINT_NORMAL)
var/obj/effect/decal/cleanable/crayon/C = new(target, paint_color, drawing, temp, graf_rot)
C.add_hiddenprint(user)
+ C.pixel_x = clickx
+ C.pixel_y = clicky
affected_turfs += target
if(PAINT_LARGE_HORIZONTAL)
var/turf/left = locate(target.x-1,target.y,target.z)
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index b4434a20e2..9c6cd9e8ee 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -94,6 +94,7 @@ GLOBAL_LIST_EMPTY(PDAs)
update_icon()
/obj/item/device/pda/equipped(mob/user, slot)
+ . = ..()
if(!equipped)
if(user.client)
background_color = user.client.prefs.pda_color
diff --git a/code/game/objects/items/stacks/wrap.dm b/code/game/objects/items/stacks/wrap.dm
index baa462e907..19172673af 100644
--- a/code/game/objects/items/stacks/wrap.dm
+++ b/code/game/objects/items/stacks/wrap.dm
@@ -27,6 +27,7 @@
/obj/item/stack/packageWrap
name = "package wrapper"
+ singular_name = "wrapping sheet"
desc = "You can use this to wrap items in."
icon = 'icons/obj/stack_objects.dmi'
icon_state = "deliveryPaper"
diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm
index f5611afcd4..7c99a715cd 100644
--- a/code/game/objects/structures/flora.dm
+++ b/code/game/objects/structures/flora.dm
@@ -345,7 +345,7 @@
/obj/structure/flora/rock
icon_state = "basalt"
- desc = "A volcanic rock."
+ desc = "A volcanic rock. Pioneers used to ride these babies for miles."
icon = 'icons/obj/flora/rocks.dmi'
resistance_flags = FIRE_PROOF
density = TRUE
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 2d2213eec7..bd104f86ab 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -816,7 +816,9 @@
//Antagonist (Orange)
var/isbanned_dept = jobban_isbanned(M, "Syndicate")
dat += "
| Antagonist Positions | |||||||||
|---|---|---|---|---|---|---|---|---|---|
| Antagonist Positions | " + dat += "Team Antagonists | " + dat += "Conversion Antagonists|||||||||