Files
Fghj240 f570c3aede Netpods can scan the dna of their occupants to create a matching bit avatar (#94052)
## About The Pull Request

Alt click a netpod to enable scanning, which scans your dna and makes
newly created bit avatars look more like you. If the netpod already has
an associated bit avatar it doesn't do anything.

Purely visual/audial if you count tts, it doesn't let you switch races.

## Why It's Good For The Game

Bitrunners can recognize their teammates.

## Changelog

🆑
add: Netpods can now scan their occupants to create more accurate bit
avatars
/🆑

---------

Co-authored-by: Fghj240 <fakeemail@notrealemail.com>
2025-11-25 19:49:21 -07:00

170 lines
5.3 KiB
Plaintext

#define BASE_DISCONNECT_DAMAGE 40
#define SCANNING_TOGGLE_COOLDOWN 5
/obj/machinery/netpod
name = "netpod"
base_icon_state = "netpod"
circuit = /obj/item/circuitboard/machine/netpod
desc = "A link to the netverse. It has an assortment of cables to connect yourself to a virtual domain."
icon = 'icons/obj/machines/bitrunning.dmi'
icon_state = "netpod"
max_integrity = 300
obj_flags = BLOCKS_CONSTRUCTION
state_open = TRUE
interaction_flags_mouse_drop = NEED_HANDS | NEED_DEXTERITY
/// Whether we have an ongoing connection
var/connected = FALSE
/// A player selected outfit by clicking the netpod
var/datum/outfit/netsuit = /datum/outfit/job/bitrunner
/// Holds this to see if it needs to generate a new one
var/datum/weakref/avatar_ref
/// The linked quantum server
var/datum/weakref/server_ref
/// The amount of brain damage done from force disconnects
var/disconnect_damage
/// Static list of outfits to select from
var/list/cached_outfits = list()
/// Whether bit avatars become visually similar to their bitrunner on first creation
var/copy_body = FALSE
/// The next time copy_body can be toggled
var/scanning_can_toggle = 0
/obj/machinery/netpod/post_machine_initialize()
. = ..()
disconnect_damage = BASE_DISCONNECT_DAMAGE
find_server()
RegisterSignal(src, COMSIG_ATOM_TAKE_DAMAGE, PROC_REF(on_damage_taken))
RegisterSignal(src, COMSIG_MACHINERY_POWER_LOST, PROC_REF(on_power_loss))
RegisterSignals(src, list(COMSIG_QDELETING, COMSIG_MACHINERY_BROKEN),PROC_REF(on_broken))
register_context()
update_appearance()
/obj/machinery/netpod/Destroy()
. = ..()
QDEL_LIST(cached_outfits)
/obj/machinery/netpod/add_context(atom/source, list/context, obj/item/held_item, mob/user)
. = ..()
if(isnull(held_item))
context[SCREENTIP_CONTEXT_LMB] = "Select Outfit"
else
if(held_item.tool_behaviour == TOOL_SCREWDRIVER && !occupant && !state_open)
context[SCREENTIP_CONTEXT_LMB] = "[panel_open ? "Close" : "Open"] Panel"
if(held_item.tool_behaviour == TOOL_CROWBAR)
if(isnull(occupant))
if(panel_open)
context[SCREENTIP_CONTEXT_LMB] = "Deconstruct"
else
context[SCREENTIP_CONTEXT_LMB] = "[state_open ? "Close" : "Open"] Cover"
else
context[SCREENTIP_CONTEXT_LMB] = "Break out"
context[SCREENTIP_CONTEXT_ALT_LMB] = "[copy_body ? "Disable" : "Enable"] Scan"
return CONTEXTUAL_SCREENTIP_SET
/obj/machinery/netpod/examine(mob/user)
. = ..()
. += span_notice("Its maintainance panel can be [EXAMINE_HINT("screwed")] [panel_open ? "close" : "open"].")
if(isnull(occupant))
if(panel_open)
. += span_notice("It can be [EXAMINE_HINT("pried")] apart.")
else
. += span_notice("Its hatch can be [EXAMINE_HINT("pried")] [state_open ? "closed" : "open"]")
if(isnull(server_ref?.resolve()))
. += span_infoplain("It's not connected to anything.")
. += span_infoplain("Netpods must be built within 4 tiles of a server.")
return
if(!isobserver(user))
. += span_infoplain("Drag yourself into the pod to engage the link.")
. += span_infoplain("It has limited resuscitation capabilities. Remaining in the pod can heal some injuries.")
. += span_infoplain("It has a security system that will alert the occupant if it is tampered with.")
if(copy_body)
. += span_infoplain("Occupant scanning is currently enabled, which will cause bit avatars to look like the occupant when first created.")
. += span_infoplain("Alt-click to [copy_body ? "disable" : "enable"] occupant scanning.")
if(isnull(occupant))
. += span_infoplain("It's currently unoccupied.")
return
. += span_infoplain("It's currently occupied by [occupant].")
if(isobserver(user))
. += span_notice("As an observer, you can click this netpod to jump to its avatar.")
return
. += span_notice("It can be pried open with a crowbar, but its safety mechanisms will alert the occupant.")
/obj/machinery/netpod/update_icon_state()
if(!is_operational)
icon_state = base_icon_state
return ..()
if(state_open)
icon_state = base_icon_state + "_open_active"
return ..()
if(panel_open)
icon_state = base_icon_state + "_panel"
return ..()
icon_state = base_icon_state + "_closed"
if(occupant)
icon_state += "_active"
return ..()
/obj/machinery/netpod/mouse_drop_receive(mob/target, mob/user, params)
var/mob/living/carbon/player = user
if(!iscarbon(player) || !is_operational || !state_open || player.buckled)
return
close_machine(target)
/obj/machinery/netpod/attack_hand(mob/living/user, list/modifiers)
. = ..()
if(!state_open && user == occupant)
container_resist_act(user)
/obj/machinery/netpod/attack_ghost(mob/dead/observer/our_observer)
var/our_target = avatar_ref?.resolve()
if(isnull(our_target) || !our_observer.orbit(our_target))
return ..()
/// When the server is upgraded, drops brain damage a little
/obj/machinery/netpod/proc/on_server_upgraded(obj/machinery/quantum_server/source)
SIGNAL_HANDLER
disconnect_damage = BASE_DISCONNECT_DAMAGE * (1 - source.servo_bonus)
/obj/machinery/netpod/click_alt(mob/user)
if(world.time < scanning_can_toggle)
return CLICK_ACTION_BLOCKING
copy_body = !copy_body
scanning_can_toggle = world.time + SCANNING_TOGGLE_COOLDOWN
playsound(src, 'sound/machines/click.ogg', 50, TRUE)
user.balloon_alert_to_viewers(user, "scanning [copy_body ? "enabled" : "disabled"]")
return CLICK_ACTION_SUCCESS
#undef BASE_DISCONNECT_DAMAGE
#undef SCANNING_TOGGLE_COOLDOWN