mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'src/block/power.rs')
-rw-r--r--src/block/power.rs251
1 files changed, 251 insertions, 0 deletions
diff --git a/src/block/power.rs b/src/block/power.rs
new file mode 100644
index 0000000..62f32f8
--- /dev/null
+++ b/src/block/power.rs
@@ -0,0 +1,251 @@
+//! power connection and generation
+use thiserror::Error;
+
+use crate::block::simple::*;
+use crate::block::*;
+use crate::data::dynamic::DynType;
+
+make_simple!(GeneratorBlock => |_, _, _, buff: &mut DataRead| read_generator(buff));
+make_simple!(NuclearGeneratorBlock => |_, _, _, buff: &mut DataRead| read_nuclear(buff));
+make_simple!(ImpactReactorBlock => |_, _, _, buff: &mut DataRead| read_impact(buff));
+make_simple!(
+ Neoplasia,
+ |_, _, _, _, rot: Rotation, scl| {
+ let mut base = load!("neoplasia-reactor", scl);
+ unsafe {
+ base.overlay(
+ load!(scl -> match rot {
+ Rotation::Up | Rotation::Right => "neoplasia-reactor-top1",
+ Rotation::Down | Rotation::Left => "neoplasia-reactor-top2",
+ })
+ .rotate(rot.rotated(false).count()),
+ )
+ };
+ base
+ },
+ |_, _, _, buff: &mut DataRead| read_heater(buff)
+);
+make_simple!(DiodeBlock, |_, _, _, _, rot: Rotation, s| {
+ let mut base = load!("diode", s);
+ if rot == Rotation::Right {
+ return base;
+ }
+ let mut top = load!("diode-arrow", s);
+ unsafe {
+ top.rotate(rot.rotated(false).count());
+ base.overlay(&top)
+ };
+ base
+});
+
+make_register! {
+ // illuminator == power ?????
+ "illuminator" -> LampBlock::new(1, true, cost!(Lead: 8, Graphite: 12, Silicon: 8));
+ "power-node" -> ConnectorBlock::new(1, true, cost!(Copper: 1, Lead: 3), 10);
+ "power-node-large" -> ConnectorBlock::new(2, true, cost!(Lead: 10, Titanium: 5, Silicon: 3), 15);
+ "surge-tower" -> ConnectorBlock::new(2, true, cost!(Lead: 10, Titanium: 7, Silicon: 15, SurgeAlloy: 15), 2);
+ "diode" => DiodeBlock::new(1, false, cost!(Metaglass: 10, Silicon: 10, Plastanium: 5));
+ "battery" -> BasicBlock::new(1, true, cost!(Copper: 5, Lead: 20));
+ "battery-large" -> BasicBlock::new(3, true, cost!(Lead: 50, Titanium: 20, Silicon: 30));
+ "combustion-generator" -> GeneratorBlock::new(1, true, cost!(Copper: 25, Lead: 15));
+ "thermal-generator" -> GeneratorBlock::new(2, true, cost!(Copper: 40, Lead: 50, Metaglass: 40, Graphite: 35, Silicon: 35));
+ "steam-generator" -> GeneratorBlock::new(2, true, cost!(Copper: 35, Lead: 40, Graphite: 25, Silicon: 30));
+ "differential-generator" -> GeneratorBlock::new(3, true, cost!(Copper: 70, Lead: 100, Metaglass: 50, Titanium: 50, Silicon: 65));
+ "rtg-generator" -> GeneratorBlock::new(2, true, cost!(Lead: 100, Thorium: 50, Silicon: 75, Plastanium: 75, PhaseFabric: 25));
+ "solar-panel" -> GeneratorBlock::new(1, true, cost!(Lead: 10, Silicon: 15));
+ "solar-panel-large" -> GeneratorBlock::new(3, true, cost!(Lead: 80, Silicon: 110, PhaseFabric: 15));
+ "thorium-reactor" -> NuclearGeneratorBlock::new(3, true, cost!(Lead: 300, Metaglass: 50, Graphite: 150, Thorium: 150, Silicon: 200));
+ "impact-reactor" -> ImpactReactorBlock::new(4, true,
+ cost!(Lead: 500, Metaglass: 250, Graphite: 400, Thorium: 100, Silicon: 300, SurgeAlloy: 250));
+ "beam-node" -> ConnectorBlock::new(1, true, cost!(Beryllium: 8), 4);
+ "beam-tower" -> ConnectorBlock::new(3, true, cost!(Beryllium: 30, Oxide: 10, Silicon: 10), 12);
+ "turbine-condenser" -> GeneratorBlock::new(3, true, cost!(Beryllium: 60));
+ "chemical-combustion-chamber" -> GeneratorBlock::new(3, true, cost!(Graphite: 40, Tungsten: 40, Oxide: 40, Silicon: 30));
+ "pyrolysis-generator" -> GeneratorBlock::new(3, true, cost!(Graphite: 50, Carbide: 50, Oxide: 60, Silicon: 50));
+ "flux-reactor" -> GeneratorBlock::new(5, true, cost!(Graphite: 300, Carbide: 200, Oxide: 100, Silicon: 600, SurgeAlloy: 300));
+ "neoplasia-reactor" => Neoplasia::new(5, true, cost!(Tungsten: 1000, Carbide: 300, Oxide: 150, Silicon: 500, PhaseFabric: 300, SurgeAlloy: 200));
+ // editor only
+ "beam-link" -> ConnectorBlock::new(3, true, &[], 12);
+ // sandbox only
+ "power-source" -> ConnectorBlock::new(1, true, &[], 100);
+ "power-void" -> GeneratorBlock::new(1, true, &[]);
+}
+
+pub struct ConnectorBlock {
+ size: u8,
+ symmetric: bool,
+ build_cost: BuildCost,
+ pub max: u8,
+}
+
+impl ConnectorBlock {
+ #[must_use]
+ pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost, max: u8) -> Self {
+ assert!(size != 0, "invalid size");
+ assert!(
+ !(max == 0 || max > i8::MAX as u8),
+ "invalid maximum link count"
+ );
+ Self {
+ size,
+ symmetric,
+ build_cost,
+ max,
+ }
+ }
+ state_impl!(pub Vec<(i16, i16)>);
+}
+
+impl BlockLogic for ConnectorBlock {
+ impl_block!();
+
+ fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError> {
+ Ok(DynData::Empty)
+ }
+
+ fn deserialize_state(&self, data: DynData) -> Result<Option<State>, DeserializeError> {
+ match data {
+ DynData::Empty => Ok(Some(Self::create_state(Vec::new()))),
+ DynData::Point2Array(s) => Ok(Some(Self::create_state(s))),
+ _ => Err(DeserializeError::InvalidType {
+ have: data.get_type(),
+ expect: DynType::Boolean,
+ }),
+ }
+ }
+
+ fn mirror_state(&self, state: &mut State, horizontally: bool, vertically: bool) {
+ for (dx, dy) in &mut *Self::get_state_mut(state) {
+ if horizontally {
+ *dx = -*dx;
+ }
+ if vertically {
+ *dy = -*dy;
+ }
+ }
+ }
+
+ fn rotate_state(&self, state: &mut State, clockwise: bool) {
+ for (dx, dy) in &mut *Self::get_state_mut(state) {
+ let (cdx, cdy) = (*dx, *dy);
+ *dx = if clockwise { cdy } else { -cdy };
+ *dy = if clockwise { -cdx } else { cdx };
+ }
+ }
+
+ fn serialize_state(&self, state: &State) -> Result<DynData, SerializeError> {
+ Ok(DynData::Point2Array(Self::get_state(state).clone()))
+ }
+}
+
+#[derive(Debug, Error)]
+pub enum ConnectorDeserializeError {
+ #[error("too many links ({have} but only {max} allowed)")]
+ LinkCount { have: usize, max: u8 },
+}
+
+impl ConnectorDeserializeError {
+ pub fn forward<T, E: Into<Self>>(result: Result<T, E>) -> Result<T, DeserializeError> {
+ match result {
+ Ok(v) => Ok(v),
+ Err(e) => Err(DeserializeError::Custom(Box::new(e.into()))),
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub struct Rgba(u8, u8, u8, u8);
+
+impl From<u32> for Rgba {
+ fn from(value: u32) -> Self {
+ Self(
+ (value >> 24) as u8,
+ (value >> 16) as u8,
+ (value >> 8) as u8,
+ value as u8,
+ )
+ }
+}
+
+impl From<Rgba> for u32 {
+ fn from(value: Rgba) -> Self {
+ (u32::from(value.0) << 24)
+ | (u32::from(value.1) << 16)
+ | (u32::from(value.2) << 8)
+ | u32::from(value.3)
+ }
+}
+
+pub struct LampBlock {
+ size: u8,
+ symmetric: bool,
+ build_cost: BuildCost,
+}
+
+impl LampBlock {
+ #[must_use]
+ pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost) -> Self {
+ assert!(size != 0, "invalid size");
+ Self {
+ size,
+ symmetric,
+ build_cost,
+ }
+ }
+
+ state_impl!(pub Rgba);
+}
+
+impl BlockLogic for LampBlock {
+ impl_block!();
+
+ fn data_from_i32(&self, config: i32, _: GridPos) -> Result<DynData, DataConvertError> {
+ Ok(DynData::Int(config))
+ }
+
+ fn deserialize_state(&self, data: DynData) -> Result<Option<State>, DeserializeError> {
+ match data {
+ DynData::Int(rgba) => Ok(Some(Self::create_state(Rgba::from(rgba as u32)))),
+ _ => Err(DeserializeError::InvalidType {
+ have: data.get_type(),
+ expect: DynType::Int,
+ }),
+ }
+ }
+
+ fn serialize_state(&self, state: &State) -> Result<DynData, SerializeError> {
+ let state = Self::get_state(state);
+ Ok(DynData::Int(u32::from(*state) as i32))
+ }
+}
+
+/// format:
+/// - production efficiency: [`f32`]
+/// - generate time: [`f32`]
+fn read_generator(buff: &mut DataRead) -> Result<(), DataReadError> {
+ buff.skip(8)
+}
+
+/// format:
+/// - call [`read_generator`]
+/// - heat: [`f32`]
+fn read_nuclear(buff: &mut DataRead) -> Result<(), DataReadError> {
+ read_generator(buff)?;
+ buff.skip(4)
+}
+
+/// format:
+/// - call [`read_generator`]
+/// - warmup: [`f32`]
+fn read_impact(buff: &mut DataRead) -> Result<(), DataReadError> {
+ read_generator(buff)?;
+ buff.skip(4)
+}
+
+/// format:
+/// - call [`read_generator`]
+/// - heat: [`f32`]
+fn read_heater(buff: &mut DataRead) -> Result<(), DataReadError> {
+ read_generator(buff)?;
+ buff.skip(4)
+}