Cleanup and update documentation

This commit is contained in:
TheOnlyZac 2024-06-28 13:12:12 -04:00
parent 5b6ead71b4
commit 773afd902c
29 changed files with 4 additions and 476 deletions

View File

@ -75,7 +75,7 @@ cd scripts
**Prerequisites**: `git`, `make`, `7zip` **Prerequisites**: `git`, `make`, `7zip`
*Note: Building on Windows is temporarily not working. You can still build on Windows using WSL.* *Note: Building Windows is untested with the new build system. If you encounter issues, you can still build on Windows using WSL.*
```powershell ```powershell
cd scripts cd scripts
@ -142,7 +142,6 @@ The project is divided into the following directories:
* `config` - Config files for Splat (binary splitting tool). * `config` - Config files for Splat (binary splitting tool).
* `scripts` - Utility scripts for setting up the build environment. * `scripts` - Utility scripts for setting up the build environment.
* `docs` - Documentation and instructions for contributing. * `docs` - Documentation and instructions for contributing.
* `test` - Handwritten unit tests for the decomp code.
* `tools` - Utilities for function matching. * `tools` - Utilities for function matching.
* `reference` - Reference files for functions and data structures. * `reference` - Reference files for functions and data structures.

1
config/readme.txt Normal file
View File

@ -0,0 +1 @@
This directory contains config files for Splat, which is used for Binary splitting.

View File

1
disc/readme.txt Normal file
View File

@ -0,0 +1 @@
To build the project, you need to extract the executable file SCUS_971.98 from your own copy of the game and put it in this directory.

View File

@ -1,4 +1,4 @@
This directory contains reference files you can use to help with decompiling game functions. They are all source code files we wrote by hand before we used Splat to decompile and reassemble the game to a byte-matching executable. Because of this, none of the functions in this directory is matching, but we tried to make them as close as possible to the original game functions. This directory contains reference files you can use to help with decompiling game functions. They are all source code files we wrote by hand before we used Splat to decompile and reassemble the game to a byte-matching executable. Because of this, none of the functions in this directory match, but we tried to make them as close as possible to the original game functions.
The include directory contains header files that are used by the source files in the src dir. Many of the short data structures/enums are correct and can be copied directly into the actual decomp. The longer ones are probably not correct (missing fields, wrong field types, etc), but they can be used as a reference. The include directory contains header files that are used by the source files in the src dir. Many of the short data structures/enums are correct and can be copied directly into the actual decomp. The longer ones are probably not correct (missing fields, wrong field types, etc), but they can be used as a reference.

View File

@ -1,24 +0,0 @@
macro(add_unit_test)
set(options PARALLEL)
set(oneValueArgs NAME)
set(multiValueArgs SOURCES LIBS)
cmake_parse_arguments(TEST "${options}" "${oneValueArgs}"
"${multiValueArgs}" ${ARGN})
message(STATUS "Generating Test ${TEST_NAME}... (${TEST_SOURCES})")
add_executable(${TEST_NAME} EXCLUDE_FROM_ALL ${TEST_SOURCES})
target_link_libraries(${TEST_NAME} ${TEST_LIBS})
if(TEST_PARALLEL AND HAVE_MPI)
set(TESTCOMMAND ${MPIEXEC})
set(TESTARGS ${MPIEXEC_NUMPROC_FLAG} 3 ${MPIEXEC_PREFLAGS}
"./${TEST_NAME}" ${MPIEXEC_POSTFLAGS})
set(TESTCOMMAND ${TESTCOMMAND} ${TESTARGS})
else()
set(TESTCOMMAND ${TEST_NAME})
endif()
add_test(NAME ${TEST_NAME}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin/tests
COMMAND ${TESTCOMMAND})
get_property(TESTNAMES GLOBAL PROPERTY TESTNAMES)
set_property(GLOBAL PROPERTY TESTNAMES ${TESTNAMES} ${TEST_NAME})
endmacro(add_unit_test)

View File

