From b6c170eadd9b96262ab4f623579fed2729cc8c9a Mon Sep 17 00:00:00 2001 From: Neerti Date: Wed, 25 Jan 2017 19:31:21 -0500 Subject: [PATCH] Does tons of stuff, see PR for details. --- .../technomancer/devices/gloves_of_regen.dm | 2 +- code/game/jobs/access.dm | 10 +- code/game/machinery/recharger.dm | 22 +- .../integrated_electronics/_defines.dm | 383 +----------------- .../{ => core}/assemblies.dm | 172 ++++++-- .../integrated_electronics/core/helpers.dm | 44 ++ .../core/integrated_circuit.dm | 282 +++++++++++++ .../integrated_electronics/core/pins.dm | 139 +++++++ .../{ => core}/tools.dm | 131 +++++- .../integrated_electronics/data_transfer.dm | 85 ---- .../integrated_electronics/passive/passive.dm | 7 + .../integrated_electronics/passive/power.dm | 109 +++++ .../{ => subtypes}/arithmetic.dm | 1 + .../{ => subtypes}/converters.dm | 1 + .../subtypes/data_transfer.dm | 186 +++++++++ .../{ => subtypes}/input_output.dm | 193 ++++++++- .../{ => subtypes}/logic.dm | 21 +- .../{ => subtypes}/manipulation.dm | 13 +- .../{ => subtypes}/memory.dm | 7 + .../integrated_electronics/subtypes/power.dm | 80 ++++ .../{ => subtypes}/reagents.dm | 3 + .../integrated_electronics/subtypes/smart.dm | 33 ++ .../{ => subtypes}/time.dm | 5 + .../{ => subtypes}/trig.dm | 3 +- .../integrated_electronics/~defines.dm | 6 - .../~defines/~defines.dm | 16 + code/unit_tests/integrated_circuits/logic.dm | 26 ++ icons/obj/electronic_assemblies.dmi | Bin 30877 -> 32741 bytes polaris.dme | 33 +- 29 files changed, 1478 insertions(+), 535 deletions(-) rename code/modules/integrated_electronics/{ => core}/assemblies.dm (51%) create mode 100644 code/modules/integrated_electronics/core/helpers.dm create mode 100644 code/modules/integrated_electronics/core/integrated_circuit.dm create mode 100644 code/modules/integrated_electronics/core/pins.dm rename code/modules/integrated_electronics/{ => core}/tools.dm (71%) delete mode 100644 code/modules/integrated_electronics/data_transfer.dm create mode 100644 code/modules/integrated_electronics/passive/passive.dm create mode 100644 code/modules/integrated_electronics/passive/power.dm rename code/modules/integrated_electronics/{ => subtypes}/arithmetic.dm (99%) rename code/modules/integrated_electronics/{ => subtypes}/converters.dm (99%) create mode 100644 code/modules/integrated_electronics/subtypes/data_transfer.dm rename code/modules/integrated_electronics/{ => subtypes}/input_output.dm (76%) rename code/modules/integrated_electronics/{ => subtypes}/logic.dm (87%) rename code/modules/integrated_electronics/{ => subtypes}/manipulation.dm (90%) rename code/modules/integrated_electronics/{ => subtypes}/memory.dm (96%) create mode 100644 code/modules/integrated_electronics/subtypes/power.dm rename code/modules/integrated_electronics/{ => subtypes}/reagents.dm (98%) create mode 100644 code/modules/integrated_electronics/subtypes/smart.dm rename code/modules/integrated_electronics/{ => subtypes}/time.dm (97%) rename code/modules/integrated_electronics/{ => subtypes}/trig.dm (97%) delete mode 100644 code/modules/integrated_electronics/~defines.dm create mode 100644 code/modules/integrated_electronics/~defines/~defines.dm diff --git a/code/game/gamemodes/technomancer/devices/gloves_of_regen.dm b/code/game/gamemodes/technomancer/devices/gloves_of_regen.dm index 9c18e774ed6..a4761c847a3 100644 --- a/code/game/gamemodes/technomancer/devices/gloves_of_regen.dm +++ b/code/game/gamemodes/technomancer/devices/gloves_of_regen.dm @@ -47,7 +47,7 @@ ..() /obj/item/clothing/gloves/regen/process() - if(!wearer || wearer.isSynthetic() || wearer.stat == DEAD || wearer.nutrition >= 10) + if(!wearer || wearer.isSynthetic() || wearer.stat == DEAD || wearer.nutrition <= 10) return // Robots and dead people don't have a metabolism. if(wearer.getBruteLoss()) diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm index f9bbeb8f33a..c354d655765 100644 --- a/code/game/jobs/access.dm +++ b/code/game/jobs/access.dm @@ -14,8 +14,12 @@ return check_access(id) return 0 -/obj/item/proc/GetAccess() - return list() +///obj/item/proc/GetAccess() +// return list() + +/atom/movable/proc/GetAccess() + var/obj/item/weapon/card/id/id = GetIdCard() + return id ? id.GetAccess() : list() /obj/proc/GetID() return null @@ -197,7 +201,7 @@ "Emergency Response Team", "Emergency Response Team Leader") -/mob/proc/GetIdCard() +/atom/movable/proc/GetIdCard() return null /mob/living/bot/GetIdCard() diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index 13168e19f46..43497523708 100644 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -8,7 +8,7 @@ obj/machinery/recharger idle_power_usage = 4 active_power_usage = 40000 //40 kW var/obj/item/charging = null - var/list/allowed_devices = list(/obj/item/weapon/gun/energy, /obj/item/weapon/melee/baton, /obj/item/device/laptop, /obj/item/weapon/cell, /obj/item/device/flashlight) + var/list/allowed_devices = list(/obj/item/weapon/gun/energy, /obj/item/weapon/melee/baton, /obj/item/device/laptop, /obj/item/weapon/cell, /obj/item/device/flashlight, /obj/item/device/electronic_assembly) var/icon_state_charged = "recharger2" var/icon_state_charging = "recharger1" var/icon_state_idle = "recharger0" //also when unpowered @@ -60,6 +60,11 @@ obj/machinery/recharger if(!L.stored_computer.battery) user << "There's no battery in it!" return + if(istype(G, /obj/item/device/electronic_assembly)) + var/obj/item/device/electronic_assembly/assembly = G + if(!assembly.battery) + to_chat(user, "The assembly doesn't have a power cell.") + return user.drop_item() G.loc = src charging = G @@ -161,6 +166,21 @@ obj/machinery/recharger update_use_power(1) return + if(istype(charging, /obj/item/device/electronic_assembly)) + var/obj/item/device/electronic_assembly/assembly = charging + if(assembly.battery) + if(!assembly.battery.fully_charged()) + icon_state = icon_state_charging + assembly.battery.give(active_power_usage*CELLRATE) + update_use_power(2) + else + icon_state = icon_state_charged + update_use_power(1) + else + icon_state = icon_state_idle + update_use_power(1) + return + /obj/machinery/recharger/emp_act(severity) if(stat & (NOPOWER|BROKEN) || !anchored) ..(severity) diff --git a/code/modules/integrated_electronics/_defines.dm b/code/modules/integrated_electronics/_defines.dm index d9daa035d54..c404f615812 100644 --- a/code/modules/integrated_electronics/_defines.dm +++ b/code/modules/integrated_electronics/_defines.dm @@ -8,6 +8,13 @@ #define IC_SPAWN_DEFAULT 1 // If the circuit comes in the default circuit box. #define IC_SPAWN_RESEARCH 2 // If the circuit design will be autogenerated for RnD. +#define IC_FORMAT_STRING "\" +#define IC_FORMAT_NUMBER "\" +#define IC_FORMAT_REF "\" +#define IC_FORMAT_LIST "\" +#define IC_FORMAT_ANY "\" +#define IC_FORMAT_PULSE "\" + var/list/all_integrated_circuits = list() /proc/initialize_integrated_circuits_list() @@ -20,377 +27,19 @@ var/list/all_integrated_circuits = list() icon = 'icons/obj/electronic_assemblies.dmi' icon_state = "template" w_class = ITEMSIZE_TINY + var/obj/item/device/electronic_assembly/assembly = null // Reference to the assembly holding this circuit, if any. var/extended_desc = null var/list/inputs = list() var/list/outputs = list() var/list/activators = list() var/next_use = 0 //Uses world.time - var/complexity = 1 //This acts as a limitation on building machines, more resource-intensive components cost more 'space'. - var/cooldown_per_use = 1 SECOND - var/spawn_flags = null // Used for world initializing, see the #defines above. - var/category_text = "NO CATEGORY" // To show up on circuit printer, and perhaps other places. - var/autopulse = -1 // When input is received, the circuit will pulse itself if set to 1. 0 means it won't. -1 means it is permanently off. - -/obj/item/integrated_circuit/examine(mob/user) - ..() - to_chat(user, "This board has [inputs.len] input pin\s and [outputs.len] output pin\s.") - for(var/datum/integrated_io/input/I in inputs) - if(I.linked.len) - to_chat(user, "The [I] is connected to [I.get_linked_to_desc()].") - for(var/datum/integrated_io/output/O in outputs) - if(O.linked.len) - to_chat(user, "The [O] is connected to [O.get_linked_to_desc()].") - for(var/datum/integrated_io/activate/A in activators) - if(A.linked.len) - to_chat(user, "The [A] is connected to [A.get_linked_to_desc()].") - - interact(user) - -/obj/item/integrated_circuit/New() - setup_io(inputs, /datum/integrated_io/input) - setup_io(outputs, /datum/integrated_io/output) - setup_io(activators, /datum/integrated_io/activate) - ..() - -/obj/item/integrated_circuit/proc/setup_io(var/list/io_list, var/io_type) - var/list/io_list_copy = io_list.Copy() - io_list.Cut() - for(var/io_entry in io_list_copy) - io_list.Add(new io_type(src, io_entry, io_list_copy[io_entry])) - -/obj/item/integrated_circuit/proc/on_data_written() //Override this for special behaviour when new data gets pushed to the circuit. - return - -/obj/item/integrated_circuit/Destroy() - for(var/datum/integrated_io/I in inputs) - qdel(I) - for(var/datum/integrated_io/O in outputs) - qdel(O) - for(var/datum/integrated_io/A in activators) - qdel(A) - . = ..() - -/obj/item/integrated_circuit/nano_host() - if(istype(src.loc, /obj/item/device/electronic_assembly)) - var/obj/item/device/electronic_assembly/assembly = loc - return assembly.resolve_nano_host() - return ..() - -/obj/item/integrated_circuit/emp_act(severity) - for(var/datum/integrated_io/io in inputs + outputs + activators) - io.scramble() - -/obj/item/integrated_circuit/verb/rename_component() - set name = "Rename Circuit" - set category = "Object" - set desc = "Rename your circuit, useful to stay organized." - - var/mob/M = usr - if(!CanInteract(M, physical_state)) - return - - var/input = sanitizeSafe(input("What do you want to name the circuit?", "Rename", src.name) as null|text, MAX_NAME_LEN) - if(src && input && CanInteract(M, physical_state)) - to_chat(M, "The circuit '[src.name]' is now labeled '[input]'.") - name = input - -/obj/item/integrated_circuit/proc/get_pin_ref(var/pin_type, var/pin_number) - switch(pin_type) - if(IC_INPUT) - if(pin_number > inputs.len) - return null - return inputs[pin_number] - if(IC_OUTPUT) - if(pin_number > outputs.len) - return null - return outputs[pin_number] - if(IC_ACTIVATOR) - if(pin_number > activators.len) - return null - return activators[pin_number] - return null - -/obj/item/integrated_circuit/interact(mob/user) - if(!CanInteract(user, physical_state)) - return - - var/window_height = 350 - var/window_width = 600 - - //var/table_edge_width = "[(window_width - window_width * 0.1) / 4]px" - //var/table_middle_width = "[(window_width - window_width * 0.1) - (table_edge_width * 2)]px" - var/table_edge_width = "30%" - var/table_middle_width = "40%" - - var/HTML = list() - HTML += "[src.name]" - HTML += "
" - HTML += "" - - HTML += "
\[Refresh\] | " - HTML += "\[Rename\] | " - HTML += "\[Remove\]
" - - HTML += "" - //HTML += "" - //HTML += "" - //HTML += "" - HTML += "" - HTML += "" - HTML += "" - HTML += "" - - var/column_width = 3 - var/row_height = max(inputs.len, outputs.len, 1) - - for(var/i = 1 to row_height) - HTML += "" - for(var/j = 1 to column_width) - var/datum/integrated_io/io = null - var/words = list() - var/height = 1 - switch(j) - if(1) - io = get_pin_ref(IC_INPUT, i) - if(io) - if(io.linked.len) - words += "[io.name] [io.display_data()]
" - for(var/datum/integrated_io/linked in io.linked) - words += "\[[linked.name]\] \ - @ [linked.holder]
" - else - words += "[io.name] [io.display_data()]
" - for(var/datum/integrated_io/linked in io.linked) - words += "\[[linked.name]\] \ - @ [linked.holder]
" - if(outputs.len > inputs.len) - height = 1 - if(2) - if(i == 1) - words += "[src.name]

[src.desc]" - height = row_height - else - continue - if(3) - io = get_pin_ref(IC_OUTPUT, i) - if(io) - if(io.linked.len) - words += "[io.name] [io.display_data()]
" - for(var/datum/integrated_io/linked in io.linked) - words += "\[[linked.name]\] \ - @ [linked.holder]
" - else - words += "[io.name] [io.display_data()]
" - for(var/datum/integrated_io/linked in io.linked) - words += "\[[linked.name]\] \ - @ [linked.holder]
" - if(inputs.len > outputs.len) - height = 1 - HTML += "" - HTML += "" - - for(var/activator in activators) - var/datum/integrated_io/io = activator - var/words = list() - if(io.linked.len) - words += "[io.name]
" - for(var/datum/integrated_io/linked in io.linked) - words += "\[[linked.name]\] \ - @ [linked.holder]
" - else - words += "[io.name]
" - for(var/datum/integrated_io/linked in io.linked) - words += "\[[linked.name]\] \ - @ [linked.holder]
" - HTML += "" - HTML += "" - HTML += "" - - HTML += "
[jointext(words, null)]
[jointext(words, null)]
" - HTML += "
" - - if(autopulse != -1) - HTML += "
Meta Variables;" - HTML += "
\[Autopulse\] = [autopulse ? "ON" : "OFF"]" - HTML += "
" - - HTML += "
Complexity: [complexity]" - HTML += "
[extended_desc]" - - HTML += "" - user << browse(jointext(HTML, null), "window=circuit-\ref[src];size=[window_width]x[window_height];border=1;can_resize=1;can_close=1;can_minimize=1") - - onclose(user, "circuit-\ref[src]") - -/obj/item/integrated_circuit/Topic(href, href_list, state = physical_state) - if(..()) - return 1 - var/pin = locate(href_list["pin"]) in inputs + outputs + activators - - var/obj/held_item = usr.get_active_hand() - if(href_list["wire"]) - if(istype(held_item, /obj/item/device/integrated_electronics/wirer)) - var/obj/item/device/integrated_electronics/wirer/wirer = held_item - if(pin) - wirer.wire(pin, usr) - - else if(istype(held_item, /obj/item/device/integrated_electronics/debugger)) - var/obj/item/device/integrated_electronics/debugger/debugger = held_item - if(pin) - debugger.write_data(pin, usr) - else - to_chat(usr, "You can't do a whole lot without the proper tools.") - - if(href_list["examine"]) - examine(usr) - - if(href_list["rename"]) - rename_component(usr) - - if(href_list["autopulse"]) - if(autopulse != -1) - autopulse = !autopulse - - if(href_list["remove"]) - if(istype(held_item, /obj/item/weapon/screwdriver)) - disconnect_all() - var/turf/T = get_turf(src) - forceMove(T) - playsound(T, 'sound/items/Crowbar.ogg', 50, 1) - to_chat(usr, "You pop \the [src] out of the case, and slide it out.") - else - to_chat(usr, "You need a screwdriver to remove components.") - var/obj/item/device/electronic_assembly/ea = loc - if(istype(ea)) - ea.interact(usr) - return - - interact(usr) // To refresh the UI. - -/datum/integrated_io - var/name = "input/output" - var/obj/item/integrated_circuit/holder = null - var/weakref/data = null // This is a weakref, to reduce typecasts. Note that oftentimes numbers and text may also occupy this. - var/list/linked = list() - var/io_type = DATA_CHANNEL - -/datum/integrated_io/New(var/newloc, var/name, var/data) - ..() - src.name = name - src.data = data - holder = newloc - if(!istype(holder)) - message_admins("ERROR: An integrated_io ([src.name]) spawned without a valid holder! This is a bug.") - -/datum/integrated_io/Destroy() - disconnect() - data = null - holder = null - . = ..() - -/datum/integrated_io/nano_host() - return holder.nano_host() + var/complexity = 1 //This acts as a limitation on building machines, more resource-intensive components cost more 'space'. + var/cooldown_per_use = 1 SECOND // Circuits are limited in how many times they can be work()'d by this variable. + var/power_draw_per_use = 0 // How much power is drawn when work()'d. + var/power_draw_idle = 0 // How much power is drawn when doing nothing. + var/spawn_flags = null // Used for world initializing, see the #defines above. + var/category_text = "NO CATEGORY THIS IS A BUG" // To show up on circuit printer, and perhaps other places. + var/autopulse = -1 // When input is received, the circuit will pulse itself if set to 1. 0 means it won't. -1 means it is permanently off. + var/removable = TRUE // Determines if a circuit is removable from the assembly. -/datum/integrated_io/proc/data_as_type(var/as_type) - if(!isweakref(data)) - return - var/weakref/w = data - var/output = w.resolve() - return istype(output, as_type) ? output : null - -/datum/integrated_io/proc/display_data() - if(isnull(data)) - return "(null)" // Empty data means nothing to show. - if(istext(data)) - return "(\"[data]\")" // Wraps the 'string' in escaped quotes, so that people know it's a 'string'. - if(isweakref(data)) - var/weakref/w = data - var/atom/A = w.resolve() - //return A ? "([A.name] \[Ref\])" : "(null)" // For refs, we want just the name displayed. - return A ? "(\ref[A] \[Ref\])" : "(null)" - return "([data])" // Nothing special needed for numbers or other stuff. - -/datum/integrated_io/activate/display_data() - return "(\[pulse\])" - -/datum/integrated_io/proc/scramble() - if(isnull(data)) - return - if(isnum(data)) - write_data_to_pin(rand(-10000, 10000)) - if(istext(data)) - write_data_to_pin("ERROR") - push_data() - -/datum/integrated_io/activate/scramble() - push_data() - -/datum/integrated_io/proc/write_data_to_pin(var/new_data) - if(isnull(new_data) || isnum(new_data) || istext(new_data) || isweakref(new_data)) // Anything else is a type we don't want. - data = new_data - holder.on_data_written() - -/datum/integrated_io/proc/push_data() - for(var/datum/integrated_io/io in linked) - io.write_data_to_pin(data) - -/datum/integrated_io/activate/push_data() - for(var/datum/integrated_io/io in linked) - io.holder.check_then_do_work() - -/datum/integrated_io/proc/pull_data() - for(var/datum/integrated_io/io in linked) - write_data_to_pin(io.data) - -/datum/integrated_io/proc/get_linked_to_desc() - if(linked.len) - return "the [english_list(linked)]" - return "nothing" - -/datum/integrated_io/proc/disconnect() - //First we iterate over everything we are linked to. - for(var/datum/integrated_io/their_io in linked) - //While doing that, we iterate them as well, and disconnect ourselves from them. - for(var/datum/integrated_io/their_linked_io in their_io.linked) - if(their_linked_io == src) - their_io.linked.Remove(src) - else - continue - //Now that we're removed from them, we gotta remove them from us. - src.linked.Remove(their_io) - -/datum/integrated_io/input - name = "input pin" - -/datum/integrated_io/output - name = "output pin" - -/datum/integrated_io/activate - name = "activation pin" - io_type = PULSE_CHANNEL - -/obj/item/integrated_circuit/proc/push_data() - for(var/datum/integrated_io/output/O in outputs) - O.push_data() - -/obj/item/integrated_circuit/proc/pull_data() - for(var/datum/integrated_io/input/I in inputs) - I.push_data() - -/obj/item/integrated_circuit/proc/check_then_do_work() - if(world.time < next_use) // All intergrated circuits have an internal cooldown, to protect from spam. - return - next_use = world.time + cooldown_per_use - do_work() - -/obj/item/integrated_circuit/proc/do_work() - return - -/obj/item/integrated_circuit/proc/disconnect_all() - for(var/datum/integrated_io/input/I in inputs) - I.disconnect() - for(var/datum/integrated_io/output/O in outputs) - O.disconnect() - for(var/datum/integrated_io/activate/A in activators) - A.disconnect() \ No newline at end of file diff --git a/code/modules/integrated_electronics/assemblies.dm b/code/modules/integrated_electronics/core/assemblies.dm similarity index 51% rename from code/modules/integrated_electronics/assemblies.dm rename to code/modules/integrated_electronics/core/assemblies.dm index ff994aa43c4..88b804f80a3 100644 --- a/code/modules/integrated_electronics/assemblies.dm +++ b/code/modules/integrated_electronics/core/assemblies.dm @@ -11,6 +11,7 @@ var/max_components = IC_COMPONENTS_BASE var/max_complexity = IC_COMPLEXITY_BASE var/opened = 0 + var/obj/item/weapon/cell/device/battery = null // Internal cell which most circuits need to work. /obj/item/device/electronic_assembly/medium name = "electronic mechanism" @@ -23,8 +24,8 @@ name = "electronic machine" icon_state = "setup_large" w_class = ITEMSIZE_LARGE - max_components = IC_COMPONENTS_BASE * 3 - max_complexity = IC_COMPLEXITY_BASE * 3 + max_components = IC_COMPONENTS_BASE * 4 + max_complexity = IC_COMPLEXITY_BASE * 4 /obj/item/device/electronic_assembly/drone name = "electronic drone" @@ -41,6 +42,32 @@ max_complexity = IC_COMPLEXITY_BASE / 2 var/obj/item/weapon/implant/integrated_circuit/implant = null +/obj/item/device/electronic_assembly/New() + ..() + battery = new(src) + processing_objects |= src + +/obj/item/device/electronic_assembly/Destroy() + battery = null + processing_objects -= src + for(var/atom/movable/AM in contents) + qdel(AM) + ..() + +/obj/item/device/electronic_assembly/process() + handle_idle_power() + +/obj/item/device/electronic_assembly/proc/handle_idle_power() + // First we generate power. + for(var/obj/item/integrated_circuit/passive/power/P in contents) + P.make_energy() + + // Now spend it. + for(var/obj/item/integrated_circuit/IC in contents) + if(IC.power_draw_idle) + if(!draw_power(IC.power_draw_idle)) + IC.power_fail() + /obj/item/device/electronic_assembly/implant/update_icon() ..() implant.icon_state = icon_state @@ -70,13 +97,18 @@ HTML += "
\[Refresh\] | " HTML += "\[Rename\]
" HTML += "[total_parts]/[max_components] ([round((total_parts / max_components) * 100, 0.1)]%) space taken up in the assembly.
" - HTML += "[total_complexity]/[max_complexity] ([round((total_complexity / max_complexity) * 100, 0.1)]%) maximum complexity." + HTML += "[total_complexity]/[max_complexity] ([round((total_complexity / max_complexity) * 100, 0.1)]%) maximum complexity.
" + if(battery) + HTML += "[round(battery.charge, 0.1)]/[battery.maxcharge] ([round(battery.percent(), 0.1)]%) cell charge. \[Remove\]" + else + HTML += "No powercell detected!" HTML += "

