diff --git a/code/__DEFINES/dcs/mob_signals.dm b/code/__DEFINES/dcs/mob_signals.dm index 286daac792f..c876da9c5c8 100644 --- a/code/__DEFINES/dcs/mob_signals.dm +++ b/code/__DEFINES/dcs/mob_signals.dm @@ -206,3 +206,7 @@ /// called when a living mob's stun status is cleared: () #define COMSIG_LIVING_CLEAR_STUNS "living_clear_stuns" + +/// Sent from datum/spell/ethereal_jaunt/cast, before the mob enters jaunting as a pre-check: (mob/jaunter) +#define COMSIG_MOB_PRE_JAUNT "spell_mob_pre_jaunt" + #define COMPONENT_BLOCK_JAUNT (1<<0) diff --git a/code/__DEFINES/dcs/movable_signals.dm b/code/__DEFINES/dcs/movable_signals.dm index c0ac15e5393..2de0ca3879d 100644 --- a/code/__DEFINES/dcs/movable_signals.dm +++ b/code/__DEFINES/dcs/movable_signals.dm @@ -63,3 +63,9 @@ // Note that this is only defined for actions because this could be a good bit expensive otherwise /// From base of /atom/movable/screen/movable/action_button/MouseWheel(src, delta_x, delta_y, location, control, params) #define COMSIG_ACTION_SCROLLED "action_scrolled" + +/// Called before a movable is being teleported from multiple sources: (destination) +#define COMSIG_MOVABLE_TELEPORTING "movable_teleporting" +/// Called when blocking a teleport +#define COMSIG_ATOM_INTERCEPT_TELEPORTED "intercept_teleported" + #define COMPONENT_BLOCK_TELEPORT (1<<0) diff --git a/code/datums/diseases/wizarditis.dm b/code/datums/diseases/wizarditis.dm index 30c18428030..4c02000bf63 100644 --- a/code/datums/diseases/wizarditis.dm +++ b/code/datums/diseases/wizarditis.dm @@ -90,6 +90,8 @@ /datum/disease/wizarditis/proc/teleport() if(!is_teleport_allowed(affected_mob.z)) return + if(SEND_SIGNAL(affected_mob, COMSIG_MOVABLE_TELEPORTING, get_turf(affected_mob)) & COMPONENT_BLOCK_TELEPORT) + return FALSE var/list/possible_areas = get_areas_in_range(80, affected_mob) for(var/area/space/S in possible_areas) diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm index 8f4aac056d2..a14b5722e23 100644 --- a/code/datums/helper_datums/teleport.dm +++ b/code/datums/helper_datums/teleport.dm @@ -149,6 +149,10 @@ if(!is_teleport_allowed(destturf.z) && !ignore_area_flag) return FALSE + if(!ignore_area_flag) // Admin or contractor portal, let em through without running signals + if(SEND_SIGNAL(teleatom, COMSIG_MOVABLE_TELEPORTING, destination) & COMPONENT_BLOCK_TELEPORT) + return FALSE + // Only check the destination zlevel for is_teleport_allowed. Checking origin as well breaks ERT teleporters. var/area/destarea = get_area(destturf) diff --git a/code/datums/spells/bloodcrawl.dm b/code/datums/spells/bloodcrawl.dm index b1ab9853096..007ff329932 100644 --- a/code/datums/spells/bloodcrawl.dm +++ b/code/datums/spells/bloodcrawl.dm @@ -29,6 +29,8 @@ return if(!isliving(user)) return FALSE + if(SEND_SIGNAL(user, COMSIG_MOB_PRE_JAUNT, get_turf(user)) & COMPONENT_BLOCK_JAUNT) + return FALSE /datum/spell/bloodcrawl/cast(list/targets, mob/living/user) var/atom/target = targets[1] diff --git a/code/datums/spells/ethereal_jaunt.dm b/code/datums/spells/ethereal_jaunt.dm index e707040501d..b671244dfc8 100644 --- a/code/datums/spells/ethereal_jaunt.dm +++ b/code/datums/spells/ethereal_jaunt.dm @@ -26,6 +26,8 @@ /datum/spell/ethereal_jaunt/cast(list/targets, mob/user = usr) //magnets, so mostly hardcoded playsound(get_turf(user), sound1, 50, TRUE, -1) for(var/mob/living/target in targets) + if(SEND_SIGNAL(target, COMSIG_MOB_PRE_JAUNT, target) & COMPONENT_BLOCK_JAUNT) + continue if(!target.can_safely_leave_loc()) // No more brainmobs hopping out of their brains to_chat(target, "You are somehow too bound to your current location to abandon it.") continue diff --git a/code/datums/spells/turf_teleport.dm b/code/datums/spells/turf_teleport.dm index 9c8e50c51c3..ee9cc820072 100644 --- a/code/datums/spells/turf_teleport.dm +++ b/code/datums/spells/turf_teleport.dm @@ -22,6 +22,8 @@ playsound(get_turf(user), sound1, 50, TRUE) for(var/mob/living/target in targets) + if(SEND_SIGNAL(target, COMSIG_MOVABLE_TELEPORTING, get_turf(target)) & COMPONENT_BLOCK_TELEPORT) + continue var/list/turfs = list() for(var/turf/T in range(target,outer_tele_radius)) if(T in range(target,inner_tele_radius)) continue diff --git a/code/game/gamemodes/cult/blood_magic.dm b/code/game/gamemodes/cult/blood_magic.dm index 6bb2febd075..cc0b0f22c20 100644 --- a/code/game/gamemodes/cult/blood_magic.dm +++ b/code/game/gamemodes/cult/blood_magic.dm @@ -537,6 +537,8 @@ var/turf/origin = get_turf(teleportee) var/turf/destination = get_turf(actual_selected_rune) + if(SEND_SIGNAL(target, COMSIG_MOVABLE_TELEPORTING, destination) & COMPONENT_BLOCK_TELEPORT) + return INVOKE_ASYNC(actual_selected_rune, TYPE_PROC_REF(/obj/effect/rune, teleport_effect), teleportee, origin, destination) if(is_mining_level(user.z) && !is_mining_level(destination.z)) //No effect if you stay on lavaland diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm index 320941a6227..0f0427d29b1 100644 --- a/code/game/gamemodes/cult/cult_items.dm +++ b/code/game/gamemodes/cult/cult_items.dm @@ -324,6 +324,8 @@ if(C.pulling) var/atom/movable/pulled = C.pulling var/turf/turf_behind = get_turf(get_step(T, turn(C.dir, 180))) + if(SEND_SIGNAL(pulled, COMSIG_MOVABLE_TELEPORTING, turf_behind) & COMPONENT_BLOCK_TELEPORT) + return FALSE if(!pulled.anchored) //Item may have been anchored while pulling, and pulling state isn't updated until you move away, so we double check. pulled.forceMove(turf_behind) . = pulled @@ -338,6 +340,8 @@ step(src, pick(GLOB.alldirs)) to_chat(user, "[src] flickers out of your hands, too eager to move!") return + if(SEND_SIGNAL(user, COMSIG_MOVABLE_TELEPORTING, get_turf(user)) & COMPONENT_BLOCK_TELEPORT) + return FALSE if(user.holy_check()) return var/outer_tele_radius = 9 diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 822b220f3d8..234bdcaf83b 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -494,6 +494,8 @@ structure_check() searches for nearby cultist structures required for the invoca var/movedsomething = FALSE var/moveuser = FALSE for(var/atom/movable/A in T) + if(SEND_SIGNAL(A, COMSIG_MOVABLE_TELEPORTING, target) & COMPONENT_BLOCK_TELEPORT) + continue if(ishuman(A)) if(A != user) // Teleporting someone else INVOKE_ASYNC(src, PROC_REF(teleport_effect), A, T, target) @@ -775,6 +777,11 @@ structure_check() searches for nearby cultist structures required for the invoca fail_invoke() log_game("Summon Cultist rune failed - target in away mission") return + if(SEND_SIGNAL(cultist_to_summon, COMSIG_MOVABLE_TELEPORTING, get_turf(src)) & COMPONENT_BLOCK_TELEPORT) + to_chat(user, "[cultist_to_summon] is anchored in bluespace!") + fail_invoke() + log_game("Summon Cultist rune failed - anchored in bluespace") + return cultist_to_summon.visible_message("[cultist_to_summon] suddenly disappears in a flash of red light!", \ "Overwhelming vertigo consumes you as you are hurled through the air!") diff --git a/code/game/gamemodes/wizard/magic_tarot.dm b/code/game/gamemodes/wizard/magic_tarot.dm index b3e825ab9e6..69ac8f6f33b 100644 --- a/code/game/gamemodes/wizard/magic_tarot.dm +++ b/code/game/gamemodes/wizard/magic_tarot.dm @@ -287,6 +287,8 @@ card_icon = "the_fool" /datum/tarot/the_fool/activate(mob/living/target) + if(SEND_SIGNAL(target, COMSIG_MOVABLE_TELEPORTING, get_turf(target)) & COMPONENT_BLOCK_TELEPORT) + return FALSE target.forceMove(pick(GLOB.latejoin)) to_chat(target, "You are abruptly pulled through space!") @@ -364,7 +366,8 @@ if(!length(L)) to_chat(target, "Huh. No bridge? Well, that sucks.") return - + if(SEND_SIGNAL(target, COMSIG_MOVABLE_TELEPORTING, get_turf(target)) & COMPONENT_BLOCK_TELEPORT) + return FALSE target.forceMove(pick(L)) to_chat(target, "You are abruptly pulled through space!") @@ -440,7 +443,8 @@ if(!length(viable_vendors)) to_chat(target, "No vending machines? Well, with luck cargo will have something to offer. If you go there yourself.") return - + if(SEND_SIGNAL(target, COMSIG_MOVABLE_TELEPORTING, get_turf(target)) & COMPONENT_BLOCK_TELEPORT) + return FALSE target.forceMove(get_turf(pick(viable_vendors))) to_chat(target, "You are abruptly pulled through space!") @@ -554,7 +558,8 @@ if(!length(L)) to_chat(target, "Huh. No evidence? Well, that means they can't charge you with a crime, right?") return - + if(SEND_SIGNAL(target, COMSIG_MOVABLE_TELEPORTING, get_turf(target)) & COMPONENT_BLOCK_TELEPORT) + return FALSE target.forceMove(pick(L)) to_chat(target, "You are abruptly pulled through space!") for(var/obj/structure/closet/C in shuffle(view(9, target))) @@ -573,6 +578,8 @@ /datum/tarot/the_moon/activate(mob/living/target) var/list/funny_ruin_list = list() var/turf/target_turf = get_turf(target) + if(SEND_SIGNAL(target, COMSIG_MOVABLE_TELEPORTING, get_turf(target)) & COMPONENT_BLOCK_TELEPORT) + return FALSE for(var/I in GLOB.ruin_landmarks) var/obj/effect/landmark/ruin/ruin_landmark = I if(ruin_landmark.z == target_turf.z) @@ -722,7 +729,8 @@ if(!length(L)) to_chat(target, "Huh. No command members? I hope you didn't kill them all already...") return - + if(SEND_SIGNAL(target, COMSIG_MOVABLE_TELEPORTING, get_turf(target)) & COMPONENT_BLOCK_TELEPORT) + return FALSE target.forceMove(get_turf(pick(L))) to_chat(target, "You are abruptly pulled through space!") @@ -975,6 +983,7 @@ if(!length(L)) to_chat(target, "Hmm. No base? A miner issue.") return - + if(SEND_SIGNAL(target, COMSIG_MOVABLE_TELEPORTING, get_turf(target)) & COMPONENT_BLOCK_TELEPORT) + return FALSE target.forceMove(pick(L)) to_chat(target, "You are abruptly pulled through space!") diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm index 2b279b5a781..71318e0dbcc 100644 --- a/code/game/objects/items/devices/traitordevices.dm +++ b/code/game/objects/items/devices/traitordevices.dm @@ -113,6 +113,8 @@ if(!is_teleport_allowed(starting.z) || starting_area.tele_proof) to_chat(user, "[src] will not work here!") return + if(SEND_SIGNAL(user, COMSIG_MOVABLE_TELEPORTING, starting) & COMPONENT_BLOCK_TELEPORT) + return FALSE var/mob/living/M = user var/turf/mobloc = get_turf(M) var/list/turfs = list() diff --git a/code/game/objects/items/weapons/bio_chips/bio_chip_tracking.dm b/code/game/objects/items/weapons/bio_chips/bio_chip_tracking.dm index 5d0d1947471..f02b9c9216c 100644 --- a/code/game/objects/items/weapons/bio_chips/bio_chip_tracking.dm +++ b/code/game/objects/items/weapons/bio_chips/bio_chip_tracking.dm @@ -20,6 +20,13 @@ return ..() /obj/item/bio_chip/tracking/implant(mob/target) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + var/obj/item/organ/internal/cyberimp/chest/bluespace_anchor/anchor = H.get_int_organ(/obj/item/organ/internal/cyberimp/chest/bluespace_anchor) + if(anchor) + target.visible_message("[src] sparks out, disrupted by [anchor] inside [H]!") + qdel(src) + return FALSE . = ..() if(!.) return diff --git a/code/modules/antagonists/vampire/vampire_powers/dantalion_powers.dm b/code/modules/antagonists/vampire/vampire_powers/dantalion_powers.dm index 3aeda9ce3f0..16e0583471d 100644 --- a/code/modules/antagonists/vampire/vampire_powers/dantalion_powers.dm +++ b/code/modules/antagonists/vampire/vampire_powers/dantalion_powers.dm @@ -164,8 +164,10 @@ var/mob/living/target = targets[1] var/turf/user_turf = get_turf(user) var/turf/target_turf = get_turf(target) - target.forceMove(user_turf) - user.forceMove(target_turf) + if(!(SEND_SIGNAL(target, COMSIG_MOVABLE_TELEPORTING, user_turf) & COMPONENT_BLOCK_TELEPORT)) + target.forceMove(user_turf) + if(!(SEND_SIGNAL(user, COMSIG_MOVABLE_TELEPORTING, target_turf) & COMPONENT_BLOCK_TELEPORT)) + user.forceMove(target_turf) /datum/spell/vampire/self/decoy name = "Deploy Decoy (30)" diff --git a/code/modules/antagonists/vampire/vampire_powers/umbrae_powers.dm b/code/modules/antagonists/vampire/vampire_powers/umbrae_powers.dm index 691eed6ece6..fcbd61fd752 100644 --- a/code/modules/antagonists/vampire/vampire_powers/umbrae_powers.dm +++ b/code/modules/antagonists/vampire/vampire_powers/umbrae_powers.dm @@ -173,6 +173,8 @@ user.make_invisible() addtimer(CALLBACK(user, TYPE_PROC_REF(/mob/living, reset_visibility)), 4 SECONDS) else + if(SEND_SIGNAL(user, COMSIG_MOVABLE_TELEPORTING, end_turf) & COMPONENT_BLOCK_TELEPORT) //You can fake it out, but no teleporting + return FALSE user.forceMove(end_turf) if(end_turf.z == start_turf.z) @@ -226,6 +228,8 @@ /datum/spell/vampire/dark_passage/cast(list/targets, mob/user) var/turf/target = get_turf(targets[1]) + if(SEND_SIGNAL(user, COMSIG_MOVABLE_TELEPORTING, target) & COMPONENT_BLOCK_TELEPORT) + return FALSE new /obj/effect/temp_visual/vamp_mist_out(get_turf(user)) diff --git a/code/modules/mining/lavaland/loot/hierophant_loot.dm b/code/modules/mining/lavaland/loot/hierophant_loot.dm index eb5b621a630..d5e747ed200 100644 --- a/code/modules/mining/lavaland/loot/hierophant_loot.dm +++ b/code/modules/mining/lavaland/loot/hierophant_loot.dm @@ -242,6 +242,8 @@ var/turf/turf_to_teleport_to = get_step(target, get_dir(source, M)) //get position relative to caster if(!turf_to_teleport_to || is_blocked_turf(turf_to_teleport_to, TRUE)) return + if(SEND_SIGNAL(M, COMSIG_MOVABLE_TELEPORTING, turf_to_teleport_to) & COMPONENT_BLOCK_TELEPORT) + return FALSE if(ishuman(M)) var/mob/living/carbon/human/H = M H.set_alpha_tracking(0, src, update_alpha = FALSE) diff --git a/code/modules/mining/lavaland/loot/tendril_loot.dm b/code/modules/mining/lavaland/loot/tendril_loot.dm index ddcceca876f..384e4c4cc93 100644 --- a/code/modules/mining/lavaland/loot/tendril_loot.dm +++ b/code/modules/mining/lavaland/loot/tendril_loot.dm @@ -293,6 +293,8 @@ if(cooldown) to_chat(user, "[src] sparks and fizzles.") return + if(SEND_SIGNAL(user, COMSIG_MOVABLE_TELEPORTING, get_turf(linked)) & COMPONENT_BLOCK_TELEPORT) + return FALSE var/datum/effect_system/smoke_spread/smoke = new smoke.set_up(1, FALSE, user) diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index 8a7eb1bf4d6..c507ca5fdd3 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -634,6 +634,17 @@ build_path = /obj/item/organ/internal/cyberimp/brain/wire_interface category = list("Medical") +/datum/design/bluespace_anchor + name = "Bluespace Anchor Implant" + desc = "This large cybernetic implant anchors you in bluespace, preventing almost any teleportation effects from working. It disrupts GPS systems however." + id = "bluespace_anchor_implant" + req_tech = list("bluespace" = 7, "biotech" = 5) + build_type = PROTOLATHE | MECHFAB + construction_time = 6 SECONDS + materials = list(MAT_METAL = 10000, MAT_BLUESPACE = 2000) + build_path = /obj/item/organ/internal/cyberimp/chest/bluespace_anchor + category = list("Medical") + /datum/design/raiden_implant name = "Reactive Repair Implant" desc = "This implant reworks the IPC frame, in order to incorporate materials that return to their original shape after being damaged. Requires power to function." diff --git a/code/modules/supply/supply_packs/pack_security.dm b/code/modules/supply/supply_packs/pack_security.dm index 1adad3d58c9..0463a992fd7 100644 --- a/code/modules/supply/supply_packs/pack_security.dm +++ b/code/modules/supply/supply_packs/pack_security.dm @@ -318,6 +318,12 @@ cost = 500 containername = "chemical bio-chip crate" +/datum/supply_packs/security/armory/bluespace_anchor + name = "Bluespace Anchor Crate" + contains = list(/obj/item/organ/internal/cyberimp/chest/bluespace_anchor) + cost = 250 + containername = "bluespace anchor crate" + /datum/supply_packs/security/securitybarriers name = "Security Barriers Crate" contains = list(/obj/item/grenade/barrier, diff --git a/code/modules/surgery/organs/augments_internal.dm b/code/modules/surgery/organs/augments_internal.dm index a1807372bcf..8b9aa48a626 100644 --- a/code/modules/surgery/organs/augments_internal.dm +++ b/code/modules/surgery/organs/augments_internal.dm @@ -734,6 +734,51 @@ if(H.stat == CONSCIOUS) to_chat(H, "You feel your heart beating again!") +/obj/item/organ/internal/cyberimp/chest/bluespace_anchor + name = "bluespace anchor implant" + desc = "This large cybernetic implant anchors you in bluespace, preventing almost any teleportation effects from working. It disrupts GPS systems however." + icon_state = "bluespace_anchor" + implant_overlay = null + slot = "bluespace_anchor" + origin_tech = "bluespace=6;biotech=4" + +/obj/item/organ/internal/cyberimp/chest/bluespace_anchor/insert(mob/living/carbon/M, special = FALSE) + ..() + RegisterSignal(M, COMSIG_MOVABLE_TELEPORTING, PROC_REF(on_teleport)) + RegisterSignal(M, COMSIG_MOB_PRE_JAUNT, PROC_REF(on_jaunt)) + for(var/obj/item/bio_chip/tracking/T in M) + if(T && T.implanted) + qdel(T) + +/obj/item/organ/internal/cyberimp/chest/bluespace_anchor/remove(mob/living/carbon/M, special = FALSE) + UnregisterSignal(M, COMSIG_MOVABLE_TELEPORTING) + UnregisterSignal(M, COMSIG_MOB_PRE_JAUNT) + return ..() + +/// Blocks teleports and stuns the would-be-teleportee. +/obj/item/organ/internal/cyberimp/chest/bluespace_anchor/proc/on_teleport(mob/living/teleportee, atom/destination, channel) + SIGNAL_HANDLER // COMSIG_MOVABLE_TELEPORTED + + to_chat(teleportee, "You feel yourself teleporting, but are suddenly flung back to where you just were!") + + teleportee.Weaken(5 SECONDS) + var/datum/effect_system/spark_spread/spark_system = new() + spark_system.set_up(5, TRUE, teleportee) + spark_system.start() + return COMPONENT_BLOCK_TELEPORT + +/// Prevents a user from entering a jaunt. +/obj/item/organ/internal/cyberimp/chest/bluespace_anchor/proc/on_jaunt(mob/living/jaunter) + SIGNAL_HANDLER // COMSIG_MOB_PRE_JAUNT + + to_chat(jaunter, "As you attempt to jaunt, you slam directly into the barrier between realities and are sent crashing back into corporeality!") + + jaunter.Weaken(5 SECONDS) + var/datum/effect_system/spark_spread/spark_system = new() + spark_system.set_up(5, TRUE, jaunter) + spark_system.start() + return COMPONENT_BLOCK_JAUNT + /obj/item/organ/internal/cyberimp/chest/ipc_repair name = "Reactive Repair Implant" desc = "This implant reworks the IPC frame, in order to incorporate materials that return to their original shape after being damaged. Requires power to function." diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi index 7b9baa40723..f1c9ac07b82 100644 Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