@ -1,2 +0,0 @@
add_unit_test(PARALLEL TRUE NAME clock.set_clock_rate SOURCES set_clock_rate.cpp LIBS ${P2_LIB_TARGET})

View File

@ -1,24 +0,0 @@
#include <clock.h>
#include <test/test.h>
int main()
{
SetClockRate(1.0);
JtAssert(g_rtClock == 1.0f);
JtAssert(g_clock.fEnabled);
SetClockRate(0.5);
JtAssert(g_rtClock == 0.5f);
JtAssert(g_clock.fEnabled);
SetClockRate(0);
JtAssert(g_rtClock == 0.f);
JtAssert(!g_clock.fEnabled);
SetClockRate(-1);
JtAssert(g_rtClock == -1.f);
JtAssert(!g_clock.fEnabled);
return 0;
}

View File

@ -1,2 +0,0 @@
add_unit_test(PARALLEL TRUE NAME coin.collect_coins SOURCES collect_coins.cpp LIBS ${P2_LIB_TARGET})

View File

@ -1,49 +0,0 @@
#include <coin.h>
#include <gs.h>
#include <test/test.h>
int main()
{
COIN coin;
// Test collecting a coin normally
g_pgsCur->ccoin = 0;
g_pgsCur->ccharm = 0;
OnCoinSmack(&coin);
JtAssert(g_pgsCur->ccoin == 1);
JtAssert(g_pgsCur->ccharm == 0);
g_pgsCur->ccoin = 98;
OnCoinSmack(&coin);
JtAssert(g_pgsCur->ccoin == 99);
JtAssert(g_pgsCur->ccharm == 0);
// Test collecting a 100 coins to get a charm
OnCoinSmack(&coin);
JtAssert(g_pgsCur->ccoin == 0);
JtAssert(g_pgsCur->ccharm == 1);
// Test collecting 100 coins to get an extra life
g_pgsCur->ccoin = 99;
g_pgsCur->ccharm = 2;
g_pgsCur->clife = 5;
OnCoinSmack(&coin);
JtAssert(g_pgsCur->ccoin == 0);
JtAssert(g_pgsCur->ccharm == 2);
JtAssert(g_pgsCur->clife == 6);
// Test collecting a coin when coins, lives, and charms are all at max
g_pgsCur->ccoin = 99;
g_pgsCur->ccharm = 2;
g_pgsCur->clife = 99;
OnCoinSmack(&coin);
JtAssert(g_pgsCur->ccoin == 99);
JtAssert(g_pgsCur->ccharm == 2);
JtAssert(g_pgsCur->clife == 99);
}

View File

@ -1,3 +0,0 @@
add_unit_test(PARALLEL TRUE NAME difficulty.change_suck SOURCES change_suck.cpp LIBS ${P2_LIB_TARGET})
add_unit_test(PARALLEL TRUE NAME difficulty.world_preload SOURCES world_preload.cpp LIBS ${P2_LIB_TARGET})

View File

@ -1,29 +0,0 @@
#include <difficulty.h>
#include <gs.h>
#include <test/test.h>
int main()
{
// Initialize difficulty
OnDifficultyGameLoad(&g_difficulty);
OnDifficultyWorldPreLoad(&g_difficulty);
OnDifficultyWorldPostLoad(&g_difficulty);
// Test changing level suck
g_plsCur->uSuck = 0.0f;
JtAssert(g_plsCur->uSuck == 0.0f);
ChangeSuck(0.1, &g_difficulty);
JtAssert(g_plsCur->uSuck == 0.1f);
ChangeSuck(1.0, &g_difficulty);
JtAssert(g_plsCur->uSuck == 1.0f);
ChangeSuck(-1.0, &g_difficulty);
JtAssert(g_plsCur->uSuck == -1.0f);
// Test collect key scenario
OnDifficultyCollectKey(&g_difficulty);
JtAssert(g_plsCur->uSuck == 0.0f);
}

View File

