mirror of
https://github.com/Citadel-Station-13/Citadel-Station-13-RP.git
synced 2026-08-21 13:46:55 +01:00
269 lines
6.5 KiB
Plaintext
269 lines
6.5 KiB
Plaintext
// todo: if byond ever gets threaded browsers, we're standardizing tgui.html and tgui_window.dm
|
|
// because manually reimplementing this shit is driving me nuts.
|
|
// todo: the cutscene system is kinda jank; we should just do lobbybrowser instead of using it for that.
|
|
|
|
/client/proc/init_cutscene_system()
|
|
set waitfor = FALSE
|
|
__init_cutscene_system()
|
|
|
|
/client/proc/__init_cutscene_system()
|
|
PRIVATE_PROC(TRUE)
|
|
sleep(1 SECONDS)
|
|
// if it is there and we can't tell because byond is byond, send it a signal to reload
|
|
src << output(null, "[SKIN_BROWSER_ID_CUTSCENE]:reviveWindow")
|
|
sleep(2 SECONDS)
|
|
// loads scenepanel if it isn't there
|
|
if(!cutscene_init)
|
|
src << browse(file('html/cutscenebrowser.html'), "window=[SKIN_BROWSER_ID_CUTSCENE]")
|
|
else
|
|
cutscene_ready = TRUE
|
|
|
|
/client/proc/cleanup_cutscene_system()
|
|
end_cutscene()
|
|
|
|
/client/verb/__declare_cutscene_boot()
|
|
set name = ".scenepanel_boot"
|
|
set hidden = TRUE
|
|
set instant = TRUE
|
|
|
|
cutscene_init = TRUE
|
|
cutscene_ready = TRUE
|
|
|
|
/client/verb/__declare_cutscene_revive()
|
|
set name = ".scenepanel_revive"
|
|
set hidden = TRUE
|
|
set instant = TRUE
|
|
|
|
cutscene_init = TRUE
|
|
|
|
/client/proc/block_on_cutscene_browser_ready()
|
|
UNTIL(cutscene_ready)
|
|
|
|
/client/proc/__start_cutscene(datum/cutscene/scene)
|
|
PRIVATE_PROC(TRUE)
|
|
block_on_cutscene_browser_ready()
|
|
if(cutscene)
|
|
end_cutscene()
|
|
cutscene = scene
|
|
cutscene.setup(src)
|
|
|
|
/client/proc/start_cutscene(datum/cutscene/scene)
|
|
set waitfor = FALSE
|
|
if(isnull(scene))
|
|
return
|
|
__start_cutscene(scene)
|
|
|
|
/client/proc/end_cutscene()
|
|
if(isnull(cutscene))
|
|
return
|
|
cutscene.cleanup(src)
|
|
cutscene = null
|
|
|
|
/**
|
|
* dynamic cutscene system with synchronization of state.
|
|
*/
|
|
/datum/cutscene
|
|
/// viewing clients
|
|
var/list/client/viewing
|
|
/// immediate start on init()
|
|
var/start_immediately = FALSE
|
|
/// started?
|
|
var/started = FALSE
|
|
|
|
/datum/cutscene/Destroy()
|
|
for(var/client/C as anything in viewing)
|
|
C.end_cutscene()
|
|
return ..()
|
|
|
|
/**
|
|
* initial state
|
|
*/
|
|
/datum/cutscene/proc/init()
|
|
if(start_immediately)
|
|
auto_start()
|
|
|
|
/**
|
|
* sends / enables all assets to client
|
|
*
|
|
* blocking proc
|
|
*/
|
|
/datum/cutscene/proc/setup(client/C)
|
|
var/had_clients = length(viewing)
|
|
LAZYINITLIST(viewing)
|
|
viewing += C
|
|
if(!had_clients)
|
|
auto_start()
|
|
return TRUE
|
|
|
|
/**
|
|
* removes / disables all assets from client
|
|
*/
|
|
/datum/cutscene/proc/cleanup(client/C)
|
|
viewing -= C
|
|
return TRUE
|
|
|
|
/**
|
|
* called when the first client starts viewing
|
|
* or immediately if start_immediately is set
|
|
*
|
|
* useful for synchronized state
|
|
*/
|
|
/datum/cutscene/proc/start()
|
|
|
|
/datum/cutscene/proc/auto_start()
|
|
if(started)
|
|
return
|
|
start()
|
|
|
|
/**
|
|
* renders in cutscene browser
|
|
*/
|
|
/datum/cutscene/browser
|
|
|
|
/**
|
|
* this should be cheap, cache results yourself if you need caching.
|
|
* this isn't done by default for memory reasons.
|
|
*
|
|
* assume that there's no polyfills other than:
|
|
* - PROP_ADD_EVENT_LISTENER
|
|
* - PROP_TEXT_CONTENT
|
|
* - window.setTimeout()
|
|
* - array.includes()
|
|
* - string.trim()
|
|
*
|
|
* returned HTML should be IE8 compatible.
|
|
*/
|
|
/datum/cutscene/browser/proc/build_inner_html(client/C)
|
|
return ""
|
|
|
|
/datum/cutscene/browser/setup(client/C)
|
|
. = ..()
|
|
push_build(C)
|
|
C.cutscene_browser = TRUE
|
|
winset(C, SKIN_BROWSER_ID_CUTSCENE, "is-visible=1")
|
|
|
|
/datum/cutscene/browser/cleanup(client/C)
|
|
. = ..()
|
|
push_dispose(C)
|
|
C.cutscene_browser = FALSE
|
|
winset(C, SKIN_BROWSER_ID_CUTSCENE, "is-visible=0")
|
|
// just in case
|
|
spawn(2 SECONDS)
|
|
// no QDELETED check because we'll already be deleted
|
|
if(winget(C, "[SKIN_BROWSER_ID_CUTSCENE]", "is-visible") == "true")
|
|
winset(C, SKIN_BROWSER_ID_CUTSCENE, "is-visible=0")
|
|
|
|
/datum/cutscene/browser/proc/push_build(client/C, raw_html = build_inner_html())
|
|
C << output("[url_encode(json_encode(list("raw_html" = raw_html)))]", "[SKIN_BROWSER_ID_CUTSCENE]:build")
|
|
|
|
/datum/cutscene/browser/proc/push_dispose(client/C)
|
|
C << output(null, "[SKIN_BROWSER_ID_CUTSCENE]:dispose")
|
|
|
|
/**
|
|
* simple cutscene that's just one asset that goes in an <img> tag
|
|
*/
|
|
/datum/cutscene/browser/simple
|
|
/// image file path
|
|
var/image_path
|
|
/// cached html
|
|
var/cached_html
|
|
/// what to fcopy the image as
|
|
var/use_fname
|
|
/// icon in question
|
|
var/icon/cached_icon
|
|
|
|
/datum/cutscene/browser/simple/init()
|
|
. = ..()
|
|
if(isicon(image_path))
|
|
cached_icon = icon(image_path)
|
|
else if(fexists(image_path)) // fails on URLs
|
|
cached_icon = icon(image_path)
|
|
/// good enough
|
|
var/mutated_path = "[ref(src)]_[rand(1, 1000)]"
|
|
cached_html = "<img id=\"primaryImage\" src=\"[isnull(cached_icon)? image_path : mutated_path]\">"
|
|
use_fname = mutated_path
|
|
|
|
/datum/cutscene/browser/simple/build_inner_html(client/C)
|
|
return cached_html
|
|
|
|
/datum/cutscene/browser/simple/setup(client/C)
|
|
if(!isnull(cached_icon))
|
|
C << browse_rsc(cached_icon, use_fname)
|
|
return ..()
|
|
|
|
/**
|
|
* renders on game map
|
|
*/
|
|
/datum/cutscene/native
|
|
/// screen objects to send over. deleted on Destroy().
|
|
var/list/atom/movable/screens
|
|
|
|
/datum/cutscene/native/Destroy()
|
|
. = ..()
|
|
QDEL_NULL_LIST(screens)
|
|
|
|
/datum/cutscene/native/setup(client/C)
|
|
. = ..()
|
|
if(!isnull(screens))
|
|
C.screen += screens
|
|
C.screen += GLOB.cutscene_backdrop
|
|
|
|
/datum/cutscene/native/cleanup(client/C)
|
|
. = ..()
|
|
if(!isnull(screens))
|
|
C.screen -= screens
|
|
C.screen -= GLOB.cutscene_backdrop
|
|
|
|
/**
|
|
* simple cutscene that loads a single icon
|
|
*/
|
|
/datum/cutscene/native/simple
|
|
/// icon path
|
|
var/icon_path
|
|
/// icon width
|
|
var/icon_width = WORLD_ICON_SIZE * 15
|
|
/// icon height
|
|
var/icon_height = WORLD_ICON_SIZE * 15
|
|
/// screen object
|
|
var/atom/movable/screen/cutscene_simple/object
|
|
|
|
/datum/cutscene/native/simple/Destroy()
|
|
. = ..()
|
|
QDEL_NULL(object)
|
|
|
|
/datum/cutscene/native/simple/init()
|
|
object = new(null, icon_path, icon_width, icon_height)
|
|
|
|
/datum/cutscene/native/simple/setup(client/C)
|
|
. = ..()
|
|
C.screen += object
|
|
|
|
/datum/cutscene/native/simple/cleanup(client/C)
|
|
. = ..()
|
|
C.screen -= object
|
|
|
|
GLOBAL_DATUM_INIT(cutscene_backdrop, /atom/movable/screen/cutscene_backdrop, new)
|
|
|
|
/atom/movable/screen/cutscene_backdrop
|
|
appearance_flags = NO_CLIENT_COLOR | TILE_BOUND | PIXEL_SCALE
|
|
plane = CUTSCENE_PLANE
|
|
layer = CUTSCENE_LAYER_BACKDROP
|
|
mouse_opacity = MOUSE_OPACITY_ICON
|
|
screen_loc = "SOUTHWEST to NORTHEAST"
|
|
icon = 'icons/screen/fullscreen/fullscreen_tiled.dmi'
|
|
icon_state = "white"
|
|
color = "#000000"
|
|
|
|
INITIALIZE_IMMEDIATE(/atom/movable/screen/cutscene_simple)
|
|
/atom/movable/screen/cutscene_simple
|
|
appearance_flags = NO_CLIENT_COLOR | TILE_BOUND | PIXEL_SCALE
|
|
plane = CUTSCENE_PLANE
|
|
layer = CUTSCENE_LAYER_MAIN
|
|
|
|
/atom/movable/screen/cutscene_simple/Initialize(mapload, path, width, height)
|
|
. = ..()
|
|
if(!isnull(path))
|
|
icon = isicon(path)? path : icon(path)
|
|
screen_loc = "CENTER:-[width / 2 - WORLD_ICON_SIZE / 2],CENTER:-[height / 2 - WORLD_ICON_SIZE / 2]"
|
|
|