Merge pull request #28946 from lzimann/holo

Changes the holodeck to use tgui, plus some code refactor/improvements
This commit is contained in:
Joan Lung
2017-07-01 11:56:57 -04:00
committed by GitHub
5 changed files with 243 additions and 259 deletions
+206 -131
View File
@@ -15,6 +15,9 @@
The base of program_type will always be ignored; only subtypes will be loaded.
*/
#define HOLODECK_CD 25
#define HOLODECK_DMG_CD 500
/obj/machinery/computer/holodeck
name = "holodeck control console"
desc = "A computer used to control a nearby holodeck."
@@ -26,109 +29,106 @@
var/area/holodeck/last_program
var/area/offline_program = /area/holodeck/rec_center/offline
var/list/program_cache = list()
var/list/emag_programs = list()
var/list/program_cache
var/list/emag_programs
// Splitting this up allows two holodecks of the same size
// to use the same source patterns. Y'know, if you want to.
var/holodeck_type = /area/holodeck/rec_center // locate(this) to get the target holodeck
var/program_type = /area/holodeck/rec_center // subtypes of this (but not this itself) are loadable programs
// set this if you want it to start with some particular program.
var/init_program = null
// or this to get anything
var/random_program = 0
var/active = 0
var/damaged = 0
var/active = FALSE
var/damaged = FALSE
var/list/spawned = list()
var/list/effects = list()
var/last_change = 0
var/current_cd = 0
/obj/machinery/computer/holodeck/Initialize(mapload)
..()
return INITIALIZE_HINT_LATELOAD
/obj/machinery/computer/holodeck/LateInitialize()
if(ispath(holodeck_type,/area))
var/list/possible = get_areas(holodeck_type,subtypes = FALSE)
linked = pop(possible)
if(ispath(offline_program,/area))
var/list/possible = get_areas(offline_program,subtypes = FALSE)
offline_program = pop(possible)
// the following is necessary for power reasons
if(!linked || !offline_program)
log_world("No matching holodeck area found")
qdel(src)
return
var/area/AS = get_area(src)
if(istype(AS,/area/holodeck))
log_world("### MAPPING ERROR")
log_world("Holodeck computer cannot be in a holodeck.")
log_world("This would cause circular power dependency.")
qdel(src) // todo handle constructed computers
return //l-lewd...
else
linked.linked = src // todo detect multiple/constructed computers
if(ispath(holodeck_type, /area))
linked = locate(holodeck_type) in GLOB.sortedAreas
if(ispath(offline_program,/area))
offline_program = locate(offline_program) in GLOB.sortedAreas
// the following is necessary for power reasons
if(!linked || !offline_program)
log_world("No matching holodeck area found")
qdel(src)
return
var/area/AS = get_area(src)
if(istype(AS, /area/holodeck))
log_world("### MAPPING ERROR")
log_world("Holodeck computer cannot be in a holodeck.")
log_world("This would cause circular power dependency.")
qdel(src)
return
else
linked.linked = src
program_cache = list()
emag_programs = list()
for(var/typekey in subtypesof(program_type))
var/area/holodeck/A = locate(typekey)
if(!A || A == offline_program)
continue
if(A.contents.len == 0)
continue // not loaded
if(A.restricted)
emag_programs += A
else
program_cache += A
if(typekey == init_program)
load_program(A,force=1)
if(random_program && program_cache.len && init_program == null)
load_program(pick(program_cache),force=1)
else if(!program)
load_program(offline_program)
generate_program_list()
load_program(offline_program, FALSE, FALSE)
/obj/machinery/computer/holodeck/Destroy()
emergency_shutdown()
if(linked)
linked.linked = null
return ..()
/obj/machinery/computer/holodeck/power_change()
..()
. = ..()
toggle_power(!stat)
/obj/machinery/computer/holodeck/proc/toggle_power(toggleOn = 0)
if(active == toggleOn) return
/obj/machinery/computer/holodeck/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "holodeck", name, 400, 500, master_ui, state)
ui.open()
if(toggleOn)
if(last_program && last_program != offline_program)
load_program(last_program, delay = 1)
active = 1
else
last_program = program
load_program(offline_program,force=1)
active = 0
/obj/machinery/computer/holodeck/ui_data(mob/user)
var/list/data = list()
/obj/machinery/computer/holodeck/proc/emergency_shutdown()
last_program = program
load_program(offline_program,1)
active = 0
data["default_programs"] = program_cache
if(emagged)
data["emagged"] = TRUE
data["emag_programs"] = emag_programs
data["program"] = program
data["can_toggle_safety"] = issilicon(user) || IsAdminGhost(user)
return data
/obj/machinery/computer/holodeck/ui_act(action, params)
if(..())
return
. = TRUE
switch(action)
if("load_program")
var/program_to_load = text2path(params["type"])
if(!ispath(program_to_load))
return FALSE
var/area/A = locate(program_to_load) in GLOB.sortedAreas
if(A)
load_program(A)
if("safety")
emagged = !emagged
if(emagged && program && emag_programs[program.name])
emergency_shutdown()
nerf(emagged)
/obj/machinery/computer/holodeck/process()
if(damaged)
if(prob(10))
for(var/turf/T in linked)
if(prob(5))
var/datum/effect_system/spark_spread/s = new
s.set_up(2, 1, T)
s.start()
return
if(damaged && prob(10))
for(var/turf/T in linked)
if(prob(5))
do_sparks(2, 1, T)
return
if(!..() || !active)
return
if(!floorcheck())
emergency_shutdown()
damaged = 1
damaged = TRUE
for(var/mob/M in urange(10,src))
M.show_message("The holodeck overloads!")
@@ -144,67 +144,24 @@
for(var/item in spawned)
if(!(get_turf(item) in linked))
derez(item, 0)
for(var/obj/effect/holodeck_effect/HE in effects)
for(var/e in effects)
var/obj/effect/holodeck_effect/HE = e
HE.tick()
active_power_usage = 50 + spawned.len * 3 + effects.len * 5
/obj/machinery/computer/holodeck/proc/floorcheck()
for(var/turf/T in linked)
if(!T.intact || isspaceturf(T))
return 0
return 1
/obj/machinery/computer/holodeck/Topic(href, list/href_list)
if(..())
/obj/machinery/computer/holodeck/emag_act(mob/user)
if(emagged)
return
usr.set_machine(src)
add_fingerprint(usr)
if(href_list["loadarea"])
var/areapath = text2path(href_list["loadarea"])
if(!ispath(areapath, /area/holodeck))
return
var/area/holodeck/area = locate(areapath)
if(!istype(area))
return
if(area == offline_program || (area in program_cache) || (emagged && (area in emag_programs)))
load_program(area)
else if("safety" in href_list)
var/safe = text2num(href_list["safety"])
if(!issilicon(usr))
return
emagged = !safe
if(!program)
return
if(safe && (program in emag_programs))
emergency_shutdown()
nerf(safe)
updateUsrDialog()
/obj/machinery/computer/holodeck/proc/nerf(active)
for(var/obj/item/I in spawned)
I.damtype = (active? STAMINA : initial(I.damtype) )
for(var/obj/effect/holodeck_effect/HE in effects)
HE.safety(active)
/obj/machinery/computer/holodeck/emag_act(mob/user as mob)
if(!emagged)
if(!emag_programs.len)
to_chat(user, "[src] does not seem to have a card swipe port. It must be an inferior model.")
return
playsound(loc, 'sound/effects/sparks4.ogg', 75, 1)
emagged = 1
to_chat(user, "<span class='warning'>You vastly increase projector power and override the safety and security protocols.</span>")
to_chat(user, "Warning. Automatic shutoff and derezing protocols have been corrupted. Please call Nanotrasen maintenance and do not use the simulator.")
log_game("[key_name(user)] emagged the Holodeck Control Console")
updateUsrDialog()
nerf(!emagged)
/obj/machinery/computer/holodeck/Destroy()
if(linked)
emergency_shutdown()
linked.linked = null
return ..()
if(!LAZYLEN(emag_programs))
to_chat(user, "[src] does not seem to have a card swipe port. It must be an inferior model.")
return
playsound(src, 'sound/effects/sparks4.ogg', 75, 1)
emagged = TRUE
to_chat(user, "<span class='warning'>You vastly increase projector power and override the safety and security protocols.</span>")
to_chat(user, "Warning. Automatic shutoff and derezing protocols have been corrupted. Please call Nanotrasen maintenance and do not use the simulator.")
log_game("[key_name(user)] emagged the Holodeck Control Console")
nerf(!emagged)
/obj/machinery/computer/holodeck/emp_act(severity)
emergency_shutdown()
@@ -216,4 +173,122 @@
/obj/machinery/computer/holodeck/blob_act(obj/structure/blob/B)
emergency_shutdown()
return ..()
return ..()
/obj/machinery/computer/holodeck/proc/generate_program_list()
for(var/typekey in subtypesof(program_type))
var/area/holodeck/A = locate(typekey) in GLOB.sortedAreas
if(!A || A == offline_program || !A.contents.len)
continue
var/list/info_this = list()
info_this["name"] = A.name
info_this["type"] = A.type
if(A.restricted)
LAZYADD(emag_programs, list(info_this))
else
LAZYADD(program_cache, list(info_this))
/obj/machinery/computer/holodeck/proc/toggle_power(toggleOn = FALSE)
if(active == toggleOn)
return
if(toggleOn)
if(last_program && last_program != offline_program)
addtimer(CALLBACK(src, .proc/load_program, last_program, TRUE), 25)
active = TRUE
else
last_program = program
load_program(offline_program, TRUE)
active = FALSE
/obj/machinery/computer/holodeck/proc/emergency_shutdown()
last_program = program
load_program(offline_program, TRUE)
active = FALSE
/obj/machinery/computer/holodeck/proc/floorcheck()
for(var/turf/T in linked)
if(!T.intact || isspaceturf(T))
return FALSE
return TRUE
/obj/machinery/computer/holodeck/proc/nerf(active)
for(var/obj/item/I in spawned)
I.damtype = active ? STAMINA : initial(I.damtype)
for(var/e in effects)
var/obj/effect/holodeck_effect/HE = e
HE.safety(active)
/obj/machinery/computer/holodeck/proc/load_program(area/A, force = FALSE, add_delay = TRUE)
if(!is_operational())
A = offline_program
force = TRUE
if(program == A)
return
if(current_cd > world.time && !force)
say("ERROR. Recalibrating projection apparatus.")
return
if(add_delay)
current_cd = world.time + HOLODECK_CD
if(damaged)
current_cd += HOLODECK_DMG_CD
active = (A != offline_program)
use_power = active + IDLE_POWER_USE
for(var/e in effects)
var/obj/effect/holodeck_effect/HE = e
HE.deactivate(src)
for(var/item in spawned)
derez(item, force)
program = A
// note nerfing does not yet work on guns, should
// should also remove/limit/filter reagents?
// this is an exercise left to others I'm afraid. -Sayu
spawned = A.copy_contents_to(linked, 1, nerf_weapons = !emagged)
for(var/obj/machinery/M in spawned)
M.flags |= NODECONSTRUCT
for(var/obj/structure/S in spawned)
S.flags |= NODECONSTRUCT
effects = list()
addtimer(CALLBACK(src, .proc/finish_spawn), 30)
/obj/machinery/computer/holodeck/proc/finish_spawn()
var/list/added = list()
for(var/obj/effect/holodeck_effect/HE in spawned)
effects += HE
spawned -= HE
var/atom/x = HE.activate(src)
if(istype(x) || islist(x))
spawned += x // holocarp are not forever
added += x
for(var/obj/machinery/M in added)
M.flags |= NODECONSTRUCT
for(var/obj/structure/S in added)
S.flags |= NODECONSTRUCT
/obj/machinery/computer/holodeck/proc/derez(obj/O, silent = TRUE, forced = FALSE)
// Emagging a machine creates an anomaly in the derez systems.
if(O && emagged && !stat && !forced)
if((ismob(O) || ismob(O.loc)) && prob(50))
addtimer(CALLBACK(src, .proc/derez, O, silent), 50) // may last a disturbingly long time
return
spawned -= O
if(!O)
return
var/turf/T = get_turf(O)
for(var/atom/movable/AM in O) // these should be derezed if they were generated
AM.forceMove(T)
if(ismob(AM))
silent = FALSE // otherwise make sure they are dropped
if(!silent)
visible_message("[O] fades away!")
qdel(O)
#undef HOLODECK_CD
#undef HOLODECK_DMG_CD
-111
View File
@@ -1,111 +0,0 @@
/obj/machinery/computer/holodeck/attack_hand(var/mob/user as mob)
user.set_machine(src)
var/dat = "<h3>Current Loaded Programs</h3>"
dat += "<a href='?src=\ref[src];loadarea=[offline_program.type]'>Power Off</a><br>"
for(var/area/A in program_cache)
dat += "<a href='?src=\ref[src];loadarea=[A.type]'>[A.name]</a><br>"
if(emagged && emag_programs.len)
dat += "<span class='warning'>SUPERVISOR ACCESS - SAFETY PROTOCOLS DISABLED - CAUTION: EMITTER ANOMALY</span><br>"
for(var/area/A in emag_programs)
dat += "<a href='?src=\ref[src];loadarea=[A.type]'>[A.name]</a><br>"
var/datum/browser/popup = new(user, "computer", name, 400, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
/obj/machinery/computer/holodeck/attack_ai(var/mob/user as mob)
var/dat = "<h3>Current Loaded Programs</h3>"
dat += "<a href='?src=\ref[src];loadarea=[offline_program.type]'>Power Off</a><br>"
for(var/area/A in program_cache)
dat += "<a href='?src=\ref[src];loadarea=[A.type]'>[A.name]</a><br>"
if(emag_programs.len)
dat += "<br>"
if(emagged)
dat += "Safety protocol: <span class='bad'>Offline</span> <a href='?\ref[src];safety=1'>Engage</a><br>"
for(var/area/A in emag_programs)
dat += "<a href='?src=\ref[src];loadarea=[A.type]'>[A.name]</a><br>"
else
dat += "Safety protocol: <span class='good'>Online</span> <a href='?\ref[src];safety=0'>Disengage</a><br>"
var/datum/browser/popup = new(user, "computer", name, 400, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/computer/holodeck/proc/load_program(var/area/A, var/force = 0, var/delay = 0)
if(stat)
A = offline_program
force = 1
delay = 0
if(program == A)
return
if(world.time < (last_change + 25 + (damaged?500:0)) && !force)
if(delay)
sleep(25)
else
if(world.time < (last_change + 15))//To prevent super-spam clicking, reduced process size and annoyance -Sieve
return
if(get_dist(usr,src) <= 3)
to_chat(usr, "<span class='warning'>ERROR. Recalibrating projection apparatus.</span>")
return
last_change = world.time
active = (A != offline_program)
use_power = active ? ACTIVE_POWER_USE : IDLE_POWER_USE
for(var/obj/effect/holodeck_effect/HE in effects)
HE.deactivate(src)
for(var/item in spawned)
derez(item, forced=force)
program = A
// note nerfing does not yet work on guns, should
// should also remove/limit/filter reagents?
// this is an exercise left to others I'm afraid. -Sayu
spawned = A.copy_contents_to(linked, 1, nerf_weapons = !emagged)
for(var/obj/machinery/M in spawned)
M.flags |= NODECONSTRUCT
for(var/obj/structure/S in spawned)
S.flags |= NODECONSTRUCT
effects = list()
spawn(30)
var/list/added = list()
for(var/obj/effect/holodeck_effect/HE in spawned)
effects += HE
spawned -= HE
var/atom/x = HE.activate(src)
if(istype(x) || islist(x))
spawned += x // holocarp are not forever
added += x
for(var/obj/machinery/M in added)
M.flags |= NODECONSTRUCT
for(var/obj/structure/S in added)
S.flags |= NODECONSTRUCT
/obj/machinery/computer/holodeck/proc/derez(var/obj/obj, var/silent = 1, var/forced = 0)
// Emagging a machine creates an anomaly in the derez systems.
if(obj && src.emagged && !src.stat && !forced)
if((ismob(obj) || ismob(obj.loc)) && prob(50))
spawn(50) .(obj,silent) // may last a disturbingly long time
return
spawned.Remove(obj)
if(!obj)
return
var/turf/T = get_turf(obj)
for(var/atom/movable/AM in obj.contents) // these should be derezed if they were generated
AM.loc = T
if(ismob(AM))
silent = FALSE // otherwise make sure they are dropped
if(!silent)
visible_message("The [obj.name] fades away!")
qdel(obj)