Skip to content

Commit

Permalink
Cinematics widescreen support (#434)
Browse files Browse the repository at this point in the history
<!-- Пишите **НИЖЕ** заголовков и **ВЫШЕ** комментариев, иначе что то
может пойти не так. -->
<!-- Вы можете прочитать Contributing.MD, если хотите узнать больше. -->

## Что этот PR делает

<!-- Вкратце опишите изменения, которые вносите. -->
<!-- Опишите **все** изменения, так как противное может сказаться на
рассмотрении этого PR'а! -->
<!-- Если вы исправляете Issue, добавьте "Fixes #1234" (где 1234 - номер
Issue) где-нибудь в описании PR'а. Это автоматически закроет Issue после
принятия PR'а. -->

Обновляет систему цинематиков под ТГ

## Почему это хорошо для игры

<!-- Опишите, почему, по вашему, следует добавить эти изменения в игру.
-->

Вайдскрин суппорт, лучше работает

## Тестирование
<!-- Как вы тестировали свой PR, если делали это вовсе? -->

* Вызвал прок на цинематик, раунд идет дальше pepelaugh
* Взорвал бимбу, раунд спать идет
* Взорвал малфа, раунд спать идет

## Changelog

:cl:
add: Cinematics widescreen support
/:cl:

<!-- Оба :cl:'а должны быть на месте, что-бы чейнджлог работал! Вы
можете написать свой ник справа от первого :cl:, если хотите. Иначе
будет использован ваш ник на ГитХабе. -->
<!-- Вы можете использовать несколько записей с одинаковым префиксом
(Они используются только для иконки в игре) и удалить ненужные. Помните,
что чейнджлог должен быть понятен обычным игроком. -->
<!-- Если чейнджлог не влияет на игроков(например, это рефактор), вы
можете исключить всю секцию. -->

---------

Co-authored-by: Furior <[email protected]>
  • Loading branch information
larentoun and Furrior committed Oct 22, 2023
1 parent 8be8928 commit 0352dda
Show file tree
Hide file tree
Showing 17 changed files with 412 additions and 0 deletions.
3 changes: 3 additions & 0 deletions modular_ss220/_defines220/_defines220.dme
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
#include "code/signals_mob/signals_mob_silicon.dm"
#include "code/signals_mob/signals_mob_simple.dm"
#include "code/signals_keybindings.dm"
#include "code/cult_defines_ss220.dm"
#include "code/hud_ss220.dm"
#include "code/layers_ss220.dm"
4 changes: 4 additions & 0 deletions modular_ss220/_defines220/code/cult_defines_ss220.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Used in determining which cinematic to play when cult ends
#define CULT_VICTORY_MASS_CONVERSION 2
#define CULT_FAILURE_NARSIE_KILLED 1
#define CULT_VICTORY_NUKE 0
2 changes: 2 additions & 0 deletions modular_ss220/_defines220/code/hud_ss220.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// Used for HUD objects
#define APPEARANCE_UI (RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|PIXEL_SCALE)
2 changes: 2 additions & 0 deletions modular_ss220/_defines220/code/layers_ss220.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// Cinematics are "below" the splash screen
#define CINEMATIC_LAYER -1
1 change: 1 addition & 0 deletions modular_ss220/_misc/_misc.dme
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "_misc.dm"

#include "code/global_procs.dm"
#include "code/ss220_general_config.dm"
#include "code/icons.dm"
2 changes: 2 additions & 0 deletions modular_ss220/_misc/code/global_procs.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/proc/cmp_typepaths_asc(A, B)
return sorttext("[B]","[A]")
4 changes: 4 additions & 0 deletions modular_ss220/cinematics/_cinematics.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/datum/modpack/cinematics
name = "Обновление системы Cinematics"
desc = "Обновление системы Cinematics, позволяя им работать в широкоформатном режиме"
author = "larentoun"
9 changes: 9 additions & 0 deletions modular_ss220/cinematics/_cinematics.dme
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include "_cinematics.dm"

#include "code/_cinematics.dm"
#include "code/cinematics_client_proc.dm"
#include "code/cinematics_screen.dm"
#include "code/cinematics_ticker.dm"
#include "code/cinematics/malf_doomsday.dm"
#include "code/cinematics/narsie_summon.dm"
#include "code/cinematics/nuke_cinematics.dm"
178 changes: 178 additions & 0 deletions modular_ss220/cinematics/code/_cinematics.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/**
* Plays a cinematic, duh. Can be to a select few people, or everyone.
*
* cinematic_type - datum typepath to what cinematic you wish to play.
* watchers - a list of all mobs you are playing the cinematic to. If world, the cinematical will play globally to all players.
* special_callback - optional callback to be invoked mid-cinematic.
*/
/proc/play_cinematic(datum/cinematic/cinematic_type, watchers, datum/callback/special_callback)
if(!ispath(cinematic_type, /datum/cinematic))
CRASH("play_cinematic called with a non-cinematic type. (Got: [cinematic_type])")
var/datum/cinematic/playing = new cinematic_type(watchers, special_callback)

if(watchers == world)
watchers = GLOB.mob_list

playing.start_cinematic(watchers)

return playing

/// The cinematic screen showed to everyone
/obj/screen/cinematic
icon = 'icons/effects/station_explosion.dmi'
icon_state = "station_intact"
plane = SPLASHSCREEN_PLANE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
screen_loc = "BOTTOM,LEFT+50%"
appearance_flags = APPEARANCE_UI | TILE_BOUND

/// Cinematic datum. Used to show an animation to everyone.
/datum/cinematic
/// A list of all clients watching the cinematic
var/list/client/watching = list()
/// A list of all mobs who have notransform set while watching the cinematic
var/list/datum/locked = list()
/// Whether the cinematic is a global cinematic or not
var/is_global = FALSE
/// Refernce to the cinematic screen shown to everyohne
var/obj/screen/cinematic/screen
/// Callbacks passed that occur during the animation
var/datum/callback/special_callback
/// How long for the final screen remains shown
var/cleanup_time = 30 SECONDS
/// Whether the cinematic turns off ooc when played globally.
var/stop_ooc = TRUE

/datum/cinematic/New(watcher, datum/callback/special_callback)
screen = new(src)
if(watcher == world)
is_global = TRUE

src.special_callback = special_callback

/datum/cinematic/Destroy()
QDEL_NULL(screen)
QDEL_NULL(special_callback)
watching.Cut()
locked.Cut()
return ..()

/// Actually goes through the process of showing the cinematic to the list of watchers.
/datum/cinematic/proc/start_cinematic(list/watchers)
if(SEND_GLOBAL_SIGNAL(COMSIG_GLOB_PLAY_CINEMATIC, src) & COMPONENT_GLOB_BLOCK_CINEMATIC)
return

// Register a signal to handle what happens when a different cinematic tries to play over us.
RegisterSignal(SSdcs, COMSIG_GLOB_PLAY_CINEMATIC, PROC_REF(handle_replacement_cinematics))

// Pause OOC
var/ooc_toggled = FALSE
if(is_global && stop_ooc && GLOB.ooc_enabled)
ooc_toggled = TRUE
toggle_ooc()

// Place the /obj/screen/cinematic into everyone's screens, and prevent movement.
for(var/mob/watching_mob in watchers)
show_to(watching_mob, watching_mob.client)
RegisterSignal(watching_mob, COMSIG_MOB_CLIENT_LOGIN, PROC_REF(show_to))
// Close watcher ui's, too, so they can watch it.
SStgui.close_user_uis(watching_mob)

// Actually plays the animation. This will sleep, likely.
play_cinematic()

// Cleans up after it's done playing.
addtimer(CALLBACK(src, PROC_REF(clean_up_cinematic), ooc_toggled), cleanup_time)

/// Cleans up the cinematic after a set timer of it sticking on the end screen.
/datum/cinematic/proc/clean_up_cinematic(was_ooc_toggled = FALSE)
if(was_ooc_toggled)
toggle_ooc(TRUE)

stop_cinematic()

/// Whenever another cinematic starts to play over us, we have the chacne to block it.
/datum/cinematic/proc/handle_replacement_cinematics(datum/source, datum/cinematic/other)
SIGNAL_HANDLER

// Stop our's and allow others to play if we're local and it's global
if(!is_global && other.is_global)
stop_cinematic()
return NONE

return COMPONENT_GLOB_BLOCK_CINEMATIC

/// Whenever a mob watching the cinematic logs in, show them the ongoing cinematic
/datum/cinematic/proc/show_to(mob/watching_mob, client/watching_client)
SIGNAL_HANDLER

// We could technically rip people out of notransform who shouldn't be,
// so we'll only lock down all viewing mobs who don't have it already set.
// This does potentially mean some mobs could lose their notrasnform and
// not be locked down by cinematics, but that should be very unlikely.
if(!watching_mob.notransform)
lock_mob(watching_mob)

// Only show the actual cinematic to cliented mobs.
if(!watching_client || (watching_client in watching))
return

watching += watching_client
watching_mob.overlay_fullscreen("cinematic", /obj/screen/fullscreen/cinematic_backdrop)
watching_client.screen += screen
RegisterSignal(watching_client, COMSIG_PARENT_QDELETING, PROC_REF(remove_watcher))

/// Simple helper for playing sounds from the cinematic.
/datum/cinematic/proc/play_cinematic_sound(sound_to_play)
if(is_global)
SEND_SOUND(world, sound_to_play)
else
for(var/client/watching_client in watching)
SEND_SOUND(watching_client, sound_to_play)

/// Invoke any special callbacks for actual effects synchronized with animation.
/// (Such as a real nuke explosion happening midway)
/datum/cinematic/proc/invoke_special_callback()
special_callback?.Invoke()

/// The actual cinematic occurs here.
/datum/cinematic/proc/play_cinematic()
return

/// Stops the cinematic and removes it from all the viewers.
/datum/cinematic/proc/stop_cinematic()
for(var/client/viewing_client in watching)
remove_watcher(viewing_client)

for(var/datum/locked_ref in locked)
unlock_mob(locked_ref)

qdel(src)

/// Locks a mob, preventing them from moving, being hurt, or acting
/datum/cinematic/proc/lock_mob(mob/to_lock)
locked += to_lock
to_lock.notransform = TRUE

/// Unlocks a previously locked ref
/datum/cinematic/proc/unlock_mob(datum/mob_ref)
var/mob/locked_mob = mob_ref
if(isnull(locked_mob))
return
locked_mob.notransform = FALSE
UnregisterSignal(locked_mob, COMSIG_MOB_CLIENT_LOGIN)

/// Removes the passed client from our watching list.
/datum/cinematic/proc/remove_watcher(client/no_longer_watching)
SIGNAL_HANDLER

if(!(no_longer_watching in watching))
CRASH("cinematic remove_watcher was passed a client which wasn't watching.")

UnregisterSignal(no_longer_watching, COMSIG_PARENT_QDELETING)
// We'll clear the cinematic if they have a mob which has one,
// but we won't remove notransform. Wait for the cinematic end to do that.
no_longer_watching.mob?.clear_fullscreen("cinematic")
no_longer_watching.screen -= screen

watching -= no_longer_watching
10 changes: 10 additions & 0 deletions modular_ss220/cinematics/code/cinematics/malf_doomsday.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/// A malfunctioning AI has activated the doomsday device and wiped the station!
/datum/cinematic/malf

/datum/cinematic/malf/play_cinematic()
flick("intro_malf", screen)
stoplag(7.6 SECONDS)
flick("station_explode_fade_red", screen)
play_cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
special_callback?.Invoke()
screen.icon_state = "summary_malf"
29 changes: 29 additions & 0 deletions modular_ss220/cinematics/code/cinematics/narsie_summon.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/// A blood cult summoned Nar'sie, and most of the station was harvested or converted!
/datum/cinematic/cult_arm // Colloquially known as "the arm"

/datum/cinematic/cult_arm/play_cinematic()
screen.icon_state = null
flick("intro_cult", screen)
stoplag(2.5 SECONDS)
play_cinematic_sound(sound('sound/misc/enter_blood.ogg'))
stoplag(2.8 SECONDS)
play_cinematic_sound(sound('sound/machines/terminal_off.ogg'))
stoplag(2 SECONDS)
flick("station_corrupted", screen)
play_cinematic_sound(sound('sound/effects/ghost.ogg'))
stoplag(7 SECONDS)
special_callback?.Invoke()

/// A blood cult summoned Nar'sie, but some badass (or admin) managed to destroy Nar'sie themselves.
/datum/cinematic/cult_fail

/datum/cinematic/cult_fail/play_cinematic()
screen.icon_state = "station_intact"
stoplag(2 SECONDS)
play_cinematic_sound(sound('sound/creatures/narsie_rises.ogg'))
stoplag(6 SECONDS)
play_cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
stoplag(1 SECONDS)
play_cinematic_sound(sound('sound/misc/demon_dies.ogg'))
stoplag(3 SECONDS)
special_callback?.Invoke()
100 changes: 100 additions & 0 deletions modular_ss220/cinematics/code/cinematics/nuke_cinematics.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/// Simple, base cinematic for all animations based around a nuke detonating.
/datum/cinematic/nuke
/// If set, this is the summary screen that pops up after the nuke is done.
var/after_nuke_summary_state

/datum/cinematic/nuke/play_cinematic()
flick("intro_nuke", screen)
stoplag(3.5 SECONDS)
play_nuke_effect()
if(special_callback)
special_callback.Invoke()
if(after_nuke_summary_state)
screen.icon_state = after_nuke_summary_state

/// Specific effects for each type of cinematics goes here.
/datum/cinematic/nuke/proc/play_nuke_effect()
return

/// The syndicate nuclear bomb was activated, and destroyed the station!
/datum/cinematic/nuke/ops_victory
after_nuke_summary_state = "summary_nukewin"

/datum/cinematic/nuke/ops_victory/play_nuke_effect()
flick("station_explode_fade_red", screen)
play_cinematic_sound(sound('sound/effects/explosion_distant.ogg'))

/// The syndicate nuclear bomb was activated, but just barely missed the station!
/datum/cinematic/nuke/ops_miss
after_nuke_summary_state = "summary_nukefail"

/datum/cinematic/nuke/ops_miss/play_nuke_effect()
flick("station_intact_fade_red", screen)
play_cinematic_sound(sound('sound/effects/explosion_distant.ogg'))

/// The self destruct, or another station-destroying entity like a blob, destroyed the station!
/datum/cinematic/nuke/self_destruct
after_nuke_summary_state = "summary_selfdes"

/datum/cinematic/nuke/self_destruct/play_nuke_effect()
flick("station_explode_fade_red", screen)
play_cinematic_sound(sound('sound/effects/explosion_distant.ogg'))

/// The self destruct was activated, yet somehow avoided destroying the station!
/datum/cinematic/nuke/self_destruct_miss
after_nuke_summary_state = "station_intact"

/datum/cinematic/nuke/self_destruct_miss/play_nuke_effect()
play_cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
special_callback?.Invoke()

/// The syndicate nuclear bomb was activated, and the nuclear operatives failed to extract on their shuttle before it detonated on the station!
/datum/cinematic/nuke/mutual_destruction
after_nuke_summary_state = "summary_totala"

/datum/cinematic/nuke/mutual_destruction/play_nuke_effect()
flick("station_explode_fade_red", screen)
play_cinematic_sound(sound('sound/effects/explosion_distant.ogg'))

/// A blood cult summoned Nar'sie, but central command deployed a nuclear package to stop them.
/datum/cinematic/nuke/cult
after_nuke_summary_state = "summary_cult"

/datum/cinematic/nuke/cult/play_nuke_effect()
flick("station_explode_fade_red", screen)
play_cinematic_sound(sound('sound/effects/explosion_distant.ogg'))

/// A fake version of the nuclear detonation, where it winds up, but doesn't explode.
/datum/cinematic/nuke/fake
cleanup_time = 10 SECONDS

/datum/cinematic/nuke/fake/play_nuke_effect()
play_cinematic_sound(sound('sound/items/bikehorn.ogg'))
flick("summary_selfdes", screen) //???

/// The clown operative nuclear bomb was activated and clowned the station!
/datum/cinematic/nuke/clown
cleanup_time = 10 SECONDS

/datum/cinematic/nuke/clown/play_nuke_effect()
play_cinematic_sound(sound('sound/items/airhorn.ogg'))
flick("summary_selfdes", screen) //???

/// A fake version of the nuclear detonation, where it winds up, but doesn't explode as the nuke core within was missing.
/datum/cinematic/nuke/no_core
cleanup_time = 10 SECONDS

/datum/cinematic/nuke/no_core/play_nuke_effect()
flick("station_intact", screen)
play_cinematic_sound(sound('sound/ambience/signal.ogg'))
stoplag(10 SECONDS)

/// The syndicate nuclear bomb was activated, but just missed the station by a whole z-level!
/datum/cinematic/nuke/far_explosion
cleanup_time = 0 SECONDS

/datum/cinematic/nuke/far_explosion/play_cinematic()
// This one has no intro sequence.
// It's actually just a global sound, which makes you wonder why it's a cinematic.
play_cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
special_callback?.Invoke()
16 changes: 16 additions & 0 deletions modular_ss220/cinematics/code/cinematics_client_proc.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/client/proc/cinematic_new()
set name = "Cinematic (NEW)"
set category = "Event"
set desc = "Shows a cinematic." // Intended for testing but I thought it might be nice for events on the rare occasion Feel free to comment it out if it's not wanted.
set hidden = TRUE

if(!SSticker)
return
if(!check_rights(R_MAINTAINER))
return

var/datum/cinematic/choice = input(usr, "Choose a cinematic to play to everyone in the server.", "Choose Cinematic") in sortTim(subtypesof(/datum/cinematic), GLOBAL_PROC_REF(cmp_typepaths_asc))
if(!choice || !ispath(choice, /datum/cinematic))
return

play_cinematic(choice, world)
8 changes: 8 additions & 0 deletions modular_ss220/cinematics/code/cinematics_screen.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/obj/screen/fullscreen/cinematic_backdrop
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "flash"
plane = SPLASHSCREEN_PLANE
layer = CINEMATIC_LAYER
color = "#000000"
show_when_dead = TRUE
Loading

0 comments on commit 0352dda

Please sign in to comment.