7d31eed2d52660b8338000373f894395d980ebdf
[hackover2013-badge-firmware.git] / badge / jumpnrun / enemies.c
1 #include "enemies.h"
2
3 #include "collision.h"
4 #include "tiles.h"
5 #include "jumpnrun.h"
6
7 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof*(arr))
8
9 static badge_sprite const anim_cat[] = {
10 { 8, 5, (uint8_t const *) "\xc7\x3f\xce\x38\x11" },
11 { 8, 5, (uint8_t const *) "\xd7\x7d\xc6\x19\x25" }
12 };
13
14 static badge_sprite const anim_mushroom[] = {
15 { 7, 7, (uint8_t const *) "\x10\x0c\x9f\xcf\xc7\x40" },
16 { 7, 7, (uint8_t const *) "\x20\x18\x1e\x8f\x87\x81" },
17 { 7, 7, (uint8_t const *) "\x10\x0c\x9f\xcf\xc7\x40" },
18 { 7, 7, (uint8_t const *) "\x08\x86\xdf\xef\x67\x20" },
19 { 7, 7, (uint8_t const *) "\x04\xc3\xef\xf7\x33\x10" },
20 { 7, 7, (uint8_t const *) "\x04\xc3\xe7\xf3\x31\x10" }
21 };
22
23 void jumpnrun_process_enemy(jumpnrun_enemy *self,
24 badge_framebuffer *fb,
25 struct jumpnrun_game_state *state,
26 struct jumpnrun_level *lv,
27 struct jumpnrun_tile_range const *visible_tiles) {
28 int const spawn_margin = 1 + self->type->animation_frames[self->current_frame].width;
29
30 if(self->flags & JUMPNRUN_ENEMY_SPAWNED) {
31 if(fixed_point_lt(self->current_pos.x, FIXED_POINT(state->left - spawn_margin, 0)) ||
32 fixed_point_gt(self->current_pos.x, FIXED_POINT(state->left + BADGE_DISPLAY_WIDTH + spawn_margin, 0)) ||
33 fixed_point_cast_int(self->current_pos.y) > BADGE_DISPLAY_HEIGHT) {
34 self->flags &= ~JUMPNRUN_ENEMY_SPAWNED;
35 } else {
36 self->type->game_tick(self, state, lv, visible_tiles);
37
38 if(state->tick_minor == 0) {
39 badge_framebuffer_blt(fb,
40 fixed_point_cast_int(self->current_pos.x) - state->left,
41 fixed_point_cast_int(self->current_pos.y),
42 &self->type->animation_frames[self->current_frame],
43 fixed_point_lt(self->inertia.x, FIXED_POINT(0, 0)) ? 0 : BADGE_BLT_MIRRORED);
44 }
45 }
46 } else if(self->flags & JUMPNRUN_ENEMY_UNAVAILABLE) {
47 if(state->left > fixed_point_cast_int(self->spawn_pos.x) + spawn_margin ||
48 state->left + BADGE_DISPLAY_WIDTH + spawn_margin < fixed_point_cast_int(self->spawn_pos.x)) {
49 self->flags &= ~JUMPNRUN_ENEMY_UNAVAILABLE;
50 }
51 } else if((fixed_point_gt(self->spawn_pos.x, FIXED_POINT(state->left - spawn_margin, 0)) &&
52 fixed_point_lt(self->spawn_pos.x, FIXED_POINT(state->left - spawn_margin / 2, 0))) ||
53 (fixed_point_lt(self->spawn_pos.x, FIXED_POINT(state->left + BADGE_DISPLAY_WIDTH + spawn_margin, 0)) &&
54 fixed_point_gt(self->spawn_pos.x, FIXED_POINT(state->left + BADGE_DISPLAY_WIDTH, 0)))) {
55 // enemy unspawned, available and in spawn zone.
56 self->flags |= JUMPNRUN_ENEMY_SPAWNED | JUMPNRUN_ENEMY_UNAVAILABLE;
57 self->current_pos = self->spawn_pos;
58 self->inertia = self->type->spawn_inertia;
59 self->current_frame = 0;
60 self->tick_counter = 0;
61 }
62 }
63
64 void enemy_collision_tiles_bounce_horiz(jumpnrun_enemy *self,
65 vec2d *desired_position,
66 jumpnrun_level *lv,
67 jumpnrun_tile_range const *visible_tiles) {
68 rectangle rect_self = rect_from_enemy(self);
69 vec2d inertia_copy = self->inertia;
70 bool touching_ground = false;
71
72 collisions_tiles_displace(desired_position,
73 &rect_self,
74 lv,
75 visible_tiles,
76 &inertia_copy,
77 &touching_ground);
78
79 if(fixed_point_ne(inertia_copy.x, self->inertia.x)) {
80 self->inertia.x = fixed_point_neg(self->inertia.x);
81 }
82 }
83
84 void enemy_collision_player_jumpable(jumpnrun_enemy *self,
85 jumpnrun_game_state *state)
86 {
87 rectangle rect_self = rect_from_enemy(self);
88 rectangle rect_hacker = hacker_rect_current(state);
89
90 if(rectangle_intersect(&rect_self, &rect_hacker)) {
91 if(fixed_point_gt(state->inertia.y, FIXED_POINT(0, 0))) {
92 self->flags &= ~JUMPNRUN_ENEMY_SPAWNED;
93 state->inertia_mod.y = FIXED_POINT(0, -167);
94 state->jumpable_frames = 12;
95 } else {
96 state->status = JUMPNRUN_DEAD;
97 }
98 }
99 }
100
101 void enemy_tick_cat(jumpnrun_enemy *self,
102 jumpnrun_game_state *state,
103 jumpnrun_level *lv,
104 jumpnrun_tile_range const *visible_tiles) {
105 int screenpos = fixed_point_cast_int(self->current_pos.x);
106
107 if(screenpos + JUMPNRUN_MAX_SPAWN_MARGIN < state->left ||
108 screenpos >= state->left + BADGE_DISPLAY_WIDTH + JUMPNRUN_MAX_SPAWN_MARGIN) {
109 return;
110 }
111
112 jumpnrun_passive_movement(&self->inertia);
113
114 vec2d new_pos = vec2d_add(self->current_pos, self->inertia);
115 self->type->collision_tiles(self, &new_pos, lv, visible_tiles);
116 self->type->collision_player(self, state);
117 self->current_pos = new_pos;
118
119 self->tick_counter = (self->tick_counter + 1) % self->type->animation_ticks_per_frame;
120 if(self->tick_counter == 0) {
121 self->current_frame = (self->current_frame + 1) % self->type->animation_length;
122 }
123 }
124
125 jumpnrun_enemy_type const jumpnrun_enemy_type_data[JUMPNRUN_ENEMY_TYPE_COUNT] = {
126 { 16, ARRAY_SIZE(anim_cat), anim_cat,
127 { FIXED_POINT_I(0, -100), FIXED_POINT_I(0, 0) },
128 enemy_collision_tiles_bounce_horiz,
129 enemy_collision_player_jumpable,
130 enemy_tick_cat
131 }, {
132 12, ARRAY_SIZE(anim_mushroom), anim_mushroom,
133 { FIXED_POINT_I(0, -50), FIXED_POINT_I(0, 0) },
134 enemy_collision_tiles_bounce_horiz,
135 enemy_collision_player_jumpable,
136 enemy_tick_cat
137 }
138 };
This page took 0.050849 seconds and 3 git commands to generate.