Compare commits

...

4 Commits

Author SHA1 Message Date
eb43986876 See your inventory! 2025-01-21 21:08:05 -05:00
868c2211be Haul items around 2025-01-21 21:01:32 -05:00
faccabcafc Items + showing them in rooms 2025-01-21 20:38:34 -05:00
b786a0fa04 Unify Makefile once again 2025-01-21 19:58:04 -05:00
12 changed files with 200 additions and 8 deletions

View File

@ -1,13 +1,9 @@
CC=gcc
ifeq ($(shell uname),Darwin)
CFLAGS=-Wall -lraylib -lm -lpthread -ldl -lX11
else
CFLAGS=-Wall -lraylib -lGL -lm -lpthread -ldl -lrt -lX11
endif
CFLAGS=-Wall -lraylib -lm -lpthread -ldl -lX11
.PHONY: clean run
game: data/actions.c data/rooms.c data/room_ins.c data/words.c data/flags.c *.c
game: data/actions.c data/rooms.c data/room_ins.c data/words.c data/flags.c data/items.c *.c
$(CC) *.c $(CFLAGS) -o game
data/%.c: data/%.txt

View File

@ -1,7 +1,7 @@
QUIT | * | 1000 | Bye! | QUIT_GAME()
LOOK | * | 1 | * | LOOK_ROOM()
HELP | * | 1 | Type commands to explore the environment. Use 'LOOK' to examine the room you're in, or 'LOOK <item>' to examine an item closely. 'N', 'S', 'E', and 'W' will move you in the four cardinal directions, and 'I' will let you check your inventory. The parser is not very advanced, so do your best. 'Q', 'QUIT', or 'EXIT' will let you quit. |
INVENTORY | * | 1 | Your inventory is empty. |
INVENTORY | * | 1 | * | CHECK_INVENTORY()
NORTH | * | 1 | You can't go north from here. |
SOUTH | * | 1 | You can't go south from here. |
EAST | * | 1 | You can't go east from here. |
@ -15,3 +15,8 @@ PULL | * | 1 | You don't see anyth
PULL | IN(SECOND_ROOM) | 10 | What do you want to pull? |
PULL LEVER | IN(SECOND_ROOM) | 100 | You pull the lever and the sound of grinding machinery comes from the first room. | ENABLE(LEVER_PULLED)
PULL LEVER | IN(SECOND_ROOM) & ENABLED(LEVER_PULLED) | 1000 | You already pulled it. |
TAKE TORCH | ITEM_HERE(UNLIT_TORCH) | 1000 | You pick up the torch | TAKE(UNLIT_TORCH)
TAKE TORCH | HAS_ITEM(UNLIT_TORCH) | 1001 | You already have a torch |
TAKE TORCH | * | 100 | What torch? |
DROP TORCH | * | 100 | What torch? |
DROP TORCH | HAS_ITEM(UNLIT_TORCH) | 1000 | You lay the torch carefully on the ground. | DROP(UNLIT_TORCH)

View File

@ -0,0 +1,4 @@
UNLIT_TORCH | a torch | true | A sturdy torch. It's unlit.
LIT_TORCH | a lit torch | true | A sturdy torch. It's on fire, and illuminates its surroundings.
FLASK | a flask | true | An empty glass flask, with a cork.
ANVIL | an anvil | false | A heavy iron anvil.

View File

@ -9,3 +9,8 @@ WEST|WEST,W
LOOK|LOOK,L
INVENTORY|INVENTORY,I,INV
HELP|HELP,H
ANVIL|ANVIL
FLASK|FLASK,BOTTLE,JAR
TORCH|TORCH
TAKE|TAKE,PICKUP,GET
DROP|DROP

View File

