Compare commits
10 Commits
c4beb89104
...
df0b65e097
Author | SHA1 | Date | |
---|---|---|---|
df0b65e097 | |||
28077a0eeb | |||
0ff24ad65b | |||
e8a9caf304 | |||
842a6852cd | |||
204bf6c3c9 | |||
a09f7106de | |||
bdab6658b3 | |||
4cddd76b5f | |||
3092e015a2 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
raylib.h
|
||||
game
|
||||
game
|
||||
|
||||
*/data/*.c
|
@ -3,9 +3,14 @@ CFLAGS=-Wall -lraylib -lGL -lm -lpthread -ldl -lrt -lX11
|
||||
|
||||
.PHONY: clean run
|
||||
|
||||
game:
|
||||
game: data/actions.c data/rooms.c data/transitions.c data/words.c data/flags.c *.c
|
||||
$(CC) *.c $(CFLAGS) -o game
|
||||
|
||||
data/%.c: data/%.txt
|
||||
echo -n "char *data_$*_txt = \"" > data/$*.c
|
||||
cat data/$*.txt | perl -pe 's/\n/\\n/g' >> data/$*.c
|
||||
echo "\";" >> data/$*.c
|
||||
|
||||
run: game
|
||||
./game
|
||||
|
||||
|
76
01_text_adventure/README.org
Normal file
76
01_text_adventure/README.org
Normal file
@ -0,0 +1,76 @@
|
||||
* Fatal Distractions Chapter 1 - Text Adventures
|
||||
** Concept
|
||||
I'm not looking for anything super complicated. I've spent maybe 90 minutes
|
||||
in my life playing text adventures, I'm sure there are some with really good
|
||||
mechanics. For this one, I'm aiming for something at about the level of
|
||||
[[https://homestarrunner.com/dungeonman][Thy Dungeonman]]. A map, moving between rooms, getting items, <verb>ing <item>s
|
||||
<preposition> <other item>s. If I'm pretty much finished before the end of the
|
||||
month, I could add
|
||||
- visual effects
|
||||
- saving and loading
|
||||
- pictures
|
||||
- music
|
||||
|
||||
I'm not trying to be a purist about this; I know 99% of all text adventures are
|
||||
*just* text, but music is also fun to put together.
|
||||
|
||||
** Implementation
|
||||
*** Flags
|
||||
A flag is a combination name and uinteger value. The value can be changed as the
|
||||
result of an action, or checked within a predicate. Three uses for these:
|
||||
- Boolean values, 1 or 0
|
||||
- Countdowns, start at some positive value and eventually become 0 = false
|
||||
- Counters, start at zero and increment ("you have rung the bell 10 times")
|
||||
Counters seem really optional, booleans and countdowns seem actually useful.
|
||||
Values should evaluate to false if zero, true otherwise.
|
||||
Effects should be able to enable (set to 1), disable (set to 0), increment, or
|
||||
decrement; if there's need for it, they'll need to set (set to X), I don't think so.
|
||||
*** Effects
|
||||
When an action evaluates, most of the time it will have no effect ("you can't
|
||||
go north from here"). Sometimes though, an action should change the world. Here
|
||||
are some effects:
|
||||
- Modify a flag (detailed above)
|
||||
- Change the current room
|
||||
- Add / remove an item from the inventory
|
||||
- Do some meta thing (save or load)
|
||||
*** Predicates
|
||||
I guess I need a DSL for predicates. I don't think I'll need to implement "OR",
|
||||
my predicates should be able to be a chain of clauses "AND"ed together. Some clauses:
|
||||
- IN(room_name), true if the current room has that name
|
||||
- HAS(item_name), true if that item is in the inventory (or in the room)
|
||||
- ENABLED(flag_name), true if that flag has a value > 0
|
||||
- TO(item_name), this is the real tough one, for transitive verbs with an object
|
||||
- 'use key on door'
|
||||
- 'give trinket to dennis'
|
||||
- 'take torch from sconce'
|
||||
Some of these things are items, some are definitely not. Not sure how to codify. Maybe:
|
||||
- DITRANSITIVE(preposition, object), which checks that the command is of the form:
|
||||
<verb> <noun> <preposition> <object>
|
||||
- Even monotransitive verbs ("pull lever") need to specify what they'll act on.
|
||||
*** Actions
|
||||
Actions are a command, or part of a command, plus a predicate, plus a priority,
|
||||
plus a description, plus (optionally) some effects:
|
||||
PULL | * | 1 | You don't see anything to pull |
|
||||
PULL | IN(lever_room) | 10 | What do you want to pull? |
|
||||
PULL LEVER | IN(lever_room) | 100 | You pull the lever. Nice. | ENABLE(lever_pulled)
|
||||
PULL LEVER | IN(lever_room) & ENABLED(lever_pulled) | 1000 | You already pulled it. |
|
||||
If the command matches all of the first column, it looks at that action.
|
||||
">PULL LEVER" would match all four, ">PULL" would only match the first two.
|
||||
The game would choose between all matched actions, filter to only the ones whose
|
||||
predicates are fulfilled, and choose from those the one with the highest priority.
|
||||
This might require a lot of typing, but I think it will have enough flexibility
|
||||
to do everything I might want to do.
|
||||
|
||||
An action describing a transition would look as follows:
|
||||
NORTH | * | 1 | You can't go north from here. |
|
||||
NORTH | IN(initial_room) | 2 | You enter the nasty room. | GOTO(nasty_room)
|
||||
NORTH | IN(other_room) | 2 | You enter the opulent room. | GOTO(opulent_room)
|
||||
, but there's nicer syntax for transitions I'm sure.
|
||||
*** Parsing
|
||||
I'm sure we want a gallery of synonyms for most verbs and nouns. I assume we split the string
|
||||
by spaces, making an array of canonical words, then write the actions around those canonical
|
||||
words.
|
||||
PULL|PULL,YANK,TUG
|
||||
ROPE|ROPE,CORD,STRING,CABLE
|
||||
With the above words, "PULL ROPE", "YANK CORD", or "TUG STRING" would all check for
|
||||
actions as "PULL ROPE".
|
50
01_text_adventure/action.c
Normal file
50
01_text_adventure/action.c
Normal file
@ -0,0 +1,50 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "action.h"
|
||||
#include "game.h"
|
||||
#include "util.h"
|
||||
|
||||
void load_action(Game *g, char *line) {
|
||||
Action *action = &g->actions->actions[g->actions->count];
|
||||
|
||||
char *line_token_guy;
|
||||
char *line_token = strtok_r(line, "|", &line_token_guy);
|
||||
|
||||
char command_buffer[200];
|
||||
strcpy(command_buffer, line_token);
|
||||
|
||||
char *command_token_guy;
|
||||
char *command_word = strtok_r(command_buffer, " ", &command_token_guy);
|
||||
while (command_word != NULL) {
|
||||
Word *word = find_word(g->words, command_word);
|
||||
action->words[action->words_count++] = word;
|
||||
command_word = strtok_r(NULL, " ", &command_token_guy);
|
||||
}
|
||||
|
||||
line_token = strtok_r(NULL, "|", &line_token_guy);
|
||||
|
||||
// predicate bullshit
|
||||
// char *command_predicate_strtok = strtok_r
|
||||
|
||||
line_token = strtok_r(NULL, "|", &line_token_guy);
|
||||
action->priority = atoi(line_token);
|
||||
|
||||
line_token = strtok_r(NULL, "|", &line_token_guy);
|
||||
action->description = malloc(strlen(line_token) + 1);
|
||||
strcpy(action->description, line_token);
|
||||
|
||||
line_token = strtok_r(NULL, "|", &line_token_guy);
|
||||
|
||||
// action bullshit
|
||||
|
||||
g->actions->count++;
|
||||
}
|
||||
|
||||
#include "data/actions.c"
|
||||
void game_load_actions(Game *g) {
|
||||
parse_multiline_string(g, data_actions_txt, &load_action);
|
||||
}
|
||||
|
||||
Action *find_action(Actions *actions, char *command) {
|
||||
return NULL;
|
||||
}
|
29
01_text_adventure/action.h
Normal file
29
01_text_adventure/action.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef _FD_ACTION_
|
||||
#define _FD_ACTION_
|
||||
|
||||
typedef struct Action Action;
|
||||
typedef struct Actions Actions;
|
||||
|
||||
#include "game.h"
|
||||
#include "word.h"
|
||||
#include "predicate.h"
|
||||
|
||||
struct Action {
|
||||
Word *words[4];
|
||||
int words_count;
|
||||
Predicate *predicates[10];
|
||||
int predicates_count;
|
||||
int priority;
|
||||
char *description;
|
||||
// Effect *effect;
|
||||
};
|
||||
|
||||
struct Actions {
|
||||
Action actions[1000];
|
||||
int count;
|
||||
};
|
||||
|
||||
void game_load_actions(Game *g);
|
||||
Action *find_action(Actions *actions, char *command);
|
||||
|
||||
#endif
|
4
01_text_adventure/data/actions.txt
Normal file
4
01_text_adventure/data/actions.txt
Normal file
@ -0,0 +1,4 @@
|
||||
PULL|*|1|You don't see anything to pull|
|
||||
PULL|IN(lever_room)|10|What do you want to pull?|
|
||||
PULL LEVER|IN(lever_room)|100|You pull the lever. Nice.|ENABLE(lever_pulled)
|
||||
PULL LEVER|IN(lever_room) & ENABLED(lever_pulled)|1000|You already pulled it.|
|
2
01_text_adventure/data/flags.txt
Normal file
2
01_text_adventure/data/flags.txt
Normal file
@ -0,0 +1,2 @@
|
||||
LEVER_PULLED|0
|
||||
STEPS_TAKEN|10
|
3
01_text_adventure/data/words.txt
Normal file
3
01_text_adventure/data/words.txt
Normal file
@ -0,0 +1,3 @@
|
||||
PULL|PULL,YANK,TUG
|
||||
ROPE|ROPE,CORD,STRING,CABLE
|
||||
LEVER|LEVER
|
31
01_text_adventure/flag.c
Normal file
31
01_text_adventure/flag.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "flag.h"
|
||||
#include "game.h"
|
||||
#include "util.h"
|
||||
|
||||
void load_flag(Game *g, char *line) {
|
||||
char *token = strtok(line, "|");
|
||||
Flag *flag = &g->flags->flags[g->flags->count];
|
||||
flag->key = malloc(strlen(token) + 1);
|
||||
strcpy(flag->key, token);
|
||||
|
||||
token = strtok(NULL, "|");
|
||||
flag->value = atoi(token);
|
||||
|
||||
g->flags->count++;
|
||||
}
|
||||
|
||||
#include "data/flags.c"
|
||||
void game_load_flags(Game *g) {
|
||||
parse_multiline_string(g, data_flags_txt, &load_flag);
|
||||
}
|
||||
|
||||
int flag_value(Flags *f, char *key) {
|
||||
for (int i = 0; i < f->count; i++) {
|
||||
if (strcmp(f->flags[i].key, key) == 0) return f->flags[i].value;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
22
01_text_adventure/flag.h
Normal file
22
01_text_adventure/flag.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef _FD_FLAG_
|
||||
#define _FD_FLAG_
|
||||
|
||||
typedef struct Flag Flag;
|
||||
typedef struct Flags Flags;
|
||||
|
||||
#include "game.h"
|
||||
|
||||
struct Flag {
|
||||
char *key;
|
||||
int value;
|
||||
};
|
||||
|
||||
struct Flags {
|
||||
Flag flags[200];
|
||||
int count;
|
||||
};
|
||||
|
||||
void game_load_flags(Game *g);
|
||||
int flag_value(Flags *f, char *key);
|
||||
|
||||
#endif
|
@ -6,6 +6,11 @@
|
||||
#include "transition.h"
|
||||
#include "input.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "word.h"
|
||||
#include "flag.h"
|
||||
#include "predicate.h"
|
||||
#include "action.h"
|
||||
|
||||
Game *game_create(void) {
|
||||
Game *g = malloc(sizeof(Game));
|
||||
@ -29,6 +34,15 @@ Game *game_create(void) {
|
||||
|
||||
g->input = input;
|
||||
|
||||
g->words = malloc(sizeof(Words));
|
||||
g->words->count = 0;
|
||||
|
||||
g->flags = malloc(sizeof(Flags));
|
||||
g->flags->count = 0;
|
||||
|
||||
g->actions = malloc(sizeof(Actions));
|
||||
g->actions->count = 0;
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
@ -118,31 +132,6 @@ void game_handle_command(Game *g, const char *command) {
|
||||
}
|
||||
}
|
||||
|
||||
#define ROOMS_PATH "./rooms.txt"
|
||||
#define MAX_ROOM_COUNT 100
|
||||
|
||||
char room_buffer[2001];
|
||||
|
||||
void game_load_rooms(Game *g) {
|
||||
FILE *rooms_file = fopen(ROOMS_PATH, "r");
|
||||
|
||||
while ((fgets(room_buffer, 2000, rooms_file)) != NULL) {
|
||||
char *token = strtok(room_buffer, "|");
|
||||
|
||||
g->rooms->rooms[g->rooms->count].name = malloc(strlen(token) + 1);
|
||||
strcpy(g->rooms->rooms[g->rooms->count].name, token);
|
||||
|
||||
token = strtok(NULL, "|");
|
||||
g->rooms->rooms[g->rooms->count].description = malloc(strlen(token) + 1);
|
||||
strcpy(g->rooms->rooms[g->rooms->count].description, token);
|
||||
|
||||
g->rooms->count++;
|
||||
}
|
||||
fclose(rooms_file);
|
||||
|
||||
g->current_room = &g->rooms->rooms[0];
|
||||
}
|
||||
|
||||
void game_handle_input(Game *g) {
|
||||
handle_pressed_keys(g->input);
|
||||
}
|
||||
|
@ -18,6 +18,9 @@ typedef enum Command {
|
||||
#include "room.h"
|
||||
#include "transition.h"
|
||||
#include "log.h"
|
||||
#include "word.h"
|
||||
#include "flag.h"
|
||||
#include "action.h"
|
||||
|
||||
struct Game {
|
||||
bool should_close;
|
||||
@ -26,6 +29,9 @@ struct Game {
|
||||
Rooms *rooms;
|
||||
Room *current_room;
|
||||
Transitions *transitions;
|
||||
Words *words;
|
||||
Flags *flags;
|
||||
Actions *actions;
|
||||
};
|
||||
|
||||
Game *game_create(void);
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "../raylib.h"
|
||||
#include "log.h"
|
||||
#include "input.h"
|
||||
#include "parse.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@ -15,7 +16,20 @@ int main(void) {
|
||||
|
||||
Game *g = game_create();
|
||||
game_load_rooms(g);
|
||||
g->current_room = &g->rooms->rooms[0];
|
||||
game_load_transitions(g);
|
||||
game_load_words(g);
|
||||
game_load_flags(g);
|
||||
game_load_actions(g);
|
||||
|
||||
for (int i = 0; i < g->actions->count; i++) {
|
||||
for (int j = 0; j < g->actions->actions[i].words_count; j++) {
|
||||
printf("%s ", g->actions->actions[i].words[j]->word);
|
||||
}
|
||||
printf("|preds|%d|%s|effects", g->actions->actions[i].priority, g->actions->actions[i].description);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
game_run_until_close(g);
|
||||
CloseWindow();
|
||||
|
30
01_text_adventure/parse.c
Normal file
30
01_text_adventure/parse.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "game.h"
|
||||
#include "word.h"
|
||||
|
||||
#define MAX_WORDS_IN_COMMAND 4
|
||||
void parse(Game *g, char *typed_command) {
|
||||
printf("Typed command: %s\n", typed_command);
|
||||
char *bluh = malloc(strlen(typed_command) + 1);
|
||||
strcpy(bluh, typed_command);
|
||||
|
||||
Word **command = malloc(MAX_WORDS_IN_COMMAND * sizeof(Word));
|
||||
int word_count = 0;
|
||||
char *token = strtok(bluh, " ");
|
||||
|
||||
while (word_count < MAX_WORDS_IN_COMMAND && token != NULL) {
|
||||
command[word_count] = find_word(g->words, token);
|
||||
|
||||
word_count++;
|
||||
token = strtok(NULL, " ");
|
||||
}
|
||||
|
||||
for(int i = 0; i < word_count; i++) {
|
||||
printf("%s ", command[i]->word);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
free(bluh);
|
||||
}
|
7
01_text_adventure/parse.h
Normal file
7
01_text_adventure/parse.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef _FD_PARSE_
|
||||
#define _FD_PARSE_
|
||||
#include "game.h"
|
||||
|
||||
void parse(Game *g, char *typed_command);
|
||||
|
||||
#endif
|
19
01_text_adventure/predicate.c
Normal file
19
01_text_adventure/predicate.c
Normal file
@ -0,0 +1,19 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "game.h"
|
||||
#include "flag.h"
|
||||
#include "predicate.h"
|
||||
|
||||
bool predicate_fulfilled(Game *g, Predicate *p) {
|
||||
switch (p->type) {
|
||||
case PREDICATE_TRUE:
|
||||
return true;
|
||||
case PREDICATE_IN_ROOM:
|
||||
return strcmp(g->current_room->name, p->argument) == 0;
|
||||
case PREDICATE_FLAG_ENABLED:
|
||||
return flag_value(g->flags, p->argument) > 0;
|
||||
default:
|
||||
printf("Invalid predicate type\n");
|
||||
return false;
|
||||
}
|
||||
}
|
22
01_text_adventure/predicate.h
Normal file
22
01_text_adventure/predicate.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef _FD_PREDICATE_
|
||||
#define _FD_PREDICATE_
|
||||
|
||||
typedef struct Predicate Predicate;
|
||||
|
||||
typedef enum PredicateType {
|
||||
PREDICATE_TRUE,
|
||||
PREDICATE_IN_ROOM,
|
||||
// PREDICATE_HAS_ITEM,
|
||||
PREDICATE_FLAG_ENABLED,
|
||||
} PredicateType;
|
||||
|
||||
#include "game.h"
|
||||
|
||||
struct Predicate {
|
||||
PredicateType type;
|
||||
char *argument;
|
||||
};
|
||||
|
||||
bool predicate_fulfilled(Game *g, Predicate *p);
|
||||
|
||||
#endif
|
@ -2,6 +2,26 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "room.h"
|
||||
#include "game.h"
|
||||
#include "util.h"
|
||||
|
||||
void load_room(Game *g, char *line) {
|
||||
char *token = strtok(line, "|");
|
||||
|
||||
g->rooms->rooms[g->rooms->count].name = malloc(strlen(token) + 1);
|
||||
strcpy(g->rooms->rooms[g->rooms->count].name, token);
|
||||
|
||||
token = strtok(NULL, "|");
|
||||
g->rooms->rooms[g->rooms->count].description = malloc(strlen(token) + 1);
|
||||
strcpy(g->rooms->rooms[g->rooms->count].description, token);
|
||||
|
||||
g->rooms->count++;
|
||||
}
|
||||
|
||||
#include "data/rooms.c"
|
||||
void game_load_rooms(Game *g) {
|
||||
parse_multiline_string(g, data_rooms_txt, &load_room);
|
||||
}
|
||||
|
||||
void free_room(Room r) {
|
||||
free(r.name);
|
||||
|
@ -3,32 +3,28 @@
|
||||
#include <string.h>
|
||||
#include "transition.h"
|
||||
#include "game.h"
|
||||
#include "util.h"
|
||||
|
||||
#define TRANSITIONS_PATH "./transitions.txt"
|
||||
void load_transition(Game *g, char *line) {
|
||||
char *token = strtok(line, "|");
|
||||
g->transitions->transitions[g->transitions->count].from = find_room(g->rooms, token);
|
||||
|
||||
char transition_buffer[2001];
|
||||
void game_load_transitions(Game *g) {
|
||||
FILE *transitions_file = fopen(TRANSITIONS_PATH, "r");
|
||||
token = strtok(NULL, "|");
|
||||
g->transitions->transitions[g->transitions->count].via = command_from_string(token);
|
||||
|
||||
while ((fgets(transition_buffer, 2000, transitions_file)) != NULL) {
|
||||
char *token = strtok(transition_buffer, "|");
|
||||
token = strtok(NULL, "|");
|
||||
g->transitions->transitions[g->transitions->count].to = find_room(g->rooms, token);
|
||||
|
||||
g->transitions->transitions[g->transitions->count].from = find_room(g->rooms, token);
|
||||
|
||||
token = strtok(NULL, "|");
|
||||
g->transitions->transitions[g->transitions->count].via = command_from_string(token);
|
||||
|
||||
token = strtok(NULL, "|");
|
||||
g->transitions->transitions[g->transitions->count].to = find_room(g->rooms, token);
|
||||
|
||||
token = strtok(NULL, "|");
|
||||
g->transitions->transitions[g->transitions->count].description = malloc(strlen(token) + 1);
|
||||
strcpy(g->transitions->transitions[g->transitions->count].description, token);
|
||||
token = strtok(NULL, "\n");
|
||||
g->transitions->transitions[g->transitions->count].description = malloc(strlen(token) + 1);
|
||||
strcpy(g->transitions->transitions[g->transitions->count].description, token);
|
||||
|
||||
g->transitions->count++;
|
||||
}
|
||||
g->transitions->count++;
|
||||
}
|
||||
|
||||
fclose(transitions_file);
|
||||
#include "data/transitions.c"
|
||||
void game_load_transitions(Game *g) {
|
||||
parse_multiline_string(g, data_transitions_txt, &load_transition);
|
||||
}
|
||||
|
||||
Transition *find_transition(Transitions *t, Room *from, Command via) {
|
||||
|
23
01_text_adventure/util.c
Normal file
23
01_text_adventure/util.c
Normal file
@ -0,0 +1,23 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "util.h"
|
||||
#include "game.h"
|
||||
|
||||
void parse_multiline_string(Game *g, char *string, void (*parse_line)(Game *g, char *line)) {
|
||||
char *buffer = malloc(0);
|
||||
char *sol = string;
|
||||
char *eol = strchr(sol, '\n');
|
||||
while (eol != NULL) {
|
||||
int line_length = eol - sol;
|
||||
buffer = realloc(buffer, line_length + 1);
|
||||
memcpy(buffer, sol, line_length);
|
||||
buffer[line_length] = '\0';
|
||||
|
||||
parse_line(g, buffer);
|
||||
|
||||
sol = eol + 1;
|
||||
eol = strchr(sol, '\n');
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
}
|
7
01_text_adventure/util.h
Normal file
7
01_text_adventure/util.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef _FD_UTIL_
|
||||
#define _FD_UTIL_
|
||||
#include "game.h"
|
||||
|
||||
void parse_multiline_string(Game *g, char *string, void (*parse_line)(Game *g, char *line));
|
||||
|
||||
#endif
|
38
01_text_adventure/word.c
Normal file
38
01_text_adventure/word.c
Normal file
@ -0,0 +1,38 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "word.h"
|
||||
#include "game.h"
|
||||
#include "util.h"
|
||||
|
||||
void load_word(Game *g, char *line) {
|
||||
char *token = strtok(line, "|");
|
||||
Word *word = &g->words->words[g->words->count];
|
||||
word->word = malloc(strlen(token) + 1);
|
||||
strcpy(word->word, token);
|
||||
|
||||
word->synonyms_count = 0;
|
||||
while ((token = strtok(NULL, ",")) != NULL) {
|
||||
word->synonyms[word->synonyms_count] = malloc(strlen(token) + 1);
|
||||
strcpy(word->synonyms[word->synonyms_count], token);
|
||||
word->synonyms_count++;
|
||||
}
|
||||
|
||||
g->words->count++;
|
||||
}
|
||||
|
||||
#include "data/words.c"
|
||||
void game_load_words(Game *g) {
|
||||
parse_multiline_string(g, data_words_txt, &load_word);
|
||||
}
|
||||
|
||||
Word *find_word(Words *words, char *word_or_syn) {
|
||||
for (int i = 0; i < words->count; i++) {
|
||||
for (int j = 0; j < words->words[i].synonyms_count; j++) {
|
||||
if (strcmp(words->words[i].synonyms[j], word_or_syn) == 0) return &words->words[i];
|
||||
}
|
||||
}
|
||||
|
||||
printf("Can't find %s\n", word_or_syn);
|
||||
return NULL;
|
||||
}
|
22
01_text_adventure/word.h
Normal file
22
01_text_adventure/word.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef _FD_WORD_
|
||||
#define _FD_WORD_
|
||||
typedef struct Word Word;
|
||||
typedef struct Words Words;
|
||||
|
||||
#include "game.h"
|
||||
|
||||
struct Word {
|
||||
char *word;
|
||||
char* synonyms[100];
|
||||
int synonyms_count;
|
||||
};
|
||||
|
||||
struct Words {
|
||||
Word words[200];
|
||||
int count;
|
||||
};
|
||||
|
||||
void game_load_words(Game *g);
|
||||
Word *find_word(Words *words, char *word);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user