219 lines
6.8 KiB
C
219 lines
6.8 KiB
C
#include <curses.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include "world.h"
|
|
#include "game.h"
|
|
|
|
// Helper function to get a random position within bounds
|
|
// Returns 1 if position is valid, 0 if we can't find a distinct position
|
|
static int get_random_position(int* x, int* y, int width, int height,
|
|
int cat_x, int cat_y,
|
|
int* existing_x, int* existing_y, int existing_count) {
|
|
// Leave 1 cell for border
|
|
int min_x = 1;
|
|
int max_x = width - 2;
|
|
int min_y = 1;
|
|
int max_y = height - 2;
|
|
|
|
int attempts = 0;
|
|
while (attempts < 100) {
|
|
*x = min_x + rand() % (max_x - min_x + 1);
|
|
*y = min_y + rand() % (max_y - min_y + 1);
|
|
|
|
// Check if position is distinct from cat
|
|
if (*x == cat_x && *y == cat_y) {
|
|
attempts++;
|
|
continue;
|
|
}
|
|
|
|
// Check if position is distinct from other entities
|
|
int distinct = 1;
|
|
for (int i = 0; i < existing_count; i++) {
|
|
if (*x == existing_x[i] && *y == existing_y[i]) {
|
|
distinct = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (distinct) {
|
|
return 1;
|
|
}
|
|
attempts++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Initialize the game state
|
|
void* init_game() {
|
|
// Allocate memory for the game state
|
|
struct game* state = calloc(1, sizeof(struct game));
|
|
|
|
if (state == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
// Use current time for random seed (more random than time(NULL) alone)
|
|
srand((unsigned int)time(NULL) + rand());
|
|
|
|
// Initial state values
|
|
state->score = 0;
|
|
strcpy(state->message, "");
|
|
|
|
// Place cat at a random position (leaving room for border)
|
|
state->cat_x = 5 + rand() % 20;
|
|
state->cat_y = 2 + rand() % 15;
|
|
|
|
// Place 5 mice at distinct random positions
|
|
for (int i = 0; i < MOUSE_COUNT; i++) {
|
|
int px, py;
|
|
get_random_position(&px, &py, 30, 20, state->cat_x, state->cat_y,
|
|
state->mouse_x, state->mouse_y, i);
|
|
state->mouse_x[i] = px;
|
|
state->mouse_y[i] = py;
|
|
state->mouse_alive[i] = 1; // All mice start alive
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
// Draw the game state on screen
|
|
static void draw_game(struct game* state, struct event* event) {
|
|
// Clear screen
|
|
clear_screen();
|
|
|
|
// Draw border around the playing field (using walls: '#' in cyan)
|
|
// Top and bottom borders
|
|
for (int x = 0; x < event->width; x++) {
|
|
set_color_cell('#', x, 0, COLOR_CYAN, COLOR_BLACK);
|
|
set_color_cell('#', x, event->height - 1, COLOR_CYAN, COLOR_BLACK);
|
|
}
|
|
|
|
// Left and right borders
|
|
for (int y = 1; y < event->height - 1; y++) {
|
|
set_color_cell('#', 0, y, COLOR_CYAN, COLOR_BLACK);
|
|
set_color_cell('#', event->width - 1, y, COLOR_CYAN, COLOR_BLACK);
|
|
}
|
|
|
|
// Draw cat in yellow
|
|
set_color_cell('c', state->cat_x, state->cat_y, COLOR_YELLOW, COLOR_BLACK);
|
|
|
|
// Draw alive mice in green
|
|
for (int i = 0; i < MOUSE_COUNT; i++) {
|
|
if (state->mouse_alive[i]) {
|
|
set_color_cell('m', state->mouse_x[i], state->mouse_y[i], COLOR_GREEN, COLOR_BLACK);
|
|
}
|
|
}
|
|
|
|
// Display score
|
|
char score_msg[50];
|
|
snprintf(score_msg, sizeof(score_msg), "Score: %d/5", state->score);
|
|
set_message(score_msg, 2, event->height - 2);
|
|
|
|
// Display end-game message if game is won
|
|
if (state->game_won) {
|
|
set_message(state->message, (event->width - 40) / 2, event->height / 2);
|
|
}
|
|
}
|
|
|
|
// Handle game events
|
|
int game_event(struct event* event, void* game) {
|
|
struct game* state = (struct game*)game;
|
|
|
|
// Handle ESC key to quit
|
|
if (event->type == EVENT_ESC) {
|
|
return 1; // Non-zero means end the game
|
|
}
|
|
|
|
// Handle keyboard input (arrow keys to move cat)
|
|
if (event->type == EVENT_KEY) {
|
|
if (event->key == KEY_UP) {
|
|
int new_y = state->cat_y - 1;
|
|
// Clamp to walls (1 inside border, event->height-2 is last valid position)
|
|
if (new_y > 0) {
|
|
state->cat_y = new_y;
|
|
}
|
|
} else if (event->key == KEY_DOWN) {
|
|
int new_y = state->cat_y + 1;
|
|
if (new_y < event->height - 1) {
|
|
state->cat_y = new_y;
|
|
}
|
|
} else if (event->key == KEY_LEFT) {
|
|
int new_x = state->cat_x - 1;
|
|
if (new_x > 0) {
|
|
state->cat_x = new_x;
|
|
}
|
|
} else if (event->key == KEY_RIGHT) {
|
|
int new_x = state->cat_x + 1;
|
|
if (new_x < event->width - 1) {
|
|
state->cat_x = new_x;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle timer tick (move mice)
|
|
if (event->type == EVENT_TIMEOUT) {
|
|
for (int i = 0; i < MOUSE_COUNT; i++) {
|
|
if (state->mouse_alive[i]) {
|
|
// Random direction: 0=up, 1=down, 2=left, 3=right, 4=stay
|
|
int direction = rand() % 5;
|
|
|
|
int new_x = state->mouse_x[i];
|
|
int new_y = state->mouse_y[i];
|
|
|
|
if (direction == 0) { // Up
|
|
new_y = state->mouse_y[i] - 1;
|
|
} else if (direction == 1) { // Down
|
|
new_y = state->mouse_y[i] + 1;
|
|
} else if (direction == 2) { // Left
|
|
new_x = state->mouse_x[i] - 1;
|
|
} else if (direction == 3) { // Right
|
|
new_x = state->mouse_x[i] + 1;
|
|
}
|
|
// direction 4 means stay (no change to new_x, new_y)
|
|
|
|
// Clamp mouse to walls
|
|
if (new_x > 0 && new_x < event->width - 1) {
|
|
state->mouse_x[i] = new_x;
|
|
}
|
|
if (new_y > 0 && new_y < event->height - 1) {
|
|
state->mouse_y[i] = new_y;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check collision: cat catches mouse
|
|
for (int i = 0; i < MOUSE_COUNT; i++) {
|
|
if (state->mouse_alive[i] &&
|
|
state->cat_x == state->mouse_x[i] &&
|
|
state->cat_y == state->mouse_y[i]) {
|
|
state->mouse_alive[i] = 0; // Mark mouse as eaten
|
|
state->score++;
|
|
}
|
|
}
|
|
|
|
// Check if all mice are caught (game won)
|
|
if (state->score == MOUSE_COUNT && !state->game_won) {
|
|
strcpy(state->message, "Zlapil si vsetky mysky! Lusty macko! :-D");
|
|
state->game_won = 1;
|
|
state->win_tick = 0;
|
|
}
|
|
|
|
// If game is won, display message and eventually exit
|
|
if (state->game_won) {
|
|
state->win_tick++;
|
|
draw_game(state, event);
|
|
// After 30 frames (~3 seconds at 10fps), exit
|
|
if (state->win_tick > 30) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Draw the current game state
|
|
draw_game(state, event);
|
|
|
|
return 0; // Continue the game
|
|
}
|