Ohne Checkpoint wieder am Anfang spawnen.
[hackover2013-badge-firmware.git] / badge / jumpnrun / jumpnrun.c
index 2aea579..28d5976 100644 (file)
@@ -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,15 +48,19 @@ 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_TICKS_PER_FRAME = 36
 };
 
 static void jumpnrun_shot_spawn(jumpnrun_shot *shot, jumpnrun_game_state const *state) {
@@ -71,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) {
@@ -79,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;
@@ -184,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;
   }
 }
@@ -214,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);
       }
     }
@@ -236,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;
@@ -280,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);
         }
@@ -313,13 +338,23 @@ 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 = 3; 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();
 
-    switch(badge_event_type(ev)) {
-    case BADGE_EVENT_USER_INPUT:
+    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:
       {
         uint8_t old_state = badge_event_old_input_state(ev);
         uint8_t new_state = badge_event_new_input_state(ev);
@@ -341,11 +376,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;
       }
+      }
     }
   }
 
This page took 0.02924 seconds and 4 git commands to generate.