mirror of
https://github.com/n64decomp/sm64.git
synced 2024-11-16 06:15:11 -05:00
299 lines
10 KiB
Diff
299 lines
10 KiB
Diff
diff --git a/Makefile b/Makefile
|
|
index f50b7622..124c7ec6 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -478,6 +478,7 @@ $(BUILD_DIR)/include/text_strings.h: $(BUILD_DIR)/include/text_menu_strings.h
|
|
$(BUILD_DIR)/src/menu/file_select.o: $(BUILD_DIR)/include/text_strings.h
|
|
$(BUILD_DIR)/src/menu/star_select.o: $(BUILD_DIR)/include/text_strings.h
|
|
$(BUILD_DIR)/src/game/ingame_menu.o: $(BUILD_DIR)/include/text_strings.h
|
|
+$(BUILD_DIR)/src/game/mem_error_screen.o: $(BUILD_DIR)/include/text_strings.h
|
|
|
|
|
|
#==============================================================================#
|
|
diff --git a/include/segments.h b/include/segments.h
|
|
index a97d6ee8..186c968e 100644
|
|
--- a/include/segments.h
|
|
+++ b/include/segments.h
|
|
@@ -3,6 +3,9 @@
|
|
|
|
#include "config.h"
|
|
|
|
+/* Use expansion pack RAM */
|
|
+#define USE_EXT_RAM 1
|
|
+
|
|
/*
|
|
* Memory addresses for segments. Ideally, this header file would not be
|
|
* needed, and the addresses would be defined in sm64.ld and linker-inserted
|
|
diff --git a/include/text_strings.h.in b/include/text_strings.h.in
|
|
index 749179b1..2f6f7a3c 100644
|
|
--- a/include/text_strings.h.in
|
|
+++ b/include/text_strings.h.in
|
|
@@ -25,6 +25,11 @@
|
|
#define TEXT_PAUSE _("PAUSE") // Pause text, Castle Courses
|
|
#define TEXT_HUD_CONGRATULATIONS _("CONGRATULATIONS") // Course Complete Text, Bowser Courses
|
|
|
|
+// Memory Expansion Error Screen
|
|
+#define TEXT_CONSOLE_8MB _("If you're using an N64 console, then you will need to buy an\nExpansion Pak to play this ROM hack.")
|
|
+#define TEXT_PJ64 _("If you are using PJ64 1.6, go to:\nOptions > Settings > Rom Settings Tab > Memory Size\nthen select 8 MB from the drop-down box.")
|
|
+#define TEXT_PJ64_2 _("If you are using PJ64 2.X, go to:\nOptions > Settings > Config: > Memory Size, select 8 MB")
|
|
+
|
|
#if defined(VERSION_JP) || defined(VERSION_SH) || defined(VERSION_CN)
|
|
|
|
/**
|
|
diff --git a/levels/entry.c b/levels/entry.c
|
|
index 17c773ed..677a5ae9 100644
|
|
--- a/levels/entry.c
|
|
+++ b/levels/entry.c
|
|
@@ -15,3 +15,12 @@ const LevelScript level_script_entry[] = {
|
|
EXECUTE(/*seg*/ 0x14, /*script*/ _introSegmentRomStart, /*scriptEnd*/ _introSegmentRomEnd, /*entry*/ level_intro_splash_screen),
|
|
JUMP(/*target*/ level_script_entry),
|
|
};
|
|
+
|
|
+const LevelScript level_script_entry_error_screen[] = {
|
|
+ INIT_LEVEL(),
|
|
+ SLEEP(/*frames*/ 2),
|
|
+ BLACKOUT(/*active*/ FALSE),
|
|
+ SET_REG(/*value*/ 0),
|
|
+ EXECUTE(/*seg*/ 0x14, /*script*/ _introSegmentRomStart, /*scriptEnd*/ _introSegmentRomEnd, /*entry*/ level_intro_entry_error_screen),
|
|
+ JUMP(/*target*/ level_script_entry_error_screen),
|
|
+};
|
|
diff --git a/levels/intro/geo.c b/levels/intro/geo.c
|
|
index 30a87806..6bf7b79a 100644
|
|
--- a/levels/intro/geo.c
|
|
+++ b/levels/intro/geo.c
|
|
@@ -15,6 +15,24 @@
|
|
|
|
#include "levels/intro/header.h"
|
|
|
|
+const GeoLayout intro_geo_error_screen[] = {
|
|
+ GEO_NODE_SCREEN_AREA(0, SCREEN_WIDTH/2, SCREEN_HEIGHT/2, SCREEN_WIDTH/2, SCREEN_HEIGHT/2),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ZBUFFER(0),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_NODE_ORTHO(100),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_BACKGROUND_COLOR(0x0001),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_ZBUFFER(0),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ASM(0, geo18_display_error_message),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_END(),
|
|
+};
|
|
+
|
|
// 0x0E0002D0
|
|
const GeoLayout intro_geo_0002D0[] = {
|
|
GEO_NODE_SCREEN_AREA(0, SCREEN_WIDTH/2, SCREEN_HEIGHT/2, SCREEN_WIDTH/2, SCREEN_HEIGHT/2),
|
|
diff --git a/levels/intro/header.h b/levels/intro/header.h
|
|
index 99277e86..04797cd7 100644
|
|
--- a/levels/intro/header.h
|
|
+++ b/levels/intro/header.h
|
|
@@ -26,4 +26,8 @@ extern const LevelScript script_intro_L3[];
|
|
extern const LevelScript script_intro_L4[];
|
|
extern const LevelScript script_intro_L5[];
|
|
|
|
+extern const GeoLayout intro_geo_error_screen[];
|
|
+extern const LevelScript level_intro_entry_error_screen[];
|
|
+extern Gfx *geo18_display_error_message(u32 run, UNUSED struct GraphNode *sp44, UNUSED u32 sp48);
|
|
+
|
|
#endif
|
|
diff --git a/levels/intro/script.c b/levels/intro/script.c
|
|
index 04b8fc4c..ca9058c4 100644
|
|
--- a/levels/intro/script.c
|
|
+++ b/levels/intro/script.c
|
|
@@ -18,6 +18,21 @@
|
|
#include "make_const_nonconst.h"
|
|
#include "levels/intro/header.h"
|
|
|
|
+const LevelScript level_intro_entry_error_screen[] = {
|
|
+ INIT_LEVEL(),
|
|
+ FIXED_LOAD(/*loadAddr*/ _goddardSegmentStart, /*romStart*/ _goddardSegmentRomStart, /*romEnd*/ _goddardSegmentRomEnd),
|
|
+ LOAD_MIO0(/*seg*/ 0x07, _intro_segment_7SegmentRomStart, _intro_segment_7SegmentRomEnd),
|
|
+ ALLOC_LEVEL_POOL(),
|
|
+
|
|
+ AREA(/*index*/ 1, intro_geo_error_screen),
|
|
+ END_AREA(),
|
|
+
|
|
+ FREE_LEVEL_POOL(),
|
|
+ LOAD_AREA(/*area*/ 1),
|
|
+ SLEEP(/*frames*/ 32767),
|
|
+ EXIT_AND_EXECUTE(/*seg*/ 0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_entry_error_screen),
|
|
+};
|
|
+
|
|
const LevelScript level_intro_splash_screen[] = {
|
|
INIT_LEVEL(),
|
|
FIXED_LOAD(/*loadAddr*/ _goddardSegmentStart, /*romStart*/ _goddardSegmentRomStart, /*romEnd*/ _goddardSegmentRomEnd),
|
|
diff --git a/src/engine/level_script.h b/src/engine/level_script.h
|
|
index d41a91c8..7d047236 100644
|
|
--- a/src/engine/level_script.h
|
|
+++ b/src/engine/level_script.h
|
|
@@ -6,6 +6,7 @@
|
|
struct LevelCommand;
|
|
|
|
extern u8 level_script_entry[];
|
|
+extern u8 level_script_entry_error_screen[];
|
|
|
|
struct LevelCommand *level_script_execute(struct LevelCommand *cmd);
|
|
|
|
diff --git a/src/game/main.c b/src/game/main.c
|
|
index 1a9d9e7e..f4f7a9e5 100644
|
|
--- a/src/game/main.c
|
|
+++ b/src/game/main.c
|
|
@@ -11,6 +11,7 @@
|
|
#include "segments.h"
|
|
#include "main.h"
|
|
#include "rumble_init.h"
|
|
+#include "mem_error_screen.h"
|
|
|
|
// Message IDs
|
|
#define MESG_SP_COMPLETE 100
|
|
@@ -131,6 +132,10 @@ void alloc_pool(void) {
|
|
void *start = (void *) SEG_POOL_START;
|
|
void *end = (void *) SEG_POOL_END;
|
|
|
|
+ // Detect memory size
|
|
+ if (does_pool_end_lie_out_of_bounds(end))
|
|
+ end = (void *)SEG_POOL_END_4MB;
|
|
+
|
|
main_pool_init(start, end);
|
|
gEffectsMemoryPool = mem_pool_init(0x4000, MEMORY_POOL_LEFT);
|
|
}
|
|
@@ -336,7 +341,10 @@ void thread3_main(UNUSED void *arg) {
|
|
create_thread(&gSoundThread, 4, thread4_sound, NULL, gThread4Stack + 0x2000, 20);
|
|
osStartThread(&gSoundThread);
|
|
|
|
- create_thread(&gGameLoopThread, 5, thread5_game_loop, NULL, gThread5Stack + 0x2000, 10);
|
|
+ if (!gNotEnoughMemory)
|
|
+ create_thread(&gGameLoopThread, 5, thread5_game_loop, NULL, gThread5Stack + 0x2000, 10);
|
|
+ else
|
|
+ create_thread(&gGameLoopThread, 5, thread5_mem_error_message_loop, NULL, gThread5Stack + 0x2000, 10);
|
|
osStartThread(&gGameLoopThread);
|
|
|
|
while (TRUE) {
|
|
diff --git a/src/game/mem_error_screen.c b/src/game/mem_error_screen.c
|
|
new file mode 100644
|
|
index 00000000..f432927c
|
|
--- /dev/null
|
|
+++ b/src/game/mem_error_screen.c
|
|
@@ -0,0 +1,104 @@
|
|
+/* clang-format off */
|
|
+/*
|
|
+ * mem_error_screen.inc.c
|
|
+ *
|
|
+ * This enhancement should be used for ROM hacks that require the expansion pak.
|
|
+ *
|
|
+ */
|
|
+/* clang-format on */
|
|
+
|
|
+#include <types.h>
|
|
+#include "segments.h"
|
|
+#include "text_strings.h"
|
|
+#include "game_init.h"
|
|
+#include "main.h"
|
|
+#include "print.h"
|
|
+#include "ingame_menu.h"
|
|
+#include "segment2.h"
|
|
+#include "../engine/level_script.h"
|
|
+
|
|
+// Ensure that USE_EXT_RAM is defined.
|
|
+#ifndef USE_EXT_RAM
|
|
+#error You have to define USE_EXT_RAM in 'include/segments.h'
|
|
+#endif
|
|
+
|
|
+// Require 8 MB of RAM, even if the pool doesn't go into extended memory.
|
|
+// Change the '8' to whatever MB limit you want.
|
|
+// Note: only special emulators allow for RAM sizes above 8 MB.
|
|
+#define REQUIRED_MIN_MEM_SIZE 1048576 * 8
|
|
+
|
|
+u8 gNotEnoughMemory = FALSE;
|
|
+u8 gDelayForErrorMessage = 0;
|
|
+
|
|
+u8 does_pool_end_lie_out_of_bounds(void *end) {
|
|
+ u32 endPhy = ((u32) end) & 0x1FFFFFFF;
|
|
+ u32 memSize = *((u32 *) 0x80000318);
|
|
+
|
|
+ if (endPhy > memSize) {
|
|
+ gNotEnoughMemory = TRUE;
|
|
+ return TRUE;
|
|
+ } else {
|
|
+ if (memSize < REQUIRED_MIN_MEM_SIZE) {
|
|
+ gNotEnoughMemory = TRUE;
|
|
+ }
|
|
+ return FALSE;
|
|
+ }
|
|
+}
|
|
+
|
|
+// If you're using an N64 console, then you will need to buy an\nexpansion pak to play this ROM hack.
|
|
+u8 text_console_8mb[] = { TEXT_CONSOLE_8MB };
|
|
+
|
|
+// If you are using PJ64 1.6, go to: Options ► Settings ► Rom Settings Tab ► Memory Size then select 8
|
|
+// MB from the drop-down box.
|
|
+u8 text_pj64[] = { TEXT_PJ64 };
|
|
+
|
|
+// If you are using PJ64 2.X, go to: Options ► Settings ► Config: ► Memory Size, select 8 MB
|
|
+u8 text_pj64_2[] = { TEXT_PJ64_2 };
|
|
+
|
|
+Gfx *geo18_display_error_message(u32 run, UNUSED struct GraphNode *sp44, UNUSED u32 sp48) {
|
|
+ if (run) {
|
|
+ if (gDelayForErrorMessage > 0) {
|
|
+ // Draw color text title.
|
|
+ print_text(10, 210, "ERROR Need more memory");
|
|
+
|
|
+ // Init generic text rendering
|
|
+ create_dl_ortho_matrix();
|
|
+ gSPDisplayList(gDisplayListHead++,
|
|
+ dl_ia_text_begin); // Init rendering stuff for generic text
|
|
+
|
|
+ // Set text color to white
|
|
+ gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
|
+
|
|
+ print_generic_string(8, 170, text_console_8mb);
|
|
+ print_generic_string(8, 120, text_pj64);
|
|
+ print_generic_string(8, 54, text_pj64_2);
|
|
+
|
|
+ // Cleanup
|
|
+ gSPDisplayList(gDisplayListHead++,
|
|
+ dl_ia_text_end); // Reset back to default render settings.
|
|
+ gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
|
+ } else {
|
|
+ gDelayForErrorMessage += 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+// Basic main loop for the error screen. Note that controllers are not enabled here.
|
|
+void thread5_mem_error_message_loop(UNUSED void *arg) {
|
|
+ struct LevelCommand *addr;
|
|
+
|
|
+ setup_game_memory();
|
|
+ set_vblank_handler(2, &gGameVblankHandler, &gGameVblankQueue, (OSMesg) 1);
|
|
+
|
|
+ addr = segmented_to_virtual(level_script_entry_error_screen);
|
|
+
|
|
+ render_init();
|
|
+
|
|
+ while (1) {
|
|
+ select_gfx_pool();
|
|
+ addr = level_script_execute(addr);
|
|
+ display_and_vsync();
|
|
+ }
|
|
+}
|
|
diff --git a/src/game/mem_error_screen.h b/src/game/mem_error_screen.h
|
|
new file mode 100644
|
|
index 00000000..9fbff34c
|
|
--- /dev/null
|
|
+++ b/src/game/mem_error_screen.h
|
|
@@ -0,0 +1,8 @@
|
|
+#ifndef MEM_ERROR_SCREEN_H
|
|
+#define MEM_ERROR_SCREEN_H
|
|
+
|
|
+extern u8 gNotEnoughMemory;
|
|
+void thread5_mem_error_message_loop(UNUSED void *arg);
|
|
+u8 does_pool_end_lie_out_of_bounds(void *end);
|
|
+
|
|
+#endif
|