]> git.seodisparate.com - LD53/commitdiff
Work on game
authorStephen Seo <seo.disparate@gmail.com>
Sat, 29 Apr 2023 05:34:15 +0000 (14:34 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Sat, 29 Apr 2023 05:34:15 +0000 (14:34 +0900)
Added sprites, WIP world logic.

Cargo.lock
Cargo.toml
src/helpers.rs
src/lib.rs
src/sprites.rs
src/world.rs [new file with mode: 0644]

index d7837fe52d426e195f35307d383e0106a9c42658..e205cc39ede33cae65a6ffb45c24e491b672c5ac 100644 (file)
@@ -13,4 +13,11 @@ name = "cart"
 version = "0.1.0"
 dependencies = [
  "buddy-alloc",
+ "tinyrand",
 ]
+
+[[package]]
+name = "tinyrand"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87ffaad2263779579369d45f65cad0647c860893d27e4543cdcc1e428d07da2c"
index 9e57f1621e48ad368a64a154ff0cc0353369bf11..b42bb03fc70d188e7ee6c8888b8d4f34f9bd3e39 100644 (file)
@@ -9,6 +9,7 @@ crate-type = ["cdylib"]
 
 [dependencies]
 buddy-alloc = { version = "0.4.1", optional = true }
+tinyrand = "0.5.0"
 
 [profile.release]
 opt-level = "z"
index 52d9cebd363a3195569c31d997f37fcf587275b7..28077f62bba6367b0fd9f1176c63f0919c56965f 100644 (file)
@@ -1,7 +1,3 @@
-static mut CAR_STATE: u8 = 0;
-static mut CAR_STATE_FRAMES: u8 = 0;
-const CAR_FRAMES: u8 = 10;
-
 pub fn fill(color: u8) {
     if color > 3 {
         crate::trace("ERROR: Invalid value passed to helper \"fill\"");
@@ -11,33 +7,3 @@ pub fn fill(color: u8) {
         (&mut *crate::FRAMEBUFFER).fill(color | (color << 2) | (color << 4) | (color << 6));
     }
 }
-
-pub fn draw_mouse() -> Option<(i16, i16)> {
-    let mouse = unsafe { *crate::MOUSE_BUTTONS };
-    let mouse_x = unsafe { *crate::MOUSE_X };
-    let mouse_y = unsafe { *crate::MOUSE_Y };
-    if mouse & crate::MOUSE_LEFT != 0 {
-        unsafe { *crate::DRAW_COLORS = 2 }
-        crate::rect(i32::from(mouse_x) - 4, i32::from(mouse_y) - 4, 8, 8);
-        Some((mouse_x, mouse_y))
-    } else {
-        unsafe { *crate::DRAW_COLORS = 1 }
-        crate::rect(i32::from(mouse_x) - 2, i32::from(mouse_y) - 2, 4, 4);
-        None
-    }
-}
-
-pub fn toggle_car_state() -> bool {
-    unsafe {
-        CAR_STATE_FRAMES += 1;
-        if CAR_STATE_FRAMES >= CAR_FRAMES {
-            CAR_STATE_FRAMES = 0;
-            if CAR_STATE == 0 {
-                CAR_STATE = 1;
-            } else {
-                CAR_STATE = 0;
-            }
-        }
-        CAR_STATE != 0
-    }
-}
index 6c038d6f3531b0cb3553479501c49651ba292b4e..6bf7098d46408a821169616778e91f201a37eb02 100644 (file)
@@ -5,53 +5,27 @@ use wasm4::*;
 
 mod helpers;
 mod sprites;
+mod world;
 
-#[rustfmt::skip]
-const SMILEY: [u8; 8] = [
-    0b11000011,
-    0b10000001,
-    0b00100100,
-    0b00100100,
-    0b00000000,
-    0b00100100,
-    0b10011001,
-    0b11000011,
-];
+static mut WORLD: Option<world::World> = None;
 
 #[no_mangle]
 fn update() {
-    helpers::fill(3);
-
-    unsafe { *DRAW_COLORS = 2 }
-    text("Hello from Rust!", 10, 10);
-
-    let gamepad = unsafe { *GAMEPAD1 };
-    if gamepad & BUTTON_1 != 0 {
-        unsafe { *DRAW_COLORS = 3 }
+    // init
+    unsafe {
+        if WORLD.is_none() {
+            WORLD = Some(world::World::new());
+        }
     }
 
-    blit(&SMILEY, 76, 76, 8, 8, BLIT_1BPP);
-    text("Press X to blink", 16, 90);
+    // update
+    unsafe {
+        WORLD.as_mut().unwrap().update();
+    }
 
-    unsafe { *DRAW_COLORS = 0x312 }
-    if helpers::toggle_car_state() {
-        blit(
-            &sprites::CAR0,
-            50,
-            40,
-            sprites::CAR0_WIDTH,
-            sprites::CAR0_HEIGHT,
-            sprites::CAR0_FLAGS,
-        );
-    } else {
-        blit(
-            &sprites::CAR1,
-            50,
-            40,
-            sprites::CAR1_WIDTH,
-            sprites::CAR1_HEIGHT,
-            sprites::CAR1_FLAGS,
-        );
+    // draw
+    helpers::fill(3);
+    unsafe {
+        WORLD.as_mut().unwrap().draw();
     }
-    if let Some((x, y)) = helpers::draw_mouse() {}
 }
index 551ef18d1d66fec5c84960ffdc3c3ee5150078aa..f29dfb21f4ca56747772e364eba38fbec7c56189 100644 (file)
@@ -58,3 +58,94 @@ pub const CAR1: [u8; 384] = [
     0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfc, 0x51, 0x4f, 0xff, 0xff, 0xff, 0xff,
     0x14, 0x53, 0xff, 0xff, 0xff, 0xff, 0x04, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc1, 0x0f, 0xff, 0xff,
 ];
+// house0
+pub const HOUSE0_WIDTH: u32 = 48;
+pub const HOUSE0_HEIGHT: u32 = 48;
+pub const HOUSE0_FLAGS: u32 = 1; // BLIT_2BPP
+pub const HOUSE0: [u8; 576] = [
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xfe, 0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xab, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xea, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xa8, 0x2a, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xfe, 0xa0, 0x0a, 0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x80, 0x02, 0xab,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xea, 0x00, 0x00, 0xaa, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xa8, 0x00, 0x00, 0x2a, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
+    0xa0, 0x00, 0x00, 0x0a, 0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x80, 0x00, 0x00, 0x02,
+    0xab, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xea, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x2a, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xa0,
+    0x00, 0x00, 0x00, 0x00, 0x0a, 0xaf, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x80, 0x00, 0x00, 0x00, 0x00,
+    0x02, 0xab, 0xff, 0xff, 0xff, 0xff, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xff, 0xff,
+    0xff, 0xff, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0xbf, 0xff, 0xff, 0xfe, 0xa0, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xaf, 0xff, 0xff, 0xfa, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x02, 0xab, 0xff, 0xff, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xff,
+    0xff, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0xbf, 0xfe, 0xa0, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xaf, 0xfa, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x02, 0xab, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa,
+    0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0xa8, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+    0xaa, 0xaa, 0xaa, 0xaa, 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+    0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x80, 0x0a,
+    0xa0, 0x00, 0x00, 0x2a, 0xaa, 0x80, 0x00, 0x80, 0x08, 0x00, 0x80, 0x0a, 0xa0, 0x00, 0x00, 0x20,
+    0x00, 0x80, 0x00, 0x85, 0x08, 0x50, 0x80, 0x0a, 0xa0, 0x00, 0x00, 0x20, 0x00, 0x80, 0x00, 0x80,
+    0x08, 0x00, 0x80, 0x0a, 0xa0, 0x00, 0x00, 0x20, 0x00, 0x80, 0x00, 0xaa, 0xaa, 0xaa, 0x80, 0x0a,
+    0xa0, 0x00, 0x00, 0x20, 0x00, 0x80, 0x00, 0x80, 0x08, 0x00, 0x80, 0x0a, 0xa0, 0x00, 0x00, 0x20,
+    0x00, 0x80, 0x00, 0x85, 0x08, 0x50, 0x80, 0x0a, 0xa0, 0x00, 0x00, 0x20, 0x00, 0x80, 0x00, 0x80,
+    0x08, 0x00, 0x80, 0x0a, 0xa0, 0x00, 0x00, 0x20, 0x04, 0x80, 0x00, 0xaa, 0xaa, 0xaa, 0x80, 0x0a,
+    0xa0, 0x00, 0x00, 0x20, 0x04, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x20,
+    0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
+    0xa0, 0x00, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x20,
+    0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+];
+// house1
+pub const HOUSE1_WIDTH: u32 = 48;
+pub const HOUSE1_HEIGHT: u32 = 21;
+pub const HOUSE1_FLAGS: u32 = 1; // BLIT_2BPP
+pub const HOUSE1: [u8; 252] = [
+    0xaa, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0xab, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0xa0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xfc, 0x80, 0x0a, 0xaa, 0x28, 0x4f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0x00, 0x0a,
+    0xaa, 0x8a, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x80, 0x0a, 0xa2, 0xa2, 0x83, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x80, 0x0a, 0xa0, 0xaa, 0x80, 0xbf, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xa0, 0x80, 0x2a, 0xa0, 0x28, 0xa1, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa0, 0x80, 0x8a,
+    0xa0, 0x2a, 0x88, 0x23, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xaa, 0x82, 0x0a, 0xa8, 0x22, 0x82, 0x23,
+    0xff, 0xff, 0xff, 0xff, 0xfc, 0x28, 0x88, 0x0a, 0xa8, 0x82, 0xa2, 0xa0, 0x3f, 0xff, 0xff, 0xff,
+    0xc8, 0xa0, 0xa0, 0x0a, 0xa2, 0x82, 0x20, 0xa8, 0xff, 0xff, 0xff, 0xfe, 0x4a, 0x80, 0xa2, 0x8a,
+    0xa2, 0xa2, 0x28, 0x22, 0xff, 0xff, 0xff, 0xfe, 0xaa, 0xaa, 0x8a, 0x0a, 0xaa, 0x2a, 0x0a, 0x28,
+    0xbf, 0xff, 0xff, 0xff, 0x28, 0x08, 0x20, 0x0a, 0xa8, 0x0a, 0x02, 0xa2, 0xa3, 0xff, 0xff, 0xfe,
+    0xa0, 0xa0, 0x80, 0x8a, 0xa2, 0x08, 0xa0, 0xa0, 0xa8, 0x40, 0x4f, 0xfe, 0xa2, 0x82, 0x02, 0xaa,
+    0xa2, 0x88, 0x2a, 0x28, 0x02, 0x80, 0x80, 0x2a, 0x2a, 0x28, 0x2a, 0x8a, 0xa0, 0xa8, 0x02, 0xa2,
+    0x82, 0x82, 0x80, 0x62, 0x80, 0x20, 0xa8, 0x0a, 0xa0, 0x2a, 0x00, 0x20, 0xaa, 0x82, 0x00, 0x80,
+    0xa8, 0xa0, 0xa0, 0x0a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+];
+// box
+pub const BOX_WIDTH: u32 = 28;
+pub const BOX_HEIGHT: u32 = 28;
+pub const BOX_FLAGS: u32 = 1; // BLIT_2BPP
+pub const BOX: [u8; 196] = [
+    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 0x00,
+    0x00, 0x68, 0x00, 0x00, 0x1a, 0xa0, 0x00, 0x00, 0x68, 0x00, 0x00, 0x1a, 0xa0, 0x00, 0x00, 0x68,
+    0x00, 0x00, 0x1a, 0xa0, 0x00, 0x00, 0x68, 0x00, 0x00, 0x1a, 0xa0, 0x00, 0x00, 0x68, 0x00, 0x00,
+    0x1a, 0xa0, 0x00, 0x00, 0x68, 0x00, 0x00, 0x1a, 0xa0, 0x00, 0x00, 0x68, 0x00, 0x00, 0x1a, 0xa0,
+    0x00, 0x00, 0x68, 0x00, 0x00, 0x1a, 0xa0, 0x00, 0x00, 0x68, 0x00, 0x00, 0x1a, 0xa0, 0x00, 0x00,
+    0x68, 0x00, 0x00, 0x1a, 0xa5, 0x55, 0x55, 0x69, 0x55, 0x55, 0x5a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 0x00, 0x00, 0x68, 0x00, 0x00, 0x1a,
+    0xa0, 0x00, 0x00, 0x68, 0x00, 0x00, 0x1a, 0xa0, 0x00, 0x00, 0x68, 0x00, 0x00, 0x1a, 0xa0, 0x00,
+    0x00, 0x68, 0x00, 0x00, 0x1a, 0xa0, 0x00, 0x00, 0x68, 0x00, 0x00, 0x1a, 0xa0, 0x00, 0x00, 0x68,
+    0x00, 0x00, 0x1a, 0xa0, 0x00, 0x00, 0x68, 0x00, 0x00, 0x1a, 0xa0, 0x00, 0x00, 0x68, 0x00, 0x00,
+    0x1a, 0xa0, 0x00, 0x00, 0x68, 0x00, 0x00, 0x1a, 0xa0, 0x00, 0x00, 0x68, 0x00, 0x00, 0x1a, 0xa5,
+    0x55, 0x55, 0x69, 0x55, 0x55, 0x5a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+    0xaa, 0xaa, 0xaa, 0xaa,
+];
+// plant
+pub const PLANT_WIDTH: u32 = 12;
+pub const PLANT_HEIGHT: u32 = 10;
+pub const PLANT_FLAGS: u32 = 1; // BLIT_2BPP
+pub const PLANT: [u8; 30] = [
+    0x7f, 0xff, 0xf7, 0x13, 0xff, 0x03, 0xf0, 0xbc, 0x3f, 0xfc, 0x3c, 0x81, 0xff, 0x30, 0x0f, 0xff,
+    0x82, 0xef, 0x43, 0x0b, 0xff, 0xf0, 0x0b, 0xff, 0xf8, 0x2f, 0xff, 0xff, 0x2f, 0xff,
+];
diff --git a/src/world.rs b/src/world.rs
new file mode 100644 (file)
index 0000000..c39036f
--- /dev/null
@@ -0,0 +1,279 @@
+use crate::sprites::*;
+use tinyrand::{Rand, StdRand};
+
+const CAR_ANIM_FRAMES: u8 = 10;
+const CAMERA_RATE: f32 = 0.07f32;
+const BOX_INTERP_RATE: f32 = 0.01f32;
+const HOUSE_MAX_DIST: f32 = 10.0f32;
+
+pub struct World {
+    // x, y
+    shrubs: [(i32, i32); 4],
+    // x, y, state
+    // state:
+    //   - 0 does not exist
+    //   - 1 exists
+    //   - 2 destroyed
+    houses: [(i32, i32, u8); 2],
+    // u8:
+    //   - 0 facing right
+    //   - 1 facing left
+    //   - 2 facing up
+    //   - 3 facing down
+    //   - 4 facing right alt
+    //   - 5 facing left alt
+    //   - 6 facing up alt
+    //   - 7 facing down alt
+    car_pos: (i32, i32, u8),
+    car_frames: u8,
+    camera_pos: (f32, f32),
+    // x, y, interp, house_idx
+    box_pos: Option<(f32, f32, f32, usize)>,
+    rand: StdRand,
+}
+
+impl World {
+    pub fn new() -> World {
+        World {
+            shrubs: [(-40, 0), (0, 40), (40, 0), (0, -40)],
+            houses: [(300, 0, 2), (0, 0, 0)],
+            car_pos: (0, 0, 0),
+            car_frames: 0,
+            camera_pos: (-80f32, -80f32),
+            box_pos: None,
+            rand: StdRand::default(),
+        }
+    }
+
+    fn car_to_left(&mut self) {
+        if self.car_pos.2 > 3 {
+            self.car_pos.2 = 5;
+        } else {
+            self.car_pos.2 = 1;
+        }
+    }
+
+    fn car_to_right(&mut self) {
+        if self.car_pos.2 > 3 {
+            self.car_pos.2 = 4;
+        } else {
+            self.car_pos.2 = 0;
+        }
+    }
+
+    fn car_to_up(&mut self) {
+        if self.car_pos.2 > 3 {
+            self.car_pos.2 = 6;
+        } else {
+            self.car_pos.2 = 2;
+        }
+    }
+
+    fn car_to_down(&mut self) {
+        if self.car_pos.2 > 3 {
+            self.car_pos.2 = 7;
+        } else {
+            self.car_pos.2 = 3;
+        }
+    }
+
+    pub fn update(&mut self) {
+        let gamepad = unsafe { *crate::GAMEPAD1 };
+
+        if gamepad & crate::BUTTON_UP != 0 {
+            self.car_pos.1 -= 1;
+            self.car_to_up();
+            self.rand.next_u16();
+        }
+        if gamepad & crate::BUTTON_DOWN != 0 {
+            self.car_pos.1 += 1;
+            self.car_to_down();
+            self.rand.next_u16();
+        }
+        if gamepad & crate::BUTTON_LEFT != 0 {
+            self.car_pos.0 -= 1;
+            self.car_to_left();
+            self.rand.next_u16();
+        }
+        if gamepad & crate::BUTTON_RIGHT != 0 {
+            self.car_pos.0 += 1;
+            self.car_to_right();
+            self.rand.next_u16();
+        }
+
+        self.camera_pos.0 += ((self.car_pos.0 as f32 - 80f32) - self.camera_pos.0) * CAMERA_RATE;
+        self.camera_pos.1 += ((self.car_pos.1 as f32 - 80f32) - self.camera_pos.1) * CAMERA_RATE;
+
+        let mut house_repaired = false;
+        for (x, y, state) in &mut self.houses {
+            if *state == 2 {
+                let dx = self.car_pos.0 - *x;
+                let dy = self.car_pos.1 - *y;
+                let dist = ((dx * dx + dy * dy) as f32).sqrt();
+                if dist <= HOUSE_MAX_DIST {
+                    *state = 1;
+                    house_repaired = true;
+                }
+            }
+        }
+        if house_repaired {
+            for (x, y, state) in &mut self.houses {
+                if *state == 0 {
+                    *state = 2;
+                    // TODO
+                    match self.rand.next_u16() % 4 {
+                        0 => (),
+                        1 => (),
+                        2 => (),
+                        3 => (),
+                        _ => unreachable!(),
+                    }
+                }
+            }
+        }
+    }
+
+    pub fn draw(&mut self) {
+        unsafe {
+            *crate::DRAW_COLORS = 0x312;
+        }
+
+        for (x, y) in self.shrubs {
+            crate::blit(
+                &PLANT,
+                ((x - PLANT_WIDTH as i32 / 2) as f32 - self.camera_pos.0).round() as i32,
+                ((y - PLANT_HEIGHT as i32 / 2) as f32 - self.camera_pos.1).round() as i32,
+                PLANT_WIDTH,
+                PLANT_HEIGHT,
+                PLANT_FLAGS,
+            )
+        }
+
+        for (x, y, flags) in &mut self.houses {
+            //            if self.car_frames == 0 {
+            //                if *flags == 1 {
+            //                    *flags = 2;
+            //                } else if *flags == 2 {
+            //                    *flags = 1;
+            //                }
+            //            }
+            match flags {
+                0 => (),
+                1 => crate::blit(
+                    &HOUSE0,
+                    ((*x - HOUSE0_WIDTH as i32 / 2) as f32 - self.camera_pos.0).round() as i32,
+                    ((*y - HOUSE0_HEIGHT as i32 / 2) as f32 - self.camera_pos.1).round() as i32,
+                    HOUSE0_WIDTH,
+                    HOUSE0_HEIGHT,
+                    HOUSE0_FLAGS,
+                ),
+                2 => crate::blit(
+                    &HOUSE1,
+                    ((*x - HOUSE1_WIDTH as i32 / 2) as f32 - self.camera_pos.0).round() as i32,
+                    ((*y - HOUSE0_HEIGHT as i32 / 2 + (HOUSE0_HEIGHT - HOUSE1_HEIGHT) as i32)
+                        as f32
+                        - self.camera_pos.1)
+                        .round() as i32,
+                    HOUSE1_WIDTH,
+                    HOUSE1_HEIGHT,
+                    HOUSE1_FLAGS,
+                ),
+                _ => (),
+            }
+        }
+
+        self.car_frames += 1;
+        if self.car_frames > CAR_ANIM_FRAMES {
+            self.car_frames = 0;
+            if self.car_pos.2 > 3 {
+                self.car_pos.2 -= 4;
+            } else {
+                self.car_pos.2 += 4;
+            }
+        }
+
+        match self.car_pos.2 {
+            0 => crate::blit(
+                &CAR0,
+                ((self.car_pos.0 - CAR0_WIDTH as i32 / 2) as f32 - self.camera_pos.0).round()
+                    as i32,
+                ((self.car_pos.1 - CAR0_HEIGHT as i32 / 2) as f32 - self.camera_pos.1).round()
+                    as i32,
+                CAR0_WIDTH,
+                CAR0_HEIGHT,
+                CAR0_FLAGS,
+            ),
+            1 => crate::blit(
+                &CAR0,
+                ((self.car_pos.0 - CAR0_WIDTH as i32 / 2) as f32 - self.camera_pos.0).round()
+                    as i32,
+                ((self.car_pos.1 - CAR0_HEIGHT as i32 / 2) as f32 - self.camera_pos.1).round()
+                    as i32,
+                CAR0_WIDTH,
+                CAR0_HEIGHT,
+                CAR0_FLAGS | crate::BLIT_FLIP_X,
+            ),
+            2 => crate::blit(
+                &CAR0,
+                ((self.car_pos.0 - CAR0_WIDTH as i32 / 2) as f32 - self.camera_pos.0).round()
+                    as i32,
+                ((self.car_pos.1 - CAR0_HEIGHT as i32 / 2) as f32 - self.camera_pos.1).round()
+                    as i32,
+                CAR0_WIDTH,
+                CAR0_HEIGHT,
+                CAR0_FLAGS | crate::BLIT_ROTATE,
+            ),
+            3 => crate::blit(
+                &CAR0,
+                ((self.car_pos.0 - CAR0_WIDTH as i32 / 2) as f32 - self.camera_pos.0).round()
+                    as i32,
+                ((self.car_pos.1 - CAR0_HEIGHT as i32 / 2) as f32 - self.camera_pos.1).round()
+                    as i32,
+                CAR0_WIDTH,
+                CAR0_HEIGHT,
+                CAR0_FLAGS | crate::BLIT_ROTATE | crate::BLIT_FLIP_X,
+            ),
+            4 => crate::blit(
+                &CAR1,
+                ((self.car_pos.0 - CAR0_WIDTH as i32 / 2) as f32 - self.camera_pos.0).round()
+                    as i32,
+                ((self.car_pos.1 - CAR0_HEIGHT as i32 / 2) as f32 - self.camera_pos.1).round()
+                    as i32,
+                CAR1_WIDTH,
+                CAR1_HEIGHT,
+                CAR1_FLAGS,
+            ),
+            5 => crate::blit(
+                &CAR1,
+                ((self.car_pos.0 - CAR0_WIDTH as i32 / 2) as f32 - self.camera_pos.0).round()
+                    as i32,
+                ((self.car_pos.1 - CAR0_HEIGHT as i32 / 2) as f32 - self.camera_pos.1).round()
+                    as i32,
+                CAR1_WIDTH,
+                CAR1_HEIGHT,
+                CAR1_FLAGS | crate::BLIT_FLIP_X,
+            ),
+            6 => crate::blit(
+                &CAR1,
+                ((self.car_pos.0 - CAR0_WIDTH as i32 / 2) as f32 - self.camera_pos.0).round()
+                    as i32,
+                ((self.car_pos.1 - CAR0_HEIGHT as i32 / 2) as f32 - self.camera_pos.1).round()
+                    as i32,
+                CAR1_WIDTH,
+                CAR1_HEIGHT,
+                CAR1_FLAGS | crate::BLIT_ROTATE,
+            ),
+            7 => crate::blit(
+                &CAR1,
+                ((self.car_pos.0 - CAR0_WIDTH as i32 / 2) as f32 - self.camera_pos.0).round()
+                    as i32,
+                ((self.car_pos.1 - CAR0_HEIGHT as i32 / 2) as f32 - self.camera_pos.1).round()
+                    as i32,
+                CAR1_WIDTH,
+                CAR1_HEIGHT,
+                CAR1_FLAGS | crate::BLIT_ROTATE | crate::BLIT_FLIP_X,
+            ),
+            _ => (),
+        }
+    }
+}