24 Commits
v1.02 ... v1.05

Author SHA1 Message Date
1b49097f80 Cambiado el tamaño por defecto del borde 2022-11-19 09:27:55 +01:00
859e3f3b44 Actualizado Makefile 2022-11-19 09:27:24 +01:00
3fa7657c79 Cuendo el jugador entra a la Jail, recupera todas sus vidas 2022-11-19 09:22:10 +01:00
e90c61a416 FIx: El jugador no se moria al caer de alto si se mantenia la tecla de slto pulsada 2022-11-19 09:02:35 +01:00
d003b51de4 Reparada la clase Screen 2022-11-19 07:49:01 +01:00
8d381010c8 Trabajando en la clase Screen 2022-11-19 07:37:03 +01:00
2216c9632e Trabajando en las notificaciones 2022-11-18 23:15:38 +01:00
fdc8797d2b Arreglada la clase Screen. Había un lio de conceptos con varias variables 2022-11-18 20:09:03 +01:00
90bdad7d51 Modificado Makefile 2022-11-18 10:43:54 +01:00
d50b193d9f Cambiado el fichero de estadisticas a stats.csv 2022-11-18 10:43:01 +01:00
ee885d5ca7 Ya crea correctamente la carpeta de sistema en las tres plataformas 2022-11-18 10:40:51 +01:00
bb3a0f263b Ya crea la carpeta de sistema en MacOS y Windows 2022-11-18 10:35:15 +01:00
85d6c48f42 Ya crea la carpeta de sistema en Linux 2022-11-18 09:48:46 +01:00
896dd9daef Trabajando en el guardado de las estadisticas en las carpetas del sistema 2022-11-18 07:32:15 +01:00
dc8c0c9e4f Fix: Algunas texturas desaparecen al bloquearse la pantalla 2022-11-17 17:54:05 +01:00
7af0dda1a0 En la pantalla de Game Over se muestran las habitaciones y los items conseguidos 2022-11-17 16:33:37 +01:00
0adf8c63f4 Las habitaciones solo cuentan como visitadas una vez por partida 2022-11-17 16:06:31 +01:00
d33f691743 Fix: Algunas texturas desaparecen al bloquearse la pantalla 2022-11-17 16:04:03 +01:00
a304f50e93 Merge branch 'master' of https://gitea.sustancia.synology.me/JailDesigner/jaildoctors_dilemma 2022-11-17 11:53:07 +01:00
496bf5c05c Actualizado Makefile 2022-11-17 11:53:00 +01:00
26a6bd6b1f Cambiada la posición y dirección inicial del tuno magenta en KILLING SPREE 2022-11-17 11:31:54 +01:00
c48dce8634 Actualizado Makefile 2022-11-17 09:36:12 +01:00
a0de547370 Eliminado un warning de variable no utilizada 2022-11-17 09:34:06 +01:00
5af554fecd Añadido soporte preliminar para estadisticas 2022-11-17 09:30:56 +01:00
30 changed files with 1105 additions and 275 deletions

3
.gitignore vendored
View File

@@ -1,5 +1,6 @@
.vscode
*config.txt
*stats.txt
*.DS_Store
thumbs.db
*.exe
@@ -9,4 +10,4 @@ thumbs.db
*.tar.gz
*.zip
*.app
*_debug
*_debug*

View File