" HTML += "Components;
" for(var/obj/item/integrated_circuit/circuit in contents) HTML += "[circuit.name] | " HTML += "\[Rename\] | " - HTML += "\[Remove\]" + if(circuit.removable) + HTML += "\[Remove\]" HTML += "
" HTML += "" @@ -89,6 +121,16 @@ if(href_list["rename"]) rename(usr) + if(href_list["remove_cell"]) + if(!battery) + to_chat(usr, "There's no power cell to remove from \the [src].") + else + var/turf/T = get_turf(src) + battery.forceMove(T) + playsound(T, 'sound/items/Crowbar.ogg', 50, 1) + to_chat(usr, "You pull \the [battery] out of \the [src]'s power supplier.") + battery = null + interact(usr) // To refresh the UI. /obj/item/device/electronic_assembly/verb/rename() @@ -117,39 +159,84 @@ else icon_state = initial(icon_state) +/obj/item/device/electronic_assembly/GetAccess() + . = list() + for(var/obj/item/integrated_circuit/part in contents) + . |= part.GetAccess() + +/obj/item/device/electronic_assembly/GetIdCard() + . = list() + for(var/obj/item/integrated_circuit/part in contents) + var/id_card = part.GetIdCard() + if(id_card) + return id_card + /obj/item/device/electronic_assembly/examine(mob/user) . = ..(user, 1) if(.) - for(var/obj/item/integrated_circuit/output/screen/S in contents) - if(S.stuff_to_display) - to_chat(user, "There's a little screen labeled '[S.name]', which displays '[S.stuff_to_display]'.") + for(var/obj/item/integrated_circuit/IC in contents) + IC.external_examine(user) + // for(var/obj/item/integrated_circuit/output/screen/S in contents) + // if(S.stuff_to_display) + // to_chat(user, "There's a little screen labeled '[S.name]', which displays '[S.stuff_to_display]'.") if(opened) interact(user) +/obj/item/device/electronic_assembly/proc/get_part_complexity() + . = 0 + for(var/obj/item/integrated_circuit/part in contents) + . += part.complexity + +/obj/item/device/electronic_assembly/proc/get_part_size() + . = 0 + for(var/obj/item/integrated_circuit/part in contents) + . += part.w_class + +// Returns true if the circuit made it inside. +/obj/item/device/electronic_assembly/proc/add_circuit(var/obj/item/integrated_circuit/IC, var/mob/user) + if(!opened) + to_chat(user, "\The [src] isn't opened, so you can't put anything inside. Try using a crowbar.") + return FALSE + + if(IC.w_class > src.w_class) + to_chat(user, "\The [IC] is way too big to fit into \the [src].") + return FALSE + + var/total_part_size = get_part_size() + var/total_complexity = get_part_complexity() + + if((total_part_size + IC.w_class) > max_components) + to_chat(user, "You can't seem to add the '[IC.name]', as there's insufficient space.") + return FALSE + if((total_complexity + IC.complexity) > max_complexity) + to_chat(user, "You can't seem to add the '[IC.name]', since this setup's too complicated for the case.") + return FALSE + + if(!IC.forceMove(src)) + return FALSE + + IC.assembly = src + + return TRUE + +/obj/item/device/electronic_assembly/afterattack(atom/target, mob/user, proximity) + if(proximity) + var/scanned = FALSE + for(var/obj/item/integrated_circuit/input/sensor/S in contents) + S.set_pin_data(IC_OUTPUT, 1, weakref(target)) + S.check_then_do_work() + scanned = TRUE + if(scanned) + visible_message("\The [user] waves \the [src] around [target].") + /obj/item/device/electronic_assembly/attackby(var/obj/item/I, var/mob/user) if(istype(I, /obj/item/integrated_circuit)) - if(!opened) - to_chat(user, "\The [src] isn't opened, so you can't put anything inside. Try using a crowbar.") + if(!user.unEquip(I)) return 0 - var/obj/item/integrated_circuit/IC = I - var/total_parts = 0 - var/total_complexity = 0 - for(var/obj/item/integrated_circuit/part in contents) - total_parts++ - total_complexity = total_complexity + part.complexity - - if( (total_parts + 1) > max_components) - to_chat(user, "You can't seem to add this [IC.name], since there's no more room.") - return 0 - if( (total_complexity + IC.complexity) > max_complexity) - to_chat(user, "You can't seem to add this [IC.name], since this setup's too complicated for the case.") - return 0 - - to_chat(user, "You slide \the [IC] inside \the [src].") - user.drop_item() - IC.forceMove(src) - playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1) - interact(user) + if(add_circuit(I, user)) + to_chat(user, "You slide \the [I] inside \the [src].") + playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1) + interact(user) else if(istype(I, /obj/item/weapon/crowbar)) playsound(get_turf(src), 'sound/items/Crowbar.ogg', 50, 1) opened = !opened @@ -161,6 +248,21 @@ else to_chat(user, "\The [src] isn't opened, so you can't fiddle with the internal components. \ Try using a crowbar.") + else if(istype(I, /obj/item/weapon/cell/device)) + if(!opened) + to_chat(user, "\The [src] isn't opened, so you can't put anything inside. Try using a crowbar.") + return FALSE + if(battery) + to_chat(user, "\The [src] already has \a [battery] inside. Remove it first if you want to replace it.") + return FALSE + var/obj/item/weapon/cell/device/cell = I + user.drop_item(cell) + cell.forceMove(src) + battery = cell + playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1) + to_chat(user, "You slot \the [cell] inside \the [src]'s power supplier.") + interact(user) + else return ..() @@ -179,4 +281,16 @@ /obj/item/device/electronic_assembly/emp_act(severity) ..() for(var/atom/movable/AM in contents) - AM.emp_act(severity) \ No newline at end of file + AM.emp_act(severity) + +// Returns true if power was successfully drawn. +/obj/item/device/electronic_assembly/proc/draw_power(amount) + if(battery && battery.checked_use(amount * CELLRATE)) + return TRUE + return FALSE + +// Ditto for giving. +/obj/item/device/electronic_assembly/proc/give_power(amount) + if(battery && battery.give(amount * CELLRATE)) + return TRUE + return FALSE \ No newline at end of file diff --git a/code/modules/integrated_electronics/core/helpers.dm b/code/modules/integrated_electronics/core/helpers.dm new file mode 100644 index 00000000000..c98d74e79f4 --- /dev/null +++ b/code/modules/integrated_electronics/core/helpers.dm @@ -0,0 +1,44 @@ +/obj/item/integrated_circuit/proc/setup_io(var/list/io_list, var/io_type) + var/list/io_list_copy = io_list.Copy() + io_list.Cut() + for(var/io_entry in io_list_copy) + io_list.Add(new io_type(src, io_entry, io_list_copy[io_entry])) + +/obj/item/integrated_circuit/proc/set_pin_data(var/pin_type, var/pin_number, var/new_data) + var/datum/integrated_io/pin = get_pin_ref(pin_type, pin_number) + return pin.write_data_to_pin(new_data) + +/obj/item/integrated_circuit/proc/get_pin_data(var/pin_type, var/pin_number) + var/datum/integrated_io/pin = get_pin_ref(pin_type, pin_number) + return pin.get_data() + +/obj/item/integrated_circuit/proc/get_pin_data_as_type(var/pin_type, var/pin_number, var/as_type) + var/datum/integrated_io/pin = get_pin_ref(pin_type, pin_number) + return pin.data_as_type(as_type) + +/obj/item/integrated_circuit/proc/activate_pin(var/pin_number) + var/datum/integrated_io/activate/A = activators[pin_number] + A.push_data() + +/datum/integrated_io/proc/get_data() + if(isnull(data)) + return + if(isweakref(data)) + return data.resolve() + return data + +/obj/item/integrated_circuit/proc/get_pin_ref(var/pin_type, var/pin_number) + switch(pin_type) + if(IC_INPUT) + if(pin_number > inputs.len) + return null + return inputs[pin_number] + if(IC_OUTPUT) + if(pin_number > outputs.len) + return null + return outputs[pin_number] + if(IC_ACTIVATOR) + if(pin_number > activators.len) + return null + return activators[pin_number] + return null diff --git a/code/modules/integrated_electronics/core/integrated_circuit.dm b/code/modules/integrated_electronics/core/integrated_circuit.dm new file mode 100644 index 00000000000..87bb4cd182f --- /dev/null +++ b/code/modules/integrated_electronics/core/integrated_circuit.dm @@ -0,0 +1,282 @@ +/* + Integrated circuits are essentially modular machines. Each circuit has a specific function, and combining them inside Electronic Assemblies allows +a creative player the means to solve many problems. Circuits are held inside an electronic assembly, and are wired using special tools. +*/ + +/obj/item/integrated_circuit/examine(mob/user) + . = ..() + external_examine(user) + +// This should be used when someone is examining while the case is opened. +/obj/item/integrated_circuit/proc/internal_examine(mob/user) + to_chat(user, "This board has [inputs.len] input pin\s, [outputs.len] output pin\s and [activators.len] activation pin\s.") + for(var/datum/integrated_io/input/I in inputs) + if(I.linked.len) + to_chat(user, "The '[I]' is connected to [I.get_linked_to_desc()].") + for(var/datum/integrated_io/output/O in outputs) + if(O.linked.len) + to_chat(user, "The '[O]' is connected to [O.get_linked_to_desc()].") + for(var/datum/integrated_io/activate/A in activators) + if(A.linked.len) + to_chat(user, "The '[A]' is connected to [A.get_linked_to_desc()].") + any_examine(user) + interact(user) + +// This should be used when someone is examining from an 'outside' perspective, e.g. reading a screen or LED. +/obj/item/integrated_circuit/proc/external_examine(mob/user) + any_examine(user) + +/obj/item/integrated_circuit/proc/any_examine(mob/user) + return + +/obj/item/integrated_circuit/New() + setup_io(inputs, /datum/integrated_io/input) + setup_io(outputs, /datum/integrated_io/output) + setup_io(activators, /datum/integrated_io/activate) + ..() + +/obj/item/integrated_circuit/proc/on_data_written() //Override this for special behaviour when new data gets pushed to the circuit. + return + +/obj/item/integrated_circuit/Destroy() + for(var/datum/integrated_io/I in inputs) + qdel(I) + for(var/datum/integrated_io/O in outputs) + qdel(O) + for(var/datum/integrated_io/A in activators) + qdel(A) + . = ..() + +/obj/item/integrated_circuit/nano_host() + if(istype(src.loc, /obj/item/device/electronic_assembly)) + var/obj/item/device/electronic_assembly/assembly = loc + return assembly.resolve_nano_host() + return ..() + +/obj/item/integrated_circuit/emp_act(severity) + for(var/datum/integrated_io/io in inputs + outputs + activators) + io.scramble() + +/obj/item/integrated_circuit/verb/rename_component() + set name = "Rename Circuit" + set category = "Object" + set desc = "Rename your circuit, useful to stay organized." + + var/mob/M = usr + if(!CanInteract(M, physical_state)) + return + + var/input = sanitizeSafe(input("What do you want to name the circuit?", "Rename", src.name) as null|text, MAX_NAME_LEN) + if(src && input && CanInteract(M, physical_state)) + to_chat(M, "The circuit '[src.name]' is now labeled '[input]'.") + name = input + +/obj/item/integrated_circuit/interact(mob/user) + if(!CanInteract(user, physical_state)) + return + + var/window_height = 350 + var/window_width = 600 + + //var/table_edge_width = "[(window_width - window_width * 0.1) / 4]px" + //var/table_middle_width = "[(window_width - window_width * 0.1) - (table_edge_width * 2)]px" + var/table_edge_width = "30%" + var/table_middle_width = "40%" + + var/HTML = list() + HTML += "[src.name]" + HTML += "
" + HTML += "" + + HTML += "
\[Refresh\] | " + HTML += "\[Rename\] | " + HTML += "\[Remove\]
" + + HTML += "" + //HTML += "" + //HTML += "" + //HTML += "" + HTML += "" + HTML += "" + HTML += "" + HTML += "" + + var/column_width = 3 + var/row_height = max(inputs.len, outputs.len, 1) + + for(var/i = 1 to row_height) + HTML += "" + for(var/j = 1 to column_width) + var/datum/integrated_io/io = null + var/words = list() + var/height = 1 + switch(j) + if(1) + io = get_pin_ref(IC_INPUT, i) + if(io) + if(io.linked.len) + words += "[io.name] [io.display_data()]
" + for(var/datum/integrated_io/linked in io.linked) + words += "\[[linked.name]\] \ + @ [linked.holder]
" + else + words += "[io.name] [io.display_data()]
" + for(var/datum/integrated_io/linked in io.linked) + words += "\[[linked.name]\] \ + @ [linked.holder]
" + if(outputs.len > inputs.len) + height = 1 + if(2) + if(i == 1) + words += "[src.name]

