mirror of
https://github.com/s4Ys369/CHEATERex.git
synced 2025-01-22 07:32:10 -05:00
58ae0d7777
featuring DynOsv0.4 by PeachyPeach
5479 lines
243 KiB
Diff
5479 lines
243 KiB
Diff
diff --git a/Makefile b/Makefile
|
|
index 772f31a..0bc6334 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -425,6 +425,9 @@ DEP_FILES := $(O_FILES:.o=.d) $(ULTRA_O_FILES:.o=.d) $(GODDARD_O_FILES:.o=.d) $(
|
|
# Segment elf files
|
|
SEG_FILES := $(SEGMENT_ELF_FILES) $(ACTOR_ELF_FILES) $(LEVEL_ELF_FILES)
|
|
|
|
+# DynOS options txt files
|
|
+include Makefile_dynos
|
|
+
|
|
##################### Compiler Options #######################
|
|
INCLUDE_CFLAGS := -I include -I $(BUILD_DIR) -I $(BUILD_DIR)/include -I src -I .
|
|
ENDIAN_BITWIDTH := $(BUILD_DIR)/endian-and-bitwidth
|
|
diff --git a/Makefile_dynos b/Makefile_dynos
|
|
new file mode 100644
|
|
index 0000000..ffe2fa6
|
|
--- /dev/null
|
|
+++ b/Makefile_dynos
|
|
@@ -0,0 +1,21 @@
|
|
+# ----------------------
|
|
+# Dynamic Options System
|
|
+# ----------------------
|
|
+
|
|
+DYNOS_INPUT_DIR := ./dynos
|
|
+DYNOS_OUTPUT_DIR := $(BUILD_DIR)/$(BASEDIR)
|
|
+DYNOS_COPY_TO_RES := \
|
|
+ mkdir -p $(DYNOS_INPUT_DIR); \
|
|
+ mkdir -p $(DYNOS_OUTPUT_DIR); \
|
|
+ for f in $(DYNOS_INPUT_DIR)/*.txt; do \
|
|
+ [ -f "$$f" ] || continue; \
|
|
+ cp -f $$f $(DYNOS_OUTPUT_DIR)/$$(basename -- $$f); \
|
|
+ done;
|
|
+
|
|
+DYNOS := $(shell $(call DYNOS_COPY_TO_RES))
|
|
+
|
|
+ifeq ($(VERSION),eu)
|
|
+$(BUILD_DIR)/src/pc/dynamic_options.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/bin/eu/translation_en.o $(BUILD_DIR)/bin/eu/translation_de.o $(BUILD_DIR)/bin/eu/translation_fr.o
|
|
+else
|
|
+$(BUILD_DIR)/src/pc/dynamic_options.o: $(BUILD_DIR)/include/text_strings.h
|
|
+endif
|
|
diff --git a/dynos/time_trials_menu.txt b/dynos/time_trials_menu.txt
|
|
new file mode 100644
|
|
index 0000000..26f823d
|
|
--- /dev/null
|
|
+++ b/dynos/time_trials_menu.txt
|
|
@@ -0,0 +1,25 @@
|
|
+# Dynamic Options System aka DynOS v0.4
|
|
+# By PeachyPeach
|
|
+#
|
|
+# This is a comment
|
|
+# Here are the available commands:
|
|
+# SUBMENU [Name] [Label] [Label2]
|
|
+# TOGGLE [Name] [Label] [ConfigName] [InitialValue]
|
|
+# SCROLL [Name] [Label] [ConfigName] [InitialValue] [Min] [Max] [Step]
|
|
+# CHOICE [Name] [Label] [ConfigName] [InitialValue] [ChoiceStrings...]
|
|
+# BIND [Name] [Label] [ConfigName] [Mask] [DefaultValues]
|
|
+# BUTTON [Name] [Label] [FuncName]
|
|
+# ENDMENU
|
|
+#
|
|
+# Valid Label characters:
|
|
+# 0-9 A-Z a-z
|
|
+# '.,-()&:!%?"~_
|
|
+#
|
|
+
|
|
+
|
|
+SUBMENU "time_trials_submenu" "Time Trials" "TIME TRIALS"
|
|
+ TOGGLE "time_trials" "Time Trials" "time_trials" 1
|
|
+ CHOICE "time_trials_ghost1" "Time Trials Ghost" "time_trials_ghost1" 1 "Hide" "Show"
|
|
+ CHOICE "time_trials_ghost2" "Time Trials Special Ghost" "time_trials_ghost2" 1 "Hide" "Show"
|
|
+ TOGGLE "time_trials_cheats" "Time Trials with Cheats" "time_trials_cheats" 0
|
|
+ENDMENU
|
|
diff --git a/src/game/area.h b/src/game/area.h
|
|
index d746caa..5fc11f5 100644
|
|
--- a/src/game/area.h
|
|
+++ b/src/game/area.h
|
|
@@ -2,7 +2,7 @@
|
|
#define AREA_H
|
|
|
|
#include <PR/ultratypes.h>
|
|
-
|
|
+#include "time_trials.h"
|
|
#include "types.h"
|
|
#include "camera.h"
|
|
#include "engine/graph_node.h"
|
|
diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c
|
|
index 7ae9f1e..db8c73b 100644
|
|
--- a/src/game/ingame_menu.c
|
|
+++ b/src/game/ingame_menu.c
|
|
@@ -2663,9 +2663,11 @@ s16 render_pause_courses_and_castle(void) {
|
|
break;
|
|
case DIALOG_STATE_HORIZONTAL:
|
|
shade_screen();
|
|
- print_hud_pause_colorful_str();
|
|
- render_pause_castle_menu_box(160, 143);
|
|
- render_pause_castle_main_strings(104, 60);
|
|
+ if (!time_trials_render_pause_castle_main_strings(gCurrSaveFileNum - 1, &gDialogLineNum)) {
|
|
+ print_hud_pause_colorful_str();
|
|
+ render_pause_castle_menu_box(160, 143);
|
|
+ render_pause_castle_main_strings(104, 60);
|
|
+ }
|
|
|
|
#ifdef VERSION_EU
|
|
if (gPlayer3Controller->buttonPressed & (A_BUTTON | Z_TRIG | START_BUTTON))
|
|
@@ -2868,7 +2870,7 @@ void render_course_complete_lvl_info_and_hud_str(void) {
|
|
play_star_fanfare_and_flash_hud(1, 1 << (gLastCompletedStarNum - 1));
|
|
|
|
if (gLastCompletedStarNum == 7) {
|
|
- name = segmented_to_virtual(actNameTbl[COURSE_STAGES_MAX * 6 + 1]);
|
|
+ name = segmented_to_virtual(actNameTbl[COURSE_STAGES_MAX * 6]);
|
|
} else {
|
|
name = segmented_to_virtual(actNameTbl[(gLastCompletedCourseNum - 1) * 6 + gLastCompletedStarNum - 1]);
|
|
}
|
|
@@ -3071,6 +3073,7 @@ s16 render_menus_and_dialogs() {
|
|
s16 mode = 0;
|
|
|
|
create_dl_ortho_matrix();
|
|
+ time_trials_update(gMarioState, gMenuMode != -1);
|
|
|
|
if (gMenuMode != -1) {
|
|
switch (gMenuMode) {
|
|
diff --git a/src/game/interaction.c b/src/game/interaction.c
|
|
index 7a9c520..180940c 100644
|
|
--- a/src/game/interaction.c
|
|
+++ b/src/game/interaction.c
|
|
@@ -817,6 +817,7 @@ u32 interact_star_or_key(struct MarioState *m, UNUSED u32 interactType, struct O
|
|
// func_802521A0
|
|
#endif
|
|
|
|
+ noExit = time_trials_save_time_and_stop_timer(gCurrSaveFileNum - 1, gCurrCourseNum, gCurrLevelNum, starIndex, (!noExit || grandStar));
|
|
if (grandStar) {
|
|
return set_mario_action(m, ACT_JUMBO_STAR_CUTSCENE, 0);
|
|
}
|
|
diff --git a/src/game/options_menu.c b/src/game/options_menu.c
|
|
index 0bcb32b..8f68bbb 100644
|
|
--- a/src/game/options_menu.c
|
|
+++ b/src/game/options_menu.c
|
|
@@ -1,3 +1,3 @@
|
|
#ifdef EXT_OPTIONS_MENU
|
|
-
|
|
+#ifdef DYNOS_INL
|
|
#include "sm64.h"
|
|
@@ -634,4 +634,5 @@ void optmenu_check_buttons(void) {
|
|
}
|
|
}
|
|
|
|
+#endif
|
|
#endif // EXT_OPTIONS_MENU
|
|
diff --git a/src/game/time_trials.c b/src/game/time_trials.c
|
|
new file mode 100644
|
|
index 0000000..f465938
|
|
--- /dev/null
|
|
+++ b/src/game/time_trials.c
|
|
@@ -0,0 +1,1217 @@
|
|
+#include "time_trials.h"
|
|
+#include "sm64.h"
|
|
+#include "game_init.h"
|
|
+#include "sound_init.h"
|
|
+#include "geo_commands.h"
|
|
+#include "gfx_dimensions.h"
|
|
+#include "ingame_menu.h"
|
|
+#include "level_update.h"
|
|
+#include "object_helpers.h"
|
|
+#include "object_list_processor.h"
|
|
+#include "save_file.h"
|
|
+#include "segment2.h"
|
|
+#include "spawn_object.h"
|
|
+#include "pc/cheats.h"
|
|
+#include "pc/cliopts.h"
|
|
+#include "pc/configfile.h"
|
|
+#include "pc/fs/fs.h"
|
|
+#include "pc/levels.h"
|
|
+#include "engine/math_util.h"
|
|
+#include "audio/external.h"
|
|
+#include <stdio.h>
|
|
+
|
|
+#define TIME_TRIALS_MAX_ALLOWED_TIME 17999 // 9'59"99
|
|
+#define TIME_TRIALS_UNDEFINED_TIME -1
|
|
+
|
|
+//
|
|
+// Models
|
|
+//
|
|
+
|
|
+#include "time_trials_ghost_geo.inl"
|
|
+
|
|
+static const BehaviorScript bhvTimeTrialGhost1[] = { 0x08000000, 0x09000000 };
|
|
+static const BehaviorScript bhvTimeTrialGhost2[] = { 0x08000000, 0x09000000 };
|
|
+
|
|
+static struct GraphNode *time_trials_get_ghost_mario_graph_node(u8 color) {
|
|
+ static const GeoLayout *sGhostMarioGeoLayouts[4] = { ghost_mario_blue_geo, ghost_mario_red_geo, ghost_mario_green_geo, ghost_mario_gold_geo};
|
|
+ static struct GraphNode *sGhostMarioGraphNodes[4] = { NULL, NULL, NULL, NULL };
|
|
+ if (sGhostMarioGraphNodes[0] == NULL) {
|
|
+ for (u8 i = 0; i != 4; ++i) {
|
|
+ struct AllocOnlyPool *pool = calloc(1, 0x10000);
|
|
+ pool->totalSpace = 0x10000 - sizeof(struct AllocOnlyPool);
|
|
+ pool->usedSpace = 0;
|
|
+ pool->startPtr = (u8 *) pool + sizeof(struct AllocOnlyPool);
|
|
+ pool->freePtr = (u8 *) pool + sizeof(struct AllocOnlyPool);
|
|
+ sGhostMarioGraphNodes[i] = process_geo_layout(pool, (void *) sGhostMarioGeoLayouts[i]);
|
|
+ }
|
|
+ }
|
|
+ return sGhostMarioGraphNodes[color];
|
|
+}
|
|
+
|
|
+//
|
|
+// Utils
|
|
+//
|
|
+
|
|
+static const char *time_trials_get_save_filename() {
|
|
+ static char buffer[256];
|
|
+ snprintf(buffer, 256, "%s", SAVE_FILENAME);
|
|
+ buffer[strlen(buffer) - 4] = 0; // cut extension
|
|
+ return buffer;
|
|
+}
|
|
+
|
|
+static const char *time_trials_get_folder(const char *path) {
|
|
+ static char buffer[256];
|
|
+ snprintf(buffer, 256, "%s/%s", path, time_trials_get_save_filename());
|
|
+ return buffer;
|
|
+}
|
|
+
|
|
+static const char *time_trials_get_filename(const char *path, s32 fileIndex, s32 slotIndex) {
|
|
+ static char buffer[256];
|
|
+ snprintf(buffer, 256, "%s/%d.%d.ttg", time_trials_get_folder(path), fileIndex, slotIndex);
|
|
+ return buffer;
|
|
+}
|
|
+
|
|
+static const u8 *time_trials_int_to_sm64_string(s32 value, const char *format) {
|
|
+ static u8 buffer[64];
|
|
+ bzero(buffer, 64);
|
|
+ if (!format || strlen(format) > 8) {
|
|
+ return buffer;
|
|
+ }
|
|
+ s32 len = snprintf((char *) buffer, 64, format, value);
|
|
+ for (s32 i = 0; i < len; ++i) {
|
|
+ if (buffer[i] >= 'A' && buffer[i] <= 'F') {
|
|
+ buffer[i] = buffer[i] - 'A';
|
|
+ } else if (buffer[i] >= 'a' && buffer[i] <= 'f') {
|
|
+ buffer[i] = buffer[i] - 'a';
|
|
+ } else {
|
|
+ buffer[i] = buffer[i] - '0';
|
|
+ }
|
|
+ }
|
|
+ buffer[len] = DIALOG_CHAR_TERMINATOR;
|
|
+ return buffer;
|
|
+}
|
|
+
|
|
+//
|
|
+// Time Trials Slots
|
|
+//
|
|
+
|
|
+#define NUM_SLOTS sizeof(sTimeTrialSlots) / sizeof(sTimeTrialSlots[0])
|
|
+#define STAR_CODE(course, star) (u16)(((u16)(course & 0xFF) << 8) | ((u16)(star & 0xFF) << 0))
|
|
+
|
|
+static const u16 sTimeTrialSlots[] = {
|
|
+
|
|
+ /* Main courses */
|
|
+ STAR_CODE(COURSE_BOB, 0),
|
|
+ STAR_CODE(COURSE_BOB, 1),
|
|
+ STAR_CODE(COURSE_BOB, 2),
|
|
+ STAR_CODE(COURSE_BOB, 3),
|
|
+ STAR_CODE(COURSE_BOB, 4),
|
|
+ STAR_CODE(COURSE_BOB, 5),
|
|
+ STAR_CODE(COURSE_BOB, 6),
|
|
+ STAR_CODE(COURSE_WF, 0),
|
|
+ STAR_CODE(COURSE_WF, 1),
|
|
+ STAR_CODE(COURSE_WF, 2),
|
|
+ STAR_CODE(COURSE_WF, 3),
|
|
+ STAR_CODE(COURSE_WF, 4),
|
|
+ STAR_CODE(COURSE_WF, 5),
|
|
+ STAR_CODE(COURSE_WF, 6),
|
|
+ STAR_CODE(COURSE_JRB, 0),
|
|
+ STAR_CODE(COURSE_JRB, 1),
|
|
+ STAR_CODE(COURSE_JRB, 2),
|
|
+ STAR_CODE(COURSE_JRB, 3),
|
|
+ STAR_CODE(COURSE_JRB, 4),
|
|
+ STAR_CODE(COURSE_JRB, 5),
|
|
+ STAR_CODE(COURSE_JRB, 6),
|
|
+ STAR_CODE(COURSE_CCM, 0),
|
|
+ STAR_CODE(COURSE_CCM, 1),
|
|
+ STAR_CODE(COURSE_CCM, 2),
|
|
+ STAR_CODE(COURSE_CCM, 3),
|
|
+ STAR_CODE(COURSE_CCM, 4),
|
|
+ STAR_CODE(COURSE_CCM, 5),
|
|
+ STAR_CODE(COURSE_CCM, 6),
|
|
+ STAR_CODE(COURSE_BBH, 0),
|
|
+ STAR_CODE(COURSE_BBH, 1),
|
|
+ STAR_CODE(COURSE_BBH, 2),
|
|
+ STAR_CODE(COURSE_BBH, 3),
|
|
+ STAR_CODE(COURSE_BBH, 4),
|
|
+ STAR_CODE(COURSE_BBH, 5),
|
|
+ STAR_CODE(COURSE_BBH, 6),
|
|
+ STAR_CODE(COURSE_HMC, 0),
|
|
+ STAR_CODE(COURSE_HMC, 1),
|
|
+ STAR_CODE(COURSE_HMC, 2),
|
|
+ STAR_CODE(COURSE_HMC, 3),
|
|
+ STAR_CODE(COURSE_HMC, 4),
|
|
+ STAR_CODE(COURSE_HMC, 5),
|
|
+ STAR_CODE(COURSE_HMC, 6),
|
|
+ STAR_CODE(COURSE_LLL, 0),
|
|
+ STAR_CODE(COURSE_LLL, 1),
|
|
+ STAR_CODE(COURSE_LLL, 2),
|
|
+ STAR_CODE(COURSE_LLL, 3),
|
|
+ STAR_CODE(COURSE_LLL, 4),
|
|
+ STAR_CODE(COURSE_LLL, 5),
|
|
+ STAR_CODE(COURSE_LLL, 6),
|
|
+ STAR_CODE(COURSE_SSL, 0),
|
|
+ STAR_CODE(COURSE_SSL, 1),
|
|
+ STAR_CODE(COURSE_SSL, 2),
|
|
+ STAR_CODE(COURSE_SSL, 3),
|
|
+ STAR_CODE(COURSE_SSL, 4),
|
|
+ STAR_CODE(COURSE_SSL, 5),
|
|
+ STAR_CODE(COURSE_SSL, 6),
|
|
+ STAR_CODE(COURSE_DDD, 0),
|
|
+ STAR_CODE(COURSE_DDD, 1),
|
|
+ STAR_CODE(COURSE_DDD, 2),
|
|
+ STAR_CODE(COURSE_DDD, 3),
|
|
+ STAR_CODE(COURSE_DDD, 4),
|
|
+ STAR_CODE(COURSE_DDD, 5),
|
|
+ STAR_CODE(COURSE_DDD, 6),
|
|
+ STAR_CODE(COURSE_SL, 0),
|
|
+ STAR_CODE(COURSE_SL, 1),
|
|
+ STAR_CODE(COURSE_SL, 2),
|
|
+ STAR_CODE(COURSE_SL, 3),
|
|
+ STAR_CODE(COURSE_SL, 4),
|
|
+ STAR_CODE(COURSE_SL, 5),
|
|
+ STAR_CODE(COURSE_SL, 6),
|
|
+ STAR_CODE(COURSE_WDW, 0),
|
|
+ STAR_CODE(COURSE_WDW, 1),
|
|
+ STAR_CODE(COURSE_WDW, 2),
|
|
+ STAR_CODE(COURSE_WDW, 3),
|
|
+ STAR_CODE(COURSE_WDW, 4),
|
|
+ STAR_CODE(COURSE_WDW, 5),
|
|
+ STAR_CODE(COURSE_WDW, 6),
|
|
+ STAR_CODE(COURSE_TTM, 0),
|
|
+ STAR_CODE(COURSE_TTM, 1),
|
|
+ STAR_CODE(COURSE_TTM, 2),
|
|
+ STAR_CODE(COURSE_TTM, 3),
|
|
+ STAR_CODE(COURSE_TTM, 4),
|
|
+ STAR_CODE(COURSE_TTM, 5),
|
|
+ STAR_CODE(COURSE_TTM, 6),
|
|
+ STAR_CODE(COURSE_THI, 0),
|
|
+ STAR_CODE(COURSE_THI, 1),
|
|
+ STAR_CODE(COURSE_THI, 2),
|
|
+ STAR_CODE(COURSE_THI, 3),
|
|
+ STAR_CODE(COURSE_THI, 4),
|
|
+ STAR_CODE(COURSE_THI, 5),
|
|
+ STAR_CODE(COURSE_THI, 6),
|
|
+ STAR_CODE(COURSE_TTC, 0),
|
|
+ STAR_CODE(COURSE_TTC, 1),
|
|
+ STAR_CODE(COURSE_TTC, 2),
|
|
+ STAR_CODE(COURSE_TTC, 3),
|
|
+ STAR_CODE(COURSE_TTC, 4),
|
|
+ STAR_CODE(COURSE_TTC, 5),
|
|
+ STAR_CODE(COURSE_TTC, 6),
|
|
+ STAR_CODE(COURSE_RR, 0),
|
|
+ STAR_CODE(COURSE_RR, 1),
|
|
+ STAR_CODE(COURSE_RR, 2),
|
|
+ STAR_CODE(COURSE_RR, 3),
|
|
+ STAR_CODE(COURSE_RR, 4),
|
|
+ STAR_CODE(COURSE_RR, 5),
|
|
+ STAR_CODE(COURSE_RR, 6),
|
|
+
|
|
+ /* Bowser Courses */
|
|
+ STAR_CODE(COURSE_BITDW, 0),
|
|
+ STAR_CODE(COURSE_BITDW, 1),
|
|
+ STAR_CODE(COURSE_BITFS, 0),
|
|
+ STAR_CODE(COURSE_BITFS, 1),
|
|
+ STAR_CODE(COURSE_BITS, 0),
|
|
+ STAR_CODE(COURSE_BITS, 1),
|
|
+
|
|
+ /* Secret Courses */
|
|
+ STAR_CODE(COURSE_PSS, 0),
|
|
+ STAR_CODE(COURSE_PSS, 1),
|
|
+ STAR_CODE(COURSE_SA, 0),
|
|
+ STAR_CODE(COURSE_WMOTR, 0),
|
|
+ STAR_CODE(COURSE_TOTWC, 0),
|
|
+ STAR_CODE(COURSE_VCUTM, 0),
|
|
+ STAR_CODE(COURSE_COTMC, 0),
|
|
+};
|
|
+
|
|
+static s32 time_trials_get_slot_index(s32 course, s32 star) {
|
|
+ u16 starCode = STAR_CODE(course, star);
|
|
+ for (u32 i = 0; i != NUM_SLOTS; ++i) {
|
|
+ if (sTimeTrialSlots[i] == starCode) {
|
|
+ return (s32) i;
|
|
+ }
|
|
+ }
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+#undef STAR_CODE
|
|
+
|
|
+//
|
|
+// Ghost Frame data
|
|
+//
|
|
+
|
|
+struct TimeTrialGhostFrameData {
|
|
+ s16 posX;
|
|
+ s16 posY;
|
|
+ s16 posZ;
|
|
+ s8 pitch;
|
|
+ s8 yaw;
|
|
+ s8 roll;
|
|
+ u8 scaleX;
|
|
+ u8 scaleY;
|
|
+ u8 scaleZ;
|
|
+ u8 animIndex;
|
|
+ u8 animFrame;
|
|
+ u8 level;
|
|
+ u8 area;
|
|
+};
|
|
+#define time_trials_is_end_frame(p, f) (p[f].level == 0)
|
|
+
|
|
+//
|
|
+// Data
|
|
+//
|
|
+
|
|
+enum { TT_TIMER_DISABLED, TT_TIMER_RUNNING, TT_TIMER_STOPPED };
|
|
+static s8 sTimeTrialTimerState = TT_TIMER_DISABLED;
|
|
+static s16 sTimeTrialTimer = 0;
|
|
+static bool sTimeTrialHiScore = false;
|
|
+static struct TimeTrialGhostFrameData sTimeTrialGhostDataR1[TIME_TRIALS_MAX_ALLOWED_TIME]; // Read-only, normal ghost
|
|
+static struct TimeTrialGhostFrameData sTimeTrialGhostDataR2[TIME_TRIALS_MAX_ALLOWED_TIME]; // Read-only, special ghost
|
|
+static struct TimeTrialGhostFrameData sTimeTrialGhostDataW[TIME_TRIALS_MAX_ALLOWED_TIME]; // Write-only
|
|
+
|
|
+//
|
|
+// Read
|
|
+//
|
|
+
|
|
+static u16 read_u16(FILE *f) {
|
|
+ u8 low, high;
|
|
+ if (fread(&high, 1, 1, f)) {
|
|
+ if (fread(&low, 1, 1, f)) {
|
|
+ return (u16)(((u16)(high) << 8) | ((u16)(low)));
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static u8 read_u8(FILE *f) {
|
|
+ u8 byte;
|
|
+ if (fread(&byte, 1, 1, f)) {
|
|
+ return byte;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static s16 time_trials_read_ghost_data(s32 fileIndex, s32 slot, struct TimeTrialGhostFrameData* ghostData) {
|
|
+ if (ghostData != NULL) {
|
|
+ bzero(ghostData, (sizeof(struct TimeTrialGhostFrameData) * TIME_TRIALS_MAX_ALLOWED_TIME));
|
|
+ }
|
|
+
|
|
+ // Valid slot
|
|
+ if (slot == -1) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ // Open file
|
|
+ const char *filename = time_trials_get_filename(fs_writepath, fileIndex, slot);
|
|
+ FILE *f = fopen(filename, "rb");
|
|
+ if (f == NULL) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ // Read data
|
|
+ s16 length = (s16) read_u16(f);
|
|
+ if (ghostData != NULL) {
|
|
+ for (s16 i = 0; i != length; ++i) {
|
|
+ ghostData[i].posX = (s16) read_u16(f);
|
|
+ ghostData[i].posY = (s16) read_u16(f);
|
|
+ ghostData[i].posZ = (s16) read_u16(f);
|
|
+ ghostData[i].pitch = (s8) read_u8(f);
|
|
+ ghostData[i].yaw = (s8) read_u8(f);
|
|
+ ghostData[i].roll = (s8) read_u8(f);
|
|
+ ghostData[i].scaleX = read_u8(f);
|
|
+ ghostData[i].scaleY = read_u8(f);
|
|
+ ghostData[i].scaleZ = read_u8(f);
|
|
+ ghostData[i].animIndex = read_u8(f);
|
|
+ ghostData[i].animFrame = read_u8(f);
|
|
+ ghostData[i].level = read_u8(f);
|
|
+ ghostData[i].area = read_u8(f);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ fclose(f);
|
|
+ return length;
|
|
+}
|
|
+
|
|
+static s16 *time_trials_time(s32 fileIndex, s32 slot) {
|
|
+ static s16 sTimeTrialTimes[NUM_SAVE_FILES][NUM_SLOTS];
|
|
+ static bool inited = false;
|
|
+ if (!inited) {
|
|
+ for (s32 i = 0; i != NUM_SAVE_FILES; ++i) {
|
|
+ for (u32 j = 0; j != NUM_SLOTS; ++j) {
|
|
+ s16 t = time_trials_read_ghost_data(i, j, NULL);
|
|
+ if (t <= 0 || t > TIME_TRIALS_MAX_ALLOWED_TIME) {
|
|
+ t = TIME_TRIALS_UNDEFINED_TIME;
|
|
+ }
|
|
+ sTimeTrialTimes[i][j] = t;
|
|
+ }
|
|
+ }
|
|
+ inited = true;
|
|
+ }
|
|
+ return &sTimeTrialTimes[fileIndex][slot];
|
|
+}
|
|
+
|
|
+//
|
|
+// Write
|
|
+//
|
|
+
|
|
+static void write_u16(FILE *f, u16 word) {
|
|
+ u8 low = (u8)(word);
|
|
+ u8 high = (u8)(word >> 8);
|
|
+ fwrite(&high, 1, 1, f);
|
|
+ fwrite(&low, 1, 1, f);
|
|
+}
|
|
+
|
|
+static void write_u8(FILE *f, u8 byte) {
|
|
+ fwrite(&byte, 1, 1, f);
|
|
+}
|
|
+
|
|
+static void time_trials_write_ghost_data(s32 fileIndex, s32 slot) {
|
|
+
|
|
+ // Make folder
|
|
+ fs_sys_mkdir(time_trials_get_folder(fs_writepath));
|
|
+
|
|
+ // Open file
|
|
+ const char *filename = time_trials_get_filename(fs_writepath, fileIndex, slot);
|
|
+ FILE *f = fopen(filename, "wb");
|
|
+ if (f == NULL) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // Write length
|
|
+ s16 length = sTimeTrialTimer;
|
|
+ write_u16(f, length);
|
|
+
|
|
+ // Write data
|
|
+ for (s16 i = 0; i != length; ++i) {
|
|
+ write_u16(f, (u16) sTimeTrialGhostDataW[i].posX);
|
|
+ write_u16(f, (u16) sTimeTrialGhostDataW[i].posY);
|
|
+ write_u16(f, (u16) sTimeTrialGhostDataW[i].posZ);
|
|
+ write_u8(f, (u8) sTimeTrialGhostDataW[i].pitch);
|
|
+ write_u8(f, (u8) sTimeTrialGhostDataW[i].yaw);
|
|
+ write_u8(f, (u8) sTimeTrialGhostDataW[i].roll);
|
|
+ write_u8(f, sTimeTrialGhostDataW[i].scaleX);
|
|
+ write_u8(f, sTimeTrialGhostDataW[i].scaleY);
|
|
+ write_u8(f, sTimeTrialGhostDataW[i].scaleZ);
|
|
+ write_u8(f, sTimeTrialGhostDataW[i].animIndex);
|
|
+ write_u8(f, sTimeTrialGhostDataW[i].animFrame);
|
|
+ write_u8(f, sTimeTrialGhostDataW[i].level);
|
|
+ write_u8(f, sTimeTrialGhostDataW[i].area);
|
|
+ }
|
|
+
|
|
+ // Update times
|
|
+ *time_trials_time(fileIndex, slot) = length;
|
|
+ fclose(f);
|
|
+}
|
|
+
|
|
+u32 time_trials_save_time_and_stop_timer(s32 fileIndex, s32 course, s32 level, s32 star, bool exit) {
|
|
+ if (TIME_TRIALS_DISABLED) {
|
|
+ return (u32) (!exit);
|
|
+ }
|
|
+
|
|
+ // Force Mario to leave the course if he collects a main course star
|
|
+ if (course >= COURSE_BOB && course <= COURSE_STAGES_MAX) {
|
|
+ drop_queued_background_music();
|
|
+ fadeout_level_music(126);
|
|
+ exit = true;
|
|
+ }
|
|
+
|
|
+ // Save the time
|
|
+ if (sTimeTrialTimerState == TT_TIMER_RUNNING) {
|
|
+
|
|
+ // Bowser Key or Grand Star
|
|
+ if (exit && (level == LEVEL_BOWSER_1 || level == LEVEL_BOWSER_2 || level == LEVEL_BOWSER_3)) {
|
|
+ star = 1;
|
|
+ }
|
|
+
|
|
+ // Write time and ghost data if new record
|
|
+ s32 slot = time_trials_get_slot_index(course, star);
|
|
+ if (slot != -1) {
|
|
+ s16 t = *time_trials_time(fileIndex, slot);
|
|
+ if (t == TIME_TRIALS_UNDEFINED_TIME || t > sTimeTrialTimer) {
|
|
+ time_trials_write_ghost_data(fileIndex, slot);
|
|
+ sTimeTrialHiScore = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Stop the timer if Mario leaves the course
|
|
+ if (exit) {
|
|
+ sTimeTrialTimerState = TT_TIMER_STOPPED;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return (u32) (!exit);
|
|
+}
|
|
+
|
|
+//
|
|
+// Get
|
|
+//
|
|
+
|
|
+static s16 time_trials_get_time(s32 fileIndex, s32 course, s32 star) {
|
|
+ s32 slot = time_trials_get_slot_index(course, star);
|
|
+ if (slot == -1) return TIME_TRIALS_UNDEFINED_TIME;
|
|
+ return *time_trials_time(fileIndex, slot);
|
|
+}
|
|
+
|
|
+static s32 time_trials_get_course_time(s32 fileIndex, s32 course) {
|
|
+ s32 courseTime = 0;
|
|
+ for (s32 star = 0;; star++) {
|
|
+ s32 slot = time_trials_get_slot_index(course, star);
|
|
+ if (slot == -1) {
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ s16 t = *time_trials_time(fileIndex, slot);
|
|
+ if (t == TIME_TRIALS_UNDEFINED_TIME) {
|
|
+ return TIME_TRIALS_UNDEFINED_TIME;
|
|
+ }
|
|
+
|
|
+ courseTime += (s32) t;
|
|
+ }
|
|
+ return courseTime;
|
|
+}
|
|
+
|
|
+static s32 time_trials_get_bowser_time(s32 fileIndex) {
|
|
+ s32 bitdw = time_trials_get_course_time(fileIndex, COURSE_BITDW);
|
|
+ if (bitdw == TIME_TRIALS_UNDEFINED_TIME) {
|
|
+ return TIME_TRIALS_UNDEFINED_TIME;
|
|
+ }
|
|
+ s32 bitfs = time_trials_get_course_time(fileIndex, COURSE_BITFS);
|
|
+ if (bitfs == TIME_TRIALS_UNDEFINED_TIME) {
|
|
+ return TIME_TRIALS_UNDEFINED_TIME;
|
|
+ }
|
|
+ s32 bits = time_trials_get_course_time(fileIndex, COURSE_BITS);
|
|
+ if (bits == TIME_TRIALS_UNDEFINED_TIME) {
|
|
+ return TIME_TRIALS_UNDEFINED_TIME;
|
|
+ }
|
|
+ return bitdw + bitfs + bits;
|
|
+}
|
|
+
|
|
+static s32 time_trials_get_secret_time(s32 fileIndex) {
|
|
+ s32 pss = time_trials_get_course_time(fileIndex, COURSE_PSS);
|
|
+ if (pss == TIME_TRIALS_UNDEFINED_TIME) {
|
|
+ return TIME_TRIALS_UNDEFINED_TIME;
|
|
+ }
|
|
+ s32 cotmc = time_trials_get_course_time(fileIndex, COURSE_COTMC);
|
|
+ if (cotmc == TIME_TRIALS_UNDEFINED_TIME) {
|
|
+ return TIME_TRIALS_UNDEFINED_TIME;
|
|
+ }
|
|
+ s32 totwc = time_trials_get_course_time(fileIndex, COURSE_TOTWC);
|
|
+ if (totwc == TIME_TRIALS_UNDEFINED_TIME) {
|
|
+ return TIME_TRIALS_UNDEFINED_TIME;
|
|
+ }
|
|
+ s32 vcutm = time_trials_get_course_time(fileIndex, COURSE_VCUTM);
|
|
+ if (vcutm == TIME_TRIALS_UNDEFINED_TIME) {
|
|
+ return TIME_TRIALS_UNDEFINED_TIME;
|
|
+ }
|
|
+ s32 wmotr = time_trials_get_course_time(fileIndex, COURSE_WMOTR);
|
|
+ if (wmotr == TIME_TRIALS_UNDEFINED_TIME) {
|
|
+ return TIME_TRIALS_UNDEFINED_TIME;
|
|
+ }
|
|
+ s32 sa = time_trials_get_course_time(fileIndex, COURSE_SA);
|
|
+ if (sa == TIME_TRIALS_UNDEFINED_TIME) {
|
|
+ return TIME_TRIALS_UNDEFINED_TIME;
|
|
+ }
|
|
+ return pss + cotmc + totwc + vcutm + wmotr + sa;
|
|
+}
|
|
+
|
|
+static s32 time_trials_get_total_time(s32 fileIndex) {
|
|
+ s32 coursesTime = 0;
|
|
+ for (s32 course = COURSE_MIN; course <= COURSE_STAGES_MAX; course++) {
|
|
+ s32 t = time_trials_get_course_time(fileIndex, course);
|
|
+ if (t == TIME_TRIALS_UNDEFINED_TIME) {
|
|
+ return TIME_TRIALS_UNDEFINED_TIME;
|
|
+ }
|
|
+ coursesTime += t;
|
|
+ }
|
|
+
|
|
+ s32 bowserTime = time_trials_get_bowser_time(fileIndex);
|
|
+ if (bowserTime == TIME_TRIALS_UNDEFINED_TIME) {
|
|
+ return TIME_TRIALS_UNDEFINED_TIME;
|
|
+ }
|
|
+
|
|
+ s32 secretTime = time_trials_get_secret_time(fileIndex);
|
|
+ if (secretTime == TIME_TRIALS_UNDEFINED_TIME) {
|
|
+ return TIME_TRIALS_UNDEFINED_TIME;
|
|
+ }
|
|
+
|
|
+ return coursesTime + bowserTime + secretTime;
|
|
+}
|
|
+
|
|
+//
|
|
+// Ghost
|
|
+//
|
|
+
|
|
+struct TimeTrialGhostAnimationData {
|
|
+ struct Animation animation;
|
|
+ u8 animationData[0x40000];
|
|
+ u8 color;
|
|
+ u16 prevValidAnimIndex;
|
|
+};
|
|
+static struct TimeTrialGhostAnimationData sGhostAnimData1;
|
|
+static struct TimeTrialGhostAnimationData sGhostAnimData2;
|
|
+
|
|
+static u16 time_trials_ghost_retrieve_current_animation_index(struct MarioState *m) {
|
|
+ struct MarioAnimDmaRelatedThing *animDmaTable = m->animation->animDmaTable;
|
|
+ void *a = m->animation->currentAnimAddr;
|
|
+ for (u16 i = 0; i != animDmaTable->count; ++i) {
|
|
+ void *b = animDmaTable->srcAddr + animDmaTable->anim[i].offset;
|
|
+ if (a == b) {
|
|
+ return i;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static s32 time_trials_ghost_load_animation(struct TimeTrialGhostAnimationData *animData, struct MarioState *m, u16 animIndex) {
|
|
+ struct MarioAnimDmaRelatedThing *animDmaTable = m->animation->animDmaTable;
|
|
+ if (animIndex >= animDmaTable->count) {
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ // Raw data
|
|
+ u8 *addr = animDmaTable->srcAddr + animDmaTable->anim[animIndex].offset;
|
|
+ u32 size = animDmaTable->anim[animIndex].size;
|
|
+ bcopy(addr, animData->animationData, size);
|
|
+
|
|
+ // Seek index and values pointers
|
|
+ struct Animation *a = (struct Animation *) animData->animationData;
|
|
+ const u16 *indexStart = (const u16 *) ((uintptr_t) (animData->animationData) + (uintptr_t) (a->index));
|
|
+ const s16 *valueStart = (const s16 *) ((uintptr_t) (animData->animationData) + (uintptr_t) (a->values));
|
|
+
|
|
+ // Fill ghost animation data
|
|
+ bcopy(animData->animationData, &animData->animation, sizeof(struct Animation));
|
|
+ animData->animation.index = indexStart;
|
|
+ animData->animation.values = valueStart;
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+static void time_trials_ghost_update_animation(struct TimeTrialGhostAnimationData *animData, struct Object *obj, struct MarioState *m, u16 animIndex, u16 animFrame) {
|
|
+ if (obj->header.gfx.unk38.curAnim == NULL) {
|
|
+ animData->prevValidAnimIndex = 0xFFFF;
|
|
+ }
|
|
+
|
|
+ // Load & set animation
|
|
+ if (animIndex != animData->prevValidAnimIndex && time_trials_ghost_load_animation(animData, m, animIndex)) {
|
|
+ obj->header.gfx.unk38.curAnim = &animData->animation;
|
|
+ obj->header.gfx.unk38.animAccel = 0;
|
|
+ obj->header.gfx.unk38.animYTrans = m->unkB0;
|
|
+ animData->prevValidAnimIndex = animIndex;
|
|
+ }
|
|
+
|
|
+ // Set frame
|
|
+ if (obj->header.gfx.unk38.curAnim != NULL) {
|
|
+ obj->header.gfx.unk38.animFrame = MIN(animFrame, obj->header.gfx.unk38.curAnim->unk08 - 1);
|
|
+ }
|
|
+}
|
|
+
|
|
+static struct Object *obj_get_time_trials_ghost(const BehaviorScript *behavior) {
|
|
+ struct ObjectNode *listHead = &gObjectLists[OBJ_LIST_DEFAULT];
|
|
+ struct Object *next = (struct Object *) listHead->next;
|
|
+ while (next != (struct Object *) listHead) {
|
|
+ if (next->behavior == behavior && next->activeFlags != 0) {
|
|
+ return next;
|
|
+ }
|
|
+ next = (struct Object *) next->header.next;
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static void time_trials_update_ghost(struct TimeTrialGhostFrameData *ghostData, struct TimeTrialGhostAnimationData *animData, const BehaviorScript *behavior, struct MarioState *m, s16 frame, s16 level, s16 area, bool hide) {
|
|
+ struct Object *ghost = obj_get_time_trials_ghost(behavior);
|
|
+
|
|
+ // If timer reached its max or frame data is ended, unload the ghost
|
|
+ if (frame >= TIME_TRIALS_MAX_ALLOWED_TIME || time_trials_is_end_frame(ghostData, frame)) {
|
|
+ if (ghost != NULL) {
|
|
+ obj_mark_for_deletion(ghost);
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // Spawn ghost if not loaded
|
|
+ if (ghost == NULL) {
|
|
+ ghost = spawn_object(m->marioObj, 0, behavior);
|
|
+ }
|
|
+
|
|
+ // Hide ghost if disabled, on first frame or its level or area differs from Mario
|
|
+ if (hide || frame == 0 || ghostData[frame].level != (u8) level || ghostData[frame].area != (u8) area) {
|
|
+ ghost->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // Update ghost
|
|
+ ghost->hitboxRadius = 0;
|
|
+ ghost->hitboxHeight = 0;
|
|
+ ghost->oOpacity = 160;
|
|
+ ghost->oPosX = (f32) ghostData[frame].posX;
|
|
+ ghost->oPosY = (f32) ghostData[frame].posY;
|
|
+ ghost->oPosZ = (f32) ghostData[frame].posZ;
|
|
+ ghost->oFaceAnglePitch = (s16) ghostData[frame].pitch * 0x100;
|
|
+ ghost->oFaceAngleYaw = (s16) ghostData[frame].yaw * 0x100;
|
|
+ ghost->oFaceAngleRoll = (s16) ghostData[frame].roll * 0x100;
|
|
+ ghost->oMoveAnglePitch = (s16) ghostData[frame].pitch * 0x100;
|
|
+ ghost->oMoveAngleYaw = (s16) ghostData[frame].yaw * 0x100;
|
|
+ ghost->oMoveAngleRoll = (s16) ghostData[frame].roll * 0x100;
|
|
+ ghost->header.gfx.pos[0] = (f32) ghostData[frame].posX;
|
|
+ ghost->header.gfx.pos[1] = (f32) ghostData[frame].posY;
|
|
+ ghost->header.gfx.pos[2] = (f32) ghostData[frame].posZ;
|
|
+ ghost->header.gfx.angle[0] = (s16) ghostData[frame].pitch * 0x100;
|
|
+ ghost->header.gfx.angle[1] = (s16) ghostData[frame].yaw * 0x100;
|
|
+ ghost->header.gfx.angle[2] = (s16) ghostData[frame].roll * 0x100;
|
|
+ ghost->header.gfx.scale[0] = (f32) ghostData[frame].scaleX / 100.f;
|
|
+ ghost->header.gfx.scale[1] = (f32) ghostData[frame].scaleY / 100.f;
|
|
+ ghost->header.gfx.scale[2] = (f32) ghostData[frame].scaleZ / 100.f;
|
|
+ ghost->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE;
|
|
+ ghost->header.gfx.sharedChild = time_trials_get_ghost_mario_graph_node(animData->color);
|
|
+ time_trials_ghost_update_animation(animData, ghost, m, (u16) ghostData[frame].animIndex, (u16) ghostData[frame].animFrame);
|
|
+}
|
|
+
|
|
+static void time_trials_record_ghost(struct MarioState *m, s32 frame) {
|
|
+ if (frame < 0 || frame >= TIME_TRIALS_MAX_ALLOWED_TIME) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (m->marioObj && m->marioObj->header.gfx.unk38.curAnim) {
|
|
+ sTimeTrialGhostDataW[frame].posX = (s16) m->marioObj->oPosX;
|
|
+ sTimeTrialGhostDataW[frame].posY = (s16) m->marioObj->oPosY;
|
|
+ sTimeTrialGhostDataW[frame].posZ = (s16) m->marioObj->oPosZ;
|
|
+ sTimeTrialGhostDataW[frame].pitch = (s8) (m->marioObj->oFaceAnglePitch / 0x100);
|
|
+ sTimeTrialGhostDataW[frame].yaw = (s8) (m->marioObj->oFaceAngleYaw / 0x100);
|
|
+ sTimeTrialGhostDataW[frame].roll = (s8) (m->marioObj->oFaceAngleRoll / 0x100);
|
|
+ sTimeTrialGhostDataW[frame].scaleX = (u8) MAX(0, MIN(255, m->marioObj->header.gfx.scale[0] * 100.f));
|
|
+ sTimeTrialGhostDataW[frame].scaleY = (u8) MAX(0, MIN(255, m->marioObj->header.gfx.scale[1] * 100.f));
|
|
+ sTimeTrialGhostDataW[frame].scaleZ = (u8) MAX(0, MIN(255, m->marioObj->header.gfx.scale[2] * 100.f));
|
|
+ sTimeTrialGhostDataW[frame].animIndex = (u8) time_trials_ghost_retrieve_current_animation_index(m);
|
|
+ sTimeTrialGhostDataW[frame].animFrame = (u8) MAX(0, MIN(255, MIN(m->marioObj->header.gfx.unk38.animFrame, m->marioObj->header.gfx.unk38.curAnim->unk08 - 1)));
|
|
+ sTimeTrialGhostDataW[frame].level = (u8) gCurrLevelNum;
|
|
+ sTimeTrialGhostDataW[frame].area = (u8) gCurrAreaIndex;
|
|
+ } else if (frame > 0) {
|
|
+ sTimeTrialGhostDataW[frame] = sTimeTrialGhostDataW[frame - 1];
|
|
+ }
|
|
+}
|
|
+
|
|
+static void time_trials_ghost_unload(const BehaviorScript *behavior) {
|
|
+ struct Object *ghost = obj_get_time_trials_ghost(behavior);
|
|
+ if (ghost != NULL) {
|
|
+ obj_mark_for_deletion(ghost);
|
|
+ }
|
|
+}
|
|
+
|
|
+//
|
|
+// SM64 Strings
|
|
+//
|
|
+
|
|
+static u8 *time_trials_to_sm64_string(const char *str) {
|
|
+ u8 *str64 = calloc(strlen(str) + 1, sizeof(u8));
|
|
+ for (int k = 0;; str++) {
|
|
+ if (*str == 0) { str64[k++] = 0xFF; break; }
|
|
+ if (*str >= '0' && *str <= '9') str64[k++] = (u8) (*str - '0' + 0);
|
|
+ if (*str >= 'A' && *str <= 'Z') str64[k++] = (u8) (*str - 'A' + 10);
|
|
+ if (*str >= 'a' && *str <= 'z') str64[k++] = (u8) (*str - 'a' + 36);
|
|
+ if (*str == '\'') str64[k++] = (u8) (62);
|
|
+ if (*str == '.') str64[k++] = (u8) (63);
|
|
+ if (*str == ':') str64[k++] = (u8) (230);
|
|
+ if (*str == ',') str64[k++] = (u8) (111);
|
|
+ if (*str == '-') str64[k++] = (u8) (159);
|
|
+ if (*str == '"') str64[k++] = (u8) (246);
|
|
+ if (*str == '@') str64[k++] = (u8) (249); // coin
|
|
+ if (*str == '_') str64[k++] = (u8) (253); // empty star
|
|
+ if (*str == '+') str64[k++] = (u8) (250); // star filled
|
|
+ if (*str == '*') str64[k++] = (u8) (251); // x
|
|
+ if (*str == ' ') str64[k++] = (u8) (158); // space
|
|
+ }
|
|
+ return str64;
|
|
+}
|
|
+
|
|
+//
|
|
+// Int to String
|
|
+//
|
|
+
|
|
+static u8 *time_trials_time_to_string(s16 time) {
|
|
+ if (time == TIME_TRIALS_UNDEFINED_TIME) {
|
|
+ return time_trials_to_sm64_string("-'--\"--");
|
|
+ }
|
|
+
|
|
+ char buffer[32];
|
|
+ sprintf(buffer, "%01d'%02d\"%02d", (time / 1800) % 10, (time / 30) % 60, ((time * 10) / 3) % 100);
|
|
+ return time_trials_to_sm64_string(buffer);
|
|
+}
|
|
+
|
|
+static u8 *time_trials_course_time_to_string(s32 coursetime) {
|
|
+ if (coursetime == TIME_TRIALS_UNDEFINED_TIME) {
|
|
+ return time_trials_to_sm64_string("-'--\"--");
|
|
+ }
|
|
+
|
|
+ char buffer[32];
|
|
+ sprintf(buffer, "%02d'%02d\"%02d", (coursetime / 1800) % 100, (coursetime / 30) % 60, ((coursetime * 10) / 3) % 100);
|
|
+ return time_trials_to_sm64_string(buffer);
|
|
+}
|
|
+
|
|
+static u8 *time_trials_total_time_to_string(s32 totaltime) {
|
|
+ if (totaltime == TIME_TRIALS_UNDEFINED_TIME) {
|
|
+ return time_trials_to_sm64_string("--:--:--.--");
|
|
+ }
|
|
+
|
|
+ char buffer[32];
|
|
+ sprintf(buffer, "%02d:%02d:%02d.%02d", (totaltime / 1080000) % 100, (totaltime / 1800) % 60, (totaltime / 30) % 60, ((totaltime * 10) / 3) % 100);
|
|
+ return time_trials_to_sm64_string(buffer);
|
|
+}
|
|
+
|
|
+//
|
|
+// Render
|
|
+//
|
|
+
|
|
+static const u8 sDialogCharWidths[256] = {
|
|
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6,
|
|
+ 6, 6, 5, 6, 6, 5, 8, 8, 6, 6, 6, 6, 6, 5, 6, 6,
|
|
+ 8, 7, 6, 6, 6, 5, 5, 6, 5, 5, 6, 5, 4, 5, 5, 3,
|
|
+ 7, 5, 5, 5, 6, 5, 5, 5, 5, 5, 7, 7, 5, 5, 4, 4,
|
|
+ 8, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
+ 8, 8, 8, 8, 7, 7, 6, 7, 7, 0, 0, 0, 0, 0, 0, 0,
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6,
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
+ 7, 5, 10, 5, 9, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
+ 0, 0, 5, 7, 7, 6, 6, 8, 0, 8, 10, 6, 4, 10, 0, 0
|
|
+};
|
|
+
|
|
+static s16 time_trials_get_string_length(const u8 *str) {
|
|
+ s16 length = 0;
|
|
+ for (; *str != DIALOG_CHAR_TERMINATOR; ++str) {
|
|
+ length += sDialogCharWidths[*str];
|
|
+ }
|
|
+ return length;
|
|
+}
|
|
+
|
|
+enum { screen_left_edge = 0, screen_center = 1, screen_right_edge = 2 };
|
|
+enum { align_left = 0, align_center = 1, align_right = 2 };
|
|
+static void time_trials_render_string(s16 dx, s16 y, u8 *str, s8 origin, s8 alignment) {
|
|
+
|
|
+ // Compute x position from origin and alignment
|
|
+ s16 x = 0;
|
|
+ s16 l = time_trials_get_string_length(str);
|
|
+ s8 mode = origin * 10 + alignment;
|
|
+ switch (mode) {
|
|
+ case 00: x = GFX_DIMENSIONS_FROM_LEFT_EDGE (dx); break; // screen_left_edge, align_left
|
|
+ case 01: x = GFX_DIMENSIONS_FROM_LEFT_EDGE (dx - l / 2); break; // screen_left_edge, align_center
|
|
+ case 02: x = GFX_DIMENSIONS_FROM_LEFT_EDGE (dx - l); break; // screen_left_edge, align_right
|
|
+ case 10: x = SCREEN_WIDTH / 2 + (dx); break; // screen_center, align_left
|
|
+ case 11: x = SCREEN_WIDTH / 2 + (dx - l / 2); break; // screen_center, align_center
|
|
+ case 12: x = SCREEN_WIDTH / 2 + (dx - l); break; // screen_center, align_right
|
|
+ case 20: x = GFX_DIMENSIONS_FROM_RIGHT_EDGE(dx); break; // screen_right_edge, align_left
|
|
+ case 21: x = GFX_DIMENSIONS_FROM_RIGHT_EDGE(dx + l / 2); break; // screen_right_edge, align_center
|
|
+ case 22: x = GFX_DIMENSIONS_FROM_RIGHT_EDGE(dx + l); break; // screen_right_edge, align_right
|
|
+ }
|
|
+
|
|
+ // Render characters
|
|
+ u8 c = ((str[0] == 159 || str[0] == 253) ? 0xA0 : 0xFF);
|
|
+ void **fontLUT = (void **) segmented_to_virtual(main_font_lut);
|
|
+ gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
|
|
+ gDPSetEnvColor(gDisplayListHead++, c, c, c, gDialogTextAlpha);
|
|
+ create_dl_translation_matrix(MENU_MTX_PUSH, x, y, 0);
|
|
+ for (u8 *p = str; *p != DIALOG_CHAR_TERMINATOR; ++p) {
|
|
+ if (*p != DIALOG_CHAR_SPACE) {
|
|
+ void *tex = segmented_to_virtual(fontLUT[*p]);
|
|
+ gDPPipeSync(gDisplayListHead++);
|
|
+ gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_16b, 1, VIRTUAL_TO_PHYSICAL(tex));
|
|
+ gSPDisplayList(gDisplayListHead++, dl_ia_text_tex_settings);
|
|
+ }
|
|
+ create_dl_translation_matrix(MENU_MTX_NOPUSH, sDialogCharWidths[*p], 0, 0);
|
|
+ }
|
|
+ gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
|
+ gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
|
+ gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
|
|
+
|
|
+ // Free the string after rendering it
|
|
+ free(str);
|
|
+}
|
|
+
|
|
+static void time_trials_render_centered_box(s32 y, s32 w, s32 h) {
|
|
+ Mtx *matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
|
|
+ if (!matrix) return;
|
|
+ create_dl_translation_matrix(MENU_MTX_PUSH, (SCREEN_WIDTH - w) / 2, y + h, 0);
|
|
+ guScale(matrix, (f32) w / 130.f, (f32) h / 80.f, 1.f);
|
|
+ gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
|
|
+ gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 105);
|
|
+ gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
|
|
+ gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
|
+}
|
|
+
|
|
+
|
|
+/*
|
|
+Position:
|
|
+Title
|
|
+1 5
|
|
+2 6
|
|
+3 7
|
|
+4 8
|
|
+C T
|
|
+*/
|
|
+
|
|
+#define TIME_TRIALS_BOX_H_MARGIN (22.5f * sqr(gfx_current_dimensions.aspect_ratio))
|
|
+#define TIME_TRIALS_BOX_V_MARGIN (40.f)
|
|
+#define TIME_TRIALS_TEXT_H_MARGIN (9.f * gfx_current_dimensions.aspect_ratio)
|
|
+#define TIME_TRIALS_TEXT_V_MARGIN (12.f)
|
|
+
|
|
+struct RenderParams { const char *label; bool starGet; s16 time; };
|
|
+static const struct RenderParams sNoParam = { NULL, 0, 0 };
|
|
+
|
|
+static void time_trials_render_pause_times(struct RenderParams params[8], const char *title, s32 courseTime, s32 totalTime) {
|
|
+
|
|
+ // Title
|
|
+ time_trials_render_string(0, SCREEN_HEIGHT - TIME_TRIALS_BOX_V_MARGIN - TIME_TRIALS_TEXT_V_MARGIN - 14, time_trials_to_sm64_string(title), screen_center, align_center);
|
|
+
|
|
+ // Stars
|
|
+ for (s32 i = 0; i != 8; ++i) {
|
|
+ if (params[i].label == NULL) continue;
|
|
+ s16 dx, y = (SCREEN_HEIGHT / 2) + ((TIME_TRIALS_TEXT_V_MARGIN / 2) + 10 + TIME_TRIALS_TEXT_V_MARGIN) - (10 + TIME_TRIALS_TEXT_V_MARGIN) * (i % 4) - 3;
|
|
+
|
|
+ // Label
|
|
+ dx = TIME_TRIALS_TEXT_H_MARGIN + (i < 4 ? TIME_TRIALS_BOX_H_MARGIN : 0);
|
|
+ time_trials_render_string(dx, y, time_trials_to_sm64_string(params[i].label), (i < 4 ? screen_left_edge : screen_center), align_left);
|
|
+
|
|
+ // Time
|
|
+ dx = (TIME_TRIALS_TEXT_H_MARGIN + (i < 4 ? 0 : TIME_TRIALS_BOX_H_MARGIN)) * (i < 4 ? -1 : +1);
|
|
+ time_trials_render_string(dx, y, time_trials_time_to_string(params[i].time), (i < 4 ? screen_center : screen_right_edge), align_right);
|
|
+
|
|
+ // Star icon
|
|
+ dx = (TIME_TRIALS_TEXT_H_MARGIN + (i < 4 ? 0 : TIME_TRIALS_BOX_H_MARGIN) + 48) * (i < 4 ? -1 : +1);
|
|
+ time_trials_render_string(dx, y, time_trials_to_sm64_string(params[i].starGet ? "+" : "_"), (i < 4 ? screen_center : screen_right_edge), align_right);
|
|
+ }
|
|
+
|
|
+ // Course time
|
|
+ time_trials_render_string(TIME_TRIALS_TEXT_H_MARGIN + TIME_TRIALS_BOX_H_MARGIN, TIME_TRIALS_BOX_V_MARGIN + TIME_TRIALS_TEXT_V_MARGIN - 3, time_trials_to_sm64_string("COURSE"), screen_left_edge, align_left);
|
|
+ time_trials_render_string(-TIME_TRIALS_TEXT_H_MARGIN, TIME_TRIALS_BOX_V_MARGIN + TIME_TRIALS_TEXT_V_MARGIN - 3, time_trials_course_time_to_string(courseTime), screen_center, align_right);
|
|
+
|
|
+ // Total time
|
|
+ time_trials_render_string(TIME_TRIALS_TEXT_H_MARGIN, TIME_TRIALS_BOX_V_MARGIN + TIME_TRIALS_TEXT_V_MARGIN - 3, time_trials_to_sm64_string("TOTAL"), screen_center, align_left);
|
|
+ time_trials_render_string(TIME_TRIALS_TEXT_H_MARGIN + TIME_TRIALS_BOX_H_MARGIN, TIME_TRIALS_BOX_V_MARGIN + TIME_TRIALS_TEXT_V_MARGIN - 3, time_trials_total_time_to_string(totalTime), screen_right_edge, align_right);
|
|
+}
|
|
+
|
|
+static void time_trials_render_pause_course_times(s32 fileIndex, s32 course) {
|
|
+ u8 starFlags = save_file_get_star_flags(fileIndex, course - COURSE_MIN);
|
|
+
|
|
+ time_trials_render_pause_times((struct RenderParams[]) {
|
|
+ (struct RenderParams) { "STAR 1", (starFlags >> 0) & 1, time_trials_get_time(fileIndex, course, 0) },
|
|
+ (struct RenderParams) { "STAR 2", (starFlags >> 1) & 1, time_trials_get_time(fileIndex, course, 1) },
|
|
+ (struct RenderParams) { "STAR 3", (starFlags >> 2) & 1, time_trials_get_time(fileIndex, course, 2) },
|
|
+ sNoParam,
|
|
+ (struct RenderParams) { "STAR 4", (starFlags >> 3) & 1, time_trials_get_time(fileIndex, course, 3) },
|
|
+ (struct RenderParams) { "STAR 5", (starFlags >> 4) & 1, time_trials_get_time(fileIndex, course, 4) },
|
|
+ (struct RenderParams) { "STAR 6", (starFlags >> 5) & 1, time_trials_get_time(fileIndex, course, 5) },
|
|
+ (struct RenderParams) { "STAR @", (starFlags >> 6) & 1, time_trials_get_time(fileIndex, course, 6) },
|
|
+ },
|
|
+ level_get_name(level_get_list(true, true)[course - COURSE_MIN]),
|
|
+ time_trials_get_course_time(fileIndex, course),
|
|
+ time_trials_get_total_time(fileIndex)
|
|
+ );
|
|
+}
|
|
+
|
|
+static void time_trials_render_pause_bowser_times(s32 fileIndex) {
|
|
+ u8 bitdwStarFlags = save_file_get_star_flags(fileIndex, COURSE_BITDW - COURSE_MIN);
|
|
+ u8 bitfsStarFlags = save_file_get_star_flags(fileIndex, COURSE_BITFS - COURSE_MIN);
|
|
+ u8 bitsStarFlags = save_file_get_star_flags(fileIndex, COURSE_BITS - COURSE_MIN);
|
|
+ u8 bitdwKeyFlag = save_file_get_flags() & (SAVE_FLAG_HAVE_KEY_1 | SAVE_FLAG_UNLOCKED_BASEMENT_DOOR);
|
|
+ u8 bitfsKeyFlag = save_file_get_flags() & (SAVE_FLAG_HAVE_KEY_2 | SAVE_FLAG_UNLOCKED_UPSTAIRS_DOOR);
|
|
+ u8 bitsGrandStar = time_trials_get_time(fileIndex, COURSE_BITS, 1) != TIME_TRIALS_UNDEFINED_TIME;
|
|
+
|
|
+ time_trials_render_pause_times((struct RenderParams[]) {
|
|
+ (struct RenderParams) { "STAR 1", (bitdwStarFlags >> 0) & 1, time_trials_get_time(fileIndex, COURSE_BITDW, 0) },
|
|
+ (struct RenderParams) { "STAR 2", (bitfsStarFlags >> 0) & 1, time_trials_get_time(fileIndex, COURSE_BITFS, 0) },
|
|
+ (struct RenderParams) { "STAR 3", (bitsStarFlags >> 0) & 1, time_trials_get_time(fileIndex, COURSE_BITS, 0) },
|
|
+ sNoParam,
|
|
+ (struct RenderParams) { "KEY 1", (bitdwKeyFlag) != 0, time_trials_get_time(fileIndex, COURSE_BITDW, 1) },
|
|
+ (struct RenderParams) { "KEY 2", (bitfsKeyFlag) != 0, time_trials_get_time(fileIndex, COURSE_BITFS, 1) },
|
|
+ (struct RenderParams) { "FINAL", (bitsGrandStar) != 0, time_trials_get_time(fileIndex, COURSE_BITS, 1) },
|
|
+ sNoParam,
|
|
+ },
|
|
+ "BOWSER COURSES",
|
|
+ time_trials_get_bowser_time(fileIndex),
|
|
+ time_trials_get_total_time(fileIndex)
|
|
+ );
|
|
+}
|
|
+
|
|
+static void time_trials_render_pause_secret_times(s32 fileIndex) {
|
|
+ u8 totwcStarFlags = save_file_get_star_flags(fileIndex, COURSE_TOTWC - COURSE_MIN);
|
|
+ u8 vcutmStarFlags = save_file_get_star_flags(fileIndex, COURSE_VCUTM - COURSE_MIN);
|
|
+ u8 cotmcStarFlags = save_file_get_star_flags(fileIndex, COURSE_COTMC - COURSE_MIN);
|
|
+ u8 pssStarFlags = save_file_get_star_flags(fileIndex, COURSE_PSS - COURSE_MIN);
|
|
+ u8 saStarFlags = save_file_get_star_flags(fileIndex, COURSE_SA - COURSE_MIN);
|
|
+ u8 wmotrStarFlags = save_file_get_star_flags(fileIndex, COURSE_WMOTR - COURSE_MIN);
|
|
+
|
|
+ time_trials_render_pause_times((struct RenderParams[]) {
|
|
+ (struct RenderParams) { "PSS 1", (pssStarFlags >> 0) & 1, time_trials_get_time(fileIndex, COURSE_PSS, 0) },
|
|
+ (struct RenderParams) { "PSS 2", (pssStarFlags >> 1) & 1, time_trials_get_time(fileIndex, COURSE_PSS, 1) },
|
|
+ (struct RenderParams) { "SA", (saStarFlags >> 0) & 1, time_trials_get_time(fileIndex, COURSE_SA, 0) },
|
|
+ (struct RenderParams) { "WMOTR", (wmotrStarFlags >> 0) & 1, time_trials_get_time(fileIndex, COURSE_WMOTR, 0) },
|
|
+ (struct RenderParams) { "TOTWC", (totwcStarFlags >> 0) & 1, time_trials_get_time(fileIndex, COURSE_TOTWC, 0) },
|
|
+ (struct RenderParams) { "VCUTM", (vcutmStarFlags >> 0) & 1, time_trials_get_time(fileIndex, COURSE_VCUTM, 0) },
|
|
+ (struct RenderParams) { "COTMC", (cotmcStarFlags >> 0) & 1, time_trials_get_time(fileIndex, COURSE_COTMC, 0) },
|
|
+ sNoParam,
|
|
+ },
|
|
+ "SECRET COURSES",
|
|
+ time_trials_get_secret_time(fileIndex),
|
|
+ time_trials_get_total_time(fileIndex)
|
|
+ );
|
|
+}
|
|
+
|
|
+extern void create_dl_rotation_matrix(s8 pushOp, f32 a, f32 x, f32 y, f32 z);
|
|
+s32 time_trials_render_pause_castle_main_strings(s32 fileIndex, s8 *index) {
|
|
+ if (TIME_TRIALS_DISABLED) {
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ s8 prevIndex = *index;
|
|
+ handle_menu_scrolling(MENU_SCROLL_VERTICAL, index, -1, COURSE_STAGES_COUNT + 2);
|
|
+ *index = (*index + COURSE_STAGES_COUNT + 2) % (COURSE_STAGES_COUNT + 2);
|
|
+
|
|
+ // Hide the undiscovered courses
|
|
+ if (*index < COURSE_STAGES_COUNT) {
|
|
+ s8 inc = (*index >= prevIndex ? +1 : -1);
|
|
+ while (save_file_get_course_star_count(fileIndex, *index) == 0) {
|
|
+ *index += inc;
|
|
+ if (*index == COURSE_STAGES_COUNT || *index == -1) {
|
|
+ *index = COURSE_STAGES_COUNT;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Render the colorful "PAUSE"
|
|
+ u8 *pause = time_trials_to_sm64_string("PAUSE");
|
|
+ gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
|
|
+ gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
|
|
+ print_hud_lut_string(HUD_LUT_GLOBAL, SCREEN_WIDTH / 2 - 30, 8, pause);
|
|
+ gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
|
|
+ free(pause);
|
|
+
|
|
+ // Render the black box behind the text
|
|
+ time_trials_render_centered_box(TIME_TRIALS_BOX_V_MARGIN, GFX_DIMENSIONS_FROM_RIGHT_EDGE(TIME_TRIALS_BOX_H_MARGIN) - GFX_DIMENSIONS_FROM_LEFT_EDGE(TIME_TRIALS_BOX_H_MARGIN), SCREEN_HEIGHT - 2 * TIME_TRIALS_BOX_V_MARGIN);
|
|
+ create_dl_translation_matrix(MENU_MTX_PUSH, SCREEN_WIDTH / 2 + 8, SCREEN_HEIGHT - TIME_TRIALS_BOX_V_MARGIN + 4, 0);
|
|
+ create_dl_rotation_matrix(MENU_MTX_NOPUSH, 90.0f, 0, 0, 1.0f);
|
|
+ gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
|
|
+ gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
|
|
+ gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
|
+ create_dl_translation_matrix(MENU_MTX_PUSH, SCREEN_WIDTH / 2 - 8, TIME_TRIALS_BOX_V_MARGIN - 4, 0);
|
|
+ create_dl_rotation_matrix(MENU_MTX_NOPUSH, 270.0f, 0, 0, 1.0f);
|
|
+ gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
|
|
+ gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
|
+
|
|
+ // Render the text
|
|
+ gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
|
|
+ gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
|
|
+ switch (*index) {
|
|
+ case COURSE_STAGES_COUNT: time_trials_render_pause_secret_times(fileIndex); break;
|
|
+ case COURSE_STAGES_COUNT + 1: time_trials_render_pause_bowser_times(fileIndex); break;
|
|
+ default: time_trials_render_pause_course_times(fileIndex, *index + COURSE_MIN); break;
|
|
+ }
|
|
+ gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+//
|
|
+// HUD
|
|
+//
|
|
+
|
|
+static s16 time_trials_get_x_centered(const u8 *str64) {
|
|
+ s16 len = 0;
|
|
+ while (*str64 != 0xFF) {
|
|
+ len += (*str64 == GLOBAL_CHAR_SPACE ? 8 : 12);
|
|
+ str64++;
|
|
+ }
|
|
+ return (SCREEN_WIDTH / 2) - (len / 2);
|
|
+}
|
|
+
|
|
+static void time_trials_render_dont_be_a_cheater(s16 y) {
|
|
+ u8 *s = time_trials_to_sm64_string("DON T BE A CHEATER");
|
|
+ s16 x = time_trials_get_x_centered(s);
|
|
+ gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
|
|
+ gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
|
+ print_hud_lut_string(HUD_LUT_GLOBAL, time_trials_get_x_centered(s), y, s);
|
|
+ print_hud_lut_string(HUD_LUT_GLOBAL, x + 33, y - 8, (const u8 *) (const u8 []) { 56, 255 });
|
|
+ gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
|
|
+ gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
|
+ free(s);
|
|
+}
|
|
+
|
|
+static s16 time_trials_get_x_from_center(const u8 *str64) {
|
|
+ s16 len = 0;
|
|
+ while (*str64 != 0xFF) {
|
|
+ len += (*str64 == GLOBAL_CHAR_SPACE ? 8 : 12);
|
|
+ str64++;
|
|
+ }
|
|
+ return (SCREEN_WIDTH / 2) - len;
|
|
+}
|
|
+
|
|
+static void time_trials_render_timer(s16 y, const char *text, s16 time, u8 colorFade) {
|
|
+ u8 *s = time_trials_to_sm64_string(text);
|
|
+ s16 x = time_trials_get_x_from_center(s);
|
|
+ gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
|
|
+ gDPSetEnvColor(gDisplayListHead++, colorFade, colorFade, colorFade, 255);
|
|
+ print_hud_lut_string(HUD_LUT_GLOBAL, x - 6, y, s);
|
|
+ print_hud_lut_string(HUD_LUT_GLOBAL, SCREEN_WIDTH / 2 + 6, y, time_trials_int_to_sm64_string( (time / 1800) % 60, "%01d"));
|
|
+ print_hud_lut_string(HUD_LUT_GLOBAL, SCREEN_WIDTH / 2 + 26, y, time_trials_int_to_sm64_string( (time / 30) % 60, "%02d"));
|
|
+ print_hud_lut_string(HUD_LUT_GLOBAL, SCREEN_WIDTH / 2 + 60, y, time_trials_int_to_sm64_string(((time * 10) / 3) % 100, "%02d"));
|
|
+ print_hud_lut_string(HUD_LUT_GLOBAL, SCREEN_WIDTH / 2 + 16, y - 8, (const u8 *) (const u8 []) { 56, 255 });
|
|
+ print_hud_lut_string(HUD_LUT_GLOBAL, SCREEN_WIDTH / 2 + 51, y - 8, (const u8 *) (const u8 []) { 57, 255 });
|
|
+ gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
|
|
+ gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
|
+ free(s);
|
|
+}
|
|
+
|
|
+void time_trials_render_star_select_time(s32 fileIndex, s32 course, s32 star) {
|
|
+ if (TIME_TRIALS_ENABLED) {
|
|
+ s16 time = time_trials_get_time(fileIndex, course, star);
|
|
+ if (time != TIME_TRIALS_UNDEFINED_TIME) {
|
|
+ time_trials_render_timer(12, "HI SCORE", time, 255);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+//
|
|
+// Update
|
|
+//
|
|
+
|
|
+static s32 time_trials_get_ghost_data_to_load(s32 course, s32 star) {
|
|
+ if (course >= COURSE_BOB && course <= COURSE_RR) return MAX(0, MIN(star, 5));
|
|
+ if (course >= COURSE_BITDW && course <= COURSE_BITS) return 1;
|
|
+ if (course == COURSE_PSS) return 0;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static s32 time_trials_get_special_ghost_data_to_load(s32 course) {
|
|
+ if (course >= COURSE_BOB && course <= COURSE_RR) return 6;
|
|
+ if (course >= COURSE_BITDW && course <= COURSE_BITS) return 0;
|
|
+ if (course == COURSE_PSS) return 1;
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static bool time_trials_should_start_timer(struct MarioState *m) {
|
|
+ switch (m->action) {
|
|
+ case ACT_SPAWN_SPIN_AIRBORNE: return (gCurrCourseNum >= COURSE_BOB && gCurrCourseNum <= COURSE_STAGES_MAX);
|
|
+ case ACT_SPAWN_NO_SPIN_AIRBORNE: return (gCurrCourseNum > COURSE_STAGES_MAX);
|
|
+ case ACT_FLYING: return (gCurrCourseNum == COURSE_TOTWC && m->actionArg == 2);
|
|
+ case ACT_WATER_IDLE: return (gCurrCourseNum == COURSE_SA && m->actionArg == 1);
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+extern bool dynos_perform_warp(enum LevelNum, int);
|
|
+static bool time_trials_warp_to_level(UNUSED const char *optName) {
|
|
+ enum LevelNum levelNum = level_get_list(true, true)[dynos_get_value("dynos_warp_level")];
|
|
+ if (TIME_TRIALS_ENABLED && (levelNum == LEVEL_BOWSER_1 || levelNum == LEVEL_BOWSER_2 || levelNum == LEVEL_BOWSER_3)) {
|
|
+ return false;
|
|
+ }
|
|
+ return dynos_perform_warp(levelNum, dynos_get_value("dynos_warp_act") + 1);
|
|
+}
|
|
+
|
|
+void time_trials_update(struct MarioState *m, bool isPaused) {
|
|
+ static s16 sLoadedSvFileNum = -1;
|
|
+ static s16 sLoadedCourseNum = -1;
|
|
+ static s16 sLoadedStarIndex = -1;
|
|
+
|
|
+ if (TIME_TRIALS_ENABLED) {
|
|
+
|
|
+ // Overwrites "dynos_warp_to_level" function to prevent the player
|
|
+ // from warping directly to Bowser fights while TT is active
|
|
+ dynos_add_action("dynos_warp_to_level", time_trials_warp_to_level, true);
|
|
+
|
|
+ // Update running ghost, record ghost data, and advance timer if it's running
|
|
+ if (sTimeTrialTimerState == TT_TIMER_RUNNING) {
|
|
+ sTimeTrialHiScore = false;
|
|
+
|
|
+ // Set to max time and stop timer if Cheats are enabled (also unload ghosts)
|
|
+ if (Cheats.EnableCheats && TIME_TRIALS_CHEATS_DISABLED) {
|
|
+ sTimeTrialTimerState = TT_TIMER_STOPPED;
|
|
+ sTimeTrialTimer = TIME_TRIALS_MAX_ALLOWED_TIME;
|
|
+ time_trials_ghost_unload(bhvTimeTrialGhost1);
|
|
+ time_trials_ghost_unload(bhvTimeTrialGhost2);
|
|
+ sLoadedSvFileNum = -1;
|
|
+ sLoadedCourseNum = -1;
|
|
+ sLoadedStarIndex = -1;
|
|
+ }
|
|
+
|
|
+ // Update ghosts and advance timer if not paused
|
|
+ else if (!isPaused) {
|
|
+ time_trials_update_ghost(sTimeTrialGhostDataR1, &sGhostAnimData1, bhvTimeTrialGhost1, m, sTimeTrialTimer, gCurrLevelNum, gCurrAreaIndex, TIME_TRIALS_GHOST1_HIDE);
|
|
+ time_trials_update_ghost(sTimeTrialGhostDataR2, &sGhostAnimData2, bhvTimeTrialGhost2, m, sTimeTrialTimer, gCurrLevelNum, gCurrAreaIndex, TIME_TRIALS_GHOST2_HIDE);
|
|
+ time_trials_record_ghost(m, sTimeTrialTimer);
|
|
+ sTimeTrialTimer = MIN(sTimeTrialTimer + 1, TIME_TRIALS_MAX_ALLOWED_TIME);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Runs timer if course is TTable
|
|
+ if (time_trials_get_slot_index(gCurrCourseNum, 0) != -1) {
|
|
+ if (sTimeTrialTimerState != TT_TIMER_STOPPED) {
|
|
+ sTimeTrialTimerState = TT_TIMER_RUNNING;
|
|
+ sTimeTrialHiScore = false;
|
|
+
|
|
+ // Start timer and init ghost if a course entry is detected
|
|
+ if (time_trials_should_start_timer(m)) {
|
|
+ bzero(sTimeTrialGhostDataW, sizeof(sTimeTrialGhostDataW));
|
|
+ sTimeTrialTimer = 0;
|
|
+
|
|
+ // Load ghosts only if not already loaded
|
|
+ s32 star = time_trials_get_ghost_data_to_load(gCurrCourseNum, gCurrActNum - 1);
|
|
+ if ((sLoadedSvFileNum != gCurrSaveFileNum) || (sLoadedCourseNum != gCurrCourseNum) || (sLoadedStarIndex != star)) {
|
|
+
|
|
+ // Normal ghost
|
|
+ time_trials_read_ghost_data(gCurrSaveFileNum - 1, time_trials_get_slot_index(gCurrCourseNum, star), sTimeTrialGhostDataR1);
|
|
+ sGhostAnimData1.color = 0;
|
|
+ sGhostAnimData1.prevValidAnimIndex = 0xFFFF;
|
|
+
|
|
+ // Special ghost
|
|
+ // Red = Bowser stages Red coins star
|
|
+ // Green = PSS star 2
|
|
+ // Gold = Main courses 100 coins star
|
|
+ s32 special = time_trials_get_special_ghost_data_to_load(gCurrCourseNum);
|
|
+ if (special != -1) {
|
|
+ time_trials_read_ghost_data(gCurrSaveFileNum - 1, time_trials_get_slot_index(gCurrCourseNum, special), sTimeTrialGhostDataR2);
|
|
+ sGhostAnimData2.color = MIN(3, special + 1);
|
|
+ sGhostAnimData2.prevValidAnimIndex = 0xFFFF;
|
|
+ }
|
|
+
|
|
+ sLoadedSvFileNum = gCurrSaveFileNum;
|
|
+ sLoadedCourseNum = gCurrCourseNum;
|
|
+ sLoadedStarIndex = star;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ sTimeTrialTimerState = TT_TIMER_DISABLED;
|
|
+ sLoadedSvFileNum = -1;
|
|
+ sLoadedCourseNum = -1;
|
|
+ sLoadedStarIndex = -1;
|
|
+ }
|
|
+
|
|
+ // Render timer
|
|
+ if (gHudDisplay.flags != HUD_DISPLAY_NONE && configHUD && sTimeTrialTimerState != TT_TIMER_DISABLED) {
|
|
+ if (Cheats.EnableCheats && TIME_TRIALS_CHEATS_DISABLED) {
|
|
+ time_trials_render_dont_be_a_cheater(SCREEN_HEIGHT - 24);
|
|
+ } else {
|
|
+ if (sTimeTrialHiScore && sTimeTrialTimerState == TT_TIMER_STOPPED) {
|
|
+ time_trials_render_timer(SCREEN_HEIGHT - 24, "HI SCORE", sTimeTrialTimer, (sins(gGlobalTimer * 0x1000) * 50.f + 205.f));
|
|
+ } else if (sTimeTrialTimer > 0) {
|
|
+ time_trials_render_timer(SCREEN_HEIGHT - 24, "TIME", sTimeTrialTimer, 255);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ } else {
|
|
+
|
|
+ // Disable timer and set timer to max time if Time Trials is disabled
|
|
+ sTimeTrialTimerState = TT_TIMER_DISABLED;
|
|
+ sTimeTrialTimer = TIME_TRIALS_MAX_ALLOWED_TIME;
|
|
+ time_trials_ghost_unload(bhvTimeTrialGhost1);
|
|
+ time_trials_ghost_unload(bhvTimeTrialGhost2);
|
|
+ sLoadedSvFileNum = -1;
|
|
+ sLoadedCourseNum = -1;
|
|
+ sLoadedStarIndex = -1;
|
|
+ }
|
|
+}
|
|
diff --git a/src/game/time_trials.h b/src/game/time_trials.h
|
|
new file mode 100644
|
|
index 0000000..72df723
|
|
--- /dev/null
|
|
+++ b/src/game/time_trials.h
|
|
@@ -0,0 +1,24 @@
|
|
+#ifndef TIME_TRIALS_H
|
|
+#define TIME_TRIALS_H
|
|
+
|
|
+#include <stdbool.h>
|
|
+#include "types.h"
|
|
+
|
|
+void time_trials_update(struct MarioState *m, bool isPaused);
|
|
+u32 time_trials_save_time_and_stop_timer(s32 fileIndex, s32 course, s32 level, s32 star, bool exit);
|
|
+s32 time_trials_render_pause_castle_main_strings(s32 fileIndex, s8 *index);
|
|
+void time_trials_render_star_select_time(s32 fileIndex, s32 course, s32 star);
|
|
+
|
|
+/* Options */
|
|
+#include "pc/dynamic_options.h"
|
|
+#define __time_trials__ dynos_get_value("time_trials")
|
|
+#define __time_trials_ghost1__ dynos_get_value("time_trials_ghost1")
|
|
+#define __time_trials_ghost2__ dynos_get_value("time_trials_ghost2")
|
|
+#define __time_trials_cheats__ dynos_get_value("time_trials_cheats")
|
|
+#define TIME_TRIALS_DISABLED (__time_trials__ == 0)
|
|
+#define TIME_TRIALS_ENABLED (__time_trials__ == 1)
|
|
+#define TIME_TRIALS_GHOST1_HIDE (__time_trials_ghost1__ == 0)
|
|
+#define TIME_TRIALS_GHOST2_HIDE (__time_trials_ghost2__ == 0)
|
|
+#define TIME_TRIALS_CHEATS_DISABLED (__time_trials_cheats__ == 0)
|
|
+
|
|
+#endif // TIME_TRIALS_H
|
|
diff --git a/src/game/time_trials_ghost_geo.inl b/src/game/time_trials_ghost_geo.inl
|
|
new file mode 100644
|
|
index 0000000..574dc72
|
|
--- /dev/null
|
|
+++ b/src/game/time_trials_ghost_geo.inl
|
|
@@ -0,0 +1,1898 @@
|
|
+//
|
|
+// Ghost Mario
|
|
+//
|
|
+
|
|
+static const Lights1 ghost_mario_blue_light = gdSPDefLights1(0x20, 0x20, 0xA0, 0x20, 0x20, 0xA0, 0x28, 0x28, 0x28);
|
|
+static const Lights1 ghost_mario_red_light = gdSPDefLights1(0x80, 0x20, 0x20, 0x80, 0x20, 0x20, 0x28, 0x28, 0x28);
|
|
+static const Lights1 ghost_mario_green_light = gdSPDefLights1(0x20, 0x60, 0x20, 0x20, 0x60, 0x20, 0x28, 0x28, 0x28);
|
|
+static const Lights1 ghost_mario_gold_light = gdSPDefLights1(0xA0, 0x80, 0x00, 0xA0, 0x80, 0x00, 0x28, 0x28, 0x28);
|
|
+
|
|
+//
|
|
+// Ghost light display list
|
|
+//
|
|
+
|
|
+static const Gfx ghost_mario_blue_light_dl[] = {
|
|
+ gsDPPipeSync(),
|
|
+ gsDPSetCombineMode(G_CC_SHADEFADEA, G_CC_SHADEFADEA),
|
|
+ gsSPLight(&ghost_mario_blue_light.l, 1),
|
|
+ gsSPLight(&ghost_mario_blue_light.a, 2),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+static const Gfx ghost_mario_red_light_dl[] = {
|
|
+ gsDPPipeSync(),
|
|
+ gsDPSetCombineMode(G_CC_SHADEFADEA, G_CC_SHADEFADEA),
|
|
+ gsSPLight(&ghost_mario_red_light.l, 1),
|
|
+ gsSPLight(&ghost_mario_red_light.a, 2),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+static const Gfx ghost_mario_green_light_dl[] = {
|
|
+ gsDPPipeSync(),
|
|
+ gsDPSetCombineMode(G_CC_SHADEFADEA, G_CC_SHADEFADEA),
|
|
+ gsSPLight(&ghost_mario_green_light.l, 1),
|
|
+ gsSPLight(&ghost_mario_green_light.a, 2),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+static const Gfx ghost_mario_gold_light_dl[] = {
|
|
+ gsDPPipeSync(),
|
|
+ gsDPSetCombineMode(G_CC_SHADEFADEA, G_CC_SHADEFADEA),
|
|
+ gsSPLight(&ghost_mario_gold_light.l, 1),
|
|
+ gsSPLight(&ghost_mario_gold_light.a, 2),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+//
|
|
+// Mario's butt
|
|
+//
|
|
+
|
|
+static const Vtx ghost_mario_butt_dl_vertex_group1[] = {
|
|
+ {{{ -9, 73, -34}, 0, { 0, 0}, {0xc2, 0x6b, 0xe6, 0x00}}},
|
|
+ {{{ -9, 73, 34}, 0, { 0, 0}, {0xbe, 0x6a, 0x12, 0x00}}},
|
|
+ {{{ 22, 82, -26}, 0, { 0, 0}, {0x07, 0x7e, 0xf5, 0x00}}},
|
|
+ {{{ 73, 11, 0}, 0, { 0, 0}, {0x7e, 0x04, 0x00, 0x00}}},
|
|
+ {{{ 55, -61, -36}, 0, { 0, 0}, {0x67, 0xbe, 0xe1, 0x00}}},
|
|
+ {{{ 44, -10, -92}, 0, { 0, 0}, {0x4f, 0xf2, 0x9e, 0x00}}},
|
|
+ {{{ 7, 33, 95}, 0, { 0, 0}, {0xe6, 0x26, 0x75, 0x00}}},
|
|
+ {{{ 44, -9, 92}, 0, { 0, 0}, {0x4f, 0xf2, 0x62, 0x00}}},
|
|
+ {{{ 43, 40, 91}, 0, { 0, 0}, {0x4e, 0x30, 0x57, 0x00}}},
|
|
+ {{{ 8, -8, -99}, 0, { 0, 0}, {0xf3, 0xee, 0x84, 0x00}}},
|
|
+ {{{ 36, -51, -79}, 0, { 0, 0}, {0x30, 0xb8, 0xa4, 0x00}}},
|
|
+ {{{ 26, -74, -46}, 0, { 0, 0}, {0x18, 0x88, 0xe2, 0x00}}},
|
|
+ {{{ 36, -52, 79}, 0, { 0, 0}, {0x30, 0xb8, 0x5c, 0x00}}},
|
|
+ {{{ 26, -74, 45}, 0, { 0, 0}, {0x12, 0x88, 0x22, 0x00}}},
|
|
+ {{{ 55, -61, 36}, 0, { 0, 0}, {0x60, 0xb3, 0x1a, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_butt_dl_vertex_group2[] = {
|
|
+ {{{ -5, 59, 72}, 0, { 0, 0}, {0xc0, 0x52, 0x47, 0x00}}},
|
|
+ {{{ -9, 73, 34}, 0, { 0, 0}, {0xbe, 0x6a, 0x12, 0x00}}},
|
|
+ {{{ -32, 40, 39}, 0, { 0, 0}, {0x8b, 0x25, 0x1d, 0x00}}},
|
|
+ {{{ 52, 70, 38}, 0, { 0, 0}, {0x53, 0x5d, 0x16, 0x00}}},
|
|
+ {{{ 22, 82, 26}, 0, { 0, 0}, {0x07, 0x7d, 0x11, 0x00}}},
|
|
+ {{{ 27, 72, 63}, 0, { 0, 0}, {0x06, 0x6c, 0x42, 0x00}}},
|
|
+ {{{ 43, 40, -91}, 0, { 0, 0}, {0x4e, 0x30, 0xa9, 0x00}}},
|
|
+ {{{ 27, 72, -63}, 0, { 0, 0}, {0x07, 0x6b, 0xbe, 0x00}}},
|
|
+ {{{ 52, 70, -39}, 0, { 0, 0}, {0x59, 0x56, 0xe5, 0x00}}},
|
|
+ {{{ -5, 59, -72}, 0, { 0, 0}, {0xc0, 0x52, 0xb9, 0x00}}},
|
|
+ {{{ -17, 32, -79}, 0, { 0, 0}, {0xa4, 0x23, 0xb1, 0x00}}},
|
|
+ {{{ -32, 40, -39}, 0, { 0, 0}, {0x89, 0x25, 0xeb, 0x00}}},
|
|
+ {{{ 73, 11, 0}, 0, { 0, 0}, {0x7e, 0x04, 0x00, 0x00}}},
|
|
+ {{{ 43, 40, 91}, 0, { 0, 0}, {0x4e, 0x30, 0x57, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_butt_dl_vertex_group3[] = {
|
|
+ {{{ -14, -74, 0}, 0, { 0, 0}, {0xcb, 0x8d, 0x00, 0x00}}},
|
|
+ {{{ -9, -69, 55}, 0, { 0, 0}, {0xcd, 0x97, 0x30, 0x00}}},
|
|
+ {{{ -31, -51, 42}, 0, { 0, 0}, {0x8d, 0xd7, 0x1f, 0x00}}},
|
|
+ {{{ 26, -74, -46}, 0, { 0, 0}, {0x18, 0x88, 0xe2, 0x00}}},
|
|
+ {{{ -9, -69, -55}, 0, { 0, 0}, {0xcd, 0x97, 0xd0, 0x00}}},
|
|
+ {{{ 4, -48, -86}, 0, { 0, 0}, {0xd8, 0xba, 0x9f, 0x00}}},
|
|
+ {{{ 4, -49, 86}, 0, { 0, 0}, {0xd8, 0xb9, 0x61, 0x00}}},
|
|
+ {{{ 26, -74, 45}, 0, { 0, 0}, {0x12, 0x88, 0x22, 0x00}}},
|
|
+ {{{ -32, 40, 39}, 0, { 0, 0}, {0x8b, 0x25, 0x1d, 0x00}}},
|
|
+ {{{ -9, 73, 34}, 0, { 0, 0}, {0xbe, 0x6a, 0x12, 0x00}}},
|
|
+ {{{ -32, 40, -39}, 0, { 0, 0}, {0x89, 0x25, 0xeb, 0x00}}},
|
|
+ {{{ 27, 72, 63}, 0, { 0, 0}, {0x06, 0x6c, 0x42, 0x00}}},
|
|
+ {{{ -5, 59, 72}, 0, { 0, 0}, {0xc0, 0x52, 0x47, 0x00}}},
|
|
+ {{{ 52, 70, -39}, 0, { 0, 0}, {0x59, 0x56, 0xe5, 0x00}}},
|
|
+ {{{ 22, 82, -26}, 0, { 0, 0}, {0x07, 0x7e, 0xf5, 0x00}}},
|
|
+ {{{ 52, 70, 38}, 0, { 0, 0}, {0x53, 0x5d, 0x16, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_butt_dl_vertex_group4[] = {
|
|
+ {{{ 6, 33, -95}, 0, { 0, 0}, {0xe6, 0x26, 0x8b, 0x00}}},
|
|
+ {{{ 27, 72, -63}, 0, { 0, 0}, {0x07, 0x6b, 0xbe, 0x00}}},
|
|
+ {{{ 43, 40, -91}, 0, { 0, 0}, {0x4e, 0x30, 0xa9, 0x00}}},
|
|
+ {{{ -31, -51, 42}, 0, { 0, 0}, {0x8d, 0xd7, 0x1f, 0x00}}},
|
|
+ {{{ -31, -51, -42}, 0, { 0, 0}, {0x91, 0xd0, 0xdc, 0x00}}},
|
|
+ {{{ -14, -74, 0}, 0, { 0, 0}, {0xcb, 0x8d, 0x00, 0x00}}},
|
|
+ {{{ -9, -69, -55}, 0, { 0, 0}, {0xcd, 0x97, 0xd0, 0x00}}},
|
|
+ {{{ 73, 11, 0}, 0, { 0, 0}, {0x7e, 0x04, 0x00, 0x00}}},
|
|
+ {{{ 44, -10, -92}, 0, { 0, 0}, {0x4f, 0xf2, 0x9e, 0x00}}},
|
|
+ {{{ 52, 70, 38}, 0, { 0, 0}, {0x53, 0x5d, 0x16, 0x00}}},
|
|
+ {{{ 52, 70, -39}, 0, { 0, 0}, {0x59, 0x56, 0xe5, 0x00}}},
|
|
+ {{{ 43, 40, 91}, 0, { 0, 0}, {0x4e, 0x30, 0x57, 0x00}}},
|
|
+ {{{ 44, -9, 92}, 0, { 0, 0}, {0x4f, 0xf2, 0x62, 0x00}}},
|
|
+ {{{ 7, 33, 95}, 0, { 0, 0}, {0xe6, 0x26, 0x75, 0x00}}},
|
|
+ {{{ 27, 72, 63}, 0, { 0, 0}, {0x06, 0x6c, 0x42, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_butt_dl_vertex_group5[] = {
|
|
+ {{{ -5, 59, -72}, 0, { 0, 0}, {0xc0, 0x52, 0xb9, 0x00}}},
|
|
+ {{{ -9, 73, -34}, 0, { 0, 0}, {0xc2, 0x6b, 0xe6, 0x00}}},
|
|
+ {{{ 27, 72, -63}, 0, { 0, 0}, {0x07, 0x6b, 0xbe, 0x00}}},
|
|
+ {{{ -32, 40, -39}, 0, { 0, 0}, {0x89, 0x25, 0xeb, 0x00}}},
|
|
+ {{{ -32, 40, 39}, 0, { 0, 0}, {0x8b, 0x25, 0x1d, 0x00}}},
|
|
+ {{{ -18, 32, 79}, 0, { 0, 0}, {0xa4, 0x23, 0x4f, 0x00}}},
|
|
+ {{{ -5, 59, 72}, 0, { 0, 0}, {0xc0, 0x52, 0x47, 0x00}}},
|
|
+ {{{ 22, 82, -26}, 0, { 0, 0}, {0x07, 0x7e, 0xf5, 0x00}}},
|
|
+ {{{ 52, 70, -39}, 0, { 0, 0}, {0x59, 0x56, 0xe5, 0x00}}},
|
|
+ {{{ 27, 72, 63}, 0, { 0, 0}, {0x06, 0x6c, 0x42, 0x00}}},
|
|
+ {{{ 43, 40, 91}, 0, { 0, 0}, {0x4e, 0x30, 0x57, 0x00}}},
|
|
+ {{{ 52, 70, 38}, 0, { 0, 0}, {0x53, 0x5d, 0x16, 0x00}}},
|
|
+ {{{ 8, -8, 99}, 0, { 0, 0}, {0xf3, 0xef, 0x7c, 0x00}}},
|
|
+ {{{ 36, -52, 79}, 0, { 0, 0}, {0x30, 0xb8, 0x5c, 0x00}}},
|
|
+ {{{ 44, -9, 92}, 0, { 0, 0}, {0x4f, 0xf2, 0x62, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_butt_dl_vertex_group6[] = {
|
|
+ {{{ 6, 33, -95}, 0, { 0, 0}, {0xe6, 0x26, 0x8b, 0x00}}},
|
|
+ {{{ 43, 40, -91}, 0, { 0, 0}, {0x4e, 0x30, 0xa9, 0x00}}},
|
|
+ {{{ 44, -10, -92}, 0, { 0, 0}, {0x4f, 0xf2, 0x9e, 0x00}}},
|
|
+ {{{ 44, -9, 92}, 0, { 0, 0}, {0x4f, 0xf2, 0x62, 0x00}}},
|
|
+ {{{ 36, -52, 79}, 0, { 0, 0}, {0x30, 0xb8, 0x5c, 0x00}}},
|
|
+ {{{ 55, -61, 36}, 0, { 0, 0}, {0x60, 0xb3, 0x1a, 0x00}}},
|
|
+ {{{ -18, 32, 79}, 0, { 0, 0}, {0xa4, 0x23, 0x4f, 0x00}}},
|
|
+ {{{ 7, 33, 95}, 0, { 0, 0}, {0xe6, 0x26, 0x75, 0x00}}},
|
|
+ {{{ -5, 59, 72}, 0, { 0, 0}, {0xc0, 0x52, 0x47, 0x00}}},
|
|
+ {{{ -20, -7, 81}, 0, { 0, 0}, {0xa3, 0xf9, 0x55, 0x00}}},
|
|
+ {{{ 8, -8, 99}, 0, { 0, 0}, {0xf3, 0xef, 0x7c, 0x00}}},
|
|
+ {{{ 4, -49, 86}, 0, { 0, 0}, {0xd8, 0xb9, 0x61, 0x00}}},
|
|
+ {{{ -20, -8, -81}, 0, { 0, 0}, {0xa3, 0xf8, 0xab, 0x00}}},
|
|
+ {{{ 8, -8, -99}, 0, { 0, 0}, {0xf3, 0xee, 0x84, 0x00}}},
|
|
+ {{{ 4, -48, -86}, 0, { 0, 0}, {0xd8, 0xba, 0x9f, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_butt_dl_vertex_group7[] = {
|
|
+ {{{ -5, 59, -72}, 0, { 0, 0}, {0xc0, 0x52, 0xb9, 0x00}}},
|
|
+ {{{ 6, 33, -95}, 0, { 0, 0}, {0xe6, 0x26, 0x8b, 0x00}}},
|
|
+ {{{ -17, 32, -79}, 0, { 0, 0}, {0xa4, 0x23, 0xb1, 0x00}}},
|
|
+ {{{ -20, -8, -81}, 0, { 0, 0}, {0xa3, 0xf8, 0xab, 0x00}}},
|
|
+ {{{ 7, 33, 95}, 0, { 0, 0}, {0xe6, 0x26, 0x75, 0x00}}},
|
|
+ {{{ -18, 32, 79}, 0, { 0, 0}, {0xa4, 0x23, 0x4f, 0x00}}},
|
|
+ {{{ -20, -7, 81}, 0, { 0, 0}, {0xa3, 0xf9, 0x55, 0x00}}},
|
|
+ {{{ -32, 40, -39}, 0, { 0, 0}, {0x89, 0x25, 0xeb, 0x00}}},
|
|
+ {{{ 55, -61, 36}, 0, { 0, 0}, {0x60, 0xb3, 0x1a, 0x00}}},
|
|
+ {{{ 73, 11, 0}, 0, { 0, 0}, {0x7e, 0x04, 0x00, 0x00}}},
|
|
+ {{{ 44, -9, 92}, 0, { 0, 0}, {0x4f, 0xf2, 0x62, 0x00}}},
|
|
+ {{{ 55, -61, -36}, 0, { 0, 0}, {0x67, 0xbe, 0xe1, 0x00}}},
|
|
+ {{{ 36, -51, -79}, 0, { 0, 0}, {0x30, 0xb8, 0xa4, 0x00}}},
|
|
+ {{{ 44, -10, -92}, 0, { 0, 0}, {0x4f, 0xf2, 0x9e, 0x00}}},
|
|
+ {{{ 8, -8, -99}, 0, { 0, 0}, {0xf3, 0xee, 0x84, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_butt_dl_vertex_group8[] = {
|
|
+ {{{ 8, -8, 99}, 0, { 0, 0}, {0xf3, 0xef, 0x7c, 0x00}}},
|
|
+ {{{ 4, -49, 86}, 0, { 0, 0}, {0xd8, 0xb9, 0x61, 0x00}}},
|
|
+ {{{ 36, -52, 79}, 0, { 0, 0}, {0x30, 0xb8, 0x5c, 0x00}}},
|
|
+ {{{ -9, 73, -34}, 0, { 0, 0}, {0xc2, 0x6b, 0xe6, 0x00}}},
|
|
+ {{{ 22, 82, -26}, 0, { 0, 0}, {0x07, 0x7e, 0xf5, 0x00}}},
|
|
+ {{{ 27, 72, -63}, 0, { 0, 0}, {0x07, 0x6b, 0xbe, 0x00}}},
|
|
+ {{{ 27, 72, 63}, 0, { 0, 0}, {0x06, 0x6c, 0x42, 0x00}}},
|
|
+ {{{ -5, 59, 72}, 0, { 0, 0}, {0xc0, 0x52, 0x47, 0x00}}},
|
|
+ {{{ 7, 33, 95}, 0, { 0, 0}, {0xe6, 0x26, 0x75, 0x00}}},
|
|
+ {{{ 6, 33, -95}, 0, { 0, 0}, {0xe6, 0x26, 0x8b, 0x00}}},
|
|
+ {{{ -5, 59, -72}, 0, { 0, 0}, {0xc0, 0x52, 0xb9, 0x00}}},
|
|
+ {{{ 22, 82, 26}, 0, { 0, 0}, {0x07, 0x7d, 0x11, 0x00}}},
|
|
+ {{{ 52, 70, 38}, 0, { 0, 0}, {0x53, 0x5d, 0x16, 0x00}}},
|
|
+ {{{ -9, 73, 34}, 0, { 0, 0}, {0xbe, 0x6a, 0x12, 0x00}}},
|
|
+ {{{ -32, 40, -39}, 0, { 0, 0}, {0x89, 0x25, 0xeb, 0x00}}},
|
|
+ {{{ 26, -74, 45}, 0, { 0, 0}, {0x12, 0x88, 0x22, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_butt_dl_vertex_group9[] = {
|
|
+ {{{ 4, -48, -86}, 0, { 0, 0}, {0xd8, 0xba, 0x9f, 0x00}}},
|
|
+ {{{ 36, -51, -79}, 0, { 0, 0}, {0x30, 0xb8, 0xa4, 0x00}}},
|
|
+ {{{ 26, -74, -46}, 0, { 0, 0}, {0x18, 0x88, 0xe2, 0x00}}},
|
|
+ {{{ -20, -7, 81}, 0, { 0, 0}, {0xa3, 0xf9, 0x55, 0x00}}},
|
|
+ {{{ -18, 32, 79}, 0, { 0, 0}, {0xa4, 0x23, 0x4f, 0x00}}},
|
|
+ {{{ -32, 40, 39}, 0, { 0, 0}, {0x8b, 0x25, 0x1d, 0x00}}},
|
|
+ {{{ 8, -8, -99}, 0, { 0, 0}, {0xf3, 0xee, 0x84, 0x00}}},
|
|
+ {{{ 7, 33, 95}, 0, { 0, 0}, {0xe6, 0x26, 0x75, 0x00}}},
|
|
+ {{{ 8, -8, 99}, 0, { 0, 0}, {0xf3, 0xef, 0x7c, 0x00}}},
|
|
+ {{{ 44, -9, 92}, 0, { 0, 0}, {0x4f, 0xf2, 0x62, 0x00}}},
|
|
+ {{{ -9, 73, 34}, 0, { 0, 0}, {0xbe, 0x6a, 0x12, 0x00}}},
|
|
+ {{{ 22, 82, 26}, 0, { 0, 0}, {0x07, 0x7d, 0x11, 0x00}}},
|
|
+ {{{ 22, 82, -26}, 0, { 0, 0}, {0x07, 0x7e, 0xf5, 0x00}}},
|
|
+ {{{ -9, -69, -55}, 0, { 0, 0}, {0xcd, 0x97, 0xd0, 0x00}}},
|
|
+ {{{ -31, -51, -42}, 0, { 0, 0}, {0x91, 0xd0, 0xdc, 0x00}}},
|
|
+ {{{ -20, -8, -81}, 0, { 0, 0}, {0xa3, 0xf8, 0xab, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_butt_dl_vertex_group10[] = {
|
|
+ {{{ -31, -51, 42}, 0, { 0, 0}, {0x8d, 0xd7, 0x1f, 0x00}}},
|
|
+ {{{ -9, -69, 55}, 0, { 0, 0}, {0xcd, 0x97, 0x30, 0x00}}},
|
|
+ {{{ 4, -49, 86}, 0, { 0, 0}, {0xd8, 0xb9, 0x61, 0x00}}},
|
|
+ {{{ -20, -7, 81}, 0, { 0, 0}, {0xa3, 0xf9, 0x55, 0x00}}},
|
|
+ {{{ -32, 40, 39}, 0, { 0, 0}, {0x8b, 0x25, 0x1d, 0x00}}},
|
|
+ {{{ -32, 40, -39}, 0, { 0, 0}, {0x89, 0x25, 0xeb, 0x00}}},
|
|
+ {{{ -20, -8, -81}, 0, { 0, 0}, {0xa3, 0xf8, 0xab, 0x00}}},
|
|
+ {{{ -31, -51, -42}, 0, { 0, 0}, {0x91, 0xd0, 0xdc, 0x00}}},
|
|
+ {{{ 55, -61, 36}, 0, { 0, 0}, {0x60, 0xb3, 0x1a, 0x00}}},
|
|
+ {{{ 26, -74, 45}, 0, { 0, 0}, {0x12, 0x88, 0x22, 0x00}}},
|
|
+ {{{ 26, -74, -46}, 0, { 0, 0}, {0x18, 0x88, 0xe2, 0x00}}},
|
|
+ {{{ -14, -74, 0}, 0, { 0, 0}, {0xcb, 0x8d, 0x00, 0x00}}},
|
|
+ {{{ -9, -69, -55}, 0, { 0, 0}, {0xcd, 0x97, 0xd0, 0x00}}},
|
|
+ {{{ 55, -61, -36}, 0, { 0, 0}, {0x67, 0xbe, 0xe1, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Gfx ghost_mario_butt[] = {
|
|
+ gsDPPipeSync(),
|
|
+ gsSPVertex(ghost_mario_butt_dl_vertex_group1, 15, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
|
+ gsSP2Triangles(6, 7, 8, 0x0, 9, 5, 10, 0x0),
|
|
+ gsSP2Triangles(4, 11, 10, 0x0, 12, 13, 14, 0x0),
|
|
+ gsSPVertex(ghost_mario_butt_dl_vertex_group2, 14, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
|
+ gsSP2Triangles(6, 7, 8, 0x0, 9, 10, 11, 0x0),
|
|
+ gsSP2Triangles(12, 3, 13, 0x0, 6, 8, 12, 0x0),
|
|
+ gsSPVertex(ghost_mario_butt_dl_vertex_group3, 16, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
|
+ gsSP2Triangles(6, 1, 7, 0x0, 8, 9, 10, 0x0),
|
|
+ gsSP2Triangles(11, 9, 12, 0x0, 13, 14, 15, 0x0),
|
|
+ gsSPVertex(ghost_mario_butt_dl_vertex_group4, 15, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
|
+ gsSP2Triangles(4, 6, 5, 0x0, 7, 8, 2, 0x0),
|
|
+ gsSP2Triangles(9, 7, 10, 0x0, 11, 12, 7, 0x0),
|
|
+ gsSP1Triangle(13, 11, 14, 0x0),
|
|
+ gsSPVertex(ghost_mario_butt_dl_vertex_group5, 15, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 1, 0, 0x0),
|
|
+ gsSP2Triangles(4, 5, 6, 0x0, 2, 7, 8, 0x0),
|
|
+ gsSP2Triangles(9, 10, 11, 0x0, 12, 13, 14, 0x0),
|
|
+ gsSPVertex(ghost_mario_butt_dl_vertex_group6, 15, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
|
+ gsSP2Triangles(6, 7, 8, 0x0, 9, 10, 7, 0x0),
|
|
+ gsSP2Triangles(11, 10, 9, 0x0, 12, 13, 14, 0x0),
|
|
+ gsSP1Triangle(0, 13, 12, 0x0),
|
|
+ gsSPVertex(ghost_mario_butt_dl_vertex_group7, 15, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 2, 1, 0x0),
|
|
+ gsSP2Triangles(4, 5, 6, 0x0, 7, 2, 3, 0x0),
|
|
+ gsSP2Triangles(8, 9, 10, 0x0, 9, 8, 11, 0x0),
|
|
+ gsSP2Triangles(11, 12, 13, 0x0, 13, 14, 1, 0x0),
|
|
+ gsSPVertex(ghost_mario_butt_dl_vertex_group8, 16, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
|
+ gsSP2Triangles(6, 7, 8, 0x0, 9, 10, 5, 0x0),
|
|
+ gsSP2Triangles(4, 11, 12, 0x0, 6, 11, 13, 0x0),
|
|
+ gsSP2Triangles(13, 3, 14, 0x0, 15, 2, 1, 0x0),
|
|
+ gsSPVertex(ghost_mario_butt_dl_vertex_group9, 16, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
|
+ gsSP2Triangles(1, 0, 6, 0x0, 7, 8, 9, 0x0),
|
|
+ gsSP2Triangles(10, 11, 12, 0x0, 0, 13, 14, 0x0),
|
|
+ gsSP1Triangle(15, 0, 14, 0x0),
|
|
+ gsSPVertex(ghost_mario_butt_dl_vertex_group10, 14, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 2, 3, 0, 0x0),
|
|
+ gsSP2Triangles(3, 4, 0, 0x0, 0, 4, 5, 0x0),
|
|
+ gsSP2Triangles(5, 6, 7, 0x0, 5, 7, 0, 0x0),
|
|
+ gsSP2Triangles(8, 9, 10, 0x0, 9, 11, 10, 0x0),
|
|
+ gsSP2Triangles(9, 1, 11, 0x0, 11, 12, 10, 0x0),
|
|
+ gsSP1Triangle(10, 13, 8, 0x0),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+//
|
|
+// Left arm
|
|
+//
|
|
+
|
|
+static const Vtx ghost_mario_left_arm_shared_dl_vertex_group1[] = {
|
|
+ {{{ 7, 27, 20}, 0, { 0, 0}, {0xda, 0x61, 0x47, 0x00}}},
|
|
+ {{{ 59, 20, 15}, 0, { 0, 0}, {0x44, 0x4a, 0x4c, 0x00}}},
|
|
+ {{{ 59, 21, -21}, 0, { 0, 0}, {0x37, 0x67, 0xd0, 0x00}}},
|
|
+ {{{ 6, -16, 32}, 0, { 0, 0}, {0xd5, 0xdc, 0x71, 0x00}}},
|
|
+ {{{ 58, -15, 25}, 0, { 0, 0}, {0x32, 0xc6, 0x64, 0x00}}},
|
|
+ {{{ 5, -42, -5}, 0, { 0, 0}, {0xd3, 0x8a, 0xff, 0x00}}},
|
|
+ {{{ 57, -36, -5}, 0, { 0, 0}, {0x3e, 0x93, 0xef, 0x00}}},
|
|
+ {{{ 6, -13, -42}, 0, { 0, 0}, {0xd6, 0xde, 0x8e, 0x00}}},
|
|
+ {{{ 58, -13, -34}, 0, { 0, 0}, {0x3b, 0xfb, 0x90, 0x00}}},
|
|
+ {{{ 7, 29, -26}, 0, { 0, 0}, {0xda, 0x62, 0xbb, 0x00}}},
|
|
+ {{{ -8, 17, -17}, 0, { 0, 0}, {0x90, 0x2a, 0xd6, 0x00}}},
|
|
+ {{{ -8, 16, 10}, 0, { 0, 0}, {0x9a, 0x44, 0x1d, 0x00}}},
|
|
+ {{{ -8, -9, -27}, 0, { 0, 0}, {0x8e, 0xe8, 0xce, 0x00}}},
|
|
+ {{{ -9, -26, -5}, 0, { 0, 0}, {0x96, 0xbd, 0x0e, 0x00}}},
|
|
+ {{{ -8, -11, 18}, 0, { 0, 0}, {0x8b, 0xff, 0x2f, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_left_arm_shared_dl_vertex_group2[] = {
|
|
+ {{{ 68, 13, -16}, 0, { 0, 0}, {0x6a, 0x38, 0xd9, 0x00}}},
|
|
+ {{{ 68, -10, -25}, 0, { 0, 0}, {0x75, 0xe7, 0xd9, 0x00}}},
|
|
+ {{{ 58, -13, -34}, 0, { 0, 0}, {0x3b, 0xfb, 0x90, 0x00}}},
|
|
+ {{{ 59, 20, 15}, 0, { 0, 0}, {0x44, 0x4a, 0x4c, 0x00}}},
|
|
+ {{{ 68, 12, 9}, 0, { 0, 0}, {0x78, 0x1f, 0x1b, 0x00}}},
|
|
+ {{{ 67, -12, 16}, 0, { 0, 0}, {0x6f, 0xe8, 0x37, 0x00}}},
|
|
+ {{{ 57, -36, -5}, 0, { 0, 0}, {0x3e, 0x93, 0xef, 0x00}}},
|
|
+ {{{ 67, -26, -5}, 0, { 0, 0}, {0x6e, 0xc2, 0xfe, 0x00}}},
|
|
+ {{{ 58, -15, 25}, 0, { 0, 0}, {0x32, 0xc6, 0x64, 0x00}}},
|
|
+ {{{ 59, 21, -21}, 0, { 0, 0}, {0x37, 0x67, 0xd0, 0x00}}},
|
|
+ {{{ 7, 27, 20}, 0, { 0, 0}, {0xda, 0x61, 0x47, 0x00}}},
|
|
+ {{{ -8, -11, 18}, 0, { 0, 0}, {0x8b, 0xff, 0x2f, 0x00}}},
|
|
+ {{{ 6, -16, 32}, 0, { 0, 0}, {0xd5, 0xdc, 0x71, 0x00}}},
|
|
+ {{{ -9, -26, -5}, 0, { 0, 0}, {0x96, 0xbd, 0x0e, 0x00}}},
|
|
+ {{{ 5, -42, -5}, 0, { 0, 0}, {0xd3, 0x8a, 0xff, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_left_arm_shared_dl_vertex_group3[] = {
|
|
+ {{{ 5, -42, -5}, 0, { 0, 0}, {0xd3, 0x8a, 0xff, 0x00}}},
|
|
+ {{{ -8, -9, -27}, 0, { 0, 0}, {0x8e, 0xe8, 0xce, 0x00}}},
|
|
+ {{{ 6, -13, -42}, 0, { 0, 0}, {0xd6, 0xde, 0x8e, 0x00}}},
|
|
+ {{{ -8, 17, -17}, 0, { 0, 0}, {0x90, 0x2a, 0xd6, 0x00}}},
|
|
+ {{{ 7, 29, -26}, 0, { 0, 0}, {0xda, 0x62, 0xbb, 0x00}}},
|
|
+ {{{ -8, 16, 10}, 0, { 0, 0}, {0x9a, 0x44, 0x1d, 0x00}}},
|
|
+ {{{ 7, 27, 20}, 0, { 0, 0}, {0xda, 0x61, 0x47, 0x00}}},
|
|
+ {{{ 58, -13, -34}, 0, { 0, 0}, {0x3b, 0xfb, 0x90, 0x00}}},
|
|
+ {{{ 57, -36, -5}, 0, { 0, 0}, {0x3e, 0x93, 0xef, 0x00}}},
|
|
+ {{{ 6, -16, 32}, 0, { 0, 0}, {0xd5, 0xdc, 0x71, 0x00}}},
|
|
+ {{{ 58, -15, 25}, 0, { 0, 0}, {0x32, 0xc6, 0x64, 0x00}}},
|
|
+ {{{ 59, 20, 15}, 0, { 0, 0}, {0x44, 0x4a, 0x4c, 0x00}}},
|
|
+ {{{ 59, 21, -21}, 0, { 0, 0}, {0x37, 0x67, 0xd0, 0x00}}},
|
|
+ {{{ -8, -11, 18}, 0, { 0, 0}, {0x8b, 0xff, 0x2f, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_left_arm_shared_dl_vertex_group4[] = {
|
|
+ {{{ 68, 12, 9}, 0, { 0, 0}, {0x78, 0x1f, 0x1b, 0x00}}},
|
|
+ {{{ 68, -10, -25}, 0, { 0, 0}, {0x75, 0xe7, 0xd9, 0x00}}},
|
|
+ {{{ 68, 13, -16}, 0, { 0, 0}, {0x6a, 0x38, 0xd9, 0x00}}},
|
|
+ {{{ 67, -12, 16}, 0, { 0, 0}, {0x6f, 0xe8, 0x37, 0x00}}},
|
|
+ {{{ 67, -26, -5}, 0, { 0, 0}, {0x6e, 0xc2, 0xfe, 0x00}}},
|
|
+ {{{ -8, 17, -17}, 0, { 0, 0}, {0x90, 0x2a, 0xd6, 0x00}}},
|
|
+ {{{ -8, -9, -27}, 0, { 0, 0}, {0x8e, 0xe8, 0xce, 0x00}}},
|
|
+ {{{ -8, -11, 18}, 0, { 0, 0}, {0x8b, 0xff, 0x2f, 0x00}}},
|
|
+ {{{ -9, -26, -5}, 0, { 0, 0}, {0x96, 0xbd, 0x0e, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Gfx ghost_mario_left_arm_shared_dl[] = {
|
|
+ gsSPVertex(ghost_mario_left_arm_shared_dl_vertex_group1, 15, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 3, 4, 1, 0x0),
|
|
+ gsSP2Triangles( 5, 6, 4, 0x0, 7, 8, 6, 0x0),
|
|
+ gsSP2Triangles( 9, 2, 8, 0x0, 9, 10, 11, 0x0),
|
|
+ gsSP2Triangles( 7, 12, 10, 0x0, 5, 13, 12, 0x0),
|
|
+ gsSP2Triangles( 3, 14, 13, 0x0, 0, 11, 14, 0x0),
|
|
+ gsSPVertex(ghost_mario_left_arm_shared_dl_vertex_group2, 15, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 3, 4, 0, 0x0),
|
|
+ gsSP2Triangles( 5, 4, 3, 0x0, 6, 7, 5, 0x0),
|
|
+ gsSP2Triangles( 1, 7, 6, 0x0, 2, 1, 6, 0x0),
|
|
+ gsSP2Triangles( 6, 5, 8, 0x0, 8, 5, 3, 0x0),
|
|
+ gsSP2Triangles( 3, 0, 9, 0x0, 9, 0, 2, 0x0),
|
|
+ gsSP2Triangles(10, 11, 12, 0x0, 12, 13, 14, 0x0),
|
|
+ gsSPVertex(ghost_mario_left_arm_shared_dl_vertex_group3, 14, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 2, 3, 4, 0x0),
|
|
+ gsSP2Triangles( 4, 5, 6, 0x0, 2, 4, 7, 0x0),
|
|
+ gsSP2Triangles( 0, 2, 8, 0x0, 9, 0, 10, 0x0),
|
|
+ gsSP2Triangles( 6, 9, 11, 0x0, 4, 6, 12, 0x0),
|
|
+ gsSP1Triangle(13, 5, 3, 0x0),
|
|
+ gsSPVertex(ghost_mario_left_arm_shared_dl_vertex_group4, 9, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 0, 3, 1, 0x0),
|
|
+ gsSP2Triangles( 3, 4, 1, 0x0, 5, 6, 7, 0x0),
|
|
+ gsSP1Triangle( 6, 8, 7, 0x0),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_left_forearm_shared_dl_vertex[] = {
|
|
+ {{{ -2, 19, 16}, 0, { 0, 0}, {0xdb, 0x61, 0x48, 0x00}}},
|
|
+ {{{ 47, 14, 13}, 0, { 0, 0}, {0x44, 0x44, 0x51, 0x00}}},
|
|
+ {{{ 47, 16, -19}, 0, { 0, 0}, {0x45, 0x61, 0xd6, 0x00}}},
|
|
+ {{{ -3, -17, 26}, 0, { 0, 0}, {0xd7, 0xdb, 0x71, 0x00}}},
|
|
+ {{{ 46, -17, 22}, 0, { 0, 0}, {0x41, 0xc7, 0x5c, 0x00}}},
|
|
+ {{{ -3, -38, -4}, 0, { 0, 0}, {0xd4, 0x89, 0xfe, 0x00}}},
|
|
+ {{{ 45, -34, -4}, 0, { 0, 0}, {0x3f, 0x95, 0xe8, 0x00}}},
|
|
+ {{{ -3, -14, -34}, 0, { 0, 0}, {0xd7, 0xde, 0x8e, 0x00}}},
|
|
+ {{{ 46, -14, -30}, 0, { 0, 0}, {0x42, 0xf4, 0x95, 0x00}}},
|
|
+ {{{ -2, 21, -21}, 0, { 0, 0}, {0xdb, 0x63, 0xbb, 0x00}}},
|
|
+ {{{ -14, 13, -15}, 0, { 0, 0}, {0x93, 0x2c, 0xd3, 0x00}}},
|
|
+ {{{ -14, 11, 10}, 0, { 0, 0}, {0x93, 0x3b, 0x19, 0x00}}},
|
|
+ {{{ -15, -11, -24}, 0, { 0, 0}, {0x9a, 0xde, 0xbe, 0x00}}},
|
|
+ {{{ -15, -27, -4}, 0, { 0, 0}, {0x8b, 0xd2, 0x0a, 0x00}}},
|
|
+ {{{ -15, -13, 17}, 0, { 0, 0}, {0x9b, 0xfb, 0x4c, 0x00}}},
|
|
+ {{{ 58, -7, -3}, 0, { 0, 0}, {0x7e, 0xfc, 0x00, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Gfx ghost_mario_left_forearm_shared_dl[] = {
|
|
+ gsSPVertex(ghost_mario_left_forearm_shared_dl_vertex, 16, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 3, 4, 1, 0x0),
|
|
+ gsSP2Triangles( 5, 6, 4, 0x0, 7, 8, 6, 0x0),
|
|
+ gsSP2Triangles( 9, 2, 8, 0x0, 9, 10, 11, 0x0),
|
|
+ gsSP2Triangles( 7, 12, 10, 0x0, 5, 13, 12, 0x0),
|
|
+ gsSP2Triangles( 3, 14, 13, 0x0, 0, 11, 14, 0x0),
|
|
+ gsSP2Triangles( 8, 15, 6, 0x0, 6, 15, 4, 0x0),
|
|
+ gsSP2Triangles( 4, 15, 1, 0x0, 1, 15, 2, 0x0),
|
|
+ gsSP2Triangles( 2, 15, 8, 0x0, 0, 14, 3, 0x0),
|
|
+ gsSP2Triangles( 3, 13, 5, 0x0, 5, 12, 7, 0x0),
|
|
+ gsSP2Triangles( 7, 10, 9, 0x0, 9, 11, 0, 0x0),
|
|
+ gsSP2Triangles( 7, 9, 8, 0x0, 5, 7, 6, 0x0),
|
|
+ gsSP2Triangles( 3, 5, 4, 0x0, 0, 3, 1, 0x0),
|
|
+ gsSP2Triangles( 9, 0, 2, 0x0, 12, 13, 10, 0x0),
|
|
+ gsSP2Triangles(13, 11, 10, 0x0, 13, 14, 11, 0x0),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_left_hand_closed_shared_dl_vertex_group1[] = {
|
|
+ {{{ 36, 6, 42}, 0, { 0, 0}, {0xe1, 0xf0, 0x79, 0x00}}},
|
|
+ {{{ 17, -1, 27}, 0, { 0, 0}, {0x00, 0xfd, 0x7f, 0x00}}},
|
|
+ {{{ 34, -41, 3}, 0, { 0, 0}, {0x42, 0xa3, 0x36, 0x00}}},
|
|
+ {{{ 26, -25, -32}, 0, { 0, 0}, {0x09, 0xc7, 0x8f, 0x00}}},
|
|
+ {{{ 4, 24, -31}, 0, { 0, 0}, {0xd5, 0x3f, 0x9c, 0x00}}},
|
|
+ {{{ 33, 7, -44}, 0, { 0, 0}, {0xc6, 0xfe, 0x90, 0x00}}},
|
|
+ {{{ -1, 39, 5}, 0, { 0, 0}, {0xea, 0x6e, 0x3a, 0x00}}},
|
|
+ {{{ 5, -6, 36}, 0, { 0, 0}, {0x44, 0x1b, 0x67, 0x00}}},
|
|
+ {{{ -10, 26, -38}, 0, { 0, 0}, {0xf0, 0x41, 0x95, 0x00}}},
|
|
+ {{{ 17, -38, -39}, 0, { 0, 0}, {0x1a, 0xb7, 0x9d, 0x00}}},
|
|
+ {{{ 86, 29, 41}, 0, { 0, 0}, {0x4b, 0x20, 0x60, 0x00}}},
|
|
+ {{{ 59, 81, 8}, 0, { 0, 0}, {0x11, 0x7a, 0x1d, 0x00}}},
|
|
+ {{{ 107, -26, 4}, 0, { 0, 0}, {0x67, 0xc5, 0x2b, 0x00}}},
|
|
+ {{{ 61, 12, -60}, 0, { 0, 0}, {0x00, 0x21, 0x86, 0x00}}},
|
|
+ {{{ 90, 17, -46}, 0, { 0, 0}, {0x43, 0x35, 0xa3, 0x00}}},
|
|
+ {{{ 100, -6, -46}, 0, { 0, 0}, {0x63, 0x0a, 0xb3, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_left_hand_closed_shared_dl_vertex_group2[] = {
|
|
+ {{{ 90, 17, -46}, 0, { 0, 0}, {0x43, 0x35, 0xa3, 0x00}}},
|
|
+ {{{ 57, 55, -37}, 0, { 0, 0}, {0x22, 0x54, 0xa9, 0x00}}},
|
|
+ {{{ 99, 40, -16}, 0, { 0, 0}, {0x6c, 0x3c, 0xe5, 0x00}}},
|
|
+ {{{ 32, 63, -28}, 0, { 0, 0}, {0xd0, 0x4f, 0xaa, 0x00}}},
|
|
+ {{{ 12, 59, 10}, 0, { 0, 0}, {0xaa, 0x58, 0x1b, 0x00}}},
|
|
+ {{{ 59, 81, 8}, 0, { 0, 0}, {0x11, 0x7a, 0x1d, 0x00}}},
|
|
+ {{{ 80, -31, -61}, 0, { 0, 0}, {0x0c, 0xb2, 0x9d, 0x00}}},
|
|
+ {{{ 100, -6, -46}, 0, { 0, 0}, {0x63, 0x0a, 0xb3, 0x00}}},
|
|
+ {{{ 107, -26, 4}, 0, { 0, 0}, {0x67, 0xc5, 0x2b, 0x00}}},
|
|
+ {{{ 61, 12, -60}, 0, { 0, 0}, {0x00, 0x21, 0x86, 0x00}}},
|
|
+ {{{ 33, 7, -44}, 0, { 0, 0}, {0xc6, 0xfe, 0x90, 0x00}}},
|
|
+ {{{ 86, 29, 41}, 0, { 0, 0}, {0x4b, 0x20, 0x60, 0x00}}},
|
|
+ {{{ 58, -45, 7}, 0, { 0, 0}, {0x01, 0x85, 0x1c, 0x00}}},
|
|
+ {{{ 36, 6, 42}, 0, { 0, 0}, {0xe1, 0xf0, 0x79, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_left_hand_closed_shared_dl_vertex_group3[] = {
|
|
+ {{{ 27, -58, 6}, 0, { 0, 0}, {0xa3, 0xad, 0x12, 0x00}}},
|
|
+ {{{ -14, -14, -4}, 0, { 0, 0}, {0x8c, 0xcd, 0x02, 0x00}}},
|
|
+ {{{ 17, -38, -39}, 0, { 0, 0}, {0x1a, 0xb7, 0x9d, 0x00}}},
|
|
+ {{{ -10, 26, -38}, 0, { 0, 0}, {0xf0, 0x41, 0x95, 0x00}}},
|
|
+ {{{ -18, 45, 8}, 0, { 0, 0}, {0x84, 0xf3, 0x13, 0x00}}},
|
|
+ {{{ 5, -6, 36}, 0, { 0, 0}, {0x99, 0xd2, 0x38, 0x00}}},
|
|
+ {{{ 34, -41, 3}, 0, { 0, 0}, {0x42, 0xa3, 0x36, 0x00}}},
|
|
+ {{{ 27, -58, 6}, 0, { 0, 0}, {0x73, 0xd5, 0x1d, 0x00}}},
|
|
+ {{{ 26, -25, -32}, 0, { 0, 0}, {0x09, 0xc7, 0x8f, 0x00}}},
|
|
+ {{{ -18, 45, 8}, 0, { 0, 0}, {0x2d, 0x71, 0x21, 0x00}}},
|
|
+ {{{ -1, 39, 5}, 0, { 0, 0}, {0xea, 0x6e, 0x3a, 0x00}}},
|
|
+ {{{ 5, -6, 36}, 0, { 0, 0}, {0x44, 0x1b, 0x67, 0x00}}},
|
|
+ {{{ 36, 6, 42}, 0, { 0, 0}, {0xe1, 0xf0, 0x79, 0x00}}},
|
|
+ {{{ 12, 59, 10}, 0, { 0, 0}, {0xaa, 0x58, 0x1b, 0x00}}},
|
|
+ {{{ 58, -45, 7}, 0, { 0, 0}, {0x01, 0x85, 0x1c, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_left_hand_closed_shared_dl_vertex_group4[] = {
|
|
+ {{{ 26, -25, -32}, 0, { 0, 0}, {0x09, 0xc7, 0x8f, 0x00}}},
|
|
+ {{{ 33, 7, -44}, 0, { 0, 0}, {0xc6, 0xfe, 0x90, 0x00}}},
|
|
+ {{{ 80, -31, -61}, 0, { 0, 0}, {0x0c, 0xb2, 0x9d, 0x00}}},
|
|
+ {{{ 58, -45, 7}, 0, { 0, 0}, {0x01, 0x85, 0x1c, 0x00}}},
|
|
+ {{{ 34, -41, 3}, 0, { 0, 0}, {0x42, 0xa3, 0x36, 0x00}}},
|
|
+ {{{ 61, 12, -60}, 0, { 0, 0}, {0x00, 0x21, 0x86, 0x00}}},
|
|
+ {{{ 12, 59, 10}, 0, { 0, 0}, {0xaa, 0x58, 0x1b, 0x00}}},
|
|
+ {{{ 32, 63, -28}, 0, { 0, 0}, {0xd0, 0x4f, 0xaa, 0x00}}},
|
|
+ {{{ 4, 24, -31}, 0, { 0, 0}, {0xd5, 0x3f, 0x9c, 0x00}}},
|
|
+ {{{ -1, 39, 5}, 0, { 0, 0}, {0xea, 0x6e, 0x3a, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Gfx ghost_mario_left_hand_closed_shared_dl[] = {
|
|
+ gsSPVertex(ghost_mario_left_hand_closed_shared_dl_vertex_group1, 16, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
|
+ gsSP2Triangles( 6, 1, 0, 0x0, 2, 1, 7, 0x0),
|
|
+ gsSP2Triangles( 7, 1, 6, 0x0, 6, 4, 8, 0x0),
|
|
+ gsSP2Triangles( 8, 4, 3, 0x0, 9, 3, 2, 0x0),
|
|
+ gsSP2Triangles( 0, 10, 11, 0x0, 12, 10, 0, 0x0),
|
|
+ gsSP1Triangle(13, 14, 15, 0x0),
|
|
+ gsSPVertex(ghost_mario_left_hand_closed_shared_dl_vertex_group2, 14, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
|
+ gsSP2Triangles( 5, 1, 3, 0x0, 6, 7, 8, 0x0),
|
|
+ gsSP2Triangles( 9, 10, 3, 0x0, 1, 0, 9, 0x0),
|
|
+ gsSP2Triangles( 9, 3, 1, 0x0, 5, 2, 1, 0x0),
|
|
+ gsSP2Triangles( 0, 2, 7, 0x0, 7, 2, 8, 0x0),
|
|
+ gsSP2Triangles( 8, 2, 11, 0x0, 11, 2, 5, 0x0),
|
|
+ gsSP2Triangles( 9, 7, 6, 0x0, 6, 8, 12, 0x0),
|
|
+ gsSP2Triangles(12, 8, 13, 0x0, 13, 5, 4, 0x0),
|
|
+ gsSPVertex(ghost_mario_left_hand_closed_shared_dl_vertex_group3, 15, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 2, 1, 3, 0x0),
|
|
+ gsSP2Triangles( 3, 1, 4, 0x0, 4, 1, 5, 0x0),
|
|
+ gsSP2Triangles( 5, 1, 0, 0x0, 6, 7, 2, 0x0),
|
|
+ gsSP2Triangles( 8, 2, 3, 0x0, 3, 9, 10, 0x0),
|
|
+ gsSP2Triangles(10, 9, 11, 0x0, 11, 7, 6, 0x0),
|
|
+ gsSP2Triangles(10, 12, 13, 0x0, 6, 14, 12, 0x0),
|
|
+ gsSPVertex(ghost_mario_left_hand_closed_shared_dl_vertex_group4, 10, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 3, 4, 0, 0x0),
|
|
+ gsSP2Triangles( 1, 5, 2, 0x0, 0, 2, 3, 0x0),
|
|
+ gsSP2Triangles( 6, 7, 8, 0x0, 8, 9, 6, 0x0),
|
|
+ gsSP1Triangle( 7, 1, 8, 0x0),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+//
|
|
+// Right arm
|
|
+//
|
|
+
|
|
+static const Vtx ghost_mario_right_arm_shared_dl_vertex_group1[] = {
|
|
+ {{{ 57, -14, -22}, 0, { 0, 0}, {0x33, 0xcf, 0x97, 0x00}}},
|
|
+ {{{ 5, -44, 5}, 0, { 0, 0}, {0xd3, 0x8a, 0xf7, 0x00}}},
|
|
+ {{{ 6, -15, -30}, 0, { 0, 0}, {0xd6, 0xe6, 0x8c, 0x00}}},
|
|
+ {{{ 57, -38, 6}, 0, { 0, 0}, {0x3e, 0x93, 0x07, 0x00}}},
|
|
+ {{{ 6, -19, 44}, 0, { 0, 0}, {0xd5, 0xd4, 0x6e, 0x00}}},
|
|
+ {{{ 57, -17, 37}, 0, { 0, 0}, {0x33, 0xe8, 0x71, 0x00}}},
|
|
+ {{{ 7, 25, 32}, 0, { 0, 0}, {0xd9, 0x5c, 0x4d, 0x00}}},
|
|
+ {{{ 58, 17, 27}, 0, { 0, 0}, {0x44, 0x59, 0x39, 0x00}}},
|
|
+ {{{ 7, 27, -13}, 0, { 0, 0}, {0xda, 0x67, 0xc2, 0x00}}},
|
|
+ {{{ 58, 19, -9}, 0, { 0, 0}, {0x3e, 0x4a, 0xaf, 0x00}}},
|
|
+ {{{ -9, -28, 6}, 0, { 0, 0}, {0x96, 0xbf, 0xec, 0x00}}},
|
|
+ {{{ -9, -10, -15}, 0, { 0, 0}, {0x8f, 0x01, 0xc7, 0x00}}},
|
|
+ {{{ -8, 15, -5}, 0, { 0, 0}, {0x91, 0x39, 0xed, 0x00}}},
|
|
+ {{{ -8, 14, 22}, 0, { 0, 0}, {0x99, 0x2e, 0x38, 0x00}}},
|
|
+ {{{ -9, -13, 30}, 0, { 0, 0}, {0x8a, 0xe9, 0x26, 0x00}}},
|
|
+ {{{ 67, -12, -13}, 0, { 0, 0}, {0x68, 0xeb, 0xbc, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_right_arm_shared_dl_vertex_group2[] = {
|
|
+ {{{ 57, -38, 6}, 0, { 0, 0}, {0x3e, 0x93, 0x07, 0x00}}},
|
|
+ {{{ 67, -14, 28}, 0, { 0, 0}, {0x6f, 0xe8, 0x37, 0x00}}},
|
|
+ {{{ 57, -17, 37}, 0, { 0, 0}, {0x33, 0xe8, 0x71, 0x00}}},
|
|
+ {{{ 58, 17, 27}, 0, { 0, 0}, {0x44, 0x59, 0x39, 0x00}}},
|
|
+ {{{ 67, 11, -4}, 0, { 0, 0}, {0x78, 0x26, 0xf1, 0x00}}},
|
|
+ {{{ 58, 19, -9}, 0, { 0, 0}, {0x3e, 0x4a, 0xaf, 0x00}}},
|
|
+ {{{ 67, 10, 21}, 0, { 0, 0}, {0x71, 0x2a, 0x25, 0x00}}},
|
|
+ {{{ 66, -28, 6}, 0, { 0, 0}, {0x75, 0xd1, 0xfe, 0x00}}},
|
|
+ {{{ 67, -12, -13}, 0, { 0, 0}, {0x68, 0xeb, 0xbc, 0x00}}},
|
|
+ {{{ -9, -13, 30}, 0, { 0, 0}, {0x8a, 0xe9, 0x26, 0x00}}},
|
|
+ {{{ -9, -28, 6}, 0, { 0, 0}, {0x96, 0xbf, 0xec, 0x00}}},
|
|
+ {{{ 5, -44, 5}, 0, { 0, 0}, {0xd3, 0x8a, 0xf7, 0x00}}},
|
|
+ {{{ -8, 14, 22}, 0, { 0, 0}, {0x99, 0x2e, 0x38, 0x00}}},
|
|
+ {{{ 6, -19, 44}, 0, { 0, 0}, {0xd5, 0xd4, 0x6e, 0x00}}},
|
|
+ {{{ -8, 15, -5}, 0, { 0, 0}, {0x91, 0x39, 0xed, 0x00}}},
|
|
+ {{{ 7, 25, 32}, 0, { 0, 0}, {0xd9, 0x5c, 0x4d, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_right_arm_shared_dl_vertex_group3[] = {
|
|
+ {{{ -9, -10, -15}, 0, { 0, 0}, {0x8f, 0x01, 0xc7, 0x00}}},
|
|
+ {{{ -8, 15, -5}, 0, { 0, 0}, {0x91, 0x39, 0xed, 0x00}}},
|
|
+ {{{ 7, 27, -13}, 0, { 0, 0}, {0xda, 0x67, 0xc2, 0x00}}},
|
|
+ {{{ -9, -28, 6}, 0, { 0, 0}, {0x96, 0xbf, 0xec, 0x00}}},
|
|
+ {{{ 6, -15, -30}, 0, { 0, 0}, {0xd6, 0xe6, 0x8c, 0x00}}},
|
|
+ {{{ 58, 19, -9}, 0, { 0, 0}, {0x3e, 0x4a, 0xaf, 0x00}}},
|
|
+ {{{ 57, -14, -22}, 0, { 0, 0}, {0x33, 0xcf, 0x97, 0x00}}},
|
|
+ {{{ 58, 17, 27}, 0, { 0, 0}, {0x44, 0x59, 0x39, 0x00}}},
|
|
+ {{{ 57, -17, 37}, 0, { 0, 0}, {0x33, 0xe8, 0x71, 0x00}}},
|
|
+ {{{ 7, 25, 32}, 0, { 0, 0}, {0xd9, 0x5c, 0x4d, 0x00}}},
|
|
+ {{{ 57, -38, 6}, 0, { 0, 0}, {0x3e, 0x93, 0x07, 0x00}}},
|
|
+ {{{ 6, -19, 44}, 0, { 0, 0}, {0xd5, 0xd4, 0x6e, 0x00}}},
|
|
+ {{{ 5, -44, 5}, 0, { 0, 0}, {0xd3, 0x8a, 0xf7, 0x00}}},
|
|
+ {{{ 67, -12, -13}, 0, { 0, 0}, {0x68, 0xeb, 0xbc, 0x00}}},
|
|
+ {{{ 67, 11, -4}, 0, { 0, 0}, {0x78, 0x26, 0xf1, 0x00}}},
|
|
+ {{{ 66, -28, 6}, 0, { 0, 0}, {0x75, 0xd1, 0xfe, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_right_arm_shared_dl_vertex_group4[] = {
|
|
+ {{{ -9, -10, -15}, 0, { 0, 0}, {0x8f, 0x01, 0xc7, 0x00}}},
|
|
+ {{{ -9, -28, 6}, 0, { 0, 0}, {0x96, 0xbf, 0xec, 0x00}}},
|
|
+ {{{ -9, -13, 30}, 0, { 0, 0}, {0x8a, 0xe9, 0x26, 0x00}}},
|
|
+ {{{ -8, 15, -5}, 0, { 0, 0}, {0x91, 0x39, 0xed, 0x00}}},
|
|
+ {{{ -8, 14, 22}, 0, { 0, 0}, {0x99, 0x2e, 0x38, 0x00}}},
|
|
+ {{{ 67, 11, -4}, 0, { 0, 0}, {0x78, 0x26, 0xf1, 0x00}}},
|
|
+ {{{ 67, -14, 28}, 0, { 0, 0}, {0x6f, 0xe8, 0x37, 0x00}}},
|
|
+ {{{ 66, -28, 6}, 0, { 0, 0}, {0x75, 0xd1, 0xfe, 0x00}}},
|
|
+ {{{ 67, 10, 21}, 0, { 0, 0}, {0x71, 0x2a, 0x25, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Gfx ghost_mario_right_arm_shared_dl[] = {
|
|
+ gsSPVertex(ghost_mario_right_arm_shared_dl_vertex_group1, 16, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 3, 4, 1, 0x0),
|
|
+ gsSP2Triangles( 5, 6, 4, 0x0, 7, 8, 6, 0x0),
|
|
+ gsSP2Triangles( 9, 2, 8, 0x0, 1, 10, 2, 0x0),
|
|
+ gsSP2Triangles( 2, 11, 8, 0x0, 8, 12, 6, 0x0),
|
|
+ gsSP2Triangles( 6, 13, 4, 0x0, 4, 14, 1, 0x0),
|
|
+ gsSP2Triangles( 9, 15, 0, 0x0, 0, 15, 3, 0x0),
|
|
+ gsSPVertex(ghost_mario_right_arm_shared_dl_vertex_group2, 16, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 2, 1, 3, 0x0),
|
|
+ gsSP2Triangles( 3, 4, 5, 0x0, 3, 6, 4, 0x0),
|
|
+ gsSP2Triangles( 1, 6, 3, 0x0, 0, 7, 1, 0x0),
|
|
+ gsSP2Triangles( 8, 7, 0, 0x0, 5, 4, 8, 0x0),
|
|
+ gsSP2Triangles( 9, 10, 11, 0x0, 12, 9, 13, 0x0),
|
|
+ gsSP1Triangle(14, 12, 15, 0x0),
|
|
+ gsSPVertex(ghost_mario_right_arm_shared_dl_vertex_group3, 16, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 3, 0, 4, 0x0),
|
|
+ gsSP2Triangles( 5, 6, 4, 0x0, 7, 5, 2, 0x0),
|
|
+ gsSP2Triangles( 8, 7, 9, 0x0, 10, 8, 11, 0x0),
|
|
+ gsSP2Triangles( 6, 10, 12, 0x0, 13, 14, 15, 0x0),
|
|
+ gsSPVertex(ghost_mario_right_arm_shared_dl_vertex_group4, 9, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 2, 3, 0, 0x0),
|
|
+ gsSP2Triangles( 2, 4, 3, 0x0, 5, 6, 7, 0x0),
|
|
+ gsSP1Triangle( 5, 8, 6, 0x0),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_right_forearm_shared_dl_vertex[] = {
|
|
+ {{{ 47, -15, -19}, 0, { 0, 0}, {0x41, 0xcf, 0x9f, 0x00}}},
|
|
+ {{{ -3, -39, 6}, 0, { 0, 0}, {0xd4, 0x8a, 0xf8, 0x00}}},
|
|
+ {{{ -2, -15, -23}, 0, { 0, 0}, {0xd7, 0xe5, 0x8c, 0x00}}},
|
|
+ {{{ 46, -36, 6}, 0, { 0, 0}, {0x3f, 0x94, 0x0f, 0x00}}},
|
|
+ {{{ -2, -18, 38}, 0, { 0, 0}, {0xd6, 0xd5, 0x6f, 0x00}}},
|
|
+ {{{ 47, -17, 34}, 0, { 0, 0}, {0x42, 0xec, 0x6a, 0x00}}},
|
|
+ {{{ -1, 18, 28}, 0, { 0, 0}, {0xdb, 0x5d, 0x4d, 0x00}}},
|
|
+ {{{ 48, 13, 25}, 0, { 0, 0}, {0x45, 0x5d, 0x32, 0x00}}},
|
|
+ {{{ -1, 20, -9}, 0, { 0, 0}, {0xdb, 0x67, 0xc1, 0x00}}},
|
|
+ {{{ 48, 15, -7}, 0, { 0, 0}, {0x45, 0x4c, 0xb6, 0x00}}},
|
|
+ {{{ -14, -28, 6}, 0, { 0, 0}, {0x90, 0xc9, 0xef, 0x00}}},
|
|
+ {{{ -14, -12, -13}, 0, { 0, 0}, {0x91, 0x01, 0xc3, 0x00}}},
|
|
+ {{{ -13, 12, -4}, 0, { 0, 0}, {0x9e, 0x4b, 0xe7, 0x00}}},
|
|
+ {{{ -13, 10, 21}, 0, { 0, 0}, {0x8d, 0x22, 0x28, 0x00}}},
|
|
+ {{{ -14, -14, 28}, 0, { 0, 0}, {0x9a, 0xd8, 0x3f, 0x00}}},
|
|
+ {{{ 59, -8, 7}, 0, { 0, 0}, {0x7f, 0xfd, 0x00, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Gfx ghost_mario_right_forearm_shared_dl[] = {
|
|
+ gsSPVertex(ghost_mario_right_forearm_shared_dl_vertex, 16, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 3, 4, 1, 0x0),
|
|
+ gsSP2Triangles( 5, 6, 4, 0x0, 7, 8, 6, 0x0),
|
|
+ gsSP2Triangles( 9, 2, 8, 0x0, 1, 10, 2, 0x0),
|
|
+ gsSP2Triangles( 2, 11, 8, 0x0, 8, 12, 6, 0x0),
|
|
+ gsSP2Triangles( 6, 13, 4, 0x0, 4, 14, 1, 0x0),
|
|
+ gsSP2Triangles( 9, 15, 0, 0x0, 0, 15, 3, 0x0),
|
|
+ gsSP2Triangles( 3, 15, 5, 0x0, 5, 15, 7, 0x0),
|
|
+ gsSP2Triangles( 7, 15, 9, 0x0, 14, 10, 1, 0x0),
|
|
+ gsSP2Triangles(13, 14, 4, 0x0, 12, 13, 6, 0x0),
|
|
+ gsSP2Triangles(11, 12, 8, 0x0, 10, 11, 2, 0x0),
|
|
+ gsSP2Triangles( 9, 0, 2, 0x0, 7, 9, 8, 0x0),
|
|
+ gsSP2Triangles( 5, 7, 6, 0x0, 3, 5, 4, 0x0),
|
|
+ gsSP2Triangles( 0, 3, 1, 0x0, 11, 13, 12, 0x0),
|
|
+ gsSP2Triangles(11, 10, 13, 0x0, 10, 14, 13, 0x0),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_right_hand_closed_dl_vertex_group1[] = {
|
|
+ {{{ 35, 9, -37}, 0, { 0, 0}, {0xe5, 0xf5, 0x85, 0x00}}},
|
|
+ {{{ 55, -44, -4}, 0, { 0, 0}, {0x00, 0x86, 0xdf, 0x00}}},
|
|
+ {{{ 31, -40, -1}, 0, { 0, 0}, {0x43, 0xa4, 0xc9, 0x00}}},
|
|
+ {{{ 10, 60, -4}, 0, { 0, 0}, {0xac, 0x5a, 0xe5, 0x00}}},
|
|
+ {{{ -2, 41, -1}, 0, { 0, 0}, {0xed, 0x70, 0xc9, 0x00}}},
|
|
+ {{{ 24, -57, -4}, 0, { 0, 0}, {0x73, 0xd4, 0xe6, 0x00}}},
|
|
+ {{{ 4, -3, -33}, 0, { 0, 0}, {0x48, 0x1e, 0x9d, 0x00}}},
|
|
+ {{{ -19, 47, -4}, 0, { 0, 0}, {0x30, 0x72, 0xe5, 0x00}}},
|
|
+ {{{ -14, 26, 41}, 0, { 0, 0}, {0xed, 0x3d, 0x6d, 0x00}}},
|
|
+ {{{ 13, -38, 41}, 0, { 0, 0}, {0x15, 0xb3, 0x61, 0x00}}},
|
|
+ {{{ 23, -26, 35}, 0, { 0, 0}, {0x04, 0xc3, 0x6e, 0x00}}},
|
|
+ {{{ 24, -57, -4}, 0, { 0, 0}, {0xa2, 0xaf, 0xe7, 0x00}}},
|
|
+ {{{ -16, -12, 6}, 0, { 0, 0}, {0x8c, 0xcf, 0xf8, 0x00}}},
|
|
+ {{{ 4, -3, -33}, 0, { 0, 0}, {0x9b, 0xd5, 0xc2, 0x00}}},
|
|
+ {{{ -19, 47, -4}, 0, { 0, 0}, {0x85, 0xf5, 0xe7, 0x00}}},
|
|
+ {{{ 58, 81, 0}, 0, { 0, 0}, {0x14, 0x7b, 0xe9, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_right_hand_closed_dl_vertex_group2[] = {
|
|
+ {{{ 35, 9, -37}, 0, { 0, 0}, {0xe5, 0xf5, 0x85, 0x00}}},
|
|
+ {{{ 104, -26, 1}, 0, { 0, 0}, {0x68, 0xc5, 0xd7, 0x00}}},
|
|
+ {{{ 55, -44, -4}, 0, { 0, 0}, {0x00, 0x86, 0xdf, 0x00}}},
|
|
+ {{{ 75, -33, 66}, 0, { 0, 0}, {0x08, 0xaf, 0x60, 0x00}}},
|
|
+ {{{ 96, -8, 52}, 0, { 0, 0}, {0x60, 0x06, 0x51, 0x00}}},
|
|
+ {{{ 57, 10, 66}, 0, { 0, 0}, {0xfd, 0x1c, 0x7b, 0x00}}},
|
|
+ {{{ 58, 81, 0}, 0, { 0, 0}, {0x14, 0x7b, 0xe9, 0x00}}},
|
|
+ {{{ 97, 39, 24}, 0, { 0, 0}, {0x6b, 0x3a, 0x21, 0x00}}},
|
|
+ {{{ 86, 30, -33}, 0, { 0, 0}, {0x4f, 0x22, 0xa4, 0x00}}},
|
|
+ {{{ 86, 15, 52}, 0, { 0, 0}, {0x40, 0x30, 0x61, 0x00}}},
|
|
+ {{{ 54, 54, 44}, 0, { 0, 0}, {0x20, 0x51, 0x5c, 0x00}}},
|
|
+ {{{ 29, 62, 34}, 0, { 0, 0}, {0xce, 0x4c, 0x57, 0x00}}},
|
|
+ {{{ 29, 6, 49}, 0, { 0, 0}, {0xc2, 0xfa, 0x6e, 0x00}}},
|
|
+ {{{ 10, 60, -4}, 0, { 0, 0}, {0xac, 0x5a, 0xe5, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_right_hand_closed_dl_vertex_group3[] = {
|
|
+ {{{ 31, -40, -1}, 0, { 0, 0}, {0x43, 0xa4, 0xc9, 0x00}}},
|
|
+ {{{ 23, -26, 35}, 0, { 0, 0}, {0x04, 0xc3, 0x6e, 0x00}}},
|
|
+ {{{ 13, -38, 41}, 0, { 0, 0}, {0x15, 0xb3, 0x61, 0x00}}},
|
|
+ {{{ 1, 24, 35}, 0, { 0, 0}, {0xd2, 0x3c, 0x65, 0x00}}},
|
|
+ {{{ -14, 26, 41}, 0, { 0, 0}, {0xed, 0x3d, 0x6d, 0x00}}},
|
|
+ {{{ -2, 41, -1}, 0, { 0, 0}, {0xed, 0x70, 0xc9, 0x00}}},
|
|
+ {{{ 15, 0, -23}, 0, { 0, 0}, {0x04, 0x01, 0x82, 0x00}}},
|
|
+ {{{ 4, -3, -33}, 0, { 0, 0}, {0x48, 0x1e, 0x9d, 0x00}}},
|
|
+ {{{ 35, 9, -37}, 0, { 0, 0}, {0xe5, 0xf5, 0x85, 0x00}}},
|
|
+ {{{ 29, 6, 49}, 0, { 0, 0}, {0xc2, 0xfa, 0x6e, 0x00}}},
|
|
+ {{{ 55, -44, -4}, 0, { 0, 0}, {0x00, 0x86, 0xdf, 0x00}}},
|
|
+ {{{ 75, -33, 66}, 0, { 0, 0}, {0x08, 0xaf, 0x60, 0x00}}},
|
|
+ {{{ 57, 10, 66}, 0, { 0, 0}, {0xfd, 0x1c, 0x7b, 0x00}}},
|
|
+ {{{ 10, 60, -4}, 0, { 0, 0}, {0xac, 0x5a, 0xe5, 0x00}}},
|
|
+ {{{ 29, 62, 34}, 0, { 0, 0}, {0xce, 0x4c, 0x57, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Gfx ghost_mario_right_hand_closed[] = {
|
|
+ gsSPVertex(ghost_mario_right_hand_closed_dl_vertex_group1, 16, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 0, 4, 0x0),
|
|
+ gsSP2Triangles(2, 5, 6, 0x0, 6, 7, 4, 0x0),
|
|
+ gsSP2Triangles(4, 7, 8, 0x0, 8, 9, 10, 0x0),
|
|
+ gsSP2Triangles(9, 5, 2, 0x0, 11, 12, 13, 0x0),
|
|
+ gsSP2Triangles(13, 12, 14, 0x0, 14, 12, 8, 0x0),
|
|
+ gsSP2Triangles(8, 12, 9, 0x0, 9, 12, 11, 0x0),
|
|
+ gsSP1Triangle(3, 15, 0, 0x0),
|
|
+ gsSPVertex(ghost_mario_right_hand_closed_dl_vertex_group2, 14, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 2, 1, 3, 0x0),
|
|
+ gsSP2Triangles(3, 4, 5, 0x0, 6, 7, 8, 0x0),
|
|
+ gsSP2Triangles(8, 7, 1, 0x0, 1, 7, 4, 0x0),
|
|
+ gsSP2Triangles(4, 7, 9, 0x0, 10, 7, 6, 0x0),
|
|
+ gsSP2Triangles(9, 10, 5, 0x0, 10, 11, 5, 0x0),
|
|
+ gsSP2Triangles(11, 12, 5, 0x0, 1, 4, 3, 0x0),
|
|
+ gsSP2Triangles(11, 10, 6, 0x0, 6, 13, 11, 0x0),
|
|
+ gsSP2Triangles(7, 10, 9, 0x0, 4, 9, 5, 0x0),
|
|
+ gsSP2Triangles(0, 8, 1, 0x0, 6, 8, 0, 0x0),
|
|
+ gsSPVertex(ghost_mario_right_hand_closed_dl_vertex_group3, 15, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 1, 3, 4, 0x0),
|
|
+ gsSP2Triangles(4, 3, 5, 0x0, 5, 6, 7, 0x0),
|
|
+ gsSP2Triangles(7, 6, 0, 0x0, 8, 6, 5, 0x0),
|
|
+ gsSP2Triangles(9, 3, 1, 0x0, 0, 6, 8, 0x0),
|
|
+ gsSP2Triangles(10, 11, 1, 0x0, 11, 9, 1, 0x0),
|
|
+ gsSP2Triangles(11, 12, 9, 0x0, 1, 0, 10, 0x0),
|
|
+ gsSP2Triangles(13, 5, 3, 0x0, 3, 9, 14, 0x0),
|
|
+ gsSP1Triangle(14, 13, 3, 0x0),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+//
|
|
+// Left leg
|
|
+//
|
|
+
|
|
+static const Vtx ghost_mario_left_thigh_dl_vertex_group1[] = {
|
|
+ {{{ 1, -44, 8}, 0, { 0, 0}, {0xab, 0xa2, 0x00, 0x00}}},
|
|
+ {{{ -15, 0, 7}, 0, { 0, 0}, {0x82, 0xf7, 0xff, 0x00}}},
|
|
+ {{{ 0, -13, -32}, 0, { 0, 0}, {0x9f, 0xe1, 0xb5, 0x00}}},
|
|
+ {{{ -4, 37, -17}, 0, { 0, 0}, {0x9e, 0x30, 0xc0, 0x00}}},
|
|
+ {{{ -5, 37, 31}, 0, { 0, 0}, {0xa0, 0x3f, 0x34, 0x00}}},
|
|
+ {{{ -1, -12, 47}, 0, { 0, 0}, {0x9e, 0xe3, 0x49, 0x00}}},
|
|
+ {{{ 95, -5, 48}, 0, { 0, 0}, {0x4e, 0xe9, 0x60, 0x00}}},
|
|
+ {{{ 116, 10, 8}, 0, { 0, 0}, {0x7e, 0x09, 0x01, 0x00}}},
|
|
+ {{{ 91, 45, 32}, 0, { 0, 0}, {0x3c, 0x4e, 0x4f, 0x00}}},
|
|
+ {{{ 92, 45, -16}, 0, { 0, 0}, {0x35, 0x5d, 0xbd, 0x00}}},
|
|
+ {{{ 96, -5, -31}, 0, { 0, 0}, {0x50, 0xe8, 0xa1, 0x00}}},
|
|
+ {{{ 98, -37, 8}, 0, { 0, 0}, {0x46, 0x97, 0x01, 0x00}}},
|
|
+ {{{ 19, -15, -42}, 0, { 0, 0}, {0xec, 0xd9, 0x8a, 0x00}}},
|
|
+ {{{ 14, 48, -23}, 0, { 0, 0}, {0xd7, 0x67, 0xc5, 0x00}}},
|
|
+ {{{ 13, 48, 38}, 0, { 0, 0}, {0xe7, 0x6d, 0x3a, 0x00}}},
|
|
+ {{{ 18, -15, 58}, 0, { 0, 0}, {0xea, 0xda, 0x76, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_left_thigh_dl_vertex_group2[] = {
|
|
+ {{{ 18, -15, 58}, 0, { 0, 0}, {0xea, 0xda, 0x76, 0x00}}},
|
|
+ {{{ 1, -44, 8}, 0, { 0, 0}, {0xab, 0xa2, 0x00, 0x00}}},
|
|
+ {{{ 21, -54, 8}, 0, { 0, 0}, {0xf0, 0x83, 0x00, 0x00}}},
|
|
+ {{{ 19, -15, -42}, 0, { 0, 0}, {0xec, 0xd9, 0x8a, 0x00}}},
|
|
+ {{{ -1, -12, 47}, 0, { 0, 0}, {0x9e, 0xe3, 0x49, 0x00}}},
|
|
+ {{{ -15, 0, 7}, 0, { 0, 0}, {0x82, 0xf7, 0xff, 0x00}}},
|
|
+ {{{ 98, -37, 8}, 0, { 0, 0}, {0x46, 0x97, 0x01, 0x00}}},
|
|
+ {{{ 13, 48, 38}, 0, { 0, 0}, {0xe7, 0x6d, 0x3a, 0x00}}},
|
|
+ {{{ 91, 45, 32}, 0, { 0, 0}, {0x3c, 0x4e, 0x4f, 0x00}}},
|
|
+ {{{ 14, 48, -23}, 0, { 0, 0}, {0xd7, 0x67, 0xc5, 0x00}}},
|
|
+ {{{ 92, 45, -16}, 0, { 0, 0}, {0x35, 0x5d, 0xbd, 0x00}}},
|
|
+ {{{ 96, -5, -31}, 0, { 0, 0}, {0x50, 0xe8, 0xa1, 0x00}}},
|
|
+ {{{ 95, -5, 48}, 0, { 0, 0}, {0x4e, 0xe9, 0x60, 0x00}}},
|
|
+ {{{ 0, -13, -32}, 0, { 0, 0}, {0x9f, 0xe1, 0xb5, 0x00}}},
|
|
+ {{{ -5, 37, 31}, 0, { 0, 0}, {0xa0, 0x3f, 0x34, 0x00}}},
|
|
+ {{{ -4, 37, -17}, 0, { 0, 0}, {0x9e, 0x30, 0xc0, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Gfx ghost_mario_left_thigh[] = {
|
|
+ gsDPPipeSync(),
|
|
+ gsSPVertex(ghost_mario_left_thigh_dl_vertex_group1, 16, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 2, 1, 3, 0x0),
|
|
+ gsSP2Triangles(3, 1, 4, 0x0, 4, 1, 5, 0x0),
|
|
+ gsSP2Triangles(6, 7, 8, 0x0, 8, 7, 9, 0x0),
|
|
+ gsSP2Triangles(9, 7, 10, 0x0, 10, 7, 11, 0x0),
|
|
+ gsSP2Triangles(11, 7, 6, 0x0, 12, 3, 13, 0x0),
|
|
+ gsSP2Triangles(13, 4, 14, 0x0, 14, 4, 15, 0x0),
|
|
+ gsSPVertex(ghost_mario_left_thigh_dl_vertex_group2, 16, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 2, 1, 3, 0x0),
|
|
+ gsSP2Triangles(4, 5, 1, 0x0, 0, 2, 6, 0x0),
|
|
+ gsSP2Triangles(7, 0, 8, 0x0, 9, 7, 10, 0x0),
|
|
+ gsSP2Triangles(3, 9, 10, 0x0, 2, 3, 6, 0x0),
|
|
+ gsSP2Triangles(3, 11, 6, 0x0, 10, 11, 3, 0x0),
|
|
+ gsSP2Triangles(7, 8, 10, 0x0, 0, 12, 8, 0x0),
|
|
+ gsSP2Triangles(6, 12, 0, 0x0, 1, 13, 3, 0x0),
|
|
+ gsSP2Triangles(0, 4, 1, 0x0, 14, 4, 0, 0x0),
|
|
+ gsSP2Triangles(9, 15, 14, 0x0, 3, 13, 15, 0x0),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_left_leg_shared_dl_vertex[] = {
|
|
+ {{{ 4, -37, 9}, 0, { 0, 0}, {0xc1, 0x93, 0x00, 0x00}}},
|
|
+ {{{ 64, -46, 9}, 0, { 0, 0}, {0x4b, 0x9a, 0x01, 0x00}}},
|
|
+ {{{ 65, -11, 54}, 0, { 0, 0}, {0x2d, 0xdb, 0x70, 0x00}}},
|
|
+ {{{ 8, 44, 33}, 0, { 0, 0}, {0xcc, 0x5e, 0x43, 0x00}}},
|
|
+ {{{ 68, 45, 37}, 0, { 0, 0}, {0x52, 0x4b, 0x3c, 0x00}}},
|
|
+ {{{ 69, 45, -18}, 0, { 0, 0}, {0x42, 0x61, 0xd1, 0x00}}},
|
|
+ {{{ 9, 44, -16}, 0, { 0, 0}, {0xc4, 0x4d, 0xaf, 0x00}}},
|
|
+ {{{ 66, -11, -36}, 0, { 0, 0}, {0x2e, 0xda, 0x91, 0x00}}},
|
|
+ {{{ 6, -6, -31}, 0, { 0, 0}, {0xb4, 0xe5, 0x9f, 0x00}}},
|
|
+ {{{ 6, -6, 49}, 0, { 0, 0}, {0xb3, 0xe7, 0x60, 0x00}}},
|
|
+ {{{ -14, 8, 8}, 0, { 0, 0}, {0x82, 0x06, 0xff, 0x00}}},
|
|
+ {{{ 81, 3, 9}, 0, { 0, 0}, {0x7e, 0xfa, 0x01, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Gfx ghost_mario_left_leg_shared_dl[] = {
|
|
+ gsSPVertex(ghost_mario_left_leg_shared_dl_vertex, 12, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 3, 2, 4, 0x0),
|
|
+ gsSP2Triangles( 3, 4, 5, 0x0, 6, 5, 7, 0x0),
|
|
+ gsSP2Triangles( 0, 7, 1, 0x0, 0, 8, 7, 0x0),
|
|
+ gsSP2Triangles( 7, 8, 6, 0x0, 5, 6, 3, 0x0),
|
|
+ gsSP2Triangles( 3, 9, 2, 0x0, 2, 9, 0, 0x0),
|
|
+ gsSP2Triangles( 3, 10, 9, 0x0, 5, 11, 7, 0x0),
|
|
+ gsSP2Triangles( 7, 11, 1, 0x0, 1, 11, 2, 0x0),
|
|
+ gsSP2Triangles( 2, 11, 4, 0x0, 4, 11, 5, 0x0),
|
|
+ gsSP2Triangles( 9, 10, 0, 0x0, 0, 10, 8, 0x0),
|
|
+ gsSP2Triangles( 8, 10, 6, 0x0, 6, 10, 3, 0x0),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_left_foot_shared_dl_vertex_group1[] = {
|
|
+ {{{ 110, 9, 35}, 0, { 0, 0}, {0x2b, 0x77, 0xff, 0x00}}},
|
|
+ {{{ 110, 8, -20}, 0, { 0, 0}, {0x2b, 0x77, 0xff, 0x00}}},
|
|
+ {{{ 76, 20, -41}, 0, { 0, 0}, {0x2b, 0x77, 0xff, 0x00}}},
|
|
+ {{{ 78, 21, 61}, 0, { 0, 0}, {0x2b, 0x77, 0xff, 0x00}}},
|
|
+ {{{ -12, 53, -32}, 0, { 0, 0}, {0x2b, 0x77, 0xff, 0x00}}},
|
|
+ {{{ -11, 54, 53}, 0, { 0, 0}, {0x2b, 0x77, 0xff, 0x00}}},
|
|
+ {{{ -39, 64, -8}, 0, { 0, 0}, {0x2b, 0x77, 0xff, 0x00}}},
|
|
+ {{{ -41, 65, 26}, 0, { 0, 0}, {0x2b, 0x77, 0xff, 0x00}}},
|
|
+ {{{ 43, -18, 54}, 0, { 0, 0}, {0x07, 0xb3, 0x64, 0x00}}},
|
|
+ {{{ 78, 21, 61}, 0, { 0, 0}, {0x15, 0xdb, 0x77, 0x00}}},
|
|
+ {{{ -11, 54, 53}, 0, { 0, 0}, {0xd9, 0x00, 0x78, 0x00}}},
|
|
+ {{{ 44, -12, -33}, 0, { 0, 0}, {0x01, 0xb7, 0x99, 0x00}}},
|
|
+ {{{ -35, 11, -21}, 0, { 0, 0}, {0xb5, 0xd2, 0xa5, 0x00}}},
|
|
+ {{{ -12, 53, -32}, 0, { 0, 0}, {0xd7, 0xfd, 0x89, 0x00}}},
|
|
+ {{{ -34, 12, 44}, 0, { 0, 0}, {0xb2, 0xd2, 0x58, 0x00}}},
|
|
+ {{{ 76, 20, -41}, 0, { 0, 0}, {0x0c, 0xd8, 0x89, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_left_foot_shared_dl_vertex_group2[] = {
|
|
+ {{{ 44, -12, -33}, 0, { 0, 0}, {0x01, 0xb7, 0x99, 0x00}}},
|
|
+ {{{ 76, 20, -41}, 0, { 0, 0}, {0x0c, 0xd8, 0x89, 0x00}}},
|
|
+ {{{ 110, 8, -20}, 0, { 0, 0}, {0x44, 0xad, 0xbe, 0x00}}},
|
|
+ {{{ 80, -31, 7}, 0, { 0, 0}, {0x34, 0x8d, 0xfb, 0x00}}},
|
|
+ {{{ 110, 9, 35}, 0, { 0, 0}, {0x4c, 0xaf, 0x3c, 0x00}}},
|
|
+ {{{ 78, 21, 61}, 0, { 0, 0}, {0x15, 0xdb, 0x77, 0x00}}},
|
|
+ {{{ 43, -18, 54}, 0, { 0, 0}, {0x07, 0xb3, 0x64, 0x00}}},
|
|
+ {{{ -34, 12, 44}, 0, { 0, 0}, {0xb2, 0xd2, 0x58, 0x00}}},
|
|
+ {{{ -11, 54, 53}, 0, { 0, 0}, {0xd9, 0x00, 0x78, 0x00}}},
|
|
+ {{{ -41, 65, 26}, 0, { 0, 0}, {0x90, 0x17, 0x35, 0x00}}},
|
|
+ {{{ -39, 64, -8}, 0, { 0, 0}, {0x93, 0x16, 0xc4, 0x00}}},
|
|
+ {{{ -35, 11, -21}, 0, { 0, 0}, {0xb5, 0xd2, 0xa5, 0x00}}},
|
|
+ {{{ -54, 15, 8}, 0, { 0, 0}, {0x88, 0xd8, 0xfd, 0x00}}},
|
|
+ {{{ -12, 53, -32}, 0, { 0, 0}, {0xd7, 0xfd, 0x89, 0x00}}},
|
|
+ {{{ 27, -35, 11}, 0, { 0, 0}, {0xdb, 0x87, 0xfc, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Gfx ghost_mario_left_foot_shared_dl[] = {
|
|
+ gsSPVertex(ghost_mario_left_foot_shared_dl_vertex_group1, 16, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 3, 0, 2, 0x0),
|
|
+ gsSP2Triangles( 3, 2, 4, 0x0, 5, 3, 4, 0x0),
|
|
+ gsSP2Triangles( 5, 4, 6, 0x0, 5, 6, 7, 0x0),
|
|
+ gsSP2Triangles( 8, 9, 10, 0x0, 11, 12, 13, 0x0),
|
|
+ gsSP2Triangles(14, 8, 10, 0x0, 11, 13, 15, 0x0),
|
|
+ gsSPVertex(ghost_mario_left_foot_shared_dl_vertex_group2, 15, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 3, 2, 4, 0x0),
|
|
+ gsSP2Triangles( 2, 3, 0, 0x0, 4, 5, 6, 0x0),
|
|
+ gsSP2Triangles( 6, 3, 4, 0x0, 7, 8, 9, 0x0),
|
|
+ gsSP2Triangles(10, 11, 12, 0x0, 10, 13, 11, 0x0),
|
|
+ gsSP2Triangles(12, 9, 10, 0x0, 9, 12, 7, 0x0),
|
|
+ gsSP2Triangles(14, 0, 3, 0x0, 11, 0, 14, 0x0),
|
|
+ gsSP2Triangles( 3, 6, 14, 0x0, 14, 6, 7, 0x0),
|
|
+ gsSP2Triangles(14, 7, 12, 0x0, 12, 11, 14, 0x0),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+//
|
|
+// Right leg
|
|
+//
|
|
+
|
|
+static const Vtx ghost_mario_right_thigh_shared_dl_vertex_group1[] = {
|
|
+ {{{ 98, -35, -10}, 0, { 0, 0}, {0x47, 0x97, 0xfc, 0x00}}},
|
|
+ {{{ 19, -16, 41}, 0, { 0, 0}, {0xee, 0xd6, 0x76, 0x00}}},
|
|
+ {{{ 22, -54, -9}, 0, { 0, 0}, {0xf2, 0x82, 0xfd, 0x00}}},
|
|
+ {{{ 91, 46, 16}, 0, { 0, 0}, {0x35, 0x5c, 0x44, 0x00}}},
|
|
+ {{{ 13, 48, 24}, 0, { 0, 0}, {0xd6, 0x66, 0x3e, 0x00}}},
|
|
+ {{{ 12, 49, -37}, 0, { 0, 0}, {0xe5, 0x6e, 0xc9, 0x00}}},
|
|
+ {{{ 90, 47, -32}, 0, { 0, 0}, {0x3b, 0x50, 0xb2, 0x00}}},
|
|
+ {{{ 18, -13, -58}, 0, { 0, 0}, {0xea, 0xdc, 0x89, 0x00}}},
|
|
+ {{{ 1, -44, -9}, 0, { 0, 0}, {0xad, 0xa1, 0xff, 0x00}}},
|
|
+ {{{ -15, 0, -7}, 0, { 0, 0}, {0x82, 0xf5, 0x02, 0x00}}},
|
|
+ {{{ -1, -11, -47}, 0, { 0, 0}, {0x9d, 0xe3, 0xb7, 0x00}}},
|
|
+ {{{ -6, 38, -31}, 0, { 0, 0}, {0x9e, 0x3f, 0xcf, 0x00}}},
|
|
+ {{{ -5, 36, 18}, 0, { 0, 0}, {0x9e, 0x2d, 0x42, 0x00}}},
|
|
+ {{{ 95, -3, -49}, 0, { 0, 0}, {0x4d, 0xec, 0x9e, 0x00}}},
|
|
+ {{{ 116, 11, -9}, 0, { 0, 0}, {0x7e, 0x0b, 0xfe, 0x00}}},
|
|
+ {{{ 96, -5, 30}, 0, { 0, 0}, {0x51, 0xe7, 0x5d, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_right_thigh_shared_dl_vertex_group2[] = {
|
|
+ {{{ -5, 36, 18}, 0, { 0, 0}, {0x9e, 0x2d, 0x42, 0x00}}},
|
|
+ {{{ -15, 0, -7}, 0, { 0, 0}, {0x82, 0xf5, 0x02, 0x00}}},
|
|
+ {{{ 0, -14, 31}, 0, { 0, 0}, {0xa0, 0xdf, 0x4b, 0x00}}},
|
|
+ {{{ 1, -44, -9}, 0, { 0, 0}, {0xad, 0xa1, 0xff, 0x00}}},
|
|
+ {{{ 19, -16, 41}, 0, { 0, 0}, {0xee, 0xd6, 0x76, 0x00}}},
|
|
+ {{{ -6, 38, -31}, 0, { 0, 0}, {0x9e, 0x3f, 0xcf, 0x00}}},
|
|
+ {{{ 13, 48, 24}, 0, { 0, 0}, {0xd6, 0x66, 0x3e, 0x00}}},
|
|
+ {{{ 18, -13, -58}, 0, { 0, 0}, {0xea, 0xdc, 0x89, 0x00}}},
|
|
+ {{{ -1, -11, -47}, 0, { 0, 0}, {0x9d, 0xe3, 0xb7, 0x00}}},
|
|
+ {{{ 95, -3, -49}, 0, { 0, 0}, {0x4d, 0xec, 0x9e, 0x00}}},
|
|
+ {{{ 98, -35, -10}, 0, { 0, 0}, {0x47, 0x97, 0xfc, 0x00}}},
|
|
+ {{{ 90, 47, -32}, 0, { 0, 0}, {0x3b, 0x50, 0xb2, 0x00}}},
|
|
+ {{{ 91, 46, 16}, 0, { 0, 0}, {0x35, 0x5c, 0x44, 0x00}}},
|
|
+ {{{ 12, 49, -37}, 0, { 0, 0}, {0xe5, 0x6e, 0xc9, 0x00}}},
|
|
+ {{{ 96, -5, 30}, 0, { 0, 0}, {0x51, 0xe7, 0x5d, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Gfx ghost_mario_right_thigh_shared_dl[] = {
|
|
+ gsSPVertex(ghost_mario_right_thigh_shared_dl_vertex_group1, 16, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 3, 4, 1, 0x0),
|
|
+ gsSP2Triangles( 3, 5, 4, 0x0, 6, 7, 5, 0x0),
|
|
+ gsSP2Triangles( 0, 2, 7, 0x0, 8, 9, 10, 0x0),
|
|
+ gsSP2Triangles( 1, 8, 2, 0x0, 2, 8, 7, 0x0),
|
|
+ gsSP2Triangles( 7, 11, 5, 0x0, 5, 11, 4, 0x0),
|
|
+ gsSP2Triangles( 4, 12, 1, 0x0, 13, 14, 0, 0x0),
|
|
+ gsSP2Triangles( 0, 14, 15, 0x0, 15, 14, 3, 0x0),
|
|
+ gsSP2Triangles( 3, 14, 6, 0x0, 6, 14, 13, 0x0),
|
|
+ gsSP2Triangles(10, 9, 11, 0x0, 11, 9, 12, 0x0),
|
|
+ gsSPVertex(ghost_mario_right_thigh_shared_dl_vertex_group2, 15, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 2, 1, 3, 0x0),
|
|
+ gsSP2Triangles( 0, 2, 4, 0x0, 5, 0, 6, 0x0),
|
|
+ gsSP2Triangles( 7, 8, 5, 0x0, 3, 8, 7, 0x0),
|
|
+ gsSP2Triangles( 4, 2, 3, 0x0, 7, 9, 10, 0x0),
|
|
+ gsSP2Triangles(11, 9, 7, 0x0, 12, 11, 13, 0x0),
|
|
+ gsSP2Triangles( 4, 14, 12, 0x0, 10, 14, 4, 0x0),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_right_leg_shared_dl_vertex_group1[] = {
|
|
+ {{{ 63, -45, -12}, 0, { 0, 0}, {0xf2, 0x9b, 0x4a, 0x00}}},
|
|
+ {{{ 66, -11, 34}, 0, { 0, 0}, {0xf2, 0x9b, 0x4a, 0x00}}},
|
|
+ {{{ 4, -36, -10}, 0, { 0, 0}, {0xc0, 0x93, 0xfe, 0x00}}},
|
|
+ {{{ 66, -11, 34}, 0, { 0, 0}, {0xfb, 0x22, 0x7a, 0x00}}},
|
|
+ {{{ 69, 45, 18}, 0, { 0, 0}, {0xfc, 0x22, 0x7a, 0x00}}},
|
|
+ {{{ 9, 44, 16}, 0, { 0, 0}, {0xc6, 0x4b, 0x53, 0x00}}},
|
|
+ {{{ 69, 45, 18}, 0, { 0, 0}, {0xff, 0x7f, 0x03, 0x00}}},
|
|
+ {{{ 69, 46, -37}, 0, { 0, 0}, {0xff, 0x7f, 0x03, 0x00}}},
|
|
+ {{{ 9, 46, -33}, 0, { 0, 0}, {0xcd, 0x60, 0xc0, 0x00}}},
|
|
+ {{{ 69, 46, -37}, 0, { 0, 0}, {0xf7, 0x27, 0x88, 0x00}}},
|
|
+ {{{ 65, -9, -56}, 0, { 0, 0}, {0xf8, 0x28, 0x88, 0x00}}},
|
|
+ {{{ 65, -9, -56}, 0, { 0, 0}, {0xef, 0xa0, 0xb0, 0x00}}},
|
|
+ {{{ 63, -45, -12}, 0, { 0, 0}, {0xef, 0xa0, 0xb0, 0x00}}},
|
|
+ {{{ 6, -6, 30}, 0, { 0, 0}, {0xb4, 0xe4, 0x61, 0x00}}},
|
|
+ {{{ -13, 10, -9}, 0, { 0, 0}, {0x82, 0x08, 0x02, 0x00}}},
|
|
+ {{{ 5, -3, -50}, 0, { 0, 0}, {0xb2, 0xea, 0xa0, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_right_leg_shared_dl_vertex_group2[] = {
|
|
+ {{{ 65, -9, -56}, 0, { 0, 0}, {0x75, 0xee, 0xd5, 0x00}}},
|
|
+ {{{ 83, 4, -10}, 0, { 0, 0}, {0x7e, 0xf9, 0xfe, 0x00}}},
|
|
+ {{{ 63, -45, -12}, 0, { 0, 0}, {0x75, 0xd1, 0xfd, 0x00}}},
|
|
+ {{{ 66, -11, 34}, 0, { 0, 0}, {0x77, 0xec, 0x26, 0x00}}},
|
|
+ {{{ 69, 45, 18}, 0, { 0, 0}, {0x7a, 0x18, 0x17, 0x00}}},
|
|
+ {{{ 69, 46, -37}, 0, { 0, 0}, {0x79, 0x19, 0xe6, 0x00}}},
|
|
+ {{{ 4, -36, -10}, 0, { 0, 0}, {0xc0, 0x93, 0xfe, 0x00}}},
|
|
+ {{{ 5, -3, -50}, 0, { 0, 0}, {0xb2, 0xea, 0xa0, 0x00}}},
|
|
+ {{{ 65, -9, -56}, 0, { 0, 0}, {0xef, 0xa0, 0xb0, 0x00}}},
|
|
+ {{{ 65, -9, -56}, 0, { 0, 0}, {0xf8, 0x28, 0x88, 0x00}}},
|
|
+ {{{ 9, 46, -33}, 0, { 0, 0}, {0xcd, 0x60, 0xc0, 0x00}}},
|
|
+ {{{ 9, 44, 16}, 0, { 0, 0}, {0xc6, 0x4b, 0x53, 0x00}}},
|
|
+ {{{ 69, 45, 18}, 0, { 0, 0}, {0xff, 0x7f, 0x03, 0x00}}},
|
|
+ {{{ 6, -6, 30}, 0, { 0, 0}, {0xb4, 0xe4, 0x61, 0x00}}},
|
|
+ {{{ 66, -11, 34}, 0, { 0, 0}, {0xfb, 0x22, 0x7a, 0x00}}},
|
|
+ {{{ 66, -11, 34}, 0, { 0, 0}, {0xf2, 0x9b, 0x4a, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Gfx ghost_mario_right_leg_shared_dl[] = {
|
|
+ gsSPVertex(ghost_mario_right_leg_shared_dl_vertex_group1, 16, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
|
+ gsSP2Triangles( 6, 7, 8, 0x0, 9, 10, 8, 0x0),
|
|
+ gsSP2Triangles(11, 12, 2, 0x0, 13, 14, 2, 0x0),
|
|
+ gsSP2Triangles( 2, 14, 15, 0x0, 15, 14, 8, 0x0),
|
|
+ gsSP2Triangles( 8, 14, 5, 0x0, 5, 14, 13, 0x0),
|
|
+ gsSPVertex(ghost_mario_right_leg_shared_dl_vertex_group2, 16, 0),
|
|
+ gsSP2Triangles( 0, 1, 2, 0x0, 2, 1, 3, 0x0),
|
|
+ gsSP2Triangles( 3, 1, 4, 0x0, 4, 1, 5, 0x0),
|
|
+ gsSP2Triangles( 5, 1, 0, 0x0, 6, 7, 8, 0x0),
|
|
+ gsSP2Triangles( 9, 7, 10, 0x0, 10, 11, 12, 0x0),
|
|
+ gsSP2Triangles(11, 13, 14, 0x0, 15, 13, 6, 0x0),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_right_foot_dl_vertex_group1[] = {
|
|
+ {{{ 27, -35, -11}, 0, { 0, 0}, {0xdc, 0x87, 0x06, 0x00}}},
|
|
+ {{{ -36, 11, 19}, 0, { 0, 0}, {0xb5, 0xd3, 0x5b, 0x00}}},
|
|
+ {{{ -54, 14, -10}, 0, { 0, 0}, {0x89, 0xd6, 0x03, 0x00}}},
|
|
+ {{{ -34, 11, -46}, 0, { 0, 0}, {0xb4, 0xd0, 0xa8, 0x00}}},
|
|
+ {{{ 43, -18, -55}, 0, { 0, 0}, {0x0a, 0xb2, 0x9d, 0x00}}},
|
|
+ {{{ 80, -29, -7}, 0, { 0, 0}, {0x36, 0x8e, 0x08, 0x00}}},
|
|
+ {{{ 44, -11, 32}, 0, { 0, 0}, {0x01, 0xb8, 0x68, 0x00}}},
|
|
+ {{{ -42, 64, -29}, 0, { 0, 0}, {0x90, 0x14, 0xc9, 0x00}}},
|
|
+ {{{ -40, 63, 5}, 0, { 0, 0}, {0x92, 0x15, 0x3b, 0x00}}},
|
|
+ {{{ -14, 54, 29}, 0, { 0, 0}, {0xd5, 0xfe, 0x77, 0x00}}},
|
|
+ {{{ -11, 53, -56}, 0, { 0, 0}, {0xda, 0xfe, 0x87, 0x00}}},
|
|
+ {{{ 110, 11, -36}, 0, { 0, 0}, {0x4e, 0xb0, 0xc6, 0x00}}},
|
|
+ {{{ 78, 22, -61}, 0, { 0, 0}, {0x17, 0xd9, 0x8a, 0x00}}},
|
|
+ {{{ 109, 11, 20}, 0, { 0, 0}, {0x45, 0xaf, 0x44, 0x00}}},
|
|
+ {{{ 75, 23, 40}, 0, { 0, 0}, {0x0b, 0xda, 0x78, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_right_foot_dl_vertex_group2[] = {
|
|
+ {{{ -42, 64, -29}, 0, { 0, 0}, {0x29, 0x77, 0x00, 0x00}}},
|
|
+ {{{ -40, 63, 5}, 0, { 0, 0}, {0x29, 0x77, 0x00, 0x00}}},
|
|
+ {{{ -11, 53, -56}, 0, { 0, 0}, {0x29, 0x77, 0x00, 0x00}}},
|
|
+ {{{ -14, 54, 29}, 0, { 0, 0}, {0x29, 0x77, 0x00, 0x00}}},
|
|
+ {{{ 78, 22, -61}, 0, { 0, 0}, {0x29, 0x77, 0x00, 0x00}}},
|
|
+ {{{ 75, 23, 40}, 0, { 0, 0}, {0x29, 0x77, 0x00, 0x00}}},
|
|
+ {{{ 110, 11, -36}, 0, { 0, 0}, {0x29, 0x77, 0x00, 0x00}}},
|
|
+ {{{ 109, 11, 20}, 0, { 0, 0}, {0x29, 0x77, 0x00, 0x00}}},
|
|
+};
|
|
+
|
|
+static const Gfx ghost_mario_right_foot[] = {
|
|
+ gsSPVertex(ghost_mario_right_foot_dl_vertex_group1, 15, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 2, 3, 0, 0x0),
|
|
+ gsSP2Triangles(3, 4, 0, 0x0, 0, 4, 5, 0x0),
|
|
+ gsSP2Triangles(0, 6, 1, 0x0, 5, 6, 0, 0x0),
|
|
+ gsSP2Triangles(3, 2, 7, 0x0, 8, 7, 2, 0x0),
|
|
+ gsSP2Triangles(1, 9, 8, 0x0, 2, 1, 8, 0x0),
|
|
+ gsSP2Triangles(7, 10, 3, 0x0, 11, 5, 4, 0x0),
|
|
+ gsSP2Triangles(4, 12, 11, 0x0, 6, 5, 13, 0x0),
|
|
+ gsSP2Triangles(11, 13, 5, 0x0, 13, 14, 6, 0x0),
|
|
+ gsSP2Triangles(14, 9, 6, 0x0, 10, 4, 3, 0x0),
|
|
+ gsSP2Triangles(9, 1, 6, 0x0, 10, 12, 4, 0x0),
|
|
+ gsSPVertex(ghost_mario_right_foot_dl_vertex_group2, 8, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 1, 3, 2, 0x0),
|
|
+ gsSP2Triangles(3, 4, 2, 0x0, 3, 5, 4, 0x0),
|
|
+ gsSP2Triangles(5, 6, 4, 0x0, 5, 7, 6, 0x0),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+//
|
|
+// Body
|
|
+//
|
|
+
|
|
+static const Vtx ghost_mario_gold_button_dl_vertex[] = {
|
|
+ {{{ 9, 89, 41}, 0, { 180, 962}, {0x14, 0x78, 0x23, 0xff}}},
|
|
+ {{{ 3, 77, 62}, 0, { 682, 966}, {0x04, 0x6a, 0x44, 0xff}}},
|
|
+ {{{ 47, 75, 35}, 0, { 34, 106}, {0x39, 0x6a, 0x26, 0xff}}},
|
|
+ {{{ 28, 85, 30}, 0, { -60, 572}, {0x2c, 0x76, 0x08, 0xff}}},
|
|
+ {{{ 17, 66, 76}, 0, { 966, 590}, {0x19, 0x58, 0x57, 0xff}}},
|
|
+ {{{ 32, 62, 74}, 0, { 902, 252}, {0x29, 0x53, 0x56, 0xff}}},
|
|
+ {{{ 48, 64, 59}, 0, { 548, 0}, {0x4d, 0x51, 0x3a, 0xff}}},
|
|
+ {{{ 9, 89, -40}, 0, { 776, 920}, {0x10, 0x7b, 0xe7, 0xff}}},
|
|
+ {{{ 28, 85, -29}, 0, { 990, 512}, {0x2d, 0x75, 0xf2, 0xff}}},
|
|
+ {{{ 47, 75, -34}, 0, { 850, 72}, {0x3e, 0x6a, 0xe2, 0xff}}},
|
|
+ {{{ 3, 77, -61}, 0, { 264, 972}, {0x03, 0x6a, 0xbb, 0xff}}},
|
|
+ {{{ 48, 64, -58}, 0, { 312, 0}, {0x4d, 0x50, 0xc5, 0xff}}},
|
|
+ {{{ 32, 62, -73}, 0, { -24, 310}, {0x29, 0x52, 0xa9, 0xff}}},
|
|
+ {{{ 17, 66, -75}, 0, { -58, 642}, {0x17, 0x58, 0xa8, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_tshirt_shared_dl_vertex_group1[] = {
|
|
+ {{{ 47, 75, -34}, 0, { 0, 0}, {0x3e, 0x6a, 0xe2, 0xff}}},
|
|
+ {{{ 47, 75, 35}, 0, { 0, 0}, {0x39, 0x6a, 0x26, 0xff}}},
|
|
+ {{{ 82, 37, 27}, 0, { 0, 0}, {0x66, 0x48, 0x14, 0xff}}},
|
|
+ {{{ 82, 37, -26}, 0, { 0, 0}, {0x69, 0x43, 0xec, 0xff}}},
|
|
+ {{{ 100, 1, 24}, 0, { 0, 0}, {0x7a, 0x17, 0x16, 0xff}}},
|
|
+ {{{ 100, 1, -23}, 0, { 0, 0}, {0x7c, 0x09, 0xea, 0xff}}},
|
|
+ {{{ 6, -10, -92}, 0, { 0, 0}, {0x00, 0xeb, 0x83, 0xff}}},
|
|
+ {{{ 47, 3, -88}, 0, { 0, 0}, {0x30, 0x09, 0x8b, 0xff}}},
|
|
+ {{{ 46, -34, -83}, 0, { 0, 0}, {0x24, 0xc8, 0x95, 0xff}}},
|
|
+ {{{ 12, 33, -90}, 0, { 0, 0}, {0x11, 0x20, 0x87, 0xff}}},
|
|
+ {{{ 20, -61, -67}, 0, { 0, 0}, {0x0a, 0x9a, 0xb7, 0xff}}},
|
|
+ {{{ 66, -52, -50}, 0, { 0, 0}, {0x3b, 0x9a, 0xd3, 0xff}}},
|
|
+ {{{ 84, -29, -62}, 0, { 0, 0}, {0x5f, 0xde, 0xb4, 0xff}}},
|
|
+ {{{ 20, -61, 68}, 0, { 0, 0}, {0x0a, 0x99, 0x49, 0xff}}},
|
|
+ {{{ 66, -52, 51}, 0, { 0, 0}, {0x3b, 0x9a, 0x2d, 0xff}}},
|
|
+ {{{ 46, -34, 84}, 0, { 0, 0}, {0x24, 0xc8, 0x6b, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_tshirt_shared_dl_vertex_group2[] = {
|
|
+ {{{ 20, -61, 68}, 0, { 0, 0}, {0x0a, 0x99, 0x49, 0xff}}},
|
|
+ {{{ 46, -34, 84}, 0, { 0, 0}, {0x24, 0xc8, 0x6b, 0xff}}},
|
|
+ {{{ 6, -11, 93}, 0, { 0, 0}, {0x00, 0xea, 0x7c, 0xff}}},
|
|
+ {{{ 47, 3, 89}, 0, { 0, 0}, {0x30, 0x08, 0x75, 0xff}}},
|
|
+ {{{ 84, -29, 63}, 0, { 0, 0}, {0x5f, 0xde, 0x4c, 0xff}}},
|
|
+ {{{ 66, -52, 51}, 0, { 0, 0}, {0x3b, 0x9a, 0x2d, 0xff}}},
|
|
+ {{{ 13, 33, 91}, 0, { 0, 0}, {0x12, 0x20, 0x79, 0xff}}},
|
|
+ {{{ 100, 1, -23}, 0, { 0, 0}, {0x7c, 0x09, 0xea, 0xff}}},
|
|
+ {{{ 100, 1, 24}, 0, { 0, 0}, {0x7a, 0x17, 0x16, 0xff}}},
|
|
+ {{{ 93, -36, 26}, 0, { 0, 0}, {0x6b, 0xbf, 0x0d, 0xff}}},
|
|
+ {{{ 93, -36, -25}, 0, { 0, 0}, {0x66, 0xb7, 0xf0, 0xff}}},
|
|
+ {{{ 54, -63, 0}, 0, { 0, 0}, {0x30, 0x8b, 0x00, 0xff}}},
|
|
+ {{{ 80, 14, 62}, 0, { 0, 0}, {0x60, 0x28, 0x47, 0xff}}},
|
|
+ {{{ 44, 51, 75}, 0, { 0, 0}, {0x3c, 0x34, 0x62, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_tshirt_shared_dl_vertex_group3[] = {
|
|
+ {{{ 80, 14, -61}, 0, { 0, 0}, {0x60, 0x28, 0xb8, 0xff}}},
|
|
+ {{{ 47, 3, -88}, 0, { 0, 0}, {0x30, 0x09, 0x8b, 0xff}}},
|
|
+ {{{ 43, 51, -74}, 0, { 0, 0}, {0x3c, 0x32, 0x9d, 0xff}}},
|
|
+ {{{ 84, -29, -62}, 0, { 0, 0}, {0x5f, 0xde, 0xb4, 0xff}}},
|
|
+ {{{ 12, 33, -90}, 0, { 0, 0}, {0x11, 0x20, 0x87, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_pants_overalls_shared_dl_vertex_group1[] = {
|
|
+ {{{ 47, 75, -34}, 0, { 0, 0}, {0x3e, 0x6a, 0xe2, 0xff}}},
|
|
+ {{{ 28, 85, 30}, 0, { 0, 0}, {0x2c, 0x76, 0x08, 0xff}}},
|
|
+ {{{ 47, 75, 35}, 0, { 0, 0}, {0x39, 0x6a, 0x26, 0xff}}},
|
|
+ {{{ 28, 85, -29}, 0, { 0, 0}, {0x2d, 0x75, 0xf2, 0xff}}},
|
|
+ {{{ 9, 89, 41}, 0, { 0, 0}, {0x14, 0x78, 0x23, 0xff}}},
|
|
+ {{{ 9, 89, -40}, 0, { 0, 0}, {0x10, 0x7b, 0xe7, 0xff}}},
|
|
+ {{{ -15, 88, 35}, 0, { 0, 0}, {0xec, 0x7a, 0x1c, 0xff}}},
|
|
+ {{{ -15, 87, -35}, 0, { 0, 0}, {0xea, 0x76, 0xda, 0xff}}},
|
|
+ {{{ 3, 77, -61}, 0, { 0, 0}, {0x03, 0x6a, 0xbb, 0xff}}},
|
|
+ {{{ -43, 83, -24}, 0, { 0, 0}, {0xcc, 0x72, 0xee, 0xff}}},
|
|
+ {{{ -28, 63, -74}, 0, { 0, 0}, {0xd1, 0x4f, 0xaa, 0xff}}},
|
|
+ {{{ -40, 72, -54}, 0, { 0, 0}, {0xc5, 0x5f, 0xc6, 0xff}}},
|
|
+ {{{ -40, 72, 55}, 0, { 0, 0}, {0xc4, 0x5e, 0x3a, 0xff}}},
|
|
+ {{{ -43, 83, 25}, 0, { 0, 0}, {0xbc, 0x69, 0x11, 0xff}}},
|
|
+ {{{ -28, 63, 75}, 0, { 0, 0}, {0xd0, 0x50, 0x55, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_pants_overalls_shared_dl_vertex_group2[] = {
|
|
+ {{{ 80, 14, -61}, 0, { 0, 0}, {0x60, 0x28, 0xb8, 0xff}}},
|
|
+ {{{ 43, 51, -74}, 0, { 0, 0}, {0x3c, 0x32, 0x9d, 0xff}}},
|
|
+ {{{ 48, 64, -58}, 0, { 0, 0}, {0x4d, 0x50, 0xc5, 0xff}}},
|
|
+ {{{ 3, 77, 62}, 0, { 0, 0}, {0x04, 0x6a, 0x44, 0xff}}},
|
|
+ {{{ 9, 89, 41}, 0, { 0, 0}, {0x14, 0x78, 0x23, 0xff}}},
|
|
+ {{{ -15, 88, 35}, 0, { 0, 0}, {0xec, 0x7a, 0x1c, 0xff}}},
|
|
+ {{{ 47, 75, 35}, 0, { 0, 0}, {0x39, 0x6a, 0x26, 0xff}}},
|
|
+ {{{ 48, 64, 59}, 0, { 0, 0}, {0x4d, 0x51, 0x3a, 0xff}}},
|
|
+ {{{ 82, 37, 27}, 0, { 0, 0}, {0x66, 0x48, 0x14, 0xff}}},
|
|
+ {{{ 32, 62, 74}, 0, { 0, 0}, {0x29, 0x53, 0x56, 0xff}}},
|
|
+ {{{ 44, 51, 75}, 0, { 0, 0}, {0x3c, 0x34, 0x62, 0xff}}},
|
|
+ {{{ 80, 14, 62}, 0, { 0, 0}, {0x60, 0x28, 0x47, 0xff}}},
|
|
+ {{{ 100, 1, 24}, 0, { 0, 0}, {0x7a, 0x17, 0x16, 0xff}}},
|
|
+ {{{ 82, 37, -26}, 0, { 0, 0}, {0x69, 0x43, 0xec, 0xff}}},
|
|
+ {{{ 32, 62, -73}, 0, { 0, 0}, {0x29, 0x52, 0xa9, 0xff}}},
|
|
+ {{{ 47, 75, -34}, 0, { 0, 0}, {0x3e, 0x6a, 0xe2, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_pants_overalls_shared_dl_vertex_group3[] = {
|
|
+ {{{ 80, 14, -61}, 0, { 0, 0}, {0x60, 0x28, 0xb8, 0xff}}},
|
|
+ {{{ 82, 37, -26}, 0, { 0, 0}, {0x69, 0x43, 0xec, 0xff}}},
|
|
+ {{{ 100, 1, -23}, 0, { 0, 0}, {0x7c, 0x09, 0xea, 0xff}}},
|
|
+ {{{ 20, -61, -67}, 0, { 0, 0}, {0x0a, 0x9a, 0xb7, 0xff}}},
|
|
+ {{{ 66, -52, -50}, 0, { 0, 0}, {0x3b, 0x9a, 0xd3, 0xff}}},
|
|
+ {{{ 54, -63, 0}, 0, { 0, 0}, {0x30, 0x8b, 0x00, 0xff}}},
|
|
+ {{{ -27, -25, -86}, 0, { 0, 0}, {0xcb, 0xd5, 0x96, 0xff}}},
|
|
+ {{{ 6, -10, -92}, 0, { 0, 0}, {0x00, 0xeb, 0x83, 0xff}}},
|
|
+ {{{ -29, -58, -59}, 0, { 0, 0}, {0xc9, 0x9a, 0xcf, 0xff}}},
|
|
+ {{{ 8, -74, 0}, 0, { 0, 0}, {0xfd, 0x82, 0x00, 0xff}}},
|
|
+ {{{ -59, -28, -37}, 0, { 0, 0}, {0x90, 0xd5, 0xd9, 0xff}}},
|
|
+ {{{ -30, -66, 0}, 0, { 0, 0}, {0xb8, 0x98, 0x00, 0xff}}},
|
|
+ {{{ -27, 26, -89}, 0, { 0, 0}, {0xc7, 0x0f, 0x90, 0xff}}},
|
|
+ {{{ 12, 33, -90}, 0, { 0, 0}, {0x11, 0x20, 0x87, 0xff}}},
|
|
+ {{{ 20, -61, 68}, 0, { 0, 0}, {0x0a, 0x99, 0x49, 0xff}}},
|
|
+ {{{ 66, -52, 51}, 0, { 0, 0}, {0x3b, 0x9a, 0x2d, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_pants_overalls_shared_dl_vertex_group4[] = {
|
|
+ {{{ 8, -74, 0}, 0, { 0, 0}, {0xfd, 0x82, 0x00, 0xff}}},
|
|
+ {{{ 20, -61, 68}, 0, { 0, 0}, {0x0a, 0x99, 0x49, 0xff}}},
|
|
+ {{{ -29, -58, 59}, 0, { 0, 0}, {0xc8, 0x99, 0x30, 0xff}}},
|
|
+ {{{ -27, -25, 87}, 0, { 0, 0}, {0xcb, 0xd3, 0x69, 0xff}}},
|
|
+ {{{ 6, -11, 93}, 0, { 0, 0}, {0x00, 0xea, 0x7c, 0xff}}},
|
|
+ {{{ -27, 26, 91}, 0, { 0, 0}, {0xc8, 0x0e, 0x70, 0xff}}},
|
|
+ {{{ 13, 33, 91}, 0, { 0, 0}, {0x12, 0x20, 0x79, 0xff}}},
|
|
+ {{{ -59, -28, 38}, 0, { 0, 0}, {0x8d, 0xd8, 0x21, 0xff}}},
|
|
+ {{{ -30, -66, 0}, 0, { 0, 0}, {0xb8, 0x98, 0x00, 0xff}}},
|
|
+ {{{ -28, 63, -74}, 0, { 0, 0}, {0xd1, 0x4f, 0xaa, 0xff}}},
|
|
+ {{{ -27, 26, -89}, 0, { 0, 0}, {0xc7, 0x0f, 0x90, 0xff}}},
|
|
+ {{{ -71, 54, -29}, 0, { 0, 0}, {0x8f, 0x2a, 0xda, 0xff}}},
|
|
+ {{{ -59, -28, -37}, 0, { 0, 0}, {0x90, 0xd5, 0xd9, 0xff}}},
|
|
+ {{{ -71, 54, 30}, 0, { 0, 0}, {0x94, 0x2a, 0x31, 0xff}}},
|
|
+ {{{ -43, 83, 25}, 0, { 0, 0}, {0xbc, 0x69, 0x11, 0xff}}},
|
|
+ {{{ -43, 83, -24}, 0, { 0, 0}, {0xcc, 0x72, 0xee, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_pants_overalls_shared_dl_vertex_group5[] = {
|
|
+ {{{ -71, 54, -29}, 0, { 0, 0}, {0x8f, 0x2a, 0xda, 0xff}}},
|
|
+ {{{ -43, 83, -24}, 0, { 0, 0}, {0xcc, 0x72, 0xee, 0xff}}},
|
|
+ {{{ -40, 72, -54}, 0, { 0, 0}, {0xc5, 0x5f, 0xc6, 0xff}}},
|
|
+ {{{ -59, -28, -37}, 0, { 0, 0}, {0x90, 0xd5, 0xd9, 0xff}}},
|
|
+ {{{ -59, -28, 38}, 0, { 0, 0}, {0x8d, 0xd8, 0x21, 0xff}}},
|
|
+ {{{ -28, 63, -74}, 0, { 0, 0}, {0xd1, 0x4f, 0xaa, 0xff}}},
|
|
+ {{{ -43, 83, 25}, 0, { 0, 0}, {0xbc, 0x69, 0x11, 0xff}}},
|
|
+ {{{ -71, 54, 30}, 0, { 0, 0}, {0x94, 0x2a, 0x31, 0xff}}},
|
|
+ {{{ -30, -66, 0}, 0, { 0, 0}, {0xb8, 0x98, 0x00, 0xff}}},
|
|
+ {{{ -27, 26, 91}, 0, { 0, 0}, {0xc8, 0x0e, 0x70, 0xff}}},
|
|
+ {{{ -28, 63, 75}, 0, { 0, 0}, {0xd0, 0x50, 0x55, 0xff}}},
|
|
+ {{{ -40, 72, 55}, 0, { 0, 0}, {0xc4, 0x5e, 0x3a, 0xff}}},
|
|
+ {{{ 13, 33, 91}, 0, { 0, 0}, {0x12, 0x20, 0x79, 0xff}}},
|
|
+ {{{ -4, 58, 84}, 0, { 0, 0}, {0xfb, 0x43, 0x6b, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_pants_overalls_shared_dl_vertex_group6[] = {
|
|
+ {{{ -27, 26, -89}, 0, { 0, 0}, {0xc7, 0x0f, 0x90, 0xff}}},
|
|
+ {{{ -4, 58, -82}, 0, { 0, 0}, {0xf9, 0x42, 0x94, 0xff}}},
|
|
+ {{{ 12, 33, -90}, 0, { 0, 0}, {0x11, 0x20, 0x87, 0xff}}},
|
|
+ {{{ -28, 63, -74}, 0, { 0, 0}, {0xd1, 0x4f, 0xaa, 0xff}}},
|
|
+ {{{ 80, 14, -61}, 0, { 0, 0}, {0x60, 0x28, 0xb8, 0xff}}},
|
|
+ {{{ 100, 1, -23}, 0, { 0, 0}, {0x7c, 0x09, 0xea, 0xff}}},
|
|
+ {{{ 84, -29, -62}, 0, { 0, 0}, {0x5f, 0xde, 0xb4, 0xff}}},
|
|
+ {{{ 93, -36, -25}, 0, { 0, 0}, {0x66, 0xb7, 0xf0, 0xff}}},
|
|
+ {{{ 66, -52, -50}, 0, { 0, 0}, {0x3b, 0x9a, 0xd3, 0xff}}},
|
|
+ {{{ 54, -63, 0}, 0, { 0, 0}, {0x30, 0x8b, 0x00, 0xff}}},
|
|
+ {{{ 66, -52, 51}, 0, { 0, 0}, {0x3b, 0x9a, 0x2d, 0xff}}},
|
|
+ {{{ 93, -36, 26}, 0, { 0, 0}, {0x6b, 0xbf, 0x0d, 0xff}}},
|
|
+ {{{ 84, -29, 63}, 0, { 0, 0}, {0x5f, 0xde, 0x4c, 0xff}}},
|
|
+ {{{ 100, 1, 24}, 0, { 0, 0}, {0x7a, 0x17, 0x16, 0xff}}},
|
|
+ {{{ 80, 14, 62}, 0, { 0, 0}, {0x60, 0x28, 0x47, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_pants_overalls_shared_dl_vertex_group7[] = {
|
|
+ {{{ 17, 66, -75}, 0, { 0, 0}, {0x17, 0x58, 0xa8, 0xff}}},
|
|
+ {{{ -4, 58, -82}, 0, { 0, 0}, {0xf9, 0x42, 0x94, 0xff}}},
|
|
+ {{{ 3, 77, -61}, 0, { 0, 0}, {0x03, 0x6a, 0xbb, 0xff}}},
|
|
+ {{{ -28, 63, -74}, 0, { 0, 0}, {0xd1, 0x4f, 0xaa, 0xff}}},
|
|
+ {{{ 32, 62, 74}, 0, { 0, 0}, {0x29, 0x53, 0x56, 0xff}}},
|
|
+ {{{ 17, 66, 76}, 0, { 0, 0}, {0x19, 0x58, 0x57, 0xff}}},
|
|
+ {{{ 13, 33, 91}, 0, { 0, 0}, {0x12, 0x20, 0x79, 0xff}}},
|
|
+ {{{ -28, 63, 75}, 0, { 0, 0}, {0xd0, 0x50, 0x55, 0xff}}},
|
|
+ {{{ -4, 58, 84}, 0, { 0, 0}, {0xfb, 0x43, 0x6b, 0xff}}},
|
|
+ {{{ 3, 77, 62}, 0, { 0, 0}, {0x04, 0x6a, 0x44, 0xff}}},
|
|
+ {{{ -15, 88, 35}, 0, { 0, 0}, {0xec, 0x7a, 0x1c, 0xff}}},
|
|
+ {{{ 12, 33, -90}, 0, { 0, 0}, {0x11, 0x20, 0x87, 0xff}}},
|
|
+ {{{ 32, 62, -73}, 0, { 0, 0}, {0x29, 0x52, 0xa9, 0xff}}},
|
|
+ {{{ 43, 51, -74}, 0, { 0, 0}, {0x3c, 0x32, 0x9d, 0xff}}},
|
|
+ {{{ 44, 51, 75}, 0, { 0, 0}, {0x3c, 0x34, 0x62, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Gfx ghost_mario_torso_shared_dl[] = {
|
|
+ gsSPVertex(ghost_mario_gold_button_dl_vertex, 14, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 2, 3, 0, 0x0),
|
|
+ gsSP2Triangles(1, 4, 2, 0x0, 5, 6, 2, 0x0),
|
|
+ gsSP2Triangles(4, 5, 2, 0x0, 7, 8, 9, 0x0),
|
|
+ gsSP2Triangles(10, 7, 9, 0x0, 9, 11, 12, 0x0),
|
|
+ gsSP2Triangles(12, 13, 9, 0x0, 13, 10, 9, 0x0),
|
|
+ gsSPVertex(ghost_mario_pants_overalls_shared_dl_vertex_group1, 15, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 0, 3, 1, 0x0),
|
|
+ gsSP2Triangles(4, 1, 5, 0x0, 1, 3, 5, 0x0),
|
|
+ gsSP2Triangles(4, 5, 6, 0x0, 5, 7, 6, 0x0),
|
|
+ gsSP2Triangles(7, 5, 8, 0x0, 9, 6, 7, 0x0),
|
|
+ gsSP2Triangles(7, 8, 10, 0x0, 10, 11, 7, 0x0),
|
|
+ gsSP2Triangles(9, 7, 11, 0x0, 12, 6, 13, 0x0),
|
|
+ gsSP2Triangles(9, 13, 6, 0x0, 6, 12, 14, 0x0),
|
|
+ gsSPVertex(ghost_mario_pants_overalls_shared_dl_vertex_group2, 16, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
|
+ gsSP2Triangles(6, 7, 8, 0x0, 9, 10, 7, 0x0),
|
|
+ gsSP2Triangles(7, 10, 11, 0x0, 11, 8, 7, 0x0),
|
|
+ gsSP2Triangles(12, 8, 11, 0x0, 13, 0, 2, 0x0),
|
|
+ gsSP2Triangles(2, 1, 14, 0x0, 2, 15, 13, 0x0),
|
|
+ gsSPVertex(ghost_mario_pants_overalls_shared_dl_vertex_group3, 16, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
|
+ gsSP2Triangles(3, 6, 7, 0x0, 3, 8, 6, 0x0),
|
|
+ gsSP2Triangles(5, 9, 3, 0x0, 8, 3, 9, 0x0),
|
|
+ gsSP2Triangles(6, 8, 10, 0x0, 11, 10, 8, 0x0),
|
|
+ gsSP2Triangles(9, 11, 8, 0x0, 6, 12, 7, 0x0),
|
|
+ gsSP2Triangles(12, 6, 10, 0x0, 7, 12, 13, 0x0),
|
|
+ gsSP2Triangles(14, 5, 15, 0x0, 14, 9, 5, 0x0),
|
|
+ gsSPVertex(ghost_mario_pants_overalls_shared_dl_vertex_group4, 16, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 2, 1, 3, 0x0),
|
|
+ gsSP2Triangles(1, 4, 3, 0x0, 5, 4, 6, 0x0),
|
|
+ gsSP2Triangles(4, 5, 3, 0x0, 2, 3, 7, 0x0),
|
|
+ gsSP2Triangles(7, 3, 5, 0x0, 8, 2, 7, 0x0),
|
|
+ gsSP2Triangles(2, 8, 0, 0x0, 9, 10, 11, 0x0),
|
|
+ gsSP2Triangles(12, 11, 10, 0x0, 11, 7, 13, 0x0),
|
|
+ gsSP1Triangle(14, 15, 11, 0x0),
|
|
+ gsSPVertex(ghost_mario_pants_overalls_shared_dl_vertex_group5, 14, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 0, 3, 4, 0x0),
|
|
+ gsSP2Triangles(2, 5, 0, 0x0, 6, 0, 7, 0x0),
|
|
+ gsSP2Triangles(4, 3, 8, 0x0, 9, 7, 4, 0x0),
|
|
+ gsSP2Triangles(7, 10, 11, 0x0, 11, 6, 7, 0x0),
|
|
+ gsSP2Triangles(9, 12, 13, 0x0, 10, 9, 13, 0x0),
|
|
+ gsSP1Triangle(7, 9, 10, 0x0),
|
|
+ gsSPVertex(ghost_mario_pants_overalls_shared_dl_vertex_group6, 15, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 0, 3, 1, 0x0),
|
|
+ gsSP2Triangles(4, 5, 6, 0x0, 5, 7, 6, 0x0),
|
|
+ gsSP2Triangles(6, 7, 8, 0x0, 9, 8, 7, 0x0),
|
|
+ gsSP2Triangles(10, 11, 12, 0x0, 12, 11, 13, 0x0),
|
|
+ gsSP2Triangles(14, 12, 13, 0x0, 11, 10, 9, 0x0),
|
|
+ gsSPVertex(ghost_mario_pants_overalls_shared_dl_vertex_group7, 15, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 2, 1, 0x0),
|
|
+ gsSP2Triangles(4, 5, 6, 0x0, 7, 8, 9, 0x0),
|
|
+ gsSP2Triangles(10, 7, 9, 0x0, 9, 8, 5, 0x0),
|
|
+ gsSP2Triangles(5, 8, 6, 0x0, 11, 1, 0, 0x0),
|
|
+ gsSP2Triangles(11, 12, 13, 0x0, 6, 14, 4, 0x0),
|
|
+ gsSP1Triangle(11, 0, 12, 0x0),
|
|
+ gsSPVertex(ghost_mario_tshirt_shared_dl_vertex_group1, 16, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 0, 2, 3, 0x0),
|
|
+ gsSP2Triangles(4, 3, 2, 0x0, 4, 5, 3, 0x0),
|
|
+ gsSP2Triangles(6, 7, 8, 0x0, 6, 9, 7, 0x0),
|
|
+ gsSP2Triangles(6, 8, 10, 0x0, 11, 8, 12, 0x0),
|
|
+ gsSP2Triangles(12, 8, 7, 0x0, 8, 11, 10, 0x0),
|
|
+ gsSP1Triangle(13, 14, 15, 0x0),
|
|
+ gsSPVertex(ghost_mario_tshirt_shared_dl_vertex_group2, 14, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 1, 3, 2, 0x0),
|
|
+ gsSP2Triangles(3, 1, 4, 0x0, 4, 1, 5, 0x0),
|
|
+ gsSP2Triangles(6, 2, 3, 0x0, 7, 8, 9, 0x0),
|
|
+ gsSP2Triangles(7, 9, 10, 0x0, 11, 10, 9, 0x0),
|
|
+ gsSP2Triangles(12, 3, 4, 0x0, 13, 3, 12, 0x0),
|
|
+ gsSP1Triangle(6, 3, 13, 0x0),
|
|
+ gsSPVertex(ghost_mario_tshirt_shared_dl_vertex_group3, 5, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 1, 0, 0x0),
|
|
+ gsSP1Triangle(1, 4, 2, 0x0),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+//
|
|
+// Head
|
|
+//
|
|
+
|
|
+static const Vtx ghost_mario_m_logo_dl_vertex[] = {
|
|
+ {{{ 195, 93, 32}, 0, { 744, 732}, {0x51, 0x54, 0x30, 0xff}}},
|
|
+ {{{ 153, 33, 95}, 0, { 1250, 1066}, {0x04, 0x46, 0x69, 0xff}}},
|
|
+ {{{ 252, 62, 70}, 0, { 1032, 152}, {0x39, 0x4a, 0x55, 0xff}}},
|
|
+ {{{ 272, 85, 0}, 0, { 472, -16}, {0x5f, 0x54, 0x00, 0xff}}},
|
|
+ {{{ 252, 62, -69}, 0, { -78, 158}, {0x39, 0x4a, 0xab, 0xff}}},
|
|
+ {{{ 195, 93, -31}, 0, { 232, 736}, {0x51, 0x54, 0xcf, 0xff}}},
|
|
+ {{{ 153, 33, -94}, 0, { -258, 1076}, {0x03, 0x46, 0x97, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_eyes_cap_on_dl_vertex[] = {
|
|
+ {{{ 145, 101, 0}, 0, { 480, 446}, {0x13, 0x7d, 0x00, 0xff}}},
|
|
+ {{{ 108, 105, 0}, 0, { 488, 854}, {0x69, 0x46, 0x00, 0xff}}},
|
|
+ {{{ 97, 103, 25}, 0, { 724, 958}, {0x40, 0x5a, 0x3d, 0xff}}},
|
|
+ {{{ 97, 103, -24}, 0, { 256, 970}, {0x40, 0x5a, 0xc3, 0xff}}},
|
|
+ {{{ 175, 91, -38}, 0, { 106, 130}, {0xc6, 0x6d, 0xe7, 0xff}}},
|
|
+ {{{ 144, 83, -66}, 0, { -146, 460}, {0x19, 0x5b, 0xad, 0xff}}},
|
|
+ {{{ 104, 87, -69}, 0, { -160, 898}, {0x30, 0x5c, 0xb7, 0xff}}},
|
|
+ {{{ 175, 91, 39}, 0, { 842, 112}, {0xc6, 0x6d, 0x19, 0xff}}},
|
|
+ {{{ 153, 33, -94}, 0, { -404, 342}, {0x03, 0x46, 0x97, 0xff}}},
|
|
+ {{{ 104, 87, 70}, 0, { 1138, 864}, {0x30, 0x5c, 0x49, 0xff}}},
|
|
+ {{{ 144, 83, 67}, 0, { 1108, 428}, {0x19, 0x5b, 0x53, 0xff}}},
|
|
+ {{{ 153, 33, 95}, 0, { 1362, 296}, {0x04, 0x46, 0x69, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_hair_sideburn_cap_on_dl_vertex[] = {
|
|
+ {{{ 120, -12, -109}, 0, { 916, 184}, {0xed, 0x24, 0x88, 0xff}}},
|
|
+ {{{ 96, 49, -93}, 0, { -70, 700}, {0x11, 0x27, 0x89, 0xff}}},
|
|
+ {{{ 153, 33, -94}, 0, { 90, -58}, {0x03, 0x46, 0x97, 0xff}}},
|
|
+ {{{ 85, -23, -110}, 0, { 1150, 582}, {0x06, 0x59, 0xa6, 0xff}}},
|
|
+ {{{ 42, 0, -102}, 0, { 842, 1210}, {0xc3, 0x05, 0x92, 0xff}}},
|
|
+ {{{ 44, 44, -96}, 0, { 118, 1334}, {0xda, 0x21, 0x8c, 0xff}}},
|
|
+ {{{ 96, 49, 94}, 0, { -74, 726}, {0x10, 0x28, 0x77, 0xff}}},
|
|
+ {{{ 44, 44, 97}, 0, { 196, 1366}, {0xda, 0x21, 0x74, 0xff}}},
|
|
+ {{{ 42, 0, 103}, 0, { 968, 1192}, {0xc3, 0x05, 0x6e, 0xff}}},
|
|
+ {{{ 85, -23, 111}, 0, { 1238, 518}, {0x04, 0x58, 0x5a, 0xff}}},
|
|
+ {{{ 120, -11, 111}, 0, { 922, 122}, {0xed, 0x24, 0x78, 0xff}}},
|
|
+ {{{ 153, 33, 95}, 0, { 22, -68}, {0x04, 0x46, 0x69, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_mustache_cap_on_dl_vertex_group1[] = {
|
|
+ {{{ 77, 108, 34}, 0, { 342, 368}, {0x0e, 0x16, 0x7c, 0xff}}},
|
|
+ {{{ 92, 88, 84}, 0, { 898, -18}, {0x23, 0x59, 0x53, 0xff}}},
|
|
+ {{{ 97, 103, 25}, 0, { 224, 146}, {0x40, 0x5a, 0x3d, 0xff}}},
|
|
+ {{{ 48, 94, 76}, 0, { 888, 564}, {0xd7, 0x60, 0x47, 0xff}}},
|
|
+ {{{ 52, 111, 31}, 0, { 354, 690}, {0xa8, 0x33, 0x4b, 0xff}}},
|
|
+ {{{ 27, 100, 30}, 0, { 442, 982}, {0xb1, 0x60, 0x16, 0xff}}},
|
|
+ {{{ 41, 109, 0}, 0, { 70, 924}, {0x95, 0x44, 0x00, 0xff}}},
|
|
+ {{{ 44, 44, 97}, 0, { 1296, 438}, {0xda, 0x21, 0x74, 0xff}}},
|
|
+ {{{ 3, 54, 52}, 0, { 892, 1090}, {0x95, 0x1d, 0x3c, 0xff}}},
|
|
+ {{{ 52, 111, -30}, 0, { 340, 684}, {0xa8, 0x32, 0xb5, 0xff}}},
|
|
+ {{{ 48, 94, -75}, 0, { 856, 608}, {0xd7, 0x60, 0xb9, 0xff}}},
|
|
+ {{{ 27, 100, -29}, 0, { 394, 998}, {0xb1, 0x60, 0xea, 0xff}}},
|
|
+ {{{ 3, 54, -51}, 0, { 806, 1162}, {0x95, 0x1d, 0xc4, 0xff}}},
|
|
+ {{{ 44, 44, -96}, 0, { 1250, 518}, {0xda, 0x21, 0x8c, 0xff}}},
|
|
+ {{{ 77, 108, -33}, 0, { 362, 344}, {0x0e, 0x16, 0x84, 0xff}}},
|
|
+ {{{ 41, 109, 0}, 0, { 50, 900}, {0x95, 0x44, 0x00, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_mustache_cap_on_dl_vertex_group2[] = {
|
|
+ {{{ 48, 94, -75}, 0, { 856, 608}, {0xd7, 0x60, 0xb9, 0xff}}},
|
|
+ {{{ 77, 108, -33}, 0, { 362, 344}, {0x0e, 0x16, 0x84, 0xff}}},
|
|
+ {{{ 92, 88, -83}, 0, { 922, -4}, {0x23, 0x59, 0xad, 0xff}}},
|
|
+ {{{ 97, 103, -24}, 0, { 274, 100}, {0x40, 0x5a, 0xc3, 0xff}}},
|
|
+ {{{ 44, 44, -96}, 0, { 1250, 518}, {0xda, 0x21, 0x8c, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_face_cap_dl_vertex_group1[] = {
|
|
+ {{{ 164, -89, -74}, 0, { 0, 0}, {0x51, 0xa9, 0xd5, 0xff}}},
|
|
+ {{{ 122, -139, -48}, 0, { 0, 0}, {0x28, 0x94, 0xcd, 0xff}}},
|
|
+ {{{ 131, -56, -123}, 0, { 0, 0}, {0xde, 0xd4, 0x8f, 0xff}}},
|
|
+ {{{ 187, -6, -133}, 0, { 0, 0}, {0x1e, 0x04, 0x85, 0xff}}},
|
|
+ {{{ 120, -12, -109}, 0, { 0, 0}, {0xed, 0x24, 0x88, 0xff}}},
|
|
+ {{{ 91, -54, -85}, 0, { 0, 0}, {0xd9, 0xb0, 0xa7, 0xff}}},
|
|
+ {{{ 77, -138, -50}, 0, { 0, 0}, {0xbc, 0x9e, 0xd8, 0xff}}},
|
|
+ {{{ 64, -103, -51}, 0, { 0, 0}, {0xde, 0x94, 0xc7, 0xff}}},
|
|
+ {{{ 122, -139, 49}, 0, { 0, 0}, {0x2d, 0x8f, 0x22, 0xff}}},
|
|
+ {{{ 77, -138, 51}, 0, { 0, 0}, {0xc1, 0xa4, 0x3c, 0xff}}},
|
|
+ {{{ 64, -103, 52}, 0, { 0, 0}, {0xc9, 0x9a, 0x31, 0xff}}},
|
|
+ {{{ 131, -56, 124}, 0, { 0, 0}, {0xdf, 0xd3, 0x71, 0xff}}},
|
|
+ {{{ 164, -89, 75}, 0, { 0, 0}, {0x4e, 0xa6, 0x2b, 0xff}}},
|
|
+ {{{ 91, -54, 86}, 0, { 0, 0}, {0xd9, 0xaf, 0x59, 0xff}}},
|
|
+ {{{ 187, -6, 134}, 0, { 0, 0}, {0x1f, 0x04, 0x7a, 0xff}}},
|
|
+ {{{ 120, -11, 111}, 0, { 0, 0}, {0xed, 0x24, 0x78, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_face_cap_dl_vertex_group2[] = {
|
|
+ {{{ 153, 33, -94}, 0, { 0, 0}, {0x03, 0x46, 0x97, 0xff}}},
|
|
+ {{{ 187, -6, -133}, 0, { 0, 0}, {0x1e, 0x04, 0x85, 0xff}}},
|
|
+ {{{ 120, -12, -109}, 0, { 0, 0}, {0xed, 0x24, 0x88, 0xff}}},
|
|
+ {{{ 175, 91, -38}, 0, { 0, 0}, {0xc6, 0x6d, 0xe7, 0xff}}},
|
|
+ {{{ 173, 132, -65}, 0, { 0, 0}, {0xda, 0x5a, 0xb0, 0xff}}},
|
|
+ {{{ 195, 93, -31}, 0, { 0, 0}, {0x51, 0x54, 0xcf, 0xff}}},
|
|
+ {{{ 252, 62, -69}, 0, { 0, 0}, {0x39, 0x4a, 0xab, 0xff}}},
|
|
+ {{{ 164, -89, -74}, 0, { 0, 0}, {0x51, 0xa9, 0xd5, 0xff}}},
|
|
+ {{{ 271, 0, -41}, 0, { 0, 0}, {0x6e, 0xcf, 0xdc, 0xff}}},
|
|
+ {{{ 187, -6, 134}, 0, { 0, 0}, {0x1f, 0x04, 0x7a, 0xff}}},
|
|
+ {{{ 153, 33, 95}, 0, { 0, 0}, {0x04, 0x46, 0x69, 0xff}}},
|
|
+ {{{ 120, -11, 111}, 0, { 0, 0}, {0xed, 0x24, 0x78, 0xff}}},
|
|
+ {{{ 252, 62, 70}, 0, { 0, 0}, {0x39, 0x4a, 0x55, 0xff}}},
|
|
+ {{{ 271, 0, 42}, 0, { 0, 0}, {0x71, 0xdc, 0x2b, 0xff}}},
|
|
+ {{{ 164, -89, 75}, 0, { 0, 0}, {0x4e, 0xa6, 0x2b, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_face_cap_dl_vertex_group3[] = {
|
|
+ {{{ 195, 93, 32}, 0, { 0, 0}, {0x51, 0x54, 0x30, 0xff}}},
|
|
+ {{{ 173, 132, 66}, 0, { 0, 0}, {0xda, 0x5a, 0x50, 0xff}}},
|
|
+ {{{ 153, 33, 95}, 0, { 0, 0}, {0x04, 0x46, 0x69, 0xff}}},
|
|
+ {{{ 175, 91, 39}, 0, { 0, 0}, {0xc6, 0x6d, 0x19, 0xff}}},
|
|
+ {{{ 164, -89, -74}, 0, { 0, 0}, {0x51, 0xa9, 0xd5, 0xff}}},
|
|
+ {{{ 271, 0, -41}, 0, { 0, 0}, {0x6e, 0xcf, 0xdc, 0xff}}},
|
|
+ {{{ 164, -89, 75}, 0, { 0, 0}, {0x4e, 0xa6, 0x2b, 0xff}}},
|
|
+ {{{ 271, 0, 42}, 0, { 0, 0}, {0x71, 0xdc, 0x2b, 0xff}}},
|
|
+ {{{ 252, 62, -69}, 0, { 0, 0}, {0x39, 0x4a, 0xab, 0xff}}},
|
|
+ {{{ 272, 85, 0}, 0, { 0, 0}, {0x5f, 0x54, 0x00, 0xff}}},
|
|
+ {{{ 182, 155, 0}, 0, { 0, 0}, {0xed, 0x7d, 0x00, 0xff}}},
|
|
+ {{{ 195, 93, -31}, 0, { 0, 0}, {0x51, 0x54, 0xcf, 0xff}}},
|
|
+ {{{ 175, 91, -38}, 0, { 0, 0}, {0xc6, 0x6d, 0xe7, 0xff}}},
|
|
+ {{{ 173, 132, -65}, 0, { 0, 0}, {0xda, 0x5a, 0xb0, 0xff}}},
|
|
+ {{{ 252, 62, 70}, 0, { 0, 0}, {0x39, 0x4a, 0x55, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_face_part_cap_on_dl_vertex_group1[] = {
|
|
+ {{{ 41, 109, 0}, 0, { 0, 0}, {0x95, 0x44, 0x00, 0xff}}},
|
|
+ {{{ 27, 100, -29}, 0, { 0, 0}, {0xb1, 0x60, 0xea, 0xff}}},
|
|
+ {{{ 27, 100, 30}, 0, { 0, 0}, {0xb1, 0x60, 0x16, 0xff}}},
|
|
+ {{{ -7, 62, 0}, 0, { 0, 0}, {0x85, 0x1d, 0x00, 0xff}}},
|
|
+ {{{ 3, 54, 52}, 0, { 0, 0}, {0x95, 0x1d, 0x3c, 0xff}}},
|
|
+ {{{ 3, 54, -51}, 0, { 0, 0}, {0x95, 0x1d, 0xc4, 0xff}}},
|
|
+ {{{ 17, -52, -46}, 0, { 0, 0}, {0x89, 0xf8, 0xd7, 0xff}}},
|
|
+ {{{ 17, -52, 47}, 0, { 0, 0}, {0x89, 0xf8, 0x29, 0xff}}},
|
|
+ {{{ 42, 0, 103}, 0, { 0, 0}, {0xc3, 0x05, 0x6e, 0xff}}},
|
|
+ {{{ 44, 44, 97}, 0, { 0, 0}, {0xda, 0x21, 0x74, 0xff}}},
|
|
+ {{{ 42, 0, -102}, 0, { 0, 0}, {0xc3, 0x05, 0x92, 0xff}}},
|
|
+ {{{ 44, 44, -96}, 0, { 0, 0}, {0xda, 0x21, 0x8c, 0xff}}},
|
|
+ {{{ 64, -25, 135}, 0, { 0, 0}, {0xcc, 0xe5, 0x70, 0xff}}},
|
|
+ {{{ 91, -54, 86}, 0, { 0, 0}, {0xd9, 0xaf, 0x59, 0xff}}},
|
|
+ {{{ 102, -33, 135}, 0, { 0, 0}, {0x30, 0x18, 0x72, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_face_part_cap_on_dl_vertex_group2[] = {
|
|
+ {{{ 102, -33, -134}, 0, { 0, 0}, {0x32, 0x19, 0x8f, 0xff}}},
|
|
+ {{{ 120, -12, -109}, 0, { 0, 0}, {0xed, 0x24, 0x88, 0xff}}},
|
|
+ {{{ 91, -54, -85}, 0, { 0, 0}, {0xd9, 0xb0, 0xa7, 0xff}}},
|
|
+ {{{ 64, -25, 135}, 0, { 0, 0}, {0xcc, 0xe5, 0x70, 0xff}}},
|
|
+ {{{ 56, -45, 77}, 0, { 0, 0}, {0xe3, 0xca, 0x6e, 0xff}}},
|
|
+ {{{ 91, -54, 86}, 0, { 0, 0}, {0xd9, 0xaf, 0x59, 0xff}}},
|
|
+ {{{ 120, -11, 111}, 0, { 0, 0}, {0xed, 0x24, 0x78, 0xff}}},
|
|
+ {{{ 85, -23, 111}, 0, { 0, 0}, {0x04, 0x58, 0x5a, 0xff}}},
|
|
+ {{{ 102, -33, 135}, 0, { 0, 0}, {0x30, 0x18, 0x72, 0xff}}},
|
|
+ {{{ 42, 0, 103}, 0, { 0, 0}, {0xc3, 0x05, 0x6e, 0xff}}},
|
|
+ {{{ 85, -23, -110}, 0, { 0, 0}, {0x06, 0x59, 0xa6, 0xff}}},
|
|
+ {{{ 64, -25, -134}, 0, { 0, 0}, {0xcc, 0xe5, 0x90, 0xff}}},
|
|
+ {{{ 42, 0, -102}, 0, { 0, 0}, {0xc3, 0x05, 0x92, 0xff}}},
|
|
+ {{{ 33, 165, 0}, 0, { 0, 0}, {0x8f, 0x38, 0x09, 0xff}}},
|
|
+ {{{ 52, 164, -40}, 0, { 0, 0}, {0xb8, 0x34, 0xa6, 0xff}}},
|
|
+ {{{ 32, 132, 0}, 0, { 0, 0}, {0x84, 0xe8, 0xf8, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_face_part_cap_on_dl_vertex_group3[] = {
|
|
+ {{{ 56, -45, -76}, 0, { 0, 0}, {0xe3, 0xca, 0x92, 0xff}}},
|
|
+ {{{ 64, -25, -134}, 0, { 0, 0}, {0xcc, 0xe5, 0x90, 0xff}}},
|
|
+ {{{ 91, -54, -85}, 0, { 0, 0}, {0xd9, 0xb0, 0xa7, 0xff}}},
|
|
+ {{{ 42, 0, -102}, 0, { 0, 0}, {0xc3, 0x05, 0x92, 0xff}}},
|
|
+ {{{ 17, -52, 47}, 0, { 0, 0}, {0x89, 0xf8, 0x29, 0xff}}},
|
|
+ {{{ 56, -45, 77}, 0, { 0, 0}, {0xe3, 0xca, 0x6e, 0xff}}},
|
|
+ {{{ 42, 0, 103}, 0, { 0, 0}, {0xc3, 0x05, 0x6e, 0xff}}},
|
|
+ {{{ 17, -52, -46}, 0, { 0, 0}, {0x89, 0xf8, 0xd7, 0xff}}},
|
|
+ {{{ 32, 132, 0}, 0, { 0, 0}, {0x84, 0xe8, 0xf8, 0xff}}},
|
|
+ {{{ 47, 131, 41}, 0, { 0, 0}, {0xb0, 0xe4, 0x5e, 0xff}}},
|
|
+ {{{ 33, 165, 0}, 0, { 0, 0}, {0x8f, 0x38, 0x09, 0xff}}},
|
|
+ {{{ 52, 111, 31}, 0, { 0, 0}, {0xa8, 0x33, 0x4b, 0xff}}},
|
|
+ {{{ 52, 111, -30}, 0, { 0, 0}, {0xa8, 0x32, 0xb5, 0xff}}},
|
|
+ {{{ 41, 109, 0}, 0, { 0, 0}, {0x95, 0x44, 0x00, 0xff}}},
|
|
+ {{{ 77, 108, 34}, 0, { 0, 0}, {0x0e, 0x16, 0x7c, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_face_part_cap_on_dl_vertex_group4[] = {
|
|
+ {{{ 92, 88, 84}, 0, { 0, 0}, {0x23, 0x59, 0x53, 0xff}}},
|
|
+ {{{ 104, 87, 70}, 0, { 0, 0}, {0x30, 0x5c, 0x49, 0xff}}},
|
|
+ {{{ 97, 103, 25}, 0, { 0, 0}, {0x40, 0x5a, 0x3d, 0xff}}},
|
|
+ {{{ 117, 128, 0}, 0, { 0, 0}, {0x7a, 0xe1, 0x06, 0xff}}},
|
|
+ {{{ 102, 129, 41}, 0, { 0, 0}, {0x45, 0xd6, 0x61, 0xff}}},
|
|
+ {{{ 77, 108, 34}, 0, { 0, 0}, {0x0e, 0x16, 0x7c, 0xff}}},
|
|
+ {{{ 108, 105, 0}, 0, { 0, 0}, {0x69, 0x46, 0x00, 0xff}}},
|
|
+ {{{ 97, 103, -24}, 0, { 0, 0}, {0x40, 0x5a, 0xc3, 0xff}}},
|
|
+ {{{ 119, 161, 0}, 0, { 0, 0}, {0x79, 0x23, 0xf6, 0xff}}},
|
|
+ {{{ 104, 162, 41}, 0, { 0, 0}, {0x52, 0x27, 0x58, 0xff}}},
|
|
+ {{{ 102, 129, -40}, 0, { 0, 0}, {0x50, 0xdc, 0xa6, 0xff}}},
|
|
+ {{{ 75, 130, 46}, 0, { 0, 0}, {0x00, 0xec, 0x7d, 0xff}}},
|
|
+ {{{ 78, 163, 46}, 0, { 0, 0}, {0x03, 0x55, 0x5d, 0xff}}},
|
|
+ {{{ 101, 179, 0}, 0, { 0, 0}, {0x27, 0x78, 0x00, 0xff}}},
|
|
+ {{{ 52, 164, 41}, 0, { 0, 0}, {0xc8, 0x3d, 0x5f, 0xff}}},
|
|
+ {{{ 47, 131, 41}, 0, { 0, 0}, {0xb0, 0xe4, 0x5e, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_face_part_cap_on_dl_vertex_group5[] = {
|
|
+ {{{ 47, 131, 41}, 0, { 0, 0}, {0xb0, 0xe4, 0x5e, 0xff}}},
|
|
+ {{{ 52, 164, 41}, 0, { 0, 0}, {0xc8, 0x3d, 0x5f, 0xff}}},
|
|
+ {{{ 33, 165, 0}, 0, { 0, 0}, {0x8f, 0x38, 0x09, 0xff}}},
|
|
+ {{{ 75, 130, 46}, 0, { 0, 0}, {0x00, 0xec, 0x7d, 0xff}}},
|
|
+ {{{ 77, 108, 34}, 0, { 0, 0}, {0x0e, 0x16, 0x7c, 0xff}}},
|
|
+ {{{ 78, 163, 46}, 0, { 0, 0}, {0x03, 0x55, 0x5d, 0xff}}},
|
|
+ {{{ 60, 181, 0}, 0, { 0, 0}, {0xea, 0x7c, 0x00, 0xff}}},
|
|
+ {{{ 52, 164, -40}, 0, { 0, 0}, {0xb8, 0x34, 0xa6, 0xff}}},
|
|
+ {{{ 96, 49, 94}, 0, { 0, 0}, {0x10, 0x28, 0x77, 0xff}}},
|
|
+ {{{ 153, 33, 95}, 0, { 0, 0}, {0x04, 0x46, 0x69, 0xff}}},
|
|
+ {{{ 144, 83, 67}, 0, { 0, 0}, {0x19, 0x5b, 0x53, 0xff}}},
|
|
+ {{{ 101, 179, 0}, 0, { 0, 0}, {0x27, 0x78, 0x00, 0xff}}},
|
|
+ {{{ 104, 87, 70}, 0, { 0, 0}, {0x30, 0x5c, 0x49, 0xff}}},
|
|
+ {{{ 92, 88, 84}, 0, { 0, 0}, {0x23, 0x59, 0x53, 0xff}}},
|
|
+ {{{ 44, 44, 97}, 0, { 0, 0}, {0xda, 0x21, 0x74, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_face_part_cap_on_dl_vertex_group6[] = {
|
|
+ {{{ 17, -52, -46}, 0, { 0, 0}, {0x89, 0xf8, 0xd7, 0xff}}},
|
|
+ {{{ 31, -84, 0}, 0, { 0, 0}, {0xa0, 0xae, 0x00, 0xff}}},
|
|
+ {{{ 17, -52, 47}, 0, { 0, 0}, {0x89, 0xf8, 0x29, 0xff}}},
|
|
+ {{{ 144, 83, -66}, 0, { 0, 0}, {0x19, 0x5b, 0xad, 0xff}}},
|
|
+ {{{ 153, 33, -94}, 0, { 0, 0}, {0x03, 0x46, 0x97, 0xff}}},
|
|
+ {{{ 96, 49, -93}, 0, { 0, 0}, {0x11, 0x27, 0x89, 0xff}}},
|
|
+ {{{ 92, 88, -83}, 0, { 0, 0}, {0x23, 0x59, 0xad, 0xff}}},
|
|
+ {{{ 104, 87, -69}, 0, { 0, 0}, {0x30, 0x5c, 0xb7, 0xff}}},
|
|
+ {{{ 44, 44, -96}, 0, { 0, 0}, {0xda, 0x21, 0x8c, 0xff}}},
|
|
+ {{{ 75, 130, -45}, 0, { 0, 0}, {0x00, 0xec, 0x83, 0xff}}},
|
|
+ {{{ 78, 163, -45}, 0, { 0, 0}, {0x03, 0x54, 0xa2, 0xff}}},
|
|
+ {{{ 104, 162, -40}, 0, { 0, 0}, {0x44, 0x31, 0xa1, 0xff}}},
|
|
+ {{{ 97, 103, -24}, 0, { 0, 0}, {0x40, 0x5a, 0xc3, 0xff}}},
|
|
+ {{{ 52, 164, -40}, 0, { 0, 0}, {0xb8, 0x34, 0xa6, 0xff}}},
|
|
+ {{{ 47, 131, -40}, 0, { 0, 0}, {0xbc, 0xde, 0x9c, 0xff}}},
|
|
+ {{{ 60, 181, 0}, 0, { 0, 0}, {0xea, 0x7c, 0x00, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_face_part_cap_on_dl_vertex_group7[] = {
|
|
+ {{{ 52, 164, -40}, 0, { 0, 0}, {0xb8, 0x34, 0xa6, 0xff}}},
|
|
+ {{{ 47, 131, -40}, 0, { 0, 0}, {0xbc, 0xde, 0x9c, 0xff}}},
|
|
+ {{{ 32, 132, 0}, 0, { 0, 0}, {0x84, 0xe8, 0xf8, 0xff}}},
|
|
+ {{{ 77, 108, -33}, 0, { 0, 0}, {0x0e, 0x16, 0x84, 0xff}}},
|
|
+ {{{ 52, 111, -30}, 0, { 0, 0}, {0xa8, 0x32, 0xb5, 0xff}}},
|
|
+ {{{ 75, 130, -45}, 0, { 0, 0}, {0x00, 0xec, 0x83, 0xff}}},
|
|
+ {{{ 104, 162, -40}, 0, { 0, 0}, {0x44, 0x31, 0xa1, 0xff}}},
|
|
+ {{{ 102, 129, -40}, 0, { 0, 0}, {0x50, 0xdc, 0xa6, 0xff}}},
|
|
+ {{{ 119, 161, 0}, 0, { 0, 0}, {0x79, 0x23, 0xf6, 0xff}}},
|
|
+ {{{ 97, 103, -24}, 0, { 0, 0}, {0x40, 0x5a, 0xc3, 0xff}}},
|
|
+ {{{ 78, 163, -45}, 0, { 0, 0}, {0x03, 0x54, 0xa2, 0xff}}},
|
|
+ {{{ 60, 181, 0}, 0, { 0, 0}, {0xea, 0x7c, 0x00, 0xff}}},
|
|
+ {{{ 101, 179, 0}, 0, { 0, 0}, {0x27, 0x78, 0x00, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_face_back_hair_cap_on_dl_vertex_group1[] = {
|
|
+ {{{ 31, -84, 0}, 0, { 0, 0}, {0xa0, 0xae, 0x00, 0xff}}},
|
|
+ {{{ 36, -116, -35}, 0, { 0, 0}, {0xfb, 0x8e, 0x37, 0xff}}},
|
|
+ {{{ 64, -103, -51}, 0, { 0, 0}, {0xde, 0x94, 0xc7, 0xff}}},
|
|
+ {{{ 31, -85, 87}, 0, { 0, 0}, {0xdb, 0xfd, 0x79, 0xff}}},
|
|
+ {{{ 35, -120, 68}, 0, { 0, 0}, {0xda, 0x94, 0x35, 0xff}}},
|
|
+ {{{ 58, -114, 60}, 0, { 0, 0}, {0x57, 0xb4, 0x32, 0xff}}},
|
|
+ {{{ 64, -103, 52}, 0, { 0, 0}, {0xc9, 0x9a, 0x31, 0xff}}},
|
|
+ {{{ 56, -45, 77}, 0, { 0, 0}, {0xe3, 0xca, 0x6e, 0xff}}},
|
|
+ {{{ 36, -116, 36}, 0, { 0, 0}, {0xfb, 0x8e, 0xc9, 0xff}}},
|
|
+ {{{ 91, -54, 86}, 0, { 0, 0}, {0xd9, 0xaf, 0x59, 0xff}}},
|
|
+ {{{ 17, -52, 47}, 0, { 0, 0}, {0x89, 0xf8, 0x29, 0xff}}},
|
|
+ {{{ 35, -120, -67}, 0, { 0, 0}, {0xda, 0x94, 0xcb, 0xff}}},
|
|
+ {{{ 58, -114, -59}, 0, { 0, 0}, {0x57, 0xb4, 0xce, 0xff}}},
|
|
+ {{{ 31, -85, -86}, 0, { 0, 0}, {0xdb, 0xfd, 0x87, 0xff}}},
|
|
+ {{{ 56, -45, -76}, 0, { 0, 0}, {0xe3, 0xca, 0x92, 0xff}}},
|
|
+ {{{ 17, -52, -46}, 0, { 0, 0}, {0x89, 0xf8, 0xd7, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Vtx ghost_mario_face_back_hair_cap_on_dl_vertex_group2[] = {
|
|
+ {{{ 31, -85, -86}, 0, { 0, 0}, {0xdb, 0xfd, 0x87, 0xff}}},
|
|
+ {{{ 35, -120, -67}, 0, { 0, 0}, {0xda, 0x94, 0xcb, 0xff}}},
|
|
+ {{{ 9, -88, -58}, 0, { 0, 0}, {0x87, 0xdf, 0xf5, 0xff}}},
|
|
+ {{{ 17, -52, -46}, 0, { 0, 0}, {0x89, 0xf8, 0xd7, 0xff}}},
|
|
+ {{{ 56, -45, -76}, 0, { 0, 0}, {0xe3, 0xca, 0x92, 0xff}}},
|
|
+ {{{ 91, -54, -85}, 0, { 0, 0}, {0xd9, 0xb0, 0xa7, 0xff}}},
|
|
+ {{{ 64, -103, -51}, 0, { 0, 0}, {0xde, 0x94, 0xc7, 0xff}}},
|
|
+ {{{ 31, -84, 0}, 0, { 0, 0}, {0xa0, 0xae, 0x00, 0xff}}},
|
|
+ {{{ 36, -116, 36}, 0, { 0, 0}, {0xfb, 0x8e, 0xc9, 0xff}}},
|
|
+ {{{ 9, -88, 59}, 0, { 0, 0}, {0x87, 0xdf, 0x0b, 0xff}}},
|
|
+ {{{ 17, -52, 47}, 0, { 0, 0}, {0x89, 0xf8, 0x29, 0xff}}},
|
|
+ {{{ 36, -116, -35}, 0, { 0, 0}, {0xfb, 0x8e, 0x37, 0xff}}},
|
|
+ {{{ 35, -120, 68}, 0, { 0, 0}, {0xda, 0x94, 0x35, 0xff}}},
|
|
+ {{{ 31, -85, 87}, 0, { 0, 0}, {0xdb, 0xfd, 0x79, 0xff}}},
|
|
+};
|
|
+
|
|
+static const Gfx ghost_mario_cap_on_shared_dl[] = {
|
|
+ gsSPVertex(ghost_mario_m_logo_dl_vertex, 7, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
|
+ gsSP2Triangles(2, 3, 0, 0x0, 3, 5, 0, 0x0),
|
|
+ gsSP1Triangle(4, 6, 5, 0x0),
|
|
+ gsSPVertex(ghost_mario_eyes_cap_on_dl_vertex, 12, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
|
+ gsSP2Triangles(3, 0, 4, 0x0, 6, 3, 5, 0x0),
|
|
+ gsSP2Triangles(3, 1, 0, 0x0, 4, 0, 7, 0x0),
|
|
+ gsSP2Triangles(5, 4, 8, 0x0, 2, 9, 10, 0x0),
|
|
+ gsSP2Triangles(10, 7, 2, 0x0, 11, 7, 10, 0x0),
|
|
+ gsSP1Triangle(7, 0, 2, 0x0),
|
|
+ gsSPVertex(ghost_mario_hair_sideburn_cap_on_dl_vertex, 12, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 1, 3, 4, 0x0),
|
|
+ gsSP2Triangles(4, 5, 1, 0x0, 3, 1, 0, 0x0),
|
|
+ gsSP2Triangles(6, 7, 8, 0x0, 8, 9, 6, 0x0),
|
|
+ gsSP2Triangles(9, 10, 6, 0x0, 11, 6, 10, 0x0),
|
|
+ gsSPVertex(ghost_mario_mustache_cap_on_dl_vertex_group1, 16, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 1, 0, 3, 0x0),
|
|
+ gsSP2Triangles(0, 4, 3, 0x0, 5, 3, 4, 0x0),
|
|
+ gsSP2Triangles(5, 4, 6, 0x0, 7, 3, 8, 0x0),
|
|
+ gsSP2Triangles(8, 3, 5, 0x0, 3, 7, 1, 0x0),
|
|
+ gsSP2Triangles(9, 10, 11, 0x0, 12, 10, 13, 0x0),
|
|
+ gsSP2Triangles(11, 10, 12, 0x0, 10, 9, 14, 0x0),
|
|
+ gsSP1Triangle(15, 9, 11, 0x0),
|
|
+ gsSPVertex(ghost_mario_mustache_cap_on_dl_vertex_group2, 5, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 2, 1, 3, 0x0),
|
|
+ gsSP1Triangle(2, 4, 0, 0x0),
|
|
+ gsSPVertex(ghost_mario_face_part_cap_on_dl_vertex_group1, 15, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 2, 1, 3, 0x0),
|
|
+ gsSP2Triangles(3, 4, 2, 0x0, 1, 5, 3, 0x0),
|
|
+ gsSP2Triangles(6, 7, 3, 0x0, 7, 4, 3, 0x0),
|
|
+ gsSP2Triangles(6, 3, 5, 0x0, 4, 7, 8, 0x0),
|
|
+ gsSP2Triangles(9, 4, 8, 0x0, 10, 6, 5, 0x0),
|
|
+ gsSP2Triangles(10, 5, 11, 0x0, 12, 13, 14, 0x0),
|
|
+ gsSPVertex(ghost_mario_face_part_cap_on_dl_vertex_group2, 16, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
|
+ gsSP2Triangles(6, 7, 8, 0x0, 5, 6, 8, 0x0),
|
|
+ gsSP2Triangles(3, 8, 7, 0x0, 9, 3, 7, 0x0),
|
|
+ gsSP2Triangles(3, 9, 4, 0x0, 10, 11, 12, 0x0),
|
|
+ gsSP2Triangles(0, 10, 1, 0x0, 10, 0, 11, 0x0),
|
|
+ gsSP2Triangles(11, 0, 2, 0x0, 13, 14, 15, 0x0),
|
|
+ gsSPVertex(ghost_mario_face_part_cap_on_dl_vertex_group3, 15, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 1, 0, 0x0),
|
|
+ gsSP2Triangles(4, 5, 6, 0x0, 3, 0, 7, 0x0),
|
|
+ gsSP2Triangles(8, 9, 10, 0x0, 11, 9, 8, 0x0),
|
|
+ gsSP2Triangles(12, 13, 8, 0x0, 8, 13, 11, 0x0),
|
|
+ gsSP1Triangle(9, 11, 14, 0x0),
|
|
+ gsSPVertex(ghost_mario_face_part_cap_on_dl_vertex_group4, 16, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 4, 2, 0x0),
|
|
+ gsSP2Triangles(5, 2, 4, 0x0, 2, 6, 3, 0x0),
|
|
+ gsSP2Triangles(3, 6, 7, 0x0, 8, 9, 3, 0x0),
|
|
+ gsSP2Triangles(9, 4, 3, 0x0, 7, 10, 3, 0x0),
|
|
+ gsSP2Triangles(3, 10, 8, 0x0, 11, 4, 9, 0x0),
|
|
+ gsSP2Triangles(12, 11, 9, 0x0, 13, 9, 8, 0x0),
|
|
+ gsSP2Triangles(9, 13, 12, 0x0, 4, 11, 5, 0x0),
|
|
+ gsSP1Triangle(14, 15, 11, 0x0),
|
|
+ gsSPVertex(ghost_mario_face_part_cap_on_dl_vertex_group5, 15, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 0, 4, 0x0),
|
|
+ gsSP2Triangles(1, 5, 6, 0x0, 1, 3, 5, 0x0),
|
|
+ gsSP2Triangles(2, 1, 6, 0x0, 2, 6, 7, 0x0),
|
|
+ gsSP2Triangles(8, 9, 10, 0x0, 6, 5, 11, 0x0),
|
|
+ gsSP2Triangles(12, 13, 8, 0x0, 10, 12, 8, 0x0),
|
|
+ gsSP1Triangle(14, 8, 13, 0x0),
|
|
+ gsSPVertex(ghost_mario_face_part_cap_on_dl_vertex_group6, 16, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
|
+ gsSP2Triangles(5, 6, 7, 0x0, 6, 5, 8, 0x0),
|
|
+ gsSP2Triangles(5, 7, 3, 0x0, 9, 10, 11, 0x0),
|
|
+ gsSP2Triangles(6, 12, 7, 0x0, 13, 10, 9, 0x0),
|
|
+ gsSP2Triangles(14, 13, 9, 0x0, 15, 10, 13, 0x0),
|
|
+ gsSPVertex(ghost_mario_face_part_cap_on_dl_vertex_group7, 13, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 4, 1, 0x0),
|
|
+ gsSP2Triangles(1, 5, 3, 0x0, 2, 1, 4, 0x0),
|
|
+ gsSP2Triangles(5, 6, 7, 0x0, 7, 6, 8, 0x0),
|
|
+ gsSP2Triangles(7, 9, 3, 0x0, 5, 7, 3, 0x0),
|
|
+ gsSP2Triangles(10, 11, 12, 0x0, 12, 6, 10, 0x0),
|
|
+ gsSP1Triangle(12, 8, 6, 0x0),
|
|
+ gsSPVertex(ghost_mario_face_cap_dl_vertex_group1, 16, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 2, 4, 0x0),
|
|
+ gsSP2Triangles(4, 2, 5, 0x0, 3, 0, 2, 0x0),
|
|
+ gsSP2Triangles(2, 1, 6, 0x0, 6, 7, 2, 0x0),
|
|
+ gsSP2Triangles(5, 2, 7, 0x0, 6, 1, 8, 0x0),
|
|
+ gsSP2Triangles(8, 1, 0, 0x0, 6, 8, 9, 0x0),
|
|
+ gsSP2Triangles(10, 7, 6, 0x0, 9, 10, 6, 0x0),
|
|
+ gsSP2Triangles(11, 10, 9, 0x0, 9, 8, 11, 0x0),
|
|
+ gsSP2Triangles(11, 8, 12, 0x0, 0, 12, 8, 0x0),
|
|
+ gsSP2Triangles(13, 10, 11, 0x0, 11, 12, 14, 0x0),
|
|
+ gsSP2Triangles(15, 11, 14, 0x0, 13, 11, 15, 0x0),
|
|
+ gsSPVertex(ghost_mario_face_cap_dl_vertex_group2, 15, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 4, 0, 0x0),
|
|
+ gsSP2Triangles(4, 5, 0, 0x0, 0, 6, 1, 0x0),
|
|
+ gsSP2Triangles(7, 1, 8, 0x0, 8, 1, 6, 0x0),
|
|
+ gsSP2Triangles(9, 10, 11, 0x0, 9, 12, 10, 0x0),
|
|
+ gsSP2Triangles(12, 9, 13, 0x0, 13, 9, 14, 0x0),
|
|
+ gsSPVertex(ghost_mario_face_cap_dl_vertex_group3, 15, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 2, 1, 3, 0x0),
|
|
+ gsSP2Triangles(4, 5, 6, 0x0, 5, 7, 6, 0x0),
|
|
+ gsSP2Triangles(8, 9, 5, 0x0, 0, 10, 1, 0x0),
|
|
+ gsSP2Triangles(1, 10, 3, 0x0, 11, 10, 0, 0x0),
|
|
+ gsSP2Triangles(12, 3, 10, 0x0, 12, 10, 13, 0x0),
|
|
+ gsSP2Triangles(13, 10, 11, 0x0, 5, 9, 7, 0x0),
|
|
+ gsSP1Triangle(7, 9, 14, 0x0),
|
|
+ gsSPVertex(ghost_mario_face_back_hair_cap_on_dl_vertex_group1, 16, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
|
+ gsSP2Triangles(5, 6, 7, 0x0, 5, 8, 6, 0x0),
|
|
+ gsSP2Triangles(5, 4, 8, 0x0, 7, 3, 5, 0x0),
|
|
+ gsSP2Triangles(0, 2, 6, 0x0, 6, 9, 7, 0x0),
|
|
+ gsSP2Triangles(0, 6, 8, 0x0, 3, 7, 10, 0x0),
|
|
+ gsSP2Triangles(1, 11, 12, 0x0, 12, 13, 14, 0x0),
|
|
+ gsSP2Triangles(11, 13, 12, 0x0, 1, 12, 2, 0x0),
|
|
+ gsSP2Triangles(14, 2, 12, 0x0, 15, 14, 13, 0x0),
|
|
+ gsSPVertex(ghost_mario_face_back_hair_cap_on_dl_vertex_group2, 14, 0),
|
|
+ gsSP2Triangles(0, 1, 2, 0x0, 0, 2, 3, 0x0),
|
|
+ gsSP2Triangles(4, 5, 6, 0x0, 7, 3, 2, 0x0),
|
|
+ gsSP2Triangles(7, 8, 9, 0x0, 9, 10, 7, 0x0),
|
|
+ gsSP2Triangles(2, 1, 11, 0x0, 2, 11, 7, 0x0),
|
|
+ gsSP2Triangles(9, 12, 13, 0x0, 10, 9, 13, 0x0),
|
|
+ gsSP1Triangle(8, 12, 9, 0x0),
|
|
+ gsSPEndDisplayList(),
|
|
+};
|
|
+
|
|
+//
|
|
+// Ghost Mario geo
|
|
+//
|
|
+
|
|
+static const GeoLayout ghost_mario_geo_body[] = {
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, NULL),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, ghost_mario_butt),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 68, 0, 0, ghost_mario_torso_shared_dl),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 87, 0, 0, NULL),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_DISPLAY_LIST(LAYER_TRANSPARENT, ghost_mario_cap_on_shared_dl),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 67, -10, 79, NULL),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, ghost_mario_left_arm_shared_dl),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 65, 0, 0, ghost_mario_left_forearm_shared_dl),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 60, 0, 0, NULL),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_DISPLAY_LIST(LAYER_TRANSPARENT, ghost_mario_left_hand_closed_shared_dl),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 68, -10, -79, NULL),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, ghost_mario_right_arm_shared_dl),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 65, 0, 0, ghost_mario_right_forearm_shared_dl),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 60, 0, 0, NULL),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_DISPLAY_LIST(LAYER_TRANSPARENT, ghost_mario_right_hand_closed),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 13, -8, 42, NULL),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, ghost_mario_left_thigh),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 89, 0, 0, ghost_mario_left_leg_shared_dl),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 67, 0, 0, ghost_mario_left_foot_shared_dl),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 13, -8, -42, NULL),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, ghost_mario_right_thigh_shared_dl),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 89, 0, 0, ghost_mario_right_leg_shared_dl),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ANIMATED_PART(LAYER_TRANSPARENT, 67, 0, 0, NULL),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_DISPLAY_LIST(LAYER_TRANSPARENT, ghost_mario_right_foot),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_RETURN(),
|
|
+};
|
|
+
|
|
+static const GeoLayout ghost_mario_blue_geo[] = {
|
|
+ GEO_SHADOW(SHADOW_CIRCLE_PLAYER, 0xB4, 0),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_SCALE(0x00, 16384),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ASM(10, geo_update_layer_transparency),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_NODE_START(),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_RENDER_RANGE(-2048, 32767),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_DISPLAY_LIST(LAYER_TRANSPARENT, ghost_mario_blue_light_dl),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_BRANCH(1, ghost_mario_geo_body),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_END(),
|
|
+};
|
|
+
|
|
+static const GeoLayout ghost_mario_red_geo[] = {
|
|
+ GEO_SHADOW(SHADOW_CIRCLE_PLAYER, 0xB4, 0),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_SCALE(0x00, 16384),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ASM(10, geo_update_layer_transparency),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_NODE_START(),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_RENDER_RANGE(-2048, 32767),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_DISPLAY_LIST(LAYER_TRANSPARENT, ghost_mario_red_light_dl),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_BRANCH(1, ghost_mario_geo_body),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_END(),
|
|
+};
|
|
+
|
|
+static const GeoLayout ghost_mario_green_geo[] = {
|
|
+ GEO_SHADOW(SHADOW_CIRCLE_PLAYER, 0xB4, 0),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_SCALE(0x00, 16384),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ASM(10, geo_update_layer_transparency),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_NODE_START(),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_RENDER_RANGE(-2048, 32767),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_DISPLAY_LIST(LAYER_TRANSPARENT, ghost_mario_green_light_dl),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_BRANCH(1, ghost_mario_geo_body),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_END(),
|
|
+};
|
|
+
|
|
+static const GeoLayout ghost_mario_gold_geo[] = {
|
|
+ GEO_SHADOW(SHADOW_CIRCLE_PLAYER, 0xB4, 0),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_SCALE(0x00, 16384),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_ASM(10, geo_update_layer_transparency),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_NODE_START(),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_RENDER_RANGE(-2048, 32767),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_DISPLAY_LIST(LAYER_TRANSPARENT, ghost_mario_gold_light_dl),
|
|
+ GEO_OPEN_NODE(),
|
|
+ GEO_BRANCH(1, ghost_mario_geo_body),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_CLOSE_NODE(),
|
|
+ GEO_END(),
|
|
+};
|
|
diff --git a/src/menu/star_select.c b/src/menu/star_select.c
|
|
index 08b988e..7495a86 100644
|
|
--- a/src/menu/star_select.c
|
|
+++ b/src/menu/star_select.c
|
|
@@ -379,6 +379,7 @@ Gfx *geo_act_selector_strings(s16 callContext, UNUSED struct GraphNode *node) {
|
|
#endif
|
|
if (callContext == GEO_CONTEXT_RENDER) {
|
|
print_act_selector_strings();
|
|
+ time_trials_render_star_select_time(gCurrSaveFileNum - 1, gCurrCourseNum, sSelectedActIndex);
|
|
}
|
|
return NULL;
|
|
}
|
|
diff --git a/src/pc/dynamic_options.c b/src/pc/dynamic_options.c
|
|
new file mode 100644
|
|
index 0000000..801f06e
|
|
--- /dev/null
|
|
+++ b/src/pc/dynamic_options.c
|
|
@@ -0,0 +1,1810 @@
|
|
+#include <stdio.h>
|
|
+#include <time.h>
|
|
+#include <dirent.h>
|
|
+#include <SDL2/SDL.h>
|
|
+#include "controller/controller_keyboard.h"
|
|
+#include "controller/controller_sdl.h"
|
|
+#include "game/object_list_processor.h"
|
|
+#include "game/spawn_object.h"
|
|
+#include "game/sound_init.h"
|
|
+#include "engine/level_script.h"
|
|
+#include "fs/fs.h"
|
|
+#include "levels.h"
|
|
+#include "configfile.h"
|
|
+#include "gfx_dimensions.h"
|
|
+
|
|
+#ifdef size_t
|
|
+#undef size_t
|
|
+#endif
|
|
+#ifdef IS_64_BIT
|
|
+#define size_t unsigned long long
|
|
+#else
|
|
+#define size_t unsigned int
|
|
+#endif
|
|
+
|
|
+//
|
|
+// C String to SM64 String conversion
|
|
+//
|
|
+
|
|
+static const unsigned char sSm64CharTable[][2] = {
|
|
+ { '0', 0 }, { '1', 1 }, { '2', 2 }, { '3', 3 }, { '4', 4 }, { '5', 5 }, { '6', 6 },
|
|
+ { '7', 7 }, { '8', 8 }, { '9', 9 }, { 'A', 10 }, { 'B', 11 }, { 'C', 12 }, { 'D', 13 },
|
|
+ { 'E', 14 }, { 'F', 15 }, { 'G', 16 }, { 'H', 17 }, { 'I', 18 }, { 'J', 19 }, { 'K', 20 },
|
|
+ { 'L', 21 }, { 'M', 22 }, { 'N', 23 }, { 'O', 24 }, { 'P', 25 }, { 'Q', 26 }, { 'R', 27 },
|
|
+ { 'S', 28 }, { 'T', 29 }, { 'U', 30 }, { 'V', 31 }, { 'W', 32 }, { 'X', 33 }, { 'Y', 34 },
|
|
+ { 'Z', 35 }, { 'a', 36 }, { 'b', 37 }, { 'c', 38 }, { 'd', 39 }, { 'e', 40 }, { 'f', 41 },
|
|
+ { 'g', 42 }, { 'h', 43 }, { 'i', 44 }, { 'j', 45 }, { 'k', 46 }, { 'l', 47 }, { 'm', 48 },
|
|
+ { 'n', 49 }, { 'o', 50 }, { 'p', 51 }, { 'q', 52 }, { 'r', 53 }, { 's', 54 }, { 't', 55 },
|
|
+ { 'u', 56 }, { 'v', 57 }, { 'w', 58 }, { 'x', 59 }, { 'y', 60 }, { 'z', 61 }, { '\'', 62 },
|
|
+ { '.', 63 }, { ',', 111 }, { ' ', 158 }, { '-', 159 }, { '(', 225 }, { ')', 227 }, { '&', 229 },
|
|
+ { ':', 230 }, { '!', 242 }, { '%', 243 }, { '?', 244 }, { '"', 246 }, { '~', 247 }, { '_', 253 }
|
|
+};
|
|
+static const unsigned int sSm64CharCount = sizeof(sSm64CharTable) / sizeof(sSm64CharTable[0]);
|
|
+
|
|
+static unsigned char sm64_char(char c) {
|
|
+ for (unsigned int i = 0; i != sSm64CharCount; ++i) {
|
|
+ if (sSm64CharTable[i][0] == (unsigned char) c) {
|
|
+ return sSm64CharTable[i][1];
|
|
+ }
|
|
+ }
|
|
+ return 0xFF;
|
|
+}
|
|
+
|
|
+static const unsigned char *sm64_string_convert(const char *str, unsigned char *str64, bool caps) {
|
|
+ unsigned int i = 0;
|
|
+ for (; *str != 0; str++) {
|
|
+ unsigned char c = sm64_char(*str);
|
|
+ if (c != 0xFF) {
|
|
+ if (caps && c >= 36 && c <= 61) {
|
|
+ str64[i++] = c - 26;
|
|
+ } else {
|
|
+ str64[i++] = c;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ str64[i] = 0xFF;
|
|
+ return (const unsigned char *) str64;
|
|
+}
|
|
+
|
|
+static const char *sm64_string_invert(const unsigned char *str64, char *str) {
|
|
+ unsigned int i = 0;
|
|
+ for (; *str64 != 0xFF; str64++) {
|
|
+ unsigned char c = *str64;
|
|
+ if (c <= 9) {
|
|
+ str[i++] = (c - 0) + '0';
|
|
+ } else if (c <= 35) {
|
|
+ str[i++] = (c - 10) + 'A';
|
|
+ } else if (c <= 61) {
|
|
+ str[i++] = (c - 36) + 'a';
|
|
+ } else {
|
|
+ str[i++] = '_';
|
|
+ }
|
|
+ }
|
|
+ str[i] = 0;
|
|
+ return (const char *) str;
|
|
+}
|
|
+
|
|
+static unsigned int strlen64(const unsigned char *str64) {
|
|
+ unsigned int length = 0;
|
|
+ while (*(str64++) != 0xFF) length++;
|
|
+ return length;
|
|
+}
|
|
+
|
|
+static const char *string_to_dynamic(const char *str) {
|
|
+ char *dstr = calloc(strlen(str) + 1, sizeof(char));
|
|
+ memcpy(dstr, str, strlen(str) + 1);
|
|
+ return dstr;
|
|
+}
|
|
+
|
|
+static const char *string_to_configname(const char *str) {
|
|
+ if (str == NULL || strcmp(str, "NULL") == 0 || strcmp(str, "null") == 0) {
|
|
+ return NULL;
|
|
+ }
|
|
+ char *dstr = calloc(strlen(str) + 1, sizeof(char));
|
|
+ char *pstr = dstr;
|
|
+ for (; *str != 0; str++, pstr++) {
|
|
+ if ((*str >= '0' && *str <= '9') || (*str >= 'A' && *str <= 'Z') || (*str >= 'a' && *str <= 'z')) {
|
|
+ *pstr = *str;
|
|
+ } else {
|
|
+ *pstr = '_';
|
|
+ }
|
|
+ }
|
|
+ *pstr = 0;
|
|
+ return dstr;
|
|
+}
|
|
+
|
|
+static const unsigned char *string_to_label(const char *str) {
|
|
+ unsigned char *str64 = calloc(strlen(str) + 1, sizeof(unsigned char));
|
|
+ return sm64_string_convert(str, str64, 0);
|
|
+}
|
|
+
|
|
+static const unsigned char *string_to_label2(const char *str) {
|
|
+ if (str == NULL) return NULL;
|
|
+ unsigned char *str64 = calloc(strlen(str) + 1, sizeof(char));
|
|
+ return sm64_string_convert(str, str64, 1);
|
|
+}
|
|
+
|
|
+static const char *label_to_name(const unsigned char *str64) {
|
|
+ char *str = calloc(strlen64(str64) + 1, sizeof(char));
|
|
+ return sm64_string_invert(str64, str);
|
|
+}
|
|
+
|
|
+static const unsigned char *label_decapitalize(const unsigned char *label) {
|
|
+ unsigned char *nlabel = calloc(strlen64(label) + 1, sizeof(unsigned char));
|
|
+ unsigned char *plabel = nlabel;
|
|
+ bool prevWasSpace = true;
|
|
+ for (; *label != 0xFF; ++label, ++plabel) {
|
|
+ if (!prevWasSpace && *label >= 10 && *label <= 35) {
|
|
+ *plabel = *label + 26;
|
|
+ } else {
|
|
+ *plabel = *label;
|
|
+ }
|
|
+ prevWasSpace = (*plabel >= 62);
|
|
+ }
|
|
+ *plabel = 0xFF;
|
|
+ return nlabel;
|
|
+}
|
|
+
|
|
+static int string_to_int(const char *str) {
|
|
+ int x = 0;
|
|
+ if (strlen(str) > 2 && str[0] == '0' && str[1] == 'x') {
|
|
+ sscanf(str + 2, "%X", &x);
|
|
+ } else {
|
|
+ sscanf(str, "%d", &x);
|
|
+ }
|
|
+ return x;
|
|
+}
|
|
+
|
|
+static const unsigned char *int_to_string(const char *fmt, int x) {
|
|
+ static char str[16];
|
|
+ static unsigned char str64[16];
|
|
+ snprintf(str, 16, fmt, x);
|
|
+ return sm64_string_convert(str, str64, 1);
|
|
+}
|
|
+
|
|
+//
|
|
+// Dynamic Size Array
|
|
+//
|
|
+
|
|
+struct Array {
|
|
+ void *buffer;
|
|
+ size_t count;
|
|
+ size_t itemSize;
|
|
+};
|
|
+
|
|
+static void array_add(struct Array *array, void *item) {
|
|
+
|
|
+ // Alloc space
|
|
+ void *newBuffer = calloc(array->count + 1, array->itemSize);
|
|
+ if (array->buffer) {
|
|
+ memcpy(newBuffer, array->buffer, array->count * array->itemSize);
|
|
+ free(array->buffer);
|
|
+ }
|
|
+ array->buffer = newBuffer;
|
|
+
|
|
+ // Insert item
|
|
+ memcpy((void *)((size_t) array->buffer + array->itemSize * array->count), item, array->itemSize);
|
|
+ array->count++;
|
|
+}
|
|
+
|
|
+// Doesn't check bounds
|
|
+static void *array_at(struct Array *array, size_t index) {
|
|
+ return (void *) ((size_t) array->buffer + array->itemSize * index);
|
|
+}
|
|
+
|
|
+#define array_get(array, i, type) (*((type *) array_at(array, i)))
|
|
+
|
|
+//
|
|
+// Action list
|
|
+//
|
|
+
|
|
+typedef bool (*DynosActionFunction)(const char *);
|
|
+struct DynosAction {
|
|
+ const char *str;
|
|
+ DynosActionFunction action;
|
|
+};
|
|
+
|
|
+// "Construct On First Use" aka COFU
|
|
+static struct Array *dynos_get_action_list() {
|
|
+ static struct Array sDynosActions = { .buffer = NULL, .count = 0, .itemSize = sizeof(struct DynosAction) };
|
|
+ return &sDynosActions;
|
|
+}
|
|
+
|
|
+static DynosActionFunction dynos_get_action(const char *funcName) {
|
|
+ struct Array *dynosActions = dynos_get_action_list();
|
|
+ for (size_t i = 0; i != dynosActions->count; ++i) {
|
|
+ if (strcmp(array_get(dynosActions, i, struct DynosAction).str, funcName) == 0) {
|
|
+ return array_get(dynosActions, i, struct DynosAction).action;
|
|
+ }
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+void dynos_add_action(const char *funcName, bool (*funcPtr)(const char *), bool overwrite) {
|
|
+ struct Array *dynosActions = dynos_get_action_list();
|
|
+ for (size_t i = 0; i != dynosActions->count; ++i) {
|
|
+ if (strcmp(array_get(dynosActions, i, struct DynosAction).str, funcName) == 0) {
|
|
+ if (overwrite) {
|
|
+ array_get(dynosActions, i, struct DynosAction).action = funcPtr;
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ struct DynosAction dynosAction = { string_to_dynamic(funcName), funcPtr };
|
|
+ array_add(dynosActions, &dynosAction);
|
|
+}
|
|
+
|
|
+//
|
|
+// Utils
|
|
+//
|
|
+
|
|
+static bool dynos_is_txt_file(const char *filename, unsigned int length) {
|
|
+ return
|
|
+ length >= 4 &&
|
|
+ filename[length - 4] == '.' &&
|
|
+ filename[length - 3] == 't' &&
|
|
+ filename[length - 2] == 'x' &&
|
|
+ filename[length - 1] == 't';
|
|
+}
|
|
+
|
|
+//
|
|
+// Tokenizer
|
|
+//
|
|
+
|
|
+#define DYNOS_STR_TOKENS_MAX_LENGTH 32
|
|
+#define DYNOS_STR_TOKENS_MAX_COUNT 128
|
|
+#define DYNOS_LINE_MAX_LENGTH (DYNOS_STR_TOKENS_MAX_LENGTH * DYNOS_STR_TOKENS_MAX_COUNT)
|
|
+
|
|
+struct StrTokens {
|
|
+ char tokens[DYNOS_STR_TOKENS_MAX_COUNT][DYNOS_STR_TOKENS_MAX_LENGTH];
|
|
+ unsigned int count;
|
|
+};
|
|
+
|
|
+static struct StrTokens dynos_split_string(const char *str) {
|
|
+ struct StrTokens strtk = { .count = 0 };
|
|
+ bool treatSpacesAsChar = false;
|
|
+ for (int l = 0;; str++) {
|
|
+ char c = *str;
|
|
+ if (c == 0 || (c == ' ' && !treatSpacesAsChar) || c == '\t' || c == '\r' || c == '\n' || c == '#') {
|
|
+ if (l > 0) {
|
|
+ strtk.tokens[strtk.count][l] = 0;
|
|
+ strtk.count++;
|
|
+ if (strtk.count == DYNOS_STR_TOKENS_MAX_COUNT) {
|
|
+ break;
|
|
+ }
|
|
+ l = 0;
|
|
+ }
|
|
+ if (c == 0 || c == '#') {
|
|
+ break;
|
|
+ }
|
|
+ } else if (c == '\"') {
|
|
+ treatSpacesAsChar = !treatSpacesAsChar;
|
|
+ } else if (l < (DYNOS_STR_TOKENS_MAX_LENGTH - 1)) {
|
|
+ strtk.tokens[strtk.count][l] = c;
|
|
+ l++;
|
|
+ }
|
|
+ }
|
|
+ return strtk;
|
|
+}
|
|
+
|
|
+//
|
|
+// Types and data
|
|
+//
|
|
+
|
|
+enum DynosOptType {
|
|
+ DOPT_TOGGLE,
|
|
+ DOPT_CHOICE,
|
|
+ DOPT_SCROLL,
|
|
+ DOPT_BIND,
|
|
+ DOPT_BUTTON,
|
|
+ DOPT_SUBMENU,
|
|
+};
|
|
+
|
|
+struct DynosOption {
|
|
+ const char *name;
|
|
+ const char *configName; // Name used in sm64config.txt
|
|
+ const unsigned char *label;
|
|
+ const unsigned char *label2; // Full caps label, displayed with colored font
|
|
+ struct DynosOption *prev;
|
|
+ struct DynosOption *next;
|
|
+ struct DynosOption *parent;
|
|
+
|
|
+ enum DynosOptType type;
|
|
+ union {
|
|
+
|
|
+ // TOGGLE
|
|
+ struct Toggle {
|
|
+ bool *ptog;
|
|
+ } toggle;
|
|
+
|
|
+ // CHOICE
|
|
+ struct Choice {
|
|
+ const unsigned char **choices;
|
|
+ int count;
|
|
+ int *pindex;
|
|
+ } choice;
|
|
+
|
|
+ // SCROLL
|
|
+ struct Scroll {
|
|
+ int min;
|
|
+ int max;
|
|
+ int step;
|
|
+ int *pvalue;
|
|
+ } scroll;
|
|
+
|
|
+ // BIND
|
|
+ struct Bind {
|
|
+ unsigned int mask;
|
|
+ unsigned int *pbinds;
|
|
+ bool dynos;
|
|
+ int index;
|
|
+ } bind;
|
|
+
|
|
+ // BUTTON
|
|
+ struct Button {
|
|
+ const char *funcName;
|
|
+ } button;
|
|
+
|
|
+ // SUBMENU
|
|
+ struct Submenu {
|
|
+ struct DynosOption *child;
|
|
+ bool empty;
|
|
+ } submenu;
|
|
+ };
|
|
+};
|
|
+
|
|
+static struct DynosOption *sPrevOpt = NULL;
|
|
+static struct DynosOption *sDynosMenu = NULL;
|
|
+static struct DynosOption *sOptionsMenu = NULL;
|
|
+static const unsigned char *sDynosTextOptionsMenu;
|
|
+static const unsigned char *sDynosTextDynosMenu;
|
|
+static const unsigned char *sDynosTextDisabled;
|
|
+static const unsigned char *sDynosTextEnabled;
|
|
+static const unsigned char *sDynosTextNone;
|
|
+static const unsigned char *sDynosTextDotDotDot;
|
|
+static const unsigned char *sDynosTextA;
|
|
+static const unsigned char *sDynosTextOpenLeft;
|
|
+static const unsigned char *sDynosTextCloseLeft;
|
|
+static const unsigned char *sDynosTextOpenRight;
|
|
+static const unsigned char *sDynosTextCloseRight;
|
|
+
|
|
+//
|
|
+// Constructors
|
|
+//
|
|
+
|
|
+static struct DynosOption *dynos_add_option(const char *name, const char *configName, const char *label, const char *label2) {
|
|
+ struct DynosOption *opt = calloc(1, sizeof(struct DynosOption));
|
|
+ opt->name = string_to_dynamic(name);
|
|
+ opt->configName = string_to_configname(configName);
|
|
+ opt->label = string_to_label(label);
|
|
+ opt->label2 = string_to_label2(label2);
|
|
+ if (sPrevOpt == NULL) { // The very first option
|
|
+ opt->prev = NULL;
|
|
+ opt->next = NULL;
|
|
+ opt->parent = NULL;
|
|
+ sDynosMenu = opt;
|
|
+ } else {
|
|
+ if (sPrevOpt->type == DOPT_SUBMENU && sPrevOpt->submenu.empty) { // First option of a sub-menu
|
|
+ opt->prev = NULL;
|
|
+ opt->next = NULL;
|
|
+ opt->parent = sPrevOpt;
|
|
+ sPrevOpt->submenu.child = opt;
|
|
+ sPrevOpt->submenu.empty = false;
|
|
+ } else {
|
|
+ opt->prev = sPrevOpt;
|
|
+ opt->next = NULL;
|
|
+ opt->parent = sPrevOpt->parent;
|
|
+ sPrevOpt->next = opt;
|
|
+ }
|
|
+ }
|
|
+ sPrevOpt = opt;
|
|
+ return opt;
|
|
+}
|
|
+
|
|
+static void dynos_end_submenu() {
|
|
+ if (sPrevOpt) {
|
|
+ if (sPrevOpt->type == DOPT_SUBMENU && sPrevOpt->submenu.empty) { // ENDMENU command following a SUBMENU command
|
|
+ sPrevOpt->submenu.empty = false;
|
|
+ } else {
|
|
+ sPrevOpt = sPrevOpt->parent;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static void dynos_create_submenu(const char *name, const char *label, const char *label2) {
|
|
+ struct DynosOption *opt = dynos_add_option(name, NULL, label, label2);
|
|
+ opt->type = DOPT_SUBMENU;
|
|
+ opt->submenu.child = NULL;
|
|
+ opt->submenu.empty = true;
|
|
+}
|
|
+
|
|
+static void dynos_create_toggle(const char *name, const char *configName, const char *label, int initValue) {
|
|
+ struct DynosOption *opt = dynos_add_option(name, configName, label, NULL);
|
|
+ opt->type = DOPT_TOGGLE;
|
|
+ opt->toggle.ptog = calloc(1, sizeof(bool));
|
|
+ *opt->toggle.ptog = (unsigned char) initValue;
|
|
+}
|
|
+
|
|
+static void dynos_create_scroll(const char *name, const char *configName, const char *label, int min, int max, int step, int initValue) {
|
|
+ struct DynosOption *opt = dynos_add_option(name, configName, label, NULL);
|
|
+ opt->type = DOPT_SCROLL;
|
|
+ opt->scroll.min = min;
|
|
+ opt->scroll.max = max;
|
|
+ opt->scroll.step = step;
|
|
+ opt->scroll.pvalue = calloc(1, sizeof(int));
|
|
+ *opt->scroll.pvalue = initValue;
|
|
+}
|
|
+
|
|
+static void dynos_create_choice(const char *name, const char *configName, const char *label, const char **choices, int count, int initValue) {
|
|
+ struct DynosOption *opt = dynos_add_option(name, configName, label, NULL);
|
|
+ opt->type = DOPT_CHOICE;
|
|
+ opt->choice.choices = calloc(count, sizeof(const unsigned char *));
|
|
+ for (int i = 0; i != count; ++i) {
|
|
+ opt->choice.choices[i] = string_to_label(choices[i]);
|
|
+ }
|
|
+ opt->choice.count = count;
|
|
+ opt->choice.pindex = calloc(1, sizeof(int));
|
|
+ *opt->choice.pindex = initValue;
|
|
+}
|
|
+
|
|
+static void dynos_create_button(const char *name, const char *label, const char *funcName) {
|
|
+ struct DynosOption *opt = dynos_add_option(name, NULL, label, NULL);
|
|
+ opt->type = DOPT_BUTTON;
|
|
+ opt->button.funcName = string_to_dynamic(funcName);
|
|
+}
|
|
+
|
|
+static void dynos_create_bind(const char *name, const char *configName, const char *label, unsigned int mask, unsigned int *binds) {
|
|
+ struct DynosOption *opt = dynos_add_option(name, configName, label, NULL);
|
|
+ opt->type = DOPT_BIND;
|
|
+ opt->bind.mask = mask;
|
|
+ opt->bind.pbinds = calloc(MAX_BINDS, sizeof(unsigned int));
|
|
+ for (int i = 0; i != MAX_BINDS; ++i) {
|
|
+ opt->bind.pbinds[i] = binds[i];
|
|
+ }
|
|
+ opt->bind.dynos = true;
|
|
+ opt->bind.index = 0;
|
|
+}
|
|
+
|
|
+static void dynos_read_file(const char *folder, const char *filename) {
|
|
+
|
|
+ // Open file
|
|
+ char fullname[SYS_MAX_PATH];
|
|
+ snprintf(fullname, SYS_MAX_PATH, "%s/%s", folder, filename);
|
|
+ FILE *f = fopen(fullname, "rt");
|
|
+ if (f == NULL) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // Read file and create options
|
|
+ char buffer[DYNOS_LINE_MAX_LENGTH];
|
|
+ while (fgets(buffer, DYNOS_LINE_MAX_LENGTH, f) != NULL) {
|
|
+ struct StrTokens strtk = dynos_split_string(buffer);
|
|
+
|
|
+ // Empty line
|
|
+ if (strtk.count == 0) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ // SUBMENU [Name] [Label]
|
|
+ if (strcmp(strtk.tokens[0], "SUBMENU") == 0 && strtk.count >= 4) {
|
|
+ dynos_create_submenu(strtk.tokens[1], strtk.tokens[2], strtk.tokens[3]);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ // TOGGLE [Name] [Label] [ConfigName] [InitialValue]
|
|
+ if (strcmp(strtk.tokens[0], "TOGGLE") == 0 && strtk.count >= 5) {
|
|
+ dynos_create_toggle(strtk.tokens[1], strtk.tokens[3], strtk.tokens[2], string_to_int(strtk.tokens[4]));
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ // SCROLL [Name] [Label] [ConfigName] [InitialValue] [Min] [Max] [Step]
|
|
+ if (strcmp(strtk.tokens[0], "SCROLL") == 0 && strtk.count >= 8) {
|
|
+ dynos_create_scroll(strtk.tokens[1], strtk.tokens[3], strtk.tokens[2], string_to_int(strtk.tokens[5]), string_to_int(strtk.tokens[6]), string_to_int(strtk.tokens[7]), string_to_int(strtk.tokens[4]));
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ // CHOICE [Name] [Label] [ConfigName] [InitialValue] [ChoiceStrings...]
|
|
+ if (strcmp(strtk.tokens[0], "CHOICE") == 0 && strtk.count >= 6) {
|
|
+ const char *choices[DYNOS_STR_TOKENS_MAX_COUNT];
|
|
+ for (unsigned int i = 0; i != strtk.count - 5; ++i) {
|
|
+ choices[i] = &strtk.tokens[5 + i][0];
|
|
+ }
|
|
+ dynos_create_choice(strtk.tokens[1], strtk.tokens[3], strtk.tokens[2], choices, strtk.count - 5, string_to_int(strtk.tokens[4]));
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ // BUTTON [Name] [Label] [FuncName]
|
|
+ if (strcmp(strtk.tokens[0], "BUTTON") == 0 && strtk.count >= 4) {
|
|
+ dynos_create_button(strtk.tokens[1], strtk.tokens[2], strtk.tokens[3]);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ // BIND [Name] [Label] [ConfigName] [Mask] [DefaultValues]
|
|
+ if (strcmp(strtk.tokens[0], "BIND") == 0 && strtk.count >= 5 + MAX_BINDS) {
|
|
+ unsigned int binds[MAX_BINDS];
|
|
+ for (int i = 0; i != MAX_BINDS; ++i) {
|
|
+ binds[i] = string_to_int(strtk.tokens[5 + i]);
|
|
+ }
|
|
+ dynos_create_bind(strtk.tokens[1], strtk.tokens[3], strtk.tokens[2], string_to_int(strtk.tokens[4]), binds);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ // ENDMENU
|
|
+ if (strcmp(strtk.tokens[0], "ENDMENU") == 0) {
|
|
+ dynos_end_submenu();
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+ fclose(f);
|
|
+}
|
|
+
|
|
+static void dynos_load_options() {
|
|
+ char optionsFolder[SYS_MAX_PATH];
|
|
+ snprintf(optionsFolder, SYS_MAX_PATH, "%s/%s", sys_exe_path(), FS_BASEDIR);
|
|
+ DIR *dir = opendir(optionsFolder);
|
|
+ sPrevOpt = NULL;
|
|
+ if (dir) {
|
|
+ struct dirent *ent = NULL;
|
|
+ while ((ent = readdir(dir)) != NULL) {
|
|
+ if (dynos_is_txt_file(ent->d_name, strlen(ent->d_name))) {
|
|
+ dynos_read_file(optionsFolder, ent->d_name);
|
|
+ }
|
|
+ }
|
|
+ closedir(dir);
|
|
+ }
|
|
+}
|
|
+
|
|
+//
|
|
+// Vanilla options menu
|
|
+//
|
|
+
|
|
+#define optmenu_toggle optmenu_toggle_unused
|
|
+#define optmenu_draw optmenu_draw_unused
|
|
+#define optmenu_draw_prompt optmenu_draw_prompt_unused
|
|
+#define optmenu_check_buttons optmenu_check_buttons_unused
|
|
+#define optmenu_open optmenu_open_unused
|
|
+#define DYNOS_INL
|
|
+#include "game/options_menu.c"
|
|
+#undef DYNOS_INL
|
|
+#undef optmenu_toggle
|
|
+#undef optmenu_draw
|
|
+#undef optmenu_draw_prompt
|
|
+#undef optmenu_check_buttons
|
|
+#undef optmenu_open
|
|
+
|
|
+//
|
|
+// Vanilla actions
|
|
+//
|
|
+
|
|
+typedef void (*VanillaActionFunction)(struct Option *, int);
|
|
+struct VanillaAction {
|
|
+ const char *str;
|
|
+ VanillaActionFunction action;
|
|
+};
|
|
+
|
|
+// "Construct On First Use" aka COFU
|
|
+static struct Array *dynos_get_vanilla_action_list() {
|
|
+ static struct Array sVanillaActions = { .buffer = NULL, .count = 0, .itemSize = sizeof(struct VanillaAction) };
|
|
+ return &sVanillaActions;
|
|
+}
|
|
+
|
|
+static VanillaActionFunction dynos_get_vanilla_action(const char *name) {
|
|
+ struct Array *vanillaActions = dynos_get_vanilla_action_list();
|
|
+ for (size_t i = 0; i != vanillaActions->count; ++i) {
|
|
+ if (strcmp(array_get(vanillaActions, i, struct VanillaAction).str, name) == 0) {
|
|
+ return array_get(vanillaActions, i, struct VanillaAction).action;
|
|
+ }
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static void dynos_add_vanilla_action(const char *name, VanillaActionFunction func) {
|
|
+ struct Array *vanillaActions = dynos_get_vanilla_action_list();
|
|
+ for (size_t i = 0; i != vanillaActions->count; ++i) {
|
|
+ if (strcmp(array_get(vanillaActions, i, struct VanillaAction).str, name) == 0) {
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ struct VanillaAction vanillaAction = { name, func };
|
|
+ array_add(vanillaActions, &vanillaAction);
|
|
+}
|
|
+
|
|
+static bool dynos_call_vanilla_action(const char *optName) {
|
|
+ VanillaActionFunction func = dynos_get_vanilla_action(optName);
|
|
+ if (func) {
|
|
+ func(NULL, 0);
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+//
|
|
+// Convert classic options menu into DynOS menu
|
|
+//
|
|
+
|
|
+static struct DynosOption *dynos_convert_option(const unsigned char *label, const unsigned char *label2) {
|
|
+ struct DynosOption *opt = calloc(1, sizeof(struct DynosOption));
|
|
+ opt->name = label_to_name(label);
|
|
+ opt->configName = NULL;
|
|
+ opt->label = label;
|
|
+ opt->label2 = label2;
|
|
+ if (sPrevOpt == NULL) { // The very first option
|
|
+ opt->prev = NULL;
|
|
+ opt->next = NULL;
|
|
+ opt->parent = NULL;
|
|
+ sOptionsMenu = opt;
|
|
+ } else {
|
|
+ if (sPrevOpt->type == DOPT_SUBMENU && sPrevOpt->submenu.empty) { // First option of a sub-menu
|
|
+ opt->prev = NULL;
|
|
+ opt->next = NULL;
|
|
+ opt->parent = sPrevOpt;
|
|
+ sPrevOpt->submenu.child = opt;
|
|
+ sPrevOpt->submenu.empty = false;
|
|
+ } else {
|
|
+ opt->prev = sPrevOpt;
|
|
+ opt->next = NULL;
|
|
+ opt->parent = sPrevOpt->parent;
|
|
+ sPrevOpt->next = opt;
|
|
+ }
|
|
+ }
|
|
+ sPrevOpt = opt;
|
|
+ return opt;
|
|
+}
|
|
+
|
|
+static void dynos_convert_submenu(const unsigned char *label, const unsigned char *label2) {
|
|
+ struct DynosOption *opt = dynos_convert_option(label_decapitalize(label), label2);
|
|
+ opt->type = DOPT_SUBMENU;
|
|
+ opt->submenu.child = NULL;
|
|
+ opt->submenu.empty = true;
|
|
+}
|
|
+
|
|
+static void dynos_convert_toggle(const unsigned char *label, bool *bval) {
|
|
+ struct DynosOption *opt = dynos_convert_option(label, NULL);
|
|
+ opt->type = DOPT_TOGGLE;
|
|
+ opt->toggle.ptog = (bool *) bval;
|
|
+}
|
|
+
|
|
+static void dynos_convert_scroll(const unsigned char *label, int min, int max, int step, unsigned int *uval) {
|
|
+ struct DynosOption *opt = dynos_convert_option(label, NULL);
|
|
+ opt->type = DOPT_SCROLL;
|
|
+ opt->scroll.min = min;
|
|
+ opt->scroll.max = max;
|
|
+ opt->scroll.step = step;
|
|
+ opt->scroll.pvalue = (int *) uval;
|
|
+}
|
|
+
|
|
+static void dynos_convert_choice(const unsigned char *label, const unsigned char **choices, int count, unsigned int *uval) {
|
|
+ struct DynosOption *opt = dynos_convert_option(label, NULL);
|
|
+ opt->type = DOPT_CHOICE;
|
|
+ opt->choice.choices = choices;
|
|
+ opt->choice.count = count;
|
|
+ opt->choice.pindex = (int *) uval;
|
|
+}
|
|
+
|
|
+static void dynos_convert_button(const unsigned char *label, VanillaActionFunction action) {
|
|
+ struct DynosOption *opt = dynos_convert_option(label_decapitalize(label), NULL);
|
|
+ opt->type = DOPT_BUTTON;
|
|
+ opt->button.funcName = string_to_dynamic("dynos_call_vanilla_action");
|
|
+ dynos_add_vanilla_action(opt->name, action);
|
|
+}
|
|
+
|
|
+static void dynos_convert_bind(const unsigned char *label, unsigned int *binds) {
|
|
+ struct DynosOption *opt = dynos_convert_option(label, NULL);
|
|
+ opt->type = DOPT_BIND;
|
|
+ opt->bind.mask = 0;
|
|
+ opt->bind.pbinds = binds;
|
|
+ opt->bind.dynos = false;
|
|
+ opt->bind.index = 0;
|
|
+}
|
|
+
|
|
+static void dynos_convert_submenu_options(struct SubMenu *submenu) {
|
|
+ for (int i = 0; i != submenu->numOpts; ++i) {
|
|
+ struct Option *opt = &submenu->opts[i];
|
|
+ switch (opt->type) {
|
|
+ case OPT_TOGGLE:
|
|
+ dynos_convert_toggle(opt->label, opt->bval);
|
|
+ break;
|
|
+
|
|
+ case OPT_CHOICE:
|
|
+ dynos_convert_choice(opt->label, opt->choices, opt->numChoices, opt->uval);
|
|
+ break;
|
|
+
|
|
+ case OPT_SCROLL:
|
|
+ dynos_convert_scroll(opt->label, opt->scrMin, opt->scrMax, opt->scrStep, opt->uval);
|
|
+ break;
|
|
+
|
|
+ case OPT_SUBMENU:
|
|
+ dynos_convert_submenu(opt->label, opt->nextMenu->label);
|
|
+ dynos_convert_submenu_options(opt->nextMenu);
|
|
+ dynos_end_submenu();
|
|
+ break;
|
|
+
|
|
+ case OPT_BIND:
|
|
+ dynos_convert_bind(opt->label, opt->uval);
|
|
+ break;
|
|
+
|
|
+ case OPT_BUTTON:
|
|
+ dynos_convert_button(opt->label, opt->actionFn);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static void dynos_convert_options_menu() {
|
|
+ sPrevOpt = NULL;
|
|
+ dynos_convert_submenu_options(&menuMain);
|
|
+ dynos_add_action("dynos_call_vanilla_action", dynos_call_vanilla_action, true);
|
|
+}
|
|
+
|
|
+//
|
|
+// Loop through DynosOptions
|
|
+//
|
|
+
|
|
+typedef bool (*DynosLoopFunc)(struct DynosOption *, void *);
|
|
+static struct DynosOption *dynos_loop(struct DynosOption *opt, DynosLoopFunc func, void *data) {
|
|
+ while (opt) {
|
|
+ if (opt->type == DOPT_SUBMENU) {
|
|
+ struct DynosOption *res = dynos_loop(opt->submenu.child, func, data);
|
|
+ if (res) {
|
|
+ return res;
|
|
+ }
|
|
+ } else {
|
|
+ if (func(opt, data)) {
|
|
+ return opt;
|
|
+ }
|
|
+ }
|
|
+ opt = opt->next;
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+//
|
|
+// Inputs
|
|
+//
|
|
+
|
|
+struct KeyState {
|
|
+ bool pressed;
|
|
+ bool down;
|
|
+};
|
|
+
|
|
+struct DynosKeyboard {
|
|
+ struct KeyState *state;
|
|
+ int count;
|
|
+};
|
|
+
|
|
+struct DynosJoystick {
|
|
+ struct KeyState *state;
|
|
+ int count;
|
|
+ SDL_Joystick *joystick;
|
|
+};
|
|
+
|
|
+static struct DynosKeyboard *sDynosKeyboard = NULL;
|
|
+static struct DynosJoystick *sDynosJoystick = NULL;
|
|
+
|
|
+static void dynos_update_controllers_state() {
|
|
+
|
|
+ // Keyboard
|
|
+ int kbcount = 0;
|
|
+ const unsigned char *kbstate = SDL_GetKeyboardState(&kbcount);
|
|
+ if (sDynosKeyboard) {
|
|
+ for (int i = 0; i < sDynosKeyboard->count; ++i) {
|
|
+ if (kbstate[i]) {
|
|
+ sDynosKeyboard->state[i].pressed = !sDynosKeyboard->state[i].down;
|
|
+ sDynosKeyboard->state[i].down = true;
|
|
+ } else {
|
|
+ sDynosKeyboard->state[i].pressed = false;
|
|
+ sDynosKeyboard->state[i].down = false;
|
|
+ }
|
|
+ }
|
|
+ } else if (kbcount > 0) {
|
|
+ sDynosKeyboard = calloc(1, sizeof(struct DynosKeyboard));
|
|
+ sDynosKeyboard->count = kbcount;
|
|
+ sDynosKeyboard->state = calloc(kbcount, sizeof(struct KeyState));
|
|
+ }
|
|
+
|
|
+ // Joysticks
|
|
+ if (sDynosJoystick) {
|
|
+ if (!SDL_JoystickGetAttached(sDynosJoystick->joystick)) { // Failsafe if the joystick is disconnected during game
|
|
+ free(sDynosJoystick);
|
|
+ sDynosJoystick = NULL;
|
|
+ } else {
|
|
+ for (int i = 0; i < sDynosJoystick->count; ++i) {
|
|
+ if (SDL_JoystickGetButton(sDynosJoystick->joystick, i)) {
|
|
+ sDynosJoystick->state[i].pressed = !sDynosJoystick->state[i].down;
|
|
+ sDynosJoystick->state[i].down = true;
|
|
+ } else {
|
|
+ sDynosJoystick->state[i].pressed = false;
|
|
+ sDynosJoystick->state[i].down = false;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ SDL_Joystick *joystick = SDL_JoystickOpen(0);
|
|
+ if (joystick) {
|
|
+ sDynosJoystick = calloc(1, sizeof(struct DynosJoystick));
|
|
+ sDynosJoystick->count = SDL_JoystickNumButtons(joystick);
|
|
+ sDynosJoystick->state = calloc(sDynosJoystick->count, sizeof(struct KeyState));
|
|
+ sDynosJoystick->joystick = joystick;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static bool dynos_update_controller_from_keyboard(struct DynosOption *opt, void *data) {
|
|
+ if (opt->type == DOPT_BIND) {
|
|
+ struct Controller *controller = (struct Controller *) data;
|
|
+ for (int i = 0; i != MAX_BINDS; ++i) {
|
|
+ int scancode = (int) opt->bind.pbinds[i];
|
|
+ if (scancode < sDynosKeyboard->count) {
|
|
+ controller->buttonPressed |= opt->bind.mask * (sDynosKeyboard->state[scancode].pressed);
|
|
+ controller->buttonDown |= opt->bind.mask * (sDynosKeyboard->state[scancode].down);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+static bool dynos_update_controller_from_joystick(struct DynosOption *opt, void *data) {
|
|
+ if (opt->type == DOPT_BIND) {
|
|
+ struct Controller *controller = (struct Controller *) data;
|
|
+ for (int i = 0; i != MAX_BINDS; ++i) {
|
|
+ int scancode = (int) opt->bind.pbinds[i] - 0x1000;
|
|
+ if (scancode < sDynosJoystick->count) {
|
|
+ controller->buttonPressed |= opt->bind.mask * (sDynosJoystick->state[scancode].pressed);
|
|
+ controller->buttonDown |= opt->bind.mask * (sDynosJoystick->state[scancode].down);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+static void dynos_update_controller() {
|
|
+ static clock_t last = 0;
|
|
+ clock_t curr = clock();
|
|
+
|
|
+ // Prevent the game from updating inputs twice or more per frame
|
|
+ // The delay between 2 consecutive updates must be at least 16 ms
|
|
+ if ((curr - last) >= (CLOCKS_PER_SEC / 60)) {
|
|
+ dynos_update_controllers_state();
|
|
+ if (sDynosKeyboard) dynos_loop(sDynosMenu, dynos_update_controller_from_keyboard, (void *) &gControllers[0]);
|
|
+ if (sDynosJoystick) dynos_loop(sDynosMenu, dynos_update_controller_from_joystick, (void *) &gControllers[0]);
|
|
+ last = curr;
|
|
+ }
|
|
+}
|
|
+
|
|
+//
|
|
+// Config
|
|
+//
|
|
+
|
|
+static const char *sDynosConfigFilename = "DynOSconfig.cfg";
|
|
+
|
|
+static bool dynos_get_option_config(struct DynosOption *opt, void *data) {
|
|
+ unsigned char type = *(unsigned char *) ((void **) data)[0];
|
|
+ const char *name = (const char *) ((void **) data)[1];
|
|
+ return (opt->configName != NULL && strcmp(opt->configName, name) == 0 && opt->type == type);
|
|
+}
|
|
+
|
|
+static bool dynos_read_config_type_and_name(FILE *f, unsigned char *type, char *name) {
|
|
+
|
|
+ // Read type
|
|
+ if (fread(type, sizeof(unsigned char), 1, f) != 1) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ // Read string length
|
|
+ unsigned char len = 0;
|
|
+ if (fread(&len, sizeof(unsigned char), 1, f) != 1) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ // Read config name
|
|
+ if (fread(name, sizeof(char), len, f) != len) {
|
|
+ return false;
|
|
+ }
|
|
+ name[len] = 0;
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static void dynos_load_config() {
|
|
+ char filename[SYS_MAX_PATH];
|
|
+ snprintf(filename, SYS_MAX_PATH, "%s/%s", sys_user_path(), sDynosConfigFilename);
|
|
+ FILE *f = fopen(filename, "rb");
|
|
+ if (f == NULL) return;
|
|
+ while (true) {
|
|
+ unsigned char type;
|
|
+ char name[DYNOS_STR_TOKENS_MAX_LENGTH];
|
|
+ if (!dynos_read_config_type_and_name(f, &type, name)) {
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ struct DynosOption *opt = dynos_loop(sDynosMenu, dynos_get_option_config, (void **) (void *[]){ &type, name });
|
|
+ if (opt != NULL) {
|
|
+ switch (opt->type) {
|
|
+ case DOPT_TOGGLE:
|
|
+ fread(opt->toggle.ptog, sizeof(bool), 1, f);
|
|
+ break;
|
|
+
|
|
+ case DOPT_CHOICE:
|
|
+ fread(opt->choice.pindex, sizeof(int), 1, f);
|
|
+ break;
|
|
+
|
|
+ case DOPT_SCROLL:
|
|
+ fread(opt->scroll.pvalue, sizeof(int), 1, f);
|
|
+ break;
|
|
+
|
|
+ case DOPT_BIND:
|
|
+ fread(opt->bind.pbinds, sizeof(unsigned int), MAX_BINDS, f);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ fclose(f);
|
|
+}
|
|
+
|
|
+static void dynos_write_config_type_and_name(FILE *f, unsigned char type, const char *name) {
|
|
+ unsigned char len = (unsigned char) strlen(name);
|
|
+ fwrite(&type, sizeof(unsigned char), 1, f);
|
|
+ fwrite(&len, sizeof(unsigned char), 1, f);
|
|
+ fwrite(name, sizeof(char), len, f);
|
|
+}
|
|
+
|
|
+static bool dynos_save_option_config(struct DynosOption *opt, void *data) {
|
|
+ if (opt->configName != NULL) {
|
|
+ FILE *f = (FILE *) data;
|
|
+ switch (opt->type) {
|
|
+ case DOPT_TOGGLE:
|
|
+ dynos_write_config_type_and_name(f, DOPT_TOGGLE, opt->configName);
|
|
+ fwrite(opt->toggle.ptog, sizeof(bool), 1, f);
|
|
+ break;
|
|
+
|
|
+ case DOPT_CHOICE:
|
|
+ dynos_write_config_type_and_name(f, DOPT_CHOICE, opt->configName);
|
|
+ fwrite(opt->choice.pindex, sizeof(int), 1, f);
|
|
+ break;
|
|
+
|
|
+ case DOPT_SCROLL:
|
|
+ dynos_write_config_type_and_name(f, DOPT_SCROLL, opt->configName);
|
|
+ fwrite(opt->scroll.pvalue, sizeof(int), 1, f);
|
|
+ break;
|
|
+
|
|
+ case DOPT_BIND:
|
|
+ dynos_write_config_type_and_name(f, DOPT_BIND, opt->configName);
|
|
+ fwrite(opt->bind.pbinds, sizeof(unsigned int), MAX_BINDS, f);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void dynos_save_config() {
|
|
+ char filename[SYS_MAX_PATH];
|
|
+ snprintf(filename, SYS_MAX_PATH, "%s/%s", sys_user_path(), sDynosConfigFilename);
|
|
+ FILE *f = fopen(filename, "wb");
|
|
+ if (f == NULL) return;
|
|
+ dynos_loop(sDynosMenu, dynos_save_option_config, (void *) f);
|
|
+ fclose(f);
|
|
+}
|
|
+
|
|
+//
|
|
+// Get/Set values
|
|
+//
|
|
+
|
|
+static bool dynos_get(struct DynosOption *opt, void *data) {
|
|
+ return (opt->type == DOPT_TOGGLE || opt->type == DOPT_CHOICE || opt->type == DOPT_SCROLL) && (strcmp(opt->name, (const char *) data) == 0);
|
|
+}
|
|
+
|
|
+int dynos_get_value(const char *name) {
|
|
+ struct DynosOption *opt = dynos_loop(sDynosMenu, dynos_get, (void *) name);
|
|
+ if (opt) {
|
|
+ if (opt->type == DOPT_TOGGLE) {
|
|
+ return (int) *opt->toggle.ptog;
|
|
+ }
|
|
+ if (opt->type == DOPT_CHOICE) {
|
|
+ return *opt->choice.pindex;
|
|
+ }
|
|
+ if (opt->type == DOPT_SCROLL) {
|
|
+ return *opt->scroll.pvalue;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void dynos_set_value(const char *name, int value) {
|
|
+ struct DynosOption *opt = dynos_loop(sDynosMenu, dynos_get, (void *) name);
|
|
+ if (opt) {
|
|
+ if (opt->type == DOPT_CHOICE) {
|
|
+ *opt->toggle.ptog = (bool) value;
|
|
+ }
|
|
+ if (opt->type == DOPT_CHOICE) {
|
|
+ *opt->choice.pindex = value;
|
|
+ }
|
|
+ if (opt->type == DOPT_SCROLL) {
|
|
+ *opt->scroll.pvalue = value;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+//
|
|
+// Render
|
|
+//
|
|
+
|
|
+static bool sIsBinding = 0;
|
|
+static struct DynosOption *sCurrentMenu = NULL;
|
|
+static struct DynosOption *sCurrentOpt = NULL;
|
|
+
|
|
+static const unsigned char sDialogCharWidths[256] = {
|
|
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6,
|
|
+ 6, 6, 5, 6, 6, 5, 8, 8, 6, 6, 6, 6, 6, 5, 6, 6,
|
|
+ 8, 7, 6, 6, 6, 5, 5, 6, 5, 5, 6, 5, 4, 5, 5, 3,
|
|
+ 7, 5, 5, 5, 6, 5, 5, 5, 5, 5, 7, 7, 5, 5, 4, 4,
|
|
+ 8, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
+ 8, 8, 8, 8, 7, 7, 6, 7, 7, 0, 0, 0, 0, 0, 0, 0,
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6,
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
+ 7, 5, 10, 5, 9, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
+ 0, 0, 5, 7, 7, 6, 6, 8, 0, 8, 10, 6, 4, 5, 0, 0
|
|
+};
|
|
+
|
|
+static int dynos_get_render_string_length(const unsigned char *str64) {
|
|
+ int length = 0;
|
|
+ for (; *str64 != DIALOG_CHAR_TERMINATOR; ++str64) {
|
|
+ length += (int) sDialogCharWidths[*str64];
|
|
+ }
|
|
+ return length;
|
|
+}
|
|
+
|
|
+static void dynos_render_string(const unsigned char *str64, int x, int y) {
|
|
+ create_dl_translation_matrix(MENU_MTX_PUSH, x, y, 0);
|
|
+ for (; *str64 != DIALOG_CHAR_TERMINATOR; ++str64) {
|
|
+ if (*str64 != DIALOG_CHAR_SPACE) {
|
|
+ if (*str64 == 253) { // underscore
|
|
+ create_dl_translation_matrix(MENU_MTX_NOPUSH, -1, -5, 0);
|
|
+ void **fontLUT = (void **) segmented_to_virtual(main_font_lut);
|
|
+ void *packedTexture = segmented_to_virtual(fontLUT[159]);
|
|
+ gDPPipeSync(gDisplayListHead++);
|
|
+ gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_16b, 1, VIRTUAL_TO_PHYSICAL(packedTexture));
|
|
+ gSPDisplayList(gDisplayListHead++, dl_ia_text_tex_settings);
|
|
+ create_dl_translation_matrix(MENU_MTX_NOPUSH, 0, +5, 0);
|
|
+ } else {
|
|
+ void **fontLUT = (void **) segmented_to_virtual(main_font_lut);
|
|
+ void *packedTexture = segmented_to_virtual(fontLUT[*str64]);
|
|
+ gDPPipeSync(gDisplayListHead++);
|
|
+ gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_16b, 1, VIRTUAL_TO_PHYSICAL(packedTexture));
|
|
+ gSPDisplayList(gDisplayListHead++, dl_ia_text_tex_settings);
|
|
+ }
|
|
+ }
|
|
+ create_dl_translation_matrix(MENU_MTX_NOPUSH, sDialogCharWidths[*str64], 0, 0);
|
|
+ }
|
|
+ gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
|
+}
|
|
+
|
|
+static void dynos_print_string(const unsigned char *str64, int x, int y, unsigned int rgbaFront, unsigned int rgbaBack, bool alignLeft) {
|
|
+ gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
|
|
+ if ((rgbaBack & 0xFF) != 0) {
|
|
+ gDPSetEnvColor(gDisplayListHead++, ((rgbaBack >> 24) & 0xFF), ((rgbaBack >> 16) & 0xFF), ((rgbaBack >> 8) & 0xFF), ((rgbaBack >> 0) & 0xFF));
|
|
+ if (alignLeft) {
|
|
+ dynos_render_string(str64, GFX_DIMENSIONS_FROM_LEFT_EDGE(x) + 1, y - 1);
|
|
+ } else {
|
|
+ dynos_render_string(str64, GFX_DIMENSIONS_FROM_RIGHT_EDGE(x + dynos_get_render_string_length(str64) - 1), y - 1);
|
|
+ }
|
|
+ }
|
|
+ if ((rgbaFront & 0xFF) != 0) {
|
|
+ gDPSetEnvColor(gDisplayListHead++, ((rgbaFront >> 24) & 0xFF), ((rgbaFront >> 16) & 0xFF), ((rgbaFront >> 8) & 0xFF), ((rgbaFront >> 0) & 0xFF));
|
|
+ if (alignLeft) {
|
|
+ dynos_render_string(str64, GFX_DIMENSIONS_FROM_LEFT_EDGE(x), y);
|
|
+ } else {
|
|
+ dynos_render_string(str64, GFX_DIMENSIONS_FROM_RIGHT_EDGE(x + dynos_get_render_string_length(str64)), y);
|
|
+ }
|
|
+ }
|
|
+ gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
|
|
+ gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
|
+}
|
|
+
|
|
+static void dynos_print_box(int x, int y, int w, int h, unsigned int rgbaColor, bool alignLeft) {
|
|
+ if ((rgbaColor && 0xFF) != 0) {
|
|
+ Mtx *matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
|
|
+ if (!matrix) return;
|
|
+ if (alignLeft) {
|
|
+ create_dl_translation_matrix(MENU_MTX_PUSH, GFX_DIMENSIONS_FROM_LEFT_EDGE(x), y + h, 0);
|
|
+ } else {
|
|
+ create_dl_translation_matrix(MENU_MTX_PUSH, GFX_DIMENSIONS_FROM_RIGHT_EDGE(x + w), y + h, 0);
|
|
+ }
|
|
+ guScale(matrix, (float) w / 130.f, (float) h / 80.f, 1.f);
|
|
+ gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
|
|
+ gDPSetEnvColor(gDisplayListHead++, ((rgbaColor >> 24) & 0xFF), ((rgbaColor >> 16) & 0xFF), ((rgbaColor >> 8) & 0xFF), ((rgbaColor >> 0) & 0xFF));
|
|
+ gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
|
|
+ gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
|
+ gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
|
+ }
|
|
+}
|
|
+
|
|
+static inline int dynos_get_label2_x(int x, const unsigned char *str) {
|
|
+ int len = 0;
|
|
+ while (*str != GLOBAR_CHAR_TERMINATOR) ++str, ++len;
|
|
+ return x - len * 6; // stride is 12
|
|
+}
|
|
+
|
|
+//
|
|
+// Options menu
|
|
+//
|
|
+
|
|
+static int dynos_get_option_count() {
|
|
+ struct DynosOption *opt = sCurrentOpt;
|
|
+ while (opt->prev) {
|
|
+ opt = opt->prev;
|
|
+ }
|
|
+ int count = 0;
|
|
+ while (opt) {
|
|
+ opt = opt->next;
|
|
+ count++;
|
|
+ }
|
|
+ return count;
|
|
+}
|
|
+
|
|
+static int dynos_get_current_option_index() {
|
|
+ struct DynosOption *opt = sCurrentOpt;
|
|
+ int index = 0;
|
|
+ while (opt->prev) {
|
|
+ opt = opt->prev;
|
|
+ index++;
|
|
+ }
|
|
+ return index;
|
|
+}
|
|
+
|
|
+#define PREV(opt) (opt == NULL ? NULL : opt->prev)
|
|
+#define NEXT(opt) (opt == NULL ? NULL : opt->next)
|
|
+static struct DynosOption **dynos_get_options_to_draw() {
|
|
+ static struct DynosOption *sOptionList[13];
|
|
+ bzero(sOptionList, 13 * sizeof(struct DynosOption *));
|
|
+
|
|
+ sOptionList[6] = sCurrentOpt;
|
|
+ sOptionList[5] = PREV(sOptionList[6]);
|
|
+ sOptionList[4] = PREV(sOptionList[5]);
|
|
+ sOptionList[3] = PREV(sOptionList[4]);
|
|
+ sOptionList[2] = PREV(sOptionList[3]);
|
|
+ sOptionList[1] = PREV(sOptionList[2]);
|
|
+ sOptionList[0] = PREV(sOptionList[1]);
|
|
+ sOptionList[7] = NEXT(sOptionList[6]);
|
|
+ sOptionList[8] = NEXT(sOptionList[7]);
|
|
+ sOptionList[9] = NEXT(sOptionList[8]);
|
|
+ sOptionList[10] = NEXT(sOptionList[9]);
|
|
+ sOptionList[11] = NEXT(sOptionList[10]);
|
|
+ sOptionList[12] = NEXT(sOptionList[11]);
|
|
+
|
|
+ int start = 12, end = 0;
|
|
+ for (int i = 0; i != 13; ++i) {
|
|
+ if (sOptionList[i] != NULL) {
|
|
+ start = MIN(start, i);
|
|
+ end = MAX(end, i);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (end - start < 7) {
|
|
+ return &sOptionList[start];
|
|
+ }
|
|
+ if (end <= 9) {
|
|
+ return &sOptionList[end - 6];
|
|
+ }
|
|
+ if (start >= 3) {
|
|
+ return &sOptionList[start];
|
|
+ }
|
|
+ return &sOptionList[3];
|
|
+}
|
|
+#undef PREV
|
|
+#undef NEXT
|
|
+
|
|
+#define COLOR_WHITE 0xFFFFFFFF
|
|
+#define COLOR_BLACK 0x000000FF
|
|
+#define COLOR_GRAY 0xA0A0A0FF
|
|
+#define COLOR_DARK_GRAY 0x808080FF
|
|
+#define COLOR_SELECT 0x80E0FFFF
|
|
+#define COLOR_SELECT_BOX 0x00FFFF20
|
|
+#define COLOR_ENABLED 0x20E020FF
|
|
+#define COLOR_DISABLED 0xFF2020FF
|
|
+#define OFFSET_FROM_LEFT_EDGE 64
|
|
+#define OFFSET_FROM_RIGHT_EDGE 64
|
|
+
|
|
+static void dynos_draw_option(struct DynosOption *opt, int y) {
|
|
+ if (opt == NULL) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // Selected box
|
|
+ if (opt == sCurrentOpt) {
|
|
+ unsigned char a = (unsigned char) ((coss(gGlobalTimer * 0x800) + 1.f) * 0x20);
|
|
+ dynos_print_box(OFFSET_FROM_LEFT_EDGE - 4, y - 2, GFX_DIMENSIONS_FROM_RIGHT_EDGE(OFFSET_FROM_RIGHT_EDGE) - GFX_DIMENSIONS_FROM_LEFT_EDGE(OFFSET_FROM_LEFT_EDGE) + 8, 20, COLOR_SELECT_BOX + a, 1);
|
|
+ }
|
|
+
|
|
+ // Label
|
|
+ if (opt == sCurrentOpt) {
|
|
+ dynos_print_string(opt->label, OFFSET_FROM_LEFT_EDGE, y, COLOR_SELECT, COLOR_BLACK, 1);
|
|
+ } else {
|
|
+ dynos_print_string(opt->label, OFFSET_FROM_LEFT_EDGE, y, COLOR_WHITE, COLOR_BLACK, 1);
|
|
+ }
|
|
+
|
|
+ // Values
|
|
+ int w;
|
|
+ switch (opt->type) {
|
|
+ case DOPT_TOGGLE:
|
|
+ if (*opt->toggle.ptog) {
|
|
+ dynos_print_string(sDynosTextEnabled, OFFSET_FROM_RIGHT_EDGE, y, COLOR_ENABLED, COLOR_BLACK, 0);
|
|
+ } else {
|
|
+ dynos_print_string(sDynosTextDisabled, OFFSET_FROM_RIGHT_EDGE, y, COLOR_DISABLED, COLOR_BLACK, 0);
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case DOPT_CHOICE:
|
|
+ dynos_print_string(opt->choice.choices[*opt->choice.pindex], OFFSET_FROM_RIGHT_EDGE, y, opt == sCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
|
|
+ break;
|
|
+
|
|
+ case DOPT_SCROLL:
|
|
+ w = 80 * (float)(*opt->scroll.pvalue - opt->scroll.min) / (float)(opt->scroll.max - opt->scroll.min);
|
|
+ dynos_print_string(int_to_string("%d", *opt->scroll.pvalue), OFFSET_FROM_RIGHT_EDGE, y, opt == sCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
|
|
+ dynos_print_box(OFFSET_FROM_RIGHT_EDGE + 28, y + 4, 82, 8, COLOR_DARK_GRAY, 0);
|
|
+ dynos_print_box(OFFSET_FROM_RIGHT_EDGE + 29 + 80 - w, y + 5, w, 6, opt == sCurrentOpt ? COLOR_SELECT : COLOR_WHITE, 0);
|
|
+ break;
|
|
+
|
|
+ case DOPT_BIND:
|
|
+ for (int i = 0; i != MAX_BINDS; ++i) {
|
|
+ unsigned int bind = opt->bind.pbinds[i];
|
|
+ if (opt == sCurrentOpt && i == opt->bind.index) {
|
|
+ if (sIsBinding) {
|
|
+ dynos_print_string(sDynosTextDotDotDot, OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, y, COLOR_SELECT, COLOR_BLACK, 0);
|
|
+ } else if (bind == VK_INVALID) {
|
|
+ dynos_print_string(sDynosTextNone, OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, y, COLOR_SELECT, COLOR_BLACK, 0);
|
|
+ } else {
|
|
+ dynos_print_string(int_to_string("%04X", bind), OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, y, COLOR_SELECT, COLOR_BLACK, 0);
|
|
+ }
|
|
+ } else {
|
|
+ if (bind == VK_INVALID) {
|
|
+ dynos_print_string(sDynosTextNone, OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, y, COLOR_GRAY, COLOR_BLACK, 0);
|
|
+ } else {
|
|
+ dynos_print_string(int_to_string("%04X", bind), OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, y, COLOR_WHITE, COLOR_BLACK, 0);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case DOPT_BUTTON:
|
|
+ break;
|
|
+
|
|
+ case DOPT_SUBMENU:
|
|
+ if (opt == sCurrentOpt) {
|
|
+ dynos_print_string(sDynosTextA, OFFSET_FROM_RIGHT_EDGE, y, COLOR_SELECT, COLOR_BLACK, 0);
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void dynos_draw_menu() {
|
|
+ if (sCurrentMenu == NULL) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // Colorful label
|
|
+ const unsigned char *label2 = (sCurrentOpt->parent ? sCurrentOpt->parent->label2 : (sCurrentMenu == sDynosMenu ? sDynosTextDynosMenu : sDynosTextOptionsMenu));
|
|
+ gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
|
|
+ gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
|
+ print_hud_lut_string(HUD_LUT_GLOBAL, dynos_get_label2_x(SCREEN_WIDTH / 2, label2), 40, label2);
|
|
+ gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
|
|
+
|
|
+ // Display options
|
|
+ struct DynosOption **optionsToDraw = dynos_get_options_to_draw();
|
|
+ for (int i = 0; i != 7; ++i) {
|
|
+ dynos_draw_option(optionsToDraw[i], 156 - 20 * i);
|
|
+ }
|
|
+
|
|
+ // Scroll bar
|
|
+ int optCount = dynos_get_option_count();
|
|
+ int optIndex = dynos_get_current_option_index();
|
|
+ if (optCount > 7) {
|
|
+ int h = (int) (134.f * sqrtf(1.f / (optCount - 6)));
|
|
+ int y = 37 + (134 - h) * (1.f - MAX(0.f, MIN(1.f, (float)(optIndex - 3) / (float)(optCount - 6))));
|
|
+ dynos_print_box(OFFSET_FROM_RIGHT_EDGE - 16, 36, 8, 136, COLOR_DARK_GRAY, 0);
|
|
+ dynos_print_box(OFFSET_FROM_RIGHT_EDGE - 15, y, 6, h, COLOR_WHITE, 0);
|
|
+ }
|
|
+}
|
|
+
|
|
+//
|
|
+// Processing
|
|
+//
|
|
+
|
|
+#define SOUND_DYNOS_SAVED (SOUND_MENU_MARIO_CASTLE_WARP2 | (0xFF << 8))
|
|
+#define SOUND_DYNOS_SELECT (SOUND_MENU_CHANGE_SELECT | (0xF8 << 8))
|
|
+#define SOUND_DYNOS_OK (SOUND_MENU_CHANGE_SELECT | (0xF8 << 8))
|
|
+#define SOUND_DYNOS_CANCEL (SOUND_MENU_CAMERA_BUZZ | (0xFC << 8))
|
|
+
|
|
+enum {
|
|
+ INPUT_LEFT,
|
|
+ INPUT_RIGHT,
|
|
+ INPUT_A,
|
|
+ INPUT_Z
|
|
+};
|
|
+
|
|
+enum {
|
|
+ RESULT_NONE,
|
|
+ RESULT_OK,
|
|
+ RESULT_CANCEL
|
|
+};
|
|
+
|
|
+static int dynos_get_keyboard_key() {
|
|
+ if (sDynosKeyboard) {
|
|
+ for (int i = 0; i < sDynosKeyboard->count; ++i) {
|
|
+ if (sDynosKeyboard->state[i].pressed) {
|
|
+ return i;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return VK_INVALID;
|
|
+}
|
|
+
|
|
+static int dynos_get_joystick_key() {
|
|
+ if (sDynosJoystick) {
|
|
+ for (int i = 0; i < sDynosJoystick->count; ++i) {
|
|
+ if (sDynosJoystick->state[i].pressed) {
|
|
+ return i + 0x1000;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return VK_INVALID;
|
|
+}
|
|
+
|
|
+static int dynos_get_raw_key() {
|
|
+ int key = dynos_get_joystick_key();
|
|
+ if (key == VK_INVALID) key = dynos_get_keyboard_key();
|
|
+ return key;
|
|
+}
|
|
+
|
|
+static int dynos_opt_process_input(struct DynosOption *opt, int input) {
|
|
+ switch (opt->type) {
|
|
+ case DOPT_TOGGLE:
|
|
+ if (input == INPUT_LEFT) {
|
|
+ *opt->toggle.ptog = false;
|
|
+ return RESULT_OK;
|
|
+ }
|
|
+ if (input == INPUT_RIGHT) {
|
|
+ *opt->toggle.ptog = true;
|
|
+ return RESULT_OK;
|
|
+ }
|
|
+ if (input == INPUT_A) {
|
|
+ *opt->toggle.ptog = !(*opt->toggle.ptog);
|
|
+ return RESULT_OK;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case DOPT_CHOICE:
|
|
+ if (input == INPUT_LEFT) {
|
|
+ *opt->choice.pindex = (*opt->choice.pindex + opt->choice.count - 1) % (opt->choice.count);
|
|
+ return RESULT_OK;
|
|
+ }
|
|
+ if (input == INPUT_RIGHT || input == INPUT_A) {
|
|
+ *opt->choice.pindex = (*opt->choice.pindex + 1) % (opt->choice.count);
|
|
+ return RESULT_OK;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case DOPT_SCROLL:
|
|
+ if (input == INPUT_LEFT) {
|
|
+ *opt->scroll.pvalue = MAX(opt->scroll.min, *opt->scroll.pvalue - opt->scroll.step * (gPlayer1Controller->buttonDown & A_BUTTON ? 5 : 1));
|
|
+ return RESULT_OK;
|
|
+ }
|
|
+ if (input == INPUT_RIGHT) {
|
|
+ *opt->scroll.pvalue = MIN(opt->scroll.max, *opt->scroll.pvalue + opt->scroll.step * (gPlayer1Controller->buttonDown & A_BUTTON ? 5 : 1));
|
|
+ return RESULT_OK;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case DOPT_BIND:
|
|
+ if (input == INPUT_LEFT) {
|
|
+ opt->bind.index = MAX(0, opt->bind.index - 1);
|
|
+ return RESULT_OK;
|
|
+ }
|
|
+ if (input == INPUT_RIGHT) {
|
|
+ opt->bind.index = MIN(MAX_BINDS - 1, opt->bind.index + 1);
|
|
+ return RESULT_OK;
|
|
+ }
|
|
+ if (input == INPUT_Z) {
|
|
+ opt->bind.pbinds[opt->bind.index] = VK_INVALID;
|
|
+ return RESULT_OK;
|
|
+ }
|
|
+ if (input == INPUT_A) {
|
|
+ opt->bind.pbinds[opt->bind.index] = VK_INVALID;
|
|
+ sIsBinding = true;
|
|
+ controller_get_raw_key();
|
|
+ return RESULT_OK;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case DOPT_BUTTON:
|
|
+ if (input == INPUT_A && opt->button.funcName != NULL) {
|
|
+ DynosActionFunction action = dynos_get_action(opt->button.funcName);
|
|
+ if (action != NULL && action(opt->name)) {
|
|
+ return RESULT_OK;
|
|
+ }
|
|
+ return RESULT_CANCEL;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case DOPT_SUBMENU:
|
|
+ if (input == INPUT_A) {
|
|
+ if (opt->submenu.child != NULL) {
|
|
+ sCurrentOpt = opt->submenu.child;
|
|
+ return RESULT_OK;
|
|
+ }
|
|
+ return RESULT_CANCEL;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ return RESULT_NONE;
|
|
+}
|
|
+
|
|
+static void dynos_open(struct DynosOption *menu) {
|
|
+ play_sound(SOUND_DYNOS_SELECT, gDefaultSoundArgs);
|
|
+ sCurrentMenu = menu;
|
|
+ sCurrentOpt = menu;
|
|
+}
|
|
+
|
|
+static void dynos_close() {
|
|
+ if (sCurrentMenu != NULL) {
|
|
+ play_sound(SOUND_DYNOS_SAVED, gDefaultSoundArgs);
|
|
+ controller_reconfigure();
|
|
+ configfile_save(configfile_name());
|
|
+ dynos_save_config();
|
|
+ sCurrentMenu = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void dynos_process_inputs() {
|
|
+ static int sStickTimer = 0;
|
|
+ static bool sPrevStick = 0;
|
|
+
|
|
+ // Stick values
|
|
+ float stickX = gPlayer1Controller->stickX;
|
|
+ float stickY = gPlayer1Controller->stickY;
|
|
+ if (absx(stickX) > 60 || absx(stickY) > 60) {
|
|
+ if (sStickTimer == 0) {
|
|
+ sStickTimer = (sPrevStick ? 2 : 9);
|
|
+ } else {
|
|
+ stickX = 0;
|
|
+ stickY = 0;
|
|
+ sStickTimer--;
|
|
+ }
|
|
+ sPrevStick = true;
|
|
+ } else {
|
|
+ sStickTimer = 0;
|
|
+ sPrevStick = false;
|
|
+ }
|
|
+
|
|
+ // Key binding
|
|
+ if (sIsBinding) {
|
|
+ unsigned int key = (sCurrentOpt->bind.dynos ? (unsigned int) dynos_get_raw_key() : controller_get_raw_key());
|
|
+ if (key != VK_INVALID) {
|
|
+ play_sound(SOUND_DYNOS_SELECT, gDefaultSoundArgs);
|
|
+ sCurrentOpt->bind.pbinds[sCurrentOpt->bind.index] = key;
|
|
+ sIsBinding = false;
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (sCurrentMenu != NULL) {
|
|
+
|
|
+ // Up
|
|
+ if (stickY > +60) {
|
|
+ if (sCurrentOpt->prev != NULL) {
|
|
+ sCurrentOpt = sCurrentOpt->prev;
|
|
+ } else {
|
|
+ while (sCurrentOpt->next) sCurrentOpt = sCurrentOpt->next;
|
|
+ }
|
|
+ play_sound(SOUND_DYNOS_SELECT, gDefaultSoundArgs);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // Down
|
|
+ if (stickY < -60) {
|
|
+ if (sCurrentOpt->next != NULL) {
|
|
+ sCurrentOpt = sCurrentOpt->next;
|
|
+ } else {
|
|
+ while (sCurrentOpt->prev) sCurrentOpt = sCurrentOpt->prev;
|
|
+ }
|
|
+ play_sound(SOUND_DYNOS_SELECT, gDefaultSoundArgs);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // Left
|
|
+ if (stickX < -60) {
|
|
+ switch (dynos_opt_process_input(sCurrentOpt, INPUT_LEFT)) {
|
|
+ case RESULT_OK: play_sound(SOUND_DYNOS_OK, gDefaultSoundArgs); break;
|
|
+ case RESULT_CANCEL: play_sound(SOUND_DYNOS_CANCEL, gDefaultSoundArgs); break;
|
|
+ case RESULT_NONE: break;
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // Right
|
|
+ if (stickX > +60) {
|
|
+ switch (dynos_opt_process_input(sCurrentOpt, INPUT_RIGHT)) {
|
|
+ case RESULT_OK: play_sound(SOUND_DYNOS_OK, gDefaultSoundArgs); break;
|
|
+ case RESULT_CANCEL: play_sound(SOUND_DYNOS_CANCEL, gDefaultSoundArgs); break;
|
|
+ case RESULT_NONE: break;
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // A
|
|
+ if (gPlayer1Controller->buttonPressed & A_BUTTON) {
|
|
+ switch (dynos_opt_process_input(sCurrentOpt, INPUT_A)) {
|
|
+ case RESULT_OK: play_sound(SOUND_DYNOS_OK, gDefaultSoundArgs); break;
|
|
+ case RESULT_CANCEL: play_sound(SOUND_DYNOS_CANCEL, gDefaultSoundArgs); break;
|
|
+ case RESULT_NONE: break;
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // B
|
|
+ if (gPlayer1Controller->buttonPressed & B_BUTTON) {
|
|
+ if (sCurrentOpt->parent != NULL) {
|
|
+ sCurrentOpt = sCurrentOpt->parent;
|
|
+ play_sound(SOUND_DYNOS_SELECT, gDefaultSoundArgs);
|
|
+ } else {
|
|
+ dynos_close();
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // Z
|
|
+ if (gPlayer1Controller->buttonPressed & Z_TRIG) {
|
|
+ switch (dynos_opt_process_input(sCurrentOpt, INPUT_Z)) {
|
|
+ case RESULT_OK: play_sound(SOUND_DYNOS_OK, gDefaultSoundArgs); break;
|
|
+ case RESULT_CANCEL: play_sound(SOUND_DYNOS_CANCEL, gDefaultSoundArgs); break;
|
|
+ case RESULT_NONE:
|
|
+ if (sCurrentMenu == sDynosMenu) {
|
|
+ dynos_close();
|
|
+ } else {
|
|
+ dynos_open(sDynosMenu);
|
|
+ } break;
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // R
|
|
+ if (gPlayer1Controller->buttonPressed & R_TRIG) {
|
|
+ if (sCurrentMenu == sOptionsMenu) {
|
|
+ dynos_close();
|
|
+ } else {
|
|
+ dynos_open(sOptionsMenu);
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // Start
|
|
+ if (gPlayer1Controller->buttonPressed & START_BUTTON) {
|
|
+ dynos_close();
|
|
+ return;
|
|
+ }
|
|
+ } else if (gPlayer1Controller->buttonPressed & R_TRIG) {
|
|
+ dynos_open(sOptionsMenu);
|
|
+ } else if (gPlayer1Controller->buttonPressed & Z_TRIG) {
|
|
+ dynos_open(sDynosMenu);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void dynos_draw_prompt() {
|
|
+ if (sCurrentMenu == sOptionsMenu) {
|
|
+ dynos_print_string(sDynosTextOpenLeft, 100, 212, COLOR_WHITE, COLOR_BLACK, 1);
|
|
+ dynos_print_string(sDynosTextCloseRight, 100, 212, COLOR_WHITE, COLOR_BLACK, 0);
|
|
+ } else if (sCurrentMenu == sDynosMenu) {
|
|
+ dynos_print_string(sDynosTextCloseLeft, 100, 212, COLOR_WHITE, COLOR_BLACK, 1);
|
|
+ dynos_print_string(sDynosTextOpenRight, 100, 212, COLOR_WHITE, COLOR_BLACK, 0);
|
|
+ } else {
|
|
+ dynos_print_string(sDynosTextOpenLeft, 100, 212, COLOR_WHITE, COLOR_BLACK, 1);
|
|
+ dynos_print_string(sDynosTextOpenRight, 100, 212, COLOR_WHITE, COLOR_BLACK, 0);
|
|
+ }
|
|
+ dynos_process_inputs();
|
|
+}
|
|
+
|
|
+//
|
|
+// Init
|
|
+//
|
|
+
|
|
+static const BehaviorScript bhvDynosUpdateController[] = {
|
|
+ 0x000B0000,
|
|
+ 0x08000000,
|
|
+ 0x0C000000, (uintptr_t) dynos_update_controller,
|
|
+ 0x09000000,
|
|
+};
|
|
+
|
|
+static void dynos_spawn_object() {
|
|
+ if (gObjectLists) {
|
|
+ struct Object *head = (struct Object *) &gObjectLists[OBJ_LIST_SPAWNER];
|
|
+ struct Object *next = (struct Object *) head->header.next;
|
|
+ while (true) {
|
|
+ if (!next || next == head) { create_object(bhvDynosUpdateController); break; }
|
|
+ if (next->behavior == bhvDynosUpdateController && next->activeFlags != 0) { break; }
|
|
+ next = (struct Object *) next->header.next;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static void (*sControllerKeyboardRead)(OSContPad *) = NULL;
|
|
+static void dynos_controller_keyboard_read(OSContPad *pad) {
|
|
+ dynos_spawn_object();
|
|
+ if (sControllerKeyboardRead) {
|
|
+ sControllerKeyboardRead(pad);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void (*sControllerJoystickRead)(OSContPad *) = NULL;
|
|
+static void dynos_controller_joystick_read(OSContPad *pad) {
|
|
+ dynos_spawn_object();
|
|
+ if (sControllerJoystickRead) {
|
|
+ sControllerJoystickRead(pad);
|
|
+ }
|
|
+}
|
|
+
|
|
+void dynos_init() {
|
|
+
|
|
+ // Convert options menu
|
|
+ dynos_convert_options_menu();
|
|
+
|
|
+ // Create DynOS menu
|
|
+ dynos_load_options();
|
|
+
|
|
+ // Warp to level
|
|
+ const char *levelNames[64];
|
|
+ int levelCount = level_get_count(true);
|
|
+ const enum LevelNum *levelList = level_get_list(true, true);
|
|
+ for (int i = 0; i < levelCount; ++i) levelNames[i] = string_to_dynamic(level_get_name_decapitalized(levelList[i]));
|
|
+ dynos_create_submenu("dynos_warp_submenu", "Warp to Level", "WARP TO LEUEL");
|
|
+ dynos_create_choice("dynos_warp_level", NULL, "Level Select", (const char **) levelNames, levelCount, 0);
|
|
+ dynos_create_choice("dynos_warp_act", NULL, "Star Select", (const char **) (const char *[]) { "Star 1", "Star 2", "Star 3", "Star 4", "Star 5", "Star 6" }, 6, 0);
|
|
+ dynos_create_button("dynos_warp_to_level", "Warp", "dynos_warp_to_level");
|
|
+ dynos_end_submenu();
|
|
+
|
|
+ // Restart level
|
|
+ dynos_create_button("dynos_restart_level", "Restart Level", "dynos_restart_level");
|
|
+
|
|
+ // Return to main menu
|
|
+ dynos_create_button("dynos_return_to_main_menu", "Return to Main Menu", "dynos_return_to_main_menu");
|
|
+
|
|
+ // Init config
|
|
+ dynos_load_config();
|
|
+
|
|
+ // Init the inputs update routine
|
|
+ sControllerKeyboardRead = controller_keyboard.read;
|
|
+ sControllerJoystickRead = controller_sdl.read;
|
|
+ controller_keyboard.read = dynos_controller_keyboard_read;
|
|
+ controller_sdl.read = dynos_controller_joystick_read;
|
|
+
|
|
+ // Init text
|
|
+ sDynosTextOptionsMenu = string_to_label2("OPTIONS");
|
|
+ sDynosTextDynosMenu = string_to_label2("DYNOS MENU");
|
|
+ sDynosTextDisabled = string_to_label("Disabled");
|
|
+ sDynosTextEnabled = string_to_label("Enabled");
|
|
+ sDynosTextNone = string_to_label("NONE");
|
|
+ sDynosTextDotDotDot = string_to_label("...");
|
|
+ sDynosTextA = string_to_label("(A) "); ((unsigned char *) sDynosTextA)[1] = 84; ((unsigned char *) sDynosTextA)[4] = 83;
|
|
+ sDynosTextOpenLeft = string_to_label("Z DynOS"); ((unsigned char *) sDynosTextOpenLeft)[0] = 87;
|
|
+ sDynosTextCloseLeft = string_to_label("Z Return"); ((unsigned char *) sDynosTextCloseLeft)[0] = 87;
|
|
+ sDynosTextOpenRight = string_to_label("R Options"); ((unsigned char *) sDynosTextOpenRight)[0] = 88;
|
|
+ sDynosTextCloseRight = string_to_label("R Return"); ((unsigned char *) sDynosTextCloseRight)[0] = 88;
|
|
+}
|
|
+
|
|
+//
|
|
+// Hijack
|
|
+//
|
|
+
|
|
+unsigned char optmenu_open = 0;
|
|
+
|
|
+void optmenu_toggle(void) {
|
|
+ dynos_close();
|
|
+}
|
|
+
|
|
+void optmenu_draw(void) {
|
|
+ dynos_draw_menu();
|
|
+}
|
|
+
|
|
+void optmenu_draw_prompt(void) {
|
|
+ dynos_draw_prompt();
|
|
+ optmenu_open = (sCurrentMenu != NULL);
|
|
+}
|
|
+
|
|
+void optmenu_check_buttons(void) {
|
|
+ dynos_update_controller();
|
|
+}
|
|
+
|
|
+//
|
|
+// Return to Main Menu
|
|
+//
|
|
+
|
|
+extern char gDialogBoxState;
|
|
+extern short gMenuMode;
|
|
+void dynos_unpause_game() {
|
|
+ level_set_transition(0, 0);
|
|
+ play_sound(SOUND_MENU_PAUSE_2, gDefaultSoundArgs);
|
|
+ gDialogBoxState = 0;
|
|
+ gMenuMode = -1;
|
|
+}
|
|
+
|
|
+bool dynos_return_to_main_menu(UNUSED const char *optName) {
|
|
+ optmenu_toggle();
|
|
+ dynos_unpause_game();
|
|
+ fade_into_special_warp(-2, 0);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+//
|
|
+// Warp to Level
|
|
+//
|
|
+
|
|
+bool dynos_perform_warp(enum LevelNum levelNum, int actNum) {
|
|
+ enum CourseNum courseNum = level_get_course(levelNum);
|
|
+ if (courseNum == COURSE_NONE) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ // Free everything from the current level
|
|
+ optmenu_toggle();
|
|
+ dynos_unpause_game();
|
|
+ set_sound_disabled(FALSE);
|
|
+ play_shell_music();
|
|
+ stop_shell_music();
|
|
+ stop_cap_music();
|
|
+ clear_objects();
|
|
+ clear_area_graph_nodes();
|
|
+ clear_areas();
|
|
+ main_pool_pop_state();
|
|
+
|
|
+ // Reset Mario's state
|
|
+ gMarioState->healCounter = 0;
|
|
+ gMarioState->hurtCounter = 0;
|
|
+ gMarioState->numCoins = 0;
|
|
+ gMarioState->input = 0;
|
|
+ gMarioState->controller->buttonPressed = 0;
|
|
+ gHudDisplay.coins = 0;
|
|
+
|
|
+ // Load the new level
|
|
+ gCurrLevelNum = levelNum;
|
|
+ gCurrCourseNum = courseNum;
|
|
+ gCurrActNum = (courseNum <= COURSE_STAGES_MAX ? actNum : 0);
|
|
+ gDialogCourseActNum = gCurrActNum;
|
|
+ gCurrAreaIndex = 1;
|
|
+ level_script_execute((struct LevelCommand *) level_get_script(levelNum));
|
|
+ sWarpDest.type = 2;
|
|
+ sWarpDest.levelNum = gCurrLevelNum;
|
|
+ sWarpDest.areaIdx = 1;
|
|
+ sWarpDest.nodeId = 0x0A;
|
|
+ sWarpDest.arg = 0;
|
|
+ gSavedCourseNum = gCurrCourseNum;
|
|
+ return true;
|
|
+}
|
|
+
|
|
+bool dynos_warp_to_level(UNUSED const char *optName) {
|
|
+ enum LevelNum levelNum = level_get_list(true, true)[dynos_get_value("dynos_warp_level")];
|
|
+ return dynos_perform_warp(levelNum, dynos_get_value("dynos_warp_act") + 1);
|
|
+}
|
|
+
|
|
+//
|
|
+// Restart Level
|
|
+//
|
|
+
|
|
+bool dynos_restart_level(UNUSED const char *optName) {
|
|
+ enum LevelNum levelNum = (enum LevelNum) gCurrLevelNum;
|
|
+ if (levelNum == LEVEL_BOWSER_1) levelNum = LEVEL_BITDW;
|
|
+ if (levelNum == LEVEL_BOWSER_2) levelNum = LEVEL_BITFS;
|
|
+ if (levelNum == LEVEL_BOWSER_3) levelNum = LEVEL_BITS;
|
|
+ return dynos_perform_warp(levelNum, gCurrActNum);
|
|
+}
|
|
diff --git a/src/pc/dynamic_options.h b/src/pc/dynamic_options.h
|
|
new file mode 100644
|
|
index 0000000..d1b4cf8
|
|
--- /dev/null
|
|
+++ b/src/pc/dynamic_options.h
|
|
@@ -0,0 +1,33 @@
|
|
+#ifndef DYNAMIC_OPTIONS_H
|
|
+#define DYNAMIC_OPTIONS_H
|
|
+
|
|
+#ifdef __cplusplus
|
|
+extern "C" {
|
|
+#endif
|
|
+
|
|
+#include <stdbool.h>
|
|
+int dynos_get_value(const char *name);
|
|
+void dynos_set_value(const char *name, int value);
|
|
+void dynos_add_action(const char *funcName, bool (*funcPtr)(const char *), bool overwrite);
|
|
+
|
|
+#ifdef __cplusplus
|
|
+}
|
|
+#endif
|
|
+
|
|
+// Warning: This is C++ code, use this macro inside a .cpp file
|
|
+// The action signature is "bool (*) (const char *)"
|
|
+// The input is the button name (not label)
|
|
+// The output is the result of the action
|
|
+#define DYNOS_DEFINE_ACTION(func) \
|
|
+extern "C" { extern bool func(const char *); } \
|
|
+class DynosAction_##func { \
|
|
+public: \
|
|
+ inline DynosAction_##func() { \
|
|
+ dynos_add_action(#func, func, false); \
|
|
+ } \
|
|
+private: \
|
|
+ static DynosAction_##func sDynosAction_##func; \
|
|
+}; \
|
|
+DynosAction_##func DynosAction_##func::sDynosAction_##func;
|
|
+
|
|
+#endif // DYNAMIC_OPTIONS_H
|
|
\ No newline at end of file
|
|
diff --git a/src/pc/dynamic_options_cpp.cpp b/src/pc/dynamic_options_cpp.cpp
|
|
new file mode 100644
|
|
index 0000000..3858e60
|
|
--- /dev/null
|
|
+++ b/src/pc/dynamic_options_cpp.cpp
|
|
@@ -0,0 +1,16 @@
|
|
+#include "dynamic_options.h"
|
|
+
|
|
+//
|
|
+// DynOS Init
|
|
+//
|
|
+
|
|
+extern "C" { extern void dynos_init(void); }
|
|
+class DynosInitialization { public: DynosInitialization() { dynos_init(); } };
|
|
+static DynosInitialization sDynosInitialization;
|
|
+
|
|
+//
|
|
+// DynOS Actions
|
|
+
|
|
+DYNOS_DEFINE_ACTION(dynos_return_to_main_menu);
|
|
+DYNOS_DEFINE_ACTION(dynos_warp_to_level);
|
|
+DYNOS_DEFINE_ACTION(dynos_restart_level);
|
|
diff --git a/src/pc/levels.c b/src/pc/levels.c
|
|
new file mode 100644
|
|
index 0000000..b38e3f7
|
|
--- /dev/null
|
|
+++ b/src/pc/levels.c
|
|
@@ -0,0 +1,250 @@
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include "levels.h"
|
|
+#define STUB_LEVEL(_0, _1, _2, _3, _4, _5, _6, _7, _8)
|
|
+#define DEFINE_LEVEL(_0, _1, _2, _name, _4, _5, _6, _7, _8, _9, _10) extern const LevelScript level_##_name##_entry[];
|
|
+#include "levels/level_defines.h"
|
|
+#undef DEFINE_LEVEL
|
|
+#undef STUB_LEVEL
|
|
+
|
|
+//
|
|
+// Level, Course, Script
|
|
+//
|
|
+
|
|
+struct LevelCourseScript {
|
|
+ enum LevelNum level;
|
|
+ enum CourseNum course;
|
|
+ const LevelScript *script;
|
|
+};
|
|
+
|
|
+#define STUB_LEVEL(_0, _1, _2, _3, _4, _5, _6, _7, _8)
|
|
+#define DEFINE_LEVEL(_0, _level, _course, _name, _4, _5, _6, _7, _8, _9, _10) { _level, _course, level_##_name##_entry },
|
|
+static const struct LevelCourseScript sLCS[] = {
|
|
+#include "levels/level_defines.h"
|
|
+};
|
|
+#undef DEFINE_LEVEL
|
|
+#undef STUB_LEVEL
|
|
+
|
|
+static const LevelScript *lcs_get_script(enum LevelNum levelId) {
|
|
+ int lcsCount = (int) (sizeof(sLCS) / sizeof(sLCS[0]));
|
|
+ for (int i = 0; i != lcsCount; ++i) {
|
|
+ if (sLCS[i].level == levelId) {
|
|
+ return sLCS[i].script;
|
|
+ }
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static enum CourseNum lcs_get_course(enum LevelNum levelId) {
|
|
+ int lcsCount = (int) (sizeof(sLCS) / sizeof(sLCS[0]));
|
|
+ for (int i = 0; i != lcsCount; ++i) {
|
|
+ if (sLCS[i].level == levelId) {
|
|
+ return sLCS[i].course;
|
|
+ }
|
|
+ }
|
|
+ return COURSE_NONE;
|
|
+}
|
|
+
|
|
+//
|
|
+// Course, Name
|
|
+//
|
|
+
|
|
+struct CourseName {
|
|
+ enum CourseNum course;
|
|
+ const char *name;
|
|
+};
|
|
+
|
|
+#define _(x) x
|
|
+#define COURSE_ACTS(_course, _name, _2, _3, _4, _5, _6, _7) { _course, _name },
|
|
+#define SECRET_STAR(_course, _name) { _course, _name },
|
|
+#define CASTLE_SECRET_STARS(_0)
|
|
+#define EXTRA_TEXT(_0, _1)
|
|
+static const struct CourseName sCN[] = {
|
|
+#include "text/us/courses.h"
|
|
+};
|
|
+#undef _
|
|
+#undef COURSE_ACTS
|
|
+#undef SECRET_STAR
|
|
+#undef CASTLE_SECRET_STARS
|
|
+#undef EXTRA_TEXT
|
|
+
|
|
+static const char *cn_get_name(enum LevelNum levelId) {
|
|
+ static const char *sDefault = " CASTLE";
|
|
+ static const char *sBowser1 = " BOWSER 1";
|
|
+ static const char *sBowser2 = " BOWSER 2";
|
|
+ static const char *sBowser3 = " BOWSER 3";
|
|
+ if (levelId == LEVEL_BOWSER_1) return sBowser1;
|
|
+ if (levelId == LEVEL_BOWSER_2) return sBowser2;
|
|
+ if (levelId == LEVEL_BOWSER_3) return sBowser3;
|
|
+ int cnCount = (int) (sizeof(sCN) / sizeof(sCN[0]));
|
|
+ for (int i = 0; i != cnCount; ++i) {
|
|
+ if (sCN[i].course == lcs_get_course(levelId)) {
|
|
+ return (strlen(sCN[i].name) > 3 ? sCN[i].name : sDefault);
|
|
+ }
|
|
+ }
|
|
+ return sDefault;
|
|
+}
|
|
+
|
|
+static const char *level_create_name(const char *cname) {
|
|
+ cname += 3; // remove course number
|
|
+ int len = (int) strlen(cname);
|
|
+ char *name = calloc(len + 1, sizeof(char));
|
|
+ memcpy(name, cname, len + 1);
|
|
+ return name;
|
|
+}
|
|
+
|
|
+static const char *level_create_name_decapitalized(const char *name) {
|
|
+ int len = (int) strlen(name);
|
|
+ char *decaps = calloc(len + 1, sizeof(char));
|
|
+ memcpy(decaps, name, len + 1);
|
|
+ bool wasSpace = true;
|
|
+ for (int i = 0; i != len; ++i) {
|
|
+ char c = decaps[i];
|
|
+ if (c >= 'A' && c <= 'Z') {
|
|
+ if (wasSpace) {
|
|
+ wasSpace = false;
|
|
+ } else {
|
|
+ decaps[i] += ('a' - 'A');
|
|
+ }
|
|
+ } else if (c != '\'') {
|
|
+ wasSpace = true;
|
|
+ }
|
|
+ }
|
|
+ return decaps;
|
|
+}
|
|
+
|
|
+//
|
|
+// Data
|
|
+//
|
|
+
|
|
+static int sLevelCount = 0;
|
|
+static int sLevelCountNoCastle = 0;
|
|
+static enum LevelNum *sLevelList = NULL;
|
|
+static enum LevelNum *sLevelListNoCastle = NULL;
|
|
+static enum LevelNum *sLevelListOrdered = NULL;
|
|
+static enum LevelNum *sLevelListOrderedNoCastle = NULL;
|
|
+static const char **sLevelNames = NULL;
|
|
+static const char **sLevelNamesDecaps = NULL;
|
|
+static const LevelScript **sLevelScripts = NULL;
|
|
+static enum CourseNum *sLevelCourses = NULL;
|
|
+
|
|
+// Runs only once
|
|
+static void level_init_data() {
|
|
+ static bool inited = false;
|
|
+ if (!inited) {
|
|
+
|
|
+ // Level count
|
|
+ sLevelCount = (int) sizeof(sLCS) / sizeof(sLCS[0]);
|
|
+
|
|
+ // Level count (no Castle)
|
|
+ sLevelCountNoCastle = 0;
|
|
+ for (int i = 0; i != sLevelCount; ++i) {
|
|
+ if (sLCS[i].course != COURSE_NONE && sLCS[i].course != COURSE_CAKE_END) {
|
|
+ sLevelCountNoCastle++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Lists allocation
|
|
+ sLevelList = calloc(sLevelCount, sizeof(enum LevelNum));
|
|
+ sLevelListNoCastle = calloc(sLevelCountNoCastle, sizeof(enum LevelNum));
|
|
+ sLevelListOrdered = calloc(sLevelCount, sizeof(enum LevelNum));
|
|
+ sLevelListOrderedNoCastle = calloc(sLevelCountNoCastle, sizeof(enum LevelNum));
|
|
+ sLevelNames = calloc(LEVEL_COUNT, sizeof(const char *));
|
|
+ sLevelNamesDecaps = calloc(LEVEL_COUNT, sizeof(const char *));
|
|
+ sLevelScripts = calloc(LEVEL_COUNT, sizeof(const LevelScript *));
|
|
+ sLevelCourses = calloc(LEVEL_COUNT, sizeof(enum CourseNum));
|
|
+
|
|
+ // Level list
|
|
+ for (int i = 0; i != sLevelCount; ++i) {
|
|
+ sLevelList[i] = sLCS[i].level;
|
|
+ }
|
|
+
|
|
+ // Level list ordered by course id
|
|
+ for (int i = 0, k = 0; i < COURSE_END; ++i) {
|
|
+ for (int j = 0; j < sLevelCount; ++j) {
|
|
+ if (sLCS[j].course == (enum CourseNum) i) {
|
|
+ sLevelListOrdered[k++] = sLCS[j].level;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Level list (no Castle)
|
|
+ for (int i = 0, k = 0; i != sLevelCount; ++i) {
|
|
+ if (sLCS[i].course != COURSE_NONE && sLCS[i].course != COURSE_CAKE_END) {
|
|
+ sLevelListNoCastle[k++] = sLCS[i].level;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Level list ordered by course id (no Castle)
|
|
+ for (int i = 0, k = 0; i < COURSE_END; ++i) {
|
|
+ if (i != COURSE_NONE && i != COURSE_CAKE_END) {
|
|
+ for (int j = 0; j < sLevelCount; ++j) {
|
|
+ if (sLCS[j].course == (enum CourseNum) i) {
|
|
+ sLevelListOrderedNoCastle[k++] = sLCS[j].level;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Level names
|
|
+ for (int i = 0; i != LEVEL_COUNT; ++i) {
|
|
+ const char *cname = cn_get_name(i);
|
|
+ sLevelNames[i] = level_create_name(cname);
|
|
+ }
|
|
+
|
|
+ // Level names decapitalized
|
|
+ for (int i = 0; i != LEVEL_COUNT; ++i) {
|
|
+ sLevelNamesDecaps[i] = level_create_name_decapitalized(sLevelNames[i]);
|
|
+ }
|
|
+
|
|
+ // Level scripts
|
|
+ for (int i = 0; i != LEVEL_COUNT; ++i) {
|
|
+ sLevelScripts[i] = lcs_get_script(i);
|
|
+ }
|
|
+
|
|
+ // Level courses
|
|
+ for (int i = 0; i != LEVEL_COUNT; ++i) {
|
|
+ sLevelCourses[i] = lcs_get_course(i);
|
|
+ }
|
|
+
|
|
+ // Done
|
|
+ inited = true;
|
|
+ }
|
|
+}
|
|
+
|
|
+//
|
|
+// Getters
|
|
+//
|
|
+
|
|
+int level_get_count(bool noCastle) {
|
|
+ level_init_data();
|
|
+ return (noCastle ? sLevelCountNoCastle : sLevelCount);
|
|
+}
|
|
+
|
|
+const enum LevelNum *level_get_list(bool ordered, bool noCastle) {
|
|
+ level_init_data();
|
|
+ if (ordered) return (noCastle ? sLevelListOrderedNoCastle : sLevelListOrdered);
|
|
+ return (noCastle ? sLevelListNoCastle : sLevelList);
|
|
+}
|
|
+
|
|
+const char *level_get_name(enum LevelNum levelId) {
|
|
+ level_init_data();
|
|
+ return sLevelNames[levelId];
|
|
+}
|
|
+
|
|
+const char *level_get_name_decapitalized(enum LevelNum levelId) {
|
|
+ level_init_data();
|
|
+ return sLevelNamesDecaps[levelId];
|
|
+}
|
|
+
|
|
+const LevelScript *level_get_script(enum LevelNum levelId) {
|
|
+ level_init_data();
|
|
+ return sLevelScripts[levelId];
|
|
+}
|
|
+
|
|
+enum CourseNum level_get_course(enum LevelNum levelId) {
|
|
+ level_init_data();
|
|
+ return sLevelCourses[levelId];
|
|
+}
|
|
+
|
|
diff --git a/src/pc/levels.h b/src/pc/levels.h
|
|
new file mode 100644
|
|
index 0000000..b0d9494
|
|
--- /dev/null
|
|
+++ b/src/pc/levels.h
|
|
@@ -0,0 +1,21 @@
|
|
+#ifndef LEVELS_H
|
|
+#define LEVELS_H
|
|
+
|
|
+/*
|
|
+This file helps to provide useful info about the game's levels:
|
|
+level list, name, script, and course id.
|
|
+*/
|
|
+
|
|
+#include <stdbool.h>
|
|
+#include "types.h"
|
|
+#include "level_table.h"
|
|
+#include "course_table.h"
|
|
+
|
|
+int level_get_count(bool noCastle);
|
|
+const enum LevelNum *level_get_list(bool ordered, bool noCastle);
|
|
+const char *level_get_name(enum LevelNum levelId);
|
|
+const char *level_get_name_decapitalized(enum LevelNum levelId);
|
|
+const LevelScript *level_get_script(enum LevelNum levelId);
|
|
+enum CourseNum level_get_course(enum LevelNum levelId);
|
|
+
|
|
+#endif // LEVELS_H
|
|
\ No newline at end of file
|