From 496322f4f100b1aa263092ccedec665c99e34536 Mon Sep 17 00:00:00 2001 From: Mechoid Date: Thu, 20 Aug 2020 18:22:39 -0700 Subject: [PATCH] Reagent Hoses --- code/__defines/hoses.dm | 3 + code/datums/autolathe/tools.dm | 12 + code/datums/beam.dm | 20 +- code/datums/supplypacks/misc.dm | 9 + code/game/machinery/reagents/pump.dm | 270 ++++++++++++++++++ .../circuitboards/machinery/fluidpump.dm | 14 + code/modules/materials/material_recipes.dm | 1 + code/modules/mining/mineral_effect.dm | 3 + code/modules/mining/ore_datum.dm | 12 + code/modules/mob/_modifiers/medical.dm | 10 + .../Chemistry-Reagents-Modifiers.dm | 11 + .../Chemistry-Reagents-Other.dm | 8 + .../Chemistry-Reagents-Toxins.dm | 7 + code/modules/reagents/hoses/connector.dm | 138 +++++++++ code/modules/reagents/hoses/hose.dm | 113 ++++++++ code/modules/reagents/hoses/hose_connector.dm | 92 ++++++ .../reagents/reagent_containers/spray.dm | 95 +++++- code/modules/reagents/reagent_dispenser.dm | 17 +- html/changelogs/mechoid - reagenthoses.yml | 37 +++ icons/effects/beam.dmi | Bin 120269 -> 120296 bytes icons/obj/machines/reagent.dmi | Bin 1748 -> 8928 bytes vorestation.dme | 6 + 22 files changed, 871 insertions(+), 7 deletions(-) create mode 100644 code/__defines/hoses.dm create mode 100644 code/game/machinery/reagents/pump.dm create mode 100644 code/game/objects/items/weapons/circuitboards/machinery/fluidpump.dm create mode 100644 code/modules/reagents/hoses/connector.dm create mode 100644 code/modules/reagents/hoses/hose.dm create mode 100644 code/modules/reagents/hoses/hose_connector.dm create mode 100644 html/changelogs/mechoid - reagenthoses.yml diff --git a/code/__defines/hoses.dm b/code/__defines/hoses.dm new file mode 100644 index 00000000000..2a7bd4d8031 --- /dev/null +++ b/code/__defines/hoses.dm @@ -0,0 +1,3 @@ +#define HOSE_INPUT "Input"// Only pull liquid. +#define HOSE_OUTPUT "Output"// Only push liquid. +#define HOSE_NEUTRAL "Neutral"// Equalize liquids, not super efficient, can waste reagents due to rounding. \ No newline at end of file diff --git a/code/datums/autolathe/tools.dm b/code/datums/autolathe/tools.dm index d0aa2aa196b..9e9a87ea71f 100644 --- a/code/datums/autolathe/tools.dm +++ b/code/datums/autolathe/tools.dm @@ -42,3 +42,15 @@ /datum/category_item/autolathe/tools/welder_industrial name = "industrial welding tool" path =/obj/item/weapon/weldingtool/largetank + +/datum/category_item/autolathe/tools/spraybottle + name = "spray bottle" + path = /obj/item/weapon/reagent_containers/spray + resources = list(MAT_PLASTIC = 2000) + +/datum/category_item/autolathe/tools/spraynozzle + name = "spray nozzle" + path = /obj/item/weapon/reagent_containers/spray + resources = list(MAT_PLASTIC = 5000, DEFAULT_WALL_MATERIAL = 2000) + hidden = 1 + man_rating = 2 diff --git a/code/datums/beam.dm b/code/datums/beam.dm index a35abf8c370..fc4e696702f 100644 --- a/code/datums/beam.dm +++ b/code/datums/beam.dm @@ -6,6 +6,7 @@ var/icon/base_icon = null var/icon var/icon_state = "" //icon state of the main segments of the beam + var/beam_color = null // Color of the beam segments var/max_distance = 0 var/endtime = 0 var/sleep_time = 3 @@ -15,7 +16,7 @@ var/static_beam = 0 var/beam_type = /obj/effect/ebeam //must be subtype -/datum/beam/New(beam_origin,beam_target,beam_icon='icons/effects/beam.dmi',beam_icon_state="b_beam",time=50,maxdistance=10,btype = /obj/effect/ebeam,beam_sleep_time=3) +/datum/beam/New(beam_origin,beam_target,beam_icon='icons/effects/beam.dmi',beam_icon_state="b_beam",time=50,maxdistance=10,btype = /obj/effect/ebeam,beam_sleep_time=3,new_beam_color = null) endtime = world.time+time origin = beam_origin origin_oldloc = get_turf(origin) @@ -28,6 +29,8 @@ base_icon = new(beam_icon,beam_icon_state) icon = beam_icon icon_state = beam_icon_state + if(new_beam_color) + beam_color = new_beam_color beam_type = btype /datum/beam/proc/Start() @@ -68,9 +71,12 @@ var/matrix/rot_matrix = matrix() rot_matrix.Turn(Angle) + var/turf/T_target = get_turf(target) //Turfs are referenced instead of the objects directly so that beams will link between 2 objects inside other objects. + var/turf/T_origin = get_turf(origin) + //Translation vector for origin and target - var/DX = (32*target.x+target.pixel_x)-(32*origin.x+origin.pixel_x) - var/DY = (32*target.y+target.pixel_y)-(32*origin.y+origin.pixel_y) + var/DX = (32*T_target.x+target.pixel_x)-(32*T_origin.x+origin.pixel_x) + var/DY = (32*T_target.y+target.pixel_y)-(32*T_origin.y+origin.pixel_y) var/N = 0 var/length = round(sqrt((DX)**2+(DY)**2)) //hypotenuse of the triangle formed by target and origin's displacement @@ -78,6 +84,10 @@ if(QDELETED(src) || finished) break var/obj/effect/ebeam/X = new beam_type(origin_oldloc) + + if(beam_color) + X.color = beam_color + X.owner = src elements |= X @@ -184,8 +194,8 @@ -/atom/proc/Beam(atom/BeamTarget,icon_state="b_beam",icon='icons/effects/beam.dmi',time=50, maxdistance=10,beam_type=/obj/effect/ebeam,beam_sleep_time=3) - var/datum/beam/newbeam = new(src,BeamTarget,icon,icon_state,time,maxdistance,beam_type,beam_sleep_time) +/atom/proc/Beam(atom/BeamTarget,icon_state="b_beam",icon='icons/effects/beam.dmi',time=50, maxdistance=10,beam_type=/obj/effect/ebeam,beam_sleep_time=3,beam_color = null) + var/datum/beam/newbeam = new(src,BeamTarget,icon,icon_state,time,maxdistance,beam_type,beam_sleep_time,beam_color) spawn(0) newbeam.Start() return newbeam diff --git a/code/datums/supplypacks/misc.dm b/code/datums/supplypacks/misc.dm index db46de1e047..0aa29b7b9c9 100644 --- a/code/datums/supplypacks/misc.dm +++ b/code/datums/supplypacks/misc.dm @@ -189,3 +189,12 @@ cost = 40 containertype = /obj/structure/closet/crate/zenghu containername = "emergency rations" + +/datum/supply_pack/misc/reagentpump + name = "Machine - Pump" + contains = list( + /obj/machinery/pump = 1 + ) + cost = 60 + containertype = /obj/structure/closet/crate/large/xion + containername = "pump crate" diff --git a/code/game/machinery/reagents/pump.dm b/code/game/machinery/reagents/pump.dm new file mode 100644 index 00000000000..04916d4d9bf --- /dev/null +++ b/code/game/machinery/reagents/pump.dm @@ -0,0 +1,270 @@ + +/obj/machinery/pump + name = "fluid pump" + desc = "A fluid pumping machine." + + description_info = "A machine that can pump fluid from certain turfs.
\ + Water can be pumped from any body of water. Certain locations or environmental\ + conditions can cause different byproducts to be produced.
\ + Magma or Lava can be pumped to produce mineralized fluid." + + anchored = 0 + density = 1 + + icon = 'icons/obj/machines/reagent.dmi' + icon_state = "pump" + + circuit = /obj/item/weapon/circuitboard/fluidpump + + var/on = 0 + var/obj/item/weapon/cell/cell = null + var/use = 200 + var/efficiency = 1 + var/reagents_per_cycle = 40 + var/unlocked = 0 + var/open = 0 + + var/obj/item/hose_connector/output/Output + +// Overlay cache vars. + var/icon/liquid + var/icon/tank + var/icon/powerlow + var/icon/glass + var/icon/open_overlay + var/icon/cell_overlay + +/obj/machinery/pump/Initialize() + create_reagents(200) + . = ..() + default_apply_parts() + + if(ispath(cell)) + cell = new cell(src) + + Output = new(src) + + RefreshParts() + update_icon() + +/obj/machinery/pump/update_icon() + ..() + if(!tank) + tank = new/icon(icon, "[icon_state]-volume") + + if(!powerlow) + powerlow = new/icon(icon, "[icon_state]-lowpower") + + if(!liquid) + var/icon/cutter = new/icon(icon, "[icon_state]-volume") + + cutter.Blend(rgb(0, 0, 0,), ICON_MULTIPLY) + + liquid = new/icon(icon, "[icon_state]-cutting") + + liquid.Blend(cutter,ICON_AND) + + if(!glass) + glass = new/icon(icon, "[icon_state]-glass") + + glass.Blend(rgb(1,1,1,0.5), ICON_MULTIPLY) + + if(!open_overlay) + open_overlay = new/icon(icon, "[icon_state]-open") + + if(!cell_overlay) + cell_overlay = new/icon(icon, "[icon_state]-cell") + + cut_overlays() + add_overlay(tank) + + if(cell && cell.charge < (use * CELLRATE / efficiency)) + add_overlay(powerlow) + + if(reagents.total_volume >= 1) + var/list/hextorgb = hex2rgb(reagents.get_color()) + liquid.GrayScale() + + liquid.Blend(rgb(hextorgb[1],hextorgb[2],hextorgb[3]),ICON_MULTIPLY) + + add_overlay(liquid) + + add_overlay(glass) + + if(open) + add_overlay(open_overlay) + + if(cell) + add_overlay(cell_overlay) + + if(on) + icon_state = "[initial(icon_state)]-running" + + else + icon_state = "[initial(icon_state)]" + +/obj/machinery/pump/process() + if(Output.get_pairing()) + reagents.trans_to_holder(Output.reagents, Output.reagents.maximum_volume) + if(prob(5)) + visible_message("\The [src] gurgles as it exports fluid.") + + if(!on) + return + + if(!cell || (cell.charge < (use * CELLRATE / efficiency))) + turn_off(TRUE) + return + + handle_pumping() + update_icon() + +/obj/machinery/pump/RefreshParts() + for(var/obj/item/weapon/stock_parts/manipulator/SM in component_parts) + efficiency = SM.rating + + var/total_bin_rating = 0 + for(var/obj/item/weapon/stock_parts/matter_bin/SB in component_parts) + total_bin_rating += SB.rating + + reagents.maximum_volume = round(initial(reagents.maximum_volume) + 100 * total_bin_rating) + + return + +/obj/machinery/pump/power_change() + if(!cell || cell.charge < (use * CELLRATE) || !anchored) + return turn_off(TRUE) + + return FALSE + + +// Returns 0 on failure and 1 on success +/obj/machinery/pump/proc/turn_on(var/loud = 0) + if(!cell) + return 0 + if(cell.charge < (use * CELLRATE)) + return 0 + + on = 1 + update_icon() + if(loud) + visible_message("\The [src] turns on.") + return 1 + +/obj/machinery/pump/proc/turn_off(var/loud = 0) + on = 0 + set_light(0, 0) + update_icon() + if(loud) + visible_message("\The [src] shuts down.") + + if(!on) + return TRUE + + return FALSE + +/obj/machinery/pump/attack_ai(mob/user as mob) + if(istype(user, /mob/living/silicon/robot) && Adjacent(user)) + return attack_hand(user) + + if(on) + turn_off(TRUE) + else + if(!turn_on(1)) + to_chat(user, "You try to turn on \the [src] but it does not work.") + +/obj/machinery/pump/attack_hand(mob/user as mob) + if(open && cell) + if(ishuman(user)) + if(!user.get_active_hand()) + user.put_in_hands(cell) + cell.loc = user.loc + else + cell.loc = src.loc + + cell.add_fingerprint(user) + cell.update_icon() + + cell = null + on = 0 + set_light(0) + to_chat(user, "You remove the power cell.") + update_icon() + return + + if(on) + turn_off(TRUE) + else if(anchored) + if(!turn_on(1)) + to_chat(user, "You try to turn on \the [src] but it does not work.") + + update_icon() + +/obj/machinery/pump/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(W.is_screwdriver()) + if(!open) + if(unlocked) + unlocked = 0 + to_chat(user, "You screw the battery panel in place.") + else + unlocked = 1 + to_chat(user, "You unscrew the battery panel.") + + else if(W.is_crowbar()) + if(unlocked) + if(open) + open = 0 + overlays = null + to_chat(user, "You crowbar the battery panel in place.") + else + if(unlocked) + open = 1 + to_chat(user, "You remove the battery panel.") + + else if(W.is_wrench()) + if(on) + to_chat(user, "\The [src] is active. Turn it off before trying to move it!") + return + default_unfasten_wrench(user, W, 2 SECONDS) + + else if(istype(W, /obj/item/weapon/cell)) + if(open) + if(cell) + to_chat(user, "There is a power cell already installed.") + else + user.drop_item() + W.loc = src + cell = W + to_chat(user, "You insert the power cell.") + else + ..() + RefreshParts() + update_icon() + +/obj/machinery/pump/proc/handle_pumping() + var/turf/T = get_turf(src) + + if(istype(T, /turf/simulated/floor/water)) + cell.use(use * CELLRATE / efficiency) + reagents.add_reagent("water", reagents_per_cycle) + + if(T.temperature <= T0C) + reagents.add_reagent("ice", round(reagents_per_cycle / 2, 0.1)) + + if((istype(T,/turf/simulated/floor/water/pool) || istype(T,/turf/simulated/floor/water/deep/pool))) + reagents.add_reagent("chlorine", round(reagents_per_cycle / 10 * efficiency, 0.1)) + + else if(istype(T,/turf/simulated/floor/water/contaminated)) + reagents.add_reagent("vatstabilizer", round(reagents_per_cycle / 2)) + + if(T.loc.name == "Sea") // Saltwater. + reagents.add_reagent("sodiumchloride", round(reagents_per_cycle / 10 * efficiency, 0.1)) + + for(var/turf/simulated/mineral/MT in range(5)) + if(MT.mineral) + var/obj/effect/mineral/OR = MT.mineral + reagents.add_reagent(OR.ore_reagent, round(reagents_per_cycle / 20 * efficiency, 0.1)) + + else if(istype(T, /turf/simulated/floor/lava)) + cell.use(use * CELLRATE / efficiency * 4) + reagents.add_reagent("mineralizedfluid", round(reagents_per_cycle * efficiency / 2, 0.1)) diff --git a/code/game/objects/items/weapons/circuitboards/machinery/fluidpump.dm b/code/game/objects/items/weapons/circuitboards/machinery/fluidpump.dm new file mode 100644 index 00000000000..3646d7311a0 --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/machinery/fluidpump.dm @@ -0,0 +1,14 @@ + +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +/obj/item/weapon/circuitboard/fluidpump + name = T_BOARD("fluid pump") + build_path = /obj/machinery/pump + board_type = new /datum/frame/frame_types/machine + origin_tech = list(TECH_DATA = 1) + req_components = list( + /obj/item/weapon/stock_parts/matter_bin = 2, + /obj/item/weapon/stock_parts/motor = 2, + /obj/item/weapon/stock_parts/manipulator = 1) diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm index 2efef5783ff..b852e10383a 100644 --- a/code/modules/materials/material_recipes.dm +++ b/code/modules/materials/material_recipes.dm @@ -139,6 +139,7 @@ recipes += new/datum/stack_recipe("lampshade", /obj/item/weapon/lampshade, 1, time = 1, pass_stack_color = TRUE) recipes += new/datum/stack_recipe("plastic net", /obj/item/weapon/material/fishing_net, 25, time = 1 MINUTE, pass_stack_color = TRUE) recipes += new/datum/stack_recipe("plastic fishtank", /obj/item/glass_jar/fish/plastic, 2, time = 30 SECONDS) + recipes += new/datum/stack_recipe("reagent tubing", /obj/item/stack/hose, 1, 4, 20, pass_stack_color = TRUE) /material/wood/generate_recipes() ..() diff --git a/code/modules/mining/mineral_effect.dm b/code/modules/mining/mineral_effect.dm index b5b3d1a1924..9406231c566 100644 --- a/code/modules/mining/mineral_effect.dm +++ b/code/modules/mining/mineral_effect.dm @@ -7,11 +7,14 @@ anchored = 1 var/ore_key var/image/scanner_image + var/ore_reagent // Reagent from pumping water near this ore. /obj/effect/mineral/New(var/newloc, var/ore/M) ..(newloc) name = "[M.display_name] deposit" ore_key = M.name + if(M.reagent) + ore_reagent = M.reagent icon_state = "rock_[ore_key]" var/turf/T = get_turf(src) layer = T.layer+0.1 diff --git a/code/modules/mining/ore_datum.dm b/code/modules/mining/ore_datum.dm index f888ae3bb63..0bca24db1f9 100644 --- a/code/modules/mining/ore_datum.dm +++ b/code/modules/mining/ore_datum.dm @@ -17,6 +17,7 @@ var/global/list/ore_data = list() "million" = 999 ) var/xarch_source_mineral = "iron" + var/reagent = "silicate" /ore/New() . = ..() @@ -36,6 +37,7 @@ var/global/list/ore_data = list() "million" = 704 ) xarch_source_mineral = "potassium" + reagent = "uranium" /ore/hematite name = "hematite" @@ -46,6 +48,7 @@ var/global/list/ore_data = list() spread_chance = 25 ore = /obj/item/weapon/ore/iron scan_icon = "mineral_common" + reagent = "iron" /ore/coal name = "carbon" @@ -57,6 +60,7 @@ var/global/list/ore_data = list() spread_chance = 25 ore = /obj/item/weapon/ore/coal scan_icon = "mineral_common" + reagent = "carbon" /ore/glass name = "sand" @@ -81,6 +85,7 @@ var/global/list/ore_data = list() "billion_lower" = 10 ) xarch_source_mineral = "phoron" + reagent = "phoron" /ore/silver name = "silver" @@ -90,6 +95,7 @@ var/global/list/ore_data = list() spread_chance = 10 ore = /obj/item/weapon/ore/silver scan_icon = "mineral_uncommon" + reagent = "silver" /ore/gold smelts_to = "gold" @@ -105,6 +111,7 @@ var/global/list/ore_data = list() "billion" = 4, "billion_lower" = 3 ) + reagent = "gold" /ore/diamond name = "diamond" @@ -116,6 +123,7 @@ var/global/list/ore_data = list() ore = /obj/item/weapon/ore/diamond scan_icon = "mineral_rare" xarch_source_mineral = "nitrogen" + reagent = "carbon" /ore/platinum name = "platinum" @@ -127,6 +135,7 @@ var/global/list/ore_data = list() spread_chance = 10 ore = /obj/item/weapon/ore/osmium scan_icon = "mineral_rare" + reagent = "platinum" /ore/hydrogen name = "mhydrogen" @@ -134,6 +143,7 @@ var/global/list/ore_data = list() smelts_to = "tritium" compresses_to = "mhydrogen" scan_icon = "mineral_rare" + reagent = "hydrogen" /ore/verdantium name = MAT_VERDANTIUM @@ -156,6 +166,7 @@ var/global/list/ore_data = list() spread_chance = 10 ore = /obj/item/weapon/ore/marble scan_icon = "mineral_common" + reagent = "calciumcarbonate" /ore/lead name = MAT_LEAD @@ -165,3 +176,4 @@ var/global/list/ore_data = list() spread_chance = 20 ore = /obj/item/weapon/ore/lead scan_icon = "mineral_rare" + reagent = "lead" diff --git a/code/modules/mob/_modifiers/medical.dm b/code/modules/mob/_modifiers/medical.dm index 7e150ceb935..3d170719039 100644 --- a/code/modules/mob/_modifiers/medical.dm +++ b/code/modules/mob/_modifiers/medical.dm @@ -50,3 +50,13 @@ evasion = -5 attack_speed_percent = 1.1 disable_duration_percent = 1.05 + +/datum/modifier/clone_stabilizer + name = "clone stabilized" + desc = "Your body's regeneration is highly restricted." + + on_created_text = "You feel nauseous." + on_expired_text = "You feel healthier." + stacks = MODIFIER_STACK_EXTEND + + incoming_healing_percent = 0.1 diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Modifiers.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Modifiers.dm index cd2e6767b4f..bed5da5f477 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Modifiers.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Modifiers.dm @@ -57,3 +57,14 @@ var/turf/simulated/S = T S.freeze_floor() return + +/datum/reagent/modapplying/vatstabilizer + name = "clone growth inhibitor" + id = "vatstabilizer" + description = "A compound produced by NanoTrasen using a secret blend of phoron and toxins to stop the rampant growth of a clone beyond intended states." + taste_description = "sour glue" + color = "#060501" + metabolism = REM * 0.2 + + modifier_to_add = /datum/modifier/clone_stabilizer + modifier_duration = 30 SECONDS diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm index ba7dc93d639..18a281783a0 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm @@ -524,6 +524,14 @@ reagent_state = LIQUID color = "#DF9FBF" +/datum/reagent/mineralfluid + name = "Mineral-Rich Fluid" + id = "mineralizedfluid" + description = "A warm, mineral-rich fluid." + taste_description = "salt" + reagent_state = LIQUID + color = "#ff205255" + // The opposite to healing nanites, exists to make unidentified hypos implied to have nanites not be 100% safe. /datum/reagent/defective_nanites name = "Defective Nanites" diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm index e18c2e56d9f..74abe0b4bf9 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm @@ -120,6 +120,13 @@ spawn(rand(30, 60)) M.IgniteMob() +/datum/reagent/toxin/lead + name = "lead" + id = "lead" + description = "Elemental Lead." + color = "#273956" + strength = 4 + /datum/reagent/toxin/spidertoxin name = "Spidertoxin" id = "spidertoxin" diff --git a/code/modules/reagents/hoses/connector.dm b/code/modules/reagents/hoses/connector.dm new file mode 100644 index 00000000000..bac7fc7c6af --- /dev/null +++ b/code/modules/reagents/hoses/connector.dm @@ -0,0 +1,138 @@ + +/obj/attackby(var/obj/item/O, var/mob/user) + . = ..() + + if(locate(/obj/item/hose_connector) in src) + if(O.is_wirecutter()) + var/list/available_sockets = list() + + for(var/obj/item/hose_connector/HC in src) + if(HC.my_hose) + available_sockets |= HC + + if(LAZYLEN(available_sockets)) + if(available_sockets.len == 1) + var/obj/item/hose_connector/AC = available_sockets[1] + var/choice = alert("Are you sure you want to disconnect [AC]?", "Confirm", "Yes", "No") + + if(choice == "Yes" && Adjacent(user)) + visible_message("[user] disconnects \the hose from \the [src].") + AC.my_hose.disconnect() + return + + else + + var/choice = input("Select a target hose connector.", "Socket Disconnect", null) as null|anything in available_sockets + + if(choice) + var/obj/item/hose_connector/AC = choice + var/confirm = alert("Are you sure you want to disconnect [AC]?", "Confirm", "Yes", "No") + + if(confirm == "Yes" && Adjacent(user)) + visible_message("[user] disconnects \the hose from \the [src].") + AC.my_hose.disconnect() + + return + +/obj/item/hose_connector + name = "hose connector" + desc = "A socket for a hose. It.. doesn't do anything on its own." + + var/obj/carrier = null + + var/flow_direction = HOSE_NEUTRAL + + var/datum/hose/my_hose = null + +/obj/item/hose_connector/Destroy() + if(my_hose) + my_hose.disconnect() + my_hose = null + if(carrier) + carrier = null + ..() + +/obj/item/hose_connector/Initialize() + ..() + + create_reagents(100) + + if(!istype(loc, /turf)) + name = "[flow_direction] hose connector ([loc])" + +/obj/item/hose_connector/proc/valid_connection(var/obj/item/hose_connector/C) + if(istype(C)) + if(C.my_hose) + return FALSE + + if(C.flow_direction in list(HOSE_INPUT, HOSE_OUTPUT) - flow_direction) + return TRUE + + return FALSE + +/obj/item/hose_connector/proc/disconnect() + my_hose = null + +/obj/item/hose_connector/proc/connect(var/datum/hose/H = null) + if(istype(H)) + my_hose = H + +/obj/item/hose_connector/proc/setup_hoses(var/obj/item/hose_connector/target) + if(target) + var/datum/hose/H = new() + + H.set_hose(src, target) + +/obj/item/hose_connector/proc/get_pairing() + if(my_hose) + return my_hose.get_pairing(src) + + return + +/* + * Subtypes + */ + +/obj/item/hose_connector/input + name = "hose input" + flow_direction = HOSE_INPUT + +/obj/item/hose_connector/input/active + name = "active hose" + +/obj/item/hose_connector/input/active/Destroy() + STOP_PROCESSING(SSobj, src) + ..() + +/obj/item/hose_connector/input/active/Initialize() + ..() + START_PROCESSING(SSobj, src) + + if(!isturf(loc)) + carrier = loc + +/obj/item/hose_connector/input/active/process() + if(carrier) + reagents.trans_to_obj(carrier, reagents.maximum_volume) + +/obj/item/hose_connector/output + name = "hose output" + flow_direction = HOSE_OUTPUT + +/obj/item/hose_connector/output/active + name = "active hose" + +/obj/item/hose_connector/output/active/Destroy() + STOP_PROCESSING(SSobj, src) + ..() + +/obj/item/hose_connector/output/active/Initialize() + ..() + START_PROCESSING(SSobj, src) + + if(!isturf(loc)) + carrier = loc + +/obj/item/hose_connector/output/active/process() + if(carrier) + carrier.reagents.trans_to_holder(reagents, reagents.maximum_volume) diff --git a/code/modules/reagents/hoses/hose.dm b/code/modules/reagents/hoses/hose.dm new file mode 100644 index 00000000000..dfe0eade792 --- /dev/null +++ b/code/modules/reagents/hoses/hose.dm @@ -0,0 +1,113 @@ + +GLOBAL_LIST_EMPTY(hoses) + +/obj/effect/ebeam/hose + plane = OBJ_PLANE + layer = STAIRS_LAYER + +/datum/hose + var/name = "hose" + + var/obj/item/hose_connector/node1 = null + var/obj/item/hose_connector/node2 = null + + var/hose_color = "#ffffff" + + var/initial_distance = 7 + + var/datum/beam/hose = null + +/datum/hose/proc/get_pairing(var/obj/item/hose_connector/target) + if(target) + if(target == node1) + return node2 + else if(target == node2) + return node1 + + return + +/datum/hose/proc/disconnect() + if(node1) + node1.disconnect() + node1 = null + if(node2) + node2.disconnect() + node2 = null + +/datum/hose/proc/set_hose(var/obj/item/hose_connector/target1, var/obj/item/hose_connector/target2) + if(target1 && target2) + node1 = target1 + node2 = target2 + + node1.connect(src) + node2.connect(src) + + name = "[name] ([node1],[node2])" + + initial_distance = get_dist(get_turf(node1), get_turf(node2)) + + GLOB.hoses |= src + START_PROCESSING(SSobj, src) + +/datum/hose/process() + if(node1 && node2) + if(get_dist(get_turf(node1), get_turf(node2)) > 0) + hose = node1.loc.Beam(node2.loc, icon_state = "hose", beam_color = hose_color, maxdistance = world.view, beam_type = /obj/effect/ebeam/hose) + + if(!hose || get_dist(get_turf(node1), get_turf(node2)) > initial_distance) // The hose didn't form. Something's fucky. + disconnect() + return + + var/datum/reagents/reagent_node1 = node1.reagents + var/datum/reagents/reagent_node2 = node2.reagents + + switch(node1.flow_direction) // Node 1 is the default 'master', interactions are considered in all current possible states in regards to it, however. + if(HOSE_INPUT) + if(node2.flow_direction == HOSE_NEUTRAL) // We're input, they're neutral. Take half of our volume. + reagent_node2.trans_to_holder(reagent_node1, reagent_node1.maximum_volume / 2) + else if(node2.flow_direction == HOSE_OUTPUT) // We're input, they're output. Take all of our volume. + reagent_node2.trans_to_holder(reagent_node1, reagent_node1.maximum_volume) + + if(HOSE_OUTPUT) // We're output, give all of their maximum volume. + reagent_node1.trans_to_holder(reagent_node2, reagent_node2.maximum_volume) + + if(HOSE_NEUTRAL) + switch(node2.flow_direction) + if(HOSE_INPUT) // We're neutral, they're input. Give them half of their volume. + reagent_node1.trans_to_holder(reagent_node2, reagent_node2.maximum_volume / 2) + + if(HOSE_NEUTRAL) // We're neutral, they're neutral. Balance our values. + var/volume_difference_perc = (reagent_node1.total_volume / reagent_node1.maximum_volume) - (reagent_node2.total_volume / reagent_node2.maximum_volume) + var/volume_difference = 0 + + var/pulling = FALSE + if(volume_difference_perc > 0) // They are smaller, so they determine the transfer amount. Half of the difference will equalize. + volume_difference = reagent_node2.maximum_volume * volume_difference_perc / 2 + + else if(volume_difference_perc < 0) // We're smaller, so we determine the transfer amount. Half of the difference will equalize. + volume_difference_perc *= -1 + + pulling = TRUE + + volume_difference = reagent_node1.maximum_volume * volume_difference_perc / 2 + + if(volume_difference) + if(pulling) + reagent_node2.trans_to_holder(reagent_node1, volume_difference) + else + reagent_node1.trans_to_holder(reagent_node2, volume_difference) + + if(HOSE_OUTPUT) + reagent_node2.trans_to_holder(reagent_node1, reagent_node2.maximum_volume) + + else + if(node1) + node1.disconnect() + node1 = null + if(node2) + node2.disconnect() + node2 = null + + STOP_PROCESSING(SSobj, src) + GLOB.hoses -= src + qdel(src) diff --git a/code/modules/reagents/hoses/hose_connector.dm b/code/modules/reagents/hoses/hose_connector.dm new file mode 100644 index 00000000000..4c442cc712b --- /dev/null +++ b/code/modules/reagents/hoses/hose_connector.dm @@ -0,0 +1,92 @@ + +/obj/item/stack/hose + name = "plastic tubing" + singular_name = "plastic tube" + desc = "A non-reusable plastic tube for moving reagents to and fro. It looks flimsy." + + description_info = "This tubing may be used to join two hose sockets, if able.
\ + Clicking on an object with a connector, such as a water tank, will display a list of possible sockets.
\ + Neutral can link to all socket types, and Input/Output sockets can link to all but their own type.

