mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-11 10:22:13 +00:00
ports anti-magic component code updates (holymelon not included).
This commit is contained in:
@@ -130,7 +130,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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
..()
|
||||
|
||||
@@ -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("<span class='suicide'>[user] is killing [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to get closer to god!</span>")
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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, "<span class='warning'>Your target seems to have some sort of protective headgear on, blocking the message from being sent!</span>")
|
||||
if(C.anti_magic_check(FALSE, FALSE, TRUE, 0))
|
||||
to_chat(user, "<span class='warning'>Your target seems to have some sort of tinfoil protection on, blocking the message from being sent!</span>")
|
||||
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, "<span class='warning'>The specimen's protective headgear is interfering with the sleep inducement!</span>")
|
||||
L.visible_message("<span class='danger'>[user] tried to induced sleep in [L] with [src], but [L.p_their()] headgear protected [L.p_them()]!</span>", \
|
||||
"<span class='userdanger'>You feel a strange wave of heavy drowsiness wash over you, but your headgear deflects most of it!</span>")
|
||||
if(L.anti_magic_check(FALSE, FALSE, TRUE, 0))
|
||||
to_chat(user, "<span class='warning'>The specimen's tinfoil protection is interfering with the sleep inducement!</span>")
|
||||
L.visible_message("<span class='danger'>[user] tried to induced sleep in [L] with [src], but [L.p_their()] tinfoil protected [L.p_them()]!</span>", \
|
||||
"<span class='userdanger'>You feel a strange wave of heavy drowsiness wash over you, but your tinfoil protection deflects most of it!</span>")
|
||||
L.drowsyness += 2
|
||||
return
|
||||
L.visible_message("<span class='danger'>[user] has induced sleep in [L] with [src]!</span>", \
|
||||
@@ -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, "<span class='warning'>The specimen's protective headgear is completely blocking our sleep inducement methods!</span>")
|
||||
L.visible_message("<span class='danger'>[user] tried to induce sleep in [L] with [src], but [L.p_their()] headgear completely protected [L.p_them()]!</span>", \
|
||||
"<span class='userdanger'>Any sense of drowsiness is quickly diminished as your headgear deflects the effects!</span>")
|
||||
if(L.anti_magic_check(FALSE, FALSE, TRUE, 0))
|
||||
to_chat(user, "<span class='warning'>The specimen's tinfoil protection is completely blocking our sleep inducement methods!</span>")
|
||||
L.visible_message("<span class='danger'>[user] tried to induce sleep in [L] with [src], but [L.p_their()] tinfoil completely protected [L.p_them()]!</span>", \
|
||||
"<span class='userdanger'>Any sense of drowsiness is quickly diminished as your tinfoil protection deflects the effects!</span>")
|
||||
return
|
||||
L.drowsyness += 1
|
||||
to_chat(user, "<span class='warning'>Sleep inducement works fully only on stunned specimens! </span>")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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("<span class='warning'>[target] shudders violently at [src]'s touch!</span>", "<span class='userdanger'>ERROR: Temperature rising!</span>")
|
||||
|
||||
@@ -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("<span class='warning'>Strange energy flows into [L]'s [I.name]!</span>", \
|
||||
"<span class='userdanger'>Your [I.name] shields you from [src]!</span>")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -237,7 +237,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
to_chat(M, "<span class='warning'>You need at least two invokers to convert [convertee]!</span>")
|
||||
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, "<span class='warning'>Something is shielding [convertee]'s mind!</span>")
|
||||
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, "<span class='userdanger'>[I] suddenly burns hotly before returning to normal!</span>")
|
||||
@@ -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))
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
if(target.anti_magic_check(FALSE, TRUE))
|
||||
to_chat(src, "<span class='revenminor'>Something's wrong! [target] seems to be resisting the siphoning, leaving you vulnerable!</span>")
|
||||
target.visible_message("<span class='warning'>[target] slumps onto the ground.</span>", \
|
||||
"<span class='revenwarning'>Violets lights, dancing in your vision, receding--</span>")
|
||||
"<span class='revenwarning'>Violet lights, dancing in your vision, receding--</span>")
|
||||
draining = FALSE
|
||||
return
|
||||
var/datum/beam/B = Beam(target,icon_state="drain_life",time=INFINITY)
|
||||
@@ -104,36 +104,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, "<span class='revenboldnotice'>You transmit to [M]:</span> <span class='revennotice'>[msg]</span>")
|
||||
if(!M.anti_magic_check(FALSE, TRUE)) //hear no evil
|
||||
to_chat(M, "<span class='revenboldnotice'>You hear something behind you talking...</span> <span class='revennotice'>[msg]</span>")
|
||||
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] <span class='revenboldnotice'>[user] Revenant Transmit:</span> <span class='revennotice'>\"[msg]\" to</span> [follow_whispee] <span class='name'>[M]</span>")
|
||||
|
||||
|
||||
notice = "revennotice"
|
||||
boldnotice = "revenboldnotice"
|
||||
holy_check = TRUE
|
||||
tinfoil_check = FALSE
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant
|
||||
clothes_req = 0
|
||||
|
||||
@@ -238,25 +238,61 @@
|
||||
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
|
||||
|
||||
/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, "<span class='warning'>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. </span>")
|
||||
. = ..()
|
||||
if(slot != SLOT_HEAD || warped)
|
||||
return
|
||||
if(paranoia)
|
||||
QDEL_NULL(paranoia)
|
||||
paranoia = new()
|
||||
user.gain_trauma(paranoia, TRAUMA_RESILIENCE_MAGIC, "conspiracies")
|
||||
to_chat(user, "<span class='warning'>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. </span>")
|
||||
|
||||
/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, "<span class='userdanger'>Why would you want to take this off? Do you want them to get into your mind?!</span>")
|
||||
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, "<span class='warning'>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.</span>")
|
||||
|
||||
/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, "<span class='userdanger'>Why would you want to take this off? Do you want them to get into your mind?!</span>")
|
||||
return
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/head/foilhat/microwave_act(obj/machinery/microwave/M)
|
||||
. = ..()
|
||||
if(!warped)
|
||||
warp_up()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, "<span class='warning'>[src] hums slightly, and seems to decay a bit.</span>")
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/grown/holymelon/proc/expire(mob/user)
|
||||
to_chat(user, "<span class='warning'>[src] rapidly turns into ash!</span>")
|
||||
qdel(src)
|
||||
new /obj/effect/decal/cleanable/ash(drop_location())
|
||||
*/
|
||||
@@ -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"
|
||||
@@ -796,21 +796,21 @@
|
||||
|
||||
/obj/item/melee/ghost_sword/proc/ghost_check()
|
||||
var/list/mob/dead/observer/current_spirits = list()
|
||||
|
||||
|
||||
recursive_orbit_collect(src, current_spirits)
|
||||
recursive_orbit_collect(loc, current_spirits) //anything holding us
|
||||
|
||||
|
||||
for(var/i in spirits - current_spirits)
|
||||
var/mob/dead/observer/G = i
|
||||
G.invisibility = GLOB.observer_default_invisibility
|
||||
|
||||
|
||||
for(var/i in current_spirits)
|
||||
var/mob/dead/observer/G = i
|
||||
G.invisibility = 0
|
||||
|
||||
|
||||
spirits = current_spirits
|
||||
return length(spirits)
|
||||
|
||||
|
||||
/obj/item/melee/ghost_sword/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
force = 0
|
||||
var/ghost_counter = ghost_check()
|
||||
|
||||
@@ -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, "<span class='noticealien'>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.</span>")
|
||||
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, "<span class='notice'>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.</span>")
|
||||
return
|
||||
log_directed_talk(user, M, msg, LOG_SAY, tag="alien whisper")
|
||||
to_chat(M, "<span class='noticealien'>You hear a strange, alien voice in your head...</span>[msg]")
|
||||
to_chat(user, "<span class='noticealien'>You said: \"[msg]\" to [M]</span>")
|
||||
|
||||
@@ -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, "<span class='notice'>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.</span>")
|
||||
return
|
||||
var/msg = sanitize(input("Message:", "Telepathy") as text|null)
|
||||
if(msg)
|
||||
if(M.anti_magic_check(FALSE, FALSE, TRUE, 0))
|
||||
to_chat(H, "<span class='notice'>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.</span>")
|
||||
return
|
||||
log_directed_talk(H, M, msg, LOG_SAY, "slime telepathy")
|
||||
to_chat(M, "<span class='notice'>You hear an alien voice in your head... </span><font color=#008CA2>[msg]</font>")
|
||||
to_chat(H, "<span class='notice'>You telepathically said: \"[msg]\" to [M]</span>")
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
to_chat(H, "<span class='notice'>[victim] doesn't have blood!</span>")
|
||||
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, "<span class='warning'>[H] tries to bite you, but stops before touching you!</span>")
|
||||
to_chat(H, "<span class='warning'>[victim] is blessed! You stop just in time to avoid catching fire.</span>")
|
||||
return
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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, "<span class='warning'>Something is interfering with [src].</span>")
|
||||
return
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/magic/can_shoot()
|
||||
|
||||
@@ -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("<span class='warning'>[src] has no effect on [user]!</span>")
|
||||
return
|
||||
user.revive(full_heal = 1)
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
C.regenerate_limbs()
|
||||
C.regenerate_organs()
|
||||
to_chat(user, "<span class='notice'>You feel great!</span>")
|
||||
charges--
|
||||
..()
|
||||
|
||||
/obj/item/gun/magic/wand/resurrection/debug //for testing
|
||||
name = "debug wand of healing"
|
||||
|
||||
@@ -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, "<span class='warning'>You shouldn't have this spell! Something's wrong.</span>")
|
||||
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, "<span class='notice'>You can't cast this spell here.</span>")
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(!skipcharge)
|
||||
if(!charge_check(user))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(user.stat && !stat_allowed)
|
||||
to_chat(user, "<span class='notice'>Not when you're incapacitated.</span>")
|
||||
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, "<span class='notice'>[antimagic] is interfering with your magic.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>Magic seems to flee from you, you can't gather enough power to cast this spell.</span>")
|
||||
return FALSE
|
||||
|
||||
if(!phase_allowed && istype(user.loc, /obj/effect/dummy))
|
||||
to_chat(user, "<span class='notice'>[name] cannot be cast unless you are completely manifested in the material plane.</span>")
|
||||
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, "<span class='notice'>You can't get the words out!</span>")
|
||||
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, "<span class='notice'>I don't feel strong enough without my robe.</span>")
|
||||
return 0
|
||||
return FALSE
|
||||
if(!is_type_in_typecache(H.head, casting_clothes))
|
||||
to_chat(H, "<span class='notice'>I don't feel strong enough without my hat.</span>")
|
||||
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, "<span class='notice'>I don't feel strong enough without my armor.</span>")
|
||||
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, "<span class='notice'>I don't feel strong enough without my helmet.</span>")
|
||||
return 0
|
||||
return FALSE
|
||||
else
|
||||
if(clothes_req || human_req)
|
||||
to_chat(user, "<span class='notice'>This spell can only be cast by humans!</span>")
|
||||
return 0
|
||||
return FALSE
|
||||
if(nonabstract_req && (isbrain(user) || ispAI(user)))
|
||||
to_chat(user, "<span class='notice'>This spell can only be cast by physical beings!</span>")
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, "<span class='warning'>[target.p_their(TRUE)] mind is resisting your spell!</span>")
|
||||
return
|
||||
|
||||
@@ -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)
|
||||
|
||||
32
code/modules/spells/spell_types/telepathy.dm
Normal file
32
code/modules/spells/spell_types/telepathy.dm
Normal file
@@ -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, "<span class='[boldnotice]'>You transmit to [M]:</span> <span class='[notice]'>[msg]</span>")
|
||||
if(!M.anti_magic_check(magic_check, holy_check, tinfoil_check, 0)) //hear no evil
|
||||
to_chat(M, "<span class='[boldnotice]'>You hear something behind you talking...</span> <span class='[notice]'>[msg]</span>")
|
||||
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] <span class='[boldnotice]'>[user] [name]:</span> <span class='[notice]'>\"[msg]\" to</span> [follow_whispee] <span class='name'>[M]</span>")
|
||||
Reference in New Issue
Block a user