Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion code/__DEFINES/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,10 @@
#define TRAIT_TOXINLOVER "toxinlover"
#define TRAIT_TOXIMMUNE "toxin_immune"
#define TRAIT_NOBREATH "no_breath"
#define TRAIT_ANTIMAGIC "anti_magic"
/// This mob is antimagic, and immune to spells / cannot cast spells
#define TRAIT_ANTIMAGIC "anti_magic"
/// This mob recently blocked magic with some form of antimagic
#define TRAIT_RECENTLY_BLOCKED_MAGIC "recently_blocked_magic"
#define TRAIT_HOLY "holy"
#define TRAIT_DEPRESSION "depression"
#define TRAIT_JOLLY "jolly"
Expand Down
152 changes: 117 additions & 35 deletions code/datums/components/anti_magic.dm
Original file line number Diff line number Diff line change
@@ -1,49 +1,131 @@
/// This provides different types of magic resistance on an object
/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, _psychic = FALSE, _allowed_slots, _charges, _blocks_self = TRUE, datum/callback/_reaction, datum/callback/_expire)
/// A bitflag with the types of magic resistance on the object
var/antimagic_flags
/// The amount of times the object can protect the user from magic
/// Set to INFINITY to have, well, infinite charges.
var/charges
/// The inventory slot the object must be located at in order to activate
var/inventory_flags
/// The callback invoked when we have been drained a antimagic charge
var/datum/callback/drain_antimagic
/// The callback invoked when twe have been depleted of all charges
var/datum/callback/expiration
/// Whether we should, on equipping, alert the caster that this item can block any of their spells
/// This changes between true and false on equip and drop, don't set it outright to something
var/alert_caster_on_equip = TRUE

/**
* Adds magic resistances to an object
*
* Magic resistance will prevent magic from affecting the user if it has the correct resistance
* against the type of magic being used
*
* args:
* * antimagic_flags (optional) A bitflag with the types of magic resistance on the object
* * charges (optional) The amount of times the object can protect the user from magic
* * inventory_flags (optional) The inventory slot the object must be located at in order to activate
* * drain_antimagic (optional) The proc that is triggered when an object has been drained a antimagic charge
* * expiration (optional) The proc that is triggered when the object is depleted of charges
* *
* antimagic bitflags: (see code/__DEFINES/magic.dm)
* * MAGIC_RESISTANCE - Default magic resistance that blocks normal magic (wizard, spells, staffs)
* * MAGIC_RESISTANCE_MIND - Tinfoil hat magic resistance that blocks mental magic (telepathy, abductors, jelly people)
* * MAGIC_RESISTANCE_HOLY - Holy magic resistance that blocks unholy magic (revenant, cult, vampire, voice of god)
**/
/datum/component/anti_magic/Initialize(
antimagic_flags = MAGIC_RESISTANCE,
charges = INFINITY,
inventory_flags = ~ITEM_SLOT_BACKPACK, // items in a backpack won't activate, anywhere else is fine
datum/callback/drain_antimagic,
datum/callback/expiration,
)

if(isitem(parent))
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip))
RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_drop))
else if(ismob(parent))
RegisterSignal(parent, COMSIG_MOB_RECEIVE_MAGIC, PROC_REF(protect))
register_antimagic_signals(parent)
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)
if(!CHECK_BITFIELD(allowed_slots, slot)) //Check that the slot is valid for antimagic
UnregisterSignal(equipper, COMSIG_MOB_RECEIVE_MAGIC)
src.antimagic_flags = antimagic_flags
src.charges = charges
src.inventory_flags = inventory_flags
src.drain_antimagic = drain_antimagic
src.expiration = expiration

/datum/component/anti_magic/Destroy(force, silent)
drain_antimagic = null
expiration = null
return ..()

/datum/component/anti_magic/proc/register_antimagic_signals(datum/on_what)
RegisterSignal(on_what, COMSIG_MOB_RECEIVE_MAGIC, PROC_REF(block_receiving_magic), override = TRUE)
RegisterSignal(on_what, COMSIG_MOB_RESTRICT_MAGIC, PROC_REF(restrict_casting_magic), override = TRUE)

/datum/component/anti_magic/proc/unregister_antimagic_signals(datum/on_what)
UnregisterSignal(on_what, list(COMSIG_MOB_RECEIVE_MAGIC, COMSIG_MOB_RESTRICT_MAGIC))

