diff options
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | game.c | 110 | ||||
| -rw-r--r-- | game.h | 12 | ||||
| -rw-r--r-- | intermediate/map.bmp | bin | 41098 -> 41098 bytes | |||
| -rw-r--r-- | intermediate/rooms.bmp | bin | 2538 -> 20538 bytes | |||
| -rw-r--r-- | map.c | 161 | ||||
| -rw-r--r-- | map.h | 9 | ||||
| -rw-r--r-- | random.c | 4 | ||||
| -rw-r--r-- | random.h | 1 | ||||
| -rw-r--r-- | str.c | 88 | ||||
| -rw-r--r-- | str.h | 14 | ||||
| -rw-r--r-- | world.c | 5 | ||||
| -rw-r--r-- | world.h | 2 | 
13 files changed, 357 insertions, 50 deletions
@@ -62,6 +62,7 @@ sources = \  	random.c \  	rect.c \  	render.c \ +	str.c \  	world.c \  image_sources = \ @@ -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; @@ -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 Binary files differindex 588a13d..8389d9f 100644 --- a/intermediate/map.bmp +++ b/intermediate/map.bmp diff --git a/intermediate/rooms.bmp b/intermediate/rooms.bmp Binary files differindex a0bf456..60d021c 100644 --- a/intermediate/rooms.bmp +++ b/intermediate/rooms.bmp @@ -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; +} @@ -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 @@ -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]; @@ -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); @@ -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; +} @@ -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 @@ -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]; @@ -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);  |