cmake_minimum_required(VERSION 3.20)
project(TmntIvTurtlesInTimeSNESRecomp C CXX)

set(CMAKE_C_STANDARD 11)
option(TMNT_RETAIL_WINDOWS "Build the end-user Windows ROM import flow" OFF)
option(TMNT_SAVE_RUNTIME_PROBE "Build private-ROM save integration probe instead of desktop entry" OFF)
set(TMNT_HD_TEST "" CACHE STRING "Optional synthetic graphics test entry: gpu, packs, or runtime")
set_property(CACHE TMNT_HD_TEST PROPERTY STRINGS "" gpu packs runtime)

# Release pin for lobby matching. Release builds stamp the VERSION file so two
# peers can prove they are the same build; everything else stamps "dev".
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" _GAME_VER_RAW)
string(STRIP "${_GAME_VER_RAW}" GAME_RELEASE_VERSION)
set(SNESRECOMP_BUILD_VERSION "" CACHE STRING
    "Lobby release pin (empty = Release uses VERSION, else dev)")
if(SNESRECOMP_BUILD_VERSION STREQUAL "")
    get_property(_is_multi GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
    if(_is_multi)
        set(SNESRECOMP_BUILD_VERSION "$<IF:$<CONFIG:Release>,${GAME_RELEASE_VERSION},dev>")
    elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
        set(SNESRECOMP_BUILD_VERSION "${GAME_RELEASE_VERSION}")
    else()
        set(SNESRECOMP_BUILD_VERSION "dev")
    endif()
endif()

set(SNESRECOMP_ROOT "${CMAKE_SOURCE_DIR}/snesrecomp" CACHE PATH
    "Path to the snesrecomp checkout used by this game")
if(NOT EXISTS "${SNESRECOMP_ROOT}/runner/runner.cmake")
    message(FATAL_ERROR
        "snesrecomp submodule missing at ${SNESRECOMP_ROOT}.\n"
        "Run: git submodule update --init --recursive")
endif()
# Mod packages are part of every project, not an option. The launcher's Mods
# page, the .snesmod loader, the trusted-plugin registry and netplay's mod-set
# gate all hang off this one switch; a build without it cannot exchange mods
# with a peer that has them, and the framework says so at every lobby init.
# Must precede the include: runner.cmake reads it to add the loader sources.
set(SNESRECOMP_ENABLE_MODS ON CACHE BOOL
    "Mod package loader + trusted plugins (required for every title)" FORCE)
include(${SNESRECOMP_ROOT}/runner/runner.cmake)

set(_tmnt_entry src/main.c)
if(TMNT_SAVE_RUNTIME_PROBE)
    set(_tmnt_entry tests/save_runtime_probe.c)
elseif(TMNT_HD_TEST STREQUAL "gpu")
    set(_tmnt_entry tests/graphics_gpu_probe.c)
elseif(TMNT_HD_TEST STREQUAL "packs")
    set(_tmnt_entry tests/hd_pack_probe.c)
elseif(TMNT_HD_TEST STREQUAL "runtime")
    set(_tmnt_entry tests/save_runtime_probe.c)
elseif(NOT TMNT_HD_TEST STREQUAL "")
    message(FATAL_ERROR "TMNT_HD_TEST must be gpu, packs, runtime, or empty")
endif()
if(TMNT_SAVE_RUNTIME_PROBE AND NOT TMNT_HD_TEST STREQUAL "")
    message(FATAL_ERROR "Use either TMNT_SAVE_RUNTIME_PROBE or TMNT_HD_TEST")
endif()
add_executable(TmntIvTurtlesInTimeSNESRecomp
    ${SNESRECOMP_RUNNER_SOURCES}
    ${_tmnt_entry}
    src/host_contract.c
    src/game_rtl.c
    src/game_save.c
    src/gen_stubs.c
)

# Native execution residue is tied to this source/ABI contract. Reject a save
# from a changed runtime rather than guessing at raw struct compatibility.
file(GLOB_RECURSE _save_sources CONFIGURE_DEPENDS
    "${SNESRECOMP_ROOT}/runner/src/*.c" "${SNESRECOMP_ROOT}/runner/src/*.h"
    "${CMAKE_SOURCE_DIR}/src/*.c" "${CMAKE_SOURCE_DIR}/src/*.h"
    "${CMAKE_SOURCE_DIR}/recomp/*.cfg")
set(_save_contract "tmnt4-save-v1;${CMAKE_C_COMPILER_ID};${CMAKE_C_COMPILER_VERSION};${CMAKE_SIZEOF_VOID_P}")
string(APPEND _save_contract ";${CMAKE_BUILD_TYPE};${CMAKE_C_FLAGS};${CMAKE_C_FLAGS_RELEASE}")
get_cmake_property(_save_options CACHE_VARIABLES)
list(SORT _save_options)
foreach(_save_option IN LISTS _save_options)
    if(_save_option MATCHES "^SNESRECOMP_" AND NOT _save_option MATCHES "ROOT|DIR|PATH")
        string(APPEND _save_contract ";${_save_option}=${${_save_option}}")
    endif()
endforeach()
foreach(_save_source IN LISTS _save_sources)
    file(SHA256 "${_save_source}" _save_hash)
    string(APPEND _save_contract "${_save_hash}")
endforeach()
string(SHA256 TMNT_SAVE_SCHEMA "${_save_contract}")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/save_schema.h"
    "#define TMNT_SAVE_SCHEMA \"${TMNT_SAVE_SCHEMA}\"\n")
