From 32a62cfcb925225359a5c90761b795f2f737ebd2 Mon Sep 17 00:00:00 2001 From: LLLL Colonq Date: Tue, 18 Aug 2026 00:08:28 -0400 Subject: Re-populate games --- 2026/games/rpc2dot0/src/computer.rs | 183 ++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 2026/games/rpc2dot0/src/computer.rs (limited to '2026/games/rpc2dot0/src/computer.rs') diff --git a/2026/games/rpc2dot0/src/computer.rs b/2026/games/rpc2dot0/src/computer.rs new file mode 100644 index 0000000..e25fb65 --- /dev/null +++ b/2026/games/rpc2dot0/src/computer.rs @@ -0,0 +1,183 @@ +use crate::constants::*; +use crate::disquette::Disquette; +use crate::game::Game; +use crate::math::ContainsPoint; +use crate::math::Rectangle; +use crate::random::RandomState; + +pub mod os; + +use os::Os; +use teleia::context; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ComputerPhase { + Off, + Booting, + On, + ShutDown, +} + +impl From for &'static str { + fn from(value: ComputerPhase) -> Self { + match value { + ComputerPhase::Off => "Off", + ComputerPhase::Booting => "Booting", + ComputerPhase::On => "On", + ComputerPhase::ShutDown => "ShutDown", + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PowerButtonAction { + On, + Off, +} + +impl From for &'static str { + fn from(value: PowerButtonAction) -> Self { + match value { + PowerButtonAction::On => "On", + PowerButtonAction::Off => "Off", + } + } +} + +#[derive(Debug, Clone, Copy)] +pub struct Computer { + pub coord: glam::Vec2, + pub phase: ComputerPhase, + pub disquette: Disquette, + pub os: Os, +} + +impl Computer { + pub fn new( + logical_width: f32, + logical_height: f32, + rng: &mut RandomState, + difficulty: f32, + ) -> Self { + const HALF_W: f32 = COMPUTER_WIDTH / 2.0; + const HALF_H: f32 = COMPUTER_HEIGHT / 2.0; + let x = rng.next_range(HALF_W, logical_width - HALF_W); + let y = rng.next_range(HALF_H, logical_height - HALF_H); + log::info!("eatyourgreens:: Computer new at ({}, {}) ", x, y); + let mut temp = Self { + coord: glam::Vec2::new(x, y), + phase: ComputerPhase::Off, + disquette: Disquette { + coord: glam::Vec2::ZERO, + vel: glam::Vec2::ZERO, + size: 0.0, + phase: crate::disquette::DisquettePhase::Free, + }, + os: Os::from(ComputerPhase::Off), + }; + + let hitzone = temp.hit_zone(difficulty); + temp.disquette = Disquette::new(logical_width, logical_height, rng, Some(hitzone)); + temp + } + + pub fn disquette_inserted(&self) -> bool { + self.disquette.is_inserted() + } + + pub fn boot(&mut self) { + log::info!("eatyourgreens:: computer boot"); + self.phase = ComputerPhase::Booting; + self.os = Os::from(self.phase); + } + + pub fn on(&mut self, ctx: &context::Context) { + log::info!("eatyourgreens:: computer on"); + self.phase = ComputerPhase::On; + self.os.set(self.phase); + self.os.os_play(&ctx); + } + + pub fn shutdown(&mut self) { + log::info!("eatyourgreens:: computer shutdown"); + self.phase = ComputerPhase::Off; + self.os.set(self.phase); + } + + pub fn already_used(&self) -> bool { + self.phase != ComputerPhase::Off + } + + // + // hitzone calculation + // + // computer pos is (x, y)so its center. + // first find the top-left corner of the computer bbox. + // second define "hitzone" as the inner rectangle offset from that top-left corner. + + // us diffculity to shrink the area, so user msut aim better at higher difficulties + + // topleft(x -width/2 , y-height/2) + // +------------------------------------------+ --- + // | | | + // | TRIGGER_OFFSET_Y | | + // | v | | COMPUTER_HEIGHT + // | -> +----------------------------+ --- | | + // | ^ | diff_y | | | | + // | | | -> +---------------+ --- | | | | + // | | | ^ | | | | | TRIGGER_HEIGHT + // | | | | | Actual Hit |actual_| | | | + // | | | | | Zone (shrunk) |height | | | | + // | | | | +---------------+ --- | | | | + // | | | diff_x | | | | + // | | +----------------------------+ --- | | + // | | | | + // | TRIGGER_OFFSET_X | | + // +------------------------------------------+ --- + // |--------------COMPUTER_WIDTH--------------| + + pub fn hit_zone(&self, difficulty: f32) -> Rectangle { + let topleft = self.coord - glam::Vec2::new(COMPUTER_WIDTH / 2.0, COMPUTER_HEIGHT / 2.0); + + let size_multiplier = 1.0 / difficulty.max(1.0); + let actual_size = glam::Vec2::new(TRIGGER_WIDTH, TRIGGER_HEIGHT) * size_multiplier; + + let diff = (glam::Vec2::new(TRIGGER_WIDTH, TRIGGER_HEIGHT) - actual_size) / 2.0; + + let trigger_pos = topleft + glam::Vec2::new(TRIGGER_OFFSET_X, TRIGGER_OFFSET_Y) + diff; + + Rectangle::from_min_max(trigger_pos, trigger_pos + actual_size) + } + + pub fn check_power_button( + &self, + point: glam::Vec2, + difficulty: f32, + ) -> Option { + let topleft = self.coord - glam::Vec2::new(COMPUTER_WIDTH / 2.0, COMPUTER_HEIGHT / 2.0); + let pb_pos = topleft + glam::Vec2::new(POWER_BUTTON_OFFSET_X, POWER_BUTTON_OFFSET_Y); + let pb_size = glam::Vec2::new(POWER_BUTTON_WIDTH, POWER_BUTTON_HEIGHT); + + let pb_rect = Rectangle::from_min_max(pb_pos, pb_pos + pb_size); + + if pb_rect.contains(point) { + if difficulty > 1.0 { + let half_width = POWER_BUTTON_WIDTH / 2.0; + if point.x < pb_pos.x + half_width { + Some(PowerButtonAction::Off) + } else { + Some(PowerButtonAction::On) + } + } else { + Some(PowerButtonAction::On) + } + } else { + None + } + } + + pub fn contains_disquette(&self, disquette: &Disquette, difficulty: f32) -> bool { + let hitzone = self.hit_zone(difficulty); + hitzone.contains(disquette.coord) + } +} -- cgit v1.3.1