A retro platform game
git clone git://soophie.de/freezo
diff --git a/assets/background.png b/assets/background.png
index dd58683..dcdc44a 100644
Binary files a/assets/background.png and b/assets/background.png differ
diff --git a/assets/tiles.png b/assets/tiles.png
index 412b610..c4b6692 100644
Binary files a/assets/tiles.png and b/assets/tiles.png differ
diff --git a/include/door.h b/include/door.h
new file mode 100644
index 0000000..6f41e1f
--- /dev/null
+++ b/include/door.h
1
@@ -0,0 +1,21 @@2
+#pragma once3
+4
+typedef struct Door door_t;5
+6
+#include "game.h"7
+#include "util.h"8
+9
+#define DOOR_COUNTDOWN 2010
+11
+struct Door {12
+ pos_t pos;13
+ bool is_locked;14
+ int countdown;15
+};16
+17
+door_t *door_create(pos_t pos);18
+void door_update(door_t *door, game_t *game);19
+void door_draw(door_t *door, game_t *game);20
+void door_free(door_t *door);21
+22
+bool door_unlock(door_t *door, game_t *game);
diff --git a/include/entity.h b/include/entity.h
index 0524eee..bdccd78 100644
--- a/include/entity.h
+++ b/include/entity.h
1
@@ -5,10 +5,12 @@ typedef struct Entity entity_t;2
#include "enemy.h"3
#include "gate.h"4
#include "game.h"5
+#include "door.h"7
typedef enum {8
ENTITY_ENEMY,9
ENTITY_GATE,10
+ ENTITY_DOOR,11
} entity_e;13
struct Entity {14
@@ -16,7 +18,9 @@ struct Entity {15
union {16
enemy_t *enemy;17
gate_t *gate;18
+ door_t *door;19
};20
+ bool is_bad;21
};23
entity_t *entity_create(entity_e type);
diff --git a/src/door.c b/src/door.c
new file mode 100644
index 0000000..c1633a2
--- /dev/null
+++ b/src/door.c
1
@@ -0,0 +1,65 @@2
+#include <stdlib.h>3
+4
+#include "../include/door.h"5
+#include "../include/const.h"6
+7
+door_t *door_create(pos_t pos) {8
+ door_t *door = malloc(sizeof(door_t));9
+ door->pos = pos;10
+ door->is_locked = true;11
+ door->countdown = 0;12
+ return door;13
+}14
+15
+void door_update(door_t *door, game_t *game) {16
+ (void) game;17
+ if (door->countdown > 0) {18
+ door->countdown--;19
+ }20
+}21
+22
+void door_draw(door_t *door, game_t *game) {23
+ if (door->is_locked) {24
+ DrawTextureRec(game->assets.tiles, texture_rect(1, 2, TILE_WIDTH, TILE_HEIGHT), (pos_t) { door->pos.x, door->pos.y - TILE_HEIGHT }, WHITE);25
+ DrawTextureRec(game->assets.tiles, texture_rect(1, 3, TILE_WIDTH, TILE_HEIGHT), door->pos, WHITE);26
+ if (door->countdown > 0) {27
+ pos_t lock_pos = {28
+ .x = door->pos.x,29
+ .y = door->pos.y - 2 * TILE_HEIGHT,30
+ };31
+ DrawTextureRec(game->assets.tiles, texture_rect(3, 1, TILE_WIDTH, TILE_HEIGHT), lock_pos, WHITE);32
+ }33
+ }34
+ else {35
+ DrawTextureRec(game->assets.tiles, texture_rect(2, 2, TILE_WIDTH, TILE_HEIGHT), (pos_t) { door->pos.x, door->pos.y - TILE_HEIGHT }, WHITE);36
+ DrawTextureRec(game->assets.tiles, texture_rect(2, 3, TILE_WIDTH, TILE_HEIGHT), door->pos, WHITE);37
+ }38
+}39
+40
+void door_free(door_t *door) {41
+ free(door);42
+}43
+44
+bool door_unlock(door_t *door, game_t *game) {45
+ if (!door->is_locked) {46
+ return true;47
+ }48
+ int enemies_len = 0;49
+ bool gates_frozen = true;50
+ for (int i = 0; i < game->entities_len; i++) {51
+ if(game->entities[i].type == ENTITY_ENEMY) {52
+ enemies_len++;53
+ }54
+ if(game->entities[i].type == ENTITY_GATE) {55
+ if (!game->entities[i].gate->frozen) {56
+ gates_frozen = false;57
+ }58
+ }59
+ }60
+ if (enemies_len == 0 && gates_frozen) {61
+ door->is_locked = false;62
+ return true;63
+ }64
+ door->countdown = DOOR_COUNTDOWN;65
+ return false;66
+}
diff --git a/src/entity.c b/src/entity.c
index 5ee085a..60c9329 100644
--- a/src/entity.c
+++ b/src/entity.c
1
@@ -3,10 +3,22 @@2
#include "../include/entity.h"3
#include "../include/enemy.h"4
#include "../include/gate.h"5
+#include "../include/door.h"7
entity_t *entity_create(entity_e type) {8
entity_t *entity = malloc(sizeof(entity_t));9
entity->type = type;10
+ switch (entity->type) {11
+ case ENTITY_ENEMY:12
+ entity->is_bad = true;13
+ break;14
+ case ENTITY_GATE:15
+ entity->is_bad = true;16
+ break;17
+ case ENTITY_DOOR:18
+ entity->is_bad = false;19
+ break;20
+ }21
return entity;22
}24
@@ -18,6 +30,9 @@ void entity_update(entity_t *entity, game_t *game) {25
case ENTITY_GATE:26
gate_update(entity->gate, game);27
break;28
+ case ENTITY_DOOR:29
+ door_update(entity->door, game);30
+ break;31
}32
}34
@@ -29,6 +44,9 @@ void entity_draw(entity_t *entity, game_t *game) {35
case ENTITY_GATE:36
gate_draw(entity->gate, game);37
break;38
+ case ENTITY_DOOR:39
+ door_draw(entity->door, game);40
+ break;41
}42
}44
@@ -40,6 +58,9 @@ void entity_detach(entity_t *entity) {45
case ENTITY_GATE:46
gate_free(entity->gate);47
break;48
+ case ENTITY_DOOR:49
+ door_free(entity->door);50
+ break;51
}52
}
diff --git a/src/game.c b/src/game.c
index 39d3ef9..f5675f0 100644
--- a/src/game.c
+++ b/src/game.c
1
@@ -58,8 +58,9 @@ void game_update(game_t *game) {2
// defeat3
if (game->defeat) {4
if (game->sceen_timer == 100) {5
+ level_e level = game->level->type;6
level_unload(game);7
- level_load(game, LEVEL_1);8
+ level_load(game, level);9
game->defeat = false;10
game->xp = 0;11
game->sceen_timer = 0;12
@@ -69,34 +70,19 @@ void game_update(game_t *game) {13
}14
}15
// victory16
- int enemies_len = 0;17
- bool gates_frozen = true;18
- for (int i = 0; i < game->entities_len; i++) {19
- if(game->entities[i].type == ENTITY_ENEMY) {20
- enemies_len++;21
- }22
- if(game->entities[i].type == ENTITY_GATE) {23
- if (!game->entities[i].gate->frozen) {24
- gates_frozen = false;25
+ if (game->victory) {26
+ if (game->sceen_timer == 100) {27
+ if (game->level->type < LEVELS) {28
+ level_e level = game->level->type;29
+ level++;30
+ level_unload(game);31
+ level_load(game, level);32
}33
+ game->victory = false;34
+ game->sceen_timer = 0;35
}36
- }37
- if (enemies_len == 0 && gates_frozen) {38
- game->victory = true;39
- if (game->victory) {40
- if (game->sceen_timer == 100) {41
- if (game->level->type < LEVELS) {42
- level_e level = game->level->type;43
- level++;44
- level_unload(game);45
- level_load(game, level);46
- }47
- game->victory = false;48
- game->sceen_timer = 0;49
- }50
- else {51
- game->sceen_timer++;52
- }53
+ else {54
+ game->sceen_timer++;55
}56
}57
if (!game->victory && !game->defeat) {
diff --git a/src/level.c b/src/level.c
index 1c8f3b1..e84fd41 100644
--- a/src/level.c
+++ b/src/level.c
1
@@ -14,12 +14,12 @@ const char *LEVEL_MAP_1 = {2
"........................"3
"........................"4
"......e......3.........."5
- "....xxxx................"6
+ "....xxxxx..............."7
".....b.................."8
"...........--...xxx....."9
"................e......."10
"...........2...--xxxxx.."11
- "....p..................."12
+ "....p....u.............."13
"..xxxxxxxxx---xxxxxxxx.."14
"........................"15
"........................"16
@@ -30,7 +30,7 @@ const char *LEVEL_MAP_2 = {17
"........................"18
"......3....b............"19
"........................"20
- "........................"21
+ "................u......."22
"...............xxxx....."23
"..o......s.e............"24
".......xxxxxxtxxx--xx..."25
@@ -51,8 +51,8 @@ const char *LEVEL_MAP_3 = {26
"............-txx-......."27
".............w.........."28
"............-w..-......."29
- "........s....w.........."30
- "..x---xxxxxxxtxxx--xx..."31
+ "........s....w......u..."32
+ "..x---xxxxxxxtxxx--xxx.."33
"....e........w....e....."34
"...---....2..w--txxx...."35
"....3........w..w......."36
@@ -176,6 +176,7 @@ void level_generate(game_t *game, const char *map, int width, int height) {37
game->entities[game->entities_len] = (entity_t) {38
.type = ENTITY_ENEMY,39
.enemy = enemy,40
+ .is_bad = true,41
};42
game->entities_len++;43
break;44
@@ -189,6 +190,21 @@ void level_generate(game_t *game, const char *map, int width, int height) {45
game->entities[game->entities_len] = (entity_t) {46
.type = ENTITY_GATE,47
.gate = gate,48
+ .is_bad = true,49
+ };50
+ game->entities_len++;51
+ break;52
+ }53
+ case 'u': {54
+ game->entities = realloc(game->entities, sizeof(enemy_t) * (game->entities_len + 1));55
+ door_t *door = door_create((pos_t) {56
+ .x = x * TILE_WIDTH + (TILE_WIDTH - ENEMY_WIDTH) / 2.0,57
+ .y = y * TILE_HEIGHT,58
+ });59
+ game->entities[game->entities_len] = (entity_t) {60
+ .type = ENTITY_DOOR,61
+ .door = door,62
+ .is_bad = false,63
};64
game->entities_len++;65
break;
diff --git a/src/player.c b/src/player.c
index fd05da3..d983ed4 100644
--- a/src/player.c
+++ b/src/player.c
1
@@ -248,6 +248,10 @@ void player_update(player_t *player, game_t *game) {2
if (entity->type == ENTITY_GATE && entity->gate->frozen) {3
continue;4
}5
+ // ignore non-bad entities6
+ if (!entity->is_bad) {7
+ continue;8
+ }9
rect_t entity_rect;10
switch (entity->type) {11
case ENTITY_ENEMY:12
@@ -256,6 +260,9 @@ void player_update(player_t *player, game_t *game) {13
case ENTITY_GATE:14
entity_rect = rect_from_pos((pos_t) { entity->gate->pos.x, entity->gate->pos.y - TILE_HEIGHT }, ENEMY_WIDTH, ENEMY_HEIGHT);15
break;16
+ case ENTITY_DOOR:17
+ entity_rect = rect_from_pos((pos_t) { entity->gate->pos.x, entity->gate->pos.y - TILE_HEIGHT }, ENEMY_WIDTH, ENEMY_HEIGHT);18
+ break;19
}20
if (rect_collide(shooting_rect, entity_rect)) {21
float entity_x = entity_rect.x + entity_rect.width / 2.0;22
@@ -314,8 +321,8 @@ void player_update(player_t *player, game_t *game) {23
float tolerance = 0.0;24
if (25
player->pos.x <= enemy->pos.x + ENEMY_WIDTH - tolerance &&26
- player->pos.x + PLAYER_WIDTH >= enemy->pos.x + tolerance &&27
- player->pos.y <= enemy->pos.y + ENEMY_HEIGHT - tolerance &&28
+ player->pos.x + PLAYER_WIDTH >= enemy->pos.x + tolerance &&29
+ player->pos.y <= enemy->pos.y + ENEMY_HEIGHT - tolerance &&30
player->pos.y + PLAYER_HEIGHT >= enemy->pos.y + tolerance31
) {32
if (player->held_enemy == NULL) {33
@@ -336,6 +343,25 @@ void player_update(player_t *player, game_t *game) {34
.y = player->pos.y - (player->sneaking ? 0.3 : 0.5) * TILE_HEIGHT,35
};36
}37
+ // detect door entering38
+ if (holding) {39
+ for (int i = 0; i < game->entities_len; i++) {40
+ if (game->entities[i].type == ENTITY_DOOR) {41
+ door_t *door = game->entities[i].door;42
+ float tolerance = 0.0;43
+ if (44
+ player->pos.x <= door->pos.x + ENEMY_WIDTH - tolerance &&45
+ player->pos.x + PLAYER_WIDTH >= door->pos.x + tolerance &&46
+ player->pos.y <= door->pos.y + ENEMY_HEIGHT - tolerance &&47
+ player->pos.y + PLAYER_HEIGHT >= door->pos.y + tolerance48
+ ) {49
+ if (door_unlock(door, game)) {50
+ game->victory = true;51
+ }52
+ }53
+ }54
+ }55
+ }56
// detect damage57
for (int i = 0; i < game->entities_len; i++) {58
if (game->entities[i].type == ENTITY_ENEMY) {59
@@ -344,8 +370,8 @@ void player_update(player_t *player, game_t *game) {60
float tolerance = TILE_WIDTH / 5.0;61
if (62
player->pos.x <= enemy->pos.x + ENEMY_WIDTH - tolerance &&63
- player->pos.x + PLAYER_WIDTH >= enemy->pos.x + tolerance &&64
- player->pos.y <= enemy->pos.y + ENEMY_HEIGHT - tolerance &&65
+ player->pos.x + PLAYER_WIDTH >= enemy->pos.x + tolerance &&66
+ player->pos.y <= enemy->pos.y + ENEMY_HEIGHT - tolerance &&67
player->pos.y + PLAYER_HEIGHT >= enemy->pos.y + tolerance68
) {69
if (player->damage_timer == 0) {