mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 12:41:09 +01:00
Further tape and universal recorder improvements (#56023)
- Makes it so warning for time happens based on the time and not when the tape recorder hears something - Makes stopping work correctly when we try to record with a full tape or when recording stops because of a full tape - Uses the SECONDS and MINUTES defines instead of a mixture of undefined deciseconds and seconds that are multiplied by 10 (while having to divide by 10 in a couple of places) - Cannot print a transcript for a blank tape - Tweaks transcript name setting to be better formatted - No longer update_icon() after stop() under play() (it's in the stop() proc) - Reorders stopping to be consistent between playing and recording and logical (which probably makes no noticeable difference) - Play/record hiss sound loop (mediocre due to lack of options in sound loops to cut and not fade in/out) - Drop and pick up sounds - 0→2 throwforce (like it was when Uhangi added them, before Hornygranny made it 0 for some reason) - Cleans up radial image() usage - Clarifies radial icon var - Clarifies tape unspooling and respooling vars - Random 3 char hexademical on tape names - Tape can spawn on either side - Adds greyscale tapes and randomised colouration
This commit is contained in:
@@ -61,6 +61,7 @@
|
||||
#define SPAN_COMMAND "command_headset"
|
||||
#define SPAN_CLOWN "clown"
|
||||
#define SPAN_SINGING "singing"
|
||||
#define SPAN_TAPE_RECORDER "tape_recorder"
|
||||
|
||||
//bitflag #defines for return value of the radio() proc.
|
||||
#define ITALICS (1<<0)
|
||||
|
||||
@@ -51,3 +51,8 @@
|
||||
mid_sounds = list('sound/items/weeoo1.ogg')
|
||||
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
|
||||
|
||||
@@ -12,7 +12,10 @@
|
||||
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 = FALSE
|
||||
var/playing = FALSE
|
||||
var/playsleepseconds = 0
|
||||
@@ -21,19 +24,37 @@
|
||||
var/open_panel = FALSE
|
||||
var/canprint = TRUE
|
||||
var/list/icons_available = list()
|
||||
var/icon_directory = 'icons/effects/icons.dmi'
|
||||
|
||||
var/radial_icon_file = 'icons/hud/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(list(src))
|
||||
update_icon()
|
||||
|
||||
/obj/item/taperecorder/proc/readout()
|
||||
if(mytape)
|
||||
if(playing)
|
||||
return "<span class='notice'><b>PLAYING</b></span>"
|
||||
else
|
||||
var/time = mytape.used_capacity / 10 //deciseconds / 10 = seconds
|
||||
var/mins = round(time / 60)
|
||||
var/secs = time - mins * 60
|
||||
return "<span class='notice'><b>[mins]</b>m <b>[secs]</b>s</span>"
|
||||
return "<span class='notice'><b>NO TAPE INSERTED</b></span>"
|
||||
|
||||
/obj/item/taperecorder/examine(mob/user)
|
||||
. = ..()
|
||||
. += "The wire panel is [open_panel ? "opened" : "closed"]."
|
||||
if(in_range(src, user) || isobserver(user))
|
||||
. += "<span class='notice'>The wire panel is [open_panel ? "opened" : "closed"]. The display reads:</span>"
|
||||
. += "[readout()]"
|
||||
|
||||
/obj/item/taperecorder/AltClick(mob/user)
|
||||
. = ..()
|
||||
@@ -42,22 +63,23 @@
|
||||
/obj/item/taperecorder/proc/update_available_icons()
|
||||
icons_available = list()
|
||||
|
||||
if(recording)
|
||||
icons_available += list("Stop Recording" = image(icon = icon_directory, icon_state = "record_stop"))
|
||||
else
|
||||
if(!playing)
|
||||
icons_available += list("Record" = image(icon = icon_directory, icon_state = "record"))
|
||||
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)
|
||||
icons_available += list("Pause" = image(icon = icon_directory, icon_state = "pause"))
|
||||
else
|
||||
if(!recording)
|
||||
icons_available += list("Play" = image(icon = icon_directory, icon_state = "play"))
|
||||
if(playing || recording)
|
||||
icons_available += list("Stop" = image(radial_icon_file,"stop"))
|
||||
|
||||
if(canprint && !recording && !playing)
|
||||
icons_available += list("Print Transcript" = image(icon = icon_directory, icon_state = "print"))
|
||||
if(mytape)
|
||||
icons_available += list("Eject" = image(icon = icon_directory, icon_state = "eject"))
|
||||
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/attackby(obj/item/I, mob/user, params)
|
||||
if(!mytape && istype(I, /obj/item/tape))
|
||||
@@ -79,7 +101,7 @@
|
||||
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
|
||||
@@ -122,7 +144,8 @@
|
||||
. = ..()
|
||||
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"
|
||||
@@ -130,30 +153,35 @@
|
||||
|
||||
if(!can_use(usr))
|
||||
return
|
||||
if(!mytape || mytape.ruined)
|
||||
if(!mytape || mytape.unspooled)
|
||||
return
|
||||
if(recording)
|
||||
return
|
||||
if(playing)
|
||||
return
|
||||
|
||||
playsound(src, 'sound/items/taperecorder/taperecorder_play.ogg', 50, FALSE)
|
||||
|
||||
if(mytape.used_capacity < mytape.max_capacity)
|
||||
to_chat(usr, "<span class='notice'>Recording started.</span>")
|
||||
playsound(src, 'sound/items/taperecorder/taperecorder_play.ogg', 50, FALSE)
|
||||
recording = 1
|
||||
recording = TRUE
|
||||
say("Recording started.")
|
||||
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 = FALSE
|
||||
update_icon()
|
||||
mytape.used_capacity += 1 SECONDS
|
||||
used += 1 SECONDS
|
||||
if(max - used < time_left_warning && !time_warned)
|
||||
time_warned = TRUE
|
||||
say("[(max - used) / 10] seconds left!") //deciseconds / 10 = seconds
|
||||
sleep(1 SECONDS)
|
||||
if(used >= max)
|
||||
say("Tape full.")
|
||||
stop()
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>The tape is full.</span>")
|
||||
say("The tape is full!")
|
||||
playsound(src, 'sound/items/taperecorder/taperecorder_stop.ogg', 50, FALSE)
|
||||
|
||||
|
||||
/obj/item/taperecorder/verb/stop()
|
||||
@@ -164,19 +192,16 @@
|
||||
return
|
||||
|
||||
if(recording)
|
||||
playsound(src, 'sound/items/taperecorder/taperecorder_stop.ogg', 50, FALSE)
|
||||
say("Recording stopped.")
|
||||
recording = FALSE
|
||||
mytape.timestamp += mytape.used_capacity
|
||||
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] Recording stopped."
|
||||
playsound(src, 'sound/items/taperecorder/taperecorder_stop.ogg', 50, FALSE)
|
||||
to_chat(usr, "<span class='notice'>Recording stopped.</span>")
|
||||
return
|
||||
else if(playing)
|
||||
playing = FALSE
|
||||
var/turf/T = get_turf(src)
|
||||
playsound(src, 'sound/items/taperecorder/taperecorder_stop.ogg', 50, FALSE)
|
||||
T.visible_message("<font color=Maroon><B>Tape Recorder</B>: Playback stopped.</font>")
|
||||
say("Playback stopped.")
|
||||
playing = FALSE
|
||||
time_warned = FALSE
|
||||
update_icon()
|
||||
|
||||
update_sound()
|
||||
|
||||
/obj/item/taperecorder/verb/play()
|
||||
set name = "Play Tape"
|
||||
@@ -184,49 +209,49 @@
|
||||
|
||||
if(!can_use(usr))
|
||||
return
|
||||
if(!mytape || mytape.ruined)
|
||||
if(!mytape || mytape.unspooled)
|
||||
return
|
||||
if(recording)
|
||||
return
|
||||
if(playing)
|
||||
return
|
||||
|
||||
playing = 1
|
||||
playing = TRUE
|
||||
update_icon()
|
||||
to_chat(usr, "<span class='notice'>Playing started.</span>")
|
||||
update_sound()
|
||||
say("Playback started.")
|
||||
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 == FALSE)
|
||||
break
|
||||
if(mytape.storedinfo.len < i)
|
||||
say("End of recording.")
|
||||
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] seconds of silence.")
|
||||
playsleepseconds = 1 SECONDS
|
||||
i++
|
||||
|
||||
playing = FALSE
|
||||
update_icon()
|
||||
stop()
|
||||
|
||||
|
||||
/obj/item/taperecorder/attack_self(mob/user)
|
||||
if(!mytape)
|
||||
to_chat(user, "<span class='notice'>The [src] does not have a tape inside.</span>")
|
||||
to_chat(user, "<span class='notice'>\The [src] is empty.</span>")
|
||||
return
|
||||
if(mytape.ruined)
|
||||
to_chat(user, "<span class='notice'>The tape inside the [src] appears to be broken.</span>")
|
||||
if(mytape.unspooled)
|
||||
to_chat(user, "<span class='warning'>\The tape inside \the [src] is broken!</span>")
|
||||
return
|
||||
|
||||
update_available_icons()
|
||||
@@ -235,9 +260,7 @@
|
||||
if(!selection)
|
||||
return
|
||||
switch(selection)
|
||||
if("Pause")
|
||||
stop()
|
||||
if("Stop Recording") // yes we actually need 2 seperate stops for the same proc- Hopek
|
||||
if("Stop")
|
||||
stop()
|
||||
if("Record")
|
||||
record()
|
||||
@@ -252,24 +275,28 @@
|
||||
set name = "Print Transcript"
|
||||
set category = "Object"
|
||||
|
||||
if(!mytape.storedinfo.len)
|
||||
return
|
||||
if(!can_use(usr))
|
||||
return
|
||||
if(!mytape)
|
||||
return
|
||||
if(!canprint)
|
||||
to_chat(usr, "<span class='notice'>The recorder can't print that fast!</span>")
|
||||
to_chat(usr, "<span class='warning'>The recorder can't print that fast!</span>")
|
||||
return
|
||||
if(recording || playing)
|
||||
return
|
||||
|
||||
to_chat(usr, "<span class='notice'>Transcript printed.</span>")
|
||||
say("Transcript printed.")
|
||||
playsound(src, 'sound/items/taperecorder/taperecorder_print.ogg', 50, FALSE)
|
||||
var/obj/item/paper/P = new /obj/item/paper(get_turf(src))
|
||||
var/t1 = "<B>Transcript:</B><BR><BR>"
|
||||
for(var/i = 1, mytape.storedinfo.len >= i, i++)
|
||||
t1 += "[mytape.storedinfo[i]]<BR>"
|
||||
P.info = t1
|
||||
P.name = "paper- 'Transcript'"
|
||||
var/tapename = mytape.name
|
||||
var/prototapename = initial(mytape.name)
|
||||
P.name = "paper- '[tapename == prototapename ? "Tape" : "[tapename]"] Transcript'"
|
||||
P.update_icon_state()
|
||||
usr.put_in_hands(P)
|
||||
canprint = FALSE
|
||||
@@ -283,7 +310,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'
|
||||
inhand_icon_state = "analyzer"
|
||||
@@ -293,46 +320,114 @@
|
||||
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 = FALSE
|
||||
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/hud/radial_tape.dmi'
|
||||
|
||||
/obj/item/tape/fire_act(exposed_temperature, exposed_volume)
|
||||
ruin()
|
||||
unspool()
|
||||
..()
|
||||
|
||||
/obj/item/tape/Initialize()
|
||||
. = ..()
|
||||
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)
|
||||
if(!ruined)
|
||||
to_chat(user, "<span class='notice'>You pull out all the tape!</span>")
|
||||
ruin()
|
||||
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()
|
||||
to_chat(user, "<span class='notice'>You turn \the [src] over.</span>")
|
||||
playsound(src, 'sound/items/taperecorder/tape_flip.ogg', 70, FALSE)
|
||||
if("Unwind tape")
|
||||
if(loc != user)
|
||||
return
|
||||
unspool()
|
||||
to_chat(user, "<span class='warning'>You pull out all the tape!</span>")
|
||||
|
||||
/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 = TRUE
|
||||
unspooled = TRUE
|
||||
|
||||
|
||||
/obj/item/tape/proc/fix()
|
||||
/obj/item/tape/proc/respool()
|
||||
cut_overlay("ribbonoverlay")
|
||||
ruined = FALSE
|
||||
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/I, mob/user, params)
|
||||
if(ruined && (I.tool_behaviour == TOOL_SCREWDRIVER || istype(I, /obj/item/pen)))
|
||||
if(unspooled && (I.tool_behaviour == TOOL_SCREWDRIVER))
|
||||
to_chat(user, "<span class='notice'>You start winding the tape back in...</span>")
|
||||
if(I.use_tool(src, user, 120))
|
||||
to_chat(user, "<span class='notice'>You wound the tape back in.</span>")
|
||||
fix()
|
||||
to_chat(user, "<span class='notice'>You wind the tape back in.</span>")
|
||||
respool()
|
||||
|
||||
//Random colour tapes
|
||||
/obj/item/tape/random
|
||||
icon_state = "random_tape"
|
||||
|
||||
/obj/item/tape/random/Initialize()
|
||||
icon_state = "tape_[pick("white", "blue", "red", "yellow", "purple", "greyscale")]"
|
||||
. = ..()
|
||||
icon_state = "tape_[pick("white", "blue", "red", "yellow", "purple")]"
|
||||
|
||||
/obj/item/tape/dyed
|
||||
icon_state = "greyscale"
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 498 B |
Binary file not shown.
|
After Width: | Height: | Size: 620 B |
Binary file not shown.
|
After Width: | Height: | Size: 457 B |
Binary file not shown.
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -666,6 +666,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: 160%;
|
||||
|
||||
@@ -706,6 +706,11 @@ h1.alert, 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: 160%;
|
||||
|
||||
Reference in New Issue
Block a user