Add inventory and cherries (collectable food)

master
Elias Fleckenstein 2021-06-11 21:11:37 +02:00
parent 14d315712d
commit 30c560e271
9 changed files with 341 additions and 16 deletions

4
plugins/cherry/Makefile Normal file
View File

@ -0,0 +1,4 @@
plugins/cherry/cherry.so: plugins/cherry/cherry.c plugins/game/game.h plugins/score/score.h plugins/inventory/inventory.h
cc -g -shared -fpic -o plugins/cherry/cherry.so plugins/cherry/cherry.c
PLUGINS := ${PLUGINS} plugins/cherry/cherry.so

71
plugins/cherry/cherry.c Normal file
View File

@ -0,0 +1,71 @@
#include <stddef.h>
#include <stdlib.h>
#include "../game/game.h"
#include "../score/score.h"
#include "../inventory/inventory.h"
static struct entity cherry_entity;
static bool use_cherry(struct itemstack *stack)
{
(void) stack;
add_health(&player, 2);
return true;
}
static struct item cherry_item = {
.name = "Cherry",
.stackable = true,
.on_use = &use_cherry,
.on_destroy = NULL,
};
static void cherry_step(struct entity *self, struct entity_step_data stepdata)
{
if (stepdata.dx == 0 && stepdata.dy == 0) {
add_score(2);
inventory_add(&player_inventory, (struct itemstack) {
.item = &cherry_item,
.count = 1,
.meta = NULL,
});
self->remove = true;
}
}
static void spawn_cherry(int x, int y)
{
spawn(cherry_entity, x, y, NULL);
}
__attribute__((constructor)) static void init()
{
cherry_entity = (struct entity) {
.name = "cherry",
.x = 0,
.y = 0,
.color = get_color("#FF2A53"),
.texture = "🍒",
.remove = false,
.meta = NULL,
.health = 1,
.max_health = 1,
.collide_with_entities = false,
.on_step = &cherry_step,
.on_collide = NULL,
.on_collide_with_entity = NULL,
.on_spawn = NULL,
.on_remove = NULL,
.on_death = NULL,
.on_damage = NULL,
};
register_air_function((struct generator_function) {
.chance = 100,
.callback = &spawn_cherry,
});
}

View File

@ -0,0 +1,3 @@
game
score
inventory

View File

