diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm
index 3a746e3639194..dbd4f1aefcf54 100644
--- a/code/__DEFINES/say.dm
+++ b/code/__DEFINES/say.dm
@@ -63,6 +63,7 @@
#define SPAN_MEGAPHONE "megaphone"
#define SPAN_CLOWN "clowntext"
#define SPAN_SINGING "singing"
+#define SPAN_TAPE_RECORDER "tape_recorder"
//bitflag #defines for return value of the radio() proc.
#define ITALICS (1<<0)
diff --git a/code/datums/looping_sounds/item_sounds.dm b/code/datums/looping_sounds/item_sounds.dm
index 5b02eef9c4ce6..181e1d5a12b70 100644
--- a/code/datums/looping_sounds/item_sounds.dm
+++ b/code/datums/looping_sounds/item_sounds.dm
@@ -51,3 +51,8 @@
mid_sounds = list('sound/items/weeoo1.ogg' = 1)
mid_length = 15
volume = 20
+
+/datum/looping_sound/tape_recorder_hiss
+ mid_sounds = list('sound/items/taperecorder/taperecorder_hiss_mid.ogg')
+ start_sound = list('sound/items/taperecorder/taperecorder_hiss_start.ogg')
+ volume = 10
diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm
index ab5d8bad62876..98d6381ede1fb 100644
--- a/code/game/objects/items/devices/taperecorder.dm
+++ b/code/game/objects/items/devices/taperecorder.dm
@@ -11,53 +11,105 @@
slot_flags = ITEM_SLOT_BELT
custom_materials = list(/datum/material/iron=60, /datum/material/glass=30)
force = 2
- throwforce = 0
+ throwforce = 2
+ speech_span = SPAN_TAPE_RECORDER
drop_sound = 'sound/items/handling/taperecorder_drop.ogg'
pickup_sound = 'sound/items/handling/taperecorder_pickup.ogg'
- var/recording = 0
- var/playing = 0
+ var/recording = FALSE
+ var/playing = FALSE
var/playsleepseconds = 0
var/obj/item/tape/mytape
var/starting_tape_type = /obj/item/tape/random
- var/open_panel = 0
- var/canprint = 1
+ var/open_panel = FALSE
+ var/canprint = TRUE
+ var/list/icons_available = list()
+ var/radial_icon_file = 'icons/obj/radial_taperecorder.dmi'
+ ///Whether we've warned during this recording session that the tape is almost up.
+ var/time_warned = FALSE
+ ///Seconds under which to warn that the tape is almost up.
+ var/time_left_warning = 60 SECONDS
+ ///Sound loop that plays when recording or playing back.
+ var/datum/looping_sound/tape_recorder_hiss/soundloop
/obj/item/taperecorder/Initialize(mapload)
. = ..()
if(starting_tape_type)
mytape = new starting_tape_type(src)
+ soundloop = new(src, FALSE)
update_icon()
become_hearing_sensitive()
+/obj/item/taperecorder/proc/readout()
+ if(mytape)
+ if(playing)
+ return "PLAYING"
+ else
+ var/time = mytape.used_capacity / 10 //deciseconds / 10 = seconds
+ var/mins = round(time / 60)
+ var/secs = time - mins * 60
+ return "[mins]m [secs]s"
+ return "NO TAPE INSERTED"
+
+/obj/item/taperecorder/proc/update_available_icons()
+ icons_available = list()
+
+ if(!playing && !recording)
+ icons_available += list("Record" = image(radial_icon_file,"record"))
+ icons_available += list("Play" = image(radial_icon_file,"play"))
+ if(canprint && mytape?.storedinfo.len)
+ icons_available += list("Print Transcript" = image(radial_icon_file,"print"))
+ if(playing || recording)
+ icons_available += list("Stop" = image(radial_icon_file,"stop"))
+ if(mytape)
+ icons_available += list("Eject" = image(radial_icon_file,"eject"))
+
+/obj/item/taperecorder/proc/update_sound()
+ if(!playing && !recording)
+ soundloop.stop()
+ else
+ soundloop.start()
+
/obj/item/taperecorder/Destroy()
+ QDEL_NULL(soundloop)
QDEL_NULL(mytape)
return ..()
/obj/item/taperecorder/examine(mob/user)
. = ..()
- . += "The wire panel is [open_panel ? "opened" : "closed"]."
-
+ if(in_range(src, user) || isobserver(user))
+ . += "The wire panel is [open_panel ? "opened" : "closed"]. The display reads:"
+ . += "[readout()]"
/obj/item/taperecorder/attackby(obj/item/I, mob/user, params)
if(!mytape && istype(I, /obj/item/tape))
if(!user.transferItemToLoc(I,src))
return
mytape = I
- to_chat(user, "You insert [I] into [src].")
- update_icon()
+ balloon_alert(user, "inserted [mytape]")
+ playsound(src, 'sound/items/taperecorder/taperecorder_close.ogg', 50, FALSE)
+ update_appearance()
/obj/item/taperecorder/proc/eject(mob/user)
- if(mytape)
- to_chat(user, "You remove [mytape] from [src].")
- stop()
- user.put_in_hands(mytape)
- mytape = null
- update_icon()
+ if(!mytape)
+ balloon_alert(user, "no tape!")
+ return
+ if(playing)
+ balloon_alert(user, "stop the tape first!")
+ return
+ if(recording)
+ balloon_alert(user, "stop the recording first!")
+ return
+ playsound(src, 'sound/items/taperecorder/taperecorder_open.ogg', 50, FALSE)
+ balloon_alert(user, "ejected [mytape]")
+ stop()
+ user.put_in_hands(mytape)
+ mytape = null
+ update_icon()
/obj/item/taperecorder/fire_act(exposed_temperature, exposed_volume)
- mytape.ruin() //Fires destroy the tape
+ mytape.unspool() //Fires unspool the tape, which makes sense if you don't think about it
..()
//ATTACK HAND IGNORING PARENT RETURN VALUE
@@ -82,8 +134,10 @@
set category = "Object"
if(!can_use(usr))
+ balloon_alert(usr, "can't use!")
return
if(!mytape)
+ balloon_alert(usr, "no tape!")
return
eject(usr)
@@ -107,37 +161,48 @@
. = ..()
if(mytape && recording)
mytape.timestamp += mytape.used_capacity
- mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [message]"
+ mytape.storedinfo += "\[[time2text(mytape.used_capacity,"mm:ss")]\] [message]"
/obj/item/taperecorder/verb/record()
set name = "Start Recording"
set category = "Object"
if(!can_use(usr))
+ balloon_alert(usr, "can't use!")
return
- if(!mytape || mytape.ruined)
+ if(!mytape || mytape.unspooled)
+ balloon_alert(usr, "no spooled tape!")
return
if(recording)
+ balloon_alert(usr, "stop recording first!")
return
if(playing)
+ balloon_alert(usr, "already playing!")
return
+ playsound(src, 'sound/items/taperecorder/taperecorder_play.ogg', 50, FALSE)
+
if(mytape.used_capacity < mytape.max_capacity)
- to_chat(usr, "Recording started.")
- recording = 1
+ recording = TRUE
+ balloon_alert(usr, "started recording")
+ update_sound()
update_icon()
- mytape.timestamp += mytape.used_capacity
- mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] Recording started."
var/used = mytape.used_capacity //to stop runtimes when you eject the tape
var/max = mytape.max_capacity
while(recording && used < max)
- mytape.used_capacity++
- used++
- sleep(10)
- recording = 0
- update_icon()
+ mytape.used_capacity += 1 SECONDS
+ used += 1 SECONDS
+ if(max - used < time_left_warning && !time_warned)
+ time_warned = TRUE
+ balloon_alert(usr, "[(max - used) / 10] second\s left")
+ sleep(1 SECONDS)
+ if(used >= max)
+ balloon_alert(usr, "tape full!")
+ sleep(1 SECONDS) //prevent balloon alerts layering over the top of each other
+ stop()
else
- to_chat(usr, "The tape is full.")
+ balloon_alert(usr, "tape full!")
+ playsound(src, 'sound/items/taperecorder/taperecorder_stop.ogg', 50, FALSE)
/obj/item/taperecorder/verb/stop()
@@ -145,70 +210,93 @@
set category = "Object"
if(!can_use(usr))
+ balloon_alert(usr, "can't use!")
return
if(recording)
- recording = 0
- mytape.timestamp += mytape.used_capacity
- mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] Recording stopped."
- to_chat(usr, "Recording stopped.")
- return
+ playsound(src, 'sound/items/taperecorder/taperecorder_stop.ogg', 50, FALSE)
+ balloon_alert(usr, "stopped recording")
+ recording = FALSE
else if(playing)
- playing = 0
- var/turf/T = get_turf(src)
- T.visible_message("Tape Recorder: Playback stopped.")
+ playsound(src, 'sound/items/taperecorder/taperecorder_stop.ogg', 50, FALSE)
+ balloon_alert(usr, "stopped playing")
+ playing = FALSE
+ time_warned = FALSE
update_icon()
-
+ update_sound()
/obj/item/taperecorder/verb/play()
set name = "Play Tape"
set category = "Object"
if(!can_use(usr))
+ balloon_alert(usr, "can't use!")
return
- if(!mytape || mytape.ruined)
+ if(!mytape || mytape.unspooled)
+ balloon_alert(usr, "no spooled tape!")
return
if(recording)
+ balloon_alert(usr, "stop recording first!")
return
if(playing)
+ balloon_alert(usr, "already playing!")
+ return
+ if(mytape.storedinfo?.len <= 0)
+ balloon_alert(usr, "[mytape] is empty!")
return
- playing = 1
+ playing = TRUE
update_icon()
- to_chat(usr, "Playing started.")
+ update_sound()
+ balloon_alert(usr, "started playing")
+ playsound(src, 'sound/items/taperecorder/taperecorder_play.ogg', 50, FALSE)
var/used = mytape.used_capacity //to stop runtimes when you eject the tape
var/max = mytape.max_capacity
- for(var/i = 1, used < max, sleep(10 * playsleepseconds))
+ for(var/i = 1, used <= max, sleep(playsleepseconds))
if(!mytape)
break
- if(playing == 0)
+ if(playing == FALSE)
break
if(mytape.storedinfo.len < i)
+ balloon_alert(usr, "recording ended")
+ sleep(1 SECONDS)
break
- say(mytape.storedinfo[i])
+ say("[mytape.storedinfo[i]]")
if(mytape.storedinfo.len < i + 1)
playsleepseconds = 1
- sleep(10)
- say("End of recording.")
+ sleep(1 SECONDS)
else
playsleepseconds = mytape.timestamp[i + 1] - mytape.timestamp[i]
- if(playsleepseconds > 14)
- sleep(10)
- say("Skipping [playsleepseconds] seconds of silence")
- playsleepseconds = 1
+ if(playsleepseconds > 14 SECONDS)
+ sleep(1 SECONDS)
+ say("Skipping [playsleepseconds/10] seconds of silence.")
+ playsleepseconds = 1 SECONDS
i++
- playing = 0
- update_icon()
+ stop()
/obj/item/taperecorder/attack_self(mob/user)
- if(!mytape || mytape.ruined)
+ if(!mytape)
+ balloon_alert(user, "it's empty!")
return
- if(recording)
- stop()
- else
- record()
+
+ update_available_icons()
+ if(icons_available)
+ var/selection = show_radial_menu(user, src, icons_available, radius = 38, require_near = TRUE, tooltips = TRUE)
+ if(!selection)
+ return
+ switch(selection)
+ if("Stop")
+ stop()
+ if("Record")
+ record()
+ if("Play")
+ play()
+ if("Print Transcript")
+ print_transcript()
+ if("Eject")
+ eject(user)
/obj/item/taperecorder/verb/print_transcript()
@@ -217,15 +305,22 @@
var/list/transcribed_info = mytape.storedinfo
if(!length(transcribed_info))
- return
- if(!mytape)
+ balloon_alert(usr, "tape is empty!")
return
if(!canprint)
- to_chat(usr, "The recorder can't print that fast!")
- return
- if(recording || playing)
+ balloon_alert(usr, "can't print that fast!")
return
if(!can_use(usr))
+ balloon_alert(usr, "can't use!")
+ return
+ if(!mytape || mytape.unspooled)
+ balloon_alert(usr, "no spooled tape!")
+ return
+ if(recording)
+ balloon_alert(usr, "stop recording first!")
+ return
+ if(playing)
+ balloon_alert(usr, "already playing!")
return
var/transcribed_text = "Transcript:
"
@@ -240,7 +335,7 @@
// Very unexpected. Better abort non-gracefully.
if(excerpt_length > MAX_PAPER_LENGTH)
- say("Error: Data corruption detected. Cannot print.")
+ balloon_alert(usr, "data corrupted, can't print!")
CRASH("Transcript entry has more than [MAX_PAPER_LENGTH] chars: [excerpt_length] chars")
// If we're going to overflow the paper's length, print the current transcribed text out first and reset to prevent us
@@ -259,7 +354,10 @@
transcript_paper.add_raw_text(transcribed_text)
transcript_paper.name = "[paper_name] page [page_count]"
transcript_paper.update_appearance()
- to_chat(usr, "Transcript printed, [page_count] pages.")
+ balloon_alert(usr, "transcript printed\n[page_count] page\s")
+ playsound(src, 'sound/items/taperecorder/taperecorder_print.ogg', 50, FALSE)
+
+ // Can't put the entire stack into their hands if there's multple pages, but hey we can at least put one page in.
usr.put_in_hands(transcript_paper)
canprint = FALSE
addtimer(VARSET_CALLBACK(src, canprint, TRUE), 30 SECONDS)
@@ -272,7 +370,7 @@
/obj/item/tape
name = "tape"
- desc = "A magnetic tape that can hold up to ten minutes of content."
+ desc = "A magnetic tape that can hold up to ten minutes of content on either side."
icon_state = "tape_white"
icon = 'icons/obj/device.dmi'
item_state = "analyzer"
@@ -282,46 +380,123 @@
custom_materials = list(/datum/material/iron=20, /datum/material/glass=5)
force = 1
throwforce = 0
- var/max_capacity = 600
- var/used_capacity = 0
+ obj_flags = UNIQUE_RENAME //my mixtape
+ drop_sound = 'sound/items/handling/tape_drop.ogg'
+ pickup_sound = 'sound/items/handling/tape_pickup.ogg'
+ ///Because we can't expect God to do all the work.
+ var/initial_icon_state
+ var/max_capacity = 10 MINUTES
+ var/used_capacity = 0 SECONDS
+ ///Numbered list of chat messages the recorder has heard with spans and prepended timestamps. Used for playback and transcription.
var/list/storedinfo = list()
+ ///Numbered list of seconds the messages in the previous list appear at on the tape. Used by playback to get the timing right.
var/list/timestamp = list()
- var/ruined = 0
+ var/used_capacity_otherside = 0 SECONDS //Separate my side
+ var/list/storedinfo_otherside = list()
+ var/list/timestamp_otherside = list()
+ var/unspooled = FALSE
+ var/list/icons_available = list()
+ var/radial_icon_file = 'icons/obj/radial_tape.dmi'
/obj/item/tape/fire_act(exposed_temperature, exposed_volume)
- ruin()
+ unspool()
..()
-/obj/item/tape/attack_self(mob/user)
- if(!ruined)
- to_chat(user, "You pull out all the tape!")
- ruin()
+/obj/item/tape/Initialize(mapload)
+ . = ..()
+ initial_icon_state = icon_state //random tapes will set this after choosing their icon
+ var/mycolor = random_short_color()
+ name += " ([mycolor])" //multiple tapes can get confusing fast
+ if(icon_state == "tape_greyscale")
+ add_atom_colour("#[mycolor]", FIXED_COLOUR_PRIORITY)
+ if(prob(50))
+ tapeflip()
+
+/obj/item/tape/proc/update_available_icons()
+ icons_available = list()
+ if(!unspooled)
+ icons_available += list("Unwind tape" = image(radial_icon_file,"tape_unwind"))
+ icons_available += list("Flip tape" = image(radial_icon_file,"tape_flip"))
+/obj/item/tape/attack_self(mob/user)
+ update_available_icons()
+ if(icons_available)
+ var/selection = show_radial_menu(user, src, icons_available, radius = 38, require_near = TRUE, tooltips = TRUE)
+ if(!selection)
+ return
+ switch(selection)
+ if("Flip tape")
+ if(loc != user)
+ return
+ tapeflip()
+ balloon_alert(user, "flipped tape")
+ playsound(src, 'sound/items/taperecorder/tape_flip.ogg', 70, FALSE)
+ if("Unwind tape")
+ if(loc != user)
+ return
+ unspool()
+ balloon_alert(user, "unspooled tape")
+
+/obj/item/tape/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
+ if(prob(50))
+ tapeflip()
+ . = ..()
-/obj/item/tape/proc/ruin()
- //Lets not add infinite amounts of overlays when our fireact is called
- //repeatedly
- if(!ruined)
+/obj/item/tape/proc/unspool()
+ //Let's not add infinite amounts of overlays when our fire_act is called repeatedly
+ if(!unspooled)
add_overlay("ribbonoverlay")
- ruined = 1
-
+ unspooled = TRUE
-/obj/item/tape/proc/fix()
+/obj/item/tape/proc/respool()
cut_overlay("ribbonoverlay")
- ruined = 0
-
-
-/obj/item/tape/attackby(obj/item/I, mob/user, params)
- if(ruined && I.tool_behaviour == TOOL_SCREWDRIVER || istype(I, /obj/item/pen))
- to_chat(user, "You start winding the tape back in...")
- if(I.use_tool(src, user, 120))
- to_chat(user, "You wound the tape back in.")
- fix()
+ unspooled = FALSE
+
+/obj/item/tape/proc/tapeflip()
+ //first we save a copy of our current side
+ var/list/storedinfo_currentside = storedinfo.Copy()
+ var/list/timestamp_currentside = timestamp.Copy()
+ var/used_capacity_currentside = used_capacity
+ //then we overwite our current side with our other side
+ storedinfo = storedinfo_otherside.Copy()
+ timestamp = timestamp_otherside.Copy()
+ used_capacity = used_capacity_otherside
+ //then we overwrite our other side with the saved side
+ storedinfo_otherside = storedinfo_currentside.Copy()
+ timestamp_otherside = timestamp_currentside.Copy()
+ used_capacity_otherside = used_capacity_currentside
+
+ if(icon_state == initial_icon_state)
+ icon_state = "[initial_icon_state]_reverse"
+ else if(icon_state == "[initial_icon_state]_reverse") //so flipping doesn't overwrite an unexpected icon_state (e.g. an admin's)
+ icon_state = initial_icon_state
+
+/obj/item/tape/attackby(obj/item/tool, mob/user, params)
+ if(unspooled && (istype(tool, /obj/item/pen)))
+ balloon_alert(user, "respooling tape...")
+ if(!tool.use_tool(src, user, 12 SECONDS))
+ balloon_alert(user, "respooling failed!")
+ return FALSE
+ balloon_alert(user, "tape respooled")
+ respool()
+
+/obj/item/tape/screwdriver_act(mob/living/user, obj/item/tool)
+ if(!unspooled)
+ return FALSE
+ balloon_alert(user, "respooling tape...")
+ if(!tool.use_tool(src, user, 12 SECONDS))
+ balloon_alert(user, "respooling failed!")
+ return FALSE
+ balloon_alert(user, "tape respooled")
+ respool()
//Random colour tapes
/obj/item/tape/random
icon_state = "random_tape"
/obj/item/tape/random/Initialize(mapload)
+ icon_state = "tape_[pick("white", "blue", "red", "yellow", "purple", "tape_greyscale")]"
. = ..()
- icon_state = "tape_[pick("white", "blue", "red", "yellow", "purple")]"
+
+/obj/item/tape/dyed
+ icon_state = "tape_greyscale"
diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi
index e6379f882ff31..d7467f636522b 100644
Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ
diff --git a/icons/obj/radial_tape.dmi b/icons/obj/radial_tape.dmi
new file mode 100644
index 0000000000000..ae5be96dd8a94
Binary files /dev/null and b/icons/obj/radial_tape.dmi differ
diff --git a/icons/obj/radial_taperecorder.dmi b/icons/obj/radial_taperecorder.dmi
new file mode 100644
index 0000000000000..29d97b0aba05f
Binary files /dev/null and b/icons/obj/radial_taperecorder.dmi differ
diff --git a/interface/stylesheet.dm b/interface/stylesheet.dm
index 75fad5d60bcff..f5624fe9aed9d 100644
--- a/interface/stylesheet.dm
+++ b/interface/stylesheet.dm
@@ -232,4 +232,5 @@ h1.alert, h2.alert {color: #000000;}
.monkeyhive {color: #774704;}
.monkeylead {color: #774704; font-size: 2;}
+.tape_recorder {color: #ff0000; font-family: 'Courier New', cursive, sans-serif;}
"}
diff --git a/sound/items/taperecorder/tape_flip.ogg b/sound/items/taperecorder/tape_flip.ogg
new file mode 100644
index 0000000000000..fae3e07373c5b
Binary files /dev/null and b/sound/items/taperecorder/tape_flip.ogg differ
diff --git a/sound/items/taperecorder/taperecorder_close.ogg b/sound/items/taperecorder/taperecorder_close.ogg
new file mode 100644
index 0000000000000..ab9f521c5f9fc
Binary files /dev/null and b/sound/items/taperecorder/taperecorder_close.ogg differ
diff --git a/sound/items/taperecorder/taperecorder_hiss_mid.ogg b/sound/items/taperecorder/taperecorder_hiss_mid.ogg
new file mode 100644
index 0000000000000..50ef4f2171b19
Binary files /dev/null and b/sound/items/taperecorder/taperecorder_hiss_mid.ogg differ
diff --git a/sound/items/taperecorder/taperecorder_hiss_start.ogg b/sound/items/taperecorder/taperecorder_hiss_start.ogg
new file mode 100644
index 0000000000000..fa57041a72281
Binary files /dev/null and b/sound/items/taperecorder/taperecorder_hiss_start.ogg differ
diff --git a/sound/items/taperecorder/taperecorder_open.ogg b/sound/items/taperecorder/taperecorder_open.ogg
new file mode 100644
index 0000000000000..7b7110fa58ba5
Binary files /dev/null and b/sound/items/taperecorder/taperecorder_open.ogg differ
diff --git a/sound/items/taperecorder/taperecorder_play.ogg b/sound/items/taperecorder/taperecorder_play.ogg
new file mode 100644
index 0000000000000..1bf4d7a3bd63a
Binary files /dev/null and b/sound/items/taperecorder/taperecorder_play.ogg differ
diff --git a/sound/items/taperecorder/taperecorder_print.ogg b/sound/items/taperecorder/taperecorder_print.ogg
new file mode 100644
index 0000000000000..7912d08dc9827
Binary files /dev/null and b/sound/items/taperecorder/taperecorder_print.ogg differ
diff --git a/sound/items/taperecorder/taperecorder_stop.ogg b/sound/items/taperecorder/taperecorder_stop.ogg
new file mode 100644
index 0000000000000..a3b0f659928f3
Binary files /dev/null and b/sound/items/taperecorder/taperecorder_stop.ogg differ
diff --git a/tgui/packages/tgui-panel/styles/goon/chat-dark.scss b/tgui/packages/tgui-panel/styles/goon/chat-dark.scss
index 7f0900ee516e1..e30a3478814e5 100644
--- a/tgui/packages/tgui-panel/styles/goon/chat-dark.scss
+++ b/tgui/packages/tgui-panel/styles/goon/chat-dark.scss
@@ -969,6 +969,11 @@ em {
font-family: 'Courier New', cursive, sans-serif;
}
+.tape_recorder {
+ color: #ff0000;
+ font-family: 'Courier New', cursive, sans-serif;
+}
+
.command_headset {
font-weight: bold;
font-size: 24px;
diff --git a/tgui/packages/tgui-panel/styles/goon/chat-light.scss b/tgui/packages/tgui-panel/styles/goon/chat-light.scss
index 44e3ea8702b07..0f9ef2f2be605 100644
--- a/tgui/packages/tgui-panel/styles/goon/chat-light.scss
+++ b/tgui/packages/tgui-panel/styles/goon/chat-light.scss
@@ -974,6 +974,11 @@ h2.alert {
font-family: 'Courier New', cursive, sans-serif;
}
+.tape_recorder {
+ color: #800000;
+ font-family: 'Courier New', cursive, sans-serif;
+}
+
.command_headset {
font-weight: bold;
font-size: 24px;