Adds support for PVP Bitrunning Domains (#89798)

## About The Pull Request

Adds support for PVP bitrunning domains. If min/max candidates are set
above 0, the virtual domain will search for any ghost spawners inside
and cause a randomly-selected ghost that signed up via poll to spawn
there. If no ghosts are signed up the process is cancelled.

Also adds content for them:
An outfit wardrobe that lets you select one of several possible outfits,
once.

![image](https://github.com/user-attachments/assets/485d854d-d0c4-43b8-9dc4-75fa9dd2f17f)

Not confident in my code, it's been in the works (as part of a
now-canned library heretic domain thing) for over a year
## Why It's Good For The Game

PvP domains are an underexplored concept. The beach domain is cloying
and overly simple. This adds support for newer and cooler domains as
long as there are ghosts for them.
## Changelog
🆑
code: Adds support for PVP Bitrunning Domains
/🆑
This commit is contained in:
carlarctg
2025-06-05 19:13:04 -04:00
committed by Roxy
parent 98c24012ea
commit 926cc5b859
6 changed files with 158 additions and 7 deletions
@@ -48,6 +48,8 @@
var/broadcasting = FALSE
/// Cooldown between being able to toggle broadcasting
COOLDOWN_DECLARE(broadcast_toggle_cd)
/// Cooldown for how often you're allowed to harass deadchat for PVP domains
COOLDOWN_DECLARE(polling_cooldown)
/obj/machinery/quantum_server/post_machine_initialize()
+40 -6
View File
@@ -1,3 +1,5 @@
#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))
@@ -84,12 +86,40 @@
for(var/datum/lazy_template/virtual_domain/available in SSbitrunning.all_domains)
if(map_key == available.key && points >= available.cost)
generated_domain = available
RegisterSignal(generated_domain, COMSIG_LAZY_TEMPLATE_LOADED, PROC_REF(on_template_loaded))
generated_domain.lazy_load()
return TRUE
break
return FALSE
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()
@@ -116,6 +146,10 @@
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)
@@ -134,12 +168,10 @@
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
@@ -199,3 +231,5 @@
generated_domain = null
mutation_candidate_refs.Cut()
spawned_threat_refs.Cut()
#undef POLLING_COOLDOWN_TIME