Files
Polaris/code/game/objects/items/devices/communicator/communicator.dm
Mechoid 1de8bc1c40 Industrial Expansion (#7811)
* Begins work on the Industrial expansion, ft hidden Lore

* Removed Painite, Quartz, and Void Opal from generation pending their eventual uses. Recipes modified to use them have been reverted of this use.

Fix Fix.

* Reset map to master.

* Add copper to Robotics, R&D, Engineering, and EVA.
2021-01-27 19:28:13 -09:00

366 lines
13 KiB
Plaintext

// Communicators
//
// Allows ghosts to roleplay with crewmembers without having to commit to joining the round, and also allows communications between two communicators.
var/global/list/obj/item/device/communicator/all_communicators = list()
// List of core tabs the communicator can switch to
#define HOMETAB 1
#define PHONTAB 2
#define CONTTAB 3
#define MESSTAB 4
#define NEWSTAB 5
#define NOTETAB 6
#define WTHRTAB 7
#define MANITAB 8
#define SETTTAB 9
#define EXTRTAB 10
/obj/item/device/communicator
name = "communicator"
desc = "A personal device used to enable long range dialog between two people, utilizing existing telecommunications infrastructure to allow \
communications across different stations, planets, or even star systems."
icon = 'icons/obj/device.dmi'
icon_state = "communicator"
w_class = ITEMSIZE_SMALL
slot_flags = SLOT_ID | SLOT_BELT
show_messages = 1
origin_tech = list(TECH_ENGINEERING = 2, TECH_MAGNET = 2, TECH_BLUESPACE = 2, TECH_DATA = 2)
matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 10, MAT_COPPER = 10)
var/video_range = 4
var/obj/machinery/camera/communicator/video_source // Their camera
var/obj/machinery/camera/communicator/camera // Our camera
var/list/voice_mobs = list()
var/list/voice_requests = list()
var/list/voice_invites = list()
var/list/im_contacts = list()
var/list/im_list = list()
var/note = "Thank you for choosing the T-14.2 Communicator, this is your notepad!" //Current note in the notepad function
var/notehtml = ""
var/fon = 0 // Internal light
var/flum = 2 // Brightness
var/list/modules = list(
list("module" = "Phone", "icon" = "phone64", "number" = PHONTAB),
list("module" = "Contacts", "icon" = "person64", "number" = CONTTAB),
list("module" = "Messaging", "icon" = "comment64", "number" = MESSTAB),
list("module" = "News", "icon" = "note64", "number" = NEWSTAB), // Need a different icon,
list("module" = "Note", "icon" = "note64", "number" = NOTETAB),
list("module" = "Weather", "icon" = "sun64", "number" = WTHRTAB),
list("module" = "Crew Manifest", "icon" = "note64", "number" = MANITAB), // Need a different icon,
list("module" = "Settings", "icon" = "gear64", "number" = SETTTAB),
) //list("module" = "Name of Module", "icon" = "icon name64", "number" = "what tab is the module")
var/selected_tab = HOMETAB
var/owner = ""
var/occupation = ""
var/alert_called = 0
var/obj/machinery/exonet_node/node = null //Reference to the Exonet node, to avoid having to look it up so often.
var/target_address = ""
var/target_address_name = ""
var/network_visibility = 1
var/ringer = 1
var/list/known_devices = list()
var/datum/exonet_protocol/exonet = null
var/list/communicating = list()
var/update_ticks = 0
var/newsfeed_channel = 0
// Proc: New()
// Parameters: None
// Description: Adds the new communicator to the global list of all communicators, sorts the list, obtains a reference to the Exonet node, then tries to
// assign the device to the holder's name automatically in a spectacularly shitty way.
/obj/item/device/communicator/Initialize()
. = ..()
all_communicators += src
all_communicators = sortAtom(all_communicators)
node = get_exonet_node()
START_PROCESSING(SSobj, src)
camera = new(src)
camera.name = "[src] #[rand(100,999)]"
camera.c_tag = camera.name
//This is a pretty terrible way of doing this.
addtimer(CALLBACK(src, .proc/register_to_holder), 5 SECONDS)
// Proc: register_to_holder()
// Parameters: None
// Description: Tries to register ourselves to the mob that we've presumably spawned in. Not the most amazing way of doing this.
/obj/item/device/communicator/proc/register_to_holder()
if(ismob(loc))
register_device(loc.name)
initialize_exonet(loc)
else if(istype(loc, /obj/item/weapon/storage))
var/obj/item/weapon/storage/S = loc
if(ismob(S.loc))
register_device(S.loc.name)
initialize_exonet(S.loc)
// Proc: examine()
// Parameters: user - the user doing the examining
// Description: Allows the user to click a link when examining to look at video if one is going.
/obj/item/device/communicator/examine(mob/user)
. = ..()
if(Adjacent(user) && video_source)
. += "<span class='notice'>It looks like it's on a video call: <a href='?src=\ref[src];watchvideo=1'>\[view\]</a></span>"
// Proc: initialize_exonet()
// Parameters: 1 (user - the person the communicator belongs to)
// Description: Sets up the exonet datum, gives the device an address, and then gets a node reference. Afterwards, populates the device
// list.
/obj/item/device/communicator/proc/initialize_exonet(mob/user)
if(!user || !istype(user, /mob/living))
return
if(!exonet)
exonet = new(src)
if(!exonet.address)
exonet.make_address("communicator-[user.client]-[user.name]")
if(!node)
node = get_exonet_node()
populate_known_devices()
// Proc: examine()
// Parameters: 1 (user - the person examining the device)
// Description: Shows all the voice mobs inside the device, and their status.
/obj/item/device/communicator/examine(mob/user)
. = ..()
for(var/mob/living/voice/voice in contents)
. += "<span class='notice'>On the screen, you can see a image feed of [voice].</span>"
if(voice && voice.key)
switch(voice.stat)
if(CONSCIOUS)
if(!voice.client)
. += "<span class='warning'>[voice] appears to be asleep.</span>" //afk
if(UNCONSCIOUS)
. += "<span class='warning'>[voice] doesn't appear to be conscious.</span>"
if(DEAD)
. += "<span class='deadsay'>[voice] appears to have died...</span>" //Hopefully this never has to be used.
else
. += "<span class='notice'>The device doesn't appear to be transmitting any data.</span>"
// Proc: emp_act()
// Parameters: None
// Description: Drops all calls when EMPed, so the holder can then get murdered by the antagonist.
/obj/item/device/communicator/emp_act()
close_connection(reason = "Hardware error de%#_^@%-BZZZZZZZT")
// Proc: add_to_EPv2()
// Parameters: 1 (hex - a single hexadecimal character)
// Description: Called when someone is manually dialing with nanoUI. Adds colons when appropiate.
/obj/item/device/communicator/proc/add_to_EPv2(var/hex)
var/length = length(target_address)
if(length >= 24)
return
if(length == 4 || length == 9 || length == 14 || length == 19 || length == 24 || length == 29)
target_address += ":[hex]"
return
target_address += hex
// Proc: populate_known_devices()
// Parameters: 1 (user - the person using the device)
// Description: Searches all communicators and ghosts in the world, and adds them to the known_devices list if they are 'visible'.
/obj/item/device/communicator/proc/populate_known_devices(mob/user)
if(!exonet)
exonet = new(src)
src.known_devices.Cut()
if(!get_connection_to_tcomms()) //If the network's down, we can't see anything.
return
for(var/obj/item/device/communicator/comm in all_communicators)
if(!comm || !comm.exonet || !comm.exonet.address || comm.exonet.address == src.exonet.address) //Don't add addressless devices, and don't add ourselves.
continue
src.known_devices |= comm
for(var/mob/observer/dead/O in dead_mob_list)
if(!O.client || O.client.prefs.communicator_visibility == 0)
continue
src.known_devices |= O
// Proc: get_connection_to_tcomms()
// Parameters: None
// Description: Simple check to see if the exonet node is active.
/obj/item/device/communicator/proc/get_connection_to_tcomms()
if(node && node.on && node.allow_external_communicators)
return can_telecomm(src,node)
return 0
// Proc: process()
// Parameters: None
// Description: Ticks the update_ticks variable, and checks to see if it needs to disconnect communicators every five ticks..
/obj/item/device/communicator/process()
update_ticks++
if(update_ticks % 5)
if(!node)
node = get_exonet_node()
if(!get_connection_to_tcomms())
close_connection(reason = "Connection timed out")
// Proc: attackby()
// Parameters: 2 (C - what is used on the communicator. user - the mob that has the communicator)
// Description: When an ID is swiped on the communicator, the communicator reads the job and checks it against the Owner name, if success, the occupation is added.
/obj/item/device/communicator/attackby(obj/item/C as obj, mob/user as mob)
..()
if(istype(C, /obj/item/weapon/card/id))
var/obj/item/weapon/card/id/idcard = C
if(!idcard.registered_name || !idcard.assignment)
to_chat(user, "<span class='notice'>\The [src] rejects the ID.</span>")
else if(!owner)
to_chat(user, "<span class='notice'>\The [src] rejects the ID.</span>")
else if(owner == idcard.registered_name)
occupation = idcard.assignment
to_chat(user, "<span class='notice'>Occupation updated.</span>")
return
// Proc: attack_self()
// Parameters: 1 (user - the mob that clicked the device in their hand)
// Description: Makes an exonet datum if one does not exist, allocates an address for it, maintains the lists of all devies, clears the alert icon, and
// finally makes NanoUI appear.
/obj/item/device/communicator/attack_self(mob/user)
initialize_exonet(user)
alert_called = 0
update_icon()
ui_interact(user)
if(video_source)
watch_video(user)
// Proc: MouseDrop()
//Same thing PDAs do
/obj/item/device/communicator/MouseDrop(obj/over_object as obj)
var/mob/M = usr
if (!(src.loc == usr) || (src.loc && src.loc.loc == usr))
return
if(!istype(over_object, /obj/screen))
return attack_self(M)
return
// Proc: attack_ghost()
// Parameters: 1 (user - the ghost clicking on the device)
// Description: Recreates the known_devices list, so that the ghost looking at the device can see themselves, then calls ..() so that NanoUI appears.
/obj/item/device/communicator/attack_ghost(mob/user)
populate_known_devices() //Update the devices so ghosts can see the list on NanoUI.
..()
/mob/observer/dead
var/datum/exonet_protocol/exonet = null
var/list/exonet_messages = list()
// Proc: New()
// Parameters: None
// Description: Gives ghosts an exonet address based on their key and ghost name.
/mob/observer/dead/Initialize()
. = ..()
exonet = new(src)
if(client)
exonet.make_address("communicator-[src.client]-[src.client.prefs.real_name]")
else
exonet.make_address("communicator-[key]-[src.real_name]")
// Proc: Destroy()
// Parameters: None
// Description: Removes the ghost's address and nulls the exonet datum, to allow qdel()ing.
/mob/observer/dead/Destroy()
. = ..()
if(exonet)
exonet.remove_address()
exonet = null
return ..()
// Proc: register_device()
// Parameters: 1 (user - the person to use their name for)
// Description: Updates the owner's name and the device's name.
/obj/item/device/communicator/proc/register_device(new_name)
if(!new_name)
return
owner = new_name
name = "[new_name]'s [initial(name)]"
if(camera)
camera.name = name
camera.c_tag = name
// Proc: Destroy()
// Parameters: None
// Description: Deletes all the voice mobs, disconnects all linked communicators, and cuts lists to allow successful qdel()
/obj/item/device/communicator/Destroy()
for(var/mob/living/voice/voice in contents)
voice_mobs.Remove(voice)
to_chat(voice, "<span class='danger'>[bicon(src)] Connection timed out with remote host.</span>")
qdel(voice)
close_connection(reason = "Connection timed out")
//Clean up all references we might have to others
communicating.Cut()
voice_requests.Cut()
voice_invites.Cut()
node = null
//Clean up references that might point at us
all_communicators -= src
STOP_PROCESSING(SSobj, src)
listening_objects.Remove(src)
QDEL_NULL(camera)
QDEL_NULL(exonet)
return ..()
// Proc: update_icon()
// Parameters: None
// Description: Self explanatory
/obj/item/device/communicator/update_icon()
if(video_source)
icon_state = "communicator-video"
return
if(voice_mobs.len || communicating.len)
icon_state = "communicator-active"
return
if(alert_called)
icon_state = "communicator-called"
return
icon_state = initial(icon_state)
// A camera preset for spawning in the communicator
/obj/machinery/camera/communicator
network = list(NETWORK_COMMUNICATORS)
/obj/machinery/camera/communicator/New()
..()
client_huds |= global_hud.whitense
client_huds |= global_hud.darkMask
//It's the 26th century. We should have smart watches by now.
/obj/item/device/communicator/watch
name = "communicator watch"
desc = "A personal device used to enable long range dialog between two people, utilizing existing telecommunications infrastructure to allow \
communications across different stations, planets, or even star systems. You can wear this one on your wrist!"
icon = 'icons/obj/device.dmi'
icon_state = "commwatch"
slot_flags = SLOT_GLOVES
/obj/item/device/communicator/watch/update_icon()
if(video_source)
icon_state = "commwatch-video"
return
if(voice_mobs.len || communicating.len)
icon_state = "commwatch-active"
return
if(alert_called)
icon_state = "commwatch-called"
return
icon_state = initial(icon_state)