aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorquou <quou@disroot.org>2024-10-08 19:56:08 +1100
committerquou <quou@disroot.org>2024-10-08 19:56:08 +1100
commit9add408984464bd6b3cc018bb14c3d69ad0a2898 (patch)
treedde2af5525fd076d03c5c8e14067a4502aa1051e
parentb5c69695c9c97c09f7ffa4d5a600d88cc06ee6da (diff)
New flying enemy that drops arrows
-rw-r--r--Makefile4
-rw-r--r--config.h2
-rw-r--r--enemy.c74
-rw-r--r--intermediate/arms.bmpbin41538 -> 41538 bytes
-rw-r--r--intermediate/arrow.anm2
-rw-r--r--intermediate/fly_left.anm11
-rw-r--r--intermediate/fly_right.anm11
-rw-r--r--intermediate/npc.bmpbin37002 -> 49290 bytes
-rw-r--r--map.c34
-rw-r--r--obj.h24
-rw-r--r--player.c13
-rw-r--r--projectile.c59
-rw-r--r--world.c20
-rw-r--r--world.h13
14 files changed, 263 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index 61b0cf4..d91d34e 100644
--- a/Makefile
+++ b/Makefile
@@ -58,6 +58,7 @@ sources = \
physics.c \
plat.c \
player.c \
+ projectile.c \
random.c \
rect.c \
render.c \
@@ -73,6 +74,7 @@ image_sources = \
$(int_dir)/rooms.bmp \
anim_sources = \
+ $(int_dir)/arrow.anm \
$(int_dir)/demon_fly_left.anm \
$(int_dir)/demon_fly_right.anm \
$(int_dir)/demon_idle_left.anm \
@@ -83,6 +85,8 @@ anim_sources = \
$(int_dir)/demon_walk_right.anm \
$(int_dir)/fade_in.anm \
$(int_dir)/fade_out.anm \
+ $(int_dir)/fly_left.anm \
+ $(int_dir)/fly_right.anm \
$(int_dir)/guy_fall_left.anm \
$(int_dir)/guy_fall_right.anm \
$(int_dir)/guy_idle_left.anm \
diff --git a/config.h b/config.h
index 906f097..5a0ccb9 100644
--- a/config.h
+++ b/config.h
@@ -53,5 +53,7 @@
#define enemy_touch_damage 1
#define enemy_knockback (4 << fbits)
#define enemy_hurt_freeze 1
+#define enemy_arrow_cooldown 60
+#define enemy_arrow_damage 2
#endif
diff --git a/enemy.c b/enemy.c
index 5901445..467b45c 100644
--- a/enemy.c
+++ b/enemy.c
@@ -18,6 +18,8 @@ int get_enemy_hp(Enemy_Type t) {
switch (t) {
case enemy_demon:
return 3;
+ case enemy_fly:
+ return 2;
}
return 0;
}
@@ -30,6 +32,12 @@ void get_enemy_rect(Enemy_Type t, Rect* d) {
d->w = 12;
d->h = 14;
break;
+ case enemy_fly:
+ d->x = 2;
+ d->y = 6;
+ d->w = 11;
+ d->h = 7;
+ break;
}
}
@@ -45,6 +53,7 @@ void init_enemy(Enemy* e, Enemy_Type t, int x, int y) {
e->face = face_left;
e->state = enemy_state_patrol;
e->inv = 0;
+ e->timer = 0;
}
void update_enemy_anim(Enemy* e) {
@@ -214,11 +223,75 @@ void update_demon_move(Enemy* e, World* w) {
}
}
+void update_fly_move(Enemy* e, World* w) {
+ (void)e;
+ (void)w;
+ if (e->state == enemy_state_patrol) {
+ const Map* m = &w->map;
+ const Player* p = &w->player;
+ int d2g = 0, d2c = 0, y;
+ int tx = (e->x >> fbits) / map_tile_size;
+ int ty = (e->y >> fbits) / map_tile_size;
+ for (y = ty; y < map_h; y++, d2g++)
+ if (m->collision[tx + y * map_w])
+ break;
+ for (y = ty; y >= 0; y--, d2c++)
+ if (m->collision[tx + y * map_w])
+ break;
+ ty =
+ ((e->y >> fbits) + (map_tile_size >> 1)) /
+ map_tile_size;
+ if (e->face == face_left) {
+ tx = (
+ (e->x >> fbits) - (map_tile_size >> 1)) /
+ map_tile_size;
+ } else {
+ tx = (
+ (e->x >> fbits) + map_tile_size +
+ (map_tile_size >> 1)) /
+ map_tile_size;
+ }
+ if (tile_at(m, tx, ty))
+ e->face = !e->face;
+ if (d2g < 3 && d2c > 2)
+ e->vy -= 3 * (f1 / (d2g + 1));
+ e->vx = e->face == face_right? f1: -f1;
+ if (!e->grounded)
+ e->vx = (e->vx << fbits) / f1;
+ if (
+ e->timer > enemy_arrow_cooldown &&
+ p->y > e->y &&
+ absolute((e->x + f1 * 8) - (p->x + f1 * 8)) < f1 * 8
+ ) {
+ Rect r;
+ r.x = 0;
+ r.y = 0;
+ r.w = 3;
+ r.h = 12;
+ e->timer = 0;
+ inst_projectile(
+ w,
+ e->x + f1 * 8,
+ e->y,
+ &r,
+ asset_id_arrow_anm
+ );
+ }
+ }
+ e->anim =
+ e->face == face_left?
+ asset_id_fly_left_anm:
+ asset_id_fly_right_anm;
+}
+
void update_enemy_move(Enemy* e, World* w) {
switch (e->t) {
case enemy_demon:
update_demon_move(e, w);
break;
+ case enemy_fly:
+ update_fly_move(e, w);
+ break;
}
}
@@ -227,6 +300,7 @@ int update_enemy(Enemy* e, World* w) {
update_enemy_hurt(e, w);
update_enemy_move(e, w);
update_enemy_phys(e, &w->map);
+ e->timer++;
return e->hp <= 0;
}
diff --git a/intermediate/arms.bmp b/intermediate/arms.bmp
index 4a0664f..299bd16 100644
--- a/intermediate/arms.bmp
+++ b/intermediate/arms.bmp
Binary files differ
diff --git a/intermediate/arrow.anm b/intermediate/arrow.anm
new file mode 100644
index 0000000..52447af
--- /dev/null
+++ b/intermediate/arrow.anm
@@ -0,0 +1,2 @@
+1
+{ 222, 34, 3, 12 }
diff --git a/intermediate/fly_left.anm b/intermediate/fly_left.anm
new file mode 100644
index 0000000..9fc3735
--- /dev/null
+++ b/intermediate/fly_left.anm
@@ -0,0 +1,11 @@
+1
+{ 0, 112, 16, 16 }
+{ 16, 112, 16, 16 }
+{ 32, 112, 16, 16 }
+{ 48, 112, 16, 16 }
+{ 64, 112, 16, 16 }
+{ 80, 112, 16, 16 }
+{ 64, 112, 16, 16 }
+{ 48, 112, 16, 16 }
+{ 32, 112, 16, 16 }
+{ 16, 112, 16, 16 }
diff --git a/intermediate/fly_right.anm b/intermediate/fly_right.anm
new file mode 100644
index 0000000..ae4ef6c
--- /dev/null
+++ b/intermediate/fly_right.anm
@@ -0,0 +1,11 @@
+1
+{ 0, 96, 16, 16 }
+{ 16, 96, 16, 16 }
+{ 32, 96, 16, 16 }
+{ 48, 96, 16, 16 }
+{ 64, 96, 16, 16 }
+{ 80, 96, 16, 16 }
+{ 64, 96, 16, 16 }
+{ 48, 96, 16, 16 }
+{ 32, 96, 16, 16 }
+{ 16, 96, 16, 16 }
diff --git a/intermediate/npc.bmp b/intermediate/npc.bmp
index 9a961a7..ebcd40a 100644
--- a/intermediate/npc.bmp
+++ b/intermediate/npc.bmp
Binary files differ
diff --git a/map.c b/map.c
index 2acd988..5c0cf78 100644
--- a/map.c
+++ b/map.c
@@ -152,6 +152,7 @@ void generate_enemies(const Map* m, World* w) {
(m->collision[x + y * map_w] == 1 && \
m->collision[x + (y - 1) * map_w] == 0)
int x, y, ex = map_w - 1, ey = map_h - 1;
+ /* enemies on platforms */
for (y = 1; y < ey; y++) {
for (x = 1; x < ex; x++) {
int plat = -1;
@@ -176,6 +177,39 @@ void generate_enemies(const Map* m, World* w) {
for (; check && x < ex; x++);
}
}
+ /* flying enemies */
+ for (y = 1; y < ey; y++)
+ for (x = 1; x < ex; x++) {
+ Rect rect = { 0 };
+ int i, j;
+ rect.x = x;
+ rect.y = y;
+ for (j = y; j < ey; j++) {
+ if (m->collision[i + j * map_w])
+ rect.h = 0;
+ for (i = x, rect.w = 0; i < ex && rect.h > 3; i++) {
+ if (!m->collision[i + j * map_w])
+ rect.w++;
+ if (rect.w > 4) {
+ Enemy* e;
+ e = inst_enemy(
+ w,
+ enemy_fly,
+ ((x + (rect.w >> 1)) * map_tile_size) << fbits,
+ ((y + (rect.h >> 1)) * map_tile_size) << fbits
+ );
+ e->face = get_r() & 1;
+ x = i;
+ y = j;
+ rect.w = 0;
+ rect.h = 0;
+ goto found;
+ }
+ }
+ rect.h++;
+ }
+ found:;
+ }
}
void generate_floor(Map* m, World* w) {
diff --git a/obj.h b/obj.h
index 98f2ebf..2227a64 100644
--- a/obj.h
+++ b/obj.h
@@ -79,7 +79,8 @@ int update_effect(Effect* e);
void ren_effect(const Effect* e, struct Renderer* r);
typedef enum {
- enemy_demon
+ enemy_demon,
+ enemy_fly
} Enemy_Type;
typedef struct {
@@ -87,7 +88,7 @@ typedef struct {
int x, y, vx, vy;
int hp, frame, anim;
int grounded, headbutted, on_ramp;
- int state, inv;
+ int state, inv, timer;
Face face;
Rect rect;
} Enemy;
@@ -116,4 +117,23 @@ int update_deathzone(Deathzone* d);
void ren_hud(const struct World* w, struct Renderer* r);
+typedef struct {
+ Rect r, s;
+ int anim, frame;
+ int x, y, vx, vy;
+} Projectile;
+
+void init_projectile(
+ Projectile* p,
+ int x,
+ int y,
+ const Rect* r,
+ int anim
+);
+int update_projectile(
+ Projectile* p,
+ const struct World* w
+);
+void ren_projectile(const Projectile* p, struct Renderer* r);
+
#endif
diff --git a/player.c b/player.c
index 4a83a91..40ab92b 100644
--- a/player.c
+++ b/player.c
@@ -201,6 +201,19 @@ void update_player_hurt(Player* p, World* w) {
goto took_damage;
}
}
+ for (i = 0; i < w->projectile_count; i++) {
+ const Projectile* pr = &w->projectiles[i];
+ Rect r2;
+ r2.x = pr->x >> fbits;
+ r2.y = pr->y >> fbits;
+ r2.w = pr->r.w;
+ r2.h = pr->r.h;
+ if (rects_overlap(&r, &r2)) {
+ p->hp -= enemy_arrow_damage;
+ inst_effect(w, cx, cy, 0, 0, 32);
+ goto took_damage;
+ }
+ }
return;
took_damage:
p->inv = player_inv_frames;
diff --git a/projectile.c b/projectile.c
new file mode 100644
index 0000000..ce68e8f
--- /dev/null
+++ b/projectile.c
@@ -0,0 +1,59 @@
+#include "animation.h"
+#include "asset.h"
+#include "maths.h"
+#include "obj.h"
+#include "physics.h"
+#include "render.h"
+#include "world.h"
+
+void init_projectile(
+ Projectile* p,
+ int x,
+ int y,
+ const Rect* r,
+ int anim
+) {
+ p->r = *r;
+ p->frame = 0;
+ p->anim = anim;
+ p->x = x;
+ p->y = y;
+ p->vx = 0;
+ p->vy = 0;
+ p->s.x = 0;
+ p->s.y = 0;
+ p->s.w = 0;
+ p->s.h = 0;
+}
+
+int update_projectile(
+ Projectile* p,
+ const World* w
+) {
+ Rect r = p->r;
+ int grounded = 1, headbutted = 1, on_ramp = 0;
+ const Animation* a = get_animation(p->anim);
+ r.x <<= fbits;
+ r.y <<= fbits;
+ r.w <<= fbits;
+ r.h <<= fbits;
+ update_body(
+ &w->map,
+ &p->x,
+ &p->y,
+ &p->vx,
+ &p->vy,
+ &grounded,
+ &headbutted,
+ &on_ramp,
+ &r
+ );
+ update_anim(a, &p->frame, &p->s);
+ return !grounded;
+}
+
+void ren_projectile(const Projectile* p, Renderer* r) {
+ const Bitmap* bm = get_bitmap(asset_id_arms_img);
+ ren_map(r, p->x >> fbits, p->y >> fbits, &p->s, bm);
+}
+
diff --git a/world.c b/world.c
index 52e2c5a..8d34b21 100644
--- a/world.c
+++ b/world.c
@@ -6,6 +6,7 @@ void init_world(World* w) {
w->enemy_count = 0;
w->deathzone_count = 0;
w->effect_count = 0;
+ w->projectile_count = 0;
w->frame = 0;
w->freeze = 0;
init_player(&w->player);
@@ -70,6 +71,20 @@ Effect* inst_effect(
return e;
}
+Projectile* inst_projectile(
+ World* w,
+ int x,
+ int y,
+ const Rect* r,
+ int anim
+) {
+ Projectile* p;
+ assert(w->projectile_count < max_projectiles);
+ p = &w->projectiles[w->projectile_count++];
+ init_projectile(p, x, y, r, anim);
+ return p;
+}
+
void update_world(World* w, const App* a) {
int i;
if (w->laser.life)
@@ -91,6 +106,9 @@ void update_world(World* w, const App* a) {
for (i = w->enemy_count - 1; i >= 0; i--)
if (update_enemy(&w->enemies[i], w))
w->enemies[i] = w->enemies[--w->enemy_count];
+ for (i = w->projectile_count - 1; i >= 0; i--)
+ if (update_projectile(&w->projectiles[i], w))
+ w->projectiles[i] = w->projectiles[--w->projectile_count];
w->frame++;
}
@@ -104,6 +122,8 @@ void ren_world(const World* w, struct Renderer* r) {
ren_effect(&w->effects[i], r);
for (i = 0; i < w->enemy_count; i++)
ren_enemy(&w->enemies[i], r);
+ for (i = 0; i < w->projectile_count; i++)
+ ren_projectile(&w->projectiles[i], r);
if (w->laser.life)
ren_laser(&w->laser, r);
ren_hud(w, r);
diff --git a/world.h b/world.h
index 81feb6f..a0f6506 100644
--- a/world.h
+++ b/world.h
@@ -4,10 +4,11 @@
#include "map.h"
#include "obj.h"
-#define max_particles 32
+#define max_particles 16
#define max_enemies 16
#define max_deathzones 16
#define max_effects 16
+#define max_projectiles 16
struct Renderer;
@@ -16,8 +17,9 @@ typedef struct World {
Enemy enemies[max_enemies];
Deathzone deathzones[max_deathzones];
Effect effects[max_effects];
+ Projectile projectiles[max_projectiles];
int particle_count, enemy_count, effect_count;
- int deathzone_count;
+ int deathzone_count, projectile_count;
Player player;
Laser laser;
Map map;
@@ -55,6 +57,13 @@ Effect* inst_effect(
int vy,
int c
);
+Projectile* inst_projectile(
+ World* w,
+ int x,
+ int y,
+ const Rect* r,
+ int anim
+);
void update_world(World* w, const struct App* a);
void ren_world(const World* w, struct Renderer* r);