timesynk/engine/map.c

174 lines
4.8 KiB
C

#include "map.h"
#include "tile.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h> // printf
/*
================================
struct Map *newMap(int width, int height)
This function allocates memory for a 2D array of Tile pointers. Calls nullMap before returning the newly allocated Map.
Returns: NULL on malloc failure for: map, map->tiles, map->tiles[x]
TODO: Map->tiles could be fragmented - figure out a way to use one malloc call for both x and y.
================================
*/
struct Map *newMap(int width, int height, int depth) {
struct Map *map = malloc(sizeof(struct Map));
if (map == NULL) {
// TODO: ERROR: could not allocate memory for Map
return NULL;
}
map->width = width;
map->height = height;
map->depth = depth;
map->tiles = malloc(width * sizeof(struct Tile ***));
if (map->tiles == NULL) {
free(map);
printf("ERR: malloc width failed\n");
return NULL;
}
int i,j;
// TODO: error check
for(i=0;i<width;i++) {
map->tiles[i] = malloc(height * sizeof(struct Tile **));
if (map->tiles[i] == NULL) {
printf("ERR: malloc height failed\n");
return NULL;
}
for(j=0;j<height;j++) {
map->tiles[i][j] = malloc(depth * sizeof(struct Tile*));
if (map->tiles[i][j] == NULL) {
printf("ERR: malloc depth failed\n");
return NULL;
}
}
}
nullMap(map);
return map;
}
/*
================================
nullMap(struct Map *map)
This function takes a fully allocated Map and sets all Tile pointers to NULL.
================================
*/
int nullMap(struct Map *map) {
if (map == NULL) {
// TODO: ERROR: zeroMap passed NULL map
return 1;
}
int i, j, k;
for(i=0;i < map->width;i++) {
for(j=0;j < map->height;j++) {
for(k=0;k < map->depth;k++) {
map->tiles[i][j][k] = NULL;
}
}
}
return 0;
}
/*
================================
freeMap(struct Map *map, int flags)
This function frees the given map. If flags contains MAP_FREE_TILES, then the Tiles themselves are also freed.
================================
*/
#define MAP_FREE_TILES 1
void freeMap(struct Map *map, int flags) {
if (map == NULL)
return;
int i, j, k;
for(i=0;i < map->width;i++) {
for(j=0;j < map->height;j++) {
for(k=0;k < map->depth;k++) {
if (flags & MAP_FREE_TILES) {
//freeTile(map->tiles[i][j][k]);
}
//free(map->tiles[i][j][k]);
}
free(map->tiles[i][j]);
}
free(map->tiles[i]);
}
free(map->tiles);
free(map);
}
/* Tile -> Map interaction */
int moveTile(struct Map *map, struct Tile *tile, float x, float y, float z) {
//printf("request to move %fx%fx%f distance from %fx%fx%f\n", x, y, z, tile->x, tile->y, tile->z);
float target_x = tile->x + x;
float target_y = tile->y + y;
float target_z = tile->z + z;
//printf("absolute new pos %fx%fx%f\n", target_x, target_y, target_z);
int tile_x = (int)target_x;
int tile_y = (int)target_y;
int tile_z = (int)target_z;
//float leftover_x = target_x - tile_x;
//float leftover_y = target_y - tile_y;
//float leftover_z = target_z - tile_z;
//printf("move to %dx%dx%d with %fx%fx%f leftover\n", tile_x, tile_y, tile_z, leftover_x, leftover_y, leftover_z);
//printf(" MAP: %dx%dx%d vs %fx%fx%f\n", map->width, map->height, map->depth, target_x, target_y, target_z);
if (target_x < -0.5f || target_y < -0.5f || target_z < -0.5f || target_x >= map->width || target_y >= map->height || target_z >= map->depth) {
return 1;
}
if (tile_x != (int)tile->x || tile_y != (int)tile->y || tile_z != (int)tile->z) {
if (map->tiles[tile_x][tile_y][tile_z] == NULL) {
map->tiles[tile_x][tile_y][tile_z] = tile;
//return 2;
} else {
removeTile(tile); // remove from current position
appendTile(map->tiles[tile_x][tile_y][tile_z], tile);
}
}
tile->x = target_x;
tile->y = target_y;
tile->z = target_z;
return 0;
}
int addTileToMap(struct Map *map, struct Tile *tile, float x, float y, float z) {
if (map == NULL)
return -1;
if (tile == NULL)
return -2;
int tile_x = (int)x;
int tile_y = (int)y;
int tile_z = (int)z;
// if out of bounds, add to nearest cell
if (tile_x >= map->width) {
tile_x = map->width-1;
} else if (tile_x < 0) {
tile_x = 0;
}
if (tile_y >= map->height) {
tile_y = map->height-1;
} else if (tile_y < 0) {
tile_y = 0;
}
if (tile_z >= map->depth) {
tile_z = map->depth-1;
} else if (tile_z < 0) {
tile_z = 0;
}
// set tile's x, y, and z params
tile->x = tile_x;
tile->y = tile_y;
tile->z = tile_z;
if (map->tiles[tile_x][tile_y][tile_z] == NULL) {
map->tiles[tile_x][tile_y][tile_z] = tile;
return 0;
}
// if existing, append to tile linked list there
appendTile(map->tiles[tile_x][tile_y][tile_z], tile);
return 0;
}