mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-19 03:55:11 +01:00
Feature: bitrunner, a new supply role (READY) (#77259)
## About The Pull Request [Design doc](https://hackmd.io/@shadowh4nd/r1P7atPjn) Adds a new supply role centered on short dungeon-esque runs with a focus on unifying the job with the fun part. Some virtual domains are combat related, some are silly, some focus on "objectives". Avatar health is linked to your physical presence and retries are limited. <details> <summary>Photos, WIP</summary> Net pod stasis  Server loaded  Server cooldown  the quantum console UI  Cyber police antag page  A safehouse  Domain info page, every domain gets this (and sometimes help text)  Me getting steamrolled in one of the missions  Ghost roles getting notified that server is kicking them out  Players enjoying the new combat missions  Players exploring some of the virtual maps  (Not part of the PR, but)  New bitrunner vendor  </details> ## Why It's Good For The Game Content, firstly, and moreso being supply department content. The framework that this implements is a great (preauthorized) replacement for two systems which are collecting dust: BEPIS and the gateway. They integrate into this system and it's a direct upgrade. This adds a way for the players on station to generate materials (if that remains). The nice part about it is that I can throw balance and believability to the wind, as unlike its unrelated predecessor VR or away missions, bitrunning entirely washes its hands of the map and mobs each reboot. It offers a very expandable map framework to add content and it's all fairly well documented. I'd like to add a feature that represents the idea that jobs don't have to be mundane and "external" jobs can stay tied to the main gameplay loop. ## Changelog jlsnow301, kinneb, mmmiracles, ical92, spockye 🆑 add: Adds Bitrunning to supply department- a semi-offstation role that rewards teamwork. add: Adds new machines to complement the job- net pod, quantum server, quantum consoles, and the nexacache vendor. add: Adds several new maps which can be loaded and unloaded at will. add: Some flair for the new bitrunning vendor. add: Adds a new antagonist for the virtual domain only. Short lived ghost role that fights bitrunners. del: Removes the BEPIS machine, moves its tech into the Bitrunning vendor. /🆑 <!-- Both 🆑's are required for the changelog to work! You can put your name to the right of the first 🆑 if you want to overwrite your GitHub username as author ingame. --> <!-- You can use multiple of the same prefix (they're only used for the icon ingame) and delete the unneeded ones. Despite some of the tags, changelogs should generally represent how a player might be affected by the changes rather than a summary of the PR's contents. --> --------- Co-authored-by: MMMiracles <lolaccount1@hotmail.com> Co-authored-by: Ical <wolfsgamingtips@gmail.com> Co-authored-by: spockye <79304582+spockye@users.noreply.github.com> Co-authored-by: Watermelon914 <37270891+Watermelon914@users.noreply.github.com> Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
#define CREDIT_TYPE_BITRUNNING "np"
|
||||
|
||||
/obj/machinery/computer/order_console/bitrunning
|
||||
name = "bitrunning supplies order console"
|
||||
desc = "NexaCache(tm)! Dubiously authentic gear for the digital daredevil."
|
||||
icon = 'icons/obj/machines/bitrunning.dmi'
|
||||
icon_state = "vendor"
|
||||
icon_keyboard = null
|
||||
icon_screen = null
|
||||
circuit = /obj/item/circuitboard/computer/order_console/bitrunning
|
||||
cooldown_time = 10 SECONDS
|
||||
cargo_cost_multiplier = 0.65
|
||||
express_cost_multiplier = 1
|
||||
purchase_tooltip = @{"Your purchases will arrive at cargo,
|
||||
and hopefully get delivered by them.
|
||||
35% cheaper than express delivery."}
|
||||
express_tooltip = @{"Sends your purchases instantly."}
|
||||
credit_type = CREDIT_TYPE_BITRUNNING
|
||||
|
||||
order_categories = list(
|
||||
CATEGORY_BITRUNNING_FLAIR,
|
||||
CATEGORY_BITRUNNING_TECH,
|
||||
CATEGORY_BEPIS,
|
||||
)
|
||||
blackbox_key = "bitrunning"
|
||||
|
||||
/obj/machinery/computer/order_console/bitrunning/subtract_points(final_cost, obj/item/card/id/card)
|
||||
if(final_cost <= card.registered_account.bitrunning_points)
|
||||
card.registered_account.bitrunning_points -= final_cost
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/computer/order_console/bitrunning/order_groceries(mob/living/purchaser, obj/item/card/id/card, list/groceries)
|
||||
var/list/things_to_order = list()
|
||||
for(var/datum/orderable_item/item as anything in groceries)
|
||||
things_to_order[item.item_path] = groceries[item]
|
||||
|
||||
var/datum/supply_pack/bitrunning/pack = new(
|
||||
purchaser = purchaser, \
|
||||
cost = get_total_cost(), \
|
||||
contains = things_to_order,
|
||||
)
|
||||
|
||||
var/datum/supply_order/new_order = new(
|
||||
pack = pack,
|
||||
orderer = purchaser,
|
||||
orderer_rank = "Bitrunning Vendor",
|
||||
orderer_ckey = purchaser.ckey,
|
||||
reason = "",
|
||||
paying_account = card.registered_account,
|
||||
department_destination = null,
|
||||
coupon = null,
|
||||
charge_on_purchase = FALSE,
|
||||
manifest_can_fail = FALSE,
|
||||
cost_type = credit_type,
|
||||
can_be_cancelled = FALSE,
|
||||
)
|
||||
say("Thank you for your purchase! It will arrive on the next cargo shuttle!")
|
||||
radio.talk_into(src, "A bitrunner has ordered equipment which will arrive on the cargo shuttle! Please make sure it gets to them as soon as possible!", radio_channel)
|
||||
SSshuttle.shopping_list += new_order
|
||||
|
||||
/obj/machinery/computer/order_console/bitrunning/retrieve_points(obj/item/card/id/id_card)
|
||||
return round(id_card.registered_account.bitrunning_points)
|
||||
|
||||
/obj/machinery/computer/order_console/bitrunning/ui_act(action, params)
|
||||
. = ..()
|
||||
if(!.)
|
||||
flick("vendor_off", src)
|
||||
|
||||
/obj/machinery/computer/order_console/bitrunning/update_icon_state()
|
||||
icon_state = "[initial(icon_state)][powered() ? null : "_off"]"
|
||||
return ..()
|
||||
|
||||
/datum/supply_pack/bitrunning
|
||||
name = "bitrunning order"
|
||||
hidden = TRUE
|
||||
crate_name = "bitrunning delivery crate"
|
||||
access = list(ACCESS_BIT_DEN)
|
||||
|
||||
/datum/supply_pack/bitrunning/New(purchaser, cost, list/contains)
|
||||
. = ..()
|
||||
name = "[purchaser]'s Bitrunning Order"
|
||||
src.cost = cost
|
||||
src.contains = contains
|
||||
|
||||
#undef CREDIT_TYPE_BITRUNNING
|
||||
@@ -0,0 +1,9 @@
|
||||
/obj/item/clothing/glasses/sunglasses/oval
|
||||
name = "oval sunglasses"
|
||||
desc = "Vintage wrap around sunglasses. Provides a little protection."
|
||||
icon_state = "jensenshades"
|
||||
|
||||
/obj/item/clothing/suit/jacket/trenchcoat
|
||||
name = "trenchcoat"
|
||||
desc = "A long, black trenchcoat. Makes you feel like you're the one, but you're not."
|
||||
icon_state = "trenchcoat"
|
||||
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* Bitrunning tech disks which let you load items or programs into the vdom on first avatar generation.
|
||||
* For the record: Balance shouldn't be a primary concern.
|
||||
* You can make the custom cheese spells you've always wanted.
|
||||
* Just make it fun and engaging, it's PvE content.
|
||||
*/
|
||||
/obj/item/bitrunning_disk
|
||||
name = "generic bitrunning program"
|
||||
desc = "A disk containing source code."
|
||||
icon = 'icons/obj/assemblies/module.dmi'
|
||||
base_icon_state = "datadisk"
|
||||
icon_state = "datadisk0"
|
||||
/// Name of the choice made
|
||||
var/choice_made
|
||||
|
||||
/obj/item/bitrunning_disk/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
icon_state = "[base_icon_state][rand(0, 7)]"
|
||||
update_icon()
|
||||
RegisterSignal(src, COMSIG_ATOM_EXAMINE, PROC_REF(on_examined))
|
||||
|
||||
/obj/item/bitrunning_disk/proc/on_examined(datum/source, mob/examiner, list/examine_text)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
examine_text += span_infoplain("This disk must be carried on your person into a netpod to be used.")
|
||||
|
||||
if(isnull(choice_made))
|
||||
examine_text += span_notice("To make a selection, toggle the disk in hand.")
|
||||
return
|
||||
|
||||
examine_text += span_info("It has been used to select: <b>[choice_made]</b>.")
|
||||
examine_text += span_notice("It cannot make another selection.")
|
||||
|
||||
/obj/item/bitrunning_disk/ability
|
||||
desc = "A disk containing source code. It can be used to preload abilities into the virtual domain."
|
||||
/// The selected ability that this grants
|
||||
var/datum/action/granted_action
|
||||
/// The list of actions that this can grant
|
||||
var/list/datum/action/selectable_actions = list()
|
||||
|
||||
/obj/item/bitrunning_disk/ability/attack_self(mob/user, modifiers)
|
||||
. = ..()
|
||||
|
||||
if(choice_made)
|
||||
return
|
||||
|
||||
var/names = list()
|
||||
for(var/datum/action/thing as anything in selectable_actions)
|
||||
names += initial(thing.name)
|
||||
|
||||
var/choice = tgui_input_list(user, message = "Select an ability", title = "Bitrunning Program", items = names)
|
||||
if(isnull(choice))
|
||||
return
|
||||
|
||||
for(var/datum/action/thing as anything in selectable_actions)
|
||||
if(initial(thing.name) == choice)
|
||||
granted_action = thing
|
||||
|
||||
if(isnull(granted_action))
|
||||
return
|
||||
|
||||
balloon_alert(user, "selected")
|
||||
playsound(user, 'sound/items/click.ogg', 50, TRUE)
|
||||
choice_made = choice
|
||||
|
||||
/// Tier 1 programs. Simple, funny, or helpful.
|
||||
/obj/item/bitrunning_disk/ability/tier1
|
||||
name = "bitrunning program: basic"
|
||||
selectable_actions = list(
|
||||
/datum/action/cooldown/spell/conjure/cheese,
|
||||
/datum/action/cooldown/spell/basic_heal,
|
||||
)
|
||||
|
||||
/// Tier 2 programs. More complex, powerful, or useful.
|
||||
/obj/item/bitrunning_disk/ability/tier2
|
||||
name = "bitrunning program: complex"
|
||||
selectable_actions = list(
|
||||
/datum/action/cooldown/spell/pointed/projectile/fireball,
|
||||
/datum/action/cooldown/spell/pointed/projectile/lightningbolt,
|
||||
/datum/action/cooldown/spell/forcewall,
|
||||
)
|
||||
|
||||
/// Tier 3 abilities. Very powerful, game breaking.
|
||||
/obj/item/bitrunning_disk/ability/tier3
|
||||
name = "bitrunning program: elite"
|
||||
selectable_actions = list(
|
||||
/datum/action/cooldown/spell/shapeshift/dragon,
|
||||
/datum/action/cooldown/spell/shapeshift/polar_bear,
|
||||
)
|
||||
|
||||
/obj/item/bitrunning_disk/item
|
||||
desc = "A disk containing source code. It can be used to preload items into the virtual domain."
|
||||
/// The selected item that this grants
|
||||
var/obj/granted_item
|
||||
/// The list of actions that this can grant
|
||||
var/list/obj/selectable_items = list()
|
||||
|
||||
/obj/item/bitrunning_disk/item/attack_self(mob/user, modifiers)
|
||||
. = ..()
|
||||
|
||||
if(choice_made)
|
||||
return
|
||||
|
||||
var/names = list()
|
||||
for(var/obj/thing as anything in selectable_items)
|
||||
names += initial(thing.name)
|
||||
|
||||
var/choice = tgui_input_list(user, message = "Select an ability", title = "Bitrunning Program", items = names)
|
||||
if(isnull(choice))
|
||||
return
|
||||
|
||||
for(var/obj/thing as anything in selectable_items)
|
||||
if(initial(thing.name) == choice)
|
||||
granted_item = thing
|
||||
|
||||
balloon_alert(user, "selected")
|
||||
playsound(user, 'sound/items/click.ogg', 50, TRUE)
|
||||
choice_made = choice
|
||||
|
||||
/// Tier 1 items. Simple, funny, or helpful.
|
||||
/obj/item/bitrunning_disk/item/tier1
|
||||
name = "bitrunning gear: simple"
|
||||
selectable_items = list(
|
||||
/obj/item/pizzabox/infinite,
|
||||
/obj/item/gun/medbeam,
|
||||
/obj/item/grenade/c4,
|
||||
)
|
||||
|
||||
/// Tier 2 items. More complex, powerful, or useful.
|
||||
/obj/item/bitrunning_disk/item/tier2
|
||||
name = "bitrunning gear: complex"
|
||||
selectable_items = list(
|
||||
/obj/item/chainsaw,
|
||||
/obj/item/gun/ballistic/automatic/pistol,
|
||||
/obj/item/melee/energy/blade/hardlight,
|
||||
)
|
||||
|
||||
/// Tier 3 items. Very powerful, game breaking.
|
||||
/obj/item/bitrunning_disk/item/tier3
|
||||
name = "bitrunning gear: advanced"
|
||||
selectable_items = list(
|
||||
/obj/item/gun/energy/tesla_cannon,
|
||||
/obj/item/dualsaber/green,
|
||||
/obj/item/melee/beesword,
|
||||
)
|
||||
@@ -0,0 +1,52 @@
|
||||
/obj/structure/hololadder
|
||||
name = "hololadder"
|
||||
|
||||
anchored = TRUE
|
||||
desc = "An abstract representation of the means to disconnect from the virtual domain."
|
||||
icon = 'icons/obj/structures.dmi'
|
||||
icon_state = "ladder11"
|
||||
obj_flags = BLOCK_Z_OUT_DOWN
|
||||
/// Time req to disconnect properly
|
||||
var/travel_time = 3 SECONDS
|
||||
|
||||
/obj/structure/hololadder/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
RegisterSignal(loc, COMSIG_ATOM_ENTERED, PROC_REF(on_enter))
|
||||
|
||||
/obj/structure/hololadder/attack_hand(mob/user, list/modifiers)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
if(!in_range(src, user) || DOING_INTERACTION(user, DOAFTER_SOURCE_CLIMBING_LADDER))
|
||||
return
|
||||
|
||||
disconnect(user)
|
||||
|
||||
/// If there's a pilot ref- send the disconnect signal
|
||||
/obj/structure/hololadder/proc/disconnect(mob/user)
|
||||
if(isnull(user.mind))
|
||||
return
|
||||
|
||||
var/datum/component/avatar_connection/connection = user.GetComponent(/datum/component/avatar_connection)
|
||||
if(isnull(connection))
|
||||
balloon_alert(user, "no connection detected.")
|
||||
return
|
||||
|
||||
balloon_alert(user, "disconnecting...")
|
||||
if(do_after(user, travel_time, src))
|
||||
SEND_SIGNAL(user, COMSIG_BITRUNNER_SAFE_DISCONNECT)
|
||||
|
||||
/// Helper for times when you dont have hands (gondola??)
|
||||
/obj/structure/hololadder/proc/on_enter(datum/source, atom/movable/arrived, turf/old_loc)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!isliving(arrived))
|
||||
return
|
||||
|
||||
var/mob/living/user = arrived
|
||||
if(isnull(user.mind))
|
||||
return
|
||||
|
||||
INVOKE_ASYNC(src, PROC_REF(disconnect), user)
|
||||
@@ -0,0 +1,33 @@
|
||||
/obj/item/bitrunning_host_monitor
|
||||
name = "host monitor"
|
||||
|
||||
custom_materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT * 2)
|
||||
desc = "A complex medical device that, when attached to an avatar's data stream, can detect the user of their host's health."
|
||||
flags_1 = CONDUCT_1
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "gps-b"
|
||||
inhand_icon_state = "electronic"
|
||||
item_flags = NOBLUDGEON
|
||||
lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi'
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
throw_range = 7
|
||||
throw_speed = 3
|
||||
throwforce = 3
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
worn_icon_state = "electronic"
|
||||
|
||||
/obj/item/bitrunning_host_monitor/attack_self(mob/user, modifiers)
|
||||
. = ..()
|
||||
|
||||
var/datum/component/avatar_connection/connection = user.GetComponent(/datum/component/avatar_connection)
|
||||
if(isnull(connection))
|
||||
balloon_alert(user, "data not recognized")
|
||||
return
|
||||
|
||||
var/mob/living/pilot = connection.old_body_ref?.resolve()
|
||||
if(isnull(pilot))
|
||||
balloon_alert(user, "host not recognized")
|
||||
return
|
||||
|
||||
to_chat(user, span_notice("Current host health: [pilot.health / pilot.maxHealth * 100]%"))
|
||||
@@ -0,0 +1,70 @@
|
||||
/obj/effect/landmark/bitrunning
|
||||
name = "Generic bitrunning effect"
|
||||
icon = 'icons/effects/bitrunning.dmi'
|
||||
icon_state = "crate"
|
||||
|
||||
/// In case you want to gate the crate behind a special condition.
|
||||
/obj/effect/landmark/bitrunning/loot_signal
|
||||
name = "Mysterious aura"
|
||||
/// The amount required to spawn a crate
|
||||
var/points_goal = 10
|
||||
/// A special condition limits this from spawning a crate
|
||||
var/points_received = 0
|
||||
/// Finished the special condition
|
||||
var/revealed = FALSE
|
||||
|
||||
/obj/effect/landmark/bitrunning/loot_signal/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
RegisterSignal(src, COMSIG_BITRUNNER_GOAL_POINT, PROC_REF(on_add_point))
|
||||
|
||||
/// Listens for points to be added which will eventually spawn a crate.
|
||||
/obj/effect/landmark/bitrunning/loot_signal/proc/on_add_point(datum/source, points_to_add)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(revealed)
|
||||
return
|
||||
|
||||
points_received += points_to_add
|
||||
|
||||
if(points_received < points_goal)
|
||||
return
|
||||
|
||||
reveal()
|
||||
|
||||
/// Spawns the crate with some effects
|
||||
/obj/effect/landmark/bitrunning/loot_signal/proc/reveal()
|
||||
playsound(src, 'sound/magic/blink.ogg', 50, TRUE)
|
||||
|
||||
var/turf/tile = get_turf(src)
|
||||
var/obj/structure/closet/crate/secure/bitrunning/encrypted/loot = new(tile)
|
||||
var/datum/effect_system/spark_spread/quantum/sparks = new(tile)
|
||||
sparks.set_up(5, 1, get_turf(loot))
|
||||
sparks.start()
|
||||
|
||||
qdel(src)
|
||||
|
||||
/// Where the crates get ported to station
|
||||
/obj/effect/landmark/bitrunning/station_reward_spawn
|
||||
name = "Bitrunning rewards spawn"
|
||||
icon_state = "station"
|
||||
|
||||
/// Where the exit hololadder spawns
|
||||
/obj/effect/landmark/bitrunning/hololadder_spawn
|
||||
name = "Bitrunning hololadder spawn"
|
||||
icon_state = "hololadder"
|
||||
|
||||
/// Where the crates need to be taken
|
||||
/obj/effect/landmark/bitrunning/cache_goal_turf
|
||||
name = "Bitrunning goal turf"
|
||||
icon_state = "goal"
|
||||
|
||||
/// Where you want the crate to spawn
|
||||
/obj/effect/landmark/bitrunning/cache_spawn
|
||||
name = "Bitrunning crate spawn"
|
||||
icon_state = "spawn"
|
||||
|
||||
/// Where the safehouse will spawn
|
||||
/obj/effect/landmark/bitrunning/safehouse_spawn
|
||||
name = "Bitrunning safehouse spawn"
|
||||
icon_state = "safehouse"
|
||||
@@ -0,0 +1,91 @@
|
||||
#define ORE_MULTIPLIER_IRON 3
|
||||
#define ORE_MULTIPLIER_GLASS 2
|
||||
#define ORE_MULTIPLIER_PLASMA 1
|
||||
#define ORE_MULTIPLIER_SILVER 0.7
|
||||
#define ORE_MULTIPLIER_GOLD 0.6
|
||||
#define ORE_MULTIPLIER_TITANIUM 0.5
|
||||
#define ORE_MULTIPLIER_URANIUM 0.4
|
||||
#define ORE_MULTIPLIER_DIAMOND 0.3
|
||||
#define ORE_MULTIPLIER_BLUESPACE_CRYSTAL 0.2
|
||||
|
||||
/obj/structure/closet/crate/secure/bitrunning // Base class. Do not spawn this.
|
||||
name = "base class cache"
|
||||
desc = "Talk to a coder."
|
||||
|
||||
/// The virtual domain - side of the bitrunning crate. Deliver to the send location.
|
||||
/obj/structure/closet/crate/secure/bitrunning/encrypted
|
||||
name = "encrypted cache"
|
||||
desc = "Needs decrypted at the safehouse to be opened."
|
||||
locked = TRUE
|
||||
|
||||
/obj/structure/closet/crate/secure/bitrunning/encrypted/can_unlock(mob/living/user, obj/item/card/id/player_id, obj/item/card/id/registered_id)
|
||||
return FALSE
|
||||
|
||||
/// The bitrunner den - side of the bitrunning crate. Appears in the receive location.
|
||||
/obj/structure/closet/crate/secure/bitrunning/decrypted
|
||||
name = "decrypted cache"
|
||||
desc = "Compiled from the virtual domain. The reward of a successful bitrunner."
|
||||
locked = FALSE
|
||||
|
||||
/obj/structure/closet/crate/secure/bitrunning/decrypted/Initialize(
|
||||
mapload,
|
||||
datum/lazy_template/virtual_domain/completed_domain,
|
||||
rewards_multiplier = 1,
|
||||
)
|
||||
. = ..()
|
||||
playsound(src, 'sound/magic/blink.ogg', 50, TRUE)
|
||||
|
||||
if(isnull(completed_domain))
|
||||
return
|
||||
|
||||
PopulateContents(completed_domain.reward_points, completed_domain.extra_loot, rewards_multiplier)
|
||||
|
||||
/obj/structure/closet/crate/secure/bitrunning/decrypted/PopulateContents(reward_points, list/extra_loot, rewards_multiplier)
|
||||
. = ..()
|
||||
spawn_loot(extra_loot)
|
||||
|
||||
new /obj/item/stack/ore/iron(src, calculate_loot(reward_points, rewards_multiplier, ORE_MULTIPLIER_IRON))
|
||||
new /obj/item/stack/ore/glass(src, calculate_loot(reward_points, rewards_multiplier, ORE_MULTIPLIER_GLASS))
|
||||
|
||||
if(reward_points > 1)
|
||||
new /obj/item/stack/ore/silver(src, calculate_loot(reward_points, rewards_multiplier, ORE_MULTIPLIER_SILVER))
|
||||
new /obj/item/stack/ore/titanium(src, calculate_loot(reward_points, rewards_multiplier, ORE_MULTIPLIER_TITANIUM))
|
||||
|
||||
if(reward_points > 2)
|
||||
new /obj/item/stack/ore/plasma(src, calculate_loot(reward_points, rewards_multiplier, ORE_MULTIPLIER_PLASMA))
|
||||
new /obj/item/stack/ore/gold(src, calculate_loot(reward_points, rewards_multiplier, ORE_MULTIPLIER_GOLD))
|
||||
new /obj/item/stack/ore/uranium(src, calculate_loot(reward_points, rewards_multiplier, ORE_MULTIPLIER_URANIUM))
|
||||
|
||||
if(reward_points > 3)
|
||||
new /obj/item/stack/ore/diamond(src, calculate_loot(reward_points, rewards_multiplier, ORE_MULTIPLIER_DIAMOND))
|
||||
new /obj/item/stack/ore/bluespace_crystal(src, calculate_loot(reward_points, rewards_multiplier, ORE_MULTIPLIER_BLUESPACE_CRYSTAL))
|
||||
|
||||
/// Handles generating random numbers & calculating loot totals
|
||||
/obj/structure/closet/crate/secure/bitrunning/decrypted/proc/calculate_loot(reward_points, rewards_multiplier, ore_multiplier)
|
||||
var/base = 1 * (rewards_multiplier + reward_points)
|
||||
var/random_sum = (rand() * 1.0 + 0.5) * base
|
||||
return ROUND_UP(random_sum * ore_multiplier)
|
||||
|
||||
/// Handles spawning extra loot. This tries to handle bad flat and assoc lists
|
||||
/obj/structure/closet/crate/secure/bitrunning/decrypted/proc/spawn_loot(list/extra_loot)
|
||||
for(var/path in extra_loot)
|
||||
if(!ispath(path))
|
||||
continue
|
||||
|
||||
if(isnull(extra_loot[path]))
|
||||
return FALSE
|
||||
|
||||
for(var/i in 1 to extra_loot[path])
|
||||
new path(src)
|
||||
|
||||
return TRUE
|
||||
|
||||
#undef ORE_MULTIPLIER_IRON
|
||||
#undef ORE_MULTIPLIER_GLASS
|
||||
#undef ORE_MULTIPLIER_PLASMA
|
||||
#undef ORE_MULTIPLIER_SILVER
|
||||
#undef ORE_MULTIPLIER_GOLD
|
||||
#undef ORE_MULTIPLIER_TITANIUM
|
||||
#undef ORE_MULTIPLIER_URANIUM
|
||||
#undef ORE_MULTIPLIER_DIAMOND
|
||||
#undef ORE_MULTIPLIER_BLUESPACE_CRYSTAL
|
||||
@@ -0,0 +1,472 @@
|
||||
#define BASE_DISCONNECT_DAMAGE 40
|
||||
|
||||
/obj/machinery/netpod
|
||||
name = "netpod"
|
||||
|
||||
base_icon_state = "netpod"
|
||||
circuit = /obj/item/circuitboard/machine/netpod
|
||||
desc = "A link to the netverse. It has an assortment of cables to connect yourself to a virtual domain."
|
||||
icon = 'icons/obj/machines/bitrunning.dmi'
|
||||
icon_state = "netpod"
|
||||
max_integrity = 300
|
||||
obj_flags = BLOCKS_CONSTRUCTION
|
||||
state_open = TRUE
|
||||
/// Whether we have an ongoing connection
|
||||
var/connected = FALSE
|
||||
/// A player selected outfit by clicking the netpod
|
||||
var/datum/outfit/netsuit = /datum/outfit/job/bitrunner
|
||||
/// Holds this to see if it needs to generate a new one
|
||||
var/datum/weakref/avatar_ref
|
||||
/// The linked quantum server
|
||||
var/datum/weakref/server_ref
|
||||
/// The amount of brain damage done from force disconnects
|
||||
var/disconnect_damage
|
||||
/// Static list of outfits to select from
|
||||
var/list/cached_outfits = list()
|
||||
|
||||
/obj/machinery/netpod/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
return INITIALIZE_HINT_LATELOAD
|
||||
|
||||
/obj/machinery/netpod/LateInitialize()
|
||||
. = ..()
|
||||
|
||||
disconnect_damage = BASE_DISCONNECT_DAMAGE
|
||||
|
||||
RegisterSignals(src, list(
|
||||
COMSIG_QDELETING,
|
||||
COMSIG_MACHINERY_BROKEN,
|
||||
COMSIG_MACHINERY_POWER_LOST,
|
||||
),
|
||||
PROC_REF(on_broken),
|
||||
)
|
||||
RegisterSignal(src, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
|
||||
RegisterSignal(src, COMSIG_ATOM_TAKE_DAMAGE, PROC_REF(on_take_damage))
|
||||
|
||||
register_context()
|
||||
update_appearance()
|
||||
|
||||
/obj/machinery/netpod/Destroy()
|
||||
. = ..()
|
||||
cached_outfits.Cut()
|
||||
|
||||
/obj/machinery/netpod/add_context(atom/source, list/context, obj/item/held_item, mob/user)
|
||||
. = ..()
|
||||
|
||||
if(isnull(held_item))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Select Outfit"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
if(istype(held_item, /obj/item/crowbar) && occupant)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Pry Open"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
/obj/machinery/netpod/update_icon_state()
|
||||
if(!is_operational)
|
||||
icon_state = base_icon_state
|
||||
return ..()
|
||||
|
||||
if(state_open)
|
||||
icon_state = base_icon_state + "_open_active"
|
||||
return ..()
|
||||
|
||||
if(panel_open)
|
||||
icon_state = base_icon_state + "_panel"
|
||||
return ..()
|
||||
|
||||
icon_state = base_icon_state + "_closed"
|
||||
if(occupant)
|
||||
icon_state += "_active"
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/netpod/MouseDrop_T(mob/target, mob/user)
|
||||
var/mob/living/carbon/player = user
|
||||
if(!iscarbon(player))
|
||||
return
|
||||
|
||||
if((HAS_TRAIT(player, TRAIT_UI_BLOCKED) && !player.resting) || !Adjacent(player) || !player.Adjacent(target) || !ISADVANCEDTOOLUSER(player) || !is_operational)
|
||||
return
|
||||
|
||||
close_machine(target)
|
||||
|
||||
/obj/machinery/netpod/crowbar_act(mob/living/user, obj/item/tool)
|
||||
if(user.combat_mode)
|
||||
attack_hand(user)
|
||||
return TOOL_ACT_TOOLTYPE_SUCCESS
|
||||
|
||||
if(default_pry_open(tool, user) || default_deconstruction_crowbar(tool))
|
||||
return TOOL_ACT_TOOLTYPE_SUCCESS
|
||||
|
||||
/obj/machinery/netpod/screwdriver_act(mob/living/user, obj/item/tool)
|
||||
if(occupant)
|
||||
balloon_alert(user, "in use!")
|
||||
return TOOL_ACT_TOOLTYPE_SUCCESS
|
||||
|
||||
if(state_open)
|
||||
balloon_alert(user, "close first.")
|
||||
return TOOL_ACT_TOOLTYPE_SUCCESS
|
||||
|
||||
if(default_deconstruction_screwdriver(user, "[base_icon_state]_panel", "[base_icon_state]_closed", tool))
|
||||
update_appearance() // sometimes icon doesnt properly update during flick()
|
||||
ui_close(user)
|
||||
return TOOL_ACT_TOOLTYPE_SUCCESS
|
||||
|
||||
/obj/machinery/netpod/attack_hand(mob/living/user, list/modifiers)
|
||||
. = ..()
|
||||
if(!state_open && user == occupant)
|
||||
container_resist_act(user)
|
||||
|
||||
/obj/machinery/netpod/Exited(atom/movable/gone, direction)
|
||||
. = ..()
|
||||
if(!state_open && gone == occupant)
|
||||
container_resist_act(gone)
|
||||
|
||||
/obj/machinery/netpod/Exited(atom/movable/gone, direction)
|
||||
. = ..()
|
||||
if(!state_open && gone == occupant)
|
||||
container_resist_act(gone)
|
||||
|
||||
/obj/machinery/netpod/relaymove(mob/living/user, direction)
|
||||
if(!state_open)
|
||||
container_resist_act(user)
|
||||
|
||||
/obj/machinery/netpod/container_resist_act(mob/living/user)
|
||||
user.visible_message(span_notice("[occupant] emerges from [src]!"),
|
||||
span_notice("You climb out of [src]!"),
|
||||
span_notice("With a hiss, you hear a machine opening."))
|
||||
open_machine()
|
||||
|
||||
/obj/machinery/netpod/open_machine(drop = TRUE, density_to_set = FALSE)
|
||||
unprotect_and_signal()
|
||||
playsound(src, 'sound/machines/tramopen.ogg', 60, TRUE, frequency = 65000)
|
||||
flick("[base_icon_state]_opening", src)
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/netpod/close_machine(mob/user, density_to_set = TRUE)
|
||||
if(!state_open || panel_open || !is_operational || !iscarbon(user))
|
||||
return
|
||||
|
||||
playsound(src, 'sound/machines/tramclose.ogg', 60, TRUE, frequency = 65000)
|
||||
flick("[base_icon_state]_closing", src)
|
||||
..()
|
||||
|
||||
if(!iscarbon(occupant))
|
||||
open_machine()
|
||||
return
|
||||
|
||||
enter_matrix()
|
||||
|
||||
/obj/machinery/netpod/default_pry_open(obj/item/crowbar, mob/living/pryer)
|
||||
if(isnull(occupant) || !iscarbon(occupant))
|
||||
if(!state_open)
|
||||
if(panel_open)
|
||||
return FALSE
|
||||
open_machine()
|
||||
else
|
||||
shut_pod()
|
||||
|
||||
return TRUE
|
||||
|
||||
pryer.visible_message(
|
||||
span_danger("[pryer] starts prying open [src]!"),
|
||||
span_notice("You start to pry open [src]."),
|
||||
span_notice("You hear loud prying on metal.")
|
||||
)
|
||||
playsound(src, 'sound/machines/airlock_alien_prying.ogg', 100, TRUE)
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_BITRUNNER_CROWBAR_ALERT, pryer)
|
||||
|
||||
if(do_after(pryer, 15 SECONDS, src))
|
||||
if(!state_open)
|
||||
open_machine()
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/netpod/ui_interact(mob/user, datum/tgui/ui)
|
||||
if(!is_operational)
|
||||
return
|
||||
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "NetpodOutfits")
|
||||
ui.set_autoupdate(FALSE)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/netpod/ui_data()
|
||||
var/list/data = list()
|
||||
|
||||
data["netsuit"] = netsuit
|
||||
return data
|
||||
|
||||
/obj/machinery/netpod/ui_static_data()
|
||||
var/list/data = list()
|
||||
|
||||
if(!length(cached_outfits))
|
||||
cached_outfits += make_outfit_collection("Jobs", subtypesof(/datum/outfit/job))
|
||||
|
||||
data["collections"] = cached_outfits
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/netpod/ui_act(action, params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return TRUE
|
||||
switch(action)
|
||||
if("select_outfit")
|
||||
var/datum/outfit/new_suit = resolve_outfit(params["outfit"])
|
||||
if(new_suit)
|
||||
netsuit = new_suit
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/// Disconnects the occupant after a certain time so they aren't just hibernating in netpod stasis. A balance change
|
||||
/obj/machinery/netpod/proc/auto_disconnect()
|
||||
if(isnull(occupant) || state_open || connected)
|
||||
return
|
||||
|
||||
if(!iscarbon(occupant))
|
||||
open_machine()
|
||||
return
|
||||
|
||||
var/mob/living/carbon/player = occupant
|
||||
|
||||
player.playsound_local(src, 'sound/effects/splash.ogg', 60, TRUE)
|
||||
to_chat(player, span_notice("The machine disconnects itself and begins to drain."))
|
||||
open_machine()
|
||||
|
||||
/**
|
||||
* ### Disconnect occupant
|
||||
* If this goes smoothly, should reconnect a receiving mind to the occupant's body
|
||||
*
|
||||
* This is the second stage of the process - if you want to disconn avatars start at the mind first
|
||||
*/
|
||||
/obj/machinery/netpod/proc/disconnect_occupant(forced = FALSE)
|
||||
var/mob/living/mob_occupant = occupant
|
||||
if(isnull(occupant) || !isliving(occupant))
|
||||
return
|
||||
|
||||
connected = FALSE
|
||||
|
||||
if(mob_occupant.stat == DEAD)
|
||||
open_machine()
|
||||
return
|
||||
|
||||
mob_occupant.playsound_local(src, "sound/magic/blink.ogg", 25, TRUE)
|
||||
mob_occupant.set_static_vision(2 SECONDS)
|
||||
mob_occupant.set_temp_blindness(1 SECONDS)
|
||||
mob_occupant.Paralyze(2 SECONDS)
|
||||
|
||||
var/heal_time = 1
|
||||
if(mob_occupant.health < mob_occupant.maxHealth)
|
||||
heal_time = (mob_occupant.stat + 2) * 5
|
||||
addtimer(CALLBACK(src, PROC_REF(auto_disconnect)), heal_time SECONDS, TIMER_UNIQUE|TIMER_STOPPABLE|TIMER_DELETE_ME)
|
||||
|
||||
if(!forced)
|
||||
return
|
||||
|
||||
mob_occupant.flash_act(override_blindness_check = TRUE, visual = TRUE)
|
||||
mob_occupant.adjustOrganLoss(ORGAN_SLOT_BRAIN, disconnect_damage)
|
||||
INVOKE_ASYNC(mob_occupant, TYPE_PROC_REF(/mob/living, emote), "scream")
|
||||
to_chat(mob_occupant, span_danger("You've been forcefully disconnected from your avatar! Your thoughts feel scrambled!"))
|
||||
|
||||
/**
|
||||
* ### Enter Matrix
|
||||
* Finds any current avatars from this chair - or generates a new one
|
||||
*
|
||||
* New avatars cost 1 attempt, and this will eject if there's none left
|
||||
*
|
||||
* Connects the mind to the avatar if everything is ok
|
||||
*/
|
||||
/obj/machinery/netpod/proc/enter_matrix()
|
||||
var/mob/living/carbon/human/neo = occupant
|
||||
if(!ishuman(neo) || neo.stat == DEAD || isnull(neo.mind))
|
||||
balloon_alert(neo, "invalid occupant.")
|
||||
return
|
||||
|
||||
var/obj/machinery/quantum_server/server = find_server()
|
||||
if(isnull(server))
|
||||
balloon_alert(neo, "no server connected!")
|
||||
return
|
||||
|
||||
var/datum/lazy_template/virtual_domain/generated_domain = server.generated_domain
|
||||
if(isnull(generated_domain) || !server.is_ready)
|
||||
balloon_alert(neo, "nothing loaded!")
|
||||
return
|
||||
|
||||
var/mob/living/carbon/current_avatar = avatar_ref?.resolve()
|
||||
var/obj/structure/hololadder/wayout
|
||||
if(isnull(current_avatar) || current_avatar.stat != CONSCIOUS) // We need a viable avatar
|
||||
wayout = server.generate_hololadder()
|
||||
if(isnull(wayout))
|
||||
balloon_alert(neo, "out of bandwidth!")
|
||||
return
|
||||
current_avatar = server.generate_avatar(wayout, netsuit)
|
||||
avatar_ref = WEAKREF(current_avatar)
|
||||
server.stock_gear(current_avatar, neo)
|
||||
|
||||
neo.set_static_vision(3 SECONDS)
|
||||
protect_occupant(occupant)
|
||||
if(!do_after(neo, 2 SECONDS, src))
|
||||
return
|
||||
|
||||
// Very invalid
|
||||
if(QDELETED(neo) || QDELETED(current_avatar) || QDELETED(src))
|
||||
return
|
||||
|
||||
// Invalid
|
||||
if(occupant != neo || isnull(neo.mind) || neo.stat == DEAD || current_avatar.stat == DEAD)
|
||||
return
|
||||
|
||||
current_avatar.AddComponent( \
|
||||
/datum/component/avatar_connection, \
|
||||
old_mind = neo.mind, \
|
||||
old_body = neo, \
|
||||
server = server, \
|
||||
pod = src, \
|
||||
help_text = generated_domain.help_text, \
|
||||
)
|
||||
|
||||
connected = TRUE
|
||||
|
||||
/// Finds a server and sets the server_ref
|
||||
/obj/machinery/netpod/proc/find_server()
|
||||
var/obj/machinery/quantum_server/server = server_ref?.resolve()
|
||||
if(server)
|
||||
return server
|
||||
|
||||
server = locate(/obj/machinery/quantum_server) in oview(4, src)
|
||||
if(isnull(server))
|
||||
return
|
||||
|
||||
server_ref = WEAKREF(server)
|
||||
RegisterSignal(server, COMSIG_BITRUNNER_SERVER_UPGRADED, PROC_REF(on_server_upgraded), override = TRUE)
|
||||
RegisterSignal(server, COMSIG_BITRUNNER_DOMAIN_COMPLETE, PROC_REF(on_domain_complete), override = TRUE)
|
||||
|
||||
return server
|
||||
|
||||
/// Creates a list of outfit entries for the UI.
|
||||
/obj/machinery/netpod/proc/make_outfit_collection(identifier, list/outfit_list)
|
||||
var/list/collection = list(
|
||||
"name" = identifier,
|
||||
"outfits" = list()
|
||||
)
|
||||
|
||||
for(var/path as anything in outfit_list)
|
||||
var/datum/outfit/outfit = path
|
||||
|
||||
var/outfit_name = initial(outfit.name)
|
||||
if(findtext(outfit_name, "(") != 0 || findtext(outfit_name, "-") != 0) // No special variants please
|
||||
continue
|
||||
|
||||
collection["outfits"] += list(list("path" = path, "name" = outfit_name))
|
||||
|
||||
return list(collection)
|
||||
|
||||
/// Machine has been broken - handles signals and reverting sprites
|
||||
/obj/machinery/netpod/proc/on_broken(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!state_open)
|
||||
open_machine()
|
||||
|
||||
if(occupant)
|
||||
unprotect_and_signal()
|
||||
|
||||
/// Puts points on the current occupant's card account
|
||||
/obj/machinery/netpod/proc/on_domain_complete(datum/source, atom/movable/crate, reward_points)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(isnull(occupant) || !connected || !iscarbon(occupant))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/player = occupant
|
||||
|
||||
var/datum/bank_account/account = player.get_bank_account()
|
||||
if(isnull(account))
|
||||
return
|
||||
|
||||
account.bitrunning_points += reward_points * 100
|
||||
|
||||
/obj/machinery/netpod/proc/on_examine(datum/source, mob/examiner, list/examine_text)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(isnull(occupant))
|
||||
examine_text += span_infoplain("It is currently unoccupied.")
|
||||
return
|
||||
|
||||
examine_text += span_infoplain("It is currently occupied by [occupant].")
|
||||
examine_text += span_notice("It can be pried open with a crowbar, but its safety mechanisms will alert the occupant.")
|
||||
|
||||
/// On unbuckle or break, make sure the occupant ref is null
|
||||
/obj/machinery/netpod/proc/unprotect_and_signal()
|
||||
unprotect_occupant(occupant)
|
||||
SEND_SIGNAL(src, COMSIG_BITRUNNER_SEVER_AVATAR, src)
|
||||
|
||||
/// When the server is upgraded, drops brain damage a little
|
||||
/obj/machinery/netpod/proc/on_server_upgraded(datum/source, servo_rating)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
disconnect_damage = BASE_DISCONNECT_DAMAGE * (1 - servo_rating)
|
||||
|
||||
/// Checks the integrity, alerts occupants
|
||||
/obj/machinery/netpod/proc/on_take_damage(datum/source, damage_amount)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(isnull(occupant))
|
||||
return
|
||||
|
||||
var/total = max_integrity - damage_amount
|
||||
var/integrity = (atom_integrity / total) * 100
|
||||
if(integrity > 50)
|
||||
return
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_BITRUNNER_NETPOD_INTEGRITY)
|
||||
|
||||
/// Puts the occupant in netpod stasis, basically short-circuiting environmental conditions
|
||||
/obj/machinery/netpod/proc/protect_occupant(mob/living/target)
|
||||
if(target != occupant)
|
||||
return
|
||||
|
||||
target.AddComponent(/datum/component/netpod_healing, \
|
||||
brute_heal = 4, \
|
||||
burn_heal = 4, \
|
||||
toxin_heal = 4, \
|
||||
clone_heal = 4, \
|
||||
blood_heal = 4, \
|
||||
)
|
||||
|
||||
target.playsound_local(src, 'sound/effects/submerge.ogg', 20, TRUE)
|
||||
target.extinguish_mob()
|
||||
update_use_power(ACTIVE_POWER_USE)
|
||||
|
||||
/// Removes the occupant from netpod stasis
|
||||
/obj/machinery/netpod/proc/unprotect_occupant(mob/living/target)
|
||||
var/datum/component/netpod_healing/healing_eff = target?.GetComponent(/datum/component/netpod_healing)
|
||||
if(healing_eff)
|
||||
qdel(healing_eff)
|
||||
|
||||
update_use_power(IDLE_POWER_USE)
|
||||
|
||||
/// Resolves a path to an outfit.
|
||||
/obj/machinery/netpod/proc/resolve_outfit(text)
|
||||
var/path = text2path(text)
|
||||
if(ispath(path, /datum/outfit))
|
||||
return path
|
||||
|
||||
/// Closes the machine without shoving in an occupant
|
||||
/obj/machinery/netpod/proc/shut_pod()
|
||||
state_open = FALSE
|
||||
playsound(src, 'sound/machines/tramclose.ogg', 60, TRUE, frequency = 65000)
|
||||
flick("[base_icon_state]_closing", src)
|
||||
set_density(TRUE)
|
||||
|
||||
update_appearance()
|
||||
|
||||
#undef BASE_DISCONNECT_DAMAGE
|
||||
@@ -0,0 +1,110 @@
|
||||
/obj/machinery/computer/quantum_console
|
||||
name = "quantum console"
|
||||
|
||||
circuit = /obj/item/circuitboard/computer/quantum_console
|
||||
icon_keyboard = "mining"
|
||||
icon_screen = "bitrunning"
|
||||
req_access = list(ACCESS_MINING)
|
||||
/// The server this console is connected to.
|
||||
var/datum/weakref/server_ref
|
||||
|
||||
/obj/machinery/computer/quantum_console/Initialize(mapload, obj/item/circuitboard/circuit)
|
||||
. = ..()
|
||||
desc = "Even in the distant year [CURRENT_STATION_YEAR], Nanostrasen is still using REST APIs. How grim."
|
||||
|
||||
return INITIALIZE_HINT_LATELOAD
|
||||
|
||||
/obj/machinery/computer/quantum_console/LateInitialize()
|
||||
. = ..()
|
||||
|
||||
if(isnull(server_ref))
|
||||
find_server()
|
||||
|
||||
/obj/machinery/computer/quantum_console/ui_interact(mob/user, datum/tgui/ui)
|
||||
. = ..()
|
||||
|
||||
if(!is_operational)
|
||||
return
|
||||
|
||||
if(isnull(server_ref))
|
||||
find_server()
|
||||
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "QuantumConsole")
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/quantum_console/ui_data()
|
||||
var/list/data = list()
|
||||
|
||||
var/obj/machinery/quantum_server/server = find_server()
|
||||
if(isnull(server))
|
||||
data["connected"] = FALSE
|
||||
return data
|
||||
|
||||
data["connected"] = TRUE
|
||||
data["generated_domain"] = server.generated_domain?.key
|
||||
data["occupants"] = length(server.avatar_connection_refs)
|
||||
data["points"] = server.points
|
||||
data["randomized"] = server.domain_randomized
|
||||
data["ready"] = server.is_ready && server.is_operational
|
||||
data["scanner_tier"] = server.scanner_tier
|
||||
data["retries_left"] = length(server.exit_turfs) - server.retries_spent
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/quantum_console/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
var/obj/machinery/quantum_server/server = find_server()
|
||||
if(isnull(server))
|
||||
return data
|
||||
|
||||
data["available_domains"] = server.get_available_domains()
|
||||
data["avatars"] = server.get_avatar_data()
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/quantum_console/ui_act(action, list/params, datum/tgui/ui)
|
||||
. = ..()
|
||||
if(.)
|
||||
return TRUE
|
||||
|
||||
var/obj/machinery/quantum_server/server = find_server()
|
||||
if(isnull(server))
|
||||
return FALSE
|
||||
|
||||
switch(action)
|
||||
if("random_domain")
|
||||
var/map_id = server.get_random_domain_id()
|
||||
if(!map_id)
|
||||
return TRUE
|
||||
|
||||
server.cold_boot_map(usr, map_id)
|
||||
return TRUE
|
||||
if("refresh")
|
||||
ui.send_full_update()
|
||||
return TRUE
|
||||
if("set_domain")
|
||||
server.cold_boot_map(usr, params["id"])
|
||||
return TRUE
|
||||
if("stop_domain")
|
||||
server.begin_shutdown(usr)
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/// Attempts to find a quantum server.
|
||||
/obj/machinery/computer/quantum_console/proc/find_server()
|
||||
var/obj/machinery/quantum_server/server = server_ref?.resolve()
|
||||
if(server)
|
||||
return server
|
||||
|
||||
for(var/direction in GLOB.cardinals)
|
||||
var/obj/machinery/quantum_server/nearby_server = locate(/obj/machinery/quantum_server, get_step(src, direction))
|
||||
if(nearby_server)
|
||||
server_ref = WEAKREF(nearby_server)
|
||||
nearby_server.console_ref = WEAKREF(src)
|
||||
return nearby_server
|
||||
|
||||
return
|
||||
Reference in New Issue
Block a user