diff --git a/.github/workflows/compare_screenshots.yml b/.github/workflows/compare_screenshots.yml
index d9fdaa2b1ff..87c9b96a6d9 100644
--- a/.github/workflows/compare_screenshots.yml
+++ b/.github/workflows/compare_screenshots.yml
@@ -13,7 +13,7 @@ jobs:
run: mkdir -p artifacts
# If we ever add more artifacts, this is going to break, but it'll be obvious.
- name: Download screenshot tests
- uses: actions/download-artifact@v5
+ uses: actions/download-artifact@v6
with:
path: artifacts
- name: ls -R
@@ -34,7 +34,7 @@ jobs:
echo ${{ github.event.pull_request.number }} > artifacts/screenshot_comparisons/pull_request_number.txt
- name: Upload bad screenshots
if: failure()
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: bad-screenshots
path: artifacts/screenshot_comparisons
diff --git a/.github/workflows/run_integration_tests.yml b/.github/workflows/run_integration_tests.yml
index d732f63cef3..71b8e4cd266 100644
--- a/.github/workflows/run_integration_tests.yml
+++ b/.github/workflows/run_integration_tests.yml
@@ -36,7 +36,7 @@ jobs:
major: ${{ inputs.major }}
minor: ${{ inputs.minor }}
- name: Download build outputs
- uses: actions/download-artifact@v5
+ uses: actions/download-artifact@v6
with:
name: build-artifact-${{ inputs.major || env.BYOND_MAJOR }}-${{ inputs.minor || env.BYOND_MINOR}}
path: ./
@@ -63,7 +63,7 @@ jobs:
bash tools/ci/run_server.sh ${{ inputs.map }}
- name: Upload screenshot tests
if: always()
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: test_artifacts_${{ inputs.map }}_${{ inputs.major }}_${{ inputs.minor }}
path: data/screenshots_new/
diff --git a/.github/workflows/setup_build_artifact.yml b/.github/workflows/setup_build_artifact.yml
index aaf4cfb4553..3cbfd8f39d9 100644
--- a/.github/workflows/setup_build_artifact.yml
+++ b/.github/workflows/setup_build_artifact.yml
@@ -35,7 +35,7 @@ jobs:
bash tools/ci/copy_build_output.sh $OUTPUT_DIR
- name: Upload artifact
if: success()
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: build-artifact-${{ inputs.major }}-${{ inputs.minor }}
path: ${{ env.OUTPUT_DIR }}
diff --git a/code/__DEFINES/icon_smoothing.dm b/code/__DEFINES/icon_smoothing.dm
index 5471e58b1d4..3f4558d89fb 100644
--- a/code/__DEFINES/icon_smoothing.dm
+++ b/code/__DEFINES/icon_smoothing.dm
@@ -239,6 +239,8 @@ DEFINE_BITFIELD(smoothing_junction, list(
#define SMOOTH_GROUP_PLATFORMS_PIZZA S_OBJ(85) ///obj/structure/platform/pizza
#define SMOOTH_GROUP_PLATFORMS_PAPER S_OBJ(86) ///obj/structure/platform/paper
+#define SMOOTH_GROUP_BOULDER_PLATFORM S_OBJ(89) ///obj/structure/lattice/catwalk/boulder
+
/// Performs the work to set smoothing_groups and canSmoothWith.
/// An inlined function used in both turf/Initialize and atom/Initialize.
#define SETUP_SMOOTHING(...) \
diff --git a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm
index 37faad6a2fb..9ae6ebca333 100644
--- a/code/__DEFINES/sound.dm
+++ b/code/__DEFINES/sound.dm
@@ -385,6 +385,8 @@ GLOBAL_LIST_EMPTY(sfx_datum_by_key)
#define SFX_GAS_MASK_PICKUP "gas_mask_pickup"
#define SFX_GAS_MASK_DROP "gas_mask_drop"
#define SFX_GAS_MASK_EQUIP "gas_mask_equip"
+#define SFX_GENERIC_DEVICE_PICKUP "generic_device_pickup"
+#define SFX_GENERIC_DEVICE_DROP "generic_device_drop"
// Standard is 44.1khz
#define MIN_EMOTE_PITCH 40000
diff --git a/code/datums/ai/monkey/monkey_controller.dm b/code/datums/ai/monkey/monkey_controller.dm
index 4c778f66122..d7929bf9a8e 100644
--- a/code/datums/ai/monkey/monkey_controller.dm
+++ b/code/datums/ai/monkey/monkey_controller.dm
@@ -31,8 +31,12 @@ have ways of interacting with a specific mob and control it.
/datum/targeting_strategy/basic/monkey
/datum/targeting_strategy/basic/monkey/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target)
+ // if they wronged us, all bets are off
if(controller.blackboard[BB_MONKEY_ENEMIES][the_target])
return FALSE
+ // target was forcibly set, all bets are off again
+ if(controller.blackboard[BB_MONKEY_CURRENT_ATTACK_TARGET] == the_target)
+ return FALSE
return ..()
/datum/ai_controller/monkey/process(seconds_per_tick)
diff --git a/code/datums/ai/monkey/monkey_subtrees.dm b/code/datums/ai/monkey/monkey_subtrees.dm
index 1210fe44ba1..9feb69df99c 100644
--- a/code/datums/ai/monkey/monkey_subtrees.dm
+++ b/code/datums/ai/monkey/monkey_subtrees.dm
@@ -55,7 +55,8 @@
controller.queue_behavior(/datum/ai_behavior/recruit_monkeys, BB_MONKEY_CURRENT_ATTACK_TARGET)
return
- controller.queue_behavior(/datum/ai_behavior/battle_screech/monkey)
+ if(SPT_PROB(ismonkey(living_pawn) ? 25 : 10, seconds_per_tick))
+ controller.queue_behavior(/datum/ai_behavior/battle_screech/monkey)
controller.queue_behavior(/datum/ai_behavior/monkey_attack_mob, BB_MONKEY_CURRENT_ATTACK_TARGET)
return SUBTREE_RETURN_FINISH_PLANNING
diff --git a/code/datums/components/space_allergy.dm b/code/datums/components/space_allergy.dm
index 595c5fc0dfa..a89161cfb77 100644
--- a/code/datums/components/space_allergy.dm
+++ b/code/datums/components/space_allergy.dm
@@ -18,6 +18,8 @@
SIGNAL_HANDLER
if(is_on_a_planet(parent) && parent.has_gravity())
- allergy = parent.apply_status_effect(/datum/status_effect/planet_allergy) //your gamer body cant stand real gravity < Soul
+ var/status_effect = parent.apply_status_effect(/datum/status_effect/planet_allergy) //your gamer body cant stand real gravity < Soul
+ if(status_effect)
+ allergy = status_effect
else
QDEL_NULL(allergy)
diff --git a/code/datums/components/wall_mounted.dm b/code/datums/components/wall_mounted.dm
index 757b171023e..ef050a7fc61 100644
--- a/code/datums/components/wall_mounted.dm
+++ b/code/datums/components/wall_mounted.dm
@@ -27,6 +27,7 @@
*/
/datum/component/wall_mounted/proc/on_examine(datum/source, mob/user, list/examine_list)
SIGNAL_HANDLER
+
if (parent in view(user.client?.view || world.view, user))
examine_list += span_notice("\The [hanging_wall_turf] is currently supporting [span_bold("[parent]")]. Deconstruction or excessive damage would cause it to [span_bold("fall to the ground")].")
diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm
index f6043d0b16e..bec38533cdd 100644
--- a/code/datums/status_effects/debuffs/debuffs.dm
+++ b/code/datums/status_effects/debuffs/debuffs.dm
@@ -374,8 +374,8 @@
return FALSE
marked_underlay = new()
- marked_underlay.pixel_w = -owner.pixel_x
- marked_underlay.pixel_z = -owner.pixel_y
+ marked_underlay.pixel_w = -(owner.base_pixel_x + owner.base_pixel_w)
+ marked_underlay.pixel_z = -(owner.base_pixel_y + owner.base_pixel_z)
marked_underlay.transform *= 0.5
owner.vis_contents += marked_underlay
animate(marked_underlay, ready_delay, transform = matrix() * 1.2, flags = CIRCULAR_EASING | EASE_IN)
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index 2f5d5a49073..5fa595c1de1 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -302,6 +302,13 @@
target_location = get_turf(src)
else
target_location = get_turf(src)
+
+ //give achievement for using unique material
+ if(design.materials[MAT_CATEGORY_ITEM_MATERIAL])
+ for(var/datum/material/material in materials_needed)
+ if(!istype(material, /datum/material/glass) && !istype(material, /datum/material/iron))
+ ui.user.client.give_award(/datum/award/achievement/misc/getting_an_upgrade, ui.user)
+ break
addtimer(CALLBACK(src, PROC_REF(do_make_item), design, build_count, build_time_per_item, material_cost_coefficient, charge_per_item, materials_needed, target_location), build_time_per_item)
return TRUE
diff --git a/code/game/objects/items/cosmetics.dm b/code/game/objects/items/cosmetics.dm
index 5b3bca0ecd5..d9b110c6107 100644
--- a/code/game/objects/items/cosmetics.dm
+++ b/code/game/objects/items/cosmetics.dm
@@ -194,6 +194,9 @@
inhand_icon_state = "razor"
obj_flags = CONDUCTS_ELECTRICITY
w_class = WEIGHT_CLASS_TINY
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
/obj/item/razor/suicide_act(mob/living/carbon/user)
user.visible_message(span_suicide("[user] begins shaving [user.p_them()]self without the razor guard! It looks like [user.p_theyre()] trying to commit suicide!"))
diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm
index 759790ab155..62ff966c91c 100644
--- a/code/game/objects/items/devices/aicard.dm
+++ b/code/game/objects/items/devices/aicard.dm
@@ -11,6 +11,9 @@
w_class = WEIGHT_CLASS_SMALL
slot_flags = ITEM_SLOT_BELT
item_flags = NOBLUDGEON
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
var/flush = FALSE
var/mob/living/silicon/ai/AI
diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm
index 0512c992370..05f99b4a447 100644
--- a/code/game/objects/items/devices/flashlight.dm
+++ b/code/game/objects/items/devices/flashlight.dm
@@ -25,6 +25,10 @@
light_range = 4
light_power = 1
light_on = FALSE
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
+
/// If we've been forcibly disabled for a temporary amount of time.
COOLDOWN_DECLARE(disabled_time)
/// Can we toggle this light on and off (used for contexual screentips only)
diff --git a/code/game/objects/items/devices/gps.dm b/code/game/objects/items/devices/gps.dm
index 7b8257d9ede..c3b17c4ce1f 100644
--- a/code/game/objects/items/devices/gps.dm
+++ b/code/game/objects/items/devices/gps.dm
@@ -11,6 +11,9 @@
w_class = WEIGHT_CLASS_SMALL
slot_flags = ITEM_SLOT_BELT
obj_flags = UNIQUE_RENAME
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
var/gpstag
var/tracking_on = TRUE
var/debug_mode = FALSE
diff --git a/code/game/objects/items/devices/radio/electropack.dm b/code/game/objects/items/devices/radio/electropack.dm
index 3867ace4fc1..c7507b31bd0 100644
--- a/code/game/objects/items/devices/radio/electropack.dm
+++ b/code/game/objects/items/devices/radio/electropack.dm
@@ -9,6 +9,9 @@
obj_flags = CONDUCTS_ELECTRICITY
slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_HUGE
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
custom_materials = list(/datum/material/iron=SHEET_MATERIAL_AMOUNT *5, /datum/material/glass=SHEET_MATERIAL_AMOUNT * 1.25)
var/on = TRUE
diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm
index 0fb0a30157f..b964310d663 100644
--- a/code/game/objects/items/devices/radio/intercom.dm
+++ b/code/game/objects/items/devices/radio/intercom.dm
@@ -42,10 +42,6 @@
find_and_hang_on_wall()
GLOB.intercoms_list += src
-/obj/item/radio/intercom/find_and_hang_on_wall()
- if(!unscrewed)
- return ..()
-
/obj/item/radio/intercom/Destroy()
GLOB.intercoms_list -= src
return ..()
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index 266f515152a..8af26ca6651 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -11,6 +11,9 @@
desc = "A basic handheld radio that communicates with local telecommunication networks."
dog_fashion = /datum/dog_fashion/back
interaction_flags_atom = parent_type::interaction_flags_atom | INTERACT_ATOM_ALLOW_USER_LOCATION | INTERACT_ATOM_IGNORE_MOBILITY
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
obj_flags = CONDUCTS_ELECTRICITY
slot_flags = ITEM_SLOT_BELT
diff --git a/code/game/objects/items/devices/scanners/autopsy_scanner.dm b/code/game/objects/items/devices/scanners/autopsy_scanner.dm
index af0ff55abd1..d407ce6b8e3 100644
--- a/code/game/objects/items/devices/scanners/autopsy_scanner.dm
+++ b/code/game/objects/items/devices/scanners/autopsy_scanner.dm
@@ -13,6 +13,9 @@
w_class = WEIGHT_CLASS_NORMAL
custom_materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT*2)
custom_price = PAYCHECK_COMMAND
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
/obj/item/autopsy_scanner/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!isliving(interacting_with))
diff --git a/code/game/objects/items/devices/scanners/health_analyzer.dm b/code/game/objects/items/devices/scanners/health_analyzer.dm
index 3c1e452b6cf..ffd5947d3c5 100644
--- a/code/game/objects/items/devices/scanners/health_analyzer.dm
+++ b/code/game/objects/items/devices/scanners/health_analyzer.dm
@@ -22,6 +22,9 @@
custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT *2)
interaction_flags_click = NEED_LITERACY|NEED_LIGHT|ALLOW_RESTING
custom_price = PAYCHECK_COMMAND
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
/// Verbose/condensed
var/mode = SCANNER_VERBOSE
/// HEALTH/WOUND
diff --git a/code/game/objects/items/devices/scanners/plant_analyzer.dm b/code/game/objects/items/devices/scanners/plant_analyzer.dm
index 857454fb7fc..e653d09dcb8 100644
--- a/code/game/objects/items/devices/scanners/plant_analyzer.dm
+++ b/code/game/objects/items/devices/scanners/plant_analyzer.dm
@@ -13,6 +13,9 @@
w_class = WEIGHT_CLASS_TINY
slot_flags = ITEM_SLOT_BELT
custom_materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT*0.3, /datum/material/glass =SMALL_MATERIAL_AMOUNT*0.2)
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
/// Cached data from ui_interact
var/list/last_scan_data
/// Weakref to the last thing we scanned
diff --git a/code/game/objects/items/devices/scanners/sequence_scanner.dm b/code/game/objects/items/devices/scanners/sequence_scanner.dm
index d22372fa108..938c5637b74 100644
--- a/code/game/objects/items/devices/scanners/sequence_scanner.dm
+++ b/code/game/objects/items/devices/scanners/sequence_scanner.dm
@@ -15,6 +15,9 @@
throw_speed = 3
throw_range = 7
custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT*2)
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
var/list/discovered = list() //hit a dna console to update the scanners database
var/list/buffer
diff --git a/code/game/objects/items/devices/scanners/t_scanner.dm b/code/game/objects/items/devices/scanners/t_scanner.dm
index 0e8e2c44182..30083139abd 100644
--- a/code/game/objects/items/devices/scanners/t_scanner.dm
+++ b/code/game/objects/items/devices/scanners/t_scanner.dm
@@ -11,6 +11,9 @@
lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi'
custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT * 1.5)
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
/// Is this T-Ray scanner currently on?
var/on = FALSE
diff --git a/code/game/objects/items/devices/sensor_device.dm b/code/game/objects/items/devices/sensor_device.dm
index e68c8095fe0..97320669be8 100644
--- a/code/game/objects/items/devices/sensor_device.dm
+++ b/code/game/objects/items/devices/sensor_device.dm
@@ -11,6 +11,9 @@
slot_flags = ITEM_SLOT_BELT
custom_price = PAYCHECK_CREW * 5
custom_premium_price = PAYCHECK_CREW * 6
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
/obj/item/sensor_device/attack_self(mob/user)
GLOB.crewmonitor.show(user,src) //Proc already exists, just had to call it
diff --git a/code/game/objects/items/holosign_creator.dm b/code/game/objects/items/holosign_creator.dm
index 23db75e850c..6e46cdb2a4d 100644
--- a/code/game/objects/items/holosign_creator.dm
+++ b/code/game/objects/items/holosign_creator.dm
@@ -13,6 +13,9 @@
throw_speed = 3
throw_range = 7
item_flags = NOBLUDGEON
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
var/list/signs
var/max_signs = 10
//time to create a holosign in deciseconds.
diff --git a/code/game/objects/items/inspector.dm b/code/game/objects/items/inspector.dm
index 2f96f3fb737..8a08562bd84 100644
--- a/code/game/objects/items/inspector.dm
+++ b/code/game/objects/items/inspector.dm
@@ -22,6 +22,9 @@
interaction_flags_click = NEED_DEXTERITY
throw_range = 1
throw_speed = 1
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
///How long it takes to print on time each mode, ordered NORMAL, FAST, HONK
var/list/time_list = list(5 SECONDS, 1 SECONDS, 0.1 SECONDS)
///Which print time mode we're on.
diff --git a/code/game/objects/items/pinpointer.dm b/code/game/objects/items/pinpointer.dm
index 2d5c09546d9..4fcb9a7aa79 100644
--- a/code/game/objects/items/pinpointer.dm
+++ b/code/game/objects/items/pinpointer.dm
@@ -14,6 +14,9 @@
throw_speed = 3
throw_range = 7
custom_materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT * 5, /datum/material/glass = SMALL_MATERIAL_AMOUNT * 2.5)
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
var/active = FALSE
var/atom/movable/target //The thing we're searching for
var/minimum_range = 0 //at what range the pinpointer declares you to be at your destination
diff --git a/code/game/objects/items/storage/wallets.dm b/code/game/objects/items/storage/wallets.dm
index 8ab4b176ee1..51bb6b6e0e1 100644
--- a/code/game/objects/items/storage/wallets.dm
+++ b/code/game/objects/items/storage/wallets.dm
@@ -35,7 +35,7 @@
is_magnetic_found = TRUE
if(!is_magnetic_found)
- var/card_tally = SSid_access.tally_access(id_card, ACCESS_FLAG_COMMAND)
+ var/card_tally = SSid_access.tally_access(id_card, ACCESS_FLAG_PRV_COMMAND)
if(card_tally > winning_tally)
winning_tally = card_tally
front_id = id_card
diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm
index f2cf5cd6443..b0c2ef8cfe4 100644
--- a/code/game/objects/items/teleportation.dm
+++ b/code/game/objects/items/teleportation.dm
@@ -87,6 +87,9 @@
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 5)
armor_type = /datum/armor/item_hand_tele
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
///List of portal pairs created by this hand tele
var/list/active_portal_pairs = list()
///Maximum concurrent active portal pairs allowed
diff --git a/code/game/objects/items/wall_mounted.dm b/code/game/objects/items/wall_mounted.dm
index 3791970c38a..be07215f3dc 100644
--- a/code/game/objects/items/wall_mounted.dm
+++ b/code/game/objects/items/wall_mounted.dm
@@ -102,3 +102,6 @@
custom_materials = list(/datum/material/iron= SMALL_MATERIAL_AMOUNT * 0.5, /datum/material/glass= SMALL_MATERIAL_AMOUNT * 0.5)
grind_results = list(/datum/reagent/iron = 10, /datum/reagent/silicon = 10)
custom_price = PAYCHECK_CREW * 0.5
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm
index 34279684ce1..4791a50f6fe 100644
--- a/code/game/objects/structures/lattice.dm
+++ b/code/game/objects/structures/lattice.dm
@@ -196,12 +196,11 @@
/obj/structure/lattice/catwalk/boulder
name = "boulder platform"
desc = "A boulder, floating on the molten hot deadly lava. More like a BOATlder."
- icon = 'icons/obj/ore.dmi'
- icon_state = "boulder_platform"
+ icon = 'icons/obj/smooth_structures/boulder_platform.dmi'
+ icon_state = "boulder_platform-0"
base_icon_state = "boulder_platform"
- smoothing_flags = NONE
- smoothing_groups = null
- canSmoothWith = null
+ smoothing_groups = SMOOTH_GROUP_BOULDER_PLATFORM
+ canSmoothWith = SMOOTH_GROUP_BOULDER_PLATFORM + SMOOTH_GROUP_FLOOR_LAVA
build_material = null
/// The type of particle to make before the platform collapses.
var/warning_particle = /particles/smoke/ash
@@ -224,10 +223,9 @@
. = ..()
/obj/structure/lattice/catwalk/boulder/proc/pre_self_destruct()
- if(istype(loc, /turf/open/lava/plasma))
- add_overlay("plasma_cracks")
- else
- add_overlay("lava_cracks")
+ var/mutable_appearance/cracks_overlay = mutable_appearance('icons/obj/ore.dmi', istype(loc, /turf/open/lava/plasma) ? "plasma_cracks" : "lava_cracks", src)
+ cracks_overlay.blend_mode = BLEND_INSET_OVERLAY
+ add_overlay(cracks_overlay)
animate(src, alpha = 0, time = 2 SECONDS, pixel_y = -16, easing = QUAD_EASING|EASE_IN)
addtimer(CALLBACK(src, PROC_REF(self_destruct)), 2 SECONDS)
diff --git a/code/game/objects/structures/signs/_signs.dm b/code/game/objects/structures/signs/_signs.dm
index d1baf9970d4..905d709b273 100644
--- a/code/game/objects/structures/signs/_signs.dm
+++ b/code/game/objects/structures/signs/_signs.dm
@@ -117,7 +117,6 @@
unwrenched_sign.sign_path = type
unwrenched_sign.set_custom_materials(custom_materials) //This is here so picture frames and wooden things don't get messed up.
unwrenched_sign.is_editable = is_editable
- unwrenched_sign.update_integrity(get_integrity()) //Transfer how damaged it is.
unwrenched_sign.setDir(dir)
/obj/structure/sign/blank //This subtype is necessary for now because some other things (posters, picture frames, paintings) inherit from the parent type.
diff --git a/code/game/sound/sound_keys/sound_keys.dm b/code/game/sound/sound_keys/sound_keys.dm
index 0a7c4ea9e0f..e8d528408e1 100644
--- a/code/game/sound/sound_keys/sound_keys.dm
+++ b/code/game/sound/sound_keys/sound_keys.dm
@@ -1089,3 +1089,22 @@
'sound/items/gas_mask/gas_mask_equip3.ogg',
)
+/datum/sound_effect/generic_device_pickup
+ key = SFX_GENERIC_DEVICE_PICKUP
+ file_paths = list(
+ 'sound/items/generic_device/generic_device_pickup1.ogg',
+ 'sound/items/generic_device/generic_device_pickup2.ogg',
+ 'sound/items/generic_device/generic_device_pickup3.ogg',
+ 'sound/items/generic_device/generic_device_pickup4.ogg',
+ 'sound/items/generic_device/generic_device_pickup5.ogg',
+ )
+
+/datum/sound_effect/generic_device_drop
+ key = SFX_GENERIC_DEVICE_DROP
+ file_paths = list(
+ 'sound/items/generic_device/generic_device_drop1.ogg',
+ 'sound/items/generic_device/generic_device_drop2.ogg',
+ 'sound/items/generic_device/generic_device_drop3.ogg',
+ 'sound/items/generic_device/generic_device_drop4.ogg',
+ 'sound/items/generic_device/generic_device_drop5.ogg',
+ )
diff --git a/code/modules/antagonists/heretic/status_effects/debuffs.dm b/code/modules/antagonists/heretic/status_effects/debuffs.dm
index 0e840f485cd..2939f2066a8 100644
--- a/code/modules/antagonists/heretic/status_effects/debuffs.dm
+++ b/code/modules/antagonists/heretic/status_effects/debuffs.dm
@@ -157,7 +157,6 @@
/datum/status_effect/star_mark/extended
duration = 3 MINUTES
-f
/// Used by moon heretics to make people mad
/datum/status_effect/moon_converted
diff --git a/code/modules/experisci/handheld_scanner.dm b/code/modules/experisci/handheld_scanner.dm
index 67850aedd28..f89fda97f3f 100644
--- a/code/modules/experisci/handheld_scanner.dm
+++ b/code/modules/experisci/handheld_scanner.dm
@@ -11,6 +11,9 @@
icon_state = "experiscanner"
lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi'
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
/obj/item/experi_scanner/Initialize(mapload)
..()
diff --git a/code/modules/explorer_drone/control_console.dm b/code/modules/explorer_drone/control_console.dm
index 78451dd71a1..21c64757bc1 100644
--- a/code/modules/explorer_drone/control_console.dm
+++ b/code/modules/explorer_drone/control_console.dm
@@ -23,16 +23,18 @@
RegisterSignal(controlled_drone,COMSIG_QDELETING, PROC_REF(drone_destroyed))
RegisterSignal(controlled_drone,COMSIG_EXODRONE_STATUS_CHANGED, PROC_REF(on_exodrone_status_changed))
update_icon()
+ playsound(src, 'sound/machines/terminal/terminal_on.ogg', 20, vary = TRUE)
/obj/machinery/computer/exodrone_control_console/proc/on_exodrone_status_changed()
SIGNAL_HANDLER
//Notify we need human action and switch screeb icon to alert.
- playsound(src,'sound/machines/ping.ogg',30,FALSE)
+ playsound(src, 'sound/machines/terminal/terminal_processing.ogg', 20, vary = TRUE)
update_icon()
/obj/machinery/computer/exodrone_control_console/proc/drone_destroyed()
SIGNAL_HANDLER
signal_lost = TRUE
+ playsound(src, 'sound/machines/terminal/terminal_alert.ogg', 20, vary = TRUE)
end_drone_control()
/obj/machinery/computer/exodrone_control_console/proc/end_drone_control()
@@ -41,6 +43,7 @@
UnregisterSignal(controlled_drone,list(COMSIG_QDELETING,COMSIG_EXODRONE_STATUS_CHANGED))
controlled_drone = null
update_icon()
+ playsound(src, 'sound/machines/terminal/terminal_off.ogg', 20, vary = TRUE)
/obj/machinery/computer/exodrone_control_console/Destroy()
. = ..()
@@ -114,7 +117,7 @@
signal_lost = FALSE
return TRUE
if("self_destruct")
- qdel(controlled_drone) //var will be nulled in signal response
+ controlled_drone.handle_deconstruct()
return TRUE
if("add_tool")
if(controlled_drone && controlled_drone.drone_status == EXODRONE_IDLE)
diff --git a/code/modules/explorer_drone/exodrone.dm b/code/modules/explorer_drone/exodrone.dm
index e0b1aec07b2..08fc0ae9142 100644
--- a/code/modules/explorer_drone/exodrone.dm
+++ b/code/modules/explorer_drone/exodrone.dm
@@ -76,9 +76,14 @@ GLOBAL_LIST_EMPTY(exodrone_launchers)
// Cargo storage
create_storage(max_slots = EXODRONE_CARGO_SLOTS, canthold = GLOB.blacklisted_cargo_types)
-/obj/item/exodrone/Destroy()
+/obj/item/exodrone/handle_deconstruct(disassembled)
. = ..()
+ explosion(src, 0, 0, 1, 1)
+ do_sparks(5, FALSE, src)
+
+/obj/item/exodrone/Destroy()
GLOB.exodrones -= src
+ . = ..()
/// Description for drone listing, describes location and current status
/obj/item/exodrone/proc/ui_description()
@@ -337,7 +342,7 @@ GLOBAL_LIST_EMPTY(exodrone_launchers)
/obj/item/exodrone/proc/drone_log(message)
if(length(drone_log) > EXODRONE_LOG_SIZE)
- drone_log = list()
+ drone_log.Remove()
drone_log.Insert(1,message)
/obj/item/exodrone/proc/has_tool(tool_type)
diff --git a/code/modules/explorer_drone/scanner_array.dm b/code/modules/explorer_drone/scanner_array.dm
index 7588eae233a..237c3aee606 100644
--- a/code/modules/explorer_drone/scanner_array.dm
+++ b/code/modules/explorer_drone/scanner_array.dm
@@ -175,6 +175,7 @@ GLOBAL_LIST_INIT(scan_conditions,init_scan_conditions())
var/datum/exoscan/scan = GLOB.exoscanner_controller.create_scan(scan_type,target)
if(scan)
RegisterSignal(scan, COMSIG_EXOSCAN_INTERRUPTED, PROC_REF(scan_failed))
+ playsound(src, 'sound/machines/terminal/terminal_processing.ogg', 20, vary = TRUE)
/obj/machinery/computer/exoscanner_control/proc/scan_failed()
SIGNAL_HANDLER
diff --git a/code/modules/fishing/aquarium/fish_analyzer.dm b/code/modules/fishing/aquarium/fish_analyzer.dm
index 35b01e1edc9..9202420ee1f 100644
--- a/code/modules/fishing/aquarium/fish_analyzer.dm
+++ b/code/modules/fishing/aquarium/fish_analyzer.dm
@@ -72,37 +72,30 @@
if(target != scanned_object)
unregister_scanned()
register_scanned(target)
- update_static_data_for_all_viewers()
ui_interact(user)
return ITEM_INTERACT_SUCCESS
/obj/item/fish_analyzer/proc/register_scanned(atom/target)
scanned_object = target
RegisterSignal(target, COMSIG_QDELETING, PROC_REF(on_target_deleted))
- if(HAS_TRAIT(target, TRAIT_IS_AQUARIUM))
- RegisterSignals(target, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON, COMSIG_ATOM_EXITED), PROC_REF(aquarium_update))
/obj/item/fish_analyzer/proc/unregister_scanned()
if(!scanned_object)
return
- UnregisterSignal(scanned_object, list(COMSIG_QDELETING, COMSIG_ATOM_ENTERED, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON, COMSIG_ATOM_EXITED))
+ UnregisterSignal(scanned_object, COMSIG_QDELETING)
scanned_object = null
/obj/item/fish_analyzer/proc/on_target_deleted()
SIGNAL_HANDLER
unregister_scanned()
-/obj/item/fish_analyzer/proc/aquarium_update()
- SIGNAL_HANDLER
- //update static data on the next tick. to give time to offsprings to properly inherit the parents' traits and all.
- addtimer(CALLBACK(src, TYPE_PROC_REF(/datum, update_static_data_for_all_viewers)), 0)
-
/obj/item/fish_analyzer/ui_interact(mob/user, datum/tgui/ui)
if(isnull(scanned_object))
balloon_alert(user, "no specimen data!")
return TRUE
if(!(scanned_object in view(7, get_turf(src))))
balloon_alert(user, "specimen data lost!")
+ unregister_scanned()
return TRUE
ui = SStgui.try_update_ui(user, src, ui)
@@ -117,25 +110,13 @@
return UI_CLOSE
return ..()
-/obj/item/fish_analyzer/ui_static_data(mob/user)
+/obj/item/fish_analyzer/ui_data(mob/user)
var/list/data = list()
data["fish_list"] = list()
data["fish_scanned"] = FALSE
if(isfish(scanned_object))
data["fish_scanned"] = TRUE
- return extract_static_fish_info(data, scanned_object)
-
- for(var/obj/item/fish/fishie in scanned_object)
- extract_static_fish_info(data, fishie)
-
- return data
-
-/obj/item/fish_analyzer/ui_data(mob/user)
- var/list/data = list()
- data["fish_list"] = list()
-
- if(isfish(scanned_object))
return extract_fish_info(data, scanned_object)
for(var/obj/item/fish/fishie in scanned_object)
@@ -143,7 +124,7 @@
return data
-/obj/item/fish_analyzer/proc/extract_static_fish_info(list/data, obj/item/fish/fishie)
+/obj/item/fish_analyzer/proc/extract_fish_info(list/data, obj/item/fish/fishie)
var/list/fish_traits = list()
var/list/fish_evolutions = list()
@@ -175,12 +156,6 @@
"fish_traits" = fish_traits,
"fish_evolutions" = fish_evolutions,
"fish_suitable_temp" = fishie.fish_flags & FISH_FLAG_SAFE_TEMPERATURE,
- ))
-
- return data
-
-/obj/item/fish_analyzer/proc/extract_fish_info(list/data, obj/item/fish/fishie)
- data["fish_list"] += list(list(
"fish_health" = fishie.status == FISH_DEAD ? 0 : PERCENT(fishie.get_health_percentage()),
"fish_size" = fishie.size,
"fish_weight" = fishie.weight,
diff --git a/code/modules/fishing/fish/_fish.dm b/code/modules/fishing/fish/_fish.dm
index e3f57d74582..aaec020028d 100644
--- a/code/modules/fishing/fish/_fish.dm
+++ b/code/modules/fishing/fish/_fish.dm
@@ -232,7 +232,7 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list(
register_context()
register_item_context()
- if(!PERFORM_ALL_TESTS(focus_only/fish_population) || type == abstract_type || stable_population > 1)
+ if(!apply_qualities || !PERFORM_ALL_TESTS(focus_only/fish_population) || type == abstract_type || stable_population > 1)
return
if(length(compatible_types))
for(var/obj/item/fish/fishie as anything in compatible_types)
diff --git a/code/modules/fishing/fish_mount.dm b/code/modules/fishing/fish_mount.dm
index 491abe25ce7..3f5671e653e 100644
--- a/code/modules/fishing/fish_mount.dm
+++ b/code/modules/fishing/fish_mount.dm
@@ -69,7 +69,8 @@
return ITEM_INTERACT_SUCCESS
/obj/structure/fish_mount/proc/add_first_fish()
- var/obj/item/fish/fish_path = pick(subtypesof(/obj/item/fish) - list(typesof(/obj/item/fish/holo) + list(/obj/item/fish/starfish/chrystarfish))) // chrystarfish immediately shatters when placed
+ var/list/valid_picks = subtypesof(/obj/item/fish) - typesof(/obj/item/fish/holo) - /obj/item/fish/starfish/chrystarfish // chrystarfish immediately shatters when placed
+ var/obj/item/fish/fish_path = pick(valid_picks)
if(fish_path.fish_id_redirect_path)
fish_path = fish_path.fish_id_redirect_path
var/fluff_name = pick("John Trasen III", "a nameless intern", "Pun Pun", AQUARIUM_COMPANY, "Unknown", "Central Command")
diff --git a/code/modules/mod/modules/_module.dm b/code/modules/mod/modules/_module.dm
index d2e916f2ff5..0c7e637d8b7 100644
--- a/code/modules/mod/modules/_module.dm
+++ b/code/modules/mod/modules/_module.dm
@@ -4,6 +4,9 @@
icon = 'icons/obj/clothing/modsuit/mod_modules.dmi'
icon_state = "module"
abstract_type = /obj/item/mod/module
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
/// If it can be removed
var/removable = TRUE
/// If it's passive, togglable, usable or active
diff --git a/code/modules/modular_computers/computers/item/pda.dm b/code/modules/modular_computers/computers/item/pda.dm
index b58b3b89083..b2f4839021f 100644
--- a/code/modules/modular_computers/computers/item/pda.dm
+++ b/code/modules/modular_computers/computers/item/pda.dm
@@ -31,6 +31,9 @@
shell_capacity = SHELL_CAPACITY_SMALL
action_slots = ALL
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
///The item currently inserted into the PDA, starts with a pen.
var/obj/item/inserted_item = /obj/item/pen
diff --git a/code/modules/pai/card.dm b/code/modules/pai/card.dm
index 0c394227c6c..b5d2e183c9f 100644
--- a/code/modules/pai/card.dm
+++ b/code/modules/pai/card.dm
@@ -11,6 +11,9 @@
slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
worn_icon_state = "electronic"
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
/// Spam alert prevention
var/alert_cooldown
diff --git a/code/modules/power/apc/apc_main.dm b/code/modules/power/apc/apc_main.dm
index 4a8572c4080..fca1ac293ac 100644
--- a/code/modules/power/apc/apc_main.dm
+++ b/code/modules/power/apc/apc_main.dm
@@ -173,29 +173,14 @@
//. += NAMEOF(src, locked)
return .
-/obj/machinery/power/apc/Initialize(mapload, ndir)
+/obj/machinery/power/apc/Initialize(mapload)
. = ..()
+ setDir(dir)
//APCs get added to their own processing tasks for the machines subsystem.
if (!(datum_flags & DF_ISPROCESSING))
datum_flags |= DF_ISPROCESSING
SSmachines.processing_apcs += src
- //Pixel offset its appearance based on its direction
- dir = ndir
- switch(dir)
- if(NORTH)
- offset_old = pixel_y
- pixel_y = APC_PIXEL_OFFSET
- if(SOUTH)
- offset_old = pixel_y
- pixel_y = -APC_PIXEL_OFFSET
- if(EAST)
- offset_old = pixel_x
- pixel_x = APC_PIXEL_OFFSET
- if(WEST)
- offset_old = pixel_x
- pixel_x = -APC_PIXEL_OFFSET
-
var/image/hud_image = image(icon = 'icons/mob/huds/hud.dmi', icon_state = "apc_hacked")
hud_image.pixel_w = pixel_x
hud_image.pixel_z = pixel_y
@@ -278,6 +263,22 @@
disconnect_terminal()
return ..()
+/obj/machinery/power/apc/setDir(newdir)
+ . = ..()
+ switch(newdir)
+ if(NORTH)
+ offset_old = pixel_y
+ pixel_y = APC_PIXEL_OFFSET
+ if(SOUTH)
+ offset_old = pixel_y
+ pixel_y = -APC_PIXEL_OFFSET
+ if(EAST)
+ offset_old = pixel_x
+ pixel_x = APC_PIXEL_OFFSET
+ if(WEST)
+ offset_old = pixel_x
+ pixel_x = -APC_PIXEL_OFFSET
+
/obj/machinery/power/apc/on_saboteur(datum/source, disrupt_duration)
. = ..()
disrupt_duration *= 0.1 // so, turns out, failure timer is in seconds, not deciseconds; without this, disruptions last 10 times as long as they probably should
diff --git a/code/modules/power/lighting/light_construct.dm b/code/modules/power/lighting/light_construct.dm
index c3872130b25..c38a34318ca 100644
--- a/code/modules/power/lighting/light_construct.dm
+++ b/code/modules/power/lighting/light_construct.dm
@@ -145,6 +145,7 @@
if("bulb")
new_light = new /obj/machinery/light/small/built(loc)
new_light.setDir(dir)
+ new_light.find_and_hang_on_wall()
transfer_fingerprints_to(new_light)
if(!QDELETED(cell))
new_light.cell = cell
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 5ee9459b13c..c542f4c4079 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -1113,7 +1113,7 @@
return
for(var/datum/surgery/surgery as anything in exposed_carbon.surgeries)
- surgery.speed_modifier = max(0.2, surgery.speed_modifier)
+ surgery.speed_modifier = min(0.8, surgery.speed_modifier)
*/// BUBBER EDIT REMOVAL END
/datum/reagent/space_cleaner/sterilizine/on_burn_wound_processing(datum/wound/burn/flesh/burn_wound)
diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm
index a417b3609e6..c2b80584b06 100644
--- a/code/modules/recycling/sortingmachinery.dm
+++ b/code/modules/recycling/sortingmachinery.dm
@@ -263,6 +263,9 @@
righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi'
obj_flags = CONDUCTS_ELECTRICITY
slot_flags = ITEM_SLOT_BELT
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
/obj/item/dest_tagger/borg
name = "cyborg destination tagger"
diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm
index 5a2a2a47630..ffbf453f393 100644
--- a/code/modules/research/stock_parts.dm
+++ b/code/modules/research/stock_parts.dm
@@ -9,6 +9,9 @@ If you create T5+ please take a pass at mech_fabricator.dm. The parts being good
///The generic category type that the stock part belongs to. Generic objects that should not be instantiated should have the same type and abstract_type
abstract_type = /obj/item/stock_parts
w_class = WEIGHT_CLASS_SMALL
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
var/rating = 1
///Used when a base part has a different name to higher tiers of part. For example, machine frames want any servo and not just a micro-servo.
var/base_name
diff --git a/code/modules/surgery/organs/internal/eyes/_eyes.dm b/code/modules/surgery/organs/internal/eyes/_eyes.dm
index 6d9582fc0c8..a466b2ee3db 100644
--- a/code/modules/surgery/organs/internal/eyes/_eyes.dm
+++ b/code/modules/surgery/organs/internal/eyes/_eyes.dm
@@ -160,9 +160,9 @@
organ_owner.remove_status_effect(/datum/status_effect/temporary_blindness)
if (scarring)
- owner.cure_nearsighted(TRAIT_RIGHT_EYE_SCAR)
- owner.cure_nearsighted(TRAIT_LEFT_EYE_SCAR)
- owner.cure_blind(EYE_SCARRING_TRAIT)
+ organ_owner.cure_nearsighted(TRAIT_RIGHT_EYE_SCAR)
+ organ_owner.cure_nearsighted(TRAIT_LEFT_EYE_SCAR)
+ organ_owner.cure_blind(EYE_SCARRING_TRAIT)
organ_owner.update_tint()
organ_owner.update_sight()
diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm
index ec2c59bd640..7291157ba48 100644
--- a/code/modules/surgery/tools.dm
+++ b/code/modules/surgery/tools.dm
@@ -643,6 +643,9 @@
attack_verb_simple = list("pump", "siphon")
tool_behaviour = TOOL_BLOODFILTER
toolspeed = 1
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
/// Assoc list of chem ids to names, used for deciding which chems to filter when used for surgery
var/list/whitelist = list()
var/surgical_tray_overlay = "filter"
diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm
index e7d336478be..c461ebd035c 100644
--- a/code/modules/unit_tests/unit_test.dm
+++ b/code/modules/unit_tests/unit_test.dm
@@ -18,6 +18,8 @@ GLOBAL_LIST_EMPTY(unit_test_mapping_logs)
/// Global assoc list of required mapping items, [item typepath] to [required item datum].
GLOBAL_LIST_EMPTY(required_map_items)
+GLOBAL_LIST_EMPTY(test_run_times)
+
/// A list of every test that is currently focused.
/// Use the PERFORM_ALL_TESTS macro instead.
GLOBAL_VAR_INIT(focused_tests, focused_tests())
@@ -237,6 +239,8 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests())
log_test(message)
test_output_desc += " [duration / 10]s"
+ if(duration > 10)
+ GLOB.test_run_times[test_path] = duration
if (test.succeeded)
log_world("[TEST_OUTPUT_GREEN("PASS")] [test_output_desc]")
@@ -409,6 +413,12 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests())
RunUnitTest(unit_path, test_results)
SSticker.delay_end = FALSE
+ log_world("::group::Expensive Unit Test Times")
+ sortTim(GLOB.test_run_times, cmp = GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE)
+ for(var/type, duration in GLOB.test_run_times)
+ log_world("[type] took [duration/10]s")
+ log_world("::endgroup::")
+
var/file_name = "data/unit_tests.json"
fdel(file_name)
file(file_name) << json_encode(test_results)
diff --git a/code/modules/vehicles/mecha/mecha_parts.dm b/code/modules/vehicles/mecha/mecha_parts.dm
index a8719eb1d4d..e0a31c762da 100644
--- a/code/modules/vehicles/mecha/mecha_parts.dm
+++ b/code/modules/vehicles/mecha/mecha_parts.dm
@@ -9,6 +9,9 @@
abstract_type = /obj/item/mecha_parts
w_class = WEIGHT_CLASS_GIGANTIC
obj_flags = CONDUCTS_ELECTRICITY
+ sound_vary = TRUE
+ pickup_sound = SFX_GENERIC_DEVICE_PICKUP
+ drop_sound = SFX_GENERIC_DEVICE_DROP
/obj/item/mecha_parts/proc/try_attach_part(mob/user, obj/vehicle/sealed/mecha/M, attach_right = FALSE) //For attaching parts to a finished mech
if(!user.transferItemToLoc(src, M))
diff --git a/html/changelogs/AutoChangeLog-pr-93461.yml b/html/changelogs/AutoChangeLog-pr-93461.yml
deleted file mode 100644
index f0f660598cb..00000000000
--- a/html/changelogs/AutoChangeLog-pr-93461.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-author: "Ghommie"
-delete-after: True
-changes:
- - qol: "The fish analyzer UI should update more reliably."
- - bugfix: "Fixed some of the fishes being unable to reproduce."
- - balance: "Fish acquired through means other than fish farming itself takes less time to be able to reproduce."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-93499.yml b/html/changelogs/AutoChangeLog-pr-93499.yml
deleted file mode 100644
index 93afa6515e0..00000000000
--- a/html/changelogs/AutoChangeLog-pr-93499.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Krysonism"
-delete-after: True
-changes:
- - balance: "prosthetic item limbs are no longer considered equipped items for some purposes such as ventcrawling."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-93521.yml b/html/changelogs/AutoChangeLog-pr-93521.yml
deleted file mode 100644
index c5a531e96df..00000000000
--- a/html/changelogs/AutoChangeLog-pr-93521.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "SmArtKar"
-delete-after: True
-changes:
- - bugfix: "Fixed dropped limbs rotating and disappearing when pulled/thrown"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-93534.yml b/html/changelogs/AutoChangeLog-pr-93534.yml
deleted file mode 100644
index 06e318aec4a..00000000000
--- a/html/changelogs/AutoChangeLog-pr-93534.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "SyncIt21"
-delete-after: True
-changes:
- - bugfix: "wall mounts placed by player now falls off when the wall they are mounted on is destroyed"
- - code_imp: "cleaned up wall mount code"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-93552.yml b/html/changelogs/AutoChangeLog-pr-93552.yml
deleted file mode 100644
index 9c12166aabc..00000000000
--- a/html/changelogs/AutoChangeLog-pr-93552.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "SmArtKar"
-delete-after: True
-changes:
- - bugfix: "Fixed glow bleeding through chair and sofa armrests"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-93554.yml b/html/changelogs/AutoChangeLog-pr-93554.yml
deleted file mode 100644
index 7092bb04750..00000000000
--- a/html/changelogs/AutoChangeLog-pr-93554.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "TheNobodyofimportance"
-delete-after: True
-changes:
- - balance: "Vomit drinking now checks for fly mouth instead of fly species"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-93559.yml b/html/changelogs/AutoChangeLog-pr-93559.yml
deleted file mode 100644
index 92d408c0e1e..00000000000
--- a/html/changelogs/AutoChangeLog-pr-93559.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "SmArtKar"
-delete-after: True
-changes:
- - bugfix: "Fixed an issue which could randomly completely break a player's visuals until an admin resets their HUD"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-93562.yml b/html/changelogs/AutoChangeLog-pr-93562.yml
new file mode 100644
index 00000000000..8d9d9de7fcf
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-93562.yml
@@ -0,0 +1,4 @@
+author: "JoJe3003"
+delete-after: True
+changes:
+ - bugfix: "Admin spawn panel toggle \"By name\"/\"By type\" updates search results without having to update the search string."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-93566.yml b/html/changelogs/AutoChangeLog-pr-93566.yml
deleted file mode 100644
index e1141113e33..00000000000
--- a/html/changelogs/AutoChangeLog-pr-93566.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Aliceee2ch"
-delete-after: True
-changes:
- - balance: "Minimal hacked APC amount for purchasing doomsday module was lowered from 15 to 10."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-93585.yml b/html/changelogs/AutoChangeLog-pr-93585.yml
new file mode 100644
index 00000000000..a62e8e58b2b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-93585.yml
@@ -0,0 +1,4 @@
+author: "Time-Green"
+delete-after: True
+changes:
+ - bugfix: "Voidwalker's 'planet allergy' effect goes away again when you leave a planet"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-93597.yml b/html/changelogs/AutoChangeLog-pr-93597.yml
new file mode 100644
index 00000000000..5ede190b21a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-93597.yml
@@ -0,0 +1,4 @@
+author: "TealSeer"
+delete-after: True
+changes:
+ - code_imp: "removed f"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-93604.yml b/html/changelogs/AutoChangeLog-pr-93604.yml
new file mode 100644
index 00000000000..4bf5632f91d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-93604.yml
@@ -0,0 +1,5 @@
+author: "mcbalaam"
+delete-after: True
+changes:
+ - qol: "Better exodrone console UI"
+ - rscadd: "Exodrones now create a small explosion (0, 0, 1, 1) when self-destruction is triggered"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-93606.yml b/html/changelogs/AutoChangeLog-pr-93606.yml
new file mode 100644
index 00000000000..dd5f128af19
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-93606.yml
@@ -0,0 +1,7 @@
+author: "SyncIt21"
+delete-after: True
+changes:
+ - bugfix: "hand crafted station intercoms now get deconstructed when the wall is destroyed"
+ - bugfix: "light fixtures applying the wall mounted component on completed light frames"
+ - bugfix: "APC offsets are correct"
+ - bugfix: "poster signs dropped from paintings again have positive integrity and will get destroyed properly"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-93612.yml b/html/changelogs/AutoChangeLog-pr-93612.yml
new file mode 100644
index 00000000000..2bd3a6dbe6e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-93612.yml
@@ -0,0 +1,4 @@
+author: "FeudeyTF"
+delete-after: True
+changes:
+ - bugfix: "Now you can get \"Getting an upgrade\" achievement. Craft your own unique item!"
\ No newline at end of file
diff --git a/html/changelogs/archive/2025-10.yml b/html/changelogs/archive/2025-10.yml
index ae298c065aa..8c8fc28ec4c 100644
--- a/html/changelogs/archive/2025-10.yml
+++ b/html/changelogs/archive/2025-10.yml
@@ -761,3 +761,42 @@
layout, pipes and cables too
- map: CATWALK - AI Upload - Re-balanced to have extra protection similar to every
other map, layout tweaks for style as well as clearer layout of modules
+2025-10-24:
+ Aliceee2ch:
+ - balance: Minimal hacked APC amount for purchasing doomsday module was lowered
+ from 15 to 10.
+ ArchBTW:
+ - qol: 'Changes Wallet Priority: Standard ID cards now go in order properly: from
+ left to right'
+ Ghommie:
+ - qol: The fish analyzer UI should update more reliably.
+ - bugfix: Fixed some of the fishes being unable to reproduce.
+ - balance: Fish acquired through means other than fish farming itself takes less
+ time to be able to reproduce.
+ Krysonism:
+ - balance: prosthetic item limbs are no longer considered equipped items for some
+ purposes such as ventcrawling.
+ Melbert:
+ - bugfix: Angry monkeys (and the primal instincts trauma) are VIOLENT again
+ - qol: Monkeys no longer screech every tick they are attacking someone (now ~1 in
+ 4 ticks, or ~1 in 10 for primal instincts)
+ SmArtKar:
+ - bugfix: Fixed dropped limbs rotating and disappearing when pulled/thrown
+ - bugfix: Fixed an issue which could randomly completely break a player's visuals
+ until an admin resets their HUD
+ - bugfix: Fixed glow bleeding through chair and sofa armrests
+ SyncIt21:
+ - bugfix: wall mounts placed by player now falls off when the wall they are mounted
+ on is destroyed
+ - code_imp: cleaned up wall mount code
+ TheNobodyofimportance:
+ - balance: Vomit drinking now checks for fly mouth instead of fly species
+2025-10-25:
+ MGOOOOOO:
+ - bugfix: Sterilizine will now correctly apply its 20% surgery speed bonus.
+ SmArtKar:
+ - bugfix: Fixed PKC mark effect being offset to the side when applied to some mobs.
+ - image: Boulder platforms spawned by throwing boulders on lava or activating vents
+ now have new sprites that smooth together
+ grungussuss:
+ - sound: added handling sounds for various devices
diff --git a/icons/obj/ore.dmi b/icons/obj/ore.dmi
index 5346161a9e7..81a7cb03fdf 100644
Binary files a/icons/obj/ore.dmi and b/icons/obj/ore.dmi differ
diff --git a/icons/obj/smooth_structures/boulder_platform.dmi b/icons/obj/smooth_structures/boulder_platform.dmi
new file mode 100644
index 00000000000..34c99f2dd5c
Binary files /dev/null and b/icons/obj/smooth_structures/boulder_platform.dmi differ
diff --git a/icons/obj/smooth_structures/boulder_platform.png b/icons/obj/smooth_structures/boulder_platform.png
new file mode 100644
index 00000000000..ac31e2b79be
Binary files /dev/null and b/icons/obj/smooth_structures/boulder_platform.png differ
diff --git a/icons/obj/smooth_structures/boulder_platform.png.toml b/icons/obj/smooth_structures/boulder_platform.png.toml
new file mode 100644
index 00000000000..9bc68fe5cd5
--- /dev/null
+++ b/icons/obj/smooth_structures/boulder_platform.png.toml
@@ -0,0 +1,2 @@
+output_name = "boulder_platform"
+template = "bitmask/diagonal_32x32.toml"
diff --git a/sound/items/generic_device/attribution.txt b/sound/items/generic_device/attribution.txt
new file mode 100644
index 00000000000..86532e8255b
--- /dev/null
+++ b/sound/items/generic_device/attribution.txt
@@ -0,0 +1 @@
+generic_device sounds made by grungussuss, license: CC-BY-SA
\ No newline at end of file
diff --git a/sound/items/generic_device/generic_device_drop1.ogg b/sound/items/generic_device/generic_device_drop1.ogg
new file mode 100644
index 00000000000..b2974510021
Binary files /dev/null and b/sound/items/generic_device/generic_device_drop1.ogg differ
diff --git a/sound/items/generic_device/generic_device_drop2.ogg b/sound/items/generic_device/generic_device_drop2.ogg
new file mode 100644
index 00000000000..a53ffc2f27a
Binary files /dev/null and b/sound/items/generic_device/generic_device_drop2.ogg differ
diff --git a/sound/items/generic_device/generic_device_drop3.ogg b/sound/items/generic_device/generic_device_drop3.ogg
new file mode 100644
index 00000000000..d58e1dd736c
Binary files /dev/null and b/sound/items/generic_device/generic_device_drop3.ogg differ
diff --git a/sound/items/generic_device/generic_device_drop4.ogg b/sound/items/generic_device/generic_device_drop4.ogg
new file mode 100644
index 00000000000..440126beb17
Binary files /dev/null and b/sound/items/generic_device/generic_device_drop4.ogg differ
diff --git a/sound/items/generic_device/generic_device_drop5.ogg b/sound/items/generic_device/generic_device_drop5.ogg
new file mode 100644
index 00000000000..f272337c26e
Binary files /dev/null and b/sound/items/generic_device/generic_device_drop5.ogg differ
diff --git a/sound/items/generic_device/generic_device_pickup1.ogg b/sound/items/generic_device/generic_device_pickup1.ogg
new file mode 100644
index 00000000000..8d0c89d628e
Binary files /dev/null and b/sound/items/generic_device/generic_device_pickup1.ogg differ
diff --git a/sound/items/generic_device/generic_device_pickup2.ogg b/sound/items/generic_device/generic_device_pickup2.ogg
new file mode 100644
index 00000000000..91c443738f3
Binary files /dev/null and b/sound/items/generic_device/generic_device_pickup2.ogg differ
diff --git a/sound/items/generic_device/generic_device_pickup3.ogg b/sound/items/generic_device/generic_device_pickup3.ogg
new file mode 100644
index 00000000000..f6dd7cb8002
Binary files /dev/null and b/sound/items/generic_device/generic_device_pickup3.ogg differ
diff --git a/sound/items/generic_device/generic_device_pickup4.ogg b/sound/items/generic_device/generic_device_pickup4.ogg
new file mode 100644
index 00000000000..348d4976a07
Binary files /dev/null and b/sound/items/generic_device/generic_device_pickup4.ogg differ
diff --git a/sound/items/generic_device/generic_device_pickup5.ogg b/sound/items/generic_device/generic_device_pickup5.ogg
new file mode 100644
index 00000000000..f4ed65563e1
Binary files /dev/null and b/sound/items/generic_device/generic_device_pickup5.ogg differ
diff --git a/tgui/packages/tgui/interfaces/ExodroneConsole.tsx b/tgui/packages/tgui/interfaces/ExodroneConsole.tsx
index b7caeeb4773..8b819187d1d 100644
--- a/tgui/packages/tgui/interfaces/ExodroneConsole.tsx
+++ b/tgui/packages/tgui/interfaces/ExodroneConsole.tsx
@@ -18,6 +18,7 @@ import {
ProgressBar,
Section,
Stack,
+ Tooltip,
} from 'tgui-core/components';
import { formatTime } from 'tgui-core/format';
import { capitalize } from 'tgui-core/string';
@@ -215,11 +216,7 @@ const SignalLostModal = (props) => {
-
@@ -279,39 +276,52 @@ const ToolSelectionModal = (props) => {
const toolData = Object.keys(all_tools);
return (
-
-
- Select Tool:
-
-
- {(!!toolData &&
- toolData.map((tool_name) => (
-
- {
- setChoosingTools(false);
- act('add_tool', { tool_type: tool_name });
- }}
- width={6}
- height={6}
- tooltip={all_tools[tool_name].description}
- >
-
- {capitalize(tool_name)}
-
-
-
-
-
-
- ))) || (
-
- setChoosingTools(false)}>Back
+
+ {
+ setChoosingTools(false);
+ }}
+ />
+ }
+ >
+
+ {(!!toolData &&
+ toolData.map((tool_name) => (
+
+
+
+ {' '}
+ {
+ setChoosingTools(false);
+ act('add_tool', { tool_type: tool_name });
+ }}
+ height={6}
+ tooltip={all_tools[tool_name].description}
+ icon={all_tools[tool_name].icon}
+ iconSize={3}
+ style={{ paddingTop: '15px' }}
+ />
+
+
+
+ {capitalize(tool_name)}
+
+
+
- )}
-
-
-
+ ))) || (
+
+ setChoosingTools(false)}>Back
+
+ )}
+
+
);
};
@@ -325,32 +335,33 @@ const EquipmentBox = (props: { cargo: CargoData; drone: DroneData }) => {
switch (cargo.type) {
case 'tool': // Tool icon+Remove button if configurable
return (
-
+
+
+
+
-
-
-
+ {capitalize(cargo.name)}
+
{!!configurable && (
-
+
act('remove_tool', { tool_type: cargo.name })}
- color="danger"
- icon="minus"
- tooltipPosition="right"
- tooltip="Remove Tool"
+ color="transparent"
+ icon="eject"
+ height={2.3}
+ tooltip="Eject"
+ style={{ paddingTop: '4px' }}
/>
)}
@@ -358,26 +369,32 @@ const EquipmentBox = (props: { cargo: CargoData; drone: DroneData }) => {
);
case 'cargo': // Jettison button.
return (
-
+
+
+
+
+
+
+ {capitalize(cargo.name)}
+
+
-
-
-
-
-
act('jettison', { target_ref: cargo.ref })}
- color="danger"
- icon="minus"
- tooltipPosition="right"
+ color="transparent"
+ icon="eject"
+ height={2.3}
tooltip={`Jettison ${cargo.name}`}
+ style={{ paddingTop: '4px' }}
/>
@@ -386,15 +403,49 @@ const EquipmentBox = (props: { cargo: CargoData; drone: DroneData }) => {
return '';
}
};
- return (
+ return boxContents(cargo) ? (
{boxContents(cargo)}
+ ) : (
+
+
+
+ Empty slot
+
+
+
);
};
@@ -406,15 +457,49 @@ const EquipmentGrid = (props: { drone: ActiveDrone & DroneData }) => {
return (
-
-
+
+
+
+
+
+ {props.drone.drone_name}
+
+
+ {capitalize(props.drone.drone_status)}
+
+
+
+
+
+
+
+
act('end_control')}>
Disconnect
-
{
-
+ setChoosingTools(true)}
+ />
+ )
+ }
+ >
- {!!configurable && (
- setChoosingTools(true)}
- >
- Install Tool
-
- )}
-
-
-
+
{cargo.map((cargo_element, index) => (
{
);
};
-const DroneStatus = (props: {
- drone_integrity: number;
- drone_max_integrity: number;
-}) => {
- const { drone_integrity, drone_max_integrity } = props;
-
- return (
-
-
- Integrity:
-
-
-
-
-
- );
-};
-
const NoSiteDimmer = () => {
return (
@@ -560,12 +618,7 @@ const TravelTargetSelectionScreen = (props: {
Cancel
)}
-
-
-
+
>
}
>
@@ -582,8 +635,9 @@ const TravelTargetSelectionScreen = (props: {
ml={1}
onClick={() => travel_to(null)}
disabled={!can_travel}
+ icon={can_travel ? 'rocket' : 'triangle-exclamation'}
>
- {can_travel ? 'Launch!' : travel_error}
+ {can_travel ? 'Launch' : travel_error}
}
@@ -600,8 +654,9 @@ const TravelTargetSelectionScreen = (props: {
ml={1}
onClick={() => travel_to(destination.ref)}
disabled={!can_travel}
+ icon={can_travel ? 'rocket' : 'triangle-exclamation'}
>
- {can_travel ? 'Launch!' : travel_error}
+ {can_travel ? 'Launch' : travel_error}
>
}
@@ -681,16 +736,7 @@ const ExplorationScreen = (props: { drone: DroneExploration & DroneData }) => {
);
}
return (
-
- }
- >
+
@@ -704,11 +750,21 @@ const ExplorationScreen = (props: { drone: DroneExploration & DroneData }) => {
- act('explore')}>Explore!
+ act('explore')}
+ >
+ Explore
+
{site.events.map((e) => (
act('explore_event', { target_event: e.ref })}
>
{capitalize(e.name)}
@@ -716,7 +772,14 @@ const ExplorationScreen = (props: { drone: DroneExploration & DroneData }) => {
))}
- setTravelDimmerShown(true)}>Travel
+ setTravelDimmerShown(true)}
+ >
+ Travel
+
@@ -728,16 +791,7 @@ const EventScreen = (props: { drone: DroneData; event: FullEventData }) => {
const { drone, event } = props;
return (
-
- }
- >
+
@@ -749,7 +803,9 @@ const EventScreen = (props: { drone: DroneData; event: FullEventData }) => {
/>
- {event.description}
+
+ {event.description}
+
@@ -791,18 +847,7 @@ export const AdventureScreen = (props: {
const rawData = adventure_data.raw_image;
const imgSource = rawData ? rawData : resolveAsset(adventure_data.image);
return (
-
- )
- }
- >
+
@@ -882,21 +927,25 @@ const ExodroneConsoleContent = (props) => {
-
+
+
+
+
+
+
+
+ {drone_log.map((log_line, ix) => (
+
+ {log_line}
+
+ ))}
+
+
+
+
-
-
-
- {drone_log.map((log_line, ix) => (
-
- {log_line}
-
- ))}
-
-
-
);
};
diff --git a/tgui/packages/tgui/interfaces/SpawnPanel/CreateObject.tsx b/tgui/packages/tgui/interfaces/SpawnPanel/CreateObject.tsx
index ab6004dafc5..8e7064d4257 100644
--- a/tgui/packages/tgui/interfaces/SpawnPanel/CreateObject.tsx
+++ b/tgui/packages/tgui/interfaces/SpawnPanel/CreateObject.tsx
@@ -1,5 +1,5 @@
import { storage } from 'common/storage';
-import { useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
import {
Button,
DmIcon,
@@ -55,10 +55,15 @@ export function CreateObject(props: CreateObjectProps) {
const currentList = objList;
const currentType = allObjects[data.copied_type ?? '']?.type || 'Objects';
+ const getSearchString = useCallback(
+ (key: string) => (searchBy ? key : allObjects[key]?.name || ''),
+ [searchBy, allObjects],
+ );
+
const { query, setQuery, results } = useFuzzySearch({
searchArray: Object.keys(allObjects),
matchStrategy: 'smart',
- getSearchString: (key) => (searchBy ? key : allObjects[key]?.name || ''),
+ getSearchString,
});
const filteredResults = results.filter((obj) => {