diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm
index 689e92fb7c..40a7381cb0 100644
--- a/code/game/objects/items/devices/taperecorder.dm
+++ b/code/game/objects/items/devices/taperecorder.dm
@@ -1,7 +1,7 @@
/obj/item/device/taperecorder
name = "universal recorder"
- desc = "A device that can record up to an hour of dialogue and play it back. It automatically translates the content in playback."
- icon_state = "taperecorderidle"
+ desc = "A device that can record to cassette tapes, and play them. It automatically translates the content in playback."
+ icon_state = "taperecorder_empty"
item_state = "analyzer"
w_class = ITEMSIZE_SMALL
@@ -10,33 +10,100 @@
var/emagged = 0.0
var/recording = 0.0
var/playing = 0.0
- var/timerecorded = 0.0
var/playsleepseconds = 0.0
- var/list/storedinfo = new/list()
- var/list/timestamp = new/list()
+ var/obj/item/device/tape/mytape = /obj/item/device/tape/random
var/canprint = 1
-
flags = CONDUCT
+ slot_flags = SLOT_BELT
throwforce = 2
throw_speed = 4
throw_range = 20
- show_messages = 1
+
+/obj/item/device/taperecorder/New()
+ ..()
+ if(ispath(mytape))
+ mytape = new mytape(src)
+ update_icon()
+ listening_objects += src
+
+/obj/item/device/taperecorder/empty
+ mytape = null
+
+/obj/item/device/taperecorder/Destroy()
+ listening_objects -= src
+ if(mytape)
+ qdel(mytape)
+ mytape = null
+ return ..()
+
+
+/obj/item/device/taperecorder/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/device/tape))
+ if(mytape)
+ to_chat(user, "There's already a tape inside.")
+ return
+ if(!user.unEquip(I))
+ return
+ I.forceMove(src)
+ mytape = I
+ to_chat(user, "You insert [I] into [src].")
+ update_icon()
+ return
+ ..()
+
+
+/obj/item/device/taperecorder/fire_act()
+ if(mytape)
+ mytape.ruin() //Fires destroy the tape
+ return ..()
+
+
+/obj/item/device/taperecorder/attack_hand(mob/user)
+ if(user.get_inactive_hand() == src)
+ if(mytape)
+ eject()
+ return
+ ..()
+
+
+/obj/item/device/taperecorder/verb/eject()
+ set name = "Eject Tape"
+ set category = "Object"
+
+ if(usr.incapacitated())
+ return
+ if(!mytape)
+ to_chat(usr, "There's no tape in \the [src].")
+ return
+ if(emagged)
+ to_chat(usr, "The tape seems to be stuck inside.")
+ return
+
+ if(playing || recording)
+ stop()
+ to_chat(usr, "You remove [mytape] from [src].")
+ usr.put_in_hands(mytape)
+ mytape = null
+ update_icon()
+
/obj/item/device/taperecorder/hear_talk(mob/living/M as mob, msg, var/verb="says", datum/language/speaking=null)
- if(recording)
- timestamp += timerecorded
+ if(mytape && recording)
if(speaking)
- storedinfo += "\[[time2text(timerecorded*10,"mm:ss")]\] [M.name] [speaking.format_message_plain(msg, verb)]"
+ if(!speaking.machine_understands)
+ msg = speaking.scramble(msg)
+ mytape.record_speech("[M.name] [speaking.format_message_plain(msg, verb)]")
else
- storedinfo += "\[[time2text(timerecorded*10,"mm:ss")]\] [M.name] [verb], \"[msg]\""
+ mytape.record_speech("[M.name] [verb], \"[msg]\"")
+
/obj/item/device/taperecorder/see_emote(mob/M as mob, text, var/emote_type)
if(emote_type != 2) //only hearable emotes
return
- if(recording)
- timestamp += timerecorded
- storedinfo += "\[[time2text(timerecorded*10,"mm:ss")]\] [strip_html_properly(text)]"
+ if(mytape && recording)
+ mytape.record_speech("[strip_html_properly(text)]")
+
/obj/item/device/taperecorder/show_message(msg, type, alt, alt_type)
var/recordedtext
@@ -46,25 +113,24 @@
recordedtext = alt
else
return
- if(recording)
- timestamp += timerecorded
- storedinfo += "*\[[time2text(timerecorded*10,"mm:ss")]\] *[strip_html_properly(recordedtext)]*" //"*" at front as a marker
+ if(mytape && recording)
+ mytape.record_noise("[strip_html_properly(recordedtext)]")
/obj/item/device/taperecorder/emag_act(var/remaining_charges, var/mob/user)
if(emagged == 0)
emagged = 1
recording = 0
- user << "PZZTTPFFFT"
- icon_state = "taperecorderidle"
+ to_chat(user, "PZZTTPFFFT")
+ update_icon()
return 1
else
- user << "It is already emagged!"
+ to_chat(user, "It is already emagged!")
/obj/item/device/taperecorder/proc/explode()
var/turf/T = get_turf(loc)
if(ismob(loc))
var/mob/M = loc
- M << "\The [src] explodes!"
+ to_chat(M, "\The [src] explodes!")
if(T)
T.hotspot_expose(700,125)
explosion(T, -1, -1, 0, 4)
@@ -75,117 +141,152 @@
set name = "Start Recording"
set category = "Object"
- if(usr.stat)
+ if(usr.incapacitated())
return
- if(emagged == 1)
- usr << "The tape recorder makes a scratchy noise."
+ if(!mytape)
+ to_chat(usr, "There's no tape!")
return
- icon_state = "taperecorderrecording"
- if(timerecorded < 3600 && playing == 0)
- usr << "Recording started."
+ if(mytape.ruined)
+ to_chat(usr, "The tape recorder makes a scratchy noise.")
+ return
+ if(recording)
+ to_chat(usr, "You're already recording!")
+ return
+ if(playing)
+ to_chat(usr, "You can't record when playing!")
+ return
+ if(emagged)
+ to_chat(usr, "The tape recorder makes a scratchy noise.")
+ return
+ if(mytape.used_capacity < mytape.max_capacity)
+ to_chat(usr, "Recording started.")
recording = 1
- timestamp+= timerecorded
- storedinfo += "\[[time2text(timerecorded*10,"mm:ss")]\] Recording started."
- for(timerecorded, timerecorded<3600)
- if(recording == 0)
- break
- timerecorded++
+ update_icon()
+
+ mytape.record_speech("Recording started.")
+
+ //count seconds until full, or recording is stopped
+ while(mytape && recording && mytape.used_capacity < mytape.max_capacity)
sleep(10)
- recording = 0
- icon_state = "taperecorderidle"
+ mytape.used_capacity++
+ if(mytape.used_capacity >= mytape.max_capacity)
+ if(ismob(loc))
+ var/mob/M = loc
+ to_chat(M, "The tape is full.")
+ stop_recording()
+
+
+ update_icon()
return
else
- usr << "Either your tape recorder's memory is full, or it is currently playing back its memory."
+ to_chat(usr, "The tape is full.")
+
+
+/obj/item/device/taperecorder/proc/stop_recording()
+ //Sanity checks skipped, should not be called unless actually recording
+ recording = 0
+ update_icon()
+ mytape.record_speech("Recording stopped.")
+ if(ismob(loc))
+ var/mob/M = loc
+ to_chat(M, "Recording stopped.")
/obj/item/device/taperecorder/verb/stop()
set name = "Stop"
set category = "Object"
- if(usr.stat)
+ if(usr.incapacitated())
return
- if(emagged == 1)
- usr << "The tape recorder makes a scratchy noise."
+ if(recording)
+ stop_recording()
return
- if(recording == 1)
- recording = 0
- timestamp+= timerecorded
- storedinfo += "\[[time2text(timerecorded*10,"mm:ss")]\] Recording stopped."
- usr << "Recording stopped."
- icon_state = "taperecorderidle"
- return
- else if(playing == 1)
+ else if(playing)
playing = 0
- var/turf/T = get_turf(src)
- T.audible_message("Tape Recorder: Playback stopped.")
- icon_state = "taperecorderidle"
- return
-
-
-/obj/item/device/taperecorder/verb/clear_memory()
- set name = "Clear Memory"
- set category = "Object"
-
- if(usr.stat)
- return
- if(emagged == 1)
- usr << "The tape recorder makes a scratchy noise."
- return
- if(recording == 1 || playing == 1)
- usr << "You can't clear the memory while playing or recording!"
+ update_icon()
+ to_chat(usr, "Playback stopped.")
return
else
- if(storedinfo) storedinfo.Cut()
- if(timestamp) timestamp.Cut()
- timerecorded = 0
- usr << "Memory cleared."
+ to_chat(usr, "Stop what?")
+
+
+/obj/item/device/taperecorder/verb/wipe_tape()
+ set name = "Wipe Tape"
+ set category = "Object"
+
+ if(usr.incapacitated())
+ return
+ if(emagged)
+ to_chat(usr, "The tape recorder makes a scratchy noise.")
+ return
+ if(mytape.ruined)
+ to_chat(usr, "The tape recorder makes a scratchy noise.")
+ return
+ if(recording || playing)
+ to_chat(usr, "You can't wipe the tape while playing or recording!")
+ return
+ else
+ if(mytape.storedinfo) mytape.storedinfo.Cut()
+ if(mytape.timestamp) mytape.timestamp.Cut()
+ mytape.used_capacity = 0
+ to_chat(usr, "You wipe the tape.")
return
/obj/item/device/taperecorder/verb/playback_memory()
- set name = "Playback Memory"
+ set name = "Playback Tape"
set category = "Object"
- if(usr.stat)
+ if(usr.incapacitated())
return
- if(emagged == 1)
- usr << "The tape recorder makes a scratchy noise."
+ if(!mytape)
+ to_chat(usr, "There's no tape!")
return
- if(recording == 1)
- usr << "You can't playback when recording!"
+ if(mytape.ruined)
+ to_chat(usr, "The tape recorder makes a scratchy noise.")
return
- if(playing == 1)
- usr << "You're already playing!"
+ if(recording)
+ to_chat(usr, "You can't playback when recording!")
+ return
+ if(playing)
+ to_chat(usr, "You're already playing!")
return
playing = 1
- icon_state = "taperecorderplaying"
- usr << "Playing started."
- for(var/i=1,timerecorded<3600,sleep(10 * (playsleepseconds) ))
- if(playing == 0)
+ update_icon()
+ to_chat(usr, "Playing started.")
+ for(var/i=1 , i < mytape.max_capacity , i++)
+ if(!mytape || !playing)
break
- if(storedinfo.len < i)
+ if(mytape.storedinfo.len < i)
break
+
var/turf/T = get_turf(src)
- var/playedmessage = storedinfo[i]
+ var/playedmessage = mytape.storedinfo[i]
if (findtextEx(playedmessage,"*",1,2)) //remove marker for action sounds
playedmessage = copytext(playedmessage,2)
T.audible_message("Tape Recorder: [playedmessage]")
- if(storedinfo.len < i+1)
+
+ if(mytape.storedinfo.len < i+1)
playsleepseconds = 1
sleep(10)
T = get_turf(src)
T.audible_message("Tape Recorder: End of recording.")
+ break
else
- playsleepseconds = timestamp[i+1] - timestamp[i]
+ playsleepseconds = mytape.timestamp[i+1] - mytape.timestamp[i]
+
if(playsleepseconds > 14)
sleep(10)
T = get_turf(src)
T.audible_message("Tape Recorder: Skipping [playsleepseconds] seconds of silence")
playsleepseconds = 1
- i++
- icon_state = "taperecorderidle"
+ sleep(10 * playsleepseconds)
+
+
playing = 0
- if(emagged == 1.0)
+ update_icon()
+
+ if(emagged)
var/turf/T = get_turf(src)
T.audible_message("Tape Recorder: This tape recorder will self-destruct in... Five.")
sleep(10)
@@ -208,24 +309,31 @@
set name = "Print Transcript"
set category = "Object"
- if(usr.stat)
+ if(usr.incapacitated())
return
- if(emagged == 1)
- usr << "The tape recorder makes a scratchy noise."
+ if(!mytape)
+ to_chat(usr, "There's no tape!")
+ return
+ if(mytape.ruined)
+ to_chat(usr, "The tape recorder makes a scratchy noise.")
+ return
+ if(emagged)
+ to_chat(usr, "The tape recorder makes a scratchy noise.")
return
if(!canprint)
- usr << "The recorder can't print that fast!"
+ to_chat(usr, "The recorder can't print that fast!")
return
- if(recording == 1 || playing == 1)
- usr << "You can't print the transcript while playing or recording!"
+ if(recording || playing)
+ to_chat(usr, "You can't print the transcript while playing or recording!")
return
- usr << "Transcript printed."
+
+ to_chat(usr, "Transcript printed.")
var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(get_turf(src))
var/t1 = "Transcript:
"
- for(var/i=1,storedinfo.len >= i,i++)
- var/printedmessage = storedinfo[i]
+ for(var/i=1,mytape.storedinfo.len >= i,i++)
+ var/printedmessage = mytape.storedinfo[i]
if (findtextEx(printedmessage,"*",1,2)) //replace action sounds
- printedmessage = "\[[time2text(timestamp[i]*10,"mm:ss")]\] (Unrecognized sound)"
+ printedmessage = "\[[time2text(mytape.timestamp[i]*10,"mm:ss")]\] (Unrecognized sound)"
t1 += "[printedmessage]
"
P.info = t1
P.name = "Transcript"
@@ -235,46 +343,98 @@
/obj/item/device/taperecorder/attack_self(mob/user)
- if(recording == 0 && playing == 0)
- if(usr.stat)
- return
- if(emagged == 1)
- usr << "The tape recorder makes a scratchy noise."
- return
- icon_state = "taperecorderrecording"
- if(timerecorded < 3600 && playing == 0)
- usr << "Recording started."
- recording = 1
- timestamp+= timerecorded
- storedinfo += "\[[time2text(timerecorded*10,"mm:ss")]\] Recording started."
- for(timerecorded, timerecorded<3600)
- if(recording == 0)
- break
- timerecorded++
- sleep(10)
- recording = 0
- icon_state = "taperecorderidle"
- return
- else
- usr << "Either your tape recorder's memory is full, or it is currently playing back its memory."
+ if(recording || playing)
+ stop()
else
- if(usr.stat)
- usr << "Not when you're incapacitated."
- return
- if(recording == 1)
- recording = 0
- timestamp+= timerecorded
- storedinfo += "\[[time2text(timerecorded*10,"mm:ss")]\] Recording stopped."
- usr << "Recording stopped."
- icon_state = "taperecorderidle"
- return
- else if(playing == 1)
- playing = 0
- var/turf/T = get_turf(src)
- for(var/mob/O in hearers(world.view-1, T))
- O.show_message("Tape Recorder: Playback stopped.",2)
- icon_state = "taperecorderidle"
- return
- else
- usr << "Stop what?"
- return
+ record()
+
+
+/obj/item/device/taperecorder/update_icon()
+ if(!mytape)
+ icon_state = "taperecorder_empty"
+ else if(recording)
+ icon_state = "taperecorder_recording"
+ else if(playing)
+ icon_state = "taperecorder_playing"
+ else
+ icon_state = "taperecorder_idle"
+
+
+
+/obj/item/device/tape
+ name = "tape"
+ desc = "A magnetic tape that can hold up to ten minutes of content."
+ icon_state = "tape_white"
+ item_state = "analyzer"
+ w_class = ITEMSIZE_TINY
+ matter = list(DEFAULT_WALL_MATERIAL=20, "glass"=5)
+ force = 1
+ throwforce = 0
+ var/max_capacity = 600
+ var/used_capacity = 0
+ var/list/storedinfo = new/list()
+ var/list/timestamp = new/list()
+ var/ruined = 0
+
+
+/obj/item/device/tape/update_icon()
+ overlays.Cut()
+ if(ruined)
+ overlays += "ribbonoverlay"
+
+
+/obj/item/device/tape/fire_act()
+ ruin()
+
+/obj/item/device/tape/attack_self(mob/user)
+ if(!ruined)
+ to_chat(user, "You pull out all the tape!")
+ ruin()
+
+
+/obj/item/device/tape/proc/ruin()
+ ruined = 1
+ update_icon()
+
+
+/obj/item/device/tape/proc/fix()
+ ruined = 0
+ update_icon()
+
+
+/obj/item/device/tape/proc/record_speech(text)
+ timestamp += used_capacity
+ storedinfo += "\[[time2text(used_capacity*10,"mm:ss")]\] [text]"
+
+
+//shows up on the printed transcript as (Unrecognized sound)
+/obj/item/device/tape/proc/record_noise(text)
+ timestamp += used_capacity
+ storedinfo += "*\[[time2text(used_capacity*10,"mm:ss")]\] [text]"
+
+
+/obj/item/device/tape/attackby(obj/item/I, mob/user, params)
+ if(ruined && istype(I, /obj/item/weapon/screwdriver))
+ to_chat(user, "You start winding the tape back in...")
+ if(do_after(user, 120, target = src))
+ to_chat(user, "You wound the tape back in.")
+ fix()
+ return
+ else if(istype(I, /obj/item/weapon/pen))
+ if(loc == user && !user.incapacitated())
+ var/new_name = input(user, "What would you like to label the tape?", "Tape labeling") as null|text
+ if(isnull(new_name)) return
+ new_name = sanitizeSafe(new_name)
+ if(new_name)
+ name = "tape - '[new_name]'"
+ to_chat(user, "You label the tape '[new_name]'.")
+ else
+ name = "tape"
+ to_chat(user, "You scratch off the label.")
+ return
+ ..()
+
+
+//Random colour tapes
+/obj/item/device/tape/random/New()
+ icon_state = "tape_[pick("white", "blue", "red", "yellow", "purple")]"
\ No newline at end of file
diff --git a/code/game/objects/structures/crates_lockers/closets/job_closets.dm b/code/game/objects/structures/crates_lockers/closets/job_closets.dm
index 2abd0e1d8a..c93f68a82a 100644
--- a/code/game/objects/structures/crates_lockers/closets/job_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/job_closets.dm
@@ -118,4 +118,6 @@
new /obj/item/clothing/glasses/sunglasses/big(src)
new /obj/item/clothing/glasses/sunglasses/big(src)
new /obj/item/clothing/under/lawyer/blue(src)
- new /obj/item/clothing/under/lawyer/blue(src)
\ No newline at end of file
+ new /obj/item/clothing/under/lawyer/blue(src)
+ new /obj/item/device/tape/random(src)
+ new /obj/item/device/tape/random(src)
\ No newline at end of file
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
index fdd1ed5c80..d886236c1b 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
@@ -236,6 +236,37 @@
req_access = list(access_chemistry)
+ New()
+ ..()
+ new /obj/item/clothing/under/rank/psych(src)
+ new /obj/item/clothing/under/rank/psych/turtleneck(src)
+ new /obj/item/clothing/suit/straight_jacket(src)
+ new /obj/item/weapon/reagent_containers/glass/bottle/stoxin(src)
+ new /obj/item/weapon/reagent_containers/syringe(src)
+ new /obj/item/weapon/storage/pill_bottle/citalopram(src)
+ new /obj/item/weapon/reagent_containers/pill/methylphenidate(src)
+ new /obj/item/weapon/clipboard(src)
+ new /obj/item/weapon/folder/white(src)
+ new /obj/item/device/taperecorder(src)
+ new /obj/item/device/tape/random(src)
+ new /obj/item/device/tape/random(src)
+ new /obj/item/device/tape/random(src)
+ new /obj/item/device/camera(src)
+ new /obj/item/toy/therapy_blue(src)
+ return
+
+/obj/structure/closet/secure_closet/psych
+ name = "psychiatric closet"
+ desc = "Store psychology tools and medicines in here."
+ icon_state = "medical1"
+ icon_closed = "medical"
+ icon_locked = "medical1"
+ icon_opened = "medicalopen"
+ icon_broken = "medicalbroken"
+ icon_off = "medicaloff"
+ req_access = list(access_psychiatrist)
+
+
New()
..()
new /obj/item/weapon/storage/box/pillbottles(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
index 064f58f83e..58fa8ed5f2 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
@@ -280,6 +280,10 @@
new /obj/item/device/flashlight/maglight(src)
new /obj/item/weapon/reagent_containers/food/drinks/flask/detflask(src)
new /obj/item/weapon/storage/briefcase/crimekit(src)
+ new /obj/item/device/taperecorder(src)
+ new /obj/item/device/tape/random(src)
+ new /obj/item/device/tape/random(src)
+ new /obj/item/device/tape/random(src)
return
/obj/structure/closet/secure_closet/detective/update_icon()
diff --git a/code/modules/mob/language/language.dm b/code/modules/mob/language/language.dm
index 372409b443..525a77e3fd 100644
--- a/code/modules/mob/language/language.dm
+++ b/code/modules/mob/language/language.dm
@@ -18,6 +18,7 @@
var/native // If set, non-native speakers will have trouble speaking.
var/list/syllables // Used when scrambling text for a non-speaker.
var/list/space_chance = 55 // Likelihood of getting a space in the random scramble string
+ var/machine_understands = 1 // Whether machines can parse and understand this language
/datum/language/proc/get_random_name(var/gender, name_count=2, syllable_count=4, syllable_divisor=2)
if(!syllables || !syllables.len)
diff --git a/code/modules/mob/language/outsider.dm b/code/modules/mob/language/outsider.dm
index d427dcbfb6..f8634f8f54 100644
--- a/code/modules/mob/language/outsider.dm
+++ b/code/modules/mob/language/outsider.dm
@@ -47,6 +47,7 @@
key = "f"
flags = RESTRICTED
space_chance = 100
+ machine_understands = 0
syllables = list("ire","ego","nahlizet","certum","veri","jatkaa","mgar","balaq", "karazet", "geeri", \
"orkan", "allaq", "sas'so", "c'arta", "forbici", "tarem", "n'ath", "reth", "sh'yro", "eth", "d'raggathnor", \
"mah'weyh", "pleggh", "at", "e'ntrath", "tok-lyr", "rqa'nap", "g'lt-ulotf", "ta'gh", "fara'qha", "fel", "d'amar det", \
diff --git a/html/changelogs/Anewbe - Tape Recorder.yml b/html/changelogs/Anewbe - Tape Recorder.yml
new file mode 100644
index 0000000000..0f5912e3ae
--- /dev/null
+++ b/html/changelogs/Anewbe - Tape Recorder.yml
@@ -0,0 +1,36 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# wip (For works in progress)
+# tweak
+# soundadd
+# sounddel
+# rscadd (general adding of nice things)
+# rscdel (general deleting of nice things)
+# imageadd
+# imagedel
+# maptweak
+# spellcheck (typo fixes)
+# experiment
+#################################
+
+# Your name.
+author: Anewbe
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
+# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - rscadd: "Ported Bay's tape recorders (which actually work)."
\ No newline at end of file
diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi
index 41da2fe40a..aa1722cba8 100644
Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