diff --git a/.clang-format b/.clang-format index 58bffd5..e148dad 100644 --- a/.clang-format +++ b/.clang-format @@ -1,6 +1,7 @@ BasedOnStyle: Google IndentWidth: 4 -IndentAccessModifiers: true +NamespaceIndentation: All +IndentAccessModifiers: false ColumnLimit: 0 # Sin límite de longitud de línea BreakBeforeBraces: Attach # Llaves en la misma línea AllowShortIfStatementsOnASingleLine: true diff --git a/.clang-tidy b/.clang-tidy index ff3dedf..836f008 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,104 +1,107 @@ Checks: - # Estrategia: Habilitar checks uno por uno, aplicar fix, compilar, commit - # ✅ Check 1: readability-uppercase-literal-suffix (1.0f → 1.0F) - # ✅ Check 2: readability-math-missing-parentheses (claridad en ops matemáticas) - # ✅ Check 3: readability-identifier-naming (DESHABILITADO temporalmente - cascada de cambios) - # ✅ Check 4: readability-const-return-type (código ya cumple) - # ✅ Check 5: readability-else-after-return (código ya cumple) - # ✅ Check 6: readability-simplify-boolean-expr (código ya cumple) - # ✅ Check 7: readability-* (225 fixes aplicados) - readability-* - - -readability-identifier-naming # Excluido (cascada de cambios) - - -readability-identifier-length # Excluido (nombres cortos son OK) - - -readability-magic-numbers # Excluido (muchos falsos positivos) - - -readability-convert-member-functions-to-static # Excluido (rompe encapsulación) - - -readability-use-anyofallof # Excluido (C++20 ranges - no todos los compiladores) - - -readability-function-cognitive-complexity # Excluido (complejidad ciclomática aceptable) - - -clang-analyzer-security.insecureAPI.rand # Excluido (rand() es suficiente para juegos) - # ✅ Check 8: modernize-* (215 fixes aplicados) - modernize-* - - -modernize-use-trailing-return-type # Excluido (estilo controversial) - - -modernize-avoid-c-arrays # Excluido (arrays C son OK en algunos contextos) - # ✅ Check 9: performance-* (91 fixes aplicados) - performance-* - - -performance-enum-size # Excluido (tamaño de enum no crítico) - # ✅ Check 10: bugprone-* (0 fixes - todos eran falsos positivos) - bugprone-* - - -bugprone-easily-swappable-parameters # Excluido (muchos falsos positivos) - - -bugprone-narrowing-conversions # Excluido (conversiones intencionales) - - -bugprone-integer-division # Excluido (divisiones enteras OK en contexto) - - -bugprone-branch-clone # Excluido (fall-through en switch es intencional) - - -bugprone-switch-missing-default-case # Excluido (no todos los switches necesitan default) - - -bugprone-implicit-widening-of-multiplication-result # Excluido (valores pequeños, sin overflow) - - -bugprone-exception-escape # Excluido (excepciones en main terminan el programa - OK) - # ✅ Check 11: llvm-include-order (validar orden de includes - 0 errores) - - llvm-include-order - # ⏸️ Check 12: misc-include-cleaner (DESHABILITADO temporalmente - requiere refactorización masiva de includes) - - -misc-include-cleaner + - -readability-identifier-length + - -readability-magic-numbers + - -bugprone-integer-division + - -bugprone-easily-swappable-parameters + - -bugprone-narrowing-conversions + - -modernize-avoid-c-arrays WarningsAsErrors: '*' -# No usar HeaderFilterRegex - usamos .clang-tidy local en source/core/audio/ para excluir +# Headers nostres (excloem source/external/ que conté dependències de tercers no editables) +HeaderFilterRegex: 'source/(core|game|utils)/' FormatStyle: file CheckOptions: - # Variables locales en snake_case - - { key: readability-identifier-naming.VariableCase, value: lower_case } + # bugprone-empty-catch: aceptar catches vacíos marcados con @INTENTIONAL en un comentario + - { key: bugprone-empty-catch.IgnoreCatchWithKeywords, value: '@INTENTIONAL' } - # Miembros privados en snake_case con sufijo _ + # ===================================================================== + # CONSTANTES → UPPER_CASE (compile-time y runtime, en cualquier scope) + # ===================================================================== + # Todo lo que sea const o constexpr se identifica visualmente en UPPER_CASE, + # sin importar si es global, local, miembro o static. + + # constexpr en cualquier scope (globales y locales) + - { key: readability-identifier-naming.ConstexprVariableCase, value: UPPER_CASE } + + # Constantes globales (const no-constexpr) + - { key: readability-identifier-naming.GlobalConstantCase, value: UPPER_CASE } + + # Constantes locales (const en función) + - { key: readability-identifier-naming.LocalConstantCase, value: UPPER_CASE } + + # Static const a nivel de archivo/namespace + - { key: readability-identifier-naming.StaticConstantCase, value: UPPER_CASE } + + # Miembros static const/constexpr de clase (p.ej. static constexpr int MAX = 100;) + - { key: readability-identifier-naming.ClassConstantCase, value: UPPER_CASE } + + # Miembros const no-static de clase (p.ej. const int limit;) + - { key: readability-identifier-naming.ConstantMemberCase, value: UPPER_CASE } + + # Valores de enums + - { key: readability-identifier-naming.EnumConstantCase, value: UPPER_CASE } + + # NOTA: Los parámetros const NO se tratan como constantes aquí. + # Un parámetro sigue siendo un parámetro aunque sea const → hereda ParameterCase. + + # ===================================================================== + # VARIABLES NO-CONST + # ===================================================================== + + # Variables locales + - { key: readability-identifier-naming.VariableCase, value: lower_case } + - { key: readability-identifier-naming.LocalVariableCase, value: lower_case } + + # Parámetros de función + - { key: readability-identifier-naming.ParameterCase, value: lower_case } + + # Variables estáticas no-const (static locales, static file-scope, + # y static members no-const de clase como el instance_ de un Singleton). + # Sufijo _ para marcar que tienen storage estático. + - { key: readability-identifier-naming.StaticVariableCase, value: lower_case } + - { key: readability-identifier-naming.StaticVariableSuffix, value: _ } + + # ===================================================================== + # MIEMBROS DE CLASE NO-CONST + # ===================================================================== + # Privados: snake_case con sufijo _ - { key: readability-identifier-naming.PrivateMemberCase, value: lower_case } - { key: readability-identifier-naming.PrivateMemberSuffix, value: _ } - # Miembros protegidos en snake_case con sufijo _ + # Protegidos: snake_case con sufijo _ - { key: readability-identifier-naming.ProtectedMemberCase, value: lower_case } - { key: readability-identifier-naming.ProtectedMemberSuffix, value: _ } - # Miembros públicos en snake_case (sin sufijo) + # Públicos: snake_case sin sufijo - { key: readability-identifier-naming.PublicMemberCase, value: lower_case } - # Namespaces en CamelCase - - { key: readability-identifier-naming.NamespaceCase, value: CamelCase } - - # Variables estáticas privadas como miembros privados - - { key: readability-identifier-naming.StaticVariableCase, value: lower_case } - - { key: readability-identifier-naming.StaticVariableSuffix, value: _ } - - # Constantes estáticas sin sufijo - - { key: readability-identifier-naming.StaticConstantCase, value: UPPER_CASE } - - # Constantes globales en UPPER_CASE - - { key: readability-identifier-naming.GlobalConstantCase, value: UPPER_CASE } - - # Variables constexpr globales en UPPER_CASE - - { key: readability-identifier-naming.ConstexprVariableCase, value: UPPER_CASE } - - # Constantes locales en UPPER_CASE - - { key: readability-identifier-naming.LocalConstantCase, value: UPPER_CASE } - - # Constexpr miembros en UPPER_CASE (sin sufijo) - - { key: readability-identifier-naming.ConstexprMemberCase, value: UPPER_CASE } - - # Constexpr miembros privados/protegidos con sufijo _ - - { key: readability-identifier-naming.ConstexprMethodCase, value: UPPER_CASE } - - # Clases, structs y enums en CamelCase + # ===================================================================== + # TIPOS + # ===================================================================== - { key: readability-identifier-naming.ClassCase, value: CamelCase } - { key: readability-identifier-naming.StructCase, value: CamelCase } - { key: readability-identifier-naming.EnumCase, value: CamelCase } + - { key: readability-identifier-naming.UnionCase, value: CamelCase } + - { key: readability-identifier-naming.TypeAliasCase, value: CamelCase } + - { key: readability-identifier-naming.TypedefCase, value: CamelCase } + - { key: readability-identifier-naming.TemplateParameterCase, value: CamelCase } - # Valores de enums en UPPER_CASE - - { key: readability-identifier-naming.EnumConstantCase, value: UPPER_CASE } + # Namespaces + - { key: readability-identifier-naming.NamespaceCase, value: CamelCase } - # Métodos en camelBack (sin sufijos) + # ===================================================================== + # FUNCIONES Y MÉTODOS (incluyendo constexpr) + # ===================================================================== + # Un método/función constexpr es un invocable, no una constante → camelBack. + - { key: readability-identifier-naming.FunctionCase, value: camelBack } + - { key: readability-identifier-naming.ConstexprFunctionCase, value: camelBack } - { key: readability-identifier-naming.MethodCase, value: camelBack } - { key: readability-identifier-naming.PrivateMethodCase, value: camelBack } - { key: readability-identifier-naming.ProtectedMethodCase, value: camelBack } - { key: readability-identifier-naming.PublicMethodCase, value: camelBack } - - # Funciones en camelBack - - { key: readability-identifier-naming.FunctionCase, value: camelBack } - - # Parámetros en lower_case - - { key: readability-identifier-naming.ParameterCase, value: lower_case } - - # misc-include-cleaner: Ignorar SDL (genera falsos positivos) - - { key: misc-include-cleaner.IgnoreHeaders, value: 'SDL3/.*' } + - { key: readability-identifier-naming.ConstexprMethodCase, value: camelBack } diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 0000000..fe14911 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,92 @@ +#!/usr/bin/env bash +# Pre-commit hook: aplica clang-format als fitxers C++ staged abans del commit. +# - Només toca fitxers staged dins source/ (exclou source/external/ i source/legacy/). +# - Avorta el commit si hi ha canvis NO staged en aquests fitxers (per no incloure'ls sense voler). + +set -euo pipefail + +if ! command -v clang-format >/dev/null 2>&1; then + echo "pre-commit: clang-format no trobat — saltant format check" >&2 + exit 0 +fi + +mapfile -t STAGED < <(git diff --cached --name-only --diff-filter=ACMR \ + | grep -E '^source/.*\.(cpp|hpp|h)$' \ + | grep -vE '^source/(external|legacy)/' || true) + +if [ ${#STAGED[@]} -eq 0 ]; then + exit 0 +fi + +UNSTAGED_DIRTY=() +for f in "${STAGED[@]}"; do + if ! git diff --quiet -- "$f"; then + UNSTAGED_DIRTY+=("$f") + fi +done + +if [ ${#UNSTAGED_DIRTY[@]} -gt 0 ]; then + echo "pre-commit: aquests fitxers tenen canvis NO staged i estan al commit." >&2 + echo " Fes 'git add' o 'git stash' abans de continuar:" >&2 + printf ' %s\n' "${UNSTAGED_DIRTY[@]}" >&2 + exit 1 +fi + +clang-format -i "${STAGED[@]}" +git add -- "${STAGED[@]}" + +# --- clang-tidy només sobre els fitxers staged --- +if ! command -v clang-tidy >/dev/null 2>&1; then + echo "pre-commit: clang-tidy no trobat — saltant tidy" >&2 + exit 0 +fi + +REPO_ROOT="$(git rev-parse --show-toplevel)" +BUILD_DIR="$REPO_ROOT/build" + +if [ ! -f "$BUILD_DIR/compile_commands.json" ]; then + echo "pre-commit: generant compile_commands.json (build dir buit)..." >&2 + cmake -S "$REPO_ROOT" -B "$BUILD_DIR" >/dev/null +fi + +echo "pre-commit: clang-tidy sobre ${#STAGED[@]} fitxer(s)..." >&2 +if ! clang-tidy -p "$BUILD_DIR" --quiet "${STAGED[@]}"; then + echo "pre-commit: clang-tidy ha trobat errors — commit avortat" >&2 + exit 1 +fi + +# --- cppcheck només sobre els .cpp staged --- +if ! command -v cppcheck >/dev/null 2>&1; then + echo "pre-commit: cppcheck no trobat — saltant cppcheck" >&2 + exit 0 +fi + +CPP_STAGED=() +for f in "${STAGED[@]}"; do + [[ "$f" == *.cpp ]] && CPP_STAGED+=("$f") +done + +if [ ${#CPP_STAGED[@]} -eq 0 ]; then + exit 0 +fi + +echo "pre-commit: cppcheck sobre ${#CPP_STAGED[@]} fitxer(s)..." >&2 +if ! cppcheck \ + --enable=warning,style,performance,portability \ + --std=c++20 \ + --language=c++ \ + --inline-suppr \ + --suppress=missingIncludeSystem \ + --suppress=toomanyconfigs \ + --suppress='*:*source/external/*' \ + --suppress='*:*source/legacy/*' \ + --suppress=normalCheckLevelMaxBranches \ + -D_DEBUG \ + -DLINUX_BUILD \ + --quiet \ + --error-exitcode=1 \ + -I "$REPO_ROOT/source" \ + "${CPP_STAGED[@]}"; then + echo "pre-commit: cppcheck ha trobat errors — commit avortat" >&2 + exit 1 +fi diff --git a/.gitignore b/.gitignore index 639e5c3..2f107db 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ tools/pack_resources/pack_resources.exe *.zip *.tar.gz *.dmg +dist/ # Generated resources resources.pack @@ -100,3 +101,5 @@ ehthumbs_vista.db *.bak *.swp *.swo + +.cache/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f512d0..8777d7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,122 +1,193 @@ -# CMakeLists.txt +cmake_minimum_required(VERSION 3.16) +project(orni VERSION 0.7.2 LANGUAGES CXX) -cmake_minimum_required(VERSION 3.10) -project(orni VERSION 0.7.2) - -# Info del proyecto +# Info del projecte (font de veritat per a project.h) set(PROJECT_LONG_NAME "Orni Attack") set(PROJECT_COPYRIGHT_ORIGINAL "© 1999 Visente i Sergi") set(PROJECT_COPYRIGHT_PORT "© 2025 JailDesigner") set(PROJECT_COPYRIGHT "${PROJECT_COPYRIGHT_ORIGINAL}, ${PROJECT_COPYRIGHT_PORT}") -# Establecer estándar de C++ -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED True) - -# Exportar comandos de compilación para herramientas de análisis -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) - -# --- GENERACIÓN DE VERSIÓN AUTOMÁTICA --- -find_package(Git QUIET) -if(GIT_FOUND) - execute_process( - COMMAND ${GIT_EXECUTABLE} rev-parse --short=7 HEAD - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE GIT_HASH - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_QUIET - ) -else() - set(GIT_HASH "unknown") +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE) +endif() + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# --- GENERACIÓ DEL project.h AMB GIT HASH --- +# Si GIT_HASH ve passat des de fora (Makefile), l'usem; si no, el resolem amb git. +if(NOT DEFINED GIT_HASH OR GIT_HASH STREQUAL "") + find_package(Git QUIET) + if(GIT_FOUND) + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-parse --short=7 HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_HASH + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + endif() + if(NOT DEFINED GIT_HASH OR GIT_HASH STREQUAL "") + set(GIT_HASH "unknown") + endif() endif() -# Configurar archivo de versión configure_file(${CMAKE_SOURCE_DIR}/source/project.h.in ${CMAKE_BINARY_DIR}/project.h @ONLY) -# --- LISTA DE FUENTES (AUTO-DESCUBRIMIENTO) --- -# Buscar automáticamente todos los archivos .cpp en core/, game/ y main.cpp -file(GLOB_RECURSE CORE_SOURCES "${CMAKE_SOURCE_DIR}/source/core/*.cpp") -file(GLOB_RECURSE GAME_SOURCES "${CMAKE_SOURCE_DIR}/source/game/*.cpp") +# --- LLISTA DE FONTS (AUTO-DESCOBRIMENT) --- +# Cerquem tots els .cpp dins core/ i game/, més main.cpp. Exclou legacy/. +file(GLOB_RECURSE CORE_SOURCES CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/source/core/*.cpp") +file(GLOB_RECURSE GAME_SOURCES CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/source/game/*.cpp") +file(GLOB_RECURSE EXTERNAL_SOURCES CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/source/external/*.cpp") + set(APP_SOURCES ${CORE_SOURCES} ${GAME_SOURCES} + ${EXTERNAL_SOURCES} source/main.cpp ) - -# Excluir archivos legacy (código Pascal de referencia) list(FILTER APP_SOURCES EXCLUDE REGEX ".*/legacy/.*") -# Log de archivos encontrados (útil para debug) list(LENGTH APP_SOURCES APP_SOURCES_COUNT) -message(STATUS "Archivos .cpp encontrados: ${APP_SOURCES_COUNT}") +message(STATUS "Fonts .cpp trobades: ${APP_SOURCES_COUNT}") -# Configuración de SDL3 +# --- SDL3 --- find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3) -message(STATUS "SDL3 encontrado: ${SDL3_INCLUDE_DIRS}") -# --- AÑADIR EJECUTABLE --- add_executable(${PROJECT_NAME} ${APP_SOURCES}) -# --- DIRECTORIOS DE INCLUSIÓN --- -target_include_directories(${PROJECT_NAME} PUBLIC +target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_SOURCE_DIR}/source" "${CMAKE_BINARY_DIR}" ) -# Enlazar las librerías SDL3 target_link_libraries(${PROJECT_NAME} PRIVATE SDL3::SDL3) -# --- CONFIGURACIÓN PLATAFORMAS Y COMPILADOR --- -# Configuración de flags de compilación -target_compile_options(${PROJECT_NAME} PRIVATE -Wall) -target_compile_options(${PROJECT_NAME} PRIVATE $<$:-O2 -ffunction-sections -fdata-sections>) +# Silencia warnings de codi de tercers (mateixa filosofia que el +# .clang-tidy a source/external/). Només afecta aquests TUs concrets; +# la resta del codi continua compilant amb -Wall -Wextra -Wpedantic. +if(EXTERNAL_SOURCES) + set_source_files_properties( + ${EXTERNAL_SOURCES} + PROPERTIES COMPILE_OPTIONS "-Wno-missing-field-initializers;-Wno-deprecated-declarations" + ) +endif() -# Definir _DEBUG en modo Debug y RELEASE_BUILD en modo Release -target_compile_definitions(${PROJECT_NAME} PRIVATE $<$:_DEBUG>) -target_compile_definitions(${PROJECT_NAME} PRIVATE $<$:RELEASE_BUILD>) +target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic) +target_compile_options(${PROJECT_NAME} PRIVATE + $<$:-O2 -ffunction-sections -fdata-sections> +) + +target_compile_definitions(${PROJECT_NAME} PRIVATE + $<$:_DEBUG> + $<$:RELEASE_BUILD> +) -# Definir MACOS_BUNDLE si es un bundle de macOS if(APPLE AND MACOSX_BUNDLE) target_compile_definitions(${PROJECT_NAME} PRIVATE MACOS_BUNDLE) endif() -# Configuración específica para cada plataforma if(WIN32) target_compile_definitions(${PROJECT_NAME} PRIVATE WINDOWS_BUILD) target_link_libraries(${PROJECT_NAME} PRIVATE mingw32) - # Static linking for libgcc and libstdc++ (avoid DLL dependencies for distribution) target_link_options(${PROJECT_NAME} PRIVATE -static-libgcc -static-libstdc++ -static ) - # Añadir icono en Windows (se configurará desde el Makefile con windres) elseif(APPLE) target_compile_definitions(${PROJECT_NAME} PRIVATE MACOS_BUILD) target_compile_options(${PROJECT_NAME} PRIVATE -Wno-deprecated) - set(CMAKE_OSX_ARCHITECTURES "arm64") elseif(UNIX AND NOT APPLE) target_compile_definitions(${PROJECT_NAME} PRIVATE LINUX_BUILD) endif() -# Especificar la ubicación del ejecutable -set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}) +# --- EINA STANDALONE: pack_resources --- +# Executable auxiliar que empaqueta `data/` a `build/resources.pack`. +# EXCLUDE_FROM_ALL: només es compila quan algun target en depèn (ho fa +# `resource_pack`). Build manual: `cmake --build build --target pack_resources`. +add_executable(pack_resources EXCLUDE_FROM_ALL + tools/pack_resources/pack_resources.cpp + source/core/resources/resource_pack.cpp +) +target_include_directories(pack_resources PRIVATE "${CMAKE_SOURCE_DIR}/source") +target_compile_options(pack_resources PRIVATE -Wall -Wextra -Wpedantic) -# --- STATIC ANALYSIS TARGETS --- -# Buscar herramientas de análisis estático -find_program(CLANG_FORMAT_EXE NAMES clang-format) +# --- REGENERACIÓ AUTOMÀTICA DE build/resources.pack --- +# A cada build re-empaquetem data/ si algun fitxer dins ha canviat. Evita +# debugar amb un pack obsolet. CONFIGURE_DEPENDS força CMake a re-globbar +# a la pròxima invocació (recull fitxers nous afegits a data/). +file(GLOB_RECURSE DATA_FILES CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/data/*") +set(RESOURCE_PACK "${CMAKE_BINARY_DIR}/resources.pack") + +add_custom_command( + OUTPUT ${RESOURCE_PACK} + COMMAND $ + "${CMAKE_SOURCE_DIR}/data" + "${RESOURCE_PACK}" + DEPENDS pack_resources ${DATA_FILES} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Empaquetant data/ → build/resources.pack" + VERBATIM +) +add_custom_target(resource_pack ALL DEPENDS ${RESOURCE_PACK}) +add_dependencies(${PROJECT_NAME} resource_pack) + +# --- STATIC ANALYSIS / FORMAT TARGETS --- find_program(CLANG_TIDY_EXE NAMES clang-tidy) +find_program(CLANG_FORMAT_EXE NAMES clang-format) +find_program(CPPCHECK_EXE NAMES cppcheck) -# Recopilar todos los archivos fuente para formateo file(GLOB_RECURSE ALL_SOURCE_FILES "${CMAKE_SOURCE_DIR}/source/*.cpp" "${CMAKE_SOURCE_DIR}/source/*.hpp" + "${CMAKE_SOURCE_DIR}/source/*.h" ) -# Excluir directorios con checks deshabilitados -list(FILTER ALL_SOURCE_FILES EXCLUDE REGEX ".*/audio/.*") +list(FILTER ALL_SOURCE_FILES EXCLUDE REGEX ".*/external/.*") list(FILTER ALL_SOURCE_FILES EXCLUDE REGEX ".*/legacy/.*") -# Targets de clang-format +set(CPPCHECK_SOURCES ${ALL_SOURCE_FILES}) +list(FILTER CPPCHECK_SOURCES INCLUDE REGEX ".*\\.cpp$") + +if(CLANG_TIDY_EXE) + # En macOS, obtenir la ruta del SDK perquè clang-tidy trobe els headers del sistema. + set(CLANG_TIDY_EXTRA_ARGS "") + if(APPLE) + execute_process( + COMMAND xcrun --show-sdk-path + OUTPUT_VARIABLE MACOS_SDK_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(MACOS_SDK_PATH) + set(CLANG_TIDY_EXTRA_ARGS "--extra-arg=-isysroot${MACOS_SDK_PATH}") + message(STATUS "clang-tidy usarà SDK de macOS: ${MACOS_SDK_PATH}") + endif() + endif() + + add_custom_target(tidy + COMMAND ${CLANG_TIDY_EXE} + -p ${CMAKE_BINARY_DIR} + ${CLANG_TIDY_EXTRA_ARGS} + ${ALL_SOURCE_FILES} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMENT "Running clang-tidy..." + ) + + add_custom_target(tidy-fix + COMMAND ${CLANG_TIDY_EXE} + -p ${CMAKE_BINARY_DIR} + ${CLANG_TIDY_EXTRA_ARGS} + --fix + ${ALL_SOURCE_FILES} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMENT "Running clang-tidy with fixes..." + ) +else() + message(STATUS "clang-tidy no trobat - targets 'tidy' i 'tidy-fix' no disponibles") +endif() + if(CLANG_FORMAT_EXE) add_custom_target(format COMMAND ${CLANG_FORMAT_EXE} @@ -135,45 +206,29 @@ if(CLANG_FORMAT_EXE) COMMENT "Checking clang-format..." ) else() - message(STATUS "clang-format no encontrado - targets 'format' y 'format-check' no disponibles") + message(STATUS "clang-format no trobat - targets 'format' i 'format-check' no disponibles") endif() -# Targets de clang-tidy -if(CLANG_TIDY_EXE) - # En macOS, obtener la ruta del SDK para que clang-tidy encuentre los headers del sistema - set(CLANG_TIDY_EXTRA_ARGS "") - if(APPLE) - execute_process( - COMMAND xcrun --show-sdk-path - OUTPUT_VARIABLE MACOS_SDK_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - if(MACOS_SDK_PATH) - set(CLANG_TIDY_EXTRA_ARGS "--extra-arg=-isysroot${MACOS_SDK_PATH}") - message(STATUS "clang-tidy usará SDK de macOS: ${MACOS_SDK_PATH}") - endif() - endif() - - add_custom_target(tidy - COMMAND ${CLANG_TIDY_EXE} - -p ${CMAKE_BINARY_DIR} - ${CLANG_TIDY_EXTRA_ARGS} - --fix - --fix-errors - ${ALL_SOURCE_FILES} +if(CPPCHECK_EXE) + add_custom_target(cppcheck + COMMAND ${CPPCHECK_EXE} + --enable=warning,style,performance,portability + --std=c++20 + --language=c++ + --inline-suppr + --suppress=missingIncludeSystem + --suppress=toomanyconfigs + --suppress=*:*source/external/* + --suppress=*:*source/legacy/* + --suppress=normalCheckLevelMaxBranches + -D_DEBUG + -DLINUX_BUILD + --quiet + -I ${CMAKE_SOURCE_DIR}/source + ${CPPCHECK_SOURCES} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - COMMENT "Running clang-tidy with auto-fix..." - ) - - add_custom_target(tidy-check - COMMAND ${CLANG_TIDY_EXE} - -p ${CMAKE_BINARY_DIR} - ${CLANG_TIDY_EXTRA_ARGS} - --warnings-as-errors='*' - ${ALL_SOURCE_FILES} - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - COMMENT "Checking clang-tidy..." + COMMENT "Running cppcheck..." ) else() - message(STATUS "clang-tidy no encontrado - targets 'tidy' y 'tidy-check' no disponibles") + message(STATUS "cppcheck no trobat - target 'cppcheck' no disponible") endif() diff --git a/Makefile b/Makefile index 744b7f0..be9bcb3 100644 --- a/Makefile +++ b/Makefile @@ -1,380 +1,340 @@ -# ============================================================================== -# DIRECTORIES -# ============================================================================== -DIR_ROOT := $(dir $(abspath $(MAKEFILE_LIST))) -DIR_SOURCES := $(addprefix $(DIR_ROOT), source/) -DIR_BIN := $(DIR_ROOT) +PROJECT := orni +BUILDDIR := build -# ============================================================================== -# TARGET NAMES -# ============================================================================== +# Detecció de plataforma. En Windows CMake defaulteja a "NMake Makefiles" +# (que requereix Visual Studio); forcem MinGW Makefiles per usar el g++ de +# MinGW. nproc tampoc existeix en cmd.exe → fem servir NUMBER_OF_PROCESSORS. ifeq ($(OS),Windows_NT) - TARGET_NAME := $(shell powershell -Command "(Select-String -Path 'CMakeLists.txt' -Pattern 'project\s*\x28(\w+)').Matches.Groups[1].Value") - LONG_NAME := $(shell powershell -Command "(Select-String -Path 'CMakeLists.txt' -Pattern 'PROJECT_LONG_NAME\s+\x22(.+?)\x22').Matches.Groups[1].Value") + ifneq ($(MSYSTEM),) + NULDEV := /dev/null + else + NULDEV := NUL + endif + JOBS ?= $(NUMBER_OF_PROCESSORS) + HAS_NINJA := $(shell ninja --version 2>$(NULDEV)) + ifneq ($(HAS_NINJA),) + CMAKE_GEN := -G "Ninja" + else + CMAKE_GEN := -G "MinGW Makefiles" + endif else - TARGET_NAME := $(shell awk '/^project/ {gsub(/[)(]/, " "); print $$2}' CMakeLists.txt) - LONG_NAME := $(shell grep 'PROJECT_LONG_NAME' CMakeLists.txt | sed 's/.*"\(.*\)".*/\1/') + NULDEV := /dev/null + JOBS ?= $(shell nproc 2>/dev/null || echo 4) + HAS_NINJA := $(shell ninja --version 2>/dev/null) + ifneq ($(HAS_NINJA),) + CMAKE_GEN := -G "Ninja" + else + CMAKE_GEN := + endif endif -TARGET_FILE := $(DIR_BIN)$(TARGET_NAME) -RELEASE_FOLDER := $(TARGET_NAME)_release -RELEASE_FILE := $(RELEASE_FOLDER)/$(TARGET_NAME) - -# ============================================================================== -# VERSION -# ============================================================================== +# VERSION (única font de veritat: CMakeLists.txt project(...) VERSION ...). +# Lazy (=): només es calcula quan s'invoca un target que la usa. ifeq ($(OS),Windows_NT) - VERSION := v$(shell powershell -Command "(Select-String -Path 'CMakeLists.txt' -Pattern 'project.*VERSION\s+([0-9.]+)').Matches.Groups[1].Value") + VERSION = v$(shell powershell -Command "(Select-String -Path 'CMakeLists.txt' -Pattern 'project.*VERSION\s+([0-9.]+)').Matches.Groups[1].Value") else - VERSION := v$(shell grep "^project" CMakeLists.txt | tr -cd 0-9.) + VERSION = v$(shell grep '^project' CMakeLists.txt | sed -E 's/.*VERSION[[:space:]]+([0-9.]+).*/\1/') endif -# Release file names (depend on VERSION, so must come after) -ifeq ($(OS),Windows_NT) - RAW_VERSION := $(shell powershell -Command "\"$(VERSION)\" -replace '^v', ''") -else - RAW_VERSION := $(shell echo $(VERSION) | sed 's/^v//') +# GIT_HASH calculat al host i passat a CMake (evita problemes si CMake corre en +# entorns sense accés a git). +GIT_HASH := $(shell git rev-parse --short=7 HEAD 2>$(NULDEV)) +ifeq ($(GIT_HASH),) + GIT_HASH := unknown endif -WINDOWS_RELEASE := $(TARGET_NAME)-$(VERSION)-windows-x64.zip -MACOS_ARM_RELEASE := $(TARGET_NAME)-$(VERSION)-macos-arm64.dmg -MACOS_INTEL_RELEASE := $(TARGET_NAME)-$(VERSION)-macos-x64.dmg -LINUX_RELEASE := $(TARGET_NAME)-$(VERSION)-linux-x64.tar.gz -RPI_RELEASE := $(TARGET_NAME)-$(VERSION)-rpi-arm64.tar.gz -APP_NAME := $(LONG_NAME) + +CMAKE_DEFS := -DGIT_HASH=$(GIT_HASH) # ============================================================================== -# SOURCE FILES +# RELEASE — variables d'empaquetat per distribució # ============================================================================== -# Note: Source files are now auto-discovered by CMake using GLOB_RECURSE -# No need to maintain this list manually anymore! +APP_NAME := Orni Attack +DIST_DIR := dist +RELEASE_FOLDER := $(DIST_DIR)/_tmp +TARGET_FILE := $(BUILDDIR)/$(PROJECT) +RELEASE_FILE := $(RELEASE_FOLDER)/$(PROJECT) -# ============================================================================== -# PLATFORM-SPECIFIC UTILITIES -# ============================================================================== -# Use Unix commands always (MinGW Make uses bash even on Windows) -RMFILE := rm -f -RMDIR := rm -rf -MKDIR := mkdir -p +# Noms dels artefactes finals (amb VERSION i PROJECT) +WINDOWS_RELEASE := $(DIST_DIR)/$(PROJECT)-$(VERSION)-win32-x64.zip +MACOS_APPLE_SILICON_RELEASE := $(DIST_DIR)/$(PROJECT)-$(VERSION)-macos-apple-silicon.dmg +LINUX_RELEASE := $(DIST_DIR)/$(PROJECT)-$(VERSION)-linux.tar.gz +# Variables específiques de Windows (PowerShell). El subst escapa apòstrofs. ifeq ($(OS),Windows_NT) - # Windows-specific: Force cmd.exe shell for PowerShell commands - SHELL := cmd.exe + WIN_TARGET_FILE := $(BUILDDIR)/$(APP_NAME) + WIN_RELEASE_FILE := $(RELEASE_FOLDER)/$(APP_NAME) + WIN_RELEASE_FILE_PS := $(subst ','',$(WIN_RELEASE_FILE)) + UNAME_S := else - # Unix-specific - UNAME_S := $(shell uname -s) + WIN_TARGET_FILE := $(TARGET_FILE) + WIN_RELEASE_FILE := $(RELEASE_FILE) + WIN_RELEASE_FILE_PS := $(WIN_RELEASE_FILE) + UNAME_S := $(shell uname -s) +endif + +# Helpers cross-platform. +ifeq ($(OS),Windows_NT) + RMFILE := del /Q + RMDIR := rmdir /S /Q + MKDIR := mkdir +else + RMFILE := rm -f + RMDIR := rm -rdf + MKDIR := mkdir -p +endif + +.PHONY: all debug release _windows-release _macos-release _linux-release \ + run run-debug clean rebuild show-version pack \ + format format-check tidy tidy-fix cppcheck hooks-install help + +# ============================================================================== +# COMPILACIÓ +# ============================================================================== +# make → Release (binari d'ús normal) +# make debug → Debug +# make release → Release + empaquetat per a distribució (zip/dmg/tar.gz segons SO) +# ============================================================================== + +all: + @cmake -S . -B $(BUILDDIR) $(CMAKE_GEN) -DCMAKE_BUILD_TYPE=Release $(CMAKE_DEFS) + @cmake --build $(BUILDDIR) -j$(JOBS) + +debug: + @cmake -S . -B $(BUILDDIR) $(CMAKE_GEN) -DCMAKE_BUILD_TYPE=Debug $(CMAKE_DEFS) + @cmake --build $(BUILDDIR) -j$(JOBS) + +run: all + @./$(BUILDDIR)/$(PROJECT) + +run-debug: debug + @./$(BUILDDIR)/$(PROJECT) + +# Release + empaquetat: detecta el SO i delega al sub-target corresponent. +release: +ifeq ($(OS),Windows_NT) + @"$(MAKE)" _windows-release +else +ifeq ($(UNAME_S),Darwin) + @$(MAKE) _macos-release +else + @$(MAKE) _linux-release +endif endif # ============================================================================== -# PACKING TOOL +# RELEASE — Linux (.tar.gz) # ============================================================================== -PACK_TOOL := tools/pack_resources/pack_resources +_linux-release: + @echo "Creando release para Linux - Version: $(VERSION)" -# ============================================================================== -# DEFAULT GOAL -# ============================================================================== -.DEFAULT_GOAL := all +# Compila Release (genera resources.pack i binari) + @cmake -S . -B $(BUILDDIR) $(CMAKE_GEN) -DCMAKE_BUILD_TYPE=Release $(CMAKE_DEFS) + @cmake --build $(BUILDDIR) -j$(JOBS) -.PHONY: pack_tool resources.pack - -pack_tool: - @make -C tools/pack_resources - -resources.pack: pack_tool - @echo "Creating resources.pack..." - @./$(PACK_TOOL) data resources.pack - -# ============================================================================== -# TARGETS -# ============================================================================== -.PHONY: all clean debug help backup - -# ============================================================================== -# BUILD TARGETS (delegate to CMake) -# ============================================================================== - -# Default target: build with CMake + resources -all: resources.pack $(TARGET_FILE) - -$(TARGET_FILE): - @cmake -B build -DCMAKE_BUILD_TYPE=Release - @cmake --build build - @echo "Build successful: $(TARGET_FILE)" - -# Debug build -debug: resources.pack - @cmake -B build -DCMAKE_BUILD_TYPE=Debug - @cmake --build build - @echo "Debug build successful: $(TARGET_FILE)" - -# ============================================================================== -# RELEASE PACKAGING TARGETS -# ============================================================================== - -# macOS Release (Apple Silicon) -.PHONY: macos_release -macos_release: pack_tool resources.pack - @echo "Creating macOS release - Version: $(VERSION)" - - # Check/install create-dmg - @command -v create-dmg >/dev/null || (echo "Installing create-dmg..." && brew install create-dmg) - - # Clean previous releases +# Recrea la carpeta temporal + @$(MKDIR) "$(DIST_DIR)" 2>/dev/null || true @$(RMDIR) "$(RELEASE_FOLDER)" 2>/dev/null || true - @$(RMDIR) Frameworks 2>/dev/null || true - @$(RMFILE) "$(MACOS_ARM_RELEASE)" 2>/dev/null || true + $(MKDIR) "$(RELEASE_FOLDER)" - # Create .app structure - @$(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks" - @$(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS" - @$(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources" - @$(MKDIR) Frameworks +# Còpia de fitxers + cp $(BUILDDIR)/resources.pack "$(RELEASE_FOLDER)" + cp README.md "$(RELEASE_FOLDER)" + @[ -f LICENSE ] && cp LICENSE "$(RELEASE_FOLDER)" || true + cp "$(TARGET_FILE)" "$(RELEASE_FILE)" + strip -s -R .comment -R .gnu.version "$(RELEASE_FILE)" --strip-unneeded - # Copy resources.pack to Resources - @cp resources.pack "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources/" - @ditto release/frameworks/SDL3.xcframework/macos-arm64_x86_64/SDL3.framework "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks/SDL3.framework" - @ditto release/frameworks/SDL3.xcframework/macos-arm64_x86_64/SDL3.framework Frameworks/SDL3.framework +# Empaqueta a .tar.gz + $(RMFILE) "$(LINUX_RELEASE)" + tar -czvf "$(LINUX_RELEASE)" -C "$(RELEASE_FOLDER)" . + @echo "Release creado: $(LINUX_RELEASE)" - # Recreate framework symlinks (may be broken) - @cd Frameworks/SDL3.framework && rm -f SDL3 Headers Resources && \ - ln -s Versions/Current/SDL3 SDL3 && \ - ln -s Versions/Current/Headers Headers && \ - ln -s Versions/Current/Resources Resources - @cd Frameworks/SDL3.framework/Versions && rm -f Current && ln -s A Current - @cd "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks/SDL3.framework" && rm -f SDL3 Headers Resources && \ - ln -s Versions/Current/SDL3 SDL3 && \ - ln -s Versions/Current/Headers Headers && \ - ln -s Versions/Current/Resources Resources - @cd "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks/SDL3.framework/Versions" && rm -f Current && ln -s A Current +# Neteja la carpeta temporal + $(RMDIR) "$(RELEASE_FOLDER)" - @cp release/icon.icns "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources/" - @cp release/Info.plist "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/" - @cp LICENSE "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: LICENSE not found" - @cp README.md "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: README.md not found" - - # Update Info.plist version and names - @echo "Updating Info.plist with version $(RAW_VERSION) and names..." - @sed -i '' '/CFBundleShortVersionString<\/key>/{n;s|.*|$(RAW_VERSION)|;}' \ - "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist" - @sed -i '' '/CFBundleVersion<\/key>/{n;s|.*|$(RAW_VERSION)|;}' \ - "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist" - @sed -i '' '/CFBundleExecutable<\/key>/{n;s|.*|$(TARGET_NAME)|;}' \ - "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist" - @sed -i '' '/CFBundleName<\/key>/{n;s|.*|$(APP_NAME)|;}' \ - "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist" - @sed -i '' '/CFBundleDisplayName<\/key>/{n;s|.*|$(APP_NAME)|;}' \ - "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist" - - # Compile for Apple Silicon using CMake - @cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES=arm64 - @cmake --build build - @cp $(TARGET_FILE) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_NAME)" - - # Code sign - @codesign --deep --force --sign - --timestamp=none "$(RELEASE_FOLDER)/$(APP_NAME).app" || echo "Warning: Code signing failed" - - # Create DMG - @echo "Creating DMG for Apple Silicon..." - @create-dmg \ - --volname "$(APP_NAME)" \ - --window-pos 200 120 \ - --window-size 720 300 \ - --icon-size 96 \ - --text-size 12 \ - --icon "$(APP_NAME).app" 278 102 \ - --icon "LICENSE" 441 102 \ - --icon "README.md" 604 102 \ - --app-drop-link 115 102 \ - --hide-extension "$(APP_NAME).app" \ - "$(MACOS_ARM_RELEASE)" \ - "$(RELEASE_FOLDER)" || true - @echo "✓ macOS release created: $(MACOS_ARM_RELEASE)" - - # Cleanup - @$(RMDIR) Frameworks - @$(RMDIR) "$(RELEASE_FOLDER)" - -# Linux Release -.PHONY: linux_release -linux_release: pack_tool resources.pack - @echo "Creating Linux release - Version: $(VERSION)" - @echo "Note: SDL3 must be installed on the target system (libsdl3-dev)" - - # Clean previous - @$(RMDIR) "$(RELEASE_FOLDER)" - @$(RMFILE) "$(LINUX_RELEASE)" - - # Create folder - @$(MKDIR) "$(RELEASE_FOLDER)" - - # Copy resources - @cp resources.pack "$(RELEASE_FOLDER)/" - @cp LICENSE "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: LICENSE not found" - @cp README.md "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: README.md not found" - - # Compile with CMake - @cmake -B build -DCMAKE_BUILD_TYPE=Release - @cmake --build build - @cp $(TARGET_FILE) "$(RELEASE_FILE)" - @strip -s -R .comment -R .gnu.version "$(RELEASE_FILE)" --strip-unneeded || strip "$(RELEASE_FILE)" - - # Package - @tar -czf "$(LINUX_RELEASE)" -C "$(RELEASE_FOLDER)" . - @echo "✓ Linux release created: $(LINUX_RELEASE)" - - # Cleanup - @$(RMDIR) "$(RELEASE_FOLDER)" - -# Windows Release (requires MinGW on Windows or cross-compiler on Linux) -.PHONY: windows_release -windows_release: pack_tool resources.pack +# ============================================================================== +# RELEASE — Windows (.zip) +# ============================================================================== +_windows-release: @echo off - @echo Creating Windows release - Version: $(VERSION) - @powershell if (Test-Path "$(RELEASE_FOLDER)") {Remove-Item "$(RELEASE_FOLDER)" -Recurse -Force} - @powershell if (Test-Path "$(WINDOWS_RELEASE)") {Remove-Item "$(WINDOWS_RELEASE)"} - @powershell if (-not (Test-Path "$(RELEASE_FOLDER)")) {New-Item "$(RELEASE_FOLDER)" -ItemType Directory} - @powershell Copy-Item -Path "resources.pack" -Destination "$(RELEASE_FOLDER)" - @powershell Copy-Item "release\dll\SDL3.dll" -Destination "$(RELEASE_FOLDER)" - @powershell Copy-Item "release\dll\libwinpthread-1.dll" -Destination "$(RELEASE_FOLDER)" - @powershell if (Test-Path "LICENSE") {Copy-Item "LICENSE" -Destination "$(RELEASE_FOLDER)"} - @powershell if (Test-Path "README.md") {Copy-Item "README.md" -Destination "$(RELEASE_FOLDER)"} - @windres release/$(TARGET_NAME).rc -O coff -o release/$(TARGET_NAME).res 2>nul || echo Warning: windres failed - @cmake -B build -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release - @cmake --build build - @powershell if (Test-Path "$(TARGET_FILE).exe") {Copy-Item "$(TARGET_FILE).exe" -Destination "$(RELEASE_FILE).exe"} else {Copy-Item "$(TARGET_FILE)" -Destination "$(RELEASE_FILE).exe"} - @strip "$(RELEASE_FILE).exe" 2>nul || echo Warning: strip not available - @powershell Compress-Archive -Path "$(RELEASE_FOLDER)\*" -DestinationPath "$(WINDOWS_RELEASE)" -Force - @echo Release created: $(WINDOWS_RELEASE) - @powershell if (Test-Path "$(RELEASE_FOLDER)") {Remove-Item "$(RELEASE_FOLDER)" -Recurse -Force} + @echo Creando release para Windows - Version: $(VERSION) -# Raspberry Pi Release (cross-compilation from Linux/macOS) -.PHONY: rpi_release -rpi_release: - @echo "Creating Raspberry Pi ARM64 release - Version: $(VERSION)" - @echo "Note: Requires aarch64-linux-gnu-g++ cross-compiler" + @cmake -S . -B $(BUILDDIR) $(CMAKE_GEN) -DCMAKE_BUILD_TYPE=Release $(CMAKE_DEFS) + @cmake --build $(BUILDDIR) -j$(JOBS) - # Check for cross-compiler - @command -v aarch64-linux-gnu-g++ >/dev/null || (echo "Error: aarch64-linux-gnu-g++ not found" && exit 1) + @powershell -Command "if (-not (Test-Path '$(DIST_DIR)')) {New-Item '$(DIST_DIR)' -ItemType Directory}" + @powershell -Command "if (Test-Path '$(RELEASE_FOLDER)') {Remove-Item '$(RELEASE_FOLDER)' -Recurse -Force}" + @powershell -Command "if (-not (Test-Path '$(RELEASE_FOLDER)')) {New-Item '$(RELEASE_FOLDER)' -ItemType Directory}" - # Clean previous - @$(RMDIR) "$(RELEASE_FOLDER)" - @$(RMFILE) "$(RPI_RELEASE)" + @powershell -Command "Copy-Item -Path '$(BUILDDIR)/resources.pack' -Destination '$(RELEASE_FOLDER)'" + @powershell -Command "if (Test-Path 'LICENSE') { Copy-Item 'LICENSE' -Destination '$(RELEASE_FOLDER)' }" + @powershell -Command "Copy-Item 'README.md' -Destination '$(RELEASE_FOLDER)'" + @powershell -Command "if (Test-Path 'release\dll') { Copy-Item 'release\dll\*.dll' -Destination '$(RELEASE_FOLDER)' }" + @powershell -Command "Copy-Item -Path '$(TARGET_FILE).exe' -Destination '$(WIN_RELEASE_FILE_PS).exe'" + strip -s -R .comment -R .gnu.version "$(WIN_RELEASE_FILE).exe" --strip-unneeded - # Create folder - @$(MKDIR) "$(RELEASE_FOLDER)" + @powershell -Command "if (Test-Path '$(WINDOWS_RELEASE)') {Remove-Item '$(WINDOWS_RELEASE)'}" + @powershell -Command "Compress-Archive -Path '$(RELEASE_FOLDER)/*' -DestinationPath '$(WINDOWS_RELEASE)'" + @echo Release creado: $(WINDOWS_RELEASE) - # Copy resources - @cp resources.pack "$(RELEASE_FOLDER)/" - @cp LICENSE "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: LICENSE not found" - @cp README.md "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: README.md not found" + @powershell -Command "if (Test-Path '$(RELEASE_FOLDER)') {Remove-Item '$(RELEASE_FOLDER)' -Recurse -Force}" - # Note: Cross-compilation with CMake is complex, would need toolchain file - @echo "Warning: RPI cross-compilation requires manual setup with CMake toolchain file" - @echo "Falling back to direct g++ compilation..." - @aarch64-linux-gnu-g++ -std=c++20 -Wall -O2 -DLINUX_BUILD -DRPI_BUILD \ - -Isource -Ibuild \ - $$(find source/core source/game -name "*.cpp") source/main.cpp \ - -lSDL3 -o "$(RELEASE_FILE)" || echo "Error: Compilation failed" - @aarch64-linux-gnu-strip -s -R .comment -R .gnu.version "$(RELEASE_FILE)" --strip-unneeded || true +# ============================================================================== +# RELEASE — macOS (.dmg per Apple Silicon) +# ============================================================================== +_macos-release: + @echo "Creando release para macOS - Version: $(VERSION)" - # Package - @tar -czf "$(RPI_RELEASE)" -C "$(RELEASE_FOLDER)" . - @echo "✓ Raspberry Pi release created: $(RPI_RELEASE)" +# Verificar/instal·lar create-dmg si cal + @which create-dmg > /dev/null || (echo "Instalando create-dmg..." && brew install create-dmg) - # Cleanup - @$(RMDIR) "$(RELEASE_FOLDER)" +# Compila la versió Apple Silicon + @cmake -S . -B $(BUILDDIR)/arm $(CMAKE_GEN) -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_OSX_ARCHITECTURES=arm64 -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 \ + -DMACOS_BUNDLE=ON $(CMAKE_DEFS) + @cmake --build $(BUILDDIR)/arm -j$(JOBS) -# Windows Cross-compilation (from Linux/macOS) -.PHONY: windows_cross -windows_cross: - @echo "Cross-compiling for Windows from $(UNAME_S) - Version: $(VERSION)" +# Neteja artefactes anteriors + @$(MKDIR) "$(DIST_DIR)" 2>/dev/null || true + $(RMDIR) "$(RELEASE_FOLDER)" 2>/dev/null || true + $(RMFILE) "$(DIST_DIR)"/rw.* 2>/dev/null || true + $(RMFILE) "$(MACOS_APPLE_SILICON_RELEASE)" - # Check for cross-compiler - @command -v x86_64-w64-mingw32-g++ >/dev/null || (echo "Error: x86_64-w64-mingw32-g++ not found" && exit 1) +# Crea l'estructura del bundle .app + $(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks" + $(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS" + $(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources" - # Clean previous - @$(RMDIR) "$(RELEASE_FOLDER)" - @$(RMFILE) "$(WINDOWS_RELEASE)" +# Còpia de recursos i metadades del bundle + cp $(BUILDDIR)/arm/resources.pack "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources" + cp -R release/frameworks/SDL3.xcframework/macos-arm64_x86_64/SDL3.framework "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks" + cp release/icon.icns "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources" + cp release/Info.plist "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents" + @[ -f LICENSE ] && cp LICENSE "$(RELEASE_FOLDER)" || true + cp README.md "$(RELEASE_FOLDER)" - # Create folder - @$(MKDIR) "$(RELEASE_FOLDER)" +# Recreate framework symlinks (Versions/Current i top-level) + @cd "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks/SDL3.framework" && \ + rm -f SDL3 Headers Resources && \ + ln -s Versions/Current/SDL3 SDL3 && \ + ln -s Versions/Current/Headers Headers && \ + ln -s Versions/Current/Resources Resources + @cd "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks/SDL3.framework/Versions" && \ + rm -f Current && ln -s A Current - # Copy resources - @cp resources.pack "$(RELEASE_FOLDER)/" - @cp release/dll/SDL3.dll release/dll/libwinpthread-1.dll "$(RELEASE_FOLDER)/" - @cp LICENSE "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: LICENSE not found" - @cp README.md "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: README.md not found" +# Actualitza Info.plist amb VERSION i metadades + @echo "Actualizando Info.plist con versión $(VERSION)..." + @RAW_VERSION=$$(echo "$(VERSION)" | sed 's/^v//'); \ + sed -i '' '/CFBundleShortVersionString<\/key>/{n;s|.*|'"$$RAW_VERSION"'|;}' "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist"; \ + sed -i '' '/CFBundleVersion<\/key>/{n;s|.*|'"$$RAW_VERSION"'|;}' "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist"; \ + sed -i '' '/CFBundleExecutable<\/key>/{n;s|.*|$(PROJECT)|;}' "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist"; \ + sed -i '' '/CFBundleName<\/key>/{n;s|.*|$(APP_NAME)|;}' "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist"; \ + sed -i '' '/CFBundleDisplayName<\/key>/{n;s|.*|$(APP_NAME)|;}' "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist" - # Compile resource file - @x86_64-w64-mingw32-windres release/$(TARGET_NAME).rc -O coff -o release/$(TARGET_NAME).res 2>/dev/null || echo "Warning: windres failed" +# Còpia del binari al bundle + cp "$(BUILDDIR)/arm/$(PROJECT)" "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(PROJECT)" - # Cross-compile - @echo "Compiling with MinGW cross-compiler..." - @x86_64-w64-mingw32-g++ -std=c++20 -Wall -O2 -DWINDOWS_BUILD -DRELEASE_BUILD \ - -static-libstdc++ -static-libgcc -Wl,-subsystem,windows \ - -Isource -Ibuild \ - $$(find source/core source/game -name "*.cpp") source/main.cpp \ - release/$(TARGET_NAME).res \ - -lmingw32 -lSDL3 -o "$(RELEASE_FILE).exe" || echo "Error: Compilation failed" - @x86_64-w64-mingw32-strip "$(RELEASE_FILE).exe" || true +# Firma ad-hoc del bundle + codesign --deep --force --sign - --timestamp=none "$(RELEASE_FOLDER)/$(APP_NAME).app" - # Package - @cd "$(RELEASE_FOLDER)" && zip -r ../$(WINDOWS_RELEASE) * - @echo "✓ Windows cross-compiled release created: $(WINDOWS_RELEASE)" +# Empaqueta el .dmg + @echo "Creando DMG Apple Silicon con iconos de 96x96..." + create-dmg \ + --volname "$(APP_NAME)" \ + --window-pos 200 120 \ + --window-size 720 300 \ + --icon-size 96 \ + --text-size 12 \ + --icon "$(APP_NAME).app" 278 102 \ + --icon "LICENSE" 441 102 \ + --icon "README.md" 604 102 \ + --app-drop-link 115 102 \ + --hide-extension "$(APP_NAME).app" \ + "$(MACOS_APPLE_SILICON_RELEASE)" \ + "$(RELEASE_FOLDER)" || true + @echo "Release Apple Silicon creado: $(MACOS_APPLE_SILICON_RELEASE)" - # Cleanup - @$(RMDIR) "$(RELEASE_FOLDER)" +# Neteja temporals + $(RMDIR) "$(RELEASE_FOLDER)" + $(RMDIR) $(BUILDDIR)/arm + $(RMFILE) "$(DIST_DIR)"/rw.* 2>/dev/null || true + +show-version: + @echo "$(PROJECT) $(VERSION) ($(GIT_HASH))" -# Clean build artifacts clean: -ifeq ($(OS),Windows_NT) - @if exist $(call FixPath,$(TARGET_FILE).exe) $(RMFILE) $(call FixPath,$(TARGET_FILE).exe) - @if exist $(call FixPath,$(TARGET_FILE)_debug.exe) $(RMFILE) $(call FixPath,$(TARGET_FILE)_debug.exe) - @if exist build $(RMDIR) build - @if exist $(RELEASE_FOLDER) $(RMDIR) $(RELEASE_FOLDER) -else - @$(RMFILE) $(TARGET_FILE) $(TARGET_FILE)_debug - @$(RMDIR) build $(RELEASE_FOLDER) - @$(RMFILE) *.dmg *.zip *.tar.gz 2>/dev/null || true - @$(RMFILE) resources.pack 2>/dev/null || true - @make -C tools/pack_resources clean 2>/dev/null || true -endif - @echo "Clean complete" + @rm -rf $(BUILDDIR) $(DIST_DIR) -# Backup to remote server -backup: - @echo "Backing up project to maverick:/home/sergio/git-backup/orni..." - rsync -a --delete \ - --exclude='build/' \ - --exclude='*.o' \ - --exclude='*.exe' \ - --exclude='orni' \ - --exclude='orni_debug' \ - --exclude='*_release/' \ - $(DIR_ROOT) maverick:/home/sergio/git-backup/orni/ - @echo "Backup completed successfully" +rebuild: clean all -# Help target +# Empaqueta data/ a $(BUILDDIR)/resources.pack. Força un rebuild del pack encara +# que res no hagi canviat dins data/. L'empaquetat també es fa automàticament a +# cada `make`/`make debug` via el target CMake `resource_pack`. +pack: + @cmake -S . -B $(BUILDDIR) $(CMAKE_GEN) $(CMAKE_DEFS) + @cmake --build $(BUILDDIR) --target pack_resources + @./$(BUILDDIR)/pack_resources data $(BUILDDIR)/resources.pack + +# ============================================================================== +# CODE QUALITY (delegats a cmake) +# ============================================================================== +format: + @cmake -S . -B $(BUILDDIR) $(CMAKE_GEN) -DCMAKE_BUILD_TYPE=Release $(CMAKE_DEFS) + @cmake --build $(BUILDDIR) --target format + +format-check: + @cmake -S . -B $(BUILDDIR) $(CMAKE_GEN) -DCMAKE_BUILD_TYPE=Release $(CMAKE_DEFS) + @cmake --build $(BUILDDIR) --target format-check + +tidy: + @cmake -S . -B $(BUILDDIR) $(CMAKE_GEN) -DCMAKE_BUILD_TYPE=Release $(CMAKE_DEFS) + @cmake --build $(BUILDDIR) --target tidy + +tidy-fix: + @cmake -S . -B $(BUILDDIR) $(CMAKE_GEN) -DCMAKE_BUILD_TYPE=Release $(CMAKE_DEFS) + @cmake --build $(BUILDDIR) --target tidy-fix + +cppcheck: + @cmake -S . -B $(BUILDDIR) $(CMAKE_GEN) -DCMAKE_BUILD_TYPE=Release $(CMAKE_DEFS) + @cmake --build $(BUILDDIR) --target cppcheck + +# ============================================================================== +# GIT HOOKS +# ============================================================================== +hooks-install: + @git config core.hooksPath .githooks + @echo "Git hooks activats: $(shell pwd)/.githooks" + +# ============================================================================== +# AJUDA +# ============================================================================== help: - @echo "Available targets:" + @echo "Makefile per a $(PROJECT)" @echo "" - @echo "Build:" - @echo " all - Build the game (default, delegates to CMake)" - @echo " debug - Build with debug symbols" - @echo " clean - Remove build artifacts and release packages" + @echo " Compilació:" + @echo " make - Compilar amb cmake (Release)" + @echo " make debug - Compilar amb cmake (Debug)" @echo "" - @echo "Release Packaging:" - @echo " macos_release - Create macOS .app bundle + .dmg (Apple Silicon)" - @echo " linux_release - Create Linux .tar.gz" - @echo " windows_release - Create Windows .zip (requires MinGW on Windows)" - @echo " windows_cross - Cross-compile Windows from Linux/macOS (requires MinGW)" - @echo " rpi_release - Cross-compile for Raspberry Pi ARM64" + @echo " Execució:" + @echo " make run - Compilar (Release) i executar" + @echo " make run-debug - Compilar (Debug) i executar" @echo "" - @echo "Other:" - @echo " backup - Backup project to remote server" - @echo " help - Show this help message" + @echo " Release:" + @echo " make release - Release + empaquetat (zip/dmg/tar.gz segons SO)" @echo "" - @echo "Current configuration:" - @echo " Project: $(LONG_NAME)" - @echo " Target: $(TARGET_NAME)" - @echo " Version: $(VERSION)" - @echo " Platform: $(UNAME_S)" + @echo " Recursos:" + @echo " make pack - Empaquetar data/ a $(BUILDDIR)/resources.pack" + @echo "" + @echo " Qualitat de codi:" + @echo " make format - Formatar codi amb clang-format" + @echo " make format-check - Verificar format sense modificar" + @echo " make tidy - Anàlisi estàtic amb clang-tidy" + @echo " make tidy-fix - Anàlisi estàtic amb auto-fix" + @echo " make cppcheck - Anàlisi estàtic amb cppcheck" + @echo "" + @echo " Altres:" + @echo " make clean - Esborrar $(BUILDDIR)/ i $(DIST_DIR)/" + @echo " make rebuild - clean + all" + @echo " make show-version - Mostrar versió" + @echo " make hooks-install - Activar git hooks del projecte" + @echo "" + @echo " Versió actual: $(VERSION) ($(GIT_HASH))" diff --git a/source/ASTEROID.PAS b/source/ASTEROID.PAS deleted file mode 100755 index cb59152..0000000 --- a/source/ASTEROID.PAS +++ /dev/null @@ -1,433 +0,0 @@ -uses crt,keyboard,sencos; - -const - marge_dalt=20; - marge_baix=460; - marge_esq=20; - marge_dret=620; - max_ipunts=30; - max_ornis=15; - velocitat=2; - velocitat_max=6; - max_bales=3; -type - ipunt=RECORD r,angle:real; END; - punt=RECORD x,y:integer; END; - ivector=array [0..max_ipunts-1] of ipunt; - triangle=RECORD p1,p2,p3:ipunt; - centre:punt; - angle:real; - velocitat:real; - END; - poligon=RECORD ipunts:^ivector; - ipuntx:ivector; - centre:punt; - angle:real; - velocitat:real; - n:byte; - drotacio,rotacio:real; - esta:boolean; - END; - - - pvirt=array [1..38400] of byte; - -var nau:triangle;pol:poligon; - ang:real; - ch:char; - Dx,Dy:word; - i,aux:byte; - dist:integer; - puntaux:punt; - orni:array [1..max_ornis] of poligon; - virt:^pvirt; - bales:array [1..max_bales] of poligon; - -procedure volca; -var i:word; -begin - for i:=1 to 38400 do mem[$A000:i]:=mem[seg(virt^):i]; -end; - -procedure crear_poligon_regular(var pol:poligon;n:byte;r:real); -var i:word;act,interval:real;aux:ipunt; -begin - {getmem(pol.ipunts,{n*464000);} - interval:=2*pi/n; - act:=0; - for i:=0 to n-1 do begin - aux.r:=r; - aux.angle:=act; - pol.ipuntx[i]:=aux; - act:=act + interval; - end; - pol.centre.x:=320; - pol.centre.y:=200; - pol.angle:=0; - pol.velocitat:=velocitat; - pol.n:=n; - pol.drotacio:=0.078539816; - pol.rotacio:=0; - end; - - procedure MCGA; - begin - asm - mov ax,0012h - int 10h - end; - directvideo:= false; - end; - - procedure Text; - begin - asm - mov ax,0003h - int 10h - end; - end; - - procedure WaitRetrace; assembler; - label - l1,l2; - - asm - mov dx,3DAh - - l1: - in al,dx - and al,08h - jnz l1 - - l2: - in al,dx - and al,08h - jz l2 - end; - - -procedure posa(x,y:word;color:byte); -begin - if color=1 then - case (x mod 8) of - 0:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $7F)OR $80; - 1:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $BF)OR $40; - 2:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $DF)OR $20; - 3:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $EF)OR $10; - 4:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $F7)OR $08; - 5:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $FB)OR $04; - 6:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $FD)OR $02; - 7:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $FE)OR $01; - end; - if color=0 then - case (x mod 8) of - 0:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $7F); - 1:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $BF); - 2:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $DF); - 3:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $EF); - 4:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $F7); - 5:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $FB); - 6:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $FD); - 7:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $FE); - end; -end; - -function llig(x,y:word):byte; -begin - case (x mod 8) of - 0:llig:=(mem[seg(virt^):y*80+(x div 8)]AND $80)shr 7; - 1:llig:=(mem[seg(virt^):y*80+(x div 8)]AND $40)shr 6; - 2:llig:=(mem[seg(virt^):y*80+(x div 8)]AND $20)shr 5; - 3:llig:=(mem[seg(virt^):y*80+(x div 8)]AND $10)shr 4; - 4:llig:=(mem[seg(virt^):y*80+(x div 8)]AND $08)shr 3; - 5:llig:=(mem[seg(virt^):y*80+(x div 8)]AND $04)shr 2; - 6:llig:=(mem[seg(virt^):y*80+(x div 8)]AND $02)shr 1; - 7:llig:=(mem[seg(virt^):y*80+(x div 8)]AND $01); - end; -end; - -procedure posavga(x,y:word;color:byte); -begin - if color=1 then - case (x mod 8) of - 0:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $7F)OR $80; - 1:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $BF)OR $40; - 2:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $DF)OR $20; - 3:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $EF)OR $10; - 4:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $F7)OR $08; - 5:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $FB)OR $04; - 6:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $FD)OR $02; - 7:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $FE)OR $01; - end; - if color=0 then - case (x mod 8) of - 0:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $7F); - 1:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $BF); - 2:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $DF); - 3:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $EF); - 4:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $F7); - 5:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $FB); - 6:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $FD); - 7:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $FE); - end; -end; - -function modul(p:punt):real; -begin - modul:=sqrt(sqr(p.x)+sqr(p.y)); -end; - -procedure diferencia(o,d:punt;var p:punt); -begin - p.x:=o.x-d.x; - p.y:=o.y-d.y; -end; - -function distancia(o,d:punt):integer; -var p:punt; -begin - diferencia(o,d,p); - distancia:=round(modul(p)); -end; -function angle(p:punt):real; -begin - if p.y<>0 then angle:=arctan(p.x/p.y); -end; - -procedure clsvirt; -var i:word; -begin - for i:=1 to 38400 do mem[seg(virt^):i]:=0; -end; - -function linea(x1,y1,x2,y2,color:word):boolean; - - function sign(x:integer):integer; {like sgn(x) in basic} - begin if x<0 then sign:=-1 else if x>0 then sign:=1 else sign:=0 end; - - var - x,y,count,xs,ys,xm,ym,col:integer; - begin - linea:=false; - col:=0; - x:=x1;y:=y1; - - xs:=x2-x1; ys:=y2-y1; - - xm:=sign(xs); ym:=sign(ys); - xs:=abs(xs); ys:=abs(ys); - if llig(x,y)=1 then inc(col); - posa(x,y,color); - - if xs > ys - then begin {flat line <45 deg} - count:=-(xs div 2); - while (x <> x2 ) do begin - count:=count+ys; - x:=x+xm; - if count>0 then begin - y:=y+ym; - count:=count-xs; - end; - if llig(x,y)=1 then inc(col); - posa(x,y,color); - end; - end - else begin {steep line >=45 deg} - count:=-(ys div 2); - while (y <> y2 ) do begin - count:=count+xs; - y:=y+ym; - if count>0 then begin - x:=x+xm; - count:=count-ys; - end; - if llig(x,y)=1 then inc(col); - posa(x,y,color); - end; - end; - if col>2 then linea:=true; -end; - -function rota_tri(tri:triangle;angul,velocitat:real;color:byte):byte; -var x1,x2,x3,y1,y2,y3:word; -begin - x1:=round((tri.p1.r+velocitat)*cos(tri.p1.angle+angul))+tri.centre.x; - x2:=round((tri.p2.r+velocitat)*cos(tri.p2.angle+angul{+velocitat/20}))+tri.centre.x; - x3:=round((tri.p3.r+velocitat)*cos(tri.p3.angle+angul{-velocitat/20}))+tri.centre.x; - y1:=round((tri.p1.r+velocitat)*sin(tri.p1.angle+angul))+tri.centre.y; - y2:=round((tri.p2.r+velocitat)*sin(tri.p2.angle+angul{+velocitat/20}))+tri.centre.y; - y3:=round((tri.p3.r+velocitat)*sin(tri.p3.angle+angul{-velocitat/20}))+tri.centre.y; - rota_tri:=0; - if linea(x1,y1,x2,y2,color) then rota_tri:=1 ; - if linea(x1,y1,x3,y3,color) then rota_tri:=1; - if linea(x3,y3,x2,y2,color) then rota_tri:=1; -end; - -procedure rota_pol(pol:poligon;angul:real;color:byte); -var xy:array [0..max_ipunts] of punt;i:byte; -begin - for i:=0 to pol.n-1 do begin - xy[i].x:=round((pol.ipuntx[i].r)*cos(pol.ipuntx[i].angle+angul))+pol.centre.x; - xy[i].y:=round((pol.ipuntx[i].r)*sin(pol.ipuntx[i].angle+angul))+pol.centre.y; - end; - for i:=0 to pol.n-2 do - linea(xy[i].x,xy[i].y,xy[i+1].x,xy[i+1].y,color); - linea(xy[pol.n-1].x,xy[pol.n-1].y,xy[0].x,xy[0].y,color); -end; - -procedure mou_orni(var orni:poligon); -var dx,dy:real; -begin - orni.angle:=orni.angle{+(random(256)/512)*(random(3)-1)}; - Dy:=round(orni.velocitat*sin(orni.angle-pi/2))+orni.centre.y; - Dx:=round(orni.velocitat*cos(orni.angle-pi/2))+orni.centre.x; - if (dy>marge_dalt) and (dymarge_esq) and (dxmarge_dalt) and (dymarge_esq) and (dx1) and (nau.p2.r>1)and (nau.p3.r>1)and (itocado<170)) then begin - nau.p1.r:=nau.p1.r-0.7; - nau.p2.r:=nau.p2.r-0.7; - nau.p3.r:=nau.p3.r-0.7; - nau.angle:=nau.angle-0.3; - rota_tri(nau,nau.angle,0,1); - end - else begin - for i:=0 to max_ipunts-1 do begin - chatarra_cosmica.ipuntx[i].r:=chatarra_cosmica.ipuntx[i].r+3; - dx:=round((chatarra_cosmica.ipuntx[i].r)*cos(chatarra_cosmica.ipuntx[i].angle)) - +chatarra_cosmica.centre.x; - dy:=round((chatarra_cosmica.ipuntx[i].r)*sin(chatarra_cosmica.ipuntx[i].angle)) - +chatarra_cosmica.centre.y; - if ((dx>=0)AND(dx<640)AND(dy>0)AND(dy<480))then posa(dx,dy,1); - end; - end; - inc(itocado); - if itocado=170 then begin - nau.p1.r:=12;nau.p1.angle:=3*pi/2; - nau.p2.r:=12;nau.p2.angle:=pi/4; - nau.p3.r:=12;nau.p3.angle:=(3*pi)/4; - nau.angle:=0; - nau.centre.x:=320;nau.centre.y:=240; - end; - if ((itocado>170)and(itocado mod 3=0)) then rota_tri(nau,nau.angle,nau.velocitat,1); - if itocado>250 then itocado:=0; - -end; - -begin - randomize; - getmem(virt,38400); - itocado:=0; - clsvirt; - nau.p1.r:=12;nau.p1.angle:=3*pi/2; - nau.p2.r:=12;nau.p2.angle:=pi/4; - nau.p3.r:=12;nau.p3.angle:=(3*pi)/4; - nau.angle:=0; - nau.centre.x:=320;nau.centre.y:=240; - crear_poligon_regular(pol,10,200); - for i:=1 to max_ornis do crear_poligon_regular(orni[i],5,20); - mcga; - rota_pol(pol,0,1); - instalarkb; - repeat -{ rota_tri(nau,nau.angle,nau.velocitat,0);} - clsvirt; - - if teclapuls(KEYarrowright) then nau.angle:=nau.angle+0.157079632; - if teclapuls(KEYarrowleft) then nau.angle:=nau.angle-0.157079632; - if teclapuls(KEYarrowup) then begin - if nau.velocitatmarge_dalt) and (dymarge_esq) and (dx0.1) then nau.velocitat:=nau.velocitat-0.1; -{ dist:=distancia(nau.centre,pol.centre); - diferencia(pol.centre,nau.centre,puntaux); - if dist<(pol.ipuntx[1].r+30) then begin - nau.centre.x:=nau.centre.x - +round(dist*cos(angle(puntaux)+0.031415)); - nau.centre.y:=nau.centre.y - +round(dist*sin(angle(puntaux)+0.031415)); - end;} -{ for i:=1 to 5 do begin - rota_pol(orni[i],ang,0); - end;} - for i:=1 to max_ornis do begin - mou_orni(orni[i]); - rota_pol(orni[i],orni[i].rotacio,1); - end; - if itocado=0 then aux:=rota_tri(nau,nau.angle,nau.velocitat,1) - else tocado; - if (aux=1) then begin inc(itocado);aux:=0;end; - if bales[1].esta then begin - mou_bales(bales[1]); - rota_pol(bales[1],0,1); - end; - waitretrace; - volca; -{ if aux=1 then begin {gotoxy(0,0);write('tocado')tocado;delay(200);end;} - gotoxy(50,24); - write(' Visente i Sergi'); - gotoxy(50,25); - write('ETA 2.2 2/6/99'); - until teclapuls(keyesc); - desinstalarkb; - ang:=0; - repeat waitretrace;rota_pol(pol,ang,0); ang:=ang+0.031415 ;rota_pol(pol,ang,1);until keypressed; - text; -end. \ No newline at end of file diff --git a/source/legacy/.clang-format b/source/legacy/.clang-format deleted file mode 100644 index 47a38a9..0000000 --- a/source/legacy/.clang-format +++ /dev/null @@ -1,2 +0,0 @@ -DisableFormat: true -SortIncludes: Never diff --git a/source/legacy/.clang-tidy b/source/legacy/.clang-tidy deleted file mode 100644 index bbae176..0000000 --- a/source/legacy/.clang-tidy +++ /dev/null @@ -1,4 +0,0 @@ -# source/external/.clang-tidy -Checks: '-*' -WarningsAsErrors: '' -HeaderFilterRegex: '' \ No newline at end of file diff --git a/source/legacy/asteroids.cpp b/source/legacy/asteroids.cpp deleted file mode 100644 index 595751c..0000000 --- a/source/legacy/asteroids.cpp +++ /dev/null @@ -1,466 +0,0 @@ -#include - -#include -#include - -#define MARGE_DALT 20 -#define MARGE_BAIX 460 -#define MARGE_ESQ 20 -#define MARGE_DRET 620 -#define MAX_IPUNTS 30 -#define MAX_ORNIS 15 -#define VELOCITAT 2 -#define VELOCITAT_MAX 6 -#define MAX_BALES 3 - -struct ipunt { - float r; - float angle; -}; - -struct punt { - int x; - int y; -}; - -struct triangle { - ipunt p1, p2, p3; - punt centre; - float angle; - float velocitat; -}; - -typedef std::vector ivector(); - -struct poligon { - ivector* ipunts; - ivector ipuntx; - punt centre; - float angl; - float velocitat; - Uint8 n; - float drotacio; - float rotacio; - bool esta; -}; - -std::vector pvirt(38400); - -triangle nau; -poligon pol; -float ang; -std::string ch; -Uint16 Dx, Dy; -Uint8 i, aux; -int dist; -punt puntaux; -std::vector orni(MAX_ORNIS); -std::vector bales(MAX_BALES); -virt : ^pvirt; - -procedure volca; -var i ; word; -begin - for i:=1 to 38400 do mem[$A000:i]:=mem[seg(virt^):i]; -end; - -procedure crear_poligon_regular(var pol : poligon; n : byte; r : real); -var i ; word; -act, interval ; real; -aux : ipunt; -begin {getmem(pol.ipunts,{n*464000);} - interval:=2*pi/n; - act:=0; - for i:=0 to n-1 do begin - aux.r:=r; - aux.angle:=act; - pol.ipuntx[i]:=aux; - act:=act + interval; - end; - pol.centre.x:=320; - pol.centre.y:=200; - pol.angle:=0; - pol.velocitat:=velocitat; - pol.n:=n; - pol.drotacio:=0.078539816; - pol.rotacio:=0; - end; - - procedure MCGA; - begin - asm - mov ax,0012h - int 10h - end; - directvideo:= false; - end; - - procedure Text; - begin - asm - mov ax,0003h - int 10h - end; - end; - - procedure WaitRetrace; assembler; - label - l1,l2; - - asm - mov dx,3DAh - - l1: - in al,dx - and al,08h - jnz l1 - - l2: - in al,dx - and al,08h - jz l2 - end; - - -procedure posa(x,y:word;color:byte); -begin - if color=1 then - case (x mod 8) of - 0:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $7F)OR $80; - 1:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $BF)OR $40; - 2:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $DF)OR $20; - 3:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $EF)OR $10; - 4:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $F7)OR $08; - 5:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $FB)OR $04; - 6:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $FD)OR $02; - 7:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $FE)OR $01; - end; - if color=0 then - case (x mod 8) of - 0:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $7F); - 1:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $BF); - 2:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $DF); - 3:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $EF); - 4:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $F7); - 5:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $FB); - 6:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $FD); - 7:mem[seg(virt^):y*80+(x div 8)]:=(mem[seg(virt^):y*80+(x div 8)]AND $FE); - end; -end; - -function llig(x,y:word):byte; -begin - case (x mod 8) of - 0:llig:=(mem[seg(virt^):y*80+(x div 8)]AND $80)shr 7; - 1:llig:=(mem[seg(virt^):y*80+(x div 8)]AND $40)shr 6; - 2:llig:=(mem[seg(virt^):y*80+(x div 8)]AND $20)shr 5; - 3:llig:=(mem[seg(virt^):y*80+(x div 8)]AND $10)shr 4; - 4:llig:=(mem[seg(virt^):y*80+(x div 8)]AND $08)shr 3; - 5:llig:=(mem[seg(virt^):y*80+(x div 8)]AND $04)shr 2; - 6:llig:=(mem[seg(virt^):y*80+(x div 8)]AND $02)shr 1; - 7:llig:=(mem[seg(virt^):y*80+(x div 8)]AND $01); - end; -end; - -procedure posavga(x,y:word;color:byte); -begin - if color=1 then - case (x mod 8) of - 0:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $7F)OR $80; - 1:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $BF)OR $40; - 2:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $DF)OR $20; - 3:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $EF)OR $10; - 4:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $F7)OR $08; - 5:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $FB)OR $04; - 6:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $FD)OR $02; - 7:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $FE)OR $01; - end; - if color=0 then - case (x mod 8) of - 0:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $7F); - 1:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $BF); - 2:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $DF); - 3:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $EF); - 4:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $F7); - 5:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $FB); - 6:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $FD); - 7:mem[$A000:y*80+(x div 8)]:=(mem[$A000:y*80+(x div 8)]AND $FE); - end; -end; - -function modul(p:punt):real; -begin - modul:=sqrt(sqr(p.x)+sqr(p.y)); -end; - -procedure diferencia(o,d:punt;var p:punt); -begin - p.x:=o.x-d.x; - p.y:=o.y-d.y; -end; - -function distancia(o,d:punt):integer; -var p:punt; -begin - diferencia(o,d,p); - distancia:=round(modul(p)); -end; -function angle(p:punt):real; -begin - if p.y<>0 then angle:=arctan(p.x/p.y); -end; - -procedure clsvirt; -var i:word; -begin - for i:=1 to 38400 do mem[seg(virt^):i]:=0; -end; - -function linea(x1,y1,x2,y2,color:word):boolean; - - function sign(x:integer):integer; {like sgn(x) in basic} - begin if x<0 then sign:=-1 else if x>0 then sign:=1 else sign:=0 end; - - var - x,y,count,xs,ys,xm,ym,col:integer; - begin - linea:=false; - col:=0; - x:=x1;y:=y1; - - xs:=x2-x1; ys:=y2-y1; - - xm:=sign(xs); ym:=sign(ys); - xs:=abs(xs); ys:=abs(ys); - if llig(x,y)=1 then inc(col); - posa(x,y,color); - - if xs > ys - then begin {flat line <45 deg} - count:=-(xs div 2); - while (x <> x2 ) do begin - count:=count+ys; - x:=x+xm; - if count>0 then begin - y:=y+ym; - count:=count-xs; - end; - if llig(x,y)=1 then inc(col); - posa(x,y,color); - end; - end - else begin {steep line >=45 deg} - count:=-(ys div 2); - while (y <> y2 ) do begin - count:=count+xs; - y:=y+ym; - if count>0 then begin - x:=x+xm; - count:=count-ys; - end; - if llig(x,y)=1 then inc(col); - posa(x,y,color); - end; - end; - if col>2 then linea:=true; -end; - -function rota_tri(tri:triangle;angul,velocitat:real;color:byte):byte; -var x1,x2,x3,y1,y2,y3:word; -begin - x1:=round((tri.p1.r+velocitat)*cos(tri.p1.angle+angul))+tri.centre.x; - x2:=round((tri.p2.r+velocitat)*cos(tri.p2.angle+angul{+velocitat/20}))+tri.centre.x; - x3:=round((tri.p3.r+velocitat)*cos(tri.p3.angle+angul{-velocitat/20}))+tri.centre.x; - y1:=round((tri.p1.r+velocitat)*sin(tri.p1.angle+angul))+tri.centre.y; - y2:=round((tri.p2.r+velocitat)*sin(tri.p2.angle+angul{+velocitat/20}))+tri.centre.y; - y3:=round((tri.p3.r+velocitat)*sin(tri.p3.angle+angul{-velocitat/20}))+tri.centre.y; - rota_tri:=0; - if linea(x1,y1,x2,y2,color) then rota_tri:=1 ; - if linea(x1,y1,x3,y3,color) then rota_tri:=1; - if linea(x3,y3,x2,y2,color) then rota_tri:=1; -end; - -procedure rota_pol(pol:poligon;angul:real;color:byte); -var xy:array [0..MAX_IPUNTS] of punt;i:byte; -begin - for i:=0 to pol.n-1 do begin - xy[i].x:=round((pol.ipuntx[i].r)*cos(pol.ipuntx[i].angle+angul))+pol.centre.x; - xy[i].y:=round((pol.ipuntx[i].r)*sin(pol.ipuntx[i].angle+angul))+pol.centre.y; - end; - for i:=0 to pol.n-2 do - linea(xy[i].x,xy[i].y,xy[i+1].x,xy[i+1].y,color); - linea(xy[pol.n-1].x,xy[pol.n-1].y,xy[0].x,xy[0].y,color); -end; - -procedure mou_orni(var orni:poligon); -var dx,dy:real; -begin - orni.angle:=orni.angle{+(random(256)/512)*(random(3)-1)}; - Dy:=round(orni.velocitat*sin(orni.angle-pi/2))+orni.centre.y; - Dx:=round(orni.velocitat*cos(orni.angle-pi/2))+orni.centre.x; - if (dy>MARGE_DALT) and (dyMARGE_ESQ) and (dxMARGE_DALT) and (dyMARGE_ESQ) and (dx1) and (nau.p2.r>1)and (nau.p3.r>1)and (itocado<170)) then begin - nau.p1.r:=nau.p1.r-0.7; - nau.p2.r:=nau.p2.r-0.7; - nau.p3.r:=nau.p3.r-0.7; - nau.angle:=nau.angle-0.3; - rota_tri(nau,nau.angle,0,1); - end - else begin - for i:=0 to MAX_IPUNTS-1 do begin - chatarra_cosmica.ipuntx[i].r:=chatarra_cosmica.ipuntx[i].r+3; - dx:=round((chatarra_cosmica.ipuntx[i].r)*cos(chatarra_cosmica.ipuntx[i].angle)) - +chatarra_cosmica.centre.x; - dy:=round((chatarra_cosmica.ipuntx[i].r)*sin(chatarra_cosmica.ipuntx[i].angle)) - +chatarra_cosmica.centre.y; - if ((dx>=0)AND(dx<640)AND(dy>0)AND(dy<480))then posa(dx,dy,1); - end; - end; - inc(itocado); - if itocado=170 then begin - nau.p1.r:=12;nau.p1.angle:=3*pi/2; - nau.p2.r:=12;nau.p2.angle:=pi/4; - nau.p3.r:=12;nau.p3.angle:=(3*pi)/4; - nau.angle:=0; - nau.centre.x:=320;nau.centre.y:=240; - end; - if ((itocado>170)and(itocado mod 3=0)) then rota_tri(nau,nau.angle,nau.velocitat,1); - if itocado>250 then itocado:=0; - -end; - -begin - randomize; - getmem(virt,38400); - itocado:=0; - clsvirt; - nau.p1.r:=12;nau.p1.angle:=3*pi/2; - nau.p2.r:=12;nau.p2.angle:=pi/4; - nau.p3.r:=12;nau.p3.angle:=(3*pi)/4; - nau.angle:=0; - nau.centre.x:=320;nau.centre.y:=240; - crear_poligon_regular(pol,10,200); - for i:=1 to MAX_ORNIS do crear_poligon_regular(orni[i],5,20); - mcga; - rota_pol(pol,0,1); - instalarkb; - repeat -{ - rota_tri(nau, nau.angle, nau.velocitat, 0);} - clsvirt; - - if teclapuls(KEYarrowright) then nau.angle:=nau.angle+0.157079632; - if teclapuls(KEYarrowleft) then nau.angle:=nau.angle-0.157079632; - if teclapuls(KEYarrowup) then begin - if nau.velocitatMARGE_DALT) and (dyMARGE_ESQ) and (dx0.1) then nau.velocitat:=nau.velocitat-0.1; -{ - dist: - = distancia(nau.centre, pol.centre); - diferencia(pol.centre, nau.centre, puntaux); - if dist - < (pol.ipuntx[1].r + 30) then begin nau.centre.x - : = nau.centre.x + round(dist * cos(angle(puntaux) + 0.031415)); - nau.centre.y - : = nau.centre.y + round(dist * sin(angle(puntaux) + 0.031415)); - end;} -{ for - i: - = 1 to 5 do begin rota_pol(orni[i], ang, 0); - end;} - for i:=1 to MAX_ORNIS do begin - mou_orni(orni[i]); - rota_pol(orni[i],orni[i].rotacio,1); - end; - if itocado=0 then aux:=rota_tri(nau,nau.angle,nau.velocitat,1) - else tocado; - if (aux=1) then begin inc(itocado);aux:=0;end; - if bales[1].esta then begin - mou_bales(bales[1]); - rota_pol(bales[1],0,1); - end; - waitretrace; - volca; -{ - if aux - = 1 then begin { - gotoxy(0, 0); - write('tocado') tocado; - delay(200); - end; - } - gotoxy(50, 24); - write('� Visente i Sergi'); - gotoxy(50, 25); - write('�ETA 2.2 2/6/99'); - until teclapuls(keyesc); - desinstalarkb; - ang: - = 0; - repeat waitretrace; - rota_pol(pol, ang, 0); - ang: - = ang + 0.031415; - rota_pol(pol, ang, 1); - until keypressed; - text; - end. \ No newline at end of file diff --git a/tools/pack_resources/Makefile b/tools/pack_resources/Makefile deleted file mode 100644 index 273095b..0000000 --- a/tools/pack_resources/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Makefile per a pack_resources -# © 2025 Orni Attack - -CXX ?= c++ -CXXFLAGS = -std=c++20 -Wall -Wextra -I../../source -TARGET = pack_resources - -SOURCES = pack_resources.cpp \ - ../../source/core/resources/resource_pack.cpp - -$(TARGET): $(SOURCES) - @echo "Compilant $(TARGET)..." - @$(CXX) $(CXXFLAGS) -o $(TARGET) $(SOURCES) - @echo "✓ $(TARGET) compilat" - -clean: - @rm -f $(TARGET) - @echo "✓ Netejat" - -.PHONY: clean