mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-19 11:08:35 +01:00
# Conflicts: # .github/CODEOWNERS # .github/workflows/compile_changelogs.yml # .github/workflows/stale.yml # SQL/database_changelog.md # _maps/map_files/CatwalkStation/CatwalkStation_2023.dmm # code/__DEFINES/atom_hud.dm # code/__DEFINES/inventory.dm # code/__DEFINES/mobs.dm # code/__DEFINES/species_clothing_paths.dm # code/__DEFINES/subsystems.dm # code/__DEFINES/surgery.dm # code/__HELPERS/global_lists.dm # code/_globalvars/lists/maintenance_loot.dm # code/_globalvars/traits/_traits.dm # code/controllers/subsystem/minor_mapping.dm # code/controllers/subsystem/processing/quirks.dm # code/controllers/subsystem/shuttle.dm # code/datums/components/palette.dm # code/datums/components/surgery_initiator.dm # code/datums/diseases/advance/advance.dm # code/datums/hud.dm # code/datums/mood.dm # code/datums/mutations/chameleon.dm # code/datums/quirks/negative_quirks/nyctophobia.dm # code/datums/status_effects/debuffs/debuffs.dm # code/datums/status_effects/debuffs/drunk.dm # code/datums/status_effects/debuffs/slime/slime_leech.dm # code/datums/weather/weather.dm # code/game/data_huds.dm # code/game/objects/items.dm # code/game/objects/items/devices/scanners/health_analyzer.dm # code/game/objects/items/frog_statue.dm # code/game/objects/items/rcd/RLD.dm # code/game/objects/items/robot/items/hypo.dm # code/game/objects/items/stacks/medical.dm # code/game/objects/items/stacks/wrap.dm # code/game/objects/items/storage/garment.dm # code/game/objects/items/tools/medical/defib.dm # code/game/objects/items/weaponry.dm # code/game/objects/items/weaponry/melee/misc.dm # code/game/objects/structures/crates_lockers/closets/secure/security.dm # code/game/objects/structures/curtains.dm # code/game/objects/structures/dresser.dm # code/game/objects/structures/girders.dm # code/game/objects/structures/maintenance.dm # code/game/objects/structures/mirror.dm # code/modules/admin/greyscale_modify_menu.dm # code/modules/admin/verbs/light_debug.dm # code/modules/antagonists/ashwalker/ashwalker.dm # code/modules/antagonists/heretic/knowledge/starting_lore.dm # code/modules/antagonists/ninja/ninjaDrainAct.dm # code/modules/art/paintings.dm # code/modules/client/preferences.dm # code/modules/client/verbs/ooc.dm # code/modules/clothing/head/wig.dm # code/modules/events/disease_outbreak.dm # code/modules/holodeck/holo_effect.dm # code/modules/jobs/job_types/head_of_security.dm # code/modules/jobs/job_types/security_officer.dm # code/modules/library/skill_learning/generic_skillchips/point.dm # code/modules/mining/lavaland/ash_flora.dm # code/modules/mining/lavaland/mining_loot/megafauna/ash_drake.dm # code/modules/mob/dead/new_player/new_player.dm # code/modules/mob/living/basic/guardian/guardian.dm # code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm # code/modules/mob/living/carbon/carbon.dm # code/modules/mob/living/carbon/human/human.dm # code/modules/mob/living/carbon/human/human_defines.dm # code/modules/mob/living/carbon/life.dm # code/modules/mob/living/living.dm # code/modules/mob/living/living_defines.dm # code/modules/mob/mob.dm # code/modules/mob_spawn/ghost_roles/mining_roles.dm # code/modules/mod/mod_control.dm # code/modules/mod/modules/modules_general.dm # code/modules/modular_computers/computers/item/computer_ui.dm # code/modules/paperwork/paper.dm # code/modules/paperwork/paperbin.dm # code/modules/power/lighting/light.dm # code/modules/projectiles/guns/energy/kinetic_accelerator.dm # code/modules/projectiles/projectile.dm # code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm # code/modules/reagents/chemistry/reagents/food_reagents.dm # code/modules/reagents/chemistry/reagents/other_reagents.dm # code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm # code/modules/research/xenobiology/crossbreeding/_clothing.dm # code/modules/research/xenobiology/crossbreeding/prismatic.dm # code/modules/surgery/advanced/brainwashing.dm # code/modules/surgery/advanced/lobotomy.dm # code/modules/surgery/amputation.dm # code/modules/surgery/blood_filter.dm # code/modules/surgery/bodyparts/_bodyparts.dm # code/modules/surgery/brain_surgery.dm # code/modules/surgery/cavity_implant.dm # code/modules/surgery/coronary_bypass.dm # code/modules/surgery/gastrectomy.dm # code/modules/surgery/healing.dm # code/modules/surgery/limb_augmentation.dm # code/modules/surgery/organ_manipulation.dm # code/modules/surgery/revival.dm # code/modules/surgery/sleeper_protocol.dm # code/modules/surgery/surgery_helpers.dm # code/modules/surgery/surgery_step.dm # code/modules/unit_tests/_unit_tests.dm # code/modules/unit_tests/designs.dm # code/modules/unit_tests/icon_state_worn.dm # code/modules/unit_tests/screenshots/screenshot_antag_icons_cultist.png # code/modules/unit_tests/screenshots/screenshot_antag_icons_headrevolutionary.png # code/modules/unit_tests/screenshots/screenshot_antag_icons_provocateur.png # code/modules/unit_tests/screenshots/screenshot_husk_body.png # code/modules/unit_tests/screenshots/screenshot_husk_body_missing_limbs.png # icons/map_icons/clothing/head/_head.dmi # icons/map_icons/clothing/shoes.dmi # icons/map_icons/items/_item.dmi # icons/mob/huds/hud.dmi # icons/mob/inhands/64x64_lefthand.dmi # icons/mob/inhands/64x64_righthand.dmi # icons/obj/machines/computer.dmi # tgui/packages/tgui/interfaces/OperatingComputer.jsx # tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/MainPage.tsx # tgui/packages/tgui/interfaces/PreferencesMenu/types.ts # tgui/packages/tgui/interfaces/SurgeryInitiator.tsx # tools/icon_cutter/check.py
338 lines
10 KiB
Plaintext
338 lines
10 KiB
Plaintext
#define PROXIMITY_NONE ""
|
|
#define PROXIMITY_ON_SCREEN "_red"
|
|
#define PROXIMITY_NEAR "_yellow"
|
|
|
|
/**
|
|
* Multitool -- A multitool is used for hacking electronic devices.
|
|
*
|
|
*/
|
|
|
|
|
|
|
|
|
|
/obj/item/multitool //SKYRAT EDIT - ICON OVERRIDDEN BY AESTHETICS - SEE MODULE
|
|
name = "multitool"
|
|
desc = "Used for pulsing wires to test which to cut. Not recommended by doctors. You can activate it in-hand to locate the nearest APC."
|
|
icon = 'icons/obj/devices/tool.dmi'
|
|
icon_state = "multitool"
|
|
inhand_icon_state = "multitool"
|
|
icon_angle = -90
|
|
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
|
|
force = 5
|
|
w_class = WEIGHT_CLASS_SMALL
|
|
tool_behaviour = TOOL_MULTITOOL
|
|
throwforce = 0
|
|
throw_range = 7
|
|
throw_speed = 3
|
|
drop_sound = 'sound/items/handling/tools/multitool_drop.ogg'
|
|
pickup_sound = 'sound/items/handling/tools/multitool_pickup.ogg'
|
|
custom_materials = list(
|
|
/datum/material/iron =SMALL_MATERIAL_AMOUNT * 0.5,
|
|
/datum/material/glass =SMALL_MATERIAL_AMOUNT * 0.2
|
|
)
|
|
custom_premium_price = PAYCHECK_CREW * 3
|
|
toolspeed = 1
|
|
usesound = 'sound/items/weapons/empty.ogg'
|
|
var/datum/buffer // simple machine buffer for device linkage
|
|
var/mode = 0
|
|
var/apc_scanner = TRUE
|
|
COOLDOWN_DECLARE(next_apc_scan)
|
|
|
|
/obj/item/multitool/Destroy()
|
|
if(buffer)
|
|
remove_buffer(buffer)
|
|
return ..()
|
|
|
|
/obj/item/multitool/examine(mob/user)
|
|
. = ..()
|
|
. += span_notice("Its buffer [buffer ? "contains [buffer]." : "is empty."]")
|
|
|
|
/obj/item/multitool/attack_self(mob/user, list/modifiers)
|
|
. = ..()
|
|
|
|
if(. || !apc_scanner)
|
|
return
|
|
|
|
scan_apc(user)
|
|
|
|
/obj/item/multitool/attack_self_secondary(mob/user, modifiers)
|
|
. = ..()
|
|
|
|
if(. || !apc_scanner)
|
|
return
|
|
|
|
scan_apc(user)
|
|
|
|
/obj/item/multitool/proc/scan_apc(mob/user)
|
|
if(!COOLDOWN_FINISHED(src, next_apc_scan))
|
|
return
|
|
|
|
COOLDOWN_START(src, next_apc_scan, 2 SECONDS)
|
|
|
|
var/area/local_area = get_area(src)
|
|
var/obj/machinery/power/apc/power_controller = local_area.apc
|
|
if(!power_controller)
|
|
user.balloon_alert(user, "couldn't find apc!")
|
|
return
|
|
|
|
var/dist = get_dist(src, power_controller)
|
|
var/dir = get_dir(user, power_controller)
|
|
var/balloon_message
|
|
var/arrow_color
|
|
|
|
switch(dist)
|
|
if (0)
|
|
user.balloon_alert(user, "found apc!")
|
|
return
|
|
if(1 to 5)
|
|
arrow_color = COLOR_GREEN
|
|
if(6 to 10)
|
|
arrow_color = COLOR_YELLOW
|
|
if(11 to 15)
|
|
arrow_color = COLOR_ORANGE
|
|
else
|
|
arrow_color = COLOR_RED
|
|
|
|
user.balloon_alert(user, balloon_message)
|
|
|
|
var/datum/hud/user_hud = user.hud_used
|
|
if(!user_hud || !istype(user_hud, /datum/hud) || !islist(user_hud.infodisplay))
|
|
return
|
|
|
|
var/atom/movable/screen/multitool_arrow/arrow = new(null, user_hud)
|
|
arrow.color = arrow_color
|
|
arrow.screen_loc = around_player
|
|
arrow.transform = matrix(dir2angle(dir), MATRIX_ROTATE)
|
|
|
|
user_hud.infodisplay += arrow
|
|
user_hud.show_hud(user_hud.hud_version)
|
|
|
|
QDEL_IN(arrow, 1.5 SECONDS)
|
|
|
|
/obj/item/multitool/suicide_act(mob/living/carbon/user)
|
|
user.visible_message(span_suicide("[user] puts the [src] to [user.p_their()] chest. It looks like [user.p_theyre()] trying to pulse [user.p_their()] heart off!"))
|
|
return OXYLOSS//there's a reason it wasn't recommended by doctors
|
|
|
|
/**
|
|
* Sets the multitool internal object buffer
|
|
*
|
|
* Arguments:
|
|
* * buffer - the new object to assign to the multitool's buffer
|
|
*/
|
|
/obj/item/multitool/proc/set_buffer(datum/buffer)
|
|
if(src.buffer)
|
|
UnregisterSignal(src.buffer, COMSIG_QDELETING)
|
|
remove_buffer(src.buffer)
|
|
src.buffer = buffer
|
|
if(!QDELETED(buffer))
|
|
RegisterSignal(buffer, COMSIG_QDELETING, PROC_REF(remove_buffer))
|
|
|
|
/**
|
|
* Called when the buffer's stored object is deleted
|
|
*
|
|
* This proc does not clear the buffer of the multitool, it is here to
|
|
* handle the deletion of the object the buffer references
|
|
*/
|
|
/obj/item/multitool/proc/remove_buffer(datum/source)
|
|
SIGNAL_HANDLER
|
|
SEND_SIGNAL(src, COMSIG_MULTITOOL_REMOVE_BUFFER, source)
|
|
buffer = null
|
|
|
|
// Syndicate device disguised as a multitool; it will turn red when an AI camera is nearby.
|
|
|
|
/obj/item/multitool/ai_detect
|
|
apc_scanner = FALSE
|
|
/// How close the AI is to us
|
|
var/detect_state = PROXIMITY_NONE
|
|
/// Range at which the closest AI makes the multitool glow red
|
|
var/rangealert = 8 //Glows red when inside
|
|
/// Range at which the closest AI makes the multitool glow yellow
|
|
var/rangewarning = 20 //Glows yellow when inside
|
|
/// Is our HUD on
|
|
var/hud_on = FALSE
|
|
|
|
// static scan stuff
|
|
/// hud object that the fake static images use
|
|
var/obj/effect/overlay/ai_detect_hud/camera_unseen/hud_obj
|
|
/// fake static image
|
|
var/list/image/static_images = list()
|
|
/// the client that we shoved those images to
|
|
var/datum/weakref/static_viewer
|
|
/// timerid for the timer that makes em disappear
|
|
var/static_disappear_timer
|
|
/// cooldown for actually doing a static scan
|
|
COOLDOWN_DECLARE(static_scan_cd)
|
|
|
|
/obj/item/multitool/ai_detect/examine(mob/user)
|
|
. = ..()
|
|
if(!hud_on)
|
|
return
|
|
. += span_notice("You can right-click to scan for nearby unseen spots. They will be shown for exactly 8 seconds due to battery limitations.")
|
|
switch(detect_state)
|
|
if(PROXIMITY_NONE)
|
|
. += span_green("No AI should be currently looking at you. Keep on your clandestine activities.")
|
|
if(PROXIMITY_NEAR)
|
|
. += span_warning("An AI is getting uncomfortably close. Maybe time to drop what youre doing.")
|
|
if(PROXIMITY_ON_SCREEN)
|
|
. += span_danger("An AI is (probably) looking at you. You should probably hide this.")
|
|
|
|
/obj/item/multitool/ai_detect/Destroy()
|
|
if(hud_on && ismob(loc))
|
|
remove_hud(loc)
|
|
cleanup_static()
|
|
return ..()
|
|
|
|
/obj/item/multitool/ai_detect/attack_self(mob/user, modifiers)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
toggle_hud(user)
|
|
|
|
/obj/item/multitool/ai_detect/attack_self_secondary(mob/user, modifiers)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
scan_unseen(user)
|
|
|
|
/obj/item/multitool/ai_detect/equipped(mob/living/carbon/human/user, slot)
|
|
. = ..()
|
|
if(hud_on)
|
|
show_hud(user)
|
|
|
|
/obj/item/multitool/ai_detect/dropped(mob/living/carbon/human/user)
|
|
. = ..()
|
|
if(hud_on)
|
|
remove_hud(user)
|
|
cleanup_static()
|
|
|
|
/obj/item/multitool/ai_detect/update_icon_state()
|
|
. = ..()
|
|
icon_state = "[initial(icon_state)][detect_state]"
|
|
|
|
/obj/item/multitool/ai_detect/process()
|
|
var/old_detect_state = detect_state
|
|
multitool_detect()
|
|
if(detect_state != old_detect_state)
|
|
update_appearance()
|
|
|
|
/obj/item/multitool/ai_detect/proc/toggle_hud(mob/user)
|
|
hud_on = !hud_on
|
|
if(user)
|
|
to_chat(user, span_notice("You toggle the ai detection feature on [src] [hud_on ? "on" : "off"]."))
|
|
if(hud_on)
|
|
START_PROCESSING(SSfastprocess, src)
|
|
show_hud(user)
|
|
else
|
|
STOP_PROCESSING(SSfastprocess, src)
|
|
detect_state = PROXIMITY_NONE
|
|
update_appearance(UPDATE_ICON)
|
|
remove_hud(user)
|
|
|
|
/obj/item/multitool/ai_detect/proc/show_hud(mob/user)
|
|
var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_AI_DETECT]
|
|
hud.show_to(user)
|
|
|
|
/obj/item/multitool/ai_detect/proc/remove_hud(mob/user)
|
|
var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_AI_DETECT]
|
|
hud.hide_from(user)
|
|
|
|
/obj/item/multitool/ai_detect/proc/multitool_detect()
|
|
var/turf/our_turf = get_turf(src)
|
|
detect_state = PROXIMITY_NONE
|
|
|
|
for(var/mob/eye/camera/ai/AI_eye in GLOB.camera_eyes)
|
|
if(!AI_eye.ai_detector_visible)
|
|
continue
|
|
|
|
var/turf/ai_turf = get_turf(AI_eye)
|
|
var/distance = get_dist(our_turf, ai_turf)
|
|
|
|
if(distance == -1) //get_dist() returns -1 for distances greater than 127 (and for errors, so assume -1 is just max range)
|
|
if(ai_turf == our_turf)
|
|
detect_state = PROXIMITY_ON_SCREEN
|
|
break
|
|
continue
|
|
|
|
if(distance < rangealert) //ai should be able to see us
|
|
detect_state = PROXIMITY_ON_SCREEN
|
|
break
|
|
if(distance < rangewarning) //ai can't see us but is close
|
|
detect_state = PROXIMITY_NEAR
|
|
|
|
/obj/item/multitool/ai_detect/proc/scan_unseen(mob/user)
|
|
if(isnull(user?.client)) // the monkey incident of 2564
|
|
return
|
|
if(!COOLDOWN_FINISHED(src, static_scan_cd))
|
|
balloon_alert(user, "recharging!")
|
|
return
|
|
cleanup_static()
|
|
var/turf/our_turf = get_turf(src)
|
|
var/list/datum/camerachunk/chunks = surrounding_chunks(our_turf)
|
|
|
|
if(!hud_obj)
|
|
hud_obj = new()
|
|
SET_PLANE_W_SCALAR(hud_obj, PLANE_TO_TRUE(hud_obj.plane), GET_TURF_PLANE_OFFSET(our_turf))
|
|
|
|
var/list/new_images = list()
|
|
for(var/datum/camerachunk/chunk as anything in chunks)
|
|
for(var/turf/seen_turf as anything in chunk.obscuredTurfs)
|
|
var/image/img = image(loc = seen_turf, layer = ABOVE_ALL_MOB_LAYER)
|
|
img.vis_contents += hud_obj
|
|
SET_PLANE(img, GAME_PLANE, seen_turf)
|
|
new_images += img
|
|
user.client.images |= new_images
|
|
static_viewer = WEAKREF(user.client)
|
|
balloon_alert(user, "nearby unseen spots shown")
|
|
static_disappear_timer = addtimer(CALLBACK(src, PROC_REF(cleanup_static)), 8 SECONDS, TIMER_STOPPABLE)
|
|
COOLDOWN_START(src, static_scan_cd, 4 SECONDS)
|
|
|
|
// copied from camera chunks but we are doing a really big edge case here though
|
|
/obj/item/multitool/ai_detect/proc/surrounding_chunks(turf/epicenter)
|
|
. = list()
|
|
var/static_range = /mob/eye/camera/ai::static_visibility_range
|
|
var/x1 = max(1, epicenter.x - static_range)
|
|
var/y1 = max(1, epicenter.y - static_range)
|
|
var/x2 = min(world.maxx, epicenter.x + static_range)
|
|
var/y2 = min(world.maxy, epicenter.y + static_range)
|
|
|
|
for(var/x = x1; x <= x2; x += CHUNK_SIZE)
|
|
for(var/y = y1; y <= y2; y += CHUNK_SIZE)
|
|
var/datum/camerachunk/chunk = SScameras.generate_chunk(x, y, epicenter.z)
|
|
// removing cameras in build mode didnt affect it and i guess it needs an AI eye to update so we have to do this manually
|
|
// unless we only want to see static in a jank manner only if an eye updates it
|
|
chunk?.force_update(only_if_necessary = FALSE) // UPDATE THE FUCK NOW
|
|
. |= chunk
|
|
|
|
/obj/item/multitool/ai_detect/proc/cleanup_static()
|
|
if(isnull(hud_obj)) //we never did anything
|
|
return
|
|
var/client/viewer = static_viewer?.resolve()
|
|
viewer?.images -= static_images
|
|
static_images.Cut()
|
|
QDEL_NULL(hud_obj)
|
|
viewer = null
|
|
deltimer(static_disappear_timer)
|
|
static_disappear_timer = null
|
|
|
|
/obj/item/multitool/abductor
|
|
name = "alien multitool"
|
|
desc = "An omni-technological interface."
|
|
icon = 'icons/obj/antags/abductor.dmi'
|
|
icon_state = "multitool"
|
|
inside_belt_icon_state = "multitool_alien"
|
|
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/silver = SHEET_MATERIAL_AMOUNT * 1.25, /datum/material/plasma = SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/titanium = SHEET_MATERIAL_AMOUNT, /datum/material/diamond = SHEET_MATERIAL_AMOUNT)
|
|
toolspeed = 0.1
|
|
|
|
/obj/item/multitool/cyborg
|
|
name = "electronic multitool"
|
|
desc = "Optimised version of a regular multitool. Streamlines processes handled by its internal microchip."
|
|
icon = 'icons/obj/items_cyborg.dmi'
|
|
icon_state = "toolkit_engiborg_multitool"
|
|
icon_angle = 0
|
|
toolspeed = 0.5
|
|
|
|
#undef PROXIMITY_NEAR
|
|
#undef PROXIMITY_NONE
|
|
#undef PROXIMITY_ON_SCREEN
|