mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-25 22:19:30 +01:00
Bitrunners can broadcast their bitruns to the crew via Entertainment Monitors (#82218)
## About The Pull Request  Bitrunners are now equipped with body cameras. The Quantum Console now holds a switch which you can toggle on to broadcast your body camera footage to the station's Entertainment Monitors. I also cleaned up some balloon alerts ## Why It's Good For The Game I did a gimmick with a bunch of bitrunners and thought it was lame I couldn't watch them as they did the bitrunning part. So here we are. I think it is pretty neat and fun, and also kinda thematic, since it is VR after all. ## Changelog 🆑 Melbert add: Bitrunners can now broadcast their Bitruns to the station's Entertainment Monitors. /🆑
This commit is contained in:
@@ -23,3 +23,6 @@
|
||||
#define BITRUNNER_DIFFICULTY_MEDIUM 2
|
||||
/// Red with skull. I am trying to kill bitrunners.
|
||||
#define BITRUNNER_DIFFICULTY_HIGH 3
|
||||
|
||||
/// Camera network bitrunner bodycams are on
|
||||
#define BITRUNNER_CAMERA_NET "bitrunner"
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/// Simple component to integrate a bodycam into a mob
|
||||
/datum/component/simple_bodycam
|
||||
/// The actual camera, in our mob's contents
|
||||
VAR_PRIVATE/obj/machinery/camera/bodycam
|
||||
/// How fast we update
|
||||
var/camera_update_time = 0.5 SECONDS
|
||||
|
||||
/datum/component/simple_bodycam/Initialize(
|
||||
camera_name = "bodycam",
|
||||
c_tag = capitalize(camera_name),
|
||||
network = "ss13",
|
||||
emp_proof = FALSE,
|
||||
camera_update_time = 0.5 SECONDS,
|
||||
)
|
||||
if(!isliving(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
src.camera_update_time = camera_update_time
|
||||
|
||||
bodycam = new(parent)
|
||||
bodycam.network = list(network)
|
||||
bodycam.name = camera_name
|
||||
bodycam.c_tag = c_tag
|
||||
if(emp_proof)
|
||||
bodycam.AddElement(/datum/element/empprotection, EMP_PROTECT_ALL)
|
||||
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(update_cam))
|
||||
RegisterSignal(parent, COMSIG_ATOM_DIR_CHANGE, PROC_REF(rotate_cam))
|
||||
RegisterSignals(bodycam, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED), PROC_REF(camera_gone))
|
||||
|
||||
do_update_cam()
|
||||
|
||||
/datum/component/simple_bodycam/Destroy()
|
||||
if(QDELETED(bodycam))
|
||||
bodycam = null
|
||||
else
|
||||
QDEL_NULL(bodycam)
|
||||
return ..()
|
||||
|
||||
/datum/component/simple_bodycam/proc/update_cam(datum/source, atom/old_loc, ...)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(get_turf(old_loc) != get_turf(parent))
|
||||
do_update_cam()
|
||||
|
||||
/datum/component/simple_bodycam/proc/do_update_cam()
|
||||
GLOB.cameranet.updatePortableCamera(bodycam, camera_update_time)
|
||||
|
||||
/datum/component/simple_bodycam/proc/rotate_cam(datum/source, old_dir, new_dir)
|
||||
SIGNAL_HANDLER
|
||||
// I don't actually think cameras care about dir but just in case
|
||||
bodycam.setDir(new_dir)
|
||||
|
||||
/datum/component/simple_bodycam/proc/camera_gone(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
qdel(src)
|
||||
@@ -87,6 +87,53 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/security/telescreen/entertai
|
||||
|
||||
notify(network.len, announcement)
|
||||
|
||||
/**
|
||||
* Adds a camera network to all entertainment monitors.
|
||||
*
|
||||
* * camera_net - The camera network ID to add to the monitors.
|
||||
* * announcement - Optional, what announcement to make when the show starts.
|
||||
*/
|
||||
/proc/start_broadcasting_network(camera_net, announcement)
|
||||
for(var/obj/machinery/computer/security/telescreen/entertainment/tv as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/computer/security/telescreen/entertainment))
|
||||
tv.update_shows(
|
||||
is_show_active = TRUE,
|
||||
tv_show_id = camera_net,
|
||||
announcement = announcement,
|
||||
)
|
||||
|
||||
/**
|
||||
* Removes a camera network from all entertainment monitors.
|
||||
*
|
||||
* * camera_net - The camera network ID to remove from the monitors.
|
||||
* * announcement - Optional, what announcement to make when the show ends.
|
||||
*/
|
||||
/proc/stop_broadcasting_network(camera_net, announcement)
|
||||
for(var/obj/machinery/computer/security/telescreen/entertainment/tv as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/computer/security/telescreen/entertainment))
|
||||
tv.update_shows(
|
||||
is_show_active = FALSE,
|
||||
tv_show_id = camera_net,
|
||||
announcement = announcement,
|
||||
)
|
||||
|
||||
/**
|
||||
* Sets the camera network status on all entertainment monitors.
|
||||
* A way to force a network to a status if you are unsure of the current state.
|
||||
*
|
||||
* * camera_net - The camera network ID to set on the monitors.
|
||||
* * is_show_active - Whether the show is active or not.
|
||||
* * announcement - Optional, what announcement to make.
|
||||
* Note this announcement will be made regardless of the current state of the show:
|
||||
* This means if it's currently on and you set it to on, the announcement will still be made.
|
||||
* Likewise, there's no way to differentiate off -> on and on -> off, unless you handle that yourself.
|
||||
*/
|
||||
/proc/set_network_broadcast_status(camera_net, is_show_active, announcement)
|
||||
for(var/obj/machinery/computer/security/telescreen/entertainment/tv as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/computer/security/telescreen/entertainment))
|
||||
tv.update_shows(
|
||||
is_show_active = is_show_active,
|
||||
tv_show_id = camera_net,
|
||||
announcement = announcement,
|
||||
)
|
||||
|
||||
/obj/machinery/computer/security/telescreen/rd
|
||||
name = "\improper Research Director's telescreen"
|
||||
desc = "Used for watching the AI and the RD's goons from the safety of his office."
|
||||
@@ -270,5 +317,4 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/security/telescreen/entertai
|
||||
is_show_active = !is_show_active
|
||||
say("The [tv_show_name] show has [is_show_active ? "begun" : "ended"]")
|
||||
var/announcement = is_show_active ? pick(tv_starters) : pick(tv_enders)
|
||||
for(var/obj/machinery/computer/security/telescreen/entertainment/tv as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/computer/security/telescreen/entertainment))
|
||||
tv.update_shows(is_show_active, tv_network_id, announcement)
|
||||
set_network_broadcast_status(tv_network_id, is_show_active, announcement)
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
data["ready"] = server.is_ready && server.is_operational
|
||||
data["scanner_tier"] = server.scanner_tier
|
||||
data["retries_left"] = length(server.exit_turfs) - server.retries_spent
|
||||
data["broadcasting"] = server.broadcasting
|
||||
data["broadcasting_on_cd"] = !COOLDOWN_FINISHED(server, broadcast_toggle_cd)
|
||||
|
||||
return data
|
||||
|
||||
@@ -83,6 +85,9 @@
|
||||
if("stop_domain")
|
||||
server.begin_shutdown(usr)
|
||||
return TRUE
|
||||
if("broadcast")
|
||||
server.toggle_broadcast()
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -44,6 +44,10 @@
|
||||
var/threat = 0
|
||||
/// The turfs we can place a hololadder on.
|
||||
var/turf/exit_turfs = list()
|
||||
/// Determines if we broadcast to entertainment monitors or not
|
||||
var/broadcasting = FALSE
|
||||
/// Cooldown between being able to toggle broadcasting
|
||||
COOLDOWN_DECLARE(broadcast_toggle_cd)
|
||||
|
||||
/obj/machinery/quantum_server/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
return FALSE
|
||||
|
||||
if(isnull(map_key))
|
||||
balloon_alert_to_viewers("no domain specified.")
|
||||
balloon_alert_to_viewers("no domain specified!")
|
||||
return FALSE
|
||||
|
||||
if(generated_domain)
|
||||
balloon_alert_to_viewers("stop the current domain first.")
|
||||
balloon_alert_to_viewers("stop the current domain first!")
|
||||
return FALSE
|
||||
|
||||
if(length(avatar_connection_refs))
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
/// If any one of these fail, it reverts the entire process
|
||||
if(!load_domain(map_key) || !load_map_items() || !load_mob_segments())
|
||||
balloon_alert_to_viewers("initialization failed.")
|
||||
balloon_alert_to_viewers("initialization failed!")
|
||||
scrub_vdom()
|
||||
is_ready = TRUE
|
||||
return FALSE
|
||||
@@ -63,6 +63,9 @@
|
||||
update_use_power(ACTIVE_POWER_USE)
|
||||
update_appearance()
|
||||
|
||||
if(broadcasting)
|
||||
start_broadcasting_network(BITRUNNER_CAMERA_NET)
|
||||
|
||||
return TRUE
|
||||
|
||||
/// Initializes a new domain if the given key is valid and the user has enough points
|
||||
@@ -147,6 +150,8 @@
|
||||
domain_randomized = FALSE
|
||||
retries_spent = 0
|
||||
|
||||
stop_broadcasting_network(BITRUNNER_CAMERA_NET)
|
||||
|
||||
/// Tries to clean up everything in the domain
|
||||
/obj/machinery/quantum_server/proc/scrub_vdom()
|
||||
sever_connections() /// just in case someone's connected
|
||||
|
||||
@@ -83,6 +83,13 @@
|
||||
|
||||
SSid_access.apply_trim_to_card(outfit_id, /datum/id_trim/bit_avatar)
|
||||
|
||||
avatar.AddComponent( \
|
||||
/datum/component/simple_bodycam, \
|
||||
camera_name = "bitrunner bodycam", \
|
||||
c_tag = "Avatar [avatar.real_name]", \
|
||||
network = BITRUNNER_CAMERA_NET, \
|
||||
emp_proof = TRUE, \
|
||||
)
|
||||
return avatar
|
||||
|
||||
/// Generates a new hololadder for the bitrunner. Effectively a respawn attempt.
|
||||
|
||||
@@ -98,3 +98,17 @@
|
||||
return chosen_turf
|
||||
|
||||
#undef MAX_DISTANCE
|
||||
|
||||
/// Toggles broadcast on and off
|
||||
/obj/machinery/quantum_server/proc/toggle_broadcast()
|
||||
if(!COOLDOWN_FINISHED(src, broadcast_toggle_cd))
|
||||
return FALSE
|
||||
|
||||
broadcasting = !broadcasting
|
||||
|
||||
if(generated_domain)
|
||||
// The cooldown only really matter is we're flipping TVs
|
||||
COOLDOWN_START(src, broadcast_toggle_cd, 5 SECONDS)
|
||||
// And we only flip TVs when there's a domain, because otherwise there's no cams to watch
|
||||
set_network_broadcast_status(BITRUNNER_CAMERA_NET, broadcasting)
|
||||
return TRUE
|
||||
|
||||
@@ -1173,6 +1173,7 @@
|
||||
#include "code\datums\components\shy_in_room.dm"
|
||||
#include "code\datums\components\sign_language.dm"
|
||||
#include "code\datums\components\simple_access.dm"
|
||||
#include "code\datums\components\simple_bodycam.dm"
|
||||
#include "code\datums\components\singularity.dm"
|
||||
#include "code\datums\components\sitcomlaughter.dm"
|
||||
#include "code\datums\components\sizzle.dm"
|
||||
|
||||
@@ -29,6 +29,8 @@ type Data =
|
||||
ready: BooleanLike;
|
||||
retries_left: number;
|
||||
scanner_tier: number;
|
||||
broadcasting: BooleanLike;
|
||||
broadcasting_on_cd: BooleanLike;
|
||||
}
|
||||
| {
|
||||
connected: 0;
|
||||
@@ -111,11 +113,13 @@ const AccessView = (props) => {
|
||||
|
||||
const {
|
||||
available_domains = [],
|
||||
broadcasting,
|
||||
broadcasting_on_cd,
|
||||
generated_domain,
|
||||
ready,
|
||||
occupants,
|
||||
points,
|
||||
randomized,
|
||||
ready,
|
||||
} = data;
|
||||
|
||||
const sorted = available_domains.sort((a, b) => a.cost - b.cost);
|
||||
@@ -139,6 +143,15 @@ const AccessView = (props) => {
|
||||
<Section
|
||||
buttons={
|
||||
<>
|
||||
<Button.Checkbox
|
||||
checked={broadcasting}
|
||||
disabled={broadcasting_on_cd}
|
||||
onClick={() => act('broadcast')}
|
||||
tooltip="Toggles whether you broadcast your
|
||||
bitrun to station Entertainment Monitors."
|
||||
>
|
||||
Broadcast
|
||||
</Button.Checkbox>
|
||||
<Button
|
||||
disabled={
|
||||
!ready || occupants > 0 || points < 1 || !!generated_domain
|
||||
@@ -146,7 +159,8 @@ const AccessView = (props) => {
|
||||
icon="random"
|
||||
onClick={() => act('random_domain')}
|
||||
mr={1}
|
||||
tooltip="Get a random domain for more rewards. Weighted towards your current points. Minimum: 1 point."
|
||||
tooltip="Get a random domain for more rewards.
|
||||
Weighted towards your current points. Minimum: 1 point."
|
||||
>
|
||||
Randomize
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user