Files
jaildoctors_dilemma/source/room.cpp

1419 lines
35 KiB
C++

#include "room.h"
#include <iostream>
#include <fstream>
#include <sstream>
// Carga las variables y texturas desde un fichero de mapa de tiles
std::vector<int> loadRoomTileFile(std::string file_path)
{
std::vector<int> tileMapFile;
const std::string filename = file_path.substr(file_path.find_last_of("\\/") + 1);
std::string line;
std::ifstream file(file_path);
// El fichero se puede abrir
if (file.good())
{
// Procesa el fichero linea a linea
//printf("Reading file %s\n", filename.c_str());
while (std::getline(file, line))
{ // Lee el fichero linea a linea
if (line.find("data encoding") != std::string::npos)
{
// Lee la primera linea
std::getline(file, line);
while (line != "</data>")
{ // Procesa lineas mientras haya
std::stringstream ss(line);
std::string tmp;
while (getline(ss, tmp, ','))
{
tileMapFile.push_back(std::stoi(tmp) - 1);
}
// Lee la siguiente linea
std::getline(file, line);
}
}
}
// Cierra el fichero
printf("TileMap loaded: %s\n", filename.c_str());
file.close();
}
else
{ // El fichero no se puede abrir
printf("Warning: Unable to open %s file\n", filename.c_str());
}
return tileMapFile;
}
// Carga las variables desde un fichero de mapa
room_t loadRoomFile(std::string file_path)
{
room_t room;
const std::string filename = file_path.substr(file_path.find_last_of("\\/") + 1);
std::string line;
std::ifstream file(file_path);
// El fichero se puede abrir
if (file.good())
{
// Procesa el fichero linea a linea
//printf("Reading file %s\n\n", filename.c_str());
while (std::getline(file, line))
{
// Si la linea contiene el texto [enemy] se realiza el proceso de carga de un enemigo
if (line == "[enemy]")
{
enemy_t enemy;
// enemy.renderer = renderer;
enemy.flip = false;
enemy.palette = p_zxspectrum;
do
{
std::getline(file, line);
// Encuentra la posición del caracter '='
int pos = line.find("=");
// Procesa las dos subcadenas
if (!setEnemy(&enemy, line.substr(0, pos), line.substr(pos + 1, line.length())))
{
printf("Warning: file %s\n, unknown parameter \"%s\"\n", filename.c_str(), line.substr(0, pos).c_str());
}
} while (line != "[/enemy]");
// Añade el enemigo al vector de enemigos
room.enemies.push_back(enemy);
}
// Si la linea contiene el texto [item] se realiza el proceso de carga de un item
else if (line == "[item]")
{
item_t item;
// item.renderer = renderer;
item.counter = 0;
item.color1 = stringToColor(p_zxspectrum, "yellow");
item.color2 = stringToColor(p_zxspectrum, "magenta");
do
{
std::getline(file, line);
// Encuentra la posición del caracter '='
int pos = line.find("=");
// Procesa las dos subcadenas
if (!setItem(&item, line.substr(0, pos), line.substr(pos + 1, line.length())))
{
printf("Warning: file %s\n, unknown parameter \"%s\"\n", filename.c_str(), line.substr(0, pos).c_str());
}
} while (line != "[/item]");
// Añade el item al vector de items
// const SDL_Point itemPos = {item.x, item.y};
// if (!itemTracker->hasBeenPicked(room.name, itemPos))
//{
// room.items.push_back(new Item(item));
// }
room.items.push_back(item);
}
// En caso contrario se parsea el fichero para buscar las variables y los valores
else
{
// Encuentra la posición del caracter '='
int pos = line.find("=");
// Procesa las dos subcadenas
if (!setVars(&room, line.substr(0, pos), line.substr(pos + 1, line.length())))
{
printf("Warning: file %s, unknown parameter \"%s\"\n", filename.c_str(), line.substr(0, pos).c_str());
}
}
}
// Cierra el fichero
printf("Room loaded: %s\n", filename.c_str());
file.close();
}
// El fichero no se puede abrir
else
{
printf("Warning: Unable to open %s file\n", filename.c_str());
}
return room;
}
// Asigna variables a partir de dos cadenas
bool setVars(room_t *room, std::string var, std::string value)
{
// Indicador de éxito en la asignación
bool success = true;
if (var == "tileMapFile")
{
room->tileMapFile = value;
}
else if (var == "name")
{
room->name = value;
}
else if (var == "bgColor")
{
room->bgColor = value;
}
else if (var == "border")
{
room->borderColor = value;
}
else if (var == "itemColor1")
{
room->itemColor1 = value;
}
else if (var == "itemColor2")
{
room->itemColor2 = value;
}
else if (var == "tileSetFile")
{
room->tileSetFile = value;
/*if (options->palette == p_zxspectrum)
{
tileSetFile = "standard.png";
}
else if (options->palette == p_zxarne)
{
tileSetFile = "standard_zxarne.png";
}*/
}
else if (var == "roomUp")
{
room->roomUp = value;
}
else if (var == "roomDown")
{
room->roomDown = value;
}
else if (var == "roomLeft")
{
room->roomLeft = value;
}
else if (var == "roomRight")
{
room->roomRight = value;
}
else if (var == "autoSurface")
{
if (value == "right")
{
room->autoSurfaceDirection = 1;
}
else
{
room->autoSurfaceDirection = -1;
}
}
else if (var == "" || var.substr(0, 1) == "#")
{
}
else
{
success = false;
}
return success;
}
// Asigna variables a una estructura enemy_t
bool setEnemy(enemy_t *enemy, std::string var, std::string value)
{
// Indicador de éxito en la asignación
bool success = true;
if (var == "animation")
{
enemy->animationString = value;
}
else if (var == "width")
{
enemy->w = std::stof(value);
}
else if (var == "height")
{
enemy->h = std::stof(value);
}
else if (var == "x")
{
enemy->x = std::stof(value) * BLOCK;
}
else if (var == "y")
{
enemy->y = std::stof(value) * BLOCK;
}
else if (var == "vx")
{
enemy->vx = std::stof(value);
}
else if (var == "vy")
{
enemy->vy = std::stof(value);
}
else if (var == "x1")
{
enemy->x1 = std::stoi(value) * BLOCK;
}
else if (var == "x2")
{
enemy->x2 = std::stoi(value) * BLOCK;
}
else if (var == "y1")
{
enemy->y1 = std::stoi(value) * BLOCK;
}
else if (var == "y2")
{
enemy->y2 = std::stoi(value) * BLOCK;
}
else if (var == "flip")
{
enemy->flip = stringToBool(value);
}
else if (var == "color")
{
enemy->color = value;
}
else if (var == "[/enemy]" || var == "tileSetFile" || var.substr(0, 1) == "#")
{
}
else
{
success = false;
}
return success;
}
// Asigna variables a una estructura item_t
bool setItem(item_t *item, std::string var, std::string value)
{
// Indicador de éxito en la asignación
bool success = true;
if (var == "tileSetFile")
{
item->tileSetFile = value;
}
else if (var == "counter")
{
item->counter = std::stoi(value);
}
else if (var == "x")
{
item->x = std::stof(value) * BLOCK;
}
else if (var == "y")
{
item->y = std::stof(value) * BLOCK;
}
else if (var == "tile")
{
item->tile = std::stof(value);
}
else if (var == "[/item]")
{
}
else
{
success = false;
}
return success;
}
// Constructor
Room::Room(room_t *room, SDL_Renderer *renderer, Screen *screen, Asset *asset, options_t *options, ItemTracker *itemTracker, int *itemsPicked, Debug *debug)
{
// Copia los punteros a objetos
this->renderer = renderer;
this->asset = asset;
this->screen = screen;
this->itemTracker = itemTracker;
this->itemsPicked = itemsPicked;
this->debug = debug;
this->options = options;
name = room->name;
bgColor = room->bgColor;
borderColor = room->borderColor;
itemColor1 = room->itemColor1 == ""?"yellow":room->itemColor1;
itemColor2 = room->itemColor2 == ""?"magenta":room->itemColor2;
roomUp = room->roomUp;
roomDown = room->roomDown;
roomLeft = room->roomLeft;
roomRight = room->roomRight;
tileSetFile = room->tileSetFile;
tileMapFile = room->tileMapFile;
autoSurfaceDirection = room->autoSurfaceDirection;
textureA = room->textureA;
textureB = room->textureB;
tileMap = room->tileMap;
// Inicializa variables
tileSize = 8;
mapWidth = 32;
mapHeight = 16;
paused = false;
counter = 0;
// itemColor1 = "magenta";
// itemColor2 = "yellow";
// autoSurfaceDirection = 1;
// Crea los enemigos
for (auto &enemy : room->enemies)
{
enemy.renderer = renderer;
enemies.push_back(new Enemy(enemy));
}
// Crea los items
for (auto &item : room->items)
{
const SDL_Point itemPos = {item.x, item.y};
if (!itemTracker->hasBeenPicked(room->name, itemPos))
{
item.renderer = renderer;
items.push_back(new Item(item));
}
}
// Crea los objetos
// loadRoomFile(file);
// texture = new Texture(renderer, asset->get(tileSetFile));
// texture = resource->getTexture(tileSetFile);
if (options->palette == p_zxspectrum)
{
texture = textureA;
}
else
{
texture = textureB;
}
tileSetWidth = texture->getWidth() / tileSize;
itemSound = JA_LoadSound(asset->get("item.wav").c_str());
// loadRoomTileFile(asset->get(tileMapFile));
// Calcula las superficies
setBottomSurfaces();
setTopSurfaces();
setLeftSurfaces();
setRightSurfaces();
setLeftSlopes();
setRightSlopes();
setAutoSurfaces();
// Busca los tiles animados
setAnimatedTiles();
// Crea la textura para el mapa de tiles de la habitación
mapTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT);
if (mapTexture == nullptr)
{
printf("Error: mapTexture could not be created!\nSDL Error: %s\n", SDL_GetError());
}
SDL_SetTextureBlendMode(mapTexture, SDL_BLENDMODE_BLEND);
// Pinta el mapa de la habitación en la textura
fillMapTexture();
// Establece el color del borde
screen->setBorderColor(stringToColor(options->palette, room->borderColor));
}
// Destructor
Room::~Room()
{
// Reclama la memoria utilizada por los objetos
// delete texture;
JA_DeleteSound(itemSound);
SDL_DestroyTexture(mapTexture);
for (auto enemy : enemies)
{
delete enemy;
}
for (auto item : items)
{
delete item;
}
for (auto a : aTile)
{
delete a.sprite;
}
}
// Devuelve el nombre de la habitación
std::string Room::getName()
{
return name;
}
// Devuelve el color de la habitación
color_t Room::getBGColor()
{
return stringToColor(options->palette, bgColor);
}
// Devuelve el color del borde
color_t Room::getBorderColor()
{
return stringToColor(options->palette, borderColor);
}
// Crea la textura con el mapeado de la habitación
void Room::fillMapTexture()
{
SDL_SetRenderTarget(renderer, mapTexture);
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00);
SDL_RenderClear(renderer);
// Los tileSetFiles son de 20x20 tiles. El primer tile es el 0. Cuentan hacia la derecha y hacia abajo
SDL_Rect clip = {0, 0, tileSize, tileSize};
for (int y = 0; y < mapHeight; ++y)
for (int x = 0; x < mapWidth; ++x)
{
// Tiled pone los tiles vacios del mapa como cero y empieza a contar de 1 a n.
// Al cargar el mapa en memoria, se resta uno, por tanto los tiles vacios son -1
// Tampoco hay que dibujar los tiles animados que estan en la fila 19 (indices)
const int index = (y * mapWidth) + x;
const bool a = (tileMap->at(index) >= 18 * tileSetWidth) && (tileMap->at(index) < 19 * tileSetWidth);
const bool b = tileMap->at(index) > -1;
if (b && !a)
{
clip.x = (tileMap->at(index) % tileSetWidth) * tileSize;
clip.y = (tileMap->at(index) / tileSetWidth) * tileSize;
texture->render(renderer, x * tileSize, y * tileSize, &clip);
// ****
if (debug->getEnabled())
{
if (clip.x != -tileSize)
{
clip.x = x * tileSize;
clip.y = y * tileSize;
SDL_SetRenderDrawColor(renderer, 64, 64, 64, 224);
SDL_RenderFillRect(renderer, &clip);
}
}
// ****
}
}
// ****
if (debug->getEnabled())
{
// BottomSurfaces
if (true)
{
for (auto l : bottomSurfaces)
{
SDL_SetRenderDrawColor(renderer, (rand() % 128) + 96, (rand() % 128) + 96, (rand() % 128) + 96, 0xFF);
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 0xFF);
SDL_RenderDrawLine(renderer, l.x1, l.y, l.x2, l.y);
}
}
// TopSurfaces
if (true)
{
for (auto l : topSurfaces)
{
SDL_SetRenderDrawColor(renderer, (rand() % 128) + 96, (rand() % 128) + 96, (rand() % 128) + 96, 0xFF);
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 0xFF);
SDL_RenderDrawLine(renderer, l.x1, l.y, l.x2, l.y);
}
}
// LeftSurfaces
if (true)
{
for (auto l : leftSurfaces)
{
SDL_SetRenderDrawColor(renderer, (rand() % 128) + 96, (rand() % 128) + 96, (rand() % 128) + 96, 0xFF);
SDL_SetRenderDrawColor(renderer, 0, 0, 255, 0xFF);
SDL_RenderDrawLine(renderer, l.x, l.y1, l.x, l.y2);
}
}
// RightSurfaces
if (true)
{
for (auto l : rightSurfaces)
{
SDL_SetRenderDrawColor(renderer, (rand() % 128) + 96, (rand() % 128) + 96, (rand() % 128) + 96, 0xFF);
SDL_SetRenderDrawColor(renderer, 255, 255, 0, 0xFF);
SDL_RenderDrawLine(renderer, l.x, l.y1, l.x, l.y2);
}
}
// LeftSlopes
if (true)
{
for (auto l : leftSlopes)
{
SDL_SetRenderDrawColor(renderer, (rand() % 128) + 96, (rand() % 128) + 96, (rand() % 128) + 96, 0xFF);
SDL_SetRenderDrawColor(renderer, 0, 255, 255, 0xFF);
SDL_RenderDrawLine(renderer, l.x1, l.y1, l.x2, l.y2);
}
}
// RightSlopes
if (true)
{
for (auto l : rightSlopes)
{
SDL_SetRenderDrawColor(renderer, (rand() % 128) + 96, (rand() % 128) + 96, (rand() % 128) + 96, 0xFF);
SDL_SetRenderDrawColor(renderer, 255, 0, 255, 0xFF);
SDL_RenderDrawLine(renderer, l.x1, l.y1, l.x2, l.y2);
}
}
// AutoSurfaces
if (true)
{
for (auto l : autoSurfaces)
{
SDL_SetRenderDrawColor(renderer, (rand() % 128) + 96, (rand() % 128) + 96, (rand() % 128) + 96, 0xFF);
SDL_RenderDrawLine(renderer, l.x1, l.y, l.x2, l.y);
}
}
}
// ****
SDL_SetRenderTarget(renderer, nullptr);
}
// Dibuja el mapa en pantalla
void Room::renderMap()
{
// Dibuja la textura con el mapa en pantalla
SDL_RenderCopy(renderer, mapTexture, nullptr, nullptr);
// Dibuja los tiles animados
if (!debug->getEnabled())
{
renderAnimatedTiles();
}
}
// Dibuja los enemigos en pantalla
void Room::renderEnemies()
{
for (auto enemy : enemies)
{
enemy->render();
}
}
// Dibuja los objetos en pantalla
void Room::renderItems()
{
for (auto item : items)
{
item->render();
}
}
// Actualiza las variables y objetos de la habitación
void Room::update()
{
if (paused)
{ // Si está en modo pausa no se actualiza nada
return;
}
// Actualiza el contador
counter++;
// Actualiza los tiles animados
updateAnimatedTiles();
for (auto enemy : enemies)
{ // Actualiza los enemigos
enemy->update();
}
for (auto item : items)
{ // Actualiza los items
item->update();
}
}
// Devuelve la cadena del fichero de la habitación contigua segun el borde
std::string Room::getRoom(int border)
{
switch (border)
{
case BORDER_TOP:
return roomUp;
break;
case BORDER_BOTTOM:
return roomDown;
break;
case BORDER_RIGHT:
return roomRight;
break;
case BORDER_LEFT:
return roomLeft;
break;
default:
break;
}
return "";
}
// Devuelve el tipo de tile que hay en ese pixel
tile_e Room::getTile(SDL_Point point)
{
const int pos = ((point.y / tileSize) * mapWidth) + (point.x / tileSize);
return getTile(pos);
}
// Devuelve el tipo de tile que hay en ese indice
tile_e Room::getTile(int index)
{
const int maxTile = mapWidth * mapHeight;
if (index < maxTile)
{
// Las filas 0-8 son de tiles t_wall
if ((tileMap->at(index) >= 0) && (tileMap->at(index) < 9 * tileSetWidth))
{
return t_wall;
}
// Las filas 9-17 son de tiles t_passable
else if ((tileMap->at(index) >= 9 * tileSetWidth) && (tileMap->at(index) < 18 * tileSetWidth))
{
return t_passable;
}
// Las filas 18-20 es de tiles t_animated
else if ((tileMap->at(index) >= 18 * tileSetWidth) && (tileMap->at(index) < 21 * tileSetWidth))
{
return t_animated;
}
// La fila 21 es de tiles t_slope_r
else if ((tileMap->at(index) >= 21 * tileSetWidth) && (tileMap->at(index) < 22 * tileSetWidth))
{
return t_slope_r;
}
// La fila 22 es de tiles t_slope_l
else if ((tileMap->at(index) >= 22 * tileSetWidth) && (tileMap->at(index) < 23 * tileSetWidth))
{
return t_slope_l;
}
// La fila 23 es de tiles t_kill
else if ((tileMap->at(index) >= 23 * tileSetWidth) && (tileMap->at(index) < 24 * tileSetWidth))
{
return t_kill;
}
}
return t_empty;
}
// Indica si hay colision con un enemigo a partir de un rectangulo
bool Room::enemyCollision(SDL_Rect &rect)
{
bool collision = false;
for (auto enemy : enemies)
{
collision |= checkCollision(rect, enemy->getCollider());
}
return collision;
}
// Indica si hay colision con un objeto a partir de un rectangulo
bool Room::itemCollision(SDL_Rect &rect)
{
for (int i = 0; i < (int)items.size(); ++i)
{
if (checkCollision(rect, items[i]->getCollider()))
{
itemTracker->addItem(name, items[i]->getPos());
delete items[i];
items.erase(items.begin() + i);
JA_PlaySound(itemSound);
*itemsPicked = *itemsPicked + 1;
return true;
}
}
return false;
}
// Recarga la textura
void Room::reLoadTexture()
{
texture->reLoad();
fillMapTexture();
for (auto enemy : enemies)
{
enemy->reLoadTexture();
}
for (auto item : items)
{
item->reLoadTexture();
}
}
// Recarga la paleta
void Room::reLoadPalette()
{
// Cambia el color de los items
for (auto item : items)
{
item->setColors(stringToColor(options->palette, itemColor1), stringToColor(options->palette, itemColor2));
}
// Cambia el color de los enemigos
for (auto enemy : enemies)
{
enemy->setPalette(options->palette);
}
// Establece el color del borde
screen->setBorderColor(stringToColor(options->palette, borderColor));
// Cambia la textura
if (options->palette == p_zxspectrum)
{
texture = textureA;
}
else
{
texture = textureB;
}
// Recarga las texturas
reLoadTexture();
}
// Obten el tamaño del tile
int Room::getTileSize()
{
return tileSize;
}
// Obten la coordenada de la cuesta a partir de un punto perteneciente a ese tile
int Room::getSlopeHeight(SDL_Point p, tile_e slope)
{
// Calcula la base del tile
int base = ((p.y / tileSize) * tileSize) + tileSize;
debug->add("BASE = " + std::to_string(base));
// Calcula cuanto se ha entrado en el tile horizontalmente
const int pos = (p.x % tileSize); // Esto da un valor entre 0 y 7
debug->add("POS = " + std::to_string(pos));
// Se resta a la base la cantidad de pixeles pos en funcion de la rampa
if (slope == t_slope_r)
{
base -= pos + 1;
debug->add("BASE_R = " + std::to_string(base));
}
else
{
base -= (tileSize - pos);
debug->add("BASE_L = " + std::to_string(base));
}
return base;
}
// Calcula las superficies inferiores
void Room::setBottomSurfaces()
{
std::vector<int> tile;
// Busca todos los tiles de tipo muro que no tengan debajo otro muro
// Hay que recorrer la habitación por filas (excepto los de la última fila)
for (int i = 0; i < (int)tileMap->size() - mapWidth; ++i)
{
if (getTile(i) == t_wall && getTile(i + mapWidth) != t_wall)
{
tile.push_back(i);
// Si llega al final de la fila, introduce un separador
if (i % mapWidth == mapWidth - 1)
{
tile.push_back(-1);
}
}
}
// Recorre el vector de tiles buscando tiles consecutivos para localizar las superficies
int i = 0;
int lastOne = 0;
while (i < (int)tile.size())
{
h_line_t line;
line.x1 = (tile.at(i) % mapWidth) * tileSize;
line.y = ((tile.at(i) / mapWidth) * tileSize) + tileSize - 1;
lastOne = i;
i++;
while (tile.at(i) == tile.at(i - 1) + 1)
{
lastOne = i;
i++;
}
line.x2 = ((tile[lastOne] % mapWidth) * tileSize) + tileSize - 1;
bottomSurfaces.push_back(line);
if (tile.at(i) == -1)
{ // Si el siguiente elemento es un separador, hay que saltarlo
i++;
}
}
}
// Calcula las superficies superiores
void Room::setTopSurfaces()
{
std::vector<int> tile;
// Busca todos los tiles de tipo muro o pasable que no tengan encima un muro
// Hay que recorrer la habitación por filas (excepto los de la primera fila)
for (int i = mapWidth; i < (int)tileMap->size(); ++i)
{
if ((getTile(i) == t_wall || getTile(i) == t_passable) && getTile(i - mapWidth) != t_wall)
{
tile.push_back(i);
// Si llega al final de la fila, introduce un separador
if (i % mapWidth == mapWidth - 1)
{
tile.push_back(-1);
}
}
}
// Recorre el vector de tiles buscando tiles consecutivos para localizar las superficies
int i = 0;
int lastOne = 0;
while (i < (int)tile.size())
{
h_line_t line;
line.x1 = (tile.at(i) % mapWidth) * tileSize;
line.y = (tile.at(i) / mapWidth) * tileSize;
lastOne = i;
i++;
while (tile.at(i) == tile.at(i - 1) + 1)
{
lastOne = i;
i++;
}
line.x2 = ((tile[lastOne] % mapWidth) * tileSize) + tileSize - 1;
topSurfaces.push_back(line);
if (tile.at(i) == -1)
{ // Si el siguiente elemento es un separador, hay que saltarlo
i++;
}
}
}
// Calcula las superficies laterales izquierdas
void Room::setLeftSurfaces()
{
std::vector<int> tile;
// Busca todos los tiles de tipo muro que no tienen a su izquierda un tile de tipo muro
// Hay que recorrer la habitación por columnas (excepto los de la primera columna)
for (int i = 1; i < mapWidth; ++i)
{
for (int j = 0; j < mapHeight; ++j)
{
const int pos = (j * mapWidth + i);
if (getTile(pos) == t_wall && getTile(pos - 1) != t_wall)
{
tile.push_back(pos);
}
}
}
// Recorre el vector de tiles buscando tiles consecutivos
// (Los tiles de la misma columna, la diferencia entre ellos es de mapWidth)
// para localizar las superficies
int i = 0;
while (i < (int)tile.size())
{
v_line_t line;
line.x = (tile.at(i) % mapWidth) * tileSize;
line.y1 = ((tile.at(i) / mapWidth) * tileSize);
while (tile.at(i) + mapWidth == tile[i + 1])
{
i++;
}
line.y2 = ((tile.at(i) / mapWidth) * tileSize) + tileSize - 1;
leftSurfaces.push_back(line);
i++;
}
}
// Calcula las superficies laterales derechas
void Room::setRightSurfaces()
{
std::vector<int> tile;
// Busca todos los tiles de tipo muro que no tienen a su derecha un tile de tipo muro
// Hay que recorrer la habitación por columnas (excepto los de la última columna)
for (int i = 0; i < mapWidth - 1; ++i)
{
for (int j = 0; j < mapHeight; ++j)
{
const int pos = (j * mapWidth + i);
if (getTile(pos) == t_wall && getTile(pos + 1) != t_wall)
{
tile.push_back(pos);
}
}
}
// Recorre el vector de tiles buscando tiles consecutivos
// (Los tiles de la misma columna, la diferencia entre ellos es de mapWidth)
// para localizar las superficies
int i = 0;
while (i < (int)tile.size())
{
v_line_t line;
line.x = ((tile.at(i) % mapWidth) * tileSize) + tileSize - 1;
line.y1 = ((tile.at(i) / mapWidth) * tileSize);
while (tile.at(i) + mapWidth == tile[i + 1])
{
i++;
}
line.y2 = ((tile.at(i) / mapWidth) * tileSize) + tileSize - 1;
rightSurfaces.push_back(line);
i++;
}
}
// Encuentra todas las rampas que suben hacia la izquierda
void Room::setLeftSlopes()
{
// Recorre la habitación entera por filas buscando tiles de tipo t_slope_l
std::vector<int> found;
for (int i = 0; i < (int)tileMap->size(); ++i)
{
if (getTile(i) == t_slope_l)
{
found.push_back(i);
}
}
// El primer elemento es el inicio de una rampa. Se añade ese elemento y se buscan los siguientes,
// que seran i + mapWidth + 1. Conforme se añaden se eliminan y se vuelve a escudriñar el vector de
// tiles encontrados hasta que esté vacío
while (found.size() > 0)
{
d_line_t line;
line.x1 = (found[0] % mapWidth) * tileSize;
line.y1 = (found[0] / mapWidth) * tileSize;
int lookingFor = found[0] + mapWidth + 1;
int lastOneFound = found[0];
found.erase(found.begin());
for (int i = 0; i < (int)found.size(); ++i)
{
if (found[i] == lookingFor)
{
lastOneFound = lookingFor;
lookingFor += mapWidth + 1;
found.erase(found.begin() + i);
i--;
}
}
line.x2 = ((lastOneFound % mapWidth) * tileSize) + tileSize - 1;
line.y2 = ((lastOneFound / mapWidth) * tileSize) + tileSize - 1;
leftSlopes.push_back(line);
}
}
// Encuentra todas las rampas que suben hacia la derecha
void Room::setRightSlopes()
{
// Recorre la habitación entera por filas buscando tiles de tipo t_slope_r
std::vector<int> found;
for (int i = 0; i < (int)tileMap->size(); ++i)
{
if (getTile(i) == t_slope_r)
{
found.push_back(i);
}
}
// El primer elemento es el inicio de una rampa. Se añade ese elemento y se buscan los siguientes,
// que seran i + mapWidth - 1. Conforme se añaden se eliminan y se vuelve a escudriñar el vector de
// tiles encontrados hasta que esté vacío
while (found.size() > 0)
{
d_line_t line;
line.x1 = ((found[0] % mapWidth) * tileSize) + tileSize - 1;
line.y1 = (found[0] / mapWidth) * tileSize;
int lookingFor = found[0] + mapWidth - 1;
int lastOneFound = found[0];
found.erase(found.begin());
for (int i = 0; i < (int)found.size(); ++i)
{
if (found[i] == lookingFor)
{
lastOneFound = lookingFor;
lookingFor += mapWidth - 1;
found.erase(found.begin() + i);
i--;
}
}
line.x2 = (lastOneFound % mapWidth) * tileSize;
line.y2 = ((lastOneFound / mapWidth) * tileSize) + tileSize - 1;
rightSlopes.push_back(line);
}
}
// Calcula las superficies automaticas
void Room::setAutoSurfaces()
{
std::vector<int> tile;
// Busca todos los tiles de tipo animado
// Hay que recorrer la habitación por filas (excepto los de la primera fila)
for (int i = mapWidth; i < (int)tileMap->size(); ++i)
{
if (getTile(i) == t_animated)
{
tile.push_back(i);
// Si llega al final de la fila, introduce un separador
if (i % mapWidth == mapWidth - 1)
{
tile.push_back(-1);
}
}
}
// Recorre el vector de tiles buscando tiles consecutivos para localizar las superficies
int i = 0;
int lastOne = 0;
while (i < (int)tile.size())
{
h_line_t line;
line.x1 = (tile.at(i) % mapWidth) * tileSize;
line.y = (tile.at(i) / mapWidth) * tileSize;
lastOne = i;
i++;
while (tile.at(i) == tile.at(i - 1) + 1)
{
lastOne = i;
i++;
}
line.x2 = ((tile[lastOne] % mapWidth) * tileSize) + tileSize - 1;
autoSurfaces.push_back(line);
if (tile.at(i) == -1)
{ // Si el siguiente elemento es un separador, hay que saltarlo
i++;
}
}
}
// Localiza todos los tiles animados de la habitación
void Room::setAnimatedTiles()
{
// Recorre la habitación entera por filas buscando tiles de tipo t_animated
for (int i = 0; i < (int)tileMap->size(); ++i)
{
if (getTile(i) == t_animated)
{
// La i es la ubicación
const int x = (i % mapWidth) * tileSize;
const int y = (i / mapWidth) * tileSize;
// TileMap->at(i) es el tile a poner
const int xc = (tileMap->at(i) % tileSetWidth) * tileSize;
const int yc = (tileMap->at(i) / tileSetWidth) * tileSize;
aTile_t at;
at.sprite = new Sprite(x, y, 8, 8, texture, renderer);
at.sprite->setSpriteClip(xc, yc, 8, 8);
at.xcOrig = xc;
aTile.push_back(at);
}
}
}
// Actualiza los tiles animados
void Room::updateAnimatedTiles()
{
const int numFrames = 4;
int offset = 0;
if (autoSurfaceDirection == -1)
{
offset = ((counter / 3) % numFrames * tileSize);
}
else
{
offset = ((numFrames - 1 - ((counter / 3) % numFrames)) * tileSize);
}
for (auto &a : aTile)
{
SDL_Rect rect = a.sprite->getSpriteClip();
rect.x = a.xcOrig + offset;
a.sprite->setSpriteClip(rect);
}
}
// Pinta los tiles animados en pantalla
void Room::renderAnimatedTiles()
{
for (auto a : aTile)
{
a.sprite->render();
}
}
// Comprueba las colisiones
int Room::checkRightSurfaces(SDL_Rect *rect)
{
for (auto s : rightSurfaces)
{
if (checkCollision(s, *rect))
{
return s.x;
}
}
return -1;
}
// Comprueba las colisiones
int Room::checkLeftSurfaces(SDL_Rect *rect)
{
for (auto s : leftSurfaces)
{
if (checkCollision(s, *rect))
{
return s.x;
}
}
return -1;
}
// Comprueba las colisiones
int Room::checkTopSurfaces(SDL_Rect *rect)
{
for (auto s : topSurfaces)
{
if (checkCollision(s, *rect))
{
return s.y;
}
}
return -1;
}
// Comprueba las colisiones
int Room::checkBottomSurfaces(SDL_Rect *rect)
{
for (auto s : bottomSurfaces)
{
if (checkCollision(s, *rect))
{
return s.y;
}
}
return -1;
}
// Comprueba las colisiones
int Room::checkAutoSurfaces(SDL_Rect *rect)
{
for (auto s : autoSurfaces)
{
if (checkCollision(s, *rect))
{
return s.y;
}
}
return -1;
}
// Comprueba las colisiones
bool Room::checkTopSurfaces(SDL_Point *p)
{
for (auto s : topSurfaces)
{
if (checkCollision(s, *p))
{
return true;
}
}
return false;
}
// Comprueba las colisiones
bool Room::checkAutoSurfaces(SDL_Point *p)
{
for (auto s : autoSurfaces)
{
if (checkCollision(s, *p))
{
return true;
}
}
return false;
}
// Comprueba las colisiones
int Room::checkLeftSlopes(v_line_t *line)
{
for (auto s : leftSlopes)
{
const SDL_Point p = checkCollision(s, *line);
if (p.x != -1)
{
return p.y;
}
}
return -1;
}
// Comprueba las colisiones
bool Room::checkLeftSlopes(SDL_Point *p)
{
for (auto s : leftSlopes)
{
if (checkCollision(*p, s))
{
return true;
}
}
return false;
}
// Comprueba las colisiones
int Room::checkRightSlopes(v_line_t *line)
{
for (auto s : rightSlopes)
{
const SDL_Point p = checkCollision(s, *line);
if (p.x != -1)
{
return p.y;
}
}
return -1;
}
// Comprueba las colisiones
bool Room::checkRightSlopes(SDL_Point *p)
{
for (auto s : rightSlopes)
{
if (checkCollision(*p, s))
{
return true;
}
}
return false;
}
// Pone el mapa en modo pausa
void Room::pause()
{
paused = true;
}
// Quita el modo pausa del mapa
void Room::resume()
{
paused = false;
}
// Obten la direccion de las superficies automaticas
int Room::getAutoSurfaceDirection()
{
return autoSurfaceDirection;
}