@ -1,48 +0,0 @@
#include <difficulty.h>
#include <gs.h>
#include <test/test.h>
void SetGameLevel(GAMEWORLD gameworld, WORLDLEVEL worldlevel);
int main()
{
// Initialize difficulty
OnDifficultyGameLoad(&g_difficulty);
// jb_intro = easy
SetGameLevel(GAMEWORLD_Intro, WORLDLEVEL_Approach);
OnDifficultyWorldPreLoad(&g_difficulty);
JtAssert(g_difficulty.pdifficultyLevel == &g_difficultyEasy);
// cw_security = easy
SetGameLevel(GAMEWORLD_Clockwerk, WORLDLEVEL_Level2);
OnDifficultyWorldPreLoad(&g_difficulty);
JtAssert(g_difficulty.pdifficultyLevel == &g_difficultyEasy);
// uw_bonus_security
SetGameLevel(GAMEWORLD_Underwater, WORLDLEVEL_Level3);
// no key = medium
g_plsCur->fls = static_cast<FLS>((int)g_plsCur->fls & ~(int)FLS_KeyCollected); // unset KeyCollected flag
OnDifficultyWorldPreLoad(&g_difficulty);
JtAssert(g_difficulty.pdifficultyLevel == &g_difficultyMedium);
// with key = hard
g_plsCur->fls = static_cast<FLS>((int)g_plsCur->fls | (int)FLS_KeyCollected); // setKeyCollected flag
OnDifficultyWorldPreLoad(&g_difficulty);
JtAssert(g_difficulty.pdifficultyLevel == &g_difficultyHard);
return 0;
}
void SetGameLevel(GAMEWORLD gameworld, WORLDLEVEL worldlevel)
{
g_pwsCur = &g_pgsCur->aws[(int)gameworld];
g_plsCur = &g_pwsCur->als[(int)worldlevel];
g_pgsCur->gameworldCur = gameworld;
g_pgsCur->worldlevelCur = worldlevel;
}

View File

@ -1,4 +0,0 @@
add_unit_test(PARALLEL TRUE NAME game.set_coin_count SOURCES set_coin_count.cpp LIBS ${P2_LIB_TARGET})
add_unit_test(PARALLEL TRUE NAME game.set_charm_count SOURCES set_charm_count.cpp LIBS ${P2_LIB_TARGET})
add_unit_test(PARALLEL TRUE NAME game.charm_available SOURCES charm_available.cpp LIBS ${P2_LIB_TARGET})

View File

@ -1,43 +0,0 @@
#include <game.h>
#include <joy.h>
#include <gs.h>
#include <test/test.h>
int main()
{
g_pgsCur->ccoin = 1; // set coins to 1
g_grfcht &= ~((int)FCHT_InfiniteCharms); // disable infinite charms
// Confirm max charm count is 2
JtAssert(CcharmMost() == 2);
// Test checking if a charm is available
g_pgsCur->ccharm = 0;
JtAssert(FCharmAvailable() == false);
g_pgsCur->ccharm = 1;
JtAssert(FCharmAvailable() == true);
g_pgsCur->ccharm = -1;
JtAssert(FCharmAvailable() == false);
g_pgsCur->ccharm = 0;
g_grfcht |= (int)FCHT_InfiniteCharms; // enable infinite charms cheat
JtAssert(FCharmAvailable() == true);
// Test setting charm count
SetCcharm(0);
JtAssert(g_pgsCur->ccharm == 0);
SetCcharm(1);
JtAssert(g_pgsCur->ccharm == 1);
SetCcharm(3);
JtAssert(g_pgsCur->ccharm == 3);
SetCcharm(-1);
JtAssert(g_pgsCur->ccharm == -1);
return 0;
}

View File

@ -1,26 +0,0 @@
#include <game.h>
#include <joy.h>
#include <gs.h>
#include <test/test.h>
int main()
{
// Confirm max charm count is 2
JtAssert(CcharmMost() == 2);
// Test setting charm count
SetCcharm(0);
JtAssert(g_pgsCur->ccharm == 0);
SetCcharm(1);
JtAssert(g_pgsCur->ccharm == 1);
SetCcharm(3);
JtAssert(g_pgsCur->ccharm == 3);
SetCcharm(-1);
JtAssert(g_pgsCur->ccharm == -1);
return 0;
}

