dorianocacasorus/main.c

638 lines
19 KiB
C
Raw Permalink Normal View History

2025-06-03 09:27:07 +02:00
#include <stdio.h>
#include <string.h>
#include "raylib.h"
typedef struct Vec2i {
int x, y;
} Vec2i;
int vec2i_equals(Vec2i v1, Vec2i v2)
{
return v1.x == v2.x && v1.y == v2.y;
}
#include "maps.h"
#include "winfun.c"
typedef struct Shot {
int up, down, left, right;
} Shot;
#ifdef RELEASE
Vector2 window = {1920, 1080};
#else
2025-06-07 13:17:02 +02:00
Vector2 window = {900, 800};
2025-06-03 09:27:07 +02:00
#endif
#ifdef RELEASE
int in_menu = 1;
#else
int in_menu = 0;
#endif
int door_open = 0;
float level_finished = 0;
float alarme_sonne = 0;
float player_dead = 0;
float shoot_cooldown = 0;
float end_time_game = 0;
float begin_play_time = 0;
Texture tex_fond;
Texture tex_tuto_key;
Texture tex_tuto_space;
void draw_menu(void)
{
BeginDrawing();
ClearBackground(BLUE);
DrawTexturePro(tex_fond, (Rectangle){0,0,tex_fond.width,tex_fond.height}, (Rectangle){0,0,window.x,window.y}, (Vector2){0,0}, 0, WHITE);
const char *title = "DORIANOCACASORUS";
int size = 50;
int width = MeasureText(title, size);
DrawText(title, window.x/2-width/2, window.y/2-size/2, size, GOLD);
Vector2 mouse = GetMousePosition();
Rectangle button = {
.x = window.x/2-250,
.y = window.y*0.6,
.width = 500,
.height = 100,
};
Color button_color = GRAY;
if (CheckCollisionPointRec(mouse, button)) {
button_color = LIGHTGRAY;
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
in_menu = 0;
begin_play_time = GetTime();
#ifdef RELEASE
HideCursor();
DisableCursor();
#endif
}
}
DrawRectangleRec(button, button_color);
DrawText("PLAY", window.x/2-MeasureText("PLAY", size)/2, window.y*0.6+size/2, size, WHITE);
EndDrawing();
}
void draw_win(void)
{
BeginDrawing();
ClearBackground(DARKBLUE);
const char *title = "Étage réussie";
int size = 75;
int width = MeasureText(title, size);
DrawText(title, window.x/2-width/2, window.y/2-size/2, size, GOLD);
EndDrawing();
}
void draw_alarme_lose(void)
{
BeginDrawing();
ClearBackground(DARKBLUE);
const char *title = "L'alarme sonne";
int size = 75;
int width = MeasureText(title, size);
DrawText(title, window.x/2-width/2, window.y/2-size/2, size, VIOLET);
EndDrawing();
}
void draw_lose(void)
{
BeginDrawing();
ClearBackground(DARKBLUE);
const char *title = "Un guarde ta attraper";
int size = 75;
int width = MeasureText(title, size);
DrawText(title, window.x/2-width/2, window.y/2-size/2, size, RED);
EndDrawing();
}
void draw_end(void)
{
BeginDrawing();
ClearBackground(DARKBLUE);
const char *title = "GG ta finit le ju";
int size = 75;
int width = MeasureText(title, size);
DrawText(title, window.x/2-width/2, window.y/2-size/2, size, GOLD);
if (end_time_game < 0.1) end_time_game = GetTime()-begin_play_time;
title = TextFormat("temps: %d", (int)(end_time_game));
size = 50;
width = MeasureText(title, size);
DrawText(title, window.x/2-width/2, window.y/2+size, size, GOLD);
EndDrawing();
}
void draw_tuto(void)
{
int scale = 7;
int y_offset = 32;
int key_frame = 4;
Vec2i key_size = {32, 20};
int key_offset = ((int)(GetTime()*5)%key_frame)*key_size.x;
int space_frame = 2;
Vec2i space_size = {28, 13};
int space_offset = ((int)(GetTime()*5)%space_frame)*space_size.x;
DrawTexturePro(
tex_tuto_key,
(Rectangle) {key_offset, 0, key_size.x, key_size.y},
(Rectangle) {
window.x/2 - space_size.x*scale/2 - key_size.x*(scale+1)/2,
y_offset,
key_size.x*scale,
key_size.y*scale
},
(Vector2) {0, 0},
0, WHITE
);
DrawTexturePro(
tex_tuto_space,
(Rectangle) {space_offset, 0, space_size.x, space_size.y},
(Rectangle) {
window.x/2 - space_size.x*scale/2 + key_size.x*(scale+1)/2,
y_offset + key_size.y*scale - space_size.y*scale,
space_size.x*scale,
space_size.y*scale
},
(Vector2) {0, 0},
0, WHITE
);
}
Vec2i find_player(Map map, Vec2i map_size)
{
for (int x=0; x<map_size.x; x++) {
for (int y=0; y<map_size.y; y++) {
if (map[y][x] == 'S') {
return (Vec2i){x, y};
}
}
}
return (Vec2i){0, 0};
}
void load_map(Map *map, Vec2i *map_size, int etage)
{
door_open = 0;
*map_size = map_sizes[etage];
2025-06-05 14:42:49 +02:00
memcpy(map, maps[etage], MAP_SIZE_MAX*MAP_SIZE_MAX);
2025-06-03 09:27:07 +02:00
for (int g=0; g<MAX_GUARD_ETAGE; g++) {
Guard guard = guards[etage][g];
if (guard.start.x == guard.end.x && guard.start.y == guard.end.y) {
guards[etage][g].dead = 1;
continue;
}
if (guard.start.x == guard.end.x && guard.start.y < guard.end .y) guards[etage][g].dir = BAS;
if (guard.start.x == guard.end.x && guard.start.y > guard.end .y) guards[etage][g].dir = HAUT;
if (guard.start.x < guard.end.x && guard.start.y == guard.end .y) guards[etage][g].dir = DROITE;
if (guard.start.x > guard.end.x && guard.start.y == guard.end .y) guards[etage][g].dir = GAUCHE;
guards[etage][g].pos = guard.start;
guards[etage][g].dead = 0;
}
}
int update_player_move(Map map, Vec2i map_size)
{
Vec2i old_pos = find_player(map, map_size);
Vec2i new_pos = old_pos;
if (IsKeyPressed(KEY_LEFT)) new_pos.x--;
if (IsKeyPressed(KEY_RIGHT)) new_pos.x++;
if (IsKeyPressed(KEY_DOWN)) new_pos.y++;
if (IsKeyPressed(KEY_UP)) new_pos.y--;
if (
new_pos.x < 0 ||
new_pos.y < 0 ||
new_pos.x >= map_size.x ||
new_pos.y >= map_size.y
) return 0;
if (door_open && map[new_pos.y][new_pos.x] == 'P') {
level_finished = 1.2;
etage++;
}
for (int g=0; g<MAX_GUARD_ETAGE; g++) {
Guard guard = guards[etage][g];
if (!guard.dead && vec2i_equals(guard.pos, new_pos)) return 0;
}
if (map[new_pos.y][new_pos.x] == ' ') {
map[new_pos.y][new_pos.x] = 'S';
map[old_pos.y][old_pos.x] = ' ';
return 1;
}
return 0;
}
void update_guard_pos(void)
{
for (int g=0; g<MAX_GUARD_ETAGE; g++) {
Guard *guard = &guards[etage][g];
if (guard->dead) continue;
switch (guard->dir) {
case HAUT: guard->pos.y--; break;
case BAS: guard->pos.y++; break;
case GAUCHE: guard->pos.x--; break;
case DROITE: guard->pos.x++; break;
}
if (vec2i_equals(guard->pos, guard->start) || vec2i_equals(guard->pos, guard->end)) {
switch (guard->dir) {
case HAUT: guard->dir = BAS; break;
case BAS: guard->dir = HAUT; break;
case GAUCHE: guard->dir = DROITE; break;
case DROITE: guard->dir = GAUCHE; break;
}
}
}
}
void check_player_dead(Map map, Vec2i map_size)
{
Vec2i player = find_player(map, map_size);
for (int g=0; g<MAX_GUARD_ETAGE; g++) {
Guard guard = guards[etage][g];
if (!guard.dead && vec2i_equals(player, guard.pos)) {
player_dead = 1.2;
return;
}
}
for (int x=player.x; x<map_size.x; x++) {
if (map[player.y][x] != ' ' && map[player.y][x] != 'S') break;
for (int g=0; g<MAX_GUARD_ETAGE; g++) {
Guard guard = guards[etage][g];
if (!guard.dead && guard.dir != DROITE && vec2i_equals((Vec2i){x, player.y}, guard.pos)) {
player_dead = 1.2;
return;
}
}
}
for (int x=player.x; x>=0; x--) {
if (map[player.y][x] != ' ' && map[player.y][x] != 'S') break;
for (int g=0; g<MAX_GUARD_ETAGE; g++) {
Guard guard = guards[etage][g];
if (!guard.dead && guard.dir != GAUCHE && vec2i_equals((Vec2i){x, player.y}, guard.pos)) {
player_dead = 1.2;
return;
}
}
}
for (int y=player.y; y<map_size.y; y++) {
if (map[y][player.x] != ' ' && map[y][player.x] != 'S') break;
for (int g=0; g<MAX_GUARD_ETAGE; g++) {
Guard guard = guards[etage][g];
if (!guard.dead && guard.dir != BAS && vec2i_equals((Vec2i){player.x, y}, guard.pos)) {
player_dead = 1.2;
return;
}
}
}
for (int y=player.y; y>=0; y--) {
if (map[y][player.x] != ' ' && map[y][player.x] != 'S') break;
for (int g=0; g<MAX_GUARD_ETAGE; g++) {
Guard guard = guards[etage][g];
if (!guard.dead && guard.dir != HAUT && vec2i_equals((Vec2i){player.x, y}, guard.pos)) {
player_dead = 1.2;
return;
}
}
}
}
int kill(Map map, Vec2i pos)
{
int killed = 1;
switch (map[pos.y][pos.x]) {
case 'G':
map[pos.y][pos.x] = ' ';
break;
case 'O':
map[pos.y][pos.x] = ' ';
break;
case 'B':
map[pos.y][pos.x] = ' ';
door_open = 1;
break;
2025-06-10 23:19:47 +02:00
case 'P': case 'E':
killed = 1;
break;
2025-06-03 09:27:07 +02:00
case 'A':
map[pos.y][pos.x] = ' ';
alarme_sonne = 1.2;
shoot_cooldown = 0;
break;
default:
killed = 0;
break;
}
for (int g=0; g<MAX_GUARD_ETAGE; g++) {
Guard guard = guards[etage][g];
if (!guard.dead && vec2i_equals(pos, guard.pos)) {
guards[etage][g].dead = 1;
return 1;
}
}
return killed;
}
Shot shoot(Map map, Vec2i map_size, Vec2i from)
{
Shot shot;
int up = from.y;
for (; up>0 && map[up-1][from.x] != 'M'; up--)
if (kill(map, (Vec2i){from.x, up-1})) break;
shot.up = up;
int down = from.y;
for (; down<map_size.y-1 && map[down+1][from.x] != 'M'; down++)
if (kill(map, (Vec2i){from.x, down+1})) break;
shot.down = down;
int left = from.x;
for (; left>0 && map[from.y][left-1] != 'M'; left--)
if (kill(map, (Vec2i){left-1, from.y})) break;
shot.left = left;
int right = from.x;
for (; right<map_size.x-1 && map[from.y][right+1] != 'M'; right++)
if (kill(map, (Vec2i){right+1, from.y})) break;
shot.right = right;
return shot;
}
int main(void)
{
#ifdef RELEASE
SetTraceLogLevel(LOG_FATAL);
#endif
SetRandomSeed(69);
InitWindow(window.x, window.y, "DIRANOCACASORUS");
#ifdef RELEASE
SetWindowState(FLAG_FULLSCREEN_MODE);
#else
SetWindowState(FLAG_WINDOW_RESIZABLE);
#endif
SetTargetFPS(60);
#ifdef RELEASE
#include "assets/fond.h"
Image img_fond = LoadImageFromMemory(".png", menufond_data, menufond_size);
tex_fond = LoadTextureFromImage(img_fond);
#else
tex_fond = LoadTexture("assets/fond.png");
#endif
InitAudioDevice();
#ifdef RELEASE
#include "assets/bittersweet.h"
Wave wave_musique = LoadWaveFromMemory(".mp3", musique_data, musique_size);
Sound musique = LoadSoundFromWave(wave_musique);
#else
Sound musique = LoadSound("assets/bittersweet.mp3");
#endif
PlaySound(musique);
Vec2i map_size;
Map map;
load_map(&map, &map_size, etage);
#ifdef RELEASE
#include "assets/Keyboard_Arrows.h"
Image img_tuto_key = LoadImageFromMemory(".png", tuto_key_data, tuto_key_size);
tex_tuto_key = LoadTextureFromImage(img_tuto_key);
#include "assets/Keyboard_Space.h"
Image img_tuto_space = LoadImageFromMemory(".png", tuto_space_data, tuto_space_size);
tex_tuto_space = LoadTextureFromImage(img_tuto_space);
#else
tex_tuto_key = LoadTexture("assets/Keyboard_Arrows.png");
tex_tuto_space = LoadTexture("assets/Keyboard_Space.png");
#endif
while (!WindowShouldClose()) {
if (IsWindowResized()) {
window.x = GetScreenWidth();
window.y = GetScreenHeight();
}
if (!IsSoundPlaying(musique)) PlaySound(musique);
if (in_menu) {
draw_menu();
continue;
}
2025-06-07 13:17:02 +02:00
if (alarme_sonne > 0 && etage < NB_ETAGE_TOTAL) {
2025-06-03 09:27:07 +02:00
alarme_sonne -= GetFrameTime();
load_map(&map, &map_size, etage); // NOTE: memcpy pendant 1.2s mais flemme
draw_alarme_lose();
continue;
}
2025-06-07 13:17:02 +02:00
if (player_dead > 0 && etage < NB_ETAGE_TOTAL) {
2025-06-03 09:27:07 +02:00
player_dead -= GetFrameTime();
load_map(&map, &map_size, etage); // NOTE: memcpy pendant 1.2s mais flemme
draw_lose();
continue;
}
Vec2i player_pos = find_player(map, map_size);
static Shot shot;
if (IsKeyPressed(KEY_SPACE)) {
shoot_cooldown = 0.12;
shot = shoot(map, map_size, player_pos);
update_guard_pos();
}
check_player_dead(map, map_size);
if (shoot_cooldown > 0) {
shoot_cooldown -= GetFrameTime();
}
if (shoot_cooldown <= 0) {
int moved = update_player_move(map, map_size);
if (moved) {
update_guard_pos();
}
}
if (level_finished > 0) {
level_finished -= GetFrameTime();
load_map(&map, &map_size, etage); // NOTE: memcpy pendant 1.2s mais flemme
draw_win();
continue;
}
if (level_finished > -2.7 && etage >= NB_ETAGE_TOTAL) {
level_finished -= GetFrameTime();
draw_end();
continue;
}
2025-06-03 12:47:41 +02:00
if (IsKeyDown(KEY_LEFT_SHIFT) && IsKeyDown(KEY_LEFT_CONTROL) && IsKeyDown(KEY_E)) etage = NB_ETAGE_TOTAL + 69;
2025-06-03 09:27:07 +02:00
if (etage >= NB_ETAGE_TOTAL) {
win_fun();
continue;
}
BeginDrawing();
ClearBackground(DARKBLUE);
if (etage == 0) {
draw_tuto();
}
int mult = 50;
int size = 50;
Vec2i offset;
offset.x = window.x/2 - map_size.x*size/2;
offset.y = window.y/2 - map_size.y*size/2;
for (int x=0; x<map_size.x; x++) {
for (int y=0; y<map_size.y; y++) {
int is_danger = 0;
for (int g=0; g<MAX_GUARD_ETAGE; g++) {
Guard guard = guards[etage][g];
if (guard.dead) continue;
Vec2i pos = {x,y};
if (vec2i_equals(pos, guard.pos)) goto skip;
if (vec2i_equals(pos, guard.start) && !vec2i_equals(pos, guard.start)) goto skip;
if (vec2i_equals(pos, guard.end) && !vec2i_equals(pos, guard.end)) goto skip;
if (pos.x == guard.pos.x) {
if (pos.y > guard.pos.y && guard.dir == HAUT) continue;
if (pos.y < guard.pos.y && guard.dir == BAS) continue;
int min = pos.y < guard.pos.y ? pos.y : guard.pos.y;
int max = pos.y > guard.pos.y ? pos.y : guard.pos.y;
int walled = 0;
for (int i=min; i<max; i++) {
2025-06-10 23:19:47 +02:00
if (map[i][x] != ' ') {
2025-06-03 09:27:07 +02:00
walled = 1;
break;
}
}
if (!walled) is_danger = 1;
}
else if (pos.y == guard.pos.y) {
if (pos.x > guard.pos.x && guard.dir == GAUCHE) continue;
if (pos.x < guard.pos.x && guard.dir == DROITE) continue;
int min = pos.x < guard.pos.x ? pos.x : guard.pos.x;
int max = pos.x > guard.pos.x ? pos.x : guard.pos.x;
int walled = 0;
for (int i=min; i<max; i++) {
2025-06-10 23:19:47 +02:00
if (map[y][i] != ' ') {
2025-06-03 09:27:07 +02:00
walled = 1;
break;
}
}
if (!walled) is_danger = 1;
}
}
switch (map[y][x]) {
case 'M':
DrawText("M", offset.x+x*mult, offset.y+y*mult, size, GOLD);
break;
case 'O':
DrawText("O", offset.x+x*mult, offset.y+y*mult, size, YELLOW);
break;
case 'P':
if (!door_open) DrawText("P", offset.x+x*mult, offset.y+y*mult, size, BLACK);
else DrawText("E", offset.x+x*mult, offset.y+y*mult, size, LIME);
break;
case 'B':
DrawText("B", offset.x+x*mult, offset.y+y*mult, size, WHITE);
break;
case 'S':
DrawText("S", offset.x+x*mult, offset.y+y*mult, size, GREEN);
break;
case 'G':
DrawText("G", offset.x+x*mult, offset.y+y*mult, size, RED);
break;
case 'A':
DrawText("A", offset.x+x*mult, offset.y+y*mult, size, VIOLET);
break;
default:
DrawText("-", offset.x+x*mult, offset.y+y*mult, size, is_danger?RED:WHITE);
break;
}
skip:
}
}
for (int i = 0; i < MAX_GUARD_ETAGE; i++) {
Guard guard = guards[etage][i];
if (guard.dead) continue;
DrawText("G", offset.x+guard.pos.x*mult, offset.y+guard.pos.y*mult, size, RED);
int to_end = 0;
switch (guard.dir) {
case HAUT: to_end = guard.pos.y <= guard.end.y; break;
case BAS: to_end = guard.pos.y > guard.end.y; break;
case GAUCHE: to_end = guard.pos.x <= guard.end.x; break;
case DROITE: to_end = guard.pos.x > guard.end.x; break;
}
if (!vec2i_equals(guard.pos, guard.start) && !vec2i_equals(guard.start, player_pos))
DrawText("+", offset.x+guard.start.x*mult, offset.y+guard.start.y*mult, size, !to_end?RED:ORANGE);
if (!vec2i_equals(guard.pos, guard.end) && !vec2i_equals(guard.end, player_pos))
DrawText("+", offset.x+guard.end.x*mult, offset.y+guard.end.y*mult, size, to_end?RED:ORANGE);
}
if (shoot_cooldown > 0) {
int up = shot.up;
int down = shot.down;
int left = shot.left;
int rigth = shot.right;
if (up != player_pos.y) for (int i=player_pos.y-1; i>=up; i--) DrawText("@", offset.x+player_pos.x*mult, offset.y+i*mult, size, ORANGE);
if (down != player_pos.y) for (int i=player_pos.y+1; i<=down; i++) DrawText("@", offset.x+player_pos.x*mult, offset.y+i*mult, size, ORANGE);
if (left != player_pos.x) for (int i=player_pos.x-1; i>=left; i--) DrawText("@", offset.x+i*mult, offset.y+player_pos.y*mult, size, ORANGE);
if (rigth != player_pos.x) for (int i=player_pos.x+1; i<=rigth; i++) DrawText("@", offset.x+i*mult, offset.y+player_pos.y*mult, size, ORANGE);
}
DrawText(TextFormat("Étage %d/%d", etage+1, NB_ETAGE_TOTAL), 10, 10, size/2, RAYWHITE);
DrawText(TextFormat("Timer: %d", (int)(GetTime()-begin_play_time)), 10, 20+size/2, size/2, RAYWHITE);
EndDrawing();
}
}