Add inventory and cherries (collectable food)
parent
14d315712d
commit
30c560e271
|
@ -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
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
game
|
||||
score
|
||||
inventory
|
|
@ -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"),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
game
|
|
@ -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,
|
||||
});
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue