diff --git a/code/datums/holocall.dm b/code/datums/holocall.dm index abad0dba1d..75abc87080 100644 --- a/code/datums/holocall.dm +++ b/code/datums/holocall.dm @@ -1,5 +1,14 @@ #define HOLOPAD_MAX_DIAL_TIME 200 +#define HOLORECORD_DELAY "delay" +#define HOLORECORD_SAY "say" +#define HOLORECORD_SOUND "sound" +#define HOLORECORD_LANGUAGE "lang" +#define HOLORECORD_PRESET "preset" +#define HOLORECORD_RENAME "rename" + +#define HOLORECORD_MAX_LENGTH 200 + /mob/camera/aiEye/remote/holo/setLoc() . = ..() var/obj/machinery/holopad/H = origin @@ -184,3 +193,122 @@ /datum/action/innate/end_holocall/Activate() hcall.Disconnect(hcall.calling_holopad) + + +//RECORDS +/datum/holorecord + var/caller_name = "Unknown" //Caller name + var/image/caller_image + var/list/entries = list() + var/language = /datum/language/common //Initial language, can be changed by HOLORECORD_LANGUAGE entries + +/obj/item/disk/holodisk + name = "holorecord disk" + desc = "Stores recorder holocalls." + icon_state = "holodisk" + var/datum/holorecord/record + //Preset variables + var/preset_image_type + var/preset_record_text + +/obj/item/disk/holodisk/Initialize(mapload) + . = ..() + if(preset_record_text) + build_record() + +/obj/item/disk/holodisk/Destroy() + QDEL_NULL(record) + return ..() + +/obj/item/disk/holodisk/proc/build_record() + record = new + var/list/lines = splittext(preset_record_text,"\n") + for(var/line in lines) + var/prepared_line = trim(line) + if(!length(prepared_line)) + continue + var/splitpoint = findtext(prepared_line," ") + if(!splitpoint) + continue + var/command = copytext(prepared_line,1,splitpoint) + var/value = copytext(prepared_line,splitpoint+1) + switch(command) + if("DELAY") + var/delay_value = text2num(value) + if(!delay_value) + continue + record.entries += list(list(HOLORECORD_DELAY,delay_value)) + if("NAME") + if(!record.caller_name) + record.caller_name = value + else + record.entries += list(list(HOLORECORD_RENAME,value)) + if("SAY") + record.entries += list(list(HOLORECORD_SAY,value)) + if("SOUND") + record.entries += list(list(HOLORECORD_SOUND,value)) + if("LANGUAGE") + var/lang_type = text2path(value) + if(ispath(lang_type,/datum/language)) + record.entries += list(list(HOLORECORD_LANGUAGE,lang_type)) + if("PRESET") + var/preset_type = text2path(value) + if(ispath(preset_type,/datum/preset_holoimage)) + record.entries += list(list(HOLORECORD_PRESET,preset_type)) + if(!preset_image_type) + record.caller_image = image('icons/mob/animal.dmi',"old") + else + var/datum/preset_holoimage/H = new preset_image_type + record.caller_image = H.build_image() + +//These build caller image from outfit and some additional data, for use by mappers for ruin holorecords +/datum/preset_holoimage + var/nonhuman_mobtype //Fill this if you just want something nonhuman + var/outfit_type + var/species_type = /datum/species/human + +/datum/preset_holoimage/proc/build_image() + if(nonhuman_mobtype) + var/mob/living/L = nonhuman_mobtype + . = image(initial(L.icon),initial(L.icon_state)) + else + var/mob/living/carbon/human/dummy/mannequin = generate_or_wait_for_human_dummy("HOLODISK_PRESET") + if(species_type) + mannequin.set_species(species_type) + if(outfit_type) + mannequin.equipOutfit(outfit_type,TRUE) + mannequin.setDir(SOUTH) + COMPILE_OVERLAYS(mannequin) + . = getFlatIcon(mannequin) + unset_busy_human_dummy("HOLODISK_PRESET") + +/obj/item/disk/holodisk/example + preset_image_type = /datum/preset_holoimage/clown + preset_record_text = {" + NAME Clown + DELAY 10 + SAY Why did the chaplain cross the maint ? + DELAY 20 + SAY He wanted to get to the other side! + SOUND clownstep + DELAY 30 + LANGUAGE /datum/language/narsie + SAY Helped him get there! + DELAY 10 + SAY ALSO IM SECRETLY A GORILLA + DELAY 10 + PRESET /datum/preset_holoimage/gorilla + NAME Gorilla + LANGUAGE /datum/language/common + SAY OOGA + DELAY 20"} + +/datum/preset_holoimage/engineer + outfit_type = /datum/outfit/job/engineer/gloved/rig + +/datum/preset_holoimage/gorilla + nonhuman_mobtype = /mob/living/simple_animal/hostile/gorilla + +/datum/preset_holoimage/clown + outfit_type = /datum/outfit/job/clown + diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index afc463a60e..d6d8c93ed1 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -47,6 +47,12 @@ Possible to do for anyone motivated enough: var/temp = "" var/list/holo_calls //array of /datum/holocalls var/datum/holocall/outgoing_call //do not modify the datums only check and call the public procs + var/obj/item/disk/holodisk/disk //Record disk + var/replay_mode = FALSE //currently replaying a recording + var/record_mode = FALSE //currently recording + var/record_start = 0 //recording start time + var/record_user //user that inititiated the recording + var/obj/effect/overlay/holo_pad_hologram/replay_holo //replay hologram var/static/force_answer_call = FALSE //Calls will be automatically answered after a couple rings, here for debugging var/static/list/holopads = list() @@ -64,6 +70,14 @@ Possible to do for anyone motivated enough: for (var/I in masters) clear_holo(I) + + if(replay_mode) + replay_stop() + if(record_mode) + record_stop() + + QDEL_NULL(disk) + holopads -= src return ..() @@ -72,6 +86,10 @@ Possible to do for anyone motivated enough: stat &= ~NOPOWER else stat |= NOPOWER + if(replay_mode) + replay_stop() + if(record_mode) + record_stop() if(outgoing_call) outgoing_call.ConnectionFailure(src) @@ -101,6 +119,18 @@ Possible to do for anyone motivated enough: if(default_deconstruction_crowbar(P)) return + + if(istype(P,/obj/item/disk/holodisk)) + if(disk) + to_chat(user,"There's already a disk inside [src]") + return + if (!user.transferItemToLoc(P,src)) + return + to_chat(user,"You insert [P] into [src]") + disk = P + updateDialog() + return + return ..() /obj/machinery/holopad/AltClick(mob/living/carbon/human/user) @@ -122,6 +152,17 @@ Possible to do for anyone motivated enough: else dat = "Request an AI's presence.
" dat += "Call another holopad.
" + if(disk) + if(disk.record) + //Replay + dat += "Replay disk recording.
" + //Clear + dat += "Clear disk recording.
" + else + //Record + dat += "Start new recording.
" + //Eject + dat += "Eject disk.
" if(LAZYLEN(holo_calls)) dat += "=====================================================
" @@ -145,7 +186,7 @@ Possible to do for anyone motivated enough: dat += "Disconnect call from [HC.user].
" - var/datum/browser/popup = new(user, "holopad", name, 300, 130) + var/datum/browser/popup = new(user, "holopad", name, 300, 150) popup.set_content(dat) popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.open() @@ -215,6 +256,22 @@ Possible to do for anyone motivated enough: temp = "" if(outgoing_call) outgoing_call.Disconnect() + + else if(href_list["disk_eject"]) + if(disk && !replay_mode) + disk.forceMove(drop_location()) + disk = null + + else if(href_list["replay_stop"]) + replay_stop() + else if(href_list["replay_start"]) + replay_start() + else if(href_list["record_start"]) + record_start(usr) + else if(href_list["record_stop"]) + record_stop() + else if(href_list["record_clear"]) + record_clear() updateDialog() @@ -269,6 +326,7 @@ Possible to do for anyone motivated enough: else playsound(src, 'sound/machines/twobeep.ogg', 100) //bring, bring! + /obj/machinery/holopad/proc/activate_holo(mob/living/user) var/mob/living/silicon/ai/AI = user if(!istype(AI)) @@ -321,15 +379,24 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ if(outgoing_call && speaker == outgoing_call.user) outgoing_call.hologram.say(raw_message) + if(record_mode && speaker == record_user) + record_message(speaker,raw_message,message_language) + /obj/machinery/holopad/proc/SetLightsAndPower() var/total_users = masters.len + LAZYLEN(holo_calls) use_power = total_users > 0 ? ACTIVE_POWER_USE : IDLE_POWER_USE active_power_usage = HOLOPAD_PASSIVE_POWER_USAGE + (HOLOGRAM_POWER_USAGE * total_users) - if(total_users) + if(total_users || replay_mode) set_light(2) - icon_state = "holopad1" else set_light(0) + update_icon() + +/obj/machinery/holopad/update_icon() + var/total_users = masters.len + LAZYLEN(holo_calls) + if(total_users || replay_mode) + icon_state = "holopad1" + else icon_state = "holopad0" /obj/machinery/holopad/proc/set_holo(mob/living/user, var/obj/effect/overlay/holo_pad_hologram/h) @@ -365,6 +432,128 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ clear_holo(user) return TRUE +// RECORDED MESSAGES + +/obj/machinery/holopad/proc/setup_replay_holo(datum/holorecord/record) + var/obj/effect/overlay/holo_pad_hologram/Hologram = new(loc)//Spawn a blank effect at the location. + Hologram.add_overlay(record.caller_image) + Hologram.alpha = 170 + Hologram.add_atom_colour("#77abff", FIXED_COLOUR_PRIORITY) + Hologram.dir = SOUTH //for now + Hologram.grant_all_languages(omnitongue=TRUE) + var/datum/language_holder/holder = Hologram.get_language_holder() + holder.selected_default_language = record.language + Hologram.mouse_opacity = MOUSE_OPACITY_TRANSPARENT//So you can't click on it. + Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them. + Hologram.anchored = TRUE//So space wind cannot drag it. + Hologram.name = "[record.caller_name] (Hologram)"//If someone decides to right click. + Hologram.set_light(2) //hologram lighting + visible_message("A holographic image of [record.caller_name] flickers to life before your eyes!") + return Hologram + +/obj/machinery/holopad/proc/replay_start() + if(!replay_mode) + replay_mode = TRUE + replay_holo = setup_replay_holo(disk.record) + temp = "Replaying...
" + temp += "End replay." + SetLightsAndPower() + replay_entry(1) + return + +/obj/machinery/holopad/proc/replay_stop() + if(replay_mode) + replay_mode = FALSE + temp = null + QDEL_NULL(replay_holo) + SetLightsAndPower() + updateDialog() + +/obj/machinery/holopad/proc/record_start(mob/living/user) + if(!user || !disk || disk.record) + return + disk.record = new + record_mode = TRUE + record_start = world.time + record_user = user + disk.record.caller_image = get_record_icon(user) + temp = "Recording...
" + temp += "End recording." + +/obj/machinery/holopad/proc/get_record_icon(mob/living/user) + var/olddir = user.dir + user.setDir(SOUTH) + . = getFlatIcon(user) + user.setDir(olddir) + +/obj/machinery/holopad/proc/record_message(mob/living/speaker,message,language) + if(!record_mode) + return + //make this command so you can have multiple languages in single record + if(!disk.record.caller_name && istype(speaker)) + disk.record.caller_name = speaker.name + if(!disk.record.language) + disk.record.language = language + else if(language != disk.record.language) + disk.record.entries += list(list(HOLORECORD_LANGUAGE,language)) + + var/current_delay = 0 + for(var/E in disk.record.entries) + var/list/entry = E + if(entry[1] != HOLORECORD_DELAY) + continue + current_delay += entry[2] + + var/time_delta = world.time - record_start - current_delay + + if(time_delta >= 1) + disk.record.entries += list(list(HOLORECORD_DELAY,time_delta)) + disk.record.entries += list(list(HOLORECORD_SAY,message)) + if(disk.record.entries.len >= HOLORECORD_MAX_LENGTH) + record_stop() + +/obj/machinery/holopad/proc/replay_entry(entry_number) + if(!replay_mode) + return + if(disk.record.entries.len < entry_number) + replay_stop() + return + var/list/entry = disk.record.entries[entry_number] + var/command = entry[1] + switch(command) + if(HOLORECORD_SAY) + var/message = entry[2] + if(replay_holo) + replay_holo.say(message) + if(HOLORECORD_SOUND) + playsound(src,entry[2],50,1) + if(HOLORECORD_DELAY) + addtimer(CALLBACK(src,.proc/replay_entry,entry_number+1),entry[2]) + return + if(HOLORECORD_LANGUAGE) + var/datum/language_holder/holder = replay_holo.get_language_holder() + holder.selected_default_language = entry[2] + if(HOLORECORD_PRESET) + var/preset_type = entry[2] + var/datum/preset_holoimage/H = new preset_type + replay_holo.cut_overlays() + replay_holo.add_overlay(H.build_image()) + if(HOLORECORD_RENAME) + replay_holo.name = entry[2] + " (Hologram)" + .(entry_number+1) + +/obj/machinery/holopad/proc/record_stop() + if(record_mode) + record_mode = FALSE + temp = null + record_user = null + updateDialog() + +/obj/machinery/holopad/proc/record_clear() + if(disk && disk.record) + QDEL_NULL(disk.record) + updateDialog() + /obj/effect/overlay/holo_pad_hologram var/mob/living/Impersonation var/datum/holocall/HC diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm index 03424346e8..1c0c12a02b 100644 --- a/code/modules/research/designs/autolathe_designs.dm +++ b/code/modules/research/designs/autolathe_designs.dm @@ -799,3 +799,22 @@ materials = list(MAT_METAL = 300, MAT_GLASS = 200) build_path = /obj/item/device/slime_scanner category = list("initial", "Misc") +<<<<<<< HEAD +======= + +/datum/design/miniature_power_cell + name = "Light Fixture Battery" + id = "miniature_power_cell" + build_type = AUTOLATHE + materials = list(MAT_GLASS = 20) + build_path = /obj/item/stock_parts/cell/emergency_light + category = list("initial", "Electronics") + +/datum/design/holodisk + name = "Holodisk" + id = "holodisk" + build_type = AUTOLATHE + materials = list(MAT_METAL = 1000) + build_path = /obj/item/disk/holodisk + category = list("initial", "Misc") +>>>>>>> 78fe2bc... Holorecord disks. (#32868) diff --git a/icons/obj/module.dmi b/icons/obj/module.dmi index c24f7c4c16..f5bd612c22 100644 Binary files a/icons/obj/module.dmi and b/icons/obj/module.dmi differ