Files
Bubberstation/code/modules/bitrunning/server/util.dm
T
Jeremiah a3849062b8 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

![netpod](https://github.com/tgstation/tgstation/assets/42397676/d99073a4-2438-4600-83c0-cafb7b3fee55)

Server loaded

![](https://cdn.discordapp.com/attachments/1131433451841662996/1135304774976278759/dreamseeker_N14j6dwLcK.gif)

Server cooldown

![](https://cdn.discordapp.com/attachments/1131433451841662996/1135304775945179217/dreamseeker_NkIwWLJZma.gif)

the quantum console UI
![Screenshot 2023-08-05
105742](https://github.com/tgstation/tgstation/assets/42397676/3a45feaf-8c80-46b2-81c9-355932d1b014)

Cyber police antag page
![Screenshot 2023-08-16
205303](https://github.com/tgstation/tgstation/assets/42397676/fc28bcdd-2a2a-487b-927c-904f224c1b89)

A safehouse

![image](https://github.com/tgstation/tgstation/assets/42397676/c22ac115-4e00-432a-aeeb-b6afdb1ef750)

Domain info page, every domain gets this (and sometimes help text)
![Screenshot 2023-08-04
141859](https://github.com/tgstation/tgstation/assets/42397676/ba9ed6d9-a318-4466-b246-d2da0fa05676)

Me getting steamrolled in one of the missions

![syndicant](https://github.com/tgstation/tgstation/assets/42397676/3eb3099a-f9b2-4431-854d-50d8cad9b7f0)

Ghost roles getting notified that server is kicking them out
![Screenshot 2023-08-04
135454](https://github.com/tgstation/tgstation/assets/42397676/edab916c-6255-4b83-b2e7-155df2f03aab)

Players enjoying the new combat missions
![Screenshot 2023-08-05
005727](https://github.com/tgstation/tgstation/assets/42397676/e302a66f-610d-4fe1-82e0-7c8aec3913ea)

Players exploring some of the virtual maps
![Screenshot 2023-08-06
220919](https://github.com/tgstation/tgstation/assets/42397676/75a92a0b-6aa1-4bac-8fd1-c9fb47c955da)

(Not part of the PR, but)
![Screenshot 2023-08-06
221527](https://github.com/tgstation/tgstation/assets/42397676/012475ec-bfa5-4fd3-9dcb-31d222bb7bef)

New bitrunner vendor

![dreamseeker_V62h2BGdEl](https://github.com/tgstation/tgstation/assets/42397676/37ca8f69-f75e-45c9-b324-e6b31696c7b7)

</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>
2023-09-23 11:14:12 +02:00

142 lines
5.1 KiB
Plaintext

#define REDACTED "???"
#define MAX_DISTANCE 4 // How far crates can spawn from the server
/// Resets the cooldown state and updates icons
/obj/machinery/quantum_server/proc/cool_off()
is_ready = TRUE
update_appearance()
/// Attempts to connect to a quantum console
/obj/machinery/quantum_server/proc/find_console()
var/obj/machinery/computer/quantum_console/console = console_ref?.resolve()
if(console)
return console
for(var/direction in GLOB.cardinals)
var/obj/machinery/computer/quantum_console/nearby_console = locate(/obj/machinery/computer/quantum_console, get_step(src, direction))
if(nearby_console)
console_ref = WEAKREF(nearby_console)
nearby_console.server_ref = WEAKREF(src)
return nearby_console
/// Compiles a list of available domains.
/obj/machinery/quantum_server/proc/get_available_domains()
var/list/levels = list()
for(var/datum/lazy_template/virtual_domain/domain as anything in available_domains)
if(initial(domain.test_only))
continue
var/can_view = initial(domain.difficulty) < scanner_tier && initial(domain.cost) <= points + 5
var/can_view_reward = initial(domain.difficulty) < (scanner_tier + 1) && initial(domain.cost) <= points + 3
levels += list(list(
"cost" = initial(domain.cost),
"desc" = can_view ? initial(domain.desc) : "Limited scanning capabilities. Cannot infer domain details.",
"difficulty" = initial(domain.difficulty),
"id" = initial(domain.key),
"name" = can_view ? initial(domain.name) : REDACTED,
"reward" = can_view_reward ? initial(domain.reward_points) : REDACTED,
))
return levels
/// If there are hosted minds, attempts to get a list of their current virtual bodies w/ vitals
/obj/machinery/quantum_server/proc/get_avatar_data()
var/list/hosted_avatars = list()
for(var/datum/weakref/avatar_ref in avatar_connection_refs)
var/datum/component/avatar_connection/connection = avatar_ref.resolve()
if(isnull(connection))
avatar_connection_refs.Remove(connection)
continue
var/mob/living/creature = connection.parent
var/mob/living/pilot = connection.old_body_ref?.resolve()
hosted_avatars += list(list(
"health" = creature.health,
"name" = creature.name,
"pilot" = pilot,
"brute" = creature.get_damage_amount(BRUTE),
"burn" = creature.get_damage_amount(BURN),
"tox" = creature.get_damage_amount(TOX),
"oxy" = creature.get_damage_amount(OXY),
))
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"]
/// 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()
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)
return shuffle(mutation_candidate_refs)
/// Locates any turfs with crate out landmarks
/obj/machinery/quantum_server/proc/locate_receive_turfs()
for(var/obj/effect/landmark/bitrunning/station_reward_spawn/spawner in GLOB.landmarks_list)
if(IN_GIVEN_RANGE(src, spawner, MAX_DISTANCE))
receive_turfs += get_turf(spawner)
qdel(spawner)
return length(receive_turfs) > 0
/// 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)
var/mob/living/baddie = baddie_ref.resolve()
if(isnull(baddie) || baddie.stat >= UNCONSCIOUS || isnull(baddie.mind))
continue
baddie.throw_alert(
ALERT_BITRUNNER_RESET,
/atom/movable/screen/alert/bitrunning/qserver_threat_deletion,
new_master = src,
)
to_chat(baddie, span_userdanger("You have been flagged for deletion! Thank you for your service."))
/// Do some magic teleport sparks
/obj/machinery/quantum_server/proc/spark_at_location(obj/crate)
playsound(crate, 'sound/magic/blink.ogg', 50, TRUE)
var/datum/effect_system/spark_spread/quantum/sparks = new()
sparks.set_up(5, 1, get_turf(crate))
sparks.start()
#undef REDACTED
#undef MAX_DISTANCE