/datum/component/anti_magic/proc/on_equip(atom/movable/source, mob/equipper, slot)
SIGNAL_HANDLER

if(!(inventory_flags & slot)) //Check that the slot is valid for antimagic
unregister_antimagic_signals(equipper)
return
RegisterSignal(equipper, COMSIG_MOB_RECEIVE_MAGIC, PROC_REF(protect), TRUE)

/datum/component/anti_magic/proc/on_drop(datum/source, mob/user)
UnregisterSignal(user, COMSIG_MOB_RECEIVE_MAGIC)
register_antimagic_signals(equipper)
if(!alert_caster_on_equip)
return

// Check to see if we have any spells that are blocked due to antimagic
for(var/datum/action/cooldown/spell/magic_spell in equipper.actions)
if(!(magic_spell.spell_requirements & SPELL_REQUIRES_NO_ANTIMAGIC))
continue

if(!(antimagic_flags & magic_spell.antimagic_flags))
continue

/datum/component/anti_magic/proc/protect(datum/source, mob/user, _magic, _holy, _psychic, chargecost, self, list/protection_sources)
if(((_magic && magic) || (_holy && holy) || (_psychic && psychic)) && (!self || blocks_self))
protection_sources += parent
reaction?.Invoke(user, chargecost)
charges -= chargecost
to_chat(equipper, span_warning("[parent] is interfering with your ability to cast magic!"))
alert_caster_on_equip = FALSE
break

/datum/component/anti_magic/proc/on_drop(atom/movable/source, mob/user)
SIGNAL_HANDLER

// Reset alert
if(source.loc != user)
alert_caster_on_equip = TRUE
unregister_antimagic_signals(user)

/datum/component/anti_magic/proc/block_receiving_magic(mob/living/carbon/source, casted_magic_flags, charge_cost, list/antimagic_sources)
SIGNAL_HANDLER

// We do not block this type of magic, good day
if(!(casted_magic_flags & antimagic_flags))
return NONE

// We have already blocked this spell
if(parent in antimagic_sources)
return NONE

// Block success! Add this parent to the list of antimagic sources
antimagic_sources += parent

if((charges != INFINITY) && charge_cost > 0)
drain_antimagic?.Invoke(source, parent)
charges -= charge_cost
if(charges <= 0)
expire?.Invoke(user)
qdel(src)
expiration?.Invoke(source, parent)
qdel(src) // no more antimagic

return COMPONENT_MAGIC_BLOCKED

/// cannot cast magic with the same type of antimagic present
/datum/component/anti_magic/proc/restrict_casting_magic(mob/user, magic_flags)
SIGNAL_HANDLER

if(magic_flags & antimagic_flags)
return COMPONENT_MAGIC_BLOCKED

return NONE
4 changes: 2 additions & 2 deletions code/datums/status_effects/debuffs/debuffs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,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(chargecost = 0) && number_legs)
if(iscarbon(owner) && !is_servant_of_ratvar(owner) && !owner.can_block_magic(charge_cost = 0) && number_legs)
if(force_damage || owner.m_intent != MOVE_INTENT_WALK)
if(GLOB.ratvar_awakens)
owner.Paralyze(20)
Expand Down Expand Up @@ -467,7 +467,7 @@
owner.remove_status_effect(/datum/status_effect/drowsiness)
owner.remove_status_effect(/datum/status_effect/confusion)
severity = 0
else if(!owner.anti_magic_check(chargecost = 0) && owner.stat != DEAD && severity)
else if(!owner.can_block_magic(charge_cost = 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))
Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/items/gems.dm
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@

/obj/item/gem/dark/Initialize(mapload)
. = ..()
AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE)
AddComponent(/datum/component/anti_magic, MAGIC_RESISTANCE|MAGIC_RESISTANCE_HOLY)

/obj/item/gem/random
name = "random gem"
Expand Down
4 changes: 2 additions & 2 deletions code/game/objects/items/holy_weapons.dm
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

/obj/item/nullrod/Initialize(mapload)
. = ..()
AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE)
AddComponent(/datum/component/anti_magic, MAGIC_RESISTANCE|MAGIC_RESISTANCE_HOLY)

/obj/item/nullrod/suicide_act(mob/user)
user.visible_message(span_suicide("[user] is killing [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to get closer to god!"))
Expand Down Expand Up @@ -1174,7 +1174,7 @@ it also swaps back if it gets thrown into the chaplain, but the chaplain catches

