Files
Bubberstation/code/modules/research/destructive_analyzer.dm
SyncIt21 21aee3112f [NO GBP] Fixes some item interactions (#87856)
## About The Pull Request
- Fixes #87854


## Changelog
🆑
fix: flatpacker accepts circuitboards with left click
fix: rcd can deconstruct tables
fix: you can open panels of destructive analyzers with screwdriver right
click. Use right click or combat mode with items for default
interactions
fix: flatpacker & machines with local storage can be RPED'd again
/🆑
2024-11-12 18:13:42 +01:00

223 lines
8.1 KiB
Plaintext

///How much power it costs to deconstruct an item.
#define DESTRUCTIVE_ANALYZER_POWER_USAGE (BASE_MACHINE_IDLE_CONSUMPTION * 2.5)
///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.
*/
/obj/machinery/rnd/destructive_analyzer
name = "destructive analyzer"
desc = "Learn science by destroying things!"
icon_state = "d_analyzer"
base_icon_state = "d_analyzer"
circuit = /obj/item/circuitboard/machine/destructive_analyzer
/obj/machinery/rnd/destructive_analyzer/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
. = ..()
var/screentip_set = FALSE
if(loaded_item)
context[SCREENTIP_CONTEXT_ALT_LMB] = "Remove Item"
screentip_set = TRUE
else if(!isnull(held_item))
context[SCREENTIP_CONTEXT_LMB] = "Insert Item"
screentip_set = TRUE
if(screentip_set)
. = CONTEXTUAL_SCREENTIP_SET
/obj/machinery/rnd/destructive_analyzer/examine(mob/user)
. = ..()
if(!in_range(user, src) && !isobserver(user))
return
if(loaded_item)
. += span_notice("[EXAMINE_HINT("Left-Click")] to remove loaded item inside.")
else
. += span_notice("An item can be loaded inside via [EXAMINE_HINT("Left-Click")].")
/obj/machinery/rnd/destructive_analyzer/base_item_interaction(mob/living/user, obj/item/weapon, list/modifiers)
if(LAZYACCESS(modifiers, RIGHT_CLICK))
return ..()
if(user.combat_mode)
return ..()
if(!is_insertion_ready(user))
return ..()
if(!user.transferItemToLoc(weapon, src))
to_chat(user, span_warning("\The [weapon] is stuck to your hand, you cannot put it in the [name]!"))
return ITEM_INTERACT_BLOCKING
busy = TRUE
loaded_item = weapon
to_chat(user, span_notice("You place the [weapon.name] inside the [name]."))
flick("[base_icon_state]_la", src)
addtimer(CALLBACK(src, PROC_REF(finish_loading)), 1 SECONDS)
return ITEM_INTERACT_SUCCESS
/obj/machinery/rnd/destructive_analyzer/click_alt(mob/user)
unload_item()
return CLICK_ACTION_SUCCESS
/obj/machinery/rnd/destructive_analyzer/update_icon_state()
icon_state = "[base_icon_state][loaded_item ? "_l" : null]"
return ..()
/obj/machinery/rnd/destructive_analyzer/ui_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/ui_data(mob/user)
var/list/data = list()
data["server_connected"] = !!stored_research
data["node_data"] = list()
if(loaded_item)
data["item_icon"] = icon2base64(getFlatIcon(image(icon = loaded_item.icon, icon_state = loaded_item.icon_state), no_anim = TRUE))
data["indestructible"] = !(loaded_item.resistance_flags & INDESTRUCTIBLE)
data["loaded_item"] = loaded_item
data["already_deconstructed"] = !!stored_research.deconstructed_items[loaded_item.type]
var/list/points = techweb_item_point_check(loaded_item)
data["recoverable_points"] = techweb_point_display_generic(points)
var/list/boostable_nodes = techweb_item_unlock_check(loaded_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/ui_static_data(mob/user)
var/list/data = list()
data["research_point_id"] = DESTRUCTIVE_ANALYZER_DESTROY_POINTS
return data
/obj/machinery/rnd/destructive_analyzer/ui_act(action, params, datum/tgui/ui)
. = ..()
if(.)
return
var/mob/user = usr
switch(action)
if("eject_item")
if(busy)
balloon_alert(user, "already busy!")
return TRUE
if(loaded_item)
unload_item()
return TRUE
if("deconstruct")
if(!user_try_decon_id(params["deconstruct_id"]))
say("Destructive analysis failed!")
return TRUE
/obj/machinery/rnd/destructive_analyzer/item_interaction_secondary(mob/living/user, obj/item/tool, list/modifiers)
// Cringe way to let emags insert on RMB because we still use attackby to insert
if(istype(tool, /obj/item/card/emag))
return ITEM_INTERACT_SKIP_TO_ATTACK
return NONE
//This allows people to put syndicate screwdrivers in the machine. Secondary act still passes.
/obj/machinery/rnd/destructive_analyzer/screwdriver_act(mob/living/user, obj/item/tool)
return FALSE
//We need to call default_deconstruction_screwdriver here since its parent will call screwdriver_act on this level which will stop us from ever deconstructing.
/obj/machinery/rnd/destructive_analyzer/screwdriver_act_secondary(mob/living/user, obj/item/tool)
return default_deconstruction_screwdriver(user, "[initial(icon_state)]_t", initial(icon_state), tool)
//We need to let wire cutter in (not block) so we can analyze alien wirecutters.
/obj/machinery/rnd/destructive_analyzer/wirecutter_act(mob/living/user, obj/item/tool)
if(panel_open)
wires.interact(user)
return ITEM_INTERACT_SUCCESS
///Drops the loaded item where it can and nulls it.
/obj/machinery/rnd/destructive_analyzer/proc/unload_item()
if(!loaded_item)
return FALSE
playsound(loc, 'sound/machines/terminal/terminal_insert_disc.ogg', 30, FALSE)
loaded_item.forceMove(drop_location())
loaded_item = null
update_appearance(UPDATE_ICON)
return TRUE
///Called in a timer callback after loading something into it, this handles resetting the 'busy' state back to its initial state
///So the machine can be used.
/obj/machinery/rnd/destructive_analyzer/proc/finish_loading()
update_appearance(UPDATE_ICON)
reset_busy()
/**
* 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)
if(QDELETED(loaded_item) || QDELETED(src))
return FALSE
flick("[base_icon_state]_process", src)
busy = TRUE
addtimer(CALLBACK(src, PROC_REF(reset_busy)), 2.4 SECONDS)
use_energy(DESTRUCTIVE_ANALYZER_POWER_USAGE)
var/list/all_contents = loaded_item.get_all_contents()
for(var/innerthing in all_contents)
destroy_item_individual(innerthing, gain_research_points)
loaded_item = null
update_appearance(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
if(mob_thing.stat != DEAD)
mob_thing.investigate_log("has been killed by a destructive analyzer.", INVESTIGATE_DEATHS)
mob_thing.death()
var/list/point_value = techweb_item_point_check(thing)
if(point_value && !stored_research.deconstructed_items[thing.type])
stored_research.deconstructed_items[thing.type] = TRUE
stored_research.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = point_value))
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)
if(!istype(loaded_item))
return FALSE
if(isnull(id))
return FALSE
var/item_type = loaded_item.type
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
SSblackbox.record_feedback("nested tally", "item_deconstructed", 1, list("[node_to_discover.id]", "[item_type]"))
stored_research.unhide_node(node_to_discover)
return TRUE
#undef DESTRUCTIVE_ANALYZER_DESTROY_POINTS
#undef DESTRUCTIVE_ANALYZER_POWER_USAGE