diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..4644b2a --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/trevors_chip8_toy.iml b/.idea/trevors_chip8_toy.iml new file mode 100644 index 0000000..ca38ecd --- /dev/null +++ b/.idea/trevors_chip8_toy.iml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 231b130..7580cc3 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -9,13 +9,10 @@ - - - - - - - + + + + - - - - - + - - @@ -237,6 +257,8 @@ + + diff --git a/gemma/src/chip8/computer.rs b/gemma/src/chip8/computer.rs index 4c9a8b5..3ee4de5 100644 --- a/gemma/src/chip8/computer.rs +++ b/gemma/src/chip8/computer.rs @@ -44,6 +44,7 @@ impl Chip8Computer { self.registers.reset(); self.delay_timer.reset(); self.sound_timer.reset(); + self.stack.reset(); } pub fn dump_keypad_to_string(&self) -> String { @@ -55,7 +56,7 @@ impl Chip8Computer { } pub fn dump_video_to_string(&self) -> String { - self.video_memory.format_as_string() + self.clone().video_memory.format_as_string() } pub fn new_with_program(new_program: Vec) -> Self { diff --git a/gemma/src/chip8/computer_manager.rs b/gemma/src/chip8/computer_manager.rs index 3eb7e49..9cba622 100644 --- a/gemma/src/chip8/computer_manager.rs +++ b/gemma/src/chip8/computer_manager.rs @@ -5,14 +5,12 @@ use std::time::{Duration, Instant}; use crate::chip8::computer::Chip8Computer; use crate::chip8::cpu_states::Chip8CpuStates; use crate::chip8::cpu_states::Chip8CpuStates::WaitingForInstruction; - pub enum ManagerDumpables { Video, Registers, Keyboard } - pub struct Chip8ComputerManager { core_should_run: bool, one_step: bool, @@ -76,7 +74,7 @@ impl Chip8ComputerManager { WaitingForInstruction => { self.core_last_cycle_start = Instant::now(); self.computer.step_system(); - println!("SYSTEM STEP"); + // println!("SYSTEM STEP"); } _ => {} } diff --git a/gemma/src/chip8/instructions.rs b/gemma/src/chip8/instructions.rs index 8f960b8..67e8d3b 100644 --- a/gemma/src/chip8/instructions.rs +++ b/gemma/src/chip8/instructions.rs @@ -880,25 +880,27 @@ impl Chip8CpuInstructions { } Chip8CpuInstructions::XXXXERRORINSTRUCTION => {} Chip8CpuInstructions::SDN(x) => { - println!("SCROLLING DOWN {x} LINES"); + input.video_memory.scroll_down(*x as i32); } Chip8CpuInstructions::SRT => { - println!("SCROLING RIGHT 4 LINES"); + input.video_memory.scroll_right(); } Chip8CpuInstructions::SLF => { - println!("SCROLLING LEFT 4 LINES"); + input.video_memory.scroll_left(); } Chip8CpuInstructions::DIS => { - println!("DISABLE VIDEO MODE"); + input.video_memory.set_lowres(); } Chip8CpuInstructions::ENA => { - println!("ENABLE VIDEO MODE"); + input.video_memory.set_highres(); } Chip8CpuInstructions::EXIT => { println!("EXIT INTERPRETER"); } Chip8CpuInstructions::LDF2(x) => { println!("POINTING TO FONT AT {x:02x}"); + // base = 0x100 + 0x0A*X + input.registers.poke_i(0x100 + (0xA * x) as u16); } Chip8CpuInstructions::STR(x) => { println!("STORING FROM RPL FOR {x}"); @@ -922,7 +924,7 @@ impl Chip8CpuInstructions { #[cfg(test)] mod test { - use crate::chip8::system_memory::{CHIP8FONT_0, CHIP8FONT_1, CHIP8FONT_2, CHIP8FONT_9}; + use crate::chip8::system_memory::{*}; use crate::constants::CHIP8_VIDEO_MEMORY; use super::*; diff --git a/gemma/src/chip8/stack.rs b/gemma/src/chip8/stack.rs index 43259c8..70d2588 100644 --- a/gemma/src/chip8/stack.rs +++ b/gemma/src/chip8/stack.rs @@ -34,6 +34,10 @@ impl Chip8Stack { items: vec![] } } + + pub fn reset(&mut self) { + self.items = vec![] + } } #[cfg(test)] diff --git a/gemma/src/chip8/system_memory.rs b/gemma/src/chip8/system_memory.rs index 2b1a0c7..3c1f809 100644 --- a/gemma/src/chip8/system_memory.rs +++ b/gemma/src/chip8/system_memory.rs @@ -1,24 +1,6 @@ use log::{trace}; -use crate::constants::{CHIP8_MEMORY_SIZE}; - -pub const CHIP8_PROGRAM_LOAD_OFFSET: i32 = 0x200; -pub const CHIP8FONT_0: [u8; 5] = [0xF0, 0x90, 0x90, 0x90, 0xF0]; -pub const CHIP8FONT_1: [u8; 5] = [0x20, 0x60, 0x20, 0x20, 0x70]; -pub const CHIP8FONT_2: [u8; 5] = [0xF0, 0x10, 0xF0, 0x80, 0xF0]; -pub const CHIP8FONT_3: [u8; 5] = [0xF0, 0x10, 0xF0, 0x10, 0xF0]; -pub const CHIP8FONT_4: [u8; 5] = [0x90, 0x90, 0xF0, 0x10, 0x10]; -pub const CHIP8FONT_5: [u8; 5] = [0xF0, 0x80, 0xF0, 0x10, 0xF0]; -pub const CHIP8FONT_6: [u8; 5] = [0xF0, 0x80, 0xF0, 0x90, 0xF0]; -pub const CHIP8FONT_7: [u8; 5] = [0xF0, 0x10, 0x20, 0x40, 0x40]; -pub const CHIP8FONT_8: [u8; 5] = [0xF0, 0x90, 0xF0, 0x90, 0xF0]; -pub const CHIP8FONT_9: [u8; 5] = [0xF0, 0x90, 0xF0, 0x10, 0xF0]; -pub const CHIP8FONT_A: [u8; 5] = [0xF0, 0x90, 0xF0, 0x90, 0x90]; -pub const CHIP8FONT_B: [u8; 5] = [0xE0, 0x90, 0xE0, 0x90, 0xE0]; -pub const CHIP8FONT_C: [u8; 5] = [0xF0, 0x80, 0x80, 0x80, 0xF0]; -pub const CHIP8FONT_D: [u8; 5] = [0xE0, 0x90, 0x90, 0x90, 0xE0]; -pub const CHIP8FONT_E: [u8; 5] = [0xF0, 0x80, 0xF0, 0x80, 0xF0]; -pub const CHIP8FONT_F: [u8; 5] = [0xF0, 0x80, 0xF0, 0x80, 0x80]; +use crate::constants::*; #[derive(Clone, Copy)] pub struct Chip8SystemMemory { @@ -33,6 +15,7 @@ impl Default for Chip8SystemMemory { }; x.load_fonts_to_memory(); + x.load_schip_fonts_to_memory(); x } } @@ -87,6 +70,22 @@ impl Chip8SystemMemory { } } } + + pub fn load_schip_fonts_to_memory(&mut self) { + let all_font_characters = [ + SCHIPFONT_0, SCHIPFONT_1, SCHIPFONT_2, SCHIPFONT_3, + SCHIPFONT_4, SCHIPFONT_5, SCHIPFONT_6, SCHIPFONT_7, + SCHIPFONT_8, SCHIPFONT_9, SCHIPFONT_A, SCHIPFONT_B, + SCHIPFONT_C, SCHIPFONT_D, SCHIPFONT_E, SCHIPFONT_F + ]; + for (font_index, current_font) in all_font_characters.iter().enumerate() { + let base_offset = 0x100; + for font_mem_offset in 0..=4 { + let real_offset = base_offset + font_index * 0x10 + font_mem_offset; + self.poke(real_offset as u16, current_font[font_mem_offset]); + } + } + } } #[cfg(test)] diff --git a/gemma/src/chip8/video.rs b/gemma/src/chip8/video.rs index 7d458c6..5bff2eb 100644 --- a/gemma/src/chip8/video.rs +++ b/gemma/src/chip8/video.rs @@ -1,18 +1,18 @@ use log::{debug}; use crate::chip8::video::Chip8VideoModes::{HighRes, LowRes}; -use crate::constants::{CHIP8_VIDEO_MEMORY, CHIP8_VIDEO_WIDTH, SCHIP_VIDE_MEMORY}; +use crate::constants::{CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_MEMORY, CHIP8_VIDEO_WIDTH, SCHIP_VIDE_MEMORY, SCHIP_VIDEO_HEIGHT, SCHIP_VIDEO_WIDTH}; #[derive(Clone, Copy)] enum Chip8VideoModes { LowRes, - HighRes + HighRes, } -#[derive(Clone, Copy)] +#[derive(Clone)] pub struct Chip8Video { - memory: [bool; CHIP8_VIDEO_MEMORY], + memory: Vec, pub has_frame_changed: bool, - current_res: Chip8VideoModes + current_res: Chip8VideoModes, } impl Chip8Video { @@ -21,13 +21,13 @@ impl Chip8Video { self.start_frame(); } - pub fn is_highres(&self) -> bool { matches!(self.current_res, HighRes) } pub fn set_highres(&mut self) { - self.current_res = HighRes + self.current_res = HighRes; + self.cls(); } pub fn set_lowres(&mut self) { @@ -39,14 +39,17 @@ impl Chip8Video { } pub fn cls(&mut self) { - match self.current_res { + self.memory.clear(); + let num_loops = match self.current_res { LowRes => { - self.memory = [false; CHIP8_VIDEO_MEMORY]; + CHIP8_VIDEO_MEMORY } HighRes => { - - // self.memory = [0u8; ] + SCHIP_VIDE_MEMORY } + }; + for i in 0..num_loops { + self.memory.push(false); } } @@ -54,15 +57,15 @@ impl Chip8Video { self.has_frame_changed = false; } - pub fn new(initial_configuration: [bool; CHIP8_VIDEO_MEMORY]) -> Self { + pub fn new(initial_configuration: Box>) -> Self { Self { - memory: initial_configuration, + memory: *initial_configuration, has_frame_changed: false, current_res: Chip8VideoModes::LowRes, } } - pub fn peek(self, address: u16) -> bool { + pub fn peek(&self, address: u16) -> bool { let loop_value: u16 = if self.is_highres() { SCHIP_VIDE_MEMORY as u16 } else { @@ -75,12 +78,7 @@ impl Chip8Video { } pub fn poke(&mut self, address: u16, new_value: bool) { - // println!("OFFSET: {address} - POKING {new_value}"); - let loop_value: u16 = if self.is_highres() { - SCHIP_VIDE_MEMORY as u16 - } else { - CHIP8_VIDEO_MEMORY as u16 - }; + let loop_value: u16 = self.get_memory_size() as u16; // Loop the address let effective_address = address % loop_value; @@ -93,6 +91,7 @@ impl Chip8Video { }; } + // println!("VIDEO POKE COMPLETE WITH {effective_address} SET TO {xored_value}"); self.memory[effective_address as usize] = xored_value; } @@ -110,13 +109,15 @@ impl Chip8Video { } } - pub fn format_as_string(self) -> String { + pub fn format_as_string(&self) -> String { + let (width, height) = self.get_resolution(); + println!("FORMATTING {width}x{height}"); let mut output = String::new(); - for row in 0..32 { - for column in 0..64 { - let data_offset = row * 64 + column; - debug!("Rendering {data_offset} with value {}", self.memory[data_offset]); - if self.memory[data_offset] { + for row in 0..height { + for column in 0..width { + let data_offset = row * width + column; + debug!("Rendering {data_offset} with value {}", self.memory[data_offset as usize]); + if self.memory[data_offset as usize] { output += "*" } else { output += " " @@ -124,39 +125,127 @@ impl Chip8Video { } output += "\n"; } - output } + pub fn get_resolution(&self) -> (i32, i32) { + if self.is_highres() { + (SCHIP_VIDEO_WIDTH, SCHIP_VIDEO_HEIGHT) + } else { + (CHIP8_VIDEO_WIDTH, CHIP8_VIDEO_HEIGHT) + } + } + + fn get_memory_size(&self) -> i32 { + let w = self.get_resolution(); + w.1 * w.0 + } + pub fn tick(&mut self) { self.has_frame_changed = false; } + + pub fn scroll_right(&mut self) { + let (width, height) = self.get_resolution(); + + for current_row in 0..height { + let row_offset: usize = (current_row * width) as usize; + for current_column in (0..(width - 4)).rev() { + let source_address = row_offset + current_column as usize; + let target_address = source_address + 4; + self.memory[target_address] = self.memory[source_address]; + } + self.memory[row_offset..row_offset + 4].fill(false); + } + } + + pub fn scroll_left(&mut self) { + let (width, height) = self.get_resolution(); + + for current_row in 0..height { + let row_offset = current_row * width; + for current_column in (0..width - 4) { + let source: usize = (row_offset + current_column) as usize; + let target: usize = source + 4; + self.memory[target] = self.memory[source]; + } + + let clear_start: usize = (row_offset + width - 4) as usize; + let clear_end: usize = clear_start + 4; + + self.memory[clear_start..clear_end].fill(false); + } + } + + pub fn scroll_down(&mut self, how_far: i32) { + let (width, height) = self.get_resolution(); + let row_shift = how_far * width; + + let max_source_row = height - how_far; + for current_source_row in (0..max_source_row).rev() { + let current_source_offset = current_source_row * width; + for current_source_column in (0..width) { + let base_offset: usize = (current_source_offset + current_source_column) as usize; + let extended_offset: usize = base_offset + row_shift as usize; + self.memory[extended_offset] = self.memory[base_offset]; + }; + } + + // Clear the new top rows after shifting + let clear_end = (how_far * width) as usize; + self.memory[0..clear_end].fill(false); + } } impl Default for Chip8Video { fn default() -> Self { - Chip8Video { memory: [false; CHIP8_VIDEO_MEMORY], has_frame_changed: false, current_res: Chip8VideoModes::LowRes } + let mut mem = vec![]; + for _ in 0..CHIP8_VIDEO_MEMORY { mem.push(false); } + Chip8Video { memory: mem, has_frame_changed: false, current_res: Chip8VideoModes::LowRes } } } #[cfg(test)] mod test { use std::io::Read; - use crate::chip8::system_memory::{CHIP8FONT_0, CHIP8FONT_1, CHIP8FONT_2, CHIP8FONT_3, CHIP8FONT_4, CHIP8FONT_5, CHIP8FONT_6, CHIP8FONT_7}; + use crate::constants::*; use super::*; const TEST_OUTPUT_SAMPLE_DIR: &str = "../resources/test/"; - fn build_checkerboard() -> Chip8Video { + fn real_build_checkboard(in_hd: bool) -> Chip8Video { let mut r = Chip8Video::default(); + let (width, height) = if in_hd { + r.set_highres(); + (SCHIP_VIDEO_WIDTH, SCHIP_VIDEO_HEIGHT) + } else { + (CHIP8_VIDEO_WIDTH, CHIP8_VIDEO_HEIGHT) + }; - for i in 0..CHIP8_VIDEO_MEMORY { - r.poke(i as u16, i % 2 == 0); + println!("BUILDING BOARD WITH SIZE OF {width}x{height}"); + + for row in 0..height { + let data_offset = row * width; + + for col in 0..width { + // XOR row and column indices to alternate in a checkerboard pattern + let to_poke = (row % 2) ^ (col % 2) == 1; + let local_offset: u16 = (data_offset + col) as u16; + + r.poke(local_offset, to_poke); + } } - r } + fn build_checkboard_hd() -> Chip8Video { + real_build_checkboard(true) + } + + fn build_checkerboard() -> Chip8Video { + real_build_checkboard(false) + } + fn read_test_result(suffix: &str) -> String { std::fs::read_to_string(TEST_OUTPUT_SAMPLE_DIR.to_owned() + suffix) .unwrap() @@ -178,36 +267,7 @@ mod test { } #[test] - fn string_test_1() { - let mut x = Chip8Video::default(); - let mut working_string = String::new(); - for i in 0..32 { - working_string += &*(" ".repeat(64) + "\n"); - } - - assert_eq!(working_string, x.format_as_string()); - - let mut working_string = String::new(); - // set a checkerboard... - for cb_row in 0..32 { - for cb_col in 0..64 { - let data_offset = cb_row * 64 + cb_col; - if data_offset % 2 == 0 { - x.poke(data_offset, true); - working_string += "*"; - } else { - x.poke(data_offset, false); - working_string += " "; - } - } - working_string += "\n"; - } - - assert_eq!(working_string, x.format_as_string()); - } - - #[test] - fn set_initial_memory() { + fn set_initial_memory_sd() { let mut x = Chip8Video::default(); // let mut initial_memory = [false; CHIP8_VIDEO_MEMORY]; let mut ws = String::new(); @@ -242,10 +302,10 @@ mod test { #[test] fn poke_2byte_test() { - let to_poke: [u8; 2] = [ - 0b11001111, - 0b00111100 - ]; + let to_poke: [u8; 2] = [ + 0b11001111, + 0b00111100 + ]; let mut x = Chip8Video::default(); x.poke_2byte(0x00, to_poke); @@ -265,22 +325,18 @@ mod test { } #[test] - fn cls() { - let mut initial_memory = [false; CHIP8_VIDEO_MEMORY]; + fn cls_stddef() { + let width = 64; + let height = 32; + let mut initial_memory = vec![]; let mut ws = String::new(); - + let mut set_x = Chip8Video::new(initial_memory.into()); for cbr in 0..32 { - for cbc in 0..64 { - let dof = cbr * 64 + cbc; - if (dof as i32 % 2) == 0 { - initial_memory[dof] = true; - } - ws += " "; - } + ws += &*" ".repeat(width); ws += "\n"; } - let mut set_x = Chip8Video::new(initial_memory); set_x.cls(); + assert_eq!(set_x.format_as_string(), ws); } @@ -289,16 +345,16 @@ mod test { let to_poke = 0b10101010; let mut v = Chip8Video::default(); v.poke_byte(0x00, to_poke); - assert!(v.peek(0x00)); - assert!(!v.peek(0x01)); - assert!(v.peek(0x02)); - assert!(!v.peek(0x03)); - assert!(v.peek(0x04)); - assert!(!v.peek(0x05)); - assert!(v.peek(0x06)); - assert!(!v.peek(0x07)); + assert!(v.clone().peek(0x00)); + assert!(!v.clone().peek(0x01)); + assert!(v.clone().peek(0x02)); + assert!(!v.clone().peek(0x03)); + assert!(v.clone().peek(0x04)); + assert!(!v.clone().peek(0x05)); + assert!(v.clone().peek(0x06)); + assert!(!v.clone().peek(0x07)); for i in 0x8..CHIP8_VIDEO_MEMORY { - assert!(!v.peek(i as u16)); + assert!(!v.clone().peek(i as u16)); } } @@ -329,7 +385,7 @@ mod test { assert!(v.clone().peek(0x47)); // row 3 column 1 - assert!(!v.peek(0xC0)); + assert!(!v.clone().peek(0xC0)); assert!(v.clone().peek(0xC1)); assert!(!v.clone().peek(0xC2)); assert!(v.clone().peek(0xC3)); @@ -360,7 +416,7 @@ mod test { } let test_offset = (x_offset * 64 + y_offset) as u16; - assert!(!v.peek(test_offset)); + assert!(!v.clone().peek(test_offset)); assert!(!v.clone().peek(test_offset + 1)); assert!(!v.clone().peek(test_offset + 2)); assert!(!v.clone().peek(test_offset + 3)); @@ -394,8 +450,7 @@ mod test { #[test] fn write_checkboard() { let mut v = build_checkerboard(); - - assert_eq!(v.format_as_string(), read_test_result("test_video_write_checkerboard.asc")); + assert_eq!(v.clone().format_as_string(), read_test_result("test_video_write_checkerboard.asc")); } #[test] @@ -426,16 +481,7 @@ mod test { #[test] fn reset_test() { - let mut x = Chip8Video::default(); - - let to_draw = [CHIP8FONT_0, CHIP8FONT_1, CHIP8FONT_2, CHIP8FONT_3, CHIP8FONT_4, CHIP8FONT_5, CHIP8FONT_6, CHIP8FONT_7]; - for (index, sprite) in to_draw.iter().enumerate() { - let data_base_offset = index * 0x8; - for (index, offset) in (0..=0x100).step_by(0x40).enumerate() { - x.poke_byte((data_base_offset + offset) as u16, sprite[index]); - } - } - + let mut x = build_checkerboard(); x.reset(); assert_eq!(x.format_as_string(), read_test_result("test_reset_clears_video.asc")); } @@ -453,7 +499,7 @@ mod test { // it becomes unset and theres a frame changed assert_eq!(false, x.peek(0x00)); - assert_eq!(true, x.has_frame_changed); + assert_eq!(true, x.clone().has_frame_changed); } #[test] @@ -481,5 +527,70 @@ mod test { assert!(true); } + #[test] + fn scroll_down_1_row_test() { + let mut x = build_checkerboard(); + x.scroll_down(1); + assert_eq!(read_test_result("test_video_scroll_down_1.asc"), x.format_as_string()); + } + #[test] + fn scroll_down_10_row_test() { + let mut x = build_checkerboard(); + x.scroll_down(10); + assert_eq!(read_test_result("test_video_scroll_down_10.asc"), x.format_as_string()); + } + + #[test] + fn high_res_has_right_resolution() { + let mut x = build_checkboard_hd(); + println!("[{}]", x.format_as_string()); + assert_eq!(read_test_result("test_video_highdef.asc"), x.format_as_string()); + } + + #[test] + fn scroll_down_1_row_test_schip() { + let mut x = build_checkboard_hd(); + x.scroll_down(1); + + println!("[{}]", x.format_as_string()); + println!("[{}]", read_test_result("test_scroll_down_1_hd.asc")); + + assert_eq!(read_test_result("test_scroll_down_1_hd.asc"), x.format_as_string()); + } + + #[test] + fn scroll_down_10_row_test_schip() { + let mut x = build_checkboard_hd(); + x.scroll_down(10); + assert_eq!(read_test_result("test_scroll_down_10_hd.asc"), x.format_as_string()); + } + + #[test] + fn scroll_left_4_row_test_std_def() { + let mut x = build_checkerboard(); + x.scroll_left(); + assert_eq!(read_test_result("test_scroll_left_4.asc"), x.format_as_string()); + } + + #[test] + fn scroll_left_4_row_test_high_def() { + let mut x = build_checkboard_hd(); + x.scroll_left(); + assert_eq!(read_test_result("test_scroll_left_4_hd.asc"), x.format_as_string()); + } + + #[test] + fn scroll_right_4_row_test_std_def() { + let mut x = build_checkerboard(); + x.scroll_right(); + assert_eq!(read_test_result("test_scroll_right_4.asc"), x.format_as_string()); + } + + #[test] + fn scroll_right_4_row_test_high_def() { + let mut x = build_checkboard_hd(); + x.scroll_right(); + assert_eq!(read_test_result("test_scroll_right_4_hd.asc"), x.format_as_string()); + } } diff --git a/gemma/src/constants.rs b/gemma/src/constants.rs index 65a2c3a..ddb8c2d 100644 --- a/gemma/src/constants.rs +++ b/gemma/src/constants.rs @@ -63,3 +63,65 @@ pub const INST_ORY: &str = "ORY"; +pub const CHIP8_PROGRAM_LOAD_OFFSET: i32 = 0x200; +pub const CHIP8FONT_0: [u8; 5] = [0xF0, 0x90, 0x90, 0x90, 0xF0]; +pub const CHIP8FONT_1: [u8; 5] = [0x20, 0x60, 0x20, 0x20, 0x70]; +pub const CHIP8FONT_2: [u8; 5] = [0xF0, 0x10, 0xF0, 0x80, 0xF0]; +pub const CHIP8FONT_3: [u8; 5] = [0xF0, 0x10, 0xF0, 0x10, 0xF0]; +pub const CHIP8FONT_4: [u8; 5] = [0x90, 0x90, 0xF0, 0x10, 0x10]; +pub const CHIP8FONT_5: [u8; 5] = [0xF0, 0x80, 0xF0, 0x10, 0xF0]; +pub const CHIP8FONT_6: [u8; 5] = [0xF0, 0x80, 0xF0, 0x90, 0xF0]; +pub const CHIP8FONT_7: [u8; 5] = [0xF0, 0x10, 0x20, 0x40, 0x40]; +pub const CHIP8FONT_8: [u8; 5] = [0xF0, 0x90, 0xF0, 0x90, 0xF0]; +pub const CHIP8FONT_9: [u8; 5] = [0xF0, 0x90, 0xF0, 0x10, 0xF0]; +pub const CHIP8FONT_A: [u8; 5] = [0xF0, 0x90, 0xF0, 0x90, 0x90]; +pub const CHIP8FONT_B: [u8; 5] = [0xE0, 0x90, 0xE0, 0x90, 0xE0]; +pub const CHIP8FONT_C: [u8; 5] = [0xF0, 0x80, 0x80, 0x80, 0xF0]; +pub const CHIP8FONT_D: [u8; 5] = [0xE0, 0x90, 0x90, 0x90, 0xE0]; +pub const CHIP8FONT_E: [u8; 5] = [0xF0, 0x80, 0xF0, 0x80, 0xF0]; +pub const CHIP8FONT_F: [u8; 5] = [0xF0, 0x80, 0xF0, 0x80, 0x80]; + + +pub const SCHIPFONT_0: [u8; 0x10] = [0xF0, 0xFC, 0xFE, 0xFF, 0xF3, 0xE1, 0xE0, 0xE0, + 0xE0, 0xE0, 0xE0, 0xF1, 0xFB, 0xFF, 0xFE, 0x7C]; +pub const SCHIPFONT_1: [u8; 0x10] = [0x18, 0x3C, 0x7E, 0xFF, 0xF7, 0xE3, 0xC1, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0 +]; +pub const SCHIPFONT_2: [u8; 0x10] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC7, 0xC3, 0xC0, 0xE0, + 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0xFF, 0xFF +]; +pub const SCHIPFONT_3: [u8; 0x10] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC7, 0xC3, 0xC0, 0xE0, +0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0xFF, 0xFF]; +pub const SCHIPFONT_4: [u8; 0x10] = [0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xF7, 0xF3, 0xF1, + 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0]; +pub const SCHIPFONT_5: [u8; 0x10] = [0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x3F, 0x7F, 0x7F, + 0x01, 0x01, 0xC1, 0xE3, 0xFF, 0xFE, 0xFC, 0x78]; +pub const SCHIPFONT_6: [u8; 0x10] = [0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF, + 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78 +]; +pub const SCHIPFONT_7: [u8; 0x10] = [0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0x78, 0x3C, + 0x1E, 0x0F, 0x07, 0x03, 0x01, 0x01, 0x01, 0x01 +]; +pub const SCHIPFONT_8: [u8; 0x10] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF, + 0x7E, 0xFE, 0xC3, 0xC3, 0xFF, 0xFF, 0xFE, 0x7C +]; +pub const SCHIPFONT_9: [u8; 0x10] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF, + 0xFF, 0x7F, 0x03, 0x03, 0xC7, 0xFF, 0xFE, 0x7C +]; +pub const SCHIPFONT_A: [u8; 0x10] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF, + 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3 +]; +pub const SCHIPFONT_B: [u8; 0x10] = [0xFE, 0xFF, 0xFF, 0xFF, 0xC3, 0xC3, 0xFE, 0xFF, + 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xFE +]; +pub const SCHIPFONT_C: [u8; 0x10] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0x01, 0x01, + 0x01, 0x01, 0xC3, 0xC3, 0xFF, 0xFE, 0xFC, 0x78 +]; +pub const SCHIPFONT_D: [u8; 0x10] = [0xFE, 0xFF, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xFE, 0x7C +]; +pub const SCHIPFONT_E: [u8; 0x10] = [0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x03, 0xFF, + 0xFF, 0xFF, 0x03, 0x03, 0xFF, 0xFF, 0xFF, 0xFF +]; +pub const SCHIPFONT_F: [u8; 0x10] = [0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x03, 0xFF, + 0xFF, 0xFF, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03]; diff --git a/gemmaimgui/src/bin/support/emmagui_support.rs b/gemmaimgui/src/bin/support/emmagui_support.rs index eaf4122..8cf2f9e 100644 --- a/gemmaimgui/src/bin/support/emmagui_support.rs +++ b/gemmaimgui/src/bin/support/emmagui_support.rs @@ -16,6 +16,8 @@ use crate::ImGuiUiState; use crate::support::gui_file_list::GuiFileList; use super::ui_state; +const ROM_ROOT: &str = "/home/tmerritt/Projects/trevors_chip8_toy/resources/octoroms"; + pub struct GemmaImguiSupport {} const CELL_WIDTH: i32 = 5i32; @@ -49,23 +51,30 @@ impl GemmaImguiSupport { ui.window(format!("Display {cell_width}x{cell_height}")) .size([300.0, 300.0], Condition::Once) .build(|| { + let (width, height) = system_to_control.video_memory.get_resolution(); let origin = ui.cursor_screen_pos(); let fg = ui.get_window_draw_list(); - ui.text("This is the video display."); - for current_row in 0..=31 { - for current_column in 0..=63 { - let x_offset = origin[0] as i32 + (current_column * cell_width); + if (system_to_control.video_memory.is_highres()) { + ui.text("High Def Video here"); + + } else { + ui.text("StdDef video here."); + + for current_row in 0..=height { let y_offset = origin[1] as i32 + (current_row * cell_height); - let current_origin = [x_offset as f32, y_offset as f32]; - let current_limit = [(x_offset + cell_width) as f32, (y_offset + cell_height) as f32]; - let memory_offset = (current_row * 64 + current_column) as u16; - let to_render = system_to_control.video_memory.peek(memory_offset); - let color: ImColor32 = if to_render { - gui_state.on_colour - } else { - gui_state.off_colour - }; - fg.add_rect_filled_multicolor(current_origin, current_limit, color, color, color, color); + for current_column in 0..=width { + let x_offset = origin[0] as i32 + (current_column * cell_width); + let current_origin = [x_offset as f32, y_offset as f32]; + let current_limit = [(x_offset + cell_width) as f32, (y_offset + cell_height) as f32]; + let memory_offset = (current_row * width + current_column) as u16; + let to_render = system_to_control.video_memory.peek(memory_offset); + let color: ImColor32 = if to_render { + gui_state.on_colour + } else { + gui_state.off_colour + }; + fg.add_rect_filled_multicolor(current_origin, current_limit, color, color, color, color); + } } } }); @@ -79,7 +88,7 @@ impl GemmaImguiSupport { ui.text(format!("Step {:04x}", system_to_control.num_cycles()).as_str()); /* ROM Lister */ - let new_filename = GuiFileList::display_path(PathBuf::from("resources/roms"), &gui_state.filename_to_load, ui); + let new_filename = GuiFileList::display_path(PathBuf::from("/home/tmerritt/Projects/trevors_chip8_toy/resources/octoroms/"), &gui_state.filename_to_load, ui); if !new_filename.is_empty() { if new_filename != gui_state.filename_to_load { debug!("NEW FILENAME SELECTED -> {new_filename}"); @@ -89,22 +98,23 @@ impl GemmaImguiSupport { let mut buffer = Vec::new(); debug!("PREPARING TO LOAD {}", gui_state.filename_to_load); // let mut input_file = File::open(Path::new("./1-chip8-logo.ch8")).expect("put 1-chip8-logo.ch8 in this directory"); - let mut input_file = File::open(Path::new(&("resources/roms/".to_string() + &gui_state.filename_to_load))).expect("put 1-chip8-logo.ch8 in this directory"); + let mut input_file = File::open(Path::new(&("/home/tmerritt/Projects/trevors_chip8_toy/resources/octoroms/".to_string() + &gui_state.filename_to_load))).expect("put 1-chip8-logo.ch8 in this directory"); input_file.read_to_end(&mut buffer).expect("unable to read file"); system_to_control.load_bytes_to_system_memory((&*buffer).into()); } } ui.separator(); if ui.button("Step") { - system_to_control.one_step = true; + system_to_control.step(); + }; ui.same_line(); if ui.button("Run") { - system_to_control.core_should_run = true; + system_to_control.start(); } ui.same_line(); if ui.button("Stop") { - system_to_control.core_should_run = false; + system_to_control.stop(); } ui.same_line(); if ui.button("Reset") { diff --git a/gemmautil/src/bin/ch8asm.rs b/gemmautil/src/bin/ch8asm.rs index 937e2b1..ef5f21e 100644 --- a/gemmautil/src/bin/ch8asm.rs +++ b/gemmautil/src/bin/ch8asm.rs @@ -60,17 +60,6 @@ mod test { println!("RULE PAIR THING: {:?}", i); } - - let parsed = Chip8AsmParser::parse(Rule::record, "ADDI ; comment"); - for i in parsed { - println!("RULE PAIR THING: {:?}", i); - } - - - println!("PARSED: {:?}", - Chip8AsmParser::parse(Rule::record, "ADD 0x01 0x02 ; Comment") - ); - println!("PARSED: {:?}", Chip8AsmParser::parse(Rule::record, "ADD ADD ADD") ); @@ -82,6 +71,5 @@ mod test { println!("PARSED: {:?}", Chip8AsmParser::parse(Rule::record, "ADD 0x01 0x02 ; Comment") ); - } } \ No newline at end of file diff --git a/gemmautil/src/chip8_asm.pest b/gemmautil/src/chip8_asm.pest index 727d8de..054c309 100644 --- a/gemmautil/src/chip8_asm.pest +++ b/gemmautil/src/chip8_asm.pest @@ -3,5 +3,5 @@ instruction = { ASCII_ALPHA+ } parameter = { "0X" ~ ASCII_HEX_DIGIT+ } comment = { ";" ~ WHITESPACE* ~ ASCII* } parameters = { parameter ~ (WHITESPACE* ~ "," ~ WHITESPACE* ~ parameter)* } -record = { instruction ~ WHITESPACE ~ parameters? ~ WHITESPACE* ~ comment? } +record = { instruction ~ WHITESPACE* ~ parameters? ~ WHITESPACE* ~ comment? } file = { SOI ~ (record ~ ("\r\n" | "\n"))* ~ EOI } diff --git a/resources/octoroms/caveexplorer.8o b/resources/octoroms/caveexplorer.8o new file mode 100644 index 0000000..1084788 --- /dev/null +++ b/resources/octoroms/caveexplorer.8o @@ -0,0 +1,1213 @@ +########################################### +# +# Cave Explorer +# +# Discover the secrets of a mysterious +# tunnel system. A fairly elaborate +# Chip8 adventure game. Best played at +# about 20 cycles/frame. +# +# On the overworld, press ASWD to move. +# In platformer levels, A/D move, +# E picks up/sets down blocks, +# Q resets the level. +# +########################################### + +: font +0x20 0x20 0x20 0x00 0x20 0xF0 0x10 0x70 0x00 0x40 0xE0 0x90 0xE0 0x90 0x90 0x90 +0xE0 0x90 0xE0 0x90 0xE0 0x80 0x80 0xD0 0xB0 0xB0 0x90 0x90 0x90 0x90 0x60 0x60 +0x90 0x90 0x90 0x60 0x90 0xD0 0xB0 0x90 0x90 0x90 0x50 0x20 0x40 0x00 0x00 0x00 +0x00 0x00 0x60 0x90 0xF0 0x90 0x90 0xF0 0x90 0x90 0xF0 0x80 0xE0 0x80 0x80 0x80 +0x80 0xF0 0x80 0xE0 0x80 0xF0 0x40 0x40 0x40 0xF0 0x20 0x40 0x80 0xF0 0x20 0x20 +0x20 0xC0 0x60 0x90 0x80 0x90 0x60 0x90 0x90 0xB0 0x70 0x80 0xB0 0x90 0x70 0x80 +0x60 0x10 0xE0 0x90 0xA0 0xC0 0xA0 0x90 0x90 0xB0 0xB0 0xD0 0xF0 0x40 0x40 0x40 +0x40 0x90 0x90 0x70 0x10 0xE0 + +: special-complete +: title1 +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x07 0xE0 0x00 0x00 0x00 0x00 0x00 0x00 +0x08 0x18 0x00 0x00 0x00 0x00 0x00 0x00 0x10 0x04 0x00 0x00 0x00 0x00 0x00 0x00 +0x20 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x20 0x02 0x00 0x00 0x00 0x00 0x00 0x00 +0x28 0x21 0x00 0x00 0x00 0x00 0x00 0x00 0x40 0x01 0x00 0x00 0x00 0x00 0x00 0x00 +0x40 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x40 0x01 0x00 0x00 0x00 0x00 0x0F 0xC0 +0x4F 0x81 0x00 0x00 0x00 0x00 0x10 0x30 0x46 0x01 0x00 0x00 0x00 0x00 0x20 0x08 +0x20 0x02 0x00 0x00 0x00 0x00 0x30 0xE8 0x20 0x02 0x00 0x00 0x00 0x00 0x4F 0x04 +0x10 0x0C 0x00 0x00 0x00 0x00 0x50 0x84 0x1F 0xF6 0x00 0x00 0x00 0x00 0x40 0x04 +0x77 0x09 0x00 0x00 0x00 0x00 0x4F 0x84 0x97 0x90 0xC0 0x00 0x00 0x00 0x50 0x4C +0x0E 0xE0 0x20 0x00 0x00 0x00 0x20 0x1E 0x0C 0x00 0x10 0x00 0x00 0x00 0x7F 0xFF + +: block-reg-buffer +: phrase1 +0x0A 0x41 0x32 0x0C 0x71 0x2D 0x3A 0x1F 0x0A 0x2D 0x2D 0x2D 0x5E 0x52 0x35 0x1F +0x1F 0x3D 0x05 + +: phrase2 +0x2D 0x2D 0x2D 0x2D 0x2D 0x2D 0x2D 0x2D 0x2D 0x24 0x1F 0x00 + +: phrase3 +0x35 0x1F 0x67 0x2D 0x32 0x10 0x1F 0x1A 0x6C 0x2D 0x2D 0x2D 0x2D + +: level-buffer +: title2 +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x70 0x00 0x00 +0x00 0x3E 0x00 0x70 0x3C 0x8C 0x7F 0x00 0x01 0xC1 0x81 0x88 0x42 0x84 0x80 0xE0 +0x02 0x00 0x42 0x04 0x42 0x84 0x80 0x10 0x04 0x00 0x44 0x02 0x21 0x04 0x80 0x10 +0x08 0x00 0x44 0x01 0x21 0x05 0x00 0x10 0x10 0x03 0x88 0x01 0x10 0x05 0x07 0x10 +0x14 0x07 0x08 0x00 0x90 0x45 0x0F 0xD0 0x10 0x0C 0x08 0x60 0x90 0x09 0x06 0x70 +0x20 0x18 0x08 0x70 0x90 0x09 0x01 0xA0 0x20 0x18 0x10 0xB0 0x54 0x19 0x00 0x80 +0x28 0x10 0x10 0x90 0x4C 0x1A 0x07 0x00 0x20 0x10 0xD0 0xF0 0xA8 0x32 0x46 0x60 +0x20 0x0F 0x58 0x00 0x28 0xB2 0x03 0x90 0x29 0x20 0xD1 0x00 0x24 0x33 0x00 0x10 +0x30 0x09 0xD4 0x72 0x17 0x73 0x40 0x10 0x14 0x43 0x98 0xF8 0xB6 0x63 0x02 0x10 +0x1A 0xA7 0x1B 0x9A 0x33 0x61 0xD0 0x30 0x0D 0x1E 0x1F 0x8D 0x63 0xC1 0xFA 0xD0 +0x0F 0xFC 0x0D 0x07 0xE1 0x81 0xFF 0x70 0x04 0x60 0x00 0x02 0xC0 0x00 0x8C 0x20 +0x00 0x00 0x00 0x00 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0x00 0xFB 0x37 0x98 0x73 0xCF 0xBC 0x00 0x00 0xFB 0xF7 0xD8 0xFB 0xEF 0xBE 0x00 +0x00 0xC1 0xE6 0xD8 0xDB 0x6C 0x36 0x00 0x00 0xF0 0xC7 0xD8 0xDB 0xEF 0x3E 0x00 +0x00 0xC1 0xE7 0x98 0xDB 0xCC 0x3C 0x00 0x00 0xFB 0xF6 0x1E 0xFB 0x6F 0xB6 0x00 +0x00 0xFB 0x36 0x1E 0x73 0x6F 0xB6 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + +: bus +0x00 0x04 0x00 0x3D 0x97 0xFF 0xFF 0xFF 0xFF 0xFD 0xFF 0x9D 0x4B 0xFF 0x8B 0x47 +0x20 0x04 0x00 0x5D 0xCB 0xFF 0xD8 0x4F 0x26 0x04 0x00 0x1D 0x05 0xFF 0xDB 0x5F +0x21 0x04 0x00 0x1D 0x85 0xFF 0xDB 0x47 0x20 0x84 0x7C 0x1C 0x05 0xFF 0xFF 0xFF +0x20 0x84 0xDA 0x5D 0xC5 0xFF 0x8B 0x47 0x20 0x94 0xBC 0xDD 0xE5 0xFF 0x99 0x5B +0x20 0xB4 0xE6 0x1D 0xE6 0x1F 0xBA 0x5B 0x20 0x94 0xC2 0xDD 0xCF 0xE7 0x8B 0x47 +0x20 0x85 0x7D 0xDC 0x3F 0xF9 0xFF 0xFF 0x2F 0xF5 0x83 0x9F 0xFF 0xFE 0xFF 0xFF +0x20 0x05 0xFF 0x1F 0xFF 0xFF 0x7F 0xFF 0xFF 0xFC 0xFE 0x1F 0xFF 0xF3 0xBF 0x07 +0xFF 0xFC 0xFE 0x1F 0xFF 0xED 0xDE 0xFB 0xA2 0x2D 0xF8 0x0C 0x07 0xDD 0xED 0xFD +0x2A 0xA8 0x07 0xF7 0xF9 0xD9 0xE3 0x7E 0xAA 0xAB 0xFF 0xEC 0x1E 0xD6 0xF3 0xFE +0xA2 0x25 0xF8 0x00 0x06 0xE7 0x1B 0xFE 0xFF 0xFA 0x07 0xF8 0x03 0x77 0xC0 0x7E +0x00 0x0B 0xBF 0xFE 0x03 0x7B 0xF8 0xFC 0xFF 0xFB 0x9F 0xFF 0x81 0x7C 0xED 0xF8 +0x00 0x0B 0xBF 0xFF 0x81 0x7F 0x0E 0x00 0xFF 0xFB 0xAF 0xF0 0x61 0x7F 0xEE 0x60 +0xFF 0xFB 0xBA 0x3F 0xF9 0x7F 0xDC 0x98 0xFF 0xFD 0xBD 0xFF 0xFE 0x3F 0xDC 0xF8 +0xFF 0xFD 0xBC 0xFF 0xFF 0xCF 0xDC 0xFC 0x00 0x01 0xBD 0x7F 0xFF 0xF1 0xBC 0xFC +0xFF 0xFD 0xBD 0xBF 0x00 0x0E 0x3C 0xDC 0x00 0x01 0x1D 0xC8 0xFF 0xFF 0x8F 0xDE +0x00 0x00 0x1D 0xF3 0xFF 0xFF 0xF3 0xBE 0x00 0x00 0x04 0xFB 0xFF 0xFF 0xFC 0x7C + +: mouth 0xF8 + +: rumbletext # "YOU HEAR A RUMBLE IN THE DISTANCE" +0x71 0x1F 0x1A 0x2D 0x35 0x41 0x32 0x0A 0x2D 0x2D 0x2D 0x2D 0x32 0x2D 0x0A 0x1A +0x17 0x10 0x3D 0x41 0x2D 0x45 0x24 0x2D 0x6C 0x35 0x41 0x2D 0x0C 0x45 0x5E 0x6C +0x32 0x24 0x52 0x41 + +: uselesstext # "JUST A BUNCHOF GOLD? HOWUSELESS!" +0x4D 0x1A 0x5E 0x6C 0x2D 0x32 0x2D 0x10 0x1A 0x24 0x52 0x35 0x1F 0x3A 0x2D 0x5A +0x1F 0x3D 0x0C 0x05 0x2D 0x35 0x1F 0x67 0x1A 0x5E 0x41 0x3D 0x41 0x5E 0x5E 0x00 + +: exittext # "CLIMBING OUTYOU EMERGE TO DAZZLING SUNLIGHT" +0x52 0x3D 0x45 0x17 0x10 0x45 0x24 0x5A 0x2D 0x1F 0x1A 0x6C 0x71 0x1F 0x1A 0x2D +0x41 0x17 0x41 0x0A 0x5A 0x41 0x2D 0x2D 0x6C 0x1F 0x2D 0x0C 0x32 0x49 0x49 0x3D +0x45 0x24 0x5A 0x2D 0x5E 0x1A 0x24 0x3D 0x45 0x5A 0x35 0x6C + +: pyramidtext # "A VISION OF A PYRAMID? ASECRET WALL?" +0x32 0x2D 0x27 0x45 0x5E 0x45 0x1F 0x24 0x2D 0x1F 0x3A 0x2D 0x32 0x2D 0x12 0x71 +0x0A 0x32 0x17 0x45 0x0C 0x05 0x2D 0x32 0x5E 0x41 0x52 0x0A 0x41 0x6C 0x2D 0x67 +0x32 0x3D 0x3D 0x05 + +: skulltext # "SOMEONE LEFTTHEIR SKULL HERE? GROSS!" +0x5E 0x1F 0x17 0x41 0x1F 0x24 0x41 0x2D 0x3D 0x41 0x3A 0x6C 0x6C 0x35 0x41 0x45 +0x0A 0x2D 0x5E 0x63 0x1A 0x3D 0x3D 0x2D 0x35 0x41 0x0A 0x41 0x05 0x2D 0x5A 0x0A +0x1F 0x5E 0x5E 0x00 + +: puzzlestext # "YOU MUST RETURN TO WHERE THIS ALL BEGAN" +0x71 0x1F 0x1A 0x2D 0x17 0x1A 0x5E 0x6C 0x2D 0x2D 0x2D 0x2D 0x0A 0x41 0x6C 0x1A +0x0A 0x24 0x2D 0x6C 0x1F 0x2D 0x2D 0x2D 0x67 0x35 0x41 0x0A 0x41 0x2D 0x6C 0x35 +0x45 0x5E 0x2D 0x2D 0x32 0x3D 0x3D 0x2D 0x10 0x41 0x5A 0x32 0x24 + +: deadendtext # "A DEAD END? NUTS!" +0x32 0x2D 0x0C 0x41 0x32 0x0C 0x2D 0x41 0x24 0x0C 0x05 0x2D 0x24 0x1A 0x6C 0x5E +0x00 + +: mazetext # "SNWEW" +0x5E 0x24 0x67 0x41 0x67 + +: draw-bitmap + clear + v0 := 0 # x + v1 := 0 # y + v2 := 0 # byte + v3 := 1 # constant + loop + sprite v0 v1 1 + i += v3 + v2 += 1 + v0 += 8 + if v0 == 64 then v1 += 1 + if v0 == 64 then v0 := 0 + if v1 != 32 then + again +; + +: draw-text + v1 := 2 # x + v2 := 1 # y + v3 := 0 # byte + # v4 contains length + loop + : text-addr i := 0 # self-modify to alter + i += v3 + load v0 + i := font + i += v0 + sprite v1 v2 5 + v1 += 5 + if v1 == 62 then v2 += 6 + if v1 == 62 then v1 := 2 + v3 += 1 + if v3 != v4 then + again +; + +: wait + v0 := 128 + delay := v0 + loop + v0 := delay + if v0 != 0 then + again +; + +: swapmouth + i := mouth + v0 := 4 + v1 := 22 + sprite v0 v1 1 + v0 := 52 + v1 := 29 + sprite v0 v1 1 +; + +: draw-phrase-1 + :unpack 0xA phrase1 + i := text-addr + save v1 + v4 := 19 + draw-text +; + +: draw-phrase-2 + :unpack 0xA phrase2 + i := text-addr + save v1 + v4 := 12 + draw-text +; + +: draw-phrase-3 + :unpack 0xA phrase3 + i := text-addr + save v1 + v4 := 13 + draw-text +; + +########################################### +# +# Block pushing puzzle +# +########################################### + +: solid 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +: empty 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF +: floor 0x00 0xFE 0x55 0x22 0x88 0x00 0x00 0x00 +: roof 0x00 0x00 0x00 0x11 0x91 0x8B 0x8F 0xDF +: exit 0xC3 0xBD 0xBD 0xBD 0xB9 0xB9 0xBD 0xBD +: block 0x81 0x7E 0x5A 0x7E 0x7E 0x5A 0x7E 0x81 + +: left 0xE7 0xE7 0xC3 0x81 0x82 0x42 0xDB 0x93 +: right 0xE7 0xE7 0xC3 0x81 0x41 0x42 0xDB 0xC9 + +:const SOLID 0 +:const EMPTY 1 +:const FLOOR 2 +:const ROOF 3 +:const EXIT 4 +:const BLOCK 5 +:const PLAYER_L 6 +:const PLAYER_R 7 + +:alias levelno ve +:alias playerx vd +:alias playery vc +:alias input vb +:alias direction va +:alias win v9 + +# v0-v8 reserved for temporary use. +# v0-v7 are used together for fast buffer copies. + +# player facing +:const FACING_LEFT 0 +:const FACING_RIGHT 1 + +# input keys: +:const MOVE_LT 7 +:const MOVE_RT 9 +:const RESET 4 +:const ACTION 6 + +########################################### +# +# Level data +# +########################################### + +: level-0 + 4 1 1 3 1 1 3 0 + 2 1 1 1 1 1 1 3 + 0 2 1 1 1 1 1 1 + 0 0 2 2 2 2 1 6 +: level-1 + 4 1 3 1 3 1 1 1 + 2 1 1 1 1 1 1 5 + 0 1 1 6 1 1 2 2 + 0 1 2 2 1 5 0 0 +: level-2 + 3 1 1 1 1 1 1 4 + 1 1 1 2 2 2 2 2 + 5 1 1 1 1 1 1 1 + 2 5 1 1 6 1 1 5 +: level-3 + 1 1 1 1 3 1 1 3 + 4 1 6 1 1 1 1 5 + 2 1 2 1 1 1 2 2 + 0 1 0 5 1 1 0 0 +: level-4 + 5 1 3 0 3 1 1 4 + 1 1 1 3 1 1 1 2 + 1 1 1 1 1 1 1 0 + 2 2 1 6 1 5 2 0 +: level-5 + 4 1 1 1 1 1 1 1 + 2 1 1 6 1 5 1 5 + 0 1 1 2 1 1 1 1 + 0 1 1 0 1 5 1 5 +: level-6 + 0 3 1 5 1 1 1 4 + 3 1 1 1 1 1 1 2 + 1 1 1 5 2 1 1 0 + 5 5 1 6 0 1 1 0 +: level-7 + 3 3 1 4 1 5 3 3 + 5 5 1 1 1 1 5 5 + 1 1 1 1 1 1 1 1 + 2 1 1 6 1 1 1 5 + +########################################### +# +# Level utilities +# +########################################### + +: level-table + i := level-0 return + i := level-1 return + i := level-2 return + i := level-3 return + i := level-4 return + i := level-5 return + i := level-6 return + i := level-7 return + +: get-level + v0 <<= levelno + v0 <<= v0 + jump0 level-table + +: copy-level + v8 := 0 + loop + get-level + i += v8 + load v7 + + i := level-buffer + i += v8 + save v7 + + v8 += 8 + if v8 != 32 then + again +; + +: get-tile + # takes tile index in v0 + v0 <<= v0 + v0 <<= v0 + v0 <<= v0 + i := solid + i += v0 +; + +: spawn-player + direction := FACING_LEFT + win := 0 + playerx := v1 + playerx >>= playerx + playerx >>= playerx + playerx >>= playerx + playery := v2 + playery >>= playery + playery >>= playery + playery >>= playery +; + +: init-level + copy-level + clear + v1 := 0 # sprite x + v2 := 0 # sprite y + v3 := 0 # tile index + loop + i := level-buffer + i += v3 + load v0 + if v0 == PLAYER_L then spawn-player + get-tile + sprite v1 v2 8 + v3 += 1 + v1 += 8 + if v1 == 64 then v2 += 8 + if v1 == 64 then v1 := 0 + if v2 != 32 then + again +; + +: index-at + # takes x/y in v1/v2 + # returns type in v0 + v0 <<= v2 + v0 <<= v0 + v0 <<= v0 + v0 += v1 + i := level-buffer + i += v0 +; + +: draw-at + # takes x/y in v1/v2 + # trashes v0-v2 + index-at + load v0 + get-tile + v1 <<= v1 + v1 <<= v1 + v1 <<= v1 + v2 <<= v2 + v2 <<= v2 + v2 <<= v2 + sprite v1 v2 8 +; + +: copy-loc + v1 := v3 + v2 := v4 +; + +: set-at + # takes x/y in v3/v4, value in v5 + copy-loc + draw-at + copy-loc + index-at + v0 := v5 + save v0 + copy-loc + draw-at +; + +########################################### +# +# Block pusher player helpers +# +########################################### + +:alias canpass v7 +:alias deltadir v6 + +: player-loc + v1 := playerx + v2 := playery +; + +: player-copy + v3 := playerx + v4 := playery +; + +: player-ahead + player-loc + v1 += deltadir +; + +: player-above + player-loc + v2 += -1 +; + +: player-below + player-loc + v2 += 1 +; + +: draw-player + player-loc + draw-at +; + +: player-above-type + player-above + index-at + load v0 +; + +: carrying? + # returns result in v0 + v0 := 0 + if playery == 0 then return + player-above-type + if v0 != BLOCK then v0 := 0 + if v0 == BLOCK then v0 := 1 +; + +########################################### +# +# Block pusher movement +# +########################################### + +: passable? + # takes x/y in v1/v2 + # returns flag in canpass + canpass := 0 + if v1 > 7 then return + if v2 > 3 then return + index-at + load v0 + if v0 == EMPTY then canpass := 1 + if v0 == EXIT then canpass := 1 +; + +: fall-scan + player-copy + v3 += deltadir + loop + copy-loc + v2 += 1 + passable? + while canpass == 1 + v4 += 1 + again +; + +: move-player + # if we're stepping onto + # an exit, we win. + copy-loc + index-at + load v0 + if v0 == EXIT then win := 1 + + # takes x/y in v3/v4 + draw-player + player-loc + index-at + v0 := EMPTY + save v0 + draw-player + + playerx := v3 + playery := v4 + + v5 := PLAYER_L + v5 += direction + set-at +; + +: hide-block + v5 := EMPTY + +: set-block + player-copy + v4 += -1 + set-at +; + +: show-block + v5 := BLOCK + jump set-block + +: climb-move + player-copy + v3 += deltadir + v4 += -1 + move-player +; + +: climb-carry + # can't climb if blocked above-side + player-above + v1 += deltadir + passable? + if canpass != 1 then return + + # can't climb if blocked above-above-side + player-above + v1 += deltadir + v2 += -1 + passable? + if canpass != 1 then return + + hide-block + climb-move + show-block +; + +: climb + # can't climb if blocked above: + player-above + passable? + if canpass != 1 then return + + # can't climb if blocked above-side + player-above + v1 += deltadir + passable? + if canpass != 1 then return + + climb-move +; + +: carry + # make sure we don't need to climb: + player-loc + v1 += deltadir + passable? + if canpass != 1 then jump climb-carry + + # make sure there's horizontal space for the block + player-loc + v1 += deltadir + v2 += -1 + passable? + if canpass != 1 then return + + hide-block + + # scan down and 'fall': + fall-scan + move-player + + show-block +; + +: walk + # make sure we aren't carrying a block: + carrying? + if v0 != 0 then jump carry + + # make sure we don't need to climb: + player-loc + v1 += deltadir + passable? + if canpass != 1 then jump climb + + # scan down and 'fall': + fall-scan + move-player +; + +: walk-left + deltadir := -1 + if direction == FACING_LEFT then jump walk + + # face left + player-copy + v5 := PLAYER_L + set-at + direction := FACING_LEFT +; + +: walk-right + deltadir := 1 + if direction == FACING_RIGHT then jump walk + + # face right + player-copy + v5 := PLAYER_R + set-at + direction := FACING_RIGHT +; + +: drop + # there must be at least one empty space + player-ahead + passable? + if canpass != 1 then return + + # erase block + player-copy + v4 += -1 + v5 := EMPTY + set-at + + # scan for drop position + fall-scan + + # draw repositioned block + v5 := BLOCK + set-at +; + +: action + deltadir := 1 + if direction == FACING_LEFT then deltadir := -1 + carrying? + if v0 != 0 then jump drop + + # we can only pick up block tiles + player-ahead + index-at + load v0 + if v0 != BLOCK then return + + # the space above us must be empty + player-above-type + if v0 != EMPTY then return + + # erase block + player-copy + v3 += deltadir + v5 := EMPTY + set-at + + # draw repositioned block + player-copy + v4 += -1 + v5 := BLOCK + set-at +; + +########################################### +# +# Block pusher main routine +# +########################################### + +: puzzle-finished-count 0 + +: block-puzzle + i := block-reg-buffer + save vd + + init-level + loop + input := key + if input == RESET then init-level + if input == MOVE_LT then walk-left + if input == MOVE_RT then walk-right + if input == ACTION then action + if win == 0 then + again + + v0 := 32 + buzzer := v0 + clear + + i := puzzle-finished-count + load v0 + v0 += 1 + i := puzzle-finished-count + save v0 + + i := block-reg-buffer + load vd +; + +########################################### +# +# Overworld +# +########################################### + +: rocks1 0x00 0x40 0x00 0x00 +: rocks2 0x00 0x20 0x40 0x00 +: rocks3 0x00 0x40 0x20 0x00 +: rocks4 0x00 0x00 0x00 0x00 + +: path 0x60 0xF0 0xF0 0x60 +: man 0x00 0x60 0x60 0x00 +: target 0x70 0x40 0xF0 0x50 + +: bits 1 2 4 8 16 32 64 128 + +:alias boardno vd +:alias manx vc +:alias many vb +:alias specialx va +:alias specialy v9 +:alias oldx v8 +:alias oldy v7 +:alias specialflag v6 + +########################################### +# +# Board data +# +########################################### + +: special-pos + 3 6 # board 0 + 7 4 # board 1 + 14 6 # board 2 + 7 4 # board 3 + 3 3 # board 4 + 12 4 # board 5 + 7 5 # board 6 + 7 4 # board 7 + 7 6 # board 8 + 9 4 # board 9 + 10 4 # board A + 11 3 # board B + 5 3 # board C + 5 3 # board D + 5 3 # board E + 5 3 # board F + +# board in each direction +# 0 1 2 3 4 5 6 7 8 9 A B C D E F +: board-n + 0x0 0x2 0x1 0x5 0xA 0x6 0x7 0x7 0x8 0x9 0x3 0xC 0xC 0xC 0xC 0xE +: board-e + 0x3 0x4 0x2 0x1 0x9 0x8 0x6 0x7 0xA 0x9 0xA 0xB 0xD 0xE 0xF 0xD +: board-s + 0x0 0x2 0x1 0xA 0xD 0x3 0x5 0x6 0x8 0x9 0x4 0xB 0xB 0xB 0xB 0xB +: board-w + 0x0 0x3 0x2 0x0 0x1 0x5 0x6 0x7 0x5 0x4 0x8 0xB 0xD 0xD 0x3 0xF + +# pixel data +: board0 + 0x28 0xEB 0x0A 0x7A 0x02 0xEF 0x28 0x2A + 0x6A 0x4A 0x5A 0x42 0x7A 0x0A 0x6E 0x28 +: board1 + 0x08 0x08 0x4A 0x08 0xFF 0x40 0x5E 0x52 + 0x42 0x7E 0x40 0xCF 0x08 0x4A 0x08 0x08 +: board2 + 0x00 0x70 0x50 0x50 0xD7 0x54 0x54 0x54 + 0x54 0x54 0x54 0xD5 0x14 0x14 0x7C 0x00 +: board3 + 0x28 0x28 0x28 0xEB 0x0A 0x6A 0x0A 0x3A + 0x22 0x3A 0x2A 0x2E 0x20 0x38 0x08 0x28 +: board4 + 0x08 0x08 0x1C 0x7F 0x5C 0xC9 0x08 0x1C + : gate1 0x60 0x1C 0x08 0x08 0x1C : gate2 0x60 0x1C 0x08 +: board5 + 0x10 0x00 0x03 0xF3 0x10 0x10 0x10 0xDF + 0xD0 0x16 0x16 0x10 0x10 0x10 0x10 0x10 +: board6 + 0x00 0x02 0x4A 0x66 0x70 0x78 0x7C 0xFF + 0x7C 0x78 0x70 0x66 0x4A 0x02 0x00 0x00 +: board7 + 0x00 0x76 0x52 0x5A 0x04 0x00 0x39 0xFB + 0x39 0x00 0x04 0x5A 0x52 0x76 0x00 0x00 +: board8 + 0x10 0x7E 0x08 0x7E 0x10 0x7E 0x08 0x7E + 0x10 0x7E 0x08 0x7E 0x10 0x7E 0x10 0x10 +: board9 + 0x08 0x08 0xD8 0x52 0xD0 0x10 0x38 0x2B + 0x3A 0x12 0x02 0xC2 0x4E 0x78 0x10 0x18 +: boardA + 0x10 0x54 0x10 0xFF 0x04 0x7C 0x40 0x7C + 0x04 0x1C 0x10 0x00 0x28 0x6C 0x74 0x38 +: boardB + 0x00 0xF2 0xEA 0x02 0x02 0xC3 0x0A 0xFA + 0x02 0xFA 0xA2 0x8A 0x22 0xF2 0x9A 0x38 +: boardC + 0x08 0x08 0x08 0x3E 0x22 0xFB 0x22 0x3E + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 +: boardD + 0x08 0x08 0x08 0x3E 0x22 0xFB 0x22 0x3E + 0x08 0x08 0x08 0x08 0x08 0x08 0x0A 0x08 +: boardE + 0x08 0x08 0x08 0x3E 0x22 0xFB 0x22 0x3E + 0x08 0x08 0x08 0x08 0x0A 0x08 0x0A 0x08 +: boardF + 0x08 0x08 0x08 0x3E 0x22 0xFB 0x22 0x3E + 0x08 0x08 0x0A 0x08 0x0A 0x08 0x0A 0x08 + +########################################### +# +# Overworld game logic +# +########################################### + +: secret-wall + if boardno != 6 then return + if v4 != 7 then return + v5 := 0b11111100 +; + +: draw-board + clear + v1 := 0 # x tile + v4 := 0 # data offset + v3 <<= boardno # data base + v3 <<= v3 + v3 <<= v3 + v3 <<= v3 + loop + i := board0 + i += v3 + i += v4 + load v0 + v5 := v0 # column + v2 := 0 # y tile + secret-wall + + loop + i := rocks1 + v0 := random 0b1100 + i += v0 + v5 >>= v5 + if vf != 0 then i := path + sprite v1 v2 4 + v2 += 4 + if v2 != 32 then + again + + v1 += 4 + v4 += 1 + if v4 != 16 then + again + + specialx := -1 + specialy := -1 + i := special-complete + i += boardno + load v0 + if v0 != 0 then return + + v0 <<= boardno + i := special-pos + i += v0 + load v1 + specialx := v0 + specialy := v1 + + v0 <<= v0 + v0 <<= v0 + v1 <<= v1 + v1 <<= v1 + i := path + sprite v0 v1 4 + i := target + sprite v0 v1 4 +; + +: draw-man + v0 <<= manx + v0 <<= v0 + v1 <<= many + v1 <<= v1 + i := man + sprite v0 v1 4 +; + +: copy-pos + oldx := manx + oldy := many +; + +: try-special + if manx != specialx then return + if many != specialy then return + specialflag := 1 +; + +: try-move + # fetch column data + i := board0 + v0 <<= boardno + v0 <<= v0 + v0 <<= v0 + v0 <<= v0 + i += v0 + + v3 := 15 + v2 := manx + v2 &= v3 + i += v2 + load v0 + v1 := v0 + + # fetch row mask + i := bits + v3 := 7 + v2 := many + v2 &= v3 + i += v2 + load v0 + + v0 &= v1 + vf := 1 + if v0 != 0 then try-special + if v0 != 0 then return + + # roll back + manx := oldx + many := oldy + vf := 0 +; + +: change-board + i += boardno + load v0 + if v0 == boardno then return + boardno := v0 + draw-board +; + +: overworld-walk-w + manx += -1 + try-move + if vf == 0 then return + if manx != -1 then return + i := board-w + manx := 15 + jump change-board + +: overworld-walk-e + manx += 1 + try-move + if vf == 0 then return + if manx != 16 then return + manx := 0 + i := board-e + jump change-board + +: overworld-walk-n + many += -1 + try-move + if vf == 0 then return + if many != -1 then return + many := 7 + i := board-n + jump change-board + +: overworld-walk-s + many += 1 + try-move + if vf == 0 then return + if many != 8 then return + many := 0 + i := board-s + jump change-board + +: overworld-walk + if v2 == 7 then jump overworld-walk-w + if v2 == 9 then jump overworld-walk-e + if v2 == 5 then jump overworld-walk-n + if v2 == 8 then jump overworld-walk-s +; + +########################################### +# +# Special scripted events +# +########################################### + +: rumble + v0 := 0b00001100 + save v0 + + clear + :unpack 0xA rumbletext + i := text-addr + save v1 + v4 := 36 + draw-text + v0 := key +; + +: open-gate-1 + i := gate1 + rumble +; + +: open-gate-2 + i := gate2 + rumble +; + +: useless-gold + clear + :unpack 0xA uselesstext + i := text-addr + save v1 + v4 := 32 + draw-text + v0 := key +; + +: pyramid-hint + clear + :unpack 0xA pyramidtext + i := text-addr + save v1 + v4 := 36 + draw-text + v0 := key +; + +: gross-skull + clear + :unpack 0xA skulltext + i := text-addr + save v1 + v4 := 36 + draw-text + v0 := key +; + +: dead-end + clear + :unpack 0xA deadendtext + i := text-addr + save v1 + v4 := 17 + draw-text + v0 := key +; + +: maze-hint + clear + :unpack 0xA mazetext + i := text-addr + save v1 + v4 := 5 + draw-text + v0 := key +; + +: nop ; + +: puzzle-0 ve := 0 block-puzzle ; +: puzzle-1 ve := 1 block-puzzle ; +: puzzle-2 ve := 2 block-puzzle ; +: puzzle-3 ve := 3 block-puzzle ; +: puzzle-4 ve := 4 block-puzzle ; +: puzzle-5 ve := 5 block-puzzle ; +: puzzle-6 ve := 6 block-puzzle ; + +: puzzle-7 + ve := 7 + block-puzzle + + clear + :unpack 0xA exittext + i := text-addr + save v1 + v4 := 44 + draw-text + v0 := key + + i := bus + draw-bitmap + loop again + +: special-things + jump puzzle-7 # 0 + jump useless-gold # 1 + jump puzzle-1 # 2 + jump puzzle-0 # 3 + jump open-gate-2 # 4 + jump gross-skull # 5 + jump puzzle-2 # 6 + jump open-gate-1 # 7 + jump puzzle-3 # 8 + jump puzzle-6 # 9 + jump dead-end # A + return # B + jump pyramid-hint # C + jump puzzle-4 # D + jump maze-hint # E + jump puzzle-5 # F + +: check-puzzles + i := puzzle-finished-count + load v0 + if v0 != 7 then return + v0 += 1 + i := puzzle-finished-count + save v0 + + clear + :unpack 0xA puzzlestext + i := text-addr + save v1 + v4 := 45 + draw-text + v0 := key + + i := board-e + v0 := 0 + save v0 +; + +########################################### +# +# Overworld main routine +# +########################################### + +: do-special + i := special-complete + i += boardno + v0 := 1 + save v0 + + v0 <<= boardno + jump0 special-things + +: main + # intro sequence + i := title1 + draw-bitmap + draw-phrase-1 + wait + draw-phrase-1 + swapmouth + draw-phrase-2 + wait + draw-phrase-2 + swapmouth + draw-phrase-3 + wait + draw-phrase-3 + i := title2 + draw-bitmap + v0 := key + + # main routine + manx := 10 + many := 4 + draw-board + loop + draw-man + v2 := key + draw-man + copy-pos + specialflag := 0 + overworld-walk + if specialflag != 0 then do-special + check-puzzles + if specialflag != 0 then draw-board + again diff --git a/resources/octoroms/chipwar.8o b/resources/octoroms/chipwar.8o new file mode 100644 index 0000000..4dbc410 --- /dev/null +++ b/resources/octoroms/chipwar.8o @@ -0,0 +1,1016 @@ +########################################### +# +# ChipWar +# +# War. War never changes. +# This game takes place on a toroidal field +# of 16 territories. Each has some number +# of troops stationed there (1-5). +# at the beginning of the game, territories +# are divided between you (white) +# and an AI opponent (black). +# +# You can order your territories to attack +# adjacent enemy territories provided you +# have more than one troop available. +# When you attack, a number of 8-sided dice +# will be rolled and summed based on the +# number of attackers and defenders. +# If the attackers win, they capture the +# territory and transfer all but one of +# their troops over. +# If the defenders win, they destroy all +# but one of the attackers and lose one troop, +# or none if they have only a single troop. +# +# After white has taken a turn, +# each territory has a 50% chance of +# producing one new troop. +# The game ends when black or white has +# conquered the entire map. +# +# When selecting a territory, ASWD move +# your cursor, E selects the territory +# and Q ends your turn. +# With a territory selected, ASWD choose +# the direction in which to attack, +# E confirms the attack and Q cancels. +# When the game is over press any key to +# play again. +# +# Based loosely on the Flash game DiceWars: +# +# http://www.gamedesign.jp/flash/dice/dice.html +# +########################################### + +: whitedice + 0xFE 0x82 0x82 0x92 0x82 0x82 0xFE 0x00 # 1 + 0xFE 0x82 0x8A 0x82 0xA2 0x82 0xFE 0x00 # 2 + 0xFE 0x82 0xAA 0x82 0x92 0x82 0xFE 0x00 # 3 + 0xFE 0x82 0xAA 0x82 0xAA 0x82 0xFE 0x00 # 4 + 0xFE 0x82 0xAA 0x92 0xAA 0x82 0xFE 0x00 # 5 + +: blackdice + 0xFE 0xFE 0xFE 0xEE 0xFE 0xFE 0xFE 0x00 # 1 + 0xFE 0xFE 0xF6 0xFE 0xDE 0xFE 0xFE 0x00 # 2 + 0xFE 0xFE 0xD6 0xFE 0xEE 0xFE 0xFE 0x00 # 3 + 0xFE 0xFE 0xD6 0xFE 0xD6 0xFE 0xFE 0x00 # 4 + 0xFE 0xFE 0xD6 0xEE 0xD6 0xFE 0xFE 0x00 # 5 + +: arrows + 0x10 0x38 0x7C 0xFE 0x38 0x38 0x38 0x00 # n + 0x10 0x18 0xFC 0xFE 0xFC 0x18 0x10 0x00 # e + 0x38 0x38 0x38 0xFE 0x7C 0x38 0x10 0x00 # s + 0x10 0x30 0x7E 0xFE 0x7E 0x30 0x10 0x00 # w + +: p1 + 0x00 0x78 0x44 0x44 0x78 0x40 0x40 0x00 + 0x10 0x30 0x10 0x10 0x7C 0x00 +: p2 + 0xFE 0x86 0xBA 0xBA 0x86 0xBE 0xBE 0xFE + 0xC6 0xBA 0xE6 0xDE 0x82 0xFE + +: curs1 0xAA 0x00 0x80 0x00 0x80 0x00 0x80 0x00 0xAA +: curs2 0x80 0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x80 + +: empty 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +: fill 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF +: plus 0x00 0x40 0xE0 0x40 + +# game over +: go1 0x7E 0xFE 0xC0 0xDE 0xC6 0xFE 0x7E 0x00 0x7C 0xFE 0xC6 0xC6 0xC6 0xFE 0x7C +: go2 0x7C 0xFE 0xC6 0xFE 0xC6 0xC6 0xC6 0x00 0xC6 0xC6 0xC6 0xC6 0xEE 0x7C 0x38 +: go3 0xC6 0xEE 0xFE 0xD6 0xC6 0xC6 0xC6 0x00 0x7E 0xFE 0xC0 0xF8 0xC0 0xFE 0x7E +: go4 0x7E 0xFE 0xC0 0xF8 0xC0 0xFE 0x7E 0x00 0xFC 0xFE 0xC6 0xFE 0xFC 0xCE 0xC6 + +# you win +: yw1 0xC6 0xC6 0xEE 0x7C 0x38 0x38 0x38 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +: yw2 0x7C 0xFE 0xC6 0xC6 0xC6 0xFE 0x7C 0x00 0x63 0x63 0x63 0x6B 0x7F 0x77 0x63 +: yw3 0xC6 0xC6 0xC6 0xC6 0xC6 0xFE 0x7C 0x00 0x7E 0x7E 0x18 0x18 0x18 0x7E 0x7E +: yw4 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xC6 0xE6 0xF6 0xFE 0xDE 0xCE 0xC6 + +# title/loading screen +: ti1 0xFE 0x82 0xAA 0x92 0xAA 0x82 0xFE 0x00 0x06 0x06 0x06 0x06 0x06 0x07 0x03 +: ti2 0x00 0x00 0x75 0x47 0x45 0x75 0x00 0x00 0x19 0x1B 0xDB 0xDB 0xDB 0xFB 0x33 +: ti3 0x00 0x00 0x5C 0x54 0x5C 0x50 0x00 0x00 0xE7 0xF7 0x36 0xF7 0xF7 0x36 0x36 +: ti4 0xFE 0xFE 0xF6 0xFE 0xDE 0xFE 0xFE 0x00 0xC0 0xE0 0x60 0xC0 0xE0 0x60 0x60 +: lo1 0x8E 0x8A 0x8A 0xEE +: lo2 0x4C 0xAA 0xEA 0xAC +: lo3 0xB3 0xAA 0xAA 0xAB +: lo4 0x80 0x00 0x80 0xAA + +# n e s w +: delta-x 0 1 0 -1 +: delta-y -1 0 1 0 + +########################################### +# +# Register Map: +# +########################################### + +# vf is always temporary +:alias mode ve +:alias cursorx vd +:alias cursory vc +:alias dir vb +:alias wdice v9 +:alias bdice v8 +:alias wtotal v7 +:alias btotal v6 +:alias wroll v5 +:alias broll v4 +:alias rolls v3 +# v0-v2 are temporary + +########################################### +# +# Mutable Data +# +########################################### + +# game modes (mode) +:const MOVE 0 +:const ATTACK 1 +:const AIMOVE 2 +:const WIN 3 +:const LOSE 4 +:const RESET 5 + +# space owners (owns-at) +:const START 0 +:const WHITE 1 +:const BLACK 2 +:const EMPTY 3 + +: bcd-buffer 0 +: tens 0 +: ones 0 + +: owns-at 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +: dice-at 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +########################################### +# +# Utility Subroutines +# +########################################### + +: random-vector + # trashes v0-v2 + # returns in v1 + v1 := random 0xFF + v2 := v1 + v0 := 0 + loop + while v2 != 0 + v2 <<= v2 + v0 += vf + again + if v0 != 4 then jump random-vector +; + +: vfwait + delay := vf + loop + vf := delay + if vf != 0 then + again +; + +: longwait + vf := 60 + jump vfwait + +: wait + vf := 30 + jump vfwait + +: uwait + vf := 10 + jump vfwait + +: fillscreen + # trashes v0-v1 + clear + i := fill + v0 := 0 + loop + v1 := 0 + sprite v0 v1 15 + v1 := 15 + sprite v0 v1 15 + v1 := 30 + sprite v0 v1 2 + v0 += 8 + if v0 != 64 then + again +; + +: draw-end-screen + v0 := 16 + v1 := 8 + v2 := 15 + loop + sprite v0 v1 15 + i += v2 + v0 += 8 + if v0 != 48 then + again + v0 := key + mode := RESET +; + +: draw-game-over + fillscreen + i := go1 + jump draw-end-screen + +: draw-you-win + clear + i := yw1 + jump draw-end-screen + +########################################### +# +# Battle +# +########################################### + +: draw-wtotal + # trashes v0-v2 + v2 := 23 + v1 := 11 + i := bcd-buffer + bcd wtotal + i := tens load v0 i := hex v0 + sprite v1 v2 5 + v1 += 5 + i := ones load v0 i := hex v0 + sprite v1 v2 5 +; + +: draw-btotal + # trashes v0-v2 + v2 := 23 + v1 := 43 + i := bcd-buffer + bcd btotal + i := tens load v0 i := hex v0 + sprite v1 v2 5 + v1 += 5 + i := ones load v0 i := hex v0 + sprite v1 v2 5 +; + +: draw-wroll + # trashes v0-v2 + v2 := 16 + v1 := 14 + i := hex wroll + sprite v1 v2 5 + v1 += -4 + i := plus + sprite v1 v2 4 +; + +: draw-broll + # trashes v0-v2 + v2 := 16 + v1 := 46 + i := hex broll + sprite v1 v2 5 + v1 += -4 + i := plus + sprite v1 v2 4 +; + +: draw-battle + # trashes v0-v2 + clear + i := fill + v0 := 32 + v1 := 0 + loop + v1 := 0 + sprite v0 v1 15 + v1 := 15 + sprite v0 v1 15 + v1 := 30 + sprite v0 v1 2 + v0 += 8 + if v0 != 64 then + again + + + # dice counters: + v1 := 4 + v0 := 12 + + i := whitedice + v2 := wdice + v2 <<= v2 + v2 <<= v2 + v2 <<= v2 + v2 += -8 + i += v2 + sprite v0 v1 7 + + i := whitedice + v2 := bdice + v2 <<= v2 + v2 <<= v2 + v2 <<= v2 + v2 += -8 + i += v2 + v0 := 45 + sprite v0 v1 7 + + draw-wtotal + draw-btotal +; + +: b-do-roll + broll := random 7 + broll += 1 + draw-broll + draw-btotal + btotal += broll + draw-btotal +; + +: w-do-roll + wroll := random 7 + wroll += 1 + draw-wroll + draw-wtotal + wtotal += wroll + draw-wtotal +; + +: defender-wins + # set attacker to 1 + cursor-to-index + i := dice-at + i += vf + v0 := 1 + save v0 + + # set defender to max(1, old-1) + direction-to-index + i := dice-at + i += vf + load v0 + v0 += -1 + if v0 == 0 then v0 := 1 + i := dice-at + i += vf + save v0 +; + +: attacker-wins + # set dest to attackers - 1 + cursor-to-index + i := dice-at + i += vf + load v0 + va := v0 + va += -1 + direction-to-index + i := dice-at + i += vf + v0 := va + save v0 + + # set dest to be attacker owned + direction-to-index + i := owns-at + i += vf + if mode == ATTACK then v0 := WHITE + if mode != ATTACK then v0 := BLACK + save v0 + + # set attackers to 1 + cursor-to-index + i := dice-at + i += vf + v0 := 1 + save v0 +; + +: white-wins-attack + attacker-wins + + # if there are no black zones, + # game over and white wins. + i := owns-at + v1 := 0 + loop + load v0 + if v0 == BLACK then return + v1 += 1 + if v1 != 18 then + again + mode := WIN +; + +: black-wins-attack + attacker-wins + + # if there are no white zones, + # game over and black wins. + i := owns-at + v1 := 0 + loop + load v0 + if v0 == WHITE then return + v1 += 1 + if v1 != 18 then + again + mode := LOSE +; + +: white-wins + if mode == ATTACK then jump white-wins-attack + jump defender-wins + +: black-wins + if mode != ATTACK then jump black-wins-attack + jump defender-wins + +: battle + wtotal := 0 + btotal := 0 + rolls := 0 + + draw-battle + wait + + loop + if bdice > rolls then b-do-roll + if wdice > rolls then w-do-roll + wait + if bdice > rolls then draw-broll + if wdice > rolls then draw-wroll + uwait + + rolls += 1 + + # get max of dice count + v0 := bdice + if wdice > bdice then v0 := wdice + + if rolls != v0 then + again + longwait + + # note that this gives black a fundamental + # advantage; it always wins ties: + if wtotal > btotal then jump white-wins + jump black-wins + +########################################### +# +# Map +# +########################################### + +: map-tile + # trashes v0-v2. + # takes an index in vf + # initializes i to the appropriate + # sprite data to draw + + v2 := vf + + i := dice-at + i += v2 + load v0 + v0 += -1 + v1 <<= v0 + v1 <<= v1 + v1 <<= v1 + + i := owns-at + i += v2 + load v0 + + i := whitedice + if v0 == BLACK then i := blackdice + i += v1 + if v0 == EMPTY then i := empty +; + +: draw-map + # trashes v0-v5 + v4 := 4 # y position + v5 := 0 # map array index + + clear + loop + v3 := 8 # x position + loop + vf := v5 map-tile + sprite v3 v4 7 + + v5 += 1 + v3 += 8 + + if v3 != 56 then + again + v4 += 8 + if v4 != 28 then + again +; + +: draw-p1 + i := p1 + v0 := 0 + v1 := 9 + sprite v0 v1 14 +; + +: draw-p2 + i := p2 + v0 := 56 + v1 := 9 + sprite v0 v1 14 +; + +########################################### +# +# Cursor +# +########################################### + +: draw-cursor + # trash v0-v2 + v0 <<= cursorx + v0 <<= v0 + v0 <<= v0 + v0 += 7 + + v1 <<= cursory + v1 <<= v1 + v1 <<= v1 + v1 += 3 + + v2 := v0 + v2 += 8 + i := curs1 + sprite v0 v1 9 + i := curs2 + sprite v2 v1 9 +; + +: cursor-to-index + # leave result in vf + vf := cursorx + if cursory == 1 then vf += 6 + if cursory == 2 then vf += 12 +; + +: direction-to-index + # trashes v0-v2 + # leave the result in vf + v1 := cursorx + i := delta-x + i += dir + load v0 + v1 += v0 + if v1 == -1 then v1 := 5 + if v1 == 6 then v1 := 0 + + v2 := cursory + i := delta-y + i += dir + load v0 + v2 += v0 + if v2 == -1 then v2 := 2 + if v2 == 3 then v2 := 0 + + if v2 == 1 then v1 += 6 + if v2 == 2 then v1 += 12 + vf := v1 +; + +: cursor-to-xy + # leave result in v0/v1 + v0 <<= cursorx + v0 <<= v0 + v0 <<= v0 + v0 += 8 + + v1 <<= cursory + v1 <<= v1 + v1 <<= v1 + v1 += 4 +; + +: erase-selected + # trash v0-v2 + cursor-to-index + map-tile + cursor-to-xy + sprite v0 v1 7 +; + +: draw-arrow + i := arrows + v0 <<= dir + v0 <<= v0 + v0 <<= v0 + i += v0 + cursor-to-xy + sprite v0 v1 7 +; + +: start-attack + dir := 0 + + # ignore spaces we don't control + cursor-to-index + i := owns-at + i += vf + load v0 + if v0 != WHITE then return + + # ignore spaces with 1 die + i := dice-at + i += vf + load v0 + if v0 == 1 then return + + # switch to attack selection mode + mode := ATTACK + draw-cursor + erase-selected + draw-arrow +; + +: cancel-attack + draw-arrow + mode := MOVE + draw-cursor + erase-selected +; + +: start-fight + direction-to-index + + # if the adjacent tile isn't black, give up + i := owns-at + i += vf + load v0 + if v0 != BLACK then return + + # set up and fight + i := dice-at + i += v1 + load v0 + bdice := v0 + + i := dice-at + cursor-to-index + i += vf + load v0 + wdice := v0 + + battle + if mode == WIN then return + draw-map + draw-p1 + draw-cursor + mode := MOVE +; + +: start-ai-turn + restock + draw-map + longwait + draw-p2 + mode := AIMOVE + ai-move + if mode == LOSE then return + mode := MOVE + draw-p2 + draw-p1 +; + +: move-cursor + va := key + draw-cursor + if va == 7 then cursorx += -1 + if va == 9 then cursorx += 1 + if va == 5 then cursory += -1 + if va == 8 then cursory += 1 + if va == 6 then start-attack + if va == 4 then start-ai-turn + + if cursorx == 6 then cursorx := 0 + if cursorx == -1 then cursorx := 5 + if cursory == 3 then cursory := 0 + if cursory == -1 then cursory := 2 + draw-cursor +; + +: attack-cursor + va := key + draw-cursor + draw-arrow + if va == 7 then dir := 3 + if va == 9 then dir := 1 + if va == 5 then dir := 0 + if va == 8 then dir := 2 + draw-arrow + draw-cursor + if va == 4 then cancel-attack + if va == 6 then start-fight +; + +########################################### +# +# AI Opponent +# +########################################### + +: ai-pickdir + direction-to-index + + # must be white + i := owns-at + i += vf + load v0 + if v0 != WHITE then return + + # is this zone weaker? + i := dice-at + i += vf + load v0 + if v5 < v0 then return + + # our new choice + v4 := dir + v5 := v0 +; + +: ai-single + # pick a random territory + v2 := random 0b1111 + v1 := 0 + cursorx := 0 + cursory := 0 + i := owns-at + loop + while v2 != 0 + load v0 + if v0 != EMPTY then v2 += -1 + v1 += 1 + cursorx += 1 + if cursorx == 6 then cursory += 1 + if cursorx == 6 then cursorx := 0 + again + # v1 now contains the (0-17) index of + # our chosen territory. + + # if it's not black, ignore it + i := owns-at + i += v1 + load v0 + if v0 != BLACK then return + + # if it has 1 die, ignore it + i := dice-at + i += v1 + load v0 + if v0 == 1 then return + bdice := v0 + + # attack the weakest adjacent white zone + v4 := -1 # best direction + v5 := 0xFF # best die count (lower is better) + dir := 0 ai-pickdir + dir := 1 ai-pickdir + dir := 2 ai-pickdir + dir := 3 ai-pickdir + if v4 == -1 then return + dir := v4 + wdice := v5 + + # show arrow + draw-cursor + longwait + draw-cursor + erase-selected + draw-arrow + longwait + + # FIRE ZE MISSILES + battle + draw-map + draw-p2 + wait +; + +# unroll these loops so that I don't +# need to keep track of a loop index: + +: ai-moves + ai-single + ai-single + ai-single + ai-single + ai-single +; + +: ai-move + ai-moves + ai-moves + ai-moves + ai-moves +; + +########################################### +# +# Restocking +# +########################################### + +: restock-single + # take index in va + i := owns-at + i += va + load v0 + if v0 == EMPTY then return + + vb += 1 + i := dice-at + i += va + load v0 + v1 <<= v1 + v0 += vf + if v0 == 6 then v0 := 5 + + i := dice-at + i += va + save v0 +; + +: restock + va := 0 # cell index + vb := 0 # bit index + random-vector + loop + restock-single + va += 1 + if vb != 8 then + again + random-vector + loop + restock-single + va += 1 + if vb != 16 then + again +; + +########################################### +# +# Map Generation +# +########################################### + +: fill-boards + # expects i to be initialized + # takes the fill value in v0 + v1 := 0 + loop + save v0 + v1 += 1 + if v1 != 18 then + again +; + +: reset-owned + i := owns-at + v0 := START + jump fill-boards + +: reset-dice + i := dice-at + v0 := 1 + jump fill-boards + +: place-empty + # trashes v0-v2 + # pick an index 0-17 + v2 := random 0b11111 + if v2 > 17 then jump place-empty + + # make sure that spot is uninitialized + i := owns-at + i += v2 + load v0 + if v0 != START then jump place-empty + + # set it to be empty + i := owns-at + i += v2 + v0 := EMPTY + save v0 +; + +: place-owned-single + # take index in va + i := owns-at + i += va + load v0 + if v0 == EMPTY then return + + v1 <<= v1 + vb += 1 + v0 := WHITE + if vf == 1 then v0 := BLACK + i := owns-at + i += va + save v0 +; + +: place-owned + va := 0 # cell index + vb := 0 # bit index + random-vector + loop + place-owned-single + va += 1 + if vb != 8 then + again + random-vector + loop + place-owned-single + va += 1 + if vb != 16 then + again +; + +: random-map + reset-owned + reset-dice + place-empty + place-empty + place-owned + restock +; + +########################################### +# +# Main +# +########################################### + +: title-screen + v0 := 16 + v1 := 4 + v2 := 0 + v3 := 15 + i := ti1 + loop + sprite v0 v1 15 + v0 += 8 + v2 += 1 + i += v3 + if v2 != 4 then + again + + v0 := 16 + v1 := 27 + v2 := 0 + v3 := 4 + loop + sprite v0 v1 4 + v0 += 8 + v2 += 1 + i += v3 + if v2 != 4 then + again +; + +: init-game + random-map + draw-map + draw-p1 + draw-cursor + mode := MOVE +; + +: main + title-screen + init-game + loop + if mode == MOVE then move-cursor + if mode == ATTACK then attack-cursor + if mode == WIN then draw-you-win + if mode == LOSE then draw-game-over + if mode == RESET then init-game + again diff --git a/resources/octoroms/deep8.8o b/resources/octoroms/deep8.8o new file mode 100644 index 0000000..e6315c3 --- /dev/null +++ b/resources/octoroms/deep8.8o @@ -0,0 +1,393 @@ +########################################### +# +# Deep8 +# +# A stripped down port of the Mako game +# "Deep" for Chip8. +# Move your boat left and right with A/D +# Press S to drop a bomb and release S +# to detonate it. Destroy incoming +# squid before they tip your boat! +# +# This game was one of the earliest +# programs written using Octo. +# +########################################### + +: waves + 0b00110011 + 0b11101110 + +: boat + 0b00000100 + 0b00000100 + 0b11111111 + 0b11111111 + 0b01111101 + +: boat-flip + 0b00000000 + 0b00000000 + 0b01111101 + 0b11111111 + 0b11111111 + +: bomb + 0b00001000 + 0b00010100 + 0b00010000 + 0b00111000 + 0b00111000 + 0b00111000 + +: fall + 0b01000000 + 0b01010000 + 0b01100000 + 0b11110000 + 0b01100000 + 0b01000000 + +: squid-0 + 0b00111100 + 0b00111100 + 0b01011010 + 0b01011010 + +: squid-1 + 0b00111100 + 0b00111100 + 0b11011011 + 0b00100100 + +: boom + 0b10010000 + 0b00010010 + 0b01100000 + 0b00000000 + 0b10000011 + 0b00100100 + 0b00100001 + +: title-0 + 0b00010000 + 0b00010000 + 0b00010000 + 0b00010000 + 0b01110000 + 0b10010000 + 0b10010000 + 0b10010000 + 0b10010000 + 0b01110000 +: title-1 + 0b01100000 + 0b10010000 + 0b11110000 + 0b10000000 + 0b10000000 + 0b01110000 +: title-2 + 0b11100000 + 0b10010000 + 0b10010000 + 0b10010000 + 0b10010000 + 0b11100010 + 0b10000000 + 0b10000000 + 0b10000000 + 0b10000000 + +: end-0 + 0b11101010 + 0b01001110 + 0b01001010 + 0b01001010 +: end-1 + 0b11100111 + 0b11000110 + 0b10000100 + 0b11100111 +: end-2 + 0b01100110 + 0b01010101 + 0b01010101 + 0b01010110 + +# register scratchpad: +: scratch 0 0 0 0 + +# storage for BCD decoding: +: score-digits 0 0 0 + +# enemy data: +: e1 1 0 0 +: e2 20 0 0 +: e3 40 0 0 +: e4 90 0 0 + +########################################### +# +# Introduction +# +########################################### + +: draw-waves + i := waves + v0 := 0 # x + v1 := 7 # y + loop + sprite v0 v1 2 + v0 += 8 + while v0 != 64 + again +; + +: title + draw-waves + i := title-0 + v0 := 16 + v1 := 12 + sprite v0 v1 10 + i := title-1 + v0 += 8 + v1 += 4 + sprite v0 v1 6 + v0 += 8 + sprite v0 v1 6 + i := title-2 + v0 += 8 + sprite v0 v1 10 + v0 := key +; + +: draw-score + i := score-digits + load v2 + i := hex v0 + v0 := 49 + v3 := 1 + sprite v0 v3 5 + i := hex v1 + v0 += 5 + sprite v0 v3 5 + i := hex v2 + v0 += 5 + sprite v0 v3 5 +; + +: inc-score + i := scratch + save v3 + draw-score + v9 += 1 + i := score-digits + bcd v9 + draw-score + i := scratch + load v3 +; + +: init-game + clear + draw-waves + v8 := 0 # enemy tick timer + v9 := 0 # player score + va := 32 # player horizontal position + vb := 1 # player vertical position + vc := 10 # bomb horizontal position + vd := 10 # bomb vertical position + ve := 0 # bomb state (0=invisible, 1=falling, 2+=exploding) + + # draw initial boat + i := boat + sprite va vb 5 + + # draw initial score + draw-score +; + +########################################### +# +# Game Over +# +########################################### + +: delay-loop + v0 := 0 + loop + v0 += 1 + while v0 != 32 + again +; + +: game-over + # erase player + i := boat + sprite va vb 5 + + # flip boat + i := boat-flip + sprite va vb 5 + + # animate the player sinking + i := fall + vb := 8 + sprite va vb 6 + loop + delay-loop + sprite va vb 6 + vb += 1 + sprite va vb 6 + while vb != 26 + again + sprite va vb 6 + + # show 'the end' + va := 20 + vb := 14 + i := end-0 + sprite va vb 4 + i := end-1 + va += 8 + sprite va vb 4 + i := end-2 + va += 8 + sprite va vb 4 + + loop again + +########################################### +# +# Enemy Logic +# +########################################### + +# v0 - enemy timer. (0=swim, >0=time until next spawn) +# v1 - horizontal position +# v2 - vertical position + +: enemy-sprite + v4 := 1 + v4 &= v2 + i := squid-0 + if v4 == 1 then i := squid-1 +; + +: spawn-enemy + v1 := random 63 + v2 := 28 + enemy-sprite + sprite v1 v2 4 +; + +: count-enemy + v0 -= v3 + if v0 == 0 then spawn-enemy +; + +: update-enemy + if v0 != 0 then jump count-enemy + enemy-sprite + sprite v1 v2 4 + v2 -= v3 + + # kill the player if + # an enemy reaches the surface: + if v2 == 8 then jump game-over + + enemy-sprite + sprite v1 v2 4 + + # die on collision: + if vf == 0 then return + sprite v1 v2 4 + v0 := random 31 + v0 += 10 + inc-score +; + +: update-enemies + v3 := 1 + v8 ^= v3 + if v8 == 0 then return + i := e1 load v2 update-enemy i := e1 save v2 + i := e2 load v2 update-enemy i := e2 save v2 + i := e3 load v2 update-enemy i := e3 save v2 + i := e4 load v2 update-enemy i := e4 save v2 +; + +########################################### +# +# Player/Bomb Logic +# +########################################### + +: bomb-fire + if ve != 0 then return + vc := va + vd := 10 + ve := 1 + i := bomb + sprite vc vd 6 +; + +: update-player + v2 := 3 + v1 := va + v0 := 7 + if v0 key then va -= v2 + v0 := 9 + if v0 key then va += v2 + v0 := 8 + if v0 key then bomb-fire + if v1 == va then return + i := boat + sprite v1 vb 5 + sprite va vb 5 +; + +: bomb-explode + ve := 2 + i := boom + sprite vc vd 7 +; + +: bomb-falling + i := bomb + sprite vc vd 6 + vd += 1 + if vd == 25 then jump bomb-explode + v0 := 8 + if v0 -key then jump bomb-explode + sprite vc vd 6 +; + +: bomb-exploding + ve += 1 + if ve != 4 then return + ve := 0 + i := boom + sprite vc vd 7 +; + +: update-bomb + if ve == 1 then jump bomb-falling + if ve != 0 then jump bomb-exploding +; + +########################################### +# +# Main Loop +# +########################################### + +: main + title + init-game + loop + update-player + update-bomb + update-enemies + again diff --git a/resources/octoroms/default.8o b/resources/octoroms/default.8o new file mode 100644 index 0000000..68a7319 --- /dev/null +++ b/resources/octoroms/default.8o @@ -0,0 +1,34 @@ +# Chip8 is a virtual machine designed in 1977 for programming video games. +# Octo is a high level assembler, disassembler and simulator for Chip8. +# Click 'Run' and then press ASWD to move the sprite around the screen. +# Click the Octo logo for source, documentation and examples. + +:alias px v1 +:alias py v2 + +: main + px := random 0b0011111 + py := random 0b0001111 + i := person + sprite px py 8 + + loop + # erase the player, update its position and then redraw: + sprite px py 8 + v0 := OCTO_KEY_W if v0 key then py += -1 + v0 := OCTO_KEY_S if v0 key then py += 1 + v0 := OCTO_KEY_A if v0 key then px += -1 + v0 := OCTO_KEY_D if v0 key then px += 1 + sprite px py 8 + + # lock the framerate of this program via the delay timer: + loop + vf := delay + if vf != 0 then + again + vf := 3 + delay := vf + again + +: person + 0x70 0x70 0x20 0x70 0xA8 0x20 0x50 0x50 diff --git a/resources/octoroms/demos/chipenstein.8o b/resources/octoroms/demos/chipenstein.8o new file mode 100644 index 0000000..972d59a --- /dev/null +++ b/resources/octoroms/demos/chipenstein.8o @@ -0,0 +1,310 @@ +########################################### +# +# Chipenstein 3D +# +# A work-in-progress experiment +# in creating a raycast 2.5d shooter. +# Uses PWM techniques to simulate extra +# colors and must run at 1000 cycles/frame. +# Epilepsy warning! +# +########################################### + +# The largest a map for this approach could be is 16x16. +# Technically we don't have to surround all sides with +# walls due to wraparound, but if there is a ray path +# around the map without hitting a wall our raycast +# routine will get stuck in an infinite loop: + +: map-data + 0xFF 0x01 0xFF 0x01 0xFF 0x01 0xFF 0x01 0xFF 0x01 + 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xFF + 0xFF 0xFF 0x01 0xFF 0x00 0x00 0x00 0x00 0x00 0x01 + 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xFF + 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 + 0x01 0x00 0xFF 0x01 0x00 0x00 0x00 0xFF 0x00 0xFF + 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 + 0x01 0xFF 0x01 0xFF 0x01 0xFF 0x01 0xFF 0x01 0xFF + +: collision-test + # take whole x/y in vc/vd, return map color in v0 + i := map-data + vF := 0b111 + vc &= vF + i += vc # + (x % 8) + vd &= vF + v0 <<= vd + v0 <<= v0 + v0 <<= v0 + i += v0 # + (y % 8)*8 + load v0 # the current map color +; + +: player-position + 0 0 0 0 # scratchpad + +: save-position + v0 := va + v1 := vb + v2 := vc + v3 := vd + i := player-position + save v3 +; + +: restore-position + i := player-position + load v3 + va := v0 + vb := v1 + vc := v2 + vd := v3 +; + +########################################### +# +# Raycasting +# +########################################### + +# This is a table of the deltas and magnitudes for a fixed-point representation +# of a cosine function. 64 entries correspond to ~5.6 degrees each. +# deltas are interleaved with magnitudes- 0 for positive and 1 for negative. +# deltas are normalized to slightly over half a step to make the distance calculations +# come up with a maximum distance of roughly 15. Generated like so: +# +# for(int x = 0; x < 64; x++) { +# double s = Math.cos(Math.PI*2/64*x); +# System.out.format("0x%02X 0x%02X ", (int)(140 * Math.abs(s)), (s>=0) ?0 : 1); +# if (x % 8 == 7) { System.out.println(); } +# } + +: cosine-table + 0x8C 0x00 0x8B 0x00 0x89 0x00 0x85 0x00 0x81 0x00 0x7B 0x00 0x74 0x00 0x6C 0x00 + 0x62 0x00 0x58 0x00 0x4D 0x00 0x41 0x00 0x35 0x00 0x28 0x00 0x1B 0x00 0x0D 0x00 + 0x00 0x00 0x0D 0x01 0x1B 0x01 0x28 0x01 0x35 0x01 0x41 0x01 0x4D 0x01 0x58 0x01 + 0x62 0x01 0x6C 0x01 0x74 0x01 0x7B 0x01 0x81 0x01 0x85 0x01 0x89 0x01 0x8B 0x01 + 0x8C 0x01 0x8B 0x01 0x89 0x01 0x85 0x01 0x81 0x01 0x7B 0x01 0x74 0x01 0x6C 0x01 + 0x62 0x01 0x58 0x01 0x4D 0x01 0x41 0x01 0x35 0x01 0x28 0x01 0x1B 0x01 0x0D 0x01 + 0x00 0x01 0x0D 0x00 0x1B 0x00 0x28 0x00 0x35 0x00 0x41 0x00 0x4D 0x00 0x58 0x00 + 0x62 0x00 0x6C 0x00 0x74 0x00 0x7B 0x00 0x81 0x00 0x85 0x00 0x89 0x00 0x8B 0x00 + +: get-cosine + # takes angle in v0, + # returns delta, magnitude in v0, v1 + vf := 0b111111 + v0 &= vf # mod 64 + v0 <<= v0 + i := cosine-table + i += v0 + load v1 +; + +: get-angles + # takes angle in v3, + # unpacks x/y delta/mag into v4-v7 + + # cos(a) = cosine-table[(a % 64) << 1] + v0 := v3 + get-cosine + v4 := v0 # x delta + v5 := v1 # x magnitude + + # sin(a) = cosine-table[(a+16 % 64) << 1] + v0 := v3 + v0 += 16 + get-cosine + v6 := v0 # y delta + v7 := v1 # y magnitude +; + +: delta-step + vf := 0 + if v5 == 0 then va += v4 # positive x delta + if vf == 1 then vc += 1 # carry in + + vf := 0 + if v5 == 1 then va -= v4 # negative x delta + if vf == 0 then vc += -1 # borrow out + + vf := 0 + if v7 == 0 then vb += v6 # positive y delta + if vf == 1 then vd += 1 # carry in + + vf := 0 + if v7 == 1 then vb -= v6 # negative y delta + if vf == 0 then vd += -1 # borrow out +; + +: heights + # {height, color} + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +: raycast + save-position + + #v0-v1 are available as scratch. + + v8 := 0 # loop index * 2 + v3 := v9 # scan angle + v3 += -8 + loop + get-angles + + v2 := 16 # height+1 + loop + delta-step + v2 += -1 # count down height + collision-test # returns result in v0 + while v2 != 0 + if v0 == 0 then + again + + # save height and color in heights table: + i := heights + i += v8 + v1 := v0 + v0 := v2 + save v1 + + vf := v3 + restore-position + v3 := vf + + v8 += 2 + v3 += 1 # 16 slices * 5.625 = 90 degree FoV + if v8 != 32 then + again +; + +########################################### +# +# Rendering +# +########################################### + +# this 45-byte table allows me to construct all the necessary vertical +# strips using only immediate i and a height offset: + +: top 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +: btm 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + +: sync + # take advantage of the fact that vf + # is always a free register if we aren't + # doing any operations that can carry: + loop + vf := delay + if vf != 0 then + again + vf := 1 + delay := vf +; + +: draw-heights + # registers for draw loop: + # v0 is used to store the current height + # v1 stores the 'color' bitmask + v2 := 0 # heightmap index + v3 := 1 # upward strip Y + v4 := 16 # down strip Y + v5 := 0 # strip X (avoid shifting v1 in loop) + v6 := 15 # constant + + sync clear + loop + # fetch height of column + i := heights + i += v2 + load v1 + + # apply PWM duty cycle for 'color' + v1 &= ve + if v1 == 0 then v0 := 0 + + # draw upward strip + i := top + i += v0 + v0 =- v6 + sprite v5 v3 15 + + # draw downward strip + i := btm + i += v0 + sprite v5 v4 15 + + # draw 16 columns + v2 += 2 + v5 += 4 + if v2 != 32 then + again + +; + +########################################### +# +# Main Loop +# +########################################### + +: gun + 0x10 0x18 0x24 0x24 0x24 0x24 0x5A 0xC2 0xE7 0x7F 0x3E 0x21 0x41 0x41 + +: spin-left + v9 += -1 + raycast +; + +: spin-right + v9 += 1 + raycast +; + +: walk-forward + v3 := v9 + get-angles + delta-step + raycast +; + +: walk-backward + v3 := v9 + get-angles + vf := 1 + v5 ^= vf + v7 ^= vf + delta-step + raycast +; + +: main + # global state: + v9 := 30 # player angle + va := 128 # x position (fractional) + vb := 128 # y position (fractional) + vc := 5 # x position (whole) + vd := 5 # y position (whole) + ve := 0 # rolling frame counter + + raycast + + loop + draw-heights + i := gun + v0 := 38 + v1 := 18 + sprite v0 v1 14 + + ve += 1 + + v0 := 7 + if v0 key then spin-left + v0 := 9 + if v0 key then spin-right + v0 := 5 + if v0 key then walk-forward + v0 := 8 + if v0 key then walk-backward + again diff --git a/resources/octoroms/demos/computer.8o b/resources/octoroms/demos/computer.8o new file mode 100644 index 0000000..0febf09 --- /dev/null +++ b/resources/octoroms/demos/computer.8o @@ -0,0 +1,83 @@ +########################################### +# +# Sprite scrolling demo: +# +# Draw a computer monitor with a scrolling +# image by using two copies of its sprites +# and adjusting an offset into that data +# before each draw. +# +########################################### + +: main + # draw the background: + + v0 := 16 + v1 := 4 + i := comp-LT + sprite v0 v1 11 + v0 += 8 + i := comp-T + sprite v0 v1 3 + v0 += 8 + sprite v0 v1 3 + v0 += 8 + i := comp-RT + sprite v0 v1 11 + + v0 := 16 + v1 += 11 + i := comp-LB + sprite v0 v1 15 + v0 += 8 + v1 += 7 + i := comp-B + sprite v0 v1 8 + v0 += 8 + sprite v0 v1 8 + v0 += 8 + v1 += -7 + i := comp-RB + sprite v0 v1 15 + + # main animation loop: + + va := 24 # left x + vb := 32 # right x + vc := 7 # common y + v9 := 0 # scroll offset + v8 := 0b1111 # constant + draw-texture + loop + draw-texture + v9 += 1 + v9 &= v8 + draw-texture + + vF := 4 + delay := vF + loop + vF := delay + if vF != 0 then + again + again + +: draw-texture + i := grenade-L + i += v9 + sprite va vc 15 + i := grenade-R + i += v9 + sprite vb vc 15 +; + +: grenade-L 0x0F 0x30 0x7C 0x7C 0xF8 0xF4 0xE0 0xE8 0xF0 0xE8 0xE0 0x68 0x70 0x34 0x08 0x00 + 0x0F 0x30 0x7C 0x7C 0xF8 0xF4 0xE0 0xE8 0xF0 0xE8 0xE0 0x68 0x70 0x34 0x08 0x00 +: grenade-R 0xF0 0x0C 0x46 0x66 0x33 0x13 0x0B 0x0B 0x1F 0x0F 0x0F 0x1E 0x1E 0x1C 0x30 0x00 + 0xF0 0x0C 0x46 0x66 0x33 0x13 0x0B 0x0B 0x1F 0x0F 0x0F 0x1E 0x1E 0x1C 0x30 0x00 +: comp-LT 0x3F 0x3F 0x3F 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C +: comp-RT 0xFC 0xFC 0xFC 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C +: comp-T 0xFF 0xFF 0xFF +: comp-LB 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C 0x3F 0x3F 0x3F 0x00 0x07 0x1C 0x73 0x7F +: comp-RB 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C 0xFC 0xFC 0xFC 0x00 0xE0 0xD8 0x26 0xFE +: comp-B 0xFF 0xFF 0xFF 0xFF 0x33 0xCC 0x33 0xFF diff --git a/resources/octoroms/demos/draw.8o b/resources/octoroms/demos/draw.8o new file mode 100644 index 0000000..c25cb4c --- /dev/null +++ b/resources/octoroms/demos/draw.8o @@ -0,0 +1,23 @@ +########################################### +# +# Key input test program. +# Move a dot around the screen in response +# to keypresses. +# +########################################### + +: dot + 0b10000000 + +: main + v0 := 10 + v1 := 10 + i := dot + + loop + sprite v0 v1 1 + v2 := 7 if v2 key then v0 += -1 # left + v2 := 9 if v2 key then v0 += 1 # right + v2 := 5 if v2 key then v1 += -1 # up + v2 := 8 if v2 key then v1 += 1 # down + again diff --git a/resources/octoroms/demos/smile.8o b/resources/octoroms/demos/smile.8o new file mode 100644 index 0000000..7c86b11 --- /dev/null +++ b/resources/octoroms/demos/smile.8o @@ -0,0 +1,30 @@ +########################################### +# +# Smile +# +# Draw smiley faces on the screen randomly +# and periodically clear the display. +# +########################################### + +: smile + 0b00100100 + 0b00100100 + 0b00000000 + 0b10000001 + 0b01000010 + 0b00111100 + +: main + i := smile + loop + v2 := 0 + loop + v0 := random 0b00111111 + v1 := random 0b00011111 + sprite v0 v1 6 + v2 += 1 + if v2 != 32 then + again + clear + again diff --git a/resources/octoroms/demos/sort1.8o b/resources/octoroms/demos/sort1.8o new file mode 100644 index 0000000..3abf488 --- /dev/null +++ b/resources/octoroms/demos/sort1.8o @@ -0,0 +1,73 @@ +########################################### +# +# An Octo implementation of an in-place +# selection sort capable of operating on +# arrays of a fixed size up to 256 elements. +# +########################################### + +:const SIZE 16 +:calc SIZE-1 { SIZE - 1 } + +:alias here v1 +:alias rest v2 +:alias min-index v3 +:alias min-value v4 +:alias here-value v5 + +: selection-sort + here := 0 + loop + min-index := here + i := data + i += here + load v0 + min-value := v0 + here-value := v0 + + rest := here + rest += 1 + i := data + i += rest + loop + load v0 + if v0 < min-value begin + min-index := rest + min-value := v0 + end + + rest += 1 + if rest != SIZE then + again + + if min-index != here begin + v0 := here-value + i := data + i += min-index + save v0 + + v0 := min-value + i := data + i += here + save v0 + end + + here += 1 + if here != SIZE-1 then + again +; + +########################################### +# +# Usage Example +# +########################################### + +: data 14 5 15 6 1 3 10 7 0 9 11 4 2 13 8 12 + +: main + selection-sort + i := data + load vf + :breakpoint sort-complete +; diff --git a/resources/octoroms/demos/sort2.8o b/resources/octoroms/demos/sort2.8o new file mode 100644 index 0000000..9cd5b32 --- /dev/null +++ b/resources/octoroms/demos/sort2.8o @@ -0,0 +1,116 @@ +########################################### +# +# An Octo implementation of an in-place +# heap sort capable of operating on +# arrays of a fixed size up to 255 elements. +# +########################################### + +:const SIZE 16 +:calc SIZE-1 { SIZE - 1 } +:calc LIMIT { ( SIZE / 2 ) + 1 } + +:alias left-val v0 +:alias right-val v1 +:alias start v2 +:alias root v3 +:alias last v4 +:alias best v5 +:alias left v6 +:alias best-val v7 +:alias root-val v8 + +: heap-sort + start := LIMIT + last := SIZE + loop + root := start + sift-down + start += -1 + if start != -1 then + again + + start := SIZE-1 + loop + # swap data[0] with data[start]: + i := data + load v0 + vf := v0 + + i := data + i += start + load v0 + i := data + save v0 + + i := data + i += start + v0 := vf + save v0 + + start += -1 + root := 0 + last := start + sift-down + + if start != 0 then + again +; + +: assign-best + best := left + best-val := left-val + jump found-best + +: sift-down + i := data + i += root + load v0 + root-val := v0 + + loop + left <<= root + + if left > last then return + + i := data + i += left + load v1 + + best := left + best += 1 + best-val := right-val + + if left-val > right-val then jump assign-best + if left == last then jump assign-best + : found-best + + if root-val >= best-val then return + + i := data + i += root + v0 := best-val + save v0 + + i := data + i += best + v0 := root-val + save v0 + + root := best + again + +########################################### +# +# Usage Example +# +########################################### + +: data 14 5 15 6 1 3 10 7 0 9 11 4 2 13 8 12 + +: main + heap-sort + i := data + load vf + :breakpoint sort-complete +; diff --git a/resources/octoroms/demos/sort3.8o b/resources/octoroms/demos/sort3.8o new file mode 100644 index 0000000..906ccb3 --- /dev/null +++ b/resources/octoroms/demos/sort3.8o @@ -0,0 +1,131 @@ +########################################### +# +# An Octo implementation of an unusual +# sorting algorithm which combines an +# optimal sorting network and a merge pass. +# This implementation is designed to sort +# exactly 16 items. The 'sort-8' subroutine +# can be used alone to sort the values +# stored in the bottom 8 registers. +# +########################################### + +: sort-8 + # compare-and-swap: + :macro cas A B { + if A > B begin + vf := A + A := B + B := vf + end + } + + cas v0 v1 + cas v2 v3 + cas v4 v5 + cas v6 v7 + cas v0 v2 + cas v4 v6 + cas v1 v3 + cas v0 v4 + cas v5 v7 + cas v3 v7 + cas v1 v5 + cas v3 v5 + cas v2 v6 + cas v2 v4 + cas v1 v2 + cas v3 v6 + cas v2 v4 + cas v5 v6 + cas v3 v4 +; + +: heap1 0 0 0 0 0 0 0 0 +: heap2 0 0 0 0 0 0 0 0 + +:alias val1 v8 +:alias val2 v9 +:alias dest va +:alias index1 vb +:alias index2 vc + +: fused-sort + i := data + load v7 + sort-8 + val1 := v0 + i := heap1 + save v7 + + i := data + load v7 + load v7 # cheaper than adding an offset of 8 + sort-8 + val2 := v0 + i := heap2 + save v7 + + index1 := 1 + index2 := 1 + dest := 0 + +: merge + if val1 > val2 then jump merge-2 + append-1 + if index1 != 9 then jump merge + loop + append-2 + if dest == 16 then return + again + +: merge-2 + append-2 + if index2 != 9 then jump merge + loop + append-1 + if dest == 16 then return + again + +: append-1 + v0 := val1 + i := data + i += dest + save v0 + dest += 1 + + i := heap1 + i += index1 + load v0 + val1 := v0 + index1 += 1 +; + +: append-2 + v0 := val2 + i := data + i += dest + save v0 + dest += 1 + + i := heap2 + i += index2 + load v0 + val2 := v0 + index2 += 1 +; + +########################################### +# +# Usage Example +# +########################################### + +: data 14 5 15 6 1 3 10 7 0 9 11 4 2 13 8 12 + +: main + fused-sort + i := data + load vf + :breakpoint sort-complete +; diff --git a/resources/octoroms/demos/sort4.8o b/resources/octoroms/demos/sort4.8o new file mode 100644 index 0000000..6ed0202 --- /dev/null +++ b/resources/octoroms/demos/sort4.8o @@ -0,0 +1,90 @@ +########################################### +# +# An Octo implementation of a +# bucket sort capable of operating on +# arrays of a fixed size up to 256 elements, +# with values ranging 0-15. +# This technique could be generalized +# for full-byte values given a larger +# bucket array. +# +########################################### + +:const SIZE 16 +:const MAX_VAL 16 + +: empty + 0 0 0 0 0 0 0 0 + +: buckets + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +: bucket-sort + # zero bucket array + i := empty + load v7 + save v7 # unrolled loop to zero bucket array + save v7 # and initialize loop counters for later. + + # bucket the elements + # v1 is data index (already 0) + loop + # load data + i := data + i += v1 + load v0 + vf := v0 + + # increment bucket + i := buckets + i += vf + load v0 + v0 += 1 + i := buckets + i += vf + save v0 + + v1 += 1 + if v1 != SIZE then + again + + # unpack bucket counts + # v1 is temporary count + # v2 is data index (already 0) + # v3 is bucket index (already 0) + loop + i := buckets + i += v3 + load v0 + if v0 != 0 begin + v1 := v0 + v0 := v3 + i := data + i += v2 + v2 += v1 + loop + save v0 + v1 += -1 + if v1 != 0 then + again + end + v3 += 1 + if v3 != MAX_VAL then + again +; + +########################################### +# +# Usage Example +# +########################################### + +: data 14 5 15 6 1 3 10 7 0 9 11 4 2 13 8 12 + +: main + bucket-sort + i := data + load vf + :breakpoint sort-complete +; + diff --git a/resources/octoroms/demos/stack1.8o b/resources/octoroms/demos/stack1.8o new file mode 100644 index 0000000..c8e87b5 --- /dev/null +++ b/resources/octoroms/demos/stack1.8o @@ -0,0 +1,74 @@ +########################################### +# +# A modular stack data structure using +# a v0-based calling convention. +# vf is used as a working temporary +# register because it is "fragile". +# maximum stack size is 256 bytes. +# +########################################### + +# the first value is the pointer index +: stack 0 0 0 0 0 0 0 0 0 + +: push + # modifies vf, v0 + # takes argument in v0 + # stack[++stack[0] + 1] := v0 + + i := stack + vf := v0 + load v0 + i += v0 + v0 := vf + save v0 + + i := stack + load v0 + v0 += 1 + i := stack + save v0 +; + +: pop + # modifies vf, v0 + # returns result in v0 + # v0 := stack[stack[0]-- + 1] + + i := stack + load v0 + v0 += -1 + vf := v0 + i := stack + save v0 + i += vf + load v0 +; + +########################################### +# +# Usage Example: +# +########################################### + +: print + # takes an arg in v0 + i := hex v0 + sprite va vb 5 + va += 6 +; + +: main + va := 3 + vb := 3 + + v0 := 5 push + v0 := 3 push + v0 := 1 push + pop print + v0 := 9 push + pop print + pop print + pop print + + # should print '1935' diff --git a/resources/octoroms/demos/stack2.8o b/resources/octoroms/demos/stack2.8o new file mode 100644 index 0000000..72c330b --- /dev/null +++ b/resources/octoroms/demos/stack2.8o @@ -0,0 +1,80 @@ +########################################### +# +# A modular stack data structure using +# a vf-based calling convention. +# This approach can only be extended up to +# a size 16 stack. +# +########################################### + +: scratch 0 0 0 0 0 0 0 0 +: under 0 +: stack 0 +: over 0 0 0 0 0 0 0 + +: push + # here we take our argument from vf. + # and do not corrupt any other registers. + # we can eliminate the scratch saving + # and restoring if low registers don't + # need to be preserved. + + i := scratch + save v6 + + i := stack + load v6 + i := over + save v6 + i := stack + v0 := vf + save v0 + + i := scratch + load v6 +; + +: pop + # result is left in vf. + # again, we don't corrupt any other registers. + + i := scratch + save v7 + + i := stack + load v7 + vf := v0 + i := under + save v7 + + i := scratch + load v7 +; + +########################################### +# +# Usage Example: +# +########################################### + +: print + # takes an arg in vf + i := hex vf + sprite va vb 5 + va += 6 +; + +: main + va := 3 + vb := 3 + + vf := 5 push + vf := 3 push + vf := 1 push + pop print + vf := 9 push + pop print + pop print + pop print + + # should print '1935' diff --git a/resources/octoroms/demos/stack3.8o b/resources/octoroms/demos/stack3.8o new file mode 100644 index 0000000..9d60131 --- /dev/null +++ b/resources/octoroms/demos/stack3.8o @@ -0,0 +1,55 @@ +########################################### +# +# A modular stack data structure using +# a v0-based calling convention. +# This approach reserves a dedicated +# register for a stack pointer and as +# a result is very simple and fast. +# maximum stack size is 256 bytes. +# +########################################### + +:alias stack-ptr vd +: stack 0 0 0 0 0 0 0 0 + +: push + i := stack + i += stack-ptr + save v0 + stack-ptr += 1 +; + +: pop + stack-ptr += -1 + i := stack + i += stack-ptr + load v0 +; + +########################################### +# +# Usage Example: +# +########################################### + +: print + # takes an arg in v0 + i := hex v0 + sprite va vb 5 + va += 6 +; + +: main + va := 3 + vb := 3 + + v0 := 5 push + v0 := 3 push + v0 := 1 push + pop print + v0 := 9 push + pop print + pop print + pop print + + # should print '1935' diff --git a/resources/octoroms/eaty.8o b/resources/octoroms/eaty.8o new file mode 100644 index 0000000..0ce79d2 --- /dev/null +++ b/resources/octoroms/eaty.8o @@ -0,0 +1,1320 @@ +########################################### +# +# Eaty The Alien +# +# An incredible intergalactic adventure. +# +# Use ASWD to move Eaty. +# Use E to activate Eaty's Magic Neck. +# +# Icons in the lower right corner indicate +# when you are standing on a special area. +# Find all three parts of Eaty's phone, +# activate it at the "C" marker and +# be on the marker with 4 arrows by +# the time the countdown ends. +# Watch your life force- every step you +# take on this inhospitable planet drains +# your health. Consume Skittles(tm) +# candies and drain the essence of flowers +# to stay alive. +# +########################################### + +:alias px vd +:alias py vc +:alias pdir vb +:alias pframe va +:alias has-item v9 #(in pits) +:alias has-enemy v9 #(on ground) +:alias is-dead v8 +:alias roomindex v7 +:alias pitindex v6 +:alias inventory v5 +:alias timer v4 + +# v0-v3 are reserved as temporaries. + +:const FACE_LEFT 0 +:const FACE_RIGHT 128 +:const KEY_LEFT 7 +:const KEY_RIGHT 9 +:const KEY_UP 5 +:const KEY_DOWN 8 +:const KEY_NECK 6 + +:const ITEM_X 12 +:const ITEM_Y 32 +:const START_LIFE 2 +:const ROSE_LIFE 3 +:const PIECES_LIFE 1 +:const PART_1 8 +:const PART_2 16 +:const PART_3 32 +:const ALL_PARTS 56 + +:const NOTHING 0 +:const ROSE 1 # (in pit) +:const PIECES 1 # (on ground) +:const NECK_ESP 2 + +:const CALL_SHIP 4 +:const GO_SHIP 5 + +:const TIMER_LO 20 +:const TIMER_HI 8 + +########################################### +# +# Main Logic +# +########################################### + +: main + loop + draw-title + + hires + clear + randomize-loot + + v0 := START_LIFE + v1 := 0 + i := life-force-hi + save v1 + + px := 60 + py := 16 + pdir := 0 + pframe := 0 + has-item := 0 + is-dead := 0 + roomindex := 4 + inventory := 0 + timer := 0 + + draw-room + draw-hud + draw-eaty + + main-loop + again + +: draw-title + lores + clear + v0 := 0 + v1 := 0 + v2 := 32 + i := title-screen + loop + sprite v0 v1 0 + v0 += 16 + i += v2 + if v0 == 64 then v1 += 16 + if v0 == 64 then v0 := 0 + if v1 != 32 then + again + v0 := 48 + v1 := 22 + v2 := KEY_NECK + i := fingat + loop + sprite v0 v1 1 + if v2 -key then + again +: wait-release + loop + if v2 key then + again +; + +: draw-end + # display image + lores + clear + v0 := 16 + v1 := 4 + sprite v0 v1 0 + v0 := 32 + i += v0 + sprite v0 v1 0 + + # show score + v1 := 22 + v2 := -7 + i := life-force-hi + draw-pair + i := life-force-lo + draw-pair + + v0 := key + jump wait-release + +: main-loop + + spawn-room + loop + if has-enemy == 1 then draw-enemy + + draw-eaty + draw-hud + save-position + move-overworld + dec-timer + if is-dead != 0 then return + + draw-eaty + if vf != 0 then overworld-collide + if has-enemy == 1 then move-enemy + if has-enemy == 1 then draw-enemy + draw-hud + + sync + again +; + +########################################### +# +# Utility Routines +# +########################################### + +: animate-magic-neck + i := eaty-neck + i += pdir + v0 := 32 + v1 := 0 + loop + sprite px py 0 + sync + sprite px py 0 + i += v0 + v1 += 1 + if v1 == 3 then buzzer := v1 + if v1 != 4 then + again +; + +: animate-death + i := eaty-walk + sprite px py 0 + sync + sprite px py 0 + i := die-0 + sprite px py 0 + sync + sprite px py 0 + i := die-1 + sprite px py 0 + sync + v0 := key + is-dead := 1 + i := game-over + jump draw-end + +: move-right + if pdir == FACE_RIGHT begin + px += 2 + else + pdir := FACE_RIGHT + pframe := -32 + end +; + +: move-left + if pdir == FACE_LEFT begin + px += -2 + else + pdir := FACE_LEFT + pframe := -32 + end +; + +: draw-eaty + i := eaty-walk + i += pdir + i += pframe + sprite px py 0 +; + +: next-frame + pframe += 32 + v0 := 127 + pframe &= v0 + dec-life +; + +: sync + loop + vf := delay + if vf != 0 then + again + vf := 5 + delay := vf +; + +: wait + loop + vf := delay + if vf != 0 then + again + vf := 1 + delay := vf +; + +: position-temp 0x00 0x00 0x00 + +: save-position + v0 := px + v1 := py + v2 := pdir + i := position-temp + save v2 +; + +: restore-position + i := position-temp + load v2 + px := v0 + py := v1 + pdir := v2 +; + +: iplus16 + v0 <<= v0 + v0 <<= v0 + v0 <<= v0 + v0 <<= v0 + i += v0 +; + +: bounce-out + loop + if vf == 0 then return + draw-eaty + px := random 127 + py := random 63 + px += 2 + if px > 110 then px += -63 + py += 1 + if py > 47 then py += -32 + draw-eaty + again +; + +########################################### +# +# Enemies +# +########################################### + +: enemy-data 00 00 + +: spawn-room + has-enemy := 0 + if roomindex == 1 then jump spawn-enemy + if roomindex == 3 then jump spawn-enemy + if timer == 0 then return + if roomindex != 4 then return +: spawn-enemy + has-enemy := 1 + v0 := random 63 + v0 += 32 + v1 := 0 + i := enemy-data + save v1 +; + +: draw-enemy + i := enemy-data + load v1 + i := copter + sprite v0 v1 0 +; + +: move-enemy + i := enemy-data + load v1 + vf := random 0b11 + if vf == 0 then v0 += -3 + if vf == 1 then v0 += 3 + vf := 127 + v0 &= vf + v1 += 1 + vf := 63 + v1 &= vf + i := enemy-data + save v1 + + # check player overlap + px += 128 + py += 64 + v0 += 128 + v1 += 64 + v0 += -16 if px < v0 then jump cleanup + v0 += 32 if px > v0 then jump cleanup + v1 += -16 if py < v1 then jump cleanup + v1 += 32 if py > v1 then jump cleanup + dec-life + dec-life + dec-life + dec-life + vf := 5 + buzzer := vf + +: cleanup + px += -128 + py += -64 +; + +########################################### +# +# Hud and Life Force +# +########################################### + +: timer-lo 00 +: life-force-hi 00 +: life-force-lo 00 +: life-force-temp 0x00 +: life-force-tens 0x00 +: life-force-ones 0x00 + +: draw-hud + i := heart + v1 := 2 + v2 := -7 + sprite v1 v2 5 + v1 += 6 + i := life-force-hi + draw-pair + i := life-force-lo + draw-pair + + v1 := -10 + i := part-tiles + i += inventory + if timer != 0 then i := bighex timer + sprite v1 v1 8 + + if roomindex > 4 then return + loot-px + v1 := -19 + v2 := -10 + i := blank + if v0 == GO_SHIP then i := go-ship + if v0 == CALL_SHIP then i := call-ship + if v0 == NECK_ESP then i := neck-esp + if v0 == PIECES then i := pieces + sprite v1 v2 8 +; + +: draw-part + v0 := inventory + v0 &= vf + if v0 != 0 then sprite v1 v1 8 +; + +: draw-pair + load v0 + i := life-force-temp + bcd v0 + i := life-force-tens + draw-digit + i := life-force-ones + draw-digit +; + +: draw-digit + load v0 + i := hex v0 + sprite v1 v2 5 + v1 += 5 +; + +: dec-life + i := life-force-hi + load v1 + vf := 1 + v1 -= vf + if vf != 1 begin + v0 += -1 + if v0 == -1 begin + animate-death + return + else + v1 := 99 + end + end + i := life-force-hi + save v1 +; + +: dec-timer + if timer == 0 then return + i := timer-lo + load v0 + if v0 == 0 begin + if timer == 1 begin + timer := 0 + loot-px + if v0 != GO_SHIP then return + is-dead := 1 + i := victory + jump draw-end + else + timer += -1 + v0 := TIMER_LO + end + end + v0 += -1 + i := timer-lo + save v0 +; + +: give-life # takes argument (in hundreds) in vf + i := life-force-hi + load v0 + v0 += vf + i := life-force-hi + save v0 +; + +########################################### +# +# Overworld Logic +# +########################################### + +: draw-room + v2 := 0 + loop + this-room + # col stride is 4, data stride is 2, so shift right. + v0 >>= v2 + i += v0 + load v1 + i := overworld-tiles + iplus16 + sprite v2 v1 15 + v2 += 4 + if v2 != 128 then + again +; + +: scroll-room-left + roomindex += 1 + if roomindex == 5 then roomindex := 0 + v2 := 124 + v3 := 0 + loop + this-room + i += v3 + load v1 + i := overworld-tiles + iplus16 + scroll-left + sprite v2 v1 15 + wait + v3 += 2 + if v3 != 64 then + again + px := 1 + spawn-room +; + +: scroll-room-right + roomindex += -1 + if roomindex == -1 then roomindex := 4 + v2 := 0 + v3 := 62 + loop + this-room + i += v3 + load v1 + i := overworld-tiles + iplus16 + scroll-right + sprite v2 v1 15 + wait + v3 += -2 + if v3 != -2 then + again + px := 111 + spawn-room +; + +: move-overworld + v0 := KEY_NECK if v0 key begin + animate-magic-neck + loot-px + if v0 == NECK_ESP begin + # neck esp reveals all nearby items in pits + reveal-pit-items + return + end + if v0 == PIECES begin + # pieces are a single-use health pickup + vf := PIECES_LIFE give-life + v0 := 0 + v1 >>= px # px / 16 + v1 >>= v1 + v1 >>= v1 + v1 >>= v1 + loot-set + return + end + if v0 == CALL_SHIP begin + # you gotta do this to end the game + if inventory == ALL_PARTS then timer := TIMER_HI + v0 := 0 + v1 >>= px # px / 16 + v1 >>= v1 + v1 >>= v1 + v1 >>= v1 + loot-set + try-place-call + end + return + end + + # track whether any keys are held down + v1 := 0 + + if py != 1 begin + v0 := KEY_UP if v0 key begin + v1 := 1 + py += -1 + end + end + if py != 47 begin + v0 := KEY_DOWN if v0 key begin + v1 := 1 + py += 1 + end + end + v0 := KEY_LEFT if v0 key begin + v1 := 1 + move-left + if px < 2 then scroll-room-right + end + v0 := KEY_RIGHT if v0 key begin + v1 := 1 + move-right + if px > 110 then scroll-room-left + end + + # if no keys were pressed, snap to neutral pose: + if v1 == 0 then pframe := 0 + if v1 != 0 then next-frame +; + +########################################### +# +# Neck ESP +# +########################################### + +: reveal-pit-items + sparkle-pit-items + sync + sparkle-pit-items +; + +: sparkle-pit-items + v2 := 0 # byte offset to room data + loop + this-room + i += v2 + load v1 + # v0 sprite index + # v1 y-coord + + # make sure it's a pit + if v0 == 1 begin + v3 := v1 + v3 += 4 + v1 >>= v2 + v1 >>= v1 + v1 >>= v1 # v2 / 8 + loot-here + # v0 loot + # v3 y-coord + + # make sure an item is down there + if v0 != 0 begin + v1 += 4 + i := sparkle + v2 <<= v2 + v2 += 3 + sprite v2 v3 8 + v2 += -3 + v2 >>= v2 + end + end + + v2 += 8 + if v2 != 64 then + again +; + +########################################### +# +# Overworld Collision +# +########################################### + +: overworld-collide + py += 64 + + this-room + v3 := 0 + loop + load v1 + # v0 - slice sprite typecode + # v1 - slice Y position + # v3 - slice X position + + # ignore blank columns entirely + if v0 == 0 then jump overworld-continue + v1 += 64 + + # is eaty vertically within the slice? + v1 += 15 + if py > v1 then jump overworld-continue + v1 += -30 + if py < v1 then jump overworld-continue + + # is eaty horizontally within the slice? + v2 := v3 + v2 += 4 + if px > v2 then jump overworld-continue + v2 += -16 + if px < v2 then jump overworld-continue + + # perform an action based on sprite id + v0 += -1 + v0 >>= v0 + v0 >>= v0 + if v0 == 0 begin + v3 >>= v3 + v3 >>= v3 + v3 >>= v3 + pitindex >>= v3 + fall-pit + else + # tree + draw-eaty + restore-position + draw-eaty + bounce-out + end + return + +: overworld-continue + v3 += 4 + if v3 != 128 then + again +; + +########################################### +# +# Pit Items +# +########################################### + +: draw-item + v0 := ITEM_X + v1 := ITEM_Y + if has-item == ROSE begin + i := rose-0 + sprite v0 v1 0 + return + end + i := blank + if has-item == PART_1 then i := part-1 + if has-item == PART_2 then i := part-2 + if has-item == PART_3 then i := part-3 + sprite v0 v1 8 +; + +: near-item # return result in v0 + v0 := 0 + if has-item == 0 then return + if px < 36 then v0 := 1 +; + +: wilt-rose + v0 := ITEM_X + v1 := ITEM_Y + v2 := 0 + i := rose-0 + loop + sprite v0 v1 0 + vf := 32 + i += vf + sprite v0 v1 0 + sync + v2 += 1 + if v2 != 4 then + again + vf := ROSE_LIFE give-life +; + +: take-item + if has-item == ROSE begin + wilt-rose + else + draw-item + inventory |= has-item + end + has-item := 0 + v0 := 0 + v1 := pitindex + roomindex += -5 + loot-set + roomindex += 5 +; + +########################################### +# +# Pit Logic +# +########################################### + +: draw-pit + i := pit-wall + v1 := 0 + v0 := -8 + loop + sprite v0 v1 0 + v1 += 16 + if v1 != 64 then + again + + i := pit-ground + v0 := 8 + v1 := 48 + loop + sprite v0 v1 0 + v0 += 16 + if v0 != 120 then + again + + v1 := 33 + i := pit-lf + v0 := 8 + sprite v0 v1 15 + i := pit-rt + v0 := -16 + sprite v0 v1 15 + + draw-item +; + +: move-pit + # track whether any keys are held down + v1 := 0 + v0 := KEY_LEFT if v0 key begin + v1 := 1 + if px != 24 then move-left + end + v0 := KEY_RIGHT if v0 key begin + v1 := 1 + if px != 100 then move-right + end + + # if no keys were pressed, snap to neutral pose: + if v1 == 0 then pframe := 0 + if v1 != 0 then next-frame +; + +: fly-pit + draw-eaty + animate-magic-neck + draw-eaty + loop + draw-eaty + py += -2 + draw-eaty + sync + if py != 0 then + again + clear + + restore-position + roomindex += -5 + draw-room + draw-eaty + bounce-out +; + +: fall-pit + v1 := pitindex + loot-here + has-item := v0 + + roomindex += 5 + clear + draw-pit + px := 60 + py := 0 + pdir := FACE_LEFT + pframe := 0 + i := eaty-walk + + draw-eaty + loop + draw-eaty + py += 2 + draw-eaty + sync + if py != 32 then + again + + draw-hud + loop + draw-eaty + draw-hud + + move-pit + dec-timer + draw-eaty + + v0 := KEY_NECK if v0 key begin + near-item + if v0 == 1 begin + draw-eaty + animate-magic-neck + draw-eaty + take-item + else + fly-pit + return + end + end + + draw-hud + sync + + if is-dead == 0 then + again +; + +########################################### +# +# Randomized Loot +# +########################################### + +: randomize-loot + # distribute common/nonvital items: + + v1 := 0 # room-0 offset + v2 := 0 # loot-data offset + loop + # pits can be 0-1 + # ground can be 0-3 + is-pit + v3 := random 0b11 + if v0 == 1 then v3 := random 0b01 + v0 := v3 + i := loot-data + i += v2 + save v0 + + v1 += 8 + v2 += 1 + if v2 != 32 then + again + + # place CALL_SHIP on ground + try-place-call + + # place parts on pits + v4 := PART_1 + try-place-part + v4 := PART_2 + try-place-part + v4 := PART_3 + try-place-part +; + +: try-place-call + v3 := random 31 + is-v3-pit + if v0 == 1 then jump try-place-call + i := loot-data + i += v3 + load v0 + if v0 > 3 then jump try-place-call + i := loot-data + i += v3 + v0 := CALL_SHIP + #:breakpoint call-place + save v0 +; + +: try-place-part + v3 := random 31 + is-v3-pit + if v0 != 1 then jump try-place-part + i := loot-data + i += v3 + load v0 + if v0 > 3 then jump try-place-part + i := loot-data + i += v3 + v0 := v4 + #:breakpoint part-place + save v0 +; + +: is-v3-pit + v1 <<= v3 + v1 <<= v1 + v1 <<= v1 # offset * 8 +: is-pit + # takes offset in v1, + # leaves 1 in v0 if it's a pit. + i := room-0 + i += v1 + load v0 + if v0 != 1 then v0 := 0 +; + +########################################### +# +# Level Data +# +########################################### + +# loot definitions are 8 bytes per room. +: loot-data + 0 0 0 0 0 0 0 0 # room 0 + 0 0 0 0 0 0 0 0 # room 1 + 0 0 0 0 0 0 0 0 # room 2 + 0 0 0 0 0 0 0 0 # room 3 + 0 0 5 0 0 0 0 0 # room 4 + +: loot-px + # leaves result in v0 + v1 >>= px + v1 >>= v1 + v1 >>= v1 + v1 >>= v1 # px / 16 +: loot-here + # takes column in v1, leaves result in v0 + v0 <<= roomindex + v0 <<= v0 + v0 <<= v0 # roomindex * 8 + i := loot-data + i += v0 + i += v1 + load v0 +; + +: loot-set + # takes column in v1, value in v0 + i := loot-data + i += v1 + v1 <<= roomindex + v1 <<= v1 + v1 <<= v1 # roomindex * 8 + i += v1 + save v0 +; + +# rooms are 64 bytes each. +# each room is a series of packed pairs: +# +: room-0 + 0 0 0 0 0 0 0 0 + 1 8 2 8 3 8 4 8 # + 0 0 0 0 0 0 0 0 + 1 40 2 40 3 40 4 40 # + 0 0 0 0 0 0 0 0 + 1 8 2 8 3 8 4 8 # + 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 +: room-1 + 0 0 0 0 0 0 0 0 + 5 6 6 6 7 6 8 6 # + 0 0 0 0 0 0 0 0 + 5 40 6 40 7 40 8 40 # + 5 32 6 32 7 32 8 32 # + 0 0 0 0 0 0 0 0 + 5 20 6 20 7 20 8 20 # + 0 0 0 0 0 0 0 0 +: room-2 + 0 0 0 0 0 0 0 0 + 1 39 2 40 3 41 4 42 # + 1 6 2 5 3 4 4 3 # + 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 + 1 3 2 4 3 5 4 6 # + 1 42 2 41 3 40 4 39 # + 0 0 0 0 0 0 0 0 +: room-3 + 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 + 5 30 6 30 7 30 8 30 # + 5 40 6 40 7 40 8 40 # + 5 40 6 40 7 40 8 40 # + 5 6 6 6 7 6 8 6 # + 1 42 2 41 3 40 4 39 # + 0 0 0 0 0 0 0 0 +: room-4 + 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 + 5 40 6 40 7 40 8 40 # + 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 + +: this-room + v0 <<= roomindex + v0 <<= v0 + jump0 room-table + +: room-table + i := room-0 ; + i := room-1 ; + i := room-2 ; + i := room-3 ; + i := room-4 ; + +########################################### +# +# Graphics +# +########################################### + +# hud tiles +: heart 0x50 0xF8 0xF8 0x70 0x20 +: call-ship 0x1C 0x3C 0x7C 0x70 0x70 0x7C 0x3C 0x1C +: go-ship 0xE7 0xC3 0xA5 0x18 0x18 0xA5 0xC3 0xE7 +: pieces 0x30 0x48 0x4E 0x39 0x39 0x4E 0x48 0x30 +: neck-esp 0x08 0x04 0x12 0x4A 0x4A 0x12 0x04 0x08 +: sparkle 0x00 0x08 0x01 0x00 0x48 0x00 0x01 0x10 + +: part-tiles 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 # 0 - nothing +: part-1 0x7E 0xFF 0x81 0x00 0x00 0x00 0x00 0x00 # 1 - 1 +: part-2 0x00 0x00 0x24 0x3C 0x3C 0x24 0x00 0x00 # 2 - 2 + 0x7E 0xFF 0xA5 0x3C 0x3C 0x24 0x00 0x00 # 3 - 1,2 +: part-3 0x00 0x00 0x00 0x00 0x18 0x18 0x7E 0xFF # 4 - 3 + 0x7E 0xFF 0x81 0x00 0x18 0x18 0x7E 0xFF # 5 - 1,3 + 0x00 0x00 0x24 0x3C 0x24 0x3C 0x7E 0xFF # 6 - 2,3 + 0x7E 0xFF 0xA5 0x3C 0x24 0x3C 0x7E 0xFF # 7 - 1,2,3 + +: fingat 0xC0 + +# overworld tiles +# packed into 4 pixel wide vertical slices, +# so I can draw as I scroll horizontally. +: overworld-tiles +: blank 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 # 0 +: pit-0 0x10 0x70 0xF0 0xC0 0xB0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0x70 0x10 0x00 # 1 +: pit-1 0xF0 0xF0 0x00 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0x00 # 2 +: pit-2 0xF0 0xF0 0x00 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0x00 # 3 +: pit-3 0x80 0xE0 0xF0 0x30 0xD0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xE0 0x80 0x00 # 4 +: tree-0 0x00 0x00 0x00 0x00 0x10 0x30 0xF0 0x70 0x30 0x60 0xF0 0x70 0x50 0x00 0x00 0x00 # 5 +: tree-1 0x10 0x20 0x60 0xB0 0x60 0xF0 0xE0 0x50 0xF0 0xB0 0x70 0xF0 0xB0 0x30 0x30 0x00 # 6 +: tree-2 0x80 0x40 0x20 0x10 0x00 0x50 0x30 0x30 0x70 0xB0 0x70 0xF0 0xD0 0xC0 0xC0 0x00 # 7 +: tree-3 0x00 0x00 0x00 0x00 0x80 0xC0 0x70 0xE0 0xC0 0xE0 0x50 0xE0 0xC0 0x00 0x00 0x00 # 8 + +# pit background tiles +: pit-ground 0xF7 0xF7 0x7F 0x7F 0xED 0xED +: pit-wall 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF +: pit-lf 0x80 0x80 0xC0 0xC0 0xC0 0xE0 0xE0 0xE0 0xF0 0xF0 0xF0 0xF8 0xF8 0xFC 0xFE +: pit-rt 0x01 0x01 0x03 0x03 0x03 0x07 0x07 0x07 0x0F 0x0F 0x0F 0x1F 0x1F 0x3F 0x7F + +# rose wilting animation +: rose-0 + 0x00 0x00 0x00 0x00 0x05 0xE0 0x05 0xE0 + 0x05 0xE0 0x06 0xE0 0x03 0xC0 0x01 0x18 + 0x19 0xA8 0x14 0xD0 0x0A 0x60 0x07 0xC0 + 0x01 0x80 0x03 0x00 0x03 0x00 0x01 0x80 +: rose-1 + 0x00 0x00 0x00 0x00 0x01 0x00 0x0B 0x70 + 0x0B 0xE0 0x0D 0xE0 0x07 0xC0 0x01 0x00 + 0x01 0x80 0x1C 0xF0 0x22 0x68 0x1F 0xD8 + 0x01 0x80 0x03 0x00 0x03 0x00 0x01 0x80 +: rose-2 + 0x00 0x00 0x00 0x00 0x00 0x00 0x02 0x40 + 0x03 0xE0 0x0D 0xF0 0x07 0xF0 0x0F 0x30 + 0x01 0x80 0x00 0xE0 0x06 0x70 0x0F 0xD0 + 0x0D 0xB0 0x0B 0x20 0x03 0x00 0x01 0x80 +: rose-3 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x01 0x20 0x13 0xC0 0x0B 0xF0 + 0x1B 0xB0 0x0A 0xC0 0x00 0x60 0x03 0xC0 + 0x05 0xA0 0x0F 0x30 0x0B 0x70 0x01 0xA0 +: rose-4 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x01 0x00 0x03 0xC0 0x03 0xC0 + 0x03 0xC0 0x03 0xC0 0x00 0x60 0x01 0xC0 + 0x01 0x80 0x03 0x00 0x03 0x70 0x0D 0xB8 + +# eaty walk animation +: eaty-walk +: walk-l0 + 0x00 0x00 0x00 0x00 0x1F 0xF0 0x3F 0xF8 + 0x19 0xF8 0x3F 0xF8 0x3F 0x9C 0x2A 0x1C + 0x00 0x1C 0x07 0xFC 0x3F 0xC8 0x2F 0xD8 + 0x0F 0xF8 0x0F 0xF8 0x0D 0x18 0x1C 0x78 +: walk-l1 + 0x00 0x00 0x00 0x00 0x1F 0xF0 0x3F 0xF8 + 0x19 0xF8 0x3F 0xF8 0x3F 0x9C 0x2A 0x1C + 0x00 0x1C 0x07 0xCC 0x0F 0xD8 0x3F 0xF8 + 0x2F 0xF8 0x0F 0x98 0x0C 0xB8 0x1C 0x00 +: walk-l2 + 0x00 0x00 0x00 0x00 0x1F 0xF0 0x3F 0xF8 + 0x19 0xF8 0x3F 0xF8 0x3F 0x9C 0x2A 0x1C + 0x00 0x1C 0x07 0xFC 0x3F 0xC8 0x2F 0xD8 + 0x0F 0xF8 0x0F 0xF8 0x0D 0x18 0x1C 0x78 +: walk-l3 + 0x00 0x00 0x00 0x00 0x1F 0xF0 0x3F 0xF8 + 0x19 0xF8 0x3F 0xF8 0x3F 0x9C 0x2A 0x1C + 0x00 0x1C 0x37 0xFC 0x2F 0xF8 0x0F 0xC8 + 0x0F 0xD8 0x0D 0xF8 0x1D 0x18 0x00 0x78 +: walk-r0 + 0x00 0x00 0x00 0x00 0x0F 0xF8 0x1F 0xFC + 0x1F 0x98 0x1F 0xFC 0x39 0xFC 0x38 0x54 + 0x38 0x00 0x3F 0xE0 0x13 0xFC 0x1B 0xF4 + 0x1F 0xF0 0x1F 0xF0 0x18 0xB0 0x1E 0x38 +: walk-r1 + 0x00 0x00 0x00 0x00 0x0F 0xF8 0x1F 0xFC + 0x1F 0x98 0x1F 0xFC 0x39 0xFC 0x38 0x54 + 0x38 0x00 0x33 0xE0 0x1B 0xF0 0x1F 0xFC + 0x1F 0xF4 0x19 0xF0 0x1D 0x30 0x00 0x38 +: walk-r2 + 0x00 0x00 0x00 0x00 0x0F 0xF8 0x1F 0xFC + 0x1F 0x98 0x1F 0xFC 0x39 0xFC 0x38 0x54 + 0x38 0x00 0x3F 0xE0 0x13 0xFC 0x1B 0xF4 + 0x1F 0xF0 0x1F 0xF0 0x18 0xB0 0x1E 0x38 +: walk-r3 + 0x00 0x00 0x00 0x00 0x0F 0xF8 0x1F 0xFC + 0x1F 0x98 0x1F 0xFC 0x39 0xFC 0x38 0x54 + 0x38 0x00 0x3F 0xEC 0x1F 0xF4 0x13 0xF0 + 0x1B 0xF0 0x1F 0xB0 0x18 0xB8 0x1E 0x00 + +# magic neck animation +: eaty-neck +: neck-l-0 + 0x00 0x00 0x00 0x00 0x1F 0xF0 0x3F 0xF8 + 0x19 0xF8 0x3F 0xF8 0x3F 0x9C 0x2A 0x1C + 0x00 0x1C 0x07 0xFC 0x3F 0xC8 0x2F 0xD8 + 0x0F 0xF8 0x0F 0xF8 0x0D 0x18 0x1C 0x78 +: neck-l-1 + 0x00 0x00 0x1F 0xF0 0x3F 0xF0 0x1A 0xF8 + 0x1D 0xF8 0x3F 0x9C 0x2A 0x1C 0x00 0x1C + 0x00 0x1C 0x07 0xF8 0x3F 0xC8 0x2F 0xD8 + 0x0F 0xF8 0x0F 0xF8 0x0D 0x18 0x1C 0x78 +: neck-l-2 + 0x3F 0xF0 0x18 0xF0 0x1A 0xF8 0x18 0xF8 + 0x3F 0x98 0x2A 0x1C 0x00 0x1C 0x00 0x1C + 0x00 0x18 0x07 0xF8 0x3F 0xC8 0x2F 0xD8 + 0x0F 0xF8 0x0F 0xF8 0x0D 0x18 0x1C 0x78 +: neck-l-3 + 0x00 0x00 0x1F 0xF0 0x3F 0xF0 0x1A 0xF8 + 0x1D 0xF8 0x3F 0x9C 0x2A 0x1C 0x00 0x1C + 0x00 0x1C 0x07 0xF8 0x3F 0xC8 0x2F 0xD8 + 0x0F 0xF8 0x0F 0xF8 0x0D 0x18 0x1C 0x78 +: neck-r-0 + 0x00 0x00 0x00 0x00 0x0F 0xF8 0x1F 0xFC + 0x1F 0x98 0x1F 0xFC 0x39 0xFC 0x38 0x54 + 0x38 0x00 0x3F 0xE0 0x13 0xFC 0x1B 0xF4 + 0x1F 0xF0 0x1F 0xF0 0x18 0xB0 0x1E 0x38 +: neck-r-1 + 0x00 0x00 0x0F 0xF8 0x0F 0xFC 0x1F 0x58 + 0x1F 0xB8 0x39 0xFC 0x38 0x54 0x38 0x00 + 0x38 0x00 0x1F 0xE0 0x13 0xFC 0x1B 0xF4 + 0x1F 0xF0 0x1F 0xF0 0x18 0xB0 0x1E 0x38 +: neck-r-2 + 0x0F 0xFC 0x0F 0x18 0x1F 0x58 0x1F 0x18 + 0x19 0xFC 0x38 0x54 0x38 0x00 0x38 0x00 + 0x18 0x00 0x1F 0xE0 0x13 0xFC 0x1B 0xF4 + 0x1F 0xF0 0x1F 0xF0 0x18 0xB0 0x1E 0x38 +: neck-r-3 + 0x00 0x00 0x0F 0xF8 0x0F 0xFC 0x1F 0x58 + 0x1F 0xB8 0x39 0xFC 0x38 0x54 0x38 0x00 + 0x38 0x00 0x1F 0xE0 0x13 0xFC 0x1B 0xF4 + 0x1F 0xF0 0x1F 0xF0 0x18 0xB0 0x1E 0x38 + +# death animation +: die-0 + 0x00 0x00 0x03 0xC0 0x00 0x00 0x1F 0xF0 + 0x3F 0xF8 0x3F 0xF8 0x1B 0xF8 0x3F 0x9C + 0x2A 0x1C 0x00 0x1C 0x07 0xFC 0x0F 0xE8 + 0x1F 0xD8 0x2F 0xD8 0x0F 0xF8 0x1D 0x78 +: die-1 + 0x00 0x00 0x03 0xC0 0x04 0x20 0x03 0xC0 + 0x00 0x00 0x1F 0xF0 0x3F 0xF8 0x3F 0xF8 + 0x3F 0xFC 0x3F 0x9C 0x2A 0x7C 0x0F 0xFC + 0x0F 0xE8 0x0F 0xE8 0x0F 0xF8 0x1F 0xF8 + +: copter + 0xF8 0x1F 0x20 0x04 0xF9 0x1F 0xF9 0x1F + 0x89 0x11 0x73 0xCE 0x17 0xE8 0x0D 0xB0 + 0x07 0xE0 0x06 0x60 0xFB 0xDF 0x23 0xC4 + 0xFC 0x3F 0xF8 0x1F 0x88 0x11 0x70 0x0E + +: title-screen + 0x00 0x00 0x00 0xF8 0x07 0xF8 0x07 0xC0 + 0x07 0x00 0x07 0xB9 0x03 0xFB 0x03 0xE3 + 0x03 0x81 0x03 0xC5 0x01 0xDE 0x01 0xFE + 0x01 0xFC 0x00 0xF0 0x00 0x80 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x08 0x00 0x4C + 0x03 0x6C 0x9F 0xB8 0xD6 0x18 0x66 0x08 + 0xF3 0x0C 0xB3 0x0C 0x93 0x80 0xC0 0x00 + 0x00 0x75 0x00 0x27 0x00 0x25 0x00 0x25 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x70 0xC8 0x61 0x28 0x41 0xE8 0x71 0x2E + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0xBB 0x40 0xB2 0xC0 0xA2 0x40 0xBA 0x40 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x00 + 0x00 0x01 0x00 0x03 0x00 0x01 0x00 0x03 + 0x00 0x01 0x00 0x01 0x00 0x01 0x00 0x00 + 0x00 0x00 0x00 0x00 0x12 0x00 0x0F 0xFF + 0x35 0x00 0xC0 0x00 0xD0 0x00 0x82 0xC2 + 0x83 0xCB 0xD0 0x1C 0x94 0x00 0xDF 0xAA + 0xAE 0xEB 0xD6 0x3E 0xEB 0x00 0xF5 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0xC0 0x03 0x20 0x1C 0x21 0x23 0xC0 0xCC + 0xC0 0x90 0x21 0xA0 0x61 0x3E 0xC3 0x9D + 0x01 0x41 0x00 0xEA 0x00 0xFE 0x00 0xB8 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0xE0 0x00 0x20 0x00 0xC0 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x80 0x00 0x00 0x00 0x00 0x00 + +: game-over + 0x1E 0x79 0x3E 0xFD 0x30 0xCD 0x36 0xFD + 0x32 0xCD 0x3E 0xCD 0x1E 0xCD 0x00 0x00 + 0x0E 0x63 0x1F 0x63 0x1B 0x63 0x1B 0x63 + 0x1B 0x77 0x1F 0x3E 0x0E 0x1C 0x00 0x00 + 0x83 0x7C 0xC7 0x7C 0xEF 0x60 0xBB 0x78 + 0x93 0x60 0x83 0x7C 0x83 0x7C 0x00 0x00 + 0x7D 0xF0 0x7D 0xF8 0x61 0x98 0x79 0xF0 + 0x61 0x98 0x7D 0x98 0x7D 0x98 0x00 0x00 + +: victory + 0x00 0x32 0x00 0x4A 0xEE 0x7A 0xEE 0x4A + 0xEE 0x4B 0xEE 0x00 0xEE 0x9B 0xFE 0xA1 + 0x7C 0xA1 0x7C 0xA1 0x38 0xA1 0x38 0xA1 + 0x10 0x99 0x00 0x00 0x00 0x00 0x00 0x00 + 0x2E 0x90 0x28 0xD0 0x2E 0xB0 0x28 0xB0 + 0xAE 0x90 0x00 0x00 0xBB 0x36 0x2A 0xB6 + 0x2A 0xB6 0x2B 0x36 0x2A 0xB6 0x2A 0xBE + 0x3A 0x9E 0x00 0x06 0x00 0x3E 0x00 0x3C diff --git a/resources/octoroms/f8z.8o b/resources/octoroms/f8z.8o new file mode 100644 index 0000000..0e3a93e --- /dev/null +++ b/resources/octoroms/f8z.8o @@ -0,0 +1,254 @@ +########################################### +# +# F8Z: a chip8/Octo tech demo +# +# A/D move gomez left and right. +# Q/E rotate the world around him. +# Runs best at 100 cycles/frame. +# +########################################### + +: letter-F 0x07 0x19 0x61 0x81 0x87 0x99 0x81 0x81 0x87 0x9E 0x98 0x90 0x90 0xF0 0xE0 +: letter-8 0x0E 0x33 0x41 0x89 0x99 0x93 0x81 0xC1 0x89 0x99 0x91 0x83 0xCE 0x78 0x60 +: letter-Z 0x07 0x19 0x61 0x81 0x91 0xE1 0x43 0x86 0x89 0x81 0x81 0x87 0x9E 0xF8 0x60 + +: cloud1 0x07 0x0F 0x7F 0xFF +: cloud2 0xC0 0xE0 0xFE 0xFF +: cloud3 0x30 0x7E 0xFF + +: pillar # (padded to 16 bytes/side) + 0x06 0x1B 0x65 0x8F 0xD5 0xBD 0xFB 0x7E 0x83 0xBB 0xBB 0xBB 0x83 0x7F 0xFD 0x00 + 0x78 0xD6 0xFE 0xFD 0xBF 0xFF 0xFE 0xFF 0x83 0xAB 0xAB 0xBB 0x82 0xFF 0xBF 0x00 + 0x60 0xB8 0xFE 0xFB 0x7B 0x7F 0xFF 0xDF 0x83 0xBA 0xA3 0xBB 0x83 0x7F 0xFD 0x00 + 0x16 0xD9 0xA6 0xBB 0xFB 0xFF 0xDF 0xFE 0x82 0xBB 0xAB 0xAB 0x83 0x7F 0xF9 0x00 + +: floors # (padded to 8 bytes/tile) + 0xFE 0xFE 0xFE 0xE0 0xEF 0xEF 0xEF 0x00 + 0xEF 0xEF 0xEF 0xE0 0xFE 0xFE 0xFE 0x00 + 0xEF 0xEF 0xEF 0xE0 0xEE 0xEE 0xEE 0x00 + 0xFE 0xFE 0xFE 0xE0 0xEE 0xEE 0xEE 0x00 + +: gomez # (padded to 16 bytes/frame) + 0x00 0x00 0x60 0xE0 0x7E 0xFF 0xBD 0xF7 0x7E 0x18 0x3C 0x5E 0x3C 0x3C 0x24 0x00 # facing right + 0x00 0x60 0x60 0xFE 0xFF 0xBD 0xF7 0x7E 0x18 0x3C 0x5E 0x3C 0x3C 0x48 0x00 0x00 + 0x00 0x60 0x60 0xFE 0xFF 0xBD 0xF7 0x7E 0x18 0x7E 0x1C 0x3C 0x3C 0x24 0x00 0x00 + 0x00 0x00 0x60 0xFE 0xFF 0xFF 0xBD 0x76 0x18 0x3C 0x5E 0x3C 0x3C 0x12 0x00 0x00 + 0x00 0x00 0x06 0x07 0x7E 0xFF 0xBD 0xEF 0x7E 0x18 0x3C 0x7A 0x3C 0x3C 0x24 0x00 # facing left + 0x00 0x06 0x06 0x7F 0xFF 0xBD 0xEF 0x7E 0x18 0x3C 0x7A 0x3C 0x3C 0x12 0x00 0x00 + 0x00 0x06 0x06 0x7F 0xFF 0xBD 0xEF 0x7E 0x18 0x7E 0x38 0x3C 0x3C 0x24 0x00 0x00 + 0x00 0x00 0x06 0x7F 0xFF 0xFF 0xBD 0x6E 0x18 0x3C 0x7A 0x3C 0x3C 0x48 0x00 0x00 + +: pillar-pos + 46 10 16 46 + +: cloud-delta + 254 255 254 255 2 1 2 1 + +: sync + v2 := 4 + delay := v2 + loop + v2 := delay + if v2 != 0 then + again +; + +: draw-objects + v0 := 2 + v1 := vd + v1 += 8 + v2 := 1 + i := gomez + i += vc # animation frame + i += v8 # direction facing + sprite va vb 15 + + # clouds + i := cloud1 + sprite vd v0 4 + i := cloud2 + sprite v1 v0 4 + i := cloud3 + sprite ve v2 3 + + # pillar + i := pillar-pos # get x coord + i += v5 + load v0 + v1 := 9 + i := pillar + v2 <<= v5 # add (rotation * 16) + v2 <<= v2 + v2 <<= v2 + v2 <<= v2 + i += v2 + sprite v0 v1 15 +; + +: draw-background + v0 := 0 + v1 := 25 + loop + i := floors + v2 := random 0b11000 + i += v2 + sprite v0 v1 7 + v0 += 8 + if v0 != 64 then + again +; + +########################################### +# +# Wipe Effects +# +########################################### + +: wipe-common + v1 := 16 + buzzer := v1 + + v1 := 0b11 # wrap rotation modulo 4 + v5 &= v1 + + i := gomez + loop + i += v1 + + v1 := 1 + sprite v0 v1 15 + v1 := 16 + sprite v0 v1 15 + + sync + + v1 := 1 + sprite v0 v1 15 + v1 := 16 + sprite v0 v1 15 + v2 := v0 + + v0 += v3 + v1 := 0b111111 + v2 := v0 + v2 &= v1 + if v2 != 0 then + again + clear + draw-background +; + +: wipe-left + # rotate player's position + v0 := va + va := v7 + v7 := 64 + v7 -= v0 + + v5 += -1 + v0 := 64 + v3 := -16 + jump wipe-common + +: wipe-right + # rotate player's position + v0 := va + va := v7 + v7 := 64 + v7 += v0 + + v5 += 1 + v0 := 0 + v3 := 16 + jump wipe-common + +########################################### +# +# Movement and Animation +# +########################################### + +: walk + v9 += -1 # count down anim timer + vc += 16 # advance frame + v0 := 0b0110000 + vc &= v0 + if v8 == 0 then va += 1 # move + if v8 != 0 then va += -1 +; + +: face-left v8 := 64 ; +: move-left if v8 == 0 then jump face-left v9 := 4 ; +: face-right v8 := 0 ; +: move-right if v8 == 64 then jump face-right v9 := 4 ; + +: move-player + if v9 != 0 then jump walk + v0 := 7 + if v0 key then jump move-left + v0 := 9 + if v0 key then jump move-right + v0 := 4 + if v0 key then jump wipe-left + v0 := 6 + if v0 key then jump wipe-right +; + +########################################### +# +# Main Loop +# +########################################### + +: main + # title screen + v0 := 15 + v1 := 13 + i := letter-F + sprite v0 v1 15 + v0 += 12 + v1 += -5 + i := letter-8 + sprite v0 v1 15 + v0 += 12 + v1 += -5 + i := letter-Z + sprite v0 v1 15 + v0 := 16 + loop + sync + v0 += -1 + if v0 != 0 then + again + clear + + # v0-v3 are used extensively as temporaries + # v4 is still free + + v5 := 0 # rotation index + v6 := 0 # real x + v7 := 0 # real y + v8 := 0 # 0 - right, 64 - left + v9 := 0 # moving? + va := 10 # player x position + vb := 10 # player y position + vc := 0 # player anim frame + vd := 10 # big cloud x + ve := 40 # small cloud x + + draw-background + draw-objects + loop + draw-objects + move-player + + i := cloud-delta + i += v5 + i += v5 + load v1 + vd += v0 + ve += v1 + + draw-objects + sync + again diff --git a/resources/octoroms/fuse.8o b/resources/octoroms/fuse.8o new file mode 100644 index 0000000..7ccc90f --- /dev/null +++ b/resources/octoroms/fuse.8o @@ -0,0 +1,231 @@ +########################################### +# +# Fuse +# +# A minimalist reinterpretation of +# the classic Pipe Dream. Assemble lines +# to guide a burning fuse. Don't let it +# burn out! +# +# Press WASD to move the current line +# fragments and E to lay them down. +# You cannot lay down a line overlapping +# any existing lines. +# +# Runs best at 7 cycles/frame. +# +# John Earnest +# +########################################### + +:alias ex vd # fuse position x +:alias ey vc # fuse position y +:alias px vb # cursor position x +:alias py va # cursor position y +:alias tile v9 # selected tile +:alias timer-0 v8 # fuse movement cookoff +:alias timer-1 v7 # score (low digits) +:alias timer-2 v6 # score (high digits) + +:const tile-mask 0b111000 +:const fuse-speed 3 # higher is slower + +: main + init-game + + # draw starting cursor: + i := tiles + i += tile + sprite px py 8 + + # wait for an initial key press: + show-title + v0 := key + show-title + + loop + i := tiles + i += tile + + v0 := 6 if v0 key begin # keyboard E + # wait for key release: + loop if v0 key then again + + # we can't drop a tile overlapping + # any existing lines: + sprite px py 8 # erase + sprite px py 8 # redraw + + if vf == 0 begin + # drop a tile: + tile := random tile-mask + i := tiles + i += tile + sprite px py 8 + end + else + # erase the cursor: + sprite px py 8 + + # move cursor: + v0 := 5 if v0 key then py += -1 # keyboard W + v0 := 8 if v0 key then py += 1 # keyboard S + v0 := 7 if v0 key then px += -1 # keyboard A + v0 := 9 if v0 key then px += 1 # keyboard D + + # handle fuse movement without + # the cursor drawn, to avoid + # extreme weirdness: + move-fuse + + # redraw cursor: + i := tiles + i += tile + sprite px py 8 + end + + # sync framerate + loop + vf := delay + if vf != 0 then + again + vf := 6 + delay := vf + again + +: init-game + clear + + # set up a random starting position: + ex := random 15 + ex += 8 + ey := random 31 + ey += 16 + v0 := random 0b11000 + i := starts + i += v0 + sprite ex ey 8 + + # initialize the cursor: + tile := random tile-mask + px := 1 + py := 1 + + # reset score: + timer-0 := 0 + timer-1 := 0 + timer-2 := 0 +; + +: move-fuse + # don't move every single frame: + timer-0 += 1 + if timer-0 != fuse-speed then return + timer-0 := 0 + + # increment score: + timer-1 += 1 + if timer-1 == 100 begin + timer-1 := 0 + timer-2 += 1 + end + + :macro try-move SPRITE REG DELTA { + i := SPRITE + sprite ex ey 5 + if vf != 0 begin + REG += DELTA + return + end + sprite ex ey 5 + } + try-move dot-n ey -1 # north + try-move dot-e ex 1 # east + try-move dot-s ey 1 # south + try-move dot-w ex -1 # west + +: game-over + # no trail, so we've failed! + i := dot + v0 := 6 # keyboard E + loop + sprite ex ey 5 + if v0 -key then # key down + again + loop + if v0 key then # key up + again + clear + +: show-score + v3 := 37 # x position + v4 := 10 # y position + + # draw low two digits: + i := digit-buffer + bcd timer-1 + show-score-byte + + # draw high two digits: + i := digit-buffer + bcd timer-2 + show-score-byte + + # wait for any key: + v0 := key + + init-game +; + +: show-score-byte + load v2 + i := hex v2 + sprite v3 v4 5 + v3 += -5 + i := hex v1 + sprite v3 v4 5 + v3 += -5 +; + +: show-title + v0 := 52 + v1 := 2 + v2 := 1 + i := title + loop + sprite v0 v1 1 + v1 += 1 + i += v2 + if v1 != 30 then + again +; + +: digit-buffer 0 0 0 + +: title + 0x7F 0xFF 0xC0 0xFC 0xC0 0xC0 0x00 0xC3 + 0xC3 0xC3 0xFF 0x7E 0x00 0x7F 0xFF 0xC0 + 0xFF 0x03 0xFF 0xFE 0x00 0x7F 0xFF 0xC0 + 0xFC 0xC0 0xFF 0x7F + +: dot 0x00 0x00 0x00 0x10 0x00 +: dot-n 0x00 0x00 0x10 0x00 0x00 +: dot-s 0x00 0x00 0x00 0x00 0x10 +: dot-e 0x00 0x00 0x00 0x08 0x00 +: dot-w 0x00 0x00 0x00 0x20 0x00 + +: starts + 0x40 0x5C 0x54 0x44 0x44 0x7C 0x00 0x00 # N + 0x00 0x7F 0x40 0x4C 0x44 0x7C 0x00 0x00 # E + 0x00 0x7C 0x44 0x44 0x54 0x74 0x04 0x00 # S + 0x00 0x3C 0x24 0x24 0x04 0xFC 0x00 0x00 # W + +: tiles + 0x20 0x20 0xE0 0x00 0x0F 0x08 0x08 0x08 # cross 1 + 0x04 0x04 0x0C 0x08 0xEF 0x20 0x20 0x20 # cross 2 + 0x02 0x7E 0x40 0x7E 0x02 0x7E 0x40 0x7E # zig n-s + 0xC0 0x5C 0x54 0x55 0x55 0x55 0x57 0x70 # zig e-w + 0x14 0x14 0x34 0xE7 0x00 0x7E 0xC3 0x00 # tee N + 0x40 0x5F 0x50 0x57 0x54 0x54 0x54 0x54 # tee E + 0x00 0xF0 0x1F 0xC0 0x6E 0x2A 0x2B 0x28 # tee S + 0x22 0xE2 0x02 0x72 0x56 0x54 0xD4 0x14 # tee W diff --git a/resources/octoroms/gradsim.8o b/resources/octoroms/gradsim.8o new file mode 100644 index 0000000..7f629ca --- /dev/null +++ b/resources/octoroms/gradsim.8o @@ -0,0 +1,215 @@ +########################################### +# +# Grad School Simulator 2014 +# +# "Welcome to the sunless depths of my ennui." +# +########################################### + +: main + hires + draw-background + loop + do-behavior + again + +: do-behavior + # by AND masking an 8 bit value with 0b1110 + # we can create the numbers 0,2,4,8,10,12,14,16: + v0 := random 0b1110 + jump0 behavior-table + +: behavior-table + # this is a jump table. Each entry + # is 1 instruction long, or 2 bytes: + jump blink + jump blink + jump idle + jump idle + jump grimace + jump show-icon + jump show-icon + jump show-icon + +# here I've overlapped two subroutines, +# since they share the same ending instructions: +: blink + blink-toggle + vf := 10 wait + blink-toggle +: idle + vf := 45 wait +; + +: blink-toggle + i := blink-mask + v0 := 55 + v1 := 26 + sprite v0 v1 3 + v0 := 65 + v1 := 26 + sprite v0 v1 3 +; + +: wait + # takes a time argument in vf. + # vf gets destroyed by +/-/>>/<> 16 } } + +:macro mirror-v_ { :byte { @ from + 7 - HERE - to } } +:macro mirror-h_ { :calc t { @ from + HERE - to } rev8 t } +:macro mirror-8 BASE OP { :calc to { HERE } :calc from { BASE } OP OP OP OP OP OP OP OP } +:macro mirror-v BASE { mirror-8 BASE mirror-v_ } +:macro mirror-h BASE { mirror-8 BASE mirror-h_ } + +: sprite-1 0x18 0x2C 0x46 0x83 0xEF 0x2C 0x2C 0x3C +: sprite-3 0x18 0x14 0xF2 0x81 0xF3 0xF6 0x1C 0x18 +: sprite-2 mirror-v sprite-1 +: sprite-4 mirror-h sprite-3 diff --git a/resources/octoroms/mondrian.8o b/resources/octoroms/mondrian.8o new file mode 100644 index 0000000..6f6381e --- /dev/null +++ b/resources/octoroms/mondrian.8o @@ -0,0 +1,80 @@ +########################################### +# +# Mondri8 +# +# Draw random compositions in the style +# of Piet Mondrian. When drawing completes, +# press any Chip8 key to draw another. +# +########################################### + +:const LINE_COUNT 10 +:const FILL_COUNT 5 + +:alias x v0 +:alias y v1 +:alias px v2 # x position when scanning +:alias py v3 # y position when scanning +:alias dx v4 # change (delta) in x position when scanning +:alias dy v5 # change (delta) in y position when scanning +:alias counter v6 + +: main + hires + i := point + loop + counter := LINE_COUNT + loop + somewhere h-line + somewhere v-line + counter += -1 + if counter != 0 then + again + counter := FILL_COUNT + loop + somewhere fill + counter += -1 + if counter != 0 then + again + v0 := key + clear + again + +: somewhere + x := random 0xFF + y := random 0xFF +; + +: scan + loop + sprite px py 1 + while vf == 0 + px += dx + py += dy + again + sprite px py 1 +; + +: v-line + px := x dx := 0 + py := y dy := -1 scan + py := y dy := 1 py += dy scan +; + +: h-line + py := y dy := 0 + px := x dx := -1 scan + px := x dx := 1 px += dx scan +; + +: fill + loop + h-line + y += 1 + sprite x y 1 + while vf == 0 + again + sprite x y 1 +; + +: point 0x80 diff --git a/resources/octoroms/murder.8o b/resources/octoroms/murder.8o new file mode 100644 index 0000000..a6677a1 --- /dev/null +++ b/resources/octoroms/murder.8o @@ -0,0 +1,4010 @@ +########################################### +# +# An Evening to Die For +# +# It is a dark and stormy night. +# A murer has been committed. +# Track down a murder weapon and identify +# the killer to bring them to justice! +# +# Arrow keys/ASWD move and change selections, +# Space/E advance dialog, confirm selections, +# and search the surrounding area for clues. +# +# An entry in the 2019 Octojam 6 +# by John Earnest +# +########################################### + +:calc CODE_POS { 0x200 } +:calc DATA_POS { 0x1000 } +:macro to-code { :calc DATA_POS { HERE } :org { CODE_POS } } +:macro to-data { :calc CODE_POS { HERE } :org { DATA_POS } } + +:macro unpack16 ADDR { + :calc hi { 0xFF & ADDR >> 8 } v0 := hi + :calc lo { 0xFF & ADDR } v1 := lo +} +:macro pointer ADDR { + :byte { 0xFF & ADDR >> 8 } + :byte { 0xFF & ADDR } +} +:macro indirect LABEL { + 0xF0 0x00 : LABEL 0x00 0x00 # i := long NNNN +} + +:macro mirror-byte X { + :byte { ( 1 & X >> 7 ) | ( 2 & X >> 5 ) | ( 4 & X >> 3 ) | ( 8 & X >> 1 ) | + ( 128 & X << 7 ) | ( 64 & X << 5 ) | ( 32 & X << 3 ) | ( 16 & X << 1 ) } +} +:macro mirror-8x15-row { + :calc val { @ base + index } + mirror-byte val + :calc index { index + 1 } +} +:macro mirror-8x15 ADDR { + :calc base { ADDR } + :calc index { 0 } + mirror-8x15-row + mirror-8x15-row + mirror-8x15-row + mirror-8x15-row + mirror-8x15-row + mirror-8x15-row + mirror-8x15-row + mirror-8x15-row + mirror-8x15-row + mirror-8x15-row + mirror-8x15-row + mirror-8x15-row + mirror-8x15-row + mirror-8x15-row + mirror-8x15-row +} + +: sync + vf := 5 +: sync-custom + delay := vf + loop + vf := delay + if vf != 0 then + again +; +:macro wait TIME { + vf := TIME + sync-custom +} + +: full-screen-blit #lrtb + v0 := 0 + v1 := 0 + v2 := 16 + v3 := 32 + v4 := 48 + loop + sprite v0 v1 0 i += v3 + sprite v0 v2 0 i += v3 + sprite v0 v3 0 i += v3 + sprite v0 v4 0 i += v3 + v0 += 16 + if v0 != 128 then + again +; + +########################################### +# +# Global State +# +########################################### + +# v0-v4 and ve are currently reserved for temporaries +:const GAME_OVER 0xFA # set current-room to this to bail out. +:alias current-room vd +:alias suspicion-level vc # 0-255 +:alias has-spyglass vb # 0/1 +:alias has-weapon va # 0/1 + +# used during room exploration mode: +:alias prev-x v5 +:alias prev-y v6 +:alias player-face v7 +:alias player-x v8 +:alias player-y v9 + +# used during endgame: +:alias accused-npc v9 +:alias guilty-npc v8 +:alias guilty-weapon v7 + +# how much does various actions advanced the game? +:const SUSPICION_TALK_NPC 2 +:const SUSPICION_TALK_MURDERER 5 +:const SUSPICION_EXAMINE_DECO 1 +:const SUSPICION_EXAMINE_ITEM 2 +:const SUSPICION_ENTER_ROOM 1 +:const SUSPICION_TAKE_WEAPON 5 +:const SUSPICION_TAKE_SPYGLASS 5 + +: thicken-plot-sub + suspicion-level += ve + if vf != 0 then suspicion-level := 0xFF +; +:macro thicken-plot CONST { + ve := CONST + thicken-plot-sub +} + +to-data + +: has-body-room 0x00 # 0-9 +: has-passage-room 0x00 # 0-9, replaces desc 1 +: has-secret-room 0x00 # 0-9, replaces desc 2 +: murder-weapon 0x00 # 0-7 + +: initial-item-positions + 0 1 2 3 4 5 6 7 8 -1 -1 +: item-positions + 0 0 0 0 0 0 0 0 0 0 0 + +: npc-positions + 0 1 # room 0, [slot 1, slot 2] ... + 2 3 # room 1 + 4 5 # room 2 + 6 7 # room 3 + -1 -1 # room 4 + -1 -1 # room 5 + -1 -1 # room 6 + -1 -1 # room 7 + -1 -1 # room 8 + -1 -1 # room 9 + -1 -1 # room 10 + +: npc-alibis + : npc-alibi-p1 0 1 # first pair + : npc-alibi-p2 2 3 # second pair + : npc-alibi-p3 4 5 # third pair + : npc-alone 6 # by themselves + : npc-murderer 7 # what it says on the tin + +: npc-quip-index +: npc-quip-1 0 1 +: npc-quip-2 2 3 + 4 5 6 7 + +: npc-scoff-index + 0 1 2 3 4 5 6 7 + +: npc-alibi-rooms + : npc-alibi-r1 0 + : npc-alibi-r2 1 + : npc-alibi-r3 2 + : npc-alibi-r4 3 + : npc-alibi-r5 4 + 5 6 7 8 9 # and the rest aren't occupied + +to-code + +: random-upto-v1 + loop + v0 := random 0xF + if v0 > v1 then + again +; + +: shuffle-base i := long 0 ; # SMC +: shuffle-array + loop + v1 := v4 + random-upto-v1 + v3 := v0 + + if v3 != v4 begin + # swap a[v4] / a[v3]... + shuffle-base + i += v3 + load v1 - v1 # has a[v3] + shuffle-base + i += v4 + load v2 - v2 # has a[v4] + save v1 - v1 + shuffle-base + i += v3 + save v2 - v2 + end + + v4 += -1 + if v4 != 2 then + again +; + +:macro random-scalar MAX ADDR { + v1 := MAX + random-upto-v1 + i := long ADDR + save v0 +} +:macro shuffle LEN ADDR { + :calc target { shuffle-base + 2 } + i := target + unpack16 ADDR + save v1 + :calc maxindex { LEN - 1 } + v4 := maxindex + shuffle-array +} + +:macro plot-a-murder { + # gotta re-initialize this, + # as items can be removed during gameplay: + i := long initial-item-positions + load vA + i := long item-positions + save vA + + # generate randomized scenario + random-scalar 9 has-body-room + random-scalar 9 has-passage-room + random-scalar 9 has-secret-room + random-scalar 7 murder-weapon + shuffle 11 item-positions + shuffle 18 npc-positions + shuffle 8 npc-alibis + shuffle 8 npc-quip-index + shuffle 8 npc-scoff-index + shuffle 10 npc-alibi-rooms + + # re-init global game state + suspicion-level := 0 + has-spyglass := 0 + has-weapon := 0 + current-room := 5 +} + +########################################### +# +# Text rendering routines +# +# These generic routines can draw pre-wrapped +# bytecoded strings with 2 colors, 2 font sizes, +# and 2 inlineable text fragment slots, +# as created by EZ-Writer: +# +# http://beyondloom.com/tools/ezwriter.html +# +# Pointers are "passed" to these routines +# by rewriting immediate i-loads, +# and macros help make the process more compact. +# +# Note that fragments should NOT contain STR_POS +# or recursive fragment references! +# +########################################### + +:const STR_END 0xFF +:const STR_POS 0xFE +:const STR_COLOR 0xFD +:const STR_SIZE 0xFC +:const STR_SLOT_0 0xFB +:const STR_SLOT_1 0xFA +:const STR_SPACE 0xF9 + +:const CHAR_WIDTH_SMALL 6 +:const CHAR_WIDTH_LARGE 8 +:calc CHAR_WIDTH_DIFF { CHAR_WIDTH_LARGE - CHAR_WIDTH_SMALL } + +:alias fragment-offset v3 +:alias string-offset v4 +:alias cursor-x v5 +:alias cursor-y v6 +:alias font-size v7 +:alias font-color v8 +:alias bit-flip v9 + +: print-char + if v0 == STR_POS begin + string-offset += 2 + cursor-x := v1 + cursor-y := v2 + return + end + if v0 == STR_SPACE begin + cursor-x += CHAR_WIDTH_SMALL + if font-size != 0 then cursor-x += CHAR_WIDTH_DIFF + return + end + if v0 == STR_COLOR begin + font-color ^= bit-flip + return + end + if v0 == STR_SIZE begin + font-size ^= bit-flip + return + end + if v0 == STR_SLOT_0 begin + fragment-offset := 0 + loop + indirect print-string0-read + i += fragment-offset + load v0 + if v0 == STR_END then return + fragment-offset += 1 + print-char + again + end + if v0 == STR_SLOT_1 begin + fragment-offset := 0 + loop + indirect print-string1-read + i += fragment-offset + load v0 + if v0 == STR_END then return + fragment-offset += 1 + print-char + again + end + # draw a plain character + if font-size == 0 begin + i := long font + i += v0 # add v0 * 9 + v0 += v0 + i += v0 + i += v0 + i += v0 + i += v0 + sprite cursor-x cursor-y 9 + if font-color != 0 begin + plane 2 + sprite cursor-x cursor-y 9 + plane 1 + end + cursor-x += CHAR_WIDTH_SMALL + else + i := long bigfont + v0 += v0 # add v0 * 14 + i += v0 + i += v0 + i += v0 + i += v0 + i += v0 + i += v0 + i += v0 + sprite cursor-x cursor-y 14 + if font-color != 0 begin + plane 2 + sprite cursor-x cursor-y 14 + plane 1 + end + cursor-x += CHAR_WIDTH_LARGE + end +; +: print-text + i := print-string-read + save v1 + i := long string-stash + save vf + i := long print-text-registers + load string-offset - bit-flip + loop + indirect print-string-read + i += string-offset + load v2 + while v0 != STR_END + string-offset += 1 + print-char + again + i := long string-stash + load vf +; + +:macro print ADDR { unpack16 ADDR print-text } + +to-data + +: print-text-registers + 0 0 0 0 0 1 +: string-stash + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + +: font + 0x1C 0x22 0x22 0x3E 0x22 0x22 0x22 0x00 0x00 # A + 0x3C 0x22 0x22 0x3C 0x22 0x22 0x3C 0x00 0x00 # B + 0x1C 0x22 0x20 0x20 0x20 0x22 0x1C 0x00 0x00 # C + 0x3C 0x22 0x22 0x22 0x22 0x22 0x3C 0x00 0x00 # D + 0x3E 0x20 0x20 0x3C 0x20 0x20 0x3E 0x00 0x00 # E + 0x3E 0x20 0x20 0x3C 0x20 0x20 0x20 0x00 0x00 # F + 0x1C 0x22 0x20 0x26 0x22 0x22 0x1C 0x00 0x00 # G + 0x22 0x22 0x22 0x3E 0x22 0x22 0x22 0x00 0x00 # H + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x00 0x00 # I + 0x02 0x02 0x02 0x02 0x22 0x22 0x1C 0x00 0x00 # J + 0x22 0x24 0x28 0x30 0x28 0x24 0x22 0x00 0x00 # K + 0x20 0x20 0x20 0x20 0x20 0x20 0x3E 0x00 0x00 # L + 0x22 0x36 0x2A 0x22 0x22 0x22 0x22 0x00 0x00 # M + 0x22 0x32 0x2A 0x26 0x22 0x22 0x22 0x00 0x00 # N + 0x1C 0x22 0x22 0x22 0x22 0x22 0x1C 0x00 0x00 # O + 0x3C 0x22 0x22 0x3C 0x20 0x20 0x20 0x00 0x00 # P + 0x1C 0x22 0x22 0x22 0x22 0x22 0x1C 0x02 0x00 # Q + 0x3C 0x22 0x22 0x3C 0x22 0x22 0x22 0x00 0x00 # R + 0x1C 0x22 0x20 0x1C 0x02 0x22 0x1C 0x00 0x00 # S + 0x3E 0x08 0x08 0x08 0x08 0x08 0x08 0x00 0x00 # T + 0x22 0x22 0x22 0x22 0x22 0x22 0x1C 0x00 0x00 # U + 0x22 0x22 0x22 0x14 0x14 0x08 0x08 0x00 0x00 # V + 0x22 0x22 0x22 0x22 0x2A 0x36 0x22 0x00 0x00 # W + 0x22 0x14 0x08 0x08 0x08 0x14 0x22 0x00 0x00 # X + 0x22 0x22 0x22 0x14 0x08 0x08 0x08 0x00 0x00 # Y + 0x3E 0x02 0x04 0x08 0x10 0x20 0x3E 0x00 0x00 # Z + 0x00 0x00 0x1E 0x22 0x22 0x26 0x1A 0x00 0x00 # a + 0x20 0x20 0x3C 0x22 0x22 0x22 0x3C 0x00 0x00 # b + 0x00 0x00 0x1C 0x22 0x20 0x20 0x1E 0x00 0x00 # c + 0x02 0x02 0x1E 0x22 0x22 0x22 0x1E 0x00 0x00 # d + 0x00 0x00 0x1C 0x22 0x3E 0x20 0x1E 0x00 0x00 # e + 0x06 0x08 0x1C 0x08 0x08 0x08 0x08 0x00 0x00 # f + 0x00 0x00 0x1E 0x22 0x22 0x22 0x1E 0x02 0x1C # g + 0x20 0x20 0x3C 0x22 0x22 0x22 0x22 0x00 0x00 # h + 0x08 0x00 0x08 0x08 0x08 0x08 0x08 0x00 0x00 # i + 0x08 0x00 0x08 0x08 0x08 0x08 0x08 0x08 0x30 # j + 0x20 0x20 0x24 0x28 0x38 0x24 0x22 0x00 0x00 # k + 0x08 0x08 0x08 0x08 0x08 0x08 0x0C 0x00 0x00 # l + 0x00 0x00 0x3C 0x2A 0x2A 0x2A 0x2A 0x00 0x00 # m + 0x00 0x00 0x2C 0x32 0x22 0x22 0x22 0x00 0x00 # n + 0x00 0x00 0x1C 0x22 0x22 0x22 0x1C 0x00 0x00 # o + 0x00 0x00 0x3C 0x22 0x22 0x22 0x3C 0x20 0x20 # p + 0x00 0x00 0x1E 0x22 0x22 0x22 0x1E 0x02 0x02 # q + 0x00 0x00 0x2C 0x32 0x20 0x20 0x20 0x00 0x00 # r + 0x00 0x00 0x1E 0x20 0x1C 0x02 0x3C 0x00 0x00 # s + 0x08 0x08 0x1E 0x08 0x08 0x08 0x06 0x00 0x00 # t + 0x00 0x00 0x22 0x22 0x22 0x26 0x1A 0x00 0x00 # u + 0x00 0x00 0x22 0x22 0x14 0x14 0x08 0x00 0x00 # v + 0x00 0x00 0x2A 0x2A 0x2A 0x2A 0x14 0x00 0x00 # w + 0x00 0x00 0x22 0x14 0x08 0x14 0x22 0x00 0x00 # x + 0x00 0x00 0x22 0x22 0x22 0x22 0x1E 0x02 0x1C # y + 0x00 0x00 0x3E 0x04 0x08 0x10 0x3E 0x00 0x00 # z + 0x1C 0x22 0x26 0x2A 0x32 0x22 0x1C 0x00 0x00 # 0 + 0x08 0x18 0x08 0x08 0x08 0x08 0x08 0x00 0x00 # 1 + 0x1C 0x22 0x02 0x04 0x08 0x10 0x3E 0x00 0x00 # 2 + 0x1C 0x22 0x02 0x0C 0x02 0x22 0x1C 0x00 0x00 # 3 + 0x04 0x0C 0x14 0x24 0x3E 0x04 0x04 0x00 0x00 # 4 + 0x3E 0x20 0x3C 0x02 0x02 0x22 0x1C 0x00 0x00 # 5 + 0x1C 0x20 0x3C 0x22 0x22 0x22 0x1C 0x00 0x00 # 6 + 0x3E 0x02 0x02 0x04 0x08 0x08 0x08 0x00 0x00 # 7 + 0x1C 0x22 0x22 0x1C 0x22 0x22 0x1C 0x00 0x00 # 8 + 0x1C 0x22 0x22 0x22 0x1E 0x02 0x1C 0x00 0x00 # 9 + 0x00 0x00 0x00 0x00 0x00 0x0C 0x0C 0x00 0x00 # . + 0x08 0x08 0x08 0x08 0x08 0x00 0x08 0x00 0x00 # ! + 0x1C 0x22 0x02 0x04 0x08 0x00 0x08 0x00 0x00 # ? + 0x00 0x00 0x00 0x00 0x00 0x18 0x18 0x08 0x10 # , + 0x08 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00 # ' + 0x00 0x00 0x00 0x3E 0x00 0x00 0x00 0x00 0x00 # - + 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0x00 0x00 # " + +: bigfont + 0x38 0x7C 0x6C 0x6C 0xC6 0xC6 0xFE 0xFE 0xC6 0xC6 0xC6 0xC6 0x00 0x00 # A + 0xF8 0xFC 0xCC 0xCC 0xF8 0xFC 0xC6 0xC6 0xC6 0xC6 0xFE 0xFC 0x00 0x00 # B + 0x7C 0xFE 0xC6 0xC0 0xC0 0xC0 0xC0 0xC0 0xC0 0xC6 0xFE 0x7C 0x00 0x00 # C + 0xF8 0xFC 0xCE 0xC6 0xC6 0xC6 0xC6 0xC6 0xC6 0xCE 0xFC 0xF8 0x00 0x00 # D + 0xFE 0xFE 0xC0 0xC0 0xC0 0xF8 0xF8 0xC0 0xC0 0xC0 0xFE 0xFE 0x00 0x00 # E + 0xFE 0xFE 0xC0 0xC0 0xC0 0xF8 0xF8 0xC0 0xC0 0xC0 0xC0 0xC0 0x00 0x00 # F + 0x7C 0xFE 0xC6 0xC6 0xC0 0xDE 0xDE 0xC6 0xC6 0xE6 0x7E 0x3E 0x00 0x00 # G + 0xC6 0xC6 0xC6 0xC6 0xC6 0xFE 0xFE 0xC6 0xC6 0xC6 0xC6 0xC6 0x00 0x00 # H + 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x00 0x00 # I + 0x0C 0x0C 0x0C 0x0C 0x0C 0x0C 0xCC 0xCC 0xCC 0xCC 0xFC 0x78 0x00 0x00 # J + 0xC6 0xCE 0xDC 0xF8 0xF0 0xF0 0xF8 0xD8 0xCC 0xCC 0xC6 0xC6 0x00 0x00 # K + 0xC0 0xC0 0xC0 0xC0 0xC0 0xC0 0xC0 0xC0 0xC0 0xC0 0xFE 0xFE 0x00 0x00 # L + 0xEC 0xFE 0xFE 0xD6 0xD6 0xD6 0xD6 0xC6 0xC6 0xC6 0xC6 0xC6 0x00 0x00 # M + 0xF8 0xFC 0xCC 0xCE 0xC6 0xC6 0xC6 0xC6 0xC6 0xC6 0xC6 0xC6 0x00 0x00 # N + 0x7C 0xFE 0xC6 0xC6 0xC6 0xC6 0xC6 0xC6 0xC6 0xC6 0xFE 0x7C 0x00 0x00 # O + 0xFC 0xFE 0xC6 0xC6 0xC6 0xFE 0xFC 0xC0 0xC0 0xC0 0xC0 0xC0 0x00 0x00 # P + 0x7C 0xFE 0xC6 0xC6 0xC6 0xC6 0xD6 0xDE 0xDC 0xCE 0xF6 0x76 0x00 0x00 # Q + 0xFC 0xFE 0xC6 0xC6 0xC6 0xFE 0xFC 0xD8 0xCC 0xCC 0xC6 0xC6 0x00 0x00 # R + 0x7C 0xFE 0xC6 0xC0 0xC0 0xFC 0x7E 0x06 0x06 0xC6 0xFE 0x7C 0x00 0x00 # S + 0xFE 0xFE 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x38 0x18 0x00 0x00 # T + 0xC6 0xC6 0xC6 0xC6 0xC6 0xC6 0xC6 0xC6 0xC6 0xC6 0xFE 0x7C 0x00 0x00 # U + 0xC6 0xC6 0xC6 0xC6 0xC6 0xC6 0xE6 0x66 0x76 0x3E 0x1E 0x0E 0x00 0x00 # V + 0xC6 0xC6 0xC6 0xC6 0xC6 0xC6 0xD6 0xD6 0xD6 0xD6 0xFE 0xEC 0x00 0x00 # W + 0xC6 0xC6 0xEE 0x6C 0x7C 0x38 0x7C 0x6C 0x6C 0xC6 0xC6 0xC6 0x00 0x00 # X + 0xC6 0xC6 0xC6 0xE6 0x7E 0x3E 0x06 0x06 0x06 0xC6 0xFE 0x7C 0x00 0x00 # Y + 0xFE 0xFE 0x0C 0x0C 0x18 0x18 0x30 0x30 0x60 0x60 0xFE 0xFE 0x00 0x00 # Z + 0x00 0x00 0x00 0x00 0x76 0xFE 0xCE 0xC6 0xC6 0xC6 0xFE 0x7E 0x00 0x00 # a + 0xC0 0xC0 0xC0 0xC0 0xDC 0xFE 0xE6 0xC6 0xC6 0xC6 0xFE 0xFC 0x00 0x00 # b + 0x00 0x00 0x00 0x00 0x7C 0xFE 0xC6 0xC0 0xC0 0xC6 0xFE 0x7C 0x00 0x00 # c + 0x06 0x06 0x06 0x06 0x76 0xFE 0xCE 0xC6 0xC6 0xC6 0xFE 0x7E 0x00 0x00 # d + 0x00 0x00 0x00 0x00 0x7C 0xFE 0xC6 0xFE 0xF8 0xC6 0xFE 0x7C 0x00 0x00 # e + 0x00 0x1E 0x3E 0x30 0xFE 0xFE 0x30 0x30 0x30 0x30 0x70 0x60 0x00 0x00 # f + 0x00 0x00 0x00 0x00 0x7C 0xFE 0xC6 0xC6 0xC6 0xFE 0x7E 0x06 0xFE 0xFC # g + 0xC0 0xC0 0xC0 0xC0 0xDC 0xFE 0xE6 0xC6 0xC6 0xC6 0xC6 0xC6 0x00 0x00 # h + 0x00 0x18 0x18 0x00 0x18 0x18 0x18 0x18 0x18 0x18 0x1C 0x1C 0x00 0x00 # i + 0x00 0x18 0x18 0x00 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0xD8 0xF8 0x70 # j + 0xC0 0xC0 0xC0 0xC6 0xCE 0xDC 0xF8 0xF0 0xF8 0xDC 0xCE 0xC6 0x00 0x00 # k + 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x3C 0x3C 0x00 0x00 # l + 0x00 0x00 0x00 0x00 0xEC 0xFE 0xFE 0xD6 0xD6 0xC6 0xC6 0xC6 0x00 0x00 # m + 0x00 0x00 0x00 0x00 0xBC 0xFE 0xE6 0xC6 0xC6 0xC6 0xC6 0xC6 0x00 0x00 # n + 0x00 0x00 0x00 0x00 0x7C 0xFE 0xC6 0xC6 0xC6 0xC6 0xFE 0x7C 0x00 0x00 # o + 0x00 0x00 0x00 0x00 0xBC 0xFE 0xC6 0xC6 0xC6 0xC6 0xFE 0xFC 0xC0 0xC0 # p + 0x00 0x00 0x00 0x00 0x76 0xFE 0xCE 0xC6 0xC6 0xC6 0xFE 0x7E 0x06 0x06 # q + 0x00 0x00 0x00 0x00 0xDC 0xFE 0xE6 0xC6 0xC0 0xC0 0xC0 0xC0 0x00 0x00 # r + 0x00 0x00 0x00 0x00 0x7E 0xFE 0xC0 0xFC 0x7E 0x06 0xFE 0xFC 0x00 0x00 # s + 0x00 0x30 0x30 0x30 0xFE 0xFE 0x30 0x30 0x30 0x30 0x3C 0x1C 0x00 0x00 # t + 0x00 0x00 0x00 0x00 0xC6 0xC6 0xC6 0xC6 0xC6 0xCE 0xFE 0x7A 0x00 0x00 # u + 0x00 0x00 0x00 0x00 0xC6 0xC6 0xEE 0x6C 0x7C 0x38 0x38 0x10 0x00 0x00 # v + 0x00 0x00 0x00 0x00 0xC6 0xC6 0xD6 0xD6 0xD6 0xFE 0xFE 0xEC 0x00 0x00 # w + 0x00 0x00 0x00 0x00 0xC6 0xEE 0x6C 0x38 0x7C 0xEE 0xC6 0xC6 0x00 0x00 # x + 0x00 0x00 0x00 0x00 0xC6 0xC6 0xC6 0xC6 0xFE 0x7E 0x06 0x06 0xFE 0xFC # y + 0x00 0x00 0x00 0x00 0xFE 0xFE 0x0E 0x1C 0x38 0x70 0xFE 0xFE 0x00 0x00 # z + 0x7C 0xFE 0xC6 0xD6 0xD6 0xD6 0xD6 0xD6 0xD6 0xC6 0xFE 0x7C 0x00 0x00 # 0 + 0x18 0x38 0x78 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x7E 0x7E 0x00 0x00 # 1 + 0x7C 0xFE 0xC6 0x06 0x3E 0x7C 0xE0 0xC0 0xC0 0xC0 0xFE 0xFE 0x00 0x00 # 2 + 0x7C 0xFE 0xC6 0x06 0x1E 0x1C 0x06 0xC6 0xC6 0xC6 0xFE 0x7C 0x00 0x00 # 3 + 0x0C 0x1C 0x3C 0x6C 0xFE 0xFE 0x0C 0x0C 0x0C 0x0C 0x0C 0x0C 0x00 0x00 # 4 + 0xFE 0xFE 0xC0 0xC0 0xFC 0xFE 0x06 0x06 0x06 0xC6 0xFE 0x7C 0x00 0x00 # 5 + 0x7C 0xFE 0xC6 0xC0 0xFC 0xFE 0xC6 0xC6 0xC6 0xC6 0xFE 0x7C 0x00 0x00 # 6 + 0xFE 0xFE 0x06 0x0E 0x1C 0x18 0xFE 0xFE 0x30 0x30 0x30 0x30 0x00 0x00 # 7 + 0x7C 0xFE 0xC6 0xC6 0x7C 0xFE 0xC6 0xC6 0xC6 0xC6 0xFE 0x7C 0x00 0x00 # 8 + 0x7C 0xFE 0xC6 0xC6 0xFE 0x7E 0x06 0x06 0xC6 0xC6 0xFE 0x7C 0x00 0x00 # 9 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x18 0x18 0x18 0x00 0x00 # . + 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x00 0x18 0x18 0x18 0x00 0x00 # ! + 0x7C 0xFE 0xC6 0xC6 0xDE 0x1C 0x18 0x18 0x00 0x18 0x18 0x18 0x00 0x00 # ? + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x18 0x18 0x18 0x08 0x10 # , + 0x18 0x18 0x18 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 # ' + 0x00 0x00 0x00 0x00 0x00 0x00 0x3C 0x3C 0x00 0x00 0x00 0x00 0x00 0x00 # - + 0x6C 0x6C 0x6C 0x24 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 # " + +: fill-stash + 0x00 0x00 0x00 0x00 0x00 +: fill-sprite + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + +: string-yes-no + 0xFE 0x1E 0x34 0x18 0x1E 0x2C 0xF9 0xFE 0x50 0x34 0x0D 0x28 0xFF +: mask-yes-no + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + +to-code + +: dialog-fill-screen + plane 3 + clear + plane 1 + i := long fill-stash + save v0 - v4 + i := long fill-sprite + full-screen-blit + i := long fill-stash + load v0 - v4 +; + +: dialog-pause + # debounced key input, to prevent + # missing out on dialog. + vf := OCTO_KEY_E + loop if vf key then again # wait for release, + loop if vf -key then again # wait for press, + loop if vf key then again # wait for release... + wait 2 # ...plus a minimum time delay. + plane 3 + clear + plane 1 +; + +: dialog-draw-answer + v0 := 24 + if v2 == 0 then v0 += 48 + v1 := 50 + i := long mask-yes-no + sprite v0 v1 0 + v0 += 16 + sprite v0 v1 0 +; + +: dialog-yes-no + # returns 0/1 in v2 + print string-yes-no + ve := OCTO_KEY_E + loop if ve key then again # wait for release + wait 2 # ...plus a minimum time delay. + v2 := 1 + loop + dialog-draw-answer + ve := key + dialog-draw-answer + while ve != OCTO_KEY_E + if ve == OCTO_KEY_A then v2 := 1 + if ve == OCTO_KEY_D then v2 := 0 + again + ve := OCTO_KEY_E + loop if ve key then again # wait for release + clear +; + +:macro print-from-table REG TABLE { + i := long TABLE + i += REG + i += REG + load v1 + print-text +} + +:macro fmt-from-table REG TABLE DEST { + i := long TABLE + i += REG + i += REG + load v3 - v4 + i := DEST + save v3 - v4 +} + +########################################### +# +# Prelude +# +########################################### + +to-data + +: cake 0x08 0x22 0x08 0x2A 0x54 0xDD 0x7E 0x81 0xFF 0x7E 0x81 0xFF 0x7E + +: prelude-placing + 32 8 + 80 10 + 98 15 + 22 13 + 80 30 + 90 35 + 30 24 + 18 35 + +: prelude-0 + 0xFE 0x24 0x11 0x44 0x16 0x21 0x1A 0x2D 0xF9 0x1A 0xFE 0x24 0x1B 0x2C 0x29 0x25 + 0x1E 0x27 0x1D 0x22 0x1D 0xFE 0x24 0x25 0x29 0x1A 0x2B 0x2D 0x32 0x3F 0x44 0xFF +: prelude-1 + 0xFE 0x12 0x0F 0x44 0x08 0x27 0x1D 0x1E 0x1E 0x1D 0x3E 0xFE 0x12 0x19 0x07 0x1A + 0x29 0x29 0x32 0xF9 0x1B 0x22 0x2B 0x2D 0x21 0x1D 0x1A 0x32 0x41 0xFE 0x12 0x23 + 0x02 0x25 0x1A 0x22 0x2B 0x1E 0x3F 0x44 0xFF +: prelude-2 + 0xFE 0x08 0x0D 0x44 0x0F 0x1E 0x2B 0x21 0x1A 0x29 0x2C 0xF9 0x30 0x1E 0xF9 0x2C + 0x21 0x28 0x2E 0x25 0x1D 0xFE 0x08 0x17 0x2E 0x2C 0x1E 0xF9 0x28 0x2E 0x2B 0xF9 + 0x1E 0x2C 0x2D 0x1E 0x1E 0x26 0x1E 0x1D 0xFE 0x08 0x21 0x1C 0x28 0x25 0x25 0x1E + 0x1A 0x20 0x2E 0x1E 0x42 0x2C 0xF9 0x27 0x1E 0x30 0xFE 0x08 0x2B 0x2D 0x22 0x2D + 0x25 0x1E 0x40 0x44 0xFF +: prelude-3 + 0xFE 0x03 0x0B 0x44 0x10 0x2E 0x22 0x2D 0x1E 0xF9 0x2B 0x22 0x20 0x21 0x2D 0x3E + 0xFE 0x03 0x15 0x00 0xF9 0x1F 0x22 0x27 0x1E 0xF9 0x1B 0x22 0x2B 0x2D 0x21 0x1D + 0x1A 0x32 0xFE 0x03 0x1F 0x2D 0x28 0xF9 0x32 0x28 0x2E 0x41 0xFE 0x03 0x29 0x08 + 0x27 0x2C 0x29 0x1E 0x1C 0x2D 0x28 0x2B 0xF9 0x01 0x25 0x1E 0x1C 0x21 0x26 0x1A + 0x27 0x3F 0x44 0xFF +: prelude-4 + 0xFE 0x03 0x0B 0x44 0x16 0x1E 0xF9 0x30 0x22 0x25 0x25 0xF9 0x1A 0x25 0x25 0xF9 + 0x26 0x28 0x2C 0x2D 0xFE 0x03 0x15 0x1A 0x2C 0x2C 0x2E 0x2B 0x1E 0x1D 0x25 0x32 + 0xF9 0x1F 0x1E 0x1E 0x25 0xF9 0x2C 0x1A 0x1F 0x1E 0x2B 0xFE 0x03 0x1F 0x30 0x22 + 0x2D 0x21 0xF9 0x32 0x28 0x2E 0xF9 0x28 0x27 0xF9 0x2D 0x21 0x1E 0xF9 0x23 0x28 + 0x1B 0x41 0xFE 0x03 0x29 0x1D 0x1E 0x1A 0x2B 0x3E 0x44 0xFF +: prelude-5 + 0xFE 0x05 0x0C 0x44 0x0D 0x28 0x2D 0xF9 0x2D 0x28 0xF9 0x2C 0x29 0x28 0x22 0x25 + 0xF9 0x2D 0x21 0x1E 0xFE 0x05 0x16 0x26 0x28 0x28 0x1D 0x41 0xF9 0x1B 0x2E 0x2D + 0xF9 0x08 0xF9 0x1C 0x1A 0x27 0x42 0x2D 0xFE 0x05 0x20 0x21 0x1E 0x25 0x29 0xF9 + 0x1B 0x2E 0x2D 0xF9 0x28 0x1B 0x2C 0x1E 0x2B 0x2F 0x1E 0xF9 0x1A 0x27 0xFE 0x05 + 0x2A 0x1A 0x1B 0x2C 0x1E 0x27 0x1C 0x1E 0x3E 0x3E 0x3E 0x44 0xFF +: prelude-6 + 0xFE 0x02 0x08 0x44 0x06 0x28 0x28 0x1D 0xF9 0x29 0x28 0x22 0x27 0x2D 0x3E 0xFE + 0x02 0x12 0x00 0x1F 0x2D 0x1E 0x2B 0xF9 0x1A 0x25 0x25 0xF9 0x2D 0x21 0x1E 0xF9 + 0x1E 0x1F 0x1F 0x28 0x2B 0x2D 0xFE 0x02 0x1C 0x2D 0x28 0xF9 0x2D 0x21 0x2B 0x28 + 0x30 0xF9 0x2D 0x21 0x22 0x2C 0xF9 0x29 0x1A 0x2B 0x2D 0x32 0x41 0xFE 0x02 0x26 + 0x30 0x21 0x1E 0x2B 0x1E 0xF9 0x1C 0x28 0x2E 0x25 0x1D 0xF9 0x28 0x2E 0x2B 0xFE + 0x02 0x30 0x21 0x28 0x2C 0x2D 0xF9 0x1B 0x1E 0x40 0x44 0xFF +: prelude-7 + 0xFE 0x02 0x08 0x44 0x08 0x2D 0x42 0x2C 0xF9 0x1B 0x1E 0x1E 0x27 0xF9 0x2A 0x2E + 0x22 0x2D 0x1E 0xF9 0x1A 0xFE 0x02 0x12 0x30 0x21 0x22 0x25 0x1E 0x41 0xF9 0x22 + 0x27 0xF9 0x1F 0x1A 0x1C 0x2D 0x3E 0xFE 0x02 0x1C 0x0F 0x1E 0x2B 0x21 0x1A 0x29 + 0x2C 0xF9 0x30 0x1E 0xF9 0x2C 0x21 0x28 0x2E 0x25 0x1D 0xF9 0x20 0x28 0xFE 0x02 + 0x26 0x25 0x28 0x28 0x24 0x22 0x27 0x20 0xF9 0x1F 0x28 0x2B 0xF9 0x2D 0x21 0x1E + 0xFE 0x02 0x30 0x28 0x25 0x1D 0xF9 0x1B 0x1E 0x1A 0x27 0x40 0x44 0xFF + +: prelude-dialog-table + pointer prelude-0 + pointer prelude-1 + pointer prelude-2 + pointer prelude-3 + pointer prelude-4 + pointer prelude-5 + pointer prelude-6 + pointer prelude-7 + +to-code + +: prelude + dialog-fill-screen + wait 60 + + current-room := 11 + clear + draw-room + player-face := 1 + i := long room-stash-start + load player-x - player-y + ve := 0 + draw-player + i := long cake + v0 := 60 + v1 := 20 + sprite v0 v1 13 + + v2 := 0 + v3 := 0 + loop + i := long prelude-placing + i += v2 + i += v2 + load v1 + i := long npc-sprites + i += v3 + sprite v0 v1 15 + v3 += 16 + v2 += 1 + if v2 != 8 then + again + dialog-pause + + v2 := 0 + loop + introduce-npc + print-from-table v2 prelude-dialog-table + dialog-pause + v2 += 1 + if v2 != 8 then + again + + dialog-fill-screen + wait 60 + jump intro-sequence + +########################################### +# +# Introduction +# +########################################### + +to-data + +: title-screen + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x69 0x01 0xFB + 0x01 0x9B 0x03 0x1B 0x03 0x3B 0x03 0xFB + 0x01 0xEA 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 + 0xF8 0x00 0xDC 0x00 0xDF 0x00 0xEF 0x00 + 0xEF 0x00 0xED 0x90 0xFD 0xB0 0xFD 0xF8 + 0xFA 0xFC 0xFF 0xEC 0xEF 0xEF 0xEF 0x6F + 0xDB 0xEB 0xFF 0xFA 0xFB 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xDF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFE + 0xFF 0xF8 0xFF 0xF1 0xFF 0x87 0xFF 0x3F + 0xF8 0xFF 0xF7 0xFE 0xEF 0xFF 0xFF 0xFF + 0xDF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0xE0 0x79 0xF0 0xFD + 0xB0 0xCD 0x30 0xF9 0x70 0xE1 0x60 0xFD + 0x70 0x79 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x08 0x00 0x0C 0x00 0x7F 0x3C + 0x7F 0x7E 0x1C 0x66 0x18 0x66 0x1A 0x6C + 0x1E 0x7C 0x0C 0x38 0x00 0x00 0x00 0x00 + 0x60 0x00 0x60 0x00 0xE0 0x00 0xF0 0x00 + 0xF0 0x00 0xF0 0x00 0xF0 0xC0 0xF1 0xD8 + 0xF1 0xFC 0xF3 0xFC 0xD3 0xFC 0xDB 0xBD + 0xFF 0xBC 0xFF 0x9E 0xFF 0xFF 0xFF 0xFB + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFE 0xFF 0xF0 + 0xFF 0x80 0xFE 0x01 0xE0 0x03 0x00 0x07 + 0x01 0xFF 0xFD 0xFF 0xE3 0xFF 0xDF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x13 0xC7 0xB7 0xEF + 0xB6 0x6E 0xB7 0xCC 0xE7 0x0D 0xC7 0xAD + 0x83 0xC9 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x3F 0xFF 0x1F 0xFF + 0x1F 0xFF 0x1F 0xFF 0x1F 0xFF 0x1F 0xFF + 0x1F 0xE0 0x1F 0xE0 0x1F 0xE0 0x1F 0xC0 + 0x3F 0xC0 0x3F 0xC0 0x3F 0xC0 0x3F 0xC0 + 0x7F 0x80 0x7F 0x81 0x7F 0xFF 0x7F 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0x00 0x00 0x00 0x00 0xC0 0x00 0xFC 0x00 + 0xFF 0xC0 0xFC 0x39 0x03 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFD 0xFF 0xFB + 0xFF 0xFF 0xFF 0xFF 0xFF 0xDF 0xFF 0xFF + 0xFF 0xBF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x89 0xE3 0xDB 0xF7 + 0xC3 0xB4 0xDB 0x36 0xDB 0x77 0x9B 0x67 + 0xD2 0x71 0x00 0x03 0x00 0x0F 0x00 0x06 + 0x00 0x00 0x00 0x00 0xF0 0x00 0xFC 0x07 + 0xFE 0x1F 0xFF 0x3F 0xFF 0x26 0xFF 0xA6 + 0x7F 0xBF 0x1F 0x9D 0x0F 0xCF 0x0F 0xCA + 0x0F 0xC0 0x0F 0xDF 0x0F 0xCF 0x1F 0xCF + 0x7F 0xCF 0xFF 0x9F 0xFF 0x9F 0xFF 0x9F + 0xFF 0x1F 0xFE 0x1F 0xFC 0x3F 0xF0 0x3F + 0x00 0x00 0x00 0x00 0x00 0x01 0x00 0x07 + 0x0F 0xF7 0xFB 0xFF 0xF7 0xDF 0xCF 0xBF + 0x3F 0x7F 0xFF 0xFF 0xF9 0xFF 0xF7 0xFF + 0xFF 0xFF 0xDF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x80 0x00 0xC0 0x00 + 0xC0 0x00 0xC0 0x00 0xC0 0x00 0xC0 0x00 + 0x80 0x00 0x80 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x3F 0x80 0xFF + 0xC1 0xFF 0xE3 0xFF 0x67 0xFF 0x67 0xF8 + 0xCF 0xF0 0xCF 0xE0 0x8F 0xFF 0x9F 0xFF + 0x1F 0xFF 0xDF 0xFF 0x9F 0xC0 0xBF 0xC0 + 0xBF 0xC0 0xBF 0xE1 0xBF 0xFF 0x9F 0xFF + 0x1F 0xFF 0x0F 0xFF 0x07 0xFF 0x81 0xFF + 0x0E 0x00 0x3F 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0xE0 0x00 0xFE 0x00 + 0xFE 0x00 0xFF 0x00 0xFF 0x00 0x3F 0x80 + 0x1F 0x83 0x1F 0xDF 0xFF 0xDF 0xFF 0xDF + 0xFF 0xDF 0xFF 0xDF 0x00 0x1F 0x00 0x3F + 0xFF 0xBF 0xFF 0xBF 0xFF 0x7F 0xFF 0x7F + 0xFE 0xFF 0xFD 0xF8 0xFB 0xF0 0xE7 0xF3 + 0x1F 0xC0 0xFF 0xE0 0xFF 0xF3 0xFF 0xC3 + 0xFF 0xE7 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFC 0xFF 0xF8 + 0x00 0x00 0x00 0x0C 0x00 0x0C 0x00 0x1E + 0x00 0x1E 0x00 0x3F 0x00 0x3F 0x00 0x3F + 0x00 0x7F 0x00 0x7F 0x00 0x7F 0x00 0x0F + 0x00 0x0E 0x00 0x0E 0x00 0x0F 0x00 0x0F + 0x00 0x0F 0x00 0x0F 0x00 0x0F 0x03 0xC0 + 0x07 0xFF 0x1F 0xFF 0x7F 0xFE 0xFF 0xF0 + 0xFF 0x87 0xFE 0x1F 0xFD 0xFF 0xF0 0xFF + 0xF3 0xFF 0xF0 0x7F 0xF8 0x7F 0xFC 0x03 + 0xFF 0x00 0xFF 0xE0 0xFF 0xF8 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0x43 0x43 0x81 0x01 + 0x99 0x91 0x99 0x13 0x91 0x27 0x81 0x21 + 0xC3 0x21 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xF8 0xFF 0xC4 0xFF 0x00 0xF2 0x00 + 0xD0 0x00 0x00 0x00 0x00 0x04 0x00 0x01 + 0x00 0x00 0x0F 0xFF 0x3F 0xFF 0x3F 0xFF + 0x0F 0xBD 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xF7 0xBF 0xF7 0xBF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x03 0xE0 + 0xFF 0x3F 0xF3 0xFF 0x0F 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0x7F 0xFF 0x0F 0xFF 0x01 0xFF 0x00 0x7F + 0xC0 0x1F 0xE0 0x07 0xF8 0x01 0xFD 0x00 + 0xFE 0x01 0xFF 0x00 0xFF 0x80 0xFF 0xA0 + 0xFF 0xC0 0xFF 0xC0 0xFF 0xF0 0xFF 0xE0 + 0xFF 0xF0 0xFF 0xE0 0xFF 0xE0 0xFF 0xE0 + 0xFF 0xC0 0xFF 0x80 0xF8 0x01 0xA0 0x00 + 0x00 0x00 0x00 0x00 0x00 0x02 0x00 0x40 + 0x01 0x13 0x10 0x3F 0x0D 0xFF 0x3F 0xFF + +# a little 3x5 semifont +: tiny-dash 0x00 0x00 0xE0 0x00 0x00 +: tiny-space 0x00 0x00 0x00 0x00 0x00 +: tiny-P 0xC0 0xA0 0xC0 0x80 0x80 +: tiny-R 0xC0 0xA0 0xC0 0xA0 0xA0 +: tiny-E 0xE0 0x80 0xC0 0x80 0xE0 +: tiny-S 0x60 0x80 0x40 0x20 0xC0 +: tiny-A 0x40 0xA0 0xE0 0xA0 0xA0 +: tiny-C 0x40 0xA0 0x80 0xA0 0x40 +: tiny-table + pointer tiny-dash + pointer tiny-P + pointer tiny-R + pointer tiny-E + pointer tiny-S + pointer tiny-S + pointer tiny-space + pointer tiny-S + pointer tiny-P + pointer tiny-A + pointer tiny-C + pointer tiny-E + pointer tiny-dash +: tiny-table-end +: wiggle-table 0 0 1 1 2 1 1 0 0 -1 -1 -2 -1 -1 0 0 + +: lightning-right + 0x00 0x04 0x00 0x08 0x00 0x70 0x00 0x88 0x01 0x08 0x1E 0x00 0x28 0x00 0x08 0x00 + 0x04 0x00 0x03 0x00 0x01 0x00 0x03 0x00 0x24 0x80 0x58 0x80 0x81 0x00 0x80 0x00 +: lightning-left + 0x78 0x00 0x1C 0x00 0x0C 0x00 0x0C 0x00 0x0E 0x00 0x0B 0x00 0x18 0xC0 0x10 0x60 + 0x20 0x20 0x20 0x20 0x20 0x1C 0x60 0x12 0x90 0x09 0x88 0x00 0x04 0x00 0x04 0x00 +: rain # (padded to 8x16) + 0x80 0x00 0x00 0x80 0x80 0x00 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x00 + 0x80 0x00 0x80 0x80 0x80 0x80 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x00 0x00 0x00 0x00 + 0x80 0x80 0x80 0x80 0x00 0x00 0x00 0x00 0x00 0x08 0x08 0x08 0x08 0x00 0x00 0x00 +: dark-and-stormy # "It is a dark and stormy night." + 0xFE 0x0B 0x15 0x08 0x2D 0xF9 0x22 0x2C 0xF9 0x1A 0xF9 0x1D 0x1A 0x2B 0x24 0xFE + 0x0B 0x1F 0x1A 0x27 0x1D 0xF9 0x2C 0x2D 0x28 0x2B 0x26 0x32 0xF9 0x27 0x22 0x20 + 0x21 0x2D 0x3E 0xFF +: a-murder-has-been-committed + 0xFE 0x0B 0x15 0xFD 0x00 0xF9 0x26 0x2E 0x2B 0x1D 0x1E 0x2B 0xF9 0x21 0x1A 0x2C + 0xF9 0x1B 0x1E 0x1E 0x27 0xF9 0xFE 0x0B 0x1F 0x1C 0x28 0x26 0x26 0x22 0x2D 0x2D + 0x1E 0x1D 0x3E 0x3E 0x3E 0xFF + +: a-shocking-end + 0xFE 0x00 0x12 0x08 0x2D 0xF9 0x2C 0x1E 0x1E 0x26 0x2C 0xF9 0x2D 0x21 0x1E 0xF9 + 0x27 0x22 0x20 0x21 0x2D 0x42 0x2C 0xFE 0x00 0x1C 0x1F 0x1E 0x2C 0x2D 0x22 0x2F + 0x22 0x2D 0x22 0x1E 0x2C 0xF9 0x21 0x1A 0x2F 0x1E 0xF9 0x1C 0x28 0x26 0x1E 0xFE + 0x00 0x26 0x2D 0x28 0xF9 0x1A 0xF9 0x2C 0x21 0x28 0x1C 0x24 0x22 0x27 0x20 0xF9 + 0x1E 0x27 0x1D 0x3E 0xFF +: a-pool-of-blood + 0xFE 0x02 0x0D 0x0E 0x2E 0x2B 0xF9 0x25 0x1A 0x2D 0x1E 0xF9 0x21 0x28 0x2C 0x2D + 0x42 0x2C 0xF9 0x1B 0x28 0x1D 0x32 0xFE 0x02 0x17 0x30 0x1A 0x2C 0xF9 0x23 0x2E + 0x2C 0x2D 0xF9 0x1D 0x22 0x2C 0x1C 0x28 0x2F 0x1E 0x2B 0x1E 0x1D 0xFE 0x02 0x21 + 0x1F 0x1A 0x1C 0x1E 0x43 0x1D 0x28 0x30 0x27 0xF9 0x22 0x27 0xF9 0x1A 0xF9 0x29 + 0x28 0x28 0x25 0xFE 0x02 0x2B 0x28 0x1F 0xF9 0x21 0x22 0x2C 0xF9 0x28 0x30 0x27 + 0xF9 0x1B 0x25 0x28 0x28 0x1D 0x3E 0x3E 0x3E 0xFF +: get-to-the-bottom-of-it + 0xFE 0x00 0x0C 0x08 0xF9 0x26 0x2E 0x2C 0x2D 0xF9 0x20 0x1E 0x2D 0xF9 0x2D 0x28 + 0xF9 0x2D 0x21 0x1E 0xFE 0x00 0x16 0x1B 0x28 0x2D 0x2D 0x28 0x26 0xF9 0x28 0x1F + 0xF9 0x2D 0x21 0x22 0x2C 0xF9 0x1A 0x2D 0xFE 0x00 0x20 0x28 0x27 0x1C 0x1E 0x43 + 0xF9 0x1B 0x1E 0x1F 0x28 0x2B 0x1E 0xF9 0x28 0x2E 0x2B 0xFE 0x00 0x2A 0x24 0x22 + 0x25 0x25 0x1E 0x2B 0xF9 0x2C 0x2D 0x2B 0x22 0x24 0x1E 0x2C 0xF9 0x1A 0x20 0x1A + 0x22 0x27 0x3F 0xFF + +: intro-1-quip-0 # "Good grief, he's dead!" + 0xFE 0x1A 0x14 0x44 0x06 0x28 0x28 0x1D 0xF9 0x20 0x2B 0x22 0x1E 0x1F 0x41 0xFE + 0x1A 0x1E 0x21 0x1E 0x42 0x2C 0xF9 0x1D 0x1E 0x1A 0x1D 0x3F 0x44 0xFF +: intro-1-quip-1 # "Hmm. No sign of a pulse." + 0xFE 0x03 0x14 0x44 0x07 0x26 0x26 0x3E 0xFE 0x03 0x1E 0x0D 0x28 0xF9 0x2C 0x22 + 0x20 0x27 0xF9 0x28 0x1F 0xF9 0x1A 0xF9 0x29 0x2E 0x25 0x2C 0x1E 0x3E 0x44 0xFF +: intro-1-quip-2 # "I can't believe it! Murdered in his own home?" + 0xFE 0x03 0x11 0x44 0x08 0xF9 0x1C 0x1A 0x27 0x42 0x2D 0xF9 0x1B 0x1E 0x25 0x22 + 0x1E 0x2F 0x1E 0xF9 0x22 0x2D 0x3F 0xFE 0x03 0x1B 0x0C 0x2E 0x2B 0x1D 0x1E 0x2B + 0x1E 0x1D 0xF9 0x22 0x27 0xF9 0x21 0x22 0x2C 0xFE 0x03 0x25 0x28 0x30 0x27 0xF9 + 0x21 0x28 0x26 0x1E 0x40 0x44 0xFF +: intro-1-quip-3 # "He's Dead? When could this have happened?" + 0xFE 0x10 0x10 0x44 0x07 0x1E 0x42 0x2C 0xF9 0x03 0x1E 0x1A 0x1D 0x40 0xFE 0x10 + 0x1A 0x16 0x21 0x1E 0x27 0xF9 0x1C 0x28 0x2E 0x25 0x1D 0xF9 0x2D 0x21 0x22 0x2C + 0xFE 0x10 0x24 0x21 0x1A 0x2F 0x1E 0xF9 0x21 0x1A 0x29 0x29 0x1E 0x27 0x1E 0x1D + 0x40 0x44 0xFF +: intro-1-quip-4 # "Doesn't take a coroner to classify this one, I'm afraid." + 0xFE 0x02 0x11 0x44 0x03 0x28 0x1E 0x2C 0x27 0x42 0x2D 0xF9 0x2D 0x1A 0x24 0x1E + 0xF9 0x1A 0xFE 0x02 0x1B 0x1C 0x28 0x2B 0x28 0x27 0x1E 0x2B 0xF9 0x2D 0x28 0xF9 + 0x1C 0x1A 0x25 0x25 0xF9 0x2D 0x21 0x22 0x2C 0xFE 0x02 0x25 0x28 0x27 0x1E 0x41 + 0xF9 0x08 0x42 0x26 0xF9 0x1A 0x1F 0x2B 0x1A 0x22 0x1D 0x3E 0x44 0xFF +: intro-1-quip-5 # "Stone dead. What a mess!" + 0xFE 0x1A 0x18 0x44 0x12 0x2D 0x28 0x27 0x1E 0xF9 0x1D 0x1E 0x1A 0x1D 0x3E 0xFE + 0x1A 0x22 0x16 0x21 0x1A 0x2D 0xF9 0x1A 0xF9 0x26 0x1E 0x2C 0x2C 0x3F 0x44 0xFF +: intro-1-quip-6 # "Oh dear. The carpet is simply ruined." + 0xFE 0x14 0x11 0x44 0x0E 0x21 0xF9 0x1D 0x1E 0x1A 0x2B 0x3E 0xFE 0x14 0x1B 0x13 + 0x21 0x1E 0xF9 0x1C 0x1A 0x2B 0x29 0x1E 0x2D 0xF9 0x22 0x2C 0xFE 0x14 0x25 0x2C + 0x22 0x26 0x29 0x25 0x32 0xF9 0x2B 0x2E 0x22 0x27 0x1E 0x1D 0x3E 0x44 0xFF +: intro-1-quip-7 # "I can't imagine he'll pull through..." + 0xFE 0x02 0x16 0x44 0x02 0x1A 0x27 0x42 0x2D 0xF9 0x22 0x26 0x1A 0x20 0x22 0x27 + 0x1E 0xF9 0x21 0x1E 0x42 0x25 0x25 0xFE 0x02 0x20 0x29 0x2E 0x25 0x25 0xF9 0x2D + 0x21 0x2B 0x28 0x2E 0x20 0x21 0x3E 0x3E 0x3E 0x44 0xFF + +: intro-2-quip-0 # "Who could have done such a thing?" + 0xFE 0x02 0x16 0x44 0x16 0x21 0x28 0xF9 0x1C 0x28 0x2E 0x25 0x1D 0xF9 0x21 0x1A + 0x2F 0x1E 0xF9 0x1D 0x28 0x27 0x1E 0xFE 0x02 0x20 0x2C 0x2E 0x1C 0x21 0xF9 0x1A + 0xF9 0x2D 0x21 0x22 0x27 0x20 0x40 0x44 0xFF +: intro-2-quip-1 # "I think I'm going to be sick!" + 0xFE 0x07 0x16 0x44 0x08 0xF9 0x2D 0x21 0x22 0x27 0x24 0xF9 0x08 0x42 0x26 0xF9 + 0x20 0x28 0x22 0x27 0x20 0xFE 0x07 0x20 0x2D 0x28 0xF9 0x1B 0x1E 0xF9 0x2C 0x22 + 0x1C 0x24 0x3F 0x44 0xFF +: intro-2-quip-2 # "I simply can't bear the signt of blood..." + 0xFE 0x0F 0x12 0x44 0x08 0xF9 0x2C 0x22 0x26 0x29 0x25 0x32 0xF9 0x1C 0x1A 0x27 + 0x42 0x2D 0xFE 0x0F 0x1C 0x1B 0x1E 0x1A 0x2B 0xF9 0x2D 0x21 0x1E 0xF9 0x2C 0x22 + 0x20 0x21 0x2D 0xFE 0x0F 0x26 0x28 0x1F 0xF9 0x1B 0x25 0x28 0x28 0x1D 0x3E 0x3E + 0x3E 0x44 0xFF +: intro-2-quip-3 # "Farewell, old chum. Such a way to go!" + 0xFE 0x02 0x16 0x44 0x05 0x1A 0x2B 0x1E 0x30 0x1E 0x25 0x25 0x41 0xF9 0x28 0x25 + 0x1D 0xF9 0x1C 0x21 0x2E 0x26 0x3E 0xFE 0x02 0x20 0x12 0x2E 0x1C 0x21 0xF9 0x1A + 0xF9 0x30 0x1A 0x32 0xF9 0x2D 0x28 0xF9 0x20 0x28 0x3F 0x44 0xFF +: intro-2-quip-4 # "How simply dreadful!" + 0xFE 0x1A 0x16 0x44 0x07 0x28 0x30 0xF9 0x2C 0x22 0x26 0x29 0x25 0x32 0xFE 0x1A + 0x20 0x1D 0x2B 0x1E 0x1A 0x1D 0x1F 0x2E 0x25 0x3F 0x44 0xFF +: intro-2-quip-5 # "I think I'm going to need a few stiff drinks..." + 0xFE 0x05 0x11 0x44 0x08 0xF9 0x2D 0x21 0x22 0x27 0x24 0xF9 0x08 0x42 0x26 0xF9 + 0x20 0x28 0x22 0x27 0x20 0xFE 0x05 0x1B 0x2D 0x28 0xF9 0x27 0x1E 0x1E 0x1D 0xF9 + 0x1A 0xF9 0x1F 0x1E 0x30 0xF9 0x2C 0x2D 0x22 0x1F 0x1F 0xFE 0x05 0x25 0x1D 0x2B + 0x22 0x27 0x24 0x2C 0x3E 0x3E 0x3E 0x44 0xFF +: intro-2-quip-6 # "There's... so much blood..." + 0xFE 0x0C 0x16 0x44 0x13 0x21 0x1E 0x2B 0x1E 0x42 0x2C 0x3E 0x3E 0x3E 0xFE 0x0C + 0x20 0x2C 0x28 0xF9 0x26 0x2E 0x1C 0x21 0xF9 0x1B 0x25 0x28 0x28 0x1D 0x3E 0x3E + 0x3E 0x44 0xFF +: intro-2-quip-7 # "The old man always did know how to make an exit, I suppose." + 0xFE 0x02 0x11 0x44 0x13 0x21 0x1E 0xF9 0x28 0x25 0x1D 0xF9 0x26 0x1A 0x27 0xF9 + 0x1A 0x25 0x30 0x1A 0x32 0x2C 0xFE 0x02 0x1B 0x1D 0x22 0x1D 0xF9 0x24 0x27 0x28 + 0x30 0xF9 0x21 0x28 0x30 0xF9 0x2D 0x28 0xF9 0x26 0x1A 0x24 0x1E 0xFE 0x02 0x25 + 0x1A 0x27 0xF9 0x1E 0x31 0x22 0x2D 0x41 0xF9 0x08 0xF9 0x2C 0x2E 0x29 0x29 0x28 + 0x2C 0x1E 0x3E 0x44 0xFF + +: intro-table-1 + pointer intro-1-quip-0 + pointer intro-1-quip-1 + pointer intro-1-quip-2 + pointer intro-1-quip-3 + pointer intro-1-quip-4 + pointer intro-1-quip-5 + pointer intro-1-quip-6 + pointer intro-1-quip-7 +: intro-table-2 + pointer intro-2-quip-0 + pointer intro-2-quip-1 + pointer intro-2-quip-2 + pointer intro-2-quip-3 + pointer intro-2-quip-4 + pointer intro-2-quip-5 + pointer intro-2-quip-6 + pointer intro-2-quip-7 +: intro-sequence-registers + 0 # ve: animation index + 0 # vd: space key latch + 0 # vc: 1 key latch + 0xF # vb: constant index mask + +to-code + +: draw-lightning + clear + vf := random 0b1 + v1 := 0 + if vf == 0 begin + i := long lightning-right + v0 := 75 + else + i := long lightning-left + v0 := 25 + end + v2 := 10 + loop + sprite v0 v1 0 + sync + vf := 5 + buzzer := vf + v2 += -1 + if v2 != 0 then + again + clear +; + +: draw-rain + loop + dialog-fill-screen + v2 := 20 # rain density + loop + i := long rain + vf := random 0b110000 # 0,16,32,48 + i += vf + v0 := random 0xFF + v1 := random 0xFF + sprite v0 v1 15 + + v2 += -1 + if v2 != 0 then + again + sync + + v3 += -1 + if v3 != 0 then + again + clear +; + +: draw-wiggle-prompt + # -PRESS SPACE- + :calc prompt-length { 0xFF & ( tiny-table-end - tiny-table ) / 2 } + :calc prompt-offset-x { 0xFF & 64 - ( prompt-length * 4 ) / 2 } + v0 := prompt-offset-x + v1 := 58 + v2 := 0 + va := ve + loop + i := long tiny-table + i += v2 + i += v2 + load v3 - v4 + i := long prompt-pointer + save v3 - v4 + + i := long wiggle-table + i += va + load v1 - v1 + v1 += 57 + + indirect prompt-pointer + sprite v0 v1 5 + + v0 += 4 + v2 += 1 + va += 1 + va &= vb + if v2 != prompt-length then + again +; + +:macro latch-key KEY LATCH { + vf := KEY + if LATCH == 0 begin + if vf key then LATCH := 1 + else + while vf key + end +} + +: test-fight + fencing-minigame + jump intro-sequence + +: intro-sequence + clear + i := long title-screen + full-screen-blit + + i := long intro-sequence-registers + load ve - vb + draw-wiggle-prompt + loop + draw-wiggle-prompt + ve += 1 + ve &= vb + draw-wiggle-prompt + latch-key OCTO_KEY_E vd + latch-key OCTO_KEY_1 vc + vf := OCTO_KEY_2 + if vf key then jump test-fight + wait 2 + again + + plane 3 + clear + plane 1 + if vc == 1 then jump prelude + + v3 := 30 # rain duration + draw-rain + dialog-fill-screen + print dark-and-stormy + plot-a-murder # do this here to hide the delay + wait 120 + + draw-lightning + v3 := 10 + draw-rain + draw-lightning + v3 := 10 + draw-rain + draw-lightning + v3 := 40 + draw-rain + + dialog-fill-screen + print a-murder-has-been-committed + wait 120 + dialog-fill-screen + wait 60 + + clear + print a-shocking-end + dialog-pause + print a-pool-of-blood + dialog-pause + + i := long npc-quip-1 + load v2 - v3 + introduce-npc + print-from-table v3 intro-table-1 + dialog-pause + + i := long npc-quip-2 + load v2 - v3 + introduce-npc + print-from-table v3 intro-table-1 + dialog-pause + + print get-to-the-bottom-of-it + dialog-pause +; + +########################################### +# +# Inventory Items +# +########################################### + +to-data + +: no-time-for-that + 0xFE 0x0B 0x12 0x0D 0x28 0xF9 0x2D 0x22 0x26 0x1E 0xF9 0x1F 0x28 0x2B 0xF9 0x2D + 0x21 0x1A 0x2D 0x43 0xFE 0x0B 0x1C 0x2D 0x21 0x1E 0x2B 0x1E 0x42 0x2C 0xF9 0x1A + 0xF9 0x26 0x2E 0x2B 0x1D 0x1E 0x2B 0xFE 0x0B 0x26 0x2D 0x28 0xF9 0x1B 0x1E 0xF9 + 0x2C 0x28 0x25 0x2F 0x1E 0x1D 0x3F 0xFF +: upon-closer-inspection + 0xFE 0x0F 0x12 0x18 0x28 0x2E 0xF9 0x1E 0x31 0x1A 0x26 0x22 0x27 0x1E 0xF9 0x22 + 0x2D 0xFE 0x0F 0x1C 0x1C 0x1A 0x2B 0x1E 0x1F 0x2E 0x25 0x25 0x32 0xF9 0x30 0x22 + 0x2D 0x21 0xFE 0x0F 0x26 0x2D 0x21 0x1E 0xF9 0x2C 0x29 0x32 0x20 0x25 0x1A 0x2C + 0x2C 0x3E 0x3E 0x3E 0xFF +: nothing-unusual + 0xFE 0x0B 0x16 0x18 0x28 0x2E 0xF9 0x1F 0x22 0x27 0x1D 0xF9 0x27 0x28 0x2D 0x21 + 0x22 0x27 0x20 0xFE 0x0B 0x20 0x2E 0x27 0x2E 0x2C 0x2E 0x1A 0x25 0xF9 0x1A 0x1B + 0x28 0x2E 0x2D 0xF9 0x22 0x2D 0x3E 0xFF +: traces-of-blood + 0xFE 0x0C 0x16 0xFD 0x13 0x21 0x1E 0x2B 0x1E 0xF9 0x1A 0x2B 0x1E 0xF9 0x2D 0x2B + 0x1A 0x1C 0x1E 0x2C 0xF9 0xFE 0x10 0x20 0x28 0x1F 0xF9 0x1B 0x25 0x28 0x28 0x1D + 0xF9 0x28 0x27 0xF9 0x22 0x2D 0x3F 0xFF +: take-murder-weapon + 0xFE 0x0E 0x12 0x13 0x1A 0x24 0x1E 0xF9 0x2D 0x21 0x1E 0xF9 0x26 0x2E 0x2B 0x1D + 0x1E 0x2B 0xFE 0x0E 0x1C 0x30 0x1E 0x1A 0x29 0x28 0x27 0xF9 0x30 0x22 0x2D 0x21 + 0xF9 0x32 0x28 0x2E 0x40 0xFF + +: item-lead-pipe # "Seems a bit dangerous." + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xFE 0xE1 0x7D 0xDD 0x83 0x22 0xFE 0x19 0x86 + 0x0C 0x06 0x0E 0x0A 0x07 0x56 0x03 0xFC 0x01 0xF8 0x00 0x00 0x00 0x00 0x00 0x00 +: item-bullet # "An ordinary household bullet." + 0x01 0x80 0x03 0x40 0x03 0x40 0x07 0xA0 0x07 0xA0 0x07 0xE0 0x0B 0xD0 0x08 0x30 + 0x0A 0xF0 0x0A 0xF0 0x0A 0xF0 0x0A 0xF0 0x1A 0xF8 0x17 0xE8 0x08 0x10 0x07 0xE0 +: item-pewter-vase # "Tacky, but quite heavy." + 0x01 0x80 0x1E 0x78 0x21 0x84 0x1C 0x38 0x1F 0xF8 0x37 0xEC 0x24 0x24 0x44 0x22 + 0x49 0x92 0x4A 0x92 0x49 0x12 0x6C 0xB6 0x6C 0x36 0x36 0x6C 0x1F 0xF8 0x07 0xE0 +: item-jar-of-caviar # "Fish eggs, Fish eggs. Eat them up, yum." + 0x00 0x00 0x7F 0xFE 0x5F 0xFA 0x40 0x02 0x40 0x02 0x3F 0xFC 0x5C 0x9A 0x57 0x62 + 0x5B 0xAA 0x5C 0xDA 0x5B 0x3A 0x51 0x2A 0x6F 0xF6 0x30 0x0C 0x1F 0xF8 0x00 0x00 +: item-jade-skull # "Supposedly stolen from a famous rapper." + 0x07 0xF0 0x18 0x0C 0x20 0x02 0x20 0x41 0x6F 0x21 0x67 0x81 0x47 0x83 0x62 0x3B + 0xF0 0x73 0xB3 0xE6 0x81 0xFE 0x55 0xBC 0x2B 0x78 0x57 0xC0 0x7F 0xC0 0x3F 0x80 +: item-brandy-snifter # "I'm not in the mood for a drink." + 0x07 0xE0 0x0B 0xD0 0x08 0x10 0x10 0x08 0x10 0x08 0x24 0x24 0x30 0x0C 0x2A 0x54 + 0x3C 0x3C 0x1B 0xD8 0x0E 0x70 0x03 0xC0 0x01 0x80 0x07 0xE0 0x0F 0xF0 0x03 0xC0 +: item-glass-orb # "It catches the light from every angle..." + 0x03 0xC0 0x0C 0x30 0x11 0x08 0x2A 0x64 0x5A 0x6A 0x59 0x02 0xB4 0xF1 0xA4 0x09 + 0xBA 0x65 0xB3 0xF5 0x5F 0xB2 0x56 0xFA 0x2F 0xF4 0x13 0xC8 0x0C 0x30 0x03 0xC0 +: item-fire-poker # "I prefer Texas Hold-em." + 0x00 0x03 0x00 0x05 0x00 0x0A 0x00 0x16 0x00 0x2C 0x00 0x58 0x00 0xB0 0x01 0xE0 + 0x03 0xC0 0x77 0x00 0xFC 0x00 0xB8 0x00 0x30 0x00 0x60 0x00 0xC0 0x00 0x80 0x00 +: item-spyglass # "Ah, my spyglass! I can examine things more closely now." + 0x0F 0x80 0x10 0x40 0x2F 0xA0 0x50 0x50 0xA3 0x28 0xE3 0x28 0xA0 0xA8 0xE8 0x28 + 0x70 0x70 0x3F 0xD0 0x1F 0xF8 0x0F 0xB4 0x00 0x1A 0x00 0x0F 0x00 0x07 0x00 0x02 + +: item-title-pipe 0xFE 0x1C 0x2D 0xFC 0x0B 0x1E 0x1A 0x1D 0xF9 0x0F 0x22 0x29 0x1E 0xFF +: item-title-bullet 0xFE 0x2A 0x2D 0xFC 0x01 0x2E 0x25 0x25 0x1E 0x2D 0xFF +: item-title-vase 0xFE 0x15 0x2D 0xFC 0x0F 0x1E 0x30 0x2D 0x1E 0x2B 0xF9 0x15 0x1A 0x2C 0x1E 0xFF +: item-title-caviar 0xFE 0x0D 0x2D 0xFC 0x09 0x1A 0x2B 0xF9 0x28 0x1F 0xF9 0x02 0x1A 0x2F 0x22 0x1A 0x2B 0xFF +: item-title-skull 0xFE 0x1A 0x2D 0xFC 0x09 0x1A 0x1D 0x1E 0xF9 0x12 0x24 0x2E 0x25 0x25 0xFF +: item-title-snifter 0xFE 0x09 0x2D 0xFC 0x01 0x2B 0x1A 0x27 0x1D 0x32 0xF9 0x12 0x27 0x22 0x1F 0x2D 0x1E 0x2B 0xFF +: item-title-orb 0xFE 0x1D 0x2D 0xFC 0x06 0x25 0x1A 0x2C 0x2C 0xF9 0x0E 0x2B 0x1B 0xFF +: item-title-poker 0xFE 0x1A 0x2D 0xFC 0x05 0x22 0x2B 0x1E 0xF9 0x0F 0x28 0x24 0x1E 0x2B 0xFF +: item-title-spyglass 0xFE 0x21 0x2D 0xFC 0x12 0x29 0x32 0x20 0x25 0x1A 0x2C 0x2C 0xFF + +: item-desc-pipe 0xFE 0x18 0x12 0x12 0x1E 0x1E 0x26 0x2C 0xF9 0x1A 0xF9 0x1B 0x22 0x2D 0xFE + 0x18 0x1C 0x1D 0x1A 0x27 0x20 0x1E 0x2B 0x28 0x2E 0x2C 0xF9 0x2D 0x28 0xF9 + 0xFE 0x18 0x26 0x2C 0x26 0x28 0x24 0x1E 0x3E 0x3E 0x3E 0xFF +: item-desc-bullet 0xFE 0x0A 0x16 0x00 0x27 0xF9 0x28 0x2B 0x1D 0x22 0x27 0x1A 0x2B 0x32 0xFE + 0x0A 0x20 0x21 0x28 0x2E 0x2C 0x1E 0x21 0x28 0x25 0x1D 0xF9 0x1B 0x2E 0x25 + 0x25 0x1E 0x2D 0x3E 0xFF +: item-desc-vase 0xFE 0x10 0x14 0x13 0x1A 0x1C 0x24 0x32 0x41 0xF9 0x1B 0x2E 0x2D 0xF9 0x1A + 0x25 0x2C 0x28 0xFE 0x10 0x1E 0x2A 0x2E 0x22 0x2D 0x1E 0xF9 0x21 0x1E 0x1A + 0x2F 0x32 0x3E 0x3E 0x3E 0xFF +: item-desc-caviar 0xFE 0x0B 0x12 0x05 0x22 0x2C 0x21 0xF9 0x1E 0x20 0x20 0x2C 0x41 0xF9 0xFE + 0x0B 0x1C 0x05 0x22 0x2C 0x21 0xF9 0x1E 0x20 0x20 0x2C 0x41 0xF9 0xFE 0x0B + 0x26 0x04 0x1A 0x2D 0xF9 0x2D 0x21 0x1E 0x26 0xF9 0x2E 0x29 0x43 0xF9 0x32 + 0x2E 0x26 0x3E 0xFF +: item-desc-skull 0xFE 0x00 0x12 0x12 0x2E 0x29 0x29 0x28 0x2C 0x1E 0x1D 0x25 0x32 0xF9 0x2C + 0x2D 0x28 0x25 0x1E 0x27 0xFE 0x00 0x1C 0x1F 0x2B 0x28 0x26 0xF9 0x1A 0xF9 + 0x1F 0x1A 0x26 0x28 0x2E 0x2C 0xFE 0x00 0x26 0x2B 0x1A 0x29 0x29 0x1E 0x2B + 0xF9 0x1A 0x27 0x1D 0xF9 0x26 0x1E 0x2B 0x1C 0x1E 0x27 0x1A 0x2B 0x32 0x3E + 0xFF +: item-desc-snifter 0xFE 0x0A 0x10 0x08 0x42 0x2F 0x1E 0xF9 0x21 0x1A 0x1D 0xF9 0x2A 0x2E 0x22 + 0x2D 0x1E 0xFE 0x0A 0x1A 0x1E 0x27 0x28 0x2E 0x20 0x21 0xF9 0x2D 0x28 0xF9 + 0x1D 0x2B 0x22 0x27 0x24 0xFE 0x0A 0x24 0x1A 0x25 0x2B 0x1E 0x1A 0x1D 0x32 + 0x41 0xF9 0x08 0xF9 0x30 0x1A 0x20 0x1E 0x2B 0x3E 0xFF +: item-desc-orb 0xFE 0x01 0x16 0x08 0x2D 0xF9 0x1C 0x1A 0x2D 0x1C 0x21 0x1E 0x2C 0xF9 0x2D + 0x21 0x1E 0xF9 0x25 0x22 0x20 0x21 0x2D 0xFE 0x01 0x20 0x1F 0x2B 0x28 0x26 + 0xF9 0x1E 0x2F 0x1E 0x2B 0x32 0xF9 0x1A 0x27 0x20 0x25 0x1E 0x3E 0x3E 0x3E + 0xFF +: item-desc-poker 0xFE 0x06 0x16 0x08 0xF9 0x1F 0x1A 0x2B 0xF9 0x29 0x2B 0x1E 0x1F 0x1E 0x2B + 0xF9 0x13 0x1E 0x31 0x1A 0x2C 0xF9 0xFE 0x06 0x20 0x21 0x28 0x25 0x1D 0x43 + 0x1E 0x26 0x41 0xF9 0x00 0x1C 0x1E 0x2C 0xF9 0x30 0x22 0x25 0x1D 0x3E 0xFF +: item-desc-spyglass 0xFE 0x03 0x12 0x00 0x21 0x1A 0x41 0xF9 0x1A 0xF9 0x2C 0x29 0x32 0x20 0x25 + 0x1A 0x2C 0x2C 0x3F 0xFE 0x03 0x1C 0x08 0xF9 0x1C 0x1A 0x27 0xF9 0x1E 0x31 + 0x1A 0x26 0x22 0x27 0x1E 0xF9 0x2D 0x21 0x22 0x27 0x20 0x2C 0xFE 0x03 0x26 + 0x26 0x28 0x2B 0x1E 0xF9 0x1C 0x25 0x28 0x2C 0x1E 0x25 0x32 0xF9 0x27 0x28 + 0x30 0x3E 0xFF + +: item-icon-table + pointer item-lead-pipe + pointer item-bullet + pointer item-pewter-vase + pointer item-jar-of-caviar + pointer item-jade-skull + pointer item-brandy-snifter + pointer item-glass-orb + pointer item-fire-poker + pointer item-spyglass + +: item-title-table + pointer item-title-pipe + pointer item-title-bullet + pointer item-title-vase + pointer item-title-caviar + pointer item-title-skull + pointer item-title-snifter + pointer item-title-orb + pointer item-title-poker + pointer item-title-spyglass + +: item-desc-table + pointer item-desc-pipe + pointer item-desc-bullet + pointer item-desc-vase + pointer item-desc-caviar + pointer item-desc-skull + pointer item-desc-snifter + pointer item-desc-orb + pointer item-desc-poker + pointer item-desc-spyglass + +to-code + +: take-item + i := long item-positions + i += current-room + v0 := -1 + save v0 +; + +: portrait + i += v2 + i += v2 + load v1 + i := icon-indirection + save v1 + indirect icon-indirection + v0 := 56 + v1 := 20 + sprite v0 v1 0 +; + +: describe-item + # (pass the item index in v2...) + thicken-plot SUSPICION_EXAMINE_ITEM + clear + + if has-weapon == 1 begin + print no-time-for-that + jump dialog-pause + end + + i := long item-icon-table + portrait + + print-from-table v2 item-title-table + dialog-pause + + print-from-table v2 item-desc-table + dialog-pause + + if v2 == 8 begin + thicken-plot SUSPICION_TAKE_SPYGLASS + has-spyglass := 1 + jump take-item + end + + if has-spyglass != 1 then return + + print upon-closer-inspection + dialog-pause + + i := long murder-weapon + load v0 + if v0 == v2 begin + print traces-of-blood + dialog-pause + print take-murder-weapon + dialog-yes-no + if v2 == 0 then return + thicken-plot SUSPICION_TAKE_WEAPON + has-weapon := 1 + jump take-item + end + + print nothing-unusual + dialog-pause +; + +########################################### +# +# The Body +# +########################################### + +to-data + +: body-sprite # 16x16 + 0x70 0x00 0x89 0xF0 0x86 0x0C 0x40 0x62 0x30 0xDC 0x20 0x20 0x40 0x10 0x48 0x08 + 0x54 0x64 0x54 0x52 0x52 0x29 0x51 0x29 0x20 0x95 0x00 0x4A 0x00 0x48 0x00 0x30 +: cycle-left 0x08 0x18 0x38 0x7F 0xFF 0x7F 0x38 0x18 0x08 +: cycle-right 0x10 0x18 0x1C 0xFE 0xFF 0xFE 0x1C 0x18 0x10 +: gather-npcs + 0xFE 0x02 0x0A 0x00 0x26 0xF9 0x08 0xF9 0x2B 0x1E 0x1A 0x1D 0x32 0xF9 0x2D 0x28 + 0xF9 0x20 0x1A 0x2D 0x21 0x1E 0x2B 0xFE 0x02 0x14 0x2D 0x21 0x1E 0xF9 0x29 0x1A + 0x2B 0x2D 0x32 0xF9 0x20 0x2E 0x1E 0x2C 0x2D 0x2C 0xF9 0x1A 0x27 0x1D 0xFE 0x02 + 0x1E 0x1E 0x31 0x29 0x28 0x2C 0x1E 0xF9 0x2D 0x21 0x1E 0xF9 0x24 0x22 0x25 0x25 + 0x1E 0x2B 0x40 0xFF +: who-dunnit + 0xFE 0x08 0x04 0x16 0x21 0x28 0xF9 0x22 0x2C 0xF9 0x2D 0x21 0x1E 0xF9 0x24 0x22 + 0x25 0x25 0x1E 0x2B 0x40 0xFF +: make-your-case + 0xFE 0x00 0x0C 0x13 0x21 0x1E 0xF9 0x20 0x2E 0x1E 0x2C 0x2D 0x2C 0xF9 0x20 0x1A + 0x2D 0x21 0x1E 0x2B 0x1E 0x1D 0x41 0xFE 0x00 0x16 0x32 0x28 0x2E 0xF9 0x25 0x1A + 0x32 0xF9 0x28 0x2E 0x2D 0xF9 0x32 0x28 0x2E 0x2B 0xF9 0x1C 0x1A 0x2C 0x1E 0xFE + 0x00 0x20 0x1A 0x27 0x1D 0xF9 0x29 0x2B 0x1E 0x29 0x1A 0x2B 0x1E 0xF9 0x2D 0x28 + 0xF9 0x1C 0x1A 0x25 0x25 0xFE 0x00 0x2A 0x2D 0x21 0x1E 0xF9 0x29 0x28 0x25 0x22 + 0x1C 0x1E 0x3E 0x3E 0x3E 0xFF +: no-weapon-part-1 # $0 is murderer... + 0xFE 0x00 0x03 0xFB 0xFE 0x00 0x0D 0x1B 0x2E 0x2B 0x2C 0x2D 0x2C 0xF9 0x28 0x2E + 0x2D 0xF9 0x25 0x1A 0x2E 0x20 0x21 0x22 0x27 0x20 0x3E 0xFE 0x00 0x17 0xFE 0x00 + 0x21 0x44 0x18 0x28 0x2E 0x2B 0xF9 0x1E 0x2F 0x22 0x1D 0x1E 0x27 0x1C 0x1E 0xF9 + 0x22 0x2C 0xFE 0x00 0x2B 0xF9 0x27 0x28 0x2D 0x21 0x22 0x27 0x20 0xF9 0x1B 0x2E + 0x2D 0xF9 0x21 0x1E 0x1A 0x2B 0x2C 0x1A 0x32 0x3F 0xFE 0x00 0x35 0xF9 0x16 0x21 + 0x1A 0x2D 0xF9 0x1A 0xF9 0x1F 0x28 0x28 0x25 0x3F 0x44 0xFF +: no-weapon-part-2 + 0xFE 0x00 0x03 0x16 0x22 0x2D 0x21 0x28 0x2E 0x2D 0xF9 0x1A 0xF9 0x30 0x1E 0x1A + 0x29 0x28 0x27 0x41 0xFE 0x00 0x0D 0x2D 0x21 0x1E 0xF9 0x29 0x28 0x25 0x22 0x1C + 0x1E 0xF9 0x1A 0x2B 0x1E 0x27 0x42 0x2D 0xFE 0x00 0x17 0x1C 0x28 0x27 0x2F 0x22 + 0x27 0x1C 0x1E 0x1D 0x41 0xF9 0x1E 0x22 0x2D 0x21 0x1E 0x2B 0x3E 0xFE 0x00 0x21 + 0xFE 0x00 0x2B 0x13 0x21 0x1E 0x32 0x42 0x2B 0x1E 0xF9 0x1F 0x28 0x2B 0x1C 0x1E + 0x1D 0xF9 0x2D 0x28 0xF9 0x25 0x1E 0x2D 0xFE 0x00 0x35 0x32 0x28 0x2E 0xF9 0x1A + 0x25 0x25 0xF9 0x20 0x28 0x41 0xF9 0x1F 0x28 0x2B 0xF9 0x27 0x28 0x30 0x3E 0xFF +: killer-goes-free + 0xFE 0x02 0x0A 0x12 0x28 0x26 0x1E 0x30 0x21 0x1E 0x2B 0x1E 0x41 0xF9 0x1A 0xF9 + 0x24 0x22 0x25 0x25 0x1E 0x2B 0xF9 0xF9 0xFE 0x02 0x14 0x30 0x1A 0x25 0x24 0x2C + 0xF9 0x1F 0x2B 0x1E 0x1E 0xF9 0x1A 0x26 0x28 0x27 0x20 0xF9 0x2E 0x2C 0x3E 0xF9 + 0xF9 0xFE 0x23 0x28 0x13 0x07 0x04 0xF9 0x04 0x0D 0x03 0x3E 0xFF +: wrong-culprit-part-1 + 0xFE 0x00 0x10 0xFB 0xFE 0x00 0x1A 0x2C 0x29 0x2E 0x2D 0x2D 0x1E 0x2B 0x2C 0xF9 + 0x22 0x27 0xF9 0x1D 0x22 0x2C 0x1B 0x1E 0x25 0x22 0x1E 0x1F 0xFE 0x00 0x24 0x1A + 0x2D 0xF9 0x32 0x28 0x2E 0x2B 0xF9 0x1A 0x1C 0x1C 0x2E 0x2C 0x1A 0x2D 0x22 0x28 + 0x27 0x3F 0xFF +: wrong-culprit-part-2 + 0xFE 0x00 0x03 0x13 0x21 0x1E 0xF9 0x28 0x2D 0x21 0x1E 0x2B 0xF9 0x20 0x2E 0x1E + 0x2C 0x2D 0x2C 0xF9 0xFE 0x00 0x0D 0x26 0x2E 0x2B 0x26 0x2E 0x2B 0xF9 0x2D 0x28 + 0xF9 0x28 0x27 0x1E 0xF9 0xFE 0x00 0x17 0x1A 0x27 0x28 0x2D 0x21 0x1E 0x2B 0xF9 + 0x30 0x1A 0x2B 0x22 0x25 0x32 0x3E 0xF9 0xFE 0x00 0x2B 0x13 0x21 0x1E 0xF9 0x29 + 0x28 0x25 0x22 0x1C 0x1E 0xF9 0xFE 0x00 0x35 0x2C 0x1E 0x1E 0x26 0xF9 0x1D 0x2E + 0x1B 0x22 0x28 0x2E 0x2C 0x3E 0xFF +: wrong-culprit-part-3 + 0xFE 0x00 0x03 0x08 0x27 0xF9 0x1C 0x28 0x2E 0x2B 0x2D 0x41 0xF9 0xFE 0x00 0x0D + 0xFB 0xF9 0x22 0x2C 0xF9 0xFE 0x00 0x17 0x1F 0x28 0x2E 0x27 0x1D 0xF9 0x22 0x27 + 0x27 0x28 0x1C 0x1E 0x27 0x2D 0x3E 0xF9 0xFE 0x00 0x2B 0x18 0x28 0x2E 0xF9 0x26 + 0x2E 0x2C 0x2D 0xF9 0x21 0x1A 0x2F 0x1E 0xF9 0x26 0x22 0x2C 0x2C 0x1E 0x1D 0xF9 + 0xFE 0x00 0x35 0x2C 0x28 0x26 0x1E 0x2D 0x21 0x22 0x27 0x20 0x3E 0x3E 0x3E 0xFF +: good-end-1 + 0xFE 0x07 0x08 0xFB 0x42 0x2C 0xF9 0xFE 0x07 0x12 0x1F 0x1A 0x1C 0x1E 0xF9 0x1C + 0x28 0x27 0x2D 0x28 0x2B 0x2D 0x2C 0xF9 0x30 0x22 0x2D 0x21 0xF9 0xFE 0x07 0x1C + 0x2B 0x1A 0x20 0x1E 0x3E 0xF9 0xFE 0x07 0x30 0x44 0x07 0x28 0x30 0xF9 0x1D 0x22 + 0x1D 0xF9 0x32 0x28 0x2E 0x3E 0x3E 0x3E 0x40 0x44 0xFF +: good-end-2 + 0xFE 0x05 0x10 0x13 0x21 0x1E 0xF9 0x29 0x28 0x25 0x22 0x1C 0x1E 0xF9 0x2C 0x28 + 0x28 0x27 0xFE 0x05 0x1A 0x1A 0x2B 0x2B 0x22 0x2F 0x1E 0xF9 0x2D 0x28 0xF9 0x2D + 0x1A 0x24 0x1E 0xF9 0x2D 0x21 0x1E 0x26 0xFE 0x05 0x24 0x22 0x27 0x2D 0x28 0xF9 + 0x1C 0x2E 0x2C 0x2D 0x28 0x1D 0x32 0x3E 0xFF +: good-end-3 + 0xFE 0x05 0x04 0x00 0x27 0x28 0x2D 0x21 0x1E 0x2B 0xF9 0x2C 0x2E 0x1C 0x1C 0x1E + 0x2C 0x2C 0x1F 0x2E 0x25 0xFE 0x05 0x0E 0x1C 0x1A 0x2C 0x1E 0x3E 0xF9 0x18 0x28 + 0x2E 0xF9 0x1C 0x1A 0x27 0xF9 0x2B 0x1E 0x2C 0x2D 0xFE 0x05 0x18 0x1E 0x1A 0x2C + 0x32 0xF9 0x1A 0x2D 0xF9 0x27 0x22 0x20 0x21 0x2D 0x41 0xFE 0x05 0x22 0x1F 0x28 + 0x2B 0xF9 0x27 0x28 0x30 0x3E 0x3E 0x3E 0xF9 0xFE 0x23 0x32 0x13 0x07 0x04 0xF9 + 0x04 0x0D 0x03 0x3E 0xFF +: murder-dialog-1 # "Well, if it isn't our friend the detective." + 0xFE 0x09 0x11 0x44 0x16 0x1E 0x25 0x25 0x41 0xF9 0x22 0x1F 0xF9 0x22 0x2D 0xF9 + 0x22 0x2C 0x27 0x42 0x2D 0xFE 0x09 0x1B 0x28 0x2E 0x2B 0xF9 0x1F 0x2B 0x22 0x1E + 0x27 0x1D 0xF9 0x2D 0x21 0x1E 0xFE 0x09 0x25 0x1D 0x1E 0x2D 0x1E 0x1C 0x2D 0x22 + 0x2F 0x1E 0x3E 0x44 0xFF +: murder-dialog-2 # "I can't afford to risk this charade any longer. Game over, old chum." + 0xFE 0x06 0x08 0x44 0x08 0xF9 0x1C 0x1A 0x27 0x42 0x2D 0xF9 0x1A 0x1F 0x1F 0x28 + 0x2B 0x1D 0xF9 0x2D 0x28 0xF9 0xF9 0xFE 0x06 0x12 0x2B 0x22 0x2C 0x24 0xF9 0x2D + 0x21 0x22 0x2C 0xF9 0x1C 0x21 0x1A 0x2B 0x1A 0x1D 0x1E 0xF9 0xF9 0xFE 0x06 0x1C + 0x1A 0x27 0x32 0xF9 0x25 0x28 0x27 0x20 0x1E 0x2B 0x3E 0xF9 0xFE 0x00 0x30 0xFD + 0x06 0x1A 0x26 0x1E 0xF9 0x28 0x2F 0x1E 0x2B 0x41 0xF9 0x28 0x25 0x1D 0xF9 0x1C + 0x21 0x2E 0x26 0x3E 0x44 0xFF +: terrible-fate + 0xFE 0x0A 0x0E 0xFD 0x18 0x28 0x2E 0xF9 0x21 0x1A 0x2F 0x1E 0xF9 0x26 0x1E 0x2D + 0xF9 0x30 0x22 0x2D 0x21 0xFE 0x0A 0x18 0x1A 0xF9 0x2D 0x1E 0x2B 0x2B 0x22 0x1B + 0x25 0x1E 0xF9 0x1F 0x1A 0x2D 0x1E 0x3E 0xF9 0xF9 0xFE 0x23 0x32 0x13 0x07 0x04 + 0xF9 0x04 0x0D 0x03 0x3E 0xFF + +: final-rank 0xFE 0x1D 0x0C 0x05 0x22 0x27 0x1A 0x25 0xF9 0x11 0x1A 0x27 0x24 0xFF + +: rank-0 0xFE 0x09 0x1E 0xFC 0x01 0x25 0x28 0x28 0x1D 0x32 0xF9 0x02 0x21 0x1E 0x1A 0x2D 0x1E 0x2B 0xFF +: rank-1 0xFE 0x27 0x1E 0xFC 0x12 0x25 0x1E 0x2E 0x2D 0x21 0xFF +: rank-2 0xFE 0x1B 0x1E 0xFC 0x03 0x1E 0x2D 0x1E 0x1C 0x2D 0x22 0x2F 0x1E 0xFF +: rank-3 0xFE 0x23 0x1E 0xFC 0x06 0x2E 0x26 0x2C 0x21 0x28 0x1E 0xFF +: rank-4 0xFE 0x1F 0x1E 0xFC 0x02 0x25 0x2E 0x1E 0x25 0x1E 0x2C 0x2C 0xFF + +: rank-thresholds + 20 60 90 150 255 +: rank-table + pointer rank-0 + pointer rank-1 + pointer rank-2 + pointer rank-3 + pointer rank-4 + +to-code + +: murder-player + wait 60 + i := long npc-murderer + load v2 - v2 + introduce-npc + + print murder-dialog-1 + dialog-pause + print murder-dialog-2 + dialog-pause + + dialog-fill-screen + wait 60 + print terrible-fate + jump show-rank + +: describe-body + clear + print gather-npcs # confirm gathering... + dialog-yes-no + if v2 == 0 then return + + # accuse! + v2 := random 0b111 + loop + print who-dunnit + i := long npc-portrait-table + portrait + v1 := 25 + v0 := 40 + i := long cycle-left + sprite v0 v1 9 + v0 := 80 + i := long cycle-right + sprite v0 v1 9 + print-from-table v2 npc-title-table + vf := key + clear + if vf == OCTO_KEY_D then v2 += 1 + if vf == OCTO_KEY_A then v2 += -1 + v0 := 0b111 + v2 &= v0 + if vf != OCTO_KEY_E then + again + accused-npc := v2 + + # the truth, and nothing but the truth: + i := long npc-murderer + load guilty-npc - guilty-npc + i := long murder-weapon + load guilty-weapon - guilty-weapon + + print make-your-case + dialog-pause + + if has-weapon == 0 begin + fmt-from-table guilty-npc npc-name-table print-string0-read + print no-weapon-part-1 + dialog-pause + print no-weapon-part-2 + dialog-pause + print killer-goes-free + suspicion-level := 255 + jump show-rank + end + + fmt-from-table accused-npc npc-name-table print-string0-read + + if guilty-npc != accused-npc begin + print wrong-culprit-part-1 + dialog-pause + print wrong-culprit-part-2 + dialog-pause + print wrong-culprit-part-3 + dialog-pause + print killer-goes-free + :calc bad-score { @ rank-thresholds + 3 } + suspicion-level := bad-score + jump show-rank + end + + print good-end-1 + dialog-pause + jump fencing-minigame + +: show-rank + dialog-pause + v2 := 0 + loop + i := long rank-thresholds + i += v2 + load v0 + while suspicion-level > v0 + v2 += 1 + again + print final-rank + print-from-table v2 rank-table + dialog-pause + current-room := GAME_OVER +; + +########################################### +# +# NPCs +# +########################################### + +to-data + +# 8x15 overworld sprites padded to 8x16 +: npc-sprites +: npc-0 0x3E 0x7C 0x76 0x66 0x7C 0x38 0x5C 0x5C 0x5C 0x64 0x7E 0x7E 0x7E 0x28 0x3C 0x00 +: npc-1 0x78 0xFC 0x4C 0x58 0x78 0x7E 0x3E 0x3E 0x7A 0x78 0x3E 0x3E 0x36 0x36 0x7E 0x00 +: npc-2 0x3C 0x3C 0x7A 0x24 0x1C 0x3E 0x7E 0x7E 0x7D 0x7D 0x34 0x34 0x38 0x38 0x1E 0x00 +: npc-3 0x38 0x7C 0x72 0x24 0x34 0x7E 0x62 0x7E 0x3E 0x7F 0x77 0x36 0x36 0x3A 0x1D 0x00 +: npc-4 0x78 0x58 0x4C 0x4C 0x7E 0x6E 0x3F 0x3F 0x1D 0x3F 0x3F 0x3F 0x3F 0x3F 0x12 0x00 +: npc-5 0x7C 0x3A 0x34 0x64 0x24 0x3C 0x42 0x6A 0x5A 0x7E 0x7E 0x7E 0x7E 0x34 0x34 0x00 +: npc-6 0x38 0x7C 0x44 0x6C 0x6C 0x7C 0x38 0x7C 0xFE 0xFE 0xFE 0x6C 0x28 0x28 0x6C 0x00 +: npc-7 0x18 0x3C 0x24 0x7E 0xC3 0xEF 0xEF 0xEF 0xAF 0xC3 0xFD 0x7E 0x3C 0x3C 0x7E 0x00 + +# 16x16 portraits +: portrait-0 + 0x0F 0xFE 0x1F 0xBF 0x3F 0x9C 0x7F 0x0C 0x7F 0xDE 0x7E 0x06 0xFD 0x9E 0xFC 0x8E + 0xF8 0x06 0xF8 0x26 0xD8 0x06 0x5C 0xF7 0x3C 0x0E 0x19 0xF8 0x2D 0xDE 0x76 0x3F +: portrait-1 + 0x1F 0x7C 0x7F 0xF8 0xFF 0xF8 0xF0 0xDC 0xB0 0x1E 0x39 0xDE 0x39 0xFC 0x3C 0x96 + 0x1C 0x16 0x2C 0x36 0x2E 0x7E 0x30 0x7E 0x3F 0x7C 0x1C 0xF6 0x3F 0xEF 0x6F 0xFF +: portrait-2 + 0x0F 0xF0 0x38 0x7C 0x30 0x1E 0x30 0x1E 0x30 0x1E 0x3F 0x1E 0xFF 0xEE 0xFF 0xFE + 0x37 0xBD 0x1F 0xF9 0x1F 0x19 0x1B 0x06 0x18 0x06 0x0F 0x8C 0x0E 0x3E 0x1F 0xFE +: portrait-3 + 0x1F 0xE0 0x3F 0xF0 0x7E 0x08 0x78 0x76 0x78 0xE1 0x3C 0x61 0x66 0x1F 0x47 0x0E + 0x41 0x86 0x2C 0x1C 0x3E 0x3C 0x1F 0x8C 0x33 0xCC 0x7C 0xF8 0xFE 0x34 0xFF 0x8E +: portrait-4 + 0x3F 0xC0 0x7F 0xF0 0x7F 0xF8 0xF6 0xEC 0xE3 0x74 0xF6 0x74 0xF7 0xB6 0xD2 0x3A + 0xC0 0x1A 0xD8 0x5B 0xCC 0x7D 0xE0 0x5D 0xEE 0xDF 0xF1 0xFE 0x7F 0xBE 0x78 0x7A +: portrait-5 + 0x3F 0xC0 0xFF 0xF8 0x7F 0xE8 0x3F 0x34 0x34 0x2C 0x3B 0xA8 0x1B 0xDC 0x62 0x38 + 0x40 0x7C 0x78 0x3C 0x18 0x7C 0x17 0x7E 0x17 0xFF 0x0F 0xDF 0x1C 0x3F 0x3B 0xCF +: portrait-6 + 0x1F 0xF8 0x1F 0xF4 0x2F 0xFA 0x77 0xFE 0x70 0xFF 0xF0 0x3F 0xFE 0xFF 0xD4 0x57 + 0xD1 0x17 0xF9 0x3F 0xF9 0x3F 0xE8 0x2F 0x7B 0xBE 0x38 0x3C 0x4F 0xF2 0xFB 0x9F +: portrait-7 + 0x1F 0xF0 0x2F 0xE8 0x23 0x8C 0x5C 0x74 0x54 0x66 0x48 0x4A 0x6F 0xD6 0x47 0x8E + 0x2F 0xEC 0x30 0x1F 0x7F 0xFB 0x5F 0xF3 0xCF 0xCF 0xE0 0x1D 0xBC 0xFB 0xFC 0xFF + +: npc-title-0 # "Mme. Genta" + 0xFE 0x17 0x2D 0xFC 0x0C 0x26 0x1E 0x3E 0xF9 0x06 0x1E 0x27 0x2D 0x1A 0xFF +: npc-title-1 # "Mr. Carmine" + 0xFE 0x14 0x2D 0xFC 0x0C 0x2B 0x3E 0xF9 0x02 0x1A 0x2B 0x26 0x22 0x27 0x1E 0xFF +: npc-title-2 # "Sir Feldgrau" + 0xFE 0x11 0x2D 0xFC 0x12 0x22 0x2B 0xF9 0x05 0x1E 0x25 0x1D 0x20 0x2B 0x1A 0x2E 0xFF +: npc-title-3 # "Prof. Puce" + 0xFE 0x16 0x2D 0xFC 0x0F 0x2B 0x28 0x1F 0x3E 0xF9 0x0F 0x2E 0x1C 0x1E 0xFF +: npc-title-4 # "Lady Veridian" + 0xFE 0x0D 0x2D 0xFC 0x0B 0x1A 0x1D 0x32 0xF9 0x15 0x1E 0x2B 0x22 0x1D 0x22 0x1A 0x27 0xFF +: npc-title-5 # "Cmdr. Coriander" (longest) + 0xFE 0x05 0x2D 0xFC 0x02 0x26 0x1D 0x2B 0x3E 0xF9 0x02 0x28 0x2B 0x22 0x1A 0x27 0x1D 0x1E 0x2B 0xFF +: npc-title-6 # "Dr. Coquelicot" + 0xFE 0x08 0x2D 0xFC 0x03 0x2B 0x3E 0xF9 0x02 0x28 0x2A 0x2E 0x1E 0x25 0x22 0x1C 0x28 0x2D 0xFF +: npc-title-7 # "Lord Zaffre" + 0xFE 0x11 0x2D 0xFC 0x0B 0x28 0x2B 0x1D 0xF9 0xF9 0x19 0x1A 0x1F 0x1F 0x2B 0x1E 0xFF + +: npc-name-0 0x0C 0x26 0x1E 0x3E 0xF9 0x06 0x1E 0x27 0x2D 0x1A 0xFF +: npc-name-1 0x0C 0x2B 0x3E 0xF9 0x02 0x1A 0x2B 0x26 0x22 0x27 0x1E 0xFF +: npc-name-2 0x12 0x22 0x2B 0xF9 0x05 0x1E 0x25 0x1D 0x20 0x2B 0x1A 0x2E 0xFF +: npc-name-3 0x0F 0x2B 0x28 0x1F 0x3E 0xF9 0x0F 0x2E 0x1C 0x1E 0xFF +: npc-name-4 0x0B 0x1A 0x1D 0x32 0xF9 0x15 0x1E 0x2B 0x22 0x1D 0x22 0x1A 0x27 0xFF +: npc-name-5 0x02 0x26 0x1D 0x2B 0x3E 0xF9 0x02 0x28 0x2B 0x22 0x1A 0x27 0x1D 0x1E 0x2B 0xFF +: npc-name-6 0x03 0x2B 0x3E 0xF9 0x02 0x28 0x2A 0x2E 0x1E 0x25 0x22 0x1C 0x28 0x2D 0xFF +: npc-name-7 0x0B 0x28 0x2B 0x1D 0xF9 0xF9 0x19 0x1A 0x1F 0x1F 0x2B 0x1E 0xFF + +: npc-scoff-0 # "Still snooping about, I see? What was I doing?" + 0xFE 0x00 0x0D 0x44 0x12 0x2D 0x22 0x25 0x25 0xF9 0x2C 0x27 0x28 0x28 0x29 0x22 + 0x27 0x20 0xF9 0x1A 0x1B 0x28 0x2E 0x2D 0xF9 0xFE 0x00 0x17 0x08 0xF9 0x2C 0x1E + 0x1E 0x40 0xF9 0x06 0x28 0x28 0x1D 0xF9 0x25 0x2E 0x1C 0x24 0x3E 0xF9 0xF9 0xFE + 0x00 0x2B 0x3E 0x3E 0x3E 0x16 0x21 0x1A 0x2D 0xF9 0x30 0x1A 0x2C 0xF9 0x08 0xF9 + 0x1D 0x28 0x22 0x27 0x20 0x40 0x44 0xFF +: npc-scoff-1 # "I suppose you want to know my wereabouts this evening?" + 0xFE 0x00 0x0F 0x44 0x08 0xF9 0x2C 0x2E 0x29 0x29 0x28 0x2C 0x1E 0xF9 0x32 0x28 + 0x2E 0xF9 0x30 0x1A 0x27 0x2D 0xF9 0xFE 0x00 0x19 0x2D 0x28 0xF9 0x24 0x27 0x28 + 0x30 0xF9 0x26 0x32 0xF9 0x30 0x1E 0x2B 0x1E 0x1A 0x1B 0x28 0x2E 0x2D 0x2C 0xF9 + 0xFE 0x00 0x23 0x2D 0x21 0x22 0x2C 0xF9 0x1E 0x2F 0x1E 0x27 0x22 0x27 0x20 0x40 + 0x44 0xFF +: npc-scoff-2 # "Oh, come now. You can't believe I was responsible for this?" + 0xFE 0x04 0x0C 0x44 0x0E 0x21 0x41 0xF9 0x1C 0x28 0x26 0x1E 0xF9 0x27 0x28 0x30 + 0x3F 0xF9 0xFE 0x04 0x16 0x18 0x28 0x2E 0xF9 0x1C 0x1A 0x27 0x42 0x2D 0xF9 0x1B + 0x1E 0x25 0x22 0x1E 0x2F 0x1E 0xF9 0x08 0xF9 0xFE 0x04 0x20 0x30 0x1A 0x2C 0xF9 + 0x2B 0x1E 0x2C 0x29 0x28 0x27 0x2C 0x22 0x1B 0x25 0x1E 0xF9 0x1F 0x28 0x2B 0xF9 + 0xFE 0x04 0x2A 0x1A 0x27 0x32 0xF9 0x28 0x1F 0xF9 0x2D 0x21 0x22 0x2C 0x40 0x44 + 0xFF +: npc-scoff-3 # "I'll have you know I was quite occupied during this vile business." + 0xFE 0x01 0x0C 0x44 0x08 0x42 0x25 0x25 0xF9 0x21 0x1A 0x2F 0x1E 0xF9 0x32 0x28 + 0x2E 0xF9 0x24 0x27 0x28 0x30 0x41 0xF9 0xFE 0x01 0x16 0x08 0xF9 0x30 0x1A 0x2C + 0xF9 0x2A 0x2E 0x22 0x2D 0x1E 0xF9 0x28 0x1C 0x1C 0x2E 0x29 0x22 0x1E 0x1D 0xF9 + 0xFE 0x01 0x20 0x1D 0x2E 0x2B 0x22 0x27 0x20 0xF9 0x1A 0x25 0x25 0xF9 0x28 0x1F + 0xF9 0x2D 0x21 0x22 0x2C 0xF9 0xFE 0x01 0x2A 0x2F 0x22 0x25 0x1E 0xF9 0x1B 0x2E + 0x2C 0x22 0x27 0x1E 0x2C 0x2C 0x3F 0x44 0xFF +: npc-scoff-4 # "Regarding tonight, I assure you I have nothing to hide." + 0xFE 0x05 0x11 0x44 0x11 0x1E 0x20 0x1A 0x2B 0x1D 0x22 0x27 0x20 0xF9 0x2D 0x28 + 0x27 0x22 0x20 0x21 0x2D 0x41 0xF9 0xFE 0x05 0x1B 0x08 0xF9 0x1A 0x2C 0x2C 0x2E + 0x2B 0x1E 0xF9 0x32 0x28 0x2E 0xF9 0x08 0xF9 0x21 0x1A 0x2F 0x1E 0xF9 0xFE 0x05 + 0x25 0x27 0x28 0x2D 0x21 0x22 0x27 0x20 0xF9 0x2D 0x28 0xF9 0x21 0x22 0x1D 0x1E + 0x3F 0x44 0xFF +: npc-scoff-5 # "Where was I all evening? Hrm. Fine, I'll tell you." + 0xFE 0x00 0x0A 0x44 0x16 0x21 0x1E 0x2B 0x1E 0xF9 0x30 0x1A 0x2C 0xF9 0x08 0xF9 + 0x1A 0x25 0x25 0xF9 0xFE 0x00 0x14 0x1E 0x2F 0x1E 0x27 0x22 0x27 0x20 0x40 0xF9 + 0x07 0x2E 0x26 0x29 0x21 0x3E 0xF9 0xFE 0x00 0x28 0x05 0x22 0x27 0x1E 0x41 0xF9 + 0x08 0x42 0x25 0x25 0xF9 0x2D 0x1E 0x25 0x25 0xF9 0x32 0x28 0x2E 0x3E 0x44 0xFF +: npc-scoff-6 # "No beating around the bush, then? I think I know what you want to hear." + 0xFE 0x04 0x0A 0x44 0x0D 0x28 0xF9 0x1B 0x1E 0x1A 0x2D 0x22 0x27 0x20 0xF9 0x1A + 0x2B 0x28 0x2E 0x27 0x1D 0xFE 0x04 0x14 0x2D 0x21 0x1E 0xF9 0x1B 0x2E 0x2C 0x21 + 0x41 0xF9 0x2D 0x21 0x1E 0x27 0x40 0xFE 0x04 0x1E 0x08 0xF9 0x2D 0x21 0x22 0x27 + 0x24 0xF9 0x08 0xF9 0x24 0x27 0x28 0x30 0xF9 0x30 0x21 0x1A 0x2D 0xFE 0x04 0x28 + 0x32 0x28 0x2E 0xF9 0x30 0x1A 0x27 0x2D 0xF9 0x2D 0x28 0xF9 0x21 0x1E 0x1A 0x2B + 0x3E 0x44 0xFF +: npc-scoff-7 # "I dearly hope you can solve this, old chum. As for myself, well..." + 0xFE 0x08 0x03 0x44 0x08 0xF9 0x1D 0x1E 0x1A 0x2B 0x25 0x32 0xF9 0x21 0x28 0x29 + 0x1E 0xF9 0x32 0x28 0x2E 0xF9 0xFE 0x08 0x0D 0x1C 0x1A 0x27 0xF9 0x2C 0x28 0x25 + 0x2F 0x1E 0xF9 0x2D 0x21 0x22 0x2C 0x41 0xF9 0xFE 0x08 0x17 0x28 0x25 0x1D 0xF9 + 0x1C 0x21 0x2E 0x26 0x3E 0xF9 0xFE 0x08 0x2B 0x00 0x2C 0xF9 0x1F 0x28 0x2B 0xF9 + 0x26 0x32 0x2C 0x1E 0x25 0x1F 0x41 0xF9 0xFE 0x08 0x35 0x30 0x1E 0x25 0x25 0x3E + 0x3E 0x3E 0x44 0xFF +: npc-scoff-8 # "Hm? Did you want something? Oh, of course, of course." + 0xFE 0x0D 0x08 0x44 0x07 0x26 0x40 0xF9 0x03 0x22 0x1D 0xF9 0x32 0x28 0x2E 0xF9 + 0x30 0x1A 0x27 0x2D 0xFE 0x0D 0x12 0x2C 0x28 0x26 0x1E 0x2D 0x21 0x22 0x27 0x20 + 0x40 0xFE 0x0D 0x1C 0xFE 0x0D 0x26 0x0E 0x21 0x41 0xF9 0x28 0x1F 0xF9 0x1C 0x28 + 0x2E 0x2B 0x2C 0x1E 0x41 0xFE 0x0D 0x30 0x28 0x1F 0xF9 0x1C 0x28 0x2E 0x2B 0x2C + 0x1E 0x3E 0x44 0xFF + +: room-name-0 0x25 0x22 0x1B 0x2B 0x1A 0x2B 0x32 0xFF +: room-name-1 0x1B 0x1A 0x2D 0x21 0x2B 0x28 0x28 0x26 0xFF +: room-name-2 0x1B 0x1E 0x1D 0x2B 0x28 0x28 0x26 0xFF +: room-name-3 0x1D 0x2B 0x1A 0x30 0x22 0x27 0x20 0xF9 0x2B 0x28 0x28 0x26 0xFF +: room-name-4 0x29 0x1A 0x2B 0x25 0x28 0x2B 0xFF +: room-name-5 0x1D 0x22 0x27 0x22 0x27 0x20 0xF9 0x2B 0x28 0x28 0x26 0xFF +: room-name-6 0x2C 0x2D 0x2E 0x1D 0x32 0xFF +: room-name-7 0x1C 0x28 0x27 0x2C 0x1E 0x2B 0x2F 0x1A 0x2D 0x28 0x2B 0x32 0xFF +: room-name-8 0x24 0x22 0x2D 0x1C 0x21 0x1E 0x27 0xFF +: room-name-9 0x29 0x1A 0x27 0x2D 0x2B 0x32 0xFF + +: npc-was-alone # $1 is location. + 0xFE 0x0E 0x10 0x44 0x08 0xF9 0x30 0x1A 0x2C 0xF9 0x1A 0x25 0x28 0x27 0x1E 0xF9 0x1A + 0x25 0x25 0xF9 0xFE 0x0E 0x1A 0x1E 0x2F 0x1E 0x27 0x22 0x27 0x20 0x41 0xF9 0x22 0x27 + 0xF9 0x2D 0x21 0x1E 0xF9 0xFE 0x0E 0x24 0xFA 0x3E 0x44 0xFF + +: npc-was-with-in # $0 is partner, $1 is location. + 0xFE 0x00 0x11 0x44 0x08 0xF9 0x30 0x1A 0x2C 0xF9 0x30 0x22 0x2D 0x21 0xF9 0xFE 0x00 + 0x1B 0xFB 0x41 0xF9 0xFE 0x00 0x25 0x22 0x27 0xF9 0x2D 0x21 0x1E 0xF9 0xFA 0x3E 0x44 + 0xFF + +: npc-portrait-table + pointer portrait-0 + pointer portrait-1 + pointer portrait-2 + pointer portrait-3 + pointer portrait-4 + pointer portrait-5 + pointer portrait-6 + pointer portrait-7 + +: npc-title-table + pointer npc-title-0 + pointer npc-title-1 + pointer npc-title-2 + pointer npc-title-3 + pointer npc-title-4 + pointer npc-title-5 + pointer npc-title-6 + pointer npc-title-7 + +: npc-name-table + pointer npc-name-0 + pointer npc-name-1 + pointer npc-name-2 + pointer npc-name-3 + pointer npc-name-4 + pointer npc-name-5 + pointer npc-name-6 + pointer npc-name-7 + +: npc-scoff-table + pointer npc-scoff-0 + pointer npc-scoff-1 + pointer npc-scoff-2 + pointer npc-scoff-3 + pointer npc-scoff-4 + pointer npc-scoff-5 + pointer npc-scoff-6 + pointer npc-scoff-7 + +: room-name-table + pointer room-name-0 + pointer room-name-1 + pointer room-name-2 + pointer room-name-3 + pointer room-name-4 + pointer room-name-5 + pointer room-name-6 + pointer room-name-7 + pointer room-name-8 + pointer room-name-9 + +to-code + +: introduce-npc + # (pass the npc index in v2...) + clear + i := long npc-portrait-table + portrait + print-from-table v2 npc-title-table + dialog-pause +; + +: describe-npc + thicken-plot SUSPICION_TALK_NPC + introduce-npc + + i := long npc-scoff-index + i += v2 + load v0 + print-from-table v0 npc-scoff-table + dialog-pause + + # find alibi slot w/ our npc + v0 := 0 + loop + i := long npc-alibis + i += v0 + load v1 - v1 + while v1 != v2 + v0 += 1 + again + + if v0 == 6 begin + # lone NPC + i := long npc-alibi-r4 + load v0 + fmt-from-table v0 room-name-table print-string1-read + print npc-was-alone + jump dialog-pause + end + + if v0 == 7 begin + thicken-plot SUSPICION_TALK_MURDERER + # murderer + i := long npc-alibi-r5 + load v0 + fmt-from-table v0 room-name-table print-string1-read + i := long npc-alibis + load v0 + else + # normal alibi + v1 := v0 + vf := 0b110 + v1 &= vf # v1 is now the base [0,2,4] alibi slot index. + i := long npc-alibi-rooms + v1 >>= v1 # v1 is now an alibi room index + i += v1 + load v1 - v1 # v1 is now the alibi room for the current slot. + fmt-from-table v1 room-name-table print-string1-read + + i := long npc-alibis + vf := 1 + v0 ^= vf # v0 is now the slot index of the partner NPC. + i += v0 + load v0 # v0 is now the id of the partner NPC. + end + fmt-from-table v0 npc-name-table print-string0-read + print npc-was-with-in + jump dialog-pause + +########################################### +# +# Decorations and Passages +# +########################################### + +to-data + +: d1-library # "Countless volumes on the history of the Orient. Fascinating." + 0xFE 0x0A 0x08 0x02 0x28 0x2E 0x27 0x2D 0x25 0x1E 0x2C 0x2C 0xF9 0x2F 0x28 0x25 + 0x2E 0x26 0x1E 0x2C 0xF9 0xFE 0x0A 0x12 0x28 0x27 0xF9 0x2D 0x21 0x1E 0xF9 0x21 + 0x22 0x2C 0x2D 0x28 0x2B 0x32 0xF9 0x28 0x1F 0xF9 0xFE 0x0A 0x1C 0x2D 0x21 0x1E + 0xF9 0x0E 0x2B 0x22 0x1E 0x27 0x2D 0x3E 0xF9 0xFE 0x0A 0x2E 0x05 0x1A 0x2C 0x1C + 0x22 0x27 0x1A 0x2D 0x22 0x27 0x20 0x3E 0xFF +: d2-library # "Philosophy, Logic, Game theory... Mosaic tiling? How Curious." + 0xFE 0x0A 0x08 0x0F 0x21 0x22 0x25 0x28 0x2C 0x28 0x29 0x21 0x32 0x41 0xF9 0x0B + 0x28 0x20 0x22 0x1C 0x41 0xF9 0xFE 0x0A 0x12 0x06 0x1A 0x26 0x1E 0xF9 0x2D 0x21 + 0x1E 0x28 0x2B 0x32 0x3E 0x3E 0x3E 0xF9 0xFE 0x0A 0x1C 0x0C 0x28 0x2C 0x1A 0x22 + 0x1C 0xF9 0x2D 0x22 0x25 0x22 0x27 0x20 0x40 0xF9 0xFE 0x0A 0x2E 0x07 0x28 0x30 + 0xF9 0x02 0x2E 0x2B 0x22 0x28 0x2E 0x2C 0x3E 0xFF + +: d1-bathroom # "Spare towels, dirty clothes. Nothing terribly out of the ordinary." + 0xFE 0x04 0x0C 0x12 0x29 0x1A 0x2B 0x1E 0xF9 0x2D 0x28 0x30 0x1E 0x25 0x2C 0x41 + 0xFE 0x04 0x16 0x1D 0x22 0x2B 0x2D 0x32 0xF9 0x1C 0x25 0x28 0x2D 0x21 0x1E 0x2C + 0x3E 0xFE 0x04 0x20 0x0D 0x28 0x2D 0x21 0x22 0x27 0x20 0xF9 0x2D 0x1E 0x2B 0x2B + 0x22 0x1B 0x25 0x32 0xFE 0x04 0x2A 0x28 0x2E 0x2D 0xF9 0x28 0x1F 0xF9 0x2D 0x21 + 0x1E 0xF9 0x28 0x2B 0x1D 0x22 0x27 0x1A 0x2B 0x32 0x3E 0xFF +: d2-bathroom # "The bathmat feels damp to the touch. Someone has showered here recently." + 0xFE 0x02 0x0C 0x13 0x21 0x1E 0xF9 0x1B 0x1A 0x2D 0x21 0x26 0x1A 0x2D 0xF9 0x1F + 0x1E 0x1E 0x25 0x2C 0xFE 0x02 0x16 0x1D 0x1A 0x26 0x29 0xF9 0x2D 0x28 0xF9 0x2D + 0x21 0x1E 0xF9 0x2D 0x28 0x2E 0x1C 0x21 0x3E 0xFE 0x02 0x20 0x12 0x28 0x26 0x1E + 0x28 0x27 0x1E 0xF9 0x21 0x1A 0x2C 0xF9 0x2C 0x21 0x28 0x30 0x1E 0x2B 0x1E 0x1D + 0xFE 0x02 0x2A 0x21 0x1E 0x2B 0x1E 0xF9 0x2B 0x1E 0x1C 0x1E 0x27 0x2D 0x25 0x32 + 0x3E 0x3E 0x3E 0xFF + +: d1-bedroom # "The covers are warm to the touch. How scandalous!" + 0xFE 0x02 0x0A 0x13 0x21 0x1E 0xF9 0x1C 0x28 0x2F 0x1E 0x2B 0x2C 0xF9 0x1A 0x2B + 0x1E 0xF9 0x2C 0x2D 0x22 0x25 0x25 0xF9 0xFE 0x02 0x14 0x30 0x1A 0x2B 0x26 0xF9 + 0x2D 0x28 0xF9 0x2D 0x21 0x1E 0xF9 0x2D 0x28 0x2E 0x1C 0x21 0x3E 0xF9 0xFE 0x02 + 0x23 0x08 0x2D 0xF9 0x2C 0x1E 0x1E 0x26 0x2C 0xF9 0x2D 0x21 0x1E 0xF9 0x20 0x2E + 0x1E 0x2C 0x2D 0x2C 0xF9 0xFE 0x02 0x2D 0x21 0x1A 0x2F 0x1E 0xF9 0x1B 0x1E 0x1E + 0x27 0x3E 0x3E 0x3E 0xF9 0x1B 0x2E 0x2C 0x32 0x3E 0x3E 0x3E 0xFF +: d2-bedroom # "On the desk is an open decanter of a particularly peaty scotch." + 0xFE 0x05 0x08 0x0E 0x27 0xF9 0x2D 0x21 0x1E 0xF9 0x1D 0x1E 0x2C 0x24 0xF9 0x22 + 0x2C 0xF9 0x1A 0x27 0xFE 0x05 0x12 0x28 0x29 0x1E 0x27 0xF9 0x1D 0x1E 0x1C 0x1A + 0x27 0x2D 0x1E 0x2B 0xF9 0x28 0x1F 0xF9 0x1A 0xFE 0x05 0x1C 0x29 0x1A 0x2B 0x2D + 0x22 0x1C 0x2E 0x25 0x1A 0x2B 0x25 0x32 0xF9 0x29 0x1E 0x1A 0x2D 0x32 0xFE 0x05 + 0x26 0x2C 0x1C 0x28 0x2D 0x1C 0x21 0x3E 0xF9 0x03 0x28 0x27 0x42 0x2D 0xF9 0x26 + 0x22 0x27 0x1D 0xFE 0x05 0x30 0x22 0x1F 0xF9 0x08 0xF9 0x1D 0x28 0x3E 0x3E 0x3E + 0xFF + +: d1-drawing-room # "A crude sketch of a naked woman. The eyes have been carefully cut out. Most unsettling." + 0xFE 0x06 0x02 0x00 0xF9 0x1C 0x2B 0x2E 0x1D 0x1E 0xF9 0x2C 0x24 0x1E 0x2D 0x1C + 0x21 0xF9 0x28 0x1F 0xF9 0x1A 0xF9 0xFE 0x06 0x0C 0x27 0x1A 0x24 0x1E 0x1D 0xF9 + 0x30 0x28 0x26 0x1A 0x27 0x3E 0xF9 0xFE 0x06 0x16 0x13 0x21 0x1E 0xF9 0x1E 0x32 + 0x1E 0x2C 0xF9 0x21 0x1A 0x2F 0x1E 0xF9 0x1B 0x1E 0x1E 0x27 0xF9 0xFE 0x06 0x20 + 0x1C 0x1A 0x2B 0x1E 0x1F 0x2E 0x25 0x25 0x32 0xF9 0x1C 0x2E 0x2D 0xF9 0x28 0x2E + 0x2D 0x3E 0xF9 0xFE 0x06 0x34 0x0C 0x28 0x2C 0x2D 0xF9 0x2E 0x27 0x2C 0x1E 0x2D + 0x2D 0x25 0x22 0x27 0x20 0x3E 0xFF +: d2-drawing-room # "A sketch of a featureless black cube. Quite modern." + 0xFE 0x16 0x06 0x00 0xF9 0x2C 0x24 0x1E 0x2D 0x1C 0x21 0xF9 0x28 0x1F 0xF9 0x1A + 0xF9 0xFE 0x16 0x10 0x1F 0x1E 0x1A 0x2D 0x2E 0x2B 0x1E 0x25 0x1E 0x2C 0x2C 0xF9 + 0xFE 0x16 0x1A 0x1B 0x25 0x1A 0x1C 0x24 0xF9 0x1C 0x2E 0x1B 0x1E 0x3E 0xF9 0xFE + 0x16 0x2E 0x10 0x2E 0x22 0x2D 0x1E 0xF9 0x26 0x28 0x1D 0x1E 0x2B 0x27 0x3E 0xFF + +# editor's note: yes, I know that a "drawing room" is not typically +# dedicated to literal drawings and sketches. It's a joke! + +: d1-parlor # "A half-written party invitation. The recipient is hastily scratched out." + 0xFE 0x00 0x04 0x00 0xF9 0x21 0x1A 0x25 0x1F 0x43 0x30 0x2B 0x22 0x2D 0x2D 0x1E + 0x27 0xF9 0x29 0x1A 0x2B 0x2D 0x32 0xF9 0xF9 0xFE 0x00 0x0E 0x22 0x27 0x2F 0x22 + 0x2D 0x1A 0x2D 0x22 0x28 0x27 0x3E 0xF9 0xF9 0xFE 0x00 0x1C 0x13 0x21 0x1E 0xF9 + 0x2B 0x1E 0x1C 0x22 0x29 0x22 0x1E 0x27 0x2D 0x42 0x2C 0xF9 0xF9 0xFE 0x00 0x26 + 0x27 0x1A 0x26 0x1E 0xF9 0x21 0x1A 0x2C 0xF9 0x1B 0x1E 0x1E 0x27 0xF9 0x21 0x1A + 0x2C 0x2D 0x22 0x25 0x32 0xF9 0xF9 0xFE 0x00 0x30 0x2C 0x1C 0x2B 0x1A 0x2D 0x1C + 0x21 0x1E 0x1D 0xF9 0x28 0x2E 0x2D 0x3E 0x3E 0x3E 0xFF +: d2-parlor # "Well-worn armchairs of the finest mink leather. A tad ostentatious." + 0xFE 0x05 0x0C 0x16 0x1E 0x25 0x25 0x43 0x30 0x28 0x2B 0x27 0xF9 0x1A 0x2B 0x26 + 0x1C 0x21 0x1A 0x22 0x2B 0x2C 0xFE 0x05 0x16 0x28 0x1F 0xF9 0x2D 0x21 0x1E 0xF9 + 0x1F 0x22 0x27 0x1E 0x2C 0x2D 0xF9 0x26 0x22 0x27 0x24 0xFE 0x05 0x20 0x25 0x1E + 0x1A 0x2D 0x21 0x1E 0x2B 0x3E 0xF9 0x00 0xF9 0x2D 0x1A 0x1D 0xFE 0x05 0x2A 0x28 + 0x2C 0x2D 0x1E 0x27 0x2D 0x1A 0x2D 0x22 0x28 0x2E 0x2C 0x41 0xF9 0x27 0x28 0x40 + 0xFF + +: d1-dining-room # "What remains of dinner. I daresay I've lost my appetite." + 0xFE 0x04 0x08 0x16 0x21 0x1A 0x2D 0xF9 0x2B 0x1E 0x26 0x1A 0x22 0x27 0x2C 0xF9 + 0xF9 0xFE 0x04 0x12 0x28 0x1F 0xF9 0x1D 0x22 0x27 0x27 0x1E 0x2B 0x3E 0xF9 0xF9 + 0xFE 0x04 0x26 0x08 0xF9 0x1D 0x1A 0x2B 0x1E 0x2C 0x1A 0x32 0xF9 0x08 0x42 0x2F + 0x1E 0xF9 0x25 0x28 0x2C 0x2D 0xF9 0xF9 0xFE 0x04 0x30 0x26 0x32 0xF9 0x1A 0x29 + 0x29 0x1E 0x2D 0x22 0x2D 0x1E 0x3E 0xFF +: d2-dining-room # "A sterling silver tea set. Someone seems to have made off with the sugar." + 0xFE 0x08 0x02 0x00 0xF9 0x2C 0x2D 0x1E 0x2B 0x25 0x22 0x27 0x20 0xF9 0x2C 0x22 + 0x25 0x2F 0x1E 0x2B 0xF9 0xFE 0x08 0x0C 0x2D 0x1E 0x1A 0xF9 0x2C 0x1E 0x2D 0x3E + 0xF9 0xFE 0x08 0x20 0x12 0x28 0x26 0x1E 0x28 0x27 0x1E 0xF9 0x2C 0x1E 0x1E 0x26 + 0x2C 0xF9 0x2D 0x28 0xF9 0xFE 0x08 0x2A 0x21 0x1A 0x2F 0x1E 0xF9 0x26 0x1A 0x1D + 0x1E 0xF9 0x28 0x1F 0x1F 0xF9 0x30 0x22 0x2D 0x21 0xF9 0xFE 0x08 0x34 0x2D 0x21 + 0x1E 0xF9 0x2C 0x2E 0x20 0x1A 0x2B 0x3E 0xFF + +: d1-study # "A leatherbound volume describing ancient torture techniques. Ghastly stuff." + 0xFE 0x00 0x0A 0x00 0xF9 0x25 0x1E 0x1A 0x2D 0x21 0x1E 0x2B 0x1B 0x28 0x2E 0x27 + 0x1D 0xF9 0x2F 0x28 0x25 0x2E 0x26 0x1E 0xFE 0x00 0x14 0x1D 0x1E 0x2C 0x1C 0x2B + 0x22 0x1B 0x22 0x27 0x20 0xF9 0x1A 0x27 0x1C 0x22 0x1E 0x27 0x2D 0xFE 0x00 0x1E + 0x2D 0x28 0x2B 0x2D 0x2E 0x2B 0x1E 0xF9 0x2D 0x1E 0x1C 0x21 0x27 0x22 0x2A 0x2E + 0x1E 0x2C 0x3E 0xFE 0x00 0x28 0x06 0x21 0x1A 0x2C 0x2D 0x25 0x32 0xF9 0x2C 0x2D + 0x2E 0x1F 0x1F 0x3E 0xFF +: d2-study # "Our host's beloved collection of mystery novels. Darkly ironic, given tonight's festivities." + 0xFE 0x00 0x03 0x0E 0x2E 0x2B 0xF9 0x21 0x28 0x2C 0x2D 0x42 0x2C 0xF9 0x1B 0x1E + 0x25 0x28 0x2F 0x1E 0x1D 0xFE 0x00 0x0D 0x1C 0x28 0x25 0x25 0x1E 0x1C 0x2D 0x22 + 0x28 0x27 0xF9 0x28 0x1F 0xF9 0x26 0x32 0x2C 0x2D 0x1E 0x2B 0x32 0xFE 0x00 0x17 + 0x27 0x28 0x2F 0x1E 0x25 0x2C 0x3E 0xFE 0x00 0x21 0x03 0x1A 0x2B 0x24 0x25 0x32 + 0xF9 0x22 0x2B 0x28 0x27 0x22 0x1C 0x41 0xF9 0x20 0x22 0x2F 0x1E 0x27 0xFE 0x00 + 0x2B 0x2D 0x21 0x1E 0xF9 0x1E 0x2F 0x1E 0x27 0x22 0x27 0x20 0x42 0x2C 0xFE 0x00 + 0x35 0x44 0x1F 0x1E 0x2C 0x2D 0x22 0x2F 0x22 0x2D 0x22 0x1E 0x2C 0x44 0x3E 0xFF + +: d1-conservatory # "Rain patters against the dark windowpanes." + 0xFE 0x00 0x07 0x11 0x1A 0x22 0x27 0xF9 0x29 0x1A 0x2D 0x2D 0x1E 0x2B 0x2C 0xF9 + 0x1A 0x20 0x1A 0x22 0x27 0x2C 0x2D 0xF9 0xFE 0x00 0x11 0x2D 0x21 0x1E 0xF9 0x1D + 0x1A 0x2B 0x24 0xF9 0x30 0x22 0x27 0x1D 0x28 0x30 0x29 0x1A 0x27 0x1E 0x2C 0x3E + 0xF9 0xFE 0x00 0x25 0x08 0x2D 0x42 0x2C 0xF9 0x2C 0x2D 0x22 0x25 0x25 0xF9 0x2C + 0x2D 0x28 0x2B 0x26 0x22 0x27 0x20 0xF9 0xFE 0x00 0x2F 0x21 0x1A 0x2B 0x1D 0xF9 + 0x28 0x2E 0x2D 0x2C 0x22 0x1D 0x1E 0x3E 0xFF +: d2-conservatory # "The loose soil in this pot suggests recent excavation." + 0xFE 0x03 0x11 0x13 0x21 0x1E 0xF9 0x25 0x28 0x28 0x2C 0x1E 0xF9 0x2C 0x28 0x22 + 0x25 0xF9 0x22 0x27 0xFE 0x03 0x1B 0x2D 0x21 0x22 0x2C 0xF9 0x29 0x28 0x2D 0xF9 + 0x2C 0x2E 0x20 0x20 0x1E 0x2C 0x2D 0x2C 0xFE 0x03 0x25 0x2B 0x1E 0x1C 0x1E 0x27 + 0x2D 0xF9 0x1E 0x31 0x1C 0x1A 0x2F 0x1A 0x2D 0x22 0x28 0x27 0x3E 0x3E 0x3E 0xFF + +: d1-kitchen # "A slew of recipe books. The master of the house was quite the gourmand." + 0xFE 0x03 0x0C 0x00 0xF9 0x2C 0x25 0x1E 0x30 0xF9 0x28 0x1F 0xF9 0x2B 0x1E 0x1C + 0x22 0x29 0x1E 0xFE 0x03 0x16 0x1B 0x28 0x28 0x24 0x2C 0x3E 0xF9 0x13 0x21 0x1E + 0xF9 0x26 0x1A 0x2C 0x2D 0x1E 0x2B 0xF9 0x28 0x1F 0xFE 0x03 0x20 0x2D 0x21 0x1E + 0xF9 0x21 0x28 0x2E 0x2C 0x1E 0xF9 0x30 0x1A 0x2C 0xF9 0x2A 0x2E 0x22 0x2D 0x1E + 0xFE 0x03 0x2A 0x2D 0x21 0x1E 0xF9 0x20 0x28 0x2E 0x2B 0x26 0x1A 0x27 0x1D 0x3E + 0x3E 0x3E 0xFF +: d2-kitchen # "The washbasin's faucet has a slow drip, which echoes through the room." + 0xFE 0x06 0x0C 0x13 0x21 0x1E 0xF9 0x30 0x1A 0x2C 0x21 0x1B 0x1A 0x2C 0x22 0x27 + 0x42 0x2C 0xFE 0x06 0x16 0x1F 0x1A 0x2E 0x1C 0x1E 0x2D 0xF9 0x21 0x1A 0x2C 0xF9 + 0x1A 0xF9 0x2C 0x25 0x28 0x30 0xFE 0x06 0x20 0x1D 0x2B 0x22 0x29 0x41 0xF9 0x30 + 0x21 0x22 0x1C 0x21 0xF9 0x1E 0x1C 0x21 0x28 0x1E 0x2C 0xFE 0x06 0x2A 0x2D 0x21 + 0x2B 0x28 0x2E 0x20 0x21 0xF9 0x2D 0x21 0x1E 0xF9 0x2B 0x28 0x28 0x26 0x3E 0xFF + +: d1-pantry # "There are enough tinned provisions on these shelves to feed a small army." + 0xFE 0x02 0x0C 0x13 0x21 0x1E 0x2B 0x1E 0xF9 0x1A 0x2B 0x1E 0xF9 0x1E 0x27 0x28 + 0x2E 0x20 0x21 0xFE 0x02 0x16 0x2D 0x22 0x27 0x27 0x1E 0x1D 0xF9 0x29 0x2B 0x28 + 0x2F 0x22 0x2C 0x22 0x28 0x27 0x2C 0xF9 0x28 0x27 0xFE 0x02 0x20 0x2D 0x21 0x1E + 0x2C 0x1E 0xF9 0x2C 0x21 0x1E 0x25 0x2F 0x1E 0x2C 0xF9 0x2D 0x28 0xFE 0x02 0x2A + 0x1F 0x1E 0x1E 0x1D 0xF9 0x1A 0xF9 0x2C 0x26 0x1A 0x25 0x25 0xF9 0x1A 0x2B 0x26 + 0x32 0x3E 0xFF +: d2-pantry # "Judging by color and odor, whatever is in these jars should stay there." + 0xFE 0x08 0x07 0x09 0x2E 0x1D 0x20 0x22 0x27 0x20 0xF9 0x1B 0x32 0xF9 0x1C 0x28 + 0x25 0x28 0x2B 0xF9 0xFE 0x08 0x11 0x1A 0x27 0x1D 0xF9 0x28 0x1D 0x28 0x2B 0x41 + 0xF9 0x30 0x21 0x1A 0x2D 0x1E 0x2F 0x1E 0x2B 0xF9 0xFE 0x08 0x1B 0x22 0x2C 0xF9 + 0x22 0x27 0xF9 0x2D 0x21 0x1E 0x2C 0x1E 0xF9 0x23 0x1A 0x2B 0x2C 0xF9 0xFE 0x08 + 0x25 0x2C 0x21 0x28 0x2E 0x25 0x1D 0xF9 0x2C 0x2D 0x1A 0x32 0xF9 0x2D 0x21 0x1E + 0x2B 0x1E 0xF9 0xFE 0x08 0x2F 0x22 0x27 0x1D 0x1E 0x1F 0x22 0x27 0x22 0x2D 0x1E + 0x25 0x32 0x3E 0xFF + +: d1-secret # "Cobwebbed boxes full of knick-knacks and bric-a-brac." + 0xFE 0x00 0x07 0x02 0x28 0x1B 0x30 0x1E 0x1B 0x1B 0x1E 0x1D 0xF9 0x1B 0x28 0x31 + 0x1E 0x2C 0xF9 0x1F 0x2E 0x25 0x25 0xFE 0x00 0x11 0x28 0x1F 0xF9 0x24 0x27 0x22 + 0x1C 0x24 0x43 0x24 0x27 0x1A 0x1C 0x24 0x2C 0x41 0xF9 0xFE 0x00 0x1B 0x1C 0x2E + 0x2B 0x22 0x28 0x2C 0x41 0xF9 0x28 0x1B 0x23 0x1E 0x2D 0xF9 0x1D 0x42 0x1A 0x2B + 0x2D 0x41 0xFE 0x00 0x25 0x1B 0x1A 0x2E 0x1B 0x25 0x1E 0x2C 0x41 0xF9 0x1C 0x2E + 0x2B 0x22 0x28 0x2C 0x22 0x2D 0x22 0x1E 0x2C 0x41 0xFE 0x00 0x2F 0x1A 0x27 0x1D + 0xF9 0x1B 0x2B 0x22 0x1C 0x43 0x1A 0x43 0x1B 0x2B 0x1A 0x1C 0x3E 0xFF +: d2-secret # "Scrapes in the dust suggest these boxes have been moved recently." + 0xFE 0x04 0x0C 0x12 0x1C 0x2B 0x1A 0x29 0x1E 0x2C 0xF9 0x22 0x27 0xF9 0x2D 0x21 + 0x1E 0xF9 0x1D 0x2E 0x2C 0x2D 0xFE 0x04 0x16 0x2C 0x2E 0x20 0x20 0x1E 0x2C 0x2D + 0xF9 0x2D 0x21 0x1E 0x2C 0x1E 0xF9 0x1B 0x28 0x31 0x1E 0x2C 0xFE 0x04 0x20 0x21 + 0x1A 0x2F 0x1E 0xF9 0x1B 0x1E 0x1E 0x27 0xF9 0x26 0x28 0x2F 0x1E 0x1D 0xFE 0x04 + 0x2A 0x2B 0x1E 0x1C 0x1E 0x27 0x2D 0x25 0x32 0x3E 0x3E 0x3E 0xFF + +: secret-passage-entrance + 0xFE 0x04 0x02 0x16 0x21 0x1A 0x2D 0x42 0x2C 0xF9 0x2D 0x21 0x22 0x2C 0x40 0xFE + 0x04 0x0C 0x00 0xF9 0x1C 0x28 0x27 0x1C 0x1E 0x1A 0x25 0x1E 0x1D 0xF9 0x1D 0x28 + 0x28 0x2B 0xF9 0x22 0x2C 0xFE 0x04 0x16 0x2C 0x25 0x22 0x20 0x21 0x2D 0x25 0x32 + 0xF9 0x1A 0x23 0x1A 0x2B 0x3F 0xFE 0x04 0x20 0x12 0x2D 0x1E 0x29 0xF9 0x22 0x27 + 0x2C 0x22 0x1D 0x1E 0x40 0xFF +: secret-room-entrance + 0xFE 0x00 0x02 0x04 0x2E 0x2B 0x1E 0x24 0x1A 0x3F 0xF9 0x00 0xF9 0x2D 0x2B 0x1A + 0x29 0xF9 0x1D 0x28 0x28 0x2B 0xFE 0x00 0x0C 0x22 0x2C 0xF9 0x21 0x22 0x1D 0x1D + 0x1E 0x27 0xF9 0x22 0x27 0xF9 0x2D 0x21 0x1E 0xFE 0x00 0x16 0x1F 0x25 0x28 0x28 + 0x2B 0xF9 0x21 0x1E 0x2B 0x1E 0x3F 0xFE 0x00 0x20 0x12 0x21 0x28 0x2E 0x25 0x1D + 0xF9 0x08 0xF9 0x22 0x27 0x2F 0x1E 0x2C 0x2D 0x22 0x20 0x1A 0x2D 0x1E 0x40 0xFF +: how-did-i-get-here + 0xFE 0x08 0x14 0x07 0x28 0x30 0xF9 0x28 0x27 0xF9 0x1E 0x1A 0x2B 0x2D 0x21 0xFE + 0x08 0x1E 0x1D 0x22 0x1D 0xF9 0x08 0xF9 0x1E 0x27 0x1D 0xF9 0x2E 0x29 0xF9 0x21 + 0x1E 0x2B 0x1E 0x40 0xFF + +: room-deco-table + pointer d1-library + pointer d2-library + pointer d1-bathroom + pointer d2-bathroom + pointer d1-bedroom + pointer d2-bedroom + pointer d1-drawing-room + pointer d2-drawing-room + pointer d1-parlor + pointer d2-parlor + pointer d1-dining-room + pointer d2-dining-room + pointer d1-study + pointer d2-study + pointer d1-conservatory + pointer d2-conservatory + pointer d1-kitchen + pointer d2-kitchen + pointer d1-pantry + pointer d2-pantry + pointer d1-secret + pointer d2-secret + +: secret-room-player-pos-stash + 0x00 0x00 + +to-code + +: describe-deco + # pass the decoration index {0,1} in v2. + thicken-plot SUSPICION_EXAMINE_DECO + clear + if v2 == 0 begin + i := long has-passage-room + load v0 + if v0 == current-room begin + print secret-passage-entrance + dialog-yes-no + if v2 == 0 then return + i := long has-body-room + load v0 + current-room := v0 + + # gotta unpack the player's + # start position for the new room: + dialog-fill-screen + plane 0 + draw-room + i := long room-stash-start + load player-x - player-y + plane 1 + + wait 60 + clear + print how-did-i-get-here + dialog-pause + jump draw-room-title + end + else + i := long has-secret-room + load v0 + if v0 == current-room begin + print secret-room-entrance + dialog-yes-no + if v2 == 0 then return + i := long secret-room-player-pos-stash + save player-x - player-y + current-room := 10 + room + i := long has-secret-room + load v0 + i := long secret-room-player-pos-stash + load player-x - player-y + current-room := v0 + jump draw-room-title + end + end + i := long room-deco-table + v0 := current-room + v0 <<= v0 + v0 <<= v0 + v0 += v2 + v0 += v2 + i += v0 + load v1 + print-text + jump dialog-pause + +########################################### +# +# Rooms +# +########################################### + +:const TILE_EMPTY 0x00 +:const TILE_SOLID 0x08 +:const TILE_EXIT_UP 0xA0 +:const TILE_EXIT_RT 0xA8 +:const TILE_EXIT_DN 0xB0 +:const TILE_EXIT_LF 0xB8 +:const TILE_NPC_1 0xC0 +:const TILE_NPC_2 0xC8 +:const TILE_DECO_1 0xD0 +:const TILE_DECO_2 0xD8 +:const TILE_START 0xE0 +:const TILE_BODY 0xE8 +:const TILE_ITEM 0xF0 +:const TILE_QUESTION 0xF8 + +to-data + +: player-left-0 0x38 0x7C 0x3C 0x3C 0x1E 0x3C 0x3C 0x1C 0x18 0x3C 0x3C 0x3C 0x1C 0x08 0x08 +: player-left-1 0x00 0x38 0x7C 0x3C 0x3C 0x1E 0x3C 0x3C 0x1C 0x38 0x3C 0x3C 0x1E 0x24 0x24 +: player-right-0 mirror-8x15 player-left-0 +: player-right-1 mirror-8x15 player-left-1 + +: tileset # 8x8 tiles + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0x95 0x95 0x95 0xFF 0x51 0x51 0xFF 0xFF + 0x00 0x7E 0x00 0x7A 0x7A 0x7E 0x00 0x00 + 0xD5 0x00 0xDD 0x10 0xC0 0x10 0xC0 0x00 + 0x55 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x56 0x00 0x06 0x00 0x06 0x00 0x06 0x00 + 0x00 0x44 0x50 0x14 0x42 0x54 0x3C 0x08 + 0xC0 0x00 0xC0 0x00 0xC0 0x00 0xD5 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x55 0x00 + 0x06 0x00 0x06 0x10 0x36 0x00 0x56 0x00 + 0xFF 0xFF 0x81 0x00 0x00 0x81 0xFF 0xDB + 0xFF 0xFF 0x80 0xBF 0xA0 0xA0 0xE0 0x00 + 0xFF 0xFF 0x01 0xFD 0x05 0x05 0x07 0x00 + 0xE0 0xE0 0xE0 0xE0 0xFE 0xFE 0xFE 0x00 + 0x07 0x07 0x07 0x07 0x7F 0x7F 0x7F 0x00 + 0x7E 0x7E 0x42 0x42 0x42 0x00 0x00 0x00 + 0xFF 0xFF 0x00 0xFF 0x00 0x00 0x00 0x00 + 0xFF 0x83 0xBB 0xB9 0xB9 0x81 0xE1 0xFF + 0x40 0x08 0x00 0x88 0x02 0x00 0x10 0x00 + 0x00 0x18 0x3C 0x7E 0x18 0x18 0x18 0x00 + 0x00 0x08 0x0C 0x7E 0x7E 0x0C 0x08 0x00 + 0x00 0x18 0x18 0x18 0x7E 0x3C 0x18 0x00 + 0x00 0x10 0x30 0x7E 0x7E 0x30 0x10 0x00 + 0x00 0x74 0x54 0x54 0x74 0x44 0x44 0x00 + 0x00 0x76 0x52 0x56 0x74 0x44 0x46 0x00 + 0x00 0x64 0x54 0x54 0x54 0x54 0x64 0x00 + 0x00 0x66 0x52 0x56 0x54 0x54 0x66 0x00 + 0x00 0x3E 0x40 0x7E 0x02 0x02 0x7C 0x00 + 0x00 0x7C 0x42 0x7C 0x42 0x42 0x7C 0x00 + 0x00 0x7E 0x08 0x08 0x08 0x08 0x7E 0x00 + 0x3C 0x7E 0x66 0x0E 0x1C 0x18 0x00 0x18 + +: map-library + 0x08 0x38 0x00 0x00 0x00 0x00 0x98 0x00 + 0x08 0x00 0x00 0x98 0x00 0x38 0x00 0x00 + 0x08 0x38 0x00 0x00 0x00 0x00 0x98 0x00 + 0x08 0x38 0x38 0x38 0x00 0x38 0x38 0x38 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x10 0x00 0x00 0x00 0x00 0x10 0x08 + 0x08 0x10 0xF0 0x00 0x00 0xD0 0x10 0x08 + 0x08 0x10 0x00 0x00 0x00 0x00 0x10 0x08 + 0x08 0xC8 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x10 0x00 0x00 0x00 0x00 0x10 0x08 + 0x08 0x10 0xE8 0x00 0x00 0xD8 0x10 0x08 + 0x08 0x10 0x00 0x00 0x00 0x00 0x10 0x08 + 0x08 0x10 0x00 0x00 0xE0 0x00 0x10 0x08 + 0x08 0xC0 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x08 0x08 0x08 0x08 0xA8 0x08 0x08 + +: map-bathroom + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x98 0x98 0x98 0x98 0x98 0x20 0x08 + 0x08 0x98 0x98 0x98 0x98 0x98 0x30 0x08 + 0x08 0x00 0xD8 0x20 0x40 0x00 0x00 0x08 + 0x08 0x00 0x00 0x30 0x50 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0xC0 0x00 0x08 + 0x08 0x08 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x58 0xF0 0x00 0x00 0x00 0x00 0x08 + 0x08 0x08 0x00 0x00 0x00 0xE8 0x00 0x08 + 0x08 0xC8 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0xE0 0x00 0x00 0xD0 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x18 0x08 + 0x08 0x08 0x08 0xA8 0x08 0x08 0x08 0x08 + +: map-bedroom + 0x08 0x08 0x08 0xB8 0x08 0x08 0x08 0x08 + 0x08 0x00 0x00 0x00 0x00 0x70 0x80 0x08 + 0x08 0xC0 0x00 0x00 0x00 0xF0 0x00 0x08 + 0x08 0x90 0x60 0xD8 0x00 0x00 0x00 0x08 + 0x08 0x08 0x68 0x00 0x00 0xC8 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0xE0 0x00 0xB0 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0xD0 0x00 0x00 0x00 0x00 0x08 + 0x08 0x08 0x20 0x20 0x60 0x00 0x00 0x08 + 0x08 0x08 0x28 0x28 0x88 0x00 0x00 0x08 + 0x08 0x08 0x50 0x30 0x68 0xE8 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + +: map-drawing-room + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x00 0x70 0x80 0x00 0xE8 0x00 0x08 + 0x08 0xC0 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x08 0x60 0x00 0x00 0x00 0x90 0x08 + 0x08 0x90 0x88 0xD0 0x00 0x00 0x08 0x08 + 0x08 0x08 0x68 0x00 0x00 0x00 0x08 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0xE0 0x00 0xB0 + 0x08 0x90 0x60 0x00 0x00 0x00 0x00 0x08 + 0x08 0x90 0x88 0xF0 0x00 0x00 0x00 0x08 + 0x08 0x08 0x68 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0xD8 0x00 0xC8 0x00 0x08 + 0x08 0x00 0x08 0x90 0x60 0x78 0x80 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + +: map-parlor + 0x00 0x38 0x00 0x00 0x00 0x98 0x00 0x38 + 0x00 0x00 0x00 0x00 0x38 0x00 0x00 0x00 + 0x00 0x98 0x00 0x00 0x00 0x00 0x00 0x98 + 0x38 0x38 0x38 0x00 0x98 0x38 0x38 0x38 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x70 0x80 0xC0 0x00 0x00 0x00 0x08 + 0x08 0xD8 0x00 0x00 0x00 0x00 0xD0 0x08 + 0x08 0x78 0x80 0x00 0x00 0x90 0x60 0x08 + 0x08 0x00 0x00 0x00 0x00 0x08 0x68 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0xF0 0x08 + 0x08 0x00 0xE8 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0xE0 0x00 0x00 0xC8 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x08 0xA8 0x08 0x08 0x08 0x08 0x08 + +: map-dining-room + 0x08 0xB8 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x00 0x00 0x00 0x00 0x70 0x80 0x08 + 0x08 0x00 0xE0 0x00 0x00 0x00 0xF0 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0xC8 0x00 0xD0 0x00 0x00 0x00 0x08 + 0x08 0x00 0x70 0x70 0x70 0x80 0x00 0x08 + 0x08 0x00 0x58 0x08 0x08 0x60 0x00 0x08 + 0x08 0x00 0x08 0x08 0x58 0x68 0x00 0x08 + 0x08 0x00 0x78 0x78 0x78 0x80 0x00 0x08 + 0x08 0x00 0x00 0xC0 0x00 0x00 0x00 0x08 + 0x08 0xE8 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0xD8 0x00 0x00 0x00 0x08 + 0x08 0x00 0x08 0x58 0x60 0x00 0x00 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0xA8 0x08 + +: map-study + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x10 0x00 0x10 0x10 0x10 0x10 0x08 + 0x08 0x10 0xC0 0x00 0xD0 0x00 0x00 0x08 + 0x08 0x10 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x10 0x00 0x00 0x70 0x80 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0xA0 0x00 0x00 0xE0 0x00 0x00 0x20 0x08 + 0x08 0xE8 0x00 0x00 0x00 0xF0 0x30 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x10 0x00 0x00 0x78 0x80 0x00 0x08 + 0x08 0x10 0xD8 0x00 0x00 0x00 0x00 0x08 + 0x08 0x10 0x00 0x00 0x00 0xC8 0x00 0x08 + 0x08 0x10 0x00 0x10 0x10 0x10 0x10 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + +: map-conservatory + 0x08 0x08 0x08 0x08 0xB8 0x08 0x08 0x08 + 0x08 0xC0 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0xE0 0x00 0x00 0x08 + 0x88 0x00 0x38 0x18 0x00 0x38 0x18 0x08 + 0x88 0x00 0x38 0x18 0x00 0x00 0x00 0x08 + 0x88 0xD0 0x00 0x00 0x00 0x00 0x00 0x08 + 0x88 0x00 0x00 0x00 0x00 0x38 0x18 0x08 + 0x08 0x00 0x38 0x18 0x00 0xD8 0x18 0x08 + 0x08 0x00 0x38 0x18 0x00 0x00 0x00 0x08 + 0x88 0xE8 0x00 0x00 0x00 0x38 0x18 0x08 + 0x88 0x00 0x00 0x00 0x00 0x38 0x18 0x08 + 0x88 0x00 0x00 0x98 0x00 0x00 0x00 0x08 + 0x88 0x00 0xF0 0x18 0x00 0xC8 0x00 0x08 + 0x08 0x00 0x38 0x18 0x00 0x38 0x18 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + +: map-kitchen + 0x08 0x08 0x08 0x08 0xB8 0x08 0x08 0x08 + 0x08 0x10 0x00 0x00 0x00 0x00 0x10 0x08 + 0x08 0x10 0xD0 0x00 0xE0 0x00 0x10 0x08 + 0x08 0x08 0x60 0x00 0x00 0x00 0x00 0x08 + 0x08 0x08 0x88 0x00 0x00 0xE8 0x00 0x08 + 0x08 0x08 0x88 0x00 0x00 0x00 0x00 0x08 + 0x08 0x08 0x68 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0xC0 0x00 0x00 0x00 0x00 0x08 + 0x08 0x08 0x60 0x00 0x00 0xC8 0x00 0x08 + 0x08 0x58 0x88 0x00 0x00 0x00 0x00 0x08 + 0x08 0x58 0x88 0xD8 0x00 0x00 0x00 0xB0 + 0x08 0x08 0x68 0x00 0x00 0x00 0x00 0x08 + 0x08 0x10 0x08 0x00 0x00 0x00 0x00 0x08 + 0x08 0x10 0x08 0x00 0x00 0x00 0x38 0x08 + 0x08 0x10 0x10 0x60 0x00 0xF0 0x38 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + +: map-pantry + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x00 0x00 0xC0 0x00 0x00 0x18 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0xF0 0x08 + 0x08 0x18 0x18 0x00 0x00 0x00 0x00 0x08 + 0x08 0x90 0x08 0x80 0x00 0x08 0x90 0x08 + 0x08 0x00 0xD0 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x08 0x80 0x00 0x00 0x08 0x08 0x08 + 0x08 0x00 0x00 0x00 0x00 0xC8 0x00 0x08 + 0xA0 0x00 0xE0 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0xE8 0x00 0x08 0x80 0xD8 0x18 0x08 + 0x08 0x00 0x00 0x08 0x80 0x00 0x18 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + +: map-secret + # note: no NPCs or body! + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x18 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x18 0xD0 0x00 0x00 0x00 0x00 0x08 + 0x08 0x98 0x00 0x00 0x00 0xE0 0x00 0xB0 + 0x08 0x18 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x98 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x98 0x08 + 0x08 0x98 0xF0 0x00 0x00 0xD8 0x18 0x08 + 0x08 0x98 0x98 0x00 0x98 0x18 0x18 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + +: map-dining-room-alt + # no NPCs or special tiles except start. + 0x08 0xB8 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x00 0x00 0x00 0x00 0x70 0x80 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0xE0 0x00 0x08 + 0x08 0x00 0x70 0x70 0x70 0x80 0x00 0x08 + 0x08 0x00 0x08 0x08 0x08 0x60 0x00 0x08 + 0x08 0x00 0x08 0x08 0x08 0x68 0x00 0x08 + 0x08 0x00 0x78 0x78 0x78 0x80 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x08 + 0x08 0x00 0x08 0x58 0x60 0x00 0x00 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0xA8 0x08 + +: room-map-table + pointer map-library + pointer map-bathroom + pointer map-bedroom + pointer map-drawing-room + pointer map-parlor + pointer map-dining-room + pointer map-study + pointer map-conservatory + pointer map-kitchen + pointer map-pantry + pointer map-secret + pointer map-dining-room-alt + +: title-library 0xFE 0x24 0x18 0xFC 0x0B 0x22 0x1B 0x2B 0x1A 0x2B 0x32 0xFF +: title-bathroom 0xFE 0x21 0x18 0xFC 0x01 0x1A 0x2D 0x21 0x2B 0x28 0x28 0x26 0xFF +: title-bedroom 0xFE 0x25 0x18 0xFC 0x01 0x1E 0x1D 0x2B 0x28 0x28 0x26 0xFF +: title-drawing-room 0xFE 0x12 0x18 0xFC 0x03 0x2B 0x1A 0x30 0x22 0x27 0x20 0xF9 0x11 0x28 0x28 0x26 0xFF +: title-parlor 0xFE 0x29 0x18 0xFC 0x0F 0x1A 0x2B 0x25 0x28 0x2B 0xFF +: title-dining-room 0xFE 0x15 0x18 0xFC 0x03 0x22 0x27 0x22 0x27 0x20 0xF9 0x11 0x28 0x28 0x26 0xFF +: title-study 0xFE 0x2B 0x18 0xFC 0x12 0x2D 0x2E 0x1D 0x32 0xFF +: title-conservatory 0xFE 0x11 0x18 0xFC 0x02 0x28 0x27 0x2C 0x1E 0x2B 0x2F 0x1A 0x2D 0x28 0x2B 0x32 0xFF +: title-kitchen 0xFE 0x25 0x18 0xFC 0x0A 0x22 0x2D 0x1C 0x21 0x1E 0x27 0xFF +: title-pantry 0xFE 0x28 0x18 0xFC 0x0F 0x1A 0x27 0x2D 0x2B 0x32 0xFF +: title-secret-room 0xFE 0x14 0x18 0xFC 0x12 0x1E 0x1C 0x2B 0x1E 0x2D 0xF9 0x11 0x28 0x28 0x26 0xFF +: title-secret-passage 0xFE 0x08 0x18 0xFC 0x12 0x1E 0x1C 0x2B 0x1E 0x2D 0xF9 0x0F 0x1A 0x2C 0x2C 0x1A 0x20 0x1E 0xFF + +: room-title-table + pointer title-library + pointer title-bathroom + pointer title-bedroom + pointer title-drawing-room + pointer title-parlor + pointer title-dining-room + pointer title-study + pointer title-conservatory + pointer title-kitchen + pointer title-pantry + pointer title-secret-room + pointer title-secret-passage + +: special-room-exits + # -1 just dumps you to the main map + # UP, RT, DN, LF to match TILE_EXIT indices + -1 -1 -1 -1 # 0 library + -1 2 -1 -1 # 1 bathroom + -1 -1 -1 1 # 2 bedroom + -1 -1 -1 -1 # 3 drawing-room + -1 -1 -1 -1 # 4 parlor + -1 -1 -1 -1 # 5 dining-room 5 + -1 -1 -1 -1 # 6 study + -1 -1 -1 -1 # 7 conservatory + -1 -1 9 -1 # 8 kitchen + 8 -1 -1 -1 # 9 pantry + -1 -1 -1 -1 # 10 secret-room + +: room-stash + 0 0 # exit-N + 0 0 # exit E + 0 0 # exit S + 0 0 # exit W +: room-stash-points-of-interest + 0 0 # npc 1 + 0 0 # npc 2 + 0 0 # deco 1 + 0 0 # deco 2 +: room-stash-start 0 0 # start + 0 0 # body + 0 0 # item + +: blink-masks +: blink-npc 0x7E 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x7E +: blink-item 0x92 0x44 0x00 0x82 0x00 0x44 0x92 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +: blink-body 0x00 0x70 0x78 0x38 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +: blink-table 0 0 15 15 -1 30 15 + +to-code + +:macro abs-diff A B RESULT { + if A < B begin + RESULT := B + RESULT -= A + else + RESULT := A + RESULT -= B + end +} + +: room-poi-find + # grab coords of the current object: + i := long room-stash-points-of-interest + i += v4 + i += v4 + load v1 + + # calculate ABS of manhattan distance to object: + prev-x := player-x + prev-y := player-y + if v4 >= 2 begin + # adjust player hitbox to the feet + # for anything but NPC positions: + prev-x += 4 + prev-y += 8 + end + abs-diff v0 prev-x v2 + abs-diff v1 prev-y v3 + v3 += v2 + + # ignore NPCs that aren't in the room. + i := long npc-positions + i += current-room + i += current-room + i += v4 + load v2 - v2 + if v4 == 0 begin + if v2 == -1 then v3 := 0xFF + end + if v4 == 1 begin + if v2 == -1 then v3 := 0xFF + end + + # ignore body if it's not in this room. + if v4 == 5 begin + i := long has-body-room + load v2 - v2 + if v2 != current-room then v3 := 0xFF + end + + # ignore item if it's not here. + if v4 == 6 begin + i := long item-positions + i += current-room + load v2 - v2 + if v2 == -1 then v3 := 0xFF + end +; + +: room-poi-walk + # first pass: if objects are close enough, + # just activate them directly. + v4 := 0 + loop + room-poi-find + + if v3 < 10 begin + if v4 == 0 begin + i := long npc-positions + : room-npc + i += current-room + i += current-room + load v2 - v2 + describe-npc + jump poi-done + end + if v4 == 1 begin + :calc npc-slot-2 { npc-positions + 1 } + i := long npc-slot-2 + jump room-npc + end + if v4 == 2 begin v2 := 0 describe-deco jump poi-done end + if v4 == 3 begin v2 := 1 describe-deco jump poi-done end + if v4 == 5 begin describe-body jump poi-done end + if v4 == 6 begin + i := long item-positions + i += current-room + load v2 - v2 + describe-item + end + : poi-done + if current-room == GAME_OVER then return + draw-room + ve := 0 + jump draw-player + end + + v4 += 1 + if v4 == 4 then v4 += 1 # skip over start position + if v4 != 7 then + again + + # second pass: if objects are near-ish, + # blink them. + v4 := 0 + loop + room-poi-find + + # if the object is further, blink it. + if v3 < 40 begin + i := long blink-table + i += v4 + load v2 - v2 + i := long blink-masks + i += v2 + v2 := 6 + loop + sprite v0 v1 15 + wait 5 + v2 += -1 + if v2 != 0 then + again + end + + v4 += 1 + if v4 == 4 then v4 += 1 # skip over start position + if v4 != 7 then + again +; + +: room-load indirect room-write ; + +: room-draw-npc + i += current-room + i += current-room + load v4 - v4 + if v4 == -1 then return # no npc here + i := long npc-sprites + v4 <<= v4 # * 2 + v4 <<= v4 # * 4 + v4 <<= v4 # * 8 + v4 <<= v4 # * 16 + i += v4 + sprite v1 v2 15 +; + +: room-unpack + if v0 == TILE_BODY begin + i := long has-body-room + load v4 - v4 + if v4 == current-room begin + i := long body-sprite + sprite v1 v2 0 + end + end + if v0 == TILE_NPC_1 begin + i := long npc-positions + room-draw-npc + end + if v0 == TILE_NPC_2 begin + :calc second-slot { npc-positions + 1 } + i := long second-slot + room-draw-npc + end + + # in the general case, all we want to do + # is store the x/y coords of the item + # in a convenient lookup table for later: + i := long room-stash + :calc special-tile-offset { 0xFF & - TILE_EXIT_UP } + v0 += special-tile-offset + v0 >>= v0 # v0 had stride 8... + v0 >>= v0 # v0 now has stride 2 + i += v0 + save v1 - v2 + v0 := TILE_EMPTY +; + +: draw-player + # pass frame offset { 0, 15 } in ve... + i := long player-left-0 + if player-face == 1 then i := long player-right-0 + i += ve + sprite player-x player-y 15 +; + +: draw-room-title + dialog-fill-screen + print-from-table current-room room-title-table + wait 60 + clear +; + +: draw-room + i := long room-map-table + i += current-room + i += current-room + load v1 + i := room-write + save v1 + + v1 := 0 # x + v2 := 0 # y + v3 := 0 # index + loop + room-load + i += v3 + load v0 + + if v0 >= TILE_NPC_1 then room-unpack + i := long tileset + i += v0 + sprite v1 v2 8 + + v3 += 1 + v2 += 8 + if v2 == 64 then v1 += 8 + if v2 == 64 then v2 := 0 + if v1 != 128 then + again +; + +: room + draw-room-title + draw-room + + # the murderer is stalking the player! + i := long interstitial-progress + load v0 + if v0 == 2 begin + i := long npc-positions + i += current-room + i += current-room + load v1 + i := long npc-murderer + load v2 - v2 + # kill the player if they're alone + # with a stalker murderer... + if v2 == v0 begin + if v1 == -1 then murder-player + if current-room == GAME_OVER then return + end + if v2 == v1 begin + if v1 == -1 then murder-player + if current-room == GAME_OVER then return + end + end + + # walk/explore mode: + player-face := 0 + i := long room-stash-start + load player-x - player-y + ve := 0 + draw-player + + loop + ve := 0 + draw-player + prev-x := player-x + prev-y := player-y + vf := OCTO_KEY_D if vf key begin player-x += 4 player-face := 1 end + vf := OCTO_KEY_A if vf key begin player-x += -4 player-face := 0 end + vf := OCTO_KEY_S if vf key then player-y += 4 + vf := OCTO_KEY_W if vf key then player-y += -4 + + room-load + # index at feet is: + # (py+8)/8 + (px/8)*8 + v0 := player-y + v0 += 8 + v0 >>= v0 + v0 >>= v0 + v0 >>= v0 + i += v0 + v0 := player-x + vf := 0b11111000 + v0 &= vf + i += v0 + load v0 + + if v0 == 0x88 then v0 := TILE_SOLID # (conservatory north windows) + if v0 == TILE_SOLID begin + player-x := prev-x + player-y := prev-y + end + + while v0 != TILE_EXIT_UP + while v0 != TILE_EXIT_DN + while v0 != TILE_EXIT_LF + while v0 != TILE_EXIT_RT + + if player-x != prev-x begin + # step animation: + player-x := prev-x + if player-face == 1 then player-x += 2 + if player-face == 0 then player-x += -2 + ve := 15 + draw-player + wait 2 + draw-player + if player-face == 1 then player-x += 2 + if player-face == 0 then player-x += -2 + end + + ve := 0 + draw-player + + vf := OCTO_KEY_E if vf key then room-poi-walk + if current-room == GAME_OVER then return + + sync + again + clear + + i := long special-room-exits + i += current-room # stride 4... + i += current-room + i += current-room + i += current-room + :calc exit-offset { 0xFF & - TILE_EXIT_UP } + v0 += exit-offset + v0 >>= v0 # stride 8 -> stride 4 + v0 >>= v0 # stride 4 -> stride 2 + v0 >>= v0 # stride 2 -> stride 1 + i += v0 + load v0 + if v0 != -1 begin + current-room := v0 + jump room + end + + # a brief pause before returning + # to the main map helps debounce + # held down keypresses: + wait 10 +; + +########################################### +# +# Interstitials +# +########################################### + +to-data + +: growing-suspicious + 0xFE 0x00 0x11 0xFD 0x13 0x21 0x1E 0xF9 0x26 0x2E 0x2B 0x1D 0x1E 0x2B 0x1E 0x2B + 0xF9 0x22 0x2C 0xFE 0x00 0x1B 0x20 0x2B 0x28 0x30 0x22 0x27 0x20 0xF9 0x2C 0x2E + 0x2C 0x29 0x22 0x1C 0x22 0x28 0x2E 0x2C 0xFE 0x00 0x25 0x28 0x1F 0xF9 0x2D 0x21 + 0x1E 0xF9 0x22 0x27 0x2F 0x1E 0x2C 0x2D 0x22 0x20 0x1A 0x2D 0x22 0x28 0x27 0x3E + 0xFF +: begun-stalking + 0xFE 0x06 0x17 0xFD 0x13 0x21 0x1E 0xF9 0x26 0x2E 0x2B 0x1D 0x1E 0x2B 0x1E 0x2B + 0xF9 0x21 0x1A 0x2C 0xFE 0x06 0x21 0x1B 0x1E 0x20 0x2E 0x27 0xF9 0x2C 0x2D 0x1A + 0x25 0x24 0x22 0x27 0x20 0xF9 0x32 0x28 0x2E 0x3F 0xFF +: footsteps-in-distance + 0xFE 0x07 0x10 0x18 0x28 0x2E 0xF9 0x21 0x1E 0x1A 0x2B 0xF9 0x1F 0x28 0x28 0x2D + 0x2C 0x2D 0x1E 0x29 0x2C 0xFE 0x07 0x1A 0x2C 0x28 0x26 0x1E 0x30 0x21 0x1E 0x2B + 0x1E 0xF9 0x22 0x27 0xF9 0x2D 0x21 0x1E 0xFE 0x07 0x24 0x1D 0x22 0x2C 0x2D 0x1A + 0x27 0x1C 0x1E 0x3E 0x3E 0x3E 0xFF + +: notice-0 # Thunder rumbles in the distance. + 0xFE 0x06 0x17 0x13 0x21 0x2E 0x27 0x1D 0x1E 0x2B 0xF9 0x2B 0x2E 0x26 0x1B 0x25 + 0x1E 0x2C 0xF9 0x22 0x27 0xFE 0x06 0x21 0x2D 0x21 0x1E 0xF9 0x1D 0x22 0x2C 0x2D + 0x1A 0x27 0x1C 0x1E 0x3E 0x3E 0x3E 0xFF +: notice-1 # You feel as though you're being watched. + 0xFE 0x14 0x13 0x18 0x28 0x2E 0xF9 0x1F 0x1E 0x1E 0x25 0xF9 0x1A 0x2C 0xFE 0x14 + 0x1D 0x2D 0x21 0x28 0x2E 0x20 0x21 0xF9 0x32 0x28 0x2E 0x42 0x2B 0x1E 0xFE 0x14 + 0x27 0x1B 0x1E 0x22 0x27 0x20 0xF9 0x30 0x1A 0x2D 0x1C 0x21 0x1E 0x1D 0x3E 0xFF +: notice-2 # You feel a sudden chill. + 0xFE 0x17 0x16 0x18 0x28 0x2E 0xF9 0x1F 0x1E 0x1E 0x25 0xF9 0x1A 0xFE 0x17 0x20 + 0x2C 0x2E 0x1D 0x1D 0x1E 0x27 0xF9 0x1C 0x21 0x22 0x25 0x25 0x3E 0xFF +: notice-3 # The door slams loudly behind you. + 0xFE 0x08 0x16 0x13 0x21 0x1E 0xF9 0x1D 0x28 0x28 0x2B 0xF9 0x2C 0x25 0x1A 0x26 + 0x2C 0xFE 0x08 0x20 0x25 0x28 0x2E 0x1D 0x25 0x32 0xF9 0x1B 0x1E 0x21 0x22 0x27 + 0x1D 0xF9 0x32 0x28 0x2E 0x3E 0xFF +: notice-4 # The lights overhead flicker momentarily. + 0xFE 0x03 0x18 0x13 0x21 0x1E 0xF9 0x25 0x22 0x20 0x21 0x2D 0x2C 0xF9 0x28 0x2F + 0x1E 0x2B 0x21 0x1E 0x1A 0x1D 0xFE 0x03 0x22 0x1F 0x25 0x22 0x1C 0x24 0x1E 0x2B + 0xF9 0x26 0x28 0x26 0x1E 0x27 0x2D 0x1A 0x2B 0x22 0x25 0x32 0x3E 0xFF +: notice-5 # You shakily wipe a bead of sweat from your brow. This case is getting to you. + 0xFE 0x03 0x0D 0x18 0x28 0x2E 0xF9 0x2C 0x21 0x1A 0x24 0x22 0x25 0x32 0xF9 0x30 + 0x22 0x29 0x1E 0xF9 0x1A 0xFE 0x03 0x17 0x1B 0x1E 0x1A 0x1D 0xF9 0x28 0x1F 0xF9 + 0x2C 0x30 0x1E 0x1A 0x2D 0xF9 0x1F 0x2B 0x28 0x26 0xFE 0x03 0x21 0x32 0x28 0x2E + 0x2B 0xF9 0x1B 0x2B 0x28 0x30 0x3E 0xF9 0x13 0x21 0x22 0x2C 0xF9 0x1C 0x1A 0x2C + 0x1E 0xFE 0x03 0x2B 0x22 0x2C 0xF9 0x20 0x1E 0x2D 0x2D 0x22 0x27 0x20 0xF9 0x2D + 0x28 0xF9 0x32 0x28 0x2E 0x3E 0xFF +: notice-6 # Lightning cracks, flooding the nearby windows with light. + 0xFE 0x05 0x11 0x0B 0x22 0x20 0x21 0x2D 0x27 0x22 0x27 0x20 0xF9 0x1C 0x2B 0x1A + 0x1C 0x24 0x2C 0x41 0xFE 0x05 0x1B 0x1F 0x25 0x28 0x28 0x1D 0x22 0x27 0x20 0xF9 + 0x2D 0x21 0x1E 0xF9 0x27 0x1E 0x1A 0x2B 0x1B 0x32 0xFE 0x05 0x25 0x30 0x22 0x27 + 0x1D 0x28 0x30 0x2C 0xF9 0x30 0x22 0x2D 0x21 0xF9 0x25 0x22 0x20 0x21 0x2D 0x3E + 0xFF +: notice-7 # The floorboards creak loudly under your feet. + 0xFE 0x09 0x13 0x13 0x21 0x1E 0xF9 0x1F 0x25 0x28 0x28 0x2B 0x1B 0x28 0x1A 0x2B + 0x1D 0x2C 0xFE 0x09 0x1D 0x1C 0x2B 0x1E 0x1A 0x24 0xF9 0x25 0x28 0x2E 0x1D 0x25 + 0x32 0xF9 0x2E 0x27 0x1D 0x1E 0x2B 0xFE 0x09 0x27 0x32 0x28 0x2E 0x2B 0xF9 0x1F + 0x1E 0x1E 0x2D 0x3E 0xFF + +: interstitial-notice-table + pointer notice-0 + pointer notice-1 + pointer notice-2 + pointer notice-3 + pointer notice-4 + pointer notice-5 + pointer notice-6 + pointer notice-7 + +: interstitial-progress 0x00 + +to-code + +: move-npcs + v1 := 9 random-upto-v1 # source room in v0. + v1 := random 1 # source slot in v1. + + # make sure we have a source NPC. + i := long npc-positions + i += v0 + i += v0 + i += v1 + load v2 - v2 + if v2 == -1 then return + + # find an adjacent, distinct room. + i := long room-nav + i += v0 + i += v0 + i += v0 + i += v0 + v2 := random 0b11 + i += v2 + load v2 - v2 + if v2 == v0 then return # dest room in v2. + + # make sure we have an empty destination. + v3 := 0 + i := long npc-positions + i += v2 + i += v2 + load v4 - v4 + if v4 != -1 then v3 := 1 + i += v3 + load v4 - v4 + if v4 != -1 then return + # dest slot is in v3. + + # remove NPC from source slot + i := long npc-positions + i += v0 + i += v0 + i += v1 + load v4 - v4 # npc id is in v4. + vf := -1 + save vf - vf + + # place NPC in destination slot + i := long npc-positions + i += v2 + i += v2 + i += v3 + save v4 - v4 + + dialog-fill-screen + print footsteps-in-distance + jump dialog-pause + +: describe-ambience + i := long interstitial-progress + load v0 + if v0 == 0 begin + if suspicion-level > 40 begin + i := long interstitial-progress + v0 := 1 + save v0 + dialog-fill-screen + print growing-suspicious + jump dialog-pause + end + end + if v0 == 1 begin + if suspicion-level > 100 begin + i := long interstitial-progress + v0 := 2 + save v0 + dialog-fill-screen + print begun-stalking + jump dialog-pause + end + end + + move-npcs + + v0 := random 0xFF + if v0 > 128 then return + v2 := random 0b111 + dialog-fill-screen + print-from-table v2 interstitial-notice-table + jump dialog-pause + +########################################### +# +# Fencing +# +########################################### + +to-data + +: fencing-background + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x33 0x18 0x33 0x18 0x33 0x18 0x33 0x18 0x33 0x18 + 0x33 0x18 0x33 0x38 0x33 0x38 0x33 0x30 0x27 0x30 0x27 0x30 0x66 0x60 0x6E 0x60 + 0x4C 0xC0 0x4C 0xC0 0x99 0x80 0x1B 0x00 0x36 0x00 0x6C 0x00 0xF8 0x00 0xE0 0x00 + 0xE0 0x00 0x70 0x00 0x70 0x00 0x70 0x00 0x78 0x00 0x78 0x00 0x78 0x00 0x5C 0x00 + 0x5C 0x00 0x5C 0x00 0x5C 0x00 0x5E 0x00 0x5E 0x00 0x5A 0x00 0x5B 0x00 0x5B 0x00 + 0x5B 0x00 0x5B 0x00 0x5B 0x00 0x5B 0x00 0x5B 0x00 0x5B 0x00 0x5B 0x00 0x5B 0x00 + 0x5B 0x00 0x5B 0x00 0x5B 0x00 0x5B 0x00 0x5B 0x00 0x5B 0x00 0x5B 0x00 0xFF 0xFF + 0xFF 0xFF 0xF2 0x72 0xE1 0x21 0xE0 0x20 0xF0 0x70 0xF8 0xF8 0xFD 0xFD 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xFF 0xFF + 0xFF 0xFF 0x72 0x7F 0x21 0x3F 0x20 0x3F 0x70 0x7F 0xF8 0xFF 0xFD 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x02 0x10 0x0A 0x14 0x2A 0x94 0x2A 0x94 0x08 0x84 + 0x72 0x25 0x1F 0x9B 0x07 0xFF 0x01 0xFF 0x02 0x2F 0x00 0x22 0x00 0x02 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x08 0x40 0x28 0x50 0x29 0x54 0x29 0x54 0x21 0x10 + 0xA4 0x4E 0xD9 0xF8 0xFF 0xE0 0xFF 0x80 0xF4 0x40 0x44 0x00 0x40 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xFF 0xFF + 0xFF 0xFF 0xFE 0x4E 0xFC 0x24 0xFC 0x04 0xFE 0x0E 0xFF 0x1F 0xFF 0xBF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x18 0xCC 0x18 0xCC 0x18 0xCC 0x18 0xCC 0x18 0xCC + 0x18 0xCC 0x1C 0xCC 0x1C 0xCC 0x0C 0xCC 0x0C 0xE4 0x0C 0xE4 0x06 0x66 0x06 0x76 + 0x03 0x32 0x03 0x32 0x01 0x99 0x00 0xD8 0x00 0x6C 0x00 0x36 0x00 0x1F 0x00 0x07 + 0x00 0x07 0x00 0x0E 0x00 0x0E 0x00 0x0E 0x00 0x1E 0x00 0x1E 0x00 0x1E 0x00 0x3A + 0x00 0x3A 0x00 0x3A 0x00 0x3A 0x00 0x7A 0x00 0x7A 0x00 0x5A 0x00 0xDA 0x00 0xDA + 0x00 0xDA 0x00 0xDA 0x00 0xDA 0x00 0xDA 0x00 0xDA 0x00 0xDA 0x00 0xDA 0x00 0xDA + 0x00 0xDA 0x00 0xDA 0x00 0xDA 0x00 0xDA 0x00 0xDA 0x00 0xDA 0x00 0xDA 0xFF 0xFF + 0xFF 0xFF 0x4E 0x4F 0x24 0x27 0x04 0x07 0x0E 0x0F 0x1F 0x1F 0xBF 0xBF 0xFF 0xFF + +: fencing-heart + 0xC8 0xF8 0x70 0x20 + +: player-sword + 0xFF 0xF8 0xC0 0x08 0xFF 0xF0 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +: enemy-sword + 0x1F 0xFF 0x10 0x03 0x0F 0xFF 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + +: player-top-neutral + 0x03 0xE0 0x07 0xF0 0x07 0xE8 0x07 0xA0 0x07 0xA0 0x0F 0xE0 0x3F 0xE0 0x1D 0xC0 + 0x01 0x80 0x0F 0xE0 0x13 0xF0 0x13 0xF8 0x27 0xEE 0x27 0xFF 0x11 0x03 0x08 0xFC +: player-top-stagger + 0x07 0xD0 0x4F 0xE0 0x0F 0xC0 0x2E 0x40 0x1F 0xC0 0x7F 0xC0 0x3F 0xC0 0x97 0x80 + 0x03 0x00 0x1F 0xF0 0x27 0xFC 0x27 0xFF 0x4F 0xC7 0x4F 0xF8 0x22 0x06 0x11 0xF8 +: player-top-attack + 0x03 0xE0 0x07 0xF8 0x07 0xE0 0x07 0xA0 0x0F 0xA0 0x3F 0xE0 0x1F 0xE0 0x0D 0xC0 + 0x01 0x83 0x03 0xFD 0x04 0x03 0x1C 0x1C 0x3F 0xE0 0x7F 0xE0 0x77 0xE0 0x37 0xE0 +: player-top-block + 0x03 0xE0 0x07 0xF8 0x07 0xE2 0x07 0xA2 0x0F 0xA5 0x3F 0xE5 0x1F 0xE5 0x0D 0xC5 + 0x01 0x85 0x03 0xCA 0x04 0x6E 0x04 0x72 0x06 0x36 0x07 0x04 0x03 0xC8 0x07 0xF0 +: player-bottom-neutral + 0x0F 0xF0 0x0F 0xF0 0x1F 0xF8 0x1F 0xF8 0x3F 0xF8 0x3F 0xFC 0x7F 0xFC 0x1F 0xF8 + 0x0E 0x70 0x0E 0x70 0x0C 0x60 0x18 0x60 0x18 0xC0 0x18 0xC0 0x1E 0xF0 0x00 0x00 +: player-bottom-step + 0x0F 0xF0 0x0F 0xF8 0x0F 0xFC 0x1F 0xFC 0x7F 0xFC 0x3F 0xFE 0x1F 0xFE 0x0F 0xFC + 0x0E 0x38 0x1C 0x18 0x38 0x1C 0x70 0x1C 0xE0 0x0C 0x60 0x0C 0x30 0x0F 0x00 0x00 +: player-bottom-stagger + 0x0F 0xF0 0x0F 0xF0 0x1F 0xF8 0x3F 0xF8 0x3F 0xF8 0xFF 0xF8 0x7F 0xF8 0x1F 0xF0 + 0x0E 0x70 0x0E 0x78 0x07 0x38 0x03 0x19 0x03 0xFF 0x03 0xCE 0x01 0x84 0x00 0x00 + +: enemy-0-top-neutral + 0x07 0xC0 0x0F 0xE0 0x1F 0xE0 0x06 0xF0 0x05 0xF0 0x07 0xF0 0x07 0xF0 0x03 0xA0 + 0x01 0x80 0x07 0xF0 0x0F 0xC8 0x1F 0xC8 0x77 0xE4 0xFF 0xE4 0xC0 0x88 0x3F 0x10 +: enemy-0-top-tell + 0x07 0xC0 0x0F 0xE0 0x1F 0xE0 0x04 0xF0 0x05 0xF0 0x07 0xF0 0x07 0xF0 0x03 0xA0 + 0x01 0x80 0x07 0xF0 0x0F 0xC8 0x1F 0xE4 0x37 0xF2 0x7F 0xF2 0x20 0x44 0x1F 0x98 +: enemy-0-top-stagger + 0x03 0xE4 0x07 0xF0 0x0F 0xF8 0x02 0x7A 0x02 0x78 0x03 0xF8 0x03 0xF8 0x01 0xD2 + 0x00 0xC0 0x0F 0xF8 0x3F 0xE4 0xFF 0xE4 0xE3 0xF2 0x1F 0xF2 0x60 0x44 0x1F 0x8C +: enemy-0-top-attack + 0x07 0xC0 0x0F 0xE0 0x1F 0xF0 0x06 0xF0 0x05 0xF0 0x07 0xF0 0x07 0xF0 0x03 0xA0 + 0xC1 0x80 0xBF 0xC0 0xC0 0x20 0x38 0x38 0x07 0xFC 0x07 0xFE 0x07 0xEE 0x07 0xEC +: enemy-0-top-block + 0x07 0xC0 0x0F 0xE0 0x5F 0xF0 0x45 0xF0 0xA5 0xF0 0xA7 0xF0 0xA7 0xF0 0xA3 0xA0 + 0xA1 0x80 0x53 0xC0 0x76 0x20 0x4E 0x20 0x6C 0x60 0x20 0xE0 0x13 0xC0 0x0F 0xE0 +: enemy-0-bottom-neutral + 0x07 0xE0 0x0F 0xE0 0x0F 0xF0 0x0F 0xF0 0x0F 0xF0 0x1F 0xF0 0x1F 0xF8 0x1F 0xF8 + 0x1F 0xF8 0x1F 0xFC 0x1F 0xFC 0x06 0x18 0x03 0x18 0x03 0x18 0x0F 0x78 0x00 0x00 +: enemy-0-bottom-step + 0x07 0xE0 0x07 0xE0 0x0F 0xF0 0x0F 0xF0 0x1F 0xF0 0x1F 0xF8 0x1F 0xFC 0x1F 0xFE + 0x1F 0xFC 0x1F 0xFC 0x3F 0x9C 0x38 0x0E 0x30 0x07 0x30 0x06 0xF0 0x0C 0x00 0x00 +: enemy-0-bottom-stagger + 0x01 0xF8 0x03 0xF8 0x03 0xF8 0x03 0xF8 0x07 0xF8 0x0F 0xF8 0x1F 0xF8 0x7F 0xF8 + 0x3F 0xF8 0x1F 0xF0 0x1F 0xF0 0x98 0xF0 0xFF 0xC0 0x73 0xC0 0x21 0x80 0x00 0x00 + +: enemy-1-top-neutral + 0x07 0xD0 0x0F 0xF0 0x0F 0xF0 0x06 0xF0 0x05 0xF0 0x0F 0xF0 0x0F 0xF0 0x07 0xE0 + 0x01 0xC0 0x07 0xF0 0x0F 0xC8 0x1F 0xC8 0x77 0xE4 0xFF 0xE4 0xC0 0x88 0x3F 0x10 +: enemy-1-top-tell + 0x07 0xD0 0x0F 0xF0 0x0F 0xF0 0x04 0xF0 0x05 0xF0 0x0F 0xF0 0x0F 0xF0 0x07 0xE0 + 0x01 0xC0 0x07 0xF0 0x0F 0xC8 0x1F 0xE4 0x37 0xF2 0x7F 0xF2 0x20 0x44 0x1F 0x98 +: enemy-1-top-stagger + 0x03 0xEA 0x07 0xF8 0x07 0xF8 0x02 0x78 0x02 0x7B 0x07 0xF8 0x07 0xF8 0x03 0xF2 + 0x00 0xE0 0x0F 0xF8 0x3F 0xE4 0xFF 0xE4 0xE3 0xF2 0x1F 0xF2 0x60 0x44 0x1F 0x8C +: enemy-1-top-attack + 0x07 0xD0 0x0F 0xF0 0x0F 0xF0 0x06 0xF0 0x05 0xF0 0x0F 0xF0 0x0F 0xF0 0x07 0xE0 + 0xF1 0xC0 0x8F 0xC0 0xC0 0x20 0x20 0x38 0x1F 0xFC 0x07 0xFE 0x07 0xFE 0x07 0xF4 +: enemy-1-top-block + 0x07 0xD0 0x0F 0xF0 0x4F 0xF0 0x45 0xF0 0xA5 0xF0 0xAF 0xF0 0xAF 0xF0 0xA7 0xE0 + 0xA1 0xC0 0x53 0xC0 0x76 0x20 0x4C 0x20 0x68 0x20 0x20 0x60 0x11 0xC0 0x0F 0xE0 +: enemy-1-bottom-neutral + 0x0F 0xF0 0x0F 0xF0 0x0F 0xF0 0x0F 0xF0 0x0F 0xF0 0x0F 0xF8 0x0F 0xF8 0x0F 0x78 + 0x0F 0x78 0x0F 0x78 0x07 0x38 0x07 0x9C 0x03 0x9C 0x03 0x9C 0x0F 0xFC 0x00 0x00 +: enemy-1-bottom-step + 0x07 0xF0 0x07 0xF0 0x0F 0xF0 0x0F 0xE0 0x1F 0xE0 0x1F 0xF0 0x1F 0xF0 0x1E 0xF8 + 0x1E 0x7C 0x1C 0x3E 0x3C 0x1E 0x3C 0x0F 0x38 0x07 0x38 0x06 0xF8 0x0C 0x00 0x00 +: enemy-1-bottom-stagger + 0x03 0xFC 0x03 0xFC 0x03 0xFC 0x03 0xFC 0x07 0xFC 0x07 0xFC 0x07 0xFC 0x0F 0xFC + 0x0F 0x78 0x1F 0x78 0x1C 0xF0 0x9C 0xE0 0xFF 0xE0 0x73 0xC0 0x21 0x80 0x00 0x00 + +: enemy-2-top-neutral + 0x07 0xC0 0x07 0xE0 0x07 0xE0 0x1F 0xE0 0x05 0xE0 0x07 0xE0 0x07 0xC0 0x03 0x80 + 0x01 0x80 0x07 0xF0 0x0F 0xC8 0x1F 0xC8 0x77 0xE4 0xFF 0xE4 0xC0 0x88 0x3F 0x10 +: enemy-2-top-tell + 0x07 0xC0 0x07 0xE0 0x07 0xE0 0x1F 0xE0 0x05 0xE0 0x07 0xE0 0x07 0xC0 0x03 0x80 + 0x01 0x80 0x07 0xF0 0x0F 0xC8 0x1F 0xE4 0x37 0xF2 0x7F 0xF2 0x20 0x44 0x1F 0x98 +: enemy-2-top-stagger + 0x03 0xE4 0x03 0xF0 0x03 0xF0 0x0F 0xF6 0x02 0xF0 0x03 0xF0 0x03 0xE4 0x01 0xC0 + 0x00 0xC0 0x0F 0xF8 0x3F 0xE4 0xFF 0xE4 0xE3 0xF2 0x1F 0xF2 0x60 0x44 0x1F 0x8C +: enemy-2-top-attack + 0x07 0xC0 0x07 0xE0 0x07 0xE0 0x1F 0xE0 0x07 0xE0 0x07 0xE0 0x07 0xC0 0x03 0x80 + 0xC1 0x80 0xBF 0xC0 0xC0 0x20 0x38 0x38 0x07 0xFC 0x07 0xFE 0x07 0xEE 0x07 0xEC +: enemy-2-top-block + 0x07 0xC0 0x07 0xE0 0x47 0xE0 0x5F 0xE0 0xA5 0xE0 0xA7 0xE0 0xA7 0xC0 0xA3 0x80 + 0xA1 0x80 0x53 0xC0 0x76 0x20 0x4E 0x20 0x6C 0x60 0x20 0xE0 0x13 0xC0 0x0F 0xE0 +: enemy-2-bottom-neutral + 0x0F 0xF0 0x0F 0xF0 0x0F 0xF0 0x0F 0xF0 0x0F 0xF0 0x0F 0xF0 0x0E 0xF0 0x0E 0x70 + 0x0E 0x70 0x0E 0x70 0x06 0x30 0x06 0x18 0x03 0x18 0x03 0x18 0x0F 0x78 0x00 0x00 +: enemy-2-bottom-step + 0x07 0xE0 0x07 0xE0 0x0F 0xE0 0x0F 0xE0 0x1F 0xF0 0x1F 0xF0 0x1E 0xF0 0x1C 0xF0 + 0x1C 0x78 0x18 0x38 0x38 0x1C 0x38 0x0E 0x30 0x07 0x30 0x06 0xF0 0x0C 0x00 0x00 +: enemy-2-bottom-stagger + 0x03 0xFC 0x03 0xFC 0x03 0xF8 0x03 0xF8 0x07 0xF8 0x07 0xF8 0x07 0x78 0x0F 0x78 + 0x0E 0x70 0x1E 0x70 0x1C 0xE0 0x98 0xC0 0xFF 0xC0 0x73 0xC0 0x21 0x80 0x00 0x00 + +: enemy-3-top-neutral + 0x07 0xC0 0x07 0xE0 0x0F 0xE0 0x1C 0xE0 0x1F 0xE0 0x07 0xE0 0x07 0xC0 0x03 0xE0 + 0x01 0xE0 0x07 0xF0 0x0F 0xC8 0x1F 0xC8 0x77 0xE4 0xFF 0xE4 0xC0 0x88 0x3F 0x10 +: enemy-3-top-tell + 0x07 0xC0 0x07 0xE0 0x0F 0xE0 0x1C 0xE0 0x1F 0xE0 0x07 0xE0 0x07 0xC0 0x03 0xE0 + 0x01 0xE0 0x07 0xF0 0x0F 0xC8 0x1F 0xE4 0x37 0xF2 0x7F 0xF2 0x20 0x44 0x1F 0x98 +: enemy-3-top-stagger + 0x03 0xE4 0x03 0xF0 0x07 0xF0 0x0E 0x76 0x0F 0xF0 0x03 0xF0 0x03 0xE4 0x01 0xF0 + 0x00 0xF0 0x0F 0xF8 0x3F 0xE4 0xFF 0xE4 0xE3 0xF2 0x1F 0xF2 0x60 0x44 0x1F 0x8C +: enemy-3-top-attack + 0x07 0xC0 0x07 0xE0 0x0F 0xE0 0x1C 0xE0 0x1F 0xE0 0x07 0xE0 0x07 0xC0 0x03 0xE0 + 0xC1 0xE0 0xBF 0xE0 0xC0 0x20 0x38 0x38 0x07 0xFC 0x07 0xFE 0x07 0xEE 0x07 0xEC +: enemy-3-top-block + 0x07 0xC0 0x07 0xE0 0x4F 0xE0 0x5C 0xE0 0xBF 0xE0 0xA7 0xE0 0xA7 0xC0 0xA3 0xE0 + 0xA1 0xE0 0x53 0xE0 0x76 0x20 0x4E 0x20 0x6C 0x60 0x20 0xE0 0x13 0xC0 0x0F 0xE0 +: enemy-3-bottom-neutral + 0x0F 0xF0 0x0F 0xF0 0x0F 0xF0 0x0F 0xF0 0x0F 0xF0 0x0F 0xF0 0x0E 0xF0 0x0E 0x70 + 0x0E 0x70 0x0E 0x70 0x06 0x30 0x06 0x18 0x03 0x18 0x03 0x18 0x0F 0x78 0x00 0x00 +: enemy-3-bottom-step + 0x07 0xE0 0x07 0xE0 0x0F 0xE0 0x0F 0xE0 0x1F 0xF0 0x1F 0xF0 0x1E 0xF0 0x1C 0xF0 + 0x1C 0x78 0x18 0x38 0x38 0x1C 0x38 0x0E 0x30 0x07 0x30 0x06 0xF0 0x0C 0x00 0x00 +: enemy-3-bottom-stagger + 0x03 0xFC 0x03 0xFC 0x03 0xF8 0x03 0xF8 0x07 0xF8 0x07 0xF8 0x07 0x78 0x0F 0x78 + 0x0E 0x70 0x1E 0x70 0x1C 0xE0 0x98 0xC0 0xFF 0xC0 0x73 0xC0 0x21 0x80 0x00 0x00 + +: enemy-4-top-neutral + 0x07 0xC0 0x0F 0xE0 0x0F 0xE0 0x0E 0xF0 0x0D 0xF0 0x1F 0xF8 0x1F 0xF8 0x1B 0xF8 + 0x01 0x80 0x07 0xF0 0x0F 0xC8 0x1F 0xC8 0x77 0xE4 0xFF 0xE4 0xC0 0x88 0x3F 0x10 +: enemy-4-top-tell + 0x07 0xC0 0x0F 0xE0 0x0F 0xE0 0x0C 0xF0 0x0D 0xF0 0x1F 0xF8 0x1F 0xF8 0x1B 0xF8 + 0x01 0x80 0x07 0xF0 0x0F 0xC8 0x1F 0xE4 0x37 0xF2 0x7F 0xF2 0x20 0x44 0x1F 0x98 +: enemy-4-top-stagger + 0x03 0xE4 0x07 0xF0 0x07 0xF0 0x06 0x79 0x06 0x78 0x0F 0xFC 0x0F 0xFD 0x0D 0xFC + 0x00 0xC0 0x0F 0xF8 0x3F 0xE4 0xFF 0xE4 0xE3 0xF2 0x1F 0xF2 0x60 0x44 0x1F 0x8C +: enemy-4-top-attack + 0x07 0xC0 0x0F 0xE0 0x0F 0xE0 0x0E 0xF0 0x0D 0xF0 0x1F 0xF8 0x1F 0xF8 0x1B 0xF8 + 0xC1 0x80 0xBF 0xC0 0xC0 0x20 0x38 0x38 0x07 0xFC 0x07 0xFE 0x07 0xEE 0x07 0xEC +: enemy-4-top-block + 0x07 0xC0 0x0F 0xE0 0x4F 0xE0 0x4E 0xF0 0xAD 0xF0 0xBF 0xF8 0xBF 0xF8 0xBB 0xF8 + 0xA1 0x80 0x53 0xC0 0x76 0x20 0x4E 0x20 0x6C 0x60 0x20 0xE0 0x13 0xC0 0x0F 0xE0 +: enemy-4-bottom-neutral + 0x07 0xF0 0x07 0xF0 0x0F 0xF0 0x0F 0xF0 0x0F 0xF0 0x0F 0xF0 0x0F 0xF0 0x0F 0xF8 + 0x0F 0xF8 0x0F 0xF8 0x0F 0xF8 0x0F 0xFC 0x0F 0xFE 0x03 0x18 0x0F 0x78 0x00 0x00 +: enemy-4-bottom-step + 0x07 0xE0 0x07 0xE0 0x0F 0xE0 0x0F 0xE0 0x1F 0xF0 0x1F 0xF0 0x1F 0xF8 0x1F 0xF8 + 0x1F 0xFC 0x1F 0xFE 0x3F 0xFE 0x3F 0xFE 0x3F 0xFF 0x30 0x06 0xF0 0x0C 0x00 0x00 +: enemy-4-bottom-stagger + 0x03 0xFC 0x03 0xFC 0x03 0xF8 0x03 0xF8 0x07 0xF8 0x07 0xF8 0x0F 0xF8 0x0F 0xF8 + 0x1F 0xF8 0x7F 0xF8 0x3F 0xF8 0x98 0xF0 0xFF 0xD0 0x73 0xC0 0x21 0x80 0x00 0x00 + +: enemy-5-top-neutral + 0x1F 0xC0 0x0F 0xE0 0x0F 0xE0 0x06 0xE0 0x0D 0xE0 0x0F 0xE0 0x07 0xE0 0x07 0xC0 + 0x01 0xC0 0x07 0xF0 0x0F 0xC8 0x1F 0xC8 0x77 0xE4 0xFF 0xE4 0xC0 0x88 0x3F 0x10 +: enemy-5-top-tell + 0x1F 0xC0 0x0F 0xE0 0x0F 0xE0 0x04 0xE0 0x0D 0xE0 0x0F 0xE0 0x07 0xE0 0x07 0xC0 + 0x01 0xC0 0x07 0xF0 0x0F 0xC8 0x1F 0xE4 0x37 0xF2 0x7F 0xF2 0x20 0x44 0x1F 0x98 +: enemy-5-top-stagger + 0x0F 0xE4 0x07 0xF0 0x07 0xF0 0x02 0x70 0x06 0x76 0x07 0xF0 0x03 0xF0 0x03 0xE4 + 0x00 0xE0 0x0F 0xF8 0x3F 0xE4 0xFF 0xE4 0xE3 0xF2 0x1F 0xF2 0x60 0x44 0x1F 0x8C +: enemy-5-top-attack + 0x1F 0xC0 0x0F 0xE0 0x07 0xE0 0x06 0xE0 0x0D 0xE0 0x0F 0xE0 0x07 0xE0 0x07 0xC0 + 0xF1 0xC0 0x8F 0xC0 0xC0 0x20 0x20 0x38 0x1F 0xFC 0x07 0xFE 0x07 0xFE 0x07 0xF4 +: enemy-5-top-block + 0x1F 0xC0 0x0F 0xE0 0x4F 0xE0 0x45 0xE0 0xAD 0xE0 0xAF 0xE0 0xA7 0xE0 0xA7 0xC0 + 0xA1 0xC0 0x53 0xC0 0x76 0x20 0x4C 0x20 0x68 0x20 0x20 0x60 0x11 0xC0 0x0F 0xE0 +: enemy-5-bottom-neutral + 0x0F 0xF0 0x0F 0xF0 0x0F 0xF0 0x0F 0xF0 0x0F 0xF0 0x0F 0xF8 0x0F 0xF8 0x0F 0x78 + 0x0F 0x78 0x0F 0x78 0x07 0x38 0x07 0x9C 0x03 0x9C 0x03 0x9C 0x0F 0xFC 0x00 0x00 +: enemy-5-bottom-step + 0x07 0xF0 0x07 0xF0 0x0F 0xF0 0x0F 0xE0 0x1F 0xE0 0x1F 0xF0 0x1F 0xF0 0x1E 0xF8 + 0x1E 0x7C 0x1C 0x3E 0x3C 0x1E 0x3C 0x0F 0x38 0x07 0x38 0x06 0xF8 0x0C 0x00 0x00 +: enemy-5-bottom-stagger + 0x03 0xFC 0x03 0xFC 0x03 0xFC 0x03 0xFC 0x07 0xFC 0x07 0xFC 0x07 0xFC 0x0F 0xFC + 0x0F 0x78 0x1F 0x78 0x1C 0xF0 0x9C 0xE0 0xFF 0xE0 0x73 0xC0 0x21 0x80 0x00 0x00 + +: enemy-6-top-neutral + 0x07 0xC0 0x0F 0xE0 0x0F 0xE0 0x06 0xF0 0x05 0xF0 0x07 0xF0 0x07 0xF0 0x03 0xF0 + 0x01 0x80 0x07 0xF0 0x0F 0xC8 0x1F 0xC8 0x77 0xE4 0xFF 0xE4 0xC0 0x88 0x3F 0x10 +: enemy-6-top-tell + 0x07 0xC0 0x0F 0xE0 0x0F 0xE0 0x04 0xF0 0x05 0xF0 0x07 0xF0 0x07 0xF0 0x03 0xF0 + 0x01 0x80 0x07 0xF0 0x0F 0xC8 0x1F 0xE4 0x37 0xF2 0x7F 0xF2 0x20 0x44 0x1F 0x98 +: enemy-6-top-stagger + 0x03 0xE2 0x07 0xF0 0x07 0xF8 0x02 0x7B 0x02 0x78 0x03 0xF8 0x03 0xFA 0x01 0xF8 + 0x00 0xC0 0x0F 0xF8 0x3F 0xE4 0xFF 0xE4 0xE3 0xF2 0x1F 0xF2 0x60 0x44 0x1F 0x8C +: enemy-6-top-attack + 0x07 0xC0 0x0F 0xE0 0x0F 0xE0 0x06 0xF0 0x05 0xF0 0x07 0xF0 0x07 0xF0 0x03 0xF0 + 0xC1 0x80 0xBF 0xC0 0xC0 0x20 0x38 0x38 0x07 0xFC 0x07 0xFE 0x07 0xEE 0x07 0xEC +: enemy-6-top-block + 0x07 0xC0 0x0F 0xE0 0x47 0xE0 0x45 0xF0 0xA5 0xF0 0xA7 0xF0 0xA7 0xF0 0xA3 0xF0 + 0xA1 0x80 0x53 0xC0 0x76 0x20 0x4E 0x20 0x6C 0x60 0x20 0xE0 0x13 0xC0 0x0F 0xE0 +: enemy-6-bottom-neutral + 0x0F 0xF0 0x0F 0xF0 0x0F 0xF8 0x1F 0xF8 0x1F 0xFC 0x0F 0xF0 0x0E 0x70 0x06 0x70 + 0x06 0x70 0x06 0x30 0x02 0x10 0x02 0x18 0x03 0x18 0x03 0x18 0x0F 0x78 0x00 0x00 +: enemy-6-bottom-step + 0x0F 0xE0 0x1F 0xF0 0x1F 0xF0 0x3F 0xF0 0x3F 0xF8 0x0F 0xE0 0x1C 0xE0 0x1C 0x70 + 0x18 0x38 0x18 0x18 0x30 0x0C 0x30 0x06 0x30 0x07 0x30 0x06 0xF0 0x0C 0x00 0x00 +: enemy-6-bottom-stagger + 0x07 0xFC 0x1F 0xFC 0x3F 0xF8 0x0F 0xF8 0x03 0xF8 0x07 0xF8 0x07 0x70 0x06 0x30 + 0x0E 0x30 0x0C 0x60 0x18 0x60 0x90 0xC0 0xFF 0xC0 0x73 0xC0 0x21 0x80 0x00 0x00 + +: enemy-7-top-neutral + 0x03 0xC0 0x07 0xE0 0x07 0xE0 0x06 0xE0 0x0D 0xE0 0x0F 0xE0 0x07 0xE0 0x03 0xE0 + 0x07 0xF0 0x0F 0x88 0x1F 0x84 0x3F 0xC4 0x77 0xE2 0xFF 0xE2 0xC0 0x84 0x3F 0x08 +: enemy-7-top-tell + 0x03 0xC0 0x07 0xE0 0x07 0xE0 0x04 0xE0 0x0D 0xE0 0x0F 0xE0 0x07 0xE0 0x03 0xE0 + 0x03 0xF8 0x07 0xC4 0x0F 0xC2 0x1F 0xE2 0x3F 0xF1 0x7F 0xE1 0x20 0x42 0x1F 0x8C +: enemy-7-top-stagger + 0x01 0xE4 0x03 0xF0 0x03 0xF0 0x06 0x76 0x06 0x70 0x03 0xF0 0x03 0xF4 0x01 0xF0 + 0x01 0xF8 0x0F 0xC4 0x3F 0xC4 0xFF 0xC4 0xE3 0xE2 0x1F 0xE2 0x60 0x44 0x1F 0x8C +: enemy-7-top-attack + 0x03 0xC0 0x07 0xE0 0x07 0xE0 0x06 0xE0 0x0D 0xE0 0x0F 0xE0 0x07 0xE0 0x03 0xE0 + 0xC1 0xF0 0xBF 0xF0 0x80 0x38 0x40 0x3C 0x38 0x3E 0x07 0xFF 0x07 0xFF 0x07 0xEE +: enemy-7-top-block + 0x03 0xC0 0x07 0xE0 0x47 0xE0 0x45 0xE0 0xAD 0xE0 0xAF 0xE0 0xA7 0xE0 0xA3 0xE0 + 0xA1 0xE0 0x53 0x30 0x76 0x10 0x4E 0x10 0x64 0x30 0x20 0x60 0x10 0xE0 0x0F 0xE0 +: enemy-7-bottom-neutral + 0x0F 0xF0 0x0F 0xF8 0x0F 0xF8 0x0F 0xF8 0x0F 0xF8 0x0F 0xF8 0x0F 0xF8 0x0F 0x7C + 0x0F 0x7C 0x0F 0xFC 0x07 0xBC 0x07 0x9E 0x03 0xDE 0x03 0xDE 0x0F 0xFE 0x00 0x00 +: enemy-7-bottom-step + 0x07 0xF0 0x07 0xF0 0x0F 0xF0 0x0F 0xF8 0x1F 0xF8 0x1F 0xF8 0x1F 0xF8 0x1F 0xFC + 0x1E 0x7C 0x1E 0x3E 0x3C 0x1F 0x3C 0x0F 0x3C 0x07 0x3C 0x06 0xFC 0x0C 0x00 0x00 +: enemy-7-bottom-stagger + 0x03 0xFE 0x03 0xFE 0x03 0xFE 0x03 0xFE 0x07 0xFE 0x07 0xFC 0x07 0xFC 0x0F 0xFC + 0x0F 0x78 0x1F 0x78 0x1E 0xF0 0xBC 0xF0 0xFF 0xF0 0x73 0xE0 0x21 0xC0 0x00 0x00 + +to-code + +:const MODE_NEUTRAL 0 +:const MODE_WALK_RT 1 +:const MODE_WALK_LF 2 +:const MODE_BLOCK 3 +:const MODE_TELL 4 +:const MODE_ATTACK 5 +:const MODE_STAGGER 6 + +#note: can't touch vc as it contains suspicion level. everything else is fair game. +:alias player-health vb # 20, 12, 4 (-8 per step) +:alias enemy-health va # 103, 111, 119 (+8 per step) +:alias player-fence-x v9 +:alias enemy-fence-x v8 +:alias player-mode v7 +:alias player-timer v6 +:alias enemy-mode v5 +:alias enemy-timer v4 + +: draw-player-and-enemy + # top halves + v0 := 24 + i := long player-top-neutral + if player-mode == MODE_ATTACK then i := long player-top-attack + if player-mode == MODE_STAGGER then i := long player-top-stagger + if player-mode == MODE_BLOCK then i := long player-top-block + sprite player-fence-x v0 0 + if player-mode == MODE_ATTACK begin + v1 := 31 + v2 := player-fence-x + v2 += 16 + i := long player-sword + sprite v2 v1 0 + end + + indirect enemy-top-neutral-slot + if enemy-mode == MODE_ATTACK then indirect enemy-top-attack-slot + if enemy-mode == MODE_STAGGER then indirect enemy-top-stagger-slot + if enemy-mode == MODE_TELL then indirect enemy-top-tell-slot + if enemy-mode == MODE_BLOCK then indirect enemy-top-block-slot + sprite enemy-fence-x v0 0 + if enemy-mode == MODE_ATTACK begin + v1 := 32 + v2 := enemy-fence-x + v2 += -16 + i := long enemy-sword + sprite v2 v1 0 + end + + # bottom halves + v0 += 16 + i := long player-bottom-neutral + vf := 0 + if player-mode == MODE_WALK_LF then vf := 1 + if player-mode == MODE_WALK_RT then vf := 1 + vf &= player-timer + if vf != 0 then i := long player-bottom-step + if player-mode == MODE_STAGGER then i := long player-bottom-stagger + sprite player-fence-x v0 0 + indirect enemy-bottom-neutral-slot + vf := 0 + if enemy-mode == MODE_WALK_LF then vf := 1 + if enemy-mode == MODE_WALK_RT then vf := 1 + vf &= enemy-timer + if vf != 0 then indirect enemy-bottom-step-slot + if enemy-mode == MODE_STAGGER then indirect enemy-bottom-stagger-slot + sprite enemy-fence-x v0 0 +; + +to-data + +: fencing-enemy-0 # { target-pointer, patch-ptr } + pointer enemy-top-neutral-slot pointer enemy-0-top-neutral + pointer enemy-top-tell-slot pointer enemy-0-top-tell + pointer enemy-top-stagger-slot pointer enemy-0-top-stagger + pointer enemy-top-attack-slot pointer enemy-0-top-attack + pointer enemy-top-block-slot pointer enemy-0-top-block + pointer enemy-bottom-neutral-slot pointer enemy-0-bottom-neutral + pointer enemy-bottom-step-slot pointer enemy-0-bottom-step + pointer enemy-bottom-stagger-slot pointer enemy-0-bottom-stagger +: fencing-enemy-1 + pointer enemy-top-neutral-slot pointer enemy-1-top-neutral + pointer enemy-top-tell-slot pointer enemy-1-top-tell + pointer enemy-top-stagger-slot pointer enemy-1-top-stagger + pointer enemy-top-attack-slot pointer enemy-1-top-attack + pointer enemy-top-block-slot pointer enemy-1-top-block + pointer enemy-bottom-neutral-slot pointer enemy-1-bottom-neutral + pointer enemy-bottom-step-slot pointer enemy-1-bottom-step + pointer enemy-bottom-stagger-slot pointer enemy-1-bottom-stagger +: fencing-enemy-2 + pointer enemy-top-neutral-slot pointer enemy-2-top-neutral + pointer enemy-top-tell-slot pointer enemy-2-top-tell + pointer enemy-top-stagger-slot pointer enemy-2-top-stagger + pointer enemy-top-attack-slot pointer enemy-2-top-attack + pointer enemy-top-block-slot pointer enemy-2-top-block + pointer enemy-bottom-neutral-slot pointer enemy-2-bottom-neutral + pointer enemy-bottom-step-slot pointer enemy-2-bottom-step + pointer enemy-bottom-stagger-slot pointer enemy-2-bottom-stagger +: fencing-enemy-3 + pointer enemy-top-neutral-slot pointer enemy-3-top-neutral + pointer enemy-top-tell-slot pointer enemy-3-top-tell + pointer enemy-top-stagger-slot pointer enemy-3-top-stagger + pointer enemy-top-attack-slot pointer enemy-3-top-attack + pointer enemy-top-block-slot pointer enemy-3-top-block + pointer enemy-bottom-neutral-slot pointer enemy-3-bottom-neutral + pointer enemy-bottom-step-slot pointer enemy-3-bottom-step + pointer enemy-bottom-stagger-slot pointer enemy-3-bottom-stagger +: fencing-enemy-4 + pointer enemy-top-neutral-slot pointer enemy-4-top-neutral + pointer enemy-top-tell-slot pointer enemy-4-top-tell + pointer enemy-top-stagger-slot pointer enemy-4-top-stagger + pointer enemy-top-attack-slot pointer enemy-4-top-attack + pointer enemy-top-block-slot pointer enemy-4-top-block + pointer enemy-bottom-neutral-slot pointer enemy-4-bottom-neutral + pointer enemy-bottom-step-slot pointer enemy-4-bottom-step + pointer enemy-bottom-stagger-slot pointer enemy-4-bottom-stagger +: fencing-enemy-5 + pointer enemy-top-neutral-slot pointer enemy-5-top-neutral + pointer enemy-top-tell-slot pointer enemy-5-top-tell + pointer enemy-top-stagger-slot pointer enemy-5-top-stagger + pointer enemy-top-attack-slot pointer enemy-5-top-attack + pointer enemy-top-block-slot pointer enemy-5-top-block + pointer enemy-bottom-neutral-slot pointer enemy-5-bottom-neutral + pointer enemy-bottom-step-slot pointer enemy-5-bottom-step + pointer enemy-bottom-stagger-slot pointer enemy-5-bottom-stagger +: fencing-enemy-6 + pointer enemy-top-neutral-slot pointer enemy-6-top-neutral + pointer enemy-top-tell-slot pointer enemy-6-top-tell + pointer enemy-top-stagger-slot pointer enemy-6-top-stagger + pointer enemy-top-attack-slot pointer enemy-6-top-attack + pointer enemy-top-block-slot pointer enemy-6-top-block + pointer enemy-bottom-neutral-slot pointer enemy-6-bottom-neutral + pointer enemy-bottom-step-slot pointer enemy-6-bottom-step + pointer enemy-bottom-stagger-slot pointer enemy-6-bottom-stagger +: fencing-enemy-7 + pointer enemy-top-neutral-slot pointer enemy-7-top-neutral + pointer enemy-top-tell-slot pointer enemy-7-top-tell + pointer enemy-top-stagger-slot pointer enemy-7-top-stagger + pointer enemy-top-attack-slot pointer enemy-7-top-attack + pointer enemy-top-block-slot pointer enemy-7-top-block + pointer enemy-bottom-neutral-slot pointer enemy-7-bottom-neutral + pointer enemy-bottom-step-slot pointer enemy-7-bottom-step + pointer enemy-bottom-stagger-slot pointer enemy-7-bottom-stagger + +: fencing-enemy-table + pointer fencing-enemy-0 + pointer fencing-enemy-1 + pointer fencing-enemy-2 + pointer fencing-enemy-3 + pointer fencing-enemy-4 + pointer fencing-enemy-5 + pointer fencing-enemy-6 + pointer fencing-enemy-7 + +: engarde + 0xFE 0x1C 0x19 0xFC 0x04 0x27 0xF9 0x06 0x1A 0x2B 0x1D 0x1E 0x3F 0xFF + +: fight-start-1 # The fiend grabs a sword from the wall. They intend to go down fighting! + 0xFE 0x03 0x08 0x13 0x21 0x1E 0xF9 0x1F 0x22 0x1E 0x27 0x1D 0xF9 0x20 0x2B 0x1A + 0x1B 0x2C 0xF9 0x1A 0xF9 0xF9 0xFE 0x03 0x12 0x2C 0x30 0x28 0x2B 0x1D 0xF9 0x1F + 0x2B 0x28 0x26 0xF9 0x2D 0x21 0x1E 0xF9 0x30 0x1A 0x25 0x25 0x3E 0xF9 0xF9 0xFE + 0x03 0x26 0x13 0x21 0x1E 0x32 0xF9 0x22 0x27 0x2D 0x1E 0x27 0x1D 0xF9 0x2D 0x28 + 0xF9 0x20 0x28 0xF9 0xF9 0xFE 0x03 0x30 0x1D 0x28 0x30 0x27 0xF9 0x1F 0x22 0x20 + 0x21 0x2D 0x22 0x27 0x20 0x3F 0xFF +: fight-start-2 # I pray those fencing lessons won't have gone to waste... + 0xFE 0x01 0x11 0x08 0xF9 0x29 0x2B 0x1A 0x32 0xF9 0x2D 0x21 0x28 0x2C 0x1E 0xF9 + 0x1F 0x1E 0x27 0x1C 0x22 0x27 0x20 0xFE 0x01 0x1B 0x25 0x1E 0x2C 0x2C 0x28 0x27 + 0x2C 0xF9 0x30 0x28 0x27 0x42 0x2D 0xF9 0x21 0x1A 0x2F 0x1E 0xFE 0x01 0x25 0x20 + 0x28 0x27 0x1E 0xF9 0x2D 0x28 0xF9 0x30 0x1A 0x2C 0x2D 0x1E 0x3E 0x3E 0x3E 0xFF +: dispatched # With a few deft blows, the villain is soundly trounced. + 0xFE 0x03 0x11 0x16 0x22 0x2D 0x21 0xF9 0x1A 0xF9 0x1F 0x1E 0x30 0xF9 0x1D 0x1E + 0x1F 0x2D 0xFE 0x03 0x1B 0x1B 0x25 0x28 0x30 0x2C 0x41 0xF9 0x2D 0x21 0x1E 0xF9 + 0x2F 0x22 0x25 0x25 0x1A 0x22 0x27 0xFE 0x03 0x25 0x22 0x2C 0xF9 0x2C 0x28 0x2E + 0x27 0x1D 0x25 0x32 0xF9 0x2D 0x2B 0x28 0x2E 0x27 0x1C 0x1E 0x1D 0x3E 0xFF +: failed-fight-1 # Blast, the villain got the best of me and made their escape! + 0xFE 0x25 0x07 0xFC 0x01 0x25 0x1A 0x2C 0x2D 0x3F 0xF9 0xFE 0x05 0x1B 0xFC 0x13 + 0x21 0x1E 0xF9 0x2F 0x22 0x25 0x25 0x1A 0x22 0x27 0xF9 0x20 0x28 0x2D 0xF9 0x2D + 0x21 0x1E 0xF9 0xFE 0x05 0x25 0x1B 0x1E 0x2C 0x2D 0xF9 0x28 0x1F 0xF9 0x26 0x1E + 0xF9 0x1A 0x27 0x1D 0xF9 0x26 0x1A 0x1D 0x1E 0xF9 0xFE 0x05 0x2F 0x2D 0x21 0x1E + 0x22 0x2B 0xF9 0x1E 0x2C 0x1C 0x1A 0x29 0x1E 0x3F 0xFF +: failed-fight-2 # Jolly good showing, anyway. I can hear the hounds calling for them already... + 0xFE 0x05 0x05 0x09 0x28 0x25 0x25 0x32 0xF9 0x20 0x28 0x28 0x1D 0xF9 0x2C 0x21 + 0x28 0x30 0x22 0x27 0x20 0x41 0xF9 0xFE 0x05 0x0F 0x1A 0x27 0x32 0x30 0x1A 0x32 + 0x3E 0xF9 0x08 0xF9 0x1C 0x1A 0x27 0xF9 0x21 0x1E 0x1A 0x2B 0xF9 0xFE 0x05 0x19 + 0x2D 0x21 0x1E 0xF9 0x21 0x28 0x2E 0x27 0x1D 0x2C 0xF9 0x1C 0x1A 0x25 0x25 0x22 + 0x27 0x20 0xF9 0xFE 0x05 0x23 0x1F 0x28 0x2B 0xF9 0x2D 0x21 0x1E 0x26 0xF9 0x1A + 0x25 0x2B 0x1E 0x1A 0x1D 0x32 0x3E 0x3E 0x3E 0xF9 0xFE 0x24 0x31 0x13 0x07 0x04 + 0xF9 0x04 0x0D 0x03 0xFF + +: fencing-registers + 20 103 +: fencing-registers-round + 32 80 0 0 0 0 + +: fencing-ai # 8 entries { mode, timer } + :byte MODE_WALK_LF 10 + :byte MODE_WALK_LF 10 + :byte MODE_WALK_LF 10 + :byte MODE_WALK_LF 10 + :byte MODE_WALK_RT 6 + :byte MODE_WALK_RT 6 + :byte MODE_BLOCK 4 + :byte MODE_BLOCK 4 + :byte MODE_BLOCK 4 + +to-code + +: fencing-minigame + clear + print fight-start-1 + dialog-pause + print fight-start-2 + dialog-pause + + # rewrite all the enemy graphics based + # on who is currently the villain... + i := long npc-murderer + load v0 + i := long fencing-enemy-table + i += v0 + i += v0 + load v1 + i := fencing-graphics-rewrite + save v1 + v4 := 0 + loop + indirect fencing-graphics-rewrite + i += v4 + i += v4 + i += v4 + i += v4 + load v3 + i := fencing-graphics-dest + save v0 - v1 + indirect fencing-graphics-dest + save v2 - v3 + v4 += 1 + if v4 != 8 then + again + + i := long fencing-registers + load vb - v4 + i := long fencing-background + full-screen-blit + print engarde + wait 60 + print engarde + + draw-player-and-enemy + loop + draw-player-and-enemy + + # player controls and state machine + if player-mode == MODE_NEUTRAL begin + vf := OCTO_KEY_A + if vf key begin + player-mode := MODE_WALK_LF + player-timer := 3 + end + vf := OCTO_KEY_D + if vf key begin + player-mode := MODE_WALK_RT + player-timer := 3 + end + vf := OCTO_KEY_W + if vf key begin + player-mode := MODE_BLOCK + player-timer := 10 + end + vf := OCTO_KEY_E + if vf key begin + player-mode := MODE_ATTACK + player-timer := 6 + # did the player hit the enemy? + if enemy-mode != MODE_BLOCK begin + v0 := enemy-fence-x + v0 -= player-fence-x + if v0 < 24 begin + enemy-mode := MODE_STAGGER + enemy-timer := 30 + player-timer := 31 + end + end + end + end + if player-fence-x > 0 begin + if player-mode == MODE_WALK_LF then player-fence-x += -1 + end + if player-fence-x < 112 begin + if player-mode == MODE_WALK_RT then player-fence-x += 1 + end + if player-mode != MODE_NEUTRAL begin + player-timer += -1 + if player-timer == 0 begin + if player-mode == MODE_STAGGER begin + # done staggering, subtract health. + i := long fencing-heart + v0 := 58 + sprite player-health v0 4 + player-health += -8 + if player-health == -4 then jump fencing-lose + i := long fencing-registers-round + load player-fence-x - enemy-timer + else + player-mode := MODE_NEUTRAL + end + end + end + + # enemy AI + if enemy-mode == MODE_NEUTRAL begin + v0 := enemy-fence-x + v0 -= player-fence-x + if v0 < 26 begin + # if player is close, attack! + enemy-mode := MODE_TELL + enemy-timer := 4 + else + # otherwise, pick randomly + i := long fencing-ai + v0 := random 0b1110 + i += v0 + load enemy-mode - enemy-timer + end + else + enemy-timer += -1 + if enemy-timer == 0 begin + if enemy-mode == MODE_STAGGER begin + # done staggering, subtract health. + i := long fencing-heart + v0 := 58 + sprite enemy-health v0 4 + enemy-health += 8 + if enemy-health == 127 then jump fencing-win + i := long fencing-registers-round + load player-fence-x - enemy-timer + end + if enemy-mode == MODE_TELL begin + enemy-mode := MODE_ATTACK + enemy-timer := 6 + # did the enemy hit the player? + if player-mode != MODE_BLOCK begin + v0 := enemy-fence-x + v0 -= player-fence-x + if v0 < 24 begin + player-mode := MODE_STAGGER + player-timer := 30 + enemy-timer := 31 + end + end + else + enemy-mode := MODE_NEUTRAL + end + end + end + if enemy-fence-x > 0 begin + if enemy-mode == MODE_WALK_LF then enemy-fence-x += -1 + end + if enemy-fence-x < 112 begin + if enemy-mode == MODE_WALK_RT then enemy-fence-x += 1 + end + + draw-player-and-enemy + wait 3 + again + +: fencing-win + clear + print dispatched + dialog-pause + print good-end-2 + dialog-pause + print good-end-3 + jump show-rank + +: fencing-lose + clear + print failed-fight-1 + dialog-pause + print failed-fight-2 + jump show-rank + +########################################### +# +# Main Map +# +########################################### + +to-data + +:const FLOORPLAN_X 16 +:const FLOORPLAN_Y 2 +:calc FLOORPLAN_END_X { FLOORPLAN_X + 16 * 6 } +:calc FLOORPLAN_END_Y { FLOORPLAN_Y + 16 * 3 } + +: empty-floorplan # 6x3 16x16 sprites, tblr + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x7F 0xFF 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 + 0x0F 0xFF 0x08 0x00 0x08 0x00 0x08 0x00 0x08 0x00 0x08 0x00 0x08 0x00 0x08 0x00 + 0xF8 0x00 0x08 0x00 0x08 0x00 0x08 0x00 0x08 0x00 0x08 0x00 0x08 0x00 0x08 0x00 + 0xFF 0xFF 0x04 0x00 0x04 0x00 0x04 0x00 0x04 0x00 0x04 0x00 0x04 0x00 0x04 0x00 + 0x04 0x00 0x1C 0x00 0x20 0x00 0x10 0x00 0x08 0x00 0x04 0x00 0x04 0x00 0x04 0x00 + 0xFF 0xFF 0x08 0x00 0x08 0x00 0x08 0x00 0x08 0x00 0x08 0x00 0x08 0x00 0x08 0x00 + 0x08 0x00 0x08 0x00 0x08 0x00 0x08 0x00 0x08 0x00 0x08 0x00 0x08 0x00 0x08 0x00 + 0xF7 0x7F 0x10 0x40 0x10 0x40 0x10 0x40 0x10 0x40 0x10 0x40 0x10 0x70 0x10 0x08 + 0x10 0x10 0x10 0x20 0x10 0x40 0x10 0x40 0x10 0x40 0x10 0x40 0x10 0x40 0x10 0x40 + 0xFF 0xFE 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 + 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 + 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 + 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x7F 0xFF 0x40 0x00 0x40 0x00 + 0x08 0x00 0x08 0x00 0x08 0x00 0x0F 0xFF 0x08 0x00 0x08 0x00 0x10 0x00 0x20 0x00 + 0x40 0x7F 0x38 0x40 0x08 0x40 0x08 0x20 0x08 0x10 0xF8 0x08 0x08 0x70 0x08 0x40 + 0x04 0x08 0x04 0x14 0x04 0x24 0xFF 0xC7 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0xFF 0xFF 0x00 0x04 0x00 0x04 0x00 0x04 0x00 0x04 0x00 0x04 0x00 0x04 0x00 0x04 + 0x08 0x10 0x08 0x28 0x08 0x48 0xFF 0x8F 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0xC7 0xFF 0x24 0x04 0x14 0x04 0x08 0x04 0x00 0x04 0x00 0x07 0x00 0x04 0x00 0x07 + 0x10 0x7F 0x10 0x40 0x10 0x40 0xF0 0x40 0x00 0x40 0x00 0x40 0x00 0x70 0x00 0x08 + 0xF0 0x10 0x10 0x20 0x10 0x40 0x10 0x40 0x10 0x40 0xF0 0x40 0x10 0x40 0xF0 0x40 + 0xFF 0xFE 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 + 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 + 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 + 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x7F 0xFF + 0x08 0x40 0x08 0x40 0x08 0x40 0x10 0x40 0x20 0x40 0x40 0x40 0x38 0x40 0x08 0x40 + 0x08 0x40 0x08 0x40 0x08 0x40 0x08 0x40 0x08 0x40 0x08 0x7F 0x08 0x40 0xFB 0x40 + 0x00 0x04 0x00 0x04 0x00 0x04 0x00 0x04 0x00 0x04 0x00 0x07 0x00 0x04 0x00 0x04 + 0x00 0x08 0x00 0x10 0x00 0x20 0x00 0x1C 0x00 0x04 0xFF 0xFF 0x00 0x00 0x00 0x00 + 0x00 0x04 0x00 0x07 0x00 0x04 0x00 0x07 0x00 0x04 0xFF 0xFD 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xFF 0xFF 0x00 0x00 0x00 0x00 + 0x10 0x7F 0xF0 0x40 0x10 0x40 0xF0 0x40 0x10 0x40 0xD0 0x40 0x00 0x40 0x00 0x40 + 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0x00 0x40 0xFF 0xC0 0x00 0x40 0x00 0x7F + 0xF1 0xFE 0x09 0x02 0x05 0x02 0x02 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 + 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0xFF 0xFE + +: room-masks # 16x16 sprites + 0xFF 0xFC 0xFF 0xFC 0xFF 0xFC 0xFF 0xFC 0xFF 0xFC 0xFF 0xFC 0xFF 0xFC 0xFF 0xFC # library + 0xFF 0xFC 0xFF 0xF8 0xFF 0xF0 0xFF 0xE0 0xFF 0xC0 0xFF 0xC0 0xFF 0xC0 0xFF 0xE0 + 0xFF 0xF0 0xFF 0xF0 0xFF 0xF0 0xFF 0xF0 0xFF 0xE0 0xFF 0xC0 0xFF 0x80 0xFF 0x80 # bathroom + 0xFF 0x80 0xFF 0xC0 0xFF 0xE0 0xFF 0xF0 0xFF 0xF0 0xFF 0xF0 0x00 0x00 0x00 0x00 + 0xFF 0xC0 0xFF 0xC0 0xFF 0xC0 0xFF 0xC0 0xFF 0xC0 0xFF 0xC0 0xFF 0xC0 0xFF 0xC0 # bedroom + 0xFF 0xC0 0xFF 0xC0 0xFF 0xC0 0xE3 0xC0 0xC1 0xC0 0x80 0xC0 0x00 0x00 0x00 0x00 + 0xFF 0xC0 0xFF 0xC0 0xFF 0xC0 0xFF 0xC0 0xFF 0xC0 0xFF 0xC0 0xFF 0xC0 0xFF 0xC0 # drawing room (same as bedroom) + 0xFF 0xC0 0xFF 0xC0 0xFF 0xC0 0xE3 0xC0 0xC1 0xC0 0x80 0xC0 0x00 0x00 0x00 0x00 + 0xFF 0xFC 0xFF 0xFC 0xFF 0xF8 0xFF 0xF0 0xFF 0xE0 0xFF 0xE0 0xFF 0xE0 0xFF 0xF0 # parlor + 0xFF 0xF8 0xFF 0xFC 0xFF 0xFC 0xFF 0xFC 0xFF 0xFC 0x00 0x00 0x00 0x00 0x00 0x00 + 0x3F 0xFE 0x1F 0xFE 0x0F 0xFE 0x0F 0xFE 0x1F 0xFE 0x3F 0xFE 0x7F 0xFE 0xFF 0xFE # dining room + 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFC 0xFF 0xF8 0xFF 0xF0 0xFF 0xE0 + 0x80 0xE0 0xC0 0xE0 0xE1 0xE0 0xFF 0xE0 0xFF 0xE0 0xFF 0xE0 0xFF 0xE0 0xFF 0xE0 # study + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0xFF 0xFF 0x7F 0xFF 0x3F 0xFF 0x1F 0xFF 0x1F 0xFF 0x1F 0xFF 0x3F 0xFF 0x7F 0xFF # conservatory + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0xFF 0xFF 0x7F 0xFF 0x3F 0xFF 0x1F 0xFF 0x1F 0xFF 0x1F 0xFF 0x3F 0xFF 0x7F 0xFF # kitchen (same as conservatory) + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0xFE 0x03 0xFF 0x03 0xFF 0x87 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF # pantry + 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + +: mask-positions # [x,y] + 20 13 # 0 - library + 39 5 # 1 - bathroom + 56 5 # 2 - bedroom + 71 5 # 3 - drawing room + 20 34 # 4 - parlor + 44 29 # 5 - dining room + 64 29 # 6 - study + 92 5 # 7 - conservatory + 92 21 # 8 - kitchen + 92 37 # 9 - pantry + +: room-nav # [n,e,s,w] + 1 1 4 0 # 0 + 1 2 5 0 # 1 + 2 3 5 1 # 2 + 3 7 6 2 # 3 + 0 5 4 4 # 4 + 2 6 5 4 # 5 + 3 9 6 5 # 6 + 7 7 8 3 # 7 + 7 8 9 6 # 8 + 8 9 9 6 # 9 + 10 10 10 10 # 10 (secret room) + +: label-library 0xFE 0x28 0x35 0x0B 0x22 0x1B 0x2B 0x1A 0x2B 0x32 0xFF +: label-bathroom 0xFE 0x26 0x35 0x01 0x1A 0x2D 0x21 0x2B 0x28 0x28 0x26 0xFF +: label-bedroom 0xFE 0x26 0x35 0x01 0x1E 0x1D 0x2B 0x28 0x28 0x26 0xFF +: label-drawing-room 0xFE 0x1B 0x35 0x03 0x2B 0x1A 0x30 0x22 0x27 0x20 0xF9 0x11 0x28 0x28 0x26 0xFF +: label-parlor 0xFE 0x2D 0x35 0x0F 0x1A 0x2B 0x25 0x28 0x2B 0xFF +: label-dining-room 0xFE 0x1E 0x35 0x03 0x22 0x27 0x22 0x27 0x20 0xF9 0x11 0x28 0x28 0x26 0xFF +: label-study 0xFE 0x2F 0x35 0x12 0x2D 0x2E 0x1D 0x32 0xFF +: label-conservatory 0xFE 0x1B 0x35 0x02 0x28 0x27 0x2C 0x1E 0x2B 0x2F 0x1A 0x2D 0x28 0x2B 0x32 0xFF +: label-kitchen 0xFE 0x29 0x35 0x0A 0x22 0x2D 0x1C 0x21 0x1E 0x27 0xFF +: label-pantry 0xFE 0x2C 0x35 0x0F 0x1A 0x27 0x2D 0x2B 0x32 0xFF + +: room-label-table + pointer label-library + pointer label-bathroom + pointer label-bedroom + pointer label-drawing-room + pointer label-parlor + pointer label-dining-room + pointer label-study + pointer label-conservatory + pointer label-kitchen + pointer label-pantry + +to-code + +: draw-map-label + i := long room-label-table + i += current-room + i += current-room + load v1 + jump print-text # TCO + +:macro main-map { + # draw the building's floorplan + clear + i := long empty-floorplan + v0 := FLOORPLAN_X + v1 := FLOORPLAN_Y + v2 := 32 + loop + sprite v0 v1 0 + i += v2 + v0 += 16 + if v0 == FLOORPLAN_END_X then v1 += 16 + if v0 == FLOORPLAN_END_X then v0 := FLOORPLAN_X + if v1 != FLOORPLAN_END_Y then + again + + # choose a new room + loop + draw-map-label + + i := long mask-positions + i += current-room + i += current-room + load v1 - v2 + + i := long room-masks + v0 := current-room + vf := 32 + loop + while v0 != 0 + v0 += -1 + i += vf + again + sprite v1 v2 0 + + v4 := key + sprite v1 v2 0 + draw-map-label + + i := long room-nav + i += current-room + i += current-room + i += current-room + i += current-room + load v3 + + if v4 == OCTO_KEY_W then current-room := v0 + if v4 == OCTO_KEY_D then current-room := v1 + if v4 == OCTO_KEY_S then current-room := v2 + if v4 == OCTO_KEY_A then current-room := v3 + + if v4 != OCTO_KEY_E then + again +} + +########################################### +# +# Entrypoint +# +########################################### + +: main + hires + loop + intro-sequence + loop + main-map + thicken-plot SUSPICION_ENTER_ROOM + room + while current-room != GAME_OVER + describe-ambience + again + again diff --git a/resources/octoroms/outlaw.8o b/resources/octoroms/outlaw.8o new file mode 100644 index 0000000..fcf6aad --- /dev/null +++ b/resources/octoroms/outlaw.8o @@ -0,0 +1,295 @@ +########################################### +# +# Outlaw +# +# An adaptation of the Atari 2600 game +# "Outlaw" for the Chip8. +# +# Move with ASWD and fire with E. +# Holding a direction while firing will +# fire an angled shot, which ricochets. +# Plays fairly well at 30 cycles/frame +# +########################################### + +: cactus 0x38 0x38 0x3B 0x1B 0x1B 0x1B 0xDF 0xDE 0xD8 0xD8 0xF8 0x78 0x18 0x1C 0x0C +: left 0x00 0x00 0x70 0xF8 0x70 0x67 0x7C 0x60 0x60 0x78 0x28 0xEC +: lwalk1 0x18 0x3E 0x1C 0x18 0x7E 0x99 0x99 0x99 0x5A 0x3C 0x66 0xC3 +: lwalk2 0x18 0x3E 0x1C 0x18 0x7E 0x99 0x99 0x99 0x5A 0x3C 0x24 0x36 +: right 0x00 0x00 0x06 0x1F 0x0E 0xE6 0x3E 0x06 0x06 0x1E 0x14 0x37 +: rwalk1 0x18 0x7C 0x38 0x18 0x7E 0x99 0x99 0x99 0x5A 0x3C 0x66 0xC3 +: rwalk2 0x18 0x7C 0x38 0x18 0x7E 0x99 0x99 0x99 0x5A 0x3C 0x24 0x6C +: edge 0xFF 0xFF +: bullet 0x80 + +########################################### +# +# Register map +# +########################################### + +:alias leftx ve +:alias lefty vd +:alias leftframe vc +:alias leftbx vb +:alias leftby va +:alias leftfire v9 + +:alias rightx v8 +:alias righty v7 +:alias rightframe v6 +:alias rightbx v5 +:alias rightby v4 +:alias rightfire v3 + +:const FIRE_ST 1 +:const FIRE_UP 2 +:const FIRE_DN 3 + +# v0-v2 and vf are left as temporaries + +########################################### +# +# Bullets +# +########################################### + +: fire-left-bullet + v0 := 6 + if v0 -key then return + leftfire := FIRE_ST + v0 := 5 + if v0 key then leftfire := FIRE_UP + v0 := 8 + if v0 key then leftfire := FIRE_DN + + # spawn bullet + leftbx := leftx + leftbx += 9 + leftby := lefty + leftby += 5 + + # draw initial bullet frame + i := bullet + sprite leftbx leftby 1 +; + +: move-left-bullet + sprite leftbx leftby 1 + leftbx += 1 + if leftfire == FIRE_UP then leftby += -1 + if leftfire == FIRE_DN then leftby += 1 + + # bounce off top and bottom edge + if leftby == 1 then leftfire := FIRE_DN + if leftby == 30 then leftfire := FIRE_UP + + # despawn on right edge + if leftbx == 63 then leftfire := 0 + if leftfire == 0 then return + sprite leftbx leftby 1 + + # collide with obstacles + if vf == 0 then return + leftfire := 0 +; + +: fire-right-bullet + if rightfire != 0 then return + rightfire := FIRE_ST + v0 := random 0b11 + if v0 == 1 then rightfire := FIRE_UP + if v0 == 2 then rightfire := FIRE_DN + + # spawn bullet + rightbx := rightx + rightbx += -1 + rightby := righty + rightby += 5 + + # draw initial bullet frame + i := bullet + sprite rightbx rightby 1 +; + +: move-right-bullet + sprite rightbx rightby 1 + rightbx += -1 + if rightfire == FIRE_UP then rightby += -1 + if rightfire == FIRE_DN then rightby += 1 + + # bounce off top and bottom edge + if rightby == 1 then rightfire := FIRE_DN + if rightby == 30 then rightfire := FIRE_UP + + # despawn on right edge + if rightbx == 0 then rightfire := 0 + if rightfire == 0 then return + sprite rightbx rightby 1 + + # collide with obstacles + if vf == 0 then return + rightfire := 0 +; + +########################################### +# +# Gunslingers +# +########################################### + +: move-left-player + v1 := leftx + v2 := lefty + + # process movement keys + v0 := 7 + if v0 key then v1 += -1 + v0 := 9 + if v0 key then v1 += 1 + v0 := 5 + if v0 key then v2 += -1 + v0 := 8 + if v0 key then v2 += 1 + + # animate player movement + v0 := 0 + if v1 != leftx then v0 := 24 + if v2 != lefty then v0 := 24 + if leftframe == 24 then v0 := 12 + vf := 6 + if vf key then v0 := 0 + + # clamp position within left side + if v1 == 0 then v1 := 1 + if v1 == 21 then v1 := 20 + if v2 == 0 then v2 := 1 + if v2 == 18 then v2 := 17 + + # update position + i := left + i += leftframe + sprite leftx lefty 12 + leftx := v1 + lefty := v2 + leftframe := v0 + i := left + i += leftframe + sprite leftx lefty 12 +; + +: brain-table + v1 += -1 return + v1 += 1 return + v2 += -1 return # vertical movement is 2x as likely + v2 += -1 return # as horizontal movement + v2 += 1 return + v2 += 1 return + v0 := v0 return # do nothing + fire-right-bullet return +: do-brain + v0 := random 0b11100 # entries are 4 bytes each + jump0 brain-table + +: move-right-player + v1 := rightx + v2 := righty + + # process (random) movement + do-brain + + # animate movement + v0 := 0 + if v1 != rightx then v0 := 24 + if v2 != righty then v0 := 24 + if rightframe == 24 then v0 := 12 + + # clamp position within right side + if v1 == 35 then v1 := 36 + if v1 == 56 then v1 := 55 + if v2 == 0 then v2 := 1 + if v2 == 18 then v2 := 17 + + # update position + i := right + i += rightframe + sprite rightx righty 12 + rightx := v1 + righty := v2 + rightframe := v0 + i := right + i += rightframe + sprite rightx righty 12 +; + +########################################### +# +# Main +# +########################################### + +: rightdead + sprite rightx righty 12 + i := bullet + sprite leftbx leftby 1 + +: gameover + v0 := 32 + buzzer := v0 + delay := v0 + loop + v0 := delay + if v0 != 0 then + again + jump main + +: leftdead + sprite leftx lefty 12 + i := bullet + sprite rightbx rightby 1 + jump gameover + +: main + # initialize state + leftx := 5 + lefty := 10 + leftframe := 0 + rightx := 51 + righty := 10 + rightframe := 0 + leftfire := 0 + rightfire := 0 + + # draw background + clear + i := cactus + v0 := 28 + v1 := 9 + sprite v0 v1 15 + + i := edge + v0 := 0 + v1 := 31 + loop + sprite v0 v1 2 + v0 += 8 + if v0 != 64 then + again + + i := left + sprite leftx lefty 12 + i := right + sprite rightx righty 12 + + # main game loop + loop + move-left-player + if vf != 0 then jump leftdead + move-right-player + if vf != 0 then jump rightdead + + i := bullet + if leftfire != 0 then move-left-bullet + if leftfire == 0 then fire-left-bullet + if rightfire != 0 then move-right-bullet + again diff --git a/resources/octoroms/sinusoid.8o b/resources/octoroms/sinusoid.8o new file mode 100644 index 0000000..2d20452 --- /dev/null +++ b/resources/octoroms/sinusoid.8o @@ -0,0 +1,39 @@ +########################################### +# +# Sinusoid +# +# Demonstrate :calc and :macro by computing +# a sinusoidal lookup table at compile time. +# +# John Earnest +# +########################################### + +: main + hires + loop + scroll-down 2 + i := table + i += v2 + load v1 + i := thin + sprite v0 v3 2 + i := thick + sprite v1 v3 2 + v2 += 2 + again + +: thin 0x0F 0x0F +: thick 0xFF 0xFF + +: table + :macro S2 { + :calc rads { ( HERE - table ) * ( 2 * PI ) / 256 } + :byte { 56 + 38 * sin rads } + :byte { 56 + 16 * cos rads } + } + + # expand S2 2*8*8 times for a 256-byte table: + :macro S1 { S2 S2 S2 S2 S2 S2 S2 S2 } + :macro S0 { S1 S1 S1 S1 S1 S1 S1 S1 } + S0 S0 diff --git a/resources/octoroms/slippery.8o b/resources/octoroms/slippery.8o new file mode 100644 index 0000000..55064d3 --- /dev/null +++ b/resources/octoroms/slippery.8o @@ -0,0 +1,805 @@ +########################################### +# +# Slippery Slope +# +# built for Octojam 2018. +# level editor: http://beyondloom.com/tools/slipedit.html +# +# John Earnest +# +########################################### + +:const MODE-INPUT 0 +:const MODE-MOVE 1 +:const MODE-NEXT 2 +:const MODE-RESET 3 + +:const FINAL_LEVEL 0xA + +# v0-v2 are reserved as temporaries. +:alias px vD # player x position (tiles) +:alias py vC # player y position (tiles) +:alias pdir vB # player direction ( E N W S ) +:alias pmode vA # see MODE-XXX +:alias gx v9 # goal x position +:alias gy v8 # goal y position +:alias gf v7 # goal frame (0,5,10,15) +:alias level v6 # current level no. + +:alias move-dx v5 # x amount player moved this step +:alias move-dy v4 # y amount player moved this step +:alias move-dir v3 # temporary direction + +:alias load-ti vD # tile index +:alias load-tx vC # x position +:alias load-ty vB # y position + +:alias copy-off vE # when unpacking, offset +:alias copy-lvl vD # when unpacking, level index + +########################################### +# +# Utilities +# +########################################### + +:macro temp-begin { :calc there { HERE } :org 0 } +:macro temp-end { :org there } +:macro xor_ { :byte { ( @ a + HERE - to ) ^ @ b + HERE - to } } +:macro xor A B { :calc to { HERE } :calc a { A } :calc b { B } + xor_ xor_ xor_ xor_ xor_ } + +:macro sync N { + loop + vf := delay + if vf != 0 then + again + vf := N + delay := vf +} +:macro copy-2 SRC DST { + i := SRC load v1 + i := DST save v1 +} +:macro times-5 SRC DST { + DST := SRC + DST <<= DST + DST <<= DST + DST += SRC +} +:macro times-6 SRC DST { + DST := SRC + DST += SRC + DST += SRC + DST += DST +} +:macro to-tile SX SY DX DY { + times-5 SX DX DX += 2 + times-5 SY DY DY += 1 +} + +########################################### +# +# Step Counter +# +########################################### + +: step-total 0 0 # high 2 digits, low 2 digits +: step-level 0 0 +: step-bcd 0 0 0 + +:macro steps-clear { + v0 := 0 + v1 := 0 + i := step-total + save v1 + i := step-level + save v1 +} + +:macro steps-inc { + i := step-level + load v1 + v1 += 1 + if v1 == 100 begin + v0 += 1 + v1 := 0 + end + if v0 == 100 begin + # cap at 9999 + v1 := 99 + v0 := 99 + end + i := step-level + save v1 +} + +:macro steps-reset-level { copy-2 step-total step-level } +:macro steps-next-level { copy-2 step-level step-total } + +:macro steps-show-digits SRC { + i := SRC + load v0 + i := step-bcd + bcd v0 + load v2 + i := hex v1 + sprite v3 v4 5 + v3 += 5 + i := hex v2 + sprite v3 v4 5 + v3 += 5 +} +:macro steps-show { # at v3,v4 + steps-show-digits step-level + :calc low-digits { 1 + step-level } + steps-show-digits low-digits +} + +########################################### +# +# Level Representation +# +########################################### + +:const board-rows 6 +:const board-cols 12 +:calc board-size { board-rows * board-cols } +: board + 00 00 00 00 00 00 + 00 00 00 05 00 00 + 00 00 05 00 05 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + +: goal-position 10 03 # (x tiles, y tiles) +: start-position 02 03 # (x tiles, y tiles) + +: level-unpack-stash + 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 + +:macro level-base-addr { + v0 := copy-lvl + i := level-data + loop + while v0 != 1 + v0 += -1 + vf := 76 + i += vf + again +} +: level-unpack + # we need most of the registers for bulk copying, + # so stash the entire register file in a buffer: + vf := level + i := level-unpack-stash + save vf + + # copy tile data + copy-off := 0 # source/dest offset + copy-lvl := vf # level index + loop + level-base-addr + i += copy-off + load vb + + i := board + i += copy-off + save vb + + copy-off += 12 + if copy-off != 72 then + again + + # copy goal/start positions + level-base-addr + i += copy-off + load v3 + i := goal-position + save v3 + + i := level-unpack-stash + load vf +; + +########################################### +# +# Text +# +########################################### + +: let-A 0xF0 0xB0 0xF0 0xB0 +: let-D 0xE0 0xB0 0xB0 0xE0 +: let-E 0xF0 0xE0 0xC0 0xF0 +: let-G 0xF0 0xC0 0xD0 0xF0 +: let-H 0xB0 0xF0 0xB0 0xB0 +: let-I 0xC0 0x00 0xC0 0xC0 +: let-L 0xC0 0xC0 0xC0 0xE0 +: let-M 0xD8 0xE8 0xC8 0xC8 +: let-N 0xE0 0xF0 0xD0 0xD0 +: let-O 0xF0 0xB0 0xB0 0xF0 +: let-P 0xF0 0xB0 0xF0 0x80 +: let-R 0xF0 0xF0 0xA0 0x90 +: let-S 0xF0 0xE0 0x30 0xF0 +: let-T 0xF0 0x60 0x60 0x60 +: let-V 0xB0 0xB0 0xB0 0x60 +: let-Y 0xB0 0xF0 0x30 0xF0 + +:stringmode print " " { + v0 += 4 +} +:stringmode print "ADEGHILMNOPRSTVY" { + :calc S { let-A + VALUE * 4 } + i := S + sprite v0 v1 4 + # compute the width of each glyph statically: + :calc p { ( @ S ) | ( @ 1 + S ) | ( @ 2 + S ) | ( @ 3 + S ) } + :calc w { 9 - ( log p & - p ) / log 2 } + v0 += w +} + +:macro draw-title { + v0 := 14 + v1 := 4 + print "SLIPPERY" + v0 := 20 + v1 := 24 + print "SLOPE" +} + +:macro draw-gameover { + v0 := 15 + v1 := 12 + print "THE END" + v3 := 8 + v4 := 20 + steps-show + v0 := v3 + v1 := v4 + print " STEPS" +} + +:macro draw-levelno { + v0 := 17 + v1 := 12 + print "LEVEL " + i := hex level + sprite v0 v1 5 +} + +########################################### +# +# Player And Movement +# +########################################### + +: stand 0x20 0x70 0x70 0x30 0x20 + 0x20 0x70 0x70 0x70 0x50 + 0x20 0x70 0x70 0x60 0x20 + 0x20 0x70 0xF8 0x70 0x50 +: slide 0x20 0x38 0x30 0x38 0x48 + 0x20 0xF0 0x78 0xB0 0x90 + 0x20 0xE0 0x60 0xE0 0x90 + 0x20 0xF8 0x70 0x70 0x48 + +:macro draw-player { + times-5 pdir v0 + i += v0 + to-tile px py v0 v1 + sprite v0 v1 5 +} +:macro draw-stand { i := stand draw-player } +:macro draw-slide { i := slide draw-player } + +: deltas 1 0 0 -1 -1 0 0 1 +: dirs-\ 3 2 1 0 +: dirs-/ 1 0 3 2 + +:macro at-edge REG DELTA VAL { + if REG == VAL begin + REG -= DELTA + pmode := MODE-INPUT + end +} +:macro get-current-tile { + times-6 px v0 + v0 += py + i := board + i += v0 + load v0 + v1 := v0 +} +:macro set-current-tile { + times-6 px v0 + v0 += py + i := board + i += v0 + v0 := v1 + save v0 +} +:macro draw-current-tile { + i := tiles + i += v1 + times-5 px v0 + times-5 py v1 + v0 += 2 + v1 += 1 + sprite v0 v1 5 +} +:macro change-dir TABLE { + i := TABLE + i += pdir + load v0 + pdir := v0 +} +:macro move-player { + loop + # move in facing direction + i := deltas + i += pdir + i += pdir + + load v1 + move-dx := v0 + move-dy := v1 + px += move-dx + py += move-dy + + # out of bounds? + at-edge px move-dx -1 + at-edge px move-dx 12 + at-edge py move-dy -1 + at-edge py move-dy 6 + + # at goal? + to-tile px py v0 v1 + v0 ^= gx + v1 ^= gy + v0 |= v1 + if v0 == 0 then pmode := MODE-NEXT + + # check current cell (into v1) + get-current-tile + + if v1 == tile-wall begin + px -= move-dx + py -= move-dy + pmode := MODE-INPUT + end + + if v1 == tile-hole begin + pmode := MODE-RESET + end + + if v1 == tile-mir-\ begin + change-dir dirs-\ + end + + if v1 == tile-mir-/ begin + change-dir dirs-/ + end + + if v1 == tile-flip-\ begin + change-dir dirs-\ + draw-current-tile + v1 := tile-flop-/ + set-current-tile + draw-current-tile + v1 := 0 # avoid fallthrough! + end + + if v1 == tile-flop-/ begin + change-dir dirs-/ + draw-current-tile + v1 := tile-flip-\ + set-current-tile + draw-current-tile + v1 := 0 # avoid fallthrough! + end + + if v1 >= tile-ground begin + draw-current-tile + pmode := MODE-INPUT + end + + while pmode == MODE-MOVE + draw-slide + animate-goal + sync 5 + draw-slide + again +} + +:macro poll-key KEY DIR { + vf := KEY if vf key begin + pmode := MODE-MOVE + move-dir := DIR + end +} +:macro poll-player { + poll-key OCTO_KEY_D 0 + poll-key OCTO_KEY_W 1 + poll-key OCTO_KEY_A 2 + poll-key OCTO_KEY_S 3 + if pmode == MODE-MOVE begin + steps-inc + draw-stand + get-current-tile + if v1 >= tile-ground begin + draw-current-tile + end + pdir := move-dir + move-player + draw-stand + end + if level != 0 begin + vf := OCTO_KEY_E + if vf key then pmode := MODE-RESET + end +} + +########################################### +# +# Level Display +# +########################################### + +: line 0xFF # top and bottom edge +: corner 0x80 # 1px +: wall 0xC0 0xC0 0xC0 0xC0 0xC0 # 2x15 pixels + 0xC0 0xC0 0xC0 0xC0 0xC0 + 0xC0 0xC0 0xC0 0xC0 0xC0 + +:macro draw-border { + i := wall + v0 := 0 + v1 := 62 + v2 := 1 + sprite v0 v2 15 + sprite v1 v2 15 + v2 := 16 + sprite v0 v2 15 + sprite v1 v2 15 + + i := line + v1 := 0 + v2 := 31 + loop + sprite v0 v1 1 + sprite v0 v2 1 + v0 += 8 + if v0 != 64 then + again + + i := corner + v0 := 2 + v1 := 61 + v2 := 1 + sprite v0 v2 1 + sprite v1 v2 1 + v2 := 30 + sprite v0 v2 1 + sprite v1 v2 1 +} + +temp-begin +: tgoal-1 0x50 0x80 0x08 0x80 0x50 +: tgoal-2 0x50 0x88 0x00 0x88 0x20 +: tgoal-3 0x50 0x08 0x80 0x08 0x50 +temp-end +: goal-0 0x20 0x88 0x00 0x88 0x50 +: goal-1 xor goal-0 tgoal-1 +: goal-2 xor tgoal-1 tgoal-2 +: goal-3 xor tgoal-2 tgoal-3 +: goal-4 xor tgoal-3 goal-0 + +:macro init-goal { + gf := 0 + i := goal-0 + sprite gx gy 5 +} + +:macro animate-goal { + i := goal-1 + i += gf + sprite gx gy 5 + gf += 5 + if gf == 20 then gf := 0 +} + +: tiles 0x00 0x00 0x00 0x00 0x00 # empty space + 0xF8 0xF8 0xF8 0xF8 0xF8 :const tile-wall 5 + 0x88 0x50 0x20 0x50 0x88 :const tile-hole 10 + 0x80 0x40 0x20 0x10 0x08 :const tile-mir-\ 15 + 0x08 0x10 0x20 0x40 0x80 :const tile-mir-/ 20 + 0x80 0x60 0x50 0x30 0x08 :const tile-flip-\ 25 + 0x08 0x30 0x70 0x60 0x80 :const tile-flop-/ 30 + 0x50 0x88 0x88 0x88 0x70 :const tile-ground 35 + 0x58 0x80 0x80 0x80 0x78 + 0x88 0x88 0x88 0x88 0x70 + 0x80 0x80 0x80 0x80 0x78 + 0x50 0x08 0x08 0x08 0xF0 + 0x58 0x00 0x00 0x00 0xF8 + 0x08 0x08 0x08 0x08 0xF0 + 0x00 0x00 0x00 0x00 0xF8 + 0x50 0x88 0x88 0x88 0x88 + 0x58 0x80 0x80 0x80 0x80 + 0x88 0x88 0x88 0x88 0x88 + 0x80 0x80 0x80 0x80 0x80 + 0x50 0x08 0x08 0x08 0x08 + 0x58 0x00 0x00 0x00 0x00 + 0x08 0x08 0x08 0x08 0x08 + 0x00 0x00 0x00 0x00 0x00 + +:macro load-tile REG Y { + i := tiles + i += REG + load-ty := Y + sprite load-tx load-ty 5 +} +: load-level + clear + draw-border + load-ti := 0 + load-tx := 2 + loop + i := board + i += load-ti + load v5 + + load-tile v0 1 + load-tile v1 6 + load-tile v2 11 + load-tile v3 16 + load-tile v4 21 + load-tile v5 26 + + load-tx += 5 + load-ti += board-rows + if load-ti != board-size then + again + i := goal-position + load v3 + to-tile v0 v1 gx gy + init-goal + + px := v2 + py := v3 + pdir := 3 + pmode := MODE-INPUT + draw-stand +; + +:macro try-key KEY { + vf := KEY + while vf -key +} +:macro wait-key { + v4 := random 3 + i := deltas + i += v4 + i += v4 + load v1 + v0 += v0 + v2 := random 63 + v3 := random 31 + i := slide + i += v4 + i += v4 + i += v4 + i += v4 + i += v4 + sprite v2 v3 5 + loop + sprite v2 v3 5 + v2 += v0 + v3 += v1 + sprite v2 v3 5 + try-key OCTO_KEY_E + try-key OCTO_KEY_A + try-key OCTO_KEY_S + try-key OCTO_KEY_W + try-key OCTO_KEY_D + again +} + +########################################### +# +# Main +# +########################################### + +: main + load-level + draw-title + + loop + loop + poll-player + while pmode == MODE-INPUT + animate-goal + sync 5 + again + + if pmode == MODE-RESET begin + steps-reset-level + level-unpack + load-level + end + + if pmode == MODE-NEXT begin + clear + if level == FINAL_LEVEL begin + level := 1 + draw-gameover + steps-clear + steps-inc # start screen takes 1 move + else + level += 1 + draw-levelno + end + steps-next-level + level-unpack + wait-key + load-level + end + again + +########################################### +# +# Level Data +# +########################################### + +: level-data +: level-1 # just walls and sliding + 05 05 05 00 00 00 + 05 00 00 00 00 00 + 05 00 00 00 00 00 + 00 00 05 00 00 05 + 00 00 05 00 00 05 + 05 05 05 00 00 05 + 00 00 00 00 00 05 + 00 00 00 05 05 05 + 00 00 00 00 00 05 + 05 00 00 00 00 00 + 05 00 00 00 05 00 + 05 05 05 05 05 00 + 10 03 04 01 +: level-2 # more walls and sliding + 00 00 00 00 00 05 + 00 05 00 00 00 05 + 05 00 00 00 00 05 + 05 00 00 00 05 05 + 05 05 00 00 05 05 + 00 00 00 00 00 05 + 05 05 00 00 00 05 + 05 00 00 00 00 05 + 05 00 00 00 05 05 + 05 00 00 00 00 05 + 00 00 00 00 00 05 + 00 00 00 00 05 05 + 05 00 01 04 + +: level-3 # introduce mirrors + 05 05 05 05 05 05 + 05 05 00 00 00 05 + 05 05 00 00 00 05 + 05 00 00 00 00 05 + 05 00 00 20 00 00 + 05 00 00 00 00 00 + 05 05 00 00 00 05 + 05 05 05 00 05 05 + 05 05 00 00 00 05 + 05 05 00 00 00 05 + 05 05 00 00 00 05 + 05 05 05 05 05 05 + 09 03 02 03 +: level-4 # many mirrors + 00 00 00 00 00 00 + 00 00 00 00 00 20 + 15 00 00 00 00 00 + 00 05 00 00 00 00 + 00 00 00 00 15 00 + 00 20 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 15 00 00 05 00 20 + 00 15 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 15 00 00 + 10 03 01 01 +: level-5 # mild mirror maze + 00 20 00 00 15 00 + 00 00 00 00 00 00 + 00 00 00 00 00 20 + 15 00 00 00 00 00 + 20 00 00 00 00 00 + 15 00 15 00 00 20 + 20 20 15 20 00 15 + 15 00 00 00 00 20 + 20 20 00 00 00 15 + 15 00 00 15 00 20 + 10 20 15 00 00 15 + 00 20 15 20 15 20 + 11 00 00 02 + +: level-6 # introduce ground + 10 10 10 10 10 10 + 10 00 00 00 00 10 + 10 00 00 00 00 10 + 10 00 00 00 00 10 + 10 00 00 00 00 10 + 10 00 80 50 00 10 + 10 00 95 65 00 10 + 10 00 00 00 00 10 + 10 00 00 00 00 10 + 10 00 00 00 00 10 + 10 00 00 00 00 10 + 10 10 10 10 10 10 + 09 03 02 02 +: level-7 # good clean fun with ground + mirrors + 00 00 00 55 00 00 + 00 00 00 00 00 05 + 05 15 00 00 00 00 + 00 00 00 20 00 75 + 00 00 00 00 00 00 + 05 05 05 00 00 00 + 05 05 05 00 20 00 + 05 20 00 00 20 00 + 00 00 00 15 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 90 50 00 10 00 20 + 03 00 08 00 + +: level-8 # introduce flip-flops + 05 05 05 05 05 05 + 05 05 05 05 05 05 + 05 05 05 00 05 05 + 05 05 05 00 05 05 + 05 00 00 30 00 00 + 05 05 00 00 05 05 + 05 05 00 00 05 05 + 00 00 25 00 00 05 + 05 05 00 05 05 05 + 05 05 00 05 05 05 + 05 05 05 05 05 05 + 05 05 05 05 05 05 + 09 02 02 03 +: level-9 # mirror maze with a few flip-flops + 15 20 00 00 20 15 + 00 00 15 00 35 00 + 20 00 00 00 00 20 + 00 15 00 00 00 15 + 00 30 00 20 00 00 + 45 00 00 00 00 20 + 00 20 15 20 00 00 + 00 00 00 00 25 00 + 20 00 20 00 00 20 + 00 00 00 20 35 00 + 00 00 00 00 15 00 + 20 15 00 20 00 20 + 02 02 10 01 +: level-A # many flip-flops + 00 00 10 05 05 00 + 00 00 00 10 05 00 + 05 05 00 00 00 00 + 50 00 25 00 00 20 + 70 00 30 00 00 15 + 70 00 30 30 00 20 + 70 00 30 30 00 15 + 70 00 25 00 00 20 + 70 00 30 25 00 15 + 65 00 30 00 00 20 + 00 00 05 00 00 00 + 00 00 05 00 00 00 + 00 05 11 01 diff --git a/resources/octoroms/snowdaze.8o b/resources/octoroms/snowdaze.8o new file mode 100644 index 0000000..a9029dd --- /dev/null +++ b/resources/octoroms/snowdaze.8o @@ -0,0 +1,382 @@ +########################################### +# +# Snow Daze +# +# Clear all the snow off your driveway +# before you're late for work! +# Press ASWD to move around the driveway +# and press E to shovel snow behind you. +# Runs best at 100 cycles/frame. +# +# Created for the 2015 CCP Game Jam +# Theme: Winter +# +########################################### + +:alias px va +:alias py vb +:alias dir vc +:alias frame vd +:alias timer v9 +:alias timerx v8 +:alias endflag v7 + +:const LEFT 45 +:const RIGHT 0 +:const TICK_TIME 8 +:const SNOWFALL 8 + +: draw-image + v0 := 0 + v1 := 0 + v2 := 32 + loop + sprite v0 v1 0 + i += v2 + v0 += 16 + if v0 == 128 begin + v0 := 0 + v1 += 16 + end + if v1 != 64 then + again +; + +: draw-player + i := person-r + i += dir + i += frame + sprite px py 15 +; + +: do-snow + i := snow + v3 := 0 + loop + v1 := random 0b111111 + v1 += 32 + v2 := random 0b11111 + v2 += 16 + sprite v1 v2 15 + v0 := 5 wait + v3 += 1 + if v3 != SNOWFALL then + again +; + +: do-scoop + frame := 15 + draw-player + v0 := 5 gamewait + draw-player + frame := 30 + draw-player + v0 := 5 gamewait + draw-player + frame := 0 + + v1 := py + i := snow + + :macro scoop DELTA1 DELTA2 { + v0 := px + v0 += DELTA1 + sprite v0 v1 15 + if vf == 0 begin + sprite v0 v1 15 + else + v0 += DELTA2 + sprite v0 v1 15 + if vf == 1 then sprite v0 v1 15 + end + } + if dir == LEFT begin + scoop -8 16 + else + scoop 8 -16 + end +; + +: move-player + vf := 5 if vf key begin + if py != 10 then py += -1 + end + vf := 8 if vf key begin + if py != 0x31 then py += 1 + end + vf := 7 if vf key begin + px += -1 + dir := LEFT + end + vf := 9 if vf key begin + px += 1 + dir := RIGHT + end + vf := 6 if vf key then do-scoop +; + +: countdown + if timer == 0 begin + timer := TICK_TIME + vf := 4 + i := timeslice + sprite timerx vf 3 + timerx += -1 + if timerx == 3 then endflag := 1 + else + timer += -1 + end +; + +: gamewait + loop + sync + countdown + v0 += -1 + if v0 != 0 then + again +; + +: wait + loop + sync + v0 += -1 + if v0 != 0 then + again +; + +: game-over + draw-player + v0 := 20 wait + + v1 := 32 + v2 := 15 + v3 := 0 + i := block + loop + sprite v1 v2 0 + if vf != 0 then v3 += 1 + v0 := 5 wait + sprite v1 v2 0 + v1 += 16 + if v1 == 96 begin + v1 := 32 + v2 += 16 + end + if v2 != 63 then + again + i := bighex v3 + v1 := 60 + v2 := 14 + sprite v1 v2 10 + + v0 := 20 wait + v0 := key + setup +; + +: sync + loop + vf := delay + if vf != 0 then + again + vf := 2 + delay := vf +; + +: intro-num + i := bighex v0 + v1 := 60 + v2 := 14 + sprite v1 v2 10 + v0 := 10 wait + sprite v1 v2 10 +; + +: setup + clear + i := background + draw-image + timerx := 123 + timer := 0 + px := 64 + py := 32 + endflag := 0 + draw-player + do-snow + v0 := 10 wait + v0 := 3 intro-num + v0 := 2 intro-num + v0 := 1 intro-num +; + +: main + hires + setup + loop + draw-player + move-player + draw-player + countdown + if endflag == 1 then game-over + sync + again + +: timeslice + 0x80 0x80 0x80 +: block + 0x00 0x00 0x7F 0xFE 0x7F 0xFE 0x7F 0xFE + 0x7F 0xFE 0x7F 0xFE 0x7F 0xFE 0x7F 0xFE + 0x7F 0xFE 0x7F 0xFE 0x7F 0xFE 0x7F 0xFE + 0x7F 0xFE 0x7F 0xFE 0x7F 0xFE 0x00 0x00 +: snow + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x7E 0x7E 0x7E 0x00 +: person-r + 0x38 0x38 0x28 0x3C 0x78 0x70 0x78 0x78 + 0xF8 0xF8 0xFB 0x7F 0x4F 0x4B 0x6C +: scoop1-r + 0x00 0x1C 0x1C 0x14 0x1E 0x7C 0xF8 0xF8 + 0xFC 0xFC 0xFC 0x7F 0x4F 0x4F 0x6F +: scoop2-r + 0xC0 0xCE 0x4E 0x6A 0x7F 0xFE 0x78 0x7E + 0x7C 0xF8 0xF8 0xF8 0x38 0x48 0x6C +: person-l + 0x1C 0x1C 0x14 0x3C 0x1E 0x0E 0x1E 0x1E + 0x1F 0x1F 0xDF 0xFE 0xF2 0xD2 0x36 +: scoop1-l + 0x00 0x38 0x38 0x28 0x78 0x3E 0x1F 0x1F + 0x3F 0x3F 0x3F 0xFE 0xF2 0xF2 0xF6 +: scoop2-l + 0x03 0x73 0x72 0x56 0xFE 0x7F 0x1E 0x7E + 0x3E 0x1F 0x1F 0x1F 0x1C 0x12 0x36 + +: background # (1024 bytes) + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xE0 0x00 + 0xEF 0xFF 0xEF 0xFF 0xEF 0xFF 0xE0 0x00 + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFE 0xFF 0xFE 0xFF 0xFF 0x00 0x00 + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 + 0xFF 0xFF 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE + 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE + 0x00 0x00 0x00 0x00 0xFF 0xFF 0x00 0x00 + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 + 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0xFF 0xFF 0x00 0x00 + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 + 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0xFF 0xFF 0x00 0x00 + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 + 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0xFF 0xFF 0x00 0x00 + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 + 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x7F 0xFF 0x7F 0xFF 0xFF 0xFF 0x00 0x00 + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 + 0xFF 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF + 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x07 + 0xFF 0xF7 0xFF 0xF7 0xFF 0xF7 0x00 0x07 + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE + 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE + 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE + 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF + 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF + 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF + 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE + 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE + 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE + 0xFF 0xFE 0xFF 0xFE 0xFF 0xFC 0xFF 0xFE + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF + 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF + 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF + 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFE + 0xFF 0xFF 0xFF 0xFF 0xF8 0xFB 0x00 0x00 + 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE + 0xFF 0xFC 0xFF 0xFC 0xFF 0xEE 0xFF 0xFE + 0xFF 0xFE 0xFF 0xFE 0xFF 0xFC 0xFF 0xF8 + 0xFF 0xB8 0xFF 0xF0 0x8F 0xC0 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x5F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF + 0x3F 0xFF 0x5F 0xFF 0x7F 0xFF 0x7F 0xFF + 0x3F 0xFF 0x3E 0xFF 0x3F 0xFF 0x1F 0xFF + 0x0F 0xDF 0x01 0xFF 0x00 0x3D 0x00 0x00 + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x7F + 0xFF 0xFF 0xFF 0xFF 0xFE 0x1F 0x00 0x00 diff --git a/resources/octoroms/sweetcopter.8o b/resources/octoroms/sweetcopter.8o new file mode 100644 index 0000000..6b49060 --- /dev/null +++ b/resources/octoroms/sweetcopter.8o @@ -0,0 +1,188 @@ +########################################### +# +# Sw8 Copter +# +# An adaptation of "Swing Copters" +# for the Super Chip8. +# Runs best at 100 cycles/frame. +# +# Press E to start a game and then +# press E to switch directions. +# Avoid obstacles! +# +########################################### + +:alias score v7 +:alias collide v8 +:alias player-key v9 +:alias player-x va +:alias player-y vb +:alias player-frame vc +:alias player-dir vd + +:const H_SPEED 3 +:const BUTTON 6 + +: sync + loop + vf := delay + if vf != 0 then + again + vf := 2 + delay := vf +; + +: girders + i := girder + v0 := 88 + v1 := 8 + loop + sprite v0 v1 0 + v0 += 16 + if v0 != 168 then + again +; + +: draw-copter + i := face-l + if player-dir == H_SPEED then i := face-r + collide := 0 + sprite player-x player-y 0 + collide |= vf + i := blade-0 + if player-frame == 1 then i := blade-1 + v0 := 16 + v0 =- player-y + sprite player-x v0 0 + collide |= vf +; + +: wait-release + if v0 key then return + player-key := 0 +; + +: switch-dir + v0 := BUTTON + if player-key != 0 then jump wait-release + if v0 -key then return + player-key := 1 + + # (~x)+1 = -x + v0 := 0xFF + player-dir ^= v0 + player-dir += 1 +; + +: move-up + player-y += -1 + v0 := 63 + v0 &= player-y + if v0 == 0 then score += 1 +; + +: move-copter + v0 := 1 + player-frame ^= v0 + move-up + v0 := random 1 + if v0 == 1 then move-up + player-x += player-dir + switch-dir +; + +: wait-key + v0 := 56 + v1 := 18 + i := tapbubble + sprite v0 v1 0 + vf := BUTTON + loop + if vf -key then + again + sprite v0 v1 0 +; + +: game-over + vf := 16 + buzzer := vf + delay := vf + loop + draw-copter + scroll-left + draw-copter + draw-copter + scroll-right + draw-copter + draw-copter + scroll-right + draw-copter + draw-copter + scroll-left + draw-copter + vf := delay + if vf != 0 then + again + +: show-score + i := bcd-buffer + bcd score + load v2 + i := bighex v1 + v0 := 55 + v1 := 30 + sprite v0 v1 10 + i := bighex v2 + v0 += 9 + sprite v0 v1 10 + vf := BUTTON + loop + if vf -key then + again + clear + +: main + hires + player-x := 56 + player-y := 48 + player-dir := H_SPEED + player-key := 0 + score := 0 + + girders + draw-copter + wait-key + + loop + draw-copter + move-copter + draw-copter + if collide != 0 then jump game-over + sync + again + +: bcd-buffer 0 0 0 + +: blade-0 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x01 0x80 0x02 0x40 0x7A 0x5E 0x89 0x91 0xF0 0x0F 0x01 0x80 0x01 0x80 0x00 0x00 + +: blade-1 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x01 0x80 0x02 0x40 0x0E 0xF0 0x31 0x0C 0x3E 0xFC 0x01 0x80 0x01 0x80 0x00 0x00 + +: face-r + 0x07 0xC0 0x18 0x30 0x20 0x08 0x23 0xB8 0x44 0x44 0x48 0x8A 0x48 0x02 0x48 0x02 + 0x34 0x44 0x23 0xB8 0x30 0x08 0x4B 0xF4 0x48 0x14 0x30 0x18 0x11 0x20 0x0F 0xC0 + +: face-l + 0x03 0xE0 0x0C 0x18 0x10 0x04 0x1D 0xC4 0x22 0x22 0x51 0x12 0x40 0x12 0x40 0x12 + 0x22 0x2C 0x1D 0xC4 0x10 0x0C 0x2F 0x92 0x28 0x12 0x18 0x0C 0x04 0x88 0x03 0xF0 + +: girder + 0xFF 0xFF 0x00 0x00 0xC3 0xC3 0x7E 0x7E 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C 0x7E 0x7E + 0xFF 0xFF 0x00 0x00 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + +: tapbubble + 0x3F 0xFC 0x7F 0xFE 0xFF 0xFF 0xF0 0x0F 0xF0 0x0F 0xF3 0xFF 0xF0 0x7F 0xF0 0x7F + 0xF3 0xFF 0xF0 0x0F 0xF0 0x0F 0xFF 0xFF 0x7F 0xFE 0x3F 0xFC 0x00 0xC0 0x00 0x80 diff --git a/resources/octoroms/tank.8o b/resources/octoroms/tank.8o new file mode 100644 index 0000000..354acb0 --- /dev/null +++ b/resources/octoroms/tank.8o @@ -0,0 +1,39 @@ +########################################### +# +# Tank +# +# Classic Chip8 program translated from +# VIPer Volume 1 Issue 1 (June 1978), pg 12-14 +# https://github.com/mattmikolay/viper/blob/master/volume1/issue1.pdf +# +# Press 2/E/S/Q to move the tank. +# +########################################### + +: tankup + 0x10 0x54 0x7c 0x6c 0x7c 0x7c +: tankdown + 0x44 0x7c 0x7c 0x6c 0x7c 0x54 0x10 +: tankleft + 0x0 0xfc 0x78 0x6e 0x78 0xfc +: tankright + 0x0 0x3f 0x1e 0x76 0x1e 0x3f 0x0 + +: up v2 += -1 i := tankup ; +: down v2 += 1 i := tankdown ; +: right v1 += -1 i := tankright ; +: left v1 += 1 i := tankleft ; + +: main + v1 := 0x20 + v2 := 0x10 + i := tankup + loop + sprite v1 v2 7 + v0 := key + sprite v1 v2 7 + if v0 == 2 then up + if v0 == 4 then right + if v0 == 6 then left + if v0 == 8 then down + again diff --git a/resources/octoroms/tests/testbigfont.8o b/resources/octoroms/tests/testbigfont.8o new file mode 100644 index 0000000..eb9468d --- /dev/null +++ b/resources/octoroms/tests/testbigfont.8o @@ -0,0 +1,23 @@ +########################################### +# +# Big Font +# +# High resolution font test program. +# Draw the complete SuperChip high res +# hex character set. +# +########################################### + +: main + hires + loop + i := bighex v0 + sprite v1 v2 10 + v1 += 9 + v0 += 1 + if v0 == 8 then v1 := 0 + if v0 == 8 then v2 += 11 + if v0 != 16 then + again + + loop again diff --git a/resources/octoroms/tests/testbranch.8o b/resources/octoroms/tests/testbranch.8o new file mode 100644 index 0000000..e4e648a --- /dev/null +++ b/resources/octoroms/tests/testbranch.8o @@ -0,0 +1,72 @@ +########################################### +# +# Branch Test +# +# Tests the if...begin...else...then +# control structure. +# Should print "51368" +# +########################################### + +: main + # simple taken branch + v0 := 1 + v1 := 3 + if v1 == 3 begin + v0 := 2 + v0 += 3 + end + print0 + + # simple not taken branch + v0 := 1 + v1 := 3 + if v1 != 3 begin + v0 := 2 + v0 += 3 + end + print0 + + # else taken + v0 := 2 + v1 := 3 + if v1 != v0 begin + v0 := 1 + v0 += 2 + else + v0 := 2 + v0 += 4 + end + print0 + + # else not taken + v0 := 2 + v1 := 3 + if v1 < v0 begin + v0 := 1 + v0 += 2 + else + v0 := 2 + v0 += 4 + end + print0 + + # nesting + v0 := 1 + if v0 != 0 begin + if v0 != 2 begin + v0 := 7 + else + v0 := 3 + end + v0 += 1 + end + print0 + + loop again + +: print0 + i := hex v0 + sprite va vb 5 + va += 5 +; diff --git a/resources/octoroms/tests/testcollide.8o b/resources/octoroms/tests/testcollide.8o new file mode 100644 index 0000000..4c0c521 --- /dev/null +++ b/resources/octoroms/tests/testcollide.8o @@ -0,0 +1,32 @@ +########################################### +# +# Collision Detection Test +# +# Draws two overlapping sprites and +# displays the contents of the vF register. +# Should print "1". +# +########################################### + +: square + 0b11110000 + 0b11110000 + 0b11110000 + 0b11110000 + +: main + v0 := 20 + v1 := 10 + i := square + + sprite v0 v1 4 + v0 += 2 + v1 += 2 + sprite v0 v1 4 + + v2 := vf + v0 += 10 + i := hex v2 + sprite v0 v1 5 + + loop again diff --git a/resources/octoroms/tests/testcompare.8o b/resources/octoroms/tests/testcompare.8o new file mode 100644 index 0000000..a3f1b98 --- /dev/null +++ b/resources/octoroms/tests/testcompare.8o @@ -0,0 +1,70 @@ +########################################### +# +# Numeric Comparison Tests +# +# Exercises all combinations of +# register-to-register and register-to-constant +# comparisons with the synthetic pseudo-ops +# < > <= and >= +# +########################################### + +: print + i := hex v0 + sprite va vb 5 + va += 5 + v0 := 0 +; + +: newline + va := 0 + vb += 6 +; + +: greater? if v1 > v2 then v0 := 1 print ; +: greater5? if v1 > 5 then v0 := 1 print ; +: less? if v1 < v2 then v0 := 1 print ; +: less5? if v1 < 5 then v0 := 1 print ; +: greatere? if v1 >= v2 then v0 := 1 print ; +: greatere5? if v1 >= 5 then v0 := 1 print ; +: lesse? if v1 <= v2 then v0 := 1 print ; +: lesse5? if v1 <= 5 then v0 := 1 print ; + +: main + # 001001 + v1 := 3 v2 := 5 greater? + v1 := 3 v2 := 3 greater? + v1 := 5 v2 := 3 greater? + v1 := 3 greater5? + v1 := 5 greater5? + v1 := 7 greater5? + newline + + # 100100 + v1 := 3 v2 := 5 less? + v1 := 3 v2 := 3 less? + v1 := 5 v2 := 3 less? + v1 := 3 less5? + v1 := 5 less5? + v1 := 7 less5? + newline + + # 011011 + v1 := 3 v2 := 5 greatere? + v1 := 3 v2 := 3 greatere? + v1 := 5 v2 := 3 greatere? + v1 := 3 greatere5? + v1 := 5 greatere5? + v1 := 7 greatere5? + newline + + # 110110 + v1 := 3 v2 := 5 lesse? + v1 := 3 v2 := 3 lesse? + v1 := 5 v2 := 3 lesse? + v1 := 3 lesse5? + v1 := 5 lesse5? + v1 := 7 lesse5? + + loop again + diff --git a/resources/octoroms/tests/testloop.8o b/resources/octoroms/tests/testloop.8o new file mode 100644 index 0000000..689efdd --- /dev/null +++ b/resources/octoroms/tests/testloop.8o @@ -0,0 +1,66 @@ +########################################### +# +# Loop Construct Tests +# +# Tests boundary conditions using `if` +# and `while` with simple and synthetic +# comparison operators. +# Should draw 5 vertical strips of 6 boxes. +# +########################################### + +: main + # while with pseudo-op + v0 := 0 + v1 := 0 + loop + while v1 < 30 + sprite v0 v1 5 + v1 += 5 + again + + # while with simple comparison + v0 := 5 + v1 := 0 + loop + while v1 != 30 + sprite v0 v1 5 + v1 += 5 + again + + # if with pseudo-op + v0 := 10 + v1 := 0 + loop + if v1 >= 30 then jump done1 + sprite v0 v1 5 + v1 += 5 + again + : done1 + + # if with simple comparison + v0 := 15 + v1 := 0 + loop + if v1 == 30 then jump done2 + sprite v0 v1 5 + v1 += 5 + again + : done2 + + # nested loops with while + v0 := 20 + v1 := 0 + loop + while v1 != 25 + sprite v0 v1 5 + v1 += 5 + v2 := 5 + loop + v2 += -1 + if v2 != 0 then + again + again + sprite v0 v1 5 + + loop again diff --git a/resources/octoroms/tests/testnext.8o b/resources/octoroms/tests/testnext.8o new file mode 100644 index 0000000..2742c71 --- /dev/null +++ b/resources/octoroms/tests/testnext.8o @@ -0,0 +1,34 @@ +########################################### +# +# Next Test +# +# Demonstrates the use of the :next +# operative to refer to the second byte +# of an instruction. Mainly used for +# writing self-modifying code. +# +########################################### + +: lt v0 := -1 i := vx save v0 ; +: rt v0 := 1 i := vx save v0 ; + +: up v0 := -1 i := vy save v0 ; +: dn v0 := 1 i := vy save v0 ; + +: main + va := 2 + vb := 8 + + loop + clear + i := hex vc + sprite va vb 5 + + :next vx va += 1 + :next vy vb += 1 + + if va == 0 then rt + if va == 59 then lt + if vb == 0 then dn + if vb == 26 then up + again diff --git a/resources/octoroms/tests/testquirks.8o b/resources/octoroms/tests/testquirks.8o new file mode 100644 index 0000000..af6a1da --- /dev/null +++ b/resources/octoroms/tests/testquirks.8o @@ -0,0 +1,66 @@ +########################################### +# +# Quirks Mode Tests +# +# Examines the behavior of operations +# which have multiple interpretations +# in the wild and demonstrates the +# distinction between Octo's defaults +# and quirks modes for each instruction. +# +########################################### + +: buffer 0 3 + +: main + # Perform a shift where source and dest + # differ. The correct behavior will draw a 1 + # while in-place vx modification will draw 2. + v0 := 4 + v1 := 2 + v0 >>= v1 + i := hex v0 + va := 5 + sprite va va 5 + + # perform a repeated store and load. + # the correct behavior should print 3 due to i autoincrements. + # quirks mode will print 4. + i := buffer + v0 := 4 + save v0 + v0 := 9 # just clobber v0 in case + load v0 + i := hex v0 + vb := 12 + sprite va vb 5 + + # perform an arithmetic operation which stores to vf. + # the correct behavior should write the carry flag last, resulting in 0. + # quirks mode will print 6. + vf := 3 + vf <<= vf + i := hex vf + vb := 19 + sprite va vb 5 + + # try a jump0 instruction. + # the correct behavior should respect the value of v0 as an offset, resulting in 7 + # quirks mode will respect v2 instead (in this case), resulting in 8. + v0 := 8 + v2 := 4 + jump0 jump-table + +: jump-table + 0x00 0x00 0x00 0x00 + vf := 8 jump show-jump0-result + vf := 7 jump show-jump0-result + 0x00 0x00 0x00 0x00 + +: show-jump0-result + i := hex vf + va := 10 + vb := 5 + sprite va vb 5 + + loop again diff --git a/resources/octoroms/tests/testunpack.8o b/resources/octoroms/tests/testunpack.8o new file mode 100644 index 0000000..4fd1535 --- /dev/null +++ b/resources/octoroms/tests/testunpack.8o @@ -0,0 +1,69 @@ +########################################### +# +# Unpacking Tests +# +# Uses the :unpack operative to perform +# self-modification and rewrite an +# i := NNN instruction. +# +########################################### + +: font + 0x20 0x20 0x20 0x00 0x20 0xF0 0x10 0x70 0x00 0x40 0xE0 0x90 0xE0 0x90 0x90 0x90 + 0xE0 0x90 0xE0 0x90 0xE0 0x80 0x80 0xD0 0xB0 0xB0 0x90 0x90 0x90 0x90 0x60 0x60 + 0x90 0x90 0x90 0x60 0x90 0xD0 0xB0 0x90 0x90 0x90 0x50 0x20 0x40 0x00 0x00 0x00 + 0x00 0x00 0x60 0x90 0xF0 0x90 0x90 0xF0 0x90 0x90 0xF0 0x80 0xE0 0x80 0x80 0x80 + 0x80 0xF0 0x80 0xE0 0x80 0xF0 0x40 0x40 0x40 0xF0 0x20 0x40 0x80 0xF0 0x20 0x20 + 0x20 0xC0 0x60 0x90 0x80 0x90 0x60 0x90 0x90 0xB0 0x70 0x80 0xB0 0x90 0x70 0x80 + 0x60 0x10 0xE0 0x90 0xA0 0xC0 0xA0 0x90 0x90 0xB0 0xB0 0xD0 0xF0 0x40 0x40 0x40 + 0x40 0x90 0x90 0x70 0x10 0xE0 + +# draw and linewrap a string at an address given +# in the v0-v1 registers. The string will consist +# of a sequence of offsets into the font data: + +: display-string + i := string-addr + save v1 + v1 := 2 # character x + v2 := 1 # character y + v3 := 0 # byte index + # v4 contains string length + loop + : string-addr 0 0 + i += v3 + load v0 + i := font + i += v0 + sprite v1 v2 5 + v1 += 5 + if v1 == 62 then v2 += 6 + if v1 == 62 then v1 := 2 + v3 += 1 + if v3 != v4 then + again +; + +: demo-string + 0x71 0x1F 0x1A 0x2D 0x35 0x41 0x32 0x0A 0x2D 0x2D 0x2D 0x2D 0x32 0x2D 0x0A 0x1A + 0x17 0x10 0x3D 0x41 0x2D 0x45 0x24 0x2D 0x6C 0x35 0x41 0x2D 0x0C 0x45 0x5E 0x6C + 0x32 0x24 0x52 0x41 +:const demo-string-length 36 + +# these constants demonstrate all the valid opcodes +# which can be built with the high nybble in :unpack +:const JUMP 0x1 # jump