diff --git a/code/__DEFINES/wiremod.dm b/code/__DEFINES/wiremod.dm index a34ce29423b..142eb4fdf1f 100644 --- a/code/__DEFINES/wiremod.dm +++ b/code/__DEFINES/wiremod.dm @@ -110,6 +110,10 @@ #define COMP_SECURITY_ARREST_AMOUNT_TO_FLAG 10 +// Proccall component +#define COMP_PROC_GLOBAL "Global" +#define COMP_PROC_OBJECT "Object" + // Shells /// Whether a circuit is stuck on a shell and cannot be removed (by a user) @@ -140,5 +144,7 @@ #define CIRCUIT_FLAG_OUTPUT_SIGNAL (1<<1) /// Prohibits the component from being duplicated via the module duplicator #define CIRCUIT_FLAG_UNDUPEABLE (1<<2) +/// Marks a circuit component as admin only. Admins will only be able to link/unlink with these circuit components. +#define CIRCUIT_FLAG_ADMIN (1<<3) /// This circuit component does not show in the menu. -#define CIRCUIT_FLAG_HIDDEN (1<<3) +#define CIRCUIT_FLAG_HIDDEN (1<<4) diff --git a/code/controllers/subsystem/delay_component.dm b/code/controllers/subsystem/delay_component.dm index 3e549ae7963..85884f7dbe7 100644 --- a/code/controllers/subsystem/delay_component.dm +++ b/code/controllers/subsystem/delay_component.dm @@ -18,6 +18,7 @@ SUBSYSTEM_DEF(circuit_component) if(QDELETED(to_call)) continue + to_call.user = null to_call.InvokeAsync() qdel(to_call) diff --git a/code/datums/components/shell.dm b/code/datums/components/shell.dm index abb988a5f00..1fde7806aeb 100644 --- a/code/datums/components/shell.dm +++ b/code/datums/components/shell.dm @@ -42,11 +42,14 @@ if(unremovable_circuit_components) QDEL_LIST(unremovable_circuit_components) - unremovable_circuit_components = components + unremovable_circuit_components = list() - for(var/obj/item/circuit_component/circuit_component as anything in unremovable_circuit_components) + for(var/obj/item/circuit_component/circuit_component as anything in components) + if(ispath(circuit_component)) + circuit_component = new circuit_component() circuit_component.removable = FALSE RegisterSignal(circuit_component, COMSIG_CIRCUIT_COMPONENT_SAVE, .proc/save_component) + unremovable_circuit_components += circuit_component /datum/component/shell/proc/save_component(datum/source, list/objects) SIGNAL_HANDLER @@ -88,7 +91,8 @@ /datum/component/shell/proc/on_object_deconstruct() SIGNAL_HANDLER - remove_circuit() + if(!attached_circuit.admin_only) + remove_circuit() /datum/component/shell/proc/on_attack_ghost(datum/source, mob/dead/observer/ghost) SIGNAL_HANDLER diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index beb42732ac3..fa4cb56a57d 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -108,7 +108,6 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list( /client/proc/show_tip, /client/proc/smite, /client/proc/admin_away, - /client/proc/load_circuit, )) GLOBAL_PROTECT(admin_verbs_fun) GLOBAL_LIST_INIT(admin_verbs_spawn, list(/datum/admins/proc/spawn_atom, /datum/admins/proc/podspawn_atom, /datum/admins/proc/spawn_cargo, /datum/admins/proc/spawn_objasmob, /client/proc/respawn_character, /datum/admins/proc/beaker_panel)) @@ -190,7 +189,8 @@ GLOBAL_PROTECT(admin_verbs_debug) /client/proc/check_timer_sources, /client/proc/toggle_cdn, /client/proc/cmd_give_sdql_spell, - /client/proc/adventure_manager + /client/proc/adventure_manager, + /client/proc/load_circuit, ) GLOBAL_LIST_INIT(admin_verbs_possess, list(/proc/possess, /proc/release)) GLOBAL_PROTECT(admin_verbs_possess) diff --git a/code/modules/research/designs/wiremod_designs.dm b/code/modules/research/designs/wiremod_designs.dm index 2d6ec2b75b6..4d2b9915ddf 100644 --- a/code/modules/research/designs/wiremod_designs.dm +++ b/code/modules/research/designs/wiremod_designs.dm @@ -238,6 +238,16 @@ id = "comp_module" build_path = /obj/item/circuit_component/module +/datum/design/component/list_literal + name = "List Literal Component" + id = "comp_list_literal" + build_path = /obj/item/circuit_component/list_literal + +/datum/design/component/typecast + name = "Typecast Component" + id = "comp_typecast" + build_path = /obj/item/circuit_component/typecast + /datum/design/component/bci category = list("Circuitry", "BCI Components") diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 2dcdcee17bc..473881ccef0 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -213,6 +213,7 @@ "comp_index_table", "comp_length", "comp_light", + "comp_list_literal", "comp_logic", "comp_mmi", "comp_module", @@ -234,6 +235,7 @@ "comp_textcase", "comp_tonumber", "comp_tostring", + "comp_typecast", "comp_typecheck", "compact_remote_shell", "component_printer", diff --git a/code/modules/wiremod/component.dm b/code/modules/wiremod/component.dm index 4016f2e6fb4..d4e310981e7 100644 --- a/code/modules/wiremod/component.dm +++ b/code/modules/wiremod/component.dm @@ -139,9 +139,12 @@ * * type - The datatype it handles * * trigger - Whether this input port triggers an update on the component when updated. */ -/obj/item/circuit_component/proc/add_input_port(name, type, trigger = TRUE, default = null) +/obj/item/circuit_component/proc/add_input_port(name, type, trigger = TRUE, default = null, index = null) var/datum/port/input/input_port = new(src, name, type, trigger, default) - input_ports += input_port + if(index) + input_ports.Insert(index, input_port) + else + input_ports += input_port if(parent) SStgui.update_uis(parent) return input_port @@ -194,9 +197,14 @@ if(!parent?.on) return TRUE - var/obj/item/stock_parts/cell/cell = parent.get_cell() - if(!cell?.use(power_usage_per_input)) - return TRUE + if(!parent.admin_only) + if(circuit_flags & CIRCUIT_FLAG_ADMIN) + message_admins("[display_name] tried to execute on [parent.get_creator_admin()] that has set the admin_only variable to TRUE!") + return TRUE + + var/obj/item/stock_parts/cell/cell = parent.get_cell() + if(!cell?.use(power_usage_per_input)) + return TRUE if((circuit_flags & CIRCUIT_FLAG_INPUT_SIGNAL) && !COMPONENT_TRIGGERED_BY(trigger_input, port)) return TRUE diff --git a/code/modules/wiremod/component_printer.dm b/code/modules/wiremod/component_printer.dm index 37247efdfdb..7400aafbf20 100644 --- a/code/modules/wiremod/component_printer.dm +++ b/code/modules/wiremod/component_printer.dm @@ -133,6 +133,84 @@ /obj/item/reagent_containers/glass/beaker = 2, ) +/obj/machinery/debug_component_printer + name = "debug component printer" + desc = "Produces components for the creation of integrated circuits." + icon = 'icons/obj/wiremod_fab.dmi' + icon_state = "fab-idle" + + /// All of the possible circuit designs stored by this debug printer + var/list/all_circuit_designs + + density = TRUE + +/obj/machinery/debug_component_printer/Initialize() + . = ..() + all_circuit_designs = list() + + for(var/id in SSresearch.techweb_designs) + var/datum/design/design = SSresearch.techweb_design_by_id(id) + if((design.build_type & COMPONENT_PRINTER) && design.build_path) + all_circuit_designs[design.build_path] = list( + "name" = design.name, + "description" = design.desc, + "materials" = design.materials, + "categories" = design.category + ) + + for(var/obj/item/circuit_component/component as anything in subtypesof(/obj/item/circuit_component)) + var/categories = list("Inaccessible") + if(initial(component.circuit_flags) & CIRCUIT_FLAG_ADMIN) + categories = list("Admin") + if(!(component in all_circuit_designs)) + all_circuit_designs[component] = list( + "name" = initial(component.display_name), + "description" = initial(component.desc), + "materials" = list(), + "categories" = categories, + ) + +/obj/machinery/debug_component_printer/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ComponentPrinter", name) + ui.open() + +/obj/machinery/debug_component_printer/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/sheetmaterials) + ) + +/obj/machinery/debug_component_printer/ui_act(action, list/params) + . = ..() + if (.) + return + + switch (action) + if ("print") + var/build_path = text2path(params["designId"]) + if (!build_path) + return TRUE + + var/list/design = all_circuit_designs[build_path] + if(!design) + return TRUE + + balloon_alert_to_viewers("printed [design["name"]]") + var/atom/printed_design = new build_path(drop_location()) + printed_design.pixel_x = printed_design.base_pixel_x + rand(-5, 5) + printed_design.pixel_y = printed_design.base_pixel_y + rand(-5, 5) + + return TRUE + +/obj/machinery/debug_component_printer/ui_static_data(mob/user) + var/list/data = list() + + data["materials"] = list() + data["designs"] = all_circuit_designs + + return data + /// Module duplicator, allows you to save and recreate module components. /obj/machinery/module_duplicator name = "module duplicator" diff --git a/code/modules/wiremod/components/admin/getvar.dm b/code/modules/wiremod/components/admin/getvar.dm new file mode 100644 index 00000000000..b9857fe892c --- /dev/null +++ b/code/modules/wiremod/components/admin/getvar.dm @@ -0,0 +1,42 @@ +/** + * # Get Variable Component + * + * A component that gets a variable on an object + */ +/obj/item/circuit_component/get_variable + display_name = "Get Variable" + desc = "A component that gets a variable on an object." + circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL|CIRCUIT_FLAG_ADMIN + + /// Entity to get variable of + var/datum/port/input/entity + + /// Variable name + var/datum/port/input/variable_name + + /// Variable value + var/datum/port/output/output_value + + +/obj/item/circuit_component/get_variable/Initialize() + . = ..() + entity = add_input_port("Target", PORT_TYPE_ATOM) + variable_name = add_input_port("Variable Name", PORT_TYPE_STRING) + + output_value = add_output_port("Output Value", PORT_TYPE_ANY) + +/obj/item/circuit_component/get_variable/input_received(datum/port/input/port) + . = ..() + if(.) + return + var/atom/object = entity.input_value + var/var_name = variable_name.input_value + if(!var_name || !object) + output_value.set_output(null) + return + + if(!object.can_vv_get(var_name) || !(var_name in object.vars)) + output_value.set_output(null) + return + + output_value.set_output(object.vars[var_name]) diff --git a/code/modules/wiremod/components/admin/proccall.dm b/code/modules/wiremod/components/admin/proccall.dm new file mode 100644 index 00000000000..9af6d0571c7 --- /dev/null +++ b/code/modules/wiremod/components/admin/proccall.dm @@ -0,0 +1,63 @@ +/** + * # Proc Call Component + * + * A component that calls a proc on an object and outputs the return value + */ +/obj/item/circuit_component/proccall + display_name = "Proc Call" + desc = "A component that gets a variable on an object." + circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL|CIRCUIT_FLAG_ADMIN + + /// Entity to proccall on + var/datum/port/input/entity + + /// Proc to call + var/datum/port/input/proc_name + + /// Arguments + var/datum/port/input/arguments + + /// Returns the output from the proccall + var/datum/port/output/output_value + +/obj/item/circuit_component/proccall/populate_options() + var/static/list/component_options = list( + COMP_PROC_OBJECT, + COMP_PROC_GLOBAL, + ) + + options = component_options + +/obj/item/circuit_component/proccall/Initialize() + . = ..() + entity = add_input_port("Target", PORT_TYPE_ATOM) + proc_name = add_input_port("Proc Name", PORT_TYPE_STRING) + arguments = add_input_port("Arguments", PORT_TYPE_LIST) + + output_value = add_output_port("Output Value", PORT_TYPE_ANY) + +/obj/item/circuit_component/proccall/input_received(datum/port/input/port) + . = ..() + if(.) + return + + var/called_on + if(current_option == COMP_PROC_OBJECT) + called_on = entity.input_value + else + called_on = GLOBAL_PROC + + if(!called_on) + return + + var/to_invoke = proc_name.input_value + var/params = arguments.input_value || list() + + if(!to_invoke) + return + + GLOB.AdminProcCaller = "CHAT_[parent.display_name]" //_ won't show up in ckeys so it'll never match with a real admin + var/result = WrapAdminProcCall(called_on, to_invoke, params) + GLOB.AdminProcCaller = null + + output_value.set_output(result) diff --git a/code/modules/wiremod/components/admin/sdql.dm b/code/modules/wiremod/components/admin/sdql.dm new file mode 100644 index 00000000000..85620d8d109 --- /dev/null +++ b/code/modules/wiremod/components/admin/sdql.dm @@ -0,0 +1,36 @@ +/** + * # SDQL Component + * + * A component that performs an sdql operation + */ +/obj/item/circuit_component/sdql_operation + display_name = "SDQL Operation" + desc = "A component that performs an SDQL operation when invoked." + circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL|CIRCUIT_FLAG_ADMIN + + /// SDQL Operation to invoke + var/datum/port/input/sdql_operation + + var/datum/port/output/results + + +/obj/item/circuit_component/sdql_operation/Initialize() + . = ..() + sdql_operation = add_input_port("SDQL String", PORT_TYPE_STRING) + results = add_output_port("Result", PORT_TYPE_LIST) + +/obj/item/circuit_component/sdql_operation/input_received(datum/port/input/port) + . = ..() + if(.) + return + + var/operation = sdql_operation.input_value + + if(GLOB.AdminProcCaller || !operation) + return TRUE + + GLOB.AdminProcCaller = "CHAT_[parent.display_name]" //_ won't show up in ckeys so it'll never match with a real admin + var/list/result = world.SDQL2_query(operation, parent.get_creator_admin(), parent.get_creator()) + GLOB.AdminProcCaller = null + + results.set_output(result) diff --git a/code/modules/wiremod/components/admin/setvar.dm b/code/modules/wiremod/components/admin/setvar.dm new file mode 100644 index 00000000000..beab6de047c --- /dev/null +++ b/code/modules/wiremod/components/admin/setvar.dm @@ -0,0 +1,36 @@ +/** + * # Set Variable Component + * + * A component that sets a variable on an object + */ +/obj/item/circuit_component/set_variable + display_name = "Set Variable" + desc = "A component that sets a variable on an object." + circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL|CIRCUIT_FLAG_ADMIN + + /// Entity to set variable of + var/datum/port/input/entity + + /// Variable name + var/datum/port/input/variable_name + + /// New value to set the variable name to. + var/datum/port/input/new_value + + +/obj/item/circuit_component/set_variable/Initialize() + . = ..() + entity = add_input_port("Target", PORT_TYPE_ATOM) + variable_name = add_input_port("Variable Name", PORT_TYPE_STRING) + new_value = add_input_port("New Value", PORT_TYPE_ANY) + +/obj/item/circuit_component/set_variable/input_received(datum/port/input/port) + . = ..() + if(.) + return + var/atom/object = entity.input_value + var/var_name = variable_name.input_value + if(!var_name || !object) + return + + object.vv_edit_var(var_name, new_value.input_value) diff --git a/code/modules/wiremod/components/admin/spawn.dm b/code/modules/wiremod/components/admin/spawn.dm new file mode 100644 index 00000000000..555b5b5151e --- /dev/null +++ b/code/modules/wiremod/components/admin/spawn.dm @@ -0,0 +1,47 @@ +/** + * # Spawn Atom Component + * + * Spawns an atom. + */ +/obj/item/circuit_component/spawn_atom + display_name = "Spawn Atom" + desc = "A component that returns the value of a list at a given index." + circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL|CIRCUIT_FLAG_ADMIN + + /// The input path to convert into a typepath + var/datum/port/input/input_path + + /// The turf to spawn them at + var/datum/port/input/spawn_at + + /// Parameters to pass to the atom being spawned + var/datum/port/input/parameters + + /// The result from the output + var/datum/port/output/spawned_atom + +/obj/item/circuit_component/spawn_atom/Initialize() + . = ..() + input_path = add_input_port("Type", PORT_TYPE_ANY) + spawn_at = add_input_port("Spawn At", PORT_TYPE_ATOM) + parameters = add_input_port("Parameters", PORT_TYPE_LIST) + + spawned_atom = add_output_port("Spawned Atom", PORT_TYPE_ATOM) + +/obj/item/circuit_component/spawn_atom/input_received(datum/port/input/port) + . = ..() + if(.) + return + + var/typepath = input_path.input_value + + if(!ispath(typepath, /atom)) + return + + var/list/params = parameters.input_value + if(!params) + params = list() + + params.Insert(1, spawn_at.input_value) + + spawned_atom.set_output(new typepath(arglist(params))) diff --git a/code/modules/wiremod/components/admin/to_type.dm b/code/modules/wiremod/components/admin/to_type.dm new file mode 100644 index 00000000000..3dc23e21293 --- /dev/null +++ b/code/modules/wiremod/components/admin/to_type.dm @@ -0,0 +1,28 @@ +/** + * # To Type Component + * + * Converts a string into a typepath. Useful for adding components. + */ +/obj/item/circuit_component/to_type + display_name = "String To Type" + desc = "A component that returns the value of a list at a given index." + circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL|CIRCUIT_FLAG_ADMIN + + /// The input path to convert into a typepath + var/datum/port/input/input_path + + /// The type output + var/datum/port/output/type_output + +/obj/item/circuit_component/to_type/Initialize() + . = ..() + input_path = add_input_port("Type", PORT_TYPE_STRING) + type_output = add_output_port("Typepath", PORT_TYPE_ANY) + +/obj/item/circuit_component/to_type/input_received(datum/port/input/port) + . = ..() + if(.) + return + + type_output.set_output(text2path(input_path.input_value)) + diff --git a/code/modules/wiremod/components/list/list_literal.dm b/code/modules/wiremod/components/list/list_literal.dm new file mode 100644 index 00000000000..924bf3bfb09 --- /dev/null +++ b/code/modules/wiremod/components/list/list_literal.dm @@ -0,0 +1,84 @@ +/** + * # List Literal Component + * + * Return a list literal. + */ +/obj/item/circuit_component/list_literal + display_name = "List Literal" + desc = "A component that returns the value of a list at a given index. Attack in hand to increase list size, right click to decrease list size." + circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL + + /// The result from the output + var/datum/port/output/list_output + + var/length = 0 + + var/default_list_size = 2 + + var/min_size = 1 + var/max_size = 20 + +/obj/item/circuit_component/list_literal/save_data_to_list(list/component_data) + . = ..() + component_data["length"] = length + +/obj/item/circuit_component/list_literal/load_data_from_list(list/component_data) + set_list_size(component_data["length"]) + + return ..() + +/obj/item/circuit_component/list_literal/proc/set_list_size(new_size) + if(new_size <= 0) + for(var/datum/port/input/port in input_ports) + if(port != trigger_input) + remove_input_port(port) + length = 0 + return + + while(length > new_size) + var/index = length(input_ports) + if(trigger_input) + index -= 1 + remove_input_port(input_ports[index]) + length-- + + while(length < new_size) + length++ + var/index = length(input_ports) + if(trigger_input) + index -= 1 + add_input_port("Index [index+1]", PORT_TYPE_ANY, index = index+1) + +/obj/item/circuit_component/list_literal/Initialize() + . = ..() + set_list_size(default_list_size) + list_output = add_output_port("Value", PORT_TYPE_LIST) + +/obj/item/circuit_component/list_literal/Destroy() + list_output = null + return ..() + +// Increases list length +/obj/item/circuit_component/list_literal/attack_self(mob/user, list/modifiers) + . = ..() + set_list_size(min(length + 1, max_size)) + balloon_alert(user, "new size is now [length]") + +// Decreases list length +/obj/item/circuit_component/list_literal/attack_self_secondary(mob/user, list/modifiers) + . = ..() + set_list_size(max(length - 1, min_size)) + balloon_alert(user, "new size is now [length]") + +/obj/item/circuit_component/list_literal/input_received(datum/port/input/port) + . = ..() + if(.) + return + + var/list/new_literal = list() + for(var/datum/port/input/input_port as anything in input_ports) + // Prevents lists from merging together + new_literal += list(input_port.input_value) + + list_output.set_output(new_literal) + diff --git a/code/modules/wiremod/components/utility/typecast.dm b/code/modules/wiremod/components/utility/typecast.dm new file mode 100644 index 00000000000..9375970d5be --- /dev/null +++ b/code/modules/wiremod/components/utility/typecast.dm @@ -0,0 +1,57 @@ +/** + * # Typecast Component + * + * A component that casts a value to a type if it matches or outputs null. + */ +/obj/item/circuit_component/typecast + display_name = "Typecast" + desc = "A component that casts a value to a type if it matches or outputs null." + circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL + + var/datum/port/input/input_value + + var/datum/port/output/output_value + + var/current_type + +/obj/item/circuit_component/typecast/Initialize() + . = ..() + current_type = current_option + input_value = add_input_port("Input", PORT_TYPE_ANY) + output_value = add_output_port("Output", current_option) + +/obj/item/circuit_component/typecast/populate_options() + var/static/component_options = list( + PORT_TYPE_STRING, + PORT_TYPE_NUMBER, + PORT_TYPE_LIST, + PORT_TYPE_ATOM, + ) + options = component_options + +/obj/item/circuit_component/typecast/input_received(datum/port/input/port) + . = ..() + if(current_type != current_option) + current_type = current_option + output_value.set_datatype(current_type) + + if(.) + return + + var/value = input_value.input_value + var/value_to_set = null + switch(current_option) + if(PORT_TYPE_STRING) + if(istext(value)) + value_to_set = value + if(PORT_TYPE_NUMBER) + if(isnum(value)) + value_to_set = value + if(PORT_TYPE_LIST) + if(islist(value)) + value_to_set = value + if(PORT_TYPE_ATOM) + if(isatom(value)) + value_to_set = value + + output_value.set_output(value_to_set) diff --git a/code/modules/wiremod/components/utility/typecheck.dm b/code/modules/wiremod/components/utility/typecheck.dm index 84392a44a26..e92313e5a78 100644 --- a/code/modules/wiremod/components/utility/typecheck.dm +++ b/code/modules/wiremod/components/utility/typecheck.dm @@ -9,15 +9,6 @@ input_port_amount = 1 -GLOBAL_LIST_INIT(comp_typecheck_options, list( - PORT_TYPE_STRING, - PORT_TYPE_NUMBER, - PORT_TYPE_LIST, - PORT_TYPE_ATOM, - COMP_TYPECHECK_MOB, - COMP_TYPECHECK_HUMAN, -)) - /obj/item/circuit_component/compare/typecheck/populate_options() var/static/component_options = list( PORT_TYPE_STRING, diff --git a/code/modules/wiremod/duplicator.dm b/code/modules/wiremod/duplicator.dm index d7546833206..7d0c31d61af 100644 --- a/code/modules/wiremod/duplicator.dm +++ b/code/modules/wiremod/duplicator.dm @@ -4,6 +4,7 @@ GLOBAL_LIST_INIT(circuit_dupe_whitelisted_types, list( PORT_TYPE_NUMBER, PORT_TYPE_STRING, + PORT_TYPE_LIST, PORT_TYPE_ANY, )) @@ -18,6 +19,8 @@ GLOBAL_LIST_INIT(circuit_dupe_whitelisted_types, list( if(general_data["display_name"]) set_display_name(general_data["display_name"]) + admin_only = general_data["admin_only"] + var/list/circuit_data = general_data["components"] var/list/identifiers_to_circuit = list() for(var/identifier in circuit_data) @@ -143,6 +146,7 @@ GLOBAL_LIST_INIT(circuit_dupe_whitelisted_types, list( general_data["components"] = circuit_data general_data["external_objects"] = external_objects_key general_data["display_name"] = display_name + general_data["admin_only"] = admin_only return json_encode(general_data) @@ -169,7 +173,7 @@ GLOBAL_LIST_INIT(circuit_dupe_whitelisted_types, list( set name = "Load Circuit" set category = "Admin.Fun" - if(!check_rights(R_ADMIN) || !check_rights(R_FUN)) + if(!check_rights(R_VAREDIT)) return var/list/errors = list() diff --git a/code/modules/wiremod/integrated_circuit.dm b/code/modules/wiremod/integrated_circuit.dm index 57dabd0ab24..a1c47472b51 100644 --- a/code/modules/wiremod/integrated_circuit.dm +++ b/code/modules/wiremod/integrated_circuit.dm @@ -33,6 +33,9 @@ /// Whether the integrated circuit is locked or not. Handled by the shell. var/locked = FALSE + /// Whether the integrated circuit is admin only. Disables power usage and allows admin circuits to be attached, at the cost of making it inaccessible to regular users. + var/admin_only = FALSE + /// The ID that is authorized to unlock/lock the shell so that the circuit can/cannot be removed. var/datum/weakref/owner_id @@ -272,7 +275,7 @@ .["examined_rel_x"] = examined_rel_x .["examined_rel_y"] = examined_rel_y - .["is_admin"] = check_rights_for(user.client, R_ADMIN) + .["is_admin"] = check_rights_for(user.client, R_VAREDIT) /obj/item/integrated_circuit/ui_host(mob/user) if(shell) @@ -284,6 +287,16 @@ return FALSE return ..() +/obj/item/integrated_circuit/ui_status(mob/user) + . = ..() + // Extra protection because ui_state will not close the UI if they already have the ui open, + // as ui_state is only set during + if(admin_only) + if(!check_rights_for(user.client, R_VAREDIT)) + return UI_CLOSE + else + return UI_INTERACTIVE + /obj/item/integrated_circuit/ui_state(mob/user) if(!shell) return GLOB.hands_state @@ -397,6 +410,14 @@ return var/obj/item/multitool/circuit/marker = usr.get_active_held_item() if(!istype(marker)) + var/client/user = usr.client + if(!check_rights_for(user, R_VAREDIT)) + return TRUE + var/atom/marked_atom = user.holder.marked_datum + if(!marked_atom) + return TRUE + port.set_input(marked_atom) + balloon_alert(usr, "updated [port.name]'s value to marked object.") return TRUE if(!marker.marked_atom) port.set_input(null) @@ -466,7 +487,7 @@ . = TRUE if("save_circuit") var/client/saver = usr.client - if(!check_rights_for(saver, R_ADMIN)) + if(!check_rights_for(saver, R_VAREDIT)) return var/temp_file = file("data/CircuitDownloadTempFile") fdel(temp_file) @@ -503,4 +524,4 @@ if(owner_id) id_card = owner_id.resolve() - return "(Shell: [shell || "*null*"], Inserter: [key_name(inserter, include_link)], Owner ID: [id_card?.name || "*null*"])" + return "[src] (Shell: [shell || "*null*"], Inserter: [key_name(inserter, include_link)], Owner ID: [id_card?.name || "*null*"])" diff --git a/code/modules/wiremod/port.dm b/code/modules/wiremod/port.dm index 8a195f9a897..d2c23b538d9 100644 --- a/code/modules/wiremod/port.dm +++ b/code/modules/wiremod/port.dm @@ -251,7 +251,7 @@ RegisterSignal(input_value, COMSIG_PARENT_QDELETING, .proc/null_output) SEND_SIGNAL(src, COMSIG_PORT_SET_INPUT, input_value) - if(trigger && send_update) + if(connected_component && trigger && send_update) TRIGGER_CIRCUIT_COMPONENT(connected_component, src) /// Signal handler proc to null the input if an atom is deleted. An update is not sent because this was not set by anything. diff --git a/code/modules/wiremod/shell/bot.dm b/code/modules/wiremod/shell/bot.dm index 30da1f9a1fe..f3c9fcae8d9 100644 --- a/code/modules/wiremod/shell/bot.dm +++ b/code/modules/wiremod/shell/bot.dm @@ -27,13 +27,17 @@ /// Called when attack_hand is called on the shell. var/datum/port/output/signal + /// The user who used the bot + var/datum/port/output/entity /obj/item/circuit_component/bot/Initialize() . = ..() + entity = add_output_port("User", PORT_TYPE_ATOM) signal = add_output_port("Signal", PORT_TYPE_SIGNAL) /obj/item/circuit_component/bot/Destroy() signal = null + entity = null return ..() /obj/item/circuit_component/bot/register_shell(atom/movable/shell) @@ -46,4 +50,6 @@ SIGNAL_HANDLER source.balloon_alert(user, "pushed button") playsound(source, get_sfx("terminal_type"), 25, FALSE) + entity.set_output(user) signal.set_output(COMPONENT_SIGNAL) + diff --git a/code/modules/wiremod/shell/compact_remote.dm b/code/modules/wiremod/shell/compact_remote.dm index c1f99e55251..d5fe33e2858 100644 --- a/code/modules/wiremod/shell/compact_remote.dm +++ b/code/modules/wiremod/shell/compact_remote.dm @@ -26,9 +26,12 @@ /// Called when attack_self is called on the shell. var/datum/port/output/signal + /// The user who used the bot + var/datum/port/output/entity /obj/item/circuit_component/compact_remote/Initialize() . = ..() + entity = add_output_port("User", PORT_TYPE_ATOM) signal = add_output_port("Signal", PORT_TYPE_SIGNAL) /obj/item/circuit_component/compact_remote/register_shell(atom/movable/shell) @@ -44,4 +47,5 @@ SIGNAL_HANDLER source.balloon_alert(user, "clicked primary button") playsound(source, get_sfx("terminal_type"), 25, FALSE) + entity.set_output(user) signal.set_output(COMPONENT_SIGNAL) diff --git a/code/modules/wiremod/shell/controller.dm b/code/modules/wiremod/shell/controller.dm index 937160824b1..20b08ca8262 100644 --- a/code/modules/wiremod/shell/controller.dm +++ b/code/modules/wiremod/shell/controller.dm @@ -30,8 +30,12 @@ var/datum/port/output/alt var/datum/port/output/right + /// The entity output + var/datum/port/output/entity + /obj/item/circuit_component/controller/Initialize() . = ..() + entity = add_output_port("User", PORT_TYPE_ATOM) signal = add_output_port("Signal", PORT_TYPE_SIGNAL) alt = add_output_port("Alternate Signal", PORT_TYPE_SIGNAL) right = add_output_port("Extra Signal", PORT_TYPE_SIGNAL) @@ -57,6 +61,7 @@ return source.balloon_alert(user, "clicked primary button") playsound(source, get_sfx("terminal_type"), 25, FALSE) + entity.set_output(user) signal.set_output(COMPONENT_SIGNAL) /** @@ -68,6 +73,7 @@ return source.balloon_alert(user, "clicked alternate button") playsound(source, get_sfx("terminal_type"), 25, FALSE) + entity.set_output(user) alt.set_output(COMPONENT_SIGNAL) /obj/item/circuit_component/controller/proc/send_right_signal(atom/source, mob/user) @@ -76,4 +82,5 @@ return source.balloon_alert(user, "clicked extra button") playsound(source, get_sfx("terminal_type"), 25, FALSE) + entity.set_output(user) right.set_output(COMPONENT_SIGNAL) diff --git a/code/modules/wiremod/shell/moneybot.dm b/code/modules/wiremod/shell/moneybot.dm index 205de700529..ee9068a57a9 100644 --- a/code/modules/wiremod/shell/moneybot.dm +++ b/code/modules/wiremod/shell/moneybot.dm @@ -90,11 +90,14 @@ var/datum/port/output/money_input /// Trigger for when money is inputted into the shell var/datum/port/output/money_trigger + /// The person who input the money + var/datum/port/output/entity /obj/item/circuit_component/money_bot/Initialize() . = ..() total_money = add_output_port("Total Money", PORT_TYPE_NUMBER) money_input = add_output_port("Last Input Money", PORT_TYPE_NUMBER) + entity = add_output_port("User", PORT_TYPE_ATOM) money_trigger = add_output_port("Money Input", PORT_TYPE_SIGNAL) /obj/item/circuit_component/money_bot/register_shell(atom/movable/shell) @@ -127,6 +130,7 @@ attached_bot.add_money(amount_to_insert) balloon_alert(attacker, "inserted [amount_to_insert] credits.") money_input.set_output(amount_to_insert) + entity.set_output(attacker) money_trigger.set_output(COMPONENT_SIGNAL) qdel(item) diff --git a/html/changelogs/AutoChangeLog-pr-60186.yml b/html/changelogs/AutoChangeLog-pr-60186.yml new file mode 100644 index 00000000000..d26517f0ffc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-60186.yml @@ -0,0 +1,4 @@ +author: "carshalash" +delete-after: True +changes: + - bugfix: "Eggs now work when cracked into glasses" diff --git a/tgstation.dme b/tgstation.dme index 4e47fc38e2b..7e7b91bbb5d 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3697,6 +3697,12 @@ #include "code\modules\wiremod\components\action\radio.dm" #include "code\modules\wiremod\components\action\soundemitter.dm" #include "code\modules\wiremod\components\action\speech.dm" +#include "code\modules\wiremod\components\admin\getvar.dm" +#include "code\modules\wiremod\components\admin\proccall.dm" +#include "code\modules\wiremod\components\admin\sdql.dm" +#include "code\modules\wiremod\components\admin\setvar.dm" +#include "code\modules\wiremod\components\admin\spawn.dm" +#include "code\modules\wiremod\components\admin\to_type.dm" #include "code\modules\wiremod\components\atom\direction.dm" #include "code\modules\wiremod\components\atom\gps.dm" #include "code\modules\wiremod\components\atom\health.dm" @@ -3711,6 +3717,7 @@ #include "code\modules\wiremod\components\list\get_column.dm" #include "code\modules\wiremod\components\list\index.dm" #include "code\modules\wiremod\components\list\index_table.dm" +#include "code\modules\wiremod\components\list\list_literal.dm" #include "code\modules\wiremod\components\list\select.dm" #include "code\modules\wiremod\components\list\split.dm" #include "code\modules\wiremod\components\math\arithmetic.dm" @@ -3731,6 +3738,7 @@ #include "code\modules\wiremod\components\utility\delay.dm" #include "code\modules\wiremod\components\utility\multiplexer.dm" #include "code\modules\wiremod\components\utility\ram.dm" +#include "code\modules\wiremod\components\utility\typecast.dm" #include "code\modules\wiremod\components\utility\typecheck.dm" #include "code\modules\wiremod\preset\hello_world.dm" #include "code\modules\wiremod\preset\speech_relay.dm" diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/index.js b/tgui/packages/tgui/interfaces/IntegratedCircuit/index.js index 2c6f2e61702..7320f0b59fa 100644 --- a/tgui/packages/tgui/interfaces/IntegratedCircuit/index.js +++ b/tgui/packages/tgui/interfaces/IntegratedCircuit/index.js @@ -238,16 +238,20 @@ export class IntegratedCircuit extends Component { + buttons={( + - act('set_display_name', { display_name: value })} + onChange={(e, value) => act("set_display_name", { display_name: value })} /> {!!is_admin && ( @@ -256,14 +260,15 @@ export class IntegratedCircuit extends Component { position="absolute" top={0} color="transparent" - onClick={() => act('save_circuit')} + onClick={() => act("save_circuit")} icon="save" /> )} - }> + )} + >