View File

@ -1,29 +0,0 @@
#include <game.h>
#include <joy.h>
#include <gs.h>
#include <test/test.h>
int main()
{
g_pgsCur->ccoin = 1; // set coins to 1
g_pgsCur->ccharm = 0; // set charms to 0
// Test setting coin count
SetCcoin(0);
JtAssert(g_pgsCur->ccoin == 0);
SetCcoin(14);
JtAssert(g_pgsCur->ccoin == 14);
SetCcoin(99);
JtAssert(g_pgsCur->ccoin == 99);
SetCcoin(-1);
JtAssert(g_pgsCur->ccoin == -1);
SetCcoin(101);
JtAssert(g_pgsCur->ccoin == 101);
return 0;
}

View File

@ -1,2 +0,0 @@
add_unit_test(PARALLEL TRUE NAME gs.calculate_gs_percent SOURCES calculate_gs_percent.cpp LIBS ${P2_LIB_TARGET})

View File

@ -1,14 +0,0 @@
#include <gs.h>
#include <test/test.h>
int main()
{
PopulatePchzLevelTable();
// Test save file percent calculation
int percent = CalculatePercentCompletion(g_pgsCur);
JtAssert(percent == 0);
return 0;
}

View File

@ -1,3 +0,0 @@
add_unit_test(PARALLEL TRUE NAME joy.chetkido SOURCES chetkido.cpp LIBS ${P2_LIB_TARGET})
add_unit_test(PARALLEL TRUE NAME joy.add_fcht SOURCES add_fcht.cpp LIBS ${P2_LIB_TARGET})

View File

@ -1,23 +0,0 @@
#include <joy.h>
#include <test/test.h>
int main()
{
// Test setting setting cheat flag
g_grfcht = 0x0;
AddFcht((int)FCHT_InfiniteCharms);
JtAssert(g_grfcht == 0x2);
AddFcht((int)FCHT_LowGravity);
JtAssert(g_grfcht == 0x6);
AddFcht((int)FCHT_Invulnerability);
JtAssert(g_grfcht == 0x7);
AddFcht((int)FCHT_LowFriction);
JtAssert(g_grfcht == 0xF);
return 0;
}

View File

@ -1,25 +0,0 @@
#include <joy.h>
#include <gs.h>
#include <test/test.h>
#include <cstring>
int main()
{
// Test chetkido string output
g_pgsCur->gameworldCur = GAMEWORLD_Snow;
g_pgsCur->worldlevelCur = WORLDLEVEL_Approach;
g_pgsCur->ccoin = 99;
g_pgsCur->clife = 0;
CheatActivateChetkido();
JtAssert(strstr(chetkido_buffer, "The password is: chetkido") != NULL);
g_pgsCur->ccoin = 98;
CheatActivateChetkido();
JtAssert(strstr(chetkido_buffer, "The password is: chetkido") == NULL);
return 0;
}

View File

