Nimbin2git.christianimmanuel.de / Games / Entropie / map.c

Entropie git · main

git clone https://git.christianimmanuel.de/games/Entropie.gitwget https://git.christianimmanuel.de/games/Entropie/archive/Entropie.tar.gz
map.c 7 KB · 207 lines raw
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "map.h"
#include "collectable.h"

Tile* Tile_create() {
    Tile* t = (Tile*)malloc(sizeof(Tile));
    if (!t)
        fprintf(stderr, "Failled to allocate memory: Tile_create();");
    return t;
}


void Map_log(void) {
    for (int i= 0; i < MAP_HEIGHT; i++) {
        printf("\n");
        for (int j= 0; j < MAP_WIDTH; j++) {
            printf("%d", map[i][j]);
        }
    }
    for (int y = 0; y < MAP_HEIGHT; y++)
        for (int x = 0; x < MAP_WIDTH; x++)
            for (int i = 0; i < map_objects_count[y][x]; i++)
                    printf("OBJECT [%d|%d] %d: %d\n", y, x, map_objects_count[y][x], map_objects[y][x][i]);
}

int Map_load(const char* filename, Character* characters, int characters_size, Object* object_first) {
    FILE* file = fopen(filename, "r");
    if (!file) {
        fprintf(stderr, "Error opening map file\n");
        return -1;
    }

    int map_width = 0;
    int map_height = 0;
    char line[1024];  // Buffer to hold each line

    // First, determine the width and height of the map by reading the file line by line
    while (fgets(line, sizeof(line), file)) {
        map_height++;  // Increment height for each line
        int line_width = 0;

        // Split the line into words and count them
        char* token = strtok(line, " \n");
        while (token != NULL) {
            line_width++;
            token = strtok(NULL, " \n");
        }

        // Track the maximum width of any row to determine the map width
        if (line_width > map_width) {
            map_width = line_width;
        }
    }

    // Rewind the file pointer to start reading the map data
    rewind(file);

    // Dynamically allocate memory for the map
    map = (TileType**)malloc(map_height * sizeof(TileType*));
    map_objects = (MapObjectType***)malloc(map_height * sizeof(MapObjectType**));
    map_objects_count = (unsigned char**)malloc(map_height * sizeof(unsigned char*));
    if (!map || !map_objects) {
        fclose(file);
        fprintf(stderr, "Memory allocation for map failed\n");
        return -1;
    }

    for (int i = 0; i < map_height; i++) {
        map[i] = (TileType*)malloc(map_width * sizeof(TileType));
        map_objects[i] = (MapObjectType**)malloc(map_width * sizeof(MapObjectType*));
        map_objects_count[i] = (unsigned char*)malloc(map_width * sizeof(unsigned char));
        if (!map[i] || !map_objects[i]) {
            fclose(file);
            fprintf(stderr, "Memory allocation for map row failed\n");
            return -1;
        }
    }

    // Now load the map data
    Object* prev = object_first;
    int y = 0;
    while (fgets(line, sizeof(line), file)) {
        int x = 0;

        // Split the line into words and map them to tile types
        char* token = strtok(line, " \n");
        while (token != NULL) {
            Object* active = Object_create();
            active->x = x*TILE_SIZE;
            active->y = y*TILE_SIZE;
            active->w = TILE_SIZE;
            active->h = TILE_SIZE;
            // Map the string (word) to the appropriate tile type
#define TILE_CREATE(t)      \
    Tile* tile = Tile_create();     \
    active->parent_type = Object_Tile;     \
    active->parent = (void*)tile;     \
    map[y][x] = t;     \
    tile->type = t;
            if (strcmp(token, "..") == 0) {
                TILE_CREATE(TILE_EMPTY)
            } else if (strcmp(token, "##") == 0) {
                TILE_CREATE(TILE_WALL)
            } else if (strcmp(token, "==") == 0) {
                TILE_CREATE(TILE_HOUSE)
            } else if (strcmp(token, "~~") == 0) {
                TILE_CREATE(TILE_WATER)
            } else if (strcmp(token, "__") == 0) {
                TILE_CREATE(TILE_WAY)
            } else if (strcmp(token, "++") == 0) {
                TILE_CREATE(TILE_ROAD)
            } else if (strcmp(token, "––") == 0) {
                TILE_CREATE(TILE_TRACK)
            } else if (strcmp(token, ";;") == 0) {
                TILE_CREATE(TILE_GRAVEL)
            } else if (strcmp(token, "DD") == 0) {
                TILE_CREATE(TILE_DIRT)
            } else if (strcmp(token, "WW") == 0) {
                TILE_CREATE(TILE_GRASS)
            } else if (strcmp(token, "TT") == 0) {
                TILE_CREATE(TILE_TREE)
            } else if (strcmp(token, "PP") == 0) {
                TILE_CREATE(TILE_PLAYER_SPAWN)
            } else if (strcmp(token, "CC") == 0) {
                TILE_CREATE(TILE_CHARACTER_SPAWN)
            } else if (strcmp(token, "oo") == 0) {
                TILE_CREATE(TILE_COLLECTABLE)
#undef TILE_CREATE

            } else if (token[0] == 'o' && isdigit(token[1])) {
                map[y][x] = TILE_COLLECTABLE;
                int collectable_index = atoi(&token[1]);
                printf("Set position of object %d %d %d\n", x, y, collectable_index);
                Collectable* collectable = Collectable_create();
                collectable->object = active;
                active->parent_type = Object_Collectable;
                active->parent = (void*)collectable;

            } else if (token[0] == 'C' && isdigit(token[1])) {
                free(active);
                map[y][x] = TILE_CHARACTER_SPAWN;
                int char_index = atoi(&token[1]);
                Character* character = &characters[char_index];
                printf("Set position of character %d to (%d, %d)\n%p || %d\n", char_index, x * TILE_SIZE, y * TILE_SIZE, character, character->object->parent_type);
                active = character->object;
                active->x = x*TILE_SIZE;
                active->y = y*TILE_SIZE;
            } else {
                map[y][x] = TILE_EMPTY;
                active->parent_type = Object_Undefined;;
                active->parent = NULL;
            }

            Object_add(prev, active);
            x++;
            prev = active;
            token = strtok(NULL, " \n");
        }

        y++;
    }

    fclose(file);

    // Update global map dimensions
    MAP_WIDTH = map_width;
    MAP_HEIGHT = map_height;
    return 0;
}


// Check if the position is within the map and if the tile is passable
int Map_isPassable(float x, float y, float w, float h) {
    int tile_x_start = (int)(x / TILE_SIZE);
    int tile_y_start = (int)(y / TILE_SIZE);
    int tile_x_end = (int)((x + w) / TILE_SIZE);
    int tile_y_end = (int)((y + h) / TILE_SIZE);

    for (int ty = tile_y_start; ty <= tile_y_end; ty++) {
        for (int tx = tile_x_start; tx <= tile_x_end; tx++) {
            if (tx < 0 || tx >= MAP_WIDTH || ty < 0 || ty >= MAP_HEIGHT) {
                return 0; // Out of bounds
            }

            TileType tile = map[ty][tx];
            if (tile == TILE_WALL || tile == TILE_HOUSE || tile == TILE_TREE) {
                return 0; // Early exit on collision
            }
        }
    }
    return 1;
}

void Map_free() {
    for (int y = 0; y < MAP_HEIGHT; y++) {
        for (int x = 0; x < MAP_WIDTH; x++)
                free(map_objects[y][x]);
        free(map[y]);
        free(map_objects_count[y]);
    }
    free(map);
    free(map_objects_count);
}