@@ 0,0 1,46 @@
+use format::ini;
+use fs;
+use io;
+use os;
+use sdl2;
+
+fn config(
+ keybindings: *[](sdl2::keycode, action),
+ cfg: io::handle,
+) (void | ini::error | sdl2::error) = {
+ let sc = ini::scan(cfg);
+ defer ini::finish(&sc);
+ for (true) match (ini::next(&sc)?) {
+ case io::EOF =>
+ break;
+ case let e: ini::entry =>
+ switch (e.0) {
+ case "keyboard" =>
+ const action = switch (e.1) {
+ case "commit" =>
+ yield action::COMMIT;
+ case "down" =>
+ yield action::DOWN;
+ case "left" =>
+ yield action::LEFT;
+ case "right" =>
+ yield action::RIGHT;
+ case "rotleft" =>
+ yield action::ROTLEFT;
+ case "rotright" =>
+ yield action::ROTRIGHT;
+ case =>
+ continue;
+ };
+ let keycode = sdl2::get_key_from_name(e.2)?;
+ for (let i = 0z; i < len(keybindings); i += 1) {
+ if (keybindings[i].0 == keycode) {
+ delete(keybindings[i]);
+ i -= 1;
+ };
+ };
+ append(keybindings, (keycode, action));
+ case => void;
+ };
+ };
+};
@@ 1,10 1,15 @@
+use dirs;
use fmt;
+use format::ini;
use fs;
+use getopt;
+use io;
use math::random;
-use sdl2;
-use sdl2::{renderer_flags, window_flags};
+use os;
use sdl2::image;
use sdl2::mixer;
+use sdl2::{renderer_flags, window_flags};
+use sdl2;
use time;
use types;
@@ 22,6 27,15 @@ type gamestate = enum {
GAMEOVER,
};
+type action = enum {
+ COMMIT,
+ DOWN,
+ LEFT,
+ RIGHT,
+ ROTLEFT,
+ ROTRIGHT,
+};
+
type state = struct {
run: bool,
window: *sdl2::window,
@@ 48,19 62,52 @@ type state = struct {
// Intro
fadein_start: u32,
fadein_finish: u32,
+
+ keybindings: [](sdl2::keycode, action),
};
export fn main() void = {
match (run()) {
case let err: sdl2::error =>
fmt::fatal("SDL error: {}", sdl2::strerror(err));
+ case let err: ini::error =>
+ fmt::fatal("Error loading config file: {}", ini::strerror(err));
case let err: fs::error =>
fmt::fatal("Error: {}", fs::strerror(err));
case void => void;
};
};
-fn run() (void | fs::error | sdl2::error) = {
+fn run() (void | fs::error | sdl2::error | ini::error) = {
+ let keybindings: [](sdl2::keycode, action) = alloc([
+ (sdl2::keycode::UP, action::ROTLEFT),
+ (sdl2::keycode::x, action::ROTLEFT),
+ (sdl2::keycode::SPACE, action::COMMIT),
+ (sdl2::keycode::LCTRL, action::ROTRIGHT),
+ (sdl2::keycode::RCTRL, action::ROTRIGHT),
+ (sdl2::keycode::z, action::ROTRIGHT),
+ (sdl2::keycode::LEFT, action::LEFT),
+ (sdl2::keycode::RIGHT, action::RIGHT),
+ (sdl2::keycode::DOWN, action::DOWN),
+ (sdl2::keycode::KP_8, action::COMMIT),
+ (sdl2::keycode::KP_4, action::LEFT),
+ (sdl2::keycode::KP_6, action::RIGHT),
+ (sdl2::keycode::KP_2, action::COMMIT),
+ (sdl2::keycode::KP_1, action::ROTLEFT),
+ (sdl2::keycode::KP_5, action::ROTLEFT),
+ (sdl2::keycode::KP_9, action::ROTLEFT),
+ (sdl2::keycode::KP_3, action::ROTRIGHT),
+ (sdl2::keycode::KP_7, action::ROTRIGHT),
+ ]);
+ defer free(keybindings);
+ const cfg = dirs::configfs("tetrominoes");
+ defer fs::close(cfg);
+ match (fs::open(cfg, "config")) {
+ case let cfg: io::handle =>
+ config(&keybindings, cfg)?;
+ case fs::error => void;
+ };
+
sdl2::init(sdl2::init_flags::VIDEO
| sdl2::init_flags::AUDIO
| sdl2::init_flags::GAMECONTROLLER)?;
@@ 101,6 148,7 @@ fn run() (void | fs::error | sdl2::error) = {
},
rand = random::init(seed),
speed = 60 * 1000 / 84, // TODO: Set this to BPM properly
+ keybindings = keybindings,
...
};
defer sdl2::destroy_texture(state.piece.tex);