Mentions légales du service

Skip to content
Snippets Groups Projects
map.c 7.97 KiB
Newer Older
static map_stack mstack;

void init_map_stack(void) {
    mstack.length = 0;
}

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;
    i->display_symbol = type;
    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;
SZCZEPANSKI Marin's avatar
SZCZEPANSKI Marin committed
    case '_': i->category = TRAP; break;
    case 'I': i->category = ITEM; 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);
    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++;
    }

    init_map_arrays(m);
    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;
SZCZEPANSKI Marin's avatar
SZCZEPANSKI Marin committed
                case 'T': f->category=TARGET; break;
                case '@':
                case 'O':
                case 'X':
                case 'M':
                case 'A':
                case 'B':
SZCZEPANSKI Marin's avatar
SZCZEPANSKI Marin committed
                case '_': f->category = GRASS;
                          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");
void free_map_stack(void) {
    while (mstack.length > 0) {
        unload_map();
    }    

int coord_idx(int y, int x) {
    return y * current_map()->width + x;
    map *m = current_map();
    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;


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("[");
SZCZEPANSKI Marin's avatar
SZCZEPANSKI Marin committed
                else if (t->category == TARGET)
                    printf("T");
                else
                    printf("§"); // empty or unknown
            }
        }
        printf("\n");
    }
}