mod background; mod buttons; mod gsa; mod gsa_render_to_screen; mod mapedit; mod maps; mod rgb; mod run; mod sprite; mod tilemap; mod tileset; //todo: figure out how to not repeat all the lib.rs stuff :( pub use crate::background::*; pub use crate::buttons::*; pub use crate::gsa::*; pub use crate::rgb::*; pub use crate::run::run; pub use crate::sprite::*; /// Amount of sprites in [Gsa::sprites] pub const MAX_SPRITES: usize = 0xff; /// Screen Width in pixels pub const SCREEN_WIDTH: usize = 304; /// Screen Height in pixels pub const SCREEN_HEIGHT: usize = 176; /// X and y dimensions of maps in [Gsa::bgs] pub const BACKGROUND_MAX_SIZE: usize = 1024; /// Tile considered empty (never drawn even if has contents) pub const EMPTY_TILE: u16 = 0xffff; /// Tile id of bold default font pub const FONT_BOLD: u16 = 0xf000; /// Tile id of thin default font pub const FONT_THIN: u16 = 0xe000; /// Width and height (in tiles) of tileset pub const TILESET_SIZE: usize = 0x100; /// Width and height of a tile pub const TILE_SIZE: usize = 16; /// Palette index which is treated as transparent pub const TRANSPARENT: u8 = 0xff; /// Width and height of a tile in half-tile mode pub const HALF_TILE_SIZE: usize = 8; /// Amount of tile maps in [Gsa::bgs] pub const MAX_BACKGROUNDS: usize = 4; use clap::{crate_name, crate_version, Parser, Subcommand}; use dunce::canonicalize; use mapedit::run_mapedit; use path_slash::PathExt; use std::fs; use std::fs::{write, OpenOptions}; use std::io::Write; use std::path::{Path, PathBuf}; use std::process::{exit, Command}; #[derive(Parser)] struct Cli { #[command(subcommand)] command: Cmd, } #[derive(Subcommand)] enum Cmd { /// Creates a new GSA project New { /// Name of new project name: String, /// Use local path to GSA instead of crates.io #[arg(long, short)] local: Option, /// Overwrite dir/file with name? WARNING: will delete stuff without further confirmation #[arg(long)] overwrite: bool, }, /// Edit map of current project MapEdit {}, } fn main() { let cli = Cli::parse(); match cli.command { Cmd::New { name, local, overwrite, } => { println!("creating {}", name); let path = Path::new(&name); if path.exists() { if overwrite { if path.is_dir() { fs::remove_dir_all(path).unwrap(); } else { fs::remove_file(path).unwrap(); } } else { eprintln!( "aborting: file or directory {} already exists; use --overwrite if you want to delete it", name ); exit(1); } } if !Command::new("cargo") .arg("new") .arg(&name) .status() .unwrap() .success() { eprintln!("aborting: cargo new failed"); exit(1); } let mut cargo = OpenOptions::new() .write(true) .append(true) .open(path.join("Cargo.toml")) .expect("opening Cargo.toml failed"); match local { None => { writeln!(cargo, "{} = \"{}\"", crate_name!(), crate_version!()).unwrap(); } Some(local) => { writeln!( cargo, "{} = {{path = \"{}\"}}\n", crate_name!(), canonicalize(local) .expect("couldn't find path") .to_slash_lossy(), ) .unwrap(); } } writeln!( cargo, "glam = \"0.24.0\"\n\n[profile.dev.package.{}]\nopt-level = 3", crate_name!() ) .unwrap(); write( path.join("src/main.rs"), include_str!("../examples/hello_world/main.rs"), ) .unwrap(); write( path.join("src/gfx.gif"), include_bytes!("../examples/hello_world/gfx.gif"), ) .unwrap(); } Cmd::MapEdit {} => run_mapedit(), } }