Skip to content

Commit

Permalink
[MIRROR] Add smooth transition between hidden and visible pipes (#1293)…
Browse files Browse the repository at this point in the history
… (#2304)

* Add smooth transition between hidden and visible pipes (#81800)

## About The Pull Request

- Adds smooth transition between hidden and visible pipes, AKA “caps”
and updates automated pipe icon generator to account mentioned changes.
- Adds centering to missed atmos machinery, for example, unary vent is
almost identical to passive, but the second one wasn't centered while
hidden.
- Fixes visual bug with extra and unremovable by normal means pixel
offset on pipes constructed from `/obj/item/pipe`.
- Fixes visual bug with visible cap on a hidden connector. 

I'm really sorry for this mess, but one-line fixes are okay, or are
they?

## Why It's Good For The Game

We're playing atmospherics simulator and pipes play an essential role in
our rounds, people see them all the time and that's why pipes deserve to
look a bit better. This project aims to resolve said issue by adding
transition states, in current implementation they're just cut off when
connected to a hidden segment.

<details>
<summary>Screenshots</summary>

Before:

![dreamseeker_N9kXd8k5a9](https://github.com/tgstation/tgstation/assets/137328283/1e9915fc-53e6-4411-baa8-22ed67c0708e)

After:

![dreamseeker_qxQepWXHwh](https://github.com/tgstation/tgstation/assets/137328283/72778646-46f5-4ebf-9988-10a87ead9768)

Extra:

![dreamseeker_Lz0a55VoCE](https://github.com/tgstation/tgstation/assets/137328283/2b198ba9-74b1-4e54-901e-a72ab3af0a6a)


</details>

## Changelog

:cl:
fix: Pipe connector no longer appears on a hidden connector.
fix: Re-wrenched atmospherics pipes no longer get extra offset.
fix: All unary devices like injectors, passive vents etc. are centered
while hidden.
image: Added smooth transition between hidden and visible pipes.
/:cl:

---------



* Add smooth transition between hidden and visible pipes

---------

Co-authored-by: NovaBot <[email protected]>
Co-authored-by: Interception&? <[email protected]>
Co-authored-by: san7890 <[email protected]>
  • Loading branch information
4 people authored Mar 8, 2024
1 parent 4aee11c commit 340a736
Show file tree
Hide file tree
Showing 15 changed files with 133 additions and 22 deletions.
4 changes: 3 additions & 1 deletion code/__DEFINES/atmospherics/atmos_piping.dm
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
#define EAST_SHORTPIPE (1<<6)
#define WEST_SHORTPIPE (1<<7)
// Helpers to convert cardinals to and from pipe bitfields
// Assumes X_FULLPIPE = X, X_SHORTPIPE >> 4 = X as above
// Assumes X_FULLPIPE = X, X_SHORTPIPE >> 4 = X, X_PIPECAPS >> 8 = X as above
#define FULLPIPE_TO_CARDINALS(bitfield) ((bitfield) & ALL_CARDINALS)
#define SHORTPIPE_TO_CARDINALS(bitfield) (((bitfield) >> 4) & ALL_CARDINALS)
#define PIPECAPS_TO_CARDINALS(bitfield) (((bitfield) >> 8) & ALL_CARDINALS)
#define CARDINAL_TO_FULLPIPES(cardinals) (cardinals)
#define CARDINAL_TO_SHORTPIPES(cardinals) ((cardinals) << 4)
#define CARDINAL_TO_PIPECAPS(cardinals) ((cardinals) << 8)
// A pipe is a stub if it only has zero or one permitted direction. For a regular pipe this is nonsensical, and there are no pipe sprites for this, so it is not allowed.
#define ISSTUB(bits) !((bits) & ((bits) - 1))
#define ISNOTSTUB(bits) ((bits) & ((bits) - 1))
Expand Down
5 changes: 1 addition & 4 deletions code/game/machinery/pipe/construction.dm
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ Buildable meters
return TRUE
// no conflicts found

var/obj/machinery/atmospherics/built_machine = new pipe_type(loc, , , p_init_dir)
var/obj/machinery/atmospherics/built_machine = new pipe_type(loc, null, fixed_dir(), p_init_dir)
build_pipe(built_machine)
built_machine.on_construction(user, pipe_color, piping_layer)
transfer_fingerprints_to(built_machine)
Expand Down Expand Up @@ -356,9 +356,6 @@ Buildable meters
return FALSE

/obj/item/pipe/proc/build_pipe(obj/machinery/atmospherics/A)
A.setDir(fixed_dir())
A.set_init_directions(p_init_dir)

if(pipename)
A.name = pipename
if(A.on)
Expand Down
71 changes: 67 additions & 4 deletions code/modules/atmospherics/machinery/atmosmachinery.dm
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@

///Whether it can be painted
var/paintable = TRUE
///Whether it will generate cap sprites when hidden
var/has_cap_visuals = FALSE
///Cap overlay that is being added to turf's `vis_contents`, `null` if pipe was never hidden or has no valid connections
var/obj/effect/overlay/cap_visual/cap_overlay

///Is the thing being rebuilt by SSair or not. Prevents list bloat
var/rebuilding = FALSE
Expand Down Expand Up @@ -106,6 +110,10 @@
if(isturf(loc))
turf_loc = loc
turf_loc.add_blueprints_preround(src)

if(hide)
RegisterSignal(src, COMSIG_OBJ_HIDE, PROC_REF(on_hide))

SSspatial_grid.add_grid_awareness(src, SPATIAL_GRID_CONTENTS_TYPE_ATMOS)
SSspatial_grid.add_grid_membership(src, turf_loc, SPATIAL_GRID_CONTENTS_TYPE_ATMOS)
if(init_processing)
Expand All @@ -119,11 +127,22 @@
SSair.stop_processing_machine(src)
SSair.rebuild_queue -= src

if(pipe_vision_img)
qdel(pipe_vision_img)
QDEL_NULL(pipe_vision_img)
QDEL_NULL(cap_overlay)

return ..()
//return QDEL_HINT_FINDREFERENCE

/**
* Handler for `COMSIG_OBJ_HIDE`, connects only if `hide` is set to `TRUE`. Calls `update_cap_visuals` on pipe and its connected nodes
*/
/obj/machinery/atmospherics/proc/on_hide(datum/source, underfloor_accessibility)
SHOULD_CALL_PARENT(TRUE)
SIGNAL_HANDLER

for(var/obj/machinery/atmospherics/node in nodes)
node.update_cap_visuals()

update_cap_visuals()

/**
* Run when you update the conditions in which an /atom might want to start reacting to its turf's air
Expand Down Expand Up @@ -205,8 +224,9 @@
update_appearance()

/obj/machinery/atmospherics/update_icon()
. = ..()
update_layer()
update_cap_visuals()
return ..()

/**
* Find a connecting /obj/machinery/atmospherics in specified direction, called by relaymove()
Expand Down Expand Up @@ -616,6 +636,49 @@
/obj/machinery/atmospherics/proc/update_layer()
return

/**
* Handles cap overlay addition and removal, won't do anything if `has_cap_visuals` is set to `FALSE`
*/
/obj/machinery/atmospherics/proc/update_cap_visuals()
if(!has_cap_visuals)
return

var/turf/our_turf = get_turf(src)
our_turf.vis_contents -= cap_overlay

var/connections = NONE
for(var/obj/machinery/atmospherics/node in nodes)
if(HAS_TRAIT(node, TRAIT_UNDERFLOOR))
continue

if(isplatingturf(get_turf(node)))
continue

var/connected_dir = get_dir(src, node)
connections |= connected_dir

if(connections == NONE)
return

var/bitfield = CARDINAL_TO_PIPECAPS(connections)
bitfield |= ((~connections) & ALL_CARDINALS)

if(isnull(cap_overlay))
cap_overlay = new

SET_PLANE_EXPLICIT(cap_overlay, initial(plane), our_turf)

cap_overlay.color = pipe_color
cap_overlay.layer = layer
cap_overlay.icon_state = "[bitfield]_[piping_layer]"

our_turf.vis_contents += cap_overlay

/obj/effect/overlay/cap_visual
appearance_flags = KEEP_APART
vis_flags = VIS_INHERIT_ID
icon = 'icons/obj/pipes_n_cables/!pipes_bitmask.dmi'

/**
* Called by the RPD.dm pre_attack()
* Arguments:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,6 @@
component_mixture.volume = 200
airs[i] = component_mixture

/obj/machinery/atmospherics/components/Initialize(mapload)
. = ..()

if(hide)
RegisterSignal(src, COMSIG_OBJ_HIDE, PROC_REF(hide_pipe))

// Iconnery

/**
Expand All @@ -46,11 +40,14 @@
/obj/machinery/atmospherics/components/proc/update_icon_nopipes()
return

/obj/machinery/atmospherics/components/on_hide(datum/source, underfloor_accessibility)
hide_pipe(underfloor_accessibility)
return ..()

/**
* Called in Initialize(), set the showpipe var to true or false depending on the situation, calls update_icon()
* Called in on_hide(), set the showpipe var to true or false depending on the situation, calls update_icon()
*/
/obj/machinery/atmospherics/components/proc/hide_pipe(datum/source, underfloor_accessibility)
SIGNAL_HANDLER
/obj/machinery/atmospherics/components/proc/hide_pipe(underfloor_accessibility)
showpipe = !!underfloor_accessibility
if(showpipe)
REMOVE_TRAIT(src, TRAIT_UNDERFLOOR, REF(src))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
hide = TRUE
layer = GAS_SCRUBBER_LAYER
pipe_state = "injector"
has_cap_visuals = TRUE
resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF //really helpful in building gas chambers for xenomorphs

idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 0.25
Expand Down Expand Up @@ -74,6 +75,8 @@
if(showpipe)
// everything is already shifted so don't shift the cap
add_overlay(get_pipe_image(icon, "inje_cap", initialize_directions, pipe_color))
else
PIPING_LAYER_SHIFT(src, PIPING_LAYER_DEFAULT)

if(!nodes[1] || !on || !is_operational)
icon_state = "inje_off"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@
shift_underlay_only = FALSE

pipe_state = "pvent"
has_cap_visuals = TRUE
vent_movement = VENTCRAWL_ALLOWED | VENTCRAWL_CAN_SEE | VENTCRAWL_ENTRANCE_ALLOWED

/obj/machinery/atmospherics/components/unary/passive_vent/update_icon_nopipes()
cut_overlays()
if(showpipe)
var/image/cap = get_pipe_image(icon, "vent_cap", initialize_directions, pipe_color)
add_overlay(cap)
else
PIPING_LAYER_SHIFT(src, PIPING_LAYER_DEFAULT)
icon_state = "passive_vent"

/obj/machinery/atmospherics/components/unary/passive_vent/process_atmos()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

pipe_flags = PIPING_ONE_PER_TURF
pipe_state = "connector"
has_cap_visuals = TRUE

custom_reconcilation = TRUE

///Reference to the connected device
Expand All @@ -29,11 +31,13 @@
return ..()

/obj/machinery/atmospherics/components/unary/portables_connector/update_icon_nopipes()
icon_state = "connector"
cut_overlays()
if(showpipe)
cut_overlays()
var/image/cap = get_pipe_image(icon, "connector_cap", initialize_directions, pipe_color)
add_overlay(cap)
else
PIPING_LAYER_SHIFT(src, PIPING_LAYER_DEFAULT)
icon_state = "connector"

/obj/machinery/atmospherics/components/unary/portables_connector/process_atmos()
if(!connected_device)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
layer = OBJ_LAYER
circuit = /obj/item/circuitboard/machine/thermomachine

hide = TRUE

move_resist = MOVE_RESIST_DEFAULT
vent_movement = NONE
pipe_flags = PIPING_ONE_PER_TURF
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
hide = TRUE
shift_underlay_only = FALSE
pipe_state = "uvent"
has_cap_visuals = TRUE
vent_movement = VENTCRAWL_ALLOWED | VENTCRAWL_CAN_SEE | VENTCRAWL_ENTRANCE_ALLOWED
// vents are more complex machinery and so are less resistant to damage
max_integrity = 100
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
hide = TRUE
shift_underlay_only = FALSE
pipe_state = "scrubber"
has_cap_visuals = TRUE
vent_movement = VENTCRAWL_ALLOWED | VENTCRAWL_CAN_SEE | VENTCRAWL_ENTRANCE_ALLOWED
processing_flags = NONE

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@
"[WEST]"=icon('icons/obj/pipes_n_cables/pipe_template_pieces.dmi', "damage_mask", WEST),
)

var/static/list/icon/cap_masks = list(
"[NORTH]" = icon('icons/obj/pipes_n_cables/pipe_template_pieces.dmi', "cap_mask", NORTH),
"[EAST]" = icon('icons/obj/pipes_n_cables/pipe_template_pieces.dmi', "cap_mask", EAST),
"[SOUTH]" = icon('icons/obj/pipes_n_cables/pipe_template_pieces.dmi', "cap_mask", SOUTH),
"[WEST]" = icon('icons/obj/pipes_n_cables/pipe_template_pieces.dmi', "cap_mask", WEST),
)

var/icon/generated_icons

/datum/pipe_icon_generator/proc/Start(icon_state_suffix="")
Expand Down Expand Up @@ -85,6 +92,34 @@
outputs[damaged] = "[icon_state_dirs]_[layer]"
return outputs

/datum/pipe_icon_generator/proc/generate_capped(icon/working, layer, dirs, x_offset=1, y_offset=1)
var/list/outputs = list()
var/list/completed = list()
for(var/combined_dirs in 1 to 15)
combined_dirs &= dirs

var/completion_key = "[combined_dirs]"
if(completed[completion_key] || (combined_dirs == NONE))
continue

completed[completion_key] = TRUE

var/icon/capped_mask = icon('icons/obj/pipes_n_cables/pipe_template_pieces.dmi', "blank_mask")
for(var/i in 0 to 3)
var/dir = 1 << i
if(!(combined_dirs & dir))
continue

var/icon/cap_mask = cap_masks["[dir]"]
capped_mask.Blend(cap_mask, ICON_OVERLAY, x_offset, y_offset)

var/icon/capped = icon(working)
capped.Blend(capped_mask, ICON_MULTIPLY)

var/icon_state_dirs = (dirs & ~combined_dirs) | CARDINAL_TO_PIPECAPS(combined_dirs)
outputs[capped] = "[icon_state_dirs]_[layer]"

return outputs

/datum/pipe_icon_generator/proc/GeneratePipeStraight(icon_state_suffix, layer, combined_dirs)
var/list/output = list()
Expand All @@ -97,8 +132,10 @@
switch(combined_dirs)
if(NORTH | SOUTH)
output += GenerateDamaged(working, layer, combined_dirs, y_offset=offset)
output += generate_capped(working, layer, combined_dirs, y_offset=offset)
if(EAST | WEST)
output += GenerateDamaged(working, layer, combined_dirs, x_offset=offset)
output += generate_capped(working, layer, combined_dirs, x_offset=offset)

return output

Expand All @@ -117,6 +154,7 @@

output[working] = "[combined_dirs]_[layer]"
output += GenerateDamaged(working, layer, combined_dirs)
output += generate_capped(working, layer, combined_dirs)

return output

Expand All @@ -135,6 +173,7 @@

output[working] = "[combined_dirs]_[layer]"
output += GenerateDamaged(working, layer, combined_dirs)
output += generate_capped(working, layer, combined_dirs)

return output

Expand All @@ -144,5 +183,6 @@

output[working] = "[combined_dirs]_[layer]"
output += GenerateDamaged(working, layer, combined_dirs)
output += generate_capped(working, layer, combined_dirs)

return output
2 changes: 2 additions & 0 deletions code/modules/atmospherics/machinery/pipes/smart.dm
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ GLOBAL_LIST_INIT(atmos_components, typecacheof(list(/obj/machinery/atmospherics)
device_type = QUATERNARY
construction_type = /obj/item/pipe/quaternary
pipe_state = "manifold4w"
has_cap_visuals = TRUE

///Current active connections
var/connections = NONE
///Was this pipe created during map load
Expand Down
Binary file modified icons/obj/pipes_n_cables/!pipe_gas_overlays.dmi
Binary file not shown.
Binary file modified icons/obj/pipes_n_cables/!pipes_bitmask.dmi
Binary file not shown.
Binary file modified icons/obj/pipes_n_cables/pipe_template_pieces.dmi
Binary file not shown.

0 comments on commit 340a736

Please sign in to comment.