From 575dda72a64744b71fbcaa7e925530ada597fc42 Mon Sep 17 00:00:00 2001 From: Tad Hardesty Date: Sun, 17 Nov 2019 18:25:58 -0800 Subject: [PATCH] Implement fancy rendering for smart cables Closes #107. --- src/tools/render_passes/mod.rs | 3 + src/tools/render_passes/smart_cables.rs | 98 +++++++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 src/tools/render_passes/smart_cables.rs diff --git a/src/tools/render_passes/mod.rs b/src/tools/render_passes/mod.rs index 0ff58ae9..ca3ea8d2 100644 --- a/src/tools/render_passes/mod.rs +++ b/src/tools/render_passes/mod.rs @@ -6,11 +6,13 @@ mod transit_tube; mod random; mod structures; mod icon_smoothing; +mod smart_cables; pub use self::transit_tube::TransitTube; pub use self::random::Random; pub use self::structures::{GravityGen, Spawners}; pub use self::icon_smoothing::IconSmoothing; +pub use self::smart_cables::SmartCables; /// A map rendering pass. /// @@ -102,6 +104,7 @@ pub const RENDER_PASSES: &[RenderPassInfo] = &[ pass!(Pipes, "only-pipenet", "Render only atmospheric pipes.", false), pass!(FancyLayers, "fancy-layers", "Layer atoms according to in-game rules.", true), pass!(IconSmoothing, "icon-smoothing", "Emulate the icon smoothing subsystem.", true), + pass!(SmartCables, "smart-cables", "Handle smart cable layout.", true), ]; pub fn configure(include: &str, exclude: &str) -> Vec> { diff --git a/src/tools/render_passes/smart_cables.rs b/src/tools/render_passes/smart_cables.rs new file mode 100644 index 00000000..8f30110b --- /dev/null +++ b/src/tools/render_passes/smart_cables.rs @@ -0,0 +1,98 @@ +use std::fmt::Write; +use dmi::Dir; +use super::*; + +#[derive(Default)] +pub struct SmartCables; + +impl RenderPass for SmartCables { + fn neighborhood_appearance<'a>(&self, + atom: &Atom<'a>, + objtree: &'a ObjectTree, + neighborhood: &Neighborhood<'a, '_>, + output: &mut Vec>, + bump: &'a bumpalo::Bump, + ) -> bool { + if !atom.istype("/obj/structure/cable/") { + return true; + } + + let cable_layer = atom.get_var("cable_layer", objtree).as_str().unwrap_or("l2"); + + let mut under_smes = false; + let mut under_terminal = false; + for atom in neighborhood.center() { + if atom.istype("/obj/machinery/power/terminal/") { + under_terminal = true; + } else if atom.istype("/obj/machinery/power/smes/") { + under_smes = true; + } + } + + // calculate linked dirs + let mut linked_dirs = 0; + 'dir: for &check_dir in Dir::CARDINALS { + let turf = neighborhood.offset(check_dir); + + // Don't link between SMES and terminal + if under_smes { + for atom in turf { + if atom.istype("/obj/machinery/power/terminal/") { + continue 'dir; + } + } + } else if under_terminal { + for atom in turf { + if atom.istype("/obj/machinery/power/smes/") { + continue 'dir; + } + } + } + + for atom in turf { + if atom.istype("/obj/structure/cable/") { + if atom.get_var("cable_layer", objtree).as_str().unwrap_or("l2") == cable_layer { + linked_dirs |= check_dir.to_int(); + break; + } + } + } + } + + // calculate icon state + let mut icon_state; + if linked_dirs == 0 { + icon_state = bumpalo::format!(in bump, "{}-noconnection", cable_layer); + } else { + icon_state = bumpalo::format!(in bump, "{}", cable_layer); + let mut count = 0; + for &check_dir in Dir::CARDINALS { + if linked_dirs & check_dir.to_int() != 0 { + let _ = write!(icon_state, "-{}", check_dir.to_int()); + count += 1; + } + } + if count > 1 && should_have_node(neighborhood.center()) { + let _ = write!(icon_state, "-node"); + } + }; + + output.push(Sprite { + icon_state: icon_state.into_bump_str(), + .. atom.sprite + }); + false + } +} + +fn should_have_node(turf: &[Atom]) -> bool { + for atom in turf { + if atom.istype("/obj/structure/grille/") || atom.istype("/obj/structure/cable_bridge/") { + return true; + } else if atom.istype("/obj/machinery/power/") { + // TODO: more detailed type-specific checks + return true; + } + } + false +}