7 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof*(arr))
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" }
14 void jumpnrun_process_enemy(jumpnrun_enemy
*self
,
15 badge_framebuffer
*fb
,
16 struct jumpnrun_game_state
*state
,
17 struct jumpnrun_level
*lv
,
18 struct jumpnrun_tile_range
const *visible_tiles
) {
19 int const spawn_margin
= 1 + self
->type
->animation_frames
[self
->current_frame
].width
;
21 if(self
->flags
& JUMPNRUN_ENEMY_SPAWNED
) {
22 if(fixed_point_lt(self
->current_pos
.x
, FIXED_POINT(state
->left
- spawn_margin
, 0)) ||
23 fixed_point_gt(self
->current_pos
.x
, FIXED_POINT(state
->left
+ BADGE_DISPLAY_WIDTH
+ spawn_margin
, 0)) ||
24 fixed_point_cast_int(self
->current_pos
.y
) > BADGE_DISPLAY_HEIGHT
) {
25 self
->flags
&= ~JUMPNRUN_ENEMY_SPAWNED
;
27 self
->type
->game_tick(self
, state
, lv
, visible_tiles
);
28 badge_framebuffer_blt(fb
,
29 fixed_point_cast_int(self
->current_pos
.x
) - state
->left
,
30 fixed_point_cast_int(self
->current_pos
.y
),
31 &self
->type
->animation_frames
[self
->current_frame
],
32 fixed_point_lt(self
->inertia
.x
, FIXED_POINT(0, 0)) ? 0 : BADGE_BLT_MIRRORED
);
34 } else if(self
->flags
& JUMPNRUN_ENEMY_UNAVAILABLE
) {
35 if(state
->left
> fixed_point_cast_int(self
->spawn_pos
.x
) + spawn_margin
||
36 state
->left
+ BADGE_DISPLAY_WIDTH
+ spawn_margin
< fixed_point_cast_int(self
->spawn_pos
.x
)) {
37 self
->flags
&= ~JUMPNRUN_ENEMY_UNAVAILABLE
;
39 } else if((fixed_point_gt(self
->spawn_pos
.x
, FIXED_POINT(state
->left
- spawn_margin
, 0)) &&
40 fixed_point_lt(self
->spawn_pos
.x
, FIXED_POINT(state
->left
- spawn_margin
/ 2, 0))) ||
41 (fixed_point_lt(self
->spawn_pos
.x
, FIXED_POINT(state
->left
+ BADGE_DISPLAY_WIDTH
+ spawn_margin
, 0)) &&
42 fixed_point_gt(self
->spawn_pos
.x
, FIXED_POINT(state
->left
+ BADGE_DISPLAY_WIDTH
, 0)))) {
43 // enemy unspawned, available and in spawn zone.
44 self
->flags
|= JUMPNRUN_ENEMY_SPAWNED
| JUMPNRUN_ENEMY_UNAVAILABLE
;
45 self
->current_pos
= self
->spawn_pos
;
46 self
->inertia
= self
->type
->spawn_inertia
;
47 self
->current_frame
= 0;
48 self
->tick_counter
= 0;
52 void enemy_collision_tiles_bounce_horiz(jumpnrun_enemy
*self
,
53 vec2d
*desired_position
,
55 jumpnrun_tile_range
const *visible_tiles
) {
56 rectangle rect_self
= rect_from_enemy(self
);
57 vec2d inertia_copy
= self
->inertia
;
58 bool touching_ground
= false;
60 collisions_tiles_displace(desired_position
,
67 if(fixed_point_ne(inertia_copy
.x
, self
->inertia
.x
)) {
68 self
->inertia
.x
= fixed_point_neg(self
->inertia
.x
);
72 void enemy_collision_player_kill(jumpnrun_enemy
*self
,
73 jumpnrun_game_state
*state
)
75 rectangle rect_self
= rect_from_enemy(self
);
76 rectangle rect_hacker
= hacker_rect_current(state
);
78 if(rectangle_intersect(&rect_self
, &rect_hacker
)) {
79 state
->status
= JUMPNRUN_DEAD
;
83 void enemy_tick_cat(jumpnrun_enemy
*self
,
84 jumpnrun_game_state
*state
,
86 jumpnrun_tile_range
const *visible_tiles
) {
87 int screenpos
= fixed_point_cast_int(self
->current_pos
.x
);
89 if(screenpos
+ JUMPNRUN_MAX_SPAWN_MARGIN
< state
->left
||
90 screenpos
>= state
->left
+ BADGE_DISPLAY_WIDTH
+ JUMPNRUN_MAX_SPAWN_MARGIN
) {
94 jumpnrun_passive_movement(&self
->inertia
);
96 vec2d new_pos
= vec2d_add(self
->current_pos
, self
->inertia
);
97 self
->type
->collision_tiles(self
, &new_pos
, lv
, visible_tiles
);
98 self
->type
->collision_player(self
, state
);
99 self
->current_pos
= new_pos
;
101 self
->tick_counter
= (self
->tick_counter
+ 1) % self
->type
->animation_ticks_per_frame
;
102 if(self
->tick_counter
== 0) {
103 self
->current_frame
= (self
->current_frame
+ 1) % self
->type
->animation_length
;
107 jumpnrun_enemy_type
const jumpnrun_enemy_type_data
[JUMPNRUN_ENEMY_TYPE_COUNT
] = {
108 { 2, ARRAY_SIZE(anim_cat
), anim_cat
,
109 { FIXED_POINT_I(0, -800), FIXED_POINT_I(0, 0) },
110 enemy_collision_tiles_bounce_horiz
,
111 enemy_collision_player_kill
,