aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--asset.c14
-rw-r--r--asset.h1
-rw-r--r--collision_system.c1
-rw-r--r--config.h4
-rw-r--r--game.c200
-rw-r--r--game.h36
-rw-r--r--game_config.h1
-rw-r--r--intermediate/usr.bmpbin67422 -> 68178 bytes
-rw-r--r--main.c24
-rw-r--r--menu.c86
-rw-r--r--menu.h35
-rw-r--r--player.c14
-rw-r--r--player.h2
-rw-r--r--render.c92
-rw-r--r--render.h18
-rw-r--r--sprite.c14
-rw-r--r--sprite.h5
-rw-r--r--world.c5
19 files changed, 522 insertions, 32 deletions
diff --git a/Makefile b/Makefile
index 4fe54fd..f4d21cf 100644
--- a/Makefile
+++ b/Makefile
@@ -92,8 +92,10 @@ sources = \
collision_system.c \
enemy.c \
fx.c \
+ game.c \
main.c \
malware.c \
+ menu.c \
platform.c \
player.c \
rect.c \
diff --git a/asset.c b/asset.c
index 5ae5419..5db8a20 100644
--- a/asset.c
+++ b/asset.c
@@ -16,6 +16,8 @@ static struct {
FILE* pack;
int pack_count;
+ BM_Font default_font;
+
unsigned char memory[asset_memory];
int memory_ptr;
@@ -113,8 +115,20 @@ void load_assets() {
#undef gi
fclose(pack);
+
+ init_font(
+ &asset_manager.default_font,
+ get_bitmap(asset_id_usr),
+ 10,
+ 10,
+ 16
+ );
}
const Bitmap* get_bitmap(Asset_ID id) {
return &asset_manager.bitmaps[id];
}
+
+const BM_Font* get_default_font() {
+ return &asset_manager.default_font;
+}
diff --git a/asset.h b/asset.h
index 8c6e201..23b0893 100644
--- a/asset.h
+++ b/asset.h
@@ -16,5 +16,6 @@ typedef enum {
void load_assets();
const Bitmap* get_bitmap(Asset_ID id);
+const BM_Font* get_default_font();
#endif
diff --git a/collision_system.c b/collision_system.c
index abd5dc9..68e3b09 100644
--- a/collision_system.c
+++ b/collision_system.c
@@ -15,6 +15,7 @@ static void handle_bullet_vs_player(
pos = &world->positions[bullet];
+ player_take_damage(&world->player, 1);
destroy_entity(world, bullet);
new_enemy_bullet_explosion(world, pos->x, pos->y);
}
diff --git a/config.h b/config.h
index 063781b..ff95ba4 100644
--- a/config.h
+++ b/config.h
@@ -18,7 +18,7 @@
#define animation_max_frames 8
#define max_entities 256
-#define max_player_bullets 32
-#define max_enemy_bullets 256
+
+#define menu_max_elements 4
#endif
diff --git a/game.c b/game.c
new file mode 100644
index 0000000..73d062b
--- /dev/null
+++ b/game.c
@@ -0,0 +1,200 @@
+#include "asset.h"
+#include "enemy.h"
+#include "game.h"
+#include "platform.h"
+#include "sprite.h"
+#include "systems.h"
+
+static void menu_new(Menu* menu) {
+ Game* game;
+
+ game = menu->ptr;
+ game_change_state(game, game_state_game);
+}
+
+static void menu_restart(Menu* menu) {
+ Game* game;
+
+ game = menu->ptr;
+ game_change_state(game, game_state_game);
+}
+
+static void menu_main_menu(Menu* menu) {
+ Game* game;
+
+ game = menu->ptr;
+ game_change_state(game, game_state_menu);
+}
+
+static void menu_quit(Menu* menu) {
+ (void)menu;
+ platform_quit();
+}
+
+static void menu_credits(Menu* menu) {
+ Game* game;
+
+ game = menu->ptr;
+ game_change_state(game, game_state_credits);
+}
+
+static void menu_init(Game* game) {
+ const BM_Font* font;
+
+ font = get_default_font();
+
+ init_menu(&game->menu, game);
+ menu_add(&game->menu, "New", menu_new, font);
+ menu_add(&game->menu, "Continue", 0, font);
+ menu_add(&game->menu, "Credits", menu_credits, font);
+ menu_add(&game->menu, "Quit", menu_quit, font);
+}
+
+static void menu_update(Game* game) {
+ const Sprite* msg;
+ const Bitmap* bmp;
+ int h, y;
+
+ update_menu(&game->menu);
+
+ h = game->menu.h;
+ y = game->menu.y;
+
+ msg = get_sprite(sprite_author);
+ bmp = get_bitmap(msg->bitmap);
+ render_bitmap(
+ bmp,
+ renderer_w / 2 - msg->rect.w / 2,
+ renderer_h - 26,
+ &msg->rect
+ );
+
+ msg = get_sprite(sprite_free);
+ bmp = get_bitmap(msg->bitmap);
+ render_bitmap(
+ bmp,
+ renderer_w / 2 - msg->rect.w / 2,
+ renderer_h - 15,
+ &msg->rect
+ );
+
+ render_menu(&game->menu, get_default_font());
+}
+
+static void menu_deinit(Game* game) {
+
+}
+
+static void gameplay_init(Game* game) {
+ init_world(&game->world);
+
+ init_player(&game->world.player, &game->world);
+
+ new_skull(&game->world, 0, 0);
+}
+
+static void gameplay_update(Game* game) {
+ update_player(&game->world.player, &game->world);
+ enemy_system(&game->world);
+ bullet_system(&game->world);
+ collision_system(&game->world);
+ animation_system(&game->world);
+ sprite_system(&game->world);
+}
+
+static void gameplay_deinit(Game* game) {
+
+}
+
+static void credits_init(Game* game) {
+
+}
+
+static void credits_update(Game* game) {
+
+}
+
+static void credits_deinit(Game* game) {
+
+}
+
+static void dead_init(Game* game) {
+ const BM_Font* font = get_default_font();
+ init_menu(&game->menu, game);
+ menu_add(&game->menu, "Restart", menu_restart, font);
+ menu_add(&game->menu, "Main Menu", menu_main_menu, font);
+}
+
+static void dead_update(Game* game) {
+ const BM_Font* font;
+
+ font = get_default_font();
+
+ update_menu(&game->menu);
+
+ sprite_system(&game->world);
+
+ rfont_text(
+ font,
+ renderer_w / 2 - 40,
+ game->menu.y - 15,
+ "You died"
+ );
+ render_menu(&game->menu, get_default_font());
+}
+
+static void dead_deinit(Game* game) {
+
+}
+
+static const Game_State_Fns game_state_fns[] = {
+ /* game_state_menu */
+ {
+ menu_init,
+ menu_update,
+ menu_deinit
+ },
+ /* game_state_game */
+ {
+ gameplay_init,
+ gameplay_update,
+ gameplay_deinit
+ },
+ /* game_state_credits */
+ {
+ credits_init,
+ credits_update,
+ credits_deinit
+ },
+ /* game_state_dead */
+ {
+ dead_init,
+ dead_update,
+ dead_deinit
+ }
+};
+
+static const Game_State_Fns* get_state_fns(Game_State state) {
+ return &game_state_fns[state];
+}
+
+void game_init(Game* game, Game_State state) {
+ game->state = state;
+ game->fns = get_state_fns(state);
+ game->fns->state_init(game);
+}
+
+void game_update(Game* game) {
+ game->fns->state_update(game);
+}
+
+void game_deinit(Game* game) {
+ game->fns->state_deinit(game);
+}
+
+void game_change_state(Game* game, Game_State state) {
+ game->fns->state_deinit(game);
+ game->state = state;
+ game->fns = get_state_fns(state);
+ game->fns->state_init(game);
+}
diff --git a/game.h b/game.h
new file mode 100644
index 0000000..6562673
--- /dev/null
+++ b/game.h
@@ -0,0 +1,36 @@
+#ifndef game_h
+#define game_h
+
+#include "world.h"
+#include "menu.h"
+
+typedef enum {
+ game_state_menu = 0,
+ game_state_game,
+ game_state_credits,
+ game_state_dead
+} Game_State;
+
+typedef struct Game Game;
+
+typedef struct {
+ void (*state_init)(Game* game);
+ void (*state_update)(Game* game);
+ void (*state_deinit)(Game* game);
+} Game_State_Fns;
+
+struct Game {
+ const Game_State_Fns* fns;
+ Game_State state;
+ Menu menu;
+
+ World world;
+};
+
+void game_init(Game* game, Game_State state);
+void game_update(Game* game);
+void game_deinit(Game* game);
+
+void game_change_state(Game* game, Game_State state);
+
+#endif
diff --git a/game_config.h b/game_config.h
index 0c97a8d..b2d569f 100644
--- a/game_config.h
+++ b/game_config.h
@@ -3,6 +3,7 @@
#define player_move_speed (3 << fbits)
#define player_bullet_speed (10 << fbits)
+#define player_max_hp 3
#define skull_hp 3
#define skull_speed (1 << fbits)
diff --git a/intermediate/usr.bmp b/intermediate/usr.bmp
index e5e8185..7735e60 100644
--- a/intermediate/usr.bmp
+++ b/intermediate/usr.bmp
Binary files differ
diff --git a/main.c b/main.c
index 9d2aff8..0e26dd3 100644
--- a/main.c
+++ b/main.c
@@ -1,12 +1,7 @@
-#include "asset.h"
-#include "player.h"
-#include "render.h"
+#include "game.h"
#include "standard.h"
-#include "systems.h"
-#include "world.h"
-#include "enemy.h"
-World world;
+Game game;
void on_init(int argc, char** argv) {
seed_rng(500);
@@ -15,23 +10,14 @@ void on_init(int argc, char** argv) {
load_assets();
- init_world(&world);
-
- init_player(&world.player, &world);
-
- new_skull(&world, 0, 0);
+ game_init(&game, game_state_menu);
}
void on_update() {
renderer_begin_frame();
- update_player(&world.player, &world);
- enemy_system(&world);
- bullet_system(&world);
- collision_system(&world);
- animation_system(&world);
- sprite_system(&world);
+ game_update(&game);
}
void on_deinit() {
-
+ game_deinit(&game);
}
diff --git a/menu.c b/menu.c
new file mode 100644
index 0000000..e4e82f5
--- /dev/null
+++ b/menu.c
@@ -0,0 +1,86 @@
+#include "asset.h"
+#include "input.h"
+#include "menu.h"
+
+#ifdef DEBUG
+#include "error.h"
+#include "platform.h"
+#endif
+
+void init_menu(Menu* menu, void* ptr) {
+ menu->el_count = 0;
+ menu->selected = 0;
+ menu->y = renderer_h / 2;
+ menu->h = 0;
+ menu->ptr = ptr;
+}
+
+void menu_add(
+ Menu* menu,
+ const char* text,
+ Menu_Event on_select,
+ const BM_Font* font
+) {
+ Menu_Item* it;
+ int i;
+
+#ifdef DEBUG
+ if (menu->el_count >= menu_max_elements) {
+ platform_err("Too many menu elements.\n");
+ platform_abort(error_gameplay_error);
+ }
+#endif
+
+ it = &menu->els[menu->el_count++];
+ it->on_select = on_select;
+ it->text_len = 0;
+ for (i = 0; text[i]; i++) {
+ it->text[i] = text[i];
+ it->text_len++;
+ } it->text[i] = 0;
+
+ menu->h = font->char_h * menu->el_count;
+ menu->y = renderer_h / 2 - (menu->h) / 2;
+}
+
+void update_menu(Menu* menu) {
+ if (button_just_pressed(btn_dpad_down)) {
+ menu->selected++;
+ if (menu->selected >= menu->el_count) {
+ menu->selected = 0;
+ }
+ }
+
+ if (button_just_pressed(btn_dpad_up)) {
+ menu->selected--;
+ if (menu->selected < 0) {
+ menu->selected = menu->el_count - 1;
+ }
+ }
+
+ if (
+ button_just_pressed(btn_jump) ||
+ button_just_pressed(btn_shoot)
+ ) {
+ menu->els[menu->selected].on_select(menu);
+ }
+}
+
+void render_menu(Menu* menu, const BM_Font* font) {
+ int i, x, y, cw, ch;
+ const Menu_Item* el;
+
+ y = menu->y;
+ cw = font->char_w;
+ ch = font->char_h;
+
+ for (i = 0; i < menu->el_count; i++) {
+ el = &menu->els[i];
+ x = renderer_w / 2 - (cw * el->text_len) / 2;
+ rfont_text(font, x, y, el->text);
+ if (i == menu->selected) {
+ rfont_char(font, x - cw, y, '>');
+ }
+ y += ch;
+ }
+}
diff --git a/menu.h b/menu.h
new file mode 100644
index 0000000..52403f1
--- /dev/null
+++ b/menu.h
@@ -0,0 +1,35 @@
+#ifndef menu_h
+#define menu_h
+
+#include "config.h"
+#include "render.h"
+
+typedef struct Menu Menu;
+
+typedef void (*Menu_Event)(Menu* menu);
+
+typedef struct {
+ Menu_Event on_select;
+ int text_len;
+ char text[20];
+} Menu_Item;
+
+struct Menu {
+ Menu_Item els[menu_max_elements];
+ int el_count;
+ int selected;
+ int y, h;
+ void* ptr;
+};
+
+void init_menu(Menu* menu, void* ptr);
+void menu_add(
+ Menu* menu,
+ const char* text,
+ Menu_Event on_select,
+ const BM_Font* font
+);
+void update_menu(Menu* menu);
+void render_menu(Menu* menu, const BM_Font* font);
+
+#endif
diff --git a/player.c b/player.c
index b2dbf29..592ef4a 100644
--- a/player.c
+++ b/player.c
@@ -1,11 +1,14 @@
#include "animation.h"
+#include "bullet.h"
#include "components.h"
+#include "game.h"
#include "game_config.h"
#include "input.h"
#include "player.h"
#include "standard.h"
#include "world.h"
-#include "bullet.h"
+
+extern Game game;
void init_player(Player* player, World* world) {
CSprite* sprite;
@@ -48,6 +51,7 @@ void init_player(Player* player, World* world) {
player->face = 0;
player->shoot_cooldown = 15;
player->shoot_countdown = 0;
+ player->hp = player_max_hp;
}
void update_player(Player* player, World* world) {
@@ -124,5 +128,13 @@ void update_player(Player* player, World* world) {
player->shoot_countdown = player->shoot_cooldown;
}
+ if (player->hp <= 0) {
+ game_change_state(&game, game_state_dead);
+ }
+
player->shoot_countdown--;
}
+
+void player_take_damage(Player* player, int dmg) {
+ player->hp -= dmg;
+}
diff --git a/player.h b/player.h
index da1605e..0e84b9e 100644
--- a/player.h
+++ b/player.h
@@ -9,9 +9,11 @@ typedef struct {
int ldx, ldy;
int shoot_cooldown;
int shoot_countdown;
+ int hp;
} Player;
void init_player(Player* player, struct World* world);
void update_player(Player* player, struct World* world);
+void player_take_damage(Player* player, int dmg);
#endif
diff --git a/render.c b/render.c
index 578abef..b2a59e2 100644
--- a/render.c
+++ b/render.c
@@ -73,7 +73,7 @@ Colour blend_mod(Colour dst, Colour src, Colour mod) {
void init_font(
BM_Font* font,
- Bitmap* bmp,
+ const Bitmap* bmp,
int char_w,
int char_h,
int chars_across
@@ -84,28 +84,65 @@ void init_font(
font->chars_across = chars_across;
}
-void rfont_char(int x, int y, char c) {
+void rfont_char(const BM_Font* font, int x, int y, char c) {
+ Rectangle rect;
+ c -= ' ';
+
+ rect.x = (c % font->chars_across) * font->char_w;
+ rect.y = (c / font->chars_across) * font->char_h;
+ rect.w = font->char_w;
+ rect.h = font->char_h;
+
+ render_bitmap(font->bmp, x, y, &rect);
}
-void rfont_char_col(int x, int y, char c, Colour colour) {
+void rfont_char_col(
+ const BM_Font* font,
+ int x,
+ int y,
+ char c,
+ Colour colour
+) {
+ Rectangle rect;
+
+ c -= ' ';
+
+ rect.x = (c % font->chars_across) * font->char_w;
+ rect.y = (c / font->chars_across) * font->char_h;
+ rect.w = font->char_w;
+ rect.h = font->char_h;
+ render_bitmap_col(font->bmp, x, y, &rect, colour);
}
void rfont_text(
+ const BM_Font* font,
int x,
int y,
const char* text
) {
+ const char* c;
+
+ for (c = text; *c; c++) {
+ rfont_char(font, x, y, *c);
+ x += font->char_w;
+ }
}
void rfont_text_col(
+ const BM_Font* font,
int x,
int y,
const char* text,
Colour colour
) {
+ const char* c;
+ for (c = text; *c; c++) {
+ rfont_char_col(font, x, y, *c, colour);
+ x += font->char_w;
+ }
}
void render_bitmap(
@@ -173,5 +210,54 @@ void render_bitmap_col(
const Rectangle* rect,
Colour colour
) {
+ int i, j, stride, sstride, n;
+ Colour* dst;
+ const Colour* src;
+ Rectangle sub;
+ sub = *rect;
+
+ if (sub.w <= 0) { return; }
+ if (sub.h <= 0) { return; }
+ if (sub.w > bitmap->w) { return; }
+ if (sub.h > bitmap->h) { return; }
+
+ if ((n = -x) > 0) {
+ sub.w -= n;
+ sub.x += n;
+ x += n;
+ }
+
+ if ((n = -y) > 0) {
+ sub.h -= n;
+ sub.y += n;
+ y += n;
+ }
+
+ if ((n = x + sub.w - renderer_w) > 0) {
+ sub.w -= n;
+ }
+
+ if ((n = y + sub.h - renderer_h) > 0) {
+ sub.h -= n;
+ }
+
+ if (sub.w <= 0) { return; }
+ if (sub.h <= 0) { return; }
+
+ dst = renderer.pixels + (x + y * renderer_w);
+ src = bitmap->pixels + (sub.x + sub.y * bitmap->w);
+
+ stride = renderer_w - sub.w;
+ sstride = bitmap->w - sub.w;
+
+ for (i = 0; i < sub.h; i++) {
+ for (j = 0; j < sub.w; j++) {
+ *dst = blend_mod(*dst, *src, colour);
+ dst++;
+ src++;
+ }
+ dst += stride;
+ src += sstride;
+ }
}
diff --git a/render.h b/render.h
index d63297e..be03f02 100644
--- a/render.h
+++ b/render.h
@@ -24,28 +24,36 @@ void init_bitmap(
int h
);
-typedef struct {
- Bitmap* bmp;
+typedef struct BM_Font {
+ const Bitmap* bmp;
int char_w, char_h;
int chars_across;
} BM_Font;
void init_font(
BM_Font* font,
- Bitmap* bmp,
+ const Bitmap* bmp,
int char_w,
int char_h,
int chars_across
);
-void rfont_char(int x, int y, char c);
-void rfont_char_col(int x, int y, char c, Colour colour);
+void rfont_char(const BM_Font* font, int x, int y, char c);
+void rfont_char_col(
+ const BM_Font* font,
+ int x,
+ int y,
+ char c,
+ Colour colour
+);
void rfont_text(
+ const BM_Font* font,
int x,
int y,
const char* text
);
void rfont_text_col(
+ const BM_Font* font,
int x,
int y,
const char* text,
diff --git a/sprite.c b/sprite.c
index c14f717..ca72f44 100644
--- a/sprite.c
+++ b/sprite.c
@@ -60,6 +60,16 @@ static const Sprite sprites[] = {
{
asset_id_bullet,
{ 18, 0, 5, 5 }
+ },
+ /* sprite_author */
+ {
+ asset_id_usr,
+ { 0, 70, 70, 10 }
+ },
+ /* sprite_free */
+ {
+ asset_id_usr,
+ { 0, 80, 171, 10 }
}
};
@@ -70,3 +80,7 @@ void init_csprite(CSprite* sprite, Sprite_ID id) {
sprite->id = s->bitmap;
sprite->rect = s->rect;
}
+
+const Sprite* get_sprite(Sprite_ID id) {
+ return &sprites[id];
+}
diff --git a/sprite.h b/sprite.h
index cf9d6e8..cdc5e28 100644
--- a/sprite.h
+++ b/sprite.h
@@ -17,7 +17,9 @@ typedef enum {
sprite_skull_debris_3,
sprite_skull_debris_4,
sprite_skull_debris_5,
- sprite_enemy_bullet
+ sprite_enemy_bullet,
+ sprite_author,
+ sprite_free
} Sprite_ID;
typedef struct {
@@ -26,5 +28,6 @@ typedef struct {
} Sprite;
void init_csprite(CSprite* sprite, Sprite_ID id);
+const Sprite* get_sprite(Sprite_ID id);
#endif
diff --git a/world.c b/world.c
index 920484c..39673d4 100644
--- a/world.c
+++ b/world.c
@@ -3,7 +3,10 @@
#include "error.h"
void init_world(World* world) {
- world->entity_count = 0;
+ int i, s = sizeof world;
+ for (i = 0; i < s; i++) {
+ ((char*)world)[i] = 0;
+ }
}
Entity new_entity(World* world) {