\ + This hose does not stretch. The maximum distance you can move two objects from eachother\ + without snapping the tube is determined by distance upon connection." + + icon = 'icons/obj/machines/reagent.dmi' + icon_state = "hose" + origin_tech = list(TECH_MATERIAL = 2, TECH_ENGINEERING = 1) + amount = 1 + w_class = ITEMSIZE_SMALL + no_variants = TRUE + + var/obj/item/hose_connector/remembered = null + +/obj/item/stack/hose/Destroy() + remembered = null + ..() + +/obj/item/stack/hose/CtrlClick(mob/user) + if(remembered) + to_chat(user, "You wind \the [src] back up.") + remembered = null + return + +/obj/item/stack/hose/afterattack(var/atom/target, var/mob/living/user, proximity, params) + if(!proximity) + return + + var/list/available_sockets = list() + + for(var/obj/item/hose_connector/HC in target.contents) + if(!HC.my_hose) + if(remembered) + if(HC.flow_direction == HOSE_NEUTRAL || HC.flow_direction != remembered.flow_direction) + available_sockets |= HC + + else + available_sockets |= HC + + if(LAZYLEN(available_sockets)) + if(available_sockets.len == 1) + var/obj/item/hose_connector/AC = available_sockets[1] + if(remembered && remembered.valid_connection(AC)) + var/distancetonode = get_dist(remembered,AC) + if(distancetonode > world.view) + to_chat(user, "\The [src] would probably burst if it were this long.") + else if(distancetonode <= amount) + to_chat(user, "You join \the [remembered] to \the [AC]") + remembered.setup_hoses(AC) + use(distancetonode) + remembered = null + else + to_chat(user, "You do not have enough tubing to connect the sockets.") + + else + remembered = AC + to_chat(user, "You connect one end of tubing to \the [AC].") + + else + var/choice = input("Select a target hose connector.", "Socket Selection", null) as null|anything in available_sockets + + if(choice) + var/obj/item/hose_connector/CC = choice + if(remembered) + if(remembered.valid_connection(CC)) + var/distancetonode = get_dist(remembered, CC) + if(distancetonode > world.view) + to_chat(user, "\The [src] would probably burst if it were this long.") + else if(distancetonode <= amount) + to_chat(user, "You join \the [remembered] to \the [CC]") + remembered.setup_hoses(CC) + use(distancetonode) + remembered = null + + else + to_chat(user, "You do not have enough tubing to connect the sockets.") + + else + remembered = CC + to_chat(user, "You connect one end of tubing to \the [CC].") + + return + + else + ..() diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 2a89067e8a0..a83c9615469 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -204,4 +204,97 @@ /obj/item/weapon/reagent_containers/spray/plantbgone/Initialize() . = ..() - reagents.add_reagent("plantbgone", 100) \ No newline at end of file + reagents.add_reagent("plantbgone", 100) + +/obj/item/weapon/reagent_containers/spray/chemsprayer/hosed + name = "hose nozzle" + desc = "A heavy spray nozzle that must be attached to a hose." + icon = 'icons/obj/janitor.dmi' + icon_state = "cleaner-industrial" + item_state = "cleaner" + center_of_mass = list("x" = 16,"y" = 10) + + possible_transfer_amounts = list(5,10,20) + + var/heavy_spray = FALSE + var/spray_particles = 3 + + var/icon/hose_overlay + + var/obj/item/hose_connector/input/active/InputSocket + +/obj/item/weapon/reagent_containers/spray/chemsprayer/hosed/Initialize() + ..() + + InputSocket = new(src) + +/obj/item/weapon/reagent_containers/spray/chemsprayer/hosed/update_icon() + ..() + + overlays.Cut() + + if(!hose_overlay) + hose_overlay = new icon(icon, "[icon_state]+hose") + + if(InputSocket.get_pairing()) + add_overlay(hose_overlay) + +/obj/item/weapon/reagent_containers/spray/chemsprayer/hosed/AltClick(mob/living/carbon/user) + if(++spray_particles > 3) spray_particles = 1 + + to_chat(user, "You turn the dial on \the [src] to [spray_particles].") + return + +/obj/item/weapon/reagent_containers/spray/chemsprayer/hosed/CtrlClick(var/mob/user) + if(loc != get_turf(src)) + heavy_spray = !heavy_spray + else + . = ..() + +/obj/item/weapon/reagent_containers/spray/chemsprayer/hosed/Spray_at(atom/A as mob|obj) + update_icon() + + var/direction = get_dir(src, A) + var/turf/T = get_turf(A) + var/turf/T1 = get_step(T,turn(direction, 90)) + var/turf/T2 = get_step(T,turn(direction, -90)) + var/list/the_targets = list(T, T1, T2) + + if(src.reagents.total_volume < 1) + to_chat(usr, "\The [src] is empty.") + return + + if(!heavy_spray) + for(var/a = 1 to 3) + spawn(0) + if(reagents.total_volume < 1) break + playsound(src, 'sound/effects/spray2.ogg', 50, 1, -6) + var/obj/effect/effect/water/chempuff/D = new/obj/effect/effect/water/chempuff(get_turf(src)) + var/turf/my_target = the_targets[a] + D.create_reagents(amount_per_transfer_from_this) + if(!src) + return + reagents.trans_to_obj(D, amount_per_transfer_from_this) + D.set_color() + D.set_up(my_target, rand(6, 8), 2) + return + + else + playsound(src, 'sound/effects/extinguish.ogg', 75, 1, -3) + + for(var/a = 1 to spray_particles) + spawn(0) + if(!src || !reagents.total_volume) return + + var/obj/effect/effect/water/W = new /obj/effect/effect/water(get_turf(src)) + var/turf/my_target + if(a <= the_targets.len) + my_target = the_targets[a] + else + my_target = pick(the_targets) + W.create_reagents(amount_per_transfer_from_this) + reagents.trans_to_obj(W, amount_per_transfer_from_this) + W.set_color() + W.set_up(my_target) + + return diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index 742f89734c5..bf9c53840a4 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -10,18 +10,33 @@ anchored = 0 pressure_resistance = 2*ONE_ATMOSPHERE + var/obj/item/hose_connector/input/active/InputSocket + var/obj/item/hose_connector/output/active/OutputSocket + var/amount_per_transfer_from_this = 10 var/possible_transfer_amounts = list(10,25,50,100) - attackby(obj/item/weapon/W as obj, mob/user as mob) +/obj/structure/reagent_dispensers/attackby(obj/item/weapon/W as obj, mob/user as mob) return +/obj/structure/reagent_dispensers/Destroy() + QDEL_NULL(InputSocket) + QDEL_NULL(OutputSocket) + + ..() + /obj/structure/reagent_dispensers/Initialize() var/datum/reagents/R = new/datum/reagents(5000) reagents = R R.my_atom = src if (!possible_transfer_amounts) src.verbs -= /obj/structure/reagent_dispensers/verb/set_APTFT + + InputSocket = new(src) + InputSocket.carrier = src + OutputSocket = new(src) + OutputSocket.carrier = src + . = ..() /obj/structure/reagent_dispensers/examine(mob/user) diff --git a/html/changelogs/mechoid - reagenthoses.yml b/html/changelogs/mechoid - reagenthoses.yml new file mode 100644 index 00000000000..6cf9cfe9a99 --- /dev/null +++ b/html/changelogs/mechoid - reagenthoses.yml @@ -0,0 +1,37 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: Mechoid + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Reagent pumps added. You can refill water tanks planetside!" + - rscadd: "Reagent hoses added. Only used player-side by tanks, pumps, and spray nozzles." diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi index 4115b01ef2e048d9a5be2a927d00c0afea1f3327..4d0710885fa704f07ebe3da18c58435ef77f6936 100644 GIT binary patch delta 13059 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 b4Mw4rE$&W3>i`<~gQKdX^`K0_^7a1#i_3L0 delta 13207 zcmZvC1z1#F8|}={B^?4vcQ*pkDJdP&NH-En%pigy9Wr!C3xa@vNDWAXv~)>GclSLb z-}m4D{?BDU^PCwtv(MgdtarU@vsQxfvjiiS5sVVYL<{XvU9w_BMJWx~KR95hL>GQP#Ly2A6!l?5XpX?Y#NsAe2 z<+rb#+*}b*b(4;KuBG9m3Wxbk--T;Nj@Ye71E{PwGVIz~Uzw+vhg^t0ldqY=Is)+N zsk8mC6_a^%hsrx%pN#zqd9>8n8P{uMF^c^>QkjRP%00=rZ))qT)h8#F;(4NJ^zU!x z?^<_61E=u{~3oYmVlr zVda-+8*8bxM?uiRq7buh)J@AAfteo{FV0Q*zME}xf8h+~BA!r()T>)$5lyV3`oIxE znidh>*y;R6?RdG*F$j)Dza~W>9yGULROhXwd=z{D7u%c6&}At`c@*0fa?f$m_YLmH5l>h?Uy9L`(!oIu z%jLM-4ON(F3mG-x3?2wX3sRAn(e+E;Y77j}UC9Vhg48NOz>4Y6)s%&6|AF-qV{Ha3 z4*}&U0&?+ww5keg)w;Ua4(qp~OOsD3GOer&C$?<1&-u-_x<9Jv4Xa4*e&=7hW;UPf z-U{pSlZ$$+!VLE&;)$z{w&RrfB1;>NRTIbe-2&^)8}7he$<^x{(ZW!~GgNI~)x~qY zr?kaGhbPpmkISS#9UG&$Po=F{#&t|pZbXi~yXvUgZL@6{fVP3qQ z$~;0~SfK5x8v{+791OEIp02}F*wQ*pV>Zw91Kr63o?tuo?~l%4;UXVtD(Bt>`6&_! z5;TtU@3H#gr3fZCdD?hl=g-@i_xMoJ^4Jku>en4BNh0ng`@Q9=k8q6B-QCNWwW4f?=o z&ETOp*BAeY!Y*%iGWK1lmyt(@?;LZ<11x>Xk^ATNhBg7r51ZAw*Ang7JZ+LKy3`@4 zhTT6I?`u*e>qn!!`E3jD%LY?H8(XczjM{l0yD}Wf^bc!>p%%Vmc)lpU$#7H-Zk6lb z)dCf$_rLS9Riug&Ry5aleelfCy0MqOb}q#}SO1T)zXa;cy0!HVg`-qK72!ykmHI8S zaXgsaU`z`NI#7t|S$IuSfiBD}vzi1MM0#*4i#~sGv`2ST&~| zL!n<3$kH?K(GL?pkMypPTlcWG--5&?&XpqKLfK-UD_kO+`<3e6%b$KaWci)ptD)xP z9;5K8+6!$&U$~C{bmqyMX^Lfh#`|94ylNH;Lu||?8MvReGpk zwLkKWaqOBhR4GLLdGtL*ALRG=LZ*>zDqqcRxfI>IgZ{K8_}pyJN5~sW`thP!@9F6j zrErPB5h{Nkh<9J3I@dqrRxYV;oz!{8!g_WyvuYmWY}V^#)S>Ygj~(dr`H_-TP9y4L zO7S;3l^=ZiGcN9>ZC!&uNg8w?h;tY|ET(J4Yrxmit%TqQ^%zmsDmN?1C|geKJh~j0 z?m$$HB32KdmZ>#-=e`g))MofJ|1QX|neaL`^zipMhD`%%W;elQbVr#sYiA`B+rMD( zqeB>86^_eCKLdUL78Df_OBelWDe@?NF{(Vu)l+wK$~;u zdQelf4tB1-W#&Dt^Q5fz@0m&^7Yh%%D1}i7Y_L>~RMQFL)$&;Gk4dKluhvugQ*W(M za-eOX6Kl3sXdI&M8&Ir>QXbf+-uX03BToc2V1H~mRCmBxS|zQ)j= zE%9xbipJ;4Zgt%Kx3S(b*YMh0Fax@G5!J_AEBFHN9y|(1%>xSq7x6qWFLV_*{8f5J z={041KU039IQ(R>G+c7kxv;$-G}Q)=;5*15A*PA+V6I9;S6pXOdLML;IIkxIv6S;( z$WDlpBX^^OuV0Os;_&qeSYPhzlH((hgxcli|v5oxsWYQ>dY=yYX=qLgxoZ#*5cwr#P zgRo}0yBvMJqVqKmUnSJ5e9^YdGd)k;Us*lYA)eN4?Wh@1+v$xzgKpA(=%&6OljT{v z)t1`xngiFaY5;~$VqLY0RYmZ1I@ zXF=6?TGc&b`k##GX6T}7JhS_p-7j8O?Vb=w;Pm6Z3eCyrrx*C)Q~8HAl9578$ruBx znY=6cY~=i)#4~9zw-4F~$rt@ewGO^_YNukv9Q@5ceH2^n!&8A=mibAnGPP`DYxsFF zuNULtK*sMDa(tpc=yQ*S?wz2ET;j09bcA)nrt1*bw3gqhU%_W!0uQ2GzQJkXD0YHL zBHfdkEcY*CTfg$VVky4MKfg!uZI&&PaL#ySKqkM!oXUFd-YFJz;B`;>ru)7I{ZM1a z)EduKP|tX>AAPo~dw<4>XVhcYg>!B#;qEUQ{Bh9&t=eNmFPJ5&!hW6=ODv}6ahP|;O+y`6N1YMMc_D{Jgr zVdZbtso(W1@Y8>*SEXJQ;|IOutVG7Rx~o;ZPKnwT6^Ub&iT|3%z&b0*<00`vRQJFm zrlo58gqp5%Au-&Ug>;UnCny7Nt#I8m`S$A)u6(XVLzbeOp zg7~|3ce>&)%381Tbu2r%8hpY;ao8a$V5IoVK!~%%>ZcL@!*pvc(rapFrT0%?89hPa>$gewI_~mK z=OC~@eJ1JcniV}fw3a^xUe>8h79JB@(Bv>WS!4Xck`OuG{z#`TU42Ip(@rFL8e4h1 z^0&>SU%exYH%h5(x49L}R_PiV{tcw=-IE9a5I%lofZ_**K3NK&oCePCNYpB1h&fJRwTx>24Agsml4fA)+F?BGG7%=X;S0-JITcLw@C9j9tQry z<-QbwljsNHO~=KWfg4^;w-@H+KBwoT>r>zLuFpE9B+q&{%AL(>T_2dAwUQeGSGT5f zX7k&N@t21`Me2^nOz^K=6xzAG9#GMajM++FtmP`*qmgXb*WMR#o4dLY`BWl8N-v3k z?n7TqpYF^~SH4)+<~}&{8aMTA+-rBPsn*)hg5F;G-dxY$UW+iZu=L925R8~Xb#-+a zZ>|Pzue^MHeRsKauhdM^&VRZE9qwjAZ_Y6)Crd{%6rBPj&9|0lZqG)t&im|cDhbLP zamELShV~InftSXeot;h`92{@mny*hz#-L+kg*Xo`t(@3=`mBbky*D?kJEOTwn}e=X z3ZkQf>n<7v9Mp3_axIFq=DqjzlWW2U9(1p_GfL>;=qWzuR`yE~Nb)?&lA*$8@DsbR z3wOwpoZnZmw?2CAEi)jW)q3Q>iB<~H!+S#`cl0PWVPazGB78xX;?xU!wDSjhip(xB7a&idxrgXM1}J_E6AU*_?5= z`t6$LJ-B8Qm>e3Ks0q8cxM11b+)TqjN1tni-Ucl#w1ntDo|&89ULyZgUthmn0BLjG zSQ~^+eDj#+C~r8J+u!$CQj)qDN`ytl#Gp)2iMYCc-W(NoNre!;t6G4C*=K~kp!cPMW zK7alOx$0tw(1)doiJ_-jz~<&2T{jv`;eCKBpcD#MxTd$jA-Xe4PEpfSxy&WY=p#F7Vf-U}Y!^u|q<8NQ?lr z2>i>dHiyC-H9M4O{%^`)*N352fQ#{6eRM4i5udS-2}4u73a|)|p6ajMP!mh3P2VC;{*{q zL_&%HOa=_ex0qirF!ut;7w+4@wLXI>px*uwf~1@*Ek;ShMZ}SfrRlTwN;9pVPJu`8 z4Q-+1eoXdl*NH)FyXf6p{k_|ivj(#JCGjg%=w}&_?H$m#-(FSfX&jwp=l!3y${iYB zSBb&rNf@^#qOv7pN>B%7^cNmOv$KtliNf6n9-r*gCX|d^6U|}*Wn@R_BK$#%8&G+-x{u4^qCS*yktPVplqThEtiZ4zZ*7WIM^Hm)1!Oh_;cGgiGi7vSYlgo-EJ*ue0YU0w;Y63E6zxt zI^^;WA+WVrz6$8&kEvR$Fc!`lAzXW3dD{C5uN$HB?%5N&C4^;x%p%euqbrI-52C~# z`^PBm4yJuH?LlY>Cy|e$6AwHP))!XYcq9Hv+sLM(t1?=g;x{Um;y%FYkmj%ZB!TXlU;b1_q3WbCoO7eC=+poPiJkh7779FwUq22p0}fM>C!~ zb0j)g`_HiPKh!GeG1OjduN9V~w_ZFpw$Tf^sR)KYNfJ<$BF3HmP)gx$ciu#E^iILY zy@1#--8);SEs}DBrZ=umNR@w^0b0bx9}fD!!x4GNORZz*xr()g z?SSXOE#$dw<&gn#`b}K8U1(I}Xj`pDE((@n0GZL;^7BuIa!G=09UO9_O*{F0g%unm zwgi~=N68BM+|4{%C)Hn_#XXn1{-n8nU)KT{h^A^|=J}hy>GK8Cy_gW0#73vnqm5-5yR4DQ{6A=oGO)h zerfXu;1ad8C~3R`W$Twa%lvx7;MDu^$wZA+csAzVmEzw(HAMY3`VM5?2%>^t1dr%_ldwuJ)vZW#TrE; z;S?RRx^WUkPW6vNZ3+6xKJT$`)ix$xhr%IXlZ6!h3Hq%Klt>AuYKVp!A=mJ&ORDYj>oF?Ndg%IE|(;XPTi1SjQP9Fp~+- zpzncH4S#4;vgM|7s$^IVV>H}5A&SaGh1@4{AfAsLiKY6;14u$@D4P8UTBRD>*E*-G zU9MV1u~ATFWg$Kd>$rBM`yg=7WAw~QY{wlh7M@A$AA-D(&3YP)h&-`^z`&xK$#Ky! z#Kpy5ZWI@;ZEZ19;NA=S@q3q)t?94J_nzMsOCVaw$`bK(r|Q(BqRcS-ylhn_L1-nUGtO~NPux#5)dHrN zdl?Ir`4p2FnS(AK$xFTc(lw}B+o?H8NxWMh!da(eT|Tz<0j8P5SqwHc6!d<9>pa(R zF4J3?DgN?cnGU#4H@rLyQGf72fl&G{A}yTXh38%?$pQyvkv4324T?FT>SaU8)Ext#UY&5uAQL*q3sqNSZL4C^RRb z?SlgPwriQlo+Hn5wy2umSkG6f1=7|%$gG>A!lUEk*-2EiT}4_`TIxKUw){A5f?+hP9G~EC+UTPw$><$vln(}%`^669 z)u1F6i*mW$@$~BH)DGHes1j#t_)W2jF(4Mw9=pYsHeWqRk(O}u7iJQ*S8SJ^{Ga+c z^DPk}S-4m$W5pWRSs>Eu-pK`#{RT(tZE#Rwg?098r`&BgsjH=Bf`e22MwF{SesQk# zLh#(&kM_g?iFj}l?iU*v6N-d+9P$mcTnHrqjjqbe;=*}LER=E}ek!{{8~ev@7mcBf z`;A6|ReIW)wX-Lw=t1(}TE28lYw{GUAaVM-iY?-^;7_(l8J?DF=D7nbbSXkR)Su_3 z8EOH3m~Gl>5}Sn$L2qu9@FF>j1Sd{@MWT?Bp{LXcSLNm|1qWW9R7Xo4D7!p|K3~}b zI>ouUsi}(>bhZm-4qTz{+3s6(g9erX4EVd!`8eFY)}KK3OOGp=_qd@N=g?uCH6|Y0 zsHoehjET7<&#imet&d~Ng&Og_sY029tYCP$DcrIOjD$Xj2$FYuce9C&#}?W%X$S~H zLd3X%^xbRXuDkh>oLKD8B2#Qf)S}Kh-178hy%WE$3brjg^!zR^e}MM$XS4s!`6^A9 zZPg0M*y($H{jQ|PV%w$U$k+)yG)aqap_Sop5OYE#%n89wKH#Q2*hAon z&K4thg2d8(CWXq<0qtfGnafLm|I0!uO3EOAku7fB0Kx^|G6hsWS7a?kjwWgxBUt$h ztT}W6=z~IjLk~T1Alh$EJWcvSBh$M zN^IJt@T-=+Px+iWrskRY30$xq%mSI`fScBX1yFv@lfV<|!F2p}QDee&q(+N0qgog} zPK!SfOD8K|yW-Hl4zD5ZzY^xk9m27#i^>p8$5Z)4ck%ksp&0y6Jy;Ohw@Ux9zJB`T zJRrPxwqx^{8HfpFJDXJu(lIrKt=&VmCFK8QYwmQAIX8-b0T$x1{CrBF-quPIc3+9_-ijEV-b43(v^h~E^P!CFJ#Ey> zan&t?njpUOwHWE-7UzSBrO=tLsq-Q!$J}wS86?_hnu;p2uq&6jLgUYOBO(i;?_Ix* zqB?Cn=;7FXKtm%Ebd*b@jx}+1CJJlxSn3EI=g;zC?$d?gFrgtAeJ=D4L{4^BC0a4} zn9y{s)3O67U8Za})EX{H9Wz>sP`aQ5ol2N1CurV^UhEHkUkeFO66ZEtcQO}{4`M&J zQ8Dwl7ZCWOoS#oC89NbQ`6ZTpRE^MgNu`TFf*xK>A|t&VxE>_#Pe50?m9N#0hOgr> z=2c}rd1C*tvra*O$RNM{OR$BU40L>atT{G5E`pDX+u#qVP#rBH7>5w6@$qr!ZBtXz zjmlh5J#B>@J0i3P(GP5ZfRX@=PPlLd&@Y?_Bx$fBUEmP1Jq?+)OW3TgklJR-?k!ef zp*Wn*!>W2+b(FxMp8P?#QnvkmZ=2}xg9JoT#~y29KB7|D{OQfBT;KJMH6A=Fs#Btd zp4grX%vX)5vZy9ZZ%y^iwtKYw5qQJ#juQ1{3L*& z=Ztb`CcS1L98!>GC3$sSGwphblQnP}8XO$_vsjniKGn7|C+GKI5|>HSL+ns99-FHa zO!plAF9M_seT9;Gu?dxTd_sJj9wGrycOF-8QxQz@e1|DU*7z(=hPUyuJ?2dU=Bj-8MBx)d}JL~wLsd#%lAPxU&yD6KIG#T zG$VhPN^dl9R>{7TqEQbxvt#KNU26DAfs$B(N^I?rYQrnPZ6Zzf70t%Q8HMEjVm#14 z0_?)R#+C7}@H5p6h1xhfms)klGbPl{2VI7{i_Ykels8>u!7~wHMkxJ+F1yfKK2PBKn3V+KK=bW&jKs~^613iBy5`W4)@OU_ zcx`reR+B{Rrix1Vs(JomtoG)h^(^ap%kFk(zHz_f)^zRc(%85ra6iI4fSdZBCMjJ^ zOw8egbxdGGQT^V@u6d#h>zm0#8}*+q`IHK$$SY67UaQobAHT2ES-)dM)P*Uru!!pv z>yA7=o%t~Uz43wsOOMa%>k5){+!RLBNEtnSTER{O_4GX0zMUL&m#bKmGSWG0n``u! zq6wE5^;kspo%J4v`op7J!0OPiSXhQL=s`?m{&*c947cj{Y+J2%e$-GHcIB?w_Bz|~ z4J1uXP1R}_kA7M=C+89!ypuL!$rt`3Y82w^0h5b(jGF=kJd4Ccvao#yZ;QJIbSk*5 zEa|D6BjQx0SB$+ytQ|A?Wl19RJp{?+jXYh%lHwb;sZ@dNiOqd)f=kq z4f8mmZuPlqg&j@(e0p!2LtG&6jA|!9X$MiS>A9Wk=a#aaBSS(avhjy-0yZ-Yu5Dq#mpU9v-n-v_L8s#k7Qex*accHAWDCaW(9z{SN16JU8TuN=3Mr$X zr6zxX^>8=*Zw;kK^Dz$Zo|*;k zDCOo0U&$W=3eosLPV0g*Kfs>Q2oo;g{FCNL`33M}v^Mr0ns|x9-pO9{h{F#Kz%4{3sD8h(_n<;JMQV%4<|Am;7?7LpKpg1vd+8tz?r3MJ zXu66+;eTf*N4W#|VeCEGxixKjd04qA%uWx5y($?=z!hMH<^R$I?rM;T&-SEB?3jah z(Dq|>@%QY{=n-&RI-I>yR6#(u51MwVy$&5%y@a+R5Qsmz?4*L~0+WM-?)JS&T;}+p zvgIP)FV-g8zES_X>XCnTYCaFya^-hW{~S5~K?HxiE~RV?aF_zI3?Q5RbVl{lhfIwQ z$%)Mg{#J4oHp0u}{8v-Q;C&Ksyn|b#2pMfon zePKoO8%v0N)*|jx+v!#6bm{X8n16jIGbH~fZw<0wFx|ConN)y5G{Kn|fP<{Snbk0j z!ogPGl;nRmfV_J3A9Etqrfn9x%w5dcd`;jW_((gL8d~3-cioWDuQC5>B?2U;b~faFNQeRSasQpVw^_GWt1o;gpZ$Ze(DmlzO@9ee*79qj{mXoTtu3^3A$HI| z6zXt5m%Mjs51_j*L_SGq*&7joxg|nL7L0K08HrvlhmxC}y|v2<^w~Z;J2Tzr z=O=ecBSc#Db;w=K13Ez*z>!qCuNgnY3vgzF=^lPeB( zg5MU&Pl>amEi9`%fk5#Cn~?-c|NTx<7g!QH`(So8$jE?CSMyEC@Ao+u`%mYkA!`gO z<`q0B;^(9$!<+54NN`M}~^in@#3o&+68@nF&;BIID@tl7wN_~2}je7EEi^pn-kRH38O z)58)#0lI$osv(VtbT;y>FVh{f;4z< z)>yS+D8YQ8Kmnh@2hhI!YjySGT8@+}%L=R2Nu&rhU7{aYoP6q^vxgLNS8JSKexEo< ziJ1k2=!J=i2|E*GG~O=RyHj3oW_%@3_))b)k>|U*FS;@|O}k&ht&zo#uyrX27Y{r6J$g z@W@vNnRpCHr(8Wsr(9rgiL9{iU&fS{t>JQ#`PbBH}dUT*M7@KGVEa+oxx}f2m_KqcTovZR?MQ*md(4mtBhonA|mZw0!V-v`X-cKc5h3Jb% zGKxw+_YLh_S~JpK+0mK3%a7hI%dv@RrfME7Z;q(W5j8;3dlNDk8aOd?hEqVeFKaoq z^z417H;arhvWkw_@{vF1oIe_e`n^1KHwCO%ZdmRja?`IX7f|RQX*9V>Me!nr3oX!X zAoq+Z@M=~laqC#b1&_)977K1CJn)lLAltyAh3c%j($JB&?1L&Poo3k@-cpSULqoZs@}94WV$y&ZlanKboy0Im90{u{xF5iK;pg6fp3i0 zHV_r_g69rAi%WZIk|&8*q^mRh=HH}vvVbRZ^rpRy@O188dT4EY=%ftPFT%X)`1_gVhX+Puyqk80S(0EtB6@>8I< z#ozBRc@4h{no`LofzTr%914-ZCjcWA;BTz&Kq&MG95dMJGEqSI$Pao15;Jh_F600p zN}~eRpn>%Q_Wm!OxI0kzySmqyyk9U;{W>7*EOn~?h$5X~K>hpACjLkxxoZ?!I+~cy zGNZ4i+MvXW&RLcSX`S&q$m^}h0d#E!NCN`Zj~QY-Xq1fu zLf-iDuNVr&{6bCjBnoLH12!O&wN7QYCpZW1-_X9y=?k17JRiR9k)Z#-?U2me6@sBieg zFv}?wO$<)LkH&?h%y7(ZkSe;L83Xcz zD!O4b-gs*%>Whnn-Js1+cESB*|09JVMJBW4&ag>aX}iZbFNEKLn!UIH^7POI_1jmZ zR|cH!{9nEeo#36O96YoQ);BQuebKkUZ=hHhWF}pJ<8BHdi4pL6pp_`rxPHuYm(~g; zZ&UPd4+0n3fql;N=sk`c1&B(`DBz4@a1tfpjZu&)-k$7daFZ?ArJ;>;5UAUhGit0d z8`uE|WClpOafM#YB7=)b7S#}n3Tz8Vgn-WwiNgAYh;U3^r0bud-YpQRK>;~o04q0= zp2cXwFFXwVXjK#>;dwzzDtEkuh_nml*8Mm8?qcRYYM{OtWrp4n&U=f?_t&&Y6hZv2e^i!$s>XhUW5s#55m`o6qUJzs!Q(NF7WV1Rc;wovdgk9-QBH zS+_%XR*v!Ip%?d8cU^9C*DB0kt_Vm#d(Ka1dw-9alsn)#LX%dZGRb&VO{mR-cmZXG zMM4x+3Y3I6uW2z~yI1$A;1%U%19@o&CPS4WK>fXue9V}44m+|;kaW)9_`!?`+}HX` zz#826aP!LcJ?5S_7XtZJ+Gk7xL|Q3re9eSl?ncnx>3F@$3{lu!SPRBzsZ6(5^W@(L8DS>GB7J}cJXXd~zE58IIT4boenHNT>D57s>}x(y z1NldL_r$&j0^d=2kgd$WtF?4Z@xZeW_Z367R&e>dsgnKwydc)5tI|eBz-wA4FdOGR z+sE&{j6=@;FaJ%A2P!KYhi)H{i2wX7P(4z#1^s=ge%5A4o1O=>Pz%FR4ZVwA2tG+vXD!6^KD$1Pu6D(g^C474*`vfU)-A#!T z=|rYw(6r&6SAx9ntgVtuUX;Ri6t#%K(2xzu7tUT+EBojI)+6{MRWyPCcD8>fL1?>M}G^m40@lEaQU^vkNGIyR4GAf$}Qx#;fAb$PQ{|2n9@54}W z7J2MCC>0a^6=+B0c>+=l~ElIun`)qQnRSLJVkEfjni{|$i|Zi zl;EYDS>V+KU?jlbMnzn#v~pHdku@w40>l&$QbN3&>dGTiOIzG0+%~l;=O{b2Y5K1h zo)}dK=SUD!;8p|t$0NV$o)Q$3?IUP6(tB)pS|ZkB)aL6upgTPS7nM+aVrgx02bkVj zk(X998i50=&|m6Gv0sK{q-F)|C0?UUi8@` zsllp;yF~O5wF)%DyZu;egZa% zYmHWEW6z937oRRBn@$c*7<|_tt zc}$7Yz={6CCASatXPRfj6q^p#?DNmJJk6N5w_3yD1r zhm4ud44Rl1Q$NJ^!jkBN<#(7Kw`5cQ3TF zCl4D5+r|ChS${|WY^SAMy0%V(yxieBX~P%x^Qv(HfB|@_D5vX_cbFgSO17Ib&{dgb zLqMt;9l>fD+Glu?^9d*mCG|*n+na39rsI*NQ8t|}nDev>#oSBpnQi~!iMn4wo1^<3 zbFkR+ACfc)3hX)c$)TQuB_Rs?6BC6LwytlNxxdNRrjULzWi{<-ZI#hK@-r}g%4NSJ zyn6X$tET>QAR^81f1m%8yg!zzr-25x*eTNLhBje+dd&ae&MH2xXw+~0CCa)NrJN5_FxLW zri6=AW5DoKu?GB+os|_!o!6l;EMKF(u@Ma*q=5llYec|0j8G+s4iivUS7*pk-~2K9 zZtvhgNRebT6K>R+UI9^7Ru*K}$m=eU@&{D$W)~MZx$;O$PxE1JXn^1h=lg|I=rigS z#)-W>4xsy|r-g+@(fY3QYCAM|R&@lVk((|QGC8Sru+~LCkVuO@;KrH}w*>>b@BZGn zZS-JzdU@%;3AaI(aliI#fJon6ZQ%m}Cw-4w@k}}c!~pZ&D1xX6`hWLLJR@Z-EiF&? z&G~U;wfijx5+TX$JX+#AwxUk+=7Z03c@RaTQdz5`PWR)8S6AM<&)tMf8uKaJiSV2B zc+IjP=jZ3sw9)}Eg<9U0+e4S&G&7ZAEmxXoTSVY&HGQ8Giu`rs{qDHy${}9h!IRuuN_Au@i`^Q7Luexu7RyGf! z)^pMt2itG9@kpi_zOBI=BAEX14`6-CxseVS11^@LqL13BhnoajRl@tX+ybsPqJfak zPHB({J0VV6lk4kiKy~@^x@|&Q1g>`(bGI`zB62PU?2(j}uliH2%aYCh+Dj8w%3kye<75J5}qrfwsj*gDr z+O$Q68R5^QqEeaq7-SP(tACiN%WAxPEq`%wanv7-cTh7T+m6sKjy3Oro+ukT2a`@c z=x2IaF><2?38WiMR8*8ul>l1Z&i?yZyr&O4ML>iNN-m>g6K>~o&5|hDIO$2q%>A4G z`BQWXO3EQ1xr~L>)bA(j%nf^ikNkzS1Z&MNLg+v4L|SbkUaz(r>2t6S>rvK^B_$?O z2{MnU|L0(iN6)yh3wH>Wx!!y+{RhOwyCzmAXAPB)me=Ga z5C&pP-($(v2u%YVnNd_g-_(B?p#wnvOo1T8!u})VfA92x6Me6>@yU1VCHuucCDBeM zIR>q*>S_0C1_nQpMJ5 zfFCW|7cK6rSXfvNl`PSOw8KtoogLe|`c%mKu4EuKbTW zni!N_-L^zkIuC93J(BLFc}He?aO`k&*`kB|IG#Lt628>rV(IKm*yOU-f4I~n0JbQ| zd|7^yh5R-1S@@pUv^@qcjZ(Z@u8gMBHu*k1ty_)7IDEfgi`b|em)6N&YJC09X4ITT z5j756*a8_O0ZXH^jx+c(@&twI*Y~!o{;@@d$IJ5kFj&m@GPtFyD{**uI1uuF%VFoz zr-PH3qd$RKR5uoJa}8c#t+a@kvB=z%YoB12-Sz_J-8!z+^O5i-XQnet+)`YTGh_UsbWvO zVApyFds;Yzw4*^*Fy~ttA}IGVOP%dxuIsL$$e%ka_**2O$Grnz59AHkt@j6_LJPN+Qv0k$ju=;)w~%DEr< zwZE@rW@grKiY_Ze#j}4FDWAHGuO+rI?hlOLM3Z7GCI0L`$QfE2}JqIL*ay~SVg-YYB8r|mb$ZQ*n~9Q zlf^1X&MH#68{_XZ_P5gbBhaL-J1rqTDPtZz%5JVIPixZv5?FAMk6azS8VWcLr=Kf(tH5-e*<&)bY!0%W~_R2UT5nts84?Q`{4+Z}!!Kagrql zsHmxTrawIzvZ`G_F}_3xw6XTMoJIIn$8Ey!U9cxaWO4oc{hxf+|5DzPrzUy*Z=9c} zEZ#dmKR;cmZ^jtmU&FuvE=l^@ZsF39u(3*bgWm1^p6|DwsDBEISY2I>NA9GqsW7GF z`UK13318pbJOK@l(=aGFxXZ@Y2)YIRagyP*P+RKk=Opadq@*37*3 zCf<)YR&``DLe*1`l9Y>mKnd@=N2`Ox^l+x<=VLy6V2hA{U%T|M>+YiJiOlT=(f*Gg zKems`xr?i+_|DD{_w6=ay+$tUd@D7_fkPV`E~%DFLSxj>G{Q(jmSp}9U0q$jH~Zpn zBIUvF)piawbn=n z-e)dw*Gd(3#^g-xw5<{z&5!s!^YauU&dVQtowxcEU~hh<7rdy*K3CDQE0u+OBFVcO zyc&ZUqo~patvz<#m#%;5iE2&YV%3W zpYwF?Ur3A!&G`+_Z{>x;K8u;*{u^Gx-aK#XK3-+oVN4iWzv=f62qp@}O->8iWlk7e z(Mkua9n>!xoj&=(t1~aLS$4{#zCNRv!qs<%S5God6#c>-t0b07oRg;$4pCBMmHHau z)mS!vBA;Af%5{OEgKlU=%&gh}d*PS^ej@*#m@fF%4Hc-O5^a-1OG~SygHRiE#rd+; ziuW;9UM*;rdV+?F(+r-9#UpmCL-_D7~8Cg$d{4DRGPWaN-I4)1RPaJTP!6?8H%9$fY& z%-YDav6VlEwEKDKwlx5H+unW)?=~Wr1UOShrp>WueY0!T_*-P!(}+rTUF$dXs%dIy z&JqXQ;d2U8Z;Cj2URg56${K5qV^~mN;rA9^2FWzTlB|p)zW0YbR>WBL5~{`@OB?{H zpH@Ebp~1P%tFFW6^>A~?vP_A%%{h8~VJVrZXiQ9^A0T5b2CP@t?EO3rjXPV9M2%n7 zty%Ax5Qg=4c-J>q5A9;`#jI~?!?{zGhF4a8_kPam@vZehC>;I0lN1|1%2~H{6T5lm zPb&h>T5`1fb!Q*93tY-o`PbsxTv8gtY$d{LYEaKqS5HR`_IH zUrH7L*LCacKZMN({o)xU$T}EBdJLP`@Idx|pWKvZ;_0@wBq>m1APhhoWjIk(? zOL1Qe)QD(?rT#>n;wrjnM6so)mY!9z@A}Gpo3|q6?v*8G#e6ew=;YwlJvjmJjv)s! zU{2h(ywu=gDEzX*Ibu1L*bae9)7ccV9KEX@k=HG#8Tq(QNovROS%D{ z5)fjQw|C$pMC?9RUgBE%GJJ+xkMk z<8NmP5nH|+n8?~a=SvI8%!qL7uY%pB`)8(~+EyMgz6gB$1hDocs`qDHZ3&lPT5l9J z7aUR;)c?zkG*26ca;0#@nj1Yz!U$9y9UFc{kd;jSZA{SaQcXBp->&511keuUFhf<2V!muRr>SE2DO@#83Fy zuP90|NnZSQo;Uh=2cig50XwA6hx_dpqw(?q9AI$ucG!y4CE|ypvIPToFTlx{x2-(YDf_`p|OI5&8+|1DXpI zH}VQx8VKnGaJxd?f|(~!}`HI3mP4^7j~fP@tLXdLd>~84G@y(#C$yJif$oD0ND=i}&0JcX>s#N|yl1K#@ahFjYGn7m zQ?g@Q;-klnjm=i9R&`j}st;;wB%CT}uJiu#r+O1T_=(ZEYFxV)hEGUXK1=C$domD8 zk3Kl|P77pVjH*;`=>B1d?K#pm1eGlynIYf3CF|X0Q0jwG6hh0xdzI%^Vq?4GC9e|q z00c|SS)J+wG&EE89s#(N`}%?Yg@1(-v5g3ue1Jbz!nV>T&3^5>T^)IrLiT4ua;LSj@v-_7-Yh z9Nhtp>_U_V8KZr^po&gxVvuQ$QDh&jq{G|`LT|5?fQ7r3ru$>;gQX^T)+sgH{Tec@ zN{qZ`Ob{l)E8HJ8N+@>bk@Jjcp8M~fixqv|>DTCNR8%el_}nMT=0Rmv7lxCSpoEsZ zM4$%81f;VF(uR!qfdE2kHXZxph32c3w><9h`)Fwnr~w>=yh9r1?Pcb=a}f?gtQ;eY}F-I7fiEjQAEYF%CoV)ery{&Ph8 zkVq_*><|bZ`Mq!=yiCjN040J#6>0R3I*3D4XySz!3(;9uBs?wva480WHB>mZrKPfK(3DdeE<8TCI z@9!|8h76_wzwIY4UPv7;QiFRB#k=^e1md!5w}G;fisx+uTD7lb$;UHC+c~~}9LDCx zVd^A1XB3c#yKf_o>h0fDxxCrY5c+b8Dc4QSNC-(nPkMdvSrW=HV?0!UF23H7rCzEA zU4mxxtQ>i7k(M29fE}&m)0eRFLxD#yTgv7G0*ZI)oAJ@}U}uax;w_ z*XUNg4^4?vIz8C=^s#?LOO4<$tx_e~bJ{UwU?FSQYoSlI8^MRXCERp{FPH3wb|`h& znC0iS1ady%)YMq)^%0Svs{WEIAN68mx+IqF+KLL6kWTDzE9xvc1lg7VT}?W}z|inG zC{ERrI@emSnUm%0mf}8Er1wHe^`YQn>|Xv{%QRK-i7~A zhGLNJK3`ZSPufG>eY#s-dpmRhjEc6wWZSAHp7y)sij*7;fIm1Gt#13tp^=LU9rx47 zRES<(Sd1zsPZ@p#U3-G{Heo^V{_(3=MBmOn)Hf!QbP9&we3-pyd-995a$SK`iNqy> zZPLGsegnp5TX^f-Ci#+iy^%TZVz$v52~H2jS5~D*c5aOG2i+Y(qN(;I&eY+^v>{1L z=F@bJ8w^#ri|ywJL-icgn1#Pl7j1{`(PX%BU@#$W{IWckg=Y6F>(u<>FS+j5qNBJ# z>ie7ynNXwCoHYlI!diIYf_?NrzXd2y*Su(+rB7(8v2gL`JZ|QJDiF4&*j&~y8tyz1 zeSHekzE9sj8uR0akLf?Q!6Z52=zkbl$qt5581GDo6-mN4diwdzjj(=7c!O;V z$Gp~O=awY)G2Pzc0oAqy`Uco!z2-V~%u8NRhiC&?oG-tVw zSW*o1xmnFWuYGZ>NI7klCs3>E#j2`<;08UasR$#nZf@$+bLBX;%FFV9<)M=n>AFCD z{KJs@h;CWr(V;23e43kH%y&xH-hKyv69AmV=|M9i(|yy_HG#uV3>=#yxOwJnkw+NW zEjOD^n8P>rUjCRe%!5ClcF}=uOWMw&Gl-(rH%nUSl`{wq%K?WlIV|JRcCMrMM3yLd z_Oby-YR_fk_2eW|W*!kJnt3Cv%SKrD0})ifdlZnx_JO#yKo;CpK+jgV9uUHnLhjXc zqvlmUvxu8aJb3UIcO(^I3k+lBuf2{&t^(0LI^?-T$v5j6XOO{pN>Vx~`*)1mjtU!m zOtv!!K%P$|>ld8i`c~+c_noAXlA|FkOSQPHH@ZfZ6Yi^H4>^jk+_Q6g2zL9JK_+X{ zNnrlt4nui}?~UYRaeBa08Yo;v$R3rGV=!l03#fHY0T+X|jSVnjjS@GPI+eMAkduSG z$$AD0?};)odWK4hYnlSmv)%{5hN3Z@^Q&1+^PPZ@rvB1%_8g)@gCI^GhIn$ilWSrp zukBInX2G0@HS2IbiEm-kEFzgH*xNb(E#LrgdRe2y$X)dGI+@U^V*OgdeEs4XZj`5V z2%0#3p%54k78;{U6L*Kp&LFa&B_u0#`ZE9k`3P|X z{dpI>#fX7<`||u;mKY;X%tP7i5l-P5WG^7(*Cji^f=P}6;YR+ToqN$Qj|8di1pq+C z#W&7Nb_Q@Ou*RwNyZBY4z&Mf$-$kE50YLl`LiT4U64&v+TLhI4;DzViJHO%PQQ-PR z#;`SCP2XX(3|xGWerznAPn66If1B|GodY@x?K_hMvjJcoVuumikFlepbgJk9w9EN2 z7=g;qL`zkk*6*U;FeL4)D0-MnRQQrIH$q7}N?|&Wh*-ZKg7=jlpYF<*Nb(QXt%wlR z;C0DonfZgTx>q@#W(NU_nx8`lt)kHb%6iNE7v#)?GMwCrTBO>+FzRsCmzg`0lXXs# z^qlcq-;S5&r?pV-Z3)WV9V%laE`NM_!?U%PVnG&C@g4C{C+6mZJ~zjIf$D!rIsI7! z-b)_k;WBC~FxR`no^4^zS&p7Hb$#py^Z(<71+=!cJ^ykI?FTdEx^2?_4bLp!u?B;A zMBpPMw*coVyU(WzqN>LQyKdL#_EVpHU+lpO8Fx_~?U(BGBe6w}bE<#jMS!`rv#H!Wn_sGHWLI#*|HA+sX zcs4oH@O}D*LsW^AIz<1m2h^t^D?`3P+W*m}??ok%OH4qYbM4L`U*Feo?5}6-w<^bf zRi5Nt3K^ILv4WMKc(ab!&jte|O* zka*D;5Gy?7i2hF<3JT#BAvP66G7=JTV4Be5yH*nrM{D4Kcy55MG&3Rx;;hPknGSf$(qUcZ;^|L|nvtl*)6 zDrk;dXz^e_ocK)Y0C)@Rjw8&-mzY*Y|Cg%BIxjQnTPytv!<4s*Oq4s0bw~TokyPC# ziY%l<6=q#@VGM;|z7P!0P2+GDZ+>-koUPFMyWZryQmd({TFy$*AK zpblEpJv=;U1){)AV7q@TNbk#*ekl`rc23Svg;5>b(fn`**W-g|semij{v$BI3QOz- z)BbJdwU4iF$i{=W`UxU>H^LCeAhx=ozkb!+agKA9pYY{gDNf_mrdxwGQm~Bof3A_L zZp)mFJejYt#J)Q(lYszU2lJueXC#GLrJDHkLEt@?L8TQ~a|N^SR@t|zEUCEBy>^a{ zX-QI7>*2mT2nlaq^g(4nw)|mj9Jy7cNgGxviLmIqx|T}|g}I3Al$4Z_#RkU>Pw~mc zMLYoJx(=k%UF}U410iqU;4}$@& zyA~&X%Lijt!-G?L{{sP#C=jBCN=SyM%MjyiL!E0JV|ozcZ}0#sg$d5yUs#0_7*w>h zm;mS{z)~>z?ege5(VcOsA&ZQAq}g39+v(GGLe4tnIHMi^GM6)T!s!0%|gj6hk zaq-x{H8|z&i?E3N3Dt0Mj1_Iv1Sw|uS1e# z?qKMES-?qTrF<5j86hxV{VJSMrafc3%CLqBUG`xWmjYv>3!6>~iJ!i3kqcL8pLy4n}M7=O(h>-{;|O%?_cBHMbc0__ zYk=D8$r%!_tK*GWwigt_iVMF^9pBCQN6VB}GSSfToTK!BQXZ;h zv1pi;rP%d2C1PZxTI8V?#?RgT|DJo!J?EbD`h4DheBOV2&gXp2=acA7b(^nkq749; z?@n>qp;7kVF;7dAYn={CHB!l<`7&LC!VjMc4P%C$JOM!D&0A?T*jP)w_~6LPT;4mH zvY{=+1RaGY&?u?4?BmlaGgAi|TG(UVdnS5Z`k_lMgk_8FdJV?@jyC-wyPlqv=7Wg$ za82AzZ(|(YZ0G}v_srHy5;O!~r6>?#_?2fP*FAUyS?l;Ip41_qSJ*+T1L2P{Nyh#@ zOEVXq?DOVV7jX4kAtg0oWpG1;ziMo{vN+J%rjzG<~!n!`LLx~%``N*eKRahrg~?lo}Ttp|CGsOsp_!TJ0}XYy$P9~ zE2If?p@s1FrfH@_k}r`Xm-_=U-`6G2Tin)`jwvxgCZ=XovWJI{hX(|J))2$m+FHPV z_H2_b77GWuwc;;d2p}Lj+G1#Eh~(r{Cy^jsM>j>-h*hem&qSi+qN0`H4HAdL?ZcEG z_JXFT9l*7#;$D&nIWTb+knK!fLJ$=D-ps;c-+P0(oqO2lol-hG{|H>a*qGyE|BQ1G z0D5pRUm&=Yn3(v{Wt-!3AB(=x(H10ID)n$nI(_;y9B?=sUnna1u7`MJg!khtlW9oa z#qnH@$Ynk4NI%hgIwYhpG$y^0IWu)*>gyYiV^G=Hrv;5^AR{9qFK~V6Th?s(CK9Q{ zX^}R{m=iNN7<7Bqd_rTKfo5^Mt}rHsQXr!fjS$}3!;)B1BO@bxOf!Q9)2%Hr*r&#w z_pFM#9%a!VZHie-B1I~Q=wkO8FD$(d zdgFboAsPXdn>}-g|7m+!{%5=Iq>7pv3r#tVGSDQXSY4zME@@_ZALUk6U`%p?X7p{_cAf)8yG-xxm+CYfS;eFzCKZzoBh1zo6ZmWafaIKk|Isa=dZIn zwJ5cDD2Hh^+ObA7Ern*^M?)u$;Chs*U9Bx7_N-4y6tiWmZeVHWxu0hVRaD9YtC@`v zHss^xecj#Nw<2;(<`p*@_s@`{cb3D?U+anp)_&K}aQVk3BksWq7a;j8X^Etll&x>K zaUr`49%J)OSX!%?-zoRclI(%$A< zb1v2^^1zFKhhfcryU<>6h7sh9E2!q)*qbF(tPtAS7KAn==g91ATL(ubM+jmpo3UqA z#o?JPy2V&$>{q-a)I{B&Wk1R&344du!=nCwl5Jq}3sY~e*qnEE&XWDIPS>1KF-(Jz*_)Ac{7I2K_sU{l}Vrp=frYcz6mj90Iz5{q8Q83;t z!CzWPCK-}RF;z$+k$COij?Z;ZMn+EL%RZ;xNrij#5y<_nFNm4j@LAGA8bOo)CUYC5 zih@7qzN`>QWp_A>o;Hmul}dDnelU^>fW}e0C1f#tB?vW-SrEWtbqSlw1-sNGW@cuu z>7~TE6ie?jFd^@TARj>{nQkSS(#QAfX)aI^ZG?DuyyrtPyj`A@bG`GsBSz!;5H?x2 zetGY2JR9-Os=JSs!p@$aq%I5bfW6M1g#mQBt(~pxq4!M&i*;Eb*s#3DeNwcbP$^uT z=t7HceKNTh?C)s2ecN2AZf(_XhL$Ui!jAau-~XY%|6=`5wzymCiELU diff --git a/vorestation.dme b/vorestation.dme index c860cdab61e..c819522cedd 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -45,6 +45,7 @@ #include "code\__defines\flags.dm" #include "code\__defines\gamemode.dm" #include "code\__defines\holomap.dm" +#include "code\__defines\hoses.dm" #include "code\__defines\integrated_circuits.dm" #include "code\__defines\inventory_sizes.dm" #include "code\__defines\is_helpers.dm" @@ -911,6 +912,7 @@ #include "code\game\machinery\pipe\pipe_dispenser.dm" #include "code\game\machinery\pipe\pipe_recipes.dm" #include "code\game\machinery\pipe\pipelayer.dm" +#include "code\game\machinery\reagents\pump.dm" #include "code\game\machinery\telecomms\broadcaster.dm" #include "code\game\machinery\telecomms\logbrowser.dm" #include "code\game\machinery\telecomms\machine_interactions.dm" @@ -1249,6 +1251,7 @@ #include "code\game\objects\items\weapons\circuitboards\machinery\biogenerator.dm" #include "code\game\objects\items\weapons\circuitboards\machinery\cloning.dm" #include "code\game\objects\items\weapons\circuitboards\machinery\engineering.dm" +#include "code\game\objects\items\weapons\circuitboards\machinery\fluidpump.dm" #include "code\game\objects\items\weapons\circuitboards\machinery\jukebox.dm" #include "code\game\objects\items\weapons\circuitboards\machinery\kitchen_appliances.dm" #include "code\game\objects\items\weapons\circuitboards\machinery\mech_recharger.dm" @@ -3286,6 +3289,9 @@ #include "code\modules\reagents\dispenser\supply.dm" #include "code\modules\reagents\distilling\Distilling-Recipes.dm" #include "code\modules\reagents\distilling\distilling.dm" +#include "code\modules\reagents\hoses\connector.dm" +#include "code\modules\reagents\hoses\hose.dm" +#include "code\modules\reagents\hoses\hose_connector.dm" #include "code\modules\reagents\reagent_containers\blood_pack.dm" #include "code\modules\reagents\reagent_containers\blood_pack_vr.dm" #include "code\modules\reagents\reagent_containers\borghydro.dm"