X-Git-Url: https://git.rohieb.name/hackover2013-badge-firmware.git/blobdiff_plain/81be30fb6f37d0f9633d5883445f3ebc57989a53..d265161cb9c1651b365e447a654c6eabe6b5470d:/badge/jumpnrun/jumpnrun.c diff --git a/badge/jumpnrun/jumpnrun.c b/badge/jumpnrun/jumpnrun.c index 9f6053a..0bdac94 100644 --- a/badge/jumpnrun/jumpnrun.c +++ b/badge/jumpnrun/jumpnrun.c @@ -19,8 +19,8 @@ static fixed_point const accel_vert = FIXED_POINT_I(0, 167); static fixed_point const drag_factor = FIXED_POINT_I(0, 854); static fixed_point const speed_jump_x = FIXED_POINT_I(0, 600); -static vec2d const hacker_extent = { FIXED_INT_I(5), FIXED_INT_I(8) }; -static vec2d const shot_spawn_inertia = { FIXED_POINT_I(1, 0), FIXED_POINT_I(0, -800) }; +vec2d hacker_extents(void) { return (vec2d) { FIXED_INT_I(5), FIXED_INT_I(8) }; } +static vec2d const shot_spawn_inertia = { FIXED_POINT_I(0, 800), FIXED_POINT_I(0, -800) }; static badge_sprite const anim_hacker[] = { { 5, 8, (uint8_t const *) "\x1c\xff\xfd\x04\x04" }, @@ -48,21 +48,21 @@ static badge_sprite const anim_hacker[] = { }; static badge_sprite const anim_sickle[] = { + { 3, 3, (uint8_t const *) "\xab\x01" }, + { 3, 3, (uint8_t const *) "\xee\x00" } +/* { 3, 3, (uint8_t const *) "\x8a\x01" }, { 3, 3, (uint8_t const *) "\x6a" }, { 3, 3, (uint8_t const *) "\xa3" }, { 3, 3, (uint8_t const *) "\xac" } +*/ }; enum { - JUMPNRUN_SHOT_EXTENT = 3, - JUMPNRUN_SHOT_TICKS_PER_FRAME = 24 + JUMPNRUN_SHOT_EXTENT = 3, + JUMPNRUN_SHOT_TICKS_PER_FRAME = 36 }; -static void jumpnrun_shot_despawn(jumpnrun_shot *shot) { - shot->inertia.x = FIXED_INT(0); -} - static void jumpnrun_shot_spawn(jumpnrun_shot *shot, jumpnrun_game_state const *state) { shot->tick = 0; shot->inertia = shot_spawn_inertia; @@ -75,6 +75,9 @@ static void jumpnrun_shot_spawn(jumpnrun_shot *shot, jumpnrun_game_state const * shot->current_box = rectangle_new((vec2d) { rectangle_right(&state->player.current_box), rectangle_top(&state->player.current_box) }, (vec2d) { FIXED_INT(JUMPNRUN_SHOT_EXTENT), FIXED_INT(JUMPNRUN_SHOT_EXTENT) }); } + + shot->old_box = shot->current_box; + shot->inertia = vec2d_add(shot->inertia, state->player.inertia); } static inline int imax(int x, int y) { @@ -83,8 +86,8 @@ static inline int imax(int x, int y) { static inline fixed_point hacker_left (vec2d const *pos, jumpnrun_game_state const *state) { (void) state; return pos->x; } static inline fixed_point hacker_top (vec2d const *pos, jumpnrun_game_state const *state) { (void) state; return pos->y; } -static inline fixed_point hacker_right (vec2d const *pos, jumpnrun_game_state const *state) { return fixed_point_add(hacker_left(pos, state), hacker_extent.x); } -static inline fixed_point hacker_bottom(vec2d const *pos, jumpnrun_game_state const *state) { return fixed_point_add(hacker_top (pos, state), hacker_extent.y); } +static inline fixed_point hacker_right (vec2d const *pos, jumpnrun_game_state const *state) { return fixed_point_add(hacker_left(pos, state), hacker_extents().x); } +static inline fixed_point hacker_bottom(vec2d const *pos, jumpnrun_game_state const *state) { return fixed_point_add(hacker_top (pos, state), hacker_extents().y); } int jumpnrun_level_assert_left_side(jumpnrun_game_state const *state) { static int const lmargin = 20; @@ -188,10 +191,10 @@ static void jumpnrun_apply_movement(jumpnrun_level const *lv, } *inertia_mod = state->player.inertia; - collisions_tiles_displace(&new_pos, &state->player, lv, tilerange, inertia_mod); + bool killed = collisions_tiles_displace(&new_pos, &state->player, lv, tilerange, inertia_mod); state->player.inertia = *inertia_mod; - if(fixed_point_gt(state->player.current_box.pos.y, FIXED_INT(BADGE_DISPLAY_HEIGHT))) { + if(killed || fixed_point_gt(state->player.current_box.pos.y, FIXED_INT(BADGE_DISPLAY_HEIGHT))) { state->status = JUMPNRUN_DEAD; } } @@ -218,19 +221,25 @@ void jumpnrun_level_tick(jumpnrun_level *lv, } for(size_t item = 0; item < lv->header.item_count; ++item) { - int screenpos = fixed_point_cast_int(lv->items[item].pos.x) - state->left; - if(screenpos > -lv->items[item].type->sprite.width && + jumpnrun_item *item_obj = &lv->items[item]; + + if(item_obj->flags & JUMPNRUN_ITEM_COLLECTED) { + continue; + } + + int screenpos = fixed_point_cast_int(item_obj->pos.x) - state->left; + if(screenpos > -item_obj->type->sprite.width && screenpos < BADGE_DISPLAY_WIDTH) { - rectangle item_rect = rect_from_item(&lv->items[item]); + rectangle item_rect = rect_from_item(item_obj); if(rectangle_intersect(&state->player.current_box, &item_rect)) { - lv->items[item].type->on_collect(state); + item_obj->type->on_collect(item_obj, state, lv); } badge_framebuffer_blt(&fb, screenpos, - fixed_point_cast_int(lv->items[item].pos.y), - &lv->items[item].type->sprite, + fixed_point_cast_int(item_obj->pos.y), + &item_obj->type->sprite, 0); } } @@ -240,17 +249,28 @@ void jumpnrun_level_tick(jumpnrun_level *lv, if(jumpnrun_shot_spawned(shot)) { rectangle_move_rel(&shot->current_box, shot->inertia); - jumpnrun_passive_movement(&shot->inertia); + shot->inertia = vec2d_add(shot->inertia, gravity); + if(fixed_point_gt(rectangle_top(&shot->current_box), FIXED_INT(BADGE_DISPLAY_HEIGHT))) { jumpnrun_shot_despawn(shot); } + /* show every position twice, because LCD switching time. This makes the shots more + * visible on the nokia lcds. + */ + badge_framebuffer_blt(&fb, + fixed_point_cast_int(shot->old_box.pos.x) - state->left, + fixed_point_cast_int(shot->old_box.pos.y), + &anim_sickle[shot->tick / JUMPNRUN_SHOT_TICKS_PER_FRAME], + fixed_point_lt(shot->inertia.x, FIXED_INT(0)) ? BADGE_BLT_MIRRORED : 0); badge_framebuffer_blt(&fb, fixed_point_cast_int(shot->current_box.pos.x) - state->left, fixed_point_cast_int(shot->current_box.pos.y), &anim_sickle[shot->tick / JUMPNRUN_SHOT_TICKS_PER_FRAME], fixed_point_lt(shot->inertia.x, FIXED_INT(0)) ? BADGE_BLT_MIRRORED : 0); + shot->old_box = shot->current_box; + ++shot->tick; if(shot->tick == ARRAY_SIZE(anim_sickle) * JUMPNRUN_SHOT_TICKS_PER_FRAME) { shot->tick = 0; @@ -284,7 +304,8 @@ void jumpnrun_level_tick(jumpnrun_level *lv, if(jumpnrun_shot_spawned(shot)) { rectangle_move_rel(&shot->current_box, shot->inertia); - jumpnrun_passive_movement(&shot->inertia); + shot->inertia = vec2d_add(shot->inertia, gravity); + if(fixed_point_gt(rectangle_top(&shot->current_box), FIXED_INT(BADGE_DISPLAY_HEIGHT))) { jumpnrun_shot_despawn(shot); } @@ -317,13 +338,22 @@ uint8_t jumpnrun_play(char const *lvname) { jumpnrun_game_state gs; memset(&gs, 0, sizeof(gs)); - gs.player.current_box = rectangle_new(lv.start_pos, hacker_extent); + for(gs.lives = 99; gs.status != JUMPNRUN_WON && gs.lives != 0; --gs.lives) { + gs.status = JUMPNRUN_PLAYING; + gs.left = 0; + memset(&gs.player, 0, sizeof(gs.player)); + gs.player.current_box = rectangle_new(lv.start_pos, + hacker_extents()); - while(gs.status == JUMPNRUN_PLAYING) { - badge_event_t ev = badge_event_wait(); + for(size_t i = 0; i < lv.header.enemy_count; ++i) { + lv.enemies[i].flags = 0; + } + + while(gs.status == JUMPNRUN_PLAYING) { + badge_event_t ev = badge_event_wait(); - switch(badge_event_type(ev)) { - case BADGE_EVENT_USER_INPUT: + switch(badge_event_type(ev)) { + case BADGE_EVENT_USER_INPUT: { uint8_t old_state = badge_event_old_input_state(ev); uint8_t new_state = badge_event_new_input_state(ev); @@ -345,11 +375,12 @@ uint8_t jumpnrun_play(char const *lvname) { break; } - case BADGE_EVENT_GAME_TICK: + case BADGE_EVENT_GAME_TICK: { jumpnrun_level_tick(&lv, &gs); break; } + } } }