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 a776996d91..6ef8eb8d45 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -49544,7 +49544,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)
@@ -113342,10 +113342,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 5140b35d20..698a585688 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{
@@ -67208,10 +67184,6 @@
/obj/structure/cable{
icon_state = "1-4"
},
-/obj/machinery/airalarm{
- dir = 1;
- pixel_y = -22
- },
/turf/open/floor/plasteel,
/area/security/main)
"cdU" = (
@@ -71325,9 +71297,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;
@@ -83279,10 +83251,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;
@@ -108990,7 +108958,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 9013e78daa..cccf44f4af 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
},
@@ -102702,7 +102693,7 @@ bue
bwa
bxU
bzD
-bBr
+dmD
bSx
bEw
bzE
@@ -103737,7 +103728,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 5bf6e58409..75826cf65a 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 53479d1148..47a934bbec 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" = (
@@ -59432,6 +59445,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/_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/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/elements/ventcrawling.dm b/code/datums/elements/ventcrawling.dm
index 4af3a085ef..254345a97f 100644
--- a/code/datums/elements/ventcrawling.dm
+++ b/code/datums/elements/ventcrawling.dm
@@ -6,6 +6,10 @@
/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)
@@ -16,9 +20,10 @@
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
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 efae2dfb5e..6e6e85146d 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -954,6 +954,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/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/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/stunbaton.dm b/code/game/objects/items/stunbaton.dm
index d7db5ce908..b52d138385 100644
--- a/code/game/objects/items/stunbaton.dm
+++ b/code/game/objects/items/stunbaton.dm
@@ -236,6 +236,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/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/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/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/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/integrated_electronics/core/integrated_circuit.dm b/code/modules/integrated_electronics/core/integrated_circuit.dm
index f391ceae26..84b299471b 100644
--- a/code/modules/integrated_electronics/core/integrated_circuit.dm
+++ b/code/modules/integrated_electronics/core/integrated_circuit.dm
@@ -379,7 +379,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
@@ -395,7 +395,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/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 9ff409a5fb..56c90ba936 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -1231,3 +1231,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_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index 858e3000fb..75aff774ce 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -805,7 +805,7 @@
/datum/species/golem/plastic/on_species_loss(mob/living/carbon/C)
. = ..()
- C.RemoveElement(/datum/element/ventcrawling)
+ 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/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm
index 2296b69762..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.RemoveElement(/datum/element/ventcrawling)
+ SA.RemoveElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
if(transfer_name)
H.name = human_caster.name
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/drone/interaction.dm b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
index 0728484cea..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"
- RemoveElement(/datum/element/ventcrawling) // 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
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/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-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-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-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/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