diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm index 444837a49a..8595d321fb 100644 --- a/_maps/map_files/BoxStation/BoxStation.dmm +++ b/_maps/map_files/BoxStation/BoxStation.dmm @@ -1492,6 +1492,10 @@ /obj/structure/lattice/catwalk, /turf/open/space, /area/solar/starboard/fore) +"adu" = ( +/obj/effect/landmark/barthpot, +/turf/open/floor/wood, +/area/library) "adw" = ( /obj/structure/cable, /obj/structure/lattice/catwalk, @@ -105520,7 +105524,7 @@ aIt aPd aIt aPb -aIt +adu aXu aYW bat diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm index ca97d52539..3521a6d637 100644 --- a/code/__DEFINES/say.dm +++ b/code/__DEFINES/say.dm @@ -79,8 +79,14 @@ #define LINGHIVE_LINK 3 //whether the emote is visible or audible. +// Requires sight #define EMOTE_VISIBLE 1 +// Requires hearing #define EMOTE_AUDIBLE 2 +// Requires sight or hearing +#define EMOTE_BOTH 3 +// Always able to be seen +#define EMOTE_OMNI 4 //Don't set this very much higher then 1024 unless you like inviting people in to dos your server with message spam #define MAX_MESSAGE_LEN 2048 //Citadel edit: What's the WORST that could happen? diff --git a/code/__DEFINES/species.dm b/code/__DEFINES/species.dm index 087d317919..13206ec0fa 100644 --- a/code/__DEFINES/species.dm +++ b/code/__DEFINES/species.dm @@ -33,6 +33,7 @@ #define SPECIES_SYNTH "synth" #define SPECIES_SYNTH_MIL "military_synth" #define SPECIES_VAMPIRE "vampire" + #define SPECIES_VAMPIRE_WEAK "vampire_roundstart" #define SPECIES_XENOHYBRID "xeno" #define SPECIES_ZOMBIE "zombie" diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 520f205381..82302a2e06 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -208,10 +208,9 @@ #define TRAIT_FAST_PUMP "fast_pump" #define TRAIT_NO_PROCESS_FOOD "no-process-food" // You don't get benefits from nutriment, nor nutrition from reagent consumables #define TRAIT_NICE_SHOT "nice_shot" //hnnnnnnnggggg..... you're pretty good... -/// Prevents stamina buffer regeneration -#define TRAIT_NO_STAMINA_BUFFER_REGENERATION "block_stamina_buffer_regen" -/// Prevents stamina regeneration -#define TRAIT_NO_STAMINA_REGENERATION "block_stamina_regen" +#define TRAIT_NO_STAMINA_BUFFER_REGENERATION "block_stamina_buffer_regen" /// Prevents stamina buffer regeneration +#define TRAIT_NO_STAMINA_REGENERATION "block_stamina_regen" /// Prevents stamina regeneration +#define TRAIT_ARMOR_BROKEN "armor_broken" //acts as if you are wearing no clothing when taking damage, does not affect non-clothing sources of protection // mobility flag traits // IN THE FUTURE, IT WOULD BE NICE TO DO SOMETHING SIMILAR TO https://github.com/tgstation/tgstation/pull/48923/files (ofcourse not nearly the same because I have my.. thoughts on it) diff --git a/code/datums/components/squeak.dm b/code/datums/components/squeak.dm index b8191a377b..0552a791ea 100644 --- a/code/datums/components/squeak.dm +++ b/code/datums/components/squeak.dm @@ -46,6 +46,21 @@ if(isnum(use_delay_override)) use_delay = use_delay_override +/datum/component/squeak/UnregisterFromParent() + if(!isatom(parent)) + return + UnregisterSignal(parent, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_BLOB_ACT, COMSIG_ATOM_HULK_ATTACK, COMSIG_PARENT_ATTACKBY)) + if(ismovable(parent)) + UnregisterSignal(parent, list(COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_IMPACT, + COMSIG_MOVABLE_CROSSED, COMSIG_ITEM_WEARERCROSSED, COMSIG_MOVABLE_CROSS, + COMSIG_CROSS_SQUEAKED, COMSIG_MOVABLE_DISPOSING)) + if(isitem(parent)) + UnregisterSignal(parent, list(COMSIG_ITEM_ATTACK, COMSIG_ITEM_ATTACK_OBJ, COMSIG_ITEM_HIT_REACT, COMSIG_ITEM_ATTACK_SELF, + COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED)) + if(istype(parent, /obj/item/clothing/shoes)) + UnregisterSignal(parent, COMSIG_SHOES_STEP_ACTION) + return ..() + /datum/component/squeak/proc/play_squeak() do_play_squeak() diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm index 1749026f53..94ab538e9d 100644 --- a/code/datums/emotes.dm +++ b/code/datums/emotes.dm @@ -69,9 +69,13 @@ M.show_message(dchatmsg) //SKYRAT CHANGE if(emote_type == EMOTE_AUDIBLE) - user.audible_message(msg, user_msg = TRUE, runechat_popup = chat_popup) //SKYRAT CHANGE - else - user.visible_message(msg, user_msg = TRUE, runechat_popup = chat_popup) //SKYRAT CHANGE + user.audible_message(msg, runechat_popup = chat_popup) + else if(emote_type == EMOTE_VISIBLE) + user.visible_message(msg, runechat_popup = chat_popup) + else if(emote_type == EMOTE_BOTH) + user.visible_message(msg, blind_message = msg, runechat_popup = chat_popup) + else if(emote_type == EMOTE_OMNI) + user.visible_message(msg, omni = TRUE, runechat_popup = chat_popup) //Skyrat change if(image_popup) flick_emote_popup_on_mob(user, image_popup, 40) diff --git a/code/datums/mutations/_mutations.dm b/code/datums/mutations/_mutations.dm index 3bddfdaa63..b72874c329 100644 --- a/code/datums/mutations/_mutations.dm +++ b/code/datums/mutations/_mutations.dm @@ -150,7 +150,6 @@ overlays_standing[CM.layer_used] = mut_overlay apply_overlay(CM.layer_used) - /datum/mutation/human/proc/modify() //called when a genome is applied so we can properly update some stats without having to remove and reapply the mutation from someone if(modified || !power || !owner) return diff --git a/code/game/machinery/announcement_system.dm b/code/game/machinery/announcement_system.dm index da82b0afc7..f46169f72e 100644 --- a/code/game/machinery/announcement_system.dm +++ b/code/game/machinery/announcement_system.dm @@ -114,7 +114,7 @@ GLOBAL_LIST_EMPTY(announcement_systems) . = ..() if(.) return - if(!usr.canUseTopic(src, !issilicon(usr))) + if(!usr.canUseTopic(src, !hasSiliconAccessInArea(usr))) return if(stat & BROKEN) visible_message("[src] buzzes.", "You hear a faint buzz.") @@ -147,7 +147,7 @@ GLOBAL_LIST_EMPTY(announcement_systems) . = attack_ai(user) /obj/machinery/announcement_system/attack_ai(mob/user) - if(!user.canUseTopic(src, !issilicon(user))) + if(!user.canUseTopic(src, !hasSiliconAccessInArea(user))) return if(stat & BROKEN) to_chat(user, "[src]'s firmware appears to be malfunctioning!") @@ -167,7 +167,9 @@ GLOBAL_LIST_EMPTY(announcement_systems) act_up() /obj/machinery/announcement_system/emag_act() + . = ..() if(obj_flags & EMAGGED) return obj_flags |= EMAGGED act_up() + return TRUE diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm index 401d05da12..9b911e9c15 100644 --- a/code/game/machinery/computer/robot.dm +++ b/code/game/machinery/computer/robot.dm @@ -21,6 +21,9 @@ return if(R.scrambledcodes) return + if(hasSiliconAccessInArea(user) && !issilicon(user)) + if(!Adjacent(user)) + return return TRUE /obj/machinery/computer/robotics/ui_interact(mob/user, datum/tgui/ui) @@ -40,6 +43,10 @@ else if(IsAdminGhost(user)) data["can_hack"] = TRUE + data["can_convert"] = FALSE + if(isAI(user) && is_servant_of_ratvar(user)) + data["can_convert"] = TRUE + data["cyborgs"] = list() for(var/mob/living/silicon/robot/R in GLOB.silicon_mobs) if(!can_control(user, R)) @@ -54,6 +61,7 @@ module = R.module ? "[R.module.name] Module" : "No Module Detected", synchronization = R.connected_ai, emagged = R.emagged, + servant = is_servant_of_ratvar(R), ref = REF(R) ) data["cyborgs"] += list(cyborg_data) @@ -110,6 +118,13 @@ log_game("[key_name(usr)] emagged [key_name(R)] using robotic console!") message_admins("[ADMIN_LOOKUPFLW(usr)] emagged cyborg [key_name_admin(R)] using robotic console!") R.SetEmagged(TRUE) + if("convert") + if(isAI(usr) && is_servant_of_ratvar(usr)) + var/mob/living/silicon/robot/R = locate(params["ref"]) in GLOB.silicon_mobs + if(istype(R) && !is_servant_of_ratvar(R) && R.connected_ai == usr) + log_game("[key_name(usr)] converted [key_name(R)] using robotic console!") + message_admins("[ADMIN_LOOKUPFLW(usr)] converted cyborg [key_name_admin(R)] using robotic console!") + add_servant_of_ratvar(R) if("killdrone") if(allowed(usr)) var/mob/living/simple_animal/drone/D = locate(params["ref"]) in GLOB.mob_list diff --git a/code/game/machinery/dna_scanner.dm b/code/game/machinery/dna_scanner.dm index e721e986d2..0dcb0e7235 100644 --- a/code/game/machinery/dna_scanner.dm +++ b/code/game/machinery/dna_scanner.dm @@ -32,6 +32,8 @@ . = ..() if(in_range(user, src) || isobserver(user)) . += "The status display reads: Radiation pulse accuracy increased by factor [precision_coeff**2].
Radiation pulse damage decreased by factor [damage_coeff**2].
" + if(scan_level >= 3) + . += "Scanner has been upgraded to support autoprocessing." /obj/machinery/dna_scannernew/update_icon_state() //no power or maintenance @@ -94,6 +96,13 @@ ..(user) +// search for ghosts, if the corpse is empty and the scanner is connected to a cloner + var/mob/living/mob_occupant = get_mob_or_brainmob(occupant) + if(istype(mob_occupant)) + if(locate_computer(/obj/machinery/computer/cloning)) + if(!mob_occupant.suiciding && !(HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && !mob_occupant.hellbound) + mob_occupant.notify_ghost_cloning("Your corpse has been placed into a cloning scanner. Re-enter your corpse if you want to be cloned!", source = src) + // DNA manipulators cannot operate on severed heads or brains if(iscarbon(occupant)) if(linked_console) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 515a4672a5..9ef34390f6 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1457,6 +1457,16 @@ ui.open() return TRUE +/obj/machinery/door/airlock/ui_status(mob/user) + . = ..() + if (!issilicon(user) && hasSiliconAccessInArea(user)) + . = UI_INTERACTIVE + +/obj/machinery/door/airlock/can_interact(mob/user) + . = ..() + if (!issilicon(user) && hasSiliconAccessInArea(user)) + return TRUE + /obj/machinery/door/airlock/ui_data() var/list/data = list() diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index 4777796331..ecc8f9187a 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -616,7 +616,7 @@ if(defib.healdisk) H.heal_overall_damage(25, 25) var/list/policies = CONFIG_GET(keyed_list/policyconfig) - var/timelimit = CONFIG_GET(number/defib_cmd_time_limit) + var/timelimit = CONFIG_GET(number/defib_cmd_time_limit) * 10 //the config is in seconds, not deciseconds var/late = timelimit && (tplus > timelimit) var/policy = late? policies[POLICYCONFIG_ON_DEFIB_LATE] : policies[POLICYCONFIG_ON_DEFIB_INTACT] if(policy) diff --git a/code/game/objects/items/implants/implant_hijack.dm b/code/game/objects/items/implants/implant_hijack.dm index 36e58d8887..06d2df9272 100644 --- a/code/game/objects/items/implants/implant_hijack.dm +++ b/code/game/objects/items/implants/implant_hijack.dm @@ -92,10 +92,17 @@ /obj/item/implant/hijack/proc/hijack_remotely(obj/machinery/power/apc/apc) if (apc.hijacker || hijacking) return FALSE //can't remotely hijack an already hijacked APC + + if(apc.being_hijacked) + to_chat(imp_in, "This APC is already being hijacked!") + return FALSE + + apc.being_hijacked = TRUE hijacking = TRUE to_chat(imp_in, "Establishing remote connection with APC.") if (!do_after(imp_in, 4 SECONDS,target=apc)) to_chat(imp_in, "Aborting.") + apc.being_hijacked = FALSE hijacking = FALSE return TRUE if (LAZYLEN(imp_in.siliconaccessareas) >= HIJACK_APC_MAX_AMOUNT) @@ -118,6 +125,7 @@ toggle_eyes() else to_chat(imp_in, "Aborting.") + apc.being_hijacked = FALSE hijacking = FALSE imp_in.light_power = 0 imp_in.light_range = 0 diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm index a2a55ee6b1..6049ee965e 100644 --- a/code/modules/atmospherics/machinery/airalarm.dm +++ b/code/modules/atmospherics/machinery/airalarm.dm @@ -237,12 +237,21 @@ . += "Alt-click to [locked ? "unlock" : "lock"] the interface." /obj/machinery/airalarm/ui_status(mob/user) - if(hasSiliconAccessInArea(user) && aidisabled) - to_chat(user, "AI control has been disabled.") - else if(!shorted) + if(hasSiliconAccessInArea(user)) + if(aidisabled) + to_chat(user, "AI control has been disabled") + return UI_CLOSE + else if(!issilicon(user)) //True sillycones use ..() + return UI_INTERACTIVE + if(!shorted) return ..() return UI_CLOSE +/obj/machinery/airalarm/can_interact(mob/user) + . = ..() + if (!issilicon(user) && hasSiliconAccessInArea(user)) + return TRUE + /obj/machinery/airalarm/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) diff --git a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm index a07f131d62..9aa3c8c16d 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm @@ -196,8 +196,8 @@ icon_state = "inje_map-1" /obj/machinery/atmospherics/components/unary/outlet_injector/layer3 - piping_layer = 2 - icon_state = "inje_map-2" + piping_layer = 3 + icon_state = "inje_map-3" /obj/machinery/atmospherics/components/unary/outlet_injector/on on = TRUE @@ -207,8 +207,8 @@ icon_state = "inje_map-1" /obj/machinery/atmospherics/components/unary/outlet_injector/on/layer3 - piping_layer = 2 - icon_state = "inje_map-2" + piping_layer = 3 + icon_state = "inje_map-3" /obj/machinery/atmospherics/components/unary/outlet_injector/atmos frequency = FREQ_ATMOS_STORAGE diff --git a/code/modules/events/anomaly.dm b/code/modules/events/anomaly.dm index 394294db37..1b0c19274b 100644 --- a/code/modules/events/anomaly.dm +++ b/code/modules/events/anomaly.dm @@ -44,7 +44,13 @@ priority_announce("Localized energetic flux wave detected on long range scanners. Expected location of impact: [impact_area.name].", "Anomaly Alert") /datum/round_event/anomaly/start() - var/turf/T = pick(get_area_turfs(impact_area)) + var/list/turf/valid = list() + for(var/i in get_area_turfs(impact_area)) + var/turf/T = i + if(T.density) + continue + valid += T + var/turf/T = pick(valid) var/newAnomaly if(T) newAnomaly = new anomaly_path(T) diff --git a/code/modules/events/pirates.dm b/code/modules/events/pirates.dm index 3bcec9f471..8bada6da77 100644 --- a/code/modules/events/pirates.dm +++ b/code/modules/events/pirates.dm @@ -219,7 +219,7 @@ suit_type = /obj/item/clothing/suit/space helmet_type = /obj/item/clothing/head/helmet/space mask_type = /obj/item/clothing/mask/breath - storage_type = /obj/item/tank/internals/oxygen + storage_type = /obj/item/tank/jetpack/void /obj/machinery/loot_locator @@ -275,6 +275,7 @@ /obj/machinery/computer/piratepad_control name = "cargo hold control terminal" + resistance_flags = INDESTRUCTIBLE ui_x = 600 ui_y = 230 var/status_report = "Ready for delivery." diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm index 429dc98e8a..2ca4d5fd2e 100644 --- a/code/modules/mining/laborcamp/laborstacker.dm +++ b/code/modules/mining/laborcamp/laborstacker.dm @@ -109,9 +109,12 @@ GLOBAL_LIST(labor_sheet_values) qdel(src) /obj/machinery/mineral/labor_claim_console/emag_act(mob/user) - if(!(obj_flags & EMAGGED)) - obj_flags |= EMAGGED - to_chat(user, "PZZTTPFFFT") + . = ..() + if((obj_flags & EMAGGED)) + return + obj_flags |= EMAGGED + to_chat(user, "PZZTTPFFFT") + return TRUE /**********************Prisoner Collection Unit**************************/ diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 87dcd73e83..9c23c8b5de 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -244,6 +244,7 @@ // called when something steps onto a human // this could be made more general, but for now just handle mulebot /mob/living/carbon/human/Crossed(atom/movable/AM) + ..() var/mob/living/simple_animal/bot/mulebot/MB = AM if(istype(MB)) MB.RunOver(src) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 19277b6cc9..5d15180b95 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -1,4 +1,6 @@ /mob/living/carbon/human/getarmor(def_zone, type) + if(HAS_TRAIT(src, TRAIT_ARMOR_BROKEN)) //trait that makes it act as if you have no armor at all, you take natural damage from all sources + return 0 var/armorval = 0 var/organnum = 0 @@ -18,7 +20,6 @@ organnum++ return (armorval/max(organnum, 1)) - /mob/living/carbon/human/proc/checkarmor(obj/item/bodypart/def_zone, d_type) if(!d_type || !def_zone) return 0 diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index 683829f133..f78173dcfb 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -715,18 +715,25 @@ return FALSE /datum/action/innate/slime_puddle/Activate() + var/mob/living/carbon/human/H = owner + //if they have anything stuck to their hands, we immediately say 'no' and return + for(var/obj/item/I in H.held_items) + if(HAS_TRAIT(I, TRAIT_NODROP)) + to_chat(owner, "There's something stuck to your hand, stopping you from transforming!") + return if(isjellyperson(owner) && IsAvailable()) transforming = TRUE UpdateButtonIcon() - var/mob/living/carbon/human/H = owner var/mutcolor = "#" + H.dna.features["mcolor"] if(!is_puddle) - if(CHECK_MOBILITY(H, MOBILITY_USE)) - is_puddle = TRUE - owner.cut_overlays() + if(CHECK_MOBILITY(H, MOBILITY_USE)) //if we can use items, we can turn into a puddle + is_puddle = TRUE //so we know which transformation to use when its used + owner.cut_overlays() //we dont show our normal sprite, we show a puddle sprite var/obj/effect/puddle_effect = new puddle_into_effect(get_turf(owner), owner.dir) puddle_effect.color = mutcolor - H.Stun(in_transformation_duration, ignore_canstun = TRUE) + H.Stun(in_transformation_duration, ignore_canstun = TRUE) //cant move while transforming + + //series of traits that make up the puddle behaviour ADD_TRAIT(H, TRAIT_PARALYSIS_L_ARM, SLIMEPUDDLE_TRAIT) ADD_TRAIT(H, TRAIT_PARALYSIS_R_ARM, SLIMEPUDDLE_TRAIT) ADD_TRAIT(H, TRAIT_MOBILITY_NOPICKUP, SLIMEPUDDLE_TRAIT) @@ -734,19 +741,30 @@ ADD_TRAIT(H, TRAIT_SPRINT_LOCKED, SLIMEPUDDLE_TRAIT) ADD_TRAIT(H, TRAIT_COMBAT_MODE_LOCKED, SLIMEPUDDLE_TRAIT) ADD_TRAIT(H, TRAIT_MOBILITY_NOREST, SLIMEPUDDLE_TRAIT) + ADD_TRAIT(H, TRAIT_ARMOR_BROKEN, SLIMEPUDDLE_TRAIT) + H.update_disabled_bodyparts(silent = TRUE) //silently update arms to be paralysed + H.add_movespeed_modifier(/datum/movespeed_modifier/slime_puddle) - H.update_disabled_bodyparts(silent = TRUE) + H.layer -= 1 //go one layer down so people go over you - ENABLE_BITFIELD(H.pass_flags, PASSMOB) - squeak = H.AddComponent(/datum/component/squeak, custom_sounds = list('sound/effects/blobattack.ogg')) - sleep(in_transformation_duration) + ENABLE_BITFIELD(H.pass_flags, PASSMOB) //this actually lets people pass over you + squeak = H.AddComponent(/datum/component/squeak, custom_sounds = list('sound/effects/blobattack.ogg')) //blorble noise when people step on you + + //if the user is a changeling, retract their sting + H.unset_sting() + + sleep(in_transformation_duration) //wait for animation to end + + //set the puddle overlay up var/mutable_appearance/puddle_overlay = mutable_appearance(icon = puddle_icon, icon_state = puddle_state) puddle_overlay.color = mutcolor tracked_overlay = puddle_overlay owner.add_overlay(puddle_overlay) + transforming = FALSE UpdateButtonIcon() else + //like the above, but reverse everything done! owner.cut_overlay(tracked_overlay) var/obj/effect/puddle_effect = new puddle_from_effect(get_turf(owner), owner.dir) puddle_effect.color = mutcolor @@ -759,6 +777,7 @@ REMOVE_TRAIT(H, TRAIT_SPRINT_LOCKED, SLIMEPUDDLE_TRAIT) REMOVE_TRAIT(H, TRAIT_COMBAT_MODE_LOCKED, SLIMEPUDDLE_TRAIT) REMOVE_TRAIT(H, TRAIT_MOBILITY_NOREST, SLIMEPUDDLE_TRAIT) + REMOVE_TRAIT(H, TRAIT_ARMOR_BROKEN, SLIMEPUDDLE_TRAIT) H.update_disabled_bodyparts(silent = TRUE) H.remove_movespeed_modifier(/datum/movespeed_modifier/slime_puddle) H.layer += 1 //go one layer back above! diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm index 676248c463..558fdc6594 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -15,8 +15,13 @@ skinned_type = /obj/item/stack/sheet/animalhide/human var/info_text = "You are a Vampire. You will slowly but constantly lose blood if outside of a coffin. If inside a coffin, you will slowly heal. You may gain more blood by grabbing a live victim and using your drain ability." species_category = SPECIES_CATEGORY_UNDEAD + var/batform_enabled = TRUE -/datum/species/vampire/check_roundstart_eligible() +/datum/species/vampire/roundstart + id = SPECIES_VAMPIRE_WEAK + batform_enabled = FALSE + +/datum/species/vampire/roundstart/check_roundstart_eligible() if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) return TRUE return FALSE @@ -27,8 +32,9 @@ if(!C.dna.skin_tone_override) C.skin_tone = "albino" C.update_body(0) - var/obj/effect/proc_holder/spell/targeted/shapeshift/bat/B = new - C.AddSpell(B) + if(batform_enabled) + var/obj/effect/proc_holder/spell/targeted/shapeshift/bat/B = new + C.AddSpell(B) /datum/species/vampire/on_species_loss(mob/living/carbon/C) . = ..() diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index eaab9eb450..a71352c4be 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -451,6 +451,7 @@ key = "me" key_third_person = "custom" message = null + emote_type = EMOTE_BOTH /datum/emote/living/custom/proc/check_invalid(mob/user, input) if(stop_bad_mime.Find(input, 1, 1)) @@ -470,24 +471,12 @@ else if(!params) var/custom_emote = stripped_multiline_input_or_reflect(user, "Choose an emote to display.", "Custom Emote", null, MAX_MESSAGE_LEN) if(custom_emote && !check_invalid(user, custom_emote)) - var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable") - switch(type) - if("Visible") - emote_type = EMOTE_VISIBLE - if("Hearable") - emote_type = EMOTE_AUDIBLE - else - alert("Unable to use this emote, must be either hearable or visible.") - return message = custom_emote else message = params - if(type_override) - emote_type = type_override message = user.say_emphasis(message) . = ..() message = null - emote_type = EMOTE_VISIBLE /datum/emote/living/custom/replace_pronoun(mob/user, message) return message diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm index 1346302aeb..f7d044831a 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm @@ -87,7 +87,7 @@ Difficulty: Medium return FALSE return ..() -/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, mob/target, target_message, user_msg, runechat_popup) //SKYRAT CHANGE +/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, mob/target, target_message, omni = FALSE, runechat_popup) if(swooping & SWOOP_INVULNERABLE) //to suppress attack messages without overriding every single proc that could send a message saying we got hit return return ..() diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 8d09249e1b..75318f9f85 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -127,12 +127,13 @@ * * ignored_mobs (optional) doesn't show any message to any given mob in the list. * * target (optional) is the other mob involved with the visible message. For example, the attacker in many combat messages. * * target_message (optional) is what the target mob will see e.g. "[src] does something to you!" + * * omni (optional) if TRUE, will show to users no matter what. */ -/atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, ignored_mobs, mob/target, target_message, user_msg, runechat_popup) //SKYRAT CHANGE +/atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, ignored_mobs, mob/target, target_message, omni = FALSE, runechat_popup) var/turf/T = get_turf(src) if(!T) return - var/final_msg = user_msg ? "[src] " + message : message //SKYRAT CHANGE + var/final_msg = !(src == null) ? "[src] " + message : "Unknown " + message //SKYRAT CHANGE var/list/hearers = get_hearers_in_view(vision_distance, src) //caches the hearers and then removes ignored mobs. if(!length(hearers)) return @@ -140,20 +141,26 @@ if(target_message && target && istype(target) && target.client) hearers -= target - //This entire if/else chain could be in two lines but isn't for readibilties sake. - var/msg = target_message - if(target.see_invisible[src] " + self_message : self_message, MSG_VISUAL, blind_message, MSG_AUDIBLE) //SKYRAT CHANGE + if(!omni) + show_message(self_message, MSG_VISUAL, blind_message, MSG_AUDIBLE) + if(runechat_popup && client?.prefs.chat_on_map && client.prefs.see_chat_emotes) //SKYRAT CHANGE + create_chat_message(src, null, self_message, list("emote", "italics"), null) //Skyrat change + else + show_message(self_message) /** * Show a message to all mobs in earshot of this atom diff --git a/code/modules/mob/say_vr.dm b/code/modules/mob/say_vr.dm index cc2d6a60bb..e03f36c344 100644 --- a/code/modules/mob/say_vr.dm +++ b/code/modules/mob/say_vr.dm @@ -39,15 +39,6 @@ proc/get_top_level_mob(var/mob/S) else if(!params) var/subtle_emote = stripped_multiline_input_or_reflect(user, "Choose an emote to display.", "Subtle", null, MAX_MESSAGE_LEN) if(subtle_emote && !check_invalid(user, subtle_emote)) - var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable") - switch(type) - if("Visible") - emote_type = EMOTE_VISIBLE - if("Hearable") - emote_type = EMOTE_AUDIBLE - else - alert("Unable to use this emote, must be either hearable or visible.") - return message = subtle_emote else return FALSE @@ -69,11 +60,7 @@ proc/get_top_level_mob(var/mob/S) if(M.stat == DEAD && M.client && (M.client.prefs.chat_toggles & CHAT_GHOSTSIGHT) && !(M in viewers(T, null)) && (user.client)) //SKYRAT CHANGE - only user controlled mobs show their emotes to all-seeing ghosts, to reduce chat spam M.show_message(message) - if(emote_type == EMOTE_AUDIBLE) - user.audible_message(message=message,hearing_distance=1) - else - user.visible_message(message=message,self_message=message,vision_distance=1) - + user.visible_message(message = message, self_message = message, vision_distance = 1, omni = TRUE) ///////////////// SUBTLE 2: NO GHOST BOOGALOO @@ -122,10 +109,7 @@ proc/get_top_level_mob(var/mob/S) user.log_message(message, LOG_SUBTLER) message = "[user] " + "[user.say_emphasis(message)]" - if(emote_type == EMOTE_AUDIBLE) - user.audible_message(message=message,hearing_distance=1, ignored_mobs = GLOB.dead_mob_list) - else - user.visible_message(message=message,self_message=message,vision_distance=1, ignored_mobs = GLOB.dead_mob_list) + user.visible_message(message = message, self_message = message, vision_distance = 1, ignored_mobs = GLOB.dead_mob_list, omni = TRUE) ///////////////// VERB CODE /mob/living/verb/subtle() diff --git a/code/modules/movespeed/modifiers/innate.dm b/code/modules/movespeed/modifiers/innate.dm index 946d93e96b..f5a599f940 100644 --- a/code/modules/movespeed/modifiers/innate.dm +++ b/code/modules/movespeed/modifiers/innate.dm @@ -20,5 +20,6 @@ flags = IGNORE_NOSLOW /datum/movespeed_modifier/slime_puddle - multiplicative_slowdown = 2 + multiplicative_slowdown = 4.5 flags = IGNORE_NOSLOW + variable = TRUE diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 1a96f36ccd..7f7c02f457 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -111,6 +111,7 @@ var/obj/machinery/computer/apc_control/remote_control = null var/mob/living/carbon/hijacker var/hijackerlast = TRUE + var/being_hijacked = FALSE /obj/machinery/power/apc/unlocked locked = FALSE @@ -902,7 +903,7 @@ if(H && !H.stealthmode && H.toggled) abilitiesavail = TRUE var/list/data = list( - "locked" = locked, + "locked" = locked && !(integration_cog && is_servant_of_ratvar(user)) && !area.hasSiliconAccessInArea(user, PRIVILEDGES_SILICON|PRIVILEDGES_DRONE), "failTime" = failure_timer, "isOperating" = operating, "externalPower" = main_status, @@ -1119,10 +1120,14 @@ /obj/machinery/power/apc/proc/hijack(mob/living/L) if (!istype(L)) return + if(being_hijacked) + to_chat(L, "This APC is already being hijacked!") + return if (hijacker && hijacker != L) var/obj/item/implant/hijack/H = L.getImplant(/obj/item/implant/hijack) to_chat(L, "Someone already has control of this APC. Beginning counter-hijack.") H.hijacking = TRUE + being_hijacked = TRUE if (do_after(L,20 SECONDS,target=src)) hijacker.toggleSiliconAccessArea(area) if (L.toggleSiliconAccessArea(area)) @@ -1130,23 +1135,28 @@ update_icon() set_hijacked_lighting() H.hijacking = FALSE + being_hijacked = FALSE return else to_chat(L, "Aborting.") H.hijacking = FALSE + being_hijacked = FALSE return to_chat(L, "Beginning hijack of APC.") var/obj/item/implant/hijack/H = L.getImplant(/obj/item/implant/hijack) H.hijacking = TRUE + being_hijacked = TRUE if (do_after(L,H.stealthmode ? 12 SECONDS : 5 SECONDS,target=src)) if (L.toggleSiliconAccessArea(area)) hijacker = L update_icon() set_hijacked_lighting() H.hijacking = FALSE + being_hijacked = FALSE else to_chat(L, "Aborting.") H.hijacking = FALSE + being_hijacked = FALSE return /obj/machinery/power/apc/proc/malfhack(mob/living/silicon/ai/malf) diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index b67fac2423..6867058faa 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -973,7 +973,7 @@ M.emote("gasp") log_combat(M, M, "revived", src) var/list/policies = CONFIG_GET(keyed_list/policyconfig) - var/timelimit = CONFIG_GET(number/defib_cmd_time_limit) + var/timelimit = CONFIG_GET(number/defib_cmd_time_limit) * 10 //the config is in seconds, not deciseconds var/late = timelimit && (tplus > timelimit) var/policy = late? policies[POLICYCONFIG_ON_DEFIB_LATE] : policies[POLICYCONFIG_ON_DEFIB_INTACT] if(policy) diff --git a/code/modules/spells/spell_types/lichdom.dm b/code/modules/spells/spell_types/lichdom.dm index 11518b236f..3d54c7130c 100644 --- a/code/modules/spells/spell_types/lichdom.dm +++ b/code/modules/spells/spell_types/lichdom.dm @@ -132,7 +132,7 @@ lich.real_name = mind.name mind.transfer_to(lich) mind.grab_ghost(force=TRUE) - lich.hardset_dna(null,null,null,lich.real_name,null, new /datum/species/skeleton) + lich.hardset_dna(null,null,null,lich.real_name,null, new /datum/species/skeleton/space) to_chat(lich, "Your bones clatter and shudder as you are pulled back into this world!") var/turf/body_turf = get_turf(old_body) lich.DefaultCombatKnockdown(200 + 200*resurrections) diff --git a/code/modules/surgery/advanced/revival.dm b/code/modules/surgery/advanced/revival.dm index c61ee330e6..0b864958a0 100644 --- a/code/modules/surgery/advanced/revival.dm +++ b/code/modules/surgery/advanced/revival.dm @@ -70,7 +70,7 @@ if(O.organ_flags & ORGAN_FAILING) O.applyOrganDamage(-5) var/list/policies = CONFIG_GET(keyed_list/policyconfig) - var/timelimit = CONFIG_GET(number/defib_cmd_time_limit) + var/timelimit = CONFIG_GET(number/defib_cmd_time_limit) * 10 //the config is in seconds, not deciseconds var/late = timelimit && (tplus > timelimit) var/policy = late? policies[POLICYCONFIG_ON_DEFIB_LATE] : policies[POLICYCONFIG_ON_DEFIB_INTACT] if(policy) diff --git a/html/changelogs/AutoChangeLog-pr-13567.yml b/html/changelogs/AutoChangeLog-pr-13567.yml new file mode 100644 index 0000000000..d51db8e3b8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13567.yml @@ -0,0 +1,8 @@ +author: "timothyteakettle" +delete-after: True +changes: + - tweak: "changeling stings retract upon turning into a slime puddle" + - tweak: "you cannot transform into a slime puddle with a no drop item in your hands" + - tweak: "slime puddles are now transparent and their colour looks more natural in comparison to the user" + - tweak: "slime puddles are now even slower" + - tweak: "slime puddles now get no protection from worn clothing" diff --git a/html/changelogs/AutoChangeLog-pr-13629.yml b/html/changelogs/AutoChangeLog-pr-13629.yml new file mode 100644 index 0000000000..954f6972ec --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13629.yml @@ -0,0 +1,4 @@ +author: "silicons" +delete-after: True +changes: + - rscdel: "anomalies no longer spawn in walls" diff --git a/html/changelogs/AutoChangeLog-pr-13632.yml b/html/changelogs/AutoChangeLog-pr-13632.yml new file mode 100644 index 0000000000..bf478ec97c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13632.yml @@ -0,0 +1,4 @@ +author: "timothyteakettle" +delete-after: True +changes: + - bugfix: "time for memory loss message to show up when being revived is now correctly 300 seconds, instead of 30" diff --git a/html/changelogs/AutoChangeLog-pr-13633.yml b/html/changelogs/AutoChangeLog-pr-13633.yml new file mode 100644 index 0000000000..d9246cfff6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13633.yml @@ -0,0 +1,4 @@ +author: "ArchieBeepBoop" +delete-after: True +changes: + - bugfix: "Outlet Injector Mapping Asset Layer Fix" diff --git a/html/changelogs/AutoChangeLog-pr-13647.yml b/html/changelogs/AutoChangeLog-pr-13647.yml new file mode 100644 index 0000000000..b3211ee759 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13647.yml @@ -0,0 +1,4 @@ +author: "zeroisthebiggay" +delete-after: True +changes: + - bugfix: "jacqueline spawns on boxstation" diff --git a/html/changelogs/AutoChangeLog-pr-13648.yml b/html/changelogs/AutoChangeLog-pr-13648.yml new file mode 100644 index 0000000000..4148230385 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13648.yml @@ -0,0 +1,13 @@ +author: "DeltaFire15" +delete-after: True +changes: + - bugfix: "The 'Your body is in a cloner' notification works again" + - bugfix: "Hijack implants should work properly again (or, at least better)" + - bugfix: "Liches are now good skeletons again instead of weak ones" + - bugfix: "The piratepad control cannot be destroyed again." + - bugfix: "Pirates have received new supplies of jetpacks instead of useless oxygen tanks" + - bugfix: "Ratvarian AIs are once again able to show their linked borgs Ratvar's light" + - bugfix: "Hijackers are once again unable to detonate borgs without being adjacent to the console" + - bugfix: "Automated annoucement systems and gulag ore consoles no longer waste emag charges" + - bugfix: "Automated announcement systems once again can be remote controlled by non-AIs with silicon access" + - bugfix: "APCs being hijacked multiple times at once is no longer possible, preventing some issues" diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi index 10b733bae4..3d1cbfa273 100644 Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ diff --git a/tgui/packages/tgui/interfaces/RoboticsControlConsole.js b/tgui/packages/tgui/interfaces/RoboticsControlConsole.js index 746cb7ad9c..1520b4093b 100644 --- a/tgui/packages/tgui/interfaces/RoboticsControlConsole.js +++ b/tgui/packages/tgui/interfaces/RoboticsControlConsole.js @@ -8,6 +8,7 @@ export const RoboticsControlConsole = (props, context) => { const [tab, setTab] = useSharedState(context, 'tab', 1); const { can_hack, + can_convert, cyborgs = [], drones = [], } = data; @@ -34,7 +35,9 @@ export const RoboticsControlConsole = (props, context) => { {tab === 1 && ( - + )} {tab === 2 && ( @@ -45,7 +48,7 @@ export const RoboticsControlConsole = (props, context) => { }; const Cyborgs = (props, context) => { - const { cyborgs, can_hack } = props; + const { cyborgs, can_hack, can_convert } = props; const { act, data } = useBackend(context); if (!cyborgs.length) { return ( @@ -70,6 +73,15 @@ const Cyborgs = (props, context) => { ref: cyborg.ref, })} /> )} + {!!can_convert && !cyborg.servant && ( +