mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-05-17 20:30:46 +01:00
d5849910e5
* Begin clickcode attack_self fix Begins the work to make everything call back to parent for attack_self so that signals are sacred. * Makes MORE things call the attack_self() parent Yes, I could make special_handling a var on obj/item HOWEVER i want it to be specific so it can be tracked down later and ONLY the objects that use it can be refactored instead of sitting there literally forever and it just becoming 'a thing'. * Finishes making the rest of attack_self call parent. As mentioned, things such as 'specialty_goggles' 'special_handling' and the such are only there to help with attack_self until the attack_self is recoded for those items. * begone foul demon * some more cleanup * These * GOD this was annoying * yeh * Fix this * fLARES * Thesee too * toys! * Even more! * More fixes * Even more * rest of em * these too * Update syndie.dm * hardref clear * Update code/game/gamemodes/nuclear/pinpointer.dm * Update code/game/objects/effects/mines.dm * Update code/game/objects/items/blueprints_vr.dm * Update code/game/objects/items/blueprints_vr.dm * Update code/game/objects/items/contraband_vr.dm * Update code/game/objects/items/crayons.dm * Update code/game/objects/items/crayons.dm * Update code/game/objects/items/gunbox.dm * Update code/game/objects/items/gunbox.dm * Update code/game/objects/items/gunbox_vr.dm * Update code/game/objects/items/gunbox_vr.dm * Update code/game/objects/items/weapons/gift_wrappaper.dm * Update code/game/objects/items/crayons.dm * Update code/game/objects/items/crayons.dm * Update code/game/objects/items/gunbox.dm * these too * Update maintpanel_stack.dm * angry warning * Fixes packaged snacks. Fixes improper var default. * Special handling for these * proper poly types * Fixes magclaws Makes the 'features' it had just part of base magboots that can be adjusted via varswap. * Fixes jackets Fixes https://github.com/VOREStation/VOREStation/issues/18941 * Small bugfix Makes p_Theyre properly capitialize Makes examine show proper wording * Update gift_wrappaper.dm
387 lines
14 KiB
Plaintext
387 lines
14 KiB
Plaintext
GLOBAL_LIST_EMPTY(all_cataloguers)
|
|
|
|
/*
|
|
This is a special scanner which exists to give explorers something to do besides shoot things.
|
|
The scanner is able to be used on certain things in the world, and after a variable delay, the scan finishes,
|
|
giving the person who scanned it some fluff and information about what they just scanned,
|
|
as well as points that currently do nothing but measure epeen,
|
|
and will be used as currency in The Future(tm) to buy things explorers care about.
|
|
|
|
Scanning hostile mobs and objects is tricky since only mobs that are alive are scannable, so scanning
|
|
them requires careful position to stay out of harms way until the scan finishes. That is why
|
|
the person with the scanner gets a visual box that shows where they are allowed to move to
|
|
without inturrupting the scan.
|
|
*/
|
|
/obj/item/cataloguer
|
|
name = "cataloguer"
|
|
desc = "A hand-held device, used for compiling information about an object by scanning it. Alt+click to highlight scannable objects around you."
|
|
description_info = "This is a special device used to obtain information about objects and entities in the environment. \
|
|
To scan something, click on it with the scanner at a distance. \
|
|
Scanning something requires remaining within a certain radius of the object for a specific period of time, until the \
|
|
scan is finished. If the scan is interrupted, it can be resumed from where it was left off, if the same thing is \
|
|
scanned again."
|
|
icon = 'icons/obj/device.dmi'
|
|
icon_state = "cataloguer"
|
|
w_class = ITEMSIZE_NORMAL
|
|
origin_tech = list(TECH_MATERIAL = 2, TECH_DATA = 3, TECH_MAGNET = 3)
|
|
force = 0
|
|
slot_flags = SLOT_BELT
|
|
var/points_stored = 0 // Amount of 'exploration points' this device holds.
|
|
var/scan_range = 3 // How many tiles away it can scan. Changing this also changes the box size.
|
|
var/credit_sharing_range = 280 // If another person is within this radius, they will also be credited with a successful scan. Original was 14
|
|
var/datum/category_item/catalogue/displayed_data = null // Used for viewing a piece of data in the UI.
|
|
var/busy = FALSE // Set to true when scanning, to stop multiple scans.
|
|
var/debug = FALSE // If true, can view all catalogue data defined, regardless of unlock status.
|
|
var/datum/weakref/partial_scanned = null // Weakref of the thing that was last scanned if inturrupted. Used to allow for partial scans to be resumed.
|
|
var/partial_scan_time = 0 // How much to make the next scan shorter.
|
|
|
|
/obj/item/cataloguer/advanced
|
|
name = "advanced cataloguer"
|
|
icon = 'icons/obj/device.dmi'
|
|
icon_state = "adv_cataloguer"
|
|
desc = "A hand-held device, used for compiling information about an object by scanning it. This one is an upgraded model, \
|
|
with a scanner that both can scan from farther away, and with less time."
|
|
scan_range = 4
|
|
toolspeed = 0.8
|
|
|
|
// Able to see all defined catalogue data regardless of if it was unlocked, intended for testing.
|
|
/obj/item/cataloguer/debug
|
|
name = "omniscient cataloguer"
|
|
desc = "A hand-held cataloguer device that appears to be plated with gold. For some reason, it \
|
|
just seems to already know everything about narrowly defined pieces of knowledge one would find \
|
|
from nearby, perhaps due to being colored gold. Truly a epistemological mystery."
|
|
icon = 'icons/obj/device.dmi'
|
|
icon_state = "debug_cataloguer"
|
|
toolspeed = 0.1
|
|
scan_range = 7
|
|
debug = TRUE
|
|
|
|
|
|
/obj/item/cataloguer/Initialize(mapload)
|
|
GLOB.all_cataloguers += src
|
|
return ..()
|
|
|
|
/obj/item/cataloguer/Destroy()
|
|
GLOB.all_cataloguers -= src
|
|
displayed_data = null
|
|
return ..()
|
|
|
|
/obj/item/cataloguer/update_icon()
|
|
if(busy)
|
|
icon_state = "[initial(icon_state)]_active"
|
|
else
|
|
icon_state = initial(icon_state)
|
|
|
|
/obj/item/cataloguer/afterattack(atom/target, mob/user, proximity_flag)
|
|
// Things that invalidate the scan immediately.
|
|
if(busy)
|
|
to_chat(user, span_warning("\The [src] is already scanning something."))
|
|
return
|
|
|
|
if(isturf(target) && (!target.can_catalogue()))
|
|
var/turf/T = target
|
|
for(var/atom/A as anything in T) // If we can't scan the turf, see if we can scan anything on it, to help with aiming.
|
|
if(A.can_catalogue())
|
|
target = A
|
|
break
|
|
|
|
if(!target.can_catalogue(user)) // This will tell the user what is wrong.
|
|
return
|
|
|
|
if(get_dist(target, user) > scan_range)
|
|
to_chat(user, span_warning("You are too far away from \the [target] to catalogue it. Get closer."))
|
|
return
|
|
|
|
// Get how long the delay will be.
|
|
var/scan_delay = target.get_catalogue_delay() * toolspeed
|
|
if(partial_scanned)
|
|
if(partial_scanned.resolve() == target)
|
|
scan_delay -= partial_scan_time
|
|
to_chat(user, span_notice("Resuming previous scan."))
|
|
else
|
|
to_chat(user, span_warning("Scanning new target. Previous scan buffer cleared."))
|
|
|
|
// Start the special effects.
|
|
busy = TRUE
|
|
update_icon()
|
|
var/datum/beam/scan_beam = user.Beam(target, icon_state = "rped_upgrade", time = scan_delay)
|
|
var/filter = filter(type = "outline", size = 1, color = "#FFFFFF")
|
|
target.filters += filter
|
|
var/list/box_segments = list()
|
|
if(user.client)
|
|
box_segments = draw_box(target, scan_range, user.client)
|
|
color_box(box_segments, "#00FFFF", scan_delay)
|
|
|
|
playsound(src, 'sound/machines/beep.ogg', 50)
|
|
|
|
// The delay, and test for if the scan succeeds or not.
|
|
var/scan_start_time = world.time
|
|
if(do_after(user, scan_delay, target, timed_action_flags = IGNORE_USER_LOC_CHANGE|IGNORE_TARGET_LOC_CHANGE, max_distance = scan_range))
|
|
if(target.can_catalogue(user))
|
|
to_chat(user, span_notice("You successfully scan \the [target] with \the [src]."))
|
|
playsound(src, 'sound/machines/ping.ogg', 50)
|
|
catalogue_object(target, user)
|
|
else
|
|
// In case someone else scans it first, or it died, etc.
|
|
to_chat(user, span_warning("\The [target] is no longer valid to scan with \the [src]."))
|
|
playsound(src, 'sound/machines/buzz-two.ogg', 50)
|
|
|
|
partial_scanned = null
|
|
partial_scan_time = 0
|
|
else
|
|
to_chat(user, span_warning("You failed to finish scanning \the [target] with \the [src]."))
|
|
playsound(src, 'sound/machines/buzz-two.ogg', 50)
|
|
color_box(box_segments, "#FF0000", 3)
|
|
partial_scanned = WEAKREF(target)
|
|
partial_scan_time += world.time - scan_start_time // This is added to the existing value so two partial scans will add up correctly.
|
|
sleep(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)
|
|
|
|
// Todo: Display scanned information, increment points, etc.
|
|
/obj/item/cataloguer/proc/catalogue_object(atom/target, mob/living/user)
|
|
// Figure out who may have helped out.
|
|
var/list/contributers = list()
|
|
var/list/contributer_names = list()
|
|
for(var/mob/living/L as anything in GLOB.player_list)
|
|
if(L == user)
|
|
continue
|
|
if(!istype(L))
|
|
continue
|
|
if(get_dist(L, user) <= credit_sharing_range)
|
|
contributers += L
|
|
contributer_names += L.name
|
|
|
|
var/points_gained = 0
|
|
|
|
// Discover each datum available.
|
|
var/list/object_data = target.get_catalogue_data()
|
|
if(LAZYLEN(object_data))
|
|
for(var/data_type in object_data)
|
|
var/datum/category_item/catalogue/I = GLOB.catalogue_data.resolve_item(data_type)
|
|
if(istype(I))
|
|
var/list/discoveries = I.discover(user, list(user.name) + contributer_names) // If one discovery leads to another, the list returned will have all of them.
|
|
if(LAZYLEN(discoveries))
|
|
for(var/datum/category_item/catalogue/data as anything in discoveries)
|
|
points_gained += data.value
|
|
|
|
// Give out points.
|
|
if(points_gained)
|
|
// First, to us.
|
|
to_chat(user, span_notice("Gained [points_gained] points from this scan."))
|
|
adjust_points(points_gained)
|
|
|
|
// Now to our friends, if any.
|
|
if(contributers.len)
|
|
for(var/mob/M in contributers)
|
|
var/list/things = M.GetAllContents(3) // Depth of two should reach into bags but just in case lets make it three.
|
|
var/obj/item/cataloguer/other_cataloguer = locate() in things // If someone has two or more scanners this only adds points to one.
|
|
if(other_cataloguer)
|
|
to_chat(M, span_notice("Gained [points_gained] points from \the [user]'s scan of \the [target]."))
|
|
other_cataloguer.adjust_points(points_gained)
|
|
to_chat(user, span_notice("Shared discovery with [contributers.len] other contributer\s."))
|
|
|
|
|
|
|
|
|
|
/obj/item/cataloguer/click_alt(mob/user)
|
|
pulse_scan(user)
|
|
|
|
// Gives everything capable of being scanned an outline for a brief moment.
|
|
// Helps to avoid having to click a hundred things in a room for things that have an entry.
|
|
/obj/item/cataloguer/proc/pulse_scan(mob/user)
|
|
if(busy)
|
|
to_chat(user, span_warning("\The [src] is busy doing something else."))
|
|
return
|
|
|
|
busy = TRUE
|
|
update_icon()
|
|
playsound(src, 'sound/machines/beep.ogg', 50)
|
|
|
|
// First, get everything able to be scanned.
|
|
var/list/scannable_atoms = list()
|
|
for(var/atom/A as anything in view(world.view, user))
|
|
if(A.can_catalogue()) // Not passing the user is intentional, so they don't get spammed.
|
|
scannable_atoms += A
|
|
|
|
// Highlight things able to be scanned.
|
|
var/filter = filter(type = "outline", size = 1, color = "#00FF00")
|
|
for(var/atom/A as anything in scannable_atoms)
|
|
A.filters += filter
|
|
to_chat(user, span_notice("\The [src] is highlighting scannable objects in green, if any exist."))
|
|
|
|
sleep(2 SECONDS)
|
|
|
|
// Remove the highlights.
|
|
for(var/atom/A as anything in scannable_atoms)
|
|
if(QDELETED(A))
|
|
continue
|
|
A.filters -= filter
|
|
|
|
busy = FALSE
|
|
update_icon()
|
|
if(scannable_atoms.len)
|
|
playsound(src, 'sound/machines/ping.ogg', 50)
|
|
else
|
|
playsound(src, 'sound/machines/buzz-two.ogg', 50)
|
|
to_chat(user, span_notice("\The [src] found [scannable_atoms.len] object\s that can be scanned."))
|
|
|
|
|
|
// Negative points are bad.
|
|
/obj/item/cataloguer/proc/adjust_points(amount)
|
|
points_stored = max(0, points_stored += amount)
|
|
|
|
/obj/item/cataloguer/attack_self(mob/living/user)
|
|
. = ..(user)
|
|
if(.)
|
|
return TRUE
|
|
interact(user)
|
|
|
|
/obj/item/cataloguer/interact(mob/user)
|
|
var/list/dat = list()
|
|
var/title = "Cataloguer Data Display"
|
|
|
|
// Important buttons go on top since the scrollbar will default to the top of the window.
|
|
dat += "Contains <b>[points_stored]</b> Exploration Points."
|
|
dat += "<a href='byond://?src=\ref[src];pulse_scan=1'>\[Highlight Scannables\]</a><a href='byond://?src=\ref[src];refresh=1'>\[Refresh\]</a><a href='byond://?src=\ref[src];close=1'>\[Close\]</a>"
|
|
|
|
// If displayed_data exists, we show that, otherwise we show a list of all data in the mysterious global list.
|
|
if(displayed_data)
|
|
title = uppertext(displayed_data.name)
|
|
|
|
dat += "<a href='byond://?src=\ref[src];show_data=null'>\[Back to List\]</a>"
|
|
if(debug && !displayed_data.visible)
|
|
dat += "<a href='byond://?src=\ref[src];debug_unlock=\ref[displayed_data]'>\[(DEBUG) Force Discovery\]</a>"
|
|
dat += "<hr>"
|
|
|
|
dat += span_italics("[displayed_data.desc]")
|
|
if(LAZYLEN(displayed_data.cataloguers))
|
|
dat += "Cataloguers : <b>[english_list(displayed_data.cataloguers)]</b>."
|
|
else
|
|
dat += "Catalogued by nobody."
|
|
dat += "Worth <b>[displayed_data.value]</b> exploration points."
|
|
|
|
else
|
|
dat += "<hr>"
|
|
for(var/datum/category_group/group as anything in GLOB.catalogue_data.categories)
|
|
var/list/group_dat = list()
|
|
var/show_group = FALSE
|
|
|
|
group_dat += span_bold("[group.name]")
|
|
for(var/datum/category_item/catalogue/item as anything in group.items)
|
|
if(item.visible || debug)
|
|
group_dat += "<a href='byond://?src=\ref[src];show_data=\ref[item]'>[item.name]</a>"
|
|
show_group = TRUE
|
|
|
|
if(show_group || debug) // Avoid showing 'empty' groups on regular cataloguers.
|
|
dat += group_dat
|
|
|
|
var/datum/browser/popup = new(user, "cataloguer_display_\ref[src]", title, 500, 600, src)
|
|
popup.set_content(dat.Join("<br>"))
|
|
popup.open()
|
|
add_fingerprint(user)
|
|
|
|
/obj/item/cataloguer/Topic(href, href_list)
|
|
if(..())
|
|
usr << browse(null, "window=cataloguer_display")
|
|
return 0
|
|
if(href_list["close"] )
|
|
usr << browse(null, "window=cataloguer_display")
|
|
return 0
|
|
|
|
if(href_list["show_data"])
|
|
displayed_data = locate(href_list["show_data"])
|
|
|
|
if(href_list["pulse_scan"])
|
|
pulse_scan(usr)
|
|
return // Don't refresh the window for this or it will open it back if its closed during the highlighting.
|
|
|
|
if(href_list["debug_unlock"] && debug)
|
|
var/datum/category_item/catalogue/item = locate(href_list["debug_unlock"])
|
|
item.discover(usr, list("Debugger"))
|
|
|
|
interact(usr) // So it refreshes the window.
|
|
return 1
|
|
|
|
/obj/item/cataloguer/attackby(obj/item/W, mob/user)
|
|
if(istype(W, /obj/item/card/id) && !busy)
|
|
busy = TRUE
|
|
var/obj/item/card/id/ID = W
|
|
if(points_stored)
|
|
ID.survey_points += points_stored
|
|
points_stored = 0
|
|
to_chat(user, span_notice("You swipe the id over \the [src]."))
|
|
else
|
|
to_chat(user, span_notice("\The [src] has no points available."))
|
|
busy = FALSE
|
|
return ..()
|
|
|
|
/obj/item/cataloguer/compact
|
|
name = "compact cataloguer"
|
|
desc = "A compact hand-held device, used for compiling information about an object by scanning it. \
|
|
Alt+click to highlight scannable objects around you."
|
|
icon = 'icons/obj/device.dmi'
|
|
icon_state = "compact"
|
|
actions_types = list(/datum/action/item_action/toggle_cataloguer)
|
|
var/deployed = TRUE
|
|
scan_range = 1
|
|
toolspeed = 1.2
|
|
|
|
/obj/item/cataloguer/compact/pathfinder
|
|
name = "pathfinder's cataloguer"
|
|
desc = "A compact hand-held device, used for compiling information about an object by scanning it. \
|
|
Alt+click to highlight scannable objects around you."
|
|
icon = 'icons/obj/device.dmi'
|
|
icon_state = "pathcat"
|
|
scan_range = 3
|
|
toolspeed = 1
|
|
|
|
/obj/item/cataloguer/compact/update_icon()
|
|
if(busy)
|
|
icon_state = "[initial(icon_state)]_s"
|
|
else
|
|
icon_state = initial(icon_state)
|
|
|
|
/obj/item/cataloguer/compact/ui_action_click(mob/user, actiontype)
|
|
toggle()
|
|
|
|
/obj/item/cataloguer/compact/verb/toggle()
|
|
set name = "Toggle Cataloguer"
|
|
set category = "Object"
|
|
|
|
if(busy)
|
|
to_chat(usr, span_warning("\The [src] is currently scanning something."))
|
|
return
|
|
deployed = !(deployed)
|
|
if(deployed)
|
|
w_class = ITEMSIZE_NORMAL
|
|
icon_state = "[initial(icon_state)]"
|
|
to_chat(usr, span_notice("You flick open \the [src]."))
|
|
else
|
|
w_class = ITEMSIZE_SMALL
|
|
icon_state = "[initial(icon_state)]_closed"
|
|
to_chat(usr, span_notice("You close \the [src]."))
|
|
|
|
if (ismob(usr))
|
|
var/mob/M = usr
|
|
M.update_mob_action_buttons()
|
|
|
|
/obj/item/cataloguer/compact/afterattack(atom/target, mob/user, proximity_flag)
|
|
if(!deployed)
|
|
to_chat(user, span_warning("\The [src] is closed."))
|
|
return
|
|
return ..()
|
|
|
|
/obj/item/cataloguer/compact/pulse_scan(mob/user)
|
|
if(!deployed)
|
|
to_chat(user, span_warning("\The [src] is closed."))
|
|
return
|
|
return ..()
|