Compare commits
39 Commits
ada5025c65
...
2025-08-21
| Author | SHA1 | Date | |
|---|---|---|---|
| 7250073d60 | |||
| dfa06870e4 | |||
| 81f3a25143 | |||
| 5aca95f3d2 | |||
| 7b193605e6 | |||
| 089a5b15d7 | |||
| e6a14ca57d | |||
| 467d609c28 | |||
| e03c798000 | |||
| 52d76b7338 | |||
| 83ee9c2649 | |||
| 43788bb01a | |||
| 58cf78e1e3 | |||
| 6bf8490776 | |||
| 8cfe28922c | |||
| 63990c75c2 | |||
| 94dca528ab | |||
| 4b6b89ceb2 | |||
| ed077c1da5 | |||
| 2819b3628e | |||
| 1e9e664012 | |||
| 0c8b39cee7 | |||
| d7b3af5ab8 | |||
| 5e5227305f | |||
| 3fc15a9512 | |||
| e774e0e8ad | |||
| a95776e6c7 | |||
| 0428ff26d5 | |||
| fc3e2deb1f | |||
| 65ca17f938 | |||
| ff2a51a507 | |||
| fe0083abd4 | |||
| 1c058694fd | |||
| cb0c3266d5 | |||
| 8ddc5d94f1 | |||
| b359a73d50 | |||
| 142603db71 | |||
| 1ec272f017 | |||
| 327987447d |
@@ -6,7 +6,14 @@ BreakBeforeBraces: Attach # Llaves en la misma línea
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AlignOperands: false
|
||||
AlignOperands: DontAlign
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
ContinuationIndentWidth: 4
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
Cpp11BracedListStyle: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
|
||||
15
.clang-tidy
15
.clang-tidy
@@ -1,10 +1,21 @@
|
||||
Checks: >
|
||||
readability-*,
|
||||
modernize-*,
|
||||
bugprone-*,
|
||||
performance-*,
|
||||
bugprone-unchecked-optional-access,
|
||||
bugprone-sizeof-expression,
|
||||
bugprone-suspicious-missing-comma,
|
||||
bugprone-suspicious-index,
|
||||
bugprone-undefined-memory-manipulation,
|
||||
bugprone-use-after-move,
|
||||
bugprone-out-of-bound-access,
|
||||
-readability-identifier-length,
|
||||
-readability-magic-numbers
|
||||
-readability-magic-numbers,
|
||||
-bugprone-narrowing-conversions,
|
||||
-performance-enum-size,
|
||||
-performance-inefficient-string-concatenation,
|
||||
-bugprone-integer-division,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
|
||||
WarningsAsErrors: '*'
|
||||
# Solo incluir archivos de tu código fuente
|
||||
|
||||
@@ -28,6 +28,9 @@ set(APP_SOURCES
|
||||
source/main.cpp
|
||||
source/param.cpp
|
||||
source/resource.cpp
|
||||
source/resource_helper.cpp
|
||||
source/resource_loader.cpp
|
||||
source/resource_pack.cpp
|
||||
source/screen.cpp
|
||||
source/text.cpp
|
||||
source/writer.cpp
|
||||
|
||||
22
LICENSE
22
LICENSE
@@ -1 +1,21 @@
|
||||
GNU General Public License v3.0 only
|
||||
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
|
||||
|
||||
Copyright (c) 2025 Coffee Crisis Arcade Edition
|
||||
|
||||
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
|
||||
|
||||
You are free to:
|
||||
- Share — copy and redistribute the material in any medium or format
|
||||
- Adapt — remix, transform, and build upon the material
|
||||
|
||||
Under the following terms:
|
||||
- Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
|
||||
- NonCommercial — You may not use the material for commercial purposes.
|
||||
- ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
|
||||
|
||||
No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
|
||||
|
||||
To view a copy of this license, visit:
|
||||
https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
25
Makefile
25
Makefile
@@ -71,6 +71,9 @@ APP_SOURCES := \
|
||||
source/path_sprite.cpp \
|
||||
source/player.cpp \
|
||||
source/resource.cpp \
|
||||
source/resource_helper.cpp \
|
||||
source/resource_loader.cpp \
|
||||
source/resource_pack.cpp \
|
||||
source/scoreboard.cpp \
|
||||
source/screen.cpp \
|
||||
source/sections/credits.cpp \
|
||||
@@ -104,7 +107,7 @@ INCLUDES := -Isource -Isource/external
|
||||
# Variables según el sistema operativo
|
||||
ifeq ($(OS),Windows_NT)
|
||||
FixPath = $(subst /,\\,$1)
|
||||
CXXFLAGS := -std=c++20 -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows -DWINDOWS_BUILD
|
||||
CXXFLAGS := -std=c++20 -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -static-libgcc -Wl,-Bstatic -lpthread -Wl,-Bdynamic -Wl,-subsystem,windows -DWINDOWS_BUILD
|
||||
CXXFLAGS_DEBUG := -std=c++20 -Wall -g -D_DEBUG -DWINDOWS_BUILD
|
||||
LDFLAGS := -lmingw32 -lws2_32 -lSDL3 -lopengl32
|
||||
RM := del /Q
|
||||
@@ -158,8 +161,9 @@ windows_release:
|
||||
powershell if (Test-Path "$(RELEASE_FOLDER)") {Remove-Item "$(RELEASE_FOLDER)" -Recurse -Force}
|
||||
powershell if (-not (Test-Path "$(RELEASE_FOLDER)")) {New-Item "$(RELEASE_FOLDER)" -ItemType Directory}
|
||||
|
||||
# Copia la carpeta 'data'
|
||||
powershell Copy-Item -Path "data" -Destination "$(RELEASE_FOLDER)" -recurse -Force
|
||||
# Copia la carpeta 'config' y el archivo 'resources.pack'
|
||||
powershell Copy-Item -Path "config" -Destination "$(RELEASE_FOLDER)" -recurse -Force
|
||||
powershell Copy-Item -Path "resources.pack" -Destination "$(RELEASE_FOLDER)"
|
||||
|
||||
# Copia los ficheros que estan en la raíz del proyecto
|
||||
powershell Copy-Item "LICENSE" -Destination "$(RELEASE_FOLDER)"
|
||||
@@ -203,7 +207,8 @@ macos_release:
|
||||
$(MKDIR) Frameworks
|
||||
|
||||
# Copia carpetas y ficheros
|
||||
cp -R data "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||
cp -R config "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||
cp resources.pack "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||
cp -R release/frameworks/SDL3.xcframework "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks"
|
||||
cp -R release/frameworks/SDL3.xcframework Frameworks
|
||||
cp release/*.icns "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||
@@ -262,7 +267,8 @@ linux_release:
|
||||
$(MKDIR) "$(RELEASE_FOLDER)"
|
||||
|
||||
# Copia ficheros
|
||||
cp -R data "$(RELEASE_FOLDER)"
|
||||
cp -R config "$(RELEASE_FOLDER)"
|
||||
cp resources.pack "$(RELEASE_FOLDER)"
|
||||
cp LICENSE "$(RELEASE_FOLDER)"
|
||||
cp README.md "$(RELEASE_FOLDER)"
|
||||
|
||||
@@ -291,7 +297,8 @@ linux_release_desktop:
|
||||
$(MKDIR) "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/$(TARGET_NAME)"
|
||||
|
||||
# Copia ficheros del juego
|
||||
cp -R data "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/$(TARGET_NAME)/"
|
||||
cp -R config "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/$(TARGET_NAME)/"
|
||||
cp resources.pack "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/$(TARGET_NAME)/"
|
||||
cp LICENSE "$(RELEASE_FOLDER)/$(TARGET_NAME)/"
|
||||
cp README.md "$(RELEASE_FOLDER)/$(TARGET_NAME)/"
|
||||
|
||||
@@ -391,7 +398,8 @@ raspi_release:
|
||||
$(MKDIR) "$(RELEASE_FOLDER)"
|
||||
|
||||
# Copia ficheros
|
||||
cp -R data "$(RELEASE_FOLDER)"
|
||||
cp -R config "$(RELEASE_FOLDER)"
|
||||
cp resources.pack "$(RELEASE_FOLDER)"
|
||||
cp LICENSE "$(RELEASE_FOLDER)"
|
||||
cp README.md "$(RELEASE_FOLDER)"
|
||||
|
||||
@@ -416,7 +424,8 @@ anbernic:
|
||||
$(MKDIR) "$(RELEASE_FOLDER)"_anbernic
|
||||
|
||||
# Copia ficheros
|
||||
cp -R data "$(RELEASE_FOLDER)"_anbernic
|
||||
cp -R config "$(RELEASE_FOLDER)"_anbernic
|
||||
cp resources.pack "$(RELEASE_FOLDER)"_anbernic
|
||||
|
||||
# Compila
|
||||
$(CXX) $(APP_SOURCES) $(INCLUDES) -DANBERNIC -DNO_SHADERS -DARCADE -DVERBOSE $(CXXFLAGS) $(LDFLAGS) -o $(RELEASE_FOLDER)_anbernic/$(TARGET_NAME)
|
||||
|
||||
@@ -9,14 +9,17 @@ DATA|${SYSTEM_FOLDER}/controllers.json|optional,absolute
|
||||
DATA|${SYSTEM_FOLDER}/score.bin|optional,absolute
|
||||
|
||||
# Archivos de configuración del juego
|
||||
DATA|${PREFIX}/data/config/formations.txt
|
||||
DATA|${PREFIX}/data/config/gamecontrollerdb.txt
|
||||
DATA|${PREFIX}/data/config/param_320x240.txt
|
||||
DATA|${PREFIX}/data/config/param_320x256.txt
|
||||
DATA|${PREFIX}/data/config/pools.txt
|
||||
DATA|${PREFIX}/data/config/stages.txt
|
||||
DEMODATA|${PREFIX}/data/config/demo1.bin
|
||||
DEMODATA|${PREFIX}/data/config/demo2.bin
|
||||
DATA|${PREFIX}/config/formations.txt
|
||||
DATA|${PREFIX}/config/gamecontrollerdb.txt
|
||||
DATA|${PREFIX}/config/param_320x240.txt
|
||||
DATA|${PREFIX}/config/param_320x256.txt
|
||||
DATA|${PREFIX}/config/param_red.txt
|
||||
DATA|${PREFIX}/config/pools.txt
|
||||
DATA|${PREFIX}/config/stages.txt
|
||||
|
||||
# Archivos con los datos de la demo
|
||||
DEMODATA|${PREFIX}/data/demo/demo1.bin
|
||||
DEMODATA|${PREFIX}/data/demo/demo2.bin
|
||||
|
||||
# Música
|
||||
MUSIC|${PREFIX}/data/music/credits.ogg
|
||||
@@ -56,12 +59,12 @@ SOUND|${PREFIX}/data/sound/tabe_hit.wav
|
||||
SOUND|${PREFIX}/data/sound/tabe.wav
|
||||
SOUND|${PREFIX}/data/sound/title.wav
|
||||
SOUND|${PREFIX}/data/sound/voice_aw_aw_aw.wav
|
||||
SOUND|${PREFIX}/data/sound/voice_brbrbr.wav
|
||||
SOUND|${PREFIX}/data/sound/voice_coffee.wav
|
||||
SOUND|${PREFIX}/data/sound/voice_credit_thankyou.wav
|
||||
SOUND|${PREFIX}/data/sound/voice_get_ready.wav
|
||||
SOUND|${PREFIX}/data/sound/voice_no.wav
|
||||
SOUND|${PREFIX}/data/sound/voice_power_up.wav
|
||||
SOUND|${PREFIX}/data/sound/voice_recover.wav
|
||||
SOUND|${PREFIX}/data/sound/voice_thankyou.wav
|
||||
SOUND|${PREFIX}/data/sound/walk.wav
|
||||
|
||||
@@ -177,6 +180,7 @@ BITMAP|${PREFIX}/data/font/04b_25_grey.png
|
||||
BITMAP|${PREFIX}/data/font/04b_25_metal.png
|
||||
BITMAP|${PREFIX}/data/font/04b_25_reversed_2x.png
|
||||
BITMAP|${PREFIX}/data/font/04b_25_reversed.png
|
||||
BITMAP|${PREFIX}/data/font/04b_25_white.png
|
||||
BITMAP|${PREFIX}/data/font/04b_25.png
|
||||
BITMAP|${PREFIX}/data/font/8bithud.png
|
||||
BITMAP|${PREFIX}/data/font/aseprite.png
|
||||
@@ -2,26 +2,26 @@
|
||||
# Formato: PARAMETRO VALOR
|
||||
|
||||
# --- GAME ---
|
||||
game.item_size 20 # Tamaño de los items del juego (en píxeles)
|
||||
game.width 320 # Ancho de la resolución nativa del juego (en píxeles)
|
||||
game.height 240 # Alto de la resolución nativa del juego (en píxeles)
|
||||
game.play_area.rect.x 0 # Posición X de la zona jugable
|
||||
game.play_area.rect.y 0 # Posición Y de la zona jugable
|
||||
game.play_area.rect.w 320 # Ancho de la zona jugable
|
||||
game.play_area.rect.h 200 # Alto de la zona jugable
|
||||
game.name_entry_idle_time 10 # Segundos para introducir el nombre al finalizar la partida si no se pulsa nada
|
||||
game.name_entry_total_time 60 # Segundos totales para introducir el nombre al finalizar la partida
|
||||
game.hit_stop false # Indica si debe haber un paro cuando el jugador es golpeado por un globo
|
||||
game.hit_stop_ms 500 # Cantidad de milisegundos que dura el hit_stop
|
||||
game.item_size 20 # Tamaño de los items del juego (en píxeles)
|
||||
game.item_text_outline_color E0E0E0F0 # Color del outline del texto de los items (RGBA hex)
|
||||
game.width 320 # Ancho de la resolución nativa del juego (en píxeles)
|
||||
game.height 240 # Alto de la resolución nativa del juego (en píxeles)
|
||||
game.play_area.rect.x 0 # Posición X de la zona jugable
|
||||
game.play_area.rect.y 0 # Posición Y de la zona jugable
|
||||
game.play_area.rect.w 320 # Ancho de la zona jugable
|
||||
game.play_area.rect.h 200 # Alto de la zona jugable
|
||||
game.name_entry_idle_time 10 # Segundos para introducir el nombre al finalizar la partida si no se pulsa nada
|
||||
game.name_entry_total_time 60 # Segundos totales para introducir el nombre al finalizar la partida
|
||||
game.hit_stop false # Indica si debe haber un paro cuando el jugador es golpeado por un globo
|
||||
game.hit_stop_ms 500 # Cantidad de milisegundos que dura el hit_stop
|
||||
|
||||
# --- FADE ---
|
||||
fade.color 1F2B30 # Color hexadecimal para el efecto de fundido
|
||||
fade.num_squares_width 160 # Número de cuadrados en el eje X para el fundido
|
||||
fade.num_squares_height 120 # Número de cuadrados en el eje Y para el fundido
|
||||
fade.random_squares_delay 1 # Delay entre aparición de cuadrados aleatorios (frames)
|
||||
fade.random_squares_mult 500 # Multiplicador para la velocidad de aparición aleatoria
|
||||
fade.post_duration 80 # Duración tras el fundido (frames)
|
||||
fade.venetian_size 12 # Tamaño de las bandas para el efecto veneciano (en píxeles)
|
||||
fade.color 1F2B30 # Color hexadecimal para el efecto de fundido
|
||||
fade.num_squares_width 64 # Número de cuadrados en el eje X para el fundido
|
||||
fade.num_squares_height 48 # Número de cuadrados en el eje Y para el fundido
|
||||
fade.random_squares_duration_ms 1200 # Duración del fade en milisegundos
|
||||
fade.post_duration_ms 500 # Duración tras el fundido en milisegundos
|
||||
fade.venetian_size 12 # Tamaño de las bandas para el efecto veneciano (en píxeles)
|
||||
|
||||
# --- SCOREBOARD ---
|
||||
scoreboard.rect.x 0 # Posición X del marcador
|
||||
@@ -84,8 +84,8 @@ service_menu.window_message.title_color 6496C8FF # Color del tít
|
||||
service_menu.window_message.text_color DCDCDCFF # Color del texto en ventanas de mensaje (RGBA hexadecimal)
|
||||
service_menu.window_message.padding 15.0f # Espaciado interno de ventanas de mensaje (píxeles)
|
||||
service_menu.window_message.line_spacing 5.0f # Espaciado entre líneas de texto (píxeles)
|
||||
service_menu.window_message.title_separator_spacing 10.0f # Espaciado entre título y contenido (píxeles)
|
||||
service_menu.window_message.min_width 250.0f # Ancho mínimo de ventanas de mensaje (píxeles)
|
||||
service_menu.window_message.title_separator_spacing 20.0f # Espaciado entre título y contenido (píxeles)
|
||||
service_menu.window_message.min_width 200.0f # Ancho mínimo de ventanas de mensaje (píxeles)
|
||||
service_menu.window_message.min_height 32.0f # Alto mínimo de ventanas de mensaje (píxeles)
|
||||
service_menu.window_message.max_width_ratio 0.8f # Ratio máximo de ancho respecto a pantalla (0.0-1.0)
|
||||
service_menu.window_message.max_height_ratio 0.8f # Ratio máximo de alto respecto a pantalla (0.0-1.0)
|
||||
@@ -110,6 +110,18 @@ tabe.min_spawn_time 2.0f # Tiempo mínimo en minutos para que aparezca el Tabe
|
||||
tabe.max_spawn_time 3.0f # Tiempo máximo en minutos para que aparezca el Tabe
|
||||
|
||||
# --- PLAYER ---
|
||||
# Jugador 1 - Camiseta por defecto
|
||||
player.default_shirt[0].darkest 028ECFFF # Tono más oscuro - bordes y contornos (Jugador 1, por defecto)
|
||||
player.default_shirt[0].dark 0297DBFF # Tono oscuro - sombras (Jugador 1, por defecto)
|
||||
player.default_shirt[0].base 029FE8FF # Tono principal - color base (Jugador 1, por defecto)
|
||||
player.default_shirt[0].light 03A9F4FF # Tono claro - zonas iluminadas (Jugador 1, por defecto)
|
||||
|
||||
# Jugador 2 - Camiseta por defecto
|
||||
player.default_shirt[1].darkest 8E8E8EFF # Tono más oscuro - bordes y contornos (Jugador 2, por defecto)
|
||||
player.default_shirt[1].dark AEADADFF # Tono oscuro - sombras (Jugador 2, por defecto)
|
||||
player.default_shirt[1].base E4E4E4FF # Tono principal - color base (Jugador 2, por defecto)
|
||||
player.default_shirt[1].light F7F1F1FF # Tono claro - zonas iluminadas (Jugador 2, por defecto)
|
||||
|
||||
# Jugador 1 - Camiseta con 1 café
|
||||
player.one_coffee_shirt[0].darkest 3D9C70FF # Tono más oscuro - bordes y contornos (Jugador 1, 1 café)
|
||||
player.one_coffee_shirt[0].dark 4FA370FF # Tono oscuro - sombras (Jugador 1, 1 café)
|
||||
@@ -132,4 +144,8 @@ player.one_coffee_shirt[1].light 55EF8DFF # Tono claro - zonas iluminadas
|
||||
player.two_coffee_shirt[1].darkest E08500FF # Tono más oscuro - bordes y contornos (Jugador 2, 2 cafés)
|
||||
player.two_coffee_shirt[1].dark FA7D00FF # Tono oscuro - sombras (Jugador 2, 2 cafés)
|
||||
player.two_coffee_shirt[1].base FAA200FF # Tono principal - color base (Jugador 2, 2 cafés)
|
||||
player.two_coffee_shirt[1].light FA8500FF # Tono claro - zonas iluminadas (Jugador 2, 2 cafés)
|
||||
player.two_coffee_shirt[1].light FA8500FF # Tono claro - zonas iluminadas (Jugador 2, 2 cafés)
|
||||
|
||||
# Colores de contorno de los jugadores
|
||||
player.outline_color[0] 66323FFF # Color del contorno del sprite del Jugador 1
|
||||
player.outline_color[1] 422028FF # Color del contorno del sprite del Jugador 2
|
||||
@@ -2,26 +2,26 @@
|
||||
# Formato: PARAMETRO VALOR
|
||||
|
||||
# --- GAME ---
|
||||
game.item_size 20 # Tamaño de los items del juego (en píxeles)
|
||||
game.width 320 # Ancho de la resolución nativa del juego (en píxeles)
|
||||
game.height 256 # Alto de la resolución nativa del juego (en píxeles)
|
||||
game.play_area.rect.x 0 # Posición X de la zona jugable
|
||||
game.play_area.rect.y 0 # Posición Y de la zona jugable
|
||||
game.play_area.rect.w 320 # Ancho de la zona jugable
|
||||
game.play_area.rect.h 216 # Alto de la zona jugable
|
||||
game.name_entry_idle_time 10 # Segundos para introducir el nombre al finalizar la partida si no se pulsa nada
|
||||
game.name_entry_total_time 60 # Segundos totales para introducir el nombre al finalizar la partida
|
||||
game.hit_stop false # Indica si debe haber un paro cuando el jugador es golpeado por un globo
|
||||
game.hit_stop_ms 500 # Cantidad de milisegundos que dura el hit_stop
|
||||
game.item_size 20 # Tamaño de los items del juego (en píxeles)
|
||||
game.item_text_outline_color E0E0E0F0 # Color del outline del texto de los items (RGBA hex)
|
||||
game.width 320 # Ancho de la resolución nativa del juego (en píxeles)
|
||||
game.height 256 # Alto de la resolución nativa del juego (en píxeles)
|
||||
game.play_area.rect.x 0 # Posición X de la zona jugable
|
||||
game.play_area.rect.y 0 # Posición Y de la zona jugable
|
||||
game.play_area.rect.w 320 # Ancho de la zona jugable
|
||||
game.play_area.rect.h 216 # Alto de la zona jugable
|
||||
game.name_entry_idle_time 10 # Segundos para introducir el nombre al finalizar la partida si no se pulsa nada
|
||||
game.name_entry_total_time 60 # Segundos totales para introducir el nombre al finalizar la partida
|
||||
game.hit_stop false # Indica si debe haber un paro cuando el jugador es golpeado por un globo
|
||||
game.hit_stop_ms 500 # Cantidad de milisegundos que dura el hit_stop
|
||||
|
||||
# --- FADE ---
|
||||
fade.color 1F2B30 # Color hexadecimal para el efecto de fundido
|
||||
fade.num_squares_width 160 # Número de cuadrados en el eje X para el fundido
|
||||
fade.num_squares_height 128 # Número de cuadrados en el eje Y para el fundido
|
||||
fade.random_squares_delay 1 # Delay entre aparición de cuadrados aleatorios (frames)
|
||||
fade.random_squares_mult 500 # Multiplicador para la velocidad de aparición aleatoria
|
||||
fade.post_duration 80 # Duración tras el fundido (frames)
|
||||
fade.venetian_size 12 # Tamaño de las bandas para el efecto veneciano (en píxeles)
|
||||
fade.color 1F2B30 # Color hexadecimal para el efecto de fundido
|
||||
fade.num_squares_width 64 # Número de cuadrados en el eje X para el fundido
|
||||
fade.num_squares_height 48 # Número de cuadrados en el eje Y para el fundido
|
||||
fade.random_squares_duration_ms 1200 # Duración del fade en milisegundos
|
||||
fade.post_duration_ms 500 # Duración tras el fundido en milisegundos
|
||||
fade.venetian_size 12 # Tamaño de las bandas para el efecto veneciano (en píxeles)
|
||||
|
||||
# --- SCOREBOARD ---
|
||||
scoreboard.rect.x 0 # Posición X del marcador
|
||||
@@ -84,8 +84,8 @@ service_menu.window_message.title_color 6496C8FF # Color del tít
|
||||
service_menu.window_message.text_color DCDCDCFF # Color del texto en ventanas de mensaje (RGBA hexadecimal)
|
||||
service_menu.window_message.padding 15.0f # Espaciado interno de ventanas de mensaje (píxeles)
|
||||
service_menu.window_message.line_spacing 5.0f # Espaciado entre líneas de texto (píxeles)
|
||||
service_menu.window_message.title_separator_spacing 10.0f # Espaciado entre título y contenido (píxeles)
|
||||
service_menu.window_message.min_width 250.0f # Ancho mínimo de ventanas de mensaje (píxeles)
|
||||
service_menu.window_message.title_separator_spacing 20.0f # Espaciado entre título y contenido (píxeles)
|
||||
service_menu.window_message.min_width 200.0f # Ancho mínimo de ventanas de mensaje (píxeles)
|
||||
service_menu.window_message.min_height 32.0f # Alto mínimo de ventanas de mensaje (píxeles)
|
||||
service_menu.window_message.max_width_ratio 0.8f # Ratio máximo de ancho respecto a pantalla (0.0-1.0)
|
||||
service_menu.window_message.max_height_ratio 0.8f # Ratio máximo de alto respecto a pantalla (0.0-1.0)
|
||||
@@ -109,6 +109,18 @@ tabe.min_spawn_time 2.0f # Tiempo mínimo en segundos para que aparezca el Ta
|
||||
tabe.max_spawn_time 3.0f # Tiempo máximo en segundos para que aparezca el Tabe
|
||||
|
||||
# --- PLAYER ---
|
||||
# Jugador 1 - Camiseta por defecto
|
||||
player.default_shirt[0].darkest 028ECFFF # Tono más oscuro - bordes y contornos (Jugador 1, por defecto)
|
||||
player.default_shirt[0].dark 0297DBFF # Tono oscuro - sombras (Jugador 1, por defecto)
|
||||
player.default_shirt[0].base 029FE8FF # Tono principal - color base (Jugador 1, por defecto)
|
||||
player.default_shirt[0].light 03A9F4FF # Tono claro - zonas iluminadas (Jugador 1, por defecto)
|
||||
|
||||
# Jugador 2 - Camiseta por defecto
|
||||
player.default_shirt[1].darkest 8E8E8EFF # Tono más oscuro - bordes y contornos (Jugador 2, por defecto)
|
||||
player.default_shirt[1].dark AEADADFF # Tono oscuro - sombras (Jugador 2, por defecto)
|
||||
player.default_shirt[1].base E4E4E4FF # Tono principal - color base (Jugador 2, por defecto)
|
||||
player.default_shirt[1].light F7F1F1FF # Tono claro - zonas iluminadas (Jugador 2, por defecto)
|
||||
|
||||
# Jugador 1 - Camiseta con 1 café
|
||||
player.one_coffee_shirt[0].darkest 3D9C70FF # Tono más oscuro - bordes y contornos (Jugador 1, 1 café)
|
||||
player.one_coffee_shirt[0].dark 4FA370FF # Tono oscuro - sombras (Jugador 1, 1 café)
|
||||
@@ -131,4 +143,8 @@ player.one_coffee_shirt[1].light 55EF8DFF # Tono claro - zonas iluminadas
|
||||
player.two_coffee_shirt[1].darkest E08500FF # Tono más oscuro - bordes y contornos (Jugador 2, 2 cafés)
|
||||
player.two_coffee_shirt[1].dark FA7D00FF # Tono oscuro - sombras (Jugador 2, 2 cafés)
|
||||
player.two_coffee_shirt[1].base FAA200FF # Tono principal - color base (Jugador 2, 2 cafés)
|
||||
player.two_coffee_shirt[1].light FA8500FF # Tono claro - zonas iluminadas (Jugador 2, 2 cafés)
|
||||
player.two_coffee_shirt[1].light FA8500FF # Tono claro - zonas iluminadas (Jugador 2, 2 cafés)
|
||||
|
||||
# Colores de contorno de los jugadores
|
||||
player.outline_color[0] 66323FFF # Color del contorno del sprite del Jugador 1
|
||||
player.outline_color[1] 422028FF # Color del contorno del sprite del Jugador 2
|
||||
150
config/param_red.txt
Normal file
150
config/param_red.txt
Normal file
@@ -0,0 +1,150 @@
|
||||
# Coffee Crisis Arcade Edition - Fichero de parametros - RED THEME
|
||||
# Formato: PARAMETRO VALOR
|
||||
|
||||
# --- GAME ---
|
||||
game.item_size 20 # Tamaño de los items del juego (en píxeles)
|
||||
game.item_text_outline_color FFB8B8F0 # Color del outline del texto de los items (RGBA hex) - Rojo claro
|
||||
game.width 320 # Ancho de la resolución nativa del juego (en píxeles)
|
||||
game.height 256 # Alto de la resolución nativa del juego (en píxeles)
|
||||
game.play_area.rect.x 0 # Posición X de la zona jugable
|
||||
game.play_area.rect.y 0 # Posición Y de la zona jugable
|
||||
game.play_area.rect.w 320 # Ancho de la zona jugable
|
||||
game.play_area.rect.h 216 # Alto de la zona jugable
|
||||
game.name_entry_idle_time 10 # Segundos para introducir el nombre al finalizar la partida si no se pulsa nada
|
||||
game.name_entry_total_time 60 # Segundos totales para introducir el nombre al finalizar la partida
|
||||
game.hit_stop false # Indica si debe haber un paro cuando el jugador es golpeado por un globo
|
||||
game.hit_stop_ms 500 # Cantidad de milisegundos que dura el hit_stop
|
||||
|
||||
# --- FADE ---
|
||||
fade.color 5C1F1F # Color hexadecimal para el efecto de fundido - Rojo oscuro
|
||||
fade.num_squares_width 64 # Número de cuadrados en el eje X para el fundido
|
||||
fade.num_squares_height 48 # Número de cuadrados en el eje Y para el fundido
|
||||
fade.random_squares_duration_ms 1200 # Duración del fade en milisegundos
|
||||
fade.post_duration_ms 500 # Duración tras el fundido en milisegundos
|
||||
fade.venetian_size 12 # Tamaño de las bandas para el efecto veneciano (en píxeles)
|
||||
|
||||
# --- SCOREBOARD ---
|
||||
scoreboard.rect.x 0 # Posición X del marcador
|
||||
scoreboard.rect.y 216 # Posición Y del marcador
|
||||
scoreboard.rect.w 320 # Ancho del marcador
|
||||
scoreboard.rect.h 40 # Alto del marcador
|
||||
scoreboard.separator_autocolor true # ¿El separador usa color automático?
|
||||
scoreboard.separator_color 2B0D0D # Color del separador - Rojo muy oscuro
|
||||
scoreboard.easy_color 8B4A2F # Color para la dificultad fácil - Marrón rojizo
|
||||
scoreboard.normal_color 6B2F2F # Color para la dificultad normal - Rojo medio
|
||||
scoreboard.hard_color A73030 # Color para la dificultad difícil - Rojo fuerte
|
||||
scoreboard.text_autocolor true # ¿El texto usa color automático?
|
||||
scoreboard.text_color1 FFE6E6 # Color principal del texto del marcador - Blanco rosado
|
||||
scoreboard.text_color2 FFE6E6 # Color secundario del texto del marcador - Blanco rosado
|
||||
scoreboard.skip_countdown_value 8 # Valor para saltar la cuenta atrás (segundos)
|
||||
|
||||
# --- TITLE ---
|
||||
title.press_start_position 180 # Posición Y del texto "Press Start"
|
||||
title.title_duration 800 # Duración de la pantalla de título (frames)
|
||||
title.arcade_edition_position 123 # Posición Y del subtítulo "Arcade Edition"
|
||||
title.title_c_c_position 80 # Posición Y del título principal
|
||||
title.bg_color 8B4A3A # Color de fondo en la sección titulo - Marrón rojizo
|
||||
|
||||
# --- BACKGROUND ---
|
||||
background.attenuate_color FF4A3A40 # Color de atenuación del fondo (RGBA hexadecimal) - Blanco rosado
|
||||
|
||||
# --- BALLOONS ---
|
||||
balloon.settings[0].vel 2.75f # Velocidad inicial del globo 1
|
||||
balloon.settings[0].grav 0.09f # Gravedad aplicada al globo 1
|
||||
balloon.settings[1].vel 3.70f # Velocidad inicial del globo 2
|
||||
balloon.settings[1].grav 0.10f # Gravedad aplicada al globo 2
|
||||
balloon.settings[2].vel 4.70f # Velocidad inicial del globo 3
|
||||
balloon.settings[2].grav 0.10f # Gravedad aplicada al globo 3
|
||||
balloon.settings[3].vel 5.45f # Velocidad inicial del globo 4
|
||||
balloon.settings[3].grav 0.10f # Gravedad aplicada al globo 4
|
||||
|
||||
balloon.color[0] orange # Color de creación del globo normal
|
||||
balloon.color[1] red # Color del globo normal
|
||||
balloon.color[2] blue # Color de creación del globo que rebota
|
||||
balloon.color[3] green # Color del globo que rebota
|
||||
|
||||
balloon.bouncing_sound false # Indica si los globos hacer sonido al rebotar
|
||||
|
||||
# --- NOTIFICATION ---
|
||||
notification.pos_v TOP # Posición vertical de la notificación (TOP/BOTTOM)
|
||||
notification.pos_h LEFT # Posición horizontal de la notificación (LEFT/RIGHT)
|
||||
notification.sound false # ¿La notificación reproduce sonido?
|
||||
notification.color 4D1A1A # Color de fondo de la notificación - Rojo oscuro
|
||||
|
||||
# --- SERVICE MENU ---
|
||||
service_menu.title_color FF9966 # Color del título del menú de servicio - Naranja claro
|
||||
service_menu.text_color FFE6E6 # Color del texto del menú de servicio - Blanco rosado
|
||||
service_menu.selected_color FFB366 # Color de la opción seleccionada - Naranja dorado
|
||||
service_menu.bg_color 331A0AF5 # Color de fondo del menú de servicio - Marrón rojizo oscuro con alpha
|
||||
service_menu.drop_shadow false # ¿El menú de servicio tiene sombra?
|
||||
|
||||
service_menu.window_message.bg_color 4D1A1AF0 # Color de fondo de ventanas - Rojo oscuro con alpha
|
||||
service_menu.window_message.border_color CC6633FF # Color del borde de ventanas - Naranja rojizo
|
||||
service_menu.window_message.title_color CC6633FF # Color del título en ventanas - Naranja rojizo
|
||||
service_menu.window_message.text_color FFE6E6FF # Color del texto en ventanas - Blanco rosado
|
||||
service_menu.window_message.padding 15.0f # Espaciado interno de ventanas de mensaje (píxeles)
|
||||
service_menu.window_message.line_spacing 5.0f # Espaciado entre líneas de texto (píxeles)
|
||||
service_menu.window_message.title_separator_spacing 20.0f # Espaciado entre título y contenido (píxeles)
|
||||
service_menu.window_message.min_width 200.0f # Ancho mínimo de ventanas de mensaje (píxeles)
|
||||
service_menu.window_message.min_height 32.0f # Alto mínimo de ventanas de mensaje (píxeles)
|
||||
service_menu.window_message.max_width_ratio 0.8f # Ratio máximo de ancho respecto a pantalla (0.0-1.0)
|
||||
service_menu.window_message.max_height_ratio 0.8f # Ratio máximo de alto respecto a pantalla (0.0-1.0)
|
||||
service_menu.window_message.text_safety_margin 15.0f # Margen de seguridad para el texto (píxeles)
|
||||
service_menu.window_message.animation_duration 0.3f # Duración de animaciones de ventanas (segundos)
|
||||
|
||||
# --- INTRO ---
|
||||
intro.bg_color B8664D # Color de fondo de la intro - Naranja tierra
|
||||
intro.card_color FFE6CC # Color de las tarjetas en la intro - Crema rojizo
|
||||
intro.shadow_color 66000080 # Color de la sombra de las tarjetas - Rojo muy oscuro con alpha
|
||||
intro.text_distance_from_bottom 48 # Posición del texto desde la parte inferior
|
||||
|
||||
# --- DEBUG ---
|
||||
debug.color FF6666 # Color para elementos de depuración - Rojo claro
|
||||
|
||||
# --- RESOURCE ---
|
||||
resource.color FFE6E6 # Color de recursos - Blanco rosado
|
||||
|
||||
# --- TABE ---
|
||||
tabe.min_spawn_time 2.0f # Tiempo mínimo en segundos para que aparezca el Tabe
|
||||
tabe.max_spawn_time 3.0f # Tiempo máximo en segundos para que aparezca el Tabe
|
||||
|
||||
# --- PLAYER ---
|
||||
# Jugador 1 - Camiseta por defecto (tonos rojos)
|
||||
player.default_shirt[0].darkest B33030FF # Tono más oscuro - Rojo fuerte
|
||||
player.default_shirt[0].dark CC4040FF # Tono oscuro - Rojo medio
|
||||
player.default_shirt[0].base E65050FF # Tono principal - Rojo claro
|
||||
player.default_shirt[0].light FF6666FF # Tono claro - Rojo muy claro
|
||||
|
||||
# Jugador 2 - Camiseta por defecto (tonos naranjas)
|
||||
player.default_shirt[1].darkest B36030FF # Tono más oscuro - Naranja oscuro
|
||||
player.default_shirt[1].dark CC7540FF # Tono oscuro - Naranja medio
|
||||
player.default_shirt[1].base E68A50FF # Tono principal - Naranja claro
|
||||
player.default_shirt[1].light FF9966FF # Tono claro - Naranja muy claro
|
||||
|
||||
# Jugador 1 - Camiseta con 1 café (tonos rojizos más intensos)
|
||||
player.one_coffee_shirt[0].darkest 8B2635FF # Tono más oscuro - Rojo granate
|
||||
player.one_coffee_shirt[0].dark A53040FF # Tono oscuro - Rojo granate claro
|
||||
player.one_coffee_shirt[0].base BF3A50FF # Tono principal - Rojo vibrante
|
||||
player.one_coffee_shirt[0].light D94460FF # Tono claro - Rojo vibrante claro
|
||||
|
||||
# Jugador 1 - Camiseta con 2 cafés (tonos naranja dorado)
|
||||
player.two_coffee_shirt[0].darkest CC6600FF # Tono más oscuro - Naranja dorado oscuro
|
||||
player.two_coffee_shirt[0].dark E6750AFF # Tono oscuro - Naranja dorado
|
||||
player.two_coffee_shirt[0].base FF8514FF # Tono principal - Naranja dorado claro
|
||||
player.two_coffee_shirt[0].light FF991EFF # Tono claro - Naranja dorado muy claro
|
||||
|
||||
# Jugador 2 - Camiseta con 1 café (tonos terracotas)
|
||||
player.one_coffee_shirt[1].darkest A0472DFF # Tono más oscuro - Terracota oscuro
|
||||
player.one_coffee_shirt[1].dark B8553AFF # Tono oscuro - Terracota medio
|
||||
player.one_coffee_shirt[1].base D06347FF # Tono principal - Terracota claro
|
||||
player.one_coffee_shirt[1].light E87154FF # Tono claro - Terracota muy claro
|
||||
|
||||
# Jugador 2 - Camiseta con 2 cafés (tonos naranjas cálidos)
|
||||
player.two_coffee_shirt[1].darkest CC5500FF # Tono más oscuro - Naranja intenso
|
||||
player.two_coffee_shirt[1].dark E66600FF # Tono oscuro - Naranja fuerte
|
||||
player.two_coffee_shirt[1].base FF7700FF # Tono principal - Naranja brillante
|
||||
player.two_coffee_shirt[1].light FF8800FF # Tono claro - Naranja muy brillante
|
||||
|
||||
# Colores de contorno de los jugadores
|
||||
player.outline_color[0] 994D33FF # Color del contorno del Jugador 1 - Marrón rojizo
|
||||
player.outline_color[1] 664433FF # Color del contorno del Jugador 2 - Marrón tierra
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
BIN
data/font/04b_25_white.png
Normal file
BIN
data/font/04b_25_white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
BIN
data/sound/voice_recover.wav
Normal file
BIN
data/sound/voice_recover.wav
Normal file
Binary file not shown.
15
linux_utils/generate_compile_commands_json.sh
Executable file
15
linux_utils/generate_compile_commands_json.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 🏁 Ruta base del proyecto
|
||||
BASE_DIR="/home/sergio/gitea/coffee_crisis_arcade_edition"
|
||||
|
||||
# 📁 Ruta al build
|
||||
BUILD_DIR="$BASE_DIR/build"
|
||||
|
||||
# 📄 Archivo de mapping personalizado
|
||||
MAPPING_FILE="$BASE_DIR/linux_utils/sdl3_mapping.imp"
|
||||
|
||||
# 📦 Generar compile_commands.json
|
||||
echo "🔧 Generando compile_commands.json..."
|
||||
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -S "$BASE_DIR" -B "$BUILD_DIR"
|
||||
|
||||
44
linux_utils/run_clang-tidy.sh
Executable file
44
linux_utils/run_clang-tidy.sh
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script para ejecutar clang-tidy en múltiples directorios
|
||||
# Uso: ./run_clang-tidy.sh
|
||||
|
||||
# Lista de rutas donde ejecutar clang-tidy
|
||||
PATHS=(
|
||||
"/home/sergio/gitea/coffee_crisis_arcade_edition/source"
|
||||
"/home/sergio/gitea/coffee_crisis_arcade_edition/source/sections"
|
||||
"/home/sergio/gitea/coffee_crisis_arcade_edition/source/ui"
|
||||
)
|
||||
|
||||
# Ruta del directorio build (relativa desde donde se ejecuta el script)
|
||||
BUILD_DIR="/home/sergio/gitea/coffee_crisis_arcade_edition/build/"
|
||||
|
||||
# Función para procesar un directorio
|
||||
process_directory() {
|
||||
local dir="$1"
|
||||
|
||||
echo "=== Procesando directorio: $dir ==="
|
||||
|
||||
# Verificar que el directorio existe
|
||||
if [[ ! -d "$dir" ]]; then
|
||||
echo "Error: El directorio $dir no existe"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Cambiar al directorio y ejecutar find con -maxdepth 1 para un solo nivel
|
||||
cd "$dir" || return 1
|
||||
|
||||
# Buscar archivos .cpp, .h, .hpp solo en el nivel actual (no subdirectorios)
|
||||
find . -maxdepth 1 \( -name '*.cpp' -o -name '*.h' -o -name '*.hpp' \) | \
|
||||
xargs -P4 -I{} bash -c 'echo "Procesando: {}"; clang-tidy {} -p '"$BUILD_DIR"' --fix'
|
||||
|
||||
echo "=== Completado: $dir ==="
|
||||
echo
|
||||
}
|
||||
|
||||
# Procesar cada directorio en la lista
|
||||
for path in "${PATHS[@]}"; do
|
||||
process_directory "$path"
|
||||
done
|
||||
|
||||
echo "¡Proceso completado para todos los directorios!"
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
resources.pack
Normal file
BIN
resources.pack
Normal file
Binary file not shown.
@@ -10,21 +10,39 @@
|
||||
#include <utility> // Para pair
|
||||
|
||||
#include "texture.h" // Para Texture
|
||||
#include "resource_helper.h" // Para ResourceHelper
|
||||
#include "utils.h" // Para printWithDots
|
||||
|
||||
// Carga las animaciones en un vector(Animations) desde un fichero
|
||||
auto loadAnimationsFromFile(const std::string& file_path) -> AnimationsFileBuffer {
|
||||
std::ifstream file(file_path);
|
||||
if (!file) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", file_path.c_str());
|
||||
throw std::runtime_error("Fichero no encontrado: " + file_path);
|
||||
// Intentar cargar desde ResourceHelper primero
|
||||
auto resource_data = ResourceHelper::loadFile(file_path);
|
||||
std::istringstream stream;
|
||||
bool using_resource_data = false;
|
||||
|
||||
if (!resource_data.empty()) {
|
||||
std::string content(resource_data.begin(), resource_data.end());
|
||||
stream.str(content);
|
||||
using_resource_data = true;
|
||||
}
|
||||
|
||||
// Fallback a archivo directo
|
||||
std::ifstream file;
|
||||
if (!using_resource_data) {
|
||||
file.open(file_path);
|
||||
if (!file) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", file_path.c_str());
|
||||
throw std::runtime_error("Fichero no encontrado: " + file_path);
|
||||
}
|
||||
}
|
||||
|
||||
std::istream& input_stream = using_resource_data ? stream : static_cast<std::istream&>(file);
|
||||
|
||||
printWithDots("Animation : ", file_path.substr(file_path.find_last_of("\\/") + 1), "[ LOADED ]");
|
||||
|
||||
std::vector<std::string> buffer;
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
while (std::getline(input_stream, line)) {
|
||||
if (!line.empty()) {
|
||||
buffer.push_back(line);
|
||||
}
|
||||
@@ -35,7 +53,7 @@ auto loadAnimationsFromFile(const std::string& file_path) -> AnimationsFileBuffe
|
||||
|
||||
// Constructor
|
||||
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const std::string& file_path)
|
||||
: MovingSprite(texture) {
|
||||
: MovingSprite(std::move(texture)) {
|
||||
// Carga las animaciones
|
||||
if (!file_path.empty()) {
|
||||
auto buffer = loadAnimationsFromFile(file_path);
|
||||
@@ -45,7 +63,7 @@ AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const std::stri
|
||||
|
||||
// Constructor
|
||||
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const AnimationsFileBuffer& animations)
|
||||
: MovingSprite(texture) {
|
||||
: MovingSprite(std::move(texture)) {
|
||||
if (!animations.empty()) {
|
||||
loadFromAnimationsFileBuffer(animations);
|
||||
}
|
||||
@@ -176,7 +194,7 @@ void AnimatedSprite::loadFromAnimationsFileBuffer(const AnimationsFileBuffer& so
|
||||
|
||||
// Procesa una línea de configuración
|
||||
void AnimatedSprite::processConfigLine(const std::string& line, AnimationConfig& config) {
|
||||
size_t pos = line.find("=");
|
||||
size_t pos = line.find('=');
|
||||
if (pos == std::string::npos) {
|
||||
return;
|
||||
}
|
||||
@@ -230,7 +248,7 @@ auto AnimatedSprite::processAnimationBlock(const AnimationsFileBuffer& source, s
|
||||
|
||||
// Procesa un parámetro individual de animación
|
||||
void AnimatedSprite::processAnimationParameter(const std::string& line, Animation& animation, const AnimationConfig& config) {
|
||||
size_t pos = line.find("=");
|
||||
size_t pos = line.find('=');
|
||||
if (pos == std::string::npos) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
#include <memory> // Para allocator, shared_ptr
|
||||
#include <string> // Para string, hash
|
||||
#include <unordered_map> // Para unordered_map
|
||||
#include <vector> // Para vector
|
||||
#include <utility>
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "moving_sprite.h" // Para MovingSprite
|
||||
|
||||
@@ -49,7 +50,7 @@ class AnimatedSprite : public MovingSprite {
|
||||
// --- Constructores y destructor ---
|
||||
AnimatedSprite(std::shared_ptr<Texture> texture, const std::string& file_path);
|
||||
AnimatedSprite(std::shared_ptr<Texture> texture, const AnimationsFileBuffer& animations);
|
||||
explicit AnimatedSprite(std::shared_ptr<Texture> texture) : MovingSprite(texture) {}
|
||||
explicit AnimatedSprite(std::shared_ptr<Texture> texture) : MovingSprite(std::move(texture)) {}
|
||||
~AnimatedSprite() override = default;
|
||||
|
||||
// --- Métodos principales ---
|
||||
@@ -71,9 +72,9 @@ class AnimatedSprite : public MovingSprite {
|
||||
|
||||
protected:
|
||||
// --- Variables de estado ---
|
||||
std::vector<Animation> animations_; // Vector de animaciones disponibles
|
||||
std::vector<Animation> animations_; // Vector de animaciones disponibles
|
||||
std::unordered_map<std::string, int> animation_indices_; // Mapa para búsqueda rápida por nombre
|
||||
int current_animation_ = 0; // Índice de la animación activa
|
||||
int current_animation_ = 0; // Índice de la animación activa
|
||||
|
||||
// --- Métodos internos ---
|
||||
void animate(); // Calcula el frame correspondiente a la animación
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <stdexcept> // Para runtime_error
|
||||
|
||||
#include "utils.h" // Para getFileName
|
||||
#include "resource_helper.h" // Para ResourceHelper
|
||||
|
||||
// Singleton
|
||||
Asset *Asset::instance = nullptr;
|
||||
@@ -92,7 +93,7 @@ void Asset::loadFromFile(const std::string &config_file_path, const std::string
|
||||
}
|
||||
|
||||
try {
|
||||
std::string type_str = parts[0];
|
||||
const std::string &type_str = parts[0];
|
||||
std::string path = parts[1];
|
||||
|
||||
// Valores por defecto
|
||||
@@ -139,6 +140,17 @@ auto Asset::get(const std::string &filename) const -> std::string {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Carga datos del archivo usando ResourceHelper
|
||||
auto Asset::loadData(const std::string &filename) const -> std::vector<uint8_t> {
|
||||
auto it = file_list_.find(filename);
|
||||
if (it != file_list_.end()) {
|
||||
return ResourceHelper::loadFile(it->second.file);
|
||||
}
|
||||
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: file %s not found for data loading", filename.c_str());
|
||||
return {};
|
||||
}
|
||||
|
||||
// Verifica si un recurso existe
|
||||
auto Asset::exists(const std::string &filename) const -> bool {
|
||||
return file_list_.find(filename) != file_list_.end();
|
||||
@@ -194,9 +206,16 @@ auto Asset::check() const -> bool {
|
||||
|
||||
// Comprueba que existe un fichero
|
||||
auto Asset::checkFile(const std::string &path) -> bool {
|
||||
std::ifstream file(path);
|
||||
bool success = file.good();
|
||||
file.close();
|
||||
// Intentar primero con ResourceHelper
|
||||
auto data = ResourceHelper::loadFile(path);
|
||||
bool success = !data.empty();
|
||||
|
||||
// Si no se encuentra en el pack, intentar con filesystem directo
|
||||
if (!success) {
|
||||
std::ifstream file(path);
|
||||
success = file.good();
|
||||
file.close();
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <unordered_map> // Para unordered_map
|
||||
#include <utility> // Para move
|
||||
#include <vector> // Para vector
|
||||
#include <cstdint> // Para uint8_t
|
||||
|
||||
// --- Clase Asset: gestor optimizado de recursos (singleton) ---
|
||||
class Asset {
|
||||
@@ -33,6 +34,7 @@ class Asset {
|
||||
void add(const std::string &file_path, Type type, bool required = true, bool absolute = false);
|
||||
void loadFromFile(const std::string &config_file_path, const std::string &prefix = "", const std::string &system_folder = ""); // Con soporte para variables
|
||||
[[nodiscard]] auto get(const std::string &filename) const -> std::string; // Mantener nombre original
|
||||
[[nodiscard]] auto loadData(const std::string &filename) const -> std::vector<uint8_t>; // Carga datos del archivo
|
||||
[[nodiscard]] auto check() const -> bool;
|
||||
[[nodiscard]] auto getListByType(Type type) const -> std::vector<std::string>;
|
||||
[[nodiscard]] auto exists(const std::string &filename) const -> bool; // Nueva función para verificar existencia
|
||||
@@ -53,12 +55,12 @@ class Asset {
|
||||
std::string executable_path_; // Ruta del ejecutable
|
||||
|
||||
// --- Métodos internos ---
|
||||
[[nodiscard]] static auto checkFile(const std::string &path) -> bool; // Verifica si un archivo existe
|
||||
[[nodiscard]] static auto getTypeName(Type type) -> std::string; // Obtiene el nombre del tipo
|
||||
[[nodiscard]] static auto parseAssetType(const std::string &type_str) -> Type; // Convierte string a tipo
|
||||
void addToMap(const std::string &file_path, Type type, bool required, bool absolute); // Añade archivo al mapa
|
||||
[[nodiscard]] static auto replaceVariables(const std::string &path, const std::string &prefix, const std::string &system_folder) -> std::string; // Reemplaza variables en la ruta
|
||||
static auto parseOptions(const std::string &options, bool &required, bool &absolute) -> void; // Parsea opciones
|
||||
[[nodiscard]] static auto checkFile(const std::string &path) -> bool; // Verifica si un archivo existe
|
||||
[[nodiscard]] static auto getTypeName(Type type) -> std::string; // Obtiene el nombre del tipo
|
||||
[[nodiscard]] static auto parseAssetType(const std::string &type_str) -> Type; // Convierte string a tipo
|
||||
void addToMap(const std::string &file_path, Type type, bool required, bool absolute); // Añade archivo al mapa
|
||||
[[nodiscard]] static auto replaceVariables(const std::string &path, const std::string &prefix, const std::string &system_folder) -> std::string; // Reemplaza variables en la ruta
|
||||
static auto parseOptions(const std::string &options, bool &required, bool &absolute) -> void; // Parsea opciones
|
||||
|
||||
// --- Constructores y destructor privados (singleton) ---
|
||||
explicit Asset(std::string executable_path) // Constructor privado
|
||||
|
||||
105
source/asset_integrated.cpp
Normal file
105
source/asset_integrated.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
#include "asset_integrated.h"
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
bool AssetIntegrated::resource_pack_enabled_ = false;
|
||||
|
||||
void AssetIntegrated::initWithResourcePack(const std::string &executable_path,
|
||||
const std::string &resource_pack_path) {
|
||||
// Inicializar Asset normal
|
||||
Asset::init(executable_path);
|
||||
|
||||
// Inicializar ResourceLoader
|
||||
auto& loader = ResourceLoader::getInstance();
|
||||
if (loader.initialize(resource_pack_path, true)) {
|
||||
resource_pack_enabled_ = true;
|
||||
std::cout << "Asset system initialized with resource pack: " << resource_pack_path << std::endl;
|
||||
} else {
|
||||
resource_pack_enabled_ = false;
|
||||
std::cout << "Asset system initialized in fallback mode (filesystem)" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> AssetIntegrated::loadFile(const std::string &filename) {
|
||||
if (shouldUseResourcePack(filename) && resource_pack_enabled_) {
|
||||
// Intentar cargar del pack de recursos
|
||||
auto& loader = ResourceLoader::getInstance();
|
||||
|
||||
// Convertir ruta completa a ruta relativa para el pack
|
||||
std::string relativePath = filename;
|
||||
|
||||
// Si la ruta contiene "data/", extraer la parte relativa
|
||||
size_t dataPos = filename.find("data/");
|
||||
if (dataPos != std::string::npos) {
|
||||
relativePath = filename.substr(dataPos + 5); // +5 para saltar "data/"
|
||||
}
|
||||
|
||||
auto data = loader.loadResource(relativePath);
|
||||
if (!data.empty()) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: cargar del filesystem
|
||||
std::ifstream file(filename, std::ios::binary | std::ios::ate);
|
||||
if (!file) {
|
||||
std::cerr << "Error: Could not open file: " << filename << std::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::streamsize fileSize = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
std::vector<uint8_t> data(fileSize);
|
||||
if (!file.read(reinterpret_cast<char*>(data.data()), fileSize)) {
|
||||
std::cerr << "Error: Could not read file: " << filename << std::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
bool AssetIntegrated::fileExists(const std::string &filename) const {
|
||||
if (shouldUseResourcePack(filename) && resource_pack_enabled_) {
|
||||
auto& loader = ResourceLoader::getInstance();
|
||||
|
||||
// Convertir ruta completa a ruta relativa para el pack
|
||||
std::string relativePath = filename;
|
||||
size_t dataPos = filename.find("data/");
|
||||
if (dataPos != std::string::npos) {
|
||||
relativePath = filename.substr(dataPos + 5);
|
||||
}
|
||||
|
||||
if (loader.resourceExists(relativePath)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Verificar en filesystem
|
||||
return std::filesystem::exists(filename);
|
||||
}
|
||||
|
||||
std::string AssetIntegrated::getSystemPath(const std::string &filename) const {
|
||||
// Los archivos de sistema/config siempre van al filesystem
|
||||
return filename;
|
||||
}
|
||||
|
||||
bool AssetIntegrated::shouldUseResourcePack(const std::string &filepath) const {
|
||||
// Los archivos que NO van al pack:
|
||||
// - Archivos de config/ (ahora están fuera de data/)
|
||||
// - Archivos con absolute=true en assets.txt
|
||||
// - Archivos de sistema (${SYSTEM_FOLDER})
|
||||
|
||||
if (filepath.find("/config/") != std::string::npos ||
|
||||
filepath.find("config/") == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filepath.find("/data/") != std::string::npos ||
|
||||
filepath.find("data/") == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
28
source/asset_integrated.h
Normal file
28
source/asset_integrated.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "asset.h"
|
||||
#include "resource_loader.h"
|
||||
#include <memory>
|
||||
|
||||
// Extensión de Asset que integra ResourceLoader
|
||||
class AssetIntegrated : public Asset {
|
||||
public:
|
||||
// Inicializa Asset con ResourceLoader
|
||||
static void initWithResourcePack(const std::string &executable_path,
|
||||
const std::string &resource_pack_path = "resources.pack");
|
||||
|
||||
// Carga un archivo usando ResourceLoader como primera opción
|
||||
std::vector<uint8_t> loadFile(const std::string &filename);
|
||||
|
||||
// Verifica si un archivo existe (pack o filesystem)
|
||||
bool fileExists(const std::string &filename) const;
|
||||
|
||||
// Obtiene la ruta completa para archivos del sistema/config
|
||||
std::string getSystemPath(const std::string &filename) const;
|
||||
|
||||
private:
|
||||
static bool resource_pack_enabled_;
|
||||
|
||||
// Determina si un archivo debe cargarse del pack o del filesystem
|
||||
bool shouldUseResourcePack(const std::string &filepath) const;
|
||||
};
|
||||
@@ -8,15 +8,15 @@ class Audio {
|
||||
public:
|
||||
// --- Enums ---
|
||||
enum class Group : int {
|
||||
ALL = -1, // Todos los grupos
|
||||
GAME = 0, // Sonidos del juego
|
||||
INTERFACE = 1 // Sonidos de la interfaz
|
||||
ALL = -1, // Todos los grupos
|
||||
GAME = 0, // Sonidos del juego
|
||||
INTERFACE = 1 // Sonidos de la interfaz
|
||||
};
|
||||
|
||||
// --- Constantes ---
|
||||
static constexpr int MAX_VOLUME = 100; // Volumen máximo
|
||||
static constexpr int MIN_VOLUME = 0; // Volumen mínimo
|
||||
static constexpr int FREQUENCY = 48000; // Frecuencia de audio
|
||||
static constexpr int MAX_VOLUME = 100; // Volumen máximo
|
||||
static constexpr int MIN_VOLUME = 0; // Volumen mínimo
|
||||
static constexpr int FREQUENCY = 48000; // Frecuencia de audio
|
||||
|
||||
// --- Métodos de singleton ---
|
||||
static void init(); // Inicializa el objeto Audio
|
||||
@@ -63,9 +63,9 @@ class Audio {
|
||||
private:
|
||||
// --- Enums privados ---
|
||||
enum class MusicState {
|
||||
PLAYING, // Reproduciendo música
|
||||
PAUSED, // Música pausada
|
||||
STOPPED, // Música detenida
|
||||
PLAYING, // Reproduciendo música
|
||||
PAUSED, // Música pausada
|
||||
STOPPED, // Música detenida
|
||||
};
|
||||
|
||||
// --- Estructuras privadas ---
|
||||
@@ -83,10 +83,10 @@ class Audio {
|
||||
};
|
||||
|
||||
// --- Variables de estado ---
|
||||
Music music_; // Estado de la música
|
||||
bool enabled_ = true; // Estado general del audio
|
||||
bool sound_enabled_ = true; // Estado de los efectos de sonido
|
||||
bool music_enabled_ = true; // Estado de la música
|
||||
Music music_; // Estado de la música
|
||||
bool enabled_ = true; // Estado general del audio
|
||||
bool sound_enabled_ = true; // Estado de los efectos de sonido
|
||||
bool music_enabled_ = true; // Estado de la música
|
||||
|
||||
// --- Métodos internos ---
|
||||
void initSDLAudio(); // Inicializa SDL Audio
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <algorithm> // Para clamp, max
|
||||
#include <cmath> // Para M_PI, cos, sin
|
||||
#include <utility>
|
||||
|
||||
#include "moving_sprite.h" // Para MovingSprite
|
||||
#include "param.h" // Para Param, ParamBackground, param
|
||||
@@ -30,8 +31,8 @@ Background::Background(float total_progress_to_complete)
|
||||
sun_completion_progress_(total_progress_to_complete_ * SUN_COMPLETION_FACTOR),
|
||||
|
||||
rect_(SDL_FRect{0, 0, static_cast<float>(gradients_texture_->getWidth() / 2), static_cast<float>(gradients_texture_->getHeight() / 2)}),
|
||||
src_rect_({0, 0, 320, 240}),
|
||||
dst_rect_({0, 0, 320, 240}),
|
||||
src_rect_({.x = 0, .y = 0, .w = 320, .h = 240}),
|
||||
dst_rect_({.x = 0, .y = 0, .w = 320, .h = 240}),
|
||||
attenuate_color_(Color(param.background.attenuate_color.r, param.background.attenuate_color.g, param.background.attenuate_color.b)),
|
||||
|
||||
alpha_color_texture_(param.background.attenuate_color.a),
|
||||
@@ -58,17 +59,17 @@ void Background::initializePaths() {
|
||||
|
||||
// Inicializa los rectángulos de gradientes y nubes
|
||||
void Background::initializeRects() {
|
||||
gradient_rect_[0] = {0, 0, rect_.w, rect_.h};
|
||||
gradient_rect_[1] = {rect_.w, 0, rect_.w, rect_.h};
|
||||
gradient_rect_[2] = {0, rect_.h, rect_.w, rect_.h};
|
||||
gradient_rect_[3] = {rect_.w, rect_.h, rect_.w, rect_.h};
|
||||
gradient_rect_[0] = {.x = 0, .y = 0, .w = rect_.w, .h = rect_.h};
|
||||
gradient_rect_[1] = {.x = rect_.w, .y = 0, .w = rect_.w, .h = rect_.h};
|
||||
gradient_rect_[2] = {.x = 0, .y = rect_.h, .w = rect_.w, .h = rect_.h};
|
||||
gradient_rect_[3] = {.x = rect_.w, .y = rect_.h, .w = rect_.w, .h = rect_.h};
|
||||
|
||||
const float TOP_CLOUDS_TEXTURE_HEIGHT = top_clouds_texture_->getHeight() / 4;
|
||||
const float BOTTOM_CLOUDS_TEXTURE_HEIGHT = bottom_clouds_texture_->getHeight() / 4;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
top_clouds_rect_[i] = {0, i * TOP_CLOUDS_TEXTURE_HEIGHT, static_cast<float>(top_clouds_texture_->getWidth()), TOP_CLOUDS_TEXTURE_HEIGHT};
|
||||
bottom_clouds_rect_[i] = {0, i * BOTTOM_CLOUDS_TEXTURE_HEIGHT, static_cast<float>(bottom_clouds_texture_->getWidth()), BOTTOM_CLOUDS_TEXTURE_HEIGHT};
|
||||
top_clouds_rect_[i] = {.x = 0, .y = i * TOP_CLOUDS_TEXTURE_HEIGHT, .w = static_cast<float>(top_clouds_texture_->getWidth()), .h = TOP_CLOUDS_TEXTURE_HEIGHT};
|
||||
bottom_clouds_rect_[i] = {.x = 0, .y = i * BOTTOM_CLOUDS_TEXTURE_HEIGHT, .w = static_cast<float>(bottom_clouds_texture_->getWidth()), .h = BOTTOM_CLOUDS_TEXTURE_HEIGHT};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +172,7 @@ void Background::incrementProgress(float amount) {
|
||||
// Establece la progresión absoluta
|
||||
void Background::setProgress(float absolute_progress) {
|
||||
float old_progress = progress_;
|
||||
progress_ = std::clamp(absolute_progress, 0.0f, total_progress_to_complete_);
|
||||
progress_ = std::clamp(absolute_progress, 0.0F, total_progress_to_complete_);
|
||||
|
||||
// Notifica el cambio si hay callback y el progreso cambió
|
||||
if (progress_callback_ && progress_ != old_progress) {
|
||||
@@ -187,11 +188,11 @@ void Background::setState(State new_state) {
|
||||
// Reinicia la progresión
|
||||
void Background::reset() {
|
||||
float old_progress = progress_;
|
||||
progress_ = 0.0f;
|
||||
progress_ = 0.0F;
|
||||
state_ = State::NORMAL;
|
||||
manual_mode_ = false;
|
||||
gradient_number_ = 0;
|
||||
transition_ = 0.0f;
|
||||
transition_ = 0.0F;
|
||||
sun_index_ = 0;
|
||||
moon_index_ = 0;
|
||||
|
||||
@@ -208,7 +209,7 @@ void Background::setManualMode(bool manual) {
|
||||
|
||||
// Establece callback para sincronización automática
|
||||
void Background::setProgressCallback(ProgressCallback callback) {
|
||||
progress_callback_ = callback;
|
||||
progress_callback_ = std::move(callback);
|
||||
}
|
||||
|
||||
// Elimina el callback
|
||||
@@ -224,8 +225,8 @@ void Background::setCloudsSpeed(float value) {
|
||||
// Las nubes inferiores van a la mitad de velocidad que las superiores
|
||||
top_clouds_sprite_a_->setVelX(value);
|
||||
top_clouds_sprite_b_->setVelX(value);
|
||||
bottom_clouds_sprite_a_->setVelX(value / 2.0f);
|
||||
bottom_clouds_sprite_b_->setVelX(value / 2.0f);
|
||||
bottom_clouds_sprite_a_->setVelX(value / 2.0F);
|
||||
bottom_clouds_sprite_b_->setVelX(value / 2.0F);
|
||||
}
|
||||
|
||||
// Establece el degradado de fondo
|
||||
@@ -262,19 +263,19 @@ void Background::updateProgression() {
|
||||
}
|
||||
|
||||
// Calcula la transición de los diferentes fondos
|
||||
const float gradient_number_float = std::min(progress_ / progress_per_stage_, 3.0F);
|
||||
const float percent = gradient_number_float - static_cast<int>(gradient_number_float);
|
||||
const float GRADIENT_NUMBER_FLOAT = std::min(progress_ / progress_per_stage_, 3.0F);
|
||||
const float PERCENT = GRADIENT_NUMBER_FLOAT - static_cast<int>(GRADIENT_NUMBER_FLOAT);
|
||||
|
||||
gradient_number_ = static_cast<size_t>(gradient_number_float);
|
||||
transition_ = percent;
|
||||
gradient_number_ = static_cast<size_t>(GRADIENT_NUMBER_FLOAT);
|
||||
transition_ = PERCENT;
|
||||
|
||||
// Calcula la posición del sol
|
||||
const float sun_progression = std::min(progress_ / sun_completion_progress_, 1.0f);
|
||||
sun_index_ = static_cast<size_t>(sun_progression * (sun_path_.size() - 1));
|
||||
const float SUN_PROGRESSION = std::min(progress_ / sun_completion_progress_, 1.0F);
|
||||
sun_index_ = static_cast<size_t>(SUN_PROGRESSION * (sun_path_.size() - 1));
|
||||
|
||||
// Calcula la posición de la luna
|
||||
const float moon_progression = std::min(progress_ / total_progress_to_complete_, 1.0f);
|
||||
moon_index_ = static_cast<size_t>(moon_progression * (moon_path_.size() - 1));
|
||||
const float MOON_PROGRESSION = std::min(progress_ / total_progress_to_complete_, 1.0F);
|
||||
moon_index_ = static_cast<size_t>(MOON_PROGRESSION * (moon_path_.size() - 1));
|
||||
|
||||
// Actualiza la velocidad de las nubes
|
||||
updateCloudsSpeed();
|
||||
@@ -294,22 +295,22 @@ void Background::updateCloudsSpeed() {
|
||||
if (state_ == State::COMPLETED) {
|
||||
float completion_factor = (progress_ - MINIMUM_COMPLETED_PROGRESS) /
|
||||
(total_progress_to_complete_ - MINIMUM_COMPLETED_PROGRESS);
|
||||
completion_factor = std::max(0.1f, completion_factor);
|
||||
completion_factor = std::max(0.1F, completion_factor);
|
||||
base_clouds_speed *= completion_factor;
|
||||
}
|
||||
|
||||
// Aplicar velocidades diferentes para nubes superiores e inferiores
|
||||
const float top_clouds_speed = base_clouds_speed;
|
||||
const float bottom_clouds_speed = base_clouds_speed / 2.0f;
|
||||
const float TOP_CLOUDS_SPEED = base_clouds_speed;
|
||||
const float BOTTOM_CLOUDS_SPEED = base_clouds_speed / 2.0F;
|
||||
|
||||
// Aplicar las velocidades a los sprites correspondientes
|
||||
top_clouds_sprite_a_->setVelX(top_clouds_speed);
|
||||
top_clouds_sprite_b_->setVelX(top_clouds_speed);
|
||||
bottom_clouds_sprite_a_->setVelX(bottom_clouds_speed);
|
||||
bottom_clouds_sprite_b_->setVelX(bottom_clouds_speed);
|
||||
top_clouds_sprite_a_->setVelX(TOP_CLOUDS_SPEED);
|
||||
top_clouds_sprite_b_->setVelX(TOP_CLOUDS_SPEED);
|
||||
bottom_clouds_sprite_a_->setVelX(BOTTOM_CLOUDS_SPEED);
|
||||
bottom_clouds_sprite_b_->setVelX(BOTTOM_CLOUDS_SPEED);
|
||||
|
||||
// Guardar la velocidad principal
|
||||
clouds_speed_ = top_clouds_speed;
|
||||
clouds_speed_ = TOP_CLOUDS_SPEED;
|
||||
}
|
||||
|
||||
// Actualiza las nubes
|
||||
@@ -478,7 +479,7 @@ void Background::createSunPath() {
|
||||
const int NUM_STEPS = static_cast<int>((M_PI - M_PI / 2) / STEP) + 1;
|
||||
|
||||
for (int i = 0; i < NUM_STEPS; ++i) {
|
||||
double theta = M_PI / 2 + i * STEP;
|
||||
double theta = M_PI / 2 + (i * STEP);
|
||||
float x = CENTER_X + (RADIUS * cos(theta));
|
||||
float y = CENTER_Y - (RADIUS * sin(theta));
|
||||
sun_path_.push_back({x, y});
|
||||
@@ -501,9 +502,9 @@ void Background::createMoonPath() {
|
||||
constexpr double STEP = 0.01;
|
||||
const int NUM_STEPS = static_cast<int>((M_PI / 2) / STEP) + 1;
|
||||
|
||||
constexpr float FREEZE_PERCENTAGE = 0.2f; // Porcentaje final del recorrido que se mantiene fijo
|
||||
constexpr float FREEZE_PERCENTAGE = 0.2F; // Porcentaje final del recorrido que se mantiene fijo
|
||||
|
||||
const int FREEZE_START_INDEX = static_cast<int>(NUM_STEPS * (1.0f - FREEZE_PERCENTAGE));
|
||||
const int FREEZE_START_INDEX = static_cast<int>(NUM_STEPS * (1.0F - FREEZE_PERCENTAGE));
|
||||
|
||||
for (int i = 0; i < NUM_STEPS; ++i) {
|
||||
double theta = i * STEP;
|
||||
|
||||
@@ -19,16 +19,16 @@ class Background {
|
||||
public:
|
||||
// --- Enums ---
|
||||
enum class State {
|
||||
NORMAL, // Progresión normal del día
|
||||
COMPLETED // Reducción gradual de la actividad
|
||||
NORMAL, // Progresión normal del día
|
||||
COMPLETED // Reducción gradual de la actividad
|
||||
};
|
||||
|
||||
// --- Tipos ---
|
||||
using ProgressCallback = std::function<void(float)>; // Callback para sincronización
|
||||
|
||||
// --- Constructor y destructor ---
|
||||
Background(float total_progress_to_complete = 6100.0f); // Constructor principal
|
||||
~Background(); // Destructor
|
||||
Background(float total_progress_to_complete = 6100.0F); // Constructor principal
|
||||
~Background(); // Destructor
|
||||
|
||||
// --- Métodos principales ---
|
||||
void update(); // Actualiza la lógica del objeto
|
||||
@@ -50,71 +50,71 @@ class Background {
|
||||
void setAlpha(int alpha); // Ajusta la transparencia del fondo
|
||||
|
||||
// --- Control de progresión ---
|
||||
void incrementProgress(float amount = 1.0f); // Incrementa la progresión interna
|
||||
void incrementProgress(float amount = 1.0F); // Incrementa la progresión interna
|
||||
void setProgress(float absolute_progress); // Establece la progresión absoluta
|
||||
|
||||
// --- Getters ---
|
||||
[[nodiscard]] auto getProgress() const -> float { return progress_; } // Obtiene el progreso actual
|
||||
[[nodiscard]] auto getState() const -> State { return state_; } // Obtiene el estado actual
|
||||
[[nodiscard]] auto getCurrentGradient() const -> int { return static_cast<int>(gradient_number_); } // Obtiene el gradiente actual
|
||||
[[nodiscard]] auto getProgress() const -> float { return progress_; } // Obtiene el progreso actual
|
||||
[[nodiscard]] auto getState() const -> State { return state_; } // Obtiene el estado actual
|
||||
[[nodiscard]] auto getCurrentGradient() const -> int { return static_cast<int>(gradient_number_); } // Obtiene el gradiente actual
|
||||
|
||||
private:
|
||||
// --- Constantes ---
|
||||
static constexpr size_t STAGES = 4; // Número de etapas
|
||||
static constexpr float COMPLETED_REDUCTION_RATE = 25.0f; // Tasa de reducción completada
|
||||
static constexpr float MINIMUM_COMPLETED_PROGRESS = 200.0f; // Progreso mínimo completado
|
||||
static constexpr float SUN_COMPLETION_FACTOR = 0.5f; // Factor de completado del sol
|
||||
static constexpr size_t STAGES = 4; // Número de etapas
|
||||
static constexpr float COMPLETED_REDUCTION_RATE = 25.0F; // Tasa de reducción completada
|
||||
static constexpr float MINIMUM_COMPLETED_PROGRESS = 200.0F; // Progreso mínimo completado
|
||||
static constexpr float SUN_COMPLETION_FACTOR = 0.5F; // Factor de completado del sol
|
||||
|
||||
// --- Objetos y punteros ---
|
||||
SDL_Renderer *renderer_; // Renderizador de la ventana
|
||||
SDL_Texture *canvas_; // Textura para componer el fondo
|
||||
SDL_Texture *color_texture_; // Textura para atenuar el fondo
|
||||
std::shared_ptr<Texture> buildings_texture_; // Textura de edificios
|
||||
std::shared_ptr<Texture> top_clouds_texture_; // Textura de nubes superiores
|
||||
std::shared_ptr<Texture> bottom_clouds_texture_; // Textura de nubes inferiores
|
||||
std::shared_ptr<Texture> grass_texture_; // Textura de hierba
|
||||
std::shared_ptr<Texture> gradients_texture_; // Textura de gradientes
|
||||
std::shared_ptr<Texture> sun_texture_; // Textura del sol
|
||||
std::shared_ptr<Texture> moon_texture_; // Textura de la luna
|
||||
std::unique_ptr<MovingSprite> top_clouds_sprite_a_; // Sprite de nubes superiores A
|
||||
std::unique_ptr<MovingSprite> top_clouds_sprite_b_; // Sprite de nubes superiores B
|
||||
std::unique_ptr<MovingSprite> bottom_clouds_sprite_a_; // Sprite de nubes inferiores A
|
||||
std::unique_ptr<MovingSprite> bottom_clouds_sprite_b_; // Sprite de nubes inferiores B
|
||||
std::unique_ptr<Sprite> buildings_sprite_; // Sprite de edificios
|
||||
std::unique_ptr<Sprite> gradient_sprite_; // Sprite de gradiente
|
||||
std::unique_ptr<Sprite> grass_sprite_; // Sprite de hierba
|
||||
std::unique_ptr<Sprite> sun_sprite_; // Sprite del sol
|
||||
std::unique_ptr<Sprite> moon_sprite_; // Sprite de la luna
|
||||
SDL_Renderer *renderer_; // Renderizador de la ventana
|
||||
SDL_Texture *canvas_; // Textura para componer el fondo
|
||||
SDL_Texture *color_texture_; // Textura para atenuar el fondo
|
||||
std::shared_ptr<Texture> buildings_texture_; // Textura de edificios
|
||||
std::shared_ptr<Texture> top_clouds_texture_; // Textura de nubes superiores
|
||||
std::shared_ptr<Texture> bottom_clouds_texture_; // Textura de nubes inferiores
|
||||
std::shared_ptr<Texture> grass_texture_; // Textura de hierba
|
||||
std::shared_ptr<Texture> gradients_texture_; // Textura de gradientes
|
||||
std::shared_ptr<Texture> sun_texture_; // Textura del sol
|
||||
std::shared_ptr<Texture> moon_texture_; // Textura de la luna
|
||||
std::unique_ptr<MovingSprite> top_clouds_sprite_a_; // Sprite de nubes superiores A
|
||||
std::unique_ptr<MovingSprite> top_clouds_sprite_b_; // Sprite de nubes superiores B
|
||||
std::unique_ptr<MovingSprite> bottom_clouds_sprite_a_; // Sprite de nubes inferiores A
|
||||
std::unique_ptr<MovingSprite> bottom_clouds_sprite_b_; // Sprite de nubes inferiores B
|
||||
std::unique_ptr<Sprite> buildings_sprite_; // Sprite de edificios
|
||||
std::unique_ptr<Sprite> gradient_sprite_; // Sprite de gradiente
|
||||
std::unique_ptr<Sprite> grass_sprite_; // Sprite de hierba
|
||||
std::unique_ptr<Sprite> sun_sprite_; // Sprite del sol
|
||||
std::unique_ptr<Sprite> moon_sprite_; // Sprite de la luna
|
||||
|
||||
// --- Variables de configuración ---
|
||||
const float total_progress_to_complete_; // Progreso total para completar
|
||||
const float progress_per_stage_; // Progreso por etapa
|
||||
const float sun_completion_progress_; // Progreso de completado del sol
|
||||
ProgressCallback progress_callback_; // Callback para notificar cambios de progreso
|
||||
const float total_progress_to_complete_; // Progreso total para completar
|
||||
const float progress_per_stage_; // Progreso por etapa
|
||||
const float sun_completion_progress_; // Progreso de completado del sol
|
||||
ProgressCallback progress_callback_; // Callback para notificar cambios de progreso
|
||||
|
||||
// --- Variables de estado ---
|
||||
std::vector<SDL_FPoint> sun_path_; // Recorrido del sol
|
||||
std::vector<SDL_FPoint> moon_path_; // Recorrido de la luna
|
||||
std::array<SDL_FRect, STAGES> gradient_rect_; // Fondos degradados
|
||||
std::array<SDL_FRect, 4> top_clouds_rect_; // Nubes superiores
|
||||
std::array<SDL_FRect, 4> bottom_clouds_rect_; // Nubes inferiores
|
||||
SDL_FRect rect_; // Tamaño del objeto
|
||||
SDL_FRect src_rect_; // Parte del objeto para copiar en pantalla
|
||||
SDL_FRect dst_rect_; // Posición en pantalla donde se copia el objeto
|
||||
Color attenuate_color_; // Color de atenuación
|
||||
State state_ = State::NORMAL; // Estado actual
|
||||
float progress_ = 0.0f; // Progresión interna
|
||||
float clouds_speed_ = 0; // Velocidad de las nubes
|
||||
float transition_ = 0; // Porcentaje de transición
|
||||
size_t gradient_number_ = 0; // Índice de fondo degradado
|
||||
size_t counter_ = 0; // Contador interno
|
||||
size_t alpha_color_texture_ = 0; // Transparencia de atenuación
|
||||
size_t previous_alpha_color_texture_ = 0; // Transparencia anterior
|
||||
size_t sun_index_ = 0; // Índice del recorrido del sol
|
||||
size_t moon_index_ = 0; // Índice del recorrido de la luna
|
||||
int base_ = 0; // Posición base del fondo
|
||||
Uint8 alpha_ = 0; // Transparencia entre fases
|
||||
bool manual_mode_ = false; // Si está en modo manual
|
||||
std::vector<SDL_FPoint> sun_path_; // Recorrido del sol
|
||||
std::vector<SDL_FPoint> moon_path_; // Recorrido de la luna
|
||||
std::array<SDL_FRect, STAGES> gradient_rect_; // Fondos degradados
|
||||
std::array<SDL_FRect, 4> top_clouds_rect_; // Nubes superiores
|
||||
std::array<SDL_FRect, 4> bottom_clouds_rect_; // Nubes inferiores
|
||||
SDL_FRect rect_; // Tamaño del objeto
|
||||
SDL_FRect src_rect_; // Parte del objeto para copiar en pantalla
|
||||
SDL_FRect dst_rect_; // Posición en pantalla donde se copia el objeto
|
||||
Color attenuate_color_; // Color de atenuación
|
||||
State state_ = State::NORMAL; // Estado actual
|
||||
float progress_ = 0.0F; // Progresión interna
|
||||
float clouds_speed_ = 0; // Velocidad de las nubes
|
||||
float transition_ = 0; // Porcentaje de transición
|
||||
size_t gradient_number_ = 0; // Índice de fondo degradado
|
||||
size_t counter_ = 0; // Contador interno
|
||||
size_t alpha_color_texture_ = 0; // Transparencia de atenuación
|
||||
size_t previous_alpha_color_texture_ = 0; // Transparencia anterior
|
||||
size_t sun_index_ = 0; // Índice del recorrido del sol
|
||||
size_t moon_index_ = 0; // Índice del recorrido de la luna
|
||||
int base_ = 0; // Posición base del fondo
|
||||
Uint8 alpha_ = 0; // Transparencia entre fases
|
||||
bool manual_mode_ = false; // Si está en modo manual
|
||||
|
||||
// --- Métodos internos ---
|
||||
void initializePaths(); // Inicializa las rutas del sol y la luna
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "texture.h" // Para Texture
|
||||
|
||||
// Constructor
|
||||
Balloon::Balloon(float x, float y, Type type, Size size, float vel_x, float speed, Uint16 creation_timer, SDL_FRect play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation)
|
||||
Balloon::Balloon(float x, float y, Type type, Size size, float vel_x, float speed, Uint16 creation_timer, SDL_FRect play_area, const std::shared_ptr<Texture> &texture, const std::vector<std::string> &animation)
|
||||
: sprite_(std::make_unique<AnimatedSprite>(texture, animation)),
|
||||
x_(x),
|
||||
y_(y),
|
||||
@@ -44,7 +44,7 @@ Balloon::Balloon(float x, float y, Type type, Size size, float vel_x, float spee
|
||||
}
|
||||
|
||||
case Type::FLOATER: {
|
||||
default_vy_ = max_vy_ = vy_ = fabs(vx_ * 2.0F);
|
||||
default_vy_ = max_vy_ = vy_ = std::fabs(vx_ * 2.0F);
|
||||
gravity_ = 0.00F;
|
||||
|
||||
const int INDEX = static_cast<int>(size_);
|
||||
|
||||
@@ -40,16 +40,16 @@ class Balloon {
|
||||
|
||||
// --- Enums ---
|
||||
enum class Size : Uint8 {
|
||||
SMALL = 0, // Tamaño pequeño
|
||||
MEDIUM = 1, // Tamaño mediano
|
||||
LARGE = 2, // Tamaño grande
|
||||
EXTRALARGE = 3, // Tamaño extra grande
|
||||
SMALL = 0, // Tamaño pequeño
|
||||
MEDIUM = 1, // Tamaño mediano
|
||||
LARGE = 2, // Tamaño grande
|
||||
EXTRALARGE = 3, // Tamaño extra grande
|
||||
};
|
||||
|
||||
enum class Type : Uint8 {
|
||||
BALLOON = 0, // Globo normal
|
||||
FLOATER = 1, // Globo flotante
|
||||
POWERBALL = 2, // Globo de poder
|
||||
BALLOON = 0, // Globo normal
|
||||
FLOATER = 1, // Globo flotante
|
||||
POWERBALL = 2, // Globo de poder
|
||||
};
|
||||
|
||||
// --- Constructores y destructor ---
|
||||
@@ -62,7 +62,7 @@ class Balloon {
|
||||
float speed,
|
||||
Uint16 creation_timer,
|
||||
SDL_FRect play_area,
|
||||
std::shared_ptr<Texture> texture,
|
||||
const std::shared_ptr<Texture>& texture,
|
||||
const std::vector<std::string>& animation);
|
||||
~Balloon() = default;
|
||||
|
||||
|
||||
@@ -17,9 +17,7 @@
|
||||
|
||||
// Constructor
|
||||
BalloonManager::BalloonManager(IStageInfo *stage_info)
|
||||
: explosions_(std::make_unique<Explosions>()),
|
||||
balloon_formations_(std::make_unique<BalloonFormations>()),
|
||||
stage_info_(stage_info) { init(); }
|
||||
: explosions_(std::make_unique<Explosions>()), balloon_formations_(std::make_unique<BalloonFormations>()), stage_info_(stage_info) { init(); }
|
||||
|
||||
// Inicializa
|
||||
void BalloonManager::init() {
|
||||
@@ -64,7 +62,7 @@ void BalloonManager::init() {
|
||||
|
||||
// Actualiza
|
||||
void BalloonManager::update() {
|
||||
for (auto balloon : balloons_) {
|
||||
for (const auto &balloon : balloons_) {
|
||||
balloon->update();
|
||||
}
|
||||
updateBalloonDeployCounter();
|
||||
@@ -134,8 +132,8 @@ void BalloonManager::deployFormation(int formation_id, int y) {
|
||||
|
||||
// Vacia del vector de globos los globos que ya no sirven
|
||||
void BalloonManager::freeBalloons() {
|
||||
auto it = std::remove_if(balloons_.begin(), balloons_.end(), [](const auto &balloon) { return !balloon->isEnabled(); });
|
||||
balloons_.erase(it, balloons_.end());
|
||||
auto result = std::ranges::remove_if(balloons_, [](const auto &balloon) { return !balloon->isEnabled(); });
|
||||
balloons_.erase(result.begin(), balloons_.end());
|
||||
}
|
||||
|
||||
// Actualiza la variable enemyDeployCounter
|
||||
@@ -226,7 +224,7 @@ void BalloonManager::setBalloonSpeed(float speed) {
|
||||
}
|
||||
|
||||
// Explosiona un globo. Lo destruye y crea otros dos si es el caso
|
||||
auto BalloonManager::popBalloon(std::shared_ptr<Balloon> balloon) -> int {
|
||||
auto BalloonManager::popBalloon(const std::shared_ptr<Balloon> &balloon) -> int {
|
||||
stage_info_->addPower(1);
|
||||
int score = 0;
|
||||
|
||||
@@ -291,7 +289,7 @@ auto BalloonManager::destroyAllBalloons() -> int {
|
||||
}
|
||||
|
||||
balloon_deploy_counter_ = 300;
|
||||
Screen::get()->flash(FLASH_COLOR, 3);
|
||||
Screen::get()->flash(Colors::FLASH, 3);
|
||||
Screen::get()->shake();
|
||||
|
||||
return score;
|
||||
@@ -336,7 +334,7 @@ void BalloonManager::createTwoBigBalloons() {
|
||||
|
||||
// Crea una disposición de globos aleatoria
|
||||
void BalloonManager::createRandomBalloons() {
|
||||
const int NUM_BALLOONS = 2 + rand() % 4;
|
||||
const int NUM_BALLOONS = 2 + (rand() % 4);
|
||||
for (int i = 0; i < NUM_BALLOONS; ++i) {
|
||||
const float X = param.game.game_area.rect.x + (rand() % static_cast<int>(param.game.game_area.rect.w)) - Balloon::WIDTH.at(3);
|
||||
const int Y = param.game.game_area.rect.y + (rand() % 50);
|
||||
|
||||
@@ -55,11 +55,11 @@ class BalloonManager {
|
||||
auto calculateScreenPower() -> int; // Calcula el poder de los globos en pantalla
|
||||
|
||||
// --- Manipulación de globos existentes ---
|
||||
auto popBalloon(std::shared_ptr<Balloon> balloon) -> int; // Explosiona un globo, creando otros si aplica
|
||||
auto destroyBalloon(std::shared_ptr<Balloon> &balloon) -> int; // Explosiona un globo sin crear otros
|
||||
auto destroyAllBalloons() -> int; // Destruye todos los globos
|
||||
void stopAllBalloons(); // Detiene el movimiento de los globos
|
||||
void startAllBalloons(); // Reactiva el movimiento de los globos
|
||||
auto popBalloon(const std::shared_ptr<Balloon> &balloon) -> int; // Explosiona un globo, creando otros si aplica
|
||||
auto destroyBalloon(std::shared_ptr<Balloon> &balloon) -> int; // Explosiona un globo sin crear otros
|
||||
auto destroyAllBalloons() -> int; // Destruye todos los globos
|
||||
void stopAllBalloons(); // Detiene el movimiento de los globos
|
||||
void startAllBalloons(); // Reactiva el movimiento de los globos
|
||||
|
||||
// --- Cambios de apariencia ---
|
||||
void reverseColorsToAllBalloons(); // Invierte los colores de los globos
|
||||
@@ -86,14 +86,14 @@ class BalloonManager {
|
||||
static const int DEFAULT_BALLOON_DEPLOY_COUNTER = 300;
|
||||
|
||||
// --- Objetos y punteros ---
|
||||
Balloons balloons_; // Vector con los globos activos
|
||||
std::unique_ptr<Explosions> explosions_; // Objeto para gestionar explosiones
|
||||
std::unique_ptr<BalloonFormations> balloon_formations_; // Objeto para manejar formaciones enemigas
|
||||
std::vector<std::shared_ptr<Texture>> balloon_textures_; // Texturas de los globos
|
||||
std::vector<std::shared_ptr<Texture>> explosions_textures_; // Texturas de explosiones
|
||||
Balloons balloons_; // Vector con los globos activos
|
||||
std::unique_ptr<Explosions> explosions_; // Objeto para gestionar explosiones
|
||||
std::unique_ptr<BalloonFormations> balloon_formations_; // Objeto para manejar formaciones enemigas
|
||||
std::vector<std::shared_ptr<Texture>> balloon_textures_; // Texturas de los globos
|
||||
std::vector<std::shared_ptr<Texture>> explosions_textures_; // Texturas de explosiones
|
||||
std::vector<std::vector<std::string>> balloon_animations_; // Animaciones de los globos
|
||||
std::vector<std::vector<std::string>> explosions_animations_; // Animaciones de las explosiones
|
||||
IStageInfo *stage_info_; // Informacion de la pantalla actual
|
||||
IStageInfo *stage_info_; // Informacion de la pantalla actual
|
||||
|
||||
// --- Variables de estado ---
|
||||
SDL_FRect play_area_ = param.game.play_area.rect;
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
// Constructor
|
||||
Bullet::Bullet(float x, float y, BulletType bullet_type, bool powered, Player::Id owner)
|
||||
: sprite_(std::make_unique<AnimatedSprite>(Resource::get()->getTexture("bullet.png"), Resource::get()->getAnimation("bullet.ani"))),
|
||||
bullet_type_(bullet_type),
|
||||
owner_(owner) ,
|
||||
bullet_type_(bullet_type),
|
||||
owner_(owner),
|
||||
pos_x_(x),
|
||||
pos_y_(y){
|
||||
pos_y_(y) {
|
||||
vel_x_ = calculateVelocity(bullet_type_);
|
||||
sprite_->setCurrentAnimation(buildAnimationString(bullet_type_, powered));
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ enum class BulletType : Uint8 {
|
||||
};
|
||||
|
||||
enum class BulletMoveStatus : Uint8 {
|
||||
OK = 0, // Movimiento normal
|
||||
OUT = 1 // Fuera de los límites
|
||||
OK = 0, // Movimiento normal
|
||||
OUT = 1 // Fuera de los límites
|
||||
};
|
||||
|
||||
// --- Clase Bullet: representa una bala del jugador ---
|
||||
@@ -34,21 +34,21 @@ class Bullet {
|
||||
~Bullet() = default; // Destructor
|
||||
|
||||
// --- Métodos principales ---
|
||||
void render(); // Dibuja la bala en pantalla
|
||||
auto update() -> BulletMoveStatus; // Actualiza el estado del objeto
|
||||
void disable(); // Desactiva la bala
|
||||
void render(); // Dibuja la bala en pantalla
|
||||
auto update() -> BulletMoveStatus; // Actualiza el estado del objeto
|
||||
void disable(); // Desactiva la bala
|
||||
|
||||
// --- Getters ---
|
||||
[[nodiscard]] auto isEnabled() const -> bool; // Comprueba si está activa
|
||||
[[nodiscard]] auto getOwner() const -> Player::Id; // Devuelve el identificador del dueño
|
||||
auto getCollider() -> Circle &; // Devuelve el círculo de colisión
|
||||
[[nodiscard]] auto isEnabled() const -> bool; // Comprueba si está activa
|
||||
[[nodiscard]] auto getOwner() const -> Player::Id; // Devuelve el identificador del dueño
|
||||
auto getCollider() -> Circle &; // Devuelve el círculo de colisión
|
||||
|
||||
private:
|
||||
// --- Constantes ---
|
||||
static constexpr float VEL_Y = -3.0F; // Velocidad vertical
|
||||
static constexpr float VEL_X_LEFT = -2.0F; // Velocidad izquierda
|
||||
static constexpr float VEL_X_RIGHT = 2.0F; // Velocidad derecha
|
||||
static constexpr float VEL_X_CENTER = 0.0F; // Velocidad central
|
||||
static constexpr float VEL_Y = -3.0F; // Velocidad vertical
|
||||
static constexpr float VEL_X_LEFT = -2.0F; // Velocidad izquierda
|
||||
static constexpr float VEL_X_RIGHT = 2.0F; // Velocidad derecha
|
||||
static constexpr float VEL_X_CENTER = 0.0F; // Velocidad central
|
||||
|
||||
// --- Objetos y punteros ---
|
||||
std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los gráficos
|
||||
|
||||
132
source/color.cpp
132
source/color.cpp
@@ -42,22 +42,8 @@ auto Color::fromHex(const std::string &hex_str) -> Color {
|
||||
return Color(r, g, b, a);
|
||||
}
|
||||
|
||||
// Obtiene un color del vector de colores imitando al Coche Fantástico
|
||||
auto getColorLikeKnightRider(const std::vector<Color> &colors, int counter) -> Color {
|
||||
int cycle_length = colors.size() * 2 - 2;
|
||||
size_t n = counter % cycle_length;
|
||||
|
||||
size_t index;
|
||||
if (n < colors.size()) {
|
||||
index = n; // Avanza: 0,1,2,3
|
||||
} else {
|
||||
index = 2 * (colors.size() - 1) - n; // Retrocede: 2,1
|
||||
}
|
||||
|
||||
return colors[index];
|
||||
}
|
||||
|
||||
constexpr auto rgbToHsv(Color color) -> HSV {
|
||||
// Implementaciones de métodos estáticos de Color
|
||||
constexpr auto Color::rgbToHsv(Color color) -> HSV {
|
||||
float r = color.r / 255.0F;
|
||||
float g = color.g / 255.0F;
|
||||
float b = color.b / 255.0F;
|
||||
@@ -84,10 +70,10 @@ constexpr auto rgbToHsv(Color color) -> HSV {
|
||||
float s = (max <= 0.0F) ? 0.0F : delta / max;
|
||||
float v = max;
|
||||
|
||||
return {h, s, v};
|
||||
return {.h = h, .s = s, .v = v};
|
||||
}
|
||||
|
||||
constexpr auto hsvToRgb(HSV hsv) -> Color {
|
||||
constexpr auto Color::hsvToRgb(HSV hsv) -> Color {
|
||||
float c = hsv.v * hsv.s;
|
||||
float x = c * (1 - std::abs(std::fmod(hsv.h / 60.0F, 2) - 1));
|
||||
float m = hsv.v - c;
|
||||
@@ -128,55 +114,73 @@ constexpr auto hsvToRgb(HSV hsv) -> Color {
|
||||
static_cast<uint8_t>(roundf((b + m) * 255)));
|
||||
}
|
||||
|
||||
auto generateMirroredCycle(Color base, ColorCycleStyle style) -> ColorCycle {
|
||||
ColorCycle result{};
|
||||
HSV base_hsv = rgbToHsv(base);
|
||||
// Implementaciones del namespace Colors
|
||||
namespace Colors {
|
||||
// Obtiene un color del vector de colores imitando al Coche Fantástico
|
||||
auto getColorLikeKnightRider(const std::vector<Color> &colors, int counter) -> Color {
|
||||
int cycle_length = (colors.size() * 2) - 2;
|
||||
size_t n = counter % cycle_length;
|
||||
|
||||
for (size_t i = 0; i < COLOR_CYCLE_SIZE; ++i) {
|
||||
float t = static_cast<float>(i) / (COLOR_CYCLE_SIZE - 1); // 0 → 1
|
||||
float hue_shift = 0.0F;
|
||||
float sat_shift = 0.0F;
|
||||
float val_shift = 0.0F;
|
||||
|
||||
switch (style) {
|
||||
case ColorCycleStyle::SUBTLE_PULSE:
|
||||
// Solo brillo suave
|
||||
val_shift = 0.07F * sinf(t * M_PI);
|
||||
break;
|
||||
|
||||
case ColorCycleStyle::HUE_WAVE:
|
||||
// Oscilación leve de tono
|
||||
hue_shift = 15.0F * (t - 0.5F) * 2.0F;
|
||||
val_shift = 0.05F * sinf(t * M_PI);
|
||||
break;
|
||||
|
||||
case ColorCycleStyle::VIBRANT:
|
||||
// Cambios fuertes en tono y brillo
|
||||
hue_shift = 35.0F * sinf(t * M_PI);
|
||||
val_shift = 0.2F * sinf(t * M_PI);
|
||||
sat_shift = -0.2F * sinf(t * M_PI);
|
||||
break;
|
||||
|
||||
case ColorCycleStyle::DARKEN_GLOW:
|
||||
// Se oscurece al centro
|
||||
val_shift = -0.15F * sinf(t * M_PI);
|
||||
break;
|
||||
|
||||
case ColorCycleStyle::LIGHT_FLASH:
|
||||
// Se ilumina al centro
|
||||
val_shift = 0.25F * sinf(t * M_PI);
|
||||
break;
|
||||
size_t index;
|
||||
if (n < colors.size()) {
|
||||
index = n; // Avanza: 0,1,2,3
|
||||
} else {
|
||||
index = 2 * (colors.size() - 1) - n; // Retrocede: 2,1
|
||||
}
|
||||
|
||||
HSV adjusted = {
|
||||
fmodf(base_hsv.h + hue_shift + 360.0F, 360.0F),
|
||||
fminf(1.0F, fmaxf(0.0F, base_hsv.s + sat_shift)),
|
||||
fminf(1.0F, fmaxf(0.0F, base_hsv.v + val_shift))};
|
||||
|
||||
Color c = hsvToRgb(adjusted);
|
||||
result[i] = c;
|
||||
result[2 * COLOR_CYCLE_SIZE - 1 - i] = c; // espejo
|
||||
return colors[index];
|
||||
}
|
||||
|
||||
return result;
|
||||
auto generateMirroredCycle(Color base, ColorCycleStyle style) -> Cycle {
|
||||
Cycle result{};
|
||||
HSV base_hsv = Color::rgbToHsv(base);
|
||||
|
||||
for (size_t i = 0; i < CYCLE_SIZE; ++i) {
|
||||
float t = static_cast<float>(i) / (CYCLE_SIZE - 1); // 0 → 1
|
||||
float hue_shift = 0.0F;
|
||||
float sat_shift = 0.0F;
|
||||
float val_shift = 0.0F;
|
||||
|
||||
switch (style) {
|
||||
case ColorCycleStyle::SUBTLE_PULSE:
|
||||
// Solo brillo suave
|
||||
val_shift = 0.07F * sinf(t * M_PI);
|
||||
break;
|
||||
|
||||
case ColorCycleStyle::HUE_WAVE:
|
||||
// Oscilación leve de tono
|
||||
hue_shift = 15.0F * (t - 0.5F) * 2.0F;
|
||||
val_shift = 0.05F * sinf(t * M_PI);
|
||||
break;
|
||||
|
||||
case ColorCycleStyle::VIBRANT:
|
||||
// Cambios fuertes en tono y brillo
|
||||
hue_shift = 35.0F * sinf(t * M_PI);
|
||||
val_shift = 0.2F * sinf(t * M_PI);
|
||||
sat_shift = -0.2F * sinf(t * M_PI);
|
||||
break;
|
||||
|
||||
case ColorCycleStyle::DARKEN_GLOW:
|
||||
// Se oscurece al centro
|
||||
val_shift = -0.15F * sinf(t * M_PI);
|
||||
break;
|
||||
|
||||
case ColorCycleStyle::LIGHT_FLASH:
|
||||
// Se ilumina al centro
|
||||
val_shift = 0.25F * sinf(t * M_PI);
|
||||
break;
|
||||
}
|
||||
|
||||
HSV adjusted = {
|
||||
.h = fmodf(base_hsv.h + hue_shift + 360.0F, 360.0F),
|
||||
.s = fminf(1.0F, fmaxf(0.0F, base_hsv.s + sat_shift)),
|
||||
.v = fminf(1.0F, fmaxf(0.0F, base_hsv.v + val_shift))};
|
||||
|
||||
Color c = Color::hsvToRgb(adjusted);
|
||||
result[i] = c;
|
||||
result[(2 * CYCLE_SIZE) - 1 - i] = c; // espejo
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,12 @@
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
// --- Constantes ---
|
||||
constexpr size_t COLOR_CYCLE_SIZE = 6; // Mitad del ciclo espejado
|
||||
// --- Estructura HSV: define un color en formato HSV ---
|
||||
struct HSV {
|
||||
float h; // Matiz (Hue)
|
||||
float s; // Saturación (Saturation)
|
||||
float v; // Valor (Value)
|
||||
};
|
||||
|
||||
// --- Estructura Color: define un color RGBA ---
|
||||
struct Color {
|
||||
@@ -60,6 +64,10 @@ struct Color {
|
||||
// Método estático para crear Color desde string hexadecimal
|
||||
static auto fromHex(const std::string &hex_str) -> Color;
|
||||
|
||||
// Conversiones de formato de color
|
||||
[[nodiscard]] constexpr static auto rgbToHsv(Color color) -> HSV;
|
||||
[[nodiscard]] constexpr static auto hsvToRgb(HSV hsv) -> Color;
|
||||
|
||||
[[nodiscard]] constexpr auto IS_EQUAL_TO(const Color &other) const -> bool {
|
||||
return r == other.r && g == other.g && b == other.b && a == other.a;
|
||||
}
|
||||
@@ -81,7 +89,7 @@ struct Color {
|
||||
}
|
||||
|
||||
// Convierte el color a un entero de 32 bits en formato RGBA
|
||||
[[nodiscard]] constexpr auto toUint32() const -> Uint32 {
|
||||
[[nodiscard]] constexpr auto TO_UINT32() const -> Uint32 {
|
||||
return (static_cast<Uint32>(r) << 24) |
|
||||
(static_cast<Uint32>(g) << 16) |
|
||||
(static_cast<Uint32>(b) << 8) |
|
||||
@@ -89,13 +97,6 @@ struct Color {
|
||||
}
|
||||
};
|
||||
|
||||
// --- Estructura HSV: define un color en formato HSV ---
|
||||
struct HSV {
|
||||
float h; // Matiz (Hue)
|
||||
float s; // Saturación (Saturation)
|
||||
float v; // Valor (Value)
|
||||
};
|
||||
|
||||
// --- Enum ColorCycleStyle: define estilos de ciclo de color ---
|
||||
enum class ColorCycleStyle {
|
||||
SUBTLE_PULSE, // Variación leve en brillo (por defecto)
|
||||
@@ -105,23 +106,27 @@ enum class ColorCycleStyle {
|
||||
LIGHT_FLASH // Ilumina hacia el centro y regresa
|
||||
};
|
||||
|
||||
// --- Alias ---
|
||||
using ColorCycle = std::array<Color, 2 * COLOR_CYCLE_SIZE>;
|
||||
// --- Namespace Colors: constantes y utilidades de color ---
|
||||
namespace Colors {
|
||||
// --- Constantes ---
|
||||
constexpr size_t CYCLE_SIZE = 6; // Mitad del ciclo espejado
|
||||
|
||||
// --- Colores predefinidos ---
|
||||
constexpr Color NO_TEXT_COLOR = Color(0XFF, 0XFF, 0XFF);
|
||||
constexpr Color SHADOW_TEXT_COLOR = Color(0X43, 0X43, 0X4F);
|
||||
constexpr Color TITLE_SHADOW_TEXT_COLOR = Color(0x14, 0x87, 0xc4);
|
||||
constexpr Color ORANGE_TEXT_COLOR = Color(0XFF, 0X7A, 0X00);
|
||||
// --- Alias ---
|
||||
using Cycle = std::array<Color, 2 * CYCLE_SIZE>;
|
||||
|
||||
constexpr Color FLASH_COLOR = Color(0XFF, 0XFF, 0XFF);
|
||||
// --- Colores predefinidos ---
|
||||
constexpr Color NO_COLOR_MOD = Color(0XFF, 0XFF, 0XFF);
|
||||
constexpr Color SHADOW_TEXT = Color(0X43, 0X43, 0X4F);
|
||||
constexpr Color TITLE_SHADOW_TEXT = Color(0x14, 0x87, 0xc4);
|
||||
constexpr Color ORANGE_TEXT = Color(0XFF, 0X7A, 0X00);
|
||||
|
||||
constexpr Color BLUE_SKY_COLOR = Color(0X02, 0X88, 0XD1);
|
||||
constexpr Color PINK_SKY_COLOR = Color(0XFF, 0X6B, 0X97);
|
||||
constexpr Color GREEN_SKY_COLOR = Color(0X00, 0X79, 0X6B);
|
||||
constexpr Color FLASH = Color(0XFF, 0XFF, 0XFF);
|
||||
|
||||
// --- Funciones ---
|
||||
auto getColorLikeKnightRider(const std::vector<Color> &colors, int counter) -> Color;
|
||||
constexpr auto rgbToHsv(Color color) -> HSV;
|
||||
constexpr auto hsvToRgb(HSV hsv) -> Color;
|
||||
auto generateMirroredCycle(Color base, ColorCycleStyle style = ColorCycleStyle::SUBTLE_PULSE) -> ColorCycle;
|
||||
constexpr Color BLUE_SKY = Color(0X02, 0X88, 0XD1);
|
||||
constexpr Color PINK_SKY = Color(0XFF, 0X6B, 0X97);
|
||||
constexpr Color GREEN_SKY = Color(0X00, 0X79, 0X6B);
|
||||
|
||||
// --- Funciones ---
|
||||
auto getColorLikeKnightRider(const std::vector<Color> &colors, int counter) -> Color;
|
||||
auto generateMirroredCycle(Color base, ColorCycleStyle style = ColorCycleStyle::SUBTLE_PULSE) -> Cycle;
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_ScaleMode
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "color.h"
|
||||
@@ -10,38 +12,38 @@ namespace GameDefaults {
|
||||
|
||||
// --- GAME ---
|
||||
namespace Game {
|
||||
constexpr float WIDTH = 320.0f;
|
||||
constexpr float HEIGHT = 256.0f;
|
||||
constexpr float ITEM_SIZE = 20.0f;
|
||||
constexpr float WIDTH = 320.0F;
|
||||
constexpr float HEIGHT = 256.0F;
|
||||
constexpr float ITEM_SIZE = 20.0F;
|
||||
constexpr int NAME_ENTRY_IDLE_TIME = 10;
|
||||
constexpr int NAME_ENTRY_TOTAL_TIME = 60;
|
||||
constexpr bool HIT_STOP = false;
|
||||
constexpr int HIT_STOP_MS = 500;
|
||||
constexpr const char* ITEM_TEXT_OUTLINE_COLOR = "FFFFFF00"; // 255, 255, 255, 0
|
||||
|
||||
// Play area por defecto
|
||||
constexpr float PLAY_AREA_X = 0.0f;
|
||||
constexpr float PLAY_AREA_Y = 0.0f;
|
||||
constexpr float PLAY_AREA_W = 320.0f;
|
||||
constexpr float PLAY_AREA_H = 216.0f;
|
||||
constexpr float PLAY_AREA_X = 0.0F;
|
||||
constexpr float PLAY_AREA_Y = 0.0F;
|
||||
constexpr float PLAY_AREA_W = 320.0F;
|
||||
constexpr float PLAY_AREA_H = 216.0F;
|
||||
} // namespace Game
|
||||
|
||||
// --- FADE ---
|
||||
namespace Fade {
|
||||
constexpr const char* COLOR = "1F2B30";
|
||||
constexpr float NUM_SQUARES_WIDTH = 160.0f;
|
||||
constexpr float NUM_SQUARES_HEIGHT = 128.0f;
|
||||
constexpr int RANDOM_SQUARES_DELAY = 1;
|
||||
constexpr int RANDOM_SQUARES_MULT = 500;
|
||||
constexpr int POST_DURATION = 80;
|
||||
constexpr float VENETIAN_SIZE = 12.0f;
|
||||
constexpr float NUM_SQUARES_WIDTH = 160.0F;
|
||||
constexpr float NUM_SQUARES_HEIGHT = 128.0F;
|
||||
constexpr int RANDOM_SQUARES_DURATION_MS = 1;
|
||||
constexpr int POST_DURATION_MS = 80;
|
||||
constexpr float VENETIAN_SIZE = 12.0F;
|
||||
} // namespace Fade
|
||||
|
||||
// --- SCOREBOARD ---
|
||||
namespace Scoreboard {
|
||||
constexpr float RECT_X = 0.0f;
|
||||
constexpr float RECT_Y = 216.0f;
|
||||
constexpr float RECT_W = 320.0f;
|
||||
constexpr float RECT_H = 40.0f;
|
||||
constexpr float RECT_X = 0.0F;
|
||||
constexpr float RECT_Y = 216.0F;
|
||||
constexpr float RECT_W = 320.0F;
|
||||
constexpr float RECT_H = 40.0F;
|
||||
constexpr bool SEPARATOR_AUTOCOLOR = true;
|
||||
constexpr const char* SEPARATOR_COLOR = "0D1A2B";
|
||||
constexpr const char* EASY_COLOR = "4B692F";
|
||||
@@ -73,18 +75,22 @@ namespace Balloon {
|
||||
struct BalloonSettings {
|
||||
float vel;
|
||||
float grav;
|
||||
constexpr BalloonSettings(float v, float g) : vel(v), grav(g) {}
|
||||
constexpr BalloonSettings(float v, float g)
|
||||
: vel(v), grav(g) {}
|
||||
};
|
||||
|
||||
constexpr std::array<BalloonSettings, 4> SETTINGS = {{
|
||||
BalloonSettings(2.75f, 0.09f), // Globo 0
|
||||
BalloonSettings(3.70f, 0.10f), // Globo 1
|
||||
BalloonSettings(4.70f, 0.10f), // Globo 2
|
||||
BalloonSettings(5.45f, 0.10f) // Globo 3
|
||||
BalloonSettings(2.75F, 0.09F), // Globo 0
|
||||
BalloonSettings(3.70F, 0.10F), // Globo 1
|
||||
BalloonSettings(4.70F, 0.10F), // Globo 2
|
||||
BalloonSettings(5.45F, 0.10F) // Globo 3
|
||||
}};
|
||||
|
||||
constexpr std::array<const char*, 4> COLORS = {
|
||||
"blue", "orange", "red", "green"};
|
||||
"blue",
|
||||
"orange",
|
||||
"red",
|
||||
"green"};
|
||||
|
||||
constexpr bool BOUNCING_SOUND = false;
|
||||
} // namespace Balloon
|
||||
@@ -111,15 +117,15 @@ constexpr const char* BG_COLOR = "141E32F0"; // Color(20, 30, 50, 240)
|
||||
constexpr const char* BORDER_COLOR = "6496C8FF"; // Color(100, 150, 200, 255)
|
||||
constexpr const char* TITLE_COLOR = "6496C8FF"; // Color(100, 150, 200, 255)
|
||||
constexpr const char* TEXT_COLOR = "DCDCDCFF"; // Color(220, 220, 220, 255)
|
||||
constexpr float PADDING = 15.0f;
|
||||
constexpr float LINE_SPACING = 5.0f;
|
||||
constexpr float TITLE_SEPARATOR_SPACING = 10.0f; // Cambiado a float
|
||||
constexpr float MIN_WIDTH = 250.0f;
|
||||
constexpr float MIN_HEIGHT = 32.0f; // Cambiado a float
|
||||
constexpr float MAX_WIDTH_RATIO = 0.8f; // Nuevo
|
||||
constexpr float MAX_HEIGHT_RATIO = 0.8f; // Nuevo
|
||||
constexpr float TEXT_SAFETY_MARGIN = 15.0f;
|
||||
constexpr float ANIMATION_DURATION = 0.3f;
|
||||
constexpr float PADDING = 15.0F;
|
||||
constexpr float LINE_SPACING = 5.0F;
|
||||
constexpr float TITLE_SEPARATOR_SPACING = 10.0F; // Cambiado a float
|
||||
constexpr float MIN_WIDTH = 250.0F;
|
||||
constexpr float MIN_HEIGHT = 32.0F; // Cambiado a float
|
||||
constexpr float MAX_WIDTH_RATIO = 0.8F; // Nuevo
|
||||
constexpr float MAX_HEIGHT_RATIO = 0.8F; // Nuevo
|
||||
constexpr float TEXT_SAFETY_MARGIN = 15.0F;
|
||||
constexpr float ANIMATION_DURATION = 0.3F;
|
||||
} // namespace WindowMessage
|
||||
} // namespace ServiceMenu
|
||||
|
||||
@@ -143,12 +149,26 @@ constexpr const char* COLOR = "FFFFFF";
|
||||
|
||||
// --- TABE ---
|
||||
namespace Tabe {
|
||||
constexpr float MIN_SPAWN_TIME = 2.0f;
|
||||
constexpr float MAX_SPAWN_TIME = 3.0f;
|
||||
constexpr float MIN_SPAWN_TIME = 2.0F;
|
||||
constexpr float MAX_SPAWN_TIME = 3.0F;
|
||||
} // namespace Tabe
|
||||
|
||||
// --- PLAYER ---
|
||||
namespace Player {
|
||||
namespace DefaultShirt {
|
||||
// Player 0 (Jugador 1)
|
||||
constexpr const char* PLAYER0_DARKEST = "028ECFFF"; // 2, 142, 207, 255
|
||||
constexpr const char* PLAYER0_DARK = "0297DBFF"; // 2, 151, 219, 255
|
||||
constexpr const char* PLAYER0_BASE = "029FE8FF"; // 2, 159, 232, 255
|
||||
constexpr const char* PLAYER0_LIGHT = "03A9F4FF"; // 3, 169, 244, 255
|
||||
|
||||
// Player 1 (Jugador 2)
|
||||
constexpr const char* PLAYER1_DARKEST = "8E8E8EFF"; // 142, 142, 142, 255
|
||||
constexpr const char* PLAYER1_DARK = "AEADADFF"; // 174, 173, 173, 255
|
||||
constexpr const char* PLAYER1_BASE = "E4E4E4FF"; // 228, 228, 228, 255
|
||||
constexpr const char* PLAYER1_LIGHT = "F7F1F1FF"; // 247, 241, 241, 255
|
||||
} // namespace DefaultShirt
|
||||
|
||||
namespace OneCoffeeShirt {
|
||||
// Player 0 (Jugador 1)
|
||||
constexpr const char* PLAYER0_DARKEST = "3D9C70FF"; // 61, 156, 112, 255
|
||||
@@ -176,5 +196,45 @@ constexpr const char* PLAYER1_DARK = "FA7D00FF"; // 250, 125, 0, 255
|
||||
constexpr const char* PLAYER1_BASE = "FAA200FF"; // 250, 162, 0, 255
|
||||
constexpr const char* PLAYER1_LIGHT = "FA8500FF"; // 250, 133, 0, 255
|
||||
} // namespace TwoCoffeeShirt
|
||||
|
||||
namespace OutlineColor {
|
||||
// Player 0 (Jugador 1)
|
||||
constexpr const char* PLAYER0 = "66323FFF";
|
||||
|
||||
// Player 1 (Jugador 2)
|
||||
constexpr const char* PLAYER1 = "422028FF";
|
||||
} // namespace OutlineColor
|
||||
} // namespace Player
|
||||
|
||||
// --- OPTIONS ---
|
||||
namespace Options {
|
||||
// Window
|
||||
constexpr const char* WINDOW_CAPTION = "Coffee Crisis Arcade Edition";
|
||||
constexpr int WINDOW_ZOOM = 2;
|
||||
constexpr int WINDOW_MAX_ZOOM = 2;
|
||||
|
||||
// Video
|
||||
constexpr SDL_ScaleMode VIDEO_SCALE_MODE = SDL_ScaleMode::SDL_SCALEMODE_NEAREST;
|
||||
constexpr bool VIDEO_FULLSCREEN = false;
|
||||
constexpr bool VIDEO_VSYNC = true;
|
||||
constexpr bool VIDEO_INTEGER_SCALE = true;
|
||||
constexpr bool VIDEO_SHADERS = false;
|
||||
|
||||
// Music
|
||||
constexpr bool MUSIC_ENABLED = true;
|
||||
constexpr int MUSIC_VOLUME = 100;
|
||||
|
||||
// Sound
|
||||
constexpr bool SOUND_ENABLED = true;
|
||||
constexpr int SOUND_VOLUME = 100;
|
||||
|
||||
// Audio
|
||||
constexpr bool AUDIO_ENABLED = true;
|
||||
constexpr int AUDIO_VOLUME = 100;
|
||||
|
||||
// Settings
|
||||
constexpr bool SETTINGS_AUTOFIRE = true;
|
||||
constexpr bool SETTINGS_SHUTDOWN_ENABLED = false;
|
||||
constexpr const char* PARAMS_FILE = "param_320x256.txt";
|
||||
} // namespace Options
|
||||
} // namespace GameDefaults
|
||||
@@ -19,7 +19,7 @@ DefineButtons::DefineButtons()
|
||||
clearButtons();
|
||||
|
||||
auto gamepads = input_->getGamepads();
|
||||
for (auto gamepad : gamepads) {
|
||||
for (const auto &gamepad : gamepads) {
|
||||
controller_names_.emplace_back(Input::getControllerName(gamepad));
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ void DefineButtons::doControllerButtonDown(const SDL_GamepadButtonEvent &event)
|
||||
|
||||
const auto BUTTON = static_cast<SDL_GamepadButton>(event.button);
|
||||
if (checkButtonNotInUse(BUTTON)) {
|
||||
buttons_.at(index_button_).button = BUTTON;
|
||||
buttons_.at(index_button_).button = static_cast<int>(BUTTON);
|
||||
incIndexButton();
|
||||
updateWindowMessage();
|
||||
}
|
||||
@@ -142,7 +142,7 @@ void DefineButtons::doControllerAxisMotion(const SDL_GamepadAxisEvent &event) {
|
||||
// Solo manejamos L2 y R2 como botones con lógica de transición
|
||||
if (event.axis == SDL_GAMEPAD_AXIS_LEFT_TRIGGER) {
|
||||
bool l2_is_pressed_now = event.value > 16384;
|
||||
|
||||
|
||||
// Solo actuar en la transición de no presionado a presionado
|
||||
if (l2_is_pressed_now && !l2_was_pressed_) {
|
||||
const auto TRIGGER_BUTTON = Input::TRIGGER_L2_AS_BUTTON;
|
||||
@@ -152,17 +152,17 @@ void DefineButtons::doControllerAxisMotion(const SDL_GamepadAxisEvent &event) {
|
||||
updateWindowMessage();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Detectar liberación del trigger para llamar checkEnd()
|
||||
if (!l2_is_pressed_now && l2_was_pressed_) {
|
||||
checkEnd();
|
||||
}
|
||||
|
||||
|
||||
l2_was_pressed_ = l2_is_pressed_now;
|
||||
|
||||
|
||||
} else if (event.axis == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) {
|
||||
bool r2_is_pressed_now = event.value > 16384;
|
||||
|
||||
|
||||
// Solo actuar en la transición de no presionado a presionado
|
||||
if (r2_is_pressed_now && !r2_was_pressed_) {
|
||||
const auto TRIGGER_BUTTON = Input::TRIGGER_R2_AS_BUTTON;
|
||||
@@ -172,19 +172,19 @@ void DefineButtons::doControllerAxisMotion(const SDL_GamepadAxisEvent &event) {
|
||||
updateWindowMessage();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Detectar liberación del trigger para llamar checkEnd()
|
||||
if (!r2_is_pressed_now && r2_was_pressed_) {
|
||||
checkEnd();
|
||||
}
|
||||
|
||||
|
||||
r2_was_pressed_ = r2_is_pressed_now;
|
||||
}
|
||||
}
|
||||
|
||||
void DefineButtons::bindButtons(Options::Gamepad *options_gamepad) {
|
||||
for (const auto &button : buttons_) {
|
||||
Input::bindGameControllerButton(options_gamepad->instance, button.action, button.button);
|
||||
Input::bindGameControllerButton(options_gamepad->instance, button.action, static_cast<SDL_GamepadButton>(button.button));
|
||||
}
|
||||
|
||||
Input::bindGameControllerButton(options_gamepad->instance, Input::Action::SM_SELECT, Input::Action::FIRE_LEFT);
|
||||
@@ -205,7 +205,7 @@ auto DefineButtons::checkButtonNotInUse(SDL_GamepadButton button) -> bool {
|
||||
});
|
||||
}
|
||||
|
||||
auto DefineButtons::checkTriggerNotInUse(SDL_GamepadButton trigger_button) -> bool {
|
||||
auto DefineButtons::checkTriggerNotInUse(int trigger_button) -> bool {
|
||||
return std::ranges::all_of(buttons_, [trigger_button](const auto &b) {
|
||||
return b.button != trigger_button;
|
||||
});
|
||||
@@ -213,11 +213,11 @@ auto DefineButtons::checkTriggerNotInUse(SDL_GamepadButton trigger_button) -> bo
|
||||
|
||||
void DefineButtons::clearButtons() {
|
||||
buttons_.clear();
|
||||
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_LEFT"), Input::Action::FIRE_LEFT, SDL_GAMEPAD_BUTTON_INVALID);
|
||||
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_UP"), Input::Action::FIRE_CENTER, SDL_GAMEPAD_BUTTON_INVALID);
|
||||
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_RIGHT"), Input::Action::FIRE_RIGHT, SDL_GAMEPAD_BUTTON_INVALID);
|
||||
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] START"), Input::Action::START, SDL_GAMEPAD_BUTTON_INVALID);
|
||||
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] SERVICE_MENU"), Input::Action::SERVICE, SDL_GAMEPAD_BUTTON_INVALID);
|
||||
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_LEFT"), Input::Action::FIRE_LEFT, static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID));
|
||||
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_UP"), Input::Action::FIRE_CENTER, static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID));
|
||||
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_RIGHT"), Input::Action::FIRE_RIGHT, static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID));
|
||||
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] START"), Input::Action::START, static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID));
|
||||
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] SERVICE_MENU"), Input::Action::SERVICE, static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID));
|
||||
}
|
||||
|
||||
void DefineButtons::checkEnd() {
|
||||
|
||||
@@ -22,9 +22,9 @@ class DefineButtons {
|
||||
struct Button {
|
||||
std::string label;
|
||||
Input::Action action;
|
||||
SDL_GamepadButton button;
|
||||
int button;
|
||||
|
||||
Button(std::string label, Input::Action action, SDL_GamepadButton button)
|
||||
Button(std::string label, Input::Action action, int button)
|
||||
: label(std::move(label)), action(action), button(button) {}
|
||||
};
|
||||
|
||||
@@ -71,7 +71,7 @@ class DefineButtons {
|
||||
void doControllerAxisMotion(const SDL_GamepadAxisEvent &event);
|
||||
void bindButtons(Options::Gamepad *options_gamepad);
|
||||
auto checkButtonNotInUse(SDL_GamepadButton button) -> bool;
|
||||
auto checkTriggerNotInUse(SDL_GamepadButton trigger_button) -> bool;
|
||||
auto checkTriggerNotInUse(int trigger_button) -> bool;
|
||||
void clearButtons();
|
||||
void checkEnd();
|
||||
void updateWindowMessage();
|
||||
|
||||
@@ -8,9 +8,9 @@ static std::vector<Info> difficulties_list;
|
||||
|
||||
void init() {
|
||||
difficulties_list = {
|
||||
{Code::EASY, "Easy"},
|
||||
{Code::NORMAL, "Normal"},
|
||||
{Code::HARD, "Hard"}};
|
||||
{.code = Code::EASY, .name = "Easy"},
|
||||
{.code = Code::NORMAL, .name = "Normal"},
|
||||
{.code = Code::HARD, .name = "Hard"}};
|
||||
}
|
||||
|
||||
auto getDifficulties() -> std::vector<Info>& {
|
||||
|
||||
@@ -21,8 +21,8 @@ struct Info {
|
||||
// --- Funciones ---
|
||||
void init(); // Inicializa la lista de dificultades con sus valores por defecto
|
||||
|
||||
auto getDifficulties() -> std::vector<Info>&; // Devuelve una referencia al vector de todas las dificultades
|
||||
auto getNameFromCode(Code code) -> std::string; // Obtiene el nombre de una dificultad a partir de su código
|
||||
auto getCodeFromName(const std::string& name) -> Code; // Obtiene el código de una dificultad a partir de su nombre
|
||||
auto getDifficulties() -> std::vector<Info>&; // Devuelve una referencia al vector de todas las dificultades
|
||||
auto getNameFromCode(Code code) -> std::string; // Obtiene el nombre de una dificultad a partir de su código
|
||||
auto getCodeFromName(const std::string& name) -> Code; // Obtiene el código de una dificultad a partir de su nombre
|
||||
|
||||
} // namespace Difficulty
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "manage_hiscore_table.h" // Para ManageHiScoreTable
|
||||
#include "options.h" // Para loadFromFile, saveToFile, Settings, settings, setConfigFile, setControllersFile
|
||||
#include "param.h" // Para loadParamsFromFile
|
||||
#include "resource_helper.h" // Para ResourceHelper
|
||||
#include "player.h" // Para Player
|
||||
#include "resource.h" // Para Resource
|
||||
#include "screen.h" // Para Screen
|
||||
@@ -41,7 +42,7 @@ Director::Director(int argc, std::span<char *> argv) {
|
||||
Section::name = Section::Name::GAME;
|
||||
Section::options = Section::Options::GAME_PLAY_1P;
|
||||
#elif _DEBUG
|
||||
Section::name = Section::Name::LOGO;
|
||||
Section::name = Section::Name::GAME;
|
||||
Section::options = Section::Options::GAME_PLAY_1P;
|
||||
#else // NORMAL GAME
|
||||
Section::name = Section::Name::LOGO;
|
||||
@@ -77,6 +78,12 @@ Director::~Director() {
|
||||
void Director::init() {
|
||||
// Configuración inicial de parametros
|
||||
Asset::init(executable_path_); // Inicializa el sistema de gestión de archivos
|
||||
|
||||
#ifdef MACOS_BUNDLE
|
||||
ResourceHelper::initializeResourceSystem(executable_path_ + "/../Resources/resources.pack");
|
||||
#else
|
||||
ResourceHelper::initializeResourceSystem("resources.pack");
|
||||
#endif
|
||||
loadAssets(); // Crea el índice de archivos
|
||||
Input::init(Asset::get()->get("gamecontrollerdb.txt"), Asset::get()->get("controllers.json")); // Carga configuración de controles
|
||||
Options::setConfigFile(Asset::get()->get("config.txt")); // Establece el fichero de configuración
|
||||
@@ -124,9 +131,9 @@ void Director::close() {
|
||||
void Director::loadParams() {
|
||||
// Carga los parametros para configurar el juego
|
||||
#ifdef ANBERNIC
|
||||
const std::string paramFilePath = asset->get("param_320x240.txt");
|
||||
const std::string PARAM_FILE_PATH = Asset::get()->get("param_320x240.txt");
|
||||
#else
|
||||
const std::string PARAM_FILE_PATH = overrides.param_file == "--320x240" ? Asset::get()->get("param_320x240.txt") : Asset::get()->get("param_320x256.txt");
|
||||
const std::string PARAM_FILE_PATH = Asset::get()->get(Options::settings.params_file);
|
||||
#endif
|
||||
loadParamsFromFile(PARAM_FILE_PATH);
|
||||
}
|
||||
@@ -154,7 +161,7 @@ void Director::loadAssets() {
|
||||
#endif
|
||||
|
||||
// Cargar la configuración de assets (también aplicar el prefijo al archivo de configuración)
|
||||
std::string config_path = executable_path_ + PREFIX + "/data/config/assets.txt";
|
||||
std::string config_path = executable_path_ + PREFIX + "/config/assets.txt";
|
||||
Asset::get()->loadFromFile(config_path, PREFIX, system_folder_);
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Assets configuration loaded successfully");
|
||||
@@ -188,7 +195,7 @@ void Director::createSystemFolder(const std::string &folder) {
|
||||
|
||||
if (result != SystemUtils::Result::SUCCESS) {
|
||||
std::cerr << "Error creando carpeta del sistema: "
|
||||
<< SystemUtils::resultToString(result) << std::endl;
|
||||
<< SystemUtils::resultToString(result) << '\n';
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
@@ -321,7 +328,7 @@ void Director::shutdownSystem(bool should_shutdown) {
|
||||
auto result = SystemShutdown::shutdownSystem(5, true); // 5 segundos, forzar apps
|
||||
|
||||
if (result != SystemShutdown::ShutdownResult::SUCCESS) {
|
||||
std::cerr << SystemShutdown::resultToString(result) << std::endl;
|
||||
std::cerr << SystemShutdown::resultToString(result) << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ void EnterName::incPosition() {
|
||||
if (position_ >= NAME_SIZE) {
|
||||
position_ = NAME_SIZE; // Mantenemos en el índice máximo válido.
|
||||
position_overflow_ = true; // Activamos el flag de overflow.
|
||||
} else if (position_ > 0) // No es necesario verificar position_ < MAX_NAME_LENGHT
|
||||
} else if (position_ > 0) // No es necesario verificar position_ < MAX_NAME_LENGTH
|
||||
{
|
||||
// Copiamos el índice del carácter anterior si es posible.
|
||||
character_index_[position_] = character_index_[position_ - 1];
|
||||
@@ -74,7 +74,7 @@ void EnterName::decPosition() {
|
||||
// character_index_[position_] = 0;
|
||||
}
|
||||
|
||||
// Si position_ es menor que NAME_LENGHT, aseguramos que el overflow esté desactivado.
|
||||
// Si position_ es menor que NAME_LENGTH, aseguramos que el overflow esté desactivado.
|
||||
if (position_ < NAME_SIZE) {
|
||||
position_overflow_ = false;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ void Explosions::render() {
|
||||
}
|
||||
|
||||
// Añade texturas al objeto
|
||||
void Explosions::addTexture(int size, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation) {
|
||||
void Explosions::addTexture(int size, const std::shared_ptr<Texture> &texture, const std::vector<std::string> &animation) {
|
||||
textures_.emplace_back(size, texture, animation);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory> // Para unique_ptr, shared_ptr
|
||||
#include <string> // Para string
|
||||
#include <utility> // Para move
|
||||
#include <vector> // Para vector
|
||||
#include <memory> // Para unique_ptr, shared_ptr
|
||||
#include <string> // Para string
|
||||
#include <utility> // Para move
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "animated_sprite.h" // Para AnimatedSprite
|
||||
|
||||
@@ -31,15 +31,15 @@ class Explosions {
|
||||
void render(); // Dibuja el objeto en pantalla
|
||||
|
||||
// --- Configuración ---
|
||||
void addTexture(int size, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation); // Añade texturas al objeto
|
||||
void add(int x, int y, int size); // Añade una explosión
|
||||
void addTexture(int size, const std::shared_ptr<Texture> &texture, const std::vector<std::string> &animation); // Añade texturas al objeto
|
||||
void add(int x, int y, int size); // Añade una explosión
|
||||
|
||||
private:
|
||||
// --- Variables de estado ---
|
||||
std::vector<ExplosionTexture> textures_; // Vector con las texturas a utilizar
|
||||
std::vector<std::unique_ptr<AnimatedSprite>> explosions_; // Lista con todas las explosiones
|
||||
std::vector<ExplosionTexture> textures_; // Vector con las texturas a utilizar
|
||||
std::vector<std::unique_ptr<AnimatedSprite>> explosions_; // Lista con todas las explosiones
|
||||
|
||||
// --- Métodos internos ---
|
||||
void freeExplosions(); // Vacía el vector de elementos finalizados
|
||||
auto getIndexBySize(int size) -> int; // Busca una textura a partir del tamaño
|
||||
void freeExplosions(); // Vacía el vector de elementos finalizados
|
||||
auto getIndexBySize(int size) -> int; // Busca una textura a partir del tamaño
|
||||
};
|
||||
483
source/fade.cpp
483
source/fade.cpp
@@ -27,32 +27,40 @@ Fade::~Fade() {
|
||||
|
||||
// Inicializa las variables
|
||||
void Fade::init() {
|
||||
type_ = FadeType::CENTER;
|
||||
mode_ = FadeMode::OUT;
|
||||
type_ = Type::CENTER;
|
||||
mode_ = Mode::OUT;
|
||||
counter_ = 0;
|
||||
r_ = 0;
|
||||
g_ = 0;
|
||||
b_ = 0;
|
||||
a_ = 0;
|
||||
post_duration_ = 0;
|
||||
post_counter_ = 0;
|
||||
post_start_time_ = 0;
|
||||
pre_duration_ = 0;
|
||||
pre_counter_ = 0;
|
||||
pre_start_time_ = 0;
|
||||
num_squares_width_ = param.fade.num_squares_width;
|
||||
num_squares_height_ = param.fade.num_squares_height;
|
||||
fade_random_squares_delay_ = param.fade.random_squares_delay;
|
||||
fade_random_squares_mult_ = param.fade.random_squares_mult;
|
||||
random_squares_duration_ = param.fade.random_squares_duration_ms; // Usar como duración en ms
|
||||
square_transition_duration_ = random_squares_duration_ / 4; // 25% del tiempo total para la transición individual
|
||||
random_squares_start_time_ = 0;
|
||||
}
|
||||
|
||||
// Resetea algunas variables para volver a hacer el fade sin perder ciertos parametros
|
||||
void Fade::reset() {
|
||||
state_ = FadeState::NOT_ENABLED;
|
||||
state_ = State::NOT_ENABLED;
|
||||
counter_ = 0;
|
||||
post_start_time_ = 0;
|
||||
pre_start_time_ = 0;
|
||||
}
|
||||
|
||||
// Pinta una transición en pantalla
|
||||
void Fade::render() {
|
||||
if (state_ != FadeState::NOT_ENABLED) {
|
||||
if (state_ != State::NOT_ENABLED) {
|
||||
// Para fade IN terminado, no renderizar (auto-desactivación visual)
|
||||
if (state_ == State::FINISHED && mode_ == Mode::IN) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_RenderTexture(renderer_, backbuffer_, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
@@ -60,13 +68,13 @@ void Fade::render() {
|
||||
// Actualiza las variables internas
|
||||
void Fade::update() {
|
||||
switch (state_) {
|
||||
case FadeState::PRE:
|
||||
case State::PRE:
|
||||
updatePreState();
|
||||
break;
|
||||
case FadeState::FADING:
|
||||
case State::FADING:
|
||||
updateFadingState();
|
||||
break;
|
||||
case FadeState::POST:
|
||||
case State::POST:
|
||||
updatePostState();
|
||||
break;
|
||||
default:
|
||||
@@ -75,25 +83,36 @@ void Fade::update() {
|
||||
}
|
||||
|
||||
void Fade::updatePreState() {
|
||||
if (pre_counter_ == pre_duration_) {
|
||||
state_ = FadeState::FADING;
|
||||
} else {
|
||||
pre_counter_++;
|
||||
// Sistema basado en tiempo únicamente
|
||||
Uint32 elapsed_time = SDL_GetTicks() - pre_start_time_;
|
||||
|
||||
if (elapsed_time >= static_cast<Uint32>(pre_duration_)) {
|
||||
state_ = State::FADING;
|
||||
// CRÍTICO: Reinicializar tiempo de inicio para tipos que usan random_squares_start_time_
|
||||
if (type_ == Type::RANDOM_SQUARE2 || type_ == Type::DIAGONAL) {
|
||||
random_squares_start_time_ = SDL_GetTicks();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Fade::updateFadingState() {
|
||||
switch (type_) {
|
||||
case FadeType::FULLSCREEN:
|
||||
case Type::FULLSCREEN:
|
||||
updateFullscreenFade();
|
||||
break;
|
||||
case FadeType::CENTER:
|
||||
case Type::CENTER:
|
||||
updateCenterFade();
|
||||
break;
|
||||
case FadeType::RANDOM_SQUARE:
|
||||
case Type::RANDOM_SQUARE:
|
||||
updateRandomSquareFade();
|
||||
break;
|
||||
case FadeType::VENETIAN:
|
||||
case Type::RANDOM_SQUARE2:
|
||||
updateRandomSquare2Fade();
|
||||
break;
|
||||
case Type::DIAGONAL:
|
||||
updateDiagonalFade();
|
||||
break;
|
||||
case Type::VENETIAN:
|
||||
updateVenetianFade();
|
||||
break;
|
||||
default:
|
||||
@@ -102,23 +121,36 @@ void Fade::updateFadingState() {
|
||||
counter_++;
|
||||
}
|
||||
|
||||
void Fade::changeToPostState() {
|
||||
state_ = State::POST;
|
||||
post_start_time_ = SDL_GetTicks();
|
||||
}
|
||||
|
||||
void Fade::updatePostState() {
|
||||
if (post_counter_ == post_duration_) {
|
||||
state_ = FadeState::FINISHED;
|
||||
} else {
|
||||
post_counter_++;
|
||||
// Sistema basado en tiempo únicamente
|
||||
Uint32 elapsed_time = SDL_GetTicks() - post_start_time_;
|
||||
|
||||
if (elapsed_time >= static_cast<Uint32>(post_duration_)) {
|
||||
state_ = State::FINISHED;
|
||||
}
|
||||
cleanBackbuffer(r_, g_, b_, a_);
|
||||
|
||||
// Mantener el alpha final correcto para cada tipo de fade
|
||||
Uint8 post_alpha = a_;
|
||||
if (type_ == Type::RANDOM_SQUARE2 || type_ == Type::DIAGONAL) {
|
||||
post_alpha = (mode_ == Mode::OUT) ? 255 : 0;
|
||||
}
|
||||
|
||||
cleanBackbuffer(r_, g_, b_, post_alpha);
|
||||
}
|
||||
|
||||
void Fade::updateFullscreenFade() {
|
||||
// Modifica la transparencia
|
||||
a_ = mode_ == FadeMode::OUT ? std::min(counter_ * 4, 255) : 255 - std::min(counter_ * 4, 255);
|
||||
a_ = mode_ == Mode::OUT ? std::min(counter_ * 4, 255) : 255 - std::min(counter_ * 4, 255);
|
||||
SDL_SetTextureAlphaMod(backbuffer_, a_);
|
||||
|
||||
// Comprueba si ha terminado
|
||||
if (counter_ >= 255 / 4) {
|
||||
state_ = FadeState::POST;
|
||||
changeToPostState();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,8 +159,8 @@ void Fade::updateCenterFade() {
|
||||
|
||||
// Comprueba si ha terminado
|
||||
if ((counter_ * 4) > param.game.height) {
|
||||
state_ = FadeState::POST;
|
||||
a_ = 255;
|
||||
changeToPostState();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,20 +183,243 @@ void Fade::drawCenterFadeRectangles() {
|
||||
}
|
||||
|
||||
void Fade::updateRandomSquareFade() {
|
||||
if (counter_ % fade_random_squares_delay_ == 0) {
|
||||
drawRandomSquares();
|
||||
}
|
||||
Uint32 elapsed_time = SDL_GetTicks() - random_squares_start_time_;
|
||||
float progress = static_cast<float>(elapsed_time) / random_squares_duration_;
|
||||
|
||||
value_ = calculateValue(0, (num_squares_width_ * num_squares_height_), (counter_ * fade_random_squares_mult_ / fade_random_squares_delay_));
|
||||
// Calcula cuántos cuadrados deberían estar activos
|
||||
int total_squares = num_squares_width_ * num_squares_height_;
|
||||
int active_squares = static_cast<int>(progress * total_squares);
|
||||
active_squares = std::min(active_squares, total_squares);
|
||||
|
||||
// Dibuja los cuadrados activos
|
||||
drawRandomSquares(active_squares);
|
||||
|
||||
value_ = calculateValue(0, total_squares, active_squares);
|
||||
|
||||
// Comprueba si ha terminado
|
||||
if (counter_ * fade_random_squares_mult_ / fade_random_squares_delay_ >=
|
||||
num_squares_width_ * num_squares_height_) {
|
||||
state_ = FadeState::POST;
|
||||
if (elapsed_time >= static_cast<Uint32>(random_squares_duration_)) {
|
||||
changeToPostState();
|
||||
}
|
||||
}
|
||||
|
||||
void Fade::drawRandomSquares() {
|
||||
void Fade::updateRandomSquare2Fade() {
|
||||
Uint32 elapsed_time = SDL_GetTicks() - random_squares_start_time_;
|
||||
|
||||
int total_squares = num_squares_width_ * num_squares_height_;
|
||||
|
||||
// Calcula el tiempo de activación: total - tiempo que necesitan los últimos cuadrados
|
||||
int activation_time = random_squares_duration_ - square_transition_duration_;
|
||||
activation_time = std::max(activation_time, square_transition_duration_); // Mínimo igual a la duración de transición
|
||||
|
||||
// Lógica diferente según el modo
|
||||
int squares_to_activate = 0;
|
||||
|
||||
if (mode_ == Mode::OUT) {
|
||||
// OUT: Activa cuadrados gradualmente
|
||||
if (elapsed_time < static_cast<Uint32>(activation_time)) {
|
||||
float activation_progress = static_cast<float>(elapsed_time) / activation_time;
|
||||
squares_to_activate = static_cast<int>(activation_progress * total_squares);
|
||||
} else {
|
||||
squares_to_activate = total_squares; // Activar todos
|
||||
}
|
||||
|
||||
// Activa nuevos cuadrados y guarda su tiempo de activación
|
||||
for (int i = 0; i < squares_to_activate && i < total_squares; ++i) {
|
||||
if (square_age_[i] == -1) {
|
||||
square_age_[i] = elapsed_time; // Guarda el tiempo de activación
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// IN: Todos los cuadrados empiezan activos desde el inicio
|
||||
squares_to_activate = total_squares;
|
||||
|
||||
// Activa cuadrados gradualmente con tiempo de inicio escalonado
|
||||
float activation_progress = static_cast<float>(elapsed_time) / activation_time;
|
||||
int squares_starting_transition = static_cast<int>(activation_progress * total_squares);
|
||||
|
||||
// Asegurar que al menos 1 cuadrado se active desde el primer frame
|
||||
squares_starting_transition = std::max(squares_starting_transition, 1);
|
||||
squares_starting_transition = std::min(squares_starting_transition, total_squares);
|
||||
|
||||
for (int i = 0; i < squares_starting_transition; ++i) {
|
||||
if (square_age_[i] == -1) {
|
||||
square_age_[i] = elapsed_time; // Empieza la transición a transparente
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawRandomSquares2();
|
||||
|
||||
value_ = calculateValue(0, total_squares, squares_to_activate);
|
||||
|
||||
// Comprueba si ha terminado - todos los cuadrados han completado su transición
|
||||
bool all_completed = (squares_to_activate >= total_squares);
|
||||
if (all_completed) {
|
||||
// Verificar que todos han completado su transición individual
|
||||
for (int i = 0; i < total_squares; ++i) {
|
||||
if (square_age_[i] >= 0) { // Cuadrado activado
|
||||
Uint32 square_elapsed = elapsed_time - square_age_[i];
|
||||
if (square_elapsed < static_cast<Uint32>(square_transition_duration_)) {
|
||||
all_completed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (all_completed) {
|
||||
// Pintar textura final: OUT opaca, IN transparente
|
||||
Uint8 final_alpha = (mode_ == Mode::OUT) ? 255 : 0;
|
||||
cleanBackbuffer(r_, g_, b_, final_alpha);
|
||||
changeToPostState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Fade::updateDiagonalFade() {
|
||||
Uint32 elapsed_time = SDL_GetTicks() - random_squares_start_time_;
|
||||
|
||||
int total_squares = num_squares_width_ * num_squares_height_;
|
||||
|
||||
// Calcula el tiempo de activación: total - tiempo que necesitan los últimos cuadrados
|
||||
int activation_time = random_squares_duration_ - square_transition_duration_;
|
||||
activation_time = std::max(activation_time, square_transition_duration_);
|
||||
|
||||
// Calcula cuántas diagonales deberían estar activas
|
||||
int max_diagonal = num_squares_width_ + num_squares_height_ - 1; // Número total de diagonales
|
||||
int active_diagonals = 0;
|
||||
|
||||
if (mode_ == Mode::OUT) {
|
||||
// OUT: Activa diagonales gradualmente desde esquina superior izquierda
|
||||
if (elapsed_time < static_cast<Uint32>(activation_time)) {
|
||||
float activation_progress = static_cast<float>(elapsed_time) / activation_time;
|
||||
active_diagonals = static_cast<int>(activation_progress * max_diagonal);
|
||||
} else {
|
||||
active_diagonals = max_diagonal; // Activar todas
|
||||
}
|
||||
|
||||
// Activa cuadrados por diagonales
|
||||
for (int diagonal = 0; diagonal < active_diagonals; ++diagonal) {
|
||||
activateDiagonal(diagonal, elapsed_time);
|
||||
}
|
||||
} else {
|
||||
// IN: Todas las diagonales empiezan activas, van desapareciendo
|
||||
active_diagonals = max_diagonal;
|
||||
|
||||
// Activa diagonales gradualmente para transición
|
||||
if (elapsed_time < static_cast<Uint32>(activation_time)) {
|
||||
float activation_progress = static_cast<float>(elapsed_time) / activation_time;
|
||||
int diagonals_starting_transition = static_cast<int>(activation_progress * max_diagonal);
|
||||
|
||||
for (int diagonal = 0; diagonal < diagonals_starting_transition; ++diagonal) {
|
||||
activateDiagonal(diagonal, elapsed_time);
|
||||
}
|
||||
} else {
|
||||
// Activar transición en todas las diagonales restantes
|
||||
for (int diagonal = 0; diagonal < max_diagonal; ++diagonal) {
|
||||
activateDiagonal(diagonal, elapsed_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawDiagonal();
|
||||
|
||||
value_ = calculateValue(0, total_squares, active_diagonals * (total_squares / max_diagonal));
|
||||
|
||||
// Comprueba si ha terminado - todas las diagonales activadas y último cuadrado completó transición
|
||||
bool all_completed = (active_diagonals >= max_diagonal);
|
||||
if (all_completed) {
|
||||
// Verificar que todos han completado su transición individual
|
||||
for (int i = 0; i < total_squares; ++i) {
|
||||
if (square_age_[i] >= 0) { // Cuadrado activado
|
||||
Uint32 square_elapsed = elapsed_time - square_age_[i];
|
||||
if (square_elapsed < static_cast<Uint32>(square_transition_duration_)) {
|
||||
all_completed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (all_completed) {
|
||||
// Pintar textura final: OUT opaca, IN transparente
|
||||
Uint8 final_alpha = (mode_ == Mode::OUT) ? 255 : 0;
|
||||
cleanBackbuffer(r_, g_, b_, final_alpha);
|
||||
changeToPostState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Fade::activateDiagonal(int diagonal_index, Uint32 current_time) {
|
||||
// Para cada diagonal, activamos los cuadrados que pertenecen a esa diagonal
|
||||
// Diagonal 0: (0,0)
|
||||
// Diagonal 1: (1,0), (0,1)
|
||||
// Diagonal 2: (2,0), (1,1), (0,2)
|
||||
// etc.
|
||||
|
||||
for (int x = 0; x < num_squares_width_; ++x) {
|
||||
int y = diagonal_index - x;
|
||||
|
||||
// Verificar que y está dentro de los límites
|
||||
if (y >= 0 && y < num_squares_height_) {
|
||||
// Convertir coordenadas (x,y) a índice en el vector
|
||||
int index = y * num_squares_width_ + x;
|
||||
|
||||
if (index >= 0 && index < static_cast<int>(square_age_.size())) {
|
||||
if (square_age_[index] == -1) {
|
||||
square_age_[index] = current_time; // Guarda el tiempo de activación
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Fade::drawDiagonal() {
|
||||
auto *temp = SDL_GetRenderTarget(renderer_);
|
||||
SDL_SetRenderTarget(renderer_, backbuffer_);
|
||||
|
||||
// CRÍTICO: Limpiar la textura antes de dibujar
|
||||
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0);
|
||||
SDL_RenderClear(renderer_);
|
||||
|
||||
SDL_BlendMode blend_mode;
|
||||
SDL_GetRenderDrawBlendMode(renderer_, &blend_mode);
|
||||
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND); // Usar BLEND para alpha
|
||||
|
||||
Uint32 current_time = SDL_GetTicks() - random_squares_start_time_;
|
||||
|
||||
// Lógica unificada: sobre textura transparente, pintar cuadrados según su estado
|
||||
for (size_t i = 0; i < square_.size(); ++i) {
|
||||
Uint8 current_alpha = 0;
|
||||
|
||||
if (square_age_[i] == -1) {
|
||||
// Cuadrado no activado
|
||||
if (mode_ == Mode::OUT) {
|
||||
current_alpha = 0; // OUT: transparente si no activado
|
||||
} else {
|
||||
current_alpha = a_; // IN: opaco si no activado
|
||||
}
|
||||
} else {
|
||||
// Cuadrado activado - calculamos progreso
|
||||
Uint32 square_elapsed = current_time - square_age_[i];
|
||||
float progress = std::min(static_cast<float>(square_elapsed) / square_transition_duration_, 1.0f);
|
||||
|
||||
if (mode_ == Mode::OUT) {
|
||||
current_alpha = static_cast<Uint8>(progress * a_); // 0 → 255
|
||||
} else {
|
||||
current_alpha = static_cast<Uint8>((1.0f - progress) * a_); // 255 → 0
|
||||
}
|
||||
}
|
||||
|
||||
if (current_alpha > 0) {
|
||||
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, current_alpha);
|
||||
SDL_RenderFillRect(renderer_, &square_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SetRenderDrawBlendMode(renderer_, blend_mode);
|
||||
SDL_SetRenderTarget(renderer_, temp);
|
||||
}
|
||||
|
||||
void Fade::drawRandomSquares(int active_count) {
|
||||
auto *temp = SDL_GetRenderTarget(renderer_);
|
||||
SDL_SetRenderTarget(renderer_, backbuffer_);
|
||||
|
||||
@@ -173,13 +428,56 @@ void Fade::drawRandomSquares() {
|
||||
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE);
|
||||
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_);
|
||||
|
||||
const int INDEX = std::min(counter_ / fade_random_squares_delay_,
|
||||
(num_squares_width_ * num_squares_height_) - 1);
|
||||
// Dibuja solo los cuadrados activos
|
||||
for (int i = 0; i < active_count && i < static_cast<int>(square_.size()); ++i) {
|
||||
SDL_RenderFillRect(renderer_, &square_[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < fade_random_squares_mult_; ++i) {
|
||||
const int INDEX2 = std::min(INDEX * fade_random_squares_mult_ + i,
|
||||
static_cast<int>(square_.size()) - 1);
|
||||
SDL_RenderFillRect(renderer_, &square_[INDEX2]);
|
||||
SDL_SetRenderDrawBlendMode(renderer_, blend_mode);
|
||||
SDL_SetRenderTarget(renderer_, temp);
|
||||
}
|
||||
|
||||
void Fade::drawRandomSquares2() {
|
||||
auto *temp = SDL_GetRenderTarget(renderer_);
|
||||
SDL_SetRenderTarget(renderer_, backbuffer_);
|
||||
|
||||
// CRÍTICO: Limpiar la textura antes de dibujar
|
||||
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0);
|
||||
SDL_RenderClear(renderer_);
|
||||
|
||||
SDL_BlendMode blend_mode;
|
||||
SDL_GetRenderDrawBlendMode(renderer_, &blend_mode);
|
||||
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND); // Usar BLEND para alpha
|
||||
|
||||
Uint32 current_time = SDL_GetTicks() - random_squares_start_time_;
|
||||
|
||||
// Lógica unificada: sobre textura transparente, pintar cuadrados según su estado
|
||||
for (size_t i = 0; i < square_.size(); ++i) {
|
||||
Uint8 current_alpha = 0;
|
||||
|
||||
if (square_age_[i] == -1) {
|
||||
// Cuadrado no activado
|
||||
if (mode_ == Mode::OUT) {
|
||||
current_alpha = 0; // OUT: transparente si no activado
|
||||
} else {
|
||||
current_alpha = a_; // IN: opaco si no activado
|
||||
}
|
||||
} else {
|
||||
// Cuadrado activado - calculamos progreso
|
||||
Uint32 square_elapsed = current_time - square_age_[i];
|
||||
float progress = std::min(static_cast<float>(square_elapsed) / square_transition_duration_, 1.0f);
|
||||
|
||||
if (mode_ == Mode::OUT) {
|
||||
current_alpha = static_cast<Uint8>(progress * a_); // 0 → 255
|
||||
} else {
|
||||
current_alpha = static_cast<Uint8>((1.0f - progress) * a_); // 255 → 0
|
||||
}
|
||||
}
|
||||
|
||||
if (current_alpha > 0) {
|
||||
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, current_alpha);
|
||||
SDL_RenderFillRect(renderer_, &square_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SetRenderDrawBlendMode(renderer_, blend_mode);
|
||||
@@ -192,7 +490,7 @@ void Fade::updateVenetianFade() {
|
||||
updateVenetianRectangles();
|
||||
calculateVenetianProgress();
|
||||
} else {
|
||||
state_ = FadeState::POST;
|
||||
changeToPostState();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,31 +531,30 @@ void Fade::calculateVenetianProgress() {
|
||||
// Activa el fade
|
||||
void Fade::activate() {
|
||||
// Si ya está habilitado, no hay que volverlo a activar
|
||||
if (state_ != FadeState::NOT_ENABLED) {
|
||||
if (state_ != State::NOT_ENABLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
state_ = FadeState::PRE;
|
||||
state_ = State::PRE;
|
||||
counter_ = 0;
|
||||
post_counter_ = 0;
|
||||
pre_counter_ = 0;
|
||||
pre_start_time_ = SDL_GetTicks();
|
||||
|
||||
switch (type_) {
|
||||
case FadeType::FULLSCREEN: {
|
||||
case Type::FULLSCREEN: {
|
||||
// Pinta el backbuffer_ de color sólido
|
||||
cleanBackbuffer(r_, g_, b_, 255);
|
||||
break;
|
||||
}
|
||||
|
||||
case FadeType::CENTER: {
|
||||
rect1_ = {0, 0, param.game.width, 0};
|
||||
rect2_ = {0, 0, param.game.width, 0};
|
||||
case Type::CENTER: {
|
||||
rect1_ = {.x = 0, .y = 0, .w = param.game.width, .h = 0};
|
||||
rect2_ = {.x = 0, .y = 0, .w = param.game.width, .h = 0};
|
||||
a_ = 64;
|
||||
break;
|
||||
}
|
||||
|
||||
case FadeType::RANDOM_SQUARE: {
|
||||
rect1_ = {0, 0, static_cast<float>(param.game.width / num_squares_width_), static_cast<float>(param.game.height / num_squares_height_)};
|
||||
case Type::RANDOM_SQUARE: {
|
||||
rect1_ = {.x = 0, .y = 0, .w = static_cast<float>(param.game.width / num_squares_width_), .h = static_cast<float>(param.game.height / num_squares_height_)};
|
||||
square_.clear();
|
||||
|
||||
// Añade los cuadrados al vector
|
||||
@@ -278,26 +575,96 @@ void Fade::activate() {
|
||||
}
|
||||
|
||||
// Limpia la textura
|
||||
a_ = mode_ == FadeMode::OUT ? 0 : 255;
|
||||
a_ = mode_ == Mode::OUT ? 0 : 255;
|
||||
cleanBackbuffer(r_, g_, b_, a_);
|
||||
|
||||
// Deja el color listo para usar
|
||||
a_ = mode_ == FadeMode::OUT ? 255 : 0;
|
||||
a_ = mode_ == Mode::OUT ? 255 : 0;
|
||||
|
||||
// Inicializa el tiempo de inicio
|
||||
random_squares_start_time_ = SDL_GetTicks();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case FadeType::VENETIAN: {
|
||||
case Type::RANDOM_SQUARE2: {
|
||||
rect1_ = {.x = 0, .y = 0, .w = static_cast<float>(param.game.width / num_squares_width_), .h = static_cast<float>(param.game.height / num_squares_height_)};
|
||||
square_.clear();
|
||||
square_age_.clear();
|
||||
|
||||
// Añade los cuadrados al vector
|
||||
for (int i = 0; i < num_squares_width_ * num_squares_height_; ++i) {
|
||||
rect1_.x = (i % num_squares_width_) * rect1_.w;
|
||||
rect1_.y = (i / num_squares_width_) * rect1_.h;
|
||||
square_.push_back(rect1_);
|
||||
square_age_.push_back(-1); // -1 indica cuadrado no activado aún
|
||||
}
|
||||
|
||||
// Desordena el vector de cuadrados y edades
|
||||
auto num = num_squares_width_ * num_squares_height_;
|
||||
while (num > 1) {
|
||||
auto num_arreu = rand() % num;
|
||||
SDL_FRect temp_rect = square_[num_arreu];
|
||||
int temp_age = square_age_[num_arreu];
|
||||
square_[num_arreu] = square_[num - 1];
|
||||
square_age_[num_arreu] = square_age_[num - 1];
|
||||
square_[num - 1] = temp_rect;
|
||||
square_age_[num - 1] = temp_age;
|
||||
num--;
|
||||
}
|
||||
|
||||
// Textura inicial: OUT transparente, IN opaca
|
||||
Uint8 initial_alpha = (mode_ == Mode::OUT) ? 0 : 255;
|
||||
cleanBackbuffer(r_, g_, b_, initial_alpha);
|
||||
|
||||
// Deja el color listo para usar (alpha target para los cuadrados)
|
||||
a_ = 255; // Siempre usar 255 como alpha target
|
||||
|
||||
// Inicializa el tiempo de inicio y recalcula la duración de transición
|
||||
random_squares_start_time_ = SDL_GetTicks();
|
||||
square_transition_duration_ = std::max(random_squares_duration_ / 4, 100); // Mínimo 100ms
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::DIAGONAL: {
|
||||
rect1_ = {.x = 0, .y = 0, .w = static_cast<float>(param.game.width / num_squares_width_), .h = static_cast<float>(param.game.height / num_squares_height_)};
|
||||
square_.clear();
|
||||
square_age_.clear();
|
||||
|
||||
// Añade los cuadrados al vector en orden (sin desordenar)
|
||||
for (int i = 0; i < num_squares_width_ * num_squares_height_; ++i) {
|
||||
rect1_.x = (i % num_squares_width_) * rect1_.w;
|
||||
rect1_.y = (i / num_squares_width_) * rect1_.h;
|
||||
square_.push_back(rect1_);
|
||||
square_age_.push_back(-1); // -1 indica cuadrado no activado aún
|
||||
}
|
||||
|
||||
// Textura inicial: OUT transparente, IN opaca
|
||||
Uint8 initial_alpha = (mode_ == Mode::OUT) ? 0 : 255;
|
||||
cleanBackbuffer(r_, g_, b_, initial_alpha);
|
||||
|
||||
// Deja el color listo para usar (alpha target para los cuadrados)
|
||||
a_ = 255; // Siempre usar 255 como alpha target
|
||||
|
||||
// Inicializa el tiempo de inicio y recalcula la duración de transición
|
||||
random_squares_start_time_ = SDL_GetTicks();
|
||||
square_transition_duration_ = std::max(random_squares_duration_ / 4, 100); // Mínimo 100ms
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::VENETIAN: {
|
||||
// Limpia la textura
|
||||
a_ = mode_ == FadeMode::OUT ? 0 : 255;
|
||||
a_ = mode_ == Mode::OUT ? 0 : 255;
|
||||
cleanBackbuffer(r_, g_, b_, a_);
|
||||
|
||||
// Deja el color listo para usar
|
||||
a_ = mode_ == FadeMode::OUT ? 255 : 0;
|
||||
a_ = mode_ == Mode::OUT ? 255 : 0;
|
||||
|
||||
// Añade los cuadrados al vector
|
||||
square_.clear();
|
||||
rect1_ = {0, 0, param.game.width, 0};
|
||||
rect1_ = {.x = 0, .y = 0, .w = param.game.width, .h = 0};
|
||||
const int MAX = param.game.height / param.fade.venetian_size;
|
||||
|
||||
for (int i = 0; i < MAX; ++i) {
|
||||
|
||||
102
source/fade.h
102
source/fade.h
@@ -6,30 +6,32 @@
|
||||
|
||||
struct Color;
|
||||
|
||||
// --- Enums ---
|
||||
enum class FadeType : Uint8 {
|
||||
FULLSCREEN = 0, // Fundido de pantalla completa
|
||||
CENTER = 1, // Fundido desde el centro
|
||||
RANDOM_SQUARE = 2, // Fundido con cuadrados aleatorios
|
||||
VENETIAN = 3, // Fundido tipo persiana veneciana
|
||||
};
|
||||
|
||||
enum class FadeMode : Uint8 {
|
||||
IN = 0, // Fundido de entrada
|
||||
OUT = 1, // Fundido de salida
|
||||
};
|
||||
|
||||
enum class FadeState : Uint8 {
|
||||
NOT_ENABLED = 0, // No activado
|
||||
PRE = 1, // Estado previo
|
||||
FADING = 2, // Fundiendo
|
||||
POST = 3, // Estado posterior
|
||||
FINISHED = 4, // Finalizado
|
||||
};
|
||||
|
||||
// --- Clase Fade: gestor de transiciones de fundido ---
|
||||
class Fade {
|
||||
public:
|
||||
// --- Enums ---
|
||||
enum class Type : Uint8 {
|
||||
FULLSCREEN = 0, // Fundido de pantalla completa
|
||||
CENTER = 1, // Fundido desde el centro
|
||||
RANDOM_SQUARE = 2, // Fundido con cuadrados aleatorios
|
||||
RANDOM_SQUARE2 = 3, // Fundido con cuadrados aleatorios (variante 2)
|
||||
DIAGONAL = 4, // Fundido diagonal desde esquina superior izquierda
|
||||
VENETIAN = 5, // Fundido tipo persiana veneciana
|
||||
};
|
||||
|
||||
enum class Mode : Uint8 {
|
||||
IN = 0, // Fundido de entrada
|
||||
OUT = 1, // Fundido de salida
|
||||
};
|
||||
|
||||
enum class State : Uint8 {
|
||||
NOT_ENABLED = 0, // No activado
|
||||
PRE = 1, // Estado previo
|
||||
FADING = 2, // Fundiendo
|
||||
POST = 3, // Estado posterior
|
||||
FINISHED = 4, // Finalizado
|
||||
};
|
||||
|
||||
// --- Constructores y destructor ---
|
||||
Fade();
|
||||
~Fade();
|
||||
@@ -41,17 +43,17 @@ class Fade {
|
||||
void activate(); // Activa el fade
|
||||
|
||||
// --- Configuración ---
|
||||
void setColor(Uint8 r, Uint8 g, Uint8 b); // Establece el color RGB del fade
|
||||
void setColor(Color color); // Establece el color del fade
|
||||
void setType(FadeType type) { type_ = type; } // Establece el tipo de fade
|
||||
void setMode(FadeMode mode) { mode_ = mode; } // Establece el modo de fade
|
||||
void setPostDuration(int value) { post_duration_ = value; } // Duración posterior al fade
|
||||
void setPreDuration(int value) { pre_duration_ = value; } // Duración previa al fade
|
||||
void setColor(Uint8 r, Uint8 g, Uint8 b); // Establece el color RGB del fade
|
||||
void setColor(Color color); // Establece el color del fade
|
||||
void setType(Type type) { type_ = type; } // Establece el tipo de fade
|
||||
void setMode(Mode mode) { mode_ = mode; } // Establece el modo de fade
|
||||
void setPostDuration(int value) { post_duration_ = value; } // Duración posterior al fade en milisegundos
|
||||
void setPreDuration(int value) { pre_duration_ = value; } // Duración previa al fade en milisegundos
|
||||
|
||||
// --- Getters ---
|
||||
[[nodiscard]] auto getValue() const -> int { return value_; }
|
||||
[[nodiscard]] auto isEnabled() const -> bool { return state_ != FadeState::NOT_ENABLED; }
|
||||
[[nodiscard]] auto hasEnded() const -> bool { return state_ == FadeState::FINISHED; }
|
||||
[[nodiscard]] auto isEnabled() const -> bool { return state_ != State::NOT_ENABLED; }
|
||||
[[nodiscard]] auto hasEnded() const -> bool { return state_ == State::FINISHED; }
|
||||
|
||||
private:
|
||||
// --- Objetos y punteros ---
|
||||
@@ -59,22 +61,24 @@ class Fade {
|
||||
SDL_Texture *backbuffer_; // Backbuffer para efectos
|
||||
|
||||
// --- Variables de estado ---
|
||||
std::vector<SDL_FRect> square_; // Vector de cuadrados
|
||||
SDL_FRect rect1_, rect2_; // Rectángulos para efectos
|
||||
FadeType type_; // Tipo de fade
|
||||
FadeMode mode_; // Modo de fade
|
||||
FadeState state_ = FadeState::NOT_ENABLED; // Estado actual
|
||||
Uint16 counter_; // Contador interno
|
||||
Uint8 r_, g_, b_, a_; // Color del fade (RGBA)
|
||||
int num_squares_width_; // Cuadrados en horizontal
|
||||
int num_squares_height_; // Cuadrados en vertical
|
||||
int fade_random_squares_delay_; // Delay entre cuadrados
|
||||
int fade_random_squares_mult_; // Cuadrados por paso
|
||||
int post_duration_ = 0; // Duración posterior
|
||||
int post_counter_ = 0; // Contador posterior
|
||||
int pre_duration_ = 0; // Duración previa
|
||||
int pre_counter_ = 0; // Contador previo
|
||||
int value_ = 0; // Estado del fade (0-100)
|
||||
std::vector<SDL_FRect> square_; // Vector de cuadrados
|
||||
std::vector<int> square_age_; // Edad de cada cuadrado (para RANDOM_SQUARE2)
|
||||
SDL_FRect rect1_, rect2_; // Rectángulos para efectos
|
||||
Type type_; // Tipo de fade
|
||||
Mode mode_; // Modo de fade
|
||||
State state_ = State::NOT_ENABLED; // Estado actual
|
||||
Uint16 counter_; // Contador interno
|
||||
Uint8 r_, g_, b_, a_; // Color del fade (RGBA)
|
||||
int num_squares_width_; // Cuadrados en horizontal
|
||||
int num_squares_height_; // Cuadrados en vertical
|
||||
Uint32 random_squares_start_time_; // Tiempo de inicio del fade de cuadrados
|
||||
int random_squares_duration_; // Duración total en milisegundos
|
||||
int square_transition_duration_; // Duración de transición de cada cuadrado en ms
|
||||
int post_duration_ = 0; // Duración posterior en milisegundos
|
||||
Uint32 post_start_time_ = 0; // Tiempo de inicio del estado POST
|
||||
int pre_duration_ = 0; // Duración previa en milisegundos
|
||||
Uint32 pre_start_time_ = 0; // Tiempo de inicio del estado PRE
|
||||
int value_ = 0; // Estado del fade (0-100)
|
||||
|
||||
// --- Inicialización y limpieza ---
|
||||
void init(); // Inicializa variables
|
||||
@@ -87,17 +91,23 @@ class Fade {
|
||||
void updatePreState(); // Actualiza el estado previo al fade
|
||||
void updateFadingState(); // Actualiza el estado durante el fade
|
||||
void updatePostState(); // Actualiza el estado posterior al fade
|
||||
void changeToPostState(); // Cambia al estado POST e inicializa el tiempo
|
||||
|
||||
// --- Efectos de fundido (fade) ---
|
||||
void updateFullscreenFade(); // Actualiza el fundido de pantalla completa
|
||||
void updateCenterFade(); // Actualiza el fundido desde el centro
|
||||
void updateRandomSquareFade(); // Actualiza el fundido con cuadrados aleatorios
|
||||
void updateRandomSquare2Fade(); // Actualiza el fundido con cuadrados aleatorios (variante 2)
|
||||
void updateDiagonalFade(); // Actualiza el fundido diagonal
|
||||
void updateVenetianFade(); // Actualiza el fundido tipo persiana veneciana
|
||||
void updateVenetianRectangles(); // Actualiza los rectángulos del efecto veneciano
|
||||
void calculateVenetianProgress(); // Calcula el progreso del efecto veneciano
|
||||
|
||||
// --- Dibujo de efectos visuales ---
|
||||
void drawCenterFadeRectangles(); // Dibuja los rectángulos del fundido central
|
||||
void drawRandomSquares(); // Dibuja los cuadrados aleatorios del fundido
|
||||
void drawRandomSquares(int active_count = -1); // Dibuja los cuadrados aleatorios del fundido
|
||||
void drawRandomSquares2(); // Dibuja los cuadrados con transición de color (RANDOM_SQUARE2)
|
||||
void drawDiagonal(); // Dibuja los cuadrados con patrón diagonal
|
||||
void activateDiagonal(int diagonal_index, Uint32 current_time); // Activa una diagonal específica
|
||||
void drawVenetianBlinds(); // Dibuja las persianas venecianas del fundido
|
||||
};
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
constexpr int ZOOM_FACTOR = 5;
|
||||
constexpr int FLASH_DELAY = 3;
|
||||
constexpr int FLASH_LENGHT = FLASH_DELAY + 3;
|
||||
constexpr int FLASH_LENGTH = FLASH_DELAY + 3;
|
||||
|
||||
// Constructor
|
||||
GameLogo::GameLogo(int x, int y)
|
||||
@@ -34,7 +34,7 @@ GameLogo::GameLogo(int x, int y)
|
||||
|
||||
// Inicializa las variables
|
||||
void GameLogo::init() {
|
||||
const auto XP = x_ - coffee_texture_->getWidth() / 2;
|
||||
const auto XP = x_ - (coffee_texture_->getWidth() / 2);
|
||||
const auto DESP = getInitialVerticalDesp();
|
||||
|
||||
// Configura texturas
|
||||
@@ -236,7 +236,7 @@ void GameLogo::finishArcadeEditionMoving() {
|
||||
|
||||
void GameLogo::playTitleEffects() {
|
||||
Audio::get()->playSound("title.wav");
|
||||
Screen::get()->flash(Color(0xFF, 0xFF, 0xFF), FLASH_LENGHT, FLASH_DELAY);
|
||||
Screen::get()->flash(Color(0xFF, 0xFF, 0xFF), FLASH_LENGTH, FLASH_DELAY);
|
||||
Screen::get()->shake();
|
||||
}
|
||||
|
||||
|
||||
@@ -36,19 +36,19 @@ class GameLogo {
|
||||
struct Shake {
|
||||
int desp = 1; // Pixels de desplazamiento para agitar la pantalla en el eje x
|
||||
int delay = 2; // Retraso entre cada desplazamiento de la pantalla al agitarse
|
||||
int lenght = 8; // Cantidad de desplazamientos a realizar
|
||||
int remaining = lenght; // Cantidad de desplazamientos pendientes a realizar
|
||||
int length = 8; // Cantidad de desplazamientos a realizar
|
||||
int remaining = length; // Cantidad de desplazamientos pendientes a realizar
|
||||
int counter = delay; // Contador para el retraso
|
||||
int origin = 0; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento
|
||||
|
||||
Shake() = default;
|
||||
Shake(int d, int de, int l, int o)
|
||||
: desp(d), delay(de), lenght(l), remaining(l), counter(de), origin(o) {}
|
||||
: desp(d), delay(de), length(l), remaining(l), counter(de), origin(o) {}
|
||||
|
||||
void init(int d, int de, int l, int o) {
|
||||
desp = d;
|
||||
delay = de;
|
||||
lenght = l;
|
||||
length = l;
|
||||
remaining = l;
|
||||
counter = de;
|
||||
origin = o;
|
||||
@@ -71,10 +71,10 @@ class GameLogo {
|
||||
Shake shake_; // Efecto de agitación
|
||||
Status coffee_crisis_status_ = Status::DISABLED; // Estado de "COFFEE CRISIS"
|
||||
Status arcade_edition_status_ = Status::DISABLED; // Estado de "ARCADE EDITION"
|
||||
float x_; // Posición X del logo
|
||||
float y_; // Posición Y del logo
|
||||
float zoom_ = 1.0F; // Zoom aplicado al texto "ARCADE EDITION"
|
||||
int post_finished_counter_ = 1; // Contador final tras animaciones
|
||||
float x_; // Posición X del logo
|
||||
float y_; // Posición Y del logo
|
||||
float zoom_ = 1.0F; // Zoom aplicado al texto "ARCADE EDITION"
|
||||
int post_finished_counter_ = 1; // Contador final tras animaciones
|
||||
|
||||
// --- Inicialización ---
|
||||
void init(); // Inicializa las variables
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
|
||||
// --- Namespace GlobalEvents: maneja eventos globales del juego ---
|
||||
namespace GlobalEvents {
|
||||
// --- Funciones ---
|
||||
void handle(const SDL_Event &event); // Comprueba los eventos que se pueden producir en cualquier sección del juego
|
||||
// --- Funciones ---
|
||||
void handle(const SDL_Event &event); // Comprueba los eventos que se pueden producir en cualquier sección del juego
|
||||
} // namespace GlobalEvents
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "global_inputs.h"
|
||||
|
||||
#include <algorithm> // Para std::ranges::any_of
|
||||
#include <functional> // Para function
|
||||
#include <memory> // Para allocator, shared_ptr
|
||||
#include <string> // Para operator+, char_traits, string, to_string
|
||||
@@ -145,11 +146,11 @@ auto checkServiceButton() -> bool {
|
||||
}
|
||||
|
||||
// Mandos
|
||||
for (auto gamepad : Input::get()->getGamepads()) {
|
||||
if (Input::get()->checkAction(Input::Action::SERVICE, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||
toggleServiceMenu();
|
||||
return true;
|
||||
}
|
||||
if (std::ranges::any_of(Input::get()->getGamepads(), [](const auto& gamepad) {
|
||||
return Input::get()->checkAction(Input::Action::SERVICE, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad);
|
||||
})) {
|
||||
toggleServiceMenu();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -176,14 +177,13 @@ auto checkSystemInputs() -> bool {
|
||||
#endif
|
||||
};
|
||||
|
||||
for (const auto& [action, func] : ACTIONS) {
|
||||
if (Input::get()->checkAction(action, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
|
||||
func();
|
||||
return std::ranges::any_of(ACTIONS, [](const auto& pair) {
|
||||
if (Input::get()->checkAction(pair.first, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
|
||||
pair.second();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
// Comprueba el resto de entradas
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
// --- Namespace GlobalInputs: gestiona inputs globales del juego ---
|
||||
namespace GlobalInputs {
|
||||
// --- Funciones ---
|
||||
auto check() -> bool; // Comprueba los inputs que se pueden introducir en cualquier sección del juego
|
||||
// --- Funciones ---
|
||||
auto check() -> bool; // Comprueba los inputs que se pueden introducir en cualquier sección del juego
|
||||
} // namespace GlobalInputs
|
||||
@@ -11,8 +11,8 @@
|
||||
struct Hit {
|
||||
public:
|
||||
// --- Constructor ---
|
||||
Hit() = delete; // Elimina el constructor por defecto para obligar a pasar una textura
|
||||
explicit Hit(std::shared_ptr<Texture> texture) // Constructor con textura obligatoria
|
||||
Hit() = delete; // Elimina el constructor por defecto para obligar a pasar una textura
|
||||
explicit Hit(const std::shared_ptr<Texture>& texture) // Constructor con textura obligatoria
|
||||
: sprite_(std::make_unique<Sprite>(texture)) {}
|
||||
|
||||
// --- Métodos principales ---
|
||||
|
||||
@@ -36,21 +36,21 @@ void Input::bindKey(Action action, SDL_Scancode code) {
|
||||
}
|
||||
|
||||
// Asigna inputs a botones del mando
|
||||
void Input::bindGameControllerButton(std::shared_ptr<Gamepad> gamepad, Action action, SDL_GamepadButton button) {
|
||||
void Input::bindGameControllerButton(const std::shared_ptr<Gamepad> &gamepad, Action action, SDL_GamepadButton button) {
|
||||
if (gamepad != nullptr) {
|
||||
gamepad->bindings[action].button = button;
|
||||
}
|
||||
}
|
||||
|
||||
// Asigna inputs a botones del mando
|
||||
void Input::bindGameControllerButton(std::shared_ptr<Gamepad> gamepad, Action action_target, Action action_source) {
|
||||
void Input::bindGameControllerButton(const std::shared_ptr<Gamepad> &gamepad, Action action_target, Action action_source) {
|
||||
if (gamepad != nullptr) {
|
||||
gamepad->bindings[action_target].button = gamepad->bindings[action_source].button;
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba si alguna acción está activa
|
||||
auto Input::checkAction(Action action, bool repeat, bool check_keyboard, std::shared_ptr<Gamepad> gamepad) -> bool {
|
||||
auto Input::checkAction(Action action, bool repeat, bool check_keyboard, const std::shared_ptr<Gamepad> &gamepad) -> bool {
|
||||
bool success_keyboard = false;
|
||||
bool success_controller = false;
|
||||
|
||||
@@ -82,7 +82,7 @@ auto Input::checkAction(Action action, bool repeat, bool check_keyboard, std::sh
|
||||
}
|
||||
|
||||
// Comprueba si hay almenos una acción activa
|
||||
auto Input::checkAnyInput(bool check_keyboard, std::shared_ptr<Gamepad> gamepad) -> bool {
|
||||
auto Input::checkAnyInput(bool check_keyboard, const std::shared_ptr<Gamepad> &gamepad) -> bool {
|
||||
// Obtenemos el número total de acciones posibles para iterar sobre ellas.
|
||||
|
||||
// --- Comprobación del Teclado ---
|
||||
@@ -122,7 +122,7 @@ auto Input::checkAnyButton(bool repeat) -> bool {
|
||||
}
|
||||
|
||||
// Comprueba los mandos
|
||||
for (auto gamepad : gamepads_) {
|
||||
for (const auto &gamepad : gamepads_) {
|
||||
if (checkAction(bi, repeat, DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||
return true;
|
||||
}
|
||||
@@ -136,7 +136,9 @@ auto Input::checkAnyButton(bool repeat) -> bool {
|
||||
auto Input::gameControllerFound() const -> bool { return !gamepads_.empty(); }
|
||||
|
||||
// Obten el nombre de un mando de juego
|
||||
auto Input::getControllerName(std::shared_ptr<Gamepad> gamepad) -> std::string { return gamepad == nullptr ? std::string() : gamepad->name; }
|
||||
auto Input::getControllerName(const std::shared_ptr<Gamepad> &gamepad) -> std::string {
|
||||
return gamepad == nullptr ? std::string() : gamepad->name;
|
||||
}
|
||||
|
||||
// Obtiene la lista de nombres de mandos
|
||||
auto Input::getControllerNames() const -> std::vector<std::string> {
|
||||
@@ -170,8 +172,8 @@ auto Input::getGamepadByName(const std::string &name) const -> std::shared_ptr<I
|
||||
}
|
||||
|
||||
// Obtiene el SDL_GamepadButton asignado a un action
|
||||
auto Input::getControllerBinding(std::shared_ptr<Gamepad> gamepad, Action action) -> SDL_GamepadButton {
|
||||
return gamepad->bindings[action].button;
|
||||
auto Input::getControllerBinding(const std::shared_ptr<Gamepad> &gamepad, Action action) -> SDL_GamepadButton {
|
||||
return static_cast<SDL_GamepadButton>(gamepad->bindings[action].button);
|
||||
}
|
||||
|
||||
// Convierte un InputAction a std::string
|
||||
@@ -206,7 +208,7 @@ auto Input::stringToInput(const std::string &name) -> Action {
|
||||
}
|
||||
|
||||
// Comprueba el eje del mando
|
||||
auto Input::checkAxisInput(Action action, std::shared_ptr<Gamepad> gamepad, bool repeat) -> bool {
|
||||
auto Input::checkAxisInput(Action action, const std::shared_ptr<Gamepad> &gamepad, bool repeat) -> bool {
|
||||
// Umbral para considerar el eje como activo
|
||||
bool axis_active_now = false;
|
||||
|
||||
@@ -248,16 +250,16 @@ auto Input::checkAxisInput(Action action, std::shared_ptr<Gamepad> gamepad, bool
|
||||
}
|
||||
|
||||
// Comprueba los triggers del mando como botones digitales
|
||||
auto Input::checkTriggerInput(Action action, std::shared_ptr<Gamepad> gamepad, bool repeat) -> bool {
|
||||
auto Input::checkTriggerInput(Action action, const std::shared_ptr<Gamepad> &gamepad, bool repeat) -> bool {
|
||||
// Solo manejamos botones específicos que pueden ser triggers
|
||||
if (gamepad->bindings[action].button != SDL_GAMEPAD_BUTTON_INVALID) {
|
||||
if (gamepad->bindings[action].button != static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID)) {
|
||||
// Solo procesamos L2 y R2 como triggers
|
||||
SDL_GamepadButton button = gamepad->bindings[action].button;
|
||||
|
||||
int button = gamepad->bindings[action].button;
|
||||
|
||||
// Verificar si el botón mapeado corresponde a un trigger virtual
|
||||
// (Para esto necesitamos valores especiales que representen L2/R2 como botones)
|
||||
bool trigger_active_now = false;
|
||||
|
||||
|
||||
// Usamos constantes especiales para L2 y R2 como botones
|
||||
if (button == TRIGGER_L2_AS_BUTTON) { // L2 como botón
|
||||
Sint16 trigger_value = SDL_GetGamepadAxis(gamepad->pad, SDL_GAMEPAD_AXIS_LEFT_TRIGGER);
|
||||
@@ -268,15 +270,15 @@ auto Input::checkTriggerInput(Action action, std::shared_ptr<Gamepad> gamepad, b
|
||||
} else {
|
||||
return false; // No es un trigger
|
||||
}
|
||||
|
||||
|
||||
// Referencia al binding correspondiente
|
||||
auto &binding = gamepad->bindings[action];
|
||||
|
||||
|
||||
if (repeat) {
|
||||
// Si se permite repetir, simplemente devolvemos el estado actual
|
||||
return trigger_active_now;
|
||||
}
|
||||
|
||||
|
||||
// Si no se permite repetir, aplicamos la lógica de transición
|
||||
if (trigger_active_now && !binding.trigger_active) {
|
||||
// Transición de inactivo a activo
|
||||
@@ -287,17 +289,17 @@ auto Input::checkTriggerInput(Action action, std::shared_ptr<Gamepad> gamepad, b
|
||||
// Transición de activo a inactivo
|
||||
binding.trigger_active = false;
|
||||
}
|
||||
|
||||
|
||||
// Mantener el estado actual
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Input::addGamepadMappingsFromFile() {
|
||||
if (SDL_AddGamepadMappingsFromFile(gamepad_mappings_file_.c_str()) < 0) {
|
||||
std::cout << "Error, could not load " << gamepad_mappings_file_.c_str() << " file: " << SDL_GetError() << std::endl;
|
||||
std::cout << "Error, could not load " << gamepad_mappings_file_.c_str() << " file: " << SDL_GetError() << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,9 +352,9 @@ void Input::update() {
|
||||
}
|
||||
|
||||
// --- MANDOS ---
|
||||
for (auto gamepad : gamepads_) {
|
||||
for (const auto &gamepad : gamepads_) {
|
||||
for (auto &binding : gamepad->bindings) {
|
||||
bool button_is_down_now = static_cast<int>(SDL_GetGamepadButton(gamepad->pad, binding.second.button)) != 0;
|
||||
bool button_is_down_now = static_cast<int>(SDL_GetGamepadButton(gamepad->pad, static_cast<SDL_GamepadButton>(binding.second.button))) != 0;
|
||||
|
||||
// El estado .is_held del fotograma anterior nos sirve para saber si es un pulso nuevo
|
||||
binding.second.just_pressed = button_is_down_now && !binding.second.is_held;
|
||||
@@ -374,13 +376,13 @@ auto Input::handleEvent(const SDL_Event &event) -> std::string {
|
||||
auto Input::addGamepad(int device_index) -> std::string {
|
||||
SDL_Gamepad *pad = SDL_OpenGamepad(device_index);
|
||||
if (pad == nullptr) {
|
||||
std::cerr << "Error al abrir el gamepad: " << SDL_GetError() << std::endl;
|
||||
std::cerr << "Error al abrir el gamepad: " << SDL_GetError() << '\n';
|
||||
return {};
|
||||
}
|
||||
|
||||
auto gamepad = std::make_shared<Gamepad>(pad);
|
||||
auto name = gamepad->name;
|
||||
std::cout << "Gamepad connected (" << name << ")" << std::endl;
|
||||
std::cout << "Gamepad connected (" << name << ")" << '\n';
|
||||
applyGamepadConfig(gamepad);
|
||||
saveGamepadConfigFromGamepad(gamepad);
|
||||
gamepads_.push_back(std::move(gamepad));
|
||||
@@ -388,23 +390,23 @@ auto Input::addGamepad(int device_index) -> std::string {
|
||||
}
|
||||
|
||||
auto Input::removeGamepad(SDL_JoystickID id) -> std::string {
|
||||
auto it = std::find_if(gamepads_.begin(), gamepads_.end(), [id](const std::shared_ptr<Gamepad> &gamepad) {
|
||||
auto it = std::ranges::find_if(gamepads_, [id](const std::shared_ptr<Gamepad> &gamepad) {
|
||||
return gamepad->instance_id == id;
|
||||
});
|
||||
|
||||
if (it != gamepads_.end()) {
|
||||
std::string name = (*it)->name;
|
||||
std::cout << "Gamepad disconnected (" << name << ")" << std::endl;
|
||||
std::cout << "Gamepad disconnected (" << name << ")" << '\n';
|
||||
gamepads_.erase(it);
|
||||
return name + " DISCONNECTED";
|
||||
}
|
||||
std::cerr << "No se encontró el gamepad con ID " << id << std::endl;
|
||||
std::cerr << "No se encontró el gamepad con ID " << id << '\n';
|
||||
return {};
|
||||
}
|
||||
|
||||
void Input::printConnectedGamepads() const {
|
||||
if (gamepads_.empty()) {
|
||||
std::cout << "No hay gamepads conectados." << std::endl;
|
||||
std::cout << "No hay gamepads conectados." << '\n';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -412,7 +414,7 @@ void Input::printConnectedGamepads() const {
|
||||
for (const auto &gamepad : gamepads_) {
|
||||
std::string name = gamepad->name.empty() ? "Desconocido" : gamepad->name;
|
||||
std::cout << " - ID: " << gamepad->instance_id
|
||||
<< ", Nombre: " << name << ")" << std::endl;
|
||||
<< ", Nombre: " << name << ")" << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,13 +434,13 @@ void Input::applyGamepadConfig(std::shared_ptr<Gamepad> gamepad) {
|
||||
}
|
||||
|
||||
// --- Buscar configuración por RUTA (path) ---
|
||||
auto config_it = std::find_if(gamepad_configs_.begin(), gamepad_configs_.end(), [&gamepad](const GamepadConfig &config) {
|
||||
auto config_it = std::ranges::find_if(gamepad_configs_, [&gamepad](const GamepadConfig &config) {
|
||||
return config.path == gamepad->path;
|
||||
});
|
||||
|
||||
if (config_it != gamepad_configs_.end()) {
|
||||
// Se encontró una configuración específica para este puerto/dispositivo. La aplicamos.
|
||||
std::cout << "Applying custom config for gamepad at path: " << gamepad->path << std::endl;
|
||||
std::cout << "Applying custom config for gamepad at path: " << gamepad->path << '\n';
|
||||
for (const auto &[action, button] : config_it->bindings) {
|
||||
if (gamepad->bindings.find(action) != gamepad->bindings.end()) {
|
||||
gamepad->bindings[action].button = button;
|
||||
@@ -454,7 +456,7 @@ void Input::saveGamepadConfigFromGamepad(std::shared_ptr<Gamepad> gamepad) {
|
||||
}
|
||||
|
||||
// --- CAMBIO CLAVE: Buscar si ya existe una configuración por RUTA (path) ---
|
||||
auto config_it = std::find_if(gamepad_configs_.begin(), gamepad_configs_.end(), [&gamepad](const GamepadConfig &config) {
|
||||
auto config_it = std::ranges::find_if(gamepad_configs_, [&gamepad](const GamepadConfig &config) {
|
||||
return config.path == gamepad->path;
|
||||
});
|
||||
|
||||
@@ -464,7 +466,7 @@ void Input::saveGamepadConfigFromGamepad(std::shared_ptr<Gamepad> gamepad) {
|
||||
|
||||
// Copiar todos los bindings actuales del gamepad
|
||||
for (const auto &[action, buttonState] : gamepad->bindings) {
|
||||
new_config.bindings[action] = buttonState.button;
|
||||
new_config.bindings[action] = static_cast<SDL_GamepadButton>(buttonState.button);
|
||||
}
|
||||
|
||||
if (config_it != gamepad_configs_.end()) {
|
||||
@@ -487,7 +489,7 @@ void Input::setGamepadConfigsFile(const std::string &filename) {
|
||||
|
||||
// Método para obtener configuración de un gamepad específico (opcional)
|
||||
auto Input::getGamepadConfig(const std::string &gamepad_name) -> GamepadConfig * {
|
||||
auto config_it = std::find_if(gamepad_configs_.begin(), gamepad_configs_.end(), [&gamepad_name](const GamepadConfig &config) {
|
||||
auto config_it = std::ranges::find_if(gamepad_configs_, [&gamepad_name](const GamepadConfig &config) {
|
||||
return config.name == gamepad_name;
|
||||
});
|
||||
|
||||
@@ -496,7 +498,7 @@ auto Input::getGamepadConfig(const std::string &gamepad_name) -> GamepadConfig *
|
||||
|
||||
// Método para eliminar configuración de gamepad (opcional)
|
||||
auto Input::removeGamepadConfig(const std::string &gamepad_name) -> bool {
|
||||
auto config_it = std::find_if(gamepad_configs_.begin(), gamepad_configs_.end(), [&gamepad_name](const GamepadConfig &config) {
|
||||
auto config_it = std::ranges::find_if(gamepad_configs_, [&gamepad_name](const GamepadConfig &config) {
|
||||
return config.name == gamepad_name;
|
||||
});
|
||||
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
class Input {
|
||||
public:
|
||||
// --- Constantes ---
|
||||
static constexpr bool ALLOW_REPEAT = true; // Permite repetición
|
||||
static constexpr bool DO_NOT_ALLOW_REPEAT = false; // No permite repetición
|
||||
static constexpr bool CHECK_KEYBOARD = true; // Comprueba teclado
|
||||
static constexpr bool DO_NOT_CHECK_KEYBOARD = false; // No comprueba teclado
|
||||
static constexpr SDL_GamepadButton TRIGGER_L2_AS_BUTTON = static_cast<SDL_GamepadButton>(100); // L2 como botón
|
||||
static constexpr SDL_GamepadButton TRIGGER_R2_AS_BUTTON = static_cast<SDL_GamepadButton>(101); // R2 como botón
|
||||
static constexpr bool ALLOW_REPEAT = true; // Permite repetición
|
||||
static constexpr bool DO_NOT_ALLOW_REPEAT = false; // No permite repetición
|
||||
static constexpr bool CHECK_KEYBOARD = true; // Comprueba teclado
|
||||
static constexpr bool DO_NOT_CHECK_KEYBOARD = false; // No comprueba teclado
|
||||
static constexpr int TRIGGER_L2_AS_BUTTON = 100; // L2 como botón
|
||||
static constexpr int TRIGGER_R2_AS_BUTTON = 101; // R2 como botón
|
||||
|
||||
// --- Tipos ---
|
||||
using Action = InputAction; // Alias para mantener compatibilidad
|
||||
@@ -36,14 +36,14 @@ class Input {
|
||||
};
|
||||
|
||||
struct ButtonState {
|
||||
SDL_GamepadButton button; // GameControllerButton asociado
|
||||
bool is_held; // Está pulsada ahora mismo
|
||||
bool just_pressed; // Se acaba de pulsar en este fotograma
|
||||
bool axis_active; // Estado del eje
|
||||
bool trigger_active; // Estado del trigger como botón digital
|
||||
int button; // GameControllerButton asociado
|
||||
bool is_held; // Está pulsada ahora mismo
|
||||
bool just_pressed; // Se acaba de pulsar en este fotograma
|
||||
bool axis_active; // Estado del eje
|
||||
bool trigger_active{false}; // Estado del trigger como botón digital
|
||||
|
||||
ButtonState(SDL_GamepadButton btn = SDL_GAMEPAD_BUTTON_INVALID, bool is_held = false, bool just_pressed = false, bool axis_act = false)
|
||||
: button(btn), is_held(is_held), just_pressed(just_pressed), axis_active(axis_act), trigger_active(false) {}
|
||||
ButtonState(int btn = static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID), bool is_held = false, bool just_pressed = false, bool axis_act = false)
|
||||
: button(btn), is_held(is_held), just_pressed(just_pressed), axis_active(axis_act) {}
|
||||
};
|
||||
|
||||
struct Keyboard {
|
||||
@@ -104,23 +104,23 @@ class Input {
|
||||
path(std::string(SDL_GetGamepadPath(pad))),
|
||||
bindings{
|
||||
// Movimiento del jugador
|
||||
{Action::UP, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_UP)},
|
||||
{Action::DOWN, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_DOWN)},
|
||||
{Action::LEFT, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_LEFT)},
|
||||
{Action::RIGHT, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_RIGHT)},
|
||||
{Action::UP, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_UP))},
|
||||
{Action::DOWN, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_DOWN))},
|
||||
{Action::LEFT, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_LEFT))},
|
||||
{Action::RIGHT, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_RIGHT))},
|
||||
|
||||
// Disparo del jugador
|
||||
{Action::FIRE_LEFT, ButtonState(SDL_GAMEPAD_BUTTON_WEST)},
|
||||
{Action::FIRE_CENTER, ButtonState(SDL_GAMEPAD_BUTTON_NORTH)},
|
||||
{Action::FIRE_RIGHT, ButtonState(SDL_GAMEPAD_BUTTON_EAST)},
|
||||
{Action::FIRE_LEFT, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_WEST))},
|
||||
{Action::FIRE_CENTER, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_NORTH))},
|
||||
{Action::FIRE_RIGHT, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_EAST))},
|
||||
|
||||
// Interfaz
|
||||
{Action::START, ButtonState(SDL_GAMEPAD_BUTTON_START)},
|
||||
{Action::SERVICE, ButtonState(SDL_GAMEPAD_BUTTON_BACK)},
|
||||
{Action::START, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_START))},
|
||||
{Action::SERVICE, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_BACK))},
|
||||
|
||||
// Menu de servicio
|
||||
{Action::SM_SELECT, ButtonState(SDL_GAMEPAD_BUTTON_WEST)},
|
||||
{Action::SM_BACK, ButtonState(SDL_GAMEPAD_BUTTON_NORTH)}} {}
|
||||
{Action::SM_SELECT, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_WEST))},
|
||||
{Action::SM_BACK, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_NORTH))}} {}
|
||||
|
||||
~Gamepad() {
|
||||
if (pad != nullptr) {
|
||||
@@ -130,7 +130,7 @@ class Input {
|
||||
|
||||
// Reasigna un botón a una acción
|
||||
void rebindAction(Action action, SDL_GamepadButton new_button) {
|
||||
bindings[action] = new_button;
|
||||
bindings[action] = static_cast<int>(new_button);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -144,18 +144,18 @@ class Input {
|
||||
|
||||
// --- Métodos de configuración de controles ---
|
||||
void bindKey(Action action, SDL_Scancode code);
|
||||
static void bindGameControllerButton(std::shared_ptr<Gamepad> gamepad, Action action, SDL_GamepadButton button);
|
||||
static void bindGameControllerButton(std::shared_ptr<Gamepad> gamepad, Action action_target, Action action_source);
|
||||
static void bindGameControllerButton(const std::shared_ptr<Gamepad> &gamepad, Action action, SDL_GamepadButton button);
|
||||
static void bindGameControllerButton(const std::shared_ptr<Gamepad> &gamepad, Action action_target, Action action_source);
|
||||
|
||||
// --- Métodos de consulta de entrada ---
|
||||
void update();
|
||||
auto checkAction(Action action, bool repeat = true, bool check_keyboard = true, std::shared_ptr<Gamepad> gamepad = nullptr) -> bool;
|
||||
auto checkAnyInput(bool check_keyboard = true, std::shared_ptr<Gamepad> gamepad = nullptr) -> bool;
|
||||
auto checkAction(Action action, bool repeat = true, bool check_keyboard = true, const std::shared_ptr<Gamepad> &gamepad = nullptr) -> bool;
|
||||
auto checkAnyInput(bool check_keyboard = true, const std::shared_ptr<Gamepad> &gamepad = nullptr) -> bool;
|
||||
auto checkAnyButton(bool repeat = DO_NOT_ALLOW_REPEAT) -> bool;
|
||||
|
||||
// --- Métodos de gestión de mandos ---
|
||||
[[nodiscard]] auto gameControllerFound() const -> bool;
|
||||
static auto getControllerName(std::shared_ptr<Gamepad> gamepad) -> std::string;
|
||||
static auto getControllerName(const std::shared_ptr<Gamepad> &gamepad) -> std::string;
|
||||
auto getControllerNames() const -> std::vector<std::string>;
|
||||
[[nodiscard]] auto getNumGamepads() const -> int;
|
||||
auto getGamepad(SDL_JoystickID id) const -> std::shared_ptr<Gamepad>;
|
||||
@@ -163,7 +163,7 @@ class Input {
|
||||
auto getGamepads() const -> const Gamepads & { return gamepads_; }
|
||||
|
||||
// --- Métodos de consulta y utilidades ---
|
||||
[[nodiscard]] static auto getControllerBinding(std::shared_ptr<Gamepad> gamepad, Action action) -> SDL_GamepadButton;
|
||||
[[nodiscard]] static auto getControllerBinding(const std::shared_ptr<Gamepad> &gamepad, Action action) -> SDL_GamepadButton;
|
||||
[[nodiscard]] static auto inputToString(Action action) -> std::string;
|
||||
[[nodiscard]] static auto stringToInput(const std::string &name) -> Action;
|
||||
|
||||
@@ -193,8 +193,8 @@ class Input {
|
||||
|
||||
// --- Métodos internos ---
|
||||
void initSDLGamePad();
|
||||
static auto checkAxisInput(Action action, std::shared_ptr<Gamepad> gamepad, bool repeat) -> bool;
|
||||
static auto checkTriggerInput(Action action, std::shared_ptr<Gamepad> gamepad, bool repeat) -> bool;
|
||||
static auto checkAxisInput(Action action, const std::shared_ptr<Gamepad> &gamepad, bool repeat) -> bool;
|
||||
static auto checkTriggerInput(Action action, const std::shared_ptr<Gamepad> &gamepad, bool repeat) -> bool;
|
||||
auto addGamepad(int device_index) -> std::string;
|
||||
auto removeGamepad(SDL_JoystickID id) -> std::string;
|
||||
void addGamepadMappingsFromFile();
|
||||
|
||||
@@ -8,10 +8,8 @@
|
||||
|
||||
class Texture; // lines 6-6
|
||||
|
||||
Item::Item(ItemType type, float x, float y, SDL_FRect &play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation)
|
||||
: sprite_(std::make_unique<AnimatedSprite>(texture, animation)),
|
||||
play_area_(play_area),
|
||||
type_(type) {
|
||||
Item::Item(ItemType type, float x, float y, SDL_FRect &play_area, const std::shared_ptr<Texture> &texture, const std::vector<std::string> &animation)
|
||||
: sprite_(std::make_unique<AnimatedSprite>(texture, animation)), play_area_(play_area), type_(type) {
|
||||
switch (type) {
|
||||
case ItemType::COFFEE_MACHINE: {
|
||||
width_ = COFFEE_MACHINE_WIDTH;
|
||||
@@ -29,7 +27,15 @@ Item::Item(ItemType type, float x, float y, SDL_FRect &play_area, std::shared_pt
|
||||
height_ = param.game.item_size;
|
||||
pos_x_ = x;
|
||||
pos_y_ = y;
|
||||
vel_x_ = -1.0F + ((rand() % 5) * 0.5F);
|
||||
// 6 velocidades: 3 negativas (-1.0, -0.66, -0.33) y 3 positivas (0.33, 0.66, 1.0)
|
||||
const int direction = rand() % 6;
|
||||
if (direction < 3) {
|
||||
// Velocidades negativas: -1.0, -0.66, -0.33
|
||||
vel_x_ = -1.0F + (direction * 0.33F);
|
||||
} else {
|
||||
// Velocidades positivas: 0.33, 0.66, 1.0
|
||||
vel_x_ = 0.33F + ((direction - 3) * 0.33F);
|
||||
}
|
||||
vel_y_ = -4.0F;
|
||||
accel_y_ = 0.2F;
|
||||
collider_.r = width_ / 2;
|
||||
@@ -82,9 +88,9 @@ void Item::move() {
|
||||
const float MAX_X = play_area_.w - width_;
|
||||
pos_x_ = std::clamp(pos_x_, MIN_X, MAX_X);
|
||||
|
||||
// Si toca el borde lateral, invierte la velocidad horizontal
|
||||
// Si toca el borde lateral
|
||||
if (pos_x_ == MIN_X || pos_x_ == MAX_X) {
|
||||
vel_x_ = -vel_x_;
|
||||
vel_x_ = -vel_x_; // Invierte la velocidad horizontal
|
||||
}
|
||||
|
||||
// Si colisiona por arriba, rebota (excepto la máquina de café)
|
||||
@@ -92,8 +98,8 @@ void Item::move() {
|
||||
// Corrige
|
||||
pos_y_ = param.game.play_area.rect.y;
|
||||
|
||||
// Invierte la velocidad
|
||||
vel_y_ = -vel_y_;
|
||||
// Fuerza la velocidad hacia abajo para evitar oscilaciones
|
||||
vel_y_ = std::abs(vel_y_);
|
||||
}
|
||||
|
||||
// Si colisiona con la parte inferior
|
||||
@@ -181,17 +187,17 @@ auto Item::getCoffeeMachineSpawn(int player_x, int item_width, int area_width, i
|
||||
// Ambos lados disponibles, elegir aleatoriamente
|
||||
if (rand() % 2 == 0) {
|
||||
// Lado izquierdo
|
||||
return rand() % (exclude_left - LEFT_BOUND) + LEFT_BOUND;
|
||||
return (rand() % (exclude_left - LEFT_BOUND)) + LEFT_BOUND;
|
||||
} // Lado derecho
|
||||
return rand() % (RIGHT_BOUND - exclude_right) + exclude_right;
|
||||
return (rand() % (RIGHT_BOUND - exclude_right)) + exclude_right;
|
||||
}
|
||||
if (can_spawn_left) {
|
||||
// Solo lado izquierdo disponible
|
||||
return rand() % (exclude_left - LEFT_BOUND) + LEFT_BOUND;
|
||||
return (rand() % (exclude_left - LEFT_BOUND)) + LEFT_BOUND;
|
||||
}
|
||||
if (can_spawn_right) {
|
||||
// Solo lado derecho disponible
|
||||
return rand() % (RIGHT_BOUND - exclude_right) + exclude_right;
|
||||
return (rand() % (RIGHT_BOUND - exclude_right)) + exclude_right;
|
||||
} // No hay espacio suficiente lejos del jugador
|
||||
// Por ahora, intentar spawn en el extremo más lejano posible
|
||||
int distance_to_left = abs(player_x - LEFT_BOUND);
|
||||
|
||||
@@ -31,8 +31,8 @@ class Item {
|
||||
static constexpr int COFFEE_MACHINE_HEIGHT = 39; // Altura de la máquina de café
|
||||
|
||||
// --- Constructor y destructor ---
|
||||
Item(ItemType type, float x, float y, SDL_FRect &play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation); // Constructor principal
|
||||
~Item() = default; // Destructor
|
||||
Item(ItemType type, float x, float y, SDL_FRect &play_area, const std::shared_ptr<Texture> &texture, const std::vector<std::string> &animation); // Constructor principal
|
||||
~Item() = default; // Destructor
|
||||
|
||||
// --- Métodos principales ---
|
||||
void alignTo(int x); // Centra el objeto en la posición X indicada
|
||||
@@ -41,14 +41,14 @@ class Item {
|
||||
void update(); // Actualiza la posición, animación y contadores
|
||||
|
||||
// --- Getters ---
|
||||
[[nodiscard]] auto getPosX() const -> float { return pos_x_; } // Obtiene la posición X
|
||||
[[nodiscard]] auto getPosY() const -> float { return pos_y_; } // Obtiene la posición Y
|
||||
[[nodiscard]] auto getWidth() const -> int { return width_; } // Obtiene la anchura
|
||||
[[nodiscard]] auto getHeight() const -> int { return height_; } // Obtiene la altura
|
||||
[[nodiscard]] auto getType() const -> ItemType { return type_; } // Obtiene el tipo
|
||||
[[nodiscard]] auto isEnabled() const -> bool { return enabled_; } // Verifica si está habilitado
|
||||
[[nodiscard]] auto isOnFloor() const -> bool { return floor_collision_; } // Verifica si está en el suelo
|
||||
auto getCollider() -> Circle & { return collider_; } // Obtiene el colisionador
|
||||
[[nodiscard]] auto getPosX() const -> float { return pos_x_; } // Obtiene la posición X
|
||||
[[nodiscard]] auto getPosY() const -> float { return pos_y_; } // Obtiene la posición Y
|
||||
[[nodiscard]] auto getWidth() const -> int { return width_; } // Obtiene la anchura
|
||||
[[nodiscard]] auto getHeight() const -> int { return height_; } // Obtiene la altura
|
||||
[[nodiscard]] auto getType() const -> ItemType { return type_; } // Obtiene el tipo
|
||||
[[nodiscard]] auto isEnabled() const -> bool { return enabled_; } // Verifica si está habilitado
|
||||
[[nodiscard]] auto isOnFloor() const -> bool { return floor_collision_; } // Verifica si está en el suelo
|
||||
auto getCollider() -> Circle & { return collider_; } // Obtiene el colisionador
|
||||
|
||||
private:
|
||||
// --- Objetos y punteros ---
|
||||
@@ -71,9 +71,9 @@ class Item {
|
||||
bool enabled_ = true; // Indica si el objeto está habilitado
|
||||
|
||||
// --- Métodos internos ---
|
||||
void shiftColliders(); // Alinea el círculo de colisión con la posición del objeto
|
||||
void shiftSprite(); // Coloca el sprite en la posición del objeto
|
||||
void move(); // Actualiza la posición y estados del objeto
|
||||
void updateTimeToLive(); // Actualiza el contador de tiempo de vida
|
||||
static auto getCoffeeMachineSpawn(int player_x, int item_width, int area_width, int margin = 2) -> int; // Calcula la zona de aparición de la máquina de café
|
||||
void shiftColliders(); // Alinea el círculo de colisión con la posición del objeto
|
||||
void shiftSprite(); // Coloca el sprite en la posición del objeto
|
||||
void move(); // Actualiza la posición y estados del objeto
|
||||
void updateTimeToLive(); // Actualiza el contador de tiempo de vida
|
||||
static auto getCoffeeMachineSpawn(int player_x, int item_width, int area_width, int margin = 2) -> int; // Calcula la zona de aparición de la máquina de café
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "difficulty.h" // Para Difficulty
|
||||
#include "external/json.hpp" // Para basic_json, iteration_proxy_value, oper...
|
||||
#include "options.h" // Para SettingsOpt...
|
||||
#include "resource_helper.h" // Para ResourceHelper
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -27,14 +28,24 @@ std::vector<Language> languages = {
|
||||
auto loadFromFile(const std::string &file_path) -> bool {
|
||||
texts.clear();
|
||||
|
||||
std::ifstream rfile(file_path);
|
||||
if (!rfile.is_open()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Intentar cargar desde ResourceHelper primero
|
||||
auto resource_data = ResourceHelper::loadFile(file_path);
|
||||
|
||||
try {
|
||||
json j;
|
||||
rfile >> j;
|
||||
|
||||
if (!resource_data.empty()) {
|
||||
// Cargar desde datos del pack
|
||||
std::string content(resource_data.begin(), resource_data.end());
|
||||
j = json::parse(content);
|
||||
} else {
|
||||
// Fallback a filesystem directo
|
||||
std::ifstream rfile(file_path);
|
||||
if (!rfile.is_open()) {
|
||||
return false;
|
||||
}
|
||||
rfile >> j;
|
||||
}
|
||||
|
||||
for (const auto &el : j.items()) {
|
||||
texts[el.key()] = el.value();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string> // Para string, basic_string
|
||||
#include <utility> // Para move
|
||||
#include <string> // Para string, basic_string
|
||||
#include <utility> // Para move
|
||||
|
||||
// --- Namespace Lang: gestión de idiomas y textos ---
|
||||
namespace Lang {
|
||||
|
||||
@@ -17,5 +17,5 @@ auto main(int argc, char* argv[]) -> int {
|
||||
auto director = std::make_unique<Director>(argc, std::span<char*>(argv, argc));
|
||||
|
||||
// Bucle principal
|
||||
return director->run();
|
||||
return Director::run();
|
||||
}
|
||||
|
||||
@@ -36,9 +36,9 @@ auto ManageHiScoreTable::add(const HiScoreEntry &entry) -> int {
|
||||
sort();
|
||||
|
||||
// Encontrar la posición del nuevo elemento
|
||||
auto it = std::find_if(table_.begin(), table_.end(), [&](const HiScoreEntry &e) { return e.name == entry.name &&
|
||||
e.score == entry.score &&
|
||||
e.one_credit_complete == entry.one_credit_complete; });
|
||||
auto it = std::ranges::find_if(table_, [&](const HiScoreEntry &e) {
|
||||
return e.name == entry.name && e.score == entry.score && e.one_credit_complete == entry.one_credit_complete;
|
||||
});
|
||||
|
||||
int position = -1;
|
||||
if (it != table_.end()) {
|
||||
@@ -66,7 +66,7 @@ void ManageHiScoreTable::sort() {
|
||||
auto operator()(const HiScoreEntry &a, const HiScoreEntry &b) const -> bool { return a.score > b.score; }
|
||||
} score_descending_comparator;
|
||||
|
||||
std::sort(table_.begin(), table_.end(), score_descending_comparator);
|
||||
std::ranges::sort(table_, score_descending_comparator);
|
||||
}
|
||||
|
||||
// Carga la tabla desde un fichero
|
||||
|
||||
@@ -26,7 +26,7 @@ class ManageHiScoreTable {
|
||||
// --- Constructor y destructor ---
|
||||
explicit ManageHiScoreTable(Table &table) // Constructor con referencia a tabla
|
||||
: table_(table) {}
|
||||
~ManageHiScoreTable() = default; // Destructor
|
||||
~ManageHiScoreTable() = default; // Destructor
|
||||
|
||||
// --- Métodos públicos ---
|
||||
void clear(); // Resetea la tabla a los valores por defecto
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#include "moving_sprite.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "texture.h" // Para Texture
|
||||
|
||||
// Constructor
|
||||
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos, Rotate rotate, float horizontal_zoom, float vertical_zoom, SDL_FlipMode flip)
|
||||
: Sprite(texture, pos),
|
||||
: Sprite(std::move(texture), pos),
|
||||
rotate_(rotate),
|
||||
flip_(flip),
|
||||
x_(pos.x),
|
||||
@@ -13,7 +15,7 @@ MovingSprite::MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos, Rota
|
||||
vertical_zoom_(vertical_zoom) {}
|
||||
|
||||
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos)
|
||||
: Sprite(texture, pos),
|
||||
: Sprite(std::move(texture), pos),
|
||||
flip_(SDL_FLIP_NONE),
|
||||
x_(pos.x),
|
||||
y_(pos.y),
|
||||
@@ -21,7 +23,7 @@ MovingSprite::MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos)
|
||||
vertical_zoom_(1.0F) {}
|
||||
|
||||
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture)
|
||||
: Sprite(texture),
|
||||
: Sprite(std::move(texture)),
|
||||
flip_(SDL_FLIP_NONE),
|
||||
horizontal_zoom_(1.0F),
|
||||
vertical_zoom_(1.0F) { Sprite::clear(); }
|
||||
|
||||
@@ -14,14 +14,12 @@ class MovingSprite : public Sprite {
|
||||
public:
|
||||
// --- Estructuras ---
|
||||
struct Rotate {
|
||||
bool enabled{false}; // Indica si ha de rotar
|
||||
int counter{0}; // Contador
|
||||
int speed{1}; // Velocidad de giro
|
||||
double angle{0.0}; // Ángulo para dibujarlo
|
||||
float amount{0.0F}; // Cantidad de grados a girar en cada iteración
|
||||
SDL_FPoint center; // Centro de rotación
|
||||
|
||||
Rotate() : center({0.0F, 0.0F}) {}
|
||||
bool enabled{false}; // Indica si ha de rotar
|
||||
int counter{0}; // Contador
|
||||
int speed{1}; // Velocidad de giro
|
||||
double angle{0.0}; // Ángulo para dibujarlo
|
||||
float amount{0.0F}; // Cantidad de grados a girar en cada iteración
|
||||
SDL_FPoint center{.x = 0.0F, .y = 0.0F}; // Centro de rotación
|
||||
};
|
||||
|
||||
// --- Constructores y destructor ---
|
||||
@@ -37,34 +35,34 @@ class MovingSprite : public Sprite {
|
||||
void render() override; // Muestra el sprite por pantalla
|
||||
|
||||
// --- Configuración ---
|
||||
void setPos(SDL_FRect rect); // Establece la posición y el tamaño del objeto
|
||||
void setPos(float pos_x, float pos_y); // Establece la posición del objeto
|
||||
void setPosX(float pos_x); // Establece la posición X
|
||||
void setPosY(float pos_y); // Establece la posición Y
|
||||
void setVelX(float value) { vx_ = value; } // Establece la velocidad X
|
||||
void setVelY(float value) { vy_ = value; } // Establece la velocidad Y
|
||||
void setAccelX(float value) { ax_ = value; } // Establece la aceleración X
|
||||
void setAccelY(float value) { ay_ = value; } // Establece la aceleración Y
|
||||
void setHorizontalZoom(float value) { horizontal_zoom_ = value; } // Establece el zoom horizontal
|
||||
void setVerticalZoom(float value) { vertical_zoom_ = value; } // Establece el zoom vertical
|
||||
void setAngle(double value) { rotate_.angle = value; } // Establece el ángulo
|
||||
void setRotatingCenter(SDL_FPoint point) { rotate_.center = point; } // Establece el centro de rotación
|
||||
void setRotate(bool enable); // Activa o desactiva el efecto de rotación
|
||||
void setRotateSpeed(int value) { rotate_.speed = std::max(1, value); } // Establece la velocidad de rotación
|
||||
void setRotateAmount(double value) { rotate_.amount = value; } // Establece la cantidad de rotación
|
||||
void switchRotate() { rotate_.amount *= -1; } // Cambia el sentido de la rotación
|
||||
void setFlip(SDL_FlipMode flip) { flip_ = flip; } // Establece el flip
|
||||
void setPos(SDL_FRect rect); // Establece la posición y el tamaño del objeto
|
||||
void setPos(float pos_x, float pos_y); // Establece la posición del objeto
|
||||
void setPosX(float pos_x); // Establece la posición X
|
||||
void setPosY(float pos_y); // Establece la posición Y
|
||||
void setVelX(float value) { vx_ = value; } // Establece la velocidad X
|
||||
void setVelY(float value) { vy_ = value; } // Establece la velocidad Y
|
||||
void setAccelX(float value) { ax_ = value; } // Establece la aceleración X
|
||||
void setAccelY(float value) { ay_ = value; } // Establece la aceleración Y
|
||||
void setHorizontalZoom(float value) { horizontal_zoom_ = value; } // Establece el zoom horizontal
|
||||
void setVerticalZoom(float value) { vertical_zoom_ = value; } // Establece el zoom vertical
|
||||
void setAngle(double value) { rotate_.angle = value; } // Establece el ángulo
|
||||
void setRotatingCenter(SDL_FPoint point) { rotate_.center = point; } // Establece el centro de rotación
|
||||
void setRotate(bool enable); // Activa o desactiva el efecto de rotación
|
||||
void setRotateSpeed(int value) { rotate_.speed = std::max(1, value); } // Establece la velocidad de rotación
|
||||
void setRotateAmount(double value) { rotate_.amount = value; } // Establece la cantidad de rotación
|
||||
void switchRotate() { rotate_.amount *= -1; } // Cambia el sentido de la rotación
|
||||
void setFlip(SDL_FlipMode flip) { flip_ = flip; } // Establece el flip
|
||||
void flip() { flip_ = (flip_ == SDL_FLIP_HORIZONTAL) ? SDL_FLIP_NONE : SDL_FLIP_HORIZONTAL; } // Cambia el flip
|
||||
|
||||
// --- Getters ---
|
||||
[[nodiscard]] auto getPosX() const -> float { return x_; } // Obtiene la posición X
|
||||
[[nodiscard]] auto getPosY() const -> float { return y_; } // Obtiene la posición Y
|
||||
[[nodiscard]] auto getVelX() const -> float { return vx_; } // Obtiene la velocidad X
|
||||
[[nodiscard]] auto getVelY() const -> float { return vy_; } // Obtiene la velocidad Y
|
||||
[[nodiscard]] auto getAccelX() const -> float { return ax_; } // Obtiene la aceleración X
|
||||
[[nodiscard]] auto getAccelY() const -> float { return ay_; } // Obtiene la aceleración Y
|
||||
[[nodiscard]] auto getPosX() const -> float { return x_; } // Obtiene la posición X
|
||||
[[nodiscard]] auto getPosY() const -> float { return y_; } // Obtiene la posición Y
|
||||
[[nodiscard]] auto getVelX() const -> float { return vx_; } // Obtiene la velocidad X
|
||||
[[nodiscard]] auto getVelY() const -> float { return vy_; } // Obtiene la velocidad Y
|
||||
[[nodiscard]] auto getAccelX() const -> float { return ax_; } // Obtiene la aceleración X
|
||||
[[nodiscard]] auto getAccelY() const -> float { return ay_; } // Obtiene la aceleración Y
|
||||
[[nodiscard]] auto isRotating() const -> bool { return rotate_.enabled; } // Verifica si está rotando
|
||||
auto getFlip() -> SDL_FlipMode { return flip_; } // Obtiene el flip
|
||||
auto getFlip() -> SDL_FlipMode { return flip_; } // Obtiene el flip
|
||||
|
||||
protected:
|
||||
// --- Variables de estado ---
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <fstream> // Para basic_ostream, operator<<, basic_ostream::operator<<, basic_ofstream, basic_istream, basic_ifstream, ifstream, ofstream
|
||||
#include <functional> // Para function
|
||||
#include <map> // Para map, operator==, _Rb_tree_const_iterator
|
||||
#include <ranges> // Para std::ranges::any_of
|
||||
#include <stdexcept> // Para invalid_argument, out_of_range
|
||||
#include <string> // Para char_traits, stoi, operator==, operator<<, allocator, string, basic_string, operator<=>, getline
|
||||
#include <utility> // Para swap, pair
|
||||
@@ -65,7 +66,7 @@ auto loadFromFile() -> bool {
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
if (line.substr(0, 1) != "#") {
|
||||
int pos = line.find("=");
|
||||
int pos = line.find('=');
|
||||
if (!set(line.substr(0, pos), line.substr(pos + 1, line.length()))) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Unknown parameter: %s", line.substr(0, pos).c_str());
|
||||
}
|
||||
@@ -133,6 +134,7 @@ auto saveToFile() -> bool {
|
||||
file << "game.difficulty=" << static_cast<int>(settings.difficulty) << "\n";
|
||||
file << "game.autofire=" << boolToString(settings.autofire) << "\n";
|
||||
file << "game.shutdown_enabled=" << boolToString(settings.shutdown_enabled) << "\n";
|
||||
file << "game.params_file=" << settings.params_file << "\n";
|
||||
|
||||
// Opciones de mandos
|
||||
file << "\n## CONTROLLERS\n";
|
||||
@@ -207,6 +209,7 @@ auto set(const std::string& var, const std::string& value) -> bool {
|
||||
}},
|
||||
{"game.autofire", [](const auto& val) { settings.autofire = stringToBool(val); }},
|
||||
{"game.shutdown_enabled", [](const auto& val) { settings.shutdown_enabled = stringToBool(val); }},
|
||||
{"game.params_file", [](const auto& val) { settings.params_file = val; }},
|
||||
// Teclado
|
||||
{"keyboard.player", [](const auto& val) { keyboard.player_id = static_cast<Player::Id>(stoi(val)); }}};
|
||||
|
||||
@@ -392,12 +395,10 @@ void GamepadManager::clearUnassignedGamepadSlots() {
|
||||
auto GamepadManager::isGamepadAssigned(
|
||||
const std::shared_ptr<Input::Gamepad>& physical_gamepad,
|
||||
const std::vector<std::shared_ptr<Input::Gamepad>>& assigned_instances) -> bool {
|
||||
for (const auto& assigned : assigned_instances) {
|
||||
if (assigned == physical_gamepad) {
|
||||
return true; // Encontrado, por lo tanto, ya está asignado.
|
||||
}
|
||||
}
|
||||
return false; // No se encontró en la lista.
|
||||
return std::ranges::any_of(assigned_instances,
|
||||
[&physical_gamepad](const auto& assigned) {
|
||||
return assigned == physical_gamepad;
|
||||
});
|
||||
}
|
||||
|
||||
// Convierte un player id a texto segun Lang
|
||||
@@ -413,7 +414,7 @@ auto playerIdToString(Player::Id player_id) -> std::string {
|
||||
}
|
||||
|
||||
// Convierte un texto a player id segun Lang
|
||||
auto stringToPlayerId(std::string name) -> Player::Id {
|
||||
auto stringToPlayerId(const std::string& name) -> Player::Id {
|
||||
if (name == Lang::getText("[SERVICE_MENU] PLAYER1")) {
|
||||
return Player::Id::PLAYER1;
|
||||
}
|
||||
|
||||
@@ -11,8 +11,10 @@
|
||||
#include <stdexcept> // Para out_of_range, invalid_argument
|
||||
#include <string> // Para char_traits, string, allocator, operator==, swap, operator<<, basic_string, stoi
|
||||
#include <string_view> // Para string_view
|
||||
#include <utility> // Para swap
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "defaults.h" // Para GameDefaults
|
||||
#include "difficulty.h" // Para Code
|
||||
#include "input.h" // Para Input
|
||||
#include "lang.h" // Para Code
|
||||
@@ -24,66 +26,47 @@ namespace Options {
|
||||
|
||||
// --- Estructuras ---
|
||||
struct Window {
|
||||
std::string caption; // Texto que aparece en la barra de título de la ventana
|
||||
int zoom{2}; // Valor por el que se multiplica el tamaño de la ventana
|
||||
int max_zoom{2}; // Tamaño máximo para que la ventana no sea mayor que la pantalla
|
||||
|
||||
// Constructor por defecto con valores iniciales
|
||||
Window()
|
||||
: caption("Coffee Crisis Arcade Edition") {}
|
||||
std::string caption = GameDefaults::Options::WINDOW_CAPTION; // Texto que aparece en la barra de título de la ventana
|
||||
int zoom = GameDefaults::Options::WINDOW_ZOOM; // Valor por el que se multiplica el tamaño de la ventana
|
||||
int max_zoom = GameDefaults::Options::WINDOW_MAX_ZOOM; // Tamaño máximo para que la ventana no sea mayor que la pantalla
|
||||
};
|
||||
|
||||
struct Video {
|
||||
SDL_ScaleMode scale_mode{SDL_ScaleMode::SDL_SCALEMODE_NEAREST}; // Filtro usado para el escalado de la imagen
|
||||
bool fullscreen{false}; // Indica si se usa pantalla completa
|
||||
bool vsync{true}; // Indica si se usa vsync
|
||||
bool integer_scale{true}; // Indica si se usa escalado entero
|
||||
bool shaders{false}; // Indica si se usan shaders para los filtros de vídeo
|
||||
std::string info; // Información sobre el modo de vídeo
|
||||
|
||||
// Constructor por defecto con valores iniciales
|
||||
Video() = default;
|
||||
SDL_ScaleMode scale_mode = GameDefaults::Options::VIDEO_SCALE_MODE; // Filtro usado para el escalado de la imagen
|
||||
bool fullscreen = GameDefaults::Options::VIDEO_FULLSCREEN; // Indica si se usa pantalla completa
|
||||
bool vsync = GameDefaults::Options::VIDEO_VSYNC; // Indica si se usa vsync
|
||||
bool integer_scale = GameDefaults::Options::VIDEO_INTEGER_SCALE; // Indica si se usa escalado entero
|
||||
bool shaders = GameDefaults::Options::VIDEO_SHADERS; // Indica si se usan shaders para los filtros de vídeo
|
||||
std::string info; // Información sobre el modo de vídeo
|
||||
};
|
||||
|
||||
struct Music {
|
||||
bool enabled{true}; // Indica si la música suena o no
|
||||
int volume{100}; // Volumen de la música
|
||||
|
||||
// Constructor por defecto
|
||||
Music() = default;
|
||||
bool enabled = GameDefaults::Options::MUSIC_ENABLED; // Indica si la música suena o no
|
||||
int volume = GameDefaults::Options::MUSIC_VOLUME; // Volumen de la música
|
||||
};
|
||||
|
||||
struct Sound {
|
||||
bool enabled{true}; // Indica si los sonidos suenan o no
|
||||
int volume{100}; // Volumen de los sonidos
|
||||
|
||||
// Constructor por defecto
|
||||
Sound() = default;
|
||||
bool enabled = GameDefaults::Options::SOUND_ENABLED; // Indica si los sonidos suenan o no
|
||||
int volume = GameDefaults::Options::SOUND_VOLUME; // Volumen de los sonidos
|
||||
};
|
||||
|
||||
struct Audio {
|
||||
Music music; // Opciones para la música
|
||||
Sound sound; // Opciones para los efectos de sonido
|
||||
bool enabled{true}; // Indica si el audio está activo o no
|
||||
int volume{100}; // Volumen general del audio
|
||||
|
||||
// Constructor por defecto
|
||||
Audio() = default;
|
||||
Music music; // Opciones para la música
|
||||
Sound sound; // Opciones para los efectos de sonido
|
||||
bool enabled = GameDefaults::Options::AUDIO_ENABLED; // Indica si el audio está activo o no
|
||||
int volume = GameDefaults::Options::AUDIO_VOLUME; // Volumen general del audio
|
||||
};
|
||||
|
||||
struct Settings {
|
||||
Difficulty::Code difficulty{Difficulty::Code::NORMAL}; // Dificultad del juego
|
||||
Lang::Code language{Lang::Code::VALENCIAN}; // Idioma usado en el juego
|
||||
bool autofire{true}; // Indicador de autofire
|
||||
bool shutdown_enabled{false}; // Especifica si se puede apagar el sistema
|
||||
Table hi_score_table; // Tabla de mejores puntuaciones
|
||||
std::vector<int> glowing_entries; // Últimas posiciones de entrada en la tabla
|
||||
std::string config_file; // Ruta al fichero donde guardar la configuración y las opciones del juego
|
||||
std::string controllers_file; // Ruta al fichero con las configuraciones de los mandos
|
||||
|
||||
// Constructor por defecto con valores iniciales
|
||||
Settings()
|
||||
: glowing_entries({ManageHiScoreTable::NO_ENTRY, ManageHiScoreTable::NO_ENTRY}) {}
|
||||
Difficulty::Code difficulty = Difficulty::Code::NORMAL; // Dificultad del juego
|
||||
Lang::Code language = Lang::Code::VALENCIAN; // Idioma usado en el juego
|
||||
bool autofire = GameDefaults::Options::SETTINGS_AUTOFIRE; // Indicador de autofire
|
||||
bool shutdown_enabled = GameDefaults::Options::SETTINGS_SHUTDOWN_ENABLED; // Especifica si se puede apagar el sistema
|
||||
Table hi_score_table; // Tabla de mejores puntuaciones
|
||||
std::vector<int> glowing_entries = {ManageHiScoreTable::NO_ENTRY, ManageHiScoreTable::NO_ENTRY}; // Últimas posiciones de entrada en la tabla
|
||||
std::string config_file; // Ruta al fichero donde guardar la configuración y las opciones del juego
|
||||
std::string controllers_file; // Ruta al fichero con las configuraciones de los mandos
|
||||
std::string params_file = GameDefaults::Options::PARAMS_FILE; // Ruta al fichero de parámetros del juego
|
||||
|
||||
// Reinicia las últimas entradas de puntuación
|
||||
void clearLastHiScoreEntries() {
|
||||
@@ -139,7 +122,7 @@ class GamepadManager {
|
||||
const std::string& name) -> bool {
|
||||
try {
|
||||
auto& gamepad = getGamepad(player_id);
|
||||
gamepad.instance = instance;
|
||||
gamepad.instance = std::move(instance);
|
||||
gamepad.name = name;
|
||||
return true;
|
||||
} catch (const std::exception&) {
|
||||
@@ -156,7 +139,7 @@ class GamepadManager {
|
||||
}
|
||||
|
||||
void resyncGamepadsWithPlayers() {
|
||||
for (auto player : players_) {
|
||||
for (const auto& player : players_) {
|
||||
switch (player->getId()) {
|
||||
case Player::Id::PLAYER1:
|
||||
player->setGamepad(gamepads_[0].instance);
|
||||
@@ -221,11 +204,11 @@ class GamepadManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
void addPlayer(std::shared_ptr<Player> player) { players_.push_back(player); } // Añade un jugador a la lista
|
||||
void clearPlayers() { players_.clear(); } // Limpia la lista de jugadores
|
||||
void addPlayer(const std::shared_ptr<Player>& player) { players_.push_back(player); } // Añade un jugador a la lista
|
||||
void clearPlayers() { players_.clear(); } // Limpia la lista de jugadores
|
||||
|
||||
// Asigna el mando a un jugador
|
||||
void assignTo(Input::Gamepad gamepad, Player::Id player_id) {
|
||||
void assignTo(const Input::Gamepad& gamepad, Player::Id player_id) {
|
||||
}
|
||||
|
||||
// Asigna los mandos físicos basándose en la configuración actual de nombres.
|
||||
@@ -274,8 +257,8 @@ struct Keyboard {
|
||||
Player::Id player_id = Player::Id::PLAYER1; // Jugador asociado al teclado
|
||||
std::vector<std::shared_ptr<Player>> players; // Punteros a los jugadores
|
||||
|
||||
void addPlayer(std::shared_ptr<Player> player) { players.push_back(player); } // Añade un jugador a la lista
|
||||
void clearPlayers() { players.clear(); } // Limpia la lista de jugadores
|
||||
void addPlayer(const std::shared_ptr<Player>& player) { players.push_back(player); } // Añade un jugador a la lista
|
||||
void clearPlayers() { players.clear(); } // Limpia la lista de jugadores
|
||||
|
||||
// Asigna el teclado a un jugador
|
||||
void assignTo(Player::Id player_id) {
|
||||
@@ -287,12 +270,9 @@ struct Keyboard {
|
||||
};
|
||||
|
||||
struct PendingChanges {
|
||||
Lang::Code new_language{Lang::Code::VALENCIAN}; // Idioma en espera de aplicar
|
||||
Difficulty::Code new_difficulty{Difficulty::Code::NORMAL}; // Dificultad en espera de aplicar
|
||||
bool has_pending_changes{false}; // Indica si hay cambios pendientes
|
||||
|
||||
// Constructor por defecto con valores iniciales
|
||||
PendingChanges() = default;
|
||||
Lang::Code new_language = Lang::Code::VALENCIAN; // Idioma en espera de aplicar
|
||||
Difficulty::Code new_difficulty = Difficulty::Code::NORMAL; // Dificultad en espera de aplicar
|
||||
bool has_pending_changes = false; // Indica si hay cambios pendientes
|
||||
};
|
||||
|
||||
// --- Variables ---
|
||||
@@ -315,7 +295,7 @@ void swapKeyboard();
|
||||
void swapControllers(); // Intercambia los jugadores asignados a los dos primeros mandos
|
||||
auto getPlayerWhoUsesKeyboard() -> Player::Id; // Averigua quién está usando el teclado
|
||||
auto playerIdToString(Player::Id player_id) -> std::string; // Convierte un player id a texto segun Lang
|
||||
auto stringToPlayerId(std::string name) -> Player::Id; // Convierte un texto a player id segun Lang
|
||||
auto stringToPlayerId(const std::string& name) -> Player::Id; // Convierte un texto a player id segun Lang
|
||||
void applyPendingChanges(); // Aplica los cambios pendientes copiando los valores a sus variables
|
||||
void checkPendingChanges(); // Verifica si hay cambios pendientes
|
||||
auto assignGamepadByName(const std::string& gamepad_name, Player::Id player_id) -> bool; // Buscar y asignar un mando disponible por nombre
|
||||
|
||||
335
source/param.cpp
335
source/param.cpp
@@ -2,23 +2,23 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_LogCategory, SDL_LogError, SDL_LogInfo
|
||||
|
||||
#include <fstream> // Para basic_istream, basic_ifstream, ifstream
|
||||
#include <fstream> // Para basic_istream, basic_ifstream, ifstream
|
||||
#include <functional>
|
||||
#include <sstream> // Para basic_istringstream
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <string> // Para operator==, stoi, char_traits, string, ope...
|
||||
#include <sstream> // Para basic_istringstream
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <string> // Para operator==, stoi, char_traits, string, ope...
|
||||
#include <unordered_map>
|
||||
|
||||
#include "color.h"
|
||||
#include "utils.h"
|
||||
#include "ui/notifier.h" // Para Notifier::Position
|
||||
#include "utils.h"
|
||||
|
||||
// Variable global - ahora se inicializa automáticamente con valores por defecto
|
||||
Param param;
|
||||
|
||||
// Declaraciones de funciones privadas
|
||||
namespace {
|
||||
auto setParams(const std::string& var, const std::string& value) -> bool;
|
||||
auto setParams(const std::string& var, const std::string& value) -> bool;
|
||||
}
|
||||
|
||||
// Implementación del método privado de Param
|
||||
@@ -32,7 +32,7 @@ void Param::precalculateZones() {
|
||||
game.play_area.third_quarter_y = game.play_area.rect.h / 4 * 3;
|
||||
|
||||
// gameArea - cálculos basados en width y height actuales
|
||||
game.game_area.rect = {0, 0, game.width, game.height};
|
||||
game.game_area.rect = {.x = 0, .y = 0, .w = game.width, .h = game.height};
|
||||
game.game_area.center_x = game.game_area.rect.w / 2;
|
||||
game.game_area.first_quarter_x = game.game_area.rect.w / 4;
|
||||
game.game_area.third_quarter_x = game.game_area.rect.w / 4 * 3;
|
||||
@@ -45,7 +45,7 @@ void Param::precalculateZones() {
|
||||
void loadParamsFromFile(const std::string& file_path) {
|
||||
// Los parámetros ya están inicializados con valores por defecto
|
||||
// Solo necesitamos abrir el archivo y sobrescribir los valores que aparezcan
|
||||
|
||||
|
||||
std::ifstream file(file_path);
|
||||
if (!file.is_open()) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo abrir el archivo %s", file_path.c_str());
|
||||
@@ -57,7 +57,7 @@ void loadParamsFromFile(const std::string& file_path) {
|
||||
std::string line;
|
||||
std::string param_name;
|
||||
std::string param_value;
|
||||
|
||||
|
||||
while (std::getline(file, line)) {
|
||||
// Elimina comentarios
|
||||
auto comment_pos = line.find('#');
|
||||
@@ -82,153 +82,194 @@ void loadParamsFromFile(const std::string& file_path) {
|
||||
|
||||
// Implementación local de setParams
|
||||
namespace {
|
||||
auto setParams(const std::string& var, const std::string& value) -> bool {
|
||||
// Mapas estáticos para diferentes tipos de parámetros
|
||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> INT_PARAMS = {
|
||||
{"game.width", [](const std::string& v) { param.game.width = std::stoi(v); }},
|
||||
{"game.height", [](const std::string& v) { param.game.height = std::stoi(v); }},
|
||||
{"game.item_size", [](const std::string& v) { param.game.item_size = std::stoi(v); }},
|
||||
{"game.play_area.rect.x", [](const std::string& v) { param.game.play_area.rect.x = std::stoi(v); }},
|
||||
{"game.play_area.rect.y", [](const std::string& v) { param.game.play_area.rect.y = std::stoi(v); }},
|
||||
{"game.play_area.rect.w", [](const std::string& v) { param.game.play_area.rect.w = std::stoi(v); }},
|
||||
{"game.play_area.rect.h", [](const std::string& v) { param.game.play_area.rect.h = std::stoi(v); }},
|
||||
{"game.name_entry_idle_time", [](const std::string& v) { param.game.name_entry_idle_time = std::stoi(v); }},
|
||||
{"game.name_entry_total_time", [](const std::string& v) { param.game.name_entry_total_time = std::stoi(v); }},
|
||||
{"game.hit_stop_ms", [](const std::string& v) { param.game.hit_stop_ms = std::stoi(v); }},
|
||||
{"fade.num_squares_width", [](const std::string& v) { param.fade.num_squares_width = std::stoi(v); }},
|
||||
{"fade.num_squares_height", [](const std::string& v) { param.fade.num_squares_height = std::stoi(v); }},
|
||||
{"fade.random_squares_delay", [](const std::string& v) { param.fade.random_squares_delay = std::stoi(v); }},
|
||||
{"fade.random_squares_mult", [](const std::string& v) { param.fade.random_squares_mult = std::stoi(v); }},
|
||||
{"fade.post_duration", [](const std::string& v) { param.fade.post_duration = std::stoi(v); }},
|
||||
{"fade.venetian_size", [](const std::string& v) { param.fade.venetian_size = std::stoi(v); }},
|
||||
{"scoreboard.rect.x", [](const std::string& v) { param.scoreboard.rect.x = std::stoi(v); }},
|
||||
{"scoreboard.rect.y", [](const std::string& v) { param.scoreboard.rect.y = std::stoi(v); }},
|
||||
{"scoreboard.rect.w", [](const std::string& v) { param.scoreboard.rect.w = std::stoi(v); }},
|
||||
{"scoreboard.rect.h", [](const std::string& v) { param.scoreboard.rect.h = std::stoi(v); }},
|
||||
{"scoreboard.skip_countdown_value", [](const std::string& v) { param.scoreboard.skip_countdown_value = std::stoi(v); }},
|
||||
{"title.press_start_position", [](const std::string& v) { param.title.press_start_position = std::stoi(v); }},
|
||||
{"title.title_duration", [](const std::string& v) { param.title.title_duration = std::stoi(v); }},
|
||||
{"title.arcade_edition_position", [](const std::string& v) { param.title.arcade_edition_position = std::stoi(v); }},
|
||||
{"title.title_c_c_position", [](const std::string& v) { param.title.title_c_c_position = std::stoi(v); }},
|
||||
{"intro.text_distance_from_bottom", [](const std::string& v) { param.intro.text_distance_from_bottom = std::stoi(v); }}
|
||||
};
|
||||
auto setParams(const std::string& var, const std::string& value) -> bool {
|
||||
// Mapas estáticos para diferentes tipos de parámetros
|
||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> INT_PARAMS = {
|
||||
{"game.width", [](const std::string& v) { param.game.width = std::stoi(v); }},
|
||||
{"game.height", [](const std::string& v) { param.game.height = std::stoi(v); }},
|
||||
{"game.item_size", [](const std::string& v) { param.game.item_size = std::stoi(v); }},
|
||||
{"game.play_area.rect.x", [](const std::string& v) { param.game.play_area.rect.x = std::stoi(v); }},
|
||||
{"game.play_area.rect.y", [](const std::string& v) { param.game.play_area.rect.y = std::stoi(v); }},
|
||||
{"game.play_area.rect.w", [](const std::string& v) { param.game.play_area.rect.w = std::stoi(v); }},
|
||||
{"game.play_area.rect.h", [](const std::string& v) { param.game.play_area.rect.h = std::stoi(v); }},
|
||||
{"game.name_entry_idle_time", [](const std::string& v) { param.game.name_entry_idle_time = std::stoi(v); }},
|
||||
{"game.name_entry_total_time", [](const std::string& v) { param.game.name_entry_total_time = std::stoi(v); }},
|
||||
{"game.hit_stop_ms", [](const std::string& v) { param.game.hit_stop_ms = std::stoi(v); }},
|
||||
{"fade.num_squares_width", [](const std::string& v) { param.fade.num_squares_width = std::stoi(v); }},
|
||||
{"fade.num_squares_height", [](const std::string& v) { param.fade.num_squares_height = std::stoi(v); }},
|
||||
{"fade.random_squares_duration_ms", [](const std::string& v) { param.fade.random_squares_duration_ms = std::stoi(v); }},
|
||||
{"fade.post_duration_ms", [](const std::string& v) { param.fade.post_duration_ms = std::stoi(v); }},
|
||||
{"fade.venetian_size", [](const std::string& v) { param.fade.venetian_size = std::stoi(v); }},
|
||||
{"scoreboard.rect.x", [](const std::string& v) { param.scoreboard.rect.x = std::stoi(v); }},
|
||||
{"scoreboard.rect.y", [](const std::string& v) { param.scoreboard.rect.y = std::stoi(v); }},
|
||||
{"scoreboard.rect.w", [](const std::string& v) { param.scoreboard.rect.w = std::stoi(v); }},
|
||||
{"scoreboard.rect.h", [](const std::string& v) { param.scoreboard.rect.h = std::stoi(v); }},
|
||||
{"scoreboard.skip_countdown_value", [](const std::string& v) { param.scoreboard.skip_countdown_value = std::stoi(v); }},
|
||||
{"title.press_start_position", [](const std::string& v) { param.title.press_start_position = std::stoi(v); }},
|
||||
{"title.title_duration", [](const std::string& v) { param.title.title_duration = std::stoi(v); }},
|
||||
{"title.arcade_edition_position", [](const std::string& v) { param.title.arcade_edition_position = std::stoi(v); }},
|
||||
{"title.title_c_c_position", [](const std::string& v) { param.title.title_c_c_position = std::stoi(v); }},
|
||||
{"intro.text_distance_from_bottom", [](const std::string& v) { param.intro.text_distance_from_bottom = std::stoi(v); }}};
|
||||
|
||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> COLOR_PARAMS = {
|
||||
{"fade.color", [](const std::string& v) { param.fade.color = Color::fromHex(v); }},
|
||||
{"scoreboard.separator_color", [](const std::string& v) { param.scoreboard.separator_color = Color::fromHex(v); }},
|
||||
{"scoreboard.easy_color", [](const std::string& v) { param.scoreboard.easy_color = Color::fromHex(v); }},
|
||||
{"scoreboard.normal_color", [](const std::string& v) { param.scoreboard.normal_color = Color::fromHex(v); }},
|
||||
{"scoreboard.hard_color", [](const std::string& v) { param.scoreboard.hard_color = Color::fromHex(v); }},
|
||||
{"scoreboard.text_color1", [](const std::string& v) { param.scoreboard.text_color1 = Color::fromHex(v); }},
|
||||
{"scoreboard.text_color2", [](const std::string& v) { param.scoreboard.text_color2 = Color::fromHex(v); }},
|
||||
{"title.bg_color", [](const std::string& v) { param.title.bg_color = Color::fromHex(v); }},
|
||||
{"background.attenuate_color", [](const std::string& v) { param.background.attenuate_color = Color::fromHex(v); }},
|
||||
{"notification.color", [](const std::string& v) { param.notification.color = Color::fromHex(v); }},
|
||||
{"service_menu.title_color", [](const std::string& v) { param.service_menu.title_color = Color::fromHex(v); }},
|
||||
{"service_menu.text_color", [](const std::string& v) { param.service_menu.text_color = Color::fromHex(v); }},
|
||||
{"service_menu.selected_color", [](const std::string& v) { param.service_menu.selected_color = Color::fromHex(v); }},
|
||||
{"service_menu.bg_color", [](const std::string& v) { param.service_menu.bg_color = Color::fromHex(v); }},
|
||||
{"service_menu.window_message.bg_color", [](const std::string& v) { param.service_menu.window_message.bg_color = Color::fromHex(v); }},
|
||||
{"service_menu.window_message.border_color", [](const std::string& v) { param.service_menu.window_message.border_color = Color::fromHex(v); }},
|
||||
{"service_menu.window_message.title_color", [](const std::string& v) { param.service_menu.window_message.title_color = Color::fromHex(v); }},
|
||||
{"service_menu.window_message.text_color", [](const std::string& v) { param.service_menu.window_message.text_color = Color::fromHex(v); }},
|
||||
{"intro.bg_color", [](const std::string& v) { param.intro.bg_color = Color::fromHex(v); }},
|
||||
{"intro.card_color", [](const std::string& v) { param.intro.card_color = Color::fromHex(v); }},
|
||||
{"intro.shadow_color", [](const std::string& v) { param.intro.shadow_color = Color::fromHex(v); }},
|
||||
{"debug.color", [](const std::string& v) { param.debug.color = Color::fromHex(v); }},
|
||||
{"resource.color", [](const std::string& v) { param.resource.color = Color::fromHex(v); }},
|
||||
{"player.one_coffee_shirt[0].darkest", [](const std::string& v) { param.player.one_coffee_shirt[0].darkest = Color::fromHex(v); }},
|
||||
{"player.one_coffee_shirt[0].dark", [](const std::string& v) { param.player.one_coffee_shirt[0].dark = Color::fromHex(v); }},
|
||||
{"player.one_coffee_shirt[0].base", [](const std::string& v) { param.player.one_coffee_shirt[0].base = Color::fromHex(v); }},
|
||||
{"player.one_coffee_shirt[0].light", [](const std::string& v) { param.player.one_coffee_shirt[0].light = Color::fromHex(v); }},
|
||||
{"player.one_coffee_shirt[1].darkest", [](const std::string& v) { param.player.one_coffee_shirt[1].darkest = Color::fromHex(v); }},
|
||||
{"player.one_coffee_shirt[1].dark", [](const std::string& v) { param.player.one_coffee_shirt[1].dark = Color::fromHex(v); }},
|
||||
{"player.one_coffee_shirt[1].base", [](const std::string& v) { param.player.one_coffee_shirt[1].base = Color::fromHex(v); }},
|
||||
{"player.one_coffee_shirt[1].light", [](const std::string& v) { param.player.one_coffee_shirt[1].light = Color::fromHex(v); }},
|
||||
{"player.two_coffee_shirt[0].darkest", [](const std::string& v) { param.player.two_coffee_shirt[0].darkest = Color::fromHex(v); }},
|
||||
{"player.two_coffee_shirt[0].dark", [](const std::string& v) { param.player.two_coffee_shirt[0].dark = Color::fromHex(v); }},
|
||||
{"player.two_coffee_shirt[0].base", [](const std::string& v) { param.player.two_coffee_shirt[0].base = Color::fromHex(v); }},
|
||||
{"player.two_coffee_shirt[0].light", [](const std::string& v) { param.player.two_coffee_shirt[0].light = Color::fromHex(v); }},
|
||||
{"player.two_coffee_shirt[1].darkest", [](const std::string& v) { param.player.two_coffee_shirt[1].darkest = Color::fromHex(v); }},
|
||||
{"player.two_coffee_shirt[1].dark", [](const std::string& v) { param.player.two_coffee_shirt[1].dark = Color::fromHex(v); }},
|
||||
{"player.two_coffee_shirt[1].base", [](const std::string& v) { param.player.two_coffee_shirt[1].base = Color::fromHex(v); }},
|
||||
{"player.two_coffee_shirt[1].light", [](const std::string& v) { param.player.two_coffee_shirt[1].light = Color::fromHex(v); }}
|
||||
};
|
||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> COLOR_PARAMS = {
|
||||
{"fade.color", [](const std::string& v) { param.fade.color = Color::fromHex(v); }},
|
||||
{"scoreboard.separator_color", [](const std::string& v) { param.scoreboard.separator_color = Color::fromHex(v); }},
|
||||
{"scoreboard.easy_color", [](const std::string& v) { param.scoreboard.easy_color = Color::fromHex(v); }},
|
||||
{"scoreboard.normal_color", [](const std::string& v) { param.scoreboard.normal_color = Color::fromHex(v); }},
|
||||
{"scoreboard.hard_color", [](const std::string& v) { param.scoreboard.hard_color = Color::fromHex(v); }},
|
||||
{"scoreboard.text_color1", [](const std::string& v) { param.scoreboard.text_color1 = Color::fromHex(v); }},
|
||||
{"scoreboard.text_color2", [](const std::string& v) { param.scoreboard.text_color2 = Color::fromHex(v); }},
|
||||
{"title.bg_color", [](const std::string& v) { param.title.bg_color = Color::fromHex(v); }},
|
||||
{"background.attenuate_color", [](const std::string& v) { param.background.attenuate_color = Color::fromHex(v); }},
|
||||
{"notification.color", [](const std::string& v) { param.notification.color = Color::fromHex(v); }},
|
||||
{"service_menu.title_color", [](const std::string& v) { param.service_menu.title_color = Color::fromHex(v); }},
|
||||
{"service_menu.text_color", [](const std::string& v) { param.service_menu.text_color = Color::fromHex(v); }},
|
||||
{"service_menu.selected_color", [](const std::string& v) { param.service_menu.selected_color = Color::fromHex(v); }},
|
||||
{"service_menu.bg_color", [](const std::string& v) { param.service_menu.bg_color = Color::fromHex(v); }},
|
||||
{"service_menu.window_message.bg_color", [](const std::string& v) { param.service_menu.window_message.bg_color = Color::fromHex(v); }},
|
||||
{"service_menu.window_message.border_color", [](const std::string& v) { param.service_menu.window_message.border_color = Color::fromHex(v); }},
|
||||
{"service_menu.window_message.title_color", [](const std::string& v) { param.service_menu.window_message.title_color = Color::fromHex(v); }},
|
||||
{"service_menu.window_message.text_color", [](const std::string& v) { param.service_menu.window_message.text_color = Color::fromHex(v); }},
|
||||
{"intro.bg_color", [](const std::string& v) { param.intro.bg_color = Color::fromHex(v); }},
|
||||
{"intro.card_color", [](const std::string& v) { param.intro.card_color = Color::fromHex(v); }},
|
||||
{"intro.shadow_color", [](const std::string& v) { param.intro.shadow_color = Color::fromHex(v); }},
|
||||
{"debug.color", [](const std::string& v) { param.debug.color = Color::fromHex(v); }},
|
||||
{"resource.color", [](const std::string& v) { param.resource.color = Color::fromHex(v); }},
|
||||
{"game.item_text_outline_color", [](const std::string& v) { param.game.item_text_outline_color = Color::fromHex(v); }},
|
||||
{"player.default_shirt[0].darkest", [](const std::string& v) { param.player.default_shirt[0].darkest = Color::fromHex(v); }},
|
||||
{"player.default_shirt[0].dark", [](const std::string& v) { param.player.default_shirt[0].dark = Color::fromHex(v); }},
|
||||
{"player.default_shirt[0].base", [](const std::string& v) { param.player.default_shirt[0].base = Color::fromHex(v); }},
|
||||
{"player.default_shirt[0].light", [](const std::string& v) { param.player.default_shirt[0].light = Color::fromHex(v); }},
|
||||
{"player.default_shirt[1].darkest", [](const std::string& v) { param.player.default_shirt[1].darkest = Color::fromHex(v); }},
|
||||
{"player.default_shirt[1].dark", [](const std::string& v) { param.player.default_shirt[1].dark = Color::fromHex(v); }},
|
||||
{"player.default_shirt[1].base", [](const std::string& v) { param.player.default_shirt[1].base = Color::fromHex(v); }},
|
||||
{"player.default_shirt[1].light", [](const std::string& v) { param.player.default_shirt[1].light = Color::fromHex(v); }},
|
||||
{"player.one_coffee_shirt[0].darkest", [](const std::string& v) { param.player.one_coffee_shirt[0].darkest = Color::fromHex(v); }},
|
||||
{"player.one_coffee_shirt[0].dark", [](const std::string& v) { param.player.one_coffee_shirt[0].dark = Color::fromHex(v); }},
|
||||
{"player.one_coffee_shirt[0].base", [](const std::string& v) { param.player.one_coffee_shirt[0].base = Color::fromHex(v); }},
|
||||
{"player.one_coffee_shirt[0].light", [](const std::string& v) { param.player.one_coffee_shirt[0].light = Color::fromHex(v); }},
|
||||
{"player.one_coffee_shirt[1].darkest", [](const std::string& v) { param.player.one_coffee_shirt[1].darkest = Color::fromHex(v); }},
|
||||
{"player.one_coffee_shirt[1].dark", [](const std::string& v) { param.player.one_coffee_shirt[1].dark = Color::fromHex(v); }},
|
||||
{"player.one_coffee_shirt[1].base", [](const std::string& v) { param.player.one_coffee_shirt[1].base = Color::fromHex(v); }},
|
||||
{"player.one_coffee_shirt[1].light", [](const std::string& v) { param.player.one_coffee_shirt[1].light = Color::fromHex(v); }},
|
||||
{"player.two_coffee_shirt[0].darkest", [](const std::string& v) { param.player.two_coffee_shirt[0].darkest = Color::fromHex(v); }},
|
||||
{"player.two_coffee_shirt[0].dark", [](const std::string& v) { param.player.two_coffee_shirt[0].dark = Color::fromHex(v); }},
|
||||
{"player.two_coffee_shirt[0].base", [](const std::string& v) { param.player.two_coffee_shirt[0].base = Color::fromHex(v); }},
|
||||
{"player.two_coffee_shirt[0].light", [](const std::string& v) { param.player.two_coffee_shirt[0].light = Color::fromHex(v); }},
|
||||
{"player.two_coffee_shirt[1].darkest", [](const std::string& v) { param.player.two_coffee_shirt[1].darkest = Color::fromHex(v); }},
|
||||
{"player.two_coffee_shirt[1].dark", [](const std::string& v) { param.player.two_coffee_shirt[1].dark = Color::fromHex(v); }},
|
||||
{"player.two_coffee_shirt[1].base", [](const std::string& v) { param.player.two_coffee_shirt[1].base = Color::fromHex(v); }},
|
||||
{"player.two_coffee_shirt[1].light", [](const std::string& v) { param.player.two_coffee_shirt[1].light = Color::fromHex(v); }},
|
||||
{"player.outline_color[0]", [](const std::string& v) { param.player.outline_color[0] = Color::fromHex(v); }},
|
||||
{"player.outline_color[1]", [](const std::string& v) { param.player.outline_color[1] = Color::fromHex(v); }}};
|
||||
|
||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> BOOL_PARAMS = {
|
||||
{"game.hit_stop", [](const std::string& v) { param.game.hit_stop = stringToBool(v); }},
|
||||
{"scoreboard.separator_autocolor", [](const std::string& v) { param.scoreboard.separator_autocolor = stringToBool(v); }},
|
||||
{"scoreboard.text_autocolor", [](const std::string& v) { param.scoreboard.text_autocolor = stringToBool(v); }},
|
||||
{"balloon.bouncing_sound", [](const std::string& v) { param.balloon.bouncing_sound = stringToBool(v); }},
|
||||
{"notification.sound", [](const std::string& v) { param.notification.sound = stringToBool(v); }},
|
||||
{"service_menu.drop_shadow", [](const std::string& v) { param.service_menu.drop_shadow = stringToBool(v); }}
|
||||
};
|
||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> BOOL_PARAMS = {
|
||||
{"game.hit_stop", [](const std::string& v) { param.game.hit_stop = stringToBool(v); }},
|
||||
{"scoreboard.separator_autocolor", [](const std::string& v) { param.scoreboard.separator_autocolor = stringToBool(v); }},
|
||||
{"scoreboard.text_autocolor", [](const std::string& v) { param.scoreboard.text_autocolor = stringToBool(v); }},
|
||||
{"balloon.bouncing_sound", [](const std::string& v) { param.balloon.bouncing_sound = stringToBool(v); }},
|
||||
{"notification.sound", [](const std::string& v) { param.notification.sound = stringToBool(v); }},
|
||||
{"service_menu.drop_shadow", [](const std::string& v) { param.service_menu.drop_shadow = stringToBool(v); }}};
|
||||
|
||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> FLOAT_PARAMS = {
|
||||
{"balloon.settings[0].vel", [](const std::string& v) { param.balloon.settings.at(0).vel = std::stof(v); }},
|
||||
{"balloon.settings[0].grav", [](const std::string& v) { param.balloon.settings.at(0).grav = std::stof(v); }},
|
||||
{"balloon.settings[1].vel", [](const std::string& v) { param.balloon.settings.at(1).vel = std::stof(v); }},
|
||||
{"balloon.settings[1].grav", [](const std::string& v) { param.balloon.settings.at(1).grav = std::stof(v); }},
|
||||
{"balloon.settings[2].vel", [](const std::string& v) { param.balloon.settings.at(2).vel = std::stof(v); }},
|
||||
{"balloon.settings[2].grav", [](const std::string& v) { param.balloon.settings.at(2).grav = std::stof(v); }},
|
||||
{"balloon.settings[3].vel", [](const std::string& v) { param.balloon.settings.at(3).vel = std::stof(v); }},
|
||||
{"balloon.settings[3].grav", [](const std::string& v) { param.balloon.settings.at(3).grav = std::stof(v); }},
|
||||
{"tabe.min_spawn_time", [](const std::string& v) { param.tabe.min_spawn_time = std::stof(v); }},
|
||||
{"tabe.max_spawn_time", [](const std::string& v) { param.tabe.max_spawn_time = std::stof(v); }},
|
||||
{"service_menu.window_message.padding", [](const std::string& v) { param.service_menu.window_message.padding = std::stof(v); }},
|
||||
{"service_menu.window_message.line_spacing", [](const std::string& v) { param.service_menu.window_message.line_spacing = std::stof(v); }},
|
||||
{"service_menu.window_message.title_separator_spacing", [](const std::string& v) { param.service_menu.window_message.title_separator_spacing = std::stof(v); }},
|
||||
{"service_menu.window_message.min_width", [](const std::string& v) { param.service_menu.window_message.min_width = std::stof(v); }},
|
||||
{"service_menu.window_message.min_height", [](const std::string& v) { param.service_menu.window_message.min_height = std::stof(v); }},
|
||||
{"service_menu.window_message.max_width_ratio", [](const std::string& v) { param.service_menu.window_message.max_width_ratio = std::stof(v); }},
|
||||
{"service_menu.window_message.max_height_ratio", [](const std::string& v) { param.service_menu.window_message.max_height_ratio = std::stof(v); }},
|
||||
{"service_menu.window_message.text_safety_margin", [](const std::string& v) { param.service_menu.window_message.text_safety_margin = std::stof(v); }},
|
||||
{"service_menu.window_message.animation_duration", [](const std::string& v) { param.service_menu.window_message.animation_duration = std::stof(v); }}
|
||||
};
|
||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> FLOAT_PARAMS = {
|
||||
{"balloon.settings[0].vel", [](const std::string& v) { param.balloon.settings.at(0).vel = std::stof(v); }},
|
||||
{"balloon.settings[0].grav", [](const std::string& v) { param.balloon.settings.at(0).grav = std::stof(v); }},
|
||||
{"balloon.settings[1].vel", [](const std::string& v) { param.balloon.settings.at(1).vel = std::stof(v); }},
|
||||
{"balloon.settings[1].grav", [](const std::string& v) { param.balloon.settings.at(1).grav = std::stof(v); }},
|
||||
{"balloon.settings[2].vel", [](const std::string& v) { param.balloon.settings.at(2).vel = std::stof(v); }},
|
||||
{"balloon.settings[2].grav", [](const std::string& v) { param.balloon.settings.at(2).grav = std::stof(v); }},
|
||||
{"balloon.settings[3].vel", [](const std::string& v) { param.balloon.settings.at(3).vel = std::stof(v); }},
|
||||
{"balloon.settings[3].grav", [](const std::string& v) { param.balloon.settings.at(3).grav = std::stof(v); }},
|
||||
{"tabe.min_spawn_time", [](const std::string& v) { param.tabe.min_spawn_time = std::stof(v); }},
|
||||
{"tabe.max_spawn_time", [](const std::string& v) { param.tabe.max_spawn_time = std::stof(v); }},
|
||||
{"service_menu.window_message.padding", [](const std::string& v) { param.service_menu.window_message.padding = std::stof(v); }},
|
||||
{"service_menu.window_message.line_spacing", [](const std::string& v) { param.service_menu.window_message.line_spacing = std::stof(v); }},
|
||||
{"service_menu.window_message.title_separator_spacing", [](const std::string& v) { param.service_menu.window_message.title_separator_spacing = std::stof(v); }},
|
||||
{"service_menu.window_message.min_width", [](const std::string& v) { param.service_menu.window_message.min_width = std::stof(v); }},
|
||||
{"service_menu.window_message.min_height", [](const std::string& v) { param.service_menu.window_message.min_height = std::stof(v); }},
|
||||
{"service_menu.window_message.max_width_ratio", [](const std::string& v) { param.service_menu.window_message.max_width_ratio = std::stof(v); }},
|
||||
{"service_menu.window_message.max_height_ratio", [](const std::string& v) { param.service_menu.window_message.max_height_ratio = std::stof(v); }},
|
||||
{"service_menu.window_message.text_safety_margin", [](const std::string& v) { param.service_menu.window_message.text_safety_margin = std::stof(v); }},
|
||||
{"service_menu.window_message.animation_duration", [](const std::string& v) { param.service_menu.window_message.animation_duration = std::stof(v); }}};
|
||||
|
||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> INT_PARAMS_EXTRA = {
|
||||
};
|
||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> INT_PARAMS_EXTRA = {};
|
||||
|
||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> STRING_PARAMS = {
|
||||
{"balloon.color[0]", [](const std::string& v) { param.balloon.color.at(0) = v; }},
|
||||
{"balloon.color[1]", [](const std::string& v) { param.balloon.color.at(1) = v; }},
|
||||
{"balloon.color[2]", [](const std::string& v) { param.balloon.color.at(2) = v; }},
|
||||
{"balloon.color[3]", [](const std::string& v) { param.balloon.color.at(3) = v; }}
|
||||
};
|
||||
// Colores válidos para globos
|
||||
static const std::unordered_map<std::string, bool> VALID_BALLOON_COLORS = {
|
||||
{"blue", true}, {"orange", true}, {"red", true}, {"green", true}
|
||||
};
|
||||
|
||||
auto validateBalloonColor = [](const std::string& color) -> bool {
|
||||
return VALID_BALLOON_COLORS.find(color) != VALID_BALLOON_COLORS.end();
|
||||
};
|
||||
|
||||
// Lambda para intentar cada mapa de parámetros
|
||||
auto try_map = [&](const auto& param_map) -> bool {
|
||||
auto it = param_map.find(var);
|
||||
if (it != param_map.end()) {
|
||||
it->second(value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Intentar con todos los mapas
|
||||
if (try_map(INT_PARAMS) || try_map(COLOR_PARAMS) || try_map(BOOL_PARAMS) ||
|
||||
try_map(FLOAT_PARAMS) || try_map(STRING_PARAMS)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Casos especiales que necesitan lógica personalizada
|
||||
if (var == "notification.pos_h") {
|
||||
if (value == "LEFT") {
|
||||
param.notification.pos_h = Notifier::Position::LEFT;
|
||||
} else if (value == "MIDDLE") {
|
||||
param.notification.pos_h = Notifier::Position::MIDDLE;
|
||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> STRING_PARAMS = {
|
||||
{"balloon.color[0]", [validateBalloonColor](const std::string& v) {
|
||||
if (!validateBalloonColor(v)) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Color de globo inválido '%s'. Usando 'blue' por defecto.", v.c_str());
|
||||
param.balloon.color.at(0) = "blue";
|
||||
} else {
|
||||
param.notification.pos_h = Notifier::Position::RIGHT;
|
||||
param.balloon.color.at(0) = v;
|
||||
}
|
||||
}},
|
||||
{"balloon.color[1]", [validateBalloonColor](const std::string& v) {
|
||||
if (!validateBalloonColor(v)) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Color de globo inválido '%s'. Usando 'orange' por defecto.", v.c_str());
|
||||
param.balloon.color.at(1) = "orange";
|
||||
} else {
|
||||
param.balloon.color.at(1) = v;
|
||||
}
|
||||
}},
|
||||
{"balloon.color[2]", [validateBalloonColor](const std::string& v) {
|
||||
if (!validateBalloonColor(v)) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Color de globo inválido '%s'. Usando 'red' por defecto.", v.c_str());
|
||||
param.balloon.color.at(2) = "red";
|
||||
} else {
|
||||
param.balloon.color.at(2) = v;
|
||||
}
|
||||
}},
|
||||
{"balloon.color[3]", [validateBalloonColor](const std::string& v) {
|
||||
if (!validateBalloonColor(v)) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Color de globo inválido '%s'. Usando 'green' por defecto.", v.c_str());
|
||||
param.balloon.color.at(3) = "green";
|
||||
} else {
|
||||
param.balloon.color.at(3) = v;
|
||||
}
|
||||
}}};
|
||||
|
||||
// Lambda para intentar cada mapa de parámetros
|
||||
auto try_map = [&](const auto& param_map) -> bool {
|
||||
auto it = param_map.find(var);
|
||||
if (it != param_map.end()) {
|
||||
it->second(value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (var == "notification.pos_v") {
|
||||
param.notification.pos_v = value == "TOP" ? Notifier::Position::TOP : Notifier::Position::BOTTOM;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // Parámetro no encontrado
|
||||
// Intentar con todos los mapas
|
||||
if (try_map(INT_PARAMS) || try_map(COLOR_PARAMS) || try_map(BOOL_PARAMS) ||
|
||||
try_map(FLOAT_PARAMS) || try_map(STRING_PARAMS)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Casos especiales que necesitan lógica personalizada
|
||||
if (var == "notification.pos_h") {
|
||||
if (value == "LEFT") {
|
||||
param.notification.pos_h = Notifier::Position::LEFT;
|
||||
} else if (value == "MIDDLE") {
|
||||
param.notification.pos_h = Notifier::Position::MIDDLE;
|
||||
} else {
|
||||
param.notification.pos_h = Notifier::Position::RIGHT;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (var == "notification.pos_v") {
|
||||
param.notification.pos_v = value == "TOP" ? Notifier::Position::TOP : Notifier::Position::BOTTOM;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // Parámetro no encontrado
|
||||
}
|
||||
} // namespace
|
||||
@@ -22,6 +22,7 @@ struct ParamGame {
|
||||
Uint32 speed = 15; // Este valor no estaba en el archivo de configuración
|
||||
bool hit_stop = GameDefaults::Game::HIT_STOP;
|
||||
Uint32 hit_stop_ms = GameDefaults::Game::HIT_STOP_MS;
|
||||
Color item_text_outline_color;
|
||||
};
|
||||
|
||||
// --- Parámetros del fade ---
|
||||
@@ -29,9 +30,8 @@ struct ParamFade {
|
||||
Color color = Color::fromHex(GameDefaults::Fade::COLOR);
|
||||
float num_squares_width = GameDefaults::Fade::NUM_SQUARES_WIDTH;
|
||||
float num_squares_height = GameDefaults::Fade::NUM_SQUARES_HEIGHT;
|
||||
int random_squares_delay = GameDefaults::Fade::RANDOM_SQUARES_DELAY;
|
||||
int random_squares_mult = GameDefaults::Fade::RANDOM_SQUARES_MULT;
|
||||
int post_duration = GameDefaults::Fade::POST_DURATION;
|
||||
int random_squares_duration_ms = GameDefaults::Fade::RANDOM_SQUARES_DURATION_MS;
|
||||
int post_duration_ms = GameDefaults::Fade::POST_DURATION_MS;
|
||||
float venetian_size = GameDefaults::Fade::VENETIAN_SIZE;
|
||||
};
|
||||
|
||||
@@ -56,7 +56,7 @@ struct ParamBalloon {
|
||||
float vel;
|
||||
|
||||
// Constructor por defecto
|
||||
constexpr Settings(float grav_val = 0.0f, float vel_val = 0.0f)
|
||||
constexpr Settings(float grav_val = 0.0F, float vel_val = 0.0F)
|
||||
: grav(grav_val), vel(vel_val) {}
|
||||
};
|
||||
|
||||
@@ -168,23 +168,51 @@ struct ParamPlayer {
|
||||
};
|
||||
|
||||
// Inicialización con valores por defecto
|
||||
std::array<Shirt, 2> one_coffee_shirt = {{Shirt(Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER0_DARKEST),
|
||||
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER0_DARK),
|
||||
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER0_BASE),
|
||||
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER0_LIGHT)),
|
||||
Shirt(Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER1_DARKEST),
|
||||
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER1_DARK),
|
||||
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER1_BASE),
|
||||
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER1_LIGHT))}};
|
||||
const Shirt default_player0_shirt = Shirt(
|
||||
Color::fromHex(GameDefaults::Player::DefaultShirt::PLAYER0_DARKEST),
|
||||
Color::fromHex(GameDefaults::Player::DefaultShirt::PLAYER0_DARK),
|
||||
Color::fromHex(GameDefaults::Player::DefaultShirt::PLAYER0_BASE),
|
||||
Color::fromHex(GameDefaults::Player::DefaultShirt::PLAYER0_LIGHT));
|
||||
|
||||
std::array<Shirt, 2> two_coffee_shirt = {{Shirt(Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER0_DARKEST),
|
||||
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER0_DARK),
|
||||
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER0_BASE),
|
||||
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER0_LIGHT)),
|
||||
Shirt(Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER1_DARKEST),
|
||||
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER1_DARK),
|
||||
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER1_BASE),
|
||||
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER1_LIGHT))}};
|
||||
const Shirt default_player1_shirt = Shirt(
|
||||
Color::fromHex(GameDefaults::Player::DefaultShirt::PLAYER1_DARKEST),
|
||||
Color::fromHex(GameDefaults::Player::DefaultShirt::PLAYER1_DARK),
|
||||
Color::fromHex(GameDefaults::Player::DefaultShirt::PLAYER1_BASE),
|
||||
Color::fromHex(GameDefaults::Player::DefaultShirt::PLAYER1_LIGHT));
|
||||
|
||||
std::array<Shirt, 2> default_shirt = {default_player0_shirt, default_player1_shirt};
|
||||
|
||||
const Shirt one_coffee_player0_shirt = Shirt(
|
||||
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER0_DARKEST),
|
||||
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER0_DARK),
|
||||
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER0_BASE),
|
||||
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER0_LIGHT));
|
||||
|
||||
const Shirt one_coffee_player1_shirt = Shirt(
|
||||
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER1_DARKEST),
|
||||
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER1_DARK),
|
||||
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER1_BASE),
|
||||
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER1_LIGHT));
|
||||
|
||||
std::array<Shirt, 2> one_coffee_shirt = {one_coffee_player0_shirt, one_coffee_player1_shirt};
|
||||
|
||||
const Shirt two_coffee_player0_shirt = Shirt(
|
||||
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER0_DARKEST),
|
||||
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER0_DARK),
|
||||
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER0_BASE),
|
||||
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER0_LIGHT));
|
||||
|
||||
const Shirt two_coffee_player1_shirt = Shirt(
|
||||
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER1_DARKEST),
|
||||
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER1_DARK),
|
||||
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER1_BASE),
|
||||
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER1_LIGHT));
|
||||
|
||||
std::array<Shirt, 2> two_coffee_shirt = {two_coffee_player0_shirt, two_coffee_player1_shirt};
|
||||
|
||||
const Color outline_player0_color = Color::fromHex(GameDefaults::Player::OutlineColor::PLAYER0);
|
||||
const Color outline_player1_color = Color::fromHex(GameDefaults::Player::OutlineColor::PLAYER1);
|
||||
std::array<Color, 2> outline_color = {outline_player0_color, outline_player1_color};
|
||||
};
|
||||
|
||||
// --- Estructura Param: almacena todos los parámetros del juego ---
|
||||
@@ -207,10 +235,10 @@ struct Param {
|
||||
Param() {
|
||||
// Inicializar play_area usando los valores por defecto
|
||||
game.play_area.rect = {
|
||||
GameDefaults::Game::PLAY_AREA_X,
|
||||
GameDefaults::Game::PLAY_AREA_Y,
|
||||
GameDefaults::Game::PLAY_AREA_W,
|
||||
GameDefaults::Game::PLAY_AREA_H};
|
||||
.x = GameDefaults::Game::PLAY_AREA_X,
|
||||
.y = GameDefaults::Game::PLAY_AREA_Y,
|
||||
.w = GameDefaults::Game::PLAY_AREA_W,
|
||||
.h = GameDefaults::Game::PLAY_AREA_H};
|
||||
|
||||
// Las zonas calculadas se inicializarán en precalculateZones()
|
||||
precalculateZones();
|
||||
|
||||
@@ -11,7 +11,7 @@ auto createPath(float start, float end, PathType type, float fixed_pos, int step
|
||||
|
||||
for (int i = 0; i < steps; ++i) {
|
||||
double t = static_cast<double>(i) / (steps - 1);
|
||||
double value = start + (end - start) * easing_function(t);
|
||||
double value = start + ((end - start) * easing_function(t));
|
||||
|
||||
if ((start > 0 && end < 0) || (start < 0 && end > 0)) {
|
||||
value = start + (end > 0 ? 1 : -1) * std::abs(end - start) * easing_function(t);
|
||||
@@ -56,7 +56,7 @@ void PathSprite::addPath(Path path, bool centered) {
|
||||
|
||||
switch (path_centered) {
|
||||
case PathCentered::ON_X: {
|
||||
const int X = path.spots.back().x - pos_.w / 2;
|
||||
const int X = path.spots.back().x - (pos_.w / 2);
|
||||
for (auto &spot : path.spots) {
|
||||
spot.x = X;
|
||||
}
|
||||
@@ -64,7 +64,7 @@ void PathSprite::addPath(Path path, bool centered) {
|
||||
break;
|
||||
}
|
||||
case PathCentered::ON_Y: {
|
||||
const int Y = path.spots.back().y - pos_.h / 2;
|
||||
const int Y = path.spots.back().y - (pos_.h / 2);
|
||||
for (auto &spot : path.spots) {
|
||||
spot.y = Y;
|
||||
}
|
||||
@@ -83,8 +83,8 @@ void PathSprite::addPath(int start, int end, PathType type, int fixed_pos, int s
|
||||
}
|
||||
|
||||
// Añade un recorrido
|
||||
void PathSprite::addPath(std::vector<SDL_FPoint> spots, int waiting_counter) {
|
||||
paths_.emplace_back(std::move(spots), waiting_counter);
|
||||
void PathSprite::addPath(const std::vector<SDL_FPoint> &spots, int waiting_counter) {
|
||||
paths_.emplace_back(spots, waiting_counter);
|
||||
}
|
||||
|
||||
// Habilita el objeto
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
#include <functional> // Para std::function
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <vector> // Para vector
|
||||
#include <utility>
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "sprite.h" // Para Sprite
|
||||
|
||||
@@ -43,7 +44,7 @@ class PathSprite : public Sprite {
|
||||
public:
|
||||
// --- Constructor y destructor ---
|
||||
explicit PathSprite(std::shared_ptr<Texture> texture)
|
||||
: Sprite(texture) {}
|
||||
: Sprite(std::move(texture)) {}
|
||||
~PathSprite() override = default;
|
||||
|
||||
// --- Métodos principales ---
|
||||
@@ -52,7 +53,7 @@ class PathSprite : public Sprite {
|
||||
|
||||
// --- Gestión de recorridos ---
|
||||
void addPath(Path path, bool centered = false); // Añade un recorrido (Path)
|
||||
void addPath(std::vector<SDL_FPoint> spots, int waiting_counter = 0); // Añade un recorrido a partir de puntos
|
||||
void addPath(const std::vector<SDL_FPoint> &spots, int waiting_counter = 0); // Añade un recorrido a partir de puntos
|
||||
void addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function<double(double)> &easing_function, int waiting_counter = 0); // Añade un recorrido generado
|
||||
|
||||
// --- Estado y control ---
|
||||
|
||||
@@ -115,7 +115,7 @@ class PauseManager {
|
||||
return result;
|
||||
}
|
||||
void setCallback(std::function<void(bool)> callback) { // Permite cambiar el callback en runtime
|
||||
on_pause_changed_callback_ = callback;
|
||||
on_pause_changed_callback_ = std::move(callback);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -22,17 +22,7 @@
|
||||
|
||||
// Constructor
|
||||
Player::Player(const Config &config)
|
||||
: player_sprite_(std::make_unique<AnimatedSprite>(config.texture.at(0), config.animations.at(0))),
|
||||
power_sprite_(std::make_unique<AnimatedSprite>(config.texture.at(4), config.animations.at(1))),
|
||||
enter_name_(std::make_unique<EnterName>()),
|
||||
hi_score_table_(config.hi_score_table),
|
||||
glowing_entry_(config.glowing_entry),
|
||||
stage_info_(config.stage_info),
|
||||
play_area_(*config.play_area),
|
||||
id_(config.id),
|
||||
default_pos_x_(config.x),
|
||||
default_pos_y_(config.y),
|
||||
demo_(config.demo) {
|
||||
: player_sprite_(std::make_unique<AnimatedSprite>(config.texture.at(0), config.animations.at(0))), power_sprite_(std::make_unique<AnimatedSprite>(config.texture.at(4), config.animations.at(1))), enter_name_(std::make_unique<EnterName>()), hi_score_table_(config.hi_score_table), glowing_entry_(config.glowing_entry), stage_info_(config.stage_info), play_area_(*config.play_area), id_(config.id), default_pos_x_(config.x), default_pos_y_(config.y), demo_(config.demo) {
|
||||
// Configura objetos
|
||||
player_sprite_->addTexture(config.texture.at(1));
|
||||
player_sprite_->addTexture(config.texture.at(2));
|
||||
@@ -199,7 +189,7 @@ void Player::handlePlayingMovement() {
|
||||
}
|
||||
|
||||
void Player::handleRecoverMovement() {
|
||||
if (player_sprite_->getCurrentAnimationFrame() == 10) { playSound("voice_brbrbr.wav"); }
|
||||
if (player_sprite_->getCurrentAnimationFrame() == 10) { playSound("voice_recover.wav"); }
|
||||
if (player_sprite_->animationIsCompleted()) { setPlayingState(State::RESPAWNING); }
|
||||
}
|
||||
|
||||
@@ -646,7 +636,7 @@ void Player::setPlayingState(State state) {
|
||||
init();
|
||||
setInvulnerable(true);
|
||||
setScoreboardMode(Scoreboard::Mode::SCORE);
|
||||
stage_info_->canCollectPower();
|
||||
stage_info_->enablePowerCollection();
|
||||
break;
|
||||
}
|
||||
case State::CONTINUE: {
|
||||
@@ -788,15 +778,30 @@ void Player::setInvulnerable(bool value) {
|
||||
|
||||
// Monitoriza el estado
|
||||
void Player::updateInvulnerable() {
|
||||
if (playing_state_ == State::PLAYING) {
|
||||
if (invulnerable_) {
|
||||
if (invulnerable_counter_ > 0) {
|
||||
--invulnerable_counter_;
|
||||
invulnerable_counter_ % 8 > 3 ? player_sprite_->setActiveTexture(coffees_) : player_sprite_->setActiveTexture(3);
|
||||
} else {
|
||||
setInvulnerable(false);
|
||||
player_sprite_->setActiveTexture(coffees_);
|
||||
if (playing_state_ == State::PLAYING && invulnerable_) {
|
||||
if (invulnerable_counter_ > 0) {
|
||||
--invulnerable_counter_;
|
||||
|
||||
// Frecuencia fija de parpadeo (como el original)
|
||||
constexpr int blink_speed = 8;
|
||||
|
||||
// Calcula proporción decreciente: menos textura blanca hacia el final
|
||||
// Al inicio: 50-50, hacia el final: 70-30 (menos blanco)
|
||||
float progress = 1.0f - (static_cast<float>(invulnerable_counter_) / INVULNERABLE_COUNTER);
|
||||
int white_frames = static_cast<int>((0.5f - progress * 0.2f) * blink_speed);
|
||||
|
||||
// Alterna entre texturas con proporción variable
|
||||
bool should_show_invulnerable = (invulnerable_counter_ % blink_speed) < white_frames;
|
||||
size_t target_texture = should_show_invulnerable ? INVULNERABLE_TEXTURE : coffees_;
|
||||
|
||||
// Solo cambia textura si es diferente (optimización)
|
||||
if (player_sprite_->getActiveTexture() != target_texture) {
|
||||
player_sprite_->setActiveTexture(target_texture);
|
||||
}
|
||||
} else {
|
||||
// Fin de invulnerabilidad
|
||||
setInvulnerable(false);
|
||||
player_sprite_->setActiveTexture(coffees_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,16 +77,16 @@ class Player {
|
||||
|
||||
// --- Estructuras ---
|
||||
struct Config {
|
||||
Id id; // Identificador del jugador
|
||||
float x; // Posición X inicial
|
||||
int y; // Posición Y inicial
|
||||
bool demo; // Modo demo
|
||||
SDL_FRect *play_area; // Área de juego (puntero para mantener referencia)
|
||||
std::vector<std::shared_ptr<Texture>> texture; // Texturas del jugador
|
||||
std::vector<std::vector<std::string>> animations; // Animaciones del jugador
|
||||
Table *hi_score_table; // Tabla de puntuaciones (puntero para referencia)
|
||||
int *glowing_entry; // Entrada brillante (puntero para mantener referencia)
|
||||
IStageInfo *stage_info; // Gestor de pantallas (puntero)
|
||||
Id id; // Identificador del jugador
|
||||
float x; // Posición X inicial
|
||||
int y; // Posición Y inicial
|
||||
bool demo; // Modo demo
|
||||
SDL_FRect *play_area; // Área de juego (puntero para mantener referencia)
|
||||
std::vector<std::shared_ptr<Texture>> texture; // Texturas del jugador
|
||||
std::vector<std::vector<std::string>> animations; // Animaciones del jugador
|
||||
Table *hi_score_table; // Tabla de puntuaciones (puntero para referencia)
|
||||
int *glowing_entry; // Entrada brillante (puntero para mantener referencia)
|
||||
IStageInfo *stage_info; // Gestor de pantallas (puntero)
|
||||
};
|
||||
|
||||
// --- Constructor y destructor ---
|
||||
@@ -184,21 +184,22 @@ class Player {
|
||||
void setScoreBoardPanel(Scoreboard::Id panel) { scoreboard_panel_ = panel; }
|
||||
void setScoreMultiplier(float value) { score_multiplier_ = value; }
|
||||
void setWalkingState(State state) { walking_state_ = state; }
|
||||
|
||||
|
||||
void addCredit();
|
||||
void setGamepad(std::shared_ptr<Input::Gamepad> gamepad) { gamepad_ = gamepad; }
|
||||
void setGamepad(std::shared_ptr<Input::Gamepad> gamepad) { gamepad_ = std::move(gamepad); }
|
||||
[[nodiscard]] auto getGamepad() const -> std::shared_ptr<Input::Gamepad> { return gamepad_; }
|
||||
void setUsesKeyboard(bool value) { uses_keyboard_ = value; }
|
||||
[[nodiscard]] auto getUsesKeyboard() const -> bool { return uses_keyboard_; }
|
||||
|
||||
private:
|
||||
// --- Constantes ---
|
||||
static constexpr int POWERUP_COUNTER = 1500; // Duración del estado PowerUp
|
||||
static constexpr int INVULNERABLE_COUNTER = 200; // Duración del estado invulnerable
|
||||
static constexpr float BASE_SPEED = 1.5F; // Velocidad base del jugador
|
||||
static constexpr int COOLING_DURATION = 50;
|
||||
static constexpr int COOLING_COMPLETE = 0;
|
||||
static constexpr int WAITING_COUNTER = 1000;
|
||||
static constexpr int POWERUP_COUNTER = 1500; // Duración del estado PowerUp
|
||||
static constexpr int INVULNERABLE_COUNTER = 200; // Duración del estado invulnerable
|
||||
static constexpr size_t INVULNERABLE_TEXTURE = 3; // Textura usada durante invulnerabilidad
|
||||
static constexpr float BASE_SPEED = 1.5F; // Velocidad base del jugador
|
||||
static constexpr int COOLING_DURATION = 50; // Duración del enfriamiento tras disparar
|
||||
static constexpr int COOLING_COMPLETE = 0; // Valor que indica enfriamiento completado
|
||||
static constexpr int WAITING_COUNTER = 1000; // Tiempo de espera en estado de espera
|
||||
|
||||
// --- Objetos y punteros ---
|
||||
std::unique_ptr<AnimatedSprite> player_sprite_; // Sprite para dibujar el jugador
|
||||
@@ -220,7 +221,7 @@ class Player {
|
||||
State firing_state_ = State::FIRING_NONE; // Estado del jugador al disparar
|
||||
State playing_state_ = State::WAITING; // Estado del jugador en el juego
|
||||
|
||||
Uint32 continue_ticks_ = 0; // Variable para poder cambiar el contador de continue en función del tiempo
|
||||
Uint32 continue_ticks_ = 0; // Variable para poder cambiar el contador de continue en función del tiempo
|
||||
Uint32 name_entry_ticks_ = 0; // Variable para poder cambiar el contador de poner nombre en función del tiempo
|
||||
Uint32 showing_name_ticks_ = 0; // Tiempo en el que se entra al estado SHOWING_NAME
|
||||
float pos_x_ = 0.0F; // Posición en el eje X
|
||||
@@ -246,7 +247,7 @@ class Player {
|
||||
int step_counter_ = 0; // Cuenta los pasos para los estados en los que camina automáticamente
|
||||
int credits_used_ = 0; // Indica el número de veces que ha continuado
|
||||
int waiting_counter_ = 0; // Contador para el estado de espera
|
||||
bool qualifies_for_high_score_ = false; // Indica si tiene una puntuación que le permite entrar en la tabla de records
|
||||
bool qualifies_for_high_score_ = false; // Indica si tiene una puntuación que le permite entrar en la tabla de records
|
||||
bool invulnerable_ = true; // Indica si el jugador es invulnerable
|
||||
bool extra_hit_ = false; // Indica si el jugador tiene un toque extra
|
||||
bool power_up_ = false; // Indica si el jugador tiene activo el modo PowerUp
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
|
||||
#include <algorithm> // Para find_if, max, find
|
||||
#include <array> // Para array
|
||||
#include <cstdlib> // Para exit
|
||||
#include <cstdlib> // Para exit, getenv
|
||||
#include <filesystem> // Para filesystem::remove, filesystem::exists
|
||||
#include <fstream> // Para ofstream
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <utility> // Para move
|
||||
|
||||
@@ -17,10 +19,41 @@
|
||||
#include "param.h" // Para Param, param, ParamResource, ParamGame
|
||||
#include "screen.h" // Para Screen
|
||||
#include "text.h" // Para Text
|
||||
#include "resource_helper.h" // Para ResourceHelper
|
||||
|
||||
struct JA_Music_t; // lines 11-11
|
||||
struct JA_Sound_t; // lines 12-12
|
||||
|
||||
// Helper para cargar archivos de audio desde pack o filesystem
|
||||
namespace {
|
||||
std::string createTempAudioFile(const std::string& file_path, std::vector<std::string>& temp_files_tracker) {
|
||||
auto resource_data = ResourceHelper::loadFile(file_path);
|
||||
if (!resource_data.empty()) {
|
||||
// Crear archivo temporal
|
||||
std::string temp_dir;
|
||||
#ifdef _WIN32
|
||||
temp_dir = std::getenv("TEMP") ? std::getenv("TEMP") : "C:\\temp";
|
||||
#else
|
||||
temp_dir = "/tmp";
|
||||
#endif
|
||||
std::string temp_path = temp_dir + "/ccae_audio_" + std::to_string(std::hash<std::string>{}(file_path));
|
||||
std::ofstream temp_file(temp_path, std::ios::binary);
|
||||
if (!temp_file) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Cannot create temp file %s", temp_path.c_str());
|
||||
return file_path;
|
||||
}
|
||||
temp_file.write(reinterpret_cast<const char*>(resource_data.data()), resource_data.size());
|
||||
temp_file.close();
|
||||
|
||||
// Agregar a la lista de archivos temporales para limpieza posterior
|
||||
temp_files_tracker.push_back(temp_path);
|
||||
|
||||
return temp_path;
|
||||
}
|
||||
return file_path; // Usar ruta original si no está en pack
|
||||
}
|
||||
}
|
||||
|
||||
// Declaraciones de funciones que necesitas implementar en otros archivos
|
||||
|
||||
// Singleton
|
||||
@@ -55,6 +88,7 @@ Resource::Resource(LoadingMode mode)
|
||||
|
||||
// Destructor
|
||||
Resource::~Resource() {
|
||||
cleanupTempAudioFiles();
|
||||
clear();
|
||||
}
|
||||
|
||||
@@ -80,7 +114,7 @@ void Resource::loadTextFilesQuiet() {
|
||||
for (const auto &l : list) {
|
||||
auto name = getFileName(l);
|
||||
// Buscar en nuestra lista y cargar directamente
|
||||
auto it = std::find_if(text_files_.begin(), text_files_.end(), [&name](const auto &t) { return t.name == name; });
|
||||
auto it = std::ranges::find_if(text_files_, [&name](const auto &t) { return t.name == name; });
|
||||
if (it != text_files_.end()) {
|
||||
it->text_file = Text::loadFile(l);
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Text file loaded: %s", name.c_str());
|
||||
@@ -109,9 +143,9 @@ void Resource::loadEssentialTextures() {
|
||||
for (const auto &file : texture_list) {
|
||||
auto name = getFileName(file);
|
||||
// Solo cargar texturas esenciales
|
||||
if (std::find(ESSENTIAL_TEXTURES.begin(), ESSENTIAL_TEXTURES.end(), name) != ESSENTIAL_TEXTURES.end()) {
|
||||
if (std::ranges::find(ESSENTIAL_TEXTURES, name) != ESSENTIAL_TEXTURES.end()) {
|
||||
// Buscar en nuestra lista y cargar
|
||||
auto it = std::find_if(textures_.begin(), textures_.end(), [&name](const auto &t) { return t.name == name; });
|
||||
auto it = std::ranges::find_if(textures_, [&name](const auto &t) { return t.name == name; });
|
||||
if (it != textures_.end()) {
|
||||
it->texture = std::make_shared<Texture>(Screen::get()->getRenderer(), file);
|
||||
}
|
||||
@@ -186,7 +220,7 @@ void Resource::initResourceLists() {
|
||||
|
||||
// Obtiene el sonido a partir de un nombre (con carga perezosa)
|
||||
auto Resource::getSound(const std::string &name) -> JA_Sound_t * {
|
||||
auto it = std::find_if(sounds_.begin(), sounds_.end(), [&name](const auto &s) { return s.name == name; });
|
||||
auto it = std::ranges::find_if(sounds_, [&name](const auto &s) { return s.name == name; });
|
||||
|
||||
if (it != sounds_.end()) {
|
||||
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
||||
@@ -202,7 +236,7 @@ auto Resource::getSound(const std::string &name) -> JA_Sound_t * {
|
||||
|
||||
// Obtiene la música a partir de un nombre (con carga perezosa)
|
||||
auto Resource::getMusic(const std::string &name) -> JA_Music_t * {
|
||||
auto it = std::find_if(musics_.begin(), musics_.end(), [&name](const auto &m) { return m.name == name; });
|
||||
auto it = std::ranges::find_if(musics_, [&name](const auto &m) { return m.name == name; });
|
||||
|
||||
if (it != musics_.end()) {
|
||||
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
||||
@@ -218,7 +252,7 @@ auto Resource::getMusic(const std::string &name) -> JA_Music_t * {
|
||||
|
||||
// Obtiene la textura a partir de un nombre (con carga perezosa)
|
||||
auto Resource::getTexture(const std::string &name) -> std::shared_ptr<Texture> {
|
||||
auto it = std::find_if(textures_.begin(), textures_.end(), [&name](const auto &t) { return t.name == name; });
|
||||
auto it = std::ranges::find_if(textures_, [&name](const auto &t) { return t.name == name; });
|
||||
|
||||
if (it != textures_.end()) {
|
||||
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
||||
@@ -234,7 +268,7 @@ auto Resource::getTexture(const std::string &name) -> std::shared_ptr<Texture> {
|
||||
|
||||
// Obtiene el fichero de texto a partir de un nombre (con carga perezosa)
|
||||
auto Resource::getTextFile(const std::string &name) -> std::shared_ptr<Text::File> {
|
||||
auto it = std::find_if(text_files_.begin(), text_files_.end(), [&name](const auto &t) { return t.name == name; });
|
||||
auto it = std::ranges::find_if(text_files_, [&name](const auto &t) { return t.name == name; });
|
||||
|
||||
if (it != text_files_.end()) {
|
||||
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
||||
@@ -250,7 +284,7 @@ auto Resource::getTextFile(const std::string &name) -> std::shared_ptr<Text::Fil
|
||||
|
||||
// Obtiene el objeto de texto a partir de un nombre (con carga perezosa)
|
||||
auto Resource::getText(const std::string &name) -> std::shared_ptr<Text> {
|
||||
auto it = std::find_if(texts_.begin(), texts_.end(), [&name](const auto &t) { return t.name == name; });
|
||||
auto it = std::ranges::find_if(texts_, [&name](const auto &t) { return t.name == name; });
|
||||
|
||||
if (it != texts_.end()) {
|
||||
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
||||
@@ -266,7 +300,7 @@ auto Resource::getText(const std::string &name) -> std::shared_ptr<Text> {
|
||||
|
||||
// Obtiene la animación a partir de un nombre (con carga perezosa)
|
||||
auto Resource::getAnimation(const std::string &name) -> AnimationsFileBuffer & {
|
||||
auto it = std::find_if(animations_.begin(), animations_.end(), [&name](const auto &a) { return a.name == name; });
|
||||
auto it = std::ranges::find_if(animations_, [&name](const auto &a) { return a.name == name; });
|
||||
|
||||
if (it != animations_.end()) {
|
||||
// Si está en modo lazy y no se ha cargado aún (vector vacío), lo carga ahora
|
||||
@@ -293,7 +327,8 @@ auto Resource::loadSoundLazy(const std::string &name) -> JA_Sound_t * {
|
||||
auto sound_list = Asset::get()->getListByType(Asset::Type::SOUND);
|
||||
for (const auto &file : sound_list) {
|
||||
if (getFileName(file) == name) {
|
||||
return JA_LoadSound(file.c_str());
|
||||
std::string audio_path = createTempAudioFile(file, Resource::get()->temp_audio_files_);
|
||||
return JA_LoadSound(audio_path.c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -306,7 +341,8 @@ auto Resource::loadMusicLazy(const std::string &name) -> JA_Music_t * {
|
||||
auto music_list = Asset::get()->getListByType(Asset::Type::MUSIC);
|
||||
for (const auto &file : music_list) {
|
||||
if (getFileName(file) == name) {
|
||||
return JA_LoadMusic(file.c_str());
|
||||
std::string audio_path = createTempAudioFile(file, Resource::get()->temp_audio_files_);
|
||||
return JA_LoadMusic(audio_path.c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -346,18 +382,18 @@ auto Resource::loadTextLazy(const std::string &name) -> std::shared_ptr<Text> {
|
||||
};
|
||||
|
||||
const std::vector<TextMapping> TEXT_MAPPINGS = {
|
||||
{"04b_25", "04b_25.png", "04b_25.txt"},
|
||||
{"04b_25_2x", "04b_25_2x.png", "04b_25_2x.txt"},
|
||||
{"04b_25_metal", "04b_25_metal.png", "04b_25.txt"},
|
||||
{"04b_25_grey", "04b_25_grey.png", "04b_25.txt"},
|
||||
{"04b_25_flat", "04b_25_flat.png", "04b_25.txt"},
|
||||
{"04b_25_reversed", "04b_25_reversed.png", "04b_25.txt"},
|
||||
{"04b_25_flat_2x", "04b_25_flat_2x.png", "04b_25_2x.txt"},
|
||||
{"04b_25_reversed_2x", "04b_25_reversed_2x.png", "04b_25_2x.txt"},
|
||||
{"8bithud", "8bithud.png", "8bithud.txt"},
|
||||
{"aseprite", "aseprite.png", "aseprite.txt"},
|
||||
{"smb2", "smb2.png", "smb2.txt"},
|
||||
{"smb2_grad", "smb2_grad.png", "smb2.txt"}};
|
||||
{.key = "04b_25", .texture_file = "04b_25.png", .text_file = "04b_25.txt"},
|
||||
{.key = "04b_25_2x", .texture_file = "04b_25_2x.png", .text_file = "04b_25_2x.txt"},
|
||||
{.key = "04b_25_metal", .texture_file = "04b_25_metal.png", .text_file = "04b_25.txt"},
|
||||
{.key = "04b_25_grey", .texture_file = "04b_25_grey.png", .text_file = "04b_25.txt"},
|
||||
{.key = "04b_25_flat", .texture_file = "04b_25_flat.png", .text_file = "04b_25.txt"},
|
||||
{.key = "04b_25_reversed", .texture_file = "04b_25_reversed.png", .text_file = "04b_25.txt"},
|
||||
{.key = "04b_25_flat_2x", .texture_file = "04b_25_flat_2x.png", .text_file = "04b_25_2x.txt"},
|
||||
{.key = "04b_25_reversed_2x", .texture_file = "04b_25_reversed_2x.png", .text_file = "04b_25_2x.txt"},
|
||||
{.key = "8bithud", .texture_file = "8bithud.png", .text_file = "8bithud.txt"},
|
||||
{.key = "aseprite", .texture_file = "aseprite.png", .text_file = "aseprite.txt"},
|
||||
{.key = "smb2", .texture_file = "smb2.png", .text_file = "smb2.txt"},
|
||||
{.key = "smb2_grad", .texture_file = "smb2_grad.png", .text_file = "smb2.txt"}};
|
||||
|
||||
for (const auto &mapping : TEXT_MAPPINGS) {
|
||||
if (mapping.key == name) {
|
||||
@@ -448,7 +484,8 @@ void Resource::loadSounds() {
|
||||
auto name = getFileName(l);
|
||||
updateLoadingProgress(name);
|
||||
#ifndef NO_AUDIO
|
||||
sounds_.emplace_back(name, JA_LoadSound(l.c_str()));
|
||||
std::string audio_path = createTempAudioFile(l, temp_audio_files_);
|
||||
sounds_.emplace_back(name, JA_LoadSound(audio_path.c_str()));
|
||||
#else
|
||||
sounds_.emplace_back(name, nullptr);
|
||||
#endif
|
||||
@@ -466,7 +503,8 @@ void Resource::loadMusics() {
|
||||
auto name = getFileName(l);
|
||||
updateLoadingProgress(name);
|
||||
#ifndef NO_AUDIO
|
||||
musics_.emplace_back(name, JA_LoadMusic(l.c_str()));
|
||||
std::string audio_path = createTempAudioFile(l, temp_audio_files_);
|
||||
musics_.emplace_back(name, JA_LoadMusic(audio_path.c_str()));
|
||||
#else
|
||||
musics_.emplace_back(name, nullptr);
|
||||
#endif
|
||||
@@ -531,18 +569,18 @@ void Resource::createPlayerTextures() {
|
||||
|
||||
// Configuración de jugadores y sus paletas
|
||||
struct PlayerConfig {
|
||||
std::string base_texture;
|
||||
std::vector<std::string> palette_files;
|
||||
std::string name_prefix;
|
||||
std::string base_texture;
|
||||
std::vector<std::string> palette_files;
|
||||
std::string name_prefix;
|
||||
};
|
||||
|
||||
std::vector<PlayerConfig> players = {
|
||||
{"player1.gif", {"player1_coffee1.pal", "player1_coffee2.pal", "player1_invencible.pal"}, "player1"},
|
||||
{"player2.gif", {"player2_coffee1.pal", "player2_coffee2.pal", "player2_invencible.pal"}, "player2"}};
|
||||
{.base_texture = "player1.gif", .palette_files = {"player1_coffee1.pal", "player1_coffee2.pal", "player1_invencible.pal"}, .name_prefix = "player1"},
|
||||
{.base_texture = "player2.gif", .palette_files = {"player2_coffee1.pal", "player2_coffee2.pal", "player2_invencible.pal"}, .name_prefix = "player2"}};
|
||||
|
||||
// Bucle principal modificado para usar un índice (player_idx)
|
||||
// Bucle principal
|
||||
for (size_t player_idx = 0; player_idx < players.size(); ++player_idx) {
|
||||
const auto &player = players[player_idx]; // Obtenemos el jugador actual
|
||||
const auto &player = players[player_idx]; // Obtenemos el jugador actual
|
||||
|
||||
// Encontrar el archivo original de la textura
|
||||
std::string texture_file_path;
|
||||
@@ -554,40 +592,52 @@ void Resource::createPlayerTextures() {
|
||||
}
|
||||
}
|
||||
|
||||
// Crear variante con paleta original (pal0) - usar la textura ya cargada
|
||||
auto base_texture = getTexture(player.base_texture);
|
||||
std::string pal0_name = player.name_prefix + "_pal0";
|
||||
textures_.emplace_back(pal0_name, base_texture);
|
||||
printWithDots("Player Texture : ", pal0_name, "[ DONE ]");
|
||||
// Crear las 4 texturas con sus respectivas paletas
|
||||
for (int palette_idx = 0; palette_idx < 4; ++palette_idx) {
|
||||
std::shared_ptr<Texture> texture;
|
||||
|
||||
// Crear variantes con paletas adicionales - CADA UNA DESDE EL ARCHIVO
|
||||
for (size_t i = 0; i < player.palette_files.size(); ++i) {
|
||||
// Crear textura completamente nueva desde el archivo
|
||||
auto texture_copy = std::make_shared<Texture>(Screen::get()->getRenderer(), texture_file_path);
|
||||
if (palette_idx == 0) {
|
||||
// Textura 0 - usar la ya cargada y modificar solo paleta 0 (default_shirt)
|
||||
texture = getTexture(player.base_texture);
|
||||
texture->setPaletteColor(0, 16, param.player.default_shirt[player_idx].darkest.TO_UINT32());
|
||||
texture->setPaletteColor(0, 17, param.player.default_shirt[player_idx].dark.TO_UINT32());
|
||||
texture->setPaletteColor(0, 18, param.player.default_shirt[player_idx].base.TO_UINT32());
|
||||
texture->setPaletteColor(0, 19, param.player.default_shirt[player_idx].light.TO_UINT32());
|
||||
texture->setPaletteColor(0, 56, param.player.outline_color[player_idx].TO_UINT32());
|
||||
} else {
|
||||
// Crear textura nueva desde archivo usando ResourceHelper
|
||||
texture = std::make_shared<Texture>(Screen::get()->getRenderer(), texture_file_path);
|
||||
|
||||
// Añadir todas las paletas
|
||||
texture_copy->addPaletteFromPalFile(Asset::get()->get(player.palette_files[0]));
|
||||
texture_copy->addPaletteFromPalFile(Asset::get()->get(player.palette_files[1]));
|
||||
texture_copy->addPaletteFromPalFile(Asset::get()->get(player.palette_files[2]));
|
||||
// Añadir todas las paletas
|
||||
texture->addPaletteFromPalFile(Asset::get()->get(player.palette_files[0]));
|
||||
texture->addPaletteFromPalFile(Asset::get()->get(player.palette_files[1]));
|
||||
texture->addPaletteFromPalFile(Asset::get()->get(player.palette_files[2]));
|
||||
|
||||
// Añade los colores establecidos en param.player usando el índice del jugador (player_idx)
|
||||
texture_copy->setPaletteColor(1, 16, param.player.one_coffee_shirt[player_idx].darkest.toUint32());
|
||||
texture_copy->setPaletteColor(1, 17, param.player.one_coffee_shirt[player_idx].dark.toUint32());
|
||||
texture_copy->setPaletteColor(1, 18, param.player.one_coffee_shirt[player_idx].base.toUint32());
|
||||
texture_copy->setPaletteColor(1, 19, param.player.one_coffee_shirt[player_idx].light.toUint32());
|
||||
if (palette_idx == 1) {
|
||||
// Textura 1 - modificar solo paleta 1 (one_coffee_shirt)
|
||||
texture->setPaletteColor(1, 16, param.player.one_coffee_shirt[player_idx].darkest.TO_UINT32());
|
||||
texture->setPaletteColor(1, 17, param.player.one_coffee_shirt[player_idx].dark.TO_UINT32());
|
||||
texture->setPaletteColor(1, 18, param.player.one_coffee_shirt[player_idx].base.TO_UINT32());
|
||||
texture->setPaletteColor(1, 19, param.player.one_coffee_shirt[player_idx].light.TO_UINT32());
|
||||
texture->setPaletteColor(1, 56, param.player.outline_color[player_idx].TO_UINT32());
|
||||
} else if (palette_idx == 2) {
|
||||
// Textura 2 - modificar solo paleta 2 (two_coffee_shirt)
|
||||
texture->setPaletteColor(2, 16, param.player.two_coffee_shirt[player_idx].darkest.TO_UINT32());
|
||||
texture->setPaletteColor(2, 17, param.player.two_coffee_shirt[player_idx].dark.TO_UINT32());
|
||||
texture->setPaletteColor(2, 18, param.player.two_coffee_shirt[player_idx].base.TO_UINT32());
|
||||
texture->setPaletteColor(2, 19, param.player.two_coffee_shirt[player_idx].light.TO_UINT32());
|
||||
texture->setPaletteColor(2, 56, param.player.outline_color[player_idx].TO_UINT32());
|
||||
}
|
||||
// Textura 3 (palette_idx == 3) - no modificar nada, usar colores originales
|
||||
}
|
||||
|
||||
texture_copy->setPaletteColor(2, 16, param.player.two_coffee_shirt[player_idx].darkest.toUint32());
|
||||
texture_copy->setPaletteColor(2, 17, param.player.two_coffee_shirt[player_idx].dark.toUint32());
|
||||
texture_copy->setPaletteColor(2, 18, param.player.two_coffee_shirt[player_idx].base.toUint32());
|
||||
texture_copy->setPaletteColor(2, 19, param.player.two_coffee_shirt[player_idx].light.toUint32());
|
||||
|
||||
// Cambiar a la paleta específica (índice i+1 porque 0 es la original)
|
||||
texture_copy->setPalette(i + 1);
|
||||
// Asignar la paleta correspondiente
|
||||
texture->setPalette(palette_idx);
|
||||
|
||||
// Guardar con nombre específico
|
||||
std::string variant_name = player.name_prefix + "_pal" + std::to_string(i + 1);
|
||||
textures_.emplace_back(variant_name, texture_copy);
|
||||
printWithDots("Player Texture : ", variant_name, "[ DONE ]");
|
||||
std::string texture_name = player.name_prefix + "_pal" + std::to_string(palette_idx);
|
||||
textures_.emplace_back(texture_name, texture);
|
||||
printWithDots("Player Texture : ", texture_name, "[ DONE ]");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -604,33 +654,42 @@ void Resource::createTextTextures() {
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> CREATING TEXTURES");
|
||||
|
||||
// Texturas de tamaño normal
|
||||
std::vector<NameAndText> strings = {
|
||||
// Texturas de tamaño normal con outline
|
||||
std::vector<NameAndText> strings1 = {
|
||||
{"game_text_1000_points", "1.000"},
|
||||
{"game_text_2500_points", "2.500"},
|
||||
{"game_text_5000_points", "5.000"},
|
||||
{"game_text_powerup", Lang::getText("[GAME_TEXT] 4")},
|
||||
{"game_text_one_hit", Lang::getText("[GAME_TEXT] 5")},
|
||||
{"game_text_stop", Lang::getText("[GAME_TEXT] 6")},
|
||||
{"game_text_stop", Lang::getText("[GAME_TEXT] 6")}};
|
||||
|
||||
auto text1 = getText("04b_25_enhanced");
|
||||
for (const auto &s : strings1) {
|
||||
textures_.emplace_back(s.name, text1->writeDXToTexture(Text::STROKE, s.text, -2, Colors::NO_COLOR_MOD, 1, param.game.item_text_outline_color));
|
||||
printWithDots("Texture : ", s.name, "[ DONE ]");
|
||||
}
|
||||
|
||||
// Texturas de tamaño normal
|
||||
std::vector<NameAndText> strings2 = {
|
||||
{"game_text_1000000_points", Lang::getText("[GAME_TEXT] 8")}};
|
||||
|
||||
auto text = getText("04b_25");
|
||||
for (const auto &s : strings) {
|
||||
textures_.emplace_back(s.name, text->writeToTexture(s.text, 1, -2));
|
||||
auto text2 = getText("04b_25");
|
||||
for (const auto &s : strings2) {
|
||||
textures_.emplace_back(s.name, text2->writeDXToTexture(Text::STROKE, s.text, -2, Colors::NO_COLOR_MOD, 1, param.game.item_text_outline_color));
|
||||
printWithDots("Texture : ", s.name, "[ DONE ]");
|
||||
}
|
||||
|
||||
// Texturas de tamaño doble
|
||||
std::vector<NameAndText> strings2_x = {
|
||||
std::vector<NameAndText> strings3 = {
|
||||
{"game_text_100000_points", "100.000"},
|
||||
{"game_text_get_ready", Lang::getText("[GAME_TEXT] 7")},
|
||||
{"game_text_last_stage", Lang::getText("[GAME_TEXT] 3")},
|
||||
{"game_text_congratulations", Lang::getText("[GAME_TEXT] 1")},
|
||||
{"game_text_game_over", "Game Over"}};
|
||||
|
||||
auto text2 = getText("04b_25_2x");
|
||||
for (const auto &s : strings2_x) {
|
||||
textures_.emplace_back(s.name, text2->writeToTexture(s.text, 1, -4));
|
||||
auto text3 = getText("04b_25_2x");
|
||||
for (const auto &s : strings3) {
|
||||
textures_.emplace_back(s.name, text3->writeToTexture(s.text, 1, -4));
|
||||
printWithDots("Texture : ", s.name, "[ DONE ]");
|
||||
}
|
||||
}
|
||||
@@ -641,15 +700,18 @@ void Resource::createText() {
|
||||
std::string key;
|
||||
std::string texture_file;
|
||||
std::string text_file;
|
||||
std::string white_texture_file; // Textura blanca opcional
|
||||
|
||||
ResourceInfo(std::string k, std::string t_file, std::string txt_file)
|
||||
: key(std::move(k)), texture_file(std::move(t_file)), text_file(std::move(txt_file)) {}
|
||||
ResourceInfo(std::string k, std::string t_file, std::string txt_file, std::string w_file = "")
|
||||
: key(std::move(k)), texture_file(std::move(t_file)), text_file(std::move(txt_file)), white_texture_file(std::move(w_file)) {}
|
||||
};
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> CREATING TEXT OBJECTS");
|
||||
|
||||
std::vector<ResourceInfo> resources = {
|
||||
{"04b_25", "04b_25.png", "04b_25.txt"},
|
||||
{"04b_25_enhanced", "04b_25.png", "04b_25.txt", "04b_25_white.png"}, // Nueva fuente con textura blanca
|
||||
{"04b_25_white", "04b_25_white.png", "04b_25.txt"},
|
||||
{"04b_25_2x", "04b_25_2x.png", "04b_25_2x.txt"},
|
||||
{"04b_25_metal", "04b_25_metal.png", "04b_25.txt"},
|
||||
{"04b_25_grey", "04b_25_grey.png", "04b_25.txt"},
|
||||
@@ -663,7 +725,13 @@ void Resource::createText() {
|
||||
{"smb2_grad", "smb2_grad.png", "smb2.txt"}};
|
||||
|
||||
for (const auto &resource : resources) {
|
||||
texts_.emplace_back(resource.key, std::make_shared<Text>(getTexture(resource.texture_file), getTextFile(resource.text_file)));
|
||||
if (!resource.white_texture_file.empty()) {
|
||||
// Crear texto con textura blanca
|
||||
texts_.emplace_back(resource.key, std::make_shared<Text>(getTexture(resource.texture_file), getTexture(resource.white_texture_file), getTextFile(resource.text_file)));
|
||||
} else {
|
||||
// Crear texto normal
|
||||
texts_.emplace_back(resource.key, std::make_shared<Text>(getTexture(resource.texture_file), getTextFile(resource.text_file)));
|
||||
}
|
||||
printWithDots("Text : ", resource.key, "[ DONE ]");
|
||||
}
|
||||
}
|
||||
@@ -784,15 +852,15 @@ void Resource::initProgressBar() {
|
||||
const float BAR_Y_POSITION = param.game.height - BAR_HEIGHT - Y_PADDING;
|
||||
|
||||
const float WIRED_BAR_WIDTH = param.game.width - (X_PADDING * 2);
|
||||
loading_wired_rect_ = {X_PADDING, BAR_Y_POSITION, WIRED_BAR_WIDTH, BAR_HEIGHT};
|
||||
loading_wired_rect_ = {.x = X_PADDING, .y = BAR_Y_POSITION, .w = WIRED_BAR_WIDTH, .h = BAR_HEIGHT};
|
||||
|
||||
const float FULL_BAR_WIDTH = WIRED_BAR_WIDTH * loading_count_.getPercentage();
|
||||
loading_full_rect_ = {X_PADDING, BAR_Y_POSITION, FULL_BAR_WIDTH, BAR_HEIGHT};
|
||||
loading_full_rect_ = {.x = X_PADDING, .y = BAR_Y_POSITION, .w = FULL_BAR_WIDTH, .h = BAR_HEIGHT};
|
||||
}
|
||||
|
||||
// Actualiza el progreso de carga, muestra la barra y procesa eventos
|
||||
void Resource::updateLoadingProgress(std::string name) {
|
||||
loading_resource_name_ = name;
|
||||
loading_resource_name_ = std::move(name);
|
||||
loading_count_.increase();
|
||||
updateProgressBar();
|
||||
renderProgress();
|
||||
@@ -803,3 +871,18 @@ void Resource::updateLoadingProgress(std::string name) {
|
||||
void Resource::updateProgressBar() {
|
||||
loading_full_rect_.w = loading_wired_rect_.w * loading_count_.getPercentage();
|
||||
}
|
||||
|
||||
// Limpia archivos temporales de audio
|
||||
void Resource::cleanupTempAudioFiles() {
|
||||
for (const auto& temp_path : temp_audio_files_) {
|
||||
try {
|
||||
if (std::filesystem::exists(temp_path)) {
|
||||
std::filesystem::remove(temp_path);
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Removed temp audio file: %s", temp_path.c_str());
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to remove temp audio file %s: %s", temp_path.c_str(), e.what());
|
||||
}
|
||||
}
|
||||
temp_audio_files_.clear();
|
||||
}
|
||||
|
||||
@@ -128,6 +128,9 @@ class Resource {
|
||||
std::string loading_resource_name_; // Nombre del recurso que se está cargando
|
||||
SDL_FRect loading_wired_rect_;
|
||||
SDL_FRect loading_full_rect_;
|
||||
|
||||
// --- Archivos temporales ---
|
||||
std::vector<std::string> temp_audio_files_; // Rutas de archivos temporales de audio para limpieza
|
||||
|
||||
// --- Métodos internos de carga y gestión ---
|
||||
void loadSounds(); // Carga los sonidos
|
||||
@@ -140,13 +143,14 @@ class Resource {
|
||||
void loadEssentialResources(); // Carga recursos esenciales en modo lazy
|
||||
void loadEssentialTextures(); // Carga solo las texturas esenciales (fuentes)
|
||||
void loadTextFilesQuiet(); // Carga ficheros de texto sin mostrar progreso (para modo lazy)
|
||||
void createPlayerTextures(); // Crea las texturas de jugadores con todas sus variantes de paleta
|
||||
void createTextTextures(); // Crea las texturas a partir de los datos cargados
|
||||
void createText(); // Crea los objetos de texto
|
||||
void clear(); // Vacía todos los vectores de recursos
|
||||
void load(); // Carga todos los recursos
|
||||
void clearSounds(); // Vacía el vector de sonidos
|
||||
void clearMusics(); // Vacía el vector de músicas
|
||||
void createPlayerTextures(); // Crea las texturas de jugadores con todas sus variantes de paleta
|
||||
void createTextTextures(); // Crea las texturas a partir de los datos cargados
|
||||
void createText(); // Crea los objetos de texto
|
||||
void clear(); // Vacía todos los vectores de recursos
|
||||
void load(); // Carga todos los recursos
|
||||
void clearSounds(); // Vacía el vector de sonidos
|
||||
void clearMusics(); // Vacía el vector de músicas
|
||||
void cleanupTempAudioFiles(); // Limpia archivos temporales de audio
|
||||
|
||||
// --- Métodos para carga perezosa ---
|
||||
void initResourceLists(); // Inicializa las listas de recursos sin cargar el contenido
|
||||
|
||||
95
source/resource_helper.cpp
Normal file
95
source/resource_helper.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
#include "resource_helper.h"
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
namespace ResourceHelper {
|
||||
static bool resource_system_initialized = false;
|
||||
|
||||
bool initializeResourceSystem(const std::string& pack_file) {
|
||||
auto& loader = ResourceLoader::getInstance();
|
||||
resource_system_initialized = loader.initialize(pack_file, true);
|
||||
|
||||
if (resource_system_initialized) {
|
||||
std::cout << "Resource system initialized with pack: " << pack_file << std::endl;
|
||||
} else {
|
||||
std::cout << "Resource system using fallback mode (filesystem only)" << std::endl;
|
||||
}
|
||||
|
||||
return true; // Always return true as fallback is acceptable
|
||||
}
|
||||
|
||||
void shutdownResourceSystem() {
|
||||
if (resource_system_initialized) {
|
||||
ResourceLoader::getInstance().shutdown();
|
||||
resource_system_initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> loadFile(const std::string& filepath) {
|
||||
if (resource_system_initialized && shouldUseResourcePack(filepath)) {
|
||||
auto& loader = ResourceLoader::getInstance();
|
||||
std::string pack_path = getPackPath(filepath);
|
||||
|
||||
auto data = loader.loadResource(pack_path);
|
||||
if (!data.empty()) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback a filesystem
|
||||
std::ifstream file(filepath, std::ios::binary | std::ios::ate);
|
||||
if (!file) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::streamsize fileSize = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
std::vector<uint8_t> data(fileSize);
|
||||
if (!file.read(reinterpret_cast<char*>(data.data()), fileSize)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
bool shouldUseResourcePack(const std::string& filepath) {
|
||||
// Archivos que NO van al pack:
|
||||
// - config/ (ahora está fuera de data/)
|
||||
// - archivos absolutos del sistema
|
||||
|
||||
if (filepath.find("config/") != std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Si contiene "data/" es candidato para el pack
|
||||
if (filepath.find("data/") != std::string::npos) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string getPackPath(const std::string& asset_path) {
|
||||
std::string pack_path = asset_path;
|
||||
|
||||
// Normalizar separadores de path a '/'
|
||||
std::replace(pack_path.begin(), pack_path.end(), '\\', '/');
|
||||
|
||||
// Remover prefijo "data/" si existe
|
||||
size_t data_pos = pack_path.find("data/");
|
||||
if (data_pos != std::string::npos) {
|
||||
pack_path = pack_path.substr(data_pos + 5); // +5 para saltar "data/"
|
||||
}
|
||||
|
||||
// Remover cualquier prefijo de path absoluto
|
||||
size_t last_data = pack_path.rfind("data/");
|
||||
if (last_data != std::string::npos) {
|
||||
pack_path = pack_path.substr(last_data + 5);
|
||||
}
|
||||
|
||||
return pack_path;
|
||||
}
|
||||
}
|
||||
46
source/resource_helper.h
Normal file
46
source/resource_helper.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include "resource_loader.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
// Helper functions para integrar ResourceLoader con el sistema existente
|
||||
namespace ResourceHelper {
|
||||
// Inicializa ResourceLoader (llamar al inicio del programa)
|
||||
bool initializeResourceSystem(const std::string& pack_file = "resources.pack");
|
||||
|
||||
// Cierra ResourceLoader
|
||||
void shutdownResourceSystem();
|
||||
|
||||
// Carga un archivo usando ResourceLoader o fallback a filesystem
|
||||
std::vector<uint8_t> loadFile(const std::string& filepath);
|
||||
|
||||
// Verifica si un archivo debería cargarse del pack vs filesystem
|
||||
bool shouldUseResourcePack(const std::string& filepath);
|
||||
|
||||
// Convierte ruta Asset a ruta relativa para ResourceLoader
|
||||
std::string getPackPath(const std::string& asset_path);
|
||||
|
||||
// Wrappea la carga de archivos para mantener compatibilidad
|
||||
template<typename T>
|
||||
T* loadResourceFile(const std::string& asset_path, T* (*loader_func)(const char*)) {
|
||||
auto data = loadFile(asset_path);
|
||||
if (data.empty()) {
|
||||
return loader_func(asset_path.c_str());
|
||||
}
|
||||
|
||||
// Crear archivo temporal para funciones que esperan path
|
||||
std::string temp_path = "/tmp/ccae_" + std::to_string(std::hash<std::string>{}(asset_path));
|
||||
std::ofstream temp_file(temp_path, std::ios::binary);
|
||||
temp_file.write(reinterpret_cast<const char*>(data.data()), data.size());
|
||||
temp_file.close();
|
||||
|
||||
T* result = loader_func(temp_path.c_str());
|
||||
std::filesystem::remove(temp_path);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
133
source/resource_loader.cpp
Normal file
133
source/resource_loader.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
#include "resource_loader.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <algorithm>
|
||||
|
||||
std::unique_ptr<ResourceLoader> ResourceLoader::instance = nullptr;
|
||||
|
||||
ResourceLoader::ResourceLoader()
|
||||
: resourcePack(nullptr), fallbackToFiles(true) {}
|
||||
|
||||
ResourceLoader& ResourceLoader::getInstance() {
|
||||
if (!instance) {
|
||||
instance = std::unique_ptr<ResourceLoader>(new ResourceLoader());
|
||||
}
|
||||
return *instance;
|
||||
}
|
||||
|
||||
ResourceLoader::~ResourceLoader() {
|
||||
shutdown();
|
||||
}
|
||||
|
||||
bool ResourceLoader::initialize(const std::string& packFile, bool enableFallback) {
|
||||
shutdown();
|
||||
|
||||
fallbackToFiles = enableFallback;
|
||||
packPath = packFile;
|
||||
|
||||
if (std::filesystem::exists(packFile)) {
|
||||
resourcePack = new ResourcePack();
|
||||
if (resourcePack->loadPack(packFile)) {
|
||||
std::cout << "Resource pack loaded successfully: " << packFile << std::endl;
|
||||
std::cout << "Resources available: " << resourcePack->getResourceCount() << std::endl;
|
||||
return true;
|
||||
} else {
|
||||
delete resourcePack;
|
||||
resourcePack = nullptr;
|
||||
std::cerr << "Failed to load resource pack: " << packFile << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (fallbackToFiles) {
|
||||
std::cout << "Using fallback mode: loading resources from data/ directory" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::cerr << "Resource pack not found and fallback disabled: " << packFile << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void ResourceLoader::shutdown() {
|
||||
if (resourcePack) {
|
||||
delete resourcePack;
|
||||
resourcePack = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ResourceLoader::loadResource(const std::string& filename) {
|
||||
if (resourcePack && resourcePack->hasResource(filename)) {
|
||||
return resourcePack->getResource(filename);
|
||||
}
|
||||
|
||||
if (fallbackToFiles) {
|
||||
return loadFromFile(filename);
|
||||
}
|
||||
|
||||
std::cerr << "Resource not found: " << filename << std::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ResourceLoader::resourceExists(const std::string& filename) {
|
||||
if (resourcePack && resourcePack->hasResource(filename)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fallbackToFiles) {
|
||||
std::string fullPath = getDataPath(filename);
|
||||
return std::filesystem::exists(fullPath);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ResourceLoader::loadFromFile(const std::string& filename) {
|
||||
std::string fullPath = getDataPath(filename);
|
||||
|
||||
std::ifstream file(fullPath, std::ios::binary | std::ios::ate);
|
||||
if (!file) {
|
||||
std::cerr << "Error: Could not open file: " << fullPath << std::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::streamsize fileSize = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
std::vector<uint8_t> data(fileSize);
|
||||
if (!file.read(reinterpret_cast<char*>(data.data()), fileSize)) {
|
||||
std::cerr << "Error: Could not read file: " << fullPath << std::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
std::string ResourceLoader::getDataPath(const std::string& filename) {
|
||||
return "data/" + filename;
|
||||
}
|
||||
|
||||
size_t ResourceLoader::getLoadedResourceCount() const {
|
||||
if (resourcePack) {
|
||||
return resourcePack->getResourceCount();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<std::string> ResourceLoader::getAvailableResources() const {
|
||||
if (resourcePack) {
|
||||
return resourcePack->getResourceList();
|
||||
}
|
||||
|
||||
std::vector<std::string> result;
|
||||
if (fallbackToFiles && std::filesystem::exists("data")) {
|
||||
for (const auto& entry : std::filesystem::recursive_directory_iterator("data")) {
|
||||
if (entry.is_regular_file()) {
|
||||
std::string filename = std::filesystem::relative(entry.path(), "data").string();
|
||||
std::replace(filename.begin(), filename.end(), '\\', '/');
|
||||
result.push_back(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
37
source/resource_loader.h
Normal file
37
source/resource_loader.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef RESOURCE_LOADER_H
|
||||
#define RESOURCE_LOADER_H
|
||||
|
||||
#include "resource_pack.h"
|
||||
#include <memory>
|
||||
|
||||
class ResourceLoader {
|
||||
private:
|
||||
static std::unique_ptr<ResourceLoader> instance;
|
||||
ResourcePack* resourcePack;
|
||||
std::string packPath;
|
||||
bool fallbackToFiles;
|
||||
|
||||
ResourceLoader();
|
||||
|
||||
public:
|
||||
static ResourceLoader& getInstance();
|
||||
~ResourceLoader();
|
||||
|
||||
bool initialize(const std::string& packFile, bool enableFallback = true);
|
||||
void shutdown();
|
||||
|
||||
std::vector<uint8_t> loadResource(const std::string& filename);
|
||||
bool resourceExists(const std::string& filename);
|
||||
|
||||
void setFallbackToFiles(bool enable) { fallbackToFiles = enable; }
|
||||
bool getFallbackToFiles() const { return fallbackToFiles; }
|
||||
|
||||
size_t getLoadedResourceCount() const;
|
||||
std::vector<std::string> getAvailableResources() const;
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> loadFromFile(const std::string& filename);
|
||||
std::string getDataPath(const std::string& filename);
|
||||
};
|
||||
|
||||
#endif
|
||||
222
source/resource_pack.cpp
Normal file
222
source/resource_pack.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
#include "resource_pack.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <algorithm>
|
||||
|
||||
const std::string ResourcePack::DEFAULT_ENCRYPT_KEY = "CCAE_RESOURCES_2024";
|
||||
|
||||
ResourcePack::ResourcePack() : loaded(false) {}
|
||||
|
||||
ResourcePack::~ResourcePack() {
|
||||
clear();
|
||||
}
|
||||
|
||||
uint32_t ResourcePack::calculateChecksum(const std::vector<uint8_t>& data) {
|
||||
uint32_t checksum = 0x12345678;
|
||||
for (size_t i = 0; i < data.size(); ++i) {
|
||||
checksum = ((checksum << 5) + checksum) + data[i];
|
||||
}
|
||||
return checksum;
|
||||
}
|
||||
|
||||
void ResourcePack::encryptData(std::vector<uint8_t>& data, const std::string& key) {
|
||||
if (key.empty()) return;
|
||||
|
||||
for (size_t i = 0; i < data.size(); ++i) {
|
||||
data[i] ^= key[i % key.length()];
|
||||
}
|
||||
}
|
||||
|
||||
void ResourcePack::decryptData(std::vector<uint8_t>& data, const std::string& key) {
|
||||
encryptData(data, key);
|
||||
}
|
||||
|
||||
bool ResourcePack::loadPack(const std::string& packFile) {
|
||||
std::ifstream file(packFile, std::ios::binary);
|
||||
if (!file) {
|
||||
std::cerr << "Error: Could not open pack file: " << packFile << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
char header[4];
|
||||
file.read(header, 4);
|
||||
if (std::string(header, 4) != "CCAE") {
|
||||
std::cerr << "Error: Invalid pack file format" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t version;
|
||||
file.read(reinterpret_cast<char*>(&version), sizeof(version));
|
||||
if (version != 1) {
|
||||
std::cerr << "Error: Unsupported pack version: " << version << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t resourceCount;
|
||||
file.read(reinterpret_cast<char*>(&resourceCount), sizeof(resourceCount));
|
||||
|
||||
resources.clear();
|
||||
resources.reserve(resourceCount);
|
||||
|
||||
for (uint32_t i = 0; i < resourceCount; ++i) {
|
||||
uint32_t filenameLength;
|
||||
file.read(reinterpret_cast<char*>(&filenameLength), sizeof(filenameLength));
|
||||
|
||||
std::string filename(filenameLength, '\0');
|
||||
file.read(&filename[0], filenameLength);
|
||||
|
||||
ResourceEntry entry;
|
||||
entry.filename = filename;
|
||||
file.read(reinterpret_cast<char*>(&entry.offset), sizeof(entry.offset));
|
||||
file.read(reinterpret_cast<char*>(&entry.size), sizeof(entry.size));
|
||||
file.read(reinterpret_cast<char*>(&entry.checksum), sizeof(entry.checksum));
|
||||
|
||||
resources[filename] = entry;
|
||||
}
|
||||
|
||||
uint64_t dataSize;
|
||||
file.read(reinterpret_cast<char*>(&dataSize), sizeof(dataSize));
|
||||
|
||||
data.resize(dataSize);
|
||||
file.read(reinterpret_cast<char*>(data.data()), dataSize);
|
||||
|
||||
decryptData(data, DEFAULT_ENCRYPT_KEY);
|
||||
|
||||
loaded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResourcePack::savePack(const std::string& packFile) {
|
||||
std::ofstream file(packFile, std::ios::binary);
|
||||
if (!file) {
|
||||
std::cerr << "Error: Could not create pack file: " << packFile << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
file.write("CCAE", 4);
|
||||
|
||||
uint32_t version = 1;
|
||||
file.write(reinterpret_cast<const char*>(&version), sizeof(version));
|
||||
|
||||
uint32_t resourceCount = static_cast<uint32_t>(resources.size());
|
||||
file.write(reinterpret_cast<const char*>(&resourceCount), sizeof(resourceCount));
|
||||
|
||||
for (const auto& [filename, entry] : resources) {
|
||||
uint32_t filenameLength = static_cast<uint32_t>(filename.length());
|
||||
file.write(reinterpret_cast<const char*>(&filenameLength), sizeof(filenameLength));
|
||||
file.write(filename.c_str(), filenameLength);
|
||||
|
||||
file.write(reinterpret_cast<const char*>(&entry.offset), sizeof(entry.offset));
|
||||
file.write(reinterpret_cast<const char*>(&entry.size), sizeof(entry.size));
|
||||
file.write(reinterpret_cast<const char*>(&entry.checksum), sizeof(entry.checksum));
|
||||
}
|
||||
|
||||
std::vector<uint8_t> encryptedData = data;
|
||||
encryptData(encryptedData, DEFAULT_ENCRYPT_KEY);
|
||||
|
||||
uint64_t dataSize = encryptedData.size();
|
||||
file.write(reinterpret_cast<const char*>(&dataSize), sizeof(dataSize));
|
||||
file.write(reinterpret_cast<const char*>(encryptedData.data()), dataSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResourcePack::addFile(const std::string& filename, const std::string& filepath) {
|
||||
std::ifstream file(filepath, std::ios::binary | std::ios::ate);
|
||||
if (!file) {
|
||||
std::cerr << "Error: Could not open file: " << filepath << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::streamsize fileSize = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
std::vector<uint8_t> fileData(fileSize);
|
||||
if (!file.read(reinterpret_cast<char*>(fileData.data()), fileSize)) {
|
||||
std::cerr << "Error: Could not read file: " << filepath << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ResourceEntry entry;
|
||||
entry.filename = filename;
|
||||
entry.offset = data.size();
|
||||
entry.size = fileData.size();
|
||||
entry.checksum = calculateChecksum(fileData);
|
||||
|
||||
data.insert(data.end(), fileData.begin(), fileData.end());
|
||||
resources[filename] = entry;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResourcePack::addDirectory(const std::string& directory) {
|
||||
if (!std::filesystem::exists(directory)) {
|
||||
std::cerr << "Error: Directory does not exist: " << directory << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& entry : std::filesystem::recursive_directory_iterator(directory)) {
|
||||
if (entry.is_regular_file()) {
|
||||
std::string filepath = entry.path().string();
|
||||
std::string filename = std::filesystem::relative(entry.path(), directory).string();
|
||||
|
||||
std::replace(filename.begin(), filename.end(), '\\', '/');
|
||||
|
||||
if (!addFile(filename, filepath)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ResourcePack::getResource(const std::string& filename) {
|
||||
auto it = resources.find(filename);
|
||||
if (it == resources.end()) {
|
||||
std::cerr << "Error: Resource not found: " << filename << std::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
const ResourceEntry& entry = it->second;
|
||||
if (entry.offset + entry.size > data.size()) {
|
||||
std::cerr << "Error: Invalid resource data: " << filename << std::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> result(data.begin() + entry.offset,
|
||||
data.begin() + entry.offset + entry.size);
|
||||
|
||||
uint32_t checksum = calculateChecksum(result);
|
||||
if (checksum != entry.checksum) {
|
||||
std::cerr << "Warning: Checksum mismatch for resource: " << filename << std::endl;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ResourcePack::hasResource(const std::string& filename) const {
|
||||
return resources.find(filename) != resources.end();
|
||||
}
|
||||
|
||||
void ResourcePack::clear() {
|
||||
resources.clear();
|
||||
data.clear();
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
size_t ResourcePack::getResourceCount() const {
|
||||
return resources.size();
|
||||
}
|
||||
|
||||
std::vector<std::string> ResourcePack::getResourceList() const {
|
||||
std::vector<std::string> result;
|
||||
result.reserve(resources.size());
|
||||
|
||||
for (const auto& [filename, entry] : resources) {
|
||||
result.push_back(filename);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
46
source/resource_pack.h
Normal file
46
source/resource_pack.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef RESOURCE_PACK_H
|
||||
#define RESOURCE_PACK_H
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
struct ResourceEntry {
|
||||
std::string filename;
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
uint32_t checksum;
|
||||
};
|
||||
|
||||
class ResourcePack {
|
||||
private:
|
||||
std::unordered_map<std::string, ResourceEntry> resources;
|
||||
std::vector<uint8_t> data;
|
||||
bool loaded;
|
||||
|
||||
uint32_t calculateChecksum(const std::vector<uint8_t>& data);
|
||||
void encryptData(std::vector<uint8_t>& data, const std::string& key);
|
||||
void decryptData(std::vector<uint8_t>& data, const std::string& key);
|
||||
|
||||
public:
|
||||
ResourcePack();
|
||||
~ResourcePack();
|
||||
|
||||
bool loadPack(const std::string& packFile);
|
||||
bool savePack(const std::string& packFile);
|
||||
|
||||
bool addFile(const std::string& filename, const std::string& filepath);
|
||||
bool addDirectory(const std::string& directory);
|
||||
|
||||
std::vector<uint8_t> getResource(const std::string& filename);
|
||||
bool hasResource(const std::string& filename) const;
|
||||
|
||||
void clear();
|
||||
size_t getResourceCount() const;
|
||||
std::vector<std::string> getResourceList() const;
|
||||
|
||||
static const std::string DEFAULT_ENCRYPT_KEY;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -309,7 +309,7 @@ void Scoreboard::renderShowNameMode(size_t panel_index) {
|
||||
text_scoreboard_->writeDX(Text::CENTER | Text::COLOR, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 11"), 1, text_color1_);
|
||||
|
||||
/* TEXTO CENTRADO */
|
||||
text_scoreboard_->writeDX(Text::CENTER | Text::COLOR, slot4_4_.x, slot4_4_.y, record_name_.at(panel_index), 1, getColorLikeKnightRider(name_colors_, loop_counter_ / 5));
|
||||
text_scoreboard_->writeDX(Text::CENTER | Text::COLOR, slot4_4_.x, slot4_4_.y, record_name_.at(panel_index), 1, Colors::getColorLikeKnightRider(name_colors_, loop_counter_ / 5));
|
||||
}
|
||||
|
||||
void Scoreboard::renderGameCompletedMode(size_t panel_index) {
|
||||
@@ -373,14 +373,14 @@ void Scoreboard::recalculateAnchors() {
|
||||
const float COL = PANEL_WIDTH / 2;
|
||||
|
||||
// Slots de 4
|
||||
slot4_1_ = {COL, ROW1};
|
||||
slot4_2_ = {COL, ROW2};
|
||||
slot4_3_ = {COL, ROW3};
|
||||
slot4_4_ = {COL, ROW4};
|
||||
slot4_1_ = {.x = COL, .y = ROW1};
|
||||
slot4_2_ = {.x = COL, .y = ROW2};
|
||||
slot4_3_ = {.x = COL, .y = ROW3};
|
||||
slot4_4_ = {.x = COL, .y = ROW4};
|
||||
|
||||
// Primer cuadrado para poner el nombre de record
|
||||
const int ENTER_NAME_LENGHT = text_scoreboard_->length(std::string(NAME_SIZE, 'A'));
|
||||
enter_name_pos_.x = COL - (ENTER_NAME_LENGHT / 2);
|
||||
const int ENTER_NAME_LENGTH = text_scoreboard_->length(std::string(NAME_SIZE, 'A'));
|
||||
enter_name_pos_.x = COL - (ENTER_NAME_LENGTH / 2);
|
||||
enter_name_pos_.y = ROW4;
|
||||
|
||||
// Recoloca los sprites
|
||||
|
||||
@@ -224,8 +224,10 @@ void Screen::renderInfo() {
|
||||
void Screen::loadShaders() {
|
||||
if (shader_source_.empty()) {
|
||||
const std::string GLSL_FILE = param.game.game_area.rect.h == 256 ? "crtpi_256.glsl" : "crtpi_240.glsl";
|
||||
std::ifstream f(Asset::get()->get(GLSL_FILE).c_str());
|
||||
shader_source_ = std::string((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
|
||||
auto data = Asset::get()->loadData(GLSL_FILE);
|
||||
if (!data.empty()) {
|
||||
shader_source_ = std::string(data.begin(), data.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,8 +38,8 @@ class Screen {
|
||||
void initShaders(); // Inicializa los shaders
|
||||
|
||||
// --- Efectos visuales ---
|
||||
void shake(int desp = 2, int delay = 3, int lenght = 8) { shake_effect_.enable(src_rect_, dst_rect_, desp, delay, lenght); } // Agita la pantalla
|
||||
void flash(Color color, int lenght = 10, int delay = 0) { flash_effect_ = FlashEffect(true, lenght, delay, color); } // Pone la pantalla de color
|
||||
void shake(int desp = 2, int delay = 3, int length = 8) { shake_effect_.enable(src_rect_, dst_rect_, desp, delay, length); } // Agita la pantalla
|
||||
void flash(Color color, int length = 10, int delay = 0) { flash_effect_ = FlashEffect(true, length, delay, color); } // Pone la pantalla de color
|
||||
void toggleShaders(); // Alterna entre activar y desactivar los shaders
|
||||
void toggleIntegerScale(); // Alterna entre activar y desactivar el escalado entero
|
||||
void toggleVSync(); // Alterna entre activar y desactivar el V-Sync
|
||||
@@ -85,16 +85,16 @@ class Screen {
|
||||
// Efecto de flash en pantalla: pinta la pantalla de un color durante unos frames
|
||||
struct FlashEffect {
|
||||
bool enabled; // Indica si el efecto está activo
|
||||
int lenght; // Duración total del efecto en frames
|
||||
int length; // Duración total del efecto en frames
|
||||
int delay; // Retraso antes de mostrar el flash
|
||||
int counter; // Contador de frames restantes
|
||||
Color color; // Color del flash
|
||||
|
||||
explicit FlashEffect(bool enabled = false, int lenght = 0, int delay = 0, Color color = Color(0xFF, 0xFF, 0xFF))
|
||||
: enabled(enabled), lenght(lenght), delay(delay), counter(lenght), color(color) {}
|
||||
explicit FlashEffect(bool enabled = false, int length = 0, int delay = 0, Color color = Color(0xFF, 0xFF, 0xFF))
|
||||
: enabled(enabled), length(length), delay(delay), counter(length), color(color) {}
|
||||
|
||||
void update() { (enabled && counter > 0) ? counter-- : static_cast<int>(enabled = false); }
|
||||
[[nodiscard]] auto isRendarable() const -> bool { return enabled && counter < lenght - delay; }
|
||||
[[nodiscard]] auto isRendarable() const -> bool { return enabled && counter < length - delay; }
|
||||
};
|
||||
|
||||
// Efecto de sacudida/agitación de pantalla: mueve la imagen para simular un temblor
|
||||
@@ -102,17 +102,17 @@ class Screen {
|
||||
int desp; // Desplazamiento máximo de la sacudida (en píxeles)
|
||||
int delay; // Frames entre cada movimiento de sacudida
|
||||
int counter; // Contador de frames para el siguiente movimiento
|
||||
int lenght; // Duración total del efecto en frames
|
||||
int length; // Duración total del efecto en frames
|
||||
int remaining; // Frames restantes de sacudida
|
||||
int original_pos; // Posición original de la imagen (x)
|
||||
int original_width; // Ancho original de la imagen
|
||||
bool enabled; // Indica si el efecto está activo
|
||||
|
||||
explicit ShakeEffect(bool en = false, int dp = 2, int dl = 3, int cnt = 0, int len = 8, int rem = 0, int orig_pos = 0, int orig_width = 800)
|
||||
: desp(dp), delay(dl), counter(cnt), lenght(len), remaining(rem), original_pos(orig_pos), original_width(orig_width), enabled(en) {}
|
||||
: desp(dp), delay(dl), counter(cnt), length(len), remaining(rem), original_pos(orig_pos), original_width(orig_width), enabled(en) {}
|
||||
|
||||
// Activa el efecto de sacudida y guarda la posición y tamaño originales
|
||||
void enable(SDL_FRect &src_rect, SDL_FRect &dst_rect, int new_desp = -1, int new_delay = -1, int new_lenght = -1) {
|
||||
void enable(SDL_FRect &src_rect, SDL_FRect &dst_rect, int new_desp = -1, int new_delay = -1, int new_length = -1) {
|
||||
if (!enabled) {
|
||||
enabled = true;
|
||||
original_pos = src_rect.x;
|
||||
@@ -125,14 +125,14 @@ class Screen {
|
||||
if (new_delay != -1) {
|
||||
delay = new_delay;
|
||||
}
|
||||
if (new_lenght != -1) {
|
||||
lenght = new_lenght;
|
||||
if (new_length != -1) {
|
||||
length = new_length;
|
||||
}
|
||||
|
||||
src_rect.w -= desp;
|
||||
dst_rect.w = src_rect.w;
|
||||
}
|
||||
remaining = lenght;
|
||||
remaining = length;
|
||||
counter = delay;
|
||||
}
|
||||
|
||||
@@ -171,12 +171,12 @@ class Screen {
|
||||
#endif
|
||||
|
||||
// --- Objetos y punteros ---
|
||||
SDL_Window *window_; // Ventana de la aplicación
|
||||
SDL_Renderer *renderer_; // El renderizador de la ventana
|
||||
SDL_Texture *game_canvas_; // Textura donde se dibuja todo antes de volcarse al renderizador
|
||||
ServiceMenu *service_menu_; // Objeto para mostrar el menú de servicio
|
||||
Notifier *notifier_; // Objeto para mostrar las notificaciones por pantalla
|
||||
std::shared_ptr<Text> text_; // Objeto para escribir texto en pantalla
|
||||
SDL_Window *window_; // Ventana de la aplicación
|
||||
SDL_Renderer *renderer_; // El renderizador de la ventana
|
||||
SDL_Texture *game_canvas_; // Textura donde se dibuja todo antes de volcarse al renderizador
|
||||
ServiceMenu *service_menu_; // Objeto para mostrar el menú de servicio
|
||||
Notifier *notifier_; // Objeto para mostrar las notificaciones por pantalla
|
||||
std::shared_ptr<Text> text_; // Objeto para escribir texto en pantalla
|
||||
|
||||
// --- Variables de estado ---
|
||||
SDL_FRect src_rect_; // Coordenadas de origen para dibujar la textura del juego
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include "audio.h" // Para Audio
|
||||
#include "balloon_manager.h" // Para BalloonManager
|
||||
#include "color.h" // Para Zone, SHADOW_TEXT_COLOR, NO_TEXT_COLOR, Color
|
||||
#include "color.h" // Para Zone, Colors::SHADOW_TEXT, Colors::NO_COLOR_MOD, Color
|
||||
#include "fade.h" // Para Fade, FadeType, FadeMode
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
@@ -35,12 +35,7 @@ constexpr std::string_view TEXT_COPYRIGHT = "@2020,2025 JailDesigner";
|
||||
|
||||
// Constructor
|
||||
Credits::Credits()
|
||||
: balloon_manager_(std::make_unique<BalloonManager>(nullptr)),
|
||||
tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::DIAGONAL)),
|
||||
fade_in_(std::make_unique<Fade>()),
|
||||
fade_out_(std::make_unique<Fade>()),
|
||||
text_texture_(SDL_CreateTexture(Screen::get()->getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
|
||||
canvas_(SDL_CreateTexture(Screen::get()->getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)) {
|
||||
: balloon_manager_(std::make_unique<BalloonManager>(nullptr)), tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::DIAGONAL)), fade_in_(std::make_unique<Fade>()), fade_out_(std::make_unique<Fade>()), text_texture_(SDL_CreateTexture(Screen::get()->getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, static_cast<int>(param.game.width), static_cast<int>(param.game.height))), canvas_(SDL_CreateTexture(Screen::get()->getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, static_cast<int>(param.game.width), static_cast<int>(param.game.height))) {
|
||||
if (text_texture_ == nullptr) {
|
||||
throw std::runtime_error("Failed to create SDL texture for text.");
|
||||
}
|
||||
@@ -48,13 +43,13 @@ Credits::Credits()
|
||||
balloon_manager_->setPlayArea(play_area_);
|
||||
|
||||
fade_in_->setColor(param.fade.color);
|
||||
fade_in_->setType(FadeType::FULLSCREEN);
|
||||
fade_in_->setType(Fade::Type::FULLSCREEN);
|
||||
fade_in_->setPostDuration(50);
|
||||
fade_in_->setMode(FadeMode::IN);
|
||||
fade_in_->setMode(Fade::Mode::IN);
|
||||
fade_in_->activate();
|
||||
|
||||
fade_out_->setColor(0, 0, 0);
|
||||
fade_out_->setType(FadeType::FULLSCREEN);
|
||||
fade_out_->setType(Fade::Type::FULLSCREEN);
|
||||
fade_out_->setPostDuration(400);
|
||||
|
||||
updateRedRect();
|
||||
@@ -63,7 +58,7 @@ Credits::Credits()
|
||||
initPlayers();
|
||||
SDL_SetTextureBlendMode(text_texture_, SDL_BLENDMODE_BLEND);
|
||||
fillTextTexture();
|
||||
steps_ = std::abs((top_black_rect_.h - param.game.game_area.center_y - 1) + ((left_black_rect_.w - param.game.game_area.center_x) / 4));
|
||||
steps_ = static_cast<int>(std::abs((top_black_rect_.h - param.game.game_area.center_y - 1) + ((left_black_rect_.w - param.game.game_area.center_x) / 4)));
|
||||
}
|
||||
|
||||
// Destructor
|
||||
@@ -170,58 +165,60 @@ void Credits::fillTextTexture() {
|
||||
|
||||
const int SPACE_POST_TITLE = 3 + text->getCharacterSize();
|
||||
const int SPACE_PRE_TITLE = text->getCharacterSize() * 4;
|
||||
const int TEXTS_HEIGHT = 1 * text->getCharacterSize() + 8 * SPACE_POST_TITLE + 3 * SPACE_PRE_TITLE;
|
||||
credits_rect_dst_.h = credits_rect_src_.h = TEXTS_HEIGHT;
|
||||
const int TEXTS_HEIGHT = (1 * text->getCharacterSize()) + (8 * SPACE_POST_TITLE) + (3 * SPACE_PRE_TITLE);
|
||||
const int POS_X = static_cast<int>(param.game.game_area.center_x);
|
||||
credits_rect_dst_.h = credits_rect_src_.h = static_cast<float>(TEXTS_HEIGHT);
|
||||
auto text_style = Text::Style(Text::CENTER | Text::SHADOW, Colors::NO_COLOR_MOD, Colors::SHADOW_TEXT);
|
||||
|
||||
// PROGRAMMED_AND_DESIGNED_BY
|
||||
int y = 0;
|
||||
text_grad->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(0), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text_grad->writeStyle(POS_X, y, TEXTS.at(0), text_style);
|
||||
|
||||
y += SPACE_POST_TITLE;
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(4), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text->writeStyle(POS_X, y, TEXTS.at(4), text_style);
|
||||
|
||||
// PIXELART_DRAWN_BY
|
||||
y += SPACE_PRE_TITLE;
|
||||
text_grad->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(1), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text_grad->writeStyle(POS_X, y, TEXTS.at(1), text_style);
|
||||
y += SPACE_POST_TITLE;
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(4), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text->writeStyle(POS_X, y, TEXTS.at(4), text_style);
|
||||
|
||||
// MUSIC_COMPOSED_BY
|
||||
y += SPACE_PRE_TITLE;
|
||||
text_grad->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(2), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text_grad->writeStyle(POS_X, y, TEXTS.at(2), text_style);
|
||||
|
||||
y += SPACE_POST_TITLE;
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(5), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text->writeStyle(POS_X, y, TEXTS.at(5), text_style);
|
||||
y += SPACE_POST_TITLE;
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(6), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text->writeStyle(POS_X, y, TEXTS.at(6), text_style);
|
||||
|
||||
// SOUND_EFFECTS
|
||||
y += SPACE_PRE_TITLE;
|
||||
text_grad->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(3), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text_grad->writeStyle(POS_X, y, TEXTS.at(3), text_style);
|
||||
y += SPACE_POST_TITLE;
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(7), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text->writeStyle(POS_X, y, TEXTS.at(7), text_style);
|
||||
y += SPACE_POST_TITLE;
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(8), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text->writeStyle(POS_X, y, TEXTS.at(8), text_style);
|
||||
y += SPACE_POST_TITLE;
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(9), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text->writeStyle(POS_X, y, TEXTS.at(9), text_style);
|
||||
y += SPACE_POST_TITLE;
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(10), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text->writeStyle(POS_X, y, TEXTS.at(10), text_style);
|
||||
|
||||
// Mini logo
|
||||
y += SPACE_PRE_TITLE;
|
||||
mini_logo_rect_src_.y = y;
|
||||
mini_logo_rect_src_.y = static_cast<float>(y);
|
||||
auto mini_logo_sprite = std::make_unique<Sprite>(Resource::get()->getTexture("logo_jailgames_mini.png"));
|
||||
mini_logo_sprite->setPosition(1 + param.game.game_area.center_x - mini_logo_sprite->getWidth() / 2, 1 + y);
|
||||
Resource::get()->getTexture("logo_jailgames_mini.png")->setColor(SHADOW_TEXT_COLOR.r, SHADOW_TEXT_COLOR.g, SHADOW_TEXT_COLOR.b);
|
||||
mini_logo_sprite->setPosition(1 + POS_X - (mini_logo_sprite->getWidth() / 2), 1 + y);
|
||||
Resource::get()->getTexture("logo_jailgames_mini.png")->setColor(Colors::SHADOW_TEXT.r, Colors::SHADOW_TEXT.g, Colors::SHADOW_TEXT.b);
|
||||
mini_logo_sprite->render();
|
||||
|
||||
mini_logo_sprite->setPosition(param.game.game_area.center_x - mini_logo_sprite->getWidth() / 2, y);
|
||||
mini_logo_sprite->setPosition(POS_X - (mini_logo_sprite->getWidth() / 2), y);
|
||||
Resource::get()->getTexture("logo_jailgames_mini.png")->setColor(255, 255, 255);
|
||||
mini_logo_sprite->render();
|
||||
|
||||
// Texto con el copyright
|
||||
y += mini_logo_sprite->getHeight() + 3;
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, std::string(TEXT_COPYRIGHT), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, POS_X, y, std::string(TEXT_COPYRIGHT), 1, Colors::NO_COLOR_MOD, 1, Colors::SHADOW_TEXT);
|
||||
|
||||
// Resetea el renderizador
|
||||
SDL_SetRenderTarget(Screen::get()->getRenderer(), nullptr);
|
||||
@@ -384,7 +381,7 @@ void Credits::initPlayers() {
|
||||
players_.back()->setPlayingState(Player::State::CREDITS);
|
||||
|
||||
// Registra los jugadores en Options
|
||||
for (auto player : players_) {
|
||||
for (const auto &player : players_) {
|
||||
Options::keyboard.addPlayer(player);
|
||||
Options::gamepad_manager.addPlayer(player);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "balloon.h" // Para Balloon
|
||||
#include "balloon_manager.h" // Para BalloonManager
|
||||
#include "bullet.h" // Para Bullet, BulletType, BulletMoveStatus
|
||||
#include "color.h" // Para Color, FLASH_COLOR
|
||||
#include "color.h" // Para Color, Colors::FLASH
|
||||
#include "difficulty.h" // Para Code
|
||||
#include "fade.h" // Para Fade, FadeType, FadeMode
|
||||
#include "global_events.h" // Para check
|
||||
@@ -49,18 +49,7 @@
|
||||
|
||||
// Constructor
|
||||
Game::Game(Player::Id player_id, int current_stage, bool demo)
|
||||
: renderer_(Screen::get()->getRenderer()),
|
||||
screen_(Screen::get()),
|
||||
input_(Input::get()),
|
||||
canvas_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.play_area.rect.w, param.game.play_area.rect.h)),
|
||||
pause_manager_(std::make_unique<PauseManager>([this](bool is_paused) { onPauseStateChanged(is_paused); })),
|
||||
stage_manager_(std::make_unique<StageManager>()),
|
||||
balloon_manager_(std::make_unique<BalloonManager>(stage_manager_.get())),
|
||||
background_(std::make_unique<Background>(stage_manager_->getTotalPowerNeededToCompleteGame())),
|
||||
fade_in_(std::make_unique<Fade>()),
|
||||
fade_out_(std::make_unique<Fade>()),
|
||||
tabe_(std::make_unique<Tabe>()),
|
||||
hit_(Hit(Resource::get()->getTexture("hit.png"))) {
|
||||
: renderer_(Screen::get()->getRenderer()), screen_(Screen::get()), input_(Input::get()), canvas_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.play_area.rect.w, param.game.play_area.rect.h)), pause_manager_(std::make_unique<PauseManager>([this](bool is_paused) { onPauseStateChanged(is_paused); })), stage_manager_(std::make_unique<StageManager>()), balloon_manager_(std::make_unique<BalloonManager>(stage_manager_.get())), background_(std::make_unique<Background>(stage_manager_->getPowerNeededToReachStage(stage_manager_->getTotalStages() - 1))), fade_in_(std::make_unique<Fade>()), fade_out_(std::make_unique<Fade>()), tabe_(std::make_unique<Tabe>()), hit_(Hit(Resource::get()->getTexture("hit.png"))) {
|
||||
// Pasa variables
|
||||
demo_.enabled = demo;
|
||||
|
||||
@@ -79,15 +68,15 @@ Game::Game(Player::Id player_id, int current_stage, bool demo)
|
||||
scoreboard_ = Scoreboard::get();
|
||||
|
||||
fade_in_->setColor(param.fade.color);
|
||||
fade_in_->setPreDuration(demo_.enabled ? 80 : 0);
|
||||
fade_in_->setPreDuration(demo_.enabled ? 500 : 0);
|
||||
fade_in_->setPostDuration(0);
|
||||
fade_in_->setType(FadeType::RANDOM_SQUARE);
|
||||
fade_in_->setMode(FadeMode::IN);
|
||||
fade_in_->setType(Fade::Type::RANDOM_SQUARE2);
|
||||
fade_in_->setMode(Fade::Mode::IN);
|
||||
fade_in_->activate();
|
||||
|
||||
fade_out_->setColor(param.fade.color);
|
||||
fade_out_->setPostDuration(param.fade.post_duration);
|
||||
fade_out_->setType(FadeType::VENETIAN);
|
||||
fade_out_->setPostDuration(param.fade.post_duration_ms);
|
||||
fade_out_->setType(Fade::Type::VENETIAN);
|
||||
|
||||
background_->setPos(param.game.play_area.rect);
|
||||
|
||||
@@ -230,7 +219,8 @@ void Game::updatePlayers() {
|
||||
handlePlayerCollision(player, balloon);
|
||||
|
||||
if (demo_.enabled && allPlayersAreNotPlaying()) {
|
||||
fade_out_->setType(FadeType::RANDOM_SQUARE);
|
||||
fade_out_->setType(Fade::Type::RANDOM_SQUARE2);
|
||||
fade_out_->setPostDuration(500);
|
||||
fade_out_->activate();
|
||||
}
|
||||
}
|
||||
@@ -281,7 +271,7 @@ void Game::updateStage() {
|
||||
// Efectos de cambio de fase
|
||||
playSound("stage_change.wav");
|
||||
balloon_manager_->resetBalloonSpeed();
|
||||
screen_->flash(FLASH_COLOR, 3);
|
||||
screen_->flash(Colors::FLASH, 3);
|
||||
screen_->shake();
|
||||
|
||||
// Obtener datos de la nueva fase
|
||||
@@ -466,35 +456,35 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player) {
|
||||
switch (item->getType()) {
|
||||
case ItemType::DISK: {
|
||||
player->addScore(1000, Options::settings.hi_score_table.back().score);
|
||||
const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(0)->getWidth()) / 2;
|
||||
const auto X = item->getPosX() + ((item->getWidth() - game_text_textures_.at(0)->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(0));
|
||||
playSound("item_pickup.wav");
|
||||
break;
|
||||
}
|
||||
case ItemType::GAVINA: {
|
||||
player->addScore(2500, Options::settings.hi_score_table.back().score);
|
||||
const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(1)->getWidth()) / 2;
|
||||
const auto X = item->getPosX() + ((item->getWidth() - game_text_textures_.at(1)->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(1));
|
||||
playSound("item_pickup.wav");
|
||||
break;
|
||||
}
|
||||
case ItemType::PACMAR: {
|
||||
player->addScore(5000, Options::settings.hi_score_table.back().score);
|
||||
const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(2)->getWidth()) / 2;
|
||||
const auto X = item->getPosX() + ((item->getWidth() - game_text_textures_.at(2)->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(2));
|
||||
playSound("item_pickup.wav");
|
||||
break;
|
||||
}
|
||||
case ItemType::DEBIAN: {
|
||||
player->addScore(100000, Options::settings.hi_score_table.back().score);
|
||||
const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(6)->getWidth()) / 2;
|
||||
const auto X = item->getPosX() + ((item->getWidth() - game_text_textures_.at(6)->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(6));
|
||||
playSound("debian_pickup.wav");
|
||||
break;
|
||||
}
|
||||
case ItemType::CLOCK: {
|
||||
enableTimeStopItem();
|
||||
const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(5)->getWidth()) / 2;
|
||||
const auto X = item->getPosX() + ((item->getWidth() - game_text_textures_.at(5)->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(5));
|
||||
playSound("item_pickup.wav");
|
||||
break;
|
||||
@@ -502,11 +492,11 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player) {
|
||||
case ItemType::COFFEE: {
|
||||
if (player->getCoffees() == 2) {
|
||||
player->addScore(5000, Options::settings.hi_score_table.back().score);
|
||||
const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(2)->getWidth()) / 2;
|
||||
const auto X = item->getPosX() + ((item->getWidth() - game_text_textures_.at(2)->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(2));
|
||||
} else {
|
||||
player->giveExtraHit();
|
||||
const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(4)->getWidth()) / 2;
|
||||
const auto X = item->getPosX() + ((item->getWidth() - game_text_textures_.at(4)->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(4));
|
||||
}
|
||||
playSound("voice_coffee.wav");
|
||||
@@ -515,7 +505,7 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player) {
|
||||
case ItemType::COFFEE_MACHINE: {
|
||||
player->setPowerUp();
|
||||
coffee_machine_enabled_ = false;
|
||||
const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(3)->getWidth()) / 2;
|
||||
const auto X = item->getPosX() + ((item->getWidth() - game_text_textures_.at(3)->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(3));
|
||||
playSound("voice_power_up.wav");
|
||||
break;
|
||||
@@ -549,7 +539,7 @@ void Game::checkBulletCollision() {
|
||||
}
|
||||
|
||||
// Maneja la colisión entre bala y Tabe
|
||||
auto Game::checkBulletTabeCollision(std::shared_ptr<Bullet> bullet) -> bool {
|
||||
auto Game::checkBulletTabeCollision(const std::shared_ptr<Bullet> &bullet) -> bool {
|
||||
if (!tabe_->isEnabled()) {
|
||||
return false;
|
||||
}
|
||||
@@ -581,7 +571,7 @@ void Game::handleTabeHitEffects() {
|
||||
}
|
||||
|
||||
// Maneja la colisión entre bala y globos
|
||||
auto Game::checkBulletBalloonCollision(std::shared_ptr<Bullet> bullet) -> bool {
|
||||
auto Game::checkBulletBalloonCollision(const std::shared_ptr<Bullet> &bullet) -> bool {
|
||||
for (auto &balloon : balloon_manager_->getBalloons()) {
|
||||
if (!balloon->isEnabled() || balloon->isInvulnerable()) {
|
||||
continue;
|
||||
@@ -598,7 +588,7 @@ auto Game::checkBulletBalloonCollision(std::shared_ptr<Bullet> bullet) -> bool {
|
||||
}
|
||||
|
||||
// Procesa el impacto en un globo
|
||||
void Game::processBalloonHit(std::shared_ptr<Bullet> bullet, std::shared_ptr<Balloon> balloon) {
|
||||
void Game::processBalloonHit(const std::shared_ptr<Bullet> &bullet, const std::shared_ptr<Balloon> &balloon) {
|
||||
auto player = getPlayer(bullet->getOwner());
|
||||
|
||||
handleItemDrop(balloon, player);
|
||||
@@ -608,7 +598,7 @@ void Game::processBalloonHit(std::shared_ptr<Bullet> bullet, std::shared_ptr<Bal
|
||||
}
|
||||
|
||||
// Maneja la caída de items cuando se destruye un globo
|
||||
void Game::handleItemDrop(std::shared_ptr<Balloon> balloon, std::shared_ptr<Player> player) {
|
||||
void Game::handleItemDrop(const std::shared_ptr<Balloon> &balloon, const std::shared_ptr<Player> &player) {
|
||||
const auto DROPPED_ITEM = dropItem();
|
||||
if (DROPPED_ITEM == ItemType::NONE || demo_.recording) {
|
||||
return;
|
||||
@@ -623,9 +613,9 @@ void Game::handleItemDrop(std::shared_ptr<Balloon> balloon, std::shared_ptr<Play
|
||||
}
|
||||
|
||||
// Maneja la destrucción del globo y puntuación
|
||||
void Game::handleBalloonDestruction(std::shared_ptr<Balloon> balloon, std::shared_ptr<Player> player) {
|
||||
void Game::handleBalloonDestruction(std::shared_ptr<Balloon> balloon, const std::shared_ptr<Player> &player) {
|
||||
if (player->isPlaying()) {
|
||||
auto const SCORE = balloon_manager_->popBalloon(balloon) * player->getScoreMultiplier() * difficulty_score_multiplier_;
|
||||
auto const SCORE = balloon_manager_->popBalloon(std::move(balloon)) * player->getScoreMultiplier() * difficulty_score_multiplier_;
|
||||
player->addScore(SCORE, Options::settings.hi_score_table.back().score);
|
||||
player->incScoreMultiplier();
|
||||
}
|
||||
@@ -758,7 +748,7 @@ void Game::freeItems() {
|
||||
}
|
||||
|
||||
// Crea un objeto PathSprite
|
||||
void Game::createItemText(int x, std::shared_ptr<Texture> texture) {
|
||||
void Game::createItemText(int x, const std::shared_ptr<Texture> &texture) {
|
||||
path_sprites_.emplace_back(std::make_unique<PathSprite>(texture));
|
||||
|
||||
const auto W = texture->getWidth();
|
||||
@@ -781,7 +771,7 @@ void Game::createItemText(int x, std::shared_ptr<Texture> texture) {
|
||||
}
|
||||
|
||||
// Crea un objeto PathSprite
|
||||
void Game::createMessage(const std::vector<Path> &paths, std::shared_ptr<Texture> texture) {
|
||||
void Game::createMessage(const std::vector<Path> &paths, const std::shared_ptr<Texture> &texture) {
|
||||
path_sprites_.emplace_back(std::make_unique<PathSprite>(texture));
|
||||
|
||||
// Inicializa
|
||||
@@ -874,7 +864,7 @@ void Game::handlePlayerCollision(std::shared_ptr<Player> &player, std::shared_pt
|
||||
if (player->hasExtraHit()) {
|
||||
// Lo pierde
|
||||
player->removeExtraHit();
|
||||
throwCoffee(player->getPosX() + (player->getWidth() / 2), player->getPosY() + (player->getHeight() / 2));
|
||||
throwCoffee(player->getPosX() + (Player::WIDTH / 2), player->getPosY() + (Player::HEIGHT / 2));
|
||||
playSound("coffee_out.wav");
|
||||
screen_->shake();
|
||||
} else {
|
||||
@@ -986,12 +976,14 @@ void Game::fillCanvas() {
|
||||
|
||||
// Dibuja los objetos
|
||||
background_->render();
|
||||
renderPlayers();
|
||||
renderSmartSprites();
|
||||
renderItems();
|
||||
|
||||
balloon_manager_->render();
|
||||
renderSmartSprites(); // El cafe que sale cuando te golpean
|
||||
renderItems();
|
||||
tabe_->render();
|
||||
renderBullets();
|
||||
renderPlayers();
|
||||
|
||||
renderPathSprites();
|
||||
|
||||
// Deja el renderizador apuntando donde estaba
|
||||
@@ -1031,7 +1023,7 @@ void Game::initPaths() {
|
||||
const auto &texture = Resource::get()->getTexture("game_text_get_ready");
|
||||
const auto W = texture->getWidth();
|
||||
const int X0 = -W;
|
||||
const int X1 = param.game.play_area.center_x - W / 2;
|
||||
const int X1 = param.game.play_area.center_x - (W / 2);
|
||||
const int X2 = param.game.play_area.rect.w;
|
||||
const int Y = param.game.play_area.center_y;
|
||||
paths_.emplace_back(createPath(X0, X1, PathType::HORIZONTAL, Y, 80, easeOutQuint), 20);
|
||||
@@ -1043,7 +1035,7 @@ void Game::initPaths() {
|
||||
const auto &texture = Resource::get()->getTexture("game_text_last_stage");
|
||||
const auto H = texture->getHeight();
|
||||
const int Y0 = param.game.play_area.rect.h - H;
|
||||
const int Y1 = param.game.play_area.center_y - H / 2;
|
||||
const int Y1 = param.game.play_area.center_y - (H / 2);
|
||||
const int Y2 = -H;
|
||||
const int X = param.game.play_area.center_x;
|
||||
paths_.emplace_back(createPath(Y0, Y1, PathType::VERTICAL, X, 80, easeOutQuint), 20);
|
||||
@@ -1056,9 +1048,9 @@ void Game::initPaths() {
|
||||
const auto W = texture->getWidth();
|
||||
const auto H = texture->getHeight();
|
||||
const int X0 = -W;
|
||||
const int X1 = param.game.play_area.center_x - W / 2;
|
||||
const int X1 = param.game.play_area.center_x - (W / 2);
|
||||
const int X2 = param.game.play_area.rect.w;
|
||||
const int Y = param.game.play_area.center_y - H / 2 - 20;
|
||||
const int Y = param.game.play_area.center_y - (H / 2) - 20;
|
||||
paths_.emplace_back(createPath(X0, X1, PathType::HORIZONTAL, Y, 80, easeOutQuint), 400);
|
||||
paths_.emplace_back(createPath(X1, X2, PathType::HORIZONTAL, Y, 80, easeInQuint), 0);
|
||||
}
|
||||
@@ -1069,9 +1061,9 @@ void Game::initPaths() {
|
||||
const auto W = texture->getWidth();
|
||||
const auto H = texture->getHeight();
|
||||
const int X0 = param.game.play_area.rect.w;
|
||||
const int X1 = param.game.play_area.center_x - W / 2;
|
||||
const int X1 = param.game.play_area.center_x - (W / 2);
|
||||
const int X2 = -W;
|
||||
const int Y = param.game.play_area.center_y + H / 2 - 20;
|
||||
const int Y = param.game.play_area.center_y + (H / 2) - 20;
|
||||
paths_.emplace_back(createPath(X0, X1, PathType::HORIZONTAL, Y, 80, easeOutQuint), 400);
|
||||
paths_.emplace_back(createPath(X1, X2, PathType::HORIZONTAL, Y, 80, easeInQuint), 0);
|
||||
}
|
||||
@@ -1239,7 +1231,7 @@ void Game::checkInput() {
|
||||
// Verifica si alguno de los controladores ha solicitado una pausa y actualiza el estado de pausa del juego.
|
||||
void Game::checkPauseInput() {
|
||||
// Comprueba los mandos
|
||||
for (auto gamepad : input_->getGamepads()) {
|
||||
for (const auto &gamepad : input_->getGamepads()) {
|
||||
if (input_->checkAction(Input::Action::PAUSE, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||
pause_manager_->togglePlayerPause();
|
||||
return;
|
||||
@@ -1302,7 +1294,7 @@ void Game::handleFireInput(const std::shared_ptr<Player> &player, BulletType bul
|
||||
switch (bullet_type) {
|
||||
case BulletType::UP:
|
||||
player->setInput(Input::Action::FIRE_CENTER);
|
||||
bullet.x = 2 + player->getPosX() + (player->getWidth() - Bullet::WIDTH) / 2;
|
||||
bullet.x = 2 + player->getPosX() + (Player::WIDTH - Bullet::WIDTH) / 2;
|
||||
bullet.y = player->getPosY() - (Bullet::HEIGHT / 2);
|
||||
break;
|
||||
case BulletType::LEFT:
|
||||
@@ -1312,7 +1304,7 @@ void Game::handleFireInput(const std::shared_ptr<Player> &player, BulletType bul
|
||||
break;
|
||||
case BulletType::RIGHT:
|
||||
player->setInput(Input::Action::FIRE_RIGHT);
|
||||
bullet.x = player->getPosX() + player->getWidth() - (Bullet::WIDTH / 2);
|
||||
bullet.x = player->getPosX() + Player::WIDTH - (Bullet::WIDTH / 2);
|
||||
bullet.y = player->getPosY();
|
||||
break;
|
||||
default:
|
||||
@@ -1489,8 +1481,10 @@ void Game::initDemo(Player::Id player_id) {
|
||||
|
||||
// Asigna cafes a los jugadores
|
||||
for (auto &player : players_) {
|
||||
for (int i = 0; i < rand() % 3; ++i) {
|
||||
player->giveExtraHit();
|
||||
if (player->isPlaying()) {
|
||||
for (int i = 0; i < rand() % 3; ++i) {
|
||||
player->giveExtraHit();
|
||||
}
|
||||
}
|
||||
|
||||
player->setInvulnerable(true);
|
||||
@@ -1616,7 +1610,7 @@ void Game::initPlayers(Player::Id player_id) {
|
||||
}
|
||||
|
||||
// Registra los jugadores en Options
|
||||
for (auto player : players_) {
|
||||
for (const auto &player : players_) {
|
||||
Options::keyboard.addPlayer(player);
|
||||
Options::gamepad_manager.addPlayer(player);
|
||||
}
|
||||
@@ -1660,7 +1654,8 @@ void Game::updateDemo() {
|
||||
|
||||
// Activa el fundido antes de acabar con los datos de la demo
|
||||
if (demo_.counter == TOTAL_DEMO_DATA - 200) {
|
||||
fade_out_->setType(FadeType::RANDOM_SQUARE);
|
||||
fade_out_->setType(Fade::Type::RANDOM_SQUARE2);
|
||||
fade_out_->setPostDuration(param.fade.post_duration_ms);
|
||||
fade_out_->activate();
|
||||
}
|
||||
|
||||
@@ -1777,11 +1772,11 @@ void Game::updateMenace() {
|
||||
}
|
||||
|
||||
const auto &stage = current_stage.value();
|
||||
const double fraction = stage_manager_->getCurrentStageProgressFraction();
|
||||
const int difference = stage.getMaxMenace() - stage.getMinMenace();
|
||||
const double FRACTION = stage_manager_->getCurrentStageProgressFraction();
|
||||
const int DIFFERENCE = stage.getMaxMenace() - stage.getMinMenace();
|
||||
|
||||
// Aumenta el nivel de amenaza en función del progreso de la fase
|
||||
menace_threshold_ = stage.getMinMenace() + (difference * fraction);
|
||||
menace_threshold_ = stage.getMinMenace() + (DIFFERENCE * FRACTION);
|
||||
|
||||
if (menace_ < menace_threshold_) {
|
||||
balloon_manager_->deployRandomFormation(stage_manager_->getCurrentStageIndex());
|
||||
@@ -1908,7 +1903,7 @@ void Game::handleDebugEvents(const SDL_Event &event) {
|
||||
}
|
||||
case SDLK_5: // 5.000
|
||||
{
|
||||
const int X = players_.at(0)->getPosX() + (players_.at(0)->getWidth() - game_text_textures_[3]->getWidth()) / 2;
|
||||
const int X = players_.at(0)->getPosX() + ((Player::WIDTH - game_text_textures_[3]->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(2));
|
||||
break;
|
||||
}
|
||||
@@ -1919,7 +1914,7 @@ void Game::handleDebugEvents(const SDL_Event &event) {
|
||||
}
|
||||
case SDLK_7: // 100.000
|
||||
{
|
||||
const int X = players_.at(0)->getPosX() + (players_.at(0)->getWidth() - game_text_textures_[3]->getWidth()) / 2;
|
||||
const int X = players_.at(0)->getPosX() + ((Player::WIDTH - game_text_textures_[3]->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(6));
|
||||
break;
|
||||
}
|
||||
@@ -1940,14 +1935,14 @@ void Game::handleDebugEvents(const SDL_Event &event) {
|
||||
++formation_id_;
|
||||
balloon_manager_->destroyAllBalloons();
|
||||
balloon_manager_->deployFormation(formation_id_);
|
||||
std::cout << formation_id_ << std::endl;
|
||||
std::cout << formation_id_ << '\n';
|
||||
break;
|
||||
}
|
||||
case SDLK_KP_MINUS: {
|
||||
--formation_id_;
|
||||
balloon_manager_->destroyAllBalloons();
|
||||
balloon_manager_->deployFormation(formation_id_);
|
||||
std::cout << formation_id_ << std::endl;
|
||||
std::cout << formation_id_ << '\n';
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -216,9 +216,9 @@ class Game {
|
||||
void freeBullets(); // Libera memoria del vector de balas
|
||||
|
||||
// --- Colisiones específicas de balas ---
|
||||
auto checkBulletTabeCollision(std::shared_ptr<Bullet> bullet) -> bool; // Detecta colisión bala-Tabe
|
||||
auto checkBulletBalloonCollision(std::shared_ptr<Bullet> bullet) -> bool; // Detecta colisión bala-globo
|
||||
void processBalloonHit(std::shared_ptr<Bullet> bullet, std::shared_ptr<Balloon> balloon); // Procesa impacto en globo
|
||||
auto checkBulletTabeCollision(const std::shared_ptr<Bullet> &bullet) -> bool; // Detecta colisión bala-Tabe
|
||||
auto checkBulletBalloonCollision(const std::shared_ptr<Bullet> &bullet) -> bool; // Detecta colisión bala-globo
|
||||
void processBalloonHit(const std::shared_ptr<Bullet> &bullet, const std::shared_ptr<Balloon> &balloon); // Procesa impacto en globo
|
||||
|
||||
// --- Sistema de ítems y power-ups ---
|
||||
void updateItems(); // Actualiza posición y estado de todos los ítems
|
||||
@@ -235,7 +235,7 @@ class Game {
|
||||
void throwCoffee(int x, int y); // Crea efecto de café arrojado al ser golpeado
|
||||
|
||||
// --- Gestión de caída de ítems ---
|
||||
void handleItemDrop(std::shared_ptr<Balloon> balloon, std::shared_ptr<Player> player); // Gestiona caída de ítem desde globo
|
||||
void handleItemDrop(const std::shared_ptr<Balloon> &balloon, const std::shared_ptr<Player> &player); // Gestiona caída de ítem desde globo
|
||||
|
||||
// --- Sprites inteligentes (smartsprites) ---
|
||||
void updateSmartSprites(); // Actualiza todos los sprites con lógica propia
|
||||
@@ -249,17 +249,16 @@ class Game {
|
||||
void initPaths(); // Inicializa rutas predefinidas para animaciones
|
||||
|
||||
// --- Creación de sprites especiales ---
|
||||
void createItemText(int x, std::shared_ptr<Texture> texture); // Crea texto animado para ítems
|
||||
void createMessage(const std::vector<Path> &paths, std::shared_ptr<Texture> texture); // Crea mensaje con animación por ruta
|
||||
void createItemText(int x, const std::shared_ptr<Texture> &texture); // Crea texto animado para ítems
|
||||
void createMessage(const std::vector<Path> &paths, const std::shared_ptr<Texture> &texture); // Crea mensaje con animación por ruta
|
||||
|
||||
// --- Sistema de globos y enemigos ---
|
||||
void handleBalloonDestruction(std::shared_ptr<Balloon> balloon, std::shared_ptr<Player> player); // Procesa destrucción de globo
|
||||
void handleTabeHitEffects(); // Gestiona efectos al golpear a Tabe
|
||||
void checkAndUpdateBalloonSpeed(); // Ajusta velocidad de globos según progreso
|
||||
void handleBalloonDestruction(std::shared_ptr<Balloon> balloon, const std::shared_ptr<Player> &player); // Procesa destrucción de globo
|
||||
void handleTabeHitEffects(); // Gestiona efectos al golpear a Tabe
|
||||
void checkAndUpdateBalloonSpeed(); // Ajusta velocidad de globos según progreso
|
||||
|
||||
// --- Gestión de fases y progresión ---
|
||||
void updateStage(); // Verifica y actualiza cambio de fase
|
||||
void setTotalPower(); // Calcula poder total necesario para completar el juego
|
||||
void initDifficultyVars(); // Inicializa variables de dificultad
|
||||
|
||||
// --- Sistema de amenaza ---
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "audio.h" // Para Audio
|
||||
#include "background.h" // Para Background
|
||||
#include "color.h" // Para Color, easeOutQuint, NO_TEXT_COLOR
|
||||
#include "color.h" // Para Color, easeOutQuint, Colors::NO_COLOR_MOD
|
||||
#include "fade.h" // Para Fade, FadeMode, FadeType
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
@@ -29,15 +29,7 @@
|
||||
|
||||
// Constructor
|
||||
HiScoreTable::HiScoreTable()
|
||||
: renderer_(Screen::get()->getRenderer()),
|
||||
backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
|
||||
fade_(std::make_unique<Fade>()),
|
||||
background_(std::make_unique<Background>()),
|
||||
|
||||
ticks_(0),
|
||||
view_area_(SDL_FRect{0, 0, param.game.width, param.game.height}),
|
||||
fade_mode_(FadeMode::IN),
|
||||
background_fade_color_(Color(0, 0, 0)) {
|
||||
: renderer_(Screen::get()->getRenderer()), backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)), fade_(std::make_unique<Fade>()), background_(std::make_unique<Background>()), ticks_(0), view_area_(SDL_FRect{0, 0, param.game.width, param.game.height}), fade_mode_(Fade::Mode::IN), background_fade_color_(Color(0, 0, 0)) {
|
||||
// Inicializa el resto
|
||||
Section::name = Section::Name::HI_SCORE_TABLE;
|
||||
SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND);
|
||||
@@ -133,13 +125,13 @@ void HiScoreTable::run() {
|
||||
void HiScoreTable::updateFade() {
|
||||
fade_->update();
|
||||
|
||||
if (fade_->hasEnded() && fade_mode_ == FadeMode::IN) {
|
||||
if (fade_->hasEnded() && fade_mode_ == Fade::Mode::IN) {
|
||||
fade_->reset();
|
||||
fade_mode_ = FadeMode::OUT;
|
||||
fade_mode_ = Fade::Mode::OUT;
|
||||
fade_->setMode(fade_mode_);
|
||||
}
|
||||
|
||||
if (fade_->hasEnded() && fade_mode_ == FadeMode::OUT) {
|
||||
if (fade_->hasEnded() && fade_mode_ == Fade::Mode::OUT) {
|
||||
Section::name = (Section::options == Section::Options::HI_SCORE_AFTER_PLAYING)
|
||||
? Section::Name::TITLE
|
||||
: Section::Name::INSTRUCTIONS;
|
||||
@@ -178,11 +170,11 @@ void HiScoreTable::createSprites() {
|
||||
float backbuffer_height;
|
||||
SDL_GetTextureSize(backbuffer_, &backbuffer_width, &backbuffer_height);
|
||||
|
||||
constexpr int ENTRY_LENGHT = 22;
|
||||
constexpr int ENTRY_LENGTH = 22;
|
||||
constexpr int MAX_NAMES = 10;
|
||||
const int SPACE_BETWEEN_HEADER = entry_text->getCharacterSize() * 4;
|
||||
const int SPACE_BETWEEN_LINES = entry_text->getCharacterSize() * 2;
|
||||
const int SIZE = SPACE_BETWEEN_HEADER + SPACE_BETWEEN_LINES * (MAX_NAMES - 1) + entry_text->getCharacterSize();
|
||||
const int SIZE = SPACE_BETWEEN_HEADER + (SPACE_BETWEEN_LINES * (MAX_NAMES - 1)) + entry_text->getCharacterSize();
|
||||
const int FIRST_LINE = (param.game.height - SIZE) / 2;
|
||||
|
||||
// Crea el sprite para el texto de cabecera
|
||||
@@ -191,13 +183,13 @@ void HiScoreTable::createSprites() {
|
||||
|
||||
// Crea los sprites para las entradas en la tabla de puntuaciones
|
||||
const int ANIMATION = rand() % 4;
|
||||
const std::string SAMPLE_LINE(ENTRY_LENGHT + 3, ' ');
|
||||
auto sample_entry = std::make_unique<Sprite>(entry_text->writeDXToTexture(Text::SHADOW, SAMPLE_LINE, 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR));
|
||||
const std::string SAMPLE_LINE(ENTRY_LENGTH + 3, ' ');
|
||||
auto sample_entry = std::make_unique<Sprite>(entry_text->writeDXToTexture(Text::SHADOW, SAMPLE_LINE, 1, Colors::NO_COLOR_MOD, 1, Colors::SHADOW_TEXT));
|
||||
const auto ENTRY_WIDTH = sample_entry->getWidth();
|
||||
for (int i = 0; i < MAX_NAMES; ++i) {
|
||||
const auto TABLE_POSITION = format(i + 1) + ". ";
|
||||
const auto SCORE = format(Options::settings.hi_score_table.at(i).score);
|
||||
const auto NUM_DOTS = ENTRY_LENGHT - Options::settings.hi_score_table.at(i).name.size() - SCORE.size();
|
||||
const auto NUM_DOTS = ENTRY_LENGTH - Options::settings.hi_score_table.at(i).name.size() - SCORE.size();
|
||||
const auto *const ONE_CC = Options::settings.hi_score_table.at(i).one_credit_complete ? " }" : "";
|
||||
std::string dots;
|
||||
for (int j = 0; j < (int)NUM_DOTS; ++j) {
|
||||
@@ -205,7 +197,7 @@ void HiScoreTable::createSprites() {
|
||||
}
|
||||
const auto LINE = TABLE_POSITION + Options::settings.hi_score_table.at(i).name + dots + SCORE + ONE_CC;
|
||||
|
||||
entry_names_.emplace_back(std::make_shared<PathSprite>(entry_text->writeDXToTexture(Text::SHADOW, LINE, 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR)));
|
||||
entry_names_.emplace_back(std::make_shared<PathSprite>(entry_text->writeDXToTexture(Text::SHADOW, LINE, 1, Colors::NO_COLOR_MOD, 1, Colors::SHADOW_TEXT)));
|
||||
const int DEFAULT_POS_X = (backbuffer_width - ENTRY_WIDTH) / 2;
|
||||
const int POS_X = (i < 9) ? DEFAULT_POS_X : DEFAULT_POS_X - entry_text->getCharacterSize();
|
||||
const int POS_Y = (i * SPACE_BETWEEN_LINES) + FIRST_LINE + SPACE_BETWEEN_HEADER;
|
||||
@@ -272,14 +264,15 @@ void HiScoreTable::updateSprites() {
|
||||
// Inicializa el fade
|
||||
void HiScoreTable::initFade() {
|
||||
fade_->setColor(param.fade.color);
|
||||
fade_->setType(FadeType::RANDOM_SQUARE);
|
||||
fade_->setPostDuration(param.fade.post_duration);
|
||||
fade_->setType(Fade::Type::RANDOM_SQUARE2);
|
||||
fade_->setPostDuration(param.fade.post_duration_ms);
|
||||
fade_->setMode(fade_mode_);
|
||||
fade_->activate();
|
||||
}
|
||||
|
||||
// Inicializa el fondo
|
||||
void HiScoreTable::initBackground() {
|
||||
background_->setManualMode(true);
|
||||
background_->setPos(param.game.game_area.rect);
|
||||
background_->setCloudsSpeed(-0.1F);
|
||||
|
||||
@@ -291,7 +284,7 @@ void HiScoreTable::initBackground() {
|
||||
background_->setTransition(0.0F);
|
||||
background_->setSunProgression(1.0F);
|
||||
background_->setMoonProgression(0.0F);
|
||||
background_fade_color_ = GREEN_SKY_COLOR;
|
||||
background_fade_color_ = Colors::GREEN_SKY;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -301,7 +294,7 @@ void HiScoreTable::initBackground() {
|
||||
background_->setTransition(0.0F);
|
||||
background_->setSunProgression(0.65F);
|
||||
background_->setMoonProgression(0.0F);
|
||||
background_fade_color_ = PINK_SKY_COLOR;
|
||||
background_fade_color_ = Colors::PINK_SKY;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -311,7 +304,7 @@ void HiScoreTable::initBackground() {
|
||||
background_->setTransition(0.0F);
|
||||
background_->setSunProgression(0.0F);
|
||||
background_->setMoonProgression(0.0F);
|
||||
background_fade_color_ = BLUE_SKY_COLOR;
|
||||
background_fade_color_ = Colors::BLUE_SKY;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -322,7 +315,7 @@ void HiScoreTable::initBackground() {
|
||||
|
||||
// Obtiene un color del vector de colores de entradas
|
||||
auto HiScoreTable::getEntryColor(int counter) -> Color {
|
||||
int cycle_length = entry_colors_.size() * 2 - 2;
|
||||
int cycle_length = (entry_colors_.size() * 2) - 2;
|
||||
size_t n = counter % cycle_length;
|
||||
|
||||
size_t index;
|
||||
|
||||
@@ -7,12 +7,11 @@
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "color.h" // Para Color
|
||||
#include "fade.h" // Para Fade
|
||||
#include "path_sprite.h" // Para Path, PathSprite (ptr only)
|
||||
|
||||
class Background;
|
||||
class Fade;
|
||||
class Sprite;
|
||||
enum class FadeMode : Uint8;
|
||||
|
||||
// --- Clase HiScoreTable: muestra la tabla de puntuaciones más altas ---
|
||||
// Esta clase gestiona un estado del programa. Se encarga de mostrar la tabla con las puntuaciones
|
||||
@@ -48,7 +47,7 @@ class HiScoreTable {
|
||||
Uint16 counter_ = 0; // Contador
|
||||
Uint64 ticks_; // Contador de ticks para ajustar la velocidad del programa
|
||||
SDL_FRect view_area_; // Parte de la textura que se muestra en pantalla
|
||||
FadeMode fade_mode_; // Modo de fade a utilizar
|
||||
Fade::Mode fade_mode_; // Modo de fade a utilizar
|
||||
Color background_fade_color_; // Color de atenuación del fondo
|
||||
std::vector<Color> entry_colors_; // Colores para destacar las entradas en la tabla
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "audio.h" // Para Audio
|
||||
#include "color.h" // Para Color, SHADOW_TEXT_COLOR, Zone, NO_TEXT_C...
|
||||
#include "color.h" // Para Color, Colors::SHADOW_TEXT, Zone, NO_TEXT_C...
|
||||
#include "fade.h" // Para Fade, FadeMode, FadeType
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
@@ -26,12 +26,7 @@
|
||||
|
||||
// Constructor
|
||||
Instructions::Instructions()
|
||||
: renderer_(Screen::get()->getRenderer()),
|
||||
texture_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
|
||||
backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
|
||||
text_(Resource::get()->getText("smb2")),
|
||||
tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::STATIC)),
|
||||
fade_(std::make_unique<Fade>()) {
|
||||
: renderer_(Screen::get()->getRenderer()), texture_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)), backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)), text_(Resource::get()->getText("smb2")), tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::STATIC)), fade_(std::make_unique<Fade>()) {
|
||||
// Configura las texturas
|
||||
SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetTextureBlendMode(texture_, SDL_BLENDMODE_BLEND);
|
||||
@@ -43,9 +38,9 @@ Instructions::Instructions()
|
||||
// Inicializa objetos
|
||||
tiled_bg_->setColor(param.title.bg_color);
|
||||
fade_->setColor(param.fade.color);
|
||||
fade_->setType(FadeType::FULLSCREEN);
|
||||
fade_->setPostDuration(param.fade.post_duration);
|
||||
fade_->setMode(FadeMode::IN);
|
||||
fade_->setType(Fade::Type::FULLSCREEN);
|
||||
fade_->setPostDuration(param.fade.post_duration_ms);
|
||||
fade_->setMode(Fade::Mode::IN);
|
||||
fade_->activate();
|
||||
|
||||
// Inicializa las líneas con un retraso progresivo de 50 ms
|
||||
@@ -137,7 +132,7 @@ void Instructions::fillTexture() {
|
||||
const int FIRST_LINE = (param.game.height - SIZE) / 2;
|
||||
|
||||
// Calcula cual es el texto más largo de las descripciones de los items
|
||||
int lenght = 0;
|
||||
int length = 0;
|
||||
const std::array<std::string, 5> ITEM_DESCRIPTIONS = {
|
||||
Lang::getText("[INSTRUCTIONS] 07"),
|
||||
Lang::getText("[INSTRUCTIONS] 08"),
|
||||
@@ -146,32 +141,32 @@ void Instructions::fillTexture() {
|
||||
Lang::getText("[INSTRUCTIONS] 11")};
|
||||
for (const auto &desc : ITEM_DESCRIPTIONS) {
|
||||
const int L = text_->length(desc);
|
||||
lenght = L > lenght ? L : lenght;
|
||||
length = L > length ? L : length;
|
||||
}
|
||||
const int ANCHOR_ITEM = (param.game.width - (lenght + X_OFFSET)) / 2;
|
||||
const int ANCHOR_ITEM = (param.game.width - (length + X_OFFSET)) / 2;
|
||||
|
||||
auto caption_style = Text::Style(Text::CENTER | Text::COLOR | Text::SHADOW, ORANGE_TEXT_COLOR, SHADOW_TEXT_COLOR);
|
||||
auto text_style = Text::Style(Text::CENTER | Text::COLOR | Text::SHADOW, NO_TEXT_COLOR, SHADOW_TEXT_COLOR);
|
||||
auto caption_style = Text::Style(Text::CENTER | Text::COLOR | Text::SHADOW, Colors::ORANGE_TEXT, Colors::SHADOW_TEXT);
|
||||
auto text_style = Text::Style(Text::CENTER | Text::COLOR | Text::SHADOW, Colors::NO_COLOR_MOD, Colors::SHADOW_TEXT);
|
||||
|
||||
// Escribe el texto de las instrucciones
|
||||
text_->writeStyle(param.game.game_area.center_x, FIRST_LINE, Lang::getText("[INSTRUCTIONS] 01"), caption_style);
|
||||
|
||||
const int ANCHOR1 = FIRST_LINE + SPACE_POST_HEADER;
|
||||
text_->writeStyle(param.game.game_area.center_x, ANCHOR1 + SPACE_BETWEEN_LINES * 0, Lang::getText("[INSTRUCTIONS] 02"), text_style);
|
||||
text_->writeStyle(param.game.game_area.center_x, ANCHOR1 + SPACE_BETWEEN_LINES * 1, Lang::getText("[INSTRUCTIONS] 03"), text_style);
|
||||
text_->writeStyle(param.game.game_area.center_x, ANCHOR1 + SPACE_NEW_PARAGRAPH + SPACE_BETWEEN_LINES * 2, Lang::getText("[INSTRUCTIONS] 04"), text_style);
|
||||
text_->writeStyle(param.game.game_area.center_x, ANCHOR1 + SPACE_NEW_PARAGRAPH + SPACE_BETWEEN_LINES * 3, Lang::getText("[INSTRUCTIONS] 05"), text_style);
|
||||
text_->writeStyle(param.game.game_area.center_x, ANCHOR1 + (SPACE_BETWEEN_LINES * 0), Lang::getText("[INSTRUCTIONS] 02"), text_style);
|
||||
text_->writeStyle(param.game.game_area.center_x, ANCHOR1 + (SPACE_BETWEEN_LINES * 1), Lang::getText("[INSTRUCTIONS] 03"), text_style);
|
||||
text_->writeStyle(param.game.game_area.center_x, ANCHOR1 + SPACE_NEW_PARAGRAPH + (SPACE_BETWEEN_LINES * 2), Lang::getText("[INSTRUCTIONS] 04"), text_style);
|
||||
text_->writeStyle(param.game.game_area.center_x, ANCHOR1 + SPACE_NEW_PARAGRAPH + (SPACE_BETWEEN_LINES * 3), Lang::getText("[INSTRUCTIONS] 05"), text_style);
|
||||
|
||||
// Escribe el texto de los objetos y sus puntos
|
||||
const int ANCHOR2 = ANCHOR1 + SPACE_PRE_HEADER + SPACE_NEW_PARAGRAPH + SPACE_BETWEEN_LINES * 3;
|
||||
const int ANCHOR2 = ANCHOR1 + SPACE_PRE_HEADER + SPACE_NEW_PARAGRAPH + (SPACE_BETWEEN_LINES * 3);
|
||||
text_->writeStyle(param.game.game_area.center_x, ANCHOR2, Lang::getText("[INSTRUCTIONS] 06"), caption_style);
|
||||
|
||||
const int ANCHOR3 = ANCHOR2 + SPACE_POST_HEADER;
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + SPACE_BETWEEN_ITEM_LINES * 0, Lang::getText("[INSTRUCTIONS] 07"), SHADOW_TEXT_COLOR);
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + SPACE_BETWEEN_ITEM_LINES * 1, Lang::getText("[INSTRUCTIONS] 08"), SHADOW_TEXT_COLOR);
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + SPACE_BETWEEN_ITEM_LINES * 2, Lang::getText("[INSTRUCTIONS] 09"), SHADOW_TEXT_COLOR);
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + SPACE_BETWEEN_ITEM_LINES * 3, Lang::getText("[INSTRUCTIONS] 10"), SHADOW_TEXT_COLOR);
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + SPACE_BETWEEN_ITEM_LINES * 4, Lang::getText("[INSTRUCTIONS] 11"), SHADOW_TEXT_COLOR);
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + (SPACE_BETWEEN_ITEM_LINES * 0), Lang::getText("[INSTRUCTIONS] 07"), Colors::SHADOW_TEXT);
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + (SPACE_BETWEEN_ITEM_LINES * 1), Lang::getText("[INSTRUCTIONS] 08"), Colors::SHADOW_TEXT);
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + (SPACE_BETWEEN_ITEM_LINES * 2), Lang::getText("[INSTRUCTIONS] 09"), Colors::SHADOW_TEXT);
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + (SPACE_BETWEEN_ITEM_LINES * 3), Lang::getText("[INSTRUCTIONS] 10"), Colors::SHADOW_TEXT);
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + (SPACE_BETWEEN_ITEM_LINES * 4), Lang::getText("[INSTRUCTIONS] 11"), Colors::SHADOW_TEXT);
|
||||
|
||||
// Deja el renderizador como estaba
|
||||
SDL_SetRenderTarget(renderer_, temp);
|
||||
|
||||
@@ -326,7 +326,7 @@ void Intro::initSprites() {
|
||||
card_sprites_.push_back(std::move(sprite));
|
||||
}
|
||||
|
||||
const float X_DEST = param.game.game_area.center_x - CARD_WIDTH / 2;
|
||||
const float X_DEST = param.game.game_area.center_x - (CARD_WIDTH / 2);
|
||||
const float Y_DEST = param.game.game_area.first_quarter_y - (CARD_HEIGHT / 4);
|
||||
|
||||
card_sprites_.at(0)->addPath(-CARD_WIDTH - 10, X_DEST, PathType::HORIZONTAL, Y_DEST, 100, easeInOutExpo, 0);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "audio.h" // Para Audio
|
||||
#include "color.h" // Para NO_TEXT_COLOR, TITLE_SHADOW_TEXT_COLOR
|
||||
#include "color.h" // Para Colors::NO_COLOR_MOD, Colors::TITLE_SHADOW_TEXT
|
||||
#include "fade.h" // Para Fade, FadeType
|
||||
#include "game_logo.h" // Para GameLogo
|
||||
#include "global_events.h" // Para check
|
||||
@@ -37,20 +37,14 @@ class Texture;
|
||||
|
||||
// Constructor
|
||||
Title::Title()
|
||||
: text_(Resource::get()->getText("smb2_grad")),
|
||||
fade_(std::make_unique<Fade>()),
|
||||
tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::RANDOM)),
|
||||
game_logo_(std::make_unique<GameLogo>(param.game.game_area.center_x, param.title.title_c_c_position)),
|
||||
mini_logo_sprite_(std::make_unique<Sprite>(Resource::get()->getTexture("logo_jailgames_mini.png"))),
|
||||
state_(TitleState::LOGO_ANIMATING),
|
||||
num_controllers_(Input::get()->getNumGamepads()) {
|
||||
: text_(Resource::get()->getText("smb2_grad")), fade_(std::make_unique<Fade>()), tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::RANDOM)), game_logo_(std::make_unique<GameLogo>(param.game.game_area.center_x, param.title.title_c_c_position)), mini_logo_sprite_(std::make_unique<Sprite>(Resource::get()->getTexture("logo_jailgames_mini.png"))), state_(TitleState::LOGO_ANIMATING), num_controllers_(Input::get()->getNumGamepads()) {
|
||||
// Configura objetos
|
||||
tiled_bg_->setColor(param.title.bg_color);
|
||||
game_logo_->enable();
|
||||
mini_logo_sprite_->setX(param.game.game_area.center_x - mini_logo_sprite_->getWidth() / 2);
|
||||
mini_logo_sprite_->setX(param.game.game_area.center_x - (mini_logo_sprite_->getWidth() / 2));
|
||||
fade_->setColor(param.fade.color);
|
||||
fade_->setType(FadeType::RANDOM_SQUARE);
|
||||
fade_->setPostDuration(param.fade.post_duration);
|
||||
fade_->setType(Fade::Type::RANDOM_SQUARE2);
|
||||
fade_->setPostDuration(param.fade.post_duration_ms);
|
||||
initPlayers();
|
||||
|
||||
// Asigna valores a otras variables
|
||||
@@ -201,7 +195,7 @@ void Title::printColorValue(const Color& color) {
|
||||
<< std::hex << std::setw(2) << std::setfill('0') << (int)color.r
|
||||
<< std::setw(2) << std::setfill('0') << (int)color.g
|
||||
<< std::setw(2) << std::setfill('0') << (int)color.b
|
||||
<< std::endl;
|
||||
<< '\n';
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -438,9 +432,9 @@ void Title::renderStartPrompt() {
|
||||
param.title.press_start_position,
|
||||
Lang::getText("[TITLE] PRESS_BUTTON_TO_PLAY"),
|
||||
1,
|
||||
NO_TEXT_COLOR,
|
||||
Colors::NO_COLOR_MOD,
|
||||
1,
|
||||
TITLE_SHADOW_TEXT_COLOR);
|
||||
Colors::TITLE_SHADOW_TEXT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,9 +449,9 @@ void Title::renderCopyright() {
|
||||
anchor_.copyright_text,
|
||||
std::string(TEXT_COPYRIGHT),
|
||||
1,
|
||||
NO_TEXT_COLOR,
|
||||
Colors::NO_COLOR_MOD,
|
||||
1,
|
||||
TITLE_SHADOW_TEXT_COLOR);
|
||||
Colors::TITLE_SHADOW_TEXT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,7 +532,7 @@ void Title::initPlayers() {
|
||||
players_.back()->setPlayingState(Player::State::TITLE_HIDDEN);
|
||||
|
||||
// Registra los jugadores en Options
|
||||
for (auto player : players_) {
|
||||
for (const auto& player : players_) {
|
||||
Options::keyboard.addPlayer(player);
|
||||
Options::gamepad_manager.addPlayer(player);
|
||||
}
|
||||
@@ -560,7 +554,7 @@ void Title::renderPlayers() {
|
||||
|
||||
// Obtiene un jugador a partir de su "id"
|
||||
auto Title::getPlayer(Player::Id id) -> std::shared_ptr<Player> {
|
||||
auto it = std::find_if(players_.begin(), players_.end(), [id](const auto& player) { return player->getId() == id; });
|
||||
auto it = std::ranges::find_if(players_, [id](const auto& player) { return player->getId() == id; });
|
||||
|
||||
if (it != players_.end()) {
|
||||
return *it;
|
||||
|
||||
@@ -21,7 +21,7 @@ struct Gamepad;
|
||||
|
||||
// --- Constantes ---
|
||||
constexpr std::string_view TEXT_COPYRIGHT = "@2020,2025 JailDesigner"; // Texto de copyright
|
||||
constexpr bool ALLOW_TITLE_ANIMATION_SKIP = false; // Permite saltar la animación del título
|
||||
constexpr bool ALLOW_TITLE_ANIMATION_SKIP = false; // Permite saltar la animación del título
|
||||
|
||||
// --- Clase Title: gestiona el estado de título/menú principal del juego ---
|
||||
class Title {
|
||||
@@ -63,9 +63,9 @@ class Title {
|
||||
Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad
|
||||
int counter_ = 0; // Temporizador para la pantalla de título
|
||||
int num_controllers_; // Número de mandos conectados
|
||||
bool should_render_start_prompt_ = false; // Indica si se muestra el texto de PRESS START BUTTON TO PLAY
|
||||
bool player1_start_pressed_ = false; // Indica si se ha pulsado el botón de empezar para el jugador 1
|
||||
bool player2_start_pressed_ = false; // Indica si se ha pulsado el botón de empezar para el jugador 2
|
||||
bool should_render_start_prompt_ = false; // Indica si se muestra el texto de PRESS START BUTTON TO PLAY
|
||||
bool player1_start_pressed_ = false; // Indica si se ha pulsado el botón de empezar para el jugador 1
|
||||
bool player2_start_pressed_ = false; // Indica si se ha pulsado el botón de empezar para el jugador 2
|
||||
|
||||
// --- Ciclo de vida del título ---
|
||||
void update(); // Actualiza las variables del objeto
|
||||
|
||||
@@ -1,155 +1,157 @@
|
||||
#include "shutdown.h"
|
||||
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <string>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
namespace SystemShutdown {
|
||||
|
||||
#ifndef _WIN32
|
||||
// Función auxiliar para sistemas Unix-like
|
||||
ShutdownResult executeUnixShutdown(const char* command, char* const args[]) {
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid == 0) {
|
||||
// Proceso hijo
|
||||
execvp(command, args);
|
||||
// Si llegamos aquí, execvp falló
|
||||
std::cerr << "Error: No se pudo ejecutar " << command << std::endl;
|
||||
_exit(1);
|
||||
} else if (pid > 0) {
|
||||
// Proceso padre
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
return (WEXITSTATUS(status) == 0) ? ShutdownResult::SUCCESS : ShutdownResult::ERROR_SYSTEM_CALL;
|
||||
} else {
|
||||
return ShutdownResult::ERROR_FORK_FAILED;
|
||||
}
|
||||
// Función auxiliar para sistemas Unix-like
|
||||
auto executeUnixShutdown(const char* command, const std::vector<char*>& args) -> ShutdownResult {
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid == 0) {
|
||||
// Proceso hijo
|
||||
execvp(command, args.data());
|
||||
// Si llegamos aquí, execvp falló
|
||||
std::cerr << "Error: No se pudo ejecutar " << command << '\n';
|
||||
_exit(1);
|
||||
} else if (pid > 0) {
|
||||
// Proceso padre
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
return (WEXITSTATUS(status) == 0) ? ShutdownResult::SUCCESS : ShutdownResult::ERROR_SYSTEM_CALL;
|
||||
} else {
|
||||
return ShutdownResult::ERROR_FORK_FAILED;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Implementación de las funciones públicas
|
||||
ShutdownResult shutdownSystem() {
|
||||
ShutdownConfig config;
|
||||
return shutdownSystem(config);
|
||||
}
|
||||
// Implementación de las funciones públicas
|
||||
auto shutdownSystem() -> ShutdownResult {
|
||||
ShutdownConfig config;
|
||||
return shutdownSystem(config);
|
||||
}
|
||||
|
||||
ShutdownResult shutdownSystem(int delay_seconds, bool force_apps) {
|
||||
ShutdownConfig config;
|
||||
config.delay_seconds = delay_seconds;
|
||||
config.force_close_apps = force_apps;
|
||||
return shutdownSystem(config);
|
||||
}
|
||||
auto shutdownSystem(int delay_seconds, bool force_apps) -> ShutdownResult {
|
||||
ShutdownConfig config;
|
||||
config.delay_seconds = delay_seconds;
|
||||
config.force_close_apps = force_apps;
|
||||
return shutdownSystem(config);
|
||||
}
|
||||
|
||||
ShutdownResult shutdownSystem(const ShutdownConfig& config) {
|
||||
auto shutdownSystem(const ShutdownConfig& config) -> ShutdownResult {
|
||||
#ifdef _WIN32
|
||||
// Windows: Usar CreateProcess
|
||||
STARTUPINFOA si = {0};
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
si.cb = sizeof(si);
|
||||
|
||||
// Crear comando con el delay especificado
|
||||
std::string command = "shutdown.exe /s /t " + std::to_string(config.delay_seconds);
|
||||
if (config.force_close_apps) {
|
||||
command += " /f";
|
||||
}
|
||||
|
||||
// CreateProcess necesita un array de char modificable
|
||||
char* cmd_buffer = new char[command.length() + 1];
|
||||
strcpy(cmd_buffer, command.c_str());
|
||||
|
||||
bool success = CreateProcessA(
|
||||
NULL, // lpApplicationName
|
||||
cmd_buffer, // lpCommandLine
|
||||
NULL, // lpProcessAttributes
|
||||
NULL, // lpThreadAttributes
|
||||
FALSE, // bInheritHandles
|
||||
0, // dwCreationFlags
|
||||
NULL, // lpEnvironment
|
||||
NULL, // lpCurrentDirectory
|
||||
&si, // lpStartupInfo
|
||||
&pi // lpProcessInformation
|
||||
);
|
||||
|
||||
delete[] cmd_buffer;
|
||||
|
||||
if (success) {
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
return ShutdownResult::SUCCESS;
|
||||
} else {
|
||||
DWORD error = GetLastError();
|
||||
if (error == ERROR_ACCESS_DENIED) {
|
||||
return ShutdownResult::ERROR_PERMISSION;
|
||||
}
|
||||
return ShutdownResult::ERROR_SYSTEM_CALL;
|
||||
// Windows: Usar CreateProcess
|
||||
STARTUPINFOA si = {0};
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
si.cb = sizeof(si);
|
||||
|
||||
// Crear comando con el delay especificado
|
||||
std::string command = "shutdown.exe /s /t " + std::to_string(config.delay_seconds);
|
||||
if (config.force_close_apps) {
|
||||
command += " /f";
|
||||
}
|
||||
|
||||
// CreateProcess necesita un array de char modificable
|
||||
char* cmd_buffer = new char[command.length() + 1];
|
||||
strcpy(cmd_buffer, command.c_str());
|
||||
|
||||
bool success = CreateProcessA(
|
||||
NULL, // lpApplicationName
|
||||
cmd_buffer, // lpCommandLine
|
||||
NULL, // lpProcessAttributes
|
||||
NULL, // lpThreadAttributes
|
||||
FALSE, // bInheritHandles
|
||||
0, // dwCreationFlags
|
||||
NULL, // lpEnvironment
|
||||
NULL, // lpCurrentDirectory
|
||||
&si, // lpStartupInfo
|
||||
&pi // lpProcessInformation
|
||||
);
|
||||
|
||||
delete[] cmd_buffer;
|
||||
|
||||
if (success) {
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
return ShutdownResult::SUCCESS;
|
||||
} else {
|
||||
DWORD error = GetLastError();
|
||||
if (error == ERROR_ACCESS_DENIED) {
|
||||
return ShutdownResult::ERROR_PERMISSION;
|
||||
}
|
||||
return ShutdownResult::ERROR_SYSTEM_CALL;
|
||||
}
|
||||
|
||||
#elif __APPLE__
|
||||
// macOS - apagado inmediato
|
||||
char* args[] = {
|
||||
const_cast<char*>("shutdown"),
|
||||
const_cast<char*>("-h"),
|
||||
const_cast<char*>("now"),
|
||||
NULL
|
||||
};
|
||||
|
||||
return executeUnixShutdown("shutdown", args);
|
||||
// macOS - apagado inmediato
|
||||
std::vector<char*> args = {
|
||||
const_cast<char*>("shutdown"),
|
||||
const_cast<char*>("-h"),
|
||||
const_cast<char*>("now"),
|
||||
nullptr};
|
||||
|
||||
return executeUnixShutdown("shutdown", args);
|
||||
|
||||
#elif __linux__
|
||||
// Linux - apagado inmediato
|
||||
char* args[] = {
|
||||
const_cast<char*>("shutdown"),
|
||||
const_cast<char*>("-h"),
|
||||
const_cast<char*>("now"),
|
||||
NULL
|
||||
};
|
||||
|
||||
return executeUnixShutdown("shutdown", args);
|
||||
// Linux - apagado inmediato
|
||||
std::vector<char*> args = {
|
||||
const_cast<char*>("shutdown"),
|
||||
const_cast<char*>("-h"),
|
||||
const_cast<char*>("now"),
|
||||
nullptr};
|
||||
|
||||
return executeUnixShutdown("shutdown", args);
|
||||
|
||||
#else
|
||||
return ShutdownResult::ERROR_UNSUPPORTED;
|
||||
return ShutdownResult::ERROR_UNSUPPORTED;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
const char* resultToString(ShutdownResult result) {
|
||||
switch (result) {
|
||||
case ShutdownResult::SUCCESS:
|
||||
return "Apagado iniciado exitosamente";
|
||||
case ShutdownResult::ERROR_PERMISSION:
|
||||
return "Error: Permisos insuficientes";
|
||||
case ShutdownResult::ERROR_SYSTEM_CALL:
|
||||
return "Error: Fallo en la llamada al sistema";
|
||||
case ShutdownResult::ERROR_FORK_FAILED:
|
||||
return "Error: No se pudo crear proceso hijo";
|
||||
case ShutdownResult::ERROR_UNSUPPORTED:
|
||||
return "Error: Sistema operativo no soportado";
|
||||
default:
|
||||
return "Error desconocido";
|
||||
}
|
||||
auto resultToString(ShutdownResult result) -> const char* {
|
||||
switch (result) {
|
||||
case ShutdownResult::SUCCESS:
|
||||
return "Apagado iniciado exitosamente";
|
||||
case ShutdownResult::ERROR_PERMISSION:
|
||||
return "Error: Permisos insuficientes";
|
||||
case ShutdownResult::ERROR_SYSTEM_CALL:
|
||||
return "Error: Fallo en la llamada al sistema";
|
||||
case ShutdownResult::ERROR_FORK_FAILED:
|
||||
return "Error: No se pudo crear proceso hijo";
|
||||
case ShutdownResult::ERROR_UNSUPPORTED:
|
||||
return "Error: Sistema operativo no soportado";
|
||||
default:
|
||||
return "Error desconocido";
|
||||
}
|
||||
}
|
||||
|
||||
bool isShutdownSupported() {
|
||||
auto isShutdownSupported() -> bool {
|
||||
#if defined(_WIN32) || defined(__APPLE__) || defined(__linux__)
|
||||
return true;
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
const char* getRequiredPermissions() {
|
||||
auto getRequiredPermissions() -> const char* {
|
||||
#ifdef _WIN32
|
||||
return "Requiere permisos de Administrador en Windows";
|
||||
return "Requiere permisos de Administrador en Windows";
|
||||
#elif defined(__APPLE__) || defined(__linux__)
|
||||
return "Requiere permisos de root/sudo en Unix";
|
||||
return "Requiere permisos de root/sudo en Unix";
|
||||
#else
|
||||
return "Sistema no soportado";
|
||||
return "Sistema no soportado";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace SystemShutdown
|
||||
} // namespace SystemShutdown
|
||||
@@ -5,33 +5,29 @@ namespace SystemShutdown {
|
||||
|
||||
// --- Enums ---
|
||||
enum class ShutdownResult {
|
||||
SUCCESS = 0, // Éxito
|
||||
ERROR_PERMISSION, // Error de permisos insuficientes
|
||||
ERROR_SYSTEM_CALL, // Error en la llamada al sistema
|
||||
ERROR_FORK_FAILED, // Error al crear proceso hijo (Unix)
|
||||
ERROR_UNSUPPORTED // Sistema operativo no soportado
|
||||
SUCCESS = 0, // Éxito
|
||||
ERROR_PERMISSION, // Error de permisos insuficientes
|
||||
ERROR_SYSTEM_CALL, // Error en la llamada al sistema
|
||||
ERROR_FORK_FAILED, // Error al crear proceso hijo (Unix)
|
||||
ERROR_UNSUPPORTED // Sistema operativo no soportado
|
||||
};
|
||||
|
||||
// --- Estructuras ---
|
||||
struct ShutdownConfig {
|
||||
int delay_seconds; // Segundos de retraso antes del apagado
|
||||
bool force_close_apps; // Forzar cierre de aplicaciones
|
||||
const char* shutdown_message; // Mensaje mostrado durante el apagado
|
||||
|
||||
// Constructor con valores por defecto
|
||||
ShutdownConfig()
|
||||
: delay_seconds(5)
|
||||
, force_close_apps(true)
|
||||
, shutdown_message("El sistema se apagará...")
|
||||
{}
|
||||
int delay_seconds{5}; // Segundos de retraso antes del apagado
|
||||
bool force_close_apps{true}; // Forzar cierre de aplicaciones
|
||||
const char* shutdown_message{"El sistema se apagará..."}; // Mensaje mostrado durante el apagado
|
||||
|
||||
// Constructor con valores por defecto
|
||||
ShutdownConfig() = default;
|
||||
};
|
||||
|
||||
// --- Funciones ---
|
||||
ShutdownResult shutdownSystem(); // Apaga el sistema con configuración por defecto
|
||||
ShutdownResult shutdownSystem(const ShutdownConfig& config); // Apaga el sistema con configuración personalizada
|
||||
ShutdownResult shutdownSystem(int delay_seconds, bool force_apps = true); // Apaga el sistema con parámetros simples
|
||||
const char* resultToString(ShutdownResult result); // Convierte un código de resultado a string descriptivo
|
||||
bool isShutdownSupported(); // Verifica si el sistema actual soporta apagado programático
|
||||
const char* getRequiredPermissions(); // Obtiene información sobre los permisos necesarios
|
||||
auto shutdownSystem() -> ShutdownResult; // Apaga el sistema con configuración por defecto
|
||||
auto shutdownSystem(const ShutdownConfig& config) -> ShutdownResult; // Apaga el sistema con configuración personalizada
|
||||
auto shutdownSystem(int delay_seconds, bool force_apps = true) -> ShutdownResult; // Apaga el sistema con parámetros simples
|
||||
auto resultToString(ShutdownResult result) -> const char*; // Convierte un código de resultado a string descriptivo
|
||||
auto isShutdownSupported() -> bool; // Verifica si el sistema actual soporta apagado programático
|
||||
auto getRequiredPermissions() -> const char*; // Obtiene información sobre los permisos necesarios
|
||||
|
||||
} // namespace SystemShutdown
|
||||
} // namespace SystemShutdown
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user