@ -1,7 +1,5 @@
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <assert.h>
#include <ctype.h>
@ -10,8 +8,8 @@
#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 */
@ -119,6 +117,14 @@ int min(int a, int b)
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()
@ -216,24 +222,22 @@ void add_health(struct entity *entity, int health)
/* 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 */
@ -254,9 +258,12 @@ 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;
@ -456,8 +463,6 @@ static void *input_thread(void *unused)
void game()
{
srand(time(0));
struct sigaction sa;
sa.sa_handler = &handle_interrupt;
sigaction(SIGINT, &sa, NULL);
@ -553,6 +558,8 @@ void game()
__attribute__ ((constructor)) static void init()
{
srand(time(0));
wall = (struct material) {
.solid = true,
.color = get_color("#5B2F00"),

View File

@ -3,6 +3,7 @@
#include <stdbool.h>
#include <sys/ioctl.h>
#include <stddef.h>
#define MAP_HEIGHT 1000
#define MAP_WIDTH 1000
#define LIGHT 10
@ -102,6 +103,7 @@ struct list *add_element(struct list *list, void *element);
int clamp(int v, int max, int min);
int max(int a, int b);
int min(int a, int b);
void *make_buffer(void *ptr, size_t size);
void quit();
bool player_dead();
@ -114,8 +116,8 @@ bool spawn(struct entity def, int x, int y, void *data);
bool move(struct entity *entity, int xoff, int yoff);
void add_health(struct entity *entity, int health);
void register_air_function(struct generator_function arg);
void register_input_handler(unsigned char c, struct input_handler arg);
void register_render_component(void (*arg)(struct winsize ws));
void register_air_function(struct generator_function func);
void register_input_handler(unsigned char c, struct input_handler handler);
void register_render_component(void (*callback)(struct winsize ws));
#endif

View File

@ -0,0 +1,4 @@
plugins/inventory/inventory.so: plugins/inventory/inventory.c plugins/inventory/inventory.h plugins/game/game.h
cc -g -shared -fpic -o plugins/inventory/inventory.so plugins/inventory/inventory.c
PLUGINS := ${PLUGINS} plugins/inventory/inventory.so

View File

@ -0,0 +1 @@
game

View File

@ -0,0 +1,203 @@
#include <stdio.h>
#include <stdlib.h>
#include "../inventory/inventory.h"
static struct color gray;
static struct color darkgray;
static bool use_item(struct itemstack *stack)
{
(void) stack;
return true;
}
struct inventory player_inventory = {NULL};
static int selected_index = 0;
void inventory_add(struct inventory *self, struct itemstack stack)
{
struct list **ptr = &self->stacks;
if (stack.item->stackable) {
for (; *ptr != NULL; ptr = &(*ptr)->next) {
struct itemstack *other = (*ptr)->element;
if (other->item == stack.item) {
other->count += stack.count;
return;
}
}
}
*ptr = add_element(*ptr, make_buffer(&stack, sizeof(struct itemstack)));
}
/*
bool inventory_remove(struct inventory *self, struct itemstack *stack)
{
stack.count = -stack.count;
for (struct list **ptr = &self->stacks; *ptr != NULL; ) {
struct itemstack *other = (*ptr)->element;
if (other->item == stack.item) {
stack.count += other->count;
if (stack.count > 0) {
other->count = stack.count;
return true;
} else {
struct list *next = ptr->next;
other->count = 0;
if (other->item->on_destroy)
other->item->on_destroy(other);
free(other);
free(*ptr);
*ptr = next;
continue;
}
}
ptr = &(*ptr)->next;
}
return false;
}
*/
static void decrease_item_count(struct list **ptr, struct itemstack *stack)
{
stack->count--;
if (stack->count == 0) {
struct list *next = (*ptr)->next;
if (stack->item->on_destroy)
stack->item->on_destroy(stack);
free(stack);
free(*ptr);
*ptr = next;
}
}
bool inventory_remove(struct inventory *self, struct item *item)
{
for (struct list **ptr = &self->stacks; *ptr != NULL; ptr = &(*ptr)->next) {
struct itemstack *stack = (*ptr)->element;
if (stack->item == item) {
decrease_item_count(ptr, stack);
return true;
}
}
return false;
}
static void handle_enter()
{
int i = 0;
for (struct list **ptr = &player_inventory.stacks; *ptr != NULL; ptr = &(*ptr)->next, i++) {
if (i == selected_index) {
struct itemstack *stack = (*ptr)->element;
if (stack->item->on_use && stack->item->on_use(stack))
decrease_item_count(ptr, stack);
return;
}
}
}
static void handle_arrow()
{
char c = fgetc(stdin);
if (c == '[') {
char dir = fgetc(stdin);
int count = 0;
for (struct list *ptr = player_inventory.stacks; ptr != NULL; ptr = ptr->next)
count++;
if (count == 0)
return;
switch (dir) {
case 'A':
selected_index--;
if (selected_index < 0)
selected_index = count - 1;
break;
case 'B':
selected_index++;
if (selected_index >= count)
selected_index = 0;
break;
}
} else {
ungetc(c, stdin);
}
}
static void render_inventory(struct winsize ws)
{
printf("\e[3;0H");
printf(" \e[1mInventory\e[21m\n");
set_color(gray, false);
int i = 0;
for (struct list *ptr = player_inventory.stacks; ptr != NULL; ptr = ptr->next, i++) {
struct itemstack *stack = ptr->element;
if (i == selected_index) {
printf(" \e[39m→ ");
set_color(gray, false);
} else {
printf(" ");
}
printf("%s", stack->item->name);
if (stack->count > 1) {
set_color(darkgray, false);
printf(" (x%u)", stack->count);
set_color(gray, false);
}
printf("\n");
}
}
__attribute__ ((constructor)) static void init()
{
gray = get_color("#9E9E9E");
darkgray = get_color("#555555");
register_render_component(&render_inventory);
register_input_handler('\033', (struct input_handler) {
.run_if_dead = false,
.callback = &handle_arrow,
});
register_input_handler('\n', (struct input_handler) {
.run_if_dead = false,
.callback = &handle_enter,
});
}

View File

@ -0,0 +1,30 @@
#ifndef _INVENTORY_H_
#define _INVENTORY_H_
#include "../game/game.h"
struct itemstack
{
struct item *item;
int count;
void *meta;
};
struct item
{
char *name;
bool stackable;
bool (*on_use)(struct itemstack *stack);
void (*on_destroy)(struct itemstack *stack);
};
struct inventory
{
struct list *stacks;
};
void inventory_add(struct inventory *self, struct itemstack stack);
bool inventory_remove(struct inventory *self, struct item *item);
extern struct inventory player_inventory;
#endif