mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-11 10:11:09 +00:00
<!-- Write **BELOW** The Headers and **ABOVE** The comments else it may not be viewable. --> <!-- You can view Contributing.MD for a detailed description of the pull request process. --> ## About The Pull Request So yesterday I've spotted that we had wrong SLOTS_AMT value set, and went a bit down a rabbit hole and found how abhorrent our ITEM_SLOT_BACKPACK and ITEM_SLOT_BELTPACK usage is. They're not real inventory slots, but just "hints" at items being located in backpacks or belts, or instructions to put an item into a belt/backpack. This PR rewrites all usages of them as "hints", and adds an equip_to_storage proc used to equip an item into a storage positioned in a certain slot, so ``equip_to_slot_if_possible(item, ITEM_SLOT_BACKPACK)`` is now ``equip_to_storage(item, ITEM_SLOT_BACK)`` ## Why It's Good For The Game Its really stupid and we shouldn't have those as slot flags, ITEM_SLOT_HANDS at least makes sense but those two are just absurd. Should make equipping things into non-backpack storage a bit easier too, in case we end up going through with the idea of suit/uniform pockets being a major part of player inventory. ## Changelog <!-- If your PR modifies aspects of the game that can be concretely observed by players or admins you should add a changelog. If your change does NOT meet this description, remove this section. Be sure to properly mark your PRs to prevent unnecessary GBP loss. You can read up on GBP and its effects on PRs in the tgstation guides for contributors. Please note that maintainers freely reserve the right to remove and add tags should they deem it appropriate. You can attempt to finagle the system all you want, but it's best to shoot for clear communication right off the bat. --> 🆑 refactor: Refactored how backpack and belt contents are handled in mob inventory code, report any issues with lingering item effects or inability to equip things into them! /🆑 <!-- Both 🆑's are required for the changelog to work! You can put your name to the right of the first 🆑 if you want to overwrite your GitHub username as author ingame. --> <!-- You can use multiple of the same prefix (they're only used for the icon ingame) and delete the unneeded ones. Despite some of the tags, changelogs should generally represent how a player might be affected by the changes rather than a summary of the PR's contents. -->
161 lines
5.8 KiB
Plaintext
161 lines
5.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 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 = ALL,
|
|
datum/callback/drain_antimagic,
|
|
datum/callback/expiration,
|
|
)
|
|
|
|
|
|
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))
|
|
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.drain_antimagic = drain_antimagic
|
|
src.expiration = expiration
|
|
|
|
/datum/component/anti_magic/Destroy(force)
|
|
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_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/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
|
|
|
|
// 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)
|
|
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)
|