aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--game.c110
-rw-r--r--game.h12
-rw-r--r--intermediate/map.bmpbin41098 -> 41098 bytes
-rw-r--r--intermediate/rooms.bmpbin2538 -> 20538 bytes
-rw-r--r--map.c161
-rw-r--r--map.h9
-rw-r--r--random.c4
-rw-r--r--random.h1
-rw-r--r--str.c88
-rw-r--r--str.h14
-rw-r--r--world.c5
-rw-r--r--world.h2
13 files changed, 357 insertions, 50 deletions
diff --git a/Makefile b/Makefile
index d91d34e..b77608e 100644
--- a/Makefile
+++ b/Makefile
@@ -62,6 +62,7 @@ sources = \
random.c \
rect.c \
render.c \
+ str.c \
world.c \
image_sources = \
diff --git a/game.c b/game.c
index 2a4731d..d9cb85c 100644
--- a/game.c
+++ b/game.c
@@ -3,6 +3,7 @@
#include "game.h"
#include "plat.h"
#include "render.h"
+#include "str.h"
const Rect logo_rect = { 47, 0, 54, 16 };
@@ -11,6 +12,8 @@ void init_game(Game* g, Game_State s) {
g->st = s;
g->frame = 0;
g->want_next = 0;
+ g->kills = 0;
+ g->cfloor = 0;
init_world(w);
}
@@ -19,9 +22,13 @@ void update_menu(Game* g, App* a) {
for (i = 0; i < btn_count; i++)
if (a->btn_states[i] & btn_state_pressed) {
queue_gs(g, game_state_fade_out);
- queue_gs(g, game_state_generate);
+ queue_gs(g, game_state_reset);
+ queue_gs(g, game_state_compute_ec);
+ queue_gs(g, game_state_reset);
+ queue_gs(g, game_state_restart);
+ queue_gs(g, game_state_generate_intro);
queue_gs(g, game_state_fade_in);
- queue_gs(g, game_state_play);
+ queue_gs(g, game_state_intro);
g->want_next = 1;
return;
}
@@ -33,9 +40,12 @@ void update_gameover(Game* g, App* a) {
if (a->btn_states[i] & btn_state_pressed) {
queue_gs(g, game_state_fade_out);
queue_gs(g, game_state_reset);
- queue_gs(g, game_state_generate);
+ queue_gs(g, game_state_compute_ec);
+ queue_gs(g, game_state_reset);
+ queue_gs(g, game_state_restart);
+ queue_gs(g, game_state_generate_intro);
queue_gs(g, game_state_fade_in);
- queue_gs(g, game_state_play);
+ queue_gs(g, game_state_intro);
g->want_next = 1;
return;
}
@@ -63,9 +73,18 @@ int detect_next(Game* g, const World* w) {
const Player* p = &w->player;
if (p->y < 0) /* next level */ {
queue_gs(g, game_state_fade_out);
- queue_gs(g, game_state_generate);
- queue_gs(g, game_state_fade_in);
- queue_gs(g, game_state_play);
+ queue_gs(g, game_state_next);
+ queue_gs(g, game_state_reset);
+ queue_gs(g, game_state_restore_player);
+ if (g->cfloor + 1 >= room_count()) {
+ queue_gs(g, game_state_generate_outro);
+ queue_gs(g, game_state_fade_in);
+ queue_gs(g, game_state_outro);
+ } else {
+ queue_gs(g, game_state_generate);
+ queue_gs(g, game_state_fade_in);
+ queue_gs(g, game_state_play);
+ }
g->want_next = 1;
return 1;
}
@@ -85,6 +104,30 @@ int detect_gameover(Game* g, const World* w) {
return 0;
}
+int detect_start(Game* g, const World* w) {
+ if (w->player.x < (30 << fbits)) {
+ queue_gs(g, game_state_fade_out);
+ queue_gs(g, game_state_reset);
+ queue_gs(g, game_state_generate);
+ queue_gs(g, game_state_fade_in);
+ queue_gs(g, game_state_play);
+ g->want_next = 1;
+ return 1;
+ }
+ return 0;
+}
+
+int compute_ec(World* w) {
+ int i, e = room_count();
+ int c = 0;
+ for (i = 0; i < e; i++) {
+ init_world(w);
+ generate_floor(&w->map, w, i);
+ c += w->enemy_count;
+ }
+ return c;
+}
+
void update_game(Game* g, App* a) {
const Animation* fa;
if (g->want_next) {
@@ -112,12 +155,30 @@ void update_game(Game* g, App* a) {
else
g->want_next = 1;
break;
+ case game_state_restart:
+ g->cfloor = 0;
+ g->kills = 0;
+ g->want_next = 1;
+ break;
case game_state_reset:
+ g->hp = g->w.player.hp;
+ g->ch = g->w.player.charge;
init_world(&g->w);
g->want_next = 1;
break;
+ case game_state_restore_player:
+ g->w.player.hp = g->hp;
+ g->w.player.charge = g->ch;
+ g->hp = -1;
+ g->want_next = 1;
+ break;
+ case game_state_next:
+ g->cfloor++;
+ g->kills += g->w.kills;
+ g->want_next = 1;
+ break;
case game_state_generate:
- generate_floor(&g->w.map, &g->w);
+ generate_floor(&g->w.map, &g->w, g->cfloor);
g->want_next = 1;
break;
case game_state_play:
@@ -125,6 +186,25 @@ void update_game(Game* g, App* a) {
if (detect_next(g, &g->w)) break;
detect_gameover(g, &g->w);
break;
+ case game_state_generate_intro:
+ generate_intro(&g->w.map, &g->w);
+ g->want_next = 1;
+ break;
+ case game_state_generate_outro:
+ generate_outro(&g->w.map, &g->w);
+ g->want_next = 1;
+ break;
+ case game_state_compute_ec:
+ g->me = compute_ec(&g->w);
+ g->want_next = 1;
+ break;
+ case game_state_intro:
+ update_world(&g->w, a);
+ detect_start(g, &g->w);
+ break;
+ case game_state_outro:
+ update_world(&g->w, a);
+ break;
}
g->frame++;
}
@@ -193,6 +273,20 @@ void ren_state(const Game* g, Game_State s, Renderer* r) {
break;
case game_state_generate:
break;
+ case game_state_outro: {
+ char buf[32];
+ int x = 228;
+ ren_text(r, 200, 100, "You win!");
+ ren_text(r, 200, 105, "Kills: ");
+ int_to_buf(g->kills, buf);
+ ren_text(r, x, 105, buf);
+ x += string_len(buf) * 4;
+ ren_text(r, x, 105, "/");
+ int_to_buf(g->me, buf);
+ ren_text(r, x + 4, 105, buf);
+ }
+ /* fall through */
+ case game_state_intro:
case game_state_play:
ren_world(&g->w, r);
break;
diff --git a/game.h b/game.h
index 43d9779..b39ef53 100644
--- a/game.h
+++ b/game.h
@@ -11,8 +11,16 @@ struct App;
typedef enum {
game_state_menu,
game_state_play,
+ game_state_intro,
+ game_state_outro,
+ game_state_compute_ec,
game_state_generate,
+ game_state_generate_intro,
+ game_state_generate_outro,
+ game_state_restart,
game_state_reset,
+ game_state_restore_player,
+ game_state_next,
game_state_fade_in,
game_state_fade_out,
game_state_over
@@ -23,8 +31,8 @@ typedef struct {
Game_State st, ps;
Game_State sq[game_max_state_queue];
Rect fr;
- int want_next;
- int qt, frame, ff;
+ int want_next, me, kills, cfloor;
+ int qt, frame, ff, hp, ch;
} Game;
void init_game(Game* g, Game_State s);
diff --git a/intermediate/map.bmp b/intermediate/map.bmp
index 588a13d..8389d9f 100644
--- a/intermediate/map.bmp
+++ b/intermediate/map.bmp
Binary files differ
diff --git a/intermediate/rooms.bmp b/intermediate/rooms.bmp
index a0bf456..60d021c 100644
--- a/intermediate/rooms.bmp
+++ b/intermediate/rooms.bmp
Binary files differ
diff --git a/map.c b/map.c
index 5c0cf78..b5680fa 100644
--- a/map.c
+++ b/map.c
@@ -14,18 +14,24 @@ Rect tile_rects[] = {
#undef x
};
-void generate_room(Map* m) {
+void generate_room(Map* m, int r) {
const Bitmap* b = get_bitmap(asset_id_rooms_img);
const unsigned* p = (const unsigned*)&b[1];
- const int max_rooms = b->h / map_h;
- const int r = get_r() % max_rooms;
+#ifdef force_room
+ r = force_room;
+#endif
int o = r * map_w * map_h;
int e = map_w * map_h, i;
for (i = 0; i < e; i++, o++) {
int bit = 1 << (o & 0x1f);
- if (p[o >> 5] & bit)
- m->tiles[i] = tile_brick;
- else
+ if (p[o >> 5] & bit) {
+ if ((get_r() & 127) == 0)
+ m->tiles[i] = tile_block1;
+ else if ((get_r() & 127) == 0)
+ m->tiles[i] = tile_stone;
+ else
+ m->tiles[i] = tile_brick;
+ } else
m->tiles[i] = null_tile;
}
}
@@ -146,6 +152,8 @@ void generate_doors(Map* m) {
#undef check
#undef place
+#undef place_a
+#undef place_o
void generate_enemies(const Map* m, World* w) {
#define check \
@@ -178,46 +186,41 @@ void generate_enemies(const Map* m, World* w) {
}
}
/* flying enemies */
- for (y = 1; y < ey; y++)
+ for (y = 1; y < ey; y++) {
+ int next_y = 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;
- }
+ int i = 0, j = 0;
+ int ei = x + 4, ej = y + 4;
+ int ok = 1;
+ for (j = y; j < ej; j++)
+ for (i = x; i < ei; i++) {
+ if (m->collision[i + j * map_w])
+ ok = 0;
}
- rect.h++;
+ if (ok) {
+ Enemy* e;
+ e = inst_enemy(
+ w,
+ enemy_fly,
+ ((x + 2) * map_tile_size) << fbits,
+ ((y + 2) * map_tile_size) << fbits
+ );
+ e->face = get_r() & 1;
+ x = i;
+ next_y = j;
}
- found:;
}
+ y = next_y;
+ }
}
-void generate_floor(Map* m, World* w) {
+void generate_floor(Map* m, World* w, int fi) {
Player* p = &w->player;
w->enemy_count = 0;
w->effect_count = 0;
w->deathzone_count = 0;
- generate_room(m);
+ set_ri(0);
+ generate_room(m, fi);
generate_ramps(m);
generate_doors(m);
generate_floors(m);
@@ -249,3 +252,89 @@ void render_map(const Map* m, Renderer* r) {
}
}
}
+
+#define place(t, c, x, y) { \
+ m->tiles[x + y * map_w] = t; \
+ m->collision[x + y * map_w] = c; \
+ }
+#define ncol(x, y) \
+ m->collision[x + y * map_w] = 0;
+
+void generate_intro(Map* m, struct World* w) {
+ int i, j, b = map_h - 1;
+ int e = map_w * map_h;
+ for (i = 0; i < e; i++) {
+ m->tiles[i] = null_tile;
+ m->collision[i] = 0;
+ }
+ for (i = 0; i < map_w; i++) {
+ int bot = b * map_w;
+ m->collision[i] = 1;
+ m->tiles[i + bot] = tile_stone;
+ m->collision[i + bot] = 1;
+ }
+ b = map_w - 1;
+ for (i = 0; i < map_h; i++)
+ m->collision[b + i * map_w] = 1;
+ for (i = 0; i < 15; i++)
+ place(tile_stone, 1, i, 13);
+ for (i = 0; i < 14; i++)
+ place(tile_stone, 1, i, 12);
+ for (i = 0; i < 12; i++)
+ place(tile_stone, 1, i, 11);
+ for (i = 0; i < 10; i++)
+ place(tile_stone, 1, i, 10);
+ place(tile_stone_ramp7, 4, 15, 13);
+ place(tile_stone_ramp8, 5, 16, 13);
+ place(tile_stone_ramp10, 7, 14, 12);
+ place(tile_stone_ramp7, 4, 12, 11);
+ place(tile_stone_ramp8, 5, 13, 11);
+ place(tile_stone_ramp7, 4, 10, 10);
+ place(tile_stone_ramp8, 5, 11, 10);
+ for (j = 0; j < 10; j++)
+ for (i = 0; i < 5; i++)
+ place(tile_brick, 1, i, j);
+ place(tile_trapdoor3, 0, 4, 9);
+ place(tile_brick_dark, 0, 3, 9);
+ place(tile_gate, 0, 2, 9);
+ place(tile_window_top, 1, 4, 3);
+ place(tile_window_mid, 1, 4, 4);
+ place(tile_window_bot, 1, 4, 5);
+ place(tile_window_top, 1, 4, 0);
+ place(tile_window_mid, 1, 4, 1);
+ place(tile_window_bot, 1, 4, 2);
+ w->player.x = (18 * map_tile_size) << fbits;
+ w->player.y = (13 * map_tile_size) << fbits;
+}
+
+void generate_outro(Map* m, struct World* w) {
+ int i, j;
+ int e = map_w * map_h;
+ for (i = 0; i < e; i++) {
+ m->tiles[i] = null_tile;
+ m->collision[i] = 0;
+ }
+ for (i = 0; i < map_h; i++) {
+ int y = i * map_w;
+ m->collision[y + (map_w - 1)] = 1;
+ m->collision[y] = 1;
+ }
+ for (j = 10; j < map_h; j++)
+ for (i = 0; i < map_w; i++)
+ place(tile_brick, 1, i, j);
+ for (i = 0; i < map_w; i++)
+ if (i & 1)
+ place(tile_brick_floor, 0, i, 9);
+ w->player.x = (map_w >> 1) << fbits;
+ w->player.x *= map_tile_size;
+ w->player.x += (map_tile_size >> 1) << fbits;
+ w->player.y = (9 * map_tile_size) << fbits;
+}
+
+#undef place
+#undef ncol
+
+int room_count(void) {
+ const Bitmap* bm = get_bitmap(asset_id_rooms_img);
+ return bm->h / map_h;
+}
diff --git a/map.h b/map.h
index 62263f5..b79151f 100644
--- a/map.h
+++ b/map.h
@@ -43,7 +43,9 @@ struct World;
x(tile_trapdoor1, 64, 48) \
x(tile_trapdoor2, 80, 48) \
x(tile_trapdoor3, 96, 48) \
- x(tile_trapdoor4, 112, 48)
+ x(tile_trapdoor4, 112, 48) \
+ x(tile_gate, 128, 48) \
+ x(tile_brick_dark, 144, 48)
typedef enum {
#define x(n, x, y) \
@@ -63,7 +65,10 @@ typedef struct Map {
*/
} Map;
-void generate_floor(Map* m, struct World* w);
+void generate_floor(Map* m, struct World* w, int fi);
+void generate_intro(Map* m, struct World* w);
+void generate_outro(Map* m, struct World* w);
void render_map(const Map* m, struct Renderer* r);
+int room_count(void);
#endif
diff --git a/random.c b/random.c
index f4ddfb9..355920b 100644
--- a/random.c
+++ b/random.c
@@ -48,6 +48,10 @@ int random_table[] = {
};
static int index = 0;
+void set_ri(int i) {
+ index = i;
+}
+
int get_r(void) {
index = (index + 1) & random_table_mask;
return random_table[index];
diff --git a/random.h b/random.h
index 8c7cb67..38afae5 100644
--- a/random.h
+++ b/random.h
@@ -7,6 +7,7 @@
extern int random_table[random_table_count];
+void set_ri(int i);
int get_r(void);
int get_rrange(int mi, int ma);
int get_rf(void);
diff --git a/str.c b/str.c
new file mode 100644
index 0000000..e5f0cd6
--- /dev/null
+++ b/str.c
@@ -0,0 +1,88 @@
+#include "maths.h"
+#include "memory.h"
+#include "str.h"
+
+int string_equal(const char* a, const char* b) {
+ while (*a && *b) {
+ if (*a != *b) { return 0; }
+ a++; b++;
+ }
+ return 1;
+}
+
+int string_copy(char* dst, const char* src) {
+ int i;
+ for (i = 0; *src; src++, dst++, i++) {
+ *dst = *src;
+ }
+ return i;
+}
+
+int string_len(const char* s) {
+ int l;
+ for (l = 0; *s; s++, l++);
+ return l;
+}
+
+char* dup_string(Arena* a, const char* s) {
+ int size = string_len(s) + 1;
+ char* d = arena_alloc_aligned(a, size, 1);
+ string_copy(d, s);
+ return d;
+}
+
+int int_to_buf(int n, char* buf) {
+ int i, sign, t;
+ unsigned n1;
+
+ if(n == 0) {
+ buf[0] = '0';
+ buf[1] = '\0';
+ return 1;
+ }
+
+ i = 0;
+ sign = n < 0;
+
+ n1 = sign ? -n : n;
+
+ while (n1 != 0) {
+ buf[i++] = n1 % 10 + '0';
+ n1 =n1 / 10;
+ }
+
+ if(sign) {
+ buf[i++] = '-';
+ }
+
+ buf[i] = '\0';
+
+ for (t = 0; t < i/2; t++) {
+ buf[t] ^= buf[i-t-1];
+ buf[i-t-1] ^= buf[t];
+ buf[t] ^= buf[i-t-1];
+ }
+
+ return i;
+}
+
+int f_to_buf(int f, char* buf) {
+ int frac, w, i;
+
+ frac = (((f) % (1 << fbits)) * 100) / (1 << fbits);
+ w = f >> fbits;
+
+ i = 0;
+
+ if (f < 0) {
+ buf[i] = '-';
+ i++;
+ }
+
+ i += int_to_buf(absolute(w), buf + i);
+ buf[i] = '.';
+ i++;
+ i += int_to_buf(absolute(frac), buf + i);
+
+ return i;
+}
diff --git a/str.h b/str.h
new file mode 100644
index 0000000..f6479cc
--- /dev/null
+++ b/str.h
@@ -0,0 +1,14 @@
+#ifndef str_h
+#define str_h
+
+struct Arena;
+
+int string_equal(const char* a, const char* b);
+int string_copy(char* dst, const char* src);
+int string_len(const char* s);
+char* dup_string(struct Arena* a, const char* s);
+
+int int_to_buf(int n, char* buf);
+int f_to_buf(int f, char* buf);
+
+#endif
diff --git a/world.c b/world.c
index 8d34b21..ae64049 100644
--- a/world.c
+++ b/world.c
@@ -9,6 +9,7 @@ void init_world(World* w) {
w->projectile_count = 0;
w->frame = 0;
w->freeze = 0;
+ w->kills = 0;
init_player(&w->player);
init_laser(&w->laser);
}
@@ -104,8 +105,10 @@ void update_world(World* w, const App* a) {
if (update_effect(&w->effects[i]))
w->effects[i] = w->effects[--w->effect_count];
for (i = w->enemy_count - 1; i >= 0; i--)
- if (update_enemy(&w->enemies[i], w))
+ if (update_enemy(&w->enemies[i], w)) {
w->enemies[i] = w->enemies[--w->enemy_count];
+ w->kills++;
+ }
for (i = w->projectile_count - 1; i >= 0; i--)
if (update_projectile(&w->projectiles[i], w))
w->projectiles[i] = w->projectiles[--w->projectile_count];
diff --git a/world.h b/world.h
index a0f6506..59faa69 100644
--- a/world.h
+++ b/world.h
@@ -23,7 +23,7 @@ typedef struct World {
Player player;
Laser laser;
Map map;
- int frame, freeze;
+ int frame, freeze, kills;
} World;
void init_world(World* w);