This commit is contained in:
VoxelTek 2025-07-29 13:50:45 +10:00
commit b3a993b9b2
369 changed files with 12453 additions and 5526 deletions

View File

@ -14,3 +14,8 @@ trim_trailing_whitespace = true
[{CMakeLists.txt,*.cmake}]
indent_size = 2
insert_final_newline = true
[*.{json,xml.in,desktop.in}]
indent_size = 2
insert_final_newline = true

4
.gitattributes vendored
View File

@ -5,3 +5,7 @@
*.html text eol=lf diff=html
*.mdp binary
*.mak text eol=crlf
**/*.ico binary
**/*.png binary
**/*.svg text eol=lf
**/*.desktop text eol=lf

View File

@ -25,6 +25,7 @@ jobs:
build:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
container: ${{ matrix.container || '' }}
defaults:
run:
shell: ${{ matrix.shell || 'sh' }}
@ -33,14 +34,19 @@ jobs:
fail-fast: false
matrix:
include:
- { name: 'Linux', os: 'ubuntu-latest', dx5: false, config: true, build-type: 'Debug', linux: true, werror: true, clang-tidy: true }
- { name: 'MSVC (x86)', os: 'windows-latest', dx5: true, config: false, build-type: 'Debug', msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64_x86' }
- { name: 'MSVC (x64)', os: 'windows-latest', dx5: false, config: false, build-type: 'Debug', msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64' }
- { name: 'MSVC (arm64)', os: 'windows-latest', dx5: false, config: false, build-type: 'Debug', msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64_arm64' }
- { name: 'msys2 mingw32', os: 'windows-latest', dx5: false, config: false, build-type: 'Debug', mingw: true, werror: true, clang-tidy: true, msystem: 'mingw32', msys-env: 'mingw-w64-i686', shell: 'msys2 {0}' }
- { name: 'msys2 mingw64', os: 'windows-latest', dx5: false, config: true, build-type: 'Debug', mingw: true, werror: true, clang-tidy: true, msystem: 'mingw64', msys-env: 'mingw-w64-x86_64', shell: 'msys2 {0}' }
- { name: 'macOS', os: 'macos-latest', dx5: false, config: true, build-type: 'Debug', brew: true, werror: true, clang-tidy: false }
- { name: 'Emscripten', os: 'ubuntu-latest', dx5: false, config: false, build-type: 'Debug', emsdk: true, werror: true, clang-tidy: false, cmake-wrapper: 'emcmake' }
- { name: 'Linux', os: 'ubuntu-latest', generator: 'Ninja', dx5: false, config: true, linux: true, werror: true, clang-tidy: true }
- { name: 'Linux (Debug)', os: 'ubuntu-latest', generator: 'Ninja', dx5: false, config: true, linux: true, werror: true, clang-tidy: true, debug: true }
- { name: 'MSVC (x86)', os: 'windows-latest', generator: 'Ninja', dx5: true, config: false, msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64_x86' }
- { name: 'MSVC (x64)', os: 'windows-latest', generator: 'Ninja', dx5: false, config: true, msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64' }
- { name: 'MSVC (x64 Debug)', os: 'windows-latest', generator: 'Ninja', dx5: false, config: true, msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64', debug: true }
- { name: 'MSVC (arm64)', os: 'windows-latest', generator: 'Ninja', dx5: false, config: false, msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64_arm64' }
- { name: 'msys2 mingw32', os: 'windows-latest', generator: 'Ninja', dx5: false, config: false, mingw: true, werror: true, clang-tidy: true, msystem: 'mingw32', msys-env: 'mingw-w64-i686', shell: 'msys2 {0}' }
- { name: 'msys2 mingw64', os: 'windows-latest', generator: 'Ninja', dx5: false, config: true, mingw: true, werror: true, clang-tidy: true, msystem: 'mingw64', msys-env: 'mingw-w64-x86_64', shell: 'msys2 {0}' }
- { name: 'macOS', os: 'macos-latest', generator: 'Ninja', dx5: false, config: true, brew: true, werror: true, clang-tidy: false }
- { name: 'iOS', os: 'macos-15', generator: 'Xcode', dx5: false, config: false, brew: true, werror: true, clang-tidy: false, cmake-args: '-DCMAKE_SYSTEM_NAME=iOS' }
- { name: 'Emscripten', os: 'ubuntu-latest', generator: 'Ninja', dx5: false, config: false, emsdk: true, werror: true, clang-tidy: false, cmake-wrapper: 'emcmake' }
- { name: 'Nintendo 3DS', os: 'ubuntu-latest', generator: 'Ninja', dx5: false, config: false, n3ds: true, werror: true, clang-tidy: false, container: 'devkitpro/devkitarm:latest', cmake-args: '-DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/3DS.cmake' }
- { name: 'Xbox One', os: 'windows-latest', generator: 'Visual Studio 17 2022', dx5: false, config: false, msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64', cmake-args: '-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0.26100.0', xbox-one: true}
steps:
- name: Setup vcvars
if: ${{ !!matrix.msvc }}
@ -59,6 +65,20 @@ jobs:
${{ matrix.msys-env }}-ninja
${{ matrix.msys-env }}-clang-tools-extra
${{ (matrix.config && format('{0}-qt6-base', matrix.msys-env)) || '' }}
- name: Install Qt
if: ${{ !!matrix.msvc && matrix.config }}
uses: jurplel/install-qt-action@v4
with:
cache: 'true'
- name: Install 3DS dependencies
if: ${{ matrix.n3ds }}
run: |
wget https://github.com/diasurgical/bannertool/releases/download/1.2.0/bannertool.zip
unzip -j "bannertool.zip" "linux-x86_64/bannertool" -d "/opt/devkitpro/tools/bin"
wget https://github.com/3DSGuy/Project_CTR/releases/download/makerom-v0.18/makerom-v0.18-ubuntu_x86_64.zip
unzip "makerom-v0.18-ubuntu_x86_64.zip" "makerom" -d "/opt/devkitpro/tools/bin"
chmod a+x /opt/devkitpro/tools/bin/makerom
- name: Install Linux dependencies (apt-get)
if: ${{ matrix.linux }}
@ -66,8 +86,8 @@ jobs:
sudo apt-get update
sudo apt-get install -y \
libx11-dev libxext-dev libxrandr-dev libxrender-dev libxfixes-dev libxi-dev libxinerama-dev \
libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev libglew-dev qt6-base-dev \
libasound2-dev
libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev qt6-base-dev \
libasound2-dev qt6-xdgdesktopportal-platformtheme
- name: Install macOS dependencies (brew)
if: ${{ matrix.brew }}
@ -88,27 +108,106 @@ jobs:
- name: Configure (CMake)
run: |
${{ matrix.cmake-wrapper || '' }} cmake -S . -B build -GNinja \
-DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
${{ matrix.cmake-wrapper || '' }} cmake -S . -B build -G "${{ matrix.generator }}" \
${{ matrix.cmake-args || '' }} \
-DCMAKE_BUILD_TYPE=Release \
-DISLE_USE_DX5=${{ !!matrix.dx5 }} \
-DISLE_BUILD_CONFIG=${{ matrix.config }} \
-DISLE_BUILD_CONFIG=${{ !!matrix.config }} \
-DENABLE_CLANG_TIDY=${{ !!matrix.clang-tidy }} \
-DISLE_WERROR=${{ !!matrix.werror }} \
-DISLE_DEBUG=${{ matrix.debug || 'OFF' }} \
-Werror=dev
- name: Build (CMake)
run: cmake --build build --verbose
run: cmake --build build --verbose --config Release
- name: Package (CPack)
if: ${{ !matrix.n3ds }}
run: |
cd build
cpack .
success=0
max_tries=10
for i in $(seq $max_tries); do
cpack . && success=1
if test $success = 1; then
break
fi
echo "Package creation failed. Sleep 1 second and try again."
sleep 1
done
if test $success = 0; then
echo "Package creation failed after $max_tries attempts."
exit 1
fi
- name: Install linuxdeploy
if: ${{ matrix.linux }}
id: install-linuxdeploy
uses: miurahr/install-linuxdeploy-action@v1.8.0
with:
plugins: qt appimage
- name: Package (AppImage)
if: ${{ matrix.linux }}
run: |
cd build && \
export LD_LIBRARY_PATH=".:$LD_LIBRARY_PATH" && \
NO_STRIP=1 ${{ steps.install-linuxdeploy.outputs.linuxdeploy }} \
-p qt \
-e isle \
-e isle-config \
-d packaging/linux/org.legoisland.Isle.desktop \
-i icons/org.legoisland.Isle.svg \
--custom-apprun=../packaging/linux/appimage/AppRun \
--appdir packaging/linux/appimage/AppDir \
--output appimage && \
mv *.AppImage dist/
- name: Package (3DS)
if: ${{ matrix.n3ds }}
run: |
cd build
mkdir dist
mv *.3dsx dist/
mv *.cia dist/
- name: Upload Build Artifacts
uses: actions/upload-artifact@v4
with:
name: '${{ matrix.name }} ${{ matrix.build-type }}'
path: build/dist/isle-*
name: '${{ matrix.name }}'
path: |
build/dist/isle-*
build/dist/*.AppImage
build/dist/*.3dsx
build/dist/*.cia
flatpak:
name: "Flatpak (${{ matrix.arch }})"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- arch: x86_64
os: ubuntu-latest
- arch: aarch64
os: ubuntu-22.04-arm
container:
image: ghcr.io/flathub-infra/flatpak-github-actions:kde-6.8
options: --privileged
steps:
- uses: actions/checkout@v4
- name: Build Flatpak
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
with:
bundle: org.legoisland.Isle.${{ matrix.arch }}.flatpak
manifest-path: packaging/linux/flatpak/org.legoisland.Isle.json
arch: ${{ matrix.arch }}
ncc:
name: 'C++'
@ -148,3 +247,30 @@ jobs:
LEGO1/omni/src/video/flic.cpp \
$action_headers \
--path LEGO1/omni LEGO1/lego/legoomni
release:
name: 'Release'
if: ${{ github.event_name == 'push' && github.ref_name == 'master' }}
runs-on: ubuntu-latest
needs:
- build
- flatpak
steps:
- name: Download All Artifacts
uses: actions/download-artifact@main
with:
pattern: "*"
path: Release
merge-multiple: true
- name: Checkout uploadtool
uses: actions/checkout@v4
with:
repository: 'probonopd/uploadtool'
path: 'uploadtool'
- name: Upload Continuous Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
./uploadtool/upload.sh Release/*

55
.github/workflows/docker.yml vendored Normal file
View File

@ -0,0 +1,55 @@
name: Docker
on:
push:
branches: ['master']
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}-emscripten
jobs:
publish-emscripten:
name: Publish web port
env:
IMAGE_NAME: ${{ github.repository }}-emscripten
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
attestations: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
id: push
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with:
file: docker/emscripten/Dockerfile
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Generate artifact attestation
uses: actions/attest-build-provenance@v2
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true

View File

@ -1,116 +0,0 @@
name: Release
on:
push:
branches:
- master
jobs:
build:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
defaults:
run:
shell: ${{ matrix.shell || 'sh' }}
strategy:
fail-fast: false
matrix:
include:
- { name: 'Linux', os: 'ubuntu-latest', dx5: false, config: true, build-type: 'Release', linux: true, werror: true, clang-tidy: false }
- { name: 'Windows', os: 'windows-latest', dx5: false, config: false, build-type: 'Release', msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64' }
- { name: 'macOS', os: 'macos-latest', dx5: false, config: true, build-type: 'Release', brew: true, werror: true, clang-tidy: false }
steps:
- name: Setup vcvars
if: ${{ !!matrix.msvc }}
uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{ matrix.vc-arch }}
- name: Set up MSYS2
if: ${{ !!matrix.msystem }}
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.msystem }}
install: >-
${{ matrix.msys-env }}-cc
${{ matrix.msys-env }}-cmake
${{ matrix.msys-env }}-ninja
${{ matrix.msys-env }}-clang-tools-extra
${{ (matrix.config && format('{0}-qt6-base', matrix.msys-env)) || '' }}
- name: Install Linux dependencies (apt-get)
if: ${{ matrix.linux }}
run: |
sudo apt-get update
sudo apt-get install -y \
libx11-dev libxext-dev libxrandr-dev libxrender-dev libxfixes-dev libxi-dev libxinerama-dev \
libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev libglew-dev qt6-base-dev \
libasound2-dev
- name: Install macOS dependencies (brew)
if: ${{ matrix.brew }}
run: |
brew update
brew install cmake ninja llvm qt6
echo "LLVM_ROOT=$(brew --prefix llvm)/bin" >> $GITHUB_ENV
- name: Setup Emscripten
uses: mymindstorm/setup-emsdk@master
if: ${{ matrix.emsdk }}
- name: Setup ninja
if: ${{ matrix.msvc }}
uses: ashutoshvarma/setup-ninja@master
- uses: actions/checkout@v4
- name: Configure (CMake)
run: |
${{ matrix.cmake-wrapper || '' }} cmake -S . -B build -GNinja \
-DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
-DISLE_USE_DX5=${{ !!matrix.dx5 }} \
-DISLE_BUILD_CONFIG=${{ matrix.config }} \
-DENABLE_CLANG_TIDY=${{ !!matrix.clang-tidy }} \
-DISLE_WERROR=${{ !!matrix.werror }} \
-DISLE_DEBUG=OFF \
-Werror=dev
- name: Build (CMake)
run: cmake --build build --verbose
- name: Package (CPack)
run: |
cd build
cpack .
- name: Upload Artifact
uses: actions/upload-artifact@main
with:
name: Release-${{ matrix.name }}
path: |
build/dist/isle-*
release:
name: 'Release'
runs-on: ubuntu-latest
needs: build
steps:
- name: Download All Artifacts
uses: actions/download-artifact@main
with:
pattern: Release-*
path: Release
merge-multiple: true
- name: Checkout uploadtool
uses: actions/checkout@v4
with:
repository: 'probonopd/uploadtool'
path: 'uploadtool'
- name: Upload Continuous Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
./uploadtool/upload.sh Release/*

6
.gitignore vendored
View File

@ -30,3 +30,9 @@ LEGO1.DLL
# Kate - Text
/.cache
# Flatpak build cache
**/.flatpak-builder/
# Flatpak build dir
**/flatpak-build/

View File

@ -88,7 +88,7 @@ persistent=yes
# Minimum Python version to use for version dependent checks. Will default to
# the version used to run pylint.
py-version=3.11
py-version=3.12
# Discover python modules and packages in the file system subtree.
recursive=no

156
CMake/detectcpu.cmake Normal file
View File

@ -0,0 +1,156 @@
function(DetectTargetCPUArchitectures DETECTED_ARCHS)
set(known_archs EMSCRIPTEN ARM32 ARM64 ARM64EC LOONGARCH64 POWERPC32 POWERPC64 X86 X64)
if(APPLE AND CMAKE_OSX_ARCHITECTURES)
foreach(known_arch IN LISTS known_archs)
set(CPU_${known_arch} "0" PARENT_SCOPE)
endforeach()
set(detected_archs)
foreach(osx_arch IN LISTS CMAKE_OSX_ARCHITECTURES)
if(osx_arch STREQUAL "x86_64")
set(CPU_X64 "1" PARENT_SCOPE)
list(APPEND detected_archs "X64")
elseif(osx_arch STREQUAL "arm64")
set(CPU_ARM64 "1" PARENT_SCOPE)
list(APPEND detected_archs "ARM64")
endif()
endforeach()
set("${DETECTED_ARCHS}" "${detected_archs}" PARENT_SCOPE)
return()
endif()
set(detected_archs)
foreach(known_arch IN LISTS known_archs)
if(CPU_${known_arch})
list(APPEND detected_archs "${known_arch}")
endif()
endforeach()
if(detected_archs)
set("${DETECTED_ARCHS}" "${detected_archs}" PARENT_SCOPE)
return()
endif()
set(arch_check_ARM32 "defined(__arm__) || defined(_M_ARM)")
set(arch_check_ARM64 "defined(__aarch64__) || defined(_M_ARM64)")
set(arch_check_ARM64EC "defined(_M_ARM64EC)")
set(arch_check_EMSCRIPTEN "defined(__EMSCRIPTEN__)")
set(arch_check_LOONGARCH64 "defined(__loongarch64)")
set(arch_check_POWERPC32 "(defined(__PPC__) || defined(__powerpc__)) && !defined(__powerpc64__)")
set(arch_check_POWERPC64 "defined(__PPC64__) || defined(__powerpc64__)")
set(arch_check_X86 "defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) ||defined( __i386) || defined(_M_IX86)")
set(arch_check_X64 "(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)) && !defined(_M_ARM64EC)")
set(src_vars "")
set(src_main "")
foreach(known_arch IN LISTS known_archs)
set(detected_${known_arch} "0")
string(APPEND src_vars "
#if ${arch_check_${known_arch}}
#define ARCH_${known_arch} \"1\"
#else
#define ARCH_${known_arch} \"0\"
#endif
const char *arch_${known_arch} = \"INFO<${known_arch}=\" ARCH_${known_arch} \">\";
")
string(APPEND src_main "
result += arch_${known_arch}[argc];")
endforeach()
set(src_arch_detect "${src_vars}
int main(int argc, char *argv[]) {
int result = 0;
(void)argv;
${src_main}
return result;
}")
if(CMAKE_C_COMPILER)
set(ext ".c")
elseif(CMAKE_CXX_COMPILER)
set(ext ".cpp")
else()
enable_language(C)
set(ext ".c")
endif()
set(path_src_arch_detect "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeTmp/detect_arch${ext}")
file(WRITE "${path_src_arch_detect}" "${src_arch_detect}")
set(path_dir_arch_detect "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeTmp/detect_arch")
set(path_bin_arch_detect "${path_dir_arch_detect}/bin")
set(detected_archs)
set(msg "Detecting Target CPU Architecture")
message(STATUS "${msg}")
include(CMakePushCheckState)
set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
cmake_push_check_state(RESET)
try_compile(CPU_CHECK_ALL
"${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeTmp/detect_arch"
SOURCES "${path_src_arch_detect}"
COPY_FILE "${path_bin_arch_detect}"
)
cmake_pop_check_state()
if(NOT CPU_CHECK_ALL)
message(STATUS "${msg} - <ERROR>")
message(WARNING "Failed to compile source detecting the target CPU architecture")
else()
set(re "INFO<([A-Z0-9]+)=([01])>")
file(STRINGS "${path_bin_arch_detect}" infos REGEX "${re}")
foreach(info_arch_01 IN LISTS infos)
string(REGEX MATCH "${re}" A "${info_arch_01}")
if(NOT "${CMAKE_MATCH_1}" IN_LIST known_archs)
message(WARNING "Unknown architecture: \"${CMAKE_MATCH_1}\"")
continue()
endif()
set(arch "${CMAKE_MATCH_1}")
set(arch_01 "${CMAKE_MATCH_2}")
set(detected_${arch} "${arch_01}")
endforeach()
foreach(known_arch IN LISTS known_archs)
if(detected_${known_arch})
list(APPEND detected_archs ${known_arch})
endif()
endforeach()
endif()
if(detected_archs)
foreach(known_arch IN LISTS known_archs)
set("CPU_${known_arch}" "${detected_${known_arch}}" CACHE BOOL "Detected architecture ${known_arch}")
endforeach()
message(STATUS "${msg} - ${detected_archs}")
else()
include(CheckCSourceCompiles)
cmake_push_check_state(RESET)
foreach(known_arch IN LISTS known_archs)
if(NOT detected_archs)
set(cache_variable "CPU_${known_arch}")
set(test_src "
int main(int argc, char *argv[]) {
#if ${arch_check_${known_arch}}
return 0;
#else
choke
#endif
}
")
check_c_source_compiles("${test_src}" "${cache_variable}")
if(${cache_variable})
set(CPU_${known_arch} "1" CACHE BOOL "Detected architecture ${known_arch}")
set(detected_archs ${known_arch})
else()
set(CPU_${known_arch} "0" CACHE BOOL "Detected architecture ${known_arch}")
endif()
endif()
endforeach()
cmake_pop_check_state()
endif()
set("${DETECTED_ARCHS}" "${detected_archs}" PARENT_SCOPE)
endfunction()

View File

@ -2,9 +2,19 @@ cmake_minimum_required(VERSION 3.25...4.0 FATAL_ERROR)
project(isle LANGUAGES CXX C VERSION 0.1)
if (IOS)
set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED NO)
set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0")
add_compile_definitions(IOS)
endif()
if (WINDOWS_STORE)
add_compile_definitions(WINDOWS_STORE)
endif()
if (EMSCRIPTEN)
add_compile_options(-pthread)
add_link_options(-sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=2gb -sUSE_PTHREADS=1 -sPROXY_TO_PTHREAD=1 -sPTHREAD_POOL_SIZE_STRICT=0 -sFORCE_FILESYSTEM=1 -sWASMFS=1 -sEXIT_RUNTIME=1)
add_link_options(-sUSE_WEBGL2=1 -sMIN_WEBGL_VERSION=2 -sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=2gb -sUSE_PTHREADS=1 -sPROXY_TO_PTHREAD=1 -sOFFSCREENCANVAS_SUPPORT=1 -sPTHREAD_POOL_SIZE_STRICT=0 -sFORCE_FILESYSTEM=1 -sWASMFS=1 -sEXIT_RUNTIME=1)
set(SDL_PTHREADS ON CACHE BOOL "Enable SDL pthreads" FORCE)
endif()
@ -13,6 +23,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
include(CheckCXXSourceCompiles)
include(CMakeDependentOption)
include(CMakePushCheckState)
include(CMake/detectcpu.cmake)
DetectTargetCPUArchitectures(ISLE_CPUS)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@ -26,7 +39,7 @@ else()
endif()
find_program(SDL_SHADERCROSS_BIN NAMES "shadercross")
find_package(Python3 3.11 COMPONENTS Interpreter)
find_package(Python3 3.12 COMPONENTS Interpreter)
option(ISLE_BUILD_APP "Build isle application" ON)
option(ISLE_ASAN "Enable Address Sanitizer" OFF)
@ -35,7 +48,8 @@ option(ISLE_WERROR "Treat warnings as errors" OFF)
option(ISLE_DEBUG "Enable imgui debug" ON)
cmake_dependent_option(ISLE_USE_DX5 "Build with internal DirectX 5 SDK" "${NOT_MINGW}" "WIN32;CMAKE_SIZEOF_VOID_P EQUAL 4" OFF)
cmake_dependent_option(ISLE_MINIWIN "Use miniwin" ON "NOT ISLE_USE_DX5" OFF)
cmake_dependent_option(ISLE_BUILD_CONFIG "Build CONFIG.EXE application" ON "MSVC OR ISLE_MINIWIN" OFF)
cmake_dependent_option(ISLE_EXTENSIONS "Use extensions" ON "NOT ISLE_USE_DX5" OFF)
cmake_dependent_option(ISLE_BUILD_CONFIG "Build CONFIG.EXE application" ON "MSVC OR ISLE_MINIWIN;NOT NINTENDO_3DS;NOT WINDOWS_STORE" OFF)
cmake_dependent_option(ISLE_COMPILE_SHADERS "Compile shaders" ON "SDL_SHADERCROSS_BIN;TARGET Python3::Interpreter" OFF)
option(CMAKE_POSITION_INDEPENDENT_CODE "Build with -fPIC" ON)
option(ENABLE_CLANG_TIDY "Enable clang-tidy")
@ -48,50 +62,60 @@ message(STATUS "Isle app: ${ISLE_BUILD_APP}")
message(STATUS "Config app: ${ISLE_BUILD_CONFIG}")
message(STATUS "Internal DirectX5 SDK: ${ISLE_USE_DX5}")
message(STATUS "Internal miniwin: ${ISLE_MINIWIN}")
message(STATUS "Isle extensions: ${ISLE_EXTENSIONS}")
message(STATUS "Isle debugging: ${ISLE_DEBUG}")
message(STATUS "Compile shaders: ${ISLE_COMPILE_SHADERS}")
add_library(Isle::iniparser INTERFACE IMPORTED)
if (DOWNLOAD_DEPENDENCIES)
# FetchContent downloads and configures dependencies
message(STATUS "Fetching SDL3 and iniparser. This might take a while...")
include(FetchContent)
# FetchContent downloads and configures dependencies
message(STATUS "Fetching SDL3 and iniparser. This might take a while...")
include(FetchContent)
if (WINDOWS_STORE)
FetchContent_Declare(
SDL3
GIT_REPOSITORY "https://github.com/Helloyunho/SDL3-uwp.git"
GIT_TAG "main"
EXCLUDE_FROM_ALL
)
else()
FetchContent_Declare(
SDL3
GIT_REPOSITORY "https://github.com/libsdl-org/SDL.git"
GIT_TAG "main"
EXCLUDE_FROM_ALL
)
FetchContent_MakeAvailable(SDL3)
endif()
FetchContent_MakeAvailable(SDL3)
FetchContent_Declare(
iniparser
GIT_REPOSITORY "https://gitlab.com/iniparser/iniparser.git"
GIT_TAG "main"
EXCLUDE_FROM_ALL
)
block()
set(BUILD_DOCS off)
set(BUILD_SHARED_LIBS off)
FetchContent_MakeAvailable(iniparser)
target_link_libraries(Isle::iniparser INTERFACE iniparser-static)
endblock()
FetchContent_Declare(
iniparser
GIT_REPOSITORY "https://gitlab.com/iniparser/iniparser.git"
GIT_TAG "main"
EXCLUDE_FROM_ALL
)
block()
set(BUILD_DOCS off)
set(BUILD_SHARED_LIBS off)
FetchContent_MakeAvailable(iniparser)
target_link_libraries(Isle::iniparser INTERFACE iniparser-static)
endblock()
else()
# find_package looks for already-installed system packages.
# Configure with `-DCMAKE_PREFIX_PATH="/path/to/package1;/path/to/package2"`
# to add search paths.
find_package(SDL3 CONFIG REQUIRED)
# find_package looks for already-installed system packages.
# Configure with `-DCMAKE_PREFIX_PATH="/path/to/package1;/path/to/package2"`
# to add search paths.
find_package(SDL3 CONFIG REQUIRED)
find_package(iniparser REQUIRED CONFIG COMPONENTS shared)
target_link_libraries(Isle::iniparser INTERFACE iniparser-shared)
find_package(iniparser REQUIRED CONFIG COMPONENTS shared)
target_link_libraries(Isle::iniparser INTERFACE iniparser-shared)
endif()
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if (ENABLE_CLANG_TIDY)
find_program(CLANG_TIDY_BIN NAMES "clang-tidy" ENV "LLVM_ROOT" REQUIRED)
set(CMAKE_C_CLANG_TIDY "${CLANG_TIDY_BIN}")
set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_BIN}")
find_program(CLANG_TIDY_BIN NAMES "clang-tidy" ENV "LLVM_ROOT" REQUIRED)
set(CMAKE_C_CLANG_TIDY "${CLANG_TIDY_BIN}")
set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_BIN}")
endif()
if (ISLE_ASAN)
@ -109,26 +133,26 @@ add_subdirectory(miniwin EXCLUDE_FROM_ALL)
set(isle_targets)
function(add_cxx_warning WARNING)
if (ISLE_WERROR)
set(compiler_option "-Werror=${WARNING}")
else()
set(compiler_option "-W${WARNING}")
endif()
string(MAKE_C_IDENTIFIER "COMPILER_SUPPORTS${compiler_option}" varname)
if (ISLE_WERROR)
set(compiler_option "-Werror=${WARNING}")
else()
set(compiler_option "-W${WARNING}")
endif()
string(MAKE_C_IDENTIFIER "COMPILER_SUPPORTS${compiler_option}" varname)
cmake_push_check_state(RESET)
set(CMAKE_REQUIRED_FLAGS "${compiler_option} ")
if (MSVC)
string(APPEND CMAKE_REQUIRED_FLAGS "/WX")
else()
string(APPEND CMAKE_REQUIRED_FLAGS "-Werror")
endif()
check_cxx_source_compiles("int main() { return 0; }" ${varname})
cmake_pop_check_state()
cmake_push_check_state(RESET)
set(CMAKE_REQUIRED_FLAGS "${compiler_option} ")
if (MSVC)
string(APPEND CMAKE_REQUIRED_FLAGS "/WX")
else()
string(APPEND CMAKE_REQUIRED_FLAGS "-Werror")
endif()
check_cxx_source_compiles("int main() { return 0; }" ${varname})
cmake_pop_check_state()
if (${varname})
add_compile_options(${compiler_option})
endif()
if (${varname})
add_compile_options(${compiler_option})
endif()
endfunction()
add_subdirectory(3rdparty EXCLUDE_FROM_ALL SYSTEM)
@ -148,6 +172,7 @@ add_library(lego1
target_precompile_headers(lego1 PRIVATE "LEGO1/lego1_pch.h")
set_property(TARGET lego1 PROPERTY DEFINE_SYMBOL "LEGO1_DLL")
target_include_directories(lego1 PUBLIC "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/util>")
target_include_directories(lego1 PUBLIC "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/extensions/include>")
target_include_directories(lego1 PUBLIC "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/LEGO1>")
target_include_directories(lego1 PUBLIC "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/LEGO1/omni/include>")
target_include_directories(lego1 PUBLIC "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/LEGO1/lego/sources>")
@ -156,6 +181,8 @@ target_include_directories(lego1 PUBLIC "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/L
target_link_libraries(lego1 PRIVATE SDL3::SDL3)
target_link_libraries(lego1 PUBLIC SDL3::Headers)
target_link_libraries(lego1 PRIVATE $<$<BOOL:${ISLE_USE_DX5}>:DirectX5::DirectX5>)
# Allow unconditional include of miniwin/miniwind3d.h
target_link_libraries(lego1 PRIVATE miniwin-headers)
if(WIN32)
set_property(TARGET lego1 PROPERTY PREFIX "")
endif()
@ -286,10 +313,10 @@ target_sources(lego1 PRIVATE
LEGO1/omni/src/common/mxcompositepresenter.cpp
LEGO1/omni/src/common/mxcore.cpp
LEGO1/omni/src/common/mxdebug.cpp
LEGO1/omni/src/common/mxmediamanager.cpp
LEGO1/omni/src/common/mxmediapresenter.cpp
LEGO1/omni/src/common/mxmisc.cpp
LEGO1/omni/src/common/mxobjectfactory.cpp
LEGO1/omni/src/common/mxpresentationmanager.cpp
LEGO1/omni/src/common/mxpresenter.cpp
LEGO1/omni/src/common/mxstring.cpp
LEGO1/omni/src/common/mxticklemanager.cpp
@ -435,9 +462,6 @@ target_sources(lego1 PRIVATE
LEGO1/lego/legoomni/src/race/raceskel.cpp
LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp
LEGO1/lego/legoomni/src/video/legoflctexturepresenter.cpp
LEGO1/lego/legoomni/src/video/legohideanimpresenter.cpp
LEGO1/lego/legoomni/src/video/legolocomotionanimpresenter.cpp
LEGO1/lego/legoomni/src/video/legoloopinganimpresenter.cpp
LEGO1/lego/legoomni/src/video/legomodelpresenter.cpp
LEGO1/lego/legoomni/src/video/legopalettepresenter.cpp
LEGO1/lego/legoomni/src/video/legopartpresenter.cpp
@ -465,11 +489,22 @@ if (NOT ISLE_MINIWIN)
target_compile_definitions(lego1 PRIVATE DIRECTINPUT_VERSION=0x0500)
endif()
if (ISLE_EXTENSIONS)
target_compile_definitions(lego1 PUBLIC EXTENSIONS)
target_sources(lego1 PRIVATE
extensions/src/extensions.cpp
extensions/src/textureloader.cpp
)
endif()
if (ISLE_BUILD_APP)
add_executable(isle WIN32
ISLE/res/isle.rc
ISLE/isleapp.cpp
ISLE/islefiles.cpp
${CMAKE_SOURCE_DIR}/ISLE/res/arrow_bmp.h
${CMAKE_SOURCE_DIR}/ISLE/res/busy_bmp.h
${CMAKE_SOURCE_DIR}/ISLE/res/no_bmp.h
)
list(APPEND isle_targets isle)
if (WIN32)
@ -490,6 +525,9 @@ if (ISLE_BUILD_APP)
# Allow unconditional include of miniwin/miniwindevice.h
target_link_libraries(isle PRIVATE miniwin-headers)
# Vector math
target_link_libraries(isle PRIVATE Vec::Vec)
# Link DSOUND and WINMM
if (WIN32)
target_link_libraries(isle PRIVATE winmm)
@ -513,19 +551,71 @@ if (ISLE_BUILD_APP)
endif()
if(EMSCRIPTEN)
target_sources(isle PRIVATE
ISLE/emscripten/config.cpp
ISLE/emscripten/events.cpp
ISLE/emscripten/filesystem.cpp
ISLE/emscripten/haptic.cpp
ISLE/emscripten/messagebox.cpp
ISLE/emscripten/window.cpp
)
target_compile_definitions(isle PRIVATE "ISLE_EMSCRIPTEN_HOST=\"${ISLE_EMSCRIPTEN_HOST}\"")
set_property(TARGET isle PROPERTY SUFFIX ".html")
endif()
if(NINTENDO_3DS)
target_sources(isle PRIVATE
ISLE/3ds/apthooks.cpp
ISLE/3ds/config.cpp
)
endif()
if(WINDOWS_STORE)
target_sources(isle PRIVATE
ISLE/xbox_one_series/config.cpp
)
endif()
if (IOS)
target_sources(isle PRIVATE
ISLE/ios/config.cpp
)
endif()
if(Python3_FOUND)
if(NOT DEFINED PYTHON_PIL_AVAILABLE)
execute_process(
COMMAND ${Python3_EXECUTABLE} -c "import PIL; print('pil')"
RESULT_VARIABLE PIL_RESULT
OUTPUT_VARIABLE PIL_OUTPUT
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(PIL_RESULT EQUAL 0 AND PIL_OUTPUT STREQUAL "pil")
set(PIL_AVAILABLE 1)
else()
message(STATUS "Python PIL not found, using pre-generated headers.")
set(PIL_AVAILABLE 0)
endif()
set(PYTHON_PIL_AVAILABLE ${PIL_AVAILABLE} CACHE BOOL "Is Python3 Pillow available?")
endif()
if(PYTHON_PIL_AVAILABLE)
add_custom_command(
OUTPUT
${CMAKE_SOURCE_DIR}/ISLE/res/arrow_bmp.h
${CMAKE_SOURCE_DIR}/ISLE/res/busy_bmp.h
${CMAKE_SOURCE_DIR}/ISLE/res/no_bmp.h
COMMAND ${Python3_EXECUTABLE} tools/curpng2h.py ISLE/res/arrow.png ISLE/res/busy.png ISLE/res/no.png
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
DEPENDS
${CMAKE_SOURCE_DIR}/tools/curpng2h.py
${CMAKE_SOURCE_DIR}/ISLE/res/arrow.png
${CMAKE_SOURCE_DIR}/ISLE/res/busy.png
${CMAKE_SOURCE_DIR}/ISLE/res/no.png
)
endif()
endif()
endif()
if (ISLE_BUILD_CONFIG)
find_package(Qt6 REQUIRED COMPONENTS Core Widgets)
qt_standard_project_setup()
qt_add_executable(config WIN32
qt_add_executable(isle-config WIN32
LEGO1/mxdirectx/mxdirectxinfo.cpp
LEGO1/mxdirectx/legodxinfo.cpp
CONFIG/config.cpp
@ -535,22 +625,22 @@ if (ISLE_BUILD_CONFIG)
CONFIG/res/config.rc
CONFIG/res/config.qrc
)
target_link_libraries(config PRIVATE Qt6::Core Qt6::Widgets)
set_property(TARGET config PROPERTY AUTOMOC ON)
set_property(TARGET config PROPERTY AUTORCC ON)
set_property(TARGET config PROPERTY AUTOUIC ON)
set_property(TARGET config PROPERTY AUTOUIC_SEARCH_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/CONFIG/res")
list(APPEND isle_targets config)
target_compile_definitions(config PRIVATE _AFXDLL MXDIRECTX_FOR_CONFIG)
target_include_directories(config PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/LEGO1")
target_include_directories(config PUBLIC "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/util>")
target_link_libraries(isle-config PRIVATE Qt6::Core Qt6::Widgets)
set_property(TARGET isle-config PROPERTY AUTOMOC ON)
set_property(TARGET isle-config PROPERTY AUTORCC ON)
set_property(TARGET isle-config PROPERTY AUTOUIC ON)
set_property(TARGET isle-config PROPERTY AUTOUIC_SEARCH_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/CONFIG/res")
list(APPEND isle_targets isle-config)
target_compile_definitions(isle-config PRIVATE _AFXDLL MXDIRECTX_FOR_CONFIG)
target_include_directories(isle-config PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/LEGO1")
target_include_directories(isle-config PUBLIC "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/util>")
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14)
target_link_libraries(config PRIVATE DirectX5::DirectX5)
target_link_libraries(isle-config PRIVATE DirectX5::DirectX5)
endif()
target_compile_definitions(config PRIVATE DIRECT3D_VERSION=0x500)
target_link_libraries(config PRIVATE SDL3::SDL3 Isle::iniparser)
target_compile_definitions(isle-config PRIVATE DIRECT3D_VERSION=0x500)
target_link_libraries(isle-config PRIVATE SDL3::SDL3 Isle::iniparser)
if (NOT ISLE_MINIWIN)
target_link_libraries(config PRIVATE ddraw dxguid)
target_link_libraries(isle-config PRIVATE ddraw dxguid)
endif()
endif()
@ -564,8 +654,14 @@ if (MSVC)
if (TARGET isle)
target_compile_definitions(isle PRIVATE "_CRT_SECURE_NO_WARNINGS")
endif()
if (TARGET config)
target_compile_definitions(config PRIVATE "_CRT_SECURE_NO_WARNINGS")
if (TARGET isle-config)
target_compile_definitions(isle-config PRIVATE "_CRT_SECURE_NO_WARNINGS")
endif()
if (TARGET iniparser-static)
target_compile_definitions(iniparser-static PRIVATE "_CRT_SECURE_NO_WARNINGS")
endif()
if (TARGET libsmacker)
target_compile_definitions(libsmacker PRIVATE "_CRT_SECURE_NO_WARNINGS")
endif()
endif()
# Visual Studio 2017 version 15.7 needs "/Zc:__cplusplus" for __cplusplus
@ -574,8 +670,8 @@ if (MSVC)
if (TARGET isle)
target_compile_options(isle PRIVATE "-Zc:__cplusplus")
endif()
if (TARGET config)
target_compile_options(config PRIVATE "-Zc:__cplusplus")
if (TARGET isle-config)
target_compile_options(isle-config PRIVATE "-Zc:__cplusplus")
endif()
endif()
endif()
@ -624,17 +720,46 @@ else()
include(GNUInstallDirs)
endif()
set(ISLE_PACKAGE_NAME "${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}" CACHE STRING "Platform name of the package")
string(REPLACE ";" "-" ISLE_CPUS_STRING "${ISLE_CPUS}")
string(TOLOWER "${ISLE_CPUS_STRING}" ISLE_CPUS_STRING)
if (WINDOWS_STORE)
set(ISLE_PACKAGE_NAME "Xbox_One_Series_XS-${ISLE_CPUS_STRING}" CACHE STRING "Platform name of the package")
else()
set(ISLE_PACKAGE_NAME "${CMAKE_SYSTEM_NAME}-${ISLE_CPUS_STRING}" CACHE STRING "Platform name of the package")
endif()
if(BUILD_SHARED_LIBS)
list(APPEND install_extra_targets lego1)
endif()
install(TARGETS isle ${install_extra_targets}
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
)
if (ISLE_BUILD_CONFIG)
install(TARGETS config
if (NOT (NINTENDO_3DS OR WINDOWS_STORE))
install(TARGETS isle ${install_extra_targets}
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
BUNDLE DESTINATION "."
)
endif()
if (ISLE_BUILD_CONFIG)
if(WIN32)
find_program(WINDEPLOYQT_EXECUTABLE windeployqt)
if(WINDEPLOYQT_EXECUTABLE)
install(CODE "message(STATUS \"Running windeployqt with minimal dependencies\")
execute_process(COMMAND \"${WINDEPLOYQT_EXECUTABLE}\"
\"$<TARGET_FILE:isle-config>\"
--dir QTLibs
--no-compiler-runtime
--no-opengl-sw
--no-system-d3d-compiler
--no-translations
--no-quick-import
)"
)
install(DIRECTORY "Build/QTLibs/" DESTINATION "${CMAKE_INSTALL_BINDIR}")
else()
message(STATUS "windeployqt not found: Qt binaries will not be installed")
endif()
endif()
install(TARGETS isle-config
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
BUNDLE DESTINATION "."
)
endif()
if(EMSCRIPTEN)
@ -643,11 +768,77 @@ if(EMSCRIPTEN)
)
endif()
add_subdirectory(packaging)
set(CPACK_PACKAGE_DIRECTORY "dist")
set(CPACK_PACKAGE_FILE_NAME "isle-${PROJECT_VERSION}-${ISLE_PACKAGE_NAME}-${CMAKE_SYSTEM_PROCESSOR}")
if(MSVC)
set(CPACK_PACKAGE_FILE_NAME "isle-${PROJECT_VERSION}-${ISLE_PACKAGE_NAME}")
if(NINTENDO_3DS)
find_program(BANNERTOOL bannertool)
find_program(MAKEROM makerom)
ctr_generate_smdh(isle.smdh
NAME "LEGO Island"
TITLE "LEGO Island"
DESCRIPTION "LEGO Island for the Nintendo 3DS"
AUTHOR "isledecomp/isle-portable"
VERSION "${PROJECT_VERSION}"
ICON "${CMAKE_SOURCE_DIR}/packaging/3ds/icon.png"
)
ctr_create_3dsx(isle SMDH isle.smdh)
if(BANNERTOOL AND MAKEROM)
add_custom_command(
OUTPUT "isle.bnr"
COMMAND "${BANNERTOOL}" makebanner
-i "${CMAKE_SOURCE_DIR}/packaging/3ds/banner.png"
-a "${CMAKE_SOURCE_DIR}/packaging/3ds/banner.wav"
-o "isle.bnr"
DEPENDS "${CMAKE_SOURCE_DIR}/packaging/3ds/banner.png" "${CMAKE_SOURCE_DIR}/packaging/3ds/banner.wav"
VERBATIM
)
add_custom_command(
OUTPUT "isle.cia"
COMMAND "${MAKEROM}"
-f cia
-exefslogo
-o "isle.cia"
-rsf "${CMAKE_SOURCE_DIR}/packaging/3ds/template.rsf"
-major "${CMAKE_PROJECT_VERSION_MAJOR}"
-minor "${CMAKE_PROJECT_VERSION_MINOR}"
-micro 0
-icon "isle.smdh"
-banner "isle.bnr"
-elf "isle.elf"
DEPENDS "${CMAKE_SOURCE_DIR}/packaging/3ds/template.rsf" "isle.smdh" "isle.bnr"
COMMENT "Building CIA executable target isle.cia"
VERBATIM
)
add_custom_target("isle_cia" ALL DEPENDS "isle.cia" isle)
install(FILES "$<TARGET_FILE_DIR:isle>/isle.cia" DESTINATION "${CMAKE_INSTALL_BINDIR}")
endif()
install(FILES "$<TARGET_FILE_DIR:isle>/isle.3dsx" DESTINATION "${CMAKE_INSTALL_BINDIR}")
endif()
if(WINDOWS_STORE)
install(
DIRECTORY
"${CMAKE_BINARY_DIR}/AppPackages/isle/"
DESTINATION "${CMAKE_INSTALL_BINDIR}"
FILES_MATCHING PATTERN "*/Dependencies/x64/Microsoft.VCLibs.x64*.14.00.appx"
PATTERN "*/*.msix"
PATTERN "*/*.msixbundle")
endif()
if(MSVC OR IOS)
set(CPACK_GENERATOR ZIP)
if(IOS)
set(CPACK_ARCHIVE_FILE_EXTENSION ".ipa")
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)
endif()
elseif(APPLE AND NOT IOS)
set(CPACK_GENERATOR DragNDrop)
else()
set(CPACK_GENERATOR TGZ)
endif()
include(CPack)

View File

@ -11,6 +11,10 @@
#include "res/resource.h"
#include <QKeyEvent>
#include <QMessageBox>
#include <QProcess>
#include <SDL3/SDL.h>
#include <cmath>
#include <mxdirectx/legodxinfo.h>
#include <ui_maindialog.h>
@ -52,13 +56,21 @@ CMainDialog::CMainDialog(QWidget* pParent) : QDialog(pParent)
this,
&CMainDialog::OnRadiobuttonTextureHighQuality
);
connect(m_ui->windowedRadioButton, &QRadioButton::toggled, this, &CMainDialog::OnRadioWindowed);
connect(m_ui->fullscreenRadioButton, &QRadioButton::toggled, this, &CMainDialog::OnRadioFullscreen);
connect(m_ui->exFullscreenRadioButton, &QRadioButton::toggled, this, &CMainDialog::OnRadioExclusiveFullscreen);
connect(m_ui->devicesList, &QListWidget::currentRowChanged, this, &CMainDialog::OnList3DevicesSelectionChanged);
connect(m_ui->musicCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckboxMusic);
connect(m_ui->sound3DCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckbox3DSound);
connect(m_ui->joystickCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckboxJoystick);
connect(m_ui->fullscreenCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckboxFullscreen);
connect(m_ui->rumbleCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckboxRumble);
connect(m_ui->textureCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckboxTexture);
connect(m_ui->touchComboBox, &QComboBox::currentIndexChanged, this, &CMainDialog::TouchControlsChanged);
connect(m_ui->transitionTypeComboBox, &QComboBox::currentIndexChanged, this, &CMainDialog::TransitionTypeChanged);
connect(m_ui->exFullResComboBox, &QComboBox::currentIndexChanged, this, &CMainDialog::ExclusiveResolutionChanged);
connect(m_ui->okButton, &QPushButton::clicked, this, &CMainDialog::accept);
connect(m_ui->cancelButton, &QPushButton::clicked, this, &CMainDialog::reject);
connect(m_ui->launchButton, &QPushButton::clicked, this, &CMainDialog::launch);
connect(m_ui->dataPathOpen, &QPushButton::clicked, this, &CMainDialog::SelectDataPathDialog);
connect(m_ui->savePathOpen, &QPushButton::clicked, this, &CMainDialog::SelectSavePathDialog);
@ -66,10 +78,57 @@ CMainDialog::CMainDialog(QWidget* pParent) : QDialog(pParent)
connect(m_ui->dataPath, &QLineEdit::editingFinished, this, &CMainDialog::DataPathEdited);
connect(m_ui->savePath, &QLineEdit::editingFinished, this, &CMainDialog::SavePathEdited);
connect(m_ui->texturePathOpen, &QPushButton::clicked, this, &CMainDialog::SelectTexturePathDialog);
connect(m_ui->texturePath, &QLineEdit::editingFinished, this, &CMainDialog::TexturePathEdited);
connect(m_ui->maxLoDSlider, &QSlider::valueChanged, this, &CMainDialog::MaxLoDChanged);
connect(m_ui->maxLoDSlider, &QSlider::sliderMoved, this, &CMainDialog::MaxLoDChanged);
connect(m_ui->maxActorsSlider, &QSlider::valueChanged, this, &CMainDialog::MaxActorsChanged);
connect(m_ui->maxActorsSlider, &QSlider::sliderMoved, this, &CMainDialog::MaxActorsChanged);
connect(m_ui->msaaSlider, &QSlider::valueChanged, this, &CMainDialog::MSAAChanged);
connect(m_ui->msaaSlider, &QSlider::sliderMoved, this, &CMainDialog::MSAAChanged);
connect(m_ui->AFSlider, &QSlider::valueChanged, this, &CMainDialog::AFChanged);
connect(m_ui->AFSlider, &QSlider::sliderMoved, this, &CMainDialog::AFChanged);
connect(m_ui->aspectRatioComboBox, &QComboBox::currentIndexChanged, this, &CMainDialog::AspectRatioChanged);
connect(m_ui->xResSpinBox, &QSpinBox::valueChanged, this, &CMainDialog::XResChanged);
connect(m_ui->yResSpinBox, &QSpinBox::valueChanged, this, &CMainDialog::YResChanged);
connect(m_ui->framerateSpinBox, &QSpinBox::valueChanged, this, &CMainDialog::FramerateChanged);
layout()->setSizeConstraint(QLayout::SetFixedSize);
if (currentConfigApp->m_ram_quality_limit != 0) {
m_modified = true;
const QString ramError = QString("Insufficient RAM!");
m_ui->sound3DCheckBox->setChecked(false);
m_ui->sound3DCheckBox->setEnabled(false);
m_ui->sound3DCheckBox->setToolTip(ramError);
m_ui->modelQualityHighRadioButton->setEnabled(false);
m_ui->modelQualityHighRadioButton->setToolTip(ramError);
m_ui->modelQualityLowRadioButton->setEnabled(true);
if (currentConfigApp->m_ram_quality_limit == 2) {
m_ui->modelQualityLowRadioButton->setChecked(true);
m_ui->modelQualityMediumRadioButton->setEnabled(false);
m_ui->modelQualityMediumRadioButton->setToolTip(ramError);
m_ui->maxLoDSlider->setMaximum(30);
m_ui->maxActorsSlider->setMaximum(15);
}
else {
m_ui->modelQualityMediumRadioButton->setChecked(true);
m_ui->modelQualityMediumRadioButton->setEnabled(true);
m_ui->maxLoDSlider->setMaximum(40);
m_ui->maxActorsSlider->setMaximum(30);
}
}
else {
m_ui->sound3DCheckBox->setEnabled(true);
m_ui->modelQualityLowRadioButton->setEnabled(true);
m_ui->modelQualityMediumRadioButton->setEnabled(true);
m_ui->modelQualityHighRadioButton->setEnabled(true);
m_ui->maxLoDSlider->setMaximum(60);
m_ui->maxActorsSlider->setMaximum(40);
}
}
CMainDialog::~CMainDialog()
@ -87,7 +146,7 @@ bool CMainDialog::OnInitDialog()
int device_i = 0;
int selected = 0;
char device_name[256];
const list<MxDriver>& driver_list = enumerator->GetDriverList();
const list<MxDriver>& driver_list = enumerator->m_ddInfo;
for (list<MxDriver>::const_iterator it_driver = driver_list.begin(); it_driver != driver_list.end(); it_driver++) {
const MxDriver& driver = *it_driver;
for (list<Direct3DDeviceInfo>::const_iterator it_device = driver.m_devices.begin();
@ -111,7 +170,27 @@ bool CMainDialog::OnInitDialog()
m_ui->devicesList->setCurrentRow(selected);
m_ui->maxLoDSlider->setValue((int) currentConfigApp->m_max_lod * 10);
m_ui->LoDNum->setNum((int) currentConfigApp->m_max_lod * 10);
m_ui->maxActorsSlider->setValue(currentConfigApp->m_max_actors);
m_ui->maxActorsNum->setNum(currentConfigApp->m_max_actors);
m_ui->exFullResComboBox->clear();
int displayModeCount;
displayModes = SDL_GetFullscreenDisplayModes(SDL_GetPrimaryDisplay(), &displayModeCount);
for (int i = 0; i < displayModeCount; ++i) {
QString mode =
QString("%1x%2 @ %3Hz").arg(displayModes[i]->w).arg(displayModes[i]->h).arg(displayModes[i]->refresh_rate);
m_ui->exFullResComboBox->addItem(mode);
if ((displayModes[i]->w == currentConfigApp->m_exf_x_res) &&
(displayModes[i]->h == currentConfigApp->m_exf_y_res) &&
(displayModes[i]->refresh_rate == currentConfigApp->m_exf_fps)) {
m_ui->exFullResComboBox->setCurrentIndex(i);
}
}
UpdateInterface();
return true;
}
@ -155,6 +234,30 @@ void CMainDialog::accept()
QDialog::accept();
}
void CMainDialog::launch()
{
if (m_modified) {
currentConfigApp->WriteRegisterSettings();
}
QDir::setCurrent(QCoreApplication::applicationDirPath());
QMessageBox msgBox = QMessageBox(
QMessageBox::Warning,
QString("Error!"),
QString("Unable to locate isle executable!"),
QMessageBox::Close
);
if (!QProcess::startDetached("./isle")) { // Check in isle-config directory
if (!QProcess::startDetached("isle")) { // Check in $PATH
msgBox.exec();
}
}
QDialog::accept();
}
// FUNCTION: CONFIG 0x00404360
void CMainDialog::UpdateInterface()
{
@ -182,11 +285,46 @@ void CMainDialog::UpdateInterface()
else {
m_ui->textureQualityHighRadioButton->setChecked(true);
}
m_ui->joystickCheckBox->setChecked(currentConfigApp->m_use_joystick);
if (currentConfigApp->m_exclusive_full_screen) {
m_ui->exFullscreenRadioButton->setChecked(true);
m_ui->resolutionBox->setEnabled(false);
m_ui->exFullResContainer->setEnabled(true);
}
else {
m_ui->resolutionBox->setEnabled(true);
m_ui->exFullResContainer->setEnabled(false);
if (currentConfigApp->m_full_screen) {
m_ui->fullscreenRadioButton->setChecked(true);
}
else {
m_ui->windowedRadioButton->setChecked(true);
}
}
m_ui->musicCheckBox->setChecked(currentConfigApp->m_music);
m_ui->fullscreenCheckBox->setChecked(currentConfigApp->m_full_screen);
m_ui->rumbleCheckBox->setChecked(currentConfigApp->m_haptic);
m_ui->touchComboBox->setCurrentIndex(currentConfigApp->m_touch_scheme);
m_ui->transitionTypeComboBox->setCurrentIndex(currentConfigApp->m_transition_type);
m_ui->dataPath->setText(QString::fromStdString(currentConfigApp->m_cd_path));
m_ui->savePath->setText(QString::fromStdString(currentConfigApp->m_save_path));
m_ui->textureCheckBox->setChecked(currentConfigApp->m_texture_load);
m_ui->texturePath->setText(QString::fromStdString(currentConfigApp->m_texture_path));
m_ui->texturePath->setEnabled(currentConfigApp->m_texture_load);
m_ui->texturePathOpen->setEnabled(currentConfigApp->m_texture_load);
m_ui->aspectRatioComboBox->setCurrentIndex(currentConfigApp->m_aspect_ratio);
m_ui->xResSpinBox->setValue(currentConfigApp->m_x_res);
m_ui->yResSpinBox->setValue(currentConfigApp->m_y_res);
m_ui->framerateSpinBox->setValue(static_cast<int>(std::round(1000.0f / currentConfigApp->m_frame_delta)));
m_ui->maxLoDSlider->setValue((int) (currentConfigApp->m_max_lod * 10));
m_ui->LoDNum->setNum(currentConfigApp->m_max_lod);
m_ui->maxActorsSlider->setValue(currentConfigApp->m_max_actors);
m_ui->maxActorsNum->setNum(currentConfigApp->m_max_actors);
m_ui->msaaSlider->setValue(log2(currentConfigApp->m_msaa));
m_ui->msaaNum->setNum(currentConfigApp->m_msaa);
m_ui->AFSlider->setValue(log2(currentConfigApp->m_anisotropy));
m_ui->AFNum->setNum(currentConfigApp->m_anisotropy);
}
// FUNCTION: CONFIG 0x004045e0
@ -246,12 +384,40 @@ void CMainDialog::OnRadiobuttonTextureHighQuality(bool checked)
}
}
// FUNCTION: CONFIG 0x00404790
void CMainDialog::OnCheckboxJoystick(bool checked)
void CMainDialog::OnRadioWindowed(bool checked)
{
currentConfigApp->m_use_joystick = checked;
m_modified = true;
UpdateInterface();
if (checked) {
currentConfigApp->m_full_screen = false;
currentConfigApp->m_exclusive_full_screen = false;
m_ui->resolutionBox->setEnabled(true);
m_ui->exFullResContainer->setEnabled(false);
m_modified = true;
UpdateInterface();
}
}
void CMainDialog::OnRadioFullscreen(bool checked)
{
if (checked) {
currentConfigApp->m_full_screen = true;
currentConfigApp->m_exclusive_full_screen = false;
m_ui->resolutionBox->setEnabled(true);
m_ui->exFullResContainer->setEnabled(false);
m_modified = true;
UpdateInterface();
}
}
void CMainDialog::OnRadioExclusiveFullscreen(bool checked)
{
if (checked) {
currentConfigApp->m_full_screen = true;
currentConfigApp->m_exclusive_full_screen = true;
m_ui->resolutionBox->setEnabled(false);
m_ui->exFullResContainer->setEnabled(true);
m_modified = true;
UpdateInterface();
}
}
// FUNCTION: CONFIG 0x004048c0
@ -262,9 +428,39 @@ void CMainDialog::OnCheckboxMusic(bool checked)
UpdateInterface();
}
void CMainDialog::OnCheckboxFullscreen(bool checked)
void CMainDialog::OnCheckboxRumble(bool checked)
{
currentConfigApp->m_full_screen = checked;
currentConfigApp->m_haptic = checked;
m_modified = true;
UpdateInterface();
}
void CMainDialog::OnCheckboxTexture(bool checked)
{
currentConfigApp->m_texture_load = checked;
m_modified = true;
UpdateInterface();
}
void CMainDialog::TouchControlsChanged(int index)
{
currentConfigApp->m_touch_scheme = index;
m_modified = true;
UpdateInterface();
}
void CMainDialog::TransitionTypeChanged(int index)
{
currentConfigApp->m_transition_type = index;
m_modified = true;
UpdateInterface();
}
void CMainDialog::ExclusiveResolutionChanged(int index)
{
currentConfigApp->m_exf_x_res = displayModes[index]->w;
currentConfigApp->m_exf_y_res = displayModes[index]->h;
currentConfigApp->m_exf_fps = displayModes[index]->refresh_rate;
m_modified = true;
UpdateInterface();
}
@ -341,10 +537,112 @@ void CMainDialog::MaxLoDChanged(int value)
{
currentConfigApp->m_max_lod = static_cast<float>(value) / 10.0f;
m_modified = true;
UpdateInterface();
}
void CMainDialog::MaxActorsChanged(int value)
{
currentConfigApp->m_max_actors = value;
m_modified = true;
UpdateInterface();
}
void CMainDialog::MSAAChanged(int value)
{
currentConfigApp->m_msaa = exp2(value);
m_modified = true;
UpdateInterface();
}
void CMainDialog::AFChanged(int value)
{
currentConfigApp->m_anisotropy = exp2(value);
m_modified = true;
UpdateInterface();
}
void CMainDialog::SelectTexturePathDialog()
{
QString texture_path = QString::fromStdString(currentConfigApp->m_texture_path);
texture_path = QFileDialog::getExistingDirectory(
this,
tr("Open Directory"),
texture_path,
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks
);
QDir texture_dir = QDir(texture_path);
if (texture_dir.exists()) {
currentConfigApp->m_texture_path = texture_dir.absolutePath().toStdString();
m_modified = true;
}
UpdateInterface();
}
void CMainDialog::TexturePathEdited()
{
QDir texture_dir = QDir(m_ui->texturePath->text());
if (texture_dir.exists()) {
currentConfigApp->m_texture_path = texture_dir.absolutePath().toStdString();
m_modified = true;
}
UpdateInterface();
}
void CMainDialog::AspectRatioChanged(int index)
{
currentConfigApp->m_aspect_ratio = index;
EnsureAspectRatio();
m_modified = true;
UpdateInterface();
}
void CMainDialog::XResChanged(int i)
{
currentConfigApp->m_x_res = i;
m_modified = true;
UpdateInterface();
}
void CMainDialog::YResChanged(int i)
{
currentConfigApp->m_y_res = i;
EnsureAspectRatio();
m_modified = true;
UpdateInterface();
}
void CMainDialog::EnsureAspectRatio()
{
if (currentConfigApp->m_aspect_ratio != 3) {
m_ui->xResSpinBox->setReadOnly(true);
switch (currentConfigApp->m_aspect_ratio) {
case 0: {
float standardAspect = 4.0f / 3.0f;
currentConfigApp->m_x_res = static_cast<int>(std::round((currentConfigApp->m_y_res) * standardAspect));
break;
}
case 1: {
float wideAspect = 16.0f / 9.0f;
currentConfigApp->m_x_res = static_cast<int>(std::round((currentConfigApp->m_y_res) * wideAspect));
break;
}
case 2: {
currentConfigApp->m_x_res = currentConfigApp->m_y_res;
break;
}
}
}
else {
m_ui->xResSpinBox->setReadOnly(false);
}
}
void CMainDialog::FramerateChanged(int i)
{
currentConfigApp->m_frame_delta = (1000.0f / static_cast<float>(i));
m_modified = true;
UpdateInterface();
}

View File

@ -7,6 +7,7 @@
#include <QDialog>
#include <QFileDialog>
#include <SDL3/SDL.h>
namespace Ui
{
@ -29,6 +30,7 @@ class CMainDialog : public QDialog {
bool m_modified = false;
bool m_advanced = false;
Ui::MainDialog* m_ui = nullptr;
SDL_DisplayMode** displayModes;
void keyReleaseEvent(QKeyEvent* event) override;
bool OnInitDialog();
@ -40,17 +42,33 @@ private slots:
void OnRadiobuttonModelHighQuality(bool checked);
void OnRadiobuttonTextureLowQuality(bool checked);
void OnRadiobuttonTextureHighQuality(bool checked);
void OnCheckboxJoystick(bool checked);
void OnRadioWindowed(bool checked);
void OnRadioFullscreen(bool checked);
void OnRadioExclusiveFullscreen(bool checked);
void OnCheckboxMusic(bool checked);
void OnCheckboxFullscreen(bool checked);
void OnCheckboxRumble(bool checked);
void OnCheckboxTexture(bool checked);
void TouchControlsChanged(int index);
void TransitionTypeChanged(int index);
void ExclusiveResolutionChanged(int index);
void accept() override;
void reject() override;
void launch();
void SelectDataPathDialog();
void SelectSavePathDialog();
void DataPathEdited();
void SavePathEdited();
void MaxLoDChanged(int value);
void MaxActorsChanged(int value);
void MSAAChanged(int value);
void AFChanged(int value);
void SelectTexturePathDialog();
void TexturePathEdited();
void XResChanged(int i);
void YResChanged(int i);
void AspectRatioChanged(int index);
void EnsureAspectRatio();
void FramerateChanged(int i);
};
// SYNTHETIC: CONFIG 0x00403de0

View File

@ -56,12 +56,27 @@ bool CConfigApp::InitInstance()
return false;
}
m_device_enumerator = new LegoDeviceEnumerate;
if (m_device_enumerator->DoEnumerate()) {
SDL_Window* window = SDL_CreateWindow("Test window", 640, 480, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL);
HWND hWnd;
#ifdef MINIWIN
hWnd = reinterpret_cast<HWND>(window);
#else
hWnd = (HWND) SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
#endif
if (m_device_enumerator->DoEnumerate(hWnd)) {
return FALSE;
}
SDL_DestroyWindow(window);
m_aspect_ratio = 0;
m_exf_x_res = m_x_res = 640;
m_exf_y_res = m_y_res = 480;
m_exf_fps = 60.00f;
m_frame_delta = 10.0f;
m_driver = NULL;
m_device = NULL;
m_full_screen = TRUE;
m_exclusive_full_screen = FALSE;
m_transition_type = 3; // 3: Mosaic
m_wide_view_angle = TRUE;
m_use_joystick = TRUE;
m_music = TRUE;
@ -69,8 +84,15 @@ bool CConfigApp::InitInstance()
m_3d_video_ram = FALSE;
m_joystick_index = -1;
m_display_bit_depth = 16;
m_msaa = 1;
m_anisotropy = 1;
m_haptic = TRUE;
m_touch_scheme = 2;
m_texture_load = TRUE;
m_texture_path = "/textures/";
int totalRamMiB = SDL_GetSystemRAM();
if (totalRamMiB < 12) {
m_ram_quality_limit = 2;
m_3d_sound = FALSE;
m_model_quality = 0;
m_texture_quality = 1;
@ -78,6 +100,7 @@ bool CConfigApp::InitInstance()
m_max_actors = 5;
}
else if (totalRamMiB < 20) {
m_ram_quality_limit = 1;
m_3d_sound = FALSE;
m_model_quality = 1;
m_texture_quality = 1;
@ -85,6 +108,7 @@ bool CConfigApp::InitInstance()
m_max_actors = 10;
}
else {
m_ram_quality_limit = 0;
m_model_quality = 2;
m_3d_sound = TRUE;
m_texture_quality = 1;
@ -113,7 +137,7 @@ D3DCOLORMODEL CConfigApp::GetHardwareDeviceColorModel() const
// FUNCTION: CONFIG 0x00403410
bool CConfigApp::IsPrimaryDriver() const
{
return m_driver == &m_device_enumerator->GetDriverList().front();
return m_driver == &m_device_enumerator->m_ddInfo.front();
}
// FUNCTION: CONFIG 0x00403430
@ -145,6 +169,9 @@ bool CConfigApp::ReadRegisterSettings()
m_display_bit_depth = iniparser_getint(dict, "isle:Display Bit Depth", -1);
m_flip_surfaces = iniparser_getboolean(dict, "isle:Flip Surfaces", m_flip_surfaces);
m_full_screen = iniparser_getboolean(dict, "isle:Full Screen", m_full_screen);
m_exclusive_full_screen = iniparser_getboolean(dict, "isle:Exclusive Full Screen", m_exclusive_full_screen);
m_transition_type = iniparser_getint(dict, "isle:Transition Type", m_transition_type);
m_touch_scheme = iniparser_getint(dict, "isle:Touch Scheme", m_touch_scheme);
m_3d_video_ram = iniparser_getboolean(dict, "isle:Back Buffers in Video RAM", m_3d_video_ram);
m_wide_view_angle = iniparser_getboolean(dict, "isle:Wide View Angle", m_wide_view_angle);
m_3d_sound = iniparser_getboolean(dict, "isle:3DSound", m_3d_sound);
@ -152,10 +179,22 @@ bool CConfigApp::ReadRegisterSettings()
m_model_quality = iniparser_getint(dict, "isle:Island Quality", m_model_quality);
m_texture_quality = iniparser_getint(dict, "isle:Island Texture", m_texture_quality);
m_use_joystick = iniparser_getboolean(dict, "isle:UseJoystick", m_use_joystick);
m_haptic = iniparser_getboolean(dict, "isle:Haptic", m_haptic);
m_music = iniparser_getboolean(dict, "isle:Music", m_music);
m_joystick_index = iniparser_getint(dict, "isle:JoystickIndex", m_joystick_index);
m_max_lod = iniparser_getdouble(dict, "isle:Max LOD", m_max_lod);
m_max_actors = iniparser_getint(dict, "isle:Max Allowed Extras", m_max_actors);
m_msaa = iniparser_getint(dict, "isle:MSAA", m_msaa);
m_anisotropy = iniparser_getint(dict, "isle:Anisotropic", m_anisotropy);
m_texture_load = iniparser_getboolean(dict, "extensions:texture loader", m_texture_load);
m_texture_path = iniparser_getstring(dict, "texture loader:texture path", m_texture_path.c_str());
m_aspect_ratio = iniparser_getint(dict, "isle:Aspect Ratio", m_aspect_ratio);
m_x_res = iniparser_getint(dict, "isle:Horizontal Resolution", m_x_res);
m_y_res = iniparser_getint(dict, "isle:Vertical Resolution", m_y_res);
m_exf_x_res = iniparser_getint(dict, "isle:Exclusive X Resolution", m_exf_x_res);
m_exf_y_res = iniparser_getint(dict, "isle:Exclusive Y Resolution", m_exf_y_res);
m_exf_fps = iniparser_getdouble(dict, "isle:Exclusive Framerate", m_exf_fps);
m_frame_delta = iniparser_getdouble(dict, "isle:Frame Delta", m_frame_delta);
iniparser_freedict(dict);
return true;
}
@ -212,7 +251,7 @@ bool CConfigApp::ValidateSettings()
is_modified = TRUE;
}
if (m_max_lod < 0.0f || m_max_lod > 5.0f) {
if (m_max_lod < 0.0f || m_max_lod > 6.0f) {
m_max_lod = 3.5f;
is_modified = TRUE;
}
@ -220,6 +259,42 @@ bool CConfigApp::ValidateSettings()
m_max_actors = 20;
is_modified = TRUE;
}
if (!m_use_joystick) {
m_use_joystick = true;
is_modified = TRUE;
}
if (m_touch_scheme < 0 || m_touch_scheme > 2) {
m_touch_scheme = 2;
is_modified = TRUE;
}
if (m_exclusive_full_screen && !m_full_screen) {
m_full_screen = TRUE;
is_modified = TRUE;
}
if (!(m_msaa & (m_msaa - 1))) { // Check if MSAA is power of 2 (1, 2, 4, 8, etc)
m_msaa = exp2(round(log2(m_msaa))); // Closest power of 2
is_modified = TRUE;
}
if (m_msaa > 16) {
m_msaa = 16;
is_modified = TRUE;
}
else if (m_msaa < 1) {
m_msaa = 1;
is_modified = TRUE;
}
if (!(m_anisotropy & (m_anisotropy - 1))) { // Check if anisotropy is power of 2 (1, 2, 4, 8, etc)
m_anisotropy = exp2(round(log2(m_anisotropy))); // Closest power of 2
is_modified = TRUE;
}
if (m_anisotropy > 16) {
m_anisotropy = 16;
is_modified = TRUE;
}
else if (m_anisotropy < 1) {
m_anisotropy = 1;
is_modified = TRUE;
}
return is_modified;
}
@ -288,6 +363,8 @@ void CConfigApp::WriteRegisterSettings() const
dictionary* dict = dictionary_new(0);
iniparser_set(dict, "isle", NULL);
iniparser_set(dict, "extensions", NULL);
iniparser_set(dict, "texture loader", NULL);
if (m_device_enumerator->FormatDeviceName(buffer, m_driver, m_device) >= 0) {
iniparser_set(dict, "isle:3D Device ID", buffer);
}
@ -296,17 +373,27 @@ void CConfigApp::WriteRegisterSettings() const
iniparser_set(dict, "isle:savepath", m_save_path.c_str());
SetIniInt(dict, "isle:Display Bit Depth", m_display_bit_depth);
SetIniInt(dict, "isle:MSAA", m_msaa);
SetIniInt(dict, "isle:Anisotropic", m_anisotropy);
SetIniBool(dict, "isle:Flip Surfaces", m_flip_surfaces);
SetIniBool(dict, "isle:Full Screen", m_full_screen);
SetIniBool(dict, "isle:Exclusive Full Screen", m_exclusive_full_screen);
SetIniBool(dict, "isle:Wide View Angle", m_wide_view_angle);
SetIniInt(dict, "isle:Transition Type", m_transition_type);
SetIniInt(dict, "isle:Touch Scheme", m_touch_scheme);
SetIniBool(dict, "isle:3DSound", m_3d_sound);
SetIniBool(dict, "isle:Music", m_music);
SetIniBool(dict, "isle:Haptic", m_haptic);
SetIniBool(dict, "isle:UseJoystick", m_use_joystick);
SetIniInt(dict, "isle:JoystickIndex", m_joystick_index);
SetIniBool(dict, "isle:Draw Cursor", m_draw_cursor);
SetIniBool(dict, "extensions:texture loader", m_texture_load);
iniparser_set(dict, "texture loader:texture path", m_texture_path.c_str());
SetIniBool(dict, "isle:Back Buffers in Video RAM", m_3d_video_ram);
SetIniInt(dict, "isle:Island Quality", m_model_quality);
@ -315,6 +402,14 @@ void CConfigApp::WriteRegisterSettings() const
iniparser_set(dict, "isle:Max LOD", std::to_string(m_max_lod).c_str());
SetIniInt(dict, "isle:Max Allowed Extras", m_max_actors);
SetIniInt(dict, "isle:Aspect Ratio", m_aspect_ratio);
SetIniInt(dict, "isle:Horizontal Resolution", m_x_res);
SetIniInt(dict, "isle:Vertical Resolution", m_y_res);
SetIniInt(dict, "isle:Exclusive X Resolution", m_exf_x_res);
SetIniInt(dict, "isle:Exclusive Y Resolution", m_exf_y_res);
iniparser_set(dict, "isle:Exclusive Framerate", std::to_string(m_exf_fps).c_str());
iniparser_set(dict, "isle:Frame Delta", std::to_string(m_frame_delta).c_str());
#undef SetIniBool
#undef SetIniInt

View File

@ -59,27 +59,43 @@ class CConfigApp {
// DECLARE_MESSAGE_MAP()
public:
int m_aspect_ratio;
int m_x_res;
int m_y_res;
int m_exf_x_res;
int m_exf_y_res;
float m_exf_fps;
float m_frame_delta;
LegoDeviceEnumerate* m_device_enumerator;
MxDriver* m_driver;
Direct3DDeviceInfo* m_device;
int m_display_bit_depth;
int m_msaa;
int m_anisotropy;
bool m_flip_surfaces;
bool m_full_screen;
bool m_exclusive_full_screen;
int m_transition_type;
bool m_3d_video_ram;
bool m_wide_view_angle;
bool m_3d_sound;
bool m_draw_cursor;
bool m_use_joystick;
bool m_haptic;
int m_joystick_index;
int m_model_quality;
int m_texture_quality;
bool m_music;
bool m_texture_load;
std::string m_texture_path;
std::string m_iniPath;
std::string m_base_path;
std::string m_cd_path;
std::string m_save_path;
float m_max_lod;
int m_max_actors;
int m_touch_scheme;
int m_ram_quality_limit;
};
extern CConfigApp g_theApp;

File diff suppressed because it is too large Load Diff

View File

@ -6,12 +6,7 @@ If you feel fit to contribute, feel free to create a pull request! Someone will
Please keep your pull requests small and understandable; you may be able to shoot ahead and make a lot of progress in a short amount of time, but this is a collaborative project, so you must allow others to catch up and follow along. Large pull requests become significantly more unwieldy to review, and as such make it exponentially more likely for a mistake or error to go undetected. They also make it harder to merge other pull requests because the more files you modify, the more likely it is for a merge conflict to occur. A general guideline is to keep submissions limited to one class at a time. Sometimes two or more classes may be too interlinked for this to be feasible, so this is not a hard rule, however if your PR is starting to modify more than 10 or so files, it's probably getting too big.
This repository has a single goal: achieving platform independence. Consequently, contributions that do not support this goal cannot be accepted. Examples of out-of-scope contributions include:
* Improving code efficiency or performance without addressing platform compatibility
* Replacing `MxString` with `std::string`
* Fixing gameplay bugs
* Enhancing audio or video quality
This repository has achieving platform independence as its primary goal, with limited support for light modding (using [`extensions`](/extensions)). Any changes that modify code in `LEGO1` are unlikely to be accepted, unless they directly serve to increase platform compatibility.
If in doubt, please contact us in the [Matrix chatroom](https://matrix.to/#/#isledecomp:matrix.org).

30
ISLE/3ds/apthooks.cpp Normal file
View File

@ -0,0 +1,30 @@
#include "apthooks.h"
#include "legomain.h"
#include "misc.h"
aptHookCookie g_aptCookie;
void N3DS_AptHookCallback(APT_HookType hookType, void* param)
{
switch (hookType) {
case APTHOOK_ONSLEEP:
case APTHOOK_ONSUSPEND:
Lego()->Pause();
break;
case APTHOOK_ONWAKEUP:
case APTHOOK_ONRESTORE:
Lego()->Resume();
break;
case APTHOOK_ONEXIT:
Lego()->CloseMainWindow();
break;
default:
break;
}
}
void N3DS_SetupAptHooks()
{
aptHook(&g_aptCookie, N3DS_AptHookCallback, NULL);
}

9
ISLE/3ds/apthooks.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef N3DS_APTHOOKS_H
#define N3DS_APTHOOKS_H
#include <3ds.h>
void N3DS_AptHookCallback(APT_HookType hookType, void* param);
void N3DS_SetupAptHooks();
#endif // N3DS_APTHOOKS_H

19
ISLE/3ds/config.cpp Normal file
View File

@ -0,0 +1,19 @@
#include "config.h"
#include <SDL3/SDL_log.h>
#include <iniparser.h>
void N3DS_SetupDefaultConfigOverrides(dictionary* p_dictionary)
{
SDL_Log("Overriding default config for 3DS");
// We are currently not bundling the assets into romfs.
// User must place assets in sdmc:/3ds/isle where
// sdmc:/3ds/isle/LEGO/SCRIPTS/CREDITS.si exists, for example.
iniparser_set(p_dictionary, "isle:diskpath", "sdmc:/3ds/isle/LEGO/disk");
iniparser_set(p_dictionary, "isle:cdpath", "sdmc:/3ds/isle");
// TODO: Save path: can we use libctru FS save data functions? Would be neat, especially for CIA install
// Extra / at the end causes some issues
iniparser_set(p_dictionary, "isle:savepath", "sdmc:/3ds/isle");
}

8
ISLE/3ds/config.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef N3DS_CONFIG_H
#define N3DS_CONFIG_H
#include "dictionary.h"
void N3DS_SetupDefaultConfigOverrides(dictionary* p_dictionary);
#endif // N3DS_CONFIG_H

View File

@ -0,0 +1,27 @@
#include "config.h"
#include "filesystem.h"
#include "window.h"
#include <SDL3/SDL_log.h>
#include <emscripten.h>
#include <iniparser.h>
void Emscripten_SetupDefaultConfigOverrides(dictionary* p_dictionary)
{
SDL_Log("Overriding default config for Emscripten");
iniparser_set(p_dictionary, "isle:diskpath", Emscripten_bundledPath);
iniparser_set(p_dictionary, "isle:cdpath", Emscripten_streamPath);
iniparser_set(p_dictionary, "isle:savepath", Emscripten_savePath);
iniparser_set(p_dictionary, "isle:Full Screen", "false");
iniparser_set(p_dictionary, "isle:Flip Surfaces", "true");
// Emscripten-only for now
Emscripten_SetScaleAspect(iniparser_getboolean(p_dictionary, "isle:Original Aspect Ratio", true));
Emscripten_SetOriginalResolution(iniparser_getboolean(p_dictionary, "isle:Original Resolution", true));
// clang-format off
MAIN_THREAD_EM_ASM({JSEvents.fullscreenEnabled = function() { return false; }});
// clang-format on
}

8
ISLE/emscripten/config.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef EMSCRIPTEN_CONFIG_H
#define EMSCRIPTEN_CONFIG_H
#include "dictionary.h"
void Emscripten_SetupDefaultConfigOverrides(dictionary* p_dictionary);
#endif // EMSCRIPTEN_CONFIG_H

View File

@ -1,5 +1,43 @@
diff --git a/src/lib/libhtml5.js b/src/lib/libhtml5.js
index da08765e7..24e5da22e 100644
--- a/src/lib/libhtml5.js
+++ b/src/lib/libhtml5.js
@@ -1182,6 +1182,7 @@ var LibraryHTML5 = {
$registerRestoreOldStyle__deps: ['$getCanvasElementSize', '$setCanvasElementSize', '$currentFullscreenStrategy'],
$registerRestoreOldStyle: (canvas) => {
+ return;
var canvasSize = getCanvasElementSize(canvas);
var oldWidth = canvasSize[0];
var oldHeight = canvasSize[1];
@@ -1326,9 +1327,9 @@ var LibraryHTML5 = {
var topMargin;
if (inAspectRatioFixedFullscreenMode) {
- if (w*y < x*h) h = (w * y / x) | 0;
- else if (w*y > x*h) w = (h * x / y) | 0;
- topMargin = ((screenHeight - h) / 2) | 0;
+ if (w*y < x*h) h = Math.round(w * y / x) | 0;
+ else if (w*y > x*h) w = Math.round(h * x / y) | 0;
+ topMargin = Math.round((screenHeight - h) / 2) | 0;
}
if (inPixelPerfectFullscreenMode) {
diff --git a/src/lib/libpthread.js b/src/lib/libpthread.js
index 6d979627e..97e3f8684 100644
--- a/src/lib/libpthread.js
+++ b/src/lib/libpthread.js
@@ -697,7 +697,7 @@ var LibraryPThread = {
{
transferredCanvasNames = UTF8ToString(transferredCanvasNames).trim();
}
- transferredCanvasNames = transferredCanvasNames ? transferredCanvasNames.split(',') : [];
+ transferredCanvasNames = transferredCanvasNames && !Module['disableOffscreenCanvases'] ? transferredCanvasNames.split(',') : [];
#if GL_DEBUG
dbg(`pthread_create: transferredCanvasNames="${transferredCanvasNames}"`);
#endif
diff --git a/src/lib/libwasmfs_fetch.js b/src/lib/libwasmfs_fetch.js
index e8c9f7e21..1c0eea957 100644
index e8c9f7e21..caf1971d2 100644
--- a/src/lib/libwasmfs_fetch.js
+++ b/src/lib/libwasmfs_fetch.js
@@ -38,36 +38,7 @@ addToLibrary({
@ -89,7 +127,21 @@ index e8c9f7e21..1c0eea957 100644
return Promise.resolve();
}
@@ -164,6 +156,21 @@ addToLibrary({
@@ -156,14 +148,31 @@ addToLibrary({
return readLength;
},
getSize: async (file) => {
- try {
- await getFileRange(file, 0, 0);
- } catch (failedResponse) {
- return 0;
+ if (!(file in wasmFS$JSMemoryRanges)) {
+ try {
+ await getFileRange(file, undefined, undefined);
+ } catch (failedResponse) {
+ return 0;
+ }
}
return wasmFS$JSMemoryRanges[file].size;
},
};
@ -112,3 +164,27 @@ index e8c9f7e21..1c0eea957 100644
},
-
});
diff --git a/src/preamble.js b/src/preamble.js
index 572694517..44e65c823 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -1062,3 +1062,19 @@ function getCompilerSetting(name) {
// dynamic linker as symbols are loaded.
var asyncifyStubs = {};
#endif
+
+if (typeof document !== "undefined") {
+ (async () => {
+ try {
+ await navigator.storage.getDirectory();
+ Module["disableOpfs"] = false;
+ } catch (e) {
+ Module["disableOpfs"] = true;
+ }
+ console.log("disableOpfs: " + Module["disableOpfs"]);
+ })();
+
+ Module["disableOffscreenCanvases"] ||= !document.createElement('canvas').getContext('webgl');
+ console.log("disableOffscreenCanvases: " + Module["disableOffscreenCanvases"]);
+}
+

View File

@ -36,3 +36,11 @@ void Emscripten_SendPresenterProgress(MxDSAction* p_action, MxPresenter::TickleS
Emscripten_SendEvent("presenterProgress", buf);
}
void Emscripten_SendExtensionProgress(const char* p_extension, MxU32 p_progress)
{
char buf[128];
SDL_snprintf(buf, sizeof(buf), "{\"name\": \"%s\", \"progress\": %d}", p_extension, p_progress);
Emscripten_SendEvent("extensionProgress", buf);
}

View File

@ -4,5 +4,6 @@
#include "mxpresenter.h"
void Emscripten_SendPresenterProgress(MxDSAction* p_action, MxPresenter::TickleState p_tickleState);
void Emscripten_SendExtensionProgress(const char* p_extension, MxU32 p_progress);
#endif // EMSCRIPTEN_EVENTS_H

View File

@ -1,22 +1,32 @@
#include "filesystem.h"
#include "events.h"
#include "extensions/textureloader.h"
#include "legogamestate.h"
#include "misc.h"
#include "mxomni.h"
#include <SDL3/SDL_filesystem.h>
#include <SDL3/SDL_log.h>
#include <emscripten.h>
#include <emscripten/wasmfs.h>
static backend_t opfs = nullptr;
static backend_t fetchfs = nullptr;
extern const char* g_files[46];
extern const char* g_textures[120];
void Emscripten_SetupConfig(const char* p_iniConfig)
bool Emscripten_OPFSDisabled()
{
if (!p_iniConfig || !*p_iniConfig) {
return;
return MAIN_THREAD_EM_ASM_INT({return !!Module["disableOpfs"]});
}
bool Emscripten_SetupConfig(const char* p_iniConfig)
{
if (Emscripten_OPFSDisabled()) {
SDL_Log("OPFS is disabled; ignoring .ini path");
return false;
}
opfs = wasmfs_create_opfs_backend();
@ -28,11 +38,13 @@ void Emscripten_SetupConfig(const char* p_iniConfig)
wasmfs_create_directory(iniConfig.GetData(), 0644, opfs);
*parse = '/';
}
return true;
}
void Emscripten_SetupFilesystem()
{
fetchfs = wasmfs_create_fetch_backend((MxString(Emscripten_streamHost) + MxString("/LEGO")).GetData(), 512 * 1024);
fetchfs = wasmfs_create_fetch_backend((MxString(Emscripten_streamHost) + "/LEGO").GetData(), 512 * 1024);
wasmfs_create_directory("/LEGO", 0644, fetchfs);
wasmfs_create_directory("/LEGO/Scripts", 0644, fetchfs);
@ -62,11 +74,42 @@ void Emscripten_SetupFilesystem()
}
};
const auto preloadFile = [](const char* p_path) -> bool {
size_t length = 0;
void* data = SDL_LoadFile(p_path, &length);
if (data) {
SDL_free(data);
}
return length > 0;
};
for (const char* file : g_files) {
registerFile(file);
}
if (GameState()->GetSavePath() && *GameState()->GetSavePath()) {
#ifdef EXTENSIONS
if (Extensions::TextureLoader::enabled) {
MxString directory =
MxString("/LEGO") + Extensions::TextureLoader::options["texture loader:texture path"].c_str();
Extensions::TextureLoader::options["texture loader:texture path"] = directory.GetData();
wasmfs_create_directory(directory.GetData(), 0644, fetchfs);
MxU32 i = 0;
Emscripten_SendExtensionProgress("HD Textures", 0);
for (const char* file : g_textures) {
MxString path = directory + "/" + file + ".bmp";
registerFile(path.GetData());
if (!preloadFile(path.GetData())) {
Extensions::TextureLoader::excludedFiles.emplace_back(file);
}
Emscripten_SendExtensionProgress("HD Textures", (++i * 100) / sizeOfArray(g_textures));
}
}
#endif
if (GameState()->GetSavePath() && *GameState()->GetSavePath() && !Emscripten_OPFSDisabled()) {
if (!opfs) {
opfs = wasmfs_create_opfs_backend();
}

View File

@ -10,7 +10,7 @@ inline static const char* Emscripten_savePath = "/save";
inline static const char* Emscripten_streamPath = "/";
inline static const char* Emscripten_streamHost = ISLE_EMSCRIPTEN_HOST;
void Emscripten_SetupConfig(const char* p_iniConfig);
bool Emscripten_SetupConfig(const char* p_iniConfig);
void Emscripten_SetupFilesystem();
#endif // EMSCRIPTEN_FILESYSTEM_H

View File

@ -0,0 +1,55 @@
#include "haptic.h"
#include "compat.h"
#include "lego/sources/misc/legoutil.h"
#include "legoinputmanager.h"
#include "misc.h"
#include <emscripten/html5.h>
void Emscripten_HandleRumbleEvent(float p_lowFrequencyRumble, float p_highFrequencyRumble, MxU32 p_milliseconds)
{
std::visit(
overloaded{
[](LegoInputManager::SDL_KeyboardID_v p_id) {},
[](LegoInputManager::SDL_MouseID_v p_id) {},
[p_lowFrequencyRumble, p_highFrequencyRumble, p_milliseconds](LegoInputManager::SDL_JoystickID_v p_id) {
const char* name = SDL_GetJoystickNameForID((SDL_JoystickID) p_id);
if (name) {
MAIN_THREAD_EM_ASM(
{
const name = UTF8ToString($0);
const gamepads = navigator.getGamepads();
for (const gamepad of gamepads) {
if (gamepad && gamepad.connected && gamepad.id == name && gamepad.vibrationActuator) {
gamepad.vibrationActuator.playEffect("dual-rumble", {
startDelay : 0,
weakMagnitude : $1,
strongMagnitude : $2,
duration : $3,
});
break;
}
}
},
name,
SDL_clamp(p_lowFrequencyRumble, 0, 1),
SDL_clamp(p_highFrequencyRumble, 0, 1),
p_milliseconds
);
}
},
[p_milliseconds](LegoInputManager::SDL_TouchID_v p_id) {
MAIN_THREAD_EM_ASM(
{
if (navigator.vibrate) {
navigator.vibrate($0);
}
},
p_milliseconds
);
}
},
InputManager()->GetLastInputMethod()
);
}

8
ISLE/emscripten/haptic.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef EMSCRIPTEN_HAPTIC_H
#define EMSCRIPTEN_HAPTIC_H
#include "mxtypes.h"
void Emscripten_HandleRumbleEvent(float p_lowFrequencyRumble, float p_highFrequencyRumble, MxU32 p_milliseconds);
#endif // EMSCRIPTEN_HAPTIC_H

View File

@ -0,0 +1,99 @@
#include "window.h"
#include "mxtypes.h"
#include <SDL3/SDL_log.h>
#include <algorithm>
#include <emscripten/html5.h>
double g_fullWidth;
double g_fullHeight;
bool g_scaleAspect = true;
bool g_originalResolution = true;
extern MxS32 g_targetWidth;
extern MxS32 g_targetHeight;
void Emscripten_SetupWindow(SDL_Window* p_window)
{
EmscriptenFullscreenStrategy strategy;
strategy.scaleMode = g_scaleAspect ? EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT : EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH;
strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF;
strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
strategy.canvasResizedCallbackUserData = p_window;
strategy.canvasResizedCallback = [](int eventType, const void* reserved, void* userData) -> bool {
int width, height;
emscripten_get_canvas_element_size("canvas", &width, &height);
emscripten_get_element_css_size("#canvas", &g_fullWidth, &g_fullHeight);
if (g_originalResolution) {
SDL_SetWindowSize((SDL_Window*) userData, g_targetWidth, g_targetHeight);
}
else {
SDL_SetWindowSize((SDL_Window*) userData, width, height);
}
SDL_Log(
"Emscripten: window size %dx%d, canvas size %dx%d, scale aspect %s, original resolution %s",
width,
height,
(int) g_fullWidth,
(int) g_fullHeight,
g_scaleAspect ? "TRUE" : "FALSE",
g_originalResolution ? "TRUE" : "FALSE"
);
return true;
};
emscripten_enter_soft_fullscreen("canvas", &strategy);
}
void Emscripten_SetScaleAspect(bool p_scaleAspect)
{
g_scaleAspect = p_scaleAspect;
}
void Emscripten_SetOriginalResolution(bool p_originalResolution)
{
g_originalResolution = p_originalResolution;
}
void Emscripten_ConvertEventToRenderCoordinates(SDL_Event* event)
{
if (!g_scaleAspect) {
return;
}
switch (event->type) {
case SDL_EVENT_MOUSE_MOTION: {
const float scale = std::min(g_fullWidth / g_targetWidth, g_fullHeight / g_targetHeight);
const float widthRatio = (g_targetWidth * scale) / g_fullWidth;
const float heightRatio = (g_targetHeight * scale) / g_fullHeight;
event->motion.x = (event->motion.x - (g_targetWidth * (1.0f - widthRatio) / 2.0f)) / widthRatio;
event->motion.y = (event->motion.y - (g_targetHeight * (1.0f - heightRatio) / 2.0f)) / heightRatio;
break;
}
case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP: {
const float scale = std::min(g_fullWidth / g_targetWidth, g_fullHeight / g_targetHeight);
const float widthRatio = (g_targetWidth * scale) / g_fullWidth;
const float heightRatio = (g_targetHeight * scale) / g_fullHeight;
event->button.x = (event->button.x - (g_targetWidth * (1.0f - widthRatio) / 2.0f)) / widthRatio;
event->button.y = (event->button.y - (g_targetHeight * (1.0f - heightRatio) / 2.0f)) / heightRatio;
break;
}
case SDL_EVENT_FINGER_MOTION:
case SDL_EVENT_FINGER_DOWN:
case SDL_EVENT_FINGER_UP:
case SDL_EVENT_FINGER_CANCELED: {
const float scale = std::min(g_fullWidth / g_targetWidth, g_fullHeight / g_targetHeight);
const float widthRatio = (g_targetWidth * scale) / g_fullWidth;
const float heightRatio = (g_targetHeight * scale) / g_fullHeight;
event->tfinger.x = (event->tfinger.x * g_targetWidth - (g_targetWidth * (1.0f - widthRatio) / 2.0f)) /
widthRatio / g_targetWidth;
event->tfinger.y = (event->tfinger.y * g_targetHeight - (g_targetHeight * (1.0f - heightRatio) / 2.0f)) /
heightRatio / g_targetHeight;
break;
}
}
}

11
ISLE/emscripten/window.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef EMSCRIPTEN_WINDOW_H
#define EMSCRIPTEN_WINDOW_H
#include <SDL3/SDL.h>
void Emscripten_SetupWindow(SDL_Window* p_window);
void Emscripten_SetScaleAspect(bool p_scaleAspect);
void Emscripten_SetOriginalResolution(bool p_originalResolution);
void Emscripten_ConvertEventToRenderCoordinates(SDL_Event* event);
#endif // EMSCRIPTEN_WINDOW_H

25
ISLE/ios/config.cpp Normal file
View File

@ -0,0 +1,25 @@
#include "config.h"
#include <SDL3/SDL_filesystem.h>
#include <SDL3/SDL_log.h>
#include <iniparser.h>
void IOS_SetupDefaultConfigOverrides(dictionary* p_dictionary)
{
SDL_Log("Overriding default config for iOS");
// Use DevelopmentFiles path for disk and cd paths
// It's good to use that path since user can easily
// connect through SMB and copy the files
const char* documentFolder = SDL_GetUserFolder(SDL_FOLDER_DOCUMENTS);
char* diskPath = new char[strlen(documentFolder) + strlen("isle") + 1]();
strcpy(diskPath, documentFolder);
strcat(diskPath, "isle");
if (!SDL_GetPathInfo(diskPath, NULL)) {
SDL_CreateDirectory(diskPath);
}
iniparser_set(p_dictionary, "isle:diskpath", diskPath);
iniparser_set(p_dictionary, "isle:cdpath", diskPath);
}

8
ISLE/ios/config.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef IOS_CONFIG_H
#define IOS_CONFIG_H
#include "dictionary.h"
void IOS_SetupDefaultConfigOverrides(dictionary* p_dictionary);
#endif // IOS_CONFIG_H

View File

@ -28,13 +28,19 @@
#include "mxtransitionmanager.h"
#include "mxutilities.h"
#include "mxvariabletable.h"
#include "res/arrow_bmp.h"
#include "res/busy_bmp.h"
#include "res/isle_bmp.h"
#include "res/no_bmp.h"
#include "res/resource.h"
#include "roi/legoroi.h"
#include "tgl/d3drm/impl.h"
#include "viewmanager/viewmanager.h"
#include <array>
#include <extensions/extensions.h>
#include <miniwin/miniwindevice.h>
#include <vec.h>
#define SDL_MAIN_USE_CALLBACKS
#include <SDL3/SDL.h>
@ -45,9 +51,25 @@
#include <time.h>
#ifdef __EMSCRIPTEN__
#include "emscripten/config.h"
#include "emscripten/events.h"
#include "emscripten/filesystem.h"
#include "emscripten/haptic.h"
#include "emscripten/messagebox.h"
#include "emscripten/window.h"
#endif
#ifdef __3DS__
#include "3ds/apthooks.h"
#include "3ds/config.h"
#endif
#ifdef WINDOWS_STORE
#include "xbox_one_series/config.h"
#endif
#ifdef IOS
#include "ios/config.h"
#endif
DECOMP_SIZE_ASSERT(IsleApp, 0x8c)
@ -82,6 +104,17 @@ MxS32 g_targetDepth = 16;
// GLOBAL: ISLE 0x410064
MxS32 g_reqEnableRMDevice = FALSE;
MxFloat g_lastJoystickMouseX = 0;
MxFloat g_lastJoystickMouseY = 0;
MxFloat g_lastMouseX = 320;
MxFloat g_lastMouseY = 240;
MxBool g_mouseWarped = FALSE;
bool g_dpadUp = false;
bool g_dpadDown = false;
bool g_dpadLeft = false;
bool g_dpadRight = false;
// STRING: ISLE 0x4101dc
#define WINDOW_TITLE "LEGO®"
@ -96,11 +129,7 @@ IsleApp::IsleApp()
m_cdPath = NULL;
m_deviceId = NULL;
m_savePath = NULL;
#ifdef __EMSCRIPTEN__
m_fullScreen = FALSE;
#else
m_fullScreen = TRUE;
#endif
m_flipSurfaces = FALSE;
m_backBuffersInVram = TRUE;
m_using8bit = FALSE;
@ -109,8 +138,6 @@ IsleApp::IsleApp()
m_drawCursor = FALSE;
m_use3dSound = TRUE;
m_useMusic = TRUE;
m_useJoystick = TRUE;
m_joystickIndex = 0;
m_wideViewAngle = TRUE;
m_islandQuality = 2;
m_islandTexture = 1;
@ -134,12 +161,29 @@ IsleApp::IsleApp()
m_cursorBusy = NULL;
m_cursorNo = NULL;
m_cursorCurrent = NULL;
m_cursorArrowBitmap = NULL;
m_cursorBusyBitmap = NULL;
m_cursorNoBitmap = NULL;
m_cursorCurrentBitmap = NULL;
LegoOmni::CreateInstance();
m_iniPath = NULL;
m_maxLod = RealtimeView::GetUserMaxLOD();
m_maxAllowedExtras = m_islandQuality <= 1 ? 10 : 20;
m_transitionType = MxTransitionManager::e_mosaic;
m_cursorSensitivity = 4;
m_touchScheme = LegoInputManager::e_gamepad;
m_haptic = TRUE;
m_xRes = 640;
m_yRes = 480;
m_exclusiveXRes = m_xRes;
m_exclusiveYRes = m_yRes;
m_exclusiveFrameRate = 60.00f;
m_frameRate = 100.0f;
m_exclusiveFullScreen = FALSE;
m_msaaSamples = 0;
m_anisotropic = 0.0f;
}
// FUNCTION: ISLE 0x4011a0
@ -244,7 +288,7 @@ void IsleApp::SetupVideoFlags(
m_videoParam.Flags().SetLacksLightSupport(!hasLightSupport);
m_videoParam.Flags().SetF1bit7(param_7);
m_videoParam.Flags().SetWideViewAngle(wideViewAngle);
m_videoParam.Flags().SetF2bit1(1);
m_videoParam.Flags().SetEnabled(TRUE);
m_videoParam.SetDeviceName(deviceId);
if (using8bit) {
m_videoParam.Flags().Set16Bit(0);
@ -261,7 +305,7 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv)
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK)) {
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD | SDL_INIT_HAPTIC)) {
char buffer[256];
SDL_snprintf(
buffer,
@ -280,7 +324,8 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv)
// Create global app instance
g_isle = new IsleApp();
if (g_isle->ParseArguments(argc, argv) != SUCCESS) {
switch (g_isle->ParseArguments(argc, argv)) {
case SDL_APP_FAILURE:
Any_ShowSimpleMessageBox(
SDL_MESSAGEBOX_ERROR,
"LEGO® Island Error",
@ -288,6 +333,10 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv)
window
);
return SDL_APP_FAILURE;
case SDL_APP_SUCCESS:
return SDL_APP_SUCCESS;
case SDL_APP_CONTINUE:
break;
}
// Create window
@ -304,6 +353,23 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv)
// Get reference to window
*appstate = g_isle->GetWindowHandle();
// Currently, SDL doesn't send SDL_EVENT_MOUSE_ADDED at startup (unlike for gamepads)
// This will probably be fixed in the future: https://github.com/libsdl-org/SDL/issues/12815
{
int count;
SDL_MouseID* mice = SDL_GetMice(&count);
if (mice) {
for (int i = 0; i < count; i++) {
if (InputManager()) {
InputManager()->AddMouse(mice[i]);
}
}
SDL_free(mice);
}
}
#ifdef __EMSCRIPTEN__
SDL_AddEventWatch(
[](void* userdata, SDL_Event* event) -> bool {
@ -316,6 +382,9 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv)
},
NULL
);
#endif
#ifdef __3DS__
N3DS_SetupAptHooks();
#endif
return SDL_APP_CONTINUE;
}
@ -367,6 +436,8 @@ SDL_AppResult SDL_AppIterate(void* appstate)
if (g_mousemoved) {
g_mousemoved = FALSE;
}
g_isle->MoveVirtualMouseViaJoystick();
}
return SDL_APP_CONTINUE;
@ -382,26 +453,27 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
return SDL_APP_CONTINUE;
}
// [library:window]
// Remaining functionality to be implemented:
// WM_TIMER - use SDL_Timer functionality instead
#ifdef __EMSCRIPTEN__
// Workaround for the fact we are getting both mouse & touch events on mobile devices running Emscripten.
// On desktops, we are only getting mouse events, but a touch device (pen_input) may also be present...
// See: https://github.com/libsdl-org/SDL/issues/13161
static bool detectedTouchEvents = false;
#endif
if (InputManager()) {
InputManager()->UpdateLastInputMethod(event);
}
switch (event->type) {
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
case SDL_EVENT_MOUSE_MOTION:
case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP:
case SDL_EVENT_FINGER_MOTION:
case SDL_EVENT_FINGER_DOWN:
case SDL_EVENT_FINGER_UP:
case SDL_EVENT_FINGER_CANCELED:
IDirect3DRMMiniwinDevice* device = GetD3DRMMiniwinDevice();
if (device && !device->ConvertEventToRenderCoordinates(event)) {
SDL_Log("Failed to convert event coordinates: %s", SDL_GetError());
}
#ifdef __EMSCRIPTEN__
Emscripten_ConvertEventToRenderCoordinates(event);
#endif
break;
}
@ -422,6 +494,7 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
}
break;
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
case SDL_EVENT_QUIT:
if (!g_closed) {
delete g_isle;
g_isle = NULL;
@ -435,7 +508,7 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
SDL_Keycode keyCode = event->key.key;
if (event->key.mod == SDL_KMOD_LALT && keyCode == SDLK_RETURN) {
if ((event->key.mod & SDL_KMOD_LALT) && keyCode == SDLK_RETURN) {
SDL_SetWindowFullscreen(window, !(SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN));
}
else {
@ -445,12 +518,155 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
}
break;
}
case SDL_EVENT_MOUSE_MOTION:
#ifdef __EMSCRIPTEN__
if (detectedTouchEvents) {
case SDL_EVENT_KEYBOARD_ADDED:
if (InputManager()) {
InputManager()->AddKeyboard(event->kdevice.which);
}
break;
case SDL_EVENT_KEYBOARD_REMOVED:
if (InputManager()) {
InputManager()->RemoveKeyboard(event->kdevice.which);
}
break;
case SDL_EVENT_MOUSE_ADDED:
if (InputManager()) {
InputManager()->AddMouse(event->mdevice.which);
}
break;
case SDL_EVENT_MOUSE_REMOVED:
if (InputManager()) {
InputManager()->RemoveMouse(event->mdevice.which);
}
break;
case SDL_EVENT_GAMEPAD_ADDED:
if (InputManager()) {
InputManager()->AddJoystick(event->jdevice.which);
}
break;
case SDL_EVENT_GAMEPAD_REMOVED:
if (InputManager()) {
InputManager()->RemoveJoystick(event->jdevice.which);
}
break;
case SDL_EVENT_GAMEPAD_BUTTON_DOWN: {
switch (event->gbutton.button) {
case SDL_GAMEPAD_BUTTON_DPAD_UP:
g_dpadUp = true;
break;
case SDL_GAMEPAD_BUTTON_DPAD_DOWN:
g_dpadDown = true;
break;
case SDL_GAMEPAD_BUTTON_DPAD_LEFT:
g_dpadLeft = true;
break;
case SDL_GAMEPAD_BUTTON_DPAD_RIGHT:
g_dpadRight = true;
break;
case SDL_GAMEPAD_BUTTON_EAST:
g_mousedown = TRUE;
if (InputManager()) {
InputManager()->QueueEvent(
c_notificationButtonDown,
LegoEventNotificationParam::c_lButtonState,
g_lastMouseX,
g_lastMouseY,
0
);
}
break;
case SDL_GAMEPAD_BUTTON_SOUTH:
if (InputManager()) {
InputManager()->QueueEvent(c_notificationKeyPress, SDLK_SPACE, 0, 0, SDLK_SPACE);
}
break;
case SDL_GAMEPAD_BUTTON_START:
if (InputManager()) {
InputManager()->QueueEvent(c_notificationKeyPress, SDLK_ESCAPE, 0, 0, SDLK_ESCAPE);
}
break;
}
#endif
break;
}
case SDL_EVENT_GAMEPAD_BUTTON_UP: {
switch (event->gbutton.button) {
case SDL_GAMEPAD_BUTTON_DPAD_UP:
g_dpadUp = false;
break;
case SDL_GAMEPAD_BUTTON_DPAD_DOWN:
g_dpadDown = false;
break;
case SDL_GAMEPAD_BUTTON_DPAD_LEFT:
g_dpadLeft = false;
break;
case SDL_GAMEPAD_BUTTON_DPAD_RIGHT:
g_dpadRight = false;
break;
case SDL_GAMEPAD_BUTTON_EAST:
g_mousedown = FALSE;
if (InputManager()) {
InputManager()->QueueEvent(
c_notificationButtonUp,
LegoEventNotificationParam::c_lButtonState,
g_lastMouseX,
g_lastMouseY,
0
);
}
break;
}
break;
}
case SDL_EVENT_GAMEPAD_AXIS_MOTION: {
MxS16 axisValue = 0;
if (event->gaxis.value < -8000 || event->gaxis.value > 8000) {
// Ignore small axis values
axisValue = event->gaxis.value;
}
if (event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHTX) {
g_lastJoystickMouseX = ((MxFloat) axisValue) / SDL_JOYSTICK_AXIS_MAX * g_isle->GetCursorSensitivity();
}
else if (event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHTY) {
g_lastJoystickMouseY = ((MxFloat) axisValue) / SDL_JOYSTICK_AXIS_MAX * g_isle->GetCursorSensitivity();
}
else if (event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) {
if (axisValue != 0 && !g_mousedown) {
g_mousedown = TRUE;
if (InputManager()) {
InputManager()->QueueEvent(
c_notificationButtonDown,
LegoEventNotificationParam::c_lButtonState,
g_lastMouseX,
g_lastMouseY,
0
);
}
}
else if (axisValue == 0 && g_mousedown) {
g_mousedown = FALSE;
if (InputManager()) {
InputManager()->QueueEvent(
c_notificationButtonUp,
LegoEventNotificationParam::c_lButtonState,
g_lastMouseX,
g_lastMouseY,
0
);
}
}
}
break;
}
case SDL_EVENT_MOUSE_MOTION:
if (g_mouseWarped) {
g_mouseWarped = FALSE;
break;
}
g_mousemoved = TRUE;
if (InputManager()) {
@ -463,34 +679,41 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
);
}
if (g_isle->GetDrawCursor()) {
VideoManager()->MoveCursor(Min((MxS32) event->motion.x, 639), Min((MxS32) event->motion.y, 479));
g_lastMouseX = event->motion.x;
g_lastMouseY = event->motion.y;
SDL_ShowCursor();
g_isle->SetDrawCursor(FALSE);
if (VideoManager()) {
VideoManager()->SetCursorBitmap(NULL);
}
break;
case SDL_EVENT_FINGER_MOTION: {
#ifdef __EMSCRIPTEN__
detectedTouchEvents = true;
#endif
g_mousemoved = TRUE;
float x = SDL_clamp(event->tfinger.x, 0, 1) * 640;
float y = SDL_clamp(event->tfinger.y, 0, 1) * 480;
float x = SDL_clamp(event->tfinger.x, 0, 1) * g_targetWidth;
float y = SDL_clamp(event->tfinger.y, 0, 1) * g_targetHeight;
if (InputManager()) {
InputManager()->QueueEvent(c_notificationMouseMove, LegoEventNotificationParam::c_lButtonState, x, y, 0);
MxU8 modifier = LegoEventNotificationParam::c_lButtonState;
if (InputManager()->HandleTouchEvent(event, g_isle->GetTouchScheme())) {
modifier |= LegoEventNotificationParam::c_motionHandled;
}
InputManager()->QueueEvent(c_notificationMouseMove, modifier, x, y, 0);
}
if (g_isle->GetDrawCursor()) {
VideoManager()->MoveCursor(Min((MxS32) x, 639), Min((MxS32) y, 479));
g_lastMouseX = x;
g_lastMouseY = y;
SDL_HideCursor();
g_isle->SetDrawCursor(FALSE);
if (VideoManager()) {
VideoManager()->SetCursorBitmap(NULL);
}
break;
}
case SDL_EVENT_MOUSE_BUTTON_DOWN:
#ifdef __EMSCRIPTEN__
if (detectedTouchEvents) {
break;
}
#endif
g_mousedown = TRUE;
if (InputManager()) {
@ -504,31 +727,27 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
}
break;
case SDL_EVENT_FINGER_DOWN: {
#ifdef __EMSCRIPTEN__
detectedTouchEvents = true;
#endif
g_mousedown = TRUE;
float x = SDL_clamp(event->tfinger.x, 0, 1) * 640;
float y = SDL_clamp(event->tfinger.y, 0, 1) * 480;
float x = SDL_clamp(event->tfinger.x, 0, 1) * g_targetWidth;
float y = SDL_clamp(event->tfinger.y, 0, 1) * g_targetHeight;
if (InputManager()) {
InputManager()->HandleTouchEvent(event, g_isle->GetTouchScheme());
InputManager()->QueueEvent(c_notificationButtonDown, LegoEventNotificationParam::c_lButtonState, x, y, 0);
}
g_lastMouseX = x;
g_lastMouseY = y;
SDL_HideCursor();
g_isle->SetDrawCursor(FALSE);
if (VideoManager()) {
VideoManager()->SetCursorBitmap(NULL);
}
break;
}
case SDL_EVENT_MOUSE_BUTTON_UP:
#ifdef __EMSCRIPTEN__
if (detectedTouchEvents) {
// Abusing the fact (bug?) that we are always getting mouse events on Emscripten.
// This functionality should be enabled in a more general way with touch events,
// but SDL touch event's don't have a "double tap" indicator right now.
if (event->button.clicks == 2) {
InputManager()->QueueEvent(c_notificationKeyPress, SDLK_SPACE, 0, 0, SDLK_SPACE);
}
break;
}
#endif
g_mousedown = FALSE;
if (InputManager()) {
@ -541,23 +760,21 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
);
}
break;
case SDL_EVENT_FINGER_UP: {
#ifdef __EMSCRIPTEN__
detectedTouchEvents = true;
#endif
case SDL_EVENT_FINGER_UP:
case SDL_EVENT_FINGER_CANCELED: {
g_mousedown = FALSE;
float x = SDL_clamp(event->tfinger.x, 0, 1) * 640;
float y = SDL_clamp(event->tfinger.y, 0, 1) * 480;
float x = SDL_clamp(event->tfinger.x, 0, 1) * g_targetWidth;
float y = SDL_clamp(event->tfinger.y, 0, 1) * g_targetHeight;
g_isle->DetectDoubleTap(event->tfinger);
if (InputManager()) {
InputManager()->HandleTouchEvent(event, g_isle->GetTouchScheme());
InputManager()->QueueEvent(c_notificationButtonUp, 0, x, y, 0);
}
break;
}
case SDL_EVENT_QUIT:
return SDL_APP_SUCCESS;
break;
}
if (event->user.type == g_legoSdlEvents.m_windowsMessage) {
@ -588,9 +805,41 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
if (!g_isle->GetGameStarted() && action && state == MxPresenter::e_ready &&
!SDL_strncmp(action->GetObjectName(), "Lego_Smk", 8)) {
g_isle->SetGameStarted(TRUE);
#ifdef __EMSCRIPTEN__
Emscripten_SetupWindow((SDL_Window*) g_isle->GetWindowHandle());
#endif
SDL_Log("Game started");
}
}
else if (event->user.type == g_legoSdlEvents.m_gameEvent) {
auto rumble = [](float p_strength, float p_lowFrequencyRumble, float p_highFrequencyRumble, MxU32 p_milliseconds
) {
if (g_isle->GetHaptic() &&
!InputManager()
->HandleRumbleEvent(p_strength, p_lowFrequencyRumble, p_highFrequencyRumble, p_milliseconds)) {
// Platform-specific handling
#ifdef __EMSCRIPTEN__
Emscripten_HandleRumbleEvent(p_lowFrequencyRumble, p_highFrequencyRumble, p_milliseconds);
#endif
}
};
switch (event->user.code) {
case e_hitActor:
rumble(0.5f, 0.5f, 0.5f, 700);
break;
case e_skeletonKick:
rumble(0.8f, 0.8f, 0.8f, 2500);
break;
case e_raceFinished:
case e_goodEnding:
case e_badEnding:
rumble(1.0f, 1.0f, 1.0f, 3000);
break;
}
}
return SDL_APP_CONTINUE;
}
@ -651,18 +900,39 @@ MxResult IsleApp::SetupWindow()
m_cursorBusy = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT);
m_cursorNo = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NOT_ALLOWED);
SDL_SetCursor(m_cursorCurrent);
m_cursorCurrentBitmap = m_cursorArrowBitmap = &arrow_cursor;
m_cursorBusyBitmap = &busy_cursor;
m_cursorNoBitmap = &no_cursor;
SDL_PropertiesID props = SDL_CreateProperties();
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, g_targetWidth);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, g_targetHeight);
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, m_fullScreen);
SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, WINDOW_TITLE);
#ifdef MINIWIN
#if defined(MINIWIN) && !defined(__3DS__) && !defined(WINDOWS_STORE)
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
#endif
window = SDL_CreateWindowWithProperties(props);
SDL_SetPointerProperty(SDL_GetWindowProperties(window), ISLE_PROP_WINDOW_CREATE_VIDEO_PARAM, &m_videoParam);
if (m_exclusiveFullScreen && m_fullScreen) {
SDL_DisplayMode closestMode;
SDL_DisplayID displayID = SDL_GetDisplayForWindow(window);
if (SDL_GetClosestFullscreenDisplayMode(
displayID,
m_exclusiveXRes,
m_exclusiveYRes,
m_exclusiveFrameRate,
true,
&closestMode
)) {
SDL_SetWindowFullscreenMode(window, &closestMode);
}
}
#ifdef MINIWIN
m_windowHandle = reinterpret_cast<HWND>(window);
#else
@ -703,6 +973,7 @@ MxResult IsleApp::SetupWindow()
return FAILURE;
}
DetectGameVersion();
GameState()->SerializePlayersInfo(LegoStorage::c_read);
GameState()->SerializeScoreHistory(LegoStorage::c_read);
@ -725,11 +996,11 @@ MxResult IsleApp::SetupWindow()
LegoBuildingManager::configureLegoBuildingManager(m_islandQuality);
LegoROI::configureLegoROI(iVar10);
LegoAnimationManager::configureLegoAnimationManager(m_maxAllowedExtras);
MxTransitionManager::configureMxTransitionManager(m_transitionType);
RealtimeView::SetUserMaxLOD(m_maxLod);
if (LegoOmni::GetInstance()) {
if (LegoOmni::GetInstance()->GetInputManager()) {
LegoOmni::GetInstance()->GetInputManager()->SetUseJoystick(m_useJoystick);
LegoOmni::GetInstance()->GetInputManager()->SetJoystickIndex(m_joystickIndex);
if (LegoOmni::GetInstance()->GetVideoManager()) {
LegoOmni::GetInstance()->GetVideoManager()->SetCursorBitmap(m_cursorCurrentBitmap);
}
MxDirect3D* d3d = LegoOmni::GetInstance()->GetVideoManager()->GetDirect3D();
if (d3d) {
@ -752,8 +1023,19 @@ MxResult IsleApp::SetupWindow()
// FUNCTION: ISLE 0x4028d0
bool IsleApp::LoadConfig()
{
#ifdef IOS
const char* prefPath = SDL_GetUserFolder(SDL_FOLDER_DOCUMENTS);
#else
char* prefPath = SDL_GetPrefPath("isledecomp", "isle");
#endif
char* iniConfig;
#ifdef __EMSCRIPTEN__
if (m_iniPath && !Emscripten_SetupConfig(m_iniPath)) {
m_iniPath = NULL;
}
#endif
if (m_iniPath) {
iniConfig = new char[strlen(m_iniPath) + 1];
strcpy(iniConfig, m_iniPath);
@ -769,10 +1051,6 @@ bool IsleApp::LoadConfig()
}
SDL_Log("Reading configuration from \"%s\"", iniConfig);
#ifdef __EMSCRIPTEN__
Emscripten_SetupConfig(iniConfig);
#endif
dictionary* dict = iniparser_load(iniConfig);
// [library:config]
@ -807,14 +1085,14 @@ bool IsleApp::LoadConfig()
iniparser_set(dict, "isle:Flip Surfaces", m_flipSurfaces ? "true" : "false");
iniparser_set(dict, "isle:Full Screen", m_fullScreen ? "true" : "false");
iniparser_set(dict, "isle:Exclusive Full Screen", m_exclusiveFullScreen ? "true" : "false");
iniparser_set(dict, "isle:Wide View Angle", m_wideViewAngle ? "true" : "false");
iniparser_set(dict, "isle:3DSound", m_use3dSound ? "true" : "false");
iniparser_set(dict, "isle:Music", m_useMusic ? "true" : "false");
iniparser_set(dict, "isle:UseJoystick", m_useJoystick ? "true" : "false");
iniparser_set(dict, "isle:JoystickIndex", SDL_itoa(m_joystickIndex, buf, 10));
iniparser_set(dict, "isle:Draw Cursor", m_drawCursor ? "true" : "false");
SDL_snprintf(buf, sizeof(buf), "%f", m_cursorSensitivity);
iniparser_set(dict, "isle:Cursor Sensitivity", buf);
iniparser_set(dict, "isle:Back Buffers in Video RAM", "-1");
@ -823,26 +1101,47 @@ bool IsleApp::LoadConfig()
SDL_snprintf(buf, sizeof(buf), "%f", m_maxLod);
iniparser_set(dict, "isle:Max LOD", buf);
iniparser_set(dict, "isle:Max Allowed Extras", SDL_itoa(m_maxAllowedExtras, buf, 10));
iniparser_set(dict, "isle:Transition Type", SDL_itoa(m_transitionType, buf, 10));
iniparser_set(dict, "isle:Touch Scheme", SDL_itoa(m_touchScheme, buf, 10));
iniparser_set(dict, "isle:Haptic", m_haptic ? "true" : "false");
iniparser_set(dict, "isle:Horizontal Resolution", SDL_itoa(m_xRes, buf, 10));
iniparser_set(dict, "isle:Vertical Resolution", SDL_itoa(m_yRes, buf, 10));
iniparser_set(dict, "isle:Exclusive X Resolution", SDL_itoa(m_exclusiveXRes, buf, 10));
iniparser_set(dict, "isle:Exclusive Y Resolution", SDL_itoa(m_exclusiveYRes, buf, 10));
iniparser_set(dict, "isle:Exclusive Framerate", SDL_itoa(m_exclusiveFrameRate, buf, 10));
iniparser_set(dict, "isle:Frame Delta", SDL_itoa(m_frameDelta, buf, 10));
#ifdef EXTENSIONS
iniparser_set(dict, "extensions", NULL);
for (const char* key : Extensions::availableExtensions) {
iniparser_set(dict, key, "false");
}
#endif
#ifdef __3DS__
N3DS_SetupDefaultConfigOverrides(dict);
#endif
#ifdef WINDOWS_STORE
XBONE_SetupDefaultConfigOverrides(dict);
#endif
#ifdef IOS
IOS_SetupDefaultConfigOverrides(dict);
#endif
iniparser_dump_ini(dict, iniFP);
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "New config written at '%s'", iniConfig);
fclose(iniFP);
}
#ifdef __EMSCRIPTEN__
const char* hdPath = Emscripten_bundledPath;
#else
const char* hdPath = iniparser_getstring(dict, "isle:diskpath", SDL_GetBasePath());
Emscripten_SetupDefaultConfigOverrides(dict);
#endif
const char* hdPath = iniparser_getstring(dict, "isle:diskpath", SDL_GetBasePath());
m_hdPath = new char[strlen(hdPath) + 1];
strcpy(m_hdPath, hdPath);
MxOmni::SetHD(m_hdPath);
#ifdef __EMSCRIPTEN__
const char* cdPath = Emscripten_streamPath;
#else
const char* cdPath = iniparser_getstring(dict, "isle:cdpath", MxOmni::GetCD());
#endif
m_cdPath = new char[strlen(cdPath) + 1];
strcpy(m_cdPath, cdPath);
MxOmni::SetCD(m_cdPath);
@ -853,12 +1152,11 @@ bool IsleApp::LoadConfig()
m_flipSurfaces = iniparser_getboolean(dict, "isle:Flip Surfaces", m_flipSurfaces);
m_fullScreen = iniparser_getboolean(dict, "isle:Full Screen", m_fullScreen);
m_exclusiveFullScreen = iniparser_getboolean(dict, "isle:Exclusive Full Screen", m_exclusiveFullScreen);
m_wideViewAngle = iniparser_getboolean(dict, "isle:Wide View Angle", m_wideViewAngle);
m_use3dSound = iniparser_getboolean(dict, "isle:3DSound", m_use3dSound);
m_useMusic = iniparser_getboolean(dict, "isle:Music", m_useMusic);
m_useJoystick = iniparser_getboolean(dict, "isle:UseJoystick", m_useJoystick);
m_joystickIndex = iniparser_getint(dict, "isle:JoystickIndex", m_joystickIndex);
m_drawCursor = iniparser_getboolean(dict, "isle:Draw Cursor", m_drawCursor);
m_cursorSensitivity = iniparser_getdouble(dict, "isle:Cursor Sensitivity", m_cursorSensitivity);
MxS32 backBuffersInVRAM = iniparser_getboolean(dict, "isle:Back Buffers in Video RAM", -1);
if (backBuffersInVRAM != -1) {
@ -879,6 +1177,22 @@ bool IsleApp::LoadConfig()
m_islandTexture = iniparser_getint(dict, "isle:Island Texture", m_islandTexture);
m_maxLod = iniparser_getdouble(dict, "isle:Max LOD", m_maxLod);
m_maxAllowedExtras = iniparser_getint(dict, "isle:Max Allowed Extras", m_maxAllowedExtras);
m_transitionType =
(MxTransitionManager::TransitionType) iniparser_getint(dict, "isle:Transition Type", m_transitionType);
m_touchScheme = (LegoInputManager::TouchScheme) iniparser_getint(dict, "isle:Touch Scheme", m_touchScheme);
m_haptic = iniparser_getboolean(dict, "isle:Haptic", m_haptic);
m_xRes = iniparser_getint(dict, "isle:Horizontal Resolution", m_xRes);
m_yRes = iniparser_getint(dict, "isle:Vertical Resolution", m_yRes);
m_exclusiveXRes = iniparser_getint(dict, "isle:Exclusive X Resolution", m_exclusiveXRes);
m_exclusiveYRes = iniparser_getint(dict, "isle:Exclusive Y Resolution", m_exclusiveXRes);
m_exclusiveFrameRate = iniparser_getdouble(dict, "isle:Exclusive Framerate", m_exclusiveFrameRate);
if (!m_fullScreen) {
m_videoParam.GetRect() = MxRect32(0, 0, (m_xRes - 1), (m_yRes - 1));
}
m_frameRate = (1000.0f / iniparser_getdouble(dict, "isle:Frame Delta", m_frameDelta));
m_frameDelta = static_cast<int>(std::round(iniparser_getdouble(dict, "isle:Frame Delta", m_frameDelta)));
m_videoParam.SetMSAASamples((m_msaaSamples = iniparser_getint(dict, "isle:MSAA", m_msaaSamples)));
m_videoParam.SetAnisotropic((m_anisotropic = iniparser_getdouble(dict, "isle:Anisotropic", m_anisotropic)));
const char* deviceId = iniparser_getstring(dict, "isle:3D Device ID", NULL);
if (deviceId != NULL) {
@ -889,17 +1203,33 @@ bool IsleApp::LoadConfig()
// [library:config]
// The original game does not save any data if no savepath is given.
// Instead, we use SDLs prefPath as a default fallback and always save data.
#ifdef __EMSCRIPTEN__
const char* savePath = Emscripten_savePath;
#else
const char* savePath = iniparser_getstring(dict, "isle:savepath", prefPath);
#endif
m_savePath = new char[strlen(savePath) + 1];
strcpy(m_savePath, savePath);
#ifdef EXTENSIONS
for (const char* key : Extensions::availableExtensions) {
if (iniparser_getboolean(dict, key, 0)) {
std::vector<const char*> extensionKeys;
const char* section = SDL_strchr(key, ':') + 1;
extensionKeys.resize(iniparser_getsecnkeys(dict, section));
iniparser_getseckeys(dict, section, extensionKeys.data());
std::map<std::string, std::string> extensionDict;
for (const char* key : extensionKeys) {
extensionDict[key] = iniparser_getstring(dict, key, NULL);
}
Extensions::Enable(key, std::move(extensionDict));
}
}
#endif
iniparser_freedict(dict);
delete[] iniConfig;
#ifndef IOS
SDL_free(prefPath);
#endif
return true;
}
@ -1003,15 +1333,19 @@ void IsleApp::SetupCursor(Cursor p_cursor)
switch (p_cursor) {
case e_cursorArrow:
m_cursorCurrent = m_cursorArrow;
m_cursorCurrentBitmap = m_cursorArrowBitmap;
break;
case e_cursorBusy:
m_cursorCurrent = m_cursorBusy;
m_cursorCurrentBitmap = m_cursorBusyBitmap;
break;
case e_cursorNo:
m_cursorCurrent = m_cursorNo;
m_cursorCurrentBitmap = m_cursorNoBitmap;
break;
case e_cursorNone:
m_cursorCurrent = NULL;
m_cursorCurrentBitmap = NULL;
case e_cursorUnused3:
case e_cursorUnused4:
case e_cursorUnused5:
@ -1023,16 +1357,21 @@ void IsleApp::SetupCursor(Cursor p_cursor)
break;
}
if (m_cursorCurrent != NULL) {
SDL_SetCursor(m_cursorCurrent);
SDL_ShowCursor();
if (g_isle->GetDrawCursor()) {
VideoManager()->SetCursorBitmap(m_cursorCurrentBitmap);
}
else {
SDL_HideCursor();
if (m_cursorCurrent != NULL) {
SDL_SetCursor(m_cursorCurrent);
SDL_ShowCursor();
}
else {
SDL_HideCursor();
}
}
}
MxResult IsleApp::ParseArguments(int argc, char** argv)
SDL_AppResult IsleApp::ParseArguments(int argc, char** argv)
{
for (int i = 1, consumed; i < argc; i += consumed) {
consumed = -1;
@ -1049,13 +1388,29 @@ MxResult IsleApp::ParseArguments(int argc, char** argv)
#endif
consumed = 1;
}
else if (strcmp(argv[i], "--help") == 0) {
DisplayArgumentHelp();
return SDL_APP_SUCCESS;
}
if (consumed <= 0) {
SDL_Log("Invalid argument(s): %s", argv[i]);
return FAILURE;
DisplayArgumentHelp();
return SDL_APP_FAILURE;
}
}
return SUCCESS;
return SDL_APP_CONTINUE;
}
void IsleApp::DisplayArgumentHelp()
{
SDL_Log("Usage: isle [options]");
SDL_Log("Options:");
SDL_Log(" --ini <path> Set custom path to .ini config");
#ifdef ISLE_DEBUG
SDL_Log(" --debug Launch in debug mode");
#endif
SDL_Log(" --help Show this help message");
}
MxResult IsleApp::VerifyFilesystem()
@ -1098,6 +1453,34 @@ MxResult IsleApp::VerifyFilesystem()
return SUCCESS;
}
void IsleApp::DetectGameVersion()
{
const char* file = "/lego/scripts/infocntr/infomain.si";
SDL_PathInfo info;
bool success = false;
MxString path = MxString(m_hdPath) + file;
path.MapPathToFilesystem();
if (!(success = SDL_GetPathInfo(path.GetData(), &info))) {
path = MxString(m_cdPath) + file;
path.MapPathToFilesystem();
success = SDL_GetPathInfo(path.GetData(), &info);
}
assert(success);
// File sizes of INFOMAIN.SI in English 1.0 and Japanese 1.0
Lego()->SetVersion10(info.size == 58130432 || info.size == 57737216);
if (Lego()->IsVersion10()) {
SDL_Log("Detected game version 1.0");
SDL_SetWindowTitle(reinterpret_cast<SDL_Window*>(m_windowHandle), "Lego Island");
}
else {
SDL_Log("Detected game version 1.1");
}
}
IDirect3DRMMiniwinDevice* GetD3DRMMiniwinDevice()
{
LegoVideoManager* videoManager = LegoOmni::GetInstance()->GetVideoManager();
@ -1126,3 +1509,80 @@ IDirect3DRMMiniwinDevice* GetD3DRMMiniwinDevice()
}
return d3drmMiniwinDev;
}
void IsleApp::MoveVirtualMouseViaJoystick()
{
float dpadX = 0.0f;
float dpadY = 0.0f;
if (g_dpadLeft) {
dpadX -= m_cursorSensitivity;
}
if (g_dpadRight) {
dpadX += m_cursorSensitivity;
}
if (g_dpadUp) {
dpadY -= m_cursorSensitivity;
}
if (g_dpadDown) {
dpadY += m_cursorSensitivity;
}
// Use joystick axis if non-zero, else fall back to dpad
float moveX = (g_lastJoystickMouseX != 0) ? g_lastJoystickMouseX : dpadX;
float moveY = (g_lastJoystickMouseY != 0) ? g_lastJoystickMouseY : dpadY;
if (moveX != 0 || moveY != 0) {
g_mousemoved = TRUE;
g_lastMouseX = SDL_clamp(g_lastMouseX + moveX, 0, g_targetWidth);
g_lastMouseY = SDL_clamp(g_lastMouseY + moveY, 0, g_targetHeight);
if (InputManager()) {
InputManager()->QueueEvent(
c_notificationMouseMove,
g_mousedown ? LegoEventNotificationParam::c_lButtonState : 0,
g_lastMouseX,
g_lastMouseY,
0
);
}
SDL_HideCursor();
g_isle->SetDrawCursor(TRUE);
if (VideoManager()) {
VideoManager()->SetCursorBitmap(m_cursorCurrentBitmap);
VideoManager()->MoveCursor(Min((MxS32) g_lastMouseX, 639), Min((MxS32) g_lastMouseY, 479));
}
IDirect3DRMMiniwinDevice* device = GetD3DRMMiniwinDevice();
if (device) {
Sint32 x, y;
device->ConvertRenderToWindowCoordinates(g_lastMouseX, g_lastMouseY, x, y);
g_mouseWarped = TRUE;
SDL_WarpMouseInWindow(window, x, y);
}
}
}
void IsleApp::DetectDoubleTap(const SDL_TouchFingerEvent& p_event)
{
typedef std::pair<Uint64, std::array<float, 2>> LastTap;
const MxU32 doubleTapMs = 500;
const float doubleTapDist = 0.001;
static LastTap lastTap = {0, {0, 0}};
LastTap currentTap = {p_event.timestamp, {p_event.x, p_event.y}};
if (SDL_NS_TO_MS(currentTap.first - lastTap.first) < doubleTapMs &&
DISTSQRD2(currentTap.second, lastTap.second) < doubleTapDist) {
if (InputManager()) {
InputManager()->QueueEvent(c_notificationKeyPress, SDLK_SPACE, 0, 0, SDLK_SPACE);
}
lastTap = {0, {0, 0}};
}
else {
lastTap = currentTap;
}
}

View File

@ -1,8 +1,11 @@
#ifndef ISLEAPP_H
#define ISLEAPP_H
#include "cursor.h"
#include "lego1_export.h"
#include "legoinputmanager.h"
#include "legoutils.h"
#include "mxtransitionmanager.h"
#include "mxtypes.h"
#include "mxvideoparam.h"
@ -50,19 +53,26 @@ class IsleApp {
SDL_Cursor* GetCursorNo() { return m_cursorNo; }
MxS32 GetDrawCursor() { return m_drawCursor; }
MxS32 GetGameStarted() { return m_gameStarted; }
MxFloat GetCursorSensitivity() { return m_cursorSensitivity; }
LegoInputManager::TouchScheme GetTouchScheme() { return m_touchScheme; }
MxBool GetHaptic() { return m_haptic; }
void SetWindowActive(MxS32 p_windowActive) { m_windowActive = p_windowActive; }
void SetGameStarted(MxS32 p_gameStarted) { m_gameStarted = p_gameStarted; }
void SetDrawCursor(MxS32 p_drawCursor) { m_drawCursor = p_drawCursor; }
MxResult ParseArguments(int argc, char** argv);
SDL_AppResult ParseArguments(int argc, char** argv);
MxResult VerifyFilesystem();
void DetectGameVersion();
void MoveVirtualMouseViaJoystick();
void DetectDoubleTap(const SDL_TouchFingerEvent& p_event);
private:
char* m_hdPath; // 0x00
char* m_cdPath; // 0x04
char* m_deviceId; // 0x08
char* m_savePath; // 0x0c
MxS32 m_fullScreen; // 0x10
MxBool m_fullScreen; // 0x10
MxS32 m_flipSurfaces; // 0x14
MxS32 m_backBuffersInVram; // 0x18
MxS32 m_using8bit; // 0x1c
@ -70,8 +80,6 @@ class IsleApp {
MxS32 m_hasLightSupport; // 0x24
MxS32 m_use3dSound; // 0x28
MxS32 m_useMusic; // 0x2c
MxS32 m_useJoystick; // 0x30
MxS32 m_joystickIndex; // 0x34
MxS32 m_wideViewAngle; // 0x38
MxS32 m_islandQuality; // 0x3c
MxS32 m_islandTexture; // 0x40
@ -85,14 +93,33 @@ class IsleApp {
SDL_Cursor* m_cursorBusy; // 0x80
SDL_Cursor* m_cursorNo; // 0x84
SDL_Cursor* m_cursorCurrent; // 0x88
const CursorBitmap* m_cursorArrowBitmap;
const CursorBitmap* m_cursorBusyBitmap;
const CursorBitmap* m_cursorNoBitmap;
const CursorBitmap* m_cursorCurrentBitmap;
char* m_mediaPath;
MxFloat m_cursorSensitivity;
void DisplayArgumentHelp();
char* m_iniPath;
MxFloat m_maxLod;
MxU32 m_maxAllowedExtras;
MxTransitionManager::TransitionType m_transitionType;
LegoInputManager::TouchScheme m_touchScheme;
MxBool m_haptic;
MxS32 m_xRes;
MxS32 m_yRes;
MxS32 m_exclusiveXRes;
MxS32 m_exclusiveYRes;
MxFloat m_exclusiveFrameRate;
MxFloat m_frameRate;
MxBool m_exclusiveFullScreen;
MxU32 m_msaaSamples;
MxFloat m_anisotropic;
};
extern IsleApp* g_isle;
extern MxS32 g_closed;
extern IDirect3DRMMiniwinDevice* GetD3DRMMiniwinDevice();

View File

@ -46,7 +46,7 @@ class DebugViewer {
if (plantManager->m_numEntries) {
if (ImGui::BeginTable("Animated Entries", 4, ImGuiTableFlags_Borders)) {
ImGui::TableSetupColumn("ROI Name");
ImGui::TableSetupColumn("ROI m_unk0x100");
ImGui::TableSetupColumn("ROI m_sharedLodList");
ImGui::TableSetupColumn("Entity Name");
ImGui::TableSetupColumn("Time");
ImGui::TableHeadersRow();
@ -55,7 +55,7 @@ class DebugViewer {
ImGui::TableNextRow();
ImGui::Text("%s", entry->m_roi->m_name);
ImGui::TableNextColumn();
ImGui::Text("%d", entry->m_roi->m_unk0x100);
ImGui::Text("%d", entry->m_roi->m_sharedLodList);
ImGui::TableNextColumn();
ImGui::Text("%s", entry->m_roi->m_entity->ClassName());
ImGui::TableNextColumn();
@ -75,7 +75,7 @@ class DebugViewer {
if (buildingManager->m_numEntries) {
if (ImGui::BeginTable("Animated Entries", 6, ImGuiTableFlags_Borders)) {
ImGui::TableSetupColumn("ROI Name");
ImGui::TableSetupColumn("ROI m_unk0x100");
ImGui::TableSetupColumn("ROI m_sharedLodList");
ImGui::TableSetupColumn("Entity Name");
ImGui::TableSetupColumn("Time");
ImGui::TableSetupColumn("Y");
@ -86,13 +86,13 @@ class DebugViewer {
ImGui::TableNextRow();
ImGui::Text("%s", entry->m_roi->m_name);
ImGui::TableNextColumn();
ImGui::Text("%d", entry->m_roi->m_unk0x100);
ImGui::Text("%d", entry->m_roi->m_sharedLodList);
ImGui::TableNextColumn();
ImGui::Text("%s", entry->m_roi->m_entity->ClassName());
ImGui::TableNextColumn();
ImGui::Text("%d", entry->m_time);
ImGui::TableNextColumn();
ImGui::Text("%d", entry->m_y);
ImGui::Text("%f", entry->m_y);
ImGui::TableNextColumn();
ImGui::Text("%d", entry->m_muted);
}
@ -135,7 +135,7 @@ class DebugViewer {
ImGui::Text("unk0x70: %u", videoManager->m_unk0x70);
ImGui::Text("Dither: %d", videoManager->m_dither);
ImGui::Text("BufferCount: %u", videoManager->m_bufferCount);
ImGui::Text("Paused: %f", videoManager->m_paused);
ImGui::Text("Paused: %d", videoManager->m_paused);
ImGui::Text("back: %g", videoManager->m_back);
ImGui::Text("front: %g", videoManager->m_front);
ImGui::Text("cameraWidth: %g", videoManager->m_cameraWidth);
@ -309,7 +309,7 @@ void IsleDebug_Render()
if (ImGui::TreeNode("Sound Manager")) {
LegoSoundManager* soundManager = lego->GetSoundManager();
Sint32 oldVolume = soundManager->GetVolume();
Sint32 volume = oldVolume;
int volume = oldVolume;
ImGui::SliderInt("volume", &volume, 0, 100);
if (volume != oldVolume) {
soundManager->SetVolume(volume);

View File

@ -46,3 +46,24 @@ const char* g_files[46] = {
"/LEGO/data/WORLD.WDB",
"/LEGO/data/testinf.dta",
};
const char* g_textures[120] = {
"bank01.gif", "beach.gif", "black.gif", "bowtie.gif", "brela_01.gif", "bth1chst.gif", "bth2chst.gif",
"capch.gif", "capdb.gif", "capjs.gif", "capmd.gif", "caprc.gif", "cave_24x.gif", "caverocx.gif",
"caverokx.gif", "cheker01.gif", "construct.gif", "copchest.gif", "dbfrfn.gif", "doctor.gif", "dogface.gif",
"dummy.gif", "e.gif", "flowers.gif", "fruit.gif", "gasroad.gif", "gdface.gif", "g.gif",
"grassx.gif", "infochst.gif", "infoface.gif", "jailpad.gif", "jfrnt.gif", "jsfrnt4.gif", "jsfrnt.gif",
"jside.gif", "jswnsh5.gif", "jswnsh.gif", "l6.gif", "l.gif", "mamachst.gif", "mamaface.gif",
"mamamap.gif", "mech.gif", "medic01.gif", "mitesx.gif", "mustache.gif", "nickchst.gif", "nickface.gif",
"nickmap.gif", "nopizza.gif", "norachst.gif", "noraface.gif", "noramap.gif", "nwcurve.gif", "octan01.gif",
"octsq01.gif", "o.gif", "papachst.gif", "papaface.gif", "papamap.gif", "pebblesx.gif", "pepperha.gif",
"peppizza.gif", "peppmap.gif", "peprchst.gif", "peprface.gif", "pianokys.gif", "pizcurve.gif", "pizza01.gif",
"pizza.gif", "polbar01.gif", "polbla01.gif", "polkadot.gif", "polwhi01.gif", "postchst.gif", "post.gif",
"rac1chst.gif", "rac2chst.gif", "radar.gif", "raddis01.gif", "rcback.gif", "rc-butn.gif", "rcfrnt5.gif",
"rcfrnt6.gif", "rcfrnt7.gif", "rcfrnt.gif", "rcside1.gif", "rcside2.gif", "rcside3.gif", "rctail.gif",
"redskul.gif", "relrel01.gif", "road1way.gif", "road3wa2.gif", "road3wa3.gif", "road3way.gif", "road4way.gif",
"roadstr8.gif", "rockx.gif", "roofpiz.gif", "sandredx.gif", "se_curve.gif", "shftchst.gif", "shftface2.gif",
"shftface.gif", "shldwn02.gif", "skull.gif", "smile.gif", "smileshd.gif", "supr2_01.gif", "tightcrv.gif",
"unkchst.gif", "val_02.gif", "vest.gif", "water2x.gif", "w_curve.gif", "wnbars.gif", "woman.gif",
"womanshd.gif"
};

BIN
ISLE/res/arrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

37
ISLE/res/arrow_bmp.h Normal file
View File

@ -0,0 +1,37 @@
#pragma once
// Generated from ISLE/res/arrow.png
// Dimensions: 32x32
// This file is auto-generated, do not edit it.
#include "cursor.h"
static const unsigned char arrow_data[] = {
0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
0x48, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
0x41, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
0x40, 0x20, 0x00, 0x00, 0x41, 0xF0, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00,
0x54, 0x80, 0x00, 0x00, 0x64, 0x80, 0x00, 0x00, 0x42, 0x40, 0x00, 0x00,
0x02, 0x40, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00,
0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const unsigned char arrow_mask[] = {
0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00,
0x78, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
0x7F, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x00,
0x7F, 0xE0, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00,
0x77, 0x80, 0x00, 0x00, 0x67, 0x80, 0x00, 0x00, 0x43, 0xC0, 0x00, 0x00,
0x03, 0xC0, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00,
0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const CursorBitmap arrow_cursor = { 32, 32, arrow_data, arrow_mask };

BIN
ISLE/res/busy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

37
ISLE/res/busy_bmp.h Normal file
View File

@ -0,0 +1,37 @@
#pragma once
// Generated from ISLE/res/busy.png
// Dimensions: 32x32
// This file is auto-generated, do not edit it.
#include "cursor.h"
static const unsigned char busy_data[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0x00,
0x00, 0x40, 0x01, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x20, 0x02, 0x00,
0x00, 0x20, 0x02, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x22, 0xA2, 0x00,
0x00, 0x11, 0x44, 0x00, 0x00, 0x08, 0x88, 0x00, 0x00, 0x04, 0x10, 0x00,
0x00, 0x02, 0x20, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x02, 0x20, 0x00,
0x00, 0x02, 0x20, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x08, 0x88, 0x00,
0x00, 0x10, 0x04, 0x00, 0x00, 0x20, 0x82, 0x00, 0x00, 0x21, 0x42, 0x00,
0x00, 0x22, 0xA2, 0x00, 0x00, 0x25, 0x52, 0x00, 0x00, 0x7F, 0xFF, 0x00,
0x00, 0x40, 0x01, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const unsigned char busy_mask[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0x00,
0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x3F, 0xFE, 0x00,
0x00, 0x3F, 0xFE, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x3F, 0xFE, 0x00,
0x00, 0x1F, 0xFC, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x07, 0xF0, 0x00,
0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, 0x00,
0x00, 0x03, 0xE0, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x0F, 0xF8, 0x00,
0x00, 0x1F, 0xFC, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x3F, 0xFE, 0x00,
0x00, 0x3F, 0xFE, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0x00,
0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const CursorBitmap busy_cursor = { 32, 32, busy_data, busy_mask };

BIN
ISLE/res/no.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

37
ISLE/res/no_bmp.h Normal file
View File

@ -0,0 +1,37 @@
#pragma once
// Generated from ISLE/res/no.png
// Dimensions: 32x32
// This file is auto-generated, do not edit it.
#include "cursor.h"
static const unsigned char no_data[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x1F, 0xF8, 0x00,
0x00, 0x3C, 0x3C, 0x00, 0x00, 0x70, 0x0E, 0x00, 0x00, 0xF8, 0x07, 0x00,
0x00, 0xDC, 0x03, 0x00, 0x01, 0xCE, 0x03, 0x80, 0x01, 0x87, 0x01, 0x80,
0x01, 0x83, 0x81, 0x80, 0x01, 0x81, 0xC1, 0x80, 0x01, 0x80, 0xE1, 0x80,
0x01, 0xC0, 0x73, 0x80, 0x00, 0xC0, 0x3B, 0x00, 0x00, 0xE0, 0x1F, 0x00,
0x00, 0x70, 0x0E, 0x00, 0x00, 0x3C, 0x1C, 0x00, 0x00, 0x1F, 0xF8, 0x00,
0x00, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const unsigned char no_mask[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0xE0, 0x00, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x3F, 0xFC, 0x00,
0x00, 0x7F, 0xFE, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x01, 0xFC, 0x0F, 0x80,
0x01, 0xFE, 0x07, 0x80, 0x03, 0xFF, 0x07, 0xC0, 0x03, 0xCF, 0x83, 0xC0,
0x03, 0xC7, 0xC3, 0xC0, 0x03, 0xC3, 0xE3, 0xC0, 0x03, 0xC1, 0xF3, 0xC0,
0x03, 0xE0, 0xFF, 0xC0, 0x01, 0xE0, 0x7F, 0x80, 0x01, 0xF0, 0x3F, 0x80,
0x00, 0xFC, 0x1F, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x3F, 0xFC, 0x00,
0x00, 0x1F, 0xF8, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const CursorBitmap no_cursor = { 32, 32, no_data, no_mask };

View File

@ -0,0 +1,18 @@
#include "config.h"
#include <SDL3/SDL_log.h>
#include <iniparser.h>
void XBONE_SetupDefaultConfigOverrides(dictionary* p_dictionary)
{
SDL_Log("Overriding default config for Xbox One/Series");
// Use DevelopmentFiles path for disk and cd paths
// It's good to use that path since user can easily
// connect through SMB and copy the files
iniparser_set(p_dictionary, "isle:diskpath", "D:\\DevelopmentFiles\\isle\\");
iniparser_set(p_dictionary, "isle:cdpath", "D:\\DevelopmentFiles\\isle\\");
// Enable cursor by default
iniparser_set(p_dictionary, "isle:Draw Cursor", "true");
}

View File

@ -0,0 +1,8 @@
#ifndef XBOX_ONE_SERIES_CONFIG_H
#define XBOX_ONE_SERIES_CONFIG_H
#include "dictionary.h"
void XBONE_SetupDefaultConfigOverrides(dictionary* p_dictionary);
#endif // XBOX_ONE_SERIES_CONFIG_H

8
LEGO1/cursor.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
typedef struct CursorBitmap {
int width;
int height;
const unsigned char* data;
const unsigned char* mask;
} CursorBitmap;

View File

@ -20,12 +20,12 @@ class MxQuaternionTransformer;
struct Act3ListElement {
MxU32 m_objectId; // 0x00
undefined4 m_unk0x04; // 0x04
undefined m_unk0x08; // 0x08
MxBool m_hasStarted; // 0x08
Act3ListElement() {}
Act3ListElement(MxU32 p_objectId, undefined4 p_unk0x04, undefined p_unk0x08)
: m_objectId(p_objectId), m_unk0x04(p_unk0x04), m_unk0x08(p_unk0x08)
Act3ListElement(MxU32 p_objectId, undefined4 p_unk0x04, MxBool p_hasStarted)
: m_objectId(p_objectId), m_unk0x04(p_unk0x04), m_hasStarted(p_hasStarted)
{
}
@ -36,12 +36,18 @@ struct Act3ListElement {
// SIZE 0x10
class Act3List : private list<Act3ListElement> {
public:
enum InsertMode {
e_replaceAction = 1,
e_queueAction = 2,
e_onlyIfEmpty = 3
};
Act3List() { m_unk0x0c = 0; }
void Insert(MxS32 p_objectId, MxS32 p_option);
void FUN_10071fa0();
void Insert(MxS32 p_objectId, InsertMode p_option);
void DeleteActionWrapper();
void Clear();
void FUN_100720d0(MxU32 p_objectId);
void RemoveByObjectIdOrFirst(MxU32 p_objectId);
private:
undefined4 m_unk0x0c; // 0x0c
@ -129,7 +135,7 @@ class Act3 : public LegoWorld {
void RemoveDonut(Act3Ammo& p_p);
MxResult ShootPizza(LegoPathController* p_controller, Vector3& p_location, Vector3& p_direction, Vector3& p_up);
MxResult ShootDonut(LegoPathController* p_controller, Vector3& p_location, Vector3& p_direction, Vector3& p_up);
void FUN_10072ad0(undefined4 p_param1);
void TriggerHitSound(undefined4 p_param1);
MxResult FUN_10073360(Act3Ammo& p_ammo, const Vector3& p_param2);
MxResult FUN_10073390(Act3Ammo& p_ammo, const Vector3& p_param2);
void SetBrickster(Act3Brickster* p_brickster);
@ -168,12 +174,12 @@ class Act3 : public LegoWorld {
Helicopter* m_copter; // 0x420c
Act3Shark* m_shark; // 0x4210
MxFloat m_time; // 0x4214
MxU8 m_unk0x4218; // 0x4218
MxU8 m_unk0x4219; // 0x4219
MxU8 m_unk0x421a; // 0x421a
MxU8 m_unk0x421b; // 0x421b
MxU8 m_unk0x421c; // 0x421c
MxU8 m_unk0x421d; // 0x421d
MxU8 m_pizzaHitSound; // 0x4218
MxU8 m_pizzaMissSound; // 0x4219
MxU8 m_copDonutSound; // 0x421a
MxU8 m_donutMissSound; // 0x421b
MxU8 m_islanderSound; // 0x421c
MxU8 m_bricksterDonutSound; // 0x421d
undefined m_unk0x421e; // 0x421e
Act3List m_unk0x4220; // 0x4220
MxPresenter* m_helicopterDots[15]; // 0x4230

View File

@ -90,7 +90,7 @@ class Act3Ammo : public LegoPathActor {
// Act3Ammo::`scalar deleting destructor'
private:
MxResult FUN_10053db0(float p_param1, const Matrix4& p_param2);
MxResult FUN_10053db0(float p_param1, Matrix4& p_param2);
static Mx3DPointFloat g_unk0x10104f08;

View File

@ -11,6 +11,12 @@ class MxEndActionNotificationParam;
// SIZE 0x24
class AmbulanceMissionState : public LegoState {
public:
enum {
e_ready = 0,
e_enteredAmbulance = 1,
e_prepareAmbulance = 2,
};
AmbulanceMissionState();
// FUNCTION: LEGO1 0x10037440
@ -125,18 +131,18 @@ class AmbulanceMissionState : public LegoState {
// SYNTHETIC: LEGO1 0x100376c0
// AmbulanceMissionState::`scalar deleting destructor'
undefined4 m_unk0x08; // 0x08
MxLong m_startTime; // 0x0c
MxS16 m_peScore; // 0x10
MxS16 m_maScore; // 0x12
MxS16 m_paScore; // 0x14
MxS16 m_niScore; // 0x16
MxS16 m_laScore; // 0x18
MxS16 m_peHighScore; // 0x1a
MxS16 m_maHighScore; // 0x1c
MxS16 m_paHighScore; // 0x1e
MxS16 m_niHighScore; // 0x20
MxS16 m_laHighScore; // 0x22
MxU32 m_state; // 0x08
MxLong m_startTime; // 0x0c
MxS16 m_peScore; // 0x10
MxS16 m_maScore; // 0x12
MxS16 m_paScore; // 0x14
MxS16 m_niScore; // 0x16
MxS16 m_laScore; // 0x18
MxS16 m_peHighScore; // 0x1a
MxS16 m_maHighScore; // 0x1c
MxS16 m_paHighScore; // 0x1e
MxS16 m_niHighScore; // 0x20
MxS16 m_laHighScore; // 0x22
};
// VTABLE: LEGO1 0x100d71a8
@ -177,15 +183,21 @@ class Ambulance : public IslePathActor {
virtual MxLong HandleEndAction(MxEndActionNotificationParam& p_param); // vtable+0xf4
void CreateState();
void FUN_10036e60();
void Init();
void ActivateSceneActions();
void StopActions();
void FUN_10037250();
void Reset();
// SYNTHETIC: LEGO1 0x10036130
// Ambulance::`scalar deleting destructor'
private:
enum {
e_none = 0,
e_waiting = 1,
e_finished = 3,
};
void PlayAnimation(IsleScript::Script p_objectId);
void PlayFinalAnimation(IsleScript::Script p_objectId);
void StopAction(IsleScript::Script p_objectId);
@ -196,10 +208,10 @@ class Ambulance : public IslePathActor {
AmbulanceMissionState* m_state; // 0x164
MxS16 m_unk0x168; // 0x168
MxS16 m_actorId; // 0x16a
MxS16 m_unk0x16c; // 0x16c
MxS16 m_unk0x16e; // 0x16e
MxS16 m_unk0x170; // 0x170
MxS16 m_unk0x172; // 0x172
MxS16 m_atPoliceTask; // 0x16c
MxS16 m_atBeachTask; // 0x16e
MxS16 m_taskState; // 0x170
MxS16 m_enableRandomAudio; // 0x172
IsleScript::Script m_lastAction; // 0x174
IsleScript::Script m_lastAnimation; // 0x178
MxFloat m_fuel; // 0x17c

View File

@ -52,13 +52,13 @@ class CarRace : public LegoRace {
return !strcmp(p_name, CarRace::ClassName()) || LegoRace::IsA(p_name);
}
MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18
void ReadyWorld() override; // vtable+0x50
MxBool Escape() override; // vtable+0x64
MxLong HandleClick(LegoEventNotificationParam&) override; // vtable+0x6c
MxLong HandlePathStruct(LegoPathStructNotificationParam&) override; // vtable+0x70
MxLong HandleEndAction(MxEndActionNotificationParam&) override; // vtable+0x74
MxLong HandleType0Notification(MxNotificationParam&) override; // vtable+0x78
MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18
void ReadyWorld() override; // vtable+0x50
MxBool Escape() override; // vtable+0x64
MxLong HandleControl(LegoControlManagerNotificationParam&) override; // vtable+0x6c
MxLong HandlePathStruct(LegoPathStructNotificationParam&) override; // vtable+0x70
MxLong HandleEndAction(MxEndActionNotificationParam&) override; // vtable+0x74
MxLong HandleType0Notification(MxNotificationParam&) override; // vtable+0x78
// FUNCTION: BETA10 0x100cd060
RaceSkel* GetSkeleton() { return m_skeleton; }

View File

@ -123,7 +123,7 @@ class Hospital : public LegoWorld {
MxLong m_copLedAnimTimer; // 0x11c
MxLong m_pizzaLedAnimTimer; // 0x120
MxLong m_time; // 0x124
undefined m_unk0x128; // 0x128
MxBool m_exited; // 0x128
};
#endif // HOSPITAL_H

View File

@ -78,10 +78,20 @@ class InfocenterState : public LegoState {
// SIZE 0x18
struct InfocenterMapEntry {
enum {
e_infocenter = 3,
e_jetrace = 10,
e_carrace = 11,
e_pizzeria = 12,
e_garage = 13,
e_hospital = 14,
e_police = 15,
};
InfocenterMapEntry();
MxStillPresenter* m_destCtl; // 0x00
undefined4 m_unk0x04; // 0x04
MxU32 m_target; // 0x04
MxRect<MxS32> m_area; // 0x08
};
@ -154,7 +164,7 @@ class Infocenter : public LegoWorld {
void PlayCutscene(Cutscene p_entityId, MxBool p_scale);
void StopCutscene();
void FUN_10070d10(MxS32 p_x, MxS32 p_y);
void UpdateEnabledGlowControl(MxS32 p_x, MxS32 p_y);
void StartCredits();
void StopCredits();
@ -173,12 +183,12 @@ class Infocenter : public LegoWorld {
Radio m_radio; // 0x10c
MxStillPresenter* m_dragPresenter; // 0x11c
InfocenterMapEntry m_glowInfo[7]; // 0x120
MxS16 m_unk0x1c8; // 0x1c8
MxS16 m_enabledGlowControl; // 0x1c8
MxStillPresenter* m_frame; // 0x1cc
MxS16 m_infoManDialogueTimer; // 0x1d0
MxS16 m_bookAnimationTimer; // 0x1d2
MxU16 m_unk0x1d4; // 0x1d4
MxS16 m_unk0x1d6; // 0x1d6
MxU16 m_playingMovieCounter; // 0x1d4
MxS16 m_bigInfoBlinkTimer; // 0x1d6
};
#endif // INFOCENTER_H

View File

@ -34,6 +34,21 @@ class Act1State : public LegoState {
c_floor3
};
enum {
e_none = 0,
e_initial = 1,
e_elevator = 2,
e_pizza = 3,
e_helicopter = 4,
e_transitionToJetski = 5,
e_transitionToRacecar = 6,
e_transitionToTowtrack = 7,
e_towtrack = 8,
e_transitionToAmbulance = 9,
e_ambulance = 10,
e_jukebox = 11,
};
Act1State();
// FUNCTION: LEGO1 0x100338a0
@ -58,11 +73,11 @@ class Act1State : public LegoState {
void RemoveActors();
void PlaceActors();
MxU32 GetUnknown18() { return m_unk0x018; }
MxU32 GetState() { return m_state; }
ElevatorFloor GetElevatorFloor() { return (ElevatorFloor) m_elevFloor; }
MxU8 GetUnknown21() { return m_unk0x021; }
void SetUnknown18(MxU32 p_unk0x18) { m_unk0x018 = p_unk0x18; }
void SetState(MxU32 p_state) { m_state = p_state; }
void SetElevatorFloor(ElevatorFloor p_elevFloor) { m_elevFloor = p_elevFloor; }
void SetUnknown21(MxU8 p_unk0x21) { m_unk0x021 = p_unk0x21; }
@ -73,7 +88,7 @@ class Act1State : public LegoState {
Playlist m_cptClickDialogue; // 0x008
IsleScript::Script m_currentCptClickDialogue; // 0x014
MxU32 m_unk0x018; // 0x018
MxU32 m_state; // 0x018
MxS16 m_elevFloor; // 0x01c
MxBool m_unk0x01e; // 0x01e
MxBool m_unk0x01f; // 0x01f

View File

@ -29,12 +29,12 @@ class JetskiRace : public LegoRace {
return !strcmp(p_name, JetskiRace::ClassName()) || LegoRace::IsA(p_name);
}
MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18
void ReadyWorld() override; // vtable+0x50
MxBool Escape() override; // vtable+0x64
MxLong HandleClick(LegoEventNotificationParam&) override; // vtable+0x6c
MxLong HandlePathStruct(LegoPathStructNotificationParam&) override; // vtable+0x70
MxLong HandleEndAction(MxEndActionNotificationParam&) override; // vtable+0x74
MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18
void ReadyWorld() override; // vtable+0x50
MxBool Escape() override; // vtable+0x64
MxLong HandleControl(LegoControlManagerNotificationParam&) override; // vtable+0x6c
MxLong HandlePathStruct(LegoPathStructNotificationParam&) override; // vtable+0x70
MxLong HandleEndAction(MxEndActionNotificationParam&) override; // vtable+0x74
void FUN_10016930(MxS32 p_param1, MxS16 p_param2);

View File

@ -304,4 +304,7 @@ class LegoAnimationManager : public MxCore {
// TEMPLATE: LEGO1 0x10061750
// MxListCursor<LegoTranInfo *>::MxListCursor<LegoTranInfo *>
// TEMPLATE: BETA10 0x1004b5d0
// MxListCursor<LegoTranInfo *>::Next
#endif // LEGOANIMATIONMANAGER_H

View File

@ -2,6 +2,7 @@
#define LEGOANIMPRESENTER_H
#include "legoroilist.h"
#include "legoroimaplist.h"
#include "mxatom.h"
#include "mxvideopresenter.h"
@ -92,7 +93,11 @@ class LegoAnimPresenter : public MxVideoPresenter {
const char* GetActionObjectName();
void SetCurrentWorld(LegoWorld* p_currentWorld) { m_currentWorld = p_currentWorld; }
// FUNCTION: BETA10 0x1005aad0
void SetUnknown0x0cTo1() { m_unk0x9c = 1; }
// FUNCTION: BETA10 0x1005ab00
void SetUnknown0xa0(Matrix4* p_unk0xa0) { m_unk0xa0 = p_unk0xa0; }
LegoAnim* GetAnimation() { return m_anim; }
@ -121,7 +126,7 @@ class LegoAnimPresenter : public MxVideoPresenter {
void SubstituteVariables();
void FUN_1006b900(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix);
void FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix);
void FUN_1006c8a0(MxBool p_bool);
void SetDisabled(MxBool p_disabled);
LegoAnim* m_anim; // 0x64
LegoROI** m_roiMap; // 0x68
@ -143,14 +148,191 @@ class LegoAnimPresenter : public MxVideoPresenter {
MxS16 m_unk0x9c; // 0x9c
Matrix4* m_unk0xa0; // 0xa0
// SYNTHETIC: LEGO1 0x10068650
// LegoAnimPresenter::`scalar deleting destructor'
public:
float m_unk0xa4; // 0xa4
Mx3DPointFloat m_unk0xa8; // 0xa8
};
// VTABLE: LEGO1 0x100d4900
// SIZE 0xc0
class LegoLoopingAnimPresenter : public LegoAnimPresenter {
public:
// FUNCTION: BETA10 0x1005c6f0
static const char* HandlerClassName()
{
// STRING: LEGO1 0x100f0700
return "LegoLoopingAnimPresenter";
}
// FUNCTION: LEGO1 0x1000c9a0
// FUNCTION: BETA10 0x1005c6c0
const char* ClassName() const override // vtable+0x0c
{
return HandlerClassName();
}
// FUNCTION: LEGO1 0x1000c9b0
MxBool IsA(const char* p_name) const override // vtable+0x10
{
return !strcmp(p_name, ClassName()) || LegoAnimPresenter::IsA(p_name);
}
void StreamingTickle() override; // vtable+0x20
void PutFrame() override; // vtable+0x6c
// SYNTHETIC: LEGO1 0x1006d000
// LegoLoopingAnimPresenter::~LegoLoopingAnimPresenter
// SYNTHETIC: LEGO1 0x1000f440
// LegoLoopingAnimPresenter::`scalar deleting destructor'
private:
undefined4 m_unk0xbc; // 0xbc
};
class LegoAnimActor;
// VTABLE: LEGO1 0x100d9170
// SIZE 0xd8
class LegoLocomotionAnimPresenter : public LegoLoopingAnimPresenter {
public:
LegoLocomotionAnimPresenter();
~LegoLocomotionAnimPresenter() override;
// FUNCTION: BETA10 0x1005c4e0
static const char* HandlerClassName()
{
// STRING: LEGO1 0x100f06e4
return "LegoLocomotionAnimPresenter";
}
// FUNCTION: LEGO1 0x1006ce50
// FUNCTION: BETA10 0x1005c4b0
const char* ClassName() const override // vtable+0x0c
{
return HandlerClassName();
}
// FUNCTION: LEGO1 0x1006ce60
MxBool IsA(const char* p_name) const override // vtable+0x10
{
return !strcmp(p_name, ClassName()) || LegoLoopingAnimPresenter::IsA(p_name);
}
void ReadyTickle() override; // vtable+0x18
void StartingTickle() override; // vtable+0x1c
void StreamingTickle() override; // vtable+0x20
MxResult AddToManager() override; // vtable+0x34
void Destroy() override; // vtable+0x38
void EndAction() override; // vtable+0x40
void PutFrame() override; // vtable+0x6c
MxResult CreateAnim(MxStreamChunk* p_chunk) override; // vtable+0x88
void FUN_1006d680(LegoAnimActor* p_actor, MxFloat p_value);
void DecrementUnknown0xd4()
{
if (m_unk0xd4) {
--m_unk0xd4;
}
}
undefined2 GetUnknown0xd4() { return m_unk0xd4; }
// SYNTHETIC: LEGO1 0x1006cfe0
// LegoLocomotionAnimPresenter::`scalar deleting destructor'
private:
void Init();
void Destroy(MxBool p_fromDestructor);
undefined4 m_unk0xc0; // 0xc0
undefined4* m_unk0xc4; // 0xc4
LegoROIMapList* m_roiMapList; // 0xc8
MxS32 m_unk0xcc; // 0xcc
MxS32 m_unk0xd0; // 0xd0
undefined2 m_unk0xd4; // 0xd4
};
class LegoPathBoundary;
struct LegoHideAnimStructComparator {
MxBool operator()(const char* const& p_a, const char* const& p_b) const { return strcmp(p_a, p_b) < 0; }
};
// SIZE 0x08
struct LegoHideAnimStruct {
LegoPathBoundary* m_boundary; // 0x00
MxU32 m_index; // 0x04
};
typedef map<const char*, LegoHideAnimStruct, LegoHideAnimStructComparator> LegoHideAnimStructMap;
// VTABLE: LEGO1 0x100d9278
// SIZE 0xc4
class LegoHideAnimPresenter : public LegoLoopingAnimPresenter {
public:
LegoHideAnimPresenter();
~LegoHideAnimPresenter() override;
// FUNCTION: LEGO1 0x1006d860
void VTable0x8c() override {} // vtable+0x8c
// FUNCTION: LEGO1 0x1006d870
void VTable0x90() override {} // vtable+0x90
// FUNCTION: BETA10 0x1005d4a0
static const char* HandlerClassName()
{
// STRING: LEGO1 0x100f06cc
return "LegoHideAnimPresenter";
}
// FUNCTION: LEGO1 0x1006d880
// FUNCTION: BETA10 0x1005d470
const char* ClassName() const override // vtable+0x0c
{
return HandlerClassName();
}
// FUNCTION: LEGO1 0x1006d890
MxBool IsA(const char* p_name) const override // vtable+0x10
{
return !strcmp(p_name, ClassName()) || LegoAnimPresenter::IsA(p_name);
}
void ReadyTickle() override; // vtable+0x18
void StartingTickle() override; // vtable+0x18
MxResult AddToManager() override; // vtable+0x34
void Destroy() override; // vtable+0x38
void EndAction() override; // vtable+0x40
void PutFrame() override; // vtable+0x6c
void FUN_1006db40(LegoTime p_time);
// SYNTHETIC: LEGO1 0x1006d9d0
// LegoHideAnimPresenter::`scalar deleting destructor'
private:
void Init();
void Destroy(MxBool p_fromDestructor);
void FUN_1006db60(LegoTreeNode* p_node, LegoTime p_time);
void FUN_1006dc10();
void FUN_1006e3f0(LegoHideAnimStructMap& p_map, LegoTreeNode* p_node);
void FUN_1006e470(
LegoHideAnimStructMap& p_map,
LegoAnimNodeData* p_data,
const char* p_name,
LegoPathBoundary* p_boundary
);
LegoPathBoundary** m_boundaryMap; // 0xc0
};
// clang-format off
// SYNTHETIC: LEGO1 0x10068650
// LegoAnimPresenter::`scalar deleting destructor'
// TEMPLATE: LEGO1 0x100689c0
// map<char const *,char const *,LegoAnimSubstComparator,allocator<char const *> >::~map<char const *,char const *,LegoAnimSubstComparator,allocator<char const *> >
@ -208,6 +390,33 @@ class LegoAnimPresenter : public MxVideoPresenter {
// GLOBAL: LEGO1 0x100f7688
// _Tree<char const *,pair<char const * const,LegoAnimStruct>,map<char const *,LegoAnimStruct,LegoAnimStructComparator,allocator<LegoAnimStruct> >::_Kfn,LegoAnimStructComparator,allocator<LegoAnimStruct> >::_Nil
// TEMPLATE: LEGO1 0x1006ddb0
// _Tree<char const *,pair<char const * const,LegoHideAnimStruct>,map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Kfn,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::~_Tree<char const *,pair<ch
// TEMPLATE: LEGO1 0x1006de80
// _Tree<char const *,pair<char const * const,LegoHideAnimStruct>,map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Kfn,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::iterator::_Inc
// TEMPLATE: LEGO1 0x1006dec0
// _Tree<char const *,pair<char const * const,LegoHideAnimStruct>,map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Kfn,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::erase
// TEMPLATE: LEGO1 0x1006e310
// _Tree<char const *,pair<char const * const,LegoHideAnimStruct>,map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Kfn,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Erase
// TEMPLATE: LEGO1 0x1006e350
// Map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator>::~Map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator>
// TEMPLATE: LEGO1 0x1006e3a0
// map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::~map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >
// TEMPLATE: LEGO1 0x1006e6d0
// _Tree<char const *,pair<char const * const,LegoHideAnimStruct>,map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Kfn,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::iterator::_Dec
// TEMPLATE: LEGO1 0x1006e720
// _Tree<char const *,pair<char const * const,LegoHideAnimStruct>,map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Kfn,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Insert
// GLOBAL: LEGO1 0x100f768c
// _Tree<char const *,pair<char const * const,LegoHideAnimStruct>,map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Kfn,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Nil
// clang-format on
#endif // LEGOANIMPRESENTER_H

View File

@ -79,7 +79,7 @@ class LegoBuildingManager : public MxCore {
MxBool SwitchMove(LegoEntity* p_entity);
MxBool SwitchMood(LegoEntity* p_entity);
MxU32 GetAnimationId(LegoEntity* p_entity);
MxU32 GetSoundId(LegoEntity* p_entity, MxBool p_state);
MxU32 GetSoundId(LegoEntity* p_entity, MxBool p_basedOnMood);
MxBool DecrementCounter(LegoEntity* p_entity);
MxBool DecrementCounter(MxS32 p_index);
MxBool DecrementCounter(LegoBuildingInfo* p_data);

View File

@ -48,10 +48,13 @@ typedef set<LegoCacheSoundEntry, Set100d6b4cComparator> Set100d6b4c;
typedef list<LegoCacheSoundEntry> List100d6b4c;
// VTABLE: LEGO1 0x100d6b4c
// VTABLE: BETA10 0x101becac
// SIZE 0x20
class LegoCacheSoundManager {
public:
// FUNCTION: BETA10 0x100d0a60
LegoCacheSoundManager() {}
~LegoCacheSoundManager();
virtual MxResult Tickle(); // vtable+0x00
@ -68,6 +71,9 @@ class LegoCacheSoundManager {
List100d6b4c m_list; // 0x14
};
// SYNTHETIC: BETA10 0x100d06b0
// LegoCacheSoundManager::`scalar deleting destructor'
// TODO: Function names subject to change.
// clang-format off

View File

@ -38,17 +38,17 @@ class LegoCameraController : public LegoPointOfViewController {
virtual MxResult Create(); // vtable+0x44
void SetWorldTransform(const Vector3& p_at, const Vector3& p_dir, const Vector3& p_up);
void FUN_10012290(float p_angle);
void FUN_10012320(float p_angle);
MxResult FUN_100123b0(Matrix4& p_matrix);
void FUN_100123e0(const Matrix4& p_transform, MxU32 p_und);
void RotateZ(float p_angle);
void RotateY(float p_angle);
MxResult GetPointOfView(Matrix4& p_matrix);
void TransformPointOfView(const Matrix4& p_transform, MxU32 p_multiply);
Mx3DPointFloat GetWorldUp();
Mx3DPointFloat GetWorldLocation();
Mx3DPointFloat GetWorldDirection();
private:
MxMatrix m_matrix1; // 0x38
MxMatrix m_matrix2; // 0x80
MxMatrix m_currentTransform; // 0x38
MxMatrix m_originalTransform; // 0x80
};
// SYNTHETIC: LEGO1 0x10011f50

View File

@ -137,11 +137,11 @@ class LegoCarBuild : public LegoWorld {
void FUN_10022f00();
void FUN_10022f30();
void FUN_10023130(MxLong p_x, MxLong p_y);
void FUN_100236d0();
void AddSelectedPartToBuild();
undefined4 FUN_10024250(LegoEventNotificationParam* p_param);
void FUN_100243a0();
undefined4 FUN_10024480(MxActionNotificationParam* p_param);
undefined4 FUN_100244e0(MxLong p_x, MxLong p_y);
undefined4 SelectPartFromMousePosition(MxLong p_x, MxLong p_y);
undefined4 FUN_100246e0(MxLong p_x, MxLong p_y);
MxS32 FUN_10024850(MxLong p_x, MxLong p_y);
undefined4 FUN_10024890(MxParam* p_param);
@ -184,7 +184,7 @@ class LegoCarBuild : public LegoWorld {
MxU8 m_unk0x109; // 0x109
MxU16 m_unk0x10a; // 0x10a
Uint64 m_unk0x10c; // 0x10c
LegoROI* m_unk0x110; // 0x110
LegoROI* m_selectedPart; // 0x110
BoundingSphere m_unk0x114; // 0x114
MxMatrix m_unk0x12c; // 0x12c
undefined m_unk0x174; // 0x174
@ -202,10 +202,10 @@ class LegoCarBuild : public LegoWorld {
MxS32 m_unk0x290[2]; // 0x290
MxS32 m_unk0x298[2]; // 0x298
MxFloat m_unk0x2a0; // 0x2a0
Mx4DPointFloat m_unk0x2a4; // 0x2a4
Mx4DPointFloat m_unk0x2bc; // 0x2bc
MxBool m_unk0x2d4; // 0x2d4
MxFloat m_unk0x2a0; // 0x2a0
Mx4DPointFloat m_unk0x2a4; // 0x2a4
Mx4DPointFloat m_unk0x2bc; // 0x2bc
MxBool m_selectedPartIsPlaced; // 0x2d4
// variable names verified by BETA10 0x1006b27a
MxStillPresenter* m_ColorBook_Bitmap; // 0x2dc

View File

@ -77,11 +77,11 @@ class LegoCarBuildAnimPresenter : public LegoAnimPresenter {
void FUN_10079050(MxS16 p_index);
void SwapNodesByName(LegoChar* p_param1, LegoChar* p_param2);
void InitBuildPlatform();
void FUN_100795d0(LegoChar* p_param);
void FUN_10079680(LegoChar* p_param);
void HideBuildPartByName(LegoChar* p_param);
void ShowBuildPartByName(LegoChar* p_param);
LegoAnimNodeData* FindNodeDataByName(LegoTreeNode* p_treeNode, const LegoChar* p_name);
LegoTreeNode* FindNodeByName(LegoTreeNode* p_treeNode, const LegoChar* p_name);
void FUN_10079790(const LegoChar* p_name);
void AddPartToBuildByName(const LegoChar* p_name);
void RotateAroundYAxis(MxFloat p_angle);
MxBool FUN_10079c30(const LegoChar* p_name);
MxBool PartIsPlaced(const LegoChar* p_name);

View File

@ -48,6 +48,7 @@ struct LegoActorInfo;
typedef map<char*, LegoCharacter*, LegoCharacterComparator> LegoCharacterMap;
// VTABLE: LEGO1 0x100da878
// VTABLE: BETA10 0x101bc028
// SIZE 0x24
class CustomizeAnimFileVariable : public MxVariable {
public:
@ -88,7 +89,7 @@ class LegoCharacterManager {
MxBool SwitchMove(LegoROI* p_roi);
MxBool SwitchMood(LegoROI* p_roi);
MxU32 GetAnimationId(LegoROI* p_roi);
MxU32 GetSoundId(LegoROI* p_roi, MxBool p_und);
MxU32 GetSoundId(LegoROI* p_roi, MxBool p_basedOnMood);
MxU8 GetMood(LegoROI* p_roi);
LegoROI* CreateAutoROI(const char* p_name, const char* p_lodName, MxBool p_createEntity);
MxResult UpdateBoundingSphereAndBox(LegoROI* p_roi);

View File

@ -24,11 +24,11 @@ class LegoControlManagerNotificationParam : public LegoEventNotificationParam {
void SetClickedObjectId(MxS32 p_clickedObjectId) { m_clickedObjectId = p_clickedObjectId; }
void SetClickedAtom(const char* p_clickedAtom) { m_clickedAtom = p_clickedAtom; }
void SetUnknown0x28(MxS16 p_unk0x28) { m_unk0x28 = p_unk0x28; }
void SetEnabledChild(MxS16 p_enabledChild) { m_enabledChild = p_enabledChild; }
MxS32 m_clickedObjectId; // 0x20
const char* m_clickedAtom; // 0x24
MxS16 m_unk0x28; // 0x28
MxS16 m_enabledChild; // 0x28
};
// SYNTHETIC: LEGO1 0x10028bf0
@ -66,27 +66,33 @@ class LegoControlManager : public MxCore {
return !strcmp(p_name, LegoControlManager::ClassName()) || MxCore::IsA(p_name);
}
void FUN_10028df0(MxPresenterList* p_presenterList);
void SetPresenterList(MxPresenterList* p_presenterList);
void Register(MxCore* p_listener);
void Unregister(MxCore* p_listener);
MxBool FUN_10029210(LegoEventNotificationParam& p_param, MxPresenter* p_presenter);
void FUN_100293c0(MxU32 p_objectId, const char* p_atom, MxS16 p_unk0x4e);
MxControlPresenter* FUN_100294e0(MxS32 p_x, MxS32 p_y);
MxBool FUN_10029630();
MxBool FUN_10029750();
void FUN_100292e0();
MxBool HandleButtonDown(LegoEventNotificationParam& p_param, MxPresenter* p_presenter);
void UpdateEnabledChild(MxU32 p_objectId, const char* p_atom, MxS16 p_enabledChild);
MxControlPresenter* GetControlAt(MxS32 p_x, MxS32 p_y);
MxBool HandleButtonDown();
MxBool HandleButtonUp();
void Notify();
undefined4 GetUnknown0x0c() { return m_unk0x0c; }
undefined GetUnknown0x10() { return m_unk0x10; }
MxU32 HandleUpNextTickle() { return m_handleUpNextTickle; }
MxBool IsSecondButtonDown() { return m_secondButtonDown; }
// SYNTHETIC: LEGO1 0x10028d40
// LegoControlManager::`scalar deleting destructor'
private:
undefined4 m_unk0x08; // 0x08
undefined4 m_unk0x0c; // 0x0c
MxBool m_unk0x10; // 0x10
MxPresenter* m_unk0x14; // 0x14
enum {
e_idle = 0,
e_waitNextTickle = 1,
e_tickled = 2,
};
MxU32 m_buttonDownState; // 0x08
MxU32 m_handleUpNextTickle; // 0x0c
MxBool m_secondButtonDown; // 0x10
MxPresenter* m_handledPresenter; // 0x14
LegoControlManagerNotificationParam m_event; // 0x18
MxPresenterList* m_presenterList; // 0x44
LegoNotifyList m_notifyList; // 0x48

View File

@ -28,7 +28,7 @@ class LegoEntity : public MxEntity {
};
enum {
c_altBit1 = 0x01
c_disabled = 0x01
};
LegoEntity() { Init(); }
@ -68,13 +68,13 @@ class LegoEntity : public MxEntity {
// FUNCTION: BETA10 0x10013260
virtual void SetWorldSpeed(MxFloat p_worldSpeed) { m_worldSpeed = p_worldSpeed; } // vtable+0x30
virtual void ClickSound(MxBool p_und); // vtable+0x34
virtual void ClickAnimation(); // vtable+0x38
virtual void SwitchVariant(); // vtable+0x3c
virtual void SwitchSound(); // vtable+0x40
virtual void SwitchMove(); // vtable+0x44
virtual void SwitchColor(LegoROI* p_roi); // vtable+0x48
virtual void SwitchMood(); // vtable+0x4c
virtual void ClickSound(MxBool p_basedOnMood); // vtable+0x34
virtual void ClickAnimation(); // vtable+0x38
virtual void SwitchVariant(); // vtable+0x3c
virtual void SwitchSound(); // vtable+0x40
virtual void SwitchMove(); // vtable+0x44
virtual void SwitchColor(LegoROI* p_roi); // vtable+0x48
virtual void SwitchMood(); // vtable+0x4c
void FUN_10010c30();
void SetType(MxU8 p_type);
@ -83,7 +83,7 @@ class LegoEntity : public MxEntity {
Mx3DPointFloat GetWorldUp();
Mx3DPointFloat GetWorldPosition();
MxBool GetUnknown0x10IsSet(MxU8 p_flag) { return m_unk0x10 & p_flag; }
MxBool IsInteraction(MxU8 p_flag) { return m_interaction & p_flag; }
MxBool GetFlagsIsSet(MxU8 p_flag) { return m_flags & p_flag; }
MxU8 GetFlags() { return m_flags; }
@ -101,14 +101,14 @@ class LegoEntity : public MxEntity {
void SetFlags(MxU8 p_flags) { m_flags = p_flags; }
void SetFlag(MxU8 p_flag) { m_flags |= p_flag; }
void ClearFlag(MxU8 p_flag) { m_flags &= ~p_flag; }
void SetUnknown0x10Flag(MxU8 p_flag) { m_unk0x10 |= p_flag; }
void ClearUnknown0x10Flag(MxU8 p_flag) { m_unk0x10 &= ~p_flag; }
void SetInteractionFlag(MxU8 p_flag) { m_interaction |= p_flag; }
void ClearInteractionFlag(MxU8 p_flag) { m_interaction &= ~p_flag; }
protected:
void Init();
void SetWorld();
MxU8 m_unk0x10; // 0x10
MxU8 m_interaction; // 0x10
MxU8 m_flags; // 0x11
Mx3DPointFloat m_worldLocation; // 0x14
Mx3DPointFloat m_worldDirection; // 0x28

View File

@ -18,6 +18,7 @@ class LegoEventNotificationParam : public MxNotificationParam {
c_rButtonState = 2,
c_modKey1 = 4,
c_modKey2 = 8,
c_motionHandled = 16,
};
// FUNCTION: LEGO1 0x10028690

View File

@ -30,6 +30,7 @@ struct InternationalCharacter {
};
// VTABLE: LEGO1 0x100d74a8
// VTABLE: BETA10 0x101bc4f0
// SIZE 0x30
class LegoBackgroundColor : public MxVariable {
public:
@ -50,9 +51,11 @@ class LegoBackgroundColor : public MxVariable {
};
// VTABLE: LEGO1 0x100d74b8
// VTABLE: BETA10 0x101bc500
// SIZE 0x24
class LegoFullScreenMovie : public MxVariable {
public:
LegoFullScreenMovie();
LegoFullScreenMovie(const char* p_key, const char* p_value);
void SetValue(const char* p_option) override; // vtable+0x04
@ -110,19 +113,19 @@ class LegoGameState {
e_dunecarbuild,
e_jetskibuild,
e_racecarbuild,
e_unk40,
e_helicopterSpawn,
e_unk41,
e_unk42,
e_unk43,
e_unk44,
e_unk45,
e_dunebuggySpawn,
e_racecarSpawn,
e_jetskiSpawn,
e_act2main,
e_act3script,
e_unk48,
e_unk49,
e_unk50,
e_unk51,
e_unk52,
e_towTrackHookedUp,
e_jukeboxw,
e_jukeboxExterior,
e_unk55,

View File

@ -1,111 +0,0 @@
#ifndef LEGOHIDEANIMPRESENTER_H
#define LEGOHIDEANIMPRESENTER_H
#include "decomp.h"
#include "legoloopinganimpresenter.h"
class LegoPathBoundary;
struct LegoHideAnimStructComparator {
MxBool operator()(const char* const& p_a, const char* const& p_b) const { return strcmp(p_a, p_b) < 0; }
};
// SIZE 0x08
struct LegoHideAnimStruct {
LegoPathBoundary* m_boundary; // 0x00
MxU32 m_index; // 0x04
};
typedef map<const char*, LegoHideAnimStruct, LegoHideAnimStructComparator> LegoHideAnimStructMap;
// VTABLE: LEGO1 0x100d9278
// SIZE 0xc4
class LegoHideAnimPresenter : public LegoLoopingAnimPresenter {
public:
LegoHideAnimPresenter();
~LegoHideAnimPresenter() override;
// FUNCTION: LEGO1 0x1006d860
void VTable0x8c() override {} // vtable+0x8c
// FUNCTION: LEGO1 0x1006d870
void VTable0x90() override {} // vtable+0x90
// FUNCTION: BETA10 0x1005d4a0
static const char* HandlerClassName()
{
// STRING: LEGO1 0x100f06cc
return "LegoHideAnimPresenter";
}
// FUNCTION: LEGO1 0x1006d880
// FUNCTION: BETA10 0x1005d470
const char* ClassName() const override // vtable+0x0c
{
return HandlerClassName();
}
// FUNCTION: LEGO1 0x1006d890
MxBool IsA(const char* p_name) const override // vtable+0x10
{
return !strcmp(p_name, ClassName()) || LegoAnimPresenter::IsA(p_name);
}
void ReadyTickle() override; // vtable+0x18
void StartingTickle() override; // vtable+0x18
MxResult AddToManager() override; // vtable+0x34
void Destroy() override; // vtable+0x38
void EndAction() override; // vtable+0x40
void PutFrame() override; // vtable+0x6c
void FUN_1006db40(LegoTime p_time);
private:
void Init();
void Destroy(MxBool p_fromDestructor);
void FUN_1006db60(LegoTreeNode* p_node, LegoTime p_time);
void FUN_1006dc10();
void FUN_1006e3f0(LegoHideAnimStructMap& p_map, LegoTreeNode* p_node);
void FUN_1006e470(
LegoHideAnimStructMap& p_map,
LegoAnimNodeData* p_data,
const char* p_name,
LegoPathBoundary* p_boundary
);
LegoPathBoundary** m_boundaryMap; // 0xc0
};
// clang-format off
// SYNTHETIC: LEGO1 0x1006d9d0
// LegoHideAnimPresenter::`scalar deleting destructor'
// TEMPLATE: LEGO1 0x1006ddb0
// _Tree<char const *,pair<char const * const,LegoHideAnimStruct>,map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Kfn,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::~_Tree<char const *,pair<ch
// TEMPLATE: LEGO1 0x1006de80
// _Tree<char const *,pair<char const * const,LegoHideAnimStruct>,map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Kfn,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::iterator::_Inc
// TEMPLATE: LEGO1 0x1006dec0
// _Tree<char const *,pair<char const * const,LegoHideAnimStruct>,map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Kfn,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::erase
// TEMPLATE: LEGO1 0x1006e310
// _Tree<char const *,pair<char const * const,LegoHideAnimStruct>,map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Kfn,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Erase
// TEMPLATE: LEGO1 0x1006e350
// Map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator>::~Map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator>
// TEMPLATE: LEGO1 0x1006e3a0
// map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::~map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >
// TEMPLATE: LEGO1 0x1006e6d0
// _Tree<char const *,pair<char const * const,LegoHideAnimStruct>,map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Kfn,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::iterator::_Dec
// TEMPLATE: LEGO1 0x1006e720
// _Tree<char const *,pair<char const * const,LegoHideAnimStruct>,map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Kfn,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Insert
// GLOBAL: LEGO1 0x100f768c
// _Tree<char const *,pair<char const * const,LegoHideAnimStruct>,map<char const *,LegoHideAnimStruct,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Kfn,LegoHideAnimStructComparator,allocator<LegoHideAnimStruct> >::_Nil
// clang-format on
#endif // LEGOHIDEANIMPRESENTER_H

View File

@ -8,6 +8,7 @@
#include "mxpresenter.h"
#include "mxqueue.h"
#include <SDL3/SDL_haptic.h>
#include <SDL3/SDL_joystick.h>
#include <SDL3/SDL_keyboard.h>
#include <SDL3/SDL_keycode.h>
@ -18,12 +19,15 @@
#include <windows.h>
#endif
#include <map>
#include <variant>
class LegoCameraController;
class LegoControlManager;
class LegoWorld;
extern MxS32 g_unk0x100f31b0;
extern const char* g_unk0x100f31b4;
extern MxS32 g_clickedObjectId;
extern const char* g_clickedAtom;
// VTABLE: LEGO1 0x100d87b8
// class MxCollection<LegoEventNotificationParam>
@ -89,6 +93,13 @@ class LegoInputManager : public MxPresenter {
c_upOrDown = c_up | c_down
};
enum TouchScheme {
e_none = -1,
e_mouse = 0,
e_arrowKeys,
e_gamepad,
};
LegoInputManager();
~LegoInputManager() override;
@ -108,7 +119,7 @@ class LegoInputManager : public MxPresenter {
MxResult Create(HWND p_hwnd);
void Destroy() override;
MxResult GetJoystick();
LEGO1_EXPORT MxResult GetJoystick();
MxResult GetJoystickState(MxU32* p_joystickX, MxU32* p_joystickY, MxU32* p_povPosition);
void StartAutoDragTimer();
void StopAutoDragTimer();
@ -121,9 +132,8 @@ class LegoInputManager : public MxPresenter {
void SetUnknown88(MxBool p_unk0x88) { m_unk0x88 = p_unk0x88; }
void SetUnknown335(MxBool p_unk0x335) { m_unk0x335 = p_unk0x335; }
void SetUnknown336(MxBool p_unk0x336) { m_unk0x336 = p_unk0x336; }
void SetUseJoystick(MxBool p_useJoystick) { m_useJoystick = p_useJoystick; }
void SetJoystickIndex(MxS32 p_joystickIndex) { m_joystickIndex = p_joystickIndex; }
// FUNCTION: BETA10 0x1002e290
void DisableInputProcessing()
{
m_unk0x88 = TRUE;
@ -144,11 +154,31 @@ class LegoInputManager : public MxPresenter {
void GetKeyboardState();
MxResult GetNavigationKeyStates(MxU32& p_keyFlags);
MxResult GetNavigationTouchStates(MxU32& p_keyFlags);
LEGO1_EXPORT void AddKeyboard(SDL_KeyboardID p_keyboardID);
LEGO1_EXPORT void RemoveKeyboard(SDL_KeyboardID p_keyboardID);
LEGO1_EXPORT void AddMouse(SDL_MouseID p_mouseID);
LEGO1_EXPORT void RemoveMouse(SDL_MouseID p_mouseID);
LEGO1_EXPORT void AddJoystick(SDL_JoystickID p_joystickID);
LEGO1_EXPORT void RemoveJoystick(SDL_JoystickID p_joystickID);
LEGO1_EXPORT MxBool HandleTouchEvent(SDL_Event* p_event, TouchScheme p_touchScheme);
LEGO1_EXPORT MxBool
HandleRumbleEvent(float p_strength, float p_lowFrequencyRumble, float p_highFrequencyRumble, MxU32 p_milliseconds);
LEGO1_EXPORT void UpdateLastInputMethod(SDL_Event* p_event);
const auto& GetLastInputMethod() { return m_lastInputMethod; }
// clang-format off
enum class SDL_KeyboardID_v : SDL_KeyboardID {};
enum class SDL_MouseID_v : SDL_MouseID {};
enum class SDL_JoystickID_v : SDL_JoystickID {};
enum class SDL_TouchID_v : SDL_TouchID {};
// clang-format on
// SYNTHETIC: LEGO1 0x1005b8d0
// LegoInputManager::`scalar deleting destructor'
private:
void InitializeHaptics();
MxCriticalSection m_criticalSection; // 0x58
LegoNotifyList* m_keyboardNotifyList; // 0x5c
LegoCameraController* m_camera; // 0x60
@ -165,12 +195,18 @@ class LegoInputManager : public MxPresenter {
MxBool m_unk0x88; // 0x88
const bool* m_keyboardState;
MxBool m_unk0x195; // 0x195
SDL_JoystickID* m_joyids;
SDL_Joystick* m_joystick;
MxS32 m_joystickIndex; // 0x19c
MxBool m_useJoystick; // 0x334
MxBool m_unk0x335; // 0x335
MxBool m_unk0x336; // 0x336
MxBool m_unk0x335; // 0x335
MxBool m_unk0x336; // 0x336
TouchScheme m_touchScheme = e_none;
SDL_Point m_touchVirtualThumb = {0, 0};
SDL_FPoint m_touchVirtualThumbOrigin;
std::map<SDL_FingerID, MxU32> m_touchFlags;
std::map<SDL_KeyboardID, std::pair<void*, void*>> m_keyboards;
std::map<SDL_MouseID, std::pair<void*, SDL_Haptic*>> m_mice;
std::map<SDL_JoystickID, std::pair<SDL_Gamepad*, SDL_Haptic*>> m_joysticks;
std::map<SDL_HapticID, SDL_Haptic*> m_otherHaptics;
std::variant<SDL_KeyboardID_v, SDL_MouseID_v, SDL_JoystickID_v, SDL_TouchID_v> m_lastInputMethod;
};
// TEMPLATE: LEGO1 0x10028850

View File

@ -1,71 +0,0 @@
#ifndef LEGOLOCOMOTIONANIMPRESENTER_H
#define LEGOLOCOMOTIONANIMPRESENTER_H
#include "legoloopinganimpresenter.h"
#include "legoroimaplist.h"
class LegoAnimActor;
// VTABLE: LEGO1 0x100d9170
// SIZE 0xd8
class LegoLocomotionAnimPresenter : public LegoLoopingAnimPresenter {
public:
LegoLocomotionAnimPresenter();
~LegoLocomotionAnimPresenter() override;
// FUNCTION: BETA10 0x1005c4e0
static const char* HandlerClassName()
{
// STRING: LEGO1 0x100f06e4
return "LegoLocomotionAnimPresenter";
}
// FUNCTION: LEGO1 0x1006ce50
// FUNCTION: BETA10 0x1005c4b0
const char* ClassName() const override // vtable+0x0c
{
return HandlerClassName();
}
// FUNCTION: LEGO1 0x1006ce60
MxBool IsA(const char* p_name) const override // vtable+0x10
{
return !strcmp(p_name, ClassName()) || LegoLoopingAnimPresenter::IsA(p_name);
}
void ReadyTickle() override; // vtable+0x18
void StartingTickle() override; // vtable+0x1c
void StreamingTickle() override; // vtable+0x20
MxResult AddToManager() override; // vtable+0x34
void Destroy() override; // vtable+0x38
void EndAction() override; // vtable+0x40
void PutFrame() override; // vtable+0x6c
MxResult CreateAnim(MxStreamChunk* p_chunk) override; // vtable+0x88
// SYNTHETIC: LEGO1 0x1006cfe0
// LegoLocomotionAnimPresenter::`scalar deleting destructor'
void FUN_1006d680(LegoAnimActor* p_actor, MxFloat p_value);
void DecrementUnknown0xd4()
{
if (m_unk0xd4) {
--m_unk0xd4;
}
}
undefined2 GetUnknown0xd4() { return m_unk0xd4; }
private:
void Init();
void Destroy(MxBool p_fromDestructor);
undefined4 m_unk0xc0; // 0xc0
undefined4* m_unk0xc4; // 0xc4
LegoROIMapList* m_roiMapList; // 0xc8
MxS32 m_unk0xcc; // 0xcc
MxS32 m_unk0xd0; // 0xd0
undefined2 m_unk0xd4; // 0xd4
};
#endif // LEGOLOCOMOTIONANIMPRESENTER_H

View File

@ -1,43 +0,0 @@
#ifndef LEGOLOOPINGANIMPRESENTER_H
#define LEGOLOOPINGANIMPRESENTER_H
#include "legoanimpresenter.h"
// VTABLE: LEGO1 0x100d4900
// SIZE 0xc0
class LegoLoopingAnimPresenter : public LegoAnimPresenter {
public:
// FUNCTION: BETA10 0x1005c6f0
static const char* HandlerClassName()
{
// STRING: LEGO1 0x100f0700
return "LegoLoopingAnimPresenter";
}
// FUNCTION: LEGO1 0x1000c9a0
// FUNCTION: BETA10 0x1005c6c0
const char* ClassName() const override // vtable+0x0c
{
return HandlerClassName();
}
// FUNCTION: LEGO1 0x1000c9b0
MxBool IsA(const char* p_name) const override // vtable+0x10
{
return !strcmp(p_name, ClassName()) || LegoAnimPresenter::IsA(p_name);
}
void StreamingTickle() override; // vtable+0x20
void PutFrame() override; // vtable+0x6c
private:
undefined4 m_unk0xbc; // 0xbc
};
// SYNTHETIC: LEGO1 0x1006d000
// LegoLoopingAnimPresenter::~LegoLoopingAnimPresenter
// SYNTHETIC: LEGO1 0x1000f440
// LegoLoopingAnimPresenter::`scalar deleting destructor'
#endif // LEGOLOOPINGANIMPRESENTER_H

View File

@ -134,7 +134,7 @@ class LegoOmni : public MxOmni {
LegoROI* FindROI(const char* p_name);
void AddWorld(LegoWorld* p_world);
void DeleteWorld(LegoWorld* p_world);
void FUN_1005b4f0(MxBool p_disable, MxU16 p_flags);
void Disable(MxBool p_disable, MxU16 p_flags);
LEGO1_EXPORT void CreateBackgroundAudio();
LEGO1_EXPORT void RemoveWorld(const MxAtomId& p_atom, MxLong p_objectId);
MxResult RegisterWorlds();
@ -185,8 +185,8 @@ class LegoOmni : public MxOmni {
// FUNCTION: BETA10 0x100d55c0
void SetExit(MxBool p_exit) { m_exit = p_exit; }
MxResult StartActionIfUnknown0x13c(MxDSAction& p_dsAction) { return m_unk0x13c ? Start(&p_dsAction) : SUCCESS; }
void SetUnknown13c(MxBool p_unk0x13c) { m_unk0x13c = p_unk0x13c; }
MxResult StartActionIfInitialized(MxDSAction& p_dsAction) { return m_initialized ? Start(&p_dsAction) : SUCCESS; }
void SetInitialized(MxBool p_unk0x13c) { m_initialized = p_unk0x13c; }
void CloseMainWindow()
{
@ -200,6 +200,9 @@ class LegoOmni : public MxOmni {
SDL_PushEvent(&event);
}
void SetVersion10(MxBool p_version10) { m_version10 = p_version10; }
MxBool IsVersion10() { return m_version10; }
// SYNTHETIC: LEGO1 0x10058b30
// LegoOmni::`scalar deleting destructor'
@ -221,9 +224,10 @@ class LegoOmni : public MxOmni {
MxDSAction m_action; // 0xa0
MxBackgroundAudioManager* m_bkgAudioManager; // 0x134
MxTransitionManager* m_transitionManager; // 0x138
MxBool m_version10;
public:
MxBool m_unk0x13c; // 0x13c
MxBool m_initialized; // 0x13c
};
#endif // LEGOMAIN_H

View File

@ -47,7 +47,7 @@ class LegoModelPresenter : public MxVideoPresenter {
void ReadyTickle() override; // vtable+0x18
void ParseExtra() override; // vtable+0x30
MxResult FUN_1007ff70(MxDSChunk& p_chunk, LegoEntity* p_entity, MxBool p_roiVisible, LegoWorld* p_world);
MxResult CreateROI(MxDSChunk& p_chunk, LegoEntity* p_entity, MxBool p_roiVisible, LegoWorld* p_world);
void Reset()
{

View File

@ -4,6 +4,7 @@
#include "lego1_export.h"
#include "legonamedpartlist.h"
#include "mxmediapresenter.h"
#include "viewmanager/viewlodlist.h"
// VTABLE: LEGO1 0x100d4df0
// SIZE 0x54
@ -50,10 +51,21 @@ class LegoPartPresenter : public MxMediaPresenter {
MxResult Read(MxDSChunk& p_chunk);
void Store();
static void Release()
{
for (auto* lodList : g_lodLists) {
lodList->Release();
}
g_lodLists.clear();
}
private:
void Destroy(MxBool p_fromDestructor);
LegoNamedPartList* m_parts; // 0x50
static vector<ViewLODList*> g_lodLists;
};
#endif // LEGOPARTPRESENTER_H

View File

@ -13,7 +13,7 @@ struct LegoPathEdgeContainer;
struct LegoOrientedEdge;
class LegoWEEdge;
extern MxLong g_unk0x100f3308;
extern MxLong g_timeLastHitSoundPlayed;
extern const char* g_strHIT_WALL_SOUND;
// VTABLE: LEGO1 0x100d6e28

View File

@ -75,7 +75,7 @@ class LegoPathBoundary : public LegoWEGEdge {
// _Tree<LegoPathActor *,LegoPathActor *,set<LegoPathActor *,LegoPathActorSetCompare,allocator<LegoPathActor *> >::_Kfn,LegoPathActorSetCompare,allocator<LegoPathActor *> >::erase
// TEMPLATE: LEGO1 0x1002c440
// TEMPLATE: BETA10 0x100b6480
// TEMPLATE: BETA10 0x10020480
// _Tree<LegoPathActor *,LegoPathActor *,set<LegoPathActor *,LegoPathActorSetCompare,allocator<LegoPathActor *> >::_Kfn,LegoPathActorSetCompare,allocator<LegoPathActor *> >::find
// TEMPLATE: LEGO1 0x1002c4c0
@ -190,6 +190,12 @@ class LegoPathBoundary : public LegoWEGEdge {
// TEMPLATE: BETA10 0x10082b40
// _Tree<LegoAnimPresenter *,LegoAnimPresenter *,set<LegoAnimPresenter *,LegoAnimPresenterSetCompare,allocator<LegoAnimPresenter *> >::_Kfn,LegoAnimPresenterSetCompare,allocator<LegoAnimPresenter *> >::const_iterator::operator*
// TEMPLATE: BETA10 0x100b6440
// set<LegoAnimPresenter *,LegoAnimPresenterSetCompare,allocator<LegoAnimPresenter *> >::find
// TEMPLATE: BETA10 0x100b6480
// _Tree<LegoAnimPresenter *,LegoAnimPresenter *,set<LegoAnimPresenter *,LegoAnimPresenterSetCompare,allocator<LegoAnimPresenter *> >::_Kfn,LegoAnimPresenterSetCompare,allocator<LegoAnimPresenter *> >::find
// TEMPLATE: BETA10 0x10021dc0
// ??0?$Set@PAVLegoPathActor@@ULegoPathActorSetCompare@@@@QAE@ABV0@@Z

View File

@ -42,9 +42,9 @@ class LegoPhonemePresenter : public MxFlcPresenter {
MxS32 m_rectCount; // 0x68
LegoTextureInfo* m_textureInfo; // 0x6c
MxBool m_unk0x70; // 0x70
MxBool m_reusedPhoneme; // 0x70
MxString m_roiName; // 0x74
MxBool m_unk0x84; // 0x84
MxBool m_isPartOfAnimMM; // 0x84
};
// TEMPLATE: LEGO1 0x1004eb20

View File

@ -49,12 +49,12 @@ class LEGO1_EXPORT LegoPlantManager : public MxCore {
MxBool SwitchMove(LegoEntity* p_entity);
MxBool SwitchMood(LegoEntity* p_entity);
MxU32 GetAnimationId(LegoEntity* p_entity);
MxU32 GetSoundId(LegoEntity* p_entity, MxBool p_state);
MxU32 GetSoundId(LegoEntity* p_entity, MxBool p_basedOnMood);
LegoPlantInfo* GetInfoArray(MxS32& p_length);
LegoEntity* CreatePlant(MxS32 p_index, LegoWorld* p_world, LegoOmni::World p_worldId);
MxBool DecrementCounter(LegoEntity* p_entity);
void ScheduleAnimation(LegoEntity* p_entity, MxLong p_length);
MxResult FUN_10026410();
MxResult DetermineBoundaries();
void ClearCounters();
void SetInitialCounters();
@ -77,11 +77,11 @@ class LEGO1_EXPORT LegoPlantManager : public MxCore {
static MxS32 g_maxMove[4];
static MxU32 g_maxSound;
LegoOmni::World m_worldId; // 0x08
undefined m_unk0x0c; // 0x0c
AnimEntry* m_entries[5]; // 0x10
MxS8 m_numEntries; // 0x24
LegoWorld* m_world; // 0x28
LegoOmni::World m_worldId; // 0x08
MxBool m_boundariesDetermined; // 0x0c
AnimEntry* m_entries[5]; // 0x10
MxS8 m_numEntries; // 0x24
LegoWorld* m_world; // 0x28
friend class DebugViewer;
};

View File

@ -11,7 +11,7 @@
#include "mxtypes.h"
class Act1State;
class LegoEventNotificationParam;
class LegoControlManagerNotificationParam;
class LegoPathActor;
class MxEndActionNotificationParam;
class MxNotificationParam;
@ -117,7 +117,7 @@ class LegoRace : public LegoWorld {
MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18
virtual MxLong HandleClick(LegoEventNotificationParam&) = 0; // vtable+0x6c
virtual MxLong HandleControl(LegoControlManagerNotificationParam&) = 0; // vtable+0x6c
// FUNCTION: LEGO1 0x10015b70
virtual MxLong HandlePathStruct(LegoPathStructNotificationParam&) { return 0; } // vtable+0x70

View File

@ -144,10 +144,10 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap {
MxResult VTable0x9c() override; // vtable+0x9c
virtual void SetMaxLinearVelocity(float p_maxLinearVelocity);
virtual void FUN_10012ff0(float p_param);
virtual void KickCamera(float p_param);
virtual MxU32 HandleSkeletonKicks(float p_param1);
static void FUN_10012de0();
static void InitYouCantStopSound();
static void InitSoundIndices();
// SYNTHETIC: LEGO1 0x10014240
@ -155,7 +155,7 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap {
private:
undefined m_userState; // 0x54
float m_unk0x58; // 0x58
float m_kickStart; // 0x58
Mx3DPointFloat m_unk0x5c; // 0x5c
// Names verified by BETA10 0x100cb4a9

View File

@ -44,8 +44,11 @@ class LegoCarRaceActor : public virtual LegoRaceActor {
Vector3& p_v3
) override; // vtable+0x6c
void Animate(float p_time) override; // vtable+0x70
void SwitchBoundary(LegoPathBoundary*& p_boundary, LegoOrientedEdge*& p_edge, float& p_unk0xe4)
override; // vtable+0x98
void SwitchBoundary(
LegoPathBoundary*& p_boundary,
LegoOrientedEdge*& p_edge,
float& p_unk0xe4
) override; // vtable+0x98
MxResult VTable0x9c() override; // vtable+0x9c
// LegoCarRaceActor vtable
@ -83,7 +86,7 @@ class LegoCarRaceActor : public virtual LegoRaceActor {
protected:
MxFloat m_unk0x08; // 0x08
MxU8 m_unk0x0c; // 0x0c
MxU8 m_animState; // 0x0c
// Could be a multiplier for the maximum speed when going straight
MxFloat m_unk0x10; // 0x10

View File

@ -17,15 +17,15 @@ class LegoSoundManager : public MxSoundManager {
void Destroy() override; // vtable+0x18
MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread) override; // vtable+0x30
// SYNTHETIC: LEGO1 0x10029920
// SYNTHETIC: BETA10 0x100d0660
// LegoSoundManager::`scalar deleting destructor'
void UpdateListener(const float* p_position, const float* p_direction, const float* p_up, const float* p_velocity);
// FUNCTION: BETA10 0x1000f350
LegoCacheSoundManager* GetCacheSoundManager() { return m_cacheSoundManager; }
// SYNTHETIC: LEGO1 0x10029920
// SYNTHETIC: BETA10 0x100d0660
// LegoSoundManager::`scalar deleting destructor'
private:
void Init();
void Destroy(MxBool p_fromDestructor);

View File

@ -28,9 +28,11 @@ class LegoTranInfoList : public MxPtrList<LegoTranInfo> {
// class MxPtrListCursor<LegoTranInfo>
// VTABLE: LEGO1 0x100d8d20
// VTABLE: BETA10 0x101bad70
// SIZE 0x10
class LegoTranInfoListCursor : public MxPtrListCursor<LegoTranInfo> {
public:
// FUNCTION: BETA10 0x100496d0
LegoTranInfoListCursor(LegoTranInfoList* p_list) : MxPtrListCursor<LegoTranInfo>(p_list) {}
};
@ -62,9 +64,14 @@ class LegoTranInfoListCursor : public MxPtrListCursor<LegoTranInfo> {
// MxPtrList<LegoTranInfo>::`scalar deleting destructor'
// SYNTHETIC: LEGO1 0x100612f0
// SYNTHETIC: BETA10 0x100498c0
// LegoTranInfoListCursor::`scalar deleting destructor'
// SYNTHETIC: BETA10 0x10049770
// MxPtrListCursor<LegoTranInfo>::MxPtrListCursor<LegoTranInfo>
// FUNCTION: LEGO1 0x10061360
// FUNCTION: BETA10 0x10049910
// MxPtrListCursor<LegoTranInfo>::~MxPtrListCursor<LegoTranInfo>
// SYNTHETIC: LEGO1 0x100613b0
@ -77,6 +84,7 @@ class LegoTranInfoListCursor : public MxPtrListCursor<LegoTranInfo> {
// MxListCursor<LegoTranInfo *>::~MxListCursor<LegoTranInfo *>
// FUNCTION: LEGO1 0x100614e0
// FUNCTION: BETA10 0x10049ab0
// LegoTranInfoListCursor::~LegoTranInfoListCursor
#endif // LEGOTRANINFOLIST_H

View File

@ -32,6 +32,14 @@ enum Cursor {
e_cursorNone
};
enum GameEvent {
e_hitActor,
e_skeletonKick,
e_raceFinished,
e_badEnding,
e_goodEnding
};
class BoundingSphere;
class MxAtomId;
class LegoEntity;
@ -49,28 +57,29 @@ LegoROI* PickROI(MxLong p_x, MxLong p_y);
LegoROI* PickRootROI(MxLong p_x, MxLong p_y);
void RotateY(LegoROI* p_roi, MxFloat p_angle);
MxBool SpheresIntersect(const BoundingSphere& p_sphere1, const BoundingSphere& p_sphere2);
MxBool FUN_1003ded0(MxFloat p_param1[2], MxFloat p_param2[3], MxFloat p_param3[3]);
MxBool CalculateRayOriginDirection(MxFloat p_coordinates[2], MxFloat p_direction[3], MxFloat p_origin[3]);
MxBool TransformWorldToScreen(const MxFloat p_world[3], MxFloat p_screen[4]);
MxS16 CountTotalTreeNodes(LegoTreeNode* p_node);
LegoTreeNode* GetTreeNode(LegoTreeNode* p_node, MxU32 p_index);
void FUN_1003e050(LegoAnimPresenter* p_presenter);
void CalculateViewFromAnimation(LegoAnimPresenter* p_presenter);
Extra::ActionType MatchActionString(const char*);
void InvokeAction(Extra::ActionType p_actionId, const MxAtomId& p_pAtom, MxS32 p_streamId, LegoEntity* p_sender);
void SetCameraControllerFromIsle();
void ConvertHSVToRGB(float p_h, float p_s, float p_v, float* p_rOut, float* p_bOut, float* p_gOut);
void PlayCamAnim(LegoPathActor* p_actor, MxBool p_unused, MxU32 p_location, MxBool p_bool);
void FUN_1003eda0();
void ResetViewVelocity();
MxBool RemoveFromCurrentWorld(const MxAtomId& p_atomId, MxS32 p_id);
void EnableAnimations(MxBool p_enable);
void SetAppCursor(Cursor p_cursor);
MxBool FUN_1003ef60();
MxBool CanExit();
MxBool RemoveFromWorld(MxAtomId& p_entityAtom, MxS32 p_entityId, MxAtomId& p_worldAtom, MxS32 p_worldEntityId);
MxS32 UpdateLightPosition(MxS32 p_increase);
void SetLightPosition(MxS32 p_index);
LegoNamedTexture* ReadNamedTexture(LegoStorage* p_storage);
void WriteDefaultTexture(LegoStorage* p_storage, const char* p_name);
void WriteNamedTexture(LegoStorage* p_storage, LegoNamedTexture* p_namedTexture);
void FUN_1003f930(LegoNamedTexture* p_namedTexture);
void LoadFromNamedTexture(LegoNamedTexture* p_namedTexture);
void EmitGameEvent(GameEvent p_event);
// FUNCTION: BETA10 0x100260a0
inline void StartIsleAction(IsleScript::Script p_objectId)

View File

@ -17,41 +17,60 @@ extern const char* g_varVISIBILITY;
extern const char* g_varCAMERALOCATION;
extern const char* g_varCURSOR;
extern const char* g_varWHOAMI;
extern const char* g_varDEBUG;
// VTABLE: LEGO1 0x100d86c8
// VTABLE: BETA10 0x101bc980
// SIZE 0x24
class VisibilityVariable : public MxVariable {
public:
// FUNCTION: BETA10 0x10093470
VisibilityVariable() { m_key = g_varVISIBILITY; }
void SetValue(const char* p_value) override; // vtable+0x04
};
// VTABLE: LEGO1 0x100d86b8
// VTABLE: BETA10 0x101bc990
// SIZE 0x24
class CameraLocationVariable : public MxVariable {
public:
// FUNCTION: BETA10 0x10093510
CameraLocationVariable() { m_key = g_varCAMERALOCATION; }
void SetValue(const char* p_value) override; // vtable+0x04
};
// VTABLE: LEGO1 0x100d86a8
// VTABLE: BETA10 0x101bc9a0
// SIZE 0x24
class CursorVariable : public MxVariable {
public:
// FUNCTION: BETA10 0x100935b0
CursorVariable() { m_key = g_varCURSOR; }
void SetValue(const char* p_value) override; // vtable+0x04
};
// VTABLE: LEGO1 0x100d8698
// VTABLE: BETA10 0x101bc9b0
// SIZE 0x24
class WhoAmIVariable : public MxVariable {
public:
// FUNCTION: BETA10 0x10093650
WhoAmIVariable() { m_key = g_varWHOAMI; }
void SetValue(const char* p_value) override; // vtable+0x04
};
// VTABLE: BETA10 0x101bc9c0
// SIZE 0x24
class DebugVariable : public MxVariable {
public:
// FUNCTION: BETA10 0x100936f0
DebugVariable() { m_key = g_varDEBUG; }
void SetValue(const char* p_value) override; // vtable+0x04
};
#endif // LEGOVARIABLES_H

View File

@ -1,6 +1,7 @@
#ifndef LEGOVIDEOMANAGER_H
#define LEGOVIDEOMANAGER_H
#include "cursor.h"
#include "decomp.h"
#include "lego1_export.h"
#include "legophonemelist.h"
@ -37,6 +38,7 @@ class LegoVideoManager : public MxVideoManager {
void EnableFullScreenMovie(MxBool p_enable);
LEGO1_EXPORT void EnableFullScreenMovie(MxBool p_enable, MxBool p_scale);
LEGO1_EXPORT void MoveCursor(MxS32 p_cursorX, MxS32 p_cursorY);
LEGO1_EXPORT void SetCursorBitmap(const CursorBitmap* p_cursorBitmap);
void ToggleFPS(MxBool p_visible);
MxResult Tickle() override; // vtable+0x08
@ -68,7 +70,9 @@ class LegoVideoManager : public MxVideoManager {
MxBool GetRender3D() { return m_render3d; }
double GetElapsedSeconds() { return m_elapsedSeconds; }
// FUNCTION: BETA10 0x1002e290
void SetRender3D(MxBool p_render3d) { m_render3d = p_render3d; }
void SetUnk0x554(MxBool p_unk0x554) { m_unk0x554 = p_unk0x554; }
private:

View File

@ -49,11 +49,11 @@ LegoPlantManager* PlantManager();
LegoBuildingManager* BuildingManager();
LegoTextureContainer* TextureContainer();
ViewLODListManager* GetViewLODListManager();
void FUN_10015820(MxBool p_disable, MxU16 p_flags);
void Disable(MxBool p_disable, MxU16 p_flags);
LegoROI* FindROI(const char* p_name);
void SetROIVisible(const char* p_name, MxBool p_visible);
void SetUserActor(LegoPathActor* p_userActor);
MxResult StartActionIfUnknown0x13c(MxDSAction& p_dsAction);
MxResult StartActionIfInitialized(MxDSAction& p_dsAction);
void DeleteAction();
LegoWorld* FindWorld(const MxAtomId& p_atom, MxS32 p_entityid);
MxDSAction& GetCurrentAction();

View File

@ -44,21 +44,28 @@ class MxControlPresenter : public MxCompositePresenter {
void EndAction() override; // vtable+0x40
MxBool HasTickleStatePassed(TickleState p_tickleState) override; // vtable+0x48
void Enable(MxBool p_enable) override; // vtable+0x54
virtual void VTable0x6c(MxS16 p_unk0x4e); // vtable+0x6c
virtual void UpdateEnabledChild(MxS16 p_enabledChild); // vtable+0x6c
MxBool FUN_10044480(LegoControlManagerNotificationParam* p_param, MxPresenter* p_presenter);
MxBool FUN_10044270(MxS32 p_x, MxS32 p_y, MxPresenter* p_presenter);
MxBool Notify(LegoControlManagerNotificationParam* p_param, MxPresenter* p_presenter);
MxBool CheckButtonDown(MxS32 p_x, MxS32 p_y, MxPresenter* p_presenter);
MxS16 GetUnknown0x4e() { return m_unk0x4e; }
MxS16 GetEnabledChild() { return m_enabledChild; }
private:
MxS16 m_unk0x4c; // 0x4c
MxS16 m_unk0x4e; // 0x4e
MxBool m_unk0x50; // 0x50
MxS16 m_unk0x52; // 0x52
MxS16 m_unk0x54; // 0x54
MxS16 m_unk0x56; // 0x56
MxS16* m_states; // 0x58
enum {
e_none,
e_toggle,
e_grid,
e_map,
};
MxS16 m_style; // 0x4c
MxS16 m_enabledChild; // 0x4e
MxBool m_unk0x50; // 0x50
MxS16 m_columnsOrRows; // 0x52
MxS16 m_rowsOrColumns; // 0x54
MxS16 m_stateOrCellIndex; // 0x56
MxS16* m_states; // 0x58
};
// SYNTHETIC: LEGO1 0x100440f0

View File

@ -55,6 +55,8 @@ class MxTransitionManager : public MxCore {
TransitionType GetTransitionType() { return m_mode; }
LEGO1_EXPORT static void configureMxTransitionManager(TransitionType p_transitionManagerConfig);
// SYNTHETIC: LEGO1 0x1004b9e0
// MxTransitionManager::`scalar deleting destructor'

View File

@ -12,6 +12,13 @@ class MxEndActionNotificationParam;
// SIZE 0x28
class TowTrackMissionState : public LegoState {
public:
enum {
e_none = 0,
e_started = 1,
e_hookedUp = 2,
e_hookingUp = 3,
};
TowTrackMissionState();
// FUNCTION: LEGO1 0x1004dde0
@ -126,19 +133,19 @@ class TowTrackMissionState : public LegoState {
// SYNTHETIC: LEGO1 0x1004e060
// TowTrackMissionState::`scalar deleting destructor'
undefined4 m_unk0x08; // 0x08
MxLong m_startTime; // 0x0c
MxBool m_unk0x10; // 0x10
MxS16 m_peScore; // 0x12
MxS16 m_maScore; // 0x14
MxS16 m_paScore; // 0x16
MxS16 m_niScore; // 0x18
MxS16 m_laScore; // 0x1a
MxS16 m_peHighScore; // 0x1c
MxS16 m_maHighScore; // 0x1e
MxS16 m_paHighScore; // 0x20
MxS16 m_niHighScore; // 0x22
MxS16 m_laHighScore; // 0x24
MxU32 m_state; // 0x08
MxLong m_startTime; // 0x0c
MxBool m_takingTooLong; // 0x10
MxS16 m_peScore; // 0x12
MxS16 m_maScore; // 0x14
MxS16 m_paScore; // 0x16
MxS16 m_niScore; // 0x18
MxS16 m_laScore; // 0x1a
MxS16 m_peHighScore; // 0x1c
MxS16 m_maHighScore; // 0x1e
MxS16 m_paHighScore; // 0x20
MxS16 m_niHighScore; // 0x22
MxS16 m_laHighScore; // 0x24
};
// VTABLE: LEGO1 0x100d7ee0
@ -174,10 +181,10 @@ class TowTrack : public IslePathActor {
virtual MxLong HandleEndAction(MxEndActionNotificationParam& p_param); // vtable+0xf0
void CreateState();
void FUN_1004dab0();
void Init();
void ActivateSceneActions();
void StopActions();
void FUN_1004dbe0();
void Reset();
// SYNTHETIC: LEGO1 0x1004c950
// TowTrack::`scalar deleting destructor'
@ -192,8 +199,8 @@ class TowTrack : public IslePathActor {
TowTrackMissionState* m_state; // 0x164
MxS16 m_unk0x168; // 0x168
MxS16 m_actorId; // 0x16a
MxS16 m_unk0x16c; // 0x16c
MxS16 m_unk0x16e; // 0x16e
MxS16 m_treeBlockageTriggered; // 0x16c
MxS16 m_speedComplaintTriggered; // 0x16e
IsleScript::Script m_lastAction; // 0x170
IsleScript::Script m_lastAnimation; // 0x174
MxFloat m_fuel; // 0x178

View File

@ -631,7 +631,7 @@ MxU32 Act2Actor::FUN_10019700(MxFloat p_param)
MxFloat time = p_param - (m_unk0x2c - m_shootAnim->GetDuration());
for (MxS32 i = 0; i < root->GetNumChildren(); i++) {
LegoROI::FUN_100a8e80(root->GetChild(i), matrix, time, m_shootAnim->GetROIMap());
LegoROI::ApplyAnimationTransformation(root->GetChild(i), matrix, time, m_shootAnim->GetROIMap());
}
return FALSE;

View File

@ -4,9 +4,9 @@
#include "act3ammo.h"
#include "anim/legoanim.h"
#include "define.h"
#include "legoanimpresenter.h"
#include "legobuildingmanager.h"
#include "legocachesoundmanager.h"
#include "legolocomotionanimpresenter.h"
#include "legopathedgecontainer.h"
#include "legoplantmanager.h"
#include "legoplants.h"
@ -580,7 +580,7 @@ void Act3Brickster::Animate(float p_time)
}
if (m_unk0x54 < p_time) {
((Act3*) m_world)->FUN_10072ad0(5);
((Act3*) m_world)->TriggerHitSound(5);
m_unk0x54 = p_time + 15000.0f;
}
@ -596,7 +596,7 @@ void Act3Brickster::Animate(float p_time)
assert(SoundManager()->GetCacheSoundManager());
if (m_unk0x58 >= 8) {
((Act3*) m_world)->FUN_10072ad0(6);
((Act3*) m_world)->TriggerHitSound(6);
}
else {
SoundManager()->GetCacheSoundManager()->Play("eatpz", NULL, FALSE);
@ -639,7 +639,7 @@ void Act3Brickster::Animate(float p_time)
float time = p_time - (m_unk0x50 - m_shootAnim->GetDuration());
for (MxS32 i = 0; i < root->GetNumChildren(); i++) {
LegoROI::FUN_100a8e80(root->GetChild(i), local70, time, m_shootAnim->GetROIMap());
LegoROI::ApplyAnimationTransformation(root->GetChild(i), local70, time, m_shootAnim->GetROIMap());
}
}
@ -686,7 +686,7 @@ void Act3Brickster::Animate(float p_time)
float time = p_time - (m_unk0x50 - m_shootAnim->GetDuration());
for (MxS32 i = 0; i < root->GetNumChildren(); i++) {
LegoROI::FUN_100a8e80(root->GetChild(i), locale4, time, m_shootAnim->GetROIMap());
LegoROI::ApplyAnimationTransformation(root->GetChild(i), locale4, time, m_shootAnim->GetROIMap());
}
}
@ -1187,7 +1187,7 @@ void Act3Shark::Animate(float p_time)
vec = m_unk0x3c;
LegoTreeNode* node = m_unk0x34->GetAnimTreePtr()->GetRoot();
LegoROI::FUN_100a8e80(node, mat, duration, m_unk0x34->GetROIMap());
LegoROI::ApplyAnimationTransformation(node, mat, duration, m_unk0x34->GetROIMap());
}
else {
roiMap[1] = m_unk0x38;

View File

@ -200,7 +200,7 @@ MxResult Act3Ammo::FUN_10053d30(LegoPathController* p_p, MxFloat p_unk0x19c)
// FUNCTION: LEGO1 0x10053db0
// FUNCTION: BETA10 0x1001e0f0
MxResult Act3Ammo::FUN_10053db0(float p_param1, const Matrix4& p_param2)
MxResult Act3Ammo::FUN_10053db0(float p_param1, Matrix4& p_param2)
{
float local34 = p_param1 * p_param1;
@ -378,12 +378,14 @@ void Act3Ammo::Animate(float p_time)
if (IsBit4()) {
if (IsPizza()) {
m_world->RemovePizza(*this);
m_world->FUN_10072ad0(2);
m_world->TriggerHitSound(2);
}
else {
m_world->RemoveDonut(*this);
m_world->FUN_10072ad0(4);
m_world->TriggerHitSound(4);
}
return;
}
else {
if (IsPizza()) {
@ -394,89 +396,99 @@ void Act3Ammo::Animate(float p_time)
assert(SoundManager()->GetCacheSoundManager());
SoundManager()->GetCacheSoundManager()->Play("stickdn", NULL, FALSE);
}
}
LegoPathActorSet& plpas = m_boundary->GetActors();
LegoPathActorSet lpas(plpas);
LegoPathActorSet& plpas = m_boundary->GetActors();
LegoPathActorSet lpas(plpas);
for (LegoPathActorSet::iterator itpa = lpas.begin(); itpa != lpas.end(); itpa++) {
if (plpas.find(*itpa) != plpas.end() && this != *itpa) {
LegoROI* r = (*itpa)->GetROI();
assert(r);
for (LegoPathActorSet::iterator itpa = lpas.begin(); itpa != lpas.end(); itpa++) {
if (plpas.find(*itpa) == plpas.end()) {
continue;
}
if (!strncmp(r->GetName(), "pammo", 5)) {
Mx3DPointFloat local1c8;
Mx3DPointFloat local1b4;
if (this == *itpa) {
continue;
}
local1c8 = r->GetLocal2World()[3];
local1b4 = m_roi->GetLocal2World()[3];
LegoROI* r = (*itpa)->GetROI();
assert(r);
local1b4 -= local1c8;
if (!strncmp(r->GetName(), "pammo", 5)) {
Mx3DPointFloat local1c8;
Mx3DPointFloat local1b4;
float radius = r->GetWorldBoundingSphere().Radius();
if (local1b4.LenSquared() <= radius * radius) {
MxS32 index = -1;
if (sscanf(r->GetName(), "pammo%d", &index) != 1) {
assert(0);
}
local1c8 = r->GetLocal2World()[3];
local1b4 = m_roi->GetLocal2World()[3];
assert(m_world);
local1b4 -= local1c8;
if (m_world->m_pizzas[index].IsValid() && !m_world->m_pizzas[index].IsSharkFood()) {
m_world->EatPizza(index);
m_world->m_brickster->FUN_100417c0();
}
if (IsDonut()) {
assert(SoundManager()->GetCacheSoundManager());
SoundManager()->GetCacheSoundManager()->Play("dnhitpz", NULL, FALSE);
m_world->RemoveDonut(*this);
local14 = TRUE;
break;
}
}
float radius = r->GetWorldBoundingSphere().Radius();
if (local1b4.LenSquared() <= radius * radius) {
MxS32 index = -1;
if (sscanf(r->GetName(), "pammo%d", &index) != 1) {
assert(0);
}
else if (!strncmp(r->GetName(), "dammo", 5)) {
Mx3DPointFloat local1f8;
Mx3DPointFloat local1e4;
local1f8 = r->GetLocal2World()[3];
local1e4 = m_roi->GetLocal2World()[3];
assert(m_world);
local1e4 -= local1f8;
#ifdef BETA10
m_world->EatPizza(index);
#else
if (m_world->m_pizzas[index].IsValid() && !m_world->m_pizzas[index].IsSharkFood()) {
m_world->EatPizza(index);
m_world->m_brickster->FUN_100417c0();
}
#endif
float radius = r->GetWorldBoundingSphere().Radius();
if (local1e4.LenSquared() <= radius * radius) {
MxS32 index = -1;
if (sscanf(r->GetName(), "dammo%d", &index) != 1) {
assert(0);
}
assert(m_world);
m_world->EatDonut(index);
if (IsPizza()) {
assert(SoundManager()->GetCacheSoundManager());
SoundManager()->GetCacheSoundManager()->Play("pzhitdn", NULL, FALSE);
m_world->RemovePizza(*this);
local14 = TRUE;
break;
}
}
if (IsDonut()) {
assert(SoundManager()->GetCacheSoundManager());
SoundManager()->GetCacheSoundManager()->Play("dnhitpz", NULL, FALSE);
m_world->RemoveDonut(*this);
local14 = TRUE;
break;
}
}
}
else if (!strncmp(r->GetName(), "dammo", 5)) {
Mx3DPointFloat local1f8;
Mx3DPointFloat local1e4;
if (!local14) {
if (IsPizza()) {
m_world->FUN_10073360(*this, local68);
}
else {
m_world->FUN_10073390(*this, local68);
}
local1f8 = r->GetLocal2World()[3];
local1e4 = m_roi->GetLocal2World()[3];
m_worldSpeed = -1.0f;
local1e4 -= local1f8;
float radius = r->GetWorldBoundingSphere().Radius();
if (local1e4.LenSquared() <= radius * radius) {
MxS32 index = -1;
if (sscanf(r->GetName(), "dammo%d", &index) != 1) {
assert(0);
}
assert(m_world);
m_world->EatDonut(index);
if (IsPizza()) {
assert(SoundManager()->GetCacheSoundManager());
SoundManager()->GetCacheSoundManager()->Play("pzhitdn", NULL, FALSE);
m_world->RemovePizza(*this);
local14 = TRUE;
break;
}
}
}
}
if (!local14) {
if (IsPizza()) {
m_world->FUN_10073360(*this, local68);
}
else {
m_world->FUN_10073390(*this, local68);
}
m_worldSpeed = -1.0f;
}
}
}

View File

@ -40,11 +40,11 @@ Ambulance::Ambulance()
m_state = NULL;
m_unk0x168 = 0;
m_actorId = -1;
m_unk0x16c = 0;
m_unk0x16e = 0;
m_unk0x170 = 0;
m_atPoliceTask = 0;
m_atBeachTask = 0;
m_taskState = Ambulance::e_none;
m_lastAction = IsleScript::c_noneIsle;
m_unk0x172 = 0;
m_enableRandomAudio = 0;
m_lastAnimation = IsleScript::c_noneIsle;
m_fuel = 1.0;
}
@ -73,7 +73,7 @@ MxResult Ambulance::Create(MxDSAction& p_dsAction)
m_state = (AmbulanceMissionState*) GameState()->GetState("AmbulanceMissionState");
if (!m_state) {
m_state = new AmbulanceMissionState();
m_state->m_unk0x08 = 0;
m_state->m_state = AmbulanceMissionState::e_ready;
GameState()->RegisterState(m_state);
}
}
@ -173,25 +173,25 @@ MxLong Ambulance::HandleEndAction(MxEndActionNotificationParam& p_param)
m_lastAction = IsleScript::c_noneIsle;
}
else if (objectId == IsleScript::c_hho027en_RunAnim) {
m_state->m_unk0x08 = 1;
m_state->m_state = AmbulanceMissionState::e_enteredAmbulance;
CurrentWorld()->PlaceActor(UserActor());
HandleClick();
m_unk0x172 = 0;
m_enableRandomAudio = 0;
TickleManager()->RegisterClient(this, 40000);
}
else if (objectId == IsleScript::c_hpz047pe_RunAnim || objectId == IsleScript::c_hpz048pe_RunAnim || objectId == IsleScript::c_hpz049bd_RunAnim || objectId == IsleScript::c_hpz053pa_RunAnim) {
if (m_unk0x170 == 3) {
if (m_taskState == Ambulance::e_finished) {
PlayAnimation(IsleScript::c_hpz055pa_RunAnim);
m_unk0x170 = 0;
m_taskState = Ambulance::e_none;
}
else {
PlayAnimation(IsleScript::c_hpz053pa_RunAnim);
}
}
else if (objectId == IsleScript::c_hpz050bd_RunAnim || objectId == IsleScript::c_hpz052ma_RunAnim) {
if (m_unk0x170 == 3) {
if (m_taskState == Ambulance::e_finished) {
PlayAnimation(IsleScript::c_hpz057ma_RunAnim);
m_unk0x170 = 0;
m_taskState = Ambulance::e_none;
}
else {
PlayAnimation(IsleScript::c_hpz052ma_RunAnim);
@ -201,21 +201,21 @@ MxLong Ambulance::HandleEndAction(MxEndActionNotificationParam& p_param)
CurrentWorld()->PlaceActor(UserActor());
HandleClick();
SpawnPlayer(LegoGameState::e_pizzeriaExterior, TRUE, 0);
m_unk0x172 = 0;
m_enableRandomAudio = 0;
TickleManager()->RegisterClient(this, 40000);
if (m_unk0x16c != 0) {
if (m_atPoliceTask != 0) {
StopActions();
}
}
else if (objectId == IsleScript::c_hps116bd_RunAnim || objectId == IsleScript::c_hps118re_RunAnim) {
if (objectId == IsleScript::c_hps116bd_RunAnim && m_unk0x170 != 3) {
if (objectId == IsleScript::c_hps116bd_RunAnim && m_taskState != Ambulance::e_finished) {
PlayAction(IsleScript::c_Avo923In_PlayWav);
}
if (m_unk0x170 == 3) {
if (m_taskState == Ambulance::e_finished) {
PlayAnimation(IsleScript::c_hps117bd_RunAnim);
m_unk0x170 = 0;
m_taskState = Ambulance::e_none;
}
else {
PlayAnimation(IsleScript::c_hps118re_RunAnim);
@ -225,15 +225,15 @@ MxLong Ambulance::HandleEndAction(MxEndActionNotificationParam& p_param)
CurrentWorld()->PlaceActor(UserActor());
HandleClick();
SpawnPlayer(LegoGameState::e_policeExited, TRUE, 0);
m_unk0x172 = 0;
m_enableRandomAudio = 0;
TickleManager()->RegisterClient(this, 40000);
if (m_unk0x16e != 0) {
if (m_atBeachTask != 0) {
StopActions();
}
}
else if (objectId == IsleScript::c_hho142cl_RunAnim || objectId == IsleScript::c_hho143cl_RunAnim || objectId == IsleScript::c_hho144cl_RunAnim) {
FUN_10037250();
Reset();
}
}
@ -244,18 +244,18 @@ MxLong Ambulance::HandleEndAction(MxEndActionNotificationParam& p_param)
// FUNCTION: BETA10 0x100230bf
MxLong Ambulance::HandleButtonDown(LegoControlManagerNotificationParam& p_param)
{
if (m_unk0x170 == 1) {
if (m_taskState == Ambulance::e_waiting) {
LegoROI* roi = PickROI(p_param.GetX(), p_param.GetY());
if (roi != NULL && !SDL_strcasecmp(roi->GetName(), "ps-gate")) {
m_unk0x170 = 3;
m_taskState = Ambulance::e_finished;
return 1;
}
roi = PickRootROI(p_param.GetX(), p_param.GetY());
if (roi != NULL && !SDL_strcasecmp(roi->GetName(), "gd")) {
m_unk0x170 = 3;
m_taskState = Ambulance::e_finished;
return 1;
}
}
@ -273,9 +273,9 @@ MxLong Ambulance::HandlePathStruct(LegoPathStructNotificationParam& p_param)
}
if (p_param.GetTrigger() == LegoPathStruct::c_camAnim && p_param.GetData() == 0x0b) {
if (m_unk0x16e != 0) {
if (m_unk0x16c != 0) {
m_state->m_unk0x08 = 2;
if (m_atBeachTask != 0) {
if (m_atPoliceTask != 0) {
m_state->m_state = AmbulanceMissionState::e_prepareAmbulance;
if (m_lastAction != IsleScript::c_noneIsle) {
InvokeAction(Extra::e_stop, *g_isleScript, m_lastAction, NULL);
@ -300,7 +300,7 @@ MxLong Ambulance::HandlePathStruct(LegoPathStructNotificationParam& p_param)
return 0;
}
if (m_unk0x16e != 0) {
if (m_atBeachTask != 0) {
if (m_lastAction != IsleScript::c_noneIsle) {
InvokeAction(Extra::e_stop, *g_isleScript, m_lastAction, NULL);
}
@ -310,7 +310,7 @@ MxLong Ambulance::HandlePathStruct(LegoPathStructNotificationParam& p_param)
}
}
if (m_unk0x16c != 0) {
if (m_atPoliceTask != 0) {
if (m_lastAction != IsleScript::c_noneIsle) {
InvokeAction(Extra::e_stop, *g_isleScript, m_lastAction, NULL);
}
@ -318,9 +318,9 @@ MxLong Ambulance::HandlePathStruct(LegoPathStructNotificationParam& p_param)
PlayAction(IsleScript::c_Avo915In_PlayWav);
}
}
else if (p_param.GetTrigger() == LegoPathStruct::c_s && p_param.GetData() == 0x131 && m_unk0x16e == 0) {
m_unk0x16e = 1;
m_unk0x170 = 1;
else if (p_param.GetTrigger() == LegoPathStruct::c_s && p_param.GetData() == 0x131 && m_atBeachTask == 0) {
m_atBeachTask = 1;
m_taskState = Ambulance::e_waiting;
if (m_lastAction != IsleScript::c_noneIsle) {
InvokeAction(Extra::e_stop, *g_isleScript, m_lastAction, NULL);
@ -348,9 +348,9 @@ MxLong Ambulance::HandlePathStruct(LegoPathStructNotificationParam& p_param)
break;
}
}
else if (p_param.GetTrigger() == LegoPathStruct::c_camAnim && (p_param.GetData() == 0x22 || p_param.GetData() == 0x23 || p_param.GetData() == 0x24) && m_unk0x16c == 0) {
m_unk0x16c = 1;
m_unk0x170 = 1;
else if (p_param.GetTrigger() == LegoPathStruct::c_camAnim && (p_param.GetData() == 0x22 || p_param.GetData() == 0x23 || p_param.GetData() == 0x24) && m_atPoliceTask == 0) {
m_atPoliceTask = 1;
m_taskState = Ambulance::e_waiting;
if (m_lastAction != IsleScript::c_noneIsle) {
InvokeAction(Extra::e_stop, *g_isleScript, m_lastAction, NULL);
@ -367,15 +367,15 @@ MxLong Ambulance::HandlePathStruct(LegoPathStructNotificationParam& p_param)
// FUNCTION: BETA10 0x10023506
MxLong Ambulance::HandleClick()
{
if (((Act1State*) GameState()->GetState("Act1State"))->m_unk0x018 != 10) {
if (((Act1State*) GameState()->GetState("Act1State"))->m_state != Act1State::e_ambulance) {
return 1;
}
if (m_state->m_unk0x08 == 2) {
if (m_state->m_state == AmbulanceMissionState::e_prepareAmbulance) {
return 1;
}
FUN_10015820(TRUE, 0);
Disable(TRUE, 0);
((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::e_ambulance);
TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE);
@ -390,7 +390,7 @@ MxLong Ambulance::HandleClick()
InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_AmbulanceDashboard, NULL);
ControlManager()->Register(this);
if (m_state->m_unk0x08 == 1) {
if (m_state->m_state == AmbulanceMissionState::e_enteredAmbulance) {
SpawnPlayer(LegoGameState::e_hospitalExited, TRUE, 0);
m_state->m_startTime = Timer()->GetTime();
InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_pns018rd_RunAnim, NULL);
@ -401,9 +401,9 @@ MxLong Ambulance::HandleClick()
// FUNCTION: LEGO1 0x10036e60
// FUNCTION: BETA10 0x100236bb
void Ambulance::FUN_10036e60()
void Ambulance::Init()
{
m_state->m_unk0x08 = 2;
m_state->m_state = AmbulanceMissionState::e_prepareAmbulance;
PlayAnimation(IsleScript::c_hho027en_RunAnim);
m_lastAction = IsleScript::c_noneIsle;
m_lastAnimation = IsleScript::c_noneIsle;
@ -414,7 +414,7 @@ void Ambulance::Exit()
{
GameState()->m_currentArea = LegoGameState::e_hospitalExterior;
StopActions();
FUN_10037250();
Reset();
Leave();
}
@ -440,7 +440,7 @@ MxLong Ambulance::HandleControl(LegoControlManagerNotificationParam& p_param)
{
MxLong result = 0;
if (p_param.m_unk0x28 == 1) {
if (p_param.m_enabledChild == 1) {
switch (p_param.m_clickedObjectId) {
case IsleScript::c_AmbulanceArms_Ctl:
Exit();
@ -457,7 +457,7 @@ MxLong Ambulance::HandleControl(LegoControlManagerNotificationParam& p_param)
case IsleScript::c_AmbulanceHorn_Ctl:
MxSoundPresenter* presenter =
(MxSoundPresenter*) CurrentWorld()->Find("MxSoundPresenter", "AmbulanceHorn_Sound");
presenter->Enable(p_param.m_unk0x28);
presenter->Enable(p_param.m_enabledChild);
break;
}
}
@ -470,11 +470,11 @@ void Ambulance::ActivateSceneActions()
{
PlayMusic(JukeboxScript::c_Hospital_Music);
if (m_state->m_unk0x08 == 1) {
m_state->m_unk0x08 = 0;
if (m_state->m_state == AmbulanceMissionState::e_enteredAmbulance) {
m_state->m_state = AmbulanceMissionState::e_ready;
PlayAction(IsleScript::c_ham033cl_PlayWav);
}
else if (m_unk0x16c != 0 && m_unk0x16e != 0) {
else if (m_atPoliceTask != 0 && m_atBeachTask != 0) {
IsleScript::Script objectId;
switch (SDL_rand(2)) {
@ -516,8 +516,8 @@ void Ambulance::ActivateSceneActions()
// FUNCTION: BETA10 0x100237df
MxResult Ambulance::Tickle()
{
if (m_unk0x172 == 0) {
m_unk0x172 = 1;
if (m_enableRandomAudio == 0) {
m_enableRandomAudio = 1;
}
else if (m_lastAction == IsleScript::c_noneIsle) {
IsleScript::Script objectId;
@ -574,14 +574,14 @@ void Ambulance::StopActions()
}
// FUNCTION: LEGO1 0x10037250
void Ambulance::FUN_10037250()
void Ambulance::Reset()
{
StopAction(m_lastAction);
BackgroundAudioManager()->RaiseVolume();
((Act1State*) GameState()->GetState("Act1State"))->m_unk0x018 = 0;
m_state->m_unk0x08 = 0;
m_unk0x16e = 0;
m_unk0x16c = 0;
((Act1State*) GameState()->GetState("Act1State"))->m_state = Act1State::e_none;
m_state->m_state = AmbulanceMissionState::e_ready;
m_atBeachTask = 0;
m_atPoliceTask = 0;
g_isleFlags |= Isle::c_playMusic;
AnimationManager()->EnableCamAnims(TRUE);
AnimationManager()->FUN_1005f6d0(TRUE);
@ -629,7 +629,7 @@ void Ambulance::PlayAction(IsleScript::Script p_objectId)
// FUNCTION: LEGO1 0x100373a0
AmbulanceMissionState::AmbulanceMissionState()
{
m_unk0x08 = 0;
m_state = AmbulanceMissionState::e_ready;
m_startTime = 0;
m_peScore = 0;
m_maScore = 0;

View File

@ -52,9 +52,9 @@ void Bike::Exit()
// FUNCTION: LEGO1 0x100769a0
MxLong Bike::HandleClick()
{
if (FUN_1003ef60()) {
if (CanExit()) {
Act1State* state = (Act1State*) GameState()->GetState("Act1State");
FUN_10015820(TRUE, 0);
Disable(TRUE, 0);
((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::Area::e_bike);
TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, TRUE);
@ -81,7 +81,7 @@ MxLong Bike::HandleControl(LegoControlManagerNotificationParam& p_param)
{
MxLong result = 0;
if (p_param.m_unk0x28 == 1) {
if (p_param.m_enabledChild == 1) {
switch (p_param.m_clickedObjectId) {
case IsleScript::c_BikeArms_Ctl:
Exit();
@ -97,7 +97,7 @@ MxLong Bike::HandleControl(LegoControlManagerNotificationParam& p_param)
case IsleScript::c_BikeHorn_Ctl:
MxSoundPresenter* presenter =
(MxSoundPresenter*) CurrentWorld()->Find("MxSoundPresenter", "BikeHorn_Sound");
presenter->Enable(p_param.m_unk0x28);
presenter->Enable(p_param.m_enabledChild);
break;
}
}

View File

@ -53,7 +53,7 @@ MxLong InfoCenterEntity::HandleClick(LegoEventNotificationParam& p_param)
isle->SetDestLocation(LegoGameState::Area::e_infomain);
Act1State* act1state = (Act1State*) GameState()->GetState("Act1State");
act1state->SetUnknown18(0);
act1state->SetState(Act1State::e_none);
break;
}
case LegoGameState::Act::e_act2: {
@ -80,11 +80,11 @@ MxLong InfoCenterEntity::HandleClick(LegoEventNotificationParam& p_param)
// FUNCTION: LEGO1 0x100151d0
MxLong GasStationEntity::HandleClick(LegoEventNotificationParam& p_param)
{
if (FUN_1003ef60()) {
if (CanExit()) {
Act1State* state = (Act1State*) GameState()->GetState("Act1State");
if (state->GetUnknown18() != 8) {
state->SetUnknown18(0);
if (state->GetState() != Act1State::e_towtrack) {
state->SetState(Act1State::e_none);
if (UserActor()->GetActorId() != GameState()->GetActorId()) {
((IslePathActor*) UserActor())->Exit();
@ -104,11 +104,11 @@ MxLong GasStationEntity::HandleClick(LegoEventNotificationParam& p_param)
// FUNCTION: LEGO1 0x10015270
MxLong HospitalEntity::HandleClick(LegoEventNotificationParam& p_param)
{
if (FUN_1003ef60()) {
if (CanExit()) {
Act1State* act1State = (Act1State*) GameState()->GetState("Act1State");
if (act1State->GetUnknown18() != 10) {
act1State->SetUnknown18(0);
if (act1State->GetState() != Act1State::e_ambulance) {
act1State->SetState(Act1State::e_none);
if (UserActor()->GetActorId() != GameState()->GetActorId()) {
((IslePathActor*) UserActor())->Exit();
@ -128,11 +128,11 @@ MxLong HospitalEntity::HandleClick(LegoEventNotificationParam& p_param)
// FUNCTION: LEGO1 0x10015310
MxLong PoliceEntity::HandleClick(LegoEventNotificationParam& p_param)
{
if (FUN_1003ef60()) {
if (CanExit()) {
Act1State* state = (Act1State*) GameState()->GetState("Act1State");
if (state->GetUnknown18() != 10) {
state->SetUnknown18(0);
if (state->GetState() != Act1State::e_ambulance) {
state->SetState(Act1State::e_none);
if (UserActor()->GetActorId() != GameState()->GetActorId()) {
((IslePathActor*) UserActor())->Exit();
@ -152,9 +152,9 @@ MxLong PoliceEntity::HandleClick(LegoEventNotificationParam& p_param)
// FUNCTION: LEGO1 0x100153b0
MxLong BeachHouseEntity::HandleClick(LegoEventNotificationParam& p_param)
{
if (FUN_1003ef60()) {
if (CanExit()) {
Act1State* state = (Act1State*) GameState()->GetState("Act1State");
state->SetUnknown18(0);
state->SetState(Act1State::e_none);
if (UserActor()->GetActorId() != GameState()->GetActorId()) {
((IslePathActor*) UserActor())->Exit();
@ -173,9 +173,9 @@ MxLong BeachHouseEntity::HandleClick(LegoEventNotificationParam& p_param)
// FUNCTION: LEGO1 0x10015450
MxLong RaceStandsEntity::HandleClick(LegoEventNotificationParam& p_param)
{
if (FUN_1003ef60()) {
if (CanExit()) {
Act1State* state = (Act1State*) GameState()->GetState("Act1State");
state->SetUnknown18(0);
state->SetState(Act1State::e_none);
if (UserActor()->GetActorId() != GameState()->GetActorId()) {
((IslePathActor*) UserActor())->Exit();
@ -195,7 +195,7 @@ MxLong RaceStandsEntity::HandleClick(LegoEventNotificationParam& p_param)
// FUNCTION: BETA10 0x100256e8
MxLong JailEntity::HandleClick(LegoEventNotificationParam& p_param)
{
if (FUN_1003ef60()) {
if (CanExit()) {
PlayCamAnim(UserActor(), FALSE, 18, TRUE);
}

View File

@ -45,7 +45,7 @@ MxLong BumpBouy::Notify(MxParam& p_param)
Act1State* isleState = (Act1State*) GameState()->GetState("Act1State");
assert(isleState);
isleState->m_unk0x018 = 5;
isleState->m_state = Act1State::e_transitionToJetski;
Isle* isle = (Isle*) FindWorld(*g_isleScript, IsleScript::c__Isle);
assert(isle);

View File

@ -91,11 +91,11 @@ void DuneBuggy::Exit()
// FUNCTION: LEGO1 0x10068060
MxLong DuneBuggy::HandleClick()
{
if (!FUN_1003ef60()) {
if (!CanExit()) {
return 1;
}
FUN_10015820(TRUE, 0);
Disable(TRUE, 0);
((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::Area::e_dunecar);
TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, TRUE);
@ -124,7 +124,7 @@ MxLong DuneBuggy::HandleControl(LegoControlManagerNotificationParam& p_param)
{
MxLong result = 0;
if (p_param.m_unk0x28 == 1) {
if (p_param.m_enabledChild == 1) {
switch (p_param.m_clickedObjectId) {
case IsleScript::c_DuneCarArms_Ctl:
Exit();
@ -140,7 +140,7 @@ MxLong DuneBuggy::HandleControl(LegoControlManagerNotificationParam& p_param)
case IsleScript::c_DuneCarHorn_Ctl:
MxSoundPresenter* presenter =
(MxSoundPresenter*) CurrentWorld()->Find("MxSoundPresenter", "DuneCarHorn_Sound");
presenter->Enable(p_param.m_unk0x28);
presenter->Enable(p_param.m_enabledChild);
break;
}
}

View File

@ -82,7 +82,7 @@ void Helicopter::Exit()
if (GameState()->GetCurrentAct() == LegoGameState::e_act1) {
SpawnPlayer(
LegoGameState::e_unk40,
LegoGameState::e_helicopterSpawn,
TRUE,
IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3
);
@ -121,7 +121,7 @@ void Helicopter::Exit()
// FUNCTION: BETA10 0x1002a3db
MxLong Helicopter::HandleClick()
{
if (!FUN_1003ef60()) {
if (!CanExit()) {
return 1;
}
@ -148,7 +148,7 @@ MxLong Helicopter::HandleClick()
IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3
);
((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::e_copter);
FUN_10015820(TRUE, 0);
Disable(TRUE, 0);
TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, TRUE);
SetActorState(c_disabled);
PlayMusic(JukeboxScript::c_Jail_Music);
@ -189,7 +189,7 @@ MxLong Helicopter::HandleControl(LegoControlManagerNotificationParam& p_param)
break;
}
if (p_param.m_unk0x28 == 1) {
if (p_param.m_enabledChild == 1) {
MxU32 isPizza = FALSE;
switch (p_param.m_clickedObjectId) {
@ -214,7 +214,7 @@ MxLong Helicopter::HandleControl(LegoControlManagerNotificationParam& p_param)
Act1State* act1State = (Act1State*) GameState()->GetState("Act1State");
assert(act1State);
if (m_state->m_unk0x08 == 0) {
act1State->m_unk0x018 = 4;
act1State->m_state = Act1State::e_helicopter;
m_state->m_unk0x08 = 1;
m_world->RemoveActor(this);
InvokeAction(Extra::ActionType::e_start, script, IsleScript::c_HelicopterTakeOff_Anim, NULL);
@ -318,7 +318,7 @@ MxLong Helicopter::HandleEndAnim(LegoEndAnimNotificationParam& p_param)
if (GameState()->GetCurrentAct() == LegoGameState::e_act1) {
Act1State* act1State = (Act1State*) GameState()->GetState("Act1State");
assert(act1State);
act1State->m_unk0x018 = 4;
act1State->m_state = Act1State::e_helicopter;
SpawnPlayer(
LegoGameState::e_unk42,
TRUE,
@ -359,7 +359,7 @@ MxLong Helicopter::HandleEndAnim(LegoEndAnimNotificationParam& p_param)
if (GameState()->GetCurrentAct() == LegoGameState::e_act1) {
Act1State* act1State = (Act1State*) GameState()->GetState("Act1State");
assert(act1State);
act1State->m_unk0x018 = 0;
act1State->m_state = Act1State::e_none;
SpawnPlayer(
LegoGameState::e_unk41,
TRUE,
@ -426,7 +426,7 @@ void Helicopter::Animate(float p_time)
v2 *= f2;
v2 += v1;
m_world->GetCameraController()->FUN_100123e0(mat, 0);
m_world->GetCameraController()->TransformPointOfView(mat, 0);
}
else {
if (m_state->m_unk0x08 == 4) {
@ -459,7 +459,7 @@ void Helicopter::FUN_100042a0(const Matrix4& p_matrix)
// the typecast makes this function match for unknown reasons
Vector3 vec6((const float*) m_unk0x1a8[3]); // locala0 // esp+0x28
m_world->GetCameraController()->FUN_100123b0(local48);
m_world->GetCameraController()->GetPointOfView(local48);
m_unk0x1a8.SetIdentity();
local90 = p_matrix;

View File

@ -153,7 +153,7 @@ void IslePathActor::Exit()
FUN_1001b660();
FUN_10010c30();
FUN_1003eda0();
ResetViewVelocity();
}
// GLOBAL: LEGO1 0x10102b28
@ -355,7 +355,7 @@ void IslePathActor::RegisterSpawnLocations()
JukeboxScript::c_PoliceStation_Music
);
g_spawnLocations[16] = SpawnLocation(
LegoGameState::e_unk40,
LegoGameState::e_helicopterSpawn,
g_isleScript,
0,
"edg02_51",
@ -379,7 +379,7 @@ void IslePathActor::RegisterSpawnLocations()
JukeboxScript::c_noneJukebox
);
g_spawnLocations[18] = SpawnLocation(
LegoGameState::e_unk43,
LegoGameState::e_dunebuggySpawn,
g_isleScript,
0,
"edg02_35",
@ -391,7 +391,7 @@ void IslePathActor::RegisterSpawnLocations()
JukeboxScript::c_noneJukebox
);
g_spawnLocations[19] = SpawnLocation(
LegoGameState::e_unk44,
LegoGameState::e_racecarSpawn,
g_isleScript,
0,
"EDG03_01",
@ -403,7 +403,7 @@ void IslePathActor::RegisterSpawnLocations()
JukeboxScript::c_noneJukebox
);
g_spawnLocations[20] = SpawnLocation(
LegoGameState::e_unk45,
LegoGameState::e_jetskiSpawn,
g_isleScript,
0,
"edg10_70",
@ -475,7 +475,7 @@ void IslePathActor::RegisterSpawnLocations()
JukeboxScript::c_noneJukebox
);
g_spawnLocations[26] = SpawnLocation(
LegoGameState::e_unk52,
LegoGameState::e_towTrackHookedUp,
g_isleScript,
0,
"edg02_19",
@ -598,7 +598,7 @@ void IslePathActor::SpawnPlayer(LegoGameState::Area p_area, MxBool p_enter, MxU8
}
if (m_cameraFlag) {
FUN_1003eda0();
ResetViewVelocity();
}
if (p_flags & c_playMusic && g_spawnLocations[i].m_music != JukeboxScript::c_noneJukebox) {
@ -632,7 +632,7 @@ void IslePathActor::VTable0xec(MxMatrix p_transform, LegoPathBoundary* p_boundar
m_roi->SetLocal2World(p_transform);
if (m_cameraFlag) {
FUN_1003eda0();
ResetViewVelocity();
FUN_10010c30();
}
}

View File

@ -69,7 +69,7 @@ void Jetski::Animate(float p_time)
// FUNCTION: LEGO1 0x1007e6f0
void Jetski::Exit()
{
SpawnPlayer(LegoGameState::e_unk45, FALSE, c_spawnBit1 | c_playMusic | c_spawnBit3);
SpawnPlayer(LegoGameState::e_jetskiSpawn, FALSE, c_spawnBit1 | c_playMusic | c_spawnBit3);
IslePathActor::Exit();
GameState()->m_currentArea = LegoGameState::e_jetski;
RemoveFromWorld();
@ -83,11 +83,11 @@ void Jetski::Exit()
MxLong Jetski::HandleClick()
{
#ifndef BETA10
if (!FUN_1003ef60()) {
if (!CanExit()) {
return 1;
}
FUN_10015820(TRUE, 0);
Disable(TRUE, 0);
((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::Area::e_jetski);
TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, TRUE);
@ -139,7 +139,7 @@ void Jetski::RemoveFromWorld()
// FUNCTION: LEGO1 0x1007e8e0
MxLong Jetski::HandleControl(LegoControlManagerNotificationParam& p_param)
{
if (p_param.m_unk0x28 == 1 && CurrentWorld()->IsA("Isle")) {
if (p_param.m_enabledChild == 1 && CurrentWorld()->IsA("Isle")) {
switch (p_param.m_clickedObjectId) {
case IsleScript::c_JetskiArms_Ctl:
Exit();
@ -164,7 +164,7 @@ void Jetski::ActivateSceneActions()
PlayMusic(JukeboxScript::c_JetskiRace_Music);
Act1State* act1state = (Act1State*) GameState()->GetState("Act1State");
if (!act1state->m_unk0x018) {
if (!act1state->m_state) {
if (act1state->m_unk0x022) {
PlayCamAnim(this, FALSE, 68, TRUE);
}

Some files were not shown because too many files have changed in this diff Show More