mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-12 23:54:24 +01:00
0c295af6e7
* Some more rad fixes * Minor fix * fixes vox ghost goggles
187 lines
6.2 KiB
Plaintext
187 lines
6.2 KiB
Plaintext
/obj/item/ghost_catcher
|
|
name = "proton rifle"
|
|
desc = "A two handed device, used for 'catching ghosts'. Weakens the entity initially grabbed."
|
|
icon = 'icons/obj/guns/ghost_beam.dmi'
|
|
icon_state = "ghost_beam"
|
|
w_class = ITEMSIZE_NORMAL
|
|
force = 0
|
|
slot_flags = SLOT_BELT
|
|
var/grab_range = 5 // How many tiles away it can grab. Changing this also changes the box size.
|
|
/// Stops multiple grabbs if set to TRUE
|
|
var/busy = FALSE
|
|
/// The entity we are currently grabbing.
|
|
var/datum/weakref/grabbed_entity
|
|
/// How far we can move an entity in one go!
|
|
var/max_move_distance = 1
|
|
/// If we're held in two hands or not...Used until we get two handed component.
|
|
var/wielded = FALSE
|
|
|
|
COOLDOWN_DECLARE(ghost_cooldown)
|
|
COOLDOWN_DECLARE(click_cooldown)
|
|
|
|
//TODO:
|
|
// Make ghosts/phased entities slow when grabbed
|
|
// Make it so it searches in an AOE and grabs thing.
|
|
|
|
/obj/item/ghost_catcher/Destroy()
|
|
grabbed_entity = null
|
|
return ..()
|
|
|
|
/obj/item/ghost_catcher/update_icon()
|
|
if(busy)
|
|
icon_state = "ghost_beam_active"
|
|
else
|
|
icon_state = initial(icon_state)
|
|
|
|
/obj/item/ghost_catcher/update_held_icon()
|
|
var/mob/living/M = loc
|
|
if(istype(M) && M.can_wield_item(src) && is_held_twohanded(M))
|
|
wielded = TRUE
|
|
else
|
|
wielded = FALSE
|
|
..()
|
|
|
|
/obj/item/ghost_catcher/afterattack(atom/target, mob/user, proximity_flag)
|
|
update_held_icon()
|
|
if(!wielded)
|
|
to_chat(user, span_warning("You need to hold \the [src] in two hands to use it!"))
|
|
return
|
|
|
|
if(!COOLDOWN_FINISHED(src, ghost_cooldown))
|
|
to_chat(user, span_warning("The [src] is recharging!"))
|
|
return
|
|
if(!COOLDOWN_FINISHED(src, click_cooldown))
|
|
to_chat(user, span_warning("The [src] needs time between movements!"))
|
|
return
|
|
|
|
if(isturf(target) && (!target.incorporeal_grab()))
|
|
var/turf/T = target
|
|
if(!busy)
|
|
for(var/mob/entity in range(1, T)) //We'll let you grab things ON the tile or AROUND the tile you click on.
|
|
if(entity.incorporeal_grab())
|
|
target = entity
|
|
break
|
|
if(!ismob(target))
|
|
to_chat(user, span_warning("No valid target in range! Beginning cooldown."))
|
|
COOLDOWN_START(src, ghost_cooldown, 3 SECONDS) //Prevent from spamclicking to find ghosts.
|
|
return
|
|
else
|
|
if(grabbed_entity)
|
|
var/atom/movable/entity = grabbed_entity.resolve()
|
|
if(get_dist(T, entity) > max_move_distance)
|
|
to_chat(user, span_warning("\The [src] is unable to pull the entity that far!"))
|
|
return
|
|
entity.forceMove(T)
|
|
COOLDOWN_START(src, click_cooldown, 1 SECOND)
|
|
return
|
|
|
|
if(istype(target, /obj/item/ghost_trap)) //Special handling for traps, since traps are full sized objects and not turf.
|
|
var/obj/item/ghost_trap/trap = target
|
|
var/atom/movable/entity = grabbed_entity.resolve()
|
|
if(!trap.deployed)
|
|
to_chat(user, span_warning("The trap isn't deployed!"))
|
|
return
|
|
if(!entity)
|
|
to_chat(user, span_warning("No valid target!"))
|
|
return
|
|
if(get_dist(trap, entity) > max_move_distance)
|
|
to_chat(user, span_warning("\The [src] is unable to pull the entity that far!"))
|
|
return
|
|
entity.forceMove(get_turf(trap))
|
|
COOLDOWN_START(src, click_cooldown, 1 SECOND)
|
|
return
|
|
|
|
// Things that invalidate the scan immediately.
|
|
if(busy)
|
|
to_chat(user, span_warning("\The [src] is already grabbing an entity!"))
|
|
return
|
|
|
|
if(!target.incorporeal_grab(user)) // This will tell the user what is wrong.
|
|
return
|
|
|
|
if(get_dist(target, user) > grab_range)
|
|
to_chat(user, span_warning("You are too far away from \the [target] to catalogue it. Get closer."))
|
|
return
|
|
|
|
// Start the special effects.
|
|
busy = TRUE
|
|
update_icon()
|
|
var/datum/beam/scan_beam = user.Beam(target, icon_state = "curse1", time = 60 SECONDS)
|
|
var/filter = filter(type = "outline", size = 1, color = "#330099")
|
|
target.filters += filter
|
|
var/list/box_segments = list()
|
|
if(user.client)
|
|
box_segments = draw_box(target, grab_range, user.client)
|
|
color_box(box_segments, "#330099", 60 SECONDS)
|
|
|
|
playsound(src, 'sound/machines/beep.ogg', 50)
|
|
|
|
grabbed_entity = WEAKREF(target)
|
|
if(isliving(target))
|
|
var/mob/living/target_mob = target
|
|
target_mob.Weaken(3)
|
|
target_mob.Stun(3)
|
|
to_chat(target, span_danger("You feel yourself weakened from the [src]'s beam!"))
|
|
|
|
// The delay, and test for if the scan succeeds or not.
|
|
if(do_after(user, 60 SECONDS, target, timed_action_flags = IGNORE_USER_LOC_CHANGE|IGNORE_TARGET_LOC_CHANGE, max_distance = grab_range))
|
|
to_chat(user, span_warning("With a buzz, \the [src] flashes red, the beam on \the [target] has broken!"))
|
|
playsound(src, 'sound/machines/buzz-two.ogg', 50)
|
|
color_box(box_segments, "#330099", 3)
|
|
busy = FALSE
|
|
|
|
// Now clean up the effects.
|
|
update_icon()
|
|
QDEL_NULL(scan_beam)
|
|
if(target)
|
|
target.filters -= filter
|
|
if(user.client) // If for some reason they logged out mid-scan the box will be gone anyways.
|
|
delete_box(box_segments, user.client)
|
|
grabbed_entity = null
|
|
COOLDOWN_START(src, ghost_cooldown, 10 SECONDS) // Arbitrary cooldown to prevent spam. Adjust as needed.
|
|
|
|
/atom/proc/incorporeal_grab(mob/user)
|
|
if(is_incorporeal())
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/mob/observer/dead/incorporeal_grab(mob/user) // Dead mobs can't be scanned.
|
|
if(admin_ghosted || !interact_with_world)
|
|
to_chat(user, span_notice("No entity detected!")) //The goggles ARE listed as unreliable. You could just be seeing static.
|
|
return FALSE
|
|
return ..()
|
|
|
|
//The backpack the gun is (typically) attached to!
|
|
/obj/item/proton_pack
|
|
name = "proton pack"
|
|
desc = "A complex backpack that houses a miniature antimatter reactor to power a spectral capture device."
|
|
icon = 'icons/obj/technomancer.dmi'
|
|
default_worn_icon = 'icons/inventory/back/mob.dmi'
|
|
icon_state = "technomancer_core"
|
|
item_state = "proton_pack"
|
|
slot_flags = SLOT_BACK
|
|
preserve_item = 1
|
|
w_class = ITEMSIZE_LARGE
|
|
unacidable = TRUE
|
|
var/obj/item/ghost_catcher/who_ya_gunna_call = /obj/item/ghost_catcher
|
|
|
|
/obj/item/proton_pack/Initialize(mapload)
|
|
AddComponent(/datum/component/tethered_item, who_ya_gunna_call)
|
|
. = ..()
|
|
|
|
/obj/item/proton_pack/attack_hand(mob/living/user)
|
|
// See important note in tethered_item.dm
|
|
if(SEND_SIGNAL(src,COMSIG_ITEM_ATTACK_SELF,user) & COMPONENT_CANCEL_ATTACK_CHAIN)
|
|
return TRUE
|
|
. = ..()
|
|
|
|
/obj/item/proton_pack/MouseDrop()
|
|
if(ismob(src.loc))
|
|
if(!CanMouseDrop(src))
|
|
return
|
|
var/mob/M = src.loc
|
|
if(!M.unEquip(src))
|
|
return
|
|
src.add_fingerprint(usr)
|
|
M.put_in_any_hand_if_possible(src)
|