diff --git a/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm b/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm
index 37a89ba2ff..274c814cf5 100644
--- a/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm
+++ b/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm
@@ -18,7 +18,7 @@
/obj/item/mining_scanner,
/obj/item/flashlight/lantern,
/obj/item/card/id/mining,
-/obj/item/gps/mining,
+/obj/item/gps/mining/off,
/turf/open/floor/plating,
/area/ruin/powered/golem_ship)
"d" = (
@@ -32,7 +32,7 @@
/obj/item/mining_scanner,
/obj/item/flashlight/lantern,
/obj/item/card/id/mining,
-/obj/item/gps/mining,
+/obj/item/gps/mining/off,
/turf/open/floor/plating,
/area/ruin/powered/golem_ship)
"e" = (
@@ -71,8 +71,8 @@
/area/ruin/powered/golem_ship)
"k" = (
/obj/machinery/computer/arcade/battle{
- icon_state = "arcade";
- dir = 4
+ dir = 4;
+ icon_state = "arcade"
},
/turf/open/floor/mineral/titanium/purple,
/area/ruin/powered/golem_ship)
@@ -112,8 +112,8 @@
/area/ruin/powered/golem_ship)
"s" = (
/obj/machinery/computer/arcade/orion_trail{
- icon_state = "arcade";
- dir = 4
+ dir = 4;
+ icon_state = "arcade"
},
/turf/open/floor/mineral/titanium/purple,
/area/ruin/powered/golem_ship)
diff --git a/_maps/map_files/CogStation/CogStation.dmm b/_maps/map_files/CogStation/CogStation.dmm
index 6f5bab0498..e41f6c7d89 100644
--- a/_maps/map_files/CogStation/CogStation.dmm
+++ b/_maps/map_files/CogStation/CogStation.dmm
@@ -6004,12 +6004,12 @@
c_tag = "Security Checkpoint";
pixel_x = 22
},
-/obj/machinery/newscaster/security_unit{
- pixel_y = 32
- },
/obj/structure/cable{
icon_state = "4-8"
},
+/obj/machinery/airalarm{
+ pixel_y = 23
+ },
/turf/open/floor/plasteel,
/area/security/checkpoint)
"aoz" = (
@@ -32290,10 +32290,6 @@
dir = 8;
light_color = "#e8eaff"
},
-/obj/machinery/airalarm{
- dir = 4;
- pixel_x = -22
- },
/turf/open/floor/plasteel,
/area/hydroponics)
"bsl" = (
@@ -71184,6 +71180,13 @@
/obj/machinery/atmospherics/pipe/simple/yellow/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
+"pMW" = (
+/obj/machinery/airalarm{
+ dir = 1;
+ pixel_y = -22
+ },
+/turf/open/floor/plasteel,
+/area/hydroponics)
"pZq" = (
/obj/structure/disposalpipe/sorting/mail/flip{
dir = 8;
@@ -121382,7 +121385,7 @@ amV
aqI
aqB
aGO
-auy
+pMW
aqB
aqI
amV
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index 07902b28b1..368b85938c 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -49530,7 +49530,7 @@
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/effect/turf_decal/stripes/line{
- dir = 10
+ dir = 8
},
/turf/open/floor/plasteel,
/area/engine/gravity_generator)
@@ -113323,10 +113323,6 @@
/obj/item/clothing/gloves/color/black,
/obj/item/storage/box/evidence,
/obj/item/taperecorder,
-/obj/machinery/airalarm{
- dir = 8;
- pixel_x = 24
- },
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm
index 408efad32f..1b37eea20c 100644
--- a/_maps/map_files/KiloStation/KiloStation.dmm
+++ b/_maps/map_files/KiloStation/KiloStation.dmm
@@ -30529,9 +30529,6 @@
dir = 8
},
/obj/structure/closet/bombcloset,
-/obj/machinery/airalarm{
- pixel_y = 24
- },
/turf/open/floor/plasteel/dark,
/area/science/mixing)
"aXC" = (
@@ -43701,10 +43698,6 @@
/obj/structure/window/reinforced{
dir = 1
},
-/obj/machinery/airalarm{
- dir = 4;
- pixel_x = -22
- },
/mob/living/simple_animal/chicken{
desc = "The arch-nemesis of Kentucky.";
name = "Popeye";
@@ -46363,9 +46356,6 @@
"bwK" = (
/obj/structure/flora/grass/jungle/b,
/obj/structure/flora/ausbushes/sparsegrass,
-/obj/machinery/airalarm{
- pixel_y = 22
- },
/turf/open/floor/grass,
/area/chapel/main)
"bwL" = (
@@ -48132,16 +48122,6 @@
},
/turf/open/floor/plasteel/showroomfloor,
/area/security/brig)
-"bzx" = (
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
- },
-/turf/closed/wall,
-/area/crew_quarters/locker)
"bzy" = (
/obj/machinery/light/small{
dir = 8
@@ -58156,10 +58136,6 @@
icon_state = "plant-02";
pixel_y = 3
},
-/obj/machinery/airalarm{
- dir = 4;
- pixel_x = -22
- },
/obj/machinery/camera{
c_tag = "Prison Wing Cells";
dir = 4;
@@ -61358,7 +61334,7 @@
dir = 10
},
/turf/open/floor/plasteel,
-/area/space)
+/area/security/warden)
"bUs" = (
/obj/machinery/door/firedoor,
/obj/machinery/door/airlock/command/glass{
@@ -67210,10 +67186,6 @@
/obj/structure/cable{
icon_state = "1-4"
},
-/obj/machinery/airalarm{
- dir = 1;
- pixel_y = -22
- },
/turf/open/floor/plasteel,
/area/security/main)
"cdU" = (
@@ -71327,9 +71299,9 @@
icon_gib = "magicarp_gib";
icon_living = "magicarp";
icon_state = "magicarp";
+ maxHealth = 200;
max_co2 = 5;
max_tox = 2;
- maxHealth = 200;
melee_damage_lower = 15;
melee_damage_upper = 20;
min_oxy = 5;
@@ -83281,10 +83253,6 @@
/obj/machinery/atmospherics/pipe/simple/yellow/visible{
dir = 5
},
-/obj/machinery/airalarm{
- dir = 4;
- pixel_x = -23
- },
/obj/machinery/camera{
c_tag = "Atmospherics Port Tanks";
dir = 4;
@@ -108992,7 +108960,7 @@ bss
btV
aEu
bxW
-bzx
+bIV
bKq
bKq
bKq
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 34fea2180d..c2a0e5c353 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -1111,10 +1111,6 @@
/turf/open/floor/plasteel,
/area/security/prison)
"acx" = (
-/obj/machinery/airalarm{
- dir = 8;
- pixel_x = 24
- },
/obj/machinery/cryopod{
dir = 8
},
@@ -40497,10 +40493,9 @@
/area/maintenance/port)
"bBr" = (
/obj/machinery/airalarm{
- dir = 4;
- pixel_x = -23
+ dir = 1;
+ pixel_y = -22
},
-/obj/structure/displaycase/trophy,
/turf/open/floor/wood,
/area/library)
"bBs" = (
@@ -45866,10 +45861,6 @@
/area/library)
"bML" = (
/obj/machinery/light/small,
-/obj/machinery/airalarm{
- dir = 1;
- pixel_y = -22
- },
/turf/open/floor/wood,
/area/library)
"bMM" = (
@@ -59581,6 +59572,10 @@
/obj/structure/chair{
dir = 1
},
+/obj/machinery/airalarm{
+ dir = 4;
+ pixel_x = -23
+ },
/turf/open/floor/plasteel/dark,
/area/medical/surgery)
"coz" = (
@@ -61596,10 +61591,6 @@
/turf/open/floor/plasteel/white,
/area/medical/surgery)
"csl" = (
-/obj/machinery/airalarm{
- dir = 1;
- pixel_y = -22
- },
/obj/structure/window/reinforced{
dir = 8
},
@@ -102698,7 +102689,7 @@ bue
bwa
bxU
bzD
-bBr
+dmD
bSx
bEw
bzE
@@ -103733,7 +103724,7 @@ bGs
bHS
bzE
bLk
-bzE
+bBr
bue
bPS
bPR
diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm
index f4d798511f..6f7f211b3e 100644
--- a/_maps/map_files/OmegaStation/OmegaStation.dmm
+++ b/_maps/map_files/OmegaStation/OmegaStation.dmm
@@ -4924,11 +4924,11 @@
/obj/effect/turf_decal/stripes/end{
dir = 1
},
-/obj/item/gun/energy/e_gun/hos,
/obj/effect/turf_decal/tile/neutral,
/obj/effect/turf_decal/tile/neutral{
dir = 4
},
+/obj/item/gun/energy/e_gun/hos,
/turf/open/floor/plasteel/dark,
/area/crew_quarters/heads/captain/private)
"ahI" = (
@@ -40544,6 +40544,9 @@
name = "Starboard Quater Maintenance APC";
pixel_y = -26
},
+/obj/structure/cable/white{
+ icon_state = "0-8"
+ },
/turf/open/floor/plating{
icon_state = "panelscorched"
},
diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm
index 12ae0092f0..12c507c2bf 100644
--- a/_maps/map_files/PubbyStation/PubbyStation.dmm
+++ b/_maps/map_files/PubbyStation/PubbyStation.dmm
@@ -16530,6 +16530,9 @@
/obj/structure/cable{
icon_state = "4-8"
},
+/obj/machinery/airalarm{
+ pixel_y = 22
+ },
/turf/open/floor/plasteel,
/area/quartermaster/warehouse)
"aMr" = (
@@ -47631,6 +47634,9 @@
pixel_x = -25;
specialfunctions = 4
},
+/obj/machinery/airalarm{
+ pixel_y = 22
+ },
/turf/open/floor/plasteel/grimy,
/area/chapel/main/monastery)
"cgM" = (
@@ -47979,6 +47985,9 @@
pixel_x = -25;
specialfunctions = 4
},
+/obj/machinery/airalarm{
+ pixel_y = 22
+ },
/turf/open/floor/plasteel/grimy,
/area/chapel/main/monastery)
"cip" = (
@@ -51466,6 +51475,10 @@
name = "Coffin Storage";
req_one_access_txt = "22"
},
+/obj/machinery/airalarm{
+ dir = 8;
+ pixel_x = 24
+ },
/turf/open/floor/plasteel/dark,
/area/chapel/main/monastery)
"cvu" = (
@@ -59434,6 +59447,10 @@
/obj/effect/turf_decal/tile/yellow{
dir = 8
},
+/obj/machinery/airalarm{
+ dir = 8;
+ pixel_x = 23
+ },
/turf/open/floor/plasteel,
/area/construction/mining/aux_base)
"qXq" = (
diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm
index 68515426c3..e71243994d 100644
--- a/code/__DEFINES/antagonists.dm
+++ b/code/__DEFINES/antagonists.dm
@@ -69,6 +69,9 @@
#define LINGBLOOD_EXPLOSION_THRESHOLD (LINGBLOOD_DETECTION_THRESHOLD * LINGBLOOD_EXPLOSION_MULT) //Hey, important to note here: the explosion threshold is explicitly more than, rather than more than or equal to. This stops a single loud ability from triggering the explosion threshold.
///Heretics --
+GLOBAL_LIST_EMPTY(living_heart_cache) //A list of all living hearts in existance, for us to iterate through.
+
+
#define IS_HERETIC(mob) (mob.mind?.has_antag_datum(/datum/antagonist/heretic))
#define IS_HERETIC_MONSTER(mob) (mob.mind?.has_antag_datum(/datum/antagonist/heretic_monster))
diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
index a084f2ae34..a1bb4122a8 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -541,6 +541,9 @@
#define COMSIG_XENO_TURF_CLICK_CTRL "xeno_turf_click_alt" //from turf AltClickOn(): (/mob)
#define COMSIG_XENO_MONKEY_CLICK_CTRL "xeno_monkey_click_ctrl" //from monkey CtrlClickOn(): (/mob)
+// /datum/element/ventcrawling signals
+#define COMSIG_HANDLE_VENTCRAWL "handle_ventcrawl" //when atom with ventcrawling element attempts to ventcrawl
+#define COMSIG_CHECK_VENTCRAWL "check_ventcrawl" //to check an atom's ventcrawling element tier (if applicable)
// twitch plays
/// Returns direction: (wipe_votes)
#define COMSIG_TWITCH_PLAYS_MOVEMENT_DATA "twitch_plays_movement_data"
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index 2275c4b90b..b7750556d5 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -253,6 +253,7 @@
// item traits
#define TRAIT_NODROP "nodrop"
+#define TRAIT_SPOOKY_THROW "spooky_throw"
// common trait sources
#define TRAIT_GENERIC "generic"
diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm
index 8d25fb8e03..a59ee9fcb0 100644
--- a/code/__HELPERS/_lists.dm
+++ b/code/__HELPERS/_lists.dm
@@ -67,24 +67,25 @@
//Returns a list in plain english as a string
/proc/english_list(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" )
- var/total = input.len
- if (!total)
- return nothing_text
- else if (total == 1)
- return "[input[1]]"
- else if (total == 2)
- return "[input[1]][and_text][input[2]]"
- else
- var/output = ""
- var/index = 1
- while (index < total)
- if (index == total - 1)
- comma_text = final_comma_text
+ var/total = length(input)
+ switch(total)
+ if (0)
+ return "[nothing_text]"
+ if (1)
+ return "[input[1]]"
+ if (2)
+ return "[input[1]][and_text][input[2]]"
+ else
+ var/output = ""
+ var/index = 1
+ while (index < total)
+ if (index == total - 1)
+ comma_text = final_comma_text
- output += "[input[index]][comma_text]"
- index++
+ output += "[input[index]][comma_text]"
+ index++
- return "[output][and_text][input[index]]"
+ return "[output][and_text][input[index]]"
//Returns list element or null. Should prevent "index out of bounds" error.
/proc/listgetindex(list/L, index)
diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm
index a61e3a6492..8ff610e68c 100644
--- a/code/__HELPERS/names.dm
+++ b/code/__HELPERS/names.dm
@@ -19,22 +19,6 @@
/proc/arachnid_name()
return "[pick(GLOB.arachnid_first)] [pick(GLOB.arachnid_last)]"
-/proc/church_name()
- var/static/church_name
- if (church_name)
- return church_name
-
- var/name = ""
-
- name += pick("Holy", "United", "First", "Second", "Last")
-
- if (prob(20))
- name += " Space"
-
- name += " " + pick("Church", "Cathedral", "Body", "Worshippers", "Movement", "Witnesses")
- name += " of [religion_name()]"
-
- return name
GLOBAL_VAR(command_name)
/proc/command_name()
@@ -52,17 +36,6 @@ GLOBAL_VAR(command_name)
return name
-/proc/religion_name()
- var/static/religion_name
- if (religion_name)
- return religion_name
-
- var/name = ""
-
- name += pick("bee", "science", "edu", "captain", "assistant", "monkey", "alien", "space", "unit", "sprocket", "gadget", "bomb", "revolution", "beyond", "station", "goon", "robot", "ivor", "hobnob")
- name += pick("ism", "ia", "ology", "istism", "ites", "ick", "ian", "ity")
-
- return capitalize(name)
/proc/station_name()
if(!GLOB.station_name)
diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm
index 0987e95dc9..87187a4c3d 100644
--- a/code/__HELPERS/type2type.dm
+++ b/code/__HELPERS/type2type.dm
@@ -78,21 +78,21 @@
//Turns a direction into text
/proc/dir2text(direction)
switch(direction)
- if(1)
+ if(NORTH)
return "north"
- if(2)
+ if(SOUTH)
return "south"
- if(4)
+ if(EAST)
return "east"
- if(8)
+ if(WEST)
return "west"
- if(5)
+ if(NORTHEAST)
return "northeast"
- if(6)
+ if(SOUTHEAST)
return "southeast"
- if(9)
+ if(NORTHWEST)
return "northwest"
- if(10)
+ if(SOUTHWEST)
return "southwest"
else
return
@@ -101,21 +101,21 @@
/proc/text2dir(direction)
switch(uppertext(direction))
if("NORTH")
- return 1
+ return NORTH
if("SOUTH")
- return 2
+ return SOUTH
if("EAST")
- return 4
+ return EAST
if("WEST")
- return 8
+ return WEST
if("NORTHEAST")
- return 5
+ return NORTHEAST
if("NORTHWEST")
- return 9
+ return NORTHWEST
if("SOUTHEAST")
- return 6
+ return SOUTHEAST
if("SOUTHWEST")
- return 10
+ return SOUTHWEST
else
return
diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm
index 4e593ba904..f376ba50d7 100644
--- a/code/_globalvars/traits.dm
+++ b/code/_globalvars/traits.dm
@@ -130,7 +130,8 @@ GLOBAL_LIST_INIT(traits_by_type, list(
),
/obj/item = list(
"TRAIT_NODROP" = TRAIT_NODROP,
- "TRAIT_NO_TELEPORT" = TRAIT_NO_TELEPORT
+ "TRAIT_NO_TELEPORT" = TRAIT_NO_TELEPORT,
+ "TRAIT_SPOOKY_THROW" = TRAIT_SPOOKY_THROW
)
))
diff --git a/code/_onclick/right_click.dm b/code/_onclick/right_click.dm
index 9a99bbd20b..4b2480eb8c 100644
--- a/code/_onclick/right_click.dm
+++ b/code/_onclick/right_click.dm
@@ -51,11 +51,7 @@
//Standard reach turf to turf or reaching inside storage
if(CanReach(A,W))
if(W)
- if(a_intent == INTENT_HELP && iscarbon(src))
- var/mob/living/carbon/C = src
- C.give()
- else
- return W.rightclick_melee_attack_chain(src, A, params)
+ return W.rightclick_melee_attack_chain(src, A, params)
else
if(!AltUnarmedAttack(A, TRUE))
. = UnarmedAttack(A, TRUE, a_intent)
diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm
index e5d6b0bbd0..0fa8035d72 100644
--- a/code/controllers/subsystem/throwing.dm
+++ b/code/controllers/subsystem/throwing.dm
@@ -84,6 +84,8 @@ SUBSYSTEM_DEF(throwing)
/datum/thrownthing/Destroy()
+ if(HAS_TRAIT_FROM(thrownthing, TRAIT_SPOOKY_THROW, "revenant"))
+ REMOVE_TRAIT(thrownthing, TRAIT_SPOOKY_THROW, "revenant")
SSthrowing.processing -= thrownthing
thrownthing.throwing = null
thrownthing = null
diff --git a/code/datums/components/gps.dm b/code/datums/components/gps.dm
index c2b3ad1f30..61098c8b66 100644
--- a/code/datums/components/gps.dm
+++ b/code/datums/components/gps.dm
@@ -21,7 +21,7 @@ GLOBAL_LIST_EMPTY(GPS_list)
var/updating = TRUE //Automatic updating of GPS list. Can be set to manual by user.
var/global_mode = TRUE //If disabled, only GPS signals of the same Z level are shown
-/datum/component/gps/item/Initialize(_gpstag = "COM0", emp_proof = FALSE)
+/datum/component/gps/item/Initialize(_gpstag = "COM0", emp_proof = FALSE, starton = TRUE)
. = ..()
if(. == COMPONENT_INCOMPATIBLE || !isitem(parent))
return COMPONENT_INCOMPATIBLE
@@ -33,6 +33,8 @@ GLOBAL_LIST_EMPTY(GPS_list)
RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, .proc/on_emp_act)
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine)
RegisterSignal(parent, COMSIG_CLICK_ALT, .proc/on_AltClick)
+ if(!starton)
+ tracking = FALSE
///Called on COMSIG_ITEM_ATTACK_SELF
/datum/component/gps/item/proc/interact(datum/source, mob/user)
diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm
index f93d40bb04..2fa5a20d7a 100644
--- a/code/datums/components/storage/storage.dm
+++ b/code/datums/components/storage/storage.dm
@@ -449,6 +449,10 @@
// this must come before the screen objects only block, dunno why it wasn't before
if(over_object == M)
user_show_to_mob(M)
+ return
+ if(isrevenant(M))
+ RevenantThrow(over_object, M, source)
+ return
if(!M.incapacitated())
if(!istype(over_object, /obj/screen))
dump_content_at(over_object, M)
diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm
index 44775ed031..8dca59ea94 100644
--- a/code/datums/diseases/transformation.dm
+++ b/code/datums/diseases/transformation.dm
@@ -121,7 +121,7 @@
add_monkey(affected_mob.mind)
if(ishuman(affected_mob))
var/mob/living/carbon/monkey/M = affected_mob.monkeyize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSE)
- M.ventcrawler = VENTCRAWLER_ALWAYS
+ M.AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/datum/disease/transformation/jungle_fever/stage_act()
diff --git a/code/datums/elements/ventcrawling.dm b/code/datums/elements/ventcrawling.dm
new file mode 100644
index 0000000000..254345a97f
--- /dev/null
+++ b/code/datums/elements/ventcrawling.dm
@@ -0,0 +1,36 @@
+/datum/element/ventcrawling
+ element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH
+ id_arg_index = 2
+ var/tier
+
+/datum/element/ventcrawling/Attach(datum/target, duration = 0, given_tier = VENTCRAWLER_NUDE)
+ . = ..()
+
+ var/mob/living/person = target
+ if(!istype(person))
+ return FALSE
+
+ src.tier = given_tier
+
+ RegisterSignal(target, COMSIG_HANDLE_VENTCRAWL, .proc/handle_ventcrawl)
+ RegisterSignal(target, COMSIG_CHECK_VENTCRAWL, .proc/check_ventcrawl)
+ to_chat(target, "You can ventcrawl! Use alt+click on vents to quickly travel about the station.")
+
+ if(duration!=0)
+ addtimer(CALLBACK(src, .proc/Detach, target), duration)
+
+/datum/element/ventcrawling/Detach(datum/target)
+ UnregisterSignal(target, list(COMSIG_HANDLE_VENTCRAWL, COMSIG_CHECK_VENTCRAWL))
+ to_chat(target, "You can no longer ventcrawl.")
+
+ return ..()
+
+/datum/element/ventcrawling/proc/handle_ventcrawl(datum/target,atom/A)
+ var/mob/living/person = target
+ if(!istype(person))
+ return FALSE
+
+ person.handle_ventcrawl(A,tier)
+
+/datum/element/ventcrawling/proc/check_ventcrawl()
+ return tier
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index bbbce9b8fd..a582fa03e4 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -574,8 +574,8 @@
return TRUE
//TODO: Better floating
-/atom/movable/proc/float(on)
- if(throwing)
+/atom/movable/proc/float(on, throw_override)
+ if(throwing || !throw_override)
return
if(on && !(movement_type & FLOATING))
animate(src, pixel_y = 2, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index d8617e0b48..0ee07951a9 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -455,7 +455,7 @@ If not set, defaults to check_completion instead. Set it. It's used by cryo.
var/target_real_name // Has to be stored because the target's real_name can change over the course of the round
var/target_missing_id
-/datum/objective/escape/escape_with_identity/find_target()
+/datum/objective/escape/escape_with_identity/find_target(dupe_search_range, blacklist)
target = ..()
update_explanation_text()
@@ -553,7 +553,7 @@ GLOBAL_LIST_EMPTY(possible_items)
for(var/I in subtypesof(/datum/objective_item/steal))
new I
-/datum/objective/steal/find_target()
+/datum/objective/steal/find_target(dupe_search_range, blacklist)
var/list/datum/mind/owners = get_owners()
var/approved_targets = list()
check_items:
@@ -631,7 +631,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
for(var/I in subtypesof(/datum/objective_item/special) + subtypesof(/datum/objective_item/stack))
new I
-/datum/objective/steal/special/find_target()
+/datum/objective/steal/special/find_target(dupe_search_range, blacklist)
return set_target(pick(GLOB.possible_items_special))
/datum/objective/steal/exchange
@@ -844,7 +844,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
name = "destroy AI"
martyr_compatible = 1
-/datum/objective/destroy/find_target()
+/datum/objective/destroy/find_target(dupe_search_range, blacklist)
var/list/possible_targets = active_ais(1)
var/mob/living/silicon/ai/target_ai = pick(possible_targets)
target = target_ai.mind
@@ -1124,7 +1124,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
/datum/objective/hoard/heirloom
name = "steal heirloom"
-/datum/objective/hoard/heirloom/find_target()
+/datum/objective/hoard/heirloom/find_target(dupe_search_range, blacklist)
set_target(pick(GLOB.family_heirlooms))
GLOBAL_LIST_EMPTY(traitor_contraband)
@@ -1141,7 +1141,7 @@ GLOBAL_LIST_EMPTY(cult_contraband)
if(!GLOB.cult_contraband.len)
GLOB.cult_contraband = list(/obj/item/clockwork/slab,/obj/item/clockwork/component/belligerent_eye,/obj/item/clockwork/component/belligerent_eye/lens_gem,/obj/item/shuttle_curse,/obj/item/cult_shift)
-/datum/objective/hoard/collector/find_target()
+/datum/objective/hoard/collector/find_target(dupe_search_range, blacklist)
var/obj/item/I
var/I_type
if(prob(50))
@@ -1172,7 +1172,7 @@ GLOBAL_LIST_EMPTY(possible_sabotages)
for(var/I in subtypesof(/datum/sabotage_objective))
new I
-/datum/objective/sabotage/find_target()
+/datum/objective/sabotage/find_target(dupe_search_range, blacklist)
var/list/datum/mind/owners = get_owners()
var/approved_targets = list()
check_sabotages:
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 251e2fe327..608768a0c7 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -468,6 +468,10 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
melee_attack_chain(usr, over)
usr.FlushCurrentAction()
return TRUE //returning TRUE as a "is this overridden?" flag
+ if(isrevenant(usr))
+ if(RevenantThrow(over, usr, src))
+ return
+
if(!Adjacent(usr) || !over.Adjacent(usr))
return // should stop you from dragging through windows
@@ -939,6 +943,10 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
/obj/item/proc/get_part_rating()
return 0
+//Can this item be given to people?
+/obj/item/proc/can_give()
+ return TRUE
+
/obj/item/doMove(atom/destination)
if (ismob(loc))
var/mob/M = loc
diff --git a/code/game/objects/items/candle.dm b/code/game/objects/items/candle.dm
index a3366e714e..960e3ce499 100644
--- a/code/game/objects/items/candle.dm
+++ b/code/game/objects/items/candle.dm
@@ -82,4 +82,8 @@
/obj/item/candle/infinite/hugbox
heats_space = FALSE
+/obj/item/candle/DoRevenantThrowEffects(atom/target)
+ if(!infinite)
+ put_out_candle()
+
#undef CANDLE_LUMINOSITY
diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm
index 5b1b86b9e4..7d2b0ed832 100644
--- a/code/game/objects/items/cards_ids.dm
+++ b/code/game/objects/items/cards_ids.dm
@@ -779,16 +779,40 @@
/obj/item/card/id/departmental_budget/update_label()
return
+/obj/item/card/id/departmental_budget/civ
+ department_ID = ACCOUNT_CIV
+ department_name = ACCOUNT_CIV_NAME
+
+/obj/item/card/id/departmental_budget/eng
+ department_ID = ACCOUNT_ENG
+ department_name = ACCOUNT_ENG_NAME
+
+/obj/item/card/id/departmental_budget/sci
+ department_ID = ACCOUNT_SCI
+ department_name = ACCOUNT_SCI_NAME
+
+/obj/item/card/id/departmental_budget/med
+ department_ID = ACCOUNT_MED
+ department_name = ACCOUNT_MED_NAME
+
+/obj/item/card/id/departmental_budget/srv
+ department_ID = ACCOUNT_SRV
+ department_name = ACCOUNT_SRV_NAME
+
/obj/item/card/id/departmental_budget/car
department_ID = ACCOUNT_CAR
department_name = ACCOUNT_CAR_NAME
+/obj/item/card/id/departmental_budget/sec
+ department_ID = ACCOUNT_SEC
+ department_name = ACCOUNT_SEC_NAME
+
//Polychromatic Knight Badge
/obj/item/card/id/knight
name = "knight badge"
icon_state = "knight"
- desc = "A badge denoting the owner as a knight! It has a strip for swiping like an ID"
+ desc = "A badge denoting the owner as a knight! It has a strip for swiping like an ID."
var/id_color = "#00FF00" //defaults to green
var/mutable_appearance/id_overlay
diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm
index de32375642..4280e7105f 100644
--- a/code/game/objects/items/cigs_lighters.dm
+++ b/code/game/objects/items/cigs_lighters.dm
@@ -136,6 +136,12 @@ CIGARETTE PACKETS ARE IN FANCY.DM
STOP_PROCESSING(SSobj, src)
. = ..()
+/obj/item/clothing/mask/cigarette/DoRevenantThrowEffects(atom/target)
+ if(lit)
+ attackby()
+ else
+ light()
+
/obj/item/clothing/mask/cigarette/attackby(obj/item/W, mob/user, params)
if(!lit && smoketime > 0)
var/lighting_text = W.ignition_effect(src, user)
@@ -517,6 +523,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM
overlay_state = pick(overlay_list)
update_icon()
+/obj/item/lighter/DoRevenantThrowEffects(atom/target)
+ set_lit()
+
/obj/item/lighter/suicide_act(mob/living/carbon/user)
if (lit)
user.visible_message("[user] begins holding \the [src]'s flame up to [user.p_their()] face! It looks like [user.p_theyre()] trying to commit suicide!")
diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm
index a2459bce9f..e29519406a 100644
--- a/code/game/objects/items/devices/flashlight.dm
+++ b/code/game/objects/items/devices/flashlight.dm
@@ -37,11 +37,14 @@
/obj/item/flashlight/attack_self(mob/user)
on = !on
update_brightness(user)
- playsound(user, on ? 'sound/weapons/magin.ogg' : 'sound/weapons/magout.ogg', 40, 1)
+ playsound(src, on ? 'sound/weapons/magin.ogg' : 'sound/weapons/magout.ogg', 40, TRUE)
for(var/X in actions)
var/datum/action/A = X
A.UpdateButtonIcon()
- return 1
+ return TRUE
+
+/obj/item/flashlight/DoRevenantThrowEffects(atom/target)
+ attack_self()
/obj/item/flashlight/suicide_act(mob/living/carbon/human/user)
if (user.eye_blind)
diff --git a/code/game/objects/items/devices/gps.dm b/code/game/objects/items/devices/gps.dm
index bb46577702..a0b695e29f 100644
--- a/code/game/objects/items/devices/gps.dm
+++ b/code/game/objects/items/devices/gps.dm
@@ -8,10 +8,11 @@
slot_flags = ITEM_SLOT_BELT
obj_flags = UNIQUE_RENAME
var/gpstag = "COM0"
+ var/starton = TRUE
/obj/item/gps/Initialize()
. = ..()
- AddComponent(/datum/component/gps/item, gpstag)
+ AddComponent(/datum/component/gps/item, gpstag, starton)
/obj/item/gps/science
icon_state = "gps-s"
@@ -26,6 +27,9 @@
gpstag = "MINE0"
desc = "A positioning system helpful for rescuing trapped or injured miners, keeping one on you at all times while mining might just save your life."
+/obj/item/gps/mining/off
+ starton = FALSE
+
/obj/item/gps/cyborg
icon_state = "gps-b"
gpstag = "BORG0"
diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm
index 6ac2d310a1..939d77a1f0 100644
--- a/code/game/objects/items/devices/radio/headset.dm
+++ b/code/game/objects/items/devices/radio/headset.dm
@@ -283,14 +283,12 @@ GLOBAL_LIST_INIT(channel_tokens, list(
SSradio.remove_object(src, GLOB.radiochannels[ch_name])
secure_radio_connections[ch_name] = null
- var/turf/T = user.drop_location()
- if(T)
- if(keyslot)
- keyslot.forceMove(T)
- keyslot = null
- if(keyslot2)
- keyslot2.forceMove(T)
- keyslot2 = null
+ if(keyslot)
+ user.put_in_hands(keyslot)
+ keyslot = null
+ if(keyslot2)
+ user.put_in_hands(keyslot2)
+ keyslot2 = null
recalculateChannels()
to_chat(user, "You pop out the encryption keys in the headset.")
diff --git a/code/game/objects/items/eightball.dm b/code/game/objects/items/eightball.dm
index 0d5c9a22aa..39c8143ee9 100644
--- a/code/game/objects/items/eightball.dm
+++ b/code/game/objects/items/eightball.dm
@@ -46,6 +46,9 @@
if(.)
new /obj/item/toy/eightball/haunted(loc)
+/obj/item/toy/eightball/DoRevenantThrowEffects(atom/target)
+ MakeHaunted()
+
/obj/item/toy/eightball/attack_self(mob/user)
if(shaking)
return
diff --git a/code/game/objects/items/extinguisher.dm b/code/game/objects/items/extinguisher.dm
index b1f51f608d..c1579dfe15 100644
--- a/code/game/objects/items/extinguisher.dm
+++ b/code/game/objects/items/extinguisher.dm
@@ -235,16 +235,23 @@
return
EmptyExtinguisher(user)
-/obj/item/extinguisher/proc/EmptyExtinguisher(var/mob/user)
- if(loc == user && reagents.total_volume)
+/obj/item/extinguisher/DoRevenantThrowEffects(atom/target)
+ EmptyExtinguisher()
+
+/obj/item/extinguisher/proc/EmptyExtinguisher(mob/user)
+ if(!reagents.total_volume)
+ return
+ if(loc == user || !user)
reagents.clear_reagents()
var/turf/T = get_turf(loc)
if(isopenturf(T))
var/turf/open/theturf = T
theturf.MakeSlippery(TURF_WET_WATER, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS)
-
- user.visible_message("[user] empties out \the [src] onto the floor using the release valve.", "You quietly empty out \the [src] by using its release valve.")
+ if(user)
+ user.visible_message("[user] empties out \the [src] onto the floor using the release valve.", "You quietly empty out \the [src] by using its release valve.")
+ else
+ user.visible_message("The release valve of \the [src] suddenly opens and sprays it's contents on the floor!")
//firebot assembly
/obj/item/extinguisher/attackby(obj/O, mob/user, params)
diff --git a/code/game/objects/items/pinpointer.dm b/code/game/objects/items/pinpointer.dm
index abd9cec950..81bae3d54b 100644
--- a/code/game/objects/items/pinpointer.dm
+++ b/code/game/objects/items/pinpointer.dm
@@ -30,9 +30,13 @@
target = null
return ..()
+/obj/item/pinpointer/DoRevenantThrowEffects(atom/target)
+ attack_self()
+
/obj/item/pinpointer/attack_self(mob/living/user)
active = !active
- user.visible_message("[user] [active ? "" : "de"]activates [user.p_their()] pinpointer.", "You [active ? "" : "de"]activate your pinpointer.")
+ if(user)
+ user.visible_message("[user] [active ? "" : "de"]activates [user.p_their()] pinpointer.", "You [active ? "" : "de"]activate your pinpointer.")
playsound(src, 'sound/items/screwdriver2.ogg', 50, 1)
if(active)
START_PROCESSING(SSfastprocess, src)
diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm
index c5193d8b19..c213fa34df 100644
--- a/code/game/objects/items/plushes.dm
+++ b/code/game/objects/items/plushes.dm
@@ -45,6 +45,10 @@
return
set_snowflake_from_config(id)
+/obj/item/toy/plush/DoRevenantThrowEffects(atom/target)
+ var/datum/component/squeak/squeaker = GetComponent(/datum/component/squeak)
+ squeaker.do_play_squeak(TRUE)
+
/obj/item/toy/plush/Initialize(mapload, set_snowflake_id)
. = ..()
AddComponent(/datum/component/squeak, squeak_override)
diff --git a/code/game/objects/items/pneumaticCannon.dm b/code/game/objects/items/pneumaticCannon.dm
index 23be8cbb9a..1db5cdd526 100644
--- a/code/game/objects/items/pneumaticCannon.dm
+++ b/code/game/objects/items/pneumaticCannon.dm
@@ -43,6 +43,13 @@
/obj/item/pneumatic_cannon/proc/init_charge() //wrapper so it can be vv'd easier
START_PROCESSING(SSobj, src)
+/obj/item/pneumatic_cannon/DoRevenantThrowEffects(atom/target)
+ var/picked_target
+ var/list/possible_targets = range(3,src)
+ picked_target = pick(possible_targets)
+ if(target)
+ Fire(null, picked_target)
+
/obj/item/pneumatic_cannon/process()
if(++charge_tick >= charge_ticks && charge_type)
fill_with_type(charge_type, charge_amount)
@@ -134,21 +141,29 @@
Fire(user, target)
/obj/item/pneumatic_cannon/proc/Fire(mob/living/user, var/atom/target)
- if(!istype(user) && !target)
+ if(!target)
return
+ if(user)
+ if(!isliving(user))
+ return
var/discharge = 0
- if(!can_trigger_gun(user))
+ if(user && !can_trigger_gun(user))
return
if(!loadedItems || !loadedWeightClass)
- to_chat(user, "\The [src] has nothing loaded.")
+ if(user)
+ to_chat(user, "\The [src] has nothing loaded.")
return
if(!tank && checktank)
- to_chat(user, "\The [src] can't fire without a source of gas.")
+ if(user)
+ to_chat(user, "\The [src] can't fire without a source of gas.")
return
if(tank && !tank.air_contents.remove(gasPerThrow * pressureSetting))
- to_chat(user, "\The [src] lets out a weak hiss and doesn't react!")
+ if(user)
+ to_chat(user, "\The [src] lets out a weak hiss and doesn't react!")
+ else
+ visible_message(src, "\The [src] lets out a weak hiss and doesn't react!")
return
- if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(75) && clumsyCheck && iscarbon(user))
+ if(user && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(75) && clumsyCheck && iscarbon(user))
var/mob/living/carbon/C = user
C.visible_message("[C] loses [C.p_their()] grip on [src], causing it to go off!", "[src] slips out of your hands and goes off!")
C.dropItemToGround(src, TRUE)
@@ -157,15 +172,18 @@
else
var/list/possible_targets = range(3,src)
target = pick(possible_targets)
- discharge = 1
- if(!discharge)
+ discharge = TRUE
+ if(!discharge && user)
user.visible_message("[user] fires \the [src]!", \
"You fire \the [src]!")
- log_combat(user, target, "fired at", src)
var/turf/T = get_target(target, get_turf(src))
- playsound(src, 'sound/weapons/sonic_jackhammer.ogg', 50, 1)
- fire_items(T, user)
- if(pressureSetting >= 3 && iscarbon(user))
+ playsound(src, 'sound/weapons/sonic_jackhammer.ogg', 50, TRUE)
+ if(user)
+ log_combat(user, target, "fired at", src)
+ fire_items(T, user)
+ else
+ fire_items(T)
+ if(user && pressureSetting >= 3 && iscarbon(user))
var/mob/living/carbon/C = user
C.visible_message("[C] is thrown down by the force of the cannon!", "[src] slams into your shoulder, knocking you down!")
C.DefaultCombatKnockdown(60)
diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm
index d7db5ce908..1de77bd8b9 100644
--- a/code/game/objects/items/stunbaton.dm
+++ b/code/game/objects/items/stunbaton.dm
@@ -47,6 +47,9 @@
cell = new preload_cell_type(src)
update_icon()
+/obj/item/melee/baton/DoRevenantThrowEffects(atom/target)
+ switch_status()
+
/obj/item/melee/baton/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
..()
//Only mob/living types have stun handling
@@ -236,6 +239,12 @@
if(!iscyborg(loc))
deductcharge(severity*10, TRUE, FALSE)
+/obj/item/melee/baton/can_give()
+ if(turned_on)
+ return FALSE
+ else
+ ..()
+
/obj/item/melee/baton/stunsword
name = "stunsword"
desc = "Not actually sharp, this sword is functionally identical to its baton counterpart."
diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm
index 08b91332ef..d57f0cc51f 100644
--- a/code/game/objects/items/tanks/tanks.dm
+++ b/code/game/objects/items/tanks/tanks.dm
@@ -73,6 +73,15 @@
/obj/item/tank/proc/populate_gas()
return
+/obj/item/tank/DoRevenantThrowEffects(atom/target)
+ if(air_contents)
+ var/turf/open/location = get_turf(src)
+ if(istype(location))
+ location.assume_air(air_contents)
+ air_contents.clear()
+ SSair.add_to_active(location)
+ visible_message("[src] can't be turned on while unsecured!")
+ if(user)
+ to_chat(user, "[src] can't be turned on while unsecured!")
return
welding = !welding
if(welding)
if(get_fuel() >= 1)
- to_chat(user, "You switch [src] on.")
+ if(user)
+ to_chat(user, "You switch [src] on.")
playsound(loc, acti_sound, 50, 1)
force = 15
damtype = "fire"
diff --git a/code/game/objects/structures/plasticflaps.dm b/code/game/objects/structures/plasticflaps.dm
index a07e9a26d5..ff8287d77b 100644
--- a/code/game/objects/structures/plasticflaps.dm
+++ b/code/game/objects/structures/plasticflaps.dm
@@ -62,7 +62,7 @@
return 1
var/mob/living/M = caller
- if(!M.ventcrawler && M.mob_size != MOB_SIZE_TINY)
+ if(!(SEND_SIGNAL(M, COMSIG_CHECK_VENTCRAWL)) && M.mob_size != MOB_SIZE_TINY)
return 0
var/atom/movable/M = caller
if(M && M.pulling)
@@ -91,7 +91,7 @@
return 1
if(M.buckled && istype(M.buckled, /mob/living/simple_animal/bot/mulebot)) // mulebot passenger gets a free pass.
return 1
- if(!M.lying && !M.ventcrawler && M.mob_size != MOB_SIZE_TINY) //If your not laying down, or a ventcrawler or a small creature, no pass.
+ if(!M.lying && !(SEND_SIGNAL(M, COMSIG_CHECK_VENTCRAWL)) && M.mob_size != MOB_SIZE_TINY) //If your not laying down, or a ventcrawler or a small creature, no pass.
return 0
return ..()
diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm
index 4348ae7661..45d05c70b9 100644
--- a/code/modules/admin/verbs/adminhelp.dm
+++ b/code/modules/admin/verbs/adminhelp.dm
@@ -174,7 +174,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
//is_bwoink is TRUE if this ticket was started by an admin PM
/datum/admin_help/New(msg, client/C, is_bwoink)
//clean the input msg
- msg = sanitize(copytext_char(msg,1,MAX_MESSAGE_LEN))
+ msg = copytext_char(msg,1,MAX_MESSAGE_LEN)
if(!msg || !C || !C.mob)
qdel(src)
return
@@ -263,7 +263,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
//message from the initiator without a target, all admins will see this
//won't bug irc
/datum/admin_help/proc/MessageNoRecipient(msg)
- msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN))
+ msg = copytext_char(msg, 1, MAX_MESSAGE_LEN)
var/ref_src = "[REF(src)]"
//Message to be sent to all admins
var/admin_msg = "Ticket [TicketHref("#[id]", ref_src)]: [LinkedReplyName(ref_src)] [FullMonty(ref_src)]: [keywords_lookup(msg)]"
@@ -523,7 +523,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
if(handle_spam_prevention(msg,MUTE_ADMINHELP))
return
- msg = trim(msg)
+ msg = sanitize(trim(msg))
if(!msg)
return
diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm
index 2931c52a5c..4856f5af32 100644
--- a/code/modules/admin/verbs/adminpm.dm
+++ b/code/modules/admin/verbs/adminpm.dm
@@ -113,6 +113,11 @@
to_chat(src, "Error: Use the admin IRC/Discord channel, nerd.", confidential = TRUE)
return
+ //clean the message if it's not sent by a high-rank admin
+ if(!check_rights(R_SERVER|R_DEBUG,0)||external)//no sending html to the poor bots
+ msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN))
+ if(!msg)
+ return
else
//get message text, limit it's length.and clean/escape html
@@ -141,15 +146,9 @@
to_chat(src, "Error: Admin-PM: You are unable to use admin PM-s (muted).", confidential = TRUE)
return
- if (src.handle_spam_prevention(msg,MUTE_ADMINHELP))
+ if(src.handle_spam_prevention(msg,MUTE_ADMINHELP))
return
- //clean the message if it's not sent by a high-rank admin
- if(!check_rights(R_SERVER|R_DEBUG,0)||external)//no sending html to the poor bots
- msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN))
- if(!msg)
- return
-
var/rawmsg = msg
if(holder)
diff --git a/code/modules/antagonists/abductor/equipment/glands/ventcrawl.dm b/code/modules/antagonists/abductor/equipment/glands/ventcrawl.dm
index 8ac083f68b..c35016cf2e 100644
--- a/code/modules/antagonists/abductor/equipment/glands/ventcrawl.dm
+++ b/code/modules/antagonists/abductor/equipment/glands/ventcrawl.dm
@@ -9,4 +9,4 @@
/obj/item/organ/heart/gland/ventcrawling/activate()
to_chat(owner, "You feel very stretchy.")
- owner.ventcrawler = VENTCRAWLER_ALWAYS
+ owner.AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
diff --git a/code/modules/antagonists/blob/blob/overmind.dm b/code/modules/antagonists/blob/blob/overmind.dm
index 02be432045..18f6817ec9 100644
--- a/code/modules/antagonists/blob/blob/overmind.dm
+++ b/code/modules/antagonists/blob/blob/overmind.dm
@@ -277,3 +277,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
var/datum/antagonist/blob/B = mind.has_antag_datum(/datum/antagonist/blob)
if(!B)
mind.add_antag_datum(/datum/antagonist/blob)
+
+//the same but it's forced to be allowed by default as cameras usually don't allow emoting
+/mob/camera/blob/emote(act, m_type=1, message = null, intentional = FALSE, forced = TRUE)
+ . = ..()
diff --git a/code/modules/antagonists/clockcult/clock_helpers/clock_rites.dm b/code/modules/antagonists/clockcult/clock_helpers/clock_rites.dm
index 59a86ffa34..58ee73ef5b 100644
--- a/code/modules/antagonists/clockcult/clock_helpers/clock_rites.dm
+++ b/code/modules/antagonists/clockcult/clock_helpers/clock_rites.dm
@@ -165,14 +165,16 @@
/datum/clockwork_rite/treat_wounds/cast(var/mob/living/invoker, var/turf/T, var/mob/living/carbon/human/target)
if(!target)
return FALSE
- if(!target.all_wounds.len)
+ if(!target.all_wounds || !target.all_wounds.len)
to_chat(invoker, "This one does not require mending.")
return FALSE
.= ..()
if(!.)
return FALSE
target.adjustToxLoss(10 * target.all_wounds.len)
- QDEL_LIST(target.all_wounds)
+ for(var/i in target.all_wounds)
+ var/datum/wound/mended = i
+ mended.remove_wound()
to_chat(target, "You feel your wounds heal, but are overcome with deep nausea.")
new /obj/effect/temp_visual/ratvar/sigil/vitality(T)
diff --git a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm
index 571a817024..ff6dc12ce1 100644
--- a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm
+++ b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm
@@ -203,10 +203,10 @@
to_chat(user, "You need to hold the slab in your active hand to recite scripture!")
return FALSE
var/initial_tier = initial(scripture.tier)
- if(initial_tier == SCRIPTURE_PERIPHERAL)
+ if(initial_tier == SCRIPTURE_PERIPHERAL && !issilicon(user)) //Silicons use peripheral scripture & cannot open the slab.
to_chat(user, "Nice try using href exploits")
return
- if(!GLOB.ratvar_awakens && !no_cost && !SSticker.scripture_states[initial_tier])
+ if(!GLOB.ratvar_awakens && !no_cost && !SSticker.scripture_states[initial_tier] &&!issilicon(user)) //silicons can't choose their spells, so lets allow them to always cast their assigned ones.
to_chat(user, "That scripture is not unlocked, and cannot be recited!")
return FALSE
var/datum/clockwork_scripture/scripture_to_recite = new scripture
diff --git a/code/modules/antagonists/devil/true_devil/_true_devil.dm b/code/modules/antagonists/devil/true_devil/_true_devil.dm
index 293b1de3dc..069080170e 100644
--- a/code/modules/antagonists/devil/true_devil/_true_devil.dm
+++ b/code/modules/antagonists/devil/true_devil/_true_devil.dm
@@ -11,7 +11,6 @@
gender = NEUTER
health = 350
maxHealth = 350
- ventcrawler = VENTCRAWLER_NONE
density = TRUE
pass_flags = 0
sight = (SEE_TURFS | SEE_OBJS)
diff --git a/code/modules/antagonists/eldritch_cult/eldritch_antag.dm b/code/modules/antagonists/eldritch_cult/eldritch_antag.dm
index ea226a3cb6..1e43754477 100644
--- a/code/modules/antagonists/eldritch_cult/eldritch_antag.dm
+++ b/code/modules/antagonists/eldritch_cult/eldritch_antag.dm
@@ -10,6 +10,8 @@
var/give_equipment = TRUE
var/list/researched_knowledge = list()
var/total_sacrifices = 0
+ var/list/sac_targetted = list() //Which targets did living hearts give them, but they did not sac?
+ var/list/actually_sacced = list() //Which targets did they actually sac?
var/ascended = FALSE
/datum/antagonist/heretic/admin_add(datum/mind/new_owner,mob/admin)
@@ -175,6 +177,17 @@
knowledge_message += "[EK.name]"
parts += knowledge_message.Join(", ")
+ parts += "Targets assigned by living hearts, but not sacrificed:"
+ if(!sac_targetted.len)
+ parts += "None."
+ else
+ parts += sac_targetted.Join(",")
+ parts += "Sacrifices performed:"
+ if(!actually_sacced.len)
+ parts += "None!"
+ else
+ parts += actually_sacced.Join(",")
+
return parts.Join("
")
////////////////
// Knowledge //
@@ -213,6 +226,23 @@
if(ascended)
. += 20
+/datum/antagonist/heretic/antag_panel()
+ var/list/parts = list()
+ parts += ..()
+ parts += "Targets currently assigned by living hearts (Can give a false negative if they stole someone elses living heart):"
+ if(!sac_targetted.len)
+ parts += "None."
+ else
+ parts += sac_targetted.Join(",")
+ parts += "Targets actually sacrificed:"
+ if(!actually_sacced.len)
+ parts += "None."
+ else
+ parts += actually_sacced.Join(",")
+
+ return (parts.Join("
") + "
")
+
+
////////////////
// Objectives //
////////////////
diff --git a/code/modules/antagonists/eldritch_cult/eldritch_items.dm b/code/modules/antagonists/eldritch_cult/eldritch_items.dm
index da2c61ad16..fbf0740e50 100644
--- a/code/modules/antagonists/eldritch_cult/eldritch_items.dm
+++ b/code/modules/antagonists/eldritch_cult/eldritch_items.dm
@@ -6,6 +6,17 @@
w_class = WEIGHT_CLASS_SMALL
///Target
var/mob/living/carbon/human/target
+ var/datum/antagonist/heretic/sac_targetter //The heretic who used this to acquire the current target - gets cleared when target gets sacrificed.
+
+/obj/item/living_heart/Initialize()
+ . = ..()
+ GLOB.living_heart_cache.Add(src) //Add is better than +=.
+
+/obj/item/living_heart/Destroy()
+ GLOB.living_heart_cache.Remove(src)
+ if(sac_targetter && target)
+ sac_targetter.sac_targetted.Remove(target.real_name)
+ return ..()
/obj/item/living_heart/attack_self(mob/user)
. = ..()
diff --git a/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm b/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm
index e0189944e5..481ac08ea5 100644
--- a/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm
+++ b/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm
@@ -1,6 +1,6 @@
/**
- * #Eldritch Knwoledge
+ * #Eldritch Knowledge
*
* Datum that makes eldritch cultist interesting.
*
@@ -252,6 +252,10 @@
LH.target = null
var/datum/antagonist/heretic/EC = carbon_user.mind.has_antag_datum(/datum/antagonist/heretic)
+ EC.actually_sacced.Add(H.real_name)
+ if(LH.sac_targetter)
+ LH.sac_targetter.sac_targetted.Remove(H.real_name)
+ LH.sac_targetter = null
EC.total_sacrifices++
for(var/X in carbon_user.get_all_gear())
if(!istype(X,/obj/item/forbidden_book))
@@ -265,8 +269,14 @@
var/datum/objective/A = new
A.owner = user.mind
var/list/targets = list()
+ var/list/target_blacklist = list()
+ for(var/obj/item/living_heart/CLH in GLOB.living_heart_cache)
+ if(!CLH || !CLH.target || !CLH.target.mind)
+ continue
+ target_blacklist.Add(CLH.target.mind)
+
for(var/i in 0 to 3)
- var/datum/mind/targeted = A.find_target()//easy way, i dont feel like copy pasting that entire block of code
+ var/datum/mind/targeted = A.find_target(blacklist = target_blacklist)//easy way, i dont feel like copy pasting that entire block of code
if(!targeted)
break
targets[targeted.current.real_name] = targeted.current
@@ -274,9 +284,24 @@
if(!LH.target && targets.len)
LH.target = pick(targets) //Tsk tsk, you can and will get another target if you want it or not.
+
+ if(LH.target)
+ target_blacklist = list()
+ for(var/obj/item/living_heart/CLH in (GLOB.living_heart_cache - LH)) //Recreate blacklist, excluding ourselves.
+ if(!CLH || !CLH.target || !CLH.target.mind)
+ continue
+ target_blacklist.Add(CLH.target.mind)
+ if(LH.target.mind in target_blacklist) //Someone was faster, or you tried to cheese the system.
+ to_chat(user, "It seems you were too slow, and your target of choice has already been selected by another living heart!")
+ LH.target = null
+
qdel(A)
if(LH.target)
to_chat(user,"Your new target has been selected, go and sacrifice [LH.target.real_name]!")
+ var/datum/antagonist/heretic/EC = carbon_user.mind.has_antag_datum(/datum/antagonist/heretic)
+ LH.sac_targetter = EC
+ EC.sac_targetted.Add(LH.target.real_name)
+
else
to_chat(user,"target could not be found for living heart.")
diff --git a/code/modules/antagonists/morph/morph.dm b/code/modules/antagonists/morph/morph.dm
index 5844aad02b..077c380ef0 100644
--- a/code/modules/antagonists/morph/morph.dm
+++ b/code/modules/antagonists/morph/morph.dm
@@ -15,7 +15,6 @@
stop_automated_movement = 1
status_flags = CANPUSH
pass_flags = PASSTABLE
- ventcrawler = VENTCRAWLER_ALWAYS
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
maxHealth = 150
@@ -53,6 +52,10 @@
You can attack any item or dead creature to consume it - creatures will fully restore your health. \
Finally, you can restore yourself to your original form while morphed by shift-clicking yourself."
+/mob/living/simple_animal/hostile/morph/Initialize()
+ . = ..()
+ src.AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
+
/mob/living/simple_animal/hostile/morph/examine(mob/user)
if(morphed)
. = form.examine(user)
diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm
index f5ebcffe35..ef58e5af39 100644
--- a/code/modules/antagonists/revenant/revenant.dm
+++ b/code/modules/antagonists/revenant/revenant.dm
@@ -72,6 +72,7 @@
var/list/drained_mobs = list() //Cannot harvest the same mob twice
var/perfectsouls = 0 //How many perfect, regen-cap increasing souls the revenant has. //TODO, add objective for getting a perfect soul(s?)
var/generated_objectives_and_spells = FALSE
+ var/telekinesis_cooldown
/mob/living/simple_animal/revenant/Initialize(mapload)
. = ..()
@@ -93,13 +94,16 @@
/mob/living/simple_animal/revenant/Login()
..()
- to_chat(src, "You are a revenant.")
- to_chat(src, "Your formerly mundane spirit has been infused with alien energies and empowered into a revenant.")
- to_chat(src, "You are not dead, not alive, but somewhere in between. You are capable of limited interaction with both worlds.")
- to_chat(src, "You are invincible and invisible to everyone but other ghosts. Most abilities will reveal you, rendering you vulnerable.")
- to_chat(src, "To function, you are to drain the life essence from humans. This essence is a resource, as well as your health, and will power all of your abilities.")
- to_chat(src, "You do not remember anything of your past lives, nor will you remember anything about this one after your death.")
- to_chat(src, "Be sure to read the wiki page to learn more.")
+ var/revenant_greet
+ revenant_greet += "You are a revenant."
+ revenant_greet += "Your formerly mundane spirit has been infused with alien energies and empowered into a revenant."
+ revenant_greet += "You are not dead, not alive, but somewhere in between. You are capable of limited interaction with both worlds."
+ revenant_greet += "You are invincible and invisible to everyone but other ghosts. Most abilities will reveal you, rendering you vulnerable."
+ revenant_greet += "To function, you are to drain the life essence from humans. This essence is a resource, as well as your health, and will power all of your abilities."
+ revenant_greet += "You do not remember anything of your past lives, nor will you remember anything about this one after your death."
+ revenant_greet += "Be sure to read the wiki page to learn more."
+ revenant_greet += "You are also able to telekinetically throw objects by clickdragging them."
+ to_chat(src, revenant_greet)
if(!generated_objectives_and_spells)
generated_objectives_and_spells = TRUE
mind.assigned_role = ROLE_REVENANT
@@ -317,6 +321,12 @@
to_chat(src, "Lost [essence_amt]E[source ? " from [source]":""].")
return 1
+/mob/living/simple_animal/revenant/proc/telekinesis_cooldown_end()
+ if(!telekinesis_cooldown)
+ CRASH("telekinesis_cooldown_end ran when telekinesis_cooldown on [src] was false")
+ else
+ telekinesis_cooldown = FALSE
+
/mob/living/simple_animal/revenant/proc/death_reset()
revealed = FALSE
unreveal_time = 0
@@ -431,6 +441,38 @@
qdel(revenant)
..()
+/proc/RevenantThrow(over, mob/user, obj/item/throwable)
+ var/mob/living/simple_animal/revenant/spooker = user
+ if(!istype(throwable))
+ return
+ if(!throwable.anchored && !spooker.telekinesis_cooldown && spooker.essence > 20)
+ if(7 < get_dist(throwable, spooker))
+ return
+ if(3 >= get_dist(throwable, spooker))
+ spooker.stun(10)
+ spooker.reveal(25)
+ else
+ spooker.stun(20)
+ spooker.reveal(50)
+ spooker.change_essence_amount(-20, FALSE, "telekinesis")
+ spooker.telekinesis_cooldown = TRUE
+ throwable.float(TRUE, TRUE)
+ sleep(20)
+ throwable.DoRevenantThrowEffects(over)
+ throwable.throw_at(over, 10, 2)
+ ADD_TRAIT(throwable, TRAIT_SPOOKY_THROW, "revenant")
+ log_combat(throwable, over, "spooky telekinesised at", throwable)
+ var/obj/effect/temp_visual/telekinesis/T = new(get_turf(throwable))
+ T.color = "#8715b4"
+ addtimer(CALLBACK(spooker, /mob/living/simple_animal/revenant.proc/telekinesis_cooldown_end), 50)
+ sleep(5)
+ throwable.float(FALSE, TRUE)
+
+
+//Use this for effects you want to happen when a revenant throws stuff, check the TRAIT_SPOOKY_THROW if you want to know if its still being thrown
+/obj/item/proc/DoRevenantThrowEffects(atom/target)
+ return TRUE
+
//objectives
/datum/objective/revenant
var/targetAmount = 100
diff --git a/code/modules/antagonists/swarmer/swarmer.dm b/code/modules/antagonists/swarmer/swarmer.dm
index 7444905b89..d1bdac7e05 100644
--- a/code/modules/antagonists/swarmer/swarmer.dm
+++ b/code/modules/antagonists/swarmer/swarmer.dm
@@ -93,7 +93,6 @@
AIStatus = AI_OFF
pass_flags = PASSTABLE
mob_size = MOB_SIZE_TINY
- ventcrawler = VENTCRAWLER_ALWAYS
ranged = 1
projectiletype = /obj/item/projectile/beam/disabler
ranged_cooldown_time = 20
@@ -112,6 +111,7 @@
remove_verb(src, /mob/living/verb/pulled)
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
diag_hud.add_to_hud(src)
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/mob/living/simple_animal/hostile/swarmer/med_hud_set_health()
var/image/holder = hud_list[DIAG_HUD]
diff --git a/code/modules/antagonists/traitor/equipment/contractor.dm b/code/modules/antagonists/traitor/equipment/contractor.dm
index 28298f4983..525f40d1f7 100644
--- a/code/modules/antagonists/traitor/equipment/contractor.dm
+++ b/code/modules/antagonists/traitor/equipment/contractor.dm
@@ -43,7 +43,7 @@
var/list/to_generate = list(
CONTRACT_PAYOUT_LARGE,
CONTRACT_PAYOUT_MEDIUM,
- CONTRACT_PAYOUT_SMALL,
+ CONTRACT_PAYOUT_MEDIUM,
CONTRACT_PAYOUT_SMALL,
CONTRACT_PAYOUT_SMALL,
CONTRACT_PAYOUT_SMALL
diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm
index 8a0645f311..07a9f499f8 100644
--- a/code/modules/assembly/flash.dm
+++ b/code/modules/assembly/flash.dm
@@ -30,6 +30,9 @@
attack(user,user)
return FIRELOSS
+/obj/item/assembly/flash/DoRevenantThrowEffects(atom/target)
+ AOE_flash()
+
/obj/item/assembly/flash/update_icon(flash = FALSE)
cut_overlays()
attached_overlays = list()
diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm
index 25e4084524..7f4a8cd794 100644
--- a/code/modules/atmospherics/machinery/atmosmachinery.dm
+++ b/code/modules/atmospherics/machinery/atmosmachinery.dm
@@ -44,7 +44,7 @@
. = ..()
if(is_type_in_list(src, GLOB.ventcrawl_machinery) && isliving(user))
var/mob/living/L = user
- if(L.ventcrawler)
+ if(SEND_SIGNAL(L, COMSIG_CHECK_VENTCRAWL))
. += "Alt-click to crawl through it."
/obj/machinery/atmospherics/New(loc, process = TRUE, setdir)
@@ -318,7 +318,7 @@
/obj/machinery/atmospherics/AltClick(mob/living/L)
if(is_type_in_typecache(src, GLOB.ventcrawl_machinery))
- return L.handle_ventcrawl(src)
+ return SEND_SIGNAL(L, COMSIG_HANDLE_VENTCRAWL, src)
return ..()
diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm
index 07039139bf..807251111a 100644
--- a/code/modules/food_and_drinks/drinks/drinks.dm
+++ b/code/modules/food_and_drinks/drinks/drinks.dm
@@ -17,10 +17,7 @@
var/isGlass = TRUE //Whether the 'bottle' is made of glass or not so that milk cartons dont shatter when someone gets hit by it
/obj/item/reagent_containers/food/drinks/on_reagent_change(changetype)
- if (gulp_size < 5)
- gulp_size = 5
- else
- gulp_size = max(round(reagents.total_volume / 5), 5)
+ gulp_size = max(round(reagents.total_volume / 5), 5)
/obj/item/reagent_containers/food/drinks/attack(mob/living/M, mob/user, def_zone)
if(!reagents || !reagents.total_volume)
diff --git a/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm b/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm
index 8e5069925f..9602c1d24e 100644
--- a/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm
+++ b/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm
@@ -52,10 +52,7 @@
/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/on_reagent_change(changetype)
cut_overlays()
- if (gulp_size < 15)
- gulp_size = 15
- else
- gulp_size = max(round(reagents.total_volume / 15), 15)
+ gulp_size = max(round(reagents.total_volume / 15), 15)
if (reagents.reagent_list.len > 0)
var/datum/reagent/largest_reagent = reagents.get_master_reagent()
diff --git a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
index 6bdf3cff8e..5954788d5c 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
@@ -151,10 +151,13 @@
to_chat(user, "You need more space cleaner!")
return TRUE
- if(istype(O, /obj/item/soap))
- var/obj/item/soap/P = O
+ if(istype(O, /obj/item/soap) || istype(O, /obj/item/reagent_containers/rag))
+ var/cleanspeed = 50
+ if(istype(O, /obj/item/soap))
+ var/obj/item/soap/used_soap = O
+ cleanspeed = used_soap.cleanspeed
user.visible_message("[user] starts to clean \the [src].", "You start to clean \the [src]...")
- if(do_after(user, P.cleanspeed, target = src))
+ if(do_after(user, cleanspeed, target = src))
user.visible_message("[user] has cleaned \the [src].", "You clean \the [src].")
dirty = 0
update_icon()
diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm
index 8467d00124..24f65756c8 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -92,6 +92,11 @@
return BULLET_ACT_HIT
else if(istype(Proj , /obj/item/projectile/energy/florayield))
return myseed.bullet_act(Proj)
+ else if(istype(Proj , /obj/item/projectile/energy/florarevolution))
+ if(myseed)
+ if(myseed.mutatelist.len > 0)
+ myseed.instability = (myseed.instability/2)
+ mutatespecie()
else
return ..()
@@ -384,7 +389,6 @@
/obj/machinery/hydroponics/proc/hardmutate()
mutate(4, 10, 2, 4, 50, 4, 10, 3)
-
/obj/machinery/hydroponics/proc/mutatespecie() // Mutagent produced a new plant!
if(!myseed || dead)
return
@@ -600,7 +604,34 @@
desc = initial(desc)
weedlevel = 0 //Has a side effect of cleaning up those nasty weeds
update_icon()
-
+ else if(istype(O, /obj/item/gun/energy/floragun))
+ var/obj/item/gun/energy/floragun/flowergun = O
+ if(flowergun.cell.charge < flowergun.cell.maxcharge)
+ to_chat(user, "[flowergun] must be fully charged to lock in a mutation!")
+ return
+ if(!myseed)
+ to_chat(user, "[src] is empty!")
+ return
+ if(myseed.endurance <= 20)
+ to_chat(user, "[myseed.plantname] isn't hardy enough to sequence its mutation!")
+ return
+ if(!myseed.mutatelist)
+ to_chat(user, "[myseed.plantname] has nothing else to mutate into!")
+ return
+ else
+ var/list/fresh_mut_list = list()
+ for(var/muties in myseed.mutatelist)
+ var/obj/item/seeds/another_mut = new muties
+ fresh_mut_list[another_mut.plantname] = muties
+ var/locked_mutation = (input(user, "Select a mutation to lock.", "Plant Mutation Locks") as null|anything in sortList(fresh_mut_list))
+ if(!user.canUseTopic(src, BE_CLOSE) || !locked_mutation)
+ return
+ myseed.mutatelist = list(fresh_mut_list[locked_mutation])
+ myseed.endurance = (myseed.endurance/2)
+ flowergun.cell.use(flowergun.cell.charge)
+ flowergun.update_icon()
+ to_chat(user, "[myseed.plantname]'s mutation was set to [locked_mutation], depleting [flowergun]'s cell!")
+ return
else
return ..()
diff --git a/code/modules/integrated_electronics/core/integrated_circuit.dm b/code/modules/integrated_electronics/core/integrated_circuit.dm
index f90b584d76..92d2aa270f 100644
--- a/code/modules/integrated_electronics/core/integrated_circuit.dm
+++ b/code/modules/integrated_electronics/core/integrated_circuit.dm
@@ -378,7 +378,7 @@ a creative player the means to solve many problems. Circuits are held inside an
// Checks if the target object is reachable. Useful for various manipulators and manipulator-like objects.
-/obj/item/integrated_circuit/proc/check_target(atom/target, exclude_contents = FALSE, exclude_components = FALSE, exclude_self = FALSE)
+/obj/item/integrated_circuit/proc/check_target(atom/target, exclude_contents = FALSE, exclude_components = FALSE, exclude_self = FALSE, exclude_outside = FALSE)
if(!target)
return FALSE
@@ -394,7 +394,7 @@ a creative player the means to solve many problems. Circuits are held inside an
if(target == assembly.battery)
return FALSE
- if(target.Adjacent(acting_object) && isturf(target.loc))
+ if(!exclude_outside && target.Adjacent(acting_object) && isturf(target.loc))
return TRUE
if(!exclude_contents && (target in acting_object.GetAllContents()))
diff --git a/code/modules/integrated_electronics/subtypes/manipulation.dm b/code/modules/integrated_electronics/subtypes/manipulation.dm
index eac16d2950..e32f8daa2d 100644
--- a/code/modules/integrated_electronics/subtypes/manipulation.dm
+++ b/code/modules/integrated_electronics/subtypes/manipulation.dm
@@ -186,6 +186,8 @@
AM.forceMove(src)
/obj/item/integrated_circuit/manipulation/grabber/proc/drop(obj/item/AM, turf/T = drop_location())
+ if(!check_target(AM, FALSE, TRUE, TRUE, TRUE))
+ return
var/atom/A = get_object()
A.investigate_log("dropped ([AM]) from [src].", INVESTIGATE_CIRCUIT)
AM.forceMove(T)
diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm
index e7ad67d240..7c80d1d426 100644
--- a/code/modules/mob/living/carbon/alien/alien.dm
+++ b/code/modules/mob/living/carbon/alien/alien.dm
@@ -4,7 +4,6 @@
gender = FEMALE //All xenos are girls!!
dna = null
faction = list(ROLE_ALIEN)
- ventcrawler = VENTCRAWLER_ALWAYS
sight = SEE_MOBS
see_in_dark = 4
verb_say = "hisses"
@@ -19,7 +18,6 @@
/// How much brute damage they do to simple animals
var/meleeSlashSAPower = 35
- var/obj/item/card/id/wear_id = null // Fix for station bounced radios -- Skie
var/has_fine_manipulation = 0
var/move_delay_add = 0 // movement delay to add
@@ -40,6 +38,8 @@
create_internal_organs()
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
+
. = ..()
/mob/living/carbon/alien/create_internal_organs()
diff --git a/code/modules/mob/living/carbon/alien/humanoid/queen.dm b/code/modules/mob/living/carbon/alien/humanoid/queen.dm
index 91a61efea6..42b62e37a0 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/queen.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/queen.dm
@@ -2,7 +2,6 @@
//Common stuffs for Praetorian and Queen
icon = 'icons/mob/alienqueen.dmi'
status_flags = 0
- ventcrawler = VENTCRAWLER_NONE //pull over that ass too fat
unique_name = 0
pixel_x = -16
bubble_icon = "alienroyal"
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 45a0d82d2c..979baeb065 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -1229,3 +1229,25 @@
*/
/mob/living/carbon/proc/get_biological_state()
return BIO_FLESH_BONE
+
+/mob/living/carbon/altattackby(obj/item/W, mob/living/carbon/user, params)
+ if(user.incapacitated() || !user.Adjacent(src))
+ return FALSE
+ if(W && user.a_intent == INTENT_HELP && W.can_give())
+ user.give()
+ return TRUE
+
+/mob/living/carbon/verb/give_verb()
+ set src in oview(1)
+ set category = "IC"
+ set name = "Give"
+
+ if(usr.incapacitated() || !usr.Adjacent(src))
+ return
+
+ if(!usr.get_active_held_item()) // Let me know if this has any problems -Yota
+ return
+ var/obj/item/I = usr.get_active_held_item()
+ var/mob/living/carbon/C = usr
+ if(I.can_give())
+ C.give()
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 94d7e84c6b..8d473639b4 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -1796,12 +1796,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
"[M] attempted to touch you!", target = M, \
target_message = "You attempted to touch [H]!")
return TRUE
+ if(M == H)
+ althelp(M, H, attacker_style)
+ return TRUE
switch(M.a_intent)
- if(INTENT_HELP)
- if(M == H)
- althelp(M, H, attacker_style)
- return TRUE
- return FALSE
if(INTENT_DISARM)
altdisarm(M, H, attacker_style)
return TRUE
@@ -1987,6 +1985,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.show_message("The radiation beam dissipates harmlessly through your body.")
if(/obj/item/projectile/energy/florayield)
H.show_message("The radiation beam dissipates harmlessly through your body.")
+ if(/obj/item/projectile/energy/florarevolution)
+ H.show_message("The radiation beam dissipates harmlessly through your body.")
/datum/species/proc/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H)
// called before a projectile hit
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index ff0287d7b9..75aff774ce 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -801,11 +801,11 @@
/datum/species/golem/plastic/on_species_gain(mob/living/carbon/C, datum/species/old_species)
. = ..()
- C.ventcrawler = VENTCRAWLER_NUDE
+ C.AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/datum/species/golem/plastic/on_species_loss(mob/living/carbon/C)
. = ..()
- C.ventcrawler = initial(C.ventcrawler)
+ C.RemoveElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/datum/species/golem/bronze
name = "Bronze Golem"
diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
index c25c5efb6c..697c3db35e 100644
--- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
@@ -64,6 +64,11 @@
H.show_message("The radiation beam singes you!")
if(/obj/item/projectile/energy/florayield)
H.adjust_nutrition(30, NUTRITION_LEVEL_FULL)
+ if(/obj/item/projectile/energy/florarevolution)
+ H.show_message("The radiation beam leaves you feeling disoriented!")
+ H.Dizzy(15)
+ H.emote("flip")
+ H.emote("spin")
/datum/species/pod/pseudo_weak
name = "Anthromorphic Plant"
diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm
index 558fdc6594..5e07150ce6 100644
--- a/code/modules/mob/living/carbon/human/species_types/vampire.dm
+++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm
@@ -169,7 +169,7 @@
if(istype(H, /mob/living/simple_animal))
var/mob/living/simple_animal/SA = H
if((human_caster.blood_volume <= (BLOOD_VOLUME_BAD*human_caster.blood_ratio)) || (ventcrawl_nude_only && length(human_caster.get_equipped_items(include_pockets = TRUE))))
- SA.ventcrawler = FALSE
+ SA.RemoveElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
if(transfer_name)
H.name = human_caster.name
diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm
index 1f3e0a1b81..d49059f839 100644
--- a/code/modules/mob/living/carbon/monkey/monkey.dm
+++ b/code/modules/mob/living/carbon/monkey/monkey.dm
@@ -6,7 +6,6 @@
icon_state = ""
gender = NEUTER
pass_flags = PASSTABLE
- ventcrawler = VENTCRAWLER_NUDE
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/monkey = 5, /obj/item/stack/sheet/animalhide/monkey = 1)
type_of_meat = /obj/item/reagent_containers/food/snacks/meat/slab/monkey
@@ -29,6 +28,8 @@
create_bodyparts()
create_internal_organs()
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_NUDE)
+
. = ..()
if (cubespawned)
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 742d4d8624..386f1174e1 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -81,7 +81,6 @@
var/bloodcrawl = 0 //0 No blood crawling, BLOODCRAWL for bloodcrawling, BLOODCRAWL_EAT for crawling+mob devour
var/holder = null //The holder for blood crawling
- var/ventcrawler = 0 //0 No vent crawling, 1 vent crawling in the nude, 2 vent crawling always
var/limb_destroyer = 0 //1 Sets AI behavior that allows mobs to target and dismember limbs with their basic attack.
var/mob_size = MOB_SIZE_HUMAN
diff --git a/code/modules/mob/living/login.dm b/code/modules/mob/living/login.dm
index 931f87eb7c..2b1c2de17a 100644
--- a/code/modules/mob/living/login.dm
+++ b/code/modules/mob/living/login.dm
@@ -17,10 +17,6 @@
if (isturf(T))
update_z(T.z)
- //Vents
- if(ventcrawler)
- to_chat(src, "You can ventcrawl! Use alt+click on vents to quickly travel about the station.")
-
if(ranged_ability)
ranged_ability.add_ranged_ability(src, "You currently have [ranged_ability] active!")
if((vore_flags & VORE_INIT) && !(vore_flags & VOREPREF_INIT)) //Vore's been initialized, voreprefs haven't. If this triggers then that means that voreprefs failed to load due to the client being missing.
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 823f759e67..e0e1d91ba9 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -1039,3 +1039,6 @@
if(current && eyeobj)
return eyeobj.emote(act, m_type, message, intentional, forced = TRUE)
return ..()
+
+/mob/living/silicon/ai/zMove(dir, feedback = FALSE)
+ . = eyeobj.zMove(dir, feedback)
diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm
index 17de811cdd..dcaa28b39c 100644
--- a/code/modules/mob/living/silicon/ai/freelook/eye.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm
@@ -94,6 +94,25 @@
if(ai.master_multicam)
ai.master_multicam.refresh_view()
+//it uses setLoc not forceMove, talks to the sillycone and not the camera mob
+/mob/camera/aiEye/zMove(dir, feedback = FALSE)
+ if(dir != UP && dir != DOWN)
+ return FALSE
+ var/turf/target = get_step_multiz(src, dir)
+ if(!target)
+ if(feedback)
+ to_chat(ai, "There's nowhere to go in that direction!")
+ return FALSE
+ if(!canZMove(dir, target))
+ if(feedback)
+ to_chat(ai, "You couldn't move there!")
+ return FALSE
+ setLoc(target, TRUE)
+ return TRUE
+
+/mob/camera/aiEye/canZMove(direction, turf/target) //cameras do not respect these FLOORS you speak so much of
+ return TRUE
+
/mob/camera/aiEye/Move()
return 0
diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm
index 0ba4023864..ff6941ec70 100644
--- a/code/modules/mob/living/simple_animal/bot/floorbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm
@@ -335,6 +335,11 @@
/mob/living/simple_animal/bot/floorbot/proc/repair(turf/target_turf)
+ if(check_bot_working(target_turf))
+ add_to_ignore(target_turf)
+ target = null
+ playsound(src, 'sound/effects/whistlereset.ogg', 50, TRUE)
+ return
if(isspaceturf(target_turf))
//Must be a hull breach or in line mode to continue.
if(!is_hull_breach(target_turf) && !targetdirection)
@@ -418,3 +423,14 @@
repair(A)
else
..()
+
+/**
+ * Checks a given turf to see if another floorbot is there, working as well.
+ */
+/mob/living/simple_animal/bot/floorbot/proc/check_bot_working(turf/active_turf)
+ if(isturf(active_turf))
+ for(var/mob/living/simple_animal/bot/floorbot/robot in active_turf)
+ if(robot.mode == BOT_REPAIRING)
+ return TRUE
+ return FALSE
+
diff --git a/code/modules/mob/living/simple_animal/friendly/bumbles.dm b/code/modules/mob/living/simple_animal/friendly/bumbles.dm
index 0debb7b98c..6ed6d03b68 100644
--- a/code/modules/mob/living/simple_animal/friendly/bumbles.dm
+++ b/code/modules/mob/living/simple_animal/friendly/bumbles.dm
@@ -20,7 +20,6 @@
density = FALSE
movement_type = FLYING
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
- ventcrawler = VENTCRAWLER_ALWAYS
mob_size = MOB_SIZE_TINY
mob_biotypes = MOB_ORGANIC|MOB_BEAST
gold_core_spawnable = FRIENDLY_SPAWN
@@ -35,6 +34,7 @@
/mob/living/simple_animal/pet/bumbles/Initialize()
. = ..()
add_verb(src, /mob/living/proc/lay_down)
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/mob/living/simple_animal/pet/bumbles/ComponentInitialize()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/friendly/butterfly.dm b/code/modules/mob/living/simple_animal/friendly/butterfly.dm
index bf4f45e283..1e6afd6044 100644
--- a/code/modules/mob/living/simple_animal/friendly/butterfly.dm
+++ b/code/modules/mob/living/simple_animal/friendly/butterfly.dm
@@ -20,7 +20,6 @@
density = FALSE
movement_type = FLYING
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
- ventcrawler = VENTCRAWLER_ALWAYS
mob_size = MOB_SIZE_TINY
mob_biotypes = MOB_ORGANIC|MOB_BUG
gold_core_spawnable = FRIENDLY_SPAWN
@@ -33,6 +32,7 @@
. = ..()
var/newcolor = rgb(rand(0, 255), rand(0, 255), rand(0, 255))
add_atom_colour(newcolor, FIXED_COLOUR_PRIORITY)
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/mob/living/simple_animal/butterfly/bee_friendly()
return TRUE //treaty signed at the Beeneeva convention
diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm
index 71ae3b4c03..4594d27ecd 100644
--- a/code/modules/mob/living/simple_animal/friendly/cat.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cat.dm
@@ -14,7 +14,6 @@
speak_chance = 1
turns_per_move = 5
see_in_dark = 6
- ventcrawler = VENTCRAWLER_ALWAYS
pass_flags = PASSTABLE
mob_size = MOB_SIZE_SMALL
mob_biotypes = MOB_ORGANIC|MOB_BEAST
@@ -40,6 +39,7 @@
/mob/living/simple_animal/pet/cat/Initialize()
. = ..()
add_verb(src, /mob/living/proc/lay_down)
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/mob/living/simple_animal/pet/cat/ComponentInitialize()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/friendly/cockroach.dm b/code/modules/mob/living/simple_animal/friendly/cockroach.dm
index f33c179911..f65b2bab9b 100644
--- a/code/modules/mob/living/simple_animal/friendly/cockroach.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cockroach.dm
@@ -22,7 +22,6 @@
response_harm_simple = "splat"
speak_emote = list("chitters")
density = FALSE
- ventcrawler = VENTCRAWLER_ALWAYS
mob_size = MOB_SIZE_TINY
gold_core_spawnable = FRIENDLY_SPAWN
verb_say = "chitters"
@@ -32,6 +31,10 @@
var/squish_chance = 50
del_on_death = 1
+/mob/living/simple_animal/cockroach/Initialize()
+ . = ..()
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
+
/mob/living/simple_animal/cockroach/death(gibbed)
if(SSticker.mode && SSticker.mode.station_was_nuked) //If the nuke is going off, then cockroaches are invincible. Keeps the nuke from killing them, cause cockroaches are immune to nukes.
return
diff --git a/code/modules/mob/living/simple_animal/friendly/crab.dm b/code/modules/mob/living/simple_animal/friendly/crab.dm
index 7f3693f622..addbd493a5 100644
--- a/code/modules/mob/living/simple_animal/friendly/crab.dm
+++ b/code/modules/mob/living/simple_animal/friendly/crab.dm
@@ -21,12 +21,15 @@
stop_automated_movement = 1
friendly_verb_continuous = "pinches"
friendly_verb_simple = "pinch"
- ventcrawler = VENTCRAWLER_ALWAYS
mob_size = MOB_SIZE_TINY
var/obj/item/inventory_head
var/obj/item/inventory_mask
gold_core_spawnable = FRIENDLY_SPAWN
+/mob/living/simple_animal/crab/Initialize()
+ . = ..()
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
+
/mob/living/simple_animal/crab/BiologicalLife(seconds, times_fired)
if(!(. = ..()))
return
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
index a8c0e7d207..e11facb4ba 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
@@ -28,7 +28,6 @@
unsuitable_atmos_damage = 0
wander = 0
speed = 0
- ventcrawler = VENTCRAWLER_ALWAYS
healable = 0
density = FALSE
pass_flags = PASSTABLE | PASSMOB
@@ -101,6 +100,8 @@
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
diag_hud.add_to_hud(src)
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
+
/mob/living/simple_animal/drone/ComponentInitialize()
. = ..()
if(can_be_held)
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm
index 55339a02fd..22dbdd3db7 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm
@@ -114,7 +114,6 @@
harm_intent_damage = 5
density = TRUE
speed = 1
- ventcrawler = VENTCRAWLER_NONE
faction = list("neutral", "ratvar")
speak_emote = list("clanks", "clinks", "clunks", "clangs")
verb_ask = "requests"
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
index 54184310a8..11d7884999 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
@@ -110,7 +110,7 @@
to_chat(src, "Your onboard antivirus has initiated lockdown. Motor servos are impaired, ventilation access is denied, and your display reports that you are hacked to all nearby.")
hacked = TRUE
mind.special_role = "hacked drone"
- ventcrawler = VENTCRAWLER_NONE //Again, balance
+ RemoveElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) // balance
speed = 1 //gotta go slow
message_admins("[src] ([src.key]) became a hacked drone hellbent on [clockwork ? "serving Ratvar" : "destroying the station"]!")
else
@@ -125,7 +125,7 @@
to_chat(src, "Having been restored, your onboard antivirus reports the all-clear and you are able to perform all actions again.")
hacked = FALSE
mind.special_role = null
- ventcrawler = initial(ventcrawler)
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
speed = initial(speed)
if(is_servant_of_ratvar(src))
remove_servant_of_ratvar(src, TRUE)
diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
index 51e7ee6c03..81925d922f 100644
--- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
+++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
@@ -241,7 +241,6 @@
attack_verb_simple = "kick"
health = 3
maxHealth = 3
- ventcrawler = VENTCRAWLER_ALWAYS
var/amount_grown = 0
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
mob_size = MOB_SIZE_TINY
@@ -253,6 +252,7 @@
. = ..()
pixel_x = rand(-6, 6)
pixel_y = rand(0, 10)
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/mob/living/simple_animal/chick/BiologicalLife(seconds, times_fired)
if(!(. = ..()))
@@ -296,7 +296,6 @@
attack_verb_simple = "kick"
health = 15
maxHealth = 15
- ventcrawler = VENTCRAWLER_ALWAYS
var/eggsleft = 0
var/eggsFertile = TRUE
var/body_color
@@ -322,6 +321,8 @@
pixel_y = rand(0, 10)
++chicken_count
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
+
/mob/living/simple_animal/chicken/Destroy()
--chicken_count
return ..()
@@ -392,7 +393,6 @@
attack_verb_simple = "kick"
health = 25
maxHealth = 25
- ventcrawler = VENTCRAWLER_ALWAYS
var/eggsleft = 0
var/eggsFertile = TRUE
pass_flags = PASSTABLE | PASSMOB
@@ -412,6 +412,8 @@
. = ..()
++kiwi_count
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
+
/mob/living/simple_animal/kiwi/BiologicalLife(seconds, times_fired)
if(!(. = ..()))
return
@@ -473,7 +475,6 @@
attack_verb_simple = "kick"
health = 10
maxHealth = 10
- ventcrawler = VENTCRAWLER_ALWAYS
var/amount_grown = 0
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
mob_size = MOB_SIZE_TINY
@@ -486,6 +487,8 @@
pixel_x = rand(-6, 6)
pixel_y = rand(0, 10)
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
+
/mob/living/simple_animal/babyKiwi/BiologicalLife(seconds, times_fired)
if(!(. = ..()))
return
diff --git a/code/modules/mob/living/simple_animal/friendly/lizard.dm b/code/modules/mob/living/simple_animal/friendly/lizard.dm
index b9ff99b677..fd0095bf87 100644
--- a/code/modules/mob/living/simple_animal/friendly/lizard.dm
+++ b/code/modules/mob/living/simple_animal/friendly/lizard.dm
@@ -18,7 +18,6 @@
response_disarm_simple = "shoo"
response_harm_continuous = "stomps on"
response_harm_simple = "stomp on"
- ventcrawler = VENTCRAWLER_ALWAYS
density = FALSE
pass_flags = PASSTABLE | PASSMOB
mob_size = MOB_SIZE_SMALL
@@ -31,6 +30,7 @@
/mob/living/simple_animal/hostile/lizard/ComponentInitialize()
. = ..()
AddElement(/datum/element/mob_holder, worn_state = "lizard", inv_slots = ITEM_SLOT_HEAD) //you can hold lizards now.
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/mob/living/simple_animal/hostile/lizard/CanAttack(atom/the_target)//Can we actually attack a possible target?
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm
index 51c903ee16..8348af43fa 100644
--- a/code/modules/mob/living/simple_animal/friendly/mouse.dm
+++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm
@@ -22,7 +22,6 @@
response_harm_continuous = "splats"
response_harm_simple = "splat"
density = FALSE
- ventcrawler = VENTCRAWLER_ALWAYS
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
mob_size = MOB_SIZE_TINY
mob_biotypes = MOB_ORGANIC|MOB_BEAST
@@ -40,6 +39,7 @@
icon_state = "mouse_[body_color]"
icon_living = "mouse_[body_color]"
icon_dead = "mouse_[body_color]_dead"
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/mob/living/simple_animal/mouse/proc/splat()
src.health = 0
diff --git a/code/modules/mob/living/simple_animal/friendly/possum.dm b/code/modules/mob/living/simple_animal/friendly/possum.dm
index 71fdbd1465..5e7ed572e2 100644
--- a/code/modules/mob/living/simple_animal/friendly/possum.dm
+++ b/code/modules/mob/living/simple_animal/friendly/possum.dm
@@ -22,12 +22,15 @@
response_harm_continuous = "stamps on"
response_harm_simple = "stamp"
density = FALSE
- ventcrawler = VENTCRAWLER_ALWAYS
pass_flags = PASSTABLE | PASSMOB
mob_size = MOB_SIZE_TINY
mob_biotypes = MOB_ORGANIC|MOB_BEAST
gold_core_spawnable = FRIENDLY_SPAWN
+/mob/living/simple_animal/opossum/Initialize()
+ . = ..()
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
+
/mob/living/simple_animal/opossum/poppy
name = "Poppy the Safety Possum"
desc = "Safety first!"
diff --git a/code/modules/mob/living/simple_animal/friendly/snake.dm b/code/modules/mob/living/simple_animal/friendly/snake.dm
index 4d20b927a6..61c735c7c1 100644
--- a/code/modules/mob/living/simple_animal/friendly/snake.dm
+++ b/code/modules/mob/living/simple_animal/friendly/snake.dm
@@ -30,7 +30,6 @@
response_harm_continuous = "steps on"
response_harm_simple = "step on"
faction = list("hostile")
- ventcrawler = VENTCRAWLER_ALWAYS
density = FALSE
pass_flags = PASSTABLE | PASSMOB
mob_size = MOB_SIZE_SMALL
@@ -39,6 +38,9 @@
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
+/mob/living/simple_animal/hostile/retaliate/poison/snake/Initialize()
+ . = ..()
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/mob/living/simple_animal/hostile/retaliate/poison/snake/ListTargets(atom/the_target)
. = oview(vision_range, targets_from) //get list of things in vision range
diff --git a/code/modules/mob/living/simple_animal/hostile/banana_spider.dm b/code/modules/mob/living/simple_animal/hostile/banana_spider.dm
index 259c0bc721..a88593ed74 100644
--- a/code/modules/mob/living/simple_animal/hostile/banana_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/banana_spider.dm
@@ -22,7 +22,6 @@
speak_emote = list("chitters")
mouse_opacity = 2
density = TRUE
- ventcrawler = VENTCRAWLER_ALWAYS
verb_say = "chitters"
verb_ask = "chitters inquisitively"
verb_exclaim = "chitters loudly"
@@ -37,6 +36,8 @@
if(A)
notify_ghosts("A banana spider has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_dnr_observers = TRUE)
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
+
/mob/living/simple_animal/banana_spider/attack_ghost(mob/user)
if(key) //please stop using src. without a good reason.
return
diff --git a/code/modules/mob/living/simple_animal/hostile/bread.dm b/code/modules/mob/living/simple_animal/hostile/bread.dm
index 317827028d..70c8b0c540 100644
--- a/code/modules/mob/living/simple_animal/hostile/bread.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bread.dm
@@ -26,7 +26,6 @@
speak_emote = list("growls")
mouse_opacity = 2
density = TRUE
- ventcrawler = VENTCRAWLER_ALWAYS
verb_say = "growls"
verb_ask = "growls inquisitively"
verb_exclaim = "growls loudly"
@@ -38,6 +37,7 @@
var/area/A = get_area(src)
if(A)
notify_ghosts("A tumor bread has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_dnr_observers = TRUE)
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/mob/living/simple_animal/hostile/bread/attack_ghost(mob/user)
if(key) //please stop using src. without a good reason.
diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
index 8b31ab6916..2349685a4e 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -44,7 +44,6 @@
var/busy = SPIDER_IDLE
pass_flags = PASSTABLE
move_to_delay = 6
- ventcrawler = VENTCRAWLER_ALWAYS
attack_verb_continuous = "bites"
attack_verb_simple = "bite"
attack_sound = 'sound/weapons/bite.ogg'
@@ -63,6 +62,8 @@
lay_web = new
lay_web.Grant(src)
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
+
/mob/living/simple_animal/hostile/poison/giant_spider/Destroy()
QDEL_NULL(lay_web)
return ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/headcrab.dm b/code/modules/mob/living/simple_animal/hostile/headcrab.dm
index 850beeb099..5e34d17bb2 100644
--- a/code/modules/mob/living/simple_animal/hostile/headcrab.dm
+++ b/code/modules/mob/living/simple_animal/hostile/headcrab.dm
@@ -20,11 +20,14 @@
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
speak_emote = list("squeaks")
- ventcrawler = VENTCRAWLER_ALWAYS
var/datum/mind/origin
var/egg_lain = 0
gold_core_spawnable = NO_SPAWN //are you sure about this?? // CITADEL CHANGE, Yes.
+/mob/living/simple_animal/hostile/headcrab/Initialize()
+ . = ..()
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
+
/mob/living/simple_animal/hostile/headcrab/proc/Infect(mob/living/carbon/victim)
var/obj/item/organ/body_egg/changeling_egg/egg = new(victim)
egg.Insert(victim)
diff --git a/code/modules/mob/living/simple_animal/hostile/killertomato.dm b/code/modules/mob/living/simple_animal/hostile/killertomato.dm
index b86d5d87fc..d3d3dadd1e 100644
--- a/code/modules/mob/living/simple_animal/hostile/killertomato.dm
+++ b/code/modules/mob/living/simple_animal/hostile/killertomato.dm
@@ -22,10 +22,13 @@
attack_verb_continuous = "slams"
attack_verb_simple = "slam"
attack_sound = 'sound/weapons/punch1.ogg'
- ventcrawler = VENTCRAWLER_ALWAYS
faction = list("plants")
atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 150
maxbodytemp = 500
gold_core_spawnable = HOSTILE_SPAWN
+
+/mob/living/simple_animal/hostile/killertomato/Initialize()
+ . = ..()
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index fa3a59a6b9..a584d34995 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -620,7 +620,6 @@ Difficulty: Very Hard
density = FALSE
movement_type = FLYING
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
- ventcrawler = VENTCRAWLER_ALWAYS
mob_size = MOB_SIZE_TINY
gold_core_spawnable = HOSTILE_SPAWN
verb_say = "warps"
@@ -648,6 +647,7 @@ Difficulty: Very Hard
remove_verb(src, /mob/verb/me_verb)
var/datum/atom_hud/medsensor = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
medsensor.add_hud_to(src)
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/mob/living/simple_animal/hostile/lightgeist/AttackingTarget()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm
index 0ccc4525c7..e35220a920 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm
@@ -27,7 +27,6 @@
friendly_verb_continuous = "pinches"
friendly_verb_simple = "pinch"
a_intent = INTENT_HELP
- ventcrawler = VENTCRAWLER_ALWAYS
gold_core_spawnable = FRIENDLY_SPAWN
stat_attack = UNCONSCIOUS
gender = NEUTER
@@ -50,6 +49,7 @@
/mob/living/simple_animal/hostile/asteroid/gutlunch/Initialize()
udder = new()
. = ..()
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/mob/living/simple_animal/hostile/asteroid/gutlunch/CanAttack(atom/the_target) // Gutlunch-specific version of CanAttack to handle stupid stat_exclusive = true crap so we don't have to do it for literally every single simple_animal/hostile except the two that spawn in lavaland
if(isturf(the_target) || !the_target || the_target.type == /atom/movable/lighting_object) // bail out on invalids
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
index 11ce4f9214..ae0f5ea3ca 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
@@ -398,7 +398,6 @@
uniform = /obj/item/clothing/under/color/grey
belt = /obj/item/tank/internals/emergency_oxygen
mask = /obj/item/clothing/mask/gas
- ears = /obj/item/radio/headset
gloves = /obj/item/clothing/gloves/color/fyellow
id = /obj/item/card/id/silver/reaper //looks cool and has a fancy name but only a 1% chance
if(prob(99))
@@ -412,7 +411,7 @@
back = /obj/item/spear
else if(prob(80)) //Now they dont always have a backpack
back = /obj/item/storage/backpack
- backpack_contents = list(/obj/item/stack/cable_coil = 1, /obj/item/assembly/flash = 1, /obj/item/storage/fancy/donut_box = 1, /obj/item/storage/fancy/cigarettes/cigpack_shadyjims = 1, /obj/item/lighter = 1)
+ backpack_contents = list(/obj/item/stack/cable_coil = 1, /obj/item/storage/fancy/donut_box = 1, /obj/item/storage/fancy/cigarettes/cigpack_shadyjims = 1, /obj/item/lighter = 1)
if(prob(90))
r_pocket = /obj/item/kitchen/knife
if(prob(60))
@@ -423,7 +422,6 @@
suit = /obj/item/clothing/suit/hooded/bee_costume
shoes = /obj/item/clothing/shoes/sneakers/yellow
gloves = /obj/item/clothing/gloves/color/yellow
- ears = /obj/item/radio/headset
belt = /obj/item/storage/belt/fannypack/yellow
id_job = "Assisant"
id = /obj/item/card/id
diff --git a/code/modules/mob/living/simple_animal/hostile/mushroom.dm b/code/modules/mob/living/simple_animal/hostile/mushroom.dm
index 9101430ccc..f41746ea69 100644
--- a/code/modules/mob/living/simple_animal/hostile/mushroom.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mushroom.dm
@@ -28,7 +28,6 @@
stat_attack = DEAD
mouse_opacity = MOUSE_OPACITY_ICON
speed = 1
- ventcrawler = VENTCRAWLER_ALWAYS
robust_searching = 1
unique_name = 1
speak_emote = list("squeaks")
@@ -41,6 +40,10 @@
var/static/mutable_appearance/cap_living //Where we store our cap icons so we dont generate them constantly to update our icon
var/static/mutable_appearance/cap_dead
+/mob/living/simple_animal/hostile/mushroom/Initialize()
+ . = ..()
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
+
/mob/living/simple_animal/hostile/mushroom/examine(mob/user)
. = ..()
if(health >= maxHealth)
diff --git a/code/modules/mob/living/simple_animal/hostile/regalrat.dm b/code/modules/mob/living/simple_animal/hostile/regalrat.dm
index 77b2d4268a..77731f0ea4 100644
--- a/code/modules/mob/living/simple_animal/hostile/regalrat.dm
+++ b/code/modules/mob/living/simple_animal/hostile/regalrat.dm
@@ -23,7 +23,6 @@
attack_verb_continuous = "slashes"
attack_verb_simple = "slash"
attack_sound = 'sound/weapons/punch1.ogg'
- ventcrawler = VENTCRAWLER_ALWAYS
unique_name = TRUE
faction = list("rat")
var/datum/action/cooldown/coffer
@@ -42,6 +41,8 @@
key = C.key
notify_ghosts("All rise for the rat king, ascendant to the throne in \the [get_area(src)].", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE)
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
+
/mob/living/simple_animal/hostile/regalrat/handle_automated_action()
if(prob(20))
riot.Trigger()
@@ -175,7 +176,6 @@
health = 15
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 1)
density = FALSE
- ventcrawler = VENTCRAWLER_ALWAYS
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
mob_size = MOB_SIZE_TINY
mob_biotypes = MOB_ORGANIC|MOB_BEAST
@@ -185,6 +185,7 @@
. = ..()
SSmobs.cheeserats += src
AddComponent(/datum/component/swarming)
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/mob/living/simple_animal/hostile/rat/Destroy()
SSmobs.cheeserats -= src
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm
index 9045ccef51..cb1ee6c6f6 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm
@@ -30,7 +30,6 @@
attack_sound = 'sound/weapons/bite.ogg'
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
- ventcrawler = VENTCRAWLER_ALWAYS
mob_size = MOB_SIZE_TINY
movement_type = FLYING
speak_emote = list("squeaks")
@@ -38,11 +37,14 @@
var/min_oxy = 0
var/max_tox = 0
-
//Space bats need no air to fly in.
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
+/mob/living/simple_animal/hostile/retaliate/bat/Initialize()
+ . = ..()
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
+
/mob/living/simple_animal/hostile/retaliate/bat/secbat
name = "Security Bat"
icon_state = "secbat"
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
index dec2159dc0..96418686d3 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
@@ -137,7 +137,6 @@
emote_see = list("honks", "sweats", "jiggles", "contemplates its existence")
speak_chance = 5
dextrous = TRUE
- ventcrawler = VENTCRAWLER_ALWAYS
maxHealth = 140
health = 140
speed = -5
@@ -147,6 +146,10 @@
obj_damage = 5
loot = list(/obj/item/clothing/suit/hooded/bloated_human, /obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap)
+/mob/living/simple_animal/hostile/retaliate/clown/fleshclown/Initialize()
+ . = ..()
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
+
/mob/living/simple_animal/hostile/retaliate/clown/longface
name = "Longface"
desc = "Often found walking into the bar."
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm
index f0fe85008a..2433b45cc0 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm
@@ -22,7 +22,6 @@
response_harm_continuous = "splats"
response_harm_simple = "splat"
density = FALSE
- ventcrawler = VENTCRAWLER_ALWAYS
faction = list("hostile")
attack_sound = 'sound/effects/reee.ogg'
butcher_results = list(/obj/item/reagent_containers/food/snacks/nugget = 1)
@@ -40,6 +39,7 @@
icon_living = "rare_frog"
icon_dead = "rare_frog_dead"
butcher_results = list(/obj/item/reagent_containers/food/snacks/nugget = 5)
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/mob/living/simple_animal/hostile/retaliate/frog/Crossed(AM as mob|obj)
. = ..()
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index ab59441572..06649ac7d6 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -4,7 +4,6 @@
icon_state = "grey baby slime"
pass_flags = PASSTABLE
mob_size = MOB_SIZE_SMALL
- ventcrawler = VENTCRAWLER_ALWAYS
gender = NEUTER
var/is_adult = 0
var/docile = 0
@@ -108,6 +107,8 @@
AddComponent(/datum/component/footstep, FOOTSTEP_MOB_SLIME, 7.5)
set_nutrition(rand(650, 800))
+ AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
+
/mob/living/simple_animal/slime/Destroy()
for (var/A in actions)
var/datum/action/AC = A
diff --git a/code/modules/mob/living/ventcrawling.dm b/code/modules/mob/living/ventcrawling.dm
index 4c00fd0033..9ade9f097f 100644
--- a/code/modules/mob/living/ventcrawling.dm
+++ b/code/modules/mob/living/ventcrawling.dm
@@ -5,7 +5,7 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, typecacheof(list(
//VENTCRAWLING
-/mob/living/proc/handle_ventcrawl(atom/A)
+/mob/living/proc/handle_ventcrawl(atom/A, ventcrawler)
if(!ventcrawler || !Adjacent(A))
return
. = TRUE //return value to stop the client from being shown the turf contents stat tab on alt-click.
@@ -59,7 +59,7 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, typecacheof(list(
if(!client)
return
- if(iscarbon(src) && ventcrawler == VENTCRAWLER_NUDE)
+ if(iscarbon(src) && ventcrawler==VENTCRAWLER_NUDE)
if(length(get_equipped_items(include_pockets = TRUE)) || get_num_held_items())
to_chat(src, "You can't crawl around in the ventilation ducts with items!")
return
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 3a7e270567..e49bd5162b 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -175,6 +175,7 @@
icon = null
cut_overlays()
invisibility = INVISIBILITY_MAXIMUM
+
new /obj/effect/temp_visual/monkeyify/humanify(loc)
transformation_timer = addtimer(CALLBACK(src, .proc/finish_humanize, tr_flags), TRANSFORMATION_DURATION, TIMER_UNIQUE)
@@ -202,6 +203,8 @@
var/mob/living/carbon/human/O = new( loc )
for(var/obj/item/C in O.loc)
+ if(C.anchored)
+ continue
O.equip_to_appropriate_slot(C)
dna.transfer_identity(O)
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index 20ec678e45..a00145f9dc 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -193,6 +193,13 @@
user.visible_message(ignition_message)
add_fingerprint(user)
fire_act(I.get_temperature())
+//I would have it become a paper plane before the throw, but that would risk runtimes
+/obj/item/paper/DoRevenantThrowEffects(atom/target)
+ sleep(10)
+ if(HAS_TRAIT(src, TRAIT_SPOOKY_THROW))
+ return
+ new /obj/item/paperplane(get_turf(src))
+ qdel(src)
/obj/item/paper/attackby(obj/item/P, mob/living/user, params)
if(burn_paper_product_attackby_check(P, user))
diff --git a/code/modules/projectiles/ammunition/energy/special.dm b/code/modules/projectiles/ammunition/energy/special.dm
index fc4207d084..2bf7c06ec6 100644
--- a/code/modules/projectiles/ammunition/energy/special.dm
+++ b/code/modules/projectiles/ammunition/energy/special.dm
@@ -24,6 +24,11 @@
projectile_type = /obj/item/projectile/energy/floramut
select_name = "mutation"
+/obj/item/ammo_casing/energy/flora/revolution
+ projectile_type = /obj/item/projectile/energy/florarevolution
+ select_name = "revolution"
+ e_cost = 250
+
/obj/item/ammo_casing/energy/temp
projectile_type = /obj/item/projectile/temp
select_name = "freeze"
diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm
index ae6050a68e..f965100846 100644
--- a/code/modules/projectiles/guns/energy/special.dm
+++ b/code/modules/projectiles/guns/energy/special.dm
@@ -45,7 +45,7 @@
desc = "A tool that discharges controlled radiation which induces mutation in plant cells."
icon_state = "flora"
item_state = "gun"
- ammo_type = list(/obj/item/ammo_casing/energy/flora/yield, /obj/item/ammo_casing/energy/flora/mut)
+ ammo_type = list(/obj/item/ammo_casing/energy/flora/yield, /obj/item/ammo_casing/energy/flora/mut, /obj/item/ammo_casing/energy/flora/revolution)
modifystate = 1
ammo_x_offset = 1
selfcharge = EGUN_SELFCHARGE
diff --git a/code/modules/projectiles/projectile/special/floral.dm b/code/modules/projectiles/projectile/special/floral.dm
index c3fe1f0fcb..b855322f09 100644
--- a/code/modules/projectiles/projectile/special/floral.dm
+++ b/code/modules/projectiles/projectile/special/floral.dm
@@ -2,7 +2,7 @@
name = "alpha somatoray"
icon_state = "energy"
damage = 0
- damage_type = TOX
+ damage_type = TRUE
nodamage = 1
flag = "energy"
@@ -21,5 +21,13 @@
icon_state = "energy2"
damage = 0
damage_type = TOX
- nodamage = 1
+ nodamage = TRUE
+ flag = "energy"
+
+/obj/item/projectile/energy/florarevolution
+ name = "gamma somatorary"
+ icon_state = "energy3"
+ damage = 0
+ damage_type = TOX
+ nodamage = TRUE
flag = "energy"
diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm
index b106005a15..ef3a053027 100644
--- a/code/modules/recycling/disposal/bin.dm
+++ b/code/modules/recycling/disposal/bin.dm
@@ -141,7 +141,7 @@
update_icon()
/obj/machinery/disposal/proc/can_stuff_mob_in(mob/living/target, mob/living/user, pushing = FALSE)
- if(!pushing && !iscarbon(user) && !user.ventcrawler) //only carbon and ventcrawlers can climb into disposal by themselves.
+ if(!pushing && !iscarbon(user) && !(SEND_SIGNAL(user, COMSIG_CHECK_VENTCRAWL))) //only carbon and ventcrawlers can climb into disposal by themselves.
if(iscyborg(user))
var/mob/living/silicon/robot/borg = user
if (!borg.module || !borg.module.canDispose)
diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm
index 8c934d39a9..11dd29a416 100644
--- a/code/modules/research/designs/weapon_designs.dm
+++ b/code/modules/research/designs/weapon_designs.dm
@@ -324,8 +324,7 @@
desc = "A tool that discharges controlled radiation which induces mutation in plant cells. Harmless to other organic life."
id = "flora_gun"
build_type = PROTOLATHE
- materials = list(/datum/material/iron = 2000, /datum/material/glass = 500)
- reagents_list = list(/datum/reagent/radium = 20)
+ materials = list(/datum/material/iron = 2000, /datum/material/glass = 500, /datum/material/uranium = 2000)
build_path = /obj/item/gun/energy/floragun
category = list("Weapons")
departmental_flags = DEPARTMENTAL_FLAG_SERVICE | DEPARTMENTAL_FLAG_SCIENCE
diff --git a/html/changelog.html b/html/changelog.html
index 4f4656771d..b18d4f45aa 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -50,6 +50,32 @@
-->
+
25 January 2021
+
MrJWhit updated:
+
+ - Alien radio code
+ - Microwave can now be cleaned by a damp rag as well as soap.
+ - Removes some unused code, and improves some other code.
+ - The AI has a verb to look up and down z-levels
+ - Making a monkey into a human doesn't unanchor random things on the tile
+ - Makes a few slight improvements to drinking code
+ - Makes encryption keys be put in the hands of the user when able instead of being dropped on the floor when removed from headsets
+
+
raspy-on-osu updated:
+
+
silicons updated:
+
+ - you can now shove yourself up in any intent, not just help.
+
+
+
22 January 2021
+
Arturlang updated:
+
+ - Adds a way to give items to people, you can combat mode rightclick to offer it to one person, right click on people without mode and click the give verb, or use the hotkey CTRL G to offer it to everyone around you
+
+
21 January 2021
Acer202 updated:
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml
index 67d9167cd5..215e3c8582 100644
--- a/html/changelogs/.all_changelog.yml
+++ b/html/changelogs/.all_changelog.yml
@@ -28251,3 +28251,22 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
harder and faster.
- balance: You can no longer cheese the colossus by being a sand golem and simply
being immune.
+2021-01-22:
+ Arturlang:
+ - rscadd: Adds a way to give items to people, you can combat mode rightclick to
+ offer it to one person, right click on people without mode and click the give
+ verb, or use the hotkey CTRL G to offer it to everyone around you
+2021-01-25:
+ MrJWhit:
+ - bugfix: Alien radio code
+ - rscadd: Microwave can now be cleaned by a damp rag as well as soap.
+ - bugfix: Removes some unused code, and improves some other code.
+ - rscadd: The AI has a verb to look up and down z-levels
+ - bugfix: Making a monkey into a human doesn't unanchor random things on the tile
+ - bugfix: Makes a few slight improvements to drinking code
+ - tweak: Makes encryption keys be put in the hands of the user when able instead
+ of being dropped on the floor when removed from headsets
+ raspy-on-osu:
+ - refactor: ventcrawling
+ silicons:
+ - tweak: you can now shove yourself up in any intent, not just help.
diff --git a/html/changelogs/AutoChangeLog-pr-14059.yml b/html/changelogs/AutoChangeLog-pr-14059.yml
new file mode 100644
index 0000000000..c20e1165ab
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-14059.yml
@@ -0,0 +1,5 @@
+author: "Hatterhat"
+delete-after: True
+changes:
+ - rscdel: "Headsets can't be found on most legion corpses now."
+ - rscdel: "The flash on the assistant corpse is gone, too."
diff --git a/html/changelogs/AutoChangeLog-pr-14102.yml b/html/changelogs/AutoChangeLog-pr-14102.yml
new file mode 100644
index 0000000000..38668ad1ed
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-14102.yml
@@ -0,0 +1,6 @@
+author: "ArcaneMusic, ported by Hatterhat"
+delete-after: True
+changes:
+ - rscadd: "Strike a hydroponics tray with a fully-charged floral somatoray to lock in a mutation."
+ - rscadd: "Floral somatorays now have the ability to force a mutation in a plant. This should drain the cell in a single shot, but we'll see."
+ - balance: "Somatorays now take uranium to craft instead of radium."
diff --git a/html/changelogs/AutoChangeLog-pr-14103.yml b/html/changelogs/AutoChangeLog-pr-14103.yml
deleted file mode 100644
index 856b66aeb7..0000000000
--- a/html/changelogs/AutoChangeLog-pr-14103.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Arturlang"
-delete-after: True
-changes:
- - rscadd: "Adds a way to give items to people, you can combat mode rightclick to offer it to one person, right click on people without mode and click the give verb, or use the hotkey CTRL G to offer it to everyone around you"
diff --git a/html/changelogs/AutoChangeLog-pr-14105.yml b/html/changelogs/AutoChangeLog-pr-14105.yml
new file mode 100644
index 0000000000..08c86c9915
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-14105.yml
@@ -0,0 +1,6 @@
+author: "DeltaFire15"
+delete-after: True
+changes:
+ - admin: "The heretic antag panel now shows their sacrifices & current sacrifice targets."
+ - tweak: "The heretic roundend report now shows their sacrifices and nonsacrificed targets."
+ - bugfix: "Living hearts can no longer select the same target as another living heart, removing a certain problem."
diff --git a/html/changelogs/AutoChangeLog-pr-14111.yml b/html/changelogs/AutoChangeLog-pr-14111.yml
new file mode 100644
index 0000000000..39510c04a4
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-14111.yml
@@ -0,0 +1,4 @@
+author: "Arturlang"
+delete-after: True
+changes:
+ - rscadd: "Revenants can now clickdrag to throw stuff at people, with some items doing various things at the same time."
diff --git a/html/changelogs/AutoChangeLog-pr-14114.yml b/html/changelogs/AutoChangeLog-pr-14114.yml
new file mode 100644
index 0000000000..5035b47431
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-14114.yml
@@ -0,0 +1,4 @@
+author: "Hatterhat"
+delete-after: True
+changes:
+ - balance: "The free golem ship's GPSes no longer start on. They were never meant to, but they did."
diff --git a/html/changelogs/AutoChangeLog-pr-14116.yml b/html/changelogs/AutoChangeLog-pr-14116.yml
new file mode 100644
index 0000000000..fdbc7f2a6c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-14116.yml
@@ -0,0 +1,4 @@
+author: "timothyteakettle"
+delete-after: True
+changes:
+ - admin: "adminhelps and pms only sanitize once instead of twice"
diff --git a/html/changelogs/AutoChangeLog-pr-14117.yml b/html/changelogs/AutoChangeLog-pr-14117.yml
new file mode 100644
index 0000000000..f3fcae5eae
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-14117.yml
@@ -0,0 +1,4 @@
+author: "timothyteakettle"
+delete-after: True
+changes:
+ - rscadd: "blobs can use the 'me' verb"
diff --git a/html/changelogs/AutoChangeLog-pr-14118.yml b/html/changelogs/AutoChangeLog-pr-14118.yml
new file mode 100644
index 0000000000..7ff53a9ae7
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-14118.yml
@@ -0,0 +1,6 @@
+author: "DeltaFire15"
+delete-after: True
+changes:
+ - bugfix: "The woundmending rite no longer causes runtimes."
+ - bugfix: "Ratvarian borgs can now use their tier-0 spells."
+ - balance: "Ratvarian borgs can always use their assigned spells, if there is enough power."
diff --git a/html/changelogs/AutoChangeLog-pr-14127.yml b/html/changelogs/AutoChangeLog-pr-14127.yml
new file mode 100644
index 0000000000..2adc32ddd6
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-14127.yml
@@ -0,0 +1,4 @@
+author: "Hatterhat"
+delete-after: True
+changes:
+ - balance: "One of the contractor tablet's payouts has been raised from a small payout to a medium payout."
diff --git a/html/changelogs/AutoChangeLog-pr-14131.yml b/html/changelogs/AutoChangeLog-pr-14131.yml
new file mode 100644
index 0000000000..5838f49bb2
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-14131.yml
@@ -0,0 +1,4 @@
+author: "MrJWhit"
+delete-after: True
+changes:
+ - tweak: "Remaps some air alarms for sanity."
diff --git a/html/changelogs/AutoChangeLog-pr-14133.yml b/html/changelogs/AutoChangeLog-pr-14133.yml
new file mode 100644
index 0000000000..9968f41134
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-14133.yml
@@ -0,0 +1,5 @@
+author: "Hatterhat"
+delete-after: True
+changes:
+ - tweak: "Department budget cards have been readded. TO THE CODE. NOT LOCKERS."
+ - tweak: "Also budget cards now look more like every other ID - see tgstation#55001."
diff --git a/html/changelogs/AutoChangeLog-pr-14134.yml b/html/changelogs/AutoChangeLog-pr-14134.yml
new file mode 100644
index 0000000000..c699728c67
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-14134.yml
@@ -0,0 +1,4 @@
+author: "Arturlang"
+delete-after: True
+changes:
+ - rscadd: "Actually adds a right click give option"
diff --git a/html/changelogs/AutoChangeLog-pr-14135.yml b/html/changelogs/AutoChangeLog-pr-14135.yml
new file mode 100644
index 0000000000..bbbb7170b9
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-14135.yml
@@ -0,0 +1,4 @@
+author: "raspy-on-osu"
+delete-after: True
+changes:
+ - bugfix: "bespoke ventcrawling element not detaching due to malformed call"
diff --git a/html/changelogs/AutoChangeLog-pr-14136.yml b/html/changelogs/AutoChangeLog-pr-14136.yml
new file mode 100644
index 0000000000..8b578f16e8
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-14136.yml
@@ -0,0 +1,5 @@
+author: "shellspeed1"
+delete-after: True
+changes:
+ - bugfix: "Floorbots had had a software update, preventing them from dogpiling on their target as easily as they did before."
+ - soundadd: "Floorbots will now play a small chime when stacked on top of each other to indicate that they're moving apart."
diff --git a/html/changelogs/AutoChangeLog-pr-14137.yml b/html/changelogs/AutoChangeLog-pr-14137.yml
new file mode 100644
index 0000000000..1b7602437b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-14137.yml
@@ -0,0 +1,4 @@
+author: "SandPoot"
+delete-after: True
+changes:
+ - bugfix: "The drop circuit can no longer drop things that are not inside it."
diff --git a/icons/obj/card.dmi b/icons/obj/card.dmi
index 13a0725b05..1bd94f2424 100644
Binary files a/icons/obj/card.dmi and b/icons/obj/card.dmi differ
diff --git a/icons/obj/guns/energy.dmi b/icons/obj/guns/energy.dmi
index 7e7e4a644b..158c95ee5d 100644
Binary files a/icons/obj/guns/energy.dmi and b/icons/obj/guns/energy.dmi differ
diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi
index 94568b8633..740c64b1dc 100644
Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ
diff --git a/sound/effects/whistlereset.ogg b/sound/effects/whistlereset.ogg
new file mode 100644
index 0000000000..cf55c06ca8
Binary files /dev/null and b/sound/effects/whistlereset.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index a0f5d54c03..5ea3b652e7 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -620,6 +620,7 @@
#include "code\datums\elements\tactical.dm"
#include "code\datums\elements\update_icon_blocker.dm"
#include "code\datums\elements\update_icon_updates_onmob.dm"
+#include "code\datums\elements\ventcrawling.dm"
#include "code\datums\elements\wuv.dm"
#include "code\datums\helper_datums\events.dm"
#include "code\datums\helper_datums\getrev.dm"