/** * # Module Component * * A component that has an input, output */ /obj/item/circuit_component/module display_name = "Module" desc = "A component that has other components within it, acting like a function. Use it in your hand to control the amount of input and output ports it has, as well as being able to access the integrated circuit contained inside." var/obj/item/integrated_circuit/module/internal_circuit var/obj/item/circuit_component/module_input/input_component var/obj/item/circuit_component/module_output/output_component /// Linked ports that follow a `first_port = second_port` keyed structure. var/list/linked_ports = list() var/port_limit = 10 /obj/item/integrated_circuit/module var/obj/item/circuit_component/module/attached_module /obj/item/integrated_circuit/module/ui_host(mob/user) . = ..() if(. == src) return attached_module /obj/item/integrated_circuit/module/set_display_name(new_name) . = ..() attached_module.display_name = new_name attached_module.name = "module ([new_name])" /obj/item/integrated_circuit/module/load_component(type) if(!attached_module) return ..() if(ispath(type, /obj/item/circuit_component/module_input)) return attached_module.input_component if(ispath(type, /obj/item/circuit_component/module_output)) return attached_module.output_component return ..() /obj/item/integrated_circuit/module/Destroy() attached_module = null return ..() /obj/item/circuit_component/module_input display_name = "Input" desc = "A component that receives data from the module it is attached to" removable = FALSE /// The currently attached module var/obj/item/circuit_component/module/attached_module /obj/item/circuit_component/module_input/Destroy() attached_module = null return ..() /obj/item/circuit_component/module_output display_name = "Output" desc = "A component that outputs data to the module it is attached to." removable = FALSE /// The currently attached module var/obj/item/circuit_component/module/attached_module /obj/item/circuit_component/module_output/input_received(datum/port/input/port) . = ..() if(!port) return // We don't check the parent here because frankly, we don't care. We only sync our input with the module's output var/datum/port/output/port_to_update = attached_module.linked_ports[port] if(!port_to_update) CRASH("[port.type] doesn't have a linked port in [type]!") port_to_update.set_output(port.value) /obj/item/circuit_component/module/input_received(datum/port/input/port) . = ..() if(!port) return var/datum/port/output/port_to_update = linked_ports[port] if(!port_to_update) CRASH("[port.type] doesn't have a linked port in [type]!") port_to_update.set_output(port.value) /obj/item/circuit_component/module_output/Destroy() attached_module = null return ..() /obj/item/circuit_component/module/Initialize() . = ..() internal_circuit = new(src) internal_circuit.attached_module = src input_component = new(internal_circuit) input_component.attached_module = src internal_circuit.add_component(input_component) input_component.rel_x = 0 input_component.rel_y = 200 output_component = new(internal_circuit) output_component.attached_module = src internal_circuit.add_component(output_component) output_component.rel_x = 400 output_component.rel_y = 200 /obj/item/circuit_component/module/save_data_to_list(list/component_data) . = ..() component_data["integrated_circuit"] = internal_circuit.convert_to_json() var/list/input_data = list() for(var/datum/port/input/input_port as anything in input_ports) input_data += list(list( "name" = input_port.name, "type" = input_port.datatype, )) var/list/output_data = list() for(var/datum/port/output/output_port as anything in output_ports) output_data += list(list( "name" = output_port.name, "type" = output_port.datatype, )) component_data["input_ports"] = input_data component_data["output_ports"] = output_data /obj/item/circuit_component/module/load_data_from_list(list/component_data) . = ..() var/list/input_ports = component_data["input_ports"] for(var/list/port_data as anything in input_ports) add_and_link_input_port(port_data["name"], port_data["type"]) var/list/output_ports = component_data["output_ports"] for(var/list/port_data as anything in output_ports) add_and_link_output_port(port_data["name"], port_data["type"]) if(component_data["integrated_circuit"]) internal_circuit.load_circuit_data(component_data["integrated_circuit"]) /obj/item/circuit_component/module/proc/add_and_link_input_port(name, type) var/datum/port/new_port = add_input_port(name, type) linked_ports[new_port] = input_component.add_output_port(name, type) /obj/item/circuit_component/module/proc/add_and_link_output_port(name, type) var/datum/port/new_port = output_component.add_input_port(name, type) linked_ports[new_port] = add_output_port(name, type) /obj/item/circuit_component/module/add_to(obj/item/integrated_circuit/added_to) . = ..() RegisterSignal(added_to, COMSIG_CIRCUIT_SET_CELL, .proc/handle_set_cell) RegisterSignal(added_to, COMSIG_CIRCUIT_SET_ON, .proc/handle_set_on) RegisterSignal(added_to, COMSIG_CIRCUIT_SET_SHELL, .proc/handle_set_shell) internal_circuit.set_cell(added_to.cell) internal_circuit.set_shell(added_to.shell) internal_circuit.set_on(added_to.on) /obj/item/circuit_component/module/removed_from(obj/item/integrated_circuit/removed_from) internal_circuit.set_cell(null) internal_circuit.set_on(FALSE) internal_circuit.remove_current_shell() UnregisterSignal(removed_from, list( COMSIG_CIRCUIT_SET_CELL, COMSIG_CIRCUIT_SET_ON, COMSIG_CIRCUIT_SET_SHELL, )) return ..() /obj/item/circuit_component/module/proc/handle_set_cell(datum/source, obj/item/stock_parts/cell/cell) SIGNAL_HANDLER internal_circuit.set_cell(cell) /obj/item/circuit_component/module/proc/handle_set_on(datum/source, new_value) SIGNAL_HANDLER internal_circuit.set_on(new_value) /obj/item/circuit_component/module/proc/handle_set_shell(datum/source, atom/movable/new_shell) SIGNAL_HANDLER internal_circuit.set_shell(new_shell) /obj/item/circuit_component/module/Destroy() QDEL_NULL(input_component) QDEL_NULL(output_component) QDEL_NULL(internal_circuit) linked_ports = null return ..() /obj/item/circuit_component/module/ui_data(mob/user) . = list() .["input_ports"] = list() for(var/datum/port/input/input_port as anything in input_ports) .["input_ports"] += list(list( "name" = input_port.name, "type" = input_port.datatype, )) .["output_ports"] = list() for(var/datum/port/output/output_port as anything in output_ports) .["output_ports"] += list(list( "name" = output_port.name, "type" = output_port.datatype, )) /obj/item/circuit_component/module/ui_static_data(mob/user) . = list() .["global_port_types"] = GLOB.wiremod_basic_types /obj/item/circuit_component/module/attackby(obj/item/I, mob/living/user, params) if(istype(I, /obj/item/circuit_component)) internal_circuit.attackby(I, user, params) return return ..() #define WITHIN_RANGE(id, table) (id >= 1 && id <= length(table)) /obj/item/circuit_component/module/ui_act(action, list/params) . = ..() if(.) return switch(action) if("open_internal_circuit") internal_circuit.interact(usr) . = TRUE if("add_input_port") if(length(input_ports) > port_limit) return add_and_link_input_port("Input Port", PORT_TYPE_ANY) . = TRUE if("remove_input_port") var/port_id = text2num(params["port_id"]) if(!WITHIN_RANGE(port_id, input_ports)) return var/datum/port/removed_port = input_ports[port_id] linked_ports -= removed_port remove_input_port(removed_port) input_component.remove_output_port(input_component.output_ports[port_id]) . = TRUE if("add_output_port") if(length(output_ports) > port_limit) return add_and_link_output_port("Output Port", PORT_TYPE_ANY) . = TRUE if("remove_output_port") var/port_id = text2num(params["port_id"]) if(!WITHIN_RANGE(port_id, output_ports)) return var/datum/port/removed_port = output_component.input_ports[port_id] linked_ports -= removed_port remove_output_port(output_ports[port_id]) output_component.remove_input_port(removed_port) . = TRUE if("set_port_name", "set_port_type") var/port_id = text2num(params["port_id"]) var/is_input = params["is_input"] var/list/ports_to_use var/list/internal_ports_to_use if(is_input) ports_to_use = input_ports internal_ports_to_use = input_component.output_ports else ports_to_use = output_ports internal_ports_to_use = output_component.input_ports if(!WITHIN_RANGE(port_id, ports_to_use)) return var/datum/port/component_port = ports_to_use[port_id] var/datum/port/internal_component_port = internal_ports_to_use[port_id] if(action == "set_port_type") var/type = params["port_type"] if(!(type in GLOB.wiremod_basic_types)) return component_port.set_datatype(type) internal_component_port.set_datatype(type) else var/port_name = params["port_name"] if(!port_name) return port_name = strip_html(port_name, PORT_MAX_NAME_LENGTH) component_port.name = port_name internal_component_port.name = port_name . = TRUE if(.) SStgui.update_uis(internal_circuit) #undef WITHIN_RANGE /obj/item/circuit_component/module/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) ui = new(user, src, "CircuitModule", name) ui.open() ui.set_autoupdate(FALSE)