mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-24 13:38:41 +01:00
[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:
co-authored by
Jeremiah
Bloop
parent
6c11290c8e
commit
3238023f73
+41
-13
@@ -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 ..()
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user