mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-18 18:47:53 +01:00
## About The Pull Request Improves some blackbox logging for bitrunner domain creation, by also logging how much information they had when they chose it. Also some minor code improvements, by making methods for whether the name/reward of a domain is visible. ## Why It's Good For The Game Right now, if we just look at blackbox logs, we cannot easily tell if a domain is being deliberately avoided when possible, as we cannot tell if it's run unintentionally or intentionally. Now we will record that information, so we can act on it, and hopefully perform actions to improve the domains that people attempt to avoid.
248 lines
8.2 KiB
Plaintext
248 lines
8.2 KiB
Plaintext
#define POLLING_COOLDOWN_TIME 2 MINUTES
|
|
|
|
/// Gives all current occupants a notification that the server is going down
|
|
/obj/machinery/quantum_server/proc/begin_shutdown(mob/user)
|
|
if(isnull(generated_domain))
|
|
return
|
|
|
|
if(!length(avatar_connection_refs))
|
|
balloon_alert_to_viewers("powering down domain...")
|
|
playsound(src, 'sound/machines/terminal/terminal_off.ogg', 40, vary = TRUE)
|
|
reset()
|
|
return
|
|
|
|
balloon_alert_to_viewers("notifying clients...")
|
|
playsound(src, 'sound/machines/terminal/terminal_alert.ogg', 100, vary = TRUE)
|
|
user.visible_message(
|
|
span_danger("[user] begins depowering the server!"),
|
|
span_notice("You start disconnecting clients..."),
|
|
span_danger("You hear frantic keying on a keyboard."),
|
|
)
|
|
|
|
SEND_SIGNAL(src, COMSIG_BITRUNNER_SHUTDOWN_ALERT, user)
|
|
|
|
if(!do_after(user, 20 SECONDS, src))
|
|
return
|
|
|
|
reset()
|
|
|
|
|
|
/// Links all the loading processes together - does validation for booting a map
|
|
/obj/machinery/quantum_server/proc/cold_boot_map(map_key, was_random_selection)
|
|
if(!is_ready)
|
|
return FALSE
|
|
|
|
if(isnull(map_key))
|
|
balloon_alert_to_viewers("no domain specified!")
|
|
return FALSE
|
|
|
|
if(generated_domain)
|
|
balloon_alert_to_viewers("stop the current domain first!")
|
|
return FALSE
|
|
|
|
if(length(avatar_connection_refs))
|
|
balloon_alert_to_viewers("all clients must disconnect!")
|
|
return FALSE
|
|
|
|
is_ready = FALSE
|
|
playsound(src, 'sound/machines/terminal/terminal_processing.ogg', 30, 2)
|
|
|
|
/// If any one of these fail, it reverts the entire process
|
|
if(!load_domain(map_key) || !load_map_items() || !load_mob_segments())
|
|
balloon_alert_to_viewers("initialization failed!")
|
|
scrub_vdom()
|
|
is_ready = TRUE
|
|
return FALSE
|
|
|
|
|
|
//We will want to record how the domain was selected. Either entirely randomly, with the name redacted, or with full information.
|
|
//Without this, it is difficult to determine what domains are selected more often intentionallly, vs unintentionally.
|
|
var/selection_type
|
|
|
|
if(was_random_selection)
|
|
selection_type = "random selection"
|
|
else
|
|
if(generated_domain.can_view_name(scanner_tier, points))
|
|
selection_type = "full information"
|
|
else
|
|
selection_type = "redacted information"
|
|
SSblackbox.record_feedback("nested tally", "bitrunning_domain_loaded", 1, list(selection_type, map_key))
|
|
|
|
is_ready = TRUE
|
|
|
|
var/spawn_chance = clamp((threat * glitch_chance), 5, threat_prob_max)
|
|
if(prob(spawn_chance))
|
|
setup_glitch()
|
|
|
|
playsound(src, 'sound/machines/terminal/terminal_insert_disc.ogg', 30, vary = TRUE)
|
|
balloon_alert_to_viewers("domain loaded.")
|
|
generated_domain.start_time = world.time
|
|
points -= generated_domain.cost
|
|
update_use_power(ACTIVE_POWER_USE)
|
|
update_appearance()
|
|
|
|
if(broadcasting)
|
|
start_broadcasting_network(BITRUNNER_CAMERA_NET)
|
|
|
|
if(generated_domain.announce_to_ghosts)
|
|
notify_ghosts("Bitrunners have loaded a domain that offers ghost interactions. Check the spawners menu for more information.",
|
|
src,
|
|
"Matrix Glitch",
|
|
)
|
|
|
|
return TRUE
|
|
|
|
|
|
/// Initializes a new domain if the given key is valid and the user has enough points
|
|
/obj/machinery/quantum_server/proc/load_domain(map_key)
|
|
for(var/datum/lazy_template/virtual_domain/available in SSbitrunning.all_domains)
|
|
if(map_key == available.key && points >= available.cost)
|
|
generated_domain = available
|
|
break
|
|
|
|
if(!generated_domain)
|
|
return FALSE
|
|
|
|
if(generated_domain.mission_min_candidates && (!COOLDOWN_FINISHED(src, polling_cooldown)))
|
|
say("Advanced NPC algorithms resetting, please wait [DisplayTimeText(polling_cooldown)] or load a different domain.")
|
|
playsound(src, "sound/machines/buzz-[pick("sigh", "two")].ogg", 50, TRUE)
|
|
return FALSE
|
|
|
|
var/list/mob/lucky_ghosts
|
|
if(generated_domain.mission_min_candidates)
|
|
playsound(src, 'sound/machines/chime.ogg', 50, TRUE)
|
|
say("Loading advanced NPCs...")
|
|
var/list/mob/candidates = SSpolling.poll_ghost_candidates("Do you want to play as a virtual [generated_domain.spawner_role] in a bitrunner domain?", ROLE_GHOST_ROLE, ROLE_GHOST_ROLE, 15 SECONDS, POLL_IGNORE_SHUTTLE_DENIZENS, TRUE)
|
|
for(var/amount in 1 to generated_domain.mission_max_candidates)
|
|
if(length(candidates)) // If no candidates, fails in code below anyways
|
|
LAZYADD(lucky_ghosts, pick_n_take(candidates))
|
|
|
|
if(length(lucky_ghosts) < generated_domain.mission_min_candidates)
|
|
notify_ghosts("Not enough candidates for [generated_domain.spawner_role]! Aborting mission!")
|
|
playsound(src, "sound/machines/buzz-[pick("sigh", "two")].ogg", 50, TRUE)
|
|
say("Error! Unable to load advanced NPCs. Please try again or select different domain.")
|
|
COOLDOWN_START(src, polling_cooldown, POLLING_COOLDOWN_TIME)
|
|
return FALSE
|
|
|
|
playsound(src, 'sound/machines/ping.ogg', 50, TRUE)
|
|
say("Success!")
|
|
|
|
generated_domain.load_advanced_npcs(lucky_ghosts)
|
|
RegisterSignal(generated_domain, COMSIG_LAZY_TEMPLATE_LOADED, PROC_REF(on_template_loaded))
|
|
generated_domain.lazy_load()
|
|
|
|
return TRUE
|
|
|
|
/// Loads in necessary map items like hololadder spawns, caches, etc
|
|
/obj/machinery/quantum_server/proc/load_map_items()
|
|
var/turf/goal_turfs = list()
|
|
var/turf/cache_turfs = list()
|
|
var/turf/curiosity_turfs = list()
|
|
|
|
for(var/obj/effect/landmark/bitrunning/thing in GLOB.landmarks_list)
|
|
if(istype(thing, /obj/effect/landmark/bitrunning/hololadder_spawn))
|
|
exit_turfs += get_turf(thing)
|
|
qdel(thing) // i'm worried about multiple servers getting confused so lets clean em up
|
|
continue
|
|
|
|
if(istype(thing, /obj/effect/landmark/bitrunning/cache_goal_turf))
|
|
var/turf/tile = get_turf(thing)
|
|
goal_turfs += tile
|
|
RegisterSignal(tile, COMSIG_ATOM_ENTERED, PROC_REF(on_goal_turf_entered))
|
|
RegisterSignal(tile, COMSIG_ATOM_EXAMINE, PROC_REF(on_goal_turf_examined))
|
|
qdel(thing)
|
|
continue
|
|
|
|
if(istype(thing, /obj/effect/landmark/bitrunning/cache_spawn))
|
|
cache_turfs += get_turf(thing)
|
|
qdel(thing)
|
|
continue
|
|
|
|
if(istype(thing, /obj/effect/mob_spawn))
|
|
generated_domain.ghost_spawners += thing
|
|
continue
|
|
|
|
if(istype(thing, /obj/effect/landmark/bitrunning/curiosity_spawn))
|
|
curiosity_turfs += get_turf(thing)
|
|
qdel(thing)
|
|
continue
|
|
|
|
if(istype(thing, /obj/effect/landmark/bitrunning/loot_signal))
|
|
var/turf/signaler_turf = get_turf(thing)
|
|
signaler_turf.AddComponent(/datum/component/bitrunning_points, generated_domain)
|
|
qdel(thing)
|
|
continue
|
|
|
|
if(istype(thing, /obj/effect/landmark/bitrunning/permanent_exit))
|
|
var/turf/tile = get_turf(thing)
|
|
exit_turfs += tile
|
|
qdel(thing)
|
|
|
|
new /obj/structure/hololadder(tile)
|
|
|
|
if(!length(exit_turfs))
|
|
CRASH("Failed to find exit turfs on generated domain.")
|
|
if(!length(goal_turfs))
|
|
CRASH("Failed to find send turfs on generated domain.")
|
|
if(!attempt_spawn_cache(cache_turfs))
|
|
return FALSE
|
|
|
|
while(length(curiosity_turfs))
|
|
var/turf/picked_turf = attempt_spawn_curiosity(curiosity_turfs)
|
|
if(!picked_turf)
|
|
break
|
|
generated_domain.secondary_loot_generated += 1
|
|
curiosity_turfs -= picked_turf
|
|
|
|
return TRUE
|
|
|
|
|
|
/// Stops the current virtual domain and disconnects all users
|
|
/obj/machinery/quantum_server/proc/reset(fast = FALSE)
|
|
is_ready = FALSE
|
|
|
|
sever_connections()
|
|
|
|
if(!fast)
|
|
notify_spawned_threats()
|
|
addtimer(CALLBACK(src, PROC_REF(scrub_vdom)), 15 SECONDS, TIMER_UNIQUE|TIMER_STOPPABLE)
|
|
else
|
|
scrub_vdom() // used in unit testing, no need to wait for callbacks
|
|
|
|
addtimer(CALLBACK(src, PROC_REF(cool_off)), ROUND_UP(server_cooldown_time * capacitor_coefficient), TIMER_UNIQUE|TIMER_STOPPABLE|TIMER_DELETE_ME)
|
|
update_appearance()
|
|
|
|
update_use_power(IDLE_POWER_USE)
|
|
domain_randomized = FALSE
|
|
retries_spent = 0
|
|
|
|
stop_broadcasting_network(BITRUNNER_CAMERA_NET)
|
|
|
|
|
|
/// Tries to clean up everything in the domain
|
|
/obj/machinery/quantum_server/proc/scrub_vdom()
|
|
sever_connections() /// just in case someone's connected
|
|
SEND_SIGNAL(src, COMSIG_BITRUNNER_DOMAIN_SCRUBBED) // avatar cleanup just in case
|
|
|
|
if(length(generated_domain.reservations))
|
|
var/datum/turf_reservation/res = generated_domain.reservations[1]
|
|
res.Release()
|
|
|
|
var/list/creatures = spawned_threat_refs + mutation_candidate_refs
|
|
for(var/datum/weakref/creature_ref as anything in creatures)
|
|
var/mob/living/creature = creature_ref?.resolve()
|
|
if(isnull(creature))
|
|
continue
|
|
|
|
qdel(creature)
|
|
|
|
generated_domain.secondary_loot_generated = 0
|
|
|
|
avatar_connection_refs.Cut()
|
|
exit_turfs = list()
|
|
generated_domain = null
|
|
mutation_candidate_refs.Cut()
|
|
spawned_threat_refs.Cut()
|
|
|
|
#undef POLLING_COOLDOWN_TIME
|