/mob/living/simple_animal/nullrod/Initialize(mapload)
. = ..()
AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE)
AddComponent(/datum/component/anti_magic, MAGIC_RESISTANCE|MAGIC_RESISTANCE_HOLY)
button = new(src)
button.Grant(src)

Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/items/singularityhammer.dm
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
. = ..()
if(isliving(hit_atom))
var/mob/M = hit_atom
var/atom/A = M.anti_magic_check()
var/atom/A = M.can_block_magic()
if(A)
if(isitem(A))
M.visible_message(span_warning("[M]'s [A] glows brightly as it disrupts the Mjolnir's power!"))
Expand Down
6 changes: 3 additions & 3 deletions code/game/objects/items/storage/belt.dm
Original file line number Diff line number Diff line change
Expand Up @@ -872,7 +872,7 @@
/// The time it takes for an arrow to return
var/return_time = 5 SECONDS
/// If the return is blocked by anti-magic
var/anti_magic_check = TRUE
var/check_for_antimagic = TRUE

/obj/item/storage/belt/quiver/returning/Initialize(mapload)
. = ..()
Expand All @@ -888,7 +888,7 @@
return
if(ismob(arrow.loc))
var/mob/arrow_holder = arrow.loc
if(anti_magic_check && arrow_holder.anti_magic_check(TRUE, FALSE ,FALSE, 0))
if(check_for_antimagic && arrow_holder.can_block_magic(charge_cost = 0))
to_chat(arrow_holder, span_notice("You feel [arrow] tugging on you."))
return
var/mob/living/carbon/carbon = arrow.loc
Expand Down Expand Up @@ -935,7 +935,7 @@
icon_state = "quiver_holding"
item_state = "quiver_holding"
content_overlays = FALSE // The arrows are stored in the quiver, so none of it hangs out
anti_magic_check = FALSE
check_for_antimagic = FALSE

/obj/item/storage/belt/quiver/returning/holding/Initialize(mapload)
. = ..()
Expand Down
4 changes: 4 additions & 0 deletions code/game/objects/items/storage/book.dm
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "burning",
slot_flags = ITEM_SLOT_BELT
var/success_heal_chance = 60

/obj/item/storage/book/bible/Initialize(mapload)
. = ..()
AddComponent(/datum/component/anti_magic, MAGIC_RESISTANCE_HOLY)

/obj/item/storage/book/bible/suicide_act(mob/user)
user.visible_message(span_suicide("[user] is offering [user.p_them()]self to [deity_name]! It looks like [user.p_theyre()] trying to commit suicide!"))
return (BRUTELOSS)
Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/structures/traps.dm
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
var/mob/M = AM
if(M.mind in immune_minds)
return
if(M.anti_magic_check())
if(M.can_block_magic())
flare()
return
if(charges <= 0)
Expand Down
6 changes: 3 additions & 3 deletions code/modules/antagonists/abductor/equipment/abduction_gear.dm
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@
if(QDELETED(G))
return

if(C.anti_magic_check(FALSE, FALSE, TRUE, 0))
if(C.can_block_magic(MAGIC_RESISTANCE_MIND, charge_cost = 0))
to_chat(user, span_warning("Your target seems to have some sort of tinfoil protection on, blocking the message from being sent!"))
return

Expand Down Expand Up @@ -516,7 +516,7 @@ 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(L.anti_magic_check(FALSE, FALSE, TRUE))
if(L.can_block_magic(MAGIC_RESISTANCE_MIND, charge_cost = 0))
to_chat(user, span_warning("The specimen's tinfoil protection is interfering with the sleep inducement!"))
L.visible_message(span_danger("[user] tried to induced sleep in [L] with [src], but [L.p_their()] tinfoil protection [L.p_them()]!"), \
span_userdanger("You feel a strange wave of heavy drowsiness wash over you, but your tinfoil protection deflects most of it!"))
Expand All @@ -528,7 +528,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
L.Sleeping(30 SECONDS)
log_combat(user, L, "put to sleep")
else
if(L.anti_magic_check(FALSE, FALSE, TRUE, 0))
if(L.can_block_magic(MAGIC_RESISTANCE_MIND, charge_cost = 0))
to_chat(user, span_warning("The specimen's tinfoil protection is completely blocking our sleep inducement methods!"))
L.visible_message(span_danger("[user] tried to induce sleep in [L] with [src], but [L.p_their()] tinfoil protection completely protected [L.p_them()]!"), \
span_userdanger("Any sense of drowsiness is quickly diminished as your tinfoil protection deflects the effects!"))
Expand Down
2 changes: 1 addition & 1 deletion code/modules/antagonists/abductor/machinery/console.dm
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@
c.console = src

