mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 20:48:56 +01:00
The Spectre-Meter App, also a bootleg data disk item for the black market. (#80188)
## About The Pull Request This PR adds in a new app that scans the nearby area for "spookiness" (e.g. presence of ghosts, mobs with the spirit biotype, objects made with hauntium or containing hauntium). A bit clunky by all means. It's a maintenance app, and as such is more often found in the rare maintenance computer disks, or downloadable from emagged PDAs (IIRC), or perhaps the black market item which I've also added here as well, that might contain it amongst other things. Oh, if you also have the camera app, it'll let you take pictures of ghosts like the 'camera obscura' does. Oh, and there's also a maintenance version of the arcade program too; just , like, lazier and easier. ## Why It's Good For The Game Mostly a shower thought, 'cause I felt the idea maintenance disks to be quite interesting yet lackluster, almost too niche. As for the remote thought of using the app for validhunting, it isn't something you can reliably get every and every other round, and if someone's got enough ghosts circling them, chances are they're some big, loud antag or doing something so cheeky, that they kinda deserve it. Also, yeah, more black market stuff. Except for the misc section, it's pretty lacking in uniqueness. Screenshot of the UI, taken at the distance of one tile from a revenant:  ## Changelog 🆑 add: The Spectre-Meter modular computer app. A little, amatuerishly coded app that, as the name implies, scan an area for spectral presence. It can be found amongst other apps in maintenance computer disks. add: An easier, lazier version of the Arcade app, also found in maintenance. add: Black market computer disks, which contains programs not readily available to the average assistant. /🆑 --------- Co-authored-by: Jacquerel <hnevard@gmail.com>
This commit is contained in:
@@ -640,9 +640,9 @@
|
||||
return SSmodular_computers.add_log("[src]: [text]")
|
||||
|
||||
/obj/item/modular_computer/proc/close_all_programs()
|
||||
active_program = null
|
||||
active_program?.kill_program()
|
||||
for(var/datum/computer_file/program/idle as anything in idle_threads)
|
||||
idle_threads.Remove(idle)
|
||||
idle.kill_program()
|
||||
|
||||
/obj/item/modular_computer/proc/shutdown_computer(loud = TRUE)
|
||||
close_all_programs()
|
||||
|
||||
@@ -14,6 +14,14 @@
|
||||
/obj/item/computer_disk/maintenance/modsuit_control
|
||||
starting_programs = list(/datum/computer_file/program/maintenance/modsuit_control)
|
||||
|
||||
///Returns A 'spookiness' value based on the number of ghastly creature and hauntium and their distance from the PC.
|
||||
/obj/item/computer_disk/maintenance/spectre_meter
|
||||
starting_programs = list(/datum/computer_file/program/maintenance/spectre_meter)
|
||||
|
||||
///A version of the arcade program with less HP/MP for the enemy and more for the player
|
||||
/obj/item/computer_disk/maintenance/arcade
|
||||
starting_programs = list(/datum/computer_file/program/arcade/eazy)
|
||||
|
||||
/obj/item/computer_disk/maintenance/theme/Initialize(mapload)
|
||||
starting_programs = list(pick(subtypesof(/datum/computer_file/program/maintenance/theme)))
|
||||
return ..()
|
||||
|
||||
@@ -9,3 +9,30 @@
|
||||
|
||||
/obj/item/computer_disk/syndicate/contractor
|
||||
starting_programs = list(/datum/computer_file/program/contract_uplink)
|
||||
|
||||
/obj/item/computer_disk/black_market
|
||||
desc = "Removable disk used to store data. This one has a smudged piece of paper glued to it, reading \"PC softwarez\"."
|
||||
|
||||
/obj/item/computer_disk/black_market/Initialize(mapload)
|
||||
icon_state = "datadisk[rand(0, 10)]"
|
||||
//Populated with programs not found in the verified downloader app or that require access to download (but not to run).
|
||||
var/list/potential_programs = list(
|
||||
/datum/computer_file/program/arcade/eazy,
|
||||
/datum/computer_file/program/radar/lifeline,
|
||||
/datum/computer_file/program/radar/custodial_locator,
|
||||
/datum/computer_file/program/supermatter_monitor,
|
||||
/datum/computer_file/program/newscaster,
|
||||
/datum/computer_file/program/secureye,
|
||||
/datum/computer_file/program/crew_manifest,
|
||||
/datum/computer_file/program/status,
|
||||
)
|
||||
potential_programs += subtypesof(/datum/computer_file/program/maintenance) - /datum/computer_file/program/maintenance/theme
|
||||
|
||||
var/total_programs_size = 0
|
||||
for(var/i in 1 to rand(2, 4))
|
||||
var/datum/computer_file/program/to_add = pick_n_take(potential_programs)
|
||||
total_programs_size += initial(to_add.size)
|
||||
starting_programs += to_add
|
||||
///Make sure the disk has enough space for all the programs
|
||||
max_capacity = max(total_programs_size, max_capacity)
|
||||
return ..()
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
///The default amount a program should take in cell use.
|
||||
#define PROGRAM_BASIC_CELL_USE 15
|
||||
|
||||
// /program/ files are executable programs that do things.
|
||||
/datum/computer_file/program
|
||||
filetype = "PRG"
|
||||
@@ -190,8 +187,8 @@
|
||||
|
||||
if(src == computer.active_program)
|
||||
computer.active_program = null
|
||||
if(computer.enabled)
|
||||
computer.update_tablet_open_uis(user)
|
||||
if(!QDELETED(computer) && computer.enabled)
|
||||
INVOKE_ASYNC(computer, TYPE_PROC_REF(/obj/item/modular_computer, update_tablet_open_uis), user)
|
||||
if(src in computer.idle_threads)
|
||||
computer.idle_threads.Remove(src)
|
||||
|
||||
@@ -214,5 +211,3 @@
|
||||
computer.update_tablet_open_uis(usr)
|
||||
computer.update_appearance(UPDATE_ICON)
|
||||
return TRUE
|
||||
|
||||
#undef PROGRAM_BASIC_CELL_USE
|
||||
|
||||
@@ -23,6 +23,20 @@
|
||||
///Determines which boss image to use on the UI.
|
||||
var/boss_id = 1
|
||||
|
||||
///Lazy version of the arade that can be found in maintenance disks
|
||||
/datum/computer_file/program/arcade/eazy
|
||||
filename = "dsarcadeez"
|
||||
filedesc = "Donksoft Micro Arcade Ez"
|
||||
filetype = "MNT"
|
||||
program_flags = PROGRAM_UNIQUE_COPY
|
||||
extended_desc = "Some sort of fan-made conversion of the classic game 'Outbomb Cuban Pete'. This one has you fight the weaker 'George Melon' instead."
|
||||
boss_hp = 40
|
||||
boss_mp = 10
|
||||
player_hp = 35
|
||||
player_mp = 15
|
||||
heads_up = "Are you a bad enough dude to grief the station?"
|
||||
boss_name = "George Melon"
|
||||
|
||||
/datum/computer_file/program/arcade/proc/game_check(mob/user)
|
||||
sleep(0.5 SECONDS)
|
||||
user?.mind?.adjust_experience(/datum/skill/gaming, 1)
|
||||
@@ -159,9 +173,9 @@
|
||||
return TRUE
|
||||
if("Start_Game")
|
||||
game_active = TRUE
|
||||
boss_hp = 45
|
||||
player_hp = 30
|
||||
player_mp = 10
|
||||
boss_hp = initial(boss_hp)
|
||||
player_hp = initial(player_hp)
|
||||
player_mp = initial(player_mp)
|
||||
heads_up = "You stand before [boss_name]! Prepare for battle!"
|
||||
program_open_overlay = "arcade"
|
||||
boss_id = rand(1,6)
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
if(internal_picture)
|
||||
QDEL_NULL(internal_picture)
|
||||
var/turf/our_turf = get_turf(tapped_atom)
|
||||
var/spooky_camera = locate(/datum/computer_file/program/maintenance/spectre_meter) in computer.stored_files
|
||||
internal_camera.see_ghosts = spooky_camera ? CAMERA_SEE_GHOSTS_BASIC : CAMERA_NO_GHOSTS
|
||||
internal_picture = internal_camera.captureimage(our_turf, user, internal_camera.picture_size_x + 1, internal_camera.picture_size_y + 1)
|
||||
picture_number++
|
||||
computer.save_photo(internal_picture.picture_image)
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/maintenance/modsuit_control/proc/unsync_modsuit(atom/source)
|
||||
SIGNAL_HANDLER
|
||||
UnregisterSignal(controlled_suit, COMSIG_QDELETING)
|
||||
controlled_suit = null
|
||||
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
|
||||
#define SPOOK_VALUE_SAME_TURF_MULT 1.5
|
||||
#define SPOOK_VALUE_LIVING_MULT 6
|
||||
#define SPOOK_VALUE_DEF_MOB 10
|
||||
#define SPOOK_VALUE_ICON_STATE_MAX 120
|
||||
#define SPOOK_VALUE_SEGMENT 15
|
||||
|
||||
/datum/computer_file/program/maintenance/spectre_meter
|
||||
filename = "spectre_meter"
|
||||
filedesc = "Spectre-Meter"
|
||||
power_cell_use = PROGRAM_BASIC_CELL_USE * 2
|
||||
downloader_category = PROGRAM_CATEGORY_EQUIPMENT
|
||||
extended_desc = "A program used to somehow detect nearby spectral presence. Combine with the camera app to take photos of ghosts."
|
||||
size = 7
|
||||
can_run_on_flags = PROGRAM_LAPTOP|PROGRAM_PDA
|
||||
tgui_id = "NtosSpectreMeter"
|
||||
program_icon = "ghost"
|
||||
program_open_overlay = "spectre_meter_0"
|
||||
/// The cooldown for manual scans
|
||||
COOLDOWN_DECLARE(manual_scan_cd)
|
||||
/// Whether the automatic scan mode is active or not
|
||||
var/auto_mode = FALSE
|
||||
/// The value reported by the last scan.
|
||||
var/last_spook_value = 0
|
||||
var/datum/looping_sound/spectre_meter/soundloop
|
||||
|
||||
/datum/computer_file/program/maintenance/spectre_meter/on_start(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
soundloop = new()
|
||||
|
||||
/datum/computer_file/program/maintenance/spectre_meter/kill_program()
|
||||
QDEL_NULL(soundloop)
|
||||
auto_mode = FALSE
|
||||
last_spook_value = 0
|
||||
program_open_overlay = "spectre_meter_0"
|
||||
power_cell_use = PROGRAM_BASIC_CELL_USE
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
return ..()
|
||||
|
||||
/datum/computer_file/program/maintenance/spectre_meter/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["spook_value"] = last_spook_value
|
||||
data["auto_mode"] = auto_mode
|
||||
data["on_cooldown"] = !COOLDOWN_FINISHED(src, manual_scan_cd)
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/maintenance/spectre_meter/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
switch(action)
|
||||
if("manual_scan")
|
||||
if(COOLDOWN_FINISHED(src, manual_scan_cd))
|
||||
INVOKE_ASYNC(src, PROC_REF(scan_surroundings))
|
||||
COOLDOWN_START(src, manual_scan_cd, 2 SECONDS)
|
||||
playsound(computer, 'sound/effects/ping_hit.ogg', vol = 40, vary = TRUE)
|
||||
return TRUE
|
||||
if("toggle_mode")
|
||||
auto_mode = !auto_mode
|
||||
if(auto_mode)
|
||||
///We want SSprocess. It fires twice as fast than the standard SSobjs used by [computer_file/program/process_tick]
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
soundloop.start(computer)
|
||||
else
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
soundloop.stop(TRUE)
|
||||
power_cell_use = auto_mode ? PROGRAM_BASIC_CELL_USE * 3 : PROGRAM_BASIC_CELL_USE
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/maintenance/spectre_meter/process(seconds_per_tick)
|
||||
if(auto_mode)
|
||||
INVOKE_ASYNC(src, PROC_REF(scan_surroundings))
|
||||
|
||||
///Return the "spook level" of the area the computer is in.
|
||||
/datum/computer_file/program/maintenance/spectre_meter/proc/scan_surroundings()
|
||||
var/spook_value = 0
|
||||
var/turf/turf = get_turf(computer)
|
||||
|
||||
for(var/atom/atom as anything in range(5, turf))
|
||||
var/spook_amount = 0
|
||||
if(ismob(atom))
|
||||
///ghastly mobs count toward spookiness more than observers.
|
||||
var/spook_value_mult = 0
|
||||
if(isliving(atom))
|
||||
var/mob/living/living = atom
|
||||
if(living.mob_biotypes & MOB_SPIRIT)
|
||||
spook_value_mult = SPOOK_VALUE_LIVING_MULT
|
||||
else if(isobserver(atom))
|
||||
spook_value_mult = 1
|
||||
spook_amount += SPOOK_VALUE_DEF_MOB * spook_value_mult
|
||||
var/list/materials = atom.has_material_type(/datum/material/hauntium)
|
||||
if(materials)
|
||||
spook_amount += materials[/datum/material/hauntium]/SHEET_MATERIAL_AMOUNT
|
||||
spook_amount += atom.reagents?.get_reagent_amount(/datum/reagent/hauntium)/20
|
||||
if(!spook_amount)
|
||||
continue
|
||||
if(atom.loc == turf)
|
||||
spook_amount *= SPOOK_VALUE_SAME_TURF_MULT
|
||||
spook_value += spook_amount/max(get_dist(turf, atom), 1)
|
||||
CHECK_TICK
|
||||
|
||||
soundloop.last_spook_value = last_spook_value = round(spook_value)
|
||||
var/old_open_overlay = program_open_overlay
|
||||
program_open_overlay = "spectre_meter_[min(FLOOR(last_spook_value, SPOOK_VALUE_SEGMENT), SPOOK_VALUE_ICON_STATE_MAX)]"
|
||||
if(program_open_overlay != old_open_overlay)
|
||||
computer.update_appearance(UPDATE_OVERLAYS)
|
||||
|
||||
/datum/looping_sound/spectre_meter
|
||||
mid_sounds = /datum/looping_sound/geiger::mid_sounds
|
||||
mid_length = 2
|
||||
volume = 12
|
||||
var/last_spook_value = 0
|
||||
|
||||
/datum/looping_sound/spectre_meter/get_sound()
|
||||
var/index = 1
|
||||
switch(last_spook_value)
|
||||
if(0 to 14)
|
||||
return null
|
||||
if(14 to 40)
|
||||
index = 1
|
||||
if(40 to 65)
|
||||
index = 2
|
||||
if(65 to 90)
|
||||
index = 3
|
||||
else
|
||||
index = 4
|
||||
return ..(mid_sounds[index])
|
||||
|
||||
/datum/looping_sound/spectre_meter/stop(null_parent = FALSE)
|
||||
last_spook_value = 0
|
||||
return ..()
|
||||
|
||||
#undef SPOOK_VALUE_SAME_TURF_MULT
|
||||
#undef SPOOK_VALUE_LIVING_MULT
|
||||
#undef SPOOK_VALUE_DEF_MOB
|
||||
#undef SPOOK_VALUE_ICON_STATE_MAX
|
||||
#undef SPOOK_VALUE_SEGMENT
|
||||
Reference in New Issue
Block a user