262 lines
No EOL
7.8 KiB
C++
262 lines
No EOL
7.8 KiB
C++
#include "Map.hpp"
|
|
|
|
#include <fstream>
|
|
|
|
bool operator==(uint32_t lhs, TileType rhs) {
|
|
return lhs == static_cast<uint32_t>(rhs);
|
|
}
|
|
|
|
bool operator&(uint8_t lhs, MapFlags rhs)
|
|
{
|
|
return lhs & static_cast<uint8_t>(rhs);
|
|
}
|
|
|
|
bool operator==(int lhs, TileType rhs)
|
|
{
|
|
return lhs == static_cast<int>(rhs);
|
|
}
|
|
|
|
auto operator<=>(int lhs, TileType rhs)
|
|
{
|
|
return lhs <=> static_cast<int>(rhs);
|
|
}
|
|
|
|
MapError Map::populate_vertex_array() {
|
|
if (!tiles) return {"Map: [Loading] Tilemap is not loaded", 2};
|
|
|
|
atlas.vertices.setPrimitiveType(sf::PrimitiveType::Triangles);
|
|
atlas.vertices.resize(map_size.x * map_size.y * 6);
|
|
|
|
const auto xw = static_cast<float>(atlas.tile_size.x);
|
|
const auto yw = static_cast<float>(atlas.tile_size.y);
|
|
const auto tex_w = static_cast<float>(atlas.tile_size.x);
|
|
const auto tex_h = static_cast<float>(atlas.tile_size.y);
|
|
for (uint32_t x = 0; x < map_size.y; x++) {
|
|
for (uint32_t y = 0; y < map_size.z; y++)
|
|
{
|
|
const int32_t tile = tiles[x + y * map_size.y];
|
|
if (tile < -atlas.wall_tiles || tile > atlas.other_tiles) return {"Map: [Loading] Invalid tile! Tile type does not have a texture; ID: " + std::to_string(tile), 3};
|
|
// map tile type to atlas
|
|
/*
|
|
* Atlas:
|
|
* +++++
|
|
* +++--
|
|
* ---##
|
|
*
|
|
* + = wall
|
|
* # = special
|
|
* - = other
|
|
*
|
|
* wall_tiles = 8
|
|
* other_tiles = 5
|
|
* special_tiles = 2
|
|
*
|
|
* Tile:
|
|
* -1 <= wall
|
|
* 0 == special @ .type == tile_type
|
|
* 1 >= other
|
|
*/
|
|
if (tile == 0) return {"Map: [Loading] [Not Implemented!] Tile is a special tile", 3};
|
|
|
|
// atlas tile index
|
|
const uint32_t atlas_tile = atlas.wall_tiles + (tile - 1);
|
|
if (atlas_tile >= atlas.wall_tiles + atlas.other_tiles) return {"Map: [Loading] Invalid tile! Tile type does not have a texture", 3};
|
|
|
|
// add the vertices
|
|
const auto xf = static_cast<float>(x * atlas.tile_size.x);
|
|
const auto yf = static_cast<float>(y * atlas.tile_size.y);
|
|
const uint32_t tile_x = atlas_tile % atlas.tile_count.x;
|
|
const uint32_t tile_y = atlas_tile / atlas.tile_count.x;
|
|
const auto tex_x = static_cast<float>(tile_x * atlas.tile_size.x);
|
|
const auto tex_y = static_cast<float>(tile_y * atlas.tile_size.y);
|
|
|
|
sf::Vertex tl = {{xf, yf}, sf::Color::White, {tex_x, tex_y}};
|
|
sf::Vertex tr = {{xf + xw, yf}, sf::Color::White, {tex_x + tex_w, tex_y}};
|
|
sf::Vertex bl = {{xf, yf + yw}, sf::Color::White, {tex_x, tex_y + tex_h}};
|
|
sf::Vertex br = {{xf + xw, yf + yw}, sf::Color::White, {tex_x + tex_w, tex_y + tex_h}};
|
|
|
|
atlas.vertices.append(tl);
|
|
atlas.vertices.append(tr);
|
|
atlas.vertices.append(bl);
|
|
|
|
atlas.vertices.append(bl);
|
|
atlas.vertices.append(tr);
|
|
atlas.vertices.append(br);
|
|
}
|
|
}
|
|
|
|
return {"Map: [Loading] Success", 0};
|
|
}
|
|
|
|
void Map::LoadDefaultTilemap() {
|
|
atlas.wall_tiles = 0;
|
|
atlas.other_tiles = 1;
|
|
atlas.special_tiles = 0;
|
|
atlas.tile_count = {1, 1};
|
|
atlas.tile_size = {16, 16};
|
|
if (!atlas.texture.loadFromFile(ASSETS_PATH "/default_tilemap.png")) {
|
|
throw std::runtime_error("Map: [Loading] Could not load default tilemap -> Fatal");
|
|
}
|
|
}
|
|
|
|
Map::Map(): atlas() {
|
|
}
|
|
|
|
|
|
#include <iostream>
|
|
#include <cstring>
|
|
|
|
#include <filesystem>
|
|
|
|
MapError Map::load(const std::filesystem::path& path)
|
|
{
|
|
// opening the file and checking the magic number
|
|
std::ifstream file(path, std::ios::binary | std::ios::in);
|
|
|
|
if (!file.is_open()) {
|
|
return {"Map: [Loading] Could not open file: " + path.string(), 1};
|
|
}
|
|
|
|
char magic[4];
|
|
file.read(magic, 4);
|
|
|
|
if (std::memcmp(magic, "CYMF", 4) != 0) {
|
|
return {"Map: [Loading] Invalid magic number: " + std::string(magic, 4) + " (expected CYMF)", 1};
|
|
}
|
|
|
|
// reading the version
|
|
uint8_t version[3];
|
|
file.read(reinterpret_cast<char*>(version), 3);
|
|
if (version[0] != MAP_VERSION_MAJOR || version[1] > MAP_VERSION_MINOR)
|
|
{
|
|
return {"Map: [Loading] Invalid version; Current: " MAP_VERSION_STRING, 1};
|
|
}
|
|
|
|
// reading the flags
|
|
uint8_t flags;
|
|
file.read(reinterpret_cast<char*>(&flags), 1);
|
|
|
|
// flag CustomTilemap -> load the tilemap
|
|
if (flags & MapFlags::CustomTilemap)
|
|
{
|
|
uint32_t filepath_buffer_size;
|
|
file.read(reinterpret_cast<char*>(&filepath_buffer_size), 4);
|
|
|
|
char* filepath_buffer = new char[filepath_buffer_size];
|
|
file.read(filepath_buffer, filepath_buffer_size);
|
|
|
|
return {"Map: [Loading] [Not Implemented] Custom Tilemap is not implemented. Tilemap file: " + std::string(filepath_buffer, filepath_buffer_size), 1};
|
|
|
|
delete[] filepath_buffer;
|
|
}
|
|
else {
|
|
LoadDefaultTilemap();
|
|
}
|
|
|
|
|
|
// load the map info
|
|
uint32_t map_info[3];
|
|
file.read(reinterpret_cast<char*>(map_info), 12);
|
|
map_size = sf::Vector3<size_t>(static_cast<size_t>(map_info[0])*map_info[1], map_info[0], map_info[1]);
|
|
|
|
// load the tiles
|
|
tiles = new int[map_info[0] * map_info[1]];
|
|
for (int i = 0; i < map_info[0] * map_info[1]; i++)
|
|
{
|
|
// read the special if needed
|
|
file.read(reinterpret_cast<char*>(&tiles[i]), 4);
|
|
if (tiles[i] == TileType::Special)
|
|
{
|
|
MapSpecial special{};
|
|
file.read(reinterpret_cast<char*>(&special), sizeof(MapSpecial));
|
|
// get position
|
|
uint32_t tile_x = i % map_info[0];
|
|
uint32_t tile_y = i / map_info[0];
|
|
specials.emplace_back(std::pair<sf::Vector2u, MapSpecial>({tile_x, tile_y}, special));
|
|
}
|
|
}
|
|
|
|
// load the player spawn
|
|
uint32_t t_player_spawn[2];
|
|
file.read(reinterpret_cast<char*>(t_player_spawn), 8);
|
|
player_spawn = sf::Vector2u{t_player_spawn[0], t_player_spawn[1]};
|
|
if (player_spawn.x >= map_size.y || player_spawn.y >= map_size.z)
|
|
{
|
|
return {"Map: [Loading] Player: Spawn out of bounds", 2};
|
|
}
|
|
int player_tile = tiles[player_spawn.x + player_spawn.y * map_size.x];
|
|
if (player_tile <= TileType::Special)
|
|
{
|
|
return {"Map: [Loading] Player: Spawn is not a valid tile (invalid: wall, special; valid: Floor)", 2};
|
|
}
|
|
|
|
// load all the enemy spawns
|
|
uint32_t number_enemy_spawns;
|
|
file.read(reinterpret_cast<char*>(&number_enemy_spawns), 4);
|
|
if (number_enemy_spawns > map_size.x)
|
|
{
|
|
return {"Map: [Loading] Enemies: Too many enemy spawns (More than tile in the map)", 3};
|
|
}
|
|
for (int i = 0; i < number_enemy_spawns; i++)
|
|
{
|
|
uint32_t t_enemy_spawn[2];
|
|
file.read(reinterpret_cast<char*>(t_enemy_spawn), 8);
|
|
if (t_enemy_spawn[0] >= map_size.x || t_enemy_spawn[1] >= map_size.y)
|
|
{
|
|
return {"Map: [Loading] Enemy: Spawn out of bounds", 4};
|
|
}
|
|
if (tiles[t_enemy_spawn[0] + t_enemy_spawn[1] * map_size.y] <= TileType::Special)
|
|
{
|
|
return {"Map: [Loading] Enemy: Spawn is not a valid tile (invalid: wall, special; valid: Floor)", 4};
|
|
}
|
|
if (t_enemy_spawn[0] == player_spawn.x && t_enemy_spawn[1] == player_spawn.y)
|
|
{
|
|
return {"Map: [Loading] Enemy: Spawn is the same as the player spawn", 4};
|
|
}
|
|
enemy_spawns.emplace_back(t_enemy_spawn[0], t_enemy_spawn[1]);
|
|
}
|
|
|
|
// Everything went well
|
|
return populate_vertex_array();
|
|
}
|
|
|
|
sf::Vector2u Map::getSize() const
|
|
{
|
|
return {static_cast<uint32_t>(map_size.y), static_cast<uint32_t>(map_size.z)};
|
|
}
|
|
|
|
void Map::draw(sf::RenderTarget& target, sf::RenderStates states) const
|
|
{
|
|
if (!tiles) return;
|
|
|
|
// apply the transform
|
|
states.transform *= getTransform();
|
|
|
|
// apply the tileset texture
|
|
states.texture = &atlas.texture;
|
|
|
|
// draw the vertex array
|
|
target.draw(atlas.vertices, states);
|
|
}
|
|
|
|
|
|
#ifdef _DEBUG
|
|
void Map::debug()
|
|
{
|
|
std::cout << "Map Debug" << std::endl;
|
|
std::cout << "\tSize : " << map_size.x << ", " << map_size.y << ", " << map_size.z << std::endl;
|
|
std::cout << "\tTiles : " << tiles << std::endl;
|
|
for (auto& special : specials)
|
|
{
|
|
std::cout << "\t\tSpecial : " << special.first.x << ", " << special.first.y << std::endl;
|
|
std::cout << "\t\t\tType : " << special.second.type << std::endl;
|
|
std::cout << "\t\t\tPortal : " << special.second.portal_end[0] << ", " << special.second.portal_end[1] << std::endl;
|
|
}
|
|
std::cout << "\t\tEnemy Spawns : " << enemy_spawns.size() << std::endl;
|
|
for (auto& spawn : enemy_spawns)
|
|
{
|
|
std::cout << "\t\t\tSpawn : " << spawn.x << ", " << spawn.y << std::endl;
|
|
}
|
|
std::cout << "\t\tPlayer Spawn : " << player_spawn.x << ", " << player_spawn.y << std::endl;
|
|
}
|
|
#endif |