/obj/machinery/abductor/console/proc/AddSnapshot(mob/living/carbon/human/target)
if(target.anti_magic_check(FALSE, FALSE, TRUE, 0))
if(target.can_block_magic(MAGIC_RESISTANCE_MIND, charge_cost = 0))
say("Subject wearing specialized protective tinfoil gear, unable to get a proper scan!")
return
var/datum/icon_snapshot/entry = new
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
var/sigil_name = "Sigil"
var/resist_string = "glows blinding white" //string for when a null rod blocks its effects, "glows [resist_string]"
var/check_antimagic = TRUE
var/check_holy = FALSE

/obj/effect/clockwork/sigil/attackby(obj/item/I, mob/living/user, params)
if(I.force)
Expand Down Expand Up @@ -46,7 +45,7 @@
var/mob/living/L = AM
if(L.stat <= stat_affected)
if((!is_servant_of_ratvar(L) || (affects_servants && is_servant_of_ratvar(L))) && (L.mind || L.has_status_effect(STATUS_EFFECT_SIGILMARK)) && !isdrone(L))
var/atom/I = L.anti_magic_check(check_antimagic, check_holy)
var/atom/I = L.can_block_magic((check_antimagic ? MAGIC_RESISTANCE : NONE))
if(I)
if(isitem(I))
L.visible_message(span_warning("[L]'s [I.name] [resist_string], protecting [L.p_them()] from [src]'s effects!"), \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@
var/mob/living/L = clicked_on
if(is_servant_of_ratvar(L) || L.stat || L.has_status_effect(STATUS_EFFECT_KINDLE))
return BULLET_ACT_HIT
var/atom/O = L.anti_magic_check()
var/atom/O = L.can_block_magic()
playsound(L, 'sound/magic/fireball.ogg', 50, TRUE, frequency = 1.25)
if(O)
if(isitem(O))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,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(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
if(!QDELETED(target) && target.stat != DEAD && !target.can_block_magic(charge_cost = 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(span_warning("[target] shudders violently at [src]'s touch!"), span_userdanger("ERROR: Temperature rising!"))
Expand All @@ -56,7 +56,7 @@
else
L.visible_message(span_warning("[src] bounces off of [L], as if repelled by an unseen force!"))
else if(!..())
if(!L.anti_magic_check())
if(!L.can_block_magic())
if(issilicon(L) || iscultist(L))
L.Paralyze(100)
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@
for(var/mob/living/L in range(1, src))
if(is_servant_of_ratvar(L))
continue
var/atom/I = L.anti_magic_check()
var/atom/I = L.can_block_magic()
if(I)
if(isitem(I))
L.visible_message(span_warning("Strange energy flows into [L]'s [I.name]!"), \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
if(last_process + time_between_shots < world.time)
if(isliving(target))
var/mob/living/L = target
if(!L.anti_magic_check(chargecost = 0))
if(!L.can_block_magic(charge_cost = 0))
if(isrevenant(L))
var/mob/living/simple_animal/revenant/R = L
if(R.revealed)
Expand Down Expand Up @@ -109,7 +109,7 @@
/obj/structure/destructible/clockwork/ocular_warden/proc/acquire_nearby_targets()
. = list()
for(var/mob/living/L in viewers(sight_range, src)) //Doesn't attack the blind
if(is_servant_of_ratvar(L) || (HAS_TRAIT(L, TRAIT_BLIND)) || L.anti_magic_check(TRUE, TRUE))
if(is_servant_of_ratvar(L) || (HAS_TRAIT(L, TRAIT_BLIND)) || L.can_block_magic(MAGIC_RESISTANCE_HOLY|MAGIC_RESISTANCE_MIND))
continue
var/obj/item/storage/book/bible/B = L.bible_check()
if(B)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,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(chargecost = 0))
if(!L.can_block_magic(charge_cost = 0))
L.adjust_confusion_up_to(15 SECONDS, 50 SECONDS)
L.adjust_dizzy_up_to(15 SECONDS, 50 SECONDS)
L.Paralyze(FLOOR(L.get_timed_status_effect_duration(/datum/status_effect/confusion) * 0.8, 1))
Expand Down
Loading