This might get a little troublesome, please help if u can.
Code:
//In main.c this line is triggered
initial_room = load_level(default_level);
//In level.c this line is called, once it is triggered from main
// loads a level from a config file and returns a pointer to the starting room
room_t *load_level(char *filename) {
. . .
. . .
return room_array;
//And some where along the main.c, 2-5 lines later this is called
look(0, NULL);
//My code is buggy when it hits this point of main.c
//This is what look() does
// prints out the room description, the exits, and monsters
int look(int argc, char **argv) {
room_t *r = the_player.current_room;
printf("%s\n", r->description);
// My code doesn't print out the room description and the_player is inside the globals.h
init_player(initial_room);
//[B] This is init_player, existing inside main.c
void init_player(room_t *starting_room) {
the_player.current_room = starting_room;
the_player.experience = 0;
the_player.level = get_level(the_player.experience);
the_player.hp = 10;
the_player.max_hp = 10;
}
//[B] The starting_room is a pointer to the first room in the room_array[\B]
//This is how I initialize my room array inside level.c
struct room* rooms = malloc(num_rooms * sizeof(struct room));
room_array = &rooms;
Question: What am I doing wrong? Why wouldn't the first room description print itself?
Code:
#include "level.h"
#include "common.h"
#include "util.h"
// array of directio names. must be consistent with the order of the enum
// in level.h
char *direction_names[] = {
"north",
"south",
"east",
"west",
"up",
"down"
};
// loads a level from a config file and returns a pointer to the starting room
room_t *load_level(char *filename) {
char buf[2048];
char *whitespace = " \t\n";
FILE *levelfile = fopen(filename,"r");
if(levelfile == NULL) {
printf("Could not open %s\n", filename);
exit(1);
}
skip_characters(levelfile, whitespace);
// get the total number of rooms
fgets(buf,256,levelfile);
num_rooms = atoi(buf);
skip_characters(levelfile, whitespace);
// allocate an array for all of the room structs to be stored
// store the pointer in the global room_array variable
/*** YOUR CODE HERE ***/
// Initialize room_array
/*** YOUR CODE HERE ***/
skip_characters(levelfile, whitespace);
// one line at a time, read in room description strings and set
// the appropriate field in each string's corresponding room struct
while(fgets(buf, 256, levelfile), buf[0] != '\n') {
/*** YOUR CODE HERE ***/
}
skip_characters(levelfile, whitespace);
// hook up rooms so that exits point to each other appropriately.
// exits should also be set to locked or unlocked as necessary
while(fgets(buf, 256, levelfile), buf[0] != '\n' && !feof(levelfile)) {
char *words[32];
tokenizer(buf, words, " \t\n");
assert(!strcmp("can-go", words[0]) || !strcmp("cant-go", words[0]));
direction dir;
switch(words[1][0]) {
case 'n':
dir = NORTH;
break;
case 's':
dir = SOUTH;
break;
case 'e':
dir = EAST;
break;
case 'w':
dir = WEST;
break;
case 'u':
dir = UP;
break;
case 'd':
dir = DOWN;
break;
default:
printf("%s isn't a direction\n", words[1]);
assert(false);
}
/*** YOUR CODE HERE ***/
}
return room_array; // equivalent to a pointer to the first element of the array
}
This is main.c
Code:
#include "common.h"
#include "util.h"
char *default_level = "cs61c-world.lvl";
char *usage =
"usage: %s [LEVEL_FILE]\n"
"LEVEL_FILE will be loaded if provided, otherwise \"%s\" will be used.\n"
;
void init_player(room_t *starting_room) {
the_player.current_room = starting_room;
the_player.experience = 0;
the_player.level = get_level(the_player.experience);
the_player.hp = 10;
the_player.max_hp = 10;
}
void tick_world(int elapsed_time, bool player_vulnerable) {
static int time = 0;
static int last_attack_time = 0;
const int attack_period = 15;
time += elapsed_time;
while(time - last_attack_time > attack_period) {
// monsters attack every attack_period seconds
if(player_vulnerable) {
monster_t *attacker;
mob_iterator_t *iter = make_mob_iterator(&the_player.current_room->mob);
while((attacker = next_monster(iter))) {
// does monster attack? 75% chance...
if (rand() % 4 <= 0) {
printf("The %s tries to %s you, but misses\n",
attacker->name,attacker->attack);
continue;
}
printf("The %s %ss you for %d points of damage\n",
attacker->name, attacker->attack, attacker->damage);
the_player.hp -= attacker->damage;
if(the_player.hp <= 0) {
printf("that %s was too much for you. you die.\n", attacker->attack);
exit(0);
}
}
delete_mob_iterator(iter);
}
last_attack_time += attack_period;
}
static int last_spawn_time = 0;
const int spawn_period = 120;
while(time - last_spawn_time > spawn_period) {
if(rand() % MONSTER_RARITY == 0) {
for(int i = 0; i < NUM_DIRECTIONS; i++) {
exit_t *exit = (the_player.current_room->exits + i);
if(exit->dest != NULL && !exit->locked) {
spawn_new_monster(&exit->dest->mob);
}
}
}
last_spawn_time += spawn_period;
}
}
void print_border(char a, char b, int length) {
for(int i = 0; i < length; i++)
putchar(i % 2 == 0 ? a : b);
putchar('\n');
}
int main(int argc, char **argv) {
//load level from cmd line arg
if(argc > 2) {
printf(usage, argv[0], default_level);
exit(1);
}
char *welcome_message = "Welcome to %s, the CS 61C adventure extravaganza!\n";
int border_length = strlen(welcome_message) + strlen(argv[0]) - 3;
print_border('-', '=', border_length);
printf(welcome_message, argv[0]);
print_border('-', '=', border_length);
room_t *initial_room = NULL;
if(argc == 1) {
initial_room = load_level(default_level);
assert(initial_room != NULL);
for (int i = 0; i < num_rooms; i++) {
room_array[i].puzzle.description_fxn = get_puzzle_description(i);
room_array[i].puzzle.interact_fxn = get_puzzle_solver(i);
}
} else {
initial_room = load_level(argv[1]); // returns a room array or null
}
assert(initial_room != NULL);
init_player(initial_room);
printf("You wake up.\n");
look(0, NULL);
// Read-eval-print loop
for(;;) {
char buf[256];
char *words[32];
int num_words;
char delimiters[] = " \t\n";
printf("> "); fflush(stdout);
fgets(buf, 256, stdin);
if(feof(stdin)) {
printf("\n");
break;
}
num_words = tokenizer(buf, words, delimiters);
char *command_name = words[0];
if(command_name == NULL) continue;
// try to find a command to do
cmd_fxn_t cmd_to_do = lookup_command(command_name);
if(cmd_to_do != NULL) {
// and do it
int elapsed_time = cmd_to_do(num_words, words);
tick_world(elapsed_time, is_player_vulnerable(command_name));
} else {
printf("Huh?\n");
}
}
}
This is commands.c
Code:
#include "commands.h"
#include "common.h"
#include "level.h"
#include "monsters.h"
#include "game.h"
// A name/command pair
typedef struct {
char *name;
cmd_fxn_t fxn;
bool player_vulnerable; // Whether or not monsters can attack the player during this command
} cmd_entry_t;
// commands[] maps command names to command functions
cmd_entry_t commands[] = {
{"look", look, true},
{"attack", attack, true},
{"dawdle", dawdle, true},
{"wait", dawdle, true},
{"quit", quit, true},
{"exit", quit, true},
{"status", status, true},
{"help", help, true},
{"cast", cast, true},
// TA FUNCTION FOR PUZZLES
{"interact", interact, false},
// movement aliases
{"go", go, false},
{"walk", go, false},
{"move", go, false},
{"north", go_north, false},
{"n", go_north, false},
{"south", go_south, false},
{"s", go_south, false},
{"east", go_east, false},
{"e", go_east, false},
{"west", go_west, false},
{"w", go_west, false},
{"up", go_up, false},
{"u", go_up, false},
{"down", go_down, false},
{"d", go_down, false},
};
const unsigned int num_commands = sizeof(commands) / sizeof(cmd_entry_t);
// finds the command with the given name string in commands[]
// returns NULL if the command is not found
cmd_fxn_t lookup_command(char *name) {
for(int i = 0; i < num_commands; i++) {
if(!strcmp(name, commands[i].name)) {
return commands[i].fxn;
}
}
return NULL;
}
bool is_player_vulnerable(char *name) {
for(int i = 0; i < num_commands; i++) {
if(!strcmp(name, commands[i].name)) {
return commands[i].player_vulnerable;
}
}
// We have no out-of-bandwidth failure value, so just bail
assert(false);
return false; // to avoid a compiler error
}
// prints the player's status
int status(int argc, char **argv) {
printf("level: %d\n", get_level(the_player.experience));
printf("exp: %d\n", the_player.experience);
printf("hp: %d/%d\n", the_player.hp, the_player.max_hp);
i_love_additional_status_its_so_bad();
return STATUS_TIME;
}
// attacks the first monster of monster type argv[1]
int attack(int argc, char **argv) {
if(argc == 1) {
printf("Please specify a monster to attack.\n");
return 0;
}
// find the monster
monster_t *target = find_monster(&the_player.current_room->mob, argv[1]);
// give up if we can't find it
if(target == NULL) {
printf("There's no %s here...\n", argv[1]);
return 0;
}
// inflict damage
int damage_amount = the_player.level;
printf("You attack the %s for %d damage...\n", target->name, damage_amount);
damage(target, damage_amount);
return ATTACK_TIME;
}
// waits for the specified number of seconds (15 by default)
int dawdle(int argc, char **argv) {
int amount = argc == 2 ? atoi(argv[1]) : DAWDLE_DEFAULT_TIME;
printf("You %s for %d seconds...\n", argv[0], amount);
return amount;
}
// prints out the room description, the exits, and monsters
int look(int argc, char **argv) {
room_t *r = the_player.current_room;
printf("%s\n", r->description);
if(r->puzzle.description_fxn != NULL) {
r->puzzle.description_fxn(argc, argv);
}
int num_exits = 0;
for(int i = 0; i < NUM_DIRECTIONS; i++) {
if(r->exits[i].dest != NULL) {
num_exits++;
}
}
switch(num_exits) {
case 0:
break;
case 1:
for(int i = 0; i < NUM_DIRECTIONS; i++) {
if(r->exits[i].dest != NULL) {
printf("There is an exit %s%s%s%s.\n",
(i == UP || i == DOWN) ? "" : "to the ",
direction_names[i],
(i == UP || i == DOWN) ? "wards" : "",
r->exits[i].locked ? " (locked)" : "");
break;
}
}
break;
default:
printf("There are exits");
int exits_remaining = num_exits;
int i = 0;
while(exits_remaining) {
if(r->exits[i].dest != NULL) {
exits_remaining--;
printf(" %s%s%s", direction_names[i],
r->exits[i].locked ? " (locked)" : "",
exits_remaining == 1 ? " and" :
exits_remaining == 0 ? ".\n" :
","
);
}
if(exits_remaining == 0) break;
i++;
}
}
if(num_monsters(&r->mob) > 0) {
print_monsters(&r->mob);
}
return LOOK_TIME;
}
// calls the puzzle function for the current room
int interact(int argc, char **argv) {
if (the_player.current_room->puzzle.interact_fxn != NULL) {
return the_player.current_room->puzzle.interact_fxn(argc, argv);
} else {
printf("There is no puzzle in this room.\n");
return INTERACT_TIME;
}
}
// quit the game
int quit(int argc, char **argv) {
printf("goodbye!\n");
exit(0);
}
int help(int argc, char **argv) {
printf("available commands:\n");
unsigned int num_commands = sizeof(commands) / sizeof(cmd_entry_t);
for (int i = 0; i < num_commands; i++) {
printf("\t%s\n",commands[i].name);
}
return HELP_TIME;
}
// go moves the player from room to room by updating the_player.current_room
// and returns the amount of time movement has taken
// the argc and argv[] arguments are passed similarly to command-line arguments
// a typical "go" command would be:
// > go north
// and would be passed in as:
// argc = 2, argv = {"go", "north"}
int go(int argc, char **argv) {
/*** YOUR CODE HERE ***/
printf("What's this!? You can't move! You'll need to implement the go() function before you can get out of this place...\n");
// print the room description
assert(look(0, NULL) == 0); // we're assuming that look doesn't take any time
return MOVE_TIME;
}
// cast() handles spellcasting
// uses get_spell() to check level_table[] in game.c for a spell name that matches argv[1]
// and acquire the corresponding function pointer
// uses get_spell_level() to check that the spell's level is <= the player's level before casting
// this function should return whatver the spell itself returns.
int cast(int argc, char **argv) {
// for part 3, remove this line
printf("Cast? There's no such thing as magic...\n");
return 0;
}
PLS help!