Verbesserte Rotor-Sprites.
[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 static badge_sprite const anim_cat[] = {
8 { 8, 5, (uint8_t const *) "\xc7\x3f\xce\x38\x11" },
9 { 8, 5, (uint8_t const *) "\xd7\x7d\xc6\x19\x25" }
10 };
11
12 static badge_sprite const anim_mushroom[] = {
13 { 7, 7, (uint8_t const *) "\x10\x0c\x9f\xcf\xc7\x40" },
14 { 7, 7, (uint8_t const *) "\x20\x18\x1e\x8f\x87\x81" },
15 { 7, 7, (uint8_t const *) "\x10\x0c\x9f\xcf\xc7\x40" },
16 { 7, 7, (uint8_t const *) "\x08\x86\xdf\xef\x67\x20" },
17 { 7, 7, (uint8_t const *) "\x04\xc3\xef\xf7\x33\x10" },
18 { 7, 7, (uint8_t const *) "\x04\xc3\xe7\xf3\x31\x10" }
19 };
20
21 static badge_sprite const anim_kaninchen[] = {
22 { 7, 5, (uint8_t const *) "\x60\x30\xbe\x31\x02" },
23 { 7, 5, (uint8_t const *) "\x42\x30\xbe\x31\x01" },
24 { 7, 5, (uint8_t const *) "\x42\x30\xae\x35\x01" },
25 { 7, 5, (uint8_t const *) "\x60\x30\xae\x35\x02" },
26 { 7, 5, (uint8_t const *) "\x60\x30\xbe\x31\x01" }
27 };
28
29 static badge_sprite const anim_snake[] = {
30 { 10, 6, (uint8_t const *) "\x10\x86\x83\x30\x04\x83\xa2\x0f" },
31 { 10, 6, (uint8_t const *) "\x10\x86\x83\x20\x0c\xc1\xa2\x0f" },
32 { 10, 6, (uint8_t const *) "\x10\x86\x83\x20\x08\x82\xe0\x0f" },
33 { 10, 6, (uint8_t const *) "\x10\x86\x83\x20\x08\x86\xe1\x0f" }
34 };
35
36 static badge_sprite const anim_spiral[] = {
37 { 10, 10, (uint8_t const *) "\xff\x07\xd8\x6f\xa1\xb5\xf6\x1a\xe8\xbf\x00\xfe\x0f" },
38 { 10, 10, (uint8_t const *) "\xff\x07\xd8\x6f\xa1\xb5\xd6\xda\x69\xb0\x7f\x02\x0c" },
39 { 10, 10, (uint8_t const *) "\xff\x07\xd8\x6f\xa1\xb5\xd6\x5a\x6a\xaf\x81\xfe\x0b" },
40 { 10, 10, (uint8_t const *) "\xff\x07\xd8\x4f\x61\x35\xd5\x55\x54\x5f\x01\xfd\x07" },
41 { 10, 10, (uint8_t const *) "\xff\x07\xd0\x7f\x81\xf5\xd6\x5a\x68\xbf\x01\xfe\x0f" },
42 { 10, 10, (uint8_t const *) "\x03\xe4\xdf\x60\xb9\xb5\xd6\x5a\x68\xbf\x01\xfe\x0f" },
43 { 10, 10, (uint8_t const *) "\xfd\x17\x58\x6f\xa5\xb5\xd6\x5a\x68\xbf\x01\xfe\x0f" },
44 { 10, 10, (uint8_t const *) "\xfe\x0b\xa8\xaf\xa2\xba\xca\x6a\x28\xbf\x01\xfe\x0f" }
45 };
46
47 static badge_sprite const anim_rotor[] = {
48 { 9, 9, (uint8_t const *) "\x00\x00\x00\x00\xf0\xe1\x42\x0c\x18\x70\x00" },
49 { 9, 9, (uint8_t const *) "\x1c\x30\x60\x80\xf0\xe1\x40\x00\x00\x00\x00" },
50 { 9, 9, (uint8_t const *) "\x1c\x30\x60\x84\x0e\x1f\x00\x00\x00\x00\x00" },
51 { 9, 9, (uint8_t const *) "\x00\x00\x00\x04\x0e\x1f\x02\x0c\x18\x70\x00" }
52 /*
53 { 9, 9, (uint8_t const *) "\x00\x00\x00\x00\xf0\xe1\x40\x00\x00\x00\x00" },
54 { 9, 9, (uint8_t const *) "\x1c\x30\x60\x80\x00\x01\x00\x00\x00\x00\x00" },
55 { 9, 9, (uint8_t const *) "\x00\x00\x00\x04\x0e\x1f\x00\x00\x00\x00\x00" },
56 { 9, 9, (uint8_t const *) "\x00\x00\x00\x00\x00\x01\x02\x0c\x18\x70\x00" }
57 */
58 };
59
60 static void enemy_animation_advance(jumpnrun_enemy *enemy) {
61 ++enemy->base.tick_minor;
62 if(enemy->base.tick_minor == enemy->type->animation_ticks_per_frame) {
63 enemy->base.tick_minor = 0;
64
65 ++enemy->base.anim_frame;
66 if(enemy->base.anim_frame >= enemy->type->animation_length) {
67 enemy->base.anim_frame = 0;
68 }
69 }
70 }
71
72 void jumpnrun_process_enemy(jumpnrun_enemy *self,
73 badge_framebuffer *fb,
74 struct jumpnrun_game_state *state,
75 struct jumpnrun_level *lv,
76 struct jumpnrun_tile_range const *visible_tiles,
77 vec2d *player_inertia_mod) {
78 int const spawn_margin = 1 + self->type->animation_frames[self->base.anim_frame].width;
79
80 if(self->flags & JUMPNRUN_ENEMY_SPAWNED) {
81 if(fixed_point_lt(rectangle_left(enemy_box(self)), FIXED_POINT(state->left - spawn_margin, 0)) ||
82 fixed_point_gt(rectangle_left(enemy_box(self)), FIXED_POINT(state->left + BADGE_DISPLAY_WIDTH + spawn_margin, 0)) ||
83 fixed_point_gt(rectangle_top (enemy_box(self)), FIXED_POINT(BADGE_DISPLAY_HEIGHT , 0))) {
84 self->flags &= ~JUMPNRUN_ENEMY_SPAWNED;
85 } else {
86 self->type->game_tick(self, state, lv, visible_tiles, player_inertia_mod);
87
88 if(fb) {
89 badge_framebuffer_blt(fb,
90 fixed_point_cast_int(rectangle_left(enemy_box(self))) - state->left,
91 fixed_point_cast_int(rectangle_top (enemy_box(self))),
92 enemy_sprite(self),
93 enemy_render_flags(self));
94 }
95 }
96 } else if(self->flags & JUMPNRUN_ENEMY_UNAVAILABLE) {
97 if(state->left > fixed_point_cast_int(self->spawn_pos.x) + spawn_margin ||
98 state->left + BADGE_DISPLAY_WIDTH + spawn_margin < fixed_point_cast_int(self->spawn_pos.x)) {
99 self->flags &= ~JUMPNRUN_ENEMY_UNAVAILABLE;
100 }
101 } else if((fixed_point_gt(self->spawn_pos.x, FIXED_POINT(state->left - spawn_margin, 0)) &&
102 fixed_point_lt(self->spawn_pos.x, FIXED_POINT(state->left - spawn_margin / 2, 0))) ||
103 (fixed_point_lt(self->spawn_pos.x, FIXED_POINT(state->left + BADGE_DISPLAY_WIDTH + spawn_margin, 0)) &&
104 fixed_point_gt(self->spawn_pos.x, FIXED_POINT(state->left + BADGE_DISPLAY_WIDTH, 0)))) {
105 // enemy unspawned, available and in spawn zone.
106 self->flags |= JUMPNRUN_ENEMY_SPAWNED | JUMPNRUN_ENEMY_UNAVAILABLE;
107 self->base.current_box = rectangle_new(self->spawn_pos, self->type->extent);
108 self->base.inertia = self->type->spawn_inertia;
109 self->base.anim_frame = 0;
110 self->base.tick_minor = 0;
111 self->base.touching_ground = false;
112 self->base.jumpable_frames = 0;
113 }
114 }
115
116 void enemy_collision_tiles_bounce_horiz(jumpnrun_enemy *self,
117 vec2d *desired_position,
118 jumpnrun_level *lv,
119 jumpnrun_tile_range const *visible_tiles) {
120 vec2d inertia_mod = self->base.inertia;
121
122 collisions_tiles_displace(desired_position,
123 &self->base,
124 lv,
125 visible_tiles,
126 &inertia_mod);
127
128 if(fixed_point_ne(inertia_mod.x, self->base.inertia.x)) {
129 self->base.inertia.x = fixed_point_neg(self->base.inertia.x);
130 }
131 }
132
133 void enemy_collision_player_jumpable(jumpnrun_enemy *self,
134 jumpnrun_game_state *state,
135 vec2d *player_inertia_mod)
136 {
137 rectangle rect_self = enemy_hitbox(self);
138
139 if(rectangle_intersect(&rect_self, &state->player.current_box)) {
140 if(fixed_point_gt(state->player.inertia.y, FIXED_POINT(0, 0))) {
141 self->flags &= ~JUMPNRUN_ENEMY_SPAWNED;
142 player_inertia_mod->y = FIXED_POINT(0, -250);
143 state->player.jumpable_frames = 12;
144 } else {
145 state->status = JUMPNRUN_DEAD;
146 }
147 }
148 }
149
150 void enemy_tick_straight_ahead(jumpnrun_enemy *self,
151 jumpnrun_game_state *state,
152 jumpnrun_level *lv,
153 jumpnrun_tile_range const *visible_tiles,
154 vec2d *player_inertia_mod) {
155 int screenpos = fixed_point_cast_int(rectangle_left(&self->base.current_box));
156
157 if(screenpos + JUMPNRUN_MAX_SPAWN_MARGIN < state->left ||
158 screenpos >= state->left + BADGE_DISPLAY_WIDTH + JUMPNRUN_MAX_SPAWN_MARGIN) {
159 return;
160 }
161
162 jumpnrun_passive_movement(&self->base.inertia);
163
164 vec2d new_pos = vec2d_add(enemy_position(self), self->base.inertia);
165 self->type->collision_tiles(self, &new_pos, lv, visible_tiles);
166 self->type->collision_player(self, state, player_inertia_mod);
167 rectangle_move_to(&self->base.current_box, new_pos);
168
169 enemy_animation_advance(self);
170 }
171
172 void enemy_collision_tiles_pass_through(struct jumpnrun_enemy *self,
173 vec2d *desired_position,
174 struct jumpnrun_level *lv,
175 struct jumpnrun_tile_range const *visible_tiles) {
176 (void) self;
177 (void) desired_position;
178 (void) lv;
179 (void) visible_tiles;
180 return;
181 }
182
183 void enemy_collision_player_deadly(struct jumpnrun_enemy *self,
184 struct jumpnrun_game_state *state,
185 vec2d *player_inertia_mod) {
186 (void) player_inertia_mod;
187
188 rectangle rect_self = enemy_hitbox(self);
189
190 if(rectangle_intersect(&rect_self, &state->player.current_box)) {
191 state->status = JUMPNRUN_DEAD;
192 }
193 }
194
195 void enemy_tick_swing_up_and_down(struct jumpnrun_enemy *self,
196 struct jumpnrun_game_state *state,
197 struct jumpnrun_level *lv,
198 struct jumpnrun_tile_range const *visible_tiles,
199 vec2d *player_inertia_mod) {
200 int screenpos = fixed_point_cast_int(rectangle_left(&self->base.current_box));
201
202 if(screenpos + JUMPNRUN_MAX_SPAWN_MARGIN < state->left ||
203 screenpos >= state->left + BADGE_DISPLAY_WIDTH + JUMPNRUN_MAX_SPAWN_MARGIN) {
204 return;
205 }
206
207 vec2d new_pos = vec2d_add(enemy_position(self), self->base.inertia);
208 self->type->collision_tiles(self, &new_pos, lv, visible_tiles);
209 self->type->collision_player(self, state, player_inertia_mod);
210 rectangle_move_to(&self->base.current_box, new_pos);
211
212 self->base.inertia.y =
213 fixed_point_add(fixed_point_add(self->base.inertia.y,
214 fixed_point_div(self->type->spawn_inertia.y, FIXED_INT(3))),
215 fixed_point_mul(FIXED_POINT(0, 5),
216 fixed_point_sub(self->spawn_pos.y,
217 enemy_position(self).y)));
218
219 enemy_animation_advance(self);
220 }
221
222 void enemy_tick_stationary(struct jumpnrun_enemy *self,
223 struct jumpnrun_game_state *state,
224 struct jumpnrun_level *lv,
225 struct jumpnrun_tile_range const *visible_tiles,
226 vec2d *player_inertia_mod) {
227 int screenpos = fixed_point_cast_int(rectangle_left(&self->base.current_box));
228
229 if(screenpos + JUMPNRUN_MAX_SPAWN_MARGIN < state->left ||
230 screenpos >= state->left + BADGE_DISPLAY_WIDTH + JUMPNRUN_MAX_SPAWN_MARGIN) {
231 return;
232 }
233
234 self->type->collision_tiles(self, &self->base.current_box.pos, lv, visible_tiles);
235 self->type->collision_player(self, state, player_inertia_mod);
236
237 enemy_animation_advance(self);
238 }
239
240
241 jumpnrun_enemy_type const jumpnrun_enemy_type_data[JUMPNRUN_ENEMY_TYPE_COUNT] = {
242 {
243 .animation_ticks_per_frame = 16,
244 .animation_length = ARRAY_SIZE(anim_cat),
245 .animation_frames = anim_cat,
246 .extent = { FIXED_INT_I(8), FIXED_INT_I(5) },
247 .hitbox = { { FIXED_INT_I(1), FIXED_INT_I(2) },
248 { FIXED_INT_I(6), FIXED_INT_I(3) } },
249 .spawn_inertia = { FIXED_POINT_I(0, -100), FIXED_INT_I(0) },
250 .collision_tiles = enemy_collision_tiles_bounce_horiz,
251 .collision_player = enemy_collision_player_jumpable,
252 .game_tick = enemy_tick_straight_ahead
253 }, {
254 .animation_ticks_per_frame = 12,
255 .animation_length = ARRAY_SIZE(anim_mushroom),
256 .animation_frames = anim_mushroom,
257 .extent = { FIXED_INT_I(7), FIXED_INT_I(7) },
258 .hitbox = { { FIXED_INT_I(1), FIXED_INT_I(1) },
259 { FIXED_INT_I(5), FIXED_INT_I(4) } },
260 .spawn_inertia = { FIXED_POINT_I(0, -50), FIXED_INT_I(0) },
261 .collision_tiles = enemy_collision_tiles_bounce_horiz,
262 .collision_player = enemy_collision_player_jumpable,
263 .game_tick = enemy_tick_straight_ahead
264 }, {
265 .animation_ticks_per_frame = 9,
266 .animation_length = ARRAY_SIZE(anim_kaninchen),
267 .animation_frames = anim_kaninchen,
268 .extent = { FIXED_INT_I(7), FIXED_INT_I(5) },
269 .hitbox = { { FIXED_INT_I(1), FIXED_INT_I(2) },
270 { FIXED_INT_I(5), FIXED_INT_I(3) } },
271 .spawn_inertia = { FIXED_POINT_I(0, -80), FIXED_POINT_I(0, 0) },
272 .collision_tiles = enemy_collision_tiles_bounce_horiz,
273 .collision_player = enemy_collision_player_jumpable,
274 .game_tick = enemy_tick_straight_ahead
275 }, {
276 .animation_ticks_per_frame = 6,
277 .animation_length = ARRAY_SIZE(anim_snake),
278 .animation_frames = anim_snake,
279 .extent = { FIXED_INT_I(10), FIXED_INT_I(6) },
280 .hitbox = { { FIXED_INT_I(1), FIXED_INT_I(4) },
281 { FIXED_INT_I(8), FIXED_INT_I(2) } },
282 .spawn_inertia = { FIXED_POINT_I(0, -150), FIXED_INT_I(0) },
283 .collision_tiles = enemy_collision_tiles_bounce_horiz,
284 .collision_player = enemy_collision_player_jumpable,
285 .game_tick = enemy_tick_straight_ahead
286 }, {
287 .animation_ticks_per_frame = 6,
288 .animation_length = ARRAY_SIZE(anim_spiral),
289 .animation_frames = anim_spiral,
290 .extent = { FIXED_INT_I(10), FIXED_INT_I(10) },
291 .hitbox = { { FIXED_INT_I(1), FIXED_INT_I(1) },
292 { FIXED_INT_I(8), FIXED_INT_I(8) } },
293 .spawn_inertia = { FIXED_INT_I(0), FIXED_POINT_I(0, -200) },
294 .collision_tiles = enemy_collision_tiles_pass_through,
295 .collision_player = enemy_collision_player_deadly,
296 .game_tick = enemy_tick_swing_up_and_down
297 }, {
298 .animation_ticks_per_frame = 3,
299 .animation_length = ARRAY_SIZE(anim_rotor),
300 .animation_frames = anim_rotor,
301 .extent = { FIXED_INT_I(9), FIXED_INT_I(9) },
302 .hitbox = { { FIXED_INT_I(1), FIXED_INT_I(1) },
303 { FIXED_INT_I(7), FIXED_INT_I(7) } },
304 .spawn_inertia = { FIXED_INT_I(0), FIXED_POINT_I(0, 0) },
305 .collision_tiles = enemy_collision_tiles_pass_through,
306 .collision_player = enemy_collision_player_deadly,
307 .game_tick = enemy_tick_stationary
308 }
309 };
This page took 0.074314 seconds and 5 git commands to generate.