Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
54a4bb0
Dutchman. (#1)
Malkierian Jan 18, 2026
feadf91
Merge branch 'develop' of github.com:Malkierian/Ghostship into develop
Malkierian Jan 18, 2026
7bd4251
Merge branch 'develop' of github.com:Malkierian/Ghostship into develop
Malkierian Jan 19, 2026
a3955cd
Merge branch 'develop' of github.com:Malkierian/Ghostship into develop
Malkierian Jan 20, 2026
3aa3553
Fixed wrong o2r path
KiritoDv Jan 23, 2026
6e4c4f7
Removed unnecesary endianness byte
KiritoDv Jan 23, 2026
c4030a6
Fixed GameEngine_OTRSigCheck being used as an int
KiritoDv Jan 23, 2026
e87b71c
Moved logging init back to after the extraction block to prevent extr…
Malkierian Jan 23, 2026
f59c6ce
clang
Malkierian Jan 23, 2026
a4bcde2
Fixed possible windows crash
KiritoDv Jan 23, 2026
b9cb71f
Fixed linux builds, for some reason O2 fucks up the code
KiritoDv Jan 23, 2026
923cf4c
Merge branch 'develop' of github.com:Malkierian/Ghostship into develop
Malkierian Jan 24, 2026
190ac0a
Merge branch 'develop-dutchman' of github.com:Malkierian/Ghostship in…
Malkierian Jan 24, 2026
06b1a41
Merge pull request #117 from Malkierian/dutchman-develop-1-23
Malkierian Jan 24, 2026
05ecd8f
Output warnings to log during engine startup otr checks
JeodC Jan 24, 2026
28fd730
Updated Readme
KiritoDv Jan 24, 2026
d3ee310
Implemented json saves among binary save file conversion (#123)
KiritoDv Jan 24, 2026
797a653
Updated wrong url
KiritoDv Jan 24, 2026
70c8dbd
Update dev
Caladius Jan 25, 2026
ca1e363
Fix MatchRefreshRate and VSync FPS behavior (#125)
Spodi Jan 25, 2026
48919b8
Save File Migration and Log Loading
Caladius Jan 25, 2026
c5d376e
Fix randomizer folder and some Red Coin/Star updates
Caladius Jan 26, 2026
becade9
Fix Pause Menu Red Coin Count
Caladius Jan 26, 2026
3f64719
Adds Spoiler options and clears Check Tracker when not in rando.
Caladius Jan 26, 2026
9c81456
Adds Check Tracker Item Colors
Caladius Jan 26, 2026
74f710a
Fix Red Coins again
Caladius Jan 26, 2026
f7e0b5e
Loading GUI Textures and Notification Icons
Caladius Jan 26, 2026
252ce59
Clean up, fixes, adds Save Editor Rando options
Caladius Jan 26, 2026
e741e2b
More Save Editor work
Caladius Jan 26, 2026
0a60b12
minor tweaks and clang
Caladius Jan 26, 2026
b0295df
Fixes and additions
Caladius Jan 27, 2026
e4acff0
Fix Saveeditor Star removals
Caladius Jan 27, 2026
87d5722
Save Editor Updates
Caladius Jan 28, 2026
6d71c43
Re-add CrashHandler initialization. (#132)
Malkierian Jan 28, 2026
039792a
Adds Skip GI toggle
Caladius Jan 28, 2026
94dbfd6
Initialize RSC before shuffling pool.
Caladius Jan 28, 2026
1a296fb
Updates to checktracker and Rando Labelling for menu
Caladius Jan 28, 2026
e9f2f13
clang
Caladius Jan 28, 2026
bf74328
Add Seeded Generation
Caladius Jan 28, 2026
2f2efa5
Seeded Rando gen fixes and Save File adjustments
Caladius Jan 28, 2026
3bfa9de
Update Save Editor styling
Caladius Jan 29, 2026
9109f2c
Expand/Collapse all for Check Tracker
Caladius Jan 29, 2026
9d44644
clang
Caladius Jan 29, 2026
60980fb
Fixes crash on exit. (#134)
Malkierian Jan 30, 2026
0c81cc5
WIP Entrance Shuffle
Caladius Jan 30, 2026
1d37473
Merge pull request #135 from HarbourMasters/develop-dutchman
Malkierian Jan 31, 2026
d3900db
Entrance Shuffle fixes.
Caladius Feb 1, 2026
4a3492b
Death Exits
Caladius Feb 1, 2026
71c1c91
Merge remote-tracking branch 'source/develop' into develop-rando
Caladius Feb 1, 2026
e6b9a7a
remove diff for Glitchless as not configured.
Caladius Feb 1, 2026
da74d99
macOS Linker fix
Caladius Feb 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
sudo make install
- name: Build
run: |
cmake -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE=Debug
cmake -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE=Release
cmake --build build-cmake -j
- name: Create Package
run: |
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@ jobs:
path: ./build-cmake
- name: Build
run: |
cmake -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE=Debug
cmake --build build-cmake --config Debug -j3
cmake -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE=Release
cmake --build build-cmake --config Release -j3
(cd build-cmake && cpack -G External)
wget -O gamecontrollerdb.txt https://raw.githubusercontent.com/mdqinc/SDL_GameControllerDB/refs/heads/master/gamecontrollerdb.txt
mv README.md readme.txt
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ build/*
*.sav
*.o2r
*.map
default.sav.bak
.assets-local.txt

build/
Expand Down Expand Up @@ -96,3 +97,6 @@ modding/
node_modules
/src/port/build.c
/properties.h
!/src/port/mods/
mods/
saves/
7 changes: 4 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ set(CMAKE_CXX_FLAGS_DEBUG "-g -ffast-math -DDEBUG")
set(CMAKE_C_FLAGS_RELEASE "-O3 -ffast-math -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -ffast-math -DNDEBUG")
else()
set(CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
set(CMAKE_OBJCXX_FLAGS_RELEASE "-O2 -DNDEBUG")
set(CMAKE_C_FLAGS_RELEASE "-O1 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O1 -DNDEBUG")
set(CMAKE_OBJCXX_FLAGS_RELEASE "-O1 -DNDEBUG")
endif()

# Set game compilation version
Expand All @@ -153,6 +153,7 @@ add_compile_definitions(
ENABLE_RUMBLE=1
F3D_OLD=1
F3D_GBI=1
USE_GBI_TRACE=1
GBI_FLOATS=1
_LANGUAGE_C
_USE_MATH_DEFINES
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ If you want to playtest a continuous integration build, you can find them at the

# Special Thanks:

* [Kenix3](https://github.com/Kenix3) : for helping with the Engine development that were brought into other ports.
* [HM64 Team](https://github.com/harbourMasters) : for creating Libultraship and helping with various issues.
* [garrettjoecox](https://github.com/garrettjoecox) : for contributing with fixes to this port.
* [inspectredc](https://github.com/inspectredc) : for contributing to the extraction of the game's assets.
Expand Down
2 changes: 1 addition & 1 deletion include/macro_presets.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ struct MacroPreset {
/*0x06*/ s16 param;
};

struct MacroPreset MacroObjectPresets[] = {
extern struct MacroPreset MacroObjectPresets[] = {
{bhvYellowCoin, MODEL_YELLOW_COIN, 0},
{bhvOneCoin, MODEL_YELLOW_COIN, 0},
{bhvMovingBlueCoin, MODEL_BLUE_COIN, 0},
Expand Down
31 changes: 17 additions & 14 deletions src/engine/behavior_script.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <libultraship.h>
#include "port/hooks/list/PlayerEvent.h"

#include "sm64.h"
#include "behavior_data.h"
Expand Down Expand Up @@ -984,20 +985,22 @@ void cur_obj_update(void) {
}

// Handle visibility of object
if (gCurrentObject->oRoom != -1) {
// If the object is in a room, only show it when Mario is in the room.
cur_obj_enable_rendering_if_mario_in_room();
} else if ((objFlags & OBJ_FLAG_COMPUTE_DIST_TO_MARIO) && gCurrentObject->collisionData == NULL) {
if (!(objFlags & OBJ_FLAG_ACTIVE_FROM_AFAR)) {
// If the object has a render distance, check if it should be shown.
if (distanceFromMario > gCurrentObject->oDrawingDistance) {
// Out of render distance, hide the object.
gCurrentObject->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE;
gCurrentObject->activeFlags |= ACTIVE_FLAG_FAR_AWAY;
} else if (gCurrentObject->oHeldState == HELD_FREE) {
// In render distance (and not being held), show the object.
gCurrentObject->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE;
gCurrentObject->activeFlags &= ~ACTIVE_FLAG_FAR_AWAY;
CALL_CANCELLABLE_EVENT(ModifyObjectVisibility, &gCurrentObject) {
if (gCurrentObject->oRoom != -1) {
// If the object is in a room, only show it when Mario is in the room.
cur_obj_enable_rendering_if_mario_in_room();
} else if ((objFlags & OBJ_FLAG_COMPUTE_DIST_TO_MARIO) && gCurrentObject->collisionData == NULL) {
if (!(objFlags & OBJ_FLAG_ACTIVE_FROM_AFAR)) {
// If the object has a render distance, check if it should be shown.
if (distanceFromMario > gCurrentObject->oDrawingDistance) {
// Out of render distance, hide the object.
gCurrentObject->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE;
gCurrentObject->activeFlags |= ACTIVE_FLAG_FAR_AWAY;
} else if (gCurrentObject->oHeldState == HELD_FREE) {
// In render distance (and not being held), show the object.
gCurrentObject->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE;
gCurrentObject->activeFlags &= ~ACTIVE_FLAG_FAR_AWAY;
}
}
}
}
Expand Down
4 changes: 1 addition & 3 deletions src/engine/level_script.c
Original file line number Diff line number Diff line change
Expand Up @@ -444,9 +444,7 @@ static void level_cmd_place_object(void) {

if (sCurrAreaIndex != -1 && ((CMD_GET(u8, 2) & val7) || CMD_GET(u8, 2) == 0x1F)) {
model = CMD_GET(u8, 3);
if (model == MODEL_STAR) {
int hi = 122;
}

spawnInfo = alloc_only_pool_alloc(sLevelPool, sizeof(struct SpawnInfo));

spawnInfo->startPos[0] = CMD_GET(s16, 4);
Expand Down
4 changes: 3 additions & 1 deletion src/game/behaviors/hidden_star.inc.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ void bhv_hidden_star_trigger_loop(void) {
}

void bhv_bowser_course_red_coin_star_loop(void) {
gRedCoinsCollected = o->oHiddenStarTriggerCounter;
CALL_CANCELLABLE_EVENT(ModifyRedCoinCount, &gRedCoinsCollected) {
gRedCoinsCollected = o->oHiddenStarTriggerCounter;
}

switch (o->oAction) {
case 0:
Expand Down
13 changes: 8 additions & 5 deletions src/game/behaviors/spawn_star.inc.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ void bhv_collect_star_init(void) {
void bhv_collect_star_loop(void) {
o->oFaceAngleYaw += 0x800;

if (o->oInteractStatus & INT_STATUS_INTERACTED) {
mark_obj_for_deletion(o);
o->oInteractStatus = 0;
CALL_CANCELLABLE_EVENT(ModifyObjectBehavior, o, MODEL_STAR) {
if (o->oInteractStatus & INT_STATUS_INTERACTED) {
mark_obj_for_deletion(o);
o->oInteractStatus = 0;
}
}
}

Expand Down Expand Up @@ -167,7 +169,9 @@ void bhv_hidden_red_coin_star_init(void) {
}

void bhv_hidden_red_coin_star_loop(void) {
gRedCoinsCollected = o->oHiddenStarTriggerCounter;
CALL_CANCELLABLE_EVENT(ModifyRedCoinCount, &gRedCoinsCollected) {
gRedCoinsCollected = o->oHiddenStarTriggerCounter;
}

switch (o->oAction) {
case 0:
Expand All @@ -184,5 +188,4 @@ void bhv_hidden_red_coin_star_loop(void) {
}
break;
}
//CALL_CANCELLABLE_EVENT(ModifyObjectBehavior, o, MODEL_STAR);
}
10 changes: 7 additions & 3 deletions src/game/level_update.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

#include "port/ui/cvar_prefixes.h"
#include "port/hooks/list/EngineEvent.h"
#include "port/hooks/list/PlayerEvent.h"
#include "port/mods/PortEnhancements.h"

#define PLAY_MODE_NORMAL 0
Expand Down Expand Up @@ -662,6 +663,7 @@ void initiate_painting_warp(void) {
if (gMarioState->action & ACT_FLAG_INTANGIBLE) {
play_painting_eject_sound();
} else if (pWarpNode->id != 0) {
CALL_EVENT(ChangeLevel, 0, pWarpNode, 0);
warpNode = *pWarpNode;

if (!(warpNode.destLevel & 0x80)) {
Expand Down Expand Up @@ -869,11 +871,13 @@ void initiate_delayed_warp(void) {

default:
warpNode = area_get_warp_node(sSourceWarpNodeId);

initiate_warp(warpNode->node.destLevel & 0x7F, warpNode->node.destArea,
warpNode->node.destNode, sDelayedWarpArg);

CALL_EVENT(ChangeLevel, sSourceWarpNodeId, &warpNode->node, &sDelayedWarpArg);
initiate_warp(warpNode->node.destLevel & 0x7F, warpNode->node.destArea, warpNode->node.destNode,
sDelayedWarpArg);

check_if_should_set_warp_checkpoint(&warpNode->node);

if (sWarpDest.type != WARP_TYPE_CHANGE_LEVEL) {
level_set_transition(2, NULL);
}
Expand Down
3 changes: 2 additions & 1 deletion src/game/object_helpers.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <libultra/types.h>
#include "port/hooks/list/PlayerEvent.h"

#include "sm64.h"
#include "area.h"
Expand Down Expand Up @@ -2317,7 +2318,7 @@ void cur_obj_call_action_function(void (*actionFunctions[])(void)) {
}

static struct Object *spawn_star_with_no_lvl_exit(s32 sp20, s32 sp24) {
struct Object *sp1C = spawn_object(o, MODEL_STAR, bhvSpawnedStarNoLevelExit);
struct Object* sp1C = spawn_object(o, MODEL_STAR, bhvSpawnedStarNoLevelExit);
sp1C->oSparkleSpawnUnk1B0 = sp24;
sp1C->oBehParams = o->oBehParams;
sp1C->oBehParams2ndByte = sp20;
Expand Down
63 changes: 39 additions & 24 deletions src/game/save_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@
#include "level_table.h"
#include "course_table.h"
#include "rumble_init.h"
#include "port/data/Saves.h"

#include "port/hooks/list/PlayerEvent.h"
#include "port/mods/PortEnhancements.h"

#define MENU_DATA_MAGIC 0x4849
#define SAVE_FILE_MAGIC 0x4441

STATIC_ASSERT(sizeof(struct SaveBuffer) == EEPROM_SIZE, "eeprom buffer size must match");
// @port: Disabled because save files are gonna be bigger soon
// STATIC_ASSERT(sizeof(struct SaveBuffer) == EEPROM_SIZE, "eeprom buffer size must match");

extern struct SaveBuffer gSaveBuffer;

Expand Down Expand Up @@ -151,6 +153,8 @@ static void add_save_block_signature(void *buffer, s32 size, u16 magic) {
* Copy main menu data from one backup slot to the other slot.
*/
static void restore_main_menu_data(s32 srcSlot) {
CALL(RestoreMainMenuData, srcSlot);

s32 destSlot = srcSlot ^ 1;

// Compute checksum on source data
Expand All @@ -164,6 +168,8 @@ static void restore_main_menu_data(s32 srcSlot) {
}

static void save_main_menu_data(void) {
CALL(SaveMainMenuData);

if (gMainMenuDataModified) {
// Compute checksum
add_save_block_signature(&gSaveBuffer.menuData[0], sizeof(gSaveBuffer.menuData[0]), MENU_DATA_MAGIC);
Expand Down Expand Up @@ -237,6 +243,8 @@ static void touch_high_score_ages(s32 fileIndex) {
* Copy save file data from one backup slot to the other slot.
*/
static void restore_save_file_data(s32 fileIndex, s32 srcSlot) {
CALL(RestoreSaveFileData, fileIndex, srcSlot);

s32 destSlot = srcSlot ^ 1;

// Compute checksum on source data
Expand All @@ -253,6 +261,8 @@ static void restore_save_file_data(s32 fileIndex, s32 srcSlot) {
}

void save_file_do_save(s32 fileIndex) {
CALL(SaveFileDoSave, fileIndex);

CALL_EVENT(OnGameFileSave, fileIndex);
if (gSaveFileModified) {
// Compute checksum
Expand Down Expand Up @@ -300,40 +310,45 @@ void save_file_load_all(void) {
gSaveFileModified = FALSE;

bzero(&gSaveBuffer, sizeof(gSaveBuffer));
read_eeprom_data(&gSaveBuffer, sizeof(gSaveBuffer));

// Verify the main menu data and create a backup copy if only one of the slots is valid.
validSlots = verify_save_block_signature(&gSaveBuffer.menuData[0], sizeof(gSaveBuffer.menuData[0]), MENU_DATA_MAGIC);
validSlots |= verify_save_block_signature(&gSaveBuffer.menuData[1], sizeof(gSaveBuffer.menuData[1]),MENU_DATA_MAGIC) << 1;
switch (validSlots) {
case 0: // Neither copy is correct
wipe_main_menu_data();
break;
case 1: // Slot 0 is correct and slot 1 is incorrect
restore_main_menu_data(0);
break;
case 2: // Slot 1 is correct and slot 0 is incorrect
restore_main_menu_data(1);
break;
}

for (file = 0; file < NUM_SAVE_FILES; file++) {
// Verify the save file and create a backup copy if only one of the slots is valid.
validSlots = verify_save_block_signature(&gSaveBuffer.files[file][0], sizeof(gSaveBuffer.files[file][0]), SAVE_FILE_MAGIC);
validSlots |= verify_save_block_signature(&gSaveBuffer.files[file][1], sizeof(gSaveBuffer.files[file][1]), SAVE_FILE_MAGIC) << 1;
if(ShouldLoadOldSaveFile()) {
read_eeprom_data(&gSaveBuffer, EEPROM_SIZE);

// Verify the main menu data and create a backup copy if only one of the slots is valid.
validSlots = verify_save_block_signature(&gSaveBuffer.menuData[0], MENU_SAVE_DATA_SIZE, MENU_DATA_MAGIC);
validSlots |= verify_save_block_signature(&gSaveBuffer.menuData[1], MENU_SAVE_DATA_SIZE, MENU_DATA_MAGIC) << 1;
switch (validSlots) {
case 0: // Neither copy is correct
save_file_erase(file);
wipe_main_menu_data();
break;
case 1: // Slot 0 is correct and slot 1 is incorrect
restore_save_file_data(file, 0);
restore_main_menu_data(0);
break;
case 2: // Slot 1 is correct and slot 0 is incorrect
restore_save_file_data(file, 1);
restore_main_menu_data(1);
break;
}

for (file = 0; file < NUM_SAVE_FILES; file++) {
// Verify the save file and create a backup copy if only one of the slots is valid.
validSlots = verify_save_block_signature(&gSaveBuffer.files[file][0], SAVE_FILE_SIZE, SAVE_FILE_MAGIC);
validSlots |= verify_save_block_signature(&gSaveBuffer.files[file][1], SAVE_FILE_SIZE, SAVE_FILE_MAGIC) << 1;
switch (validSlots) {
case 0: // Neither copy is correct
save_file_erase(file);
break;
case 1: // Slot 0 is correct and slot 1 is incorrect
restore_save_file_data(file, 0);
break;
case 2: // Slot 1 is correct and slot 0 is incorrect
restore_save_file_data(file, 1);
break;
}
}
}

CALL(SaveFileLoadAll);

stub_save_file_1();
}

Expand Down
Loading
Loading