Afterattack is dead, long live Afterattack (#83818)

## About The Pull Request

- Afterattack is a very simple proc now: All it does is this, and all
it's used for is for having a convenient place to put effects an item
does after a successful attack (IE, the attack was not blocked)


![image](https://github.com/tgstation/tgstation/assets/51863163/1e70f7be-0990-4827-a60a-0c9dd0e0ee49)

- An overwhelming majority of afterattack implementations have been
moved to `interact_with_atom` or the new `ranged_interact_with_atom`

I have manually tested many of the refactored procs but there was 200+
so it's kinda hard

## Why It's Good For The Game

Afterattack is one of the worst parts of the attack chain, as it
simultaneously serves as a way of doing random interactions NOT AT ALL
related to attacks (despite the name) while ALSO serving as the defacto
way to do a ranged interaction with an item

This means careless coders (most of them) may throw stuff in afterattack
without realizing how wide reaching it is, which causes bugs. By making
two well defined, separate procs for handing adjacent vs ranged
interactions, it becomes WAY WAY WAY more easy to develop for.

If you want to do something when you click on something else and you're
adjacent, use `interact_with_atom`
If you want to do something when you click on something else and you're
not adjacent, use 'ranged_interact_with_atom`

This does result in some instances of boilerplate as shown here:


![image](https://github.com/tgstation/tgstation/assets/51863163/a7e469dd-115e-4e5b-88e0-0c664619c878)

But I think it's acceptable, feel free to oppose if you don't I'm sure
we can think of another solution

~~Additionally it makes it easier to implement swing combat. That's a
bonus I guess~~

## Changelog

🆑 Melbert
refactor: Over 200 item interactions have been refactored to use a
newer, easier-to-use system. Report any oddities with using items on
other objects you may see (such as surgery, reagent containers like cups
and spray bottles, or construction devices), especially using something
at range (such as guns or chisels)
refactor: Item-On-Modsuit interactions have changed slightly. While on
combat mode, you will attempt to "use" the item on the suit instead of
inserting it into the suit's storage. This means being on combat mode
while the suit's panel is open will block you from inserting items
entirely via click (but other methods such as hotkey, clicking on the
storage boxes, and mousedrop will still work).
refactor: The detective's scanner will now be inserted into storage
items if clicked normally, and will scan the storage item if on combat
mode
/🆑
This commit is contained in:
MrMelbert
2024-06-11 21:58:09 -07:00
committed by GitHub
parent efe3f3dfef
commit ff6b41aa07
235 changed files with 3211 additions and 3231 deletions
@@ -63,14 +63,8 @@
return ITEM_INTERACT_SUCCESS
/obj/item/abductor/gizmo/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
// Proximity is already handled via the interact_with_atom proc
if(proximity_flag)
return
. |= AFTERATTACK_PROCESSED_ITEM
interact_with_atom(target, user)
/obj/item/abductor/gizmo/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
/obj/item/abductor/gizmo/proc/scan(atom/target, mob/living/user)
if(ishuman(target))
@@ -117,14 +111,8 @@
radio_off(interacting_with, user)
return ITEM_INTERACT_SUCCESS
/obj/item/abductor/silencer/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
// Proximity is already handled via the interact_with_atom proc
if(proximity_flag)
return
. |= AFTERATTACK_PROCESSED_ITEM
interact_with_atom(target, user)
/obj/item/abductor/silencer/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
/obj/item/abductor/silencer/proc/radio_off(atom/target, mob/living/user)
if( !(user in (viewers(7,target))) )
@@ -167,17 +155,19 @@
icon_state = "mind_device_message"
to_chat(user, span_notice("You switch the device to [mode == MIND_DEVICE_MESSAGE? "TRANSMISSION": "COMMAND"] MODE"))
/obj/item/abductor/mind_device/afterattack(atom/target, mob/living/user, flag, params)
. = ..()
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/abductor/mind_device/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
/obj/item/abductor/mind_device/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!ScientistCheck(user))
return
return ITEM_INTERACT_BLOCKING
switch(mode)
if(MIND_DEVICE_CONTROL)
mind_control(target, user)
mind_control(interacting_with, user)
if(MIND_DEVICE_MESSAGE)
mind_message(target, user)
mind_message(interacting_with, user)
return ITEM_INTERACT_SUCCESS
/obj/item/abductor/mind_device/proc/mind_control(atom/target, mob/living/user)
if(iscarbon(target))
@@ -218,17 +218,13 @@
effectiveness = 80, \
)
/obj/item/melee/arm_blade/afterattack(atom/target, mob/user, proximity)
. = ..()
if(!proximity)
return
/obj/item/melee/arm_blade/afterattack(atom/target, mob/user, click_parameters)
if(istype(target, /obj/structure/table))
var/obj/structure/table/T = target
T.deconstruct(FALSE)
var/obj/smash = target
smash.deconstruct(FALSE)
else if(istype(target, /obj/machinery/computer))
var/obj/machinery/computer/C = target
C.attack_alien(user) //muh copypasta
target.attack_alien(user) //muh copypasta
else if(istype(target, /obj/machinery/door/airlock))
var/obj/machinery/door/airlock/opening = target
+197 -182
View File
@@ -376,7 +376,7 @@
return ..()
/obj/item/melee/blood_magic/attack_self(mob/living/user)
afterattack(user, user, TRUE)
cast_spell(user, user)
/obj/item/melee/blood_magic/attack(mob/living/M, mob/living/carbon/user)
if(!iscarbon(user) || !IS_CULTIST(user))
@@ -387,9 +387,18 @@
SSblackbox.record_feedback("tally", "cult_spell_invoke", 1, "[name]")
M.lastattacker = user.real_name
M.lastattackerckey = user.ckey
cast_spell(M, user)
/obj/item/melee/blood_magic/afterattack(atom/target, mob/living/carbon/user, proximity)
. = ..()
/obj/item/melee/blood_magic/attack_atom(atom/attacked_atom, mob/living/user, params)
if(!iscarbon(user) || !IS_CULTIST(user))
uses = 0
qdel(src)
return
log_combat(user, attacked_atom, "used a cult spell on", source.name, "")
SSblackbox.record_feedback("tally", "cult_spell_invoke", 1, "[name]")
cast_spell(attacked_atom, user)
/obj/item/melee/blood_magic/proc/cast_spell(atom/target, mob/living/carbon/user)
if(invocation)
user.whisper(invocation, language = /datum/language/common)
if(health_cost)
@@ -411,41 +420,41 @@
color = RUNE_COLOR_RED
invocation = "Fuu ma'jin!"
/obj/item/melee/blood_magic/stun/afterattack(mob/living/target, mob/living/carbon/user, proximity)
if(!isliving(target) || !proximity)
return
if(IS_CULTIST(target))
/obj/item/melee/blood_magic/stun/cast_spell(mob/living/target, mob/living/carbon/user)
if(!istype(target) || IS_CULTIST(target))
return
var/datum/antagonist/cult/cultist = IS_CULTIST(user)
if(!isnull(cultist))
var/datum/team/cult/cult_team = cultist.get_team()
var/effect_coef = 1 - (cult_team.cult_risen ? 0.4 : 0) - (cult_team.cult_ascendent ? 0.5 : 0)
user.visible_message(span_warning("[user] holds up [user.p_their()] hand, which explodes in a flash of red light!"), \
span_cult_italic("You attempt to stun [target] with the spell!"))
user.mob_light(range = 1.1, power = 2, color = LIGHT_COLOR_BLOOD_MAGIC, duration = 0.2 SECONDS)
if(IS_HERETIC(target))
to_chat(user, span_warning("Some force greater than you intervenes! [target] is protected by the Forgotten Gods!"))
to_chat(target, span_warning("You are protected by your faith to the Forgotten Gods."))
var/old_color = target.color
target.color = rgb(0, 128, 0)
animate(target, color = old_color, time = 1 SECONDS, easing = EASE_IN)
else if(target.can_block_magic())
to_chat(user, span_warning("The spell had no effect!"))
else
to_chat(user, span_cult_italic("In a brilliant flash of red, [target] falls to the ground!"))
target.Paralyze(16 SECONDS * effect_coef)
target.flash_act(1, TRUE)
if(issilicon(target))
var/mob/living/silicon/silicon_target = target
silicon_target.emp_act(EMP_HEAVY)
else if(iscarbon(target))
var/mob/living/carbon/carbon_target = target
carbon_target.adjust_silence(12 SECONDS * effect_coef)
carbon_target.adjust_stutter(30 SECONDS * effect_coef)
carbon_target.adjust_timed_status_effect(30 SECONDS * effect_coef, /datum/status_effect/speech/slurring/cult)
carbon_target.set_jitter_if_lower(30 SECONDS * effect_coef)
uses--
..()
var/datum/team/cult/cult_team = cultist.get_team()
var/effect_coef = 1 - (cult_team.cult_risen ? 0.4 : 0) - (cult_team.cult_ascendent ? 0.5 : 0)
user.visible_message(
span_warning("[user] holds up [user.p_their()] hand, which explodes in a flash of red light!"),
span_cult_italic("You attempt to stun [target] with the spell!"),
visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE,
)
user.mob_light(range = 1.1, power = 2, color = LIGHT_COLOR_BLOOD_MAGIC, duration = 0.2 SECONDS)
if(IS_HERETIC(target))
to_chat(user, span_warning("Some force greater than you intervenes! [target] is protected by the Forgotten Gods!"))
to_chat(target, span_warning("You are protected by your faith to the Forgotten Gods."))
var/old_color = target.color
target.color = rgb(0, 128, 0)
animate(target, color = old_color, time = 1 SECONDS, easing = EASE_IN)
else if(target.can_block_magic())
to_chat(user, span_warning("The spell had no effect!"))
else
to_chat(user, span_cult_italic("In a brilliant flash of red, [target] falls to the ground!"))
target.Paralyze(16 SECONDS * effect_coef)
target.flash_act(1, TRUE)
if(issilicon(target))
var/mob/living/silicon/silicon_target = target
silicon_target.emp_act(EMP_HEAVY)
else if(iscarbon(target))
var/mob/living/carbon/carbon_target = target
carbon_target.adjust_silence(12 SECONDS * effect_coef)
carbon_target.adjust_stutter(30 SECONDS * effect_coef)
carbon_target.adjust_timed_status_effect(30 SECONDS * effect_coef, /datum/status_effect/speech/slurring/cult)
carbon_target.set_jitter_if_lower(30 SECONDS * effect_coef)
uses--
return ..()
//Teleportation
/obj/item/melee/blood_magic/teleport
@@ -454,47 +463,50 @@
desc = "Will teleport a cultist to a teleport rune on contact."
invocation = "Sas'so c'arta forbici!"
/obj/item/melee/blood_magic/teleport/afterattack(atom/target, mob/living/carbon/user, proximity)
var/mob/mob_target = target
if(istype(mob_target) && !IS_CULTIST(mob_target) || !proximity)
to_chat(user, span_warning("You can only teleport adjacent cultists with this spell!"))
/obj/item/melee/blood_magic/teleport/cast_spell(mob/living/target, mob/living/carbon/user)
if(!istype(target) || !IS_CULTIST(target))
to_chat(user, span_warning("You can only teleport cultists with this spell!"))
return
if(IS_CULTIST(user))
var/list/potential_runes = list()
var/list/teleportnames = list()
for(var/obj/effect/rune/teleport/teleport_rune as anything in GLOB.teleport_runes)
potential_runes[avoid_assoc_duplicate_keys(teleport_rune.listkey, teleportnames)] = teleport_rune
if(!length(potential_runes))
to_chat(user, span_warning("There are no valid runes to teleport to!"))
return
var/list/potential_runes = list()
var/list/teleportnames = list()
for(var/obj/effect/rune/teleport/teleport_rune as anything in GLOB.teleport_runes)
potential_runes[avoid_assoc_duplicate_keys(teleport_rune.listkey, teleportnames)] = teleport_rune
var/turf/T = get_turf(src)
if(is_away_level(T.z))
to_chat(user, span_cult_italic("You are not in the right dimension!"))
return
var/input_rune_key = tgui_input_list(user, "Rune to teleport to", "Teleportation Target", potential_runes) //we know what key they picked
if(isnull(input_rune_key))
return
if(isnull(potential_runes[input_rune_key]))
to_chat(user, span_warning("You must pick a valid rune!"))
return
var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to?
if(QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated() || !actual_selected_rune || !proximity)
return
var/turf/dest = get_turf(actual_selected_rune)
if(dest.is_blocked_turf(TRUE))
to_chat(user, span_warning("The target rune is blocked. You cannot teleport there."))
return
uses--
var/turf/origin = get_turf(user)
var/mob/living/L = target
if(do_teleport(L, dest, channel = TELEPORT_CHANNEL_CULT))
origin.visible_message(span_warning("Dust flows from [user]'s hand, and [user.p_they()] disappear[user.p_s()] with a sharp crack!"), \
span_cult_italic("You speak the words of the talisman and find yourself somewhere else!"), "<i>You hear a sharp crack.</i>")
dest.visible_message(span_warning("There is a boom of outrushing air as something appears above the rune!"), null, "<i>You hear a boom.</i>")
..()
if(!length(potential_runes))
to_chat(user, span_warning("There are no valid runes to teleport to!"))
return
var/turf/T = get_turf(src)
if(is_away_level(T.z))
to_chat(user, span_cult_italic("You are not in the right dimension!"))
return
var/input_rune_key = tgui_input_list(user, "Rune to teleport to", "Teleportation Target", potential_runes) //we know what key they picked
if(isnull(input_rune_key))
return
if(isnull(potential_runes[input_rune_key]))
to_chat(user, span_warning("You must pick a valid rune!"))
return
var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to?
if(QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated() || !actual_selected_rune)
return
var/turf/dest = get_turf(actual_selected_rune)
if(dest.is_blocked_turf(TRUE))
to_chat(user, span_warning("The target rune is blocked. You cannot teleport there."))
return
uses--
var/turf/origin = get_turf(user)
if(do_teleport(target, dest, channel = TELEPORT_CHANNEL_CULT))
origin.visible_message(
span_warning("Dust flows from [user]'s hand, and [user.p_they()] disappear[user.p_s()] with a sharp crack!"),
span_cult_italic("You speak the words of the talisman and find yourself somewhere else!"),
span_hear("You hear a sharp crack."),
)
dest.visible_message(
span_warning("There is a boom of outrushing air as something appears above the rune!"),
null,
span_hear("You hear a boom."),
)
return ..()
//Shackles
/obj/item/melee/blood_magic/shackles
@@ -503,15 +515,17 @@
invocation = "In'totum Lig'abis!"
color = COLOR_BLACK // black
/obj/item/melee/blood_magic/shackles/afterattack(atom/target, mob/living/carbon/user, proximity)
if(IS_CULTIST(user) && iscarbon(target) && proximity)
var/mob/living/carbon/C = target
if(C.canBeHandcuffed())
CuffAttack(C, user)
else
user.visible_message(span_cult_italic("This victim doesn't have enough arms to complete the restraint!"))
return
..()
/obj/item/melee/blood_magic/shackles/cast_spell(atom/target, mob/living/carbon/user)
if(!iscarbon(target))
return
var/mob/living/carbon/C = target
if(IS_CULTIST(C))
return
if(!C.canBeHandcuffed())
user.visible_message(span_cult_italic("This victim doesn't have enough arms to complete the restraint!"))
return
CuffAttack(C, user)
return ..()
/obj/item/melee/blood_magic/shackles/proc/CuffAttack(mob/living/carbon/C, mob/living/user)
if(!C.handcuffed)
@@ -564,90 +578,95 @@
Purified soulstones (and any shades inside) into cultist soulstones\n
Airlocks into brittle runed airlocks after a delay (harm intent)"}
/obj/item/melee/blood_magic/construction/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
if(proximity_flag && IS_CULTIST(user))
if(channeling)
to_chat(user, span_cult_italic("You are already invoking twisted construction!"))
/obj/item/melee/blood_magic/construction/cast_spell(atom/target, mob/living/carbon/user)
if(channeling)
to_chat(user, span_cult_italic("You are already invoking twisted construction!"))
return
var/turf/T = get_turf(target)
if(istype(target, /obj/item/stack/sheet/iron))
var/obj/item/stack/sheet/candidate = target
if(!candidate.use(IRON_TO_CONSTRUCT_SHELL_CONVERSION))
to_chat(user, span_warning("You need [IRON_TO_CONSTRUCT_SHELL_CONVERSION] iron to produce a construct shell!"))
return
. |= AFTERATTACK_PROCESSED_ITEM
var/turf/T = get_turf(target)
if(istype(target, /obj/item/stack/sheet/iron))
var/obj/item/stack/sheet/candidate = target
if(candidate.use(IRON_TO_CONSTRUCT_SHELL_CONVERSION))
uses--
to_chat(user, span_warning("A dark cloud emanates from your hand and swirls around the iron, twisting it into a construct shell!"))
new /obj/structure/constructshell(T)
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
else
to_chat(user, span_warning("You need [IRON_TO_CONSTRUCT_SHELL_CONVERSION] iron to produce a construct shell!"))
return
else if(istype(target, /obj/item/stack/sheet/plasteel))
var/obj/item/stack/sheet/plasteel/candidate = target
var/quantity = candidate.amount
if(candidate.use(quantity))
uses --
new /obj/item/stack/sheet/runed_metal(T,quantity)
to_chat(user, span_warning("A dark cloud emanates from you hand and swirls around the plasteel, transforming it into runed metal!"))
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
else if(istype(target,/mob/living/silicon/robot))
var/mob/living/silicon/robot/candidate = target
if(candidate.mmi || candidate.shell)
channeling = TRUE
user.visible_message(span_danger("A dark cloud emanates from [user]'s hand and swirls around [candidate]!"))
playsound(T, 'sound/machines/airlock_alien_prying.ogg', 80, TRUE)
var/prev_color = candidate.color
candidate.color = "black"
if(do_after(user, 9 SECONDS, target = candidate))
candidate.undeploy()
candidate.emp_act(EMP_HEAVY)
var/construct_class = show_radial_menu(user, src, GLOB.construct_radial_images, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE, tooltips = TRUE)
if(!check_menu(user))
return
if(QDELETED(candidate))
channeling = FALSE
return
candidate.grab_ghost()
user.visible_message(span_danger("The dark cloud recedes from what was formerly [candidate], revealing a\n [construct_class]!"))
make_new_construct_from_class(construct_class, THEME_CULT, candidate, user, FALSE, T)
uses--
qdel(candidate)
channeling = FALSE
else
channeling = FALSE
candidate.color = prev_color
return
else
uses--
to_chat(user, span_warning("A dark cloud emanates from you hand and swirls around [candidate] - twisting it into a construct shell!"))
new /obj/structure/constructshell(T)
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
qdel(candidate)
else if(istype(target,/obj/machinery/door/airlock))
uses--
to_chat(user, span_warning("A dark cloud emanates from your hand and swirls around the iron, twisting it into a construct shell!"))
new /obj/structure/constructshell(T)
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
return ..()
if(istype(target, /obj/item/stack/sheet/plasteel))
var/obj/item/stack/sheet/plasteel/candidate = target
var/quantity = candidate.amount
if(!candidate.use(quantity))
return
uses--
new /obj/item/stack/sheet/runed_metal(T,quantity)
to_chat(user, span_warning("A dark cloud emanates from you hand and swirls around the plasteel, transforming it into runed metal!"))
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
return ..()
if(istype(target,/mob/living/silicon/robot))
var/mob/living/silicon/robot/candidate = target
if(candidate.mmi || candidate.shell)
channeling = TRUE
playsound(T, 'sound/machines/airlockforced.ogg', 50, TRUE)
do_sparks(5, TRUE, target)
if(do_after(user, 5 SECONDS, target = user))
if(QDELETED(target))
channeling = FALSE
return
target.narsie_act()
uses--
user.visible_message(span_warning("Black ribbons suddenly emanate from [user]'s hand and cling to the airlock - twisting and corrupting it!"))
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
channeling = FALSE
else
user.visible_message(span_danger("A dark cloud emanates from [user]'s hand and swirls around [candidate]!"))
playsound(T, 'sound/machines/airlock_alien_prying.ogg', 80, TRUE)
var/prev_color = candidate.color
candidate.color = "black"
if(!do_after(user, 9 SECONDS, target = candidate))
channeling = FALSE
candidate.color = prev_color
return
else if(istype(target,/obj/item/soulstone))
var/obj/item/soulstone/candidate = target
if(candidate.corrupt())
uses--
to_chat(user, span_warning("You corrupt [candidate]!"))
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
else
to_chat(user, span_warning("The spell will not work on [target]!"))
candidate.undeploy()
candidate.emp_act(EMP_HEAVY)
var/construct_class = show_radial_menu(user, src, GLOB.construct_radial_images, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE, tooltips = TRUE)
if(!check_menu(user) || QDELETED(candidate))
channeling = FALSE
candidate.color = prev_color
return
candidate.grab_ghost()
user.visible_message(span_danger("The dark cloud recedes from what was formerly [candidate], revealing a\n [construct_class]!"))
make_new_construct_from_class(construct_class, THEME_CULT, candidate, user, FALSE, T)
uses--
qdel(candidate)
channeling = FALSE
return ..()
uses--
to_chat(user, span_warning("A dark cloud emanates from you hand and swirls around [candidate] - twisting it into a construct shell!"))
new /obj/structure/constructshell(T)
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
qdel(candidate)
return ..()
if(istype(target,/obj/machinery/door/airlock))
channeling = TRUE
playsound(T, 'sound/machines/airlockforced.ogg', 50, TRUE)
do_sparks(5, TRUE, target)
if(!do_after(user, 5 SECONDS, target = user) && !QDELETED(target))
channeling = FALSE
return
return . | ..()
target.narsie_act()
uses--
user.visible_message(span_warning("Black ribbons suddenly emanate from [user]'s hand and cling to the airlock - twisting and corrupting it!"))
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
channeling = FALSE
return ..()
if(istype(target,/obj/item/soulstone))
var/obj/item/soulstone/candidate = target
if(!candidate.corrupt())
return
uses--
to_chat(user, span_warning("You corrupt [candidate]!"))
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
return ..()
to_chat(user, span_warning("The spell will not work on [target]!"))
/obj/item/melee/blood_magic/construction/proc/check_menu(mob/user)
if(!istype(user))
@@ -663,21 +682,21 @@
desc = "Will equip cult combat gear onto a cultist on contact."
color = "#33cc33" // green
/obj/item/melee/blood_magic/armor/afterattack(atom/target, mob/living/carbon/user, proximity)
/obj/item/melee/blood_magic/armor/cast_spell(mob/living/target, mob/living/carbon/user)
if(!iscarbon(target) || !IS_CULTIST(target))
return
uses--
var/mob/living/carbon/carbon_target = target
if(istype(carbon_target) && IS_CULTIST(carbon_target) && proximity)
uses--
var/mob/living/carbon/C = target
C.visible_message(span_warning("Otherworldly armor suddenly appears on [C]!"))
C.equip_to_slot_or_del(new /obj/item/clothing/under/color/black,ITEM_SLOT_ICLOTHING)
C.equip_to_slot_or_del(new /obj/item/clothing/suit/hooded/cultrobes/alt(user), ITEM_SLOT_OCLOTHING)
C.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult/alt(user), ITEM_SLOT_FEET)
C.equip_to_slot_or_del(new /obj/item/storage/backpack/cultpack(user), ITEM_SLOT_BACK)
if(C == user)
qdel(src) //Clears the hands
C.put_in_hands(new /obj/item/melee/cultblade/dagger(user))
C.put_in_hands(new /obj/item/restraints/legcuffs/bola/cult(user))
..()
carbon_target.visible_message(span_warning("Otherworldly armor suddenly appears on [carbon_target]!"))
carbon_target.equip_to_slot_or_del(new /obj/item/clothing/under/color/black,ITEM_SLOT_ICLOTHING)
carbon_target.equip_to_slot_or_del(new /obj/item/clothing/suit/hooded/cultrobes/alt(user), ITEM_SLOT_OCLOTHING)
carbon_target.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult/alt(user), ITEM_SLOT_FEET)
carbon_target.equip_to_slot_or_del(new /obj/item/storage/backpack/cultpack(user), ITEM_SLOT_BACK)
if(carbon_target == user)
qdel(src) //Clears the hands
carbon_target.put_in_hands(new /obj/item/melee/cultblade/dagger(user))
carbon_target.put_in_hands(new /obj/item/restraints/legcuffs/bola/cult(user))
return ..()
/obj/item/melee/blood_magic/manipulator
name = "Blood Rite Aura"
@@ -698,10 +717,7 @@
*
* '/obj/item/melee/blood_magic/manipulator/proc/blood_draw' handles blood pools/trails and does not affect parent proc
*/
/obj/item/melee/blood_magic/manipulator/afterattack(atom/target, mob/living/carbon/human/user, proximity)
if(!proximity)
return
/obj/item/melee/blood_magic/manipulator/cast_spell(mob/living/target, mob/living/carbon/user)
if((isconstruct(target) || isshade(target)) && !heal_construct(target, user))
return
if(istype(target, /obj/effect/decal/cleanable/blood) || istype(target, /obj/effect/decal/cleanable/trail_holder) || isturf(target))
@@ -714,12 +730,11 @@
if(human_bloodbag.stat == DEAD)
human_bloodbag.balloon_alert(user, "dead!")
return
if(IS_CULTIST(human_bloodbag) && !heal_cultist(human_bloodbag, user))
return
if(!IS_CULTIST(human_bloodbag) && !drain_victim(human_bloodbag, user))
return
..()
return ..()
/**
* handles blood rites usage on constructs
+47 -45
View File
@@ -639,49 +639,49 @@ Striking a noncultist, however, will tear their flesh."}
var/charges = 5
start_on = TRUE
/obj/item/flashlight/flare/culttorch/afterattack(atom/movable/A, mob/user, proximity)
if(!proximity)
return
if(!IS_CULTIST(user))
to_chat(user, "That doesn't seem to do anything useful.")
return
/obj/item/flashlight/flare/culttorch/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
var/datum/antagonist/cult/cult = user.mind.has_antag_datum(/datum/antagonist/cult)
var/datum/team/cult/cult_team = cult?.get_team()
if(isnull(cult_team))
to_chat(user, span_warning("That doesn't seem to do anything useful."))
return ITEM_INTERACT_BLOCKING
if(!isitem(A))
..()
to_chat(user, span_warning("\The [src] can only transport items!"))
return
if(!isitem(interacting_with))
to_chat(user, span_warning("[src] can only transport items!"))
return ITEM_INTERACT_BLOCKING
. |= AFTERATTACK_PROCESSED_ITEM
var/list/mob/living/cultists = list()
for(var/datum/mind/cult_mind as anything in cult_team.members)
if(cult_mind == user.mind)
continue
if(cult_mind.current?.stat != DEAD)
cultists |= cult_mind.current
var/list/cultists = list()
for(var/datum/mind/M as anything in get_antag_minds(/datum/antagonist/cult))
if(M.current && M.current.stat != DEAD)
cultists |= M.current
var/mob/living/cultist_to_receive = tgui_input_list(user, "Who do you wish to call to [src]?", "Followers of the Geometer", (cultists - user))
if(!Adjacent(user) || !src || QDELETED(src) || user.incapacitated())
return
if(QDELETED(src) || loc != user || user.incapacitated())
return ITEM_INTERACT_BLOCKING
if(isnull(cultist_to_receive))
to_chat(user, "<span class='cult italic'>You require a destination!</span>")
log_game("[key_name(user)]'s Void torch failed - no target.")
return
to_chat(user, span_cult_italic("You require a destination!"))
return ITEM_INTERACT_BLOCKING
if(cultist_to_receive.stat == DEAD)
to_chat(user, "<span class='cult italic'>[cultist_to_receive] has died!</span>")
log_game("[key_name(user)]'s Void torch failed - target died.")
return
if(!IS_CULTIST(cultist_to_receive))
to_chat(user, "<span class='cult italic'>[cultist_to_receive] is not a follower of the Geometer!</span>")
log_game("[key_name(user)]'s Void torch failed - target was deconverted.")
return
if(A in user.get_all_contents())
to_chat(user, "<span class='cult italic'>[A] must be on a surface in order to teleport it!</span>")
return
to_chat(user, "<span class='cult italic'>You ignite [A] with \the [src], turning it to ash, but through the torch's flames you see that [A] has reached [cultist_to_receive]!</span>")
user.log_message("teleported [A] to [cultist_to_receive] with \the [src].", LOG_GAME)
cultist_to_receive.put_in_hands(A)
to_chat(user, span_cult_italic("[cultist_to_receive] has died!"))
return ITEM_INTERACT_BLOCKING
if(!(cultist_to_receive.mind in cult_team.members))
to_chat(user, span_cult_italic("[cultist_to_receive] is not a follower of the Geometer!"))
return ITEM_INTERACT_BLOCKING
if(!isturf(interacting_with.loc))
to_chat(user, span_cult_italic("[interacting_with] must be on a surface in order to teleport it!"))
return ITEM_INTERACT_BLOCKING
to_chat(user, span_cult_italic("You ignite [interacting_with] with [src], turning it to ash, \
but through the torch's flames you see that [interacting_with] has reached [cultist_to_receive]!"))
user.log_message("teleported [interacting_with] to [cultist_to_receive] with [src].", LOG_GAME)
cultist_to_receive.put_in_hands(interacting_with)
charges--
to_chat(user, "\The [src] now has [charges] charge\s.")
if(charges == 0)
to_chat(user, span_notice("[src] now has [charges] charge\s."))
if(charges <= 0)
qdel(src)
return ITEM_INTERACT_SUCCESS
/obj/item/melee/cultblade/halberd
name = "bloody halberd"
@@ -859,31 +859,33 @@ Striking a noncultist, however, will tear their flesh."}
ADD_TRAIT(src, TRAIT_NODROP, CULT_TRAIT)
/obj/item/blood_beam/afterattack(atom/A, mob/living/user, proximity_flag, clickparams)
. = ..()
/obj/item/blood_beam/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return ranged_interact_with_atom(interacting_with, user, modifiers)
/obj/item/blood_beam/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(firing || charging)
return
if(ishuman(user))
angle = get_angle(user, A)
else
qdel(src)
return . | AFTERATTACK_PROCESSED_ITEM
return ITEM_INTERACT_BLOCKING
if(!ishuman(user))
return ITEM_INTERACT_BLOCKING
angle = get_angle(user, interacting_with)
charging = TRUE
INVOKE_ASYNC(src, PROC_REF(charge), user)
if(do_after(user, 9 SECONDS, target = user))
firing = TRUE
ADD_TRAIT(user, TRAIT_IMMOBILIZED, CULT_TRAIT)
INVOKE_ASYNC(src, PROC_REF(pewpew), user, clickparams)
var/params = list2params(modifiers)
INVOKE_ASYNC(src, PROC_REF(pewpew), user, params)
var/obj/structure/emergency_shield/cult/weak/N = new(user.loc)
if(do_after(user, 9 SECONDS, target = user))
user.Paralyze(40)
to_chat(user, "<span class='cult italic'>You have exhausted the power of this spell!</span>")
to_chat(user, span_cult_italic("You have exhausted the power of this spell!"))
REMOVE_TRAIT(user, TRAIT_IMMOBILIZED, CULT_TRAIT)
firing = FALSE
if(N)
qdel(N)
qdel(src)
charging = FALSE
return ITEM_INTERACT_SUCCESS
/obj/item/blood_beam/proc/charge(mob/user)
var/obj/O
@@ -230,7 +230,7 @@
GLOB.reality_smash_track.add_tracked_mind(owner)
RegisterSignals(our_mob, list(COMSIG_MOB_BEFORE_SPELL_CAST, COMSIG_MOB_SPELL_ACTIVATED), PROC_REF(on_spell_cast))
RegisterSignal(our_mob, COMSIG_MOB_ITEM_AFTERATTACK, PROC_REF(on_item_afterattack))
RegisterSignal(our_mob, COMSIG_USER_ITEM_INTERACTION, PROC_REF(on_item_use))
RegisterSignal(our_mob, COMSIG_MOB_LOGIN, PROC_REF(fix_influence_network))
RegisterSignal(our_mob, COMSIG_LIVING_POST_FULLY_HEAL, PROC_REF(after_fully_healed))
@@ -245,7 +245,7 @@
UnregisterSignal(our_mob, list(
COMSIG_MOB_BEFORE_SPELL_CAST,
COMSIG_MOB_SPELL_ACTIVATED,
COMSIG_MOB_ITEM_AFTERATTACK,
COMSIG_USER_ITEM_INTERACTION,
COMSIG_MOB_LOGIN,
COMSIG_LIVING_POST_FULLY_HEAL,
))
@@ -286,26 +286,25 @@
return SPELL_CANCEL_CAST
/*
* Signal proc for [COMSIG_MOB_ITEM_AFTERATTACK].
* Signal proc for [COMSIG_USER_ITEM_INTERACTION].
*
* If a heretic is holding a pen in their main hand,
* and have mansus grasp active in their offhand,
* they're able to draw a transmutation rune.
*/
/datum/antagonist/heretic/proc/on_item_afterattack(mob/living/source, atom/target, obj/item/weapon, proximity_flag, click_parameters)
/datum/antagonist/heretic/proc/on_item_use(mob/living/source, atom/target, obj/item/weapon, click_parameters)
SIGNAL_HANDLER
if(!is_type_in_typecache(weapon, scribing_tools))
return
if(!isturf(target) || !isliving(source) || !proximity_flag)
return
return NONE
if(!isturf(target) || !isliving(source))
return NONE
var/obj/item/offhand = source.get_inactive_held_item()
if(QDELETED(offhand) || !istype(offhand, /obj/item/melee/touch_attack/mansus_fist))
return
return NONE
try_draw_rune(source, target, additional_checks = CALLBACK(src, PROC_REF(check_mansus_grasp_offhand), source))
return COMPONENT_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_SUCCESS
/**
* Attempt to draw a rune on [target_turf].
@@ -45,20 +45,16 @@
AddElement(/datum/element/heretic_focus)
update_weight_class(WEIGHT_CLASS_NORMAL)
/obj/item/codex_cicatrix/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(!proximity_flag)
return
/obj/item/codex_cicatrix/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
var/datum/antagonist/heretic/heretic_datum = IS_HERETIC(user)
if(!heretic_datum)
return
if(isopenturf(target))
var/obj/effect/heretic_influence/influence = locate(/obj/effect/heretic_influence) in target
return NONE
if(isopenturf(interacting_with))
var/obj/effect/heretic_influence/influence = locate(/obj/effect/heretic_influence) in interacting_with
if(!influence?.drain_influence_with_codex(user, src))
heretic_datum.try_draw_rune(user, target, drawing_time = 8 SECONDS)
return TRUE
heretic_datum.try_draw_rune(user, interacting_with, drawing_time = 8 SECONDS)
return ITEM_INTERACT_BLOCKING
return NONE
/// Plays a little animation that shows the book opening and closing.
/obj/item/codex_cicatrix/proc/open_animation()
@@ -24,14 +24,19 @@
attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "rend")
var/after_use_message = ""
/obj/item/melee/sickly_blade/attack(mob/living/M, mob/living/user)
/obj/item/melee/sickly_blade/pre_attack(atom/A, mob/living/user, params)
. = ..()
if(.)
return .
if(!IS_HERETIC_OR_MONSTER(user))
to_chat(user, span_danger("You feel a pulse of alien intellect lash out at your mind!"))
var/mob/living/carbon/human/human_user = user
human_user.AdjustParalyzed(5 SECONDS)
user.AdjustParalyzed(5 SECONDS)
return TRUE
return .
return ..()
/obj/item/melee/sickly_blade/afterattack(atom/target, mob/user, click_parameters)
if(isliving(target))
SEND_SIGNAL(user, COMSIG_HERETIC_BLADE_ATTACK, target, src)
/obj/item/melee/sickly_blade/attack_self(mob/user)
var/turf/safe_turf = find_safe_turf(zlevels = z, extended_safety_checks = TRUE)
@@ -45,15 +50,10 @@
playsound(src, SFX_SHATTER, 70, TRUE) //copied from the code for smashing a glass sheet onto the ground to turn it into a shard
qdel(src)
/obj/item/melee/sickly_blade/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(!isliving(target))
return
if(proximity_flag)
SEND_SIGNAL(user, COMSIG_HERETIC_BLADE_ATTACK, target, src)
else
SEND_SIGNAL(user, COMSIG_HERETIC_RANGED_BLADE_ATTACK, target, src)
/obj/item/melee/sickly_blade/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(isliving(interacting_with))
SEND_SIGNAL(user, COMSIG_HERETIC_RANGED_BLADE_ATTACK, interacting_with, src)
return ITEM_INTERACT_BLOCKING
/obj/item/melee/sickly_blade/examine(mob/user)
. = ..()
@@ -171,20 +171,17 @@
playsound(drop_location(),'sound/items/eatfood.ogg', rand(10,50), TRUE)
access += card.access
/obj/item/card/id/advanced/heretic/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(!proximity_flag || !IS_HERETIC(user))
return
/obj/item/card/id/advanced/heretic/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(!IS_HERETIC(user))
return NONE
if(istype(target, /obj/effect/lock_portal))
clear_portals()
return
return ITEM_INTERACT_SUCCESS
if(!istype(target, /obj/machinery/door))
return
return NONE
var/reference_resolved = link?.resolve()
if(reference_resolved == target)
return
return ITEM_INTERACT_BLOCKING
if(reference_resolved)
make_portal(user, reference_resolved, target)
@@ -194,6 +191,7 @@
else
link = WEAKREF(target)
balloon_alert(user, "link 1/2")
return ITEM_INTERACT_SUCCESS
/obj/item/card/id/advanced/heretic/Destroy()
QDEL_LIST_ASSOC(fused_ids)
@@ -41,24 +41,29 @@
. += span_hypnophrase("Materializes a barrier upon any tile in sight, which only you can pass through. Lasts 8 seconds.")
. += span_hypnophrase("It has <b>[uses]</b> uses left.")
/obj/item/heretic_labyrinth_handbook/afterattack(atom/target, mob/user, proximity_flag)
. = ..()
if(IS_HERETIC(user))
var/turf/turf_target = get_turf(target)
if(locate(barrier_type) in turf_target)
user.balloon_alert(user, "already occupied!")
return
turf_target.visible_message(span_warning("A storm of paper materializes!"))
new /obj/effect/temp_visual/paper_scatter(turf_target)
playsound(turf_target, 'sound/magic/smoke.ogg', 30)
new barrier_type(turf_target, user)
uses--
if(uses <= 0)
to_chat(user, span_warning("[src] falls apart, turning into ash and dust!"))
qdel(src)
return
var/mob/living/carbon/human/human_user = user
to_chat(human_user, span_userdanger("Your mind burns as you stare deep into the book, a headache setting in like your brain is on fire!"))
human_user.adjustOrganLoss(ORGAN_SLOT_BRAIN, 30, 190)
human_user.add_mood_event("gates_of_mansus", /datum/mood_event/gates_of_mansus)
human_user.dropItemToGround(src)
/obj/item/heretic_labyrinth_handbook/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
/obj/item/heretic_labyrinth_handbook/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!IS_HERETIC(user))
if(ishuman(user))
var/mob/living/carbon/human/human_user = user
to_chat(human_user, span_userdanger("Your mind burns as you stare deep into the book, a headache setting in like your brain is on fire!"))
human_user.adjustOrganLoss(ORGAN_SLOT_BRAIN, 30, 190)
human_user.add_mood_event("gates_of_mansus", /datum/mood_event/gates_of_mansus)
human_user.dropItemToGround(src)
return ITEM_INTERACT_BLOCKING
var/turf/turf_target = get_turf(interacting_with)
if(locate(barrier_type) in turf_target)
user.balloon_alert(user, "already occupied!")
return ITEM_INTERACT_BLOCKING
turf_target.visible_message(span_warning("A storm of paper materializes!"))
new /obj/effect/temp_visual/paper_scatter(turf_target)
playsound(turf_target, 'sound/magic/smoke.ogg', 30)
new barrier_type(turf_target, user)
uses--
if(uses <= 0)
to_chat(user, span_warning("[src] falls apart, turning into ash and dust!"))
qdel(src)
return ITEM_INTERACT_SUCCESS
@@ -45,21 +45,14 @@
var/potion_string = span_info("\tThe " + initial(trap.name) + " - " + initial(trap.carver_tip))
. += potion_string
/obj/item/melee/rune_carver/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(!proximity_flag)
return
/obj/item/melee/rune_carver/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!IS_HERETIC_OR_MONSTER(user))
return
return NONE
if(!isopenturf(interacting_with) || is_type_in_typecache(interacting_with, blacklisted_turfs))
return NONE
if(!isopenturf(target))
return
if(is_type_in_typecache(target, blacklisted_turfs))
return
INVOKE_ASYNC(src, PROC_REF(try_carve_rune), target, user)
INVOKE_ASYNC(src, PROC_REF(try_carve_rune), interacting_with, user)
return ITEM_INTERACT_SUCCESS
/*
* Begin trying to carve a rune. Go through a few checks, then call do_carve_rune if successful.
@@ -44,12 +44,11 @@
spark_system.set_up(5, 0, src)
spark_system.attach(src)
/obj/item/energy_katana/afterattack_secondary(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return
if(!target.density)
jaunt?.teleport(user, target)
/obj/item/energy_katana/ranged_interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
if(!interacting_with.density)
jaunt?.teleport(user, interacting_with)
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/energy_katana/equipped(mob/user, slot, initial)
. = ..()
@@ -47,15 +47,16 @@
return
detonation_area = objective.detonation_location
/obj/item/grenade/c4/ninja/afterattack(atom/movable/target, mob/ninja, flag)
if(!IS_SPACE_NINJA(ninja))
/obj/item/grenade/c4/ninja/plant_c4(atom/bomb_target, mob/living/user)
if(!IS_SPACE_NINJA(user))
say("Access denied.")
return
. |= AFTERATTACK_PROCESSED_ITEM
if (!check_loc(ninja))
return .
detonator = WEAKREF(ninja)
return . | ..()
return FALSE
if(!check_loc(user))
return FALSE
if(!..())
return FALSE
detonator = WEAKREF(user)
return TRUE
/obj/item/grenade/c4/ninja/detonate(mob/living/lanced_by)
if(!check_loc(detonator.resolve())) // if its moved, deactivate the c4
@@ -29,7 +29,7 @@
/obj/machinery/nuclearbomb/beer/attackby(obj/item/weapon, mob/user, params)
if(weapon.is_refillable())
weapon.afterattack(keg, user, TRUE) // redirect refillable containers to the keg, allowing them to be filled
weapon.interact_with_atom(keg, user) // redirect refillable containers to the keg, allowing them to be filled
return TRUE // pretend we handled the attack, too.
if(istype(weapon, /obj/item/nuke_core_container))
@@ -243,28 +243,24 @@
objective_weakref = null
return ..()
/obj/item/grenade/c4/es8/afterattack(atom/movable/target, mob/user, flag)
if(!user.mind)
return
/obj/item/grenade/c4/es8/plant_c4(atom/bomb_target, mob/living/user)
if(!IS_TRAITOR(user))
to_chat(user, span_warning("You can't seem to find a way to detonate the charge."))
return
return FALSE
var/datum/traitor_objective/locate_weakpoint/objective = objective_weakref.resolve()
if(!objective || objective.objective_state == OBJECTIVE_STATE_INACTIVE || objective.handler.owner != user.mind)
to_chat(user, span_warning("You don't think it would be wise to use [src]."))
return
return FALSE
var/area/target_area = get_area(target)
var/area/target_area = get_area(bomb_target)
if (target_area.type != objective.weakpoint_area)
to_chat(user, span_warning("[src] can only be detonated in [initial(objective.weakpoint_area.name)]."))
return
return FALSE
if(!isfloorturf(target) && !iswallturf(target))
if(!isfloorturf(bomb_target) && !iswallturf(bomb_target))
to_chat(user, span_warning("[src] can only be planted on a wall or the floor!"))
return
return FALSE
return ..()
@@ -277,28 +277,26 @@ GLOBAL_DATUM_INIT(steal_item_handler, /datum/objective_item_handler, new())
. += span_notice("This device must be placed by <b>clicking on the [initial(target_object_type.name)]</b> with it.")
. += span_notice("Remember, you may leave behind fingerprints or fibers on the device. Use <b>soap</b> or similar to scrub it clean to be safe!")
/obj/item/traitor_bug/afterattack(atom/movable/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(!target_object_type)
return
if(!user.Adjacent(target))
return
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/traitor_bug/interact_with_atom(atom/movable/target, mob/living/user, list/modifiers)
if(!target_object_type || !ismovable(target))
return NONE
var/result = SEND_SIGNAL(src, COMSIG_TRAITOR_BUG_PRE_PLANTED_OBJECT, target)
if(!(result & COMPONENT_FORCE_PLACEMENT))
if(result & COMPONENT_FORCE_FAIL_PLACEMENT || !istype(target, target_object_type))
balloon_alert(user, "you can't attach this onto here!")
return
return ITEM_INTERACT_BLOCKING
if(!do_after(user, deploy_time, src, hidden = TRUE))
return
return ITEM_INTERACT_BLOCKING
if(planted_on)
return
return ITEM_INTERACT_BLOCKING
forceMove(target)
target.vis_contents += src
vis_flags |= VIS_INHERIT_PLANE
planted_on = target
RegisterSignal(planted_on, COMSIG_QDELETING, PROC_REF(handle_planted_on_deletion))
SEND_SIGNAL(src, COMSIG_TRAITOR_BUG_PLANTED_OBJECT, target)
return ITEM_INTERACT_SUCCESS
/obj/item/traitor_bug/proc/handle_planted_on_deletion()
planted_on = null
@@ -318,5 +316,5 @@ GLOBAL_DATUM_INIT(steal_item_handler, /datum/objective_item_handler, new())
UnregisterSignal(planted_on, COMSIG_QDELETING)
planted_on = null
/obj/item/traitor_bug/attackby_storage_insert(datum/storage, atom/storage_holder, mob/user)
/obj/item/traitor_bug/storage_insert_on_interaction(datum/storage, atom/storage_holder, mob/user)
return !istype(storage_holder, target_object_type)
@@ -431,43 +431,45 @@
COMSIG_ITEM_MAGICALLY_CHARGED = PROC_REF(on_magic_charge),
)
/obj/item/runic_vendor_scepter/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
/obj/item/runic_vendor_scepter/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
/obj/item/runic_vendor_scepter/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(scepter_is_busy_recharging)
user.balloon_alert(user, "busy!")
return
if(!check_allowed_items(target, not_inside = TRUE))
return
. |= AFTERATTACK_PROCESSED_ITEM
var/turf/afterattack_turf = get_turf(target)
if(istype(target, /obj/machinery/vending/runic_vendor))
var/obj/machinery/vending/runic_vendor/runic_explosion_target = target
return ITEM_INTERACT_BLOCKING
if(!check_allowed_items(interacting_with, not_inside = TRUE))
return NONE
if(istype(interacting_with, /obj/machinery/vending/runic_vendor))
var/obj/machinery/vending/runic_vendor/runic_explosion_target = interacting_with
runic_explosion_target.runic_explosion()
return
return ITEM_INTERACT_SUCCESS
var/turf/afterattack_turf = get_turf(interacting_with)
var/obj/machinery/vending/runic_vendor/vendor_on_turf = locate() in afterattack_turf
if(vendor_on_turf)
vendor_on_turf.runic_explosion()
return
return ITEM_INTERACT_SUCCESS
if(!summon_vendor_charges)
user.balloon_alert(user, "no charges!")
return
return ITEM_INTERACT_BLOCKING
if(get_dist(afterattack_turf,src) > max_summon_range)
user.balloon_alert(user, "too far!")
return
return ITEM_INTERACT_BLOCKING
if(get_turf(src) == afterattack_turf)
user.balloon_alert(user, "too close!")
return
return ITEM_INTERACT_BLOCKING
if(scepter_is_busy_summoning)
user.balloon_alert(user, "already summoning!")
return
return ITEM_INTERACT_BLOCKING
if(afterattack_turf.is_blocked_turf(TRUE))
user.balloon_alert(user, "blocked!")
return
return ITEM_INTERACT_BLOCKING
if(summoning_time)
scepter_is_busy_summoning = TRUE
user.balloon_alert(user, "summoning...")
if(!do_after(user, summoning_time, target = target))
if(!do_after(user, summoning_time, target = interacting_with))
scepter_is_busy_summoning = FALSE
return
return ITEM_INTERACT_BLOCKING
scepter_is_busy_summoning = FALSE
if(summon_vendor_charges)
playsound(src,'sound/weapons/resonator_fire.ogg',50,TRUE)
@@ -475,8 +477,8 @@
new /obj/machinery/vending/runic_vendor(afterattack_turf)
summon_vendor_charges--
user.changeNext_move(CLICK_CD_MELEE)
return
return ..()
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/runic_vendor_scepter/attack_self(mob/user, modifiers)
. = ..()
@@ -489,17 +491,20 @@
scepter_is_busy_recharging = FALSE
summon_vendor_charges = RUNIC_SCEPTER_MAX_CHARGES
/obj/item/runic_vendor_scepter/afterattack_secondary(atom/target, mob/user, proximity_flag, click_parameters)
var/turf/afterattack_secondary_turf = get_turf(target)
/obj/item/runic_vendor_scepter/ranged_interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom_secondary(interacting_with, user, modifiers)
/obj/item/runic_vendor_scepter/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
var/turf/afterattack_secondary_turf = get_turf(interacting_with)
var/obj/machinery/vending/runic_vendor/vendor_on_turf = locate() in afterattack_secondary_turf
if(istype(target, /obj/machinery/vending/runic_vendor))
var/obj/machinery/vending/runic_vendor/vendor_being_throw = target
vendor_being_throw.throw_at(get_edge_target_turf(target, get_cardinal_dir(src, target)), 4, 20, user)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if(istype(interacting_with, /obj/machinery/vending/runic_vendor))
var/obj/machinery/vending/runic_vendor/vendor_being_throw = interacting_with
vendor_being_throw.throw_at(get_edge_target_turf(interacting_with, get_cardinal_dir(src, interacting_with)), 4, 20, user)
return ITEM_INTERACT_SUCCESS
if(vendor_on_turf)
vendor_on_turf.throw_at(get_edge_target_turf(target, get_cardinal_dir(src, target)), 4, 20, user)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
vendor_on_turf.throw_at(get_edge_target_turf(interacting_with, get_cardinal_dir(src, interacting_with)), 4, 20, user)
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_BLOCKING
/obj/item/runic_vendor_scepter/proc/on_magic_charge(datum/source, datum/action/cooldown/spell/charge/spell, mob/living/caster)
SIGNAL_HANDLER
@@ -77,7 +77,7 @@
whatever spark it once held long extinguished."
///signal called whenever a soulstone is smacked by a bible
/obj/item/soulstone/proc/on_bible_smacked(datum/source, mob/living/user, direction)
/obj/item/soulstone/proc/on_bible_smacked(datum/source, mob/living/user, ...)
SIGNAL_HANDLER
INVOKE_ASYNC(src, PROC_REF(attempt_exorcism), user)
@@ -55,28 +55,21 @@
var/datum/status_effect/teleport_flux/perma/permaflux = user.has_status_effect(/datum/status_effect/teleport_flux/perma)
permaflux?.delayed_remove(src)
/obj/item/teleport_rod/afterattack(atom/target, mob/living/user, proximity_flag, click_parameters)
. = ..()
if(!isliving(user))
return
if(proximity_flag) // assuming you don't want to teleport 1 tile away
return
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/teleport_rod/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
. = ITEM_INTERACT_BLOCKING
var/turf/start_turf = get_turf(user)
var/turf/target_turf = get_turf(target)
var/turf/target_turf = get_turf(interacting_with)
if(get_dist(start_turf, target_turf) > max_tp_range)
user.balloon_alert(user, "too far!")
return
return .
if(!(target_turf in view(user, user.client?.view || world.view)))
user.balloon_alert(user, "out of view!")
return
return .
if(target_turf.is_blocked_turf(exclude_mobs = TRUE, source_atom = user))
user.balloon_alert(user, "obstructed!")
return
return .
var/tp_result = do_teleport(
teleatom = user,
@@ -88,7 +81,9 @@
if(!tp_result)
user.balloon_alert(user, "teleport failed!")
return
return .
. = ITEM_INTERACT_SUCCESS
var/sound/teleport_sound = sound('sound/magic/summonitems_generic.ogg')
teleport_sound.pitch = 0.5
@@ -101,7 +96,7 @@
user.changeNext_move(CLICK_CD_SLOW * 1.2)
if(!apply_debuffs)
return
return .
// Teleporting leaves some of your reagents behind!
// (Primarily a way to prevent cheese with damage healing chem mixes,
@@ -110,13 +105,14 @@
user.reagents?.remove_all(0.33, relative = TRUE)
user_stomach?.reagents?.remove_all(0.33, relative = TRUE)
if(user.has_status_effect(/datum/status_effect/teleport_flux/perma))
return
return .
if(user.has_status_effect(/datum/status_effect/teleport_flux))
// The status effect handles the damage, but we'll add a special pop up for rod usage specifically
user.balloon_alert(user, "too soon!")
user.apply_status_effect(/datum/status_effect/teleport_flux)
return .
/// Temp visual displayed on both sides of a teleport rod teleport
/obj/effect/temp_visual/teleport_flux
+15 -15
View File
@@ -310,12 +310,11 @@ Point with the chisel at the target to choose what to sculpt or hit block to cho
Hit block again to start sculpting.
Moving interrupts
*/
/obj/item/chisel/pre_attack(atom/target, mob/living/user, params)
. = ..()
/obj/item/chisel/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(sculpting)
return TRUE
if(istype(target, /obj/structure/carving_block))
var/obj/structure/carving_block/sculpt_block = target
return ITEM_INTERACT_BLOCKING
if(istype(interacting_with, /obj/structure/carving_block))
var/obj/structure/carving_block/sculpt_block = interacting_with
if(sculpt_block.completion) // someone already started sculpting this so just finish
set_block(sculpt_block, user, silent = TRUE)
@@ -326,19 +325,20 @@ Moving interrupts
set_block(sculpt_block, user)
else if(sculpt_block == prepared_block)
show_generic_statues_prompt(user)
return TRUE
return ITEM_INTERACT_SUCCESS
else if(prepared_block) //We're aiming at something next to us with block prepared
prepared_block.set_target(target, user)
return TRUE
prepared_block.set_target(interacting_with, user)
return ITEM_INTERACT_SUCCESS
return NONE
// We aim at something distant.
/obj/item/chisel/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if (!sculpting && prepared_block && ismovable(target) && prepared_block.completion == 0)
prepared_block.set_target(target,user)
return . | AFTERATTACK_PROCESSED_ITEM
/obj/item/chisel/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if (!sculpting && prepared_block && ismovable(interacting_with) && prepared_block.completion == 0)
prepared_block.set_target(interacting_with, user)
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_BLOCKING
/// Starts or continues the sculpting action on the carving block material
/obj/item/chisel/proc/start_sculpting(mob/living/user)
@@ -5,29 +5,27 @@
icon_state = "hypernoblium_crystal"
var/uses = 1
/obj/item/hypernoblium_crystal/afterattack(obj/target_object, mob/user, proximity)
. = ..()
if(!proximity)
return
. |= AFTERATTACK_PROCESSED_ITEM
var/obj/machinery/portable_atmospherics/atmos_device = target_object
/obj/item/hypernoblium_crystal/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
var/obj/machinery/portable_atmospherics/atmos_device = interacting_with
var/obj/item/clothing/worn_item = interacting_with
if(!istype(worn_item) && !istype(atmos_device))
to_chat(user, span_warning("The crystal can only be used on clothing and portable atmospheric devices!"))
return ITEM_INTERACT_BLOCKING
if(istype(atmos_device))
if(atmos_device.nob_crystal_inserted)
to_chat(user, span_warning("[atmos_device] already has a hypernoblium crystal inserted in it!"))
return
return ITEM_INTERACT_BLOCKING
atmos_device.nob_crystal_inserted = TRUE
to_chat(user, span_notice("You insert the [src] into [atmos_device]."))
var/obj/item/clothing/worn_item = target_object
if(!istype(worn_item) && !istype(atmos_device))
to_chat(user, span_warning("The crystal can only be used on clothing and portable atmospheric devices!"))
return
if(istype(worn_item))
if(istype(worn_item, /obj/item/clothing/suit/space))
to_chat(user, span_warning("The [worn_item] is already pressure-resistant!"))
return
return ITEM_INTERACT_BLOCKING
if(worn_item.min_cold_protection_temperature == SPACE_SUIT_MIN_TEMP_PROTECT && worn_item.clothing_flags & STOPSPRESSUREDAMAGE)
to_chat(user, span_warning("[worn_item] is already pressure-resistant!"))
return
return ITEM_INTERACT_BLOCKING
to_chat(user, span_notice("You see how the [worn_item] changes color, it's now pressure proof."))
worn_item.name = "pressure-resistant [worn_item.name]"
worn_item.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
@@ -35,6 +33,8 @@
worn_item.min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
worn_item.cold_protection = worn_item.body_parts_covered
worn_item.clothing_flags |= STOPSPRESSUREDAMAGE
uses--
if(!uses)
if(uses <= 0)
qdel(src)
return ITEM_INTERACT_SUCCESS
+18 -12
View File
@@ -173,31 +173,37 @@
user.swap_hand(user.get_held_index_of_item(src))
playsound(src, 'sound/items/basketball_bounce.ogg', 75, FALSE)
/obj/item/toy/basketball/afterattack(atom/target, mob/living/user)
. = ..()
if(!user.combat_mode)
user.throw_item(target)
/obj/item/toy/basketball/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
/obj/item/toy/basketball/afterattack_secondary(atom/aim_target, mob/living/baller, proximity_flag, click_parameters)
// dunking negates shooting
if(istype(aim_target, /obj/structure/hoop) && baller.Adjacent(aim_target))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/toy/basketball/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(user.combat_mode)
user.throw_item(interacting_with)
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/toy/basketball/ranged_interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom_secondary(interacting_with, user, modifiers)
/obj/item/toy/basketball/interact_with_atom_secondary(atom/interacting_with, mob/living/baller, list/modifiers)
if(istype(interacting_with, /obj/structure/hoop) && baller.Adjacent(interacting_with))
return NONE // Do hoop stuff
baller.adjustStaminaLoss(STAMINA_COST_SHOOTING)
var/dunk_dir = get_dir(baller, aim_target)
var/dunk_dir = get_dir(baller, interacting_with)
var/dunk_pixel_y = dunk_dir & SOUTH ? -16 : 16
var/dunk_pixel_x = dunk_dir & EAST && 16 || dunk_dir & WEST && -16 || 0
animate(baller, pixel_x = dunk_pixel_x, pixel_y = dunk_pixel_y, time = 5, easing = BOUNCE_EASING|EASE_IN|EASE_OUT)
if(do_after(baller, 0.5 SECONDS))
pass_flags |= PASSMOB
baller.throw_item(aim_target)
baller.throw_item(interacting_with)
animate(baller, pixel_x = 0, pixel_y = 0, time = 3)
return SECONDARY_ATTACK_CONTINUE_CHAIN
return ITEM_INTERACT_SUCCESS
animate(baller, pixel_x = 0, pixel_y = 0, time = 3)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
/obj/item/toy/basketball/throw_impact(mob/living/carbon/target, datum/thrownthing/throwingdatum)
playsound(src, 'sound/items/basketball_bounce.ogg', 75, FALSE)
+8 -9
View File
@@ -58,17 +58,16 @@
icon_state = "[choice]"
playsound(src, 'sound/machines/click.ogg', 40, TRUE)
/obj/item/universal_scanner/afterattack(obj/object, mob/user, proximity)
. = ..()
if(!istype(object) || !proximity)
return
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/universal_scanner/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!isobj(interacting_with))
return NONE
if(scanning_mode == SCAN_EXPORTS)
export_scan(object, user)
return .
export_scan(interacting_with, user)
return ITEM_INTERACT_SUCCESS
if(scanning_mode == SCAN_PRICE_TAG)
price_tag(target = object, user = user)
return .
price_tag(interacting_with, user)
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/universal_scanner/attackby(obj/item/attacking_item, mob/user, params)
. = ..()
@@ -43,25 +43,24 @@
. += span_red("<b>Left click</b> will stealthily scan a target up to [scan_range] meters away and upload their getup as a custom outfit for you to use.")
. += span_red("<b>Right click</b> will do the same, but instantly equip the outfit you obtain.")
/obj/item/chameleon_scanner/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(scan_target(target, user))
. |= AFTERATTACK_PROCESSED_ITEM
return .
/obj/item/chameleon_scanner/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return scan_target(interacting_with, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
/obj/item/chameleon_scanner/afterattack_secondary(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return .
/obj/item/chameleon_scanner/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
var/list/scanned_outfit = scan_target(target, user)
/obj/item/chameleon_scanner/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
var/list/scanned_outfit = scan_target(interacting_with, user)
if(length(scanned_outfit))
var/datum/outfit/empty_outfit = new()
var/datum/action/chameleon_outfit/outfit_action = locate() in user.actions
outfit_action?.apply_outfit(empty_outfit, scanned_outfit.Copy())
qdel(empty_outfit)
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_BLOCKING
return SECONDARY_ATTACK_CONTINUE_CHAIN // no normal afterattack
/obj/item/chameleon_scanner/ranged_interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom_secondary(interacting_with, user, modifiers)
/**
* Attempts to scan a human's outfit
+13 -11
View File
@@ -39,18 +39,20 @@
icon = 'icons/obj/clothing/gloves.dmi'
icon_state = "sprayoncan"
/obj/item/toy/sprayoncan/afterattack(atom/target, mob/living/carbon/user, proximity)
if(iscarbon(target) && proximity)
var/mob/living/carbon/C = target
var/mob/living/carbon/U = user
var/success = C.equip_to_slot_if_possible(new /obj/item/clothing/gloves/color/yellow/sprayon, ITEM_SLOT_GLOVES, qdel_on_fail = TRUE, disable_warning = TRUE)
if(success)
if(C == user)
C.visible_message(span_notice("[U] sprays their hands with glittery rubber!"))
else
C.visible_message(span_warning("[U] sprays glittery rubber on the hands of [C]!"))
/obj/item/toy/sprayoncan/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!iscarbon(interacting_with))
return NONE
var/mob/living/carbon/C = interacting_with
var/mob/living/carbon/U = user
var/success = C.equip_to_slot_if_possible(new /obj/item/clothing/gloves/color/yellow/sprayon, ITEM_SLOT_GLOVES, qdel_on_fail = TRUE, disable_warning = TRUE)
if(success)
if(C == user)
C.visible_message(span_notice("[U] sprays their hands with glittery rubber!"))
else
C.visible_message(span_warning("The rubber fails to stick to [C]'s hands!"))
C.visible_message(span_warning("[U] sprays glittery rubber on the hands of [C]!"))
else
C.visible_message(span_warning("The rubber fails to stick to [C]'s hands!"))
return ITEM_INTERACT_SUCCESS
/obj/item/clothing/gloves/color/yellow/sprayon
desc = "How're you gonna get 'em off, nerd?"
+9 -6
View File
@@ -60,20 +60,22 @@
add_atom_colour(newcolor, FIXED_COLOUR_PRIORITY)
update_appearance()
/obj/item/clothing/head/wig/afterattack(mob/living/carbon/human/target, mob/user)
. = ..()
if(!istype(target))
return
/obj/item/clothing/head/wig/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
/obj/item/clothing/head/wig/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!ishuman(interacting_with) || interacting_with == user)
return NONE
var/mob/living/carbon/human/target = interacting_with
if(target.head)
var/obj/item/clothing/head = target.head
if((head.flags_inv & HIDEHAIR) && !istype(head, /obj/item/clothing/head/wig))
to_chat(user, span_warning("You can't get a good look at [target.p_their()] hair!"))
return
return ITEM_INTERACT_BLOCKING
var/obj/item/bodypart/head/noggin = target.get_bodypart(BODY_ZONE_HEAD)
if(!noggin)
to_chat(user, span_warning("[target.p_They()] have no head!"))
return
return ITEM_INTERACT_BLOCKING
var/selected_hairstyle = null
var/selected_hairstyle_color = null
@@ -90,6 +92,7 @@
add_atom_colour(selected_hairstyle_color, FIXED_COLOUR_PRIORITY)
hairstyle = selected_hairstyle
update_appearance()
return ITEM_INTERACT_SUCCESS
/obj/item/clothing/head/wig/random/Initialize(mapload)
hairstyle = pick(SSaccessories.hairstyles_list - "Bald") //Don't want invisible wig
+5 -9
View File
@@ -476,25 +476,21 @@
selling = !selling
to_chat(user, span_notice("[src] has been set to [selling ? "'Sell'" : "'Get Price'"] mode."))
/obj/item/clothing/neck/necklace/dope/merchant/afterattack(obj/item/I, mob/user, proximity)
. = ..()
if(!proximity)
return
. |= AFTERATTACK_PROCESSED_ITEM
var/datum/export_report/ex = export_item_and_contents(I, delete_unsold = selling, dry_run = !selling)
/obj/item/clothing/neck/necklace/dope/merchant/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
var/datum/export_report/ex = export_item_and_contents(interacting_with, delete_unsold = selling, dry_run = !selling)
var/price = 0
for(var/x in ex.total_amount)
price += ex.total_value[x]
if(price)
var/true_price = round(price*profit_scaling)
to_chat(user, span_notice("[selling ? "Sold" : "Getting the price of"] [I], value: <b>[true_price]</b> credits[I.contents.len ? " (exportable contents included)" : ""].[profit_scaling < 1 && selling ? "<b>[round(price-true_price)]</b> credit\s taken as processing fee\s." : ""]"))
to_chat(user, span_notice("[selling ? "Sold" : "Getting the price of"] [interacting_with], value: <b>[true_price]</b> credits[interacting_with.contents.len ? " (exportable contents included)" : ""].[profit_scaling < 1 && selling ? "<b>[round(price-true_price)]</b> credit\s taken as processing fee\s." : ""]"))
if(selling)
new /obj/item/holochip(get_turf(user), true_price)
else
to_chat(user, span_warning("There is no export value for [I] or any items within it."))
to_chat(user, span_warning("There is no export value for [interacting_with] or any items within it."))
return .
return ITEM_INTERACT_BLOCKING
/obj/item/clothing/neck/beads
name = "plastic bead necklace"
+5 -6
View File
@@ -8,12 +8,11 @@
inhand_icon_state = ""
w_class = WEIGHT_CLASS_TINY
/obj/item/evidencebag/afterattack(obj/item/I, mob/user,proximity)
. = ..()
if(!proximity || loc == I)
return
evidencebagEquip(I, user)
return . | AFTERATTACK_PROCESSED_ITEM
/obj/item/evidencebag/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(interacting_with == loc)
return NONE
evidencebagEquip(interacting_with, user)
return ITEM_INTERACT_SUCCESS
/obj/item/evidencebag/attackby(obj/item/I, mob/user, params)
if(evidencebagEquip(I, user))
+9 -7
View File
@@ -74,14 +74,16 @@
// Clear the logs
log = list()
/obj/item/detective_scanner/pre_attack_secondary(atom/A, mob/user, params)
safe_scan(user, atom_to_scan = A)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/detective_scanner/storage_insert_on_interaction(datum/storage, atom/storage_holder, mob/living/user)
return !user.combat_mode
/obj/item/detective_scanner/afterattack(atom/A, mob/user, params)
. = ..()
safe_scan(user, atom_to_scan = A)
return . | AFTERATTACK_PROCESSED_ITEM
/obj/item/detective_scanner/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
safe_scan(user, interacting_with)
return ITEM_INTERACT_SUCCESS
/obj/item/detective_scanner/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
safe_scan(user, interacting_with)
return ITEM_INTERACT_SUCCESS
/**
* safe_scan - a wrapper proc for scan()
@@ -89,16 +89,12 @@
/**
* Provides feedback when an item isn't related to an experiment, and has fully passed the attack chain
*/
/datum/component/experiment_handler/proc/ignored_handheld_experiment_attempt(datum/source, atom/target, mob/user, proximity_flag, params)
/datum/component/experiment_handler/proc/ignored_handheld_experiment_attempt(datum/source, atom/target, mob/user, params)
SIGNAL_HANDLER
if (!proximity_flag)
if ((isnull(selected_experiment) && !(config_flags & EXPERIMENT_CONFIG_ALWAYS_ACTIVE)) || (config_flags & EXPERIMENT_CONFIG_SILENT_FAIL))
return
. |= COMPONENT_AFTERATTACK_PROCESSED_ITEM
if ((selected_experiment == null && !(config_flags & EXPERIMENT_CONFIG_ALWAYS_ACTIVE)) || config_flags & EXPERIMENT_CONFIG_SILENT_FAIL)
return .
playsound(user, 'sound/machines/buzz-sigh.ogg', 25)
to_chat(user, span_notice("[target] is not related to your currently selected experiment."))
return .
/**
* Checks that an experiment can be run using the provided target, used for preventing the cancellation of the attack chain inappropriately
+11 -10
View File
@@ -167,19 +167,18 @@ GLOBAL_LIST_INIT(adventure_loot_generator_index,generate_generator_index())
/obj/item/firelance/get_cell()
return cell
/obj/item/firelance/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
. |= AFTERATTACK_PROCESSED_ITEM
if(!HAS_TRAIT(src,TRAIT_WIELDED))
to_chat(user,span_notice("You need to wield [src] in two hands before you can fire it."))
return
/obj/item/firelance/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
. = ITEM_INTERACT_BLOCKING
if(!HAS_TRAIT(src, TRAIT_WIELDED))
to_chat(user, span_notice("You need to wield [src] in two hands before you can fire it."))
return .
if(LAZYACCESS(user.do_afters, "firelance"))
return
return .
if(!cell.use(0.2 * STANDARD_CELL_CHARGE))
to_chat(user,span_warning("[src] battery ran dry!"))
return
to_chat(user,span_warning("[src]'s battery ran dry!"))
return .
ADD_TRAIT(user, TRAIT_IMMOBILIZED, REF(src))
to_chat(user,span_notice("You begin to charge [src]"))
to_chat(user,span_notice("You begin to charge [src]..."))
inhand_icon_state = "firelance_charging"
user.update_held_items()
if(do_after(user,windup_time,interaction_key="firelance",extra_checks = CALLBACK(src, PROC_REF(windup_checks))))
@@ -189,9 +188,11 @@ GLOBAL_LIST_INIT(adventure_loot_generator_index,generate_generator_index())
for(var/turf/turf_to_melt in get_line(start_turf,last_turf))
if(turf_to_melt.density)
turf_to_melt.Melt()
. = ITEM_INTERACT_SUCCESS
inhand_icon_state = initial(inhand_icon_state)
user.update_held_items()
REMOVE_TRAIT(user, TRAIT_IMMOBILIZED, REF(src))
return .
/// Additional windup checks
/obj/item/firelance/proc/windup_checks()
+13 -15
View File
@@ -78,31 +78,29 @@
return CONTEXTUAL_SCREENTIP_SET
return NONE
/obj/item/fish_analyzer/afterattack(atom/target, mob/user, proximity)
. = ..()
if(!proximity || !user.can_read(src) || user.is_blind())
return
/obj/item/fish_analyzer/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(!isfish(target) && !isaquarium(target))
return NONE
if(!user.can_read(src) || user.is_blind())
return ITEM_INTERACT_BLOCKING
if(isfish(target))
balloon_alert(user, "analyzing stats")
user.visible_message(span_notice("[user] analyzes [target]."), span_notice("You analyze [target]."))
analyze_status(target, user)
else if(istype(target, /obj/structure/aquarium))
scan_aquarium(target, user)
return ITEM_INTERACT_SUCCESS
/obj/item/fish_analyzer/afterattack_secondary(atom/target, mob/user, proximity_flag, click_parameters)
if(!isfish(target))
return
if(!proximity_flag || !user.can_read(src) || user.is_blind())
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/fish_analyzer/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
if(!isfish(interacting_with))
return NONE
if(!user.can_read(src) || user.is_blind())
return ITEM_INTERACT_BLOCKING
balloon_alert(user, "analyzing traits")
analyze_traits(target, user)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
analyze_traits(interacting_with, user)
return ITEM_INTERACT_SUCCESS
///Instantiates the radial menu, populates the list of choices, shows it and register signals on the aquarium.
/obj/item/fish_analyzer/proc/scan_aquarium(obj/structure/aquarium/aquarium, mob/user)
+15 -23
View File
@@ -145,16 +145,6 @@
. = ..()
ui_interact(user)
/obj/item/fishing_rod/pre_attack(atom/targeted_atom, mob/living/user, params)
. = ..()
/// Reel in if able
if(currently_hooked)
reel(user)
return TRUE
if(!hook)
balloon_alert(user, "install a hook first!")
SEND_SIGNAL(targeted_atom, COMSIG_PRE_FISHING)
/// Generates the fishing line visual from the current user to the target and updates inhands
/obj/item/fishing_rod/proc/create_fishing_line(atom/movable/target, target_py = null)
if(!display_fishing_line)
@@ -205,22 +195,26 @@
qdel(source)
return BEAM_CANCEL_DRAW
/obj/item/fishing_rod/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/fishing_rod/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return ranged_interact_with_atom(interacting_with, user, modifiers)
/// Reel in if able
/obj/item/fishing_rod/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!hook)
balloon_alert(user, "install a hook first!")
return ITEM_INTERACT_BLOCKING
// Reel in if able
if(currently_hooked)
reel(user)
return .
return ITEM_INTERACT_BLOCKING
cast_line(target, user, proximity_flag)
SEND_SIGNAL(interacting_with, COMSIG_PRE_FISHING)
cast_line(interacting_with, user)
return ITEM_INTERACT_SUCCESS
return .
///Called by afterattack(). If the line to whatever that is is clear and we're not already busy, try fishing in it
/obj/item/fishing_rod/proc/cast_line(atom/target, mob/user, proximity_flag)
if(casting || currently_hooked || proximity_flag)
/// If the line to whatever that is is clear and we're not already busy, try fishing in it
/obj/item/fishing_rod/proc/cast_line(atom/target, mob/user)
if(casting || currently_hooked)
return
if(!hook)
balloon_alert(user, "install a hook first!")
@@ -230,8 +224,6 @@
return
if(!COOLDOWN_FINISHED(src, casting_cd))
return
/// Annoyingly pre attack is only called in melee
SEND_SIGNAL(target, COMSIG_PRE_FISHING)
casting = TRUE
var/obj/projectile/fishing_cast/cast_projectile = new(get_turf(src))
cast_projectile.range = cast_range
@@ -36,40 +36,33 @@
user.balloon_alert(user, "[activated ? "activated" : "deactivated"]")
return TRUE
/obj/item/bee_smoker/afterattack(atom/attacked_atom, mob/living/user, proximity)
. = ..()
if(!proximity)
return
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/bee_smoker/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!activated)
user.balloon_alert(user, "not activated!")
return
return ITEM_INTERACT_BLOCKING
if(current_herb_fuel < single_use_cost)
user.balloon_alert(user, "not enough fuel!")
return
return ITEM_INTERACT_BLOCKING
current_herb_fuel -= single_use_cost
playsound(src, 'sound/effects/spray2.ogg', 100, TRUE)
var/turf/target_turf = get_turf(attacked_atom)
var/turf/target_turf = get_turf(interacting_with)
new /obj/effect/temp_visual/mook_dust(target_turf)
for(var/mob/living/basic/bee/friend in target_turf)
if(friend.flags_1 & HOLOGRAM_1)
continue
friend.befriend(user)
if(!istype(attacked_atom, /obj/structure/beebox))
return
if(!istype(interacting_with, /obj/structure/beebox))
return ITEM_INTERACT_BLOCKING
var/obj/structure/beebox/hive = attacked_atom
var/obj/structure/beebox/hive = interacting_with
for(var/mob/living/bee as anything in hive.bees)
if(bee.flags_1 & HOLOGRAM_1)
continue
bee.befriend(user)
return ITEM_INTERACT_SUCCESS
/obj/item/bee_smoker/attackby(obj/item/herb, mob/living/carbon/human/user, list/modifiers)
. = ..()
+1 -16
View File
@@ -76,24 +76,9 @@
return
/// Signal proc for [COMSIG_ITEM_AFTERATTACK] that allows for effects after an attack is done
/datum/plant_gene/trait/attack/proc/after_plant_attack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
/datum/plant_gene/trait/attack/proc/after_plant_attack(obj/item/source, atom/target, mob/user, click_parameters)
SIGNAL_HANDLER
if(!proximity_flag)
return
if(!ismovable(target))
return
. |= COMPONENT_AFTERATTACK_PROCESSED_ITEM
if(isobj(target))
var/obj/object_target = target
if(!(object_target.obj_flags & CAN_BE_HIT))
return .
INVOKE_ASYNC(src, PROC_REF(after_attack_effect), source, target, user)
return .
/*
* Effects done when we hit people with our plant, AFTER the attack is done.
+16 -14
View File
@@ -269,49 +269,48 @@ GLOBAL_LIST_INIT(bibleitemstates, list(
playsound(target_mob, SFX_PUNCH, 25, TRUE, -1)
log_combat(user, target_mob, "attacked", src)
/obj/item/book/bible/attackby_storage_insert(datum/storage, atom/storage_holder, mob/user)
/obj/item/book/bible/storage_insert_on_interaction(datum/storage, atom/storage_holder, mob/user)
return !istype(storage_holder, /obj/item/book/bible)
/obj/item/book/bible/afterattack(atom/bible_smacked, mob/user, proximity_flag, click_parameters)
. = ..()
if(!proximity_flag)
return
if(SEND_SIGNAL(bible_smacked, COMSIG_BIBLE_SMACKED, user, proximity_flag, click_parameters) & COMSIG_END_BIBLE_CHAIN)
return . | AFTERATTACK_PROCESSED_ITEM
/obj/item/book/bible/interact_with_atom(atom/bible_smacked, mob/living/user, list/modifiers)
if(SEND_SIGNAL(bible_smacked, COMSIG_BIBLE_SMACKED, user) & COMSIG_END_BIBLE_CHAIN)
return ITEM_INTERACT_SUCCESS
if(isfloorturf(bible_smacked))
if(user.mind?.holy_role)
var/area/current_area = get_area(bible_smacked)
if(!GLOB.chaplain_altars.len && istype(current_area, /area/station/service/chapel))
make_new_altar(bible_smacked, user)
return
return ITEM_INTERACT_SUCCESS
for(var/obj/effect/rune/nearby_runes in range(2, user))
nearby_runes.SetInvisibility(INVISIBILITY_NONE, id=type, priority=INVISIBILITY_PRIORITY_BASIC_ANTI_INVISIBILITY)
bible_smacked.balloon_alert(user, "floor smacked!")
return ITEM_INTERACT_SUCCESS
if(user.mind?.holy_role)
if(bible_smacked.reagents && bible_smacked.reagents.has_reagent(/datum/reagent/water)) // blesses all the water in the holder
. |= AFTERATTACK_PROCESSED_ITEM
if(bible_smacked.reagents?.has_reagent(/datum/reagent/water)) // blesses all the water in the holder
bible_smacked.balloon_alert(user, "blessed")
var/water2holy = bible_smacked.reagents.get_reagent_amount(/datum/reagent/water)
bible_smacked.reagents.del_reagent(/datum/reagent/water)
bible_smacked.reagents.add_reagent(/datum/reagent/water/holywater,water2holy)
if(bible_smacked.reagents && bible_smacked.reagents.has_reagent(/datum/reagent/fuel/unholywater)) // yeah yeah, copy pasted code - sue me
. |= AFTERATTACK_PROCESSED_ITEM
. = ITEM_INTERACT_SUCCESS
if(bible_smacked.reagents?.has_reagent(/datum/reagent/fuel/unholywater)) // yeah yeah, copy pasted code - sue me
bible_smacked.balloon_alert(user, "purified")
var/unholy2holy = bible_smacked.reagents.get_reagent_amount(/datum/reagent/fuel/unholywater)
bible_smacked.reagents.del_reagent(/datum/reagent/fuel/unholywater)
bible_smacked.reagents.add_reagent(/datum/reagent/water/holywater,unholy2holy)
. = ITEM_INTERACT_SUCCESS
if(istype(bible_smacked, /obj/item/book/bible) && !istype(bible_smacked, /obj/item/book/bible/syndicate))
. |= AFTERATTACK_PROCESSED_ITEM
bible_smacked.balloon_alert(user, "converted")
var/obj/item/book/bible/other_bible = bible_smacked
other_bible.name = name
other_bible.icon_state = icon_state
other_bible.inhand_icon_state = inhand_icon_state
other_bible.deity_name = deity_name
. = ITEM_INTERACT_SUCCESS
if(.)
return .
if(istype(bible_smacked, /obj/item/cult_bastard) && !IS_CULTIST(user))
. |= AFTERATTACK_PROCESSED_ITEM
var/obj/item/cult_bastard/sword = bible_smacked
bible_smacked.balloon_alert(user, "exorcising...")
playsound(src,'sound/hallucinations/veryfar_noise.ogg',40,TRUE)
@@ -333,6 +332,9 @@ GLOBAL_LIST_INIT(bibleitemstates, list(
new /obj/item/nullrod/claymore(get_turf(sword))
user.visible_message(span_notice("[user] exorcises [sword]!"))
qdel(sword)
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_BLOCKING
return NONE
/obj/item/book/bible/booze
desc = "To be applied to the head repeatedly."
@@ -320,21 +320,23 @@
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "prison_cube"
/obj/item/prisoncube/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(!proximity_flag || !isliving(target))
return
var/mob/living/victim = target
var/mob/living/carbon/carbon_victim = victim
/obj/item/prisoncube/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!isliving(interacting_with))
return NONE
var/mob/living/carbon/carbon_victim = interacting_with
//Handcuffed or unconscious
if(istype(carbon_victim) && carbon_victim.handcuffed || victim.stat != CONSCIOUS)
if(!puzzle_imprison(target))
to_chat(user,span_warning("[src] does nothing."))
return
to_chat(user,span_warning("You trap [victim] in the prison cube!"))
if(istype(carbon_victim) && (carbon_victim.handcuffed || carbon_victim.stat != CONSCIOUS))
user.do_attack_animation(carbon_victim)
if(!puzzle_imprison(carbon_victim))
to_chat(user, span_warning("[src] does nothing."))
return ITEM_INTERACT_BLOCKING
to_chat(user, span_warning("You trap [carbon_victim] in the prison cube!"))
qdel(src)
else
to_chat(user,span_notice("[src] only accepts restrained or unconscious prisoners."))
return ITEM_INTERACT_SUCCESS
to_chat(user, span_notice("[src] only accepts restrained or unconscious prisoners."))
return ITEM_INTERACT_BLOCKING
/proc/puzzle_imprison(mob/living/prisoner)
var/turf/T = get_turf(prisoner)
@@ -36,18 +36,17 @@
w_class = WEIGHT_CLASS_NORMAL
hitsound = 'sound/weapons/bladeslice.ogg'
/obj/item/knife/envy/afterattack(atom/movable/AM, mob/living/carbon/human/user, proximity)
. = ..()
if(!proximity)
/obj/item/knife/envy/afterattack(atom/target, mob/living/carbon/human/user, click_parameters)
if(!istype(user) || !ishuman(target))
return
if(!istype(user))
var/mob/living/carbon/human/H = target
if(user.real_name == H.dna.real_name)
return
if(ishuman(AM))
var/mob/living/carbon/human/H = AM
if(user.real_name != H.dna.real_name)
user.real_name = H.dna.real_name
H.dna.transfer_identity(user, transfer_SE=1)
user.updateappearance(mutcolor_update=1)
user.domutcheck()
user.visible_message(span_warning("[user]'s appearance shifts into [H]'s!"), \
span_boldannounce("[H.p_They()] think[H.p_s()] [H.p_theyre()] <i>sooo</i> much better than you. Not anymore, [H.p_they()] won't."))
user.real_name = H.dna.real_name
H.dna.transfer_identity(user, transfer_SE=1)
user.updateappearance(mutcolor_update=1)
user.domutcheck()
user.visible_message(span_warning("[user]'s appearance shifts into [H]'s!"), \
span_boldannounce("[H.p_They()] think[H.p_s()] [H.p_theyre()] <i>sooo</i> much better than you. Not anymore, [H.p_they()] won't."))
@@ -524,14 +524,12 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999))
icon_state = "hilbertsanalyzer"
worn_icon_state = "analyzer"
/obj/item/analyzer/hilbertsanalyzer/afterattack(atom/target, mob/user, proximity)
. = ..()
if(istype(target, /obj/item/hilbertshotel))
. |= AFTERATTACK_PROCESSED_ITEM
if(!proximity)
/obj/item/analyzer/hilbertsanalyzer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(istype(interacting_with, /obj/item/hilbertshotel))
if(!Adjacent(interacting_with))
to_chat(user, span_warning("It's to far away to scan!"))
return .
var/obj/item/hilbertshotel/sphere = target
return ITEM_INTERACT_BLOCKING
var/obj/item/hilbertshotel/sphere = interacting_with
if(sphere.activeRooms.len)
to_chat(user, "Currently Occupied Rooms:")
for(var/roomnumber in sphere.activeRooms)
@@ -544,7 +542,8 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999))
to_chat(user, roomnumber)
else
to_chat(user, "No vacated rooms.")
return .
return ITEM_INTERACT_SUCCESS
return ..()
/obj/effect/landmark/transport/transport_id/hilbert
specific_transport_id = HILBERT_LINE_1
+9 -14
View File
@@ -35,26 +35,22 @@
zipline_sound = new(src)
update_appearance()
/obj/item/grapple_gun/afterattack(atom/target, mob/living/user, proximity)
. = ..()
/obj/item/grapple_gun/ranged_interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(isgroundlessturf(target))
return
return NONE
if(target == user || !hooked)
return NONE
if(!lavaland_equipment_pressure_check(get_turf(user)))
user.balloon_alert(user, "gun mechanism wont work here!")
return
if(target == user || !hooked)
return
return ITEM_INTERACT_BLOCKING
if(get_dist(user, target) > 9)
user.balloon_alert(user, "too far away!")
return
return ITEM_INTERACT_BLOCKING
var/turf/attacked_atom = get_turf(target)
if(isnull(attacked_atom))
return
return ITEM_INTERACT_BLOCKING
var/list/turf_list = (get_line(user, attacked_atom) - get_turf(src))
for(var/turf/singular_turf as anything in turf_list)
@@ -66,9 +62,7 @@
break
if(user.CanReach(attacked_atom))
return
. |= AFTERATTACK_PROCESSED_ITEM
return ITEM_INTERACT_BLOCKING
var/atom/bullet = fire_projectile(/obj/projectile/grapple_hook, attacked_atom, 'sound/weapons/zipline_fire.ogg')
zipline = user.Beam(bullet, icon_state = "zipline_hook", maxdistance = 9, layer = BELOW_MOB_LAYER)
@@ -77,6 +71,7 @@
RegisterSignal(bullet, COMSIG_PREQDELETED, PROC_REF(on_grapple_fail))
zipliner = WEAKREF(user)
update_appearance()
return ITEM_INTERACT_SUCCESS
/obj/item/grapple_gun/proc/on_grapple_hit(datum/source, atom/movable/firer, atom/target, Angle)
SIGNAL_HANDLER
@@ -83,27 +83,24 @@
crusher_trophy.remove_from(src, user)
return ITEM_INTERACT_SUCCESS
/obj/item/kinetic_crusher/attack(mob/living/target, mob/living/carbon/user)
if(!HAS_TRAIT(src, TRAIT_WIELDED))
user.balloon_alert(user, "must be wielded!")
return
var/datum/status_effect/crusher_damage/crusher_damage_effect = target.has_status_effect(/datum/status_effect/crusher_damage)
if(!crusher_damage_effect)
crusher_damage_effect = target.apply_status_effect(/datum/status_effect/crusher_damage)
var/target_health = target.health
..()
for(var/obj/item/crusher_trophy/crusher_trophy as anything in trophies)
if(!QDELETED(target))
crusher_trophy.on_melee_hit(target, user)
if(!QDELETED(crusher_damage_effect) && !QDELETED(target))
crusher_damage_effect.total_damage += target_health - target.health //we did some damage, but let's not assume how much we did
/obj/item/kinetic_crusher/afterattack(mob/living/target, mob/living/user, proximity_flag, clickparams)
/obj/item/kinetic_crusher/pre_attack(atom/A, mob/living/user, params)
. = ..()
if(.)
return TRUE
if(!HAS_TRAIT(src, TRAIT_WIELDED))
user.balloon_alert(user, "must be wielded!")
return TRUE
return .
/obj/item/kinetic_crusher/afterattack(mob/living/target, mob/living/user, clickparams)
if(!isliving(target))
return
if(!proximity_flag || !isliving(target))
// Melee effect
for(var/obj/item/crusher_trophy/crusher_trophy as anything in trophies)
crusher_trophy.on_melee_hit(target, user)
if(QDELETED(target))
return
// Clear existing marks
var/valid_crusher_attack = FALSE
for(var/datum/status_effect/crusher_mark/crusher_mark_effect as anything in target.get_all_status_effect_of_id(/datum/status_effect/crusher_mark))
//this will erase ALL crusher marks, not only ones by you.
@@ -113,9 +110,8 @@
break
if(!valid_crusher_attack)
return
var/datum/status_effect/crusher_damage/crusher_damage_effect = target.has_status_effect(/datum/status_effect/crusher_damage)
if(!crusher_damage_effect)
crusher_damage_effect = target.apply_status_effect(/datum/status_effect/crusher_damage)
// Detonation effect
var/datum/status_effect/crusher_damage/crusher_damage_effect = target.has_status_effect(/datum/status_effect/crusher_damage) || target.apply_status_effect(/datum/status_effect/crusher_damage)
var/target_health = target.health
for(var/obj/item/crusher_trophy/crusher_trophy as anything in trophies)
crusher_trophy.on_mark_detonation(target, user)
@@ -128,6 +124,7 @@
var/combined_damage = detonation_damage
var/backstab_dir = get_dir(user, target)
var/def_check = target.getarmor(type = BOMB)
// Backstab bonus
if((user.dir & backstab_dir) && (target.dir & backstab_dir))
backstabbed = TRUE
combined_damage += backstab_bonus
@@ -137,24 +134,23 @@
SEND_SIGNAL(user, COMSIG_LIVING_CRUSHER_DETONATE, target, src, backstabbed)
target.apply_damage(combined_damage, BRUTE, blocked = def_check)
/obj/item/kinetic_crusher/attack_secondary(atom/target, mob/living/user, clickparams)
return SECONDARY_ATTACK_CONTINUE_CHAIN
/obj/item/kinetic_crusher/afterattack_secondary(atom/target, mob/living/user, proximity_flag, click_parameters)
/obj/item/kinetic_crusher/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
if(!HAS_TRAIT(src, TRAIT_WIELDED))
balloon_alert(user, "wield it first!")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if(target == user)
return ITEM_INTERACT_BLOCKING
if(interacting_with == user)
balloon_alert(user, "can't aim at yourself!")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
fire_kinetic_blast(target, user, click_parameters)
return ITEM_INTERACT_BLOCKING
fire_kinetic_blast(interacting_with, user, modifiers)
user.changeNext_move(CLICK_CD_MELEE)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_SUCCESS
/obj/item/kinetic_crusher/proc/fire_kinetic_blast(atom/target, mob/living/user, click_parameters)
/obj/item/kinetic_crusher/ranged_interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom_secondary(interacting_with, user, modifiers)
/obj/item/kinetic_crusher/proc/fire_kinetic_blast(atom/target, mob/living/user, list/modifiers)
if(!charged)
return
var/modifiers = params2list(click_parameters)
var/turf/proj_turf = user.loc
if(!isturf(proj_turf))
return
@@ -25,27 +25,25 @@
///So you can't revive boss monsters or robots with it
var/revive_type = SENTIENCE_ORGANIC
/obj/item/lazarus_injector/afterattack(atom/target, mob/user, proximity_flag)
. = ..()
if(!loaded || !proximity_flag)
return
/obj/item/lazarus_injector/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(!loaded)
return NONE
if(SEND_SIGNAL(target, COMSIG_ATOM_ON_LAZARUS_INJECTOR, src, user) & LAZARUS_INJECTOR_USED)
return
return ITEM_INTERACT_SUCCESS
if(!isliving(target))
return
return NONE
var/mob/living/target_animal = target
if(!target_animal.compare_sentience_type(revive_type)) // Will also return false if not a basic or simple mob, which are the only two we want anyway
balloon_alert(user, "invalid creature!")
return
return ITEM_INTERACT_BLOCKING
if(target_animal.stat != DEAD)
balloon_alert(user, "it's not dead!")
return
return ITEM_INTERACT_BLOCKING
target_animal.lazarus_revive(user, malfunctioning)
expend(target_animal, user)
return ITEM_INTERACT_SUCCESS
/obj/item/lazarus_injector/proc/expend(atom/revived_target, mob/user)
user.visible_message(span_notice("[user] injects [revived_target] with [src], reviving it."))
@@ -8,24 +8,21 @@
desc = "Inject certain types of monster organs with this stabilizer to prevent their rapid decay."
w_class = WEIGHT_CLASS_TINY
/obj/item/mining_stabilizer/afterattack(obj/item/organ/target_organ, mob/user, proximity)
. = ..()
if (!proximity)
return
. |= AFTERATTACK_PROCESSED_ITEM
var/obj/item/organ/internal/monster_core/target_core = target_organ
if (!istype(target_core, /obj/item/organ/internal/monster_core))
/obj/item/mining_stabilizer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!isorgan(interacting_with))
return NONE
var/obj/item/organ/internal/monster_core/target_core = interacting_with
if (!istype(target_core))
balloon_alert(user, "invalid target!")
return .
return ITEM_INTERACT_BLOCKING
if (!target_core.preserve())
balloon_alert(user, "organ decayed!")
return .
return ITEM_INTERACT_BLOCKING
balloon_alert(user, "organ stabilized")
qdel(src)
return .
return ITEM_INTERACT_SUCCESS
/**
* Useful organs which drop as loot from a mining creature.
@@ -135,12 +132,9 @@
icon_state = initial(icon_state)
return ..()
/obj/item/organ/internal/monster_core/afterattack(atom/target, mob/user, proximity_flag)
. = ..()
if (!proximity_flag)
return
try_apply(target, user)
return . | AFTERATTACK_PROCESSED_ITEM
/obj/item/organ/internal/monster_core/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
try_apply(interacting_with, user)
return ITEM_INTERACT_SUCCESS
/obj/item/organ/internal/monster_core/attack_self(mob/user)
if (!user.can_perform_action(src, FORBID_TELEKINESIS_REACH|ALLOW_RESTING))
+21 -22
View File
@@ -51,36 +51,33 @@ GLOBAL_LIST_EMPTY(total_extraction_beacons)
beacon_ref = WEAKREF(chosen_beacon)
balloon_alert(user, "linked!")
/obj/item/extraction_pack/afterattack(atom/movable/thing, mob/living/carbon/human/user, proximity_flag, params)
. = ..()
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/extraction_pack/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!ismovable(interacting_with))
return NONE
if(!isturf(interacting_with.loc)) // no extracting stuff inside other stuff
return NONE
var/atom/movable/thing = interacting_with
if(thing.anchored)
return NONE
. = ITEM_INTERACT_BLOCKING
var/obj/structure/extraction_point/beacon = beacon_ref?.resolve()
if(isnull(beacon))
balloon_alert(user, "not linked")
balloon_alert(user, "not linked!")
beacon_ref = null
return
return .
if(!can_use_indoors)
var/area/area = get_area(thing)
if(!area.outdoors)
balloon_alert(user, "not outdoors")
return
if(!proximity_flag || !istype(thing))
return
balloon_alert(user, "not outdoors!")
return .
if(!safe_for_living_creatures && check_for_living_mobs(thing))
to_chat(user, span_warning("[src] is not safe for use with living creatures, they wouldn't survive the trip back!"))
balloon_alert(user, "not safe!")
return
if(!isturf(thing.loc)) // no extracting stuff inside other stuff
return
if(thing.anchored || (thing.move_resist > max_force_fulton))
return .
if(thing.move_resist > max_force_fulton)
balloon_alert(user, "too heavy!")
return
return .
balloon_alert_to_viewers("attaching...")
playsound(thing, 'sound/items/zip.ogg', vol = 50, vary = TRUE)
if(isliving(thing))
@@ -89,11 +86,12 @@ GLOBAL_LIST_EMPTY(total_extraction_beacons)
to_chat(thing, span_userdanger("You are being extracted! Stand still to proceed."))
if(!do_after(user, 5 SECONDS, target = thing))
return
return .
balloon_alert_to_viewers("extracting!")
if(loc == user)
user.back?.atom_storage?.attempt_insert(src, user, force = STORAGE_SOFT_LOCKED)
if(loc == user && ishuman(user))
var/mob/living/carbon/human/human_user = user
human_user.back?.atom_storage?.attempt_insert(src, user, force = STORAGE_SOFT_LOCKED)
uses_left--
if(uses_left <= 0)
@@ -180,6 +178,7 @@ GLOBAL_LIST_EMPTY(total_extraction_beacons)
qdel(holder_obj)
if(uses_left <= 0)
qdel(src)
return ITEM_INTERACT_SUCCESS
/obj/item/fulton_core
name = "extraction beacon assembly kit"
+52 -44
View File
@@ -99,14 +99,14 @@
blink_activated = !blink_activated
to_chat(user, span_notice("You [blink_activated ? "enable" : "disable"] the blink function on [src]."))
/obj/item/hierophant_club/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/hierophant_club/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
// If our target is the beacon and the hierostaff is next to the beacon, we're trying to pick it up.
if((target == beacon) && target.Adjacent(src))
return
if(interacting_with == beacon)
return NONE
if(blink_activated)
blink.teleport(user, target)
blink.teleport(user, interacting_with)
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/hierophant_club/update_icon_state()
icon_state = inhand_icon_state = "hierophant_club[blink?.current_charges > 0 ? "_ready":""][(!QDELETED(beacon)) ? "":"_beacon"]"
@@ -795,40 +795,43 @@
var/timer = 0
var/static/list/banned_turfs = typecacheof(list(/turf/open/space, /turf/closed))
/obj/item/lava_staff/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
/obj/item/lava_staff/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
/obj/item/lava_staff/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(timer > world.time)
return
. |= AFTERATTACK_PROCESSED_ITEM
if(is_type_in_typecache(target, banned_turfs))
return
if(target in view(user.client.view, get_turf(user)))
var/turf/open/T = get_turf(target)
if(!istype(T))
return
if(!islava(T))
var/obj/effect/temp_visual/lavastaff/L = new /obj/effect/temp_visual/lavastaff(T)
L.alpha = 0
animate(L, alpha = 255, time = create_delay)
user.visible_message(span_danger("[user] points [src] at [T]!"))
timer = world.time + create_delay + 1
if(do_after(user, create_delay, target = T))
var/old_name = T.name
if(T.TerraformTurf(turf_type, flags = CHANGETURF_INHERIT_AIR))
user.visible_message(span_danger("[user] turns \the [old_name] into [transform_string]!"))
message_admins("[ADMIN_LOOKUPFLW(user)] fired the lava staff at [ADMIN_VERBOSEJMP(T)]")
user.log_message("fired the lava staff at [AREACOORD(T)].", LOG_ATTACK)
timer = world.time + create_cooldown
playsound(T,'sound/magic/fireball.ogg', 200, TRUE)
else
timer = world.time
qdel(L)
else
return NONE
if(is_type_in_typecache(interacting_with, banned_turfs))
return NONE
if(!(interacting_with in view(user.client.view, get_turf(user))))
return NONE
var/turf/open/T = get_turf(interacting_with)
if(!istype(T))
return NONE
if(!islava(T))
var/obj/effect/temp_visual/lavastaff/L = new /obj/effect/temp_visual/lavastaff(T)
L.alpha = 0
animate(L, alpha = 255, time = create_delay)
user.visible_message(span_danger("[user] points [src] at [T]!"))
timer = world.time + create_delay + 1
if(do_after(user, create_delay, target = T))
var/old_name = T.name
if(T.TerraformTurf(reset_turf_type, flags = CHANGETURF_INHERIT_AIR))
user.visible_message(span_danger("[user] turns \the [old_name] into [reset_string]!"))
timer = world.time + reset_cooldown
if(T.TerraformTurf(turf_type, flags = CHANGETURF_INHERIT_AIR))
user.visible_message(span_danger("[user] turns \the [old_name] into [transform_string]!"))
message_admins("[ADMIN_LOOKUPFLW(user)] fired the lava staff at [ADMIN_VERBOSEJMP(T)]")
user.log_message("fired the lava staff at [AREACOORD(T)].", LOG_ATTACK)
timer = world.time + create_cooldown
playsound(T,'sound/magic/fireball.ogg', 200, TRUE)
else
timer = world.time
qdel(L)
else
var/old_name = T.name
if(T.TerraformTurf(reset_turf_type, flags = CHANGETURF_INHERIT_AIR))
user.visible_message(span_danger("[user] turns \the [old_name] into [reset_string]!"))
timer = world.time + reset_cooldown
playsound(T,'sound/magic/fireball.ogg', 200, TRUE)
return ITEM_INTERACT_SUCCESS
/obj/effect/temp_visual/lavastaff
icon_state = "lavastaff_warn"
@@ -1028,23 +1031,27 @@
affected_weather.wind_down()
user.log_message("has dispelled a storm at [AREACOORD(user_turf)].", LOG_GAME)
/obj/item/storm_staff/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/storm_staff/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return thunder_blast(interacting_with, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
/obj/item/storm_staff/afterattack(atom/target, mob/user, click_parameters)
thunder_blast(target, user)
/obj/item/storm_staff/proc/thunder_blast(atom/target, mob/user)
if(!thunder_charges)
balloon_alert(user, "needs to charge!")
return
return FALSE
var/turf/target_turf = get_turf(target)
var/area/target_area = get_area(target)
if(!target_turf || !target_area || (is_type_in_list(target_area, excluded_areas)))
balloon_alert(user, "can't bolt here!")
return
return FALSE
if(target_turf in targeted_turfs)
balloon_alert(user, "already targeted!")
return
return FALSE
if(HAS_TRAIT(user, TRAIT_PACIFISM))
balloon_alert(user, "you don't want to harm!")
return
return FALSE
var/power_boosted = FALSE
for(var/datum/weather/weather as anything in SSweather.processing)
if(weather.stage != MAIN_STAGE)
@@ -1060,6 +1067,7 @@
thunder_charges--
addtimer(CALLBACK(src, PROC_REF(recharge)), thunder_charge_time)
user.log_message("fired the staff of storms at [AREACOORD(target_turf)].", LOG_ATTACK)
return TRUE
/obj/item/storm_staff/proc/recharge(mob/user)
thunder_charges = min(thunder_charges + 1, max_thunder_charges)
+11 -13
View File
@@ -646,20 +646,18 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
continue
target_airlock.lock()
/obj/item/coin/eldritch/afterattack(atom/target_atom, mob/user, proximity)
. = ..()
if(!proximity)
return
/obj/item/coin/eldritch/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!istype(interacting_with, /obj/machinery/door/airlock))
return NONE
if(!IS_HERETIC(user))
var/mob/living/living_user = user
living_user.adjustBruteLoss(5)
living_user.adjustFireLoss(5)
return
if(istype(target_atom, /obj/machinery/door/airlock))
var/obj/machinery/door/airlock/target_airlock = target_atom
to_chat(user, span_warning("You insert [src] into the airlock."))
target_airlock.emag_act(user, src)
qdel(src)
user.adjustBruteLoss(5)
user.adjustFireLoss(5)
return ITEM_INTERACT_BLOCKING
var/obj/machinery/door/airlock/target_airlock = interacting_with
to_chat(user, span_warning("You insert [src] into the airlock."))
target_airlock.emag_act(user, src)
qdel(src)
return ITEM_INTERACT_SUCCESS
#undef GIBTONITE_QUALITY_HIGH
#undef GIBTONITE_QUALITY_LOW
@@ -215,10 +215,10 @@
balloon_alert(user, "now [combat_mode ? "attacking wildlife" : "collecting loose ore"]")
return CLICK_ACTION_SUCCESS
/mob/living/basic/mining_drone/RangedAttack(atom/target)
/mob/living/basic/mining_drone/RangedAttack(atom/target, list/modifiers)
if(!combat_mode)
return
stored_gun.afterattack(target, src)
stored_gun.try_fire_gun(target, src, list2params(modifiers))
/mob/living/basic/mining_drone/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
. = ..()
@@ -43,22 +43,22 @@
user.client?.mouse_override_icon = 'icons/effects/mouse_pointers/weapon_pointer.dmi'
user.update_mouse_pointer()
/obj/item/minebot_remote_control/afterattack(atom/attacked_atom, mob/living/user, proximity)
. = ..()
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/minebot_remote_control/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return ranged_interact_with_atom(interacting_with, user, modifiers)
/obj/item/minebot_remote_control/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!primed)
user.balloon_alert(user, "not primed!")
return
var/turf/target_turf = get_turf(attacked_atom)
return ITEM_INTERACT_BLOCKING
var/turf/target_turf = get_turf(interacting_with)
if(isnull(target_turf) || isclosedturf(target_turf) || isgroundlessturf(target_turf))
user.balloon_alert(user, "invalid target!")
return
return ITEM_INTERACT_BLOCKING
playsound(src, 'sound/machines/beep.ogg', 30)
clear_priming()
new /obj/effect/temp_visual/minebot_target(target_turf)
COOLDOWN_START(src, bomb_timer, BOMB_COOLDOWN)
return ITEM_INTERACT_SUCCESS
/obj/effect/temp_visual/minebot_target
name = "Rocket Target"
@@ -5,11 +5,11 @@
icon = 'icons/obj/devices/circuitry_n_data.dmi'
item_flags = NOBLUDGEON
/obj/item/mine_bot_upgrade/afterattack(mob/living/basic/mining_drone/minebot, mob/user, proximity)
. = ..()
if(!istype(minebot) || !proximity)
return
upgrade_bot(minebot, user)
/obj/item/mine_bot_upgrade/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!istype(interacting_with, /mob/living/basic/mining_drone))
return NONE
upgrade_bot(interacting_with, user)
return ITEM_INTERACT_SUCCESS
/obj/item/mine_bot_upgrade/proc/upgrade_bot(mob/living/basic/mining_drone/minebot, mob/user)
if(minebot.melee_damage_upper != initial(minebot.melee_damage_upper))
@@ -90,4 +90,3 @@
icon = 'icons/mob/silicon/aibots.dmi'
icon_state = "minebot_shield_bottom_layer"
layer = BELOW_MOB_LAYER
@@ -18,18 +18,17 @@
/mob/living/basic/guardian,
))
/obj/item/fugu_gland/afterattack(atom/target, mob/user, proximity_flag)
. = ..()
if(!proximity_flag || !isanimal_or_basicmob(target) || fugu_blacklist[target.type])
return
var/mob/living/animal = target
/obj/item/fugu_gland/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!isanimal_or_basicmob(interacting_with) || fugu_blacklist[interacting_with.type])
return NONE
var/mob/living/animal = interacting_with
if(animal.stat == DEAD || HAS_TRAIT(animal, TRAIT_FAKEDEATH))
balloon_alert(user, "it's dead!")
return
return ITEM_INTERACT_BLOCKING
if(HAS_TRAIT(animal, TRAIT_FUGU_GLANDED))
balloon_alert(user, "already large!")
return
return ITEM_INTERACT_BLOCKING
ADD_TRAIT(animal, TRAIT_FUGU_GLANDED, type)
animal.AddComponent(/datum/component/seethrough_mob)
@@ -41,3 +40,4 @@
animal.AddElement(/datum/element/wall_tearer)
to_chat(user, span_info("You increase the size of [animal], giving [animal.p_them()] a surge of strength!"))
qdel(src)
return ITEM_INTERACT_SUCCESS
+12 -12
View File
@@ -352,18 +352,18 @@
return ..()
/obj/item/food/deadmouse/afterattack(obj/target, mob/living/user, proximity_flag)
. = ..()
if(proximity_flag && reagents && target.is_open_container())
. |= AFTERATTACK_PROCESSED_ITEM
// is_open_container will not return truthy if target.reagents doesn't exist
var/datum/reagents/target_reagents = target.reagents
var/trans_amount = reagents.maximum_volume - reagents.total_volume * (4 / 3)
if(target_reagents.has_reagent(/datum/reagent/fuel) && target_reagents.trans_to(src, trans_amount))
to_chat(user, span_notice("You dip [src] into [target]."))
else
to_chat(user, span_warning("That's a terrible idea."))
return .
/obj/item/food/deadmouse/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(isnull(reagents) || !interacting_with.is_open_container())
return NONE
// is_open_container will not return truthy if target.reagents doesn't exist
var/datum/reagents/target_reagents = interacting_with.reagents
var/trans_amount = reagents.maximum_volume - reagents.total_volume * (4 / 3)
if(target_reagents.has_reagent(/datum/reagent/fuel) && target_reagents.trans_to(src, trans_amount))
to_chat(user, span_notice("You dip [src] into [interacting_with]."))
else
to_chat(user, span_warning("That's a terrible idea."))
return ITEM_INTERACT_BLOCKING
/obj/item/food/deadmouse/moldy
name = "moldy dead mouse"
+2 -3
View File
@@ -23,15 +23,14 @@
QDEL_NULL(dna)
GLOB.carbon_list -= src
/mob/living/carbon/item_tending(mob/living/user, obj/item/tool, list/modifiers)
/mob/living/carbon/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
. = ..()
if(. & ITEM_INTERACT_ANY_BLOCKER)
return .
// Needs to happen after parent call otherwise wounds are prioritized over surgery
for(var/datum/wound/wound as anything in shuffle(all_wounds))
if(wound.try_treating(tool, user))
return ITEM_INTERACT_SUCCESS
return .
/mob/living/carbon/CtrlShiftClick(mob/user)
@@ -82,7 +82,7 @@
if(!can_unarmed_attack())
return
if(internal_ext)
internal_ext.afterattack(A, src)
internal_ext.interact_with_atom(A, src, modifiers)
else
return ..()
@@ -90,7 +90,7 @@
if(!(bot_mode_flags & BOT_MODE_ON))
return
if(internal_ext)
internal_ext.afterattack(A, src)
internal_ext.interact_with_atom(A, src, modifiers)
else
return ..()
@@ -289,7 +289,7 @@
flick("firebots_use", user)
else
flick("firebot1_use", user)
internal_ext.afterattack(target, user, null)
internal_ext.interact_with_atom(target, src)
/mob/living/simple_animal/bot/firebot/update_icon_state()
. = ..()
@@ -368,26 +368,26 @@ While using this makes the system rely on OnFire, it still gives options for tim
throw_speed = 3
throw_range = 5
/obj/item/tumor_shard/afterattack(atom/target, mob/user, proximity_flag)
. = ..()
if(istype(target, /mob/living/simple_animal/hostile/asteroid/elite) && proximity_flag)
var/mob/living/simple_animal/hostile/asteroid/elite/E = target
if(E.stat != DEAD || E.sentience_type != SENTIENCE_BOSS || !E.key)
user.visible_message(span_notice("It appears [E] is unable to be revived right now. Perhaps try again later."))
return
E.faction = list("[REF(user)]")
E.revive(HEAL_ALL)
user.visible_message(span_notice("[user] stabs [E] with [src], reviving it."))
E.playsound_local(get_turf(E), 'sound/effects/magic.ogg', 40, 0)
to_chat(E, "<span class='userdanger'>You have been revived by [user]. While you can't speak to them, you owe [user] a great debt. Assist [user.p_them()] in achieving [user.p_their()] goals, regardless of risk.</span>")
to_chat(E, "<span class='big bold'>Note that you now share the loyalties of [user]. You are expected not to intentionally sabotage their faction unless commanded to!</span>")
E.maxHealth = E.maxHealth * 0.4
E.health = E.maxHealth
E.desc = "[E.desc] However, this one appears to be less wild in nature, and calmer around people."
E.sentience_type = SENTIENCE_ORGANIC
qdel(src)
else
to_chat(user, span_info("[src] only works on the corpse of a sentient lavaland elite."))
/obj/item/tumor_shard/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!istype(interacting_with, /mob/living/simple_animal/hostile/asteroid/elite))
return NONE
var/mob/living/simple_animal/hostile/asteroid/elite/E = interacting_with
if(E.stat != DEAD || E.sentience_type != SENTIENCE_BOSS || !E.key)
user.visible_message(span_notice("It appears [E] is unable to be revived right now. Perhaps try again later."))
return ITEM_INTERACT_BLOCKING
E.faction = list("[REF(user)]")
E.revive(HEAL_ALL)
user.visible_message(span_notice("[user] stabs [E] with [src], reviving it."))
E.playsound_local(get_turf(E), 'sound/effects/magic.ogg', 40, 0)
to_chat(E, "<span class='userdanger'>You have been revived by [user]. While you can't speak to them, you owe [user] a great debt. Assist [user.p_them()] in achieving [user.p_their()] goals, regardless of risk.</span>")
to_chat(E, "<span class='big bold'>Note that you now share the loyalties of [user]. You are expected not to intentionally sabotage their faction unless commanded to!</span>")
E.maxHealth = E.maxHealth * 0.4
E.health = E.maxHealth
E.desc = "[E.desc] However, this one appears to be less wild in nature, and calmer around people."
E.sentience_type = SENTIENCE_ORGANIC
qdel(src)
return ITEM_INTERACT_SUCCESS
/obj/effect/temp_visual/elite_tumor_wall
name = "magic wall"
+44 -34
View File
@@ -142,6 +142,9 @@
if(active)
. += span_notice("Charge: [core ? "[get_charge_percent()]%" : "No core"].")
. += span_notice("Selected module: [selected_module || "None"].")
if(atom_storage)
. += span_notice("<i>While the suit's panel is open, \
being on <b>combat mode</b> will prevent you from inserting items into it when clicking on it.</i>")
if(!open && !active)
if(!wearer)
. += span_notice("You could equip it to turn it on.")
@@ -239,33 +242,28 @@
return ..()
/obj/item/mod/control/wrench_act(mob/living/user, obj/item/wrench)
if(..())
return TRUE
if(seconds_electrified && get_charge() && shock(user))
return TRUE
return ITEM_INTERACT_BLOCKING
if(open)
if(!core)
balloon_alert(user, "no core!")
return TRUE
return ITEM_INTERACT_BLOCKING
balloon_alert(user, "removing core...")
wrench.play_tool_sound(src, 100)
if(!wrench.use_tool(src, user, 3 SECONDS) || !open)
balloon_alert(user, "interrupted!")
return TRUE
return ITEM_INTERACT_BLOCKING
wrench.play_tool_sound(src, 100)
balloon_alert(user, "core removed")
core.forceMove(drop_location())
return TRUE
return ..()
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/mod/control/screwdriver_act(mob/living/user, obj/item/screwdriver)
. = ..()
if(.)
return TRUE
if(active || activating || ai_controller)
balloon_alert(user, "deactivate suit first!")
playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE)
return FALSE
return ITEM_INTERACT_BLOCKING
balloon_alert(user, "[open ? "closing" : "opening"] cover...")
screwdriver.play_tool_sound(src, 100)
if(screwdriver.use_tool(src, user, 1 SECONDS))
@@ -276,21 +274,21 @@
open = !open
else
balloon_alert(user, "interrupted!")
return TRUE
return ITEM_INTERACT_SUCCESS
/obj/item/mod/control/crowbar_act(mob/living/user, obj/item/crowbar)
. = ..()
if(!open)
balloon_alert(user, "open the cover first!")
playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE)
return FALSE
return ITEM_INTERACT_BLOCKING
if(!allowed(user))
balloon_alert(user, "insufficient access!")
playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE)
return
return ITEM_INTERACT_BLOCKING
if(SEND_SIGNAL(src, COMSIG_MOD_MODULE_REMOVAL, user) & MOD_CANCEL_REMOVAL)
playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE)
return FALSE
return ITEM_INTERACT_BLOCKING
if(length(modules))
var/list/removable_modules = list()
for(var/obj/item/mod/module/module as anything in modules)
@@ -299,52 +297,64 @@
removable_modules += module
var/obj/item/mod/module/module_to_remove = tgui_input_list(user, "Which module to remove?", "Module Removal", removable_modules)
if(!module_to_remove?.mod)
return FALSE
return ITEM_INTERACT_BLOCKING
uninstall(module_to_remove)
module_to_remove.forceMove(drop_location())
crowbar.play_tool_sound(src, 100)
SEND_SIGNAL(src, COMSIG_MOD_MODULE_REMOVED, user)
return TRUE
return ITEM_INTERACT_SUCCESS
balloon_alert(user, "no modules!")
playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE)
return FALSE
return ITEM_INTERACT_BLOCKING
/obj/item/mod/control/attackby(obj/item/attacking_item, mob/living/user, params)
/obj/item/mod/control/storage_insert_on_interacted_with(datum/storage, obj/item/inserted, mob/living/user)
if(user.combat_mode)
// Block all item-click-inserts when we're open
// Other form of insertion will still function (mousedrop, hotkey)
if(open)
return FALSE
// ...You have to open it up somehow though
if(inserted.tool_behaviour == TOOL_SCREWDRIVER)
return FALSE
return TRUE
/obj/item/mod/control/item_interaction(mob/living/user, obj/item/attacking_item, list/modifiers)
if(istype(attacking_item, /obj/item/pai_card))
if(!open)
balloon_alert(user, "open the cover first!")
return FALSE
return ITEM_INTERACT_BLOCKING
insert_pai(user, attacking_item)
return TRUE
return ITEM_INTERACT_SUCCESS
if(istype(attacking_item, /obj/item/mod/module))
if(!open)
balloon_alert(user, "open the cover first!")
playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE)
return FALSE
return ITEM_INTERACT_BLOCKING
install(attacking_item, user)
SEND_SIGNAL(src, COMSIG_MOD_MODULE_ADDED, user)
return TRUE
else if(istype(attacking_item, /obj/item/mod/core))
return ITEM_INTERACT_SUCCESS
if(istype(attacking_item, /obj/item/mod/core))
if(!open)
balloon_alert(user, "open the cover first!")
playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE)
return FALSE
return ITEM_INTERACT_BLOCKING
if(core)
balloon_alert(user, "core already installed!")
playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE)
return FALSE
return ITEM_INTERACT_BLOCKING
var/obj/item/mod/core/attacking_core = attacking_item
attacking_core.install(src)
balloon_alert(user, "core installed")
playsound(src, 'sound/machines/click.ogg', 50, TRUE, SILENCED_SOUND_EXTRARANGE)
return TRUE
else if(is_wire_tool(attacking_item) && open)
wires.interact(user)
return TRUE
else if(open && attacking_item.GetID())
update_access(user, attacking_item.GetID())
return TRUE
return ..()
return ITEM_INTERACT_SUCCESS
if(open)
if(is_wire_tool(attacking_item))
wires.interact(user)
return ITEM_INTERACT_SUCCESS
if(attacking_item.GetID())
update_access(user, attacking_item.GetID())
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/mod/control/get_cell()
var/obj/item/stock_parts/cell/cell = get_charge_source()
+1 -2
View File
@@ -104,7 +104,7 @@
return ..()
/obj/structure/filingcabinet/attack_self_tk(mob/user)
. = COMPONENT_CANCEL_ATTACK_CHAIN
. = ITEM_INTERACT_BLOCKING
if(contents.len)
if(prob(40 + contents.len * 5))
var/obj/item/I = pick(contents)
@@ -203,4 +203,3 @@ GLOBAL_LIST_EMPTY(employmentCabinets)
fillCurrent()
virgin = FALSE
return ..()
+1 -1
View File
@@ -116,7 +116,7 @@
labels_left = initial(labels_left) //Yes, it's capped at its initial value
return ITEM_INTERACT_SUCCESS
/obj/item/hand_labeler/attackby_storage_insert(datum/storage, atom/storage_holder, mob/user)
/obj/item/hand_labeler/storage_insert_on_interaction(datum/storage, atom/storage_holder, mob/user)
return !mode
/obj/item/hand_labeler/borg
+5 -5
View File
@@ -501,22 +501,22 @@
. += span_notice("To initiate the surrender prompt, simply click on an individual within your proximity.")
//Code from the medical penlight
/obj/item/pen/red/security/afterattack(atom/target, mob/living/user, proximity)
. = ..()
/obj/item/pen/red/security/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!COOLDOWN_FINISHED(src, holosign_cooldown))
balloon_alert(user, "not ready!")
return
return ITEM_INTERACT_BLOCKING
var/target_turf = get_turf(target)
var/turf/target_turf = get_turf(interacting_with)
var/mob/living/living_target = locate(/mob/living) in target_turf
if(!living_target || (living_target == user))
return
return ITEM_INTERACT_BLOCKING
living_target.apply_status_effect(/datum/status_effect/surrender_timed)
to_chat(living_target, span_userdanger("[user] requests your immediate surrender! You are given 30 seconds to comply!"))
new /obj/effect/temp_visual/security_holosign(target_turf, user) //produce a holographic glow
COOLDOWN_START(src, holosign_cooldown, 30 SECONDS)
return ITEM_INTERACT_SUCCESS
/obj/effect/temp_visual/security_holosign
name = "security holosign"
+15 -9
View File
@@ -107,7 +107,7 @@
. += "It has [pictures_left] photos left."
//user can be atom or mob
/obj/item/camera/proc/can_target(atom/target, mob/user, prox_flag)
/obj/item/camera/proc/can_target(atom/target, mob/user)
if(!on || blending || !pictures_left)
return FALSE
var/turf/T = get_turf(target)
@@ -128,24 +128,30 @@
return FALSE
return TRUE
/obj/item/camera/afterattack(atom/target, mob/user, flag)
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/camera/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return ranged_interact_with_atom(interacting_with, user, modifiers)
/obj/item/camera/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if (disk)
if(ismob(target))
if(ismob(interacting_with))
if (disk.record)
QDEL_NULL(disk.record)
disk.record = new
var/mob/M = target
var/mob/M = interacting_with
disk.record.caller_name = M.name
disk.record.set_caller_image(M)
else
to_chat(user, span_warning("Invalid holodisk target."))
return
return ITEM_INTERACT_BLOCKING
if(!can_target(target, user, flag))
return
if(!can_target(interacting_with, user))
return ITEM_INTERACT_BLOCKING
if(!photo_taken(interacting_with, user))
return ITEM_INTERACT_BLOCKING
return ITEM_INTERACT_SUCCESS
/obj/item/camera/proc/photo_taken(atom/target, mob/user)
on = FALSE
addtimer(CALLBACK(src, PROC_REF(cooldown)), cooldown)
@@ -153,7 +159,7 @@
icon_state = state_off
INVOKE_ASYNC(src, PROC_REF(captureimage), target, user, picture_size_x - 1, picture_size_y - 1)
return TRUE
/obj/item/camera/proc/cooldown()
UNTIL(!blending)
+8 -9
View File
@@ -354,24 +354,23 @@ All the important duct code:
duct_color = new_color
add_atom_colour(GLOB.pipe_paint_colors[new_color], FIXED_COLOUR_PRIORITY)
/obj/item/stack/ducts/afterattack(atom/target, user, proximity)
. = ..()
if(!proximity)
return
if(istype(target, /obj/machinery/duct))
var/obj/machinery/duct/duct = target
/obj/item/stack/ducts/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(istype(interacting_with, /obj/machinery/duct))
var/obj/machinery/duct/duct = interacting_with
if(duct.anchored)
to_chat(user, span_warning("The duct must be unanchored before it can be picked up."))
return
return ITEM_INTERACT_BLOCKING
// Turn into a duct stack and then merge to the in-hand stack.
var/obj/item/stack/ducts/stack = new(duct.loc, 1, FALSE)
qdel(duct)
if(stack.can_merge(src))
stack.merge(src)
return
return ITEM_INTERACT_SUCCESS
check_attach_turf(interacting_with)
return ITEM_INTERACT_SUCCESS
check_attach_turf(target)
/obj/item/stack/ducts/proc/check_attach_turf(atom/target)
if(isopenturf(target) && use(1))
-4
View File
@@ -304,10 +304,6 @@
/obj/item/stock_parts/cell/get_part_rating()
return maxcharge * 10 + charge
/obj/item/stock_parts/cell/attackby_storage_insert(datum/storage, atom/storage_holder, mob/user)
var/obj/item/mod/control/mod = storage_holder
return !(istype(mod) && mod.open)
/* Cell variants*/
/obj/item/stock_parts/cell/empty
empty = TRUE
+7 -5
View File
@@ -501,11 +501,12 @@
. = ..()
ADD_TRAIT(src, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT)
/obj/item/turret_control/afterattack(atom/targeted_atom, mob/user, proxflag, clickparams)
. = ..()
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/turret_control/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return ranged_interact_with_atom(interacting_with, user, modifiers)
/obj/item/turret_control/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
var/obj/machinery/power/emitter/emitter = user.buckled
emitter.setDir(get_dir(emitter,targeted_atom))
emitter.setDir(get_dir(emitter, interacting_with))
user.setDir(emitter.dir)
switch(emitter.dir)
if(NORTH)
@@ -541,7 +542,7 @@
user.pixel_x = 8
user.pixel_y = -12
emitter.last_projectile_params = calculate_projectile_angle_and_pixel_offsets(user, null, clickparams)
emitter.last_projectile_params = calculate_projectile_angle_and_pixel_offsets(user, null, list2params(modifiers))
if(emitter.charge >= 10 && world.time > delay)
emitter.charge -= 10
@@ -549,6 +550,7 @@
delay = world.time + 10
else if (emitter.charge < 10)
playsound(src,'sound/machines/buzz-sigh.ogg', 50, TRUE)
return ITEM_INTERACT_SUCCESS
/obj/machinery/power/emitter/ctf
name = "Energy Cannon"
+55 -52
View File
@@ -248,30 +248,66 @@
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/gun/afterattack_secondary(mob/living/victim, mob/living/user, proximity_flag, click_parameters)
if(!isliving(victim) || !IN_GIVEN_RANGE(user, victim, GUNPOINT_SHOOTER_STRAY_RANGE))
return ..() //if they're out of range, just shootem.
if(!can_hold_up)
return ..()
/obj/item/gun/pre_attack(atom/A, mob/living/user, params)
. = ..()
if(.)
return .
if(isnull(bayonet) || !user.combat_mode)
return .
return bayonet.melee_attack_chain(user, A, params)
/obj/item/gun/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
if(user.combat_mode)
return NONE
if(istype(tool, /obj/item/knife))
var/obj/item/knife/new_stabber = tool
if(!can_bayonet || !new_stabber.bayonet || !isnull(bayonet)) //ensure the gun has an attachment point available, and that the knife is compatible with it.
return ITEM_INTERACT_BLOCKING
if(!user.transferItemToLoc(new_stabber, src))
return ITEM_INTERACT_BLOCKING
to_chat(user, span_notice("You attach [new_stabber] to [src]'s bayonet lug."))
bayonet = new_stabber
update_appearance()
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/gun/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(user.combat_mode && isliving(interacting_with))
return ITEM_INTERACT_SKIP_TO_ATTACK // Gun bash / bayonet attack
if(try_fire_gun(interacting_with, user, list2params(modifiers)))
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/gun/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
if(!can_hold_up || !isliving(interacting_with))
return interact_with_atom(interacting_with, user, modifiers)
var/datum/component/gunpoint/gunpoint_component = user.GetComponent(/datum/component/gunpoint)
if (gunpoint_component)
if(gunpoint_component.target == victim)
balloon_alert(user, "already holding them up!")
else
balloon_alert(user, "already holding someone up!")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if (user == victim)
balloon_alert(user, "already holding [gunpoint_component.target == interacting_with ? "them" : "someone"] up!")
return ITEM_INTERACT_BLOCKING
if (user == interacting_with)
balloon_alert(user, "can't hold yourself up!")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
if(do_after(user, 0.5 SECONDS, victim))
user.AddComponent(/datum/component/gunpoint, victim, src)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if(do_after(user, 0.5 SECONDS, interacting_with))
user.AddComponent(/datum/component/gunpoint, interacting_with, src)
return ITEM_INTERACT_SUCCESS
/obj/item/gun/afterattack(atom/target, mob/living/user, flag, params)
..()
fire_gun(target, user, flag, params)
return AFTERATTACK_PROCESSED_ITEM
/obj/item/gun/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(try_fire_gun(interacting_with, user, list2params(modifiers)))
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_BLOCKING
/obj/item/gun/ranged_interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
if(IN_GIVEN_RANGE(user, interacting_with, GUNPOINT_SHOOTER_STRAY_RANGE))
return interact_with_atom_secondary(interacting_with, user, modifiers)
return ..()
/obj/item/gun/proc/try_fire_gun(atom/target, mob/living/user, params)
return fire_gun(target, user, user.Adjacent(target), params)
/obj/item/gun/proc/fire_gun(atom/target, mob/living/user, flag, params)
if(QDELETED(target))
@@ -466,39 +502,6 @@
/obj/item/gun/proc/reset_semicd()
semicd = FALSE
/obj/item/gun/attack(mob/M, mob/living/user)
if(user.combat_mode) //Flogging
if(bayonet)
M.attackby(bayonet, user)
return
else
return ..()
return
/obj/item/gun/attack_atom(obj/O, mob/living/user, params)
if(user.combat_mode)
if(bayonet)
O.attackby(bayonet, user)
return
return ..()
/obj/item/gun/attackby(obj/item/I, mob/living/user, params)
if(user.combat_mode)
return ..()
else if(istype(I, /obj/item/knife))
var/obj/item/knife/K = I
if(!can_bayonet || !K.bayonet || bayonet) //ensure the gun has an attachment point available, and that the knife is compatible with it.
return ..()
if(!user.transferItemToLoc(I, src))
return
to_chat(user, span_notice("You attach [K] to [src]'s bayonet lug."))
bayonet = K
update_appearance()
else
return ..()
/obj/item/gun/screwdriver_act(mob/living/user, obj/item/I)
. = ..()
if(.)
@@ -159,17 +159,18 @@
underbarrel = new /obj/item/gun/ballistic/revolver/grenadelauncher/unrestricted(src)
update_appearance()
/obj/item/gun/ballistic/automatic/m90/afterattack_secondary(atom/target, mob/living/user, proximity_flag, click_parameters)
underbarrel.afterattack(target, user, proximity_flag, click_parameters)
return SECONDARY_ATTACK_CONTINUE_CHAIN
/obj/item/gun/ballistic/automatic/m90/try_fire_gun(atom/target, mob/living/user, params)
if(LAZYACCESS(params2list(params), RIGHT_CLICK))
return underbarrel.try_fire_gun(target, user, params)
return ..()
/obj/item/gun/ballistic/automatic/m90/attackby(obj/item/A, mob/user, params)
if(isammocasing(A))
if(istype(A, underbarrel.magazine.ammo_type))
/obj/item/gun/ballistic/automatic/m90/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
if(isammocasing(tool))
if(istype(tool, underbarrel.magazine.ammo_type))
underbarrel.attack_self(user)
underbarrel.attackby(A, user, params)
else
..()
underbarrel.attackby(tool, user, list2params(modifiers))
return ITEM_INTERACT_BLOCKING
return ..()
/obj/item/gun/ballistic/automatic/tommygun
name = "\improper Thompson SMG"
@@ -276,15 +277,15 @@
. += "l6_door_[cover_open ? "open" : "closed"]"
/obj/item/gun/ballistic/automatic/l6_saw/afterattack(atom/target as mob|obj|turf, mob/living/user as mob|obj, flag, params)
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/gun/ballistic/automatic/l6_saw/try_fire_gun(atom/target, mob/living/user, params)
if(cover_open)
balloon_alert(user, "close the cover!")
return
else
. |= ..()
return FALSE
. = ..()
if(.)
update_appearance()
return .
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/gun/ballistic/automatic/l6_saw/attack_hand(mob/user, list/modifiers)
@@ -63,14 +63,13 @@
playsound(src, 'sound/weapons/gun/bow/bow_draw.ogg', 25, TRUE)
update_appearance()
/obj/item/gun/ballistic/bow/afterattack(atom/target, mob/living/user, flag, params, passthrough = FALSE)
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/gun/ballistic/bow/try_fire_gun(atom/target, mob/living/user, params)
if(!chambered)
return
return FALSE
if(!drawn)
to_chat(user, span_warning("Without drawing the bow, the arrow uselessly falls to the ground."))
drop_arrow()
return
return FALSE
return ..() //fires, removing the arrow
/obj/item/gun/ballistic/bow/equipped(mob/user, slot, initial)
@@ -89,8 +89,10 @@
This one has been fitted with a special backblast diverter to prevent 'friendly' fire 'accidents' during use."
backblast = FALSE
/obj/item/gun/ballistic/rocketlauncher/afterattack()
/obj/item/gun/ballistic/rocketlauncher/try_fire_gun(atom/target, mob/living/user, params)
. = ..()
if(!.)
return
magazine.get_round(FALSE) //Hack to clear the mag after it's fired
/obj/item/gun/ballistic/rocketlauncher/attack_self_tk(mob/user)
@@ -85,21 +85,20 @@
QDEL_NULL(underbarrel)
return ..()
/obj/item/gun/ballistic/automatic/pistol/clandestine/fisher/afterattack_secondary(atom/target, mob/living/user, proximity_flag, click_parameters)
underbarrel.afterattack(target, user, proximity_flag, click_parameters)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/gun/ballistic/automatic/pistol/clandestine/fisher/try_fire_gun(atom/target, mob/living/user, params)
if(LAZYACCESS(params2list(params), RIGHT_CLICK))
return underbarrel.try_fire_gun(target, user, params)
return ..()
/obj/item/gun/ballistic/automatic/pistol/clandestine/fisher/afterattack(atom/target, mob/living/user, flag, params)
// mirrors what the standalone fisher does when you hit people with it
. = ..()
if(user.Adjacent(target))
var/obj/projectile/energy/fisher/melee/simulated_hit = new
simulated_hit.firer = user
simulated_hit.on_hit(target)
/obj/item/gun/ballistic/automatic/pistol/clandestine/fisher/afterattack(atom/target, mob/user, click_parameters)
var/obj/projectile/energy/fisher/melee/simulated_hit = new
simulated_hit.firer = user
simulated_hit.on_hit(target)
/obj/item/gun/ballistic/automatic/pistol/clandestine/fisher/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
// as above comment, mirrors what the standalone fisher does when you hit people with it
. = ..()
if(.)
return
var/obj/projectile/energy/fisher/melee/simulated_hit = new
simulated_hit.firer = throwingdatum.get_thrower()
simulated_hit.on_hit(hit_atom)
@@ -218,26 +218,24 @@
toggle_magazine()
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/gun/ballistic/shotgun/bulldog/afterattack_secondary(mob/living/victim, mob/living/user, proximity_flag, click_parameters)
/obj/item/gun/ballistic/shotgun/bulldog/ranged_interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
if(secondary_magazine)
toggle_magazine()
return SECONDARY_ATTACK_CALL_NORMAL
return ..()
/obj/item/gun/ballistic/shotgun/bulldog/attackby_secondary(obj/item/weapon, mob/user, params)
if(!istype(weapon, secondary_magazine_type))
balloon_alert(user, "[weapon.name] doesn't fit!")
return SECONDARY_ATTACK_CALL_NORMAL
if(!user.transferItemToLoc(weapon, src))
to_chat(user, span_warning("You cannot seem to get [src] out of your hands!"))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/gun/ballistic/shotgun/bulldog/item_interaction_secondary(mob/living/user, obj/item/tool, list/modifiers)
if(!istype(tool, secondary_magazine_type))
return ..()
if(!user.transferItemToLoc(tool, src))
return ITEM_INTERACT_BLOCKING
var/obj/item/ammo_box/magazine/old_mag = secondary_magazine
secondary_magazine = weapon
secondary_magazine = tool
if(old_mag)
user.put_in_hands(old_mag)
balloon_alert(user, "secondary [magazine_wording] loaded")
playsound(src, load_empty_sound, load_sound_volume, load_sound_vary)
update_appearance()
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_SUCCESS
/obj/item/gun/ballistic/shotgun/bulldog/click_alt_secondary(mob/user)
if(secondary_magazine)
@@ -338,6 +336,7 @@
. = ..()
. += span_notice("Right-click to shoot the hook.")
/obj/item/gun/ballistic/shotgun/hook/afterattack_secondary(atom/target, mob/user, proximity_flag, click_parameters)
hook.afterattack(target, user, proximity_flag, click_parameters)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/gun/ballistic/shotgun/hook/try_fire_gun(atom/target, mob/living/user, params)
if(LAZYACCESS(params2list(params), RIGHT_CLICK))
return hook.try_fire_gun(target, user, params)
return ..()
@@ -328,26 +328,27 @@
sync_ammo()
var/atom/target = source.mouse_object_ref?.resolve()
if(target)
INVOKE_ASYNC(src, PROC_REF(afterattack), target, source.mob, FALSE, source.mouseParams, passthrough = TRUE)
INVOKE_ASYNC(src, PROC_REF(try_fire_gun), target, source.mob, source.mouseParams, TRUE)
stop_aiming()
QDEL_LIST(current_tracers)
/obj/item/gun/energy/beam_rifle/afterattack(atom/target, mob/living/user, flag, params, passthrough = FALSE)
. |= AFTERATTACK_PROCESSED_ITEM
if(flag) //It's adjacent, is the user, or is on the user's person
/obj/item/gun/energy/beam_rifle/try_fire_gun(atom/target, mob/living/user, params, passthrough = FALSE)
if(user.Adjacent(target)) //It's adjacent, is the user, or is on the user's person
if(target in user.contents) //can't shoot stuff inside us.
return
return FALSE
if(!ismob(target) || user.combat_mode) //melee attack
return
return FALSE
if(target == user && user.zone_selected != BODY_ZONE_PRECISE_MOUTH) //so we can't shoot ourselves (unless mouth selected)
return
return FALSE
if(!passthrough && (aiming_time > aiming_time_fire_threshold))
return
return FALSE
if(lastfire > world.time + delay)
return
return FALSE
if(!..())
return FALSE
lastfire = world.time
. = ..()
stop_aiming()
return TRUE
/obj/item/gun/energy/beam_rifle/proc/sync_ammo()
for(var/obj/item/ammo_casing/energy/beam_rifle/AC in contents)
@@ -149,10 +149,11 @@
cell.give(transferred)
/obj/item/gun/energy/minigun/afterattack(atom/target, mob/living/user, flag, params)
/obj/item/gun/energy/minigun/try_fire_gun(atom/target, mob/living/user, params)
if(!ammo_pack || ammo_pack.loc != user)
to_chat(user, span_warning("You need the backpack power source to fire the gun!"))
. = ..()
return FALSE
return ..()
/obj/item/stock_parts/cell/minigun
name = "gatling gun fusion core"
@@ -156,13 +156,13 @@
While some would argue that this is a really terrible design choice, others argue that it is very funny to be able to shoot at light sources.<br>\
Caveat emptor.")
/obj/item/gun/energy/recharge/fisher/afterattack(atom/target, mob/living/user, flag, params)
// you should just shoot them, but in case you can't/wont
/obj/item/gun/energy/recharge/fisher/attack(mob/living/target_mob, mob/living/user, params)
. = ..()
if(user.Adjacent(target))
var/obj/projectile/energy/fisher/melee/simulated_hit = new
simulated_hit.firer = user
simulated_hit.on_hit(target)
if(.)
return
var/obj/projectile/energy/fisher/melee/simulated_hit = new
simulated_hit.firer = user
simulated_hit.on_hit(target_mob)
/obj/item/gun/energy/recharge/fisher/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
// ...you reeeeeally just shoot them, but in case you can't/won't
+13 -14
View File
@@ -231,17 +231,15 @@
if(istype(WH))
WH.gun = WEAKREF(src)
/obj/item/gun/energy/wormhole_projector/afterattack(atom/target, mob/living/user, flag, params)
if(select == AMMO_SELECT_ORANGE) //Last fired in right click mode. Switch to blue wormhole (left click).
select_fire()
/obj/item/gun/energy/wormhole_projector/try_fire_gun(atom/target, mob/living/user, params)
if(LAZYACCESS(params2list(params), RIGHT_CLICK))
if(select == AMMO_SELECT_BLUE) //Last fired in left click mode. Switch to orange wormhole (right click).
select_fire()
else
if(select == AMMO_SELECT_ORANGE) //Last fired in right click mode. Switch to blue wormhole (left click).
select_fire()
return ..()
/obj/item/gun/energy/wormhole_projector/afterattack_secondary(atom/target, mob/living/user, flag, params)
if(select == AMMO_SELECT_BLUE) //Last fired in left click mode. Switch to orange wormhole (right click).
select_fire()
fire_gun(target, user, flag, params)
return SECONDARY_ATTACK_CONTINUE_CHAIN
/obj/item/gun/energy/wormhole_projector/proc/on_portal_destroy(obj/effect/portal/P)
SIGNAL_HANDLER
if(P == p_blue)
@@ -408,13 +406,15 @@
coin_count++
COOLDOWN_START(src, coin_regen_cd, coin_regen_rate)
/obj/item/gun/energy/marksman_revolver/afterattack_secondary(atom/target, mob/living/user, params)
if(!CAN_THEY_SEE(target, user))
/obj/item/gun/energy/marksman_revolver/try_fire_gun(atom/target, mob/living/user, params)
if(!LAZYACCESS(params2list(params), RIGHT_CLICK))
return ..()
if(!CAN_THEY_SEE(target, user))
return ITEM_INTERACT_BLOCKING
if(max_coins && coin_count <= 0)
to_chat(user, span_warning("You don't have any coins right now!"))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
if(max_coins)
START_PROCESSING(SSobj, src)
@@ -426,5 +426,4 @@
var/obj/projectile/bullet/coin/new_coin = new(get_turf(user), target_turf, user)
new_coin.preparePixelProjectile(target_turf, user)
new_coin.fire()
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_SUCCESS
+12 -13
View File
@@ -33,24 +33,23 @@
return
..()
/obj/item/gun/magic/wand/afterattack(atom/target, mob/living/user)
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/gun/magic/wand/try_fire_gun(atom/target, mob/living/user, params)
if(!charges)
shoot_with_empty_chamber(user)
return
return FALSE
if(target == user)
if(no_den_usage)
var/area/A = get_area(user)
if(istype(A, /area/centcom/wizard_station))
to_chat(user, span_warning("You know better than to violate the security of The Den, best wait until you leave to use [src]."))
return
else
no_den_usage = 0
if(no_den_usage && istype(get_area(user), /area/centcom/wizard_station))
to_chat(user, span_warning("You know better than to violate the security of The Den, best wait until you leave to use [src]."))
return FALSE
zap_self(user)
else
. |= ..()
update_appearance()
. = TRUE
else
. = ..()
if(.)
update_appearance()
return .
/obj/item/gun/magic/wand/proc/zap_self(mob/living/user)
user.visible_message(span_danger("[user] zaps [user.p_them()]self with [src]."))
@@ -110,10 +110,8 @@
update_appearance()
return TRUE
/obj/item/gun/blastcannon/afterattack(atom/target, mob/user, flag, params)
. |= AFTERATTACK_PROCESSED_ITEM
if((!bomb && bombcheck) || !target || (get_dist(get_turf(target), get_turf(user)) <= 2))
/obj/item/gun/blastcannon/try_fire_gun(atom/target, mob/living/user, params)
if((!bomb && bombcheck) || isnull(target) || (get_dist(get_turf(target), get_turf(user)) <= 2))
return ..()
cached_target = WEAKREF(target)
@@ -123,12 +121,12 @@
span_danger("[user] points [src] at [target]!"),
span_danger("You point [src] at [target]!")
)
return
return FALSE
cached_firer = WEAKREF(user)
if(!bomb)
fire_debug(target, user, flag, params)
return
fire_debug(target, user, params)
return TRUE
playsound(src, dry_fire_sound, 30, TRUE) // *click
user.visible_message(
@@ -141,8 +139,7 @@
user.log_message("opened blastcannon transfer valve at [AREACOORD(current_turf)] while aiming at [AREACOORD(target_turf)] (target).", LOG_GAME)
bomb.toggle_valve()
update_appearance()
return
return TRUE
/**
* Channels an internal explosion into a blastwave projectile.
@@ -37,29 +37,36 @@
balloon_alert(user, "not enough gold")
// Siphon gold from a victim, recharging our gun & removing their Midas Blight debuff in the process.
/obj/item/gun/magic/midas_hand/afterattack_secondary(mob/living/victim, mob/living/user, proximity_flag, click_parameters)
if(!isliving(victim) || !IN_GIVEN_RANGE(user, victim, gold_suck_range))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if(victim == user)
balloon_alert(user, "can't siphon from self")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if(!victim.reagents)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/gun/magic/midas_hand/ranged_interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
if(!isliving(interacting_with) || !IN_GIVEN_RANGE(user, interacting_with, gold_suck_range))
return ITEM_INTERACT_BLOCKING
if(interacting_with == user)
balloon_alert(user, "can't siphon from self!")
return ITEM_INTERACT_BLOCKING
if(!interacting_with.reagents)
return ITEM_INTERACT_BLOCKING
var/gold_amount = victim.reagents.get_reagent_amount(/datum/reagent/gold, type_check = REAGENT_SUB_TYPE)
var/gold_amount = interacting_with.reagents.get_reagent_amount(/datum/reagent/gold, type_check = REAGENT_SUB_TYPE)
if(!gold_amount)
balloon_alert(user, "no gold in bloodstream")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
var/gold_beam = user.Beam(victim, icon_state="drain_gold")
if(!do_after(user = user, delay = 1 SECONDS, target = victim, timed_action_flags = (IGNORE_USER_LOC_CHANGE | IGNORE_TARGET_LOC_CHANGE), extra_checks = CALLBACK(src, PROC_REF(check_gold_range), user, victim)))
balloon_alert(user, "no gold in bloodstream!")
return ITEM_INTERACT_BLOCKING
var/mob/living/victim = interacting_with
var/gold_beam = user.Beam(victim, icon_state = "drain_gold")
if(!do_after(
user = user,
delay = 1 SECONDS,
target = victim,
timed_action_flags = (IGNORE_USER_LOC_CHANGE | IGNORE_TARGET_LOC_CHANGE),
extra_checks = CALLBACK(src, PROC_REF(check_gold_range), user, victim),
))
qdel(gold_beam)
balloon_alert(user, "link broken")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
balloon_alert(user, "link broken!")
return ITEM_INTERACT_BLOCKING
handle_gold_charges(user, gold_amount)
victim.reagents.remove_reagent(/datum/reagent/gold, gold_amount, include_subtypes = TRUE)
victim.remove_status_effect(/datum/status_effect/midas_blight)
qdel(gold_beam)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_SUCCESS
// If we botch a shot, we have to start over again by inserting gold coins into the gun. Can only be done if it has no charges or gold.
/obj/item/gun/magic/midas_hand/attackby(obj/item/I, mob/living/user, params)
@@ -77,23 +77,23 @@
return TRUE
/obj/item/gun/syringe/attackby(obj/item/A, mob/user, params, show_msg = TRUE)
if(istype(A, /obj/item/reagent_containers/syringe/bluespace))
balloon_alert(user, "[A.name] is too big!")
return TRUE
if(istype(A, /obj/item/reagent_containers/syringe))
/obj/item/gun/syringe/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
if(istype(tool, /obj/item/reagent_containers/syringe/bluespace))
balloon_alert(user, "[tool.name] is too big!")
return ITEM_INTERACT_BLOCKING
if(istype(tool, /obj/item/reagent_containers/syringe))
if(syringes.len < max_syringes)
if(!user.transferItemToLoc(A, src))
return FALSE
balloon_alert(user, "[A.name] loaded")
syringes += A
if(!user.transferItemToLoc(tool, src))
return ITEM_INTERACT_BLOCKING
balloon_alert(user, "[tool.name] loaded")
syringes += tool
recharge_newshot()
update_appearance()
playsound(loc, load_sound, 40)
return TRUE
else
balloon_alert(user, "it's already full!")
return FALSE
playsound(src, load_sound, 40)
return ITEM_INTERACT_SUCCESS
balloon_alert(user, "it's full!")
return ITEM_INTERACT_BLOCKING
return NONE
/obj/item/gun/syringe/update_overlays()
. = ..()
@@ -158,24 +158,24 @@
. = ..()
chambered = new /obj/item/ammo_casing/dnainjector(src)
/obj/item/gun/syringe/dna/attackby(obj/item/A, mob/user, params, show_msg = TRUE)
if(istype(A, /obj/item/dnainjector))
var/obj/item/dnainjector/D = A
/obj/item/gun/syringe/dna/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
if(istype(tool, /obj/item/dnainjector))
var/obj/item/dnainjector/D = tool
if(D.used)
balloon_alert(user, "[D.name] is used up!")
return
return ITEM_INTERACT_BLOCKING
if(syringes.len < max_syringes)
if(!user.transferItemToLoc(D, src))
return FALSE
return ITEM_INTERACT_BLOCKING
balloon_alert(user, "[D.name] loaded")
syringes += D
recharge_newshot()
update_appearance()
playsound(loc, load_sound, 40)
return TRUE
else
balloon_alert(user, "it's already full!")
return FALSE
return ITEM_INTERACT_SUCCESS
balloon_alert(user, "it's already full!")
return ITEM_INTERACT_BLOCKING
return NONE
/obj/item/gun/syringe/blowgun
name = "blowgun"
+28 -27
View File
@@ -25,32 +25,31 @@
if(isgun(newloc))
gun = newloc
/obj/item/firing_pin/afterattack(atom/target, mob/user, proximity_flag)
. = ..()
if(proximity_flag)
if(isgun(target))
. |= AFTERATTACK_PROCESSED_ITEM
var/obj/item/gun/targeted_gun = target
var/obj/item/firing_pin/old_pin = targeted_gun.pin
if(old_pin?.pin_removable && (force_replace || old_pin.pin_hot_swappable))
if(Adjacent(user))
user.put_in_hands(old_pin)
else
old_pin.forceMove(targeted_gun.drop_location())
old_pin.gun_remove(user)
/obj/item/firing_pin/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!isgun(interacting_with))
return NONE
if(!targeted_gun.pin)
if(!user.temporarilyRemoveItemFromInventory(src))
return .
if(gun_insert(user, targeted_gun))
if(old_pin)
balloon_alert(user, "swapped firing pin")
else
balloon_alert(user, "inserted firing pin")
else
to_chat(user, span_notice("This firearm already has a firing pin installed."))
var/obj/item/gun/targeted_gun = interacting_with
var/obj/item/firing_pin/old_pin = targeted_gun.pin
if(old_pin?.pin_removable && (force_replace || old_pin.pin_hot_swappable))
if(Adjacent(user))
user.put_in_hands(old_pin)
else
old_pin.forceMove(targeted_gun.drop_location())
old_pin.gun_remove(user)
if(!targeted_gun.pin)
if(!user.temporarilyRemoveItemFromInventory(src))
return .
if(gun_insert(user, targeted_gun))
if(old_pin)
balloon_alert(user, "swapped firing pin")
else
balloon_alert(user, "inserted firing pin")
else
to_chat(user, span_notice("This firearm already has a firing pin installed."))
return ITEM_INTERACT_SUCCESS
/obj/item/firing_pin/emag_act(mob/user, obj/item/card/emag/emag_card)
if(obj_flags & EMAGGED)
@@ -190,13 +189,15 @@
fail_message = "dna check failed!"
var/unique_enzymes = null
/obj/item/firing_pin/dna/afterattack(atom/target, mob/user, proximity_flag)
. = ..()
if(proximity_flag && iscarbon(target))
var/mob/living/carbon/M = target
/obj/item/firing_pin/dna/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(iscarbon(interacting_with))
var/mob/living/carbon/M = interacting_with
if(M.dna && M.dna.unique_enzymes)
unique_enzymes = M.dna.unique_enzymes
balloon_alert(user, "dna lock set")
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_BLOCKING
return ..()
/obj/item/firing_pin/dna/pin_auth(mob/living/carbon/user)
if(user && user.dna && user.dna.unique_enzymes)
+51 -50
View File
@@ -78,20 +78,20 @@
///If the paper was used, and therefore cannot change color again
var/used = FALSE
/obj/item/ph_paper/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
if(!is_reagent_container(target))
return
. |= AFTERATTACK_PROCESSED_ITEM
var/obj/item/reagent_containers/cont = target
if(used == TRUE)
to_chat(user, span_warning("[src] has already been used!"))
/obj/item/ph_paper/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!is_reagent_container(interacting_with))
return
var/obj/item/reagent_containers/cont = interacting_with
if(!LAZYLEN(cont.reagents.reagent_list))
return
return NONE
if(used)
to_chat(user, span_warning("[src] has already been used!"))
return ITEM_INTERACT_BLOCKING
CONVERT_PH_TO_COLOR(round(cont.reagents.ph, 1), color)
desc += " The paper looks to be around a pH of [round(cont.reagents.ph, 1)]"
name = "used [name]"
used = TRUE
return ITEM_INTERACT_SUCCESS
/*
* pH meter that will give a detailed or truncated analysis of all the reagents in of an object with a reagents datum attached to it. Only way of detecting purity for now.
@@ -113,18 +113,16 @@
to_chat(user, span_notice("You switch the chemical analyzer to not include reagent descriptions in it's report."))
scanmode = SHORTENED_CHEM_OUTPUT
/obj/item/ph_meter/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(!is_reagent_container(target))
return
. |= AFTERATTACK_PROCESSED_ITEM
var/obj/item/reagent_containers/cont = target
if(LAZYLEN(cont.reagents.reagent_list) == null)
return
/obj/item/ph_meter/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!is_reagent_container(interacting_with))
return NONE
var/obj/item/reagent_containers/cont = interacting_with
if(!LAZYLEN(cont.reagents.reagent_list))
return NONE
var/list/out_message = list()
to_chat(user, "<i>The chemistry meter beeps and displays:</i>")
out_message += "<span class='notice'><b>Total volume: [round(cont.volume, 0.01)] Current temperature: [round(cont.reagents.chem_temp, 0.1)]K Total pH: [round(cont.reagents.ph, 0.01)]\n"
out_message += "Chemicals found in [target.name]:</b>\n"
out_message += "Chemicals found in [interacting_with.name]:</b>\n"
if(cont.reagents.is_reacting)
out_message += "[span_warning("A reaction appears to be occuring currently.")]<span class='notice'>\n"
for(var/datum/reagent/reagent in cont.reagents.reagent_list)
@@ -137,6 +135,7 @@
out_message += "<b>Analysis:</b> [reagent.description]\n"
to_chat(user, "[out_message.Join()]</span>")
desc = "An electrode attached to a small circuit box that will display details of a solution. Can be toggled to provide a description of each of the reagents. The screen currently displays detected vol: [round(cont.volume, 0.01)] detected pH:[round(cont.reagents.ph, 0.1)]."
return ITEM_INTERACT_SUCCESS
/obj/item/burner
name = "burner"
@@ -187,24 +186,25 @@
set_lit(TRUE)
user.visible_message(span_notice("[user] lights up the [src]."))
/obj/item/burner/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(lit)
. |= AFTERATTACK_PROCESSED_ITEM
if(is_reagent_container(target))
var/obj/item/reagent_containers/container = target
container.reagents.expose_temperature(get_temperature())
to_chat(user, span_notice("You heat up the [src]."))
playsound(user.loc, 'sound/chemistry/heatdam.ogg', 50, TRUE)
return .
else if(isitem(target))
var/obj/item/item = target
if(item.heat > 1000)
. |= AFTERATTACK_PROCESSED_ITEM
set_lit(TRUE)
user.visible_message(span_notice("[user] lights up the [src]."))
/obj/item/burner/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!lit)
return NONE
return .
if(is_reagent_container(interacting_with))
var/obj/item/reagent_containers/container = interacting_with
container.reagents.expose_temperature(get_temperature())
user.visible_message(span_notice("[user] heats up [src]."), span_notice("You heat up [src]."))
playsound(user, 'sound/chemistry/heatdam.ogg', 50, TRUE)
return ITEM_INTERACT_SUCCESS
else if(isitem(interacting_with))
var/obj/item/item = interacting_with
if(item.get_temperature() > 1000)
set_lit(TRUE)
user.visible_message(span_notice("[user] lights up [src]."), span_notice("You light up [src]."))
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_BLOCKING
/obj/item/burner/update_icon_state()
. = ..()
@@ -281,7 +281,7 @@
/obj/item/thermometer
name = "thermometer"
desc = "A thermometer for checking a beaker's temperature"
desc = "A thermometer for checking a something's temperature."
icon_state = "thermometer"
icon = 'icons/obj/medical/chemical.dmi'
item_flags = NOBLUDGEON
@@ -291,19 +291,18 @@
var/datum/reagents/attached_to_reagents
/obj/item/thermometer/Destroy()
QDEL_NULL(attached_to_reagents) //I have no idea how you can destroy this, but not the beaker, but here we go
attached_to_reagents = null
return ..()
/obj/item/thermometer/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
. |= AFTERATTACK_PROCESSED_ITEM
if(target.reagents)
if(!user.transferItemToLoc(src, target))
return .
attached_to_reagents = target.reagents
to_chat(user, span_notice("You add the [src] to the [target]."))
ui_interact(usr, null)
return .
/obj/item/thermometer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(isnull(interacting_with.reagents))
return NONE
if(!user.transferItemToLoc(src, interacting_with))
return ITEM_INTERACT_BLOCKING
attached_to_reagents = interacting_with.reagents
to_chat(user, span_notice("You add the [src] to [interacting_with]."))
ui_interact(user)
return ITEM_INTERACT_SUCCESS
/obj/item/thermometer/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
@@ -316,7 +315,7 @@
INVOKE_ASYNC(src, PROC_REF(remove_thermometer), user)
/obj/item/thermometer/ui_status(mob/user, datum/ui_state/state)
if(!(in_range(src, user)))
if(!in_range(src, user))
return UI_CLOSE
return UI_INTERACTIVE
@@ -326,7 +325,9 @@
/obj/item/thermometer/ui_data(mob/user)
if(!attached_to_reagents)
ui_close(user)
var/data = list()
return
var/list/data = list()
data["Temperature"] = round(attached_to_reagents.chem_temp)
return data
@@ -335,8 +336,8 @@
attached_to_reagents = null
/obj/item/thermometer/proc/try_put_in_hand(obj/object, mob/living/user)
to_chat(user, span_notice("You remove the [src] from the [attached_to_reagents.my_atom]."))
if(!issilicon(user) && in_range(src.loc, user))
to_chat(user, span_notice("You remove the [src] from [attached_to_reagents.my_atom]."))
if(!issilicon(user) && in_range(loc, user))
user.put_in_hands(object)
else
object.forceMove(drop_location())
@@ -96,7 +96,7 @@
if(!QDELETED(beaker))
if(istype(held_item, /obj/item/reagent_containers/dropper) || istype(held_item, /obj/item/reagent_containers/syringe))
var/obj/item/reagent_containers/injector = held_item
injector.afterattack(beaker, user, proximity_flag = TRUE)
injector.interact_with_atom(beaker, user, modifiers)
return ITEM_INTERACT_SUCCESS
if(is_reagent_container(held_item) && held_item.is_open_container())
@@ -87,9 +87,9 @@
return ..()
var/list/modifiers = params2list(params)
if(istype(held_item, /obj/item/reagent_containers/syringe) && LAZYACCESS(modifiers, RIGHT_CLICK))
held_item.afterattack_secondary(beaker, user, Adjacent(user), params)
held_item.interact_with_atom_secondary(beaker, user)
else
held_item.afterattack(beaker, user, Adjacent(user), params)
held_item.interact_with_atom(beaker, user)
SStgui.update_uis(src)
return TRUE
@@ -66,34 +66,33 @@
playsound(M.loc,'sound/items/drink.ogg', rand(10,50), TRUE)
return TRUE
/obj/item/reagent_containers/condiment/afterattack(obj/target, mob/user , proximity)
. = ..()
if(!proximity)
return
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/reagent_containers/condiment/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(istype(target, /obj/structure/reagent_dispensers)) //A dispenser. Transfer FROM it TO us.
if(!target.reagents.total_volume)
to_chat(user, span_warning("[target] is empty!"))
return
return ITEM_INTERACT_BLOCKING
if(reagents.total_volume >= reagents.maximum_volume)
to_chat(user, span_warning("[src] is full!"))
return
return ITEM_INTERACT_BLOCKING
var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, transferred_by = user)
to_chat(user, span_notice("You fill [src] with [trans] units of the contents of [target]."))
return ITEM_INTERACT_SUCCESS
//Something like a glass or a food item. Player probably wants to transfer TO it.
else if(target.is_drainable() || IS_EDIBLE(target))
if(!reagents.total_volume)
to_chat(user, span_warning("[src] is empty!"))
return
return ITEM_INTERACT_BLOCKING
if(target.reagents.total_volume >= target.reagents.maximum_volume)
to_chat(user, span_warning("you can't add anymore to [target]!"))
return
return ITEM_INTERACT_BLOCKING
var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this, transferred_by = user)
to_chat(user, span_notice("You transfer [trans] units of the condiment to [target]."))
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/reagent_containers/condiment/enzyme
name = "universal enzyme"
@@ -149,11 +148,10 @@
desc = "Salt. From dead crew, presumably."
return TOXLOSS
/obj/item/reagent_containers/condiment/saltshaker/afterattack(obj/target, mob/living/user, proximity)
/obj/item/reagent_containers/condiment/saltshaker/interact_with_atom(atom/target, mob/living/user, list/modifiers)
. = ..()
if(!proximity)
return
. |= AFTERATTACK_PROCESSED_ITEM
if(. & ITEM_INTERACT_ANY_BLOCKER)
return .
if(isturf(target))
if(!reagents.has_reagent(/datum/reagent/consumable/salt, 2))
to_chat(user, span_warning("You don't have enough salt to make a pile!"))
@@ -161,7 +159,8 @@
user.visible_message(span_notice("[user] shakes some salt onto [target]."), span_notice("You shake some salt onto [target]."))
reagents.remove_reagent(/datum/reagent/consumable/salt, 2)
new/obj/effect/decal/cleanable/food/salt(target)
return
return ITEM_INTERACT_SUCCESS
return .
/obj/item/reagent_containers/condiment/peppermill
name = "pepper mill"
@@ -441,26 +440,22 @@
/obj/item/reagent_containers/condiment/pack/attack(mob/M, mob/user, def_zone) //Can't feed these to people directly.
return
/obj/item/reagent_containers/condiment/pack/afterattack(obj/target, mob/user , proximity)
if(!proximity)
return
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/reagent_containers/condiment/pack/interact_with_atom(atom/target, mob/living/user, list/modifiers)
//You can tear the bag open above food to put the condiments on it, obviously.
if(IS_EDIBLE(target))
if(!reagents.total_volume)
to_chat(user, span_warning("You tear open [src], but there's nothing in it."))
qdel(src)
return
return ITEM_INTERACT_BLOCKING
if(target.reagents.total_volume >= target.reagents.maximum_volume)
to_chat(user, span_warning("You tear open [src], but [target] is stacked so high that it just drips off!") )
qdel(src)
return
else
to_chat(user, span_notice("You tear open [src] above [target] and the condiments drip onto it."))
src.reagents.trans_to(target, amount_per_transfer_from_this, transferred_by = user)
qdel(src)
return
return . | ..()
return ITEM_INTERACT_BLOCKING
to_chat(user, span_notice("You tear open [src] above [target] and the condiments drip onto it."))
src.reagents.trans_to(target, amount_per_transfer_from_this, transferred_by = user)
qdel(src)
return ITEM_INTERACT_SUCCESS
return ..()
/// Handles reagents getting added to the condiment pack.
/obj/item/reagent_containers/condiment/pack/proc/on_reagent_add(datum/reagents/reagents)
@@ -101,68 +101,66 @@
if(LAZYLEN(diseases_to_add))
AddComponent(/datum/component/infective, diseases_to_add)
/obj/item/reagent_containers/cup/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(!proximity_flag)
return
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/reagent_containers/cup/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(!check_allowed_items(target, target_self = TRUE))
return
return NONE
if(!spillable)
return
return NONE
if(target.is_refillable()) //Something like a glass. Player probably wants to transfer TO it.
if(!reagents.total_volume)
to_chat(user, span_warning("[src] is empty!"))
return
return ITEM_INTERACT_BLOCKING
if(target.reagents.holder_full())
to_chat(user, span_warning("[target] is full."))
return
return ITEM_INTERACT_BLOCKING
var/trans = reagents.trans_to(target, amount_per_transfer_from_this, transferred_by = user)
to_chat(user, span_notice("You transfer [trans] unit\s of the solution to [target]."))
SEND_SIGNAL(src, COMSIG_REAGENTS_CUP_TRANSFER_TO, target)
target.update_appearance()
return ITEM_INTERACT_SUCCESS
else if(target.is_drainable()) //A dispenser. Transfer FROM it TO us.
if(target.is_drainable()) //A dispenser. Transfer FROM it TO us.
if(!target.reagents.total_volume)
to_chat(user, span_warning("[target] is empty and can't be refilled!"))
return
return ITEM_INTERACT_BLOCKING
if(reagents.holder_full())
to_chat(user, span_warning("[src] is full."))
return
return ITEM_INTERACT_BLOCKING
var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, transferred_by = user)
to_chat(user, span_notice("You fill [src] with [trans] unit\s of the contents of [target]."))
SEND_SIGNAL(src, COMSIG_REAGENTS_CUP_TRANSFER_FROM, target)
target.update_appearance()
return ITEM_INTERACT_SUCCESS
/obj/item/reagent_containers/cup/afterattack_secondary(atom/target, mob/user, proximity_flag, click_parameters)
if((!proximity_flag) || !check_allowed_items(target, target_self = TRUE))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return NONE
/obj/item/reagent_containers/cup/interact_with_atom_secondary(atom/target, mob/living/user, list/modifiers)
if(user.combat_mode)
return ITEM_INTERACT_SKIP_TO_ATTACK
if(!check_allowed_items(target, target_self = TRUE))
return NONE
if(!spillable)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
if(target.is_drainable()) //A dispenser. Transfer FROM it TO us.
if(!target.reagents.total_volume)
to_chat(user, span_warning("[target] is empty!"))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
if(reagents.holder_full())
to_chat(user, span_warning("[src] is full."))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, transferred_by = user)
to_chat(user, span_notice("You fill [src] with [trans] unit\s of the contents of [target]."))
target.update_appearance()
return SECONDARY_ATTACK_CONTINUE_CHAIN
return ITEM_INTERACT_SUCCESS
/obj/item/reagent_containers/cup/attackby(obj/item/attacking_item, mob/user, params)
var/hotness = attacking_item.get_temperature()
@@ -291,20 +291,18 @@
return ..()
/obj/item/reagent_containers/cup/glass/waterbottle/afterattack(obj/target, mob/living/user, proximity)
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/reagent_containers/cup/glass/waterbottle/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(cap_on && (target.is_refillable() || target.is_drainable() || (reagents.total_volume && !user.combat_mode)))
to_chat(user, span_warning("You must remove the cap before you can do that!"))
return
return ITEM_INTERACT_BLOCKING
else if(istype(target, /obj/item/reagent_containers/cup/glass/waterbottle))
if(istype(target, /obj/item/reagent_containers/cup/glass/waterbottle))
var/obj/item/reagent_containers/cup/glass/waterbottle/other_bottle = target
if(other_bottle.cap_on)
to_chat(user, span_warning("[other_bottle] has a cap firmly twisted on!"))
return
return ITEM_INTERACT_BLOCKING
return . | ..()
return ..()
// heehoo bottle flipping
/obj/item/reagent_containers/cup/glass/waterbottle/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
@@ -11,22 +11,18 @@
reagent_flags = TRANSPARENT
custom_price = PAYCHECK_CREW
/obj/item/reagent_containers/dropper/afterattack(obj/target, mob/user , proximity)
. = ..()
if(!proximity)
return
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/reagent_containers/dropper/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(!target.reagents)
return
return NONE
if(reagents.total_volume > 0)
if(target.reagents.holder_full())
to_chat(user, span_notice("[target] is full."))
return
return ITEM_INTERACT_BLOCKING
if(!target.is_injectable(user))
to_chat(user, span_warning("You cannot transfer reagents to [target]!"))
return
return ITEM_INTERACT_BLOCKING
var/trans = 0
var/fraction = min(amount_per_transfer_from_this / reagents.total_volume, 1)
@@ -48,10 +44,10 @@
to_chat(user, span_notice("You transfer [trans] unit\s of the solution."))
update_appearance()
return
return ITEM_INTERACT_BLOCKING
else if(isalien(target)) //hiss-hiss has no eyes!
to_chat(target, span_danger("[target] does not seem to have any eyes!"))
return
return ITEM_INTERACT_BLOCKING
target.visible_message(span_danger("[user] squirts something into [target]'s eyes!"), \
span_userdanger("[user] squirts something into your eyes!"))
@@ -69,23 +65,23 @@
to_chat(user, span_notice("You transfer [trans] unit\s of the solution."))
update_appearance()
target.update_appearance()
return ITEM_INTERACT_SUCCESS
else
if(!target.is_drawable(user, FALSE)) //No drawing from mobs here
to_chat(user, span_warning("You cannot directly remove reagents from [target]!"))
return ITEM_INTERACT_BLOCKING
if(!target.is_drawable(user, FALSE)) //No drawing from mobs here
to_chat(user, span_warning("You cannot directly remove reagents from [target]!"))
return
if(!target.reagents.total_volume)
to_chat(user, span_warning("[target] is empty!"))
return ITEM_INTERACT_BLOCKING
if(!target.reagents.total_volume)
to_chat(user, span_warning("[target] is empty!"))
return
var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, transferred_by = user)
var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, transferred_by = user)
to_chat(user, span_notice("You fill [src] with [trans] unit\s of the solution."))
to_chat(user, span_notice("You fill [src] with [trans] unit\s of the solution."))
update_appearance()
target.update_appearance()
update_appearance()
target.update_appearance()
return ITEM_INTERACT_SUCCESS
/obj/item/reagent_containers/dropper/update_overlays()
. = ..()
@@ -137,15 +137,13 @@
user.visible_message(span_suicide("[user] is smothering [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
return OXYLOSS
/obj/item/reagent_containers/cup/rag/afterattack(atom/target, mob/living/user, proximity_flag, click_parameters)
if(!proximity_flag)
return
if(!iscarbon(target) || !reagents?.total_volume)
/obj/item/reagent_containers/cup/rag/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!iscarbon(interacting_with) || !reagents?.total_volume)
return ..()
var/mob/living/carbon/carbon_target = target
var/mob/living/carbon/carbon_target = interacting_with
var/reagentlist = pretty_string_from_reagent_list(reagents.reagent_list)
var/log_object = "containing [reagentlist]"
if(user.combat_mode && !carbon_target.is_mouth_covered())
if(!carbon_target.is_mouth_covered())
reagents.trans_to(carbon_target, reagents.total_volume, transferred_by = user, methods = INGEST)
carbon_target.visible_message(span_danger("[user] smothers \the [carbon_target] with \the [src]!"), span_userdanger("[user] smothers you with \the [src]!"), span_hear("You hear some struggling and muffled cries of surprise."))
log_combat(user, carbon_target, "smothered", src, log_object)
@@ -154,7 +152,12 @@
reagents.clear_reagents()
carbon_target.visible_message(span_notice("[user] touches \the [carbon_target] with \the [src]."))
log_combat(user, carbon_target, "touched", src, log_object)
return ITEM_INTERACT_SUCCESS
///Checks whether or not we should clean.
/obj/item/reagent_containers/cup/rag/proc/should_clean(datum/cleaning_source, atom/atom_to_clean, mob/living/cleaner)
return (src in cleaner)
if(cleaner.combat_mode && ismob(atom_to_clean))
return CLEAN_BLOCKED|CLEAN_DONT_BLOCK_INTERACTION
if(loc == cleaner)
return CLEAN_ALLOWED
return CLEAN_ALLOWED|CLEAN_NO_XP
@@ -59,24 +59,20 @@
return TRUE
/obj/item/reagent_containers/pill/afterattack(obj/target, mob/user , proximity)
. = ..()
if(!proximity)
return
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/reagent_containers/pill/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(!dissolvable || !target.is_refillable())
return
return NONE
if(target.is_drainable() && !target.reagents.total_volume)
to_chat(user, span_warning("[target] is empty! There's nothing to dissolve [src] in."))
return
return ITEM_INTERACT_BLOCKING
if(target.reagents.holder_full())
to_chat(user, span_warning("[target] is full."))
return
return ITEM_INTERACT_BLOCKING
user.visible_message(span_warning("[user] slips something into [target]!"), span_notice("You dissolve [src] in [target]."), null, 2)
reagents.trans_to(target, reagents.total_volume, transferred_by = user)
qdel(src)
return ITEM_INTERACT_SUCCESS
/*
* On accidental consumption, consume the pill
@@ -26,31 +26,38 @@
possible_transfer_amounts = list(5,10)
var/spray_sound = 'sound/effects/spray2.ogg'
/obj/item/reagent_containers/spray/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(istype(target, /obj/structure/sink) || istype(target, /obj/structure/mop_bucket/janitorialcart) || istype(target, /obj/machinery/hydroponics))
return
/obj/item/reagent_containers/spray/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return try_spray(interacting_with, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/reagent_containers/spray/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
// This is a hack to make spray bottles fillable from / transferable to these sources
// However it can be completely removed when these objects are updated to use the new interaction system
// (because the desired effect will just work out of the box)
if(istype(interacting_with, /obj/structure/sink) || istype(interacting_with, /obj/structure/mop_bucket/janitorialcart) || istype(interacting_with, /obj/machinery/hydroponics))
return NONE
if((target.is_drainable() && !target.is_refillable()) && (get_dist(src, target) <= 1) && can_fill_from_container)
return try_spray(interacting_with, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
/obj/item/reagent_containers/spray/proc/try_spray(atom/target, mob/user)
var/adjacent = user.Adjacent(target)
if((target.is_drainable() && !target.is_refillable()) && adjacent && can_fill_from_container)
if(!target.reagents.total_volume)
to_chat(user, span_warning("[target] is empty."))
return
return FALSE
if(reagents.holder_full())
to_chat(user, span_warning("[src] is full."))
return
return FALSE
var/trans = target.reagents.trans_to(src, 50, transferred_by = user) //transfer 50u , using the spray's transfer amount would take too long to refill
to_chat(user, span_notice("You fill \the [src] with [trans] units of the contents of \the [target]."))
return
return FALSE
if(reagents.total_volume < amount_per_transfer_from_this)
to_chat(user, span_warning("Not enough left!"))
return
return FALSE
if(proximity_flag && (target.density || ismob(target)))
if(adjacent && (target.density || ismob(target)))
// If we're spraying an adjacent mob or a dense object, we start the spray on ITS tile rather than OURs
// This is so we can use a spray bottle to clean stuff like windows without getting blocked by passflags
spray(target, user, get_turf(target))
@@ -58,9 +65,9 @@
spray(target, user)
playsound(src, spray_sound, 50, TRUE, -6)
user.changeNext_move(CLICK_CD_RANGE*2)
user.changeNext_move(CLICK_CD_RANGE * 2)
user.newtonian_move(get_dir(target, user))
return
return TRUE
/// Handles creating a chem puff that travels towards the target atom, exposing reagents to everything it hits on the way.
/obj/item/reagent_containers/spray/proc/spray(atom/target, mob/user, turf/start_turf = get_turf(src))
@@ -232,10 +239,10 @@
return OXYLOSS
// Fix pepperspraying yourself
/obj/item/reagent_containers/spray/pepper/afterattack(atom/A as mob|obj, mob/user)
if (A.loc == user)
return
return ..() | AFTERATTACK_PROCESSED_ITEM
/obj/item/reagent_containers/spray/pepper/try_spray(atom/target, mob/user)
if (target.loc == user)
return FALSE
return ..()
//water flower
/obj/item/reagent_containers/spray/waterflower
@@ -320,11 +327,10 @@
amount_per_transfer_from_this = 10
volume = 600
/obj/item/reagent_containers/spray/chemsprayer/afterattack(atom/A as mob|obj, mob/user)
// Make it so the bioterror spray doesn't spray yourself when you click your inventory items
if (A.loc == user)
return
return ..() | AFTERATTACK_PROCESSED_ITEM
/obj/item/reagent_containers/spray/chemsprayer/try_spray(atom/target, mob/user)
if (target.loc == user)
return FALSE
return ..()
/obj/item/reagent_containers/spray/chemsprayer/spray(atom/A, mob/user)
var/direction = get_dir(src, A)
@@ -25,9 +25,7 @@
/obj/item/reagent_containers/syringe/attackby(obj/item/I, mob/user, params)
return
/obj/item/reagent_containers/syringe/proc/try_syringe(atom/target, mob/user, proximity)
if(!proximity)
return FALSE
/obj/item/reagent_containers/syringe/proc/try_syringe(atom/target, mob/user)
if(!target.reagents)
return FALSE
@@ -36,49 +34,50 @@
if(!living_target.try_inject(user, injection_flags = INJECT_TRY_SHOW_ERROR_MESSAGE|inject_flags))
return FALSE
// chance of monkey retaliation
SEND_SIGNAL(target, COMSIG_LIVING_TRY_SYRINGE, user)
return TRUE
/obj/item/reagent_containers/syringe/afterattack(atom/target, mob/user, proximity)
. = ..()
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/reagent_containers/syringe/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(!target.reagents)
return NONE
if(!try_syringe(target, user))
return ITEM_INTERACT_BLOCKING
if (!try_syringe(target, user, proximity))
return
SEND_SIGNAL(target, COMSIG_LIVING_TRY_SYRINGE_INJECT, user)
var/contained = reagents.get_reagent_log_string()
log_combat(user, target, "attempted to inject", src, addition="which had [contained]")
if(!reagents.total_volume)
to_chat(user, span_warning("[src] is empty! Right-click to draw."))
return
return ITEM_INTERACT_BLOCKING
if(!isliving(target) && !target.is_injectable(user))
to_chat(user, span_warning("You cannot directly fill [target]!"))
return
return ITEM_INTERACT_BLOCKING
if(target.reagents.total_volume >= target.reagents.maximum_volume)
to_chat(user, span_notice("[target] is full."))
return
return ITEM_INTERACT_BLOCKING
if(isliving(target))
var/mob/living/living_target = target
if(!living_target.try_inject(user, injection_flags = INJECT_TRY_SHOW_ERROR_MESSAGE|inject_flags))
return
if(living_target != user)
living_target.visible_message(span_danger("[user] is trying to inject [living_target]!"), \
span_userdanger("[user] is trying to inject you!"))
if(!do_after(user, CHEM_INTERACT_DELAY(3 SECONDS, user), living_target, extra_checks = CALLBACK(living_target, TYPE_PROC_REF(/mob/living, try_inject), user, null, INJECT_TRY_SHOW_ERROR_MESSAGE|inject_flags)))
return
living_target.visible_message(
span_danger("[user] is trying to inject [living_target]!"),
span_userdanger("[user] is trying to inject you!"),
)
if(!do_after(user, CHEM_INTERACT_DELAY(3 SECONDS, user), living_target, extra_checks = CALLBACK(src, PROC_REF(try_syringe), living_target, user)))
return ITEM_INTERACT_BLOCKING
if(!reagents.total_volume)
return
return ITEM_INTERACT_BLOCKING
if(living_target.reagents.total_volume >= living_target.reagents.maximum_volume)
return
living_target.visible_message(span_danger("[user] injects [living_target] with the syringe!"), \
span_userdanger("[user] injects you with the syringe!"))
return ITEM_INTERACT_BLOCKING
living_target.visible_message(
span_danger("[user] injects [living_target] with the syringe!"),
span_userdanger("[user] injects you with the syringe!"),
)
if (living_target == user)
if(living_target == user)
living_target.log_message("injected themselves ([contained]) with [name]", LOG_ATTACK, color="orange")
else
log_combat(user, living_target, "injected", src, addition="which had [contained]")
@@ -86,44 +85,53 @@
if(reagents.trans_to(target, amount_per_transfer_from_this, transferred_by = user, methods = INJECT))
to_chat(user, span_notice("You inject [amount_per_transfer_from_this] units of the solution. The syringe now contains [reagents.total_volume] units."))
target.update_appearance()
return ITEM_INTERACT_SUCCESS
/obj/item/reagent_containers/syringe/afterattack_secondary(atom/target, mob/user, proximity_flag, click_parameters)
if (!try_syringe(target, user, proximity_flag))
return SECONDARY_ATTACK_CONTINUE_CHAIN
return ITEM_INTERACT_BLOCKING
/obj/item/reagent_containers/syringe/interact_with_atom_secondary(atom/target, mob/living/user, list/modifiers)
if (!target.reagents)
return NONE
if (!try_syringe(target, user))
return ITEM_INTERACT_BLOCKING
SEND_SIGNAL(target, COMSIG_LIVING_TRY_SYRINGE_WITHDRAW, user)
if(reagents.total_volume >= reagents.maximum_volume)
to_chat(user, span_notice("[src] is full."))
return SECONDARY_ATTACK_CONTINUE_CHAIN
return ITEM_INTERACT_BLOCKING
if(isliving(target))
var/mob/living/living_target = target
var/drawn_amount = reagents.maximum_volume - reagents.total_volume
if(target != user)
target.visible_message(span_danger("[user] is trying to take a blood sample from [target]!"), \
span_userdanger("[user] is trying to take a blood sample from you!"))
if(!do_after(user, CHEM_INTERACT_DELAY(3 SECONDS, user), target, extra_checks = CALLBACK(living_target, TYPE_PROC_REF(/mob/living, try_inject), user, null, INJECT_TRY_SHOW_ERROR_MESSAGE|inject_flags)))
return SECONDARY_ATTACK_CONTINUE_CHAIN
target.visible_message(
span_danger("[user] is trying to take a blood sample from [target]!"),
span_userdanger("[user] is trying to take a blood sample from you!"),
)
if(!do_after(user, CHEM_INTERACT_DELAY(3 SECONDS, user), target, extra_checks = CALLBACK(src, PROC_REF(try_syringe), living_target, user)))
return ITEM_INTERACT_BLOCKING
if(reagents.total_volume >= reagents.maximum_volume)
return SECONDARY_ATTACK_CONTINUE_CHAIN
return ITEM_INTERACT_BLOCKING
if(living_target.transfer_blood_to(src, drawn_amount))
user.visible_message(span_notice("[user] takes a blood sample from [living_target]."))
else
to_chat(user, span_warning("You are unable to draw any blood from [living_target]!"))
else
if(!target.reagents.total_volume)
to_chat(user, span_warning("[target] is empty!"))
return SECONDARY_ATTACK_CONTINUE_CHAIN
return ITEM_INTERACT_SUCCESS
if(!target.is_drawable(user))
to_chat(user, span_warning("You cannot directly remove reagents from [target]!"))
return SECONDARY_ATTACK_CONTINUE_CHAIN
if(!target.reagents.total_volume)
to_chat(user, span_warning("[target] is empty!"))
return ITEM_INTERACT_BLOCKING
var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, transferred_by = user) // transfer from, transfer to - who cares?
if(!target.is_drawable(user))
to_chat(user, span_warning("You cannot directly remove reagents from [target]!"))
return ITEM_INTERACT_BLOCKING
to_chat(user, span_notice("You fill [src] with [trans] units of the solution. It now contains [reagents.total_volume] units."))
target.update_appearance()
var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, transferred_by = user) // transfer from, transfer to - who cares?
return SECONDARY_ATTACK_CONTINUE_CHAIN
to_chat(user, span_notice("You fill [src] with [trans] units of the solution. It now contains [reagents.total_volume] units."))
target.update_appearance()
return ITEM_INTERACT_SUCCESS
/*
* On accidental consumption, inject the eater with 2/3rd of the syringe and reveal it
+14 -14
View File
@@ -543,10 +543,9 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
belt.id = id
to_chat(user, span_notice("You have linked all nearby conveyor belt assemblies to this switch."))
/obj/item/conveyor_switch_construct/afterattack(atom/target, mob/user, proximity)
. = ..()
if(!proximity || user.stat || !isfloorturf(target) || istype(target, /area/shuttle))
return
/obj/item/conveyor_switch_construct/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!isfloorturf(interacting_with))
return NONE
var/found = FALSE
for(var/obj/machinery/conveyor/belt in view())
@@ -555,10 +554,11 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
break
if(!found)
to_chat(user, "[icon2html(src, user)]" + span_notice("The conveyor switch did not detect any linked conveyor belts in range."))
return
var/obj/machinery/conveyor_switch/built_switch = new/obj/machinery/conveyor_switch(target, id)
return ITEM_INTERACT_BLOCKING
var/obj/machinery/conveyor_switch/built_switch = new/obj/machinery/conveyor_switch(interacting_with, id)
transfer_fingerprints_to(built_switch)
qdel(src)
return ITEM_INTERACT_SUCCESS
/obj/item/stack/conveyor
name = "conveyor belt assembly"
@@ -576,17 +576,17 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
. = ..()
id = _id
/obj/item/stack/conveyor/afterattack(atom/target, mob/user, proximity)
. = ..()
if(!proximity || user.stat || !isfloorturf(target) || istype(target, /area/shuttle))
return
var/belt_dir = get_dir(target, user)
if(target == user.loc)
/obj/item/stack/conveyor/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!isfloorturf(interacting_with))
return NONE
var/belt_dir = get_dir(interacting_with, user)
if(interacting_with == user.loc)
to_chat(user, span_warning("You cannot place a conveyor belt under yourself!"))
return
var/obj/machinery/conveyor/belt = new/obj/machinery/conveyor(target, belt_dir, id)
return ITEM_INTERACT_BLOCKING
var/obj/machinery/conveyor/belt = new/obj/machinery/conveyor(interacting_with, belt_dir, id)
transfer_fingerprints_to(belt)
use(1)
return ITEM_INTERACT_SUCCESS
/obj/item/stack/conveyor/attackby(obj/item/item_used, mob/user, params)
..()
+1 -1
View File
@@ -252,7 +252,7 @@
unwrap_contents()
post_unwrap_contents(user)
return COMPONENT_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
/obj/item/dest_tagger
name = "destination tagger"
+17 -12
View File
@@ -37,19 +37,24 @@ If you create T5+ please take a pass at mech_fabricator.dm. The parts being good
user.Beam(attacked_machinery, icon_state = "rped_upgrade", time = 0.5 SECONDS)
return TRUE
/obj/item/storage/part_replacer/afterattack(obj/attacked_object, mob/living/user, adjacent, params)
. = ..()
if(!works_from_distance || adjacent) // Adjacent things = already handled by pre-attack
return .
/obj/item/storage/part_replacer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(part_replace_action(interacting_with, user))
return ITEM_INTERACT_SUCCESS
return NONE
if(part_replace_action(attacked_object, user))
user.Beam(attacked_object, icon_state = "rped_upgrade", time = 0.5 SECONDS)
return . | AFTERATTACK_PROCESSED_ITEM
if(istype(attacked_object, /obj/structure/frame))
attacked_object.item_interaction(user, src) // Cursed snowflake but we need to handle frame ranged interaction here
user.Beam(attacked_object, icon_state = "rped_upgrade", time = 0.5 SECONDS)
return . | AFTERATTACK_PROCESSED_ITEM
/obj/item/storage/part_replacer/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!works_from_distance)
return NONE
if(part_replace_action(interacting_with, user))
user.Beam(interacting_with, icon_state = "rped_upgrade", time = 0.5 SECONDS)
return ITEM_INTERACT_SUCCESS
if(istype(interacting_with, /obj/structure/frame))
// Cursed snowflake but we need to handle frame ranged interaction here
// Likely no longer necessary with the new framework, revisit later
interacting_with.item_interaction(user, src)
user.Beam(interacting_with, icon_state = "rped_upgrade", time = 0.5 SECONDS)
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/storage/part_replacer/proc/play_rped_sound()
//Plays the sound for RPED exhanging or installing parts.
@@ -52,11 +52,10 @@ Slimecrossing Items
ret[part.body_zone] = saved_part
return ret
/obj/item/camera/rewind/afterattack(atom/target, mob/user, flag)
. |= AFTERATTACK_PROCESSED_ITEM
if(!on || !pictures_left || !isturf(target.loc))
return .
/obj/item/camera/rewind/photo_taken(atom/target, mob/user)
. = ..()
if(!.)
return
if(user == target)
to_chat(user, span_notice("You take a selfie!"))
@@ -66,9 +65,6 @@ Slimecrossing Items
to_chat(target, span_boldnotice("You'll remember this moment forever!"))
target.AddComponent(/datum/component/dejavu, 2)
return . | ..()
//Timefreeze camera - Old Burning Sepia result. Kept in case admins want to spawn it
/obj/item/camera/timefreeze
@@ -77,13 +73,11 @@ Slimecrossing Items
pictures_left = 1
pictures_max = 1
/obj/item/camera/timefreeze/afterattack(atom/target, mob/user, flag)
. |= AFTERATTACK_PROCESSED_ITEM
if(!on || !pictures_left || !isturf(target.loc))
return .
/obj/item/camera/timefreeze/photo_taken(atom/target, mob/user)
. = ..()
if(!.)
return
new /obj/effect/timestop(get_turf(target), 2, 50, list(user))
return . | ..()
//Hypercharged slime cell - Charged Yellow
/obj/item/stock_parts/cell/high/slime_hypercharged
@@ -11,27 +11,25 @@ Slimecrossing Potions
icon = 'icons/obj/medical/chemical.dmi'
icon_state = "potpurple"
/obj/item/slimepotion/extract_cloner/afterattack(obj/item/target, mob/user , proximity)
if(!proximity)
return
. |= AFTERATTACK_PROCESSED_ITEM
if(is_reagent_container(target))
return ..(target, user, proximity)
if(istype(target, /obj/item/slimecross))
to_chat(user, span_warning("[target] is too complex for the potion to clone!"))
return
if(!istype(target, /obj/item/slime_extract))
return
var/obj/item/slime_extract/S = target
/obj/item/slimepotion/extract_cloner/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
. = ..()
if(. & ITEM_INTERACT_ANY_BLOCKER)
return .
if(istype(interacting_with, /obj/item/slimecross))
to_chat(user, span_warning("[interacting_with] is too complex for the potion to clone!"))
return ITEM_INTERACT_BLOCKING
if(!istype(interacting_with, /obj/item/slime_extract))
return ITEM_INTERACT_BLOCKING
var/obj/item/slime_extract/S = interacting_with
if(S.recurring)
to_chat(user, span_warning("[target] is too complex for the potion to clone!"))
return
to_chat(user, span_warning("[interacting_with] is too complex for the potion to clone!"))
return ITEM_INTERACT_BLOCKING
var/path = S.type
var/obj/item/slime_extract/C = new path(get_turf(target))
var/obj/item/slime_extract/C = new path(get_turf(interacting_with))
C.extract_uses = S.extract_uses
to_chat(user, span_notice("You pour the potion onto [target], and the fluid solidifies into a copy of it!"))
to_chat(user, span_notice("You pour the potion onto [interacting_with], and the fluid solidifies into a copy of it!"))
qdel(src)
return
return ITEM_INTERACT_SUCCESS
//Peace potion - Charged Light Pink
/obj/item/slimepotion/peacepotion
@@ -107,34 +105,34 @@ Slimecrossing Potions
icon_state = "potblue"
var/uses = 2
/obj/item/slimepotion/spaceproof/afterattack(obj/item/clothing/C, mob/user, proximity)
/obj/item/slimepotion/spaceproof/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
. = ..()
if(!uses)
if(. & ITEM_INTERACT_ANY_BLOCKER)
return .
if(uses <= 0)
qdel(src)
return
if(!proximity)
return
if(!istype(C))
return ITEM_INTERACT_BLOCKING
var/obj/item/clothing/clothing = interacting_with
if(!istype(clothing))
to_chat(user, span_warning("The potion can only be used on clothing!"))
return
. |= AFTERATTACK_PROCESSED_ITEM
if(istype(C, /obj/item/clothing/suit/space))
to_chat(user, span_warning("The [C] is already pressure-resistant!"))
return . | ..()
if(C.min_cold_protection_temperature == SPACE_SUIT_MIN_TEMP_PROTECT && C.clothing_flags & STOPSPRESSUREDAMAGE)
to_chat(user, span_warning("The [C] is already pressure-resistant!"))
return . | ..()
to_chat(user, span_notice("You slather the blue gunk over the [C], making it airtight."))
C.name = "pressure-resistant [C.name]"
C.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
C.add_atom_colour(COLOR_NAVY, FIXED_COLOUR_PRIORITY)
C.min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
C.cold_protection = C.body_parts_covered
C.clothing_flags |= STOPSPRESSUREDAMAGE
return ITEM_INTERACT_BLOCKING
if(istype(clothing, /obj/item/clothing/suit/space))
to_chat(user, span_warning("The [interacting_with] is already pressure-resistant!"))
return ITEM_INTERACT_BLOCKING
if(clothing.min_cold_protection_temperature == SPACE_SUIT_MIN_TEMP_PROTECT && (clothing.clothing_flags & STOPSPRESSUREDAMAGE))
to_chat(user, span_warning("The [interacting_with] is already pressure-resistant!"))
return ITEM_INTERACT_BLOCKING
to_chat(user, span_notice("You slather the blue gunk over the [clothing], making it airtight."))
clothing.name = "pressure-resistant [clothing.name]"
clothing.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
clothing.add_atom_colour(COLOR_NAVY, FIXED_COLOUR_PRIORITY)
clothing.min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
clothing.cold_protection = clothing.body_parts_covered
clothing.clothing_flags |= STOPSPRESSUREDAMAGE
uses--
if(!uses)
if(uses <= 0)
qdel(src)
return .
return ITEM_INTERACT_SUCCESS
//Enhancer potion - Charged Cerulean
/obj/item/slimepotion/enhancer/max
@@ -152,29 +150,30 @@ Slimecrossing Potions
resistance_flags = LAVA_PROOF | FIRE_PROOF
var/uses = 2
/obj/item/slimepotion/lavaproof/afterattack(obj/item/C, mob/user, proximity)
/obj/item/slimepotion/lavaproof/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
. = ..()
if(!uses)
if(. & ITEM_INTERACT_ANY_BLOCKER)
return .
if(uses <= 0)
qdel(src)
return ..()
if(!proximity)
return ..()
if(!istype(C))
return ITEM_INTERACT_BLOCKING
if(!isitem(interacting_with))
to_chat(user, span_warning("You can't coat this with lavaproofing fluid!"))
return ..()
. |= AFTERATTACK_PROCESSED_ITEM
to_chat(user, span_notice("You slather the red gunk over the [C], making it lavaproof."))
C.name = "lavaproof [C.name]"
C.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
C.add_atom_colour(COLOR_MAROON, FIXED_COLOUR_PRIORITY)
C.resistance_flags |= LAVA_PROOF
if (isclothing(C))
var/obj/item/clothing/CL = C
CL.clothing_flags |= LAVAPROTECT
return ITEM_INTERACT_BLOCKING
var/obj/item/clothing = interacting_with
to_chat(user, span_notice("You slather the red gunk over the [clothing], making it lavaproof."))
clothing.name = "lavaproof [clothing.name]"
clothing.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
clothing.add_atom_colour(COLOR_MAROON, FIXED_COLOUR_PRIORITY)
clothing.resistance_flags |= LAVA_PROOF
if (isclothing(clothing))
var/obj/item/clothing/clothing_real = clothing
clothing_real.clothing_flags |= LAVAPROTECT
uses--
if(!uses)
if(uses <= 0)
qdel(src)
return .
return ITEM_INTERACT_SUCCESS
//Revival potion - Charged Grey
/obj/item/slimepotion/slime_reviver
@@ -183,15 +182,21 @@ Slimecrossing Potions
icon = 'icons/obj/medical/chemical.dmi'
icon_state = "potsilver"
/obj/item/slimepotion/slime_reviver/attack(mob/living/basic/slime/revive_target, mob/user)
/obj/item/slimepotion/slime_reviver/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
. = ..()
if(. & ITEM_INTERACT_ANY_BLOCKER)
return .
var/mob/living/basic/slime/revive_target = interacting_with
if(!isslime(revive_target))
to_chat(user, span_warning("The potion only works on slimes!"))
return ..()
return ITEM_INTERACT_BLOCKING
if(revive_target.stat != DEAD)
to_chat(user, span_warning("The slime is still alive!"))
return
return ITEM_INTERACT_BLOCKING
if(revive_target.maxHealth <= 0)
to_chat(user, span_warning("The slime is too unstable to return!"))
return ITEM_INTERACT_BLOCKING
user.do_attack_animation(interacting_with)
revive_target.revive(HEAL_ALL)
revive_target.set_stat(CONSCIOUS)
revive_target.visible_message(span_notice("[revive_target] is filled with renewed vigor and blinks awake!"))
@@ -199,6 +204,7 @@ Slimecrossing Potions
revive_target.health -= 10
revive_target.regenerate_icons()
qdel(src)
return ITEM_INTERACT_SUCCESS
//Stabilizer potion - Charged Blue
/obj/item/slimepotion/slime/chargedstabilizer
@@ -1079,7 +1079,7 @@
var/obj/item/slimecross/stabilized/rainbow/X = linked_extract
if(istype(X))
if(X.regencore)
X.regencore.afterattack(owner,owner,TRUE)
X.regencore.interact_with_atom(owner, owner)
X.regencore = null
owner.visible_message(span_warning("[owner] flashes a rainbow of colors, and [owner.p_their()] skin is coated in a milky regenerative goo!"))
qdel(src)
@@ -27,8 +27,8 @@ Slimecrossing Weapons
throwforce = 15
damtype = BRUTE
/obj/item/knife/rainbowknife/afterattack(atom/O, mob/user, proximity)
if(proximity && isliving(O))
/obj/item/knife/rainbowknife/afterattack(atom/target, mob/user, params)
if(isliving(target))
damtype = pick(BRUTE, BURN, TOX, OXY)
switch(damtype)
if(BRUTE)
@@ -47,7 +47,6 @@ Slimecrossing Weapons
hitsound = 'sound/effects/space_wind.ogg'
attack_verb_continuous = string_list(list("suffocates", "winds", "vacuums"))
attack_verb_simple = string_list(list("suffocate", "wind", "vacuum"))
return ..()
//Adamantine shield - Chilling Adamantine
/obj/item/shield/adamantineshield
@@ -151,19 +151,20 @@ Chilling extracts:
var/list/allies = list()
var/active = FALSE
/obj/item/slimecross/chilling/bluespace/afterattack(atom/target, mob/user, proximity)
if(!proximity || !isliving(target) || active)
return
if(HAS_TRAIT(target, TRAIT_NO_TELEPORT))
to_chat(user, span_warning("[target] resists being linked with [src]!"))
return
if(target in allies)
allies -= target
to_chat(user, span_notice("You unlink [src] with [target]."))
/obj/item/slimecross/chilling/bluespace/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!isliving(interacting_with) || active)
return NONE
user.do_attack_animation(interacting_with)
if(HAS_TRAIT(interacting_with, TRAIT_NO_TELEPORT))
to_chat(user, span_warning("[interacting_with] resists being linked with [src]!"))
return ITEM_INTERACT_BLOCKING
if(interacting_with in allies)
allies -= interacting_with
to_chat(user, span_notice("You unlink [src] with [interacting_with]."))
else
allies |= target
to_chat(user, span_notice("You link [src] with [target]."))
return
allies += interacting_with
to_chat(user, span_notice("You link [src] with [interacting_with]."))
return ITEM_INTERACT_SUCCESS
/obj/item/slimecross/chilling/bluespace/do_effect(mob/user)
if(allies.len <= 0)
@@ -193,16 +194,17 @@ Chilling extracts:
effect_desc = "Touching someone with it adds/removes them from a list. Activating the extract stops time for 30 seconds, and everyone on the list is immune, except the user."
var/list/allies = list()
/obj/item/slimecross/chilling/sepia/afterattack(atom/target, mob/user, proximity)
if(!proximity || !isliving(target))
return
if(target in allies)
allies -= target
to_chat(user, span_notice("You unlink [src] with [target]."))
/obj/item/slimecross/chilling/sepia/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!isliving(interacting_with))
return NONE
user.do_attack_animation(interacting_with)
if(interacting_with in allies)
allies -= interacting_with
to_chat(user, span_notice("You unlink [src] with [interacting_with]."))
else
allies |= target
to_chat(user, span_notice("You link [src] with [target]."))
return
allies += interacting_with
to_chat(user, span_notice("You link [src] with [interacting_with]."))
return ITEM_INTERACT_SUCCESS
/obj/item/slimecross/chilling/sepia/do_effect(mob/user)
user.visible_message(span_warning("[src] shatters, freezing time itself!"))
@@ -10,25 +10,25 @@ Prismatic extracts:
icon_state = "prismatic"
var/paintcolor = COLOR_WHITE
/obj/item/slimecross/prismatic/afterattack(turf/target, mob/user, proximity)
if(!proximity)
return
if(!istype(target) || isspaceturf(target))
return
target.add_atom_colour(paintcolor, WASHABLE_COLOUR_PRIORITY)
playsound(target, 'sound/effects/slosh.ogg', 20, TRUE)
/obj/item/slimecross/prismatic/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!isturf(interacting_with) || isspaceturf(interacting_with))
return NONE
user.do_attack_animation(interacting_with)
interacting_with.add_atom_colour(paintcolor, WASHABLE_COLOUR_PRIORITY)
playsound(interacting_with, 'sound/effects/slosh.ogg', 20, TRUE)
return ITEM_INTERACT_SUCCESS
/obj/item/slimecross/prismatic/grey/
/obj/item/slimecross/prismatic/grey
colour = SLIME_TYPE_GREY
desc = "It's constantly wet with a pungent-smelling, clear chemical."
/obj/item/slimecross/prismatic/grey/afterattack(turf/target, mob/user, proximity)
. = ..()
if(!proximity)
return
if(istype(target) && target.color != initial(target.color))
target.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
playsound(target, 'sound/effects/slosh.ogg', 20, TRUE)
/obj/item/slimecross/prismatic/grey/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(isturf(interacting_with) && interacting_with.color != initial(interacting_with.color))
user.do_attack_animation(interacting_with)
interacting_with.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
playsound(interacting_with, 'sound/effects/slosh.ogg', 20, TRUE)
return ITEM_INTERACT_SUCCESS
return ..()
/obj/item/slimecross/prismatic/orange
paintcolor = "#FFA500"
@@ -14,14 +14,13 @@ Regenerative extracts:
/obj/item/slimecross/regenerative/proc/core_effect_before(mob/living/carbon/human/target, mob/user)
return
/obj/item/slimecross/regenerative/afterattack(atom/target,mob/user,prox)
. = ..()
if(!prox || !isliving(target))
/obj/item/slimecross/regenerative/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!isliving(interacting_with))
return
var/mob/living/H = target
var/mob/living/H = interacting_with
if(H.stat == DEAD)
to_chat(user, span_warning("[src] will not work on the dead!"))
return
return ITEM_INTERACT_BLOCKING
if(H != user)
user.visible_message(span_notice("[user] crushes [src] over [H], the milky goo quickly regenerating all of [H.p_their()] injuries!"),
span_notice("You squeeze [src], and it bursts over [H], the milky goo regenerating [H.p_their()] injuries."))
@@ -29,10 +28,12 @@ Regenerative extracts:
user.visible_message(span_notice("[user] crushes [src] over [user.p_them()]self, the milky goo quickly regenerating all of [user.p_their()] injuries!"),
span_notice("You squeeze [src], and it bursts in your hand, splashing you with milky goo which quickly regenerates your injuries!"))
core_effect_before(H, user)
user.do_attack_animation(interacting_with)
H.revive(HEAL_ALL)
core_effect(H, user)
playsound(target, 'sound/effects/splat.ogg', 40, TRUE)
playsound(H, 'sound/effects/splat.ogg', 40, TRUE)
qdel(src)
return ITEM_INTERACT_SUCCESS
/obj/item/slimecross/regenerative/grey
colour = SLIME_TYPE_GREY //Has no bonus effect.
@@ -644,13 +644,12 @@
desc = "A hard yet gelatinous capsule excreted by a slime, containing mysterious substances."
w_class = WEIGHT_CLASS_TINY
/obj/item/slimepotion/afterattack(obj/item/reagent_containers/target, mob/user , proximity)
. = ..()
if(!proximity)
return
if (istype(target))
to_chat(user, span_warning("You cannot transfer [src] to [target]! It appears the potion must be given directly to a slime to absorb.") )
return
/obj/item/slimepotion/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(is_reagent_container(interacting_with))
to_chat(user, span_warning("You cannot transfer [src] to [interacting_with]! \
It appears the potion must be given directly to a slime to absorb.") )
return ITEM_INTERACT_BLOCKING
return NONE
/obj/item/slimepotion/slime/docility
name = "docility potion"
@@ -778,33 +777,36 @@
var/prompted = 0
var/animal_type = SENTIENCE_ORGANIC
/obj/item/slimepotion/transference/afterattack(mob/living/switchy_mob, mob/living/user, proximity)
if(!proximity)
return
/obj/item/slimepotion/transference/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
. = ..()
if(. & ITEM_INTERACT_ANY_BLOCKER)
return .
var/mob/living/switchy_mob = interacting_with
if(prompted || !isliving(switchy_mob))
return
return ITEM_INTERACT_BLOCKING
if(switchy_mob.ckey) //much like sentience, these will not work on something that is already player controlled
balloon_alert(user, "already sentient!")
return ..()
return ITEM_INTERACT_BLOCKING
if(switchy_mob.stat)
balloon_alert(user, "it's dead!")
return ..()
return ITEM_INTERACT_BLOCKING
if(!switchy_mob.compare_sentience_type(animal_type))
balloon_alert(user, "invalid creature!")
return ..()
return ITEM_INTERACT_BLOCKING
var/job_banned = is_banned_from(user.ckey, ROLE_MIND_TRANSFER)
if(QDELETED(src) || QDELETED(switchy_mob) || QDELETED(user))
return
return ITEM_INTERACT_BLOCKING
if(job_banned)
balloon_alert(user, "you're banned!")
return
return ITEM_INTERACT_BLOCKING
user.do_attack_animation(interacting_with)
prompted = 1
if(tgui_alert(usr,"This will permanently transfer your consciousness to [switchy_mob]. Are you sure you want to do this?",,list("Yes","No")) == "No")
prompted = 0
return
return ITEM_INTERACT_BLOCKING
to_chat(user, span_notice("You drink the potion then place your hands on [switchy_mob]..."))
@@ -820,6 +822,7 @@
if(isanimal(switchy_mob))
var/mob/living/simple_animal/switchy_animal= switchy_mob
switchy_animal.sentience_act()
return ITEM_INTERACT_SUCCESS
/obj/item/slimepotion/slime/steroid
name = "slime steroid"
@@ -903,29 +906,29 @@
icon = 'icons/obj/medical/chemical.dmi'
icon_state = "potyellow"
/obj/item/slimepotion/speed/afterattack(obj/C, mob/user, proximity)
/obj/item/slimepotion/speed/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
. = ..()
if(!proximity)
return
if(!istype(C))
if(. & ITEM_INTERACT_ANY_BLOCKER)
return .
if(!isobj(interacting_with))
to_chat(user, span_warning("The potion can only be used on objects!"))
return
. |= AFTERATTACK_PROCESSED_ITEM
if(SEND_SIGNAL(C, COMSIG_SPEED_POTION_APPLIED, src, user) & SPEED_POTION_STOP)
return
if(isitem(C))
var/obj/item/I = C
if(I.slowdown <= 0 || (I.item_flags & IMMUTABLE_SLOW))
to_chat(user, span_warning("The [C] can't be made any faster!"))
return ..()
I.slowdown = 0
return ITEM_INTERACT_BLOCKING
if(SEND_SIGNAL(interacting_with, COMSIG_SPEED_POTION_APPLIED, src, user) & SPEED_POTION_STOP)
return ITEM_INTERACT_SUCCESS
if(isitem(interacting_with))
var/obj/item/apply_to = interacting_with
if(apply_to.slowdown <= 0 || (apply_to.item_flags & IMMUTABLE_SLOW))
to_chat(user, span_warning("The [apply_to] can't be made any faster!"))
return ITEM_INTERACT_BLOCKING
apply_to.slowdown = 0
to_chat(user, span_notice("You slather the red gunk over the [C], making it faster."))
C.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
C.add_atom_colour(COLOR_RED, FIXED_COLOUR_PRIORITY)
to_chat(user, span_notice("You slather the red gunk over the [interacting_with], making it faster."))
interacting_with.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
interacting_with.add_atom_colour(COLOR_RED, FIXED_COLOUR_PRIORITY)
qdel(src)
return ITEM_INTERACT_SUCCESS
/obj/item/slimepotion/speed/attackby_storage_insert(datum/storage, atom/storage_holder, mob/user)
/obj/item/slimepotion/speed/storage_insert_on_interaction(datum/storage, atom/storage_holder, mob/user)
if(!isitem(storage_holder))
return TRUE
if(istype(storage_holder, /obj/item/mod/control))
@@ -942,20 +945,20 @@
resistance_flags = FIRE_PROOF
var/uses = 3
/obj/item/slimepotion/fireproof/afterattack(obj/item/clothing/clothing, mob/user, proximity)
/obj/item/slimepotion/fireproof/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
. = ..()
if(!proximity)
return
if(!uses)
if(. & ITEM_INTERACT_ANY_BLOCKER)
return .
if(uses <= 0)
qdel(src)
return
. |= AFTERATTACK_PROCESSED_ITEM
return ITEM_INTERACT_BLOCKING
var/obj/item/clothing/clothing = interacting_with
if(!istype(clothing))
to_chat(user, span_warning("The potion can only be used on clothing!"))
return
return ITEM_INTERACT_BLOCKING
if(clothing.max_heat_protection_temperature >= FIRE_IMMUNITY_MAX_TEMP_PROTECT)
to_chat(user, span_warning("The [clothing] is already fireproof!"))
return
return ITEM_INTERACT_BLOCKING
to_chat(user, span_notice("You slather the blue gunk over the [clothing], fireproofing it."))
clothing.name = "fireproofed [clothing.name]"
clothing.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
@@ -964,8 +967,9 @@
clothing.heat_protection = clothing.body_parts_covered
clothing.resistance_flags |= FIRE_PROOF
uses --
if(!uses)
if(uses <= 0)
qdel(src)
return ITEM_INTERACT_BLOCKING
/obj/item/slimepotion/genderchange
name = "gender change potion"
@@ -1080,4 +1084,3 @@
max_amount = 60
turf_type = /turf/open/floor/sepia
merge_type = /obj/item/stack/tile/sepia
+2 -8
View File
@@ -797,14 +797,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/item/storage/pod, 32)
new /obj/item/bodybag/environmental(src)
new /obj/item/bodybag/environmental(src)
/obj/item/storage/pod/attackby(obj/item/W, mob/user, params)
if (can_interact(user))
return ..()
/obj/item/storage/pod/attackby_secondary(obj/item/weapon, mob/user, params)
if (!can_interact(user))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ..()
/obj/item/storage/pod/storage_insert_on_interacted_with(datum/storage, obj/item/inserted, mob/living/user)
return can_interact(user)
/obj/item/storage/pod/attack_hand(mob/user, list/modifiers)
if (can_interact(user))
@@ -58,7 +58,7 @@
RegisterSignal(enchanted, COMSIG_ITEM_DROPPED, PROC_REF(on_dropped))
/// signal called from attacking with the enchanted item
/datum/action/cooldown/spell/sanguine_strike/proc/on_enchanted_afterattack(obj/item/enchanted, atom/target, mob/user, proximity_flag, click_parameters)
/datum/action/cooldown/spell/sanguine_strike/proc/on_enchanted_afterattack(obj/item/enchanted, atom/target, mob/user, click_parameters)
SIGNAL_HANDLER
end_enchantment(enchanted)
if(!isliving(target))

Some files were not shown because too many files have changed in this diff Show More