2022-07-02 00:22:38 +00:00
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 " ) ;
2022-07-01 21:10:57 +00:00
const std = @import ( " std " ) ;
const fmt = std . fmt ;
2022-04-24 09:46:36 +00:00
2022-06-27 03:39:57 +00:00
const Direction = sh0rk . Direction ;
const Point = sh0rk . Point ;
const Rect = sh0rk . Rect ;
2022-07-02 01:46:56 +00:00
const map = @import ( " ./maps/overworld.zig " ) ;
2022-07-01 22:05:55 +00:00
2022-06-27 03:39:57 +00:00
var frame_count : u32 = 0 ;
var mara_direction : Direction = Direction . Right ;
var mara_frame : bool = false ;
2022-07-02 12:49:59 +00:00
var mara_box : Rect = Rect { . base = map . start_point , . width = 16 , . height = 16 } ;
2022-07-02 12:16:29 +00:00
var mara_speed : i16 = 0 ;
var old_speed : i16 = 0 ;
2022-06-27 03:39:57 +00:00
2022-07-02 01:18:54 +00:00
const screen_width = 20 ;
const screen_height = 20 ;
2022-07-02 12:49:59 +00:00
const tile_size : i16 = 8 ;
2022-07-02 00:22:38 +00:00
2022-07-01 18:23:39 +00:00
var sound_timer : u8 = 0 ;
2022-07-01 17:11:52 +00:00
var textBuf : [ 160 ] u8 = undefined ;
2022-07-02 01:18:54 +00:00
var done : bool = false ;
2022-07-01 21:10:57 +00:00
2022-07-02 17:40:41 +00:00
var camera = Point { . x = 32 , . y = 0 } ;
2022-07-02 01:46:13 +00:00
2022-07-02 12:16:29 +00:00
var state : sh0rk . State = . Gameplay ;
fn world_to_screen ( p : Point ) Point {
2022-07-02 17:04:58 +00:00
return p . sub ( camera ) ;
2022-07-02 12:16:29 +00:00
}
fn screen_to_world ( p : Point ) Point {
p . add ( camera ) ;
}
2022-07-02 02:51:31 +00:00
2022-06-27 03:39:57 +00:00
export fn start ( ) void {
2022-07-02 12:16:29 +00:00
palette . mist ( ) ;
2022-07-02 00:22:38 +00:00
}
2022-07-01 17:11:52 +00:00
2022-07-01 18:23:39 +00:00
fn bonk ( ) void {
if ( sound_timer ! = 0 ) {
return ;
}
w4 . tone (
2022-07-02 12:49:59 +00:00
w4 . Tone . Frequency { . start = 220 , . end = 40 } ,
2022-07-01 18:23:39 +00:00
w4 . Tone . Duration {
. attack = 0 ,
. decay = 0 ,
. sustain = 6 ,
. release = 6 ,
} ,
w4 . Tone . Volume {
. sustain = 100 ,
. attack = 100 ,
} ,
w4 . Tone . Flags {
. channel = . triangle ,
2022-07-01 21:10:57 +00:00
. pulse_duty = . @ " 1/4 " ,
2022-07-01 18:23:39 +00:00
} ,
) ;
2022-07-02 17:04:58 +00:00
sound_timer = 30 ;
2022-07-01 18:23:39 +00:00
}
2022-07-02 17:04:58 +00:00
fn map_colors ( ) void {
2022-07-02 13:21:51 +00:00
switch ( map . tileset ) {
. Dungeon = > {
w4 . m . colors . * = . {
. _0 = . p2 ,
. _1 = . p0 ,
. _2 = . p1 ,
. _3 = . p3 ,
} ;
} ,
. Rpg = > {
w4 . m . colors . * = . {
. _0 = . p3 ,
. _1 = . p2 ,
. _2 = . p1 ,
. _3 = . p0 ,
} ;
} ,
}
2022-07-02 17:04:58 +00:00
}
2022-07-02 17:40:41 +00:00
fn clampCamera ( ) void {
if ( camera . x < 0 ) {
camera . x = 0 ;
}
if ( camera . y < 0 ) {
camera . y = 0 ;
}
if ( camera . x > = ( map . width * 8 ) - screen_width * 8 ) {
camera . x = ( map . width * 8 ) - screen_width * 8 ;
}
if ( camera . y > = ( map . height * 8 ) - screen_height * 8 ) {
camera . y = ( map . height * 8 ) - screen_height * 8 ;
}
}
2022-07-02 17:04:58 +00:00
fn drawMap ( ) ! void {
map_colors ( ) ;
2022-07-02 12:49:59 +00:00
2022-07-02 17:04:58 +00:00
var startCol = @divTrunc ( camera . x , tile_size ) ;
2022-07-02 12:49:59 +00:00
var endCol = startCol + screen_width ;
2022-07-02 17:04:58 +00:00
var startRow = @divTrunc ( camera . y , tile_size ) ;
2022-07-02 12:49:59 +00:00
var endRow = startRow + screen_height ;
2022-07-02 17:04:58 +00:00
var col : i16 = startCol ;
2022-07-02 17:40:41 +00:00
while ( col < endCol + 1 ) {
2022-07-02 17:04:58 +00:00
var row : i16 = startRow ;
2022-07-02 12:49:59 +00:00
defer col + = 1 ;
2022-07-02 17:40:41 +00:00
while ( row < endRow + 1 ) {
2022-07-01 21:10:57 +00:00
defer row + = 1 ;
2022-07-02 17:04:58 +00:00
if ( col < map . width and row < map . height ) {
var tile = map . get_tile ( col , row ) ;
var world = Point { . x = col * 8 , . y = row * 8 } ;
var scr = world_to_screen ( world ) ;
2022-07-02 17:40:41 +00:00
// if(!done) {
// var buf = fmt.bufPrint(&textBuf, "{},{}: {},{}", .{ row, col, scr.x, scr.y }) catch unreachable;
// w4.trace(buf);
// }
2022-07-02 12:49:59 +00:00
2022-07-02 17:40:41 +00:00
draw_tile ( tile , scr . x , scr . y ) ;
2022-07-02 13:21:51 +00:00
}
2022-07-01 21:10:57 +00:00
}
2022-07-01 17:11:52 +00:00
}
}
2022-07-02 17:04:58 +00:00
fn draw_tile ( tile : u32 , x : i32 , y : i32 ) void {
2022-07-02 12:49:59 +00:00
if ( tile = = 0 ) {
w4 . rect ( x , y , 8 , 8 ) ;
return ;
}
var tileX = ( tile - 1 ) % map . ts_width ;
var tileY = ( tile - 1 ) / map . ts_width ;
2022-07-02 12:16:29 +00:00
switch ( map . tileset ) {
. Rpg = > w4 . blitSub (
2022-07-02 12:49:59 +00:00
& sprites . kenney_rpg ,
2022-07-02 12:16:29 +00:00
x ,
y ,
2022-07-02 12:49:59 +00:00
8 ,
2022-07-02 12:16:29 +00:00
8 ,
2022-07-02 17:04:58 +00:00
tileX * 8 ,
tileY * 8 ,
2022-07-02 12:49:59 +00:00
sprites . kenney_rpg_width ,
w4 . BlitFlags { . two_bits = true } ,
2022-07-02 12:16:29 +00:00
) ,
. Dungeon = > w4 . blitSub (
2022-07-02 12:49:59 +00:00
& sprites . dungeon ,
2022-07-02 12:16:29 +00:00
x ,
y ,
2022-07-02 12:49:59 +00:00
8 ,
2022-07-02 12:16:29 +00:00
8 ,
2022-07-02 17:04:58 +00:00
tileX * 8 ,
tileY * 8 ,
2022-07-02 12:49:59 +00:00
sprites . dungeon_width ,
w4 . BlitFlags { . two_bits = true } ,
2022-07-02 12:16:29 +00:00
) ,
}
}
2022-07-01 18:23:39 +00:00
fn move_mara ( gamepad : w4 . GamePad ) void {
2022-07-02 00:22:38 +00:00
if ( mara_speed > 0 ) {
mara_speed - = 1 ;
2022-06-27 12:56:16 +00:00
}
2022-06-27 03:39:57 +00:00
if ( gamepad . up ) {
mara_direction = Direction . Up ;
2022-07-01 15:06:47 +00:00
mara_speed = 1 ;
2022-06-27 03:39:57 +00:00
} else if ( gamepad . down ) {
mara_direction = Direction . Down ;
2022-07-01 15:06:47 +00:00
mara_speed = 1 ;
2022-06-27 03:39:57 +00:00
} else if ( gamepad . left ) {
mara_direction = Direction . Left ;
2022-07-01 15:06:47 +00:00
mara_speed = 1 ;
2022-06-27 03:39:57 +00:00
} else if ( gamepad . right ) {
mara_direction = Direction . Right ;
2022-07-01 15:06:47 +00:00
mara_speed = 1 ;
2022-06-27 03:39:57 +00:00
}
switch ( mara_direction ) {
. Up = > {
2022-07-02 17:40:41 +00:00
camera . y - = mara_speed ;
mara_box . base . y - = mara_speed ;
2022-06-27 03:39:57 +00:00
} ,
. Down = > {
2022-07-02 17:40:41 +00:00
camera . y + = mara_speed ;
mara_box . base . y + = mara_speed ;
2022-06-27 03:39:57 +00:00
} ,
. Left = > {
2022-07-02 17:40:41 +00:00
camera . x - = mara_speed ;
mara_box . base . x - = mara_speed ;
2022-06-27 03:39:57 +00:00
} ,
. Right = > {
2022-07-02 17:40:41 +00:00
camera . x + = mara_speed ;
mara_box . base . x + = mara_speed ;
2022-06-27 03:39:57 +00:00
} ,
}
2022-07-01 18:23:39 +00:00
}
2022-07-02 02:51:31 +00:00
fn title ( ) ! void {
2022-07-01 21:10:57 +00:00
w4 . m . colors . _0 = . p3 ;
w4 . m . colors . _1 = . p0 ;
2022-07-02 02:51:31 +00:00
w4 . text ( " Mara 2: \n Tamamo'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 ;
2022-07-02 12:49:59 +00:00
w4 . blit ( & sprites . tamamotitle , 48 , 60 , sprites . tamamotitle_width , sprites . tamamotitle_height , w4 . BlitFlags { . two_bits = true } ) ;
2022-07-02 02:51:31 +00:00
const gamepad = w4 . m . gamepads [ 0 ] ;
if ( gamepad . a or gamepad . b ) {
state = . StoryDump ;
}
}
const story = " After defeating \n the evil mage, \n Malto was at \n peace. \n \n One day Mara was \n walking along the \n beach when she saw \n the killing stone \n was split in two. \n Tamamo-no-Mae was \n free to wreak havoc \n across the land. \n \n Help us again Mara! \n Save Kanar from \n Tamamo-no-Mae! \n \n Press x. " ;
2022-07-02 17:04:58 +00:00
var story_idx : u16 = 0 ;
2022-07-02 02:51:31 +00:00
var story_counter : u8 = 4 ;
2022-07-02 12:49:59 +00:00
fn storydump ( ) ! void {
2022-07-02 02:51:31 +00:00
w4 . m . colors . _0 = . p3 ;
w4 . m . colors . _1 = . p0 ;
w4 . text ( story [ 0 . . story_idx ] , 4 , 4 ) ;
2022-07-02 12:49:59 +00:00
2022-07-02 02:51:31 +00:00
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 ;
2022-07-02 12:49:59 +00:00
2022-07-02 02:51:31 +00:00
w4 . tone (
2022-07-02 12:49:59 +00:00
w4 . Tone . Frequency { . start = 280 , . end = 310 } ,
2022-07-02 02:51:31 +00:00
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 ( ) ;
}
2022-07-02 12:49:59 +00:00
}
2022-07-01 21:10:57 +00:00
}
2022-07-01 18:23:39 +00:00
export fn update ( ) void {
2022-07-02 12:16:29 +00:00
defer frame_count + = 1 ;
2022-07-02 17:40:41 +00:00
if ( frame_count % 60 = = 0 ) {
done = false ;
}
2022-07-02 12:49:59 +00:00
2022-07-02 02:51:31 +00:00
switch ( state ) {
. Title = > title ( ) catch unreachable ,
. StoryDump = > storydump ( ) catch unreachable ,
. Gameplay = > gameplay ( ) catch unreachable ,
}
}
fn gameplay ( ) ! void {
2022-07-01 21:10:57 +00:00
defer done = true ;
2022-07-02 17:40:41 +00:00
defer clampCamera ( ) ;
2022-07-01 18:23:39 +00:00
if ( sound_timer ! = 0 ) {
sound_timer - = 1 ;
}
drawMap ( ) catch unreachable ;
const gamepad = w4 . m . gamepads [ 0 ] ;
2022-07-01 21:10:57 +00:00
2022-07-01 22:05:55 +00:00
if ( ! tframe . enabled ) {
move_mara ( gamepad ) ;
} else {
2022-07-02 17:40:41 +00:00
tframe . update ( gamepad ) ;
2022-07-01 21:10:57 +00:00
}
2022-07-01 17:37:13 +00:00
for ( map . coll ) | box | {
if ( mara_box . collides ( box ) ) {
2022-07-01 18:23:39 +00:00
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 ;
} ,
}
2022-07-01 17:37:13 +00:00
mara_speed = 0 ;
2022-07-01 18:23:39 +00:00
bonk ( ) ;
2022-07-01 17:37:13 +00:00
}
}
2022-07-01 22:05:55 +00:00
for ( map . triggers ) | trig | {
if ( mara_box . collides ( trig . aura ) and mara_direction = = trig . direction and gamepad . b ) {
tframe . set_text ( trig . dialogue ) ;
}
}
2022-07-02 17:40:41 +00:00
if ( mara_box . base . x < 0 ) {
2022-06-27 03:39:57 +00:00
mara_box . base . x = 0 ;
2022-07-01 21:10:57 +00:00
bonk ( ) ;
2022-06-27 03:39:57 +00:00
}
2022-07-02 12:49:59 +00:00
2022-07-02 17:40:41 +00:00
if ( mara_box . base . y < 0 ) {
2022-06-27 03:39:57 +00:00
mara_box . base . y = 0 ;
2022-07-01 21:10:57 +00:00
bonk ( ) ;
2022-04-24 09:46:36 +00:00
}
2022-07-02 12:16:29 +00:00
draw_mara ( ) ;
}
fn draw_glaceon ( p : Point ) void {
palette . mist ( ) ;
w4 . m . colors . * = . {
. _0 = . p0 ,
. _1 = . p1 ,
. _2 = . p3 ,
. _3 = . transparent ,
} ;
2022-07-02 12:49:59 +00:00
w4 . blit ( & sprites . glaceon , p . x , p . y , sprites . glaceon_width , sprites . glaceon_height , w4 . BlitFlags { . two_bits = true } ) ;
2022-07-02 12:16:29 +00:00
}
fn draw_mara ( ) void {
2022-07-02 12:49:59 +00:00
var flags : w4 . BlitFlags = w4 . BlitFlags {
2022-07-01 15:06:47 +00:00
. two_bits = true ,
} ;
2022-07-01 17:11:52 +00:00
w4 . m . colors . * = . {
. _0 = . transparent ,
. _1 = . p0 ,
. _2 = . p1 ,
. _3 = . p3 ,
} ;
2022-06-27 03:39:57 +00:00
if ( mara_direction = = Direction . Left ) {
flags . flip_x = true ;
}
2022-07-02 17:04:58 +00:00
if ( frame_count % 16 = = 0 and mara_speed > 0 ) {
2022-07-02 12:49:59 +00:00
mara_frame = ! mara_frame ;
2022-06-27 12:56:16 +00:00
}
2022-06-27 03:39:57 +00:00
var frame : u32 = switch ( mara_direction ) {
. Left = > 4 ,
. Right = > 4 ,
. Up = > 2 ,
. Down = > 0 ,
} ;
2022-07-02 12:16:29 +00:00
var step : u32 = if ( mara_frame ) 1 else 0 ;
2022-06-27 03:39:57 +00:00
2022-07-02 17:40:41 +00:00
w4 . blitSub (
& sprites . Mara ,
mara_box . base . x ,
mara_box . base . y ,
16 ,
16 ,
16 * ( frame + step ) ,
0 ,
96 ,
flags ,
) ;
var scr = world_to_screen ( mara_box . base ) ;
w4 . blitSub (
& sprites . Mara ,
scr . x ,
scr . y ,
16 ,
16 ,
16 * ( frame + step ) ,
0 ,
96 ,
flags ,
) ;
2022-07-02 12:49:59 +00:00
}
2022-07-02 13:50:37 +00:00
pub fn panic ( msg : [ ] const u8 , st : ? * std . builtin . StackTrace ) noreturn {
_ = st ;
w4 . trace ( " !!! PANIC !!! " ) ;
w4 . trace ( msg ) ;
2022-07-02 17:04:58 +00:00
unreachable ;
2022-07-02 13:50:37 +00:00
}