diff --git a/_maps/templates/lazy_templates/nukie_base.dmm b/_maps/templates/lazy_templates/nukie_base.dmm index 63c0fc2b168..059d27000d0 100644 --- a/_maps/templates/lazy_templates/nukie_base.dmm +++ b/_maps/templates/lazy_templates/nukie_base.dmm @@ -152,6 +152,10 @@ }, /turf/open/floor/plating, /area/centcom/syndicate_mothership/control) +"bZ" = ( +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "cl" = ( /turf/open/lava/plasma/ice_moon, /area/centcom/syndicate_mothership/control) @@ -349,6 +353,15 @@ }, /turf/open/floor/iron/dark/textured_large, /area/centcom/syndicate_mothership/control) +"dZ" = ( +/obj/machinery/light/small/directional/north, +/obj/effect/decal/cleanable/cobweb/cobweb2, +/obj/structure/closet/crate/bin, +/obj/effect/decal/cleanable/fuel_pool, +/obj/item/binoculars, +/obj/item/stack/sheet/animalhide/carp/five, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "ec" = ( /obj/structure/sign/poster/contraband/cc64k_ad, /turf/closed/indestructible/syndicate, @@ -485,9 +498,27 @@ /turf/open/floor/iron/freezer, /area/centcom/syndicate_mothership/control) "fw" = ( -/obj/item/kirbyplants/random, +/obj/structure/frame/computer, +/obj/effect/decal/cleanable/cobweb, +/obj/structure/sign/poster/contraband/syndiemoth/directional/north, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) +"fx" = ( +/obj/machinery/light/small/dim/directional/west, +/obj/structure/rack, +/obj/effect/turf_decal/box/white, +/obj/item/stack/cable_coil/thirty{ + pixel_x = 4; + pixel_y = -2 + }, +/obj/item/circuitboard/computer/stationalert{ + pixel_y = 1; + pixel_x = 3 + }, +/obj/item/stack/cable_coil/thirty, +/obj/item/circuitboard/computer/advanced_camera, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "fy" = ( /obj/structure/lattice/catwalk, /obj/effect/turf_decal/stripes/line{ @@ -536,6 +567,8 @@ /obj/structure/frame/computer{ dir = 1 }, +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/computer/security/telescreen/entertainment/directional/south, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) "gf" = ( @@ -740,6 +773,20 @@ /obj/item/melee/powerfist, /turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bombthreat) +"id" = ( +/obj/structure/extinguisher_cabinet/directional/south, +/obj/item/storage/fancy/donut_box, +/obj/structure/rack, +/obj/item/food/syndicake{ + pixel_x = -1; + pixel_y = -1 + }, +/obj/item/food/syndicake{ + pixel_x = 1; + pixel_y = 1 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "ig" = ( /obj/effect/turf_decal/siding/wideplating{ dir = 1 @@ -1033,6 +1080,10 @@ /obj/structure/sign/poster/contraband/power/directional/north, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership/expansion_chemicalwarfare) +"lx" = ( +/obj/machinery/light/small/dim/directional/east, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "lA" = ( /obj/machinery/door/window/survival_pod/left/directional/west{ name = "Toilet Door" @@ -1281,6 +1332,22 @@ dir = 8 }, /area/centcom/syndicate_mothership/control) +"oN" = ( +/obj/structure/rack, +/obj/item/poster/random_contraband{ + pixel_x = 3; + pixel_y = 4 + }, +/obj/item/poster/random_contraband{ + pixel_x = 3; + pixel_y = 8 + }, +/obj/item/poster/random_contraband{ + pixel_x = 1 + }, +/obj/effect/decal/cleanable/cobweb, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "oR" = ( /obj/structure/table/wood, /obj/item/storage/box/donkpockets, @@ -1367,6 +1434,7 @@ /obj/structure/chair/greyscale{ dir = 4 }, +/obj/effect/landmark/start/nukeop_overwatch, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) "pU" = ( @@ -1641,6 +1709,7 @@ /area/centcom/syndicate_mothership/control) "sv" = ( /obj/machinery/light/small/directional/north, +/obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) "sE" = ( @@ -1731,6 +1800,17 @@ /obj/machinery/portable_atmospherics/scrubber, /turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bombthreat) +"tB" = ( +/obj/effect/turf_decal/siding/wideplating{ + dir = 1 + }, +/obj/effect/turf_decal/siding/wideplating, +/obj/machinery/door/airlock/hatch{ + name = "Workout Room" + }, +/obj/effect/mapping_helpers/airlock/access/all/syndicate/general, +/turf/open/floor/mineral/plastitanium, +/area/centcom/syndicate_mothership) "tJ" = ( /obj/effect/light_emitter{ set_cap = 1; @@ -2046,6 +2126,10 @@ dir = 8 }, /area/centcom/syndicate_mothership/control) +"yA" = ( +/obj/effect/decal/cleanable/insectguts, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "yB" = ( /obj/machinery/light/small/directional/north, /turf/open/misc/asteroid/snow/icemoon, @@ -2100,12 +2184,12 @@ /area/centcom/syndicate_mothership/control) "zy" = ( /obj/structure/table/reinforced/plasmarglass, -/obj/item/pen{ - pixel_x = 6; - pixel_y = 5 +/obj/item/flashlight/lamp/green{ + pixel_y = 9; + pixel_x = 5 }, -/obj/item/folder/red{ - pixel_x = -5 +/obj/item/circuitboard/computer/overwatch{ + pixel_x = -2 }, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) @@ -3037,6 +3121,10 @@ }, /turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bioterrorism) +"Jx" = ( +/obj/effect/decal/cleanable/plastic, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "JJ" = ( /obj/effect/turf_decal/siding/thinplating_new/dark{ dir = 5 @@ -3318,6 +3406,19 @@ /obj/structure/noticeboard/directional/east, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership/expansion_bioterrorism) +"MA" = ( +/obj/item/stack/sheet/iron/fifty{ + pixel_x = -3; + pixel_y = 3 + }, +/obj/structure/rack, +/obj/item/stack/sheet/glass/fifty{ + pixel_y = 3; + pixel_x = 5 + }, +/obj/item/storage/toolbox/mechanical, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "MD" = ( /obj/machinery/door/airlock/maintenance/external{ name = "Bunk Room 1" @@ -3483,6 +3584,14 @@ pixel_x = -2; pixel_y = 6 }, +/obj/item/paper/fluff/overwatch{ + pixel_y = 8; + pixel_x = -2 + }, +/obj/item/toy/figure/syndie{ + pixel_x = 5 + }, +/obj/structure/sign/clock/directional/north, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) "Ov" = ( @@ -3706,6 +3815,14 @@ /obj/effect/turf_decal/tile/bar/opposingcorners, /turf/open/floor/iron, /area/centcom/syndicate_mothership/control) +"QD" = ( +/obj/item/flashlight{ + pixel_y = 6 + }, +/obj/structure/rack, +/obj/item/flashlight, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "QJ" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -3728,10 +3845,39 @@ }, /turf/open/misc/asteroid/snow/icemoon, /area/centcom/syndicate_mothership/control) +"QS" = ( +/obj/item/soap/syndie, +/obj/structure/rack, +/obj/item/storage/fancy/cigarettes/cigpack_syndicate{ + pixel_x = 5; + pixel_y = 2 + }, +/obj/effect/spawner/random/entertainment/lighter, +/obj/machinery/light/small/directional/north, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "Rd" = ( /obj/structure/cable, /turf/open/floor/catwalk_floor/iron, /area/centcom/syndicate_mothership/control) +"Rn" = ( +/obj/item/circuitboard/computer/syndicate_shuttle{ + pixel_x = 2; + pixel_y = 3 + }, +/obj/structure/rack, +/obj/item/stack/cable_coil/thirty{ + pixel_x = -2; + pixel_y = -1 + }, +/obj/effect/turf_decal/box/white, +/obj/item/circuitboard/computer/syndicate_shuttle_docker, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) +"Rr" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "Rs" = ( /obj/effect/turf_decal/siding/thinplating_new/dark{ dir = 1 @@ -3830,6 +3976,11 @@ }, /turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bombthreat) +"St" = ( +/obj/effect/decal/cleanable/fuel_pool, +/obj/machinery/light_switch/directional/east, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "Su" = ( /obj/structure/chair/stool/bar/directional/west, /obj/effect/turf_decal/siding/thinplating/dark{ @@ -4276,6 +4427,11 @@ /obj/machinery/light/cold/directional/east, /turf/open/floor/catwalk_floor/iron_dark, /area/centcom/syndicate_mothership/control) +"XO" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "XQ" = ( /obj/effect/turf_decal/siding/wideplating/dark, /obj/effect/turf_decal/siding/wideplating/dark{ @@ -4375,6 +4531,14 @@ }, /turf/open/misc/asteroid/snow/icemoon, /area/centcom/syndicate_mothership/control) +"YT" = ( +/obj/structure/rack, +/obj/effect/turf_decal/box/white, +/obj/item/storage/medkit/emergency, +/obj/item/tank/internals/emergency_oxygen/double, +/obj/item/clothing/mask/gas/syndicate, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "YX" = ( /obj/structure/railing{ dir = 6 @@ -4491,6 +4655,7 @@ /turf/open/floor/plating/snowed/icemoon, /area/centcom/syndicate_mothership/control) "ZX" = ( +/obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) "ZZ" = ( @@ -5254,9 +5419,9 @@ sU sU sU sU -sU -sU -sU +Ye +Ye +Ye Ye Ye Ye @@ -5356,13 +5521,13 @@ sU sU sU sU -sU -sU Ye Ye Kq Kq Kq +Kq +Kq Ye KU KU @@ -5458,12 +5623,12 @@ sU sU sU sU -sU -Ye Ye Kq Kq -Xk +YT +fx +Rn Kq Kq KU @@ -5561,12 +5726,12 @@ sU sU sU Ye -Ye -Kq Kq +oN +Jx Xk -Xk -Xk +Rr +MA Kq Kq uT @@ -5664,12 +5829,12 @@ sU sU Ye Kq -Kq -Xk -Xk -Xk +QS Xk Xk +bZ +Rr +id Kq Kq uT @@ -5766,12 +5931,12 @@ sU sU Ye Kq -Xk -Xk -Xk -Xk -Xk -Xk +QD +Rr +lx +bZ +St +XO Xk Kq Kq @@ -5871,12 +6036,12 @@ Kq Kq Kq Kq -lg +tB Kq +dZ Xk -Xk -Xk -Kq +yA +tO uT ds HW diff --git a/code/__DEFINES/ai/ai.dm b/code/__DEFINES/ai/ai.dm index 65cc4214908..e894b32b1f6 100644 --- a/code/__DEFINES/ai/ai.dm +++ b/code/__DEFINES/ai/ai.dm @@ -2,8 +2,12 @@ #define GET_TARGETING_STRATEGY(targeting_type) SSai_behaviors.targeting_strategies[targeting_type] #define HAS_AI_CONTROLLER_TYPE(thing, type) istype(thing?.ai_controller, type) -#define AI_STATUS_ON 1 -#define AI_STATUS_OFF 2 +//AI controller flags +//If you add a new status, be sure to add it to the ai_controllers subsystem's ai_controllers_by_status list. +///The AI is currently active. +#define AI_STATUS_ON "ai_on" +///The AI is currently offline for any reason. +#define AI_STATUS_OFF "ai_off" ///For JPS pathing, the maximum length of a path we'll try to generate. Should be modularized depending on what we're doing later on #define AI_MAX_PATH_LENGTH 30 // 30 is possibly overkill since by default we lose interest after 14 tiles of distance, but this gives wiggle room for weaving around obstacles diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 7a510c9cdee..5f7a41c542f 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -396,3 +396,6 @@ GLOBAL_LIST_INIT(human_invader_antagonists, list( #define SPY_DIFFICULTY_MEDIUM "Medium" /// Very difficult to accomplish, almost guaranteed to require crew conflict #define SPY_DIFFICULTY_HARD "Hard" + +/// Camera net used by battle royale objective +#define BATTLE_ROYALE_CAMERA_NET "battle_royale_camera_net" diff --git a/code/__DEFINES/cameranets.dm b/code/__DEFINES/cameranets.dm index 1dea0cd18ae..15b4493738e 100644 --- a/code/__DEFINES/cameranets.dm +++ b/code/__DEFINES/cameranets.dm @@ -26,3 +26,4 @@ #define CAMERANET_NETWORK_BAR "bar" #define CAMERANET_NETWORK_INTERROGATION "interrogation" #define CAMERANET_NETWORK_ABDUCTOR "abductor" +#define OPERATIVE_CAMERA_NET "operative" diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm index c6cde1d8b46..637ea90c8e4 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm @@ -57,6 +57,8 @@ /// Called from bodypart being removed /obj/item/bodypart/proc/drop_limb(mob/living/carbon/old_owner, special, dismembered) #define COMSIG_BODYPART_REMOVED "bodypart_removed" +/// from /mob/living/carbon/enter_stamcrit() +#define COMSIG_CARBON_ENTER_STAMCRIT "carbon_enter_stamcrit" ///from base of mob/living/carbon/soundbang_act(): (list(intensity)) #define COMSIG_CARBON_SOUNDBANG "carbon_soundbang" ///from /item/organ/proc/Insert() (/obj/item/organ/) diff --git a/code/__DEFINES/dcs/signals/signals_operatives.dm b/code/__DEFINES/dcs/signals/signals_operatives.dm new file mode 100644 index 00000000000..12a3bed4668 --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_operatives.dm @@ -0,0 +1,2 @@ +/// For when a new teammate is added to a nukie team +#define COMSIG_NUKE_TEAM_ADDITION "nuke_team_addition" diff --git a/code/__DEFINES/dcs/signals/signals_traitor.dm b/code/__DEFINES/dcs/signals/signals_traitor.dm index 4290b25b800..2752ab2363e 100644 --- a/code/__DEFINES/dcs/signals/signals_traitor.dm +++ b/code/__DEFINES/dcs/signals/signals_traitor.dm @@ -34,3 +34,6 @@ #define COMSIG_TRAITOR_GRAFFITI_SLIPPED "traitor_demoralise_event" /// For when someone is injected with the EHMS virus from /datum/traitor_objective_category/infect #define COMSIG_EHMS_INJECTOR_INJECTED "after_ehms_inject" + +/// Called by an battle royale implanter when successfully implanting someone. Passes the implanted mob. +#define COMSIG_ROYALE_IMPLANTED "royale_implanted" diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm index aca45241f1c..1939ca94ec4 100644 --- a/code/__DEFINES/maths.dm +++ b/code/__DEFINES/maths.dm @@ -250,7 +250,7 @@ //We used to use linear regression to approximate the answer, but Mloc realized this was actually faster. //And lo and behold, it is, and it's more accurate to boot. -#define CHEAP_HYPOTENUSE(Ax, Ay, Bx, By) (sqrt(abs(Ax - Bx) ** 2 + abs(Ay - By) ** 2)) //A squared + B squared = C squared +#define CHEAP_HYPOTENUSE(Ax, Ay, Bx, By) (sqrt((Ax - Bx) ** 2 + (Ay - By) ** 2)) //A squared + B squared = C squared /// The number of cells in a taxicab circle (rasterized diamond) of radius X. #define DIAMOND_AREA(X) (1 + 2*(X)*((X)+1)) diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 28c202281f4..e46600abe2a 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -351,7 +351,6 @@ #define AI_ON 1 #define AI_IDLE 2 #define AI_OFF 3 -#define AI_Z_OFF 4 //The range at which a mob should wake up if you spawn into the z level near it #define MAX_SIMPLEMOB_WAKEUP_RANGE 5 diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm index 8ace303b843..469811c96dc 100644 --- a/code/__DEFINES/obj_flags.dm +++ b/code/__DEFINES/obj_flags.dm @@ -15,7 +15,7 @@ #define IGNORE_DENSITY (1<<11) //! Can we ignore density when building on this object? (for example, directional windows and grilles) #define INFINITE_RESKIN (1<<12) // We can reskin this item infinitely #define CONDUCTS_ELECTRICITY (1<<13) //! Can this object conduct electricity? -#define NO_DECONSTRUCTION (1<<14) //! Prevent deconstruction of this object. +#define NO_DECONSTRUCTION (1<<14) //! Atoms don't spawn anything when deconstructed. They just vanish // If you add new ones, be sure to add them to /obj/Initialize as well for complete mapping support diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index ca33d9b4635..cdf16e72818 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -88,6 +88,7 @@ #define ROLE_WIZARD_APPRENTICE "apprentice" #define ROLE_SYNDICATE_MONKEY "Syndicate Monkey Agent" #define ROLE_CONTRACTOR_SUPPORT "Contractor Support Unit" +#define ROLE_OPERATIVE_OVERWATCH "Operative Overwatch Agent" #define ROLE_SYNDICATE_SABOBORG "Syndicate Sabotage Cyborg" #define ROLE_SYNDICATE_MEDBORG "Syndicate Medical Cyborg" #define ROLE_SYNDICATE_ASSAULTBORG "Syndicate Assault Cyborg" diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 36a0e8b411c..1a1940b76cd 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -199,7 +199,6 @@ // If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child) #define FIRE_PRIORITY_PING 10 -#define FIRE_PRIORITY_IDLE_NPC 10 #define FIRE_PRIORITY_SERVER_MAINT 10 #define FIRE_PRIORITY_RESEARCH 10 #define FIRE_PRIORITY_VIS 10 diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index b38055afa42..1b93f024285 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -267,8 +267,10 @@ GLOBAL_LIST_EMPTY(species_list) * @param {string} interaction_key - The assoc key under which the do_after is capped, with max_interact_count being the cap. Interaction key will default to target if not set. * * @param {number} max_interact_count - The maximum amount of interactions allowed. + * + * @param {boolean} hidden - By default, any action 1 second or longer shows a cog over the user while it is in progress. If hidden is set to TRUE, the cog will not be shown. */ -/proc/do_after(mob/user, delay, atom/target, timed_action_flags = NONE, progress = TRUE, datum/callback/extra_checks, interaction_key, max_interact_count = 1) +/proc/do_after(mob/user, delay, atom/target, timed_action_flags = NONE, progress = TRUE, datum/callback/extra_checks, interaction_key, max_interact_count = 1, hidden = FALSE) if(!user) return FALSE if(!isnum(delay)) @@ -295,10 +297,15 @@ GLOBAL_LIST_EMPTY(species_list) delay *= user.cached_multiplicative_actions_slowdown var/datum/progressbar/progbar + var/datum/cogbar/cog + if(progress) if(user.client) progbar = new(user, delay, target || user) + if(!hidden && delay >= 1 SECONDS) + cog = new(user) + SEND_SIGNAL(user, COMSIG_DO_AFTER_BEGAN) var/endtime = world.time + delay @@ -330,6 +337,8 @@ GLOBAL_LIST_EMPTY(species_list) if(!QDELETED(progbar)) progbar.end_progress() + + cog?.remove() if(interaction_key) var/reduced_interaction_count = (LAZYACCESS(user.do_afters, interaction_key) || 0) - 1 diff --git a/code/_globalvars/lists/mapping.dm b/code/_globalvars/lists/mapping.dm index 8719f45f18f..45f59fb4475 100644 --- a/code/_globalvars/lists/mapping.dm +++ b/code/_globalvars/lists/mapping.dm @@ -111,6 +111,7 @@ GLOBAL_LIST_EMPTY(gorilla_start) GLOBAL_LIST_EMPTY(wizardstart) GLOBAL_LIST_EMPTY(nukeop_start) GLOBAL_LIST_EMPTY(nukeop_leader_start) +GLOBAL_LIST_EMPTY(nukeop_overwatch_start) GLOBAL_LIST_EMPTY(newplayer_start) GLOBAL_LIST_EMPTY(prisonwarp) //admin prisoners go to these GLOBAL_LIST_EMPTY(holdingfacility) //captured people go here (ninja energy net) diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 2de6a1c691f..4e33aa43708 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -59,7 +59,7 @@ GLOBAL_LIST_EMPTY(human_list) //all instances of /mob/living/carbon/human and su GLOBAL_LIST_EMPTY(ai_list) GLOBAL_LIST_EMPTY(pai_list) GLOBAL_LIST_EMPTY(available_ai_shells) -GLOBAL_LIST_INIT(simple_animals, list(list(),list(),list(),list())) // One for each AI_* status define +GLOBAL_LIST_INIT(simple_animals, list(list(),list(),list())) // One for each AI_* status define GLOBAL_LIST_EMPTY(spidermobs) //all sentient spider mobs GLOBAL_LIST_EMPTY(bots_list) GLOBAL_LIST_EMPTY(aiEyes) diff --git a/code/_globalvars/lists/quirks.dm b/code/_globalvars/lists/quirks.dm index 4cd45ecc4be..f436bdf9d9f 100644 --- a/code/_globalvars/lists/quirks.dm +++ b/code/_globalvars/lists/quirks.dm @@ -20,13 +20,17 @@ GLOBAL_LIST_INIT(limb_choice, list( "Right Leg" = /obj/item/bodypart/leg/right/robot/surplus, )) + ///Transhumanist quirk -GLOBAL_LIST_INIT(limb_choice_transhuman, list( +GLOBAL_LIST_INIT(part_choice_transhuman, list( "Left Arm" = /obj/item/bodypart/arm/left/robot, "Right Arm" = /obj/item/bodypart/arm/right/robot, "Left Leg" = /obj/item/bodypart/leg/left/robot, "Right Leg" = /obj/item/bodypart/leg/right/robot, + "Robotic Voice Box" = /obj/item/organ/internal/tongue/robot, + "Flashlights for Eyes" = /obj/item/organ/internal/eyes/robotic/flashlight, )) + ///Hemiplegic Quirk GLOBAL_LIST_INIT(side_choice_hemiplegic, list( "Left Side" = /datum/brain_trauma/severe/paralysis/hemiplegic/left, diff --git a/code/controllers/subsystem/ai_controllers.dm b/code/controllers/subsystem/ai_controllers.dm index 3d8d2653149..44e1948e386 100644 --- a/code/controllers/subsystem/ai_controllers.dm +++ b/code/controllers/subsystem/ai_controllers.dm @@ -3,27 +3,32 @@ SUBSYSTEM_DEF(ai_controllers) name = "AI Controller Ticker" flags = SS_POST_FIRE_TIMING|SS_BACKGROUND priority = FIRE_PRIORITY_NPC - runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME init_order = INIT_ORDER_AI_CONTROLLERS wait = 0.5 SECONDS //Plan every half second if required, not great not terrible. + runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME ///List of all ai_subtree singletons, key is the typepath while assigned value is a newly created instance of the typepath. See setup_subtrees() - var/list/ai_subtrees = list() - ///List of all ai controllers currently running - var/list/active_ai_controllers = list() + var/list/datum/ai_planning_subtree/ai_subtrees = list() + ///Assoc List of all AI statuses and all AI controllers with that status. + var/list/ai_controllers_by_status = list( + AI_STATUS_ON = list(), + AI_STATUS_OFF = list(), + ) + ///Assoc List of all AI controllers and the Z level they are on, which we check when someone enters/leaves a Z level to turn them on/off. + var/list/ai_controllers_by_zlevel = list() /datum/controller/subsystem/ai_controllers/Initialize() setup_subtrees() return SS_INIT_SUCCESS -/datum/controller/subsystem/ai_controllers/proc/setup_subtrees() - ai_subtrees = list() - for(var/subtree_type in subtypesof(/datum/ai_planning_subtree)) - var/datum/ai_planning_subtree/subtree = new subtree_type - ai_subtrees[subtree_type] = subtree +/datum/controller/subsystem/ai_controllers/stat_entry(msg) + var/list/active_list = ai_controllers_by_status[AI_STATUS_ON] + var/list/inactive_list = ai_controllers_by_status[AI_STATUS_OFF] + msg = "Active AIs:[length(active_list)]|Inactive:[length(inactive_list)]" + return ..() /datum/controller/subsystem/ai_controllers/fire(resumed) - for(var/datum/ai_controller/ai_controller as anything in active_ai_controllers) + for(var/datum/ai_controller/ai_controller as anything in ai_controllers_by_status[AI_STATUS_ON]) if(!COOLDOWN_FINISHED(ai_controller, failed_planning_cooldown)) continue @@ -32,3 +37,17 @@ SUBSYSTEM_DEF(ai_controllers) ai_controller.SelectBehaviors(wait * 0.1) if(!LAZYLEN(ai_controller.current_behaviors)) //Still no plan COOLDOWN_START(ai_controller, failed_planning_cooldown, AI_FAILED_PLANNING_COOLDOWN) + +///Creates all instances of ai_subtrees and assigns them to the ai_subtrees list. +/datum/controller/subsystem/ai_controllers/proc/setup_subtrees() + for(var/subtree_type in subtypesof(/datum/ai_planning_subtree)) + var/datum/ai_planning_subtree/subtree = new subtree_type + ai_subtrees[subtree_type] = subtree + +///Called when the max Z level was changed, updating our coverage. +/datum/controller/subsystem/ai_controllers/proc/on_max_z_changed() + if (!islist(ai_controllers_by_zlevel)) + ai_controllers_by_zlevel = new /list(world.maxz,0) + while (SSai_controllers.ai_controllers_by_zlevel.len < world.maxz) + SSai_controllers.ai_controllers_by_zlevel.len++ + SSai_controllers.ai_controllers_by_zlevel[ai_controllers_by_zlevel.len] = list() diff --git a/code/controllers/subsystem/battle_royale.dm b/code/controllers/subsystem/battle_royale.dm new file mode 100644 index 00000000000..139a5aa8b49 --- /dev/null +++ b/code/controllers/subsystem/battle_royale.dm @@ -0,0 +1,230 @@ +/// Global list of areas which are considered to be inside the same department for our purposes +GLOBAL_LIST_INIT(battle_royale_regions, list( + "Medical Bay" = list( + /area/station/command/heads_quarters/cmo, + /area/station/medical, + /area/station/security/checkpoint/medical, + ), + "Research Division" = list( + /area/station/command/heads_quarters/rd, + /area/station/security/checkpoint/science, + /area/station/science, + ), + "Engineering Bay" = list( + /area/station/command/heads_quarters/ce, + /area/station/engineering, + /area/station/maintenance/disposal/incinerator, + /area/station/security/checkpoint/engineering, + ), + "Cargo Bay" = list( + /area/station/cargo, + /area/station/command/heads_quarters/qm, + /area/station/security/checkpoint/supply, + ), +)) + +/// Basically just exists to hold references to datums so that they don't GC +SUBSYSTEM_DEF(battle_royale) + name = "Battle Royale" + flags = SS_NO_INIT | SS_NO_FIRE + /// List of battle royale datums currently running + var/list/active_battles + +/// Start a new battle royale using a passed list of implants +/datum/controller/subsystem/battle_royale/proc/start_battle(list/competitors) + var/datum/battle_royale_controller/controller = new() + if (!controller.start(competitors)) + return FALSE + LAZYADD(active_battles, controller) + if (LAZYLEN(active_battles) == 1) + start_broadcasting_network(BATTLE_ROYALE_CAMERA_NET) + RegisterSignal(controller, COMSIG_QDELETING, PROC_REF(battle_ended)) + return TRUE + +/// Drop reference when it kills itself +/datum/controller/subsystem/battle_royale/proc/battle_ended(datum/source) + SIGNAL_HANDLER + LAZYREMOVE(active_battles, source) + if (!LAZYLEN(active_battles)) + stop_broadcasting_network(BATTLE_ROYALE_CAMERA_NET) + + +/// Datum which controls the conflict +/datum/battle_royale_controller + /// Where is our battle taking place? + var/chosen_area + /// Is the battle currently in progress? + var/battle_running = TRUE + /// Should we let everyone know that someone has died? + var/announce_deaths = TRUE + /// List of implants involved + var/list/contestant_implants = list() + /// Ways to describe that someone has died + var/static/list/euphemisms = list( + "cashed their last paycheque.", + "didn't make it...", + "didn't make the cut.", + "had their head blown clean off!", + "has been killed!", + "has failed the challenge!", + "has passed away.", + "has died.", + "is in a better place now.", + "isn't going to be clocking in tomorrow!", + "just flatlined.", + "isn't today's winner.", + "seems to have exploded!", + "was just murdered on live tv!", + "won't be making it to retirement.", + "won't be getting back up after that one.", + ) + /// Ways to tell people not to salt in deadchat, surely effective + var/static/list/condolences = list( + "Better luck next time!", + "But stay tuned, there's still everything to play for!", + "Did you catch who did it?", + "It looked like that one really hurt...", + "Let's get that one on action replay!", + "Let's have a moment of silence, please.", + "Let's hope the next one does better.", + "Someone please notify their next of kin.", + "They had a good run.", + "Too bad!", + "What a shame!", + "What an upset!", + "What's going to happen next?", + "Who could have seen that coming?", + "Who will be next?", + ) + +/datum/battle_royale_controller/Destroy(force) + contestant_implants = null + return ..() + +/// Start a battle royale with the list of provided implants +/datum/battle_royale_controller/proc/start(list/implants, battle_time = 10 MINUTES) + chosen_area = pick(GLOB.battle_royale_regions) + for (var/obj/item/implant/explosive/battle_royale/contestant_implant in implants) + contestant_implant.start_battle(chosen_area, GLOB.battle_royale_regions[chosen_area]) + if (isnull(contestant_implant)) + continue // Might have exploded if it was removed from a person + RegisterSignal(contestant_implant, COMSIG_QDELETING, PROC_REF(implant_destroyed)) + contestant_implants |= contestant_implant + + if (length(contestant_implants) <= 1) + return FALSE // Well there's not much point is there + + priority_announce( + text = "Congratulations [station_name()], you have been chosen as the next site of the Rumble Royale! \n\ + Viewers across the sector will watch our [convert_integer_to_words(length(contestant_implants))] lucky contestants battle their way into your [chosen_area] and fight until only one is left standing! \n\ + If they don't make it in five minutes, they'll be disqualified. If you see one of our players struggling to get in, do lend them a hand... or don't, if you can live with the consequences! \n\ + As a gesture of gratitude, we will be providing our premium broadcast to your entertainment monitors at no cost so that you can watch the excitement. \n\ + Bystanders are advised not to intervene... but if you do, make it look good for the camera!", + title = "Rumble Royale Beginning", + sound = 'sound/machines/alarm.ogg', + has_important_message = TRUE, + sender_override = "Rumble Royale Pirate Broadcast Station", + color_override = "red", + ) + + for (var/obj/item/implant/explosive/battle_royale/contestant_implant as anything in contestant_implants) + contestant_implant.announce() + addtimer(CALLBACK(src, PROC_REF(limit_area)), battle_time / 2, TIMER_DELETE_ME) + addtimer(CALLBACK(src, PROC_REF(finish)), battle_time, TIMER_DELETE_ME) + return TRUE + +/// An implant was destroyed, hopefully because it exploded. Count how many competitors remain. +/datum/battle_royale_controller/proc/implant_destroyed(obj/item/implant/implant) + SIGNAL_HANDLER + contestant_implants -= implant + if (!battle_running) + return + + if (length(contestant_implants) <= 1) + announce_winner(implant) + else if (announce_deaths) + var/message = "" + if (isnull(implant.imp_in)) + message = "Looks like someone removed and destroyed their implant, that's cheating!" + else + message = "[implant.imp_in.real_name] [pick(euphemisms)] [pick(condolences)]" + priority_announce( + text = message, + title = "Rumble Royale Casualty Report", + sound = 'sound/misc/notice1.ogg', + has_important_message = TRUE, + sender_override = "Rumble Royale Pirate Broadcast Station", + color_override = "red", + ) + +/// There's only one person left, we have a winner! +/datum/battle_royale_controller/proc/announce_winner(obj/item/implant/losing_implant) + battle_running = FALSE + if (length(contestant_implants) > 1) + return + + var/message = "" + var/mob/living/loser = losing_implant.imp_in + var/obj/item/implant/winning_implant = pop(contestant_implants) + var/mob/living/winner = winning_implant?.imp_in + + if (isnull(winner) && isnull(loser)) + message = "Somehow, it seems like there's no winner tonight. What a disappointment!" + else + var/loser_text = isnull(loser) ? "With the disqualification of the other remaining contestant" : "With the death of [loser.real_name]" + var/winner_text = isnull(winner) ? "we must sadly announce that the would-be winner has also been disqualified. Such bad showmanship!" : "only [winner.real_name] remains. Congratulations, we have a winner!" + message = "[loser_text], [winner_text]" + + if (!isnull(winner)) + podspawn(list( + "target" = get_turf(winner), + "style" = STYLE_SYNDICATE, + "spawn" = /obj/item/food/roast_dinner, + )) + + priority_announce( + text = message, + title = "Rumble Royale Winner", + sound = 'sound/misc/notice1.ogg', + has_important_message = TRUE, + sender_override = "Rumble Royale Pirate Broadcast Station", + color_override = "red", + ) + + qdel(winning_implant) // You get to live! + winner?.mind?.remove_antag_datum(/datum/antagonist/survivalist/battle_royale) + qdel(src) + +/// Called halfway through the battle, if you've not made it to the designated battle zone we kill you +/datum/battle_royale_controller/proc/limit_area() + priority_announce( + text = "We're halfway done folks! And bad news to anyone who hasn't made it to the [chosen_area]... you're out!", + title = "Rumble Royale Update", + sound = 'sound/misc/notice1.ogg', + has_important_message = TRUE, + sender_override = "Rumble Royale Pirate Broadcast Station", + color_override = "red", + ) + + for (var/obj/item/implant/explosive/battle_royale/contestant_implant as anything in contestant_implants) + contestant_implant.limit_areas() + +/// Well you're out of time, bad luck +/datum/battle_royale_controller/proc/finish() + battle_running = FALSE + + priority_announce( + text = "Sorry remaining contestants, your time is up. \ + We're sorry to announce that this edition of Royal Rumble has no winner. \n\ + Better luck next time!", + title = "Rumble Royale Concluded", + sound = 'sound/misc/notice1.ogg', + has_important_message = TRUE, + sender_override = "Rumble Royale Pirate Broadcast Station", + color_override = "red", + ) + + for (var/obj/item/implant/explosive/battle_royale/contestant_implant as anything in contestant_implants) + contestant_implant.explode() + + qdel(src) diff --git a/code/controllers/subsystem/idlenpcpool.dm b/code/controllers/subsystem/idlenpcpool.dm deleted file mode 100644 index ee98e8c4e67..00000000000 --- a/code/controllers/subsystem/idlenpcpool.dm +++ /dev/null @@ -1,47 +0,0 @@ -SUBSYSTEM_DEF(idlenpcpool) - name = "Idling NPC Pool" - flags = SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT - priority = FIRE_PRIORITY_IDLE_NPC - wait = 60 - runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME - - var/list/currentrun = list() - var/static/list/idle_mobs_by_zlevel[][] - -/datum/controller/subsystem/idlenpcpool/stat_entry(msg) - var/list/idlelist = GLOB.simple_animals[AI_IDLE] - var/list/zlist = GLOB.simple_animals[AI_Z_OFF] - msg = "IdleNPCS:[length(idlelist)]|Z:[length(zlist)]" - return ..() - -/datum/controller/subsystem/idlenpcpool/proc/MaxZChanged() - if (!islist(idle_mobs_by_zlevel)) - idle_mobs_by_zlevel = new /list(world.maxz,0) - while (SSidlenpcpool.idle_mobs_by_zlevel.len < world.maxz) - SSidlenpcpool.idle_mobs_by_zlevel.len++ - SSidlenpcpool.idle_mobs_by_zlevel[idle_mobs_by_zlevel.len] = list() - -/datum/controller/subsystem/idlenpcpool/fire(resumed = FALSE) - - if (!resumed) - var/list/idlelist = GLOB.simple_animals[AI_IDLE] - src.currentrun = idlelist.Copy() - - //cache for sanic speed (lists are references anyways) - var/list/currentrun = src.currentrun - - while(currentrun.len) - var/mob/living/simple_animal/SA = currentrun[currentrun.len] - --currentrun.len - if (QDELETED(SA)) - GLOB.simple_animals[AI_IDLE] -= SA - stack_trace("Found a null in simple_animals deactive list [SA.type]!") - continue - - if(!SA.ckey) - if(SA.stat != DEAD) - SA.handle_automated_movement() - if(SA.stat != DEAD) - SA.consider_wakeup() - if (MC_TICK_CHECK) - return diff --git a/code/datums/ai/_ai_controller.dm b/code/datums/ai/_ai_controller.dm index 91f624972ad..664e89eab09 100644 --- a/code/datums/ai/_ai_controller.dm +++ b/code/datums/ai/_ai_controller.dm @@ -68,7 +68,6 @@ multiple modular subtrees with behaviors PossessPawn(new_pawn) /datum/ai_controller/Destroy(force) - set_ai_status(AI_STATUS_OFF) UnpossessPawn(FALSE) set_movement_target(type, null) if(ai_movement.moving_controllers[src]) @@ -116,9 +115,14 @@ multiple modular subtrees with behaviors pawn = new_pawn pawn.ai_controller = src + var/turf/pawn_turf = get_turf(pawn) + if(pawn_turf) + SSai_controllers.ai_controllers_by_zlevel[pawn_turf.z] += src + SEND_SIGNAL(src, COMSIG_AI_CONTROLLER_POSSESSED_PAWN) reset_ai_status() + RegisterSignal(pawn, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_changed_z_level)) RegisterSignal(pawn, COMSIG_MOB_STATCHANGE, PROC_REF(on_stat_changed)) RegisterSignal(pawn, COMSIG_MOB_LOGIN, PROC_REF(on_sentience_gained)) RegisterSignal(pawn, COMSIG_QDELETING, PROC_REF(on_pawn_qdeleted)) @@ -127,25 +131,53 @@ multiple modular subtrees with behaviors /datum/ai_controller/proc/reset_ai_status() set_ai_status(get_expected_ai_status()) -/// Returns what the AI status should be based on current conditions. +/** + * Gets the AI status we expect the AI controller to be on at this current moment. + * Returns AI_STATUS_OFF if it's inhabited by a Client and shouldn't be, if it's dead and cannot act while dead, or is on a z level without clients. + * Returns AI_STATUS_ON otherwise. + */ /datum/ai_controller/proc/get_expected_ai_status() - var/final_status = AI_STATUS_ON - if (!ismob(pawn)) - return final_status + return AI_STATUS_ON var/mob/living/mob_pawn = pawn - if(!continue_processing_when_client && mob_pawn.client) - final_status = AI_STATUS_OFF - - if(ai_traits & CAN_ACT_WHILE_DEAD) - return final_status + return AI_STATUS_OFF if(mob_pawn.stat == DEAD) - final_status = AI_STATUS_OFF + if(ai_traits & CAN_ACT_WHILE_DEAD) + return AI_STATUS_ON + return AI_STATUS_OFF + + var/turf/pawn_turf = get_turf(mob_pawn) +#ifdef TESTING + if(!pawn_turf) + CRASH("AI controller [src] controlling pawn ([pawn]) is not on a turf.") +#endif + if(!length(SSmobs.clients_by_zlevel[pawn_turf.z])) + return AI_STATUS_OFF + return AI_STATUS_ON - return final_status +/datum/ai_controller/proc/get_current_turf() + var/mob/living/mob_pawn = pawn + var/turf/pawn_turf = get_turf(mob_pawn) + to_chat(world, "[pawn_turf]") + +///Called when the AI controller pawn changes z levels, we check if there's any clients on the new one and wake up the AI if there is. +/datum/ai_controller/proc/on_changed_z_level(atom/source, turf/old_turf, turf/new_turf, same_z_layer, notify_contents) + SIGNAL_HANDLER + var/mob/mob_pawn = pawn + if((mob_pawn?.client && !continue_processing_when_client)) + return + if(old_turf) + SSai_controllers.ai_controllers_by_zlevel[old_turf.z] -= src + if(new_turf) + SSai_controllers.ai_controllers_by_zlevel[new_turf.z] += src + var/new_level_clients = SSmobs.clients_by_zlevel[new_turf.z].len + if(new_level_clients) + set_ai_status(AI_STATUS_ON) + else + set_ai_status(AI_STATUS_OFF) ///Abstract proc for initializing the pawn to the new controller /datum/ai_controller/proc/TryPossessPawn(atom/new_pawn) @@ -156,9 +188,15 @@ multiple modular subtrees with behaviors if(isnull(pawn)) return // instantiated without an applicable pawn, fine - UnregisterSignal(pawn, list(COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT, COMSIG_MOB_STATCHANGE, COMSIG_QDELETING)) + set_ai_status(AI_STATUS_OFF) + UnregisterSignal(pawn, list(COMSIG_MOVABLE_Z_CHANGED, COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT, COMSIG_MOB_STATCHANGE, COMSIG_QDELETING)) if(ai_movement.moving_controllers[src]) ai_movement.stop_moving_towards(src) + var/turf/pawn_turf = get_turf(pawn) + if(pawn_turf) + SSai_controllers.ai_controllers_by_zlevel[pawn_turf.z] -= src + if(ai_status) + SSai_controllers.ai_controllers_by_status[ai_status] -= src pawn.ai_controller = null pawn = null if(destroy) @@ -269,15 +307,17 @@ multiple modular subtrees with behaviors /datum/ai_controller/proc/set_ai_status(new_ai_status) if(ai_status == new_ai_status) return FALSE //no change - + + //remove old status, if we've got one + if(ai_status) + SSai_controllers.ai_controllers_by_status[ai_status] -= src ai_status = new_ai_status + SSai_controllers.ai_controllers_by_status[new_ai_status] += src switch(ai_status) if(AI_STATUS_ON) - SSai_controllers.active_ai_controllers += src START_PROCESSING(SSai_behaviors, src) if(AI_STATUS_OFF) STOP_PROCESSING(SSai_behaviors, src) - SSai_controllers.active_ai_controllers -= src CancelActions() /datum/ai_controller/proc/PauseAi(time) diff --git a/code/datums/cogbar.dm b/code/datums/cogbar.dm new file mode 100644 index 00000000000..c52092e5bd1 --- /dev/null +++ b/code/datums/cogbar.dm @@ -0,0 +1,87 @@ +#define COGBAR_ANIMATION_TIME 5 DECISECONDS + +/** + * ### Cogbar + * Represents that the user is busy doing something. + */ +/datum/cogbar + /// Who's doing the thing + var/mob/user + /// The user client + var/client/user_client + /// The visible element to other players + var/obj/effect/overlay/vis/cog + /// The blank image that overlaps the cog - hides it from the source user + var/image/blank + /// The offset of the icon + var/offset_y + + +/datum/cogbar/New(mob/user) + src.user = user + src.user_client = user.client + + var/list/icon_offsets = user.get_oversized_icon_offsets() + offset_y = icon_offsets["y"] + + add_cog_to_user() + + RegisterSignal(user, COMSIG_QDELETING, PROC_REF(on_user_delete)) + + +/datum/cogbar/Destroy() + if(user) + SSvis_overlays.remove_vis_overlay(user, user.managed_vis_overlays) + user_client?.images -= blank + + user = null + user_client = null + cog = null + QDEL_NULL(blank) + + return ..() + + +/// Adds the cog to the user, visible by other players +/datum/cogbar/proc/add_cog_to_user() + cog = SSvis_overlays.add_vis_overlay(user, + icon = 'icons/effects/progressbar.dmi', + iconstate = "cog", + plane = HIGH_GAME_PLANE, + add_appearance_flags = APPEARANCE_UI_IGNORE_ALPHA, + unique = TRUE, + alpha = 0, + ) + cog.pixel_y = world.icon_size + offset_y + animate(cog, alpha = 255, time = COGBAR_ANIMATION_TIME) + + if(isnull(user_client)) + return + + blank = image('icons/blanks/32x32.dmi', cog, "nothing") + SET_PLANE_EXPLICIT(blank, HIGH_GAME_PLANE, user) + blank.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA + blank.override = TRUE + + user_client.images += blank + + +/// Removes the cog from the user +/datum/cogbar/proc/remove() + if(isnull(cog)) + qdel(src) + return + + animate(cog, alpha = 0, time = COGBAR_ANIMATION_TIME) + + QDEL_IN(src, COGBAR_ANIMATION_TIME) + + +/// When the user is deleted, remove the cog +/datum/cogbar/proc/on_user_delete(datum/source) + SIGNAL_HANDLER + + qdel(src) + + +#undef COGBAR_ANIMATION_TIME diff --git a/code/datums/components/crafting/tailoring.dm b/code/datums/components/crafting/tailoring.dm index 56a6bfb2c3f..14a7ebfc21b 100644 --- a/code/datums/components/crafting/tailoring.dm +++ b/code/datums/components/crafting/tailoring.dm @@ -199,6 +199,29 @@ ) category = CAT_CLOTHING +/datum/crafting_recipe/wreath + name = "Watcher Wreath" + result = /obj/item/clothing/neck/wreath + time = 2 SECONDS + reqs = list( + /obj/item/stack/sheet/bone = 2, + /obj/item/stack/sheet/sinew = 2, + /obj/item/stack/ore/diamond = 2, + ) + category = CAT_CLOTHING + +/datum/crafting_recipe/icewreath + name = "Icewing Wreath" + result = /obj/item/clothing/neck/wreath/icewing + time = 2 SECONDS + reqs = list( + /obj/item/stack/sheet/bone = 1, + /obj/item/stack/sheet/sinew = 1, + /obj/item/stack/ore/diamond = 2, + /obj/item/crusher_trophy/watcher_wing/ice_wing = 1, + ) + category = CAT_CLOTHING + /datum/crafting_recipe/bracers name = "Bone Bracers" result = /obj/item/clothing/gloves/bracer diff --git a/code/datums/components/simple_bodycam.dm b/code/datums/components/simple_bodycam.dm index 81deb50649d..9d653f38a78 100644 --- a/code/datums/components/simple_bodycam.dm +++ b/code/datums/components/simple_bodycam.dm @@ -65,4 +65,5 @@ /datum/component/simple_bodycam/proc/camera_gone(datum/source) SIGNAL_HANDLER - qdel(src) + if (!QDELETED(src)) + qdel(src) diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm index 23462256342..771cdd12e10 100644 --- a/code/datums/diseases/advance/advance.dm +++ b/code/datums/diseases/advance/advance.dm @@ -160,7 +160,8 @@ for(var/s in symptoms) var/datum/symptom/symptom_datum = s - symptom_datum.Activate(src) + if(!symptom_datum.neutered) + symptom_datum.Activate(src) // Tell symptoms stage changed diff --git a/code/datums/diseases/advance/symptoms/itching.dm b/code/datums/diseases/advance/symptoms/itching.dm index cb468a132cc..7615edb1b82 100644 --- a/code/datums/diseases/advance/symptoms/itching.dm +++ b/code/datums/diseases/advance/symptoms/itching.dm @@ -27,6 +27,7 @@ COOLDOWN_DECLARE(itching_cooldown) ///if FALSE, there is a percentage chance that the mob will emote scratching while itching_cooldown is on cooldown. If TRUE, won't emote again until after the off cooldown scratch occurs. var/off_cooldown_scratched = FALSE + /datum/symptom/itching/Start(datum/disease/advance/active_disease) . = ..() if(!.) @@ -41,17 +42,12 @@ . = ..() if(!.) return - var/mob/living/carbon/affected_mob = active_disease.affected_mob - var/obj/item/bodypart/bodypart = affected_mob.get_bodypart(affected_mob.get_random_valid_zone(even_weights = TRUE)) - if(bodypart && IS_ORGANIC_LIMB(bodypart) && !(bodypart.bodypart_flags & BODYPART_PSEUDOPART)) //robotic limbs will mean less scratching overall (why are golems able to damage themselves with self-scratching, but not androids? the world may never know) - var/can_scratch = scratch && !affected_mob.incapacitated() - if(can_scratch) - bodypart.receive_damage(0.5) - //below handles emotes, limiting the emote of emotes passed to chat - if(COOLDOWN_FINISHED(src, itching_cooldown) || !COOLDOWN_FINISHED(src, itching_cooldown) && prob(60) && !off_cooldown_scratched) - affected_mob.visible_message("[can_scratch ? span_warning("[affected_mob] scratches [affected_mob.p_their()] [bodypart.plaintext_zone].") : ""]", span_warning("Your [bodypart.plaintext_zone] itches. [can_scratch ? " You scratch it." : ""]")) - COOLDOWN_START(src, itching_cooldown, 5 SECONDS) - if(!off_cooldown_scratched && !COOLDOWN_FINISHED(src, itching_cooldown)) - off_cooldown_scratched = TRUE - else - off_cooldown_scratched = FALSE + + var/announce_scratch = COOLDOWN_FINISHED(src, itching_cooldown) || (!COOLDOWN_FINISHED(src, itching_cooldown) && prob(60) && !off_cooldown_scratched) + if (!active_disease.affected_mob.itch(silent = !announce_scratch, can_scratch = scratch) || !announce_scratch) + return + COOLDOWN_START(src, itching_cooldown, 5 SECONDS) + if(!off_cooldown_scratched && !COOLDOWN_FINISHED(src, itching_cooldown)) + off_cooldown_scratched = TRUE + else + off_cooldown_scratched = FALSE diff --git a/code/datums/diseases/advance/symptoms/narcolepsy.dm b/code/datums/diseases/advance/symptoms/narcolepsy.dm index ac7eae25d4a..cbf6462f2c4 100644 --- a/code/datums/diseases/advance/symptoms/narcolepsy.dm +++ b/code/datums/diseases/advance/symptoms/narcolepsy.dm @@ -35,6 +35,10 @@ symptom_delay_max = 45 /datum/symptom/narcolepsy/Activate(datum/disease/advance/A) + . = ..() + if(!.) + return + var/mob/living/M = A.affected_mob switch(A.stage) if(1) diff --git a/code/datums/elements/screentips/README.md b/code/datums/elements/screentips/README.md index 92a66ca9dd4..30d0e7a90cc 100644 --- a/code/datums/elements/screentips/README.md +++ b/code/datums/elements/screentips/README.md @@ -35,18 +35,17 @@ Example: ```dm /obj/structure/table/Initialize(mapload) - if (!(obj_flags & NO_DECONSTRUCTION)) - var/static/list/tool_behaviors = list( - TOOL_SCREWDRIVER = list( - SCREENTIP_CONTEXT_RMB = "Disassemble", - ), + var/static/list/tool_behaviors = list( + TOOL_SCREWDRIVER = list( + SCREENTIP_CONTEXT_RMB = "Disassemble", + ), - TOOL_WRENCH = list( - SCREENTIP_CONTEXT_RMB = "Deconstruct", - ), - ) + TOOL_WRENCH = list( + SCREENTIP_CONTEXT_RMB = "Deconstruct", + ), + ) - AddElement(/datum/element/contextual_screentip_tools, tool_behaviors) + AddElement(/datum/element/contextual_screentip_tools, tool_behaviors) ``` This will display "RMB: Deconstruct" when the user hovers over a table with a wrench. diff --git a/code/datums/quirks/neutral_quirks/transhumanist.dm b/code/datums/quirks/neutral_quirks/transhumanist.dm index 88923d463f6..046c2bb30f0 100644 --- a/code/datums/quirks/neutral_quirks/transhumanist.dm +++ b/code/datums/quirks/neutral_quirks/transhumanist.dm @@ -15,7 +15,7 @@ /datum/quirk/transhumanist name = "Transhumanist" - desc = "You see silicon life as the perfect lifeform and despise organic flesh. You are happier around silicons, but get frustrated when around organics. You seek to replace your fleshy limbs with their silicon counterparts. You start with a robotic limb." + desc = "You see silicon life as the perfect lifeform and despise organic flesh. You are happier around silicons, but get frustrated when around organics. You seek to replace your failing flesh with perfect silicon. You start with a robotic augmentation." icon = FA_ICON_ROBOT quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES|QUIRK_MOODLET_BASED value = 0 @@ -29,7 +29,8 @@ /obj/item/toy/figure/borg, ) var/slot_string - var/obj/item/bodypart/old_limb + var/obj/item/old_part + /datum/quirk/transhumanist/add(client/client_source) RegisterSignal(quirk_holder, COMSIG_CARBON_POST_ATTACH_LIMB, PROC_REF(calculate_bodypart_score)) @@ -100,27 +101,59 @@ if(-INFINITY to 0) quirk_holder.add_mood_event(MOOD_CATEGORY_TRANSHUMANIST_BODYPART, /datum/mood_event/very_organic) +/datum/quirk_constant_data/transhumanist + associated_typepath = /datum/quirk/transhumanist + customization_options = list(/datum/preference/choiced/trans_prosthetic) /datum/quirk/transhumanist/add_unique(client/client_source) - var/limb_type = GLOB.limb_choice_transhuman[client_source?.prefs?.read_preference(/datum/preference/choiced/prosthetic)] - if(isnull(limb_type)) //Client gone or they chose a random prosthetic - limb_type = GLOB.limb_choice_transhuman[pick(GLOB.limb_choice_transhuman)] + var/part_type = GLOB.part_choice_transhuman[client_source?.prefs?.read_preference(/datum/preference/choiced/trans_prosthetic)] + if(isnull(part_type)) //Client gone or they chose a random part + part_type = GLOB.part_choice_transhuman[pick(GLOB.part_choice_transhuman)] var/mob/living/carbon/human/human_holder = quirk_holder - var/obj/item/bodypart/new_part = new limb_type() - - slot_string = "[new_part.plaintext_zone]" - old_limb = human_holder.return_and_replace_bodypart(new_part, special = TRUE) + var/obj/item/new_part = new part_type() + if(isbodypart(new_part)) + var/obj/item/bodypart/new_bodypart = new_part + slot_string = new_bodypart.plaintext_zone + old_part = human_holder.return_and_replace_bodypart(new_bodypart, special = TRUE) + else if(isorgan(new_part)) + var/obj/item/organ/new_organ = new_part + old_part = human_holder.get_organ_slot(new_organ.slot) + if(new_organ.Insert(human_holder, special = TRUE)) + old_part.moveToNullspace() + STOP_PROCESSING(SSobj, old_part) + slot_string = new_organ.name /datum/quirk/transhumanist/post_add() - if(slot_string) - to_chat(quirk_holder, span_boldannounce("Your [slot_string] has been replaced with a robot arm. You need to use a welding tool and cables to repair it, instead of sutures and regenerative meshes.")) + if(!slot_string) + return + if(isbodypart(old_part)) + to_chat(quirk_holder, span_boldannounce("Your [slot_string] has been replaced with a robotic limb. You need to use a welding tool and cables to repair it, instead of sutures and regenerative meshes.")) + else if (old_part.name == "eyes") + to_chat(quirk_holder, span_boldannounce("You replaced your eyes with flashlights, not cameras. You can't see a thing!")) + else if (isorgan(old_part)) + to_chat(quirk_holder, span_boldannounce("Your [slot_string] brings you one step closer to silicon perfection, but you feel you're not quite there yet.")) /datum/quirk/transhumanist/remove() - if(old_limb) - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.del_and_replace_bodypart(old_limb, special = TRUE) - old_limb = null + if(isnull(old_part)) + quirk_holder.clear_mood_event(MOOD_CATEGORY_TRANSHUMANIST_BODYPART) + quirk_holder.clear_mood_event(MOOD_CATEGORY_TRANSHUMANIST_PEOPLE) + return + + var/mob/living/carbon/human/human_holder = quirk_holder + if(isbodypart(old_part)) + var/obj/item/bodypart/old_bodypart = old_part + human_holder.del_and_replace_bodypart(old_bodypart, special = TRUE) + old_bodypart = null + else if(isorgan(old_part)) + var/obj/item/organ/old_organ = old_part + old_part = human_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + old_organ.Insert(quirk_holder, special = TRUE) + old_part.moveToNullspace() + STOP_PROCESSING(SSobj, old_part) + old_organ = null + old_part = null + quirk_holder.clear_mood_event(MOOD_CATEGORY_TRANSHUMANIST_BODYPART) quirk_holder.clear_mood_event(MOOD_CATEGORY_TRANSHUMANIST_PEOPLE) diff --git a/code/datums/sprite_accessories.dm b/code/datums/sprite_accessories.dm index c8cbfb54abb..2c31b61ea1a 100644 --- a/code/datums/sprite_accessories.dm +++ b/code/datums/sprite_accessories.dm @@ -1916,6 +1916,26 @@ hasinner = TRUE color_src = HAIR_COLOR +/datum/sprite_accessory/ears/cat/big + name = "Big" + icon_state = "big" + +/datum/sprite_accessory/ears/cat/miqo + name = "Coeurl" + icon_state = "miqo" + +/datum/sprite_accessory/ears/cat/fold + name = "Fold" + icon_state = "fold" + +/datum/sprite_accessory/ears/cat/lynx + name = "Lynx" + icon_state = "lynx" + +/datum/sprite_accessory/ears/cat/round + name = "Round" + icon_state = "round" + /datum/sprite_accessory/ears/fox icon = 'icons/mob/human/fox_features.dmi' name = "Fox" diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index d61145e4dd4..d9ceac4f7f2 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -799,7 +799,7 @@ SEND_SIGNAL(src, COMSIG_MACHINERY_REFRESH_PARTS) /obj/machinery/proc/default_pry_open(obj/item/crowbar, close_after_pry = FALSE, open_density = FALSE, closed_density = TRUE) - . = !(state_open || panel_open || is_operational || (obj_flags & NO_DECONSTRUCTION)) && crowbar.tool_behaviour == TOOL_CROWBAR + . = !(state_open || panel_open || is_operational) && crowbar.tool_behaviour == TOOL_CROWBAR if(!.) return crowbar.play_tool_sound(src, 50) @@ -809,23 +809,23 @@ close_machine(density_to_set = closed_density) /obj/machinery/proc/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel = 0, custom_deconstruct = FALSE) - . = (panel_open || ignore_panel) && !(obj_flags & NO_DECONSTRUCTION) && crowbar.tool_behaviour == TOOL_CROWBAR + . = (panel_open || ignore_panel) && crowbar.tool_behaviour == TOOL_CROWBAR if(!. || custom_deconstruct) return crowbar.play_tool_sound(src, 50) deconstruct(TRUE) -/obj/machinery/deconstruct(disassembled = TRUE) +/obj/machinery/handle_deconstruct(disassembled = TRUE) SHOULD_NOT_OVERRIDE(TRUE) if(obj_flags & NO_DECONSTRUCTION) - dump_contents() //drop everything inside us - return ..() //Just delete us, no need to call anything else. + dump_inventory_contents() //drop stuff we consider important + return //Just delete us, no need to call anything else. on_deconstruction(disassembled) if(!LAZYLEN(component_parts)) dump_contents() //drop everything inside us - return ..() //we don't have any parts. + return //we don't have any parts. spawn_frame(disassembled) for(var/part in component_parts) @@ -849,8 +849,6 @@ //to handle their contents before we dump them dump_contents() - return ..() - /** * Spawns a frame where this machine is. If the machine was not disassmbled, the * frame is spawned damaged. If the frame couldn't exist on this turf, it's smashed @@ -882,7 +880,7 @@ /obj/machinery/atom_break(damage_flag) . = ..() - if(!(machine_stat & BROKEN) && !(obj_flags & NO_DECONSTRUCTION)) + if(!(machine_stat & BROKEN)) set_machine_stat(machine_stat | BROKEN) SEND_SIGNAL(src, COMSIG_MACHINERY_BROKEN, damage_flag) update_appearance() @@ -929,7 +927,7 @@ qdel(atom_part) /obj/machinery/proc/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) - if((obj_flags & NO_DECONSTRUCTION) || screwdriver.tool_behaviour != TOOL_SCREWDRIVER) + if(screwdriver.tool_behaviour != TOOL_SCREWDRIVER) return FALSE screwdriver.play_tool_sound(src, 50) @@ -956,7 +954,7 @@ if(!istype(replacer_tool)) return FALSE - if((obj_flags & NO_DECONSTRUCTION) && !replacer_tool.works_from_distance) + if(!replacer_tool.works_from_distance) return FALSE var/shouldplaysound = FALSE diff --git a/code/game/machinery/barsigns.dm b/code/game/machinery/barsigns.dm index faa29c2673e..006620ec5f4 100644 --- a/code/game/machinery/barsigns.dm +++ b/code/game/machinery/barsigns.dm @@ -88,7 +88,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/barsign, 32) /obj/machinery/barsign/atom_break(damage_flag) . = ..() - if((machine_stat & BROKEN) && !(obj_flags & NO_DECONSTRUCTION)) + if(machine_stat & BROKEN) set_sign(new /datum/barsign/hiddensigns/signoff) /obj/machinery/barsign/on_deconstruction(disassembled) diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index e0031e2548f..ed896cc7576 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -302,23 +302,22 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) toggle_cam(null, 0) /obj/machinery/camera/on_deconstruction(disassembled) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - var/obj/item/wallframe/camera/dropped_cam = new(drop_location()) - dropped_cam.update_integrity(dropped_cam.max_integrity * 0.5) - if(camera_construction_state >= CAMERA_STATE_WIRED) - new /obj/item/stack/cable_coil(drop_location(), 2) - if(xray_module) - drop_upgrade(xray_module) - if(emp_module) - drop_upgrade(emp_module) - if(proximity_monitor) - drop_upgrade(proximity_monitor) - else - if(camera_construction_state >= CAMERA_STATE_WIRED) - new /obj/item/stack/cable_coil(drop_location(), 2) - new /obj/item/stack/sheet/iron(loc) - return ..() + if(!disassembled) + if(camera_construction_state >= CAMERA_STATE_WIRED) + new /obj/item/stack/cable_coil(drop_location(), 2) + new /obj/item/stack/sheet/iron(loc) + return + + var/obj/item/wallframe/camera/dropped_cam = new(drop_location()) + dropped_cam.update_integrity(dropped_cam.max_integrity * 0.5) + if(camera_construction_state >= CAMERA_STATE_WIRED) + new /obj/item/stack/cable_coil(drop_location(), 2) + if(xray_module) + drop_upgrade(xray_module) + if(emp_module) + drop_upgrade(emp_module) + if(proximity_monitor) + drop_upgrade(proximity_monitor) /obj/machinery/camera/update_icon_state() //TO-DO: Make panel open states, xray camera, and indicator lights overlays instead. var/xray_module diff --git a/code/game/machinery/computer/_computer.dm b/code/game/machinery/computer/_computer.dm index f9158d21996..0749c79bb88 100644 --- a/code/game/machinery/computer/_computer.dm +++ b/code/game/machinery/computer/_computer.dm @@ -63,7 +63,7 @@ /obj/machinery/computer/screwdriver_act(mob/living/user, obj/item/I) if(..()) return TRUE - if(circuit && !(obj_flags & NO_DECONSTRUCTION)) + if(circuit) balloon_alert(user, "disconnecting monitor...") if(I.use_tool(src, user, time_to_unscrew, volume=50)) deconstruct(TRUE) diff --git a/code/game/machinery/computer/atmos_computers/_air_sensor.dm b/code/game/machinery/computer/atmos_computers/_air_sensor.dm index d9d461149bc..1c365dd0876 100644 --- a/code/game/machinery/computer/atmos_computers/_air_sensor.dm +++ b/code/game/machinery/computer/atmos_computers/_air_sensor.dm @@ -221,8 +221,6 @@ deconstruct(TRUE) return ITEM_INTERACT_SUCCESS -/obj/item/air_sensor/deconstruct(disassembled) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/analyzer(loc) - new /obj/item/stack/sheet/iron(loc, 1) - return ..() +/obj/item/air_sensor/atom_deconstruct(disassembled) + new /obj/item/analyzer(loc) + new /obj/item/stack/sheet/iron(loc, 1) diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index 12d364e6130..18ca1665765 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -11,18 +11,16 @@ AddComponent(/datum/component/simple_rotation) register_context() -/obj/structure/frame/computer/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/atom/drop_loc = drop_location() - if(state == FRAME_COMPUTER_STATE_GLASSED) - if(disassembled) - new /obj/item/stack/sheet/glass(drop_loc, 2) - else - new /obj/item/shard(drop_loc) - new /obj/item/shard(drop_loc) - if(state >= FRAME_COMPUTER_STATE_WIRED) - new /obj/item/stack/cable_coil(drop_loc, 5) - +/obj/structure/frame/computer/atom_deconstruct(disassembled = TRUE) + var/atom/drop_loc = drop_location() + if(state == FRAME_COMPUTER_STATE_GLASSED) + if(disassembled) + new /obj/item/stack/sheet/glass(drop_loc, 2) + else + new /obj/item/shard(drop_loc) + new /obj/item/shard(drop_loc) + if(state >= FRAME_COMPUTER_STATE_WIRED) + new /obj/item/stack/cable_coil(drop_loc, 5) return ..() /obj/structure/frame/computer/add_context(atom/source, list/context, obj/item/held_item, mob/user) diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index e6830fd1848..f47948753ab 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -22,13 +22,10 @@ if(circuit) . += "It has \a [circuit] installed." -/obj/structure/frame/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/atom/movable/drop_loc = drop_location() - new /obj/item/stack/sheet/iron(drop_loc, 5) - circuit?.forceMove(drop_loc) - - return ..() +/obj/structure/frame/atom_deconstruct(disassembled = TRUE) + var/atom/movable/drop_loc = drop_location() + new /obj/item/stack/sheet/iron(drop_loc, 5) + circuit?.forceMove(drop_loc) /// Called when circuit has been set to a new board /obj/structure/frame/proc/circuit_added(obj/item/circuitboard/added) @@ -61,8 +58,6 @@ /obj/structure/frame/proc/try_dissassemble(mob/living/user, obj/item/tool, disassemble_time = 8 SECONDS) if(state != FRAME_STATE_EMPTY) return NONE - if(obj_flags & NO_DECONSTRUCTION) - return NONE if(anchored && state == FRAME_STATE_EMPTY) //when using a screwdriver on an incomplete frame(missing components) no point checking for this balloon_alert(user, "must be unanchored first!") return ITEM_INTERACT_BLOCKING diff --git a/code/game/machinery/dance_machine.dm b/code/game/machinery/dance_machine.dm index f791c0dcc27..0a626459667 100644 --- a/code/game/machinery/dance_machine.dm +++ b/code/game/machinery/dance_machine.dm @@ -33,8 +33,6 @@ /obj/machinery/jukebox/wrench_act(mob/living/user, obj/item/tool) if(!isnull(music_player.active_song_sound)) return NONE - if(obj_flags & NO_DECONSTRUCTION) - return NONE if(default_unfasten_wrench(user, tool) == SUCCESSFUL_UNFASTEN) return ITEM_INTERACT_SUCCESS diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index bedb1692978..61f12100de2 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -17,12 +17,13 @@ var/proj_pass_rate = 50 //How many projectiles will pass the cover. Lower means stronger cover var/bar_material = METAL -/obj/structure/barricade/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - make_debris() - qdel(src) +/obj/structure/barricade/atom_deconstruct(disassembled = TRUE) + make_debris() +/// Spawn debris & stuff upon deconstruction /obj/structure/barricade/proc/make_debris() + PROTECTED_PROC(TRUE) + return /obj/structure/barricade/attackby(obj/item/I, mob/living/user, params) diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 1dc343a0c0b..0849a5ad8c5 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -347,8 +347,6 @@ /obj/machinery/door/window/screwdriver_act(mob/living/user, obj/item/tool) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return if(density || operating) to_chat(user, span_warning("You need to open the door to access the maintenance panel!")) return @@ -360,8 +358,6 @@ /obj/machinery/door/window/crowbar_act(mob/living/user, obj/item/tool) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return if(!panel_open || density || operating) return add_fingerprint(user) diff --git a/code/game/machinery/fat_sucker.dm b/code/game/machinery/fat_sucker.dm index 279e83ecbe9..4567959b844 100644 --- a/code/game/machinery/fat_sucker.dm +++ b/code/game/machinery/fat_sucker.dm @@ -80,7 +80,7 @@ user.visible_message(span_notice("You see [user] kicking against the door of [src]!"), \ span_notice("You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)"), \ span_hear("You hear a metallic creaking from [src].")) - if(do_after(user, breakout_time, target = src)) + if(do_after(user, breakout_time, target = src, hidden = TRUE)) if(!user || user.stat != CONSCIOUS || user.loc != src || state_open) return free_exit = TRUE diff --git a/code/game/machinery/harvester.dm b/code/game/machinery/harvester.dm index 33d08def9d2..09599b0cbff 100644 --- a/code/game/machinery/harvester.dm +++ b/code/game/machinery/harvester.dm @@ -171,7 +171,7 @@ return TRUE /obj/machinery/harvester/default_pry_open(obj/item/tool) //wew - . = !(state_open || panel_open || (obj_flags & NO_DECONSTRUCTION)) && tool.tool_behaviour == TOOL_CROWBAR //We removed is_operational here + . = !(state_open || panel_open) && tool.tool_behaviour == TOOL_CROWBAR //We removed is_operational here if(.) tool.play_tool_sound(src, 50) visible_message(span_notice("[usr] pries open \the [src]."), span_notice("You pry open [src].")) diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 5b62c5b402b..18ccc976f06 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -111,6 +111,9 @@ Possible to do for anyone motivated enough: ) AddElement(/datum/element/contextual_screentip_mob_typechecks, hovering_mob_typechecks) + if(on_network) + holopads += src + /obj/machinery/holopad/secure name = "secure holopad" desc = "It's a floor-mounted device for projecting holographic images. This one will refuse to auto-connect incoming calls." @@ -175,11 +178,6 @@ Possible to do for anyone motivated enough: if(!replay_mode && (disk?.record)) replay_start() -/obj/machinery/holopad/Initialize(mapload) - . = ..() - if(on_network) - holopads += src - /obj/machinery/holopad/Destroy() if(outgoing_call) outgoing_call.ConnectionFailure(src) diff --git a/code/game/machinery/limbgrower.dm b/code/game/machinery/limbgrower.dm index 1fe2f542ba2..b63d13648eb 100644 --- a/code/game/machinery/limbgrower.dm +++ b/code/game/machinery/limbgrower.dm @@ -283,7 +283,6 @@ /obj/machinery/limbgrower/fullupgrade //Inherently cheaper organ production. This is to NEVER be inherently emagged, no valids. desc = "It grows new limbs using Synthflesh. This alien model seems more efficient." - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION circuit = /obj/item/circuitboard/machine/limbgrower/fullupgrade /obj/machinery/limbgrower/fullupgrade/Initialize(mapload) diff --git a/code/game/machinery/machine_frame.dm b/code/game/machinery/machine_frame.dm index 84c58d32823..4edb3215e2b 100644 --- a/code/game/machinery/machine_frame.dm +++ b/code/game/machinery/machine_frame.dm @@ -17,11 +17,10 @@ QDEL_LIST(components) return ..() -/obj/structure/frame/machine/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(state >= FRAME_STATE_WIRED) - new /obj/item/stack/cable_coil(drop_location(), 5) - dump_contents() +/obj/structure/frame/machine/atom_deconstruct(disassembled = TRUE) + if(state >= FRAME_STATE_WIRED) + new /obj/item/stack/cable_coil(drop_location(), 5) + dump_contents() return ..() /obj/structure/frame/machine/add_context(atom/source, list/context, obj/item/held_item, mob/user) diff --git a/code/game/machinery/sleepers.dm b/code/game/machinery/sleepers.dm index 68b4026b744..f768381548a 100644 --- a/code/game/machinery/sleepers.dm +++ b/code/game/machinery/sleepers.dm @@ -147,7 +147,7 @@ return FALSE /obj/machinery/sleeper/default_pry_open(obj/item/I) //wew - . = !(state_open || panel_open || (obj_flags & NO_DECONSTRUCTION)) && I.tool_behaviour == TOOL_CROWBAR + . = !(state_open || panel_open) && I.tool_behaviour == TOOL_CROWBAR if(.) I.play_tool_sound(src, 50) visible_message(span_notice("[usr] pries open [src]."), span_notice("You pry open [src].")) diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index 0fadef7b823..d95668975f5 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -794,21 +794,21 @@ causes the SSU to break due to state_open being set to TRUE at the end, and the panel becoming inaccessible. */ /obj/machinery/suit_storage_unit/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) - if(!(obj_flags & NO_DECONSTRUCTION) && screwdriver.tool_behaviour == TOOL_SCREWDRIVER && (uv || locked)) + if(screwdriver.tool_behaviour == TOOL_SCREWDRIVER && (uv || locked)) to_chat(user, span_warning("You cant open the panel while its [locked ? "locked" : "decontaminating"]")) return TRUE return ..() /obj/machinery/suit_storage_unit/default_pry_open(obj/item/crowbar)//needs to check if the storage is locked. - . = !(state_open || panel_open || is_operational || locked || (obj_flags & NO_DECONSTRUCTION)) && crowbar.tool_behaviour == TOOL_CROWBAR + . = !(state_open || panel_open || is_operational || locked) && crowbar.tool_behaviour == TOOL_CROWBAR if(.) crowbar.play_tool_sound(src, 50) visible_message(span_notice("[usr] pries open \the [src]."), span_notice("You pry open \the [src].")) open_machine() /obj/machinery/suit_storage_unit/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct) - . = (!locked && panel_open && !(obj_flags & NO_DECONSTRUCTION) && crowbar.tool_behaviour == TOOL_CROWBAR) + . = (!locked && panel_open && crowbar.tool_behaviour == TOOL_CROWBAR) if(.) return ..() diff --git a/code/game/machinery/telecomms/machines/allinone.dm b/code/game/machinery/telecomms/machines/allinone.dm index f8a6b66c049..f159339193e 100644 --- a/code/game/machinery/telecomms/machines/allinone.dm +++ b/code/game/machinery/telecomms/machines/allinone.dm @@ -22,6 +22,12 @@ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION +/obj/machinery/telecomms/allinone/indestructible/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) + return NONE + +/obj/machinery/telecomms/allinone/indestructible/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct) + return NONE + /obj/machinery/telecomms/allinone/receive_signal(datum/signal/subspace/signal) if(!istype(signal) || signal.transmission_method != TRANSMISSION_SUBSPACE) // receives on subspace only return diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm index 2a6d1c039ad..0ac4188328f 100644 --- a/code/game/objects/effects/landmarks.dm +++ b/code/game/objects/effects/landmarks.dm @@ -298,6 +298,16 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark) GLOB.nukeop_leader_start += loc return INITIALIZE_HINT_QDEL +/obj/effect/landmark/start/nukeop_overwatch + name = "nukeop overwatch" + icon = 'icons/effects/landmarks_static.dmi' + icon_state = "snukeop_leader_spawn" + +/obj/effect/landmark/start/nukeop_overwatch/Initialize(mapload) + ..() + GLOB.nukeop_overwatch_start += loc + return INITIALIZE_HINT_QDEL + // Must be immediate because players will // join before SSatom initializes everything. INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player) diff --git a/code/game/objects/items/cardboard_cutouts.dm b/code/game/objects/items/cardboard_cutouts.dm index e50963a855e..71f3a244a30 100644 --- a/code/game/objects/items/cardboard_cutouts.dm +++ b/code/game/objects/items/cardboard_cutouts.dm @@ -92,10 +92,8 @@ if((damage_flag == BULLET || damage_flag == MELEE) && (damage_type == BRUTE) && prob(damage_sustained)) push_over() -/obj/item/cardboard_cutout/deconstruct(disassembled) - if(!(flags_1 & HOLOGRAM_1) || !(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/cardboard(loc, 1) - return ..() +/obj/item/cardboard_cutout/atom_deconstruct(disassembled) + new /obj/item/stack/sheet/cardboard(loc, 1) /proc/get_cardboard_cutout_instance(datum/cardboard_cutout/cardboard_cutout) ASSERT(ispath(cardboard_cutout), "[cardboard_cutout] is not a path of /datum/cardboard_cutout") diff --git a/code/game/objects/items/devices/battle_royale.dm b/code/game/objects/items/devices/battle_royale.dm new file mode 100644 index 00000000000..b4ea15c6de7 --- /dev/null +++ b/code/game/objects/items/devices/battle_royale.dm @@ -0,0 +1,117 @@ +/// Quietly implants people with battle royale implants +/obj/item/royale_implanter + name = "royale implanter" + desc = "Subtly implants people with rumble royale implants, \ + preparing them to struggle for their life for the enjoyment of the Syndicate's paying audience. \ + Implants may cause irritation at site of implantation." + icon = 'icons/obj/medical/syringe.dmi' + icon_state = "nanite_hypo" + w_class = WEIGHT_CLASS_SMALL + /// Do we have a linked remote? Just to prevent headdesk moments + var/linked = FALSE + +/obj/item/royale_implanter/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(!isliving(interacting_with)) + if (!istype(interacting_with, /obj/item/royale_remote)) + return NONE + var/obj/item/royale_remote/remote = interacting_with + remote.link_implanter(src, user) + return ITEM_INTERACT_SUCCESS + if (!linked) + balloon_alert(user, "no linked remote!") + return ITEM_INTERACT_BLOCKING + if (DOING_INTERACTION_WITH_TARGET(user, interacting_with)) + balloon_alert(user, "busy!") + return ITEM_INTERACT_BLOCKING + var/mob/living/potential_winner = interacting_with + if (potential_winner.stat != CONSCIOUS) + balloon_alert(user, "target unconscious!") + return ITEM_INTERACT_BLOCKING + if (!potential_winner.mind) + balloon_alert(user, "target too boring!") + return ITEM_INTERACT_BLOCKING + log_combat(user, potential_winner, "tried to implant a battle royale implant into") + if (!do_after(user, 1.5 SECONDS, potential_winner)) + balloon_alert(user, "interrupted!") + return ITEM_INTERACT_BLOCKING + + var/obj/item/implant/explosive/battle_royale/encouragement_implant = new + if(!encouragement_implant.implant(potential_winner, user)) + qdel(encouragement_implant) // no balloon alert - feedback is usually provided by the implant + return ITEM_INTERACT_BLOCKING + + potential_winner.balloon_alert(user, "implanted") + SEND_SIGNAL(src, COMSIG_ROYALE_IMPLANTED, encouragement_implant) + return ITEM_INTERACT_SUCCESS + +/// Activates implants implanted by linked royale implanter +/obj/item/royale_remote + name = "royale remote" + desc = "A single use device which will activate any linked rumble royale implants, starting the show." + icon = 'icons/obj/devices/remote.dmi' + icon_state = "designator_syndicate" + w_class = WEIGHT_CLASS_SMALL + /// Minimum number of contestants we should have + var/required_contestants = 6 + /// List of implanters we are linked to + var/list/linked_implanters = list() + /// List of implants of lucky contestants + var/list/implanted_implants = list() + +/obj/item/royale_remote/Destroy(force) + linked_implanters = null + implanted_implants = null + return ..() + +/obj/item/royale_remote/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if (!istype(interacting_with, /obj/item/royale_implanter)) + return NONE + link_implanter(interacting_with) + return ITEM_INTERACT_SUCCESS + +/obj/item/royale_remote/attack_self(mob/user, modifiers) + . = ..() + if (.) + return + var/contestant_count = length(implanted_implants) + if (contestant_count < required_contestants) + balloon_alert(user, "[required_contestants - contestant_count] contestants needed!") + return + + SSbattle_royale.start_battle(implanted_implants) + + for (var/obj/implanter as anything in linked_implanters) + do_sparks(3, cardinal_only = FALSE, source = implanter) + qdel(implanter) + do_sparks(3, cardinal_only = FALSE, source = src) + qdel(src) + +/// Link to an implanter +/obj/item/royale_remote/proc/link_implanter(obj/item/royale_implanter/implanter, mob/user) + if (implanter in linked_implanters) + if (user) + balloon_alert(user, "already linked!") + return + + if (user) + balloon_alert(user, "link established") + + implanter.linked = TRUE + linked_implanters += implanter + RegisterSignal(implanter, COMSIG_ROYALE_IMPLANTED, PROC_REF(record_contestant)) + RegisterSignal(implanter, COMSIG_QDELETING, PROC_REF(implanter_destroyed)) + +/// Record that someone just got implanted +/obj/item/royale_remote/proc/record_contestant(obj/item/implanter, obj/item/implant) + SIGNAL_HANDLER + implanted_implants |= implant + RegisterSignal(implant, COMSIG_QDELETING, PROC_REF(implant_destroyed)) + +/// A linked implanter was destroyed +/obj/item/royale_remote/proc/implanter_destroyed(obj/item/implanter) + SIGNAL_HANDLER + linked_implanters -= implanter + +/obj/item/royale_remote/proc/implant_destroyed(obj/item/implant) + SIGNAL_HANDLER + implanted_implants -= implant diff --git a/code/game/objects/items/grenades/_grenade.dm b/code/game/objects/items/grenades/_grenade.dm index e7e592eabac..4c737ed53f3 100644 --- a/code/game/objects/items/grenades/_grenade.dm +++ b/code/game/objects/items/grenades/_grenade.dm @@ -63,11 +63,9 @@ sleep(det_time)//so you dont die instantly return dud_flags ? SHAME : BRUTELOSS -/obj/item/grenade/deconstruct(disassembled = TRUE) +/obj/item/grenade/atom_deconstruct(disassembled = TRUE) if(!disassembled) detonate() - if(!QDELETED(src)) - qdel(src) /obj/item/grenade/apply_fantasy_bonuses(bonus) . = ..() diff --git a/code/game/objects/items/implants/implant.dm b/code/game/objects/items/implants/implant.dm index cc64788e597..4541bbdbdad 100644 --- a/code/game/objects/items/implants/implant.dm +++ b/code/game/objects/items/implants/implant.dm @@ -119,7 +119,7 @@ * Arguments: * * mob/living/source - What the implant is being removed from * * silent - unused here - * * special - unused here + * * special - Set to true if removed by admin panel, should bypass any side effects */ /obj/item/implant/proc/removed(mob/living/source, silent = FALSE, special = 0) moveToNullspace() diff --git a/code/game/objects/items/implants/implant_battle_royale.dm b/code/game/objects/items/implants/implant_battle_royale.dm new file mode 100644 index 00000000000..11f68ec9345 --- /dev/null +++ b/code/game/objects/items/implants/implant_battle_royale.dm @@ -0,0 +1,142 @@ + +/// Implant used by the traitor Battle Royale objective, is not active immediately +/obj/item/implant/explosive/battle_royale + name = "rumble royale implant" + actions_types = null + instant_explosion = FALSE + master_implant = TRUE + delay = 10 SECONDS + panic_beep_sound = TRUE + announce_activation = FALSE + /// Where is this going to tell us to go to avoid death? + var/target_area_name = "" + /// Is this implant active yet? + var/battle_started = FALSE + /// Are we enforcing a specific area yet? + var/area_limited = FALSE + /// Are we presently exploding? + var/has_exploded = FALSE + /// How likely are we to blow up if removed? + var/removed_explode_chance = 70 + /// Reference to our applied camera component + var/camera + /// We will explode if we're not in here after a set time + var/list/limited_areas = list() + +/obj/item/implant/explosive/battle_royale/get_data() + return "Implant Specifications:
\ + Name: Donk Co. 'Rumble Royale' Contestant Motivation Implant
\ + Life: Activates upon death, or expiry of an internal timer.
\ + Important Notes: Explodes.
\ +
\ + Implant Details:
\ + Function: Contains a compact, electrically detonated explosive that detonates upon receiving a specially encoded signal or upon host death. \ + Upon triggering the timer, the implant will begin to broadcast the surrounding area for the purposes of televised entertainment. This signal can be detected by GPS trackers.
\ + Special Features: Exploding.
" + +/obj/item/implant/explosive/battle_royale/on_death(datum/source, gibbed) + if (!battle_started) + return + return ..() + +/obj/item/implant/explosive/battle_royale/implant(mob/living/target, mob/user, silent, force) + . = ..() + if (!.) + return + RegisterSignal(target, COMSIG_LIVING_LIFE, PROC_REF(on_life)) + if (!battle_started) + return + name = "[name] - [imp_in.real_name]" + camera = target.AddComponent( \ + /datum/component/simple_bodycam, \ + camera_name = "rumble royale tracker", \ + c_tag = "Competitor [target.real_name]", \ + network = BATTLE_ROYALE_CAMERA_NET, \ + emp_proof = TRUE, \ + ) + announce() + if (area_limited) + limit_areas() + +/obj/item/implant/explosive/battle_royale/removed(mob/target, silent, special) + . = ..() + UnregisterSignal(target, list(COMSIG_LIVING_LIFE, COMSIG_ENTER_AREA)) + QDEL_NULL(camera) + if (has_exploded || QDELETED(src)) + return + if (!special && prob(removed_explode_chance)) + target.visible_message(span_boldwarning("[src] beeps ominously.")) + playsound(loc, 'sound/items/timer.ogg', 50, vary = FALSE) + explode(target) + target?.mind?.remove_antag_datum(/datum/antagonist/survivalist/battle_royale) + +/obj/item/implant/explosive/battle_royale/emp_act(severity) + removed_explode_chance = rand(0, 100) + return ..() + +/obj/item/implant/explosive/battle_royale/explode(atom/override_explode_target = null) + has_exploded = TRUE + return ..() + +/// Give a slight tell +/obj/item/implant/explosive/battle_royale/proc/on_life(mob/living/source) + SIGNAL_HANDLER + if (prob(98)) + return + if (!source.itch() || prob(80)) + return + to_chat(source, span_boldwarning("You feel a lump which shouldn't be there.")) + +/// Start the battle royale +/obj/item/implant/explosive/battle_royale/proc/start_battle(target_area_name, list/limited_areas) + if (isnull(imp_in)) + explode() + return + src.target_area_name = target_area_name + src.limited_areas = limited_areas + battle_started = TRUE + name = "[name] - [imp_in.real_name]" + imp_in.AddComponent( \ + /datum/component/simple_bodycam, \ + camera_name = "rumble royale tracker", \ + c_tag = "Competitor [imp_in.real_name]", \ + network = BATTLE_ROYALE_CAMERA_NET, \ + emp_proof = TRUE, \ + ) + AddComponent(/datum/component/gps, "Rumble Royale - [imp_in.real_name]") + playsound(loc, 'sound/items/timer.ogg', 50, vary = FALSE) + +/// Limit the owner to the specified area +/obj/item/implant/explosive/battle_royale/proc/limit_areas() + if (isnull(imp_in)) + explode() + return + area_limited = TRUE + RegisterSignal(imp_in, COMSIG_ENTER_AREA, PROC_REF(check_area)) + check_area(imp_in) + +/// Called when our implantee moves somewhere +/obj/item/implant/explosive/battle_royale/proc/check_area(mob/living/source) + SIGNAL_HANDLER + if (!length(limited_areas)) + return + if (is_type_in_list(get_area(source), limited_areas)) + return + playsound(imp_in, 'sound/items/timer.ogg', 50, vary = FALSE) + to_chat(imp_in, span_boldwarning("You are out of bounds! Get to the [target_area_name] quickly!")) + addtimer(CALLBACK(src, PROC_REF(check_area_deadly)), 5 SECONDS, TIMER_DELETE_ME) + +/// After a grace period they're still out of bounds, killing time +/obj/item/implant/explosive/battle_royale/proc/check_area_deadly() + if (isnull(imp_in) || has_exploded) + return + var/area/our_area = get_area(imp_in) + if (is_type_in_list(our_area, limited_areas)) + return + log_combat(src, imp_in, "exploded due to out of bounds", addition = "target area was [target_area_name], area was [our_area]") + explode() + +/// Add the antag datum to our new contestant, also printing some flavour text +/obj/item/implant/explosive/battle_royale/proc/announce() + var/datum/antagonist/survivalist/battle_royale/royale = imp_in.mind?.add_antag_datum(/datum/antagonist/survivalist/battle_royale) + royale?.set_target_area(target_area_name) diff --git a/code/game/objects/items/implants/implant_explosive.dm b/code/game/objects/items/implants/implant_explosive.dm index 51564799f6e..687b8db014e 100644 --- a/code/game/objects/items/implants/implant_explosive.dm +++ b/code/game/objects/items/implants/implant_explosive.dm @@ -37,6 +37,8 @@ var/master_implant = FALSE ///Will this implant notify ghosts when activated? var/notify_ghosts = TRUE + ///Do we tell people when they activated it? + var/announce_activation = TRUE /obj/item/implant/explosive/proc/on_death(datum/source, gibbed) SIGNAL_HANDLER @@ -71,7 +73,8 @@ return FALSE if(cause == "death" && HAS_TRAIT(imp_in, TRAIT_PREVENT_IMPLANT_AUTO_EXPLOSION)) return FALSE - to_chat(imp_in, span_notice("You activate your [name].")) + if(announce_activation) + to_chat(imp_in, span_notice("You activate your [name].")) active = TRUE var/turf/boomturf = get_turf(imp_in) message_admins("[ADMIN_LOOKUPFLW(imp_in)] has activated their [name] at [ADMIN_VERBOSEJMP(boomturf)], with cause of [cause].") @@ -86,7 +89,7 @@ if(istype(target_implant, /obj/item/implant/explosive)) //we don't use our own type here, because macrobombs inherit this proc and need to be able to upgrade microbombs var/obj/item/implant/explosive/other_implant = target_implant if(other_implant.master_implant && master_implant) //we cant have two master implants at once - target.balloon_alert(target, "cannot fit implant!") + target.balloon_alert(user, "cannot fit implant!") return FALSE if(master_implant) merge_implants(src, other_implant) @@ -120,17 +123,19 @@ * Make the implantee beep a few times, keel over and explode. Usually to a devastating effect. */ /obj/item/implant/explosive/proc/timed_explosion() - imp_in.visible_message(span_warning("[imp_in] starts beeping ominously!")) - - if(notify_ghosts) - notify_ghosts( - "[imp_in] is about to detonate their explosive implant!", - source = src, - header = "Tick Tick Tick...", - notify_flags = NOTIFY_CATEGORY_NOFLASH, - ghost_sound = 'sound/machines/warning-buzzer.ogg', - notify_volume = 75, - ) + if (isnull(imp_in)) + visible_message(span_warning("[src] starts beeping ominously!")) + else + imp_in.visible_message(span_warning("[imp_in] starts beeping ominously!")) + if(notify_ghosts) + notify_ghosts( + "[imp_in] is about to detonate their explosive implant!", + source = src, + header = "Tick Tick Tick...", + notify_flags = NOTIFY_CATEGORY_NOFLASH, + ghost_sound = 'sound/machines/warning-buzzer.ogg', + notify_volume = 75, + ) playsound(loc, 'sound/items/timer.ogg', 30, FALSE) if(!panic_beep_sound) @@ -160,14 +165,15 @@ ///When called, just explodes -/obj/item/implant/explosive/proc/explode() +/obj/item/implant/explosive/proc/explode(atom/override_explode_target = null) explosion_devastate = round(explosion_devastate) explosion_heavy = round(explosion_heavy) explosion_light = round(explosion_light) - explosion(src, devastation_range = explosion_devastate, heavy_impact_range = explosion_heavy, light_impact_range = explosion_light, flame_range = explosion_light, flash_range = explosion_light, explosion_cause = src) - if(imp_in) - imp_in.investigate_log("has been gibbed by an explosive implant.", INVESTIGATE_DEATHS) - imp_in.gib(DROP_ORGANS|DROP_BODYPARTS) + explosion(override_explode_target || src, devastation_range = explosion_devastate, heavy_impact_range = explosion_heavy, light_impact_range = explosion_light, flame_range = explosion_light, flash_range = explosion_light, explosion_cause = src) + var/mob/living/kill_mob = isliving(override_explode_target) ? override_explode_target : imp_in + if(!isnull(kill_mob)) + kill_mob.investigate_log("has been gibbed by an explosive implant.", INVESTIGATE_DEATHS) + kill_mob.gib(DROP_ORGANS|DROP_BODYPARTS) qdel(src) ///Macrobomb has the strength and delay of 10 microbombs diff --git a/code/game/objects/items/piggy_bank.dm b/code/game/objects/items/piggy_bank.dm index 8d50e8a39e8..b6294dbc4dd 100644 --- a/code/game/objects/items/piggy_bank.dm +++ b/code/game/objects/items/piggy_bank.dm @@ -63,7 +63,7 @@ persistence_cb = null return ..() -/obj/item/piggy_bank/deconstruct(disassembled = TRUE) +/obj/item/piggy_bank/atom_deconstruct(disassembled = TRUE) for(var/obj/item/thing as anything in contents) thing.forceMove(loc) //Smashing the piggy after the round is over doesn't count. diff --git a/code/game/objects/items/rcd/RCD.dm b/code/game/objects/items/rcd/RCD.dm index 1e0ea79119b..91b51053b0e 100644 --- a/code/game/objects/items/rcd/RCD.dm +++ b/code/game/objects/items/rcd/RCD.dm @@ -203,6 +203,11 @@ * * [mob][user]- the user building this structure */ /obj/item/construction/rcd/proc/rcd_create(atom/target, mob/user) + //straight up cant touch this + if(mode == RCD_DECONSTRUCT && (target.resistance_flags & INDESTRUCTIBLE)) + balloon_alert(user, "too durable!") + return + //does this atom allow for rcd actions? var/list/rcd_results = target.rcd_vals(user, src) if(!rcd_results) diff --git a/code/game/objects/items/storage/boxes/clothes_boxes.dm b/code/game/objects/items/storage/boxes/clothes_boxes.dm index d4d32e974c7..6b4e995a276 100644 --- a/code/game/objects/items/storage/boxes/clothes_boxes.dm +++ b/code/game/objects/items/storage/boxes/clothes_boxes.dm @@ -47,6 +47,15 @@ new /obj/item/clothing/head/syndicatefake(src) new /obj/item/clothing/suit/syndicatefake(src) +/obj/item/storage/box/syndie_kit/battle_royale + name = "rumble royale broadcast kit" + desc = "Contains everything you need to host the galaxy's greatest show; Rumble Royale." + +/obj/item/storage/box/syndie_kit/battle_royale/PopulateContents() + var/obj/item/royale_implanter/implanter = new(src) + var/obj/item/royale_remote/remote = new(src) + remote.link_implanter(implanter) + /obj/item/storage/box/deputy name = "box of deputy armbands" desc = "To be issued to those authorized to act as deputy of security." diff --git a/code/game/objects/items/surgery_tray.dm b/code/game/objects/items/surgery_tray.dm index 1839245929e..48be955b2ed 100644 --- a/code/game/objects/items/surgery_tray.dm +++ b/code/game/objects/items/surgery_tray.dm @@ -176,12 +176,10 @@ for(var/atom/movable/tool as anything in contents) tool.forceMove(drop_point) -/obj/item/surgery_tray/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - dump_contents() - new /obj/item/stack/rods(drop_location(), 2) - new /obj/item/stack/sheet/mineral/silver(drop_location()) - return ..() +/obj/item/surgery_tray/atom_deconstruct(disassembled = TRUE) + dump_contents() + new /obj/item/stack/rods(drop_location(), 2) + new /obj/item/stack/sheet/mineral/silver(drop_location()) /obj/item/surgery_tray/deployed is_portable = FALSE diff --git a/code/game/objects/items/syndie_spraycan.dm b/code/game/objects/items/syndie_spraycan.dm index 02a576a2cb9..774219fa122 100644 --- a/code/game/objects/items/syndie_spraycan.dm +++ b/code/game/objects/items/syndie_spraycan.dm @@ -86,7 +86,7 @@ if(HAS_TRAIT(user, TRAIT_TAGGER)) wait_time *= 0.5 - if(!do_after(user, wait_time, target)) + if(!do_after(user, wait_time, target, hidden = TRUE)) user.balloon_alert(user, "interrupted!") drawing_rune = FALSE return FALSE diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm index e198f7d75d7..8772e2f41c9 100644 --- a/code/game/objects/items/tanks/tanks.dm +++ b/code/game/objects/items/tanks/tanks.dm @@ -174,7 +174,7 @@ if(tank_assembly) . += span_warning("There is some kind of device [EXAMINE_HINT("rigged")] to the tank!") -/obj/item/tank/deconstruct(disassembled = TRUE) +/obj/item/tank/atom_deconstruct(disassembled = TRUE) var/atom/location = loc if(location) location.assume_air(air_contents) diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 6c033dd74a1..4f22a5e256b 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -156,9 +156,48 @@ var/mob/living/buckled_mob = m buckled_mob.electrocute_act((clamp(round(strength * 1.25e-3), 10, 90) + rand(-5, 5)), src, flags = SHOCK_TESLA) -///the obj is deconstructed into pieces, whether through careful disassembly or when destroyed. +/** + * Custom behaviour per atom subtype on how they should deconstruct themselves + * Arguments + * + * * disassembled - TRUE means we cleanly took this atom apart using tools. FALSE means this was destroyed in a violent way + */ +/obj/proc/atom_deconstruct(disassembled = TRUE) + PROTECTED_PROC(TRUE) + + return + +/** + * The interminate proc between deconstruct() & atom_deconstruct(). By default this delegates deconstruction to + * atom_deconstruct if NO_DECONSTRUCTION is absent but subtypes can override this to handle NO_DECONSTRUCTION in their + * own unique way. Override this if for example you want to dump out important content like mobs from the + * atom before deconstruction regardless if NO_DECONSTRUCTION is present or not + * Arguments + * + * * disassembled - TRUE means we cleanly took this atom apart using tools. FALSE means this was destroyed in a violent way + */ +/obj/proc/handle_deconstruct(disassembled = TRUE) + SHOULD_CALL_PARENT(FALSE) + + if(!(obj_flags & NO_DECONSTRUCTION)) + atom_deconstruct(disassembled) + +/** + * The obj is deconstructed into pieces, whether through careful disassembly or when destroyed. + * Arguments + * + * * disassembled - TRUE means we cleanly took this atom apart using tools. FALSE means this was destroyed in a violent way + */ /obj/proc/deconstruct(disassembled = TRUE) + SHOULD_NOT_OVERRIDE(TRUE) + + //allow objects to deconstruct themselves + handle_deconstruct(disassembled) + + //inform objects we were deconstructed SEND_SIGNAL(src, COMSIG_OBJ_DECONSTRUCT, disassembled) + + //delete our self qdel(src) ///what happens when the obj's integrity reaches zero. diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 2b22ca8be05..d84fc46de43 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -367,8 +367,6 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) /// If we can unwrench this object; returns SUCCESSFUL_UNFASTEN and FAILED_UNFASTEN, which are both TRUE, or CANT_UNFASTEN, which isn't. /obj/proc/can_be_unfasten_wrench(mob/user, silent) - if(obj_flags & NO_DECONSTRUCTION) - return CANT_UNFASTEN if(!(isfloorturf(loc) || isindestructiblefloor(loc)) && !anchored) to_chat(user, span_warning("[src] needs to be on the floor to be secured!")) return FAILED_UNFASTEN diff --git a/code/game/objects/structures/ai_core.dm b/code/game/objects/structures/ai_core.dm index 530d76f22e0..6207a4031c1 100644 --- a/code/game/objects/structures/ai_core.dm +++ b/code/game/objects/structures/ai_core.dm @@ -380,7 +380,7 @@ icon_state = "ai-empty" return ..() -/obj/structure/ai_core/deconstruct(disassembled = TRUE) +/obj/structure/ai_core/atom_deconstruct(disassembled = TRUE) if(state >= GLASS_CORE) new /obj/item/stack/sheet/rglass(loc, 2) if(state >= CABLED_CORE) @@ -389,7 +389,6 @@ circuit.forceMove(loc) circuit = null new /obj/item/stack/sheet/plasteel(loc, 4) - qdel(src) /// Quick proc to call to see if the brainmob inside of us has suicided. Returns TRUE if we have, FALSE in any other scenario. /obj/structure/ai_core/proc/suicide_check() diff --git a/code/game/objects/structures/aliens.dm b/code/game/objects/structures/aliens.dm index 3b8b4dad83f..6d8e8ca701e 100644 --- a/code/game/objects/structures/aliens.dm +++ b/code/game/objects/structures/aliens.dm @@ -41,10 +41,8 @@ icon = 'icons/obj/fluff/general.dmi' icon_state = "gelmound" -/obj/structure/alien/gelpod/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/effect/mob_spawn/corpse/human/damaged(get_turf(src)) - qdel(src) +/obj/structure/alien/gelpod/atom_deconstruct(disassembled = TRUE) + new /obj/effect/mob_spawn/corpse/human/damaged(get_turf(src)) /* * Resin @@ -446,9 +444,8 @@ /obj/structure/alien/egg/atom_break(damage_flag) . = ..() - if(!(obj_flags & NO_DECONSTRUCTION)) - if(status != BURST) - Burst(kill=TRUE) + if(status != BURST) + Burst(kill=TRUE) /obj/structure/alien/egg/HasProximity(atom/movable/AM) if(status == GROWN) diff --git a/code/game/objects/structures/beds_chairs/alien_nest.dm b/code/game/objects/structures/beds_chairs/alien_nest.dm index 0a157dc98a1..1654cecff45 100644 --- a/code/game/objects/structures/beds_chairs/alien_nest.dm +++ b/code/game/objects/structures/beds_chairs/alien_nest.dm @@ -12,10 +12,18 @@ smoothing_groups = SMOOTH_GROUP_ALIEN_NEST canSmoothWith = SMOOTH_GROUP_ALIEN_NEST build_stack_type = null - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION elevation = 0 var/static/mutable_appearance/nest_overlay = mutable_appearance('icons/mob/nonhuman-player/alien.dmi', "nestoverlay", LYING_MOB_LAYER) +/obj/structure/bed/nest/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) + if(held_item?.tool_behaviour == TOOL_WRENCH) + return NONE + + return ..() + +/obj/structure/bed/nest/wrench_act_secondary(mob/living/user, obj/item/weapon) + return ITEM_INTERACT_BLOCKING + /obj/structure/bed/nest/user_unbuckle_mob(mob/living/buckled_mob, mob/living/user) if(has_buckled_mobs()) for(var/buck in buckled_mobs) //breaking a nest releases all the buckled mobs, because the nest isn't holding them down anymore diff --git a/code/game/objects/structures/beds_chairs/bed.dm b/code/game/objects/structures/beds_chairs/bed.dm index e2038cb623b..5c5fac60eaa 100644 --- a/code/game/objects/structures/beds_chairs/bed.dm +++ b/code/game/objects/structures/beds_chairs/bed.dm @@ -34,12 +34,11 @@ /obj/structure/bed/examine(mob/user) . = ..() - if(!(obj_flags & NO_DECONSTRUCTION)) - . += span_notice("It's held together by a couple of bolts.") + . += span_notice("It's held together by a couple of bolts.") /obj/structure/bed/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) if(held_item) - if(held_item.tool_behaviour != TOOL_WRENCH || obj_flags & NO_DECONSTRUCTION) + if(held_item.tool_behaviour != TOOL_WRENCH) return context[SCREENTIP_CONTEXT_RMB] = "Dismantle" @@ -49,19 +48,14 @@ context[SCREENTIP_CONTEXT_LMB] = "Unbuckle" return CONTEXTUAL_SCREENTIP_SET -/obj/structure/bed/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(build_stack_type) - new build_stack_type(loc, build_stack_amount) - ..() +/obj/structure/bed/atom_deconstruct(disassembled = TRUE) + if(build_stack_type) + new build_stack_type(loc, build_stack_amount) /obj/structure/bed/attack_paw(mob/user, list/modifiers) return attack_hand(user, modifiers) /obj/structure/bed/wrench_act_secondary(mob/living/user, obj/item/weapon) - if(obj_flags & NO_DECONSTRUCTION) - return TRUE - ..() weapon.play_tool_sound(src) deconstruct(disassembled = TRUE) diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index 2fe14ed1dd9..0808c306ddb 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -36,16 +36,12 @@ SSjob.latejoin_trackers -= src //These may be here due to the arrivals shuttle return ..() -/obj/structure/chair/deconstruct(disassembled) - // If we have materials, and don't have the NOCONSTRUCT flag - if(!(obj_flags & NO_DECONSTRUCTION)) - if(buildstacktype) - new buildstacktype(loc,buildstackamount) - else - for(var/i in custom_materials) - var/datum/material/M = i - new M.sheet_type(loc, FLOOR(custom_materials[M] / SHEET_MATERIAL_AMOUNT, 1)) - ..() +/obj/structure/chair/atom_deconstruct(disassembled) + if(buildstacktype) + new buildstacktype(loc,buildstackamount) + else + for(var/datum/material/mat as anything in custom_materials) + new mat.sheet_type(loc, FLOOR(custom_materials[mat] / SHEET_MATERIAL_AMOUNT, 1)) /obj/structure/chair/attack_paw(mob/user, list/modifiers) return attack_hand(user, modifiers) @@ -56,8 +52,6 @@ qdel(src) /obj/structure/chair/attackby(obj/item/W, mob/user, params) - if(obj_flags & NO_DECONSTRUCTION) - return . = ..() if(istype(W, /obj/item/assembly/shock_kit) && !HAS_TRAIT(src, TRAIT_ELECTRIFIED_BUCKLE)) electrify_self(W, user) return @@ -85,8 +79,6 @@ /obj/structure/chair/wrench_act_secondary(mob/living/user, obj/item/weapon) - if(obj_flags & NO_DECONSTRUCTION) - return TRUE ..() weapon.play_tool_sound(src) deconstruct(disassembled = TRUE) @@ -279,7 +271,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool, 0) /obj/structure/chair/MouseDrop(over_object, src_location, over_location) . = ..() if(over_object == usr && Adjacent(usr)) - if(!item_chair || has_buckled_mobs() || src.obj_flags & NO_DECONSTRUCTION) + if(!item_chair || has_buckled_mobs()) return if(!usr.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS)) return @@ -495,6 +487,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0) obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION alpha = 0 +/obj/structure/chair/mime/wrench_act_secondary(mob/living/user, obj/item/weapon) + return ITEM_INTERACT_BLOCKING + /obj/structure/chair/mime/post_buckle_mob(mob/living/M) M.pixel_y += 5 diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm index 50fcae8dec1..108ca3fe9b8 100644 --- a/code/game/objects/structures/bedsheet_bin.dm +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -609,8 +609,6 @@ LINEN BINS ..() /obj/structure/bedsheetbin/screwdriver_act(mob/living/user, obj/item/tool) - if(obj_flags & NO_DECONSTRUCTION) - return FALSE if(amount) to_chat(user, span_warning("The [src] must be empty first!")) return ITEM_INTERACT_SUCCESS diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index dc273bdc938..3eb29fc1526 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -581,25 +581,23 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) else return open(user) -/obj/structure/closet/deconstruct(disassembled = TRUE) - if (!(obj_flags & NO_DECONSTRUCTION)) - if(ispath(material_drop) && material_drop_amount) - new material_drop(loc, material_drop_amount) - if (secure) - var/obj/item/electronics/airlock/electronics = new(drop_location()) - if(length(req_one_access)) - electronics.one_access = TRUE - electronics.accesses = req_one_access - else - electronics.accesses = req_access - if(card_reader_installed) - new /obj/item/stock_parts/card_reader(drop_location()) +/obj/structure/closet/atom_deconstruct(disassembled = TRUE) + if(ispath(material_drop) && material_drop_amount) + new material_drop(loc, material_drop_amount) + if (secure) + var/obj/item/electronics/airlock/electronics = new(drop_location()) + if(length(req_one_access)) + electronics.one_access = TRUE + electronics.accesses = req_one_access + else + electronics.accesses = req_access + if(card_reader_installed) + new /obj/item/stock_parts/card_reader(drop_location()) dump_contents() - qdel(src) /obj/structure/closet/atom_break(damage_flag) . = ..() - if(!broken && !(obj_flags & NO_DECONSTRUCTION)) + if(!broken) bust_open() /obj/structure/closet/CheckParts(list/parts_list) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm index 1ac7e65884e..1e19671a455 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm @@ -36,10 +36,8 @@ flags_1 &= ~PREVENT_CONTENTS_EXPLOSION_1 return FALSE -/obj/structure/closet/secure_closet/freezer/deconstruct(disassembled) - if (!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/assembly/igniter/condenser(drop_location()) - . = ..() +/obj/structure/closet/secure_closet/freezer/atom_deconstruct(disassembled) + new /obj/item/assembly/igniter/condenser(drop_location()) /obj/structure/closet/secure_closet/freezer/empty name = "freezer" diff --git a/code/game/objects/structures/destructible_structures.dm b/code/game/objects/structures/destructible_structures.dm index f33c99b681a..beffa5d4fd7 100644 --- a/code/game/objects/structures/destructible_structures.dm +++ b/code/game/objects/structures/destructible_structures.dm @@ -4,16 +4,13 @@ var/break_sound = 'sound/magic/clockwork/invoke_general.ogg' //The sound played when a structure breaks var/list/debris = null //Parts left behind when a structure breaks, takes the form of list(path = amount_to_spawn) -/obj/structure/destructible/deconstruct(disassembled = TRUE) +/obj/structure/destructible/atom_deconstruct(disassembled = TRUE) if(!disassembled) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(islist(debris)) - for(var/I in debris) - for(var/i in 1 to debris[I]) - new I (get_turf(src)) - if(break_message) - visible_message(break_message) - if(break_sound) - playsound(src, break_sound, 50, TRUE) - qdel(src) - return 1 + if(islist(debris)) + for(var/I in debris) + for(var/i in 1 to debris[I]) + new I (get_turf(src)) + if(break_message) + visible_message(break_message) + if(break_sound) + playsound(src, break_sound, 50, TRUE) diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm index 7d2eb6e7c20..ae7cd5654ba 100644 --- a/code/game/objects/structures/displaycase.dm +++ b/code/game/objects/structures/displaycase.dm @@ -81,17 +81,15 @@ if(BURN) playsound(src, 'sound/items/welder.ogg', 100, TRUE) -/obj/structure/displaycase/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - dump() - if(!disassembled) - new /obj/item/shard(drop_location()) - trigger_alarm() - qdel(src) +/obj/structure/displaycase/atom_deconstruct(disassembled = TRUE) + dump() + if(!disassembled) + new /obj/item/shard(drop_location()) + trigger_alarm() /obj/structure/displaycase/atom_break(damage_flag) . = ..() - if(!broken && !(obj_flags & NO_DECONSTRUCTION)) + if(!broken) set_density(FALSE) broken = TRUE new /obj/item/shard(drop_location()) @@ -673,7 +671,7 @@ /obj/structure/displaycase/forsale/atom_break(damage_flag) . = ..() - if(!broken && !(obj_flags & NO_DECONSTRUCTION)) + if(!broken) broken = TRUE playsound(src, SFX_SHATTER, 70, TRUE) update_appearance() diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index 1206dada21e..f75a8b9ce72 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -363,25 +363,22 @@ target.update_name() qdel(source) -/obj/structure/door_assembly/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/turf/T = get_turf(src) - if(!disassembled) - material_amt = rand(2,4) - new material_type(T, material_amt) - if(glass) - if(disassembled) - if(heat_proof_finished) - new /obj/item/stack/sheet/rglass(T) - else - new /obj/item/stack/sheet/glass(T) +/obj/structure/door_assembly/atom_deconstruct(disassembled = TRUE) + var/turf/target_turf = get_turf(src) + if(!disassembled) + material_amt = rand(2,4) + new material_type(target_turf, material_amt) + if(glass) + if(disassembled) + if(heat_proof_finished) + new /obj/item/stack/sheet/rglass(target_turf) else - new /obj/item/shard(T) - if(mineral) - var/obj/item/stack/sheet/mineral/mineral_path = text2path("/obj/item/stack/sheet/mineral/[mineral]") - new mineral_path(T, 2) - qdel(src) - + new /obj/item/stack/sheet/glass(target_turf) + else + new /obj/item/shard(target_turf) + if(mineral) + var/obj/item/stack/sheet/mineral/mineral_path = text2path("/obj/item/stack/sheet/mineral/[mineral]") + new mineral_path(target_turf, 2) /obj/structure/door_assembly/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) if(the_rcd.mode == RCD_DECONSTRUCT) diff --git a/code/game/objects/structures/door_assembly_types.dm b/code/game/objects/structures/door_assembly_types.dm index 589cad42bca..dd06f7e42a9 100644 --- a/code/game/objects/structures/door_assembly_types.dm +++ b/code/game/objects/structures/door_assembly_types.dm @@ -271,24 +271,21 @@ name = "large public airlock assembly" base_name = "large public airlock" -/obj/structure/door_assembly/door_assembly_material/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/turf/T = get_turf(src) - for(var/material in custom_materials) - var/datum/material/material_datum = material - var/material_count = FLOOR(custom_materials[material_datum] / SHEET_MATERIAL_AMOUNT, 1) - if(!disassembled) - material_count = rand(FLOOR(material_count/2, 1), material_count) - new material_datum.sheet_type(T, material_count) - if(glass) - if(disassembled) - if(heat_proof_finished) - new /obj/item/stack/sheet/rglass(T) - else - new /obj/item/stack/sheet/glass(T) +/obj/structure/door_assembly/door_assembly_material/atom_deconstruct(disassembled = TRUE) + var/turf/target_turf = get_turf(src) + for(var/datum/material/material_datum as anything in custom_materials) + var/material_count = FLOOR(custom_materials[material_datum] / SHEET_MATERIAL_AMOUNT, 1) + if(!disassembled) + material_count = rand(FLOOR(material_count/2, 1), material_count) + new material_datum.sheet_type(target_turf, material_count) + if(glass) + if(disassembled) + if(heat_proof_finished) + new /obj/item/stack/sheet/rglass(target_turf) else - new /obj/item/shard(T) - qdel(src) + new /obj/item/stack/sheet/glass(target_turf) + else + new /obj/item/shard(target_turf) /obj/structure/door_assembly/door_assembly_material/finish_door() var/obj/machinery/door/airlock/door = ..() diff --git a/code/game/objects/structures/dresser.dm b/code/game/objects/structures/dresser.dm index 9232a992a5b..18332de296d 100644 --- a/code/game/objects/structures/dresser.dm +++ b/code/game/objects/structures/dresser.dm @@ -18,10 +18,8 @@ else return ..() -/obj/structure/dresser/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/mineral/wood(drop_location(), 10) - qdel(src) +/obj/structure/dresser/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/mineral/wood(drop_location(), 10) /obj/structure/dresser/attack_hand(mob/user, list/modifiers) . = ..() diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm index f8780a28d50..f218f4d77f7 100644 --- a/code/game/objects/structures/extinguisher.dm +++ b/code/game/objects/structures/extinguisher.dm @@ -164,7 +164,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/extinguisher_cabinet, 29) /obj/structure/extinguisher_cabinet/atom_break(damage_flag) . = ..() - if(!broken && !(obj_flags & NO_DECONSTRUCTION)) + if(!broken) broken = 1 opened = 1 if(stored_extinguisher) @@ -173,16 +173,14 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/extinguisher_cabinet, 29) update_appearance(UPDATE_ICON) -/obj/structure/extinguisher_cabinet/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - new /obj/item/wallframe/extinguisher_cabinet(loc) - else - new /obj/item/stack/sheet/iron (loc, 2) - if(stored_extinguisher) - stored_extinguisher.forceMove(loc) - stored_extinguisher = null - qdel(src) +/obj/structure/extinguisher_cabinet/atom_deconstruct(disassembled = TRUE) + if(disassembled) + new /obj/item/wallframe/extinguisher_cabinet(loc) + else + new /obj/item/stack/sheet/iron (loc, 2) + if(stored_extinguisher) + stored_extinguisher.forceMove(loc) + stored_extinguisher = null /obj/item/wallframe/extinguisher_cabinet name = "extinguisher cabinet frame" diff --git a/code/game/objects/structures/false_walls.dm b/code/game/objects/structures/false_walls.dm index bdb6ba08525..e9f9eb5d11e 100644 --- a/code/game/objects/structures/false_walls.dm +++ b/code/game/objects/structures/false_walls.dm @@ -133,14 +133,12 @@ playsound(src, 'sound/items/welder.ogg', 100, TRUE) deconstruct(disassembled) -/obj/structure/falsewall/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - new girder_type(loc) - if(mineral_amount) - for(var/i in 1 to mineral_amount) - new mineral(loc) - qdel(src) +/obj/structure/falsewall/atom_deconstruct(disassembled = TRUE) + if(disassembled) + new girder_type(loc) + if(mineral_amount) + for(var/i in 1 to mineral_amount) + new mineral(loc) /obj/structure/falsewall/get_dumping_location() return null @@ -387,14 +385,12 @@ canSmoothWith = SMOOTH_GROUP_MATERIAL_WALLS material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS -/obj/structure/falsewall/material/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - new girder_type(loc) - for(var/material in custom_materials) - var/datum/material/material_datum = material - new material_datum.sheet_type(loc, FLOOR(custom_materials[material_datum] / SHEET_MATERIAL_AMOUNT, 1)) - qdel(src) +/obj/structure/falsewall/material/atom_deconstruct(disassembled = TRUE) + if(disassembled) + new girder_type(loc) + for(var/material in custom_materials) + var/datum/material/material_datum = material + new material_datum.sheet_type(loc, FLOOR(custom_materials[material_datum] / SHEET_MATERIAL_AMOUNT, 1)) /obj/structure/falsewall/material/mat_update_desc(mat) desc = "A huge chunk of [mat] used to separate rooms." diff --git a/code/game/objects/structures/fans.dm b/code/game/objects/structures/fans.dm index 924da72ee30..4f0a5fc450b 100644 --- a/code/game/objects/structures/fans.dm +++ b/code/game/objects/structures/fans.dm @@ -10,21 +10,15 @@ var/buildstackamount = 5 can_atmos_pass = ATMOS_PASS_NO -/obj/structure/fans/deconstruct() - if(!(obj_flags & NO_DECONSTRUCTION)) - if(buildstacktype) - new buildstacktype(loc,buildstackamount) - qdel(src) +/obj/structure/fans/atom_deconstruct(disassembled = TRUE) + if(buildstacktype) + new buildstacktype(loc,buildstackamount) /obj/structure/fans/wrench_act(mob/living/user, obj/item/I) - ..() - if(obj_flags & NO_DECONSTRUCTION) - return TRUE - user.visible_message(span_warning("[user] disassembles [src]."), span_notice("You start to disassemble [src]..."), span_hear("You hear clanking and banging noises.")) if(I.use_tool(src, user, 20, volume=50)) - deconstruct() + deconstruct(TRUE) return TRUE /obj/structure/fans/tiny diff --git a/code/game/objects/structures/fireaxe.dm b/code/game/objects/structures/fireaxe.dm index ab7d410f096..ab69b7bc7a4 100644 --- a/code/game/objects/structures/fireaxe.dm +++ b/code/game/objects/structures/fireaxe.dm @@ -108,19 +108,17 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/fireaxecabinet, 32) /obj/structure/fireaxecabinet/atom_break(damage_flag) . = ..() - if(!broken && !(obj_flags & NO_DECONSTRUCTION)) + if(!broken) update_appearance() broken = TRUE playsound(src, 'sound/effects/glassbr3.ogg', 100, TRUE) new /obj/item/shard(loc) new /obj/item/shard(loc) -/obj/structure/fireaxecabinet/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(held_item && loc) - held_item.forceMove(loc) - new /obj/item/wallframe/fireaxecabinet(loc) - qdel(src) +/obj/structure/fireaxecabinet/atom_deconstruct(disassembled = TRUE) + if(held_item && loc) + held_item.forceMove(loc) + new /obj/item/wallframe/fireaxecabinet(loc) /obj/structure/fireaxecabinet/blob_act(obj/structure/blob/B) if(held_item) @@ -230,12 +228,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/fireaxecabinet/empty, 32) MAPPING_DIRECTIONAL_HELPERS(/obj/structure/fireaxecabinet/mechremoval, 32) -/obj/structure/fireaxecabinet/mechremoval/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(held_item && loc) - held_item.forceMove(loc) - new /obj/item/wallframe/fireaxecabinet/mechremoval(loc) - qdel(src) +/obj/structure/fireaxecabinet/mechremoval/atom_deconstruct(disassembled = TRUE) + if(held_item && loc) + held_item.forceMove(loc) + new /obj/item/wallframe/fireaxecabinet/mechremoval(loc) /obj/structure/fireaxecabinet/mechremoval/empty populate_contents = FALSE diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm index e7060a145e9..8749691c91d 100644 --- a/code/game/objects/structures/flora.dm +++ b/code/game/objects/structures/flora.dm @@ -263,13 +263,11 @@ var/matrix/M = matrix(transform) transform = M.Turn(-previous_rotation) -/obj/structure/flora/deconstruct() - if(!(obj_flags & NO_DECONSTRUCTION)) - if(harvested) - return ..() +/obj/structure/flora/atom_deconstruct(disassembled = TRUE) + if(harvested) + return ..() - harvest(product_amount_multiplier = 0.6) - . = ..() + harvest(product_amount_multiplier = 0.6) /********* * Trees * diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index bbd4824b327..a1cb0f82696 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -383,11 +383,9 @@ return TRUE return FALSE -/obj/structure/girder/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/remains = pick(/obj/item/stack/rods, /obj/item/stack/sheet/iron) - new remains(loc) - qdel(src) +/obj/structure/girder/atom_deconstruct(disassembled = TRUE) + var/remains = pick(/obj/item/stack/rods, /obj/item/stack/sheet/iron) + new remains(loc) /obj/structure/girder/narsie_act() new /obj/structure/girder/cult(loc) @@ -460,10 +458,8 @@ /obj/structure/girder/cult/narsie_act() return -/obj/structure/girder/cult/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/runed_metal(drop_location(), 1) - qdel(src) +/obj/structure/girder/cult/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/runed_metal(drop_location(), 1) /obj/structure/girder/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) switch(the_rcd.mode) diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index da023942518..a25dfaada50 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -52,8 +52,6 @@ /obj/structure/grille/examine(mob/user) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return if(anchored) . += span_notice("It's secured in place with screws. The rods look like they could be cut through.") @@ -200,10 +198,8 @@ add_fingerprint(user) if(shock(user, 100)) return - if(obj_flags & NO_DECONSTRUCTION) - return FALSE tool.play_tool_sound(src, 100) - deconstruct() + deconstruct(TRUE) return ITEM_INTERACT_SUCCESS /obj/structure/grille/screwdriver_act(mob/living/user, obj/item/tool) @@ -212,8 +208,6 @@ add_fingerprint(user) if(shock(user, 90)) return FALSE - if(obj_flags & NO_DECONSTRUCTION) - return FALSE if(!tool.use_tool(src, user, 0, volume=100)) return FALSE set_anchored(!anchored) @@ -296,18 +290,13 @@ playsound(src, 'sound/items/welder.ogg', 80, TRUE) -/obj/structure/grille/deconstruct(disassembled = TRUE) - if(!loc) //if already qdel'd somehow, we do nothing - return - if(!(obj_flags & NO_DECONSTRUCTION)) - var/obj/R = new rods_type(drop_location(), rods_amount) - transfer_fingerprints_to(R) - qdel(src) - ..() +/obj/structure/grille/atom_deconstruct(disassembled = TRUE) + var/obj/rods = new rods_type(drop_location(), rods_amount) + transfer_fingerprints_to(rods) /obj/structure/grille/atom_break() . = ..() - if(!broken && !(obj_flags & NO_DECONSTRUCTION)) + if(!broken) icon_state = "brokengrille" set_density(FALSE) atom_integrity = 20 diff --git a/code/game/objects/structures/headpike.dm b/code/game/objects/structures/headpike.dm index b48cafc85d9..0c29d92d53b 100644 --- a/code/game/objects/structures/headpike.dm +++ b/code/game/objects/structures/headpike.dm @@ -64,7 +64,7 @@ if(!QDELETED(src)) deconstruct(TRUE) -/obj/structure/headpike/deconstruct(disassembled) +/obj/structure/headpike/atom_deconstruct(disassembled) var/obj/item/bodypart/head/our_head = victim var/obj/item/spear/our_spear = spear victim = null @@ -73,7 +73,6 @@ if(!disassembled) return ..() our_spear?.forceMove(drop_location()) - return ..() /obj/structure/headpike/attack_hand(mob/user, list/modifiers) . = ..() diff --git a/code/game/objects/structures/icemoon/cave_entrance.dm b/code/game/objects/structures/icemoon/cave_entrance.dm index 20f14844c12..4401b87d23e 100644 --- a/code/game/objects/structures/icemoon/cave_entrance.dm +++ b/code/game/objects/structures/icemoon/cave_entrance.dm @@ -40,10 +40,9 @@ GLOBAL_LIST_INIT(ore_probability, list( var/turf/closed/mineral/clearable = potential clearable.ScrapeAway(flags = CHANGETURF_IGNORE_AIR) -/obj/structure/spawner/ice_moon/deconstruct(disassembled) +/obj/structure/spawner/ice_moon/atom_deconstruct(disassembled) destroy_effect() drop_loot() - return ..() /** * Effects and messages created when the spawner is destroyed diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm index fd4daaeaa18..039735dc36f 100644 --- a/code/game/objects/structures/kitchen_spike.dm +++ b/code/game/objects/structures/kitchen_spike.dm @@ -159,13 +159,12 @@ buckled_mob.pixel_y = buckled_mob.base_pixel_y + PIXEL_Y_OFFSET_LYING REMOVE_TRAIT(buckled_mob, TRAIT_MOVE_UPSIDE_DOWN, REF(src)) -/obj/structure/kitchenspike/deconstruct(disassembled = TRUE) +/obj/structure/kitchenspike/atom_deconstruct(disassembled = TRUE) if(disassembled) var/obj/structure/meatspike_frame = new /obj/structure/kitchenspike_frame(src.loc) transfer_fingerprints_to(meatspike_frame) else new /obj/item/stack/sheet/iron(src.loc, 4) new /obj/item/stack/rods(loc, MEATSPIKE_IRONROD_REQUIREMENT) - qdel(src) #undef MEATSPIKE_IRONROD_REQUIREMENT diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm index 72f28ed8251..6d65705586a 100644 --- a/code/game/objects/structures/lattice.dm +++ b/code/game/objects/structures/lattice.dm @@ -57,10 +57,8 @@ var/turf/T = get_turf(src) return T.attackby(C, user) //hand this off to the turf instead (for building plating, catwalks, etc) -/obj/structure/lattice/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new build_material(get_turf(src), number_of_mats) - qdel(src) +/obj/structure/lattice/atom_deconstruct(disassembled = TRUE) + new build_material(get_turf(src), number_of_mats) /obj/structure/lattice/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) if(the_rcd.mode == RCD_TURF) @@ -113,11 +111,10 @@ C.deconstruct() ..() -/obj/structure/lattice/catwalk/deconstruct() +/obj/structure/lattice/catwalk/atom_deconstruct(disassembled = TRUE) var/turf/T = loc for(var/obj/structure/cable/C in T) C.deconstruct() - ..() /obj/structure/lattice/catwalk/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) if(the_rcd.mode == RCD_DECONSTRUCT) diff --git a/code/game/objects/structures/lavaland/necropolis_tendril.dm b/code/game/objects/structures/lavaland/necropolis_tendril.dm index 803a4aeac58..58308b9b9cf 100644 --- a/code/game/objects/structures/lavaland/necropolis_tendril.dm +++ b/code/game/objects/structures/lavaland/necropolis_tendril.dm @@ -42,9 +42,8 @@ GLOBAL_LIST_INIT(tendrils, list()) AddComponent(/datum/component/gps, "Eerie Signal") GLOB.tendrils += src -/obj/structure/spawner/lavaland/deconstruct(disassembled) +/obj/structure/spawner/lavaland/atom_deconstruct(disassembled) new /obj/effect/collapse(loc) - return ..() /obj/structure/spawner/lavaland/examine(mob/user) var/list/examine_messages = ..() diff --git a/code/game/objects/structures/maintenance.dm b/code/game/objects/structures/maintenance.dm index f9ed6d93c1e..ecd6f54d255 100644 --- a/code/game/objects/structures/maintenance.dm +++ b/code/game/objects/structures/maintenance.dm @@ -303,11 +303,9 @@ at the cost of risking a vicious bite.**/ deconstruct() return TRUE -/obj/structure/steam_vent/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/iron(loc, 1) - new /obj/item/stock_parts/water_recycler(loc, 1) - qdel(src) +/obj/structure/steam_vent/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/iron(loc, 1) + new /obj/item/stock_parts/water_recycler(loc, 1) /** * Creates "steam" smoke, and determines when the vent needs to block line of sight via reset_opacity. diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index 03e37346c57..d794f24dd08 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -204,14 +204,12 @@ /////////////////////// END TOOL OVERRIDES /////////////////////// -/obj/structure/mineral_door/deconstruct(disassembled = TRUE) +/obj/structure/mineral_door/atom_deconstruct(disassembled = TRUE) var/turf/T = get_turf(src) if(disassembled) new sheetType(T, sheetAmount) else new sheetType(T, max(sheetAmount - 2, 1)) - qdel(src) - /obj/structure/mineral_door/iron name = "iron door" diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index bbe56b68c16..21452c0895d 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -260,7 +260,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) /obj/structure/mirror/atom_break(damage_flag, mapload) . = ..() - if(broken || (obj_flags & NO_DECONSTRUCTION)) + if(broken) return icon_state = "mirror_broke" if(!mapload) @@ -269,13 +269,11 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) desc = "Oh no, seven years of bad luck!" broken = TRUE -/obj/structure/mirror/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(!disassembled) - new /obj/item/shard(loc) - else - new /obj/item/wallframe/mirror(loc) - qdel(src) +/obj/structure/mirror/atom_deconstruct(disassembled = TRUE) + if(!disassembled) + new /obj/item/shard(loc) + else + new /obj/item/wallframe/mirror(loc) /obj/structure/mirror/welder_act(mob/living/user, obj/item/I) ..() diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 500060850b7..feb5cdd2b31 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -104,10 +104,8 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an return return attack_hand(user) -/obj/structure/bodycontainer/deconstruct(disassembled = TRUE) - if (!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/iron(loc, 5) - qdel(src) +/obj/structure/bodycontainer/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/iron(loc, 5) /obj/structure/bodycontainer/container_resist_act(mob/living/user) if(!locked) @@ -477,9 +475,8 @@ GLOBAL_LIST_EMPTY(crematoriums) connected = null return ..() -/obj/structure/tray/deconstruct(disassembled = TRUE) +/obj/structure/tray/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/iron (loc, 2) - qdel(src) /obj/structure/tray/attack_paw(mob/user, list/modifiers) return attack_hand(user, modifiers) diff --git a/code/game/objects/structures/noticeboard.dm b/code/game/objects/structures/noticeboard.dm index c737f21e6d9..841da899725 100644 --- a/code/game/objects/structures/noticeboard.dm +++ b/code/game/objects/structures/noticeboard.dm @@ -110,15 +110,13 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/noticeboard, 32) notices-- update_appearance(UPDATE_ICON) -/obj/structure/noticeboard/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(!disassembled) - new /obj/item/stack/sheet/mineral/wood(loc) - else - new /obj/item/wallframe/noticeboard(loc) +/obj/structure/noticeboard/atom_deconstruct(disassembled = TRUE) + if(!disassembled) + new /obj/item/stack/sheet/mineral/wood(loc) + else + new /obj/item/wallframe/noticeboard(loc) for(var/obj/item/content in contents) remove_item(content) - qdel(src) /obj/item/wallframe/noticeboard name = "notice board" diff --git a/code/game/objects/structures/petrified_statue.dm b/code/game/objects/structures/petrified_statue.dm index a752faba40c..5383436d4db 100644 --- a/code/game/objects/structures/petrified_statue.dm +++ b/code/game/objects/structures/petrified_statue.dm @@ -73,7 +73,7 @@ petrified_mob.forceMove(loc) return ..() -/obj/structure/statue/petrified/deconstruct(disassembled = TRUE) +/obj/structure/statue/petrified/atom_deconstruct(disassembled = TRUE) var/destruction_message = "[src] shatters!" if(!disassembled) if(petrified_mob) @@ -89,7 +89,6 @@ destruction_message = "[src] shatters, a solid brain tumbling out!" petrified_mob.dust() visible_message(span_danger(destruction_message)) - qdel(src) /obj/structure/statue/petrified/animate_atom_living(mob/living/owner) if(isnull(petrified_mob)) diff --git a/code/game/objects/structures/pinatas.dm b/code/game/objects/structures/pinatas.dm index 116de95c167..63502f12ad5 100644 --- a/code/game/objects/structures/pinatas.dm +++ b/code/game/objects/structures/pinatas.dm @@ -41,9 +41,8 @@ if(BURN) playsound(src, 'sound/items/welder.ogg', 100, TRUE) -/obj/structure/pinata/deconstruct(disassembled) +/obj/structure/pinata/atom_deconstruct(disassembled) new debris(get_turf(src)) - return ..() ///An item that when used inhand spawns an immovable pinata /obj/item/pinata @@ -72,7 +71,7 @@ base_icon_state = "pinata_syndie_placed" destruction_loot = 2 debris = /obj/effect/decal/cleanable/wrapping/pinata/syndie - candy_options = list( + candy_options = list( /obj/item/food/bubblegum, /obj/item/food/candy, /obj/item/food/chocolatebar, diff --git a/code/game/objects/structures/plasticflaps.dm b/code/game/objects/structures/plasticflaps.dm index f4834ecf48a..71890f72613 100644 --- a/code/game/objects/structures/plasticflaps.dm +++ b/code/game/objects/structures/plasticflaps.dm @@ -124,10 +124,8 @@ return FALSE //If you're not laying down, or a small creature, or a ventcrawler, then no pass. -/obj/structure/plasticflaps/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/plastic/five(loc) - qdel(src) +/obj/structure/plasticflaps/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/plastic/five(loc) /obj/structure/plasticflaps/Initialize(mapload) . = ..() diff --git a/code/game/objects/structures/railings.dm b/code/game/objects/structures/railings.dm index 3604bd06c63..95cf4fc58e5 100644 --- a/code/game/objects/structures/railings.dm +++ b/code/game/objects/structures/railings.dm @@ -98,19 +98,14 @@ deconstruct() return TRUE -/obj/structure/railing/deconstruct(disassembled) - if((obj_flags & NO_DECONSTRUCTION)) - return ..() +/obj/structure/railing/atom_deconstruct(disassembled) var/rods_to_make = istype(src,/obj/structure/railing/corner) ? 1 : 2 var/obj/rod = new item_deconstruct(drop_location(), rods_to_make) transfer_fingerprints_to(rod) - return ..() ///Implements behaviour that makes it possible to unanchor the railing. /obj/structure/railing/wrench_act(mob/living/user, obj/item/I) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return to_chat(user, span_notice("You begin to [anchored ? "unfasten the railing from":"fasten the railing to"] the floor...")) if(I.use_tool(src, user, volume = 75, extra_checks = CALLBACK(src, PROC_REF(check_anchored), anchored))) set_anchored(!anchored) diff --git a/code/game/objects/structures/secure_safe.dm b/code/game/objects/structures/secure_safe.dm index bc73eea6ec0..76c3ab4575f 100644 --- a/code/game/objects/structures/secure_safe.dm +++ b/code/game/objects/structures/secure_safe.dm @@ -45,12 +45,11 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/secure_safe, 32) if(mapload) PopulateContents() -/obj/structure/secure_safe/deconstruct(disassembled) +/obj/structure/secure_safe/atom_deconstruct(disassembled) if(!density) //if we're a wall item, we'll drop a wall frame. var/obj/item/wallframe/secure_safe/new_safe = new(get_turf(src)) for(var/obj/item in contents) item.forceMove(new_safe) - return ..() /obj/structure/secure_safe/proc/PopulateContents() new /obj/item/paper(src) diff --git a/code/game/objects/structures/shower.dm b/code/game/objects/structures/shower.dm index 245b9cc6cb3..298c6fd2294 100644 --- a/code/game/objects/structures/shower.dm +++ b/code/game/objects/structures/shower.dm @@ -191,9 +191,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/shower, (-16)) /obj/machinery/shower/wrench_act(mob/living/user, obj/item/I) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return - I.play_tool_sound(src) deconstruct() return TRUE diff --git a/code/game/objects/structures/stairs.dm b/code/game/objects/structures/stairs.dm index 169f76a4b57..a26354211dc 100644 --- a/code/game/objects/structures/stairs.dm +++ b/code/game/objects/structures/stairs.dm @@ -209,9 +209,8 @@ deconstruct(TRUE) return TRUE -/obj/structure/stairs_frame/deconstruct(disassembled = TRUE) +/obj/structure/stairs_frame/atom_deconstruct(disassembled = TRUE) new frame_stack(get_turf(src), frame_stack_amount) - qdel(src) /obj/structure/stairs_frame/attackby(obj/item/attacked_by, mob/user, params) if(!isstack(attacked_by)) diff --git a/code/game/objects/structures/syndicate_uplink_beacon.dm b/code/game/objects/structures/syndicate_uplink_beacon.dm index f4d4ea6fe64..2106fade55a 100644 --- a/code/game/objects/structures/syndicate_uplink_beacon.dm +++ b/code/game/objects/structures/syndicate_uplink_beacon.dm @@ -43,7 +43,7 @@ return var/datum/looping_sound/typing/typing_sounds = new(src, start_immediately = TRUE) balloon_alert(user, "synchronizing...") - if(!do_after(user = user, delay = 3 SECONDS, target = src, interaction_key = REF(src))) + if(!do_after(user = user, delay = 3 SECONDS, target = src, interaction_key = REF(src), hidden = TRUE)) typing_sounds.stop() return typing_sounds.stop() @@ -52,7 +52,7 @@ /obj/structure/syndicate_uplink_beacon/screwdriver_act_secondary(mob/living/user, obj/item/tool) tool.play_tool_sound(src) balloon_alert(user, "deconstructing...") - if (!do_after(user, 5 SECONDS, target = src)) + if (!do_after(user, 5 SECONDS, target = src, hidden = TRUE)) return FALSE var/turf/beacon_tile = get_turf(src) new /obj/item/stack/sheet/iron/five(beacon_tile) diff --git a/code/game/objects/structures/table_frames.dm b/code/game/objects/structures/table_frames.dm index 81017299795..cb45eb18e75 100644 --- a/code/game/objects/structures/table_frames.dm +++ b/code/game/objects/structures/table_frames.dm @@ -75,9 +75,8 @@ T.set_custom_materials(custom_materials) qdel(src) -/obj/structure/table_frame/deconstruct(disassembled = TRUE) +/obj/structure/table_frame/atom_deconstruct(disassembled = TRUE) new framestack(get_turf(src), framestackamount) - qdel(src) /obj/structure/table_frame/narsie_act() new /obj/structure/table_frame/wood(src.loc) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 391ce514fbd..234abcbeb39 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -73,7 +73,7 @@ context[SCREENTIP_CONTEXT_RMB] = "Deal card faceup" . = CONTEXTUAL_SCREENTIP_SET - if(!(obj_flags & NO_DECONSTRUCTION) && deconstruction_ready) + if(deconstruction_ready) if(held_item.tool_behaviour == TOOL_SCREWDRIVER) context[SCREENTIP_CONTEXT_RMB] = "Disassemble" . = CONTEXTUAL_SCREENTIP_SET @@ -207,7 +207,7 @@ pushed_mob.add_mood_event("table", /datum/mood_event/table_limbsmash, banged_limb) /obj/structure/table/screwdriver_act_secondary(mob/living/user, obj/item/tool) - if(obj_flags & NO_DECONSTRUCTION || !deconstruction_ready) + if(!deconstruction_ready) return FALSE to_chat(user, span_notice("You start disassembling [src]...")) if(tool.use_tool(src, user, 2 SECONDS, volume=50)) @@ -215,12 +215,12 @@ return ITEM_INTERACT_SUCCESS /obj/structure/table/wrench_act_secondary(mob/living/user, obj/item/tool) - if(obj_flags & NO_DECONSTRUCTION || !deconstruction_ready) + if(!deconstruction_ready) return FALSE to_chat(user, span_notice("You start deconstructing [src]...")) if(tool.use_tool(src, user, 4 SECONDS, volume=50)) playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) - deconstruct(TRUE, 1) + deconstruct(TRUE) return ITEM_INTERACT_SUCCESS /obj/structure/table/attackby(obj/item/I, mob/living/user, params) @@ -297,20 +297,14 @@ /obj/structure/table/proc/AfterPutItemOnTable(obj/item/thing, mob/living/user) return -/obj/structure/table/deconstruct(disassembled = TRUE, wrench_disassembly = 0) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/turf/T = get_turf(src) - if(buildstack) - new buildstack(T, buildstackamount) - else - for(var/i in custom_materials) - var/datum/material/M = i - new M.sheet_type(T, FLOOR(custom_materials[M] / SHEET_MATERIAL_AMOUNT, 1)) - if(!wrench_disassembly) - new frame(T) - else - new framestack(T, framestackamount) - qdel(src) +/obj/structure/table/atom_deconstruct(disassembled = TRUE) + var/turf/target_turf = get_turf(src) + if(buildstack) + new buildstack(target_turf, buildstackamount) + else + for(var/datum/material/mat in custom_materials) + new mat.sheet_type(target_turf, FLOOR(custom_materials[mat] / SHEET_MATERIAL_AMOUNT, 1)) + new framestack(target_turf, framestackamount) /obj/structure/table/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) if(the_rcd.mode == RCD_DECONSTRUCT) @@ -437,8 +431,7 @@ /obj/structure/table/glass/proc/on_entered(datum/source, atom/movable/AM) SIGNAL_HANDLER - if(obj_flags & NO_DECONSTRUCTION) - return + if(!isliving(AM)) return // Don't break if they're just flying past @@ -469,19 +462,16 @@ victim.Paralyze(100) qdel(src) -/obj/structure/table/glass/deconstruct(disassembled = TRUE, wrench_disassembly = 0) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - ..() - return - else - var/turf/T = get_turf(src) - playsound(T, SFX_SHATTER, 50, TRUE) +/obj/structure/table/glass/atom_deconstruct(disassembled = TRUE) + if(disassembled) + ..() + return + else + var/turf/T = get_turf(src) + playsound(T, SFX_SHATTER, 50, TRUE) - new frame(loc) - new glass_shard_type(loc) - - qdel(src) + new frame(loc) + new glass_shard_type(loc) /obj/structure/table/glass/narsie_act() color = NARSIE_WINDOW_COLOUR @@ -845,10 +835,9 @@ if(isnull(held_item)) return NONE - if(!(obj_flags & NO_DECONSTRUCTION)) - if(held_item.tool_behaviour == TOOL_WRENCH) - context[SCREENTIP_CONTEXT_RMB] = "Deconstruct" - return CONTEXTUAL_SCREENTIP_SET + if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_RMB] = "Deconstruct" + return CONTEXTUAL_SCREENTIP_SET return NONE @@ -864,8 +853,6 @@ return TRUE /obj/structure/rack/wrench_act_secondary(mob/living/user, obj/item/tool) - if(obj_flags & NO_DECONSTRUCTION) - return NONE tool.play_tool_sound(src) deconstruct(TRUE) return ITEM_INTERACT_SUCCESS @@ -905,12 +892,10 @@ * Rack destruction */ -/obj/structure/rack/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - set_density(FALSE) - var/obj/item/rack_parts/newparts = new(loc) - transfer_fingerprints_to(newparts) - qdel(src) +/obj/structure/rack/atom_deconstruct(disassembled = TRUE) + set_density(FALSE) + var/obj/item/rack_parts/newparts = new(loc) + transfer_fingerprints_to(newparts) /* @@ -939,24 +924,19 @@ context[SCREENTIP_CONTEXT_LMB] = "Construct Rack" return CONTEXTUAL_SCREENTIP_SET - if(!(obj_flags & NO_DECONSTRUCTION)) - if(held_item.tool_behaviour == TOOL_WRENCH) - context[SCREENTIP_CONTEXT_LMB] = "Deconstruct" - return CONTEXTUAL_SCREENTIP_SET + if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_LMB] = "Deconstruct" + return CONTEXTUAL_SCREENTIP_SET return NONE /obj/item/rack_parts/wrench_act(mob/living/user, obj/item/tool) - if(obj_flags & NO_DECONSTRUCTION) - return NONE tool.play_tool_sound(src) deconstruct(TRUE) return ITEM_INTERACT_SUCCESS -/obj/item/rack_parts/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/iron(drop_location()) - return ..() +/obj/item/rack_parts/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/iron(drop_location()) /obj/item/rack_parts/attack_self(mob/user) if(building) diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm index ec00eb110a7..2c0b3bdc95b 100644 --- a/code/game/objects/structures/tank_dispenser.dm +++ b/code/game/objects/structures/tank_dispenser.dm @@ -103,13 +103,11 @@ return TRUE -/obj/structure/tank_dispenser/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - for(var/X in src) - var/obj/item/I = X - I.forceMove(loc) - new /obj/item/stack/sheet/iron (loc, 2) - qdel(src) +/obj/structure/tank_dispenser/atom_deconstruct(disassembled = TRUE) + for(var/X in src) + var/obj/item/I = X + I.forceMove(loc) + new /obj/item/stack/sheet/iron (loc, 2) /obj/structure/tank_dispenser/proc/dispense(tank_type, mob/receiver) var/existing_tank = locate(tank_type) in src diff --git a/code/game/objects/structures/tank_holder.dm b/code/game/objects/structures/tank_holder.dm index 5b7c9d2ed55..34284b1f1dd 100644 --- a/code/game/objects/structures/tank_holder.dm +++ b/code/game/objects/structures/tank_holder.dm @@ -63,12 +63,11 @@ deconstruct(TRUE) return TRUE -/obj/structure/tank_holder/deconstruct(disassembled = TRUE) +/obj/structure/tank_holder/atom_deconstruct(disassembled = TRUE) var/atom/Tsec = drop_location() new /obj/item/stack/rods(Tsec, 2) if(tank) tank.forceMove(Tsec) - qdel(src) /obj/structure/tank_holder/attack_paw(mob/user, list/modifiers) return attack_hand(user, modifiers) diff --git a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm index 67d3d4c9510..b1168302f68 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm @@ -35,22 +35,16 @@ user.visible_message(span_notice("[user] empties \the [src]."), span_notice("You empty \the [src].")) empty_pod() else - deconstruct(TRUE, user) + deconstruct(TRUE) else return ..() -/obj/structure/transit_tube_pod/deconstruct(disassembled = TRUE, mob/user) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/atom/location = get_turf(src) - if(user) - location = user.loc - add_fingerprint(user) - user.visible_message(span_notice("[user] removes [src]."), span_notice("You remove [src].")) - var/obj/structure/c_transit_tube_pod/R = new/obj/structure/c_transit_tube_pod(location) - transfer_fingerprints_to(R) - R.setDir(dir) - empty_pod(location) - qdel(src) +/obj/structure/transit_tube_pod/atom_deconstruct(disassembled = TRUE) + var/atom/location = get_turf(src) + var/obj/structure/c_transit_tube_pod/tube_pod = new/obj/structure/c_transit_tube_pod(location) + transfer_fingerprints_to(tube_pod) + tube_pod.setDir(dir) + empty_pod(location) /obj/structure/transit_tube_pod/ex_act(severity, target) . = ..() diff --git a/code/game/objects/structures/votingbox.dm b/code/game/objects/structures/votingbox.dm index 00eeeb55ae2..42ccd625093 100644 --- a/code/game/objects/structures/votingbox.dm +++ b/code/game/objects/structures/votingbox.dm @@ -149,9 +149,8 @@ for(var/atom/movable/AM in contents) AM.forceMove(droppoint) -/obj/structure/votebox/deconstruct(disassembled) +/obj/structure/votebox/atom_deconstruct(disassembled) dump_contents() - . = ..() /obj/structure/votebox/proc/raffle(mob/user) var/list/options = list() diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index 4706392fec9..559e2dd7808 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -83,17 +83,15 @@ icon_state = "toilet[open][cistern]" return ..() -/obj/structure/toilet/deconstruct() - if(!(obj_flags & NO_DECONSTRUCTION)) - for(var/obj/toilet_item in contents) - toilet_item.forceMove(drop_location()) - if(buildstacktype) - new buildstacktype(loc,buildstackamount) - else - for(var/i in custom_materials) - var/datum/material/M = i - new M.sheet_type(loc, FLOOR(custom_materials[M] / SHEET_MATERIAL_AMOUNT, 1)) - ..() +/obj/structure/toilet/atom_deconstruct(dissambled = TRUE) + for(var/obj/toilet_item in contents) + toilet_item.forceMove(drop_location()) + if(buildstacktype) + new buildstacktype(loc,buildstackamount) + else + for(var/i in custom_materials) + var/datum/material/M = i + new M.sheet_type(loc, FLOOR(custom_materials[M] / SHEET_MATERIAL_AMOUNT, 1)) /obj/structure/toilet/attackby(obj/item/I, mob/living/user, params) add_fingerprint(user) @@ -105,7 +103,7 @@ cistern = !cistern update_appearance() return COMPONENT_CANCEL_ATTACK_CHAIN - else if(I.tool_behaviour == TOOL_WRENCH && !(obj_flags & NO_DECONSTRUCTION)) + else if(I.tool_behaviour == TOOL_WRENCH) I.play_tool_sound(src) deconstruct() return TRUE @@ -227,10 +225,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/urinal, 32) exposed = !exposed return TRUE -/obj/structure/urinal/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/wallframe/urinal(loc) - qdel(src) +/obj/structure/urinal/atom_deconstruct(disassembled = TRUE) + new /obj/item/wallframe/urinal(loc) /obj/item/wallframe/urinal name = "urinal frame" @@ -419,7 +415,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink, (-14)) playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE) return - if(O.tool_behaviour == TOOL_WRENCH && !(obj_flags & NO_DECONSTRUCTION)) + if(O.tool_behaviour == TOOL_WRENCH) O.play_tool_sound(src) deconstruct() return @@ -495,12 +491,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink, (-14)) else return ..() -/obj/structure/sink/deconstruct() - if(!(obj_flags & NO_DECONSTRUCTION)) - drop_materials() - if(has_water_reclaimer) - new /obj/item/stock_parts/water_recycler(drop_location()) - ..() +/obj/structure/sink/atom_deconstruct(dissambled = TRUE) + drop_materials() + if(has_water_reclaimer) + new /obj/item/stock_parts/water_recycler(drop_location()) /obj/structure/sink/process(seconds_per_tick) // Water reclamation complete? @@ -571,10 +565,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink/kitchen, (-16)) deconstruct() return TRUE -/obj/structure/sinkframe/deconstruct() - if(!(obj_flags & NO_DECONSTRUCTION)) - drop_materials() - return ..() +/obj/structure/sinkframe/atom_deconstruct(dissambled = TRUE) + drop_materials() /obj/structure/sinkframe/proc/drop_materials() for(var/datum/material/material as anything in custom_materials) @@ -725,9 +717,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink/kitchen, (-16)) . = ..() icon_state = "puddle" -/obj/structure/water_source/puddle/deconstruct(disassembled = TRUE) - qdel(src) - //End legacy sink @@ -804,11 +793,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink/kitchen, (-16)) playsound(loc, 'sound/effects/curtain.ogg', 50, TRUE) toggle() -/obj/structure/curtain/deconstruct(disassembled = TRUE) +/obj/structure/curtain/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/cloth (loc, 2) new /obj/item/stack/sheet/plastic (loc, 2) new /obj/item/stack/rods (loc, 1) - qdel(src) /obj/structure/curtain/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) switch(damage_type) @@ -840,10 +828,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink/kitchen, (-16)) alpha = 255 opaque_closed = TRUE -/obj/structure/curtain/cloth/deconstruct(disassembled = TRUE) +/obj/structure/curtain/cloth/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/cloth (loc, 4) new /obj/item/stack/rods (loc, 1) - qdel(src) /obj/structure/curtain/cloth/fancy icon_type = "cur_fancy" diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 5473902e9ef..89d04f46976 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -78,8 +78,6 @@ /obj/structure/window/examine(mob/user) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return switch(state) if(WINDOW_SCREWED_TO_FRAME) @@ -210,8 +208,6 @@ return ITEM_INTERACT_SUCCESS /obj/structure/window/screwdriver_act(mob/living/user, obj/item/tool) - if(obj_flags & NO_DECONSTRUCTION) - return switch(state) if(WINDOW_SCREWED_TO_FRAME) @@ -240,7 +236,7 @@ /obj/structure/window/wrench_act(mob/living/user, obj/item/tool) if(anchored) return FALSE - if((obj_flags & NO_DECONSTRUCTION) || (reinf && state >= RWINDOW_FRAME_BOLTED)) + if(reinf && state >= RWINDOW_FRAME_BOLTED) return FALSE to_chat(user, span_notice("You begin to disassemble [src]...")) @@ -255,7 +251,7 @@ return ITEM_INTERACT_SUCCESS /obj/structure/window/crowbar_act(mob/living/user, obj/item/tool) - if(!anchored || (obj_flags & NO_DECONSTRUCTION)) + if(!anchored) return FALSE switch(state) @@ -330,18 +326,13 @@ playsound(src, 'sound/items/welder.ogg', 100, TRUE) -/obj/structure/window/deconstruct(disassembled = TRUE) - if(QDELETED(src)) - return +/obj/structure/window/atom_deconstruct(disassembled = TRUE) if(!disassembled) playsound(src, break_sound, 70, TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - for(var/obj/item/shard/debris in spawn_debris(drop_location())) - transfer_fingerprints_to(debris) // transfer fingerprints to shards only - qdel(src) + for(var/obj/item/shard/debris in spawn_debris(drop_location())) + transfer_fingerprints_to(debris) // transfer fingerprints to shards only update_nearby_icons() - ///Spawns shard and debris decal based on the glass_material_datum, spawns rods if window is reinforned and number of shards/rods is determined by the window being fulltile or not. /obj/structure/window/proc/spawn_debris(location) var/datum/material/glass_material_ref = GET_MATERIAL_REF(glass_material_datum) @@ -480,9 +471,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/unanchored/spawner, 0) return FALSE /obj/structure/window/reinforced/attackby_secondary(obj/item/tool, mob/user, params) - if(obj_flags & NO_DECONSTRUCTION) - return ..() - switch(state) if(RWINDOW_SECURE) if(tool.tool_behaviour == TOOL_WELDER) @@ -546,7 +534,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/unanchored/spawner, 0) /obj/structure/window/reinforced/crowbar_act(mob/living/user, obj/item/tool) if(!anchored) return FALSE - if((obj_flags & NO_DECONSTRUCTION) || (state != WINDOW_OUT_OF_FRAME)) + if(state != WINDOW_OUT_OF_FRAME) return FALSE to_chat(user, span_notice("You begin to lever the window back into the frame...")) if(tool.use_tool(src, user, 10 SECONDS, volume = 75, extra_checks = CALLBACK(src, PROC_REF(check_state_and_anchored), state, anchored))) @@ -561,8 +549,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/unanchored/spawner, 0) /obj/structure/window/reinforced/examine(mob/user) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return + switch(state) if(RWINDOW_SECURE) . += span_notice("It's been screwed in with one way screws, you'd need to heat them to have any chance of backing them out.") @@ -803,9 +790,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/tinted/frosted/spaw /obj/structure/window/reinforced/shuttle/indestructible name = "hardened shuttle window" - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION flags_1 = PREVENT_CLICK_UNDER_1 resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION /obj/structure/window/reinforced/shuttle/indestructible/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) return FALSE diff --git a/code/game/world.dm b/code/game/world.dm index 09ae2f81064..53f3a0fe95d 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -450,7 +450,7 @@ GLOBAL_VAR(restart_counter) /world/proc/incrementMaxZ() maxz++ SSmobs.MaxZChanged() - SSidlenpcpool.MaxZChanged() + SSai_controllers.on_max_z_changed() /world/proc/change_fps(new_value = 20) if(new_value <= 0) diff --git a/code/modules/admin/verbs/manipulate_organs.dm b/code/modules/admin/verbs/manipulate_organs.dm index 6ead4d3b137..30f198bfba9 100644 --- a/code/modules/admin/verbs/manipulate_organs.dm +++ b/code/modules/admin/verbs/manipulate_organs.dm @@ -70,7 +70,7 @@ organ_holder.Remove(carbon_victim) else implant_holder = organ_to_modify - implant_holder.removed(carbon_victim) + implant_holder.removed(carbon_victim, special = TRUE) organ_to_modify.forceMove(get_turf(carbon_victim)) diff --git a/code/modules/admin/view_variables/topic_basic.dm b/code/modules/admin/view_variables/topic_basic.dm index 96500de5070..8a27d342578 100644 --- a/code/modules/admin/view_variables/topic_basic.dm +++ b/code/modules/admin/view_variables/topic_basic.dm @@ -98,9 +98,7 @@ if(!check_rights(NONE)) return var/mass_remove = href_list[VV_HK_MASS_REMOVECOMPONENT] - var/list/components = list() - for(var/datum/component/component in target.GetComponents(/datum/component)) - components += component.type + var/list/components = target._datum_components.Copy() var/list/names = list() names += "---Components---" if(length(components)) diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm index c6924cdb8c3..18dce0501ff 100644 --- a/code/modules/antagonists/_common/antag_spawner.dm +++ b/code/modules/antagonists/_common/antag_spawner.dm @@ -103,11 +103,13 @@ /// The applied outfit var/datum/outfit/syndicate/outfit = /datum/outfit/syndicate/reinforcement /// The antag datum applied - var/datum/antagonist/nukeop/reinforcement/antag_datum = /datum/antagonist/nukeop/reinforcement + var/antag_datum = /datum/antagonist/nukeop/reinforcement /// Style used by the droppod var/pod_style = STYLE_SYNDICATE /// Do we use a random subtype of the outfit? var/use_subtypes = TRUE + /// Where do we land our pod? + var/turf/spawn_location /obj/item/antag_spawner/nuke_ops/proc/check_usability(mob/user) if(used) @@ -143,7 +145,6 @@ /obj/item/antag_spawner/nuke_ops/spawn_antag(client/our_client, turf/T, kind, datum/mind/user) var/mob/living/carbon/human/nukie = new() - var/obj/structure/closet/supplypod/pod = setup_pod() our_client.prefs.safe_transfer_prefs_to(nukie, is_antag = TRUE) nukie.ckey = our_client.key var/datum/mind/op_mind = nukie.mind @@ -152,15 +153,33 @@ else nukie.forceMove(locate(1,1,1)) - antag_datum = new() - - antag_datum.nukeop_outfit = use_subtypes ? pick(subtypesof(outfit)) : outfit + var/new_datum = new antag_datum() var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop, TRUE) - op_mind.add_antag_datum(antag_datum, creator_op ? creator_op.get_team() : null) + op_mind.add_antag_datum(new_datum, creator_op ? creator_op.get_team() : null) op_mind.special_role = special_role_name + + if(outfit) + var/datum/antagonist/nukeop/nukie_datum = op_mind.has_antag_datum(antag_datum) + nukie_datum.nukeop_outfit = use_subtypes ? pick(subtypesof(outfit)) : outfit + + var/obj/structure/closet/supplypod/pod = setup_pod() nukie.forceMove(pod) - new /obj/effect/pod_landingzone(get_turf(src), pod) + new /obj/effect/pod_landingzone(spawn_location ? spawn_location : get_turf(src), pod) + +/obj/item/antag_spawner/nuke_ops/overwatch + name = "overwatch support beacon" + desc = "Assigns an Overwatch Intelligence Agent to your operation. Stationed at their own remote outpost, they can view station cameras, alarms, and even move the Infiltrator shuttle! \ + Also, all members of your operation will recieve body cameras that they can view your progress from." + special_role_name = ROLE_OPERATIVE_OVERWATCH + outfit = /datum/outfit/syndicate/support + use_subtypes = FALSE + antag_datum = /datum/antagonist/nukeop/support + +/obj/item/antag_spawner/nuke_ops/overwatch/Initialize(mapload) + . = ..() + if(length(GLOB.nukeop_overwatch_start)) //Otherwise, it will default to the datum's spawn point anyways + spawn_location = pick(GLOB.nukeop_overwatch_start) //////CLOWN OP /obj/item/antag_spawner/nuke_ops/clown diff --git a/code/modules/antagonists/changeling/powers/absorb.dm b/code/modules/antagonists/changeling/powers/absorb.dm index 5bd0f390cb8..7e13612153b 100644 --- a/code/modules/antagonists/changeling/powers/absorb.dm +++ b/code/modules/antagonists/changeling/powers/absorb.dm @@ -145,7 +145,7 @@ target.take_overall_damage(40) SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("Absorb DNA", "[absorbing_iteration]")) - if(!do_after(owner, 15 SECONDS, target)) + if(!do_after(owner, 15 SECONDS, target, hidden = TRUE)) owner.balloon_alert(owner, "interrupted!") is_absorbing = FALSE return FALSE diff --git a/code/modules/antagonists/heretic/heretic_antag.dm b/code/modules/antagonists/heretic/heretic_antag.dm index 6dee633061a..edb2d9c8136 100644 --- a/code/modules/antagonists/heretic/heretic_antag.dm +++ b/code/modules/antagonists/heretic/heretic_antag.dm @@ -350,7 +350,7 @@ else drawing_effect = new(target_turf, rune_colour) - if(!do_after(user, drawing_time, target_turf, extra_checks = additional_checks)) + if(!do_after(user, drawing_time, target_turf, extra_checks = additional_checks, hidden = TRUE)) target_turf.balloon_alert(user, "interrupted!") new /obj/effect/temp_visual/drawing_heretic_rune/fail(target_turf, rune_colour) qdel(drawing_effect) diff --git a/code/modules/antagonists/heretic/influences.dm b/code/modules/antagonists/heretic/influences.dm index 62759d52ab9..350c694012e 100644 --- a/code/modules/antagonists/heretic/influences.dm +++ b/code/modules/antagonists/heretic/influences.dm @@ -285,7 +285,7 @@ being_drained = TRUE balloon_alert(user, "draining influence...") - if(!do_after(user, 10 SECONDS, src)) + if(!do_after(user, 10 SECONDS, src, hidden = TRUE)) being_drained = FALSE balloon_alert(user, "interrupted!") return diff --git a/code/modules/antagonists/heretic/magic/manse_link.dm b/code/modules/antagonists/heretic/magic/manse_link.dm index 565e7e683eb..06fd4dd9863 100644 --- a/code/modules/antagonists/heretic/magic/manse_link.dm +++ b/code/modules/antagonists/heretic/magic/manse_link.dm @@ -55,7 +55,7 @@ to_chat(owner, span_notice("You begin linking [linkee]'s mind to yours...")) to_chat(linkee, span_warning("You feel your mind being pulled somewhere... connected... intertwined with the very fabric of reality...")) - if(!do_after(owner, link_time, linkee)) + if(!do_after(owner, link_time, linkee, hidden = TRUE)) to_chat(owner, span_warning("You fail to link to [linkee]'s mind.")) to_chat(linkee, span_warning("The foreign presence leaves your mind.")) return FALSE diff --git a/code/modules/antagonists/heretic/magic/mirror_walk.dm b/code/modules/antagonists/heretic/magic/mirror_walk.dm index 0bc9b059020..b9029e1ab07 100644 --- a/code/modules/antagonists/heretic/magic/mirror_walk.dm +++ b/code/modules/antagonists/heretic/magic/mirror_walk.dm @@ -64,7 +64,7 @@ jaunter.Beam(nearby_reflection, icon_state = "light_beam", time = phase_out_time) nearby_reflection.visible_message(span_warning("[nearby_reflection] begins to shimmer and shake slightly!")) - if(!do_after(jaunter, phase_out_time, nearby_reflection, IGNORE_USER_LOC_CHANGE|IGNORE_INCAPACITATED)) + if(!do_after(jaunter, phase_out_time, nearby_reflection, IGNORE_USER_LOC_CHANGE|IGNORE_INCAPACITATED, hidden = TRUE)) return playsound(jaunter, 'sound/magic/ethereal_enter.ogg', 50, TRUE, -1) @@ -96,7 +96,7 @@ nearby_reflection.Beam(phase_turf, icon_state = "light_beam", time = phase_in_time) nearby_reflection.visible_message(span_warning("[nearby_reflection] begins to shimmer and shake slightly!")) - if(!do_after(unjaunter, phase_in_time, nearby_reflection)) + if(!do_after(unjaunter, phase_in_time, nearby_reflection, hidden = TRUE)) return FALSE // We can move around while phasing in, but we'll always end up where we started it. diff --git a/code/modules/antagonists/heretic/structures/mawed_crucible.dm b/code/modules/antagonists/heretic/structures/mawed_crucible.dm index 7c1208b1e44..8e5410f0f67 100644 --- a/code/modules/antagonists/heretic/structures/mawed_crucible.dm +++ b/code/modules/antagonists/heretic/structures/mawed_crucible.dm @@ -21,8 +21,7 @@ . = ..() break_message = span_warning("[src] falls apart with a thud!") -/obj/structure/destructible/eldritch_crucible/deconstruct(disassembled = TRUE) - +/obj/structure/destructible/eldritch_crucible/atom_deconstruct(disassembled = TRUE) // Create a spillage if we were destroyed with leftover mass if(current_mass) break_message = span_warning("[src] falls apart with a thud, spilling shining extract everywhere!") diff --git a/code/modules/antagonists/ninja/ninjaDrainAct.dm b/code/modules/antagonists/ninja/ninjaDrainAct.dm index 68ee227d6cd..c50df819e0d 100644 --- a/code/modules/antagonists/ninja/ninjaDrainAct.dm +++ b/code/modules/antagonists/ninja/ninjaDrainAct.dm @@ -32,7 +32,7 @@ if(hacking_module.mod.get_charge() + drain > hacking_module.mod.get_max_charge()) drain = hacking_module.mod.get_max_charge() - hacking_module.mod.get_charge() maxcapacity = TRUE//Reached maximum battery capacity. - if (do_after(ninja, 1 SECONDS, target = src)) + if (do_after(ninja, 1 SECONDS, target = src, hidden = TRUE)) spark_system.start() playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) cell.use(drain) @@ -68,7 +68,7 @@ if(hacking_module.mod.get_charge() + drain > hacking_module.mod.get_max_charge()) drain = hacking_module.mod.get_max_charge() - hacking_module.mod.get_charge() maxcapacity = TRUE - if (do_after(ninja, 1 SECONDS, target = src)) + if (do_after(ninja, 1 SECONDS, target = src, hidden = TRUE)) spark_system.start() playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) charge -= drain @@ -88,7 +88,7 @@ /obj/item/stock_parts/cell/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) var/drain_total = 0 - if(charge && !do_after(ninja, 3 SECONDS, target = src)) + if(charge && !do_after(ninja, 3 SECONDS, target = src, hidden = TRUE)) drain_total = charge if(hacking_module.mod.get_charge() + charge > hacking_module.mod.get_max_charge()) drain_total = hacking_module.mod.get_max_charge() - hacking_module.mod.get_charge() @@ -112,7 +112,7 @@ return COMPONENT_CANCEL_ATTACK_CHAIN /obj/machinery/rnd/server/master/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) - if(!do_after(ninja, 30 SECONDS, target = src)) + if(!do_after(ninja, 30 SECONDS, target = src, hidden = TRUE)) return overload_source_code_hdd() to_chat(ninja, span_notice("Sabotage complete. Storage device overloaded.")) @@ -131,7 +131,7 @@ return COMPONENT_CANCEL_ATTACK_CHAIN /obj/machinery/rnd/server/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) - if(!do_after(ninja, 30 SECONDS, target = src)) + if(!do_after(ninja, 30 SECONDS, target = src, hidden = TRUE)) return stored_research.modify_points_all(0) to_chat(ninja, span_notice("Sabotage complete. Research notes corrupted.")) @@ -154,7 +154,7 @@ return COMPONENT_CANCEL_ATTACK_CHAIN /obj/machinery/computer/records/security/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) - if(!do_after(ninja, 20 SECONDS, src, extra_checks = CALLBACK(src, PROC_REF(can_hack), ninja))) + if(!do_after(ninja, 20 SECONDS, src, extra_checks = CALLBACK(src, PROC_REF(can_hack), ninja), hidden = TRUE)) return for(var/datum/record/crew/target in GLOB.manifest.general) target.wanted_status = WANTED_ARREST @@ -230,7 +230,7 @@ while(!maxcapacity && src) drain = (round((rand(hacking_module.mindrain, hacking_module.maxdrain))/2)) var/drained = 0 - if(wire_powernet && do_after(ninja, 1 SECONDS, target = src)) + if(wire_powernet && do_after(ninja, 1 SECONDS, target = src, hidden = TRUE)) drained = min(drain, delayed_surplus()) add_delayedload(drained) if(drained < drain)//if no power on net, drain apcs @@ -270,7 +270,7 @@ if(hacking_module.mod.get_charge() + drain > hacking_module.mod.get_max_charge()) drain = hacking_module.mod.get_max_charge() - hacking_module.mod.get_charge() maxcapacity = TRUE - if (do_after(ninja, 1 SECONDS, target = src)) + if (do_after(ninja, 1 SECONDS, target = src, hidden = TRUE)) spark_system.start() playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) cell.use(drain) @@ -296,7 +296,7 @@ modelselected["Medical"] = "/obj/item/robot_model/ninja/ninja_medical" modelselected["Saboteur"] = "/obj/item/robot_model/ninja_saboteur" //SKYRAT EDIT: ADDITION END - if(!do_after(ninja, 6 SECONDS, target = src)) + if(!do_after(ninja, 6 SECONDS, target = src, hidden = TRUE)) return spark_system.start() playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) @@ -353,7 +353,7 @@ //BOTS// /mob/living/simple_animal/bot/ninjadrain_act(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) to_chat(src, span_boldwarning("Your circutry suddenly begins heating up!")) - if(!do_after(ninja, 1.5 SECONDS, target = src)) + if(!do_after(ninja, 1.5 SECONDS, target = src, hidden = TRUE)) return COMPONENT_CANCEL_ATTACK_CHAIN if(!hacking_module.mod.subtract_charge(DEFAULT_CHARGE_DRAIN * 7)) @@ -379,7 +379,7 @@ balloon_alert(ninja, "no energy!") return COMPONENT_CANCEL_ATTACK_CHAIN - if(!do_after(ninja, 1.5 SECONDS, target = src)) + if(!do_after(ninja, 1.5 SECONDS, target = src, hidden = TRUE)) return COMPONENT_CANCEL_ATTACK_CHAIN hacking_module.mod.add_charge(cell.charge) @@ -396,7 +396,7 @@ balloon_alert(ninja, "already hacked!") return COMPONENT_CANCEL_ATTACK_CHAIN - if(!do_after(ninja, 2 SECONDS, target = src)) + if(!do_after(ninja, 2 SECONDS, target = src, hidden = TRUE)) return COMPONENT_CANCEL_ATTACK_CHAIN if(!hacking_module.mod.subtract_charge(DEFAULT_CHARGE_DRAIN * 5)) @@ -414,7 +414,7 @@ return COMPONENT_CANCEL_ATTACK_CHAIN AI_notify_hack() - if(!do_after(ninja, 30 SECONDS, target = src)) + if(!do_after(ninja, 30 SECONDS, target = src, hidden = TRUE)) return COMPONENT_CANCEL_ATTACK_CHAIN do_sparks(3, cardinal_only = FALSE, source = src) @@ -428,7 +428,7 @@ balloon_alert(ninja, "already hacked!") return COMPONENT_CANCEL_ATTACK_CHAIN - if(!do_after(ninja, 2 SECONDS, target = src)) + if(!do_after(ninja, 2 SECONDS, target = src, hidden = TRUE)) return COMPONENT_CANCEL_ATTACK_CHAIN do_sparks(3, cardinal_only = FALSE, source = src) @@ -449,7 +449,7 @@ AI_notify_hack() - if(!do_after(ninja, 20 SECONDS, target = src)) //Shorter due to how incredibly easy it is for someone to (even accidentally) interrupt. + if(!do_after(ninja, 20 SECONDS, target = src, hidden = TRUE)) //Shorter due to how incredibly easy it is for someone to (even accidentally) interrupt. return COMPONENT_CANCEL_ATTACK_CHAIN force_event(/datum/round_event_control/tram_malfunction, "ninja interference") diff --git a/code/modules/antagonists/nukeop/datums/operative.dm b/code/modules/antagonists/nukeop/datums/operative.dm index 516108c5725..3b4c9fa4da7 100644 --- a/code/modules/antagonists/nukeop/datums/operative.dm +++ b/code/modules/antagonists/nukeop/datums/operative.dm @@ -46,7 +46,6 @@ var/datum/component/uplink/uplink = owner.find_syndicate_uplink() if (uplink) uplink.uplink_handler.add_telecrystals(extra_tc) - var/datum/component/uplink/uplink = owner.find_syndicate_uplink() if(uplink) var/datum/team/nuclear/nuke_team = get_team() diff --git a/code/modules/antagonists/nukeop/datums/operative_support.dm b/code/modules/antagonists/nukeop/datums/operative_support.dm new file mode 100644 index 00000000000..c9ea12b63c5 --- /dev/null +++ b/code/modules/antagonists/nukeop/datums/operative_support.dm @@ -0,0 +1,54 @@ +/datum/antagonist/nukeop/support + name = ROLE_OPERATIVE_OVERWATCH + show_to_ghosts = TRUE + send_to_spawnpoint = TRUE + nukeop_outfit = /datum/outfit/syndicate/support + +/datum/antagonist/nukeop/support/greet() + owner.current.playsound_local(get_turf(owner.current), 'sound/machines/printer.ogg', 100, 0, use_reverb = FALSE) + to_chat(owner, span_big("You are a [name]! You've been temporarily assigned to provide camera overwatch and manage communications for a nuclear operative team!")) + to_chat(owner, span_red("Use your tools to set up your equipment however you like, but do NOT attempt to leave your outpost.")) + owner.announce_objectives() + +/datum/antagonist/nukeop/support/on_gain() + ..() + for(var/datum/mind/teammate_mind in nuke_team.members) + var/mob/living/our_teammate = teammate_mind.current + our_teammate.AddComponent( \ + /datum/component/simple_bodycam, \ + camera_name = "operative bodycam", \ + c_tag = "[our_teammate.real_name]", \ + network = OPERATIVE_CAMERA_NET, \ + emp_proof = FALSE, \ + ) + our_teammate.playsound_local(get_turf(owner.current), 'sound/weapons/egloves.ogg', 100, 0) + to_chat(our_teammate, span_notice("A Syndicate Overwatch Intelligence Agent has been assigned to your team. Smile, you're on camera!")) + + RegisterSignal(nuke_team, COMSIG_NUKE_TEAM_ADDITION, PROC_REF(late_bodycam)) + + owner.current.grant_language(/datum/language/codespeak) + +/datum/antagonist/nukeop/support/get_spawnpoint() + return pick(GLOB.nukeop_overwatch_start) + +/datum/antagonist/nukeop/support/forge_objectives() + var/datum/objective/overwatch/objective = new + objective.owner = owner + objectives += objective + +/datum/antagonist/nukeop/support/proc/late_bodycam(datum/source, mob/living/new_teammate) + SIGNAL_HANDLER + new_teammate.AddComponent( \ + /datum/component/simple_bodycam, \ + camera_name = "operative bodycam", \ + c_tag = "[new_teammate.real_name]", \ + network = OPERATIVE_CAMERA_NET, \ + emp_proof = FALSE, \ + ) + to_chat(new_teammate, span_notice("You have been equipped with a bodycam, viewable by your Overwatch Intelligence Agent. Make sure to show them a good performance!")) + +/datum/objective/overwatch + explanation_text = "Provide intelligence support and overwatch to your operative team!" + +/datum/objective/overwatch/check_completion() + return GLOB.station_was_nuked diff --git a/code/modules/antagonists/nukeop/datums/operative_team.dm b/code/modules/antagonists/nukeop/datums/operative_team.dm index 9bec3b0fcf0..3345f3cf4d2 100644 --- a/code/modules/antagonists/nukeop/datums/operative_team.dm +++ b/code/modules/antagonists/nukeop/datums/operative_team.dm @@ -313,5 +313,9 @@ return TRUE return FALSE +/datum/team/nuclear/add_member(datum/mind/new_member) + ..() + SEND_SIGNAL(src, COMSIG_NUKE_TEAM_ADDITION, new_member.current) + #undef SPAWN_AT_BASE #undef SPAWN_AT_INFILTRATOR diff --git a/code/modules/antagonists/nukeop/equipment/borgchameleon.dm b/code/modules/antagonists/nukeop/equipment/borgchameleon.dm index 68e62a1044c..a2a072f02e2 100644 --- a/code/modules/antagonists/nukeop/equipment/borgchameleon.dm +++ b/code/modules/antagonists/nukeop/equipment/borgchameleon.dm @@ -66,7 +66,7 @@ to_chat(user, span_notice("You activate \the [src].")) playsound(src, 'sound/effects/seedling_chargeup.ogg', 100, TRUE, -6) apply_wibbly_filters(user) - if (do_after(user, 5 SECONDS, target=user) && user.cell.use(ACTIVATION_COST)) + if (do_after(user, 5 SECONDS, target = user, hidden = TRUE) && user.cell.use(ACTIVATION_COST)) playsound(src, 'sound/effects/bamf.ogg', 100, TRUE, -6) to_chat(user, span_notice("You are now disguised as the Nanotrasen engineering borg \"[friendlyName]\".")) activate(user) diff --git a/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm b/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm index 190b9bcfe34..a52a026abe0 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm @@ -124,7 +124,7 @@ GLOBAL_VAR(station_nuke_source) if(istype(weapon, /obj/item/nuke_core_container)) var/obj/item/nuke_core_container/core_box = weapon to_chat(user, span_notice("You start loading the plutonium core into [core_box]...")) - if(do_after(user, 5 SECONDS, target=src)) + if(do_after(user, 5 SECONDS, target = src, hidden = TRUE)) if(core_box.load(core, user)) to_chat(user, span_notice("You load the plutonium core into [core_box].")) deconstruction_state = NUKESTATE_CORE_REMOVED diff --git a/code/modules/antagonists/nukeop/equipment/overwatch_tools.dm b/code/modules/antagonists/nukeop/equipment/overwatch_tools.dm new file mode 100644 index 00000000000..852c0d7d32f --- /dev/null +++ b/code/modules/antagonists/nukeop/equipment/overwatch_tools.dm @@ -0,0 +1,46 @@ +///One of the special items that spawns in the overwatch agent's room. +/obj/item/paper/fluff/overwatch + name = "OVERWATCH NOTES #1" + color = COLOR_RED + desc = "A note from Syndicate leadership regarding your new job. You should read this!" + default_raw_text = @{" +Congratulations! You have been picked to be the Sole Survivor of an anti-Nanotrasen suicide mission! +We're kidding of course, these types of missions tend to have abnormally high survival rates. I guess that says a lot about who your team will be going up against. +
+You've been assigned to provide intelligence support to the ground-pounders carrying out the operation. +Each operative has been equipped with a bodycam that can be accessed via your Overwatch Camera Console. +Additionally, you have been given the boards to access station alerts, cameras, and remotely control the infiltrator shuttle. +
+Feel free to set up your workplace however you like. We've provided the tools and boards in your backroom. +
+Happy hunting! + "} + +/obj/machinery/computer/security/overwatch + name = "overwatch camera console" + desc = "Allows you to view members of your operative team via their bodycam feeds. We call them 'bodycams', but they're actually a swarm of tiny, near-imperceptible camera drones that follow each target. \ + It is believed that adversaries either don't notice the drones, or avoid attacking them in hopes that they'll capture footage of their combat prowess against our operatives." + icon_screen = "commsyndie" + icon_keyboard = "syndie_key" + network = list(OPERATIVE_CAMERA_NET) + circuit = /obj/item/circuitboard/computer/overwatch + +/obj/item/circuitboard/computer/overwatch + name = "Overwatch Body Cameras" + build_path = /obj/machinery/computer/security/overwatch + greyscale_colors = CIRCUIT_COLOR_SECURITY + +/obj/item/circuitboard/computer/syndicate_shuttle_docker + name = "Shuttle Controller" + build_path = /obj/machinery/computer/camera_advanced/shuttle_docker/syndicate + greyscale_colors = CIRCUIT_COLOR_SECURITY + +/obj/item/clothing/glasses/overwatch + name = "intelligence glasses" + desc = "A set of incredibly advanced sunglasses, providing you with an array of different sensor scans and visual readouts for pretty much anything you look at. \ + It's kind of overwhelming, actually. Wearing this for a few hours will probably give you a migrane." + icon_state = "sunhudmed" + flags_cover = GLASSESCOVERSEYES + flash_protect = FLASH_PROTECTION_WELDER + clothing_traits = list(TRAIT_REAGENT_SCANNER) + var/list/hudlist = list(DATA_HUD_MEDICAL_ADVANCED, DATA_HUD_DIAGNOSTIC_ADVANCED, DATA_HUD_SECURITY_ADVANCED) diff --git a/code/modules/antagonists/nukeop/outfits.dm b/code/modules/antagonists/nukeop/outfits.dm index 80360f56360..eb251bcc363 100644 --- a/code/modules/antagonists/nukeop/outfits.dm +++ b/code/modules/antagonists/nukeop/outfits.dm @@ -114,6 +114,17 @@ r_hand = /obj/item/tank/internals/plasmaman/belt/full tc = 0 +/datum/outfit/syndicate/support/plasmaman + name = "Nuclear Operative Overwatch Agent (Plasmaman)" + back = /obj/item/storage/backpack/satchel + head = /obj/item/clothing/head/helmet/space/plasmaman/syndie + uniform = /obj/item/clothing/under/plasmaman/syndicate + glasses = /obj/item/clothing/glasses/overwatch + suit = /obj/item/clothing/suit/jacket/letterman_syndie + r_hand = /obj/item/tank/internals/plasmaman/belt/full + command_radio = TRUE + tc = 0 + /datum/outfit/syndicate/reinforcement/gorlex name = "Syndicate Operative - Gorlex Reinforcement" suit = /obj/item/clothing/suit/armor/vest/alt @@ -191,3 +202,13 @@ var/obj/item/shield/energy/shield = locate() in H.held_items shield.icon_state = "[shield.base_icon_state]1" H.update_held_items() + +/datum/outfit/syndicate/support + name = "Nuclear Operative Overwatch Agent" + back = /obj/item/storage/backpack/satchel + uniform = /obj/item/clothing/under/syndicate/tacticool + glasses = /obj/item/clothing/glasses/overwatch + suit = /obj/item/clothing/suit/jacket/letterman_syndie + shoes = /obj/item/clothing/shoes/sandal + command_radio = TRUE + tc = 0 diff --git a/code/modules/antagonists/spy/spy_uplink.dm b/code/modules/antagonists/spy/spy_uplink.dm index 2a9d9b9b14e..88e091310ca 100644 --- a/code/modules/antagonists/spy/spy_uplink.dm +++ b/code/modules/antagonists/spy/spy_uplink.dm @@ -136,7 +136,7 @@ span_notice("You start scanning [stealing], preparing it for extraction."), ) - if(!do_after(spy, bounty.theft_time, stealing, interaction_key = REF(src))) + if(!do_after(spy, bounty.theft_time, stealing, interaction_key = REF(src), hidden = TRUE)) return FALSE if(bounty.claimed) to_chat(spy, span_warning("Your uplinks blinks red: The bounty for [stealing] has been claimed by another spy!")) diff --git a/code/modules/antagonists/survivalist/survivalist.dm b/code/modules/antagonists/survivalist/survivalist.dm index 2480b186600..b801076747f 100644 --- a/code/modules/antagonists/survivalist/survivalist.dm +++ b/code/modules/antagonists/survivalist/survivalist.dm @@ -3,7 +3,10 @@ show_in_antagpanel = FALSE show_name_in_check_antagonists = TRUE suicide_cry = "FOR MYSELF!!" + /// What do we display when you gain the antag datum? var/greet_message = "" + /// Should we immediately print the objectives? + var/announce_objectives = TRUE /datum/antagonist/survivalist/forge_objectives() var/datum/objective/survive/survive = new @@ -18,7 +21,8 @@ /datum/antagonist/survivalist/greet() . = ..() to_chat(owner, "[greet_message]") - owner.announce_objectives() + if (announce_objectives) + owner.announce_objectives() /datum/antagonist/survivalist/guns greet_message = "Your own safety matters above all else, and the only way to ensure your safety is to stockpile weapons! Grab as many guns as possible, by any means necessary. Kill anyone who gets in your way." @@ -52,3 +56,52 @@ /datum/antagonist/survivalist/magic/on_removal() REMOVE_TRAIT(owner, TRAIT_MAGICALLY_GIFTED, REF(src)) return..() + +/// Applied by the battle royale objective +/datum/antagonist/survivalist/battle_royale + name = "Battle Royale Contestant" + greet_message = "There has to be some way you can make it out of this alive..." + announce_objectives = FALSE + +/datum/antagonist/survivalist/battle_royale/on_gain() + . = ..() + if (isnull(owner.current)) + return + RegisterSignals(owner.current, list(COMSIG_LIVING_DEATH, COMSIG_QDELETING), PROC_REF(on_died)) + +/datum/antagonist/survivalist/battle_royale/greet() + to_chat(owner, span_warning("[span_bold("You hear a tinny voice in your ear: ")] \ + Welcome contestant to Rumble Royale, the galaxy's greatest show! \n\ + You may have already heard our announcement, but we're glad to tell you that you are on live TV! \n\ + Your objective in this contest is simple: Within ten minutes be the last contestant left alive, to win a fabulous prize! \n\ + Your fellow contestants will be hearing this too, so you should grab a GPS quick and get hunting! \n\ + Noncompliance and removal of this implant is not recommended, and remember to smile for the cameras!")) + + return ..() + +/datum/antagonist/survivalist/battle_royale/on_removal() + if (isnull(owner.current)) + return ..() + UnregisterSignal(owner.current, list(COMSIG_LIVING_DEATH, COMSIG_QDELETING)) + if (owner.current.stat == DEAD) + return ..() + to_chat(owner, span_notice("Your body is flooded with relief. Against all the odds, you've made it out alive.")) + owner.current?.mob_mood.add_mood_event("battle_royale", /datum/mood_event/royale_survivor) + return ..() + +/// Add an objective to go to a specific place. +/datum/antagonist/survivalist/battle_royale/proc/set_target_area(target_area_name) + var/datum/objective/custom/travel = new + travel.owner = owner + travel.explanation_text = "Reach the [target_area_name] before time runs out." + objectives.Insert(1, travel) + owner.announce_objectives() + +/// Called if you fail to survive. +/datum/antagonist/survivalist/battle_royale/proc/on_died() + SIGNAL_HANDLER + owner.remove_antag_datum(type) + +/datum/mood_event/royale_survivor + description = "I made it out of Rumble Royale with my life." + mood_change = 4 diff --git a/code/modules/antagonists/traitor/objectives/final_objective/battle_royale.dm b/code/modules/antagonists/traitor/objectives/final_objective/battle_royale.dm new file mode 100644 index 00000000000..9b8f519da95 --- /dev/null +++ b/code/modules/antagonists/traitor/objectives/final_objective/battle_royale.dm @@ -0,0 +1,43 @@ +/datum/traitor_objective/ultimate/battle_royale + name = "Implant crewmembers with a subtle implant, then make them fight to the death on pay-per-view TV." + description = "Go to %AREA%, and receive the Royale Broadcast Kit. \ + Use the contained implant on station personnel to subtly implant them with a micro-explosive. \ + Once you have at least six contestants, use the contained remote to start a timer and begin broadcasting live. \ + If more than one contestant remains alive after ten minutes, all of the implants will detonate." + + ///Area type the objective owner must be in to receive the tools. + var/area/kit_spawn_area + ///Whether the kit was sent already. + var/equipped = FALSE + +/datum/traitor_objective/ultimate/battle_royale/generate_objective(datum/mind/generating_for, list/possible_duplicates) + var/list/possible_areas = GLOB.the_station_areas.Copy() + for(var/area/possible_area as anything in possible_areas) + if(ispath(possible_area, /area/station/hallway) || ispath(possible_area, /area/station/security)) + possible_areas -= possible_area + if(length(possible_areas) == 0) + return FALSE + kit_spawn_area = pick(possible_areas) + replace_in_name("%AREA%", initial(kit_spawn_area.name)) + return TRUE + +/datum/traitor_objective/ultimate/battle_royale/generate_ui_buttons(mob/user) + var/list/buttons = list() + if(!equipped) + buttons += add_ui_button("", "Pressing this will call down a pod with the Royale Broadcast kit.", "biohazard", "deliver_kit") + return buttons + +/datum/traitor_objective/ultimate/battle_royale/ui_perform_action(mob/living/user, action) + . = ..() + if(action != "deliver_kit" || equipped) + return + var/area/delivery_area = get_area(user) + if(delivery_area.type != kit_spawn_area) + to_chat(user, span_warning("You must be in [initial(kit_spawn_area.name)] to receive the Royale Broadcast kit.")) + return + equipped = TRUE + podspawn(list( + "target" = get_turf(user), + "style" = STYLE_SYNDICATE, + "spawn" = /obj/item/storage/box/syndie_kit/battle_royale, + )) diff --git a/code/modules/antagonists/traitor/objectives/final_objective/final_objective.dm b/code/modules/antagonists/traitor/objectives/final_objective/final_objective.dm index 6d8bd27f9c7..cb9f4ac73aa 100644 --- a/code/modules/antagonists/traitor/objectives/final_objective/final_objective.dm +++ b/code/modules/antagonists/traitor/objectives/final_objective/final_objective.dm @@ -1,11 +1,12 @@ /datum/traitor_objective_category/final_objective name = "Final Objective" objectives = list( - /datum/traitor_objective/ultimate/romerol = 1, /datum/traitor_objective/ultimate/battlecruiser = 1, - /datum/traitor_objective/ultimate/supermatter_cascade = 1, - /datum/traitor_objective/ultimate/infect_ai = 1, + /datum/traitor_objective/ultimate/battle_royale = 1, /datum/traitor_objective/ultimate/dark_matteor = 1, + /datum/traitor_objective/ultimate/infect_ai = 1, + /datum/traitor_objective/ultimate/romerol = 1, + /datum/traitor_objective/ultimate/supermatter_cascade = 1, ) weight = 100 diff --git a/code/modules/antagonists/traitor/objectives/infect.dm b/code/modules/antagonists/traitor/objectives/infect.dm index 5f761a273fc..459e8f54a0d 100644 --- a/code/modules/antagonists/traitor/objectives/infect.dm +++ b/code/modules/antagonists/traitor/objectives/infect.dm @@ -166,7 +166,7 @@ to_chat(affected_mob, span_warning("You feel someone try to inject you with something.")) balloon_alert(user, "injecting...") log_combat(user, affected_mob, "attempted to inject", src) - if(!do_after(user, 1.5 SECONDS)) + if(!do_after(user, 1.5 SECONDS, hidden = TRUE)) balloon_alert(user, "interrupted!") return var/datum/disease/chronic_illness/hms = new /datum/disease/chronic_illness() diff --git a/code/modules/antagonists/traitor/objectives/locate_weakpoint.dm b/code/modules/antagonists/traitor/objectives/locate_weakpoint.dm index b3e211d2867..1976fd38fc8 100644 --- a/code/modules/antagonists/traitor/objectives/locate_weakpoint.dm +++ b/code/modules/antagonists/traitor/objectives/locate_weakpoint.dm @@ -192,7 +192,7 @@ for(var/mob/living/silicon/ai/ai_player in GLOB.player_list) to_chat(ai_player, alertstr) - if(!do_after(user, 30 SECONDS, src, IGNORE_USER_LOC_CHANGE | IGNORE_TARGET_LOC_CHANGE | IGNORE_HELD_ITEM | IGNORE_INCAPACITATED | IGNORE_SLOWDOWNS, extra_checks = CALLBACK(src, PROC_REF(scan_checks), user, user_area, objective))) + if(!do_after(user, 30 SECONDS, src, IGNORE_USER_LOC_CHANGE | IGNORE_TARGET_LOC_CHANGE | IGNORE_HELD_ITEM | IGNORE_INCAPACITATED | IGNORE_SLOWDOWNS, extra_checks = CALLBACK(src, PROC_REF(scan_checks), user, user_area, objective), hidden = TRUE)) playsound(user, 'sound/machines/buzz-sigh.ogg', 30, TRUE) return diff --git a/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm b/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm index 48a29598981..9723d2b653e 100644 --- a/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm +++ b/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm @@ -165,7 +165,7 @@ GLOBAL_DATUM_INIT(objective_machine_handler, /datum/objective_target_machine_han if (. || !istype(target, target_machine_path)) return balloon_alert(user, "planting device...") - if(!do_after(user, delay = deploy_time, target = src, interaction_key = DOAFTER_SOURCE_PLANTING_DEVICE)) + if(!do_after(user, delay = deploy_time, target = src, interaction_key = DOAFTER_SOURCE_PLANTING_DEVICE, hidden = TRUE)) return TRUE target.AddComponent(\ /datum/component/interaction_booby_trap,\ diff --git a/code/modules/antagonists/traitor/objectives/steal.dm b/code/modules/antagonists/traitor/objectives/steal.dm index 61d4796d66f..22d8ed7d39c 100644 --- a/code/modules/antagonists/traitor/objectives/steal.dm +++ b/code/modules/antagonists/traitor/objectives/steal.dm @@ -285,7 +285,7 @@ GLOBAL_DATUM_INIT(steal_item_handler, /datum/objective_item_handler, new()) if(result & COMPONENT_FORCE_FAIL_PLACEMENT || !istype(target, target_object_type)) balloon_alert(user, "you can't attach this onto here!") return - if(!do_after(user, deploy_time, src)) + if(!do_after(user, deploy_time, src, hidden = TRUE)) return if(planted_on) return diff --git a/code/modules/art/statues.dm b/code/modules/art/statues.dm index caebda50766..428bb5d8e06 100644 --- a/code/modules/art/statues.dm +++ b/code/modules/art/statues.dm @@ -30,35 +30,30 @@ /obj/structure/statue/wrench_act(mob/living/user, obj/item/tool) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return FALSE default_unfasten_wrench(user, tool) return ITEM_INTERACT_SUCCESS /obj/structure/statue/attackby(obj/item/W, mob/living/user, params) add_fingerprint(user) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(W.tool_behaviour == TOOL_WELDER) - if(!W.tool_start_check(user, amount=1)) - return FALSE - user.balloon_alert(user, "slicing apart...") - if(W.use_tool(src, user, 40, volume=50)) - deconstruct(TRUE) - return + if(W.tool_behaviour == TOOL_WELDER) + if(!W.tool_start_check(user, amount=1)) + return FALSE + user.balloon_alert(user, "slicing apart...") + if(W.use_tool(src, user, 40, volume=50)) + deconstruct(TRUE) + return return ..() /obj/structure/statue/AltClick(mob/user) return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation -/obj/structure/statue/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/amount_mod = disassembled ? 0 : -2 - for(var/mat in custom_materials) - var/datum/material/custom_material = GET_MATERIAL_REF(mat) - var/amount = max(0,round(custom_materials[mat]/SHEET_MATERIAL_AMOUNT) + amount_mod) - if(amount > 0) - new custom_material.sheet_type(drop_location(), amount) - qdel(src) +/obj/structure/statue/atom_deconstruct(disassembled = TRUE) + var/amount_mod = disassembled ? 0 : -2 + for(var/mat in custom_materials) + var/datum/material/custom_material = GET_MATERIAL_REF(mat) + var/amount = max(0,round(custom_materials[mat]/SHEET_MATERIAL_AMOUNT) + amount_mod) + if(amount > 0) + new custom_material.sheet_type(drop_location(), amount) //////////////////////////////////////STATUES///////////////////////////////////////////////////////////// ////////////////////////uranium/////////////////////////////////// diff --git a/code/modules/atmospherics/machinery/components/tank.dm b/code/modules/atmospherics/machinery/components/tank.dm index cf18488f052..8df616c179c 100644 --- a/code/modules/atmospherics/machinery/components/tank.dm +++ b/code/modules/atmospherics/machinery/components/tank.dm @@ -459,11 +459,10 @@ var/welder_hint = EXAMINE_HINT("welder") . += span_notice("The plating has been firmly attached and would need a [crowbar_hint] to detach, but still needs to be sealed by a [welder_hint].") -/obj/structure/tank_frame/deconstruct(disassembled) +/obj/structure/tank_frame/atom_deconstruct(disassembled) if(disassembled) for(var/datum/material/mat as anything in custom_materials) new mat.sheet_type(drop_location(), custom_materials[mat] / SHEET_MATERIAL_AMOUNT) - return ..() /obj/structure/tank_frame/update_icon(updates) . = ..() diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index cc75dd244c4..71610f05f40 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -430,7 +430,7 @@ user.visible_message(span_notice("You see [user] kicking against the glass of [src]!"), \ span_notice("You struggle inside [src], kicking the release with your foot... (this will take about [DisplayTimeText(CRYO_BREAKOUT_TIME)].)"), \ span_hear("You hear a thump from [src].")) - if(do_after(user, CRYO_BREAKOUT_TIME, target = src)) + if(do_after(user, CRYO_BREAKOUT_TIME, target = src, hidden = TRUE)) if(!user || user.stat != CONSCIOUS || user.loc != src ) return user.visible_message(span_warning("[user] successfully broke out of [src]!"), \ diff --git a/code/modules/cargo/bounties/mining.dm b/code/modules/cargo/bounties/mining.dm index 9c287341b88..be39268663f 100644 --- a/code/modules/cargo/bounties/mining.dm +++ b/code/modules/cargo/bounties/mining.dm @@ -46,6 +46,21 @@ reward = CARGO_CRATE_VALUE * 15 required_count = 3 wanted_types = list(/obj/item/clothing/accessory/talisman = TRUE) + +/datum/bounty/item/mining/watcher_wreath + name = "Watcher Wreaths" + description = "Station 14's Research Director thinks they're onto a break-through on the cultural icons of some pagan beliefs. Ship them a few watcher wreaths for analysis." + reward = CARGO_CRATE_VALUE * 15 + required_count = 3 + wanted_types = list(/obj/item/clothing/neck/wreath = FALSE) + +/datum/bounty/item/mining/icewing_wreath + name = "Icewing Wreath" + description = "We're getting some....weird messages from Station 14's Research Director. And most of what they said was incoherent. But they apparently want an icewing wreath. Could you send them one?" + reward = CARGO_CRATE_VALUE * 30 + required_count = 1 + wanted_types = list(/obj/item/clothing/neck/wreath/icewing = FALSE) + //SKYRAT EDIT REMOVAL /* /datum/bounty/item/mining/bone_dagger diff --git a/code/modules/client/preferences/middleware/antags.dm b/code/modules/client/preferences/middleware/antags.dm index 13e3bfa718f..b3bc613d2ee 100644 --- a/code/modules/client/preferences/middleware/antags.dm +++ b/code/modules/client/preferences/middleware/antags.dm @@ -1,3 +1,11 @@ +// Antagonists that don't have a dynamic ruleset, but do have a preference +GLOBAL_LIST_INIT(non_ruleset_antagonists, list( + ROLE_GLITCH = /datum/antagonist/bitrunning_glitch, + ROLE_FUGITIVE = /datum/antagonist/fugitive, + ROLE_LONE_OPERATIVE = /datum/antagonist/nukeop/lone, + ROLE_SENTIENCE = /datum/antagonist/sentient_creature, + )) + /datum/preference_middleware/antags action_delegations = list( "set_antags" = PROC_REF(set_antags), @@ -69,6 +77,12 @@ if (is_banned_from(preferences.parent.ckey, list(antag_flag_override || antag_flag, ROLE_SYNDICATE))) antag_bans += serialize_antag_name(antag_flag) + for(var/antag_key in GLOB.non_ruleset_antagonists) + var/datum/antagonist/antag = GLOB.non_ruleset_antagonists[antag_key] + var/antag_flag = initial(antag.job_rank) + if(is_banned_from(preferences.parent.ckey, list(antag_flag, ROLE_SYNDICATE))) + antag_bans += serialize_antag_name(antag_flag) + return antag_bans /datum/preference_middleware/antags/proc/get_antag_days_left() @@ -91,6 +105,17 @@ if (days_needed > 0) antag_days_left[serialize_antag_name(antag_flag)] = days_needed + for(var/antag_key in GLOB.non_ruleset_antagonists) + var/datum/antagonist/antag = GLOB.non_ruleset_antagonists[antag_key] + var/antag_flag = initial(antag.job_rank) + + var/days_needed = preferences.parent?.get_remaining_days( + GLOB.special_roles[antag_flag] + ) + + if (days_needed > 0) + antag_days_left[serialize_antag_name(antag_flag)] = days_needed + return antag_days_left /datum/preference_middleware/antags/proc/get_serialized_antags() @@ -113,15 +138,7 @@ var/list/antag_icons = list() /datum/asset/spritesheet/antagonists/create_spritesheets() - // Antagonists that don't have a dynamic ruleset, but do have a preference - var/static/list/non_ruleset_antagonists = list( - ROLE_GLITCH = /datum/antagonist/bitrunning_glitch, - ROLE_FUGITIVE = /datum/antagonist/fugitive, - ROLE_LONE_OPERATIVE = /datum/antagonist/nukeop/lone, - ROLE_SENTIENCE = /datum/antagonist/sentient_creature, - ) - - var/list/antagonists = non_ruleset_antagonists.Copy() + var/list/antagonists = GLOB.non_ruleset_antagonists.Copy() for (var/datum/dynamic_ruleset/ruleset as anything in subtypesof(/datum/dynamic_ruleset)) var/datum/antagonist/antagonist_type = initial(ruleset.antag_datum) diff --git a/code/modules/client/preferences/trans_prosthetic.dm b/code/modules/client/preferences/trans_prosthetic.dm new file mode 100644 index 00000000000..fd28cb1ecf8 --- /dev/null +++ b/code/modules/client/preferences/trans_prosthetic.dm @@ -0,0 +1,17 @@ +/datum/preference/choiced/trans_prosthetic + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "trans_prosthetic" + savefile_identifier = PREFERENCE_CHARACTER + +/datum/preference/choiced/trans_prosthetic/init_possible_values() + return list("Random") + GLOB.part_choice_transhuman + +/datum/preference/choiced/trans_prosthetic/is_accessible(datum/preferences/preferences) + . = ..() + if (!.) + return FALSE + + return "Transhumanist" in preferences.all_quirks + +/datum/preference/choiced/trans_prosthetic/apply_to_human(mob/living/carbon/human/target, value) + return diff --git a/code/modules/clothing/chameleon/chameleon_scanner.dm b/code/modules/clothing/chameleon/chameleon_scanner.dm index 343ceb5c001..5023997cefe 100644 --- a/code/modules/clothing/chameleon/chameleon_scanner.dm +++ b/code/modules/clothing/chameleon/chameleon_scanner.dm @@ -89,7 +89,7 @@ balloon_alert(scanner, "too far away!") return // Very short scan timer, keep you on your toes - if(!do_after(scanner, 0.5 SECONDS, scanned)) + if(!do_after(scanner, 0.5 SECONDS, scanned, hidden = TRUE)) return var/list/all_scanned_items = list() diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm index 51a0a795fc0..6d5e328b0d6 100644 --- a/code/modules/clothing/neck/_neck.dm +++ b/code/modules/clothing/neck/_neck.dm @@ -487,3 +487,23 @@ /obj/item/clothing/neck/beads/Initialize(mapload) . = ..() color = color = pick("#ff0077","#d400ff","#2600ff","#00ccff","#00ff2a","#e5ff00","#ffae00","#ff0000", "#ffffff") + +/obj/item/clothing/neck/wreath + name = "\improper Watcher Wreath" + desc = "An elaborate crown made from the twisted flesh and sinew of a watcher. \ + Wearing it makes you feel like you have eyes in the back of your head." + icon_state = "watcher_wreath" + worn_y_offset = 10 + alternate_worn_layer = ABOVE_BODY_FRONT_HEAD_LAYER + resistance_flags = FIRE_PROOF + +/obj/item/clothing/neck/wreath/worn_overlays(mutable_appearance/standing, isinhands, icon_file) + . = ..() + if(!isinhands) + . += emissive_appearance(icon_file, "wreath_emissive", src, alpha = src.alpha) + +/obj/item/clothing/neck/wreath/icewing + name = "\improper Icewing Wreath" + desc = "An elaborate crown made from the twisted flesh and sinew of an icewing watcher. \ + Wearing it sends shivers down your spine just from being near it." + icon_state = "icewing_wreath" diff --git a/code/modules/clothing/shoes/cowboy.dm b/code/modules/clothing/shoes/cowboy.dm index b7382584e57..73c5a9d0d95 100644 --- a/code/modules/clothing/shoes/cowboy.dm +++ b/code/modules/clothing/shoes/cowboy.dm @@ -4,8 +4,8 @@ icon_state = "cowboy_brown" armor_type = /datum/armor/shoes_cowboy custom_price = PAYCHECK_CREW - var/max_occupants = 4 can_be_tied = FALSE + var/max_occupants = 4 /// Do these boots have spur sounds? var/has_spurs = FALSE /// The jingle jangle jingle of our spurs diff --git a/code/modules/economy/holopay.dm b/code/modules/economy/holopay.dm index 3f11d096205..15247d19d57 100644 --- a/code/modules/economy/holopay.dm +++ b/code/modules/economy/holopay.dm @@ -65,9 +65,8 @@ if(BURN) playsound(loc, 'sound/weapons/egloves.ogg', 80, TRUE) -/obj/structure/holopay/deconstruct() +/obj/structure/holopay/atom_deconstruct(dissambled = TRUE) dissipate() - return ..() /obj/structure/holopay/Destroy() linked_card?.my_store = null diff --git a/code/modules/food_and_drinks/machinery/griddle.dm b/code/modules/food_and_drinks/machinery/griddle.dm index f997b049feb..b54a470897f 100644 --- a/code/modules/food_and_drinks/machinery/griddle.dm +++ b/code/modules/food_and_drinks/machinery/griddle.dm @@ -37,8 +37,6 @@ /obj/machinery/griddle/crowbar_act(mob/living/user, obj/item/I) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return if(default_deconstruction_crowbar(I, ignore_panel = TRUE)) return variant = rand(1,3) diff --git a/code/modules/holodeck/items.dm b/code/modules/holodeck/items.dm index eb0261739ad..3d80ef6d968 100644 --- a/code/modules/holodeck/items.dm +++ b/code/modules/holodeck/items.dm @@ -140,7 +140,7 @@ for (var/list/zlevel_turfs as anything in currentarea.get_zlevel_turf_lists()) for(var/turf/area_turf as anything in zlevel_turfs) for(var/obj/structure/window/barrier in area_turf) - if((barrier.obj_flags & NO_DECONSTRUCTION) || (barrier.flags_1 & HOLOGRAM_1))// Just in case: only holo-windows + if(barrier.flags_1 & HOLOGRAM_1)// Just in case: only holo-windows qdel(barrier) for(var/mob/contestant in area_turf) diff --git a/code/modules/hydroponics/beekeeping/beebox.dm b/code/modules/hydroponics/beekeeping/beebox.dm index 6636fedd25c..521afd6b539 100644 --- a/code/modules/hydroponics/beekeeping/beebox.dm +++ b/code/modules/hydroponics/beekeeping/beebox.dm @@ -249,7 +249,7 @@ visible_message(span_notice("[user] removes the queen from the apiary.")) queen_bee = null -/obj/structure/beebox/deconstruct(disassembled = TRUE) +/obj/structure/beebox/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/mineral/wood (loc, 20) for(var/mob/living/basic/bee/worker as anything in bees) if(worker.loc == src) @@ -260,7 +260,6 @@ if(frame.loc == src) frame.forceMove(get_turf(src)) honey_frames -= frame - qdel(src) /obj/structure/beebox/unwrenched anchored = FALSE diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index abe7dc4277b..ad12fa24e68 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -1164,6 +1164,12 @@ self_sustaining_overlay_icon_state = null maxnutri = 15 +/obj/machinery/hydroponics/soil/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) + return NONE + +/obj/machinery/hydroponics/soil/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct) + return NONE + /obj/machinery/hydroponics/soil/update_icon(updates=ALL) . = ..() if(self_sustaining) diff --git a/code/modules/library/bookcase.dm b/code/modules/library/bookcase.dm index be2beca42ba..822e4ae583c 100644 --- a/code/modules/library/bookcase.dm +++ b/code/modules/library/bookcase.dm @@ -172,14 +172,13 @@ choice.forceMove(drop_location()) update_appearance() -/obj/structure/bookcase/deconstruct(disassembled = TRUE) +/obj/structure/bookcase/atom_deconstruct(disassembled = TRUE) var/atom/Tsec = drop_location() new /obj/item/stack/sheet/mineral/wood(Tsec, 4) for(var/obj/item/I in contents) if(!isbook(I)) //Wake me up inside continue I.forceMove(Tsec) - return ..() /obj/structure/bookcase/update_icon_state() if(state == BOOKCASE_UNANCHORED || state == BOOKCASE_ANCHORED) diff --git a/code/modules/logging/log_holder.dm b/code/modules/logging/log_holder.dm index b378e4b8ef3..f246dfc4543 100644 --- a/code/modules/logging/log_holder.dm +++ b/code/modules/logging/log_holder.dm @@ -107,11 +107,10 @@ GENERAL_PROTECT_DATUM(/datum/log_holder) return switch(action) - if("re-render") + if("refresh") cache_ui_data() SStgui.update_uis(src) return TRUE - else stack_trace("unknown ui_act action [action] for [type]") diff --git a/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm b/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm index 97a543fa7e7..3c29a6a3945 100644 --- a/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm +++ b/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm @@ -107,7 +107,7 @@ /obj/structure/sink/oil_well/attackby(obj/item/O, mob/living/user, params) flick("puddle-oil-splash",src) - if(O.tool_behaviour == TOOL_SHOVEL && !(obj_flags & NO_DECONSTRUCTION)) //attempt to deconstruct the puddle with a shovel + if(O.tool_behaviour == TOOL_SHOVEL) //attempt to deconstruct the puddle with a shovel to_chat(user, "You fill in the oil well with soil.") O.play_tool_sound(src) deconstruct() diff --git a/code/modules/mapfluff/ruins/objects_and_mobs/ash_walker_den.dm b/code/modules/mapfluff/ruins/objects_and_mobs/ash_walker_den.dm index af694619898..4bfcd97e464 100644 --- a/code/modules/mapfluff/ruins/objects_and_mobs/ash_walker_den.dm +++ b/code/modules/mapfluff/ruins/objects_and_mobs/ash_walker_den.dm @@ -35,11 +35,10 @@ STOP_PROCESSING(SSprocessing, src) return ..() -/obj/structure/lavaland/ash_walker/deconstruct(disassembled) +/obj/structure/lavaland/ash_walker/atom_deconstruct(disassembled) var/core_to_drop = pick(subtypesof(/obj/item/assembly/signaler/anomaly)) new core_to_drop (get_step(loc, pick(GLOB.alldirs))) new /obj/effect/collapse(loc) - return ..() /obj/structure/lavaland/ash_walker/process() consume() diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm index ce42eaa43c2..5022dac212c 100644 --- a/code/modules/mining/abandoned_crates.dm +++ b/code/modules/mining/abandoned_crates.dm @@ -121,7 +121,7 @@ return return ..() -/obj/structure/closet/crate/secure/loot/deconstruct(disassembled = TRUE) +/obj/structure/closet/crate/secure/loot/atom_deconstruct(disassembled = TRUE) if(locked) boom() return diff --git a/code/modules/mining/equipment/marker_beacons.dm b/code/modules/mining/equipment/marker_beacons.dm index 67eb767f767..38dda48d345 100644 --- a/code/modules/mining/equipment/marker_beacons.dm +++ b/code/modules/mining/equipment/marker_beacons.dm @@ -99,12 +99,10 @@ GLOBAL_LIST_INIT(marker_beacon_colors, sort_list(list( picked_color = set_color update_appearance() -/obj/structure/marker_beacon/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/obj/item/stack/marker_beacon/M = new(loc) - M.picked_color = picked_color - M.update_appearance() - qdel(src) +/obj/structure/marker_beacon/atom_deconstruct(disassembled = TRUE) + var/obj/item/stack/marker_beacon/beacon = new(loc) + beacon.picked_color = picked_color + beacon.update_appearance() /obj/structure/marker_beacon/examine(mob/user) . = ..() diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm index f4463434066..d40589dd3f8 100644 --- a/code/modules/mining/equipment/survival_pod.dm +++ b/code/modules/mining/equipment/survival_pod.dm @@ -214,8 +214,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/door/window/survival_pod/left, 0) /obj/item/gps/computer/wrench_act(mob/living/user, obj/item/I) ..() - if(obj_flags & NO_DECONSTRUCTION) - return TRUE user.visible_message(span_warning("[user] disassembles [src]."), span_notice("You start to disassemble [src]..."), span_hear("You hear clanking and banging noises.")) diff --git a/code/modules/mining/satchel_ore_box.dm b/code/modules/mining/satchel_ore_box.dm index 3b2a5ce054c..b94796b1614 100644 --- a/code/modules/mining/satchel_ore_box.dm +++ b/code/modules/mining/satchel_ore_box.dm @@ -19,13 +19,11 @@ for(var/obj/item/weapon in src) weapon.forceMove(drop) -/obj/structure/ore_box/deconstruct(disassembled = TRUE) +/obj/structure/ore_box/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/mineral/wood(loc, 4) dump_box_contents() - return ..() - /obj/structure/ore_box/add_context(atom/source, list/context, obj/item/held_item, mob/user) . = NONE if(isnull(held_item)) diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm index 615eb55898c..30d273db7da 100644 --- a/code/modules/mob/dead/dead.dm +++ b/code/modules/mob/dead/dead.dm @@ -90,16 +90,20 @@ INITIALIZE_IMMEDIATE(/mob/dead) #undef SERVER_HOPPER_TRAIT -/mob/dead/proc/update_z(new_z) // 1+ to register, null to unregister - if (registered_z != new_z) - if (registered_z) - SSmobs.dead_players_by_zlevel[registered_z] -= src - if (client) - if (new_z) - SSmobs.dead_players_by_zlevel[new_z] += src - registered_z = new_z - else - registered_z = null +/** + * updates the Z level for dead players + * If they don't have a new z, we'll keep the old one, preventing bugs from ghosting and re-entering, among others + */ +/mob/dead/proc/update_z(new_z) + if(registered_z == new_z) + return + if(registered_z) + SSmobs.dead_players_by_zlevel[registered_z] -= src + if(isnull(client)) + registered_z = null + return + registered_z = new_z + SSmobs.dead_players_by_zlevel[new_z] += src /mob/dead/Login() . = ..() diff --git a/code/modules/mob/dead/observer/login.dm b/code/modules/mob/dead/observer/login.dm index 4135f8d22fa..c239817a30e 100644 --- a/code/modules/mob/dead/observer/login.dm +++ b/code/modules/mob/dead/observer/login.dm @@ -14,10 +14,6 @@ preferred_form = client.prefs.read_preference(/datum/preference/choiced/ghost_form) ghost_orbit = client.prefs.read_preference(/datum/preference/choiced/ghost_orbit) - var/turf/T = get_turf(src) - if (isturf(T)) - update_z(T.z) - update_icon(ALL, preferred_form) updateghostimages() client.set_right_click_menu_mode(FALSE) diff --git a/code/modules/mob/dead/observer/logout.dm b/code/modules/mob/dead/observer/logout.dm index 4ba701c0ae0..53db92d91e3 100644 --- a/code/modules/mob/dead/observer/logout.dm +++ b/code/modules/mob/dead/observer/logout.dm @@ -1,5 +1,4 @@ /mob/dead/observer/Logout() - update_z(null) if (client) client.images -= (GLOB.ghost_images_default+GLOB.ghost_images_simple) diff --git a/code/modules/mob/living/basic/lavaland/gutlunchers/gutluncher_foodtrough.dm b/code/modules/mob/living/basic/lavaland/gutlunchers/gutluncher_foodtrough.dm index 1ac43c13eb4..734d431912f 100644 --- a/code/modules/mob/living/basic/lavaland/gutlunchers/gutluncher_foodtrough.dm +++ b/code/modules/mob/living/basic/lavaland/gutlunchers/gutluncher_foodtrough.dm @@ -22,11 +22,8 @@ list_of_materials -= mover.type return ..() -/obj/structure/ore_container/gutlunch_trough/deconstruct(disassembled = TRUE) - if(obj_flags & NO_DECONSTRUCTION) - return +/obj/structure/ore_container/gutlunch_trough/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/mineral/wood(drop_location(), 5) - qdel(src) /obj/structure/ore_container/gutlunch_trough/update_overlays() . = ..() diff --git a/code/modules/mob/living/basic/ruin_defender/flesh.dm b/code/modules/mob/living/basic/ruin_defender/flesh.dm index e33cdcad1a1..17d625cb591 100644 --- a/code/modules/mob/living/basic/ruin_defender/flesh.dm +++ b/code/modules/mob/living/basic/ruin_defender/flesh.dm @@ -40,7 +40,11 @@ /mob/living/basic/living_limb_flesh/Destroy(force) . = ..() - QDEL_NULL(current_bodypart) + if(current_bodypart) + var/obj/item/bodypart/bodypart = current_bodypart + unregister_from_limb(current_bodypart.owner) + if(!QDELETED(bodypart)) + qdel(bodypart) /mob/living/basic/living_limb_flesh/Life(seconds_per_tick = SSMOBS_DT, times_fired) . = ..() @@ -119,16 +123,10 @@ part_type = /obj/item/bodypart/leg/right/flesh target.visible_message(span_danger("[src] [target_part ? "tears off and attaches itself" : "attaches itself"] to where [target][target.p_s()] limb used to be!")) - current_bodypart = new part_type(TRUE) //dont_spawn_flesh, we cant use named arguments here - current_bodypart.replace_limb(target, TRUE) - forceMove(current_bodypart) - register_to_limb(current_bodypart) - -/mob/living/basic/living_limb_flesh/proc/register_to_limb(obj/item/bodypart/part) - ai_controller.set_ai_status(AI_STATUS_OFF) - RegisterSignal(part, COMSIG_BODYPART_REMOVED, PROC_REF(on_limb_lost)) - RegisterSignal(part.owner, COMSIG_LIVING_DEATH, PROC_REF(owner_died)) - RegisterSignal(part.owner, COMSIG_LIVING_ELECTROCUTE_ACT, PROC_REF(owner_shocked)) //detach if we are shocked, not beneficial for the host but hey its a sideeffect + var/obj/item/bodypart/new_bodypart = new part_type(TRUE) //dont_spawn_flesh, we cant use named arguments here + new_bodypart.replace_limb(target, TRUE) + forceMove(new_bodypart) + register_to_limb(new_bodypart) /mob/living/basic/living_limb_flesh/proc/owner_shocked(datum/source, shock_damage, shock_source, siemens_coeff, flags) SIGNAL_HANDLER @@ -154,15 +152,28 @@ /mob/living/basic/living_limb_flesh/proc/on_limb_lost(atom/movable/source, mob/living/carbon/old_owner, special, dismembered) SIGNAL_HANDLER - UnregisterSignal(source, COMSIG_BODYPART_REMOVED) - UnregisterSignal(old_owner, COMSIG_LIVING_ELECTROCUTE_ACT) - UnregisterSignal(old_owner, COMSIG_LIVING_DEATH) + unregister_from_limb(old_owner) addtimer(CALLBACK(src, PROC_REF(wake_up), source), 2 SECONDS) -/mob/living/basic/living_limb_flesh/proc/wake_up(atom/limb) - ai_controller.set_ai_status(AI_STATUS_ON) - forceMove(limb.drop_location()) +/mob/living/basic/living_limb_flesh/proc/register_to_limb(obj/item/bodypart/part) + current_bodypart = part + ai_controller.set_ai_status(AI_STATUS_OFF) + RegisterSignal(current_bodypart, COMSIG_BODYPART_REMOVED, PROC_REF(on_limb_lost)) + if(current_bodypart.owner) + RegisterSignal(current_bodypart.owner, COMSIG_LIVING_DEATH, PROC_REF(owner_died)) + RegisterSignal(current_bodypart.owner, COMSIG_LIVING_ELECTROCUTE_ACT, PROC_REF(owner_shocked)) //detach if we are shocked, not beneficial for the host but hey its a sideeffect + +/mob/living/basic/living_limb_flesh/proc/unregister_from_limb(mob/living/carbon/removing_owner) + UnregisterSignal(current_bodypart, COMSIG_BODYPART_REMOVED) + if(removing_owner) + UnregisterSignal(removing_owner, COMSIG_LIVING_ELECTROCUTE_ACT) + UnregisterSignal(removing_owner, COMSIG_LIVING_DEATH) current_bodypart = null - qdel(limb) + +/mob/living/basic/living_limb_flesh/proc/wake_up(atom/limb) visible_message(span_warning("[src] begins flailing around!")) Shake(6, 6, 0.5 SECONDS) + ai_controller.set_ai_status(AI_STATUS_ON) + forceMove(limb.drop_location()) + qdel(limb) + diff --git a/code/modules/mob/living/basic/slime/defense.dm b/code/modules/mob/living/basic/slime/defense.dm index 17bd22b905a..b747c242019 100644 --- a/code/modules/mob/living/basic/slime/defense.dm +++ b/code/modules/mob/living/basic/slime/defense.dm @@ -31,7 +31,7 @@ return //Checks if the item passes through the slime first. Safe items can be used simply - if(check_item_passthrough(attacking_item)) + if(check_item_passthrough(attacking_item, user)) return try_discipline_slime(attacking_item) diff --git a/code/modules/mob/living/brain/MMI.dm b/code/modules/mob/living/brain/MMI.dm index 74e5931163b..56693b20b36 100644 --- a/code/modules/mob/living/brain/MMI.dm +++ b/code/modules/mob/living/brain/MMI.dm @@ -289,10 +289,9 @@ brainmob.emp_damage = min(brainmob.emp_damage + rand(0,10), 30) brainmob.emote("alarm") -/obj/item/mmi/deconstruct(disassembled = TRUE) +/obj/item/mmi/atom_deconstruct(disassembled = TRUE) if(brain) eject_brain() - qdel(src) /obj/item/mmi/examine(mob/user) . = ..() diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index bbb3c980ca8..6af6bac4d4c 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1479,3 +1479,10 @@ if(!unwagged) return FALSE return unwagged.stop_wag(src) + +/mob/living/carbon/itch(obj/item/bodypart/target_part = null, damage = 0.5, can_scratch = TRUE, silent = FALSE) + if (isnull(target_part)) + target_part = get_bodypart(get_random_valid_zone(even_weights = TRUE)) + if (!IS_ORGANIC_LIMB(target_part) || (target_part.bodypart_flags & BODYPART_PSEUDOPART)) + return FALSE + return ..() diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index d9e041e1ec9..4fbaefef165 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -1217,25 +1217,12 @@ GLOBAL_LIST_EMPTY(features_by_species) target.force_say() log_combat(user, target, grappled ? "grapple punched" : "kicked") target.apply_damage(damage, attack_type, affecting, armor_block - limb_accuracy, attack_direction = attack_direction) - target.apply_damage(damage*1.5, STAMINA, affecting, armor_block - limb_accuracy) else // Normal attacks do not gain the benefit of armor penetration. target.apply_damage(damage, attack_type, affecting, armor_block, attack_direction = attack_direction, sharpness = unarmed_sharpness) //SKYRAT EDIT - Applies sharpness if it does - ORIGINAL: target.apply_damage(damage, attack_type, affecting, armor_block, attack_direction = attack_direction) - target.apply_damage(damage*1.5, STAMINA, affecting, armor_block) if(damage >= 9) target.force_say() log_combat(user, target, "punched") - //If we rolled a punch high enough to hit our stun threshold, or our target is staggered and they have at least 40 damage+stamina loss, we knock them down - //This does not work against opponents who are knockdown immune, such as from wearing riot armor. - if(!HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) - if((target.stat != DEAD) && prob(limb_accuracy) || (target.stat != DEAD) && staggered && (target.getStaminaLoss() + user.getBruteLoss()) >= 40) - target.visible_message(span_danger("[user] knocks [target] down!"), \ - span_userdanger("You're knocked down by [user]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, user) - to_chat(user, span_danger("You knock [target] down!")) - var/knockdown_duration = 4 SECONDS + (target.getStaminaLoss() + (target.getBruteLoss()*0.5))*0.8 //50 total damage = 4 second base stun + 4 second stun modifier = 8 second knockdown duration - target.apply_effect(knockdown_duration, EFFECT_KNOCKDOWN, armor_block) - log_combat(user, target, "got a stun punch with their previous punch") - /datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) if(user.body_position != STANDING_UP) return FALSE diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm index 7c41b25efb6..f45fcf20111 100644 --- a/code/modules/mob/living/carbon/human/species_types/felinid.dm +++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm @@ -40,11 +40,19 @@ target_human.dna.features["tail_cat"] = "Cat" if(target_human.dna.features["ears"] == "None") target_human.dna.features["ears"] = "Cat" + /* SKYRAT EDIT -- START -- ORIGINAL + if(target_human.dna.features["ears"] == "None") + mutantears = /obj/item/organ/internal/ears + else + var/obj/item/organ/internal/ears/cat/ears = new(FALSE, target_human.dna.features["ears"]) + ears.Insert(target_human, movement_flags = DELETE_IF_REPLACED) + */ if(target_human.dna.features["ears"] == "Cat") var/obj/item/organ/internal/ears/cat/ears = new ears.Insert(target_human, movement_flags = DELETE_IF_REPLACED) else mutantears = /obj/item/organ/internal/ears + // SKYRAT EDIT -- END return ..() /datum/species/human/felinid/randomize_features(mob/living/carbon/human/human_mob) diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index 1cf8b67db5d..ba6e9619a2f 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -62,6 +62,7 @@ /datum/outfit/syndicate/reinforcement/interdyne = /datum/outfit/syndicate/reinforcement/plasmaman, /datum/outfit/syndicate/reinforcement/mi13 = /datum/outfit/syndicate/reinforcement/plasmaman, /datum/outfit/syndicate/reinforcement/waffle = /datum/outfit/syndicate/reinforcement/plasmaman, + /datum/outfit/syndicate/support = /datum/outfit/syndicate/support/plasmaman, ) /// If the bones themselves are burning clothes won't help you much 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 fbd56846ecb..111b35cb7f7 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -186,7 +186,7 @@ victim.show_message(span_warning("[H] tries to bite you, but recoils in disgust!")) to_chat(H, span_warning("[victim] reeks of garlic! you can't bring yourself to drain such tainted blood.")) return - if(!do_after(H, 3 SECONDS, target = victim)) + if(!do_after(H, 3 SECONDS, target = victim, hidden = TRUE)) return var/blood_volume_difference = BLOOD_VOLUME_MAXIMUM - H.blood_volume //How much capacity we have left to absorb blood var/drained_blood = min(victim.blood_volume, VAMP_DRAIN_AMOUNT, blood_volume_difference) diff --git a/code/modules/mob/living/carbon/status_procs.dm b/code/modules/mob/living/carbon/status_procs.dm index b9b5fd0b365..fd9bd8f2c5a 100644 --- a/code/modules/mob/living/carbon/status_procs.dm +++ b/code/modules/mob/living/carbon/status_procs.dm @@ -10,6 +10,7 @@ return if(check_stun_immunity(CANKNOCKDOWN)) return + SEND_SIGNAL(src, COMSIG_CARBON_ENTER_STAMCRIT) to_chat(src, span_notice("You're too exhausted to keep going...")) add_traits(list(TRAIT_INCAPACITATED, TRAIT_IMMOBILIZED, TRAIT_FLOORED), STAMINA) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 9ef879f016d..c0763a67e01 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1125,6 +1125,20 @@ else return pick("trails_1", "trails_2") +/// Print a message about an annoying sensation you are feeling. Returns TRUE if successful. +/mob/living/proc/itch(obj/item/bodypart/target_part = null, damage = 0.5, can_scratch = TRUE, silent = FALSE) + if ((mob_biotypes & (MOB_ROBOTIC | MOB_SPIRIT))) + return FALSE + var/will_scratch = can_scratch && !incapacitated() + var/applied_damage = 0 + if (will_scratch && damage) + applied_damage = apply_damage(damage, damagetype = BRUTE, def_zone = target_part) + if (silent) + return applied_damage > 0 + var/visible_part = isnull(target_part) ? "side" : target_part.plaintext_zone + visible_message("[can_scratch ? span_warning("[src] scratches [p_their()] [visible_part].") : ""]", span_warning("Your [visible_part] itches. [can_scratch ? "You scratch it." : ""]")) + return TRUE + /mob/living/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta = 0) playsound(src, 'sound/effects/space_wind.ogg', 50, TRUE) if(buckled || mob_negates_gravity()) @@ -1822,32 +1836,34 @@ GLOBAL_LIST_EMPTY(fire_appearances) /mob/living/proc/update_z(new_z) // 1+ to register, null to unregister - if (registered_z != new_z) - if (registered_z) - SSmobs.clients_by_zlevel[registered_z] -= src - if (client) - if (new_z) - //Figure out how many clients were here before - var/oldlen = SSmobs.clients_by_zlevel[new_z].len - SSmobs.clients_by_zlevel[new_z] += src - for (var/I in length(SSidlenpcpool.idle_mobs_by_zlevel[new_z]) to 1 step -1) //Backwards loop because we're removing (guarantees optimal rather than worst-case performance), it's fine to use .len here but doesn't compile on 511 - var/mob/living/simple_animal/SA = SSidlenpcpool.idle_mobs_by_zlevel[new_z][I] - if (SA) - if(oldlen == 0) - //Start AI idle if nobody else was on this z level before (mobs will switch off when this is the case) - SA.toggle_ai(AI_IDLE) + if(registered_z == new_z) + return + if(registered_z) + SSmobs.clients_by_zlevel[registered_z] -= src + if(isnull(client)) + registered_z = null + return - //If they are also within a close distance ask the AI if it wants to wake up - if(get_dist(get_turf(src), get_turf(SA)) < MAX_SIMPLEMOB_WAKEUP_RANGE) - SA.consider_wakeup() // Ask the mob if it wants to turn on it's AI - //They should clean up in destroy, but often don't so we get them here - else - SSidlenpcpool.idle_mobs_by_zlevel[new_z] -= SA + //Check the amount of clients exists on the Z level we're leaving from, + //this excludes us as we haven't added ourselves to the new z level yet. + var/old_level_new_clients = (registered_z ? SSmobs.clients_by_zlevel[registered_z].len : null) + //No one is left after we're gone, shut off inactive ones + if(registered_z && old_level_new_clients == 0) + for(var/datum/ai_controller/controller as anything in SSai_controllers.ai_controllers_by_zlevel[registered_z]) + controller.set_ai_status(AI_STATUS_OFF) + + //Check the amount of clients exists on the Z level we're moving towards, excluding ourselves. + var/new_level_old_clients = SSmobs.clients_by_zlevel[new_z].len + registered_z = new_z + //We'll add ourselves to the list now so get_expected_ai_status() will know we're on the z level. + SSmobs.clients_by_zlevel[registered_z] += src - registered_z = new_z - else - registered_z = null + if(new_level_old_clients == 0) //No one was here before, wake up all the AIs. + for (var/datum/ai_controller/controller as anything in SSai_controllers.ai_controllers_by_zlevel[new_z]) + //We don't set them directly on, for instances like AIs acting while dead and other cases that may exist in the future. + //This isn't a problem for AIs with a client since the client will prevent this from being called anyway. + controller.set_ai_status(controller.get_expected_ai_status()) /mob/living/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents) ..() diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index e8d2fd6be50..3ff8f04fb92 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -616,29 +616,6 @@ value = initial(search_objects) search_objects = value -/mob/living/simple_animal/hostile/consider_wakeup() - ..() - var/list/tlist - var/turf/T = get_turf(src) - - if (!T) - return - - if (!length(SSmobs.clients_by_zlevel[T.z])) // It's fine to use .len here but doesn't compile on 511 - toggle_ai(AI_Z_OFF) - return - - var/cheap_search = isturf(T) && !is_station_level(T.z) - if (cheap_search) - tlist = ListTargetsLazy(T.z) - else - tlist = ListTargets() - - if(AIStatus == AI_IDLE && FindTarget(tlist)) - if(cheap_search) //Try again with full effort - FindTarget() - toggle_ai(AI_ON) - /mob/living/simple_animal/hostile/proc/ListTargetsLazy(_Z)//Step 1, find out what we can see var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/vehicle/sealed/mecha)) . = list() diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 1c1ea138d23..47d3ddcf20f 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -131,7 +131,7 @@ ///Played when someone punches the creature. var/attacked_sound = SFX_PUNCH - ///The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever), AI_Z_OFF (Temporarily off due to nonpresence of players). + ///The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever). var/AIStatus = AI_ON ///once we have become sentient, we can never go back. var/can_have_ai = TRUE @@ -221,10 +221,6 @@ GLOB.simple_animals[AIStatus] -= src SSnpcpool.currentrun -= src - var/turf/T = get_turf(src) - if (T && AIStatus == AI_Z_OFF) - SSidlenpcpool.idle_mobs_by_zlevel[T.z] -= src - return ..() /mob/living/simple_animal/examine(mob/user) @@ -514,29 +510,12 @@ return if (AIStatus != togglestatus) if (togglestatus > 0 && togglestatus < 5) - if (togglestatus == AI_Z_OFF || AIStatus == AI_Z_OFF) - var/turf/T = get_turf(src) - if (T) - if (AIStatus == AI_Z_OFF) - SSidlenpcpool.idle_mobs_by_zlevel[T.z] -= src - else - SSidlenpcpool.idle_mobs_by_zlevel[T.z] += src GLOB.simple_animals[AIStatus] -= src GLOB.simple_animals[togglestatus] += src AIStatus = togglestatus else stack_trace("Something attempted to set simple animals AI to an invalid state: [togglestatus]") -/mob/living/simple_animal/proc/consider_wakeup() - if (pulledby || shouldwakeup) - toggle_ai(AI_ON) - -/mob/living/simple_animal/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents) - ..() - if (old_turf && AIStatus == AI_Z_OFF) - SSidlenpcpool.idle_mobs_by_zlevel[old_turf.z] -= src - toggle_ai(initial(AIStatus)) - ///This proc is used for adding the swabbale element to mobs so that they are able to be biopsied and making sure holograpic and butter-based creatures don't yield viable cells samples. /mob/living/simple_animal/proc/add_cell_sample() return diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 7da01f047ef..44d0db90355 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -164,7 +164,7 @@ ///Allows a datum to intercept all click calls this mob is the source of var/datum/click_intercept - ///THe z level this mob is currently registered in + ///The z level this mob is currently registered in var/registered_z = null var/memory_throttle_time = 0 diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm index 8c652b5b55c..c63441124ae 100644 --- a/code/modules/modular_computers/computers/item/computer.dm +++ b/code/modules/modular_computers/computers/item/computer.dm @@ -901,20 +901,18 @@ update_appearance() return ITEM_INTERACT_SUCCESS -/obj/item/modular_computer/deconstruct(disassembled = TRUE) +/obj/item/modular_computer/atom_deconstruct(disassembled = TRUE) remove_pai() eject_aicard() - if(!(obj_flags & NO_DECONSTRUCTION)) - if (disassembled) - internal_cell?.forceMove(drop_location()) - computer_id_slot?.forceMove(drop_location()) - inserted_disk?.forceMove(drop_location()) - new /obj/item/stack/sheet/iron(drop_location(), steel_sheet_cost) - else - physical.visible_message(span_notice("\The [src] breaks apart!")) - new /obj/item/stack/sheet/iron(drop_location(), round(steel_sheet_cost * 0.5)) + if (disassembled) + internal_cell?.forceMove(drop_location()) + computer_id_slot?.forceMove(drop_location()) + inserted_disk?.forceMove(drop_location()) + new /obj/item/stack/sheet/iron(drop_location(), steel_sheet_cost) + else + physical.visible_message(span_notice("\The [src] breaks apart!")) + new /obj/item/stack/sheet/iron(drop_location(), round(steel_sheet_cost * 0.5)) relay_qdel() - return ..() // Ejects the inserted intellicard, if one exists. Used when the computer is deconstructed. /obj/item/modular_computer/proc/eject_aicard() diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm index 7fbd4e1db85..70e930ca31e 100644 --- a/code/modules/paperwork/filingcabinet.dm +++ b/code/modules/paperwork/filingcabinet.dm @@ -37,12 +37,10 @@ if(I.w_class < WEIGHT_CLASS_NORMAL) //there probably shouldn't be anything placed ontop of filing cabinets in a map that isn't meant to go in them I.forceMove(src) -/obj/structure/filingcabinet/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/iron(loc, 2) - for(var/obj/item/I in src) - I.forceMove(loc) - qdel(src) +/obj/structure/filingcabinet/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/iron(loc, 2) + for(var/obj/item/obj in src) + obj.forceMove(loc) /obj/structure/filingcabinet/attackby(obj/item/P, mob/living/user, params) var/list/modifiers = params2list(params) diff --git a/code/modules/paperwork/paper_cutter.dm b/code/modules/paperwork/paper_cutter.dm index 9878249a6d1..ae93a1daad8 100644 --- a/code/modules/paperwork/paper_cutter.dm +++ b/code/modules/paperwork/paper_cutter.dm @@ -61,8 +61,7 @@ return CONTEXTUAL_SCREENTIP_SET -/obj/item/papercutter/deconstruct(disassembled) - ..() +/obj/item/papercutter/atom_deconstruct(disassembled) if(!disassembled) return diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm index 86db803322f..3d7177dcb3e 100644 --- a/code/modules/paperwork/paperbin.dm +++ b/code/modules/paperwork/paperbin.dm @@ -240,7 +240,7 @@ if(total_paper == 0) deconstruct(FALSE) -/obj/item/paper_bin/bundlenatural/deconstruct(disassembled) +/obj/item/paper_bin/bundlenatural/atom_deconstruct(disassembled) dump_contents(drop_location()) return ..() diff --git a/code/modules/photography/photos/frame.dm b/code/modules/photography/photos/frame.dm index 4fbe3e034d8..9efde283e07 100644 --- a/code/modules/photography/photos/frame.dm +++ b/code/modules/photography/photos/frame.dm @@ -173,18 +173,15 @@ if(framed) . += framed -/obj/structure/sign/picture_frame/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/obj/item/wallframe/picture/F = new /obj/item/wallframe/picture(loc) - if(framed) - F.displayed = framed - set_and_save_framed(null) - if(contents.len) - var/obj/item/I = pick(contents) - I.forceMove(F) - F.update_appearance() - qdel(src) - +/obj/structure/sign/picture_frame/atom_deconstruct(disassembled = TRUE) + var/obj/item/wallframe/picture/showcase = new /obj/item/wallframe/picture(loc) + if(framed) + showcase.displayed = framed + set_and_save_framed(null) + if(contents.len) + var/obj/item/I = pick(contents) + I.forceMove(showcase) + showcase.update_appearance() /obj/structure/sign/picture_frame/showroom name = "distinguished crew display" diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index fc40b074fae..fd5752fea68 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -141,11 +141,9 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri return ..() // then go ahead and delete the cable -/obj/structure/cable/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/obj/item/stack/cable_coil/cable = new(drop_location(), 1) - cable.set_cable_color(cable_color) - qdel(src) +/obj/structure/cable/atom_deconstruct(disassembled = TRUE) + var/obj/item/stack/cable_coil/cable = new(drop_location(), 1) + cable.set_cable_color(cable_color) /////////////////////////////////// // General procedures @@ -637,6 +635,9 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri /obj/item/stack/cable_coil/five amount = 5 +/obj/item/stack/cable_coil/thirty + amount = 30 + /obj/item/stack/cable_coil/cut amount = null icon_state = "coil2" diff --git a/code/modules/power/lighting/light_construct.dm b/code/modules/power/lighting/light_construct.dm index 905ae72c2e3..8b79c33d69b 100644 --- a/code/modules/power/lighting/light_construct.dm +++ b/code/modules/power/lighting/light_construct.dm @@ -162,10 +162,8 @@ if(attacking_blob && attacking_blob.loc == loc) qdel(src) -/obj/structure/light_construct/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/iron(loc, sheets_refunded) - qdel(src) +/obj/structure/light_construct/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/iron(loc, sheets_refunded) /obj/structure/light_construct/small name = "small light fixture frame" diff --git a/code/modules/power/pipecleaners.dm b/code/modules/power/pipecleaners.dm index 2f18bab660a..2a41c70bdfe 100644 --- a/code/modules/power/pipecleaners.dm +++ b/code/modules/power/pipecleaners.dm @@ -106,15 +106,13 @@ By design, d1 is the smallest direction and d2 is the highest QDEL_NULL(stored) return ..() // then go ahead and delete the pipe_cleaner -/obj/structure/pipe_cleaner/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/turf/T = get_turf(loc) - if(T) - stored.forceMove(T) - stored = null - else - qdel(stored) - qdel(src) +/obj/structure/pipe_cleaner/atom_deconstruct(disassembled = TRUE) + var/turf/location = get_turf(loc) + if(location) + stored.forceMove(location) + stored = null + else + qdel(stored) /////////////////////////////////// // General procedures diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index 81964996845..80afcc534b0 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -689,8 +689,7 @@ /obj/machinery/chem_dispenser/drinks/fullupgrade //fully ugpraded stock parts, emagged desc = "Contains a large reservoir of soft drinks. This model has had its safeties shorted out." - obj_flags = CAN_BE_HIT | EMAGGED | NO_DECONSTRUCTION - circuit = /obj/item/circuitboard/machine/chem_dispenser/drinks/fullupgrade + obj_flags = CAN_BE_HIT | EMAGGED /obj/machinery/chem_dispenser/drinks/fullupgrade/Initialize(mapload) . = ..() @@ -752,7 +751,7 @@ /obj/machinery/chem_dispenser/drinks/beer/fullupgrade //fully ugpraded stock parts, emagged desc = "Contains a large reservoir of the good stuff. This model has had its safeties shorted out." - obj_flags = CAN_BE_HIT | EMAGGED | NO_DECONSTRUCTION + obj_flags = CAN_BE_HIT | EMAGGED circuit = /obj/item/circuitboard/machine/chem_dispenser/drinks/beer/fullupgrade /obj/machinery/chem_dispenser/drinks/beer/fullupgrade/Initialize(mapload) @@ -776,7 +775,6 @@ /obj/machinery/chem_dispenser/mutagensaltpeter name = "botanical chemical dispenser" desc = "Creates and dispenses chemicals useful for botany." - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION circuit = /obj/item/circuitboard/machine/chem_dispenser/mutagensaltpeter /// The default list of dispensable reagents available in the mutagensaltpeter chem dispenser @@ -802,7 +800,7 @@ /obj/machinery/chem_dispenser/fullupgrade //fully ugpraded stock parts, emagged desc = "Creates and dispenses chemicals. This model has had its safeties shorted out." - obj_flags = CAN_BE_HIT | EMAGGED | NO_DECONSTRUCTION + obj_flags = CAN_BE_HIT | EMAGGED circuit = /obj/item/circuitboard/machine/chem_dispenser/fullupgrade /obj/machinery/chem_dispenser/fullupgrade/Initialize(mapload) diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index 7f316a05f79..bcdee284bd7 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -753,19 +753,20 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/toxin/itching_powder/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - var/need_mob_update = FALSE - if(SPT_PROB(8, seconds_per_tick)) - to_chat(affected_mob, span_danger("You scratch at your head.")) - need_mob_update += affected_mob.adjustBruteLoss(0.2*REM, FALSE, required_bodytype = affected_bodytype) - if(SPT_PROB(8, seconds_per_tick)) - to_chat(affected_mob, span_danger("You scratch at your leg.")) - need_mob_update += affected_mob.adjustBruteLoss(0.2*REM, FALSE, required_bodytype = affected_bodytype) - if(SPT_PROB(8, seconds_per_tick)) - to_chat(affected_mob, span_danger("You scratch at your arm.")) - need_mob_update += affected_mob.adjustBruteLoss(0.2*REM, FALSE, required_bodytype = affected_bodytype) + var/scratched = FALSE + var/scratch_damage = 0.2 * REM - if(need_mob_update) - . = UPDATE_MOB_HEALTH + var/obj/item/bodypart/head = affected_mob.get_bodypart(BODY_ZONE_HEAD) + if(!isnull(head) && SPT_PROB(8, seconds_per_tick)) + scratched = affected_mob.itch(damage = scratch_damage, target_part = head) + + var/obj/item/bodypart/leg = affected_mob.get_bodypart(pick(BODY_ZONE_L_LEG,BODY_ZONE_R_LEG)) + if(!isnull(leg) && SPT_PROB(8, seconds_per_tick)) + scratched = affected_mob.itch(damage = scratch_damage, target_part = leg, silent = scratched) || scratched + + var/obj/item/bodypart/arm = affected_mob.get_bodypart(pick(BODY_ZONE_L_ARM,BODY_ZONE_R_ARM)) + if(!isnull(arm) && SPT_PROB(8, seconds_per_tick)) + scratched = affected_mob.itch(damage = scratch_damage, target_part = arm, silent = scratched) || scratched if(SPT_PROB(1.5, seconds_per_tick)) holder.add_reagent(/datum/reagent/toxin/histamine,rand(1,3)) diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 4cbb4839416..c4cd57b1568 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -122,7 +122,7 @@ has_variable_transfer_amount = FALSE volume = 15 ignore_flags = 1 //so you can medipen through spacesuits - reagent_flags = DRAWABLE + reagent_flags = NONE flags_1 = null list_reagents = list(/datum/reagent/medicine/epinephrine = 10, /datum/reagent/toxin/formaldehyde = 3, /datum/reagent/medicine/coagulant = 2) custom_price = PAYCHECK_CREW @@ -312,7 +312,6 @@ base_icon_state = "gorillapen" volume = 5 ignore_flags = 0 - reagent_flags = NONE list_reagents = list(/datum/reagent/magillitis = 5) /obj/item/reagent_containers/hypospray/medipen/pumpup diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index 02ad176e8e0..d9ce792f1a0 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -199,12 +199,9 @@ explosion(src, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 6, flame_range = 8) qdel(src) -/obj/structure/reagent_dispensers/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(!disassembled) - boom() - else - qdel(src) +/obj/structure/reagent_dispensers/atom_deconstruct(disassembled = TRUE) + if(!disassembled) + boom() /obj/structure/reagent_dispensers/proc/tank_leak() if(leaking && reagents && reagents.total_volume >= amount_to_leak) diff --git a/code/modules/recycling/disposal/pipe.dm b/code/modules/recycling/disposal/pipe.dm index 69519874cd2..9a1ad786e72 100644 --- a/code/modules/recycling/disposal/pipe.dm +++ b/code/modules/recycling/disposal/pipe.dm @@ -170,27 +170,24 @@ return TRUE // called when pipe is cut with welder -/obj/structure/disposalpipe/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - if(spawn_pipe) - var/obj/structure/disposalconstruct/construct = stored - if(!construct) // Don't have something? Make one now - construct = new /obj/structure/disposalconstruct(src, null, SOUTH, FALSE, src) - stored = null - construct.forceMove(loc) - transfer_fingerprints_to(construct) - construct.setDir(dir) - spawn_pipe = FALSE - else - var/turf/T = get_turf(src) - for(var/D in GLOB.cardinals) - if(D & dpdir) - var/obj/structure/disposalpipe/broken/P = new(T) - P.setDir(D) +/obj/structure/disposalpipe/atom_deconstruct(disassembled = TRUE) + if(disassembled) + if(spawn_pipe) + var/obj/structure/disposalconstruct/construct = stored + if(!construct) // Don't have something? Make one now + construct = new /obj/structure/disposalconstruct(src, null, SOUTH, FALSE, src) + stored = null + construct.forceMove(loc) + transfer_fingerprints_to(construct) + construct.setDir(dir) + spawn_pipe = FALSE + else + var/turf/location = get_turf(src) + for(var/dir in GLOB.cardinals) + if(dir & dpdir) + var/obj/structure/disposalpipe/broken/pipe = new(location) + pipe.setDir(dir) spew_forth() - qdel(src) - /obj/structure/disposalpipe/singularity_pull(S, current_size) ..() @@ -323,9 +320,6 @@ spawn_pipe = FALSE anchored = FALSE -/obj/structure/disposalpipe/broken/deconstruct() - qdel(src) - /obj/structure/disposalpipe/rotator icon_state = "pipe-r1" initialize_dirs = DISP_DIR_LEFT | DISP_DIR_RIGHT | DISP_DIR_FLIP diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm index b5f2c283f19..f11ad91e002 100644 --- a/code/modules/recycling/sortingmachinery.dm +++ b/code/modules/recycling/sortingmachinery.dm @@ -51,10 +51,9 @@ if(EXPLODE_LIGHT) SSexplosions.low_mov_atom += contents -/obj/item/delivery/deconstruct() +/obj/item/delivery/atom_deconstruct(dissambled = TRUE) unwrap_contents() post_unwrap_contents() - return ..() /obj/item/delivery/examine(mob/user) . = ..() diff --git a/code/modules/shuttle/syndicate.dm b/code/modules/shuttle/syndicate.dm index f08446b650d..402a87bf6d4 100644 --- a/code/modules/shuttle/syndicate.dm +++ b/code/modules/shuttle/syndicate.dm @@ -64,5 +64,6 @@ y_offset = -1 whitelist_turfs = list(/turf/open/space, /turf/open/floor/plating, /turf/open/lava, /turf/closed/mineral, /turf/open/openspace, /turf/open/misc) see_hidden = TRUE + circuit = /obj/item/circuitboard/computer/syndicate_shuttle_docker #undef SYNDICATE_CHALLENGE_TIMER diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 01c7359c198..03f87b6d741 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -1178,10 +1178,11 @@ bodypart_overlays -= overlay overlay.removed_from_limb(src) -/obj/item/bodypart/deconstruct(disassembled = TRUE) +/obj/item/bodypart/atom_deconstruct(disassembled = TRUE) SHOULD_CALL_PARENT(TRUE) drop_organs() + return ..() /// INTERNAL PROC, DO NOT USE diff --git a/code/modules/surgery/implant_removal.dm b/code/modules/surgery/implant_removal.dm index a2b9eb33cbf..66eaf6faf73 100644 --- a/code/modules/surgery/implant_removal.dm +++ b/code/modules/surgery/implant_removal.dm @@ -56,6 +56,9 @@ display_pain(target, "You can feel your [implant.name] pulled out of you!") implant.removed(target) + if (QDELETED(implant)) + return ..() + var/obj/item/implantcase/case for(var/obj/item/implantcase/implant_case in user.held_items) case = implant_case diff --git a/code/modules/surgery/organs/_organ.dm b/code/modules/surgery/organs/_organ.dm index d7f08a7be35..366f0f0087f 100644 --- a/code/modules/surgery/organs/_organ.dm +++ b/code/modules/surgery/organs/_organ.dm @@ -239,6 +239,11 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) for(var/obj/item/organ/organ as anything in organs) organ.set_organ_damage(0) set_heartattack(FALSE) + + // Ears have aditional vаr "deaf", need to update it too + var/obj/item/organ/internal/ears/ears = get_organ_slot(ORGAN_SLOT_EARS) + ears?.adjustEarDamage(0, -INFINITY) // full heal ears deafness + return // Default organ fixing handling @@ -273,7 +278,7 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) if(!ears) ears = new() ears.Insert(src) - ears.set_organ_damage(0) + ears.adjustEarDamage(-INFINITY, -INFINITY) // actually do: set_organ_damage(0) and deaf = 0 /obj/item/organ/proc/handle_failing_organs(seconds_per_tick) return diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm b/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm index 0e004ab3c5c..89c6f9c96a4 100644 --- a/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm +++ b/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm @@ -106,32 +106,62 @@ var/static/list/signalCache = list( COMSIG_LIVING_STATUS_STUN, - COMSIG_LIVING_STATUS_KNOCKDOWN, COMSIG_LIVING_STATUS_IMMOBILIZE, COMSIG_LIVING_STATUS_PARALYZE, ) - var/stun_cap_amount = 40 + ///timer before the implant activates + var/stun_cap_amount = 1 SECONDS + ///amount of time you are resistant to stuns and knockdowns + var/stun_resistance_time = 6 SECONDS + COOLDOWN_DECLARE(implant_cooldown) /obj/item/organ/internal/cyberimp/brain/anti_stun/on_mob_remove(mob/living/carbon/implant_owner) . = ..() UnregisterSignal(implant_owner, signalCache) + UnregisterSignal(implant_owner, COMSIG_CARBON_ENTER_STAMCRIT) /obj/item/organ/internal/cyberimp/brain/anti_stun/on_mob_insert(mob/living/carbon/receiver) . = ..() RegisterSignals(receiver, signalCache, PROC_REF(on_signal)) + RegisterSignal(receiver, COMSIG_CARBON_ENTER_STAMCRIT, PROC_REF(on_stamcrit)) /obj/item/organ/internal/cyberimp/brain/anti_stun/proc/on_signal(datum/source, amount) SIGNAL_HANDLER if(!(organ_flags & ORGAN_FAILING) && amount > 0) addtimer(CALLBACK(src, PROC_REF(clear_stuns)), stun_cap_amount, TIMER_UNIQUE|TIMER_OVERRIDE) +/obj/item/organ/internal/cyberimp/brain/anti_stun/proc/on_stamcrit(datum/source) + SIGNAL_HANDLER + if(!(organ_flags & ORGAN_FAILING)) + addtimer(CALLBACK(src, PROC_REF(clear_stuns)), stun_cap_amount, TIMER_UNIQUE|TIMER_OVERRIDE) + /obj/item/organ/internal/cyberimp/brain/anti_stun/proc/clear_stuns() - if(owner || !(organ_flags & ORGAN_FAILING)) - owner.SetStun(0) - owner.SetKnockdown(0) - owner.SetImmobilized(0) - owner.SetParalyzed(0) + if(isnull(owner) || (organ_flags & ORGAN_FAILING) || !COOLDOWN_FINISHED(src, implant_cooldown)) + return + + owner.SetStun(0) + owner.SetKnockdown(0) + owner.SetImmobilized(0) + owner.SetParalyzed(0) + owner.setStaminaLoss(0) + addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/living, setStaminaLoss), 0), stun_resistance_time) + + var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread + sparks.set_up(5, 1, src) + sparks.start() + + owner.add_traits(list(TRAIT_IGNOREDAMAGESLOWDOWN, TRAIT_BATON_RESISTANCE, TRAIT_STUNIMMUNE), REF(src)) + addtimer(TRAIT_CALLBACK_REMOVE(owner, TRAIT_IGNOREDAMAGESLOWDOWN, REF(src)), stun_resistance_time) + addtimer(TRAIT_CALLBACK_REMOVE(owner, TRAIT_BATON_RESISTANCE, REF(src)), stun_resistance_time) + addtimer(TRAIT_CALLBACK_REMOVE(owner, TRAIT_STUNIMMUNE, REF(src)), stun_resistance_time) + + COOLDOWN_START(src, implant_cooldown, 60 SECONDS) + addtimer(CALLBACK(src, PROC_REF(implant_ready)),60 SECONDS) + +/obj/item/organ/internal/cyberimp/brain/anti_stun/proc/implant_ready() + if(owner) + to_chat(owner, span_purple("Your rebooter implant is ready.")) /obj/item/organ/internal/cyberimp/brain/anti_stun/emp_act(severity) . = ..() @@ -141,7 +171,8 @@ addtimer(CALLBACK(src, PROC_REF(reboot)), 90 / severity) /obj/item/organ/internal/cyberimp/brain/anti_stun/proc/reboot() - organ_flags &= ~ORGAN_FAILING + organ_flags &= ~ORGAN_FAILING + implant_ready() //[[[[MOUTH]]]] /obj/item/organ/internal/cyberimp/mouth diff --git a/code/modules/surgery/organs/internal/ears/_ears.dm b/code/modules/surgery/organs/internal/ears/_ears.dm index 2a3eabd5f8e..8e9c7ae70a7 100644 --- a/code/modules/surgery/organs/internal/ears/_ears.dm +++ b/code/modules/surgery/organs/internal/ears/_ears.dm @@ -67,6 +67,13 @@ icon_state = "kitty" visual = TRUE damage_multiplier = 2 + // Keeps track of which cat ears sprite is associated with this. + var/variant = "Cat" + +/obj/item/organ/internal/ears/cat/Initialize(mapload, variant_pref) + . = ..() + if(variant_pref) + variant = variant_pref //SKYRAT EDIT REMOVAL BEGIN - CUSTOMIZATION /* @@ -74,7 +81,7 @@ . = ..() if(istype(ear_owner) && ear_owner.dna) color = ear_owner.hair_color - ear_owner.dna.features["ears"] = ear_owner.dna.species.mutant_bodyparts["ears"] = "Cat" + ear_owner.dna.features["ears"] = ear_owner.dna.species.mutant_bodyparts["ears"] = variant ear_owner.dna.update_uf_block(DNA_EARS_BLOCK) ear_owner.update_body() diff --git a/code/modules/surgery/surgery_helpers.dm b/code/modules/surgery/surgery_helpers.dm index 922ef836dbb..ec33b47dca2 100644 --- a/code/modules/surgery/surgery_helpers.dm +++ b/code/modules/surgery/surgery_helpers.dm @@ -34,10 +34,10 @@ if(covered_locations & HEAD) return FALSE if(BODY_ZONE_PRECISE_EYES) - if(covered_locations & HEAD || face_covered & HIDEEYES || eyesmouth_covered & GLASSESCOVERSEYES) + if((face_covered & HIDEEYES) || (eyesmouth_covered & (MASKCOVERSEYES|HEADCOVERSEYES|GLASSESCOVERSEYES))) return FALSE if(BODY_ZONE_PRECISE_MOUTH) - if(covered_locations & HEAD || face_covered & HIDEFACE || eyesmouth_covered & MASKCOVERSMOUTH || eyesmouth_covered & HEADCOVERSMOUTH) + if((face_covered & HIDEFACE) || (eyesmouth_covered & (MASKCOVERSMOUTH|HEADCOVERSMOUTH))) return FALSE if(BODY_ZONE_CHEST) if(covered_locations & CHEST) diff --git a/code/modules/transport/tram/tram_structures.dm b/code/modules/transport/tram/tram_structures.dm index 74532d87be7..f868fe21c48 100644 --- a/code/modules/transport/tram/tram_structures.dm +++ b/code/modules/transport/tram/tram_structures.dm @@ -212,14 +212,12 @@ return ..() -/obj/structure/tram/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - new girder_type(loc) - if(mineral_amount) - for(var/i in 1 to mineral_amount) - new mineral(loc) - qdel(src) +/obj/structure/tram/atom_deconstruct(disassembled = TRUE) + if(disassembled) + new girder_type(loc) + if(mineral_amount) + for(var/i in 1 to mineral_amount) + new mineral(loc) /obj/structure/tram/attackby(obj/item/item, mob/user, params) . = ..() diff --git a/code/modules/unit_tests/limbsanity.dm b/code/modules/unit_tests/limbsanity.dm index 9988c7471e2..a92d481f556 100644 --- a/code/modules/unit_tests/limbsanity.dm +++ b/code/modules/unit_tests/limbsanity.dm @@ -2,13 +2,13 @@ /datum/unit_test/limbsanity/Run() for(var/path in subtypesof(/obj/item/bodypart) - list(/obj/item/bodypart/arm, /obj/item/bodypart/leg)) /// removes the abstract items. - var/obj/item/bodypart/part = new path(null) - if(part.is_dimorphic) - if(!icon_exists(UNLINT(part.should_draw_greyscale ? part.icon_greyscale : part.icon_static), "[part.limb_id]_[part.body_zone]_m")) + var/obj/item/bodypart/part = path + if(part::is_dimorphic) + if(!icon_exists(UNLINT(part::should_draw_greyscale ? part::icon_greyscale : part::icon_static), "[part::limb_id]_[part::body_zone]_m")) TEST_FAIL("[path] does not have a valid icon for male variants") - if(!icon_exists(UNLINT(part.should_draw_greyscale ? part.icon_greyscale : part.icon_static), "[part.limb_id]_[part.body_zone]_f")) + if(!icon_exists(UNLINT(part::should_draw_greyscale ? part::icon_greyscale : part::icon_static), "[part::limb_id]_[part::body_zone]_f")) TEST_FAIL("[path] does not have a valid icon for female variants") - else if(!icon_exists(UNLINT(part.should_draw_greyscale ? part.icon_greyscale : part.icon_static), "[part.limb_id]_[part.body_zone]")) + else if(!icon_exists(UNLINT(part::should_draw_greyscale ? part::icon_greyscale : part::icon_static), "[part::limb_id]_[part::body_zone]")) TEST_FAIL("[path] does not have a valid icon") /// Tests the height adjustment system which dynamically changes how much the chest, head, and arms of a carbon are adjusted upwards or downwards based on the length of their legs and chest. diff --git a/code/modules/unit_tests/mouse_bite_cable.dm b/code/modules/unit_tests/mouse_bite_cable.dm index 6d3150d279d..c2277fe4fd7 100644 --- a/code/modules/unit_tests/mouse_bite_cable.dm +++ b/code/modules/unit_tests/mouse_bite_cable.dm @@ -19,6 +19,8 @@ // Ai controlling processes expect a seconds_per_tick, supply a real-fake dt var/fake_dt = SSai_controllers.wait * 0.1 + // Set AI - AIs by default are off in z-levels with no client, we have to force it on. + biter.ai_controller.set_ai_status(AI_STATUS_ON) // Select behavior - this will queue finding the cable biter.ai_controller.SelectBehaviors(fake_dt) // Process behavior - this will execute the "locate the cable" behavior diff --git a/code/modules/unit_tests/suit_storage_icons.dm b/code/modules/unit_tests/suit_storage_icons.dm index 8c77b052411..12305e7abfc 100644 --- a/code/modules/unit_tests/suit_storage_icons.dm +++ b/code/modules/unit_tests/suit_storage_icons.dm @@ -10,18 +10,13 @@ continue wearable_item_paths |= item_path - for(var/clothing_path in (subtypesof(/obj/item/clothing) - typesof(/obj/item/clothing/head/mob_holder) - typesof(/obj/item/clothing/suit/space/santa))) //mob_holder is a psuedo abstract item. santa suit is a VERY SNOWFLAKE admin spawn suit that can hold /every/ possible item. - var/obj/item/clothing/spawned_item = new clothing_path - for(var/path in spawned_item.allowed) //find all usable suit storage stuff. + for(var/obj/item/clothing/clothing_path in (subtypesof(/obj/item/clothing) - typesof(/obj/item/clothing/head/mob_holder) - typesof(/obj/item/clothing/suit/space/santa))) //mob_holder is a psuedo abstract item. santa suit is a VERY SNOWFLAKE admin spawn suit that can hold /every/ possible item. + for(var/path in clothing_path::allowed) //find all usable suit storage stuff. wearable_item_paths |= path - qdel(spawned_item) - for(var/mod_path in subtypesof(/obj/item/mod/control)) - var/obj/item/mod/control/control_mod = new - for(var/path in control_mod.chestplate.allowed) + for(var/obj/item/mod/control/mod_path in subtypesof(/obj/item/mod/control)) + for(var/path in mod_path::chestplate::allowed) wearable_item_paths |= path - qdel(control_mod) - var/list/already_warned_icons = list() var/count = 1 //to be removed once the test goes live / into CI failure mode. diff --git a/code/modules/uplink/uplink_items/nukeops.dm b/code/modules/uplink/uplink_items/nukeops.dm index 95a8194cd6a..185c3f44681 100644 --- a/code/modules/uplink/uplink_items/nukeops.dm +++ b/code/modules/uplink/uplink_items/nukeops.dm @@ -475,6 +475,14 @@ Its chameleon projector lets it disguise itself as a Nanotrasen cyborg, on top it has thermal vision and a pinpointer." item = /obj/item/antag_spawner/nuke_ops/borg_tele/saboteur +/datum/uplink_item/reinforcements/overwatch_agent + name = "Overwatch Intelligence Agent" + desc = "An Overwatch Intelligence Agent is assigned to your operation. They can view your progress and help coordinate using your \ + operative team's body-cams. They can also pilot the shuttle remotely and view the station's camera net. \ + If you're a meathead who's just here to kill people and don't care about strategising or intel, you'll still have someone to bear witness to your murder-spree!" + item = /obj/item/antag_spawner/nuke_ops/overwatch + cost = 12 + // ~~ Disposable Sentry Gun ~~ // Technically not a spawn but it is a kind of reinforcement...I guess. diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index 188f8ac629a..42f6ff2a436 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -1157,7 +1157,7 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock) /obj/machinery/vending/exchange_parts(mob/user, obj/item/storage/part_replacer/replacer) if(!istype(replacer)) return FALSE - if((obj_flags & NO_DECONSTRUCTION) && !replacer.works_from_distance) + if(!replacer.works_from_distance) return FALSE if(!component_parts || !refill_canister) return FALSE diff --git a/code/modules/wiremod/shell/dispenser.dm b/code/modules/wiremod/shell/dispenser.dm index 4ea2d03c9d7..4a00f7fed88 100644 --- a/code/modules/wiremod/shell/dispenser.dm +++ b/code/modules/wiremod/shell/dispenser.dm @@ -18,10 +18,9 @@ var/list/obj/item/stored_items = list() var/locked = FALSE -/obj/structure/dispenser_bot/deconstruct(disassembled) +/obj/structure/dispenser_bot/atom_deconstruct(disassembled = TRUE) for(var/obj/item/stored_item as anything in stored_items) remove_item(stored_item) - return ..() /obj/structure/dispenser_bot/Destroy() QDEL_LIST(stored_items) diff --git a/code/modules/wiremod/shell/moneybot.dm b/code/modules/wiremod/shell/moneybot.dm index cacb457149d..f3c2dfe93da 100644 --- a/code/modules/wiremod/shell/moneybot.dm +++ b/code/modules/wiremod/shell/moneybot.dm @@ -15,9 +15,8 @@ var/stored_money = 0 var/locked = FALSE -/obj/structure/money_bot/deconstruct(disassembled) +/obj/structure/money_bot/atom_deconstruct(disassembled = TRUE) new /obj/item/holochip(drop_location(), stored_money) - return ..() /obj/structure/money_bot/proc/add_money(to_add) stored_money += to_add diff --git a/icons/effects/progressbar.dmi b/icons/effects/progressbar.dmi index f055a07ba14..3eed14db704 100644 Binary files a/icons/effects/progressbar.dmi and b/icons/effects/progressbar.dmi differ diff --git a/icons/mob/clothing/neck.dmi b/icons/mob/clothing/neck.dmi index 7895a3ac7fa..a193fbd74a8 100644 Binary files a/icons/mob/clothing/neck.dmi and b/icons/mob/clothing/neck.dmi differ diff --git a/icons/mob/human/cat_features.dmi b/icons/mob/human/cat_features.dmi index f80d0167ae8..6e7fd024fee 100644 Binary files a/icons/mob/human/cat_features.dmi and b/icons/mob/human/cat_features.dmi differ diff --git a/icons/obj/clothing/neck.dmi b/icons/obj/clothing/neck.dmi index 986d9bd9158..e937d125ec2 100644 Binary files a/icons/obj/clothing/neck.dmi and b/icons/obj/clothing/neck.dmi differ diff --git a/modular_skyrat/modules/ashwalkers/code/buildings/planttank.dm b/modular_skyrat/modules/ashwalkers/code/buildings/planttank.dm index 0bc1b4d722e..de9bb608a50 100644 --- a/modular_skyrat/modules/ashwalkers/code/buildings/planttank.dm +++ b/modular_skyrat/modules/ashwalkers/code/buildings/planttank.dm @@ -107,7 +107,7 @@ deconstruct() return TRUE -/obj/structure/plant_tank/deconstruct(disassembled) +/obj/structure/plant_tank/atom_deconstruct(disassembled) var/target_turf = get_turf(src) for(var/loop in 1 to 4) new /obj/item/stack/sheet/glass(target_turf) diff --git a/modular_skyrat/modules/barricades/code/barricade.dm b/modular_skyrat/modules/barricades/code/barricade.dm index 02270d9421f..fca6f627624 100644 --- a/modular_skyrat/modules/barricades/code/barricade.dm +++ b/modular_skyrat/modules/barricades/code/barricade.dm @@ -132,7 +132,7 @@ update_icon() -/obj/structure/deployable_barricade/deconstruct(disassembled = TRUE) +/obj/structure/deployable_barricade/atom_deconstruct(disassembled = TRUE) if(stack_type) var/stack_amt if(!disassembled && destroyed_stack_amount) diff --git a/modular_skyrat/modules/clock_cult/code/structures/technologists_lectern.dm b/modular_skyrat/modules/clock_cult/code/structures/technologists_lectern.dm index edfbef4391b..e04d5564d9d 100644 --- a/modular_skyrat/modules/clock_cult/code/structures/technologists_lectern.dm +++ b/modular_skyrat/modules/clock_cult/code/structures/technologists_lectern.dm @@ -58,7 +58,7 @@ return ..() -/obj/structure/destructible/clockwork/gear_base/technologists_lectern/deconstruct(disassembled) +/obj/structure/destructible/clockwork/gear_base/technologists_lectern/atom_deconstruct(disassembled) if(primary_researcher) deltimer(research_timer_id) researching = FALSE diff --git a/modular_skyrat/modules/colony_fabricator/code/construction/manual_door.dm b/modular_skyrat/modules/colony_fabricator/code/construction/manual_door.dm index 2781c521353..f5bba70b5ee 100644 --- a/modular_skyrat/modules/colony_fabricator/code/construction/manual_door.dm +++ b/modular_skyrat/modules/colony_fabricator/code/construction/manual_door.dm @@ -10,7 +10,7 @@ /// How long it takes to open/close the door var/manual_actuation_delay = 1 SECONDS -/obj/structure/mineral_door/manual_colony_door/deconstruct(disassembled = TRUE) +/obj/structure/mineral_door/manual_colony_door/atom_deconstruct(disassembled = TRUE) if(disassembled) new disassembled_type(get_turf(src)) qdel(src) diff --git a/modular_skyrat/modules/mapping/code/machinery.dm b/modular_skyrat/modules/mapping/code/machinery.dm index 960dc2861d3..53500a29628 100644 --- a/modular_skyrat/modules/mapping/code/machinery.dm +++ b/modular_skyrat/modules/mapping/code/machinery.dm @@ -12,17 +12,20 @@ gpstag = SPACE_SIGNAL_GPSTAG //really the only non-aesthetic change, gives the space ruin GPS signal /obj/item/gps/computer/space/wrench_act(mob/living/user, obj/item/I) - ..() + . = ..() if(obj_flags & NO_DECONSTRUCTION) return TRUE - user.visible_message(span_warning("[user] disassembles [src]."), - span_notice("You start to disassemble [src]..."), span_hear("You hear clanking and banging noises.")) if(I.use_tool(src, user, 20, volume=50)) - new /obj/item/gps/spaceruin(loc) //really the only non-aesthetic change, gives the space ruin GPS signal - qdel(src) + user.visible_message(span_warning("[user] disassembles [src]."), + span_notice("You start to disassemble [src]..."), span_hear("You hear clanking and banging noises.")) + deconstruct(TRUE) return TRUE +/obj/item/gps/computer/space/atom_deconstruct(disassembled) + . = ..() + new /obj/item/gps/spaceruin(loc) //really the only non-aesthetic change, gives the space ruin GPS signal + /obj/item/gps/computer/attack_hand(mob/user, list/modifiers) . = ..() if(.) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_machinery/milking_machine.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_machinery/milking_machine.dm index b04539f95ad..25dba7d3508 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_machinery/milking_machine.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_machinery/milking_machine.dm @@ -419,7 +419,7 @@ return TRUE // Machine deconstruction process handler -/obj/structure/chair/milking_machine/deconstruct(disassembled) +/obj/structure/chair/milking_machine/atom_deconstruct(disassembled) if(beaker) beaker.forceMove(drop_location()) adjust_item_drop_location(beaker) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_structures/shibari_stand.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_structures/shibari_stand.dm index 702d7293c62..968b6a34925 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_structures/shibari_stand.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_structures/shibari_stand.dm @@ -123,10 +123,7 @@ to_chat(user, span_warning("You cannot buckle yourself to this stand, there is no way that level of self-bondage exists!")) return FALSE -/obj/structure/chair/shibari_stand/deconstruct(disassembled) - if(obj_flags & NO_DECONSTRUCTION) - return - +/obj/structure/chair/shibari_stand/atom_deconstruct(disassembled) qdel(src) /obj/structure/chair/shibari_stand/proc/add_rope_overlays(color, taur) diff --git a/modular_skyrat/modules/primitive_cooking_additions/code/millstone.dm b/modular_skyrat/modules/primitive_cooking_additions/code/millstone.dm index 9a028936f1e..57b5d23e385 100644 --- a/modular_skyrat/modules/primitive_cooking_additions/code/millstone.dm +++ b/modular_skyrat/modules/primitive_cooking_additions/code/millstone.dm @@ -44,7 +44,7 @@ drop_everything_contained() return ..() -/obj/structure/millstone/deconstruct(disassembled) +/obj/structure/millstone/atom_deconstruct(disassembled) var/obj/item/stack/sheet/mineral/stone = new (drop_location()) stone.amount = 6 stone.update_appearance(UPDATE_ICON) diff --git a/modular_skyrat/modules/primitive_structures/code/storage_structures.dm b/modular_skyrat/modules/primitive_structures/code/storage_structures.dm index 0a3aaa0db60..58c08df7941 100644 --- a/modular_skyrat/modules/primitive_structures/code/storage_structures.dm +++ b/modular_skyrat/modules/primitive_structures/code/storage_structures.dm @@ -24,7 +24,7 @@ deconstruct(TRUE) return ITEM_INTERACT_SUCCESS -/obj/structure/rack/wooden/deconstruct(disassembled = TRUE) +/obj/structure/rack/wooden/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/mineral/wood(drop_location(), 2) return ..() @@ -47,7 +47,7 @@ deconstruct(TRUE) return ITEM_INTERACT_SUCCESS -/obj/structure/closet/crate/wooden/storage_barrel/deconstruct(disassembled = TRUE) +/obj/structure/closet/crate/wooden/storage_barrel/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/mineral/wood(drop_location(), 4) return ..() diff --git a/modular_skyrat/modules/reagent_forging/code/anvil.dm b/modular_skyrat/modules/reagent_forging/code/anvil.dm index e0516c42abb..cb5cf2f875c 100644 --- a/modular_skyrat/modules/reagent_forging/code/anvil.dm +++ b/modular_skyrat/modules/reagent_forging/code/anvil.dm @@ -53,7 +53,7 @@ deconstruct(TRUE) return TRUE -/obj/structure/reagent_anvil/deconstruct(disassembled = TRUE) +/obj/structure/reagent_anvil/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/iron/ten(get_turf(src)) return ..() diff --git a/modular_skyrat/modules/reagent_forging/code/forge.dm b/modular_skyrat/modules/reagent_forging/code/forge.dm index 4ecd4351573..175e7ce9343 100644 --- a/modular_skyrat/modules/reagent_forging/code/forge.dm +++ b/modular_skyrat/modules/reagent_forging/code/forge.dm @@ -888,7 +888,7 @@ deconstruct(TRUE) return TRUE -/obj/structure/reagent_forge/deconstruct(disassembled) +/obj/structure/reagent_forge/atom_deconstruct(disassembled) new /obj/item/stack/sheet/iron/ten(get_turf(src)) return ..() diff --git a/modular_skyrat/modules/tarkon/code/misc-fluff/spawner.dm b/modular_skyrat/modules/tarkon/code/misc-fluff/spawner.dm index 87e16990c3f..417d0224eb7 100644 --- a/modular_skyrat/modules/tarkon/code/misc-fluff/spawner.dm +++ b/modular_skyrat/modules/tarkon/code/misc-fluff/spawner.dm @@ -200,7 +200,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/cryopod/tarkon, 32) var/boss_mob = /mob/living/basic/alien/queen/large var/loot_drop = /obj/effect/mob_spawn/corpse/human/tarkon -/obj/structure/spawner/tarkon_xenos/deconstruct(disassembled) +/obj/structure/spawner/tarkon_xenos/atom_deconstruct(disassembled) var/obj/effect/nest_break/nest = new /obj/effect/nest_break(loc) nest.loot_drop = loot_drop nest.boss_mob = boss_mob diff --git a/modular_skyrat/modules/wrestlingring/code/wrestlingring.dm b/modular_skyrat/modules/wrestlingring/code/wrestlingring.dm index 8c0e09deccc..d865fc0653f 100644 --- a/modular_skyrat/modules/wrestlingring/code/wrestlingring.dm +++ b/modular_skyrat/modules/wrestlingring/code/wrestlingring.dm @@ -113,11 +113,10 @@ deconstruct() return TRUE -/obj/structure/wrestling_corner/deconstruct(disassembled) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/obj/item/stack/sheet/iron/iron_sheets = new /obj/item/stack/sheet/iron(drop_location(), 3) - transfer_fingerprints_to(iron_sheets) - return ..() +/obj/structure/wrestling_corner/atom_deconstruct(disassembled) + . = ..() + var/obj/item/stack/sheet/iron/iron_sheets = new /obj/item/stack/sheet/iron(drop_location(), 3) + transfer_fingerprints_to(iron_sheets) ///Implements behaviour that makes it possible to unanchor the railing. /obj/structure/wrestling_corner/wrench_act(mob/living/user, obj/item/tool) diff --git a/tgstation.dme b/tgstation.dme index bc12d4524e3..48819548895 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -335,6 +335,7 @@ #include "code\__DEFINES\dcs\signals\signals_music.dm" #include "code\__DEFINES\dcs\signals\signals_object.dm" #include "code\__DEFINES\dcs\signals\signals_operating_computer.dm" +#include "code\__DEFINES\dcs\signals\signals_operatives.dm" #include "code\__DEFINES\dcs\signals\signals_painting.dm" #include "code\__DEFINES\dcs\signals\signals_proxmonitor.dm" #include "code\__DEFINES\dcs\signals\signals_radiation.dm" @@ -715,6 +716,7 @@ #include "code\controllers\subsystem\atoms.dm" #include "code\controllers\subsystem\augury.dm" #include "code\controllers\subsystem\ban_cache.dm" +#include "code\controllers\subsystem\battle_royale.dm" #include "code\controllers\subsystem\bitrunning.dm" #include "code\controllers\subsystem\blackbox.dm" #include "code\controllers\subsystem\blackmarket.dm" @@ -733,7 +735,6 @@ #include "code\controllers\subsystem\garbage.dm" #include "code\controllers\subsystem\icon_smooth.dm" #include "code\controllers\subsystem\id_access.dm" -#include "code\controllers\subsystem\idlenpcpool.dm" #include "code\controllers\subsystem\init_profiler.dm" #include "code\controllers\subsystem\input.dm" #include "code\controllers\subsystem\ipintel.dm" @@ -858,6 +859,7 @@ #include "code\datums\candidate_poll.dm" #include "code\datums\chat_payload.dm" #include "code\datums\chatmessage.dm" +#include "code\datums\cogbar.dm" #include "code\datums\dash_weapon.dm" #include "code\datums\datum.dm" #include "code\datums\datumvars.dm" @@ -2439,6 +2441,7 @@ #include "code\game\objects\items\devices\aicard_evil.dm" #include "code\game\objects\items\devices\anomaly_neutralizer.dm" #include "code\game\objects\items\devices\anomaly_releaser.dm" +#include "code\game\objects\items\devices\battle_royale.dm" #include "code\game\objects\items\devices\beacon.dm" #include "code\game\objects\items\devices\chameleonproj.dm" #include "code\game\objects\items\devices\destabilizing_crystal.dm" @@ -2555,6 +2558,7 @@ #include "code\game\objects\items\grenades\syndieminibomb.dm" #include "code\game\objects\items\implants\implant.dm" #include "code\game\objects\items\implants\implant_abductor.dm" +#include "code\game\objects\items\implants\implant_battle_royale.dm" #include "code\game\objects\items\implants\implant_clown.dm" #include "code\game\objects\items\implants\implant_deathrattle.dm" #include "code\game\objects\items\implants\implant_explosive.dm" @@ -3240,10 +3244,12 @@ #include "code\modules\antagonists\nukeop\datums\operative_leader.dm" #include "code\modules\antagonists\nukeop\datums\operative_lone.dm" #include "code\modules\antagonists\nukeop\datums\operative_reinforcement.dm" +#include "code\modules\antagonists\nukeop\datums\operative_support.dm" #include "code\modules\antagonists\nukeop\datums\operative_team.dm" #include "code\modules\antagonists\nukeop\equipment\borgchameleon.dm" #include "code\modules\antagonists\nukeop\equipment\nuclear_authentication_disk.dm" #include "code\modules\antagonists\nukeop\equipment\nuclear_challenge.dm" +#include "code\modules\antagonists\nukeop\equipment\overwatch_tools.dm" #include "code\modules\antagonists\nukeop\equipment\pinpointer.dm" #include "code\modules\antagonists\nukeop\equipment\nuclear_bomb\_nuclear_bomb.dm" #include "code\modules\antagonists\nukeop\equipment\nuclear_bomb\beer_nuke.dm" @@ -3307,6 +3313,7 @@ #include "code\modules\antagonists\traitor\objectives\sleeper_protocol.dm" #include "code\modules\antagonists\traitor\objectives\steal.dm" #include "code\modules\antagonists\traitor\objectives\abstract\target_player.dm" +#include "code\modules\antagonists\traitor\objectives\final_objective\battle_royale.dm" #include "code\modules\antagonists\traitor\objectives\final_objective\battlecruiser.dm" #include "code\modules\antagonists\traitor\objectives\final_objective\final_objective.dm" #include "code\modules\antagonists\traitor\objectives\final_objective\infect_ai.dm" @@ -3757,6 +3764,7 @@ #include "code\modules\client\preferences\statpanel.dm" #include "code\modules\client\preferences\tgui.dm" #include "code\modules\client\preferences\tooltips.dm" +#include "code\modules\client\preferences\trans_prosthetic.dm" #include "code\modules\client\preferences\ui_style.dm" #include "code\modules\client\preferences\underwear_color.dm" #include "code\modules\client\preferences\uplink_location.dm" diff --git a/tgui/global.d.ts b/tgui/global.d.ts index 542788717ab..9cb8e37c2e8 100644 --- a/tgui/global.d.ts +++ b/tgui/global.d.ts @@ -41,36 +41,6 @@ type ByondType = { */ windowId: string; - /** - * True if javascript is running in BYOND. - */ - IS_BYOND: boolean; - - /** - * Version of Trident engine of Internet Explorer. Null if N/A. - */ - TRIDENT: number | null; - - /** - * True if browser is IE8 or lower. - */ - IS_LTE_IE8: boolean; - - /** - * True if browser is IE9 or lower. - */ - IS_LTE_IE9: boolean; - - /** - * True if browser is IE10 or lower. - */ - IS_LTE_IE10: boolean; - - /** - * True if browser is IE11 or lower. - */ - IS_LTE_IE11: boolean; - /** * If `true`, unhandled errors and common mistakes result in a blue screen * of death, which stops this window from handling incoming messages and diff --git a/tgui/packages/tgui-panel/chat/renderer.jsx b/tgui/packages/tgui-panel/chat/renderer.jsx index 0d26061f60b..7e30a0274ac 100644 --- a/tgui/packages/tgui-panel/chat/renderer.jsx +++ b/tgui/packages/tgui-panel/chat/renderer.jsx @@ -6,7 +6,7 @@ import { EventEmitter } from 'common/events'; import { classes } from 'common/react'; -import { render } from 'react-dom'; +import { createRoot } from 'react-dom/client'; import { Tooltip } from 'tgui/components'; import { createLogger } from 'tgui/logging'; @@ -168,7 +168,7 @@ class ChatRenderer { // Find scrollable parent this.scrollNode = findNearestScrollableParent(this.rootNode); this.scrollNode.addEventListener('scroll', this.handleScroll); - setImmediate(() => { + setTimeout(() => { this.scrollToBottom(); }); // Flush the queue @@ -413,14 +413,16 @@ class ChatRenderer { childNode.removeChild(childNode.firstChild); } const Element = TGUI_CHAT_COMPONENTS[targetName]; + + const reactRoot = createRoot(childNode); + /* eslint-disable react/no-danger */ - render( + reactRoot.render( , childNode, ); - /* eslint-enable react/no-danger */ } // Highlight text @@ -455,15 +457,9 @@ class ChatRenderer { message.node = node; // Query all possible selectors to find out the message type if (!message.type) { - // IE8: Does not support querySelector on elements that - // are not yet in the document. - - const typeDef = - !Byond.IS_LTE_IE8 && - MESSAGE_TYPES.find( - (typeDef) => - typeDef.selector && node.querySelector(typeDef.selector), - ); + const typeDef = MESSAGE_TYPES.find( + (typeDef) => typeDef.selector && node.querySelector(typeDef.selector), + ); message.type = typeDef?.type || MESSAGE_TYPE_UNKNOWN; } updateMessageBadge(message); @@ -486,7 +482,7 @@ class ChatRenderer { this.rootNode.appendChild(fragment); } if (this.scrollTracking) { - setImmediate(() => this.scrollToBottom()); + setTimeout(() => this.scrollToBottom()); } } // Notify listeners that we have processed the batch @@ -586,10 +582,6 @@ class ChatRenderer { } saveToDisk() { - // Allow only on IE11 - if (Byond.IS_LTE_IE10) { - return; - } // Compile currently loaded stylesheets as CSS text let cssText = ''; const styleSheets = document.styleSheets; diff --git a/tgui/packages/tgui-panel/panelFocus.js b/tgui/packages/tgui-panel/panelFocus.js index b7cea229314..8cff4a361b3 100644 --- a/tgui/packages/tgui-panel/panelFocus.js +++ b/tgui/packages/tgui-panel/panelFocus.js @@ -15,7 +15,7 @@ import { focusMap } from 'tgui/focus'; // text you can select with the mouse. const MIN_SELECTION_DISTANCE = 10; -const deferredFocusMap = () => setImmediate(() => focusMap()); +const deferredFocusMap = () => setTimeout(() => focusMap()); export const setupPanelFocusHacks = () => { let focusStolen = false; diff --git a/tgui/packages/tgui-say/index.tsx b/tgui/packages/tgui-say/index.tsx index d902ae85cdf..9757cca4ff4 100644 --- a/tgui/packages/tgui-say/index.tsx +++ b/tgui/packages/tgui-say/index.tsx @@ -1,21 +1,18 @@ import './styles/main.scss'; -import { createRenderer } from 'tgui/renderer'; +import { createRoot, Root } from 'react-dom/client'; import { TguiSay } from './TguiSay'; -const renderApp = createRenderer(() => { - return ; -}); +let reactRoot: Root | null = null; -const setupApp = () => { - // Delay setup - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', setupApp); - return; +document.onreadystatechange = function () { + if (document.readyState !== 'complete') return; + + if (!reactRoot) { + const root = document.getElementById('react-root'); + reactRoot = createRoot(root!); } - renderApp(); + reactRoot.render(); }; - -setupApp(); diff --git a/tgui/packages/tgui-say/package.json b/tgui/packages/tgui-say/package.json index da9ff074d4b..55410500e58 100644 --- a/tgui/packages/tgui-say/package.json +++ b/tgui/packages/tgui-say/package.json @@ -4,8 +4,10 @@ "version": "1.0.0", "dependencies": { "@types/react": "^18.2.74", + "@types/react-dom": "^18.2.24", "common": "workspace:*", "react": "^18.2.0", + "react-dom": "^18.2.0", "tgui": "workspace:*", "tgui-polyfill": "workspace:*" } diff --git a/tgui/packages/tgui/backend.ts b/tgui/packages/tgui/backend.ts index bf75306108a..c85d5153210 100644 --- a/tgui/packages/tgui/backend.ts +++ b/tgui/packages/tgui/backend.ts @@ -177,7 +177,7 @@ export const backendMiddleware = (store) => { Byond.winset(Byond.windowId, { 'is-visible': false, }); - setImmediate(() => focusMap()); + setTimeout(() => focusMap()); } if (type === 'backend/update') { @@ -207,7 +207,7 @@ export const backendMiddleware = (store) => { setupDrag(); // We schedule this for the next tick here because resizing and unhiding // during the same tick will flash with a white background. - setImmediate(() => { + setTimeout(() => { perf.mark('resume/start'); // Doublecheck if we are not re-suspended. const { suspended } = selectBackend(store.getState()); diff --git a/tgui/packages/tgui/components/Flex.tsx b/tgui/packages/tgui/components/Flex.tsx index 50dba277958..41ea6bd8275 100644 --- a/tgui/packages/tgui/components/Flex.tsx +++ b/tgui/packages/tgui/components/Flex.tsx @@ -23,8 +23,6 @@ export const computeFlexClassName = (props: FlexProps) => { return classes([ 'Flex', props.inline && 'Flex--inline', - Byond.IS_LTE_IE10 && 'Flex--iefix', - Byond.IS_LTE_IE10 && props.direction === 'column' && 'Flex--iefix--column', computeBoxClassName(props), ]); }; @@ -65,11 +63,7 @@ export type FlexItemProps = BoxProps & }>; export const computeFlexItemClassName = (props: FlexItemProps) => { - return classes([ - 'Flex__item', - Byond.IS_LTE_IE10 && 'Flex__item--iefix', - computeBoxClassName(props), - ]); + return classes(['Flex__item', computeBoxClassName(props)]); }; export const computeFlexItemProps = (props: FlexItemProps) => { diff --git a/tgui/packages/tgui/interfaces/ColorMatrixEditor.tsx b/tgui/packages/tgui/interfaces/ColorMatrixEditor.tsx index 897c43e6234..edf75dcf161 100644 --- a/tgui/packages/tgui/interfaces/ColorMatrixEditor.tsx +++ b/tgui/packages/tgui/interfaces/ColorMatrixEditor.tsx @@ -13,7 +13,7 @@ import { Window } from '../layouts'; type Data = { mapRef: string; - currentColor: string[]; + currentColor: number[]; }; const PREFIXES = ['r', 'g', 'b', 'a', 'c'] as const; @@ -49,7 +49,7 @@ export const ColorMatrixEditor = (props) => { format={(value) => toFixed(value, 2)} onDrag={(value) => { let retColor = currentColor; - retColor[row * 4 + col] = `${value}`; + retColor[row * 4 + col] = value; act('transition_color', { color: retColor, }); diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx index 19da0a98d90..30766576256 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx @@ -3,6 +3,9 @@ import { exhaustiveCheck } from 'common/exhaustive'; import { classes } from 'common/react'; import { useState } from 'react'; +import { filter } from '../../../common/collections'; +import { flow } from '../../../common/fp'; +import { createSearch } from '../../../common/string'; import { sendAct, useBackend } from '../../backend'; import { Autofocus, @@ -10,6 +13,7 @@ import { Button, Dropdown, // SKYRAT EDIT ADDITION Flex, + Input, LabeledList, Popper, Stack, @@ -117,6 +121,7 @@ const ChoicedSelection = (props: { const { act } = useBackend(); const { catalog, supplementalFeature, supplementalValue } = props; + const [getSearchText, searchTextSet] = useState(''); if (!catalog.icons) { return Provided catalog had no icons!; @@ -172,39 +177,49 @@ const ChoicedSelection = (props: { + searchTextSet(value)} + /> - {Object.entries(catalog.icons).map(([name, image], index) => { - return ( - - - - ); - })} + + + ); + }, + )} @@ -213,6 +228,11 @@ const ChoicedSelection = (props: { ); }; +const searchInCatalog = (searchText = '', catalog: Record) => { + const maybeSearch = createSearch(searchText, ([name, _icon]) => name); + return flow([searchText && filter(maybeSearch)])(Object.entries(catalog)); +}; + const GenderButton = (props: { handleSetGender: (gender: Gender) => void; gender: Gender; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/trans_prosthetic.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/trans_prosthetic.tsx new file mode 100644 index 00000000000..368a2a16a1b --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/trans_prosthetic.tsx @@ -0,0 +1,6 @@ +import { FeatureChoiced, FeatureDropdownInput } from '../base'; + +export const trans_prosthetic: FeatureChoiced = { + name: 'Augment', + component: FeatureDropdownInput, +}; diff --git a/tgui/packages/tgui/stories/ByondUi.stories.jsx b/tgui/packages/tgui/stories/ByondUi.stories.jsx index 0a97be11da7..2203fef23ca 100644 --- a/tgui/packages/tgui/stories/ByondUi.stories.jsx +++ b/tgui/packages/tgui/stories/ByondUi.stories.jsx @@ -34,7 +34,7 @@ const Story = (props) => {