diff --git a/code/__DEFINES/admin/keybindings.dm b/code/__DEFINES/admin/keybindings.dm
index fcfe7c5e58..e8616fd3ce 100644
--- a/code/__DEFINES/admin/keybindings.dm
+++ b/code/__DEFINES/admin/keybindings.dm
@@ -1,6 +1,6 @@
// Defines for managed input/keybinding system.
/// Max length of a keypress command before it's considered to be a forged packet/bogus command
-#define MAX_KEYPRESS_COMMANDLENGTH 32
+#define MAX_KEYPRESS_COMMANDLENGTH 64
/// Maximum keys that can be bound to one button
#define MAX_COMMANDS_PER_KEY 5
/// Maximum keys per keybind
diff --git a/code/controllers/subsystem/persistence.dm b/code/controllers/subsystem/persistence.dm
index 5b60747725..e1b6e6f6e2 100644
--- a/code/controllers/subsystem/persistence.dm
+++ b/code/controllers/subsystem/persistence.dm
@@ -48,25 +48,6 @@ SUBSYSTEM_DEF(persistence)
/datum/controller/subsystem/persistence/proc/LoadSatchels()
var/placed_satchel = 0
var/path
- if(fexists("data/npc_saves/SecretSatchels.sav")) //legacy conversion. Will only ever run once.
- var/savefile/secret_satchels = new /savefile("data/npc_saves/SecretSatchels.sav")
- for(var/map in secret_satchels)
- var/json_file = file("data/npc_saves/SecretSatchels[map].json")
- var/list/legacy_secret_satchels = splittext(secret_satchels[map],"#")
- var/list/satchels = list()
- for(var/i=1,i<=legacy_secret_satchels.len,i++)
- var/satchel_string = legacy_secret_satchels[i]
- var/list/chosen_satchel = splittext(satchel_string,"|")
- if(chosen_satchel.len == 3)
- var/list/data = list()
- data["x"] = text2num(chosen_satchel[1])
- data["y"] = text2num(chosen_satchel[2])
- data["saved_obj"] = chosen_satchel[3]
- satchels += list(data)
- var/list/file_data = list()
- file_data["data"] = satchels
- WRITE_FILE(json_file, json_encode(file_data))
- fdel("data/npc_saves/SecretSatchels.sav")
var/json_file = file("data/npc_saves/SecretSatchels[SSmapping.config.map_name].json")
var/list/json = list()
diff --git a/code/datums/mutations/_mutations.dm b/code/datums/mutations/_mutations.dm
index fb5f6ed5f6..3bddfdaa63 100644
--- a/code/datums/mutations/_mutations.dm
+++ b/code/datums/mutations/_mutations.dm
@@ -11,7 +11,7 @@
var/lowest_value = 256 * 8
var/text_gain_indication = ""
var/text_lose_indication = ""
- var/list/mutable_appearance/visual_indicators = list()
+ var/list/visual_indicators = list()
var/obj/effect/proc_holder/spell/power
var/layer_used = MUTATIONS_LAYER //which mutation layer to use
var/list/species_allowed = list() //to restrict mutation to only certain species
diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm
index 179adf46bd..9af78b0090 100644
--- a/code/datums/wires/airlock.dm
+++ b/code/datums/wires/airlock.dm
@@ -71,7 +71,7 @@
/datum/wires/airlock/on_pulse(wire)
set waitfor = FALSE
var/obj/machinery/door/airlock/A = holder
- if(!A.hasSiliconAccessInArea(usr) && A.isElectrified() && A.shock(usr, 100))
+ if(usr && !A.hasSiliconAccessInArea(usr) && A.isElectrified() && A.shock(usr, 100))
return FALSE
switch(wire)
if(WIRE_POWER1, WIRE_POWER2) // Pulse to loose power.
@@ -127,7 +127,7 @@
/datum/wires/airlock/on_cut(wire, mend)
var/obj/machinery/door/airlock/A = holder
- if(!A.hasSiliconAccessInArea(usr) && A.isElectrified() && A.shock(usr, 100))
+ if(usr && !A.hasSiliconAccessInArea(usr) && A.isElectrified() && A.shock(usr, 100))
return FALSE
switch(wire)
if(WIRE_POWER1, WIRE_POWER2) // Cut to loose power, repair all to gain power.
diff --git a/code/game/area/Space_Station_13_areas.dm b/code/game/area/Space_Station_13_areas.dm
index cbad2f7ab0..5310b24202 100644
--- a/code/game/area/Space_Station_13_areas.dm
+++ b/code/game/area/Space_Station_13_areas.dm
@@ -43,6 +43,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
outdoors = TRUE
ambientsounds = SPACE
blob_allowed = FALSE //Eating up space doesn't count for victory as a blob.
+ considered_hull_exterior = TRUE
/area/space/nearstation
icon_state = "space_near"
@@ -1592,4 +1593,4 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
valid_territory = FALSE
outdoors = TRUE
ambientsounds = SPACE
- blob_allowed = FALSE //While part of the station, what good will it do you?
\ No newline at end of file
+ blob_allowed = FALSE //While part of the station, what good will it do you?
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 672d5c096f..b9415f3cf8 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -34,6 +34,9 @@
/// If megafauna can be spawned by natural random generation
var/megafauna_spawn_allowed = FALSE
+ /// Considered space for hull shielding
+ var/considered_hull_exterior = FALSE
+
var/fire = null
var/atmos = TRUE
var/atmosalm = FALSE
diff --git a/code/game/objects/items/devices/portable_chem_mixer.dm b/code/game/objects/items/devices/portable_chem_mixer.dm
index 25ecef5955..3e1b20cfc2 100644
--- a/code/game/objects/items/devices/portable_chem_mixer.dm
+++ b/code/game/objects/items/devices/portable_chem_mixer.dm
@@ -113,8 +113,7 @@
if (loc != user)
return ..()
if(SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED))
- ui_interact(user)
- return
+ INVOKE_ASYNC(src, /datum.proc/ui_interact, user)
/obj/item/storage/portable_chem_mixer/attack_self(mob/user)
if(loc == user)
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 7ba2196184..a96b0104f1 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -269,8 +269,8 @@
to_chat(user, "[M] is at full health.")
return FALSE
user.visible_message("[user] applies \the [src] on [M].", "You apply \the [src] on [M].")
- return heal_carbon(M, user, heal_brute, heal_burn)
-
+ M.heal_bodypart_damage(heal_brute)
+ return TRUE
to_chat(user, "You can't heal [M] with \the [src]!")
/obj/item/stack/medical/ointment
diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm
index bcdf509fbe..3de28b38e8 100644
--- a/code/game/objects/obj_defense.dm
+++ b/code/game/objects/obj_defense.dm
@@ -204,9 +204,6 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e
/obj/proc/acid_processing()
. = 1
if(!(resistance_flags & ACID_PROOF))
- for(var/armour_value in armor)
- if(armour_value != "acid" && armour_value != "fire")
- armor = armor.modifyAllRatings(0 - round(sqrt(acid_level)*0.1))
if(prob(33))
playsound(loc, 'sound/items/welder.ogg', 150, 1)
take_damage(min(1 + round(sqrt(acid_level)*0.3), 300), BURN, "acid", 0)
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index 9ff4f668a4..402ab36947 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -138,7 +138,7 @@
if(prob(hardness))
playsound(src, 'sound/effects/meteorimpact.ogg', 100, TRUE)
user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk")
- hulk_recoil(arm, user)
+ //hulk_recoil(arm, user) // citadel edit - no, hulks are already subject to stamina combat
dismantle_wall(1)
else
diff --git a/code/modules/antagonists/bloodsucker/powers/brawn.dm b/code/modules/antagonists/bloodsucker/powers/brawn.dm
index cf0393ff3a..5444cccd3f 100644
--- a/code/modules/antagonists/bloodsucker/powers/brawn.dm
+++ b/code/modules/antagonists/bloodsucker/powers/brawn.dm
@@ -1,7 +1,7 @@
/datum/action/bloodsucker/targeted/brawn
- name = "Brawn"//"Cellular Emporium"
+ name = "Brawn"
desc = "Snap restraints with ease, or deal terrible damage with your bare hands."
button_icon_state = "power_strength"
bloodcost = 10
@@ -107,8 +107,6 @@
if(user_C.handcuffed)
var/obj/O = user_C.get_item_by_slot(SLOT_HANDCUFFED)
if(istype(O))
- //user_C.visible_message("[user_C] attempts to remove [O]!", \
- // "You snap [O] like it's nothing!")
user_C.clear_cuffs(O,TRUE)
playsound(get_turf(usr), 'sound/effects/grillehit.ogg', 80, 1, -1)
return TRUE
@@ -128,8 +126,6 @@
if(user_C.legcuffed)
var/obj/O = user_C.get_item_by_slot(SLOT_LEGCUFFED)
if(istype(O))
- //user_C.visible_message("[user_C] attempts to remove [O]!", \
- // "You snap [O] like it's nothing!")
user_C.clear_cuffs(O,TRUE)
playsound(get_turf(usr), 'sound/effects/grillehit.ogg', 80, 1, -1)
return TRUE
diff --git a/code/modules/antagonists/bloodsucker/powers/feed.dm b/code/modules/antagonists/bloodsucker/powers/feed.dm
index caca020b32..81ebdbe4e2 100644
--- a/code/modules/antagonists/bloodsucker/powers/feed.dm
+++ b/code/modules/antagonists/bloodsucker/powers/feed.dm
@@ -165,8 +165,8 @@
// Broadcast Message
if(amSilent)
//if (!iscarbon(target))
- // user.visible_message("[user] shifts [target] closer to [user.p_their()] mouth.", \
- // "You secretly slip your fangs into [target]'s flesh.", \
+ // user.visible_message("[user] shifts [target] closer to [user.p_their()] mouth.",
+ // "You secretly slip your fangs into [target]'s flesh.",
// vision_distance = 2, ignored_mobs=target) // Only people who AREN'T the target will notice this action.
//else
var/deadmessage = target.stat == DEAD ? "" : " [target.p_they(TRUE)] looks dazed, and will not remember this."
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 664e8fc8b4..e62b8c1619 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -1411,6 +1411,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/obj/item/bodypart/affecting = target.get_bodypart(ran_zone(user.zone_selected))
+ if(!affecting) //Maybe the bodypart is missing? Or things just went wrong..
+ affecting = target.get_bodypart(BODY_ZONE_CHEST) //target chest instead, as failsafe. Or hugbox? You decide.
+
var/miss_chance = 100//calculate the odds that a punch misses entirely. considers stamina and brute damage of the puncher. punches miss by default to prevent weird cases
if(attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)
miss_chance = 0
@@ -1626,6 +1629,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
/datum/species/proc/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H, attackchain_flags = NONE, damage_multiplier = 1)
var/totitemdamage = H.pre_attacked_by(I, user) * damage_multiplier
+
+ if(!affecting) //Something went wrong. Maybe the limb is missing?
+ affecting = H.get_bodypart(BODY_ZONE_CHEST) //If the limb is missing, or something went terribly wrong, just hit the chest instead
+
// Allows you to put in item-specific reactions based on species
if(user != H)
var/list/block_return = list()
@@ -1637,8 +1644,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
return 0
var/hit_area
- if(!affecting) //Something went wrong. Maybe the limb is missing?
- affecting = H.bodyparts[1]
hit_area = affecting.name
var/def_zone = affecting.body_zone
diff --git a/code/modules/paperwork/ticketmachine.dm b/code/modules/paperwork/ticketmachine.dm
index e46ed64971..0e553ced35 100644
--- a/code/modules/paperwork/ticketmachine.dm
+++ b/code/modules/paperwork/ticketmachine.dm
@@ -162,6 +162,9 @@
/obj/machinery/ticket_machine/attack_hand(mob/living/carbon/user)
. = ..()
+ INVOKE_ASYNC(src, .proc/attempt_ticket, user)
+
+/obj/machinery/ticket_machine/proc/attempt_ticket(mob/living/carbon/user)
if(!ready)
to_chat(user,"You press the button, but nothing happens...")
return
@@ -195,7 +198,7 @@
/obj/item/ticket_machine_ticket
name = "Ticket"
- desc = "A ticket which shows your place in the Head of Personnel's line. Made from Nanotrasen patented NanoPaper®. Though solid, its form seems to shimmer slightly. Feels (and burns) just like the real thing."
+ desc = "A ticket which shows your place in the Head of Personnel's line. Made from Nanotrasen patented NanoPaper®. Though solid, its form seems to shimmer slightly. Feels (and burns) just like the real thing."
icon = 'icons/obj/bureaucracy.dmi'
icon_state = "ticket"
maptext_x = 7
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 99a0bedc4d..4e81c5aeb6 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -460,6 +460,7 @@
return TRUE //Bullets don't drift in space
/obj/item/projectile/process(wait)
+ set waitfor = FALSE
if(!loc || !fired || !trajectory)
fired = FALSE
return PROCESS_KILL
diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm
index c8da9ab5e3..b106005a15 100644
--- a/code/modules/recycling/disposal/bin.dm
+++ b/code/modules/recycling/disposal/bin.dm
@@ -263,7 +263,7 @@
. = ..()
if(.)
return
- for(var/obj/item/I in src_object)
+ for(var/obj/item/I in src_object.contents())
if(user.active_storage != src_object)
if(I.on_found(user))
return
diff --git a/code/modules/shielding/helpers.dm b/code/modules/shielding/helpers.dm
new file mode 100644
index 0000000000..8995cc3b03
--- /dev/null
+++ b/code/modules/shielding/helpers.dm
@@ -0,0 +1,65 @@
+//////// HELPER FILE FOR SHIELDING /////////
+
+// HULL SHIELD GENERATION HELPERS
+/**
+ * Gets hull exterior adjacent tiles of a certain area
+ * Area method.
+ * EXPENSIVE.
+ * If the area itself is already considered exterior, it'll find all tiles inside it that's next to an interior area.
+ */
+/proc/hull_shielding_get_tiles_around_area(area/instance, check_tick = FALSE)
+ var/list/cache = list()
+ var/area/A
+ if(instance.considered_hull_exterior)
+ for(var/turf/potential in instance)
+ for(var/turf/looking in orange(1, potential))
+ A = looking.loc
+ if(!A.considered_hull_exterior)
+ cache[potential] = TRUE // we're the exterior area, grab the one that's reaching out
+ if(check_tick)
+ CHECK_TICK
+ else
+ for(var/turf/potential in instance)
+ for(var/turf/looking in orange(1, potential))
+ A = looking.loc
+ if(A.considered_hull_exterior)
+ cache[looking] = TRUE // we're not the exterior area, grab the one that's being reached to
+ if(check_tick)
+ CHECK_TICK
+ . = list()
+ for(var/i in cache)
+ . += i // strip assoc value
+
+/**
+ * Gets hull adjacent exterior tiles of an entire zlevel
+ * EXPENSIVE.
+ * Gets the tiles in the exterior area touching to a non-exterior area
+ */
+/proc/hull_shielding_get_tiles_in_z(zlevel, check_tick = FALSE, recurse = FALSE, list/outlist = list(), list/scanned_zlevels = list())
+ . = outlist
+ if(zlevel in scanned_zlevels)
+ return
+ scanned_zlevels |= zlevel
+ if(recurse)
+ var/up = SSmapping.level_trait(zlevel, ZTRAIT_UP)
+ var/down = SSmapping.level_trait(zlevel, ZTRAIT_DOWN)
+ if(isnum(up) && (up != 0))
+ hull_shielding_get_tiles_in_z(up, check_tick, recurse, outlist, scanned_zlevels)
+ if(isnum(down) && (down != 0))
+ hull_shielding_get_tiles_in_z(down, check_tick, recurse, outlist, scanned_zlevels)
+ // sigh. why.
+ var/turf/potential
+ var/area/p_area
+ var/area/l_area
+ for(var/x in 1 to world.maxx)
+ for(var/y in 1 to world.maxy)
+ if(check_tick)
+ CHECK_TICK
+ potential = locate(x, y, zlevel)
+ p_area = potential.loc
+ if(!p_area.considered_hull_exterior)
+ continue
+ for(var/turf/looking in orange(1, potential))
+ l_area = looking.loc
+ if(!l_area.considered_hull_exterior)
+ outlist += potential
diff --git a/html/changelogs/AutoChangeLog-pr-13382.yml b/html/changelogs/AutoChangeLog-pr-13382.yml
new file mode 100644
index 0000000000..2dfa78c540
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13382.yml
@@ -0,0 +1,4 @@
+author: "silicons"
+delete-after: True
+changes:
+ - balance: "hulks can smash again (walls no longer break their hands)"
diff --git a/html/changelogs/AutoChangeLog-pr-13394.yml b/html/changelogs/AutoChangeLog-pr-13394.yml
new file mode 100644
index 0000000000..6fe20032da
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13394.yml
@@ -0,0 +1,5 @@
+author: "DeltaFire15"
+delete-after: True
+changes:
+ - bugfix: "Sutures work on simplemobs again."
+ - bugfix: "Attacking dismembered bodyparts now targets the chest instead, for weapons aswell as unarmed attacks."
diff --git a/html/changelogs/AutoChangeLog-pr-13399.yml b/html/changelogs/AutoChangeLog-pr-13399.yml
new file mode 100644
index 0000000000..2da88988a0
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13399.yml
@@ -0,0 +1,4 @@
+author: "silicons"
+delete-after: True
+changes:
+ - rscdel: "acid no longer degrades armor"
diff --git a/html/changelogs/AutoChangeLog-pr-13401.yml b/html/changelogs/AutoChangeLog-pr-13401.yml
new file mode 100644
index 0000000000..6bfc8e4e21
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13401.yml
@@ -0,0 +1,4 @@
+author: "MrJWhit"
+delete-after: True
+changes:
+ - rscadd: "New sprites for chess pieces! You can craft them in-game with metal sheets."
diff --git a/icons/obj/chess.dmi b/icons/obj/chess.dmi
index 09d9c766fd..ec9415eab4 100644
Binary files a/icons/obj/chess.dmi and b/icons/obj/chess.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 7c3673bee2..7d30d694b0 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -3284,6 +3284,7 @@
#include "code\modules\ruins\spaceruin_code\whiteshipruin_box.dm"
#include "code\modules\security_levels\keycard_authentication.dm"
#include "code\modules\security_levels\security_levels.dm"
+#include "code\modules\shielding\helpers.dm"
#include "code\modules\shuttle\arrivals.dm"
#include "code\modules\shuttle\assault_pod.dm"
#include "code\modules\shuttle\computer.dm"