[src.desc]" + height = row_height + else + continue + if(3) + io = get_pin_ref(IC_OUTPUT, i) + if(io) + if(io.linked.len) + words += "[io.name] [io.display_data()]
" + for(var/datum/integrated_io/linked in io.linked) + words += "\[[linked.name]\] \ + @ [linked.holder]
" + else + words += "[io.name] [io.display_data()]
" + for(var/datum/integrated_io/linked in io.linked) + words += "\[[linked.name]\] \ + @ [linked.holder]
" + if(inputs.len > outputs.len) + height = 1 + HTML += "" + HTML += "" + + for(var/activator in activators) + var/datum/integrated_io/io = activator + var/words = list() + if(io.linked.len) + words += "[io.name]
" + for(var/datum/integrated_io/linked in io.linked) + words += "\[[linked.name]\] \ + @ [linked.holder]
" + else + words += "[io.name]
" + for(var/datum/integrated_io/linked in io.linked) + words += "\[[linked.name]\] \ + @ [linked.holder]
" + HTML += "" + HTML += "" + HTML += "" + + HTML += "
[jointext(words, null)]
[jointext(words, null)]
" + HTML += "
" + + if(autopulse != -1) + HTML += "
Meta Variables;" + HTML += "
\[Autopulse\] = [autopulse ? "ON" : "OFF"]" + HTML += "
" + + HTML += "
Complexity: [complexity]" + if(power_draw_idle) + HTML += "
Power Draw: [power_draw_idle] W (Idle)" + if(power_draw_per_use) + HTML += "
Power Draw: [power_draw_per_use] W (Active)" // Borgcode says that powercells' checked_use() takes joules as input. + HTML += "
[extended_desc]" + + HTML += "" + user << browse(jointext(HTML, null), "window=circuit-\ref[src];size=[window_width]x[window_height];border=1;can_resize=1;can_close=1;can_minimize=1") + + onclose(user, "circuit-\ref[src]") + +/obj/item/integrated_circuit/Topic(href, href_list, state = physical_state) + if(..()) + return 1 + var/pin = locate(href_list["pin"]) in inputs + outputs + activators + + var/obj/held_item = usr.get_active_hand() + if(href_list["wire"]) + if(istype(held_item, /obj/item/device/integrated_electronics/wirer)) + var/obj/item/device/integrated_electronics/wirer/wirer = held_item + if(pin) + wirer.wire(pin, usr) + + else if(istype(held_item, /obj/item/device/integrated_electronics/debugger)) + var/obj/item/device/integrated_electronics/debugger/debugger = held_item + if(pin) + debugger.write_data(pin, usr) + else + to_chat(usr, "You can't do a whole lot without the proper tools.") + + if(href_list["examine"]) + examine(usr) + + if(href_list["rename"]) + rename_component(usr) + + if(href_list["autopulse"]) + if(autopulse != -1) + autopulse = !autopulse + + if(href_list["remove"]) + if(istype(held_item, /obj/item/weapon/screwdriver)) + if(!removable) + to_chat(usr, "\The [src] seems to be permanently attached to the case.") + return + disconnect_all() + var/turf/T = get_turf(src) + forceMove(T) + assembly = null + playsound(T, 'sound/items/Crowbar.ogg', 50, 1) + to_chat(usr, "You pop \the [src] out of the case, and slide it out.") + else + to_chat(usr, "You need a screwdriver to remove components.") + var/obj/item/device/electronic_assembly/ea = loc + if(istype(ea)) + ea.interact(usr) + return + + interact(usr) // To refresh the UI. + +/obj/item/integrated_circuit/proc/push_data() + for(var/datum/integrated_io/output/O in outputs) + O.push_data() + +/obj/item/integrated_circuit/proc/pull_data() + for(var/datum/integrated_io/input/I in inputs) + I.push_data() + +/obj/item/integrated_circuit/proc/draw_idle_power() + if(assembly) + return assembly.draw_power(power_draw_idle) + +// Override this for special behaviour when there's no power left. +/obj/item/integrated_circuit/proc/power_fail() + return + +// Returns true if there's enough power to work(). +/obj/item/integrated_circuit/proc/check_power() + if(!assembly) + return FALSE // Not in an assembly, therefore no power. + if(assembly.draw_power(power_draw_per_use)) + return TRUE // Battery has enough. + return FALSE // Not enough power. + +/obj/item/integrated_circuit/proc/check_then_do_work() + if(world.time < next_use) // All intergrated circuits have an internal cooldown, to protect from spam. + return + if(power_draw_per_use) + if(!check_power()) + power_fail() + return + next_use = world.time + cooldown_per_use + do_work() + +/obj/item/integrated_circuit/proc/do_work() + return + +/obj/item/integrated_circuit/proc/disconnect_all() + for(var/datum/integrated_io/input/I in inputs) + I.disconnect() + for(var/datum/integrated_io/output/O in outputs) + O.disconnect() + for(var/datum/integrated_io/activate/A in activators) + A.disconnect() diff --git a/code/modules/integrated_electronics/core/pins.dm b/code/modules/integrated_electronics/core/pins.dm new file mode 100644 index 00000000000..dc6d48e3034 --- /dev/null +++ b/code/modules/integrated_electronics/core/pins.dm @@ -0,0 +1,139 @@ +/* + Pins both hold data for circuits, as well move data between them. Some also cause circuits to do their function. DATA_CHANNEL pins are the data holding/moving kind, +where as PULSE_CHANNEL causes circuits to work() when their pulse hits them. + + +A visualization of how pins work is below. Imagine the below image involves an addition circuit. +When the bottom pin, the activator, receives a pulse, all the numbers on the left (input) get added, and the answer goes on the right side (output). + +Inputs Outputs + +A [2]\ /[8] result +B [1]-\|++|/ +C [4]-/|++| +D [1]/ || + || + Activator + + + +*/ +/datum/integrated_io + var/name = "input/output" + var/obj/item/integrated_circuit/holder = null + var/weakref/data = null // This is a weakref, to reduce typecasts. Note that oftentimes numbers and text may also occupy this. + var/list/linked = list() + var/io_type = DATA_CHANNEL + +/datum/integrated_io/New(var/newloc, var/name, var/data) + ..() + src.name = name + src.data = data + holder = newloc + if(!istype(holder)) + message_admins("ERROR: An integrated_io ([src.name]) spawned without a valid holder! This is a bug.") + +/datum/integrated_io/Destroy() + disconnect() + data = null + holder = null + . = ..() + +/datum/integrated_io/nano_host() + return holder.nano_host() + + +/datum/integrated_io/proc/data_as_type(var/as_type) + if(!isweakref(data)) + return + var/weakref/w = data + var/output = w.resolve() + return istype(output, as_type) ? output : null + +/datum/integrated_io/proc/display_data() + if(isnull(data)) + return "(null)" // Empty data means nothing to show. + if(istext(data)) + return "(\"[data]\")" // Wraps the 'string' in escaped quotes, so that people know it's a 'string'. + if(isweakref(data)) + var/weakref/w = data + var/atom/A = w.resolve() + //return A ? "([A.name] \[Ref\])" : "(null)" // For refs, we want just the name displayed. + return A ? "(\ref[A] \[Ref\])" : "(null)" + return "([data])" // Nothing special needed for numbers or other stuff. + +/datum/integrated_io/activate/display_data() + return "(\[pulse\])" + +/datum/integrated_io/proc/display_pin_type() + return IC_FORMAT_ANY + +/datum/integrated_io/activate/display_pin_type() + return IC_FORMAT_PULSE + +/datum/integrated_io/proc/scramble() + if(isnull(data)) + return + if(isnum(data)) + write_data_to_pin(rand(-10000, 10000)) + if(istext(data)) + write_data_to_pin("ERROR") + push_data() + +/datum/integrated_io/activate/scramble() + push_data() + +/datum/integrated_io/proc/write_data_to_pin(var/new_data) + if(isnull(new_data) || isnum(new_data) || istext(new_data) || isweakref(new_data)) // Anything else is a type we don't want. + data = new_data + holder.on_data_written() + +/datum/integrated_io/proc/push_data() + for(var/datum/integrated_io/io in linked) + io.write_data_to_pin(data) + +/datum/integrated_io/activate/push_data() + for(var/datum/integrated_io/io in linked) + io.holder.check_then_do_work() + +/datum/integrated_io/proc/pull_data() + for(var/datum/integrated_io/io in linked) + write_data_to_pin(io.data) + +/datum/integrated_io/proc/get_linked_to_desc() + if(linked.len) + return "the [english_list(linked)]" + return "nothing" + +/datum/integrated_io/proc/disconnect() + //First we iterate over everything we are linked to. + for(var/datum/integrated_io/their_io in linked) + //While doing that, we iterate them as well, and disconnect ourselves from them. + for(var/datum/integrated_io/their_linked_io in their_io.linked) + if(their_linked_io == src) + their_io.linked.Remove(src) + else + continue + //Now that we're removed from them, we gotta remove them from us. + src.linked.Remove(their_io) + +/datum/integrated_io/input + name = "input pin" + +/datum/integrated_io/output + name = "output pin" + +/datum/integrated_io/activate + name = "activation pin" + io_type = PULSE_CHANNEL + +/datum/integrated_io/list + name = "list pin" + +/datum/integrated_io/list/write_data_to_pin(var/new_data) + if(islist(new_data)) + data = new_data + holder.on_data_written() + +/datum/integrated_io/list/display_pin_type() + return IC_FORMAT_LIST \ No newline at end of file diff --git a/code/modules/integrated_electronics/tools.dm b/code/modules/integrated_electronics/core/tools.dm similarity index 71% rename from code/modules/integrated_electronics/tools.dm rename to code/modules/integrated_electronics/core/tools.dm index 6c76b9b4ffe..21a56f014dd 100644 --- a/code/modules/integrated_electronics/tools.dm +++ b/code/modules/integrated_electronics/core/tools.dm @@ -20,6 +20,9 @@ icon_state = "wirer-[mode]" /obj/item/device/integrated_electronics/wirer/proc/wire(var/datum/integrated_io/io, mob/user) + if(!io.holder.assembly) + to_chat(user, "\The [io.holder] needs to be secured inside an assembly first.") + return if(mode == WIRE) selected_io = io to_chat(user, "You attach a data wire to \the [selected_io.holder]'s [selected_io.name] data channel.") @@ -33,6 +36,9 @@ to_chat(user, "Those two types of channels are incompatable. The first is a [selected_io.io_type], \ while the second is a [io.io_type].") return + if(io.holder.assembly && io.holder.assembly != selected_io.holder.assembly) + to_chat(user, "Both \the [io.holder] and \the [selected_io.holder] need to be inside the same assembly.") + return selected_io.linked |= io io.linked |= selected_io @@ -191,6 +197,7 @@ new /obj/item/weapon/storage/bag/circuits/mini/reagents(src) new /obj/item/weapon/storage/bag/circuits/mini/transfer(src) new /obj/item/weapon/storage/bag/circuits/mini/converter(src) + new /obj/item/weapon/storage/bag/circuits/mini/power(src) new /obj/item/device/electronic_assembly(src) new /obj/item/device/integrated_electronics/wirer(src) @@ -202,11 +209,24 @@ /obj/item/weapon/storage/bag/circuits/all/New() ..() spawn(2 SECONDS) // So the list has time to initialize. - for(var/obj/item/integrated_circuit/IC in all_integrated_circuits) - for(var/i = 1 to 10) - new IC.type(src) + new /obj/item/weapon/storage/bag/circuits/mini/arithmetic/all(src) + new /obj/item/weapon/storage/bag/circuits/mini/trig/all(src) + new /obj/item/weapon/storage/bag/circuits/mini/input/all(src) + new /obj/item/weapon/storage/bag/circuits/mini/output/all(src) + new /obj/item/weapon/storage/bag/circuits/mini/memory/all(src) + new /obj/item/weapon/storage/bag/circuits/mini/logic/all(src) + new /obj/item/weapon/storage/bag/circuits/mini/smart/all(src) + new /obj/item/weapon/storage/bag/circuits/mini/manipulation/all(src) + new /obj/item/weapon/storage/bag/circuits/mini/time/all(src) + new /obj/item/weapon/storage/bag/circuits/mini/reagents/all(src) + new /obj/item/weapon/storage/bag/circuits/mini/transfer/all(src) + new /obj/item/weapon/storage/bag/circuits/mini/converter/all(src) + new /obj/item/weapon/storage/bag/circuits/mini/power/all(src) new /obj/item/device/electronic_assembly(src) + new /obj/item/device/electronic_assembly/medium(src) + new /obj/item/device/electronic_assembly/large(src) + new /obj/item/device/electronic_assembly/drone(src) new /obj/item/device/integrated_electronics/wirer(src) new /obj/item/device/integrated_electronics/debugger(src) new /obj/item/weapon/crowbar(src) @@ -219,16 +239,20 @@ w_class = 2 display_contents_with_number = 1 can_hold = list(/obj/item/integrated_circuit) + var/spawn_flags_to_use = IC_SPAWN_DEFAULT /obj/item/weapon/storage/bag/circuits/mini/arithmetic name = "arithmetic circuit box" desc = "Warning: Contains math." icon_state = "box_arithmetic" +/obj/item/weapon/storage/bag/circuits/mini/arithmetic/all // Don't believe this will ever be needed. + spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + /obj/item/weapon/storage/bag/circuits/mini/arithmetic/New() ..() for(var/obj/item/integrated_circuit/arithmetic/IC in all_integrated_circuits) - if(IC.spawn_flags & IC_SPAWN_DEFAULT) + if(IC.spawn_flags & spawn_flags_to_use) for(var/i = 1 to 3) new IC.type(src) make_exact_fit() @@ -239,10 +263,13 @@ desc = "Danger: Contains more math." icon_state = "box_trig" +/obj/item/weapon/storage/bag/circuits/mini/trig/all // Ditto + spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + /obj/item/weapon/storage/bag/circuits/mini/trig/New() ..() for(var/obj/item/integrated_circuit/trig/IC in all_integrated_circuits) - if(IC.spawn_flags & IC_SPAWN_DEFAULT) + if(IC.spawn_flags & spawn_flags_to_use) for(var/i = 1 to 3) new IC.type(src) make_exact_fit() @@ -253,10 +280,13 @@ desc = "Tell these circuits everything you know." icon_state = "box_input" +/obj/item/weapon/storage/bag/circuits/mini/input/all + spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + /obj/item/weapon/storage/bag/circuits/mini/input/New() ..() for(var/obj/item/integrated_circuit/input/IC in all_integrated_circuits) - if(IC.spawn_flags & IC_SPAWN_DEFAULT) + if(IC.spawn_flags & spawn_flags_to_use) for(var/i = 1 to 3) new IC.type(src) make_exact_fit() @@ -267,10 +297,13 @@ desc = "Circuits to interface with the world beyond itself." icon_state = "box_output" +/obj/item/weapon/storage/bag/circuits/mini/output/all + spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + /obj/item/weapon/storage/bag/circuits/mini/output/New() ..() for(var/obj/item/integrated_circuit/output/IC in all_integrated_circuits) - if(IC.spawn_flags & IC_SPAWN_DEFAULT) + if(IC.spawn_flags & spawn_flags_to_use) for(var/i = 1 to 3) new IC.type(src) make_exact_fit() @@ -281,25 +314,30 @@ desc = "Machines can be quite forgetful without these." icon_state = "box_memory" +/obj/item/weapon/storage/bag/circuits/mini/memory/all + spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + /obj/item/weapon/storage/bag/circuits/mini/memory/New() ..() for(var/obj/item/integrated_circuit/memory/IC in all_integrated_circuits) - if(IC.spawn_flags & IC_SPAWN_DEFAULT) + if(IC.spawn_flags & spawn_flags_to_use) for(var/i = 1 to 3) new IC.type(src) make_exact_fit() - /obj/item/weapon/storage/bag/circuits/mini/logic name = "logic circuit box" desc = "May or may not be Turing complete." icon_state = "box_logic" +/obj/item/weapon/storage/bag/circuits/mini/logic/all + spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + /obj/item/weapon/storage/bag/circuits/mini/logic/New() ..() for(var/obj/item/integrated_circuit/logic/IC in all_integrated_circuits) - if(IC.spawn_flags & IC_SPAWN_DEFAULT) + if(IC.spawn_flags & spawn_flags_to_use) for(var/i = 1 to 3) new IC.type(src) make_exact_fit() @@ -310,10 +348,13 @@ desc = "No time machine parts, sadly." icon_state = "box_time" +/obj/item/weapon/storage/bag/circuits/mini/time/all + spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + /obj/item/weapon/storage/bag/circuits/mini/time/New() ..() for(var/obj/item/integrated_circuit/time/IC in all_integrated_circuits) - if(IC.spawn_flags & IC_SPAWN_DEFAULT) + if(IC.spawn_flags & spawn_flags_to_use) for(var/i = 1 to 3) new IC.type(src) make_exact_fit() @@ -324,10 +365,13 @@ desc = "Unlike most electronics, these circuits are supposed to come in contact with liquids." icon_state = "box_reagents" +/obj/item/weapon/storage/bag/circuits/mini/reagents/all + spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + /obj/item/weapon/storage/bag/circuits/mini/reagents/New() ..() for(var/obj/item/integrated_circuit/reagent/IC in all_integrated_circuits) - if(IC.spawn_flags & IC_SPAWN_DEFAULT) + if(IC.spawn_flags & spawn_flags_to_use) for(var/i = 1 to 3) new IC.type(src) make_exact_fit() @@ -338,10 +382,13 @@ desc = "Useful for moving data representing something arbitrary to another arbitrary virtual place." icon_state = "box_transfer" +/obj/item/weapon/storage/bag/circuits/mini/transfer/all + spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + /obj/item/weapon/storage/bag/circuits/mini/transfer/New() ..() for(var/obj/item/integrated_circuit/transfer/IC in all_integrated_circuits) - if(IC.spawn_flags & IC_SPAWN_DEFAULT) + if(IC.spawn_flags & spawn_flags_to_use) for(var/i = 1 to 3) new IC.type(src) make_exact_fit() @@ -352,10 +399,66 @@ desc = "Transform one piece of data to another type of data with these." icon_state = "box_converter" +/obj/item/weapon/storage/bag/circuits/mini/converter/all + spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + /obj/item/weapon/storage/bag/circuits/mini/converter/New() ..() for(var/obj/item/integrated_circuit/converter/IC in all_integrated_circuits) - if(IC.spawn_flags & IC_SPAWN_DEFAULT) + if(IC.spawn_flags & spawn_flags_to_use) + for(var/i = 1 to 3) + new IC.type(src) + make_exact_fit() + +/obj/item/weapon/storage/bag/circuits/mini/smart + name = "smart box" + desc = "Sentience not included." + icon_state = "box_ai" + +/obj/item/weapon/storage/bag/circuits/mini/smart/all + spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + +/obj/item/weapon/storage/bag/circuits/mini/smart/New() + ..() + for(var/obj/item/integrated_circuit/smart/IC in all_integrated_circuits) + if(IC.spawn_flags & spawn_flags_to_use) + for(var/i = 1 to 3) + new IC.type(src) + make_exact_fit() + +/obj/item/weapon/storage/bag/circuits/mini/manipulation + name = "manipulation box" + desc = "Make your machines actually useful with these." + icon_state = "box_manipulation" + +/obj/item/weapon/storage/bag/circuits/mini/manipulation/all + spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + +/obj/item/weapon/storage/bag/circuits/mini/manipulation/New() + ..() + for(var/obj/item/integrated_circuit/manipulation/IC in all_integrated_circuits) + if(IC.spawn_flags & spawn_flags_to_use) + for(var/i = 1 to 3) + new IC.type(src) + make_exact_fit() + + +/obj/item/weapon/storage/bag/circuits/mini/power + name = "power circuit box" + desc = "Electronics generally require electricity." + icon_state = "box_power" + +/obj/item/weapon/storage/bag/circuits/mini/power/all + spawn_flags_to_use = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + +/obj/item/weapon/storage/bag/circuits/mini/power/New() + ..() + for(var/obj/item/integrated_circuit/passive/power/IC in all_integrated_circuits) + if(IC.spawn_flags & spawn_flags_to_use) + for(var/i = 1 to 3) + new IC.type(src) + for(var/obj/item/integrated_circuit/power/IC in all_integrated_circuits) + if(IC.spawn_flags & spawn_flags_to_use) for(var/i = 1 to 3) new IC.type(src) make_exact_fit() \ No newline at end of file diff --git a/code/modules/integrated_electronics/data_transfer.dm b/code/modules/integrated_electronics/data_transfer.dm deleted file mode 100644 index 7e37995df5b..00000000000 --- a/code/modules/integrated_electronics/data_transfer.dm +++ /dev/null @@ -1,85 +0,0 @@ -/obj/item/integrated_circuit/transfer - category_text = "Data Transfer" - autopulse = 1 - -/obj/item/integrated_circuit/transfer/on_data_written() - if(autopulse == 1) - check_then_do_work() - -/obj/item/integrated_circuit/transfer/splitter - name = "splitter" - desc = "Splits incoming data into all of the output pins." - icon_state = "splitter" - complexity = 3 - inputs = list("data to split") - outputs = list("A","B") - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - -/obj/item/integrated_circuit/transfer/splitter/medium - name = "four splitter" - icon_state = "splitter4" - complexity = 5 - outputs = list("A","B","C","D") - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - -/obj/item/integrated_circuit/transfer/splitter/large - name = "eight splitter" - icon_state = "splitter8" - complexity = 9 - outputs = list("A","B","C","D","E","F","G","H") - spawn_flags = IC_SPAWN_RESEARCH - -/obj/item/integrated_circuit/transfer/splitter/do_work() - var/datum/integrated_io/I = inputs[1] - for(var/datum/integrated_io/output/O in outputs) - O.data = I.data - -/obj/item/integrated_circuit/transfer/activator_splitter - name = "activator splitter" - desc = "Splits incoming activation pulses into all of the output pins." - icon_state = "splitter" - complexity = 3 - activators = list( - "incoming pulse", - "outgoing pulse A", - "outgoing pulse B" - ) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - -/obj/item/integrated_circuit/transfer/activator_splitter/do_work() - for(var/datum/integrated_io/activate/A in outputs) - if(A == activators[1]) - continue - if(A.linked.len) - for(var/datum/integrated_io/activate/target in A.linked) - target.holder.check_then_do_work() - -/obj/item/integrated_circuit/transfer/activator_splitter/medium - name = "four activator splitter" - icon_state = "splitter4" - complexity = 5 - activators = list( - "incoming pulse", - "outgoing pulse A", - "outgoing pulse B", - "outgoing pulse C", - "outgoing pulse D" - ) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - -/obj/item/integrated_circuit/transfer/activator_splitter/large - name = "eight activator splitter" - icon_state = "splitter4" - complexity = 9 - activators = list( - "incoming pulse", - "outgoing pulse A", - "outgoing pulse B", - "outgoing pulse C", - "outgoing pulse D", - "outgoing pulse E", - "outgoing pulse F", - "outgoing pulse G", - "outgoing pulse H" - ) - spawn_flags = IC_SPAWN_RESEARCH \ No newline at end of file diff --git a/code/modules/integrated_electronics/passive/passive.dm b/code/modules/integrated_electronics/passive/passive.dm new file mode 100644 index 00000000000..02f03d48d7c --- /dev/null +++ b/code/modules/integrated_electronics/passive/passive.dm @@ -0,0 +1,7 @@ +// 'Passive' components do not have any pins, and instead contribute in some form to the assembly holding them. +/obj/item/integrated_circuit/passive + inputs = list() + outputs = list() + activators = list() + power_draw_idle = 0 + power_draw_per_use = 0 \ No newline at end of file diff --git a/code/modules/integrated_electronics/passive/power.dm b/code/modules/integrated_electronics/passive/power.dm new file mode 100644 index 00000000000..9e08a96d24f --- /dev/null +++ b/code/modules/integrated_electronics/passive/power.dm @@ -0,0 +1,109 @@ + +/obj/item/integrated_circuit/passive/power + name = "power thingy" + desc = "Does power stuff." + complexity = 5 + origin_tech = list(TECH_POWER = 2, TECH_ENGINEERING = 2, TECH_DATA = 2) + category_text = "Power - Passive" + +/obj/item/integrated_circuit/passive/power/proc/make_energy() + return + +// For calculators. +/obj/item/integrated_circuit/passive/power/solar_cell + name = "tiny photovoltaic cell" + desc = "It's a very tiny solar cell, generally used in calculators." + extended_desc = "The cell generates 1W of energy per second in optimal lighting conditions. Less light will result in less power being generated." + icon_state = "solar_cell" + complexity = 8 + origin_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 3, TECH_DATA = 2) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + var/max_power = 1 + +/obj/item/integrated_circuit/passive/power/solar_cell/make_energy() + var/atom/movable/lighting_overlay/light = locate(/atom/movable/lighting_overlay) in get_turf(src) + var/light_amount = 1 // Unsimulated tiles are pretend-lit, so we need to be pretend too if that somehow happens. + if(light) + light_amount = (light.lum_r + light.lum_g + light.lum_b) / 3 + + var/adjusted_power = max(max_power * light_amount, 0) + adjusted_power = round(adjusted_power, 0.1) + if(adjusted_power) + if(assembly) + assembly.give_power(adjusted_power) + +// For implants. +/obj/item/integrated_circuit/passive/power/metabolic_siphon + name = "metabolic siphon" + desc = "A complicated piece of technology which converts bodily nutriments of a host into electricity." + extended_desc = "The siphon generates 10W of energy, so long as the siphon exists inside a biological entity. The entity will feel an increased \ + appetite and will need to eat more often due to this. This device will fail if used inside synthetic entities." + icon_state = "setup_implant" + complexity = 10 + origin_tech = list(TECH_POWER = 4, TECH_ENGINEERING = 4, TECH_DATA = 4, TECH_BIO = 5) + spawn_flags = IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/passive/power/metabolic_siphon/proc/test_validity(var/mob/living/carbon/human/host) + if(!host || host.isSynthetic() || host.stat == DEAD || host.nutrition <= 10) + return FALSE // Robots and dead people don't have a metabolism. + return TRUE + +/obj/item/integrated_circuit/passive/power/metabolic_siphon/make_energy() + var/mob/living/carbon/human/host = null + if(assembly && istype(assembly, /obj/item/device/electronic_assembly/implant)) + var/obj/item/device/electronic_assembly/implant/implant_assembly = assembly + if(implant_assembly.implant.imp_in) + host = implant_assembly.implant.imp_in + if(host && test_validity(host)) + assembly.give_power(10) + host.nutrition = max(host.nutrition - DEFAULT_HUNGER_FACTOR, 0) + +/obj/item/integrated_circuit/passive/power/metabolic_siphon/synthetic + name = "internal energy siphon" + desc = "A small circuit designed to be connected to an internal power wire inside a synthetic entity." + extended_desc = "The siphon generates 10W of energy, so long as the siphon exists inside a synthetic entity. The entity need to recharge \ + more often due to this. This device will fail if used inside organic entities." + icon_state = "setup_implant" + complexity = 10 + origin_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 4, TECH_DATA = 3) + spawn_flags = IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/passive/power/metabolic_siphon/synthetic/test_validity(var/mob/living/carbon/human/host) + if(!host || !host.isSynthetic() || host.stat == DEAD || host.nutrition <= 10) + return FALSE // This time we don't want a metabolism. + return TRUE + +// For fat machines that need fat power, like drones. +/obj/item/integrated_circuit/passive/power/relay + name = "tesla power relay" + desc = "A seemingly enigmatic device which connects to nearby APCs wirelessly and draws power from them." + w_class = ITEMSIZE_NORMAL + extended_desc = "The siphon generates 250W of energy, so long as an APC is in the same room, with a cell that has energy. It will always drain \ + from the 'equipment' power channel." + icon_state = "power_relay" + complexity = 7 + origin_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 3, TECH_DATA = 2) + spawn_flags = IC_SPAWN_RESEARCH + var/power_amount = 250 + +// For really fat machines. +/obj/item/integrated_circuit/passive/power/relay/large + name = "large tesla power relay" + desc = "A seemingly enigmatic device which connects to nearby APCs wirelessly and draws power from them, now in industiral size!" + w_class = ITEMSIZE_LARGE + extended_desc = "The siphon generates 2 kW of energy, so long as an APC is in the same room, with a cell that has energy. It will always drain \ + from the 'equipment' power channel." + icon_state = "power_relay" + complexity = 15 + origin_tech = list(TECH_POWER = 6, TECH_ENGINEERING = 5, TECH_DATA = 4) + spawn_flags = IC_SPAWN_RESEARCH + power_amount = 2000 + +/obj/item/integrated_circuit/passive/power/relay/make_energy() + if(!assembly) + return + var/area/A = get_area(src) + if(A) + if(A.powered(EQUIP)) + A.use_power(power_amount, EQUIP) + assembly.give_power(power_amount) // give_power() handles CELLRATE on its own. diff --git a/code/modules/integrated_electronics/arithmetic.dm b/code/modules/integrated_electronics/subtypes/arithmetic.dm similarity index 99% rename from code/modules/integrated_electronics/arithmetic.dm rename to code/modules/integrated_electronics/subtypes/arithmetic.dm index 37eabf20270..c6134f9bd1d 100644 --- a/code/modules/integrated_electronics/arithmetic.dm +++ b/code/modules/integrated_electronics/subtypes/arithmetic.dm @@ -6,6 +6,7 @@ activators = list("compute") category_text = "Arithmetic" autopulse = 1 + power_draw_per_use = 5 // Math is pretty cheap. /obj/item/integrated_circuit/arithmetic/on_data_written() if(autopulse == 1) diff --git a/code/modules/integrated_electronics/converters.dm b/code/modules/integrated_electronics/subtypes/converters.dm similarity index 99% rename from code/modules/integrated_electronics/converters.dm rename to code/modules/integrated_electronics/subtypes/converters.dm index 96494ba469f..9e04e24db51 100644 --- a/code/modules/integrated_electronics/converters.dm +++ b/code/modules/integrated_electronics/subtypes/converters.dm @@ -6,6 +6,7 @@ activators = list("convert") category_text = "Converter" autopulse = 1 + power_draw_per_use = 10 /obj/item/integrated_circuit/converter/on_data_written() if(autopulse == 1) diff --git a/code/modules/integrated_electronics/subtypes/data_transfer.dm b/code/modules/integrated_electronics/subtypes/data_transfer.dm new file mode 100644 index 00000000000..c5fe9741be1 --- /dev/null +++ b/code/modules/integrated_electronics/subtypes/data_transfer.dm @@ -0,0 +1,186 @@ +/obj/item/integrated_circuit/transfer + category_text = "Data Transfer" + autopulse = 1 + power_draw_per_use = 2 + +/obj/item/integrated_circuit/transfer/on_data_written() + if(autopulse == 1) + check_then_do_work() + +/obj/item/integrated_circuit/transfer/splitter + name = "splitter" + desc = "Splits incoming data into all of the output pins." + icon_state = "splitter" + complexity = 3 + inputs = list("data to split") + outputs = list("A","B") + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/transfer/splitter/medium + name = "four splitter" + icon_state = "splitter4" + complexity = 5 + outputs = list("A","B","C","D") + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 4 + +/obj/item/integrated_circuit/transfer/splitter/large + name = "eight splitter" + icon_state = "splitter8" + w_class = ITEMSIZE_SMALL + complexity = 9 + outputs = list("A","B","C","D","E","F","G","H") + spawn_flags = IC_SPAWN_RESEARCH + power_draw_per_use = 8 + +/obj/item/integrated_circuit/transfer/splitter/do_work() + var/datum/integrated_io/I = inputs[1] + for(var/datum/integrated_io/output/O in outputs) + O.data = I.data + +/obj/item/integrated_circuit/transfer/activator_splitter + name = "activator splitter" + desc = "Splits incoming activation pulses into all of the output pins." + icon_state = "splitter" + complexity = 3 + activators = list( + "incoming pulse", + "outgoing pulse A", + "outgoing pulse B" + ) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 2 + +/obj/item/integrated_circuit/transfer/activator_splitter/do_work() + for(var/datum/integrated_io/activate/A in outputs) + if(A == activators[1]) + continue + if(A.linked.len) + for(var/datum/integrated_io/activate/target in A.linked) + target.holder.check_then_do_work() + +/obj/item/integrated_circuit/transfer/activator_splitter/medium + name = "four activator splitter" + icon_state = "splitter4" + complexity = 5 + activators = list( + "incoming pulse", + "outgoing pulse A", + "outgoing pulse B", + "outgoing pulse C", + "outgoing pulse D" + ) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 4 + +/obj/item/integrated_circuit/transfer/activator_splitter/large + name = "eight activator splitter" + icon_state = "splitter4" + w_class = ITEMSIZE_SMALL + complexity = 9 + activators = list( + "incoming pulse", + "outgoing pulse A", + "outgoing pulse B", + "outgoing pulse C", + "outgoing pulse D", + "outgoing pulse E", + "outgoing pulse F", + "outgoing pulse G", + "outgoing pulse H" + ) + spawn_flags = IC_SPAWN_RESEARCH + power_draw_per_use = 8 + + +/obj/item/integrated_circuit/transfer/multiplexer + name = "two multiplexer" + desc = "This is what those in the business tend to refer to as a 'mux' or data selector. It moves data from one of the selected inputs to the output." + extended_desc = "The first input pin is used to select which of the other input pins which has its data moved to the output. If the input selection is outside the valid range then no output is given." + complexity = 2 + icon_state = "mux2" + inputs = list("input selection") + outputs = list("output") + activators = list("select") + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 4 + var/number_of_inputs = 2 + +/obj/item/integrated_circuit/transfer/multiplexer/New() + for(var/i = 1 to number_of_inputs) + inputs += "input [i]" + complexity = number_of_inputs + ..() + desc += " It has [number_of_inputs] input pins." + extended_desc += " This multiplexer has a range from 1 to [inputs.len - 1]." + +/obj/item/integrated_circuit/transfer/multiplexer/do_work() + var/input_index = get_pin_data(IC_INPUT, 1) + var/output = null + + if(isnum(input_index) && (input_index >= 1 && input_index < inputs.len)) + output = get_pin_data(IC_INPUT, input_index + 1) + set_pin_data(IC_OUTPUT, 1, output) + +/obj/item/integrated_circuit/transfer/multiplexer/medium + name = "four multiplexer" + number_of_inputs = 4 + icon_state = "mux4" + +/obj/item/integrated_circuit/transfer/multiplexer/large + name = "eight multiplexer" + number_of_inputs = 8 + w_class = ITEMSIZE_SMALL + icon_state = "mux8" + +/obj/item/integrated_circuit/transfer/multiplexer/huge + name = "sixteen multiplexer" + icon_state = "mux16" + w_class = ITEMSIZE_SMALL + number_of_inputs = 16 + +/obj/item/integrated_circuit/transfer/demultiplexer + name = "two demultiplexer" + desc = "This is what those in the business tend to refer to as a 'demux'. It moves data from the input to one of the selected outputs." + extended_desc = "The first input pin is used to select which of the output pins is given the data from the second input pin. If the output selection is outside the valid range then no output is given." + complexity = 2 + icon_state = "dmux2" + inputs = list("output selection","input") + outputs = list() + activators = list("select") + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 4 + var/number_of_outputs = 2 + +/obj/item/integrated_circuit/transfer/demultiplexer/New() + for(var/i = 1 to number_of_outputs) + outputs += "output [i]" + complexity = number_of_outputs + + ..() + desc += " It has [number_of_outputs] output pins." + extended_desc += " This demultiplexer has a range from 1 to [outputs.len]." + +/obj/item/integrated_circuit/transfer/demultiplexer/do_work() + var/output_index = get_pin_data(IC_INPUT, 1) + var/output = get_pin_data(IC_INPUT, 2) + + for(var/i = 1 to outputs.len) + set_pin_data(IC_OUTPUT, i, i == output_index ? output : null) + +/obj/item/integrated_circuit/transfer/demultiplexer/medium + name = "four demultiplexer" + icon_state = "dmux4" + number_of_outputs = 4 + +/obj/item/integrated_circuit/transfer/demultiplexer/large + name = "eight demultiplexer" + icon_state = "dmux8" + w_class = ITEMSIZE_SMALL + number_of_outputs = 8 + +/obj/item/integrated_circuit/transfer/demultiplexer/huge + name = "sixteen demultiplexer" + icon_state = "dmux16" + w_class = ITEMSIZE_SMALL + number_of_outputs = 16 \ No newline at end of file diff --git a/code/modules/integrated_electronics/input_output.dm b/code/modules/integrated_electronics/subtypes/input_output.dm similarity index 76% rename from code/modules/integrated_electronics/input_output.dm rename to code/modules/integrated_electronics/subtypes/input_output.dm index c77ad3dc69c..753c092974f 100644 --- a/code/modules/integrated_electronics/input_output.dm +++ b/code/modules/integrated_electronics/subtypes/input_output.dm @@ -1,6 +1,7 @@ /obj/item/integrated_circuit/input var/can_be_asked_input = 0 category_text = "Input" + power_draw_per_use = 5 /obj/item/integrated_circuit/input/proc/ask_for_input(mob/user) return @@ -23,6 +24,21 @@ target.holder.check_then_do_work() to_chat(user, "You press the button labeled '[src.name]'.") +/obj/item/integrated_circuit/input/toggle_button + name = "toggle button" + desc = "It toggles on, off, on, off..." + icon_state = "toggle_button" + complexity = 1 + inputs = list() + outputs = list("on" = 0) + activators = list("on toggle") + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/input/toggle_button/ask_for_input(mob/user) // Ditto. + set_pin_data(IC_OUTPUT, 1, !get_pin_data(IC_OUTPUT, 1)) + activate_pin(1) + to_chat(user, "You toggle the button labeled '[src.name]' [get_pin_data(IC_OUTPUT, 1) ? "on" : "off"].") + /obj/item/integrated_circuit/input/numberpad name = "number pad" desc = "This small number pad allows someone to input a number into the system." @@ -33,6 +49,7 @@ outputs = list("number entered") activators = list("on entered") spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 4 /obj/item/integrated_circuit/input/numberpad/ask_for_input(mob/user) var/new_input = input(user, "Enter a number, please.","Number pad") as null|num @@ -53,6 +70,7 @@ outputs = list("string entered") activators = list("on entered") spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 4 /obj/item/integrated_circuit/input/textpad/ask_for_input(mob/user) var/new_input = input(user, "Enter some words, please.","Number pad") as null|text @@ -73,6 +91,7 @@ activators = list("scan") spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2) + power_draw_per_use = 40 /obj/item/integrated_circuit/input/med_scanner/do_work() var/datum/integrated_io/I = inputs[1] @@ -111,6 +130,7 @@ activators = list("scan") spawn_flags = IC_SPAWN_RESEARCH origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3, TECH_BIO = 4) + power_draw_per_use = 80 /obj/item/integrated_circuit/input/adv_med_scanner/do_work() var/datum/integrated_io/I = inputs[1] @@ -148,12 +168,12 @@ outputs = list("located ref") activators = list("locate") spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 20 /obj/item/integrated_circuit/input/local_locator/do_work() var/datum/integrated_io/O = outputs[1] O.data = null - if(istype(src.loc, /obj/item/device/electronic_assembly)) // Check to make sure we're actually in a machine. - var/obj/item/device/electronic_assembly/assembly = src.loc + if(assembly) if(istype(assembly.loc, /mob/living)) // Now check if someone's holding us. O.data = weakref(assembly.loc) @@ -170,6 +190,7 @@ outputs = list("located ref") activators = list("locate") spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 30 /obj/item/integrated_circuit/input/adjacent_locator/do_work() var/datum/integrated_io/I = inputs[1] @@ -206,6 +227,8 @@ activators = list("send signal","on signal received") spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_MAGNETS = 2) + power_draw_idle = 5 + power_draw_per_use = 40 var/frequency = 1457 var/code = 30 @@ -288,6 +311,7 @@ activators = list("send data", "on data received") spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_MAGNETS = 2, TECH_BLUESPACE = 2) + power_draw_per_use = 50 var/datum/exonet_protocol/exonet = null /obj/item/integrated_circuit/input/EPv2/New() @@ -334,6 +358,7 @@ outputs = list("X (abs)", "Y (abs)") activators = list("get coordinates") spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 30 /obj/item/integrated_circuit/input/gps/do_work() var/turf/T = get_turf(src) @@ -361,6 +386,7 @@ outputs = list("speaker \", "message \") activators = list("on message received") spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 15 /obj/item/integrated_circuit/input/microphone/New() ..() @@ -385,9 +411,27 @@ for(var/datum/integrated_io/output/out in outputs) out.push_data() + A.push_data() +/obj/item/integrated_circuit/input/sensor + name = "sensor" + desc = "Scans and obtains a reference for any objects or persons near you. All you need to do is shove the machine in their face." + icon_state = "recorder" + complexity = 12 + inputs = list() + outputs = list("scanned ref \") + activators = list("on scanned") + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 120 + +/obj/item/integrated_circuit/input/sensor/do_work() + // Because this gets called by attack(), all this needs to do is pulse the activator. + for(var/datum/integrated_io/output/O in outputs) + O.push_data() + var/datum/integrated_io/activate/A = activators[1] + A.push_data() /obj/item/integrated_circuit/output @@ -401,8 +445,18 @@ outputs = list() activators = list("load data") spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 10 + autopulse = 1 var/stuff_to_display = null + +/obj/item/integrated_circuit/output/screen/disconnect_all() + ..() + stuff_to_display = null + +/obj/item/integrated_circuit/output/screen/any_examine(mob/user) + to_chat(user, "There is a little screen labeled '[name]', which displays [stuff_to_display ? "'[stuff_to_display]'" : "nothing"].") + /obj/item/integrated_circuit/output/screen/do_work() var/datum/integrated_io/I = inputs[1] if(isweakref(I.data)) @@ -416,22 +470,24 @@ name = "screen" desc = "This screen allows for people holding the device to see a piece of data." icon_state = "screen_medium" + power_draw_per_use = 20 /obj/item/integrated_circuit/output/screen/medium/do_work() ..() var/list/nearby_things = range(0, get_turf(src)) for(var/mob/M in nearby_things) - var/obj/O = istype(loc, /obj/item/device/electronic_assembly) ? loc : src + var/obj/O = assembly ? assembly : src visible_message("\icon[O] [stuff_to_display]") /obj/item/integrated_circuit/output/screen/large name = "large screen" desc = "This screen allows for people able to see the device to see a piece of data." icon_state = "screen_large" + power_draw_per_use = 40 /obj/item/integrated_circuit/output/screen/large/do_work() ..() - var/obj/O = istype(loc, /obj/item/device/electronic_assembly) ? loc : src + var/obj/O = assembly ? loc : assembly O.visible_message("\icon[O] [stuff_to_display]") /obj/item/integrated_circuit/output/light @@ -446,6 +502,10 @@ var/light_toggled = 0 var/light_brightness = 3 var/light_rgb = "#FFFFFF" + power_draw_idle = 0 // Adjusted based on brightness. + +/obj/item/integrated_circuit/output/light/Destroy() + ..() /obj/item/integrated_circuit/output/light/do_work() light_toggled = !light_toggled @@ -456,6 +516,7 @@ set_light(l_range = light_brightness, l_power = light_brightness, l_color = light_rgb) else set_light(0) + power_draw_idle = light_toggled ? light_brightness * 2 : 0 /obj/item/integrated_circuit/output/light/advanced/update_lighting() var/datum/integrated_io/R = inputs[1] @@ -473,6 +534,10 @@ ..() +/obj/item/integrated_circuit/output/light/power_fail() // Turns off the flashlight if there's no power left. + light_toggled = FALSE + update_lighting() + /obj/item/integrated_circuit/output/light/advanced name = "advanced light" desc = "This light can turn on and off on command, in any color, and in various brightness levels." @@ -504,6 +569,7 @@ ) outputs = list() activators = list("play sound") + power_draw_per_use = 20 var/list/sounds = list() /obj/item/integrated_circuit/output/text_to_speech @@ -517,11 +583,12 @@ outputs = list() activators = list("to speech") spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 60 /obj/item/integrated_circuit/output/text_to_speech/do_work() var/datum/integrated_io/text = inputs[1] if(istext(text.data)) - var/obj/O = istype(loc, /obj/item/device/electronic_assembly) ? loc : src + var/obj/O = assembly ? loc : assembly audible_message("\icon[O] \The [O.name] states, \"[text.data]\"") /obj/item/integrated_circuit/output/sound/New() @@ -576,4 +643,118 @@ "secure day" = 'sound/voice/bsecureday.ogg', ) spawn_flags = IC_SPAWN_RESEARCH - origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_ILLEGAL = 1) \ No newline at end of file + origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_ILLEGAL = 1) + +/obj/item/integrated_circuit/output/video_camera + name = "video camera circuit" + desc = "This small camera allows a remote viewer to see what it sees." + extended_desc = "The camera is linked to the Research camera network." + icon_state = "video_camera" + w_class = ITEMSIZE_SMALL + complexity = 10 + inputs = list("camera name" = "video camera circuit", "camera active" = 0) + outputs = list() + activators = list() + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_idle = 5 // Raises to 80 when on. + var/obj/machinery/camera/network/research/camera + +/obj/item/integrated_circuit/output/video_camera/New() + ..() + camera = new(src) + on_data_written() + +/obj/item/integrated_circuit/output/video_camera/Destroy() + qdel(camera) + ..() + +/obj/item/integrated_circuit/output/video_camera/proc/set_camera_status(var/status) + if(camera) + camera.set_status(status) + power_draw_idle = camera.status ? 80 : 5 + if(camera.status) // Ensure that there's actually power. + if(!draw_idle_power()) + power_fail() + +/obj/item/integrated_circuit/output/video_camera/on_data_written() + if(camera) + var/datum/integrated_io/cam_name = inputs[1] + var/datum/integrated_io/cam_active = inputs[2] + if(istext(cam_name.data)) + camera.c_tag = cam_name.data + if(isnum(cam_active.data)) + set_camera_status(cam_active.data) + +/obj/item/integrated_circuit/output/video_camera/power_fail() + if(camera) + set_camera_status(0) + var/datum/integrated_io/cam_active = inputs[2] + cam_active.data = FALSE + +/obj/item/integrated_circuit/output/led + name = "light-emitting diode" + desc = "This a LED that is lit whenever there is TRUE-equivalent data on its input." + extended_desc = "TRUE-equivalent values are: Non-empty strings, non-zero numbers, and valid refs." + complexity = 0.1 + icon_state = "led" + inputs = list("lit") + outputs = list() + activators = list() + power_draw_idle = 0 // Raises to 1 when lit. + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + var/led_color + +/obj/item/integrated_circuit/output/led/on_data_written() + power_draw_idle = get_pin_data(IC_INPUT, 1) ? 1 : 0 + +/obj/item/integrated_circuit/output/led/power_fail() + set_pin_data(IC_INPUT, 1, FALSE) + +/obj/item/integrated_circuit/output/led/any_examine(mob/user) + var/text_output = list() + var/initial_name = initial(name) + + // Doing all this work just to have a color-blind friendly output. + text_output += "There is " + if(name == initial_name) + text_output += "\an [name]" + else + text_output += "\an ["\improper[initial_name]"] labeled '[name]'" + text_output += " which is currently [get_pin_data(IC_INPUT, 1) ? "lit ¤" : "unlit."]" + to_chat(user,jointext(text_output,null)) + +/obj/item/integrated_circuit/output/led/red + name = "red LED" + led_color = COLOR_RED + +/obj/item/integrated_circuit/output/led/orange + name = "orange LED" + led_color = COLOR_ORANGE + +/obj/item/integrated_circuit/output/led/yellow + name = "yellow LED" + led_color = COLOR_YELLOW + +/obj/item/integrated_circuit/output/led/green + name = "green LED" + led_color = COLOR_GREEN + +/obj/item/integrated_circuit/output/led/blue + name = "blue LED" + led_color = COLOR_BLUE + +/obj/item/integrated_circuit/output/led/purple + name = "purple LED" + led_color = COLOR_PURPLE + +/obj/item/integrated_circuit/output/led/cyan + name = "cyan LED" + led_color = COLOR_CYAN + +/obj/item/integrated_circuit/output/led/white + name = "white LED" + led_color = COLOR_WHITE + +/obj/item/integrated_circuit/output/led/pink + name = "pink LED" + led_color = COLOR_PINK diff --git a/code/modules/integrated_electronics/logic.dm b/code/modules/integrated_electronics/subtypes/logic.dm similarity index 87% rename from code/modules/integrated_electronics/logic.dm rename to code/modules/integrated_electronics/subtypes/logic.dm index d477be3cbe1..8feed0457c9 100644 --- a/code/modules/integrated_electronics/logic.dm +++ b/code/modules/integrated_electronics/subtypes/logic.dm @@ -4,9 +4,10 @@ extended_desc = "Logic circuits will treat a null, 0, and a \"\" string value as FALSE and anything else as TRUE." complexity = 3 outputs = list("result") - activators = list("compare", "on true result") + activators = list("compare", "on true result", "on false result") category_text = "Logic" autopulse = 1 + power_draw_per_use = 1 /obj/item/integrated_circuit/logic/on_data_written() if(autopulse == 1) @@ -14,10 +15,13 @@ /obj/item/integrated_circuit/logic/do_work() var/datum/integrated_io/O = outputs[1] - var/datum/integrated_io/P = activators[2] + var/datum/integrated_io/T = activators[2] + var/datum/integrated_io/F = activators[3] O.push_data() if(O.data) - P.push_data() + T.push_data() + else + F.push_data() /obj/item/integrated_circuit/logic/binary inputs = list("A","B") @@ -53,6 +57,15 @@ /obj/item/integrated_circuit/logic/binary/equals/do_compare(var/datum/integrated_io/A, var/datum/integrated_io/B) return A.data == B.data +/obj/item/integrated_circuit/logic/binary/not_equals + name = "not equal gate" + desc = "This gate compares two values, and outputs the number one if both are different." + icon_state = "not equal" + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/logic/binary/not_equals/do_compare(var/datum/integrated_io/A, var/datum/integrated_io/B) + return A.data != B.data + /obj/item/integrated_circuit/logic/binary/and name = "and gate" desc = "This gate will output 'one' if both inputs evaluate to true." @@ -114,4 +127,4 @@ spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH /obj/item/integrated_circuit/logic/unary/not/do_check(var/datum/integrated_io/A) - return !A.data \ No newline at end of file + return !A.data diff --git a/code/modules/integrated_electronics/manipulation.dm b/code/modules/integrated_electronics/subtypes/manipulation.dm similarity index 90% rename from code/modules/integrated_electronics/manipulation.dm rename to code/modules/integrated_electronics/subtypes/manipulation.dm index f49b96d16c6..65bae751e00 100644 --- a/code/modules/integrated_electronics/manipulation.dm +++ b/code/modules/integrated_electronics/subtypes/manipulation.dm @@ -9,6 +9,7 @@ The 'fire' activator will cause the mechanism to attempt to fire the weapon at the coordinates, if possible. Note that the \ normal limitations to firearms, such as ammunition requirements and firing delays, still hold true if fired by the mechanism." complexity = 20 + w_class = ITEMSIZE_NORMAL inputs = list( "target X rel", "target Y rel" @@ -20,6 +21,7 @@ var/obj/item/weapon/gun/installed_gun = null spawn_flags = IC_SPAWN_RESEARCH origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3, TECH_COMBAT = 4) + power_draw_per_use = 50 // The targeting mechanism uses this. The actual gun uses its own cell for firing if it's an energy weapon. /obj/item/integrated_circuit/manipulation/weapon_firing/Destroy() qdel(installed_gun) @@ -106,20 +108,21 @@
\ Pulsing the 'step towards dir' activator pin will cause the machine to move a meter in that direction, assuming it is not \ being held, or anchored in some way. It should be noted that the ability to move is dependant on the type of assembly that this circuit inhabits." + w_class = ITEMSIZE_NORMAL complexity = 20 inputs = list("dir num") outputs = list() activators = list("step towards dir") spawn_flags = IC_SPAWN_RESEARCH + power_draw_per_use = 100 /obj/item/integrated_circuit/manipulation/locomotion/do_work() ..() var/turf/T = get_turf(src) - if(T && istype(loc, /obj/item/device/electronic_assembly)) - var/obj/item/device/electronic_assembly/machine = loc - if(machine.anchored || !machine.can_move()) + if(T && assembly) + if(assembly.anchored || !assembly.can_move()) return - if(machine.loc == T) // Check if we're held by someone. If the loc is the floor, we're not held. + if(assembly.loc == T) // Check if we're held by someone. If the loc is the floor, we're not held. var/datum/integrated_io/wanted_dir = inputs[1] if(isnum(wanted_dir.data)) - step(machine, wanted_dir.data) \ No newline at end of file + step(assembly, wanted_dir.data) \ No newline at end of file diff --git a/code/modules/integrated_electronics/memory.dm b/code/modules/integrated_electronics/subtypes/memory.dm similarity index 96% rename from code/modules/integrated_electronics/memory.dm rename to code/modules/integrated_electronics/subtypes/memory.dm index f9cd109dce5..49a049a9827 100644 --- a/code/modules/integrated_electronics/memory.dm +++ b/code/modules/integrated_electronics/subtypes/memory.dm @@ -8,6 +8,7 @@ activators = list("set") category_text = "Memory" spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 1 /obj/item/integrated_circuit/memory/examine(mob/user) ..() @@ -33,15 +34,18 @@ name = "memory circuit" desc = "This circuit can store four pieces of data." icon_state = "memory4" + w_class = ITEMSIZE_SMALL complexity = 4 inputs = list("input pin 1","input pin 2","input pin 3","input pin 4") outputs = list("output pin 1","output pin 2","output pin 3","output pin 4") spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 2 /obj/item/integrated_circuit/memory/large name = "large memory circuit" desc = "This big circuit can hold eight pieces of data." icon_state = "memory8" + w_class = ITEMSIZE_SMALL complexity = 8 inputs = list( "input pin 1", @@ -63,11 +67,13 @@ "output pin 8") spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3) + power_draw_per_use = 4 /obj/item/integrated_circuit/memory/huge name = "large memory stick" desc = "This stick of memory can hold up up to sixteen pieces of data." icon_state = "memory16" + w_class = ITEMSIZE_NORMAL complexity = 16 inputs = list( "input pin 1", @@ -106,6 +112,7 @@ "output pin 16") spawn_flags = IC_SPAWN_RESEARCH origin_tech = list(TECH_ENGINEERING = 4, TECH_DATA = 4) + power_draw_per_use = 8 /obj/item/integrated_circuit/memory/constant name = "constant chip" diff --git a/code/modules/integrated_electronics/subtypes/power.dm b/code/modules/integrated_electronics/subtypes/power.dm new file mode 100644 index 00000000000..013a35c0588 --- /dev/null +++ b/code/modules/integrated_electronics/subtypes/power.dm @@ -0,0 +1,80 @@ +/obj/item/integrated_circuit/power/ + category_text = "Power - Active" + +/obj/item/integrated_circuit/power/transmitter + name = "power transmission circuit" + desc = "This can wirelessly transmit electricity from an assembly's battery towards a nearby machine." + icon_state = "power_transmitter" + extended_desc = "This circuit transmits 5 kJ of electricity every time the activator pin is pulsed. The input pin must be \ + a reference to a machine to send electricity to. This can be a battery, or anything containing a battery. The machine can exist \ + inside the assembly, or adjacent to it. The power is sourced from the assembly's power cell. If the target is outside of the assembly, \ + some power is lost due to ineffiency." + w_class = ITEMSIZE_SMALL + complexity = 16 + inputs = list("target ref") + outputs = list("target cell charge", "target cell max charge", "target cell percentage") + activators = list("transmit") + spawn_flags = IC_SPAWN_RESEARCH + origin_tech = list(TECH_ENGINEERING = 4, TECH_DATA = 4, TECH_POWER = 4, TECH_MAGNETS = 3) + power_draw_per_use = 500 // Inefficency has to come from somewhere. + var/amount_to_move = 5000 + +/obj/item/integrated_circuit/power/transmitter/large + name = "large power transmission circuit" + desc = "This can wirelessly transmit a lot of electricity from an assembly's battery towards a nearby machine. Warning: Do not operate in flammable enviroments." + extended_desc = "This circuit transmits 20 kJ of electricity every time the activator pin is pulsed. The input pin must be \ + a reference to a machine to send electricity to. This can be a battery, or anything containing a battery. The machine can exist \ + inside the assembly, or adjacent to it. The power is sourced from the assembly's power cell. If the target is outside of the assembly, \ + some power is lost due to ineffiency." + w_class = ITEMSIZE_LARGE + complexity = 32 + origin_tech = list(TECH_ENGINEERING = 4, TECH_DATA = 4, TECH_POWER = 6, TECH_MAGNETS = 5) + power_draw_per_use = 2000 + amount_to_move = 20000 + +/obj/item/integrated_circuit/power/transmitter/do_work() + set_pin_data(IC_OUTPUT, 1, null) + set_pin_data(IC_OUTPUT, 2, null) + set_pin_data(IC_OUTPUT, 3, null) + var/atom/movable/AM = get_pin_data_as_type(IC_INPUT, 1, /atom/movable) + if(AM) + if(!assembly) + return FALSE // Pointless to do everything else if there's no battery to draw from. + + var/obj/item/weapon/cell/cell = null + if(istype(AM, /obj/item/weapon/cell)) // Is this already a cell? + cell = AM + else // If not, maybe there's a cell inside it? + for(var/obj/item/weapon/cell/C in AM.contents) + if(C) // Find one cell to charge. + cell = C + break + if(cell) + var/transfer_amount = amount_to_move + var/turf/A = get_turf(src) + var/turf/B = get_turf(AM) + if(A.Adjacent(B)) + if(AM.loc != assembly) + transfer_amount *= 0.8 // Losses due to distance. + + if(cell.fully_charged()) + return FALSE + + if(transfer_amount && assembly.draw_power(amount_to_move)) // CELLRATE is already handled in draw_power() + cell.give(transfer_amount * CELLRATE) + AM.update_icon() + + set_pin_data(IC_OUTPUT, 1, cell.charge) + set_pin_data(IC_OUTPUT, 2, cell.maxcharge) + set_pin_data(IC_OUTPUT, 3, cell.percent()) + return TRUE + return FALSE + +/obj/item/integrated_circuit/power/transmitter/large/do_work() + if(..()) // If the above code succeeds, do this below. + if(prob(2)) + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() + sparks.set_up(3, 0, get_turf(src)) + sparks.start() + visible_message("\The [assembly] makes some sparks!") + qdel(sparks) \ No newline at end of file diff --git a/code/modules/integrated_electronics/reagents.dm b/code/modules/integrated_electronics/subtypes/reagents.dm similarity index 98% rename from code/modules/integrated_electronics/reagents.dm rename to code/modules/integrated_electronics/subtypes/reagents.dm index bd6cd1d9333..d0c26baf663 100644 --- a/code/modules/integrated_electronics/reagents.dm +++ b/code/modules/integrated_electronics/subtypes/reagents.dm @@ -23,6 +23,7 @@ spawn_flags = IC_SPAWN_RESEARCH origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3, TECH_BIO = 3) volume = 100 + power_draw_per_use = 20 /obj/item/integrated_circuit/reagent/smoke/do_work() playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3) @@ -47,6 +48,7 @@ activators = list("inject") spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH volume = 30 + power_draw_per_use = 15 /obj/item/integrated_circuit/reagent/injector/proc/inject_amount() var/datum/integrated_io/amount = inputs[2] @@ -92,6 +94,7 @@ spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2) var/transfer_amount = 10 + power_draw_per_use = 10 /obj/item/integrated_circuit/reagent/pump/on_data_written() var/datum/integrated_io/amount = inputs[3] diff --git a/code/modules/integrated_electronics/subtypes/smart.dm b/code/modules/integrated_electronics/subtypes/smart.dm new file mode 100644 index 00000000000..c159522e974 --- /dev/null +++ b/code/modules/integrated_electronics/subtypes/smart.dm @@ -0,0 +1,33 @@ +/obj/item/integrated_circuit/smart + category_text = "Smart" + +/obj/item/integrated_circuit/smart/basic_pathfinder + name = "basic pathfinder" + desc = "This complex circuit is able to determine what direction a given target is." + extended_desc = "This circuit uses a miniturized, integrated camera to determine where the target is. If the machine \ + cannot see the target, it will not be able to calculate the correct direction." + icon_state = "numberpad" + complexity = 25 + inputs = list("target ref") + outputs = list("dir") + activators = list("calculate dir") + spawn_flags = IC_SPAWN_RESEARCH + origin_tech = list(TECH_ENGINEERING = 4, TECH_DATA = 5) + power_draw_per_use = 40 + +/obj/item/integrated_circuit/smart/basic_pathfinder/do_work() + var/datum/integrated_io/I = inputs[1] + var/datum/integrated_io/O = outputs[1] + O.data = null + + if(!isweakref(I.data)) + return + var/atom/A = I.data.resolve() + if(!A) + return + if(!(A in view(get_turf(src)))) + return // Can't see the target. + var/desired_dir = get_dir(get_turf(src), A) + if(desired_dir) + O.data = desired_dir + O.push_data() \ No newline at end of file diff --git a/code/modules/integrated_electronics/time.dm b/code/modules/integrated_electronics/subtypes/time.dm similarity index 97% rename from code/modules/integrated_electronics/time.dm rename to code/modules/integrated_electronics/subtypes/time.dm index 50bcc5e3867..72766c0c48c 100644 --- a/code/modules/integrated_electronics/time.dm +++ b/code/modules/integrated_electronics/subtypes/time.dm @@ -14,6 +14,7 @@ var/delay = 2 SECONDS activators = list("incoming pulse","outgoing pulse") spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 2 /obj/item/integrated_circuit/time/delay/do_work() set waitfor = 0 // Don't sleep in a proc that is called by a processor. It'll delay the entire thing @@ -82,6 +83,7 @@ inputs = list("enable ticking") activators = list("outgoing pulse") spawn_flags = IC_SPAWN_RESEARCH + power_draw_per_use = 4 /obj/item/integrated_circuit/time/ticker/Destroy() if(is_running) @@ -116,6 +118,7 @@ complexity = 12 ticks_to_pulse = 2 spawn_flags = IC_SPAWN_RESEARCH + power_draw_per_use = 8 /obj/item/integrated_circuit/time/ticker/slow name = "slow ticker" @@ -124,6 +127,7 @@ complexity = 4 ticks_to_pulse = 6 spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 2 /obj/item/integrated_circuit/time/clock name = "integrated clock" @@ -132,6 +136,7 @@ inputs = list() outputs = list("time (string)", "hours (number)", "minutes (number)", "seconds (number)") spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 4 /obj/item/integrated_circuit/time/clock/do_work() var/datum/integrated_io/time = outputs[1] diff --git a/code/modules/integrated_electronics/trig.dm b/code/modules/integrated_electronics/subtypes/trig.dm similarity index 97% rename from code/modules/integrated_electronics/trig.dm rename to code/modules/integrated_electronics/subtypes/trig.dm index e8e2e09ca9e..b1a19f4a406 100644 --- a/code/modules/integrated_electronics/trig.dm +++ b/code/modules/integrated_electronics/subtypes/trig.dm @@ -7,6 +7,7 @@ category_text = "Trig" extended_desc = "Input and output are in degrees." autopulse = 1 + power_draw_per_use = 1 // Still cheap math. /obj/item/integrated_circuit/trig/on_data_written() if(autopulse == 1) @@ -118,7 +119,7 @@ /obj/item/integrated_circuit/trig/cotangent name = "cot circuit" - desc = "Outputs the cotangent of A. Has nothing to do with the security department." + desc = "Outputs the cotangent of A." icon_state = "cotangent" inputs = list("A") spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH diff --git a/code/modules/integrated_electronics/~defines.dm b/code/modules/integrated_electronics/~defines.dm deleted file mode 100644 index 7aea6dabbb9..00000000000 --- a/code/modules/integrated_electronics/~defines.dm +++ /dev/null @@ -1,6 +0,0 @@ -#undef IC_INPUT -#undef IC_OUTPUT -#undef IC_ACTIVATOR - -#undef DATA_CHANNEL -#undef PULSE_CHANNEL \ No newline at end of file diff --git a/code/modules/integrated_electronics/~defines/~defines.dm b/code/modules/integrated_electronics/~defines/~defines.dm new file mode 100644 index 00000000000..78ce72f3655 --- /dev/null +++ b/code/modules/integrated_electronics/~defines/~defines.dm @@ -0,0 +1,16 @@ +#undef IC_INPUT +#undef IC_OUTPUT +#undef IC_ACTIVATOR + +#undef DATA_CHANNEL +#undef PULSE_CHANNEL + +#undef IC_SPAWN_DEFAULT +//#undef IC_SPAWN_RESEARCH // Research designs depend on this unfortunately. + +#undef IC_FORMAT_STRING +#undef IC_FORMAT_NUMBER +#undef IC_FORMAT_REF +#undef IC_FORMAT_LIST +#undef IC_FORMAT_ANY +#undef IC_FORMAT_PULSE \ No newline at end of file diff --git a/code/unit_tests/integrated_circuits/logic.dm b/code/unit_tests/integrated_circuits/logic.dm index 314150f3b4d..a022078c070 100644 --- a/code/unit_tests/integrated_circuits/logic.dm +++ b/code/unit_tests/integrated_circuits/logic.dm @@ -65,6 +65,32 @@ +/datum/unit_test/integrated_circuits/not_equals_1 + name = "Logic Circuits: Not Equals - String True" + circuit_type = /obj/item/integrated_circuit/logic/binary/not_equals + inputs_to_give = list("Test", "Nope") + expected_outputs = list(TRUE) + +/datum/unit_test/integrated_circuits/not_equals_2 + name = "Logic Circuits: Not Equals - String False" + circuit_type = /obj/item/integrated_circuit/logic/binary/not_equals + inputs_to_give = list("Test", "Test") + expected_outputs = list(FALSE) + +/datum/unit_test/integrated_circuits/not_equals_3 + name = "Logic Circuits: Not Equals - Number True" + circuit_type = /obj/item/integrated_circuit/logic/binary/not_equals + inputs_to_give = list(150, 20) + expected_outputs = list(TRUE) + +/datum/unit_test/integrated_circuits/not_equals_4 + name = "Logic Circuits: Not Equals - Number False" + circuit_type = /obj/item/integrated_circuit/logic/binary/not_equals + inputs_to_give = list(100, 100) + expected_outputs = list(FALSE) + + + /datum/unit_test/integrated_circuits/and_1 name = "Logic Circuits: And - True" circuit_type = /obj/item/integrated_circuit/logic/binary/and diff --git a/icons/obj/electronic_assemblies.dmi b/icons/obj/electronic_assemblies.dmi index 8fd1c4f5e103d398b2f5af104791ae27f98a10b7..81aa71eac773dda32062093e11546a517e6dc041 100644 GIT binary patch literal 32741 zcmbq)bySpJ+wKgFBA|#!BO;)PASpRuAV`Z!mr8f{3@D&Tw;%|D0!m8vfFLL>DLHfv zFmz0w&F_8RZ++)m>#VcRI)BW}Gf(Vi#~s&w-S>{r(Rz694BHt91aeMI_5NcBgiHy1 zcxb4=87JpaM+k&`$^VIg=Y1=W7w&eho^~$I5QuL^v4MK*{2fNcw$iuOCD5H`=Cwus zmFsOi=4DZ)oQ;2PY5%0cqA(%wP{xJlJ`@p3*maL&v>l?9h}}8rE?qxa={}|zX4@aB zHqx|N`15@z@sLMjU)bO)Odqu9M1W(r!0&SAf z2ipOb5T}U;3Gc$ZeycDQ=_XK)E!!H=Gxk9hjt!oTO3(@G3Pf6!pwuqV++8d}cN>?) zQAQ3*a~LyMXY-x?_2uP-3;dFvyf0&BI%;q4 zm0t2CWquaUkymNGXJl)9{-`{I{ai?tlKi$nvC?z-Kb13&R8)DB^>_@Ju5O1c zZ67P8khcreke?}cR15W3ob|r0q7qV-XZ5G*9ptjYz4O5=^p$E$j)4!2)uMQ_>At?q zxpP@dCi42W4ig zCsutqX2X#?Z)aaN_IYTE2KO_~eB-c^ShXtQD)na@j+Ae^nu4OOIT%Yo`#%*yKTts0 z)FuzNWL7oYc4NPg=@jtG?&oHDfB2C)lXqv_Qd1EI}G zo5H9+^bD-prs#lTXQm0uPnu&*Sy_FI&@*Z)MlDU(I9H$DW?PZdQVqJP(u3`y%-gAh zr$v`Tc3W(1FEPvZFl=>yoHI{&m^qgkP(Zok|xn0DLai};J#!JEYr>cYK) z>U$R}THaHZ+1;eEF4Rw` z8r=?dC9pH;QMJ+*yGBc#CzAK zR*GW2Prajv`N{RKbP23^8GtMMCN~XG55G$+Z?~ujnvQUIo5s06h@>;5*Ff^%-rYa z3s|9QYCM8!7ja(pp0X)Oq z&x;35BofEj%j4VkR4E&;=tNw3SEchv2~!nygpL*tGb-6V|5blT>b_E)(W)kHob7%Y zZp7)!mt%5rr?F9yb$#J1vztfh4f*slkxEI=M|j$E7~Lu3c~r^%_{(L%q{P!QGp92% zvl`_3J7ogAeY~x?Flk2{Jq~7=qaK2@*8Bc%7sL6T2 zl~4+LDkbojhL(da`1FPgcP>NDpFZL$3gHD8RAP}Qo+gSfg)_? zD>#BMp8f9!3g34@BK|a!Thwj6>62)Ks7Cia2$wm*#a$XOmmq3(KrjFMmBt4jx*)#` zdwRZc`#t4VSb9PwsE^bez?5cz&bviML3QqMT$)hlQ#Od7)Cgl%3W(qfZL>7i&3^iy zyHs7jt}|QJLF3q`(n!G?FcseOGSx+tyWj5XJw&XKZD%C2fv}wGYESE*_FP&Wa6`l%T;z@LR z&jN26>vb308>Nz8BU6%AtHGO%C`%zHm$n^F&}g(Kp??Z5V!z_F=+;)eMKVc8v>rlt zc_F`+r5kkX=f*x#;^wGl>&?%#qz^SH&_afet1xERD)iK*>@R6N{h`>L*Ersc1&$-| z7&FfDPY^PR#|wwwf7v1mNgEw-)p61qK?U8{HjuoqaY1b<yDsfLxJVa6TCxDUoePsL5*uVNBX@mRfv zq337TcP7tMNju*WCX`Ux)<63DkwJVdgU+1{%`DbJcz!m@963STaHWo^8U^P$>Bl@{ zdLoM?#$q0dzh}`bQ_&*Wlw#qZ_wsRD$*AswxKaY5@y461?yTbGCZj`7#Txu0s?|;^ zGlBJ%!KW7XB4`O|UU%G$GRJ>4%@!;fSw6ZjGGe`k50;i|@`S_an^k<*4sNV|0V=iE zS!zQ0EMR~W`GrnLYN`+7M@b-J_u{j+-r^5e*!IIMJyz}k1vWmEdw}51zGPr`rccG0 zmFKm3NVKak`OCq7M7{qZe&YOqHVrM?BdTA;CoA5}26e67kg*an@im__Si%7lFc8l1 zJC+5Hs4O&C%ZexQZM{IpcjFg=^;ok_2wKWWBplq+F07$&?&GNi`uzUaUka5|1M@iQ zKZeBuavz+CYiWhNJ-sF5_5Z77`fm*w@L!1d1y4P-cHha!d7h{JEx&|}R08cAyn-@* z?|Cmqn(9$Je^=GjZT>QkYQmzD?v(NrU)P^5+pg_X72fNJX4iwq{!9PuLilQpS|H~m z?k|FNBv;R;Lp{j^sTafB%dU2Y)Js;;ylE>bJ^E&*>nvhPxNujM5wxnK!W77&xJz76Hx)R2tNs%Lxbz zLbb2!=Ym@!qn+C|^3VP9(BJT%#j{T@bz$f(0_(|bf>2CqRY%sUX`Hjg8u27FlgF|3 zrrHHt`CZDOQ;d4WO%T1tPQge2&WthQ{!5YcfZbMZ`Zrcd%N_+q8^I>tM6DFS%SmW92%+dD27^RTDFEWs%FDYgy(308DoyExPNDb-tC0A9zP@hGPF!in*B)oDBc^1Z zkMAN{K1wY7@L7UVKQCs%N=9eg{E|qc5mFI{UUR=1!TS-0Zp8vTtz=6$4nBBACDvCId)#3FY)iihAp?>ai)Zg<4df9_t}HFN{Mt6 zN~&3uyEho^oirt&*Tk+AyUTO=C`^n{@z5d)i;l1EGOqxfmiHK z3|uf)qcaI{$0CL zGN$xI1XKFl#8ZoRM-#5XF&x^knfQekAf|UrseXz`+}m``Z#wfwII8iTF>XB8-Pf-? z-cF%*e9FnXZrX%ooiZ7T)qXSC=hJ?kM2YJ5Vked1ljeg+l>T<%2IUB#vC83_6N0DIc;5&LD~} z>;2OM==;-rxj|9J3qPVpMhta== zE}as4(ra{0xeuSg{0-3{7*GD>iz;^WO0hkB zl~4HLHNPj*%W4`n@J*O3h>mc1!$BDl57l#JT{GSB;FUW zJ(7KHbFlLF{M2w}_D{_mlYla*{JXMlFfu}BHgq8>mMA?#JK^UmU<<4^++y9j$9bBT zZ5y^LvA)5PB-FACouLL6T~$%f)92M;{buUr7vP18jm->kf23v)GqY*0gf2?g9YV#X zDN-DiGwjK__Zz0-0(rc1>G)tk39z!-m2wqpk&Jg=X_T-mEFKKaR?Hm@xklhFA3z6D z@00=@AXIk&IPK9HfX1P;UkIE6Rm;Z%|8gL2nN8}LBu+uDs$$#!hi_56Wc@CusPSfh z?l878G!Cz{K1r?0aM-ZW) zu{{mlq#gV9yrjD9@q}mNz-s{_t^NKcL zrtMO0ncB;i8PzyvE|5Z=AK07=27a~N+op6nBB1GBe}1{|1IAPtb5SGYB%hj6jrld+ zP>Qtm_4T5Ko2KdPTY4h>C8Vek_0Q&>lAUXiggV_#DrIjO|NVlid#non z5-PD=y*zI(@;yt>ffLZ?a@Co*P3h;@{WZhR@hS%v0&AHkvw=L9Hmi59s6x zQRB^|)$JdV%lR7UmRKuqcJYu>R(pGUjnYWR5bIl)HB;3MAr`yai3TKcwDLd>?%_gJ zVw?KON$1 z*xeFb)mz*H!}L`YqUkT;(d;J*Zis6^F8Q9lz3b{5&i6;$l6Us)sh5Snw(8S+&9*nP zd2*~P^)|9SdGaJXHF(gr?t8C>KsqsTs&JO7O z{y3G$cAFg)0qXUEj~2dP_qDXN|GIk0*=ORn>#XJW@0@?z{`~gv$Ou%FC8M4hzuNu$ z(lr{RI*-7Po%WzMH2>$7Oog6QY{&$uem z5hTa8Yu6ybhlk!nLrH<=_*d9=-Pw928c4NN0XHJt+Jd`mrd_jr&~4JGX09cK zJRDhU*2EU8aQJ@7kL8uQa=IX`kbX%LG`qa~!irC3EJJ_bdm6T9^~mTi$E2OWK$;c& z>Gi7apV7!W-Jt(3mo_|h7oTZ3XJ+^|Nwey$ z3%m&Os=}tr*D*i-U3&h5JnQ%05hySUjgM3B*4I;A^*KfBT+G@PRWudNr0!Avap6Dy zZ6)9BX>aED!y^@;xby%i^B&q2?^y$dT+p}MF}(kKdpYXxJ$_=b5=oe)hP4omP%iSB zQnP8$BKbSyuB!?DcN??YL$Xa%ip^Ei=S3d6Us|mqM#Zwj#eLnrJiU!egO(dyB6OcE zsasC3EDf~!!1wj&+WZSS_ZP?8b9UyC;aMASU?B5Cr3-UL{JHq!WzC{o3Fz9J2wc;6 z^Xsi6O3l%gA1fm5Vf_MRS;(gSrq8Kkj;nHWBB(fDRGFprplgk86FcDm-Tf)BKl}?s z@E2=#pc1>M-}zv}weH+36?PgKy>AwxaJ+BN``hGAO-*W9g@uK;1CLz;7uZp%Y}zLT z8}pNQD^{Bu8=eF%B{=RUA;*7YD2s%*@jC8G7NQinrFQhAG}DD2dANR4It5u%qfeN^ zOL`2gb}~_*9}Hr3OZ=9CIgzZF4mWXfEc`Ppw=xnWrktL*G$G+ZGD(>6vOwndug3Jv ztYrUEUpa;*qz-Lbm3;kr{?t4PDaZX`wt%Ay>jo|ZgUhG(O7LAApBkr`scGgg?Ngb{ z*K6LEmXvg~zNXe&7I^pJrJB*~aXrJ`ZE`+YD0u`q5p;2h0frwKB1${sDth%X+zS4c z=x+0;Pbn+O<&befQ{A`@{Z}jk>Dk}DeGAS^hguQ1kGO@@*=mY<{1E(I(vJ66e)v27 zEu%imqSYE6&HlZt*(}J1y-DAkYmCsfdt+&!$)@cYceW?cC+=4qu&&urW;5$;^y9<& zdfA80p{rFxT88Zgy!W0(w=)~d`E1=+Q;WdDw`W^FW5B;Boq7ZGV^`JAQV1yzyogl@ zpLA{z-gI%M=7!^N2P`3-LtQP_42ho0hT5aP zlvc0riPdMl{I6bNdlI)4*k!1d;2duq?CnEU`4U((1>lstKL_h3G!AX@1iQqc_&aP~ zi;w*)pc$Etsng|xA^rW&BQWT~kVFCP`e!jFzbgr0ZF4zC`EC7jw^=GkJDuDt&P@l; z>T+^;^8>a8={RLCzG2`FA88N;UN17i?T?LF62>|AXiZ$%>}1I5RrwX$q4m&O&1#4s z>O<$0VAf?OtFKxY%+P3VNy7w+C91btxl^v-#56DP zd^pft;On2vpiEuH?4~Ikm&PWy;onVPShfbdiQToC`>`xCezGV_(}K@MFo`bCcqvfx z;!?wU6e4lm{U~Cd-z&e^Y3unO%avu_*WBW%El1NrzlwQiR3)gP%g$u0Pne#3$Ff4= z8*}1b@hnv&E(L+df8V-^sJD2_n814bMwiSqDSv1hLbJ+1)-&q~d8`4aQsOHWOoFIJ z4q3r9eJWI?$$0O+mD#-w;q7ZtRN`|HJ;QfOd{l4YXVMCMYT;F-m_*IX+l+VL;sDLz zr+&rib+uYTurpF!nZ}KB^PWyc^use$QX%n;KZ=_rLm8hZ2iBg6x&x*MU}-?cs%yVK z1+z5QU!M8KFyJ+2YI9P(h{R1}9P_WOF;oMxQ*}p2RMTS2)F%^q6dcFP zDJN@OYP=Xf!~UK!FF(U3C{ntk!x}rbT1yKHBjH#8x*3x{^Ot>5PwiUUN?#qzIhc?=-Io}B&~t8 zSJ^=REdhEoe9a>s@s2xbgotlcknjnMDB-uJV$+@Bw?TW zClWO42TZo$_3PhrG;(TcSRyY8C$LhS7p~qSmuSLRB+&|KUiL5N3`}-A9M({0%gZ24 zZl1jhh^w%J7aeox2Jg9_ks=*GS^B6Kxwzix-y}j>Vd@#PH z{1%RVy$ti)eOZ!tS_LDg!Pgq2xCWtX7i^zjT5;k34{0OD3oqcuI{jj>GCbzKgEE2yY@@H}q zt;!#9ktJq|790KD1q!`+1R=HUBf3)iGkffe#EI_Qk|bm++dNsp8nEj1Up zX;i67Jgh;UgIpHnsc9S8o@;~hy(%y#?xq48?x{5-bmtGlZ>`Y?_z|A+K#;ERc=~(_ z+y);R!*M#h&VNY)dO9yVOQ%m@xQz-K&49LZ(z7naWtZ)_H{64O`H|U87wn3J6p@xh zgf&Z7R{!M6aKB{%$Tc-7Df{#1`@OsehlkI>GS~-yaot^1%aHdIvzr2DZNlC^7iEgz zA>(=c7eBebc5H91hmK$pNWhXH5zA%wI3M1wmOqlHGyE8IXqc3m`eNhn_w};2Hw=X~ zRVqjY(3{%1aQ4-F6ceeaPfJ1?^8QRx>8(x#=?Fm%>4T91J$-ywJ|lv>Brk1FzG+~? zQhAbL2;#1D`fQBR&%P~4N)cHh;3!Aeej}@OlnPJRYmoHe1!cTWQ>h%MOUgQb)#5MpFSU*s&PeUi&6eS>EnCw{YrP}(_6X3&zu#ZH zk##P~e9()9k#^}fX3lA3o(c3-D<>s#%84?!I77ZD9>Yp^5Ua0|S_`DF>O_qLaDW`Y zhLB);01y^%ePyn5cSlHziQ4nuP$rZoib{X!l2TImonrM(+`^Xl%QEn>nqdQtlhx)I zrGG1tmod~9e!{$4&{8s^EFxUk7MCE8ZZTE8uL8U0@jOEXVym;VCoZvYOJddrS4642 zM&E4R@l;3b(lc4lAxsG>9`cqD^p>TFTbw>}2F@;I!-_Yc*O(OVou#(XrHAX~lZmWF z>X>cSo4a9VGO?4mrKP_UM|H#0q-R-#LP<1A7?Fo1g;NtzCSJ_MH5iFW-}HdpHg-jy zuzbV9p7%I@g)9|6oVj_s5a}nq82+_(F<&8tkW;HxQZiaJor-;sIz^|nP`p(bc90%2 zlAdlDYu_@(X`G;g%@m~843cVn>$$M{!G5)$8@UM)*O&U)FqP(B_tr^$J+_*F^AXo&F2fV2^%U@tKghqQyt={5@}|qCg@9*B zz={DAlT%-B)O5Xog%!9!5izASyxGfOv6CjyCh+zDwS^X|Fp zck*n6RD}xC+(axqq2jken3JwrR#ed?@d+~~@!0;!NgY2VyvkOSX-E1bUyzTcLfqWG4XnJRdDkNLlr7=%_qv;JwRfK zWWOu%43DLYW7$HHD?r=m2ULQ30w({pcEyN)4xNvnT_$Di zR&zk5Dd8R?Pkp~m07ZwN9E@|c9KYkv-3ca=XODc?S*u`O!>cUF%p==Aqb%ef;^895 z$kXwiPY?mk2LRLhIlFT!NPqBT$m@qf;IZhV!o=?7D$+d$eA*~UTfu;ohL;YQ6VY5u z0jOWBtNVzblJ)eh6O&8?)8UtK%xB?fRCJlg_7`L=!5&iSJS}Uv zHuyybw$T?!7q@$V*ReMFdN%AYF;mWmOjR*=FRt`p@#(6XTWF%F-TH| zM;{czv3}>>l`pTwV$dp#62PGa?*DmsS=Lif5xaV|va<5?)SP}Dx)d&tUGwQgko7B0 z#z}mfi6uM45!$`6ujjPw$hswIZlG#!Z}wz5lQ|HL=9}h@V){m_^-rcFyUU^*PpTEC zR7iq!JO^6?TG{f{zgM&K5VsQkv|_^9om=`c8T@juUQ?=c3~EsCUdI~DszAZ4N&(AnfVHkU z`*4NZFI%Pn$3=|N~20)PM~X*3fc1(afuhz{(E^YfD%Wg5@~{rBgTs$EbqD8iOc zOtSP?OXqduNN{%v?1Qv1WO;a(UDD%Vzj9$U-rC}Z=%tR{@6QO2RYR z4vu!`RU<<%1g(EbCfN_j(m!bRp&7MOXAEbBeDQP-Ibk2<7q6Rzde$)XQ=cNsHlaT~ zv;P5%p%+E`IR7b82(4|EfwKgk<__B({%6&Ks|2KeH7D|>kI}U-1~lw%8S(Ww@N@Aw zL7e>ml6HLP5_+80AE-jiBAsOA)RLDr-y4&|H0oXKUg9qzS+rppq`;5f+k<|{FFpkY zg>`P;i)WaZ#3sTHxE&2ht>NJ3%y*)u0-YD226yAG+$)bcO3cDjph(0cE6AN7tOS?e z;`xWqRBm2MT1S! z)SMh0T~_5RBN~#5NN@vEM;S5ElCXjxd^i)#ubCcdH^{HE}pR@;!nEtS<6y?SP?3~%L!#fJxg#D@}m%;2aS7G9=CSKd&A&X zMa6@>F4wc0R75PgbYZt!#AhQmMd*>tMTFqRSBDx)U-Liy@aR`~L(S#e@;!+Uopq2! zJBsu<9nYh*Buo)$>i2cXBLQI{Au!^$^^wB!kw10x^;hnXKlWWtvl))oiKrji*=oSl zKc@Q0eI{&RcsQy23RYQD^BnNVehr2Qg{GA}t~_s1 z0w;KS8`QdfYP4*lQn&jRc9x|J1XYMZ(M_t+p`l!7yb6*$!m6x(>cotcMvN;WQT#L^ zK}e(`#3(`sjfx;3x}q6Bq^B=lxfgB$ywG)aB|}5Q3H`h0-M``O%s!GYLKPD~8^`2&T#hanW3kD4%6nf+@+ z`A?DFe(p>AYeRnAS6nV$LqF(P0J@`S&BebJK#jruXPVD6`#_sb6pvvZZ5YD^Xnddtf zVkgqvAbqr_i9O1KaMbp1Id~>Gj2$aQG#q51u}9^^bL2cu&`Rkm_4Dt9M4hMZaL9Vn z$a!z5vgKtHgfB(@R@&w6qMO)B_Jb(t>$8Al-k*_?u=uMFb3jlA8SbC(*{rN1LYbeH znh6U^dzZf(IW)JLC@HyROf;E9Ku3{eK)CzCtBuoZWA7Fr2&ZGND?x~$QQMXUHhmeo zXFoN4n6GtP(79dBYZuZP&Hl!!JLRj$rb}1lYifo*yKA>`*bN;31ieAyW^s5}@mwn?EOAK#X_?)3}$w+j8#>{U>tHJD#g? zvP3{?m09sWeSKKsbHcGC#`aqg0!&HaLBYTRjPyUEuwJr!xf(zpQLZ#`VtrTc zR2Q_f6f+aqS22_yBlTn5)nm!%vpgEW{Zh+#~;$F0EM_t=ki$DkulsX-(nq2TLRwe%yaRMYSfa%yW%MYs9; z>RO`+SP=qOMl5c_)&O@ajW;8iVJX!T9#h>isnwy{F#Ta;0|zu}Ue&v4tL-+-5%y@( zMWXoWsZo#{svtHUv1>Xok0Rh>NXvi9f*2q7T$TzstwapHDE@ycP5f^KK>xFXh`J7V zf5+*{cNe9K5CBea{7--&8ptLOC^2+pbv3`_n~nuHP%ilJqtkr^5vOL^LI;W@Yg>Tp zE(2B(xXX5Z(o9o8(4LUhHo4XKv=J#@mCqpyi3wbhD>*p(8PyDPf_VOU!18+{HJOYm z8tBl8DMhCRVTB%@wYs*pwlfV2!g`udHF$6S;3jTUn@>SR!3q5_grlMQ1ghG3`i2cw z3jseKk_u_s>yuMk`|@D{; zAK&}L=)F0y)YaIT1l^qOK=!6fs_W3#8`n4|+w`U{9V5cwIAT#yaLP?XUhQ;=>vn&E zv0O?>xX}Lmd(=?)-76qjH*U0TaFgFSdLEej?O#`8|C;Tnr`(M1{j7`FP0X6bp-9bi zkbLbd@Ah+iqpd)N-P5hRQ-rI>6k4#<1|;QD#O)jWuaLX@3#w;7^J&X->BA-!j#v zkC_sE{RrY-(d0e83-K?yjX<6)lv#DdHKaYn0B88-GP4z(DnU5Pb+mja3kH|7{a}*R z@BC7EwPvOND^sQS${qkbxivLoHBwtTf=Qlb=fds+O*sW7r?@QtqyHJOR&4-BUi~X` zYzN?(I*u&(MQ4o6r`tbw7COb7r-BbK=7a`Q)FY*Ag!UUA001 zs5!d}s#x0c!BZCl7Vr$f1AXuoZ zf9Yf3uA1Lyk>M-%mZyralf}doT$b3p1k zIAC*Yjb6ga%IfXU=LSvwlFz?i1`A@c0|OXo9jom#TD<))3^t0mVK$7s@bb&mRHwEZ zk2tAIh*hlAeDvQ6G$bl2qg<4`gD-(%H;N=aEMFzvs(QB%+0JWviJt?Q53p-zzZ`>% zBtrhnP004&!q~a*`rPVCmUnn=VO;X+*782A_FqMQg{Yz`Khb@VcKIlhxp8qtykGux zvXK5Mp-WBAp(J?mu}{16Mw~cj=sq=tG*Gox02==c4^!|EpyTI&vqfS1NAY0ydIe*q(q?`HU3>gOL`+&$)@Y8E(peq)O3&(-8x406a9rD5*+7iw zEtB|(vG%xWNM0Vv(BxLv;Om67C<($AR$M9sWcbIMJ)P!$gr%%lN)&rPoC26`3m*li zE)u?{r|s>`q@(Iy9A!gXdC z_}&GxG-7+(Sp0tdNi>^emn-NR6wuDMfcjBu*dW{w@?RfdTnILWnDTNlugS7`>2;Q& z;bA_+?r#Bz*qC3Qlf~}hZ`SV22*;uHuO!R1@YZ#yEce6lR5jZ*4Xxkkc(!Y&+(CEq zL9xr+M5z{W_blmfLLG@6DGjFFXGuVn(WMQ%{00h2hR^asX6sfywtes&(j!G9uuO`k zRbA3ZRJTh9Fb%Rn*vch2KUp{GfqwvIYYaC`F?R((Pk<6%YBk5gh?l#d3n1zN!s;$~ zvFqerN>jiQFMx2TAQ#w++`h?o$l~I2oSdAH;FG`I;ZX-*CeX;LB-yPzcyr@j{drWHur1r7`z3K1lWM zVWscdYiN#h%iQWxX=5HOHmK#%b3ZIsO8n)Vg*1rp)z}U^n8sqe5mS7ae zKSkh{c1DFYO8WGdAs{Fc@bvQfU1t_9Z_~#Cu=ZnHN5>>;1}?{L5=i0wZVNxB_r?xp zlLKTg!Tc;5rc2T{50Wf_!4=Bb-*U!YgFl)0;Byo$PZNhBSLBHMJ7)Bi1cDQ8z{J1@ zeIUoBB&o7GuffdU1+;Xk8P@#z(TZXD%ZNrF49aq*k-=^4OX~bgK#0x96Y-A$eP)C#pBcaK zZtJ5u9WMv_^M_mC?6G^lT$Z`+efjbQ5^T7V@mgCF)pR&E<6}PP1H)&L2~L-_dXR#d zh01RsIv}g%TpBa`=Q4uiim(M~h#n}oP6bj%HWx(9gq zhl8S&n=SyyQYA1HJi~Xb0IWVdHg=k0x%x2XKEU{pf~+cxH~vf!iHOB)Z6TKmrbLC<)gNTd8G`uY5Gw3z1)uOasFQG^6Jc3Mf z>MubR5J$w{o`ud;PZJDToTQdj=X1qMGO^ldgh;&Aj{ryqAJy+84b7wl1tr@Vr`7)C zrRRuxL*y-Uz(z!2ChR^sJGKL_wlg0o(ghrE@A^m#&hy2Kcc>_1ShTlchJQYcgwK;xcJL9@H&>u&VSStP_B8AWJPkWeN7Vq_*ZgJ; ziYm^QY`{90o>MlI-jh#Ze-{XVL4~#EpidaUI7i?nZ3H$^7A6kgJf5J_DG`K&2gJKXP)?tRAZ`F8bnvh@Ug>Bst{$#1Ubu-KDGc*}Azhtx?jcXi%kxd~JYQ`pgH_ zBzQe8*M*d^uZ~(}UqraLxI8NrbWU(^2${B35~lywR)wwxMK@r&)o>+C9kv&>rKRST z)h^t3OXP@tme-{2EnyVV(E+=cU`^ZoK)3leo952S{FeE(2rJ!`UUj_e@et+}s%L3` zg5QnYy^bOSenc=N&sKg-WvEy-_1}Y=M~@!e)C}0FTUnOx1=D+4IRa_R z(MezBr`~G&{w|=I%0R4PcpW(|Zqa0J7ydZCdLM)nhC66Wg1|bmvht$s7Poe7G4%Ze zOv!eO;nAa&0~-r>Q_>>@=QULw><&mq<-G8qUViq3ugT$SK`jF(r%xd&*)CbAPAgM3 zd9+Z%XJnKs^l;jlpq+6?mjLfqcu}sE%eex8SSypZyk!INpnLI&_+{El*p=unKYxr^ z@8cHw{kgM2VlXEshYSeCPY@To`J7>p~~G>Prg>f^T+Lqmkdfb(NDA ze<#KaBlPr`oEtW!dKzp$V#(t6P31PKC!J57_Ll>g?EuedNd*A$Kfy%19*pQ;y?AC0 z81!%cbv1{kxIubQZC8t3FT4%zG;wXEJWbe&+74t_&XlBFs;rE92zH3n8yPXuzoA@$ zz04} z$A2G<%+G)LQOb#pjh$2!!vsWAL)vLVq6*dJ2U+LxyYE_0OpVOJw~#Z?bTxR(>Q3>& zwp++wxnDoI8hcZ8$^6#4U1tfUgiAC)h~YZxup##xB6kv>Wu0KxduawtGw#;J#KhyS zY|g_z@%~w$0GDo=2+AFh^t*V}5_sOl9dxVF&~h2dDPur~0kAraLT@!}h|zJ}VFZ8I z1M=o3_G_N*!<$5gTnph&R4ud{FN5*h4rw6l4nN19H(Km%YQw(u1X6Uc8k81pe865z z0(zDE-R;g+oedouJMQ)RLT79)7-kRw79CxCo9*X=z2&c&E}NrBT>&%60@2g%CsZn( z3oSpX3JD(6e|WO>l7NEaHh%!4a%)v2ggO`$ecsoBkJ0kg7yl%eMSZLBm0PZ2x*5TF;6+{r(wA&?AOE{bi zTgnkcc<%g^Nq&GHv%V2kehF&{QlrnDr3wP2j7g7XbDIo5F`-e9svo3v{KiTfDS|C5 zzu6$?FL)+FR!=dHigwO-w_2=06d0U<>9p73hG9~2@-<2&@A7jhP@U>*K@|P|qr9#S z|6g8#|JogMw>>9sD3`)U&87cEj(sf7n@oY?^TaN=&BR+mcE2e|Q{E*IAk*g?aG z_)nN^xvqQpv^eF;Pm2H4tNi!PgMR&hI^61Jn%?`VP24@@LwWKg+Le}d=ebEXMZZ$WyQSi*~t3)^R$*W!6nDW}_X=__!s7~I+Z2-QOG*Fo> zF0d=@a?K~j9~NEUXnxkr^pH%uha$4bkB*wIr!~9yXqQ0p(}P@`A`+)aIh_@Om>N6$ z6)~Bji;pzN|A?P$b3uOmXM@oW#%>DiKa2$%h3;_Vp{)KH$q+fLRnU(DGP@ax z(!yhsH`M)h5zT+`|3rN_`AuReQ-N;<@1`e`cu>kIgaQ%b%xGp~W4!8p`mnnoObVHt z42?%@PE@%A1akKi<5uIIRzJZ^81b0kuv12aE_lsKf|6`8$nfy6!L3fn%Dcp<>fdT7 z8!DGNv`O#9vYRG<%M6;U5>L1FT-88QMkB@kRfn22#4dz!_7%fw*rCeOh^|_TV(|<%94efS`h`zZicMa8Hcfw*_76I%@uVqZTLvFgpLV`-LQp z80YD((lgRKZ%*Ttr4P>aYLH;S{AoGC2kHBnkp#6RRax?(mtO|=spHr(Ba_xZmis3L za#NLf6vp(ml_5^*>_#{@cDC~#((p8~01Es7m*?r}32GC&{+v7%%6-cnl}jnSPAXm* z;sV%iu04Y3^6lpoR191j1>zrIz+re~;W$1bh<+wsBTs3@H;!dlkk%q=5+^eGhAt}KZzK5dC#$T6wO8$B2ng-iul zQIytfK5XkHg*tFIcd)=9jWgBU{h9t#9;CB1o!>pQg&=>;NE0vu*yknc{7RFHUpOu_ z?MqJJ;vEa0wAWi>?t8Cf)>mqbQCpo`KZ7Sypp>lWbdDO zxJ>!n`xhJJ`dRqgnZ#88Eh70e;CxcmK|%yz+!YR_|=vNYZRiz+OB$x7B>aHRaRa+hOmF`c|LmhhMqWD5#s#3;F(GqyipHRZ8RF47PA_qOS! zr**x@{}seP167z08lcwm%>i3K(M~vM?EpS8j8)Hm_%)K7xGVraor-j}V82ad;Nblp zB6e)Rbq_Xvm_L2kbxVA>8R6GMJ+Neqz2z4xDJW<;7&DK> zz>gYgceD}ZcpJ|jARHK*oM3%F0l`gyS~3Z)>1{^h%Et9>ML8mdXd!cYyx~_h!a_23 zX%1H?t;Q}Rz%KLeD*uaanh~n=sUShr{*(k)OUl`H`YZWP=J&oIS7ivF&^$!R zN8lVth+l=-RGGpH#tG$F&U5*&RDVFsD}g$zJdLzhV8cUq(_ODageXh^4|uH z+w>YI2_B}49y=)Ch3MlRzqT^pInL&j{J^hNSu!r~MTl85B%Zv$uO0CRS+}>>hZ{X> zlS63J&AYQJt^|4yGUB_>j@>heSG??X7DiAxh$|-??EnVg6R=d@6_vtQ%d@~(K)Bcj z>g!I;>=8L*CO~`Cr>9P7(D^Q*QcoB}+~8C*Z!LAJ+!@Os#V#EiSZ z>YR^**s1xH=7LQZS->k?Rf%f(s+VtaR%!5Lti)6ZiQnz6UH?{SvKg9TcOsyf{@I(% zr=CIQ)&YjHi!>b@5GMo5j2}Zj=LL$JkWEZaN1tPt%5G?22h_qU2;Wo;Zd!djsjy1e zYFIIo0QLdmx^km{j(Dn9#E0mX6vb)Y{?={)TM-PW)us-`KOAQv`k!v@O*>FfM1QK~aG6nCI zl7DZ$pvWl_SBu!f z{tLG3^6vG%w^mqywU7e5plFbaFLh_!N#gxYC86xt@g?nPy?+%uV8Fveo>p2Hb| zSe0ew0A6XhY^-X6Hx#OweXYpyVlM9ew0!?_QNHJCk8d^o6m|p~4I)_WmB@Bgi(2&K zK>T`SyPhusToPSLUumQriXmsBjca*76lK4s(fp3z$72ldg#bppvG7~_n!_F^>7X?| zqzI>O(2UWo|EhQWq0IkpFyy%rusvOH`416(761&hw;V19i5R|f*^ilp3(WxnzH!cF z9oPy@PV>bV>yT`xA>PM;qu90eEbg8;pL}E^tVTofEYJG@9jl~YqFSVdP#umWGU35< z?qIbXYl;>5S{>ZPuj@`gG>8gn3u>@Kom-FJPEVo~GR(l?Q3ZmQ*RQ{!k0FgR_nLMZ zf!OFib3LLno+Wx5ygz^P?9(&kGTwEyQ(6Ok`}t=|^ak^Y5a8n1KlX)f1sr=2=4M^| z35{L%@E|!WKOJA3N5~d9i;f?n9>oEUILL!5e-ND;yp)7ezSJCj`pVq|Lxm~W?my)E z?9;LE;am4k`=ltdE(8@zOcU2o^IGfg9{{#N4#<`N3Owpx-C(`Tk+jGQIFsGH$P*n- zCoak_d=>*VQ~_-=$9)i4-?%8yoWxPEv}R^EcS1Sz)DYi94E*4!(3?L7eX6`ix=w&E z{QUhp+|?13ToBsAy#=o#d*&3_P2f|eNlw=UPS!u0tr zBjo`Nb<~EZRY2V(6h=wrUz)r2GPruveJMHY=ZZDp?}1JVvE0cX%Mc|49y!@Ta3 zUsA88Tpuj=xczPiEM!grM)4C-2Tm3`LjMB0D0fz=@ic^X&`^Vq>lxH-&H;5e7d0pqvV8;6L8+dIYgvQ96Hubg~e6fq@(MW5{UHalgO3tc#3LVJ++F?Jb>+H zG+DA9x`zJJ7wAe6v;+jP$$iFB*$1~hWX(My3uld;6z%=_bML+)#K~tS_=xu%Eo0th zIQ=1O>_QoHC^Dm+z*^xQLJN`z?g+UGn$x%`A{$UQJL=Uig+ZYqq3_>Pzp~~o@l1m< z1`KxN=X-t&J49;wfO-PJnqiy9t#Z=h#X)rvn<_lL#xIQ(4r1S!aYa zXmJn!%e!UA$}thWBrTf5<;)Ctw%HD+A*H#n;+`S+!I_qJrOLNqUZJx?1eeu85m0;1zm54S^B`Mx6h(pg#~Ifa{-%m(X932#nl`^ly@&u1Jx+zuolu*A(((j zMHt?L0(VS{kvA)vl<2-&k-QhEySSdp9yQON#K2T!enPIg@cO-Kc8Ku^=tv z%8O$oyWB4?QT&}NS>%g~_(ZlYBaQg1S7#1z zXYPq_s@Ir$G=@nDrG%X!Y<%;=ZVK$BXB<|t|+es3b8zlD6G~of8yCL4KFpZRx!mno2$B24=W$==~hP zmg;<}jwWqPFXFahC>zIpxb$2Sh_g8vA68=1jkIm0xM7WB-k`o3_P(LU=Z`QGn!@Dp z-y{a?>CGea?Hr;ofGf8%^NgA?t2K#RJkJM&V8pjeOIuxa!uHEz!$Rt73m)(Ro*4L8=Ki@Tg@Ew5kN7^m0#f;;{jKNKzbWgZh zbTOy9>LV^>$ys916uLI>U3zIg63>X`tfv!s2fG&VYq~0+rlw@&>EZDN3*=7}9^HF; zIA)yR;BzR~5P>Eo3R)C9BAA4s?x$5T2D73I1iRxg#GQlOt>S=;HO;l5m%>&}>6JC} zqc}FW-Z`Zrib9$xc=M*-Z@rwx#z=tj1AL*k+^oR+?!RtQO5!w0iUp~ZL zDTl$L1f{}lRH6W^P!b@mc?=2G4#c3b{w?t>RzU^W3MU|hQ$HM)g`t95L%2imLFk#t zG5h-9D*8x-NHtk-??(B84UD&`4Lm3tLbSRuT&rCrazC~!_Zv;Mj(7%;c4(6zxWDpF za&2*Ft_p2oiQqBaP!NMcpn~X}S#J#r2h7A)4j^#aP(C!Ab!KrK9TfW4ny{c$xF$mW z0o|JUHvU^ypWmka(HQI$UG48onP!I92c- z)f>>W(~cX-%1G1)mknt%!}*W@Khz-pXQ?8PaRjiD%)NYn<;no?+8T4oBBE$kd;$pl z6kp=|qmRaJohqYT9d)H`-pm8>&zt*ffDqdMGPR8p{_3g$pY;%bf#>DBcV9cl%X9E< zEQl+3oy`aYgTi2K+lMu;eXu(KEAO!_l*zePBtl`&Yh(o$jD6Mc1^flr`@rSPgWTEp zD6CaO3J!4Z*iRPBAnf3(BhSkO#&OXw&}f%GhfJ+`1<8H^%QX$od}J%eleIA&pb^G@ z_g-Ws$7L>aY{H*G$8ON!J@bO1J8y2xJBvRbRK(Q%*SAz}LjTQsSSK<^E`Wvq#~g{6 z4{)R*9Q{6mOxVw#w%{Icn0991zug3Tcs`HL*~>Qf9z(-=Tyg*O8b4H^1Voz_{&Q#l z*c3Y3M@iuXERDa9pyGakk{TOrmSEU;foDUIDo^we6zzW_{{BzC;b2FheT_5Jj=HyH zL+a{s8mKQ*?70kO!Zrj-dH^Tp3qe72lyBoOwscjoiCMJuTqD5`Jq;+Qd5(LCNQ8V7 z>c+)b{PCrX8?2C`z8L&meK&*c?nGd~zM`kG`iA$z4!U4c8iK%zzs^<}Q$#Z)58l}x z4D_TbQjEjv6l|iwa|SYefS)=-n3wTkDfVl9T%8^Hm~yC(mAMoT>e{WvuIUOSShD`U`J)1E z+ReB_KM;?{h~+3y=emS()n0<^SCERa6-cToU9z z08am=j?P#G^ybYzKgUpY)F}Euh?J1XSSmE)vT*b2$nd_$CvJIX(wFOzoUr;I=N}>; zn&o980qrEfIhBs4D=;Z7NQt*#CJ{l=;WDs1{;o~})R46z?AG+(S?n$W3$6s~UE!Nb zTi=B4Y&l-#dAgt=A`HjOdz)r(Hod-1=aR&M{xxri!PYvV+ivFWX6ebsKXVE8yeO(n zRaPYHOrwXZ5MP?YxdnQc`#_!pe|swPA(wpH;Uh21DunKgYq87Q<~ydph3WVBpAS;= zUU`m}80V9F>;8ztEj>5PXleD?9^69k(!j}LdepAZ&_b2w9yuS6%zL?SWr$Bk@&VX^ zwIsrlGfkv1ZYI)02=?~&6y9KiWS&J*mzUGJhdp;WFcdnE2bGqX$D8Wtzi-;Gy?n^h zW{?rJm1>GnHkY%NIv;R%)5lHOV0ks4#qYLyvgzd;rn}2lD=Gknxo(v;EXZPR;TYpSjRJ@KfS4CT_nTS=bmt=>EPIxWrX-y0?nRdO`>Y7O3 zYt;$X?5(r!H)FMGSx?G;39H|lwj_;+C<@b0o$v&pNXi(3HGORreS#%zL7A&4rk8VO zpG1W80*lIDiw*Hs#lFx#0@?&(@0|eeeHM^@L=t=~4}aVPsbd*IViU$czwVtoetTfo z99_tgYukUWi)0Sfa^ z4_@Kv)Fb~&@;MTTN#&5_F^D^})0XEwEHlQ@SXz{$GxMJFC}h3{ow@nW#4>1v9C3MB z1Mb{{9+#4Y7&Gc>n@o6r)R#InFa#5P5>9{QhDN)gHwWU*-nI@mtoaaKF1Tmabj;$C zgY<3#%Tr5ZUsvWd)IjP}jMrYs!4)Ln+zf**J8BK)ABVn3p;6bet%lM1fVJ2E(5w?y zRc5}m9zcw?%ThoZQV7;i;?gcd63<|*YE5Y(T|?(7vAXcF3gqB<8xvle4&kp08;xi~ zRgF}nSy`1J%y|r4C#P=l@J)Bo$G`P=%uIAerAWy=a}`(BK-mH*l?jv2X4*0OBa1I@KoAT$Gjy&MF*nF~AFkx_R9LXF*Ce}mC&C;_U5XPGDDwAOvK2RZl zePEWW4h&6nk)ds^`@w5kv}tnCdh9RU;@-D`x`m5&5B$|V(cF_y&s`&Y$-p9*%>9gW0TzG zX@QOy_1!xjeQFJPhF{~CA(T7RinSevw}Y!l4zoP(`t&qs2t41H ze&5r){~=dl-F~Zi#K$VXM4<%(yvY3~^bhN>s$lUm7XXwEJy^M<5q{; z-m6?H7X&?X;RYs1O3u}Bnye1bn_Jpm@F17TG5b)7dkve#$Yzz7!#uU^YkRL?r^o@&jV-S!Bk>dszY=*p5wKq{e_QU7Q^ ztQ{^E5G4pBe7Sz5 zzmP3@&-mzI)ffJB_5~=>nxmbp+%bl9qiacbf%CdZTkNeR8FYiPh;JH(yf|dC>hs#} zgnK&l%TC$$SDIHhu%2?z*$yIa3&E&m)NpM}qKKx7-R|g9ra77sduTANHEvJd1D?Mp zkIHu{0L9G!DG*(WUWOOx$Zv}PgnICYA!l@f+h35s!hedP{!M@Q-`CfdQ$d~0S0v^+ zUi?7yv;v6T@EgY^gNpW}XyF~RmqbNxfpWj>znyGUPQ&y#x|G9#q6!YVh`V!m`w55! z(!s6QcQJ_D;_&|LBxLZ=Z}vjC-s<+)-CQyRAow5ISZx)DTFHPRzikq#4sV5h?ai@b zh!EnV{!`Q$)$MFLI)E@JUuGYupKxGq^!(x0>kwWlA)88Cwdm*lTmY8l*mvt5yzFql zGYmr&NcR{@1VgJY4>`n!CxB>G*I@WMWL5qtUeK(Y4(b696FjCcY$k!{lL!nowgcI4 z&8hKph+7J%mv6y6=N_J4ngQ$VrvQks{qBvS>ho+!LjK%GFXTG3kZI*EeKC!|a&4A= z6cZlZu zs^6+~4?dL3pW3jfl;Zj{I?HVOoLf#o^zJ^-kN(f)!w$M?H4Ygl4wFY6|_tY(66O z6vrZU9n{lXDD0YA72+`VYt8}`BqaT}$QyPkmlqZ!=A*TGvlf%>2iy7t-v#K0(#}F6 zB5Wl+06zv~I8|BQz|fA44&yGa^JH4Py1F_iOmh47k3jkEZdN47{UIqjZLpbY2fw3w zQ|lm>X#oFi4n3Hj3hP!KfY!CX*Vt^CBoNQg0DoHJeaZOhdK9d&ecG85^oT!(gg>xA7pI<&$tQ##u*;bWij;WKJILd^=(ut?|S%t2X%(lOW!>zcfi$CgXCRSSDU3-5446UQ{AkhEkw45(*+rk6O_$#FRZers0`MC0 zSO7U3>+H-mmKIf3mKMm>@R2cQ5&N4XHnD4}|SV!PUC%LE?==PcH?{|!RN zH|Eax1!<;9H*Ee5UUpzhB9_%Dq_t(KnN^GqCUm4wn?-&|B_M|{Hi=-=IeIiBT^www zSj7QCFWOPNufKn}<@bIZ=cL>AV*rodRs*>k$ZPmhI^WtS%fTyMkIRfv*zIQB^&vW*3 zDoX=C5;$F*$=G8drT=JzB|hsL%0(GcmpRJyw!q2PcMB}x6n{?zF?Lf!+PZ0Yl-#BD z6%$7-^JgJ%m3^o7)X{mTYbqstI@#Iy9sGNw#?e zyJ>w#C=YAdgg!bf9#ALB8o>(x;x6w)Cqdttgk!99uX^pJP94HI^ql}P1pH?8n!m$I zAMPKva~0+7)hgR!e>>+XQcs>Zv4j|_7rf^yo}4Xc7J*NVC{_H7ThZkraSy8`y%$8q zuSdGQ`Tk}R29r)IagppZ${4>cb8Cr2xE+wkGjnB||kH#jT8EQ+2=W}4l&Ej%YibXfAb zal`TEP0@EYg6Zk$fxiPoMnbx>^e7+{*_!-XkM$;zL5Ly2*QA!(v35;8h}LxYx9gZk z$3i>kxl^b^tFgJ;kSx#X*$a~X+nIxv%Mo61%3*ybL_v23<+C`EGq0VAJ*uhYUW?RC zOL*Mece?{xBiP{%jB1K1TGpK;Ez^4YB?p(U_uPA~&gCAAwuJHz^7X^?bv&9)!g zL(5DTM`y5U6#methiYf038vUm70aU46jeA*>Jlz&atnAoSYTFRBTSy?2(0$rbL5~> z%ZICv$5i>+QD33&(DG|LmH^>13BhtEQ+1f~Mle!R?b~#xZ}=Mr%`0m2aQEjJf`Y1=`V9aEi|0;~8QJWsOAhY}Uo+LAO|FgxR+2C5nP zSx+Y)VlkL<(^o!8Hl$cxN`Ktp`lh`pw`N{wuPwKf6OU{OLm2cgkX~#4_D!sQHIq=; zm1{XfkeRQO%J1kn?R4xWu?KI#T#Rbqi+SoG#dFEdPG-sBc-bzsIbY}#s4%@NFON!1 zm7*^OK)yH}5^D~@GKi4xnm|LH_C9t~9$3QVoO~^&^U>-haE(+`2hs+pS0#kXt%)A42~`zvM`m--n&H9#j=` zGk%?!^AfWH#)oD{=#3lqs)SGYAszEsU~~)?tE}A5a9C1RQR!Cws!CfGY44I(Gd$WL zm6&*F>#lYPAhTaciCS5QyyxQbasH|(c{J2FfV7l zN4UGceywblt)qDLO2b}i9dAZ2!~oh-AUAk^d5f5YJxg@7)U9g?z(jXGDCx%YFioOC zXT4zyU=iPpC@Y$A3WcpJ(=h-j{{8oFr(pK$Lb-qdHC|ID_&?5bI1FSP;$?;Adn@As zTPFlyi4^x(fp&oFd?#)ZI~*3>P>T)^A}?0WW%^lZ{mo3WKT@(k9iEkz_WI$22aX{j z_HC*;8`thBdV%IiHFItGU1xV-+dzFb(hf=B0fElld6d%QSAf$B2%gD;};o z$lnhxKtQB~-B@OFYbOeZI-1!GbWMR!LRb{3y}f<+)=kAK*9TX=;x929ATB)+%K0ru z=^i;UU5Jp8xp60Dy!g-Y=+oHeXFdR|@+EyhDjZ!7yfhG=J?>K#W|$KSCekP%ECf=C zuV_CYEb`lo=H4f#e%MlX5_#KT+Css=34s8}Gq0?=`u^WACv4o{UnfS&X~C`fNY{8! zg_b}3Yk&^HNp-=KSPHX2N-lpH-T>y?^7<5RY&d{$<$Sk&*bIIaVx`%!vVdcTg5oi$ z%>Ko85(J%GAV7OD15$jj)?H$)PnEu$Rr<1XZR}aBlG*B3^%qjF(wR$)FnBfyM1kQy z0yK93BTd%k$9|$0DgTTQ<9VVT@U(8UxiUu4edz7n_Xk&VEq9NA67WaBJ2^{c%U9%D zwhJ0P3hO4l`M&xz>}uA>^;9Z#cCZ1e6|`#<>%5{=A{WYZr-vyU#Dix}@0NG;5CV1_ z)+igA_Sc(Ij7qS_a&Ze5g~%u2#XLX0slMbWVSFa(NQJIy!20I>Sfu!doD{d4n@z!e z8T7=PIeD~ zm{tvW2#9c$>&obN`%#|}(fs}Ri#*c=5srjFp2<}KBz$%KxFL3RO<5D(w0061kNvm? zeG$A{i1sT|+Ea)JeK_1Gez<=svjBKha<16N}^6>W1kBq1(Q@cjQNS5hDE3u zZmg8hMrSwXLv<9kMujZ+g|IDzrw{lf;>Jy)73)C5wv2iDPpT@wog|9{VJIIJepqX# zTh7%qhHhci90x7np2Dhya#&&u_H;2;g+DKtgcG0Voxc-AX5E@%pP6;=z~3`Zl2cB> z91^Cs@iRIGajk;qO4pQMu9L>uAwpLR(hF?gHM&em_Q===<+h@ZWENe@(m0wOS$GwX zR2~3MSe^!V3q5>z-pdvUm9Qtt{6NGQt~OLJXzi}`>rke();JX(WKhU@JVtCMde!dj zXMGIvVU$3u*EAY~GDYAzblMle)L`yb7sW_ylaS8J%#ms@>0PlfUa_Fe;t0R+%LQt+ z3RY*`{U#TfRz z$eXZnI#+c?j*yTLze&hfwvp>8Dn!5pKe<=y&k7n{*8J^XKRnU+GDONYDHG|4p6MOI zZJqZz&ocSUJTMDZ89qw&9bH{xfM`?cJ0&b3A#wLKACbl}0-&>J=rFbp;2tJ$U}HdR z2`1;lLIXz(%fm8D7_dPE_`&UF`BzlmQ>VmK`{tt`LeI2Oz{?5<2ne++6y3{4Mge2I zcOj*Yb)MYLq`S~u2v~83j!UX@z&B^|W^nmJ&ZUy7s+hPqA$c_C-_BdnsFb%->%OL2 zCVuwpSzxAr@1Miz1w{d{!^vUe4I?~b-D6?=luI}iMl%H-sbu+2wXx_0E}?jO_r`8W zd;=X^%w25V`@0E4!hc8*yZ`Q_^nd(%awI*+RXue-GGbA=O}hV2PqVu_U{2)Lz6WfZ z-NNRy?yq>aVUiOwQS4{2@jwt!;5ohTIShDu4{j*`0RXT+i2g02%av@N?+v_*%#oYf zPK=cm^-YnSD(ycH8_r4m=?u0N_hf`A8BG08b~gbl^-s}~sYVZrYG|u=;10D@_Y^smh2`s^{+Qw!60*F~PUK-o2V-*sK}BtZDeCaRGB)Iw19EJ+~#n zHF|LOw^>{BM{nB!!=(&cwHJ<*?dt7U7q5(&aA@hVJ<3+7t22z3{wh=^hoJr!E8 zszhIAWU9APnc5zx*Jyvn3_*bPki+uWEI$ft#(|i4qTaS%;x^dD`FYUk61M)q%6%i& zeMhW`5990#ka9dFMU@)D5FQ+$uUZe|RFB~vPm}wwg}iG}-WZMrBu8UcbnsOxr*8Mt z2HRj#&HIGLuBN>(=+ShZDn-5azSLgAxh?k!t4zf*aT?d5?N1KC=af5NcuJV3J7{ zm6rclZH4FUMH9>biA)os1tnx$cn?;D!ck5r>3+uscN+@`1?2=XXpIOJ*xrF-a>7j$ zxwNAP)9%%;>`Zw39g#{`ql+$DE#PcyhuZsnO9HvXccIP=`6s?{Hg zZ$f8TiO!H)D#jZ_Aa|j8sNzdORAfK0gBma^vK6*Vse;8n`*I&n@;TZCdOS=_{$!{( zvF8hN58L_^O;@#O!be@Q(Hz*v`cFxOUx;akKX?NMYQ&^_19?!h;|~YQ>hB(F|JPn0 z7V$D7fV~*Hnhus>-50(8n0)p$dPWwJjM{808{Yz)xUDD16oHURQ3vEA|4uceAa(@i zp6?+HNQMLE|Js)gY&!G_5y+>KX+8!-U4h^R>JxQh!e#3wZkyyXkGp;Q|Jos7bB3t! z)8U;HKJZ9G4iSWYBOq}u5ogYl-(gvpyq>G)_CAqgsf+&eeJ2WBDC~(}-6mL-QEtIU zp1u74F`*$j_Gt8t;ZlFWzna9qdXGVw&gJjXjeG#M8wd#d8-aqR6Z-J}JjVS+eadnj zDg#~DQ6!I%6y=4c)u$hhtH`Gq-<9R~6CrQd#0jtKV($yl1xjKSbNf8|&ssiv49jS` z$BFt^AK;j3jIct^)y~2LMM;ljOsm_IT{vJM-WgdQ8`(AB!3>uAeDyY_VVGAq=Ih-% z;7?-{Vo_3zBNC^431)Ov-#$KYQp|qz5p1M(G9F*Z^uk2D~@n z4yR~*%g_lMhdlsC7*x)9>)~DVo|vLYy}rXsTXmSwJFqevy3fJsSD!SdXTAnky90E;@&MJfC8Zg;?RvP##sfLU1FdNRwf4 z!<)Hdz{E?Lz^$&keSZy&k@W9UuP->H;g|2U$u|-9oCJF}L^segA=6hgKfABaSa4J- zeO2Xy@Rcs8^djs`nYR#_jz_?mejZ|jT2&!OiNo2Txftk?gsxhl@(i*UHhSL2vR8`98 zCq#N#XEy(Qn@d9{f`0ePT(fLP@hx|mthEOjA8etOd{RYY;1cGPeDA4gjIySZCh-7PP6Nnyv-qV9D!nZd9^MRSNC! z+oBx_&kA)JagT~1m9}+d@gi(I#iau4!gzeYA6Je8dmqiS)3$%toge~% zXJ?jc2QE1}{}=luUwrFm97wQ_f@+n}TuMrc)$Xm17yHUL+gAL0^dX|je>A0C2pBQl zV2Y?kmhOk1e2bwLK=FBGo^SQ)TsXZQ_0RV~D5c4Dp^vl|HZB%ZzDfF};y*SloF1kc z(e>Z14vBc~sQ)mo&?W4kl$1@(s#?`|j9D@g5JF5Hs;9 z0a|}`6-z!Vi}ko@%*X_$EV1Wv)Rizxq+$p&k-;ROZ$EzkCRS($0jrHZ;bWVNyh|lW z!VcwS!KU4A0lNWy2V{D;zx1G8931r@5N8S`G8E>J`JXBsQMfIH0O2DYvssd-jR?Rd z4p;Z<(;D+&z`B{PX;qGqT$~n=y9UrJ@AX>HH2qD>pR8F)Bf#>NG2}Z$mPzp~9`6Qu z8-F{jEA|qI93^!5@9YkWT5f|`B4MsmrQMoBX)mfCrGVt1pdGe8690H}OfOin9~-+o__GmkyORg03GeyRV07YFDuIO*#W%-RMjdOD1Oly4Eybj<)p-F+;r zMx_b4?*m$A=8MBzJu}QJk^|QHd=)GO-+On&H2{<4ul3`c0PDRR_EjVp17EK&O^>@r z1wt&?baozIi!RrQlrLg-X2iN8@n6Z9u8b5OtVsg$doFX20j76K*90WNnrL;$^nO*?F(yo_J4zIVZq1CoW>E-p}XNaftidm}S(uG|2eiAahMo;py z-v1;8{KR4B(f6R;jl=~!o#ZC}YjRw6B7 z<94$Z$L;o+^~PCLW6vyu;Xz0m&VwMv@S59)pWkGUV_45AF8z1{?i|opW+c1lT`Qc`;zv4#~#vl!z_+)m)O60R>4uSBWs|vSzvI^9u)uRXHc_+w*{47~FCM zb}GN;$Q|NtVVNV{#hBZ-r9gC+?BWp=^$UbJ~InEb6jMrj;d|$NTdPulqhXWbS;*+^kg;|Od z13lJJG-v%Lrg4FKf6%XGS`p^wEX!9Y}|j!oN4NUZk*>0 z1^8xA5&;Y7OR~ZUwP(jb!ujh39^*Bs-Qe?CvT#Vjc>CgNs`ieG1Cm)jirI6xNHoll zZ{{rL>F_n2Um7mWunQIRm5^j`pLL&q^}Z1>T>D0~9$53h9B&-uhdqUoBVSwvznds; zCkuJ!@$z896ByJ%xP`%B&k^53il4C`V5eYb z8bCOt#-W%`3t-Wz{5~{L-tsgwROUFXpLutf%e9I_6wCEU)X-n4TSl&-hvS1jys!BX zS#Psj_OP&V6o_SZ>froRo{;ht*Qahd7r6`_e%bN5lx4l*^5C?xef$=Bpax111KOj< z$q=@@{oIZa*nCJ*ZToOMRj@ZTK%t#5lCd77gQSYDSg3G5Zyqtdi@l}J5vZQoS;CN6 zu%G6a&%^V9rB_Sh?xLhi!rI4&))n&~@1ANmHg8{slR%Cx1O;(2f70_^J=9JiBc#E; z)hQ^B1ec2-nPuBq5kr;pxF{j^IFa#eZNR@&y}KwBdnOAIKa2yps<%nX=RqTEg8>Gd r*v9^Vt)6V!9W314v4WN(zG_Ev0nKPzoplf^V>_lySjW_BSmbS;?aAE*1UY_Wm za<$1zLwM4rXxv{$`bqc6^Hd?$!H%ot<9kc$ZEv_HZ7^)l9WVT1H%k zxE_-@3)e2QcU%uLANyit8d}wKtD35crO8q5DKFX2@7JlL2AiH<3y)p1si8_% zV$fzKoJ$t2qw}P0e6*^~)^oFIll*J0ha)5G)uT%e^s5bfZzMYDs*BaiC|-CdYVOVT zb?Tp~imea4YnJV#Q~60KKkjm*Z%4I>bgxzQ;kWf-QTx@y^1~R!y@&53G@c#5@8L!) zzFlqpMQhHvEKqocmA9TD`QkO{i|ZLhN|eXkJ+69xBp0iRuHSo%jztlROC`bBH0qD-deqZ4T68c3y==(5UZ1vnZEmLg>Z0@)cS^dbwiku+-{(?FxHZjW zR0OcnGre;XPLj@*tBHq%LD^lUxH78}LV^~ZN5L8DdBIWx?CnoU*a8;Ig{RAw53Pj? zLuRu?b2|+De_JrHY;%ehGPdjm+`qkcm%0CMd_jLhTOp%rZu5E(cZ+c)SAd3*Z#tTQ z73Q#fm}~E(hClpT)>N4IR9?>%{yX8gUF?}@ZgRp`YlU6<B^Oe5%|5R*7}uQoW(M@5n887H;!$)wZkVan5ra{o=3A)2m(0$SbBw4e*7D zj%`TKc=&3#lY(rTu52iY&wg_V(TO&7nT^tPhjYvdZX&pAHp2SPNlv-f_1*cR%jV+3 zyFdH(JZ}G6jGY8){%m8^dZ?QZ{{CackLsM4*O88uIWP0%c4x?Q60Uwf?n`g;`$>HM zR)WRm^V{u}$Jvf|pDpB>KbS?AH)4CZoJzR26?il`98{_W%>MiH!W}aLVNSOsXEe?llFWC9-%U;*ZnTxPZR{)$?xVi?3JtSI@Ge0h zFo>p#(nIgGjfMd43rh_o(#+Y*`v?aXH>L!NOd zRPLQviN=k0Y;4KRd`%5NmpYb>r>7^6%D?RG@&EG@BgS!$hXoeOq)fxy(H1NW;Q}wu zGE)8f2?GWAoGX+jj0{|vltX_(PH*J;`2=$MG1J_we{K(VeS8MiZ};%vGi-lQ4^99V z)ZEcs=c_7){nt92R3l<0mHYnv98P$()SE;Wp_cPPHJYcFFG2fS`j_i}_PY5J7T;Xe z^yJ`@#`>KhG~vD~{rfvaoRGC*uJJZ);m}`I^%OS<%efgsh|gs zmHOBNwUHjvgefY+5sV&sgz_O{iOYLFFX5AS7U-_`=iVc+uuP{k8g&1FPXEb>CJNl5fkQ9^ zQ^-)#j1Uh*Yhjd86^EUi+Lmb-4`!$q<*I$II`RHq5gu zQV)y<84;1}Nl^-A#2>c!b4T-G4Mo~;eDbXXolyAT!QaWu5@8h=6f;tmT?CGA#hB*r z9xX}Yey4ogz!Mv~1NUcQudN9uA!QXm?Vc6)Jr9vKMJXW%&s#!>7vv5K%#ah%3>tLu z=&g4&s0l#^Mgl*3(trZ0H7*)~9IKn(|K)P?Zhp}dG~RH>kMLET;>`?EO=Sc1aUE{f zYD7v$5Zx6BJMBH&a4X&+4IUPUyOfDSS`Ca+X1s}gqD#`S_ZkubHfgwqV4@|#ly?j_ zq+70Z5;O$OMCia)@vXDh!fn`?bpma47yRx!kyi1m3U7DcPBDC+Al-c^9sHQ|94q87 zJ$RgkwC7eJ!mw0;eo3%tGn*Q+#M`ZsWeFIzI>HR8F^opl0gZs+=+O;eS z0Vl#xOAkg&Yl4I>3W0N|#2Un;9DbKAFs9!6xu&bL4FXJpGh2mw&ijwu9RYRj_c2~A z9YVS9Vy_5BV>u9JWYP;0zf)T}ioGGULL*MT0?|L) zj_v$rRS=l+Xqf4Xp5ea63p3_*u)?%?0SW^<{=eYZfD`=m*Xwf=TAb?m>nstW6K`0u zOQs|Gyim})#d5Eca_LG5C3vOUrx-JJk+}Eg>=nxsQ%W0;d7oWXFC-Gb6;~T|il+QOPYpZ0L4G0cj!!y$r zvFtH_{t$Jpyox33mr+eTeD^?B{;lG+QOL`Fq}9RwPy~j3`sTGYFKJwfmk-Ha#W`%E z4cE!-d%{5wK)Rs1OX~P8Hb4!brLEnPm|}mvZCU6${DB6d!H|%xW_`J6Ik1>a!|Xn{ zyGhOqNsZs%2I=t3Y+jISACdGp#pa|l%ooEeEBSPo?%l{zb#`_>AoMT>K(da^o()5t zwx;L&X&?{x$@(G-$IWl)P>51|#4Y*4D(U&*zCTE_qrVx$Co$c48)_7@1Bf-ClTSVhj=T>8sCZaqOxKJi ziltRTF&le|vJf`f&*ux@5QW*SZU_(2V77wqH`J(ncH4M}Ta8L5caC`YYhAREsDCZc zz&ed6d=q_p?=5|GH$ITmoo+ZX+3QDJdP zOD2Z%`(pOGm@M3swzZMT<}NeYo5CXDfZ6yC7f zZm+W(!kBg{jAlQlW=0Oip%vklER?i=IYwp8<&Tcd?${{e4+^f($r^OM5B`CZ%y=8Q zL^EIQjmFzdA{NsV69}C7Uu{8fek#XoYxV>i#X?6n!{-u|Rkt%qJB*^V#Aq5;J6 zprIY2vG`IkxF_(L3?%#;`8_Z4H7^Luiev+Bcg)4QVQ@Hv_2gqb_F%9qmj8TQaMos7 z?K{>VxEDuN1R*ZF6N-RI5SmA7Abl0+L)kj(_AzP|r$cn{{a8Kt2&pZR|6E*BBGU`m zk8c`pIumdQXfMCEysrA(_4D(~5=TVE(1{w}Itl&&#lN4B4M6ul7 zE|!t+{IJB;=CANbVCBhd*9GVGc=azTP^%~nP2bpGel2N)7nmY8vA9cD9LMVxj>!Hr z#fh-l=kOHi`B$21lx?>#{467huvtBLYvSU*kS>K6VcYJbR>Tkj9H@XB_%3-ei=a}0 zdan>Zo2f36`k9n96s#7cVLCwy)I2Ngy~SVcv!}@7=>AFrtS4Gtj=#dh{HjA$rAD6R zrFJI8z}uDOz@$wIB%C%LM1ac)sg@hU-Y`6?wnW+E%;VMa=fUh!D-6g!GCe&<1rw&hVeA0Tit&H-A3Pa{y}$7f zqO|y5A{(ZeK(OS1y^qCRr|C*iKTGS%6L87sy4ote2y)<>4g?DuGiJ)1FDjO$Bg ztV+2!GoDnwXkZe4_&bKj1W_Z#quB~QAwjhzsy%s?TdkRwfgc~FkSARZI_iMhb_Y|= zM!(p0CEe7hA-5t)(ZvLsG~6vSsrUY}^uwk*MLdHb9| zmGN!Gx-~agxZJ59aVu+ZJuopz_DE@Y%i4vc4S&2xA)imRISRfIK|#%6oYJG)%B_J0Xtod)GMqUj#@VcTCk!k=V{1X;uW`9$ zkS%qr$NGpHg2zYI#Kc7R7>zA)c~wkLP(DXqVa+`R`?0PaK8iFV)9}|kKf&bom8L6+ zvw2WFXy36$@=iK^ZUxhcaS4U^nEPc#Z)X2UcCpsgjr=YvU@k~2@$+OygI5;vFpnUj z)s%K(m0gi|AK`sUe`@g&ImX#={?xXBG^oMFT67;82|p#R`*1R z8aAL7M?A*~x#zJU`$6d=7xSB=BsP0z=Pk*tKdCOd#~WDMU%!(X&|Obk6`${ZVL39% z{`|RfSK{`|wGb`Yq;A`Sn~+;RDy$;`lRiupvtMqHO^W~A!Q0$4t>jy%_Fnr`;6F_* zcFZbd%5$>G`!pGjYJ6;H`1-b0YgS&~nMaQvCA{8S?oDiy?3feN#!>@HfAyJhzR=STaM&bQr|KLl{suRbeq~Cu28?8R!=Bs;gBDyliLHA;3 zXJ_BcOqAc&cXi~SWZNt8{l7{5>QIx*zH>F5oMoHql3TCVOR*1DlQDY`p32`O`taMo zV8O67!&@2pr*>L)k}TD&GS)C5Ij;(1if+6A-~q)CQ`bL6f1liZ`)COE>^N$Ny&#Su z@`n`yCj_ya2(stLbaSF9q>3rIoKp}LXP|j`d5u(D2}&6u`4cfU}OL=E+i8DPc^W)ds&vdvK0ma>pf z3Xi9~M1`px939CZ*U<7Tfl2flPEJA+&&T>)R(My_ls;VNKvF_I^?rMn9T09H#O?y` z{L*XVhvb@{x+i2CPv<%g7r2HDRI~Pfd|Xe6en%s;Zq^!w7|N;Gy=b%)u9mag884`V zHmh~#A2@Tvg1HjW;ys+n7W-p&sZ-NfMeSoIX^AqScYg%!fBZuFHV@fq8l{!%6Zb1{ zGZ7zcnKR|scRD%`;fmL8=s7D{F9{y0oxAnj z%cNP}Mu&krRq1TM%k`sjv2-gL_p&QD?{pL%7TT(d*Ojx?a&t2wb^%v`p;c`s zkug8Gv><3So}yvbt2~#pwt4$$b9ki)#PlzCL31-xq6Bj&FgQPm6H1j*cM850702*q z98EV3rKv4$vlg*<-DUBRJQ|J0rGH4Y8#%Q2n^0=>dVO?TlYLt<#VbS%opU4U&mWsj zaj&h%ztd%nPJ}Dz?F8?I;_F#N7U?yZq*lA0q^U#0y&ru3X^B7DNs@57?Ca}mFk@tB z2xh{3G?3W%K{OplU?lE9UnN%M8S z3Df+@Vw9d<^g-he-N>KYx~ylVMPg^74W_%OobiT*>kUU6g%4hPc#IZA9&&V>t^anZ zJMS=flpl$CTT7>=x}VOQTyc)#_EF*I&u6PDE8BI0nZC+e1|uu%8gJYDW&``E5gQ6} zjdx|m#oDWsg&Fii>O5e&^MB`l5fXScIhItOW-L!OG6gd#u7=X`@lGvuC3bB$o|N_x zS&=7Sg+^DPVm6W6>xldJ$tuZY6_Nuc)_n_%La0Sj6a@qX0y%4$uLrm=X7FhySLZhS zp>Et8bx~9|7aA$Ugw)oqe?bDeWf;&c=-a;UmO9id6aet}$m%oS`wDi~ojtfVzB)g@ zHIDjygl8@P+Y3gbD)IVT#^YbCsNcMKQ#m*HE9`;7_Sl!Zsk*B084d2+B8xmUK7dqm z+ip0_C-iK`q56d=I1`zGIE7T*E*oA z+4Nor(t-WM4)5e`xh{P_j%IUn6DlVCp5_xHZ0|Bwvk)oX!Zd&VaO!3B0w#!+my|^i zc*`o1An4J%BkejHxC9T`o5#2kcFlSMdH$Hlt_YA`caehm-EA&ti7E_xos`5+y1kS? zVrp8P!5;pFI$A@{H0Wp&=e?-7MhOCrBgM4rA%Q`&hxN2JAZ-rihW#k!>mWPDT^jWD z%YjGz5fWflnr@nE=VJakWCzfPZ|Z8qXxv^8FvmNP-J&BOnzSUFeWJaZDplFFhlC~L z)g&!Tpl_A|n)Ic*H#;Zka6Xc9kHY+8E79{q?z@SK{cfS>NUmlX)4xxaE=@65`=Udb zbPCpO?-yj2kC^i6m*I7%6HWq|xP$%eU-!d%o4a4inw>L*%s%VXDC5^Uw|ENv z7P*|^3YEIfx)sbG{$FnO3V}oTlza{67^7~cs=*-Z7TR`+xKXrcdO{AmoB+UkjOF=A zRcAE8^LX4gvq~N#yImjBohoTHS?yG+tGv%z4LDG$%hH3CR?AH{KDznsu5N4qLJ80^ zGB+ig!o7DV=3Cw_x$jY77i+Tg6#nxCf$Eb$<73Hs?I4wEYunUOJ@orY7qmHY<4fD$ z9@*`&jM1VvDB%@gkz#@(OCY%w6)e;YSK2RA8q@Nm{r3Cwn;kNq$#Ib(P!0Dk@I0$`yZ(Hv_E0Y%LhfOQg1o# z_@Rc`C+BN=t+Ca3;_Nd~XwX3m?AitTQ(D!b$Zd zKHK$sy7*}ffpaF{&>Z+t%niTmnidet>1fo39r9XRG_;13=B9DEqOgE~^8Neo6I54M zSDV6_uT?_S^NNb-%+1aD2R%JJzB}M{CVL^FF*i?#ncr*B2`JFZ)LkW!@pa!;pNL-A zH8`<1Es`VQ_xOZ_T9y(KrSD_`ob-HTdoaD%3y%iJAP$Lpb>yD-;T`~xU<0s0&h#Sif$<74=N zD(N9PLx`8tNhb=&V#6fx!Z{QF#hBj7$*HigP|@5x{SWE57ZsI?^gX|*9@KXu>)SUe zYgC#-K<&Z}HZx*D0c_}7R}~^wqEk`c6>_8&u+5ps8CXwlOyHlTwxhfp=%N^*eTt1! zs33)-340WG<~a)67#XDKln2uBCE7(FZEmKy7h)&3H6h#;=rHz;Z6%d*=MAZw-g`PX z(Zh>f29|3XpKc($-}>$*i=OdrF%BItzz{zBjg}HIguKcNX1*9!>RAj+IV#WjDoXaGgpxp*_;ID}OzJq!$ zweJ-MH6Do7^X49sko200noA?AYKChLHk<-vj(U+AN}FEU8I|wGDa8hKtey*WTt}}% zcvfU}f)C<;&K)_am)BDm&-f*r-1QKj*GjonO)2Gh_FF(SnwX;=JwILafnr*4rLIL^ zl{6Dg-`=02e&62x(*>3q+_D#HL7tWv*~-_k(FVRd;5;Xgb51i#2LANRB1%TJ-WgDWd`Vt#VFu=!v=0nl1W%NTmB+ zk+BEj!vk?rgwqlUZq}+(`1)+2!c;1u(5M3X723#*3PA@b1`>^4;CRVT(#b&WLzW^I zl&h$CQZd`~8WQMC_84D2vYFGv(j|fk+njV!wO_r|O?rhuDXpXC9#Q?QM%R!u?c%=D zYXi8JOT|TZss7`%?`QNGsrMQ`immd;-F-#H&7TR4b_H~$NCcRgqTOVA@fa<>@u=s> zU+#wZQVJ&Vg)d0L)uCZ?jLV87(pK??PD<#=h@lp*6#VKh9n@cBp^hLgnLm9}Ewwl6 z_WVH}PL$An*j8@4MoD{=N!Bq$%kmfgpNUT%{JREQs$AwD`&}Y!ec5-(Aj899{WBI* z%a}8v3h@)STe}GTv826Edr~_bVla!o!NCOq2wOXHlq@`DM?d7;LZ6GuGex|@mp(o8 zBT+P-~lW6VDYeyQR7cAe@z~UZk+Ij)f@E&s{zoMEPU&8DobQr z*tokQhIVZA*N@2YP7?>c7kKGH;}nC^2np!&F*z-97*x8t~aodJ^D^EQ&F+W*Bh1IJ5MK35+hDrqvdd)x^WaH zOO95DVc4K84ErdV&#Z-{kSCr7w}~RJ$2*n*P->3il&!23C+xr7AEofwq73Jw7Y`?9jba?6@iull zuk1sj-(OSr#qoJ!XB`iy9}f=?vq?NpIygRF&Xkmgfn0`SFkk1_dKo$@DvDw3SnvgI z)oUG7VMXn{x$*-zE}v!Ir>;ZPD(A>O4~UYlp{EaNvxoaoj!sc?}$;X1mne{5$`?o&tD?t{#8$GLe!*@IYrrD5%SY^$5*~ zD_+Xo7hvHqJGiAhWUShW14&p%_!(N%1%(+Q3&^6)P!cZHkoF?1q@#`IjY(I$@wHoL zzFqm#9i&TeSeE5=cX$7$a10IsE78YijhFZf^{e}5u4dd##CWQQq8!LXPH|_`iJ6(% zATfI&ocYmF9eQtu^fi-kvoGWZVV|`kGdzea{7l-+`0Q}JTjI%Fq)Wv$K<37X~fW_?X{{`O)m)!rMstvsV`^o@(WkPNWsL&t|6QC{+Z~f&6qh?Z^hCaGh@=LbL;5xCxpqify{m(4K~mFLGUtwoQ|~!cZrCSMF+JTt{w>57=M%PZT5Y^-L^=dL46R z1SMd&26u#10JQkMu#iSoRdr=`wg2@swa6a;y&2?huB|B>85wm}0tCl)`zht6o5nC% zTEL-FbYi~frOR9_&`rN5tD~t&3z?0Q-2%Ea+** zRQBDlTTgyc4h;=i9`7zCiP=W|p%42t;eP&xw(BN(vwG5CWV+M$)vqU~Bnp9#V#^@B z7zO5vW*kAGj7dFfa4Sgc)?yh02x1wc4dZv#yght8g9Eb&YD4KaIh~1()56I}dSo`H z$--|_{IS=xN5SFTys zAs76e3yX^4M#~V}eCJG!jCkP(V^;hN`?CI`$wLeZHW-Rd87cGa$7LjKYLyZ6PsLJH zAR0A-LXM(Zso$G}6Tv3#@DRQss4`_+BEnN{K2?StIe@c@ZsQA@BFCFax;l| zvb_MtIFt481vnGG=E^s(PM;iZtAjTf6e%E0)=Sr{`XU;M^Oh5?sjmJA_#ntF!0Y+1 zn_)U@)4tmFIv@$Sv89diuVZKwdh-|}m7&-Br#p3UYj&Y6x_3p|@1Xcnx#=q`1|PtY4S=PnYAo&MIHX)PFcL) zA+WT=CY{YNt!h^m$7{Q8_U5({<-0`*j$SOh}QXMMYY&LF;0)Yt#I=>~VL< z<1d#a`E{OeD&B%y8X(JvKqRKUn9Jk}gw* z3`ny~JFFVD=#sjV+I9|SZQ@pkwJj#8n~>1Q-3U>J?muoJNE5>;XF~EC#<=a(W0G0* z^V@{y644y{UH6tRJR->v&59_B8Y9`6%2IUFsK6Bbe0~3d(i1sExbbNI1I-c0)$P<} z!G3(yK`pj37n@cIEPcHP4CD010ysg_ECU#ZZvf?U*5NV)v|z=naCi3wuo&UZKE|OX z+-8p{iSY~3w&%*(*~b&v&_X17dVCEv{P|HaX~s!NlcgtJc69qIw6II(-wFAdQQK26 zN$SyKgR}6)9&f$=-2_yr^1)D=Xh^f=omXVIy7Ww ze@nc|=1M+C0S>!vl}IO2-?yW*^j`gH6C>*AuKM0u;@rOQ=eNSOzyTMN9s(0Q^`jWt zQ(u2xo9m;?&j=7afYsgx{@APx#1F^*BHz)dNBe_q3vS22xTRkHi7ZK+pqu!n;HmFI zD~lq^wZ7x9bu>0Kq%ujkZ)CJA6!xbxEbKgRvtr?O0e+^gdJRXJ}a+n%&0us64X@o!AlFoNhc z_b`&B@dyg~@3It%QI6PN`fyqc zjKszb@&j_obuqVj6?&+`6;StMlk>h+`u)#k@b)o>&1KZzS*1~Hxc6Te;BO5Q0=mUV zErGW*Y12!S>VF^iPgs;MMlF{Ur{lV?P#~m?Ix7)#e^AZYnd{}(dQjKglWEzMp`2s% zJ)z!|OdaJvwf59w6Vm+YpRT9I{a06cgAI^z|L;1>{{bKWXsOc3E(Sh!Yq?l@HAQ*% zU+BQggJ#qJ_g8l*{wuX2or<^G13%{FUC)y){r;W(y+(5!$uJuu3l}>TdQx4v8^+K= zB%IuKU+GgM03XNryDWi=X2_$rl0f~CY7v;b5^IxKBFe#ge2IFaYZq-G7# zWcn%6crWr&s)Q5E*39>pys;fTKj+F_B_XFZ-6O&_D$^|m%#)rck~$5*8P1rWbGI1P zC;*%QNayf%mTqGp3xsl&Iv zZeG}l+-~sipluLbHn2a)^XIyOTz7Z(gkKFW#{a;N+54M0N&DG3 zMd!Lr2>?wrPM%xa0{D?6>s5-oPc@at#0!$ePY(*_hdw>9FW~3rCxcA6wQ)iMjSvCD zpGu(}&qS>`jMLlbK)`wf?#qvqbzfn+p`8?%l5+VbqVdYhKfn9aaN&MGLupHa{huB< z5{{IJI%XZTO&a@zy7v7c>8nlmz2rY(aQu@I0@r_4sgP`Ih>S0qPrP0d*22RcfmJvaWkg(TZPTD7dl#_7|9|{-Z~)G~;f}v7(R8{P~?60zjtV;-eF5O-;=SR>&z3 zrh9i?H(e%vXNejIB{`Ngyw1qT_%R^`Trx@dGYY+KCeOtYwtA}w_5LJy7?&yTm~hG8 z)Lb(DR2B&;R?1zz>TG(R4VguZMpi%%X0)%d8~IeTlvrq*%42x-E_TjADhNp;WbBiD z`utg0Pmj^m)D&_wx|OgMW?^6u>@61s>YChFqfg-|E9qsge1W-je%+eB&&g&@0Ds6D zW7sd_TK7-YB_SKnTX5Tq>lnY_Vw8BhW>|W_FMbD3*2jePvTxaGL;9t;$EmH7+4lP9 zPm2kBj zpSm^>H~Y5Hm`CR$eTV0)c^biBC2e&(v+KBU;1Oew`{9f8rRTwh38)wdq;kJH#Gnv;*ZDpH6=L8Du6ub z5vZS8ko#lfGx3YO#^68;;9mB+tV&El2`lOc_om(ss?Rd8i>mk`9y~a|wz2VHbB4-m z(y8VN08!bmUsIXLL!_|i{|mTtTO1Vwc~YAZSlxecU6AD(0^Lwwhzbah*{Lf*)geJx z$^-BsEkagznrwr7zF@vHu@0iW%1Qp?RUn@4?-p#ycsZ9y+D$~yilC0QIzc%ylXMJ? z^ml%iIk>XTS+nOT>*m{I{}@HUdLJ((K1g^UVRvVutYc~Zt%#>N$!ltdB`|tnF0Ab- ziAVq&u{&%;(nBx51R@)a88iuc%eJTP8%XeW+OPe1*-Ky-sh=$+iZmWQ9rSp4g60t~ z`po>r%ji=<-}XEBg3~wMNd~NxCORE}YFV0=1vjVVbcFz!KRxMhR|gAzN$Ccxq8}`C ziaw*+xDq;WEGsK}-^}c7Pmk{AS7HNlrL}DSj>o4q9Zsr8B;4kbDq($n@EyjUFo^{q z^Q8KTmsia}!((`!%Tw{Aq>uH=sknTP3c~P47;fVoV3W98P$p%2#@l|=-zuPqN~M_} zb&7h56g0HWtJ&9R$EDo0ZW=~~L9f0A_r5M|#I1eUUAf<89)KNAl74Bk0ycsBlHlP- zn#SVPcDP{<29C~K4qQRiqmSRQbi0gKwCsN!m-Fn02JY+aasVKmaML8%ZK1X4Kg;rX zN&aGwN2vgLt<|SwD2M}b10_>{8>d4f{n*#h8@r;D*zG%zJ2=&zqPA~B;0^>rW815=w9d3%1tJ5pBHlPtO1E_@tS&+CBU%!D4D#dL6ji? zjxT`Up8*vzCm&tB?r2K{oD=7??#20Rx8UXH%;~377OglJ^}5Z|BX|*2I*P`4#B}_- zHdCsn#k;Y#g5wO3A0K9V8Tm1*VldBjM9UqDK^pDxGohaRzswt&^a|aKFp+hETfGG~ zmJfl>LC>%Zkk~~mN%~HG*Z12VA-{#UVb6@700cXHf&$ugW@} zu?(boDcj&;%5e+w9Mi}-S>vLYJo7&&d>3#c5C~ugqVQ`ZtwPSvk-yv*(vIFe_MUqc z#kdhIw@ZUO`URCqF+$V#W6LlW7DMPph4iE85i}>7c?4~6`g9eoFz(rY>p}bh*OcD{ zC@JlvHPVMpZgx?Sz@z5ppH{j!v~5&We8|qIs8H{pA;uh-q#HHFE&Wawvu|*K zN35;=>SLT9AvH&wuj*xl%So)u;p{B}u#fN?w(ytcq*jkNpc|)8hlWS8eT?z}NZq?C zA}cCH)8MG9AkF$JUcWz}#VOyFRamGoxw^3Pt=?zPMmy(wzhT!(M0_}hcg1>bb2@oYg}c<4}hE@#(La? zVD#{z)Bz}$`WTQvY;0*boOvs4^t;~zVxX|zHto0FaEb?VHc@l0Sf7rSKLMmCn{fSK z<=<)2=K-mbNy0BzP3mCp613pLR~W27fkNz1UsIj&prBJ##4fv{H=;Y)KTJ)&S{7JLMW%*M zRhO0BS-DngTeNmq%*Y&e44vnjeF@aGDE$mGMsJyWmzt);YdM7ifsoei>ISbKU(Ff#fp+2ClIy$07SK1n|Q!l;c-qQf0xx<1$92VtaiHPA*k|^cn z*RJqXmj5?Fx&>nXKtFNiqKlV;o&GM3;PhcPIcE_KR%PUP#AvSEKI!%IxpEMGoxt(z$a1 zN}B*o$7tWE8YK<(1&Xvi{r0ryO37Z%Bu;W&^TVDb=Dw?NlOJ?uGPo5A`omgjr*d7%Y-@Hu z>54d0xL5q|8C*HB<)r(MN2g*Ts%q~U;NF0p-xWdQD~d_yt3ga~V8GS^=zsBW+6!^I zotV1aduG=CCs?C38>7uux7f=2hR}n&#u`(S!)!LnIEi%AROhy2zx&vIFL zF5S~+ybk;QXqFnB>rHXU&QBLlA$Tw zTG3BI3y?C+4$FTt#s6bZPfQw6l4j5@LOou#!1e!6Eq}3tcdjERUD9xjKVQv43;*H9 zW4)RaDNo93l}@P1{~2JB(@N{?q{}M+*Wd+T@05}=3Gx?~p$O}ZP7vHGQaOglyD(ip=xkhvP15L-Kiwf?7l1M^*sRZ|7k;F#s&NlL^NnA$R1HV7Ko;V)cY)@ zc5YjAD}2Z&{-I7mL|=$|wwY7_Cwf4v%M$a_w}Dg#TkQX@QfLjQmUCbF3d6Nz?Vmjg zx7&-9+4~FXhYyjDUk&J?^od`tE1K0LYURQ+@t`Nl?rtcO3=GozyIOMRMN9lA1Wl*n z>HG4s`iMg!#u7iy=hr}wA|0Y!aMOVJlXJ6U4Fq!P6JaXb%(QoU{`2SA6#S)n(xgL% zi;TJ$<^BfdS(Pk7RNi3E3O)aO>PUCZy{0dc2eMjtD`}zD+a_Ou_M`oR4Hx97bXaswW5K{X&yR zPJ-gAL!|bC9Pbh=?DU4I-No*pBeL15kr3~>-(o)rBGaRhoPMT|AJ~J@Z9lWR^IU>D zfuL2a4`i?hPt)n9%XZ_-X0Bt9y+RYq1*Y=>I2@kvK!}hiD=nSMYTB1LOMpdroVZk1S z;z>5#k@rbI(SFouE?fO-YYrnkm^H&+?HhW>7Oo2Zn)5t(H;)6g);Q`nD`{i0pQ&{s z>S0m*GW!IZw!YOQTb8Z{dI2)h&V*i$-vJ}0q^35UUn+$5SqJr_Nbo=kNFZ3yJv!xy ziHXOyibDZeB^-*Mc-F&%(c?mE!En_x61cqESc zMpffEl_Kg+PS~ej9nFD5p3V1%L7N;)sL77{@G-Bz#O--8F#J3C3BOIi4xK54X96{y z8KMp*%PB>bB!k>fPG~KQL4{Zx7tY0n2I5O?q+h^UJo}nVqmA>JNxs4DmoR z^1BUX0!Ys+4!8Tk%+2WPQyY^7yML=blq$M)JT6`PYn9n0J>gStN& zcug-Z9QBE2mGCjYn8aH;Vn%Q4<9&Nr8^RXKyym{Fkr;Q++9@G`-uA;rCW3Oc<^dys zLqJph3p@dha(sQTp5-%~@u$X3uk#8MtH(sGgP%K|3^}o3obVMy=_NN1v$_W9Fyee@fU|2lv zOZgV^G3k?lt!N?hS zr{aYaMDMHRUu^RBd_-)XER$)10^9yu7{LbH=R(?EdM7!fsH*x3^Z>EakE30sB7w|y zVSjZH_?>Sh^x-*^t|htYZ{EHogVZ25td2Ae$LThXil6~^mR>Ruqahc{5F%5jlTR}y zW#OR#d#QyZ0iIf*6~rKwY(KqxpY0@2T{ci3Dln@u zT$c~k%Ww@BY7xC*Q2)j0pS!{Hr*wE)Z7r>=v7l}w8E`DL`dA`a`{x2M!;dp`jFqJ=S+ zYW8w11`t?kK%{>u^s&eAqv{G~-3WkcPaQh&rcDv&d7lq|Z{W>N@gNt=0A;OjcYY}o z=kbObr?HnYN$%aF=`o|O2gpFBRN07*UNwl7>JWc*CM4k5#LDE@A= zlQ>PM9~Bv5y8`VNFc_ZSWxat%tCE7z6E|}iRH9MXZUY) z;OG@)BpT2iiRS~?5DmWKr^PMsBlZ{}lM2ey`Vs}B+$~E`E{1c{uQAew957zEiFvI> z!}aQouYo!E031)a6(wBb^(V5@*3bc9=!fYI|0|X zJpB(7B#st6M)`lG#?M9RS@8Z20EHv}-P-jJbKRY;ZM^YMxQ-qTHC{*V-|nC$DF*4> z0$p?O!Q(90q;bMBep}&H3Htw6F8F_Fy*_Qxt_B@3_9WJJfq&53SnJ#KOoZe0Xc7At z4fN_{8hwISD}iX@ET@RB;{I|O>UqS8wbWU~V2hnBfXxh6yxqt@!b$i6HBD!G`}gRR z6Sj~2|66Nc0uJT-?mzZDvLsoCB9%fEr5IE~Wu#EVv?vixS(0sDQI-@!BxwlIhRVJT zE!H%aBqqkbZ)2M=+xve;-|zRF-}#?&o%27}zpKkT^UgER`@GM4KllB4?)(1Sle^P1 zQ9+%Te}9UbhfwR!G=uBQlbv2VDTntd)Pd=h@N!Vj;ov9W$^%INhc~asumW6yj0DoCQz_Po_i9IH+7dd=+y0@4=pLJX2 zGud%uDZA)eSGjZe%+@Do{6#yF%Vvg(O&VYu*`8%_oAOnbYa5>R=^Os|RxSi^Vr>T5 zVp$+5&-6rX8>g~G&Xzwkj?kucZCZ7N8v~|Y%^aKa4<}s5AY^oO^oNiogFEEx$152i z)V;u?*&foC{OPSMQyoxpK$Sx=_nfi13%tq? zv8EmAKYn1q4Bi!z(gp;KAWAf5X%C`c5WO{lHYiJono_NHzS98`qa$SHB#!#kB3c7TuY-+&tpda- zPtUL8ZJAE8-(pa!CnbT){S$~$-vo)_DqPmU;Pp8-RKHn!4m?zl>bd{X6WRES4_Rmr z#bE5A=EMr^&Fkp`@#Kb2_e7k?d_y}CyQh~LKU;8Ob(}{4{Hyn>0;%OY5}hDgR=dD3 z$Gq(K%6fu`1Y#<>{pFJW?x|=2#JF`{O>A2HFyQ(>M@in{VAh{`PSGb)^~xN~wmmX0 z)ohsTd^3`uj=l(W-vqpuR?qg` z0kFyO>O9vrMOzR@yaR3l#4M#uLt{A`rPeTU#KFaHx*41|anFC26|g~UPRs_=NLIM;RSaX4Dq7kLaZ4tk1_{9}g?onQqH=>eH@Ae+l7yr*aFi36U!>4CK$vSV zO5JobH6kf#!+txZ4kLYieGS%0A6mD-+DvTFJQF#2f*XI=Qd%i!zV_LEu7i{>QW=1d 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 V5T-FAzMv7p;)vDZJk#@`{|7gHIxGMH diff --git a/polaris.dme b/polaris.dme index 00fea66294a..ccada6a7653 100644 --- a/polaris.dme +++ b/polaris.dme @@ -1393,19 +1393,26 @@ #include "code\modules\hydroponics\trays\tray_tools.dm" #include "code\modules\hydroponics\trays\tray_update_icons.dm" #include "code\modules\integrated_electronics\_defines.dm" -#include "code\modules\integrated_electronics\arithmetic.dm" -#include "code\modules\integrated_electronics\assemblies.dm" -#include "code\modules\integrated_electronics\converters.dm" -#include "code\modules\integrated_electronics\data_transfer.dm" -#include "code\modules\integrated_electronics\input_output.dm" -#include "code\modules\integrated_electronics\logic.dm" -#include "code\modules\integrated_electronics\manipulation.dm" -#include "code\modules\integrated_electronics\memory.dm" -#include "code\modules\integrated_electronics\reagents.dm" -#include "code\modules\integrated_electronics\time.dm" -#include "code\modules\integrated_electronics\tools.dm" -#include "code\modules\integrated_electronics\trig.dm" -#include "code\modules\integrated_electronics\~defines.dm" +#include "code\modules\integrated_electronics\core\assemblies.dm" +#include "code\modules\integrated_electronics\core\helpers.dm" +#include "code\modules\integrated_electronics\core\integrated_circuit.dm" +#include "code\modules\integrated_electronics\core\pins.dm" +#include "code\modules\integrated_electronics\core\tools.dm" +#include "code\modules\integrated_electronics\passive\passive.dm" +#include "code\modules\integrated_electronics\passive\power.dm" +#include "code\modules\integrated_electronics\subtypes\arithmetic.dm" +#include "code\modules\integrated_electronics\subtypes\converters.dm" +#include "code\modules\integrated_electronics\subtypes\data_transfer.dm" +#include "code\modules\integrated_electronics\subtypes\input_output.dm" +#include "code\modules\integrated_electronics\subtypes\logic.dm" +#include "code\modules\integrated_electronics\subtypes\manipulation.dm" +#include "code\modules\integrated_electronics\subtypes\memory.dm" +#include "code\modules\integrated_electronics\subtypes\power.dm" +#include "code\modules\integrated_electronics\subtypes\reagents.dm" +#include "code\modules\integrated_electronics\subtypes\smart.dm" +#include "code\modules\integrated_electronics\subtypes\time.dm" +#include "code\modules\integrated_electronics\subtypes\trig.dm" +#include "code\modules\integrated_electronics\~defines\~defines.dm" #include "code\modules\library\lib_items.dm" #include "code\modules\library\lib_machines.dm" #include "code\modules\library\lib_readme.dm"