diff --git a/code/__DEFINES/cinematics.dm b/code/__DEFINES/cinematics.dm new file mode 100644 index 0000000000..4bfc8dd3c4 --- /dev/null +++ b/code/__DEFINES/cinematics.dm @@ -0,0 +1,11 @@ +#define CINEMATIC_DEFAULT 1 +#define CINEMATIC_SELFDESTRUCT 2 +#define CINEMATIC_SELFDESTRUCT_MISS 3 +#define CINEMATIC_NUKE_WIN 4 +#define CINEMATIC_NUKE_MISS 5 +#define CINEMATIC_ANNIHILATION 6 +#define CINEMATIC_MALF 7 +#define CINEMATIC_CULT 8 +#define CINEMATIC_NUKE_FAKE 9 +#define CINEMATIC_NUKE_NO_CORE 10 +#define CINEMATIC_NUKE_FAR 11 \ No newline at end of file diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 220c0e355a..e7333966f9 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -51,14 +51,14 @@ SUBSYSTEM_DEF(ticker) var/queue_delay = 0 var/list/queued_players = list() //used for join queues when the server exceeds the hard population cap - var/obj/screen/cinematic = null //used for station explosion cinematic - var/maprotatechecked = 0 var/news_report var/late_join_disabled + var/roundend_check_paused = FALSE + var/round_start_time = 0 var/list/round_start_events var/mode_result = "undefined" @@ -137,7 +137,7 @@ SUBSYSTEM_DEF(ticker) scripture_states = scripture_unlock_alert(scripture_states) SSshuttle.autoEnd() - if(!mode.explosion_in_progress && mode.check_finished(force_ending) || force_ending) + if(!roundend_check_paused && mode.check_finished(force_ending) || force_ending) current_state = GAME_STATE_FINISHED toggle_ooc(TRUE) // Turn it on toggle_dooc(TRUE) @@ -274,6 +274,7 @@ SUBSYSTEM_DEF(ticker) if(epi) explosion(epi, 0, 256, 512, 0, TRUE, TRUE, 0, TRUE) +<<<<<<< HEAD //Plus it provides an easy way to make cinematics for other events. Just use this as a template /datum/controller/subsystem/ticker/proc/station_explosion_cinematic(station_missed=0, override = null, atom/bomb = null) if( cinematic ) @@ -411,6 +412,8 @@ SUBSYSTEM_DEF(ticker) if(actually_blew_up && !isnull(killz) && M.stat != DEAD && M.z == killz) M.gib() +======= +>>>>>>> 1304e83... Refactors cinematics. (#30888) /datum/controller/subsystem/ticker/proc/create_characters() for(var/mob/dead/new_player/player in GLOB.player_list) if(player.ready == PLAYER_READY_TO_PLAY && player.mind) @@ -711,13 +714,11 @@ SUBSYSTEM_DEF(ticker) queue_delay = SSticker.queue_delay queued_players = SSticker.queued_players - cinematic = SSticker.cinematic maprotatechecked = SSticker.maprotatechecked round_start_time = SSticker.round_start_time queue_delay = SSticker.queue_delay queued_players = SSticker.queued_players - cinematic = SSticker.cinematic maprotatechecked = SSticker.maprotatechecked modevoted = SSticker.modevoted diff --git a/code/datums/cinematic.dm b/code/datums/cinematic.dm new file mode 100644 index 0000000000..3f72ff995b --- /dev/null +++ b/code/datums/cinematic.dm @@ -0,0 +1,223 @@ +GLOBAL_LIST_EMPTY(cinematics) + +// Use to play cinematics. +// Watcher can be world,mob, or a list of mobs +// Blocks until sequence is done. +/proc/Cinematic(id,watcher,datum/callback/special_callback) + var/datum/cinematic/playing + for(var/V in subtypesof(/datum/cinematic)) + var/datum/cinematic/C = V + if(initial(C.id) == id) + playing = new V() + break + if(!playing) + CRASH("Cinematic type not found") + if(special_callback) + playing.special_callback = special_callback + if(watcher == world) + playing.is_global = TRUE + watcher = GLOB.mob_list + playing.play(watcher) + +/obj/screen/cinematic + icon = 'icons/effects/station_explosion.dmi' + icon_state = "station_intact" + layer = 21 + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + screen_loc = "1,1" + +/datum/cinematic + var/id = CINEMATIC_DEFAULT + var/list/watching = list() //List of clients watching this + var/list/locked = list() //Who had notransform set during the cinematic + var/is_global = FALSE //Global cinematics will override mob-specific ones + var/obj/screen/cinematic/screen + var/datum/callback/special_callback //For special effects synced with animation (explosions after the countdown etc) + var/cleanup_time = 300 //How long for the final screen to remain + +/datum/cinematic/New() + GLOB.cinematics += src + screen = new(src) + +/datum/cinematic/Destroy() + GLOB.cinematics -= src + QDEL_NULL(screen) + for(var/mob/M in locked) + M.notransform = FALSE + return ..() + +/datum/cinematic/proc/play(watchers) + //Check if you can actually play it (stop mob cinematics for global ones) and create screen objects + for(var/A in GLOB.cinematics) + var/datum/cinematic/C = A + if(C == src) + continue + if(C.is_global || !is_global) + return //Can't play two global or local cinematics at the same time + + //Close all open windows if global + if(is_global) + for (var/datum/html_interface/hi in GLOB.html_interfaces) + hi.closeAll() + SStgui.close_all_uis() + + + for(var/mob/M in GLOB.mob_list) + if(M in watchers) + M.notransform = TRUE //Should this be done for non-global cinematics or even at all ? + locked += M + //Close watcher ui's + SStgui.close_user_uis(M) + if(M.client) + watching += M.client + M.client.screen += screen + else + if(is_global) + M.notransform = TRUE + locked += M + + //Actually play it + content() + //Cleanup + sleep(cleanup_time) + qdel(src) + +//Sound helper +/datum/cinematic/proc/cinematic_sound(s) + if(is_global) + SEND_SOUND(world,s) + else + for(var/C in watching) + SEND_SOUND(C,s) + +//Fire up special callback for actual effects synchronized with animation (eg real nuke explosion happens midway) +/datum/cinematic/proc/special() + if(special_callback) + special_callback.Invoke() + +//Actual cinematic goes in here +/datum/cinematic/proc/content() + sleep(50) + +/datum/cinematic/nuke_win + id = CINEMATIC_NUKE_WIN + +/datum/cinematic/nuke_win/content() + flick("intro_nuke",screen) + sleep(35) + flick("station_explode_fade_red",screen) + cinematic_sound(sound('sound/effects/explosion_distant.ogg')) + special() + screen.icon_state = "summary_nukewin" + +/datum/cinematic/nuke_miss + id = CINEMATIC_NUKE_MISS + +/datum/cinematic/nuke_miss/content() + flick("intro_nuke",screen) + sleep(35) + cinematic_sound(sound('sound/effects/explosion_distant.ogg')) + special() + flick("station_intact_fade_red",screen) + screen.icon_state = "summary_nukefail" + +//Also used for blob +/datum/cinematic/nuke_selfdestruct + id = CINEMATIC_SELFDESTRUCT + +/datum/cinematic/nuke_selfdestruct/content() + flick("intro_nuke",screen) + sleep(35) + flick("station_explode_fade_red", screen) + cinematic_sound(sound('sound/effects/explosion_distant.ogg')) + special() + screen.icon_state = "summary_selfdes" + +/datum/cinematic/nuke_selfdestruct_miss + id = CINEMATIC_SELFDESTRUCT_MISS + +/datum/cinematic/nuke_selfdestruct_miss/content() + flick("intro_nuke",screen) + sleep(35) + cinematic_sound(sound('sound/effects/explosion_distant.ogg')) + special() + screen.icon_state = "station_intact" + +/datum/cinematic/malf + id = CINEMATIC_MALF + +/datum/cinematic/malf/content() + flick("intro_malf",screen) + sleep(76) + flick("station_explode_fade_red",screen) + cinematic_sound(sound('sound/effects/explosion_distant.ogg')) + special() + screen.icon_state = "summary_malf" + +/datum/cinematic/cult + id = CINEMATIC_CULT + +/datum/cinematic/cult/content() + screen.icon_state = null + flick("intro_cult",screen) + sleep(25) + cinematic_sound(sound('sound/magic/enter_blood.ogg')) + sleep(28) + cinematic_sound(sound('sound/machines/terminal_off.ogg')) + sleep(20) + flick("station_corrupted",screen) + cinematic_sound(sound('sound/effects/ghost.ogg')) + sleep(70) + special() + +/datum/cinematic/nuke_annihilation + id = CINEMATIC_ANNIHILATION + +/datum/cinematic/nuke_annihilation/content() + flick("intro_nuke",screen) + sleep(35) + flick("station_explode_fade_red",screen) + cinematic_sound(sound('sound/effects/explosion_distant.ogg')) + special() + screen.icon_state = "summary_totala" + +/datum/cinematic/fake + id = CINEMATIC_NUKE_FAKE + cleanup_time = 100 + +/datum/cinematic/fake/content() + flick("intro_nuke",screen) + sleep(35) + cinematic_sound(sound('sound/items/bikehorn.ogg')) + flick("summary_selfdes",screen) //??? + special() + +/datum/cinematic/no_core + id = CINEMATIC_NUKE_NO_CORE + cleanup_time = 100 + +/datum/cinematic/no_core/content() + flick("intro_nuke",screen) + sleep(35) + flick("station_intact",screen) + cinematic_sound(sound('sound/ambience/signal.ogg')) + sleep(100) + +/datum/cinematic/nuke_far + id = CINEMATIC_NUKE_FAR + cleanup_time = 0 + +/datum/cinematic/nuke_far/content() + cinematic_sound(sound('sound/effects/explosion_distant.ogg')) + special() + +/* Intended usage. +Nuke.Explosion() + -> Cinematic(NUKE_BOOM,world) + -> ActualExplosion() + -> Mode.OnExplosion() + + +Narsie() + -> Cinematic(CULT,world) +*/ \ No newline at end of file diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index f65a64fb08..18a19fb153 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -19,7 +19,6 @@ var/probability = 0 var/false_report_weight = 0 //How often will this show up incorrectly in a centcom report? var/station_was_nuked = 0 //see nuclearbomb.dm and malfunction.dm - var/explosion_in_progress = 0 //sit back and relax var/round_ends_with_antag_death = 0 //flags the "one verse the station" antags as such var/list/datum/mind/modePlayer = new var/list/datum/mind/antag_candidates = list() // List of possible starting antags goes here @@ -562,3 +561,8 @@ /datum/game_mode/proc/generate_report() //Generates a small text blurb for the gamemode in centcom report return "Gamemode report for [name] not set. Contact a coder." + +//By default nuke just ends the round +/datum/game_mode/proc/OnNukeExplosion(off_station) + if(off_station < 2) + station_was_nuked = TRUE //Will end the round on next check. \ No newline at end of file diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index d48628ddd1..4c21f9688b 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -161,6 +161,12 @@ synd_mob.equipOutfit(/datum/outfit/syndicate/no_crystals) return 1 +/datum/game_mode/nuclear/OnNukeExplosion(off_station) + ..() + nukes_left-- + var/obj/docking_port/mobile/Shuttle = SSshuttle.getShuttle("syndicate") + syndies_didnt_escape = (Shuttle && (Shuttle.z == ZLEVEL_CENTCOM || Shuttle.z == ZLEVEL_TRANSIT)) ? 0 : 1 + nuke_off_station = off_station /datum/game_mode/nuclear/check_win() if (nukes_left == 0) diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm index 7642801a6a..8870399f24 100644 --- a/code/game/gamemodes/nuclear/nuclearbomb.dm +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm @@ -81,6 +81,20 @@ /obj/machinery/nuclearbomb/syndicate //ui_style = "syndicate" // actually the nuke op bomb is a stole nt bomb +/obj/machinery/nuclearbomb/syndicate/get_cinematic_type(off_station) + var/datum/game_mode/nuclear/NM = SSticker.mode + switch(off_station) + if(0) + if(istype(NM) && NM.syndies_didnt_escape) + return CINEMATIC_ANNIHILATION + else + return CINEMATIC_NUKE_WIN + if(1) + return CINEMATIC_NUKE_MISS + if(2) + return CINEMATIC_NUKE_FAR + return CINEMATIC_NUKE_FAR + /obj/machinery/nuclearbomb/syndicate/Initialize() . = ..() var/obj/machinery/nuclearbomb/existing = locate("syndienuke") in GLOB.nuke_list @@ -422,12 +436,12 @@ update_icon() sound_to_playing_players('sound/machines/alarm.ogg') if(SSticker && SSticker.mode) - SSticker.mode.explosion_in_progress = 1 + SSticker.roundend_check_paused = TRUE sleep(100) if(!core) - SSticker.station_explosion_cinematic(3,"no_core",src) - SSticker.mode.explosion_in_progress = 0 + Cinematic(CINEMATIC_NUKE_NO_CORE,world) + SSticker.roundend_check_paused = FALSE return GLOB.enter_allowed = 0 @@ -437,28 +451,37 @@ var/area/A = get_area(bomb_location) if(bomb_location && (bomb_location.z in GLOB.station_z_levels)) if(istype(A, /area/space)) - off_station = NUKE_MISS_STATION + off_station = NUKE_NEAR_MISS if((bomb_location.x < (128-NUKERANGE)) || (bomb_location.x > (128+NUKERANGE)) || (bomb_location.y < (128-NUKERANGE)) || (bomb_location.y > (128+NUKERANGE))) - off_station = NUKE_MISS_STATION + off_station = NUKE_NEAR_MISS else if((istype(A, /area/syndicate_mothership) || (istype(A, /area/shuttle/syndicate)) && bomb_location.z == ZLEVEL_CENTCOM)) off_station = NUKE_SYNDICATE_BASE else - off_station = NUKE_NEAR_MISS + off_station = NUKE_MISS_STATION - if(istype(SSticker.mode, /datum/game_mode/nuclear)) - var/obj/docking_port/mobile/Shuttle = SSshuttle.getShuttle("syndicate") - var/datum/game_mode/nuclear/NM = SSticker.mode - NM.syndies_didnt_escape = (Shuttle && (Shuttle.z == ZLEVEL_CENTCOM || Shuttle.z == ZLEVEL_TRANSIT)) ? 0 : 1 - NM.nuke_off_station = off_station + if(off_station < 2) + SSshuttle.registerHostileEnvironment(src) + SSshuttle.lockdown = TRUE - SSticker.station_explosion_cinematic(off_station,null,src) - if(SSticker.mode) - if(istype(SSticker.mode, /datum/game_mode/nuclear)) - var/datum/game_mode/nuclear/NM = SSticker.mode - NM.nukes_left -- - if(!SSticker.mode.check_finished())//If the mode does not deal with the nuke going off so just reboot because everyone is stuck as is - SSticker.Reboot("Station destroyed by Nuclear Device.", "nuke - unhandled ending") + //Cinematic + SSticker.mode.OnNukeExplosion(off_station) + var/bombz = z + Cinematic(get_cinematic_type(off_station),world,CALLBACK(SSticker,/datum/controller/subsystem/ticker/proc/station_explosion_detonation,src)) + INVOKE_ASYNC(GLOBAL_PROC,.proc/KillEveryoneOnZLevel,bombz) + SSticker.roundend_check_paused = FALSE +/obj/machinery/nuclearbomb/proc/get_cinematic_type(off_station) + if(off_station < 2) + return CINEMATIC_SELFDESTRUCT + else + return CINEMATIC_SELFDESTRUCT_MISS + +/proc/KillEveryoneOnZLevel(z) + if(!z) + return + for(var/mob/M in GLOB.mob_list) + if(M.stat != DEAD && M.z == z) + M.gib() /* This is here to make the tiles around the station mininuke change when it's armed. diff --git a/code/modules/admin/verbs/cinematic.dm b/code/modules/admin/verbs/cinematic.dm index 186eee2195..58b60277c0 100644 --- a/code/modules/admin/verbs/cinematic.dm +++ b/code/modules/admin/verbs/cinematic.dm @@ -1,3 +1,4 @@ +<<<<<<< HEAD /client/proc/cinematic(cinematic as anything in list("explosion",null)) set name = "cinematic" set category = "Fun" @@ -15,4 +16,17 @@ if(0) override = input(src,"mode = ?","Enter Parameter",null) as anything in list("blob","nuclear emergency","AI malfunction","no override") SSticker.station_explosion_cinematic(parameter,override) - return \ No newline at end of file + return +======= +/client/proc/cinematic() + set name = "cinematic" + set category = "Fun" + 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 = 1 + if(!SSticker) + return + + var/datum/cinematic/choice = input(src,"Cinematic","Choose",null) as anything in subtypesof(/datum/cinematic) + if(choice) + Cinematic(initial(choice.id),world,null) +>>>>>>> 1304e83... Refactors cinematics. (#30888) diff --git a/code/modules/events/wizard/fakeexplosion.dm b/code/modules/events/wizard/fakeexplosion.dm index 3dee4a1f49..a0852afa5e 100644 --- a/code/modules/events/wizard/fakeexplosion.dm +++ b/code/modules/events/wizard/fakeexplosion.dm @@ -7,4 +7,5 @@ /datum/round_event/wizard/fake_explosion/start() sound_to_playing_players('sound/machines/alarm.ogg') - addtimer(CALLBACK(SSticker, /datum/controller/subsystem/ticker/.proc/station_explosion_cinematic, 1, "fake"), 100) //:o) \ No newline at end of file + sleep(100) + Cinematic(CINEMATIC_NUKE_FAKE,world) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/cockroach.dm b/code/modules/mob/living/simple_animal/friendly/cockroach.dm index b49534808a..0218ce5726 100644 --- a/code/modules/mob/living/simple_animal/friendly/cockroach.dm +++ b/code/modules/mob/living/simple_animal/friendly/cockroach.dm @@ -27,7 +27,7 @@ del_on_death = 1 /mob/living/simple_animal/cockroach/death(gibbed) - if(SSticker.cinematic) //If the nuke is going off, then cockroaches are invincible. Keeps the nuke from killing them, cause cockroaches are immune to nukes. + if(SSticker.mode && SSticker.mode.station_was_nuked) //If the nuke is going off, then cockroaches are invincible. Keeps the nuke from killing them, cause cockroaches are immune to nukes. return ..() diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm index 381dcbaa75..b566d65f49 100644 --- a/code/modules/power/singularity/narsie.dm +++ b/code/modules/power/singularity/narsie.dm @@ -73,7 +73,6 @@ resolved = TRUE sound_to_playing_players('sound/machines/alarm.ogg') addtimer(CALLBACK(GLOBAL_PROC, .proc/cult_ending_helper), 120) - addtimer(CALLBACK(GLOBAL_PROC, .proc/ending_helper), 220) /obj/singularity/narsie/large/cult/Destroy() GLOB.cult_narsie = null @@ -83,7 +82,7 @@ SSticker.force_ending = 1 /proc/cult_ending_helper(var/no_explosion = 0) - SSticker.station_explosion_cinematic(no_explosion, "cult", null) + Cinematic(CINEMATIC_CULT,world,CALLBACK(GLOBAL_PROC,.ending_helper)) /obj/singularity/narsie/large/attack_ghost(mob/dead/observer/user as mob) diff --git a/tgstation.dme b/tgstation.dme index eb1bfd6c11..f1dbfb642b 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -28,7 +28,11 @@ #include "code\__DEFINES\atmospherics.dm" #include "code\__DEFINES\atom_hud.dm" #include "code\__DEFINES\callbacks.dm" +<<<<<<< HEAD #include "code\__DEFINES\citadel_defines.dm" +======= +#include "code\__DEFINES\cinematics.dm" +>>>>>>> 1304e83... Refactors cinematics. (#30888) #include "code\__DEFINES\clockcult.dm" #include "code\__DEFINES\combat.dm" #include "code\__DEFINES\components.dm" @@ -251,6 +255,7 @@ #include "code\datums\beam.dm" #include "code\datums\browser.dm" #include "code\datums\callback.dm" +#include "code\datums\cinematic.dm" #include "code\datums\datacore.dm" #include "code\datums\datum.dm" #include "code\datums\datumvars.dm"