Unit Test rework & Master/Ticker update (#17912)

* Unit Test rework & Master/Ticker update

* Fixes and working unit testing

* Fixes

* Test fixes and FA update

* Fixed runtimes

* Radio subsystem

* move that glob wherever later

* ident

* CIBUILDING compile option

* Fixed runtimes

* Some changes to the workflow

* CI Split

* More split

* Pathing

* Linters and Annotators

* ci dir fix

* Missing undef fixed

* Enable grep checks

* More test conversions

* More split

* Correct file

* Removes unneeded inputs

* oop

* More dependency changes

* More conversions

* Conversion fixes

* Fixes

* Some assert fixes

* Corrects start gate

* Converted some README.dms to README.mds

* Removes duplicate proc

* Removes unused defines

* Example configs

* fix dll access viol by double calling

* Post-rebase fixes

* Cleans up names global list

* Undef restart counter

* More code/game/ cleanup

* Statpanel update

* Skybox

* add

* Fix ticker

* Roundend fix

* Persistence dependency update

* Reordering

* Reordering

* Reordering

* Initstage fix

* .

* .

* Reorder

* Reorder

* Circle

* Mobs

* Air

* Test fix

* CI Script Fix

* Configs

* More ticker stuff

* This is now in 'reboot world'

* Restart world announcements

* no glob in PreInit

* to define

* Update

* Removed old include

* Make this file normal again

* moved

* test

* shared unit testing objects

* Updates batched_spritesheets and universal_icon

* .

* job data debug

* rm that

* init order

* show us

* .

* i wonder

* .

* .

* urg

* do we not have a job ID?

* .

* rm sleep for now

* updated rust-g linux binaries

* binaries update 2

* binaries update 3

* testing something

* change that

* test something

* .

* .

* .

* locavar

* test

* move that

* .

* debug

* don't run this test

* strack trace it

* cleaner

* .

* .

* cras again

* also comment this out

* return to official rust g

* Update robot_icons.dm

* monitor the generation

* .

---------

Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
Selis
2025-08-10 01:37:23 +02:00
committed by GitHub
co-authored by Kashargul
parent 5e54e17ebd
commit f4bf017921
382 changed files with 10193 additions and 4421 deletions
+181
View File
@@ -0,0 +1,181 @@
#define CINEMATIC_SOURCE "cinematic"
/**
* 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
/atom/movable/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 TRAIT_NO_TRANSFORM set while watching the cinematic
var/list/datum/weakref/locked = list()
/// Whether the cinematic is a global cinematic or not
var/is_global = FALSE
/// Refernce to the cinematic screen shown to everyohne
var/atom/movable/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)
special_callback = null
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
// NOT IMPLEMENTED
var/ooc_toggled = FALSE
//if(is_global && stop_ooc && GLOB.ooc_allowed)
// ooc_toggled = TRUE
// toggle_ooc(FALSE)
// Place the /atom/movable/screen/cinematic into everyone's screens, and prevent movement.
for(var/mob/watching_mob in watchers)
//show_to(watching_mob, GET_CLIENT(watching_mob)) // NOT IMPLEMENTED (GET_CLIENT)
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)
// NOT IMPLEMENTED
//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
if(!HAS_TRAIT_FROM(watching_mob, TRAIT_NO_TRANSFORM, CINEMATIC_SOURCE))
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 as anything 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 as anything in watching)
remove_watcher(viewing_client)
for(var/datum/weakref/locked_ref as anything 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 += WEAKREF(to_lock)
ADD_TRAIT(to_lock, TRAIT_NO_TRANSFORM, CINEMATIC_SOURCE)
/// Unlocks a previously locked weakref
/datum/cinematic/proc/unlock_mob(datum/weakref/mob_ref)
var/mob/locked_mob = mob_ref.resolve()
if(isnull(locked_mob))
return
REMOVE_TRAIT(locked_mob, TRAIT_NO_TRANSFORM, CINEMATIC_SOURCE)
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 TRAIT_NO_TRANSFORM. Wait for the cinematic end to do that.
no_longer_watching.mob?.clear_fullscreen("cinematic")
no_longer_watching.screen -= screen
watching -= no_longer_watching
#undef CINEMATIC_SOURCE
+10
View File
@@ -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/explosionfar.ogg'))
special_callback?.Invoke()
screen.icon_state = "summary_malf"
+160
View File
@@ -0,0 +1,160 @@
/// 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/explosionfar.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/explosionfar.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/explosionfar.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/explosionfar.ogg'))
special_callback?.Invoke()
/// 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/explosionfar.ogg'))
special_callback?.Invoke()
/*
/datum/controller/subsystem/ticker/proc/station_explosion_cinematic(var/station_missed=0, var/override = null)
if( cinematic ) return //already a cinematic in progress!
//initialise our cinematic screen object
cinematic = new(src)
cinematic.icon = 'icons/effects/station_explosion.dmi'
cinematic.icon_state = "station_intact"
cinematic.layer = 100
cinematic.plane = PLANE_PLAYER_HUD
cinematic.mouse_opacity = 0
cinematic.screen_loc = "1,0"
var/obj/structure/bed/temp_buckle = new(src)
//Incredibly hackish. It creates a bed within the gameticker (lol) to stop mobs running around
if(station_missed)
for(var/mob/living/M in living_mob_list)
M.buckled = temp_buckle //buckles the mob so it can't do anything
if(M.client)
M.client.screen += cinematic //show every client the cinematic
else //nuke kills everyone on z-level 1 to prevent "hurr-durr I survived"
for(var/mob/living/M in living_mob_list)
M.buckled = temp_buckle
if(M.client)
M.client.screen += cinematic
switch(M.z)
if(0) //inside a crate or something
var/turf/T = get_turf(M)
if(T && (T.z in using_map.station_levels)) //we don't use M.death(0) because it calls a for(/mob) loop and
M.health = 0
M.set_stat(DEAD)
if(1) //on a z-level 1 turf.
M.health = 0
M.set_stat(DEAD)
//Now animate the cinematic
switch(station_missed)
if(1) //nuke was nearby but (mostly) missed
if( mode && !override )
override = mode.name
switch( override )
if("mercenary") //Nuke wasn't on station when it blew up
flick("intro_nuke",cinematic)
sleep(35)
world << sound('sound/effects/explosionfar.ogg')
flick("station_intact_fade_red",cinematic)
cinematic.icon_state = "summary_nukefail"
else
flick("intro_nuke",cinematic)
sleep(35)
world << sound('sound/effects/explosionfar.ogg')
//flick("end",cinematic)
if(2) //nuke was nowhere nearby //TODO: a really distant explosion animation
sleep(50)
world << sound('sound/effects/explosionfar.ogg')
else //station was destroyed
if( mode && !override )
override = mode.name
switch( override )
if("mercenary") //Nuke Ops successfully bombed the station
flick("intro_nuke",cinematic)
sleep(35)
flick("station_explode_fade_red",cinematic)
world << sound('sound/effects/explosionfar.ogg')
cinematic.icon_state = "summary_nukewin"
if("AI malfunction") //Malf (screen,explosion,summary)
flick("intro_malf",cinematic)
sleep(76)
flick("station_explode_fade_red",cinematic)
world << sound('sound/effects/explosionfar.ogg')
cinematic.icon_state = "summary_malf"
if("blob") //Station nuked (nuke,explosion,summary)
flick("intro_nuke",cinematic)
sleep(35)
flick("station_explode_fade_red",cinematic)
world << sound('sound/effects/explosionfar.ogg')
cinematic.icon_state = "summary_selfdes"
else //Station nuked (nuke,explosion,summary)
flick("intro_nuke",cinematic)
sleep(35)
flick("station_explode_fade_red", cinematic)
world << sound('sound/effects/explosionfar.ogg')
cinematic.icon_state = "summary_selfdes"
for(var/mob/living/M in living_mob_list)
if(M.loc.z in using_map.station_levels)
M.death()//No mercy
//If its actually the end of the round, wait for it to end.
//Otherwise if its a verb it will continue on afterwards.
sleep(300)
if(cinematic) qdel(cinematic) //end the cinematic
if(temp_buckle) qdel(temp_buckle) //release everybody
return
*/
+2 -2
View File
@@ -489,8 +489,8 @@ GLOBAL_LIST_INIT(advance_cures, list(
return main_symptom.name
// Prefixes. These need a space right after.
var/list/prefixes = list("Spacer's ", "Space ", "Infectious ","Viral ", "The ", "[capitalize(prob(50) ? pick(first_names_male) : pick(first_names_female))]'s ", "[capitalize(pick(last_names))]'s ", "Acute ")
var/list/bodies = list(pick("[capitalize(prob(50) ? pick(first_names_male) : pick(first_names_female))]", "[pick(last_names)]"), "Space", "Disease", "Noun", "Cold", "Germ", "Virus")
var/list/prefixes = list("Spacer's ", "Space ", "Infectious ","Viral ", "The ", "[capitalize(prob(50) ? pick(GLOB.first_names_male) : pick(GLOB.first_names_female))]'s ", "[capitalize(pick(GLOB.last_names))]'s ", "Acute ")
var/list/bodies = list(pick("[capitalize(prob(50) ? pick(GLOB.first_names_male) : pick(GLOB.first_names_female))]", "[pick(GLOB.last_names)]"), "Space", "Disease", "Noun", "Cold", "Germ", "Virus")
// These might need some space before the word, depends on what you want to add.
var/list/suffixes = list("ism", "itis", "osis", "itosis", " #[rand(1,10000)]", "-[rand(1,100)]", "s", "y", " Virus", " Bug", " Infection", " Disease", " Complex", " Syndrome", " Sickness")
+1 -1
View File
@@ -57,7 +57,7 @@
to_chat(host, span_info("You are now a mouse. Try to avoid interaction with players, and do not give hints away that you are more than a simple rodent."))
/datum/tgui_module/ghost_spawn_menu/proc/become_drone(mob/observer/dead/user, fabricator)
if(ticker.current_state < GAME_STATE_PLAYING)
if(SSticker.current_state < GAME_STATE_PLAYING)
to_chat(user, span_danger("The game hasn't started yet!"))
return
+9 -8
View File
@@ -1,9 +1,10 @@
var/bluespace_item_types = newlist(/obj/item/storage/backpack/holding,
/obj/item/storage/bag/trash/holding,
/obj/item/storage/pouch/holding,
/obj/item/storage/belt/utility/holding,
/obj/item/storage/belt/medical/holding
)
GLOBAL_LIST_INIT(bluespace_item_types, list(
/obj/item/storage/backpack/holding,
/obj/item/storage/bag/trash/holding,
/obj/item/storage/pouch/holding,
/obj/item/storage/belt/utility/holding,
/obj/item/storage/belt/medical/holding
))
//wrapper
/proc/do_teleport(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, local=TRUE, bohsafe=FALSE)
@@ -167,7 +168,7 @@ var/bluespace_item_types = newlist(/obj/item/storage/backpack/holding,
var/list/bluespace_things = newlist()
for (var/item in bluespace_item_types)
for (var/item in GLOB.bluespace_item_types)
if (istype(teleatom, item))
precision = rand(1, 100)
bluespace_things |= teleatom.search_contents_for(item)
@@ -176,7 +177,7 @@ var/bluespace_item_types = newlist(/obj/item/storage/backpack/holding,
var/mob/living/L = teleatom
if(LAZYLEN(L.buckled_mobs))
for(var/mob/rider in L.buckled_mobs)
for (var/item in bluespace_item_types)
for (var/item in GLOB.bluespace_item_types)
bluespace_things |= rider.search_contents_for(item)
if(bluespace_things.len)
+4 -4
View File
@@ -123,7 +123,7 @@
popup.open()
/datum/mind/proc/edit_memory()
if(!ticker || !ticker.mode)
if(!SSticker || !SSticker.mode)
tgui_alert_async(usr, "Not before round-start!", "Alert")
return
@@ -239,7 +239,7 @@
var/objective_type = "[objective_type_capital][objective_type_text]"//Add them together into a text string.
var/list/possible_targets = list("Free objective")
for(var/datum/mind/possible_target in ticker.minds)
for(var/datum/mind/possible_target in SSticker.minds)
if ((possible_target != src) && ishuman(possible_target.current))
possible_targets += possible_target.current
@@ -509,8 +509,8 @@
else
mind = new /datum/mind(key)
mind.original = src
if(ticker)
ticker.minds += mind
if(SSticker)
SSticker.minds += mind
else
to_world_log("## DEBUG: mind_initialize(): No ticker ready yet! Please inform Carn")
if(!mind.name) mind.name = real_name
+1 -1
View File
@@ -8,7 +8,7 @@
creation_time = DS2TICKS(world.time)
. = ..()
#ifndef UNIT_TEST
#ifndef UNIT_TESTS
/datum/callback/verb_callback/Invoke(...)
var/mob/our_user = user?.resolve()
if(QDELETED(our_user) || isnull(our_user.client))