@ -32,6 +32,16 @@ void cause_effect(Game *g, Effect *e) {
break;
case EFFECT_LOOK_ROOM:
push_line_to_log(g->input->log, find_room_in(g)->description);
log_items_in_room(g, g->current_room);
break;
case EFFECT_TAKE_ITEM:
take_item(g, e->argument);
break;
case EFFECT_DROP_ITEM:
drop_item(g, e->argument);
break;
case EFFECT_CHECK_INVENTORY:
check_inventory(g);
break;
}
}
@ -60,6 +70,12 @@ Effect *create_effect(Game *g, const char *string) {
e->type = EFFECT_QUIT_GAME;
} else if (strcmp(token, "LOOK_ROOM") == 0) {
e->type = EFFECT_LOOK_ROOM;
} else if (strcmp(token, "TAKE") == 0) {
e->type = EFFECT_TAKE_ITEM;
} else if (strcmp(token, "DROP") == 0) {
e->type = EFFECT_DROP_ITEM;
} else if (strcmp(token, "CHECK_INVENTORY") == 0) {
e->type = EFFECT_CHECK_INVENTORY;
}
token = strtok_r(NULL, ")", &strtok_guy);
@ -99,5 +115,14 @@ void print_effect(Effect *e) {
case EFFECT_LOOK_ROOM:
printf("LOOK_ROOM()");
break;
case EFFECT_TAKE_ITEM:
printf("TAKE(%s)", e->argument);
break;
case EFFECT_DROP_ITEM:
printf("DROP(%s)", e->argument);
break;
case EFFECT_CHECK_INVENTORY:
printf("CHECK_INVENTORY()");
break;
}
}

View File

@ -12,6 +12,9 @@ typedef enum EffectType {
EFFECT_DISABLE,
EFFECT_QUIT_GAME,
EFFECT_LOOK_ROOM,
EFFECT_TAKE_ITEM,
EFFECT_DROP_ITEM,
EFFECT_CHECK_INVENTORY,
} EffectType;
#include "game.h"

View File

