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