mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-22 15:05:11 +00:00
* Atmos QOL + Small Sprite Fix (#74251) ## About The Pull Request Added screentips and balloon alerts to many atmos machines/pipes Volume pump overclocking overlay is much slower and less seizure inducing RPD screentips for right clicking pipes to copy settings Removed (RPD) from the RPD's name since having an abbreviation in the name is ugly Crystallizer and electrolyzer use ctrl+click and alt-click to turn on On examine electrolyzer tells you about anchoring to drain from APC instead of cell ## Why It's Good For The Game QOL for atmos stuff, user friendliness and better experience ## Changelog 🆑 fix: Volume pump overclocking animation is much slower, no more headaches qol: Added screentips to the RPD; screentips and balloon alerts to many atmos machines and devices 🆑 * Atmos QOL + Small Sprite Fix --------- Co-authored-by: 13spacemen <46101244+13spacemen@users.noreply.github.com>
745 lines
31 KiB
Plaintext
745 lines
31 KiB
Plaintext
#define ATMOS_CATEGORY 0
|
|
#define DISPOSALS_CATEGORY 1
|
|
#define TRANSIT_CATEGORY 2
|
|
|
|
#define BUILD_MODE (1<<0)
|
|
#define WRENCH_MODE (1<<1)
|
|
#define DESTROY_MODE (1<<2)
|
|
#define REPROGRAM_MODE (1<<3)
|
|
|
|
GLOBAL_LIST_INIT(atmos_pipe_recipes, list(
|
|
"Pipes" = list(
|
|
new /datum/pipe_info/pipe("Pipe", /obj/machinery/atmospherics/pipe/smart, TRUE),
|
|
new /datum/pipe_info/pipe("Layer Adapter", /obj/machinery/atmospherics/pipe/layer_manifold, TRUE),
|
|
new /datum/pipe_info/pipe("Color Adapter", /obj/machinery/atmospherics/pipe/color_adapter, TRUE),
|
|
new /datum/pipe_info/pipe("Bridge Pipe", /obj/machinery/atmospherics/pipe/bridge_pipe, TRUE),
|
|
new /datum/pipe_info/pipe("Multi-Deck Adapter", /obj/machinery/atmospherics/pipe/multiz, FALSE),
|
|
),
|
|
"Devices" = list(
|
|
new /datum/pipe_info/pipe("Connector", /obj/machinery/atmospherics/components/unary/portables_connector, TRUE),
|
|
new /datum/pipe_info/pipe("Gas Pump", /obj/machinery/atmospherics/components/binary/pump, TRUE),
|
|
new /datum/pipe_info/pipe("Volume Pump", /obj/machinery/atmospherics/components/binary/volume_pump, TRUE),
|
|
new /datum/pipe_info/pipe("Gas Filter", /obj/machinery/atmospherics/components/trinary/filter, TRUE),
|
|
new /datum/pipe_info/pipe("Gas Mixer", /obj/machinery/atmospherics/components/trinary/mixer, TRUE),
|
|
new /datum/pipe_info/pipe("Passive Gate", /obj/machinery/atmospherics/components/binary/passive_gate, TRUE),
|
|
new /datum/pipe_info/pipe("Injector", /obj/machinery/atmospherics/components/unary/outlet_injector, TRUE),
|
|
new /datum/pipe_info/pipe("Scrubber", /obj/machinery/atmospherics/components/unary/vent_scrubber, TRUE),
|
|
new /datum/pipe_info/pipe("Unary Vent", /obj/machinery/atmospherics/components/unary/vent_pump, TRUE),
|
|
new /datum/pipe_info/pipe("Passive Vent", /obj/machinery/atmospherics/components/unary/passive_vent, TRUE),
|
|
new /datum/pipe_info/pipe("Manual Valve", /obj/machinery/atmospherics/components/binary/valve, TRUE),
|
|
new /datum/pipe_info/pipe("Digital Valve", /obj/machinery/atmospherics/components/binary/valve/digital, TRUE),
|
|
new /datum/pipe_info/pipe("Pressure Valve", /obj/machinery/atmospherics/components/binary/pressure_valve, TRUE),
|
|
new /datum/pipe_info/pipe("Temperature Gate", /obj/machinery/atmospherics/components/binary/temperature_gate, TRUE),
|
|
new /datum/pipe_info/pipe("Temperature Pump", /obj/machinery/atmospherics/components/binary/temperature_pump, TRUE),
|
|
new /datum/pipe_info/meter("Meter"),
|
|
),
|
|
"Heat Exchange" = list(
|
|
new /datum/pipe_info/pipe("Pipe", /obj/machinery/atmospherics/pipe/heat_exchanging/simple, FALSE),
|
|
new /datum/pipe_info/pipe("Manifold", /obj/machinery/atmospherics/pipe/heat_exchanging/manifold, FALSE),
|
|
new /datum/pipe_info/pipe("4-Way Manifold", /obj/machinery/atmospherics/pipe/heat_exchanging/manifold4w, FALSE),
|
|
new /datum/pipe_info/pipe("Junction", /obj/machinery/atmospherics/pipe/heat_exchanging/junction, FALSE),
|
|
new /datum/pipe_info/pipe("Heat Exchanger", /obj/machinery/atmospherics/components/unary/heat_exchanger, FALSE),
|
|
),
|
|
"Air Sensors" = list(
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/plasma_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/oxygen_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/nitrogen_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/mix_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/nitrous_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/air_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/carbon_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/bz_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/freon_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/halon_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/healium_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/hydrogen_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/hypernoblium_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/miasma_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/nitrium_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/pluoxium_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/proto_nitrate_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/tritium_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/water_vapor_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/zauker_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/helium_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/antinoblium_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/incinerator_tank),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/ordnance_burn_chamber),
|
|
new /datum/pipe_info/sensor(/obj/machinery/air_sensor/ordnance_freezer_chamber),
|
|
)
|
|
))
|
|
|
|
GLOBAL_LIST_INIT(disposal_pipe_recipes, list(
|
|
"Disposal Pipes" = list(
|
|
new /datum/pipe_info/disposal("Pipe", /obj/structure/disposalpipe/segment, PIPE_BENDABLE),
|
|
new /datum/pipe_info/disposal("Junction", /obj/structure/disposalpipe/junction, PIPE_TRIN_M),
|
|
new /datum/pipe_info/disposal("Y-Junction", /obj/structure/disposalpipe/junction/yjunction),
|
|
new /datum/pipe_info/disposal("Sort Junction", /obj/structure/disposalpipe/sorting/mail, PIPE_TRIN_M),
|
|
new /datum/pipe_info/disposal("Trunk", /obj/structure/disposalpipe/trunk),
|
|
new /datum/pipe_info/disposal("Bin", /obj/machinery/disposal/bin, PIPE_ONEDIR),
|
|
new /datum/pipe_info/disposal("Outlet", /obj/structure/disposaloutlet),
|
|
new /datum/pipe_info/disposal("Chute", /obj/machinery/disposal/delivery_chute),
|
|
)
|
|
))
|
|
|
|
GLOBAL_LIST_INIT(transit_tube_recipes, list(
|
|
"Transit Tubes" = list(
|
|
new /datum/pipe_info/transit("Straight Tube", /obj/structure/c_transit_tube, PIPE_STRAIGHT),
|
|
new /datum/pipe_info/transit("Straight Tube with Crossing", /obj/structure/c_transit_tube/crossing, PIPE_STRAIGHT),
|
|
new /datum/pipe_info/transit("Curved Tube", /obj/structure/c_transit_tube/curved, PIPE_UNARY_FLIPPABLE),
|
|
new /datum/pipe_info/transit("Diagonal Tube", /obj/structure/c_transit_tube/diagonal, PIPE_STRAIGHT),
|
|
new /datum/pipe_info/transit("Diagonal Tube with Crossing", /obj/structure/c_transit_tube/diagonal/crossing, PIPE_STRAIGHT),
|
|
new /datum/pipe_info/transit("Junction", /obj/structure/c_transit_tube/junction, PIPE_UNARY_FLIPPABLE),
|
|
),
|
|
"Station Equipment" = list(
|
|
new /datum/pipe_info/transit("Through Tube Station", /obj/structure/c_transit_tube/station, PIPE_STRAIGHT),
|
|
new /datum/pipe_info/transit("Terminus Tube Station", /obj/structure/c_transit_tube/station/reverse, PIPE_UNARY),
|
|
new /datum/pipe_info/transit("Through Tube Dispenser Station", /obj/structure/c_transit_tube/station/dispenser, PIPE_STRAIGHT),
|
|
new /datum/pipe_info/transit("Terminus Tube Dispenser Station", /obj/structure/c_transit_tube/station/dispenser/reverse, PIPE_UNARY),
|
|
new /datum/pipe_info/transit("Transit Tube Pod", /obj/structure/c_transit_tube_pod, PIPE_ONEDIR),
|
|
)
|
|
))
|
|
|
|
/datum/pipe_info
|
|
var/name
|
|
var/icon_state
|
|
var/id = -1
|
|
var/dirtype = PIPE_BENDABLE
|
|
var/all_layers
|
|
|
|
/datum/pipe_info/proc/Params()
|
|
return ""
|
|
|
|
/datum/pipe_info/proc/get_preview(selected_dir)
|
|
var/list/dirs
|
|
switch(dirtype)
|
|
if(PIPE_STRAIGHT, PIPE_BENDABLE)
|
|
dirs = list("[NORTH]" = "Vertical", "[EAST]" = "Horizontal")
|
|
if(dirtype == PIPE_BENDABLE)
|
|
dirs += list("[NORTHWEST]" = "West to North", "[NORTHEAST]" = "North to East",
|
|
"[SOUTHWEST]" = "South to West", "[SOUTHEAST]" = "East to South")
|
|
if(PIPE_TRINARY)
|
|
dirs = list("[NORTH]" = "West South East", "[SOUTH]" = "East North West",
|
|
"[EAST]" = "North West South", "[WEST]" = "South East North")
|
|
if(PIPE_TRIN_M)
|
|
dirs = list("[NORTH]" = "North East South", "[SOUTHWEST]" = "North West South",
|
|
"[NORTHEAST]" = "South East North", "[SOUTH]" = "South West North",
|
|
"[WEST]" = "West North East", "[SOUTHEAST]" = "West South East",
|
|
"[NORTHWEST]" = "East North West", "[EAST]" = "East South West",)
|
|
if(PIPE_UNARY)
|
|
dirs = list("[NORTH]" = "North", "[SOUTH]" = "South", "[WEST]" = "West", "[EAST]" = "East")
|
|
if(PIPE_ONEDIR)
|
|
dirs = list("[SOUTH]" = name)
|
|
if(PIPE_UNARY_FLIPPABLE)
|
|
dirs = list("[NORTH]" = "North", "[EAST]" = "East", "[SOUTH]" = "South", "[WEST]" = "West",
|
|
"[NORTHEAST]" = "North Flipped", "[SOUTHEAST]" = "East Flipped", "[SOUTHWEST]" = "South Flipped", "[NORTHWEST]" = "West Flipped")
|
|
|
|
var/list/rows = list()
|
|
var/list/row = list("previews" = list())
|
|
var/i = 0
|
|
for(var/dir in dirs)
|
|
var/numdir = text2num(dir)
|
|
var/flipped = ((dirtype == PIPE_TRIN_M) || (dirtype == PIPE_UNARY_FLIPPABLE)) && (ISDIAGONALDIR(numdir))
|
|
row["previews"] += list(list(
|
|
"selected" = dirtype == PIPE_ONEDIR ? TRUE : (numdir == selected_dir),
|
|
"dir" = dir2text(numdir),
|
|
"dir_name" = dirs[dir],
|
|
"icon_state" = icon_state,
|
|
"flipped" = flipped,
|
|
))
|
|
if(i++ || dirtype == PIPE_ONEDIR)
|
|
rows += list(row)
|
|
row = list("previews" = list())
|
|
i = 0
|
|
|
|
return rows
|
|
|
|
/datum/pipe_info/sensor
|
|
dirtype = PIPE_ONEDIR
|
|
|
|
/datum/pipe_info/sensor/New(obj/machinery/air_sensor/sensor)
|
|
id = sensor
|
|
name = capitalize(replacetext(initial(sensor.name), "gas sensor", ""))
|
|
icon_state = "gsensor1"
|
|
|
|
/datum/pipe_info/pipe/New(label, obj/machinery/atmospherics/path, use_five_layers)
|
|
name = label
|
|
id = path
|
|
all_layers = use_five_layers
|
|
icon_state = initial(path.pipe_state)
|
|
var/obj/item/pipe/c = initial(path.construction_type)
|
|
dirtype = initial(c.RPD_type)
|
|
|
|
/datum/pipe_info/pipe/Params()
|
|
return "makepipe=[id]&type=[dirtype]"
|
|
|
|
/datum/pipe_info/meter
|
|
icon_state = "meter"
|
|
dirtype = PIPE_ONEDIR
|
|
|
|
/datum/pipe_info/meter/New(label)
|
|
name = label
|
|
|
|
/datum/pipe_info/meter/Params()
|
|
return "makemeter=[id]&type=[dirtype]"
|
|
|
|
/datum/pipe_info/disposal/New(label, obj/path, dt=PIPE_UNARY)
|
|
name = label
|
|
id = path
|
|
|
|
icon_state = initial(path.icon_state)
|
|
if(ispath(path, /obj/structure/disposalpipe))
|
|
icon_state = "con[icon_state]"
|
|
|
|
dirtype = dt
|
|
|
|
/datum/pipe_info/disposal/Params()
|
|
return "dmake=[id]&type=[dirtype]"
|
|
|
|
/datum/pipe_info/transit/New(label, obj/path, dt=PIPE_UNARY)
|
|
name = label
|
|
id = path
|
|
dirtype = dt
|
|
icon_state = initial(path.icon_state)
|
|
if(dt == PIPE_UNARY_FLIPPABLE)
|
|
icon_state = "[icon_state]_preview"
|
|
|
|
/obj/item/pipe_dispenser
|
|
name = "Rapid Pipe Dispenser"
|
|
desc = "A device used to rapidly pipe things."
|
|
icon = 'icons/obj/tools.dmi'
|
|
icon_state = "rpd"
|
|
worn_icon_state = "RPD"
|
|
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
|
|
flags_1 = CONDUCT_1
|
|
force = 10
|
|
throwforce = 10
|
|
throw_speed = 1
|
|
throw_range = 5
|
|
w_class = WEIGHT_CLASS_NORMAL
|
|
slot_flags = ITEM_SLOT_BELT
|
|
custom_materials = list(/datum/material/iron=75000, /datum/material/glass=37500)
|
|
armor_type = /datum/armor/item_pipe_dispenser
|
|
resistance_flags = FIRE_PROOF
|
|
///Sparks system used when changing device in the UI
|
|
var/datum/effect_system/spark_spread/spark_system
|
|
///Direction of the device we are going to spawn, set up in the UI
|
|
var/p_dir = NORTH
|
|
///Initial direction of the smart pipe we are going to spawn, set up in the UI
|
|
var/p_init_dir = ALL_CARDINALS
|
|
///Is the device of the flipped type?
|
|
var/p_flipped = FALSE
|
|
///Color of the device we are going to spawn
|
|
var/paint_color = "green"
|
|
///Speed of building atmos devices
|
|
var/atmos_build_speed = 0.5 SECONDS
|
|
///Speed of building disposal devices
|
|
var/disposal_build_speed = 0.5 SECONDS
|
|
///Speed of building transit devices
|
|
var/transit_build_speed = 0.5 SECONDS
|
|
///Speed of removal of unwrenched devices
|
|
var/destroy_speed = 0.5 SECONDS
|
|
///Speed of reprogramming connectable directions of smart pipes
|
|
var/reprogram_speed = 0.5 SECONDS
|
|
///Category currently active (Atmos, disposal, transit)
|
|
var/category = ATMOS_CATEGORY
|
|
///Piping layer we are going to spawn the atmos device in
|
|
var/piping_layer = PIPING_LAYER_DEFAULT
|
|
///Layer for disposal ducts
|
|
var/ducting_layer = DUCT_LAYER_DEFAULT
|
|
///Stores the current device to spawn
|
|
var/datum/pipe_info/recipe
|
|
///Stores the first atmos device
|
|
var/static/datum/pipe_info/first_atmos
|
|
///Stores the first disposal device
|
|
var/static/datum/pipe_info/first_disposal
|
|
///Stores the first transit device
|
|
var/static/datum/pipe_info/first_transit
|
|
///The modes that are allowed for the RPD
|
|
var/mode = BUILD_MODE | DESTROY_MODE | WRENCH_MODE | REPROGRAM_MODE
|
|
/// Bitflags for upgrades
|
|
var/upgrade_flags
|
|
|
|
/datum/armor/item_pipe_dispenser
|
|
fire = 100
|
|
acid = 50
|
|
|
|
/obj/item/pipe_dispenser/Initialize(mapload)
|
|
. = ..()
|
|
spark_system = new
|
|
spark_system.set_up(5, 0, src)
|
|
spark_system.attach(src)
|
|
if(!first_atmos)
|
|
first_atmos = GLOB.atmos_pipe_recipes[GLOB.atmos_pipe_recipes[1]][1]
|
|
if(!first_disposal)
|
|
first_disposal = GLOB.disposal_pipe_recipes[GLOB.disposal_pipe_recipes[1]][1]
|
|
if(!first_transit)
|
|
first_transit = GLOB.transit_tube_recipes[GLOB.transit_tube_recipes[1]][1]
|
|
|
|
recipe = first_atmos
|
|
register_item_context()
|
|
|
|
/obj/item/pipe_dispenser/Destroy()
|
|
qdel(spark_system)
|
|
spark_system = null
|
|
return ..()
|
|
|
|
/obj/item/pipe_dispenser/examine(mob/user)
|
|
. = ..()
|
|
. += "You can scroll your mouse wheel to change the piping layer."
|
|
. += "You can right click a pipe to set the RPD to its color and layer."
|
|
|
|
/obj/item/pipe_dispenser/equipped(mob/user, slot, initial)
|
|
. = ..()
|
|
if(slot & ITEM_SLOT_HANDS)
|
|
RegisterSignal(user, COMSIG_MOUSE_SCROLL_ON, PROC_REF(mouse_wheeled))
|
|
else
|
|
UnregisterSignal(user,COMSIG_MOUSE_SCROLL_ON)
|
|
|
|
/obj/item/pipe_dispenser/dropped(mob/user, silent)
|
|
UnregisterSignal(user, COMSIG_MOUSE_SCROLL_ON)
|
|
return ..()
|
|
|
|
/obj/item/pipe_dispenser/cyborg_unequip(mob/user)
|
|
UnregisterSignal(user, COMSIG_MOUSE_SCROLL_ON)
|
|
return ..()
|
|
|
|
/obj/item/pipe_dispenser/attack_self(mob/user)
|
|
ui_interact(user)
|
|
|
|
/obj/item/pipe_dispenser/pre_attack(atom/target, mob/user, params)
|
|
if(istype(target, /obj/item/rpd_upgrade/unwrench))
|
|
install_upgrade(target, user)
|
|
return TRUE
|
|
return ..()
|
|
|
|
/obj/item/pipe_dispenser/pre_attack_secondary(obj/machinery/atmospherics/target, mob/user, params)
|
|
if(istype(target, /obj/machinery/air_sensor))
|
|
if(!do_after(user, destroy_speed, target))
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
qdel(target)
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
if(!istype(target, /obj/machinery/atmospherics))
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
if(target.pipe_color && target.piping_layer)
|
|
paint_color = GLOB.pipe_color_name[target.pipe_color]
|
|
piping_layer = target.piping_layer
|
|
to_chat(user, span_notice("You change [src] to [paint_color] color and layer [piping_layer] pipes."))
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
/obj/item/pipe_dispenser/attackby(obj/item/W, mob/user, params)
|
|
if(istype(W, /obj/item/rpd_upgrade))
|
|
install_upgrade(W, user)
|
|
return TRUE
|
|
return ..()
|
|
|
|
/obj/item/pipe_dispenser/add_item_context(obj/item/source, list/context, atom/target, mob/living/user)
|
|
. = ..()
|
|
if(istype(target, /obj/machinery/atmospherics))
|
|
var/obj/machinery/atmospherics/atmos_target = target
|
|
if(atmos_target.pipe_color && atmos_target.piping_layer)
|
|
context[SCREENTIP_CONTEXT_RMB] = "Copy piping color and layer"
|
|
return CONTEXTUAL_SCREENTIP_SET
|
|
|
|
/**
|
|
* Installs an upgrade into the RPD
|
|
*
|
|
* Installs an upgrade into the RPD checking if it is already installed
|
|
* Arguments:
|
|
* * rpd_up - RPD upgrade
|
|
* * user - mob that use upgrade on RPD
|
|
*/
|
|
/obj/item/pipe_dispenser/proc/install_upgrade(obj/item/rpd_upgrade/rpd_up, mob/user)
|
|
if(rpd_up.upgrade_flags& upgrade_flags)
|
|
to_chat(user, span_warning("[src] has already installed this upgrade!"))
|
|
return
|
|
upgrade_flags |= rpd_up.upgrade_flags
|
|
playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
|
|
qdel(rpd_up)
|
|
|
|
/obj/item/pipe_dispenser/suicide_act(mob/living/user)
|
|
user.visible_message(span_suicide("[user] points the end of the RPD down [user.p_their()] throat and presses a button! It looks like [user.p_theyre()] trying to commit suicide..."))
|
|
playsound(get_turf(user), 'sound/machines/click.ogg', 50, TRUE)
|
|
playsound(get_turf(user), 'sound/items/deconstruct.ogg', 50, TRUE)
|
|
return BRUTELOSS
|
|
|
|
/obj/item/pipe_dispenser/ui_assets(mob/user)
|
|
return list(
|
|
get_asset_datum(/datum/asset/spritesheet/pipes),
|
|
)
|
|
|
|
/obj/item/pipe_dispenser/ui_interact(mob/user, datum/tgui/ui)
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "RapidPipeDispenser", name)
|
|
ui.open()
|
|
|
|
/obj/item/pipe_dispenser/ui_static_data(mob/user)
|
|
var/list/data = list("paint_colors" = GLOB.pipe_paint_colors)
|
|
return data
|
|
|
|
/obj/item/pipe_dispenser/ui_data(mob/user)
|
|
var/list/data = list(
|
|
"category" = category,
|
|
"piping_layer" = piping_layer,
|
|
"ducting_layer" = ducting_layer,
|
|
"preview_rows" = recipe.get_preview(p_dir),
|
|
"categories" = list(),
|
|
"selected_recipe" = recipe.name,
|
|
"selected_color" = paint_color,
|
|
"mode" = mode,
|
|
)
|
|
|
|
var/list/recipes
|
|
switch(category)
|
|
if(ATMOS_CATEGORY)
|
|
recipes = GLOB.atmos_pipe_recipes
|
|
if(DISPOSALS_CATEGORY)
|
|
recipes = GLOB.disposal_pipe_recipes
|
|
if(TRANSIT_CATEGORY)
|
|
recipes = GLOB.transit_tube_recipes
|
|
for(var/c in recipes)
|
|
var/list/cat = recipes[c]
|
|
var/list/r = list()
|
|
for(var/i in 1 to cat.len)
|
|
var/datum/pipe_info/info = cat[i]
|
|
|
|
//skip sensors which are already in the world so we dont create duplicate ones
|
|
if(info.type == /datum/pipe_info/sensor)
|
|
var/datum/pipe_info/sensor/sensor_info = info
|
|
var/obj/machinery/air_sensor/sensor = sensor_info.id
|
|
if(GLOB.objects_by_id_tag[CHAMBER_SENSOR_FROM_ID(initial(sensor.chamber_id))] != null)
|
|
continue
|
|
|
|
r += list(list("pipe_name" = info.name, "pipe_index" = i))
|
|
if(info == recipe)
|
|
data["selected_category"] = c
|
|
if(r.len == 0) //when all air sensors are installed this list will become empty
|
|
continue
|
|
data["categories"] += list(list("cat_name" = c, "recipes" = r))
|
|
|
|
var/list/init_directions = list("north" = FALSE, "south" = FALSE, "east" = FALSE, "west" = FALSE)
|
|
for(var/direction in GLOB.cardinals)
|
|
if(p_init_dir & direction)
|
|
init_directions[dir2text(direction)] = TRUE
|
|
data["init_directions"] = init_directions
|
|
return data
|
|
|
|
/obj/item/pipe_dispenser/ui_act(action, params)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
|
|
var/playeffect = TRUE
|
|
switch(action)
|
|
if("color")
|
|
paint_color = params["paint_color"]
|
|
if("category")
|
|
category = text2num(params["category"])
|
|
switch(category)
|
|
if(DISPOSALS_CATEGORY)
|
|
recipe = first_disposal
|
|
if(ATMOS_CATEGORY)
|
|
recipe = first_atmos
|
|
if(TRANSIT_CATEGORY)
|
|
recipe = first_transit
|
|
p_dir = NORTH
|
|
playeffect = FALSE
|
|
if("piping_layer")
|
|
piping_layer = text2num(params["piping_layer"])
|
|
playeffect = FALSE
|
|
if("ducting_layer")
|
|
ducting_layer = text2num(params["ducting_layer"])
|
|
playeffect = FALSE
|
|
if("pipe_type")
|
|
var/static/list/recipes
|
|
if(!recipes)
|
|
recipes = GLOB.disposal_pipe_recipes + GLOB.atmos_pipe_recipes + GLOB.transit_tube_recipes
|
|
recipe = recipes[params["category"]][text2num(params["pipe_type"])]
|
|
p_dir = NORTH
|
|
if("setdir")
|
|
p_dir = text2dir(params["dir"])
|
|
p_flipped = text2num(params["flipped"])
|
|
playeffect = FALSE
|
|
if("mode")
|
|
var/n = text2num(params["mode"])
|
|
mode ^= n
|
|
if("init_dir_setting")
|
|
var/target_dir = p_init_dir ^ text2dir(params["dir_flag"])
|
|
// Refuse to create a smart pipe that can only connect in one direction (it would act weirdly and lack an icon)
|
|
if (ISNOTSTUB(target_dir))
|
|
p_init_dir = target_dir
|
|
else
|
|
to_chat(usr, span_warning("\The [src]'s screen flashes a warning: Can't configure a pipe to only connect in one direction."))
|
|
playeffect = FALSE
|
|
if("init_reset")
|
|
p_init_dir = ALL_CARDINALS
|
|
if(playeffect)
|
|
spark_system.start()
|
|
playsound(get_turf(src), 'sound/effects/pop.ogg', 50, FALSE)
|
|
return TRUE
|
|
|
|
/obj/item/pipe_dispenser/pre_attack(atom/A, mob/user)
|
|
if(!ISADVANCEDTOOLUSER(user) || istype(A, /turf/open/space/transit))
|
|
return ..()
|
|
|
|
var/atom/attack_target = A
|
|
|
|
//So that changing the menu settings doesn't affect the pipes already being built.
|
|
var/queued_p_type = recipe.id
|
|
var/queued_p_dir = p_dir
|
|
var/queued_p_flipped = p_flipped
|
|
|
|
//Unwrench pipe before we build one over/paint it, but only if we're not already running a do_after on it already to prevent a potential runtime.
|
|
if((mode & DESTROY_MODE) && (upgrade_flags & RPD_UPGRADE_UNWRENCH) && istype(attack_target, /obj/machinery/atmospherics) && !(DOING_INTERACTION_WITH_TARGET(user, attack_target)))
|
|
attack_target = attack_target.wrench_act(user, src)
|
|
if(!isatom(attack_target))
|
|
CRASH("When attempting to call [A.type].wrench_act(), received the following non-atom return value: [attack_target]")
|
|
|
|
//make sure what we're clicking is valid for the current category
|
|
var/static/list/make_pipe_whitelist
|
|
if(!make_pipe_whitelist)
|
|
make_pipe_whitelist = typecacheof(list(/obj/structure/lattice, /obj/structure/girder, /obj/item/pipe, /obj/structure/window, /obj/structure/grille))
|
|
if(istype(attack_target, /obj/machinery/atmospherics) && mode & BUILD_MODE)
|
|
attack_target = get_turf(attack_target)
|
|
var/can_make_pipe = (isturf(attack_target) || is_type_in_typecache(attack_target, make_pipe_whitelist))
|
|
|
|
. = TRUE
|
|
|
|
if((mode & DESTROY_MODE) && istype(attack_target, /obj/item/pipe) || istype(attack_target, /obj/structure/disposalconstruct) || istype(attack_target, /obj/structure/c_transit_tube) || istype(attack_target, /obj/structure/c_transit_tube_pod) || istype(attack_target, /obj/item/pipe_meter) || istype(attack_target, /obj/structure/disposalpipe/broken))
|
|
to_chat(user, span_notice("You start destroying a pipe..."))
|
|
playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE)
|
|
if(do_after(user, destroy_speed, target = attack_target))
|
|
activate()
|
|
qdel(attack_target)
|
|
return
|
|
|
|
if(mode & REPROGRAM_MODE)
|
|
// If this is a placed smart pipe, try to reprogram it
|
|
var/obj/machinery/atmospherics/pipe/smart/S = attack_target
|
|
if(istype(S))
|
|
if (S.dir == ALL_CARDINALS)
|
|
to_chat(user, span_warning("\The [S] has no unconnected directions!"))
|
|
return
|
|
var/old_init_dir = S.get_init_directions()
|
|
if (old_init_dir == p_init_dir)
|
|
to_chat(user, span_warning("\The [S] is already in this configuration!"))
|
|
return
|
|
// Check for differences in unconnected directions
|
|
var/target_differences = (p_init_dir ^ old_init_dir) & ~S.connections
|
|
if (!target_differences)
|
|
to_chat(user, span_warning("\The [S] is already in this configuration for its unconnected directions!"))
|
|
return
|
|
|
|
to_chat(user, span_notice("You start reprogramming \the [S]..."))
|
|
playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE)
|
|
if(!do_after(user, reprogram_speed, target = S))
|
|
return
|
|
|
|
// Something else could have changed the target's state while we were waiting in do_after
|
|
// Most of the edge cases don't matter, but atmos components being able to have live connections not described by initializable directions sounds like a headache at best and an exploit at worst
|
|
|
|
// Double check to make sure that nothing has changed. If anything we were about to change was connected during do_after, abort
|
|
if (target_differences & S.connections)
|
|
to_chat(user, span_warning("\The [src]'s screen flashes a warning: Can't configure a pipe in a currently connected direction."))
|
|
return
|
|
// Grab the current initializable directions, which may differ from old_init_dir if someone else was working on the same pipe at the same time
|
|
var/current_init_dir = S.get_init_directions()
|
|
// Access p_init_dir directly. The RPD can change target layer and initializable directions (though not pipe type or dir) while working to dispense and connect a component,
|
|
// and have it reflected in the final result. Reprogramming should be similarly consistent.
|
|
var/new_init_dir = (current_init_dir & ~target_differences) | (p_init_dir & target_differences)
|
|
// Don't make a smart pipe with only one connection
|
|
if (ISSTUB(new_init_dir))
|
|
to_chat(user, span_warning("\The [src]'s screen flashes a warning: Can't configure a pipe to only connect in one direction."))
|
|
return
|
|
S.set_init_directions(new_init_dir)
|
|
// We're now reconfigured.
|
|
// We can never disconnect from existing connections, but we can connect to previously unconnected directions, and should immediately do so
|
|
var/newly_permitted_connections = new_init_dir & ~current_init_dir
|
|
if(newly_permitted_connections)
|
|
// We're allowed to connect in new directions. Recompute our nodes
|
|
// Disconnect from everything that is currently connected
|
|
for (var/i in 1 to S.device_type)
|
|
// This is basically pipe.nullifyNode, but using it here would create a pitfall for others attempting to
|
|
// copy and paste disconnection code for other components. Welcome to the atmospherics subsystem
|
|
var/obj/machinery/atmospherics/node = S.nodes[i]
|
|
if (!node)
|
|
continue
|
|
node.disconnect(S)
|
|
S.nodes[i] = null
|
|
// Get our new connections
|
|
S.atmos_init()
|
|
// Connect to our new connections
|
|
for (var/obj/machinery/atmospherics/O in S.nodes)
|
|
O.atmos_init()
|
|
O.add_member(src)
|
|
SSair.add_to_rebuild_queue(S)
|
|
// Finally, update our internal state - update_pipe_icon also updates dir and connections
|
|
S.update_pipe_icon()
|
|
user.visible_message(span_notice("[user] reprograms the \the [S]."),span_notice("You reprogram \the [S]."))
|
|
return
|
|
// If this is an unplaced smart pipe, try to reprogram it
|
|
var/obj/item/pipe/quaternary/I = attack_target
|
|
if(istype(I) && ispath(I.pipe_type, /obj/machinery/atmospherics/pipe/smart))
|
|
// An unplaced pipe never has any existing connections, so just directly assign the new configuration
|
|
I.p_init_dir = p_init_dir
|
|
I.update()
|
|
|
|
if(mode & BUILD_MODE)
|
|
switch(category) //if we've gotten this var, the target is valid
|
|
if(ATMOS_CATEGORY) //Making pipes
|
|
if(!can_make_pipe)
|
|
return ..()
|
|
playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE)
|
|
if (recipe.type == /datum/pipe_info/meter)
|
|
to_chat(user, span_notice("You start building a meter..."))
|
|
if(do_after(user, atmos_build_speed, target = attack_target))
|
|
activate()
|
|
var/obj/item/pipe_meter/PM = new /obj/item/pipe_meter(get_turf(attack_target))
|
|
PM.setAttachLayer(piping_layer)
|
|
if(mode & WRENCH_MODE)
|
|
PM.wrench_act(user, src)
|
|
else if(recipe.type == /datum/pipe_info/sensor)
|
|
balloon_alert(user, "building air sensor...")
|
|
if(do_after(user, atmos_build_speed, target = attack_target))
|
|
activate()
|
|
var/datum/pipe_info/sensor/sensor_recipe = recipe
|
|
var/obj/machinery/air_sensor/sensor_blueprint = sensor_recipe.id
|
|
new sensor_blueprint(get_turf(attack_target))
|
|
//change the recipe as the current one becomes unavailable
|
|
recipe = first_atmos
|
|
else
|
|
if(recipe.all_layers == FALSE && (piping_layer == 1 || piping_layer == 5))
|
|
to_chat(user, span_notice("You can't build this object on the layer..."))
|
|
return ..()
|
|
to_chat(user, span_notice("You start building a pipe..."))
|
|
if(do_after(user, atmos_build_speed, target = attack_target))
|
|
if(recipe.all_layers == FALSE && (piping_layer == 1 || piping_layer == 5))//double check to stop cheaters (and to not waste time waiting for something that can't be placed)
|
|
to_chat(user, span_notice("You can't build this object on the layer..."))
|
|
return ..()
|
|
activate()
|
|
var/obj/machinery/atmospherics/path = queued_p_type
|
|
var/pipe_item_type = initial(path.construction_type) || /obj/item/pipe
|
|
var/obj/item/pipe/pipe_type = new pipe_item_type(
|
|
get_turf(attack_target),
|
|
queued_p_type,
|
|
queued_p_dir,
|
|
null,
|
|
GLOB.pipe_paint_colors[paint_color],
|
|
ispath(queued_p_type, /obj/machinery/atmospherics/pipe/smart) ? p_init_dir : null,
|
|
)
|
|
if(queued_p_flipped && istype(pipe_type, /obj/item/pipe/trinary/flippable))
|
|
var/obj/item/pipe/trinary/flippable/F = pipe_type
|
|
F.flipped = queued_p_flipped
|
|
|
|
pipe_type.update()
|
|
pipe_type.add_fingerprint(usr)
|
|
pipe_type.set_piping_layer(piping_layer)
|
|
if(ispath(queued_p_type, /obj/machinery/atmospherics) && !ispath(queued_p_type, /obj/machinery/atmospherics/pipe/color_adapter))
|
|
pipe_type.add_atom_colour(GLOB.pipe_paint_colors[paint_color], FIXED_COLOUR_PRIORITY)
|
|
if(mode & WRENCH_MODE)
|
|
pipe_type.wrench_act(user, src)
|
|
|
|
if(DISPOSALS_CATEGORY) //Making disposals pipes
|
|
if(!can_make_pipe)
|
|
return ..()
|
|
attack_target = get_turf(attack_target)
|
|
if(isclosedturf(attack_target))
|
|
to_chat(user, span_warning("[src]'s error light flickers; there's something in the way!"))
|
|
return
|
|
to_chat(user, span_notice("You start building a disposals pipe..."))
|
|
playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE)
|
|
if(do_after(user, disposal_build_speed, target = attack_target))
|
|
var/obj/structure/disposalconstruct/C = new (attack_target, queued_p_type, queued_p_dir, queued_p_flipped)
|
|
|
|
if(!C.can_place())
|
|
to_chat(user, span_warning("There's not enough room to build that here!"))
|
|
qdel(C)
|
|
return
|
|
|
|
activate()
|
|
|
|
C.add_fingerprint(usr)
|
|
C.update_appearance()
|
|
if(mode & WRENCH_MODE)
|
|
C.wrench_act(user, src)
|
|
return
|
|
|
|
if(TRANSIT_CATEGORY) //Making transit tubes
|
|
if(!can_make_pipe)
|
|
return ..()
|
|
attack_target = get_turf(attack_target)
|
|
if(isclosedturf(attack_target))
|
|
to_chat(user, span_warning("[src]'s error light flickers; there's something in the way!"))
|
|
return
|
|
|
|
var/turf/target_turf = get_turf(attack_target)
|
|
if(target_turf.is_blocked_turf(exclude_mobs = TRUE))
|
|
to_chat(user, span_warning("[src]'s error light flickers; there's something in the way!"))
|
|
return
|
|
|
|
to_chat(user, span_notice("You start building a transit tube..."))
|
|
playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE)
|
|
if(do_after(user, transit_build_speed, target = attack_target))
|
|
activate()
|
|
if(queued_p_type == /obj/structure/c_transit_tube_pod)
|
|
var/obj/structure/c_transit_tube_pod/pod = new /obj/structure/c_transit_tube_pod(attack_target)
|
|
pod.add_fingerprint(usr)
|
|
if(mode & WRENCH_MODE)
|
|
pod.wrench_act(user, src)
|
|
|
|
else
|
|
var/obj/structure/c_transit_tube/tube = new queued_p_type(attack_target)
|
|
tube.setDir(queued_p_dir)
|
|
|
|
if(queued_p_flipped)
|
|
tube.setDir(turn(queued_p_dir, 45 + ROTATION_FLIP))
|
|
tube.AfterRotation(user, ROTATION_FLIP)
|
|
|
|
tube.add_fingerprint(usr)
|
|
if(mode & WRENCH_MODE)
|
|
tube.wrench_act(user, src)
|
|
return
|
|
else
|
|
return ..()
|
|
|
|
/obj/item/pipe_dispenser/proc/activate()
|
|
playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, TRUE)
|
|
|
|
/obj/item/pipe_dispenser/proc/mouse_wheeled(mob/source, atom/A, delta_x, delta_y, params)
|
|
SIGNAL_HANDLER
|
|
if(source.incapacitated(IGNORE_RESTRAINTS|IGNORE_STASIS))
|
|
return
|
|
|
|
if(delta_y < 0)
|
|
piping_layer = min(PIPING_LAYER_MAX, piping_layer + 1)
|
|
else if(delta_y > 0)
|
|
piping_layer = max(PIPING_LAYER_MIN, piping_layer - 1)
|
|
else
|
|
return
|
|
SStgui.update_uis(src)
|
|
to_chat(source, span_notice("You set the layer to [piping_layer]."))
|
|
|
|
#undef ATMOS_CATEGORY
|
|
#undef DISPOSALS_CATEGORY
|
|
#undef TRANSIT_CATEGORY
|
|
|
|
#undef BUILD_MODE
|
|
#undef DESTROY_MODE
|
|
#undef WRENCH_MODE
|
|
#undef REPROGRAM_MODE
|
|
|
|
/obj/item/rpd_upgrade
|
|
name = "RPD advanced design disk"
|
|
desc = "It seems to be empty."
|
|
icon = 'icons/obj/module.dmi'
|
|
icon_state = "datadisk3"
|
|
/// Bitflags for upgrades
|
|
var/upgrade_flags
|
|
|
|
/obj/item/rpd_upgrade/unwrench
|
|
desc = "Adds reverse wrench mode to the RPD. Attention, due to budget cuts, the mode is hard linked to the destroy mode control button."
|
|
upgrade_flags = RPD_UPGRADE_UNWRENCH
|