[MIRROR] Adds more bitrunning antagonists + fixes (READY) [MDB IGNORE] (#25054)

* Adds more bitrunning antagonists + fixes (READY)

* Update role_preferences.dm

* Update poll_ignore.dm

* Update poll_ignore.dm

* Update cyber_police.dm

---------

Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com>
Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com>
This commit is contained in:
SkyratBot
2023-11-16 18:50:32 -05:00
committed by GitHub
co-authored by Jeremiah Bloop
parent 6c11290c8e
commit 3238023f73
76 changed files with 2806 additions and 8479 deletions
@@ -14,12 +14,12 @@
var/capacitor_coefficient = 1
/// The loaded map template, map_template/virtual_domain
var/datum/lazy_template/virtual_domain/generated_domain
/// The loaded safehouse, map_template/safehouse
var/datum/map_template/safehouse/generated_safehouse
/// If the current domain was a random selection
var/domain_randomized = FALSE
/// Prevents multiple user actions. Handled by loading domains and cooldowns
var/is_ready = TRUE
/// Chance multipled by threat to spawn a glitch
var/glitch_chance = 0.05
/// List of available domains
var/list/available_domains = list()
/// Current plugged in users
@@ -42,6 +42,8 @@
var/server_cooldown_time = 3 MINUTES
/// Applies bonuses to rewards etc
var/servo_bonus = 0
/// Determines the glitches available to spawn, builds with completion
var/threat = 0
/// The turfs we can place a hololadder on.
var/turf/exit_turfs = list()
@@ -54,15 +56,12 @@
. = ..()
radio = new(src)
radio.set_frequency(FREQ_SUPPLY)
radio.subspace_transmission = TRUE
radio.canhear_range = 0
radio.keyslot = new /obj/item/encryptionkey/headset_cargo()
radio.set_listening(FALSE)
radio.recalculateChannels()
RegisterSignals(src, list(COMSIG_MACHINERY_BROKEN, COMSIG_MACHINERY_POWER_LOST), PROC_REF(on_broken))
RegisterSignal(src, COMSIG_QDELETING, PROC_REF(on_delete))
RegisterSignal(src, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
RegisterSignal(src, COMSIG_BITRUNNER_SPAWN_GLITCH, PROC_REF(on_threat_created))
// This further gets sorted in the client by cost so it's random and grouped
available_domains = shuffle(subtypesof(/datum/lazy_template/virtual_domain))
@@ -76,17 +75,39 @@
spawned_threat_refs.Cut()
QDEL_NULL(exit_turfs)
QDEL_NULL(generated_domain)
QDEL_NULL(generated_safehouse)
QDEL_NULL(radio)
/obj/machinery/quantum_server/examine(mob/user)
. = ..()
. += span_infoplain("Can be resource intensive to run. Ensure adequate power supply.")
if(capacitor_coefficient < 1)
. += span_infoplain("Its coolant capacity reduces cooldown time by [(1 - capacitor_coefficient) * 100]%.")
if(servo_bonus > 0.2)
. += span_infoplain("Its manipulation potential is increasing rewards by [servo_bonus]x.")
. += span_infoplain("Injury from unsafe ejection reduced [servo_bonus * 100]%.")
if(!is_ready)
. += span_notice("It is currently cooling down. Give it a few moments.")
/obj/machinery/quantum_server/emag_act(mob/user, obj/item/card/emag/emag_card)
. = ..()
obj_flags |= EMAGGED
glitch_chance = 0.09
add_overlay(mutable_appearance('icons/obj/machines/bitrunning.dmi', "emag_overlay"))
balloon_alert(user, "bzzzt...")
playsound(src, 'sound/effects/sparks1.ogg', 35, vary = TRUE)
/obj/machinery/quantum_server/update_appearance(updates)
if(isnull(generated_domain) || !is_operational)
set_light(l_on = FALSE)
return ..()
set_light_color(is_ready ? LIGHT_COLOR_BABY_BLUE : LIGHT_COLOR_FIRE)
set_light(l_range = 2, l_power = 1.5, l_on = TRUE)
set_light(l_range = 2, l_power = 1.5, l_color = is_ready ? LIGHT_COLOR_BABY_BLUE : LIGHT_COLOR_FIRE, l_on = TRUE)
return ..()
/obj/machinery/quantum_server/update_icon_state()
@@ -97,6 +118,14 @@
icon_state = "[base_icon_state]_[is_ready ? "on" : "off"]"
return ..()
/obj/machinery/quantum_server/attackby(obj/item/weapon, mob/user, params)
. = ..()
if(istype(weapon, /obj/item/bitrunning_debug))
obj_flags |= EMAGGED
glitch_chance = 0.5
capacitor_coefficient = 0.01
points = 100
/obj/machinery/quantum_server/crowbar_act(mob/living/user, obj/item/crowbar)
. = ..()
@@ -121,8 +150,6 @@
return FALSE
/obj/machinery/quantum_server/RefreshParts()
. = ..()
var/capacitor_rating = 1.15
var/datum/stock_part/capacitor/cap = locate() in component_parts
capacitor_rating -= cap.tier * 0.15
@@ -139,3 +166,4 @@
servo_bonus = servo_rating
return ..()
+4
View File
@@ -110,6 +110,9 @@
score += time_score * base
// Increases the chance for glitches to spawn based on how well they're doing
threat += score
switch(score)
if(1 to 4)
return "D"
@@ -121,3 +124,4 @@
return "A"
else
return "S"
+44 -60
View File
@@ -1,18 +1,16 @@
#define ONLY_TURF 1
/// 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(user, "powering down domain...")
playsound(src, 'sound/machines/terminal_off.ogg', 40, 2)
balloon_alert_to_viewers("powering down domain...")
playsound(src, 'sound/machines/terminal_off.ogg', 40, vary = TRUE)
reset()
return
balloon_alert(user, "notifying clients...")
playsound(src, 'sound/machines/terminal_alert.ogg', 100, TRUE)
balloon_alert_to_viewers("notifying clients...")
playsound(src, 'sound/machines/terminal_alert.ogg', 100, vary = TRUE)
user.visible_message(
span_danger("[user] begins depowering the server!"),
span_notice("You start disconnecting clients..."),
@@ -26,40 +24,40 @@
reset()
/**
* ### Quantum Server Cold Boot
* Procedurally links the 3 booting processes together.
*
* This is the starting point if you have an id. Does validation and feedback on steps
*/
/obj/machinery/quantum_server/proc/cold_boot_map(mob/user, map_key)
/// Links all the loading processes together - does validation for booting a map
/obj/machinery/quantum_server/proc/cold_boot_map(map_key)
if(!is_ready)
return FALSE
if(isnull(map_key))
balloon_alert(user, "no domain specified.")
balloon_alert_to_viewers("no domain specified.")
return FALSE
if(generated_domain)
balloon_alert(user, "stop the current domain first.")
balloon_alert_to_viewers("stop the current domain first.")
return FALSE
if(length(avatar_connection_refs))
balloon_alert(user, "all clients must disconnect!")
balloon_alert_to_viewers("all clients must disconnect!")
return FALSE
is_ready = FALSE
playsound(src, 'sound/machines/terminal_processing.ogg', 30, 2)
if(!initialize_domain(map_key) || !initialize_safehouse() || !initialize_map_items())
balloon_alert(user, "initialization failed.")
/// If any one of these fail, it reverts the entire process
if(!load_domain(map_key) || !load_safehouse() || !load_map_items() || !load_mob_segments())
balloon_alert_to_viewers("initialization failed.")
scrub_vdom()
is_ready = TRUE
return FALSE
is_ready = TRUE
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 30, 2)
balloon_alert(user, "domain loaded.")
if(prob(clamp((threat * glitch_chance), 1, 10)))
setup_glitch()
playsound(src, 'sound/machines/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)
@@ -68,28 +66,20 @@
return TRUE
/// Initializes a new domain if the given key is valid and the user has enough points
/obj/machinery/quantum_server/proc/initialize_domain(map_key)
var/datum/lazy_template/virtual_domain/to_load
/obj/machinery/quantum_server/proc/load_domain(map_key)
for(var/datum/lazy_template/virtual_domain/available as anything in subtypesof(/datum/lazy_template/virtual_domain))
if(map_key != initial(available.key) || points < initial(available.cost))
continue
to_load = available
break
if(map_key == initial(available.key) && points >= initial(available.cost))
generated_domain = new available()
RegisterSignal(generated_domain, COMSIG_LAZY_TEMPLATE_LOADED, PROC_REF(on_template_loaded))
generated_domain.lazy_load()
return TRUE
if(isnull(to_load))
return FALSE
return FALSE
generated_domain = new to_load()
RegisterSignal(generated_domain, COMSIG_LAZY_TEMPLATE_LOADED, PROC_REF(on_template_loaded))
generated_domain.lazy_load()
return TRUE
/// Loads in necessary map items, sets mutation targets, etc
/obj/machinery/quantum_server/proc/initialize_map_items()
/// 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/crate_turfs = list()
var/turf/cache_turfs = list()
for(var/obj/effect/landmark/bitrunning/thing in GLOB.landmarks_list)
if(istype(thing, /obj/effect/landmark/bitrunning/hololadder_spawn))
@@ -106,7 +96,7 @@
continue
if(istype(thing, /obj/effect/landmark/bitrunning/cache_spawn))
crate_turfs += get_turf(thing)
cache_turfs += get_turf(thing)
qdel(thing)
continue
@@ -120,26 +110,23 @@
if(!length(goal_turfs))
CRASH("Failed to find send turfs on generated domain.")
if(length(crate_turfs))
shuffle_inplace(crate_turfs)
new /obj/structure/closet/crate/secure/bitrunning/encrypted(pick(crate_turfs))
if(!attempt_spawn_cache(cache_turfs))
return FALSE
return TRUE
/// Loads the safehouse
/obj/machinery/quantum_server/proc/initialize_safehouse()
var/turf/safehouse_load_turf = list()
for(var/obj/effect/landmark/bitrunning/safehouse_spawn/spawner in GLOB.landmarks_list)
safehouse_load_turf += get_turf(spawner)
qdel(spawner)
break
/obj/machinery/quantum_server/proc/load_safehouse()
var/obj/effect/landmark/bitrunning/safehouse_spawn/landmark = locate() in GLOB.landmarks_list
if(isnull(landmark))
CRASH("vdom: failed to find safehouse spawn landmark")
if(!length(safehouse_load_turf))
CRASH("Failed to find safehouse load landmark on map.")
var/turf/spawn_loc = get_turf(landmark)
qdel(landmark)
var/datum/map_template/safehouse/safehouse = new generated_domain.safehouse_path()
safehouse.load(safehouse_load_turf[ONLY_TURF])
generated_safehouse = safehouse
var/datum/map_template/safehouse/new_safehouse = new generated_domain.safehouse_path()
if(!new_safehouse.load(spawn_loc))
CRASH("vdom: failed to load safehouse")
return TRUE
@@ -155,14 +142,14 @@
else
scrub_vdom() // used in unit testing, no need to wait for callbacks
addtimer(CALLBACK(src, PROC_REF(cool_off)), min(server_cooldown_time * capacitor_coefficient), TIMER_UNIQUE|TIMER_STOPPABLE|TIMER_DELETE_ME)
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
/// Deletes all the tile contents
/// 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
@@ -171,19 +158,16 @@
var/datum/turf_reservation/res = generated_domain.reservations[1]
res.Release()
var/list/datum/weakref/creatures = spawned_threat_refs + mutation_candidate_refs
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
creature.dust() // sometimes mobs just don't die
creature.dust(just_ash = TRUE, force = TRUE) // sometimes mobs just don't die
avatar_connection_refs.Cut()
exit_turfs = list()
generated_domain = null
generated_safehouse = null
mutation_candidate_refs.Cut()
spawned_threat_refs.Cut()
#undef ONLY_TURF
@@ -1,3 +1,20 @@
/// Attempts to spawn a crate twice based on the list of available locations
/obj/machinery/quantum_server/proc/attempt_spawn_cache(list/possible_turfs)
if(!length(possible_turfs))
return TRUE
shuffle_inplace(possible_turfs)
var/turf/chosen_turf = validate_turf(pick(possible_turfs))
if(isnull(chosen_turf))
possible_turfs.Remove(chosen_turf)
chosen_turf = validate_turf(pick(possible_turfs))
if(isnull(chosen_turf))
CRASH("vdom: after two attemps, could not find a valid turf for cache")
new /obj/structure/closet/crate/secure/bitrunning/encrypted(chosen_turf)
return TRUE
/// Generates a new avatar for the bitrunner.
/obj/machinery/quantum_server/proc/generate_avatar(obj/structure/hololadder/wayout, datum/outfit/netsuit)
var/mob/living/carbon/human/avatar = new(wayout.loc)
@@ -19,17 +36,11 @@
if(istype(jumpsuit))
jumpsuit.set_armor(/datum/armor/clothing_under)
var/obj/item/clothing/head/hat = avatar.get_clothing_on_part(HEAD)
var/obj/item/clothing/head/hat = locate() in avatar.get_equipped_items()
if(istype(hat))
hat.set_armor(null)
hat.set_armor(/datum/armor/none)
var/thing = avatar.get_active_held_item()
if(!isnull(thing))
qdel(thing)
thing = avatar.get_inactive_held_item()
if(!isnull(thing))
qdel(thing)
QDEL_LIST(avatar.held_items)
var/obj/item/storage/backpack/bag = avatar.back
if(istype(bag))
@@ -78,6 +89,33 @@
return wayout
/// Loads in any mob segments of the map
/obj/machinery/quantum_server/proc/load_mob_segments()
if(!length(generated_domain.mob_modules))
return TRUE
var/current_index = 1
shuffle_inplace(generated_domain.mob_modules)
for(var/obj/effect/landmark/bitrunning/mob_segment/landmark in GLOB.landmarks_list)
if(current_index > length(generated_domain.mob_modules))
stack_trace("vdom: mobs segments are set to unique, but there are more landmarks than available segments")
return FALSE
var/path
if(generated_domain.modular_unique_mobs)
path = generated_domain.mob_modules[current_index]
current_index += 1
else
path = pick(generated_domain.mob_modules)
var/datum/modular_mob_segment/segment = new path()
segment.spawn_mobs(get_turf(landmark))
mutation_candidate_refs += segment.spawned_mob_refs
qdel(landmark)
return TRUE
/// Scans over neo's contents for bitrunning tech disks. Loads the items or abilities onto the avatar.
/obj/machinery/quantum_server/proc/stock_gear(mob/living/carbon/human/avatar, mob/living/carbon/human/neo, datum/lazy_template/virtual_domain/generated_domain)
var/domain_forbids_items = generated_domain.forbids_disk_items
@@ -109,6 +147,11 @@
continue
var/datum/action/our_action = new ability_disk.granted_action()
if(locate(our_action.type) in avatar.actions)
failed = TRUE
continue
our_action.Grant(avatar)
continue
@@ -122,4 +165,4 @@
avatar.put_in_hands(new item_disk.granted_item())
if(failed)
to_chat(neo, span_warning("One of your disks failed to load. You must activate them to make a selection."))
to_chat(neo, span_warning("One of your disks failed to load. Check for duplicate or inactive disks."))
@@ -14,8 +14,9 @@
/obj/machinery/quantum_server/proc/on_delete(datum/source)
SIGNAL_HANDLER
sever_connections()
if(generated_domain)
sever_connections()
scrub_vdom()
if(is_ready)
@@ -25,23 +26,6 @@
if(circuit)
qdel(circuit)
/// Handles examining the server. Shows cooldown time and efficiency.
/obj/machinery/quantum_server/proc/on_examine(datum/source, mob/examiner, list/examine_text)
SIGNAL_HANDLER
examine_text += span_infoplain("Can be resource intensive to run. Ensure adequate power supply.")
if(capacitor_coefficient < 1)
examine_text += span_infoplain("Its coolant capacity reduces cooldown time by [(1 - capacitor_coefficient) * 100]%.")
if(servo_bonus > 0.2)
examine_text += span_infoplain("Its manipulation potential is increasing rewards by [servo_bonus]x.")
examine_text += span_infoplain("Injury from unsafe ejection reduced [servo_bonus * 100]%.")
if(!is_ready)
examine_text += span_notice("It is currently cooling down. Give it a few moments.")
return
/// Whenever something enters the send tiles, check if it's a loot crate. If so, alert players.
/obj/machinery/quantum_server/proc/on_goal_turf_entered(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs)
SIGNAL_HANDLER
@@ -50,6 +34,15 @@
if(isnull(chosen_forge))
return
if((obj_flags & EMAGGED) && isliving(arrived))
var/mob/living/creature = arrived
if(!creature.mind?.has_antag_datum(/datum/antagonist/bitrunning_glitch, check_subtypes = TRUE))
return
INVOKE_ASYNC(src, PROC_REF(station_spawn), arrived, chosen_forge)
return
if(istype(arrived, /obj/structure/closet/crate/secure/bitrunning/encrypted))
generate_loot(arrived, chosen_forge)
return
@@ -70,7 +63,8 @@
var/mob/living/creature = thing
if(ismegafauna(creature))
creature.AddElement(/datum/element/virtual_elite_mob)
var/mob/living/simple_animal/hostile/megafauna/boss = creature
boss.make_virtual_megafauna()
continue
mutation_candidate_refs.Add(WEAKREF(creature))
+143
View File
@@ -3,6 +3,37 @@
spawned_threat_refs.Add(WEAKREF(threat))
SEND_SIGNAL(src, COMSIG_BITRUNNER_THREAT_CREATED)
/// Choses which antagonist role is spawned based on threat
/obj/machinery/quantum_server/proc/get_antagonist_role()
var/list/available = list()
for(var/datum/antagonist/bitrunning_glitch/subtype as anything in subtypesof(/datum/antagonist/bitrunning_glitch))
if(threat >= initial(subtype.threat))
available += subtype
shuffle_inplace(available)
var/datum/antagonist/bitrunning_glitch/chosen = pick(available)
threat -= initial(chosen.threat) * 0.5
return chosen
/// Selects a target to mutate. Gives two attempts, then crashes if it fails.
/obj/machinery/quantum_server/proc/get_mutation_target()
var/datum/weakref/target_ref = pick(mutation_candidate_refs)
var/mob/living/resolved = target_ref.resolve()
if(resolved)
return resolved
mutation_candidate_refs.Remove(target_ref)
if(!length(mutation_candidate_refs))
return
target_ref = pick(mutation_candidate_refs)
resolved = target_ref.resolve()
return resolved
/// Finds any mobs with minds in the zones and gives them the bad news
/obj/machinery/quantum_server/proc/notify_spawned_threats()
for(var/datum/weakref/baddie_ref as anything in spawned_threat_refs)
@@ -19,3 +50,115 @@
alert.desc = "The server is resetting. Oblivion awaits."
to_chat(baddie, span_userdanger("You have been flagged for deletion! Thank you for your service."))
/// Removes a specific threat - used when station spawning
/obj/machinery/quantum_server/proc/remove_threat(mob/living/threat)
spawned_threat_refs.Remove(WEAKREF(threat))
/// Selects the role and waits for a ghost orbiter
/obj/machinery/quantum_server/proc/setup_glitch(datum/antagonist/bitrunning_glitch/forced_role)
if(!validate_mutation_candidates())
return
var/mob/living/mutation_target = get_mutation_target()
if(isnull(mutation_target))
CRASH("vdom: After two attempts, no valid mutation target was found.")
var/atom/thing = mutation_target
thing.create_digital_aura()
var/datum/antagonist/bitrunning_glitch/chosen_role = forced_role || get_antagonist_role()
var/role_name = initial(chosen_role.name)
var/datum/callback/to_call = CALLBACK(src, PROC_REF(spawn_glitch), chosen_role, mutation_target)
mutation_target.AddComponent(/datum/component/orbit_poll, \
ignore_key = POLL_IGNORE_GLITCH, \
job_bans = ROLE_GLITCH, \
to_call = to_call, \
title = role_name, \
header = "Bitrunning Malfunction", \
)
return mutation_target
/// Orbit poll has concluded - spawn the antag
/obj/machinery/quantum_server/proc/spawn_glitch(datum/antagonist/bitrunning_glitch/chosen_role, mob/living/mutation_target, mob/dead/observer/ghost)
if(QDELETED(mutation_target))
return
if(QDELETED(src) || isnull(ghost) || isnull(generated_domain) || !is_ready || !is_operational)
var/atom/thing = mutation_target
thing.remove_digital_aura()
return
var/role_name = initial(chosen_role.name)
var/mob/living/antag_mob
switch(role_name)
if(ROLE_NETGUARDIAN)
antag_mob = new /mob/living/basic/netguardian(mutation_target.loc)
else // any other humanoid mob
antag_mob = new /mob/living/carbon/human(mutation_target.loc)
mutation_target.gib(DROP_ALL_REMAINS)
antag_mob.key = ghost.key
var/datum/mind/ghost_mind = antag_mob.mind
ghost_mind.add_antag_datum(chosen_role)
ghost_mind.special_role = ROLE_GLITCH
ghost_mind.set_assigned_role(SSjob.GetJobType(/datum/job/bitrunning_glitch))
playsound(antag_mob, 'sound/magic/ethereal_exit.ogg', 50, vary = TRUE)
message_admins("[ADMIN_LOOKUPFLW(antag_mob)] has been made into virtual antagonist by an event.")
antag_mob.log_message("was spawned as a virtual antagonist by an event.", LOG_GAME)
add_threats(antag_mob)
/// Oh boy - transports the antag station side
/obj/machinery/quantum_server/proc/station_spawn(mob/living/antag, obj/machinery/byteforge/chosen_forge)
antag.balloon_alert(antag, "scanning...")
chosen_forge.setup_particles(angry = TRUE)
radio.talk_into(src, "SECURITY BREACH: Unauthorized entry sequence detected.", RADIO_CHANNEL_SUPPLY)
SEND_SIGNAL(src, COMSIG_BITRUNNER_STATION_SPAWN)
var/timeout = 2 SECONDS
if(!ishuman(antag))
radio.talk_into(src, "Fabrication protocols have crashed unexpectedly. Please evacuate the area.", RADIO_CHANNEL_SUPPLY)
timeout = 10 SECONDS
if(!do_after(antag, timeout) || QDELETED(chosen_forge) || QDELETED(antag) || QDELETED(src) || !is_ready || !is_operational)
chosen_forge.setup_particles()
return
var/datum/component/glitch/effect = antag.AddComponent(/datum/component/glitch, \
server = src, \
forge = chosen_forge, \
)
chosen_forge.flicker(angry = TRUE)
if(!do_after(antag, 1 SECONDS))
chosen_forge.setup_particles()
qdel(effect)
return
chosen_forge.flash()
if(ishuman(antag))
reset_equipment(antag)
else
radio.talk_into(src, "CRITICAL ALERT: Unregistered mechanical entity deployed.")
do_teleport(antag, get_turf(chosen_forge), forced = TRUE, asoundin = 'sound/magic/ethereal_enter.ogg', asoundout = 'sound/magic/ethereal_exit.ogg', channel = TELEPORT_CHANNEL_QUANTUM)
/// Removes any invalid candidates from the list
/obj/machinery/quantum_server/proc/validate_mutation_candidates()
for(var/datum/weakref/creature_ref as anything in mutation_candidate_refs)
var/mob/living/creature = creature_ref.resolve()
if(isnull(creature) || creature.mind)
mutation_candidate_refs.Remove(creature_ref)
if(!length(mutation_candidate_refs))
return FALSE
shuffle_inplace(mutation_candidate_refs)
return TRUE
+40 -46
View File
@@ -22,6 +22,7 @@
"desc" = can_view ? initial(domain.desc) : "Limited scanning capabilities. Cannot infer domain details.",
"difficulty" = initial(domain.difficulty),
"id" = initial(domain.key),
"is_modular" = initial(domain.is_modular),
"name" = can_view ? initial(domain.name) : REDACTED,
"reward" = can_view_reward ? initial(domain.reward_points) : REDACTED,
))
@@ -53,31 +54,6 @@
return hosted_avatars
/// Gets a random available domain given the current points. Weighted towards higher cost domains.
/obj/machinery/quantum_server/proc/get_random_domain_id()
if(points < 1)
return
var/list/random_domains = list()
var/total_cost = 0
for(var/datum/lazy_template/virtual_domain/available as anything in subtypesof(/datum/lazy_template/virtual_domain))
var/init_cost = initial(available.cost)
if(!initial(available.test_only) && init_cost > 0 && init_cost < 4 && init_cost <= points)
random_domains += list(list(
cost = init_cost,
id = initial(available.key),
))
var/random_value = rand(0, total_cost)
var/accumulated_cost = 0
for(var/available as anything in random_domains)
accumulated_cost += available["cost"]
if(accumulated_cost >= random_value)
domain_randomized = TRUE
return available["id"]
/// Locates any turfs with forges on them, returns a random one
/obj/machinery/quantum_server/proc/get_random_nearby_forge()
var/list/nearby_forges = list()
@@ -87,30 +63,39 @@
return pick(nearby_forges)
/// Gets all mobs originally generated by the loaded domain and returns a list that are capable of being antagged
/obj/machinery/quantum_server/proc/get_valid_domain_targets()
// A: No one is playing
// B: The domain is not loaded
// C: The domain is shutting down
// D: There are no mobs
if(!length(avatar_connection_refs) || isnull(generated_domain) || !is_ready || !is_operational || !length(mutation_candidate_refs))
return list()
/// Gets a random available domain given the current points.
/obj/machinery/quantum_server/proc/get_random_domain_id()
if(points < 1)
return
for(var/datum/weakref/creature_ref as anything in mutation_candidate_refs)
var/mob/living/creature = creature_ref.resolve()
if(isnull(creature) || creature.mind)
mutation_candidate_refs.Remove(creature_ref)
var/list/random_domains = list()
return shuffle(mutation_candidate_refs)
for(var/datum/lazy_template/virtual_domain/available as anything in subtypesof(/datum/lazy_template/virtual_domain))
var/init_cost = initial(available.cost)
/// Locates any turfs with forges on them
/obj/machinery/quantum_server/proc/get_nearby_forges()
var/list/obj/machinery/byteforge/nearby_forges = list()
if(!initial(available.test_only) && \
init_cost <= points && \
init_cost > BITRUNNER_COST_NONE && \
init_cost < BITRUNNER_COST_EXTREME \
)
random_domains.Add(available)
for(var/obj/machinery/byteforge/forge in oview(MAX_DISTANCE, src))
nearby_forges += forge
shuffle_inplace(random_domains)
var/datum/lazy_template/virtual_domain/selected = pick(random_domains)
domain_randomized = TRUE
return nearby_forges
return initial(selected.key)
/// Removes all blacklisted items from a mob and returns them to base state
/obj/machinery/quantum_server/proc/reset_equipment(mob/living/carbon/human/person)
for(var/item in person.get_contents())
qdel(item)
var/datum/antagonist/bitrunning_glitch/antag_datum = locate() in person.mind?.antag_datums
if(isnull(antag_datum?.preview_outfit))
return
person.equipOutfit(antag_datum.preview_outfit)
/// Severs any connected users
/obj/machinery/quantum_server/proc/sever_connections()
@@ -121,10 +106,19 @@
/// Do some magic teleport sparks
/obj/machinery/quantum_server/proc/spark_at_location(obj/cache)
playsound(cache, 'sound/magic/blink.ogg', 50, TRUE)
playsound(cache, 'sound/magic/blink.ogg', 50, vary = TRUE)
var/datum/effect_system/spark_spread/quantum/sparks = new()
sparks.set_up(5, 1, get_turf(cache))
sparks.set_up(5, location = get_turf(cache))
sparks.start()
/// Returns a turf if it's not dense, else will find a neighbor.
/obj/machinery/quantum_server/proc/validate_turf(turf/chosen_turf)
if(!chosen_turf.is_blocked_turf())
return chosen_turf
for(var/turf/tile in get_adjacent_open_turfs(chosen_turf))
if(!tile.is_blocked_turf())
return chosen_turf
#undef REDACTED
#undef MAX_DISTANCE