Upgrade to Time Trialsv2.2

featuring DynOsv0.4 by PeachyPeach
This commit is contained in:
$4Y$ 2020-10-12 00:47:19 -04:00
parent d20ac8573c
commit 58ae0d7777
19 changed files with 10815 additions and 7 deletions

View file

@ -427,6 +427,9 @@ DEP_FILES := $(O_FILES:.o=.d) $(ULTRA_O_FILES:.o=.d) $(GODDARD_O_FILES:.o=.d) $(
# Segment elf files # Segment elf files
SEG_FILES := $(SEGMENT_ELF_FILES) $(ACTOR_ELF_FILES) $(LEVEL_ELF_FILES) SEG_FILES := $(SEGMENT_ELF_FILES) $(ACTOR_ELF_FILES) $(LEVEL_ELF_FILES)
# DynOS options txt files
include Makefile_dynos
##################### Compiler Options ####################### ##################### Compiler Options #######################
INCLUDE_CFLAGS := -I include -I $(BUILD_DIR) -I $(BUILD_DIR)/include -I src -I . INCLUDE_CFLAGS := -I include -I $(BUILD_DIR) -I $(BUILD_DIR)/include -I src -I .
ENDIAN_BITWIDTH := $(BUILD_DIR)/endian-and-bitwidth ENDIAN_BITWIDTH := $(BUILD_DIR)/endian-and-bitwidth

21
Makefile_dynos Normal file
View file

@ -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

View file

@ -13,6 +13,10 @@ Run `./extract_assets.py --clean && make clean` or `make distclean` to remove RO
## Additional Cheats ## Additional Cheats
* Instant Death/Level Exit L Trigger + R Trigger + A Button + B Button * Instant Death/Level Exit L Trigger + R Trigger + A Button + B Button
* CHAOS Mode
* Time Stop
- Just press Y to stop time
- Can be reserved by CAP cheat or level transition
* FLYER * FLYER
* All Jumps Triple * All Jumps Triple
* Hover Mode * Hover Mode
@ -76,8 +80,7 @@ Run `./extract_assets.py --clean && make clean` or `make distclean` to remove RO
* Bugfixes by JAGSTAX * Bugfixes by JAGSTAX
* DynOS by PeachyPeach * DynOS by PeachyPeach
-Exit to Main Menu by Adya -Exit to Main Menu by Adya
-Go to Level Select by $4Y$ * And of course, CHEATERv9.5 by $4Y$, me
* And of course, CHEATERv9 by $4Y$, me
## How to add cheats/mods ## How to add cheats/mods
* Use `src/game/mario_cheats.c` for code * Use `src/game/mario_cheats.c` for code

View file

@ -10,6 +10,9 @@ Ejecuta `./extract_assets.py --clean && make clean` o `make distclean` para elim
## Trucos adicionales ## Trucos adicionales
* Muerte Instantanea/Salir del Nivel Gatillo L + Gatillo R + Boton A + Boton B * Muerte Instantanea/Salir del Nivel Gatillo L + Gatillo R + Boton A + Boton B
* "CHAOS Mode"
* "Time Stop"
- Botón Y
* FLYER * FLYER
* Todos los saltos triples * Todos los saltos triples
* "HOVER MODE" * "HOVER MODE"
@ -67,8 +70,7 @@ Ejecuta `./extract_assets.py --clean && make clean` o `make distclean` para elim
* "Bugfixes" por JAGSTAX * "Bugfixes" por JAGSTAX
* "DynOS" por PeachyPeach * "DynOS" por PeachyPeach
-"Exit to Main Menu" por Adya incluido -"Exit to Main Menu" por Adya incluido
-"Go to Level Select" por $4Y$ incluido * Y por supuesto, "CHEATERv9.5" por $4Y$, yo mismo
* Y por supuesto, "CHEATERv9" por $4Y$, yo mismo
## Como agregar los trucos/mods ## Como agregar los trucos/mods
* Usa `src/game/mario_cheats.c` para el código * Usa `src/game/mario_cheats.c` para el código

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
#define AREA_H #define AREA_H
#include <PR/ultratypes.h> #include <PR/ultratypes.h>
#include "time_trials.h"
#include "types.h" #include "types.h"
#include "camera.h" #include "camera.h"
#include "engine/graph_node.h" #include "engine/graph_node.h"

View file

@ -2716,9 +2716,11 @@ s16 render_pause_courses_and_castle(void) {
break; break;
case DIALOG_STATE_HORIZONTAL: case DIALOG_STATE_HORIZONTAL:
shade_screen(); shade_screen();
if (!time_trials_render_pause_castle_main_strings(gCurrSaveFileNum - 1, &gDialogLineNum)) {
print_hud_pause_colorful_str(); print_hud_pause_colorful_str();
render_pause_castle_menu_box(160, 143); render_pause_castle_menu_box(160, 143);
render_pause_castle_main_strings(104, 60); render_pause_castle_main_strings(104, 60);
}
#ifdef VERSION_EU #ifdef VERSION_EU
if (gPlayer3Controller->buttonPressed & (A_BUTTON | Z_TRIG | START_BUTTON)) if (gPlayer3Controller->buttonPressed & (A_BUTTON | Z_TRIG | START_BUTTON))
@ -2921,7 +2923,7 @@ void render_course_complete_lvl_info_and_hud_str(void) {
play_star_fanfare_and_flash_hud(1, 1 << (gLastCompletedStarNum - 1)); play_star_fanfare_and_flash_hud(1, 1 << (gLastCompletedStarNum - 1));
if (gLastCompletedStarNum == 7) { if (gLastCompletedStarNum == 7) {
name = segmented_to_virtual(actNameTbl[COURSE_STAGES_MAX * 6 + 1]); name = segmented_to_virtual(actNameTbl[COURSE_STAGES_MAX * 6]);
} else { } else {
name = segmented_to_virtual(actNameTbl[(gLastCompletedCourseNum - 1) * 6 + gLastCompletedStarNum - 1]); name = segmented_to_virtual(actNameTbl[(gLastCompletedCourseNum - 1) * 6 + gLastCompletedStarNum - 1]);
} }
@ -3121,6 +3123,7 @@ s16 render_menus_and_dialogs() {
s16 mode = 0; s16 mode = 0;
create_dl_ortho_matrix(); create_dl_ortho_matrix();
time_trials_update(gMarioState, gMenuMode != -1);
if (gMenuMode != -1) { if (gMenuMode != -1) {
switch (gMenuMode) { switch (gMenuMode) {

View file

@ -825,6 +825,7 @@ u32 interact_star_or_key(struct MarioState *m, UNUSED u32 interactType, struct O
// func_802521A0 // func_802521A0
#endif #endif
noExit = time_trials_save_time_and_stop_timer(gCurrSaveFileNum - 1, gCurrCourseNum, gCurrLevelNum, starIndex, (!noExit || grandStar));
if (grandStar) { if (grandStar) {
return set_mario_action(m, ACT_JUMBO_STAR_CUTSCENE, 0); return set_mario_action(m, ACT_JUMBO_STAR_CUTSCENE, 0);
} }

View file

@ -1,5 +1,5 @@
#ifdef EXT_OPTIONS_MENU #ifdef EXT_OPTIONS_MENU
#ifdef DYNOS_INL
#include "sm64.h" #include "sm64.h"
#include "text_strings.h" #include "text_strings.h"
#include "engine/math_util.h" #include "engine/math_util.h"
@ -690,4 +690,5 @@ void optmenu_check_buttons(void) {
} }
} }
#endif
#endif // EXT_OPTIONS_MENU #endif // EXT_OPTIONS_MENU

1217
src/game/time_trials.c Normal file

File diff suppressed because it is too large Load diff

24
src/game/time_trials.h Normal file
View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -368,6 +368,7 @@ Gfx *geo_act_selector_strings(s16 callContext, UNUSED struct GraphNode *node) {
#endif #endif
if (callContext == GEO_CONTEXT_RENDER) { if (callContext == GEO_CONTEXT_RENDER) {
print_act_selector_strings(); print_act_selector_strings();
time_trials_render_star_select_time(gCurrSaveFileNum - 1, gCurrCourseNum, sSelectedActIndex);
} }
return NULL; return NULL;
} }

1810
src/pc/dynamic_options.c Normal file

File diff suppressed because it is too large Load diff

33
src/pc/dynamic_options.h Normal file
View file

@ -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

View file

@ -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);

250
src/pc/levels.c Normal file
View file

@ -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];
}

21
src/pc/levels.h Normal file
View file

@ -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