mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-09 16:12:17 +00:00
[MIRROR] Rebuild the Destructive Analyzer For Experisci - Part1 (#11816)
Co-authored-by: Will <7099514+Willburd@users.noreply.github.com> Co-authored-by: C.L. <killer65311@gmail.com> Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
a9e8ab2b6d
commit
ef45ecf681
18
bun.lock
18
bun.lock
@@ -9,23 +9,23 @@
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@biomejs/biome": ["@biomejs/biome@2.2.5", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.2.5", "@biomejs/cli-darwin-x64": "2.2.5", "@biomejs/cli-linux-arm64": "2.2.5", "@biomejs/cli-linux-arm64-musl": "2.2.5", "@biomejs/cli-linux-x64": "2.2.5", "@biomejs/cli-linux-x64-musl": "2.2.5", "@biomejs/cli-win32-arm64": "2.2.5", "@biomejs/cli-win32-x64": "2.2.5" }, "bin": { "biome": "bin/biome" } }, "sha512-zcIi+163Rc3HtyHbEO7CjeHq8DjQRs40HsGbW6vx2WI0tg8mYQOPouhvHSyEnCBAorfYNnKdR64/IxO7xQ5faw=="],
|
||||
"@biomejs/biome": ["@biomejs/biome@2.2.6", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.2.6", "@biomejs/cli-darwin-x64": "2.2.6", "@biomejs/cli-linux-arm64": "2.2.6", "@biomejs/cli-linux-arm64-musl": "2.2.6", "@biomejs/cli-linux-x64": "2.2.6", "@biomejs/cli-linux-x64-musl": "2.2.6", "@biomejs/cli-win32-arm64": "2.2.6", "@biomejs/cli-win32-x64": "2.2.6" }, "bin": { "biome": "bin/biome" } }, "sha512-yKTCNGhek0rL5OEW1jbLeZX8LHaM8yk7+3JRGv08my+gkpmtb5dDE+54r2ZjZx0ediFEn1pYBOJSmOdDP9xtFw=="],
|
||||
|
||||
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.2.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MYT+nZ38wEIWVcL5xLyOhYQQ7nlWD0b/4mgATW2c8dvq7R4OQjt/XGXFkXrmtWmQofaIM14L7V8qIz/M+bx5QQ=="],
|
||||
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.2.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-UZPmn3M45CjTYulgcrFJFZv7YmK3pTxTJDrFYlNElT2FNnkkX4fsxjExTSMeWKQYoZjvekpH5cvrYZZlWu3yfA=="],
|
||||
|
||||
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.2.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-FLIEl73fv0R7dI10EnEiZLw+IMz3mWLnF95ASDI0kbx6DDLJjWxE5JxxBfmG+udz1hIDd3fr5wsuP7nwuTRdAg=="],
|
||||
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.2.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-HOUIquhHVgh/jvxyClpwlpl/oeMqntlteL89YqjuFDiZ091P0vhHccwz+8muu3nTyHWM5FQslt+4Jdcd67+xWQ=="],
|
||||
|
||||
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.2.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-5DjiiDfHqGgR2MS9D+AZ8kOfrzTGqLKywn8hoXpXXlJXIECGQ32t+gt/uiS2XyGBM2XQhR6ztUvbjZWeccFMoQ=="],
|
||||
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.2.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-BpGtuMJGN+o8pQjvYsUKZ+4JEErxdSmcRD/JG3mXoWc6zrcA7OkuyGFN1mDggO0Q1n7qXxo/PcupHk8gzijt5g=="],
|
||||
|
||||
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.2.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Ov2wgAFwqDvQiESnu7b9ufD1faRa+40uwrohgBopeY84El2TnBDoMNXx6iuQdreoFGjwW8vH6k68G21EpNERw=="],
|
||||
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.2.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-TjCenQq3N6g1C+5UT3jE1bIiJb5MWQvulpUngTIpFsL4StVAUXucWD0SL9MCW89Tm6awWfeXBbZBAhJwjyFbRQ=="],
|
||||
|
||||
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.2.5", "", { "os": "linux", "cpu": "x64" }, "sha512-fq9meKm1AEXeAWan3uCg6XSP5ObA6F/Ovm89TwaMiy1DNIwdgxPkNwxlXJX8iM6oRbFysYeGnT0OG8diCWb9ew=="],
|
||||
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.2.6", "", { "os": "linux", "cpu": "x64" }, "sha512-1HaM/dpI/1Z68zp8ZdT6EiBq+/O/z97a2AiHMl+VAdv5/ELckFt9EvRb8hDHpk8hUMoz03gXkC7VPXOVtU7faA=="],
|
||||
|
||||
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.2.5", "", { "os": "linux", "cpu": "x64" }, "sha512-AVqLCDb/6K7aPNIcxHaTQj01sl1m989CJIQFQEaiQkGr2EQwyOpaATJ473h+nXDUuAcREhccfRpe/tu+0wu0eQ=="],
|
||||
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.2.6", "", { "os": "linux", "cpu": "x64" }, "sha512-1ZcBux8zVM3JhWN2ZCPaYf0+ogxXG316uaoXJdgoPZcdK/rmRcRY7PqHdAos2ExzvjIdvhQp72UcveI98hgOog=="],
|
||||
|
||||
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.2.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-xaOIad4wBambwJa6mdp1FigYSIF9i7PCqRbvBqtIi9y29QtPVQ13sDGtUnsRoe6SjL10auMzQ6YAe+B3RpZXVg=="],
|
||||
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.2.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-h3A88G8PGM1ryTeZyLlSdfC/gz3e95EJw9BZmA6Po412DRqwqPBa2Y9U+4ZSGUAXCsnSQE00jLV8Pyrh0d+jQw=="],
|
||||
|
||||
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.2.5", "", { "os": "win32", "cpu": "x64" }, "sha512-F/jhuXCssPFAuciMhHKk00xnCAxJRS/pUzVfXYmOMUp//XW7mO6QeCjsjvnm8L4AO/dG2VOB0O+fJPiJ2uXtIw=="],
|
||||
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.2.6", "", { "os": "win32", "cpu": "x64" }, "sha512-yx0CqeOhPjYQ5ZXgPfu8QYkgBhVJyvWe36as7jRuPrKPO5ylVDfwVtPQ+K/mooNTADW0IhxOZm3aPu16dP8yNQ=="],
|
||||
|
||||
"prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
|
||||
}
|
||||
|
||||
@@ -194,6 +194,7 @@
|
||||
#define COMSIG_CLICK_CTRL "ctrl_click"
|
||||
///from base of atom/AltClick(): (/mob)
|
||||
#define COMSIG_CLICK_ALT "alt_click"
|
||||
#define COMPONENT_CANCEL_CLICK_ALT (1<<0)
|
||||
///from base of atom/CtrlShiftClick(/mob)
|
||||
#define COMSIG_CLICK_CTRL_SHIFT "ctrl_shift_click"
|
||||
///from base of atom/MouseDrop(): (/atom/over, /mob/user)
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
///from /obj/machinery/computer/arcade/prizevend(mob/user, prizes = 1)
|
||||
#define COMSIG_ARCADE_PRIZEVEND "arcade_prizevend"
|
||||
///from /obj/machinery/rnd/destructive_analyzer/proc/destroy_item_individual(gain_research_points = FALSE): Runs when the destructive scanner scans a group of objects. (obj/item)
|
||||
#define COMSIG_MACHINERY_DESTRUCTIVE_SCAN "machinery_destructive_scan"
|
||||
|
||||
@@ -398,6 +398,20 @@ GLOBAL_LIST_INIT(item_digestion_blacklist, list(
|
||||
/obj/item/mmi/digital/robot,
|
||||
/obj/item/rig/protean))
|
||||
|
||||
///A list of stuff we do NOT want being deconstructed. Either due to how critical it is (ID/nuke disk) or buggy (holders and paicards)
|
||||
GLOBAL_LIST_INIT(item_deconstruction_blacklist, list(
|
||||
/obj/item/card/id,
|
||||
/obj/item/areaeditor/blueprints,
|
||||
/obj/item/disk/nuclear,
|
||||
/obj/item/perfect_tele_beacon,
|
||||
/obj/item/organ/internal/brain,
|
||||
/obj/item/mmi,
|
||||
/obj/item/rig/protean,
|
||||
/obj/item/holder,
|
||||
/obj/item/paicard,
|
||||
/obj/item/stack/material/cyborg,
|
||||
/obj/item/storage))
|
||||
|
||||
///A list of chemicals that are banned from being obtainable through means that generate chemicals. These chemicals are either lame, annoying, pref-breaking, or OP (This list does NOT include reactions)
|
||||
GLOBAL_LIST_INIT(obtainable_chemical_blacklist, list(
|
||||
REAGENT_ID_ADMINORDRAZINE,
|
||||
|
||||
@@ -303,8 +303,8 @@
|
||||
// if(!user.can_interact_with(src))
|
||||
// return FALSE
|
||||
|
||||
// if(SEND_SIGNAL(src, COMSIG_CLICK_ALT, user) & COMPONENT_CANCEL_CLICK_ALT)
|
||||
// return TRUE
|
||||
if(SEND_SIGNAL(src, COMSIG_CLICK_ALT, user) & COMPONENT_CANCEL_CLICK_ALT)
|
||||
return TRUE
|
||||
|
||||
if(HAS_TRAIT(src, TRAIT_ALT_CLICK_BLOCKER) && !isobserver(user))
|
||||
return TRUE
|
||||
|
||||
@@ -41,7 +41,17 @@ SUBSYSTEM_DEF(research)
|
||||
var/list/techweb_nodes_experimental = list()
|
||||
///path = list(point type = value)
|
||||
var/list/techweb_point_items = list(
|
||||
// /obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_5_POINTS)
|
||||
/obj/item/research_sample/common = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS*0.5),
|
||||
/obj/item/research_sample/uncommon = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS*0.5),
|
||||
/obj/item/research_sample/rare = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS*0.5),
|
||||
/obj/item/research_sample/bluespace = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS*0.5)
|
||||
)
|
||||
///Allows repeated deconstruction of these items for points. These items MUST be in techweb_point_items as well.
|
||||
var/list/techweb_repeatable_items = list(
|
||||
/obj/item/research_sample/common,
|
||||
/obj/item/research_sample/uncommon,
|
||||
/obj/item/research_sample/rare,
|
||||
/obj/item/research_sample/bluespace
|
||||
)
|
||||
var/list/errored_datums = list()
|
||||
///Associated list of all point types that techwebs will have and their respective 'abbreviated' name.
|
||||
|
||||
@@ -111,3 +111,13 @@
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/stock_parts/console_screen = 1)
|
||||
|
||||
/obj/item/circuitboard/destructive_analyzer
|
||||
name = T_BOARD("destructive analyzer")
|
||||
build_path = /obj/machinery/rnd/destructive_analyzer
|
||||
board_type = new /datum/frame/frame_types/machine
|
||||
origin_tech = list(TECH_MAGNET = 2, TECH_ENGINEERING = 2, TECH_DATA = 2)
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/scanning_module = 1,
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/stock_parts/micro_laser = 1)
|
||||
|
||||
@@ -196,3 +196,12 @@
|
||||
RND_CATEGORY_MACHINE
|
||||
)
|
||||
departmental_flags = DEPARTMENT_BITFLAG_SCIENCE | DEPARTMENT_BITFLAG_ENGINEERING
|
||||
|
||||
/datum/design_techweb/board/destructive_analyzer
|
||||
name = "destructive analyzer"
|
||||
id = "destructive_analyzer"
|
||||
build_path = /obj/item/circuitboard/destructive_analyzer
|
||||
category = list(
|
||||
RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_RESEARCH
|
||||
)
|
||||
departmental_flags = DEPARTMENT_BITFLAG_SCIENCE
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
/datum/component/experiment_handler/proc/try_run_destructive_experiment(datum/source, list/scanned_atoms)
|
||||
SIGNAL_HANDLER
|
||||
var/atom/movable/our_scanner = parent
|
||||
if (selected_experiment == null)
|
||||
if (selected_experiment == null && !(config_flags & EXPERIMENT_CONFIG_ALWAYS_ACTIVE) )
|
||||
if(!(config_flags & EXPERIMENT_CONFIG_SILENT_FAIL))
|
||||
playsound(our_scanner, 'sound/machines/buzz-sigh.ogg', 25)
|
||||
to_chat(our_scanner, span_notice("No experiment selected!"))
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
|
||||
///Example of a destructive experiment.
|
||||
/datum/experiment/scanning/random/artifact_destruction
|
||||
name = "Artifact Analysis"
|
||||
description = "Destroy some artifacts"
|
||||
possible_types = list(/obj/item/research_sample/common)
|
||||
total_requirement = 3
|
||||
traits = EXPERIMENT_TRAIT_DESTRUCTIVE
|
||||
exp_tag = "Physical Experiment"
|
||||
|
||||
/datum/experiment/scanning/random/artifact_destruction/serialize_progress_stage(atom/target, list/seen_instances)
|
||||
return EXPERIMENT_PROG_INT("Destroy artifacts.", \
|
||||
traits & EXPERIMENT_TRAIT_DESTRUCTIVE ? scanned[target] : seen_instances.len, required_atoms[target])
|
||||
|
||||
/datum/experiment/scanning/random/janitor_trash
|
||||
name = "Station Hygiene Inspection"
|
||||
description = "To learn how to clean, we must first learn what it is to have filth. We need you to scan some filth around the station."
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
name = "Scanning Experiment"
|
||||
description = "Base experiment for scanning atoms"
|
||||
exp_tag = "Scan"
|
||||
allowed_experimentors = list(/obj/item/experi_scanner)
|
||||
allowed_experimentors = list(/obj/item/experi_scanner, /obj/machinery/rnd/destructive_analyzer)
|
||||
performance_hint = "Perform scanning experiments using a handheld experi-scanner."
|
||||
/// The typepaths and number of atoms that must be scanned
|
||||
var/list/required_atoms = list()
|
||||
|
||||
319
code/modules/research/tg/machinery/destructive_analyzer.dm
Normal file
319
code/modules/research/tg/machinery/destructive_analyzer.dm
Normal file
@@ -0,0 +1,319 @@
|
||||
///The 'ID' for deconstructing items for Research points instead of nodes.
|
||||
#define DESTRUCTIVE_ANALYZER_DESTROY_POINTS "research_points"
|
||||
|
||||
/*
|
||||
Destructive Analyzer
|
||||
|
||||
It is used to destroy hand-held objects and advance technological research. Used to perform /datum/experiment/physical/destructive_analysis experiments.
|
||||
*/
|
||||
|
||||
/obj/machinery/rnd/destructive_analyzer
|
||||
name = "destructive analyzer"
|
||||
icon_state = "d_analyzer"
|
||||
var/decon_mod = 0
|
||||
circuit = /obj/item/circuitboard/destructive_analyzer
|
||||
use_power = USE_POWER_IDLE
|
||||
idle_power_usage = 30
|
||||
active_power_usage = 2500
|
||||
var/rped_recycler_ready = TRUE
|
||||
var/datum/component/remote_materials/rmat
|
||||
|
||||
/obj/machinery/rnd/destructive_analyzer/Initialize(mapload)
|
||||
rmat = AddComponent(
|
||||
/datum/component/remote_materials, \
|
||||
mapload, \
|
||||
mat_container_flags = MATCONTAINER_NO_INSERT \
|
||||
)
|
||||
|
||||
//Destructive analysis
|
||||
var/static/list/destructive_signals = list(
|
||||
COMSIG_MACHINERY_DESTRUCTIVE_SCAN = TYPE_PROC_REF(/datum/component/experiment_handler, try_run_destructive_experiment),
|
||||
)
|
||||
|
||||
AddComponent(/datum/component/experiment_handler, \
|
||||
allowed_experiments = list(/datum/experiment/scanning),\
|
||||
config_flags = EXPERIMENT_CONFIG_ALWAYS_ACTIVE|EXPERIMENT_CONFIG_SILENT_FAIL,\
|
||||
experiment_signals = destructive_signals, \
|
||||
)
|
||||
. = ..()
|
||||
default_apply_parts()
|
||||
|
||||
/obj/machinery/rnd/destructive_analyzer/Destroy()
|
||||
rmat = null
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/rnd/destructive_analyzer/RefreshParts()
|
||||
var/T = 0
|
||||
for(var/obj/item/stock_parts/S in component_parts)
|
||||
T += S.rating
|
||||
T *= 0.1
|
||||
decon_mod = clamp(T, 0, 1)
|
||||
|
||||
/obj/machinery/rnd/destructive_analyzer/update_icon()
|
||||
var/current_item = loaded_item?.resolve()
|
||||
if(panel_open)
|
||||
icon_state = "d_analyzer_t"
|
||||
else if(current_item)
|
||||
icon_state = "d_analyzer_l"
|
||||
else
|
||||
icon_state = "d_analyzer"
|
||||
|
||||
/obj/machinery/rnd/destructive_analyzer/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if(busy)
|
||||
to_chat(user, span_notice("\The [src] is busy right now."))
|
||||
return
|
||||
if(default_deconstruction_screwdriver(user, O))
|
||||
return
|
||||
if(default_deconstruction_crowbar(user, O))
|
||||
return
|
||||
if(default_part_replacement(user, O))
|
||||
return
|
||||
if(!panel_open)
|
||||
var/current_item = loaded_item?.resolve()
|
||||
if(current_item)
|
||||
to_chat(user, span_notice("There is something already loaded into \the [src]."))
|
||||
else
|
||||
if(isrobot(user)) //Don't put your module items in there!
|
||||
return
|
||||
if(is_type_in_list(O, GLOB.item_deconstruction_blacklist))
|
||||
to_chat(user, span_notice("The machine rejects \the [O]!"))
|
||||
return
|
||||
if((O.item_flags & DROPDEL) || (O.item_flags & NOSTRIP))
|
||||
to_chat(user, span_notice("The machine rejects \the [O]!"))
|
||||
return
|
||||
if(O.tethered_host_item)
|
||||
to_chat(user, span_notice("The machine rejects \the [O]!"))
|
||||
return
|
||||
if(LAZYLEN(O.contents))
|
||||
to_chat(user, span_notice("The machine rejects \the [O]! You need to clear it of all items first!"))
|
||||
return
|
||||
busy = TRUE
|
||||
loaded_item = WEAKREF(O)
|
||||
user.drop_item()
|
||||
O.forceMove(src)
|
||||
SStgui.update_uis(src)
|
||||
to_chat(user, span_notice("You add \the [O] to \the [src]."))
|
||||
flick("d_analyzer_la", src)
|
||||
addtimer(CALLBACK(src, PROC_REF(analyze_finish)), 1 SECONDS, TIMER_DELETE_ME)
|
||||
return TRUE
|
||||
// Handle signal to remote_materials so we can link the DA to the silo
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/rnd/destructive_analyzer/proc/analyze_finish()
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
PRIVATE_PROC(TRUE)
|
||||
update_icon()
|
||||
reset_busy()
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RPED recycling
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/obj/machinery/rnd/destructive_analyzer/MouseDrop_T(atom/dropping, mob/living/user)
|
||||
if(istype(dropping, /obj/item/storage/part_replacer))
|
||||
var/obj/item/storage/part_replacer/replacer = dropping
|
||||
replacer.hide_from(user)
|
||||
if(!rped_recycler_ready)
|
||||
to_chat(user, span_notice("\The [src]'s stock parts recycler isn't ready yet."))
|
||||
return FALSE
|
||||
|
||||
// We want the lowest-part tier rating in the RPED so we only recycle the lowest-tier parts.
|
||||
var/lowest_rating = INFINITY
|
||||
for(var/obj/item/B in replacer.contents)
|
||||
if(B.rped_rating() < lowest_rating)
|
||||
lowest_rating = B.rped_rating()
|
||||
if(lowest_rating == INFINITY)
|
||||
atom_say("Mass part deconstruction attempt canceled - no valid parts for recycling detected.")
|
||||
return FALSE
|
||||
// Sending salvaged materials to the silo
|
||||
var/datum/component/material_container/materials = get_silo_material_container_datum(TRUE)
|
||||
if(!materials)
|
||||
return FALSE
|
||||
for(var/obj/item/B in replacer.contents)
|
||||
if(B.rped_rating() > lowest_rating)
|
||||
continue
|
||||
materials.insert_item(B, decon_mod, src)
|
||||
// Feedback
|
||||
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
|
||||
rped_recycler_ready = FALSE
|
||||
addtimer(CALLBACK(src, PROC_REF(rped_ready)), 5 SECONDS, TIMER_DELETE_ME)
|
||||
to_chat(user, span_notice("You deconstruct all the parts of rating [lowest_rating] in [replacer] with [src]."))
|
||||
return TRUE
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/rnd/destructive_analyzer/proc/rped_ready()
|
||||
PRIVATE_PROC(TRUE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
|
||||
rped_recycler_ready = TRUE
|
||||
playsound(get_turf(src), 'sound/machines/chime.ogg', 50, 1)
|
||||
|
||||
/obj/machinery/rnd/destructive_analyzer/proc/get_silo_material_container_datum(verbose)
|
||||
var/datum/component/material_container/materials = rmat.mat_container
|
||||
if(!materials)
|
||||
if(verbose)
|
||||
atom_say("No access to material storage, please contact the quartermaster.")
|
||||
return null
|
||||
if(rmat.on_hold())
|
||||
if(verbose)
|
||||
atom_say("Mineral access is on hold, please contact the quartermaster.")
|
||||
return null
|
||||
return materials
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Handling deconstruction
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/obj/machinery/rnd/destructive_analyzer/attack_hand(mob/user as mob)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/rnd/destructive_analyzer/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "DestructiveAnalyzer")
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/rnd/destructive_analyzer/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["server_connected"] = !!stored_research
|
||||
data["node_data"] = null
|
||||
var/obj/item/current_item = loaded_item?.resolve()
|
||||
if(current_item)
|
||||
data["item_icon"] = icon2base64(getFlatIcon(image(icon = current_item.icon, icon_state = current_item.icon_state), no_anim = TRUE))
|
||||
data["indestructible"] = is_type_in_list(current_item, GLOB.item_deconstruction_blacklist)
|
||||
data["loaded_item"] = current_item
|
||||
data["already_deconstructed"] = !!stored_research.deconstructed_items[current_item.type]
|
||||
var/list/points = techweb_item_point_check(current_item)
|
||||
data["recoverable_points"] = techweb_point_display_generic(points)
|
||||
|
||||
var/list/boostable_nodes = techweb_item_unlock_check(current_item)
|
||||
for(var/id in boostable_nodes)
|
||||
var/datum/techweb_node/unlockable_node = SSresearch.techweb_node_by_id(id)
|
||||
var/list/node_data = list()
|
||||
node_data["node_name"] = unlockable_node.display_name
|
||||
node_data["node_id"] = unlockable_node.id
|
||||
node_data["node_hidden"] = !!stored_research.hidden_nodes[unlockable_node.id]
|
||||
data["node_data"] += list(node_data)
|
||||
else
|
||||
data["loaded_item"] = null
|
||||
return data
|
||||
|
||||
/obj/machinery/rnd/destructive_analyzer/tgui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["research_point_id"] = DESTRUCTIVE_ANALYZER_DESTROY_POINTS
|
||||
return data
|
||||
|
||||
/obj/machinery/rnd/destructive_analyzer/tgui_act(action, params, datum/tgui/ui)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
var/mob/user = usr
|
||||
var/current_item = loaded_item?.resolve()
|
||||
switch(action)
|
||||
if("eject_item")
|
||||
if(busy)
|
||||
balloon_alert(user, "already busy!")
|
||||
return TRUE
|
||||
if(current_item)
|
||||
unload_item()
|
||||
return TRUE
|
||||
if("deconstruct")
|
||||
if(!user_try_decon_id(params["deconstruct_id"]))
|
||||
balloon_alert(user, "analysis failed!")
|
||||
return TRUE
|
||||
|
||||
///Drops the loaded item where it can and nulls it.
|
||||
/obj/machinery/rnd/destructive_analyzer/proc/unload_item()
|
||||
var/obj/item/current_item = loaded_item?.resolve()
|
||||
if(!current_item)
|
||||
loaded_item = null
|
||||
return FALSE
|
||||
//playsound(loc, 'sound/machines/terminal/terminal_insert_disc.ogg', 30, FALSE)
|
||||
current_item.forceMove(drop_location())
|
||||
loaded_item = null
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Destroys an item by going through all its contents (including itself) and calling destroy_item_individual
|
||||
* Args:
|
||||
* gain_research_points - Whether deconstructing each individual item should check for research points to boost.
|
||||
*/
|
||||
/obj/machinery/rnd/destructive_analyzer/proc/destroy_item(gain_research_points = FALSE)
|
||||
var/obj/item/current_item = loaded_item?.resolve()
|
||||
if(!current_item || QDELETED(src))
|
||||
return FALSE
|
||||
//flick("[base_icon_state]_process", src)
|
||||
busy = TRUE
|
||||
addtimer(CALLBACK(src, PROC_REF(reset_busy)), 2.4 SECONDS)
|
||||
use_power(active_power_usage)
|
||||
//Failsafe.
|
||||
for(var/atom/movable/AM in current_item.contents)
|
||||
AM.forceMove(get_turf(src))
|
||||
playsound(src, 'sound/machines/destructive_analyzer.ogg', 50, 1)
|
||||
SEND_SIGNAL(src, COMSIG_MACHINERY_DESTRUCTIVE_SCAN, current_item)
|
||||
destroy_item_individual(current_item, gain_research_points)
|
||||
loaded_item = null
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Destroys the individual provided item
|
||||
* Args:
|
||||
* thing - The thing being destroyed. Generally an object, but it can be a mob too, such as intellicards and pAIs.
|
||||
* gain_research_points - Whether deconstructing this should give research points to the stored techweb, if applicable.
|
||||
*/
|
||||
/obj/machinery/rnd/destructive_analyzer/proc/destroy_item_individual(obj/item/thing, gain_research_points = FALSE)
|
||||
if(isliving(thing))
|
||||
var/mob/living/mob_thing = thing
|
||||
var/turf/turf_to_dump_to = get_turf(src)
|
||||
log_and_message_admins("made an attempt to kill [mob_thing] in a destructive analyzer was made at [ADMIN_VERBOSEJMP(turf_to_dump_to)]")
|
||||
visible_message(span_warning("A loud buzz sounds out from \the [src] as it rejects and spits out \the [mob_thing]!"))
|
||||
mob_thing.forceMove(turf_to_dump_to)
|
||||
return
|
||||
//Safety.
|
||||
if(is_type_in_list(thing, GLOB.item_deconstruction_blacklist))
|
||||
var/turf/turf_to_dump_to = get_turf(src)
|
||||
log_and_message_admins("made an attempt to destroy [thing] in a destructive analyzer was made at [ADMIN_VERBOSEJMP(turf_to_dump_to)]")
|
||||
visible_message(span_warning("A loud buzz sounds out from \the [src] as it rejects and spits out \the [thing]!"))
|
||||
thing.forceMove(turf_to_dump_to)
|
||||
return
|
||||
var/list/point_value = techweb_item_point_check(thing)
|
||||
//If it has a point value and we haven't deconstructed it OR we've deconstructed it but it's a repeatable.
|
||||
if(point_value && (!stored_research.deconstructed_items[thing.type] || (stored_research.deconstructed_items[thing.type] && (thing.type in SSresearch.techweb_repeatable_items))))
|
||||
stored_research.deconstructed_items[thing.type] = TRUE
|
||||
stored_research.add_point_list(point_value)
|
||||
|
||||
//Finally, let's add it to the material silo, if applicable.
|
||||
var/datum/component/material_container/materials = get_silo_material_container_datum(FALSE)
|
||||
materials.insert_item(thing, decon_mod, src, FALSE)
|
||||
qdel(thing)
|
||||
|
||||
/**
|
||||
* Attempts to destroy the loaded item using a provided research id.
|
||||
* Args:
|
||||
* id - The techweb ID node that we're meant to unlock if applicable.
|
||||
*/
|
||||
/obj/machinery/rnd/destructive_analyzer/proc/user_try_decon_id(id)
|
||||
var/obj/item/current_item = loaded_item?.resolve()
|
||||
if(!istype(current_item))
|
||||
return FALSE
|
||||
if(LAZYLEN(current_item.contents))
|
||||
visible_message(span_notice("A warning blares from \the [src]: The [current_item] still has items inside it!"))
|
||||
return FALSE
|
||||
if(isnull(id))
|
||||
return FALSE
|
||||
|
||||
if(id == DESTRUCTIVE_ANALYZER_DESTROY_POINTS)
|
||||
if(!destroy_item(gain_research_points = TRUE))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
var/datum/techweb_node/node_to_discover = SSresearch.techweb_node_by_id(id)
|
||||
if(!istype(node_to_discover))
|
||||
return FALSE
|
||||
if(!destroy_item())
|
||||
return FALSE
|
||||
stored_research.unhide_node(node_to_discover)
|
||||
return TRUE
|
||||
|
||||
#undef DESTRUCTIVE_ANALYZER_DESTROY_POINTS
|
||||
@@ -14,7 +14,7 @@
|
||||
///Ref to global science techweb.
|
||||
var/datum/techweb/stored_research
|
||||
///The item loaded inside the machine, used by experimentors and destructive analyzers only.
|
||||
var/obj/item/loaded_item
|
||||
var/datum/weakref/loaded_item
|
||||
|
||||
/obj/machinery/rnd/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -59,6 +59,8 @@
|
||||
return ..()
|
||||
|
||||
/obj/machinery/rnd/dismantle()
|
||||
if(loaded_item)
|
||||
loaded_item.forceMove(drop_location())
|
||||
var/obj/item/our_item = loaded_item?.resolve()
|
||||
if(our_item)
|
||||
our_item.forceMove(drop_location())
|
||||
loaded_item = null
|
||||
. = ..()
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// "rdservercontrol",
|
||||
// "doppler_array",
|
||||
// "experimentor",
|
||||
// "destructive_analyzer",
|
||||
"destructive_analyzer",
|
||||
// "destructive_scanner",
|
||||
// "laptop",
|
||||
// "portadrive_basic",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2.2.5",
|
||||
"@biomejs/biome": "^2.2.6",
|
||||
"prettier": "^3.6.2"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
159
tgui/packages/tgui/interfaces/DestructiveAnalyzer.tsx
Normal file
159
tgui/packages/tgui/interfaces/DestructiveAnalyzer.tsx
Normal file
@@ -0,0 +1,159 @@
|
||||
import { useBackend } from 'tgui/backend';
|
||||
import { Window } from 'tgui/layouts';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Image,
|
||||
NoticeBox,
|
||||
Section,
|
||||
Stack,
|
||||
} from 'tgui-core/components';
|
||||
import type { BooleanLike } from 'tgui-core/react';
|
||||
|
||||
type Data = {
|
||||
server_connected: BooleanLike;
|
||||
loaded_item: string;
|
||||
item_icon: string;
|
||||
indestructible: BooleanLike;
|
||||
already_deconstructed: BooleanLike;
|
||||
recoverable_points: string;
|
||||
node_data: NodeData[] | null;
|
||||
research_point_id: string;
|
||||
};
|
||||
|
||||
type NodeData = {
|
||||
node_name: string;
|
||||
node_id: string;
|
||||
node_hidden: BooleanLike;
|
||||
};
|
||||
|
||||
export const DestructiveAnalyzer = () => {
|
||||
const { act, data } = useBackend<Data>();
|
||||
const {
|
||||
server_connected,
|
||||
indestructible,
|
||||
loaded_item,
|
||||
item_icon,
|
||||
already_deconstructed,
|
||||
recoverable_points,
|
||||
research_point_id,
|
||||
node_data,
|
||||
} = data;
|
||||
if (!server_connected) {
|
||||
return (
|
||||
<Window width={400} height={260} title="Destructive Analyzer">
|
||||
<Window.Content>
|
||||
<NoticeBox textAlign="center" danger>
|
||||
Not connected to a server. Please sync one using a multitool.
|
||||
</NoticeBox>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
}
|
||||
if (!loaded_item) {
|
||||
return (
|
||||
<Window width={400} height={260} title="Destructive Analyzer">
|
||||
<Window.Content>
|
||||
<NoticeBox textAlign="center" danger>
|
||||
No item loaded! <br />
|
||||
Put any item inside to see what it's capable of!
|
||||
</NoticeBox>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Window width={400} height={270} title="Destructive Analyzer">
|
||||
<Window.Content>
|
||||
<Stack vertical fill>
|
||||
<Stack.Item grow>
|
||||
<Section
|
||||
title={loaded_item}
|
||||
fill
|
||||
buttons={
|
||||
<Button
|
||||
icon="eject"
|
||||
tooltip="Ejects the item currently inside the machine."
|
||||
onClick={() => act('eject_item')}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Image
|
||||
src={`data:image/jpeg;base64,${item_icon}`}
|
||||
height="64px"
|
||||
width="64px"
|
||||
verticalAlign="middle"
|
||||
/>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<Section fill title="Deconstruction Methods">
|
||||
<Stack vertical fill>
|
||||
{!!indestructible && (
|
||||
<Stack.Item>
|
||||
<NoticeBox textAlign="center" danger>
|
||||
This item can't be deconstructed!
|
||||
</NoticeBox>
|
||||
</Stack.Item>
|
||||
)}
|
||||
{!indestructible && !!recoverable_points && (
|
||||
<>
|
||||
<Stack.Item>
|
||||
<Box fontSize="14px">
|
||||
Research points from deconstruction
|
||||
</Box>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Box>{recoverable_points}</Box>
|
||||
</Stack.Item>
|
||||
</>
|
||||
)}
|
||||
<Stack.Item>
|
||||
<Stack>
|
||||
{!indestructible && (
|
||||
<Stack.Item>
|
||||
<Button.Confirm
|
||||
icon="hammer"
|
||||
tooltip={
|
||||
already_deconstructed
|
||||
? 'This item item has already been deconstructed, and will not give any additional information.'
|
||||
: 'Destroys the object currently residing in the machine.'
|
||||
}
|
||||
onClick={() =>
|
||||
act('deconstruct', {
|
||||
deconstruct_id: research_point_id,
|
||||
})
|
||||
}
|
||||
>
|
||||
Deconstruct
|
||||
</Button.Confirm>
|
||||
</Stack.Item>
|
||||
)}
|
||||
{node_data?.map((node) => (
|
||||
<Stack.Item key={node.node_id}>
|
||||
<Button.Confirm
|
||||
icon="cash-register"
|
||||
disabled={!node.node_hidden}
|
||||
tooltip={
|
||||
node.node_hidden
|
||||
? 'Deconstruct this to research the selected node.'
|
||||
: 'This node has already been researched.'
|
||||
}
|
||||
onClick={() =>
|
||||
act('deconstruct', { deconstruct_id: node.node_id })
|
||||
}
|
||||
>
|
||||
{node.node_name}
|
||||
</Button.Confirm>
|
||||
</Stack.Item>
|
||||
))}
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
import { ConstructorEnum, type Data, Tab } from './data';
|
||||
import { Constructor } from './pages/Constructor';
|
||||
import { DesignList } from './pages/DesignList';
|
||||
import { DestructiveAnalyzer } from './pages/DestructiveAnalyzer';
|
||||
import { DestructiveAnalyzer } from '../DestructiveAnalyzer';
|
||||
import { LockScreen } from './pages/LockScreen';
|
||||
import { Misc } from './pages/Misc';
|
||||
import { ResearchList } from './pages/ResearchList';
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useBackend } from 'tgui/backend';
|
||||
import { Box, Button, Icon, Section, Stack, Table } from 'tgui-core/components';
|
||||
import { classes } from 'tgui-core/react';
|
||||
|
||||
import type { Data, LinkedDestroyer } from '../data';
|
||||
|
||||
export const DestructiveAnalyzer = (props) => {
|
||||
const { act, data } = useBackend<Data>();
|
||||
|
||||
let inner;
|
||||
|
||||
if (!data.linked_destroy) {
|
||||
inner = <Box color="bad">No Destructive Analyzer linked.</Box>;
|
||||
} else if (!data.linked_destroy.loaded_item) {
|
||||
inner = <Box color="average">No item loaded.</Box>;
|
||||
} else {
|
||||
inner = <DestroyButton destroyer={data.linked_destroy} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Section title="Destructive Analyzer" fill textAlign="center">
|
||||
{inner}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const DestroyButton = (props: { destroyer: LinkedDestroyer }) => {
|
||||
const { act } = useBackend();
|
||||
const { destroyer } = props;
|
||||
|
||||
const [buttonPressed, setButtonPressed] = useState(false);
|
||||
|
||||
return (
|
||||
<Stack fill>
|
||||
<Stack.Item basis="60%" textAlign="left">
|
||||
<Section
|
||||
title="Loaded Item"
|
||||
fill
|
||||
buttons={<Button onClick={() => act('eject_item')}>Eject</Button>}
|
||||
fontSize={1.2}
|
||||
mt={2}
|
||||
ml={1}
|
||||
backgroundColor="#0a0a0a"
|
||||
height="95%"
|
||||
style={{ borderRadius: '5px' }}
|
||||
>
|
||||
<Box
|
||||
fontSize={2}
|
||||
mb={2}
|
||||
ml={2}
|
||||
color="good"
|
||||
style={{ textTransform: 'capitalize' }}
|
||||
>
|
||||
{destroyer.loaded_item}
|
||||
</Box>
|
||||
<Table>
|
||||
<Table.Row header>
|
||||
<Table.Cell header>Tech Levels - Name</Table.Cell>
|
||||
<Table.Cell header textAlign="center">
|
||||
Level
|
||||
</Table.Cell>
|
||||
<Table.Cell header textAlign="center">
|
||||
Current
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{destroyer.origin_tech.map((tech) => (
|
||||
<Table.Row key={tech.name}>
|
||||
<Table.Cell>{tech.name}</Table.Cell>
|
||||
<Table.Cell textAlign="center">{tech.level}</Table.Cell>
|
||||
<Table.Cell textAlign="center" position="relative">
|
||||
{tech.current}
|
||||
{tech.level >= tech.current ? (
|
||||
<AnimatedArrows
|
||||
on
|
||||
position="absolute"
|
||||
top={0.25}
|
||||
right={0}
|
||||
style={{ transform: 'rotate(-90deg)' }}
|
||||
/>
|
||||
) : null}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
))}
|
||||
</Table>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<Stack fill align="center" justify="center">
|
||||
<Stack.Item>
|
||||
{/* https://codepen.io/ovr/pen/yLXBbB */}
|
||||
<Button
|
||||
color="danger"
|
||||
className={classes(
|
||||
buttonPressed
|
||||
? ['BigButton', 'BigButton__Pressed']
|
||||
: ['BigButton'],
|
||||
)}
|
||||
verticalAlignContent="middle"
|
||||
onClick={() => {
|
||||
setButtonPressed(true);
|
||||
setTimeout(() => {
|
||||
setButtonPressed(false);
|
||||
act('deconstruct');
|
||||
}, 200);
|
||||
}}
|
||||
>
|
||||
Deconstruct
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export const AnimatedArrows = (props: { on: boolean } & any) => {
|
||||
const { on, ...rest } = props;
|
||||
|
||||
const [activeArrow, setActiveArrow] = useState(0);
|
||||
|
||||
// Lower to make it animate faster
|
||||
const SPEED = 200;
|
||||
|
||||
useEffect(() => {
|
||||
const id = setInterval(() => {
|
||||
setActiveArrow((arrow) => (arrow + 1) % 3);
|
||||
}, SPEED);
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Box {...rest}>
|
||||
<Icon
|
||||
color={!on ? 'gray' : activeArrow === 0 ? 'green' : 'white'}
|
||||
name="chevron-right"
|
||||
size={0.8}
|
||||
mr={-0.5}
|
||||
/>
|
||||
<Icon
|
||||
color={!on ? 'gray' : activeArrow === 1 ? 'green' : 'white'}
|
||||
name="chevron-right"
|
||||
size={0.8}
|
||||
mr={-0.5}
|
||||
/>
|
||||
<Icon
|
||||
color={!on ? 'gray' : activeArrow === 2 ? 'green' : 'white'}
|
||||
name="chevron-right"
|
||||
size={0.8}
|
||||
mr={-0.5}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -4541,6 +4541,7 @@
|
||||
#include "code\modules\research\tg\machinery\_production.dm"
|
||||
#include "code\modules\research\tg\machinery\circuit_imprinter.dm"
|
||||
#include "code\modules\research\tg\machinery\departmental_protolathe.dm"
|
||||
#include "code\modules\research\tg\machinery\destructive_analyzer.dm"
|
||||
#include "code\modules\research\tg\machinery\mech_fabricator.dm"
|
||||
#include "code\modules\research\tg\machinery\mech_prosfab.dm"
|
||||
#include "code\modules\research\tg\machinery\protolathe.dm"
|
||||
|
||||
Reference in New Issue
Block a user