mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-13 11:12:14 +00:00
## About The Pull Request This PR introduces new examine tags for the antimagic component to give players specific feedback on an item's defensive properties. | Condition | Tag | Description | | :--- | :--- | :--- | | **All Resistances** | `magic-proof` | "It is thoroughly shielded against all known forms of magic." | | **MAGIC_RESISTANCE** | `warded` | "It possesses a general resistance to regular spells and magic." | | **MAGIC_RESISTANCE_MIND** | `telepathy-proof` | "It appears to be insulated against telepathic or mental influence." | | **MAGIC_RESISTANCE_HOLY** | `blessed` | "It is protected by a divine shield against unholy and dark forms of magic." | ## Why It's Good For The Game Gives players more context and helpful information about items. ## Changelog 🆑 qol: New examine tags for the antimagic component to give players specific feedback on an item's magical resistance. /🆑
183 lines
6.8 KiB
Plaintext
183 lines
6.8 KiB
Plaintext
/// This provides different types of magic resistance on an object
|
|
/datum/component/anti_magic
|
|
/// 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 block magic
|
|
var/datum/callback/block_magic
|
|
/// The callback invoked when twe have been depleted of all charges
|
|
var/datum/callback/expiration
|
|
/// Callback to invoke to see if we can block magic
|
|
var/datum/callback/check_blocking
|
|
/// 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
|
|
* * block_magic (optional) The proc that is triggered when an object blocks magic
|
|
* * expiration (optional) The proc that is triggered when the object is depleted of charges
|
|
* * check_blocking (optional) The proc that is triggered to check if we can block magic
|
|
* *
|
|
* 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 = ALL,
|
|
datum/callback/block_magic,
|
|
datum/callback/expiration,
|
|
datum/callback/check_blocking,
|
|
)
|
|
|
|
var/atom/movable/movable = parent
|
|
if(!istype(movable))
|
|
return COMPONENT_INCOMPATIBLE
|
|
|
|
var/compatible = FALSE
|
|
if(isitem(movable))
|
|
RegisterSignal(movable, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip))
|
|
RegisterSignal(movable, COMSIG_ITEM_DROPPED, PROC_REF(on_drop))
|
|
RegisterSignal(movable, COMSIG_ATOM_EXAMINE_TAGS, PROC_REF(get_examine_tags))
|
|
RegisterSignals(movable, list(COMSIG_ITEM_ATTACK, COMSIG_ITEM_ATTACK_ATOM), PROC_REF(on_attack))
|
|
compatible = TRUE
|
|
else if(ismob(movable))
|
|
register_antimagic_signals(movable)
|
|
compatible = TRUE
|
|
|
|
if(movable.can_buckle)
|
|
RegisterSignal(movable, COMSIG_MOVABLE_BUCKLE, PROC_REF(on_buckle))
|
|
RegisterSignal(movable, COMSIG_MOVABLE_UNBUCKLE, PROC_REF(on_unbuckle))
|
|
compatible = TRUE
|
|
|
|
if(!compatible)
|
|
return COMPONENT_INCOMPATIBLE
|
|
|
|
src.antimagic_flags = antimagic_flags
|
|
src.charges = charges
|
|
src.inventory_flags = inventory_flags
|
|
src.block_magic = block_magic
|
|
src.expiration = expiration
|
|
src.check_blocking = check_blocking
|
|
|
|
/datum/component/anti_magic/Destroy(force)
|
|
block_magic = 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_buckle(atom/movable/source, mob/living/bucklee)
|
|
SIGNAL_HANDLER
|
|
register_antimagic_signals(bucklee)
|
|
|
|
/datum/component/anti_magic/proc/on_unbuckle(atom/movable/source, mob/living/bucklee)
|
|
SIGNAL_HANDLER
|
|
unregister_antimagic_signals(bucklee)
|
|
|
|
/datum/component/anti_magic/proc/get_examine_tags(atom/source, mob/user, list/examine_list)
|
|
SIGNAL_HANDLER
|
|
|
|
if(antimagic_flags == ALL_MAGIC_RESISTANCE)
|
|
examine_list["magic-proof"] = "It is thoroughly shielded against all known forms of magic."
|
|
return
|
|
|
|
if(antimagic_flags & MAGIC_RESISTANCE)
|
|
examine_list["warded"] = "It possesses a general resistance to regular spells and magic."
|
|
if(antimagic_flags & MAGIC_RESISTANCE_MIND)
|
|
examine_list["telepathy-proof"] = "It appears to be insulated against telepathic or mental influence."
|
|
if(antimagic_flags & MAGIC_RESISTANCE_HOLY)
|
|
examine_list["blessed"] = "It is protected by a divine shield against unholy and dark forms of 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
|
|
|
|
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
|
|
|
|
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
|
|
|
|
if(check_blocking && !check_blocking.Invoke())
|
|
return NONE
|
|
|
|
// 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
|
|
|
|
block_magic?.Invoke(source, parent)
|
|
if((charges != INFINITY) && charge_cost > 0)
|
|
charges -= charge_cost
|
|
if(charges <= 0)
|
|
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)
|
|
if(HAS_TRAIT(user, TRAIT_ANTIMAGIC_NO_SELFBLOCK)) // this trait bypasses magic casting restrictions
|
|
return NONE
|
|
return COMPONENT_MAGIC_BLOCKED
|
|
|
|
return NONE
|
|
|
|
/datum/component/anti_magic/proc/on_attack(atom/movable/source, atom/target, mob/user)
|
|
SIGNAL_HANDLER
|
|
SEND_SIGNAL(target, COMSIG_ATOM_HOLYATTACK, source, user, antimagic_flags)
|