tamamo/src/main.zig

322 lines
7.8 KiB
Zig

const w4 = @import("./wasm4.zig");
const sh0rk = @import("./sh0rk.zig");
const sprites = @import("./sprites.zig");
const palette = @import("./palette.zig");
const tframe = @import("./tframe.zig");
const std = @import("std");
const fmt = std.fmt;
const Direction = sh0rk.Direction;
const Point = sh0rk.Point;
const Rect = sh0rk.Rect;
const map = @import("./maps/overworld.zig");
var frame_count: u32 = 0;
var mara_direction: Direction = Direction.Right;
var mara_frame: bool = false;
var mara_box: Rect = Rect{.base = map.start_point, .width = 16, .height = 16};
var mara_speed: u16 = 0;
var screen = Rect{.base = Point{.x = 0, .y = 0}, .width = 160, .height = 160};
const screen_width = 20;
const screen_height = 20;
var sound_timer: u8 = 0;
var textBuf: [160]u8 = undefined;
var done: bool = false;
var camera: [400]u9 = []u9{} ** 400;
var state: sh0rk.State = .Title;
export fn start() void {
palette.tamtam();
}
fn bonk() void {
if (sound_timer != 0) {
return;
}
w4.tone(
w4.Tone.Frequency{.start = 220, .end = 40},
w4.Tone.Duration{
.attack = 0,
.decay = 0,
.sustain = 6,
.release = 6,
},
w4.Tone.Volume{
.sustain = 100,
.attack = 100,
},
w4.Tone.Flags{
.channel = .triangle,
.pulse_duty = .@"1/4",
},
);
sound_timer = 12;
}
fn drawMap() !void {
w4.m.colors.* = .{
._0 = .p3,
._1 = .p2,
._2 = .p1,
._3 = .p0,
};
var col: u32 = 0;
while (col < screen_width) {
var row: u32 = 0;
defer col += 1;
while (row < screen_height) {
defer row += 1;
var tile = map.data[col * map.width + row];
var tileX = tile % map.ts_width;
var tileY = tile / map.ts_width;
// if (!done) {
// var buf = fmt.bufPrint(&textBuf, "{},{}: {}: {},{}", .{col, row, tile, tileX, tileY}) catch unreachable;
// w4.trace(buf);
// }
w4.blitSub(
&sprites.kenney_rpg,
row * 8,
col * 8,
8,
8,
@intCast(u32, tileX) * 8,
@intCast(u32, tileY) * 8,
sprites.kenney_rpg_width,
w4.BlitFlags{.two_bits = true},
);
}
}
}
fn move_mara(gamepad: w4.GamePad) void {
if (mara_speed > 0) {
mara_speed -= 1;
}
if (gamepad.up) {
mara_direction = Direction.Up;
mara_speed = 1;
} else if (gamepad.down) {
mara_direction = Direction.Down;
mara_speed = 1;
} else if (gamepad.left) {
mara_direction = Direction.Left;
mara_speed = 1;
} else if (gamepad.right) {
mara_direction = Direction.Right;
mara_speed = 1;
}
switch (mara_direction) {
.Up => {
mara_box.base.y -= mara_speed;
},
.Down => {
mara_box.base.y += mara_speed;
},
.Left => {
mara_box.base.x -= mara_speed;
},
.Right => {
mara_box.base.x += mara_speed;
},
}
}
fn title() !void {
w4.m.colors._0 = .p3;
w4.m.colors._1 = .p0;
w4.text("Mara 2:\nTamamo's Fury", 28, 8);
w4.text("Press z or x", 32, 136);
w4.text("From Within 2022", 16, 152);
w4.m.colors._0 = .p0;
w4.m.colors._1 = .p1;
w4.m.colors._2 = .p2;
w4.m.colors._3 = .p3;
w4.blit(&sprites.tamamotitle, 48, 60, sprites.tamamotitle_width, sprites.tamamotitle_height, w4.BlitFlags{.two_bits = true});
const gamepad = w4.m.gamepads[0];
if (gamepad.a or gamepad.b) {
state = .StoryDump;
}
}
const story = "After defeating\nthe evil mage,\nMalto was at\npeace.\n\nOne day Mara was\nwalking along the\nbeach when she saw\nthe killing stone\nwas split in two.\nTamamo-no-Mae was\nfree to wreak havoc\nacross the land.\n\nHelp us again Mara!\nSave Kanar from\nTamamo-no-Mae!\n\nPress x.";
var story_idx: usize = 0;
var story_counter: u8 = 4;
fn storydump() !void {
w4.m.colors._0 = .p3;
w4.m.colors._1 = .p0;
w4.text(story[0..story_idx], 4, 4);
const gamepad = w4.m.gamepads[0];
if (gamepad.b) {
state = .Gameplay;
palette.mist();
}
if (story_idx < story.len) {
story_counter -= 1;
if (gamepad.a) {
story_counter = 0;
}
if (story_counter == 0) {
story_idx += 1;
story_counter = 4;
w4.tone(
w4.Tone.Frequency{.start = 280, .end = 310},
w4.Tone.Duration{
.attack = 0,
.decay = 0,
.sustain = 2,
.release = 0,
},
w4.Tone.Volume{
.sustain = 100,
.attack = 100,
},
w4.Tone.Flags{
.channel = .triangle,
.pulse_duty = .@"1/4",
},
);
}
} else {
if (gamepad.a) {
state = .Gameplay;
palette.mist();
}
}
}
export fn update() void {
switch (state) {
.Title => title() catch unreachable,
.StoryDump => storydump() catch unreachable,
.Gameplay => gameplay() catch unreachable,
}
}
fn gameplay() !void {
defer done = true;
if (sound_timer != 0) {
sound_timer -= 1;
}
drawMap() catch unreachable;
const gamepad = w4.m.gamepads[0];
const old_speed = mara_speed;
if (!tframe.enabled) {
move_mara(gamepad);
} else {
tframe.update(gamepad);
}
for (map.coll) |box| {
if (mara_box.collides(box)) {
switch (mara_direction) {
.Up => {
mara_box.base.y += mara_speed;
},
.Down => {
mara_box.base.y -= mara_speed;
},
.Left => {
mara_box.base.x += mara_speed;
},
.Right => {
mara_box.base.x -= mara_speed;
},
}
mara_speed = 0;
bonk();
}
}
for (map.triggers) |trig| {
if (mara_box.collides(trig.aura) and mara_direction == trig.direction and gamepad.b) {
tframe.set_text(trig.dialogue);
}
}
if (mara_box.base.x < 0) {
mara_box.base.x = 0;
bonk();
} else if (mara_box.base.x > 160 - mara_box.width) {
mara_box.base.x = 160 - mara_box.width;
bonk();
}
if (mara_box.base.y < 0) {
mara_box.base.y = 0;
bonk();
} else if (mara_box.base.y > 160 - mara_box.height) {
mara_box.base.y = 160 - mara_box.height;
bonk();
}
var flags: w4.BlitFlags = w4.BlitFlags {
.two_bits = true,
};
// w4.m.colors._0 = .p0;
// w4.m.colors._1 = .p1;
// w4.m.colors._2 = .p3;
// w4.m.colors._3 = .transparent;
// w4.blit(&sprites.glaceon, 0, 0, sprites.glaceon_width, sprites.glaceon_height, flags);
w4.m.colors.* = .{
._0 = .transparent,
._1 = .p0,
._2 = .p1,
._3 = .p3,
};
if (mara_direction == Direction.Left) {
flags.flip_x = true;
}
if (frame_count % 15 == 0 and mara_speed > 0) {
mara_frame = !mara_frame;
}
if (old_speed != mara_speed) {
mara_frame = !mara_frame;
}
var frame: u32 = switch (mara_direction) {
.Left => 4,
.Right => 4,
.Up => 2,
.Down => 0,
};
var step: u32 = if (mara_frame) 1 else 0;
w4.blitSub(&sprites.Mara, @intCast(u32, mara_box.base.x), @intCast(u32, mara_box.base.y), 16, 16, 16 * (frame + step), 0, 96, flags);
frame_count += 1;
}