diff --git a/code/__defines/machinery.dm b/code/__defines/machinery.dm
index 1f65364e1ae..cc77b8c3c59 100644
--- a/code/__defines/machinery.dm
+++ b/code/__defines/machinery.dm
@@ -50,6 +50,7 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called
#define NETWORK_SECURITY "Security"
#define NETWORK_TELECOM "Tcomsat"
#define NETWORK_THUNDER "Thunderdome"
+#define NETWORK_COMMUNICATORS "Communicators"
// Those networks can only be accessed by pre-existing terminals. AIs and new terminals can't use them.
var/list/restricted_camera_networks = list(NETWORK_ERT,NETWORK_MERCENARY,"Secret")
diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm
index 0858ebc1a40..1e14d391833 100644
--- a/code/_helpers/unsorted.dm
+++ b/code/_helpers/unsorted.dm
@@ -1257,7 +1257,7 @@ var/list/WALLITEMS = list(
arglist = list2params(arglist)
return "[content]"
-/proc/get_random_colour(var/simple, var/lower, var/upper)
+/proc/get_random_colour(var/simple, var/lower=0, var/upper=255)
var/colour
if(simple)
colour = pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index 291b9852949..7c466514194 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -35,10 +35,13 @@
var/affected_by_emp_until = 0
+ var/client_huds = list()
+
/obj/machinery/camera/New()
wires = new(src)
assembly = new(src)
assembly.state = 4
+ client_huds |= global_hud.whitense
/* // Use this to look for cameras that have the same c_tag.
for(var/obj/machinery/camera/C in cameranet.cameras)
diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm
index ea730a4a9ff..c9350bd3d1d 100644
--- a/code/game/machinery/camera/presets.dm
+++ b/code/game/machinery/camera/presets.dm
@@ -17,7 +17,8 @@ var/global/list/station_networks = list(
NETWORK_RESEARCH_OUTPOST,
NETWORK_ROBOTS,
NETWORK_PRISON,
- NETWORK_SECURITY
+ NETWORK_SECURITY,
+ NETWORK_COMMUNICATORS
)
var/global/list/engineering_networks = list(
NETWORK_ENGINE,
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index b0f1460249a..0f3ff025b95 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -741,7 +741,8 @@
/obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask = 8,
/obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar = 8,
/obj/item/weapon/reagent_containers/food/snacks/liquidfood = 8,
- /obj/item/weapon/reagent_containers/pill/diet = 8)
+ /obj/item/weapon/reagent_containers/pill/diet = 8,
+ /obj/item/weapon/towel/random = 8)
prices = list(/obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton = 3,
/obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton/chocolate = 3,
@@ -749,7 +750,8 @@
/obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask = 5,
/obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar = 5,
/obj/item/weapon/reagent_containers/food/snacks/liquidfood = 5,
- /obj/item/weapon/reagent_containers/pill/diet = 25)
+ /obj/item/weapon/reagent_containers/pill/diet = 25,
+ /obj/item/weapon/towel/random = 40)
contraband = list(/obj/item/weapon/reagent_containers/syringe/steroid = 4)
diff --git a/code/game/objects/items/devices/communicator/communicator.dm b/code/game/objects/items/devices/communicator/communicator.dm
index 9b62767eb85..97e856e27ab 100644
--- a/code/game/objects/items/devices/communicator/communicator.dm
+++ b/code/game/objects/items/devices/communicator/communicator.dm
@@ -18,6 +18,8 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 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()
@@ -63,6 +65,9 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
all_communicators = sortAtom(all_communicators)
node = get_exonet_node()
processing_objects |= src
+ camera = new(src)
+ camera.name = "[src] #[rand(100,999)]"
+ camera.c_tag = camera.name
//This is a pretty terrible way of doing this.
spawn(5 SECONDS) //Wait for our mob to finish spawning.
if(ismob(loc))
@@ -74,6 +79,14 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
register_device(S.loc)
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)
+ . = ..(user, 1)
+ if(. && video_source)
+ user << "It looks like it's on a video call: \[view\]"
+
// 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
@@ -257,27 +270,27 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
//Now for ghosts who we pretend have communicators.
for(var/mob/observer/dead/O in known_devices)
if(O.client && O.client.prefs.communicator_visibility == 1 && O.exonet)
- communicators[++communicators.len] = list("name" = sanitize("[O.client.prefs.real_name]'s communicator"), "address" = O.exonet.address)
+ communicators[++communicators.len] = list("name" = sanitize("[O.client.prefs.real_name]'s communicator"), "address" = O.exonet.address, "ref" = "\ref[O]")
//Lists all the other communicators that we invited.
for(var/obj/item/device/communicator/comm in voice_invites)
if(comm.exonet)
- invites[++invites.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address)
+ invites[++invites.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address, "ref" = "\ref[comm]")
//Ghosts we invited.
for(var/mob/observer/dead/O in voice_invites)
if(O.exonet && O.client)
- invites[++invites.len] = list("name" = sanitize("[O.client.prefs.real_name]'s communicator"), "address" = O.exonet.address)
+ invites[++invites.len] = list("name" = sanitize("[O.client.prefs.real_name]'s communicator"), "address" = O.exonet.address, "ref" = "\ref[O]")
//Communicators that want to talk to us.
for(var/obj/item/device/communicator/comm in voice_requests)
if(comm.exonet)
- requests[++requests.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address)
+ requests[++requests.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address, "ref" = "\ref[comm]")
//Ghosts that want to talk to us.
for(var/mob/observer/dead/O in voice_requests)
if(O.exonet && O.client)
- requests[++requests.len] = list("name" = sanitize("[O.client.prefs.real_name]'s communicator"), "address" = O.exonet.address)
+ requests[++requests.len] = list("name" = sanitize("[O.client.prefs.real_name]'s communicator"), "address" = O.exonet.address, "ref" = "\ref[O]")
//Now for all the voice mobs inside the communicator.
for(var/mob/living/voice/voice in contents)
@@ -285,12 +298,12 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
//Finally, all the communicators linked to this one.
for(var/obj/item/device/communicator/comm in communicating)
- connected_communicators[++connected_communicators.len] = list("name" = sanitize(comm.name), "true_name" = sanitize(comm.name))
+ connected_communicators[++connected_communicators.len] = list("name" = sanitize(comm.name), "true_name" = sanitize(comm.name), "ref" = "\ref[comm]")
//Devices that have been messaged or recieved messages from.
for(var/obj/item/device/communicator/comm in im_contacts)
if(comm.exonet)
- im_contacts_ui[++im_contacts_ui.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address)
+ im_contacts_ui[++im_contacts_ui.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address, "ref" = "\ref[comm]")
//Actual messages.
for(var/I in im_list)
@@ -313,6 +326,7 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
data["requestsReceived"] = requests
data["voice_mobs"] = voices
data["communicating"] = connected_communicators
+ data["video_comm"] = video_source ? "\ref[video_source.loc]" : null
data["imContacts"] = im_contacts_ui
data["imList"] = im_list_ui
data["time"] = worldtime2text()
@@ -325,7 +339,7 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
if(!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
- ui = new(user, src, ui_key, "communicator.tmpl", "Communicator", 450, 700)
+ ui = new(user, src, ui_key, "communicator.tmpl", "Communicator", 475, 700)
// when the ui is first opened this is the data it will use
ui.set_initial_data(data)
// open the new ui window
@@ -344,9 +358,20 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
if(new_name)
owner = new_name
name = "[owner]'s [initial(name)]"
+ if(camera)
+ camera.name = name
+ camera.c_tag = name
if(href_list["toggle_visibility"])
- network_visibility = !network_visibility
+ switch(network_visibility)
+ if(1) //Visible, becoming invisbile
+ network_visibility = 0
+ if(camera)
+ camera.remove_network(NETWORK_COMMUNICATORS)
+ if(0) //Invisible, becoming visible
+ network_visibility = 1
+ if(camera)
+ camera.add_network(NETWORK_COMMUNICATORS)
if(href_list["toggle_ringer"])
ringer = !ringer
@@ -371,6 +396,12 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
var/their_address = href_list["dial"]
exonet.send_message(their_address, "voice")
+ if(href_list["decline"])
+ var/ref_to_remove = href_list["decline"]
+ var/atom/decline = locate(ref_to_remove)
+ if(decline)
+ del_request(decline)
+
if(href_list["message"])
if(!get_connection_to_tcomms())
usr << "Error: Cannot connect to Exonet node."
@@ -385,10 +416,24 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
var/name_to_disconnect = href_list["disconnect"]
for(var/mob/living/voice/V in contents)
if(name_to_disconnect == V.name)
- close_connection(usr, V, "[usr] hung up.")
+ close_connection(usr, V, "[usr] hung up")
for(var/obj/item/device/communicator/comm in communicating)
if(name_to_disconnect == comm.name)
- close_connection(usr, comm, "[usr] hung up.")
+ close_connection(usr, comm, "[usr] hung up")
+
+ if(href_list["startvideo"])
+ var/ref_to_video = href_list["startvideo"]
+ var/obj/item/device/communicator/comm = locate(ref_to_video)
+ if(comm)
+ connect_video(usr, comm)
+
+ if(href_list["endvideo"])
+ if(video_source)
+ end_video()
+
+ if(href_list["watchvideo"])
+ if(video_source)
+ watch_video(usr,video_source.loc)
if(href_list["copy"])
target_address = href_list["copy"]
@@ -398,9 +443,9 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
if(href_list["hang_up"])
for(var/mob/living/voice/V in contents)
- close_connection(usr, V, "[usr] hung up.")
+ close_connection(usr, V, "[usr] hung up")
for(var/obj/item/device/communicator/comm in communicating)
- close_connection(usr, comm, "[usr] hung up.")
+ close_connection(usr, comm, "[usr] hung up")
if(href_list["switch_tab"])
selected_tab = href_list["switch_tab"]
@@ -475,7 +520,9 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
owner = user.name
name = "[owner]'s [initial(name)]"
-
+ if(camera)
+ camera.name = name
+ camera.c_tag = name
// Proc: add_communicating()
// Parameters: 1 (comm - the communicator to add to communicating)
@@ -485,6 +532,7 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
communicating |= comm
listening_objects |= src
+ update_icon()
// Proc: del_communicating()
// Parameters: 1 (comm - the communicator to remove from communicating)
@@ -493,6 +541,7 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
if(!comm || !istype(comm)) return
communicating.Remove(comm)
+ update_icon()
// Proc: open_connection()
// Parameters: 2 (user - the person who initiated the connecting being opened, candidate - the communicator or observer that will connect to the device)
@@ -601,15 +650,19 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
visible_message("\icon[src] [reason].")
voice_mobs.Remove(voice)
qdel(voice)
+ update_icon()
for(var/obj/item/device/communicator/comm in communicating) //Now we handle real communicators.
if(target && comm != target)
continue
- comm.visible_message("\icon[src] [reason].")
- visible_message("\icon[src] [reason].")
src.del_communicating(comm)
comm.del_communicating(src)
- update_icon()
+ comm.visible_message("\icon[src] [reason].")
+ visible_message("\icon[src] [reason].")
+ if(comm.camera && video_source == comm.camera) //We hung up on the person on video
+ end_video()
+ if(camera && comm.video_source == camera) //We hung up on them while they were watching us
+ comm.end_video()
if(voice_mobs.len == 0 && communicating.len == 0)
listening_objects.Remove(src)
@@ -649,6 +702,29 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
if(L)
L << "\icon[src] Communications request from [who]."
+// Proc: del_request()
+// Parameters: 1 (candidate - the ghost or communicator to be declined)
+// Description: Declines a request and cleans up both ends
+/obj/item/device/communicator/proc/del_request(var/atom/candidate)
+ if(!(candidate in voice_requests))
+ return
+
+ if(isobserver(candidate))
+ candidate << "Your communicator call request was declined."
+ else if(istype(candidate, /obj/item/device/communicator))
+ var/obj/item/device/communicator/comm = candidate
+ comm.voice_invites -= src
+
+ voice_requests -= candidate
+
+ //Search for holder of our device.
+ var/mob/living/us = null
+ if(loc && isliving(loc))
+ us = loc
+
+ if(us)
+ us << "\icon[src] Declined request."
+
// Proc: request_im()
// Parameters: 3 (candidate - the communicator wanting to message the device, origin_address - the address of the sender, text - the message)
// Description: Response to a communicator trying to message the device.
@@ -700,6 +776,8 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
all_communicators -= src
processing_objects -= src
listening_objects.Remove(src)
+ qdel(camera)
+ camera = null
if(exonet)
exonet.remove_address()
exonet = null
@@ -709,7 +787,11 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
// Parameters: None
// Description: Self explanatory
/obj/item/device/communicator/update_icon()
- if(voice_mobs.len > 0)
+ if(video_source)
+ icon_state = "communicator-video"
+ return
+
+ if(voice_mobs.len || communicating.len)
icon_state = "communicator-active"
return
@@ -833,7 +915,71 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
src << "A communications request has been sent to [chosen_communicator]. Now you need to wait until someone answers."
-/obj/item/device/communicator/integrated //For synths who have no hands.
+// Proc: connect_video()
+// Parameters: user - the mob doing the viewing of video, comm - the communicator at the far end
+// Description: Sets up a videocall and puts the first view into it using watch_video, and updates the icon
+/obj/item/device/communicator/proc/connect_video(mob/user,obj/item/device/communicator/comm)
+ if((!user) || (!comm) || user.stat) return //KO or dead, or already in a video
+
+ if(video_source) //Already in a video
+ user << "You are already connected to a video call!"
+
+ if(user.blinded) //User is blinded
+ user << "You cannot see well enough to do that!"
+
+ if(!(src in comm.communicating) || !comm.camera) //You called someone with a broken communicator or one that's fake or yourself or something
+ user << "\icon[src]ERROR: Video failed. Either bandwidth is too low, or the other communicator is malfunctioning."
+
+ user << "\icon[src] Attempting to start video over existing call."
+ sleep(30)
+ user << "\icon[src] Please wait..."
+
+ video_source = comm.camera
+ comm.visible_message("\icon[src] New video connection from [comm].")
+ watch_video(user)
+ update_icon()
+
+// Proc: watch_video()
+// Parameters: user - the mob doing the viewing of video
+// Description: Moves a mob's eye to the far end for the duration of viewing the far end
+/obj/item/device/communicator/proc/watch_video(mob/user)
+ if(!Adjacent(user) || !video_source) return
+ user.set_machine(video_source)
+ user.reset_view(video_source)
+ user << "Now viewing video session. To leave camera view: OOC -> Cancel Camera View"
+ spawn(0)
+ while(user.machine == video_source && Adjacent(user))
+ var/turf/T = get_turf(video_source)
+ if(!T || !is_on_same_plane_or_station(T.z, user.z) || !video_source.can_use())
+ user << "The screen bursts into static, then goes black."
+ video_cleanup(user)
+ return
+ sleep(10)
+
+ video_cleanup(user)
+
+// Proc: video_cleanup()
+// Parameters: user - the mob who doesn't want to see video anymore
+// Description: Cleans up mob's client when they stop watching a video
+/obj/item/device/communicator/proc/video_cleanup(mob/user)
+ if(!user) return
+
+ user.reset_view(null)
+ user.unset_machine()
+
+// Proc: end_video()
+// Parameters: reason - the text reason to print for why it ended
+// Description: Ends the video call by clearing video_source
+/obj/item/device/communicator/proc/end_video(var/reason)
+ video_source = null
+
+ . = "\icon[src] [reason ? reason : "Video session ended"]."
+
+ visible_message(.)
+ update_icon()
+
+//For synths who have no hands.
+/obj/item/device/communicator/integrated
name = "integrated communicator"
desc = "A circuit used for long-range communications, able to be integrated into a system."
@@ -864,3 +1010,12 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
return
src.attack_self(usr)
+
+// 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
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/towels.dm b/code/game/objects/items/weapons/towels.dm
index 94c266142e5..d51cc8d1d06 100644
--- a/code/game/objects/items/weapons/towels.dm
+++ b/code/game/objects/items/weapons/towels.dm
@@ -12,3 +12,7 @@
/obj/item/weapon/towel/attack_self(mob/living/user as mob)
user.visible_message(text("[] uses [] to towel themselves off.", user, src))
playsound(user, 'sound/weapons/towelwipe.ogg', 25, 1)
+
+/obj/item/weapon/towel/random/New()
+ ..()
+ color = "#"+get_random_colour()
\ No newline at end of file
diff --git a/code/modules/client/preference_setup/antagonism/01_basic.dm b/code/modules/client/preference_setup/antagonism/01_basic.dm
index eefc531da15..5b0be7bb71f 100644
--- a/code/modules/client/preference_setup/antagonism/01_basic.dm
+++ b/code/modules/client/preference_setup/antagonism/01_basic.dm
@@ -15,6 +15,10 @@ var/global/list/uplink_locations = list("PDA", "Headset", "None")
/datum/category_item/player_setup_item/antagonism/basic/sanitize_character()
pref.uplinklocation = sanitize_inlist(pref.uplinklocation, uplink_locations, initial(pref.uplinklocation))
+// Moved from /datum/preferences/proc/copy_to()
+/datum/category_item/player_setup_item/antagonism/basic/copy_to_mob(var/mob/living/carbon/human/character)
+ character.exploit_record = pref.exploit_record
+
/datum/category_item/player_setup_item/antagonism/basic/content(var/mob/user)
. +="Uplink Type : [pref.uplinklocation]"
. +="
"
diff --git a/code/modules/client/preference_setup/general/01_basic.dm b/code/modules/client/preference_setup/general/01_basic.dm
index 6a0c0705aec..da1cab4ecc9 100644
--- a/code/modules/client/preference_setup/general/01_basic.dm
+++ b/code/modules/client/preference_setup/general/01_basic.dm
@@ -40,6 +40,25 @@ datum/preferences/proc/set_biological_gender(var/gender)
pref.spawnpoint = sanitize_inlist(pref.spawnpoint, spawntypes, initial(pref.spawnpoint))
pref.be_random_name = sanitize_integer(pref.be_random_name, 0, 1, initial(pref.be_random_name))
+// Moved from /datum/preferences/proc/copy_to()
+/datum/category_item/player_setup_item/general/basic/copy_to_mob(var/mob/living/carbon/human/character)
+ if(config.humans_need_surnames)
+ var/firstspace = findtext(pref.real_name, " ")
+ var/name_length = length(pref.real_name)
+ if(!firstspace) //we need a surname
+ pref.real_name += " [pick(last_names)]"
+ else if(firstspace == name_length)
+ pref.real_name += "[pick(last_names)]"
+
+ character.real_name = pref.real_name
+ character.name = character.real_name
+ if(character.dna)
+ character.dna.real_name = character.real_name
+
+ character.gender = pref.biological_gender
+ character.identifying_gender = pref.identifying_gender
+ character.age = pref.age
+
/datum/category_item/player_setup_item/general/basic/content()
. = list()
. += "Name: "
diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm
index a092b859b31..8bd528cb5d6 100644
--- a/code/modules/client/preference_setup/general/03_body.dm
+++ b/code/modules/client/preference_setup/general/03_body.dm
@@ -76,6 +76,53 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
if(!pref.organ_data) pref.organ_data = list()
if(!pref.rlimb_data) pref.rlimb_data = list()
+// Moved from /datum/preferences/proc/copy_to()
+/datum/category_item/player_setup_item/general/body/copy_to_mob(var/mob/living/carbon/human/character)
+ // Copy basic values
+ character.r_eyes = pref.r_eyes
+ character.g_eyes = pref.g_eyes
+ character.b_eyes = pref.b_eyes
+ character.h_style = pref.h_style
+ character.r_hair = pref.r_hair
+ character.g_hair = pref.g_hair
+ character.b_hair = pref.b_hair
+ character.f_style = pref.f_style
+ character.r_facial = pref.r_facial
+ character.g_facial = pref.g_facial
+ character.b_facial = pref.b_facial
+ character.r_skin = pref.r_skin
+ character.g_skin = pref.g_skin
+ character.b_skin = pref.b_skin
+ character.s_tone = pref.s_tone
+ character.h_style = pref.h_style
+ character.f_style = pref.f_style
+ character.b_type = pref.b_type
+
+ // Destroy/cyborgize organs and limbs.
+ for(var/name in list(BP_HEAD, BP_L_HAND, BP_R_HAND, BP_L_ARM, BP_R_ARM, BP_L_FOOT, BP_R_FOOT, BP_L_LEG, BP_R_LEG, BP_GROIN, BP_TORSO))
+ var/status = pref.organ_data[name]
+ var/obj/item/organ/external/O = character.organs_by_name[name]
+ if(O)
+ if(status == "amputated")
+ O.remove_rejuv()
+ else if(status == "cyborg")
+ if(pref.rlimb_data[name])
+ O.robotize(pref.rlimb_data[name])
+ else
+ O.robotize()
+
+ for(var/name in list(O_HEART,O_EYES,O_BRAIN))
+ var/status = pref.organ_data[name]
+ if(!status)
+ continue
+ var/obj/item/organ/I = character.internal_organs_by_name[name]
+ if(I)
+ if(status == "assisted")
+ I.mechassist()
+ else if(status == "mechanical")
+ I.robotize()
+ return
+
/datum/category_item/player_setup_item/general/body/content(var/mob/user)
. = list()
if(!pref.preview_icon)
diff --git a/code/modules/client/preference_setup/general/04_equipment.dm b/code/modules/client/preference_setup/general/04_equipment.dm
index c455cef524a..537f2632e73 100644
--- a/code/modules/client/preference_setup/general/04_equipment.dm
+++ b/code/modules/client/preference_setup/general/04_equipment.dm
@@ -18,6 +18,30 @@
S["backbag"] << pref.backbag
S["pdachoice"] << pref.pdachoice
+// Moved from /datum/preferences/proc/copy_to()
+/datum/category_item/player_setup_item/general/equipment/copy_to_mob(var/mob/living/carbon/human/character)
+ character.all_underwear.Cut()
+ character.all_underwear_metadata.Cut()
+
+ for(var/underwear_category_name in pref.all_underwear)
+ var/datum/category_group/underwear/underwear_category = global_underwear.categories_by_name[underwear_category_name]
+ if(underwear_category)
+ var/underwear_item_name = pref.all_underwear[underwear_category_name]
+ character.all_underwear[underwear_category_name] = underwear_category.items_by_name[underwear_item_name]
+ if(pref.all_underwear_metadata[underwear_category_name])
+ character.all_underwear_metadata[underwear_category_name] = pref.all_underwear_metadata[underwear_category_name]
+ else
+ pref.all_underwear -= underwear_category_name
+
+ // TODO - Looks like this is duplicating the work of sanitize_character() if so, remove
+ if(pref.backbag > 4 || pref.backbag < 1)
+ pref.backbag = 1 //Same as above
+ character.backbag = pref.backbag
+
+ if(pref.pdachoice > 3 || pref.pdachoice < 1)
+ pref.pdachoice = 1
+ character.pdachoice = pref.pdachoice
+
/datum/category_item/player_setup_item/general/equipment/sanitize_character()
if(!islist(pref.gear)) pref.gear = list()
diff --git a/code/modules/client/preference_setup/general/05_background.dm b/code/modules/client/preference_setup/general/05_background.dm
index 5708d3c757e..e3076629a8e 100644
--- a/code/modules/client/preference_setup/general/05_background.dm
+++ b/code/modules/client/preference_setup/general/05_background.dm
@@ -30,6 +30,16 @@
pref.nanotrasen_relation = sanitize_inlist(pref.nanotrasen_relation, COMPANY_ALIGNMENTS, initial(pref.nanotrasen_relation))
+// Moved from /datum/preferences/proc/copy_to()
+/datum/category_item/player_setup_item/general/background/copy_to_mob(var/mob/living/carbon/human/character)
+ character.med_record = pref.med_record
+ character.sec_record = pref.sec_record
+ character.gen_record = pref.gen_record
+ character.home_system = pref.home_system
+ character.citizenship = pref.citizenship
+ character.personal_faction = pref.faction
+ character.religion = pref.religion
+
/datum/category_item/player_setup_item/general/background/content(var/mob/user)
. += "Background Information
"
. += "[company_name] Relation: [pref.nanotrasen_relation]
"
diff --git a/code/modules/client/preference_setup/general/06_flavor.dm b/code/modules/client/preference_setup/general/06_flavor.dm
index b312bb95e9b..94525ee06ff 100644
--- a/code/modules/client/preference_setup/general/06_flavor.dm
+++ b/code/modules/client/preference_setup/general/06_flavor.dm
@@ -36,6 +36,18 @@
/datum/category_item/player_setup_item/general/flavor/sanitize_character()
return
+// Moved from /datum/preferences/proc/copy_to()
+/datum/category_item/player_setup_item/general/flavor/copy_to_mob(var/mob/living/carbon/human/character)
+ character.flavor_texts["general"] = pref.flavor_texts["general"]
+ character.flavor_texts["head"] = pref.flavor_texts["head"]
+ character.flavor_texts["face"] = pref.flavor_texts["face"]
+ character.flavor_texts["eyes"] = pref.flavor_texts["eyes"]
+ character.flavor_texts["torso"] = pref.flavor_texts["torso"]
+ character.flavor_texts["arms"] = pref.flavor_texts["arms"]
+ character.flavor_texts["hands"] = pref.flavor_texts["hands"]
+ character.flavor_texts["legs"] = pref.flavor_texts["legs"]
+ character.flavor_texts["feet"] = pref.flavor_texts["feet"]
+
/datum/category_item/player_setup_item/general/flavor/content(var/mob/user)
. += "Flavor:
"
. += "Set Flavor Text
"
diff --git a/code/modules/client/preference_setup/preference_setup.dm b/code/modules/client/preference_setup/preference_setup.dm
index 7028894fda4..6344d538e7c 100644
--- a/code/modules/client/preference_setup/preference_setup.dm
+++ b/code/modules/client/preference_setup/preference_setup.dm
@@ -72,6 +72,10 @@
for(var/datum/category_group/player_setup_category/PS in categories)
PS.save_preferences(S)
+/datum/category_collection/player_setup_collection/proc/copy_to_mob(var/mob/living/carbon/human/C)
+ for(var/datum/category_group/player_setup_category/PS in categories)
+ PS.copy_to_mob(C)
+
/datum/category_collection/player_setup_collection/proc/header()
var/dat = ""
for(var/datum/category_group/player_setup_category/PS in categories)
@@ -143,6 +147,10 @@
for(var/datum/category_item/player_setup_item/PI in items)
PI.save_preferences(S)
+/datum/category_group/player_setup_category/proc/copy_to_mob(var/mob/living/carbon/human/C)
+ for(var/datum/category_item/player_setup_item/PI in items)
+ PI.copy_to_mob(C)
+
/datum/category_group/player_setup_category/proc/content(var/mob/user)
. = "
| "
var/current = 0
@@ -201,6 +209,12 @@
/datum/category_item/player_setup_item/proc/save_preferences(var/savefile/S)
return
+/*
+* Called when the item is asked to apply its per character settings to a new mob.
+*/
+/datum/category_item/player_setup_item/proc/copy_to_mob(var/mob/living/carbon/human/C)
+ return
+
/datum/category_item/player_setup_item/proc/content()
return
diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm
index 7255e25bc46..ab5a6c17e10 100644
--- a/code/modules/client/preference_setup/skills/skills.dm
+++ b/code/modules/client/preference_setup/skills/skills.dm
@@ -18,6 +18,11 @@
if(!pref.skills.len) pref.ZeroSkills()
if(pref.used_skillpoints < 0) pref.used_skillpoints = 0
+// Moved from /datum/preferences/proc/copy_to()
+/datum/category_item/player_setup_item/skills/copy_to_mob(var/mob/living/carbon/human/character)
+ character.skills = pref.skills
+ character.used_skillpoints = pref.used_skillpoints
+
/datum/category_item/player_setup_item/skills/content()
. = list()
. += "Select your Skills " diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index c26bde7fa0c..6600b78c830 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -254,123 +254,14 @@ datum/preferences // Sanitizing rather than saving as someone might still be editing when copy_to occurs. player_setup.sanitize_setup() - // VOREStation Edit - Start - player_setup.copy_to_mob(character) - // VOREStation Edit - End - + // This needs to happen before anything else becuase it sets some variables. character.set_species(species) - + // Special Case: This references variables owned by two different datums, so do it here. if(be_random_name) real_name = random_name(identifying_gender,species) - if(config.humans_need_surnames) - var/firstspace = findtext(real_name, " ") - var/name_length = length(real_name) - if(!firstspace) //we need a surname - real_name += " [pick(last_names)]" - else if(firstspace == name_length) - real_name += "[pick(last_names)]" - - character.real_name = real_name - character.name = character.real_name - if(character.dna) - character.dna.real_name = character.real_name - - character.flavor_texts["general"] = flavor_texts["general"] - character.flavor_texts["head"] = flavor_texts["head"] - character.flavor_texts["face"] = flavor_texts["face"] - character.flavor_texts["eyes"] = flavor_texts["eyes"] - character.flavor_texts["torso"] = flavor_texts["torso"] - character.flavor_texts["arms"] = flavor_texts["arms"] - character.flavor_texts["hands"] = flavor_texts["hands"] - character.flavor_texts["legs"] = flavor_texts["legs"] - character.flavor_texts["feet"] = flavor_texts["feet"] - - character.med_record = med_record - character.sec_record = sec_record - character.gen_record = gen_record - character.exploit_record = exploit_record - - character.gender = biological_gender - character.identifying_gender = identifying_gender - character.age = age - character.b_type = b_type - - character.r_eyes = r_eyes - character.g_eyes = g_eyes - character.b_eyes = b_eyes - - character.h_style = h_style - character.r_hair = r_hair - character.g_hair = g_hair - character.b_hair = b_hair - - character.f_style = f_style - character.r_facial = r_facial - character.g_facial = g_facial - character.b_facial = b_facial - - character.r_skin = r_skin - character.g_skin = g_skin - character.b_skin = b_skin - - character.s_tone = s_tone - - character.h_style = h_style - character.f_style = f_style - - character.home_system = home_system - character.citizenship = citizenship - character.personal_faction = faction - character.religion = religion - - character.skills = skills - character.used_skillpoints = used_skillpoints - - // Destroy/cyborgize organs and limbs. - for(var/name in list(BP_HEAD, BP_L_HAND, BP_R_HAND, BP_L_ARM, BP_R_ARM, BP_L_FOOT, BP_R_FOOT, BP_L_LEG, BP_R_LEG, BP_GROIN, BP_TORSO)) - var/status = organ_data[name] - var/obj/item/organ/external/O = character.organs_by_name[name] - if(O) - if(status == "amputated") - O.remove_rejuv() - else if(status == "cyborg") - if(rlimb_data[name]) - O.robotize(rlimb_data[name]) - else - O.robotize() - - for(var/name in list(O_HEART,O_EYES,O_BRAIN)) - var/status = organ_data[name] - if(!status) - continue - var/obj/item/organ/I = character.internal_organs_by_name[name] - if(I) - if(status == "assisted") - I.mechassist() - else if(status == "mechanical") - I.robotize() - - character.all_underwear.Cut() - character.all_underwear_metadata.Cut() - - for(var/underwear_category_name in all_underwear) - var/datum/category_group/underwear/underwear_category = global_underwear.categories_by_name[underwear_category_name] - if(underwear_category) - var/underwear_item_name = all_underwear[underwear_category_name] - character.all_underwear[underwear_category_name] = underwear_category.items_by_name[underwear_item_name] - if(all_underwear_metadata[underwear_category_name]) - character.all_underwear_metadata[underwear_category_name] = all_underwear_metadata[underwear_category_name] - else - all_underwear -= underwear_category_name - - if(backbag > 4 || backbag < 1) - backbag = 1 //Same as above - character.backbag = backbag - - if(pdachoice > 3 || pdachoice < 1) - pdachoice = 1 - character.pdachoice = pdachoice + // Ask the preferences datums to apply their own settings to the new mob + player_setup.copy_to_mob(character) if(icon_updates) character.force_update_limbs() diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index d61ab57048a..b669647ec93 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -1050,7 +1050,11 @@ if(copytext(hud.icon_state,1,4) == "hud") //ugly, but icon comparison is worse, I believe client.images.Remove(hud) - client.screen.Remove(global_hud.blurry, global_hud.druggy, global_hud.vimpaired, global_hud.darkMask, global_hud.nvg, global_hud.thermal, global_hud.meson, global_hud.science) + client.screen.Remove(global_hud.blurry, global_hud.druggy, global_hud.vimpaired, global_hud.darkMask, global_hud.nvg, global_hud.thermal, global_hud.meson, global_hud.science, global_hud.whitense) + + if(istype(client.eye,/obj/machinery/camera)) + var/obj/machinery/camera/cam = client.eye + client.screen |= cam.client_huds if(damageoverlay.overlays) damageoverlay.overlays = list() diff --git a/code/modules/reagents/reagent_containers/food/drinks.dm b/code/modules/reagents/reagent_containers/food/drinks.dm index 69472021b84..f2770d98237 100644 --- a/code/modules/reagents/reagent_containers/food/drinks.dm +++ b/code/modules/reagents/reagent_containers/food/drinks.dm @@ -132,7 +132,7 @@ reagents.add_reagent("soymilk", 50) /obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton - name = "small chocolate milk carton" + name = "small milk carton" volume = 30 icon_state = "mini-milk" /obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton/New() @@ -140,9 +140,9 @@ reagents.add_reagent("milk", 30) /obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton/chocolate - name = "Small Carton of Chocolate Milk" + name = "small chocolate milk carton" desc = "It's milk! This one is in delicious chocolate flavour." - + icon_state = "mini-milk_choco" /obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton/chocolate/New() ..() reagents.add_reagent("chocolate_milk", 30) diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index cba5ea04cae..2c2e234a3ff 100644 Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ diff --git a/nano/templates/communicator.tmpl b/nano/templates/communicator.tmpl index bb0a26842f5..58b86a30d7e 100644 --- a/nano/templates/communicator.tmpl +++ b/nano/templates/communicator.tmpl @@ -103,7 +103,12 @@ Used In File(s): code\game\objects\items\devices\communicator\communicator.dm {{:value.name}}
-
{{/for}}
@@ -114,7 +119,7 @@ Used In File(s): code\game\objects\items\devices\communicator\communicator.dm
{{:value.name}}
{{:helper.link('Disconnect', 'close', {'disconnect' : value.true_name}, null, 'redButton')}}
+ {{:helper.link('Disconnect', 'close', {'disconnect' : value.true_name}, null, 'redButton')}}
+ {{if data.video_comm == null}}
+ {{:helper.link('Start Video', 'signal-diag', {'startvideo' : value.ref})}}
+ {{else data.video_comm == value.ref}}
+ {{:helper.link('End Video', 'signal-diag', {'endvideo' : value.true_name}, null, 'redButton')}}
+ {{/if}}
-
{{/for}}
{{:value.address}} {{:helper.link('Dial', 'signal-diag', {'dial' : value.address})}}
+ {{:value.address}} {{:helper.link('Accept', 'signal-diag', {'dial' : value.address})}}{{:helper.link('Decline', 'close', {'decline' : value.ref})}}
|