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 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" }
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
;
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
;
36 self
->type
->game_tick(self
, state
, lv
, visible_tiles
);
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
);
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
;
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;
64 void enemy_collision_tiles_bounce_horiz(jumpnrun_enemy
*self
,
65 vec2d
*desired_position
,
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;
72 collisions_tiles_displace(desired_position
,
79 if(fixed_point_ne(inertia_copy
.x
, self
->inertia
.x
)) {
80 self
->inertia
.x
= fixed_point_neg(self
->inertia
.x
);
84 void enemy_collision_player_jumpable(jumpnrun_enemy
*self
,
85 jumpnrun_game_state
*state
)
87 rectangle rect_self
= rect_from_enemy(self
);
88 rectangle rect_hacker
= hacker_rect_current(state
);
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, -250);
94 state
->jumpable_frames
= 8;
96 state
->status
= JUMPNRUN_DEAD
;
101 void enemy_tick_cat(jumpnrun_enemy
*self
,
102 jumpnrun_game_state
*state
,
104 jumpnrun_tile_range
const *visible_tiles
) {
105 int screenpos
= fixed_point_cast_int(self
->current_pos
.x
);
107 if(screenpos
+ JUMPNRUN_MAX_SPAWN_MARGIN
< state
->left
||
108 screenpos
>= state
->left
+ BADGE_DISPLAY_WIDTH
+ JUMPNRUN_MAX_SPAWN_MARGIN
) {
112 jumpnrun_passive_movement(&self
->inertia
);
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
;
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
;
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
,
132 16, 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
,