A retro platform game
git clone git://soophie.de/freezo
blob: 52cadebc4444724cb6c1c1c052412e5ea5f46eda (11545 bytes)[raw]
1
#include <stdio.h>2
#include <stdlib.h>3
#include <string.h>5
#include "../lib/raylib.h"6
#include "../include/entity.h"7
#include "../include/game.h"8
#include "../include/tile.h"9
#include "../include/util.h"10
#include "../include/player.h"11
#include "../include/const.h"12
#include "../include/level.h"14
game_t *game_create(void) {15
game_t *game = malloc(sizeof(game_t));16
*game = (game_t) {17
.state = STATE_GAME,18
.level = NULL,19
.quit = false,20
.defeat = false,21
.victory = false,22
.menu = menu_create(),23
.player = NULL,24
.tiles = NULL,25
.tiles_len = 0,26
.entities = NULL,27
.entities_len = 0,28
.effects = NULL,29
.effects_len = 0,30
.assets.tiles = texture_load("assets/tiles.png", SCALE),31
.assets.entities = texture_load("assets/entities.png", SCALE),32
.assets.font = texture_load("assets/font.png", SCALE - 1),33
.assets.images = texture_load("assets/images.png", SCALE),34
.assets.background = texture_load("assets/background.png", SCALE),35
.assets.track = LoadSound("assets/song.wav"),36
.assets.win = LoadSound("assets/win.wav"),37
.assets.lose = LoadSound("assets/lose.wav"),38
.assets.locked = LoadSound("assets/locked.wav"),39
.camera = (Camera2D) {40
.offset = (pos_t) { 0.0, 0.0 },41
.zoom = 1,42
},43
.xp = 0,44
.sceen_timer = 0,45
.door = NULL,46
.overlay = LoadRenderTexture(WINDOW_WIDTH, WINDOW_HEIGHT),47
.is_muted = false,48
};49
level_load(game, LEVEL_1);50
SetSoundVolume(game->assets.track, GAME_MUSIC_VOLUME);51
SetSoundVolume(game->assets.win, GAME_SOUND_VOLUME);52
SetSoundVolume(game->assets.lose, GAME_SOUND_VOLUME);53
SetSoundVolume(game->assets.locked, GAME_SOUND_VOLUME);54
return game;55
}57
void game_update(game_t *game) {58
bool do_toggle_mute = false;59
if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) {60
pos_t mouse_pos = GetMousePosition();61
rect_t mouse_rect = {62
.x = mouse_pos.x,63
.y = mouse_pos.y,64
.width = 1,65
.height = 1,66
};67
rect_t mute_button_rect = {68
.x = TILE_WIDTH / 2.0,69
.y = WINDOW_HEIGHT - TILE_HEIGHT - TILE_HEIGHT / 2.0,70
.width = TILE_WIDTH,71
.height = TILE_HEIGHT,72
};73
rect_t pause_button_rect = {74
.x = WINDOW_WIDTH - TILE_WIDTH - TILE_WIDTH / 2.0,75
.y = WINDOW_HEIGHT - TILE_HEIGHT - TILE_HEIGHT / 2.0,76
.width = TILE_WIDTH,77
.height = TILE_HEIGHT,78
};79
if (rect_collide(mouse_rect, mute_button_rect)) {80
do_toggle_mute = true;81
}82
if (!game->victory && !game->defeat) {83
if (rect_collide(mouse_rect, pause_button_rect)) {84
switch (game->state) {85
case STATE_GAME:86
game->state = STATE_MENU;87
break;88
case STATE_MENU:89
game->state = STATE_GAME;90
break;91
}92
}93
}94
}95
if (IsKeyPressed(KEY_M)) {96
do_toggle_mute = true;97
}98
if (do_toggle_mute) {99
game->is_muted = !game->is_muted;100
if (game->is_muted) {101
SetSoundVolume(game->assets.track, 0.0f);102
SetSoundVolume(game->assets.win, 0.0f);103
SetSoundVolume(game->assets.lose, 0.0f);104
SetSoundVolume(game->assets.locked, 0.0f);105
}106
else {107
SetSoundVolume(game->assets.track, GAME_MUSIC_VOLUME);108
SetSoundVolume(game->assets.win, GAME_SOUND_VOLUME);109
SetSoundVolume(game->assets.lose, GAME_SOUND_VOLUME);110
SetSoundVolume(game->assets.locked, GAME_SOUND_VOLUME);111
}112
}113
if (!IsSoundPlaying(game->assets.track) && !game->victory && !game->defeat) {114
PlaySound(game->assets.track);115
}116
switch (game->state) {117
case STATE_MENU: {118
menu_update(game->menu, game);119
break;120
}121
case STATE_GAME: {122
if (!game->victory && !game->defeat) {123
if (IsKeyPressed(KEY_ESCAPE)) {124
game->state = STATE_MENU;125
game->menu->idx = 0;126
}127
}128
if (game->level != NULL) {129
// defeat130
if (game->defeat) {131
if (game->sceen_timer == 0) {132
StopSound(game->assets.track);133
}134
if (game->sceen_timer == 20) {135
PlaySound(game->assets.lose);136
}137
if (game->sceen_timer == GAME_SCEEN_TIMER) {138
level_e level = game->level->type;139
int max_health = game->player->max_health;140
max_health -= 2;141
if (max_health <= 0) {142
level = LEVEL_1;143
max_health = PLAYER_MAX_HEALTH;144
}145
level_unload(game);146
level_load(game, level);147
game->player->max_health = max_health;148
game->player->health = max_health;149
game->defeat = false;150
game->xp = 0;151
game->sceen_timer = 0;152
}153
else {154
game->sceen_timer++;155
}156
}157
// victory158
if (game->victory) {159
if (game->sceen_timer == 0) {160
StopSound(game->assets.track);161
}162
if (game->sceen_timer == 20) {163
PlaySound(game->assets.win);164
}165
if (game->sceen_timer == GAME_SCEEN_TIMER) {166
if (game->level->type < LEVELS) {167
level_e level = game->level->type;168
int max_health = game->player->max_health;169
level++;170
level_unload(game);171
level_load(game, level);172
game->player->max_health = max_health;173
game->player->health = max_health;174
}175
game->victory = false;176
game->sceen_timer = 0;177
}178
else {179
if (game->sceen_timer == 125) {180
game->door->is_locked = true;181
}182
game->sceen_timer++;183
}184
}185
if (!game->victory && !game->defeat) {186
player_update(game->player, game);187
}188
for (int i = 0; i < game->tiles_len; i++) {189
tile_update(game->tiles[i], game);190
}191
for (int i = 0; i < game->entities_len; i++) {192
int len = game->entities_len;193
entity_update(&game->entities[i], game);194
// check if entity was removed195
if (game->entities_len < len) {196
i--;197
}198
}199
for (int i = 0; i < game->effects_len; i++) {200
int len = game->effects_len;201
effect_update(game->effects[i], game);202
// check if enemy was removed203
if (game->effects_len < len) {204
i--;205
}206
}207
pos_t camera_pos = (pos_t) {208
.x = WINDOW_WIDTH / 2.0 - game->player->pos.x - PLAYER_WIDTH / 2.0,209
.y = WINDOW_HEIGHT / 2.0 - game->player->pos.y,210
};211
if (camera_pos.x > 0.0) {212
camera_pos.x = 0.0;213
}214
if (camera_pos.x + TILE_WIDTH * game->level->width < WINDOW_WIDTH) {215
camera_pos.x = WINDOW_WIDTH - TILE_WIDTH * game->level->width;216
}217
if (camera_pos.y > 0.0) {218
camera_pos.y = 0.0;219
}220
if (camera_pos.y + TILE_HEIGHT * game->level->height < WINDOW_HEIGHT) {221
camera_pos.y = WINDOW_HEIGHT - TILE_HEIGHT * game->level->height;222
}223
game->camera.offset = pos_snap(camera_pos);224
}225
break;226
}227
}228
}230
void game_draw(game_t *game) {231
// render overlay232
BeginTextureMode(game->overlay);233
ClearBackground(BLACK);234
DrawRectangle(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, BLACK);235
BeginBlendMode(BLEND_SUBTRACT_COLORS);236
int radius = WINDOW_WIDTH;237
radius -= radius / 80.0 * game->sceen_timer;238
if (radius < PLAYER_HEIGHT) {239
radius = PLAYER_HEIGHT;240
}241
DrawCircle(game->player->pos.x + PLAYER_WIDTH / 2.0, WINDOW_HEIGHT - (game->player->pos.y + PLAYER_HEIGHT / 2.0), radius, WHITE);242
EndBlendMode();243
EndTextureMode();244
// render sceen245
BeginDrawing();246
ClearBackground((Color) { 5, 5, 5, 255 });247
if (game->level != LEVEL_NULL) {248
BeginMode2D(game->camera);249
for (int i = 0; i < game->tiles_len; i++) {250
tile_draw(game->tiles[i], game);251
}252
for (int i = 0; i < game->entities_len; i++) {253
entity_t *entity = &game->entities[i];254
if (entity->type == ENTITY_GATE || entity->type == ENTITY_DOOR) {255
entity_draw(entity, game);256
}257
}258
for (int i = 0; i < game->entities_len; i++) {259
entity_t *entity = &game->entities[i];260
if (entity->type != ENTITY_GATE && entity->type != ENTITY_DOOR) {261
entity_draw(entity, game);262
}263
}264
if (game->sceen_timer < 100) {265
player_draw(game->player, game);266
}267
for (int i = 0; i < game->effects_len; i++) {268
effect_draw(game->effects[i], game);269
}270
// draw overlay271
DrawTexture(game->overlay.texture, 0, 0, WHITE);272
EndMode2D();273
// draw interface274
int i = 0;275
for (i = 0; i < game->player->health / 2; i++) {276
DrawTextureRec(game->assets.tiles, texture_rect(0, 1, TILE_WIDTH, TILE_HEIGHT), (pos_t) { TILE_WIDTH / 2.0 + i * (TILE_WIDTH + TILE_WIDTH / 4.0), TILE_WIDTH / 2.0 }, WHITE);277
}278
if (game->player->health % 2 != 0) {279
DrawTextureRec(game->assets.tiles, texture_rect(1, 1, TILE_WIDTH, TILE_HEIGHT), (pos_t) { TILE_WIDTH / 2.0 + i * (TILE_WIDTH + TILE_WIDTH / 4.0), TILE_WIDTH / 2.0 }, WHITE);280
i++;281
}282
for (; i < game->player->max_health / 2; i++) {283
DrawTextureRec(game->assets.tiles, texture_rect(2, 1, TILE_WIDTH, TILE_HEIGHT), (pos_t) { TILE_WIDTH / 2.0 + i * (TILE_WIDTH + TILE_WIDTH / 4.0), TILE_WIDTH / 2.0 }, WHITE);284
}285
char xp_text[10];286
snprintf(xp_text, 10, "%dXP", game->xp);287
pos_t xp_pos = (pos_t) {288
.x = WINDOW_WIDTH - TILE_WIDTH / 2.0,289
.y = TILE_WIDTH / 1.5,290
};291
text_draw(xp_pos, xp_text, TEXT_ALIGNMENT_RIGHT, game);292
char level_text[10];293
snprintf(level_text, 10, "L%d", game->level->type);294
pos_t level_pos = (pos_t) {295
.x = WINDOW_WIDTH - TILE_WIDTH / 2.0,296
.y = TILE_WIDTH / 1.5 + 25,297
};298
text_draw(level_pos, level_text, TEXT_ALIGNMENT_RIGHT, game);299
}300
if (game->state == STATE_MENU) {301
menu_draw(game->menu, game);302
}303
if (game->is_muted) {304
DrawTextureRec(game->assets.tiles, texture_rect(5, 1, TILE_WIDTH, TILE_HEIGHT), (pos_t) { TILE_WIDTH / 2.0, WINDOW_HEIGHT - TILE_HEIGHT - TILE_HEIGHT / 2.0 }, WHITE);305
}306
else {307
DrawTextureRec(game->assets.tiles, texture_rect(4, 1, TILE_WIDTH, TILE_HEIGHT), (pos_t) { TILE_WIDTH / 2.0, WINDOW_HEIGHT - TILE_HEIGHT - TILE_HEIGHT / 2.0 }, WHITE);308
}309
if (game->state == STATE_GAME) {310
if (game->victory || game->defeat) {311
DrawTextureRec(game->assets.tiles, texture_rect(8, 1, TILE_WIDTH, TILE_HEIGHT), (pos_t) { WINDOW_WIDTH - TILE_WIDTH - TILE_WIDTH / 2.0, WINDOW_HEIGHT - TILE_HEIGHT - TILE_HEIGHT / 2.0 }, WHITE);312
}313
else {314
DrawTextureRec(game->assets.tiles, texture_rect(6, 1, TILE_WIDTH, TILE_HEIGHT), (pos_t) { WINDOW_WIDTH - TILE_WIDTH - TILE_WIDTH / 2.0, WINDOW_HEIGHT - TILE_HEIGHT - TILE_HEIGHT / 2.0 }, WHITE);315
}316
}317
else {318
DrawTextureRec(game->assets.tiles, texture_rect(7, 1, TILE_WIDTH, TILE_HEIGHT), (pos_t) { WINDOW_WIDTH - TILE_WIDTH - TILE_WIDTH / 2.0, WINDOW_HEIGHT - TILE_HEIGHT - TILE_HEIGHT / 2.0 }, WHITE);319
}320
EndDrawing();321
}323
void game_free(game_t *game) {324
menu_free(game->menu);325
if (game->level != LEVEL_NULL) {326
level_unload(game);327
}328
UnloadTexture(game->assets.tiles);329
UnloadTexture(game->assets.entities);330
UnloadTexture(game->assets.font);331
UnloadTexture(game->assets.images);332
UnloadTexture(game->assets.background);333
UnloadSound(game->assets.track);334
UnloadSound(game->assets.win);335
UnloadSound(game->assets.lose);336
UnloadSound(game->assets.locked);337
UnloadRenderTexture(game->overlay);338
free(game);339
}