Newer
Older
void init_map_stack(void) {
map * current_map(void) {
if (mstack.length <= 0)
return NULL;
return &mstack.maps[mstack.length-1];
}
void place_player(map *m, int y, int x, direction dir) {
m->player_x = x;
m->player_y = y;
m->player_direction = dir;
}
void place_entity(map *m, int y, int x, int id, int category, int *stats, char display_symbol) {
// Creates entity
entity * e = malloc(sizeof(entity));
e->id = id;
e->category = category;
e->stats = stats;
e->display_symbol = display_symbol;
// Place it on the map
m->entities[coord_idx(y, x)] = e;
}
entity * create_entity(char type, int id) {
entity * i = malloc(sizeof(entity));
i->id = id;
i->stats = NULL;
switch (type) {
case '@': i->category = FLAG; break;
case 'O':
case 'X': i->category = SWI; break;
case 'M': i->category = MONSTER; break;
case 'A': i->category = NPC; break;
case 'B': i->category = PUSHABLE; break;
default: printf("create_entity : unknown type"); break;
}
return i;
}
direction char_dir(char dir) {
switch (dir) {
case '^': return UP;
case 'v': return DOWN;
case '<': return LEFT;
case '>': return RIGHT;
default: return UNKNOWN;
}
}
// Internal function to init a map with a name
map * internal_init_map_with_name(const char * name) {
if (mstack.length >= MAX_MAPS - 1) {
printf("load_map: can't load a new map, the maximum number has been reached.\n");
return current_map();
mstack.length++;
m = current_map();
/* allocating enough space to hold the map */
m->name = (char *) malloc(sizeof(char) * (strlen(name) + 1));
strcpy(m->name, name);
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
return m;
}
// Internal function for map array initialization
void init_map_arrays(map * m) {
m->entities = (entity **) calloc(sizeof(entity *), m->width * m->height);
m->floor = (tile **) malloc(sizeof(tile *) * m->width * m->height);
// Allocate an empty floor tile for every tile.
tile *t;
for(int i = 0; i < m->width*m->height; i++) {
t = malloc(sizeof(tile));
t->category = EMPTY;
t->obstacle = false;
m->floor[i] = t;
}
}
map * create_empty_map(const char * name, const int width, const int height) {
map * m = internal_init_map_with_name(name);
m->width = width;
m->height = height;
init_map_arrays(m);
return m;
}
map * load_map(const char * name, const char * data) {
map * m = internal_init_map_with_name(name);;
const char *ch = strchr(data, '\n');
if (!ch) {
fprintf (stderr, "Error: cannot find line return in map description!");
exit(EXIT_FAILURE);
}
m->width = ch - data;
m->height = 0;
while (ch) {
ch = strchr(ch+1, '\n');
m->height++;
}
int nth_entity = 0;
ch = data;
tile * f;
entity * i;
for (int y=0; y<m->height; y++) {
for (int x=0; x<m->width; x++) {
f = malloc(sizeof(tile));
f->category = EMPTY;
f->obstacle = false;
i = NULL;
switch (*ch) {
case ' ': f->category=GRASS; break;
case '+':
case '|':
case '-': f->category=WALL; f->obstacle = true; break;
case '~': f->category=WATER; break;
case ']':
case '[': f->category=DOOR; f->obstacle = true; break;
case '@':
case 'O':
case 'X':
case 'M':
case 'A':
case 'B':
i = create_entity(*ch, nth_entity);
nth_entity++;
break;
case '^':
case 'v':
case '<':
case '>': f->category=GRASS;
m->player_x = x;
m->player_y = y;
m->player_direction = char_dir(*ch);
break;
default:
fprintf(stderr, "Unknown map character '%c'!\n",*ch);
}
m->floor[y*m->width + x] = f;
m->entities[y*m->width+x] = i;
ch++;
}
assert (*ch == '\n');
ch++;
}
map * unload_map(void) {
if (mstack.length > 0) {
map * m = current_map();
for (int i = 0; i < m->width * m->height; i++) {
if (m->entities[i] != NULL) {
if (m->entities[i]->stats)
free(m->entities[i]->stats);
free(m->entities[i]);
}
if (m->floor[i] != NULL) {
free(m->floor[i]);
}
}
free(m->entities);
free(m->floor);
mstack.length--;
} else {
printf("unload_map: Can't unload map: map stack is already empty.\n");
return current_map();
void free_map_stack(void) {
while (mstack.length > 0) {
unload_map();
}
int coord_idx(int y, int x) {
return y * current_map()->width + x;
int player_idx(void) {
return coord_idx(m->player_y, m->player_x);
bool is_obstacle(int y, int x) {
return current_map()->floor[coord_idx(y, x)]->obstacle;
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
void show_map(void) {
map * m = current_map();
for (int y = 0; y < m->height; y++) {
for (int x = 0; x < m->width; x++) {
int i = coord_idx(y, x);
// the player has absolute priority for the drawing
if (m->player_x == x && m->player_y == y) {
switch (m->player_direction) {
case UP:
printf("^");
break;
case DOWN:
printf("v");
break;
case LEFT:
printf("<");
break;
case RIGHT:
printf(">");
break;
default:
printf("?");
break;
}
continue;
}
// then entities are displayed in front of tiles
if (m->entities[i]) {
entity * e = m->entities[i];
if (e->category == FLAG) {
printf("@");
} else if (e->category == SWI) {
if (e->stats && e->stats[0] == ACTIVATED)
printf("O");
else
printf("X");
} else if (e->category == MONSTER) {
printf("M");
} else if (e->category == NPC) {
printf("A");
} else if (e->category == PUSHABLE) {
printf("B");
} else if (e->category == TRAP) {
printf(" ");
} else if (e->category == ITEM) {
printf("I");
} else { // unknown
printf("!");
}
// tiles are displayed last
} else {
tile * t = m->floor[i];
if (t->category == WALL)
printf("#"); // rip pretty - | + walls
else if (t->category == WATER)
printf("~");
else if (t->category == GRASS)
printf(" ");
else if (t->category == DOOR)
printf("[");
else
printf("§"); // empty or unknown
}
}
printf("\n");
}
}