From 19d80a3531f96ebd9775dc3967cd85d1d8b33774 Mon Sep 17 00:00:00 2001 From: CoolElectronics Date: Mon, 10 Jul 2023 16:28:58 -0400 Subject: [PATCH] implement proper savestates --- Cargo.lock | 107 ++++++++++------- core/Cargo.toml | 3 +- core/src/assign_skipped_consts.rs | 146 +++++++++++++++++++++++ core/src/lib.rs | 186 ++++++++++++++++++++++++------ core/src/memory.rs | 26 +++-- core/src/objects/balloon.rs | 9 +- core/src/objects/bigchest.rs | 8 +- core/src/objects/chest.rs | 9 +- core/src/objects/fakewall.rs | 10 +- core/src/objects/fallfloor.rs | 11 +- core/src/objects/flag.rs | 10 +- core/src/objects/flyfruit.rs | 11 +- core/src/objects/fruit.rs | 11 +- core/src/objects/key.rs | 11 +- core/src/objects/lifeup.rs | 10 +- core/src/objects/message.rs | 8 +- core/src/objects/orb.rs | 8 +- core/src/objects/platform.rs | 8 +- core/src/objects/player.rs | 10 +- core/src/objects/playerspawn.rs | 8 +- core/src/objects/roomtitle.rs | 8 +- core/src/objects/smoke.rs | 8 +- core/src/objects/spring.rs | 11 +- core/src/objects/template.rs | 4 +- core/src/structures.rs | 19 ++- standalone/src/main.rs | 14 +++ t | 0 web/index.html | 6 +- web/main.js | 8 +- web/src/lib.rs | 37 ++++-- 30 files changed, 520 insertions(+), 205 deletions(-) create mode 100644 core/src/assign_skipped_consts.rs create mode 100644 t diff --git a/Cargo.lock b/Cargo.lock index fb715a1..503173c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,9 +10,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bumpalo" -version = "3.10.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "cfg-if" @@ -32,9 +32,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.7" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "js-sys", @@ -49,11 +49,17 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "itoa" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" + [[package]] name = "js-sys" -version = "0.3.57" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -66,39 +72,42 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.135" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "ppv-lite86" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.18" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ "proc-macro2", ] @@ -143,6 +152,7 @@ dependencies = [ "lazy_static", "rand", "serde", + "serde_json", ] [[package]] @@ -163,6 +173,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "ryu" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" + [[package]] name = "sdl2" version = "0.35.2" @@ -188,29 +204,40 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.147" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.147" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "serde_json" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "syn" -version = "1.0.96" +version = "2.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" dependencies = [ "proc-macro2", "quote", @@ -219,15 +246,15 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" [[package]] name = "version-compare" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe88247b92c1df6b6de80ddc290f3976dbdf2f5f5d3fd049a9fb598c6dd5ca73" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" [[package]] name = "wasi" @@ -237,9 +264,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.80" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -247,13 +274,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.80" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", - "lazy_static", "log", + "once_cell", "proc-macro2", "quote", "syn", @@ -262,9 +289,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.80" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -272,9 +299,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.80" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", @@ -285,6 +312,6 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.80" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" diff --git a/core/Cargo.toml b/core/Cargo.toml index 7f9d931..3fc42bb 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -8,4 +8,5 @@ hex = "*" lazy_static= "*" rand = {version= "*",features=["serde"]} getrandom = {version = "*", features = ["js"]} -serde = {version = "*", features=["derive","rc"]} \ No newline at end of file +serde = {version = "*", features=["derive","rc"]} +serde_json = "*" diff --git a/core/src/assign_skipped_consts.rs b/core/src/assign_skipped_consts.rs new file mode 100644 index 0000000..b610d67 --- /dev/null +++ b/core/src/assign_skipped_consts.rs @@ -0,0 +1,146 @@ +use crate::objects::orb::Orb; +// ok let me explain +// first of all, each "Object" needs to have an update and draw function. this is to keep things +// accurate to the original cart. +// +// you would think to use dyn traits for this, but that's actually not possible because safely +// downcasting would be impossible +// +// so each "Object" holds a function pointer, and a string of that name, used for formatting +// +// this is normally perfectly fine, but serde can't handle function pointers +// giving rise to this +// +// i could use rust macros, but for a project like this i didn't feel like learning them +// here's the javascript i used to generate it +// +// +// console.log(["","Balloon","BigChest","Chest","FakeWall","FallFloor","Flag","FlyFruit","Fruit","Key","LifeUp","Messsage","Orb","Platform","Player","PlayerSpawn","RoomTitle","Smoke","Spring"].reduce((p,n)=>p+` +// ObjectType::${n}(_)=>{ +// obj.draw = ObjFunc(${n}::draw); +// obj.update = ObjFunc(${n}::update); +// obj.name = "${n}" +// } +// `)) +// +// +// +use crate::objects::{ + balloon::Balloon, bigchest::BigChest, chest::Chest, fakewall::FakeWall, fallfloor::FallFloor, + flag::Flag, flyfruit::FlyFruit, fruit::Fruit, key::Key, lifeup::LifeUp, message::Message, + platform::Platform, player::Player, playerspawn::PlayerSpawn, roomtitle::RoomTitle, + smoke::Smoke, spring::Spring, +}; + +use crate::structures::{ObjFunc, Object, ObjectType}; +pub fn assign_skipped_consts(obj: &mut Object) { + match obj.obj_type { + ObjectType::Balloon(_) => { + obj.draw = ObjFunc(Balloon::draw); + obj.update = ObjFunc(Balloon::update); + obj.name = "Balloon" + } + + ObjectType::BigChest(_) => { + obj.draw = ObjFunc(BigChest::draw); + obj.update = ObjFunc(BigChest::update); + obj.name = "BigChest" + } + + ObjectType::Chest(_) => { + obj.draw = ObjFunc(Chest::draw); + obj.update = ObjFunc(Chest::update); + obj.name = "Chest" + } + + ObjectType::FakeWall(_) => { + obj.draw = ObjFunc(FakeWall::draw); + obj.update = ObjFunc(FakeWall::update); + obj.name = "FakeWall" + } + + ObjectType::FallFloor(_) => { + obj.draw = ObjFunc(FallFloor::draw); + obj.update = ObjFunc(FallFloor::update); + obj.name = "FallFloor" + } + + ObjectType::Flag(_) => { + obj.draw = ObjFunc(Flag::draw); + obj.update = ObjFunc(Flag::update); + obj.name = "Flag" + } + + ObjectType::FlyFruit(_) => { + obj.draw = ObjFunc(FlyFruit::draw); + obj.update = ObjFunc(FlyFruit::update); + obj.name = "FlyFruit" + } + + ObjectType::Fruit(_) => { + obj.draw = ObjFunc(Fruit::draw); + obj.update = ObjFunc(Fruit::update); + obj.name = "Fruit" + } + + ObjectType::Key(_) => { + obj.draw = ObjFunc(Key::draw); + obj.update = ObjFunc(Key::update); + obj.name = "Key" + } + + ObjectType::LifeUp(_) => { + obj.draw = ObjFunc(LifeUp::draw); + obj.update = ObjFunc(LifeUp::update); + obj.name = "LifeUp" + } + + ObjectType::Message(_) => { + obj.draw = ObjFunc(Message::draw); + obj.update = ObjFunc(Message::update); + obj.name = "Messsage" + } + + ObjectType::Orb(_) => { + obj.draw = ObjFunc(Orb::draw); + obj.update = ObjFunc(Orb::update); + obj.name = "Orb" + } + + ObjectType::Platform(_) => { + obj.draw = ObjFunc(Platform::draw); + obj.update = ObjFunc(Platform::update); + obj.name = "Platform" + } + + ObjectType::Player(_) => { + obj.draw = ObjFunc(Player::draw); + obj.update = ObjFunc(Player::update); + obj.name = "Player" + } + + ObjectType::PlayerSpawn(_) => { + obj.draw = ObjFunc(PlayerSpawn::draw); + obj.update = ObjFunc(PlayerSpawn::update); + obj.name = "PlayerSpawn" + } + + ObjectType::RoomTitle(_) => { + obj.draw = ObjFunc(RoomTitle::draw); + obj.update = ObjFunc(RoomTitle::update); + obj.name = "RoomTitle" + } + + ObjectType::Smoke(_) => { + obj.draw = ObjFunc(Smoke::draw); + obj.update = ObjFunc(Smoke::update); + obj.name = "Smoke" + } + + ObjectType::Spring(_) => { + obj.draw = ObjFunc(Spring::draw); + obj.update = ObjFunc(Spring::update); + obj.name = "Spring" + } + } +} diff --git a/core/src/lib.rs b/core/src/lib.rs index e8bd99a..83c5eba 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,32 +1,34 @@ -#[macro_use] -extern crate lazy_static; - +pub mod assign_skipped_consts; pub mod memory; pub mod objects; pub mod structures; -#[macro_use] pub mod utils; use std::{cell::RefCell, rc::Rc, vec}; +use assign_skipped_consts::assign_skipped_consts; use memory::Memory; use objects::{ balloon::Balloon, bigchest::BigChest, chest::Chest, fakewall::FakeWall, fallfloor::FallFloor, - flag::Flag, flyfruit::FlyFruit, fruit::Fruit, key::Key, platform::Platform, - playerspawn::PlayerSpawn, roomtitle::RoomTitle, spring::Spring, + flag::Flag, flyfruit::FlyFruit, fruit::Fruit, key::Key, lifeup::LifeUp, message::Message, + platform::Platform, player::Player, playerspawn::PlayerSpawn, roomtitle::RoomTitle, + spring::Spring, }; use serde::{Deserialize, Serialize}; +use serde_json; +use serde_json::json; use structures::*; use rand::prelude::*; -use utils::sin; -#[derive(Serialize)] +use utils::{max, sin}; +#[derive(Serialize, Deserialize)] pub struct Celeste { pub mem: Memory, + // #[serde(skip)] pub objects: Vec>>, pub got_fruit: Vec, pub max_djump: u8, - pub deaths: u8, - pub frames: u64, + pub deaths: u64, + pub frames: u8, pub room: Vector, pub level: u8, pub has_dashed: bool, @@ -36,9 +38,14 @@ pub struct Celeste { pub dead_particles: Vec, pub delay_restart: u8, pub shake: u8, - pub seconds: u64, + pub seconds: u8, pub minutes: u64, pub clouds: Vec, + pub start_game_flash: f32, + pub music_timer: i32, + pub start_game: bool, + pub flash_bg: bool, + pub new_bg: bool, } impl Celeste { @@ -88,9 +95,15 @@ impl Celeste { dead_particles: vec![], delay_restart: 0, shake: 0, + start_game: false, + music_timer: 0, + start_game_flash: 0.0, + flash_bg: false, + + new_bg: false, }; - cel.load_room(0, 0); - // cel.mem.fontatlas.reverse(); + cel.title_screen(); + // cel.load_room(0, 0); cel } @@ -100,7 +113,7 @@ impl Celeste { if self.level < 31 { self.seconds += self.frames / 30; - self.minutes += self.seconds / 60; + self.minutes += (self.seconds / 60) as u64; self.seconds %= 60; } self.frames %= 30; @@ -128,7 +141,9 @@ impl Celeste { } } - for i in 0..self.objects.len() { + let mut i = 0; + let mut lastlen = self.objects.len(); + loop { if i >= self.objects.len() { break; } @@ -140,41 +155,93 @@ impl Celeste { y: obj.spd.y, }; drop(obj); - // dbg!(); v.borrow_mut().do_move(self, spd.x, spd.y, 0f32); v.borrow_mut().update(self); + i += 1; + } + if self.is_title() { + if self.start_game { + self.start_game_flash -= 1.0; + if self.start_game_flash <= -30.0 { + self.begin_game(); + } + } else if self.mem.buttons[4] || self.mem.buttons[5] { + // music -1 + self.start_game_flash = 50.0; + self.start_game = true; + // sfx 38 + } } - // let graph = &mut rself.borrow_mut().mem.graphics; // for i in 0..128 * 128 { // // graphics[(i % 15) as u8] = i as ; // } } + pub fn is_title(&self) -> bool { + self.level == 32 + } + pub fn begin_game(&mut self) { + self.max_djump = 1; + self.deaths = 0; + self.frames = 0; + self.seconds = 0; + self.minutes = 0; + self.music_timer = 0; + // music 007 + self.level = 0; + self.load_room(0, 0); + } pub fn draw(&mut self) { if self.freeze > 0 { return; } - for i in 0..128 * 128 { - self.mem.graphics[i] = 0; // (i % 15) as u8; + + self.mem.pal_reset(); + + if self.is_title() && self.start_game { + for i in 1..16 { + self.mem.pal( + i, + if self.start_game_flash <= 10.0 { + f32::ceil(max(self.start_game_flash, 0.0) / 5.0) as u8 + } else { + if self.frames % 10 < 5 { + 7 + } else { + i as u8 + } + }, + ); + } } + //clearing screen - // TODO: - // title screen - // reset palette - self.mem.pal(8, 8); - for cloud in &mut self.clouds { - cloud.x += cloud.spd; - self.mem.rectfill( - cloud.x, - cloud.y, - cloud.x + cloud.w, - cloud.y + 16 - (cloud.w as f32 * 0.1875) as i32, - 1, - ); - if cloud.x > 128 { - cloud.x = -cloud.w; - cloud.y = self.mem.rng.gen_range(0..120); + let bg_col = if self.flash_bg { + self.frames as u8 / 5 + } else { + if self.new_bg { + 2 + } else { + 0 + } + }; + self.mem.rrectfill(-1, -1, 128, 128, bg_col); + + if !self.is_title() { + for cloud in &mut self.clouds { + cloud.x += cloud.spd; + self.mem.rectfill( + cloud.x, + cloud.y, + cloud.x + cloud.w, + cloud.y + 16 - (cloud.w as f32 * 0.1875) as i32, + 1, + ); + if cloud.x > 128 { + cloud.x = -cloud.w; + cloud.y = self.mem.rng.gen_range(0..120); + } } } @@ -239,12 +306,28 @@ impl Celeste { } } self.dead_particles.retain(|f| f.t > 0.0); + + if self.is_title() { + self.mem.print("z+x", 58, 80, 5); + // self.mem.print("(rust edition)", 41, 91, 5); + self.mem.print("maddy thorson", 42, 96, 5); + self.mem.print("noel berry", 46, 102, 5); + } + + // todo: summit blinds } pub fn next_room(&mut self) { // do sound at some point self.level += 1; self.load_room(self.level % 8, self.level / 8); } + pub fn title_screen(&mut self) { + self.frames = 0; + self.start_game_flash = 0.0; + self.level = 32; + // music + self.load_room(7, 3); + } pub fn load_room(&mut self, x: u8, y: u8) { self.objects.clear(); @@ -297,8 +380,7 @@ impl Celeste { // } } - if true { - // not title screen + if !self.is_title() { let obj = RoomTitle::init(self, 0.0, 0.0); self.objects.push(Rc::new(RefCell::new(obj))); } @@ -336,6 +418,33 @@ impl Celeste { } return false; } + + pub fn save_state(&mut self) -> Result { + // let mut holders = vec![]; + // for i in 0..self.objects.len() { + // let o = &self.objects[i]; + // holders.push(o.borrow()); + // } + // + // let refs: Vec<&Object> = holders.iter().map(|f| &**f).collect(); + // // yes this is stupid. + // + // let json = json!({ + // "state": self, + // "objects":refs, + // }); + // Ok(json.to_string()) + serde_json::to_string(self) + } + pub fn load_state(&mut self, json: &str) { + let deserialized: Self = serde_json::from_str(json).unwrap(); + for i in 0..deserialized.objects.len() { + let o = &deserialized.objects[i]; + let mut obj = o.borrow_mut(); + assign_skipped_consts(&mut obj); + } + *self = deserialized; + } } pub fn draw_time(celeste: &mut Celeste, x: i32, y: i32) { celeste.mem.rectfill(x, y, x + 33, y + 7, 0); @@ -343,7 +452,7 @@ pub fn draw_time(celeste: &mut Celeste, x: i32, y: i32) { "{}:{}:{}", two_digit_str(celeste.minutes / 60), two_digit_str(celeste.minutes % 60), - two_digit_str(celeste.seconds) + two_digit_str(celeste.seconds as u64) ); celeste.mem.print(&time, x + 1, y + 1, 7); } @@ -354,6 +463,7 @@ fn two_digit_str(n: u64) -> String { format!("{}", n) } } + #[derive(Serialize, Deserialize)] pub struct Cloud { diff --git a/core/src/memory.rs b/core/src/memory.rs index 732e888..c269ac5 100644 --- a/core/src/memory.rs +++ b/core/src/memory.rs @@ -1,6 +1,4 @@ -use crate::{ - structures::{FlipState, Vector}, -}; +use crate::structures::{FlipState, Vector}; use rand::{rngs::ThreadRng, thread_rng}; use serde::{Deserialize, Serialize}; @@ -77,13 +75,11 @@ impl Memory { if flip.y { cj = 7 - j; } - let color = self.pallete[self.sprites[((sprite as usize % 16) * 8) - + (((sprite as usize / 16) * 8 * 128) + ci + (cj * 128))] - as usize] - .clone(); + let color = self.sprites[((sprite as usize % 16) * 8) + + (((sprite as usize / 16) * 8 * 128) + ci + (cj * 128))]; - if !color.transparent { - self.pset(color.color, x + i as i32, y + j as i32); + if !self.pallete[color as usize].transparent { + self.pset(color, x + i as i32, y + j as i32); } } } @@ -123,7 +119,7 @@ impl Memory { self.draw_circ(xc as i32, yc as i32, x as i32, y as i32, c); } } - fn draw_circ(&mut self, xc: i32, yc: i32, x: i32, y: i32, c: u8) { + pub fn draw_circ(&mut self, xc: i32, yc: i32, x: i32, y: i32, c: u8) { self.rectfill( (xc - x).into(), (yc + y).into(), @@ -199,6 +195,13 @@ impl Memory { pub fn palt(&mut self, index: usize, transparent: bool) { self.pallete[index].transparent = transparent; } + pub fn pal_reset(&mut self) { + for i in 0..self.pallete.len() { + self.pallete[i].color = i as u8; + self.pallete[i].transparent = false; + } + self.pallete[0].transparent = true; + } pub fn print(&mut self, text: &str, x: i32, y: i32, col: u8) { for (c, chr) in text.char_indices() { let char_index = chr as usize; @@ -216,12 +219,13 @@ impl Memory { } } pub fn pset(&mut self, col: u8, mut x: i32, mut y: i32) { + let c = &self.pallete[col as usize]; x += self.camera.x as i32; y += self.camera.y as i32; if x < 0 || y < 0 || x >= 128 || y >= 128 { return; } - self.graphics[x as usize + y as usize * 128] = col; + self.graphics[x as usize + y as usize * 128] = c.color; } pub fn mget(&self, x: u8, y: u8) -> u8 { diff --git a/core/src/objects/balloon.rs b/core/src/objects/balloon.rs index 96e0b54..d23986d 100644 --- a/core/src/objects/balloon.rs +++ b/core/src/objects/balloon.rs @@ -3,7 +3,6 @@ use std::rc::Rc; use rand::Rng; - use crate::{structures::*, utils::*, Celeste}; use serde::{Deserialize, Serialize}; @@ -34,12 +33,12 @@ impl Balloon { timer: 0.0, start: y, }))), - draw: Self::draw, - update: Self::update, + draw: ObjFunc(Self::draw), + update: ObjFunc(Self::update), name: "Balloon", } } - fn update(obj: &mut Object, celeste: &mut Celeste) { + pub fn update(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::Balloon(p) => p.clone(), _ => unreachable!(), @@ -76,7 +75,7 @@ impl Balloon { obj.spr = 22; } } - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::Balloon(p) => p.clone(), _ => unreachable!(), diff --git a/core/src/objects/bigchest.rs b/core/src/objects/bigchest.rs index 5f1ae84..7c54c8a 100644 --- a/core/src/objects/bigchest.rs +++ b/core/src/objects/bigchest.rs @@ -40,13 +40,13 @@ impl BigChest { timer: 0.0, particles: vec![], }))), - draw: Self::draw, - update: Self::update, + draw: ObjFunc(Self::draw), + update: ObjFunc(Self::update), name: "BigChest", } } - fn update(_obj: &mut Object, _celeste: &mut Celeste) {} - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn update(_obj: &mut Object, _celeste: &mut Celeste) {} + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::BigChest(p) => p.clone(), _ => unreachable!(), diff --git a/core/src/objects/chest.rs b/core/src/objects/chest.rs index 4ced750..ddaddbe 100644 --- a/core/src/objects/chest.rs +++ b/core/src/objects/chest.rs @@ -3,7 +3,6 @@ use std::rc::Rc; use rand::Rng; - use crate::{structures::*, Celeste}; use serde::{Deserialize, Serialize}; @@ -32,12 +31,12 @@ impl Chest { start: x - 4.0, timer: 20, }))), - draw: Self::draw, - update: Self::update, + draw: ObjFunc(Self::draw), + update: ObjFunc(Self::update), name: "Chest", } } - fn update(obj: &mut Object, celeste: &mut Celeste) { + pub fn update(obj: &mut Object, celeste: &mut Celeste) { if celeste.has_key { let tref = match &mut obj.obj_type { ObjectType::Chest(p) => p.clone(), @@ -51,7 +50,7 @@ impl Chest { } } } - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { obj.draw_sprite(celeste); } } diff --git a/core/src/objects/fakewall.rs b/core/src/objects/fakewall.rs index 806591b..5782691 100644 --- a/core/src/objects/fakewall.rs +++ b/core/src/objects/fakewall.rs @@ -1,7 +1,5 @@ use std::{cell::RefCell, rc::Rc}; - - use crate::{structures::*, utils::sign, Celeste}; use serde::{Deserialize, Serialize}; @@ -24,12 +22,12 @@ impl FakeWall { collidable: true, solids: false, obj_type: ObjectType::FakeWall(Rc::new(RefCell::new(Self {}))), - draw: Self::draw, - update: Self::update, + draw: ObjFunc(Self::draw), + update: ObjFunc(Self::update), name: "FakeWall", } } - fn update(obj: &mut Object, celeste: &mut Celeste) { + pub fn update(obj: &mut Object, celeste: &mut Celeste) { // hitbox is mutated during the duration of update(). not sure why? it makes check() more // generous i guess obj.hitbox = Rectangle { @@ -81,7 +79,7 @@ impl FakeWall { h: 16.0, }; } - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { celeste .mem .spr(64, obj.pos.x as i32, obj.pos.y as i32, None); diff --git a/core/src/objects/fallfloor.rs b/core/src/objects/fallfloor.rs index fc1111e..9c580ca 100644 --- a/core/src/objects/fallfloor.rs +++ b/core/src/objects/fallfloor.rs @@ -1,9 +1,6 @@ use std::cell::RefCell; use std::rc::Rc; - - - use crate::{structures::*, Celeste}; use serde::{Deserialize, Serialize}; @@ -28,13 +25,13 @@ impl FallFloor { flip: FlipState { x: false, y: false }, collidable: true, obj_type: ObjectType::FallFloor(Rc::new(RefCell::new(Self { state: 0, delay: 0 }))), - draw: Self::draw, - update: Self::update, + draw: ObjFunc(Self::draw), + update: ObjFunc(Self::update), name: "FallFloor", solids: false, } } - fn update(obj: &mut Object, celeste: &mut Celeste) { + pub fn update(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::FallFloor(p) => p.clone(), _ => unreachable!(), @@ -66,7 +63,7 @@ impl FallFloor { } } } - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::FallFloor(p) => p.clone(), _ => unreachable!(), diff --git a/core/src/objects/flag.rs b/core/src/objects/flag.rs index 1364861..fd17cf5 100644 --- a/core/src/objects/flag.rs +++ b/core/src/objects/flag.rs @@ -1,7 +1,5 @@ use std::{cell::RefCell, rc::Rc}; - - use crate::{structures::*, Celeste}; use serde::{Deserialize, Serialize}; @@ -33,13 +31,13 @@ impl Flag { .fold(0, |acc, x| acc + if *x { 0 } else { 1 }), show: false, }))), // score = - draw: Self::draw, - update: Self::update, + draw: ObjFunc(Self::draw), + update: ObjFunc(Self::update), name: "Flag", } } - fn update(_obj: &mut Object, _celeste: &mut Celeste) {} - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn update(_obj: &mut Object, _celeste: &mut Celeste) {} + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::Flag(p) => p.clone(), _ => unreachable!(), diff --git a/core/src/objects/flyfruit.rs b/core/src/objects/flyfruit.rs index fd2ef64..da4a259 100644 --- a/core/src/objects/flyfruit.rs +++ b/core/src/objects/flyfruit.rs @@ -1,9 +1,6 @@ use std::cell::RefCell; use std::rc::Rc; - - - use crate::{structures::*, utils::*, Celeste}; use serde::{Deserialize, Serialize}; @@ -32,12 +29,12 @@ impl FlyFruit { collidable: false, solids: false, obj_type: ObjectType::FlyFruit(Rc::new(RefCell::new(Self { start: y, off: 0.5 }))), - draw: Self::draw, - update: Self::update, + draw: ObjFunc(Self::draw), + update: ObjFunc(Self::update), name: "FlyFruit", } } - fn update(obj: &mut Object, celeste: &mut Celeste) { + pub fn update(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::FlyFruit(p) => p.clone(), _ => unreachable!(), @@ -56,7 +53,7 @@ impl FlyFruit { check_fruit(obj, celeste); } - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::FlyFruit(p) => p.clone(), _ => unreachable!(), diff --git a/core/src/objects/fruit.rs b/core/src/objects/fruit.rs index 33f4f0c..086efcb 100644 --- a/core/src/objects/fruit.rs +++ b/core/src/objects/fruit.rs @@ -1,9 +1,6 @@ use std::cell::RefCell; use std::rc::Rc; - - - use crate::{structures::*, utils::*, Celeste}; use super::lifeup::LifeUp; @@ -31,12 +28,12 @@ impl Fruit { collidable: true, solids: false, obj_type: ObjectType::Fruit(Rc::new(RefCell::new(Self { start: y, off: 0.0 }))), - draw: Self::draw, - update: Self::update, + draw: ObjFunc(Self::draw), + update: ObjFunc(Self::update), name: "Fruit", } } - fn update(obj: &mut Object, celeste: &mut Celeste) { + pub fn update(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::Fruit(p) => p.clone(), _ => unreachable!(), @@ -47,7 +44,7 @@ impl Fruit { check_fruit(obj, celeste); } - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { obj.draw_sprite(celeste); } } diff --git a/core/src/objects/key.rs b/core/src/objects/key.rs index 5856a77..9630f3d 100644 --- a/core/src/objects/key.rs +++ b/core/src/objects/key.rs @@ -1,9 +1,6 @@ use std::cell::RefCell; use std::rc::Rc; - - - use crate::{structures::*, utils::*, Celeste}; use serde::{Deserialize, Serialize}; @@ -26,12 +23,12 @@ impl Key { collidable: true, solids: false, obj_type: ObjectType::Key(Rc::new(RefCell::new(Self {}))), - draw: Self::draw, - update: Self::update, + draw: ObjFunc(Self::draw), + update: ObjFunc(Self::update), name: "Key", } } - fn update(obj: &mut Object, celeste: &mut Celeste) { + pub fn update(obj: &mut Object, celeste: &mut Celeste) { obj.spr = (9.5 + sin(celeste.frames as f32 / 30.0)).floor() as u8; if celeste.frames == 18 { obj.flip.x = !obj.flip.x; @@ -42,7 +39,7 @@ impl Key { obj.destroy_self(celeste); } } - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { obj.draw_sprite(celeste); } } diff --git a/core/src/objects/lifeup.rs b/core/src/objects/lifeup.rs index 83d7aa7..8afd23a 100644 --- a/core/src/objects/lifeup.rs +++ b/core/src/objects/lifeup.rs @@ -1,7 +1,5 @@ use std::{cell::RefCell, rc::Rc}; - - use crate::{structures::*, Celeste}; use serde::{Deserialize, Serialize}; @@ -30,12 +28,12 @@ impl LifeUp { duration: 30.0, flash: 0.0, }))), - draw: Self::draw, - update: Self::update, + draw: ObjFunc(Self::draw), + update: ObjFunc(Self::update), name: "LifeUp", } } - fn update(obj: &mut Object, celeste: &mut Celeste) { + pub fn update(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::LifeUp(p) => p.clone(), _ => unreachable!(), @@ -46,7 +44,7 @@ impl LifeUp { obj.destroy_self(celeste); } } - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::LifeUp(p) => p.clone(), _ => unreachable!(), diff --git a/core/src/objects/message.rs b/core/src/objects/message.rs index e3657b4..7019e23 100644 --- a/core/src/objects/message.rs +++ b/core/src/objects/message.rs @@ -28,13 +28,13 @@ impl Message { index: 0.0, last: 0.0, }))), - draw: Self::draw, - update: Self::update, + draw: ObjFunc(Self::draw), + update: ObjFunc(Self::update), name: "FakeWall", } } - fn update(_obj: &mut Object, _celeste: &mut Celeste) {} - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn update(_obj: &mut Object, _celeste: &mut Celeste) {} + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { let text = "-- celeste mountain --#this memorial to those# perished on the climb"; let tref = match &mut obj.obj_type { ObjectType::Message(p) => p.clone(), diff --git a/core/src/objects/orb.rs b/core/src/objects/orb.rs index 1cd5349..da67d02 100644 --- a/core/src/objects/orb.rs +++ b/core/src/objects/orb.rs @@ -24,19 +24,19 @@ impl Orb { collidable: false, solids: false, obj_type: ObjectType::Orb(Rc::new(RefCell::new(Self { spr: 29.0 }))), - draw: Self::draw, - update: Self::update, + draw: ObjFunc(Self::draw), + update: ObjFunc(Self::update), name: "Orb", } } - fn update(obj: &mut Object, _celeste: &mut Celeste) { + pub fn update(obj: &mut Object, _celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::Orb(p) => p.clone(), _ => unreachable!(), }; let _this = tref.borrow_mut(); } - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { obj.draw_sprite(celeste); } } diff --git a/core/src/objects/platform.rs b/core/src/objects/platform.rs index fbefd6b..ce5009c 100644 --- a/core/src/objects/platform.rs +++ b/core/src/objects/platform.rs @@ -28,12 +28,12 @@ impl Platform { last: -4.0, dir: if spr == 11 { -1.0 } else { 1.0 }, }))), - draw: Self::draw, - update: Self::update, + draw: ObjFunc(Self::draw), + update: ObjFunc(Self::update), name: "Platform", } } - fn update(obj: &mut Object, celeste: &mut Celeste) { + pub fn update(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::Platform(p) => p.clone(), _ => unreachable!(), @@ -59,7 +59,7 @@ impl Platform { } this.last = obj.pos.x; } - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::Platform(p) => p.clone(), _ => unreachable!(), diff --git a/core/src/objects/player.rs b/core/src/objects/player.rs index 1e7e4bd..6cf66c2 100644 --- a/core/src/objects/player.rs +++ b/core/src/objects/player.rs @@ -1,8 +1,6 @@ use std::cell::RefCell; use std::rc::Rc; - - use crate::utils::mid; use crate::DeadParticle; use crate::{structures::*, utils::*, Celeste}; @@ -30,8 +28,8 @@ pub struct Player { impl Player { pub fn init(celeste: &mut Celeste, x: f32, y: f32) -> Object { Object { - draw: Self::draw, - update: Self::update, + draw: ObjFunc(Self::draw), + update: ObjFunc(Self::update), pos: Vector { x, y }, spd: Vector { x: 0.0, y: 0.0 }, rem: Vector { x: 0.0, y: 0.0 }, @@ -65,7 +63,7 @@ impl Player { name: "Player", } } - fn update(obj: &mut Object, celeste: &mut Celeste) { + pub fn update(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::Player(p) => p.clone(), _ => unreachable!(), @@ -265,7 +263,7 @@ impl Player { }; this.was_on_ground = on_ground; } - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::Player(p) => p.clone(), _ => unreachable!(), diff --git a/core/src/objects/playerspawn.rs b/core/src/objects/playerspawn.rs index 201d7aa..a9bcf60 100644 --- a/core/src/objects/playerspawn.rs +++ b/core/src/objects/playerspawn.rs @@ -37,13 +37,13 @@ impl PlayerSpawn { target: y, hair: vec![Vector { x, y: 128.0 }; 4], }))), - draw: Self::draw, - update: Self::update, + draw: ObjFunc(Self::draw), + update: ObjFunc(Self::update), name: "PlayerSpawn", } //sfx 4 } - fn update(obj: &mut Object, celeste: &mut Celeste) { + pub fn update(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::PlayerSpawn(p) => p.clone(), _ => unreachable!(), @@ -79,7 +79,7 @@ impl PlayerSpawn { } } } - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::PlayerSpawn(p) => p.clone(), _ => unreachable!(), diff --git a/core/src/objects/roomtitle.rs b/core/src/objects/roomtitle.rs index deac2b1..51a0450 100644 --- a/core/src/objects/roomtitle.rs +++ b/core/src/objects/roomtitle.rs @@ -24,13 +24,13 @@ impl RoomTitle { collidable: false, solids: false, obj_type: ObjectType::RoomTitle(Rc::new(RefCell::new(Self { delay: 5 }))), - draw: Self::draw, - update: Self::update, + draw: ObjFunc(Self::draw), + update: ObjFunc(Self::update), name: "Orb", } } - fn update(_obj: &mut Object, _celeste: &mut Celeste) {} - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn update(_obj: &mut Object, _celeste: &mut Celeste) {} + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::RoomTitle(p) => p.clone(), _ => unreachable!(), diff --git a/core/src/objects/smoke.rs b/core/src/objects/smoke.rs index 45b6392..171e7cc 100644 --- a/core/src/objects/smoke.rs +++ b/core/src/objects/smoke.rs @@ -35,12 +35,12 @@ impl Smoke { collidable: false, solids: false, obj_type: ObjectType::Smoke(Rc::new(RefCell::new(Self { spr: 29.0 }))), - draw: Self::draw, - update: Self::update, + draw: ObjFunc(Self::draw), + update: ObjFunc(Self::update), name: "Smoke", } } - fn update(obj: &mut Object, celeste: &mut Celeste) { + pub fn update(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::Smoke(p) => p.clone(), _ => unreachable!(), @@ -52,7 +52,7 @@ impl Smoke { } obj.spr = this.spr as u8; } - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { obj.draw_sprite(celeste); } } diff --git a/core/src/objects/spring.rs b/core/src/objects/spring.rs index 2fc4c25..420e4a8 100644 --- a/core/src/objects/spring.rs +++ b/core/src/objects/spring.rs @@ -1,9 +1,6 @@ use std::cell::RefCell; use std::rc::Rc; - - - use crate::{structures::*, Celeste}; use serde::{Deserialize, Serialize}; @@ -34,12 +31,12 @@ impl Spring { hide_for: 0, delay: 0, }))), - draw: Self::draw, - update: Self::update, + draw: ObjFunc(Self::draw), + update: ObjFunc(Self::update), name: "Spring", } } - fn update(obj: &mut Object, celeste: &mut Celeste) { + pub fn update(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::Spring(p) => p.clone(), _ => unreachable!(), @@ -107,7 +104,7 @@ impl Spring { } } } - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::Spring(p) => p.clone(), _ => unreachable!(), diff --git a/core/src/objects/template.rs b/core/src/objects/template.rs index 1293355..ed138f6 100644 --- a/core/src/objects/template.rs +++ b/core/src/objects/template.rs @@ -29,14 +29,14 @@ impl BaseObject { name: "BaseObject", } } - fn update(obj: &mut Object, celeste: &mut Celeste) { + pub fn update(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::BaseObject(p) => p.clone(), _ => unreachable!(), }; let mut this = tref.borrow_mut(); } - fn draw(obj: &mut Object, celeste: &mut Celeste) { + pub fn draw(obj: &mut Object, celeste: &mut Celeste) { let tref = match &mut obj.obj_type { ObjectType::BaseObject(p) => p.clone(), _ => unreachable!(), diff --git a/core/src/structures.rs b/core/src/structures.rs index 02a1436..3f22e60 100644 --- a/core/src/structures.rs +++ b/core/src/structures.rs @@ -40,7 +40,7 @@ pub struct FlipState { pub x: bool, pub y: bool, } -#[derive(Serialize)] +#[derive(Serialize, Deserialize)] pub struct Object { pub pos: Vector, @@ -54,18 +54,27 @@ pub struct Object { pub solids: bool, pub obj_type: ObjectType, + #[serde(skip, default)] + pub draw: ObjFunc, #[serde(skip)] - pub draw: fn(&mut Object, &mut Celeste), + pub update: ObjFunc, + #[serde(skip)] - pub update: fn(&mut Object, &mut Celeste), pub name: &'static str, } +pub struct ObjFunc(pub fn(&mut Object, &mut Celeste)); +impl Default for ObjFunc { + fn default() -> Self { + ObjFunc(noop) + } +} +pub fn noop(_: &mut Object, _: &mut Celeste) {} impl Object { pub fn draw(&mut self, celeste: &mut Celeste) { - (self.draw)(self, celeste); + (self.draw).0(self, celeste); } pub fn update(&mut self, celeste: &mut Celeste) { - (self.update)(self, celeste); + (self.update).0(self, celeste); } pub fn left(&self) -> f32 { self.pos.x + self.hitbox.x diff --git a/standalone/src/main.rs b/standalone/src/main.rs index 7fd0ed6..93d5e46 100644 --- a/standalone/src/main.rs +++ b/standalone/src/main.rs @@ -54,6 +54,8 @@ pub fn main() { canvas.set_draw_color(Color::RGB(0, 255, 255)); canvas.clear(); canvas.present(); + + let mut savestate: Option = None; let mut event_pump = sdl_context.event_pump().unwrap(); 'running: loop { // canvas.set_draw_color(Color::BLUE); @@ -111,6 +113,18 @@ pub fn main() { Keycode::F => { engine.next_room(); } + Keycode::E => match engine.save_state() { + Ok(e) => { + println!("{}", e); + savestate = Some(e) + } + Err(e) => panic!("{:?}", e), + }, + Keycode::Q => { + if let Some(s) = &savestate { + engine.load_state(s); + } + } _ => {} }, _ => {} diff --git a/t b/t new file mode 100644 index 0000000..e69de29 diff --git a/web/index.html b/web/index.html index de9329b..133fa68 100644 --- a/web/index.html +++ b/web/index.html @@ -10,7 +10,9 @@ - +
+ + - \ No newline at end of file + diff --git a/web/main.js b/web/main.js index 6239224..1cd93f5 100644 --- a/web/main.js +++ b/web/main.js @@ -1,4 +1,4 @@ -import init, { start, render_screen, next_tick, set_btn, skip_level } from "./pkg/rustic_mountain_web.js" +import init, { start, render_screen, next_tick, set_btn, skip_level, save_state, load_state } from "./pkg/rustic_mountain_web.js" const mapdata = `2331252548252532323232323300002425262425252631323232252628282824252525252525323328382828312525253232323233000000313232323232323232330000002432323233313232322525252525482525252525252526282824252548252525262828282824254825252526282828283132323225482525252525 252331323232332900002829000000242526313232332828002824262a102824254825252526002a2828292810244825282828290000000028282900000000002810000000372829000000002a2831482525252525482525323232332828242525254825323338282a283132252548252628382828282a2a2831323232322525 252523201028380000002a0000003d24252523201028292900282426003a382425252548253300002900002a0031252528382900003a676838280000000000003828393e003a2800000000000028002425253232323232332122222328282425252532332828282900002a283132252526282828282900002a28282838282448 @@ -207,6 +207,12 @@ window.onload = () => { if (canvas.getContext) { ctx = canvas.getContext("2d") } + document.getElementById("savestate").addEventListener("click", () => { + save_state(); + }); + document.getElementById("loadstate").addEventListener("click", () => { + load_state(); + }); start(mapdata, sprites, flags, fontatlas) window.requestAnimationFrame(doupdate); window.requestAnimationFrame(draw); diff --git a/web/src/lib.rs b/web/src/lib.rs index fb81bd8..515228d 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -1,14 +1,13 @@ use rustic_mountain_core::Celeste; use wasm_bindgen::prelude::*; mod test; -///... -/// belive me, i tried -/// i tried lazy_static, wrapping mutexes in rwlocks in boxes, experimental compiler features, passing closures as JsValues, even more stuff -/// there's just not a safe way of having a global ownerless mutable singleton that can be written to concurrently -/// or maybe i'm just stupid -/// anyway have this raw pointer lol segfault + +/// raw pointer neccesary in wasm +/// shouldn't break, just be careful with it static mut CELESTE: *mut Celeste = std::ptr::null_mut::(); +static mut SAVESTATE: *mut Option = std::ptr::null_mut(); + #[wasm_bindgen] extern "C" { @@ -21,6 +20,9 @@ pub fn start(map: String, sprites: String, flags: String, fontatlas: String) { std::panic::set_hook(Box::new(console_error_panic_hook::hook)); unsafe { console_error_panic_hook::set_once(); + + let none = Box::leak(Box::new(None)); + SAVESTATE = none; CELESTE = Box::leak(Box::new(Celeste::new(map, sprites, flags, fontatlas))); (*CELESTE).mem.logger = Box::new(log); // (*CELESTE).mem @@ -36,6 +38,25 @@ pub fn next_tick() { } } #[wasm_bindgen] +pub fn save_state() { + unsafe { + let res = (*CELESTE).save_state(); + if let Ok(s) = res { + *SAVESTATE = Some(s); + } else { + log("???") + } + } +} +#[wasm_bindgen] +pub fn load_state() { + unsafe { + if let Some(state) = &(*SAVESTATE) { + (*CELESTE).load_state(state); + } + } +} +#[wasm_bindgen] pub fn render_screen() -> Vec { unsafe { (*CELESTE).draw(); @@ -43,8 +64,8 @@ pub fn render_screen() -> Vec { } } #[wasm_bindgen] -pub fn skip_level(){ - unsafe{ +pub fn skip_level() { + unsafe { (*CELESTE).next_room(); } }