target_include_directories(TmntIvTurtlesInTimeSNESRecomp PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
target_compile_definitions(TmntIvTurtlesInTimeSNESRecomp PRIVATE
    SNES_SAVESTATE_SLOTS=5 SNESRECOMP_PERSISTENT_SAVE_PROFILE=1 SNESRECOMP_HD_ASSETS=1)

# ROM identity. rom_identity.txt is the one place the digests live: the build
# turns it into snesrecomp_rom_identity.h (SNESRECOMP_ROM_EXPECTED_SHA256 and
# friends) for src/main.c, and tools/regen.sh, scripts/package_release.sh and
# the release workflow read the same file. A revision bump is one edit there.
snesrecomp_rom_identity(TmntIvTurtlesInTimeSNESRecomp ${CMAKE_SOURCE_DIR}/rom_identity.txt)

# Generated recompiler output. Not committed: it is derived from a copyrighted
# ROM, so every developer regenerates it locally from their own copy -- and a
# release does not ship it either. With -DSNESRECOMP_SETUP_HOST=ON and an empty
# src/gen/, this builds the SETUP HOST instead: the same executable minus the
# recompiled code, whose only path is the launcher's Generate & rebuild wizard.
# That is what release zips contain; the player's machine produces the
# playable binary from their own ROM. Without the option an empty src/gen/ is
# still a hard error (the framework owns the message).
snesrecomp_target_generated_code(TmntIvTurtlesInTimeSNESRecomp ${CMAKE_SOURCE_DIR}/src/gen)

# The mod catalog. This names WHERE the packages are; the framework owns the
# layout they are staged into beside the executable, and stages them on every
# build OF THE EXECUTABLE -- including the launcher's own Generate & rebuild on
# a player's machine, which builds only this target and would skip a sibling
# ALL target. mods/preloaded/packages/ holds reviewed, default-disabled
# packages; players install .snesmod archives through the launcher.
# snesrecomp/docs/MOD_PACKAGES.md.
#
# It used to be `snesrecomp_target_stage_dir(... ${CMAKE_SOURCE_DIR}/mods mods)`
# -- the destination spelled per title, which is how three ports in the same
# workspace ended up shipping an empty Mods page and nothing said so. Declaring
# it is now also enforced: a project with packages that never calls this fails
# to configure.
snesrecomp_target_mod_catalog(TmntIvTurtlesInTimeSNESRecomp ${CMAKE_SOURCE_DIR}/mods/preloaded)
# Any other directory the game reads exe-relative (a translations/ table, ...)
# is staged with snesrecomp_target_stage_dir, never with a separate ALL target.

target_include_directories(TmntIvTurtlesInTimeSNESRecomp PRIVATE
    ${SNESRECOMP_RUNNER_INCLUDE_DIRS}
    # common_rtl.c includes "config.h": the desktop key-map / Config contract
    # the framework host supplies (snesrecomp_target_desktop_host below).
    ${SNESRECOMP_ROOT}/runner/src/desktop
    ${CMAKE_SOURCE_DIR}/src
    ${CMAKE_SOURCE_DIR}/recomp
)
target_link_libraries(TmntIvTurtlesInTimeSNESRecomp PRIVATE ${SNESRECOMP_RUNNER_LIBRARIES})
target_compile_definitions(TmntIvTurtlesInTimeSNESRecomp PRIVATE
    SNES_GAME_VERSION="${SNESRECOMP_BUILD_VERSION}"
    SNES_GAME_TITLE="TMNT IV Turtles in Time"
)
snesrecomp_target_sdl(TmntIvTurtlesInTimeSNESRecomp)

# The desktop host: launcher flow, ROM resolution, config.ini + [KeyMap],
# window + SDL/OpenGL presenters, audio, gamepads, the save-state browser and
# rewind filmstrip, the pacing clock, crash handlers and the post-mortem
# report. src/main.c is the shim that names this title and supplies its
# hooks; the host is the framework's and improves on a submodule pull.
# Add TIER2 once this port reads the interpreter-gap manifest after each run.
snesrecomp_target_desktop_host(TmntIvTurtlesInTimeSNESRecomp)
# rom.cfg (the ROM the wizard set this project up from; git-ignored) is
# staged beside the executable when none is there yet, so the first launch
# opens on that dump rather than asking for one.
if(NOT TMNT_RETAIL_WINDOWS)
    snesrecomp_target_rom_cache(TmntIvTurtlesInTimeSNESRecomp)
endif()

# Shared Dear ImGui pre-boot launcher (ROM picker, verification, display /
# audio / input settings). Self-contained: it brings its own ImGui, GL link and
# staged assets, and defines RECOMP_LAUNCHER so src/main.c compiles its GUI path.
set(RECOMP_UI_ROOT "${CMAKE_SOURCE_DIR}/recomp-ui" CACHE PATH
    "Root directory of the recomp-ui launcher repo" FORCE)
if(NOT EXISTS "${RECOMP_UI_ROOT}/recomp_ui.cmake")
    message(FATAL_ERROR
        "recomp-ui missing at ${RECOMP_UI_ROOT}.\n"
        "Run: git submodule update --init --recursive recomp-ui")
endif()
include(${RECOMP_UI_ROOT}/recomp_ui.cmake)
# BOXART stages launcher_assets/img/boxart.tga beside the exe; the launcher
# shows assets/img/boxart.tga by default. EXISTS-guarded in recomp_ui.cmake,
# so this configures cleanly before any art is fetched.
recomp_target_launcher_ui(TmntIvTurtlesInTimeSNESRecomp CONSOLE snes
    BOXART "${CMAKE_SOURCE_DIR}/launcher_assets/img/boxart.tga")

# Generate & rebuild from inside the launcher: pick ROM -> recompile locally
# -> cmake --build -> relaunch. The implementation is the framework's; this
# project contributes no configuration (snesrecomp_codegen_host_autowire in
# src/main.c). recomp-ui/src is on the include path because the host speaks
# RecompLauncherCGameInfo.
target_sources(TmntIvTurtlesInTimeSNESRecomp PRIVATE
    ${SNESRECOMP_ROOT}/host/snesrecomp_codegen_host.c)
target_include_directories(TmntIvTurtlesInTimeSNESRecomp PRIVATE
    ${SNESRECOMP_ROOT}/host
    ${RECOMP_UI_ROOT}/src)

# Netplay is not built into this target.
# No multitap: two seats, one controller per port.

if(WIN32)
    enable_language(RC)
    target_sources(TmntIvTurtlesInTimeSNESRecomp PRIVATE installer/tmnt.rc)
endif()
if(WIN32 AND TMNT_RETAIL_WINDOWS)
    target_sources(TmntIvTurtlesInTimeSNESRecomp PRIVATE src/windows_rom.c installer/utf8.manifest)
    target_compile_definitions(TmntIvTurtlesInTimeSNESRecomp PRIVATE TMNT_RETAIL_WINDOWS=1)
    if(MSVC)
        target_link_options(TmntIvTurtlesInTimeSNESRecomp PRIVATE /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup)
    endif()
    target_link_libraries(TmntIvTurtlesInTimeSNESRecomp PRIVATE comdlg32 shell32)
endif()

