#include <stdio.h>
-#include <stdbool.h>
#include <stdlib.h>
-#include <stddef.h>
#include <unistd.h>
#include <assert.h>
#include <ctype.h>
#include <termios.h>
#include <math.h>
#include <pthread.h>
+#include <string.h>
#include "game.h"
-#define MAKEBUF(type) type *buf = malloc(sizeof(type)); *buf = arg;
/* Shared variables */
-struct color black = {0, 0, 0};
+struct color black = {0};
struct material wall;
struct material air;
struct node map[MAP_WIDTH][MAP_HEIGHT];
-struct entity player;
struct list *entities = & (struct list) {
.element = &player,
.next = NULL,
return a < b ? a : b;
}
+void *make_buffer(void *ptr, size_t size)
+{
+ void *buf = malloc(size);
+ memcpy(buf, ptr, size);
+
+ return buf;
+}
+
/* Game-related utility functions */
void quit()
/* Register callback functions */
-void register_air_function(struct generator_function arg)
+void register_air_function(struct generator_function func)
{
- MAKEBUF(struct generator_function);
- air_functions = add_element(air_functions, buf);
+ air_functions = add_element(air_functions, make_buffer(&func, sizeof(struct generator_function)));
}
-void register_input_handler(unsigned char c, struct input_handler arg)
+void register_input_handler(unsigned char c, struct input_handler handler)
{
if (input_handlers[c])
return;
- MAKEBUF(struct input_handler);
- input_handlers[c] = buf;
+ input_handlers[c] = make_buffer(&handler, sizeof(struct input_handler));
}
-void register_render_component(void (*arg)(struct winsize ws))
+void register_render_component(void (*callback)(struct winsize ws))
{
- render_components = add_element(render_components, arg);
+ render_components = add_element(render_components, callback);
};
/* Player */
damage_overlay += (double) damage * 0.5;
}
+struct entity player = {
+ .name = "player",
+ .x = MAP_WIDTH / 2,
+ .y = MAP_HEIGHT / 2,
+ .color = {0},
+ .use_color = false,
+ .texture = "🙂",
+ .remove = false,
+ .meta = NULL,
+ .health = 10,
+ .max_health = 10,
+ .collide_with_entities = true,
+
+ .on_step = NULL,
+ .on_collide = NULL,
+ .on_collide_with_entity = NULL,
+ .on_spawn = NULL,
+ .on_remove = NULL,
+ .on_death = &player_death,
+ .on_damage = &player_damage,
+};
+
/* Mapgen */
+static void mapgen_set_air(int x, int y)
+{
+ if (is_outside(x, y))
+ return;
+
+ if (map[x][y].material == &air)
+ return;
+
+ map[x][y] = (struct node) {&air};
+
+ for (struct list *ptr = air_functions; ptr != NULL; ptr = ptr->next) {
+ struct generator_function *func = ptr->element;
+
+ if (rand() % func->chance == 0)
+ func->callback(x, y);
+ }
+}
+
+static void generate_room(int origin_x, int origin_y)
+{
+ int left = 5 + rand() % 10;
+ int right = 5 + rand() % 10;
+
+ int up = 0;
+ int down = 0;
+
+ for (int x = -left; x <= right; x++) {
+ if (x < 0) {
+ up += rand() % 2;
+ down += rand() % 2;
+ } else {
+ up -= rand() % 2;
+ down -= rand() % 2;
+ }
+
+ for (int y = -up; y <= down; y++)
+ mapgen_set_air(origin_x + x, origin_y + y);
+ }
+}
+
static bool check_direction(int x, int y, enum direction dir)
{
if (dir % 2 == 0)
if (is_outside(lx, ly))
return;
- map[lx][ly] = (struct node) {&air};
-
- for (struct list *ptr = air_functions; ptr != NULL; ptr = ptr->next) {
- struct generator_function *func = ptr->element;
-
- if (! func->chance || rand() % func->chance == 0) {
- func->callback(lx, ly);
- }
+ if (rand() % 200 == 0) {
+ generate_room(lx, ly);
+ return;
}
+ mapgen_set_air(lx, ly);
+
int x, y;
enum direction dir;
/* Rendering */
-static bool render_color(struct color color, double light, bool bg)
+static bool render_color(struct color color, double light, bool bg, bool use_color)
{
if (light <= 0.0) {
set_color(black, bg);
return false;
- } else {
+ } else if (use_color) {
if (damage_overlay > 0.0)
mix_color(&color, damage_overlay_color, damage_overlay * 2.0);
set_color(color, bg);
return true;
+ } else {
+ return true;
}
}
double dist = sqrt(x * x + y * y);
double light = 1.0 - (double) dist / (double) LIGHT;
- render_color(node.material->color, light, true);
+ render_color(node.material->color, light, true, true);
struct entity *entity = render_entities[x + LIGHT][y + LIGHT];
render_entities[x + LIGHT][y + LIGHT] = NULL;
- if (entity && render_color(entity->color, light, false))
+ if (entity && render_color(entity->color, light, false, entity->use_color))
printf("%s", entity->texture);
else
printf(" ");
printf(" ");
}
- for (int i = 0; i < rows_left + 1; i++)
+ for (int i = 0; i < rows_left; i++)
for (int i = 0; i < ws.ws_col; i++)
printf(" ");
}
void game()
{
- srand(time(0));
-
struct sigaction sa;
sa.sa_handler = &handle_interrupt;
sigaction(SIGINT, &sa, NULL);
__attribute__ ((constructor)) static void init()
{
+ srand(time(0));
+
wall = (struct material) {
.solid = true,
.color = get_color("#5B2F00"),
.color = black,
};
- player = (struct entity) {
- .name = "player",
- .x = MAP_WIDTH / 2,
- .y = MAP_HEIGHT / 2,
- .color = get_color("#00FFFF"),
- .texture = "🙂",
- .remove = false,
- .meta = NULL,
- .health = 10,
- .max_health = 10,
- .collide_with_entities = true,
-
- .on_step = NULL,
- .on_collide = NULL,
- .on_collide_with_entity = NULL,
- .on_spawn = NULL,
- .on_remove = NULL,
- .on_death = &player_death,
- .on_damage = &player_damage,
- };
-
entity_collision_map[player.x][player.y] = &player;
for (int x = 0; x < MAP_WIDTH; x++)