@ -1,30 +0,0 @@
/**
* @file test.h
*
* @brief Contains macros for testing and debugging.
*/
#ifndef TEST_H
#define TEST_H
#include <stdexcept>
#include <exception>
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
// Custom assert macro that doesn't call abort
#define JtAssert(assertion) \
{ \
if (!(assertion)) \
{ \
printf( \
"\nAn assertion failure has occurred\n" \
"========================================\n" \
"Assertion: %s\n" \
"File: %s\nLine %d, in %s\n" \
"========================================\n\n", \
#assertion, __FILENAME__, __LINE__, __FUNCTION__); \
exit(1); \
} \
}
#endif // TEST_H

View File

@ -1,3 +0,0 @@
add_unit_test(PARALLEL TRUE NAME util.limit_lm SOURCES limit_lm.cpp LIBS ${P2_LIB_TARGET})
add_unit_test(PARALLEL TRUE NAME util.limit_abs SOURCES limit_abs.cpp LIBS ${P2_LIB_TARGET})

View File

@ -1,36 +0,0 @@
#include <util.h>
#include <test/test.h>
// disable warning for truncating double to float
#pragma warning(disable: 4305)
int main()
{
// Clamp value between -1 and 1
JtAssert(GLimitAbs(-5, 1) == -1.f);
JtAssert(GLimitAbs(-1, 1) == -1.f);
JtAssert(GLimitAbs(-0.4, 1) == -0.4f);
JtAssert(GLimitAbs(0.76, 1) == 0.76f);
JtAssert(GLimitAbs(1, 1) == 1.f);
JtAssert(GLimitAbs(17, 1) == 1.f);
// Clamp value between -3.14 and 3.14
JtAssert(GLimitAbs(-5, 3.14) == -3.14f);
JtAssert(GLimitAbs(-1, 3.14) == -1.f);
JtAssert(GLimitAbs(-0.4, 3.14) == -0.4f);
JtAssert(GLimitAbs(0.76, 3.14) == 0.76f);
JtAssert(GLimitAbs(3.14, 3.14) == 3.14f);
JtAssert(GLimitAbs(17, 3.14) == 3.14f);
// Clamp value between -100 and 100
JtAssert(GLimitAbs(-1000, 100) == -100.f);
JtAssert(GLimitAbs(-100, 100) == -100.f);
JtAssert(GLimitAbs(-17.3, 100) == -17.3f);
JtAssert(GLimitAbs(0, 100) == 0.f);
JtAssert(GLimitAbs(91, 100) == 91.f);
JtAssert(GLimitAbs(100.2, 100) == 100.f);
JtAssert(GLimitAbs(420.69, 100) == 100.f);
return 0;
}

View File

@ -1,27 +0,0 @@
#include <util.h>
#include <test/test.h>
// disable warning for truncating double to float
#pragma warning(disable: 4305)
int main()
{
// Clamp value using global 0-1 limit
JtAssert(GLimitLm(&g_lmZeroOne, -2.3) == 0.f);
JtAssert(GLimitLm(&g_lmZeroOne, 0) == 0.f);
JtAssert(GLimitLm(&g_lmZeroOne, 0.234) == 0.234f);
JtAssert(GLimitLm(&g_lmZeroOne, 0.7) == 0.7f);
JtAssert(GLimitLm(&g_lmZeroOne, 1) == 1.f);
JtAssert(GLimitLm(&g_lmZeroOne, 4) == 1.f);
// Clamp value using local limit
LM lmFiveTen(5, 10);
JtAssert(GLimitLm(&lmFiveTen, 1) == 5.f);
JtAssert(GLimitLm(&lmFiveTen, 5) == 5.f);
JtAssert(GLimitLm(&lmFiveTen, 7) == 7.f);
JtAssert(GLimitLm(&lmFiveTen, 10) == 10.f);
JtAssert(GLimitLm(&lmFiveTen, 99) == 10.f);
return 0;
}

View File

@ -1,2 +0,0 @@
add_unit_test(PARALLEL TRUE NAME xform.set_exits SOURCES set_exits.cpp LIBS ${P2_LIB_TARGET})

View File

@ -1,25 +0,0 @@
#include <xform.h>
#include <cassert>
#include <test/test.h>
int main()
{
EXIT exit;
// todo: why does the custom assert macro cause errors here
SetExitExits(&exit, EXITS_Blocked);
assert(exit.fKeyed == EXITS_Blocked);
SetExitExits(&exit, EXITS_Disabled);
assert(exit.fKeyed == EXITS_Disabled);
SetExitExits(&exit, EXITS_Enabled);
assert(exit.fKeyed == EXITS_Enabled);
SetExitExits(&exit, EXITS_Exiting);
assert(exit.fKeyed == EXITS_Exiting);
return 0;
}