diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm index e33d42df64..692ebad447 100644 --- a/code/__DEFINES/components.dm +++ b/code/__DEFINES/components.dm @@ -126,7 +126,7 @@ #define COMSIG_MOB_GHOSTIZE "mob_ghostize" //from base of mob/Ghostize() (can_reenter_corpse) #define COMPONENT_BLOCK_GHOSTING 1 #define COMSIG_MOB_ALLOWED "mob_allowed" //from base of obj/allowed(mob/M): (/obj) returns bool, if TRUE the mob has id access to the obj -#define COMSIG_MOB_RECEIVE_MAGIC "mob_receive_magic" //from base of mob/anti_magic_check(): (magic, holy, protection_sources) +#define COMSIG_MOB_RECEIVE_MAGIC "mob_receive_magic" //from base of mob/anti_magic_check(): (mob/user, magic, holy, tinfoil, chargecost, self, protection_sources) #define COMPONENT_BLOCK_MAGIC 1 #define COMSIG_MOB_HUD_CREATED "mob_hud_created" //from base of mob/create_mob_hud(): () #define COMSIG_MOB_ATTACK_HAND "mob_attack_hand" //from base of diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm index 24d381d1a8..eb9ed377a1 100644 --- a/code/__DEFINES/inventory.dm +++ b/code/__DEFINES/inventory.dm @@ -28,7 +28,9 @@ #define ITEM_SLOT_POCKET (1<<11) // this is to allow items with a w_class of WEIGHT_CLASS_NORMAL or WEIGHT_CLASS_BULKY to fit in pockets. #define ITEM_SLOT_DENYPOCKET (1<<12) // this is to deny items with a w_class of WEIGHT_CLASS_SMALL or WEIGHT_CLASS_TINY to fit in pockets. #define ITEM_SLOT_NECK (1<<13) -#define ITEM_SLOT_SUITSTORE (1<<14) +#define ITEM_SLOT_HANDS (1<<14) +#define ITEM_SLOT_BACKPACK (1<<15) +#define ITEM_SLOT_SUITSTORE (1<<16) //SLOTS #define SLOT_BACK 1 @@ -86,6 +88,10 @@ . = ITEM_SLOT_ICLOTHING if(SLOT_L_STORE, SLOT_R_STORE) . = ITEM_SLOT_POCKET + if(SLOT_HANDS) + . = ITEM_SLOT_HANDS + if(SLOT_IN_BACKPACK) + . = ITEM_SLOT_BACKPACK if(SLOT_S_STORE) . = ITEM_SLOT_SUITSTORE diff --git a/code/datums/components/anti_magic.dm b/code/datums/components/anti_magic.dm index df03918c5d..6f289af1fc 100644 --- a/code/datums/components/anti_magic.dm +++ b/code/datums/components/anti_magic.dm @@ -1,26 +1,48 @@ /datum/component/anti_magic var/magic = FALSE var/holy = FALSE + var/psychic = FALSE + var/allowed_slots = ~ITEM_SLOT_BACKPACK + var/charges = INFINITY + var/blocks_self = TRUE + var/datum/callback/reaction + var/datum/callback/expire -/datum/component/anti_magic/Initialize(_magic = FALSE, _holy = FALSE) +/datum/component/anti_magic/Initialize(_magic = FALSE, _holy = FALSE, _psychic = FALSE, _allowed_slots, _charges, _blocks_self = TRUE, datum/callback/_reaction, datum/callback/_expire) if(isitem(parent)) RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/on_equip) RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/on_drop) else if(ismob(parent)) - RegisterSignal(parent, COMSIG_MOB_RECEIVE_MAGIC, .proc/can_protect) + RegisterSignal(parent, COMSIG_MOB_RECEIVE_MAGIC, .proc/protect) else return COMPONENT_INCOMPATIBLE magic = _magic holy = _holy + psychic = _psychic + if(_allowed_slots) + allowed_slots = _allowed_slots + if(!isnull(_charges)) + charges = _charges + blocks_self = _blocks_self + reaction = _reaction + expire = _expire /datum/component/anti_magic/proc/on_equip(datum/source, mob/equipper, slot) - RegisterSignal(equipper, COMSIG_MOB_RECEIVE_MAGIC, .proc/can_protect, TRUE) + if(!CHECK_BITFIELD(allowed_slots, slotdefine2slotbit(slot))) //Check that the slot is valid for antimagic + UnregisterSignal(equipper, COMSIG_MOB_RECEIVE_MAGIC) + return + RegisterSignal(equipper, COMSIG_MOB_RECEIVE_MAGIC, .proc/protect, TRUE) /datum/component/anti_magic/proc/on_drop(datum/source, mob/user) UnregisterSignal(user, COMSIG_MOB_RECEIVE_MAGIC) -/datum/component/anti_magic/proc/can_protect(datum/source, _magic, _holy, list/protection_sources) - if((_magic && magic) || (_holy && holy)) +/datum/component/anti_magic/proc/protect(datum/source, mob/user, _magic, _holy, _psychic, chargecost = 1, self, list/protection_sources) + if(((_magic && magic) || (_holy && holy) || (_psychic && psychic)) && (!self || blocks_self)) protection_sources += parent + reaction?.Invoke(user, chargecost) + charges -= chargecost + if(charges <= 0) + expire?.Invoke(user) + qdel(src) return COMPONENT_BLOCK_MAGIC diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index 186c988595..fb636f6911 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -155,7 +155,7 @@ /datum/status_effect/belligerent/proc/do_movement_toggle(force_damage) var/number_legs = owner.get_num_legs(FALSE) - if(iscarbon(owner) && !is_servant_of_ratvar(owner) && !owner.anti_magic_check() && number_legs) + if(iscarbon(owner) && !is_servant_of_ratvar(owner) && !owner.anti_magic_check(chargecost = 0) && number_legs) if(force_damage || owner.m_intent != MOVE_INTENT_WALK) if(GLOB.ratvar_awakens) owner.Knockdown(20) @@ -248,7 +248,7 @@ if(owner.confused) owner.confused = 0 severity = 0 - else if(!owner.anti_magic_check() && owner.stat != DEAD && severity) + else if(!owner.anti_magic_check(chargecost = 0) && owner.stat != DEAD && severity) var/static/hum = get_sfx('sound/effects/screech.ogg') //same sound for every proc call if(owner.getToxLoss() > MANIA_DAMAGE_TO_CONVERT) if(is_eligible_servant(owner)) diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm index 207497922e..cf55d4178e 100644 --- a/code/game/objects/items/devices/multitool.dm +++ b/code/game/objects/items/devices/multitool.dm @@ -48,7 +48,7 @@ /obj/item/multitool/chaplain/Initialize() . = ..() - AddComponent(/datum/component/anti_magic, TRUE, TRUE) + AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE) /obj/item/multitool/examine(mob/user) ..() diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm index ccb82f7029..84439985b2 100644 --- a/code/game/objects/items/holy_weapons.dm +++ b/code/game/objects/items/holy_weapons.dm @@ -233,7 +233,7 @@ /obj/item/nullrod/Initialize() . = ..() - AddComponent(/datum/component/anti_magic, TRUE, TRUE) + AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE) /obj/item/nullrod/suicide_act(mob/user) user.visible_message("[user] is killing [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to get closer to god!") diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm index 9b2ec5c98f..14f924a27e 100644 --- a/code/game/objects/items/twohanded.dm +++ b/code/game/objects/items/twohanded.dm @@ -506,7 +506,7 @@ /obj/item/twohanded/dualsaber/hypereutactic/chaplain/Initialize() . = ..() - AddComponent(/datum/component/anti_magic, TRUE, TRUE) + AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE) /obj/item/twohanded/dualsaber/hypereutactic/chaplain/IsReflect() return FALSE diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 4552e846ad..fec17cfa69 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -528,7 +528,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 /obj/item/melee/baseball_bat/chaplain/Initialize() . = ..() - AddComponent(/datum/component/anti_magic, TRUE, TRUE) + AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE) /obj/item/melee/baseball_bat/homerun name = "home run bat" diff --git a/code/game/objects/structures/traps.dm b/code/game/objects/structures/traps.dm index ffc2c344f9..176779abd7 100644 --- a/code/game/objects/structures/traps.dm +++ b/code/game/objects/structures/traps.dm @@ -65,6 +65,8 @@ var/mob/M = AM if(M.mind in immune_minds) return + if(M.anti_magic_check()) + flare() if(charges <= 0) return flare() diff --git a/code/modules/antagonists/abductor/equipment/abduction_gear.dm b/code/modules/antagonists/abductor/equipment/abduction_gear.dm index 3d874aac58..c1088cbb3d 100644 --- a/code/modules/antagonists/abductor/equipment/abduction_gear.dm +++ b/code/modules/antagonists/abductor/equipment/abduction_gear.dm @@ -345,8 +345,8 @@ if(QDELETED(G)) return - if(istype(C.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat)) - to_chat(user, "Your target seems to have some sort of protective headgear on, blocking the message from being sent!") + if(C.anti_magic_check(FALSE, FALSE, TRUE, 0)) + to_chat(user, "Your target seems to have some sort of tinfoil protection on, blocking the message from being sent!") return G.mind_control(command, user) @@ -524,10 +524,10 @@ Congratulations! You are now trained for invasive xenobiology research!"} /obj/item/abductor_baton/proc/SleepAttack(mob/living/L,mob/living/user) if(L.incapacitated(TRUE, TRUE)) - if(istype(L.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat)) - to_chat(user, "The specimen's protective headgear is interfering with the sleep inducement!") - L.visible_message("[user] tried to induced sleep in [L] with [src], but [L.p_their()] headgear protected [L.p_them()]!", \ - "You feel a strange wave of heavy drowsiness wash over you, but your headgear deflects most of it!") + if(L.anti_magic_check(FALSE, FALSE, TRUE, 0)) + to_chat(user, "The specimen's tinfoil protection is interfering with the sleep inducement!") + L.visible_message("[user] tried to induced sleep in [L] with [src], but [L.p_their()] tinfoil protected [L.p_them()]!", \ + "You feel a strange wave of heavy drowsiness wash over you, but your tinfoil protection deflects most of it!") L.drowsyness += 2 return L.visible_message("[user] has induced sleep in [L] with [src]!", \ @@ -536,10 +536,10 @@ Congratulations! You are now trained for invasive xenobiology research!"} L.Sleeping(1200) log_combat(user, L, "put to sleep") else - if(istype(L.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat)) - to_chat(user, "The specimen's protective headgear is completely blocking our sleep inducement methods!") - L.visible_message("[user] tried to induce sleep in [L] with [src], but [L.p_their()] headgear completely protected [L.p_them()]!", \ - "Any sense of drowsiness is quickly diminished as your headgear deflects the effects!") + if(L.anti_magic_check(FALSE, FALSE, TRUE, 0)) + to_chat(user, "The specimen's tinfoil protection is completely blocking our sleep inducement methods!") + L.visible_message("[user] tried to induce sleep in [L] with [src], but [L.p_their()] tinfoil completely protected [L.p_them()]!", \ + "Any sense of drowsiness is quickly diminished as your tinfoil protection deflects the effects!") return L.drowsyness += 1 to_chat(user, "Sleep inducement works fully only on stunned specimens! ") diff --git a/code/modules/antagonists/abductor/machinery/console.dm b/code/modules/antagonists/abductor/machinery/console.dm index 9a9b1a6ba0..bcf02bda01 100644 --- a/code/modules/antagonists/abductor/machinery/console.dm +++ b/code/modules/antagonists/abductor/machinery/console.dm @@ -178,8 +178,8 @@ c.console = src /obj/machinery/abductor/console/proc/AddSnapshot(mob/living/carbon/human/target) - if(istype(target.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat)) - say("Subject wearing specialized protective headgear, unable to get a proper scan!") + if(target.anti_magic_check(FALSE, FALSE, TRUE, 0)) + say("Subject wearing specialized protective tinfoil gear, unable to get a proper scan!") return var/datum/icon_snapshot/entry = new entry.name = target.name diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm index 3ad6684725..07b4366194 100644 --- a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm +++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm @@ -35,7 +35,7 @@ /obj/item/clockwork/weapon/ratvarian_spear/attack(mob/living/target, mob/living/carbon/human/user) . = ..() - if(!QDELETED(target) && target.stat != DEAD && !target.anti_magic_check() && !is_servant_of_ratvar(target)) //we do bonus damage on attacks unless they're a servant, have a null rod, or are dead + if(!QDELETED(target) && target.stat != DEAD && !target.anti_magic_check(chargecost = 0) && !is_servant_of_ratvar(target)) //we do bonus damage on attacks unless they're a servant, have a null rod, or are dead var/bonus_damage = bonus_burn //normally a total of 20 damage, 30 with ratvar if(issilicon(target)) target.visible_message("[target] shudders violently at [src]'s touch!", "ERROR: Temperature rising!") diff --git a/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm b/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm index 28deba679b..644d9eedd5 100644 --- a/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm +++ b/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm @@ -190,8 +190,8 @@ for(var/mob/living/L in range(1, src)) if(is_servant_of_ratvar(L)) continue - if(L.anti_magic_check()) - var/atom/I = L.anti_magic_check() + var/atom/I = L.anti_magic_check() + if(I) if(isitem(I)) L.visible_message("Strange energy flows into [L]'s [I.name]!", \ "Your [I.name] shields you from [src]!") diff --git a/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm b/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm index df0083e845..7afd9e7dbc 100644 --- a/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm +++ b/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm @@ -60,7 +60,7 @@ else if(isliving(target)) var/mob/living/L = target - if(!L.anti_magic_check()) + if(!L.anti_magic_check(chargecost = 0)) if(isrevenant(L)) var/mob/living/simple_animal/revenant/R = L if(R.revealed) diff --git a/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm b/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm index 10c68b606f..1158b02a4c 100644 --- a/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm +++ b/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm @@ -53,7 +53,7 @@ /obj/structure/destructible/clockwork/taunting_trail/proc/affect_mob(mob/living/L) if(istype(L) && !is_servant_of_ratvar(L)) - if(!L.anti_magic_check()) + if(!L.anti_magic_check(chargecost = 0)) L.confused = min(L.confused + 15, 50) L.dizziness = min(L.dizziness + 15, 50) if(L.confused >= 25) diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index 2e233d26e4..f0fc59834c 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -237,7 +237,7 @@ structure_check() searches for nearby cultist structures required for the invoca to_chat(M, "You need at least two invokers to convert [convertee]!") log_game("Offer rune failed - tried conversion with one invoker") return 0 - if(convertee.anti_magic_check(TRUE, TRUE, FALSE, 0)) //Not chargecost because it can be spammed + if(convertee.anti_magic_check(TRUE, TRUE, chargecost = 0)) //Not major because it can be spammed for(var/M in invokers) to_chat(M, "Something is shielding [convertee]'s mind!") log_game("Offer rune failed - convertee had anti-magic") @@ -767,7 +767,7 @@ structure_check() searches for nearby cultist structures required for the invoca set_light(6, 1, color) for(var/mob/living/L in viewers(T)) if(!iscultist(L) && L.blood_volume) - var/atom/I = L.anti_magic_check() + var/atom/I = L.anti_magic_check(chargecost = 0) if(I) if(isitem(I)) to_chat(L, "[I] suddenly burns hotly before returning to normal!") @@ -797,7 +797,7 @@ structure_check() searches for nearby cultist structures required for the invoca set_light(6, 1, color) for(var/mob/living/L in viewers(T)) if(!iscultist(L) && L.blood_volume) - if(L.anti_magic_check()) + if(L.anti_magic_check(chargecost = 0)) continue L.take_overall_damage(tick_damage*multiplier, tick_damage*multiplier) if(is_servant_of_ratvar(L)) diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm index f380fa68e9..b43024fb31 100644 --- a/code/modules/antagonists/revenant/revenant.dm +++ b/code/modules/antagonists/revenant/revenant.dm @@ -69,7 +69,7 @@ /mob/living/simple_animal/revenant/Initialize(mapload) . = ..() AddSpell(new /obj/effect/proc_holder/spell/targeted/night_vision/revenant(null)) - AddSpell(new /obj/effect/proc_holder/spell/targeted/revenant_transmit(null)) + AddSpell(new /obj/effect/proc_holder/spell/targeted/telepathy/revenant(null)) AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/defile(null)) AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/overload(null)) AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/blight(null)) diff --git a/code/modules/antagonists/revenant/revenant_abilities.dm b/code/modules/antagonists/revenant/revenant_abilities.dm index a03151e2d7..17d200a685 100644 --- a/code/modules/antagonists/revenant/revenant_abilities.dm +++ b/code/modules/antagonists/revenant/revenant_abilities.dm @@ -66,7 +66,7 @@ if(target.anti_magic_check(FALSE, TRUE)) to_chat(src, "Something's wrong! [target] seems to be resisting the siphoning, leaving you vulnerable!") target.visible_message("[target] slumps onto the ground.", \ - "Violets lights, dancing in your vision, receding--") + "Violet lights, dancing in your vision, receding--") draining = FALSE return var/datum/beam/B = Beam(target,icon_state="drain_life",time=INFINITY) @@ -105,36 +105,16 @@ action_background_icon_state = "bg_revenant" //Transmit: the revemant's only direct way to communicate. Sends a single message silently to a single mob -/obj/effect/proc_holder/spell/targeted/revenant_transmit - name = "Transmit" - desc = "Telepathically transmits a message to the target." +/obj/effect/proc_holder/spell/targeted/telepathy/revenant + name = "Revenant Transmit" panel = "Revenant Abilities" - charge_max = 0 - clothes_req = 0 - range = 7 - include_user = 0 action_icon = 'icons/mob/actions/actions_revenant.dmi' action_icon_state = "r_transmit" action_background_icon_state = "bg_revenant" - -/obj/effect/proc_holder/spell/targeted/revenant_transmit/cast(list/targets, mob/living/simple_animal/revenant/user = usr) - for(var/mob/living/M in targets) - var/msg = stripped_input(usr, "What do you wish to tell [M]?", null, "") - if(!msg) - charge_counter = charge_max - return - log_directed_talk(user, M, msg, LOG_SAY, "revenant whisper") - to_chat(user, "You transmit to [M]: [msg]") - if(!M.anti_magic_check(FALSE, TRUE)) //hear no evil - to_chat(M, "You hear something behind you talking... [msg]") - for(var/ded in GLOB.dead_mob_list) - if(!isobserver(ded)) - continue - var/follow_rev = FOLLOW_LINK(ded, user) - var/follow_whispee = FOLLOW_LINK(ded, M) - to_chat(ded, "[follow_rev] [user] Revenant Transmit: \"[msg]\" to [follow_whispee] [M]") - - + notice = "revennotice" + boldnotice = "revenboldnotice" + holy_check = TRUE + tinfoil_check = FALSE /obj/effect/proc_holder/spell/aoe_turf/revenant clothes_req = 0 diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm index fdaa0e8158..0dea8bfe79 100644 --- a/code/modules/clothing/head/misc_special.dm +++ b/code/modules/clothing/head/misc_special.dm @@ -242,26 +242,62 @@ armor = list("melee" = 0, "bullet" = 0, "laser" = -5,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = -5, "fire" = 0, "acid" = 0) equip_delay_other = 140 var/datum/brain_trauma/mild/phobia/paranoia + var/warped = FALSE clothing_flags = ANTI_TINFOIL_MANEUVER +/obj/item/clothing/head/foilhat/Initialize(mapload) + . = ..() + if(!warped) + AddComponent(/datum/component/anti_magic, FALSE, FALSE, TRUE, ITEM_SLOT_HEAD, 6, TRUE, null, CALLBACK(src, .proc/warp_up)) + else + warp_up() + /obj/item/clothing/head/foilhat/equipped(mob/living/carbon/human/user, slot) - ..() - if(slot == SLOT_HEAD) - if(paranoia) - QDEL_NULL(paranoia) - paranoia = new() - user.gain_trauma(paranoia, TRAUMA_RESILIENCE_MAGIC, "conspiracies") - to_chat(user, "As you don the foiled hat, an entire world of conspiracy theories and seemingly insane ideas suddenly rush into your mind. What you once thought unbelievable suddenly seems.. undeniable. Everything is connected and nothing happens just by accident. You know too much and now they're out to get you. ") + . = ..() + if(slot != SLOT_HEAD || warped) + return + if(paranoia) + QDEL_NULL(paranoia) + paranoia = new() + user.gain_trauma(paranoia, TRAUMA_RESILIENCE_MAGIC, "conspiracies") + to_chat(user, "As you don the foiled hat, an entire world of conspiracy theories and seemingly insane ideas suddenly rush into your mind. What you once thought unbelievable suddenly seems.. undeniable. Everything is connected and nothing happens just by accident. You know too much and now they're out to get you. ") + +/obj/item/clothing/head/foilhat/MouseDrop(atom/over_object) + //God Im sorry + if(!warped && iscarbon(usr)) + var/mob/living/carbon/C = usr + if(src == C.head) + to_chat(C, "Why would you want to take this off? Do you want them to get into your mind?!") + return + return ..() /obj/item/clothing/head/foilhat/dropped(mob/user) - ..() + . = ..() if(paranoia) QDEL_NULL(paranoia) +/obj/item/clothing/head/foilhat/proc/warp_up() + name = "scorched tinfoil hat" + desc = "A badly warped up hat. Quite unprobable this will still work against any of fictional and contemporary dangers it used to." + warped = TRUE + if(!isliving(loc) || !paranoia) + return + var/mob/living/target = loc + if(target.get_item_by_slot(SLOT_HEAD) != src) + return + QDEL_NULL(paranoia) + if(!target.IsUnconscious()) + to_chat(target, "Your zealous conspirationism rapidly dissipates as the donned hat warps up into a ruined mess. All those theories starting to sound like nothing but a ridicolous fanfare.") + /obj/item/clothing/head/foilhat/attack_hand(mob/user) - if(iscarbon(user)) + if(!warped && iscarbon(user)) var/mob/living/carbon/C = user if(src == C.head) to_chat(user, "Why would you want to take this off? Do you want them to get into your mind?!") return - ..() + return ..() + +/obj/item/clothing/head/foilhat/microwave_act(obj/machinery/microwave/M) + . = ..() + if(!warped) + warp_up() diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm index 6e21a399ec..5b9bcee94e 100644 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ b/code/modules/clothing/spacesuits/hardsuit.dm @@ -433,7 +433,7 @@ /obj/item/clothing/suit/space/hardsuit/wizard/Initialize() . = ..() - AddComponent(/datum/component/anti_magic, TRUE, FALSE) + AddComponent(/datum/component/anti_magic, TRUE, FALSE, FALSE, ITEM_SLOT_OCLOTHING, INFINITY, FALSE) //Medical hardsuit /obj/item/clothing/head/helmet/space/hardsuit/medical diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm index 5d718a8173..88e17d158c 100644 --- a/code/modules/clothing/spacesuits/miscellaneous.dm +++ b/code/modules/clothing/spacesuits/miscellaneous.dm @@ -368,6 +368,10 @@ Contains: resistance_flags = FIRE_PROOF mutantrace_variation = NO_MUTANTRACE_VARIATION +/obj/item/clothing/suit/space/hardsuit/ert/paranormal/Initialize() + . = ..() + AddComponent(/datum/component/anti_magic, FALSE, FALSE, TRUE, ITEM_SLOT_HEAD) + /obj/item/clothing/suit/space/hardsuit/ert/paranormal name = "paranormal response team suit" desc = "Powerful wards are built into this hardsuit, protecting the user from all manner of paranormal threats." @@ -380,7 +384,7 @@ Contains: /obj/item/clothing/suit/space/hardsuit/ert/paranormal/Initialize() . = ..() - AddComponent(/datum/component/anti_magic, TRUE, TRUE) + AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, ITEM_SLOT_OCLOTHING) /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor name = "inquisitor's hardsuit" diff --git a/code/modules/fields/timestop.dm b/code/modules/fields/timestop.dm index 11a5d416e7..a063296edf 100644 --- a/code/modules/fields/timestop.dm +++ b/code/modules/fields/timestop.dm @@ -133,6 +133,7 @@ /datum/proximity_monitor/advanced/timestop/proc/freeze_mob(mob/living/L) if(L.anti_magic_check(check_anti_magic, check_holy)) + immune += L return L.Stun(20, 1, 1) frozen_mobs[L] = L.anchored diff --git a/code/modules/hydroponics/grown/melon.dm b/code/modules/hydroponics/grown/melon.dm index eb463e5f6d..87db12d892 100644 --- a/code/modules/hydroponics/grown/melon.dm +++ b/code/modules/hydroponics/grown/melon.dm @@ -58,7 +58,20 @@ wine_power = 70 //Water to wine, baby. wine_flavor = "divinity" +/* +/obj/item/reagent_containers/food/snacks/grown/holymelon/Initialize() + . = ..() + var/uses = 1 + if(seed) + uses = round(seed.potency / 20) + AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, ITEM_SLOT_HANDS, uses, TRUE, CALLBACK(src, .proc/block_magic), CALLBACK(src, .proc/expire)) //deliver us from evil o melon god -// /obj/item/reagent_containers/food/snacks/grown/holymelon/Initialize() -// . = ..() -// AddComponent(/datum/component/anti_magic, TRUE, TRUE) //deliver us from evil o melon god +/obj/item/reagent_containers/food/snacks/grown/holymelon/proc/block_magic(mob/user, major) + if(major) + to_chat(user, "[src] hums slightly, and seems to decay a bit.") + +/obj/item/reagent_containers/food/snacks/grown/holymelon/proc/expire(mob/user) + to_chat(user, "[src] rapidly turns into ash!") + qdel(src) + new /obj/effect/decal/cleanable/ash(drop_location()) +*/ \ No newline at end of file diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 9b9d6dd3bb..e146f1686a 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -453,7 +453,7 @@ /obj/item/immortality_talisman/Initialize() . = ..() - AddComponent(/datum/component/anti_magic, TRUE, TRUE) + AddComponent(/datum/component/anti_magic, TRUE, TRUE, TRUE) /datum/action/item_action/immortality name = "Immortality" diff --git a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm index 323bd408cf..ef6a372f9e 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm @@ -95,8 +95,14 @@ Doesn't work on other aliens/AI.*/ var/mob/living/M = input("Select who to whisper to:","Whisper to?",null) as null|mob in options if(!M) return 0 + if(M.anti_magic_check(FALSE, FALSE, TRUE, 0)) + to_chat(user, "As you try to communicate with [M], you're suddenly stopped by a vision of a massive tinfoil wall that streches beyond visible range. It seems you've been foiled.") + return FALSE var/msg = sanitize(input("Message:", "Alien Whisper") as text|null) if(msg) + if(M.anti_magic_check(FALSE, FALSE, TRUE, 0)) + to_chat(user, "As you try to communicate with [M], you're suddenly stopped by a vision of a massive tinfoil wall that streches beyond visible range. It seems you've been foiled.") + return log_directed_talk(user, M, msg, LOG_SAY, tag="alien whisper") to_chat(M, "You hear a strange, alien voice in your head...[msg]") to_chat(user, "You said: \"[msg]\" to [M]") 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 f416854838..79ebdd1a68 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -856,6 +856,8 @@ return FALSE if(HAS_TRAIT(M, TRAIT_MINDSHIELD)) //mindshield implant, no dice return FALSE + if(M.anti_magic_check(FALSE, FALSE, TRUE, 0)) + return FALSE if(M in linked_mobs) return FALSE linked_mobs.Add(M) @@ -941,9 +943,14 @@ var/mob/living/M = input("Select who to send your message to:","Send thought to?",null) as null|mob in options if(!M) return - + if(M.anti_magic_check(FALSE, FALSE, TRUE, 0)) + to_chat(H, "As you try to communicate with [M], you're suddenly stopped by a vision of a massive tinfoil wall that streches beyond visible range. It seems you've been foiled.") + return var/msg = sanitize(input("Message:", "Telepathy") as text|null) if(msg) + if(M.anti_magic_check(FALSE, FALSE, TRUE, 0)) + to_chat(H, "As you try to communicate with [M], you're suddenly stopped by a vision of a massive tinfoil wall that streches beyond visible range. It seems you've been foiled.") + return log_directed_talk(H, M, msg, LOG_SAY, "slime telepathy") to_chat(M, "You hear an alien voice in your head... [msg]") to_chat(H, "You telepathically said: \"[msg]\" to [M]") 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 53c6f1bd0f..3ce49469db 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -88,7 +88,7 @@ to_chat(H, "[victim] doesn't have blood!") return V.drain_cooldown = world.time + 30 - if(victim.anti_magic_check(FALSE, TRUE)) + if(victim.anti_magic_check(FALSE, TRUE, FALSE, 0)) to_chat(victim, "[H] tries to bite you, but stops before touching you!") to_chat(H, "[victim] is blessed! You stop just in time to avoid catching fire.") return diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index d249cd1a61..5aa8ce8cfa 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -935,7 +935,7 @@ apply_effect((amount*RAD_MOB_COEFFICIENT)/max(1, (radiation**2)*RAD_OVERDOSE_REDUCTION), EFFECT_IRRADIATE, blocked) -/mob/living/anti_magic_check(magic = TRUE, holy = FALSE) +/mob/living/anti_magic_check(magic = TRUE, holy = FALSE, chargecost = 1, self = FALSE) . = ..() if(.) return diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 5a7c6e21ab..00b27f26db 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -737,15 +737,17 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0) mob_spell_list -= S qdel(S) -/mob/proc/anti_magic_check(magic = TRUE, holy = FALSE) - if(!magic && !holy) +/mob/proc/anti_magic_check(magic = TRUE, holy = FALSE, tinfoil = FALSE, chargecost = 1, self = FALSE) + if(!magic && !holy && !tinfoil) return var/list/protection_sources = list() - if(SEND_SIGNAL(src, COMSIG_MOB_RECEIVE_MAGIC, magic, holy, protection_sources) & COMPONENT_BLOCK_MAGIC) + if(SEND_SIGNAL(src, COMSIG_MOB_RECEIVE_MAGIC, src, magic, holy, tinfoil, chargecost, self, protection_sources) & COMPONENT_BLOCK_MAGIC) if(protection_sources.len) return pick(protection_sources) else return src + if((magic && HAS_TRAIT(src, TRAIT_ANTIMAGIC)) || (holy && HAS_TRAIT(src, TRAIT_HOLY))) + return src //You can buckle on mobs if you're next to them since most are dense /mob/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE) diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index bb97f9cf99..2bb813d793 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -181,7 +181,7 @@ /obj/item/gun/energy/laser/redtag/hitscan/chaplain/Initialize() . = ..() - AddComponent(/datum/component/anti_magic, TRUE, TRUE) + AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE) /obj/item/gun/energy/laser/redtag/hitscan/chaplain/handle_suicide(mob/living/carbon/human/user, mob/living/carbon/human/target, params, bypass_timer) if(!ishuman(user) || !ishuman(target)) diff --git a/code/modules/projectiles/guns/magic.dm b/code/modules/projectiles/guns/magic.dm index 9dd25bf3e3..55f21a5a2b 100644 --- a/code/modules/projectiles/guns/magic.dm +++ b/code/modules/projectiles/guns/magic.dm @@ -9,6 +9,7 @@ fire_sound = 'sound/weapons/emitter.ogg' flags_1 = CONDUCT_1 w_class = WEIGHT_CLASS_HUGE + var/checks_antimagic = FALSE var/max_charges = 6 var/charges = 0 var/recharge_rate = 4 @@ -31,6 +32,9 @@ return else no_den_usage = 0 + if(checks_antimagic && user.anti_magic_check(TRUE, FALSE, FALSE, 0, TRUE)) + to_chat(user, "Something is interfering with [src].") + return . = ..() /obj/item/gun/magic/can_shoot() diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm index 42033d8c88..4cdfc6d70d 100644 --- a/code/modules/projectiles/guns/magic/wand.dm +++ b/code/modules/projectiles/guns/magic/wand.dm @@ -87,14 +87,17 @@ max_charges = 10 //10, 5, 5, 4 /obj/item/gun/magic/wand/resurrection/zap_self(mob/living/user) + ..() + charges-- + if(user.anti_magic_check()) + user.visible_message("[src] has no effect on [user]!") + return user.revive(full_heal = 1) if(iscarbon(user)) var/mob/living/carbon/C = user C.regenerate_limbs() C.regenerate_organs() to_chat(user, "You feel great!") - charges-- - ..() /obj/item/gun/magic/wand/resurrection/debug //for testing name = "debug wand of healing" diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm index 98eb6f56bf..22dee60eb4 100644 --- a/code/modules/spells/spell.dm +++ b/code/modules/spells/spell.dm @@ -115,6 +115,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th var/nonabstract_req = 0 //spell can only be cast by mobs that are physical entities var/stat_allowed = 0 //see if it requires being conscious/alive, need to set to 1 for ghostpells var/phase_allowed = 0 // If true, the spell can be cast while phased, eg. blood crawling, ethereal jaunting + var/antimagic_allowed = TRUE // If false, the spell cannot be cast while under the effect of antimagic var/invocation = "HURP DURP" //what is uttered when the wizard casts the spell var/invocation_emote_self = null var/invocation_type = "none" //can be none, whisper, emote and shout @@ -147,27 +148,36 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th if(player_lock) if(!user.mind || !(src in user.mind.spell_list) && !(src in user.mob_spell_list)) to_chat(user, "You shouldn't have this spell! Something's wrong.") - return 0 + return FALSE else if(!(src in user.mob_spell_list)) - return 0 + return FALSE var/turf/T = get_turf(user) if(is_centcom_level(T.z) && !centcom_cancast) //Certain spells are not allowed on the centcom zlevel to_chat(user, "You can't cast this spell here.") - return 0 + return FALSE if(!skipcharge) if(!charge_check(user)) - return 0 + return FALSE if(user.stat && !stat_allowed) to_chat(user, "Not when you're incapacitated.") - return 0 + return FALSE + + if(!antimagic_allowed) + var/antimagic = user.anti_magic_check(TRUE, FALSE, chargecost = 0, self = TRUE) + if(antimagic) + if(isitem(antimagic)) + to_chat(user, "[antimagic] is interfering with your magic.") + else + to_chat(user, "Magic seems to flee from you, you can't gather enough power to cast this spell.") + return FALSE if(!phase_allowed && istype(user.loc, /obj/effect/dummy)) to_chat(user, "[name] cannot be cast unless you are completely manifested in the material plane.") - return 0 + return FALSE if(ishuman(user)) @@ -175,7 +185,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th if((invocation_type == "whisper" || invocation_type == "shout") && !H.can_speak_vocal()) to_chat(user, "You can't get the words out!") - return 0 + return FALSE var/list/casting_clothes = typecacheof(list(/obj/item/clothing/suit/wizrobe, /obj/item/clothing/suit/space/hardsuit/wizard, @@ -187,24 +197,24 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th if(clothes_req) //clothes check if(!is_type_in_typecache(H.wear_suit, casting_clothes)) to_chat(H, "I don't feel strong enough without my robe.") - return 0 + return FALSE if(!is_type_in_typecache(H.head, casting_clothes)) to_chat(H, "I don't feel strong enough without my hat.") - return 0 + return FALSE if(cult_req) //CULT_REQ CLOTHES CHECK if(!istype(H.wear_suit, /obj/item/clothing/suit/magusred) && !istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/cult)) to_chat(H, "I don't feel strong enough without my armor.") - return 0 + return FALSE if(!istype(H.head, /obj/item/clothing/head/magus) && !istype(H.head, /obj/item/clothing/head/helmet/space/hardsuit/cult)) to_chat(H, "I don't feel strong enough without my helmet.") - return 0 + return FALSE else if(clothes_req || human_req) to_chat(user, "This spell can only be cast by humans!") - return 0 + return FALSE if(nonabstract_req && (isbrain(user) || ispAI(user))) to_chat(user, "This spell can only be cast by physical beings!") - return 0 + return FALSE if(!skipcharge) @@ -499,6 +509,9 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th if(user.stat && !stat_allowed) return FALSE + if(!antimagic_allowed && user.anti_magic_check(TRUE, FALSE, chargecost = 0, self = TRUE)) + return FALSE + if(!ishuman(user)) if(clothes_req || human_req) return FALSE diff --git a/code/modules/spells/spell_types/forcewall.dm b/code/modules/spells/spell_types/forcewall.dm index 47d6f71f9b..ed78e3315a 100644 --- a/code/modules/spells/spell_types/forcewall.dm +++ b/code/modules/spells/spell_types/forcewall.dm @@ -35,6 +35,6 @@ return TRUE if(ismob(mover)) var/mob/M = mover - if(M.anti_magic_check()) + if(M.anti_magic_check(chargecost = 0)) return TRUE return FALSE diff --git a/code/modules/spells/spell_types/mind_transfer.dm b/code/modules/spells/spell_types/mind_transfer.dm index 107f303049..d78b32c643 100644 --- a/code/modules/spells/spell_types/mind_transfer.dm +++ b/code/modules/spells/spell_types/mind_transfer.dm @@ -61,7 +61,7 @@ Also, you never added distance checking after target is selected. I've went ahea return var/datum/mind/TM = target.mind - if((target.anti_magic_check() || TM.has_antag_datum(/datum/antagonist/wizard) || TM.has_antag_datum(/datum/antagonist/cult) || TM.has_antag_datum(/datum/antagonist/clockcult) || TM.has_antag_datum(/datum/antagonist/changeling) || TM.has_antag_datum(/datum/antagonist/rev)) || cmptext(copytext(target.key,1,2),"@")) + if((target.anti_magic_check(TRUE, FALSE) || TM.has_antag_datum(/datum/antagonist/wizard) || TM.has_antag_datum(/datum/antagonist/cult) || TM.has_antag_datum(/datum/antagonist/clockcult) || TM.has_antag_datum(/datum/antagonist/changeling) || TM.has_antag_datum(/datum/antagonist/rev)) || cmptext(copytext(target.key,1,2),"@")) if(!silent) to_chat(user, "[target.p_their(TRUE)] mind is resisting your spell!") return diff --git a/code/modules/spells/spell_types/spacetime_distortion.dm b/code/modules/spells/spell_types/spacetime_distortion.dm index 7fd857dc51..7a19787675 100644 --- a/code/modules/spells/spell_types/spacetime_distortion.dm +++ b/code/modules/spells/spell_types/spacetime_distortion.dm @@ -86,7 +86,7 @@ /obj/effect/cross_action/spacetime_dist/proc/walk_link(atom/movable/AM) if(ismob(AM)) var/mob/M = AM - if(M.anti_magic_check()) + if(M.anti_magic_check(chargecost = 0)) return if(linked_dist && walks_left > 0) flick("purplesparkles", src) diff --git a/code/modules/spells/spell_types/telepathy.dm b/code/modules/spells/spell_types/telepathy.dm new file mode 100644 index 0000000000..34f100f753 --- /dev/null +++ b/code/modules/spells/spell_types/telepathy.dm @@ -0,0 +1,32 @@ +/obj/effect/proc_holder/spell/targeted/telepathy + name = "Telepathy" + desc = "Telepathically transmits a message to the target." + charge_max = 0 + clothes_req = 0 + range = 7 + include_user = 0 + action_icon = 'icons/mob/actions/actions_revenant.dmi' + action_icon_state = "r_transmit" + action_background_icon_state = "bg_spell" + var/notice = "notice" + var/boldnotice = "boldnotice" + var/magic_check = FALSE + var/holy_check = FALSE + var/tinfoil_check = TRUE + +/obj/effect/proc_holder/spell/targeted/telepathy/cast(list/targets, mob/living/user = usr) + for(var/mob/living/M in targets) + var/msg = stripped_input(usr, "What do you wish to tell [M]?", null, "") + if(!msg) + charge_counter = charge_max + return + log_directed_talk(user, M, msg, LOG_SAY, "[name]") + to_chat(user, "You transmit to [M]: [msg]") + if(!M.anti_magic_check(magic_check, holy_check, tinfoil_check, 0)) //hear no evil + to_chat(M, "You hear something behind you talking... [msg]") + for(var/ded in GLOB.dead_mob_list) + if(!isobserver(ded)) + continue + var/follow_rev = FOLLOW_LINK(ded, user) + var/follow_whispee = FOLLOW_LINK(ded, M) + to_chat(ded, "[follow_rev] [user] [name]: \"[msg]\" to [follow_whispee] [M]") diff --git a/tgstation.dme b/tgstation.dme index e5e6b5c37d..c13db8171d 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -2774,6 +2774,7 @@ #include "code\modules\spells\spell_types\spacetime_distortion.dm" #include "code\modules\spells\spell_types\summonitem.dm" #include "code\modules\spells\spell_types\taeclowndo.dm" +#include "code\modules\spells\spell_types\telepathy.dm" #include "code\modules\spells\spell_types\the_traps.dm" #include "code\modules\spells\spell_types\touch_attacks.dm" #include "code\modules\spells\spell_types\trigger.dm"