const std = @import("std"); const SDL = @import("sdl2"); const Grid = @import("Game/Grid.zig"); const Piece = @import("Game/Piece.zig"); const Bag = @import("Game/Bag.zig"); const Timer = @import("Timer.zig"); const State = @import("flow.zig").State; const Action = @import("Action.zig"); const Renderer = @import("Game/Renderer.zig"); const movement = @import("Game/movement.zig"); const Self = @This(); // Codes to access action list pub const ActionCode = enum(usize) { right = 0, left = 1, down = 2, hard = 3, swap = 4, rot_r = 5, rot_l = 6, }; grid: Grid, renderer: Renderer, state: State = State.game, bag: Bag, held: ?Piece.Type, piece: Piece, shadow: Piece, action_list: [7]Action = .{ Action.init(SDL.SDL_SCANCODE_D, actionRight), // Right Action.init(SDL.SDL_SCANCODE_A, actionLeft), // Left Action.init(SDL.SDL_SCANCODE_S, actionDown), // Down Action.init(SDL.SDL_SCANCODE_W, actionHard), // Instant Drop Action.init(SDL.SDL_SCANCODE_SPACE, actionSwap), // Swap Piece Action.init(SDL.SDL_SCANCODE_RIGHT, actionRotR), // Rotate Action.init(SDL.SDL_SCANCODE_LEFT, actionRotL), // Rotate }, timer_down: Timer, timer_left_arr: Timer, timer_left_das: Timer, timer_right_arr: Timer, timer_right_das: Timer, timer_gravity: Timer, pub fn init(renderer: *SDL.SDL_Renderer) Self { var ret = Self{ .grid = Grid.init(), .bag = Bag.init(), .piece = undefined, .shadow = undefined, .held = null, .renderer = Renderer.init(renderer), .timer_down = Timer.init(50), .timer_left_arr = Timer.init(50), .timer_left_das = Timer.init(200), .timer_right_arr = Timer.init(50), .timer_right_das = Timer.init(200), .timer_gravity = Timer.init(200), }; // Get a piece from the bag ret.piece = ret.bag.pop(); return ret; } pub fn tick(self: *Self) State { // TIMERS // Dropping a piece if (self.piece.timer_dropped.finished()) { self.piece.timer_dropped.stop(); self.piece.dropped = true; } // Repeat Right // DAS if (self.action_list[@enumToInt(ActionCode.right)].holding) { if (!self.timer_right_das.started) { self.timer_right_das.start(); } } else { // Stop both self.timer_right_das.stop(); self.timer_right_arr.stop(); } // ARR if (self.timer_right_das.finished()) { if (!self.timer_right_arr.started) { self.timer_right_arr.start(); } else if (self.timer_right_arr.finished()) { self.timer_right_arr.stop(); self.action_list[@enumToInt(ActionCode.right)].holding = false; } } // Repeat Left // DAS if (self.action_list[@enumToInt(ActionCode.left)].holding) { if (!self.timer_left_das.started) { self.timer_left_das.start(); } } else { // Stop both self.timer_left_das.stop(); self.timer_left_arr.stop(); } // ARR if (self.timer_left_das.finished()) { if (!self.timer_left_arr.started) { self.timer_left_arr.start(); } else if (self.timer_left_arr.finished()) { self.timer_left_arr.stop(); self.action_list[@enumToInt(ActionCode.left)].holding = false; } } // Repeat Down if (self.action_list[@enumToInt(ActionCode.down)].holding) { if (!self.timer_down.started) { self.timer_down.start(); } else if (self.timer_down.finished()) { self.timer_down.stop(); self.action_list[@enumToInt(ActionCode.down)].holding = false; } } else { self.timer_down.stop(); } // Gravity if (!self.piece.timer_dropped.started) { if (!self.timer_gravity.started) { self.timer_gravity.start(); } else if (self.timer_gravity.finished()) { self.action_list[@enumToInt(ActionCode.down)].activate = true; self.timer_gravity.start(); } } else { self.timer_gravity.stop(); } // DROP if (self.piece.dropped) { self.grid = movement.drop(self.grid, self.piece); // New Piece self.piece = self.bag.pop(); } // KEY EVENTS var key_state = SDL.SDL_GetKeyboardState(null); for (self.action_list) |*action| { if (key_state[action.*.code] == 1 and !action.*.holding) { action.*.holding = true; action.*.activate = true; } if (key_state[action.*.code] == 0) { action.*.holding = false; } // Action if (action.*.activate) { action.*.activate = false; action.*.call(self); } } // Update Shadow { self.shadow = movement.shadow(self.grid, self.piece); self.shadow.color.a /= 4; } self.grid.clearLines(); self.renderer.render(self.*); return self.state; } // ACTION CALLBACKS fn actionDown(self: *Self) void { self.piece = movement.moveDown(self.grid, self.piece); } fn actionRight(self: *Self) void { self.piece = movement.moveRight(self.grid, self.piece); } fn actionLeft(self: *Self) void { self.piece = movement.moveLeft(self.grid, self.piece); } fn actionHard(self: *Self) void { self.piece = movement.hardDrop(self.grid, self.piece); } fn actionSwap(self: *Self) void { if (self.held) |held_piece| { if (!self.piece.swapped) { self.held = self.piece.piece_type; self.piece = Piece.init(held_piece); self.piece.swapped = true; } } else { self.held = self.piece.piece_type; self.piece = self.bag.pop(); self.piece.swapped = true; } } fn actionRotR(self: *Self) void { self.piece = movement.rotateRight(self.grid, self.piece); } fn actionRotL(self: *Self) void { self.piece = movement.rotateLeft(self.grid, self.piece); }