@ -11,6 +11,7 @@
#include "predicate.h"
#include "action.h"
#include "parse.h"
#include "item.h"
Game *game_create(void) {
Game *g = malloc(sizeof(Game));
@ -21,6 +22,9 @@ Game *game_create(void) {
game_load_actions(g);
game_load_rooms(g);
game_load_room_ins(g);
game_load_items(g);
g->items->items[0].location = &g->rooms->rooms[0];
Log *log = create_log();
g->log = log;

View File

@ -22,6 +22,7 @@ typedef enum CommandType {
#include "word.h"
#include "flag.h"
#include "action.h"
#include "item.h"
struct Game {
bool should_close;
@ -33,6 +34,7 @@ struct Game {
Words *words;
Flags *flags;
Actions *actions;
Items *items;
};
Game *game_create(void);

95
01_text_adventure/item.c Normal file
View File

@ -0,0 +1,95 @@
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "game.h"
#include "room.h"
#include "item.h"
#include "util.h"
void load_item(Game *g, char *line) {
char *token = strtok(line, "|");
Item *item = &g->items->items[g->items->count];
item->name = malloc(strlen(token) + 1);
strcpy(item->name, token);
token = strtok(NULL, "|");
item->indefinite = malloc(strlen(token) + 1);
strcpy(item->indefinite, token);
token = strtok(NULL, "|");
item->pickuppable = strcmp("true", token) == 0;
token = strtok(NULL, "|");
item->description = malloc(strlen(token) + 1);
strcpy(item->description, token);
item->in_inventory = false;
item->location = NULL;
g->items->count++;
}
#include "data/items.c"
void game_load_items(Game *g) {
g->items = malloc(sizeof(Items));
g->items->count = 0;
parse_multiline_string(g, data_items_txt, &load_item);
printf("loaded items\n");
}
#define ITEM_IN_ROOM "There is %s here."
void log_item_in_room(Game *g, Item *i) {
char *response = malloc(strlen(ITEM_IN_ROOM) + strlen(i->indefinite) + 1);
sprintf(response, ITEM_IN_ROOM, i->indefinite);
push_line_to_log(g->input->log, response);
free(response);
}
#define ITEM_IN_INVENTORY "You have %s."
void log_item_in_inventory(Game *g, Item *i) {
char *response = malloc(strlen(ITEM_IN_INVENTORY) + strlen(i->indefinite) + 1);
sprintf(response, ITEM_IN_INVENTORY, i->indefinite);
push_line_to_log(g->input->log, response);
free(response);
}
void log_items_in_room(Game *g, Room *r) {
for (int i = 0; i < g->items->count; i++) {
if (g->items->items[i].location == r) log_item_in_room(g, &g->items->items[i]);
}
}
Item *find_item(Items *items, char *item_name) {
for (int i = 0; i < items->count; i++) {
if (strcmp(items->items[i].name, item_name) == 0) return &items->items[i];
}
return NULL;
}
void take_item(Game *g, char *item_name) {
Item *item = find_item(g->items, item_name);
item->location = NULL;
item->in_inventory = true;
}
void drop_item(Game *g, char *item_name) {
Item *item = find_item(g->items, item_name);
item->location = g->current_room;
item->in_inventory = false;
}
void check_inventory(Game *g) {
bool empty = true;
for (int i = 0; i < g->items->count; i++) {
if (g->items->items[i].in_inventory) {
empty = false;
log_item_in_inventory(g, &g->items->items[i]);
}
}
if (empty) {
push_line_to_log(g->input->log, "Your inventory is empty.");
}
}

31
01_text_adventure/item.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef _FD_ITEM_
#define _FD_ITEM_
typedef struct Item Item;
typedef struct Items Items;
#include "game.h"
#include "room.h"
struct Item {
char *name;
char *indefinite;
bool pickuppable;
char *description;
bool in_inventory;
Room *location;
};
struct Items {
Item items[200];
int count;
};
void game_load_items(Game *g);
void log_items_in_room(Game *g, Room *r);
Item *find_item(Items *items, char *item_name);
void take_item(Game *g, char *item_name);
void drop_item(Game *g, char *item_name);
void check_inventory(Game *g);
#endif

View File

@ -3,6 +3,7 @@
#include <string.h>
#include "game.h"
#include "flag.h"
#include "item.h"
#include "predicate.h"
bool predicate_fulfilled(Game *g, Predicate *p) {
@ -11,6 +12,10 @@ bool predicate_fulfilled(Game *g, Predicate *p) {
return true;
case PREDICATE_IN_ROOM:
return strcmp(g->current_room->name, p->argument) == 0;
case PREDICATE_ITEM_HERE:
return find_item(g->items, p->argument)->location == g->current_room;
case PREDICATE_HAS_ITEM:
return find_item(g->items, p->argument)->in_inventory;
case PREDICATE_FLAG_ENABLED:
return flag_value(g->flags, p->argument) > 0;
default:
@ -33,6 +38,16 @@ Predicate *create_predicate(Game *g, const char *string) {
token = strtok_r(NULL, ")", &strtok_guy);
p->argument = malloc(strlen(token) + 1);
strcpy(p->argument, token);
} else if (strcmp(token, "ITEM_HERE") == 0) {
p->type = PREDICATE_ITEM_HERE;
token = strtok_r(NULL, ")", &strtok_guy);
p->argument = malloc(strlen(token) + 1);
strcpy(p->argument, token);
} else if (strcmp(token, "HAS_ITEM") == 0) {
p->type = PREDICATE_HAS_ITEM;
token = strtok_r(NULL, ")", &strtok_guy);
p->argument = malloc(strlen(token) + 1);
strcpy(p->argument, token);
} else if (strcmp(token, "ENABLED") == 0) {
p->type = PREDICATE_FLAG_ENABLED;
token = strtok_r(NULL, ")", &strtok_guy);
@ -52,6 +67,12 @@ void print_predicate(Predicate *p) {
case PREDICATE_IN_ROOM:
printf("IN(%s)", p->argument);
break;
case PREDICATE_ITEM_HERE:
printf("ITEM_HERE(%s)", p->argument);
break;
case PREDICATE_HAS_ITEM:
printf("HAS_ITEM(%s)", p->argument);
break;
case PREDICATE_FLAG_ENABLED:
printf("ENABLED(%s)", p->argument);
break;

View File

@ -6,7 +6,8 @@ typedef struct Predicate Predicate;
typedef enum PredicateType {
PREDICATE_TRUE,
PREDICATE_IN_ROOM,
// PREDICATE_HAS_ITEM,
PREDICATE_ITEM_HERE,
PREDICATE_HAS_ITEM,
PREDICATE_FLAG_ENABLED,
} PredicateType;