diff --git a/_maps/RandomRuins/IceRuins/icemoon_surface_pizza.dmm b/_maps/RandomRuins/IceRuins/icemoon_surface_pizza.dmm index 0e78558d6f38c..121f9e4ea45d4 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_surface_pizza.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_surface_pizza.dmm @@ -300,7 +300,6 @@ /area/ruin/pizzeria) "kr" = ( /obj/structure/table, -/obj/item/trash/waffles, /obj/effect/turf_decal/tile/blue/opposingcorners{ dir = 1 }, diff --git a/_maps/RandomRuins/IceRuins/icemoon_underground_comms_agent.dmm b/_maps/RandomRuins/IceRuins/icemoon_underground_comms_agent.dmm index ff3417fefce6d..d5c344e9cd31a 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_underground_comms_agent.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_underground_comms_agent.dmm @@ -451,12 +451,8 @@ /area/ruin/comms_agent) "xq" = ( /obj/effect/decal/cleanable/dirt, -/obj/item/radio/intercom{ - pixel_x = 31; - syndie = 1; - freerange = 1; - name = "syndicate radio intercom"; - desc = "A custom-made Syndicate-issue intercom used to transmit on all Nanotrasen frequencies. Particularly expensive." +/obj/item/radio/intercom/syndicate/freerange{ + pixel_x = 31 }, /obj/structure/table/reinforced, /obj/machinery/fax{ diff --git a/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm b/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm index a7eac1fe1a8b1..edd734ee6f586 100644 --- a/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm +++ b/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm @@ -1062,7 +1062,7 @@ /turf/open/floor/iron/dark, /area/ruin/space/has_grav/dangerous_research/lab) "oJ" = ( -/obj/structure/closet/crate/medical, +/obj/structure/closet/crate/secure/interdyne, /obj/item/stack/medical/suture/emergency, /obj/item/stack/medical/gauze/twelve, /obj/item/reagent_containers/hypospray/medipen/blood_loss, @@ -2155,7 +2155,7 @@ /turf/open/floor/iron/dark, /area/ruin/space/has_grav/dangerous_research/lab) "BG" = ( -/obj/structure/closet/crate, +/obj/structure/closet/crate/secure/interdyne, /obj/item/stack/sheet/mineral/plasma/thirty, /obj/item/stack/sheet/mineral/wood/fifty, /obj/item/stack/sheet/iron/fifty, @@ -3658,7 +3658,7 @@ /turf/open/floor/iron/dark, /area/ruin/space/has_grav/dangerous_research) "VQ" = ( -/obj/structure/closet/crate, +/obj/structure/closet/crate/secure/interdyne, /obj/item/reagent_containers/cup/glass/waterbottle/large, /obj/item/reagent_containers/cup/glass/waterbottle/large, /obj/item/reagent_containers/cup/glass/waterbottle/large, diff --git a/_maps/RandomRuins/SpaceRuins/garbagetruck1.dmm b/_maps/RandomRuins/SpaceRuins/garbagetruck1.dmm index a81508dbe1f40..6aca5d7938a01 100644 --- a/_maps/RandomRuins/SpaceRuins/garbagetruck1.dmm +++ b/_maps/RandomRuins/SpaceRuins/garbagetruck1.dmm @@ -491,9 +491,6 @@ /area/ruin/space/has_grav/garbagetruck/foodwaste) "xf" = ( /obj/item/trash/tray, -/obj/item/trash/waffles, -/obj/item/trash/waffles, -/obj/item/trash/waffles, /obj/item/food/grown/mushroom/plumphelmet, /obj/structure/closet/crate/trashcart, /mob/living/basic/mouse/rat, diff --git a/_maps/RandomZLevels/TheBeach.dmm b/_maps/RandomZLevels/TheBeach.dmm index 64cdcbb6d362e..982660859296e 100644 --- a/_maps/RandomZLevels/TheBeach.dmm +++ b/_maps/RandomZLevels/TheBeach.dmm @@ -505,6 +505,10 @@ }, /turf/closed/wall/mineral/wood, /area/awaymission/beach) +"gq" = ( +/obj/item/broken_bottle, +/turf/open/misc/beach/sand, +/area/awaymission/beach) "gw" = ( /obj/item/stack/sheet/mineral/sandstone{ pixel_x = -8 @@ -1191,6 +1195,10 @@ }, /turf/open/misc/beach/sand, /area/awaymission/beach) +"pq" = ( +/obj/effect/spawner/random/trash/cigbutt, +/turf/open/misc/beach/sand, +/area/awaymission/beach) "pr" = ( /obj/item/reagent_containers/cup/soda_cans/space_mountain_wind{ pixel_x = -17; @@ -2856,6 +2864,17 @@ /obj/machinery/light/directional/west, /turf/open/floor/wood/large, /area/awaymission/beach) +"Jv" = ( +/obj/item/paper/fluff/old_pirate_note{ + pixel_x = -5; + pixel_y = -7 + }, +/obj/item/pen/fountain{ + pixel_y = -11; + pixel_x = -8 + }, +/turf/open/misc/beach/sand, +/area/awaymission/beach) "JF" = ( /obj/structure/marker_beacon/burgundy, /turf/open/water/beach, @@ -3330,6 +3349,12 @@ }, /turf/open/misc/beach/sand, /area/awaymission/beach) +"Pb" = ( +/obj/item/fishing_rod, +/obj/structure/closet/crate/trashcart, +/obj/item/reagent_containers/cup/glass/bottle/rum/aged, +/turf/open/misc/beach/sand, +/area/awaymission/beach) "Pe" = ( /turf/open/misc/beach/coast{ dir = 5 @@ -3378,6 +3403,11 @@ }, /turf/open/misc/beach/sand, /area/awaymission/beach) +"PU" = ( +/obj/effect/mob_spawn/corpse/human/old_pirate_captain, +/obj/structure/bed/maint, +/turf/open/misc/beach/sand, +/area/awaymission/beach) "Qe" = ( /obj/effect/turf_decal/sand, /obj/machinery/door/airlock/wood{ @@ -7415,8 +7445,8 @@ XB XB Vf YV -VY -VY +Pb +gq hL ni XB @@ -7672,8 +7702,8 @@ XB XB Vf VY -VY -VY +pq +PU Er BK XB @@ -7929,7 +7959,7 @@ XB XB Vf VY -VY +Jv VY VY BK @@ -8187,7 +8217,7 @@ XB Vf IZ VY -VY +pq VY BK XB diff --git a/_maps/RandomZLevels/snowdin.dmm b/_maps/RandomZLevels/snowdin.dmm index 6f565143e790e..5f0c85ff0b4bc 100644 --- a/_maps/RandomZLevels/snowdin.dmm +++ b/_maps/RandomZLevels/snowdin.dmm @@ -1909,11 +1909,6 @@ }, /turf/open/floor/iron/cafeteria, /area/awaymission/snowdin/post/messhall) -"ht" = ( -/obj/structure/table, -/obj/item/trash/waffles, -/turf/open/floor/iron/cafeteria, -/area/awaymission/snowdin/post/messhall) "hu" = ( /obj/structure/chair{ dir = 8 @@ -25007,7 +25002,7 @@ Kd ex fJ gA -ht +hq hW iH jz diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index b88647d4934a0..4fd1978a11add 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -5684,7 +5684,6 @@ dir = 4 }, /obj/effect/decal/cleanable/dirt, -/obj/item/trash/waffles, /turf/open/floor/plating, /area/station/maintenance/port/aft) "bGm" = ( diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm index 1d1e21590b7e2..bd9f54bd9bb52 100644 --- a/_maps/map_files/generic/CentCom.dmm +++ b/_maps/map_files/generic/CentCom.dmm @@ -2412,10 +2412,7 @@ "lb" = ( /obj/structure/table/wood, /obj/machinery/door/window/left/directional/south, -/obj/item/radio/intercom{ - desc = "Talk smack through this."; - syndie = 1 - }, +/obj/item/radio/intercom/syndicate, /turf/open/floor/iron/grimy, /area/centcom/central_command_areas/courtroom) "lc" = ( @@ -2428,10 +2425,7 @@ /area/centcom/central_command_areas/courtroom) "ld" = ( /obj/structure/table/wood, -/obj/item/radio/intercom{ - desc = "Talk smack through this."; - syndie = 1 - }, +/obj/item/radio/intercom/syndicate, /obj/machinery/door/window/brigdoor/right/directional/south{ name = "CentCom Stand"; req_access = list("cent_captain") @@ -2600,10 +2594,8 @@ /obj/structure/chair{ dir = 8 }, -/obj/item/radio/intercom{ - desc = "Talk smack through this."; - pixel_x = -32; - syndie = 1 +/obj/item/radio/intercom/syndicate{ + pixel_x = -32 }, /turf/open/floor/iron/grimy, /area/centcom/central_command_areas/courtroom) @@ -2669,10 +2661,7 @@ /area/centcom/central_command_areas/courtroom) "mn" = ( /obj/structure/table/wood, -/obj/item/radio/intercom{ - desc = "Talk smack through this."; - syndie = 1 - }, +/obj/item/radio/intercom/syndicate, /turf/open/floor/iron/grimy, /area/centcom/central_command_areas/courtroom) "mo" = ( @@ -10246,10 +10235,8 @@ /obj/machinery/computer/station_alert{ dir = 8 }, -/obj/item/radio/intercom{ - desc = "Talk smack through this."; - pixel_x = 28; - syndie = 1 +/obj/item/radio/intercom/syndicate{ + pixel_x = 28 }, /turf/open/floor/iron/dark, /area/centcom/central_command_areas/control) diff --git a/_maps/map_files/wawastation/wawastation.dmm b/_maps/map_files/wawastation/wawastation.dmm index fa4ea9e4b3263..61153209d2477 100644 --- a/_maps/map_files/wawastation/wawastation.dmm +++ b/_maps/map_files/wawastation/wawastation.dmm @@ -13766,7 +13766,6 @@ "eTu" = ( /obj/effect/turf_decal/tile/neutral, /obj/structure/table, -/obj/item/trash/waffles, /turf/open/floor/iron, /area/station/hallway/primary/central) "eTZ" = ( diff --git a/_maps/shuttles/pirate_ex_interdyne.dmm b/_maps/shuttles/pirate_ex_interdyne.dmm index dce984f19c993..4036972b7a87a 100644 --- a/_maps/shuttles/pirate_ex_interdyne.dmm +++ b/_maps/shuttles/pirate_ex_interdyne.dmm @@ -291,7 +291,7 @@ /area/shuttle/pirate) "aS" = ( /obj/effect/turf_decal/tile/dark_blue/opposingcorners, -/obj/structure/closet/crate/freezer/blood, +/obj/structure/closet/crate/freezer/blood/interdyne, /obj/machinery/light/small/blacklight/directional/south, /obj/machinery/iv_drip, /turf/open/floor/iron/dark, diff --git a/code/__DEFINES/MC.dm b/code/__DEFINES/MC.dm index 8a658f3913d7d..4836625d9197f 100644 --- a/code/__DEFINES/MC.dm +++ b/code/__DEFINES/MC.dm @@ -133,3 +133,11 @@ }\ /datum/controller/subsystem/verb_manager/##X/fire() {..() /*just so it shows up on the profiler*/} \ /datum/controller/subsystem/verb_manager/##X + +#define AI_CONTROLLER_SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/ai_controllers/##X);\ +/datum/controller/subsystem/ai_controllers/##X/New(){\ + NEW_SS_GLOBAL(SS##X);\ + PreInit();\ +}\ +/datum/controller/subsystem/ai_controllers/##X/fire() {..() /*just so it shows up on the profiler*/} \ +/datum/controller/subsystem/ai_controllers/##X diff --git a/code/__DEFINES/access.dm b/code/__DEFINES/access.dm index 325116eb5b869..7d0f804dc5028 100644 --- a/code/__DEFINES/access.dm +++ b/code/__DEFINES/access.dm @@ -326,7 +326,6 @@ ACCESS_PHARMACY, \ ACCESS_PLUMBING, \ ACCESS_PSYCHOLOGY, \ - ACCESS_QM, \ ACCESS_RESEARCH, \ ACCESS_ROBOTICS, \ ACCESS_SCIENCE, \ diff --git a/code/__DEFINES/achievements.dm b/code/__DEFINES/achievements.dm index 0253df0b57a4d..4f1cf4b746ac6 100644 --- a/code/__DEFINES/achievements.dm +++ b/code/__DEFINES/achievements.dm @@ -57,6 +57,7 @@ #define MEDAL_DEBT_EXTINGUISHED "Debt Extinguished" #define MEDAL_SISYPHUS "Sisyphus" #define MEDAL_ARCHMAGE "Archmage" +#define MEDAL_CIGARETTES "Cigarettes" #define MEDAL_THEORETICAL_LIMITS "All Within Theoretical Limits" //Skill medal hub IDs diff --git a/code/__DEFINES/ai/ai.dm b/code/__DEFINES/ai/ai.dm index 37ee5c077e2a5..73a8f2d1900bd 100644 --- a/code/__DEFINES/ai/ai.dm +++ b/code/__DEFINES/ai/ai.dm @@ -68,7 +68,7 @@ ///macro for whether it's appropriate to resist right now, used by resist subtree #define SHOULD_RESIST(source) (source.on_fire || source.buckled || HAS_TRAIT(source, TRAIT_RESTRAINED) || (source.pulledby && source.pulledby.grab_state > GRAB_PASSIVE)) ///macro for whether the pawn can act, used generally to prevent some horrifying ai disasters -#define IS_DEAD_OR_INCAP(source) (source.incapacitated() || source.stat) +#define IS_DEAD_OR_INCAP(source) (source.incapacitated || source.stat) GLOBAL_LIST_INIT(all_radial_directions, list( "NORTH" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = NORTH), diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm index 4374288b07c5b..45f302bc6dd41 100644 --- a/code/__DEFINES/ai/ai_blackboard.dm +++ b/code/__DEFINES/ai/ai_blackboard.dm @@ -133,6 +133,9 @@ ///Range for a MOD AI controller. #define MOD_AI_RANGE 200 +///Only target mobs with these traits +#define BB_TARGET_ONLY_WITH_TRAITS "BB_target_only_with_traits" + ///should we skip the faction check for the targeting strategy? #define BB_ALWAYS_IGNORE_FACTION "BB_always_ignore_factions" ///are we in some kind of temporary state of ignoring factions when targeting? can result in volatile results if multiple behaviours touch this diff --git a/code/__DEFINES/cameranets.dm b/code/__DEFINES/cameranets.dm index 935e015e0cda0..3cd0d30660d3b 100644 --- a/code/__DEFINES/cameranets.dm +++ b/code/__DEFINES/cameranets.dm @@ -30,6 +30,7 @@ #define CAMERA_NETWORK_CARGO "cargo" #define CAMERANET_NETWORK_ABDUCTOR "abductor" #define OPERATIVE_CAMERA_NET "operative" +#define CAMERANET_NETWORK_CURATOR "curator" // Ruins/Away missiosn/Misc camera nets #define CAMERANET_NETWORK_MOON19_XENO "mo19x" diff --git a/code/__DEFINES/crushing.dm b/code/__DEFINES/crushing.dm index 1261b98e730e8..62705e0e3b871 100644 --- a/code/__DEFINES/crushing.dm +++ b/code/__DEFINES/crushing.dm @@ -8,7 +8,7 @@ #define SUCCESSFULLY_FELL_OVER (1<<2) #define CRUSH_CRIT_SHATTER_LEGS "crush_crit_shatter_legs" -#define CRUSH_CRIT_PARAPALEGIC "crush_crit_parapalegic" +#define CRUSH_CRIT_PARAPLEGIC "crush_crit_paraplegic" #define CRUSH_CRIT_SQUISH_LIMB "crush_crit_pin" #define CRUSH_CRIT_HEADGIB "crush_crit_headgib" #define VENDOR_CRUSH_CRIT_PIN "vendor_crush_crit_pin" diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm index d75d8bacec73a..0e6578d6e9a12 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm @@ -119,6 +119,9 @@ /// From base of area/Exited(): (area/left, direction) #define COMSIG_MOVABLE_EXITED_AREA "movable_exited_area" +///from base of /atom/movable/point_at: (atom/A, obj/effect/temp_visual/point/point) +#define COMSIG_MOVABLE_POINTED "movable_pointed" + /// Sent to movables when they are being stolen by a spy: (mob/living/spy, datum/spy_bounty/bounty) #define COMSIG_MOVABLE_SPY_STEALING "movable_spy_stealing" /// Called when something is pushed by a living mob bumping it: (mob/living/pusher, push force) diff --git a/code/__DEFINES/dcs/signals/signals_mind.dm b/code/__DEFINES/dcs/signals/signals_mind.dm index 72f43f518ebcd..e9a62a26102cf 100644 --- a/code/__DEFINES/dcs/signals/signals_mind.dm +++ b/code/__DEFINES/dcs/signals/signals_mind.dm @@ -6,3 +6,6 @@ /// Called on the mind when an antagonist is being removed, after the antagonist list has updated (datum/antagonist/antagonist) #define COMSIG_ANTAGONIST_REMOVED "antagonist_removed" + +/// Called on the mob when losing an antagonist datum (datum/antagonist/antagonist) +#define COMSIG_MOB_ANTAGONIST_REMOVED "mob_antagonist_removed" diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_ai.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_ai.dm index 026247acf57ab..16f7e00e78a19 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_ai.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_ai.dm @@ -9,3 +9,5 @@ ///Signal sent when a bot is reset #define COMSIG_BOT_RESET "bot_reset" +///Sent off /mob/living/basic/bot/proc/set_mode_flags() : (new_flags) +#define COMSIG_BOT_MODE_FLAGS_SET "bot_mode_flags_set" 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 051953bd7e508..2a936bbbbd94a 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm @@ -133,6 +133,10 @@ #define VISIBLE_NAME_FACE 1 //Index for the name of the id #define VISIBLE_NAME_ID 2 + //Index for whether their name is being overriden instead of obsfuscated + #define VISIBLE_NAME_FORCED 3 +///from /mob/living/carbon/human/get_id_name; only returns if the mob has TRAIT_UNKNOWN and it's being overriden: (identity) +#define COMSIG_HUMAN_GET_FORCED_NAME "human_get_forced_name" // Mob transformation signals ///Called when a human turns into a monkey, from /mob/living/carbon/proc/finish_monkeyize() diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm index dfbfe68ad52cd..da28cfe0b2f4b 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm @@ -150,8 +150,6 @@ /// from base of mob/swap_hand(): () /// Performed after the hands are swapped. #define COMSIG_MOB_SWAP_HANDS "mob_swap_hands" -///from base of /mob/verb/pointed: (atom/A) -#define COMSIG_MOB_POINTED "mob_pointed" ///Mob is trying to open the wires of a target [/atom], from /datum/wires/interactable(): (atom/target) #define COMSIG_TRY_WIRES_INTERACT "try_wires_interact" #define COMPONENT_CANT_INTERACT_WIRES (1<<0) @@ -248,3 +246,6 @@ /// from /mob/proc/key_down(): (key, client/client, full_key) #define COMSIG_MOB_KEYDOWN "mob_key_down" + +/// from /mob/update_incapacitated(): (old_incap, new_incap) +#define COMSIG_MOB_INCAPACITATE_CHANGED "mob_incapacitated" diff --git a/code/__DEFINES/dcs/signals/signals_movetype.dm b/code/__DEFINES/dcs/signals/signals_movetype.dm index bc8b296b47531..da584ba022f4a 100644 --- a/code/__DEFINES/dcs/signals/signals_movetype.dm +++ b/code/__DEFINES/dcs/signals/signals_movetype.dm @@ -1,6 +1,3 @@ -// /datum/element/movetype_handler signals -/// Called when the floating anim has to be temporarily stopped and restarted later: (timer) -#define COMSIG_PAUSE_FLOATING_ANIM "pause_floating_anim" /// From base of datum/element/movetype_handler/on_movement_type_trait_gain: (flag, old_movement_type) #define COMSIG_MOVETYPE_FLAG_ENABLED "movetype_flag_enabled" /// From base of datum/element/movetype_handler/on_movement_type_trait_loss: (flag, old_movement_type) diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index 45b671141a380..72828cc891699 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -530,6 +530,9 @@ /// from /datum/component/dart_insert/on_reskin() #define COMSIG_DART_INSERT_PARENT_RESKINNED "dart_insert_parent_reskinned" +/// from /datum/element/undertile/hide() +#define COMSIG_UNDERTILE_UPDATED "undertile_updated" + /// Sent from /obj/item/update_weight_class(). (old_w_class, new_w_class) #define COMSIG_ITEM_WEIGHT_CLASS_CHANGED "item_weight_class_changed" /// Sent from /obj/item/update_weight_class(), to its loc. (obj/item/changed_item, old_w_class, new_w_class) diff --git a/code/__DEFINES/food.dm b/code/__DEFINES/food.dm index 3787aeb4df7b9..c9b7cb43cf0d9 100644 --- a/code/__DEFINES/food.dm +++ b/code/__DEFINES/food.dm @@ -139,7 +139,7 @@ GLOBAL_LIST_INIT(food_quality_events, list( FOOD_QUALITY_TOP = /datum/mood_event/food/top, )) -/// Crafted food buffs grouped by crafting_complexity +/// Weighted lists of crafted food buffs randomly given according to crafting_complexity unless the food has a specific buff GLOBAL_LIST_INIT(food_buffs, list( FOOD_COMPLEXITY_1 = list( /datum/status_effect/food/haste = 1, @@ -152,11 +152,9 @@ GLOBAL_LIST_INIT(food_buffs, list( ), FOOD_COMPLEXITY_4 = list( /datum/status_effect/food/haste = 1, - /datum/status_effect/food/trait/shockimmune = 1, ), FOOD_COMPLEXITY_5 = list( /datum/status_effect/food/haste = 1, - /datum/status_effect/food/trait/shockimmune = 2, ), )) diff --git a/code/__DEFINES/icon_smoothing.dm b/code/__DEFINES/icon_smoothing.dm index af219a90eb1f4..d4d18ede5f386 100644 --- a/code/__DEFINES/icon_smoothing.dm +++ b/code/__DEFINES/icon_smoothing.dm @@ -210,6 +210,8 @@ DEFINE_BITFIELD(smoothing_junction, list( #define SMOOTH_GROUP_SPIDER_WEB_WALL_TOUGH S_OBJ(73) // /obj/structure/spider/stickyweb/sealed/thick #define SMOOTH_GROUP_SPIDER_WEB_WALL_MIRROR S_OBJ(74) // /obj/structure/spider/stickyweb/sealed/reflector +#define SMOOTH_GROUP_GRAV_FIELD S_OBJ(69) + /// Performs the work to set smoothing_groups and canSmoothWith. /// An inlined function used in both turf/Initialize and atom/Initialize. #define SETUP_SMOOTHING(...) \ diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 0d9d28d4d858a..be21dcf081a21 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -69,6 +69,8 @@ GLOBAL_LIST_INIT(turfs_openspace, typecacheof(list( #define isplatingturf(A) (istype(A, /turf/open/floor/plating)) +#define iscatwalkturf(A) (istype(A, /turf/open/floor/catwalk_floor)) + #define isasteroidturf(A) (istype(A, /turf/open/misc/asteroid)) #define istransparentturf(A) (HAS_TRAIT(A, TURF_Z_TRANSPARENT_TRAIT)) diff --git a/code/__DEFINES/language.dm b/code/__DEFINES/language.dm index cd6ee5ec0c9bd..d530185c14288 100644 --- a/code/__DEFINES/language.dm +++ b/code/__DEFINES/language.dm @@ -27,6 +27,7 @@ #define LANGUAGE_GLAND "gland" #define LANGUAGE_HAT "hat" #define LANGUAGE_QUIRK "quirk" +#define LANGUAGE_DRINK "drink" #define LANGUAGE_MALF "malf" #define LANGUAGE_PIRATE "pirate" #define LANGUAGE_MASTER "master" diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index 55272920fdd5a..dbb95419c2cc4 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -145,9 +145,9 @@ #define WIRE_LAYER (9 + TOPDOWN_LAYER) #define GLASS_FLOOR_LAYER (10 + TOPDOWN_LAYER) #define TRAM_RAIL_LAYER (11 + TOPDOWN_LAYER) +#define ABOVE_OPEN_TURF_LAYER (12 + TOPDOWN_LAYER) ///catwalk overlay of /turf/open/floor/plating/catwalk_floor -#define CATWALK_LAYER (12 + TOPDOWN_LAYER) -#define ABOVE_OPEN_TURF_LAYER (13 + TOPDOWN_LAYER) +#define CATWALK_LAYER (13 + TOPDOWN_LAYER) //WALL_PLANE layers #define BELOW_CLOSED_TURF_LAYER 2.053 diff --git a/code/__DEFINES/living.dm b/code/__DEFINES/living.dm index 63993f4bc620b..340bf3608bb5d 100644 --- a/code/__DEFINES/living.dm +++ b/code/__DEFINES/living.dm @@ -4,3 +4,6 @@ /// Always does *deathgasp when they die /// If unset mobs will only deathgasp if supplied a death sound or custom death message #define ALWAYS_DEATHGASP (1<<1) + +/// Getter for a mob/living's lying angle, otherwise protected +#define GET_LYING_ANGLE(mob) (UNLINT(mob.lying_angle)) diff --git a/code/__DEFINES/market.dm b/code/__DEFINES/market.dm index f0a19ad056d9a..e0bd457835208 100644 --- a/code/__DEFINES/market.dm +++ b/code/__DEFINES/market.dm @@ -10,3 +10,5 @@ // Sends a supply pod to the buyer's location, showy. #define SHIPPING_METHOD_SUPPLYPOD "Supply Pod" +/// The percentage on gains that's removed when selling an item through the blackmarket with the LTSRBT +#define MARKET_WITHHOLDING_TAX 0.15 diff --git a/code/__DEFINES/melee.dm b/code/__DEFINES/melee.dm index 8b3a422fc0b25..1880c75c97b8d 100644 --- a/code/__DEFINES/melee.dm +++ b/code/__DEFINES/melee.dm @@ -1,8 +1,9 @@ //Martial arts defines #define MARTIALART_BOXING "boxing" -#define MARTIALART_EVIL_BOXING "evil boxing" #define MARTIALART_CQC "CQC" +#define MARTIALART_EVIL_BOXING "evil boxing" +#define MARTIALART_HUNTER_BOXING "hunter boxing" #define MARTIALART_KRAVMAGA "krav maga" #define MARTIALART_MUSHPUNCH "mushroom punch" #define MARTIALART_PLASMAFIST "plasma fist" diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 833d2d546a718..18db049f6c179 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -917,6 +917,8 @@ GLOBAL_LIST_INIT(layers_to_offset, list( /// Possible value of [/atom/movable/buckle_lying]. If set to a different (positive-or-zero) value than this, the buckling thing will force a lying angle on the buckled. #define NO_BUCKLE_LYING -1 +/// Possible value of [/atom/movable/buckle_dir]. If set to a different (positive-or-zero) value than this, the buckling thing will force a dir on the buckled. +#define BUCKLE_MATCH_DIR -1 // Flags for fully_heal(). @@ -1013,6 +1015,8 @@ GLOBAL_LIST_INIT(layers_to_offset, list( /// The duration of the flip emote animation #define FLIP_EMOTE_DURATION 0.7 SECONDS +///The duration of a taunt emote, so how long they can deflect projectiles +#define TAUNT_EMOTE_DURATION 0.9 SECONDS // Sprites for photocopying butts #define BUTT_SPRITE_HUMAN_MALE "human_male" diff --git a/code/__DEFINES/radio.dm b/code/__DEFINES/radio.dm index 686c42e07d075..44e4417a20996 100644 --- a/code/__DEFINES/radio.dm +++ b/code/__DEFINES/radio.dm @@ -37,6 +37,10 @@ #define RADIO_KEY_AI_PRIVATE "o" #define RADIO_TOKEN_AI_PRIVATE ":o" +#define RADIO_CHANNEL_ENTERTAINMENT "Entertainment" +#define RADIO_KEY_ENTERTAINMENT "p" +#define RADIO_TOKEN_ENTERTAINMENT ":p" + #define RADIO_CHANNEL_SYNDICATE "Syndicate" #define RADIO_KEY_SYNDICATE "t" @@ -73,6 +77,7 @@ #define FREQ_MEDICAL 1355 // Medical comms frequency, soft blue #define FREQ_ENGINEERING 1357 // Engineering comms frequency, orange #define FREQ_SECURITY 1359 // Security comms frequency, red +#define FREQ_ENTERTAINMENT 1415 // Used by entertainment monitors, cyan #define FREQ_HOLOGRID_SOLUTION 1433 #define FREQ_STATUS_DISPLAYS 1435 @@ -130,3 +135,10 @@ #define RADIO_FREQENCY_LOCKED 1 /// Radio frequency is locked and unchangeable, but can be unlocked by an emag #define RADIO_FREQENCY_EMAGGABLE_LOCK 2 + +///Bitflag for if a headset can use the syndicate radio channel +#define RADIO_SPECIAL_SYNDIE (1<<0) +///Bitflag for if a headset can use the centcom radio channel +#define RADIO_SPECIAL_CENTCOM (1<<1) +///Bitflag for if a headset can use the binary radio channel +#define RADIO_SPECIAL_BINARY (1<<2) diff --git a/code/__DEFINES/research/anomalies.dm b/code/__DEFINES/research/anomalies.dm index 93f1bc924c288..e04aead3464bc 100644 --- a/code/__DEFINES/research/anomalies.dm +++ b/code/__DEFINES/research/anomalies.dm @@ -2,7 +2,7 @@ #define MAX_CORES_BLUESPACE 3 #define MAX_CORES_GRAVITATIONAL 6 #define MAX_CORES_FLUX 8 -#define MAX_CORES_VORTEX 1 +#define MAX_CORES_VORTEX 3 #define MAX_CORES_PYRO 8 #define MAX_CORES_HALLUCINATION 8 #define MAX_CORES_BIOSCRAMBLER 8 diff --git a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm index 2dcb96b8c42f1..f78e86fa33acc 100644 --- a/code/__DEFINES/sound.dm +++ b/code/__DEFINES/sound.dm @@ -176,5 +176,8 @@ GLOBAL_LIST_INIT(announcer_keys, list( #define SFX_PORTAL_CLOSE "portal_closed" #define SFX_PORTAL_CREATED "portal_created" #define SFX_SCREECH "screech" +#define SFX_TOOL_SWITCH "tool_switch" +#define SFX_KEYBOARD_CLICKS "keyboard_clicks" #define SFX_STONE_DROP "stone_drop" #define SFX_STONE_PICKUP "stone_pickup" +#define SFX_MUFFLED_SPEECH "muffspeech" diff --git a/code/__DEFINES/span.dm b/code/__DEFINES/span.dm index fadd00053156d..259a13e1e9afe 100644 --- a/code/__DEFINES/span.dm +++ b/code/__DEFINES/span.dm @@ -48,6 +48,7 @@ #define span_drone(str) ("" + str + "") #define span_engradio(str) ("" + str + "") #define span_extremelybig(str) ("" + str + "") +#define span_enteradio(str) ("" + str + "") #define span_game_say(str) ("" + str + "") #define span_ghostalert(str) ("" + str + "") #define span_green(str) ("" + str + "") diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index 8ada83a2109cb..ead7764d60523 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -24,12 +24,18 @@ #define CURSE_GRASPING (1<<3) //Incapacitated status effect flags -/// If the incapacitated status effect will ignore a mob in restraints (handcuffs) -#define IGNORE_RESTRAINTS (1<<0) -/// If the incapacitated status effect will ignore a mob in stasis (stasis beds) -#define IGNORE_STASIS (1<<1) -/// If the incapacitated status effect will ignore a mob being agressively grabbed -#define IGNORE_GRAB (1<<2) +/// If the mob is normal incapacitated. Should never need this, just avoids issues if we ever overexpand this +#define TRADITIONAL_INCAPACITATED (1<<0) +/// If the incapacitated status effect is being caused by restraints (handcuffs) +#define INCAPABLE_RESTRAINTS (1<<1) +/// If the incapacitated status effect is being caused by stasis (stasis beds) +#define INCAPABLE_STASIS (1<<2) +/// If the incapacitated status effect is being caused by being agressively grabbed +#define INCAPABLE_GRAB (1<<3) + +/// Checks to see if a mob would be incapacitated even while ignoring some types +/// Does this by inverting the passed in flags and seeing if we're still incapacitated +#define INCAPACITATED_IGNORING(mob, flags) (mob.incapacitated & ~(flags)) /// Maxamounts of fire stacks a mob can get #define MAX_FIRE_STACKS 20 diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index fba8a97d713a2..a08d454315d5a 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -156,6 +156,7 @@ #define INIT_ORDER_TICKER 55 #define INIT_ORDER_TCG 55 #define INIT_ORDER_MAPPING 50 +#define INIT_ORDER_AI_IDLE_CONTROLLERS 50 #define INIT_ORDER_EARLY_ASSETS 48 #define INIT_ORDER_RESEARCH 47 #define INIT_ORDER_TIMETRACK 46 @@ -192,7 +193,7 @@ // Subsystem fire priority, from lowest to highest priority // If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child) - +#define FIRE_PRIORITY_IDLE_NPC 5 #define FIRE_PRIORITY_PING 10 #define FIRE_PRIORITY_SERVER_MAINT 10 #define FIRE_PRIORITY_RESEARCH 10 diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 294d32ddc3b0f..a95d771a6fd81 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -357,8 +357,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_GUNFLIP "gunflip" /// Increases chance of getting special traumas, makes them harder to cure #define TRAIT_SPECIAL_TRAUMA_BOOST "special_trauma_boost" -/// Doubles the duration and cooldown of a flip -#define TRAIT_SLOW_FLIP "slow_flip" #define TRAIT_SPACEWALK "spacewalk" /// Sanity trait to keep track of when we're in hyperspace and add the appropriate element if we werent #define TRAIT_HYPERSPACED "hyperspaced" @@ -419,6 +417,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_ANTENNAE "antennae" /// Blowing kisses actually does damage to the victim #define TRAIT_KISS_OF_DEATH "kiss_of_death" +/// Syndie kisses can apply burn damage +#define TRAIT_SYNDIE_KISS "syndie_kiss" /// Used to activate french kissing #define TRAIT_GARLIC_BREATH "kiss_of_garlic_death" /// Addictions don't tick down, basically they're permanently addicted @@ -527,9 +527,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Mobs with this trait cannot be hit by projectiles, meaning the projectiles will just go through. #define TRAIT_UNHITTABLE_BY_PROJECTILES "unhittable_by_projectiles" -/// Projectile with this trait will always hit the defined zone of a struck living mob. -#define TRAIT_ALWAYS_HIT_ZONE "always_hit_zone" - /// Mobs with this trait do care about a few grisly things, such as digging up graves. They also really do not like bringing people back to life or tending wounds, but love autopsies and amputations. #define TRAIT_MORBID "morbid" @@ -667,6 +664,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// This movable atom has the explosive block element #define TRAIT_BLOCKING_EXPLOSIVES "blocking_explosives" +///This mob is currently blocking a projectile. +#define TRAIT_BLOCKING_PROJECTILES "blocking_projectiles" + ///Lava will be safe to cross while it has this trait. #define TRAIT_LAVA_STOPPED "lava_stopped" ///Chasms will be safe to cross while they've this trait. @@ -1230,4 +1230,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai ///Trait which allows mobs to parry mining mob projectiles #define TRAIT_MINING_PARRYING "mining_parrying" +///A "fake" effect that should not be subject to normal effect removal methods (like the effect remover component) +#define TRAIT_ILLUSORY_EFFECT "illusory_effect" + // END TRAIT DEFINES diff --git a/code/__DEFINES/traits/sources.dm b/code/__DEFINES/traits/sources.dm index f11cc50dbbd58..be19cfde51a0a 100644 --- a/code/__DEFINES/traits/sources.dm +++ b/code/__DEFINES/traits/sources.dm @@ -45,7 +45,8 @@ /// Trait given by an Action datum #define ACTION_TRAIT "action" - +///A trait given by someone blocking. +#define BLOCKING_TRAIT "blocking" #define CLOTHING_TRAIT "clothing" #define HELMET_TRAIT "helmet" /// inherited from the mask @@ -193,6 +194,9 @@ /// Trait given by a fulton extraction pack #define FULTON_PACK_TRAIT "fulton-pack" +/// Trait from mob/living/update_transform() +#define UPDATE_TRANSFORM_TRAIT "update_transform" + /// Trait granted by the berserker hood. #define BERSERK_TRAIT "berserk_trait" /// Trait granted by [/obj/item/rod_of_asclepius] diff --git a/code/__HELPERS/atoms.dm b/code/__HELPERS/atoms.dm index 7106ec81be1ba..646410026a054 100644 --- a/code/__HELPERS/atoms.dm +++ b/code/__HELPERS/atoms.dm @@ -63,17 +63,17 @@ var/turf/target_turf = get_turf(target) if(get_dist(source, target) > length) return FALSE - var/steps = 1 - if(current == target_turf)//they are on the same turf, source can see the target + if(current == target_turf || source.CanReach(target))//they are on the same turf or in reach, source can see the target return TRUE - current = get_step_towards(current, target_turf) - while(current != target_turf) - if(steps > length) - return FALSE + var/list/steps = get_steps_to(source, target) + if(isnull(steps) || length(steps) > length) + return FALSE + for(var/direction in steps) + current = get_step(current, direction) + if(current == target_turf) + break if(IS_OPAQUE_TURF(current)) return FALSE - current = get_step_towards(current, target_turf) - steps++ return TRUE ///Get the cardinal direction between two atoms diff --git a/code/__HELPERS/hallucinations.dm b/code/__HELPERS/hallucinations.dm index edd65ee926abf..00fee61e2b1ca 100644 --- a/code/__HELPERS/hallucinations.dm +++ b/code/__HELPERS/hallucinations.dm @@ -86,6 +86,30 @@ GLOBAL_LIST_EMPTY(all_ongoing_hallucinations) if(length(optional_messages)) to_chat(nearby_living, pick(optional_messages)) +/** + * Emits a hallucinating pulse around the passed atom. + * Affects everyone in the passed radius except for those with TRAIT_MADNESS_IMMUNE. This affects blind players. + * + * center - required, the center of the pulse + * radius - the radius around that the pulse reaches + * hallucination_duration - how much hallucination is added by the pulse. reduced based on distance to the center. + * hallucination_max_duration - a cap on how much hallucination can be added + * optional_messages - optional list of messages passed. Those affected by pulses will be given one of the messages in said list. + */ +/proc/hallucination_pulse(atom/center, radius = 7, hallucination_duration = 50 SECONDS, hallucination_max_duration, list/optional_messages) + for(var/mob/living/nearby_living in range(center, radius)) + if(HAS_MIND_TRAIT(nearby_living, TRAIT_MADNESS_IMMUNE)) + continue + + if(nearby_living.mob_biotypes & NO_HALLUCINATION_BIOTYPES) + continue + + // Everyone else gets hallucinations. + var/dist = sqrt(1 / max(1, get_dist(nearby_living, center))) + nearby_living.adjust_hallucinations_up_to(hallucination_duration * dist, hallucination_max_duration) + if(length(optional_messages)) + to_chat(nearby_living, pick(optional_messages)) + /// Global weighted list of all hallucinations that can show up randomly. GLOBAL_LIST_INIT(random_hallucination_weighted_list, generate_hallucination_weighted_list()) diff --git a/code/__HELPERS/paths/path.dm b/code/__HELPERS/paths/path.dm index 189120b76c3bc..85bada9db13b4 100644 --- a/code/__HELPERS/paths/path.dm +++ b/code/__HELPERS/paths/path.dm @@ -335,7 +335,7 @@ src.has_gravity = construct_from.has_gravity() if(ismob(construct_from)) var/mob/living/mob_construct = construct_from - src.incapacitated = mob_construct.incapacitated() + src.incapacitated = mob_construct.incapacitated if(mob_construct.buckled) src.buckled_info = new(mob_construct.buckled, access, no_id, call_depth + 1) if(isobserver(construct_from)) diff --git a/code/__HELPERS/reagents.dm b/code/__HELPERS/reagents.dm index cb87e21cefa54..51ff7df475ee1 100644 --- a/code/__HELPERS/reagents.dm +++ b/code/__HELPERS/reagents.dm @@ -180,14 +180,23 @@ else return null -///Returns a random reagent object minus blacklisted reagents -/proc/get_random_reagent_id() - var/static/list/random_reagents = list() - if(!random_reagents.len) +///Returns a random reagent object, with the option to blacklist reagents. +/proc/get_random_reagent_id(list/blacklist) + var/static/list/reagent_static_list = list() //This is static, and will be used by default if a blacklist is not passed. + var/list/reagent_list_to_process + if(blacklist) //If we do have a blacklist, we recompile a new list with the excluded reagents not present and pick from there. + reagent_list_to_process = list() + else + reagent_list_to_process = reagent_static_list + + if(!reagent_list_to_process.len) for(var/datum/reagent/reagent_path as anything in subtypesof(/datum/reagent)) + if(is_path_in_list(reagent_path, blacklist)) + continue if(initial(reagent_path.chemical_flags) & REAGENT_CAN_BE_SYNTHESIZED) - random_reagents += reagent_path - var/picked_reagent = pick(random_reagents) + reagent_list_to_process += reagent_path + + var/picked_reagent = pick(reagent_list_to_process) return picked_reagent ///Returns a random reagent consumable ethanol object minus blacklisted reagents diff --git a/code/__HELPERS/spatial_info.dm b/code/__HELPERS/spatial_info.dm index 529532f50cf4d..2a8b61bd01db8 100644 --- a/code/__HELPERS/spatial_info.dm +++ b/code/__HELPERS/spatial_info.dm @@ -195,8 +195,12 @@ var/turf/inbetween_turf = center_turf //this is the lowest overhead way of doing a loop in dm other than a goto. distance is guaranteed to be >= steps taken to target by this algorithm - for(var/step_counter in 1 to distance) - inbetween_turf = get_step_towards(inbetween_turf, target_turf) + var/list/steps = get_steps_to(inbetween_turf, target_turf) + if(isnull(steps)) + return + steps.Cut(distance + 1) + for(var/direction in steps) + inbetween_turf = get_step(inbetween_turf, direction) if(inbetween_turf == target_turf)//we've gotten to target's turf without returning due to turf opacity, so we must be able to see target break diff --git a/code/__HELPERS/visual_effects.dm b/code/__HELPERS/visual_effects.dm index d219d11e1ce82..2b845c2131b00 100644 --- a/code/__HELPERS/visual_effects.dm +++ b/code/__HELPERS/visual_effects.dm @@ -44,9 +44,9 @@ speed /= segments if(parallel) - animate(src, transform = matrices[1], time = speed, loops , flags = ANIMATION_PARALLEL) + animate(src, transform = matrices[1], time = speed, loop = loops, flags = ANIMATION_PARALLEL) else - animate(src, transform = matrices[1], time = speed, loops) + animate(src, transform = matrices[1], time = speed, loop = loops) for(var/i in 2 to segments) //2 because 1 is covered above animate(transform = matrices[i], time = speed) //doesn't have an object argument because this is "Stacking" with the animate call above diff --git a/code/_globalvars/admin.dm b/code/_globalvars/admin.dm index 96f07e3cca870..e14a56c16814c 100644 --- a/code/_globalvars/admin.dm +++ b/code/_globalvars/admin.dm @@ -76,6 +76,7 @@ GLOBAL_LIST_INIT(spanname_to_formatting, list( "Drone Radio" = "drone", "Engineering Radio" = "engradio", "Extremely Big" = "extremelybig", + "Entertainment Radio" = "enteradio", "Game Say" = "game say", "Ghost Alert" = "ghostalert", "Green" = "green", diff --git a/code/_globalvars/lists/basic_ai.dm b/code/_globalvars/lists/basic_ai.dm new file mode 100644 index 0000000000000..8d79c9bfafeaf --- /dev/null +++ b/code/_globalvars/lists/basic_ai.dm @@ -0,0 +1,12 @@ +///all basic ai subtrees +GLOBAL_LIST_EMPTY(ai_subtrees) + +///basic ai controllers based on status +GLOBAL_LIST_INIT(ai_controllers_by_status, list( + AI_STATUS_ON = list(), + AI_STATUS_OFF = list(), + AI_STATUS_IDLE = list(), +)) + +///basic ai controllers based on their z level +GLOBAL_LIST_EMPTY(ai_controllers_by_zlevel) diff --git a/code/_globalvars/lists/quirks.dm b/code/_globalvars/lists/quirks.dm index 22ef830ea773d..896504beb7b2a 100644 --- a/code/_globalvars/lists/quirks.dm +++ b/code/_globalvars/lists/quirks.dm @@ -92,3 +92,9 @@ GLOBAL_LIST_INIT(organ_choice, list( "Liver" = ORGAN_SLOT_LIVER, "Stomach" = ORGAN_SLOT_STOMACH, )) + +///Paraplegic Quirk +GLOBAL_LIST_INIT(paraplegic_choice, list( + "Default" = FALSE, + "Amputee" = TRUE, +)) diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 0dfcc67c5e1be..527271e91ce0b 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -148,6 +148,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_BIRTHDAY_BOY" = TRAIT_BIRTHDAY_BOY, "TRAIT_BLOB_ALLY" = TRAIT_BLOB_ALLY, "TRAIT_BLOCK_SHUTTLE_MOVEMENT" = TRAIT_BLOCK_SHUTTLE_MOVEMENT, + "TRAIT_BLOCKING_PROJECTILES" = TRAIT_BLOCKING_PROJECTILES, "TRAIT_BLOOD_CLANS" = TRAIT_BLOOD_CLANS, "TRAIT_BLOODSHOT_EYES" = TRAIT_BLOODSHOT_EYES, "TRAIT_BLOODY_MESS" = TRAIT_BLOODY_MESS, @@ -288,6 +289,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_IWASBATONED" = TRAIT_IWASBATONED, "TRAIT_JOLLY" = TRAIT_JOLLY, "TRAIT_KISS_OF_DEATH" = TRAIT_KISS_OF_DEATH, + "TRAIT_SYNDIE_KISS" = TRAIT_SYNDIE_KISS, "TRAIT_KNOCKEDOUT" = TRAIT_KNOCKEDOUT, "TRAIT_KNOW_ENGI_WIRES" = TRAIT_KNOW_ENGI_WIRES, "TRAIT_KNOW_ROBO_WIRES" = TRAIT_KNOW_ROBO_WIRES, @@ -446,7 +448,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_SIXTHSENSE" = TRAIT_SIXTHSENSE, "TRAIT_SKITTISH" = TRAIT_SKITTISH, "TRAIT_SLEEPIMMUNE" = TRAIT_SLEEPIMMUNE, - "TRAIT_SLOW_FLIP" = TRAIT_SLOW_FLIP, "TRAIT_SMOKER" = TRAIT_SMOKER, "TRAIT_SNEAK" = TRAIT_SNEAK, "TRAIT_SNOB" = TRAIT_SNOB, @@ -531,6 +532,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_XRAY_VISION" = TRAIT_XRAY_VISION, "TRAIT_SPEECH_BOOSTER" = TRAIT_SPEECH_BOOSTER, "TRAIT_MINING_PARRYING" = TRAIT_MINING_PARRYING, + "TRAIT_ILLUSORY_EFFECT" = TRAIT_ILLUSORY_EFFECT, ), /obj/item = list( "TRAIT_APC_SHOCKING" = TRAIT_APC_SHOCKING, @@ -632,9 +634,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( /obj/machinery/modular_computer = list( "TRAIT_MODPC_INTERACTING_WITH_FRAME" = TRAIT_MODPC_INTERACTING_WITH_FRAME, ), - /obj/projectile = list( - "TRAIT_ALWAYS_HIT_ZONE" = TRAIT_ALWAYS_HIT_ZONE, - ), /obj/structure = list( "TRAIT_RADSTORM_IMMUNE" = TRAIT_RADSTORM_IMMUNE, ), diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index 585d121e6ce67..4c8b0a9c7a190 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -259,7 +259,6 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_SIXTHSENSE" = TRAIT_SIXTHSENSE, "TRAIT_SKITTISH" = TRAIT_SKITTISH, "TRAIT_SLEEPIMMUNE" = TRAIT_SLEEPIMMUNE, - "TRAIT_SLOW_FLIP" = TRAIT_SLOW_FLIP, "TRAIT_SMOKER" = TRAIT_SMOKER, "TRAIT_SNOB" = TRAIT_SNOB, "TRAIT_SOFTSPOKEN" = TRAIT_SOFTSPOKEN, diff --git a/code/_onclick/adjacent.dm b/code/_onclick/adjacent.dm index ab5b3f4aad974..a4a8ae1cdc41a 100644 --- a/code/_onclick/adjacent.dm +++ b/code/_onclick/adjacent.dm @@ -68,6 +68,8 @@ /atom/movable/Adjacent(atom/neighbor, atom/target, atom/movable/mover) if(neighbor == loc) return TRUE + if(neighbor?.loc == src) + return TRUE var/turf/T = loc if(!istype(T)) return FALSE @@ -79,6 +81,8 @@ /obj/item/Adjacent(atom/neighbor, atom/target, atom/movable/mover, recurse = 1) if(neighbor == loc) return TRUE + if(neighbor?.loc == src) + return TRUE if(isitem(loc)) if(recurse > 0) return loc.Adjacent(neighbor, target, mover, recurse - 1) diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index ec76dee9c8e22..200f56bed971c 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -7,7 +7,7 @@ Note that AI have no need for the adjacency proc, and so this proc is a lot cleaner. */ /mob/living/silicon/ai/DblClickOn(atom/A, params) - if(control_disabled || incapacitated()) + if(control_disabled || incapacitated) return if(ismob(A)) @@ -39,7 +39,7 @@ if(check_click_intercept(params,A)) return - if(control_disabled || incapacitated()) + if(control_disabled || incapacitated) return var/turf/pixel_turf = get_turf_pixel(A) diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 1d7e07f7b9912..6696d985d0b8c 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -101,7 +101,7 @@ CtrlClickOn(A) return - if(incapacitated(IGNORE_RESTRAINTS|IGNORE_STASIS)) + if(INCAPACITATED_IGNORING(src, INCAPABLE_RESTRAINTS|INCAPABLE_STASIS)) return face_atom(A) @@ -247,7 +247,8 @@ return TRUE /proc/CheckToolReach(atom/movable/here, atom/movable/there, reach) - if(!here || !there) + . = FALSE + if(QDELETED(here) || QDELETED(there)) return switch(reach) if(0) @@ -258,14 +259,18 @@ var/obj/dummy = new(get_turf(here)) dummy.pass_flags |= PASSTABLE dummy.SetInvisibility(INVISIBILITY_ABSTRACT) - for(var/i in 1 to reach) //Limit it to that many tries - var/turf/T = get_step(dummy, get_dir(dummy, there)) + var/list/steps = get_steps_to(dummy, there) + if(isnull(steps) || length(steps) > reach) // If the path is further than the reach, no way we can reach it anyways. + qdel(dummy) + return FALSE + for(var/direction in steps) + var/turf/next_step = get_step(dummy, direction) if(dummy.CanReach(there)) qdel(dummy) return TRUE - if(!dummy.Move(T)) //we're blocked! + if(!dummy.Move(next_step)) // We're blocked, nope. qdel(dummy) - return + return FALSE qdel(dummy) /// Default behavior: ignore double clicks (the second click that makes the doubleclick call already calls for a normal click) diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm index a2dda93f4011f..60640d01d5a1f 100644 --- a/code/_onclick/cyborg.dm +++ b/code/_onclick/cyborg.dm @@ -58,7 +58,7 @@ return if(W) - if(incapacitated()) + if(incapacitated) return //while buckled, you can still connect to and control things like doors, but you can't use your modules diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm index 84efaf77c5dc9..aaad7457f6d3c 100644 --- a/code/_onclick/hud/ai.dm +++ b/code/_onclick/hud/ai.dm @@ -2,7 +2,7 @@ icon = 'icons/hud/screen_ai.dmi' /atom/movable/screen/ai/Click() - if(isobserver(usr) || usr.incapacitated()) + if(isobserver(usr) || usr.incapacitated) return TRUE /atom/movable/screen/ai/aicore diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index d0f6426254936..c2972081007ab 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -110,7 +110,7 @@ if(world.time <= usr.next_move) return 1 - if(usr.incapacitated()) + if(usr.incapacitated) return 1 if(ismob(usr)) @@ -143,7 +143,7 @@ screen_loc = ui_building /atom/movable/screen/area_creator/Click() - if(usr.incapacitated() || (isobserver(usr) && !isAdminGhostAI(usr))) + if(usr.incapacitated || (isobserver(usr) && !isAdminGhostAI(usr))) return TRUE var/area/A = get_area(usr) if(!A.outdoors) @@ -204,7 +204,7 @@ if(world.time <= usr.next_move) return TRUE - if(usr.incapacitated(IGNORE_STASIS)) + if(INCAPACITATED_IGNORING(usr, INCAPABLE_STASIS)) return TRUE if(ismecha(usr.loc)) // stops inventory actions in a mech return TRUE @@ -294,7 +294,7 @@ return TRUE if(world.time <= user.next_move) return TRUE - if(user.incapacitated()) + if(user.incapacitated) return TRUE if (ismecha(user.loc)) // stops inventory actions in a mech return TRUE @@ -471,7 +471,7 @@ if(world.time <= usr.next_move) return TRUE - if(usr.incapacitated()) + if(usr.incapacitated) return TRUE if(ismecha(usr.loc)) // stops inventory actions in a mech return TRUE diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 17de9f9d5cb77..aa8c3076135ce 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -275,7 +275,7 @@ if(!attacking_item.force) return - var/damage = take_damage(attacking_item.force, attacking_item.damtype, MELEE, 1) + var/damage = take_damage(attacking_item.force, attacking_item.damtype, MELEE, 1, get_dir(src, user)) //only witnesses close by and the victim see a hit message. user.visible_message(span_danger("[user] hits [src] with [attacking_item][damage ? "." : ", without leaving a mark!"]"), \ span_danger("You hit [src] with [attacking_item][damage ? "." : ", without leaving a mark!"]"), null, COMBAT_MESSAGE_RANGE) diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index 2f1465ac4ffe2..eab5f0a7cd9c9 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -109,11 +109,11 @@ if(!(interaction_flags_atom & INTERACT_ATOM_IGNORE_INCAPACITATED)) var/ignore_flags = NONE if(interaction_flags_atom & INTERACT_ATOM_IGNORE_RESTRAINED) - ignore_flags |= IGNORE_RESTRAINTS + ignore_flags |= INCAPABLE_RESTRAINTS if(!(interaction_flags_atom & INTERACT_ATOM_CHECK_GRAB)) - ignore_flags |= IGNORE_GRAB + ignore_flags |= INCAPABLE_GRAB - if(user.incapacitated(ignore_flags)) + if(INCAPACITATED_IGNORING(user, ignore_flags)) return FALSE return TRUE diff --git a/code/controllers/subsystem/ai_controllers.dm b/code/controllers/subsystem/ai_controllers.dm index a6badb44a3f0e..30d3c4986f2a2 100644 --- a/code/controllers/subsystem/ai_controllers.dm +++ b/code/controllers/subsystem/ai_controllers.dm @@ -6,40 +6,23 @@ SUBSYSTEM_DEF(ai_controllers) 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/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(), - AI_STATUS_IDLE = 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() + ///type of status we are interested in running + var/planning_status = AI_STATUS_ON /// The tick cost of all active AI, calculated on fire. - var/cost_on - /// The tick cost of all idle AI, calculated on fire. - var/cost_idle - + var/our_cost /datum/controller/subsystem/ai_controllers/Initialize() setup_subtrees() return SS_INIT_SUCCESS /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] - var/list/idle_list = ai_controllers_by_status[AI_STATUS_IDLE] - msg = "Active AIs:[length(active_list)]/[round(cost_on,1)]%|Inactive:[length(inactive_list)]|Idle:[length(idle_list)]/[round(cost_idle,1)]%" + var/list/planning_list = GLOB.ai_controllers_by_status[planning_status] + msg = "Planning AIs:[length(planning_list)]/[round(our_cost,1)]%" return ..() /datum/controller/subsystem/ai_controllers/fire(resumed) var/timer = TICK_USAGE_REAL - cost_idle = MC_AVERAGE(cost_idle, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) - - timer = TICK_USAGE_REAL - for(var/datum/ai_controller/ai_controller as anything in ai_controllers_by_status[AI_STATUS_ON]) + for(var/datum/ai_controller/ai_controller as anything in GLOB.ai_controllers_by_status[planning_status]) if(!COOLDOWN_FINISHED(ai_controller, failed_planning_cooldown)) continue @@ -49,18 +32,20 @@ SUBSYSTEM_DEF(ai_controllers) if(!LAZYLEN(ai_controller.current_behaviors)) //Still no plan COOLDOWN_START(ai_controller, failed_planning_cooldown, AI_FAILED_PLANNING_COOLDOWN) - cost_on = MC_AVERAGE(cost_on, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) + our_cost = MC_AVERAGE(our_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) ///Creates all instances of ai_subtrees and assigns them to the ai_subtrees list. /datum/controller/subsystem/ai_controllers/proc/setup_subtrees() + if(length(GLOB.ai_subtrees)) + return for(var/subtree_type in subtypesof(/datum/ai_planning_subtree)) var/datum/ai_planning_subtree/subtree = new subtree_type - ai_subtrees[subtree_type] = subtree + GLOB.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() + if(!length(GLOB.ai_controllers_by_zlevel)) + GLOB.ai_controllers_by_zlevel = new /list(world.maxz,0) + while (GLOB.ai_controllers_by_zlevel.len < world.maxz) + GLOB.ai_controllers_by_zlevel.len++ + GLOB.ai_controllers_by_zlevel[GLOB.ai_controllers_by_zlevel.len] = list() diff --git a/code/controllers/subsystem/ai_idle_controllers.dm b/code/controllers/subsystem/ai_idle_controllers.dm new file mode 100644 index 0000000000000..367a2c82ffc95 --- /dev/null +++ b/code/controllers/subsystem/ai_idle_controllers.dm @@ -0,0 +1,8 @@ +AI_CONTROLLER_SUBSYSTEM_DEF(ai_idle_controllers) + name = "AI Idle Controllers" + flags = SS_POST_FIRE_TIMING | SS_BACKGROUND + priority = FIRE_PRIORITY_IDLE_NPC + init_order = INIT_ORDER_AI_IDLE_CONTROLLERS + wait = 5 SECONDS + runlevels = RUNLEVEL_GAME + planning_status = AI_STATUS_IDLE diff --git a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm index 3ea1a9a40d88f..18ba37eb13785 100644 --- a/code/controllers/subsystem/blackbox.dm +++ b/code/controllers/subsystem/blackbox.dm @@ -152,6 +152,8 @@ SUBSYSTEM_DEF(blackbox) record_feedback("tally", "radio_usage", 1, "centcom") if(FREQ_AI_PRIVATE) record_feedback("tally", "radio_usage", 1, "ai private") + if(FREQ_ENTERTAINMENT) + record_feedback("tally", "radio_usage", 1, "entertainment") if(FREQ_CTF_RED) record_feedback("tally", "radio_usage", 1, "CTF red team") if(FREQ_CTF_BLUE) diff --git a/code/controllers/subsystem/id_access.dm b/code/controllers/subsystem/id_access.dm index 38bf3b568a1f9..b80e5718128bd 100644 --- a/code/controllers/subsystem/id_access.dm +++ b/code/controllers/subsystem/id_access.dm @@ -291,7 +291,7 @@ SUBSYSTEM_DEF(id_access) desc_by_access["[ACCESS_VIROLOGY]"] = "Virology" desc_by_access["[ACCESS_PSYCHOLOGY]"] = "Psychology" desc_by_access["[ACCESS_CMO]"] = "CMO Office" - desc_by_access["[ACCESS_QM]"] = "Quartermaster" + desc_by_access["[ACCESS_QM]"] = "QM Office" desc_by_access["[ACCESS_SURGERY]"] = "Surgery" desc_by_access["[ACCESS_THEATRE]"] = "Theatre" desc_by_access["[ACCESS_RESEARCH]"] = "Science" @@ -398,6 +398,8 @@ SUBSYSTEM_DEF(id_access) id_card.clear_access() id_card.trim = trim + id_card.big_pointer = trim.big_pointer + id_card.pointer_color = trim.pointer_color if(copy_access) id_card.access = trim.access.Copy() @@ -441,6 +443,8 @@ SUBSYSTEM_DEF(id_access) id_card.department_color_override = trim.department_color id_card.department_state_override = trim.department_state id_card.subdepartment_color_override = trim.subdepartment_color + id_card.big_pointer = trim.big_pointer + id_card.pointer_color = trim.pointer_color if(!check_forged || !id_card.forged) id_card.assignment = trim.assignment @@ -461,6 +465,8 @@ SUBSYSTEM_DEF(id_access) id_card.department_color_override = null id_card.department_state_override = null id_card.subdepartment_color_override = null + id_card.big_pointer = id_card.trim.big_pointer + id_card.pointer_color = id_card.trim.pointer_color /** * Adds the accesses associated with a trim to an ID card. diff --git a/code/controllers/subsystem/persistence/engravings.dm b/code/controllers/subsystem/persistence/engravings.dm index f47fc7fbba124..6808a101bb8d5 100644 --- a/code/controllers/subsystem/persistence/engravings.dm +++ b/code/controllers/subsystem/persistence/engravings.dm @@ -27,7 +27,7 @@ var/successfully_loaded_engravings = 0 - for(var/iteration in 1 to rand(MIN_PERSISTENT_ENGRAVINGS, MAX_PERSISTENT_ENGRAVINGS)) + for(var/iteration in 1 to min(rand(MIN_PERSISTENT_ENGRAVINGS, MAX_PERSISTENT_ENGRAVINGS), saved_engravings.len)) var/engraving = pick_n_take(saved_engravings) if(!islist(engraving)) stack_trace("something's wrong with the engraving data! one of the saved engravings wasn't a list!") diff --git a/code/controllers/subsystem/polling.dm b/code/controllers/subsystem/polling.dm index fa219cd3da9f0..b830514460e0e 100644 --- a/code/controllers/subsystem/polling.dm +++ b/code/controllers/subsystem/polling.dm @@ -176,6 +176,8 @@ SUBSYSTEM_DEF(polling) UNTIL(new_poll.finished) if(!(amount_to_pick > 0)) return new_poll.signed_up + if(length(new_poll.signed_up) < amount_to_pick) + return new_poll.signed_up for(var/pick in 1 to amount_to_pick) new_poll.chosen_candidates += pick_n_take(new_poll.signed_up) if(announce_chosen) diff --git a/code/controllers/subsystem/processing/ai_idle_behaviors.dm b/code/controllers/subsystem/processing/ai_idle_behaviors.dm new file mode 100644 index 0000000000000..cda3d354882f4 --- /dev/null +++ b/code/controllers/subsystem/processing/ai_idle_behaviors.dm @@ -0,0 +1,6 @@ +PROCESSING_SUBSYSTEM_DEF(idle_ai_behaviors) + name = "idle_ai_behaviors" + flags = SS_NO_INIT | SS_BACKGROUND + wait = 1.5 SECONDS + priority = FIRE_PRIORITY_IDLE_NPC + init_order = INIT_ORDER_AI_IDLE_CONTROLLERS //must execute only after ai behaviors are initialized diff --git a/code/datums/achievements/misc_achievements.dm b/code/datums/achievements/misc_achievements.dm index 1d7b9da3a015a..bd1719783e12a 100644 --- a/code/datums/achievements/misc_achievements.dm +++ b/code/datums/achievements/misc_achievements.dm @@ -232,3 +232,9 @@ desc = "Successfully carry a boulder from Lavaland all the way to Centcom, without ever dropping it. We must imagine you're happy to unlock this." database_id = MEDAL_SISYPHUS icon_state = "sisyphus" + +/datum/award/achievement/misc/cigarettes + name = "Unhealthy snacks" + desc = "You were curious to taste it. And then another. You must have more!" + database_id = MEDAL_CIGARETTES + icon_state = "cigarettes" diff --git a/code/datums/actions/items/reload_rebar.dm b/code/datums/actions/items/reload_rebar.dm new file mode 100644 index 0000000000000..a29b02f6b227e --- /dev/null +++ b/code/datums/actions/items/reload_rebar.dm @@ -0,0 +1,5 @@ +/datum/action/item_action/reload_rebar + name = "Reload Rebar" + desc = "Reloads a held crossbow" + button_icon = 'icons/mob/actions/actions_items.dmi' + button_icon_state = "bolts" diff --git a/code/datums/ai/_ai_controller.dm b/code/datums/ai/_ai_controller.dm index 33b63f09a01dc..a2fc1cdc62e18 100644 --- a/code/datums/ai/_ai_controller.dm +++ b/code/datums/ai/_ai_controller.dm @@ -63,6 +63,12 @@ multiple modular subtrees with behaviors ///What distance should we be checking for interesting things when considering idling/deidling? Defaults to AI_DEFAULT_INTERESTING_DIST var/interesting_dist = AI_DEFAULT_INTERESTING_DIST + /// TRUE if we're able to run, FALSE if we aren't + /// Should not be set manually, override get_able_to_run() instead + /// Make sure you hook update_able_to_run() in setup_able_to_run() to whatever parameters changing that you added + /// Otherwise we will not pay attention to them changing + var/able_to_run = FALSE + /datum/ai_controller/New(atom/new_pawn) change_ai_movement_type(ai_movement) init_subtrees() @@ -103,12 +109,13 @@ multiple modular subtrees with behaviors return var/list/temp_subtree_list = list() for(var/subtree in planning_subtrees) - var/subtree_instance = SSai_controllers.ai_subtrees[subtree] + var/subtree_instance = GLOB.ai_subtrees[subtree] temp_subtree_list += subtree_instance planning_subtrees = temp_subtree_list ///Proc to move from one pawn to another, this will destroy the target's existing controller. /datum/ai_controller/proc/PossessPawn(atom/new_pawn) + SHOULD_CALL_PARENT(TRUE) if(pawn) //Reset any old signals UnpossessPawn(FALSE) @@ -124,7 +131,7 @@ multiple modular subtrees with behaviors var/turf/pawn_turf = get_turf(pawn) if(pawn_turf) - SSai_controllers.ai_controllers_by_zlevel[pawn_turf.z] += src + GLOB.ai_controllers_by_zlevel[pawn_turf.z] += src SEND_SIGNAL(src, COMSIG_AI_CONTROLLER_POSSESSED_PAWN) @@ -133,6 +140,8 @@ multiple modular subtrees with behaviors 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)) + update_able_to_run() + setup_able_to_run() our_cells = new(interesting_dist, interesting_dist, 1) set_new_cells() @@ -248,14 +257,11 @@ multiple modular subtrees with behaviors 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_IDLE) - else - set_ai_status(AI_STATUS_OFF) + GLOB.ai_controllers_by_zlevel[old_turf.z] -= src + if(isnull(new_turf)) + return + GLOB.ai_controllers_by_zlevel[new_turf.z] += src + reset_ai_status() ///Abstract proc for initializing the pawn to the new controller /datum/ai_controller/proc/TryPossessPawn(atom/new_pawn) @@ -263,25 +269,38 @@ multiple modular subtrees with behaviors ///Proc for deinitializing the pawn to the old controller /datum/ai_controller/proc/UnpossessPawn(destroy) + SHOULD_CALL_PARENT(TRUE) if(isnull(pawn)) return // instantiated without an applicable pawn, fine set_ai_status(AI_STATUS_OFF) UnregisterSignal(pawn, list(COMSIG_MOVABLE_Z_CHANGED, COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT, COMSIG_MOB_STATCHANGE, COMSIG_QDELETING)) + clear_able_to_run() 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 + GLOB.ai_controllers_by_zlevel[pawn_turf.z] -= src if(ai_status) - SSai_controllers.ai_controllers_by_status[ai_status] -= src + GLOB.ai_controllers_by_status[ai_status] -= src pawn.ai_controller = null pawn = null if(destroy) qdel(src) -///Returns TRUE if the ai controller can actually run at the moment. -/datum/ai_controller/proc/able_to_run() +/datum/ai_controller/proc/setup_able_to_run() + // paused_until is handled by PauseAi() manually + RegisterSignals(pawn, list(SIGNAL_ADDTRAIT(TRAIT_AI_PAUSED), SIGNAL_REMOVETRAIT(TRAIT_AI_PAUSED)), PROC_REF(update_able_to_run)) + +/datum/ai_controller/proc/clear_able_to_run() + UnregisterSignal(pawn, list(SIGNAL_ADDTRAIT(TRAIT_AI_PAUSED), SIGNAL_REMOVETRAIT(TRAIT_AI_PAUSED))) + +/datum/ai_controller/proc/update_able_to_run() + SIGNAL_HANDLER + able_to_run = get_able_to_run() + +///Returns TRUE if the ai controller can actually run at the moment, FALSE otherwise +/datum/ai_controller/proc/get_able_to_run() if(HAS_TRAIT(pawn, TRAIT_AI_PAUSED)) return FALSE if(world.time < paused_until) @@ -291,7 +310,7 @@ multiple modular subtrees with behaviors ///Runs any actions that are currently running /datum/ai_controller/process(seconds_per_tick) - if(!able_to_run()) + if(!able_to_run) GLOB.move_manager.stop_looping(pawn) //stop moving return //this should remove them from processing in the future through event-based stuff. @@ -386,18 +405,30 @@ multiple modular subtrees with behaviors //remove old status, if we've got one if(ai_status) - SSai_controllers.ai_controllers_by_status[ai_status] -= src + GLOB.ai_controllers_by_status[ai_status] -= src + stop_previous_processing() ai_status = new_ai_status - SSai_controllers.ai_controllers_by_status[new_ai_status] += src + GLOB.ai_controllers_by_status[new_ai_status] += src switch(ai_status) if(AI_STATUS_ON) START_PROCESSING(SSai_behaviors, src) - if(AI_STATUS_OFF, AI_STATUS_IDLE) - STOP_PROCESSING(SSai_behaviors, src) + if(AI_STATUS_IDLE) + START_PROCESSING(SSidle_ai_behaviors, src) + CancelActions() + if(AI_STATUS_OFF) CancelActions() +/datum/ai_controller/proc/stop_previous_processing() + switch(ai_status) + if(AI_STATUS_ON) + STOP_PROCESSING(SSai_behaviors, src) + if(AI_STATUS_IDLE) + STOP_PROCESSING(SSidle_ai_behaviors, src) + /datum/ai_controller/proc/PauseAi(time) paused_until = world.time + time + update_able_to_run() + addtimer(CALLBACK(src, PROC_REF(update_able_to_run)), time) /datum/ai_controller/proc/modify_cooldown(datum/ai_behavior/behavior, new_cooldown) behavior_cooldowns[behavior] = new_cooldown diff --git a/code/datums/ai/bane/bane_controller.dm b/code/datums/ai/bane/bane_controller.dm index 8d6820a800bdc..64e1dcf31af3a 100644 --- a/code/datums/ai/bane/bane_controller.dm +++ b/code/datums/ai/bane/bane_controller.dm @@ -12,7 +12,19 @@ And the only victory you achieved was a lie. Now you understand Gotham is beyond return AI_CONTROLLER_INCOMPATIBLE return ..() //Run parent at end -/datum/ai_controller/bane/able_to_run() +/datum/ai_controller/bane/on_stat_changed(mob/living/source, new_stat) + . = ..() + update_able_to_run() + +/datum/ai_controller/bane/setup_able_to_run() + . = ..() + RegisterSignal(pawn, COMSIG_MOB_INCAPACITATE_CHANGED, PROC_REF(update_able_to_run)) + +/datum/ai_controller/bane/clear_able_to_run() + UnregisterSignal(pawn, list(COMSIG_MOB_INCAPACITATE_CHANGED, COMSIG_MOB_STATCHANGE)) + return ..() + +/datum/ai_controller/bane/get_able_to_run() var/mob/living/living_pawn = pawn if(IS_DEAD_OR_INCAP(living_pawn)) return FALSE diff --git a/code/datums/ai/basic_mobs/base_basic_controller.dm b/code/datums/ai/basic_mobs/base_basic_controller.dm index cd025b28bcb2b..a14630fa0e83a 100644 --- a/code/datums/ai/basic_mobs/base_basic_controller.dm +++ b/code/datums/ai/basic_mobs/base_basic_controller.dm @@ -12,17 +12,29 @@ return ..() //Run parent at end +/datum/ai_controller/basic_controller/on_stat_changed(mob/living/source, new_stat) + . = ..() + update_able_to_run() -/datum/ai_controller/basic_controller/able_to_run() +/datum/ai_controller/basic_controller/setup_able_to_run() . = ..() - if(!isliving(pawn)) - return - var/mob/living/living_pawn = pawn - var/incap_flags = NONE - if (ai_traits & CAN_ACT_IN_STASIS) - incap_flags |= IGNORE_STASIS - if(!(ai_traits & CAN_ACT_WHILE_DEAD) && (living_pawn.incapacitated(incap_flags) || living_pawn.stat)) + RegisterSignal(pawn, COMSIG_MOB_INCAPACITATE_CHANGED, PROC_REF(update_able_to_run)) + +/datum/ai_controller/basic_controller/clear_able_to_run() + UnregisterSignal(pawn, list(COMSIG_MOB_INCAPACITATE_CHANGED, COMSIG_MOB_STATCHANGE)) + return ..() + +/datum/ai_controller/basic_controller/get_able_to_run() + . = ..() + if(!.) return FALSE + var/mob/living/living_pawn = pawn + if(!(ai_traits & CAN_ACT_WHILE_DEAD)) + // Unroll for flags here + if (ai_traits & CAN_ACT_IN_STASIS && (living_pawn.stat || INCAPACITATED_IGNORING(living_pawn, INCAPABLE_STASIS))) + return FALSE + else if(IS_DEAD_OR_INCAP(living_pawn)) + return FALSE if(ai_traits & PAUSE_DURING_DO_AFTER && LAZYLEN(living_pawn.do_afters)) return FALSE diff --git a/code/datums/ai/basic_mobs/basic_subtrees/call_reinforcements.dm b/code/datums/ai/basic_mobs/basic_subtrees/call_reinforcements.dm index 44d7cb4fe480b..f78697b2b8132 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/call_reinforcements.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/call_reinforcements.dm @@ -44,6 +44,6 @@ other_mob.ai_controller.set_blackboard_key(BB_BASIC_MOB_REINFORCEMENT_TARGET, pawn_mob) controller.set_blackboard_key(BB_BASIC_MOB_REINFORCEMENTS_COOLDOWN, world.time + REINFORCEMENTS_COOLDOWN) - return AI_BEHAVIOR_DELAY + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED #undef REINFORCEMENTS_COOLDOWN diff --git a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm index d9e0d1e7fb9ff..83e514f327020 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm @@ -21,4 +21,5 @@ controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list/nearest, BB_BASIC_MOB_RETALIATE_LIST, target_key, targeting_key, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/from_flee_key + target_key = BB_BASIC_MOB_FLEE_TARGET targeting_key = BB_FLEE_TARGETING_STRATEGY diff --git a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm index 42608730f9891..759355283acd4 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm @@ -1,8 +1,10 @@ /datum/ai_planning_subtree/simple_find_target + /// Variable to store target in + var/target_key = BB_BASIC_MOB_CURRENT_TARGET /datum/ai_planning_subtree/simple_find_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) . = ..() - controller.queue_behavior(/datum/ai_behavior/find_potential_targets, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + controller.queue_behavior(/datum/ai_behavior/find_potential_targets, target_key, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) // Prevents finding a target if a human is nearby /datum/ai_planning_subtree/simple_find_target/not_while_observed @@ -12,3 +14,6 @@ if(watcher.stat != DEAD) return return ..() + +/datum/ai_planning_subtree/simple_find_target/to_flee + target_key = BB_BASIC_MOB_FLEE_TARGET diff --git a/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm b/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm index 2394f2a38623b..35673f3efca21 100644 --- a/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm +++ b/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm @@ -85,6 +85,21 @@ // trust fall exercise return TRUE +/datum/targeting_strategy/basic/require_traits + +/datum/targeting_strategy/basic/require_traits/can_attack(mob/living/living_mob, atom/the_target, vision_range) + . = ..() + if (!.) + return FALSE + var/list/required_traits = living_mob.ai_controller.blackboard[BB_TARGET_ONLY_WITH_TRAITS] + if (!length(required_traits)) + return TRUE + + for (var/trait as anything in required_traits) + if (HAS_TRAIT(the_target, trait)) + return TRUE + return FALSE + /// Subtype which searches for mobs of a size relative to ours /datum/targeting_strategy/basic/of_size /// If true, we will return mobs which are smaller than us. If false, larger. diff --git a/code/datums/ai/monkey/monkey_behaviors.dm b/code/datums/ai/monkey/monkey_behaviors.dm index a5febe03143f1..e6720d7d96a78 100644 --- a/code/datums/ai/monkey/monkey_behaviors.dm +++ b/code/datums/ai/monkey/monkey_behaviors.dm @@ -197,7 +197,7 @@ var/can_shoot = gun?.can_shoot() || FALSE if(gun && controller.blackboard[BB_MONKEY_GUN_WORKED] && prob(95)) // We attempt to attack even if we can't shoot so we get the effects of pulling the trigger - gun.melee_attack_chain(living_pawn, real_target) + gun.interact_with_atom(real_target, living_pawn) controller.set_blackboard_key(BB_MONKEY_GUN_WORKED, can_shoot ? TRUE : prob(80)) // Only 20% likely to notice it didn't work if(can_shoot) controller.set_blackboard_key(BB_MONKEY_GUN_NEURONS_ACTIVATED, TRUE) diff --git a/code/datums/ai/monkey/monkey_controller.dm b/code/datums/ai/monkey/monkey_controller.dm index 451d692b65d34..0c87d127b15c8 100644 --- a/code/datums/ai/monkey/monkey_controller.dm +++ b/code/datums/ai/monkey/monkey_controller.dm @@ -104,10 +104,22 @@ have ways of interacting with a specific mob and control it. . = ..() set_trip_mode(mode = TRUE) -/datum/ai_controller/monkey/able_to_run() +/datum/ai_controller/monkey/on_stat_changed(mob/living/source, new_stat) + . = ..() + update_able_to_run() + +/datum/ai_controller/monkey/setup_able_to_run() + . = ..() + RegisterSignal(pawn, COMSIG_MOB_INCAPACITATE_CHANGED, PROC_REF(update_able_to_run)) + +/datum/ai_controller/monkey/clear_able_to_run() + UnregisterSignal(pawn, list(COMSIG_MOB_INCAPACITATE_CHANGED, COMSIG_MOB_STATCHANGE)) + return ..() + +/datum/ai_controller/monkey/get_able_to_run() var/mob/living/living_pawn = pawn - if(living_pawn.incapacitated(IGNORE_RESTRAINTS | IGNORE_GRAB | IGNORE_STASIS) || living_pawn.stat > CONSCIOUS) + if(INCAPACITATED_IGNORING(living_pawn, INCAPABLE_RESTRAINTS|INCAPABLE_STASIS|INCAPABLE_GRAB) || living_pawn.stat > CONSCIOUS) return FALSE return ..() diff --git a/code/datums/ai/movement/_ai_movement.dm b/code/datums/ai/movement/_ai_movement.dm index d48166eeb23ac..96b1b0ee63849 100644 --- a/code/datums/ai/movement/_ai_movement.dm +++ b/code/datums/ai/movement/_ai_movement.dm @@ -59,7 +59,7 @@ var/datum/ai_controller/controller = source.extra_info // Check if this controller can actually run, so we don't chase people with corpses - if(!controller.able_to_run()) + if(!controller.able_to_run) controller.CancelActions() qdel(source) //stop moving return MOVELOOP_SKIP_STEP diff --git a/code/datums/ai/oldhostile/hostile_tameable.dm b/code/datums/ai/oldhostile/hostile_tameable.dm index 1c30cb95487c1..907ab955a8d53 100644 --- a/code/datums/ai/oldhostile/hostile_tameable.dm +++ b/code/datums/ai/oldhostile/hostile_tameable.dm @@ -50,7 +50,19 @@ if(buckler != blackboard[BB_HOSTILE_FRIEND]) return COMPONENT_BLOCK_BUCKLE -/datum/ai_controller/hostile_friend/able_to_run() +/datum/ai_controller/hostile_friend/on_stat_changed(mob/living/source, new_stat) + . = ..() + update_able_to_run() + +/datum/ai_controller/hostile_friend/setup_able_to_run() + . = ..() + RegisterSignal(pawn, COMSIG_MOB_INCAPACITATE_CHANGED, PROC_REF(update_able_to_run)) + +/datum/ai_controller/hostile_friend/clear_able_to_run() + UnregisterSignal(pawn, list(COMSIG_MOB_INCAPACITATE_CHANGED, COMSIG_MOB_STATCHANGE)) + return ..() + +/datum/ai_controller/hostile_friend/get_able_to_run() var/mob/living/living_pawn = pawn if(IS_DEAD_OR_INCAP(living_pawn)) @@ -77,14 +89,14 @@ if(pawn.Adjacent(pawn, new_friend)) new_friend.visible_message("[pawn] looks at [new_friend] in a friendly manner!", span_notice("[pawn] looks at you in a friendly manner!")) set_blackboard_key(BB_HOSTILE_FRIEND, new_friend) - RegisterSignal(new_friend, COMSIG_MOB_POINTED, PROC_REF(check_point)) + RegisterSignal(new_friend, COMSIG_MOVABLE_POINTED, PROC_REF(check_point)) RegisterSignal(new_friend, COMSIG_MOB_SAY, PROC_REF(check_verbal_command)) /// Someone is being mean to us, take them off our friends (add actual enemies behavior later) /datum/ai_controller/hostile_friend/proc/unfriend() var/mob/living/old_friend = blackboard[BB_HOSTILE_FRIEND] if(old_friend) - UnregisterSignal(old_friend, list(COMSIG_MOB_POINTED, COMSIG_MOB_SAY)) + UnregisterSignal(old_friend, list(COMSIG_MOVABLE_POINTED, COMSIG_MOB_SAY)) clear_blackboard_key(BB_HOSTILE_FRIEND) /// Someone is looking at us, if we're currently carrying something then show what it is, and include a message if they're our friend @@ -129,7 +141,7 @@ /datum/ai_controller/hostile_friend/proc/check_menu(mob/user) if(!istype(user)) CRASH("A non-mob is trying to issue an order to [pawn].") - if(user.incapacitated() || !can_see(user, pawn)) + if(user.incapacitated || !can_see(user, pawn)) return FALSE return TRUE @@ -190,7 +202,7 @@ set_blackboard_key(BB_HOSTILE_ORDER_MODE, HOSTILE_COMMAND_ATTACK) /// Someone we like is pointing at something, see if it's something we might want to interact with (like if they might want us to fetch something for them) -/datum/ai_controller/hostile_friend/proc/check_point(mob/pointing_friend, atom/movable/pointed_movable) +/datum/ai_controller/hostile_friend/proc/check_point(mob/pointing_friend, atom/movable/pointed_movable, obj/effect/temp_visual/point/point) SIGNAL_HANDLER var/mob/living/simple_animal/hostile/living_pawn = pawn diff --git a/code/datums/beam.dm b/code/datums/beam.dm index fe34b0c7eddee..708a416301159 100644 --- a/code/datums/beam.dm +++ b/code/datums/beam.dm @@ -122,10 +122,10 @@ /datum/beam/proc/Draw() if(SEND_SIGNAL(src, COMSIG_BEAM_BEFORE_DRAW) & BEAM_CANCEL_DRAW) return - var/origin_px = isnull(override_origin_pixel_x) ? origin.pixel_x : override_origin_pixel_x - var/origin_py = isnull(override_origin_pixel_y) ? origin.pixel_y : override_origin_pixel_y - var/target_px = isnull(override_target_pixel_x) ? target.pixel_x : override_target_pixel_x - var/target_py = isnull(override_target_pixel_y) ? target.pixel_y : override_target_pixel_y + var/origin_px = (isnull(override_origin_pixel_x) ? origin.pixel_x : override_origin_pixel_x) + origin.pixel_w + var/origin_py = (isnull(override_origin_pixel_y) ? origin.pixel_y : override_origin_pixel_y) + origin.pixel_z + var/target_px = (isnull(override_target_pixel_x) ? target.pixel_x : override_target_pixel_x) + target.pixel_w + var/target_py = (isnull(override_target_pixel_y) ? target.pixel_y : override_target_pixel_y) + target.pixel_z var/Angle = get_angle_raw(origin.x, origin.y, origin_px, origin_py, target.x , target.y, target_px, target_py) ///var/Angle = round(get_angle(origin,target)) var/matrix/rot_matrix = matrix() diff --git a/code/datums/bodypart_overlays/simple_bodypart_overlay.dm b/code/datums/bodypart_overlays/simple_bodypart_overlay.dm index 6c9eb4240ecd0..20467eede042b 100644 --- a/code/datums/bodypart_overlays/simple_bodypart_overlay.dm +++ b/code/datums/bodypart_overlays/simple_bodypart_overlay.dm @@ -25,11 +25,6 @@ icon_state = "sixpack" layers = EXTERNAL_ADJACENT -///A creampie drawn on the head -/datum/bodypart_overlay/simple/creampie - icon_state = "creampie_human" - layers = EXTERNAL_FRONT - ///bags drawn beneath the eyes /datum/bodypart_overlay/simple/bags icon_state = "bags" diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm index d5f0a0e91240a..cd45ae1abf468 100644 --- a/code/datums/brain_damage/severe.dm +++ b/code/datums/brain_damage/severe.dm @@ -407,7 +407,7 @@ var/obj/item/bodypart/bodypart = owner.get_bodypart(owner.get_random_valid_zone(even_weights = TRUE)) if(!(bodypart && IS_ORGANIC_LIMB(bodypart)) && bodypart.bodypart_flags & BODYPART_PSEUDOPART) return - if(owner.incapacitated()) + if(owner.incapacitated) return bodypart.receive_damage(scratch_damage) if(SPT_PROB(33, seconds_per_tick)) diff --git a/code/datums/components/appearance_on_aggro.dm b/code/datums/components/appearance_on_aggro.dm index 8c0df88e6fdbc..6d4cab3d91410 100644 --- a/code/datums/components/appearance_on_aggro.dm +++ b/code/datums/components/appearance_on_aggro.dm @@ -13,8 +13,6 @@ var/alpha_on_aggro /// visibility of our icon when deaggroed var/alpha_on_deaggro - /// do we currently have a target - var/atom/current_target /datum/component/appearance_on_aggro/Initialize(aggro_state, overlay_icon, overlay_state, alpha_on_aggro, alpha_on_deaggro) if (!isliving(parent)) @@ -27,7 +25,7 @@ /datum/component/appearance_on_aggro/RegisterWithParent() RegisterSignal(parent, COMSIG_AI_BLACKBOARD_KEY_SET(target_key), PROC_REF(on_set_target)) - RegisterSignal(parent, COMSIG_AI_BLACKBOARD_KEY_CLEARED(target_key), PROC_REF(on_clear_target)) + RegisterSignals(parent, list(COMSIG_AI_BLACKBOARD_KEY_CLEARED(target_key), COMSIG_LIVING_DEATH), PROC_REF(on_clear_or_death)) if (!isnull(aggro_state)) RegisterSignal(parent, COMSIG_ATOM_UPDATE_ICON_STATE, PROC_REF(on_icon_state_updated)) if (!isnull(aggro_overlay)) @@ -35,32 +33,29 @@ /datum/component/appearance_on_aggro/UnregisterFromParent() . = ..() - UnregisterSignal(parent, list(COMSIG_AI_BLACKBOARD_KEY_SET(target_key), COMSIG_AI_BLACKBOARD_KEY_CLEARED(target_key))) + UnregisterSignal(parent, list(COMSIG_AI_BLACKBOARD_KEY_SET(target_key), COMSIG_AI_BLACKBOARD_KEY_CLEARED(target_key), COMSIG_LIVING_DEATH)) /datum/component/appearance_on_aggro/proc/on_set_target(mob/living/source) SIGNAL_HANDLER - var/atom/target = source.ai_controller.blackboard[target_key] + var/atom/target = source.ai_controller?.blackboard[target_key] if (QDELETED(target)) return - current_target = target if (!isnull(aggro_overlay) || !isnull(aggro_state)) source.update_appearance(UPDATE_ICON) if (!isnull(alpha_on_aggro)) animate(source, alpha = alpha_on_aggro, time = 2 SECONDS) /datum/component/appearance_on_aggro/Destroy() - if (!isnull(current_target)) - revert_appearance(parent) + revert_appearance(parent) return ..() -/datum/component/appearance_on_aggro/proc/on_clear_target(atom/source) +/datum/component/appearance_on_aggro/proc/on_clear_or_death(atom/source) SIGNAL_HANDLER revert_appearance(parent) /datum/component/appearance_on_aggro/proc/revert_appearance(mob/living/source) - current_target = null if (!isnull(aggro_overlay) || !isnull(aggro_state)) source.update_appearance(UPDATE_ICON) if (!isnull(alpha_on_deaggro)) @@ -70,11 +65,11 @@ SIGNAL_HANDLER if (source.stat == DEAD) return - source.icon_state = isnull(current_target) ? initial(source.icon_state) : aggro_state + source.icon_state = source.ai_controller?.blackboard_key_exists(target_key) ? aggro_state : initial(source.icon_state) -/datum/component/appearance_on_aggro/proc/on_overlays_updated(atom/source, list/overlays) +/datum/component/appearance_on_aggro/proc/on_overlays_updated(mob/living/basic/source, list/overlays) SIGNAL_HANDLER - if (isnull(current_target)) + if(!(source.ai_controller?.blackboard_key_exists(target_key))) return overlays += aggro_overlay diff --git a/code/datums/components/chasm.dm b/code/datums/components/chasm.dm index b4406857ac1e3..43d7201b1e469 100644 --- a/code/datums/components/chasm.dm +++ b/code/datums/components/chasm.dm @@ -212,6 +212,10 @@ REMOVE_TRAIT(fallen_mob, TRAIT_NO_TRANSFORM, REF(src)) if (fallen_mob.stat != DEAD) fallen_mob.investigate_log("has died from falling into a chasm.", INVESTIGATE_DEATHS) + if(issilicon(fallen_mob)) + //Silicons are held together by hopes and dreams, unfortunately, I'm having a nightmare + var/mob/living/silicon/robot/fallen_borg = fallen_mob + fallen_borg.mmi = null fallen_mob.death(TRUE) fallen_mob.apply_damage(300) diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm index 8f436faa9c6c4..d383c6f639e7a 100644 --- a/code/datums/components/crafting/crafting.dm +++ b/code/datums/components/crafting/crafting.dm @@ -611,6 +611,9 @@ data["name"] = "[data["name"]] [recipe.result_amount]x" data["desc"] = recipe.desc || initial(atom.desc) + if(ispath(recipe.result, /obj/item/food)) + var/obj/item/food/food = recipe.result + data["has_food_effect"] = !!food.crafted_food_buff // Crafting if(recipe.non_craftable) diff --git a/code/datums/components/crafting/equipment.dm b/code/datums/components/crafting/equipment.dm index 75b257156084e..dfd79e696224c 100644 --- a/code/datums/components/crafting/equipment.dm +++ b/code/datums/components/crafting/equipment.dm @@ -23,7 +23,7 @@ time = 4 SECONDS category = CAT_EQUIPMENT -/datum/crafting_recipe/improvisedshield +/datum/crafting_recipe/moonflowershield name = "Moonflower Shield" result = /obj/item/shield/buckler/moonflower reqs = list( diff --git a/code/datums/components/crafting/ranged_weapon.dm b/code/datums/components/crafting/ranged_weapon.dm index 0e3c7b119169b..174c0226a423e 100644 --- a/code/datums/components/crafting/ranged_weapon.dm +++ b/code/datums/components/crafting/ranged_weapon.dm @@ -77,7 +77,7 @@ reqs = list( /obj/item/assembly/signaler/anomaly/flux = 2, /obj/item/assembly/signaler/anomaly/grav = 1, - /obj/item/assembly/signaler/anomaly/vortex = MAX_CORES_VORTEX, + /obj/item/assembly/signaler/anomaly/vortex = (MAX_CORES_VORTEX - 1), /obj/item/assembly/signaler/anomaly/bluespace = 1, /obj/item/weaponcrafting/gunkit/beam_rifle = 1, ) diff --git a/code/datums/components/crafting/tailoring.dm b/code/datums/components/crafting/tailoring.dm index 3c498f74416bd..0bd3194813398 100644 --- a/code/datums/components/crafting/tailoring.dm +++ b/code/datums/components/crafting/tailoring.dm @@ -603,3 +603,43 @@ . = ..() if(HAS_TRAIT(user, TRAIT_BALLOON_SUTRA)) return TRUE + +/datum/crafting_recipe/press_armor + name = "press armor vest" + result = /obj/item/clothing/suit/armor/vest/press + time = 2 SECONDS + tool_paths = list(/obj/item/clothing/accessory/press_badge) + reqs = list( + /obj/item/clothing/suit/armor/vest = 1, + ) + category = CAT_CLOTHING + +/datum/crafting_recipe/press_helmet + name = "press helmet vest" + result = /obj/item/clothing/head/helmet/press + time = 2 SECONDS + tool_paths = list(/obj/item/clothing/accessory/press_badge) + reqs = list( + /obj/item/clothing/head/helmet/sec = 1, + ) + category = CAT_CLOTHING + +/datum/crafting_recipe/press_vest + name = "press vest" + result = /obj/item/clothing/suit/hazardvest/press + time = 2 SECONDS + tool_paths = list(/obj/item/clothing/accessory/press_badge) + reqs = list( + /obj/item/clothing/suit/hazardvest = 1, + ) + category = CAT_CLOTHING + +/datum/crafting_recipe/press_fedora + name = "press fedora" + result = /obj/item/clothing/head/fedora/beige/press + time = 2 SECONDS + tool_paths = list(/obj/item/clothing/accessory/press_badge) + reqs = list( + /obj/item/clothing/head/fedora/beige = 1, + ) + category = CAT_CLOTHING diff --git a/code/datums/components/cult_ritual_item.dm b/code/datums/components/cult_ritual_item.dm index dedd30bda0ef5..71e07e6380e11 100644 --- a/code/datums/components/cult_ritual_item.dm +++ b/code/datums/components/cult_ritual_item.dm @@ -404,7 +404,7 @@ if(!rune.Adjacent(cultist)) return FALSE - if(cultist.incapacitated()) + if(cultist.incapacitated) return FALSE if(cultist.stat == DEAD) @@ -427,7 +427,7 @@ if(QDELETED(tool) || !cultist.is_holding(tool)) return FALSE - if(cultist.incapacitated() || cultist.stat == DEAD) + if(cultist.incapacitated || cultist.stat == DEAD) to_chat(cultist, span_warning("You can't draw a rune right now.")) return FALSE diff --git a/code/datums/components/dejavu.dm b/code/datums/components/dejavu.dm index 8a1902526c42a..fefa9d7e6bee8 100644 --- a/code/datums/components/dejavu.dm +++ b/code/datums/components/dejavu.dm @@ -2,6 +2,7 @@ * A component to reset the parent to its previous state after some time passes */ /datum/component/dejavu + dupe_mode = COMPONENT_DUPE_ALLOWED ///message sent when dejavu rewinds var/rewind_message = "You remember a time not so long ago..." @@ -16,6 +17,8 @@ var/rewinds_remaining /// How long to wait between each rewind var/rewind_interval + /// Do we add a new component before teleporting the target to they teleport to the place where *we* teleported them from? + var/repeating_component /// The starting value of toxin loss at the beginning of the effect var/tox_loss = 0 @@ -34,13 +37,14 @@ /// A list of body parts saved at the beginning of the effect var/list/datum/saved_bodypart/saved_bodyparts -/datum/component/dejavu/Initialize(rewinds = 1, interval = 10 SECONDS) +/datum/component/dejavu/Initialize(rewinds = 1, interval = 10 SECONDS, add_component = FALSE) if(!isatom(parent)) return COMPONENT_INCOMPATIBLE starting_turf = get_turf(parent) rewinds_remaining = rewinds rewind_interval = interval + repeating_component = add_component if(isliving(parent)) var/mob/living/L = parent @@ -92,6 +96,9 @@ qdel(src) /datum/component/dejavu/proc/rewind_living() + if (rewinds_remaining == 1 && repeating_component && !iscarbon(parent) && !isanimal_or_basicmob(parent)) + parent.AddComponent(type, 1, rewind_interval, TRUE) + var/mob/living/master = parent master.setToxLoss(tox_loss) master.setOxyLoss(oxy_loss) @@ -100,18 +107,27 @@ rewind() /datum/component/dejavu/proc/rewind_carbon() + if (rewinds_remaining == 1 && repeating_component) + parent.AddComponent(type, 1, rewind_interval, TRUE) + if(saved_bodyparts) var/mob/living/carbon/master = parent master.apply_saved_bodyparts(saved_bodyparts) rewind_living() /datum/component/dejavu/proc/rewind_animal() + if (rewinds_remaining == 1 && repeating_component) + parent.AddComponent(type, 1, rewind_interval, TRUE) + var/mob/living/master = parent master.bruteloss = brute_loss master.updatehealth() rewind_living() /datum/component/dejavu/proc/rewind_obj() + if (rewinds_remaining == 1 && repeating_component) + parent.AddComponent(type, 1, rewind_interval, TRUE) + var/obj/master = parent master.update_integrity(integrity) rewind() @@ -124,3 +140,10 @@ /datum/component/dejavu/timeline/rewind() playsound(get_turf(parent), 'sound/items/modsuit/rewinder.ogg') . = ..() + +/datum/component/dejavu/wizard + rewind_message = "Your temporal ward activated, pulling you through spacetime!" + +/datum/component/dejavu/wizard/rewind() + playsound(get_turf(parent), 'sound/items/modsuit/rewinder.ogg') + . = ..() diff --git a/code/datums/components/effect_remover.dm b/code/datums/components/effect_remover.dm index a67962250dbe1..c8490d760f1f8 100644 --- a/code/datums/components/effect_remover.dm +++ b/code/datums/components/effect_remover.dm @@ -66,6 +66,10 @@ if(!isliving(user)) return NONE + if(HAS_TRAIT(target, TRAIT_ILLUSORY_EFFECT)) + to_chat(user, span_notice("You pass [parent] through the [target], but nothing seems to happen. Is it really even there?")) + return NONE + if(is_type_in_typecache(target, effects_we_clear)) // Make sure we get all subtypes and everything INVOKE_ASYNC(src, PROC_REF(do_remove_effect), target, user) return ITEM_INTERACT_SUCCESS diff --git a/code/datums/components/creamed.dm b/code/datums/components/face_decal.dm similarity index 50% rename from code/datums/components/creamed.dm rename to code/datums/components/face_decal.dm index d1ff1b792e17a..f045a4f18df6e 100644 --- a/code/datums/components/creamed.dm +++ b/code/datums/components/face_decal.dm @@ -1,37 +1,37 @@ -GLOBAL_LIST_INIT(creamable, typecacheof(list( - /mob/living/carbon/human, - /mob/living/basic/pet/dog/corgi, - /mob/living/silicon/ai))) /** - * Creamed component + * Face decal component * - * For when you have pie on your face + * For when you have some dirt on your face */ -/datum/component/creamed - dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS - /// Creampie overlay we use for non-carbon mobs + +/datum/component/face_decal + dupe_mode = COMPONENT_DUPE_HIGHLANDER + /// Overlay we use for non-carbon mobs var/mutable_appearance/normal_overlay - /// Creampie bodypart overlay we use for carbon mobs - var/datum/bodypart_overlay/simple/creampie/bodypart_overlay - /// Cached head for carbons, to ensure proper removal of the creampie overlay + /// Bodypart overlay we use for carbon mobs + var/datum/bodypart_overlay/simple/bodypart_overlay + /// Cached head for carbons, to ensure proper removal of our overlay var/obj/item/bodypart/my_head + /// Base icon state we use for the effect + var/icon_state + /// Layers for the bodypart_overlay to draw on + var/layers + /// Color that the overlay is modified by + var/color -/datum/component/creamed/Initialize() - if(!is_type_in_typecache(parent, GLOB.creamable)) - return COMPONENT_INCOMPATIBLE - - SEND_SIGNAL(parent, COMSIG_MOB_CREAMED, src) - - add_memory_in_range(parent, 7, /datum/memory/witnessed_creampie, protagonist = parent) +/datum/component/face_decal/Initialize(icon_state, layers, color) + src.icon_state = icon_state + src.layers = layers + src.color = color -/datum/component/creamed/Destroy(force) +/datum/component/face_decal/Destroy(force) . = ..() normal_overlay = null my_head = null QDEL_NULL(bodypart_overlay) -/datum/component/creamed/RegisterWithParent() +/datum/component/face_decal/RegisterWithParent() if(iscarbon(parent)) var/mob/living/carbon/human/carbon_parent = parent my_head = carbon_parent.get_bodypart(BODY_ZONE_HEAD) @@ -39,32 +39,38 @@ GLOBAL_LIST_INIT(creamable, typecacheof(list( qdel(src) return bodypart_overlay = new() + bodypart_overlay.layers = layers if(carbon_parent.bodyshape & BODYSHAPE_SNOUTED) //stupid, but external organ bodytypes are not stored on the limb - bodypart_overlay.icon_state = "creampie_lizard" + bodypart_overlay.icon_state = "[icon_state]_lizard" else if(my_head.bodyshape & BODYSHAPE_MONKEY) - bodypart_overlay.icon_state = "creampie_monkey" + bodypart_overlay.icon_state = "[icon_state]_monkey" else - bodypart_overlay.icon_state = "creampie_human" + bodypart_overlay.icon_state = "[icon_state]_human" + if (!isnull(color)) + bodypart_overlay.draw_color = color my_head.add_bodypart_overlay(bodypart_overlay) RegisterSignals(my_head, list(COMSIG_BODYPART_REMOVED, COMSIG_QDELETING), PROC_REF(lost_head)) - carbon_parent.add_mood_event("creampie", /datum/mood_event/creampie) carbon_parent.update_body_parts() - else if(iscorgi(parent)) - normal_overlay = mutable_appearance('icons/mob/effects/creampie.dmi', "creampie_corgi") - else if(isAI(parent)) - normal_overlay = mutable_appearance('icons/mob/effects/creampie.dmi', "creampie_ai") + else + normal_overlay = get_normal_overlay() RegisterSignals(parent, list( COMSIG_COMPONENT_CLEAN_ACT, COMSIG_COMPONENT_CLEAN_FACE_ACT), PROC_REF(clean_up) ) - if(normal_overlay) + + if (!isnull(normal_overlay)) + if (!isnull(color)) + normal_overlay.color = color var/atom/atom_parent = parent RegisterSignal(atom_parent, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(update_overlays)) atom_parent.update_appearance() -/datum/component/creamed/UnregisterFromParent() +/datum/component/face_decal/proc/get_normal_overlay() + return + +/datum/component/face_decal/UnregisterFromParent() UnregisterSignal(parent, list( COMSIG_COMPONENT_CLEAN_ACT, COMSIG_COMPONENT_CLEAN_FACE_ACT)) @@ -78,7 +84,6 @@ GLOBAL_LIST_INIT(creamable, typecacheof(list( my_head = null if(iscarbon(parent)) var/mob/living/carbon/carbon_parent = parent - carbon_parent.clear_mood_event("creampie") carbon_parent.update_body_parts() if(normal_overlay) var/atom/atom_parent = parent @@ -86,8 +91,8 @@ GLOBAL_LIST_INIT(creamable, typecacheof(list( atom_parent.update_appearance() normal_overlay = null -///Callback to remove pieface -/datum/component/creamed/proc/clean_up(datum/source, clean_types) +///Callback to remove our decal +/datum/component/face_decal/proc/clean_up(datum/source, clean_types) SIGNAL_HANDLER if(!(clean_types & CLEAN_TYPE_BLOOD)) @@ -97,14 +102,48 @@ GLOBAL_LIST_INIT(creamable, typecacheof(list( return COMPONENT_CLEANED /// Ensures normal_overlay overlay in case the mob is not a carbon -/datum/component/creamed/proc/update_overlays(atom/parent_atom, list/overlays) +/datum/component/face_decal/proc/update_overlays(atom/parent_atom, list/overlays) SIGNAL_HANDLER if(normal_overlay) overlays += normal_overlay -/// Removes creampie when the head gets dismembered -/datum/component/creamed/proc/lost_head(obj/item/bodypart/source, mob/living/carbon/owner, dismembered) +/// Removes the decal when the head gets dismembered +/datum/component/face_decal/proc/lost_head(obj/item/bodypart/source, mob/living/carbon/owner, dismembered) SIGNAL_HANDLER - qdel(src) + +/// Creampie subtype, handling signals and mood logic + +GLOBAL_LIST_INIT(creamable, typecacheof(list( + /mob/living/carbon/human, + /mob/living/basic/pet/dog/corgi, + /mob/living/silicon/ai, +))) + +/datum/component/face_decal/creampie/Initialize() + . = ..() + if(!is_type_in_typecache(parent, GLOB.creamable)) + return COMPONENT_INCOMPATIBLE + + SEND_SIGNAL(parent, COMSIG_MOB_CREAMED, src) + add_memory_in_range(parent, 7, /datum/memory/witnessed_creampie, protagonist = parent) + +/datum/component/face_decal/creampie/get_normal_overlay() + if(iscorgi(parent)) + return mutable_appearance('icons/mob/effects/creampie.dmi', "[icon_state]_corgi") + + if(isAI(parent)) + return mutable_appearance('icons/mob/effects/creampie.dmi', "[icon_state]_ai") + +/datum/component/face_decal/creampie/RegisterWithParent() + . = ..() + if(iscarbon(parent)) + var/mob/living/carbon/human/carbon_parent = parent + carbon_parent.add_mood_event("creampie", /datum/mood_event/creampie) + +/datum/component/face_decal/creampie/UnregisterFromParent() + . = ..() + if(iscarbon(parent)) + var/mob/living/carbon/carbon_parent = parent + carbon_parent.clear_mood_event("creampie") diff --git a/code/datums/components/food/edible.dm b/code/datums/components/food/edible.dm index 056f1e5791e6c..6f3991b1ed81b 100644 --- a/code/datums/components/food/edible.dm +++ b/code/datums/components/food/edible.dm @@ -40,6 +40,8 @@ Behavior that's still missing from this component that original food items had t var/volume = 50 ///The flavortext for taste (haha get it flavor text) var/list/tastes + ///Whether to tell the examiner that this is edible or not. + var/show_examine = TRUE /datum/component/edible/Initialize( list/initial_reagents, @@ -55,6 +57,7 @@ Behavior that's still missing from this component that original food items had t datum/callback/on_consume, datum/callback/check_liked, reagent_purity = 0.5, + show_examine = TRUE, ) if(!isatom(parent)) return COMPONENT_INCOMPATIBLE @@ -70,12 +73,13 @@ Behavior that's still missing from this component that original food items had t src.on_consume = on_consume src.tastes = string_assoc_list(tastes) src.check_liked = check_liked + src.show_examine = show_examine setup_initial_reagents(initial_reagents, reagent_purity) /datum/component/edible/RegisterWithParent() RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(examine)) - RegisterSignals(parent, COMSIG_ATOM_ATTACK_ANIMAL, PROC_REF(UseByAnimal)) + RegisterSignal(parent, COMSIG_ATOM_ATTACK_ANIMAL, PROC_REF(UseByAnimal)) RegisterSignal(parent, COMSIG_ATOM_CHECKPARTS, PROC_REF(OnCraft)) RegisterSignal(parent, COMSIG_ATOM_CREATEDBY_PROCESSING, PROC_REF(OnProcessed)) RegisterSignal(parent, COMSIG_FOOD_INGREDIENT_ADDED, PROC_REF(edible_ingredient_added)) @@ -212,7 +216,8 @@ Behavior that's still missing from this component that original food items had t SIGNAL_HANDLER var/atom/owner = parent - + if(!show_examine) + return if(foodtypes) var/list/types = bitfield_to_list(foodtypes, FOOD_FLAGS) examine_list += span_notice("It is [LOWER_TEXT(english_list(types))].") diff --git a/code/datums/components/fullauto.dm b/code/datums/components/fullauto.dm index 1faa04ceacc75..a3f2009b3b506 100644 --- a/code/datums/components/fullauto.dm +++ b/code/datums/components/fullauto.dm @@ -275,7 +275,7 @@ // Gun procs. /obj/item/gun/proc/on_autofire_start(mob/living/shooter) - if(semicd || shooter.incapacitated() || !can_trigger_gun(shooter)) + if(semicd || shooter.incapacitated || !can_trigger_gun(shooter)) return FALSE if(!can_shoot()) shoot_with_empty_chamber(shooter) @@ -295,7 +295,7 @@ /obj/item/gun/proc/do_autofire(datum/source, atom/target, mob/living/shooter, allow_akimbo, params) SIGNAL_HANDLER - if(semicd || shooter.incapacitated()) + if(semicd || shooter.incapacitated) return NONE if(!can_shoot()) shoot_with_empty_chamber(shooter) diff --git a/code/datums/components/pet_commands/pet_command.dm b/code/datums/components/pet_commands/pet_command.dm index a8db88d3a44ef..52b4cc8834920 100644 --- a/code/datums/components/pet_commands/pet_command.dm +++ b/code/datums/components/pet_commands/pet_command.dm @@ -186,14 +186,14 @@ /datum/pet_command/point_targeting/add_new_friend(mob/living/tamer) . = ..() - RegisterSignal(tamer, COMSIG_MOB_POINTED, PROC_REF(on_point)) + RegisterSignal(tamer, COMSIG_MOVABLE_POINTED, PROC_REF(on_point)) /datum/pet_command/point_targeting/remove_friend(mob/living/unfriended) . = ..() - UnregisterSignal(unfriended, COMSIG_MOB_POINTED) + UnregisterSignal(unfriended, COMSIG_MOVABLE_POINTED) /// Target the pointed atom for actions -/datum/pet_command/point_targeting/proc/on_point(mob/living/friend, atom/pointed_atom) +/datum/pet_command/point_targeting/proc/on_point(mob/living/friend, atom/pointed_atom, obj/effect/temp_visual/point/point) SIGNAL_HANDLER var/mob/living/parent = weak_parent.resolve() diff --git a/code/datums/components/riding/riding.dm b/code/datums/components/riding/riding.dm index 7ead11012b024..cfdaf605878bf 100644 --- a/code/datums/components/riding/riding.dm +++ b/code/datums/components/riding/riding.dm @@ -9,7 +9,6 @@ /datum/component/riding dupe_mode = COMPONENT_DUPE_UNIQUE - var/last_move_diagonal = FALSE ///tick delay between movements, lower = faster, higher = slower var/vehicle_move_delay = 2 diff --git a/code/datums/components/riding/riding_mob.dm b/code/datums/components/riding/riding_mob.dm index 50798fce50157..1e3c94d84c6a3 100644 --- a/code/datums/components/riding/riding_mob.dm +++ b/code/datums/components/riding/riding_mob.dm @@ -58,10 +58,10 @@ if(living_parent.body_position != STANDING_UP) // if we move while on the ground, the rider falls off . = FALSE // for piggybacks and (redundant?) borg riding, check if the rider is stunned/restrained - else if((ride_check_flags & RIDER_NEEDS_ARMS) && (HAS_TRAIT(rider, TRAIT_RESTRAINED) || rider.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB))) + else if((ride_check_flags & RIDER_NEEDS_ARMS) && (HAS_TRAIT(rider, TRAIT_RESTRAINED) || INCAPACITATED_IGNORING(rider, INCAPABLE_RESTRAINTS|INCAPABLE_GRAB))) . = FALSE // for fireman carries, check if the ridden is stunned/restrained - else if((ride_check_flags & CARRIER_NEEDS_ARM) && (HAS_TRAIT(living_parent, TRAIT_RESTRAINED) || living_parent.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB))) + else if((ride_check_flags & CARRIER_NEEDS_ARM) && (HAS_TRAIT(living_parent, TRAIT_RESTRAINED) || INCAPACITATED_IGNORING(living_parent, INCAPABLE_RESTRAINTS|INCAPABLE_GRAB))) . = FALSE else if((ride_check_flags & JUST_FRIEND_RIDERS) && !(living_parent.faction.Find(REF(rider)))) . = FALSE @@ -105,9 +105,7 @@ to_chat(user, span_warning("You need a [initial(key.name)] to ride [movable_parent]!")) return COMPONENT_DRIVER_BLOCK_MOVE var/mob/living/living_parent = parent - var/turf/next = get_step(living_parent, direction) step(living_parent, direction) - last_move_diagonal = ((direction & (direction - 1)) && (living_parent.loc == next)) var/modified_move_cooldown = vehicle_move_cooldown var/modified_move_delay = vehicle_move_delay if(ishuman(user) && HAS_TRAIT(user, TRAIT_ROUGHRIDER)) // YEEHAW! @@ -133,7 +131,7 @@ if(SANITY_LEVEL_INSANE) modified_move_cooldown *= 1.2 modified_move_delay *= 1.2 - COOLDOWN_START(src, vehicle_move_cooldown = modified_move_cooldown, (last_move_diagonal ? 2 : 1) * modified_move_delay) + COOLDOWN_START(src, vehicle_move_cooldown = modified_move_cooldown, modified_move_delay) return ..() /// Yeets the rider off, used for animals and cyborgs, redefined for humans who shove their piggyback rider off @@ -515,9 +513,9 @@ /datum/component/riding/creature/leaper/Initialize(mob/living/riding_mob, force = FALSE, ride_check_flags = NONE, potion_boost = FALSE) . = ..() - RegisterSignal(riding_mob, COMSIG_MOB_POINTED, PROC_REF(attack_pointed)) + RegisterSignal(riding_mob, COMSIG_MOVABLE_POINTED, PROC_REF(attack_pointed)) -/datum/component/riding/creature/leaper/proc/attack_pointed(mob/living/rider, atom/pointed) +/datum/component/riding/creature/leaper/proc/attack_pointed(mob/living/rider, atom/pointed, obj/effect/temp_visual/point/point) SIGNAL_HANDLER if(!isclosedturf(pointed)) return @@ -529,7 +527,7 @@ /datum/component/riding/leaper/handle_unbuckle(mob/living/rider) . = ..() - UnregisterSignal(rider, COMSIG_MOB_POINTED) + UnregisterSignal(rider, COMSIG_MOVABLE_POINTED) /datum/component/riding/creature/raptor require_minigame = TRUE diff --git a/code/datums/components/riding/riding_vehicle.dm b/code/datums/components/riding/riding_vehicle.dm index 5555369c67ae8..f7ee78673e057 100644 --- a/code/datums/components/riding/riding_vehicle.dm +++ b/code/datums/components/riding/riding_vehicle.dm @@ -97,8 +97,7 @@ return step(movable_parent, direction) - last_move_diagonal = ((direction & (direction - 1)) && (movable_parent.loc == next)) - COOLDOWN_START(src, vehicle_move_cooldown, (last_move_diagonal? 2 : 1) * vehicle_move_delay) + COOLDOWN_START(src, vehicle_move_cooldown, vehicle_move_delay) if(QDELETED(src)) return diff --git a/code/datums/components/soapbox.dm b/code/datums/components/soapbox.dm index 4622cc089288c..4d4577d5e12c8 100644 --- a/code/datums/components/soapbox.dm +++ b/code/datums/components/soapbox.dm @@ -33,7 +33,7 @@ SIGNAL_HANDLER for(var/atom/movable/loud as anything in soapboxers) UnregisterSignal(loud, COMSIG_MOB_SAY) - soapboxers = list() + soapboxers.Cut() ///Gives a mob a unique say span /datum/component/soapbox/proc/soapbox_speech(datum/source, list/speech_args) diff --git a/code/datums/components/space_kidnap.dm b/code/datums/components/space_kidnap.dm index 8a1de2123d9d3..7d59a6d7f9fde 100644 --- a/code/datums/components/space_kidnap.dm +++ b/code/datums/components/space_kidnap.dm @@ -23,7 +23,7 @@ target.balloon_alert(parent, "is dead!") return COMPONENT_CANCEL_ATTACK_CHAIN - if(!victim.incapacitated()) + if(!victim.incapacitated) return if(!isspaceturf(get_turf(target))) @@ -39,7 +39,7 @@ var/obj/particles = new /obj/effect/abstract/particle_holder (victim, /particles/void_kidnap) kidnapping = TRUE - if(do_after(parent, kidnap_time, victim, extra_checks = CALLBACK(victim, TYPE_PROC_REF(/mob, incapacitated)))) + if(do_after(parent, kidnap_time, victim, extra_checks = victim.incapacitated)) take_them(victim) qdel(particles) diff --git a/code/datums/components/speechmod.dm b/code/datums/components/speechmod.dm index 2506a0b914077..8ffa3e8624e49 100644 --- a/code/datums/components/speechmod.dm +++ b/code/datums/components/speechmod.dm @@ -34,6 +34,12 @@ var/atom/owner = parent + if (istype(parent, /datum/status_effect)) + var/datum/status_effect/effect = parent + targeted = effect.owner + RegisterSignal(targeted, COMSIG_MOB_SAY, PROC_REF(handle_speech)) + return + if (ismob(parent)) targeted = parent RegisterSignal(targeted, COMSIG_MOB_SAY, PROC_REF(handle_speech)) diff --git a/code/datums/components/sticker.dm b/code/datums/components/sticker.dm index 2c87d856da872..a11ab10e7c6f8 100644 --- a/code/datums/components/sticker.dm +++ b/code/datums/components/sticker.dm @@ -13,18 +13,21 @@ var/atom/movable/our_sticker /// Reference to the created overlay, used during component deletion. var/mutable_appearance/sticker_overlay - // Callback invoked when sticker is applied to the parent. + /// Callback invoked when sticker is applied to the parent. var/datum/callback/stick_callback - // Callback invoked when sticker is peeled (not removed) from the parent. + /// Callback invoked when sticker is peeled (not removed) from the parent. var/datum/callback/peel_callback + /// Text added to the atom's examine when stickered. + var/examine_text -/datum/component/sticker/Initialize(atom/stickering_atom, dir = NORTH, px = 0, py = 0, datum/callback/stick_callback, datum/callback/peel_callback) +/datum/component/sticker/Initialize(atom/stickering_atom, dir = NORTH, px = 0, py = 0, datum/callback/stick_callback, datum/callback/peel_callback, examine_text) if(!isatom(parent)) return COMPONENT_INCOMPATIBLE src.our_sticker = our_sticker src.stick_callback = stick_callback src.peel_callback = peel_callback + src.examine_text = examine_text stick(stickering_atom, px, py) register_turf_signals(dir) @@ -45,9 +48,10 @@ /datum/component/sticker/RegisterWithParent() RegisterSignal(parent, COMSIG_LIVING_IGNITED, PROC_REF(on_ignite)) RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(on_clean)) + RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) /datum/component/sticker/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_LIVING_IGNITED, COMSIG_COMPONENT_CLEAN_ACT)) + UnregisterSignal(parent, list(COMSIG_LIVING_IGNITED, COMSIG_COMPONENT_CLEAN_ACT, COMSIG_ATOM_EXAMINE)) /// Subscribes to `COMSIG_TURF_EXPOSE` if parent atom is a turf. If turf is closed - subscribes to signal /datum/component/sticker/proc/register_turf_signals(dir) @@ -116,3 +120,9 @@ if(exposed_temperature >= FIRE_MINIMUM_TEMPERATURE_TO_EXIST) qdel(our_sticker) // which qdels us + +/datum/component/sticker/proc/on_examine(atom/source, mob/user, list/examine_list) + SIGNAL_HANDLER + + if(!isnull(examine_text)) + examine_list += span_warning(examine_text) diff --git a/code/datums/components/style/style.dm b/code/datums/components/style/style.dm index 9bc420cc175c0..cc8b061fd353e 100644 --- a/code/datums/components/style/style.dm +++ b/code/datums/components/style/style.dm @@ -98,8 +98,7 @@ RegisterSignal(parent, COMSIG_USER_ITEM_INTERACTION, PROC_REF(hotswap)) RegisterSignal(parent, COMSIG_MOB_MINED, PROC_REF(on_mine)) RegisterSignal(parent, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(on_take_damage)) - RegisterSignal(parent, COMSIG_MOB_EMOTED("flip"), PROC_REF(on_flip)) - RegisterSignal(parent, COMSIG_MOB_EMOTED("spin"), PROC_REF(on_spin)) + RegisterSignal(parent, COMSIG_MOB_EMOTED("taunt"), PROC_REF(on_taunt)) RegisterSignal(parent, COMSIG_MOB_ITEM_ATTACK, PROC_REF(on_attack)) RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_punch)) RegisterSignal(SSdcs, COMSIG_GLOB_MOB_DEATH, PROC_REF(on_death)) @@ -114,7 +113,7 @@ UnregisterSignal(parent, COMSIG_USER_ITEM_INTERACTION) UnregisterSignal(parent, COMSIG_MOB_MINED) UnregisterSignal(parent, COMSIG_MOB_APPLY_DAMAGE) - UnregisterSignal(parent, list(COMSIG_MOB_EMOTED("flip"), COMSIG_MOB_EMOTED("spin"))) + UnregisterSignal(parent, COMSIG_MOB_EMOTED("taunt")) UnregisterSignal(parent, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_LIVING_UNARMED_ATTACK)) UnregisterSignal(SSdcs, COMSIG_GLOB_MOB_DEATH) UnregisterSignal(parent, COMSIG_LIVING_RESONATOR_BURST) @@ -407,19 +406,12 @@ // Emote-based multipliers -/datum/component/style/proc/on_flip() +/datum/component/style/proc/on_taunt() SIGNAL_HANDLER point_multiplier = round(min(point_multiplier + 0.5, 3), 0.1) update_screen() -/datum/component/style/proc/on_spin() - SIGNAL_HANDLER - - point_multiplier = round(min(point_multiplier + 0.3, 3), 0.1) - update_screen() - - // Negative effects /datum/component/style/proc/on_take_damage(...) SIGNAL_HANDLER diff --git a/code/datums/components/subtype_picker.dm b/code/datums/components/subtype_picker.dm index 78401c9e02293..2cc76e42ecf1f 100644 --- a/code/datums/components/subtype_picker.dm +++ b/code/datums/components/subtype_picker.dm @@ -87,6 +87,6 @@ return FALSE if(QDELETED(target)) return FALSE - if(user.incapacitated() || !user.is_holding(target)) + if(user.incapacitated || !user.is_holding(target)) return FALSE return TRUE diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm index 8e902ced2fdbf..0c23733ea1658 100644 --- a/code/datums/components/tackle.dm +++ b/code/datums/components/tackle.dm @@ -74,10 +74,7 @@ if(modifiers[ALT_CLICK] || modifiers[SHIFT_CLICK] || modifiers[CTRL_CLICK] || modifiers[MIDDLE_CLICK]) return - if(!modifiers[RIGHT_CLICK]) - return - - if(!user.throw_mode || user.get_active_held_item() || user.pulling || user.buckled || user.incapacitated()) + if(!user.throw_mode || user.get_active_held_item() || user.pulling || user.buckled || user.incapacitated) return if(!clicked_atom || !(isturf(clicked_atom) || isturf(clicked_atom.loc))) diff --git a/code/datums/components/tactical.dm b/code/datums/components/tactical.dm index 59df008b2b100..7ced0d05f1a16 100644 --- a/code/datums/components/tactical.dm +++ b/code/datums/components/tactical.dm @@ -42,6 +42,9 @@ RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(unmodify)) RegisterSignal(parent, COMSIG_ATOM_UPDATED_ICON, PROC_REF(on_icon_update)) RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) + RegisterSignal(user, COMSIG_HUMAN_GET_VISIBLE_NAME, PROC_REF(on_name_inquiry)) + RegisterSignal(user, COMSIG_HUMAN_GET_FORCED_NAME, PROC_REF(on_name_inquiry)) + ADD_TRAIT(user, TRAIT_UNKNOWN, REF(src)) current_slot = slot @@ -62,6 +65,24 @@ image.plane = FLOAT_PLANE user.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/everyone, "sneaking_mission[REF(src)]", image) + +/datum/component/tactical/proc/on_name_inquiry(obj/item/source, list/identity) + SIGNAL_HANDLER + + var/tactical_disguise_power = INFINITY // it's a flawless plan: they'll never look behind this unassuming potted plant + if(identity[VISIBLE_NAME_FORCED]) + if(identity[VISIBLE_NAME_FORCED] >= tactical_disguise_power) // my disguise is too powerful for you, traveler! but seriously this is bad + stack_trace("A name forcing signal ([identity[VISIBLE_NAME_FACE]]) has a priority collision with [src].") + else + identity[VISIBLE_NAME_FORCED] = tactical_disguise_power + else + identity[VISIBLE_NAME_FORCED] = tactical_disguise_power + + var/obj/item/flawless_disguise = parent + identity[VISIBLE_NAME_FACE] = flawless_disguise.name + identity[VISIBLE_NAME_ID] = flawless_disguise.name // for Unknown (as 'potted plant') says + + /datum/component/tactical/proc/unmodify(obj/item/source, mob/user) SIGNAL_HANDLER if(!source) @@ -76,9 +97,17 @@ COMSIG_ITEM_DROPPED, COMSIG_MOVABLE_MOVED, COMSIG_ATOM_UPDATED_ICON, + COMSIG_HUMAN_GET_VISIBLE_NAME, + COMSIG_HUMAN_GET_FORCED_NAME, + )) + + UnregisterSignal(user, list( + COMSIG_HUMAN_GET_VISIBLE_NAME, + COMSIG_HUMAN_GET_FORCED_NAME, )) current_slot = null user.remove_alt_appearance("sneaking_mission[REF(src)]") + REMOVE_TRAIT(user, TRAIT_UNKNOWN, REF(src)) ///Checks if a mob is holding us, and if so we will modify our appearance to properly match w/ the mob. /datum/component/tactical/proc/tactical_update(obj/item/source) diff --git a/code/datums/elements/block_turf_fingerprints.dm b/code/datums/elements/block_turf_fingerprints.dm new file mode 100644 index 0000000000000..f3b7ab9cf19f1 --- /dev/null +++ b/code/datums/elements/block_turf_fingerprints.dm @@ -0,0 +1,56 @@ +/** + * ## block_turf_fingerprints + * + * Attach to a movable, prevents mobs from leaving fingerprints on the turf below it + */ +/datum/element/block_turf_fingerprints + element_flags = ELEMENT_DETACH_ON_HOST_DESTROY + +/datum/element/block_turf_fingerprints/Attach(datum/target) + . = ..() + if(!ismovable(target)) + return ELEMENT_INCOMPATIBLE + + var/atom/movable/target_movable = target + if(isturf(target_movable.loc)) + apply_to_turf(target_movable.loc) + + RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(move_turf)) + +/datum/element/block_turf_fingerprints/Detach(atom/movable/target) + . = ..() + if(isturf(target.loc)) + remove_from_turf(target.loc) + + UnregisterSignal(target, COMSIG_MOVABLE_MOVED) + +/datum/element/block_turf_fingerprints/proc/apply_to_turf(turf/the_turf) + // It's possible two things with this element could be on the same turf, so let's avoid double-applying + if(the_turf.interaction_flags_atom & INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND) + // But what if the turf has this flag by default? We still need to override register a signal. + // Otherwise we may run into a very niche bug: + // - A turf as this flag by default + // - A movable with this element is placed on the turf + // - It does not gain the flag nor register a signal + // - The turf changes, and the new turf does not gain the flag + if(initial(the_turf.interaction_flags_atom) & INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND) + RegisterSignal(the_turf, COMSIG_TURF_CHANGE, PROC_REF(replace_our_turf), override = TRUE) + return + + the_turf.interaction_flags_atom |= INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND + RegisterSignal(the_turf, COMSIG_TURF_CHANGE, PROC_REF(replace_our_turf)) + +/datum/element/block_turf_fingerprints/proc/remove_from_turf(turf/the_turf) + the_turf.interaction_flags_atom &= ~INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND + UnregisterSignal(the_turf, COMSIG_TURF_CHANGE) + +/datum/element/block_turf_fingerprints/proc/move_turf(atom/movable/source, atom/old_loc) + SIGNAL_HANDLER + if(isturf(old_loc)) + remove_from_turf(old_loc) + if(isturf(source.loc)) + apply_to_turf(source.loc) + +/datum/element/block_turf_fingerprints/proc/replace_our_turf(datum/source, path, new_baseturfs, flags, post_change_callbacks) + SIGNAL_HANDLER + post_change_callbacks += CALLBACK(src, PROC_REF(apply_to_turf)) diff --git a/code/datums/elements/movetype_handler.dm b/code/datums/elements/movetype_handler.dm index 6d730d345e284..e88aac6e26515 100644 --- a/code/datums/elements/movetype_handler.dm +++ b/code/datums/elements/movetype_handler.dm @@ -8,7 +8,6 @@ element_flags = ELEMENT_DETACH_ON_HOST_DESTROY var/list/attached_atoms = list() - var/list/paused_floating_anim_atoms = list() /datum/element/movetype_handler/Attach(datum/target) . = ..() @@ -22,7 +21,6 @@ RegisterSignals(movable_target, GLOB.movement_type_removetrait_signals, PROC_REF(on_movement_type_trait_loss)) RegisterSignal(movable_target, SIGNAL_ADDTRAIT(TRAIT_NO_FLOATING_ANIM), PROC_REF(on_no_floating_anim_trait_gain)) RegisterSignal(movable_target, SIGNAL_REMOVETRAIT(TRAIT_NO_FLOATING_ANIM), PROC_REF(on_no_floating_anim_trait_loss)) - RegisterSignal(movable_target, COMSIG_PAUSE_FLOATING_ANIM, PROC_REF(pause_floating_anim)) attached_atoms[movable_target] = TRUE if(movable_target.movement_type & (FLOATING|FLYING) && !HAS_TRAIT(movable_target, TRAIT_NO_FLOATING_ANIM)) @@ -32,14 +30,12 @@ var/list/signals_to_remove = list( SIGNAL_ADDTRAIT(TRAIT_NO_FLOATING_ANIM), SIGNAL_REMOVETRAIT(TRAIT_NO_FLOATING_ANIM), - COMSIG_PAUSE_FLOATING_ANIM ) signals_to_remove += GLOB.movement_type_addtrait_signals signals_to_remove += GLOB.movement_type_removetrait_signals UnregisterSignal(source, signals_to_remove) attached_atoms -= source - paused_floating_anim_atoms -= source STOP_FLOATING_ANIM(source) return ..() @@ -51,7 +47,7 @@ return var/old_state = source.movement_type source.movement_type |= flag - if(!(old_state & (FLOATING|FLYING)) && (source.movement_type & (FLOATING|FLYING)) && !paused_floating_anim_atoms[source] && !HAS_TRAIT(source, TRAIT_NO_FLOATING_ANIM)) + if(!(old_state & (FLOATING|FLYING)) && (source.movement_type & (FLOATING|FLYING)) && !HAS_TRAIT(source, TRAIT_NO_FLOATING_ANIM)) DO_FLOATING_ANIM(source) SEND_SIGNAL(source, COMSIG_MOVETYPE_FLAG_ENABLED, flag, old_state) @@ -78,24 +74,5 @@ /// Called when the TRAIT_NO_FLOATING_ANIM trait is removed from the mob. Restarts the bobbing animation. /datum/element/movetype_handler/proc/on_no_floating_anim_trait_loss(atom/movable/source, trait) SIGNAL_HANDLER - if(source.movement_type & (FLOATING|FLYING) && !paused_floating_anim_atoms[source]) + if(source.movement_type & (FLOATING|FLYING)) DO_FLOATING_ANIM(source) - -///Pauses the floating animation for the duration of the timer... plus [tickrate - (world.time + timer) % tickrate] to be precise. -/datum/element/movetype_handler/proc/pause_floating_anim(atom/movable/source, timer) - SIGNAL_HANDLER - if(paused_floating_anim_atoms[source] < world.time + timer) - STOP_FLOATING_ANIM(source) - if(!length(paused_floating_anim_atoms)) - START_PROCESSING(SSdcs, src) //1 second tickrate. - paused_floating_anim_atoms[source] = world.time + timer - -/datum/element/movetype_handler/process() - for(var/_paused in paused_floating_anim_atoms) - var/atom/movable/paused = _paused - if(paused_floating_anim_atoms[paused] < world.time) - if(paused.movement_type & (FLOATING|FLYING) && !HAS_TRAIT(paused, TRAIT_NO_FLOATING_ANIM)) - DO_FLOATING_ANIM(paused) - paused_floating_anim_atoms -= paused - if(!length(paused_floating_anim_atoms)) - STOP_PROCESSING(SSdcs, src) diff --git a/code/datums/elements/undertile.dm b/code/datums/elements/undertile.dm index ed901b196c1aa..229b292b31ae9 100644 --- a/code/datums/elements/undertile.dm +++ b/code/datums/elements/undertile.dm @@ -43,8 +43,13 @@ var/turf/T = get_turf(source) if(underfloor_accessibility < UNDERFLOOR_INTERACTABLE) - SET_PLANE_IMPLICIT(source, FLOOR_PLANE) // We do this so that turfs that allow you to see what's underneath them don't have to be on the game plane (which causes ambient occlusion weirdness) - source.layer = ABOVE_OPEN_TURF_LAYER + // We only want to change the layer/plane for things that aren't already on the floor plane, + // as overriding the settings for those would cause layering issues + if(PLANE_TO_TRUE(source.plane) != FLOOR_PLANE) + // We do this so that turfs that allow you to see what's underneath them don't have to be on the game plane (which causes ambient occlusion weirdness) + SET_PLANE_IMPLICIT(source, FLOOR_PLANE) + source.layer = ABOVE_OPEN_TURF_LAYER + ADD_TRAIT(source, TRAIT_UNDERFLOOR, REF(src)) if(tile_overlay) @@ -77,6 +82,8 @@ if(use_anchor) source.set_anchored(FALSE) + SEND_SIGNAL(source, COMSIG_UNDERTILE_UPDATED) + /datum/element/undertile/Detach(atom/movable/source, visibility_trait, invisibility_level = INVISIBILITY_MAXIMUM) . = ..() diff --git a/code/datums/elements/waddling.dm b/code/datums/elements/waddling.dm index e63d0329bb630..45c7fe5e93773 100644 --- a/code/datums/elements/waddling.dm +++ b/code/datums/elements/waddling.dm @@ -18,7 +18,7 @@ return if(isliving(moved)) var/mob/living/living_moved = moved - if (living_moved.incapacitated() || living_moved.body_position == LYING_DOWN) + if (living_moved.incapacitated || living_moved.body_position == LYING_DOWN) return waddling_animation(moved) diff --git a/code/datums/elements/wheel.dm b/code/datums/elements/wheel.dm index 2bb8977ca5cae..a50addb15a382 100644 --- a/code/datums/elements/wheel.dm +++ b/code/datums/elements/wheel.dm @@ -17,7 +17,7 @@ return if(isliving(moved)) var/mob/living/living_moved = moved - if (living_moved.incapacitated() || living_moved.body_position == LYING_DOWN) + if (living_moved.incapacitated || living_moved.body_position == LYING_DOWN) return var/rotation_degree = (360 / 3) if(direction & SOUTHWEST) diff --git a/code/datums/ert.dm b/code/datums/ert.dm index 7e358b38cecb4..2000d59199908 100644 --- a/code/datums/ert.dm +++ b/code/datums/ert.dm @@ -1,14 +1,23 @@ /datum/ert - var/mobtype = /mob/living/carbon/human + ///Antag datum team for this type of ERT. var/team = /datum/team/ert + ///Do we open the doors to the "high-impact" weapon/explosive cabinets? Used for combat-focused ERTs. var/opendoors = TRUE + ///Alternate antag datum given to the leader of the squad. var/leader_role = /datum/antagonist/ert/commander + ///Do we humanize all spawned players or keep them the species in their current character prefs? var/enforce_human = TRUE - var/roles = list(/datum/antagonist/ert/security, /datum/antagonist/ert/medic, /datum/antagonist/ert/engineer) //List of possible roles to be assigned to ERT members. + ///A list of roles distributed to the selected candidates that are not the leader. + var/roles = list(/datum/antagonist/ert/security, /datum/antagonist/ert/medic, /datum/antagonist/ert/engineer) + ///The custom name assigned to this team, for their antag datum/roundend reporting. var/rename_team + ///Defines the color/alert code of the response team. Unused if a polldesc is defined. var/code + ///The mission given to this ERT type in their flavor text. var/mission = "Assist the station." + ///The number of players for consideration. var/teamsize = 5 + ///The "would you like to play as XXX" message used when polling for players. var/polldesc /// If TRUE, gives the team members "[role] [random last name]" style names var/random_names = TRUE @@ -20,6 +29,8 @@ var/datum/map_template/ert_template /// If we should actually _use_ the ert_template custom shuttle var/use_custom_shuttle = TRUE + /// Used for spawning bodies for your ERT. Unless customized in the Summon-ERT verb settings, will be overridden and should not be defined at the datum level. + var/mob/living/carbon/human/mob_type /datum/ert/New() if (!polldesc) @@ -126,3 +137,14 @@ mission = "Having heard the station's request for aid, assist the crew in defending themselves." polldesc = "an independent station defense militia" random_names = TRUE + +/datum/ert/medical + opendoors = FALSE + teamsize = 4 + leader_role = /datum/antagonist/ert/medical_commander + enforce_human = FALSE //All the best doctors I know are moths and cats + roles = list(/datum/antagonist/ert/medical_technician) + rename_team = "EMT Squad" + code = "Violet" + mission = "Provide emergency medical services to the crew." + polldesc = "an emergency medical response team" diff --git a/code/datums/greyscale/config_types/greyscale_configs/greyscale_effects.dm b/code/datums/greyscale/config_types/greyscale_configs/greyscale_effects.dm index 34db9013a893d..91cfb618c210f 100644 --- a/code/datums/greyscale/config_types/greyscale_configs/greyscale_effects.dm +++ b/code/datums/greyscale/config_types/greyscale_configs/greyscale_effects.dm @@ -2,3 +2,8 @@ name = "Transmutation Rune" icon_file = 'icons/effects/96x96.dmi' json_config = 'code/datums/greyscale/json_configs/heretic_rune.json' + +/datum/greyscale_config/manipulator_hand + name = "Manipulator Hand" + icon_file = 'icons/obj/machines/big_manipulator_parts/big_manipulator_hand.dmi' + json_config = 'code/datums/greyscale/json_configs/manipulator_hand.json' diff --git a/code/datums/greyscale/config_types/greyscale_configs/greyscale_objects.dm b/code/datums/greyscale/config_types/greyscale_configs/greyscale_objects.dm index 7202c41ecc540..9556612be189c 100644 --- a/code/datums/greyscale/config_types/greyscale_configs/greyscale_objects.dm +++ b/code/datums/greyscale/config_types/greyscale_configs/greyscale_objects.dm @@ -3,6 +3,11 @@ icon_file = 'icons/obj/doors/airlocks/material/material.dmi' json_config = 'code/datums/greyscale/json_configs/material_airlock.json' +/datum/greyscale_config/big_manipulator + name = "Big Manipulator" + icon_file = 'icons/obj/machines/big_manipulator_parts/big_manipulator_core.dmi' + json_config = 'code/datums/greyscale/json_configs/big_manipulator.json' + // // BENCHES // diff --git a/code/datums/greyscale/json_configs/big_manipulator.json b/code/datums/greyscale/json_configs/big_manipulator.json new file mode 100644 index 0000000000000..c7f96bac2abaa --- /dev/null +++ b/code/datums/greyscale/json_configs/big_manipulator.json @@ -0,0 +1,15 @@ +{ + "core": [ + { + "type": "icon_state", + "icon_state": "core", + "blend_mode": "overlay" + }, + { + "type": "icon_state", + "icon_state": "core_colour", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/manipulator_hand.json b/code/datums/greyscale/json_configs/manipulator_hand.json new file mode 100644 index 0000000000000..be7c96df62b64 --- /dev/null +++ b/code/datums/greyscale/json_configs/manipulator_hand.json @@ -0,0 +1,15 @@ +{ + "hand": [ + { + "type": "icon_state", + "icon_state": "hand", + "blend_mode": "overlay" + }, + { + "type": "icon_state", + "icon_state": "hand_colour", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ] +} diff --git a/code/datums/holocall.dm b/code/datums/holocall.dm index c69a279938dd1..fead0417db9b2 100644 --- a/code/datums/holocall.dm +++ b/code/datums/holocall.dm @@ -179,7 +179,7 @@ if(QDELETED(src)) return FALSE - . = !QDELETED(user) && !user.incapacitated() && !QDELETED(calling_holopad) && calling_holopad.is_operational && user.loc == calling_holopad.loc + . = !QDELETED(user) && !user.incapacitated && !QDELETED(calling_holopad) && calling_holopad.is_operational && user.loc == calling_holopad.loc if(.) if(!connected_holopad) diff --git a/code/datums/id_trim/_id_trim.dm b/code/datums/id_trim/_id_trim.dm index 067e2e3826390..562232214b3d1 100644 --- a/code/datums/id_trim/_id_trim.dm +++ b/code/datums/id_trim/_id_trim.dm @@ -24,6 +24,11 @@ /// Accesses that this trim unlocks on a card that require wildcard slots to apply. If a card cannot accept all a trim's wildcard accesses, the card is incompatible with the trim. var/list/wildcard_access = list() + ///If true, IDs with this trim will grant wearers with bigger arrows when pointing + var/big_pointer = FALSE + ///If set, IDs with this trim will give wearers arrows of different colors when pointing + var/pointer_color + /// Returns the SecHUD job icon state for whatever this object's ID card is, if it has one. /obj/item/proc/get_sechud_job_icon_state() var/obj/item/card/id/id_card = GetID() diff --git a/code/datums/id_trim/admin.dm b/code/datums/id_trim/admin.dm index 9de155c9a0468..ee0cf1b977e0a 100644 --- a/code/datums/id_trim/admin.dm +++ b/code/datums/id_trim/admin.dm @@ -5,6 +5,8 @@ department_color = COLOR_CENTCOM_BLUE subdepartment_color = COLOR_SERVICE_LIME threat_modifier = -INFINITY + big_pointer = TRUE + pointer_color = COLOR_GREEN /datum/id_trim/admin/New() . = ..() diff --git a/code/datums/id_trim/centcom.dm b/code/datums/id_trim/centcom.dm index 5cc24f4bd6e19..498a4de254e3b 100644 --- a/code/datums/id_trim/centcom.dm +++ b/code/datums/id_trim/centcom.dm @@ -7,6 +7,8 @@ department_color = COLOR_CENTCOM_BLUE subdepartment_color = COLOR_CENTCOM_BLUE threat_modifier = -10 // Centcom are legally allowed to do whatever they want + big_pointer = TRUE + pointer_color = COLOR_CENTCOM_BLUE /// Trim for Centcom VIPs /datum/id_trim/centcom/vip @@ -20,6 +22,7 @@ trim_state = "trim_janitor" department_color = COLOR_CENTCOM_BLUE subdepartment_color = COLOR_SERVICE_LIME + big_pointer = FALSE /// Trim for Centcom Thunderdome Overseers. /datum/id_trim/centcom/thunderdome_overseer @@ -35,10 +38,12 @@ /datum/id_trim/centcom/intern access = list(ACCESS_CENT_GENERAL, ACCESS_CENT_LIVING, ACCESS_WEAPONS) assignment = "CentCom Intern" + big_pointer = FALSE /// Trim for Centcom Head Interns. Different assignment, common station access added on. /datum/id_trim/centcom/intern/head assignment = "CentCom Head Intern" + big_pointer = TRUE /datum/id_trim/centcom/intern/head/New() . = ..() @@ -49,11 +54,13 @@ /datum/id_trim/centcom/bounty_hunter access = list(ACCESS_CENT_GENERAL) assignment = "Bounty Hunter" + big_pointer = FALSE /// Trim for Centcom Bartenders. /datum/id_trim/centcom/bartender access = list(ACCESS_CENT_GENERAL, ACCESS_CENT_LIVING, ACCESS_CENT_BAR) assignment = JOB_CENTCOM_BARTENDER + big_pointer = FALSE /// Trim for Centcom Medical Officers. /datum/id_trim/centcom/medical_officer @@ -68,6 +75,7 @@ /// Trim for Centcom Specops Officers. All Centcom and Station Access. /datum/id_trim/centcom/specops_officer assignment = JOB_CENTCOM_SPECIAL_OFFICER + big_pointer = FALSE /datum/id_trim/centcom/specops_officer/New() . = ..() @@ -129,6 +137,7 @@ trim_state = "trim_securityofficer" subdepartment_color = COLOR_SECURITY_RED sechud_icon_state = SECHUD_SECURITY_RESPONSE_OFFICER + big_pointer = FALSE /datum/id_trim/centcom/ert/security/New() . = ..() @@ -141,6 +150,7 @@ trim_state = "trim_stationengineer" subdepartment_color = COLOR_ENGINEERING_ORANGE sechud_icon_state = SECHUD_ENGINEERING_RESPONSE_OFFICER + big_pointer = FALSE /datum/id_trim/centcom/ert/engineer/New() . = ..() @@ -153,6 +163,7 @@ trim_state = "trim_medicaldoctor" subdepartment_color = COLOR_MEDICAL_BLUE sechud_icon_state = SECHUD_MEDICAL_RESPONSE_OFFICER + big_pointer = FALSE /datum/id_trim/centcom/ert/medical/New() . = ..() @@ -165,6 +176,7 @@ trim_state = "trim_chaplain" subdepartment_color = COLOR_SERVICE_LIME sechud_icon_state = SECHUD_RELIGIOUS_RESPONSE_OFFICER + big_pointer = FALSE /datum/id_trim/centcom/ert/chaplain/New() . = ..() @@ -177,6 +189,7 @@ trim_state = "trim_ert_janitor" subdepartment_color = COLOR_SERVICE_LIME sechud_icon_state = SECHUD_JANITORIAL_RESPONSE_OFFICER + big_pointer = FALSE /datum/id_trim/centcom/ert/janitor/New() . = ..() @@ -189,6 +202,7 @@ trim_state = "trim_clown" subdepartment_color = COLOR_MAGENTA sechud_icon_state = SECHUD_ENTERTAINMENT_RESPONSE_OFFICER + big_pointer = FALSE /datum/id_trim/centcom/ert/clown/New() . = ..() @@ -197,6 +211,8 @@ /datum/id_trim/centcom/ert/militia assignment = "Frontier Militia" + big_pointer = FALSE /datum/id_trim/centcom/ert/militia/general assignment = "Frontier Militia General" + big_pointer = TRUE diff --git a/code/datums/id_trim/jobs.dm b/code/datums/id_trim/jobs.dm index 190c4a38a299c..548e5d7576b6e 100644 --- a/code/datums/id_trim/jobs.dm +++ b/code/datums/id_trim/jobs.dm @@ -238,6 +238,8 @@ ACCESS_CHANGE_IDS, ) job = /datum/job/captain + big_pointer = TRUE + pointer_color = COLOR_COMMAND_BLUE /// Captain gets all station accesses hardcoded in because it's the Captain. /datum/id_trim/job/captain/New() @@ -360,6 +362,8 @@ ACCESS_CHANGE_IDS, ) job = /datum/job/chief_engineer + big_pointer = TRUE + pointer_color = COLOR_ENGINEERING_ORANGE /datum/id_trim/job/chief_medical_officer assignment = JOB_CHIEF_MEDICAL_OFFICER @@ -399,6 +403,8 @@ ACCESS_CHANGE_IDS, ) job = /datum/job/chief_medical_officer + big_pointer = TRUE + pointer_color = COLOR_MEDICAL_BLUE /datum/id_trim/job/clown assignment = JOB_CLOWN @@ -612,6 +618,8 @@ ACCESS_CHANGE_IDS, ) job = /datum/job/head_of_personnel + big_pointer = TRUE + pointer_color = COLOR_SERVICE_LIME /datum/id_trim/job/head_of_security assignment = JOB_HEAD_OF_SECURITY @@ -661,6 +669,8 @@ ACCESS_CHANGE_IDS, ) job = /datum/job/head_of_security + big_pointer = TRUE + pointer_color = COLOR_SECURITY_RED /datum/id_trim/job/head_of_security/refresh_trim_access() . = ..() @@ -893,6 +903,8 @@ ACCESS_CHANGE_IDS, ) job = /datum/job/quartermaster + big_pointer = TRUE + pointer_color = COLOR_CARGO_BROWN /datum/id_trim/job/research_director assignment = JOB_RESEARCH_DIRECTOR @@ -941,6 +953,8 @@ ACCESS_CHANGE_IDS, ) job = /datum/job/research_director + big_pointer = TRUE + pointer_color = COLOR_SCIENCE_PINK /datum/id_trim/job/roboticist assignment = JOB_ROBOTICIST @@ -1206,6 +1220,7 @@ extra_access = list() template_access = list() job = /datum/job/veteran_advisor + big_pointer = TRUE /datum/id_trim/job/veteran_advisor/refresh_trim_access() . = ..() @@ -1275,3 +1290,5 @@ extra_access = list() template_access = list() job = /datum/job/human_ai + big_pointer = TRUE + pointer_color = COLOR_MODERATE_BLUE diff --git a/code/datums/id_trim/ruins.dm b/code/datums/id_trim/ruins.dm index e308287ec5c5d..0b0591e54292d 100644 --- a/code/datums/id_trim/ruins.dm +++ b/code/datums/id_trim/ruins.dm @@ -72,6 +72,7 @@ /datum/id_trim/centcom/corpse/commander assignment = "Commander" access = list(ACCESS_CENT_CAPTAIN, ACCESS_CENT_GENERAL, ACCESS_CENT_SPECOPS, ACCESS_CENT_MEDICAL, ACCESS_CENT_STORAGE) + big_pointer = TRUE /// Trim for various Centcom corpses. /datum/id_trim/centcom/corpse/private_security @@ -115,12 +116,14 @@ /datum/id_trim/pirate/captain assignment = "Pirate Captain" trim_state = "trim_captain" + big_pointer = TRUE /datum/id_trim/pirate/silverscale assignment = "Silver Scale Member" /datum/id_trim/pirate/captain/silverscale assignment = "Silver Scale VIP" + big_pointer = TRUE //Trims for Dangerous Research, used in ``dangerous_research.dm`` /datum/id_trim/away/dangerous_research @@ -130,6 +133,7 @@ /datum/id_trim/away/dangerous_research/head_occultist assignment = "Head Occultist" access = list(ACCESS_AWAY_SCIENCE, ACCESS_AWAY_COMMAND) + big_pointer = TRUE //Trims for waystation.dmm space ruin /datum/id_trim/away/waystation/cargo_technician @@ -143,6 +147,7 @@ trim_state = "trim_quartermaster" department_color = COLOR_CARGO_BROWN access = list(ACCESS_AWAY_SUPPLY, ACCESS_AWAY_COMMAND) + big_pointer = TRUE /datum/id_trim/away/waystation/security assignment = "Waystation Security Officer" @@ -162,8 +167,9 @@ /datum/id_trim/away/the_outlet/mad_manager assignment = "The Mad Manager" access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_MEDICAL, ACCESS_AWAY_SEC) + big_pointer = TRUE -//Haunted Trading Post IDs // +//Haunted Trading Post IDs /datum/id_trim/away/hauntedtradingpost assignment = "Donk Co. Employee" department_color = COLOR_ENGINEERING_ORANGE @@ -174,4 +180,4 @@ /datum/id_trim/away/hauntedtradingpost/boss assignment = "Donk Co. Executive" access = list(ACCESS_SYNDICATE, ACCESS_AWAY_COMMAND) -// // + big_pointer = TRUE diff --git a/code/datums/id_trim/syndicate.dm b/code/datums/id_trim/syndicate.dm index 9a3e0c5fc9173..41c76aaf3784c 100644 --- a/code/datums/id_trim/syndicate.dm +++ b/code/datums/id_trim/syndicate.dm @@ -7,11 +7,14 @@ sechud_icon_state = SECHUD_SYNDICATE access = list(ACCESS_SYNDICATE) threat_modifier = 5 // Bad guy on deck + big_pointer = TRUE + pointer_color = COLOR_SYNDIE_RED /// Trim for Syndicate mobs, outfits and corpses. /datum/id_trim/syndicom/crew assignment = "Syndicate Operative" access = list(ACCESS_SYNDICATE, ACCESS_ROBOTICS) + big_pointer = FALSE /// Interdyne medical Staff /datum/id_trim/syndicom/Interdyne/pharmacist @@ -19,6 +22,8 @@ trim_state = "trim_medicaldoctor" sechud_icon_state = SECHUD_SYNDICATE_INTERDYNE access = list(ACCESS_SYNDICATE, ACCESS_ROBOTICS, ACCESS_SURGERY) + big_pointer = FALSE + pointer_color = null /// Interdyne head medical Staff /datum/id_trim/syndicom/Interdyne/pharmacist_director @@ -28,6 +33,8 @@ subdepartment_color = COLOR_SYNDIE_RED_HEAD sechud_icon_state = SECHUD_SYNDICATE_INTERDYNE_HEAD access = list(ACCESS_SYNDICATE, ACCESS_ROBOTICS, ACCESS_SURGERY) + big_pointer = TRUE + pointer_color = COLOR_SYNDIE_RED_HEAD /// Trim for the space IRS agents (why are they syndie access? I wouldn't worry about it.) /datum/id_trim/syndicom/irs @@ -37,11 +44,14 @@ subdepartment_color = COLOR_COMMAND_BLUE sechud_icon_state = SECHUD_DEATH_COMMANDO access = list(ACCESS_SYNDICATE, ACCESS_MAINT_TUNNELS) + big_pointer = FALSE + pointer_color = null /datum/id_trim/syndicom/irs/auditor assignment = "Internal Revenue Service Head Auditor" trim_state = "trim_quartermaster" sechud_icon_state = SECHUD_QUARTERMASTER + big_pointer = TRUE /// Trim for Syndicate mobs, outfits and corpses. /datum/id_trim/syndicom/captain @@ -60,6 +70,8 @@ /datum/id_trim/battlecruiser/captain assignment = "Syndicate Battlecruiser Captain" access = list(ACCESS_SYNDICATE, ACCESS_SYNDICATE_LEADER) + big_pointer = TRUE + pointer_color = COLOR_SYNDIE_RED /// Trim for Chameleon ID cards. Many outfits, nuke ops and some corpses hold Chameleon ID cards. /datum/id_trim/chameleon @@ -79,6 +91,8 @@ /datum/id_trim/chameleon/operative/nuke_leader assignment = "Syndicate Operative Leader" access = list(ACCESS_MAINT_TUNNELS, ACCESS_SYNDICATE, ACCESS_SYNDICATE_LEADER) + big_pointer = TRUE + pointer_color = COLOR_SYNDIE_RED /// Trim for Chameleon ID cards. Many outfits, nuke ops and some corpses hold Chameleon ID cards. /datum/id_trim/chameleon/operative/clown @@ -89,3 +103,5 @@ /datum/id_trim/chameleon/operative/clown_leader assignment = "Syndicate Entertainment Operative Leader" access = list(ACCESS_MAINT_TUNNELS, ACCESS_SYNDICATE, ACCESS_SYNDICATE_LEADER) + big_pointer = TRUE + pointer_color = COLOR_SYNDIE_RED diff --git a/code/datums/looping_sounds/_looping_sound.dm b/code/datums/looping_sounds/_looping_sound.dm index 54185efdb8dda..122eab2861e99 100644 --- a/code/datums/looping_sounds/_looping_sound.dm +++ b/code/datums/looping_sounds/_looping_sound.dm @@ -2,7 +2,7 @@ * A datum for sounds that need to loop, with a high amount of configurability. */ /datum/looping_sound - /// (list or soundfile) Since this can be either a list or a single soundfile you can have random sounds. May contain further lists but must contain a soundfile at the end. + /// (list or soundfile) Since this can be either a list or a single soundfile you can have random sounds. May contain further lists but must contain a soundfile at the end. In a list, path must have also be assigned a value or it will be assigned 0 and not play. var/mid_sounds /// The length of time to wait between playing mid_sounds. var/mid_length diff --git a/code/datums/looping_sounds/breathing.dm b/code/datums/looping_sounds/breathing.dm index 82b33ee8311b1..73474149ae4bb 100644 --- a/code/datums/looping_sounds/breathing.dm +++ b/code/datums/looping_sounds/breathing.dm @@ -1,8 +1,19 @@ /datum/looping_sound/breathing - mid_sounds = 'sound/voice/breathing.ogg' + mid_sounds = list( + 'sound/voice/breathing/internals_breathing1.ogg' = 1, + 'sound/voice/breathing/internals_breathing2.ogg' = 1, + 'sound/voice/breathing/internals_breathing3.ogg' = 1, + 'sound/voice/breathing/internals_breathing4.ogg' = 1, + 'sound/voice/breathing/internals_breathing5.ogg' = 1, + 'sound/voice/breathing/internals_breathing6.ogg' = 1, + 'sound/voice/breathing/internals_breathing7.ogg' = 1, + 'sound/voice/breathing/internals_breathing8.ogg' = 1, + ) //Calculated this by using the average breathing time of an adult (12 to 20 per minute, which on average is 16 per minute) - mid_length = 3.75 SECONDS - mid_length_vary = 0.2 SECONDS + // realism is overrated, make it longer to reduce ear fatigue + mid_length = 7 SECONDS + mid_length_vary = 0.7 SECONDS //spess station- - volume = 13 + volume = 7 pressure_affected = FALSE + vary = TRUE diff --git a/code/datums/looping_sounds/machinery_sounds.dm b/code/datums/looping_sounds/machinery_sounds.dm index 2d5e3564e6d09..bc32b03125660 100644 --- a/code/datums/looping_sounds/machinery_sounds.dm +++ b/code/datums/looping_sounds/machinery_sounds.dm @@ -116,7 +116,7 @@ start_sound = 'sound/machines/computer/computer_start.ogg' start_length = 7.2 SECONDS start_volume = 10 - mid_sounds = list('sound/machines/computer/computer_mid1.ogg', 'sound/machines/computer/computer_mid2.ogg') + mid_sounds = list('sound/machines/computer/computer_mid1.ogg' = 1, 'sound/machines/computer/computer_mid2.ogg' = 1) mid_length = 1.8 SECONDS end_sound = 'sound/machines/computer/computer_end.ogg' end_volume = 10 @@ -126,10 +126,17 @@ falloff_distance = 1 //Instant falloff after initial tile /datum/looping_sound/gravgen - mid_sounds = list('sound/machines/gravgen/gravgen_mid1.ogg' = 1, 'sound/machines/gravgen/gravgen_mid2.ogg' = 1, 'sound/machines/gravgen/gravgen_mid3.ogg' = 1, 'sound/machines/gravgen/gravgen_mid4.ogg' = 1) - mid_length = 1.8 SECONDS - extra_range = 10 - volume = 20 + start_sound = 'sound/machines/gravgen/grav_gen_start.ogg' + start_length = 1 SECONDS + mid_sounds = list( + 'sound/machines/gravgen/grav_gen_mid1.ogg' = 12, + 'sound/machines/gravgen/grav_gen_mid2.ogg' = 1, + ) + mid_length = 1.1 SECONDS + end_sound = 'sound/machines/gravgen/grav_gen_end.ogg' + extra_range = 8 + vary = TRUE + volume = 70 falloff_distance = 5 falloff_exponent = 20 diff --git a/code/datums/martial/boxing.dm b/code/datums/martial/boxing.dm index 5c24aaf45b7b2..9d6252855d3e1 100644 --- a/code/datums/martial/boxing.dm +++ b/code/datums/martial/boxing.dm @@ -7,8 +7,10 @@ name = "Boxing" id = MARTIALART_BOXING pacifist_style = TRUE - ///Boolean on whether we are sportsmanlike in our tussling; TRUE means we have restrictions + /// Boolean on whether we are sportsmanlike in our tussling; TRUE means we have restrictions var/honorable_boxer = TRUE + /// Default damage type for our boxing. + var/default_damage_type = STAMINA /// List of traits applied to users of this martial art. var/list/boxing_traits = list(TRAIT_BOXING_READY) /// Balloon alert cooldown for warning our boxer to alternate their blows to get more damage @@ -40,10 +42,16 @@ if(findtext(streak, LEFT_RIGHT_COMBO) || findtext(streak, RIGHT_LEFT_COMBO)) reset_streak() + // If we have an extra effect from the combo, perform it here. By default, we have no extra effect. + perform_extra_effect(attacker, defender) return combo_multiplier * 1.5 return combo_multiplier +/// An extra effect on some moves and attacks. +/datum/martial_art/boxing/proc/perform_extra_effect(mob/living/attacker, mob/living/defender) + return + /datum/martial_art/boxing/disarm_act(mob/living/attacker, mob/living/defender) if(honor_check(defender)) add_to_streak("D", defender) @@ -88,8 +96,8 @@ // If true, grants experience for punching; we only gain experience if we punch another boxer. var/grant_experience = FALSE - // What type of damage does our kind of boxing do? Defaults to STAMINA, unless you're performing EVIL BOXING - var/damage_type = honorable_boxer ? STAMINA : attacker.get_attack_type() + // What type of damage does our kind of boxing do? Defaults to STAMINA for normal boxing, unless you're performing EVIL BOXING. Subtypes use different damage types. + var/damage_type = honorable_boxer ? default_damage_type : attacker.get_attack_type() attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH) @@ -147,12 +155,12 @@ log_combat(attacker, defender, "punched (boxing) ") + if(defender.stat == DEAD || !honor_check(defender)) //early returning here so we don't worry about knockout probs or experience gain + return TRUE + if(grant_experience) skill_experience_adjustment(attacker, (damage/lower_force)) - if(defender.stat == DEAD || !honor_check(defender)) //early returning here so we don't worry about knockout probs - return TRUE - //Determine our attackers athletics level as a knockout probability bonus var/attacker_athletics_skill = (attacker.mind?.get_skill_modifier(/datum/skill/athletics, SKILL_RANDS_MODIFIER) + base_unarmed_effectiveness) @@ -165,6 +173,18 @@ if(!prob(final_knockout_probability)) return TRUE + crit_effect(attacker, defender, armor_block, damage_type, damage) + + experience_earned *= 2 //Double our experience gain on a crit hit + + playsound(defender, 'sound/effects/coin2.ogg', 40, TRUE) + new /obj/effect/temp_visual/crit(get_turf(defender)) + skill_experience_adjustment(attacker, experience_earned) //double experience for a successful crit + + return TRUE + +/// Our crit effect. For normal boxing, this applies a stagger, then applies a knockout if they're staggered. Other types of boxing apply different kinds of effects. +/datum/martial_art/boxing/proc/crit_effect(mob/living/attacker, mob/living/defender, armor_block = 0, damage_type = STAMINA, damage = 0) if(defender.get_timed_status_effect_duration(/datum/status_effect/staggered)) defender.visible_message( span_danger("[attacker] knocks [defender] out with a haymaker!"), @@ -189,14 +209,6 @@ to_chat(attacker, span_danger("You stagger [defender] with a haymaker!")) log_combat(attacker, defender, "staggered (boxing) ") - experience_earned *= 2 //Double our experience gain on a crit hit - - playsound(defender, 'sound/effects/coin2.ogg', 40, TRUE) - new /obj/effect/temp_visual/crit(get_turf(defender)) - skill_experience_adjustment(attacker, experience_earned) //double experience for a successful crit - - return TRUE - /// Returns whether whoever is checked by this proc is complying with the rules of boxing. The boxer cannot block non-boxers, and cannot apply their scariest moves against non-boxers. /datum/martial_art/boxing/proc/honor_check(mob/living/possible_boxer) if(!honorable_boxer) @@ -220,7 +232,7 @@ /datum/martial_art/boxing/proc/check_block(mob/living/boxer, atom/movable/hitby, damage, attack_text, attack_type, ...) SIGNAL_HANDLER - if(!can_use(boxer) || !boxer.throw_mode || boxer.incapacitated(IGNORE_GRAB)) + if(!can_use(boxer) || !boxer.throw_mode || INCAPACITATED_IGNORING(boxer, INCAPABLE_GRAB)) return NONE if(attack_type != UNARMED_ATTACK) @@ -254,8 +266,9 @@ return NONE if(istype(attacker) && boxer.Adjacent(attacker)) - attacker.apply_damage(10, STAMINA) + attacker.apply_damage(10, default_damage_type) boxer.apply_damage(5, STAMINA) + perform_extra_effect(boxer, attacker) boxer.visible_message( span_danger("[boxer] [block_text]s [attack_text]!"), @@ -271,6 +284,8 @@ return FALSE return ..() +// Boxing Variants! + /// Evil Boxing; for sick, evil scoundrels. Has no honor, making it more lethal (therefore unable to be used by pacifists). /// Grants Strength and Stimmed to speed up any experience gain. @@ -281,6 +296,68 @@ honorable_boxer = FALSE boxing_traits = list(TRAIT_BOXING_READY, TRAIT_STRENGTH, TRAIT_STIMMED) +/// Hunter Boxing: for the uncaring, completely deranged one-spacer ecological disaster. +/// The honor check accepts boxing ready targets, OR various biotypes as valid targets. Uses a special crit effect rather than the standard one (against monsters). +/// I guess technically, this allows for lethal boxing. If you want. +/datum/martial_art/boxing/hunter + name = "Hunter Boxing" + id = MARTIALART_HUNTER_BOXING + pacifist_style = FALSE + default_damage_type = BRUTE + boxing_traits = list(TRAIT_BOXING_READY) + /// The mobs we are looking for to pass the honor check + var/honorable_mob_biotypes = MOB_BEAST | MOB_SPECIAL | MOB_PLANT | MOB_BUG + /// Our crit shout words. First word is then paired with a second word to form an attack name. + var/list/first_word_strike = list("Extinction", "Brutalization", "Explosion", "Adventure", "Thunder", "Lightning", "Sonic", "Atomizing", "Whirlwind", "Tornado", "Shark", "Falcon") + var/list/second_word_strike = list(" Punch", " Pawnch", "-punch", " Jab", " Hook", " Fist", " Uppercut", " Straight", " Strike", " Lunge") + +/datum/martial_art/boxing/hunter/honor_check(mob/living/possible_boxer) + if(HAS_TRAIT(possible_boxer, TRAIT_BOXING_READY)) + return TRUE + + if(possible_boxer.mob_biotypes & MOB_HUMANOID && !istype(possible_boxer, /mob/living/simple_animal/hostile/megafauna)) //We're after animals, not people. Unless they want to box. (Or a megafauna) + return FALSE + + if(possible_boxer.mob_biotypes & honorable_mob_biotypes) //We're after animals, not people + return TRUE + + return FALSE //rather than default assume TRUE, we default assume FALSE. After all, there could be mobs that are none of our biotypes and also not humanoid. By default, they would be valid for being boxed if TRUE. + +// Our hunter boxer applies a rebuke and double damage against the target of their crit. If the target is humanoid, we just perform our regular crit effect instead. + +/datum/martial_art/boxing/hunter/crit_effect(mob/living/attacker, mob/living/defender, armor_block = 0, damage_type = STAMINA, damage = 0) + if(defender.mob_biotypes & MOB_HUMANOID && !istype(defender, /mob/living/simple_animal/hostile/megafauna)) + return ..() //Applies the regular crit effect if it is a normal human, and not a megafauna + + var/first_word_pick = pick(first_word_strike) + var/second_word_pick = pick(second_word_strike) + + defender.visible_message( + span_danger("[attacker] knocks the absolute bajeezus out of [defender] utilizing the terrifying [first_word_pick][second_word_pick]!!!"), + span_userdanger("You have the absolute bajeezus knocked out of you by [attacker]!!!"), + span_hear("You hear a sickening sound of flesh hitting flesh!"), + COMBAT_MESSAGE_RANGE, + attacker, + ) + to_chat(attacker, span_danger("You knock the absolute bajeezus out of [defender] out with the terrifying [first_word_pick][second_word_pick]!!!")) + if(ishuman(attacker)) + var/mob/living/carbon/human/human_attacker = attacker + human_attacker.force_say() + human_attacker.say("[first_word_pick][second_word_pick]!!!", forced = "hunter boxing enthusiastic battlecry") + defender.apply_status_effect(/datum/status_effect/rebuked) + defender.apply_damage(damage * 2, default_damage_type, BODY_ZONE_CHEST, armor_block) //deals double our damage AGAIN + attacker.reagents.add_reagent(/datum/reagent/medicine/omnizine/godblood, 3) //Get a little healing in return for a successful crit + log_combat(attacker, defender, "hunter crit punched (boxing)") + +// Our hunter boxer speeds up their attacks when completing a combo against a valid target, and does a sizable amount of extra damage. + +/datum/martial_art/boxing/hunter/perform_extra_effect(mob/living/attacker, mob/living/defender) + if(defender.mob_biotypes & MOB_HUMANOID && !istype(defender, /mob/living/simple_animal/hostile/megafauna)) + return // Does not apply to humans (who aren't megafauna) + + attacker.changeNext_move(CLICK_CD_RAPID) + defender.apply_damage(rand(15,20), default_damage_type, BODY_ZONE_CHEST) + #undef LEFT_RIGHT_COMBO #undef RIGHT_LEFT_COMBO #undef LEFT_LEFT_COMBO diff --git a/code/datums/martial/cqc.dm b/code/datums/martial/cqc.dm index 8e33ac5a851ea..28b820278e21b 100644 --- a/code/datums/martial/cqc.dm +++ b/code/datums/martial/cqc.dm @@ -46,7 +46,7 @@ /datum/martial_art/cqc/proc/check_block(mob/living/cqc_user, atom/movable/hitby, damage, attack_text, attack_type, ...) SIGNAL_HANDLER - if(!can_use(cqc_user) || !cqc_user.throw_mode || cqc_user.incapacitated(IGNORE_GRAB)) + if(!can_use(cqc_user) || !cqc_user.throw_mode || INCAPACITATED_IGNORING(cqc_user, INCAPABLE_GRAB)) return NONE if(attack_type == PROJECTILE_ATTACK) return NONE diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index 330c224070c3e..1f81b884f45fa 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -184,7 +184,7 @@ /datum/martial_art/the_sleeping_carp/proc/can_deflect(mob/living/carp_user) if(!can_use(carp_user) || !carp_user.combat_mode) return FALSE - if(carp_user.incapacitated(IGNORE_GRAB)) //NO STUN + if(INCAPACITATED_IGNORING(carp_user, INCAPABLE_GRAB)) //NO STUN return FALSE if(!(carp_user.mobility_flags & MOBILITY_USE)) //NO UNABLE TO USE return FALSE diff --git a/code/datums/mutations/hulk.dm b/code/datums/mutations/hulk.dm index 4bc6c77a9fe81..38ecb0fa07356 100644 --- a/code/datums/mutations/hulk.dm +++ b/code/datums/mutations/hulk.dm @@ -113,7 +113,7 @@ return if(!user.throw_mode || user.get_active_held_item() || user.zone_selected != BODY_ZONE_PRECISE_GROIN) return - if(user.grab_state < GRAB_NECK || !iscarbon(user.pulling) || user.buckled || user.incapacitated()) + if(user.grab_state < GRAB_NECK || !iscarbon(user.pulling) || user.buckled || user.incapacitated) return var/mob/living/carbon/possible_throwable = user.pulling @@ -166,7 +166,7 @@ * For each step of the swinging, with the delay getting shorter along the way. Checks to see we still have them in our grasp at each step. */ /datum/mutation/human/hulk/proc/swing_loop(mob/living/carbon/human/the_hulk, mob/living/carbon/yeeted_person, step, original_dir) - if(!yeeted_person || !the_hulk || the_hulk.incapacitated()) + if(!yeeted_person || !the_hulk || the_hulk.incapacitated) return if(get_dist(the_hulk, yeeted_person) > 1 || !isturf(the_hulk.loc) || !isturf(yeeted_person.loc)) to_chat(the_hulk, span_warning("You lose your grasp on [yeeted_person]!")) @@ -237,7 +237,7 @@ /// Time to toss the victim at high speed /datum/mutation/human/hulk/proc/finish_swing(mob/living/carbon/human/the_hulk, mob/living/carbon/yeeted_person, original_dir) - if(!yeeted_person || !the_hulk || the_hulk.incapacitated()) + if(!yeeted_person || !the_hulk || the_hulk.incapacitated) return if(get_dist(the_hulk, yeeted_person) > 1 || !isturf(the_hulk.loc) || !isturf(yeeted_person.loc)) to_chat(the_hulk, span_warning("You lose your grasp on [yeeted_person]!")) diff --git a/code/datums/outfit.dm b/code/datums/outfit.dm index e427b2994f066..2a7696be65787 100644 --- a/code/datums/outfit.dm +++ b/code/datums/outfit.dm @@ -354,8 +354,11 @@ preload += suit_store preload += back //Load in backpack gear and shit - for(var/datum/type_to_load in backpack_contents) - for(var/i in 1 to backpack_contents[type_to_load]) + for(var/type_to_load in backpack_contents) + var/num_to_load = backpack_contents[type_to_load] + if(!isnum(num_to_load)) + num_to_load = 1 + for(var/i in 1 to num_to_load) preload += type_to_load preload += belt preload += ears diff --git a/code/datums/proximity_monitor/fields/gravity.dm b/code/datums/proximity_monitor/fields/gravity.dm index b7e22840041dc..745072d69e10a 100644 --- a/code/datums/proximity_monitor/fields/gravity.dm +++ b/code/datums/proximity_monitor/fields/gravity.dm @@ -63,3 +63,63 @@ /datum/proximity_monitor/advanced/gravity/warns_on_entrance/proc/clear_recent_warning(mob_ref_key) LAZYREMOVE(recently_warned, mob_ref_key) + +/obj/gravity_fluff_field + icon = 'icons/obj/smooth_structures/grav_field.dmi' + icon_state = "grav_field-0" + base_icon_state = "grav_field" + obj_flags = NONE + anchored = TRUE + move_resist = INFINITY + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + pass_flags_self = LETPASSCLICKS + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_GRAV_FIELD + canSmoothWith = SMOOTH_GROUP_GRAV_FIELD + alpha = 200 + /// our emissive appearance + var/mutable_appearance/emissive + +/obj/gravity_fluff_field/Initialize(mapload, strength) + . = ..() + if(isnull(strength)) + return INITIALIZE_HINT_QDEL + QUEUE_SMOOTH(src) + QUEUE_SMOOTH_NEIGHBORS(src) + switch(strength) + if(2 to INFINITY) + particles = new /particles/grav_field_down/strong() + if(1 to 2) + particles = new /particles/grav_field_down() + if(0 to 1) + particles = new /particles/grav_field_float() + if(-INFINITY to -1) + particles = new /particles/grav_field_up() + color = particles.color + RegisterSignal(src, COMSIG_ATOM_SMOOTHED_ICON, PROC_REF(smoothed)) + +/obj/gravity_fluff_field/Destroy(force) + . = ..() + QDEL_NULL(particles) + emissive = null + +/obj/gravity_fluff_field/proc/smoothed(datum/source) + SIGNAL_HANDLER + cut_overlay(emissive) + // because it uses a different name + emissive = emissive_appearance('icons/obj/smooth_structures/grav_field_emissive.dmi', "grav_field_emissive-[splittext(icon_state, "-")[2]]", src) + add_overlay(emissive) + +// Subtype which adds a subtle overlay to all turfs +/datum/proximity_monitor/advanced/gravity/subtle_effect + +/datum/proximity_monitor/advanced/gravity/subtle_effect/setup_field_turf(turf/target) + . = ..() + if(!isopenturf(target)) + return + new /obj/gravity_fluff_field(target, gravity_value) + +/datum/proximity_monitor/advanced/gravity/subtle_effect/cleanup_field_turf(turf/target) + . = ..() + qdel(locate(/obj/gravity_fluff_field) in target) diff --git a/code/datums/quirks/negative_quirks/paraplegic.dm b/code/datums/quirks/negative_quirks/paraplegic.dm index 58e1c4ba31e87..1cbb2dbac1017 100644 --- a/code/datums/quirks/negative_quirks/paraplegic.dm +++ b/code/datums/quirks/negative_quirks/paraplegic.dm @@ -9,6 +9,10 @@ hardcore_value = 15 mail_goodies = list(/obj/vehicle/ridden/wheelchair/motorized) //yes a fullsized unfolded motorized wheelchair does fit +/datum/quirk_constant_data/paraplegic + associated_typepath = /datum/quirk/paraplegic + customization_options = list(/datum/preference/choiced/paraplegic) + /datum/quirk/paraplegic/add_unique(client/client_source) if(quirk_holder.buckled) // Handle late joins being buckled to arrival shuttle chairs. quirk_holder.buckled.unbuckle_mob(quirk_holder) @@ -32,6 +36,16 @@ if(dropped_item.fingerprintslast == quirk_holder.ckey) quirk_holder.put_in_hands(dropped_item) + // Finally, removes their legs if they have opted as such, deleting the shoes + var/amputee = GLOB.paraplegic_choice[client_source?.prefs?.read_preference(/datum/preference/choiced/paraplegic)] + if(amputee) + delete_legs(quirk_holder) + +/datum/quirk/paraplegic/proc/delete_legs(mob/living/carbon/human/human_holder) + qdel(human_holder.get_item_by_slot(ITEM_SLOT_FEET)) + qdel(human_holder.get_bodypart(BODY_ZONE_L_LEG)) + qdel(human_holder.get_bodypart(BODY_ZONE_R_LEG)) + /datum/quirk/paraplegic/add(client/client_source) var/mob/living/carbon/human/human_holder = quirk_holder human_holder.gain_trauma(/datum/brain_trauma/severe/paralysis/paraplegic, TRAUMA_RESILIENCE_ABSOLUTE) diff --git a/code/datums/quirks/negative_quirks/prosthetic_organ.dm b/code/datums/quirks/negative_quirks/prosthetic_organ.dm index cd7ca2a801481..4a377699b40ac 100644 --- a/code/datums/quirks/negative_quirks/prosthetic_organ.dm +++ b/code/datums/quirks/negative_quirks/prosthetic_organ.dm @@ -60,9 +60,9 @@ medical_record_text = "During physical examination, patient was found to have a low-budget prosthetic [slot_string]. \ Removal of these organs is known to be dangerous to the patient as well as the practitioner." old_organ = human_holder.get_organ_slot(organ_slot) - if(prosthetic.Insert(human_holder, special = TRUE)) - old_organ.moveToNullspace() - STOP_PROCESSING(SSobj, old_organ) + prosthetic.Insert(human_holder, special = TRUE) + old_organ.moveToNullspace() + STOP_PROCESSING(SSobj, old_organ) /datum/quirk/prosthetic_organ/post_add() to_chat(quirk_holder, span_boldannounce("Your [slot_string] has been replaced with a surplus organ. It is weak and highly unstable. \ diff --git a/code/datums/records/crime.dm b/code/datums/records/crime.dm index a22ce7c816ad2..729b85c56b8e3 100644 --- a/code/datums/records/crime.dm +++ b/code/datums/records/crime.dm @@ -12,6 +12,8 @@ var/time /// Whether the crime is active or not var/valid = TRUE + /// Player that marked the crime as invalid + var/voider /datum/crime/New(name = "Crime", details = "No details provided.", author = "Anonymous") src.author = author diff --git a/code/datums/station_traits/neutral_traits.dm b/code/datums/station_traits/neutral_traits.dm index 3069e644d6e1b..5432701992b29 100644 --- a/code/datums/station_traits/neutral_traits.dm +++ b/code/datums/station_traits/neutral_traits.dm @@ -479,7 +479,7 @@ return if((skub_stance == RANDOM_SKUB && prob(50)) || skub_stance == PRO_SKUB) - var/obj/item/storage/box/skub/boxie = new(spawned.loc) + var/obj/item/storage/box/stickers/skub/boxie = new(spawned.loc) spawned.equip_to_slot_if_possible(boxie, ITEM_SLOT_BACKPACK, indirect_action = TRUE) if(ishuman(spawned)) var/obj/item/clothing/suit/costume/wellworn_shirt/skub/shirt = new(spawned.loc) @@ -496,24 +496,28 @@ shirt.forceMove(boxie) /// A box containing a skub, for easier carry because skub is a bulky item. -/obj/item/storage/box/skub - name = "skub box" - desc = "A box to store your skub and pro-skub shirt in. A label on the back reads: \"Skubtide, Stationwide\"." - icon_state = "hugbox" - illustration = "skub" - -/obj/item/storage/box/skub/Initialize(mapload) +/obj/item/storage/box/stickers/skub + name = "skub fan pack" + desc = "A vinyl pouch to store your skub and pro-skub shirt in. A label on the back reads: \"Skubtide, Stationwide\"." + icon_state = "skubpack" + illustration = "label_skub" + w_class = WEIGHT_CLASS_SMALL + +/obj/item/storage/box/stickers/skub/Initialize(mapload) . = ..() + atom_storage.max_slots = 3 atom_storage.exception_hold = typecacheof(list(/obj/item/skub, /obj/item/clothing/suit/costume/wellworn_shirt/skub)) -/obj/item/storage/box/skub/PopulateContents() +/obj/item/storage/box/stickers/skub/PopulateContents() new /obj/item/skub(src) new /obj/item/sticker/skub(src) new /obj/item/sticker/skub(src) /obj/item/storage/box/stickers/anti_skub - name = "anti-skub stickers box" - desc = "The enemy may have been given a skub and a shirt, but I've more stickers! Plus the box can hold my anti-skub shirt." + name = "anti-skub stickers pack" + desc = "The enemy may have been given a skub and a shirt, but I've got more stickers! Plus the pack can hold my anti-skub shirt." + icon_state = "skubpack" + illustration = "label_anti_skub" /obj/item/storage/box/stickers/anti_skub/Initialize(mapload) . = ..() diff --git a/code/datums/status_effects/food_effects.dm b/code/datums/status_effects/buffs/food/_food_effect.dm similarity index 64% rename from code/datums/status_effects/food_effects.dm rename to code/datums/status_effects/buffs/food/_food_effect.dm index f36f1e2034d9c..fe63df29e3a8a 100644 --- a/code/datums/status_effects/food_effects.dm +++ b/code/datums/status_effects/buffs/food/_food_effect.dm @@ -1,19 +1,18 @@ /// Buffs given by eating hand-crafted food. The duration scales with consumable reagents purity. /datum/status_effect/food - id = "food_buff" + id = "food_effect" duration = 5 MINUTES // Same as food mood buffs status_type = STATUS_EFFECT_REPLACE // Only one food buff allowed alert_type = /atom/movable/screen/alert/status_effect/food show_duration = TRUE - /// Buff power + /// Buff power equal to food complexity (1 to 5) var/strength /datum/status_effect/food/on_creation(mob/living/new_owner, timeout_mod = 1, strength = 1) + . = ..() src.strength = strength - //Generate alert when not specified if(isnum(timeout_mod)) duration *= timeout_mod - . = ..() if(istype(linked_alert, /atom/movable/screen/alert/status_effect/food)) linked_alert.icon_state = "[linked_alert.base_icon_state]_[strength]" @@ -22,19 +21,3 @@ desc = "Eating it made me feel better." icon_state = "food_buff_1" base_icon_state = "food_buff" - -/// Makes you gain a trait -/datum/status_effect/food/trait - var/trait = TRAIT_DUMB // You need to override this - -/datum/status_effect/food/trait/on_apply() - ADD_TRAIT(owner, trait, type) - return ..() - -/datum/status_effect/food/trait/be_replaced() - REMOVE_TRAIT(owner, trait, type) - return ..() - -/datum/status_effect/food/trait/on_remove() - REMOVE_TRAIT(owner, trait, type) - return ..() diff --git a/code/datums/status_effects/buffs/food/food_traits.dm b/code/datums/status_effects/buffs/food/food_traits.dm deleted file mode 100644 index dfd0b888aa096..0000000000000 --- a/code/datums/status_effects/buffs/food/food_traits.dm +++ /dev/null @@ -1,7 +0,0 @@ -/datum/status_effect/food/trait/shockimmune - alert_type = /atom/movable/screen/alert/status_effect/food/trait_shockimmune - trait = TRAIT_SHOCKIMMUNE - -/atom/movable/screen/alert/status_effect/food/trait_shockimmune - name = "Grounded" - desc = "That meal made me feel like a superconductor..." diff --git a/code/datums/status_effects/buffs/food/grant_trait.dm b/code/datums/status_effects/buffs/food/grant_trait.dm new file mode 100644 index 0000000000000..f25be3b0b3bfd --- /dev/null +++ b/code/datums/status_effects/buffs/food/grant_trait.dm @@ -0,0 +1,56 @@ +/// Makes you gain a trait +/datum/status_effect/food/trait + var/trait = TRAIT_DUMB // You need to override this + +/datum/status_effect/food/trait/on_apply() + if(!HAS_TRAIT_FROM(owner, trait, type)) // Check if trait was already applied + ADD_TRAIT(owner, trait, type) + return ..() + +/datum/status_effect/food/trait/be_replaced() + REMOVE_TRAIT(owner, trait, type) + return ..() + +/datum/status_effect/food/trait/on_remove() + REMOVE_TRAIT(owner, trait, type) + return ..() + +/datum/status_effect/food/trait/shockimmune + alert_type = /atom/movable/screen/alert/status_effect/shockimmune + trait = TRAIT_SHOCKIMMUNE + +/atom/movable/screen/alert/status_effect/shockimmune + name = "Grounded" + desc = "That meal made me feel like a superconductor..." + icon_state = "shock_immune" + +/datum/status_effect/food/trait/mute + alert_type = /atom/movable/screen/alert/status_effect/mute + trait = TRAIT_MUTE + +/atom/movable/screen/alert/status_effect/mute + name = "..." + desc = "..." + icon_state = "mute" + +/datum/status_effect/food/trait/ashstorm_immune + alert_type = /atom/movable/screen/alert/status_effect/ashstorm_immune + trait = TRAIT_ASHSTORM_IMMUNE + +/atom/movable/screen/alert/status_effect/ashstorm_immune + name = "Ashstorm-proof" + desc = "That meal makes me feel born on Lavaland." + icon_state = "ashstorm_immune" + +/datum/status_effect/food/trait/waddle + alert_type = /atom/movable/screen/alert/status_effect/waddle + trait = TRAIT_WADDLING + +/datum/status_effect/food/trait/waddle/on_apply() + owner.AddElementTrait(trait, type, /datum/element/waddling) + return ..() + +/atom/movable/screen/alert/status_effect/waddle + name = "Waddling" + desc = "That meal makes me want to joke around." + icon_state = "waddle" diff --git a/code/datums/status_effects/buffs/food/speech.dm b/code/datums/status_effects/buffs/food/speech.dm new file mode 100644 index 0000000000000..634fd739709b3 --- /dev/null +++ b/code/datums/status_effects/buffs/food/speech.dm @@ -0,0 +1,45 @@ +///Temporary modifies the speech using the /datum/component/speechmod +/datum/status_effect/food/speech + +/datum/status_effect/food/speech/italian + alert_type = /atom/movable/screen/alert/status_effect/italian_speech + +/datum/status_effect/food/speech/italian/on_apply() + AddComponent( \ + /datum/component/speechmod, \ + replacements = strings("italian_replacement.json", "italian"), \ + end_string = list( + " Ravioli, ravioli, give me the formuoli!", + " Mamma-mia!", + " Mamma-mia! That's a spicy meat-ball!", + " La la la la la funiculi funicula!" + ), \ + end_string_chance = 3 \ + ) + return ..() + +/atom/movable/screen/alert/status_effect/italian_speech + name = "Linguini Embrace" + desc = "You feel a sudden urge to gesticulate wildly." + icon_state = "food_italian" + +/datum/status_effect/food/speech/french + alert_type = /atom/movable/screen/alert/status_effect/french_speech + +/datum/status_effect/food/speech/french/on_apply() + AddComponent( \ + /datum/component/speechmod, \ + replacements = strings("french_replacement.json", "french"), \ + end_string = list( + " Honh honh honh!", + " Honh!", + " Zut Alors!" + ), \ + end_string_chance = 3, \ + ) + return ..() + +/atom/movable/screen/alert/status_effect/french_speech + name = "Café Chic" + desc = "Suddenly, everything seems worthy of a passionate debate." + icon_state = "food_french" diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index df93089633629..0162ef4e4ed27 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -606,7 +606,7 @@ alert_type = null /datum/status_effect/spasms/tick(seconds_between_ticks) - if(owner.stat >= UNCONSCIOUS || owner.incapacitated() || HAS_TRAIT(owner, TRAIT_HANDS_BLOCKED) || HAS_TRAIT(owner, TRAIT_IMMOBILIZED)) + if(owner.stat >= UNCONSCIOUS || owner.incapacitated || HAS_TRAIT(owner, TRAIT_HANDS_BLOCKED) || HAS_TRAIT(owner, TRAIT_IMMOBILIZED)) return if(!prob(15)) return diff --git a/code/datums/status_effects/debuffs/staggered.dm b/code/datums/status_effects/debuffs/staggered.dm index 9db72e1fd06ee..1291da1307a61 100644 --- a/code/datums/status_effects/debuffs/staggered.dm +++ b/code/datums/status_effects/debuffs/staggered.dm @@ -4,7 +4,7 @@ /// Staggered can occur most often via shoving, but can also occur in other places too. /datum/status_effect/staggered id = "staggered" - tick_interval = 0.5 SECONDS + tick_interval = 0.8 SECONDS alert_type = null remove_on_fullheal = TRUE @@ -25,7 +25,7 @@ UnregisterSignal(owner, COMSIG_LIVING_DEATH) owner.remove_movespeed_modifier(/datum/movespeed_modifier/staggered) // Resetting both X on remove so we're back to normal - owner.pixel_x = owner.base_pixel_x + animate(owner, pixel_x = owner.base_pixel_x, time = 0.2 SECONDS, flags = ANIMATION_PARALLEL) /// Signal proc that self deletes our staggered effect /datum/status_effect/staggered/proc/clear_staggered(datum/source) @@ -40,13 +40,16 @@ return if(HAS_TRAIT(owner, TRAIT_FAKEDEATH)) return - owner.do_stagger_animation() + INVOKE_ASYNC(owner, TYPE_PROC_REF(/mob/living, do_stagger_animation)) /// Helper proc that causes the mob to do a stagger animation. /// Doesn't change significantly, just meant to represent swaying back and forth /mob/living/proc/do_stagger_animation() - animate(src, pixel_x = 4, time = 0.2 SECONDS, loop = 6, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) - animate(pixel_x = -4, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE) + animate(src, pixel_x = 4, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + sleep(0.2 SECONDS) + animate(src, pixel_x = -8, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + sleep(0.2 SECONDS) + animate(src, pixel_x = 4, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) /// Status effect specifically for instances where someone is vulnerable to being stunned when shoved. /datum/status_effect/next_shove_stuns diff --git a/code/datums/status_effects/debuffs/strandling.dm b/code/datums/status_effects/debuffs/strandling.dm index 6050a3df304da..0ce0ad4188221 100644 --- a/code/datums/status_effects/debuffs/strandling.dm +++ b/code/datums/status_effects/debuffs/strandling.dm @@ -57,7 +57,7 @@ * tool - the tool the user's using to remove the strange. Can be null. */ /datum/status_effect/strandling/proc/try_remove_effect(mob/user, obj/item/tool) - if(user.incapacitated() || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED)) + if(user.incapacitated || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED)) return user.visible_message( diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm index 7cdb9d406152b..72681642a268e 100644 --- a/code/datums/storage/storage.dm +++ b/code/datums/storage/storage.dm @@ -735,7 +735,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) /datum/storage/proc/on_mousedrop_onto(datum/source, atom/over_object, mob/user) SIGNAL_HANDLER - if(ismecha(user.loc) || !user.canUseStorage()) + if(ismecha(user.loc) || user.incapacitated || !user.canUseStorage()) return if(istype(over_object, /atom/movable/screen/inventory/hand)) @@ -824,6 +824,9 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) return if(!iscarbon(user) && !isdrone(user)) return + var/mob/living/user_living = user + if(user_living.incapacitated) + return attempt_insert(dropping, user) return COMPONENT_CANCEL_MOUSEDROPPED_ONTO diff --git a/code/datums/weather/weather_types/radiation_storm.dm b/code/datums/weather/weather_types/radiation_storm.dm index a20b552df4f04..8a1cfff765733 100644 --- a/code/datums/weather/weather_types/radiation_storm.dm +++ b/code/datums/weather/weather_types/radiation_storm.dm @@ -20,7 +20,7 @@ protected_areas = list(/area/station/maintenance, /area/station/ai_monitored/turret_protected/ai_upload, /area/station/ai_monitored/turret_protected/ai_upload_foyer, /area/station/ai_monitored/turret_protected/aisat/maint, /area/station/ai_monitored/command/storage/satellite, /area/station/ai_monitored/turret_protected/ai, /area/station/commons/storage/emergency/starboard, /area/station/commons/storage/emergency/port, - /area/shuttle, /area/station/security/prison/safe, /area/station/security/prison/toilet, /area/icemoon/underground, /area/ruin/comms_agent/maint) + /area/shuttle, /area/station/security/prison/safe, /area/station/security/prison/toilet, /area/mine/maintenance, /area/icemoon/underground, /area/ruin/comms_agent/maint) target_trait = ZTRAIT_STATION immunity_type = TRAIT_RADSTORM_IMMUNE diff --git a/code/game/area/areas/away_content.dm b/code/game/area/areas/away_content.dm index ded38af6201ab..5e2219ef857e0 100644 --- a/code/game/area/areas/away_content.dm +++ b/code/game/area/areas/away_content.dm @@ -13,16 +13,6 @@ Unused icons for new areas are "awaycontent1" ~ "awaycontent30" sound_environment = SOUND_ENVIRONMENT_ROOM area_flags = UNIQUE_AREA -/area/awaymission/beach - name = "Beach" - icon_state = "away" - static_lighting = FALSE - base_lighting_alpha = 255 - base_lighting_color = "#FFFFCC" - requires_power = FALSE - has_gravity = STANDARD_GRAVITY - ambientsounds = list('sound/ambience/shore.ogg', 'sound/ambience/seag1.ogg','sound/ambience/seag2.ogg','sound/ambience/seag2.ogg','sound/ambience/ambiodd.ogg','sound/ambience/ambinice.ogg') - /area/awaymission/museum name = "Nanotrasen Museum" icon_state = "awaycontent28" diff --git a/code/game/atom/alternate_appearance.dm b/code/game/atom/alternate_appearance.dm index 228462f7936a4..108b72b95d286 100644 --- a/code/game/atom/alternate_appearance.dm +++ b/code/game/atom/alternate_appearance.dm @@ -35,20 +35,51 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances) GLOB.active_alternate_appearances += src for(var/mob in GLOB.player_list) - if(mobShouldSee(mob)) - show_to(mob) + apply_to_new_mob(mob) /datum/atom_hud/alternate_appearance/Destroy() GLOB.active_alternate_appearances -= src return ..() -/datum/atom_hud/alternate_appearance/proc/onNewMob(mob/M) - if(mobShouldSee(M)) - show_to(M) +/// Wrapper for applying this alt hud to the passed mob (if they should see it) +/datum/atom_hud/alternate_appearance/proc/apply_to_new_mob(mob/applying_to) + if(mobShouldSee(applying_to)) + if(!hud_users_all_z_levels[applying_to]) + show_to(applying_to) + return TRUE + return FALSE +/// Checks if the passed mob should be seeing this hud /datum/atom_hud/alternate_appearance/proc/mobShouldSee(mob/M) return FALSE +/datum/atom_hud/alternate_appearance/show_to(mob/new_viewer) + . = ..() + if(!new_viewer) + return + track_mob(new_viewer) + +/// Registers some signals to track the mob's state to determine if they should be seeing the hud still +/datum/atom_hud/alternate_appearance/proc/track_mob(mob/new_viewer) + return + +/datum/atom_hud/alternate_appearance/hide_from(mob/former_viewer, absolute) + . = ..() + if(!former_viewer || hud_atoms_all_z_levels[former_viewer] >= 1) + return + untrack_mob(former_viewer) + +/// Unregisters the signals that were tracking the mob's state +/datum/atom_hud/alternate_appearance/proc/untrack_mob(mob/former_viewer) + return + +/datum/atom_hud/alternate_appearance/proc/check_hud(mob/source) + SIGNAL_HANDLER + // Attempt to re-apply the hud entirely + if(!apply_to_new_mob(source)) + // If that failed, probably shouldn't be seeing it at all, so nuke it + hide_from(source, absolute = TRUE) + /datum/atom_hud/alternate_appearance/add_atom_to_hud(atom/A, image/I) . = ..() if(.) @@ -99,6 +130,22 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances) if(ghost_appearance) QDEL_NULL(ghost_appearance) +/datum/atom_hud/alternate_appearance/basic/track_mob(mob/new_viewer) + RegisterSignals(new_viewer, list( + COMSIG_MOB_ANTAGONIST_REMOVED, + COMSIG_MOB_GHOSTIZED, + COMSIG_MOB_MIND_TRANSFERRED_INTO, + COMSIG_MOB_MIND_TRANSFERRED_OUT_OF, + ), PROC_REF(check_hud), override = TRUE) + +/datum/atom_hud/alternate_appearance/basic/untrack_mob(mob/former_viewer) + UnregisterSignal(former_viewer, list( + COMSIG_MOB_ANTAGONIST_REMOVED, + COMSIG_MOB_GHOSTIZED, + COMSIG_MOB_MIND_TRANSFERRED_INTO, + COMSIG_MOB_MIND_TRANSFERRED_OUT_OF, + )) + /datum/atom_hud/alternate_appearance/basic/add_atom_to_hud(atom/A) LAZYINITLIST(A.hud_list) A.hud_list[appearance_key] = image @@ -136,16 +183,10 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances) /datum/atom_hud/alternate_appearance/basic/noncult /datum/atom_hud/alternate_appearance/basic/noncult/mobShouldSee(mob/M) - if(!IS_CULTIST(M)) - return TRUE - return FALSE - -/datum/atom_hud/alternate_appearance/basic/cult + return !IS_CULTIST(M) -/datum/atom_hud/alternate_appearance/basic/cult/mobShouldSee(mob/M) - if(IS_CULTIST(M)) - return TRUE - return FALSE +/datum/atom_hud/alternate_appearance/basic/has_antagonist/cult + antag_datum_type = /datum/antagonist/cult /datum/atom_hud/alternate_appearance/basic/blessed_aware diff --git a/code/game/communications.dm b/code/game/communications.dm index 6d26a9779937d..aba409b558710 100644 --- a/code/game/communications.dm +++ b/code/game/communications.dm @@ -104,6 +104,7 @@ GLOBAL_LIST_INIT(radiochannels, list( RADIO_CHANNEL_SUPPLY = FREQ_SUPPLY, RADIO_CHANNEL_SERVICE = FREQ_SERVICE, RADIO_CHANNEL_AI_PRIVATE = FREQ_AI_PRIVATE, + RADIO_CHANNEL_ENTERTAINMENT = FREQ_ENTERTAINMENT, RADIO_CHANNEL_CTF_RED = FREQ_CTF_RED, RADIO_CHANNEL_CTF_BLUE = FREQ_CTF_BLUE, RADIO_CHANNEL_CTF_GREEN = FREQ_CTF_GREEN, @@ -123,6 +124,7 @@ GLOBAL_LIST_INIT(reverseradiochannels, list( "[FREQ_SUPPLY]" = RADIO_CHANNEL_SUPPLY, "[FREQ_SERVICE]" = RADIO_CHANNEL_SERVICE, "[FREQ_AI_PRIVATE]" = RADIO_CHANNEL_AI_PRIVATE, + "[FREQ_ENTERTAINMENT]" = RADIO_CHANNEL_ENTERTAINMENT, "[FREQ_CTF_RED]" = RADIO_CHANNEL_CTF_RED, "[FREQ_CTF_BLUE]" = RADIO_CHANNEL_CTF_BLUE, "[FREQ_CTF_GREEN]" = RADIO_CHANNEL_CTF_GREEN, @@ -141,10 +143,11 @@ GLOBAL_LIST_INIT(radiocolors, list( RADIO_CHANNEL_SUPPLY = "#a8732b", RADIO_CHANNEL_SERVICE = "#6eaa2c", RADIO_CHANNEL_AI_PRIVATE = "#ff00ff", + RADIO_CHANNEL_ENTERTAINMENT = "#00ff99", RADIO_CHANNEL_CTF_RED = "#ff0000", RADIO_CHANNEL_CTF_BLUE = "#0000ff", RADIO_CHANNEL_CTF_GREEN = "#00ff00", - RADIO_CHANNEL_CTF_YELLOW = "#d1ba22" + RADIO_CHANNEL_CTF_YELLOW = "#d1ba22", )) /datum/radio_frequency diff --git a/code/game/machinery/big_manipulator.dm b/code/game/machinery/big_manipulator.dm new file mode 100644 index 0000000000000..8d2bde3e145ae --- /dev/null +++ b/code/game/machinery/big_manipulator.dm @@ -0,0 +1,282 @@ +/// Manipulator Core. Main part of the mechanism that carries out the entire process. +/obj/machinery/big_manipulator + name = "Big Manipulator" + desc = "Take and drop objects. Innovation..." + icon = 'icons/obj/machines/big_manipulator_parts/big_manipulator_core.dmi' + icon_state = "core" + density = TRUE + circuit = /obj/item/circuitboard/machine/big_manipulator + greyscale_colors = "#d8ce13" + greyscale_config = /datum/greyscale_config/big_manipulator + /// How many time manipulator need to take and drop item. + var/working_speed = 2 SECONDS + /// Using high tier manipulators speeds up big manipulator and requires more energy. + var/power_use_lvl = 0.2 + /// When manipulator already working with item inside he don't take any new items. + var/on_work = FALSE + /// Activate mechanism. + var/on = FALSE + /// Dir to get turf where we take items. + var/take_here = NORTH + /// Dir to get turf where we drop items. + var/drop_here = SOUTH + /// Turf where we take items. + var/turf/take_turf + /// Turf where we drop items. + var/turf/drop_turf + /// Obj inside manipulator. + var/datum/weakref/containment_obj + /// Other manipulator component. + var/obj/effect/manipulator_hand + +/obj/machinery/big_manipulator/Initialize(mapload) + . = ..() + take_and_drop_turfs_check() + create_manipulator_hand() + RegisterSignal(manipulator_hand, COMSIG_QDELETING, PROC_REF(on_hand_qdel)) + manipulator_lvl() + if(on) + press_on(pressed_by = null) + +/obj/machinery/big_manipulator/examine(mob/user) + . = ..() + . += "You can change direction with alternative wrench usage." + +/obj/machinery/big_manipulator/Destroy(force) + . = ..() + qdel(manipulator_hand) + if(isnull(containment_obj)) + return + var/obj/obj_resolve = containment_obj?.resolve() + obj_resolve?.forceMove(get_turf(obj_resolve)) + +/obj/machinery/big_manipulator/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) + . = ..() + take_and_drop_turfs_check() + if(isnull(get_turf(src))) + qdel(manipulator_hand) + return + if(!manipulator_hand) + create_manipulator_hand() + +/obj/machinery/big_manipulator/wrench_act(mob/living/user, obj/item/tool) + . = ..() + default_unfasten_wrench(user, tool, time = 1 SECONDS) + return ITEM_INTERACT_SUCCESS + +/obj/machinery/big_manipulator/wrench_act_secondary(mob/living/user, obj/item/tool) + . = ..() + if(on_work || on) + to_chat(user, span_warning("[src] is activated!")) + return ITEM_INTERACT_BLOCKING + rotate_big_hand() + playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) + return ITEM_INTERACT_SUCCESS + +/obj/machinery/big_manipulator/can_be_unfasten_wrench(mob/user, silent) + if(on_work || on) + to_chat(user, span_warning("[src] is activated!")) + return FAILED_UNFASTEN + return ..() + +/obj/machinery/big_manipulator/default_unfasten_wrench(mob/user, obj/item/wrench, time) + . = ..() + if(. == SUCCESSFUL_UNFASTEN) + take_and_drop_turfs_check() + +/obj/machinery/big_manipulator/screwdriver_act(mob/living/user, obj/item/tool) + if(default_deconstruction_screwdriver(user, icon_state, icon_state, tool)) + return ITEM_INTERACT_SUCCESS + return ITEM_INTERACT_BLOCKING + +/obj/machinery/big_manipulator/crowbar_act(mob/living/user, obj/item/tool) + . = ..() + if(default_deconstruction_crowbar(tool)) + return ITEM_INTERACT_SUCCESS + return ITEM_INTERACT_BLOCKING + +/obj/machinery/big_manipulator/RefreshParts() + . = ..() + + manipulator_lvl() + +/// Creat manipulator hand effect on manipulator core. +/obj/machinery/big_manipulator/proc/create_manipulator_hand() + manipulator_hand = new/obj/effect/big_manipulator_hand(src) + manipulator_hand.dir = take_here + vis_contents += manipulator_hand + +/// Check servo tier and change manipulator speed, power_use and colour. +/obj/machinery/big_manipulator/proc/manipulator_lvl() + var/datum/stock_part/servo/locate_servo = locate() in component_parts + if(!locate_servo) + return + switch(locate_servo.tier) + if(-INFINITY to 1) + working_speed = 2 SECONDS + power_use_lvl = 0.2 + set_greyscale(COLOR_YELLOW) + manipulator_hand?.set_greyscale(COLOR_YELLOW) + if(2) + working_speed = 1.4 SECONDS + power_use_lvl = 0.4 + set_greyscale(COLOR_ORANGE) + manipulator_hand?.set_greyscale(COLOR_ORANGE) + if(3) + working_speed = 0.8 SECONDS + power_use_lvl = 0.6 + set_greyscale(COLOR_RED) + manipulator_hand?.set_greyscale(COLOR_RED) + if(4 to INFINITY) + working_speed = 0.2 SECONDS + power_use_lvl = 0.8 + set_greyscale(COLOR_PURPLE) + manipulator_hand?.set_greyscale(COLOR_PURPLE) + + active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * power_use_lvl + +/// Changing take and drop turf tiles when we anchore manipulator or if manipulator not in turf. +/obj/machinery/big_manipulator/proc/take_and_drop_turfs_check() + if(anchored && isturf(src.loc)) + take_turf = get_step(src, take_here) + drop_turf = get_step(src, drop_here) + else + take_turf = null + drop_turf = null + +/// Changing take and drop turf dirs and also changing manipulator hand sprite dir. +/obj/machinery/big_manipulator/proc/rotate_big_hand() + switch(take_here) + if(NORTH) + take_here = EAST + drop_here = WEST + if(EAST) + take_here = SOUTH + drop_here = NORTH + if(SOUTH) + take_here = WEST + drop_here = EAST + if(WEST) + take_here = NORTH + drop_here = SOUTH + manipulator_hand.dir = take_here + take_and_drop_turfs_check() + +/// Deliting hand will destroy our manipulator core. +/obj/machinery/big_manipulator/proc/on_hand_qdel() + SIGNAL_HANDLER + + deconstruct(TRUE) + +/// Pre take and drop proc from [take and drop procs loop]: +/// Check if we can start take and drop loop +/obj/machinery/big_manipulator/proc/is_work_check() + if(isclosedturf(drop_turf)) + on = !on + say("Output blocked") + return FALSE + for(var/obj/item/take_item in take_turf.contents) + try_take_thing(take_turf, take_item) + break + + return TRUE + +/// First take and drop proc from [take and drop procs loop]: +/// Check if we can take item from take_turf to work with him. This proc also calling from ATOM_ENTERED signal. +/obj/machinery/big_manipulator/proc/try_take_thing(datum/source, atom/movable/target) + SIGNAL_HANDLER + + if(!on) + return + if(!anchored) + return + if(QDELETED(source) || QDELETED(target)) + return + if(!isturf(target.loc)) + return + if(on_work) + return + if(!use_energy(active_power_usage, force = FALSE)) + on = FALSE + say("Not enough energy!") + return + if(isitem(target)) + start_work(target) + +/// Second take and drop proc from [take and drop procs loop]: +/// Taking our item and start manipulator hand rotate animation. +/obj/machinery/big_manipulator/proc/start_work(atom/movable/target) + target.forceMove(src) + containment_obj = WEAKREF(target) + on_work = TRUE + do_rotate_animation(1) + addtimer(CALLBACK(src, PROC_REF(drop_thing), target), working_speed) + +/// Third take and drop proc from [take and drop procs loop]: +/// Drop our item and start manipulator hand backward animation. +/obj/machinery/big_manipulator/proc/drop_thing(atom/movable/target) + target.forceMove(drop_turf) + do_rotate_animation(0) + addtimer(CALLBACK(src, PROC_REF(end_work)), working_speed) + +/// Fourth and last take and drop proc from [take and drop procs loop]: +/// Finishes work and begins to look for a new item for [take and drop procs loop]. +/obj/machinery/big_manipulator/proc/end_work() + on_work = FALSE + is_work_check() + +/// Rotates manipulator hand 90 degrees. +/obj/machinery/big_manipulator/proc/do_rotate_animation(backward) + animate(manipulator_hand, transform = matrix(90, MATRIX_ROTATE), working_speed*0.5) + addtimer(CALLBACK(src, PROC_REF(finish_rotate_animation), backward), working_speed*0.5) + +/// Rotates manipulator hand from 90 degrees to 180 or 0 if backward. +/obj/machinery/big_manipulator/proc/finish_rotate_animation(backward) + animate(manipulator_hand, transform = matrix(180 * backward, MATRIX_ROTATE), working_speed*0.5) + +/// Proc call when we press on/off button +/obj/machinery/big_manipulator/proc/press_on(pressed_by) + if(pressed_by) + on = !on + if(!is_work_check()) + return + if(on) + RegisterSignal(take_turf, COMSIG_ATOM_ENTERED, PROC_REF(try_take_thing)) + else + UnregisterSignal(take_turf, COMSIG_ATOM_ENTERED) + +/obj/machinery/big_manipulator/ui_interact(mob/user, datum/tgui/ui) + if(!anchored) + to_chat(user, span_warning("[src] isn't attached to the ground!")) + ui?.close() + return + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "BigManipulator") + ui.open() + +/obj/machinery/big_manipulator/ui_data(mob/user) + var/list/data = list() + data["active"] = on + return data + +/obj/machinery/big_manipulator/ui_act(action, params, datum/tgui/ui) + . = ..() + if(.) + return + switch(action) + if("on") + press_on(pressed_by = TRUE) + return TRUE + +/// Manipulator hand. Effect we animate to show that the manipulator is working and moving something. +/obj/effect/big_manipulator_hand + name = "Manipulator claw" + desc = "Take and drop objects. Innovation..." + icon = 'icons/obj/machines/big_manipulator_parts/big_manipulator_hand.dmi' + icon_state = "hand" + layer = LOW_ITEM_LAYER + anchored = TRUE + greyscale_config = /datum/greyscale_config/manipulator_hand + pixel_x = -32 + pixel_y = -32 diff --git a/code/game/machinery/computer/_computer.dm b/code/game/machinery/computer/_computer.dm index 3292cbf977b5f..6e1009def324f 100644 --- a/code/game/machinery/computer/_computer.dm +++ b/code/game/machinery/computer/_computer.dm @@ -135,6 +135,12 @@ . = ..() update_use_power(ACTIVE_POWER_USE) +/obj/machinery/computer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + SHOULD_CALL_PARENT(TRUE) + . = ..() + if(!issilicon(ui.user)) + playsound(src, SFX_KEYBOARD_CLICKS, 10, TRUE, FALSE) + /obj/machinery/computer/ui_close(mob/user) SHOULD_CALL_PARENT(TRUE) . = ..() diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index b5bb04fac35e1..870ff2d20183f 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -116,7 +116,6 @@ if(action == "switch_camera") var/obj/machinery/camera/selected_camera = locate(params["camera"]) in GLOB.cameranet.cameras active_camera = selected_camera - playsound(src, SFX_TERMINAL_TYPE, 25, FALSE) if(isnull(active_camera)) return TRUE diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 8fb1e71f05ed7..21dba256733d8 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -361,7 +361,6 @@ if (state == STATE_BUYING_SHUTTLE && can_buy_shuttles(usr) != TRUE) return set_state(usr, params["state"]) - playsound(src, SFX_TERMINAL_TYPE, 50, FALSE) if ("setStatusMessage") if (!authenticated(usr)) return @@ -369,7 +368,6 @@ var/line_two = reject_bad_text(params["lowerText"] || "", MAX_STATUS_LINE_LENGTH) post_status("message", line_one, line_two) last_status_display = list(line_one, line_two) - playsound(src, SFX_TERMINAL_TYPE, 50, FALSE) if ("setStatusPicture") if (!authenticated(usr)) return @@ -384,7 +382,6 @@ else post_status("alert", picture) - playsound(src, SFX_TERMINAL_TYPE, 50, FALSE) if ("toggleAuthentication") // Log out if we're logged in if (authorize_name) diff --git a/code/game/machinery/computer/orders/order_computer/mining_order.dm b/code/game/machinery/computer/orders/order_computer/mining_order.dm index 7e7eabcc1bfd5..fda571157c434 100644 --- a/code/game/machinery/computer/orders/order_computer/mining_order.dm +++ b/code/game/machinery/computer/orders/order_computer/mining_order.dm @@ -121,7 +121,7 @@ /obj/machinery/computer/order_console/mining/proc/check_menu(obj/item/mining_voucher/voucher, mob/living/redeemer) if(!istype(redeemer)) return FALSE - if(redeemer.incapacitated()) + if(redeemer.incapacitated) return FALSE if(QDELETED(voucher)) return FALSE diff --git a/code/game/machinery/computer/records/records.dm b/code/game/machinery/computer/records/records.dm index e8d8beef854dd..d53895300438d 100644 --- a/code/game/machinery/computer/records/records.dm +++ b/code/game/machinery/computer/records/records.dm @@ -100,7 +100,6 @@ if(!target) return FALSE - playsound(src, SFX_TERMINAL_TYPE, 50, TRUE) update_preview(user, params["assigned_view"], target) return TRUE diff --git a/code/game/machinery/computer/records/security.dm b/code/game/machinery/computer/records/security.dm index dac62612a4c74..bdfa996dad68f 100644 --- a/code/game/machinery/computer/records/security.dm +++ b/code/game/machinery/computer/records/security.dm @@ -102,6 +102,7 @@ paid = warrant.paid, time = warrant.time, valid = warrant.valid, + voider = warrant.voider, )) var/list/crimes = list() @@ -113,6 +114,7 @@ name = crime.name, time = crime.time, valid = crime.valid, + voider = crime.voider, )) records += list(list( @@ -250,8 +252,8 @@ editing_crime.name = new_name return TRUE - if(params["details"] && length(params["description"]) > 2 && params["name"] != editing_crime.name) - var/new_details = strip_html_full(params["details"], MAX_MESSAGE_LEN) + if(params["description"] && length(params["description"]) > 2 && params["name"] != editing_crime.name) + var/new_details = strip_html_full(params["description"], MAX_MESSAGE_LEN) investigate_log("[user] edited crime \"[editing_crime.name]\" for target: \"[target.name]\", changing the details to: \"[new_details]\" from: \"[editing_crime.details]\".", INVESTIGATE_RECORDS) editing_crime.details = new_details return TRUE @@ -269,6 +271,9 @@ /// Only qualified personnel can edit records. /obj/machinery/computer/records/security/proc/has_armory_access(mob/user) + if (HAS_SILICON_ACCESS(user)) + return TRUE + if(!isliving(user)) return FALSE var/mob/living/player = user @@ -284,16 +289,22 @@ /// Voids crimes, or sets someone to discharged if they have none left. /obj/machinery/computer/records/security/proc/invalidate_crime(mob/user, datum/record/crew/target, list/params) - if(!has_armory_access(user)) - return FALSE var/datum/crime/to_void = locate(params["crime_ref"]) in target.crimes + var/acquitted = TRUE if(!to_void) + to_void = locate(params["crime_ref"]) in target.citations + // No need to change status after invalidatation of citation + acquitted = FALSE + if(!to_void) + return FALSE + + if(user != to_void.author && !has_armory_access(user)) return FALSE to_void.valid = FALSE + to_void.voider = user investigate_log("[key_name(user)] has invalidated [target.name]'s crime: [to_void.name]", INVESTIGATE_RECORDS) - var/acquitted = TRUE for(var/datum/crime/incident in target.crimes) if(!incident.valid) continue diff --git a/code/game/machinery/computer/telescreen.dm b/code/game/machinery/computer/telescreen.dm index deca4ec8245e1..5a1c2d720e3bf 100644 --- a/code/game/machinery/computer/telescreen.dm +++ b/code/game/machinery/computer/telescreen.dm @@ -40,6 +40,8 @@ circuit = null interaction_flags_atom = INTERACT_ATOM_UI_INTERACT | INTERACT_ATOM_NO_FINGERPRINT_INTERACT | INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND | INTERACT_MACHINE_REQUIRES_SIGHT frame_type = /obj/item/wallframe/telescreen/entertainment + /// Virtual radio inside of the entertainment monitor to broadcast audio + var/obj/item/radio/entertainment/speakers/speakers var/icon_state_off = "entertainment_blank" var/icon_state_on = "entertainment" @@ -54,9 +56,18 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/security/telescreen/entertai /obj/machinery/computer/security/telescreen/entertainment/Initialize(mapload) . = ..() RegisterSignal(src, COMSIG_CLICK, PROC_REF(BigClick)) - find_and_hang_on_wall() + update_appearance() + speakers = new(src) -// Bypass clickchain to allow humans to use the telescreen from a distance +/obj/machinery/computer/security/telescreen/entertainment/Destroy() + . = ..() + QDEL_NULL(speakers) + +/obj/machinery/computer/security/telescreen/on_set_machine_stat(old_value) + . = ..() + update_appearance() + +/// Bypass clickchain to allow humans to use the telescreen from a distance /obj/machinery/computer/security/telescreen/entertainment/proc/BigClick() SIGNAL_HANDLER @@ -66,7 +77,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/security/telescreen/entertai INVOKE_ASYNC(src, TYPE_PROC_REF(/atom, interact), usr) -///Sets the monitor's icon to the selected state, and says an announcement +/// Sets the monitor's icon to the selected state, and says an announcement /obj/machinery/computer/security/telescreen/entertainment/proc/notify(on, announcement) if(on && icon_state == icon_state_off) icon_state = icon_state_on diff --git a/code/game/machinery/computer/warrant.dm b/code/game/machinery/computer/warrant.dm index 1e3557f76f046..3b73a8b75bfea 100644 --- a/code/game/machinery/computer/warrant.dm +++ b/code/game/machinery/computer/warrant.dm @@ -133,6 +133,7 @@ return TRUE warrant.alert_owner(user, src, target.name, "One of your outstanding warrants has been completely paid.") + warrant.valid = FALSE return TRUE /// Finishes printing, resets the printer. diff --git a/code/game/machinery/dish_drive.dm b/code/game/machinery/dish_drive.dm index b386ebb376f57..74ca492657b6e 100644 --- a/code/game/machinery/dish_drive.dm +++ b/code/game/machinery/dish_drive.dm @@ -12,7 +12,6 @@ interaction_flags_click = ALLOW_SILICON_REACH /// List of dishes the drive can hold var/static/list/collectable_items = list( - /obj/item/trash/waffles, /obj/item/broken_bottle, /obj/item/kitchen/fork, /obj/item/plate, @@ -24,7 +23,6 @@ ) /// List of items the drive detects as trash var/static/list/disposable_items = list( - /obj/item/trash/waffles, /obj/item/broken_bottle, /obj/item/plate_shard, /obj/item/shard, diff --git a/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm b/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm index aa3e9441d84a0..10fcae90a9591 100644 --- a/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm @@ -58,11 +58,12 @@ var/datum/species/rec_species = human_receiver.dna.species rec_species.update_no_equip_flags(tongue_owner, rec_species.no_equip_flags | ITEM_SLOT_MASK) -/obj/item/organ/internal/tongue/carp/on_bodypart_insert(obj/item/bodypart/limb) +/obj/item/organ/internal/tongue/carp/on_bodypart_insert(obj/item/bodypart/head) . = ..() - limb.unarmed_damage_low = 10 - limb.unarmed_damage_high = 15 - limb.unarmed_effectiveness = 15 + head.unarmed_damage_low = 10 + head.unarmed_damage_high = 15 + head.unarmed_effectiveness = 15 + head.unarmed_attack_effect = ATTACK_EFFECT_BITE /obj/item/organ/internal/tongue/carp/on_mob_remove(mob/living/carbon/tongue_owner) . = ..() @@ -76,10 +77,10 @@ /obj/item/organ/internal/tongue/carp/on_bodypart_remove(obj/item/bodypart/head) . = ..() - head.unarmed_damage_low = initial(head.unarmed_damage_low) head.unarmed_damage_high = initial(head.unarmed_damage_high) head.unarmed_effectiveness = initial(head.unarmed_effectiveness) + head.unarmed_attack_effect = initial(head.unarmed_attack_effect) /obj/item/organ/internal/tongue/carp/on_life(seconds_per_tick, times_fired) . = ..() diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 601ad67a6e9a4..335389c40ce42 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -605,6 +605,24 @@ /obj/machinery/door/morgue icon = 'icons/obj/doors/doormorgue.dmi' +/obj/machinery/door/morgue/Initialize(mapload) + . = ..() + AddComponent(/datum/component/redirect_attack_hand_from_turf) + +/obj/machinery/door/morgue/update_icon_state() + . = ..() + if(animation && animation != "deny") + icon_state = animation + else + icon_state = density ? "closed" : "open_top" + +/obj/machinery/door/morgue/update_overlays() + . = ..() + if(!density) + // If we're open we layer the bit below us "above" any mobs so they can walk through + . += mutable_appearance(icon, "open_bottom", ABOVE_MOB_LAYER, appearance_flags = KEEP_APART) + . += emissive_blocker(icon, "open_bottom", src, ABOVE_MOB_LAYER) + /obj/machinery/door/get_dumping_location() return null diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index cbb7eede250b9..f8325de36e7fc 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -168,7 +168,7 @@ Possible to do for anyone motivated enough: /obj/machinery/holopad/tutorial/attack_hand(mob/user, list/modifiers) if(!istype(user)) return - if(user.incapacitated() || !is_operational) + if(user.incapacitated || !is_operational) return if(replay_mode) replay_stop() @@ -675,7 +675,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ if(!isliving(owner)) return TRUE var/mob/living/user = owner - if(user.incapacitated() || !user.client) + if(user.incapacitated || !user.client) return FALSE return TRUE diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm index 4ac2a177e76bc..aa49f2b1e3c49 100644 --- a/code/game/machinery/iv_drip.dm +++ b/code/game/machinery/iv_drip.dm @@ -322,7 +322,7 @@ return if(!usr.can_perform_action(src)) return - if(usr.incapacitated()) + if(usr.incapacitated) return if(reagent_container) if(attached) @@ -340,7 +340,7 @@ if(!isliving(usr)) to_chat(usr, span_warning("You can't do that!")) return - if(!usr.can_perform_action(src) || usr.incapacitated()) + if(!usr.can_perform_action(src) || usr.incapacitated) return if(inject_only) mode = IV_INJECTING diff --git a/code/game/machinery/newscaster/newspaper.dm b/code/game/machinery/newscaster/newspaper.dm index 2bd8187b9f8c0..c381f2f506304 100644 --- a/code/game/machinery/newscaster/newspaper.dm +++ b/code/game/machinery/newscaster/newspaper.dm @@ -132,6 +132,15 @@ /// Called when someone tries to figure out what our identity is, but they can't see it because of the newspaper /obj/item/newspaper/proc/holder_checked_name(mob/living/carbon/human/source, list/identity) SIGNAL_HANDLER + + var/newspaper_obscurity_priority = 100 // how powerful obscuring your appearance with a newspaper is + if(identity[VISIBLE_NAME_FORCED]) + if(identity[VISIBLE_NAME_FORCED] > newspaper_obscurity_priority) // the other set forced name is forcier than breaking news + return + else if(identity[VISIBLE_NAME_FORCED] == newspaper_obscurity_priority) + stack_trace("A name-setting signal operation ([identity[VISIBLE_NAME_FACE]]) has a priority collision with [src].") + else + identity[VISIBLE_NAME_FORCED] = newspaper_obscurity_priority identity[VISIBLE_NAME_FACE] = "" identity[VISIBLE_NAME_ID] = "" diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm index ef18dc6b068ae..39d6fe7d2ea0c 100644 --- a/code/game/machinery/pipe/construction.dm +++ b/code/game/machinery/pipe/construction.dm @@ -175,7 +175,7 @@ Buildable meters set name = "Invert Pipe" set src in view(1) - if ( usr.incapacitated() ) + if ( usr.incapacitated ) return do_a_flip() diff --git a/code/game/machinery/pipe/pipe_dispenser.dm b/code/game/machinery/pipe/pipe_dispenser.dm index eb5b499bce79e..022db936c74dc 100644 --- a/code/game/machinery/pipe/pipe_dispenser.dm +++ b/code/game/machinery/pipe/pipe_dispenser.dm @@ -187,6 +187,9 @@ //Allow you to drag-drop disposal pipes and transit tubes into it /obj/machinery/pipedispenser/disposal/mouse_drop_receive(obj/structure/pipe, mob/user, params) + if(user.incapacitated) + return + if (!istype(pipe, /obj/structure/disposalconstruct) && !istype(pipe, /obj/structure/c_transit_tube) && !istype(pipe, /obj/structure/c_transit_tube_pod)) return diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index c9694730a3f8a..c266ee85cc619 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -143,7 +143,7 @@ DEFINE_BITFIELD(turret_flags, list( /obj/machinery/porta_turret/proc/toggle_on(turn_on = TRUE) if(on == turn_on) return - if(on && !COOLDOWN_FINISHED(src, disabled_time)) + if(turn_on && !COOLDOWN_FINISHED(src, disabled_time)) return on = turn_on check_should_process() diff --git a/code/game/machinery/portagrav.dm b/code/game/machinery/portagrav.dm new file mode 100644 index 0000000000000..c970fa5f8f1c6 --- /dev/null +++ b/code/game/machinery/portagrav.dm @@ -0,0 +1,268 @@ +/obj/machinery/power/portagrav + anchored = FALSE + density = TRUE + interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON + icon = 'icons/obj/machines/gravity_generator.dmi' + icon_state = "portagrav" + base_icon_state = "portagrav" + name = "Portable Gravity Unit" + desc = "Generates gravity around itself. Powered by wire or cell. Must be anchored before use." + max_integrity = 250 + circuit = /obj/item/circuitboard/machine/portagrav + armor_type = /datum/armor/portable_gravity + interaction_flags_click = ALLOW_SILICON_REACH + //We don't use area power + use_power = NO_POWER_USE + ///The cell we spawn with + var/obj/item/stock_parts/power_store/cell/cell = /obj/item/stock_parts/power_store/cell/high + ///Is the machine on? + var/on = FALSE + /// do we use power from wire instead + var/wire_mode = FALSE + /// our gravity field + var/datum/proximity_monitor/advanced/gravity/subtle_effect/gravity_field + /// strength of our gravity + var/grav_strength = STANDARD_GRAVITY + /// gravity range + var/range = 4 + /// max gravity range + var/max_range = 6 + /// draw per range + var/draw_per_range = BASE_MACHINE_ACTIVE_CONSUMPTION + +/datum/armor/portable_gravity + fire = 100 + melee = 10 + bomb = 40 + +/obj/machinery/power/portagrav/Initialize(mapload) + . = ..() + if(ispath(cell)) + cell = new cell(src) + if(anchored && wire_mode) + connect_to_network() + + AddElement( \ + /datum/element/contextual_screentip_bare_hands, \ + rmb_text = "Toggle power", \ + ) + + var/static/list/tool_behaviors = list( + TOOL_WRENCH = list( + SCREENTIP_CONTEXT_LMB = "Anchor", + ), + ) + AddElement(/datum/element/contextual_screentip_tools, tool_behaviors) + +/obj/machinery/power/portagrav/Destroy() + . = ..() + cell = null + +/obj/machinery/power/portagrav/update_overlays() + . = ..() + if(anchored) + . += "portagrav_anchors" + if(on) + . += "portagrav_o" + . += "activated" + +/obj/machinery/power/portagrav/examine(mob/user) + . = ..() + . += "It is [on ? "on" : "off"]." + . += "The charge meter reads: [!isnull(cell) ? "[round(cell.percent(), 1)]%" : "NO CELL"]." + . += "It is[anchored ? "" : " not"] anchored." + if(in_range(user, src) || isobserver(user)) + . += span_notice("Right-click to toggle [on ? "off" : "on"].") + +/obj/machinery/power/portagrav/RefreshParts() + . = ..() + var/power_usage = initial(draw_per_range) + for(var/datum/stock_part/micro_laser/laser in component_parts) + power_usage -= BASE_MACHINE_ACTIVE_CONSUMPTION / 10 * (laser.tier - 1) + draw_per_range = power_usage + var/new_range = 4 + for(var/datum/stock_part/capacitor/capacitor in component_parts) + new_range += capacitor.tier + max_range = new_range + update_field() + +/obj/machinery/power/portagrav/screwdriver_act(mob/living/user, obj/item/tool) + . = NONE + if(default_deconstruction_screwdriver(user, "[base_icon_state]_o", base_icon_state, tool)) + return ITEM_INTERACT_SUCCESS + +/obj/machinery/power/portagrav/crowbar_act(mob/living/user, obj/item/tool) + . = NONE + if(default_deconstruction_crowbar(tool)) + return ITEM_INTERACT_SUCCESS + +/obj/machinery/power/portagrav/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + . = NONE + if(!istype(tool, /obj/item/stock_parts/power_store/cell)) + return + if(!panel_open) + balloon_alert(user, "must open panel!") + return ITEM_INTERACT_BLOCKING + if(cell) + balloon_alert(user, "already has a cell!") + return ITEM_INTERACT_BLOCKING + if(!user.transferItemToLoc(tool, src)) + return ITEM_INTERACT_FAILURE + cell = tool + return ITEM_INTERACT_SUCCESS + +/obj/machinery/power/portagrav/should_have_node() + return anchored + +/obj/machinery/power/portagrav/connect_to_network() + if(!anchored) + return FALSE + . = ..() + +/obj/machinery/power/portagrav/wrench_act(mob/living/user, obj/item/tool) + . = ..() + if(on) + balloon_alert(user, "turn off first!") + return + default_unfasten_wrench(user, tool) + if(anchored && wire_mode) + connect_to_network() + else + disconnect_from_network() + update_appearance() + return ITEM_INTERACT_SUCCESS + +/obj/machinery/power/portagrav/get_cell() + return cell + +/obj/machinery/power/portagrav/attack_hand(mob/living/carbon/user, list/modifiers) + . = ..() + if(!panel_open || isnull(cell) || !istype(user) || user.combat_mode) + return + if(user.put_in_hands(cell)) + cell = null + +/obj/machinery/power/portagrav/attack_hand_secondary(mob/user, list/modifiers) + if(!can_interact(user)) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + toggle_on(user) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/machinery/power/portagrav/emag_act(mob/user, obj/item/card/emag/emag_card) + if(obj_flags & EMAGGED) + return FALSE + obj_flags |= EMAGGED + visible_message(span_warning("Sparks fly out of [src]!")) + if(user) + balloon_alert(user, "unsafe gravity unlocked") + user.log_message("emagged [src].", LOG_ATTACK) + playsound(src, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + return TRUE + +/obj/machinery/power/portagrav/proc/toggle_on(mob/user) + if(on) + turn_off(user) + else + turn_on(user) + +/obj/machinery/power/portagrav/proc/turn_on(mob/user) + if(!anchored) + if(!isnull(user)) + balloon_alert(user, "not anchored!") + return FALSE + if((!wire_mode && cell?.charge < draw_per_range * range) || (wire_mode && surplus() < draw_per_range * range)) + if(!isnull(user)) + balloon_alert(user, "not enough power!") + return FALSE + if(!isnull(user)) + balloon_alert(user, "turned on") + on = TRUE + START_PROCESSING(SSmachines, src) + gravity_field = new(src, range = src.range, gravity = grav_strength) + update_appearance() + +/obj/machinery/power/portagrav/proc/turn_off(mob/user) + on = FALSE + if(!isnull(user)) + balloon_alert(user, "turned off") + STOP_PROCESSING(SSmachines, src) + QDEL_NULL(gravity_field) + update_appearance() + +/obj/machinery/power/portagrav/process(seconds_per_tick) + if(!on || !anchored) + return PROCESS_KILL + if(wire_mode) + if(powernet && surplus() >= draw_per_range * range) + add_load(draw_per_range * range) + else + turn_off() + else + if(!cell?.use(draw_per_range * range)) + turn_off() + +/obj/machinery/power/portagrav/proc/update_field() + if(isnull(gravity_field)) + return + gravity_field.set_range(range) + gravity_field.gravity_value = grav_strength + gravity_field.recalculate_field(full_recalc = TRUE) + +/obj/machinery/power/portagrav/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Portagrav", name) + ui.open() + +/obj/machinery/power/portagrav/ui_data(mob/user) + . = list() + if(!isnull(cell)) + .["percentage"] = (cell.charge / cell.maxcharge) * 100 + .["gravity"] = grav_strength + .["range"] = range + .["maxrange"] = max_range + .["on"] = on + .["wiremode"] = wire_mode + .["draw"] = display_power(draw_per_range * range) + +/obj/machinery/power/portagrav/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + playsound(src, 'sound/machines/terminal_button07.ogg', 45, TRUE) + switch(action) + if("adjust_grav") + var/adjustment = text2num(params["adjustment"]) + if(isnull(adjustment)) + return + var/bonus = (obj_flags & EMAGGED) ? 2 : 0 + // REPLACE 0 with NEGATIVE_GRAVITY ONCE NEGATIVE GRAVITY IS SOMETHING ACTUALLY FUNCTIONAL + var/result = clamp(grav_strength + adjustment, 0, GRAVITY_DAMAGE_THRESHOLD - 1 + bonus) + if(result == grav_strength) + return + grav_strength = result + update_field() + return TRUE + if("toggle_power") + toggle_on(usr) + return TRUE + if("toggle_wire") + wire_mode = !wire_mode + if(wire_mode && anchored) + connect_to_network() + else + disconnect_from_network() + return TRUE + if("adjust_range") + var/adjustment = text2num(params["adjustment"]) + if(isnull(adjustment)) + return + var/result = clamp(range + adjustment, 0, max_range) + if(result == range) + return + range = result + update_field() + return TRUE + +/obj/machinery/power/portagrav/anchored + anchored = TRUE diff --git a/code/game/machinery/sleepers.dm b/code/game/machinery/sleepers.dm index 63291035e784f..b237436f3044c 100644 --- a/code/game/machinery/sleepers.dm +++ b/code/game/machinery/sleepers.dm @@ -300,17 +300,21 @@ * Can be controlled from the inside and can be deconstructed. */ /obj/machinery/sleeper/syndie + name = "syndicate sleeper" icon_state = "sleeper_s" base_icon_state = "sleeper_s" controls_inside = TRUE deconstructable = TRUE + circuit = /obj/item/circuitboard/machine/sleeper/syndie ///Fully upgraded variant, the circuit using tier 4 parts. /obj/machinery/sleeper/syndie/fullupgrade + name = "upgraded syndicate sleeper" circuit = /obj/item/circuitboard/machine/sleeper/fullupgrade ///Fully upgraded, not deconstructable, while using the normal sprite. /obj/machinery/sleeper/syndie/fullupgrade/nt + name = "\improper Nanotrasen sleeper" icon_state = "sleeper" base_icon_state = "sleeper" deconstructable = FALSE diff --git a/code/game/machinery/stasis.dm b/code/game/machinery/stasis.dm index 9ef3d8e3a99a9..bf33530b93e3e 100644 --- a/code/game/machinery/stasis.dm +++ b/code/game/machinery/stasis.dm @@ -9,6 +9,7 @@ obj_flags = BLOCKS_CONSTRUCTION can_buckle = TRUE buckle_lying = 90 + buckle_dir = SOUTH circuit = /obj/item/circuitboard/machine/stasis fair_market_price = 10 payment_department = ACCOUNT_MED @@ -22,6 +23,7 @@ /obj/machinery/stasis/Initialize(mapload) . = ..() AddElement(/datum/element/elevation, pixel_shift = 6) + update_buckle_vars(dir) /obj/machinery/stasis/examine(mob/user) . = ..() @@ -57,6 +59,13 @@ thaw_them(L) return ..() +/obj/machinery/stasis/setDir(newdir) + . = ..() + update_buckle_vars(newdir) + +/obj/machinery/stasis/proc/update_buckle_vars(newdir) + buckle_lying = newdir & NORTHEAST ? 270 : 90 + /obj/machinery/stasis/proc/stasis_running() return stasis_enabled && is_operational diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm index 3a7cc849acd30..0ac1f7ee44df8 100644 --- a/code/game/machinery/syndicatebomb.dm +++ b/code/game/machinery/syndicatebomb.dm @@ -621,7 +621,7 @@ balloon_alert(user, "set to [chosen_theme?.name || DIMENSION_CHOICE_RANDOM]") /obj/item/bombcore/dimensional/proc/check_menu(mob/user) - if(!user.is_holding(src) || user.incapacitated()) + if(!user.is_holding(src) || user.incapacitated) return FALSE return TRUE diff --git a/code/game/machinery/telecomms/broadcasting.dm b/code/game/machinery/telecomms/broadcasting.dm index 2c31dcbd98955..06d390e5f2e27 100644 --- a/code/game/machinery/telecomms/broadcasting.dm +++ b/code/game/machinery/telecomms/broadcasting.dm @@ -155,7 +155,7 @@ if (TRANSMISSION_SUPERSPACE) // Only radios which are independent for(var/obj/item/radio/independent_radio in GLOB.all_radios["[frequency]"]) - if(independent_radio.independent && independent_radio.can_receive(frequency, signal_reaches_every_z_level)) + if((independent_radio.special_channels & RADIO_SPECIAL_CENTCOM) && independent_radio.can_receive(frequency, signal_reaches_every_z_level)) radios += independent_radio for(var/obj/item/radio/called_radio as anything in radios) diff --git a/code/game/machinery/telecomms/machines/bus.dm b/code/game/machinery/telecomms/machines/bus.dm index 15d20b3d1eb25..b56b4811083d3 100644 --- a/code/game/machinery/telecomms/machines/bus.dm +++ b/code/game/machinery/telecomms/machines/bus.dm @@ -60,8 +60,8 @@ /obj/machinery/telecomms/bus/preset_two id = "Bus 2" network = "tcommsat" - freq_listening = list(FREQ_SUPPLY, FREQ_SERVICE) - autolinkers = list("processor2", "supply", "service") + freq_listening = list(FREQ_SUPPLY, FREQ_SERVICE, FREQ_ENTERTAINMENT) + autolinkers = list("processor2", "supply", "service", "entertainment") /obj/machinery/telecomms/bus/preset_three id = "Bus 3" diff --git a/code/game/machinery/telecomms/machines/hub.dm b/code/game/machinery/telecomms/machines/hub.dm index 8136aed843514..6583cfe410577 100644 --- a/code/game/machinery/telecomms/machines/hub.dm +++ b/code/game/machinery/telecomms/machines/hub.dm @@ -70,6 +70,7 @@ "common", "command", "engineering", + "entertainment", "security", "receiverA", "receiverB", diff --git a/code/game/machinery/telecomms/machines/receiver.dm b/code/game/machinery/telecomms/machines/receiver.dm index 8d6f8c85f43a1..875398fb8f245 100644 --- a/code/game/machinery/telecomms/machines/receiver.dm +++ b/code/game/machinery/telecomms/machines/receiver.dm @@ -57,7 +57,7 @@ id = "Receiver A" network = "tcommsat" autolinkers = list("receiverA") // link to relay - freq_listening = list(FREQ_SCIENCE, FREQ_MEDICAL, FREQ_SUPPLY, FREQ_SERVICE) + freq_listening = list(FREQ_SCIENCE, FREQ_MEDICAL, FREQ_SUPPLY, FREQ_SERVICE, FREQ_ENTERTAINMENT) //--PRESET RIGHT--// diff --git a/code/game/machinery/telecomms/machines/server.dm b/code/game/machinery/telecomms/machines/server.dm index 0c87a6101d182..1c7557b79def8 100644 --- a/code/game/machinery/telecomms/machines/server.dm +++ b/code/game/machinery/telecomms/machines/server.dm @@ -100,9 +100,9 @@ autolinkers = list("supply") /obj/machinery/telecomms/server/presets/service - id = "Service Server" - freq_listening = list(FREQ_SERVICE) - autolinkers = list("service") + id = "Service & Entertainment Server" + freq_listening = list(FREQ_SERVICE, FREQ_ENTERTAINMENT) + autolinkers = list("service", "entertainment") /obj/machinery/telecomms/server/presets/common id = "Common Server" diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index fd57b24da099f..f06ac5d920916 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -3,6 +3,8 @@ var/can_buckle = FALSE /// Bed-like behaviour, forces mob.lying = buckle_lying if not set to [NO_BUCKLE_LYING]. var/buckle_lying = NO_BUCKLE_LYING + /// Bed-like behaviour, sets mob dir to buckle_dir if not set to [BUCKLE_MATCH_DIR]. If set to [BUCKLE_MATCH_DIR], makes mob dir match ours. + var/buckle_dir = BUCKLE_MATCH_DIR /// Require people to be handcuffed before being able to buckle. eg: pipes var/buckle_requires_restraints = FALSE /// The mobs currently buckled to this atom @@ -106,7 +108,10 @@ M.set_glide_size(glide_size) M.Move(loc) - M.setDir(dir) + if(buckle_dir == BUCKLE_MATCH_DIR) + M.setDir(dir) + else + M.setDir(buckle_dir) //Something has unbuckled us in reaction to the above movement if(!M.buckled) @@ -261,7 +266,7 @@ */ /atom/movable/proc/is_user_buckle_possible(mob/living/target, mob/user, check_loc = TRUE) // Standard adjacency and other checks. - if(!Adjacent(user) || !Adjacent(target) || !isturf(user.loc) || user.incapacitated() || target.anchored) + if(!Adjacent(user) || !Adjacent(target) || !isturf(user.loc) || user.incapacitated || target.anchored) return FALSE if(iscarbon(user)) diff --git a/code/game/objects/effects/anomalies/anomalies_bluespace.dm b/code/game/objects/effects/anomalies/anomalies_bluespace.dm index 2ed19adb4f2c8..0a71427776eea 100644 --- a/code/game/objects/effects/anomalies/anomalies_bluespace.dm +++ b/code/game/objects/effects/anomalies/anomalies_bluespace.dm @@ -31,8 +31,16 @@ // Calculate new position (searches through beacons in world) var/obj/item/beacon/chosen var/list/possible = list() - for(var/obj/item/beacon/W in GLOB.teleportbeacons) - possible += W + for(var/obj/item/beacon/beacon in GLOB.teleportbeacons) + var/turf/turf = get_turf(beacon) + if(!turf) + continue + if(is_centcom_level(turf.z) || is_away_level(turf.z)) + continue + var/area/area = get_area(turf) + if(!area || (area.area_flags & NOTELEPORT)) + continue + possible += beacon if(possible.len > 0) chosen = pick(possible) diff --git a/code/game/objects/effects/anomalies/anomalies_hallucination.dm b/code/game/objects/effects/anomalies/anomalies_hallucination.dm index 4065d8c04a45e..63997d4da6809 100644 --- a/code/game/objects/effects/anomalies/anomalies_hallucination.dm +++ b/code/game/objects/effects/anomalies/anomalies_hallucination.dm @@ -18,6 +18,7 @@ /obj/effect/anomaly/hallucination/Initialize(mapload, new_lifespan, drops_core) . = ..() apply_wibbly_filters(src) + generate_decoys() /obj/effect/anomaly/hallucination/anomalyEffect(seconds_per_tick) . = ..() @@ -40,10 +41,60 @@ if(!isturf(loc)) return - visible_hallucination_pulse( + hallucination_pulse( center = get_turf(src), - radius = 10, + radius = 15, hallucination_duration = 50 SECONDS, hallucination_max_duration = 300 SECONDS, optional_messages = messages, ) + +/obj/effect/anomaly/hallucination/proc/generate_decoys() + for(var/turf/floor in orange(1, src)) + if(prob(35)) + new /obj/effect/anomaly/hallucination/decoy(floor) + +/obj/effect/anomaly/hallucination/decoy + drops_core = FALSE + ///Stores the fake analyzer scan text, so the result is always consistent for each anomaly. + var/report_text + +/obj/effect/anomaly/hallucination/decoy/Initialize(mapload, new_lifespan, drops_core) + . = ..() + ADD_TRAIT(src, TRAIT_ILLUSORY_EFFECT, INNATE_TRAIT) + report_text = pick( + "[src]'s unstable field is fluctuating along frequency 9999999.99999, code 9999999.99999. No, no, that can't be right?", + "It doesn't detect anything. It awaits an input, as if you're pointing it towards nothing at all. What?", + "The interface displays [pick("a bad memory from your past", "the frequency numbers in a language you cannot read", "the first 15 digits of Pi", "yourself, from behind, angled at a 3/4ths isometric perspective")]. What the hell?", + "Nothing happens?", + "It reports that you are a [pick("moron", "idiot", "cretin", "lowlife", "worthless denthead", "gump")]. Huh?", + "It tells you to try again, because you're doing it all wrong. What?", + "It occurs to you that the anomaly you're scanning isn't actually there.", + "It's not working. You activate %TOOL% again. Still broken. You activate %TOOL%. You activate %TOOL%. Why isn't this working??", + "Something happens. You can't tell what. The interface on %TOOL% remains blank.", + "What are you even trying to accomplish here? Did you really think that was going to work?", + "Someone behind you whispers the frequency code to you, but you can't quite hear them. The interface on %TOOL% remains blank.", + "For a brief moment, you see yourself traversing a frozen forest, before snapping back to reality. The interface on %TOOL% remains blank.", + "Nothing interesting happens. Are you sure you're actually using it on anything?", + "For a moment you can feel your skin falling off, then blink as the sensation vanishes. What the hell did that mean?", + "The interface reports that you are a complete failure, and have screwed everything up again. Great work.", + "You realize that the formatting of this message is completely wrong, and get confused. Now why would that be?", + "%TOOL% stares back at you. It looks dissapointed, its screen practically saying 'You missed the anomaly, you dolt. There's nothing there!'", + "Nothing. Weird, maybe %TOOL% must be broken or something?", + "You activate %TOOL%. You activate %TOOL%. You activate %TOOL%. You activate %TOOL%. You activate %TOOL%. You activate %TOOL%. You activate %TOOL%. Why isn't it working??", + ) + +/obj/effect/anomaly/hallucination/decoy/anomalyEffect(seconds_per_tick) + if(SPT_PROB(move_chance, seconds_per_tick)) + move_anomaly() + +/obj/effect/anomaly/hallucination/decoy/analyzer_act(mob/living/user, obj/item/analyzer/tool) + to_chat(user, span_notice("You activate [tool]. [replacetext(report_text, "%TOOL%", "[tool]")]")) + return ITEM_INTERACT_BLOCKING + +/obj/effect/anomaly/hallucination/decoy/detonate() + do_sparks(3, source = src) + return + +/obj/effect/anomaly/hallucination/decoy/generate_decoys() + return diff --git a/code/game/objects/effects/decals/crayon.dm b/code/game/objects/effects/decals/crayon.dm index e42ee4d491fd2..eced2fb66f1ee 100644 --- a/code/game/objects/effects/decals/crayon.dm +++ b/code/game/objects/effects/decals/crayon.dm @@ -11,11 +11,14 @@ var/rotation = 0 var/paint_colour = COLOR_WHITE -/obj/effect/decal/cleanable/crayon/Initialize(mapload, main, type, e_name, graf_rot, alt_icon = null) +/obj/effect/decal/cleanable/crayon/Initialize(mapload, main, type, e_name, graf_rot, alt_icon = null, desc_override = null) . = ..() if(e_name) name = e_name - desc = "A [name] vandalizing the station." + if(desc_override) + desc = "[desc_override]" + else + desc = "A [name] vandalizing the station." if(alt_icon) icon = alt_icon if(type) diff --git a/code/game/objects/effects/decals/remains.dm b/code/game/objects/effects/decals/remains.dm index 61f14f9d80ebb..55cd7cd98d089 100644 --- a/code/game/objects/effects/decals/remains.dm +++ b/code/game/objects/effects/decals/remains.dm @@ -18,18 +18,23 @@ return !istype(here_turf, /obj/structure/closet/crate/grave/filled) && ..() /obj/effect/decal/remains/human/smokey - desc = "They look like human remains. They have a strange, smokey aura about them..." + name = "remains of Charles Morlbaro" + desc = "I guess we figured out what happened to the guy who lives here. You'd best tread lightly around this..." ///Our proximity monitor, for detecting nearby looters. var/datum/proximity_monitor/proximity_monitor ///The reagent we will release when our remains are disturbed. var/datum/reagent/that_shit_that_killed_saddam + ///A cooldown for how frequently the gas is released when disturbed. COOLDOWN_DECLARE(gas_cooldown) + ///The length of the aforementioned cooldown. + var/gas_cooldown_length = (20 SECONDS) /obj/effect/decal/remains/human/smokey/Initialize(mapload) . = ..() - proximity_monitor = new(src, 0) - that_shit_that_killed_saddam = get_random_reagent_id() + proximity_monitor = new(src, 1) + var/list/blocked_reagents = subtypesof(/datum/reagent/medicine) + subtypesof(/datum/reagent/consumable) //Boooooriiiiing + that_shit_that_killed_saddam = get_random_reagent_id(blacklist = blocked_reagents) /obj/effect/decal/remains/human/smokey/HasProximity(atom/movable/tomb_raider) if(!COOLDOWN_FINISHED(src, gas_cooldown)) @@ -37,10 +42,11 @@ if(iscarbon(tomb_raider)) var/mob/living/carbon/nearby_carbon = tomb_raider - if (nearby_carbon.move_intent != MOVE_INTENT_WALK || prob(15)) + if(nearby_carbon.move_intent != MOVE_INTENT_WALK || prob(5)) release_smoke(nearby_carbon) - COOLDOWN_START(src, gas_cooldown, rand(20 SECONDS, 2 MINUTES)) + COOLDOWN_START(src, gas_cooldown, gas_cooldown_length) +///Releases a cloud of smoke based on the randomly generated reagent in Initialize(). /obj/effect/decal/remains/human/smokey/proc/release_smoke(mob/living/smoke_releaser) visible_message(span_warning("[smoke_releaser] disturbs the [src], which releases a huge cloud of gas!")) var/datum/effect_system/fluid_spread/smoke/chem/cigarette_puff = new() @@ -49,6 +55,15 @@ cigarette_puff.set_up(range = 2, amount = DIAMOND_AREA(2), holder = src, location = get_turf(src), silent = TRUE) cigarette_puff.start() +///Subtype of smokey remains used for rare maintenance spawns. +/obj/effect/decal/remains/human/smokey/maintenance + name = "smokey remains" + desc = "They look like human remains. They have a strange, smokey aura about them... You should tread lightly when walking near this." + +/obj/effect/decal/remains/human/smokey/maintenance/Initialize(mapload) + . = ..() + gas_cooldown_length = rand(4 MINUTES, 6 MINUTES) + /obj/effect/decal/remains/plasma icon_state = "remainsplasma" diff --git a/code/game/objects/effects/particles/gravity.dm b/code/game/objects/effects/particles/gravity.dm new file mode 100644 index 0000000000000..0d74896e20a7b --- /dev/null +++ b/code/game/objects/effects/particles/gravity.dm @@ -0,0 +1,44 @@ +/particles/grav_field_down + icon = 'icons/effects/particles/generic.dmi' + icon_state = "cross" + width = 100 + height = 100 + count = 5 + spawning = 1 + lifespan = 0.6 SECONDS + fade = 0.5 SECONDS + fadein = 0.2 SECONDS + position = generator(GEN_CIRCLE, 0, 16, UNIFORM_RAND) + gravity = list(0, -0.75) + color = "#FF0000" + +/particles/grav_field_down/strong + gravity = list(0, -1.75) + +/particles/grav_field_up + icon = 'icons/effects/particles/generic.dmi' + icon_state = "cross" + width = 100 + height = 100 + count = 5 + spawning = 1 + lifespan = 0.6 SECONDS + fade = 0.5 SECONDS + fadein = 0.2 SECONDS + position = generator(GEN_CIRCLE, 0, 16, UNIFORM_RAND) + gravity = list(0, 0.75) + color = "#0077ff" + +/particles/grav_field_float + icon = 'icons/effects/particles/generic.dmi' + icon_state = "cross" + width = 100 + height = 100 + count = 5 + spawning = 1 + lifespan = 0.6 SECONDS + fade = 0.5 SECONDS + fadein = 0.2 SECONDS + position = generator(GEN_CIRCLE, 0, 16, UNIFORM_RAND) + velocity = generator(GEN_VECTOR, list(2,0), list(-2,0), UNIFORM_RAND) + color = "#FFFF00" diff --git a/code/game/objects/effects/spawners/random/exotic.dm b/code/game/objects/effects/spawners/random/exotic.dm index e802e30056f4f..cb43d6f06ae4f 100644 --- a/code/game/objects/effects/spawners/random/exotic.dm +++ b/code/game/objects/effects/spawners/random/exotic.dm @@ -16,8 +16,9 @@ name = "language book spawner" icon_state = "book" loot = list( // A single roundstart species language book. - /obj/item/language_manual/roundstart_species = 100, + /obj/item/language_manual/roundstart_species = 96, /obj/item/book/granter/sign_language = 10, + /obj/item/language_manual/piratespeak = 4, /obj/item/language_manual/roundstart_species/five = 3, /obj/item/language_manual/roundstart_species/unlimited = 1, ) diff --git a/code/game/objects/effects/spawners/random/food_or_drink.dm b/code/game/objects/effects/spawners/random/food_or_drink.dm index 192914b6e3db6..4ff47f08fe994 100644 --- a/code/game/objects/effects/spawners/random/food_or_drink.dm +++ b/code/game/objects/effects/spawners/random/food_or_drink.dm @@ -167,6 +167,7 @@ /obj/item/reagent_containers/cup/glass/bottle/lizardwine = 1, /obj/item/reagent_containers/cup/glass/bottle/vodka/badminka = 1, /obj/item/reagent_containers/cup/glass/bottle/trappist = 1, + /obj/item/reagent_containers/cup/glass/bottle/rum/aged = 1, ) /obj/effect/spawner/random/food_or_drink/pizzaparty diff --git a/code/game/objects/effects/spawners/random/structure.dm b/code/game/objects/effects/spawners/random/structure.dm index 359c147eb4fb5..289a2aba27600 100644 --- a/code/game/objects/effects/spawners/random/structure.dm +++ b/code/game/objects/effects/spawners/random/structure.dm @@ -23,6 +23,7 @@ /obj/effect/spawner/random/trash/mess = 30, /obj/item/kirbyplants/fern = 20, /obj/structure/closet/crate/decorations = 15, + /obj/effect/decal/remains/human/smokey/maintenance = 7, /obj/structure/destructible/cult/pants_altar = 1, ) diff --git a/code/game/objects/effects/spawners/random/trash.dm b/code/game/objects/effects/spawners/random/trash.dm index dfac8e4c0c814..9cf00c20ee3ec 100644 --- a/code/game/objects/effects/spawners/random/trash.dm +++ b/code/game/objects/effects/spawners/random/trash.dm @@ -89,7 +89,6 @@ /obj/item/trash/cnds = 1, /obj/item/trash/syndi_cakes = 1, /obj/item/trash/shrimp_chips = 1, - /obj/item/trash/waffles = 1, /obj/item/trash/tray = 1, ) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 8ee5e171f3d2e..2b320151509e1 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -738,7 +738,7 @@ /obj/item/proc/on_equipped(mob/user, slot, initial = FALSE) SHOULD_NOT_OVERRIDE(TRUE) equipped(user, slot, initial) - if(SEND_SIGNAL(src, COMSIG_ITEM_POST_EQUIPPED, user, slot) && COMPONENT_EQUIPPED_FAILED) + if(SEND_SIGNAL(src, COMSIG_ITEM_POST_EQUIPPED, user, slot) & COMPONENT_EQUIPPED_FAILED) return FALSE return TRUE @@ -829,7 +829,7 @@ set category = "Object" set name = "Pick up" - if(usr.incapacitated() || !Adjacent(usr)) + if(usr.incapacitated || !Adjacent(usr)) return if(isliving(usr)) @@ -1116,7 +1116,7 @@ var/timedelay = usr.client.prefs.read_preference(/datum/preference/numeric/tooltip_delay) / 100 tip_timer = addtimer(CALLBACK(src, PROC_REF(openTip), location, control, params, usr), timedelay, TIMER_STOPPABLE)//timer takes delay in deciseconds, but the pref is in milliseconds. dividing by 100 converts it. if(usr.client.prefs.read_preference(/datum/preference/toggle/item_outlines)) - if(istype(L) && L.incapacitated()) + if(istype(L) && L.incapacitated) apply_outline(COLOR_RED_GRAY) //if they're dead or handcuffed, let's show the outline as red to indicate that they can't interact with that right now else apply_outline() //if the player's alive and well we send the command with no color set, so it uses the theme's color @@ -1781,9 +1781,11 @@ /obj/item/proc/set_embed(datum/embed_data/embed) if(embed_data == embed) return + if(isnull(get_embed())) // Add embed on objects that did not have it added + AddElement(/datum/element/embed) if(!GLOB.embed_by_type[embed_data?.type]) qdel(embed_data) - embed_data = ispath(embed) ? get_embed_by_type(armor) : embed + embed_data = ispath(embed) ? get_embed_by_type(embed) : embed SEND_SIGNAL(src, COMSIG_ITEM_EMBEDDING_UPDATE) /** diff --git a/code/game/objects/items/bodybag.dm b/code/game/objects/items/bodybag.dm index c949f977508f1..4adb8d28b8c8a 100644 --- a/code/game/objects/items/bodybag.dm +++ b/code/game/objects/items/bodybag.dm @@ -86,7 +86,7 @@ return item_bag /obj/item/bodybag/bluespace/container_resist_act(mob/living/user) - if(user.incapacitated()) + if(user.incapacitated) to_chat(user, span_warning("You can't get out while you're restrained like this!")) return user.changeNext_move(CLICK_CD_BREAKOUT) @@ -97,7 +97,7 @@ return // you are still in the bag? time to go unless you KO'd, honey! // if they escape during this time and you rebag them the timer is still clocking down and does NOT reset so they can very easily get out. - if(user.incapacitated()) + if(user.incapacitated) to_chat(loc, span_warning("The pressure subsides. It seems that they've stopped resisting...")) return loc.visible_message(span_warning("[user] suddenly appears in front of [loc]!"), span_userdanger("[user] breaks free of [src]!")) diff --git a/code/game/objects/items/cardboard_cutouts.dm b/code/game/objects/items/cardboard_cutouts.dm index d4508710a8547..b49991b132a4e 100644 --- a/code/game/objects/items/cardboard_cutouts.dm +++ b/code/game/objects/items/cardboard_cutouts.dm @@ -149,7 +149,7 @@ /obj/item/cardboard_cutout/proc/check_menu(mob/living/user, obj/item/toy/crayon/crayon) if(!istype(user)) return FALSE - if(user.incapacitated()) + if(user.incapacitated) return FALSE if(pushed_over) to_chat(user, span_warning("Right [src] first!")) diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index 41731cdf31d8f..60c1ee5ef4086 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -104,6 +104,11 @@ /// Boolean value. If TRUE, the [Intern] tag gets prepended to this ID card when the label is updated. var/is_intern = FALSE + ///If true, the wearer will have bigger arrow when pointing at things. Passed down by trims. + var/big_pointer = FALSE + ///If set, the arrow will have a different color. + var/pointer_color + /datum/armor/card_id fire = 100 acid = 100 @@ -144,6 +149,29 @@ QDEL_NULL(my_store) return ..() +/obj/item/card/id/equipped(mob/user, slot) + . = ..() + if(slot == ITEM_SLOT_ID) + RegisterSignal(user, COMSIG_MOVABLE_POINTED, PROC_REF(on_pointed)) + +/obj/item/card/id/proc/on_pointed(mob/living/user, atom/pointed, obj/effect/temp_visual/point/point) + SIGNAL_HANDLER + if((!big_pointer && !pointer_color) || HAS_TRAIT(user, TRAIT_UNKNOWN)) + return + if(point.icon_state != /obj/effect/temp_visual/point::icon_state) //it differs from the original icon_state already. + return + if(big_pointer) + point.icon_state = "arrow_large" + if(pointer_color) + point.icon_state = "[point.icon_state]_white" + point.color = pointer_color + var/mutable_appearance/highlight = mutable_appearance(point.icon, "[point.icon_state]_highlights", appearance_flags = RESET_COLOR) + point.add_overlay(highlight) + +/obj/item/card/id/dropped(mob/user) + UnregisterSignal(user, COMSIG_MOVABLE_POINTED) + return ..() + /obj/item/card/id/get_id_examine_strings(mob/user) . = ..() . += list("[icon2html(get_cached_flat_icon(), user, extra_classes = "bigicon")]") @@ -1859,7 +1887,7 @@ /obj/item/card/cardboard/proc/after_input_check(mob/living/user, obj/item/item, input, value) if(!input || (value && input == value)) return FALSE - if(QDELETED(user) || QDELETED(item) || QDELETED(src) || user.incapacitated() || !user.is_holding(item) || !user.CanReach(src) || !user.can_write(item)) + if(QDELETED(user) || QDELETED(item) || QDELETED(src) || user.incapacitated || !user.is_holding(item) || !user.CanReach(src) || !user.can_write(item)) return FALSE return TRUE diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index fe1f6b7495bda..35f14640278e4 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -129,9 +129,10 @@ CIGARETTE PACKETS ARE IN FANCY.DM ////////////////// //FINE SMOKABLES// ////////////////// + /obj/item/cigarette name = "cigarette" - desc = "A roll of tobacco and nicotine." + desc = "A roll of tobacco and nicotine. It is not food." icon = 'icons/obj/cigarettes.dmi' icon_state = "cigoff" inhand_icon_state = "cigon" //gets overriden during intialize(), just have it for unit test sanity. @@ -180,6 +181,8 @@ CIGARETTE PACKETS ARE IN FANCY.DM VAR_PRIVATE/obj/effect/abstract/particle_holder/mob_smoke /// How long the current mob has been smoking this cigarette VAR_FINAL/how_long_have_we_been_smokin = 0 SECONDS + /// Which people ate cigarettes and how many + var/static/list/cigarette_eaters = list() /obj/item/cigarette/Initialize(mapload) . = ..() @@ -194,12 +197,37 @@ CIGARETTE PACKETS ARE IN FANCY.DM icon_state = icon_off inhand_icon_state = inhand_icon_off + // "It is called a cigarette" + AddComponent(/datum/component/edible,\ + initial_reagents = list_reagents,\ + food_flags = null,\ + foodtypes = JUNKFOOD,\ + volume = 50,\ + eat_time = 0 SECONDS,\ + tastes = list("a never before experienced flavour.", "finally sitting down after standing your entire life"),\ + eatverbs = list("taste"),\ + bite_consumption = 50,\ + junkiness = 0,\ + reagent_purity = null,\ + on_consume = CALLBACK(src, PROC_REF(on_consume)),\ + show_examine = FALSE, \ + ) + /obj/item/cigarette/Destroy() STOP_PROCESSING(SSobj, src) QDEL_NULL(mob_smoke) QDEL_NULL(cig_smoke) return ..() +/obj/item/cigarette/proc/on_consume(mob/living/eater, mob/living/feeder) + if(isnull(eater.client)) + return + var/ckey = eater.client.ckey + // We must have more! + cigarette_eaters[ckey]++ + if(cigarette_eaters[ckey] >= 500) + eater.client.give_award(/datum/award/achievement/misc/cigarettes) + /obj/item/cigarette/equipped(mob/equipee, slot) . = ..() if(!(slot & ITEM_SLOT_MASK)) @@ -216,7 +244,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM if(!QDELETED(src) && !QDELETED(dropee) && how_long_have_we_been_smokin >= 4 SECONDS && iscarbon(dropee) && iscarbon(loc)) var/mob/living/carbon/smoker = dropee // This relies on the fact that dropped is called before slot is nulled - if(src == smoker.wear_mask && !smoker.incapacitated()) + if(src == smoker.wear_mask && !smoker.incapacitated) long_exhale(smoker) UnregisterSignal(dropee, list(COMSIG_HUMAN_FORCESAY, COMSIG_ATOM_DIR_CHANGE)) diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm index 53fef07eb194a..0b7bd54f5c69b 100644 --- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm @@ -926,6 +926,9 @@ /obj/item/stack/cable_coil = 1, /obj/item/stack/sheet/glass = 2) +/obj/item/circuitboard/machine/sleeper/syndie + build_path = /obj/machinery/sleeper/syndie + /obj/item/circuitboard/machine/sleeper/fullupgrade build_path = /obj/machinery/sleeper/syndie/fullupgrade req_components = list( @@ -1376,6 +1379,10 @@ /datum/stock_part/capacitor = 1) needs_anchored = FALSE +/obj/item/circuitboard/machine/fishing_portal_generator/emagged + name = "Emagged Fishing Portal Generator" + build_path = /obj/machinery/fishing_portal_generator + //Supply /obj/item/circuitboard/machine/ore_redemption name = "Ore Redemption" @@ -1685,3 +1692,20 @@ req_components = list( /obj/item/pipe/trinary/flippable/filter = 1, ) + +/obj/item/circuitboard/machine/portagrav + name = "Portable Gravity Unit" + greyscale_colors = CIRCUIT_COLOR_ENGINEERING + build_path = /obj/machinery/power/portagrav + req_components = list( + /datum/stock_part/capacitor = 2, + /datum/stock_part/micro_laser = 2, + /obj/item/stack/sheet/glass = 1) + +/obj/item/circuitboard/machine/big_manipulator + name = "Big Manipulator" + greyscale_colors = CIRCUIT_COLOR_ENGINEERING + build_path = /obj/machinery/big_manipulator + req_components = list( + /datum/stock_part/servo = 1, + ) diff --git a/code/game/objects/items/cosmetics.dm b/code/game/objects/items/cosmetics.dm index b16cf3a6ef61a..dbe6712a469e3 100644 --- a/code/game/objects/items/cosmetics.dm +++ b/code/game/objects/items/cosmetics.dm @@ -8,6 +8,7 @@ desc = "A generic brand of lipstick." icon = 'icons/obj/cosmetic.dmi' icon_state = "lipstick" + base_icon_state = "lipstick" inhand_icon_state = "lipstick" w_class = WEIGHT_CLASS_TINY interaction_flags_click = NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING @@ -18,6 +19,8 @@ var/style = "lipstick" /// A trait that's applied while someone has this lipstick applied, and is removed when the lipstick is removed var/lipstick_trait + /// Can this lipstick spawn randomly + var/random_spawn = TRUE /obj/item/lipstick/Initialize(mapload) . = ..() @@ -34,8 +37,8 @@ . += "Alt-click to change the style." /obj/item/lipstick/update_icon_state() - icon_state = "lipstick[open ? "_uncap" : null]" - inhand_icon_state = "lipstick[open ? "open" : null]" + icon_state = "[base_icon_state][open ? "_uncap" : null]" + inhand_icon_state = "[base_icon_state][open ? "open" : null]" return ..() /obj/item/lipstick/update_overlays() @@ -72,7 +75,7 @@ /obj/item/lipstick/proc/check_menu(mob/living/user) if(!istype(user)) return FALSE - if(user.incapacitated() || !user.is_holding(src)) + if(user.incapacitated || !user.is_holding(src)) return FALSE return TRUE @@ -104,6 +107,16 @@ name = "\improper Kiss of Death" desc = "An incredibly potent tube of lipstick made from the venom of the dreaded Yellow Spotted Space Lizard, as deadly as it is chic. Try not to smear it!" lipstick_trait = TRAIT_KISS_OF_DEATH + random_spawn = FALSE + +/obj/item/lipstick/syndie + name = "syndie lipstick" + desc = "Syndicate branded lipstick with a killer dose of kisses. Observe safety regulations!" + icon_state = "slipstick" + base_icon_state = "slipstick" + lipstick_color = COLOR_SYNDIE_RED + lipstick_trait = TRAIT_SYNDIE_KISS + random_spawn = FALSE /obj/item/lipstick/random name = "lipstick" @@ -116,7 +129,7 @@ if(!possible_colors) possible_colors = list() for(var/obj/item/lipstick/lipstick_path as anything in (typesof(/obj/item/lipstick) - src.type)) - if(!initial(lipstick_path.lipstick_color)) + if(!initial(lipstick_path.lipstick_color) || !initial(lipstick_path.random_spawn)) continue possible_colors[initial(lipstick_path.lipstick_color)] = initial(lipstick_path.name) lipstick_color = pick(possible_colors) diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index 93c6b6bdc992f..e3fb1453eaac6 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -645,13 +645,38 @@ dye_color = DYE_BLACK /obj/item/toy/crayon/white - name = "white crayon" + name = "stick of chalk" + desc = "A stark-white stick of chalk." icon_state = "crayonwhite" paint_color = COLOR_WHITE crayon_color = "white" reagent_contents = list(/datum/reagent/consumable/nutriment = 0.5, /datum/reagent/colorful_reagent/powder/white/crayon = 1.5) dye_color = DYE_WHITE +/obj/item/toy/crayon/white/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + /// Wherein, we draw a chalk body outline vaguely around the dead or "dead" mob + if(!ishuman(interacting_with) || user.combat_mode) + return ..() + + var/mob/living/carbon/human/pwned_human = interacting_with + + if(!(pwned_human.stat == DEAD || HAS_TRAIT(pwned_human, TRAIT_FAKEDEATH))) + balloon_alert_to_viewers("FEEDING TIME") + return ..() + + balloon_alert_to_viewers("drawing outline...") + if(!do_after(user, DRAW_TIME, target = pwned_human, max_interact_count = 4)) + return NONE + if(!use_charges(user, 1)) + return NONE + + var/decal_rotation = GET_LYING_ANGLE(pwned_human) - 90 + var/obj/effect/decal/cleanable/crayon/chalk_line = new(get_turf(pwned_human), paint_color, "body", "chalk outline", decal_rotation, null, "A vaguely [pwned_human] shaped outline of a body.") + to_chat(user, span_notice("You draw a chalk outline around [pwned_human].")) + chalk_line.pixel_y = (pwned_human.pixel_y + pwned_human.pixel_z) + rand(-2, 2) + chalk_line.pixel_x = (pwned_human.pixel_x + pwned_human.pixel_w) + rand(-1, 1) + return ITEM_INTERACT_SUCCESS + /obj/item/toy/crayon/mime name = "mime crayon" icon_state = "crayonmime" @@ -796,7 +821,6 @@ return (isfloorturf(surface) || iswallturf(surface)) /obj/item/toy/crayon/spraycan/suicide_act(mob/living/user) - var/mob/living/carbon/human/H = user var/used = min(charges_left, 10) if(is_capped || !actually_paints || !use_charges(user, 10, FALSE)) user.visible_message(span_suicide("[user] shakes up [src] with a rattle and lifts it to [user.p_their()] mouth, but nothing happens!")) @@ -811,7 +835,7 @@ set_painting_tool_color(COLOR_SILVER) update_appearance() if(actually_paints) - H.update_lips("spray_face", paint_color) + user.AddComponent(/datum/component/face_decal, "spray", EXTERNAL_ADJACENT, paint_color) reagents.trans_to(user, used, volume_multiplier, transferred_by = user, methods = VAPOR) return OXYLOSS @@ -866,7 +890,7 @@ flash_color(carbon_target, flash_color=paint_color, flash_time=40) if(ishuman(carbon_target) && actually_paints) var/mob/living/carbon/human/human_target = carbon_target - human_target.update_lips("spray_face", paint_color) + human_target.AddComponent(/datum/component/face_decal, "spray", EXTERNAL_ADJACENT, paint_color) use_charges(user, 10, FALSE) var/fraction = min(1, . / reagents.maximum_volume) reagents.expose(carbon_target, VAPOR, fraction * volume_multiplier) diff --git a/code/game/objects/items/debug_items.dm b/code/game/objects/items/debug_items.dm index 071561d57a095..24f350f37907a 100644 --- a/code/game/objects/items/debug_items.dm +++ b/code/game/objects/items/debug_items.dm @@ -46,7 +46,7 @@ /obj/item/debug/omnitool/proc/check_menu(mob/user) if(!istype(user)) return FALSE - if(user.incapacitated() || !user.Adjacent(src)) + if(user.incapacitated || !user.Adjacent(src)) return FALSE return TRUE diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index 02934d1a03eaa..b1e01e5a6cebc 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -137,11 +137,12 @@ return ..() /obj/item/defibrillator/mouse_drop_dragged(atom/over_object, mob/user, src_location, over_location, params) - if(ismob(loc)) - var/mob/M = loc - if(istype(over_object, /atom/movable/screen/inventory/hand)) - var/atom/movable/screen/inventory/hand/H = over_object - M.putItemFromInventoryInHandIfPossible(src, H.held_index) + if(!ismob(loc)) + return + var/mob/living_mob = loc + if(!living_mob.incapacitated && istype(over_object, /atom/movable/screen/inventory/hand)) + var/atom/movable/screen/inventory/hand/hand = over_object + living_mob.putItemFromInventoryInHandIfPossible(src, hand.held_index) /obj/item/defibrillator/screwdriver_act(mob/living/user, obj/item/tool) if(!cell || !cell_removable) diff --git a/code/game/objects/items/devices/broadcast_camera.dm b/code/game/objects/items/devices/broadcast_camera.dm new file mode 100644 index 0000000000000..f2fc0192f5684 --- /dev/null +++ b/code/game/objects/items/devices/broadcast_camera.dm @@ -0,0 +1,104 @@ +// Unique broadcast camera given to the first Curator +// Only one should exist ideally, if other types are created they must have different camera_networks +// Broadcasts its surroundings to entertainment monitors and its audio to entertainment radio channel +/obj/item/broadcast_camera + name = "broadcast camera" + desc = "A large camera that streams its live feed and audio to entertainment monitors across the station, allowing everyone to watch the broadcast." + desc_controls = "Right-click to change the broadcast name. Alt-click to toggle microphone." + icon = 'icons/obj/service/broadcast.dmi' + icon_state = "broadcast_cam0" + base_icon_state = "broadcast_cam" + lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' + force = 8 + throwforce = 12 + w_class = WEIGHT_CLASS_NORMAL + obj_flags = INDESTRUCTIBLE | EMP_PROTECT_ALL // No fun police + slot_flags = NONE + light_system = OVERLAY_LIGHT + light_color = COLOR_SOFT_RED + light_range = 1 + light_power = 0.3 + light_on = FALSE + /// Is camera streaming + var/active = FALSE + /// The name of the broadcast + var/broadcast_name = "Curator News" + /// The networks it broadcasts to, default is CAMERANET_NETWORK_CURATOR + var/list/camera_networks = list(CAMERANET_NETWORK_CURATOR) + /// The "virtual" security camera inside of the physical camera + var/obj/machinery/camera/internal_camera + /// The "virtual" radio inside of the the physical camera, a la microphone + var/obj/item/radio/entertainment/microphone/internal_radio + +/obj/item/broadcast_camera/Destroy(force) + QDEL_NULL(internal_radio) + QDEL_NULL(internal_camera) + + return ..() + +/obj/item/broadcast_camera/update_icon_state() + icon_state = "[base_icon_state]0" + return ..() + +/obj/item/broadcast_camera/attack_self(mob/user, modifiers) + . = ..() + active = !active + if(active) + on_activating() + else + on_deactivating() + +/obj/item/broadcast_camera/attack_self_secondary(mob/user, modifiers) + . = ..() + broadcast_name = tgui_input_text(user = user, title = "Broadcast Name", message = "What will be the name of your broadcast?", default = "[broadcast_name]", max_length = MAX_CHARTER_LEN) + +/obj/item/broadcast_camera/examine(mob/user) + . = ..() + . += span_notice("Broadcast name is [broadcast_name]") + +/obj/item/broadcast_camera/on_enter_storage(datum/storage/master_storage) + . = ..() + if(active) + on_deactivating() + +/obj/item/broadcast_camera/dropped(mob/user, silent) + . = ..() + if(active) + on_deactivating() + +/// When activating the camera +/obj/item/broadcast_camera/proc/on_activating() + if(!iscarbon(loc)) + return + active = TRUE + icon_state = "[base_icon_state][active]" + /// The carbon who wielded the camera, allegedly + var/mob/living/carbon/wielding_carbon = loc + + // INTERNAL CAMERA + internal_camera = new(wielding_carbon) // Cameras for some reason do not work inside of obj's + internal_camera.internal_light = FALSE + internal_camera.network = camera_networks + internal_camera.c_tag = "LIVE: [broadcast_name]" + start_broadcasting_network(camera_networks, "[broadcast_name] is now LIVE!") + + // INTERNAL RADIO + internal_radio = new(src) + + set_light_on(TRUE) + playsound(source = src, soundin = 'sound/machines/terminal_processing.ogg', vol = 20, vary = FALSE, ignore_walls = FALSE) + balloon_alert_to_viewers("live!") + +/// When deactivating the camera +/obj/item/broadcast_camera/proc/on_deactivating() + active = FALSE + icon_state = "[base_icon_state][active]" + QDEL_NULL(internal_camera) + QDEL_NULL(internal_radio) + + stop_broadcasting_network(camera_networks) + + set_light_on(FALSE) + playsound(source = src, soundin = 'sound/machines/terminal_prompt_deny.ogg', vol = 20, vary = FALSE, ignore_walls = FALSE) + balloon_alert_to_viewers("offline") diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm index 4211e2f507990..3fe16fdb3fd96 100644 --- a/code/game/objects/items/devices/laserpointer.dm +++ b/code/game/objects/items/devices/laserpointer.dm @@ -271,7 +271,7 @@ //catpeople: make any felinid near the target to face the target, chance for felinids to pounce at the light, stepping to the target for(var/mob/living/carbon/human/target_felinid in view(1, targloc)) - if(!isfelinid(target_felinid) || target_felinid.stat == DEAD || target_felinid.is_blind() || target_felinid.incapacitated()) + if(!isfelinid(target_felinid) || target_felinid.stat == DEAD || target_felinid.is_blind() || target_felinid.incapacitated) continue if(target_felinid.body_position == STANDING_UP) target_felinid.setDir(get_dir(target_felinid, targloc)) // kitty always looks at the light diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm index 88c9251d5b2bc..2eab06806dd09 100644 --- a/code/game/objects/items/devices/radio/encryptionkey.dm +++ b/code/game/objects/items/devices/radio/encryptionkey.dm @@ -4,26 +4,22 @@ icon = 'icons/obj/devices/circuitry_n_data.dmi' icon_state = "cypherkey_basic" w_class = WEIGHT_CLASS_TINY - /// Can this radio key access the binary radio channel? - var/translate_binary = FALSE - /// Decrypts Syndicate radio transmissions. - var/syndie = FALSE - /// If true, the radio can say/hear on the special CentCom channel. - var/independent = FALSE /// What channels does this encryption key grant to the parent headset. var/list/channels = list() + /// Flags for which "special" radio networks should be accessible + var/special_channels = NONE var/datum/language/translated_language greyscale_config = /datum/greyscale_config/encryptionkey_basic greyscale_colors = "#820a16#3758c4" /obj/item/encryptionkey/examine(mob/user) . = ..() - if(LAZYLEN(channels) || translate_binary) + if(LAZYLEN(channels) || special_channels & RADIO_SPECIAL_BINARY) var/list/examine_text_list = list() for(var/i in channels) examine_text_list += "[GLOB.channel_tokens[i]] - [LOWER_TEXT(i)]" - if(translate_binary) + if(special_channels & RADIO_SPECIAL_BINARY) examine_text_list += "[GLOB.channel_tokens[MODE_BINARY]] - [MODE_BINARY]" . += span_notice("It can access the following channels; [jointext(examine_text_list, ", ")].") @@ -34,14 +30,14 @@ name = "syndicate encryption key" icon_state = "cypherkey_syndicate" channels = list(RADIO_CHANNEL_SYNDICATE = 1) - syndie = TRUE + special_channels = RADIO_SPECIAL_SYNDIE greyscale_config = /datum/greyscale_config/encryptionkey_syndicate greyscale_colors = "#171717#990000" /obj/item/encryptionkey/binary name = "binary translator key" icon_state = "cypherkey_basic" - translate_binary = TRUE + special_channels = RADIO_SPECIAL_BINARY translated_language = /datum/language/machine greyscale_config = /datum/greyscale_config/encryptionkey_basic greyscale_colors = "#24a157#3758c4" @@ -102,6 +98,13 @@ greyscale_config = /datum/greyscale_config/encryptionkey_service greyscale_colors = "#ebebeb#3bca5a" +/obj/item/encryptionkey/headset_srvent + name = "press radio encryption key" + icon_state = "cypherkey_service" + channels = list(RADIO_CHANNEL_SERVICE = 1, RADIO_CHANNEL_ENTERTAINMENT = 0) + greyscale_config = /datum/greyscale_config/encryptionkey_service + greyscale_colors = "#83eb8f#3bca5a" + /obj/item/encryptionkey/headset_com name = "command radio encryption key" icon_state = "cypherkey_cube" @@ -182,7 +185,7 @@ /obj/item/encryptionkey/headset_cent name = "\improper CentCom radio encryption key" icon_state = "cypherkey_centcom" - independent = TRUE + special_channels = RADIO_SPECIAL_CENTCOM channels = list(RADIO_CHANNEL_CENTCOM = 1) greyscale_config = /datum/greyscale_config/encryptionkey_centcom greyscale_colors = "#24a157#dca01b" @@ -197,6 +200,7 @@ RADIO_CHANNEL_SUPPLY = 1, RADIO_CHANNEL_SERVICE = 1, RADIO_CHANNEL_AI_PRIVATE = 1, + RADIO_CHANNEL_ENTERTAINMENT = 1, ) /obj/item/encryptionkey/ai_with_binary @@ -210,15 +214,16 @@ RADIO_CHANNEL_SUPPLY = 1, RADIO_CHANNEL_SERVICE = 1, RADIO_CHANNEL_AI_PRIVATE = 1, + RADIO_CHANNEL_ENTERTAINMENT = 1, ) - translate_binary = TRUE + special_channels = RADIO_SPECIAL_BINARY translated_language = /datum/language/machine /obj/item/encryptionkey/ai/evil //ported from NT, this goes 'inside' the AI. name = "syndicate binary encryption key" icon_state = "cypherkey_syndicate" channels = list(RADIO_CHANNEL_SYNDICATE = 1) - syndie = TRUE + special_channels = RADIO_SPECIAL_SYNDIE greyscale_config = /datum/greyscale_config/encryptionkey_syndicate greyscale_colors = "#171717#990000" diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index edf24b0d942d4..5673afc678a41 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -11,7 +11,8 @@ GLOBAL_LIST_INIT(channel_tokens, list( RADIO_CHANNEL_SUPPLY = RADIO_TOKEN_SUPPLY, RADIO_CHANNEL_SERVICE = RADIO_TOKEN_SERVICE, MODE_BINARY = MODE_TOKEN_BINARY, - RADIO_CHANNEL_AI_PRIVATE = RADIO_TOKEN_AI_PRIVATE + RADIO_CHANNEL_AI_PRIVATE = RADIO_TOKEN_AI_PRIVATE, + RADIO_CHANNEL_ENTERTAINMENT = RADIO_TOKEN_ENTERTAINMENT, )) /obj/item/radio/headset @@ -49,7 +50,7 @@ GLOBAL_LIST_INIT(channel_tokens, list( if(item_flags & IN_INVENTORY && loc == user) // construction of frequency description var/list/avail_chans = list("Use [RADIO_KEY_COMMON] for the currently tuned frequency") - if(translate_binary) + if(special_channels & RADIO_SPECIAL_BINARY) avail_chans += "use [MODE_TOKEN_BINARY] for [MODE_BINARY]" if(length(channels)) for(var/i in 1 to length(channels)) @@ -203,6 +204,13 @@ GLOBAL_LIST_INIT(channel_tokens, list( worn_icon_state = "srv_headset" keyslot = /obj/item/encryptionkey/headset_srvmed +/obj/item/radio/headset/headset_srvent + name = "press headset" + desc = "A headset allowing the wearer to communicate with service and broadcast to entertainment channel." + icon_state = "srvent_headset" + worn_icon_state = "srv_headset" + keyslot = /obj/item/encryptionkey/headset_srvent + /obj/item/radio/headset/headset_com name = "command radio headset" desc = "A headset with a commanding channel." @@ -430,12 +438,7 @@ GLOBAL_LIST_INIT(channel_tokens, list( if(!(ch_name in src.channels)) LAZYSET(channels, ch_name, keyslot2.channels[ch_name]) - if(keyslot2.translate_binary) - translate_binary = TRUE - if(keyslot2.syndie) - syndie = TRUE - if(keyslot2.independent) - independent = TRUE + special_channels |= keyslot2.special_channels for(var/ch_name in channels) secure_radio_connections[ch_name] = add_radio(src, GLOB.radiochannels[ch_name]) @@ -459,6 +462,8 @@ GLOBAL_LIST_INIT(channel_tokens, list( grant_headset_languages(mob_loc) /obj/item/radio/headset/click_alt(mob/living/user) + if(!istype(user) || !Adjacent(user) || user.incapacitated) + return CLICK_ACTION_BLOCKING if (!command) return CLICK_ACTION_BLOCKING use_command = !use_command diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm index 504f547b5cb78..b7c43c95e5fd0 100644 --- a/code/game/objects/items/devices/radio/intercom.dm +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -118,7 +118,7 @@ return FALSE if(freq == FREQ_SYNDICATE) - if(!(syndie)) + if(!(special_channels &= RADIO_SPECIAL_SYNDIE)) return FALSE//Prevents broadcast of messages over devices lacking the encryption return TRUE @@ -219,6 +219,17 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom, 27) command = TRUE icon_off = "intercom_command-p" +/obj/item/radio/intercom/syndicate + name = "syndicate intercom" + desc = "Talk smack through this." + command = TRUE + special_channels = RADIO_SPECIAL_SYNDIE + +/obj/item/radio/intercom/syndicate/freerange + name = "syndicate wide-band intercom" + desc = "A custom-made Syndicate-issue intercom used to transmit on all Nanotrasen frequencies. Particularly expensive." + freerange = TRUE + MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/prison, 27) MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/chapel, 27) MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/command, 27) diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 121f0bba965b3..e1d106152d9a0 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -57,18 +57,16 @@ var/use_command = FALSE /// If true, use_command can be toggled at will. var/command = FALSE + /// Does it play radio noise? + var/radio_noise = TRUE ///makes anyone who is talking through this anonymous. var/anonymize = FALSE /// Encryption key handling var/obj/item/encryptionkey/keyslot - /// If true, can hear the special binary channel. - var/translate_binary = FALSE - /// If true, can say/hear on the special CentCom channel. - var/independent = FALSE - /// If true, hears all well-known channels automatically, and can say/hear on the Syndicate channel. Also protects from radio jammers. - var/syndie = FALSE + /// Flags for which "special" radio networks should be accessible + var/special_channels = NONE /// associative list of the encrypted radio channels this radio is currently set to listen/broadcast to, of the form: list(channel name = TRUE or FALSE) var/list/channels /// associative list of the encrypted radio channels this radio can listen/broadcast to, of the form: list(channel name = channel frequency) @@ -91,6 +89,11 @@ /// If TRUE, will set the icon in initializations. VAR_PRIVATE/should_update_icon = FALSE + /// A very brief cooldown to prevent regular radio sounds from overlapping. + COOLDOWN_DECLARE(audio_cooldown) + /// A very brief cooldown to prevent "important" radio sounds from overlapping. + COOLDOWN_DECLARE(important_audio_cooldown) + /obj/item/radio/Initialize(mapload) set_wires(new /datum/wires/radio(src)) secure_radio_connections = list() @@ -104,7 +107,7 @@ perform_update_icon = FALSE set_listening(listening) set_broadcasting(broadcasting) - set_frequency(sanitize_frequency(frequency, freerange, syndie)) + set_frequency(sanitize_frequency(frequency, freerange, (special_channels & RADIO_SPECIAL_SYNDIE))) set_on(on) perform_update_icon = TRUE @@ -149,12 +152,7 @@ if(!(channel_name in channels)) channels[channel_name] = keyslot.channels[channel_name] - if(keyslot.translate_binary) - translate_binary = TRUE - if(keyslot.syndie) - syndie = TRUE - if(keyslot.independent) - independent = TRUE + special_channels = keyslot.special_channels for(var/channel_name in channels) secure_radio_connections[channel_name] = add_radio(src, GLOB.radiochannels[channel_name]) @@ -163,9 +161,7 @@ /obj/item/radio/proc/resetChannels() channels = list() secure_radio_connections = list() - translate_binary = FALSE - syndie = FALSE - independent = FALSE + special_channels = NONE ///goes through all radio channels we should be listening for and readds them to the global list /obj/item/radio/proc/readd_listening_radio_channels() @@ -177,7 +173,7 @@ /obj/item/radio/proc/make_syndie() // Turns normal radios into Syndicate radios! qdel(keyslot) keyslot = new /obj/item/encryptionkey/syndicate() - syndie = TRUE + special_channels |= RADIO_SPECIAL_SYNDIE recalculateChannels() /obj/item/radio/interact(mob/user) @@ -334,7 +330,7 @@ channel = null // Nearby active jammers prevent the message from transmitting - if(is_within_radio_jammer_range(src) && !syndie) + if(is_within_radio_jammer_range(src) && !(special_channels & RADIO_SPECIAL_SYNDIE)) return // Determine the identity information which will be attached to the signal. @@ -344,7 +340,7 @@ var/datum/signal/subspace/vocal/signal = new(src, freq, speaker, language, radio_message, spans, message_mods) // Independent radios, on the CentCom frequency, reach all independent radios - if (independent && (freq == FREQ_CENTCOM || freq == FREQ_CTF_RED || freq == FREQ_CTF_BLUE || freq == FREQ_CTF_GREEN || freq == FREQ_CTF_YELLOW)) + if (special_channels & RADIO_SPECIAL_CENTCOM && (freq == FREQ_CENTCOM || freq == FREQ_CTF_RED || freq == FREQ_CTF_BLUE || freq == FREQ_CTF_GREEN || freq == FREQ_CTF_YELLOW)) signal.data["compression"] = 0 signal.transmission_method = TRANSMISSION_SUPERSPACE signal.levels = list(0) @@ -354,7 +350,7 @@ if(isliving(talking_movable)) var/mob/living/talking_living = talking_movable - if(talking_living.client?.prefs.read_preference(/datum/preference/toggle/radio_noise)) + if(talking_living.client?.prefs.read_preference(/datum/preference/toggle/radio_noise) && !HAS_TRAIT(talking_living, TRAIT_DEAF) && radio_noise) SEND_SOUND(talking_living, 'sound/misc/radio_talk.ogg') // All radios make an attempt to use the subspace system first @@ -412,7 +408,7 @@ if(!position || !(position.z in levels)) return FALSE - if (input_frequency == FREQ_SYNDICATE && !syndie) + if (input_frequency == FREQ_SYNDICATE && !(special_channels & RADIO_SPECIAL_SYNDIE)) return FALSE // allow checks: are we listening on that frequency? @@ -420,7 +416,7 @@ return TRUE for(var/ch_name in channels) if(channels[ch_name] & FREQ_LISTENING) - if(GLOB.radiochannels[ch_name] == text2num(input_frequency) || syndie) + if(GLOB.radiochannels[ch_name] == text2num(input_frequency) || special_channels & RADIO_SPECIAL_SYNDIE) return TRUE return FALSE @@ -432,12 +428,15 @@ return var/mob/living/holder = loc - if(!holder.client?.prefs.read_preference(/datum/preference/toggle/radio_noise)) + if(!holder.client?.prefs.read_preference(/datum/preference/toggle/radio_noise) && HAS_TRAIT(holder, TRAIT_DEAF) && !radio_noise) return var/list/spans = data["spans"] - SEND_SOUND(holder, 'sound/misc/radio_receive.ogg') - if(SPAN_COMMAND in spans) + if(COOLDOWN_FINISHED(src, audio_cooldown)) + COOLDOWN_START(src, audio_cooldown, 0.5 SECONDS) + SEND_SOUND(holder, 'sound/misc/radio_receive.ogg') + if((SPAN_COMMAND in spans) && COOLDOWN_FINISHED(src, important_audio_cooldown)) + COOLDOWN_START(src, important_audio_cooldown, 0.5 SECONDS) SEND_SOUND(holder, 'sound/misc/radio_important.ogg') /obj/item/radio/ui_state(mob/user) @@ -488,7 +487,7 @@ tune = tune * 10 . = TRUE if(.) - set_frequency(sanitize_frequency(tune, freerange, syndie)) + set_frequency(sanitize_frequency(tune, freerange, (special_channels & RADIO_SPECIAL_SYNDIE))) if("listen") set_listening(!listening) . = TRUE @@ -516,10 +515,6 @@ recalculateChannels() . = TRUE -/obj/item/radio/suicide_act(mob/living/user) - user.visible_message(span_suicide("[user] starts bouncing [src] off [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!")) - return BRUTELOSS - /obj/item/radio/examine(mob/user) . = ..() if (frequency && in_range(src, user)) @@ -538,6 +533,11 @@ if(listening && overlay_speaker_idle) . += overlay_speaker_idle +/obj/item/radio/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(user.combat_mode && tool.tool_behaviour == TOOL_SCREWDRIVER) + return screwdriver_act(user, tool) + return ..() + /obj/item/radio/screwdriver_act(mob/living/user, obj/item/tool) add_fingerprint(user) unscrewed = !unscrewed @@ -591,7 +591,7 @@ channels[ch_name] = TRUE /obj/item/radio/borg/syndicate - syndie = TRUE + special_channels = RADIO_SPECIAL_SYNDIE keyslot = /obj/item/encryptionkey/syndicate /obj/item/radio/borg/syndicate/Initialize(mapload) @@ -639,4 +639,60 @@ . = ..() set_listening(FALSE) +// RADIOS USED BY BROADCASTING +/obj/item/radio/entertainment + desc = "You should not hold this." + canhear_range = 7 + freerange = TRUE + freqlock = RADIO_FREQENCY_LOCKED + radio_noise = FALSE + +/obj/item/radio/entertainment/Initialize(mapload) + . = ..() + set_frequency(FREQ_ENTERTAINMENT) + +/obj/item/radio/entertainment/speakers // Used inside of the entertainment monitors, not to be used as a actual item + should_be_listening = TRUE + should_be_broadcasting = FALSE + +/obj/item/radio/entertainment/speakers/Initialize(mapload) + . = ..() + set_broadcasting(FALSE) + set_listening(TRUE) + wires?.cut(WIRE_TX) + +/obj/item/radio/entertainment/speakers/on_receive_message(list/data) + playsound(source = src, soundin = SFX_MUFFLED_SPEECH, vol = 60, extrarange = -4, vary = TRUE, ignore_walls = FALSE) + + return ..() + +/obj/item/radio/entertainment/speakers/physical // Can be used as a physical item + name = "entertainment radio" + desc = "A portable one-way radio permamently tuned into entertainment frequency." + icon_state = "radio" + inhand_icon_state = "radio" + worn_icon_state = "radio" + overlay_speaker_idle = "radio_s_idle" + overlay_speaker_active = "radio_s_active" + overlay_mic_idle = "radio_m_idle" + overlay_mic_active = "radio_m_active" + +/obj/item/radio/entertainment/microphone // Used inside of a broadcast camera, not to be used as a actual item + should_be_listening = FALSE + should_be_broadcasting = TRUE + +/obj/item/radio/entertainment/microphone/Initialize(mapload) + . = ..() + set_broadcasting(TRUE) + set_listening(FALSE) + wires?.cut(WIRE_RX) + +/obj/item/radio/entertainment/microphone/physical // Can be used as a physical item + name = "microphone" + desc = "No comments." + icon = 'icons/obj/service/broadcast.dmi' + icon_state = "microphone" + inhand_icon_state = "microphone" + canhear_range = 3 + #undef FREQ_LISTENING diff --git a/code/game/objects/items/devices/scanners/health_analyzer.dm b/code/game/objects/items/devices/scanners/health_analyzer.dm index bebafbdab83b7..26df57683aa26 100644 --- a/code/game/objects/items/devices/scanners/health_analyzer.dm +++ b/code/game/objects/items/devices/scanners/health_analyzer.dm @@ -132,7 +132,7 @@ * tochat - Whether to immediately post the result into the chat of the user, otherwise it will return the results. */ /proc/healthscan(mob/user, mob/living/target, mode = SCANNER_VERBOSE, advanced = FALSE, tochat = TRUE) - if(user.incapacitated()) + if(user.incapacitated) return // the final list of strings to render @@ -409,7 +409,7 @@ return(jointext(render_list, "")) /proc/chemscan(mob/living/user, mob/living/target) - if(user.incapacitated()) + if(user.incapacitated) return if(istype(target) && target.reagents) @@ -495,7 +495,7 @@ /// Displays wounds with extended information on their status vs medscanners /proc/woundscan(mob/user, mob/living/carbon/patient, obj/item/healthanalyzer/scanner, simple_scan = FALSE) - if(!istype(patient) || user.incapacitated()) + if(!istype(patient) || user.incapacitated) return var/render_list = "" @@ -664,7 +664,7 @@ /// Checks the individual for any diseases that are visible to the scanner, and displays the diseases in the attacked to the attacker. /proc/diseasescan(mob/user, mob/living/carbon/patient, obj/item/healthanalyzer/simple/scanner) - if(!istype(patient) || user.incapacitated()) + if(!istype(patient) || user.incapacitated) return var/list/render = list() diff --git a/code/game/objects/items/devices/swapper.dm b/code/game/objects/items/devices/swapper.dm index dee9198c93296..fc5a9d39f9742 100644 --- a/code/game/objects/items/devices/swapper.dm +++ b/code/game/objects/items/devices/swapper.dm @@ -97,7 +97,7 @@ return teleportable /obj/item/swapper/proc/swap(mob/user) - if(QDELETED(linked_swapper) || world.time < linked_swapper.cooldown) + if(QDELETED(linked_swapper) || isnull(linked_swapper.loc) || world.time < linked_swapper.cooldown) return var/atom/movable/A = get_teleportable_container() diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm index d30f379197eea..b86489fae9ea7 100644 --- a/code/game/objects/items/devices/taperecorder.dm +++ b/code/game/objects/items/devices/taperecorder.dm @@ -122,7 +122,7 @@ /obj/item/taperecorder/proc/can_use(mob/user) if(user && ismob(user)) - if(!user.incapacitated()) + if(!user.incapacitated) return TRUE return FALSE diff --git a/code/game/objects/items/food/bait.dm b/code/game/objects/items/food/bait.dm index 41b50c181f287..f31eb44f308eb 100644 --- a/code/game/objects/items/food/bait.dm +++ b/code/game/objects/items/food/bait.dm @@ -60,15 +60,23 @@ */ /obj/item/food/bait/doughball/synthetic name = "synthetic doughball" - icon_state = "doughball" + icon_state = "doughball_blue" preserved_food = TRUE /obj/item/food/bait/doughball/synthetic/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_OMNI_BAIT, INNATE_TRAIT) +///Found in the can of omni-baits, only available from the super fishing toolbox, from the fishing mystery box. +/obj/item/food/bait/doughball/synthetic/super + name = "super-doughball" + desc = "No fish will be able to resist this." + bait_quality = TRAIT_GREAT_QUALITY_BAIT + +///Used by the advanced fishing rod /obj/item/food/bait/doughball/syntethic/unconsumable /obj/item/food/bait/doughball/synthetic/unconsumable/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_BAIT_UNCONSUMABLE, INNATE_TRAIT) + diff --git a/code/game/objects/items/food/cake.dm b/code/game/objects/items/food/cake.dm index 0b443554bb3b6..ec3e0a0390caa 100644 --- a/code/game/objects/items/food/cake.dm +++ b/code/game/objects/items/food/cake.dm @@ -45,6 +45,10 @@ foodtypes = GRAIN | DAIRY | SUGAR slice_type = /obj/item/food/cakeslice/plain +/obj/item/food/cake/plain/Initialize(mapload) + . = ..() + AddComponent(/datum/component/customizable_reagent_holder, /obj/item/food/cake/empty, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 16) + /obj/item/food/cakeslice/plain name = "plain cake slice" desc = "Just a slice of cake, it is enough for everyone." @@ -52,6 +56,23 @@ tastes = list("sweetness" = 2, "cake" = 5) foodtypes = GRAIN | DAIRY | SUGAR +/obj/item/food/cake/empty + name = "cake" + desc = "A custom cake made by an insane chef." + icon_state = "cake_custom" + foodtypes = GRAIN | DAIRY | SUGAR + slice_type = /obj/item/food/cakeslice/empty + +/obj/item/food/cakeslice/empty + name = "cake slice" + desc = "A slice of custom cake, made by an insane chef." + icon_state = "cake_custom_slice" + foodtypes = GRAIN | DAIRY | SUGAR + +/obj/item/food/cakeslice/empty/Initialize(mapload) + . = ..() + AddComponent(/datum/component/customizable_reagent_holder, null, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 16) + /obj/item/food/cake/carrot name = "carrot cake" desc = "A favorite desert of a certain wascally wabbit. Not a lie." @@ -521,6 +542,7 @@ foodtypes = GRAIN | SUGAR | DAIRY slice_type = /obj/item/food/cakeslice/clown_slice crafting_complexity = FOOD_COMPLEXITY_5 + crafted_food_buff = /datum/status_effect/food/trait/waddle /obj/item/food/cakeslice/clown_slice name = "clown cake slice" @@ -534,6 +556,7 @@ tastes = list("cake" = 1, "sugar" = 1, "joy" = 10) foodtypes = GRAIN | SUGAR | DAIRY crafting_complexity = FOOD_COMPLEXITY_5 + crafted_food_buff = /datum/status_effect/food/trait/waddle /obj/item/food/cake/trumpet name = "spaceman's cake" diff --git a/code/game/objects/items/food/egg.dm b/code/game/objects/items/food/egg.dm index b669e16b103cd..bcc61e721e211 100644 --- a/code/game/objects/items/food/egg.dm +++ b/code/game/objects/items/food/egg.dm @@ -277,6 +277,7 @@ GLOBAL_VAR_INIT(chicks_from_eggs, 0) foodtypes = MEAT | BREAKFAST | DAIRY venue_value = FOOD_PRICE_CHEAP crafting_complexity = FOOD_COMPLEXITY_2 + crafted_food_buff = /datum/status_effect/food/speech/french /obj/item/food/omelette/attackby(obj/item/item, mob/user, params) if(istype(item, /obj/item/kitchen/fork)) diff --git a/code/game/objects/items/food/meatslab.dm b/code/game/objects/items/food/meatslab.dm index a5fe073e56f3f..c59051ef664f3 100644 --- a/code/game/objects/items/food/meatslab.dm +++ b/code/game/objects/items/food/meatslab.dm @@ -353,7 +353,7 @@ /obj/item/food/meat/rawbacon name = "raw piece of bacon" desc = "A raw piece of bacon." - icon_state = "baconb" + icon_state = "bacon" bite_consumption = 2 food_reagents = list( /datum/reagent/consumable/nutriment/protein = 2, @@ -369,7 +369,7 @@ /obj/item/food/meat/bacon name = "piece of bacon" desc = "A delicious piece of bacon." - icon_state = "baconcookedb" + icon_state = "baconcooked" food_reagents = list( /datum/reagent/consumable/nutriment/protein = 2, /datum/reagent/consumable/nutriment/vitamin = 1, diff --git a/code/game/objects/items/food/mexican.dm b/code/game/objects/items/food/mexican.dm index 396e351ff4bde..c4349ca38c673 100644 --- a/code/game/objects/items/food/mexican.dm +++ b/code/game/objects/items/food/mexican.dm @@ -196,6 +196,7 @@ w_class = WEIGHT_CLASS_SMALL venue_value = FOOD_PRICE_LEGENDARY crafting_complexity = FOOD_COMPLEXITY_5 + crafted_food_buff = /datum/status_effect/food/trait/ashstorm_immune /obj/item/food/chipsandsalsa name = "chips and salsa" diff --git a/code/game/objects/items/food/pastries.dm b/code/game/objects/items/food/pastries.dm index 1024e44c625f3..0b96101a99d51 100644 --- a/code/game/objects/items/food/pastries.dm +++ b/code/game/objects/items/food/pastries.dm @@ -67,7 +67,6 @@ name = "waffles" desc = "Mmm, waffles." icon_state = "waffles" - trash_type = /obj/item/trash/waffles food_reagents = list( /datum/reagent/consumable/nutriment = 8, /datum/reagent/consumable/nutriment/vitamin = 2, @@ -85,7 +84,6 @@ name = "\improper Soylent Green" desc = "Not made of people. Honest." //Totally people. icon_state = "soylent_green" - trash_type = /obj/item/trash/waffles food_reagents = list( /datum/reagent/consumable/nutriment = 10, /datum/reagent/consumable/nutriment/vitamin = 2, @@ -100,7 +98,6 @@ name = "\improper Soylent Virdians" desc = "Not made of people. Honest." //Actually honest for once. icon_state = "soylent_yellow" - trash_type = /obj/item/trash/waffles food_reagents = list( /datum/reagent/consumable/nutriment = 10, /datum/reagent/consumable/nutriment/vitamin = 2, @@ -115,7 +112,6 @@ name = "roffle waffles" desc = "Waffles from Roffle. Co." icon_state = "rofflewaffles" - trash_type = /obj/item/trash/waffles bite_consumption = 4 food_reagents = list( /datum/reagent/consumable/nutriment = 8, @@ -327,6 +323,20 @@ tastes = list("cake" = 3, "blue cherry" = 1) crafting_complexity = FOOD_COMPLEXITY_3 +/obj/item/food/jupitercupcake + name = "jupiter-cup-cake" + desc = "A static dessert." + icon_state = "jupitercupcake" + food_reagents = list( + /datum/reagent/consumable/nutriment = 6, + /datum/reagent/consumable/nutriment/vitamin = 2, + /datum/reagent/consumable/caramel = 3, + /datum/reagent/consumable/liquidelectricity/enriched = 3, + ) + tastes = list("cake" = 3, "caramel" = 2, "zap" = 1) + crafting_complexity = FOOD_COMPLEXITY_3 + crafted_food_buff = /datum/status_effect/food/trait/shockimmune + /obj/item/food/honeybun name = "honey bun" desc = "A sticky pastry bun glazed with honey." diff --git a/code/game/objects/items/food/pie.dm b/code/game/objects/items/food/pie.dm index e57759915208d..2eb6057e4f5c7 100644 --- a/code/game/objects/items/food/pie.dm +++ b/code/game/objects/items/food/pie.dm @@ -39,6 +39,27 @@ foodtypes = GRAIN crafting_complexity = FOOD_COMPLEXITY_2 +/obj/item/food/pie/plain/Initialize(mapload) + . = ..() + AddComponent(/datum/component/customizable_reagent_holder, /obj/item/food/pie/empty, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 8) + +/obj/item/food/pie/empty + name = "pie" + desc = "A custom pie made by a crazed chef." + icon_state = "pie_custom" + foodtypes = GRAIN + slice_type = /obj/item/food/pieslice/empty + +/obj/item/food/pieslice/empty + name = "pie slice" + desc = "A custom pie slice made by a crazed chef." + icon_state = "pie_custom_slice" + foodtypes = GRAIN + +/obj/item/food/pieslice/empty/Initialize(mapload) + . = ..() + AddComponent(/datum/component/customizable_reagent_holder, null, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 8) + /obj/item/food/pie/cream name = "banana cream pie" desc = "Just like back home, on clown planet! HONK!" @@ -77,7 +98,7 @@ living_target_getting_hit.visible_message(span_warning("[living_target_getting_hit] is creamed by [src]!"), span_userdanger("You've been creamed by [src]!")) playsound(living_target_getting_hit, SFX_DESECRATION, 50, TRUE) if(is_creamable && is_type_in_typecache(hit_atom, GLOB.creamable)) - hit_atom.AddComponent(/datum/component/creamed, src) + hit_atom.AddComponent(/datum/component/face_decal/creampie, "creampie", EXTERNAL_FRONT) qdel(src) /obj/item/food/pie/cream/nostun @@ -316,6 +337,7 @@ ) tastes = list("nothing" = 3) foodtypes = GRAIN + crafted_food_buff = /datum/status_effect/food/trait/mute /obj/item/food/pie/berrytart name = "berry tart" diff --git a/code/game/objects/items/food/spaghetti.dm b/code/game/objects/items/food/spaghetti.dm index cab4a62a29f3b..bf1fca9332a08 100644 --- a/code/game/objects/items/food/spaghetti.dm +++ b/code/game/objects/items/food/spaghetti.dm @@ -249,3 +249,17 @@ tastes = list("noodles" = 5, "fried tofu" = 4, "lime" = 2, "peanut" = 3, "onion" = 2) foodtypes = GRAIN | VEGETABLES | NUTS | FRUIT crafting_complexity = FOOD_COMPLEXITY_4 + +/obj/item/food/spaghetti/carbonara + name = "spaghetti carbonara" + desc = "Silky eggs, crispy pork, cheesy bliss. Mamma mia!" + icon_state = "carbonara" + food_reagents = list( + /datum/reagent/consumable/nutriment = 10, + /datum/reagent/consumable/nutriment/protein = 6, + /datum/reagent/consumable/nutriment/vitamin = 4, + ) + tastes = list("spaghetti" = 1, "parmigiano reggiano" = 1, "guanciale" = 1) + foodtypes = GRAIN | MEAT | DAIRY + crafting_complexity = FOOD_COMPLEXITY_4 + crafted_food_buff = /datum/status_effect/food/speech/italian diff --git a/code/game/objects/items/grenades/_grenade.dm b/code/game/objects/items/grenades/_grenade.dm index bb9d275fb00b8..e8e04e3921b73 100644 --- a/code/game/objects/items/grenades/_grenade.dm +++ b/code/game/objects/items/grenades/_grenade.dm @@ -19,6 +19,7 @@ max_integrity = 40 pickup_sound = 'sound/items/grenade_pick_up.ogg' drop_sound = 'sound/items/grenade_drop.ogg' + sound_vary = TRUE /// Bitfields which prevent the grenade from detonating if set. Includes ([GRENADE_DUD]|[GRENADE_USED]) var/dud_flags = NONE ///Is this grenade currently armed? diff --git a/code/game/objects/items/hand_items.dm b/code/game/objects/items/hand_items.dm index 8030eed9883a9..cf752bf82accb 100644 --- a/code/game/objects/items/hand_items.dm +++ b/code/game/objects/items/hand_items.dm @@ -532,6 +532,12 @@ color = COLOR_BLACK kiss_type = /obj/projectile/kiss/death +/obj/item/hand_item/kisser/syndie + name = "syndie kiss" + desc = "oooooo you like syndicate ur a syndiekisser" + color = COLOR_SYNDIE_RED + kiss_type = /obj/projectile/kiss/syndie + /obj/projectile/kiss name = "kiss" icon = 'icons/mob/simple/animal.dmi' @@ -543,17 +549,21 @@ damage_type = BRUTE damage = 0 // love can't actually hurt you armour_penetration = 100 // but if it could, it would cut through even the thickest plate + var/silent_blown = FALSE /obj/projectile/kiss/Initialize(mapload) . = ..() AddComponent(/datum/component/parriable_projectile) /obj/projectile/kiss/fire(angle, atom/direct_target) - if(firer) + if(firer && !silent_blown) name = "[name] blown by [firer]" + return ..() /obj/projectile/kiss/Impact(atom/A) + def_zone = BODY_ZONE_HEAD // let's keep it PG, people + if(damage > 0 || !isliving(A)) // if we do damage or we hit a nonliving thing, we don't have to worry about a harmless hit because we can't wrongly do damage anyway return ..() @@ -607,7 +617,6 @@ living_target.visible_message("[living_target] [other_msg]", span_userdanger("Whoa! [self_msg]")) /obj/projectile/kiss/on_hit(atom/target, blocked, pierce_hit) - def_zone = BODY_ZONE_HEAD // let's keep it PG, people . = ..() if(isliving(target)) var/mob/living/living_target = target @@ -629,6 +638,18 @@ var/obj/item/organ/internal/heart/dont_go_breakin_my_heart = heartbreakee.get_organ_slot(ORGAN_SLOT_HEART) dont_go_breakin_my_heart.apply_organ_damage(999) +// Based on energy gun characteristics +/obj/projectile/kiss/syndie + name = "syndie kiss" + color = COLOR_SYNDIE_RED + impact_effect_type = /obj/effect/temp_visual/impact_effect/red_laser + damage_type = BURN + armor_flag = LASER + armour_penetration = 0 + damage = 25 + wound_bonus = -20 + bare_wound_bonus = 40 + silent_blown = TRUE /obj/projectile/kiss/french name = "french kiss (is that a hint of garlic?)" diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm index 7edc000920454..9e8f1d7308860 100644 --- a/code/game/objects/items/handcuffs.dm +++ b/code/game/objects/items/handcuffs.dm @@ -50,6 +50,7 @@ custom_price = PAYCHECK_COMMAND * 0.35 pickup_sound = 'sound/items/handcuffs_pick_up.ogg' drop_sound = 'sound/items/handcuffs_drop.ogg' + sound_vary = TRUE ///How long it takes to handcuff someone var/handcuff_time = 4 SECONDS diff --git a/code/game/objects/items/inducer.dm b/code/game/objects/items/inducer.dm index d74bb7aa8d10e..2404974d69970 100644 --- a/code/game/objects/items/inducer.dm +++ b/code/game/objects/items/inducer.dm @@ -81,9 +81,9 @@ return /obj/item/inducer/attackby(obj/item/used_item, mob/user) + var/obj/item/stock_parts/power_store/our_cell = get_cell() if(istype(used_item, /obj/item/stock_parts/power_store)) if(opened) - var/obj/item/stock_parts/power_store/our_cell = get_cell() if(isnull(our_cell)) if(!user.transferItemToLoc(used_item, src)) return @@ -95,6 +95,15 @@ to_chat(user, span_warning("[src] already has \a [our_cell] installed!")) return + if (istype(used_item, /obj/item/stack/sheet/mineral/plasma) && !isnull(our_cell)) + if(our_cell.charge == our_cell.maxcharge) + balloon_alert(user, "already fully charged!") + return + used_item.use(1) + our_cell.give(1.5 * STANDARD_CELL_CHARGE) + balloon_alert(user, "cell recharged") + return + if(cantbeused(user)) return @@ -187,7 +196,7 @@ opened = TRUE /obj/item/inducer/orderable - cell_type = /obj/item/stock_parts/power_store/cell/inducer_supply + cell_type = /obj/item/stock_parts/power_store/battery/upgraded opened = FALSE /obj/item/inducer/sci diff --git a/code/game/objects/items/kirby_plants/kirbyplants.dm b/code/game/objects/items/kirby_plants/kirbyplants.dm index 26199bcd42c9c..0c5b255db38b6 100644 --- a/code/game/objects/items/kirby_plants/kirbyplants.dm +++ b/code/game/objects/items/kirby_plants/kirbyplants.dm @@ -1,4 +1,3 @@ - /obj/item/kirbyplants name = "potted plant" icon = 'icons/obj/fluff/flora/plants.dmi' diff --git a/code/game/objects/items/maintenance_loot.dm b/code/game/objects/items/maintenance_loot.dm index 51a272509969c..74d908732a562 100644 --- a/code/game/objects/items/maintenance_loot.dm +++ b/code/game/objects/items/maintenance_loot.dm @@ -20,6 +20,9 @@ wound_bonus = 20 demolition_mod = 1.25 grind_results = list(/datum/reagent/lead = 20) + pickup_sound = 'sound/items/lead_pipe_pickup.ogg' + drop_sound = 'sound/items/lead_pipe_drop.ogg' + hitsound = 'sound/items/lead_pipe_hit.ogg' //A good battery early in the shift. Source of lead & sulfuric acid reagents. //Add lead material to this once implemented. diff --git a/code/game/objects/items/melee/baton.dm b/code/game/objects/items/melee/baton.dm index 4af5c4c923e75..8c1ae33c4c70e 100644 --- a/code/game/objects/items/melee/baton.dm +++ b/code/game/objects/items/melee/baton.dm @@ -12,6 +12,7 @@ force = 12 //9 hit crit w_class = WEIGHT_CLASS_NORMAL wound_bonus = 15 + sound_vary = TRUE /// Whether this baton is active or not var/active = TRUE @@ -318,9 +319,13 @@ bare_wound_bonus = 5 clumsy_knockdown_time = 15 SECONDS active = FALSE - pickup_sound = 'sound/items/stun_baton_pick_up.ogg' - drop_sound = 'sound/items/stun_baton_drop.ogg' - + var/folded_drop_sound = 'sound/items/baton/telescopic_baton_folded_drop.ogg' + var/folded_pickup_sound = 'sound/items/baton/telescopic_baton_folded_pickup.ogg' + var/unfolded_drop_sound = 'sound/items/baton/telescopic_baton_unfolded_drop.ogg' + var/unfolded_pickup_sound = 'sound/items/baton/telescopic_baton_unfolded_pickup.ogg' + pickup_sound = 'sound/items/baton/telescopic_baton_folded_pickup.ogg' + drop_sound = 'sound/items/baton/telescopic_baton_folded_drop.ogg' + sound_vary = TRUE /// The sound effecte played when our baton is extended. var/on_sound = 'sound/weapons/batonextend.ogg' /// The inhand iconstate used when our baton is extended. @@ -376,6 +381,12 @@ inhand_icon_state = active ? on_inhand_icon_state : null // When inactive, there is no inhand icon_state. if(user) balloon_alert(user, active ? "extended" : "collapsed") + if(!active) + drop_sound = folded_drop_sound + pickup_sound = folded_pickup_sound + else + drop_sound = unfolded_drop_sound + pickup_sound = unfolded_pickup_sound playsound(src, on_sound, 50, TRUE) return COMPONENT_NO_DEFAULT_MESSAGE @@ -397,6 +408,8 @@ clumsy_knockdown_time = 24 SECONDS affect_cyborg = TRUE on_stun_sound = 'sound/effects/contractorbatonhit.ogg' + unfolded_drop_sound = 'sound/items/baton/contractor_baton_unfolded_pickup.ogg' + unfolded_pickup_sound = 'sound/items/baton/contractor_baton_unfolded_pickup.ogg' on_inhand_icon_state = "contractor_baton_on" on_sound = 'sound/weapons/contractorbatonextend.ogg' @@ -438,9 +451,13 @@ light_on = FALSE light_color = LIGHT_COLOR_ORANGE light_power = 0.5 - pickup_sound = 'sound/items/stun_baton_pick_up.ogg' - drop_sound = 'sound/items/stun_baton_drop.ogg' - + var/inactive_drop_sound = 'sound/items/baton/stun_baton_inactive_drop.ogg' + var/inactive_pickup_sound = 'sound/items/baton/stun_baton_inactive_pickup.ogg' + var/active_drop_sound = 'sound/items/baton/stun_baton_active_drop.ogg' + var/active_pickup_sound = 'sound/items/baton/stun_baton_active_pickup.ogg' + drop_sound = 'sound/items/baton/stun_baton_inactive_drop.ogg' + pickup_sound = 'sound/items/baton/stun_baton_inactive_pickup.ogg' + sound_vary = TRUE var/throw_stun_chance = 35 var/obj/item/stock_parts/power_store/cell @@ -501,15 +518,14 @@ SIGNAL_HANDLER if(!active) return - toggle_light() - active = FALSE + turn_off() update_appearance() return COMSIG_SABOTEUR_SUCCESS /obj/item/melee/baton/security/Exited(atom/movable/mov_content) . = ..() if(mov_content == cell) cell = null - active = FALSE + turn_off() update_appearance() /obj/item/melee/baton/security/update_icon_state() @@ -559,26 +575,41 @@ return FALSE /obj/item/melee/baton/security/attack_self(mob/user) - if(cell?.charge >= cell_hit_cost) - active = !active - balloon_alert(user, "turned [active ? "on" : "off"]") - playsound(src, SFX_SPARKS, 75, TRUE, -1) - toggle_light(user) - do_sparks(1, TRUE, src) + if(cell?.charge >= cell_hit_cost && !active) + turn_on(user) + balloon_alert(user, "turned on") else - active = FALSE + turn_off() if(!cell) balloon_alert(user, "no power source!") - else + else if(cell?.charge < cell_hit_cost) balloon_alert(user, "out of charge!") - update_appearance() + else + balloon_alert(user, "turned off") add_fingerprint(user) /// Toggles the stun baton's light -/obj/item/melee/baton/security/proc/toggle_light(mob/user) +/obj/item/melee/baton/security/proc/toggle_light() set_light_on(!light_on) return +/obj/item/melee/baton/security/proc/turn_on(mob/user) + active = TRUE + playsound(src, SFX_SPARKS, 75, TRUE, -1) + update_appearance() + toggle_light() + do_sparks(1, TRUE, src) + drop_sound = active_drop_sound + pickup_sound = active_pickup_sound + +/obj/item/melee/baton/security/proc/turn_off() + active = FALSE + set_light_on(FALSE) + update_appearance() + playsound(src, SFX_SPARKS, 75, TRUE, -1) + drop_sound = inactive_drop_sound + pickup_sound = inactive_pickup_sound + /obj/item/melee/baton/security/proc/deductcharge(deducted_charge) if(!cell) return @@ -587,10 +618,7 @@ . = cell.use(deducted_charge) if(active && cell.charge < cell_hit_cost) //we're below minimum, turn off - active = FALSE - set_light_on(FALSE) - update_appearance() - playsound(src, SFX_SPARKS, 75, TRUE, -1) + turn_off() /obj/item/melee/baton/security/clumsy_check(mob/living/carbon/human/user) . = ..() diff --git a/code/game/objects/items/paint.dm b/code/game/objects/items/paint.dm index 41c1809b5589e..66e0b15e99fd7 100644 --- a/code/game/objects/items/paint.dm +++ b/code/game/objects/items/paint.dm @@ -108,7 +108,7 @@ return FALSE if(!user.is_holding(src)) return FALSE - if(user.incapacitated()) + if(user.incapacitated) return FALSE return TRUE diff --git a/code/game/objects/items/pinpointer.dm b/code/game/objects/items/pinpointer.dm index 5d7fc1957f4f4..526b5ca2e985e 100644 --- a/code/game/objects/items/pinpointer.dm +++ b/code/game/objects/items/pinpointer.dm @@ -152,7 +152,7 @@ return if(isnull(names[pinpoint_target])) return - if(QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated()) + if(QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated) return target = names[pinpoint_target] toggle_on() diff --git a/code/game/objects/items/rcd/RCD.dm b/code/game/objects/items/rcd/RCD.dm index cf254e447818d..5bd0b4c9d39b8 100644 --- a/code/game/objects/items/rcd/RCD.dm +++ b/code/game/objects/items/rcd/RCD.dm @@ -16,6 +16,9 @@ item_flags = NO_MAT_REDEMPTION | NOBLUDGEON has_ammobar = TRUE actions_types = list(/datum/action/item_action/rcd_scan) + drop_sound = 'sound/items/handling/rcd_drop.ogg' + pickup_sound = 'sound/items/handling/rcd_pickup.ogg' + sound_vary = TRUE /// main category of currently selected design[Structures, Airlocks, Airlock Access] var/root_category @@ -103,7 +106,7 @@ T.rcd_act(user, src, list("[RCD_DESIGN_MODE]" = RCD_TURF, "[RCD_DESIGN_PATH]" = /turf/open/floor/plating/rcd)) useResource(16, user) activate() - playsound(loc, 'sound/machines/click.ogg', 50, 1) + playsound(get_turf(user), SFX_TOOL_SWITCH, 20, TRUE) user.gib(DROP_ALL_REMAINS) return MANUAL_SUICIDE @@ -144,7 +147,7 @@ //check if we can build our window on the grill if(target_turf.is_blocked_turf(exclude_mobs = !is_full_tile, source_atom = null, ignore_atoms = structures_to_ignore, type_list = TRUE)) - playsound(loc, 'sound/machines/click.ogg', 50, TRUE) + playsound(get_turf(user), SFX_TOOL_SWITCH, 20, TRUE) balloon_alert(user, "something is blocking the turf") return FALSE @@ -155,7 +158,7 @@ else if(rcd_mode == RCD_TURF && rcd_structure == /turf/open/floor/plating/rcd && (!istype(target_turf, /turf/open/floor) || istype(target, /obj/structure/girder))) //if a player builds a wallgirder on top of himself manually with iron sheets he can't finish the wall if he is still on the girder. Exclude the girder itself when checking for other dense objects on the turf if(istype(target, /obj/structure/girder) && target_turf.is_blocked_turf(exclude_mobs = FALSE, source_atom = null, ignore_atoms = list(target))) - playsound(loc, 'sound/machines/click.ogg', 50, TRUE) + playsound(get_turf(user), SFX_TOOL_SWITCH, 20, TRUE) balloon_alert(user, "something is on the girder!") return FALSE @@ -190,7 +193,7 @@ //check if the structure can fit on this turf if(target_turf.is_blocked_turf(exclude_mobs = ignore_mobs, source_atom = null, ignore_atoms = ignored_types, type_list = TRUE)) - playsound(loc, 'sound/machines/click.ogg', 50, TRUE) + playsound(get_turf(user), SFX_TOOL_SWITCH, 20, TRUE) balloon_alert(user, "something is on the tile!") return FALSE @@ -341,6 +344,7 @@ return data /obj/item/construction/rcd/handle_ui_act(action, params, datum/tgui/ui, datum/ui_state/state) + playsound(src, SFX_TOOL_SWITCH, 20, TRUE) switch(action) if("root_category") diff --git a/code/game/objects/items/rcd/RHD.dm b/code/game/objects/items/rcd/RHD.dm index 64179a81b5fb4..a212274ce46be 100644 --- a/code/game/objects/items/rcd/RHD.dm +++ b/code/game/objects/items/rcd/RHD.dm @@ -292,7 +292,7 @@ /obj/item/construction/proc/check_menu(mob/living/user, remote_anchor) if(!istype(user)) return FALSE - if(user.incapacitated()) + if(user.incapacitated) return FALSE if(remote_anchor && user.remote_control != remote_anchor) return FALSE diff --git a/code/game/objects/items/rcd/RPD.dm b/code/game/objects/items/rcd/RPD.dm index 41a962ed7e7de..caa96e176a27d 100644 --- a/code/game/objects/items/rcd/RPD.dm +++ b/code/game/objects/items/rcd/RPD.dm @@ -59,6 +59,8 @@ GLOBAL_LIST_INIT(disposal_pipe_recipes, list( new /datum/pipe_info/disposal("Sort Junction", /obj/structure/disposalpipe/sorting/mail, PIPE_TRIN_M), new /datum/pipe_info/disposal("Rotator", /obj/structure/disposalpipe/rotator, PIPE_ONEDIR_FLIPPABLE), new /datum/pipe_info/disposal("Trunk", /obj/structure/disposalpipe/trunk), + new /datum/pipe_info/disposal("Down Turn", /obj/structure/disposalpipe/trunk/multiz/down), + new /datum/pipe_info/disposal("Up Turn", /obj/structure/disposalpipe/trunk/multiz), new /datum/pipe_info/disposal("Bin", /obj/machinery/disposal/bin, PIPE_ONEDIR), new /datum/pipe_info/disposal("Outlet", /obj/structure/disposaloutlet), new /datum/pipe_info/disposal("Chute", /obj/machinery/disposal/delivery_chute), @@ -142,6 +144,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( /datum/pipe_info/meter icon_state = "meter" dirtype = PIPE_ONEDIR + all_layers = TRUE /datum/pipe_info/meter/New(label) name = label @@ -182,6 +185,9 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( custom_materials = list(/datum/material/iron=SHEET_MATERIAL_AMOUNT*37.5, /datum/material/glass=SHEET_MATERIAL_AMOUNT*18.75) armor_type = /datum/armor/item_pipe_dispenser resistance_flags = FIRE_PROOF + drop_sound = 'sound/items/handling/rpd_drop.ogg' + pickup_sound = 'sound/items/handling/rpd_pickup.ogg' + sound_vary = TRUE ///Sparks system used when changing device in the UI var/datum/effect_system/spark_spread/spark_system ///Direction of the device we are going to spawn, set up in the UI @@ -293,7 +299,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( /obj/item/pipe_dispenser/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] points the end of the RPD down [user.p_their()] throat and presses a button! It looks like [user.p_theyre()] trying to commit suicide...")) - playsound(get_turf(user), 'sound/machines/click.ogg', 50, TRUE) + playsound(get_turf(user), SFX_TOOL_SWITCH, 20, TRUE) playsound(get_turf(user), RPD_USE_SOUND, 50, TRUE) return BRUTELOSS @@ -362,6 +368,8 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( if(.) return + playsound(src, SFX_TOOL_SWITCH, 20, TRUE) + var/playeffect = TRUE switch(action) if("color") @@ -456,7 +464,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( . = TRUE if((mode & DESTROY_MODE) && istype(attack_target, /obj/item/pipe) || istype(attack_target, /obj/structure/disposalconstruct) || istype(attack_target, /obj/structure/c_transit_tube) || istype(attack_target, /obj/structure/c_transit_tube_pod) || istype(attack_target, /obj/item/pipe_meter) || istype(attack_target, /obj/structure/disposalpipe/broken)) - playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE) + playsound(get_turf(src), SFX_TOOL_SWITCH, 20, TRUE) playsound(get_turf(src), RPD_USE_SOUND, 50, TRUE) qdel(attack_target) return @@ -478,7 +486,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( balloon_alert(user, "already configured for its directions!") return - playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE) + playsound(get_turf(src), SFX_TOOL_SWITCH, 20, TRUE) // Something else could have changed the target's state while we were waiting in do_after // Most of the edge cases don't matter, but atmos components being able to have live connections not described by initializable directions sounds like a headache at best and an exploit at worst @@ -542,7 +550,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( if(isclosedturf(attack_target)) balloon_alert(user, "target is blocked!") return - playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE) + playsound(get_turf(src), SFX_TOOL_SWITCH, 20, TRUE) if(do_after(user, disposal_build_speed, target = attack_target)) var/obj/structure/disposalconstruct/new_disposals_segment = new (attack_target, queued_pipe_type, queued_pipe_dir, queued_pipe_flipped) @@ -572,7 +580,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( balloon_alert(user, "something in the way!") return - playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE) + playsound(get_turf(src), SFX_TOOL_SWITCH, 20, TRUE) if(do_after(user, transit_build_speed, target = attack_target)) playsound(get_turf(src), RPD_USE_SOUND, 50, TRUE) if(queued_pipe_type == /obj/structure/c_transit_tube_pod) @@ -619,7 +627,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( return FALSE if(!can_make_pipe) return FALSE - playsound(get_turf(src), 'sound/machines/click.ogg', 50, vary = TRUE) + playsound(get_turf(src), SFX_TOOL_SWITCH, 20, vary = TRUE) if(!continued_build && !do_after(user, atmos_build_speed, target = atom_to_target)) return FALSE if(!recipe.all_layers && (layer_to_build == 1 || layer_to_build == 5)) @@ -681,7 +689,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( if(multi_layer) balloon_alert(source_mob, "turn off multi layer!") return - if(source_mob.incapacitated(IGNORE_RESTRAINTS|IGNORE_STASIS)) + if(INCAPACITATED_IGNORING(source_mob, INCAPABLE_RESTRAINTS|INCAPABLE_STASIS)) return if(source_mob.get_active_held_item() != src) return diff --git a/code/game/objects/items/rcd/RPLD.dm b/code/game/objects/items/rcd/RPLD.dm index 56452e2e452b1..4872dffde362e 100644 --- a/code/game/objects/items/rcd/RPLD.dm +++ b/code/game/objects/items/rcd/RPLD.dm @@ -12,6 +12,9 @@ banned_upgrades = RCD_ALL_UPGRADES & ~RCD_UPGRADE_SILO_LINK matter = 200 max_matter = 200 + drop_sound = 'sound/items/handling/rcd_drop.ogg' + pickup_sound = 'sound/items/handling/rcd_pickup.ogg' + sound_vary = TRUE ///category of design selected var/selected_category @@ -153,6 +156,8 @@ return data /obj/item/construction/plumbing/handle_ui_act(action, params, datum/tgui/ui, datum/ui_state/state) + playsound(src, SFX_TOOL_SWITCH, 20, TRUE) + switch(action) if("color") var/color = params["paint_color"] @@ -178,8 +183,6 @@ blueprint = design blueprint_changed = TRUE - playsound(src, 'sound/effects/pop.ogg', 50, vary = FALSE) - return TRUE @@ -285,7 +288,7 @@ /obj/item/construction/plumbing/proc/mouse_wheeled(mob/source, atom/A, delta_x, delta_y, params) SIGNAL_HANDLER - if(source.incapacitated(IGNORE_RESTRAINTS|IGNORE_STASIS)) + if(INCAPACITATED_IGNORING(source, INCAPABLE_RESTRAINTS|INCAPABLE_STASIS)) return if(delta_y == 0) return diff --git a/code/game/objects/items/rcd/RSF.dm b/code/game/objects/items/rcd/RSF.dm index ee85994143a00..e3d27620ce9ff 100644 --- a/code/game/objects/items/rcd/RSF.dm +++ b/code/game/objects/items/rcd/RSF.dm @@ -121,7 +121,7 @@ RSF return radial_list /obj/item/rsf/proc/check_menu(mob/user) - if(user.incapacitated() || !user.Adjacent(src)) + if(user.incapacitated || !user.Adjacent(src)) return FALSE return TRUE diff --git a/code/game/objects/items/rcd/RTD.dm b/code/game/objects/items/rcd/RTD.dm index 45b9c9e3687dd..93e5147175e4e 100644 --- a/code/game/objects/items/rcd/RTD.dm +++ b/code/game/objects/items/rcd/RTD.dm @@ -24,6 +24,9 @@ item_flags = NO_MAT_REDEMPTION | NOBLUDGEON has_ammobar = TRUE banned_upgrades = RCD_ALL_UPGRADES & ~RCD_UPGRADE_SILO_LINK + drop_sound = 'sound/items/handling/rcd_drop.ogg' + pickup_sound = 'sound/items/handling/rcd_pickup.ogg' + sound_vary = TRUE /// main category for tile design var/root_category = "Conventional" @@ -195,6 +198,7 @@ return data /obj/item/construction/rtd/handle_ui_act(action, params, datum/tgui/ui, datum/ui_state/state) + playsound(src, SFX_TOOL_SWITCH, 20, TRUE) var/floor_designs = GLOB.floor_designs switch(action) diff --git a/code/game/objects/items/rcd/RWD.dm b/code/game/objects/items/rcd/RWD.dm index 0ee29e87a352f..bafbfdc5d8dd9 100644 --- a/code/game/objects/items/rcd/RWD.dm +++ b/code/game/objects/items/rcd/RWD.dm @@ -152,7 +152,7 @@ if(!ISADVANCEDTOOLUSER(user)) to_chat(user, span_warning("You don't have the dexterity to do this!")) return FALSE - if(user.incapacitated() || !user.Adjacent(src)) + if(user.incapacitated || !user.Adjacent(src)) return FALSE return TRUE diff --git a/code/game/objects/items/robot/items/hypo.dm b/code/game/objects/items/robot/items/hypo.dm index 9a29ccbd9ef97..29773f329222b 100644 --- a/code/game/objects/items/robot/items/hypo.dm +++ b/code/game/objects/items/robot/items/hypo.dm @@ -90,6 +90,9 @@ /datum/reagent/consumable/ethanol/fernet,\ ) +#define REAGENT_CONTAINER_INTERNAL "internal_beaker" +#define REAGENT_CONTAINER_BEVAPPARATUS "beverage_apparatus" + ///Borg Hypospray /obj/item/reagent_containers/borghypo name = "cyborg hypospray" @@ -325,6 +328,7 @@ dispensed_temperature = WATER_MATTERSTATE_CHANGE_TEMP //Water stays wet, ice stays ice default_reagent_types = BASE_SERVICE_REAGENTS expanded_reagent_types = EXPANDED_SERVICE_REAGENTS + var/reagent_search_container = REAGENT_CONTAINER_BEVAPPARATUS /obj/item/reagent_containers/borghypo/borgshaker/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) @@ -332,6 +336,27 @@ ui = new(user, src, "BorgShaker", name) ui.open() +/obj/item/reagent_containers/borghypo/borgshaker/ui_act(action, params) + . = ..() + if(.) + return + var/mob/living/silicon/robot/user = usr + switch(action) + if("reaction_lookup") + if(!iscyborg(usr)) + return + if (reagent_search_container == REAGENT_CONTAINER_BEVAPPARATUS) + var/obj/item/borg/apparatus/beaker/service/beverage_apparatus = (locate() in user.model.modules) || (locate() in user.held_items) + if (!isnull(beverage_apparatus) && !isnull(beverage_apparatus.stored)) + beverage_apparatus.stored.reagents.ui_interact(user) + else if (reagent_search_container == REAGENT_CONTAINER_INTERNAL) + var/obj/item/reagent_containers/cup/beaker/large/internal_beaker = (locate() in user.model.modules) || (locate() in user.held_items) + if (!isnull(internal_beaker)) + internal_beaker.reagents.ui_interact(user) + if ("set_preferred_container") + reagent_search_container = params["value"] + return TRUE + /obj/item/reagent_containers/borghypo/borgshaker/ui_data(mob/user) var/list/drink_reagents = list() var/list/alcohol_reagents = list() @@ -354,6 +379,17 @@ data["sodas"] = drink_reagents data["alcohols"] = alcohol_reagents data["selectedReagent"] = selected_reagent?.name + data["reagentSearchContainer"] = reagent_search_container + + if(iscyborg(user)) + var/mob/living/silicon/robot/cyborg = user + var/obj/item/borg/apparatus/beaker/service/beverage_apparatus = (locate() in cyborg.model.modules) || (locate() in cyborg.held_items) + + if (isnull(beverage_apparatus)) + to_chat(user, span_warning("This unit has no beverage apparatus. This shouldn't be possible. Delete yourself, NOW!")) + data["apparatusHasItem"] = FALSE + else + data["apparatusHasItem"] = !isnull(beverage_apparatus.stored) return data /obj/item/reagent_containers/borghypo/borgshaker/attack(mob/M, mob/user) @@ -452,6 +488,8 @@ dispensed_temperature = WATER_MATTERSTATE_CHANGE_TEMP default_reagent_types = HACKED_SERVICE_REAGENTS +#undef REAGENT_CONTAINER_INTERNAL +#undef REAGENT_CONTAINER_BEVAPPARATUS #undef BASE_MEDICAL_REAGENTS #undef EXPANDED_MEDICAL_REAGENTS #undef HACKED_MEDICAL_REAGENTS diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index 7e954fbcec5cd..e496cfe43bfa3 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -121,14 +121,11 @@ if(chest) chest.forceMove(drop_to) - new /obj/item/stack/cable_coil(drop_to, 1) - chest.wired = FALSE - chest.cell?.forceMove(drop_to) + chest.drop_organs() if(head) - head.flash1?.forceMove(drop_to) - head.flash2?.forceMove(drop_to) head.forceMove(drop_to) + head.drop_organs() /obj/item/robot_suit/proc/put_in_hand_or_drop(mob/living/user, obj/item/I) //normal put_in_hands() drops the item ontop of the player, this drops it at the suit's loc if(!user.put_in_hands(I)) diff --git a/code/game/objects/items/scrolls.dm b/code/game/objects/items/scrolls.dm index 65d9000728d53..3fea8376eb3d2 100644 --- a/code/game/objects/items/scrolls.dm +++ b/code/game/objects/items/scrolls.dm @@ -55,7 +55,7 @@ if(!ishuman(user)) return var/mob/living/carbon/human/human_user = user - if(human_user.incapacitated() || !human_user.is_holding(src)) + if(human_user.incapacitated || !human_user.is_holding(src)) return var/datum/action/cooldown/spell/teleport/area_teleport/wizard/scroll/teleport = locate() in actions if(!teleport) diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm index c980fe0dbb359..d0b92ffaa1ad2 100644 --- a/code/game/objects/items/shields.dm +++ b/code/game/objects/items/shields.dm @@ -26,6 +26,10 @@ var/shield_break_sound = 'sound/effects/bang.ogg' /// baton bash cooldown COOLDOWN_DECLARE(baton_bash) + /// is shield bashable? + var/is_bashable = TRUE + /// sound when a shield is bashed + var/shield_bash_sound = 'sound/effects/shieldbash.ogg' /datum/armor/item_shield melee = 50 @@ -61,6 +65,19 @@ if(0 to 25) . += span_warning("It's falling apart!") +/obj/item/shield/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) + . = ..() + if(. & ITEM_INTERACT_ANY_BLOCKER) + return . + if(!istype(tool, /obj/item/melee/baton) || !is_bashable) + return . + if(!COOLDOWN_FINISHED(src, baton_bash)) + return ITEM_INTERACT_BLOCKING + user.visible_message(span_warning("[user] bashes [src] with [tool]!")) + playsound(src, shield_bash_sound, 50, TRUE) + COOLDOWN_START(src, baton_bash, BATON_BASH_COOLDOWN) + return ITEM_INTERACT_SUCCESS + /obj/item/shield/proc/on_shield_block(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE) if(!breakable_by_damage || (damage_type != BRUTE && damage_type != BURN)) return TRUE @@ -162,13 +179,6 @@ ) /obj/item/shield/riot/attackby(obj/item/attackby_item, mob/user, params) - if(istype(attackby_item, /obj/item/melee/baton)) - if(!COOLDOWN_FINISHED(src, baton_bash)) - return - user.visible_message(span_warning("[user] bashes [src] with [attackby_item]!")) - playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, TRUE) - COOLDOWN_START(src, baton_bash, BATON_BASH_COOLDOWN) - return if(istype(attackby_item, /obj/item/stack/sheet/mineral/titanium)) if (atom_integrity >= max_integrity) to_chat(user, span_warning("[src] is already in perfect condition.")) @@ -296,6 +306,8 @@ throw_speed = 3 breakable_by_damage = FALSE block_sound = 'sound/weapons/block_blade.ogg' + is_bashable = FALSE // Gotta wait till it activates y'know + shield_bash_sound = 'sound/effects/energyshieldbash.ogg' /// Force of the shield when active. var/active_force = 10 /// Throwforce of the shield when active. @@ -344,6 +356,7 @@ if(user) balloon_alert(user, active ? "activated" : "deactivated") playsound(src, active ? 'sound/weapons/saberon.ogg' : 'sound/weapons/saberoff.ogg', 35, TRUE) + is_bashable = !is_bashable return COMPONENT_NO_DEFAULT_MESSAGE /obj/item/shield/energy/proc/can_disarm_attack(datum/source, mob/living/victim, mob/living/user, send_message = TRUE) diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm index 1f13ec34a764c..84578bedbc2f6 100644 --- a/code/game/objects/items/stacks/sheets/leather.dm +++ b/code/game/objects/items/stacks/sheets/leather.dm @@ -346,6 +346,8 @@ GLOBAL_LIST_INIT(sinew_recipes, list ( \ icon_state = "sheet-hairlesshide" inhand_icon_state = null merge_type = /obj/item/stack/sheet/hairlesshide + pickup_sound = 'sound/items/skin_pick_up.ogg' + drop_sound = 'sound/items/skin_drop.ogg' /obj/item/stack/sheet/hairlesshide/examine(mob/user) . = ..() @@ -359,6 +361,8 @@ GLOBAL_LIST_INIT(sinew_recipes, list ( \ icon_state = "sheet-wetleather" inhand_icon_state = null merge_type = /obj/item/stack/sheet/wethide + pickup_sound = 'sound/items/skin_pick_up.ogg' + drop_sound = 'sound/items/skin_drop.ogg' /// Reduced when exposed to high temperatures var/wetness = 30 /// Kelvin to start drying diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index a6571eeb1e9b3..7f408a926cf00 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -369,7 +369,7 @@ /obj/item/stack/proc/radial_check(mob/builder) if(QDELETED(builder) || QDELETED(src)) return FALSE - if(builder.incapacitated()) + if(builder.incapacitated) return FALSE if(!builder.is_holding(src)) return FALSE diff --git a/code/game/objects/items/stickers.dm b/code/game/objects/items/stickers.dm index 19ac58f6f4072..447e202247367 100644 --- a/code/game/objects/items/stickers.dm +++ b/code/game/objects/items/stickers.dm @@ -30,8 +30,10 @@ /// `list` or `null`, contains possible alternate `icon_states`. var/list/icon_states - /// Whether sticker is legal and allowed to generate inside non-syndicate boxes. - var/contraband = FALSE + /// This sticker won't be generated inside random sticker packs. + var/exclude_from_random = FALSE + /// Text added to the atom's examine when stickered. + var/examine_text /obj/item/sticker/Initialize(mapload) . = ..() @@ -85,7 +87,7 @@ user.log_message("stuck [src] to [key_name(victim)]", LOG_ATTACK) victim.log_message("had [src] stuck to them by [key_name(user)]", LOG_ATTACK) - target.AddComponent(/datum/component/sticker, src, get_dir(target, src), px, py) + target.AddComponent(/datum/component/sticker, src, get_dir(target, src), px, py, null, null, examine_text) return TRUE #undef MAX_STICKER_COUNT @@ -123,6 +125,7 @@ name = "blue R sticker" desc = "A sticker of FUCK THE SYSTEM, the galaxy's premiere hardcore punk band." icon_state = "revhead" + examine_text = "There is a sticker displaying FUCK THE SYSTEM, the galaxy's premiere hardcore punk band." /obj/item/sticker/pslime name = "slime plushie sticker" @@ -149,6 +152,12 @@ name = "toolbox sticker" icon_state = "soul" +/obj/item/sticker/chief_engineer + name = "CE approved sticker" + icon_state = "ce_approved" + exclude_from_random = TRUE + examine_text = "There is a sticker displaying the Chief Engineer's SEAL OF APPROVAL." + /obj/item/sticker/clown name = "clown sticker" icon_state = "honkman" @@ -164,15 +173,17 @@ /obj/item/sticker/skub name = "skub sticker" icon_state = "skub" + examine_text = "There is a sticker displaying Skubtide, Stationwide!" /obj/item/sticker/anti_skub name = "anti-skub sticker" icon_state = "anti_skub" + examine_text = "There is an anti-skub sticker." /obj/item/sticker/syndicate name = "syndicate sticker" icon_state = "synd" - contraband = TRUE + exclude_from_random = TRUE /obj/item/sticker/syndicate/Initialize(mapload) . = ..() diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm index 996cd933647a1..15db8bd6bf28f 100644 --- a/code/game/objects/items/storage/bags.dm +++ b/code/game/objects/items/storage/bags.dm @@ -274,6 +274,8 @@ . += span_notice("Ctrl-click to activate seed extraction.") /obj/item/storage/bag/plants/portaseeder/item_ctrl_click(mob/user) + if(user.incapacitated) + return for(var/obj/item/plant in contents) seedify(plant, 1) return CLICK_ACTION_SUCCESS @@ -581,7 +583,7 @@ worn_icon_state = "rebar_quiver" inhand_icon_state = "rebar_quiver" desc = "A oxygen tank cut in half, used for holding sharpened rods for the rebar crossbow." - slot_flags = ITEM_SLOT_BACK|ITEM_SLOT_SUITSTORE + slot_flags = ITEM_SLOT_BACK|ITEM_SLOT_SUITSTORE|ITEM_SLOT_NECK resistance_flags = FLAMMABLE /obj/item/storage/bag/rebar_quiver/Initialize(mapload) @@ -598,4 +600,58 @@ /obj/item/ammo_casing/rebar/paperball, )) +/obj/item/storage/bag/rebar_quiver/syndicate + icon_state = "syndie_quiver_0" + worn_icon_state = "syndie_quiver_0" + inhand_icon_state = "holyquiver" + desc = "A specialized quiver meant to hold any kind of bolts intended for use with the rebar crossbow. \ + Clearly a better design than a cut up oxygen tank..." + slot_flags = ITEM_SLOT_NECK + resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + actions_types = list(/datum/action/item_action/reload_rebar) + +/obj/item/storage/bag/rebar_quiver/syndicate/Initialize(mapload) + . = ..() + atom_storage.max_slots = 20 + atom_storage.max_total_storage = 20 + update_appearance(UPDATE_OVERLAYS) + +/obj/item/storage/bag/rebar_quiver/syndicate/PopulateContents() + for(var/to_fill in 1 to 20) + new /obj/item/ammo_casing/rebar/syndie(src) + +/obj/item/storage/bag/rebar_quiver/syndicate/update_icon_state() + . = ..() + switch(contents.len) + if(0) + icon_state = "syndie_quiver_0" + if(1 to 7) + icon_state = "syndie_quiver_1" + if(8 to 13) + icon_state = "syndie_quiver_2" + if(14 to 20) + icon_state = "syndie_quiver_3" + +/obj/item/storage/bag/rebar_quiver/syndicate/ui_action_click(mob/user, actiontype) + if(istype(actiontype, /datum/action/item_action/reload_rebar)) + reload_held_rebar(user) + +/obj/item/storage/bag/rebar_quiver/syndicate/proc/reload_held_rebar(mob/user) + if(!contents.len) + user.balloon_alert(user, "no bolts left!") + return + var/obj/held_item = user.get_active_held_item() + if(!held_item || !istype(held_item, /obj/item/gun/ballistic/rifle/rebarxbow)) + user.balloon_alert(user, "no held crossbow!") + return + var/obj/item/gun/ballistic/rifle/rebarxbow/held_crossbow = held_item + if(held_crossbow.magazine.contents.len >= held_crossbow.magazine.max_ammo) + user.balloon_alert(user, "no more room!") + return + if(!do_after(user, 0.8 SECONDS, user, IGNORE_USER_LOC_CHANGE)) + return + + var/obj/item/ammo_casing/rebar/ammo_to_load = contents[1] + held_crossbow.attackby(ammo_to_load, user) + #undef ORE_BAG_BALOON_COOLDOWN diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index 32b825f803f61..5a98627dd3157 100644 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -76,10 +76,11 @@ /obj/item/wrench, /obj/item/spess_knife, /obj/item/melee/sickly_blade/lock, + /obj/item/reagent_containers/cup/soda_cans, )) /obj/item/storage/belt/utility/chief - name = "\improper Chief Engineer's toolbelt" //"the Chief Engineer's toolbelt", because "Chief Engineer's toolbelt" is not a proper noun + name = "chief engineer's toolbelt" desc = "Holds tools, looks snazzy." icon_state = "utility_ce" inhand_icon_state = "utility_ce" diff --git a/code/game/objects/items/storage/boxes/clothes_boxes.dm b/code/game/objects/items/storage/boxes/clothes_boxes.dm index 6b4e995a2762e..582b611186c56 100644 --- a/code/game/objects/items/storage/boxes/clothes_boxes.dm +++ b/code/game/objects/items/storage/boxes/clothes_boxes.dm @@ -130,6 +130,24 @@ new /obj/item/clothing/under/ethereal_tunic/trailwarden(src) new /obj/item/storage/backpack/saddlepack(src) +/obj/item/storage/box/hero/journalist + name = "Assassinated by CIA - 1984." // Literally + desc = "Many courageous individuals risked their lives to report on events the government sought to keep hidden from the public, ensuring that the truth remained buried and unheard. These garments are replicas of the clothing worn by one such 'journalist,' a silent sentinel in the fight for truth." + +/obj/item/storage/box/hero/journalist/PopulateContents() + new /obj/item/clothing/under/costume/buttondown/slacks(src) + new /obj/item/clothing/suit/toggle/suspenders(src) + new /obj/item/clothing/neck/tie/red(src) + new /obj/item/clothing/head/fedora/beige/press(src) + new /obj/item/clothing/accessory/press_badge(src) + new /obj/item/clothing/suit/hazardvest/press(src) + new /obj/item/radio/entertainment/microphone/physical(src) + new /obj/item/radio/entertainment/speakers/physical(src) + new /obj/item/clipboard(src) + new /obj/item/taperecorder(src) + new /obj/item/camera(src) + new /obj/item/wallframe/telescreen/entertainment(src) + /obj/item/storage/box/holy name = "Templar Kit" /// This item is used to generate a preview image for this set. diff --git a/code/game/objects/items/storage/boxes/engineering_boxes.dm b/code/game/objects/items/storage/boxes/engineering_boxes.dm index a46703ec8bf9d..09f641ec31520 100644 --- a/code/game/objects/items/storage/boxes/engineering_boxes.dm +++ b/code/game/objects/items/storage/boxes/engineering_boxes.dm @@ -112,3 +112,12 @@ ..() for(var/i in 1 to 7) new /obj/item/tank/internals/emergency_oxygen/engi(src) //in case anyone ever wants to do anything with spawning them, apart from crafting the box + +/obj/item/storage/box/stickers/chief_engineer + name = "CE approved sticker pack" + desc = "With one of these stickers, inform the crew that the contraption in the corridor is COMPLETELY SAFE!" + illustration = "label_ce" + +/obj/item/storage/box/stickers/chief_engineer/PopulateContents() + for(var/i in 1 to 3) + new /obj/item/sticker/chief_engineer(src) diff --git a/code/game/objects/items/storage/boxes/food_boxes.dm b/code/game/objects/items/storage/boxes/food_boxes.dm index bccb04f14d006..86d59123c72aa 100644 --- a/code/game/objects/items/storage/boxes/food_boxes.dm +++ b/code/game/objects/items/storage/boxes/food_boxes.dm @@ -126,7 +126,7 @@ /obj/item/storage/box/papersack/proc/check_menu(mob/user, obj/item/pen/P) if(!istype(user)) return FALSE - if(user.incapacitated()) + if(user.incapacitated) return FALSE if(contents.len) balloon_alert(user, "items inside!") diff --git a/code/game/objects/items/storage/boxes/security_boxes.dm b/code/game/objects/items/storage/boxes/security_boxes.dm index 935ead8f93e95..de18eb76258fe 100644 --- a/code/game/objects/items/storage/boxes/security_boxes.dm +++ b/code/game/objects/items/storage/boxes/security_boxes.dm @@ -174,6 +174,12 @@ for(var/i in 1 to 7) new /obj/item/ammo_casing/shotgun/buckshot(src) +/obj/item/storage/box/lethalshot/old + +/obj/item/storage/box/lethalshot/old/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/ammo_casing/shotgun/buckshot/old(src) + /obj/item/storage/box/slugs name = "box of shotgun shells (Lethal - Slugs)" desc = "A box full of lethal shotgun slugs, designed for shotguns." diff --git a/code/game/objects/items/storage/boxes/service_boxes.dm b/code/game/objects/items/storage/boxes/service_boxes.dm index ee558d863daf4..767f351635d3a 100644 --- a/code/game/objects/items/storage/boxes/service_boxes.dm +++ b/code/game/objects/items/storage/boxes/service_boxes.dm @@ -224,14 +224,35 @@ new /obj/item/toy/balloon/long(src) /obj/item/storage/box/stickers - name = "box of stickers" - desc = "A box full of random stickers. Do give to the clown." + name = "sticker pack" + desc = "A pack of removable stickers. Removable? What a rip off!
On the back, DO NOT GIVE TO THE CLOWN! is printed in large lettering." + icon = 'icons/obj/toys/stickers.dmi' + icon_state = "stickerpack" + illustration = null + w_class = WEIGHT_CLASS_TINY + var/static/list/pack_labels = list( + "smile", + "frown", + "heart", + "silentman", + "tider", + "star", + ) + +/obj/item/storage/box/stickers/Initialize(mapload) + . = ..() + atom_storage.max_slots = 8 + atom_storage.set_holdable(list(/obj/item/sticker)) + atom_storage.max_specific_storage = WEIGHT_CLASS_TINY + if(isnull(illustration)) + illustration = pick(pack_labels) + update_appearance() /obj/item/storage/box/stickers/proc/generate_non_contraband_stickers_list() var/list/allowed_stickers = list() for(var/obj/item/sticker/sticker_type as anything in subtypesof(/obj/item/sticker)) - if(!sticker_type::contraband) + if(!sticker_type::exclude_from_random) allowed_stickers += sticker_type return allowed_stickers @@ -247,8 +268,9 @@ new type(src) /obj/item/storage/box/stickers/googly - name = "box of googly eye stickers" + name = "googly eye sticker pack" desc = "Turn anything and everything into something vaguely alive!" + illustration = "googly-alt" /obj/item/storage/box/stickers/googly/PopulateContents() for(var/i in 1 to 6) diff --git a/code/game/objects/items/storage/holsters.dm b/code/game/objects/items/storage/holsters.dm index f8dee3afdc7f4..cc8a790c8ef34 100644 --- a/code/game/objects/items/storage/holsters.dm +++ b/code/game/objects/items/storage/holsters.dm @@ -113,8 +113,8 @@ /obj/item/storage/belt/holster/detective/full/PopulateContents() generate_items_inside(list( - /obj/item/gun/ballistic/revolver/c38/detective = 1, /obj/item/ammo_box/c38 = 2, + /obj/item/gun/ballistic/revolver/c38/detective = 1, ), src) /obj/item/storage/belt/holster/detective/full/ert @@ -126,8 +126,8 @@ /obj/item/storage/belt/holster/detective/full/ert/PopulateContents() generate_items_inside(list( - /obj/item/gun/ballistic/automatic/pistol/m1911 = 1, /obj/item/ammo_box/magazine/m45 = 2, + /obj/item/gun/ballistic/automatic/pistol/m1911 = 1, ),src) /obj/item/storage/belt/holster/chameleon @@ -197,8 +197,8 @@ /obj/item/storage/belt/holster/nukie/cowboy/full/PopulateContents() generate_items_inside(list( - /obj/item/gun/ballistic/revolver/syndicate/cowboy/nuclear = 1, /obj/item/ammo_box/a357 = 2, + /obj/item/gun/ballistic/revolver/syndicate/cowboy/nuclear = 1, ), src) diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm index eacd0b4b630d0..ecdde8f0e8f03 100644 --- a/code/game/objects/items/storage/uplink_kits.dm +++ b/code/game/objects/items/storage/uplink_kits.dm @@ -346,6 +346,7 @@ /obj/item/storage/box/syndie_kit/rebarxbowsyndie/PopulateContents() new /obj/item/book/granter/crafting_recipe/dusting/rebarxbowsyndie_ammo(src) new /obj/item/gun/ballistic/rifle/rebarxbow/syndie(src) + new /obj/item/storage/bag/rebar_quiver/syndicate(src) /obj/item/storage/box/syndie_kit/origami_bundle name = "origami kit" @@ -584,6 +585,7 @@ new /obj/item/storage/backpack/satchel(src) new /obj/item/modular_computer/pda/heads(src) new /obj/item/clipboard(src) + new /obj/item/skillchip/big_pointer(src) /obj/item/storage/box/syndie_kit/chameleon/broken/PopulateContents() new /obj/item/clothing/under/chameleon/broken(src) @@ -683,14 +685,7 @@ group.register(i) desc += " The implants are registered to the \"[group.name]\" group." -/obj/item/storage/box/syndie_kit/stickers - name = "sticker kit" - -/obj/item/storage/box/syndie_kit/stickers/Initialize(mapload) - . = ..() - atom_storage.max_slots = 8 - -/obj/item/storage/box/syndie_kit/stickers/PopulateContents() +/obj/item/storage/box/stickers/syndie_kit/PopulateContents() var/list/types = subtypesof(/obj/item/sticker/syndicate) for(var/i in 1 to atom_storage.max_slots) diff --git a/code/game/objects/items/syndie_spraycan.dm b/code/game/objects/items/syndie_spraycan.dm index 1b7e0d9c4024a..fb6192c6e3990 100644 --- a/code/game/objects/items/syndie_spraycan.dm +++ b/code/game/objects/items/syndie_spraycan.dm @@ -143,7 +143,7 @@ user.visible_message(span_suicide("[user] shakes up [src] with a rattle and lifts it to [user.p_their()] mouth, spraying paint across [user.p_their()] teeth!")) user.say("WITNESS ME!!", forced="spraycan suicide") playsound(src, 'sound/effects/spray.ogg', 5, TRUE, 5) - suicider.update_lips("spray_face", paint_color) + suicider.AddComponent(/datum/component/face_decal, "spray", EXTERNAL_ADJACENT, paint_color) return OXYLOSS /obj/effect/decal/cleanable/traitor_rune diff --git a/code/game/objects/items/tanks/jetpack.dm b/code/game/objects/items/tanks/jetpack.dm index cd5a9a1841ead..a7a577c77cf16 100644 --- a/code/game/objects/items/tanks/jetpack.dm +++ b/code/game/objects/items/tanks/jetpack.dm @@ -79,7 +79,7 @@ toggle_internals(user) /obj/item/tank/jetpack/proc/cycle(mob/user) - if(user.incapacitated()) + if(user.incapacitated) return if(!on) diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm index 8094a9a21c863..15db2a5d3edf2 100644 --- a/code/game/objects/items/tanks/watertank.dm +++ b/code/game/objects/items/tanks/watertank.dm @@ -47,7 +47,7 @@ if(user.get_item_by_slot(user.getBackSlot()) != src) to_chat(user, span_warning("The watertank must be worn properly to use!")) return - if(user.incapacitated()) + if(user.incapacitated) return if(QDELETED(noz)) diff --git a/code/game/objects/items/tcg/tcg.dm b/code/game/objects/items/tcg/tcg.dm index fc2eeba82ff72..23204b4809ff8 100644 --- a/code/game/objects/items/tcg/tcg.dm +++ b/code/game/objects/items/tcg/tcg.dm @@ -151,7 +151,7 @@ GLOBAL_LIST_EMPTY(tcgcard_radial_choices) /obj/item/tcgcard/proc/check_menu(mob/living/user) if(!istype(user)) return FALSE - if(user.incapacitated() || !user.Adjacent(src)) + if(user.incapacitated || !user.Adjacent(src)) return FALSE return TRUE @@ -249,7 +249,7 @@ GLOBAL_LIST_EMPTY(tcgcard_radial_choices) /obj/item/tcgcard_deck/proc/check_menu(mob/living/user) if(!istype(user)) return FALSE - if(user.incapacitated() || !user.Adjacent(src)) + if(user.incapacitated || !user.Adjacent(src)) return FALSE return TRUE diff --git a/code/game/objects/items/tcg/tcg_machines.dm b/code/game/objects/items/tcg/tcg_machines.dm index 78854afdd5b39..77b6891e4c17a 100644 --- a/code/game/objects/items/tcg/tcg_machines.dm +++ b/code/game/objects/items/tcg/tcg_machines.dm @@ -105,7 +105,7 @@ GLOBAL_LIST_EMPTY(tcgcard_machine_radial_choices) /obj/machinery/trading_card_holder/proc/check_menu(mob/living/user) if(!istype(user)) return FALSE - if(user.incapacitated() || !user.Adjacent(src)) + if(user.incapacitated || !user.Adjacent(src)) return FALSE return TRUE @@ -356,7 +356,7 @@ GLOBAL_LIST_EMPTY(tcgcard_mana_bar_radial_choices) /obj/machinery/trading_card_button/proc/check_menu(mob/living/user) if(!istype(user)) return FALSE - if(user.incapacitated() || !user.Adjacent(src)) + if(user.incapacitated || !user.Adjacent(src)) return FALSE return TRUE diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm index 04f5a0688db82..6fa7e8d23b340 100644 --- a/code/game/objects/items/teleportation.dm +++ b/code/game/objects/items/teleportation.dm @@ -190,7 +190,7 @@ var/teleport_location_key = tgui_input_list(user, "Teleporter to lock on", "Hand Teleporter", sort_list(locations)) if (isnull(teleport_location_key)) return - if(user.get_active_held_item() != src || user.incapacitated()) + if(user.get_active_held_item() != src || user.incapacitated) return // Not always a datum, but needed for IS_WEAKREF_OF to cast properly. diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm index fb40a70cbeea0..143b8eab174e6 100644 --- a/code/game/objects/items/tools/weldingtool.dm +++ b/code/game/objects/items/tools/weldingtool.dm @@ -153,8 +153,9 @@ if(isnull(affecting) || !IS_ROBOTIC_LIMB(affecting)) return NONE - if (!affecting.get_damage()) - return + if (!affecting.brute_dam) + balloon_alert(user, "limb not damaged") + return ITEM_INTERACT_BLOCKING user.visible_message(span_notice("[user] starts to fix some of the dents on [attacked_humanoid == user ? user.p_their() : "[attacked_humanoid]'s"] [affecting.name]."), span_notice("You start fixing some of the dents on [attacked_humanoid == user ? "your" : "[attacked_humanoid]'s"] [affecting.name].")) diff --git a/code/game/objects/items/toy_mechs.dm b/code/game/objects/items/toy_mechs.dm index 1b3367032c190..d08deec62e316 100644 --- a/code/game/objects/items/toy_mechs.dm +++ b/code/game/objects/items/toy_mechs.dm @@ -96,7 +96,7 @@ return FALSE //dead men tell no tales, incapacitated men fight no fights - if(attacker_controller.incapacitated()) + if(attacker_controller.incapacitated) return FALSE //if the attacker_controller isn't next to the attacking toy (and doesn't have telekinesis), the battle ends if(!in_range(attacker, attacker_controller) && !(attacker_controller.dna.check_mutation(/datum/mutation/human/telekinesis))) @@ -106,7 +106,7 @@ //if it's PVP and the opponent is not next to the defending(src) toy (and doesn't have telekinesis), the battle ends if(opponent) - if(opponent.incapacitated()) + if(opponent.incapacitated) return FALSE if(!in_range(src, opponent) && !(opponent.dna.check_mutation(/datum/mutation/human/telekinesis))) opponent.visible_message(span_notice("[opponent.name] separates from [src], ending the battle."), \ diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm index ff540932f31b7..82636c0ee8514 100644 --- a/code/game/objects/items/trash.dm +++ b/code/game/objects/items/trash.dm @@ -85,10 +85,6 @@ desc = "In the Mothic Fleet every individual wrapper is carefully recycled and repurposed into fresh material. Over here they are more commonly dropped directly onto the floor." icon_state = "moth_ration" -/obj/item/trash/waffles - name = "waffles tray" - icon_state = "waffles" - /obj/item/trash/pistachios name = "pistachios pack" icon_state = "pistachios_pack" diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 0d3e3f60d4abf..265f1cc2375d7 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -160,6 +160,14 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 throw_range = 5 armour_penetration = 35 +/obj/item/claymore/cutlass/old + name = "old cutlass" + desc = parent_type::desc + " This one seems a tad old." + force = 24 + throwforce = 17 + armour_penetration = 20 + block_chance = 30 + /obj/item/claymore/carrot name = "carrot sword" desc = "A full-sized carrot sword. Definitely not good for the eyes, not anymore." diff --git a/code/game/objects/items_reskin.dm b/code/game/objects/items_reskin.dm index 9fa3b91d0e198..f8bffa7bf5f63 100644 --- a/code/game/objects/items_reskin.dm +++ b/code/game/objects/items_reskin.dm @@ -81,6 +81,6 @@ return FALSE if(!istype(user)) return FALSE - if(user.incapacitated()) + if(user.incapacitated) return FALSE return TRUE diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index d07f7ad21c5f5..ceaa0e0beb734 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -96,7 +96,7 @@ /obj/proc/collision_damage(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction) var/amt = max(0, ((force - (move_resist * MOVE_FORCE_CRUSH_RATIO)) / (move_resist * MOVE_FORCE_CRUSH_RATIO)) * 10) - take_damage(amt, BRUTE) + take_damage(amt, BRUTE, attack_dir = REVERSE_DIR(direction)) /obj/singularity_act() SSexplosions.high_mov_atom += src diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index f12479c66a444..f3c02ef12b5ac 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -70,7 +70,7 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) var/total_force = (attacking_item.force * attacking_item.demolition_mod) - var/damage = take_damage(total_force, attacking_item.damtype, MELEE, 1) + var/damage = take_damage(total_force, attacking_item.damtype, MELEE, 1, get_dir(src, user)) var/damage_verb = "hit" @@ -190,7 +190,6 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) if(obj_flags & UNIQUE_RENAME) . += span_notice("Use a pen on it to rename it or change its description.") - /obj/analyzer_act(mob/living/user, obj/item/analyzer/tool) if(atmos_scan(user=user, target=src, silent=FALSE)) return TRUE diff --git a/code/game/objects/structures/beds_chairs/alien_nest.dm b/code/game/objects/structures/beds_chairs/alien_nest.dm index 77759c9e309b0..2eb63324f1f64 100644 --- a/code/game/objects/structures/beds_chairs/alien_nest.dm +++ b/code/game/objects/structures/beds_chairs/alien_nest.dm @@ -59,7 +59,7 @@ add_fingerprint(hero) /obj/structure/bed/nest/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE) - if ( !ismob(M) || (get_dist(src, user) > 1) || (M.loc != src.loc) || user.incapacitated() || M.buckled ) + if ( !ismob(M) || (get_dist(src, user) > 1) || (M.loc != src.loc) || user.incapacitated || M.buckled ) return if(M.get_organ_by_type(/obj/item/organ/internal/alien/plasmavessel)) diff --git a/code/game/objects/structures/beds_chairs/bed.dm b/code/game/objects/structures/beds_chairs/bed.dm index 4cfd6355eb0b2..f24cebd357b03 100644 --- a/code/game/objects/structures/beds_chairs/bed.dm +++ b/code/game/objects/structures/beds_chairs/bed.dm @@ -15,6 +15,7 @@ anchored = TRUE can_buckle = TRUE buckle_lying = 90 + buckle_dir = SOUTH resistance_flags = FLAMMABLE max_integrity = 100 integrity_failure = 0.35 @@ -30,6 +31,7 @@ AddElement(/datum/element/soft_landing) if(elevation) AddElement(/datum/element/elevation, pixel_shift = elevation) + update_buckle_vars(dir) register_context() /obj/structure/bed/examine(mob/user) @@ -48,6 +50,13 @@ context[SCREENTIP_CONTEXT_LMB] = "Unbuckle" return CONTEXTUAL_SCREENTIP_SET +/obj/structure/bed/setDir(newdir) + . = ..() + update_buckle_vars(newdir) + +/obj/structure/bed/proc/update_buckle_vars(newdir) + buckle_lying = newdir & NORTHEAST ? 270 : 90 + /obj/structure/bed/atom_deconstruct(disassembled = TRUE) if(build_stack_type) new build_stack_type(loc, build_stack_amount) diff --git a/code/game/objects/structures/cannons/cannon.dm b/code/game/objects/structures/cannons/cannon.dm index 3408ade8283d0..3a10cc17189f8 100644 --- a/code/game/objects/structures/cannons/cannon.dm +++ b/code/game/objects/structures/cannons/cannon.dm @@ -140,5 +140,17 @@ new /obj/item/stack/rods(src.loc) . = ..() +///A cannon found from the fishing mystery box. +/obj/structure/cannon/mystery_box + icon_state = "mystery_box_cannon" //east facing sprite for the presented item, it'll be changed back to normal on init + dir = EAST + anchored = FALSE + +/obj/structure/cannon/mystery_box/Initialize(mapload) + . = ..() + icon_state = "falconet_patina" + reagents.add_reagent(/datum/reagent/gunpowder, charge_size) + loaded_cannonball = new(src) + #undef BAD_FUEL_DAMAGE_TAX #undef BAD_FUEL_EXPLODE_PROBABILTY diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 4484e3c512ef3..f407dcd82c04f 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -915,6 +915,8 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) /obj/structure/closet/mouse_drop_receive(atom/movable/O, mob/living/user, params) if(!istype(O) || O.anchored || istype(O, /atom/movable/screen)) return + if(!istype(user) || user.incapacitated || user.body_position == LYING_DOWN) + return if(user == O) //try to climb onto it return ..() if(!opened) @@ -1193,6 +1195,8 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) if(!toggle()) return if(was_opened) + if (!target.Move(get_turf(src), get_dir(target, src))) + return target.forceMove(src) else target.Knockdown(SHOVE_KNOCKDOWN_SOLID) diff --git a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm index f0d1eaa0cc819..2f555ed84dea5 100644 --- a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm +++ b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm @@ -32,7 +32,7 @@ var/move_delay = FALSE /obj/structure/closet/cardboard/relaymove(mob/living/user, direction) - if(opened || move_delay || user.incapacitated() || !isturf(loc) || !has_gravity(loc)) + if(opened || move_delay || user.incapacitated || !isturf(loc) || !has_gravity(loc)) return move_delay = TRUE var/oldloc = loc @@ -72,7 +72,7 @@ for(var/mob/living/alerted_mob as anything in alerted) if(alerted_mob.stat != CONSCIOUS || alerted_mob.is_blind()) continue - if(!alerted_mob.incapacitated(IGNORE_RESTRAINTS)) + if(!INCAPACITATED_IGNORING(alerted_mob, INCAPABLE_RESTRAINTS)) alerted_mob.face_atom(src) alerted_mob.do_alert_animation() diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm index 3dc59fb9ce21a..22dd2bec4b2bb 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm @@ -18,6 +18,7 @@ new /obj/item/extinguisher/advanced(src) new /obj/item/storage/photo_album/ce(src) new /obj/item/storage/box/skillchips/engineering(src) + new /obj/item/storage/box/stickers/chief_engineer(src) /obj/structure/closet/secure_closet/engineering_chief/populate_contents_immediate() . = ..() diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 7b64b6569d6cc..cac9fbaf890bb 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -222,6 +222,12 @@ icon_state = "medicalcrate" base_icon_state = "medicalcrate" +/obj/structure/closet/crate/deforest + name = "deforest medical crate" + desc = "A DeFortest brand crate of medical supplies." + icon_state = "deforest" + base_icon_state = "deforest" + /obj/structure/closet/crate/medical/department icon_state = "medical" base_icon_state = "medical" @@ -290,6 +296,24 @@ icon_state = "food" base_icon_state = "food" +/obj/structure/closet/crate/freezer/donk + name = "donk co. fridge" + desc = "A Donk Co. brand fridge, keeps your donkpcokets and foam ammunition fresh!" + icon_state = "donkcocrate" + base_icon_state = "donkcocrate" + +/obj/structure/closet/crate/freezer/interdyne + name = "interdyne freezer" + desc = "Interdyne Pharmauceutics branded freezer. Might or might not contain cold steel, or fresh organs." + icon_state = "interdynefreezer" + base_icon_state = "interdynefreezer" + +/obj/structure/closet/crate/freezer/blood/interdyne + name = "interdyne blood freezer" + desc = "Interdyne Pharmauceutics branded freezer. Only freshly harvested- I mean, freshly kept blood inside!" + icon_state = "interdynefreezer" + base_icon_state = "interdynefreezer" + /obj/structure/closet/crate/radiation desc = "A crate with a radiation sign on it." name = "radiation crate" @@ -312,6 +336,12 @@ icon_state = "cargo" base_icon_state = "cargo" +/obj/structure/closet/crate/robust + name = "robust industries crate" + desc = "Robust Inustries LLC. crate. Feels oddly nostalgic." + icon_state = "robust" + base_icon_state = "robust" + /obj/structure/closet/crate/cargo/mining name = "mining crate" icon_state = "mining" @@ -322,6 +352,12 @@ icon_state = "engi_crate" base_icon_state = "engi_crate" +/obj/structure/closet/crate/nakamura + name = "nakamura engineering crate" + desc = "Crate from Nakamura Engineering, most likely containing engineering supplies or MODcores." + icon_state = "nakamura" + base_icon_state = "nakamura" + /obj/structure/closet/crate/engineering/electrical icon_state = "engi_e_crate" base_icon_state = "engi_e_crate" diff --git a/code/game/objects/structures/crates_lockers/crates/secure.dm b/code/game/objects/structures/crates_lockers/crates/secure.dm index 1a102fdb512fd..e93591f1d596c 100644 --- a/code/game/objects/structures/crates_lockers/crates/secure.dm +++ b/code/game/objects/structures/crates_lockers/crates/secure.dm @@ -44,6 +44,17 @@ icon_state = "weaponcrate" base_icon_state = "weaponcrate" +/obj/structure/closet/crate/secure/gorlex_weapons + desc = "A secure weapons crate of Gorlex Marauders." + name = "weapons crate" + icon_state = "gorlex_weaponcrate" + base_icon_state = "gorlex_weaponcrate" + +/obj/structure/closet/crate/secure/gorlex_weapons/jammed + desc = "A beaten up, jammed open weapon crate of Gorlex Marauders." + name = "jammed weapons crate" + locked = FALSE + /obj/structure/closet/crate/secure/plasma desc = "A secure plasma crate." name = "plasma crate" @@ -192,3 +203,65 @@ else if(!silent) to_chat(user, span_warning("[src] is broken!")) else ..() + +/obj/structure/closet/crate/secure/interdyne + name = "interdyne crate" + desc = "Crate belonging to Interdyne Pharmaceutics. Hopefully doesn't have bioweapons inside..." + icon_state = "interdynecrate" + base_icon_state = "interdynecrate" + +/obj/structure/closet/crate/secure/tiger + name = "tiger co-op crate" + icon_state = "tigercrate" + base_icon_state = "tigercrate" + +/obj/structure/closet/crate/secure/self + name = "s.e.l.f. crate" + desc = "A secure crate locked from the inside with a scanning panel above it and holographic display of lock's status. Sentient Engine Liberation Front engineers are quite the show-offs." + icon_state = "selfcrate" + base_icon_state = "selfcrate" + +/obj/structure/closet/crate/secure/m13 + name = "mysterious secure crate" + desc = "A secure crate. Lacks any obvious logos or even codes for where it arrived from, but looks like taken straight from a spy movie." + icon_state = "mithirteencrate" + base_icon_state = "mithirteencrate" + +/obj/structure/closet/crate/secure/arc + name = "animal rights consortium crate" + icon_state = "arccrate" + base_icon_state = "arccrate" + +/obj/structure/closet/crate/secure/cybersun + name = "cybersun crate" + +/obj/structure/closet/crate/secure/cybersun/dawn + desc = "A secure crate from Cybersun Industries. It has distinct orange-green colouring, probably of some departament or division, but you cannot tell what is it." + icon_state = "cyber_dawncrate" + base_icon_state = "cyber_dawncrate" + +/obj/structure/closet/crate/secure/cybersun/noon + desc = "A secure crate from Cybersun Industries. It has distinct yellow-orange colouring, probably of some departament or division, but you cannot tell what is it." + icon_state = "cyber_nooncrate" + base_icon_state = "cyber_nooncrate" + +/obj/structure/closet/crate/secure/cybersun/dusk + desc = "A secure crate from Cybersun Industries. It has distinct purple-green colouring, probably of some departament or division, but you cannot tell what is it." + icon_state = "cyber_duskcrate" + base_icon_state = "cyber_duskcrate" + +/obj/structure/closet/crate/secure/cybersun/night + desc = "A secure crate from Cybersun Industries. This one blatantly adorns syndicate colours. You can only guess it contains equipement for syndicate operatives." + icon_state = "cyber_nightcrate" + base_icon_state = "cyber_nightcrate" + +/obj/structure/closet/crate/secure/wafflecorp + name = "wafflecorp crate" + desc = "A very outdated model and design of shipment crate with a modern lock strapped on it, how befitting of its brand owner, Waffle Corporation. Golden lettering written in cursive by the logo reads 'bringing you consecutively top five world-wide rated* breakfast since 2055. A much smaller fineprint, also in cursive, clarifies: '*in years 2099-2126'... It's year 2563 now, however." + icon_state = "wafflecrate" + base_icon_state = "wafflecrate" + +/obj/structure/closet/crate/secure/gorlex + name = "gorlex marauders crate" + icon_state = "gorlexcrate" + base_icon_state = "gorlexcrate" diff --git a/code/game/objects/structures/deployable_turret.dm b/code/game/objects/structures/deployable_turret.dm index 2b1a90500ccf8..908d2348db4b3 100644 --- a/code/game/objects/structures/deployable_turret.dm +++ b/code/game/objects/structures/deployable_turret.dm @@ -85,7 +85,7 @@ STOP_PROCESSING(SSfastprocess, src) /obj/machinery/deployable_turret/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE) - if(user.incapacitated() || !istype(user)) + if(user.incapacitated || !istype(user)) return M.forceMove(get_turf(src)) . = ..() @@ -129,7 +129,7 @@ calculated_projectile_vars = calculate_projectile_angle_and_pixel_offsets(controller, target_turf, modifiers) /obj/machinery/deployable_turret/proc/direction_track(mob/user, atom/targeted) - if(user.incapacitated()) + if(user.incapacitated) return setDir(get_dir(src,targeted)) user.setDir(dir) @@ -169,7 +169,7 @@ /obj/machinery/deployable_turret/proc/checkfire(atom/targeted_atom, mob/user) target = targeted_atom - if(target == user || user.incapacitated() || target == get_turf(src)) + if(target == user || user.incapacitated || target == get_turf(src)) return if(world.time < cooldown) if(!warned && world.time > (cooldown - cooldown_duration + rate_of_fire*number_of_shots)) // To capture the window where one is done firing @@ -187,7 +187,7 @@ addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/deployable_turret/, fire_helper), user), i*rate_of_fire) /obj/machinery/deployable_turret/proc/fire_helper(mob/user) - if(user.incapacitated() || !(user in buckled_mobs)) + if(user.incapacitated || !(user in buckled_mobs)) return update_positioning() //REFRESH MOUSE TRACKING!! var/turf/targets_from = get_turf(src) diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm index 49a230d6bdc48..a464f41827678 100644 --- a/code/game/objects/structures/flora.dm +++ b/code/game/objects/structures/flora.dm @@ -2,7 +2,7 @@ name = "flora" desc = "Some sort of plant." resistance_flags = FLAMMABLE - max_integrity = 150 + max_integrity = 100 anchored = TRUE drag_slowdown = 1.3 @@ -113,6 +113,12 @@ if(harvest(user)) after_harvest(user) +/obj/structure/flora/run_atom_armor(damage_amount, damage_type, damage_flag = 0, attack_dir) + if(damage_flag == MELEE) + if(damage_type == BURN) + damage_amount *= 4 + return ..() + /obj/structure/flora/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) var/use_default_sound = TRUE //Because I don't wanna do unnecessary bitflag checks in a single if statement, while also allowing for multiple sounds to be played if(flora_flags & FLORA_HERBAL) @@ -278,6 +284,7 @@ name = "tree" desc = "A large tree." density = TRUE + max_integrity = 150 pixel_x = -16 layer = FLY_LAYER plane = ABOVE_GAME_PLANE diff --git a/code/game/objects/structures/guncase.dm b/code/game/objects/structures/guncase.dm index 4f4972d486415..b297b670b0ebe 100644 --- a/code/game/objects/structures/guncase.dm +++ b/code/game/objects/structures/guncase.dm @@ -104,7 +104,7 @@ return FALSE if(!istype(user)) return FALSE - if(user.incapacitated()) + if(user.incapacitated) return FALSE return TRUE diff --git a/code/game/objects/structures/icemoon/cave_entrance.dm b/code/game/objects/structures/icemoon/cave_entrance.dm index 4401b87d23eca..6efa671875915 100644 --- a/code/game/objects/structures/icemoon/cave_entrance.dm +++ b/code/game/objects/structures/icemoon/cave_entrance.dm @@ -178,7 +178,8 @@ GLOBAL_LIST_INIT(ore_probability, list( if(16) new /mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/doom(loc) if(17) - new /obj/item/reagent_containers/cup/glass/drinkingglass/filled/nuka_cola(loc) + new /obj/item/clothing/gloves/fingerless/punch_mitts(loc) + new /obj/item/clothing/head/cowboy(loc) if(18) new /obj/item/soulstone/anybody(loc) if(19) diff --git a/code/game/objects/structures/janitor.dm b/code/game/objects/structures/janitor.dm index 0413bcac53986..a8df82e02b2fa 100644 --- a/code/game/objects/structures/janitor.dm +++ b/code/game/objects/structures/janitor.dm @@ -337,7 +337,7 @@ * * user The mob interacting with a menu */ /obj/structure/mop_bucket/janitorialcart/proc/check_menu(mob/living/user) - return istype(user) && !user.incapacitated() + return istype(user) && !user.incapacitated /obj/structure/mop_bucket/janitorialcart/update_overlays() . = ..() diff --git a/code/game/objects/structures/ladders.dm b/code/game/objects/structures/ladders.dm index 314539aa2b412..ffe4ea44a00cb 100644 --- a/code/game/objects/structures/ladders.dm +++ b/code/game/objects/structures/ladders.dm @@ -182,7 +182,7 @@ INVOKE_ASYNC(src, PROC_REF(start_travelling), user, going_up) /obj/structure/ladder/proc/check_menu(mob/user, is_ghost) - if(user.incapacitated() || (!user.Adjacent(src))) + if(user.incapacitated || (!user.Adjacent(src))) return FALSE return TRUE diff --git a/code/game/objects/structures/maintenance.dm b/code/game/objects/structures/maintenance.dm index 768bd22d2abe2..42fd381044ec0 100644 --- a/code/game/objects/structures/maintenance.dm +++ b/code/game/objects/structures/maintenance.dm @@ -226,7 +226,7 @@ at the cost of risking a vicious bite.**/ /obj/structure/destructible/cult/pants_altar/proc/check_menu(mob/user) if(!istype(user)) return FALSE - if(user.incapacitated() || !user.Adjacent(src)) + if(user.incapacitated || !user.Adjacent(src)) return FALSE return TRUE diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 7ea2330281413..a0ed1013f549b 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -88,7 +88,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) return display_radial_menu(user) /obj/structure/mirror/proc/display_radial_menu(mob/living/carbon/human/user) - var/pick = show_radial_menu(user, src, mirror_options, user, radius = 36, require_near = TRUE) + var/pick = show_radial_menu(user, src, mirror_options, user, radius = 36, require_near = TRUE, tooltips = TRUE) if(!pick) return TRUE //get out @@ -382,12 +382,36 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) desc = "Pride cometh before the..." race_flags = MIRROR_PRIDE mirror_options = PRIDE_MIRROR_OPTIONS + /// If the last user has altered anything about themselves + var/changed = FALSE + +/obj/structure/mirror/magic/pride/display_radial_menu(mob/living/carbon/human/user) + var/pick = show_radial_menu(user, src, mirror_options, user, radius = 36, require_near = TRUE, tooltips = TRUE) + if(!pick) + return TRUE //get out + + changed = TRUE + switch(pick) + if(CHANGE_HAIR) + change_hair(user) + if(CHANGE_BEARD) + change_beard(user) + if(CHANGE_RACE) + change_race(user) + if(CHANGE_SEX) // sex: yes + change_sex(user) + if(CHANGE_NAME) + change_name(user) + if(CHANGE_EYES) + change_eyes(user) + + return display_radial_menu(user) /obj/structure/mirror/magic/pride/attack_hand(mob/living/carbon/human/user) + changed = FALSE . = ..() - if(.) - return TRUE - + if (!changed) + return user.visible_message( span_bolddanger("The ground splits beneath [user] as [user.p_their()] hand leaves the mirror!"), span_notice("Perfect. Much better! Now nobody will be able to resist yo-"), diff --git a/code/game/objects/structures/mystery_box.dm b/code/game/objects/structures/mystery_box.dm index e165c2e295c93..9bb51ba09cbef 100644 --- a/code/game/objects/structures/mystery_box.dm +++ b/code/game/objects/structures/mystery_box.dm @@ -19,7 +19,6 @@ #define MBOX_DURATION_STANDBY (2.7 SECONDS) GLOBAL_LIST_INIT(mystery_box_guns, list( - /obj/item/gun/energy/lasercannon, /obj/item/gun/energy/recharge/ebow/large, /obj/item/gun/energy/e_gun, /obj/item/gun/energy/e_gun/nuclear, @@ -45,6 +44,7 @@ GLOBAL_LIST_INIT(mystery_box_guns, list( /obj/item/gun/ballistic/automatic/m90/unrestricted, /obj/item/gun/ballistic/automatic/tommygun, /obj/item/gun/ballistic/automatic/wt550, + /obj/item/gun/ballistic/automatic/smartgun, /obj/item/gun/ballistic/rifle/sniper_rifle, /obj/item/gun/ballistic/rifle/boltaction, )) @@ -85,6 +85,30 @@ GLOBAL_LIST_INIT(mystery_magic, list( /obj/item/runic_vendor_scepter, )) +GLOBAL_LIST_INIT(mystery_fishing, list( + /obj/item/storage/toolbox/fishing/master, + /obj/item/storage/box/fish_revival_kit, + /obj/item/circuitboard/machine/fishing_portal_generator/emagged, + /obj/item/fishing_rod/telescopic/master, + /obj/item/bait_can/super_baits, + /obj/item/storage/fish_case/tiziran, + /obj/item/storage/fish_case/syndicate, + /obj/item/claymore/cutlass/old, + /obj/item/gun/energy/laser/retro/old, + /obj/item/gun/energy/laser/musket, + /obj/item/gun/energy/disabler/smoothbore, + /obj/item/gun/ballistic/rifle/boltaction/surplus, + /obj/item/food/rationpack, + /obj/item/food/canned/squid_ink, + /obj/item/reagent_containers/cup/glass/bottle/rum/aged, + /obj/item/storage/bag/money/dutchmen, + /obj/item/language_manual/piratespeak, + /obj/item/clothing/head/costume/pirate/armored, + /obj/item/clothing/suit/costume/pirate/armored, + /obj/structure/cannon/mystery_box, + /obj/item/stack/cannonball/trashball/four, + /obj/item/stack/cannonball/four, +)) /obj/structure/mystery_box name = "mystery box" @@ -117,6 +141,10 @@ GLOBAL_LIST_INIT(mystery_magic, list( var/grant_extra_mag = TRUE /// Stores the current sound channel we're using so we can cut off our own sounds as needed. Randomized after each roll var/current_sound_channel + /// How many time can it still be used? + var/uses_left + /// A list of weakrefs to mind datums of people that opened it and how many times. + var/list/datum/weakref/minds_that_opened_us /obj/structure/mystery_box/Initialize(mapload) . = ..() @@ -126,6 +154,7 @@ GLOBAL_LIST_INIT(mystery_magic, list( QDEL_NULL(presented_item) if(current_sound_channel) SSsounds.free_sound_channel(current_sound_channel) + minds_that_opened_us = null return ..() /obj/structure/mystery_box/attack_hand(mob/living/user, list/modifiers) @@ -163,6 +192,11 @@ GLOBAL_LIST_INIT(mystery_magic, list( current_sound_channel = SSsounds.reserve_sound_channel(src) playsound(src, open_sound, 70, FALSE, channel = current_sound_channel, falloff_exponent = 10) playsound(src, crate_open_sound, 80) + if(user.mind) + LAZYINITLIST(minds_that_opened_us) + var/datum/weakref/ref = WEAKREF(user.mind) + minds_that_opened_us[ref] += 1 + uses_left-- /// The box has finished choosing, mark it as available for grabbing /obj/structure/mystery_box/proc/present_weapon() @@ -186,6 +220,9 @@ GLOBAL_LIST_INIT(mystery_magic, list( box_close_timer = null box_expire_timer = null addtimer(CALLBACK(src, PROC_REF(ready_again)), MBOX_DURATION_STANDBY) + if(uses_left <= 0) + visible_message("[src] breaks down.") + deconstruct(disassembled = FALSE) /// The cooldown between activations has finished, shake to show that /obj/structure/mystery_box/proc/ready_again() @@ -196,22 +233,26 @@ GLOBAL_LIST_INIT(mystery_magic, list( /// Someone attacked the box with an empty hand, spawn the shown prize and give it to them, then close the box /obj/structure/mystery_box/proc/grant_weapon(mob/living/user) - var/obj/item/instantiated_weapon = new presented_item.selected_path(src) - user.put_in_hands(instantiated_weapon) - - if(isgun(instantiated_weapon)) // handle pins + possibly extra ammo - var/obj/item/gun/instantiated_gun = instantiated_weapon - instantiated_gun.unlock() - if(grant_extra_mag && istype(instantiated_gun, /obj/item/gun/ballistic)) - var/obj/item/gun/ballistic/instantiated_ballistic = instantiated_gun - if(!instantiated_ballistic.internal_magazine) - var/obj/item/ammo_box/magazine/extra_mag = new instantiated_ballistic.spawn_magazine_type(loc) - user.put_in_hands(extra_mag) - + var/atom/movable/instantiated_weapon = new presented_item.selected_path(loc) user.visible_message(span_notice("[user] takes [presented_item] from [src]."), span_notice("You take [presented_item] from [src]."), vision_distance = COMBAT_MESSAGE_RANGE) playsound(src, grant_sound, 70, FALSE, channel = current_sound_channel, falloff_exponent = 10) close_box() + if(!isitem(instantiated_weapon)) + return + user.put_in_hands(instantiated_weapon) + + if(!isgun(instantiated_weapon)) + return + // handle pins + possibly extra ammo + var/obj/item/gun/instantiated_gun = instantiated_weapon + instantiated_gun.unlock() + if(!grant_extra_mag || !istype(instantiated_gun, /obj/item/gun/ballistic)) + return + var/obj/item/gun/ballistic/instantiated_ballistic = instantiated_gun + if(!instantiated_ballistic.internal_magazine) + var/obj/item/ammo_box/magazine/extra_mag = new instantiated_ballistic.spawn_magazine_type(loc) + user.put_in_hands(extra_mag) /obj/structure/mystery_box/guns desc = "A wooden crate that seems equally magical and mysterious, capable of granting the user all kinds of different pieces of gear. This one seems focused on firearms." @@ -231,6 +272,28 @@ GLOBAL_LIST_INIT(mystery_magic, list( /obj/structure/mystery_box/wands/generate_valid_types() valid_types = GLOB.mystery_magic +///One of a kind, rarely found by fishing in the ocean. +/obj/structure/mystery_box/fishing + name = "treasure chest" + desc = "A pirate-y chest that seems equally magial and mysterious, capable of granting the user different pieces of gear." + icon_state = "treasure" + uses_left = 18 + max_integrity = 100 + damage_deflection = 30 + grant_extra_mag = FALSE + +/obj/structure/mystery_box/handle_deconstruct(disassembled) + new /obj/item/stack/sheet/mineral/wood(drop_location(), 2) + return ..() + +/obj/structure/mystery_box/fishing/generate_valid_types() + valid_types = GLOB.mystery_fishing + +/obj/structure/mystery_box/fishing/activate(mob/living/user) + if(user.mind && minds_that_opened_us?[WEAKREF(user.mind)] >= 3) + to_chat(user, span_warning("[src] refuses to open to you anymore. Perhaps you should present it to someone else...")) + return + return ..() /// This represents the item that comes out of the box and is constantly changing before the box finishes deciding. Can probably be just an /atom or /movable. /obj/mystery_box_item @@ -290,14 +353,14 @@ GLOBAL_LIST_INIT(mystery_magic, list( /// animate() isn't up to the task for queueing up icon changes, so this is the proc we call with timers to update our icon /obj/mystery_box_item/proc/update_random_icon(new_item_type) - var/obj/item/new_item = new_item_type - icon = initial(new_item.icon) - icon_state = initial(new_item.icon_state) + var/atom/movable/new_item = new_item_type + icon = new_item::icon + icon_state = new_item::icon_state /obj/mystery_box_item/proc/present_item() - var/obj/item/selected_item = selected_path + var/atom/movable/selected_item = selected_path add_filter("ready_outline", 2, list("type" = "outline", "color" = COLOR_VIVID_YELLOW, "size" = 0.2)) - name = initial(selected_item.name) + name = selected_item::name parent_box.present_weapon() claimable = TRUE diff --git a/code/game/objects/structures/railings.dm b/code/game/objects/structures/railings.dm index c3d9b115f01de..b23641a416a16 100644 --- a/code/game/objects/structures/railings.dm +++ b/code/game/objects/structures/railings.dm @@ -155,6 +155,7 @@ icon_state = "wooden_railing" item_deconstruct = /obj/item/stack/sheet/mineral/wood layer = ABOVE_MOB_LAYER + plane = GAME_PLANE /obj/structure/railing/wooden_fence/Initialize(mapload) . = ..() @@ -167,7 +168,6 @@ /obj/structure/railing/wooden_fence/proc/adjust_dir_layer(direction) layer = (direction & NORTH) ? MOB_LAYER : initial(layer) - plane = (direction & NORTH) ? GAME_PLANE : initial(plane) /obj/structure/railing/corner/end/wooden_fence 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 f88aadc04631f..6522a2125fea3 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm @@ -69,7 +69,7 @@ deconstruct(FALSE) /obj/structure/transit_tube_pod/container_resist_act(mob/living/user) - if(!user.incapacitated()) + if(!user.incapacitated) empty_pod() return if(!moving) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index b2b3ee50df64c..46a113ae8d024 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -449,7 +449,7 @@ addtimer(VARSET_CALLBACK(src, atom_integrity, atom_integrity), time_to_go + time_to_return) //set the health back (icon is updated on move) addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/movable, forceMove), loc), time_to_go + time_to_return) //we back boys addtimer(VARSET_CALLBACK(src, dramatically_disappearing, FALSE), time_to_go + time_to_return) //also set the var back - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_appearance)), time_to_go + time_to_return) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound), get_turf(src), 'sound/effects/glass_reverse.ogg', 70, TRUE), time_to_go + time_to_return) var/obj/structure/grille/grill = take_grill ? (locate(/obj/structure/grille) in loc) : null if(grill) diff --git a/code/game/say.dm b/code/game/say.dm index 42aea57cf6110..d8cb91c4ea429 100644 --- a/code/game/say.dm +++ b/code/game/say.dm @@ -12,6 +12,7 @@ GLOBAL_LIST_INIT(freqtospan, list( "[FREQ_SECURITY]" = "secradio", "[FREQ_COMMAND]" = "comradio", "[FREQ_AI_PRIVATE]" = "aiprivradio", + "[FREQ_ENTERTAINMENT]" = "enteradio", "[FREQ_SYNDICATE]" = "syndradio", "[FREQ_UPLINK]" = "syndradio", // this probably shouldnt appear ingame "[FREQ_CENTCOM]" = "centcomradio", diff --git a/code/game/sound.dm b/code/game/sound.dm index 17e5f6e3e3209..311491468007b 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -473,6 +473,18 @@ 'sound/creatures/monkey/monkey_screech_6.ogg', 'sound/creatures/monkey/monkey_screech_7.ogg', ) + if(SFX_TOOL_SWITCH) + soundin = 'sound/items/handling/tool_switch.ogg' + if(SFX_KEYBOARD_CLICKS) + soundin = pick( + 'sound/machines/computer/keyboard_clicks_1.ogg', + 'sound/machines/computer/keyboard_clicks_2.ogg', + 'sound/machines/computer/keyboard_clicks_3.ogg', + 'sound/machines/computer/keyboard_clicks_4.ogg', + 'sound/machines/computer/keyboard_clicks_5.ogg', + 'sound/machines/computer/keyboard_clicks_6.ogg', + 'sound/machines/computer/keyboard_clicks_7.ogg', + ) if(SFX_STONE_DROP) soundin = pick( 'sound/items/stones/stone_drop1.ogg', @@ -484,4 +496,16 @@ 'sound/items/stones/stone_pick_up1.ogg', 'sound/items/stones/stone_pick_up2.ogg', ) + if(SFX_MUFFLED_SPEECH) + soundin = pick( + 'sound/effects/muffspeech/muffspeech1.ogg', + 'sound/effects/muffspeech/muffspeech2.ogg', + 'sound/effects/muffspeech/muffspeech3.ogg', + 'sound/effects/muffspeech/muffspeech4.ogg', + 'sound/effects/muffspeech/muffspeech5.ogg', + 'sound/effects/muffspeech/muffspeech6.ogg', + 'sound/effects/muffspeech/muffspeech7.ogg', + 'sound/effects/muffspeech/muffspeech8.ogg', + 'sound/effects/muffspeech/muffspeech9.ogg', + ) return soundin diff --git a/code/game/turfs/closed/walls.dm b/code/game/turfs/closed/walls.dm index ed31138bb19f8..a78579d713e9a 100644 --- a/code/game/turfs/closed/walls.dm +++ b/code/game/turfs/closed/walls.dm @@ -40,7 +40,7 @@ if(!iscarbon(dropping) && !iscyborg(dropping)) return var/mob/living/leaner = dropping - if(leaner.incapacitated(IGNORE_RESTRAINTS) || leaner.stat != CONSCIOUS || HAS_TRAIT(leaner, TRAIT_NO_TRANSFORM)) + if(INCAPACITATED_IGNORING(leaner, INCAPABLE_RESTRAINTS) || leaner.stat != CONSCIOUS || HAS_TRAIT(leaner, TRAIT_NO_TRANSFORM)) return if(!leaner.density || leaner.pulledby || leaner.buckled || !(leaner.mobility_flags & MOBILITY_STAND)) return diff --git a/code/game/turfs/open/floor/light_floor.dm b/code/game/turfs/open/floor/light_floor.dm index dd30a86d8de45..793e4ce8e55e4 100644 --- a/code/game/turfs/open/floor/light_floor.dm +++ b/code/game/turfs/open/floor/light_floor.dm @@ -184,7 +184,7 @@ /turf/open/floor/light/proc/check_menu(mob/living/user, obj/item/multitool) if(!istype(user)) return FALSE - if(user.incapacitated()) + if(user.incapacitated) return FALSE if(!multitool || !user.is_holding(multitool)) return FALSE diff --git a/code/modules/admin/verbs/borgpanel.dm b/code/modules/admin/verbs/borgpanel.dm index ffeb1cce2731c..b9843da93820d 100644 --- a/code/modules/admin/verbs/borgpanel.dm +++ b/code/modules/admin/verbs/borgpanel.dm @@ -153,15 +153,15 @@ ADMIN_VERB(borg_panel, R_ADMIN, "Show Borg Panel", ADMIN_VERB_NO_DESCRIPTION, AD if (!borg.radio.keyslot) // There's no encryption key. This shouldn't happen but we can cope borg.radio.channels -= channel if (channel == RADIO_CHANNEL_SYNDICATE) - borg.radio.syndie = FALSE + borg.radio.special_channels &= ~RADIO_SPECIAL_SYNDIE else if (channel == "CentCom") - borg.radio.independent = FALSE + borg.radio.special_channels &= ~RADIO_SPECIAL_CENTCOM else borg.radio.keyslot.channels -= channel if (channel == RADIO_CHANNEL_SYNDICATE) - borg.radio.keyslot.syndie = FALSE + borg.radio.keyslot.special_channels &= ~RADIO_SPECIAL_SYNDIE else if (channel == "CentCom") - borg.radio.keyslot.independent = FALSE + borg.radio.keyslot.special_channels &= ~RADIO_SPECIAL_CENTCOM message_admins("[key_name_admin(user)] removed the [channel] radio channel from [ADMIN_LOOKUPFLW(borg)].") log_silicon("[key_name(user)] removed the [channel] radio channel from [key_name(borg)].") else // We're adding a channel @@ -169,9 +169,9 @@ ADMIN_VERB(borg_panel, R_ADMIN, "Show Borg Panel", ADMIN_VERB_NO_DESCRIPTION, AD borg.radio.keyslot = new() borg.radio.keyslot.channels[channel] = 1 if (channel == RADIO_CHANNEL_SYNDICATE) - borg.radio.keyslot.syndie = TRUE + borg.radio.keyslot.special_channels |= RADIO_SPECIAL_SYNDIE else if (channel == "CentCom") - borg.radio.keyslot.independent = TRUE + borg.radio.keyslot.special_channels |= RADIO_SPECIAL_CENTCOM message_admins("[key_name_admin(user)] added the [channel] radio channel to [ADMIN_LOOKUPFLW(borg)].") log_silicon("[key_name(user)] added the [channel] radio channel to [key_name(borg)].") borg.radio.recalculateChannels() diff --git a/code/modules/admin/verbs/ert.dm b/code/modules/admin/verbs/ert.dm index 2d1ba075a4795..441a5d0dd56fe 100644 --- a/code/modules/admin/verbs/ert.dm +++ b/code/modules/admin/verbs/ert.dm @@ -90,6 +90,7 @@ "random_names" = list("desc" = "Randomize names", "type" = "boolean", "value" = "[(ertemplate.random_names ? "Yes" : "No")]"), "spawn_admin" = list("desc" = "Spawn yourself as briefing officer", "type" = "boolean", "value" = "[(ertemplate.spawn_admin ? "Yes" : "No")]"), "use_custom_shuttle" = list("desc" = "Use the ERT's custom shuttle (if it has one)", "type" = "boolean", "value" = "[(ertemplate.use_custom_shuttle ? "Yes" : "No")]"), + "mob_type" = list("desc" = "Base Species", "callback" = CALLBACK(src, PROC_REF(makeERTTemplateModified)), "type" = "datum", "path" = "/mob/living/carbon/human", "subtypesonly" = TRUE, "value" = ertemplate.mob_type), ) ) @@ -117,6 +118,7 @@ ertemplate.random_names = prefs["random_names"]["value"] == "Yes" ertemplate.spawn_admin = prefs["spawn_admin"]["value"] == "Yes" ertemplate.use_custom_shuttle = prefs["use_custom_shuttle"]["value"] == "Yes" + ertemplate.mob_type = prefs["mob_type"]["value"] var/list/spawnpoints = GLOB.emergencyresponseteamspawn var/index = 0 @@ -222,11 +224,15 @@ continue //Spawn the body - var/mob/living/carbon/human/ert_operative = new ertemplate.mobtype(spawnloc) - chosen_candidate.client.prefs.safe_transfer_prefs_to(ert_operative, is_antag = TRUE) + var/mob/living/carbon/human/ert_operative + if(ertemplate.mob_type) + ert_operative = new ertemplate.mob_type(spawnloc) + else + ert_operative = new /mob/living/carbon/human(spawnloc) + chosen_candidate.client.prefs.safe_transfer_prefs_to(ert_operative, is_antag = TRUE) ert_operative.key = chosen_candidate.key - if(ertemplate.enforce_human || !(ert_operative.dna.species.changesource_flags & ERT_SPAWN)) // Don't want any exploding plasmemes + if(ertemplate.enforce_human || !(ert_operative.dna.species.changesource_flags & ERT_SPAWN)) ert_operative.set_species(/datum/species/human) //Give antag datum diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index d51885d51431f..9aebab36aab68 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -271,6 +271,9 @@ GLOBAL_LIST_EMPTY(antagonists) if(count_against_dynamic_roll_chance && owner.current.stat != DEAD && owner.current.client) owner.current.add_to_current_living_antags() + for (var/datum/atom_hud/alternate_appearance/basic/antag_hud as anything in GLOB.active_alternate_appearances) + antag_hud.apply_to_new_mob(owner.current) + SEND_SIGNAL(owner, COMSIG_ANTAGONIST_GAINED, src) /** @@ -328,13 +331,8 @@ GLOBAL_LIST_EMPTY(antagonists) if(team) team.remove_member(owner) SEND_SIGNAL(owner, COMSIG_ANTAGONIST_REMOVED, src) - - // Remove HUDs that they should no longer see - var/mob/living/current = owner.current - for (var/datum/atom_hud/alternate_appearance/basic/has_antagonist/antag_hud as anything in GLOB.has_antagonist_huds) - if (!antag_hud.mobShouldSee(current)) - antag_hud.hide_from(current) - + if(owner.current) + SEND_SIGNAL(owner.current, COMSIG_MOB_ANTAGONIST_REMOVED, src) qdel(src) /** @@ -530,8 +528,7 @@ GLOBAL_LIST_EMPTY(antagonists) // Add HUDs that they couldn't see before for (var/datum/atom_hud/alternate_appearance/basic/has_antagonist/antag_hud as anything in GLOB.has_antagonist_huds) - if (antag_hud.mobShouldSee(owner.current)) - antag_hud.show_to(owner.current) + antag_hud.apply_to_new_mob(owner.current) /// Takes a location, returns an image drawing "on" it that matches this antag datum's hud icon /datum/antagonist/proc/hud_image_on(mob/hud_loc) diff --git a/code/modules/antagonists/_common/antag_hud.dm b/code/modules/antagonists/_common/antag_hud.dm index 863d52ef5ffe4..9933569f9a988 100644 --- a/code/modules/antagonists/_common/antag_hud.dm +++ b/code/modules/antagonists/_common/antag_hud.dm @@ -8,8 +8,9 @@ GLOBAL_LIST_EMPTY_TYPED(has_antagonist_huds, /datum/atom_hud/alternate_appearanc var/datum/weakref/team_ref /datum/atom_hud/alternate_appearance/basic/has_antagonist/New(key, image/I, antag_datum_type, datum/weakref/team) - src.antag_datum_type = antag_datum_type - team_ref = team + if(antag_datum_type) + src.antag_datum_type = antag_datum_type + src.team_ref = team GLOB.has_antagonist_huds += src return ..(key, I, NONE) @@ -18,6 +19,8 @@ GLOBAL_LIST_EMPTY_TYPED(has_antagonist_huds, /datum/atom_hud/alternate_appearanc return ..() /datum/atom_hud/alternate_appearance/basic/has_antagonist/mobShouldSee(mob/M) + if(add_ghost_version && isobserver(M)) + return FALSE // use the ghost version instead var/datum/team/antag_team = team_ref?.resolve() if(!isnull(antag_team)) return !!(M.mind in antag_team.members) diff --git a/code/modules/antagonists/abductor/equipment/gear/abductor_clothing.dm b/code/modules/antagonists/abductor/equipment/gear/abductor_clothing.dm index c54ce6937d86f..e5951473df087 100644 --- a/code/modules/antagonists/abductor/equipment/gear/abductor_clothing.dm +++ b/code/modules/antagonists/abductor/equipment/gear/abductor_clothing.dm @@ -103,6 +103,8 @@ /obj/item/clothing/suit/armor/abductor/vest/proc/return_disguise_name(mob/living/carbon/human/source, list/identity) SIGNAL_HANDLER + if(identity[VISIBLE_NAME_FORCED]) // name-forcing overrides disguise + return identity[VISIBLE_NAME_FACE] = disguise.name identity[VISIBLE_NAME_ID] = "" diff --git a/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm b/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm index d3f162f5fb55a..25bbea665777c 100644 --- a/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm +++ b/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm @@ -384,7 +384,7 @@ Congratulations! You are now trained for invasive xenobiology research!"} /obj/item/melee/baton/abductor/proc/SleepAttack(mob/living/target, mob/living/user) playsound(src, on_stun_sound, 50, TRUE, -1) - if(target.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB)) + if(INCAPACITATED_IGNORING(target, INCAPABLE_RESTRAINTS|INCAPABLE_GRAB)) if(target.can_block_magic(MAGIC_RESISTANCE_MIND)) to_chat(user, span_warning("The specimen has some kind of mental protection that is interfering with the sleep inducement! It seems you've been foiled.")) target.visible_message(span_danger("[user] tried to induced sleep in [target] with [src], but is unsuccessful!"), \ @@ -689,7 +689,7 @@ Congratulations! You are now trained for invasive xenobiology research!"} /obj/item/abductor/alien_omnitool/proc/check_menu(mob/user) if(!istype(user)) return FALSE - if(user.incapacitated() || !user.Adjacent(src)) + if(user.incapacitated || !user.Adjacent(src)) return FALSE return TRUE diff --git a/code/modules/antagonists/brother/brother.dm b/code/modules/antagonists/brother/brother.dm index 5f4622bd910a4..a2a64fc50b98d 100644 --- a/code/modules/antagonists/brother/brother.dm +++ b/code/modules/antagonists/brother/brother.dm @@ -221,6 +221,9 @@ return . = ..() member.remove_antag_datum(/datum/antagonist/brother) + if (!length(members)) + qdel(src) + return if (isnull(member.current)) return for (var/datum/mind/brother_mind as anything in members) diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index db261c29b5433..01d97f448cd60 100644 --- a/code/modules/antagonists/changeling/powers/mutations.dm +++ b/code/modules/antagonists/changeling/powers/mutations.dm @@ -498,6 +498,7 @@ lefthand_file = 'icons/mob/inhands/antag/changeling_lefthand.dmi' righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi' block_chance = 50 + is_bashable = FALSE var/remaining_uses //Set by the changeling ability. diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm index 39cd9b550ae45..f942e49f62201 100644 --- a/code/modules/antagonists/cult/blood_magic.dm +++ b/code/modules/antagonists/cult/blood_magic.dm @@ -79,7 +79,7 @@ return qdel(nullify_spell) BS = possible_spells[entered_spell_name] - if(QDELETED(src) || owner.incapacitated() || !BS || (rune && !(locate(/obj/effect/rune/empower) in range(1, owner))) || (length(spells) >= limit)) + if(QDELETED(src) || owner.incapacitated || !BS || (rune && !(locate(/obj/effect/rune/empower) in range(1, owner))) || (length(spells) >= limit)) return to_chat(owner,span_warning("You begin to carve unnatural symbols into your flesh!")) SEND_SOUND(owner, sound('sound/weapons/slice.ogg',0,1,10)) @@ -137,7 +137,7 @@ ..() /datum/action/innate/cult/blood_spell/IsAvailable(feedback = FALSE) - if(!IS_CULTIST(owner) || owner.incapacitated() || (!charges && deletes_on_empty)) + if(!IS_CULTIST(owner) || owner.incapacitated || (!charges && deletes_on_empty)) return FALSE return ..() @@ -263,7 +263,7 @@ SEND_SOUND(caller, sound('sound/effects/ghost.ogg', FALSE, TRUE, 50)) var/image/sparkle_image = image('icons/effects/cult.dmi', clicked_on, "bloodsparkles", ABOVE_MOB_LAYER) - clicked_on.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/cult, "cult_apoc", sparkle_image, NONE) + clicked_on.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/has_antagonist/cult, "cult_apoc", sparkle_image, NONE) addtimer(CALLBACK(clicked_on, TYPE_PROC_REF(/atom/, remove_alt_appearance), "cult_apoc", TRUE), 4 MINUTES, TIMER_OVERRIDE|TIMER_UNIQUE) to_chat(caller, span_cult_bold("[clicked_on] has been cursed with living nightmares!")) @@ -513,7 +513,7 @@ to_chat(user, span_warning("You must pick a valid rune!")) return var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to? - if(QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated() || !actual_selected_rune) + if(QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated || !actual_selected_rune) return var/turf/dest = get_turf(actual_selected_rune) if(dest.is_blocked_turf(TRUE)) @@ -699,7 +699,7 @@ /obj/item/melee/blood_magic/construction/proc/check_menu(mob/user) if(!istype(user)) CRASH("The cult construct selection radial menu was accessed by something other than a valid user.") - if(user.incapacitated() || !user.Adjacent(src)) + if(user.incapacitated || !user.Adjacent(src)) return FALSE return TRUE @@ -965,7 +965,7 @@ /obj/item/melee/blood_magic/manipulator/proc/check_menu(mob/living/user) if(!istype(user)) CRASH("The Blood Rites manipulator radial menu was accessed by something other than a valid user.") - if(user.incapacitated() || !user.Adjacent(src)) + if(user.incapacitated || !user.Adjacent(src)) return FALSE return TRUE diff --git a/code/modules/antagonists/cult/cult_comms.dm b/code/modules/antagonists/cult/cult_comms.dm index a4f3b291f74da..3d5677996502a 100644 --- a/code/modules/antagonists/cult/cult_comms.dm +++ b/code/modules/antagonists/cult/cult_comms.dm @@ -120,7 +120,7 @@ if(!team_member.current) continue team_member.current.update_mob_action_buttons() - if(team_member.current.incapacitated()) + if(team_member.current.incapacitated) continue SEND_SOUND(team_member.current, 'sound/hallucinations/im_here1.ogg') to_chat(team_member.current, span_cult_large("Acolyte [nominee] has asserted that [nominee.p_theyre()] worthy of leading the cult. A vote will be called shortly.")) @@ -129,19 +129,19 @@ ///Polls all Cultists on whether the person putting themselves forward should be made the Cult Leader, if they can actually be such. /proc/poll_cultists_for_leader(mob/living/nominee, datum/team/cult/team) - if(QDELETED(nominee) || nominee.incapacitated()) + if(QDELETED(nominee) || nominee.incapacitated) team.cult_vote_called = FALSE for(var/datum/mind/team_member as anything in team.members) if(!team_member.current) continue team_member.current.update_mob_action_buttons() - if(team_member.current.incapacitated()) + if(team_member.current.incapacitated) continue to_chat(team_member.current,span_cult_large("[nominee] has died in the process of attempting to start a vote!")) return FALSE var/list/mob/living/asked_cultists = list() for(var/datum/mind/team_member as anything in team.members) - if(!team_member.current || team_member.current == nominee || team_member.current.incapacitated()) + if(!team_member.current || team_member.current == nominee || team_member.current.incapacitated) continue SEND_SOUND(team_member.current, 'sound/magic/exit_blood.ogg') asked_cultists += team_member.current @@ -161,13 +161,13 @@ chat_text_border_icon = mutable_appearance('icons/effects/effects.dmi', "cult_master_logo") ) ) - if(QDELETED(nominee) || nominee.incapacitated()) + if(QDELETED(nominee) || nominee.incapacitated) team.cult_vote_called = FALSE for(var/datum/mind/team_member as anything in team.members) if(!team_member.current) continue team_member.current.update_mob_action_buttons() - if(team_member.current.incapacitated()) + if(team_member.current.incapacitated) continue to_chat(team_member.current,span_cult_large("[nominee] has died in the process of attempting to win the cult's support!")) return FALSE @@ -177,7 +177,7 @@ if(!team_member.current) continue team_member.current.update_mob_action_buttons() - if(team_member.current.incapacitated()) + if(team_member.current.incapacitated) continue to_chat(team_member.current,span_cult_large("[nominee] has gone catatonic in the process of attempting to win the cult's support!")) return FALSE @@ -187,7 +187,7 @@ if(!team_member.current) continue team_member.current.update_mob_action_buttons() - if(team_member.current.incapacitated()) + if(team_member.current.incapacitated) continue to_chat(team_member.current, span_cult_large("[nominee] could not win the cult's support and shall continue to serve as an acolyte.")) return FALSE diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index 994f98ed099ea..4c6fa90759ab3 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -911,7 +911,7 @@ Striking a noncultist, however, will tear their flesh."} cultists |= cult_mind.current var/mob/living/cultist_to_receive = tgui_input_list(user, "Who do you wish to call to [src]?", "Followers of the Geometer", (cultists - user)) - if(QDELETED(src) || loc != user || user.incapacitated()) + if(QDELETED(src) || loc != user || user.incapacitated) return ITEM_INTERACT_BLOCKING if(isnull(cultist_to_receive)) to_chat(user, span_cult_italic("You require a destination!")) @@ -1223,6 +1223,7 @@ Striking a noncultist, however, will tear their flesh."} attack_verb_simple = list("bump", "prod") hitsound = 'sound/weapons/smash.ogg' block_sound = 'sound/weapons/effects/ric5.ogg' + shield_bash_sound = 'sound/effects/glassknock.ogg' var/illusions = 2 /obj/item/shield/mirror/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE) diff --git a/code/modules/antagonists/cult/cult_structures.dm b/code/modules/antagonists/cult/cult_structures.dm index 2cdb2c2e6f468..773f890d25dbb 100644 --- a/code/modules/antagonists/cult/cult_structures.dm +++ b/code/modules/antagonists/cult/cult_structures.dm @@ -201,7 +201,7 @@ * Returns TRUE if the user is a living mob that is a cultist and is not incapacitated. */ /obj/structure/destructible/cult/item_dispenser/proc/check_menu(mob/user) - return isliving(user) && is_cultist_check(user) && !user.incapacitated() + return isliving(user) && is_cultist_check(user) && !user.incapacitated // Spooky looking door used in gateways. Or something. /obj/effect/gateway diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index d8ce241caf3c8..c201af65dfb8e 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -505,7 +505,7 @@ structure_check() searches for nearby cultist structures required for the invoca fail_invoke() return var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to? - if(!Adjacent(user) || QDELETED(src) || user.incapacitated() || !actual_selected_rune) + if(!Adjacent(user) || QDELETED(src) || user.incapacitated || !actual_selected_rune) fail_invoke() return @@ -774,7 +774,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0) /obj/effect/rune/raise_dead/proc/validness_checks(mob/living/target_mob, mob/living/user) if(QDELETED(user)) return FALSE - if(!Adjacent(user) || user.incapacitated()) + if(!Adjacent(user) || user.incapacitated) return FALSE if(QDELETED(target_mob)) return FALSE @@ -839,7 +839,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0) return var/mob/living/cultist_to_summon = tgui_input_list(user, "Who do you wish to call to [src]?", "Followers of the Geometer", cultists) var/fail_logmsg = "Summon Cultist rune activated by [user] at [COORD(src)] failed - " - if(!Adjacent(user) || !src || QDELETED(src) || user.incapacitated()) + if(!Adjacent(user) || !src || QDELETED(src) || user.incapacitated) return if(isnull(cultist_to_summon)) to_chat(user, "You require a summoning target!") @@ -1160,8 +1160,8 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0) images += B if(!IS_CULTIST(M)) if(M.client) - var/image/C = image('icons/effects/cult.dmi',M,"bloodsparkles", ABOVE_MOB_LAYER) - add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/cult, "cult_apoc", C, NONE) + var/image/C = image('icons/effects/cult.dmi', M, "bloodsparkles", ABOVE_MOB_LAYER) + add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/has_antagonist/cult, "cult_apoc", C, NONE) addtimer(CALLBACK(M, TYPE_PROC_REF(/atom/, remove_alt_appearance),"cult_apoc",TRUE), duration) images += C else diff --git a/code/modules/antagonists/ert/ert.dm b/code/modules/antagonists/ert/ert.dm index 5d266227a1053..4b94666abc367 100644 --- a/code/modules/antagonists/ert/ert.dm +++ b/code/modules/antagonists/ert/ert.dm @@ -238,6 +238,10 @@ H.open_internals(H.get_item_for_held_index(2)) H.equipOutfit(outfit) + if(isplasmaman(H)) + var/obj/item/mod/control/our_modsuit = locate() in H.get_equipped_items() + if(our_modsuit) + our_modsuit.install(new /obj/item/mod/module/plasma_stabilizer) /datum/antagonist/ert/greet() if(!ert_team) @@ -285,3 +289,13 @@ name = "Frontier Militia General" outfit = /datum/outfit/centcom/militia/general role = "General" + +/datum/antagonist/ert/medical_commander + role = "Chief EMT" + outfit = /datum/outfit/centcom/ert/medical_commander + plasmaman_outfit = /datum/outfit/plasmaman/medical_commander + +/datum/antagonist/ert/medical_technician + role = "Emergency Medical Technician" + outfit = /datum/outfit/centcom/ert/medical_technician + plasmaman_outfit = /datum/outfit/plasmaman/medical_technician diff --git a/code/modules/antagonists/heretic/heretic_antag.dm b/code/modules/antagonists/heretic/heretic_antag.dm index 67a12b3555188..1babdabcbf522 100644 --- a/code/modules/antagonists/heretic/heretic_antag.dm +++ b/code/modules/antagonists/heretic/heretic_antag.dm @@ -313,7 +313,6 @@ RegisterSignal(our_mob, COMSIG_LIVING_CULT_SACRIFICED, PROC_REF(on_cult_sacrificed)) RegisterSignals(our_mob, list(COMSIG_MOB_BEFORE_SPELL_CAST, COMSIG_MOB_SPELL_ACTIVATED), PROC_REF(on_spell_cast)) RegisterSignal(our_mob, COMSIG_USER_ITEM_INTERACTION, PROC_REF(on_item_use)) - RegisterSignal(our_mob, COMSIG_MOB_LOGIN, PROC_REF(fix_influence_network)) RegisterSignal(our_mob, COMSIG_LIVING_POST_FULLY_HEAL, PROC_REF(after_fully_healed)) /datum/antagonist/heretic/remove_innate_effects(mob/living/mob_override) @@ -329,7 +328,6 @@ COMSIG_MOB_BEFORE_SPELL_CAST, COMSIG_MOB_SPELL_ACTIVATED, COMSIG_USER_ITEM_INTERACTION, - COMSIG_MOB_LOGIN, COMSIG_LIVING_POST_FULLY_HEAL, COMSIG_LIVING_CULT_SACRIFICED, )) @@ -457,18 +455,6 @@ var/obj/item/offhand = user.get_inactive_held_item() return !QDELETED(offhand) && istype(offhand, /obj/item/melee/touch_attack/mansus_fist) -/* - * Signal proc for [COMSIG_MOB_LOGIN]. - * - * Calls rework_network() on our reality smash tracker - * whenever a login / client change happens, to ensure - * influence client visibility is fixed. - */ -/datum/antagonist/heretic/proc/fix_influence_network(mob/source) - SIGNAL_HANDLER - - GLOB.reality_smash_track.rework_network() - /// Signal proc for [COMSIG_LIVING_POST_FULLY_HEAL], /// Gives the heretic aliving heart on aheal or organ refresh /datum/antagonist/heretic/proc/after_fully_healed(mob/living/source, heal_flags) @@ -656,7 +642,7 @@ /datum/antagonist/heretic/proc/passive_influence_gain() knowledge_points++ if(owner.current.stat <= SOFT_CRIT) - to_chat(owner.current, "[span_hear("You hear a whisper...")] [span_hypnophrase(pick(strings(HERETIC_INFLUENCE_FILE, "drain_message")))]") + to_chat(owner.current, "[span_hear("You hear a whisper...")] [span_hypnophrase(pick_list(HERETIC_INFLUENCE_FILE, "drain_message"))]") addtimer(CALLBACK(src, PROC_REF(passive_influence_gain)), passive_gain_timer) /datum/antagonist/heretic/roundend_report() diff --git a/code/modules/antagonists/heretic/heretic_knowledge.dm b/code/modules/antagonists/heretic/heretic_knowledge.dm index 6cab092280000..6c77ed0d6ccea 100644 --- a/code/modules/antagonists/heretic/heretic_knowledge.dm +++ b/code/modules/antagonists/heretic/heretic_knowledge.dm @@ -680,9 +680,8 @@ our_heretic.knowledge_points += KNOWLEDGE_RITUAL_POINTS was_completed = TRUE - var/drain_message = pick(strings(HERETIC_INFLUENCE_FILE, "drain_message")) to_chat(user, span_boldnotice("[name] completed!")) - to_chat(user, span_hypnophrase(span_big("[drain_message]"))) + to_chat(user, span_hypnophrase(span_big("[pick_list(HERETIC_INFLUENCE_FILE, "drain_message")]"))) desc += " (Completed!)" log_heretic_knowledge("[key_name(user)] completed a [name] at [worldtime2text()].") user.add_mob_memory(/datum/memory/heretic_knowledge_ritual) diff --git a/code/modules/antagonists/heretic/influences.dm b/code/modules/antagonists/heretic/influences.dm index 631bf04dcefc6..dcdfb175d1328 100644 --- a/code/modules/antagonists/heretic/influences.dm +++ b/code/modules/antagonists/heretic/influences.dm @@ -29,36 +29,6 @@ tracked_heretics.Cut() return ..() -/** - * Automatically fixes the target and smash network - * - * Fixes any bugs that are caused by late Generate() or exchanging clients - */ -/datum/reality_smash_tracker/proc/rework_network() - SIGNAL_HANDLER - - for(var/mind in tracked_heretics) - if(isnull(mind)) - stack_trace("A null somehow landed in the [type] list of minds. How?") - tracked_heretics -= mind - continue - - add_to_smashes(mind) - -/** - * Allow [to_add] to see all tracked reality smashes. - */ -/datum/reality_smash_tracker/proc/add_to_smashes(datum/mind/to_add) - for(var/obj/effect/heretic_influence/reality_smash as anything in smashes) - reality_smash.add_mind(to_add) - -/** - * Stop [to_remove] from seeing any tracked reality smashes. - */ -/datum/reality_smash_tracker/proc/remove_from_smashes(datum/mind/to_remove) - for(var/obj/effect/heretic_influence/reality_smash as anything in smashes) - reality_smash.remove_mind(to_remove) - /** * Generates a set amount of reality smashes * based on the number of already existing smashes @@ -83,8 +53,6 @@ new /obj/effect/heretic_influence(chosen_location) - rework_network() - /** * Adds a mind to the list of people that can see the reality smashes * @@ -97,9 +65,6 @@ if(ishuman(heretic.current) && !is_centcom_level(heretic.current.z)) generate_new_influences() - add_to_smashes(heretic) - - /** * Removes a mind from the list of people that can see the reality smashes * @@ -108,8 +73,6 @@ /datum/reality_smash_tracker/proc/remove_tracked_mind(datum/mind/heretic) tracked_heretics -= heretic - remove_from_smashes(heretic) - /obj/effect/visible_heretic_influence name = "pierced reality" icon = 'icons/effects/eldritch.dmi' @@ -201,46 +164,23 @@ var/being_drained = FALSE /// The icon state applied to the image created for this influence. var/real_icon_state = "reality_smash" - /// A list of all minds that can see us. - var/list/datum/mind/minds = list() - /// The image shown to heretics - var/image/heretic_image - /// We hold the turf we're on so we can remove and add the 'no prints' flag. - var/turf/on_turf /obj/effect/heretic_influence/Initialize(mapload) . = ..() GLOB.reality_smash_track.smashes += src - heretic_image = image(icon, src, real_icon_state, OBJ_LAYER) generate_name() - on_turf = get_turf(src) - if(!istype(on_turf)) - return - on_turf.interaction_flags_atom |= INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND - RegisterSignal(on_turf, COMSIG_TURF_CHANGE, PROC_REF(replace_our_turf)) + var/image/heretic_image = image(icon, src, real_icon_state, OBJ_LAYER) + add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/has_antagonist/heretic, "reality_smash", heretic_image) + + AddElement(/datum/element/block_turf_fingerprints) AddComponent(/datum/component/redirect_attack_hand_from_turf, interact_check = CALLBACK(src, PROC_REF(verify_user_can_see))) /obj/effect/heretic_influence/proc/verify_user_can_see(mob/user) - return (user?.mind in minds) - -/obj/effect/heretic_influence/proc/replace_our_turf(datum/source, path, new_baseturfs, flags, post_change_callbacks) - SIGNAL_HANDLER - post_change_callbacks += CALLBACK(src, PROC_REF(replace_our_turf_two)) - on_turf = null //hard del ref? - -/obj/effect/heretic_influence/proc/replace_our_turf_two(turf/new_turf) - new_turf.interaction_flags_atom |= INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND - on_turf = new_turf + return (user.mind in GLOB.reality_smash_track.tracked_heretics) /obj/effect/heretic_influence/Destroy() GLOB.reality_smash_track.smashes -= src - for(var/datum/mind/heretic in minds) - remove_mind(heretic) - - heretic_image = null - on_turf?.interaction_flags_atom &= ~INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND - on_turf = null return ..() /obj/effect/heretic_influence/attack_hand_secondary(mob/user, list/modifiers) @@ -296,43 +236,29 @@ // Aaand now we delete it after_drain(user) -/* +/** * Handle the effects of the drain. */ /obj/effect/heretic_influence/proc/after_drain(mob/living/user) if(user) - to_chat(user, span_hypnophrase(pick(strings(HERETIC_INFLUENCE_FILE, "drain_message")))) + to_chat(user, span_hypnophrase(pick_list(HERETIC_INFLUENCE_FILE, "drain_message"))) to_chat(user, span_warning("[src] begins to fade into reality!")) var/obj/effect/visible_heretic_influence/illusion = new /obj/effect/visible_heretic_influence(drop_location()) - illusion.name = "\improper" + pick(strings(HERETIC_INFLUENCE_FILE, "drained")) + " " + format_text(name) + illusion.name = "\improper" + pick_list(HERETIC_INFLUENCE_FILE, "drained") + " " + format_text(name) GLOB.reality_smash_track.num_drained++ qdel(src) -/* - * Add a mind to the list of tracked minds, - * making another person able to see us. - */ -/obj/effect/heretic_influence/proc/add_mind(datum/mind/heretic) - minds |= heretic - heretic.current?.client?.images |= heretic_image - -/* - * Remove a mind present in our list - * from being able to see us. - */ -/obj/effect/heretic_influence/proc/remove_mind(datum/mind/heretic) - if(!(heretic in minds)) - CRASH("[type] - remove_mind called with a mind not present in the minds list!") - - minds -= heretic - heretic.current?.client?.images -= heretic_image - -/* +/** * Generates a random name for the influence. */ /obj/effect/heretic_influence/proc/generate_name() - name = "\improper" + pick(strings(HERETIC_INFLUENCE_FILE, "prefix")) + " " + pick(strings(HERETIC_INFLUENCE_FILE, "postfix")) + name = "\improper" + pick_list(HERETIC_INFLUENCE_FILE, "prefix") + " " + pick_list(HERETIC_INFLUENCE_FILE, "postfix") #undef NUM_INFLUENCES_PER_HERETIC + +/// Hud used for heretics to see influences +/datum/atom_hud/alternate_appearance/basic/has_antagonist/heretic + antag_datum_type = /datum/antagonist/heretic + add_ghost_version = TRUE diff --git a/code/modules/antagonists/heretic/knowledge/blade_lore.dm b/code/modules/antagonists/heretic/knowledge/blade_lore.dm index de79151739f4b..55db187ee73ba 100644 --- a/code/modules/antagonists/heretic/knowledge/blade_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/blade_lore.dm @@ -147,7 +147,7 @@ if(!riposte_ready) return - if(source.incapacitated(IGNORE_GRAB)) + if(INCAPACITATED_IGNORING(source, INCAPABLE_GRAB)) return var/mob/living/attacker = hitby.loc diff --git a/code/modules/antagonists/heretic/knowledge/lock_lore.dm b/code/modules/antagonists/heretic/knowledge/lock_lore.dm index 17e73cb162c17..ac375d7942a36 100644 --- a/code/modules/antagonists/heretic/knowledge/lock_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/lock_lore.dm @@ -136,7 +136,7 @@ /datum/heretic_knowledge/limited_amount/concierge_rite // item that creates 3 max at a time heretic only barriers, probably should limit to 1 only, holy people can also pass name = "Concierge's Rite" - desc = "Allows you to transmute a white crayon, a wooden plank, and a multitool to create a Labyrinth Handbook. \ + desc = "Allows you to transmute a stick of chalk, a wooden plank, and a multitool to create a Labyrinth Handbook. \ It can materialize a barricade at range that only you and people resistant to magic can pass. 3 uses." gain_text = "The Concierge scribbled my name into the Handbook. \"Welcome to your new home, fellow Steward.\"" required_atoms = list( diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm index 3020c0b2530c0..7b53ff43b3c04 100644 --- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm +++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm @@ -403,6 +403,8 @@ to_chat(sac_target, span_big(span_hypnophrase("Unnatural forces begin to claw at your every being from beyond the veil."))) + playsound(sac_target, 'sound/ambience/antag/heretic/heretic_sacrifice.ogg', 50, FALSE) // play theme + sac_target.apply_status_effect(/datum/status_effect/unholy_determination, SACRIFICE_REALM_DURATION) addtimer(CALLBACK(src, PROC_REF(after_target_wakes), sac_target), SACRIFICE_SLEEP_DURATION * 0.5) // Begin the minigame diff --git a/code/modules/antagonists/heretic/knowledge/starting_lore.dm b/code/modules/antagonists/heretic/knowledge/starting_lore.dm index 4e5e2910e0ef9..cbf4dad0d54ef 100644 --- a/code/modules/antagonists/heretic/knowledge/starting_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/starting_lore.dm @@ -271,7 +271,7 @@ GLOBAL_LIST_INIT(heretic_start_knowledge, initialize_starting_knowledge()) /datum/heretic_knowledge/codex_cicatrix/cleanup_atoms(list/selected_atoms) var/mob/living/body = locate() in selected_atoms if(!body) - return + return ..() // A golem or an android doesn't have skin! var/exterior_text = "skin" // If carbon, it's the limb. If not, it's the body. @@ -332,5 +332,5 @@ GLOBAL_LIST_INIT(heretic_start_knowledge, initialize_starting_knowledge()) sleep(1 SECONDS) heretic_datum.feast_of_owls = TRUE to_chat(user, span_danger(span_big("Your ambition is ravaged, but something powerful remains in its wake..."))) - var/drain_message = pick(strings(HERETIC_INFLUENCE_FILE, "drain_message")) + var/drain_message = pick_list(HERETIC_INFLUENCE_FILE, "drain_message") to_chat(user, span_hypnophrase(span_big("[drain_message]"))) diff --git a/code/modules/antagonists/heretic/status_effects/buffs.dm b/code/modules/antagonists/heretic/status_effects/buffs.dm index c72e6bfdef113..1668ea5a11ef7 100644 --- a/code/modules/antagonists/heretic/status_effects/buffs.dm +++ b/code/modules/antagonists/heretic/status_effects/buffs.dm @@ -232,6 +232,7 @@ blade_orbit_radius = 20, time_between_initial_blades = 0.25 SECONDS, blade_recharge_time = 1 MINUTES, + blade_type = /obj/effect/floating_blade, ) src.blade_recharge_time = blade_recharge_time diff --git a/code/modules/antagonists/malf_ai/malf_ai_modules.dm b/code/modules/antagonists/malf_ai/malf_ai_modules.dm index 57e6ec444196e..881dac74acc46 100644 --- a/code/modules/antagonists/malf_ai/malf_ai_modules.dm +++ b/code/modules/antagonists/malf_ai/malf_ai_modules.dm @@ -446,7 +446,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) desc = "[desc] It has [uses] use\s remaining." /datum/action/innate/ai/ranged/override_machine/do_ability(mob/living/caller, atom/clicked_on) - if(caller.incapacitated()) + if(caller.incapacitated) unset_ranged_ability(caller) return FALSE if(!ismachinery(clicked_on)) @@ -539,7 +539,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) qdel(to_explode) /datum/action/innate/ai/ranged/overload_machine/do_ability(mob/living/caller, atom/clicked_on) - if(caller.incapacitated()) + if(caller.incapacitated) unset_ranged_ability(caller) return FALSE if(!ismachinery(clicked_on)) @@ -679,7 +679,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) C.images -= I /mob/living/silicon/ai/proc/can_place_transformer(datum/action/innate/ai/place_transformer/action) - if(!eyeobj || !isturf(loc) || incapacitated() || !action) + if(!eyeobj || !isturf(loc) || incapacitated || !action) return var/turf/middle = get_turf(eyeobj) var/list/turfs = list(middle, locate(middle.x - 1, middle.y, middle.z), locate(middle.x + 1, middle.y, middle.z)) @@ -1096,7 +1096,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) var/mob/living/silicon/ai/ai_caller = caller - if(ai_caller.incapacitated()) + if(ai_caller.incapacitated) unset_ranged_ability(caller) return FALSE @@ -1186,7 +1186,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) return FALSE var/mob/living/silicon/ai/ai_caller = caller - if (ai_caller.incapacitated() || !isturf(ai_caller.loc)) + if (ai_caller.incapacitated || !isturf(ai_caller.loc)) return FALSE var/turf/target = get_turf(clicked_on) @@ -1214,7 +1214,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) COOLDOWN_START(src, time_til_next_tilt, roll_over_cooldown) /datum/action/innate/ai/ranged/core_tilt/proc/do_roll_over(mob/living/silicon/ai/ai_caller, picked_dir) - if (ai_caller.incapacitated() || !isturf(ai_caller.loc)) // prevents bugs where the ai is carded and rolls + if (ai_caller.incapacitated || !isturf(ai_caller.loc)) // prevents bugs where the ai is carded and rolls return var/turf/target = get_step(ai_caller, picked_dir) // in case we moved we pass the dir not the target turf @@ -1228,7 +1228,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) /// Used in our radial menu, state-checking proc after the radial menu sleeps /datum/action/innate/ai/ranged/core_tilt/proc/radial_check(mob/living/silicon/ai/caller) - if (QDELETED(caller) || caller.incapacitated() || caller.stat == DEAD) + if (QDELETED(caller) || caller.incapacitated || caller.stat == DEAD) return FALSE if (uses <= 0) @@ -1275,7 +1275,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) return FALSE var/mob/living/silicon/ai/ai_caller = caller - if(ai_caller.incapacitated()) + if(ai_caller.incapacitated) unset_ranged_ability(caller) return FALSE @@ -1331,7 +1331,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) /// Used in our radial menu, state-checking proc after the radial menu sleeps /datum/action/innate/ai/ranged/remote_vendor_tilt/proc/radial_check(mob/living/silicon/ai/caller, obj/machinery/vending/clicked_vendor) - if (QDELETED(caller) || caller.incapacitated() || caller.stat == DEAD) + if (QDELETED(caller) || caller.incapacitated || caller.stat == DEAD) return FALSE if (QDELETED(clicked_vendor)) diff --git a/code/modules/antagonists/pirate/pirate_outfits.dm b/code/modules/antagonists/pirate/pirate_outfits.dm index 72318fe4987ca..14ba07cad274f 100644 --- a/code/modules/antagonists/pirate/pirate_outfits.dm +++ b/code/modules/antagonists/pirate/pirate_outfits.dm @@ -42,6 +42,7 @@ belt = /obj/item/gun/magic/midas_hand l_pocket = /obj/item/coin/gold/doubloon + /datum/outfit/pirate/space name = "Space Pirate (EVA)" @@ -55,6 +56,8 @@ head = /obj/item/clothing/head/helmet/space/pirate + id_trim = /datum/id_trim/pirate/captain + /datum/outfit/pirate/silverscale name = "Silver Scale Member" @@ -151,6 +154,8 @@ suit = /obj/item/clothing/suit/jacket/oversized head = /obj/item/clothing/head/costume/crown + id_trim = /datum/id_trim/pirate/captain + /datum/outfit/pirate/medieval name = "Medieval Warmonger" @@ -181,3 +186,5 @@ belt = /obj/item/gun/magic/hook l_pocket = /obj/item/tank/internals/emergency_oxygen r_pocket = /obj/item/flashlight/lantern + + skillchips = list(/obj/item/skillchip/big_pointer) //they don't have an id, so this is needed diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm index fa07215cf6715..695586dbe98d0 100644 --- a/code/modules/antagonists/revolution/revolution.dm +++ b/code/modules/antagonists/revolution/revolution.dm @@ -433,7 +433,7 @@ var/list/datum/mind/promotable = list() var/list/datum/mind/monkey_promotable = list() for(var/datum/mind/khrushchev in non_heads) - if(khrushchev.current && !khrushchev.current.incapacitated() && !HAS_TRAIT(khrushchev.current, TRAIT_RESTRAINED) && khrushchev.current.client) + if(khrushchev.current && !khrushchev.current.incapacitated && !HAS_TRAIT(khrushchev.current, TRAIT_RESTRAINED) && khrushchev.current.client) if((ROLE_REV_HEAD in khrushchev.current.client.prefs.be_special) || (ROLE_PROVOCATEUR in khrushchev.current.client.prefs.be_special)) if(!ismonkey(khrushchev.current)) promotable += khrushchev diff --git a/code/modules/antagonists/spy/spy_bounty.dm b/code/modules/antagonists/spy/spy_bounty.dm index 01a1a1baf7b9a..42ab0203e5c03 100644 --- a/code/modules/antagonists/spy/spy_bounty.dm +++ b/code/modules/antagonists/spy/spy_bounty.dm @@ -529,7 +529,7 @@ return TRUE if(IS_WEAKREF_OF(stealing, target_ref)) var/mob/living/carbon/human/target = stealing - if(!target.incapacitated(IGNORE_RESTRAINTS|IGNORE_STASIS)) + if(!INCAPACITATED_IGNORING(target, INCAPABLE_RESTRAINTS|INCAPABLE_STASIS)) return FALSE if(find_desired_thing(target)) return TRUE diff --git a/code/modules/antagonists/voidwalker/voidwalker_abilities.dm b/code/modules/antagonists/voidwalker/voidwalker_abilities.dm index 4fe88f50d01c6..7c1771cdb4fe7 100644 --- a/code/modules/antagonists/voidwalker/voidwalker_abilities.dm +++ b/code/modules/antagonists/voidwalker/voidwalker_abilities.dm @@ -37,7 +37,7 @@ spookify(cast_on) return owner.balloon_alert(owner, "line of sight broken!") - return SPELL_CANCEL_CAST + return SPELL_NO_IMMEDIATE_COOLDOWN /datum/action/cooldown/spell/pointed/unsettle/proc/check_if_in_view(mob/living/carbon/human/target) SIGNAL_HANDLER diff --git a/code/modules/antagonists/voidwalker/voidwalker_species.dm b/code/modules/antagonists/voidwalker/voidwalker_species.dm index 069582fbb2c7e..5b50c3da69ed9 100644 --- a/code/modules/antagonists/voidwalker/voidwalker_species.dm +++ b/code/modules/antagonists/voidwalker/voidwalker_species.dm @@ -20,6 +20,7 @@ TRAIT_ADVANCEDTOOLUSER, TRAIT_NO_BLOOD_OVERLAY, TRAIT_NO_THROWING, + TRAIT_GENELESS, ) changesource_flags = MIRROR_BADMIN diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm index 3bea19a5bb309..e5f991c33a122 100644 --- a/code/modules/antagonists/wizard/equipment/soulstone.dm +++ b/code/modules/antagonists/wizard/equipment/soulstone.dm @@ -372,7 +372,7 @@ /obj/item/soulstone/proc/check_menu(mob/user, obj/structure/constructshell/shell) if(!istype(user)) return FALSE - if(user.incapacitated() || !user.is_holding(src) || !user.CanReach(shell, src)) + if(user.incapacitated || !user.is_holding(src) || !user.CanReach(shell, src)) return FALSE return TRUE @@ -444,7 +444,7 @@ /// Called when a ghost is chosen to become a shade. /obj/item/soulstone/proc/on_poll_concluded(mob/living/master, mob/living/victim, mob/dead/observer/ghost) - if(isnull(victim) || master.incapacitated() || !master.is_holding(src) || !master.CanReach(victim, src)) + if(isnull(victim) || master.incapacitated || !master.is_holding(src) || !master.CanReach(victim, src)) return FALSE if(isnull(ghost?.client)) to_chat(master, span_danger("There were no spirits willing to become a shade.")) diff --git a/code/modules/antagonists/wizard/equipment/spellbook_entries/perks.dm b/code/modules/antagonists/wizard/equipment/spellbook_entries/perks.dm index 6cebe8fa1e974..0230274b8e88b 100644 --- a/code/modules/antagonists/wizard/equipment/spellbook_entries/perks.dm +++ b/code/modules/antagonists/wizard/equipment/spellbook_entries/perks.dm @@ -42,9 +42,9 @@ /datum/spellbook_entry/perks/dejavu/proc/give_dejavu(mob/living/carbon/human/wizard, area/new_area) SIGNAL_HANDLER - if(new_area == GLOB.areas_by_type[/area/centcom/wizard_station]) + if(istype(new_area, /area/centcom)) return - wizard.AddComponent(/datum/component/dejavu/timeline, -1, 60 SECONDS) + wizard.AddComponent(/datum/component/dejavu/wizard, 1, 60 SECONDS, TRUE) UnregisterSignal(wizard, COMSIG_ENTER_AREA) /datum/spellbook_entry/perks/spell_lottery diff --git a/code/modules/art/paintings.dm b/code/modules/art/paintings.dm index 8affc71e568f3..567ac383d9440 100644 --- a/code/modules/art/paintings.dm +++ b/code/modules/art/paintings.dm @@ -545,6 +545,8 @@ /obj/item/canvas/twentythree_twentythree, /obj/item/canvas/twentyfour_twentyfour, ) + /// the type of wallframe it 'disassembles' into + var/wallframe_type = /obj/item/wallframe/painting /obj/structure/sign/painting/Initialize(mapload, dir, building) . = ..() @@ -565,6 +567,16 @@ else return ..() +/obj/structure/sign/painting/knock_down(mob/living/user) + var/turf/drop_turf + if(user) + drop_turf = get_turf(user) + else + drop_turf = drop_location() + current_canvas?.forceMove(drop_turf) + var/obj/item/wallframe/frame = new wallframe_type(drop_turf) + frame.update_integrity(get_integrity()) //Transfer how damaged it is. + /obj/structure/sign/painting/examine(mob/user) . = ..() if(persistence_id) @@ -768,6 +780,7 @@ /obj/item/canvas/thirtysix_twentyfour, /obj/item/canvas/fortyfive_twentyseven, ) + wallframe_type = /obj/item/wallframe/painting/large /obj/structure/sign/painting/large/Initialize(mapload) . = ..() diff --git a/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm b/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm index 0cb82c5c77c7c..6f1e0c6fcd9cb 100644 --- a/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm +++ b/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm @@ -8,7 +8,7 @@ idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 0.05 active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.02 power_channel = AREA_USAGE_ENVIRON - req_access = list(ACCESS_ATMOSPHERICS) + req_access = list(ACCESS_ENGINEERING) max_integrity = 250 integrity_failure = 0.33 armor_type = /datum/armor/machinery_airalarm diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm index 8674e6331e4ac..12e6c684079e6 100644 --- a/code/modules/atmospherics/machinery/atmosmachinery.dm +++ b/code/modules/atmospherics/machinery/atmosmachinery.dm @@ -112,7 +112,7 @@ turf_loc.add_blueprints_preround(src) if(hide) - RegisterSignal(src, COMSIG_OBJ_HIDE, PROC_REF(on_hide)) + setup_hiding() SSspatial_grid.add_grid_awareness(src, SPATIAL_GRID_CONTENTS_TYPE_ATMOS) SSspatial_grid.add_grid_membership(src, turf_loc, SPATIAL_GRID_CONTENTS_TYPE_ATMOS) @@ -133,9 +133,18 @@ return ..() /** - * Handler for `COMSIG_OBJ_HIDE`, connects only if `hide` is set to `TRUE`. Calls `update_cap_visuals` on pipe and its connected nodes + * Sets up our pipe hiding logic, consolidated in one place so subtypes may override it. + * This lets subtypes implement their own hiding logic without needing to worry about conflicts with the parent hiding logic. */ -/obj/machinery/atmospherics/proc/on_hide(datum/source, underfloor_accessibility) +/obj/machinery/atmospherics/proc/setup_hiding() + // Register pipe cap updating when hidden/unhidden + RegisterSignal(src, COMSIG_OBJ_HIDE, PROC_REF(on_hide)) + +/** + * Signal handler. Updates both our pipe cap visuals and those of adjacent nodes. + * We update adjacent nodes as their pipe caps are based partially on our state, so they need updating as well. + */ +/obj/machinery/atmospherics/proc/on_hide(datum/source) SHOULD_CALL_PARENT(TRUE) SIGNAL_HANDLER @@ -651,7 +660,8 @@ if(HAS_TRAIT(node, TRAIT_UNDERFLOOR)) continue - if(isplatingturf(get_turf(node))) + var/turf/node_turf = get_turf(node) + if(isplatingturf(node_turf) || iscatwalkturf(node_turf)) continue var/connected_dir = get_dir(src, node) diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index acb454a983689..70cafb11be888 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -660,7 +660,7 @@ if(isliving(target)) var/mob/living/living_mob = target - if(living_mob.incapacitated()) + if(living_mob.incapacitated) close_machine(target) return diff --git a/code/modules/atmospherics/machinery/datum_pipeline.dm b/code/modules/atmospherics/machinery/datum_pipeline.dm index 9c953922c72a7..9d9a5a6292f5d 100644 --- a/code/modules/atmospherics/machinery/datum_pipeline.dm +++ b/code/modules/atmospherics/machinery/datum_pipeline.dm @@ -360,7 +360,7 @@ /obj/effect/abstract/gas_visual/Initialize(mapload) . = ..() - color_filter = filter(type="color", color=matrix()) + color_filter = filter(type="color", color="white") filters += color_filter color_filter = filters[filters.len] if(current_color) diff --git a/code/modules/atmospherics/machinery/pipes/pipes.dm b/code/modules/atmospherics/machinery/pipes/pipes.dm index 230edc9a897f0..ebc31e847b85a 100644 --- a/code/modules/atmospherics/machinery/pipes/pipes.dm +++ b/code/modules/atmospherics/machinery/pipes/pipes.dm @@ -27,12 +27,11 @@ volume = 35 * device_type . = ..() -///I have no idea why there's a new and at this point I'm too afraid to ask -/obj/machinery/atmospherics/pipe/Initialize(mapload) - . = ..() +/obj/machinery/atmospherics/pipe/setup_hiding() + AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE) //if changing this, change the subtypes RemoveElements too, because thats how bespoke works - if(hide) - AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE) //if changing this, change the subtypes RemoveElements too, because thats how bespoke works + // Registering on `COMSIG_OBJ_HIDE` would cause order of operations issues with undertile, so we register to run when undertile updates instead + RegisterSignal(src, COMSIG_UNDERTILE_UPDATED, PROC_REF(on_hide)) /obj/machinery/atmospherics/pipe/on_deconstruction(disassembled) //we delete the parent here so it initializes air_temporary for us. See /datum/pipeline/Destroy() which calls temporarily_store_air() diff --git a/code/modules/awaymissions/mission_code/Beach.dm b/code/modules/awaymissions/mission_code/Beach.dm new file mode 100644 index 0000000000000..8e05cfe4a5eb1 --- /dev/null +++ b/code/modules/awaymissions/mission_code/Beach.dm @@ -0,0 +1,19 @@ +/area/awaymission/beach + name = "Beach" + icon_state = "away" + static_lighting = FALSE + base_lighting_alpha = 255 + base_lighting_color = "#FFFFCC" + requires_power = FALSE + has_gravity = STANDARD_GRAVITY + ambientsounds = list('sound/ambience/shore.ogg', 'sound/ambience/seag1.ogg','sound/ambience/seag2.ogg','sound/ambience/seag2.ogg','sound/ambience/ambiodd.ogg','sound/ambience/ambinice.ogg') + +/obj/item/paper/fluff/old_pirate_note + name = "rum-stained letter" + icon_state = "scrap_mud" + desc = "An unsent letter from a terminally drunk pirate." + default_raw_text = {"Dear, +
I'm sorry I won't sail back home soon, +
son of a biscuit eater walked the plank with me coffer (or treasure chest as landlubbers call'em), +
so I got me fishing rod, bottles, waiting to fish the booty back. +
Luv you hun, I hope this letter find you we-"} diff --git a/code/modules/bitrunning/orders/tech.dm b/code/modules/bitrunning/orders/tech.dm index 7e987e4818104..0b097127ffb71 100644 --- a/code/modules/bitrunning/orders/tech.dm +++ b/code/modules/bitrunning/orders/tech.dm @@ -32,7 +32,7 @@ desc = "This disk contains a program that lets you shapeshift into a lesser ashdrake, or a polar bear." /datum/orderable_item/bitrunning_tech/flip_skillchip - item_path = /obj/item/skillchip/matrix_flip + item_path = /obj/item/skillchip/matrix_taunt cost_per_order = 2000 /datum/orderable_item/bitrunning_tech/pka_mod diff --git a/code/modules/capture_the_flag/ctf_classes.dm b/code/modules/capture_the_flag/ctf_classes.dm index 0482bd1ec88eb..8f6a03ba7dfc4 100644 --- a/code/modules/capture_the_flag/ctf_classes.dm +++ b/code/modules/capture_the_flag/ctf_classes.dm @@ -55,7 +55,7 @@ var/obj/item/radio/headset = human_to_equip.ears headset.set_frequency(team_radio_freq) headset.freqlock = RADIO_FREQENCY_LOCKED - headset.independent = TRUE + headset.special_channels |= RADIO_SPECIAL_CENTCOM human_to_equip.dna.species.stunmod = 0 /datum/outfit/ctf/instagib diff --git a/code/modules/cards/cardhand.dm b/code/modules/cards/cardhand.dm index ac14e17fea61b..8fc9b4d0dc70a 100644 --- a/code/modules/cards/cardhand.dm +++ b/code/modules/cards/cardhand.dm @@ -67,7 +67,7 @@ qdel(src) // cardhand is empty now so delete it /obj/item/toy/cards/cardhand/proc/check_menu(mob/living/user) - return isliving(user) && !user.incapacitated() + return isliving(user) && !user.incapacitated /obj/item/toy/cards/cardhand/attackby(obj/item/weapon, mob/living/user, params, flip_card = FALSE) var/obj/item/toy/singlecard/card diff --git a/code/modules/cargo/markets/market_item.dm b/code/modules/cargo/markets/market_item.dm index d7a4dd4c0eef3..faa6c45d795c4 100644 --- a/code/modules/cargo/markets/market_item.dm +++ b/code/modules/cargo/markets/market_item.dm @@ -30,6 +30,9 @@ /// Probability for this item to be available. Used by SSmarket on init. var/availability_prob + /// If set, this icon will be shown in the UI. + var/html_icon + ///The identifier for the market item, generated on runtime and used to access them in the market categories. var/identifier @@ -51,9 +54,11 @@ //we're replacing the item to sell, and the old item is an instance! if(ismovable(item)) UnregisterSignal(item, COMSIG_QDELETING) + html_icon = null item = path_or_ref identifier = "[path_or_ref]" if(ismovable(path_or_ref)) + html_icon = icon2base64(getFlatIcon(item, no_anim=TRUE)) RegisterSignal(item, COMSIG_QDELETING, PROC_REF(on_item_del)) identifier = "[REF(src)]" diff --git a/code/modules/cargo/markets/market_items/local_goods.dm b/code/modules/cargo/markets/market_items/local_goods.dm new file mode 100644 index 0000000000000..d81c38fec98ba --- /dev/null +++ b/code/modules/cargo/markets/market_items/local_goods.dm @@ -0,0 +1,25 @@ +///A special category for goods placed on the market by station by someone with the LTSRBT. +/datum/market_item/local_good + category = "Local Goods" + abstract_path = /datum/market_item/local_good + stock = 1 + availability_prob = 100 + restockable = FALSE + var/datum/bank_account/seller + +/datum/market_item/local_good/New(atom/movable/thing, datum/bank_account/seller) + ..() + set_item(thing) + src.seller = seller + if(seller) + RegisterSignal(seller, COMSIG_QDELETING, PROC_REF(delete_reference)) + +/datum/market_item/local_good/buy(obj/item/market_uplink/uplink, mob/buyer, shipping_method, legal_status) + . = ..() + if(. && seller) + seller.adjust_money(round(price * (1 - MARKET_WITHHOLDING_TAX)), "Market: Item Sold") + QDEL_IN(src, 10 MINUTES) //This category cannot hold more than 40 items at a time, so we need to clear sold items. + +/datum/market_item/local_good/proc/delete_reference(datum/source) + SIGNAL_HANDLER + seller = null diff --git a/code/modules/cargo/markets/market_items/weapons.dm b/code/modules/cargo/markets/market_items/weapons.dm index 4f20cf865bc9b..12241450ba59a 100644 --- a/code/modules/cargo/markets/market_items/weapons.dm +++ b/code/modules/cargo/markets/market_items/weapons.dm @@ -24,6 +24,16 @@ stock_max = 4 availability_prob = 40 +/datum/market_item/weapon/buckshot + name = "Box of Buckshot Shells" + desc = "It wasn't easy since buckshot has been made illegal all over this sector of space, but \ + we managed to find a large cache of it... somewhere. A word of caution, the stuff may be a tad old." + stock_max = 3 + availability_prob = 35 + item = /obj/item/storage/box/lethalshot/old + price_min = CARGO_CRATE_VALUE * 3 + price_max = CARGO_CRATE_VALUE * 4.5 + /datum/market_item/weapon/bone_spear name = "Bone Spear" desc = "Authentic tribal spear, made from real bones! A steal at any price, especially if you're a caveman." diff --git a/code/modules/cargo/markets/market_telepad.dm b/code/modules/cargo/markets/market_telepad.dm index 799395f30d125..53a3d73ee486a 100644 --- a/code/modules/cargo/markets/market_telepad.dm +++ b/code/modules/cargo/markets/market_telepad.dm @@ -1,4 +1,5 @@ -#define DEFAULT_RESTOCK_COST 675 +#define DEFAULT_RESTOCK_COST CARGO_CRATE_VALUE * 3.375 +#define PLACE_ON_MARKET_COST PAYCHECK_LOWER * 1.2 /obj/item/circuitboard/machine/ltsrbt name = "LTSRBT (Machine Board)" @@ -14,13 +15,14 @@ /obj/machinery/ltsrbt name = "Long-To-Short-Range-Bluespace-Transceiver" desc = "The LTSRBT is a compact teleportation machine for receiving and sending items outside the station and inside the station.\nUsing teleportation frequencies stolen from NT it is near undetectable.\nEssential for any illegal market operations on NT stations.\n" - icon = 'icons/obj/machines/telecomms.dmi' - icon_state = "exonet_node_idle" - base_icon_state = "exonet_node" + icon = 'icons/obj/machines/ltsrbt.dmi' + icon_state = "ltsrbt_idle" + base_icon_state = "ltsrbt" circuit = /obj/item/circuitboard/machine/ltsrbt density = TRUE idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 2 + interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND /// Divider for energy_usage_per_teleport. var/power_efficiency = 1 @@ -38,6 +40,12 @@ var/datum/market_purchase/transmitting /// Queue for purchases that the machine should receive and send. var/list/datum/market_purchase/queue = list() + /// The name of the market item that we've set on the UI + var/current_name = "" + /// The desc of the market item that we've set on the UI + var/current_desc = "" + /// The price of the market item that we've set on the UI + var/current_price = CARGO_CRATE_VALUE /** * Attacking the machinery with enough credits will restock the markets, allowing for more/better items. * The cost doubles each time this is done. @@ -48,32 +56,267 @@ . = ..() register_context() SSmarket.telepads += src + ADD_TRAIT(src, TRAIT_SECLUDED_LOCATION, INNATE_TRAIT) //you cannot sell disky, boss. + update_appearance() /obj/machinery/ltsrbt/Destroy() SSmarket.telepads -= src // Bye bye orders. if(length(SSmarket.telepads)) - for(var/datum/market_purchase/P in queue) - SSmarket.queue_item(P) - . = ..() + for(var/datum/market_purchase/purchase in queue) + SSmarket.queue_item(purchase) + if(receiving) + SSmarket.queue_item(receiving) + queue = null + receiving = null + transmitting = null + return ..() /obj/machinery/ltsrbt/add_context(atom/source, list/context, obj/item/held_item, mob/user) - if(held_item && held_item.get_item_credit_value()) - context[SCREENTIP_CONTEXT_LMB] = "Restock" + if(held_item) + if(state_open) + context[SCREENTIP_CONTEXT_LMB] = "Insert" + return CONTEXTUAL_SCREENTIP_SET + if(held_item.get_item_credit_value() && !(machine_stat & NOPOWER)) + context[SCREENTIP_CONTEXT_LMB] = "Restock" + return CONTEXTUAL_SCREENTIP_SET + return NONE + if(state_open) + context[SCREENTIP_CONTEXT_LMB] = "Close" return CONTEXTUAL_SCREENTIP_SET - return NONE + context[SCREENTIP_CONTEXT_LMB] = "Open" + if(occupant && !(machine_stat & NOPOWER)) + context[SCREENTIP_CONTEXT_RMB] = "Place on market" + return CONTEXTUAL_SCREENTIP_SET /obj/machinery/ltsrbt/examine(mob/user) . = ..() - if(machine_stat & NOPOWER) - . += span_info("A display reads: \"Current market restock price: [EXAMINE_HINT("[restock_cost] cr")]\".") + if(!(machine_stat & NOPOWER)) + . += span_info("A small display reads:") + . += span_tinynoticeital("Current market restock price: [EXAMINE_HINT("[restock_cost] cr")].") + . += span_tinynoticeital("Market placement fee: [EXAMINE_HINT("[PLACE_ON_MARKET_COST] cr")].") + . += span_tinynoticeital("Withholding tax on local items: [EXAMINE_HINT("[MARKET_WITHHOLDING_TAX * 100]%")].") /obj/machinery/ltsrbt/update_icon_state() . = ..() if(machine_stat & NOPOWER) icon_state = "[base_icon_state]_off" else - icon_state = "[base_icon_state][(receiving || length(queue)) ? "" : "_idle"]" + icon_state = "[base_icon_state][(receiving || length(queue) || occupant) ? "" : "_idle"]" + +/obj/machinery/ltsrbt/update_overlays() + . = ..() + if(!state_open) + . += "[base_icon_state]_closed" + else + var/mutable_appearance/overlay = mutable_appearance(icon, "[base_icon_state]_open") + overlay.pixel_w -= 2 + overlay.pixel_z -= 1 + . += overlay + +/obj/machinery/ltsrbt/attack_hand(mob/user, list/modifiers) + . = ..() + if(.) + return + if(!state_open) + open_machine(density_to_set = TRUE) + else + close_machine() + +/obj/machinery/ltsrbt/open_machine(drop = TRUE, density_to_set = FALSE) + . = ..() + playsound(src, 'sound/machines/oven/oven_open.ogg', 75, TRUE) + +/obj/machinery/ltsrbt/close_machine(atom/movable/target, density_to_set = TRUE) + . = ..() + playsound(src, 'sound/machines/oven/oven_close.ogg', 75, TRUE) + +/obj/machinery/ltsrbt/set_occupant(obj/item/new_occupant) + . = ..() + if(new_occupant) + current_name = new_occupant.name + current_desc = new_occupant.desc + +/obj/machinery/ltsrbt/can_be_occupant(atom/movable/atom) + return isitem(atom) && !atom.anchored + +/obj/machinery/ltsrbt/Exited(atom/movable/gone) + if(gone == occupant) + current_price = initial(current_price) + current_name = "" + current_desc = "" + update_appearance(UPDATE_ICON_STATE) + return ..() + +/obj/machinery/ltsrbt/attack_hand_secondary(mob/user, list/modifiers) + . = ..() + if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) + return + if(state_open) + balloon_alert(user, "close it first!") + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + if(!occupant) + balloon_alert(user, "nothing loaded!") + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + if(machine_stat & NOPOWER) + balloon_alert(user, "machine unpowered!") + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + if(!COOLDOWN_FINISHED(src, recharge_cooldown)) + balloon_alert(user, "on cooldown!") + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + ui_interact(user) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/machinery/ltsrbt/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(user.combat_mode) + return NONE + + var/creds_value = tool.get_item_credit_value() + + if(state_open) + if(locate(/mob/living) in tool.get_all_contents()) + say("Living being detected, cannot sell!") + playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE) + return ITEM_INTERACT_BLOCKING + if(!user.transferItemToLoc(tool, src)) + balloon_alert(user, "stuck to your hands!") + return ITEM_INTERACT_BLOCKING + balloon_alert(user, "item loaded") + close_machine(tool) + return ITEM_INTERACT_SUCCESS + else if(!creds_value) + balloon_alert(user, "open the machine!") + return ITEM_INTERACT_BLOCKING + + if(machine_stat & NOPOWER) + return + + if(creds_value < restock_cost) + say("Insufficient credits!") + playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE) + return ITEM_INTERACT_BLOCKING + + if(istype(tool, /obj/item/holochip)) + var/obj/item/holochip/chip = tool + chip.spend(restock_cost) + else + qdel(tool) + if(creds_value != restock_cost) + var/obj/item/holochip/change = new(loc, creds_value - restock_cost) + user.put_in_hands(change) + + SSmarket.restock() + restock_cost *= 2 + return ITEM_INTERACT_SUCCESS + +/obj/machinery/ltsrbt/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "LTSRBT", name) + ui.open() + +/obj/machinery/ltsrbt/ui_state() + if(!occupant || !COOLDOWN_FINISHED(src, recharge_cooldown)) + return GLOB.never_state //close it. + else + return GLOB.default_state + +#define LTSRBT_MIN_PRICE PAYCHECK_LOWER +#define LTSRBT_MAX_PRICE CARGO_CRATE_VALUE * 50 + +/obj/machinery/ltsrbt/ui_static_data(mob/user) + var/list/data = list() + data["loaded_icon"] = icon2base64(getFlatIcon(occupant, no_anim=TRUE)) + data["min_price"] = LTSRBT_MIN_PRICE + data["max_price"] = LTSRBT_MAX_PRICE + return data + +/obj/machinery/ltsrbt/ui_data(mob/user) + var/list/data = list() + data["name"] = current_name + data["price"] = current_price + data["desc"] = current_desc + return data + +/obj/machinery/ltsrbt/ui_act(action, list/params) + . = ..() + if(.) + return + switch(action) + if("change_name") + var/value = params["value"] + if(!CAN_BYPASS_FILTER(usr) && is_ic_filtered_for_pdas(value)) + return TRUE + current_name = trim(value, MAX_NAME_LEN) + return TRUE + if("change_desc") + var/value = params["value"] + if(!CAN_BYPASS_FILTER(usr) && is_ic_filtered_for_pdas(value)) + return TRUE + current_desc = trim(value, MAX_DESC_LEN) + return TRUE + if("change_price") + current_price = clamp(params["value"], LTSRBT_MIN_PRICE, LTSRBT_MAX_PRICE) + return TRUE + if("place_on_market") + place_on_market(usr) + return TRUE + +#undef LTSRBT_MIN_PRICE +#undef LTSRBT_MAX_PRICE + +#define LTSRBT_MAX_MARKET_ITEMS 40 +/obj/machinery/ltsrbt/proc/place_on_market(mob/user) + if(QDELETED(occupant)) + return + if(locate(/mob/living) in occupant.get_all_contents()) + say("Living being detected, cannot sell!") + playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE) + return + var/datum/bank_account/account + var/datum/market/our_market = SSmarket.markets[/datum/market/blackmarket] + if(!isAdminGhostAI(user)) + if(!isliving(user)) + return + if(length(our_market.available_items[/datum/market_item/local_good::category]) >= LTSRBT_MAX_MARKET_ITEMS) + say("Local market saturated, buy some goods first!") + playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE) + return + var/mob/living/living_user = user + var/obj/item/card/id/card = living_user.get_idcard(TRUE) + if(!(card?.registered_account)) + say("No bank account to charge market fees detected!") + playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE) + return + if(!card.registered_account.adjust_money(-PLACE_ON_MARKET_COST, "Market: Placement Fee")) + say("Insufficient credits!") + playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE) + return + account = card.registered_account + + var/obj/item/item = occupant //occupant, name, price and desc will be null'd once it exits the machine so we need this. + var/name_to_use = current_name || item.name + var/desc_to_use = current_desc + if(account) + desc_to_use += "[current_desc ? " - " : ""]Seller: [account.account_holder]" + var/price_to_use = current_price + item.moveToNullspace() + //Something happened and the item was deleted or relocated as soon as it was moved to nullspace. + if(QDELETED(item) || item.loc != null) + say("Runtime at market_placement.dm, line 153: item gone!") //metajoke + return + var/datum/market_item/local_good/new_item = new(item, account) + new_item.name = name_to_use + new_item.desc = desc_to_use + new_item.price = price_to_use + + our_market.add_item(new_item) + + say("Item placed on the market!") + playsound(src, 'sound/effects/cashregister.ogg', 40, FALSE) + COOLDOWN_START(src, recharge_cooldown, recharge_time * 3) + +#undef LTSRBT_MAX_MARKET_ITEMS /obj/machinery/ltsrbt/RefreshParts() . = ..() @@ -81,7 +324,6 @@ // On tier 4 recharge_time should be 20 and by default it is 80 as scanning modules should be tier 1. for(var/datum/stock_part/scanning_module/scanning_module in component_parts) recharge_time -= scanning_module.tier * 1 SECONDS - recharge_cooldown = recharge_time power_efficiency = 0 for(var/datum/stock_part/micro_laser/laser in component_parts) @@ -132,43 +374,17 @@ transmitting = receiving receiving = null - COOLDOWN_START(src, recharge_cooldown, recharge_time) return if(transmitting) if(transmitting.item.loc == turf) do_teleport(transmitting.item, get_turf(transmitting.uplink)) use_energy(energy_usage_per_teleport / power_efficiency) QDEL_NULL(transmitting) + COOLDOWN_START(src, recharge_cooldown, recharge_time) return if(length(queue)) receiving = pick_n_take(queue) -/obj/machinery/ltsrbt/item_interaction(mob/living/user, obj/item/tool, list/modifiers) - var/creds_value = tool.get_item_credit_value() - if(!creds_value) - return NONE - - . = ITEM_INTERACT_SUCCESS - - if(machine_stat & NOPOWER) - return - - if(creds_value < restock_cost) - say("Insufficient credits!") - playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE) - return - - if(istype(tool, /obj/item/holochip)) - var/obj/item/holochip/chip = tool - chip.spend(restock_cost) - else - qdel(tool) - if(creds_value != restock_cost) - var/obj/item/holochip/change = new(creds_value - restock_cost) - user.put_in_hands(change) - - SSmarket.restock() - restock_cost *= 2 - #undef DEFAULT_RESTOCK_COST +#undef PLACE_ON_MARKET_COST diff --git a/code/modules/cargo/markets/market_uplink.dm b/code/modules/cargo/markets/market_uplink.dm index a324a2f0409be..147e37e3f9d87 100644 --- a/code/modules/cargo/markets/market_uplink.dm +++ b/code/modules/cargo/markets/market_uplink.dm @@ -80,7 +80,8 @@ "name" = item.name, "cost" = item.price, "amount" = item.stock, - "desc" = item.desc || item.name + "desc" = item.desc || item.name, + "html_icon" = item.html_icon, )) return data diff --git a/code/modules/cargo/packs/costumes_toys.dm b/code/modules/cargo/packs/costumes_toys.dm index de84a263597da..a25c47c5d9f88 100644 --- a/code/modules/cargo/packs/costumes_toys.dm +++ b/code/modules/cargo/packs/costumes_toys.dm @@ -90,7 +90,7 @@ /datum/supply_pack/costumes_toys/knucklebones name = "Knucklebones Game Crate" desc = "A fun dice game definitely not invented by a cult. Consult your local chaplain regarding \ - approved religious activity. Contains eighteen d6, one white crayon, and instructions on how to play." + approved religious activity. Contains eighteen d6, one stick of chalk, and instructions on how to play." cost = CARGO_CRATE_VALUE * 2 contains = list(/obj/item/dice/d6 = 18, /obj/item/paper/guides/knucklebone, diff --git a/code/modules/cargo/packs/engineering.dm b/code/modules/cargo/packs/engineering.dm index 771cba47df61d..e8255a58e6431 100644 --- a/code/modules/cargo/packs/engineering.dm +++ b/code/modules/cargo/packs/engineering.dm @@ -76,7 +76,7 @@ cost = CARGO_CRATE_VALUE * 4 contains = list(/obj/item/inducer/orderable = 2) crate_name = "inducer crate" - crate_type = /obj/structure/closet/crate/engineering/electrical + crate_type = /obj/structure/closet/crate/nakamura /datum/supply_pack/engineering/pacman name = "P.A.C.M.A.N Generator Crate" @@ -86,7 +86,7 @@ access_view = ACCESS_ENGINEERING contains = list(/obj/machinery/power/port_gen/pacman) crate_name = "\improper PACMAN generator crate" - crate_type = /obj/structure/closet/crate/engineering/electrical + crate_type = /obj/structure/closet/crate/nakamura /datum/supply_pack/engineering/power name = "Power Cell Crate" @@ -328,3 +328,12 @@ ) crate_name = "radioactive nebula shielding (IMPORTANT)" crate_type = /obj/structure/closet/crate/engineering + +/datum/supply_pack/engineering/portagrav + name = "Portable Gravity Unit Crate" + desc = "Contains a portable gravity unit, to make the clown float into the ceiling." + cost = CARGO_CRATE_VALUE * 4 + access_view = ACCESS_ENGINEERING + contains = list(/obj/machinery/power/portagrav = 1) + crate_name = "portable gravity unit crate" + crate_type = /obj/structure/closet/crate/engineering diff --git a/code/modules/cargo/packs/imports.dm b/code/modules/cargo/packs/imports.dm index 98fc4d650212c..fc35e473f5ada 100644 --- a/code/modules/cargo/packs/imports.dm +++ b/code/modules/cargo/packs/imports.dm @@ -17,6 +17,7 @@ cost = CARGO_CRATE_VALUE * 2 contains = list(/obj/item/gun/ballistic/shotgun/toy = 8) crate_name = "foam force crate" + crate_type = /obj/structure/closet/crate/freezer/donk discountable = SUPPLY_PACK_STD_DISCOUNTABLE /datum/supply_pack/imports/foamforce/bonus @@ -30,6 +31,7 @@ /obj/item/ammo_box/magazine/toy/pistol = 2, ) crate_name = "foam force crate" + crate_type = /obj/structure/closet/crate/freezer/donk /datum/supply_pack/imports/meatmeatmeatmeat // MEAT MEAT MEAT MEAT name = "MEAT MEAT MEAT MEAT MEAT" @@ -141,6 +143,7 @@ /obj/item/gun/ballistic/automatic/wt550 = 2, /obj/item/ammo_box/magazine/wt550m9 = 2, ) + crate_type = /obj/structure/closet/crate/secure/gorlex_weapons/jammed /datum/supply_pack/imports/wt550ammo name = "Smuggled WT-550 Ammo Crate" @@ -153,7 +156,7 @@ /obj/item/ammo_box/magazine/wt550m9/wtic = 2, ) crate_name = "emergency crate" - crate_type = /obj/structure/closet/crate/internals + crate_type = /obj/structure/closet/crate/secure/gorlex_weapons/jammed /datum/supply_pack/imports/shocktrooper name = "Shocktrooper Crate" @@ -169,6 +172,7 @@ /obj/item/clothing/suit/armor/vest, /obj/item/clothing/head/helmet, ) + crate_type = /obj/structure/closet/crate/secure/gorlex_weapons/jammed /datum/supply_pack/imports/specialops name = "Special Ops Crate" @@ -184,6 +188,7 @@ /obj/item/switchblade, /obj/item/grenade/mirage = 5, ) + crate_type = /obj/structure/closet/crate/secure/gorlex_weapons/jammed /datum/supply_pack/imports/russian name = "Russian Surplus Military Gear Crate" diff --git a/code/modules/cargo/packs/medical.dm b/code/modules/cargo/packs/medical.dm index 0c626223916af..560fb717f3491 100644 --- a/code/modules/cargo/packs/medical.dm +++ b/code/modules/cargo/packs/medical.dm @@ -29,7 +29,7 @@ /obj/item/reagent_containers/hypospray/medipen/ekit = 3, /obj/item/reagent_containers/hypospray/medipen/blood_loss = 3) crate_name = "medipen crate" - crate_type = /obj/structure/closet/crate/medical + crate_type = /obj/structure/closet/crate/deforest /datum/supply_pack/medical/coroner_crate name = "Autopsy Kit" @@ -138,6 +138,7 @@ /obj/item/emergency_bed, ) crate_name = "surgical supplies crate" + crate_type = /obj/structure/closet/crate/deforest /datum/supply_pack/medical/salglucanister name = "Heavy-Duty Saline Canister" diff --git a/code/modules/cargo/packs/science.dm b/code/modules/cargo/packs/science.dm index dfa2a66359336..6b4f38b95a03a 100644 --- a/code/modules/cargo/packs/science.dm +++ b/code/modules/cargo/packs/science.dm @@ -189,4 +189,4 @@ access_view = ACCESS_ROBOTICS contains = list(/obj/item/mod/core/standard = 3) crate_name = "\improper MOD core crate" - crate_type = /obj/structure/closet/crate/secure/science/robo + crate_type = /obj/structure/closet/crate/nakamura diff --git a/code/modules/cargo/packs/security.dm b/code/modules/cargo/packs/security.dm index 05360fe913f0a..8a0765602b342 100644 --- a/code/modules/cargo/packs/security.dm +++ b/code/modules/cargo/packs/security.dm @@ -36,7 +36,7 @@ /datum/supply_pack/security/forensics name = "Forensics Crate" desc = "Stay hot on the criminal's heels with Nanotrasen's Detective Essentials™. \ - Contains a forensics scanner, six evidence bags, camera, tape recorder, white crayon, \ + Contains a forensics scanner, six evidence bags, camera, tape recorder, stick of chalk, \ and of course, a fedora." cost = CARGO_CRATE_VALUE * 2.5 access_view = ACCESS_MORGUE diff --git a/code/modules/cargo/packs/service.dm b/code/modules/cargo/packs/service.dm index bf6afe107d6c7..26af45f960a5e 100644 --- a/code/modules/cargo/packs/service.dm +++ b/code/modules/cargo/packs/service.dm @@ -245,7 +245,7 @@ /obj/item/food/ready_donk/donkhiladas, ) crate_name = "\improper Ready-Donk crate" - crate_type = /obj/structure/closet/crate/freezer/food + crate_type = /obj/structure/closet/crate/freezer/donk discountable = SUPPLY_PACK_UNCOMMON_DISCOUNTABLE /datum/supply_pack/service/randomized/ready_donk/fill(obj/structure/closet/crate/C) @@ -269,6 +269,7 @@ /obj/item/reagent_containers/cup/bottle/syrup_bottle/caramel, //one extra syrup as a treat ) crate_name = "coffee equipment crate" + crate_type = /obj/structure/closet/crate/robust discountable = SUPPLY_PACK_UNCOMMON_DISCOUNTABLE /datum/supply_pack/service/coffeemaker diff --git a/code/modules/cargo/packs/vending_restock.dm b/code/modules/cargo/packs/vending_restock.dm index 10ae874d5d6c9..201cce8b1e69e 100644 --- a/code/modules/cargo/packs/vending_restock.dm +++ b/code/modules/cargo/packs/vending_restock.dm @@ -17,7 +17,7 @@ cost = CARGO_CRATE_VALUE * 2 contains = list(/obj/item/vending_refill/cigarette) crate_name = "cigarette supply crate" - crate_type = /obj/structure/closet/crate + crate_type = /obj/structure/closet/crate/robust /datum/supply_pack/vending/dinnerware name = "Dinnerware Supply Crate" @@ -106,6 +106,7 @@ cost = CARGO_CRATE_VALUE * 2 contains = list(/obj/item/vending_refill/snack) crate_name = "snacks supply crate" + crate_type = /obj/structure/closet/crate/robust /datum/supply_pack/vending/cola name = "Softdrinks Supply Crate" diff --git a/code/modules/cargo/universal_scanner.dm b/code/modules/cargo/universal_scanner.dm index 484f4a7a03201..9ce1771421e61 100644 --- a/code/modules/cargo/universal_scanner.dm +++ b/code/modules/cargo/universal_scanner.dm @@ -257,7 +257,7 @@ /obj/item/universal_scanner/proc/check_menu(mob/living/user) if(!istype(user)) return FALSE - if(user.incapacitated()) + if(user.incapacitated) return FALSE return TRUE diff --git a/code/modules/client/preferences/paraplegic.dm b/code/modules/client/preferences/paraplegic.dm new file mode 100644 index 0000000000000..1ffa704c77d0b --- /dev/null +++ b/code/modules/client/preferences/paraplegic.dm @@ -0,0 +1,20 @@ +/datum/preference/choiced/paraplegic + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "paraplegic" + savefile_identifier = PREFERENCE_CHARACTER + +/datum/preference/choiced/paraplegic/init_possible_values() + return GLOB.paraplegic_choice + +/datum/preference/choiced/paraplegic/create_default_value() + return "Default" + +/datum/preference/choiced/paraplegic/is_accessible(datum/preferences/preferences) + . = ..() + if (!.) + return FALSE + + return "Paraplegic" in preferences.all_quirks + +/datum/preference/choiced/paraplegic/apply_to_human(mob/living/carbon/human/target, value) + return diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 1998b7abc4db3..d4705aee14c43 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -528,7 +528,7 @@ BLIND // can't see anything update_appearance() //most of the time the sprite changes /obj/item/clothing/proc/can_use(mob/user) - return istype(user) && !user.incapacitated() + return istype(user) && !user.incapacitated /obj/item/clothing/proc/spawn_shreds() new /obj/effect/decal/cleanable/shreds(get_turf(src), name) diff --git a/code/modules/clothing/gloves/_gloves.dm b/code/modules/clothing/gloves/_gloves.dm index 5f63e0c3464bf..418f8358f4d2a 100644 --- a/code/modules/clothing/gloves/_gloves.dm +++ b/code/modules/clothing/gloves/_gloves.dm @@ -12,6 +12,9 @@ siemens_coefficient = 0.5 body_parts_covered = HANDS slot_flags = ITEM_SLOT_GLOVES + equip_sound = 'sound/items/equip/glove_equip.ogg' + drop_sound = 'sound/items/handling/glove_drop.ogg' + pickup_sound = 'sound/items/handling/glove_pick_up.ogg' attack_verb_continuous = list("challenges") attack_verb_simple = list("challenge") strip_delay = 20 diff --git a/code/modules/clothing/gloves/punch_mitts.dm b/code/modules/clothing/gloves/punch_mitts.dm new file mode 100644 index 0000000000000..07d93d5ab021c --- /dev/null +++ b/code/modules/clothing/gloves/punch_mitts.dm @@ -0,0 +1,24 @@ +/obj/item/clothing/gloves/fingerless/punch_mitts + name = "punching mitts" + desc = "Fingerless gloves with nasty spikes attached. Allows the wearer to utilize the ill-reputed fighting technique known as Hunter Boxing. The style \ + allows the user to punch wildlife rapidly to death. Supposedly, this is an incredible workout, but few people are insane enough to attempt to \ + punch every dangerous creature they encounter in the wild to death with their bare hands. Also kinda works against humanoids as well. \ + Not that you would... right?" + icon_state = "punch_mitts" + body_parts_covered = HANDS|ARMS + resistance_flags = LAVA_PROOF | FIRE_PROOF + armor_type = /datum/armor/gloves_mitts + +/obj/item/clothing/gloves/fingerless/punch_mitts/Initialize(mapload) + . = ..() + + AddComponent(/datum/component/martial_art_giver, /datum/martial_art/boxing/hunter) + +/datum/armor/gloves_mitts + melee = 25 + bullet = 5 + laser = 5 + energy = 5 + bomb = 100 + fire = 100 + acid = 30 diff --git a/code/modules/clothing/head/costume.dm b/code/modules/clothing/head/costume.dm index 13a6e549b0e91..ed3d42228aa3a 100644 --- a/code/modules/clothing/head/costume.dm +++ b/code/modules/clothing/head/costume.dm @@ -115,14 +115,10 @@ /obj/item/clothing/head/costume/cardborg/equipped(mob/living/user, slot) ..() if(ishuman(user) && (slot & ITEM_SLOT_HEAD)) - var/mob/living/carbon/human/H = user - if(istype(H.wear_suit, /obj/item/clothing/suit/costume/cardborg)) - var/obj/item/clothing/suit/costume/cardborg/CB = H.wear_suit - CB.disguise(user, src) - -/obj/item/clothing/head/costume/cardborg/dropped(mob/living/user) - ..() - user.remove_alt_appearance("standard_borg_disguise") + var/mob/living/carbon/human/human_user = user + if(istype(human_user.wear_suit, /obj/item/clothing/suit/costume/cardborg)) + var/obj/item/clothing/suit/costume/cardborg/suit = human_user.wear_suit + suit.disguise(user, src) /obj/item/clothing/head/costume/bronze name = "bronze hat" diff --git a/code/modules/clothing/head/fedora.dm b/code/modules/clothing/head/fedora.dm index e4e8d4b54368d..cf0d23ac37f58 100644 --- a/code/modules/clothing/head/fedora.dm +++ b/code/modules/clothing/head/fedora.dm @@ -35,3 +35,9 @@ name = "carpskin fedora" icon_state = "fedora_carpskin" inhand_icon_state = null + +/obj/item/clothing/head/fedora/beige/press + name = "press fedora" + desc = "An beige fedora with a piece of paper saying \"PRESS\" stuck in its rim." + icon_state = "fedora_press" + inhand_icon_state = null diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index 76c230ca504d2..2874a27b72b98 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -75,6 +75,16 @@ update_appearance() return CLICK_ACTION_SUCCESS +/obj/item/clothing/head/helmet/press + name = "press helmet" + desc = "A blue helmet used to distinguish non-combatant \"PRESS\" members, like if anyone cares." + icon_state = "helmet_press" + +/obj/item/clothing/head/helmet/press/worn_overlays(mutable_appearance/standing, isinhands, icon_file) + . = ..() + if(!isinhands) + . += emissive_appearance(icon_file, "[icon_state]-emissive", src, alpha = src.alpha) + /obj/item/clothing/head/helmet/alt name = "bulletproof helmet" desc = "A bulletproof combat helmet that excels in protecting the wearer against traditional projectile weaponry and explosives to a minor extent." @@ -101,6 +111,7 @@ name = "tactical combat helmet" desc = "A tactical black helmet, sealed from outside hazards with a plate of glass and not much else." icon_state = "marine_command" + base_icon_state = "marine_command" inhand_icon_state = "marine_helmet" armor_type = /datum/armor/helmet_marine min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT @@ -126,14 +137,17 @@ /obj/item/clothing/head/helmet/marine/security name = "marine heavy helmet" icon_state = "marine_security" + base_icon_state = "marine_security" /obj/item/clothing/head/helmet/marine/engineer name = "marine utility helmet" icon_state = "marine_engineer" + base_icon_state = "marine_engineer" /obj/item/clothing/head/helmet/marine/medic name = "marine medic helmet" icon_state = "marine_medic" + base_icon_state = "marine_medic" /obj/item/clothing/head/helmet/marine/pmc icon_state = "marine" diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm index a5041de7fa0a9..5d5fc87d409f4 100644 --- a/code/modules/clothing/head/jobs.dm +++ b/code/modules/clothing/head/jobs.dm @@ -54,7 +54,7 @@ /obj/item/clothing/head/utility/chefhat/proc/on_mouse_emote(mob/living/source, key, emote_message, type_override) SIGNAL_HANDLER var/mob/living/carbon/wearer = loc - if(!wearer || wearer.incapacitated(IGNORE_RESTRAINTS)) + if(!wearer || INCAPACITATED_IGNORING(wearer, INCAPABLE_RESTRAINTS)) return if (!prob(mouse_control_probability)) return COMPONENT_CANT_EMOTE @@ -68,7 +68,7 @@ return COMPONENT_MOVABLE_BLOCK_PRE_MOVE // Didn't roll well enough or on cooldown var/mob/living/carbon/wearer = loc - if(!wearer || wearer.incapacitated(IGNORE_RESTRAINTS)) + if(!wearer || INCAPACITATED_IGNORING(wearer, INCAPABLE_RESTRAINTS)) return COMPONENT_MOVABLE_BLOCK_PRE_MOVE // Not worn or can't move var/move_direction = get_dir(wearer, moved_to) diff --git a/code/modules/clothing/head/soft_caps.dm b/code/modules/clothing/head/soft_caps.dm index cb0f9033960c3..1b9f2d5d301ab 100644 --- a/code/modules/clothing/head/soft_caps.dm +++ b/code/modules/clothing/head/soft_caps.dm @@ -33,7 +33,7 @@ /obj/item/clothing/head/soft/proc/flip(mob/user) - if(!user.incapacitated()) + if(!user.incapacitated) flipped = !flipped if(flipped) icon_state = "[soft_type][soft_suffix]_flipped" diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm index cab7a6557e3c4..c5871d23c1859 100644 --- a/code/modules/clothing/masks/gasmask.dm +++ b/code/modules/clothing/masks/gasmask.dm @@ -301,14 +301,14 @@ GLOBAL_LIST_INIT(clown_mask_options, list( AddElement(/datum/element/swabable, CELL_LINE_TABLE_CLOWN, CELL_VIRUS_TABLE_GENERIC, rand(2,3), 0) /obj/item/clothing/mask/gas/clown_hat/ui_action_click(mob/user) - if(!istype(user) || user.incapacitated()) + if(!istype(user) || user.incapacitated) return var/choice = show_radial_menu(user,src, clownmask_designs, custom_check = FALSE, radius = 36, require_near = TRUE) if(!choice) return FALSE - if(src && choice && !user.incapacitated() && in_range(user,src)) + if(src && choice && !user.incapacitated && in_range(user,src)) var/list/options = GLOB.clown_mask_options icon_state = options[choice] user.update_worn_mask() @@ -355,7 +355,7 @@ GLOBAL_LIST_INIT(clown_mask_options, list( ) /obj/item/clothing/mask/gas/mime/ui_action_click(mob/user) - if(!istype(user) || user.incapacitated()) + if(!istype(user) || user.incapacitated) return var/list/options = list() @@ -368,7 +368,7 @@ GLOBAL_LIST_INIT(clown_mask_options, list( if(!choice) return FALSE - if(src && choice && !user.incapacitated() && in_range(user,src)) + if(src && choice && !user.incapacitated && in_range(user,src)) icon_state = options[choice] user.update_worn_mask() update_item_action_buttons() diff --git a/code/modules/clothing/outfits/ert.dm b/code/modules/clothing/outfits/ert.dm index 2aa61b0046070..0cfa011433d74 100644 --- a/code/modules/clothing/outfits/ert.dm +++ b/code/modules/clothing/outfits/ert.dm @@ -104,6 +104,8 @@ l_pocket = /obj/item/healthanalyzer/advanced additional_radio = /obj/item/encryptionkey/heads/cmo + skillchips = list(/obj/item/skillchip/entrails_reader) + /datum/outfit/centcom/ert/medic/alert name = "ERT Medic - High Alert" @@ -133,6 +135,8 @@ l_pocket = /obj/item/rcd_ammo/large additional_radio = /obj/item/encryptionkey/heads/ce + skillchips = list(/obj/item/skillchip/job/engineer) + /datum/outfit/centcom/ert/engineer/alert name = "ERT Engineer - High Alert" @@ -502,6 +506,8 @@ head = /obj/item/clothing/head/helmet/marine/security additional_radio = /obj/item/encryptionkey/heads/hos + skillchips = null + /datum/outfit/centcom/ert/marine/medic name = "Marine Medic" @@ -520,6 +526,8 @@ glasses = /obj/item/clothing/glasses/hud/health/sunglasses additional_radio = /obj/item/encryptionkey/heads/cmo + skillchips = list(/obj/item/skillchip/entrails_reader) + /datum/outfit/centcom/ert/marine/engineer name = "Marine Engineer" @@ -533,6 +541,8 @@ glasses = /obj/item/clothing/glasses/hud/diagnostic/sunglasses additional_radio = /obj/item/encryptionkey/heads/ce + skillchips = list(/obj/item/skillchip/job/engineer) + /datum/outfit/centcom/militia name = "Militia Man" @@ -563,3 +573,72 @@ head = /obj/item/clothing/head/beret/militia l_hand = /obj/item/megaphone suit_store = /obj/item/gun/energy/laser/musket/prime + +/datum/outfit/centcom/ert/medical_commander + name = "Chief EMT" + id = /obj/item/card/id/advanced/centcom/ert/medical + uniform = /obj/item/clothing/under/rank/medical/chief_medical_officer + l_pocket = /obj/item/healthanalyzer/advanced + shoes = /obj/item/clothing/shoes/sneakers/white + backpack_contents = list( + /obj/item/reagent_containers/hypospray/combat = 1, + /obj/item/storage/medkit/regular = 1, + /obj/item/storage/medkit/advanced = 1, + /obj/item/melee/baton/telescopic = 1, + /obj/item/gun/energy/pulse/pistol/loyalpin = 1, + /obj/item/stack/medical/poultice = 1, //These stacks contain 15 by default. Great for getting corpses to defib range without surgery. + ) + belt = /obj/item/storage/belt/medical/ert + glasses = /obj/item/clothing/glasses/hud/health/sunglasses + additional_radio = /obj/item/encryptionkey/heads/cmo + mask = /obj/item/clothing/mask/surgical + back = /obj/item/mod/control/pre_equipped/emergency_medical/corpsman + gloves = null + suit = null + head = null + suit_store = /obj/item/tank/internals/oxygen + +/datum/outfit/centcom/ert/medical_technician + name = "EMT Paramedic" + id = /obj/item/card/id/advanced/centcom/ert/medical + uniform = /obj/item/clothing/under/rank/medical/scrubs/blue + l_pocket = /obj/item/healthanalyzer + backpack_contents = list( + /obj/item/reagent_containers/hypospray/combat = 1, + /obj/item/storage/medkit/regular = 1, + /obj/item/reagent_containers/syringe = 1, + /obj/item/reagent_containers/cup/bottle/formaldehyde = 1, + /obj/item/reagent_containers/medigel/sterilizine = 1, + /obj/item/bodybag = 2, + ) + mask = /obj/item/clothing/mask/surgical + belt = /obj/item/storage/belt/medical/ert + glasses = /obj/item/clothing/glasses/hud/health + additional_radio = /obj/item/encryptionkey/heads/cmo + shoes = /obj/item/clothing/shoes/sneakers/blue + back = /obj/item/mod/control/pre_equipped/emergency_medical + gloves = null + suit = null + head = null + suit_store = /obj/item/tank/internals/oxygen + +/obj/item/mod/control/pre_equipped/emergency_medical + theme = /datum/mod_theme/medical + starting_frequency = MODLINK_FREQ_CENTCOM + applied_cell = /obj/item/stock_parts/power_store/cell/hyper + applied_modules = list( + /obj/item/mod/module/organizer, + /obj/item/mod/module/defibrillator, + /obj/item/mod/module/flashlight, + /obj/item/mod/module/health_analyzer, + /obj/item/mod/module/injector, + /obj/item/mod/module/surgical_processor/emergency, + /obj/item/mod/module/storage/large_capacity, + ) + +/obj/item/mod/control/pre_equipped/emergency_medical/corpsman + theme = /datum/mod_theme/medical/corpsman + +///Identical to medical MODsuit, but uses the alternate skin by default. +/datum/mod_theme/medical/corpsman + default_skin = "corpsman" diff --git a/code/modules/clothing/outfits/plasmaman.dm b/code/modules/clothing/outfits/plasmaman.dm index 1b2e0ead14883..a0e927c631938 100644 --- a/code/modules/clothing/outfits/plasmaman.dm +++ b/code/modules/clothing/outfits/plasmaman.dm @@ -302,3 +302,15 @@ uniform = /obj/item/clothing/under/plasmaman //same gloves = /obj/item/clothing/gloves/color/plasmaman/black head = /obj/item/clothing/head/helmet/space/plasmaman + +/datum/outfit/plasmaman/medical_commander + name = "Chief EMT Plasmaman" + uniform = /obj/item/clothing/under/plasmaman/chief_medical_officer + gloves = /obj/item/clothing/gloves/color/plasmaman/white + head = /obj/item/clothing/head/helmet/space/plasmaman/chief_medical_officer + +/datum/outfit/plasmaman/medical_technician + name = "EMT Paramedic Plasmaman" + uniform = /obj/item/clothing/under/plasmaman/medical + gloves = /obj/item/clothing/gloves/color/plasmaman/white + head = /obj/item/clothing/head/helmet/space/plasmaman/medical diff --git a/code/modules/clothing/shoes/jumpboots.dm b/code/modules/clothing/shoes/jumpboots.dm index 3446c2e7c7873..dc9dadcea5a53 100644 --- a/code/modules/clothing/shoes/jumpboots.dm +++ b/code/modules/clothing/shoes/jumpboots.dm @@ -36,6 +36,7 @@ user.visible_message(span_warning("[usr] dashes forward into the air!")) recharging_time = world.time + recharging_rate else + REMOVE_TRAIT(user, TRAIT_MOVE_FLOATING, LEAPING_TRAIT) to_chat(user, span_warning("Something prevents you from dashing forward!")) /obj/item/clothing/shoes/bhop/rocket diff --git a/code/modules/clothing/spacesuits/specialops.dm b/code/modules/clothing/spacesuits/specialops.dm index cf8fc2a475cc6..caaa32cc24be2 100644 --- a/code/modules/clothing/spacesuits/specialops.dm +++ b/code/modules/clothing/spacesuits/specialops.dm @@ -7,6 +7,7 @@ inhand_icon_state = null greyscale_colors = "#397F3F#FFCE5B" clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SNUG_FIT + slowdown = 0 flags_inv = 0 armor_type = /datum/armor/space_beret strip_delay = 130 diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 3c7fa506b208d..6e56107173c46 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -59,6 +59,16 @@ /obj/item/clothing/suit/armor/vest/alt/sec icon_state = "armor_sec" +/obj/item/clothing/suit/armor/vest/press + name = "press armor vest" + desc = "A blue armor vest used to distinguish non-combatant \"PRESS\" members, like if anyone cares." + icon_state = "armor_press" + +/obj/item/clothing/suit/armor/vest/press/worn_overlays(mutable_appearance/standing, isinhands, icon_file) + . = ..() + if(!isinhands) + . += emissive_appearance(icon_file, "[icon_state]-emissive", src, alpha = src.alpha) + /obj/item/clothing/suit/armor/vest/marine name = "tactical armor vest" desc = "A set of the finest mass produced, stamped plasteel armor plates, containing an environmental protection unit for all-condition door kicking." diff --git a/code/modules/clothing/suits/costume.dm b/code/modules/clothing/suits/costume.dm index 929e8d931d5ca..22ba6010ae567 100644 --- a/code/modules/clothing/suits/costume.dm +++ b/code/modules/clothing/suits/costume.dm @@ -168,6 +168,7 @@ body_parts_covered = CHEST|GROIN|LEGS flags_inv = HIDEJUMPSUIT dog_fashion = /datum/dog_fashion/back + var/in_use = FALSE /obj/item/clothing/suit/costume/cardborg/equipped(mob/living/user, slot) ..() @@ -176,17 +177,33 @@ /obj/item/clothing/suit/costume/cardborg/dropped(mob/living/user) ..() + if (!in_use) + return user.remove_alt_appearance("standard_borg_disguise") - -/obj/item/clothing/suit/costume/cardborg/proc/disguise(mob/living/carbon/human/H, obj/item/clothing/head/costume/cardborg/borghead) - if(istype(H)) - if(!borghead) - borghead = H.head - if(istype(borghead, /obj/item/clothing/head/costume/cardborg)) //why is this done this way? because equipped() is called BEFORE THE ITEM IS IN THE SLOT WHYYYY - var/image/I = image(icon = 'icons/mob/silicon/robots.dmi' , icon_state = "robot", loc = H) - I.override = 1 - I.add_overlay(mutable_appearance('icons/mob/silicon/robots.dmi', "robot_e")) //gotta look realistic - add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/silicons, "standard_borg_disguise", I) //you look like a robot to robots! (including yourself because you're totally a robot) + in_use = FALSE + var/mob/living/carbon/human/human_user = user + if (istype(human_user.head, /obj/item/clothing/head/costume/cardborg)) + UnregisterSignal(human_user.head, COMSIG_ITEM_DROPPED) + +/obj/item/clothing/suit/costume/cardborg/proc/disguise(mob/living/carbon/human/human_user, obj/item/clothing/head/costume/cardborg/borghead) + if(!istype(human_user)) + return + if(!borghead) + borghead = human_user.head + if(!istype(borghead, /obj/item/clothing/head/costume/cardborg)) //why is this done this way? because equipped() is called BEFORE THE ITEM IS IN THE SLOT WHYYYY + return + RegisterSignal(borghead, COMSIG_ITEM_DROPPED, PROC_REF(helmet_drop)) // Don't need to worry about qdeleting since dropped will be called from there + in_use = TRUE + var/image/override_image = image(icon = 'icons/mob/silicon/robots.dmi' , icon_state = "robot", loc = human_user) + override_image.override = TRUE + override_image.add_overlay(mutable_appearance('icons/mob/silicon/robots.dmi', "robot_e")) //gotta look realistic + add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/silicons, "standard_borg_disguise", override_image) //you look like a robot to robots! (including yourself because you're totally a robot) + +/obj/item/clothing/suit/costume/cardborg/proc/helmet_drop(datum/source, mob/living/user) + SIGNAL_HANDLER + UnregisterSignal(source, COMSIG_ITEM_DROPPED) + user.remove_alt_appearance("standard_borg_disguise") + in_use = FALSE /obj/item/clothing/suit/costume/snowman name = "snowman outfit" diff --git a/code/modules/clothing/suits/jobs.dm b/code/modules/clothing/suits/jobs.dm index d211b3cc91edf..7e6bdde01cdfd 100644 --- a/code/modules/clothing/suits/jobs.dm +++ b/code/modules/clothing/suits/jobs.dm @@ -191,6 +191,11 @@ if(!isinhands) . += emissive_appearance(icon_file, "[icon_state]-emissive", src, alpha = src.alpha) +/obj/item/clothing/suit/hazardvest/press // Variant used by the Curator + name = "press hazard vest" + desc = "A blue high-visibility vest used to distinguish non-combatant \"PRESS\" members, like if anyone cares." + icon_state = "hazard_press" + //Lawyer /obj/item/clothing/suit/toggle/lawyer name = "blue formal suit jacket" @@ -225,6 +230,10 @@ blood_overlay_type = "coat" body_parts_covered = CHEST|ARMS allowed = list( + /obj/item/tank/internals/emergency_oxygen, + /obj/item/tank/internals/plasmaman, + /obj/item/boxcutter, + /obj/item/dest_tagger, /obj/item/stamp, /obj/item/storage/bag/mail, /obj/item/universal_scanner, diff --git a/code/modules/clothing/under/accessories/badges.dm b/code/modules/clothing/under/accessories/badges.dm index 0ea3922893a76..cc66e9d406a57 100644 --- a/code/modules/clothing/under/accessories/badges.dm +++ b/code/modules/clothing/under/accessories/badges.dm @@ -241,3 +241,46 @@ if (ishuman(user)) var/mob/living/carbon/human/human_wearer = user human_wearer.sec_hud_set_security_status() + +/obj/item/clothing/accessory/press_badge + name = "press badge" + desc = "A blue press badge that clearly identifies the wearer as a member of the media. While it signifies press affiliation, it does not grant any special privileges or rights no matter how much the wearer yells about it." + desc_controls = "Click person with it to show them it" + icon_state = "press_badge" + attachment_slot = NONE // actually NECK but that doesn't make sense + /// The name of the person in the badge + var/journalist_name + /// The name of the press person is working for + var/press_name + +/obj/item/clothing/accessory/press_badge/examine(mob/user) + . = ..() + if(!journalist_name || !press_name) + . += span_notice("Use it in hand to input information") + return + + . += span_notice("It belongs to [journalist_name], [press_name]") + +/obj/item/clothing/accessory/press_badge/attack_self(mob/user, modifiers) + . = ..() + if(!journalist_name) + journalist_name = tgui_input_text(user, "What is your name?", "Journalist Name", "[user.name]", MAX_NAME_LEN) + if(!press_name) + press_name = tgui_input_text(user, "For what organization you work?", "Press Name", "Nanotrasen", MAX_CHARTER_LEN) + +/obj/item/clothing/accessory/press_badge/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + . = ..() + if(!isliving(interacting_with)) + return + + var/mob/living/interacting_living = interacting_with + if(user.combat_mode) + playsound(interacting_living, 'sound/weapons/throw.ogg', 30) + examine(interacting_living) + to_chat(interacting_living, span_userdanger("[user] shoves the [src] up your face!")) + user.visible_message(span_warning("[user] have shoved a [src] into [interacting_living] face.")) + else + playsound(interacting_living, 'sound/weapons/throwsoft.ogg', 20) + examine(interacting_living) + to_chat(interacting_living, span_boldwarning("[user] shows the [src] to you.")) + user.visible_message(span_notice("[user] shows a [src] to [interacting_living].")) diff --git a/code/modules/deathmatch/deathmatch_modifier.dm b/code/modules/deathmatch/deathmatch_modifier.dm index dadca49d70a4f..9faafa91a48b7 100644 --- a/code/modules/deathmatch/deathmatch_modifier.dm +++ b/code/modules/deathmatch/deathmatch_modifier.dm @@ -232,7 +232,7 @@ projectile.ricochets_max += 2 projectile.min_ricochets += 2 projectile.ricochet_incidence_leeway = 0 - ADD_TRAIT(projectile, TRAIT_ALWAYS_HIT_ZONE, DEATHMATCH_TRAIT) + projectile.accuracy_falloff = 0 /datum/deathmatch_modifier/stormtrooper name = "Stormtrooper Aim" diff --git a/code/modules/events/aurora_caelus.dm b/code/modules/events/aurora_caelus.dm index 0acb0ad9781a7..875b8c0dcf23a 100644 --- a/code/modules/events/aurora_caelus.dm +++ b/code/modules/events/aurora_caelus.dm @@ -17,10 +17,12 @@ start_when = 21 end_when = 80 -/datum/round_event/aurora_caelus/announce() +/datum/round_event/aurora_caelus/announce(fake) priority_announce("[station_name()]: A harmless cloud of ions is approaching your station, and will exhaust their energy battering the hull. Nanotrasen has approved a short break for all employees to relax and observe this very rare event. During this time, starlight will be bright but gentle, shifting between quiet green and blue colors. Any staff who would like to view these lights for themselves may proceed to the area nearest to them with viewing ports to open space. We hope you enjoy the lights.", sound = 'sound/misc/notice2.ogg', sender_override = "Nanotrasen Meteorology Division") + if (fake) + return for(var/V in GLOB.player_list) var/mob/M = V if((M.client.prefs.read_preference(/datum/preference/toggle/sound_midi)) && is_station_level(M.z)) @@ -31,6 +33,8 @@ /datum/round_event/aurora_caelus/start() if(!prob(1) && !check_holidays(APRIL_FOOLS)) return + + var/list/human_blacklist = list() for(var/area/station/service/kitchen/affected_area in GLOB.areas) var/obj/machinery/oven/roast_ruiner = locate() in affected_area if(roast_ruiner) @@ -40,10 +44,13 @@ message_admins("Aurora Caelus event caused an oven to ignite at [ADMIN_VERBOSEJMP(ruined_roast)].") log_game("Aurora Caelus event caused an oven to ignite at [loc_name(ruined_roast)].") announce_to_ghosts(roast_ruiner) - for(var/mob/living/carbon/human/seymour as anything in GLOB.human_list) - if(seymour.mind && istype(seymour.mind.assigned_role, /datum/job/cook)) - seymour.say("My roast is ruined!!!", forced = "ruined roast") - seymour.emote("scream") + for(var/mob/living/carbon/human/seymour in viewers(roast_ruiner, 7)) + if (seymour in human_blacklist) + continue + human_blacklist += seymour + if(seymour.mind && istype(seymour.mind.assigned_role, /datum/job/cook)) + seymour.say("My roast is ruined!!!", forced = "ruined roast") + seymour.emote("scream") /datum/round_event/aurora_caelus/tick() if(activeFor % 8 != 0) diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm index 686adf1e5d3f6..9c9d81d01d73f 100644 --- a/code/modules/events/ion_storm.dm +++ b/code/modules/events/ion_storm.dm @@ -34,7 +34,7 @@ //AI laws for(var/mob/living/silicon/ai/M in GLOB.alive_mob_list) M.laws_sanity_check() - if(M.stat != DEAD && !M.incapacitated()) + if(M.stat != DEAD && !M.incapacitated) if(prob(replaceLawsetChance)) var/datum/ai_laws/ion_lawset = pick_weighted_lawset() // pick_weighted_lawset gives us a typepath, diff --git a/code/modules/fishing/aquarium/aquarium_kit.dm b/code/modules/fishing/aquarium/aquarium_kit.dm index 1161648f7d15f..9f88a0cd297b2 100644 --- a/code/modules/fishing/aquarium/aquarium_kit.dm +++ b/code/modules/fishing/aquarium/aquarium_kit.dm @@ -143,6 +143,7 @@ /obj/item/storage/box/aquarium_props name = "aquarium props box" desc = "All you need to make your aquarium look good." + illustration = "fish" /obj/item/storage/box/aquarium_props/PopulateContents() for(var/prop_type in subtypesof(/obj/item/aquarium_prop)) diff --git a/code/modules/fishing/bait.dm b/code/modules/fishing/bait.dm index b67298fab9fea..78d18aa539e8d 100644 --- a/code/modules/fishing/bait.dm +++ b/code/modules/fishing/bait.dm @@ -3,13 +3,16 @@ desc = "there's a lot of them in there, getting them out takes a while though" icon = 'icons/obj/fishing.dmi' icon_state = "bait_can" + base_icon_state = "bait_can" w_class = WEIGHT_CLASS_SMALL /// Tracking until we can take out another bait item COOLDOWN_DECLARE(bait_removal_cooldown) /// What bait item it produces - var/bait_type + var/obj/item/bait_type = /obj/item/food/bait /// Time between bait retrievals - var/cooldown_time = 10 SECONDS + var/cooldown_time = 5 SECONDS + /// How many uses does it have left. + var/uses_left = 20 /obj/item/bait_can/attack_self(mob/user, modifiers) . = ..() @@ -17,19 +20,44 @@ if(fresh_bait) user.put_in_hands(fresh_bait) +/obj/item/bait_can/examine(mob/user) + . = ..() + . += span_info("It[uses_left ? " has got [uses_left] [bait_type::name] left" : "'s empty"].") + +/obj/item/bait_can/update_icon_state() + . = ..() + icon_state = base_icon_state + if(uses_left <= initial(uses_left)) + if(!uses_left) + icon_state = "[icon_state]_empty" + else + icon_state = "[icon_state]_open" + /obj/item/bait_can/proc/retrieve_bait(mob/user) + if(!uses_left) + user.balloon_alert(user, "empty") + return if(!COOLDOWN_FINISHED(src, bait_removal_cooldown)) - user.balloon_alert(user, "wait a bit") //I can't think of generic ic reason. + user.balloon_alert(user, "wait a bit") return COOLDOWN_START(src, bait_removal_cooldown, cooldown_time) + update_appearance() + uses_left-- return new bait_type(src) /obj/item/bait_can/worm name = "can o' worm" - desc = "this can got worms." + desc = "This can got worms." bait_type = /obj/item/food/bait/worm /obj/item/bait_can/worm/premium name = "can o' worm deluxe" - desc = "this can got fancy worms." + desc = "This can got fancy worms." bait_type = /obj/item/food/bait/worm/premium + +/obj/item/bait_can/super_baits + name = "can o' super-baits" + desc = "This can got the nectar of god." + bait_type = /obj/item/food/bait/doughball/synthetic/super + uses_left = 12 + diff --git a/code/modules/fishing/fish/_fish.dm b/code/modules/fishing/fish/_fish.dm index 19a20a40a816b..547d992da1bd6 100644 --- a/code/modules/fishing/fish/_fish.dm +++ b/code/modules/fishing/fish/_fish.dm @@ -390,6 +390,20 @@ update_appearance() SEND_SIGNAL(src, COMSIG_FISH_STATUS_CHANGED) +/obj/item/fish/expose_reagents(list/reagents, datum/reagents/source, methods = TOUCH, volume_modifier = 1, show_message = TRUE) + . = ..() + if(. & COMPONENT_NO_EXPOSE_REAGENTS || status != FISH_DEAD) + return + var/datum/reagent/medicine/strange_reagent/revival = locate() in reagents + if(!revival) + return + if(reagents[revival] >= 2 * w_class) + set_status(FISH_ALIVE) + else + balloon_alert_to_viewers("twitches for a moment!") + animate(src, pixel_x = 1, time = 0.1 SECONDS, loop = 2, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + animate(pixel_x = -1, flags = ANIMATION_RELATIVE) + /obj/item/fish/proc/use_lazarus(datum/source, obj/item/lazarus_injector/injector, mob/user) SIGNAL_HANDLER if(injector.revive_type != SENTIENCE_ORGANIC) diff --git a/code/modules/fishing/fishing_equipment.dm b/code/modules/fishing/fishing_equipment.dm index f6b49a9b52314..b943f2bcdb708 100644 --- a/code/modules/fishing/fishing_equipment.dm +++ b/code/modules/fishing/fishing_equipment.dm @@ -260,7 +260,6 @@ // Can hold fishing rod despite the size var/static/list/exception_cache = typecacheof(list( /obj/item/fishing_rod, - /obj/item/fishing_line, )) atom_storage.exception_hold = exception_cache @@ -286,30 +285,73 @@ new /obj/item/fishing_hook(src) new /obj/item/fishing_line(src) +/obj/item/storage/toolbox/fishing/master + name = "super fishing toolbox" + desc = "Contains EVERYTHING (almost) you need for your fishing trip." + icon_state = "gold" + inhand_icon_state = "toolbox_gold" + +/obj/item/storage/toolbox/fishing/master/PopulateContents() + new /obj/item/fishing_rod/telescopic/master(src) + new /obj/item/storage/box/fishing_hooks/master(src) + new /obj/item/storage/box/fishing_lines/master(src) + new /obj/item/bait_can/super_baits(src) + new /obj/item/fish_feed(src) + new /obj/item/aquarium_kit(src) + new /obj/item/fish_analyzer(src) + new /obj/item/experi_scanner(src) + /obj/item/storage/box/fishing_hooks name = "fishing hook set" + illustration = "fish" /obj/item/storage/box/fishing_hooks/PopulateContents() - . = ..() new /obj/item/fishing_hook/magnet(src) new /obj/item/fishing_hook/shiny(src) new /obj/item/fishing_hook/weighted(src) +/obj/item/storage/box/fishing_hooks/master + +/obj/item/storage/box/fishing_hooks/master/PopulateContents() + . = ..() + new /obj/item/fishing_hook/stabilized(src) + new /obj/item/fishing_hook/jaws(src) + /obj/item/storage/box/fishing_lines name = "fishing line set" + illustration = "fish" /obj/item/storage/box/fishing_lines/PopulateContents() - . = ..() new /obj/item/fishing_line/bouncy(src) new /obj/item/fishing_line/reinforced(src) new /obj/item/fishing_line/cloaked(src) +/obj/item/storage/box/fishing_lines/master + +/obj/item/storage/box/fishing_lines/master/PopulateContents() + . = ..() + new /obj/item/fishing_line/auto_reel(src) + /obj/item/storage/box/fish_debug name = "box full of fish" + illustration = "fish" /obj/item/storage/box/fish_debug/PopulateContents() for(var/fish_type in subtypesof(/obj/item/fish)) new fish_type(src) +///From the fishing mystery box. It's basically a lazarus and a few bottles of strange reagents. +/obj/item/storage/box/fish_revival_kit + name = "fish revival kit" + desc = "Become a fish doctor today." + illustration = "fish" + +/obj/item/storage/box/fish_revival_kit/PopulateContents() + new /obj/item/lazarus_injector(src) + new /obj/item/reagent_containers/cup/bottle/strange_reagent(src) + new /obj/item/reagent_containers/cup(src) //to splash the reagents on the fish. + new /obj/item/storage/fish_case(src) + new /obj/item/storage/fish_case(src) + #undef MAGNET_HOOK_BONUS_MULTIPLIER #undef RESCUE_HOOK_FISH_MULTIPLIER diff --git a/code/modules/fishing/fishing_minigame.dm b/code/modules/fishing/fishing_minigame.dm index 9c70d474a62d7..6c36b4e2da02f 100644 --- a/code/modules/fishing/fishing_minigame.dm +++ b/code/modules/fishing/fishing_minigame.dm @@ -428,7 +428,7 @@ ///Initialize the minigame hud and register some signals to make it work. /datum/fishing_challenge/proc/prepare_minigame_hud() - if(!user.client || user.incapacitated()) + if(!user.client || user.incapacitated) return FALSE . = TRUE fishing_hud = new diff --git a/code/modules/fishing/fishing_portal_machine.dm b/code/modules/fishing/fishing_portal_machine.dm index 494b29b4183ee..8b157cbebfff3 100644 --- a/code/modules/fishing/fishing_portal_machine.dm +++ b/code/modules/fishing/fishing_portal_machine.dm @@ -100,3 +100,7 @@ if(!choice || !can_interact(user)) return activate(available_fish_sources[choice]) + +/obj/machinery/fishing_portal_generator/emagged + obj_flags = parent_type::obj_flags | EMAGGED + circuit = /obj/item/circuitboard/machine/fishing_portal_generator/emagged diff --git a/code/modules/fishing/sources/source_types.dm b/code/modules/fishing/sources/source_types.dm index dd5602b12f99d..e7192bbd09c7d 100644 --- a/code/modules/fishing/sources/source_types.dm +++ b/code/modules/fishing/sources/source_types.dm @@ -9,9 +9,11 @@ /obj/item/fish/lanternfish = 5, /obj/item/fish/zipzap = 5, /obj/item/fish/clownfish/lube = 3, + /obj/structure/mystery_box/fishing = 1, ) fish_counts = list( /obj/item/fish/clownfish/lube = 2, + /obj/structure/mystery_box/fishing = 1, ) fishing_difficulty = FISHING_DEFAULT_DIFFICULTY + 5 explosive_malus = TRUE diff --git a/code/modules/food_and_drinks/machinery/icecream_vat.dm b/code/modules/food_and_drinks/machinery/icecream_vat.dm index 355601693b9d2..b58af21331eab 100644 --- a/code/modules/food_and_drinks/machinery/icecream_vat.dm +++ b/code/modules/food_and_drinks/machinery/icecream_vat.dm @@ -1,5 +1,5 @@ ///How many units of a reagent is needed to make a cone. -#define CONE_REAGENET_NEEDED 1 +#define CONE_REAGENT_NEEDED 1 ///The vat is set to dispense ice cream. #define VAT_MODE_ICECREAM "ice cream" @@ -242,7 +242,7 @@ ///Makes an ice cream cone of the make_type, using ingredients list as reagents used to make it. Puts in user's hand if possible. /obj/machinery/icecream_vat/proc/make_cone(mob/user, make_type, list/ingredients) for(var/reagents_needed in ingredients) - if(!reagents.has_reagent(reagents_needed, CONE_REAGENET_NEEDED)) + if(!reagents.has_reagent(reagents_needed, CONE_REAGENT_NEEDED)) balloon_alert(user, "not enough ingredients!") return var/cone_type = cone_prototypes[make_type].type @@ -251,7 +251,7 @@ var/obj/item/food/icecream/cone = new cone_type(src) for(var/reagents_used in ingredients) - reagents.remove_reagent(reagents_used, CONE_REAGENET_NEEDED) + reagents.remove_reagent(reagents_used, CONE_REAGENT_NEEDED) balloon_alert_to_viewers("cooks up [cone.name]", "cooks up [cone.name]") try_put_in_hand(cone, user) @@ -262,14 +262,14 @@ CRASH("[user] was making ice cream of [selected_flavour] but had no flavor datum for it!") for(var/reagents_needed in flavor.ingredients) - if(!reagents.has_reagent(reagents_needed, CONE_REAGENET_NEEDED)) + if(!reagents.has_reagent(reagents_needed, CONE_REAGENT_NEEDED)) balloon_alert(user, "not enough ingredients!") return var/should_use_custom_ingredients = (flavor.takes_custom_ingredients && custom_ice_cream_beaker && custom_ice_cream_beaker.reagents.total_volume) if(flavor.add_flavour(source, should_use_custom_ingredients ? custom_ice_cream_beaker.reagents : null)) for(var/reagents_used in flavor.ingredients) - reagents.remove_reagent(reagents_used, CONE_REAGENET_NEEDED) + reagents.remove_reagent(reagents_used, CONE_REAGENT_NEEDED) balloon_alert_to_viewers("scoops [selected_flavour]", "scoops [selected_flavour]") if(istype(cone)) @@ -297,4 +297,4 @@ #undef VAT_MODE_ICECREAM #undef VAT_MODE_CONES -#undef CONE_REAGENET_NEEDED +#undef CONE_REAGENT_NEEDED diff --git a/code/modules/food_and_drinks/machinery/smartfridge.dm b/code/modules/food_and_drinks/machinery/smartfridge.dm index a8d07dc8d8769..007b81cf3e8a5 100644 --- a/code/modules/food_and_drinks/machinery/smartfridge.dm +++ b/code/modules/food_and_drinks/machinery/smartfridge.dm @@ -396,43 +396,39 @@ if(. || !ui.user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) return - . = TRUE var/mob/living_mob = ui.user switch(action) if("Release") var/amount = text2num(params["amount"]) - var/desired = 1 + if(isnull(amount) || !isnum(amount)) + return TRUE var/dispensed_amount = 0 if(isAI(living_mob)) to_chat(living_mob, span_warning("[src] does not respect your authority!")) - return - - if (amount > 1) - desired = tgui_input_number(living_mob, "How many items would you like to take out?", "Release", default = min(amount, 50), max_value = min(amount, 50)) - if(!desired) - return + return TRUE - for(var/obj/item/dispensed_item in src) - if(desired <= 0) + for(var/obj/item/dispensed_item in contents) + if(amount <= 0) break var/item_name = "[dispensed_item.type]-[replacetext(replacetext(dispensed_item.name, "\proper", ""), "\improper", "")]" - if(params["path"] == item_name) - if(dispensed_item in component_parts) - CRASH("Attempted removal of [dispensed_item] component_part from smartfridge via smartfridge interface.") - //dispense the item - if(!living_mob.put_in_hands(dispensed_item)) - dispensed_item.forceMove(drop_location()) - adjust_item_drop_location(dispensed_item) - use_energy(active_power_usage) - dispensed_amount++ - desired-- + if(params["path"] != item_name) + continue + if(dispensed_item in component_parts) + CRASH("Attempted removal of [dispensed_item] component_part from smartfridge via smartfridge interface.") + //dispense the item + if(!living_mob.put_in_hands(dispensed_item)) + dispensed_item.forceMove(drop_location()) + adjust_item_drop_location(dispensed_item) + use_energy(active_power_usage) + dispensed_amount++ + amount-- if(dispensed_amount && vend_sound) playsound(src, vend_sound, 50, TRUE, extrarange = -3) if (visible_contents) update_appearance() - return + return TRUE return FALSE diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm index ec8eda8d3cfff..7b8c071b3a539 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm @@ -13,7 +13,7 @@ category = CAT_EGG /datum/crafting_recipe/food/omelette - name = "Omelette" + name = "Omelette du fromage" reqs = list( /obj/item/food/egg = 2, /obj/item/food/cheese/wedge = 2 diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm index 376c1d4f84509..c965526bcb1c6 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm @@ -604,6 +604,16 @@ result = /obj/item/food/cherrycupcake/blue category = CAT_PASTRY +/datum/crafting_recipe/food/jupitercupcake + name = "Jupiter-cup-cake" + reqs = list( + /obj/item/food/pastrybase = 1, + /obj/item/food/grown/mushroom/jupitercup = 1, + /datum/reagent/consumable/caramel = 3, + ) + result = /obj/item/food/jupitercupcake + category = CAT_PASTRY + /datum/crafting_recipe/food/honeybun name = "Honey bun" reqs = list( diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_spaghetti.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_spaghetti.dm index 589235eacb70c..1af5651624d71 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_spaghetti.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_spaghetti.dm @@ -157,3 +157,15 @@ ) result = /obj/item/food/spaghetti/pad_thai category = CAT_SPAGHETTI + +/datum/crafting_recipe/food/carbonara + name = "Spaghetti Carbonara" + reqs = list( + /obj/item/food/spaghetti/boiledspaghetti = 1, + /obj/item/food/cheese/firm_cheese_slice = 1, + /obj/item/food/meat/bacon = 1, + /obj/item/food/egg = 1, + /datum/reagent/consumable/blackpepper = 2, + ) + result = /obj/item/food/spaghetti/carbonara + category = CAT_SPAGHETTI diff --git a/code/modules/instruments/items.dm b/code/modules/instruments/items.dm index 170000eb11557..f0176e6453092 100644 --- a/code/modules/instruments/items.dm +++ b/code/modules/instruments/items.dm @@ -27,7 +27,7 @@ if(!ismob(music_player)) return STOP_PLAYING var/mob/user = music_player - if(user.incapacitated() || !((loc == user) || (isturf(loc) && Adjacent(user)))) // sorry, no more TK playing. + if(user.incapacitated || !((loc == user) || (isturf(loc) && Adjacent(user)))) // sorry, no more TK playing. return STOP_PLAYING /obj/item/instrument/suicide_act(mob/living/user) diff --git a/code/modules/jobs/job_types/curator.dm b/code/modules/jobs/job_types/curator.dm index e2eb35af5497e..93475fdc79e23 100644 --- a/code/modules/jobs/job_types/curator.dm +++ b/code/modules/jobs/job_types/curator.dm @@ -47,7 +47,7 @@ /obj/item/choice_beacon/hero = 1, ) belt = /obj/item/modular_computer/pda/curator - ears = /obj/item/radio/headset/headset_srv + ears = /obj/item/radio/headset/headset_srvent shoes = /obj/item/clothing/shoes/laceup l_pocket = /obj/item/laser_pointer/green r_pocket = /obj/item/key/displaycase @@ -55,6 +55,18 @@ accessory = /obj/item/clothing/accessory/pocketprotector/full +/datum/outfit/job/curator/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + if(visualsOnly) + return ..() + + /// There can be only one cameraman on this station, and no, not that kind + var/static/cameraman_choosen = FALSE + if(!cameraman_choosen) + backpack_contents[/obj/item/broadcast_camera] = 1 + cameraman_choosen = TRUE + return ..() + + /datum/outfit/job/curator/post_equip(mob/living/carbon/human/translator, visualsOnly = FALSE) ..() diff --git a/code/modules/jobs/job_types/mime.dm b/code/modules/jobs/job_types/mime.dm index eba86ec2af07a..46090cdbe30ac 100644 --- a/code/modules/jobs/job_types/mime.dm +++ b/code/modules/jobs/job_types/mime.dm @@ -131,7 +131,7 @@ return FALSE if(!user.is_holding(src)) return FALSE - if(user.incapacitated()) + if(user.incapacitated) return FALSE if(!user.mind) return FALSE diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm index 5d3c620322759..8bfbe362327cb 100644 --- a/code/modules/jobs/job_types/research_director.dm +++ b/code/modules/jobs/job_types/research_director.dm @@ -76,7 +76,10 @@ messenger = /obj/item/storage/backpack/messenger/science chameleon_extras = /obj/item/stamp/head/rd - skillchips = list(/obj/item/skillchip/research_director, /obj/item/skillchip/job/roboticist) + skillchips = list( + /obj/item/skillchip/research_director, + /obj/item/skillchip/job/roboticist, + ) /datum/outfit/job/rd/mod name = "Research Director (MODsuit)" diff --git a/code/modules/language/_language_manuals.dm b/code/modules/language/_language_manuals.dm index eb4ca456440d8..7a4298a06b150 100644 --- a/code/modules/language/_language_manuals.dm +++ b/code/modules/language/_language_manuals.dm @@ -85,6 +85,14 @@ . = ..() name = "extended [initial(language.name)] manual" +/obj/item/language_manual/piratespeak + name = "\improper Captain Pete's Guide to Pirate Lingo" + icon_state = "book_pirate" + desc = "A book containing all the knowledge, jargon and buzzwords to speak like a true old salt." + language = /datum/language/piratespeak + flavour_text = "Blimey! I feel less of a landlubber now." + charges = 5 + // So drones can teach borgs and AI dronespeak. For best effect, combine with mother drone lawset. /obj/item/language_manual/dronespeak_manual name = "dronespeak manual" diff --git a/code/modules/library/bibles.dm b/code/modules/library/bibles.dm index 5221dc8047422..0c6a1aad71d63 100644 --- a/code/modules/library/bibles.dm +++ b/code/modules/library/bibles.dm @@ -186,7 +186,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list( return FALSE if(!istype(user) || !user.is_holding(src)) return FALSE - if(user.incapacitated()) + if(user.incapacitated) return FALSE if(user.mind?.holy_role != HOLY_ROLE_HIGHPRIEST) return FALSE diff --git a/code/modules/library/skill_learning/generic_skillchips/matrix_flip.dm b/code/modules/library/skill_learning/generic_skillchips/matrix_flip.dm deleted file mode 100644 index a836442eca052..0000000000000 --- a/code/modules/library/skill_learning/generic_skillchips/matrix_flip.dm +++ /dev/null @@ -1,40 +0,0 @@ -#define FLIP_STAMINA_COST 19 - -/obj/item/skillchip/matrix_flip - name = "BULLET_DODGER skillchip" - skill_name = "Flip 2 Dodge" - skill_description = "At the cost of stamina, your flips can also be used to dodge incoming projectiles." - skill_icon = FA_ICON_SPINNER - activate_message = span_notice("You feel the urge to flip scenically as if you are the 'Chosen One'.") - deactivate_message = span_notice("The urge to flip goes away.") - -/obj/item/skillchip/matrix_flip/on_activate(mob/living/carbon/user, silent = FALSE) - . = ..() - ADD_TRAIT(user, TRAIT_SLOW_FLIP, SKILLCHIP_TRAIT) - RegisterSignal(user, COMSIG_MOB_EMOTED("flip"), PROC_REF(on_flip)) - RegisterSignal(user, COMSIG_MOB_PRE_EMOTED, PROC_REF(check_if_we_can_flip)) - -/obj/item/skillchip/matrix_flip/on_deactivate(mob/living/carbon/user, silent=FALSE) - REMOVE_TRAIT(user, TRAIT_SLOW_FLIP, SKILLCHIP_TRAIT) - UnregisterSignal(user, list(COMSIG_MOB_EMOTED("flip"), COMSIG_MOB_PRE_EMOTED)) - return ..() - -///Prevent players from stamcritting from INTENTIONAL flips. 1.4s of bullet immunity isn't worth several secs of stun. -/obj/item/skillchip/matrix_flip/proc/check_if_we_can_flip(mob/living/source, key, params, type_override, intentional, datum/emote/emote) - SIGNAL_HANDLER - if(key != "flip" || !intentional) - return - if((source.maxHealth - (source.getStaminaLoss() + FLIP_STAMINA_COST)) <= source.crit_threshold) - source.balloon_alert(source, "too tired!") - return COMPONENT_CANT_EMOTE - -/obj/item/skillchip/matrix_flip/proc/on_flip(mob/living/source) - SIGNAL_HANDLER - if(HAS_TRAIT_FROM(source, TRAIT_UNHITTABLE_BY_PROJECTILES, SKILLCHIP_TRAIT)) - return - playsound(source, 'sound/weapons/fwoosh.ogg', 90, FALSE, frequency = 0.7) - ADD_TRAIT(source, TRAIT_UNHITTABLE_BY_PROJECTILES, SKILLCHIP_TRAIT) - source.adjustStaminaLoss(FLIP_STAMINA_COST) - addtimer(TRAIT_CALLBACK_REMOVE(source, TRAIT_UNHITTABLE_BY_PROJECTILES, SKILLCHIP_TRAIT), FLIP_EMOTE_DURATION * 2) - -#undef FLIP_STAMINA_COST diff --git a/code/modules/library/skill_learning/generic_skillchips/matrix_taunt.dm b/code/modules/library/skill_learning/generic_skillchips/matrix_taunt.dm new file mode 100644 index 0000000000000..cfe61b08e0c3c --- /dev/null +++ b/code/modules/library/skill_learning/generic_skillchips/matrix_taunt.dm @@ -0,0 +1,37 @@ +#define TAUNT_STAMINA_COST 19 + +/obj/item/skillchip/matrix_taunt + name = "BULLET_DODGER skillchip" + skill_name = "Taunt 2 Dodge" + skill_description = "At the cost of stamina, your taunts can also be used to dodge incoming projectiles." + skill_icon = FA_ICON_SPINNER + activate_message = span_notice("You feel the urge to taunt scenically as if you are the 'Chosen One'.") + deactivate_message = span_notice("The urge to taunt goes away.") + +/obj/item/skillchip/matrix_taunt/on_activate(mob/living/carbon/user, silent = FALSE) + . = ..() + RegisterSignal(user, COMSIG_MOB_EMOTED("taunt"), PROC_REF(on_taunt)) + RegisterSignal(user, COMSIG_MOB_PRE_EMOTED, PROC_REF(check_if_we_can_taunt)) + +/obj/item/skillchip/matrix_taunt/on_deactivate(mob/living/carbon/user, silent=FALSE) + UnregisterSignal(user, list(COMSIG_MOB_EMOTED("taunt"), COMSIG_MOB_PRE_EMOTED)) + return ..() + +///Prevent players from stamcritting from INTENTIONAL flips. 1.4s of bullet immunity isn't worth several secs of stun. +/obj/item/skillchip/matrix_taunt/proc/check_if_we_can_taunt(mob/living/source, key, params, type_override, intentional, datum/emote/emote) + SIGNAL_HANDLER + if(key != "taunt" || !intentional) + return + if((source.maxHealth - (source.getStaminaLoss() + TAUNT_STAMINA_COST)) <= source.crit_threshold) + source.balloon_alert(source, "too tired!") + return COMPONENT_CANT_EMOTE + +/obj/item/skillchip/matrix_taunt/proc/on_taunt(mob/living/source) + SIGNAL_HANDLER + if(HAS_TRAIT_FROM(source, TRAIT_UNHITTABLE_BY_PROJECTILES, SKILLCHIP_TRAIT)) + return + ADD_TRAIT(source, TRAIT_UNHITTABLE_BY_PROJECTILES, SKILLCHIP_TRAIT) + source.adjustStaminaLoss(TAUNT_STAMINA_COST) + addtimer(TRAIT_CALLBACK_REMOVE(source, TRAIT_UNHITTABLE_BY_PROJECTILES, SKILLCHIP_TRAIT), TAUNT_EMOTE_DURATION * 1.5) + +#undef TAUNT_STAMINA_COST diff --git a/code/modules/library/skill_learning/generic_skillchips/point.dm b/code/modules/library/skill_learning/generic_skillchips/point.dm new file mode 100644 index 0000000000000..761a482268952 --- /dev/null +++ b/code/modules/library/skill_learning/generic_skillchips/point.dm @@ -0,0 +1,99 @@ +/** + * A skillchip that gives the user bigger arrows when pointing at things (like some id trims do). + * As a bonus, they can costumize the color of the arrow/pointer too. + */ +/obj/item/skillchip/big_pointer + name = "Kommand skillchip" + desc = "A biochip detailing various techniques employed by historical leaders to points at things like a true boss." + skill_name = "Enhanced pointing" + skill_description = "Learn to point at things in a more noticeable way." + skill_icon = FA_ICON_ARROW_DOWN + activate_message = span_notice("From \"The Definitive Compendium of Body Language for the Aspiring Leader\", page 164, paragraph 3...") + deactivate_message = span_notice("So, uh, yeah, how do I point at things again?") + + ///The action for changing the pointer color + var/datum/action/change_pointer_color/action + +/obj/item/skillchip/big_pointer/Destroy() + action = null + return ..() + +/obj/item/skillchip/big_pointer/on_activate(mob/living/carbon/user, silent=FALSE) + . = ..() + RegisterSignal(user, COMSIG_MOVABLE_POINTED, PROC_REF(fancier_pointer)) + if(!action) + action = new(src) + action.Grant(user) + +/obj/item/skillchip/big_pointer/on_deactivate(mob/living/carbon/user, silent=FALSE) + UnregisterSignal(user, COMSIG_MOVABLE_POINTED) + action?.arrow_color = null + action?.arrow_overlay = null + action?.Remove(user) + return ..() + +/obj/item/skillchip/big_pointer/proc/fancier_pointer(mob/living/user, atom/pointed, obj/effect/temp_visual/point/point) + SIGNAL_HANDLER + if(HAS_TRAIT(user, TRAIT_UNKNOWN)) + return + point.cut_overlays() + if(!action.arrow_color) + point.icon_state = "arrow_large" + return + point.icon_state = "arrow_large_white" + point.color = action.arrow_color + var/mutable_appearance/highlight = mutable_appearance(point.icon, "arrow_large_white_highlights", appearance_flags = RESET_COLOR) + point.add_overlay(highlight) + +/datum/action/change_pointer_color + name = "Change Pointer Color" + desc = "Set your custom pointer color, or reset it to the default." + button_icon = /obj/effect/temp_visual/point::icon + button_icon_state = "arrow_large_still" + check_flags = AB_CHECK_CONSCIOUS + ///the color of our arrow + var/arrow_color + ///the arrow overlay shown on the button + var/mutable_appearance/arrow_overlay + +/datum/action/change_pointer_color/Destroy() + . = ..() + arrow_overlay = null + +/datum/action/change_pointer_color/Trigger(trigger_flags) + . = ..() + if(!.) + return + var/mob/user = owner + if(!arrow_color) + pick_color(user) + return + var/choice = tgui_alert(owner, "Reset or update pointer color?","Pointer Color", list("Reset","Update")) + if(user != owner || !choice || !IsAvailable(feedback = TRUE)) + return + if(choice == "Update") + pick_color(user) + else + arrow_color = null + owner.balloon_alert(owner, "pointer reset") + build_all_button_icons(update_flags = UPDATE_BUTTON_ICON, force = TRUE) + +/datum/action/change_pointer_color/proc/pick_color(mob/user) + var/ncolor = input(owner, "Pick new color", "Pointer Color", arrow_color) as color|null + if(user != owner || !IsAvailable(feedback = TRUE)) + return + arrow_color = ncolor + owner.balloon_alert(owner, "pointer updated") + build_all_button_icons(update_flags = UPDATE_BUTTON_ICON, force = TRUE) + +/datum/action/change_pointer_color/apply_button_icon(atom/movable/screen/movable/action_button/current_button, force = FALSE) + if(!arrow_color) + return ..() + + current_button.icon = current_button.icon_state = null + current_button.cut_overlay(arrow_overlay) + + arrow_overlay = mutable_appearance(icon = /obj/effect/temp_visual/point::icon, icon_state = "arrow_large_white_still") + arrow_overlay.color = arrow_color + arrow_overlay.overlays += mutable_appearance(icon = /obj/effect/temp_visual/point::icon, icon_state = "arrow_large_white_still_highlights", appearance_flags = RESET_COLOR) + current_button.add_overlay(arrow_overlay) diff --git a/code/modules/lootpanel/_lootpanel.dm b/code/modules/lootpanel/_lootpanel.dm index 45862ebf45542..2c6239ce9b18f 100644 --- a/code/modules/lootpanel/_lootpanel.dm +++ b/code/modules/lootpanel/_lootpanel.dm @@ -56,7 +56,7 @@ /datum/lootpanel/ui_status(mob/user, datum/ui_state/state) - if(user.incapacitated()) + if(user.incapacitated) return UI_DISABLED return UI_INTERACTIVE diff --git a/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm b/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm index 860eb8c816882..646de6a2186ef 100644 --- a/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm +++ b/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm @@ -161,7 +161,7 @@ GLOBAL_DATUM(necropolis_gate, /obj/structure/necropolis_gate/legion_gate) /obj/structure/necropolis_gate/legion_gate/attack_hand(mob/user, list/modifiers) if(!open && !changing_openness) var/safety = tgui_alert(user, "You think this might be a bad idea...", "Knock on the door?", list("Proceed", "Abort")) - if(safety == "Abort" || !in_range(src, user) || !src || open || changing_openness || user.incapacitated()) + if(safety == "Abort" || !in_range(src, user) || !src || open || changing_openness || user.incapacitated) return user.visible_message(span_warning("[user] knocks on [src]..."), span_boldannounce("You tentatively knock on [src]...")) playsound(user.loc, 'sound/effects/shieldbash.ogg', 100, TRUE) diff --git a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm index 21075cea38add..b761425c94735 100644 --- a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm +++ b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm @@ -72,7 +72,7 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) to_chat(target, span_warning("You too far away from \the [src] to enter it!")) // If the target is incapacitated after selecting a room, they're not allowed to teleport. - if(target.incapacitated()) + if(target.incapacitated) to_chat(target, span_warning("You aren't able to activate \the [src] anymore!")) // Has the user thrown it away or otherwise disposed of it such that it's no longer in their hands or in some storage connected to them? diff --git a/code/modules/mining/equipment/mining_tools.dm b/code/modules/mining/equipment/mining_tools.dm index abf5ca77e181d..0685dda148dee 100644 --- a/code/modules/mining/equipment/mining_tools.dm +++ b/code/modules/mining/equipment/mining_tools.dm @@ -285,7 +285,7 @@ /obj/item/trench_tool/proc/check_menu(mob/user) if(!istype(user)) return FALSE - if(user.incapacitated() || !user.Adjacent(src)) + if(user.incapacitated || !user.Adjacent(src)) return FALSE return TRUE diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index a553415176ea5..f833e15d3f3de 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -18,7 +18,7 @@ /obj/structure/closet/crate/necropolis/tendril/attackby(obj/item/item, mob/user, params) if(!istype(item, /obj/item/skeleton_key) || spawned_loot) return ..() - var/loot = rand(1,20) + var/loot = rand(1,21) var/mod switch(loot) if(1) @@ -71,6 +71,9 @@ new /obj/item/bedsheet/cult(src) if(20) new /obj/item/clothing/neck/necklace/memento_mori(src) + if(21) + new /obj/item/clothing/gloves/fingerless/punch_mitts(src) + new /obj/item/clothing/head/cowboy(src) if(!contents.len) to_chat(user, span_warning("[src] makes a clunking sound as you try to open it. You feel compelled to let the gods know! (Please open an adminhelp and try again!)")) CRASH("Failed to generate loot. loot number: [loot][mod ? "subloot: [mod]" : null]") diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm index e9e8b3a7c3daf..7ad08083df3a8 100644 --- a/code/modules/mining/ores_coins.dm +++ b/code/modules/mining/ores_coins.dm @@ -517,7 +517,7 @@ GLOBAL_LIST_INIT(sand_recipes, list(\ playsound(user.loc, 'sound/items/coinflip.ogg', 50, TRUE) var/oldloc = loc sleep(1.5 SECONDS) - if(loc == oldloc && user && !user.incapacitated()) + if(loc == oldloc && user && !user.incapacitated) user.visible_message(span_notice("[user] flips [src]. It lands on [coinflip]."), \ span_notice("You flip [src]. It lands on [coinflip]."), \ span_hear("You hear the clattering of loose change.")) @@ -599,7 +599,7 @@ GLOBAL_LIST_INIT(sand_recipes, list(\ playsound(user.loc, 'sound/items/coinflip.ogg', 50, TRUE) var/oldloc = loc sleep(1.5 SECONDS) - if(loc == oldloc && user && !user.incapacitated()) + if(loc == oldloc && user && !user.incapacitated) user.visible_message(span_notice("[user] flips [src]. It lands on [coinflip]."), \ span_notice("You flip [src]. It lands on [coinflip]."), \ span_hear("You hear the clattering of loose change.")) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index bf4411a0d482d..80f7be5e3180e 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -141,11 +141,8 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) add_to_dead_mob_list() - for(var/v in GLOB.active_alternate_appearances) - if(!v) - continue - var/datum/atom_hud/alternate_appearance/AA = v - AA.onNewMob(src) + for(var/datum/atom_hud/alternate_appearance/alt_hud as anything in GLOB.active_alternate_appearances) + alt_hud.apply_to_new_mob(src) . = ..() diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm index 84b00249a4972..0fae07a4442dd 100644 --- a/code/modules/mob/emote.dm +++ b/code/modules/mob/emote.dm @@ -83,15 +83,10 @@ /datum/emote/flip/run_emote(mob/user, params , type_override, intentional) . = ..() - user.SpinAnimation(HAS_TRAIT(user, TRAIT_SLOW_FLIP) ? FLIP_EMOTE_DURATION * 2 : FLIP_EMOTE_DURATION, 1) + user.SpinAnimation(FLIP_EMOTE_DURATION, 1) /datum/emote/flip/check_cooldown(mob/user, intentional) - var/slow_flipper = HAS_TRAIT(user, TRAIT_SLOW_FLIP) - if(slow_flipper) - cooldown *= 2 . = ..() - if(slow_flipper) - cooldown *= 0.5 if(.) return if(!can_run_emote(user, intentional=intentional)) @@ -147,3 +142,27 @@ #undef BEYBLADE_DIZZINESS_DURATION #undef BEYBLADE_CONFUSION_INCREMENT #undef BEYBLADE_CONFUSION_LIMIT + + +/datum/emote/jump + key = "jump" + key_third_person = "jumps" + message = "jumps!" + // Allows ghosts to jump + mob_type_ignore_stat_typecache = list(/mob/dead/observer) + +/datum/emote/jump/run_emote(mob/user, params, type_override, intentional) + . = ..() + + var/original_transform = user.transform + animate(user, transform = user.transform.Translate(0, 4), time = 0.1 SECONDS, flags = ANIMATION_PARALLEL) + animate(transform = original_transform, time = 0.1 SECONDS) + +/datum/emote/jump/get_sound(mob/user) + return 'sound/weapons/thudswoosh.ogg' + +// Avoids playing sounds if we're a ghost +/datum/emote/jump/should_play_sound(mob/user, intentional) + if(isliving(user)) + return ..() + return FALSE diff --git a/code/modules/mob/living/basic/basic.dm b/code/modules/mob/living/basic/basic.dm index 582af27c3161b..9501c4e21d3e9 100644 --- a/code/modules/mob/living/basic/basic.dm +++ b/code/modules/mob/living/basic/basic.dm @@ -266,7 +266,7 @@ REMOVE_TRAIT(src, TRAIT_NO_GLIDE, SPEED_TRAIT) /mob/living/basic/relaymove(mob/living/user, direction) - if(user.incapacitated()) + if(user.incapacitated) return return relaydrive(user, direction) diff --git a/code/modules/mob/living/basic/blob_minions/blob_ai.dm b/code/modules/mob/living/basic/blob_minions/blob_ai.dm index 5aad05d4656ff..5fc90f3dd676b 100644 --- a/code/modules/mob/living/basic/blob_minions/blob_ai.dm +++ b/code/modules/mob/living/basic/blob_minions/blob_ai.dm @@ -46,7 +46,7 @@ ai_movement = /datum/ai_movement/jps idle_behavior = /datum/idle_behavior/idle_random_walk planning_subtrees = list( - /datum/ai_planning_subtree/find_and_hunt_target/corpses, + /datum/ai_planning_subtree/find_and_hunt_target/corpses/human, /datum/ai_planning_subtree/travel_to_point/and_clear_target, /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/attack_obstacle_in_path, diff --git a/code/modules/mob/living/basic/bots/_bots.dm b/code/modules/mob/living/basic/bots/_bots.dm index 04b3a7864d21e..d0045cca07a1e 100644 --- a/code/modules/mob/living/basic/bots/_bots.dm +++ b/code/modules/mob/living/basic/bots/_bots.dm @@ -59,6 +59,7 @@ GLOBAL_LIST_INIT(command_strings, list( ///All initial access this bot started with. var/list/initial_access = list() ///Bot-related mode flags on the Bot indicating how they will act. BOT_MODE_ON | BOT_MODE_AUTOPATROL | BOT_MODE_REMOTE_ENABLED | BOT_MODE_CAN_BE_SAPIENT | BOT_MODE_ROUNDSTART_POSSESSION + /// DO NOT MODIFY MANUALLY, USE set_bot_mode_flags. If you don't shit breaks BAD var/bot_mode_flags = BOT_MODE_ON | BOT_MODE_REMOTE_ENABLED | BOT_MODE_CAN_BE_SAPIENT | BOT_MODE_ROUNDSTART_POSSESSION ///Bot-related cover flags on the Bot to deal with what has been done to their cover, including emagging. BOT_COVER_MAINTS_OPEN | BOT_COVER_LOCKED | BOT_COVER_EMAGGED | BOT_COVER_HACKED var/bot_access_flags = BOT_COVER_LOCKED @@ -151,6 +152,11 @@ GLOBAL_LIST_INIT(command_strings, list( ai_controller.set_blackboard_key(BB_RADIO_CHANNEL, radio_channel) update_appearance() +/mob/living/basic/bot/proc/set_mode_flags(mode_flags) + SHOULD_CALL_PARENT(TRUE) + bot_mode_flags = mode_flags + SEND_SIGNAL(src, COMSIG_BOT_MODE_FLAGS_SET, mode_flags) + /mob/living/basic/bot/proc/get_mode() if(client) //Player bots do not have modes, thus the override. Also an easy way for PDA users/AI to know when a bot is a player. return span_bold("[paicard ? "pAI Controlled" : "Autonomous"]") @@ -181,7 +187,7 @@ GLOBAL_LIST_INIT(command_strings, list( /mob/living/basic/bot/proc/turn_on() if(stat == DEAD) return FALSE - bot_mode_flags |= BOT_MODE_ON + set_mode_flags(bot_mode_flags | BOT_MODE_ON) remove_traits(list(TRAIT_INCAPACITATED, TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED), POWER_LACK_TRAIT) set_light_on(bot_mode_flags & BOT_MODE_ON ? TRUE : FALSE) update_appearance() @@ -190,7 +196,7 @@ GLOBAL_LIST_INIT(command_strings, list( return TRUE /mob/living/basic/bot/proc/turn_off() - bot_mode_flags &= ~BOT_MODE_ON + set_mode_flags(bot_mode_flags & ~BOT_MODE_ON) add_traits(on_toggle_traits, POWER_LACK_TRAIT) set_light_on(bot_mode_flags & BOT_MODE_ON ? TRUE : FALSE) bot_reset() //Resets an AI's call, should it exist. @@ -308,7 +314,7 @@ GLOBAL_LIST_INIT(command_strings, list( return FALSE bot_access_flags |= BOT_COVER_EMAGGED bot_access_flags |= BOT_COVER_LOCKED - bot_mode_flags &= ~BOT_MODE_REMOTE_ENABLED //Manually emagging the bot also locks the AI from controlling it. + set_mode_flags(bot_mode_flags & ~BOT_MODE_REMOTE_ENABLED) //Manually emagging the bot also locks the AI from controlling it. bot_reset() turn_on() //The bot automatically turns on when emagged, unless recently hit with EMP. to_chat(src, span_userdanger("(#$*#$^^( OVERRIDE DETECTED")) @@ -553,9 +559,9 @@ GLOBAL_LIST_INIT(command_strings, list( switch(command) if("patroloff") bot_reset() //HOLD IT!! //OBJECTION!! - bot_mode_flags &= ~BOT_MODE_AUTOPATROL + set_mode_flags(bot_mode_flags & ~BOT_MODE_AUTOPATROL) if("patrolon") - bot_mode_flags |= BOT_MODE_AUTOPATROL + set_mode_flags(bot_mode_flags | BOT_MODE_AUTOPATROL) if("summon") summon_bot(user, user_access = user_access) if("ejectpai") @@ -607,10 +613,10 @@ GLOBAL_LIST_INIT(command_strings, list( if("maintenance") bot_access_flags ^= BOT_COVER_MAINTS_OPEN if("patrol") - bot_mode_flags ^= BOT_MODE_AUTOPATROL + set_mode_flags(bot_mode_flags ^ BOT_MODE_AUTOPATROL) bot_reset() if("airplane") - bot_mode_flags ^= BOT_MODE_REMOTE_ENABLED + set_mode_flags(bot_mode_flags ^ BOT_MODE_REMOTE_ENABLED) if("hack") if(!HAS_SILICON_ACCESS(the_user)) return diff --git a/code/modules/mob/living/basic/bots/bot_ai.dm b/code/modules/mob/living/basic/bots/bot_ai.dm index b7cd5dcabd394..a0abbbfd48b40 100644 --- a/code/modules/mob/living/basic/bots/bot_ai.dm +++ b/code/modules/mob/living/basic/bots/bot_ai.dm @@ -55,7 +55,15 @@ var/mob/living/basic/bot/bot_pawn = pawn bot_pawn.bot_reset() -/datum/ai_controller/basic_controller/bot/able_to_run() +/datum/ai_controller/basic_controller/bot/setup_able_to_run() + . = ..() + RegisterSignal(pawn, COMSIG_BOT_MODE_FLAGS_SET, PROC_REF(update_able_to_run)) + +/datum/ai_controller/basic_controller/bot/clear_able_to_run() + UnregisterSignal(pawn, list(COMSIG_BOT_MODE_FLAGS_SET)) + return ..() + +/datum/ai_controller/basic_controller/bot/get_able_to_run() var/mob/living/basic/bot/bot_pawn = pawn if(!(bot_pawn.bot_mode_flags & BOT_MODE_ON)) return FALSE diff --git a/code/modules/mob/living/basic/bots/bot_hud.dm b/code/modules/mob/living/basic/bots/bot_hud.dm index 61aee9f10b180..345fcd2bbe7bf 100644 --- a/code/modules/mob/living/basic/bots/bot_hud.dm +++ b/code/modules/mob/living/basic/bots/bot_hud.dm @@ -47,12 +47,14 @@ if(isnull(ai_controller)) return + //Removes path images and handles removing hud client images clear_path_hud() + var/list/path_huds_watching_me = list(GLOB.huds[DATA_HUD_DIAGNOSTIC], GLOB.huds[DATA_HUD_BOT_PATH]) + var/list/path_images = active_hud_list[DIAG_PATH_HUD] LAZYCLEARLIST(path_images) - var/list/path_huds_watching_me = list(GLOB.huds[DATA_HUD_DIAGNOSTIC], GLOB.huds[DATA_HUD_BOT_PATH]) var/atom/move_target = ai_controller.current_movement_target if(move_target != ai_controller.blackboard[BB_BEACON_TARGET]) @@ -62,9 +64,6 @@ if(!length(our_path)) return - for(var/datum/atom_hud/hud as anything in path_huds_watching_me) - hud.remove_atom_from_hud(src) - for(var/index in 1 to our_path.len) if(index == 1 || index == our_path.len) continue @@ -75,7 +74,9 @@ var/next_direction = get_dir(previous_turf, next_turf) var/previous_direction = get_dir(current_turf, previous_turf) - var/image/path_display = image(icon = path_image_icon, loc = current_turf, icon_state = path_image_icon_state, layer = GAME_PLANE, dir = next_direction) + var/image/path_display = image(icon = path_image_icon, loc = current_turf, icon_state = path_image_icon_state, layer = BOT_PATH_LAYER, dir = next_direction) + + SET_PLANE(path_display, GAME_PLANE, current_turf) if((ISDIAGONALDIR(next_direction) && (previous_direction & (NORTH|SOUTH)))) var/turn_value = (next_direction == SOUTHWEST || next_direction == NORTHEAST) ? 90 : -90 @@ -118,3 +119,8 @@ animate(our_image, alpha = 0, time = 0.3 SECONDS) current_pathed_turfs -= index + // Call hud remove handlers to ensure viewing user client images are removed + var/list/path_huds_watching_me = list(GLOB.huds[DATA_HUD_DIAGNOSTIC], GLOB.huds[DATA_HUD_BOT_PATH]) + for(var/datum/atom_hud/hud as anything in path_huds_watching_me) + hud.remove_atom_from_hud(src) + diff --git a/code/modules/mob/living/basic/drone/_drone.dm b/code/modules/mob/living/basic/drone/_drone.dm index 6501e35d51dc2..3ef8cdc3aa136 100644 --- a/code/modules/mob/living/basic/drone/_drone.dm +++ b/code/modules/mob/living/basic/drone/_drone.dm @@ -222,7 +222,7 @@ holder.pixel_y = hud_icon.Height() - world.icon_size if(stat == DEAD) holder.icon_state = "huddead2" - else if(incapacitated()) + else if(incapacitated) holder.icon_state = "hudoffline" else holder.icon_state = "hudstat" diff --git a/code/modules/mob/living/basic/drone/visuals_icons.dm b/code/modules/mob/living/basic/drone/visuals_icons.dm index 7a2122022f81b..32ff97da305a1 100644 --- a/code/modules/mob/living/basic/drone/visuals_icons.dm +++ b/code/modules/mob/living/basic/drone/visuals_icons.dm @@ -108,7 +108,7 @@ /mob/living/basic/drone/proc/check_menu() if(!istype(src)) return FALSE - if(incapacitated()) + if(incapacitated) return FALSE return TRUE diff --git a/code/modules/mob/living/basic/guardian/guardian_creator.dm b/code/modules/mob/living/basic/guardian/guardian_creator.dm index 441a60124a7bf..08a28041cc845 100644 --- a/code/modules/mob/living/basic/guardian/guardian_creator.dm +++ b/code/modules/mob/living/basic/guardian/guardian_creator.dm @@ -129,7 +129,7 @@ GLOBAL_LIST_INIT(guardian_radial_images, setup_guardian_radial()) /obj/item/guardian_creator/proc/check_menu(mob/living/user) if(!istype(user)) return FALSE - if(user.incapacitated() || !user.is_holding(src) || used) + if(user.incapacitated || !user.is_holding(src) || used) return FALSE return TRUE diff --git a/code/modules/mob/living/basic/lavaland/legion/legion.dm b/code/modules/mob/living/basic/lavaland/legion/legion.dm index 1abd916461bb8..12bf6555d97d4 100644 --- a/code/modules/mob/living/basic/lavaland/legion/legion.dm +++ b/code/modules/mob/living/basic/lavaland/legion/legion.dm @@ -10,7 +10,7 @@ icon_living = "legion" icon_dead = "legion" icon_gib = "syndicate_gib" - mob_biotypes = MOB_ORGANIC|MOB_HUMANOID + mob_biotypes = MOB_ORGANIC|MOB_SPECIAL|MOB_UNDEAD basic_mob_flags = DEL_ON_DEATH speed = 3 maxHealth = 75 diff --git a/code/modules/mob/living/basic/slime/ai/behaviours.dm b/code/modules/mob/living/basic/slime/ai/behaviours.dm index 1cd4677994531..8cdda9a402baa 100644 --- a/code/modules/mob/living/basic/slime/ai/behaviours.dm +++ b/code/modules/mob/living/basic/slime/ai/behaviours.dm @@ -30,14 +30,14 @@ /datum/ai_behavior/find_hunt_target/find_slime_food/valid_dinner(mob/living/basic/slime/hunter, mob/living/dinner, radius, datum/ai_controller/controller, seconds_per_tick) if(REF(dinner) in hunter.faction) //Don't eat our friends... - return + return FALSE var/static/list/slime_faction = list(FACTION_SLIME) if(faction_check(slime_faction, dinner.faction)) //Don't try to eat slimy things, no matter how hungry we are. Anyone else can be betrayed. - return + return FALSE if(!hunter.can_feed_on(dinner, check_adjacent = FALSE)) //Are they tasty to slimes? - return + return FALSE //If we are retaliating on someone edible, lets eat them instead if(dinner == controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]) @@ -69,6 +69,7 @@ /datum/ai_behavior/hunt_target/unarmed_attack_target/slime/finish_action(datum/ai_controller/controller, succeeded, hunting_target_key, hunting_cooldown_key) . = ..() - var/mob/living/living_pawn = controller.pawn - if(living_pawn.buckled) + var/mob/living/basic/slime/slime_pawn = controller.pawn + var/atom/target = controller.blackboard[hunting_target_key] + if(!slime_pawn.can_feed_on(target)) controller.clear_blackboard_key(hunting_target_key) diff --git a/code/modules/mob/living/basic/slime/ai/subtrees.dm b/code/modules/mob/living/basic/slime/ai/subtrees.dm index 66c01e6f6c3c6..056befece5d4b 100644 --- a/code/modules/mob/living/basic/slime/ai/subtrees.dm +++ b/code/modules/mob/living/basic/slime/ai/subtrees.dm @@ -31,11 +31,11 @@ /datum/ai_planning_subtree/find_and_hunt_target/find_slime_food/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) var/mob/living/living_pawn = controller.pawn if(living_pawn.buckled) - return FALSE + return //Slimes don't want to hunt if they are neither rabid, hungry or feeling attack right now if( (controller.blackboard[BB_SLIME_HUNGER_LEVEL] == SLIME_HUNGER_NONE) && !controller.blackboard[BB_SLIME_RABID] && isnull(controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET])) - return FALSE + return return ..() diff --git a/code/modules/mob/living/basic/slime/slime.dm b/code/modules/mob/living/basic/slime/slime.dm index 352a8149ca616..6adf4e35f3582 100644 --- a/code/modules/mob/living/basic/slime/slime.dm +++ b/code/modules/mob/living/basic/slime/slime.dm @@ -286,7 +286,7 @@ /mob/living/basic/slime/proc/on_slime_pre_attack(mob/living/basic/slime/our_slime, atom/target, proximity, modifiers) SIGNAL_HANDLER - if(LAZYACCESS(modifiers, RIGHT_CLICK) && isliving(target) && target != src && usr == src) + if(LAZYACCESS(modifiers, RIGHT_CLICK) && isliving(target) && target != src) if(our_slime.can_feed_on(target)) our_slime.start_feeding(target) return COMPONENT_HOSTILE_NO_ATTACK diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp.dm b/code/modules/mob/living/basic/space_fauna/carp/carp.dm index 816bb7cd838e1..1d32b7809a89e 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp.dm @@ -44,6 +44,8 @@ minimum_survivable_temperature = 0 maximum_survivable_temperature = 1500 + /// If true we will run away from attackers even at full health + var/cowardly = FALSE /// Cytology cells you can swab from this creature var/cell_line = CELL_LINE_TABLE_CARP /// What colour is our 'healing' outline? @@ -88,7 +90,8 @@ if (cell_line) AddElement(/datum/element/swabable, cell_line, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) AddElement(/datum/element/simple_flying) - AddElement(/datum/element/ai_flee_while_injured) + if (!cowardly) + AddElement(/datum/element/ai_flee_while_injured) setup_eating() AddComponent(/datum/component/aggro_emote, emote_list = string_list(list("gnashes"))) @@ -267,8 +270,8 @@ ///Wild carp that just vibe ya know /mob/living/basic/carp/passive - name = "passive carp" - desc = "A timid, sucker-bearing creature that resembles a fish. " + name = "false carp" + desc = "A close relative of the space carp which is entirely toothless and feeds by stealing its cousin's leftovers." icon_state = "base_friend" icon_living = "base_friend" @@ -278,11 +281,19 @@ attack_verb_continuous = "suckers" attack_verb_simple = "suck" - melee_damage_lower = 4 - melee_damage_upper = 4 + melee_damage_lower = 0 + melee_damage_upper = 0 + cowardly = TRUE ai_controller = /datum/ai_controller/basic_controller/carp/passive + gold_core_spawnable = FRIENDLY_SPAWN /mob/living/basic/carp/passive/Initialize(mapload) . = ..() - AddElement(/datum/element/ai_retaliate) + AddComponent(/datum/component/ai_retaliate_advanced, CALLBACK(src, PROC_REF(on_attacked))) AddElement(/datum/element/pet_bonus, "bloops happily!") + ADD_TRAIT(src, TRAIT_PACIFISM, INNATE_TRAIT) + +/// If someone slaps one of the school, scatter +/mob/living/basic/carp/passive/proc/on_attacked(mob/living/attacker) + for(var/mob/living/basic/carp/passive/schoolmate in oview(src, 9)) + schoolmate.ai_controller?.insert_blackboard_key_lazylist(BB_BASIC_MOB_RETALIATE_LIST, attacker) diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm index f104d3566b347..260dce64bdc29 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm @@ -7,18 +7,20 @@ var/datum/ai_behavior/rift_behaviour /// If true we finish planning after this var/finish_planning = FALSE + /// Key to read for flee target + var/target_key = BB_BASIC_MOB_CURRENT_TARGET /datum/ai_planning_subtree/make_carp_rift/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) if (!rift_behaviour) CRASH("Forgot to specify rift behaviour for [src]") - if (!controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET)) + if (!controller.blackboard_key_exists(target_key)) return var/datum/action/cooldown/using_action = controller.blackboard[BB_CARP_RIFT] if (!using_action?.IsAvailable()) return - controller.queue_behavior(rift_behaviour, BB_CARP_RIFT, BB_BASIC_MOB_CURRENT_TARGET) + controller.queue_behavior(rift_behaviour, BB_CARP_RIFT, target_key) if (finish_planning) return SUBTREE_RETURN_FINISH_PLANNING @@ -31,13 +33,17 @@ finish_planning = TRUE /datum/ai_planning_subtree/make_carp_rift/panic_teleport/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - var/atom/movable/fleeing_from = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] + var/atom/movable/fleeing_from = controller.blackboard[target_key] if(!QDELETED(fleeing_from) && controller.blackboard[BB_CARPS_FEAR_FISHERMAN] && HAS_TRAIT(fleeing_from, TRAIT_SCARY_FISHERMAN)) return ..() if (controller.blackboard[BB_BASIC_MOB_STOP_FLEEING]) return return ..() +/datum/ai_planning_subtree/make_carp_rift/panic_teleport/flee_key + target_key = BB_BASIC_MOB_FLEE_TARGET + + /** * # Make carp rift (aggressive) * Plan to teleport towards our target so we can fuck them up @@ -46,7 +52,7 @@ rift_behaviour = /datum/ai_behavior/make_carp_rift/towards/aggressive /datum/ai_planning_subtree/make_carp_rift/aggressive_teleport/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - var/atom/movable/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] + var/atom/movable/target = controller.blackboard[target_key] if(!QDELETED(target) && controller.blackboard[BB_CARPS_FEAR_FISHERMAN] && HAS_TRAIT(target, TRAIT_SCARY_FISHERMAN)) return return ..() diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm index 4491ef1149137..ae011f5b14a31 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm @@ -106,22 +106,21 @@ */ /datum/ai_controller/basic_controller/carp/passive blackboard = list( - BB_BASIC_MOB_STOP_FLEEING = TRUE, - BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/require_traits, + BB_FLEE_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, - BB_TARGET_PRIORITY_TRAIT = TRAIT_SCARY_FISHERMAN, BB_CARPS_FEAR_FISHERMAN = TRUE, + BB_TARGET_ONLY_WITH_TRAITS = list(TRAIT_SCARY_FISHERMAN), ) ai_traits = STOP_MOVING_WHEN_PULLED planning_subtrees = list( /datum/ai_planning_subtree/pet_planning, - /datum/ai_planning_subtree/simple_find_nearest_target_to_flee, - /datum/ai_planning_subtree/make_carp_rift/panic_teleport, - /datum/ai_planning_subtree/flee_target/from_fisherman, + /datum/ai_planning_subtree/simple_find_target/to_flee, // This should only find master fishermen because of the targeting strategy + /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/from_flee_key, + /datum/ai_planning_subtree/make_carp_rift/panic_teleport/flee_key, + /datum/ai_planning_subtree/flee_target/from_flee_key, /datum/ai_planning_subtree/find_food, - /datum/ai_planning_subtree/attack_obstacle_in_path/carp, - /datum/ai_planning_subtree/shortcut_to_target_through_carp_rift, /datum/ai_planning_subtree/make_carp_rift/aggressive_teleport, - /datum/ai_planning_subtree/basic_melee_attack_subtree/no_fisherman, + /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/carp_migration, ) diff --git a/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/wrap.dm b/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/wrap.dm index e7771f075a871..088905a5ae2f3 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/wrap.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/wrap.dm @@ -26,7 +26,7 @@ /datum/action/cooldown/mob_cooldown/wrap/IsAvailable(feedback = FALSE) . = ..() - if(!. || owner.incapacitated()) + if(!. || owner.incapacitated) return FALSE if(DOING_INTERACTION(owner, DOAFTER_SOURCE_SPIDER)) if (feedback) diff --git a/code/modules/mob/living/basic/vermin/crab.dm b/code/modules/mob/living/basic/vermin/crab.dm index 18a935443a11d..f856bf889c0f0 100644 --- a/code/modules/mob/living/basic/vermin/crab.dm +++ b/code/modules/mob/living/basic/vermin/crab.dm @@ -88,7 +88,6 @@ planning_subtrees = list( /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/from_flee_key, /datum/ai_planning_subtree/flee_target/from_flee_key, - /datum/ai_planning_subtree/target_retaliate/to_flee, /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/random_speech/crab, diff --git a/code/modules/mob/living/carbon/alien/adult/adult.dm b/code/modules/mob/living/carbon/alien/adult/adult.dm index ad005888178ac..663419ce22cff 100644 --- a/code/modules/mob/living/carbon/alien/adult/adult.dm +++ b/code/modules/mob/living/carbon/alien/adult/adult.dm @@ -78,6 +78,7 @@ GLOBAL_LIST_INIT(strippable_alien_humanoid_items, create_strippable_list(list( SEND_SIGNAL(src, COMSIG_MOVABLE_SET_GRAB_STATE, newstate) . = grab_state grab_state = newstate + update_incapacitated() switch(grab_state) // Current state. if(GRAB_PASSIVE) REMOVE_TRAIT(pulling, TRAIT_IMMOBILIZED, CHOKEHOLD_TRAIT) @@ -101,7 +102,7 @@ GLOBAL_LIST_INIT(strippable_alien_humanoid_items, create_strippable_list(list( /mob/living/carbon/alien/adult/proc/can_consume(atom/movable/poor_soul) if(!isliving(poor_soul) || pulling != poor_soul) return FALSE - if(incapacitated() || grab_state < GRAB_AGGRESSIVE || stat != CONSCIOUS) + if(incapacitated || grab_state < GRAB_AGGRESSIVE || stat != CONSCIOUS) return FALSE if(get_dir(src, poor_soul) != dir) // Gotta face em 4head return FALSE diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 79af6c802d623..978714e9bf7a3 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -395,7 +395,7 @@ playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) // Shake animation - if (incapacitated()) + if (incapacitated) shake_up_animation() /mob/proc/shake_up_animation() @@ -650,6 +650,12 @@ /// Randomise a body part and organ of this mob /mob/living/carbon/proc/bioscramble(scramble_source) + if(!(mob_biotypes & MOB_ORGANIC)) + return FALSE + + if (HAS_TRAIT(src, TRAIT_GENELESS)) + return FALSE + if (run_armor_check(attack_flag = BIO, absorb_text = "Your armor protects you from [scramble_source]!") >= 100) return FALSE diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 9816012218225..cf73704600c7f 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -909,7 +909,7 @@ return ishuman(target) && target.body_position == LYING_DOWN /mob/living/carbon/human/proc/fireman_carry(mob/living/carbon/target) - if(!can_be_firemanned(target) || incapacitated(IGNORE_GRAB)) + if(!can_be_firemanned(target) || INCAPACITATED_IGNORING(src, INCAPABLE_GRAB)) to_chat(src, span_warning("You can't fireman carry [target] while [target.p_they()] [target.p_are()] standing!")) return @@ -940,7 +940,7 @@ return //Second check to make sure they're still valid to be carried - if(!can_be_firemanned(target) || incapacitated(IGNORE_GRAB) || target.buckled) + if(!can_be_firemanned(target) || INCAPACITATED_IGNORING(src, INCAPABLE_GRAB) || target.buckled) visible_message(span_warning("[src] fails to fireman carry [target]!")) return @@ -956,7 +956,7 @@ visible_message(span_warning("[target] fails to climb onto [src]!")) return - if(target.incapacitated(IGNORE_GRAB) || incapacitated(IGNORE_GRAB)) + if(INCAPACITATED_IGNORING(target, INCAPABLE_GRAB) || INCAPACITATED_IGNORING(src, INCAPABLE_GRAB)) target.visible_message(span_warning("[target] can't hang onto [src]!")) return diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 3a9004618470f..c561ca28999f1 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -58,10 +58,13 @@ //repurposed proc. Now it combines get_id_name() and get_face_name() to determine a mob's name variable. Made into a separate proc as it'll be useful elsewhere /mob/living/carbon/human/get_visible_name(add_id_name = TRUE, force_real_name = FALSE) - var/list/identity = list(null, null) + var/list/identity = list(null, null, null) SEND_SIGNAL(src, COMSIG_HUMAN_GET_VISIBLE_NAME, identity) var/signal_face = LAZYACCESS(identity, VISIBLE_NAME_FACE) var/signal_id = LAZYACCESS(identity, VISIBLE_NAME_ID) + var/force_set = LAZYACCESS(identity, VISIBLE_NAME_FORCED) + if(force_set) // our name is overriden by something + return signal_face // no need to null-check, because force_set will always set a signal_face var/face_name = !isnull(signal_face) ? signal_face : get_face_name("") var/id_name = !isnull(signal_id) ? signal_id : get_id_name("") if (force_real_name) @@ -107,6 +110,11 @@ var/obj/item/card/id/id = wear_id if(HAS_TRAIT(src, TRAIT_UNKNOWN)) . = if_no_id //You get NOTHING, no id name, good day sir + var/list/identity = list(null, null, null) + SEND_SIGNAL(src, COMSIG_HUMAN_GET_FORCED_NAME, identity) + if(identity[VISIBLE_NAME_FORCED]) + . = identity[VISIBLE_NAME_FACE] // to return forced names when unknown, instead of ID + return if(istype(wallet)) id = wallet.front_id if(istype(id)) diff --git a/code/modules/mob/living/carbon/human/human_say.dm b/code/modules/mob/living/carbon/human/human_say.dm index 0ce34ffa27205..8edeeb8088403 100644 --- a/code/modules/mob/living/carbon/human/human_say.dm +++ b/code/modules/mob/living/carbon/human/human_say.dm @@ -73,7 +73,7 @@ var/area/our_area = get_area(src) if(our_area.area_flags & BINARY_JAMMING) return FALSE - return dongle.translate_binary + return (dongle.special_channels & RADIO_SPECIAL_BINARY) /mob/living/carbon/human/radio(message, list/message_mods = list(), list/spans, language) //Poly has a copy of this, lazy bastard . = ..() diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index a24e9cd070d86..f0b0d9b8cdc39 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -368,7 +368,7 @@ /// take the most recent item out of a slot or place held item in a slot /mob/living/carbon/human/proc/smart_equip_targeted(slot_type = ITEM_SLOT_BELT, slot_item_name = "belt") - if(incapacitated()) + if(incapacitated) return var/obj/item/thing = get_active_held_item() var/obj/item/equipped_item = get_item_by_slot(slot_type) 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 0cb0d9d85f084..8b347a22cca96 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -27,7 +27,7 @@ heatmod = 1.5 payday_modifier = 1.0 breathid = GAS_PLASMA - changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC + changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | ERT_SPAWN species_cookie = /obj/item/reagent_containers/condiment/milk outfit_important_for_life = /datum/outfit/plasmaman species_language_holder = /datum/language_holder/skeleton diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 62030cf1eba59..a626cb47cc6d8 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -4,6 +4,16 @@ mob_type_allowed_typecache = /mob/living mob_type_blacklist_typecache = list(/mob/living/brain) +/datum/emote/living/taunt + key = "taunt" + key_third_person = "taunts" + message = "taunts!" + cooldown = 1.6 SECONDS //note when changing this- this is used by the matrix taunt to block projectiles. + +/datum/emote/living/taunt/run_emote(mob/living/user, params, type_override, intentional) + . = ..() + user.spin(TAUNT_EMOTE_DURATION, 0.1 SECONDS) + /datum/emote/living/blush key = "blush" key_third_person = "blushes" @@ -225,20 +235,6 @@ key_third_person = "grimaces" message = "grimaces." -/datum/emote/living/jump - key = "jump" - key_third_person = "jumps" - message = "jumps!" - hands_use_check = TRUE - -/datum/emote/living/jump/run_emote(mob/living/user, params, type_override, intentional) - . = ..() - animate(user, pixel_y = user.pixel_y + 4, time = 0.1 SECONDS) - animate(pixel_y = user.pixel_y - 4, time = 0.1 SECONDS) - -/datum/emote/living/jump/get_sound(mob/living/user) - return 'sound/weapons/thudswoosh.ogg' - /datum/emote/living/kiss key = "kiss" key_third_person = "kisses" @@ -248,6 +244,9 @@ . = ..() var/kiss_type = /obj/item/hand_item/kisser + if(HAS_TRAIT(user, TRAIT_SYNDIE_KISS)) + kiss_type = /obj/item/hand_item/kisser/syndie + if(HAS_TRAIT(user, TRAIT_KISS_OF_DEATH)) kiss_type = /obj/item/hand_item/kisser/death diff --git a/code/modules/mob/living/init_signals.dm b/code/modules/mob/living/init_signals.dm index 4bf0407c4670a..0797f77c08210 100644 --- a/code/modules/mob/living/init_signals.dm +++ b/code/modules/mob/living/init_signals.dm @@ -40,6 +40,8 @@ RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_DEAF), PROC_REF(on_hearing_loss)) RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_DEAF), PROC_REF(on_hearing_regain)) + RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_STASIS), PROC_REF(on_stasis_trait_gain)) + RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_STASIS), PROC_REF(on_stasis_trait_loss)) RegisterSignals(src, list( SIGNAL_ADDTRAIT(TRAIT_CRITICAL_CONDITION), @@ -187,24 +189,36 @@ SIGNAL_HANDLER add_traits(list(TRAIT_UI_BLOCKED, TRAIT_PULL_BLOCKED), TRAIT_INCAPACITATED) update_appearance() + update_incapacitated() /// Called when [TRAIT_INCAPACITATED] is removed from the mob. /mob/living/proc/on_incapacitated_trait_loss(datum/source) SIGNAL_HANDLER remove_traits(list(TRAIT_UI_BLOCKED, TRAIT_PULL_BLOCKED), TRAIT_INCAPACITATED) update_appearance() - + update_incapacitated() /// Called when [TRAIT_RESTRAINED] is added to the mob. /mob/living/proc/on_restrained_trait_gain(datum/source) SIGNAL_HANDLER ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, TRAIT_RESTRAINED) + update_incapacitated() /// Called when [TRAIT_RESTRAINED] is removed from the mob. /mob/living/proc/on_restrained_trait_loss(datum/source) SIGNAL_HANDLER REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, TRAIT_RESTRAINED) + update_incapacitated() + +/// Called when [TRAIT_STASIS] is added to the mob +/mob/living/proc/on_stasis_trait_gain(datum/source) + SIGNAL_HANDLER + update_incapacitated() +/// Called when [TRAIT_STASIS] is removed from the mob +/mob/living/proc/on_stasis_trait_loss(datum/source) + SIGNAL_HANDLER + update_incapacitated() /** * Called when traits that alter succumbing are added/removed. diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 70f268c2a454a..ee2aaa1fa7201 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -70,7 +70,7 @@ damage_softening_multiplier *= potential_spine.athletics_boost_multiplier // If you are incapped, you probably can't brace yourself - var/can_help_themselves = !incapacitated(IGNORE_RESTRAINTS) + var/can_help_themselves = !INCAPACITATED_IGNORING(src, INCAPABLE_RESTRAINTS) if(levels <= 1 && can_help_themselves) var/obj/item/organ/external/wings/gliders = get_organ_by_type(/obj/item/organ/external/wings) if(HAS_TRAIT(src, TRAIT_FREERUNNING) || gliders?.can_soften_fall()) // the power of parkour or wings allows falling short distances unscathed @@ -516,7 +516,7 @@ //same as above /mob/living/pointed(atom/A as mob|obj|turf in view(client.view, src)) - if(incapacitated()) + if(incapacitated) return FALSE return ..() @@ -545,31 +545,21 @@ investigate_log("has succumbed to death.", INVESTIGATE_DEATHS) death() -/** - * Checks if a mob is incapacitated - * - * Normally being restrained, agressively grabbed, or in stasis counts as incapacitated - * unless there is a flag being used to check if it's ignored - * - * args: - * * flags (optional) bitflags that determine if special situations are exempt from being considered incapacitated - * - * bitflags: (see code/__DEFINES/status_effects.dm) - * * IGNORE_RESTRAINTS - mob in a restraint (handcuffs) is not considered incapacitated - * * IGNORE_STASIS - mob in stasis (stasis bed, etc.) is not considered incapacitated - * * IGNORE_GRAB - mob that is agressively grabbed is not considered incapacitated -**/ -/mob/living/incapacitated(flags) +// Remember, anything that influences this needs to call update_incapacitated somehow when it changes +// Most often best done in [code/modules/mob/living/init_signals.dm] +/mob/living/build_incapacitated(flags) + // Holds a set of flags that describe how we are currently incapacitated + var/incap_status = NONE if(HAS_TRAIT(src, TRAIT_INCAPACITATED)) - return TRUE + incap_status |= TRADITIONAL_INCAPACITATED + if(HAS_TRAIT(src, TRAIT_RESTRAINED)) + incap_status |= INCAPABLE_RESTRAINTS + if(pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE) + incap_status |= INCAPABLE_GRAB + if(HAS_TRAIT(src, TRAIT_STASIS)) + incap_status |= INCAPABLE_STASIS - if(!(flags & IGNORE_RESTRAINTS) && HAS_TRAIT(src, TRAIT_RESTRAINED)) - return TRUE - if(!(flags & IGNORE_GRAB) && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE) - return TRUE - if(!(flags & IGNORE_STASIS) && HAS_TRAIT(src, TRAIT_STASIS)) - return TRUE - return FALSE + return incap_status /mob/living/canUseStorage() if (usable_hands <= 0) @@ -1124,7 +1114,7 @@ /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/will_scratch = can_scratch && !incapacitated var/applied_damage = 0 if (will_scratch && damage) applied_damage = apply_damage(damage, damagetype = BRUTE, def_zone = target_part) @@ -1354,11 +1344,11 @@ if(!(interaction_flags_atom & INTERACT_ATOM_IGNORE_INCAPACITATED)) var/ignore_flags = NONE if(interaction_flags_atom & INTERACT_ATOM_IGNORE_RESTRAINED) - ignore_flags |= IGNORE_RESTRAINTS + ignore_flags |= INCAPABLE_RESTRAINTS if(!(interaction_flags_atom & INTERACT_ATOM_CHECK_GRAB)) - ignore_flags |= IGNORE_GRAB + ignore_flags |= INCAPABLE_GRAB - if(incapacitated(ignore_flags)) + if(INCAPACITATED_IGNORING(src, ignore_flags)) to_chat(src, span_warning("You are incapacitated at the moment!")) return FALSE @@ -1842,7 +1832,7 @@ GLOBAL_LIST_EMPTY(fire_appearances) 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]) + for(var/datum/ai_controller/controller as anything in GLOB.ai_controllers_by_zlevel[registered_z]) controller.set_ai_status(AI_STATUS_OFF) if(new_z) @@ -1853,7 +1843,7 @@ GLOBAL_LIST_EMPTY(fire_appearances) SSmobs.clients_by_zlevel[new_z] += src 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]) + for (var/datum/ai_controller/controller as anything in GLOB.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()) @@ -2152,10 +2142,9 @@ GLOBAL_LIST_EMPTY(fire_appearances) /mob/living/proc/can_look_up() if(next_move > world.time) return FALSE - if(incapacitated(IGNORE_RESTRAINTS)) + if(INCAPACITATED_IGNORING(src, INCAPABLE_RESTRAINTS)) return FALSE return TRUE - /** * look_up Changes the perspective of the mob to any openspace turf above the mob * @@ -2346,6 +2335,7 @@ GLOBAL_LIST_EMPTY(fire_appearances) /mob/living/set_pulledby(new_pulledby) . = ..() + update_incapacitated() if(. == FALSE) //null is a valid value here, we only want to return if FALSE is explicitly passed. return if(pulledby) @@ -2819,3 +2809,25 @@ GLOBAL_LIST_EMPTY(fire_appearances) return "[span_notice("You'd estimate [p_their()] fitness level at about...")] [span_boldwarning("What?!? [our_fitness_level]???")]" return span_notice("You'd estimate [p_their()] fitness level at about [our_fitness_level]. [comparative_fitness <= 0.33 ? "Pathetic." : ""]") + +///Performs the aftereffects of blocking a projectile. +/mob/living/proc/block_projectile_effects() + var/static/list/icon/blocking_overlay + if(isnull(blocking_overlay)) + blocking_overlay = list( + mutable_appearance('icons/mob/effects/blocking.dmi', "wow"), + mutable_appearance('icons/mob/effects/blocking.dmi', "nice"), + mutable_appearance('icons/mob/effects/blocking.dmi', "good"), + ) + ADD_TRAIT(src, TRAIT_BLOCKING_PROJECTILES, BLOCKING_TRAIT) + var/icon/selected_overlay = pick(blocking_overlay) + add_overlay(selected_overlay) + playsound(src, 'sound/weapons/fwoosh.ogg', 90, FALSE, frequency = 0.7) + update_transform(1.25) + addtimer(CALLBACK(src, PROC_REF(end_block_effects), selected_overlay), 0.6 SECONDS) + +///Remoevs the effects of blocking a projectile and allows the user to block another. +/mob/living/proc/end_block_effects(selected_overlay) + REMOVE_TRAIT(src, TRAIT_BLOCKING_PROJECTILES, BLOCKING_TRAIT) + cut_overlay(selected_overlay) + update_transform(0.8) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 99538836476d6..7e724d8862117 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -269,6 +269,7 @@ return FALSE grippedby(user) + update_incapacitated() //proc to upgrade a simple pull into a more aggressive grab. /mob/living/proc/grippedby(mob/living/user, instant = FALSE) diff --git a/code/modules/mob/living/living_movement.dm b/code/modules/mob/living/living_movement.dm index 62c290217fd3f..4522b6ca69a52 100644 --- a/code/modules/mob/living/living_movement.dm +++ b/code/modules/mob/living/living_movement.dm @@ -124,7 +124,7 @@ return ..() /mob/living/can_z_move(direction, turf/start, turf/destination, z_move_flags = ZMOVE_FLIGHT_FLAGS, mob/living/rider) - if(z_move_flags & ZMOVE_INCAPACITATED_CHECKS && incapacitated()) + if(z_move_flags & ZMOVE_INCAPACITATED_CHECKS && incapacitated) if(z_move_flags & ZMOVE_FEEDBACK) to_chat(rider || src, span_warning("[rider ? src : "You"] can't do that right now!")) return FALSE diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm index 459410d0a026a..c5f41678732cf 100644 --- a/code/modules/mob/living/living_say.dm +++ b/code/modules/mob/living/living_say.dm @@ -28,6 +28,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( // Misc RADIO_KEY_AI_PRIVATE = RADIO_CHANNEL_AI_PRIVATE, // AI Upload channel + RADIO_KEY_ENTERTAINMENT = RADIO_CHANNEL_ENTERTAINMENT, // Entertainment monitors //kinda localization -- rastaf0 @@ -56,7 +57,8 @@ GLOBAL_LIST_INIT(department_radio_keys, list( "в" = MODE_KEY_DEADMIN, // Misc - "щ" = RADIO_CHANNEL_AI_PRIVATE + "щ" = RADIO_CHANNEL_AI_PRIVATE, + "з" = RADIO_CHANNEL_ENTERTAINMENT, )) /** diff --git a/code/modules/mob/living/living_update_icons.dm b/code/modules/mob/living/living_update_icons.dm index a9e1a136800b0..4e8b809e047f9 100644 --- a/code/modules/mob/living/living_update_icons.dm +++ b/code/modules/mob/living/living_update_icons.dm @@ -58,7 +58,8 @@ if(!changed) //Nothing has been changed, nothing has to be done. return - SEND_SIGNAL(src, COMSIG_PAUSE_FLOATING_ANIM, 0.3 SECONDS) + ADD_TRAIT(src, TRAIT_NO_FLOATING_ANIM, UPDATE_TRANSFORM_TRAIT) + addtimer(TRAIT_CALLBACK_REMOVE(src, TRAIT_NO_FLOATING_ANIM, UPDATE_TRANSFORM_TRAIT), 0.3 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) //if true, we want to avoid any animation time, it'll tween and not rotate at all otherwise. var/is_opposite_angle = SIMPLIFY_DEGREES(lying_angle+180) == lying_prev animate(src, transform = ntransform, time = is_opposite_angle ? 0 : UPDATE_TRANSFORM_ANIMATION_TIME, pixel_y = final_pixel_y, dir = final_dir, easing = (EASE_IN|EASE_OUT)) diff --git a/code/modules/mob/living/navigation.dm b/code/modules/mob/living/navigation.dm index 3096efb3a7c47..a18342c445616 100644 --- a/code/modules/mob/living/navigation.dm +++ b/code/modules/mob/living/navigation.dm @@ -12,7 +12,7 @@ set name = "Navigate" set category = "IC" - if(incapacitated()) + if(incapacitated) return if(length(client.navigation_images)) addtimer(CALLBACK(src, PROC_REF(cut_navigation)), world.tick_lag) @@ -46,7 +46,7 @@ if(isnull(navigate_target)) return - if(incapacitated()) + if(incapacitated) return COOLDOWN_START(src, navigate_cooldown, 15 SECONDS) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 7e0cd4e5ef3e7..a8a49c004cadd 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -288,7 +288,7 @@ /mob/living/silicon/ai/verb/pick_icon() set category = "AI Commands" set name = "Set AI Core Display" - if(incapacitated()) + if(incapacitated) return icon = initial(icon) icon_state = "ai" @@ -306,7 +306,7 @@ view_core() var/ai_core_icon = show_radial_menu(src, src , iconstates, radius = 42) - if(!ai_core_icon || incapacitated()) + if(!ai_core_icon || incapacitated) return display_icon_override = ai_core_icon @@ -347,7 +347,7 @@ var/reason = tgui_input_text(src, "What is the nature of your emergency? ([CALL_SHUTTLE_REASON_LENGTH] characters required.)", "Confirm Shuttle Call") - if(incapacitated()) + if(incapacitated) return if(trim(reason)) @@ -409,7 +409,7 @@ return // stop if(stat == DEAD) return - if(incapacitated()) + if(incapacitated) if(battery < 50) to_chat(src, span_warning("Insufficient backup power!")) return @@ -481,14 +481,14 @@ if(usr != src) return - if(href_list["emergencyAPC"]) //This check comes before incapacitated() because the only time it would be useful is when we have no power. + if(href_list["emergencyAPC"]) //This check comes before incapacitated because the only time it would be useful is when we have no power. if(!apc_override) to_chat(src, span_notice("APC backdoor is no longer available.")) return apc_override.ui_interact(src) return - if(incapacitated()) + if(incapacitated) return if (href_list["switchcamera"]) @@ -638,7 +638,7 @@ ai_tracking_tool.reset_tracking() var/cameralist[0] - if(incapacitated()) + if(incapacitated) return var/mob/living/silicon/ai/U = usr @@ -680,7 +680,7 @@ set desc = "Change the default hologram available to AI to something else." set category = "AI Commands" - if(incapacitated()) + if(incapacitated) return var/input switch(tgui_input_list(usr, "Would you like to select a hologram based on a custom character, an animal, or switch to a unique avatar?", "Customize", list("Custom Character","Unique","Animal"))) @@ -830,7 +830,7 @@ set desc = "Allows you to change settings of your radio." set category = "AI Commands" - if(incapacitated()) + if(incapacitated) return to_chat(src, "Accessing Subspace Transceiver control...") @@ -846,7 +846,7 @@ set desc = "Modify the default radio setting for your automatic announcements." set category = "AI Commands" - if(incapacitated()) + if(incapacitated) return set_autosay() @@ -1046,7 +1046,7 @@ set category = "AI Commands" set name = "Deploy to Shell" - if(incapacitated()) + if(incapacitated) return if(control_disabled) to_chat(src, span_warning("Wireless networking module is offline.")) diff --git a/code/modules/mob/living/silicon/ai/ai_defense.dm b/code/modules/mob/living/silicon/ai/ai_defense.dm index 0c5eb6ec164b2..55a00a6ffc0bc 100644 --- a/code/modules/mob/living/silicon/ai/ai_defense.dm +++ b/code/modules/mob/living/silicon/ai/ai_defense.dm @@ -63,7 +63,7 @@ . = ..() if(user.combat_mode) return - if(stat != DEAD && !incapacitated() && (client || deployed_shell?.client)) + if(stat != DEAD && !incapacitated && (client || deployed_shell?.client)) // alive and well AIs control their floor bolts balloon_alert(user, "the AI's bolt motors resist.") return ITEM_INTERACT_SUCCESS diff --git a/code/modules/mob/living/silicon/ai/ai_say.dm b/code/modules/mob/living/silicon/ai/ai_say.dm index 48b3cdc437350..a71074f9a014c 100644 --- a/code/modules/mob/living/silicon/ai/ai_say.dm +++ b/code/modules/mob/living/silicon/ai/ai_say.dm @@ -18,12 +18,23 @@ return ..() /mob/living/silicon/ai/radio(message, list/message_mods = list(), list/spans, language) - if(incapacitated()) + if(incapacitated) return FALSE if(!radio_enabled) //AI cannot speak if radio is disabled (via intellicard) or depowered. to_chat(src, span_danger("Your radio transmitter is offline!")) return FALSE - ..() + . = ..() + if(.) + return . + if(message_mods[MODE_HEADSET]) + if(radio) + radio.talk_into(src, message, , spans, language, message_mods) + return NOPASS + else if(message_mods[RADIO_EXTENSION] in GLOB.radiochannels) + if(radio) + radio.talk_into(src, message, message_mods[RADIO_EXTENSION], spans, language, message_mods) + return NOPASS + return FALSE //For holopads only. Usable by AI. /mob/living/silicon/ai/proc/holopad_talk(message, language) @@ -56,7 +67,7 @@ set desc = "Display a list of vocal words to announce to the crew." set category = "AI Commands" - if(incapacitated()) + if(incapacitated) return var/dat = {" @@ -95,7 +106,7 @@ last_announcement = message - if(incapacitated()) + if(incapacitated) return if(control_disabled) diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm index 98a2e629776b1..32382b663398b 100644 --- a/code/modules/mob/living/silicon/ai/freelook/eye.dm +++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm @@ -235,7 +235,7 @@ set category = "AI Commands" set name = "Toggle Camera Acceleration" - if(incapacitated()) + if(incapacitated) return acceleration = !acceleration to_chat(usr, "Camera acceleration has been toggled [acceleration ? "on" : "off"].") diff --git a/code/modules/mob/living/silicon/ai/robot_control.dm b/code/modules/mob/living/silicon/ai/robot_control.dm index d963fc77be62f..a04d1c3af75c4 100644 --- a/code/modules/mob/living/silicon/ai/robot_control.dm +++ b/code/modules/mob/living/silicon/ai/robot_control.dm @@ -7,7 +7,7 @@ owner = new_owner /datum/robot_control/proc/is_interactable(mob/user) - if(user != owner || owner.incapacitated()) + if(user != owner || owner.incapacitated) return FALSE if(owner.control_disabled) to_chat(user, span_warning("Wireless control is disabled.")) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 4871370d16c3d..2f670c5fbe21b 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -389,7 +389,7 @@ return ..() /mob/living/silicon/robot/execute_mode() - if(incapacitated()) + if(incapacitated) return var/obj/item/W = get_active_held_item() if(W) @@ -504,14 +504,19 @@ lampButton?.update_appearance() update_icons() +///Completely deconstructs the borg, dropping the MMI/posibrain, removing applied upgrades and stripping the exoskeleton of all limbs, +///while also burning out the flashes and prying out the cabling and the cell used in construction /mob/living/silicon/robot/proc/cyborg_deconstruct() SEND_SIGNAL(src, COMSIG_BORG_SAFE_DECONSTRUCT) if(shell) undeploy() var/turf/drop_to = drop_location() - if (robot_suit) + //remove installed upgrades + for(var/obj/item/borg/upgrade/upgrade_to_remove in upgrades) + upgrade_to_remove.forceMove(drop_to) + if(robot_suit) robot_suit.drop_all_parts(drop_to) - + robot_suit.forceMove(drop_to) else new /obj/item/robot_suit(drop_to) new /obj/item/bodypart/leg/left/robot(drop_to) @@ -874,7 +879,7 @@ lawupdate = TRUE lawsync() if(radio && AI.radio) //AI keeps all channels, including Syndie if it is a Traitor - if(AI.radio.syndie) + if((AI.radio.special_channels & RADIO_SPECIAL_SYNDIE)) radio.make_syndie() radio.subspace_transmission = TRUE radio.channels = AI.radio.channels @@ -936,7 +941,7 @@ M.visible_message(span_warning("[M] really can't seem to mount [src]...")) return - if(stat || incapacitated()) + if(stat || incapacitated) return if(model && !model.allow_riding) M.visible_message(span_boldwarning("Unfortunately, [M] just can't seem to hold onto [src]!")) diff --git a/code/modules/mob/living/silicon/robot/robot_model.dm b/code/modules/mob/living/silicon/robot/robot_model.dm index 015f23182dca3..7aabdafaa4825 100644 --- a/code/modules/mob/living/silicon/robot/robot_model.dm +++ b/code/modules/mob/living/silicon/robot/robot_model.dm @@ -327,7 +327,7 @@ /obj/item/robot_model/proc/check_menu(mob/living/silicon/robot/user, obj/item/robot_model/old_model) if(!istype(user)) return FALSE - if(user.incapacitated()) + if(user.incapacitated) return FALSE if(user.model != old_model) return FALSE diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index e41cd2157080f..5dc69f49df148 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -400,7 +400,7 @@ silicon_hud.show_to(src) /mob/living/silicon/proc/toggle_sensors() - if(incapacitated()) + if(incapacitated) return sensors_on = !sensors_on if (!sensors_on) diff --git a/code/modules/mob/living/silicon/silicon_say.dm b/code/modules/mob/living/silicon/silicon_say.dm index 9310211aa0e6d..824bba98dc070 100644 --- a/code/modules/mob/living/silicon/silicon_say.dm +++ b/code/modules/mob/living/silicon/silicon_say.dm @@ -82,10 +82,10 @@ if(message_mods[MODE_HEADSET]) if(radio) radio.talk_into(src, message, , spans, language, message_mods) - return REDUCE_RANGE + return NOPASS else if(message_mods[RADIO_EXTENSION] in GLOB.radiochannels) if(radio) radio.talk_into(src, message, message_mods[RADIO_EXTENSION], spans, language, message_mods) - return ITALICS | REDUCE_RANGE + return NOPASS return FALSE diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index e2bb112e1565e..f48d542ba191d 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -378,9 +378,9 @@ if(HAS_TRAIT(src, TRAIT_COMMISSIONED) && COOLDOWN_FINISHED(src, next_salute_check)) COOLDOWN_START(src, next_salute_check, BOT_COMMISSIONED_SALUTE_DELAY) - for(var/mob/living/simple_animal/bot/B in view(5, src)) - if(!HAS_TRAIT(B, TRAIT_COMMISSIONED) && B.bot_mode_flags & BOT_MODE_ON) - manual_emote("performs an elaborate salute for [src]!") + for(var/mob/living/simple_animal/bot/nearby_bot in view(5, src)) + if(!HAS_TRAIT(nearby_bot, TRAIT_COMMISSIONED) && nearby_bot.bot_mode_flags & BOT_MODE_ON) + manual_emote("performs an elaborate salute for [nearby_bot]!") break switch(mode) //High-priority overrides are processed first. Bots can do nothing else while under direct command. diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index 6c0cd6d16ab55..bbd45e12a2733 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -42,7 +42,7 @@ var/list/targets = list() for(var/mob/living/carbon/nearby_carbon in view(7, src)) //Let's find us a target var/threatlevel = 0 - if(nearby_carbon.incapacitated()) + if(nearby_carbon.incapacitated) continue threatlevel = nearby_carbon.assess_threat(judgement_criteria) if(threatlevel < THREAT_ASSESS_DANGEROUS) diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index f3194e88b1862..6c867448d4d68 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -711,7 +711,7 @@ // player on mulebot attempted to move /mob/living/simple_animal/bot/mulebot/relaymove(mob/living/user, direction) - if(user.incapacitated()) + if(user.incapacitated) return if(load == user) unload(0) @@ -805,7 +805,7 @@ /mob/living/simple_animal/bot/mulebot/paranormal/mouse_drop_receive(atom/movable/AM, mob/user, params) var/mob/living/L = user - if(user.incapacitated() || (istype(L) && L.body_position == LYING_DOWN)) + if(user.incapacitated || (istype(L) && L.body_position == LYING_DOWN)) return if(!istype(AM) || iscameramob(AM) || istype(AM, /obj/effect/dummy/phased_mob)) //allows ghosts! diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 507563e7c207c..0803d96a706b9 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -320,7 +320,7 @@ /mob/living/simple_animal/hostile/proc/CheckAndAttack() var/atom/target_from = GET_TARGETS_FROM(src) - if(target && isturf(target_from.loc) && target.Adjacent(target_from) && !incapacitated()) + if(target && isturf(target_from.loc) && target.Adjacent(target_from) && !incapacitated) AttackingTarget(target) /mob/living/simple_animal/hostile/proc/MoveToTarget(list/possible_targets)//Step 5, handle movement between us and our target diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm index 31d2e62fba7dc..231977a323954 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm @@ -64,7 +64,7 @@ if(gps_name && true_spawn) AddComponent(/datum/component/gps, gps_name) ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT) - add_traits(list(TRAIT_NO_TELEPORT, TRAIT_MARTIAL_ARTS_IMMUNE), MEGAFAUNA_TRAIT) + add_traits(list(TRAIT_NO_TELEPORT), MEGAFAUNA_TRAIT) grant_actions_by_list(attack_action_types) /mob/living/simple_animal/hostile/megafauna/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm index 193545d9985fa..935ed7a7215b0 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm @@ -27,7 +27,7 @@ Difficulty: Medium icon_living = "miner" icon = 'icons/mob/simple/broadMobs.dmi' health_doll_icon = "miner" - mob_biotypes = MOB_ORGANIC|MOB_HUMANOID + mob_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_SPECIAL light_color = COLOR_LIGHT_GRAYISH_RED speak_emote = list("roars") speed = 3 diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm index 2af3018bed306..448896e3700de 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm @@ -18,7 +18,7 @@ Difficulty: Extremely Hard attack_verb_continuous = "pummels" attack_verb_simple = "pummels" attack_sound = 'sound/weapons/sonic_jackhammer.ogg' - mob_biotypes = MOB_ORGANIC|MOB_HUMANOID + mob_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_SPECIAL light_color = COLOR_LIGHT_GRAYISH_RED movement_type = GROUND weather_immunities = list(TRAIT_SNOWSTORM_IMMUNE) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 25d0e566b15dd..9d5041fe870a4 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -495,7 +495,7 @@ //ANIMAL RIDING /mob/living/simple_animal/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE) - if(user.incapacitated()) + if(user.incapacitated) return for(var/atom/movable/A in get_turf(src)) if(A != src && A != M && A.density) @@ -521,7 +521,7 @@ return /mob/living/simple_animal/relaymove(mob/living/user, direction) - if(user.incapacitated()) + if(user.incapacitated) return return relaydrive(user, direction) diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index d017a2acca1be..17e929ba42290 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -91,11 +91,9 @@ sync_mind() //Reload alternate appearances - for(var/v in GLOB.active_alternate_appearances) - if(!v) - continue - var/datum/atom_hud/alternate_appearance/AA = v - AA.onNewMob(src) + for(var/datum/atom_hud/alternate_appearance/alt_hud as anything in GLOB.active_alternate_appearances) + if(!alt_hud.apply_to_new_mob(src)) + alt_hud.hide_from(src, absolute = TRUE) update_client_colour() update_mouse_pointer() diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index c90c81b6ce43d..f321a8396a379 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -83,13 +83,12 @@ add_to_dead_mob_list() else add_to_alive_mob_list() + update_incapacitated() set_focus(src) prepare_huds() - for(var/v in GLOB.active_alternate_appearances) - if(!v) - continue - var/datum/atom_hud/alternate_appearance/AA = v - AA.onNewMob(src) + for(var/datum/atom_hud/alternate_appearance/alt_hud as anything in GLOB.active_alternate_appearances) + alt_hud.apply_to_new_mob(src) + set_nutrition(rand(NUTRITION_LEVEL_START_MIN, NUTRITION_LEVEL_START_MAX)) . = ..() setup_hud_traits() @@ -414,9 +413,21 @@ return null -///Is the mob incapacitated -/mob/proc/incapacitated(flags) - return +/// Called whenever anything that modifes incapacitated is ran, updates it and sends a signal if it changes +/// Returns TRUE if anything changed, FALSE otherwise +/mob/proc/update_incapacitated() + SIGNAL_HANDLER + var/old_incap = incapacitated + incapacitated = build_incapacitated() + if(old_incap == incapacitated) + return FALSE + + SEND_SIGNAL(src, COMSIG_MOB_INCAPACITATE_CHANGED, old_incap, incapacitated) + return TRUE + +/// Returns an updated incapacitated bitflag. If a flag is set it means we're incapacitated in that case +/mob/proc/build_incapacitated() + return NONE /** * This proc is called whenever someone clicks an inventory ui slot. @@ -543,7 +554,7 @@ /mob/living/blind_examine_check(atom/examined_thing) //need to be next to something and awake - if(!Adjacent(examined_thing) || incapacitated()) + if(!Adjacent(examined_thing) || incapacitated) to_chat(src, span_warning("Something is there, but you can't see it!")) return FALSE @@ -702,7 +713,7 @@ if(ismecha(loc)) return - if(incapacitated()) + if(incapacitated) return var/obj/item/I = get_active_held_item() diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 2206efd0e13ce..7f439db6bc9ac 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -66,6 +66,20 @@ /// Whether a mob is alive or dead. TODO: Move this to living - Nodrak (2019, still here) var/stat = CONSCIOUS + /** + * Whether and how a mob is incapacitated + * + * Normally being restrained, agressively grabbed, or in stasis counts as incapacitated + * unless there is a flag being used to check if it's ignored + * + * * bitflags: (see code/__DEFINES/status_effects.dm) + * * INCAPABLE_RESTRAINTS - if our mob is in a restraint (handcuffs) + * * INCAPABLE_STASIS - if our mob is in stasis (stasis bed, etc.) + * * INCAPABLE_GRAB - if our mob is being agressively grabbed + * + **/ + VAR_FINAL/incapacitated = NONE + /* A bunch of this stuff really needs to go under their own defines instead of being globally attached to mob. A variable should only be globally attached to turfs/objects/whatever, when it is in fact needed as such. The current method unnecessarily clusters up the variable list, especially for humans (although rearranging won't really clean it up a lot but the difference will be noticable for other mobs). diff --git a/code/modules/mob_spawn/corpses/mob_corpses.dm b/code/modules/mob_spawn/corpses/mob_corpses.dm index f83dc13f1eded..c6d0cbd55cf4c 100644 --- a/code/modules/mob_spawn/corpses/mob_corpses.dm +++ b/code/modules/mob_spawn/corpses/mob_corpses.dm @@ -162,6 +162,16 @@ head = /obj/item/clothing/head/helmet/space/pirate back = /obj/item/tank/jetpack/carbondioxide +/obj/effect/mob_spawn/corpse/human/old_pirate_captain + name = "Pirate Captain Skeleton" + outfit = /datum/outfit/piratecorpse/captain + mob_species = /datum/species/skeleton + +/datum/outfit/piratecorpse/captain + glasses = /obj/item/clothing/glasses/eyepatch + head = /obj/item/clothing/head/costume/pirate + suit = /obj/item/clothing/suit/costume/pirate + /obj/effect/mob_spawn/corpse/human/russian name = "Russian" outfit = /datum/outfit/russiancorpse diff --git a/code/modules/mob_spawn/ghost_roles/space_roles.dm b/code/modules/mob_spawn/ghost_roles/space_roles.dm index 79d028bdbcb27..528aea46b8690 100644 --- a/code/modules/mob_spawn/ghost_roles/space_roles.dm +++ b/code/modules/mob_spawn/ghost_roles/space_roles.dm @@ -160,6 +160,8 @@ l_pocket = /obj/item/uplink/nuclear r_pocket = /obj/item/modular_computer/pda/nukeops + skillchips = list(/obj/item/skillchip/disk_verifier) + /obj/effect/mob_spawn/ghost_role/human/syndicate/battlecruiser/captain name = "Syndicate Battlecruiser Captain" you_are_text = "You are the captain aboard the syndicate flagship: the SBC Starfury." @@ -184,3 +186,8 @@ mask = /obj/item/cigarette/cigar/havana l_pocket = /obj/item/melee/energy/sword/saber/red r_pocket = /obj/item/melee/baton/telescopic + + skillchips = list( + /obj/item/skillchip/disk_verifier, + /obj/item/skillchip/big_pointer, + ) diff --git a/code/modules/mod/mod_activation.dm b/code/modules/mod/mod_activation.dm index 237e151bcb2c0..8c4de3be84d84 100644 --- a/code/modules/mod/mod_activation.dm +++ b/code/modules/mod/mod_activation.dm @@ -17,8 +17,8 @@ if(!pick) return var/part_reference = display_names[pick] - var/obj/item/part = locate(part_reference) in parts - if(!istype(part) || user.incapacitated()) + var/obj/item/part = locate(part_reference) in get_parts() + if(!istype(part) || user.incapacitated) return if(active || activating) balloon_alert(user, "deactivate the suit first!") diff --git a/code/modules/mod/mod_control.dm b/code/modules/mod/mod_control.dm index cf91aaf482c22..cbd299e8b58b0 100644 --- a/code/modules/mod/mod_control.dm +++ b/code/modules/mod/mod_control.dm @@ -233,7 +233,7 @@ balloon_alert(wearer, "retract parts first!") playsound(src, 'sound/machines/scanbuzz.ogg', 25, FALSE, SILENCED_SOUND_EXTRARANGE) return - if(!wearer.incapacitated()) + if(!wearer.incapacitated) var/atom/movable/screen/inventory/hand/ui_hand = over_object if(wearer.putItemFromInventoryInHandIfPossible(src, ui_hand.held_index)) add_fingerprint(user) @@ -572,6 +572,11 @@ balloon_alert(user, "[new_module] incompatible with [src]'s parts!") playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) return + if(!new_module.can_install(src)) + if(user) + balloon_alert(user, "[new_module] cannot be installed into [src]!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return new_module.forceMove(src) modules += new_module complexity += new_module.complexity diff --git a/code/modules/mod/mod_paint.dm b/code/modules/mod/mod_paint.dm index 7897b60b794a7..6896ac3c15fcc 100644 --- a/code/modules/mod/mod_paint.dm +++ b/code/modules/mod/mod_paint.dm @@ -126,7 +126,7 @@ mod.theme.set_skin(mod, pick) /obj/item/mod/paint/proc/check_menu(obj/item/mod/control/mod, mob/user) - if(user.incapacitated() || !user.is_holding(src) || !mod || mod.active || mod.activating) + if(user.incapacitated || !user.is_holding(src) || !mod || mod.active || mod.activating) return FALSE return TRUE diff --git a/code/modules/mod/mod_theme.dm b/code/modules/mod/mod_theme.dm index 230f53e9403be..0fe69b77f0171 100644 --- a/code/modules/mod/mod_theme.dm +++ b/code/modules/mod/mod_theme.dm @@ -199,6 +199,8 @@ UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, SEALED_MESSAGE = HELMET_SEAL_MESSAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEEYES|HIDEHAIR|HIDESNOUT, + SEALED_COVER = HEADCOVERSEYES, ), /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm index db9d150f3438a..b20efa4c66641 100644 --- a/code/modules/mod/mod_types.dm +++ b/code/modules/mod/mod_types.dm @@ -493,7 +493,7 @@ /obj/item/mod/control/pre_equipped/responsory/janitor insignia_type = /obj/item/mod/module/insignia/janitor - additional_module = /obj/item/mod/module/clamp + additional_module = /obj/item/mod/module/noslip /obj/item/mod/control/pre_equipped/responsory/clown insignia_type = /obj/item/mod/module/insignia/clown diff --git a/code/modules/mod/modules/_module.dm b/code/modules/mod/modules/_module.dm index 4bd4ef0d2ab80..551145b5e6d3a 100644 --- a/code/modules/mod/modules/_module.dm +++ b/code/modules/mod/modules/_module.dm @@ -94,6 +94,10 @@ needed_slots -= needed_slot return !length(needed_slots) +/// Additional checks for whenever a module can be installed into a suit or not +/obj/item/mod/module/proc/can_install(obj/item/mod/control/mod) + return TRUE + /// Called when the module is selected from the TGUI, radial or the action button /obj/item/mod/module/proc/on_select() if(!mod.wearer) @@ -200,7 +204,7 @@ /// Called when an activated module without a device is used /obj/item/mod/module/proc/on_select_use(atom/target) - if(!(allow_flags & MODULE_ALLOW_INCAPACITATED) && mod.wearer.incapacitated(IGNORE_GRAB)) + if(!(allow_flags & MODULE_ALLOW_INCAPACITATED) && INCAPACITATED_IGNORING(mod.wearer, INCAPABLE_GRAB)) return FALSE mod.wearer.face_atom(target) if(!used()) diff --git a/code/modules/mod/modules/module_kinesis.dm b/code/modules/mod/modules/module_kinesis.dm index 9048701f1d017..374be840d9507 100644 --- a/code/modules/mod/modules/module_kinesis.dm +++ b/code/modules/mod/modules/module_kinesis.dm @@ -67,7 +67,7 @@ clear_grab(playsound = !deleting) /obj/item/mod/module/anomaly_locked/kinesis/process(seconds_per_tick) - if(!mod.wearer.client || mod.wearer.incapacitated(IGNORE_GRAB)) + if(!mod.wearer.client || INCAPACITATED_IGNORING(mod.wearer, INCAPABLE_GRAB)) clear_grab() return if(!range_check(grabbed_atom)) diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm index 2ab0b0a1fd269..ae7f916d1beed 100644 --- a/code/modules/mod/modules/modules_general.dm +++ b/code/modules/mod/modules/modules_general.dm @@ -310,6 +310,15 @@ mask.flags_cover &= ~(MASKCOVERSMOUTH |PEPPERPROOF) mask.visor_flags_cover &= ~(MASKCOVERSMOUTH |PEPPERPROOF) +/obj/item/mod/module/mouthhole/can_install(obj/item/mod/control/mod) + var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) + var/obj/item/clothing/mask = mod.get_part_from_slot(ITEM_SLOT_MASK) + if(istype(helmet) && ((helmet.flags_cover|helmet.visor_flags_cover) & (HEADCOVERSMOUTH|PEPPERPROOF))) + return ..() + if(istype(mask) && ((mask.flags_cover|mask.visor_flags_cover) & (MASKCOVERSMOUTH|PEPPERPROOF))) + return ..() + return FALSE + /obj/item/mod/module/mouthhole/on_uninstall(deleting = FALSE) if(deleting) return diff --git a/code/modules/mod/modules/modules_medical.dm b/code/modules/mod/modules/modules_medical.dm index 8a1d31a92f6b0..0f44570201776 100644 --- a/code/modules/mod/modules/modules_medical.dm +++ b/code/modules/mod/modules/modules_medical.dm @@ -428,3 +428,22 @@ /datum/surgery/advanced/bioware/cortex_folding, /datum/surgery/advanced/bioware/cortex_folding/mechanic, ) + +/obj/item/mod/module/surgical_processor/emergency + desc = "A module using an onboard surgical computer which can be connected to other computers to download and \ + perform advanced surgeries on the go. This one came pre-loaded with some emergency surgeries." + device = /obj/item/surgical_processor/mod/emergency + +/obj/item/surgical_processor/mod/emergency + loaded_surgeries = list( + /datum/surgery/healing/combo/upgraded/femto, + /datum/surgery/blood_filter, + /datum/surgery/brain_surgery, + /datum/surgery/coronary_bypass, + /datum/surgery/ear_surgery, + /datum/surgery/eye_surgery, + /datum/surgery/hepatectomy, + /datum/surgery/revival, + /datum/surgery/stomach_pump, + /datum/surgery/advanced/wing_reconstruction, + ) diff --git a/code/modules/mod/modules/modules_security.dm b/code/modules/mod/modules/modules_security.dm index 752273fa0748c..5da8ff00241c9 100644 --- a/code/modules/mod/modules/modules_security.dm +++ b/code/modules/mod/modules/modules_security.dm @@ -568,7 +568,7 @@ projectile.ricochets_max += 1 projectile.min_ricochets += 1 projectile.ricochet_incidence_leeway = 0 //allows the projectile to bounce at any angle. - ADD_TRAIT(projectile, TRAIT_ALWAYS_HIT_ZONE, MOD_TRAIT) + projectile.accuracy_falloff = 0 #undef SHOOTING_ASSISTANT_OFF #undef STORMTROOPER_MODE diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm index 08bd61945ef47..03503ac36d864 100644 --- a/code/modules/modular_computers/computers/item/computer.dm +++ b/code/modules/modular_computers/computers/item/computer.dm @@ -727,6 +727,8 @@ UpdateDisplay() /obj/item/modular_computer/ui_action_click(mob/user, actiontype) + if(!issilicon(user)) + playsound(src, SFX_KEYBOARD_CLICKS, 10, TRUE, FALSE) if(istype(actiontype, /datum/action/item_action/toggle_computer_light)) toggle_flashlight(user) return diff --git a/code/modules/modular_computers/computers/item/disks/role_disks.dm b/code/modules/modular_computers/computers/item/disks/role_disks.dm index f7f20efb70b43..2191aaccdff1d 100644 --- a/code/modules/modular_computers/computers/item/disks/role_disks.dm +++ b/code/modules/modular_computers/computers/item/disks/role_disks.dm @@ -6,7 +6,6 @@ max_capacity = 32 ///Static list of programss ALL command tablets have. var/static/list/datum/computer_file/command_programs = list( - /datum/computer_file/program/crew_manifest, /datum/computer_file/program/science, /datum/computer_file/program/status, ) @@ -74,7 +73,6 @@ icon_state = "datadisk9" starting_programs = list( /datum/computer_file/program/records/security, - /datum/computer_file/program/crew_manifest, ) /** diff --git a/code/modules/modular_computers/computers/item/disks/unique_disks.dm b/code/modules/modular_computers/computers/item/disks/unique_disks.dm index 1fd31957befca..a5e9d9750f3ea 100644 --- a/code/modules/modular_computers/computers/item/disks/unique_disks.dm +++ b/code/modules/modular_computers/computers/item/disks/unique_disks.dm @@ -23,7 +23,6 @@ /datum/computer_file/program/supermatter_monitor, /datum/computer_file/program/newscaster, /datum/computer_file/program/secureye, - /datum/computer_file/program/crew_manifest, /datum/computer_file/program/status, ) potential_programs += subtypesof(/datum/computer_file/program/maintenance) - /datum/computer_file/program/maintenance/theme diff --git a/code/modules/modular_computers/computers/item/pda.dm b/code/modules/modular_computers/computers/item/pda.dm index b40ae45f27f91..0c41f2e80655f 100644 --- a/code/modules/modular_computers/computers/item/pda.dm +++ b/code/modules/modular_computers/computers/item/pda.dm @@ -38,6 +38,7 @@ /datum/computer_file/program/messenger, /datum/computer_file/program/nt_pay, /datum/computer_file/program/notepad, + /datum/computer_file/program/crew_manifest, ) ///List of items that can be stored in a PDA var/static/list/contained_item = list( diff --git a/code/modules/modular_computers/computers/item/role_tablet_presets.dm b/code/modules/modular_computers/computers/item/role_tablet_presets.dm index 7e4c7402c770b..02cdff752f4d5 100644 --- a/code/modules/modular_computers/computers/item/role_tablet_presets.dm +++ b/code/modules/modular_computers/computers/item/role_tablet_presets.dm @@ -6,8 +6,7 @@ greyscale_config = /datum/greyscale_config/tablet/head greyscale_colors = "#67A364#a92323" max_capacity = parent_type::max_capacity * 2 - starting_programs = list( - /datum/computer_file/program/crew_manifest, + var/static/list/datum/computer_file/head_programs = list( /datum/computer_file/program/status, /datum/computer_file/program/science, /datum/computer_file/program/robocontrol, @@ -129,7 +128,6 @@ inserted_item = /obj/item/pen/red/security starting_programs = list( /datum/computer_file/program/records/security, - /datum/computer_file/program/crew_manifest, /datum/computer_file/program/robocontrol, ) @@ -139,7 +137,6 @@ inserted_item = /obj/item/pen/red/security starting_programs = list( /datum/computer_file/program/records/security, - /datum/computer_file/program/crew_manifest, /datum/computer_file/program/robocontrol, ) @@ -150,7 +147,6 @@ inserted_item = /obj/item/pen/red/security starting_programs = list( /datum/computer_file/program/records/security, - /datum/computer_file/program/crew_manifest, /datum/computer_file/program/robocontrol, ) @@ -244,7 +240,6 @@ greyscale_colors = "#FAFAFA#000099#1f2026" starting_programs = list( /datum/computer_file/program/records/medical, - /datum/computer_file/program/crew_manifest, ) /** @@ -405,7 +400,6 @@ greyscale_colors = "#333333#000099#3F96CC" starting_programs = list( /datum/computer_file/program/records/medical, - /datum/computer_file/program/crew_manifest, /datum/computer_file/program/robocontrol, ) @@ -422,7 +416,6 @@ name = "bridge assistant PDA" greyscale_colors = "#374f7e#a92323" starting_programs = list( - /datum/computer_file/program/crew_manifest, /datum/computer_file/program/status, ) @@ -432,7 +425,6 @@ inserted_item = /obj/item/pen/fountain starting_programs = list( /datum/computer_file/program/records/security, - /datum/computer_file/program/crew_manifest, /datum/computer_file/program/coupon, //veteran discount /datum/computer_file/program/skill_tracker, ) diff --git a/code/modules/modular_computers/file_system/programs/crewmanifest.dm b/code/modules/modular_computers/file_system/programs/crewmanifest.dm index 39a9d8c3c7fe5..d0dcf0ae873fe 100644 --- a/code/modules/modular_computers/file_system/programs/crewmanifest.dm +++ b/code/modules/modular_computers/file_system/programs/crewmanifest.dm @@ -1,15 +1,13 @@ /datum/computer_file/program/crew_manifest filename = "plexagoncrew" filedesc = "Plexagon Crew List" - downloader_category = PROGRAM_CATEGORY_SECURITY + downloader_category = PROGRAM_CATEGORY_DEVICE program_open_overlay = "id" extended_desc = "Program for viewing and printing the current crew manifest" - download_access = list(ACCESS_SECURITY, ACCESS_COMMAND) program_flags = PROGRAM_ON_NTNET_STORE | PROGRAM_REQUIRES_NTNET - size = 4 + size = 0 tgui_id = "NtosCrewManifest" program_icon = "clipboard-list" - detomatix_resistance = DETOMATIX_RESIST_MAJOR /datum/computer_file/program/crew_manifest/ui_static_data(mob/user) var/list/data = list() diff --git a/code/modules/modular_computers/file_system/programs/records.dm b/code/modules/modular_computers/file_system/programs/records.dm index 063c19d35e18b..fbd0b9edabd66 100644 --- a/code/modules/modular_computers/file_system/programs/records.dm +++ b/code/modules/modular_computers/file_system/programs/records.dm @@ -29,6 +29,7 @@ download_access = list(ACCESS_SECURITY, ACCESS_FLAG_COMMAND) program_flags = PROGRAM_ON_NTNET_STORE mode = "security" + detomatix_resistance = DETOMATIX_RESIST_MINOR /datum/computer_file/program/records/proc/GetRecordsReadable() var/list/all_records = list() diff --git a/code/modules/modular_computers/file_system/programs/statusdisplay.dm b/code/modules/modular_computers/file_system/programs/statusdisplay.dm index fa844215b93b9..a57940d99c1fa 100644 --- a/code/modules/modular_computers/file_system/programs/statusdisplay.dm +++ b/code/modules/modular_computers/file_system/programs/statusdisplay.dm @@ -11,6 +11,7 @@ can_run_on_flags = PROGRAM_ALL program_flags = PROGRAM_REQUIRES_NTNET + detomatix_resistance = DETOMATIX_RESIST_MAJOR var/upper_text = "" var/lower_text = "" diff --git a/code/modules/modular_computers/file_system/programs/virtual_pet.dm b/code/modules/modular_computers/file_system/programs/virtual_pet.dm index 78a9148b013fe..8f1eef074d46a 100644 --- a/code/modules/modular_computers/file_system/programs/virtual_pet.dm +++ b/code/modules/modular_computers/file_system/programs/virtual_pet.dm @@ -429,7 +429,7 @@ GLOBAL_LIST_EMPTY(virtual_pets_list) var/static/list/possible_emotes = list( /datum/emote/flip, - /datum/emote/living/jump, + /datum/emote/jump, /datum/emote/living/shiver, /datum/emote/spin, /datum/emote/silicon/beep, diff --git a/code/modules/pai/hud.dm b/code/modules/pai/hud.dm index b104c7b90eab4..77bcafefc82d2 100644 --- a/code/modules/pai/hud.dm +++ b/code/modules/pai/hud.dm @@ -5,7 +5,7 @@ var/required_software /atom/movable/screen/pai/Click() - if(isobserver(usr) || usr.incapacitated()) + if(isobserver(usr) || usr.incapacitated) return FALSE var/mob/living/silicon/pai/user = usr if(required_software && !user.installed_software.Find(required_software)) diff --git a/code/modules/pai/say.dm b/code/modules/pai/say.dm index b35abfe7f9d80..c7ed1a566d883 100644 --- a/code/modules/pai/say.dm +++ b/code/modules/pai/say.dm @@ -1,2 +1,2 @@ /mob/living/silicon/pai/binarycheck() - return radio?.translate_binary + return (radio?.special_channels & RADIO_SPECIAL_BINARY) diff --git a/code/modules/pai/shell.dm b/code/modules/pai/shell.dm index 2ef3cf3d8e2dd..6a8a8e709c82b 100644 --- a/code/modules/pai/shell.dm +++ b/code/modules/pai/shell.dm @@ -30,7 +30,7 @@ * FALSE otherwise. */ /mob/living/silicon/pai/proc/check_menu(atom/anchor) - if(incapacitated()) + if(incapacitated) return FALSE if(get_turf(src) != get_turf(anchor)) return FALSE diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index fe2de7e752030..b0eba4d9396b4 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -306,7 +306,7 @@ set category = "Object" set src in usr - if(!usr.can_read(src) || usr.is_blind() || usr.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB) || (isobserver(usr) && !isAdminGhostAI(usr))) + if(!usr.can_read(src) || usr.is_blind() || INCAPACITATED_IGNORING(usr, INCAPABLE_RESTRAINTS|INCAPABLE_GRAB) || (isobserver(usr) && !isAdminGhostAI(usr))) return if(ishuman(usr)) var/mob/living/carbon/human/H = usr @@ -351,7 +351,7 @@ return UI_UPDATE if(!in_range(user, src) && !isobserver(user)) return UI_CLOSE - if(user.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB) || (isobserver(user) && !isAdminGhostAI(user))) + if(INCAPACITATED_IGNORING(user, INCAPABLE_RESTRAINTS|INCAPABLE_GRAB) || (isobserver(user) && !isAdminGhostAI(user))) return UI_UPDATE // Even harder to read if your blind...braile? humm // .. or if you cannot read diff --git a/code/modules/photography/camera/silicon_camera.dm b/code/modules/photography/camera/silicon_camera.dm index 9cdbee1bc2b7a..a8bf7a3ba90e7 100644 --- a/code/modules/photography/camera/silicon_camera.dm +++ b/code/modules/photography/camera/silicon_camera.dm @@ -7,7 +7,7 @@ /// Checks if we can take a picture at this moment. Returns TRUE if we can, FALSE if we can't. /obj/item/camera/siliconcam/proc/can_take_picture(mob/living/silicon/clicker) - if(clicker.stat != CONSCIOUS || clicker.incapacitated()) + if(clicker.stat != CONSCIOUS || clicker.incapacitated) return FALSE return TRUE diff --git a/code/modules/photography/photos/photo.dm b/code/modules/photography/photos/photo.dm index b009c5b2e7913..fa1d28eba9d79 100644 --- a/code/modules/photography/photos/photo.dm +++ b/code/modules/photography/photos/photo.dm @@ -104,7 +104,7 @@ var/n_name = tgui_input_text(usr, "What would you like to label the photo?", "Photo Labelling", max_length = MAX_NAME_LEN) //loc.loc check is for making possible renaming photos in clipboards - if(n_name && (loc == usr || loc.loc && loc.loc == usr) && usr.stat == CONSCIOUS && !usr.incapacitated()) + if(n_name && (loc == usr || loc.loc && loc.loc == usr) && usr.stat == CONSCIOUS && !usr.incapacitated) name = "photo[(n_name ? "- '[n_name]'" : null)]" add_fingerprint(usr) diff --git a/code/modules/point/point.dm b/code/modules/point/point.dm index 6e61b1154d59c..681fbce2c6bac 100644 --- a/code/modules/point/point.dm +++ b/code/modules/point/point.dm @@ -7,22 +7,30 @@ * * Not intended as a replacement for the mob verb */ -/atom/movable/proc/point_at(atom/pointed_atom) +/atom/movable/proc/point_at(atom/pointed_atom, intentional = FALSE) if(!isturf(loc)) - return + return FALSE if (pointed_atom in src) create_point_bubble(pointed_atom) - return + return FALSE var/turf/tile = get_turf(pointed_atom) if (!tile) - return + return FALSE var/turf/our_tile = get_turf(src) var/obj/visual = new /obj/effect/temp_visual/point(our_tile, invisibility) + SEND_SIGNAL(src, COMSIG_MOVABLE_POINTED, pointed_atom, visual, intentional) + animate(visual, pixel_x = (tile.x - our_tile.x) * world.icon_size + pointed_atom.pixel_x, pixel_y = (tile.y - our_tile.y) * world.icon_size + pointed_atom.pixel_y, time = 1.7, easing = EASE_OUT) + return TRUE + +/mob/point_at(atom/pointed_atom, intentional = FALSE) + . = ..() + if(.) + face_atom(pointed_atom) /atom/movable/proc/create_point_bubble(atom/pointed_atom) var/mutable_appearance/thought_bubble = mutable_appearance( @@ -109,7 +117,6 @@ if(client && !(pointing_at in view(client.view, src))) return FALSE - point_at(pointing_at) + point_at(pointing_at, TRUE) - SEND_SIGNAL(src, COMSIG_MOB_POINTED, pointing_at) return TRUE diff --git a/code/modules/power/apc/apc_tool_act.dm b/code/modules/power/apc/apc_tool_act.dm index 8e4d51a703da6..9d7c008c6165c 100644 --- a/code/modules/power/apc/apc_tool_act.dm +++ b/code/modules/power/apc/apc_tool_act.dm @@ -110,7 +110,7 @@ if(isnull(choice) \ || !user.is_holding(installing_cable) \ || !user.Adjacent(src) \ - || user.incapacitated() \ + || user.incapacitated \ || !can_place_terminal(user, installing_cable, silent = TRUE) \ ) return ITEM_INTERACT_BLOCKING diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 65b4f01722959..f68319f4205fb 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -497,7 +497,7 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri if(!ISADVANCEDTOOLUSER(user)) to_chat(user, span_warning("You don't have the dexterity to do this!")) return FALSE - if(user.incapacitated() || !user.Adjacent(src)) + if(user.incapacitated || !user.Adjacent(src)) return FALSE return TRUE @@ -581,8 +581,9 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri if(isnull(affecting) || !IS_ROBOTIC_LIMB(affecting)) return NONE - if (!affecting.get_damage()) - return + if (!affecting.burn_dam) + balloon_alert(user, "limb not damaged") + return ITEM_INTERACT_BLOCKING user.visible_message(span_notice("[user] starts to fix some of the wires in [attacked_humanoid == user ? user.p_their() : "[attacked_humanoid]'s"] [affecting.name]."), span_notice("You start fixing some of the wires in [attacked_humanoid == user ? "your" : "[attacked_humanoid]'s"] [affecting.name].")) @@ -766,7 +767,7 @@ GLOBAL_LIST(hub_radial_layer_list) if(!ISADVANCEDTOOLUSER(user)) to_chat(user, span_warning("You don't have the dexterity to do this!")) return FALSE - if(user.incapacitated() || !user.Adjacent(src)) + if(user.incapacitated || !user.Adjacent(src)) return FALSE return TRUE diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index fbb36703cc569..a168150c7dac8 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -221,9 +221,6 @@ custom_materials = null grind_results = null -/obj/item/stock_parts/power_store/cell/inducer_supply - maxcharge = STANDARD_CELL_CHARGE * 5 - /obj/item/stock_parts/power_store/cell/ethereal name = "ahelp it" desc = "you sohuldn't see this" diff --git a/code/modules/power/pipecleaners.dm b/code/modules/power/pipecleaners.dm index 4c91301978940..4700004904796 100644 --- a/code/modules/power/pipecleaners.dm +++ b/code/modules/power/pipecleaners.dm @@ -233,7 +233,7 @@ By design, d1 is the smallest direction and d2 is the highest return FALSE if(!user.is_holding(src)) return FALSE - if(user.incapacitated()) + if(user.incapacitated) return FALSE return TRUE diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm index c5353ce62d537..715a1a118c93d 100644 --- a/code/modules/power/port_gen.dm +++ b/code/modules/power/port_gen.dm @@ -10,7 +10,7 @@ use_power = NO_POWER_USE var/active = FALSE - var/power_gen = 5000 + var/power_gen = 5 KILO JOULES var/power_output = 1 var/consumption = 0 var/datum/looping_sound/generator/soundloop @@ -81,13 +81,13 @@ /obj/machinery/power/port_gen/pacman name = "\improper P.A.C.M.A.N.-type portable generator" circuit = /obj/item/circuitboard/machine/pacman - power_gen = 5000 + power_gen = 10 KILO JOULES var/sheets = 0 var/max_sheets = 50 var/sheet_name = "" var/sheet_path = /obj/item/stack/sheet/mineral/plasma var/sheet_left = 0 // How much is left of the sheet - var/time_per_sheet = 60 + var/time_per_sheet = 180 var/current_heat = 0 /obj/machinery/power/port_gen/pacman/Initialize(mapload) @@ -108,8 +108,8 @@ icon_state = "portgen1_0" base_icon_state = "portgen1" max_sheets = 20 - time_per_sheet = 20 - power_gen = 15000 + time_per_sheet = 60 + power_gen = 30 KILO JOULES sheet_path = /obj/item/stack/sheet/mineral/uranium /obj/machinery/power/port_gen/pacman/examine(mob/user) @@ -274,8 +274,8 @@ icon_state = "portgen1_0" base_icon_state = "portgen1" max_sheets = 20 - time_per_sheet = 20 - power_gen = 15000 + time_per_sheet = 60 + power_gen = 30 KILO JOULES sheet_path = /obj/item/stack/sheet/mineral/uranium /obj/machinery/power/port_gen/pacman/pre_loaded diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index 562bf4c0825cd..b288fd6aa87cd 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -421,7 +421,7 @@ . = ..() /obj/machinery/power/emitter/prototype/user_buckle_mob(mob/living/buckled_mob, mob/user, check_loc = TRUE) - if(user.incapacitated() || !istype(user)) + if(user.incapacitated || !istype(user)) return for(var/atom/movable/atom in get_turf(src)) if(atom.density && (atom != src && atom != buckled_mob)) diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm index 935601b834bc3..0842cdf13646f 100644 --- a/code/modules/power/smes.dm +++ b/code/modules/power/smes.dm @@ -121,7 +121,7 @@ if(isnull(choice) \ || !user.is_holding(item) \ || !user.Adjacent(src) \ - || user.incapacitated() \ + || user.incapacitated \ || !can_place_terminal(user, item, silent = TRUE) \ ) return diff --git a/code/modules/projectiles/ammunition/_ammunition.dm b/code/modules/projectiles/ammunition/_ammunition.dm index 45e09db624caf..42751441fca4f 100644 --- a/code/modules/projectiles/ammunition/_ammunition.dm +++ b/code/modules/projectiles/ammunition/_ammunition.dm @@ -32,6 +32,12 @@ var/firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect ///pacifism check for boolet, set to FALSE if bullet is non-lethal var/harmful = TRUE + ///If set to true or false, this ammunition can or cannot misfire, regardless the gun can_misfire setting + var/can_misfire = null + ///This is how much misfire probability is added to the gun when it fires this casing. + var/misfire_increment = 0 + ///If set, this casing will damage any gun it's fired from by the specified amount + var/integrity_damage = 0 /obj/item/ammo_casing/spent name = "spent bullet casing" diff --git a/code/modules/projectiles/ammunition/_firing.dm b/code/modules/projectiles/ammunition/_firing.dm index e2afc1bd67e7f..282c722b169e6 100644 --- a/code/modules/projectiles/ammunition/_firing.dm +++ b/code/modules/projectiles/ammunition/_firing.dm @@ -52,12 +52,19 @@ loaded_projectile.suppressed = quiet if(isgun(fired_from)) - var/obj/item/gun/G = fired_from - loaded_projectile.damage *= G.projectile_damage_multiplier - loaded_projectile.stamina *= G.projectile_damage_multiplier + var/obj/item/gun/gun = fired_from - loaded_projectile.wound_bonus += G.projectile_wound_bonus - loaded_projectile.bare_wound_bonus += G.projectile_wound_bonus + var/integrity_mult = 0.5 + gun.get_integrity_percentage() * 0.5 + if(integrity_mult >= 0.95) //Guns that are only mildly smudged don't debuff projectiles. + integrity_mult = 1 + + loaded_projectile.damage *= gun.projectile_damage_multiplier * integrity_mult + loaded_projectile.stamina *= gun.projectile_damage_multiplier * integrity_mult + + loaded_projectile.wound_bonus += gun.projectile_wound_bonus + loaded_projectile.wound_bonus *= loaded_projectile.wound_bonus >= 0 ? 1 : 2 - integrity_mult + loaded_projectile.bare_wound_bonus += gun.projectile_wound_bonus + loaded_projectile.bare_wound_bonus *= loaded_projectile.bare_wound_bonus >= 0 ? 1 : 2 - integrity_mult if(tk_firing(user, fired_from)) loaded_projectile.ignore_source_check = TRUE diff --git a/code/modules/projectiles/ammunition/ballistic/shotgun.dm b/code/modules/projectiles/ammunition/ballistic/shotgun.dm index b7cda3e93e1a8..84c75ed24935e 100644 --- a/code/modules/projectiles/ammunition/ballistic/shotgun.dm +++ b/code/modules/projectiles/ammunition/ballistic/shotgun.dm @@ -82,6 +82,20 @@ pellets = 6 variance = 25 +/obj/item/ammo_casing/shotgun/buckshot/old + projectile_type = /obj/projectile/bullet/pellet/shotgun_buckshot/old + can_misfire = TRUE + misfire_increment = 2 + integrity_damage = 4 + +/obj/item/ammo_casing/shotgun/buckshot/old/fire_casing(atom/target, mob/living/user, params, distro, quiet, zone_override, spread, atom/fired_from) + . = ..() + if(!fired_from) + return + + var/datum/effect_system/fluid_spread/smoke/smoke = new + smoke.set_up(0, holder = fired_from, location = fired_from) + /obj/item/ammo_casing/shotgun/buckshot/spent projectile_type = null diff --git a/code/modules/projectiles/boxes_magazines/internal/rifle.dm b/code/modules/projectiles/boxes_magazines/internal/rifle.dm index b092e207c10d6..b1f761831ee62 100644 --- a/code/modules/projectiles/boxes_magazines/internal/rifle.dm +++ b/code/modules/projectiles/boxes_magazines/internal/rifle.dm @@ -60,5 +60,5 @@ /obj/item/ammo_box/magazine/internal/boltaction/rebarxbow/syndie max_ammo = 3 caliber = CALIBER_REBAR_SYNDIE - ammo_type = /obj/item/ammo_casing/rebar + ammo_type = /obj/item/ammo_casing/rebar/syndie diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 1452d879799fa..190f9e1a7aca8 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -153,6 +153,15 @@ else . += "It doesn't have a firing pin installed, and won't fire." + var/healthpercent = (atom_integrity/max_integrity) * 100 + switch(healthpercent) + if(60 to 95) + . += span_info("It looks slightly damaged.") + if(25 to 60) + . += span_warning("It appears heavily damaged.") + if(0 to 25) + . += span_boldwarning("It's falling apart!") + //called after the gun has successfully fired its chambered ammo. /obj/item/gun/proc/process_chamber(empty_chamber = TRUE, from_firing = TRUE, chamber_next_round = TRUE) handle_chamber(empty_chamber, from_firing, chamber_next_round) @@ -179,36 +188,48 @@ else playsound(src, fire_sound, fire_sound_volume, vary_fire_sound) -/obj/item/gun/proc/shoot_live_shot(mob/living/user, pointblank = 0, atom/pbtarget = null, message = 1) +/obj/item/gun/proc/shoot_live_shot(mob/living/user, pointblank = FALSE, atom/pbtarget = null, message = TRUE) if(recoil && !tk_firing(user)) shake_camera(user, recoil + 1, recoil) fire_sounds() - if(!suppressed) - if(message) - if(tk_firing(user)) - visible_message( - span_danger("[src] fires itself[pointblank ? " point blank at [pbtarget]!" : "!"]"), - blind_message = span_hear("You hear a gunshot!"), - vision_distance = COMBAT_MESSAGE_RANGE - ) - else if(pointblank) - user.visible_message( - span_danger("[user] fires [src] point blank at [pbtarget]!"), - span_danger("You fire [src] point blank at [pbtarget]!"), - span_hear("You hear a gunshot!"), COMBAT_MESSAGE_RANGE, pbtarget - ) - to_chat(pbtarget, span_userdanger("[user] fires [src] point blank at you!")) - if(pb_knockback > 0 && ismob(pbtarget)) - var/mob/PBT = pbtarget - var/atom/throw_target = get_edge_target_turf(PBT, user.dir) - PBT.throw_at(throw_target, pb_knockback, 2) - else if(!tk_firing(user)) - user.visible_message( - span_danger("[user] fires [src]!"), - blind_message = span_hear("You hear a gunshot!"), - vision_distance = COMBAT_MESSAGE_RANGE, - ignored_mobs = user - ) + if(suppressed || !message) + return + if(tk_firing(user)) + visible_message( + span_danger("[src] fires itself[pointblank ? " point blank at [pbtarget]!" : "!"]"), + blind_message = span_hear("You hear a gunshot!"), + vision_distance = COMBAT_MESSAGE_RANGE + ) + else if(pointblank) + user.visible_message( + span_danger("[user] fires [src] point blank at [pbtarget]!"), + span_danger("You fire [src] point blank at [pbtarget]!"), + span_hear("You hear a gunshot!"), COMBAT_MESSAGE_RANGE, pbtarget + ) + to_chat(pbtarget, span_userdanger("[user] fires [src] point blank at you!")) + if(pb_knockback > 0 && ismob(pbtarget)) + var/mob/PBT = pbtarget + var/atom/throw_target = get_edge_target_turf(PBT, user.dir) + PBT.throw_at(throw_target, pb_knockback, 2) + else if(!tk_firing(user)) + user.visible_message( + span_danger("[user] fires [src]!"), + blind_message = span_hear("You hear a gunshot!"), + vision_distance = COMBAT_MESSAGE_RANGE, + ignored_mobs = user + ) + + if(chambered?.integrity_damage) + take_damage(chambered.integrity_damage, sound_effect = FALSE) + +/obj/item/gun/atom_destruction(damage_flag) + if(!isliving(loc)) + return ..() + var/mob/living/holder = loc + if(holder.is_holding(src) && holder.stat < UNCONSCIOUS) + to_chat(holder, span_boldwarning("[src] breaks down!")) + holder.playsound_local(get_turf(src), 'sound/weapons/smash.ogg', 50, TRUE) + return ..() /obj/item/gun/emp_act(severity) . = ..() @@ -403,9 +424,9 @@ return FALSE else if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot - shoot_live_shot(user, 1, target, message) + shoot_live_shot(user, TRUE, target, message) else - shoot_live_shot(user, 0, target, message) + shoot_live_shot(user, FALSE, target, message) if (iteration >= burst_size) firing_burst = FALSE else @@ -459,9 +480,9 @@ return else if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot - shoot_live_shot(user, 1, target, message) + shoot_live_shot(user, TRUE, target, message) else - shoot_live_shot(user, 0, target, message) + shoot_live_shot(user, FALSE, target, message) else shoot_with_empty_chamber(user) return diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm index 8a8b4dbacfccc..2d77185f1d255 100644 --- a/code/modules/projectiles/guns/ballistic.dm +++ b/code/modules/projectiles/guns/ballistic.dm @@ -7,6 +7,7 @@ w_class = WEIGHT_CLASS_NORMAL pickup_sound = 'sound/items/gun_pick_up.ogg' drop_sound = 'sound/items/gun_drop.ogg' + sound_vary = TRUE ///sound when inserting magazine var/load_sound = 'sound/weapons/gun/general/magazine_insert_full.ogg' @@ -451,7 +452,7 @@ if (sawoff(user, A)) return - if(can_misfire && istype(A, /obj/item/stack/sheet/cloth)) + if(misfire_probability && istype(A, /obj/item/stack/sheet/cloth)) if(guncleaning(user, A)) return @@ -463,7 +464,8 @@ return TRUE /obj/item/gun/ballistic/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0) - if(target != user && chambered.loaded_projectile && can_misfire && prob(misfire_probability) && blow_up(user)) + var/could_it_misfire = (can_misfire && chambered.can_misfire != FALSE) || chambered.can_misfire + if(target != user && chambered.loaded_projectile && could_it_misfire && prob(misfire_probability) && blow_up(user)) to_chat(user, span_userdanger("[src] misfires!")) return @@ -473,9 +475,14 @@ return ..() /obj/item/gun/ballistic/shoot_live_shot(mob/living/user, pointblank = 0, atom/pbtarget = null, message = 1) - if(can_misfire) + if(isnull(chambered)) + return ..() + if(can_misfire && chambered.can_misfire != FALSE) misfire_probability += misfire_percentage_increment misfire_probability = clamp(misfire_probability, 0, misfire_probability_cap) + if(chambered.can_misfire) + misfire_probability += chambered.misfire_increment + misfire_probability = clamp(misfire_probability, 0, misfire_probability_cap) return ..() ///Installs a new suppressor, assumes that the suppressor is already in the contents of src @@ -579,6 +586,9 @@ . += span_danger("You get the feeling this might explode if you fire it...") if(misfire_probability > 0) . += span_danger("Given the state of the gun, there is a [misfire_probability]% chance it'll misfire.") + else if(misfire_probability > 0) + . += span_warning("You get a feeling this might explode if you fire it with the wrong ammunitions...") + . += span_warning("Given the state of the gun, there is a [EXAMINE_HINT("[misfire_probability]%")] chance it'll misfire.") ///Gets the number of bullets in the gun /obj/item/gun/ballistic/proc/get_ammo(countchambered = TRUE) diff --git a/code/modules/projectiles/guns/ballistic/rifle.dm b/code/modules/projectiles/guns/ballistic/rifle.dm index 024f8353ddb48..888b784ddf86c 100644 --- a/code/modules/projectiles/guns/ballistic/rifle.dm +++ b/code/modules/projectiles/guns/ballistic/rifle.dm @@ -193,18 +193,17 @@ /obj/item/gun/ballistic/rifle/rebarxbow name = "Heated Rebar Crossbow" - desc = "Made from an inducer, iron rods, and some wire, this crossbow fires sharpened iron rods, made from the plentiful iron rods found stationwide. \ - Additionally, can fire specialty ammo made from the materials in the atmos crystalizer - zaukerite, metallic hydrogen, and healium crytals all work. \ - Very slow to reload - you can craft the crossbow with a crowbar to try loosen the crossbar, but risks a misfire, or worse..." + desc = "A handcrafted crossbow. \ + Aside from conventional sharpened iron rods, it can also fire specialty ammo made from the atmos crystalizer - zaukerite, metallic hydrogen, and healium rods all work. \ + Very slow to reload - you can craft the crossbow with a crowbar to loosen the crossbar, but risk a misfire, or worse..." icon = 'icons/obj/weapons/guns/ballistic.dmi' icon_state = "rebarxbow" inhand_icon_state = "rebarxbow" worn_icon_state = "rebarxbow" rack_sound = 'sound/weapons/gun/sniper/rack.ogg' - must_hold_to_load = TRUE mag_display = FALSE empty_indicator = TRUE - bolt_type = BOLT_TYPE_LOCKING + bolt_type = BOLT_TYPE_OPEN semi_auto = FALSE internal_magazine = TRUE can_modify_ammo = FALSE @@ -212,7 +211,6 @@ bolt_wording = "bowstring" magazine_wording = "rod" cartridge_wording = "rod" - misfire_probability = 25 weapon_weight = WEAPON_HEAVY initial_caliber = CALIBER_REBAR accepted_magazine_type = /obj/item/ammo_box/magazine/internal/boltaction/rebarxbow/normal @@ -250,10 +248,22 @@ return FALSE return ..() +/obj/item/gun/ballistic/rifle/rebarxbow/shoot_with_empty_chamber(mob/living/user) + if(chambered || !magazine || !length(magazine.contents)) + return ..() + drop_bolt(user) + /obj/item/gun/ballistic/rifle/rebarxbow/examine(mob/user) . = ..() . += "The crossbow is [bolt_locked ? "not ready" : "ready"] to fire." +/obj/item/gun/ballistic/rifle/rebarxbow/update_overlays() + . = ..() + if(!magazine) + . += "[initial(icon_state)]" + "_empty" + if(!bolt_locked) + . += "[initial(icon_state)]" + "_bolt_locked" + /obj/item/gun/ballistic/rifle/rebarxbow/forced name = "Stressed Rebar Crossbow" desc = "Some idiot decided that they would risk shooting themselves in the face if it meant they could have a draw this crossbow a bit faster. Hopefully, it was worth it." @@ -266,7 +276,7 @@ /obj/item/gun/ballistic/rifle/rebarxbow/syndie name = "Syndicate Rebar Crossbow" desc = "The syndicate liked the bootleg rebar crossbow NT engineers made, so they showed what it could be if properly developed. \ - Holds three shots without a chance of exploding, and features a built in scope. Compatable with all known crossbow ammunition." + Holds three shots without a chance of exploding, and features a built in scope. Compatible with all known crossbow ammunition." icon_state = "rebarxbowsyndie" inhand_icon_state = "rebarxbowsyndie" worn_icon_state = "rebarxbowsyndie" diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index 9f854926dbdff..9be59ffb5344b 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -24,6 +24,7 @@ cartridge_wording = "shell" tac_reloads = FALSE weapon_weight = WEAPON_HEAVY + misfire_probability_cap = 35 // Even if the misfire probability and increment are both zero, we've some shots that may do that. pb_knockback = 2 diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 9c16133e1ea35..39e55f94fca17 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -5,6 +5,7 @@ icon = 'icons/obj/weapons/guns/energy.dmi' pickup_sound = 'sound/items/gun_pick_up.ogg' drop_sound = 'sound/items/gun_drop.ogg' + sound_vary = TRUE /// What type of power cell this uses var/obj/item/stock_parts/power_store/cell diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index 53cbe825085b2..1180a90e8d217 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -123,7 +123,7 @@ /obj/item/gun/energy/recharge/kinetic_accelerator/proc/check_menu(mob/living/carbon/human/user) if(!istype(user)) return FALSE - if(user.incapacitated()) + if(user.incapacitated) return FALSE return TRUE diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index c501f15db90e6..5856f8df44729 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -209,6 +209,10 @@ var/wound_falloff_tile ///How much we want to drop the embed_chance value, if we can embed, per tile, for falloff purposes var/embed_falloff_tile + ///How much accuracy is lost for each tile travelled + var/accuracy_falloff = 7 + ///How much accuracy before falloff starts to matter. Formula is range - falloff * tiles travelled + var/accurate_range = 100 var/static/list/projectile_connections = list(COMSIG_ATOM_ENTERED = PROC_REF(on_entered)) /// If true directly targeted turfs can be hit var/can_hit_turfs = FALSE @@ -296,6 +300,12 @@ hitx = target.pixel_x + rand(-8, 8) hity = target.pixel_y + rand(-8, 8) + if(isturf(target) && hitsound_wall) + var/volume = clamp(vol_by_damage() + 20, 0, 100) + if(suppressed) + volume = 5 + playsound(loc, hitsound_wall, volume, TRUE, -1) + if(damage > 0 && (damage_type == BRUTE || damage_type == BURN) && iswallturf(target_turf) && prob(75)) var/turf/closed/wall/target_wall = target_turf if(impact_effect_type && !hitscan) @@ -308,11 +318,7 @@ if(!isliving(target)) if(impact_effect_type && !hitscan) new impact_effect_type(target_turf, hitx, hity) - if(isturf(target) && hitsound_wall) - var/volume = clamp(vol_by_damage() + 20, 0, 100) - if(suppressed) - volume = 5 - playsound(loc, hitsound_wall, volume, TRUE, -1) + return BULLET_ACT_HIT var/mob/living/living_target = target @@ -450,9 +456,8 @@ store_hitscan_collision(point_cache) return TRUE - if(!HAS_TRAIT(src, TRAIT_ALWAYS_HIT_ZONE)) - var/distance = get_dist(T, starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations. - def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use. + var/distance = get_dist(T, starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations. + def_zone = ran_zone(def_zone, clamp(accurate_range - (accuracy_falloff * distance), 5, 100)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use. return process_hit(T, select_target(T, A, A), A) // SELECT TARGET FIRST! @@ -569,6 +574,9 @@ if((target.pass_flags_self & pass_flags) && !direct_target) return FALSE if(HAS_TRAIT(target, TRAIT_UNHITTABLE_BY_PROJECTILES)) + if(!HAS_TRAIT(target, TRAIT_BLOCKING_PROJECTILES) && isliving(target)) + var/mob/living/living_target = target + living_target.block_projectile_effects() return FALSE if(!ignore_source_check && firer) var/mob/M = firer @@ -1039,7 +1047,9 @@ var/list/screen_loc_Y = splittext(screen_loc_params[2],":") var/tx = (text2num(screen_loc_X[1]) - 1) * world.icon_size + text2num(screen_loc_X[2]) - var/ty = (text2num(screen_loc_Y[1]) - 1) * world.icon_size + text2num(screen_loc_Y[2]) + // We are here trying to lower our target location by the firing source's visual offset + // So visually things make a nice straight line while properly accounting for actual physical position + var/ty = (text2num(screen_loc_Y[1]) - 1) * world.icon_size + text2num(screen_loc_Y[2]) - source.pixel_z //Calculate the "resolution" of screen based on client's view and world's icon size. This will work if the user can view more tiles than average. var/list/screenview = view_to_pixels(user.client.view) diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index 542c2aaa35d92..0e50326f1b07c 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -50,13 +50,11 @@ //overclocked laser, does a bit more damage but has much higher wound power (-0 vs -20) /obj/projectile/beam/laser/hellfire name = "hellfire laser" + icon_state = "hellfire" wound_bonus = 0 damage = 30 speed = 0.6 // higher power = faster, that's how light works right - -/obj/projectile/beam/laser/hellfire/Initialize(mapload) - . = ..() - transform *= 2 + light_color = "#FF969D" /obj/projectile/beam/laser/heavylaser name = "heavy laser" diff --git a/code/modules/projectiles/projectile/bullets/rifle.dm b/code/modules/projectiles/projectile/bullets/rifle.dm index 6f14df2f4c8bd..2915e3e59bd6c 100644 --- a/code/modules/projectiles/projectile/bullets/rifle.dm +++ b/code/modules/projectiles/projectile/bullets/rifle.dm @@ -140,27 +140,38 @@ /obj/projectile/bullet/rebar/hydrogen name = "metallic hydrogen bolt" icon_state = "rebar_hydrogen" - damage = 40 + damage = 55 speed = 0.6 + projectile_piercing = PASSMOB|PASSVEHICLE + projectile_phasing = ~(PASSMOB|PASSVEHICLE) + phasing_ignore_direct_target = TRUE dismemberment = 0 //goes through clean. damage_type = BRUTE armour_penetration = 30 //very pointy. - projectile_piercing = PASSMOB //felt this might have been a nice compromise for the lower damage for the difficulty of getting it wound_bonus = -15 bare_wound_bonus = 10 + shrapnel_type = /obj/item/ammo_casing/rebar/hydrogen embed_type = /datum/embed_data/rebar_hydrogen embed_falloff_tile = -3 shrapnel_type = /obj/item/ammo_casing/rebar/hydrogen + accurate_range = 205 //15 tiles before falloff starts to kick in + +/obj/projectile/bullet/rebar/hydrogen/Impact(atom/A) + . = ..() + def_zone = ran_zone(def_zone, clamp(205-(7*get_dist(get_turf(A), starting)), 5, 100)) /datum/embed_data/rebar_hydrogen - embed_chance = 50 - fall_chance = 2 - jostle_chance = 3 - ignore_throwspeed_threshold = TRUE - pain_stam_pct = 0.6 - pain_mult = 4 - jostle_pain_mult = 2 - rip_time =18 + embed_chance = 0 + +/obj/projectile/bullet/rebar/hydrogen/on_hit(atom/target, blocked, pierce_hit) + if(isAI(target)) + return BULLET_ACT_FORCE_PIERCE + return ..() + +/obj/projectile/bullet/rebar/hydrogen/process_hit(turf/T, atom/target, atom/bumped, hit_something) + . = ..() + if(pierces >= 3) + qdel(src) /obj/projectile/bullet/rebar/healium name = "healium bolt" diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm index 7ae5741f3b992..215093c9f100e 100644 --- a/code/modules/projectiles/projectile/bullets/shotgun.dm +++ b/code/modules/projectiles/projectile/bullets/shotgun.dm @@ -79,6 +79,15 @@ bare_wound_bonus = 5 wound_falloff_tile = -2.5 // low damage + additional dropoff will already curb wounding potential anything past point blank +/** + * A slightly weaker version of the buckshot, available from the blackmarket. + * The casings they're in have a very small chance to misfire and will gradually damage the firearm, making it weaker. + */ +/obj/projectile/bullet/pellet/shotgun_buckshot/old + damage_falloff_tile = -0.47 + wound_bonus = -100 + bare_wound_bonus = -100 + /obj/projectile/bullet/pellet/shotgun_rubbershot name = "rubber shot pellet" damage = 3 diff --git a/code/modules/reagents/chemistry/holder/holder.dm b/code/modules/reagents/chemistry/holder/holder.dm index 11117142d70e5..f084a7eaa39d4 100644 --- a/code/modules/reagents/chemistry/holder/holder.dm +++ b/code/modules/reagents/chemistry/holder/holder.dm @@ -344,26 +344,29 @@ stack_trace("invalid reagent path passed to convert reagent [source_reagent_typepath]") return FALSE - var/reagent_amount - var/reagent_purity - var/reagent_ph + var/reagent_amount = 0 + var/reagent_purity = 0 + var/reagent_ph = 0 if(include_source_subtypes) reagent_ph = ph var/weighted_purity var/list/reagent_type_list = typecacheof(source_reagent_typepath) for(var/datum/reagent/reagent as anything in reagent_list) - if(reagent.type in reagent_type_list) + if(is_type_in_typecache(reagent, reagent_type_list)) weighted_purity += reagent.volume * reagent.purity reagent_amount += reagent.volume remove_reagent(reagent.type, reagent.volume * multiplier) reagent_purity = weighted_purity / reagent_amount else var/datum/reagent/source_reagent = has_reagent(source_reagent_typepath) - reagent_amount = source_reagent.volume - reagent_purity = source_reagent.purity - reagent_ph = source_reagent.ph - remove_reagent(source_reagent_typepath, reagent_amount) - add_reagent(target_reagent_typepath, reagent_amount * multiplier, reagtemp = chem_temp, added_purity = reagent_purity, added_ph = reagent_ph) + if(istype(source_reagent)) + reagent_amount = source_reagent.volume + reagent_purity = source_reagent.purity + reagent_ph = source_reagent.ph + remove_reagent(source_reagent_typepath, reagent_amount) + + if(reagent_amount > 0) + add_reagent(target_reagent_typepath, reagent_amount * multiplier, reagtemp = chem_temp, added_purity = reagent_purity, added_ph = reagent_ph) /// Removes all reagents /datum/reagents/proc/clear_reagents() diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index cf193decb6931..5f665d876afaa 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -572,6 +572,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 + circuit = /obj/item/circuitboard/machine/chem_dispenser/drinks/fullupgrade /obj/machinery/chem_dispenser/drinks/fullupgrade/Initialize(mapload) . = ..() diff --git a/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm index 3f5b7e3a24479..da57f6ce405a1 100644 --- a/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm @@ -344,6 +344,28 @@ taste_description = "spiked butterscotch" ph = 6.5 default_container = /obj/item/reagent_containers/cup/glass/bottle/rum + chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + +/datum/reagent/consumable/ethanol/rum/aged + name = "Aged Rum" + description = "Sink me! That's some fancy rum to share with buckoos." + color = "#c0b675" // rgb: 192,183,117 + boozepwr = 70 + taste_description = "extra-spiked butterscotch" + default_container = /obj/item/reagent_containers/cup/glass/bottle/rum/aged + quality = DRINK_FANTASTIC + metabolized_traits = list(TRAIT_STRONG_STOMACH) + +/datum/reagent/consumable/ethanol/rum/aged/on_mob_metabolize(mob/living/drinker) + . = ..() + drinker.add_blocked_language(subtypesof(/datum/language) - /datum/language/piratespeak, LANGUAGE_DRINK) + drinker.grant_language(/datum/language/piratespeak, source = LANGUAGE_DRINK) + +/datum/reagent/consumable/ethanol/rum/aged/on_mob_end_metabolize(mob/living/drinker) + if(!QDELING(drinker)) + drinker.remove_blocked_language(subtypesof(/datum/language), LANGUAGE_DRINK) + drinker.remove_language(/datum/language/piratespeak, source = LANGUAGE_DRINK) + return ..() /datum/reagent/consumable/ethanol/tequila name = "Tequila" @@ -2637,7 +2659,7 @@ var/mob/living/carbon/exposed_carbon = exposed_mob var/obj/item/organ/internal/stomach/ethereal/stomach = exposed_carbon.get_organ_slot(ORGAN_SLOT_STOMACH) if(istype(stomach)) - stomach.adjust_charge(reac_volume * 0.003 * STANDARD_CELL_CHARGE) + stomach.adjust_charge(reac_volume * 0.003 * ETHEREAL_CHARGE_NORMAL) /datum/reagent/consumable/ethanol/telepole name = "Telepole" @@ -2657,7 +2679,7 @@ var/mob/living/carbon/exposed_carbon = exposed_mob var/obj/item/organ/internal/stomach/ethereal/stomach = exposed_carbon.get_organ_slot(ORGAN_SLOT_STOMACH) if(istype(stomach)) - stomach.adjust_charge(reac_volume * 0.002 * STANDARD_CELL_CHARGE) + stomach.adjust_charge(reac_volume * 0.002 * ETHEREAL_CHARGE_NORMAL) /datum/reagent/consumable/ethanol/pod_tesla name = "Pod Tesla" @@ -2684,7 +2706,7 @@ var/mob/living/carbon/exposed_carbon = exposed_mob var/obj/item/organ/internal/stomach/ethereal/stomach = exposed_carbon.get_organ_slot(ORGAN_SLOT_STOMACH) if(istype(stomach)) - stomach.adjust_charge(reac_volume * 0.005 * STANDARD_CELL_CHARGE) + stomach.adjust_charge(reac_volume * 0.005 * ETHEREAL_CHARGE_NORMAL) // Welcome to the Blue Room Bar and Grill, home to Mars' finest cocktails /datum/reagent/consumable/ethanol/rice_beer diff --git a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm index d3070474558d7..c7be6ead5e898 100644 --- a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm @@ -1291,4 +1291,4 @@ var/mob/living/carbon/exposed_carbon = exposed_mob var/obj/item/organ/internal/stomach/ethereal/stomach = exposed_carbon.get_organ_slot(ORGAN_SLOT_STOMACH) if(istype(stomach)) - stomach.adjust_charge(reac_volume * 0.003 * STANDARD_CELL_CHARGE) + stomach.adjust_charge(reac_volume * 0.003 * ETHEREAL_CHARGE_NORMAL) diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index 4f7377d407fec..5365be6fe8d7f 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -949,7 +949,7 @@ var/mob/living/carbon/exposed_carbon = exposed_mob var/obj/item/organ/internal/stomach/ethereal/stomach = exposed_carbon.get_organ_slot(ORGAN_SLOT_STOMACH) if(istype(stomach)) - stomach.adjust_charge(reac_volume * 0.03 * STANDARD_CELL_CHARGE) + stomach.adjust_charge(reac_volume * 0.03 * ETHEREAL_CHARGE_NORMAL) /datum/reagent/consumable/liquidelectricity/enriched/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() diff --git a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm index 3a633e5c83679..ce829a6ac1222 100644 --- a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm @@ -230,7 +230,7 @@ Basically, we fill the time between now and 2s from now with hands based off the //Just the removed itching mechanism - omage to its origins. /datum/reagent/inverse/ichiyuri/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() - if(prob(resetting_probability) && !(HAS_TRAIT(affected_mob, TRAIT_RESTRAINED) || affected_mob.incapacitated())) + if(prob(resetting_probability) && !(HAS_TRAIT(affected_mob, TRAIT_RESTRAINED) || affected_mob.incapacitated)) . = TRUE if(spammer < world.time) to_chat(affected_mob,span_warning("You can't help but itch yourself.")) diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index cf9c7ae38c64e..bff4d526333be 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -38,6 +38,13 @@ results = list(/datum/reagent/consumable/salt = 2) required_reagents = list(/datum/reagent/sodium = 1, /datum/reagent/chlorine = 1) // That's what I said! Sodium Chloride! reaction_tags = REACTION_TAG_EASY | REACTION_TAG_FOOD + required_other = TRUE + +/datum/chemical_reaction/sodiumchloride/pre_reaction_other_checks(datum/reagents/holder) + . = ..() + if(holder.has_reagent(/datum/reagent/consumable/liquidelectricity) || holder.has_reagent(/datum/reagent/consumable/liquidelectricity/enriched)) + return FALSE + /datum/chemical_reaction/stable_plasma results = list(/datum/reagent/stable_plasma = 1) @@ -600,6 +607,18 @@ results = list(/datum/reagent/oxygen = 2.5, /datum/reagent/hydrogen = 5) required_reagents = list(/datum/reagent/consumable/liquidelectricity/enriched = 1, /datum/reagent/water = 5) reaction_tags = REACTION_TAG_EASY | REACTION_TAG_CHEMICAL + +//salt electrolysis +/datum/chemical_reaction/saltelectrolysis + results = list(/datum/reagent/chlorine = 2.5, /datum/reagent/sodium = 2.5) + required_reagents = list(/datum/reagent/consumable/salt = 5) + required_catalysts = list(/datum/reagent/consumable/liquidelectricity = 1) + reaction_tags = REACTION_TAG_EASY | REACTION_TAG_CHEMICAL + +/datum/chemical_reaction/saltelectrolysis/enriched + required_catalysts = list(/datum/reagent/consumable/liquidelectricity/enriched = 1) + + //butterflium /datum/chemical_reaction/butterflium required_reagents = list(/datum/reagent/colorful_reagent = 1, /datum/reagent/medicine/omnizine = 1, /datum/reagent/medicine/strange_reagent = 1, /datum/reagent/consumable/nutriment = 1) diff --git a/code/modules/reagents/reagent_containers/cups/_cup.dm b/code/modules/reagents/reagent_containers/cups/_cup.dm index 87df7765233ec..5590be84f4386 100644 --- a/code/modules/reagents/reagent_containers/cups/_cup.dm +++ b/code/modules/reagents/reagent_containers/cups/_cup.dm @@ -161,7 +161,7 @@ to_chat(user, span_notice("You fill [src] with [trans] unit\s of the contents of [target].")) target.update_appearance() - return ITEM_INTERACT_SUCCESS + return NONE /obj/item/reagent_containers/cup/attackby(obj/item/attacking_item, mob/user, params) var/hotness = attacking_item.get_temperature() @@ -230,6 +230,7 @@ fill_icon_thresholds = list(0, 1, 20, 40, 60, 80, 100) pickup_sound = 'sound/items/handling/beaker_pickup.ogg' drop_sound = 'sound/items/handling/beaker_place.ogg' + sound_vary = TRUE /obj/item/reagent_containers/cup/beaker/Initialize(mapload) . = ..() diff --git a/code/modules/reagents/reagent_containers/cups/bottle.dm b/code/modules/reagents/reagent_containers/cups/bottle.dm index fda39ed4877ba..2259cda34d79c 100644 --- a/code/modules/reagents/reagent_containers/cups/bottle.dm +++ b/code/modules/reagents/reagent_containers/cups/bottle.dm @@ -129,6 +129,11 @@ desc = "A small bottle. Contains cold sauce." list_reagents = list(/datum/reagent/consumable/frostoil = 30) +/obj/item/reagent_containers/cup/bottle/strange_reagent + name = "Strange Reagent Bottle" + desc = "A small bottle. May be used to revive people." + list_reagents = list(/datum/reagent/medicine/strange_reagent = 30) + /obj/item/reagent_containers/cup/bottle/traitor name = "syndicate bottle" desc = "A small bottle. Contains a random nasty chemical." diff --git a/code/modules/reagents/reagent_containers/cups/drinkingglass.dm b/code/modules/reagents/reagent_containers/cups/drinkingglass.dm index 7441614682c06..fa3a53434bbcc 100644 --- a/code/modules/reagents/reagent_containers/cups/drinkingglass.dm +++ b/code/modules/reagents/reagent_containers/cups/drinkingglass.dm @@ -14,6 +14,7 @@ obj_flags = UNIQUE_RENAME drop_sound = 'sound/items/handling/drinkglass_drop.ogg' pickup_sound = 'sound/items/handling/drinkglass_pickup.ogg' + sound_vary = TRUE custom_price = PAYCHECK_LOWER //the screwdriver cocktail can make a drinking glass into the world's worst screwdriver. beautiful. toolspeed = 25 diff --git a/code/modules/reagents/reagent_containers/cups/glassbottle.dm b/code/modules/reagents/reagent_containers/cups/glassbottle.dm index b246cc01e07e9..7b2183b1f2269 100644 --- a/code/modules/reagents/reagent_containers/cups/glassbottle.dm +++ b/code/modules/reagents/reagent_containers/cups/glassbottle.dm @@ -316,6 +316,12 @@ icon_state = "rumbottle" list_reagents = list(/datum/reagent/consumable/ethanol/rum = 100) +/obj/item/reagent_containers/cup/glass/bottle/rum/aged + name = "Captain Pete's Vintage spiced rum" + desc = "Shiver me timbers, a vintage edition of Captain Pete's rum. It's pratically GRIFF in a bottle from over 50 years ago." + icon_state = "rumbottle_gold" + list_reagents = list(/datum/reagent/consumable/ethanol/rum/aged = 100) + /obj/item/reagent_containers/cup/glass/bottle/maltliquor name = "\improper Rabid Bear malt liquor" desc = "A 40 full of malt liquor. Kicks stronger than, well, a rabid bear." diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index dc54dcd7db44b..4b6ee9c8c7860 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -154,7 +154,7 @@ set name = "Empty Spray Bottle" set category = "Object" set src in usr - if(usr.incapacitated()) + if(usr.incapacitated) return if (tgui_alert(usr, "Are you sure you want to empty that?", "Empty Bottle:", list("Yes", "No")) != "Yes") return diff --git a/code/modules/recycling/conveyor.dm b/code/modules/recycling/conveyor.dm index 21c5aa7a1a902..0d207ed7e11fc 100644 --- a/code/modules/recycling/conveyor.dm +++ b/code/modules/recycling/conveyor.dm @@ -434,6 +434,8 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) /// Updates the switch's `position` and `last_pos` variable. Useful so that the switch can properly cycle between the forwards, backwards and neutral positions. /obj/machinery/conveyor_switch/proc/update_position(direction) if(position == CONVEYOR_OFF) + playsound(src, 'sound/machines/lever_start.ogg', 40, TRUE) + if(oneway) //is it a oneway switch position = oneway else @@ -442,6 +444,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) else position = CONVEYOR_BACKWARDS else + playsound(src, 'sound/machines/lever_stop.ogg', 40, TRUE) position = CONVEYOR_OFF /obj/machinery/conveyor_switch/proc/on_user_activation(mob/user, direction) diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm index 4b54cf9f4b023..8d6b1217360f5 100644 --- a/code/modules/recycling/disposal/bin.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -624,6 +624,12 @@ SIGNAL_HANDLER if((shove_flags & SHOVE_KNOCKDOWN_BLOCKED) || !(shove_flags & SHOVE_BLOCKED)) return + var/cur_density = density + density = FALSE + if (!target.Move(get_turf(src), get_dir(target, src))) + density = cur_density + return + density = cur_density target.Knockdown(SHOVE_KNOCKDOWN_SOLID) target.forceMove(src) target.visible_message(span_danger("[shover.name] shoves [target.name] into \the [src]!"), diff --git a/code/modules/recycling/disposal/holder.dm b/code/modules/recycling/disposal/holder.dm index b842a69413d7d..78469d491912b 100644 --- a/code/modules/recycling/disposal/holder.dm +++ b/code/modules/recycling/disposal/holder.dm @@ -195,7 +195,7 @@ // called when player tries to move while in a pipe /obj/structure/disposalholder/relaymove(mob/living/user, direction) - if(user.incapacitated()) + if(user.incapacitated) return for(var/mob/M in range(5, get_turf(src))) M.show_message("CLONG, clong!", MSG_AUDIBLE) diff --git a/code/modules/research/designs/autolathe/service_designs.dm b/code/modules/research/designs/autolathe/service_designs.dm index e7177037e522c..94772421b69ab 100644 --- a/code/modules/research/designs/autolathe/service_designs.dm +++ b/code/modules/research/designs/autolathe/service_designs.dm @@ -581,7 +581,7 @@ /datum/design/telescreen_entertainment name = "Entertainment Telescreen" id = "telescreen_entertainment" - build_type = PROTOLATHE + build_type = AUTOLATHE | PROTOLATHE materials = list( /datum/material/iron = SHEET_MATERIAL_AMOUNT*5, /datum/material/glass =SHEET_MATERIAL_AMOUNT * 2.5, @@ -593,6 +593,21 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SERVICE +/datum/design/entertainment_radio + name = "Entertainment Radio" + id = "radio_entertainment" + build_type = AUTOLATHE | PROTOLATHE + materials = list( + /datum/material/iron = SMALL_MATERIAL_AMOUNT*0.75, + /datum/material/glass =SMALL_MATERIAL_AMOUNT*0.25 + ) + build_path = /obj/item/radio/entertainment/speakers/physical + category = list( + RND_CATEGORY_INITIAL, + RND_CATEGORY_CONSTRUCTION + RND_SUBCATEGORY_CONSTRUCTION_MOUNTS, + ) + departmental_flags = DEPARTMENT_BITFLAG_SERVICE + /datum/design/barcode_scanner name = "Barcode Scanner" id = "barcode_scanner" diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm index 53104494c820e..0543214077ef2 100644 --- a/code/modules/research/designs/machine_designs.dm +++ b/code/modules/research/designs/machine_designs.dm @@ -1247,3 +1247,13 @@ RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_SERVICE ) departmental_flags = DEPARTMENT_BITFLAG_SERVICE + +/datum/design/board/big_manipulator + name = "Big Manipulator Board" + desc = "The circuit board for a big manipulator." + id = "big_manipulator" + build_path = /obj/item/circuitboard/machine/big_manipulator + category = list( + RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_ENGINEERING + ) + departmental_flags = DEPARTMENT_BITFLAG_SCIENCE | DEPARTMENT_BITFLAG_ENGINEERING | DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_SERVICE diff --git a/code/modules/research/techweb/nodes/engi_nodes.dm b/code/modules/research/techweb/nodes/engi_nodes.dm index 0fe1b7bd75f33..949b880d1f23a 100644 --- a/code/modules/research/techweb/nodes/engi_nodes.dm +++ b/code/modules/research/techweb/nodes/engi_nodes.dm @@ -126,6 +126,7 @@ "firelock_board", "trapdoor_electronics", "blast", + "big_manipulator", "tile_sprayer", "airlock_painter", "decal_painter", diff --git a/code/modules/research/xenobiology/crossbreeding/_weapons.dm b/code/modules/research/xenobiology/crossbreeding/_weapons.dm index c5136baafb149..152a90f9795eb 100644 --- a/code/modules/research/xenobiology/crossbreeding/_weapons.dm +++ b/code/modules/research/xenobiology/crossbreeding/_weapons.dm @@ -66,6 +66,7 @@ Slimecrossing Weapons attack_verb_simple = list("bash", "pound", "slam") item_flags = SLOWS_WHILE_IN_HAND breakable_by_damage = FALSE + shield_bash_sound = 'sound/effects/glassknock.ogg' /datum/armor/shield_adamantineshield melee = 50 diff --git a/code/modules/spells/spell_types/pointed/finger_guns.dm b/code/modules/spells/spell_types/pointed/finger_guns.dm index 24f51a0e90862..cf80489fc916a 100644 --- a/code/modules/spells/spell_types/pointed/finger_guns.dm +++ b/code/modules/spells/spell_types/pointed/finger_guns.dm @@ -33,7 +33,7 @@ return FALSE var/mob/living/carbon/human/human_invoker = invoker - if(human_invoker.incapacitated()) + if(human_invoker.incapacitated) if(feedback) to_chat(human_invoker, span_warning("You can't properly point your fingers while incapacitated.")) return FALSE diff --git a/code/modules/spells/spell_types/shapeshift/_shapeshift.dm b/code/modules/spells/spell_types/shapeshift/_shapeshift.dm index 59c9ffdde3b0b..b7542d4077f3c 100644 --- a/code/modules/spells/spell_types/shapeshift/_shapeshift.dm +++ b/code/modules/spells/spell_types/shapeshift/_shapeshift.dm @@ -141,7 +141,7 @@ if(QDELETED(caster)) return FALSE - return !caster.incapacitated() + return !caster.incapacitated /// Actually does the shapeshift, for the caster. /datum/action/cooldown/spell/shapeshift/proc/do_shapeshift(mob/living/caster) diff --git a/code/modules/spells/spell_types/teleport/teleport.dm b/code/modules/spells/spell_types/teleport/teleport.dm index d486157204283..57e88b9852025 100644 --- a/code/modules/spells/spell_types/teleport/teleport.dm +++ b/code/modules/spells/spell_types/teleport/teleport.dm @@ -48,5 +48,5 @@ return var/mob/living/carbon/caster = cast_on - if(caster.incapacitated() || !caster.is_holding(target)) + if(caster.incapacitated || !caster.is_holding(target)) return . | SPELL_CANCEL_CAST diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index c656daeb18445..5579cb64d83d5 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -231,8 +231,6 @@ for(var/obj/item/head_item as anything in list(owner.glasses, owner.ears, owner.wear_mask, owner.head)) owner.dropItemToGround(head_item, force = TRUE) - qdel(owner.GetComponent(/datum/component/creamed)) //clean creampie overlay flushed emoji - //Handle dental implants for(var/datum/action/item_action/activate_pill/pill_action in owner.actions) pill_action.Remove(owner) diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm index 314f3396f0afe..738b3ce97ac3b 100644 --- a/code/modules/surgery/bodyparts/robot_bodyparts.dm +++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm @@ -124,8 +124,8 @@ if (severity == EMP_HEAVY) knockdown_time *= 2 owner.Knockdown(knockdown_time) - if(owner.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB)) // So the message isn't duplicated. If they were stunned beforehand by something else, then the message not showing makes more sense anyways. - return FALSE + if(INCAPACITATED_IGNORING(owner, INCAPABLE_RESTRAINTS|INCAPABLE_GRAB)) // So the message isn't duplicated. If they were stunned beforehand by something else, then the message not showing makes more sense anyways. + return to_chat(owner, span_danger("As your [plaintext_zone] unexpectedly malfunctions, it causes you to fall to the ground!")) return @@ -173,8 +173,8 @@ if (severity == EMP_HEAVY) knockdown_time *= 2 owner.Knockdown(knockdown_time) - if(owner.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB)) // So the message isn't duplicated. If they were stunned beforehand by something else, then the message not showing makes more sense anyways. - return FALSE + if(INCAPACITATED_IGNORING(owner, INCAPABLE_RESTRAINTS|INCAPABLE_GRAB)) // So the message isn't duplicated. If they were stunned beforehand by something else, then the message not showing makes more sense anyways. + return to_chat(owner, span_danger("As your [plaintext_zone] unexpectedly malfunctions, it causes you to fall to the ground!")) return diff --git a/code/modules/surgery/organs/internal/stomach/_stomach.dm b/code/modules/surgery/organs/internal/stomach/_stomach.dm index ba526aff2e0f7..4f1edd1542d69 100644 --- a/code/modules/surgery/organs/internal/stomach/_stomach.dm +++ b/code/modules/surgery/organs/internal/stomach/_stomach.dm @@ -217,6 +217,7 @@ disgusted.adjust_confusion(2.5 SECONDS) disgusted.adjust_stutter(2 SECONDS) disgusted.vomit(VOMIT_CATEGORY_KNOCKDOWN, distance = 0) + disgusted.adjust_disgust(-50) disgusted.set_dizzy_if_lower(10 SECONDS) if(disgust >= DISGUST_LEVEL_DISGUSTED) if(SPT_PROB(13, seconds_per_tick)) diff --git a/code/modules/tgui/states.dm b/code/modules/tgui/states.dm index dc3d543f14364..a29279457a04a 100644 --- a/code/modules/tgui/states.dm +++ b/code/modules/tgui/states.dm @@ -67,7 +67,7 @@ else if(stat) return UI_DISABLED // Update UIs if incapicitated but concious. - else if(incapacitated()) + else if(incapacitated) return UI_UPDATE return UI_INTERACTIVE diff --git a/code/modules/tgui/states/not_incapacitated.dm b/code/modules/tgui/states/not_incapacitated.dm index f7278c86de473..ab8cd5f6246fd 100644 --- a/code/modules/tgui/states/not_incapacitated.dm +++ b/code/modules/tgui/states/not_incapacitated.dm @@ -29,6 +29,6 @@ GLOBAL_DATUM_INIT(not_incapacitated_turf_state, /datum/ui_state/not_incapacitate /datum/ui_state/not_incapacitated_state/can_use_topic(src_object, mob/user) if(user.stat != CONSCIOUS) return UI_CLOSE - if(HAS_TRAIT(src, TRAIT_UI_BLOCKED) || user.incapacitated() || (turf_check && !isturf(user.loc))) + if(HAS_TRAIT(src, TRAIT_UI_BLOCKED) || user.incapacitated || (turf_check && !isturf(user.loc))) return UI_DISABLED return UI_INTERACTIVE diff --git a/code/modules/transport/transport_module.dm b/code/modules/transport/transport_module.dm index af8f4199438db..01a3493130501 100644 --- a/code/modules/transport/transport_module.dm +++ b/code/modules/transport/transport_module.dm @@ -612,7 +612,7 @@ if(!isliving(user)) return FALSE // Gotta be awake and aware - if(user.incapacitated()) + if(user.incapacitated) return FALSE // Maintain the god given right to fight an elevator if(user.combat_mode) @@ -704,7 +704,7 @@ * * boolean, FALSE if the menu should be closed, TRUE if the menu is clear to stay opened. */ /obj/structure/transport/linear/proc/check_menu(mob/user, starting_loc) - if(user.incapacitated() || !user.Adjacent(src) || starting_loc != src.loc) + if(user.incapacitated || !user.Adjacent(src) || starting_loc != src.loc) return FALSE return TRUE diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index a42c25dc94ee1..9f0bbc5637d7b 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -107,6 +107,7 @@ #include "breath.dm" #include "burning.dm" #include "cable_powernets.dm" +#include "can_see.dm" #include "card_mismatch.dm" #include "cardboard_cutouts.dm" #include "cargo_dep_order_locations.dm" diff --git a/code/modules/unit_tests/can_see.dm b/code/modules/unit_tests/can_see.dm new file mode 100644 index 0000000000000..cb7f7bef047ee --- /dev/null +++ b/code/modules/unit_tests/can_see.dm @@ -0,0 +1,7 @@ +/// Unit test to make sure can_see is working properly +/datum/unit_test/can_see_test + +/datum/unit_test/can_see_test/Run() + var/mob/living/carbon/human/observer = allocate(/mob/living/carbon/human/consistent, run_loc_floor_bottom_left) //make sure they're both apart + var/mob/living/carbon/human/to_be_seen = allocate(/mob/living/carbon/human/consistent, run_loc_floor_top_right) + TEST_ASSERT(can_see(observer, to_be_seen, get_dist(observer, to_be_seen)), "can_see returned false despite dummies being able to see one another!") diff --git a/code/modules/unit_tests/mecha_damage.dm b/code/modules/unit_tests/mecha_damage.dm index dc5f4ecae8a1d..9dd82dddc41ec 100644 --- a/code/modules/unit_tests/mecha_damage.dm +++ b/code/modules/unit_tests/mecha_damage.dm @@ -25,7 +25,8 @@ // Get a sample "melee" weapon. // The energy axe is chosen here due to having a high base force, to make sure we get over the equipment DT. var/obj/item/dummy_melee = allocate(/obj/item/melee/energy/axe) - var/expected_melee_damage = round(dummy_melee.force * (1 - expected_melee_armor / 100) * dummy_melee.demolition_mod, DAMAGE_PRECISION) + dummy_melee.force = 150 + var/expected_melee_damage = round(dummy_melee.force * (1 - expected_melee_armor / 100) * dummy_melee.demolition_mod * demo_mech.facing_modifiers[MECHA_FRONT_ARMOUR], DAMAGE_PRECISION) // Get a sample laser weapon. // The captain's laser gun here is chosen primarily because it deals more damage than normal lasers. diff --git a/code/modules/unit_tests/say.dm b/code/modules/unit_tests/say.dm index 7536392e70cd4..a845b6ccf9886 100644 --- a/code/modules/unit_tests/say.dm +++ b/code/modules/unit_tests/say.dm @@ -237,9 +237,9 @@ // Normally speaking, if there isn't a functional telecomms array on the same z-level, then handheld radios // have a short delay before sending the message. We use the centcom frequency to get around this. speaker_radio.set_frequency(FREQ_CENTCOM) - speaker_radio.independent = TRUE + speaker_radio.special_channels = RADIO_SPECIAL_CENTCOM listener_radio.set_frequency(FREQ_CENTCOM) - listener_radio.independent = TRUE + listener_radio.special_channels = RADIO_SPECIAL_CENTCOM var/pangram_quote = "The quick brown fox jumps over the lazy dog" diff --git a/code/modules/uplink/uplink_items/badass.dm b/code/modules/uplink/uplink_items/badass.dm index 08cf3affe0741..5c5e0390b5046 100644 --- a/code/modules/uplink/uplink_items/badass.dm +++ b/code/modules/uplink/uplink_items/badass.dm @@ -91,7 +91,7 @@ /datum/uplink_item/badass/stickers name = "Syndicate Sticker Pack" desc = "Contains 8 random stickers precisely engineered to resemble suspicious objects, which may or may not be useful for fooling crew." - item = /obj/item/storage/box/syndie_kit/stickers + item = /obj/item/storage/box/stickers/syndie_kit cost = 1 /datum/uplink_item/badass/demotivational_posters diff --git a/code/modules/uplink/uplink_items/stealthy.dm b/code/modules/uplink/uplink_items/stealthy.dm index e4c4de412fb44..6bd315498afa1 100644 --- a/code/modules/uplink/uplink_items/stealthy.dm +++ b/code/modules/uplink/uplink_items/stealthy.dm @@ -29,6 +29,12 @@ item = /obj/item/pen/edagger cost = 2 +/datum/uplink_item/stealthy_weapons/slipstick + name = "Syndie Lipstick" + desc = "Stylish way to kiss to death, isn't it syndiekisser?" + item = /obj/item/lipstick/syndie + cost = 6 + /datum/uplink_item/stealthy_weapons/traitor_chem_bottle name = "Poison Kit" desc = "An assortment of deadly chemicals packed into a compact box. Comes with a syringe for more precise application." diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index d28b510328a98..846d6a6434b1e 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -586,7 +586,7 @@ /obj/vehicle/sealed/mecha/proc/process_occupants(seconds_per_tick) for(var/mob/living/occupant as anything in occupants) - if(!(mecha_flags & IS_ENCLOSED) && occupant?.incapacitated()) //no sides mean it's easy to just sorta fall out if you're incapacitated. + if(!(mecha_flags & IS_ENCLOSED) && occupant?.incapacitated) //no sides mean it's easy to just sorta fall out if you're incapacitated. mob_exit(occupant, randomstep = TRUE) //bye bye continue if(cell && cell.maxcharge) @@ -658,7 +658,7 @@ if(phasing) balloon_alert(user, "not while [phasing]!") return - if(user.incapacitated()) + if(user.incapacitated) return if(!get_charge()) return diff --git a/code/modules/vehicles/mecha/equipment/tools/radio.dm b/code/modules/vehicles/mecha/equipment/tools/radio.dm index 33a113a8274f5..18740fc22b9bd 100644 --- a/code/modules/vehicles/mecha/equipment/tools/radio.dm +++ b/code/modules/vehicles/mecha/equipment/tools/radio.dm @@ -36,7 +36,7 @@ return TRUE if("set_frequency") var/new_frequency = text2num(params["new_frequency"]) - radio.set_frequency(sanitize_frequency(new_frequency, radio.freerange, radio.syndie)) + radio.set_frequency(sanitize_frequency(new_frequency, radio.freerange, (radio.special_channels & RADIO_SPECIAL_SYNDIE))) return TRUE return FALSE diff --git a/code/modules/vehicles/mecha/mecha_defense.dm b/code/modules/vehicles/mecha/mecha_defense.dm index 912993d1ee640..1237c931b33a5 100644 --- a/code/modules/vehicles/mecha/mecha_defense.dm +++ b/code/modules/vehicles/mecha/mecha_defense.dm @@ -317,7 +317,7 @@ if(!attacking_item.force) return - var/damage_taken = take_damage(attacking_item.force * attacking_item.demolition_mod, attacking_item.damtype, MELEE, 1) + var/damage_taken = take_damage(attacking_item.force * attacking_item.demolition_mod, attacking_item.damtype, MELEE, 1, get_dir(src, user)) try_damage_component(damage_taken, user.zone_selected) var/hit_verb = length(attacking_item.attack_verb_simple) ? "[pick(attacking_item.attack_verb_simple)]" : "hit" diff --git a/code/modules/vehicles/mecha/mecha_mob_interaction.dm b/code/modules/vehicles/mecha/mecha_mob_interaction.dm index 7a9141e80c1a7..a1e398f6f90cf 100644 --- a/code/modules/vehicles/mecha/mecha_mob_interaction.dm +++ b/code/modules/vehicles/mecha/mecha_mob_interaction.dm @@ -20,7 +20,7 @@ moved_inside(M) /obj/vehicle/sealed/mecha/enter_checks(mob/M) - if(M.incapacitated()) + if(M.incapacitated) return FALSE if(atom_integrity <= 0) to_chat(M, span_warning("You cannot get in the [src], it has been destroyed!")) diff --git a/code/modules/vehicles/mecha/mecha_ui.dm b/code/modules/vehicles/mecha/mecha_ui.dm index 1113a85381361..3c06c901e4e1f 100644 --- a/code/modules/vehicles/mecha/mecha_ui.dm +++ b/code/modules/vehicles/mecha/mecha_ui.dm @@ -121,26 +121,26 @@ )) if(ui_selected_module_index == module_index) ui_selected_module_index = null - continue - var/obj/item/mecha_parts/mecha_equipment/module = islist(equipment) ? equipment[i] : equipment - data += list(list( - "slot" = category, - "icon" = module.icon_state, - "name" = module.name, - "desc" = module.desc, - "detachable" = module.detachable, - "integrity" = (module.get_integrity()/module.max_integrity), - "can_be_toggled" = module.can_be_toggled, - "can_be_triggered" = module.can_be_triggered, - "active" = module.active, - "active_label" = module.active_label, - "equip_cooldown" = module.equip_cooldown && DisplayTimeText(module.equip_cooldown), - "energy_per_use" = module.energy_drain, - "snowflake" = module.get_snowflake_data(), - "ref" = REF(module), - )) - if(isnull(ui_selected_module_index)) - ui_selected_module_index = module_index + else + var/obj/item/mecha_parts/mecha_equipment/module = islist(equipment) ? equipment[i] : equipment + data += list(list( + "slot" = category, + "icon" = module.icon_state, + "name" = module.name, + "desc" = module.desc, + "detachable" = module.detachable, + "integrity" = (module.get_integrity()/module.max_integrity), + "can_be_toggled" = module.can_be_toggled, + "can_be_triggered" = module.can_be_triggered, + "active" = module.active, + "active_label" = module.active_label, + "equip_cooldown" = module.equip_cooldown && DisplayTimeText(module.equip_cooldown), + "energy_per_use" = module.energy_drain, + "snowflake" = module.get_snowflake_data(), + "ref" = REF(module), + )) + if(isnull(ui_selected_module_index)) + ui_selected_module_index = module_index module_index++ return data diff --git a/code/modules/vehicles/mecha/working/clarke.dm b/code/modules/vehicles/mecha/working/clarke.dm index 2ec0b4a473648..8b0c71b91ca31 100644 --- a/code/modules/vehicles/mecha/working/clarke.dm +++ b/code/modules/vehicles/mecha/working/clarke.dm @@ -77,15 +77,19 @@ /obj/item/mecha_parts/mecha_equipment/orebox_manager/get_snowflake_data() var/list/contents = chassis.ore_box?.contents var/list/contents_grouped = list() - for(var/obj/item/stack/ore/item as anything in contents) + for(var/atom/movable/item as anything in contents) + var/amount = 1 + if(isstack(item)) + var/obj/item/stack/stack = item + amount = stack.amount if(isnull(contents_grouped[item.icon_state])) var/ore_data = list() ore_data["name"] = item.name ore_data["icon"] = item.icon_state - ore_data["amount"] = item.amount + ore_data["amount"] = amount contents_grouped[item.icon_state] = ore_data else - contents_grouped[item.icon_state]["amount"] += item.amount + contents_grouped[item.icon_state]["amount"] += amount var/list/data = list( "snowflake_id" = MECHA_SNOWFLAKE_ID_OREBOX_MANAGER, "contents" = contents_grouped, diff --git a/code/modules/vehicles/scooter.dm b/code/modules/vehicles/scooter.dm index 82146976ad1f8..25e8ed9740943 100644 --- a/code/modules/vehicles/scooter.dm +++ b/code/modules/vehicles/scooter.dm @@ -169,7 +169,7 @@ pick_up_board(skater) /obj/vehicle/ridden/scooter/skateboard/proc/pick_up_board(mob/living/carbon/skater) - if (skater.incapacitated() || !Adjacent(skater)) + if (skater.incapacitated || !Adjacent(skater)) return if(has_buckled_mobs()) to_chat(skater, span_warning("You can't lift this up when somebody's on it.")) diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index 2a27433bdee6d..6fa163df26c06 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -988,7 +988,7 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock) var/list/weighted_crits = list() weighted_crits[CRUSH_CRIT_SHATTER_LEGS] = 100 - weighted_crits[CRUSH_CRIT_PARAPALEGIC] = 80 + weighted_crits[CRUSH_CRIT_PARAPLEGIC] = 80 weighted_crits[CRUSH_CRIT_HEADGIB] = 20 weighted_crits[CRUSH_CRIT_SQUISH_LIMB] = 100 @@ -1027,7 +1027,7 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock) if(left_leg || right_leg) carbon_target.visible_message(span_danger("[carbon_target]'s legs shatter with a sickening crunch!"), span_userdanger("Your legs shatter with a sickening crunch!")) return TRUE - if(CRUSH_CRIT_PARAPALEGIC) // paralyze this binch + if(CRUSH_CRIT_PARAPLEGIC) // paralyze this binch // the new paraplegic gets like 4 lines of losing their legs so skip them if (!iscarbon(atom_target)) return FALSE diff --git a/code/modules/vending/games.dm b/code/modules/vending/games.dm index 33fefd08d2e79..4053d5eb6cd1b 100644 --- a/code/modules/vending/games.dm +++ b/code/modules/vending/games.dm @@ -58,6 +58,7 @@ /obj/item/skillchip/sabrage = 2, /obj/item/skillchip/useless_adapter = 5, /obj/item/skillchip/wine_taster = 2, + /obj/item/skillchip/big_pointer = 2, ), ), list( diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm index 3b962490347a3..3d8a1f6cf60e2 100644 --- a/code/modules/vending/wardrobes.dm +++ b/code/modules/vending/wardrobes.dm @@ -331,7 +331,7 @@ GLOBAL_VAR_INIT(roaches_deployed, FALSE) /obj/item/storage/backpack/satchel/explorer = 1, /obj/item/storage/backpack/messenger/explorer = 1, /obj/item/storage/bag/books = 1, - /obj/item/radio/headset/headset_srv = 2, + /obj/item/radio/headset/headset_srvent = 2, ) refill_canister = /obj/item/vending_refill/wardrobe/curator_wardrobe payment_department = ACCOUNT_SRV diff --git a/code/modules/wiremod/shell/controller.dm b/code/modules/wiremod/shell/controller.dm index 126cc8894368f..ae0eb01b36763 100644 --- a/code/modules/wiremod/shell/controller.dm +++ b/code/modules/wiremod/shell/controller.dm @@ -53,7 +53,7 @@ /obj/item/circuit_component/controller/proc/handle_trigger(atom/source, user, port_name, datum/port/output/port_signal) source.balloon_alert(user, "clicked [port_name] button") - playsound(source, SFX_TERMINAL_TYPE, 25, FALSE) + playsound(source, SFX_KEYBOARD_CLICKS, 25, FALSE) entity.set_output(user) port_signal.set_output(COMPONENT_SIGNAL) diff --git a/icons/hud/screen_alert.dmi b/icons/hud/screen_alert.dmi index dda7d6cc635af..10d0b741f0b7c 100644 Binary files a/icons/hud/screen_alert.dmi and b/icons/hud/screen_alert.dmi differ diff --git a/icons/hud/screen_gen.dmi b/icons/hud/screen_gen.dmi index 9792124d1b68c..86383abbef1e2 100644 Binary files a/icons/hud/screen_gen.dmi and b/icons/hud/screen_gen.dmi differ diff --git a/icons/mob/actions/actions_items.dmi b/icons/mob/actions/actions_items.dmi index 7aaeb9b36d281..3887804e55ddc 100644 Binary files a/icons/mob/actions/actions_items.dmi and b/icons/mob/actions/actions_items.dmi differ diff --git a/icons/mob/clothing/accessories.dmi b/icons/mob/clothing/accessories.dmi index 57670005b9240..0e09772a79f50 100644 Binary files a/icons/mob/clothing/accessories.dmi and b/icons/mob/clothing/accessories.dmi differ diff --git a/icons/mob/clothing/back.dmi b/icons/mob/clothing/back.dmi index a96beb1cfa936..5bcaa41f5ed58 100644 Binary files a/icons/mob/clothing/back.dmi and b/icons/mob/clothing/back.dmi differ diff --git a/icons/mob/clothing/hands.dmi b/icons/mob/clothing/hands.dmi index b62b6a0a8ee58..449be68d4e531 100644 Binary files a/icons/mob/clothing/hands.dmi and b/icons/mob/clothing/hands.dmi differ diff --git a/icons/mob/clothing/head/hats.dmi b/icons/mob/clothing/head/hats.dmi index 5e76ab78608f2..1ff429b68b101 100644 Binary files a/icons/mob/clothing/head/hats.dmi and b/icons/mob/clothing/head/hats.dmi differ diff --git a/icons/mob/clothing/head/helmet.dmi b/icons/mob/clothing/head/helmet.dmi index 579f4c53f0f97..db48dda1fd61c 100644 Binary files a/icons/mob/clothing/head/helmet.dmi and b/icons/mob/clothing/head/helmet.dmi differ diff --git a/icons/mob/clothing/modsuit/mod_clothing.dmi b/icons/mob/clothing/modsuit/mod_clothing.dmi index cb2a472c32ed6..aa9b6feca11af 100644 Binary files a/icons/mob/clothing/modsuit/mod_clothing.dmi and b/icons/mob/clothing/modsuit/mod_clothing.dmi differ diff --git a/icons/mob/clothing/neck.dmi b/icons/mob/clothing/neck.dmi index 3467f752ac3a5..bd57cb6eee916 100644 Binary files a/icons/mob/clothing/neck.dmi and b/icons/mob/clothing/neck.dmi differ diff --git a/icons/mob/clothing/suits/armor.dmi b/icons/mob/clothing/suits/armor.dmi index ea80204c2cdcc..426a760e7700c 100644 Binary files a/icons/mob/clothing/suits/armor.dmi and b/icons/mob/clothing/suits/armor.dmi differ diff --git a/icons/mob/clothing/suits/utility.dmi b/icons/mob/clothing/suits/utility.dmi index 0ef867a2866b8..c8e85bf9a45c7 100644 Binary files a/icons/mob/clothing/suits/utility.dmi and b/icons/mob/clothing/suits/utility.dmi differ diff --git a/icons/mob/effects/blocking.dmi b/icons/mob/effects/blocking.dmi new file mode 100644 index 0000000000000..03872fa0fe36d Binary files /dev/null and b/icons/mob/effects/blocking.dmi differ diff --git a/icons/mob/human/human_face.dmi b/icons/mob/human/human_face.dmi index 886094ec49573..5b3b141c7edb0 100644 Binary files a/icons/mob/human/human_face.dmi and b/icons/mob/human/human_face.dmi differ diff --git a/icons/mob/human/species/misc/bodypart_overlay_simple.dmi b/icons/mob/human/species/misc/bodypart_overlay_simple.dmi index 8df76eb63147b..dbaaeec55cd24 100644 Binary files a/icons/mob/human/species/misc/bodypart_overlay_simple.dmi and b/icons/mob/human/species/misc/bodypart_overlay_simple.dmi differ diff --git a/icons/mob/inhands/items/devices_lefthand.dmi b/icons/mob/inhands/items/devices_lefthand.dmi index 48c47f872df3c..334d962e4057d 100644 Binary files a/icons/mob/inhands/items/devices_lefthand.dmi and b/icons/mob/inhands/items/devices_lefthand.dmi differ diff --git a/icons/mob/inhands/items/devices_righthand.dmi b/icons/mob/inhands/items/devices_righthand.dmi index f8f19a8709b15..d26bf452aa5ec 100644 Binary files a/icons/mob/inhands/items/devices_righthand.dmi and b/icons/mob/inhands/items/devices_righthand.dmi differ diff --git a/icons/mob/simple/carp.dmi b/icons/mob/simple/carp.dmi index 1be59c43ecb6e..e33b9c7ada810 100644 Binary files a/icons/mob/simple/carp.dmi and b/icons/mob/simple/carp.dmi differ diff --git a/icons/obj/art/painting_frames.dmi b/icons/obj/art/painting_frames.dmi new file mode 100644 index 0000000000000..28e1b8665962e Binary files /dev/null and b/icons/obj/art/painting_frames.dmi differ diff --git a/icons/obj/clothing/accessories.dmi b/icons/obj/clothing/accessories.dmi index 0253485cec327..578aebd0c65a1 100644 Binary files a/icons/obj/clothing/accessories.dmi and b/icons/obj/clothing/accessories.dmi differ diff --git a/icons/obj/clothing/belt_overlays.dmi b/icons/obj/clothing/belt_overlays.dmi index 7a215dcb9b1cc..0692033a5361b 100644 Binary files a/icons/obj/clothing/belt_overlays.dmi and b/icons/obj/clothing/belt_overlays.dmi differ diff --git a/icons/obj/clothing/gloves.dmi b/icons/obj/clothing/gloves.dmi index 4739498c16426..a4549f9e74b3b 100644 Binary files a/icons/obj/clothing/gloves.dmi and b/icons/obj/clothing/gloves.dmi differ diff --git a/icons/obj/clothing/head/hats.dmi b/icons/obj/clothing/head/hats.dmi index da4a30e996740..2ce0eebb2ad22 100644 Binary files a/icons/obj/clothing/head/hats.dmi and b/icons/obj/clothing/head/hats.dmi differ diff --git a/icons/obj/clothing/head/helmet.dmi b/icons/obj/clothing/head/helmet.dmi index cc54b2bf92934..621afe57ddce4 100644 Binary files a/icons/obj/clothing/head/helmet.dmi and b/icons/obj/clothing/head/helmet.dmi differ diff --git a/icons/obj/clothing/headsets.dmi b/icons/obj/clothing/headsets.dmi index b977487e2c6ce..57e67e5761a0c 100644 Binary files a/icons/obj/clothing/headsets.dmi and b/icons/obj/clothing/headsets.dmi differ diff --git a/icons/obj/clothing/modsuit/mod_clothing.dmi b/icons/obj/clothing/modsuit/mod_clothing.dmi index 6ab49417aa52f..160606c790afa 100644 Binary files a/icons/obj/clothing/modsuit/mod_clothing.dmi and b/icons/obj/clothing/modsuit/mod_clothing.dmi differ diff --git a/icons/obj/clothing/suits/armor.dmi b/icons/obj/clothing/suits/armor.dmi index b1763f5453ffe..b2c9a1aa8b430 100644 Binary files a/icons/obj/clothing/suits/armor.dmi and b/icons/obj/clothing/suits/armor.dmi differ diff --git a/icons/obj/clothing/suits/utility.dmi b/icons/obj/clothing/suits/utility.dmi index 25fb8fd502a35..f8e3c4ce46897 100644 Binary files a/icons/obj/clothing/suits/utility.dmi and b/icons/obj/clothing/suits/utility.dmi differ diff --git a/icons/obj/cosmetic.dmi b/icons/obj/cosmetic.dmi index b04bde541ad6c..e9f831fbc9690 100644 Binary files a/icons/obj/cosmetic.dmi and b/icons/obj/cosmetic.dmi differ diff --git a/icons/obj/devices/mecha_equipment.dmi b/icons/obj/devices/mecha_equipment.dmi index 90f0ce8c736cf..ebfa5438ae911 100644 Binary files a/icons/obj/devices/mecha_equipment.dmi and b/icons/obj/devices/mecha_equipment.dmi differ diff --git a/icons/obj/devices/voice.dmi b/icons/obj/devices/voice.dmi index 1e875d9323038..4188d7867eebd 100644 Binary files a/icons/obj/devices/voice.dmi and b/icons/obj/devices/voice.dmi differ diff --git a/icons/obj/drinks/bottles.dmi b/icons/obj/drinks/bottles.dmi index 205a67c84e20d..cd3cf9fef09d4 100644 Binary files a/icons/obj/drinks/bottles.dmi and b/icons/obj/drinks/bottles.dmi differ diff --git a/icons/obj/fishing.dmi b/icons/obj/fishing.dmi index 92d1cf9a12231..b1d5a787b202f 100644 Binary files a/icons/obj/fishing.dmi and b/icons/obj/fishing.dmi differ diff --git a/icons/obj/food/food.dmi b/icons/obj/food/food.dmi index 9ad8d3235e1f0..ad7421dbf6d3a 100644 Binary files a/icons/obj/food/food.dmi and b/icons/obj/food/food.dmi differ diff --git a/icons/obj/food/meat.dmi b/icons/obj/food/meat.dmi index bf0b1df4f4cd2..ca3007749e7e6 100644 Binary files a/icons/obj/food/meat.dmi and b/icons/obj/food/meat.dmi differ diff --git a/icons/obj/food/mexican.dmi b/icons/obj/food/mexican.dmi index ba02c15a0b577..772d6b2e3fc74 100644 Binary files a/icons/obj/food/mexican.dmi and b/icons/obj/food/mexican.dmi differ diff --git a/icons/obj/food/piecake.dmi b/icons/obj/food/piecake.dmi index e6c0a71022d50..1097c9d2acd3b 100644 Binary files a/icons/obj/food/piecake.dmi and b/icons/obj/food/piecake.dmi differ diff --git a/icons/obj/food/spaghetti.dmi b/icons/obj/food/spaghetti.dmi index 1c97a45e7b788..0d5e473e9b4b6 100644 Binary files a/icons/obj/food/spaghetti.dmi and b/icons/obj/food/spaghetti.dmi differ diff --git a/icons/obj/machines/big_manipulator.dmi b/icons/obj/machines/big_manipulator.dmi new file mode 100644 index 0000000000000..b6e878e189842 Binary files /dev/null and b/icons/obj/machines/big_manipulator.dmi differ diff --git a/icons/obj/machines/big_manipulator_parts/big_manipulator_core.dmi b/icons/obj/machines/big_manipulator_parts/big_manipulator_core.dmi new file mode 100644 index 0000000000000..614b4d51cbbf9 Binary files /dev/null and b/icons/obj/machines/big_manipulator_parts/big_manipulator_core.dmi differ diff --git a/icons/obj/machines/big_manipulator_parts/big_manipulator_hand.dmi b/icons/obj/machines/big_manipulator_parts/big_manipulator_hand.dmi new file mode 100644 index 0000000000000..e165441e8052e Binary files /dev/null and b/icons/obj/machines/big_manipulator_parts/big_manipulator_hand.dmi differ diff --git a/icons/obj/machines/gravity_generator.dmi b/icons/obj/machines/gravity_generator.dmi index 69395034dc840..18ad0ca0c20af 100644 Binary files a/icons/obj/machines/gravity_generator.dmi and b/icons/obj/machines/gravity_generator.dmi differ diff --git a/icons/obj/machines/ltsrbt.dmi b/icons/obj/machines/ltsrbt.dmi new file mode 100644 index 0000000000000..cdb7e06cbb3df Binary files /dev/null and b/icons/obj/machines/ltsrbt.dmi differ diff --git a/icons/obj/machines/telecomms.dmi b/icons/obj/machines/telecomms.dmi index f1380268c29cf..1d27e0b10b2d6 100644 Binary files a/icons/obj/machines/telecomms.dmi and b/icons/obj/machines/telecomms.dmi differ diff --git a/icons/obj/pipes_n_cables/disposal.dmi b/icons/obj/pipes_n_cables/disposal.dmi index 41207b7a7cd6f..a65413d3d007c 100644 Binary files a/icons/obj/pipes_n_cables/disposal.dmi and b/icons/obj/pipes_n_cables/disposal.dmi differ diff --git a/icons/obj/service/broadcast.dmi b/icons/obj/service/broadcast.dmi new file mode 100644 index 0000000000000..e82023791f3d6 Binary files /dev/null and b/icons/obj/service/broadcast.dmi differ diff --git a/icons/obj/service/janitor.dmi b/icons/obj/service/janitor.dmi index 0e30180832345..b340aa54cee09 100644 Binary files a/icons/obj/service/janitor.dmi and b/icons/obj/service/janitor.dmi differ diff --git a/icons/obj/service/library.dmi b/icons/obj/service/library.dmi index f9273a55e5530..5c393ae3c8622 100644 Binary files a/icons/obj/service/library.dmi and b/icons/obj/service/library.dmi differ diff --git a/icons/obj/smooth_structures/grav_field.dmi b/icons/obj/smooth_structures/grav_field.dmi new file mode 100644 index 0000000000000..4f51707938e9c Binary files /dev/null and b/icons/obj/smooth_structures/grav_field.dmi differ diff --git a/icons/obj/smooth_structures/grav_field.png b/icons/obj/smooth_structures/grav_field.png new file mode 100644 index 0000000000000..5177e57724049 Binary files /dev/null and b/icons/obj/smooth_structures/grav_field.png differ diff --git a/icons/obj/smooth_structures/grav_field.png.toml b/icons/obj/smooth_structures/grav_field.png.toml new file mode 100644 index 0000000000000..49f4000c213db --- /dev/null +++ b/icons/obj/smooth_structures/grav_field.png.toml @@ -0,0 +1,5 @@ +output_name = "grav_field" +template = "bitmask/diagonal_32x32.toml" + +[animation] +delays = [1, 1, 1] diff --git a/icons/obj/smooth_structures/grav_field_emissive.dmi b/icons/obj/smooth_structures/grav_field_emissive.dmi new file mode 100644 index 0000000000000..a2db63f082a5b Binary files /dev/null and b/icons/obj/smooth_structures/grav_field_emissive.dmi differ diff --git a/icons/obj/smooth_structures/grav_field_emissive.png b/icons/obj/smooth_structures/grav_field_emissive.png new file mode 100644 index 0000000000000..d3746ac5b63ac Binary files /dev/null and b/icons/obj/smooth_structures/grav_field_emissive.png differ diff --git a/icons/obj/smooth_structures/grav_field_emissive.png.toml b/icons/obj/smooth_structures/grav_field_emissive.png.toml new file mode 100644 index 0000000000000..ba6a7f73aaf7b --- /dev/null +++ b/icons/obj/smooth_structures/grav_field_emissive.png.toml @@ -0,0 +1,5 @@ +output_name = "grav_field_emissive" +template = "bitmask/diagonal_32x32.toml" + +[animation] +delays = [1, 1, 1] diff --git a/icons/obj/storage/box.dmi b/icons/obj/storage/box.dmi index 01588bd050f74..747fb5462c7df 100644 Binary files a/icons/obj/storage/box.dmi and b/icons/obj/storage/box.dmi differ diff --git a/icons/obj/storage/crates.dmi b/icons/obj/storage/crates.dmi index 46c61f8299767..a5a26c285a7d6 100644 Binary files a/icons/obj/storage/crates.dmi and b/icons/obj/storage/crates.dmi differ diff --git a/icons/obj/toys/stickers.dmi b/icons/obj/toys/stickers.dmi index 37780f5fd6cfe..80c0e138e38f9 100644 Binary files a/icons/obj/toys/stickers.dmi and b/icons/obj/toys/stickers.dmi differ diff --git a/icons/obj/vending_restock.dmi b/icons/obj/vending_restock.dmi index 836aebca7ae2d..ca8e40349c406 100644 Binary files a/icons/obj/vending_restock.dmi and b/icons/obj/vending_restock.dmi differ diff --git a/icons/obj/weapons/bows/quivers.dmi b/icons/obj/weapons/bows/quivers.dmi index 615f96ee6af6d..86e6ffd2b925a 100644 Binary files a/icons/obj/weapons/bows/quivers.dmi and b/icons/obj/weapons/bows/quivers.dmi differ diff --git a/icons/obj/weapons/cannons.dmi b/icons/obj/weapons/cannons.dmi index f0e37c5310ac6..b9735ba0aef9f 100644 Binary files a/icons/obj/weapons/cannons.dmi and b/icons/obj/weapons/cannons.dmi differ diff --git a/icons/obj/weapons/guns/ammo.dmi b/icons/obj/weapons/guns/ammo.dmi index 4cd031af7ee8b..971bdaf4d2041 100644 Binary files a/icons/obj/weapons/guns/ammo.dmi and b/icons/obj/weapons/guns/ammo.dmi differ diff --git a/icons/obj/weapons/guns/ballistic.dmi b/icons/obj/weapons/guns/ballistic.dmi index 824d8b7c0a073..4ebb17baec329 100644 Binary files a/icons/obj/weapons/guns/ballistic.dmi and b/icons/obj/weapons/guns/ballistic.dmi differ diff --git a/icons/obj/weapons/guns/projectiles.dmi b/icons/obj/weapons/guns/projectiles.dmi index a6cf89e9b910f..cbf79a92b538f 100644 Binary files a/icons/obj/weapons/guns/projectiles.dmi and b/icons/obj/weapons/guns/projectiles.dmi differ diff --git a/icons/ui/achievements/achievements.dmi b/icons/ui/achievements/achievements.dmi index 143d0dc0a03ae..740759467e0cc 100644 Binary files a/icons/ui/achievements/achievements.dmi and b/icons/ui/achievements/achievements.dmi differ diff --git a/interface/stylesheet.dm b/interface/stylesheet.dm index 1ee06ed48550d..e0e1181f93c98 100644 --- a/interface/stylesheet.dm +++ b/interface/stylesheet.dm @@ -51,6 +51,7 @@ em {font-style: normal; font-weight: bold;} .syndradio {color: #6d3f40;} .centcomradio {color: #686868;} .aiprivradio {color: #ff00ff;} +.enteradio {color: #00ff99;} .redteamradio {color: #ff0000;} .blueteamradio {color: #0000ff;} .greenteamradio {color: #00ff00;} diff --git a/modular_doppler/cryosleep/code/ai.dm b/modular_doppler/cryosleep/code/ai.dm index 5397311dc2f89..a134ee057f9a6 100644 --- a/modular_doppler/cryosleep/code/ai.dm +++ b/modular_doppler/cryosleep/code/ai.dm @@ -3,7 +3,7 @@ set desc = "Puts the current AI personality into cryogenic stasis, freeing the space for another." set category = "AI Commands" - if(incapacitated()) + if(IS_DEAD_OR_INCAP(src)) return switch(alert("Would you like to enter cryo? This will ghost you. Remember to AHELP before cryoing out of important roles, even with no admins online.",,"Yes.","No.")) if("Yes.") diff --git a/sound/ambience/antag/heretic/attribution.txt b/sound/ambience/antag/heretic/attribution.txt new file mode 100644 index 0000000000000..8744b2497f5bd --- /dev/null +++ b/sound/ambience/antag/heretic/attribution.txt @@ -0,0 +1 @@ +heretic_sacrifice.ogg - made by sadboysusss, License: CC-by-SA \ No newline at end of file diff --git a/sound/ambience/antag/heretic/heretic_sacrifice.ogg b/sound/ambience/antag/heretic/heretic_sacrifice.ogg new file mode 100644 index 0000000000000..5a8efb6508356 Binary files /dev/null and b/sound/ambience/antag/heretic/heretic_sacrifice.ogg differ diff --git a/sound/attributions.txt b/sound/attributions.txt index 123fde0794c19..3a2468205d027 100644 --- a/sound/attributions.txt +++ b/sound/attributions.txt @@ -209,3 +209,7 @@ beaker_pickup.ogg was made by lowering pitch: Bottle Tap.wav by alex_alexalex -- https://freesound.org/s/395492/ -- License: Attribution NonCommercial 3.0 beaker_place.ogg was made by cutting and lowering pitch: place glass object.wav by milpower -- https://freesound.org/s/353105/ -- License: Creative Commons 0 + +glass_reverse.ogg is adapted from a combination of: +https://freesound.org/people/C_Rogers/sounds/203368/ -- glass-shattering-hit_01.ogg by C_Rogers on freesound.org (CC0) +https://freesound.org/people/Czarcazas/sounds/330800/ -- Audio reversal/fading of Shattering Glass (Small) by Czarcazas -- https://freesound.org/s/330800/ -- License: Attribution 3.0 \ No newline at end of file diff --git a/sound/effects/energyshieldbash.ogg b/sound/effects/energyshieldbash.ogg new file mode 100644 index 0000000000000..c8d5bee557222 Binary files /dev/null and b/sound/effects/energyshieldbash.ogg differ diff --git a/sound/effects/glass_reverse.ogg b/sound/effects/glass_reverse.ogg new file mode 100644 index 0000000000000..af1492d9b86b4 Binary files /dev/null and b/sound/effects/glass_reverse.ogg differ diff --git a/sound/effects/muffspeech/muffspeech1.ogg b/sound/effects/muffspeech/muffspeech1.ogg new file mode 100644 index 0000000000000..b8b2f5f40b19d Binary files /dev/null and b/sound/effects/muffspeech/muffspeech1.ogg differ diff --git a/sound/effects/muffspeech/muffspeech2.ogg b/sound/effects/muffspeech/muffspeech2.ogg new file mode 100644 index 0000000000000..9ffecadf61e06 Binary files /dev/null and b/sound/effects/muffspeech/muffspeech2.ogg differ diff --git a/sound/effects/muffspeech/muffspeech3.ogg b/sound/effects/muffspeech/muffspeech3.ogg new file mode 100644 index 0000000000000..dff0e567daccc Binary files /dev/null and b/sound/effects/muffspeech/muffspeech3.ogg differ diff --git a/sound/effects/muffspeech/muffspeech4.ogg b/sound/effects/muffspeech/muffspeech4.ogg new file mode 100644 index 0000000000000..4e46c7a707acc Binary files /dev/null and b/sound/effects/muffspeech/muffspeech4.ogg differ diff --git a/sound/effects/muffspeech/muffspeech5.ogg b/sound/effects/muffspeech/muffspeech5.ogg new file mode 100644 index 0000000000000..ff1c9948c5621 Binary files /dev/null and b/sound/effects/muffspeech/muffspeech5.ogg differ diff --git a/sound/effects/muffspeech/muffspeech6.ogg b/sound/effects/muffspeech/muffspeech6.ogg new file mode 100644 index 0000000000000..13b70731ac3e0 Binary files /dev/null and b/sound/effects/muffspeech/muffspeech6.ogg differ diff --git a/sound/effects/muffspeech/muffspeech7.ogg b/sound/effects/muffspeech/muffspeech7.ogg new file mode 100644 index 0000000000000..ea566e6ef5872 Binary files /dev/null and b/sound/effects/muffspeech/muffspeech7.ogg differ diff --git a/sound/effects/muffspeech/muffspeech8.ogg b/sound/effects/muffspeech/muffspeech8.ogg new file mode 100644 index 0000000000000..ad51432d2da54 Binary files /dev/null and b/sound/effects/muffspeech/muffspeech8.ogg differ diff --git a/sound/effects/muffspeech/muffspeech9.ogg b/sound/effects/muffspeech/muffspeech9.ogg new file mode 100644 index 0000000000000..5d1be3b745f3e Binary files /dev/null and b/sound/effects/muffspeech/muffspeech9.ogg differ diff --git a/sound/items/attributions.txt b/sound/items/attributions.txt index 9ad1a09d8cb41..a9fa969808060 100644 --- a/sound/items/attributions.txt +++ b/sound/items/attributions.txt @@ -31,8 +31,6 @@ handcuffs_drop.ogg - handcuffs.ogg by kimuracarter -- https://freesound.org/s/52 handcuffs_pick_up.ogg - handcuffs.ogg by kimuracarter -- https://freesound.org/s/528749/ -- License: Attribution 3.0 plastic_shield_drop.ogg - made by sadboysuss -- License: CC-by-SA plastic_shield_pick_up.ogg - made by sadboysuss -- License: CC-by-SA -stun_baton_drop.ogg - Fn P90 Submachine Gun 5.7Mm. Mechan; Empty Mag Inserted Into And Pulled Out Slow And Various 02 by PNMCarrieRailfan -- https://freesound.org/s/682041/ -- License: Attribution NonCommercial 4.0 -stun_baton_pick_up.ogg - Fn P90 Submachine Gun 5.7Mm. Mechan; Empty Mag Inserted Into And Pulled Out Slow And Various 02 by PNMCarrieRailfan -- https://freesound.org/s/682041/ -- License: Attribution NonCommercial 4.0 pepper_spray_drop.ogg - Spray Paint Shake Slow Five.wav by cbakos -- https://freesound.org/s/200376/ -- License: Creative Commons 0 pepper_spray_pick_up.ogg - Spray Paint Shake Slow Five.wav by cbakos -- https://freesound.org/s/200376/ -- License: Creative Commons 0 grenade_drop.ogg - made by sadboysuss -- License: CC-by-SA @@ -56,3 +54,21 @@ gas_tank_drop.ogg gas_tank_pick_up.ogg } - https://freesound.org/people/Globofonia/sounds/698346/ , License CC0 edited by grungussuss + +{ +cardboad_box_open.ogg - made by sadboysuss +cardboad_box_rustle.ogg - made by sadboysuss +toolbox_open.ogg - made by sadboysuss +toolbox_rustle.ogg - made by sadboysuss +medkit_rustle.ogg - made by sadboysuss +} - license: CC-by-SA + +{ +glove_pick_up.ogg - made by sadboysuss +glove_drop.ogg - made by sadboysuss +} - license: CC-by-SA +glove_equip.ogg - LETHRCreak_Leather Belt Short Creak 01_PF_365 DAYS OF SOUND by itmightgetloud -- https://freesound.org/s/751281/ -- License: Creative Commons 0 + +lead_pipe_hit.ogg - jixaw-metal-pipe-falling-sound.mp3 by thenotcheeseman -- https://freesound.org/s/679206/ -- License: Creative Commons 0 +lead_pipe_drop.ogg - jixaw-metal-pipe-falling-sound.mp3 by thenotcheeseman -- https://freesound.org/s/679206/ -- License: Creative Commons 0 +lead_pipe_pickup.ogg - Metal pipe hitting the ground.flac by CGEffex -- https://freesound.org/s/93962/ -- License: Attribution 4.0 diff --git a/sound/items/baton/attribution.txt b/sound/items/baton/attribution.txt new file mode 100644 index 0000000000000..b580347bf6100 --- /dev/null +++ b/sound/items/baton/attribution.txt @@ -0,0 +1,12 @@ +stun_baton_inactive_drop.ogg - Fn P90 Submachine Gun 5.7Mm. Mechan; Empty Mag Inserted Into And Pulled Out Slow And Various 02 by PNMCarrieRailfan -- https://freesound.org/s/682041/ -- License: Attribution NonCommercial 4.0 +stun_baton_inactive_pickup.ogg - Fn P90 Submachine Gun 5.7Mm. Mechan; Empty Mag Inserted Into And Pulled Out Slow And Various 02 by PNMCarrieRailfan -- https://freesound.org/s/682041/ -- License: Attribution NonCommercial 4.0 +{ +telescopic_baton_folded_drop.ogg +telescopic_baton_folded_pickup.ogg +telescopic_baton_unfolded_drop.ogg +telescopic_baton_unfolded_pickup.ogg +} - made by sadboysuss, license: CC-BY-SA +contractor_baton_unfolded_drop.ogg is spliced with Taser by JavierZumer -- https://freesound.org/s/257236/ -- License: Attribution 4.0 +contractor_baton_unfolded_pickup.ogg is spliced with Taser by JavierZumer -- https://freesound.org/s/257236/ -- License: Attribution 4.0 +stun_baton_active_drop.ogg is stun_baton_inactive_drop.ogg spliced with Taser by JavierZumer -- https://freesound.org/s/257236/ -- License: Attribution 4.0 +stun_baton_active_pickup.ogg is stun_baton_inactive_pickup.ogg spliced with Taser by JavierZumer -- https://freesound.org/s/257236/ -- License: Attribution 4.0 diff --git a/sound/items/baton/contractor_baton_unfolded_drop.ogg b/sound/items/baton/contractor_baton_unfolded_drop.ogg new file mode 100644 index 0000000000000..acebcd9d053c0 Binary files /dev/null and b/sound/items/baton/contractor_baton_unfolded_drop.ogg differ diff --git a/sound/items/baton/contractor_baton_unfolded_pickup.ogg b/sound/items/baton/contractor_baton_unfolded_pickup.ogg new file mode 100644 index 0000000000000..59ebc61163850 Binary files /dev/null and b/sound/items/baton/contractor_baton_unfolded_pickup.ogg differ diff --git a/sound/items/baton/stun_baton_active_drop.ogg b/sound/items/baton/stun_baton_active_drop.ogg new file mode 100644 index 0000000000000..a5e7cc8474948 Binary files /dev/null and b/sound/items/baton/stun_baton_active_drop.ogg differ diff --git a/sound/items/baton/stun_baton_active_pickup.ogg b/sound/items/baton/stun_baton_active_pickup.ogg new file mode 100644 index 0000000000000..3f4908c094556 Binary files /dev/null and b/sound/items/baton/stun_baton_active_pickup.ogg differ diff --git a/sound/items/stun_baton_drop.ogg b/sound/items/baton/stun_baton_inactive_drop.ogg similarity index 100% rename from sound/items/stun_baton_drop.ogg rename to sound/items/baton/stun_baton_inactive_drop.ogg diff --git a/sound/items/stun_baton_pick_up.ogg b/sound/items/baton/stun_baton_inactive_pickup.ogg similarity index 100% rename from sound/items/stun_baton_pick_up.ogg rename to sound/items/baton/stun_baton_inactive_pickup.ogg diff --git a/sound/items/baton/telescopic_baton_folded_drop.ogg b/sound/items/baton/telescopic_baton_folded_drop.ogg new file mode 100644 index 0000000000000..e61d11d0540ed Binary files /dev/null and b/sound/items/baton/telescopic_baton_folded_drop.ogg differ diff --git a/sound/items/baton/telescopic_baton_folded_pickup.ogg b/sound/items/baton/telescopic_baton_folded_pickup.ogg new file mode 100644 index 0000000000000..b0f126a76d683 Binary files /dev/null and b/sound/items/baton/telescopic_baton_folded_pickup.ogg differ diff --git a/sound/items/baton/telescopic_baton_unfolded_drop.ogg b/sound/items/baton/telescopic_baton_unfolded_drop.ogg new file mode 100644 index 0000000000000..dc6a11a90aef2 Binary files /dev/null and b/sound/items/baton/telescopic_baton_unfolded_drop.ogg differ diff --git a/sound/items/baton/telescopic_baton_unfolded_pickup.ogg b/sound/items/baton/telescopic_baton_unfolded_pickup.ogg new file mode 100644 index 0000000000000..2a7eb3d27882b Binary files /dev/null and b/sound/items/baton/telescopic_baton_unfolded_pickup.ogg differ diff --git a/sound/items/equip/glove_equip.ogg b/sound/items/equip/glove_equip.ogg new file mode 100644 index 0000000000000..33ab18a5e6e6a Binary files /dev/null and b/sound/items/equip/glove_equip.ogg differ diff --git a/sound/items/handling/attribution.txt b/sound/items/handling/attribution.txt new file mode 100644 index 0000000000000..c1a72a40c3c91 --- /dev/null +++ b/sound/items/handling/attribution.txt @@ -0,0 +1,7 @@ +{ +rcd_drop.ogg - made by sadboysuss - license: CC-by-SA +rcd_pickup.ogg - made by sadboysuss - license: CC-by-SA +rpd_drop.ogg - made by sadboysuss - license: CC-by-SA +rpd_pickup.ogg - made by sadboysuss - license: CC-by-SA +tool_switch.ogg - made by sadboysuss - license: CC-by-SA +} - edited by sadboysuss \ No newline at end of file diff --git a/sound/items/handling/glove_drop.ogg b/sound/items/handling/glove_drop.ogg new file mode 100644 index 0000000000000..bfd490e94a8ae Binary files /dev/null and b/sound/items/handling/glove_drop.ogg differ diff --git a/sound/items/handling/glove_pick_up.ogg b/sound/items/handling/glove_pick_up.ogg new file mode 100644 index 0000000000000..1fd7de9e6b968 Binary files /dev/null and b/sound/items/handling/glove_pick_up.ogg differ diff --git a/sound/items/handling/rcd_drop.ogg b/sound/items/handling/rcd_drop.ogg new file mode 100644 index 0000000000000..276a014ae3123 Binary files /dev/null and b/sound/items/handling/rcd_drop.ogg differ diff --git a/sound/items/handling/rcd_pickup.ogg b/sound/items/handling/rcd_pickup.ogg new file mode 100644 index 0000000000000..bc7d103800bfa Binary files /dev/null and b/sound/items/handling/rcd_pickup.ogg differ diff --git a/sound/items/handling/rpd_drop.ogg b/sound/items/handling/rpd_drop.ogg new file mode 100644 index 0000000000000..8591719c918ea Binary files /dev/null and b/sound/items/handling/rpd_drop.ogg differ diff --git a/sound/items/handling/rpd_pickup.ogg b/sound/items/handling/rpd_pickup.ogg new file mode 100644 index 0000000000000..ef6bf685d0073 Binary files /dev/null and b/sound/items/handling/rpd_pickup.ogg differ diff --git a/sound/items/handling/tool_switch.ogg b/sound/items/handling/tool_switch.ogg new file mode 100644 index 0000000000000..b0cacda41623c Binary files /dev/null and b/sound/items/handling/tool_switch.ogg differ diff --git a/sound/items/lead_pipe_drop.ogg b/sound/items/lead_pipe_drop.ogg new file mode 100644 index 0000000000000..144d24ca94c7a Binary files /dev/null and b/sound/items/lead_pipe_drop.ogg differ diff --git a/sound/items/lead_pipe_hit.ogg b/sound/items/lead_pipe_hit.ogg new file mode 100644 index 0000000000000..51b4dbf60b146 Binary files /dev/null and b/sound/items/lead_pipe_hit.ogg differ diff --git a/sound/items/lead_pipe_pickup.ogg b/sound/items/lead_pipe_pickup.ogg new file mode 100644 index 0000000000000..559138d66a53f Binary files /dev/null and b/sound/items/lead_pipe_pickup.ogg differ diff --git a/sound/machines/computer/attribution.txt b/sound/machines/computer/attribution.txt new file mode 100644 index 0000000000000..ab10c922afb69 --- /dev/null +++ b/sound/machines/computer/attribution.txt @@ -0,0 +1,7 @@ +computer_clicks_1.ogg - made by sadboysuss, license: CC-by-SA +computer_clicks_2.ogg - made by sadboysuss, license: CC-by-SA +computer_clicks_3.ogg - made by sadboysuss, license: CC-by-SA +computer_clicks_4.ogg - made by sadboysuss, license: CC-by-SA +computer_clicks_5.ogg - made by sadboysuss, license: CC-by-SA +computer_clicks_6.ogg - made by sadboysuss, license: CC-by-SA +computer_clicks_7.ogg - made by sadboysuss, license: CC-by-SA \ No newline at end of file diff --git a/sound/machines/computer/keyboard_clicks_1.ogg b/sound/machines/computer/keyboard_clicks_1.ogg new file mode 100644 index 0000000000000..b33c6fd56a338 Binary files /dev/null and b/sound/machines/computer/keyboard_clicks_1.ogg differ diff --git a/sound/machines/computer/keyboard_clicks_2.ogg b/sound/machines/computer/keyboard_clicks_2.ogg new file mode 100644 index 0000000000000..64d810753c3cb Binary files /dev/null and b/sound/machines/computer/keyboard_clicks_2.ogg differ diff --git a/sound/machines/computer/keyboard_clicks_3.ogg b/sound/machines/computer/keyboard_clicks_3.ogg new file mode 100644 index 0000000000000..0e1bb3696f103 Binary files /dev/null and b/sound/machines/computer/keyboard_clicks_3.ogg differ diff --git a/sound/machines/computer/keyboard_clicks_4.ogg b/sound/machines/computer/keyboard_clicks_4.ogg new file mode 100644 index 0000000000000..b700393a9c38e Binary files /dev/null and b/sound/machines/computer/keyboard_clicks_4.ogg differ diff --git a/sound/machines/computer/keyboard_clicks_5.ogg b/sound/machines/computer/keyboard_clicks_5.ogg new file mode 100644 index 0000000000000..d54b211da0217 Binary files /dev/null and b/sound/machines/computer/keyboard_clicks_5.ogg differ diff --git a/sound/machines/computer/keyboard_clicks_6.ogg b/sound/machines/computer/keyboard_clicks_6.ogg new file mode 100644 index 0000000000000..84ff3bb7f8003 Binary files /dev/null and b/sound/machines/computer/keyboard_clicks_6.ogg differ diff --git a/sound/machines/computer/keyboard_clicks_7.ogg b/sound/machines/computer/keyboard_clicks_7.ogg new file mode 100644 index 0000000000000..39204e360c9f7 Binary files /dev/null and b/sound/machines/computer/keyboard_clicks_7.ogg differ diff --git a/sound/machines/gravgen/attribution.txt b/sound/machines/gravgen/attribution.txt new file mode 100644 index 0000000000000..f4aeab2c4902a --- /dev/null +++ b/sound/machines/gravgen/attribution.txt @@ -0,0 +1,6 @@ +{ +grav_gen_start.ogg +grav_gen_mid1.ogg +grav_gen_mid2.ogg - + Explosion 7b by LiamG_SFX -- https://freesound.org/s/322492/ -- License: Attribution NonCommercial 4.0 +grav_gen_end.ogg +} made by sadboysuss by editing a sound made by kayozz , license: CC-by-SA \ No newline at end of file diff --git a/sound/machines/gravgen/grav_gen_end.ogg b/sound/machines/gravgen/grav_gen_end.ogg new file mode 100644 index 0000000000000..a63305708d030 Binary files /dev/null and b/sound/machines/gravgen/grav_gen_end.ogg differ diff --git a/sound/machines/gravgen/grav_gen_mid1.ogg b/sound/machines/gravgen/grav_gen_mid1.ogg new file mode 100644 index 0000000000000..e6e38c11d467b Binary files /dev/null and b/sound/machines/gravgen/grav_gen_mid1.ogg differ diff --git a/sound/machines/gravgen/grav_gen_mid2.ogg b/sound/machines/gravgen/grav_gen_mid2.ogg new file mode 100644 index 0000000000000..cf112de1885b4 Binary files /dev/null and b/sound/machines/gravgen/grav_gen_mid2.ogg differ diff --git a/sound/machines/gravgen/grav_gen_start.ogg b/sound/machines/gravgen/grav_gen_start.ogg new file mode 100644 index 0000000000000..4a734e5517020 Binary files /dev/null and b/sound/machines/gravgen/grav_gen_start.ogg differ diff --git a/sound/machines/gravgen/gravgen_mid1.ogg b/sound/machines/gravgen/gravgen_mid1.ogg deleted file mode 100644 index de2744194bdc6..0000000000000 Binary files a/sound/machines/gravgen/gravgen_mid1.ogg and /dev/null differ diff --git a/sound/machines/gravgen/gravgen_mid2.ogg b/sound/machines/gravgen/gravgen_mid2.ogg deleted file mode 100644 index 7b09d566e91eb..0000000000000 Binary files a/sound/machines/gravgen/gravgen_mid2.ogg and /dev/null differ diff --git a/sound/machines/gravgen/gravgen_mid3.ogg b/sound/machines/gravgen/gravgen_mid3.ogg deleted file mode 100644 index 6e133b5fcfe60..0000000000000 Binary files a/sound/machines/gravgen/gravgen_mid3.ogg and /dev/null differ diff --git a/sound/machines/gravgen/gravgen_mid4.ogg b/sound/machines/gravgen/gravgen_mid4.ogg deleted file mode 100644 index 4f08f5e6d2273..0000000000000 Binary files a/sound/machines/gravgen/gravgen_mid4.ogg and /dev/null differ diff --git a/sound/machines/lever_start.ogg b/sound/machines/lever_start.ogg new file mode 100644 index 0000000000000..4160f39026ac0 Binary files /dev/null and b/sound/machines/lever_start.ogg differ diff --git a/sound/machines/lever_stop.ogg b/sound/machines/lever_stop.ogg new file mode 100644 index 0000000000000..22f8875019dd4 Binary files /dev/null and b/sound/machines/lever_stop.ogg differ diff --git a/sound/machines/license.txt b/sound/machines/license.txt index 6a54969a19170..0d7de5a5dfa3d 100644 --- a/sound/machines/license.txt +++ b/sound/machines/license.txt @@ -7,4 +7,8 @@ coffeemaker_brew.ogg originally made by Adriana Lopez (Acekat13X31), edited to r This is licensed under CC-BY 4.0, found at https://creativecommons.org/licenses/by/4.0/ shutter.ogg adapted from Joseph Sardin on BigSoundBank -https://bigsoundbank.com/detail-2475-manual-roller-shutter-closing-out-2.html \ No newline at end of file +https://bigsoundbank.com/detail-2475-manual-roller-shutter-closing-out-2.html + +lever_start.ogg and lever_stop.ogg are made by A_Kuha on FreeSound +https://freesound.org/people/A_Kuha/sounds/676412 +This is licensed under CC-0, found at https://creativecommons.org/publicdomain/zero/1.0/ diff --git a/sound/voice/breathing.ogg b/sound/voice/breathing.ogg deleted file mode 100644 index f940a1b211a6b..0000000000000 Binary files a/sound/voice/breathing.ogg and /dev/null differ diff --git a/sound/voice/breathing/attribution.txt b/sound/voice/breathing/attribution.txt new file mode 100644 index 0000000000000..20f8ef5df6d1e --- /dev/null +++ b/sound/voice/breathing/attribution.txt @@ -0,0 +1,10 @@ +{ +internals_breathing1.ogg +internals_breathing2.ogg +internals_breathing3.ogg +internals_breathing4.ogg +internals_breathing5.ogg +internals_breathing6.ogg +internals_breathing7.ogg +internals_breathing8.ogg +} - foley by sadboysuss, edited by Beeblie , license: CC-by-SA \ No newline at end of file diff --git a/sound/voice/breathing/internals_breathing1.ogg b/sound/voice/breathing/internals_breathing1.ogg new file mode 100644 index 0000000000000..e4f1d564ad697 Binary files /dev/null and b/sound/voice/breathing/internals_breathing1.ogg differ diff --git a/sound/voice/breathing/internals_breathing2.ogg b/sound/voice/breathing/internals_breathing2.ogg new file mode 100644 index 0000000000000..7b09c04cc62b5 Binary files /dev/null and b/sound/voice/breathing/internals_breathing2.ogg differ diff --git a/sound/voice/breathing/internals_breathing3.ogg b/sound/voice/breathing/internals_breathing3.ogg new file mode 100644 index 0000000000000..0ea34b9024b67 Binary files /dev/null and b/sound/voice/breathing/internals_breathing3.ogg differ diff --git a/sound/voice/breathing/internals_breathing4.ogg b/sound/voice/breathing/internals_breathing4.ogg new file mode 100644 index 0000000000000..30718fab3070e Binary files /dev/null and b/sound/voice/breathing/internals_breathing4.ogg differ diff --git a/sound/voice/breathing/internals_breathing5.ogg b/sound/voice/breathing/internals_breathing5.ogg new file mode 100644 index 0000000000000..c78354481955e Binary files /dev/null and b/sound/voice/breathing/internals_breathing5.ogg differ diff --git a/sound/voice/breathing/internals_breathing6.ogg b/sound/voice/breathing/internals_breathing6.ogg new file mode 100644 index 0000000000000..f415845902d98 Binary files /dev/null and b/sound/voice/breathing/internals_breathing6.ogg differ diff --git a/sound/voice/breathing/internals_breathing7.ogg b/sound/voice/breathing/internals_breathing7.ogg new file mode 100644 index 0000000000000..946c34d45f307 Binary files /dev/null and b/sound/voice/breathing/internals_breathing7.ogg differ diff --git a/sound/voice/breathing/internals_breathing8.ogg b/sound/voice/breathing/internals_breathing8.ogg new file mode 100644 index 0000000000000..36f4925612542 Binary files /dev/null and b/sound/voice/breathing/internals_breathing8.ogg differ diff --git a/tgstation.dme b/tgstation.dme index 62e3dad0ed50b..167d3398f4add 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -543,6 +543,7 @@ #include "code\_globalvars\time_vars.dm" #include "code\_globalvars\lists\achievements.dm" #include "code\_globalvars\lists\ambience.dm" +#include "code\_globalvars\lists\basic_ai.dm" #include "code\_globalvars\lists\canisters.dm" #include "code\_globalvars\lists\cargo.dm" #include "code\_globalvars\lists\client.dm" @@ -642,6 +643,7 @@ #include "code\controllers\subsystem\addiction.dm" #include "code\controllers\subsystem\admin_verbs.dm" #include "code\controllers\subsystem\ai_controllers.dm" +#include "code\controllers\subsystem\ai_idle_controllers.dm" #include "code\controllers\subsystem\air.dm" #include "code\controllers\subsystem\ambience.dm" #include "code\controllers\subsystem\area_contents.dm" @@ -762,6 +764,7 @@ #include "code\controllers\subsystem\processing\acid.dm" #include "code\controllers\subsystem\processing\ai_basic_avoidance.dm" #include "code\controllers\subsystem\processing\ai_behaviors.dm" +#include "code\controllers\subsystem\processing\ai_idle_behaviors.dm" #include "code\controllers\subsystem\processing\antag_hud.dm" #include "code\controllers\subsystem\processing\aura.dm" #include "code\controllers\subsystem\processing\clock_component.dm" @@ -860,6 +863,7 @@ #include "code\datums\actions\items\cult_dagger.dm" #include "code\datums\actions\items\hands_free.dm" #include "code\datums\actions\items\organ_action.dm" +#include "code\datums\actions\items\reload_rebar.dm" #include "code\datums\actions\items\set_internals.dm" #include "code\datums\actions\items\stealth_box.dm" #include "code\datums\actions\items\summon_stickmen.dm" @@ -1091,7 +1095,6 @@ #include "code\datums\components\cracked.dm" #include "code\datums\components\crank_recharge.dm" #include "code\datums\components\crate_carrier.dm" -#include "code\datums\components\creamed.dm" #include "code\datums\components\cuff_n_stun.dm" #include "code\datums\components\cult_ritual_item.dm" #include "code\datums\components\curse_of_hunger.dm" @@ -1118,6 +1121,7 @@ #include "code\datums\components\evolutionary_leap.dm" #include "code\datums\components\explodable.dm" #include "code\datums\components\explode_on_attack.dm" +#include "code\datums\components\face_decal.dm" #include "code\datums\components\faction_granter.dm" #include "code\datums\components\fertile_egg.dm" #include "code\datums\components\fish_growth.dm" @@ -1428,6 +1432,7 @@ #include "code\datums\elements\beauty.dm" #include "code\datums\elements\bed_tucking.dm" #include "code\datums\elements\befriend_petting.dm" +#include "code\datums\elements\block_turf_fingerprints.dm" #include "code\datums\elements\blocks_explosives.dm" #include "code\datums\elements\body_temp_sensitive.dm" #include "code\datums\elements\bombable_turf.dm" @@ -1857,7 +1862,6 @@ #include "code\datums\status_effects\agent_pinpointer.dm" #include "code\datums\status_effects\buffs.dm" #include "code\datums\status_effects\drug_effects.dm" -#include "code\datums\status_effects\food_effects.dm" #include "code\datums\status_effects\gas.dm" #include "code\datums\status_effects\grouped_effect.dm" #include "code\datums\status_effects\limited_effect.dm" @@ -1872,9 +1876,11 @@ #include "code\datums\status_effects\buffs\bioware\cortex.dm" #include "code\datums\status_effects\buffs\bioware\ligaments.dm" #include "code\datums\status_effects\buffs\bioware\nerves.dm" +#include "code\datums\status_effects\buffs\food\_food_effect.dm" #include "code\datums\status_effects\buffs\food\chilling.dm" -#include "code\datums\status_effects\buffs\food\food_traits.dm" +#include "code\datums\status_effects\buffs\food\grant_trait.dm" #include "code\datums\status_effects\buffs\food\haste.dm" +#include "code\datums\status_effects\buffs\food\speech.dm" #include "code\datums\status_effects\debuffs\blindness.dm" #include "code\datums\status_effects\debuffs\choke.dm" #include "code\datums\status_effects\debuffs\confusion.dm" @@ -2032,6 +2038,7 @@ #include "code\game\machinery\autolathe.dm" #include "code\game\machinery\bank_machine.dm" #include "code\game\machinery\barsigns.dm" +#include "code\game\machinery\big_manipulator.dm" #include "code\game\machinery\botlaunchpad.dm" #include "code\game\machinery\buttons.dm" #include "code\game\machinery\cell_charger.dm" @@ -2072,6 +2079,7 @@ #include "code\game\machinery\nebula_shielding.dm" #include "code\game\machinery\PDApainter.dm" #include "code\game\machinery\photobooth.dm" +#include "code\game\machinery\portagrav.dm" #include "code\game\machinery\prisongate.dm" #include "code\game\machinery\prisonlabor.dm" #include "code\game\machinery\quantum_pad.dm" @@ -2274,6 +2282,7 @@ #include "code\game\objects\effects\landmarks\atmospherics_sanity_landmarks.dm" #include "code\game\objects\effects\particles\acid.dm" #include "code\game\objects\effects\particles\fire.dm" +#include "code\game\objects\effects\particles\gravity.dm" #include "code\game\objects\effects\particles\misc.dm" #include "code\game\objects\effects\particles\note_particles.dm" #include "code\game\objects\effects\particles\slime.dm" @@ -2437,6 +2446,7 @@ #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\broadcast_camera.dm" #include "code\game\objects\items\devices\chameleonproj.dm" #include "code\game\objects\items\devices\destabilizing_crystal.dm" #include "code\game\objects\items\devices\desynchronizer.dm" @@ -3529,6 +3539,7 @@ #include "code\modules\awaymissions\signpost.dm" #include "code\modules\awaymissions\super_secret_room.dm" #include "code\modules\awaymissions\zlevel.dm" +#include "code\modules\awaymissions\mission_code\Beach.dm" #include "code\modules\awaymissions\mission_code\Cabin.dm" #include "code\modules\awaymissions\mission_code\caves.dm" #include "code\modules\awaymissions\mission_code\centcomAway.dm" @@ -3711,6 +3722,7 @@ #include "code\modules\cargo\markets\market_items\clothing.dm" #include "code\modules\cargo\markets\market_items\consumables.dm" #include "code\modules\cargo\markets\market_items\hostages.dm" +#include "code\modules\cargo\markets\market_items\local_goods.dm" #include "code\modules\cargo\markets\market_items\misc.dm" #include "code\modules\cargo\markets\market_items\stolen_goods.dm" #include "code\modules\cargo\markets\market_items\tools.dm" @@ -3774,6 +3786,7 @@ #include "code\modules\client\preferences\operative_species.dm" #include "code\modules\client\preferences\paint_color.dm" #include "code\modules\client\preferences\parallax.dm" +#include "code\modules\client\preferences\paraplegic.dm" #include "code\modules\client\preferences\pda.dm" #include "code\modules\client\preferences\persistent_scars.dm" #include "code\modules\client\preferences\phobia.dm" @@ -3854,6 +3867,7 @@ #include "code\modules\clothing\gloves\costume.dm" #include "code\modules\clothing\gloves\insulated.dm" #include "code\modules\clothing\gloves\plasmaman.dm" +#include "code\modules\clothing\gloves\punch_mitts.dm" #include "code\modules\clothing\gloves\special.dm" #include "code\modules\clothing\gloves\tacklers.dm" #include "code\modules\clothing\head\_head.dm" @@ -4473,7 +4487,8 @@ #include "code\modules\library\random_books.dm" #include "code\modules\library\skill_learning\skill_station.dm" #include "code\modules\library\skill_learning\skillchip.dm" -#include "code\modules\library\skill_learning\generic_skillchips\matrix_flip.dm" +#include "code\modules\library\skill_learning\generic_skillchips\matrix_taunt.dm" +#include "code\modules\library\skill_learning\generic_skillchips\point.dm" #include "code\modules\library\skill_learning\generic_skillchips\rod_suplex.dm" #include "code\modules\library\skill_learning\job_skillchips\_job.dm" #include "code\modules\library\skill_learning\job_skillchips\chef.dm" diff --git a/tgui/packages/tgui-panel/chat/constants.ts b/tgui/packages/tgui-panel/chat/constants.ts index 2efc1d0a3ec06..57ad525a9a9aa 100644 --- a/tgui/packages/tgui-panel/chat/constants.ts +++ b/tgui/packages/tgui-panel/chat/constants.ts @@ -60,7 +60,7 @@ export const MESSAGE_TYPES = [ name: 'Radio', description: 'All departments of radio messages', selector: - '.alert, .minorannounce, .syndradio, .centcomradio, .aiprivradio, .comradio, .secradio, .gangradio, .engradio, .medradio, .sciradio, .suppradio, .servradio, .radio, .deptradio, .binarysay, .newscaster, .resonate, .abductor, .alien, .changeling', + '.alert, .minorannounce, .syndradio, .centcomradio, .aiprivradio, .enteradio, .comradio, .secradio, .gangradio, .engradio, .medradio, .sciradio, .suppradio, .servradio, .radio, .deptradio, .binarysay, .newscaster, .resonate, .abductor, .alien, .changeling', }, { type: MESSAGE_TYPE_INFO, diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss index 2ce4afbafd1db..efd8b7df9e642 100644 --- a/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss +++ b/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss @@ -373,6 +373,10 @@ em { color: #d65d95; } +.enteradio { + color: #00ff99; +} + .redteamradio { color: #ff4444 !important; } diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss index b73bfef990d9d..bb0673869a0cb 100644 --- a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss +++ b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss @@ -390,6 +390,10 @@ em { color: #ff00ff; } +.enteradio { + color: #00d680; +} + .redteamradio { color: #ff0000 !important; } diff --git a/tgui/packages/tgui-say/constants.ts b/tgui/packages/tgui-say/constants.ts index 0c3d7943c2676..fba5562ccb201 100644 --- a/tgui/packages/tgui-say/constants.ts +++ b/tgui/packages/tgui-say/constants.ts @@ -25,6 +25,7 @@ export const RADIO_PREFIXES = { ':m ': 'Med', ':n ': 'Sci', ':o ': 'AI', + ':p ': 'Ent', ':s ': 'Sec', ':t ': 'Synd', ':u ': 'Supp', diff --git a/tgui/packages/tgui-say/styles/colors.scss b/tgui/packages/tgui-say/styles/colors.scss index ded5ffeeb9729..a6b492247187b 100644 --- a/tgui/packages/tgui-say/styles/colors.scss +++ b/tgui/packages/tgui-say/styles/colors.scss @@ -18,6 +18,7 @@ $_channel_map: ( 'Me': #5975da, 'Med': #57b8f0, 'OOC': #cca300, + 'Ent': #00ff99, 'Radio': #1ecc43, 'Say': #a4bad6, 'Sci': #c68cfa, diff --git a/tgui/packages/tgui/components/Input.tsx b/tgui/packages/tgui/components/Input.tsx index 9bc48aa809406..0e6ed7e258810 100644 --- a/tgui/packages/tgui/components/Input.tsx +++ b/tgui/packages/tgui/components/Input.tsx @@ -59,6 +59,8 @@ type OptionalProps = Partial<{ placeholder: string; /** Clears the input value on enter */ selfClear: boolean; + /** Auto-updates the input value on props change */ + updateOnPropsChange: boolean; /** The state variable of the input. */ value: string | number; }>; @@ -96,6 +98,7 @@ export function Input(props: Props) { placeholder, selfClear, value, + updateOnPropsChange, ...rest } = props; @@ -155,6 +158,19 @@ export function Input(props: Props) { }, 1); }, []); + if (updateOnPropsChange) { + /** Updates the initial value on props change */ + useEffect(() => { + const input = inputRef.current; + if (!input) return; + + const newValue = toInputValue(value); + if (input.value === newValue) return; + + input.value = newValue; + }, [value]); + } + return ( { + const { data, act } = useBackend(); + const { active } = data; + return ( + + +
+ +
+
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/BlackMarketUplink.tsx b/tgui/packages/tgui/interfaces/BlackMarketUplink.tsx index 51d397d500cd8..9dea92bedbeba 100644 --- a/tgui/packages/tgui/interfaces/BlackMarketUplink.tsx +++ b/tgui/packages/tgui/interfaces/BlackMarketUplink.tsx @@ -2,6 +2,7 @@ import { AnimatedNumber, Box, Button, + Image, Modal, Section, Stack, @@ -36,6 +37,7 @@ type Item = { desc: string; amount: number; cost: number; + html_icon: string; }; type DeliveryMethod = { @@ -106,8 +108,22 @@ export const BlackMarketUplink = (props) => { {items.map((item) => ( - - {item.name} + + + {!!item.html_icon && ( + + + + )} + + {item.name} + + {item.amount ? item.amount + ' in stock' : 'Out of stock'} diff --git a/tgui/packages/tgui/interfaces/BorgShaker.tsx b/tgui/packages/tgui/interfaces/BorgShaker.tsx index b16a68a39181c..bfcd716cb2bc9 100644 --- a/tgui/packages/tgui/interfaces/BorgShaker.tsx +++ b/tgui/packages/tgui/interfaces/BorgShaker.tsx @@ -9,6 +9,8 @@ type BorgShakerContext = { sodas: Reagent[]; alcohols: Reagent[]; selectedReagent: string; + reagentSearchContainer: ContainerPreference; + apparatusHasItem: boolean; }; type Reagent = { @@ -17,8 +19,13 @@ type Reagent = { description: string; }; +enum ContainerPreference { + BeverageApparatus = 'beverage_apparatus', + InternalBeaker = 'internal_beaker', +} + export const BorgShaker = (props) => { - const { data } = useBackend(); + const { act, data } = useBackend(); const { theme, minVolume, sodas, alcohols, selectedReagent } = data; const dynamicHeight = @@ -29,7 +36,58 @@ export const BorgShaker = (props) => { return ( -
+
+