@@ -2,7 +2,7 @@ executable = jaildoctors_dilemma
source = source/*.cpp source/common/*.cpp
appName = JailDoctor's Dilemma
releaseFolder = jdd_release
version = v1.02
version = v1.05
# Release names
windowsRelease = $(executable)-$(version)-win32-x64.zip
@@ -12,20 +12,16 @@ linuxRelease = $(executable)-$(version)-linux.tar.gz
windows:
@echo off
powershell if (Test-Path data\config) {Remove-Item data\config -Recurse -Force}
powershell if (-not (Test-Path data\config)) {New-Item data\config -ItemType Directory}
g++ $(source) -D DEBUG -std=c++11 -Wall -Os -lmingw32 -lSDL2main -lSDL2 -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows -o $(executable).exe
g++ $(source) -D DEBUG -std=c++11 -Wall -Os -lmingw32 -lws2_32 -lSDL2main -lSDL2 -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows -o $(executable).exe
strip -s -R .comment -R .gnu.version $(executable).exe --strip-unneeded
windows_release:
@echo off
# Remove data
powershell if (Test-Path data\config) {Remove-Item data\config -Recurse -Force}
powershell if (Test-Path $(releaseFolder)) {Remove-Item $(releaseFolder) -Recurse -Force}
# Create folders
powershell if (-not (Test-Path data\config)) {New-Item data\config -ItemType Directory}
powershell if (-not (Test-Path $(releaseFolder))) {New-Item $(releaseFolder) -ItemType Directory}
# Copy data
@@ -37,9 +33,13 @@ windows_release:
# Remove data
powershell if (Test-Path "$(releaseFolder)\data\room\map.world") {Remove-Item "$(releaseFolder)\data\room\map.world" -Recurse -Force}
powershell if (Test-Path "$(releaseFolder)\data\room\standard.tsx") {Remove-Item "$(releaseFolder)\data\room\standard.tsx" -Recurse -Force}
powershell if (Test-Path "$(releaseFolder)\data\config") {Remove-Item "$(releaseFolder)\data\config" -Recurse -Force}
# Create data
powershell if (-not (Test-Path "$(releaseFolder)\data\config")) {New-Item "$(releaseFolder)\data\config" -ItemType Directory}
# Build
g++ $(source) -std=c++11 -Wall -Os -lmingw32 -lSDL2main -lSDL2 -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows -o "$(releaseFolder)/$(executable).exe"
g++ $(source) -std=c++11 -Wall -Os -lmingw32 -lws2_32 -lSDL2main -lSDL2 -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows -o "$(releaseFolder)/$(executable).exe"
strip -s -R .comment -R .gnu.version "$(releaseFolder)/$(executable).exe" --strip-unneeded
# Create ZIP
@@ -50,13 +50,10 @@ windows_release:
powershell if (Test-Path $(releaseFolder)) {Remove-Item $(releaseFolder) -Recurse -Force}
macos:
rm -rdf data/config
mkdir -p data/config
clang++ $(source) -D DEBUG -std=c++11 -Wall -Os -lSDL2 -ffunction-sections -fdata-sections -o $(executable)_macos
macos_release:
# Remove data and possible data
rm -rdf data/config
rm -rdf "$(releaseFolder)"
rm -rdf Frameworks
rm -f tmp.dmg
@@ -64,7 +61,6 @@ macos_release:
rm -f "$(macosAppleSiliconRelease)"
# Create folders
mkdir -p data/config
mkdir -p "$(releaseFolder)/$(appName).app/Contents/Frameworks"
mkdir -p "$(releaseFolder)/$(appName).app/Contents/MacOS"
mkdir -p "$(releaseFolder)/$(appName).app/Contents/Resources"
@@ -78,10 +74,16 @@ macos_release:
# Delete data
rm -f "$(releaseFolder)/$(appName).app/Contents/Resources/data/room/map.world"
rm -f "$(releaseFolder)/$(appName).app/Contents/Resources/data/room/standard.tsx"
rm -rdf "$(releaseFolder)/$(appName).app/Contents/Resources/data/config"
# Create folders
mkdir -p "$(releaseFolder)/$(appName).app/Contents/Resources/data/config"
# Copy files
cp release/*.icns "$(releaseFolder)/$(appName).app/Contents/Resources"
cp release/Info.plist "$(releaseFolder)/$(appName).app/Contents"
cp LICENSE "$(releaseFolder)"
cp README.md "$(releaseFolder)"
# Build INTEL
clang++ $(source) -D MACOS_BUNDLE -std=c++11 -Wall -Os -framework SDL2 -F ./Frameworks -ffunction-sections -fdata-sections -o "$(releaseFolder)/$(appName).app/Contents/MacOS/$(executable)" -rpath @executable_path/../Frameworks/ -target x86_64-apple-macos10.12
@@ -104,18 +106,14 @@ macos_release:
rm -rdf "$(releaseFolder)"
linux:
rm -rdf data/config
mkdir -p data/config
g++ $(source) -D DEBUG -std=c++11 -Wall -Os -lSDL2 -ffunction-sections -fdata-sections -Wl,--gc-sections -o $(executable)_linux
strip -s -R .comment -R .gnu.version $(executable)_linux --strip-unneeded
linux_release:
# Remove data
rm -rdf data/config
rm -rdf $(releaseFolder)
# Create folders
mkdir -p data/config
mkdir -p $(releaseFolder)
# Copy data
@@ -126,6 +124,10 @@ linux_release:
# Delete data
rm -f "$(releaseFolder)/data/room/map.world"
rm -f "$(releaseFolder)/data/room/standard.tsx"
rm -rdf "$(releaseFolder)/data/config"
# Create folders
mkdir -p "$(releaseFolder)/data/config"
# Build
g++ $(source) -std=c++11 -Wall -Os -lSDL2 -ffunction-sections -fdata-sections -Wl,--gc-sections -o $(releaseFolder)/$(executable)

View File

@@ -48,9 +48,9 @@ animation=tuno.ani
width=16
height=16
x=28
y=8
y=6
vx=0
vy=0.4
vy=-0.4
x1=28
y1=2
x2=28

View File

@@ -10,10 +10,10 @@ Asset::Asset(std::string executablePath)
}
// Añade un elemento a la lista
void Asset::add(std::string file, enum assetType type, bool required)
void Asset::add(std::string file, enum assetType type, bool required, bool absolute)
{
item_t temp;
temp.file = executablePath + file;
temp.file = absolute ? file : executablePath + file;
temp.type = type;
temp.required = required;
fileList.push_back(temp);

View File

@@ -31,6 +31,7 @@ private:
std::string file; // Ruta del fichero desde la raiz del directorio
enum assetType type; // Indica el tipo de recurso
bool required; // Indica si es un fichero que debe de existir
//bool absolute; // Indica si la ruta que se ha proporcionado es una ruta absoluta
};
// Variables
@@ -50,7 +51,7 @@ public:
Asset(std::string path);
// Añade un elemento a la lista
void add(std::string file, enum assetType type, bool required = true);
void add(std::string file, enum assetType type, bool required = true, bool absolute = false);
// Devuelve un elemento de la lista a partir de una cadena
std::string get(std::string text);

154
source/common/jscore.cpp Normal file
View File

@@ -0,0 +1,154 @@
#include "jscore.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#endif
#include <unistd.h>
#include <string>
#include <vector>
namespace jscore {
using namespace std;
struct user {
string name;
int points;
};
vector<user> score;
#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)
int sock;
struct sockaddr_in client;
int PORT = 9911;
string HOST = "jaildoctor.duckdns.org";
#ifdef WIN32
WSADATA WsaData;
#endif
bool jscore_error = false;
string error_message;
void init(std::string host, const int port) {
PORT = port;
HOST = host;
}
void setErrorMessage(string message) {
jscore_error = true;
error_message = message;
}
string sendRequest(const string request) {
#ifdef WIN32
int ret = WSAStartup(0x101,&WsaData);
if (ret != 0) return 0;
#endif
struct hostent * host = gethostbyname(HOST.c_str());
if ( (host == NULL) || (host->h_addr == NULL) ) {
setErrorMessage("Error retrieving DNS information.\n");
return "";
}
bzero(&client, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons( PORT );
memcpy(&client.sin_addr, host->h_addr, host->h_length);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
setErrorMessage("Error creating socket.\n");
return "";
}
if ( connect(sock, (struct sockaddr *)&client, sizeof(client)) < 0 ) {
close(sock);
setErrorMessage("Could not connect\n");
return "";
}
string r = request + " HTTP/1.1\r\nHost: "+HOST+"\r\nConnection: close\r\n\r\n\r\n";
if (send(sock, r.c_str(), r.length(), 0) != (int)r.length()) {
setErrorMessage("Error sending request.\n");
return "";
}
char cur;
char start[5]="\r\n\r\n";
int pos = 0;
while ( recv(sock, &cur, 1,0) > 0 ) {
if (cur==start[pos]) { pos++; if (pos == 4) break; } else { pos = 0; }
}
char buffer[1024]; buffer[0]=0; pos=0;
while ( recv(sock, &cur, 1,0) > 0 ) {
buffer[pos] = cur;
pos++;
}
#ifdef WIN32
WSACleanup();
#endif
buffer[pos]=0;
return buffer;
}
const bool initOnlineScore(string game) {
string strbuff = sendRequest("GET /score-list.php?game=" + game);
if (jscore_error) return not jscore_error;
user u;
char buffer[1024];
strcpy(buffer, strbuff.c_str());
char *str = buffer;
char *p = str;
score.clear();
while (*p!=0) {
while (*p!=',') {p++;}
*p=0; u.name = str; p++; str=p;
while (*p!='\n') {p++;}
*p=0; u.points = atoi(str); p++; str=p;
score.push_back(u);
}
return not jscore_error;
}
const int getNumUsers() {
return score.size();
}
string getUserName(const int index) {
return score[index].name;
}
const int getPoints(const int index) {
return score[index].points;
}
const bool updateUserPoints(string game, string user, const int points) {
string strbuff = sendRequest("GET /score-update.php?game=" + game + "&user=" + user + "&points=" + to_string(points));
initOnlineScore(game);
return not jscore_error;
}
const int getUserPoints(string game, std::string user) {
return atoi(sendRequest("GET /getuserpoints.php?game=" + game + "&user=" + user).c_str());
}
string getUserData(string game, string user) {
return sendRequest("GET /getuserdata.php?game=" + game + "&user=" + user);
}
void setUserData(string game, string user, string data) {
sendRequest("GET /setuserdata.php?game=" + game + "&user=" + user + "&data=" + data);
}
};

16
source/common/jscore.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
#include <string>
namespace jscore {
void init(std::string host, const int port);
const bool initOnlineScore(std::string game);
const int getNumUsers();
std::string getUserName(const int index);
const int getPoints(const int index);
const int getUserPoints(std::string game, std::string user);
const bool updateUserPoints(std::string game, std::string user, const int points);
std::string getUserData(std::string game, std::string user);
void setUserData(std::string game, std::string user, std::string data);
};

162
source/common/notify.cpp Normal file
View File

@@ -0,0 +1,162 @@
#include "notify.h"
#include <string>
#include <stdio.h>
#include <iostream>
// Constructor
Notify::Notify(SDL_Renderer *renderer, std::string bitmapFile, std::string textFile)
{
// Inicializa variables
this->renderer = renderer;
bgColor = {64, 64, 64};
waitTime = 300;
// Crea objetos
texture = new Texture(renderer, bitmapFile);
text = new Text(textFile, texture, renderer);
}
// Destructor
Notify::~Notify()
{
// Libera la memoria de los objetos
delete texture;
delete text;
for (auto notification : notifications)
{
delete notification.sprite;
delete notification.texture;
}
}
// Dibuja las notificaciones por pantalla
void Notify::render()
{
for (int i = (int)notifications.size() - 1; i >= 0; --i)
{
notifications.at(i).sprite->render();
}
}
// Actualiza el estado de las notificaiones
void Notify::update()
{
for (int i = 0; i < (int)notifications.size(); ++i)
{
notifications.at(i).counter++;
// Comprueba los estados
if (notifications.at(i).state == ns_rising)
{
const float step = ((float)notifications.at(i).counter / notifications.at(i).travelDist);
const int alpha = 255 * step;
notifications.at(i).rect.y++;
notifications.at(i).texture->setAlpha(alpha);
if (notifications.at(i).rect.y == notifications.at(i).y)
{
notifications.at(i).state = ns_stay;
notifications.at(i).texture->setAlpha(255);
notifications.at(i).counter = 0;
}
}
else if (notifications.at(i).state == ns_stay)
{
if (notifications.at(i).counter == waitTime)
{
notifications.at(i).state = ns_vanishing;
notifications.at(i).counter = 0;
}
}
else if (notifications.at(i).state == ns_vanishing)
{
const float step = (notifications.at(i).counter / (float)notifications.at(i).travelDist);
const int alpha = 255 * (1 - step);
notifications.at(i).rect.y--;
notifications.at(i).texture->setAlpha(alpha);
if (notifications.at(i).rect.y == notifications.at(i).y - notifications.at(i).travelDist)
{
notifications.at(i).state = ns_finished;
}
}
notifications.at(i).sprite->setRect(notifications.at(i).rect);
}
clearFinishedNotifications();
}
// Elimina las notificaciones finalizadas
void Notify::clearFinishedNotifications()
{
for (int i = (int)notifications.size() - 1; i >= 0; --i)
{
if (notifications.at(i).state == ns_finished)
{
delete notifications.at(i).sprite;
delete notifications.at(i).texture;
notifications.erase(notifications.begin() + i);
}
}
}
// Muestra una notificación de texto por pantalla;
void Notify::showText(std::string text)
{
// Crea constantes
const int width = this->text->lenght(text) + (this->text->getCharacterSize() * 2);
const int height = this->text->getCharacterSize() * 2;
const int despH = this->text->getCharacterSize() / 2;
const int despV = despH;
const int travelDist = height + despV;
const int offset = (int)notifications.size() > 0 ? notifications.back().y + travelDist : despV;
// Crea la notificacion
notification_t n;
// inicializa variables
n.y = offset;
n.travelDist = travelDist;
n.counter = 0;
n.state = ns_rising;
n.text = text;
n.rect = {despH, offset - travelDist, width, height};
// Crea la textura
n.texture = new Texture(renderer);
n.texture->createBlank(renderer, width, height, SDL_TEXTUREACCESS_TARGET);
n.texture->setAsRenderTarget(renderer);
SDL_SetRenderDrawColor(renderer, bgColor.r, bgColor.g, bgColor.b, 255);
SDL_RenderClear(renderer);
n.texture->setBlendMode(SDL_BLENDMODE_BLEND);
this->text->writeDX(TXT_CENTER | TXT_STROKE, width / 2, despV, text, 1, {255, 255, 255}, 1, {0, 0, 0});
// Crea el sprite
n.sprite = new Sprite(n.rect, n.texture, renderer);
// Añade la notificación a la lista
notifications.push_back(n);
//std::cout << "Notification " << notifications.size() << std::endl;
//std::cout << "width " << width << std::endl;
//std::cout << "height " << height << std::endl;
//std::cout << "offset " << offset << std::endl;
//std::cout << "desp " << despH << std::endl;
}
// Indica si hay notificaciones activas
bool Notify::active()
{
if ((int)notifications.size() > 0)
{
return true;
}
return false;
}

82
source/common/notify.h Normal file
View File

@@ -0,0 +1,82 @@
#pragma once
#include <SDL2/SDL.h>
#include "text.h"
#include "texture.h"
#include "sprite.h"
#include "utils.h"
#include <vector>
#ifndef NOTIFY_H
#define NOTIFY_H
class Notify
{
private:
enum notification_state_e
{
ns_rising,
ns_stay,
ns_vanishing,
ns_finished
};
enum notification_position_e
{
upperLeft,
upperCenter,
upperRight,
middleLeft,
middleRight,
bottomLeft,
bottomCenter,
bottomRight
};
struct notification_t
{
std::string text;
int counter;
notification_state_e state;
notification_position_e position;
Texture *texture;
Sprite *sprite;
SDL_Rect rect;
int y;
int travelDist;
};
// Objetos y punteros
SDL_Renderer *renderer; // El renderizador de la ventana
Texture *texture; // Textura para la fuente de las notificaciones
Text *text; // Objeto para dibujar texto
// Variables
color_t bgColor; // Color de fondo de las notificaciones
int waitTime; // Tiempo que se ve la notificación
std::vector<notification_t> notifications; // La lista de notificaciones activas
// Elimina las notificaciones finalizadas
void clearFinishedNotifications();
public:
// Dibuja las notificaciones por pantalla
void render();
// Actualiza el estado de las notificaiones
void update();
// Constructor
Notify(SDL_Renderer *renderer, std::string bitmapFile, std::string textFile);
// Destructor
~Notify();
// Muestra una notificación de texto por pantalla;
void showText(std::string text);
// Indica si hay notificaciones activas
bool active();
};
#endif

View File

@@ -3,15 +3,21 @@
#include <iostream>
// Constructor
Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, options_t *options, int gameInternalResX, int gameInternalResY)
Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options_t *options)
{
// Inicializa variables
this->window = window;
this->renderer = renderer;
this->options = options;
this->asset = asset;
gameCanvasWidth = gameInternalResX;
gameCanvasHeight = gameInternalResY;
// Crea los objetos
notify = new Notify(renderer, asset->get("smb2.png"), asset->get("smb2.txt"));
gameCanvasWidth = options->gameWidth;
gameCanvasHeight = options->gameHeight;
borderWidth = options->gameWidth * options->borderSize;
borderHeight = options->gameHeight * options->borderSize;
iniFade();
iniSpectrumFade();
@@ -27,15 +33,16 @@ Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, options_t *options, i
}
// Establece el modo de video
setVideoMode(options->fullScreenMode);
setVideoMode(options->videoMode);
// Calcula los anclajes
anchor.left = 0;
anchor.right = gameCanvasWidth;
anchor.center = gameCanvasWidth / 2;
anchor.top = 0;
anchor.bottom = gameCanvasHeight;
anchor.middle = gameCanvasHeight / 2;
// Inicializa variables
notifyActive = false;
}
// Destructor
Screen::~Screen()
{
delete notify;
}
// Limpia la pantalla
@@ -64,107 +71,100 @@ void Screen::blit()
// Copia la textura de juego en el renderizador en la posición adecuada
SDL_RenderCopy(renderer, gameCanvas, nullptr, &dest);
// Dibuja las notificaciones
renderNotifications();
// Muestra por pantalla el renderizador
SDL_RenderPresent(renderer);
}
// Establece el modo de video
void Screen::setVideoMode(int fullScreenMode)
void Screen::setVideoMode(int videoMode)
{
// Aplica el modo de video
SDL_SetWindowFullscreen(window, fullScreenMode);
SDL_SetWindowFullscreen(window, videoMode);
// Si está activo el modo ventana quita el borde
if (fullScreenMode == 0)
if (videoMode == 0)
{
if (options->borderEnabled)
{
const int incWidth = gameCanvasWidth * options->borderSize;
const int incHeight = gameCanvasHeight * options->borderSize;
screenWidth = gameCanvasWidth + incWidth;
screenHeight = gameCanvasHeight + incHeight;
dest = {0 + (incWidth / 2), 0 + (incHeight / 2), gameCanvasWidth, gameCanvasHeight};
windowWidth = gameCanvasWidth + borderWidth;
windowHeight = gameCanvasHeight + borderHeight;
dest = {0 + (borderWidth / 2), 0 + (borderHeight / 2), gameCanvasWidth, gameCanvasHeight};
}
else
{
screenWidth = gameCanvasWidth;
screenHeight = gameCanvasHeight;
windowWidth = gameCanvasWidth;
windowHeight = gameCanvasHeight;
dest = {0, 0, gameCanvasWidth, gameCanvasHeight};
}
// Modifica el tamaño del renderizador y de la ventana
SDL_RenderSetLogicalSize(renderer, screenWidth, screenHeight);
SDL_SetWindowSize(window, screenWidth * options->windowSize, screenHeight * options->windowSize);
SDL_RenderSetLogicalSize(renderer, windowWidth, windowHeight);
SDL_SetWindowSize(window, windowWidth * options->windowSize, windowHeight * options->windowSize);
}
// Si está activo el modo de pantalla completa añade el borde
else if (fullScreenMode == SDL_WINDOW_FULLSCREEN_DESKTOP)
else if (videoMode == SDL_WINDOW_FULLSCREEN_DESKTOP)
{
// Obten el alto y el ancho de la ventana
SDL_GetWindowSize(window, &screenWidth, &screenHeight);
SDL_GetWindowSize(window, &windowWidth, &windowHeight);
// Aplica el escalado al rectangulo donde se pinta la textura del juego
if (options->integerScale)
{
// Calcula el tamaño de la escala máxima
int scale = 0;
while (((gameCanvasWidth * (scale + 1)) <= screenWidth) && ((gameCanvasHeight * (scale + 1)) <= screenHeight))
while (((gameCanvasWidth * (scale + 1)) <= windowWidth) && ((gameCanvasHeight * (scale + 1)) <= windowHeight))
{
scale++;
}
dest.w = gameCanvasWidth * scale;
dest.h = gameCanvasHeight * scale;
dest.x = (screenWidth - dest.w) / 2;
dest.y = (screenHeight - dest.h) / 2;
dest.x = (windowWidth - dest.w) / 2;
dest.y = (windowHeight - dest.h) / 2;
}
else if (options->keepAspect)
{
float ratio = (float)gameCanvasWidth / (float)gameCanvasHeight;
if ((screenWidth - gameCanvasWidth) >= (screenHeight - gameCanvasHeight))
if ((windowWidth - gameCanvasWidth) >= (windowHeight - gameCanvasHeight))
{
dest.h = screenHeight;
dest.w = (int)((screenHeight * ratio) + 0.5f);
dest.x = (screenWidth - dest.w) / 2;
dest.y = (screenHeight - dest.h) / 2;
dest.h = windowHeight;
dest.w = (int)((windowHeight * ratio) + 0.5f);
dest.x = (windowWidth - dest.w) / 2;
dest.y = (windowHeight - dest.h) / 2;
}
else
{
dest.w = screenWidth;
dest.h = (int)((screenWidth / ratio) + 0.5f);
dest.x = (screenWidth - dest.w) / 2;
dest.y = (screenHeight - dest.h) / 2;
dest.w = windowWidth;
dest.h = (int)((windowWidth / ratio) + 0.5f);
dest.x = (windowWidth - dest.w) / 2;
dest.y = (windowHeight - dest.h) / 2;
}
}
else
{
dest.w = screenWidth;
dest.h = screenHeight;
dest.w = windowWidth;
dest.h = windowHeight;
dest.x = dest.y = 0;
}
// Modifica el tamaño del renderizador
SDL_RenderSetLogicalSize(renderer, screenWidth, screenHeight);
SDL_RenderSetLogicalSize(renderer, windowWidth, windowHeight);
}
// Actualiza el valor de la variable
options->fullScreenMode = fullScreenMode;
options->videoMode = videoMode;
}
// Camibia entre pantalla completa y ventana
void Screen::switchVideoMode()
{
if (options->fullScreenMode == 0)
{
options->fullScreenMode = SDL_WINDOW_FULLSCREEN_DESKTOP;
}
else
{
options->fullScreenMode = 0;
}
setVideoMode(options->fullScreenMode);
options->videoMode = (options->videoMode == 0) ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0;
setVideoMode(options->videoMode);
}
// Cambia el tamaño de la ventana
@@ -338,4 +338,30 @@ void Screen::renderFX()
{
renderFade();
renderSpectrumFade();
}
// Actualiza el notificador
void Screen::updateNotifier()
{
notify->update();
notifyActive = notify->active();
}
// Muestra una notificación de texto por pantalla;
void Screen::showText(std::string text)
{
notify->showText(text);
}
// Dibuja las notificaciones
void Screen::renderNotifications()
{
//if (!notifyActive)
//{
// return;
//}
//SDL_RenderSetLogicalSize(renderer, windowWidth * options->windowSize, windowHeight * options->windowSize);
notify->render();
//SDL_RenderSetLogicalSize(renderer, windowWidth, windowHeight);
}

View File

@@ -1,6 +1,8 @@
#pragma once
#include <SDL2/SDL.h>
#include "asset.h"
#include "notify.h"
#include "utils.h"
#include <vector>
@@ -10,42 +12,35 @@
#define FILTER_NEAREST 0
#define FILTER_LINEAL 1
struct anchor_t
{
int left; // Parte izquierda de la pantalla de juego
int right; // Parte drecha de la pantalla de juego
int center; // Parte central horizontal de la pantalla de juego
int top; // Parte superior de la pantalla de juego
int bottom; // Parte infoerior de la pantalla de juego
int middle; // Parte central vertical de la pantalla de juego
};
// Clase Screen
class Screen
{
private:
// Objetos y punteros
SDL_Window *window; // Ventana de la aplicación
SDL_Renderer *renderer; // El renderizador de la ventana
Asset *asset; // Objeto con el listado de recursos
SDL_Texture *gameCanvas; // Textura para completar la ventana de juego hasta la pantalla completa
options_t *options; // Variable con todas las opciones del programa
Notify *notify; // Dibuja notificaciones por pantalla
// Variables
int screenWidth; // Ancho de la pantalla o ventana
int screenHeight; // Alto de la pantalla o ventana
int windowWidth; // Ancho de la pantalla o ventana
int windowHeight; // Alto de la pantalla o ventana
int gameCanvasWidth; // Resolución interna del juego. Es el ancho de la textura donde se dibuja el juego
int gameCanvasHeight; // Resolución interna del juego. Es el alto de la textura donde se dibuja el juego
anchor_t anchor; // Variable con los anclajes de la pantalla
int borderWidth; // Anchura del borde
int borderHeight; // Anltura del borde
SDL_Rect dest; // Coordenadas donde se va a dibujar la textura del juego sobre la pantalla o ventana
color_t borderColor; // Color del borde añadido a la textura de juego para rellenar la pantalla
bool notifyActive; // Indica si hay notificaciones activas
// Variables - Efectos
bool fade; // Indica si esta activo el efecto de fade
int fadeCounter; // Temporizador para el efecto de fade
int fadeLenght; // Duración del fade
bool spectrumFade; // Indica si esta activo el efecto de fade spectrum
int spectrumFadeCounter; // Temporizador para el efecto de fade spectrum
int spectrumFadeLenght; // Duración del fade spectrum
bool fade; // Indica si esta activo el efecto de fade
int fadeCounter; // Temporizador para el efecto de fade
int fadeLenght; // Duración del fade
bool spectrumFade; // Indica si esta activo el efecto de fade spectrum
int spectrumFadeCounter; // Temporizador para el efecto de fade spectrum
int spectrumFadeLenght; // Duración del fade spectrum
std::vector<color_t> spectrumColor; // Colores para el fade spectrum
// Inicializa las variables para el fade
@@ -66,9 +61,15 @@ private:
// Dibuja el spectrum fade
void renderSpectrumFade();
// Dibuja las notificaciones
void renderNotifications();
public:
// Constructor
Screen(SDL_Window *window, SDL_Renderer *renderer, options_t *options, int gameInternalResX, int gameInternalResY);
Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options_t *options);
// Destructor
~Screen();
// Limpia la pantalla
void clean(color_t color = {0x00, 0x00, 0x00});
@@ -80,7 +81,7 @@ public:
void blit();
// Establece el modo de video
void setVideoMode(int fullScreenMode);
void setVideoMode(int videoMode);
// Camibia entre pantalla completa y ventana
void switchVideoMode();
@@ -120,6 +121,12 @@ public:
// Dibuja los efectos
void renderFX();
// Actualiza el notificador
void updateNotifier();
// Muestra una notificación de texto por pantalla;
void showText(std::string text);
};
#endif

View File

@@ -70,22 +70,36 @@ struct cheat_t
bool altSkin; // Indicxa si se usa una skin diferente para el jugador
};
// Estructura para el servicio online
struct online_t
{
bool enabled; // Indica si se quiere usar el modo online o no
std::string server; // Servidor para los servicios online
int port; // Puerto del servidor
std::string gameID; // Identificador del juego para los servicios online
std::string jailerID; // Identificador del jugador para los servicios online
int score; // Puntuación almacenada online
};
// Estructura con todas las opciones de configuración del programa
struct options_t
{
Uint32 fullScreenMode; // Contiene el valor del modo de pantalla completa
int windowSize; // Contiene el valor por el que se multiplica el tamaño de la ventana
Uint32 filter; // Filtro usado para el escalado de la imagen
bool vSync; // Indica si se quiere usar vsync o no
int screenWidth; // Ancho de la pantalla o ventana
int screenHeight; // Alto de la pantalla o ventana
bool integerScale; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa
bool keepAspect; // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa
bool borderEnabled; // Indica si ha de mostrar el borde en el modo de ventana
float borderSize; // Porcentaje de borde que se añade a lo ventana
palette_e palette; // Paleta de colores a usar en el juego
bool console; // Indica si ha de mostrar información por la consola de texto
cheat_t cheat; // Contiene trucos y ventajas para el juego
Uint32 videoMode; // Contiene el valor del modo de pantalla completa
int windowSize; // Contiene el valor por el que se multiplica el tamaño de la ventana
Uint32 filter; // Filtro usado para el escalado de la imagen
bool vSync; // Indica si se quiere usar vsync o no
int gameWidth; // Ancho de la resolucion nativa del juego
int gameHeight; // Alto de la resolucion nativa del juego
bool integerScale; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa
bool keepAspect; // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa
bool borderEnabled; // Indica si ha de mostrar el borde en el modo de ventana
float borderSize; // Porcentaje de borde que se añade a lo ventana
palette_e palette; // Paleta de colores a usar en el juego
bool console; // Indica si ha de mostrar información por la consola de texto
cheat_t cheat; // Contiene trucos y ventajas para el juego
int rooms; // Cantidad de habitaciones visitadas
int items; // Cantidad de items obtenidos
online_t online; // Datos del servicio online
};
// Calcula el cuadrado de la distancia entre dos puntos

View File

@@ -168,7 +168,7 @@ void Credits::fillTexture()
{
// Inicializa los textos
iniTexts();
// Rellena la textura de texto
SDL_SetRenderTarget(renderer, textTexture);
color_t c = stringToColor(options->palette, "black");
@@ -264,6 +264,9 @@ void Credits::update()
// Actualiza el contador
updateCounter();
// Actualiza las notificaciones
screen->updateNotifier();
// Actualiza el sprite con el brillo
if (counter > 770)
{

View File

@@ -153,6 +153,9 @@ void Demo::update()
scoreboard->update();
screen->updateFX();
checkRoomChange();
// Actualiza las notificaciones
screen->updateNotifier();
}
}
@@ -189,7 +192,7 @@ void Demo::renderRoomName()
// Recarga todas las texturas
void Demo::reLoadTextures()
{
if (options->console)
if (options->console)
{
std::cout << "** RELOAD REQUESTED" << std::endl;
}

View File

@@ -1,7 +1,15 @@
#include "director.h"
#include "common/jscore.h"
#include "common/utils.h"
#include "director.h"
#include <errno.h>
#include <iostream>
#include <string>
#include <sys/stat.h>
#include <unistd.h>
#ifndef _WIN32
#include <pwd.h>
#endif
// Constructor
Director::Director(int argc, char *argv[])
@@ -19,6 +27,9 @@ Director::Director(int argc, char *argv[])
// Comprueba los parametros del programa
checkProgramArguments(argc, argv);
// Crea la carpeta del sistema donde guardar datos
createSystemFolder();
// Crea el objeto que controla los ficheros de recursos
asset = new Asset(executablePath);
asset->setVerbose(options->console);
@@ -26,7 +37,7 @@ Director::Director(int argc, char *argv[])
// Si falta algún fichero no inicia el programa
if (!setFileList())
{
section.name = SECTION_PROG_QUIT;
exit(EXIT_FAILURE);
}
// Inicializa variables desde el fichero de configuración
@@ -42,11 +53,13 @@ Director::Director(int argc, char *argv[])
resource = new Resource(renderer, asset, options);
input = new Input(asset->get("gamecontrollerdb.txt"));
initInput();
screen = new Screen(window, renderer, options, GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT);
screen = new Screen(window, renderer, asset, options);
screen->setBorderColor(borderColor);
screen->setVideoMode(options->fullScreenMode);
debug = new Debug(renderer, screen, asset);
music = JA_LoadMusic(asset->get("title.ogg").c_str());
// Inicializa los servicios online
//initOnline();
}
Director::~Director()
@@ -68,6 +81,56 @@ Director::~Director()
SDL_Quit();
}
// Inicializa los servicios online
void Director::initOnline()
{
if (!options->online.enabled)
{
return;
}
// Obten el Jailer ID
if (options->online.jailerID == "")
{ // Jailer ID no definido
screen->showText("No ha especificado ningun Jailer ID");
std::cout << "No ha especificado ningun Jailer ID" << std::endl;
}
else
{ // Jailer ID iniciado
// Establece el servidor y el puerto
jscore::init(options->online.server, options->online.port);
// Obtiene la información online
if (jscore::initOnlineScore(options->online.gameID))
{
screen->showText(options->online.jailerID + " ha iniciado sesion");
std::cout << options->online.jailerID << " ha iniciado sesion" << std::endl;
}
else
{
screen->showText("Fallo al conectar a " + options->online.server);
std::cout << "Fallo al conectar a " << options->online.server << std::endl;
options->online.enabled = false;
return;
}
// Obten las estadisticas online
const int points = jscore::getUserPoints(options->online.gameID, options->online.jailerID);
if (points == 0)
{ // Fallo de conexión o no hay registros
screen->showText("No se ha podido obtener la puntuacion online");
std::cout << "No se ha podido obtener la puntuacion online" << std::endl;
}
else
{
options->online.score = points;
}
}
}
// Crea e inicializa las opciones del programa
void Director::iniOptions()
{
@@ -75,14 +138,16 @@ void Director::iniOptions()
options = new options_t;
// Inicializa valores
options->fullScreenMode = 0;
options->gameWidth = GAMECANVAS_WIDTH;
options->gameHeight = GAMECANVAS_HEIGHT;
options->videoMode = 0;
options->windowSize = 3;
options->filter = FILTER_NEAREST;
options->vSync = true;
options->integerScale = true;
options->keepAspect = true;
options->borderEnabled = true;
options->borderSize = 0.1f;
options->borderSize = 0.2f;
options->palette = p_zxspectrum;
// Estos valores no se guardan en el fichero de configuraci´ón
@@ -91,6 +156,15 @@ void Director::iniOptions()
options->cheat.invincible = false;
options->cheat.jailEnabled = false;
options->cheat.altSkin = false;
options->rooms = 0;
options->items = 0;
// Online
options->online.enabled = false;
options->online.server = "";
options->online.port = 0;
options->online.gameID = "jaildoctors_dilemma_test";
options->online.jailerID = "";
}
// Comprueba los parametros del programa
@@ -181,19 +255,33 @@ bool Director::loadConfig()
saveConfig();
}
// Normaliza los valores
const bool a = options->videoMode == 0;
const bool b = options->videoMode == SDL_WINDOW_FULLSCREEN;
const bool c = options->videoMode == SDL_WINDOW_FULLSCREEN_DESKTOP;
if (!(a || b || c))
{
options->videoMode = 0;
}
if (options->windowSize < 1 || options->windowSize > 4)
{
options->windowSize = 3;
}
// Aplica opciones
if (options->borderEnabled)
{
const int incWidth = GAMECANVAS_WIDTH * options->borderSize;
const int incHeight = GAMECANVAS_HEIGHT * options->borderSize;
options->screenWidth = (GAMECANVAS_WIDTH + incWidth) * options->windowSize;
options->screenHeight = (GAMECANVAS_HEIGHT + incHeight) * options->windowSize;
}
else
{
options->screenWidth = GAMECANVAS_WIDTH * options->windowSize;
options->screenHeight = GAMECANVAS_HEIGHT * options->windowSize;
}
// if (options->borderEnabled)
//{
// const int incWidth = GAMECANVAS_WIDTH * options->borderSize;
// const int incHeight = GAMECANVAS_HEIGHT * options->borderSize;
// options->gameWidth = GAMECANVAS_WIDTH + incWidth;
// options->gameHeight = GAMECANVAS_HEIGHT + incHeight;
//}
// else
//{
// options->gameWidth = GAMECANVAS_WIDTH;
// options->gameHeight = GAMECANVAS_HEIGHT;
//}
return success;
}
@@ -206,20 +294,36 @@ bool Director::saveConfig()
// Crea y abre el fichero de texto
std::ofstream file(asset->get("config.txt"));
if (file.good())
{
if (options->console)
{
std::cout << asset->get("config.txt") << " open for writing" << std::endl;
}
}
else
{
if (options->console)
{
std::cout << asset->get("config.txt") << " can't be opened" << std::endl;
}
}
// Escribe en el fichero
if (options->fullScreenMode == 0)
file << "## VISUAL OPTIONS\n";
if (options->videoMode == 0)
{
file << "fullScreenMode=0\n";
file << "videoMode=0\n";
}
else if (options->fullScreenMode == SDL_WINDOW_FULLSCREEN)
else if (options->videoMode == SDL_WINDOW_FULLSCREEN)
{
file << "fullScreenMode=SDL_WINDOW_FULLSCREEN\n";
file << "videoMode=SDL_WINDOW_FULLSCREEN\n";
}
else if (options->fullScreenMode == SDL_WINDOW_FULLSCREEN_DESKTOP)
else if (options->videoMode == SDL_WINDOW_FULLSCREEN_DESKTOP)
{
file << "fullScreenMode=SDL_WINDOW_FULLSCREEN_DESKTOP\n";
file << "videoMode=SDL_WINDOW_FULLSCREEN_DESKTOP\n";
}
file << "windowSize=" + std::to_string(options->windowSize) + "\n";
@@ -240,12 +344,64 @@ bool Director::saveConfig()
file << "borderSize=" + std::to_string(options->borderSize) + "\n";
file << "palette=" + std::to_string(options->palette) + "\n";
file << "\n## ONLINE OPTIONS\n";
file << "enabled=" + boolToString(options->online.enabled) + "\n";
file << "server=" + options->online.server + "\n";
file << "port=" + std::to_string(options->online.port) + "\n";
file << "jailerID=" + options->online.jailerID + "\n";
// Cierra el fichero
file.close();
return success;
}
// Crea la carpeta del sistema donde guardar datos
void Director::createSystemFolder()
{
#ifdef _WIN32
systemFolder = std::string(getenv("APPDATA")) + "/jaildoctors_dilemma";
#elif __APPLE__
struct passwd *pw = getpwuid(getuid());
const char *homedir = pw->pw_dir;
systemFolder = std::string(homedir) + "/Library/Application Support/jaildoctors_dilemma";
#elif __linux__
struct passwd *pw = getpwuid(getuid());
const char *homedir = pw->pw_dir;
systemFolder = std::string(homedir) + "/.jaildoctors_dilemma";
#endif
struct stat st = {0};
if (stat(systemFolder.c_str(), &st) == -1)
{
errno = 0;
#ifdef _WIN32
int ret = mkdir(systemFolder.c_str());
#else
int ret = mkdir(systemFolder.c_str(), S_IRWXU);
#endif
if (ret == -1)
{
switch (errno)
{
case EACCES:
printf("the parent directory does not allow write");
exit(EXIT_FAILURE);
case EEXIST:
printf("pathname already exists");
exit(EXIT_FAILURE);
case ENAMETOOLONG:
printf("pathname is too long");
exit(EXIT_FAILURE);
default:
perror("mkdir");
exit(EXIT_FAILURE);
}
}
}
}
// Carga los recursos
void Director::loadResources(section_t section)
{
@@ -810,19 +966,19 @@ bool Director::setOptions(options_t *options, std::string var, std::string value
// Indicador de éxito en la asignación
bool success = true;
if (var == "fullScreenMode")
if (var == "videoMode")
{
if (value == "SDL_WINDOW_FULLSCREEN_DESKTOP")
{
options->fullScreenMode = SDL_WINDOW_FULLSCREEN_DESKTOP;
options->videoMode = SDL_WINDOW_FULLSCREEN_DESKTOP;
}
else if (value == "SDL_WINDOW_FULLSCREEN")
{
options->fullScreenMode = SDL_WINDOW_FULLSCREEN;
options->videoMode = SDL_WINDOW_FULLSCREEN;
}
else
{
options->fullScreenMode = 0;
options->videoMode = 0;
}
}
@@ -891,7 +1047,31 @@ bool Director::setOptions(options_t *options, std::string var, std::string value
}
}
else if (var == "")
else if (var == "enabled")
{
options->online.enabled = stringToBool(value);
}
else if (var == "server")
{
options->online.server = value;
}
else if (var == "port")
{
if (value == "")
{
value = "0";
}
options->online.port = std::stoi(value);
}
else if (var == "jailerID")
{
options->online.jailerID = value;
}
else if (var == "" || var.substr(0, 1) == "#")
{
}
@@ -971,7 +1151,15 @@ bool Director::initSDL()
}
// Crea la ventana
window = SDL_CreateWindow(WINDOW_CAPTION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, options->screenWidth, options->screenHeight, SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI);
int incW = 0;
int incH = 0;
if (options->borderEnabled)
{
incW = options->gameWidth * options->borderSize;
incH = options->gameHeight * options->borderSize;
}
window = SDL_CreateWindow(WINDOW_CAPTION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (options->gameWidth + incW) * options->windowSize, (options->gameHeight + incH) * options->windowSize, SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI);
if (window == nullptr)
{
if (options->console)
@@ -1006,7 +1194,7 @@ bool Director::initSDL()
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);
// Establece el tamaño del buffer de renderizado
SDL_RenderSetLogicalSize(renderer, options->screenWidth, options->screenHeight);
SDL_RenderSetLogicalSize(renderer, options->gameWidth, options->gameHeight);
// Establece el modo de mezcla
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
@@ -1039,6 +1227,7 @@ bool Director::setFileList()
// Configuración
asset->add(prefix + "/data/input/gamecontrollerdb.txt", t_data);
asset->add(prefix + "/data/config/config.txt", t_data, false);
asset->add(systemFolder + "/stats.csv", t_data, false, true);
// Habitaciones
asset->add(prefix + "/data/room/01.room", t_room);
@@ -1555,4 +1744,4 @@ void Director::run()
break;
}
}
}
}

View File

@@ -40,7 +40,7 @@ private:
Credits *credits; // Objeto para gestionar los creditos del juego
Demo *demo; // Objeto para gestionar el modo demo, en el que se ven pantallas del juego
Ending *ending; // Objeto para gestionar el final del juego
Ending2 *ending2; // Objeto para gestionar el final del juego
Ending2 *ending2; // Objeto para gestionar el final del juego
GameOver *gameOver; // Objeto para gestionar el final de la partida
Debug *debug; // Objeto para getsionar la información de debug
struct options_t *options; // Variable con todas las opciones del programa
@@ -49,6 +49,10 @@ private:
JA_Music music; // Musica del titulo
std::string executablePath; // Path del ejecutable
section_t section; // Sección y subsección actual del programa;
std::string systemFolder; // Carpeta del sistema donde guardar datos
// Inicializa los servicios online
void initOnline();
// Crea e inicializa las opciones del programa
void iniOptions();
@@ -62,6 +66,9 @@ private:
// Guarda el fichero de configuración
bool saveConfig();
// Crea la carpeta del sistema donde guardar datos
void createSystemFolder();
// Carga los recursos
void loadResources(section_t section);

View File

@@ -103,6 +103,9 @@ void Ending::update()
// Actualiza el volumen de la musica
updateMusicVolume();
// Actualiza las notificaciones
screen->updateNotifier();
}
}

View File

@@ -102,6 +102,9 @@ void Ending2::update()
// Actualiza el volumen de la musica
updateMusicVolume();
// Actualiza las notificaciones
screen->updateNotifier();
}
}

View File

@@ -21,9 +21,9 @@ Game::Game(SDL_Renderer *renderer, Screen *screen, Resource *resource, Asset *as
this->options = options;
#ifdef DEBUG
currentRoom = "48.room";
const int x1 = 18;
const int y1 = 13;
currentRoom = "02.room";
const int x1 = 20;
const int y1 = 6;
spawnPoint = {x1 * 8, y1 * 8, 0, 0, 0, s_standing, SDL_FLIP_HORIZONTAL};
#endif
@@ -40,6 +40,8 @@ Game::Game(SDL_Renderer *renderer, Screen *screen, Resource *resource, Asset *as
text = new Text(resource->getOffset("smb2.txt"), resource->getTexture("smb2.png"), renderer);
music = JA_LoadMusic(asset->get("game.ogg").c_str());
deathSound = JA_LoadSound(asset->get("death.wav").c_str());
stats = new Stats(asset->get("stats.csv"));
stats->addVisit(room->getName());
// Inicializa el resto de variables
ticks = 0;
@@ -70,6 +72,7 @@ Game::~Game()
delete player;
delete eventHandler;
delete text;
delete stats;
JA_DeleteMusic(music);
JA_DeleteSound(deathSound);
@@ -89,6 +92,11 @@ void Game::checkEventHandler()
break;
}
if (eventHandler->type == SDL_RENDER_DEVICE_RESET || eventHandler->type == SDL_RENDER_TARGETS_RESET)
{
reLoadTextures();
}
if ((eventHandler->type == SDL_KEYDOWN) and (eventHandler->key.repeat == 0))
{
switch (eventHandler->key.keysym.scancode)
@@ -123,6 +131,10 @@ void Game::checkEventHandler()
case SDL_SCANCODE_D:
goToRoom(BORDER_RIGHT);
break;
case SDL_SCANCODE_F6:
screen->showText("MAMA MIRA! SIN MANOS!");
break;
#endif
case SDL_SCANCODE_M:
@@ -210,7 +222,7 @@ void Game::update()
#ifdef DEBUG
debug->clear();
#endif
// Actualiza los objetos
room->update();
player->update();
@@ -220,11 +232,15 @@ void Game::update()
checkIfPlayerIsAlive();
checkGameOver();
checkEndGame();
checkRestoringJail();
scoreboard->update();
input->update();
updateBlackScreen();
// Actualiza las notificaciones
screen->updateNotifier();
#ifdef DEBUG
updateDebugInfo();
#endif
@@ -329,8 +345,13 @@ bool Game::changeRoom(std::string file)
setScoreBoardColor();
if (roomTracker->addRoom(file))
{ // Incrementa el contador de habitaciones visitadas
{
// Incrementa el contador de habitaciones visitadas
board.rooms++;
options->rooms = board.rooms;
// Actualiza las estadisticas
stats->addVisit(room->getName());
}
// Pasa la nueva habitación al jugador
@@ -406,6 +427,9 @@ void Game::killPlayer()
board.lives--;
}
// Actualiza las estadisticas
stats->addDeath(room->getName());
// Destruye la habitacion y el jugador
delete room;
delete this->player;
@@ -577,4 +601,22 @@ void Game::switchPause()
scoreboard->pause();
paused = true;
}
}
// Da vidas al jugador cuando está en la Jail
void Game::checkRestoringJail()
{
if (room->getName() != "THE JAIL" || board.lives == 9)
{
return;
}
static int counter = 0;
counter++;
if (counter == 100)
{
counter = 0;
board.lives++;
JA_PlaySound(deathSound);
}
}

View File

@@ -17,6 +17,7 @@
#include "room_tracker.h"
#include "room.h"
#include "scoreboard.h"
#include "stats.h"
#ifndef GAME_H
#define GAME_H
@@ -39,6 +40,7 @@ private:
Resource *resource; // Objeto con los recursos
Debug *debug; // Objeto para gestionar la información de debug
options_t *options; // Puntero a las opciones del juego
Stats *stats; // Objeto encargado de gestionar las estadísticas
// Variables
JA_Music music; // Musica que suena durante el juego
@@ -125,6 +127,9 @@ private:
// Pone el juego en pausa
void switchPause();
// Da vidas al jugador cuando está en la Jail
void checkRestoringJail();
public:
// Constructor
Game(SDL_Renderer *renderer, Screen *screen, Resource *resource, Asset *asset, options_t *options, Input *input, Debug *debug);

View File

@@ -28,9 +28,9 @@ GameOver::GameOver(SDL_Renderer *renderer, Screen *screen, Resource *resource, A
iniFade = 310;
fadeLenght = 20;
playerSprite->setPosX(GAMECANVAS_CENTER_X + 10);
playerSprite->setPosY(GAMECANVAS_CENTER_Y + 10);
playerSprite->setPosY(GAMECANVAS_CENTER_Y - 10);
tvSprite->setPosX(GAMECANVAS_CENTER_X - tvSprite->getAnimationClip(0, 0).w - 10);
tvSprite->setPosY(GAMECANVAS_CENTER_Y + 10);
tvSprite->setPosY(GAMECANVAS_CENTER_Y - 10);
// Inicializa el vector de colores
const std::vector<std::string> colorList = {"white", "yellow", "cyan", "green", "magenta", "red", "blue", "black"};
@@ -73,6 +73,9 @@ void GameOver::update()
// Actualiza los dos sprites
playerSprite->update();
tvSprite->update();
// Actualiza las notificaciones
screen->updateNotifier();
}
}
@@ -86,12 +89,16 @@ void GameOver::render()
screen->clean();
// Escribe el texto de GAME OVER
text->writeDX(TXT_CENTER | TXT_COLOR, GAMECANVAS_CENTER_X, GAMECANVAS_CENTER_Y - 20, "G A M E O V E R", 1, color);
text->writeDX(TXT_CENTER | TXT_COLOR, GAMECANVAS_CENTER_X, GAMECANVAS_CENTER_Y - 40, "G A M E O V E R", 1, color);
// Dibuja los sprites
renderSprites();
// text->write(0, 0, std::to_string(counter));
// Escribe el texto con las habitaciones y los items
const std::string itemsTxt = std::to_string(options->items / 100) + std::to_string((options->items % 100) / 10) + std::to_string(options->items % 10);
const std::string roomsTxt = std::to_string(options->rooms / 100) + std::to_string((options->rooms % 100) / 10) + std::to_string(options->rooms % 10);
text->writeDX(TXT_CENTER | TXT_COLOR, GAMECANVAS_CENTER_X, GAMECANVAS_CENTER_Y + 40, "ITEMS: " + itemsTxt, 1, color);
text->writeDX(TXT_CENTER | TXT_COLOR, GAMECANVAS_CENTER_X, GAMECANVAS_CENTER_Y + 55, "ROOMS: " + roomsTxt, 1, color);
// Vuelca el contenido del renderizador en pantalla
screen->blit();
@@ -180,7 +187,7 @@ void GameOver::updateColor()
if (counter < half)
{
//const float step = std::min(std::max(counter, iniFade) - iniFade, fadeLenght) / (float)fadeLenght;
// const float step = std::min(std::max(counter, iniFade) - iniFade, fadeLenght) / (float)fadeLenght;
const float step = std::min(counter, fadeLenght) / (float)fadeLenght;
const int index = (colors.size() - 1) - int((colors.size() - 1) * step);
color = colors.at(index);

View File

@@ -251,6 +251,9 @@ void Intro::update()
// Gestiona el contador de carga
updateLoad();
// Actualiza las notificaciones
screen->updateNotifier();
// Comprueba si ha terminado la intro
if (loadCounter >= 768)
{
@@ -281,7 +284,7 @@ void Intro::render()
section_t Intro::run()
{
// Inicia el sonido de carga
JA_SetVolume(64);
JA_SetVolume(64);
JA_PlayMusic(loadingSound1);
while (section.name == SECTION_PROG_INTRO)
@@ -290,7 +293,7 @@ section_t Intro::run()
render();
}
JA_SetVolume(128);
JA_SetVolume(128);
return section;
}

View File

@@ -85,7 +85,7 @@ void Logo::checkEventHandler()
switch (eventHandler->key.keysym.scancode)
{
case SDL_SCANCODE_ESCAPE:
//std::cout << "PULSADO ESCAPE" << std::endl;
// std::cout << "PULSADO ESCAPE" << std::endl;
section.name = SECTION_PROG_QUIT;
break;
@@ -262,6 +262,9 @@ void Logo::update()
// Gestiona el color de las texturas
updateTextureColors();
// Actualiza las notificaciones
screen->updateNotifier();
// Comprueba si ha terminado el logo
if (counter == endLogo + postLogo)
{

View File

@@ -823,6 +823,8 @@ void Player::setState(state_e value)
{
prevState = state;
state = value;
checkState();
}
// Comprueba si el jugador esta vivo

View File

@@ -824,6 +824,7 @@ bool Room::itemCollision(SDL_Rect &rect)
items.erase(items.begin() + i);
JA_PlaySound(itemSound);
*itemsPicked = *itemsPicked + 1;
options->items = *itemsPicked;
return true;
}
}

158
source/stats.cpp Normal file
View File

@@ -0,0 +1,158 @@
#include "stats.h"
#include <iostream>
#include <fstream>
#include <sstream>
// Constructor
Stats::Stats(std::string file)
{
filePath = file;
list.clear();
loadFromFile();
}
// Destructor
Stats::~Stats()
{
#ifndef DEBUG
saveToFile();
#endif
list.clear();
}
// Añade una muerte a las estadisticas
void Stats::addDeath(std::string name)
{
// Primero busca si ya hay una entrada con ese nombre
const int index = findByName(name);
if (index != -1)
{
list.at(index).died++;
}
// En caso contrario crea la entrada
else
{
stats_t item;
item.name = name;
item.visited = 0;
item.died = 1;
list.push_back(item);
}
}
// Añade una visita a las estadisticas
void Stats::addVisit(std::string name)
{
// Primero busca si ya hay una entrada con ese nombre
const int index = findByName(name);
if (index != -1)
{
list.at(index).visited++;
}
// En caso contrario crea la entrada
else
{
stats_t item;
item.name = name;
item.visited = 1;
item.died = 0;
list.push_back(item);
}
}
// Busca una entrada en la lista por nombre
int Stats::findByName(std::string name)
{
int i = 0;
for (auto l : list)
{
if (l.name == name)
{
return i;
}
i++;
}
return -1;
}
// Carga las estadisticas desde un fichero
bool Stats::loadFromFile()
{
// Indicador de éxito en la carga
bool success = true;
// Variables para manejar el fichero
std::string line;
std::ifstream file(filePath);
// Si el fichero se puede abrir
if (file.good())
{
// Procesa el fichero linea a linea
while (std::getline(file, line))
{
// Comprueba que la linea no sea un comentario
if (line.substr(0, 1) != "#")
{
stats_t stat;
std::stringstream ss(line);
std::string tmp;
// Obtiene el nombre
getline(ss, tmp, ';');
stat.name = tmp;
// Obtiene las visitas
getline(ss, tmp, ';');
stat.visited = std::stoi(tmp);
// Obtiene las muertes
getline(ss, tmp, ';');
stat.died = std::stoi(tmp);
list.push_back(stat);
}
}
// Cierra el fichero
file.close();
}
// El fichero no existe
else
{ // Crea el fichero con los valores por defecto
saveToFile();
}
return success;
}
// Guarda las estadisticas en un fichero
void Stats::saveToFile()
{
// Crea y abre el fichero de texto
std::ofstream file(filePath);
if (file.good())
{
std::cout << filePath << " open for writing" << std::endl;
}
else
{
std::cout << filePath << " can't be opened" << std::endl;
}
// Escribe en el fichero
file << "# NOMBRE DE LA HABITACION;VISITAS;MUERTES" << std::endl;
for (auto item : list)
{
file << item.name << ";" << item.visited << ";" << item.died << std::endl;
}
// Cierra el fichero
file.close();
}

47
source/stats.h Normal file
View File

@@ -0,0 +1,47 @@
#pragma once
#include <SDL2/SDL.h>
#include "common/utils.h"
#include <string>
#include <vector>
#ifndef STATS_H
#define STATS_H
struct stats_t
{
std::string name; // Nombre de la habitación donde se encuentra el objeto
int visited; // Cuenta las veces que se ha visitado una habitación
int died; // Cuenta las veces que se ha muerto en una habitación
};
class Stats
{
private:
// Variables
std::vector<stats_t> list; // Lista con las estadisticas por habitación
std::string filePath; // Fichero con las estadísticas
// Busca una entrada en la lista por nombre
int findByName(std::string name);
// Carga las estadisticas desde un fichero
bool loadFromFile();
// Guarda las estadisticas en un fichero
void saveToFile();
public:
// Constructor
Stats(std::string file);
// Destructor
~Stats();
// Añade una muerte a las estadisticas
void addDeath(std::string name);
// Añade una visita a las estadisticas
void addVisit(std::string name);
};
#endif

View File

@@ -1,74 +0,0 @@
#include "test.h"
// Constructor
Test::Test(SDL_Renderer *renderer, Screen *screen, Asset *asset, Debug *debug)
{
// Copia la dirección de los objetos
this->renderer = renderer;
this->screen = screen;
this->asset = asset;
this->debug = debug;
// Inicializa variables
for (int i = 0; i < 4; ++i)
{
point_t p;
p.x = rand() % 256;
p.y = rand() % 192;
p.vx = (float)((rand() % 10) + 1) / 10.0f;
p.vy = (float)((rand() % 10) + 1) / 10.0f;
rand() % 2 == 0 ? p.dx = -1 : p.dx = 1;
rand() % 2 == 0 ? p.dy = -1 : p.dy = 1;
p.vx *= p.dx;
p.vy *= p.dy;
points.push_back(p);
}
}
// Actualiza las variables
void Test::update()
{
for (int i = 0; i < (int)points.size(); ++i)
{
points[i].x += points[i].vx;
points[i].y += points[i].vy;
if (points[i].x > 255)
{
points[i].x = 255;
points[i].vx = -(float)((rand() % 10) + 1) / 10.0f;
}
else if (points[i].x < 0)
{
points[i].x = 0;
points[i].vx = (float)((rand() % 10) + 1) / 10.0f;
}
if (points[i].y > 191)
{
points[i].y = 191;
points[i].vy = -(float)((rand() % 10) + 1) / 10.0f;
}
else if (points[i].y < 0)
{
points[i].y = 0;
points[i].vy = (float)((rand() % 10) + 1) / 10.0f;
}
std::string text = "P" + std::to_string(i) + ": x=" + std::to_string(points[i].x).substr(0,3) + " y=" + std::to_string(points[i].y).substr(0,3) + " vx=" + std::to_string(points[i].vx).substr(0,3) + " vy=" + std::to_string(points[i].vy).substr(0,3);
debug->add(text);
}
}
// Dibuja en pantalla
void Test::render()
{
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
line_t l1 = {(int)points[0].x, (int)points[0].y, (int)points[1].x, (int)points[1].y};
line_t l2 = {(int)points[2].x, (int)points[2].y, (int)points[3].x, (int)points[3].y};
SDL_RenderDrawLine(renderer, l1.x1, l1.y1, l1.x2, l1.y2);
SDL_RenderDrawLine(renderer, l2.x1, l2.y1, l2.x2, l2.y2);
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
SDL_Point p = checkCollision(l1, l2);
SDL_RenderDrawPoint(renderer, p.x, p.y);
}

View File

@@ -1,46 +0,0 @@
#pragma once
#include <SDL2/SDL.h>
#include "common/asset.h"
#include "common/debug.h"
#include "common/screen.h"
#include "common/text.h"
#include "common/utils.h"
#include "const.h"
#include <string>
#include <vector>
#ifndef TEST_H
#define TEST_H
struct point_t
{
float x, y;
float vx, vy;
int dx, dy;
};
class Test
{
private:
// Objetos y punteros
SDL_Renderer *renderer; // El renderizador de la ventana
Screen *screen; // Objeto encargado de dibujar en pantalla
Asset *asset; // Objeto con los ficheros de recursos
Debug *debug;
// Variables
std::vector<point_t> points;
public:
// Constructor
Test(SDL_Renderer *renderer, Screen *screen, Asset *asset, Debug *debug);
// Actualiza las variables
void update();
// Dibuja en pantalla
void render();
};
#endif

View File

@@ -115,6 +115,12 @@ void Title::checkEventHandler()
switchPalette();
break;
#ifdef DEBUG
case SDL_SCANCODE_F6:
screen->showText("MAMA MIRA! SIN MANOS!");
break;
#endif
default:
break;
}
@@ -176,6 +182,9 @@ void Title::update()
// Actualiza la marquesina
updateMarquee();
// Actualiza las notificaciones
screen->updateNotifier();
// Comprueba si ha terminado la marquesina y acaba con el titulo
if (letters.at(letters.size() - 1).x < -10)
{