From 044c84d19cae9244bef5d87c1ec40ef063199965 Mon Sep 17 00:00:00 2001 From: camthehaxman Date: Wed, 7 Feb 2024 16:42:24 -0600 Subject: [PATCH 01/12] WIP SMB1 timer mod --- configs/default-config.txt | 1 + src/mkb/mkb2_ghidra.h | 4 +- src/patches/tweaks/bomb_fuse.gma | Bin 0 -> 12832 bytes src/patches/tweaks/bomb_fuse.tpl | Bin 0 -> 576 bytes src/patches/tweaks/smb1_timer.cpp | 741 ++++++++++++++++++++++++++++++ 5 files changed, 744 insertions(+), 2 deletions(-) create mode 100644 src/patches/tweaks/bomb_fuse.gma create mode 100644 src/patches/tweaks/bomb_fuse.tpl create mode 100644 src/patches/tweaks/smb1_timer.cpp diff --git a/configs/default-config.txt b/configs/default-config.txt index a97adc4..9447d6a 100644 --- a/configs/default-config.txt +++ b/configs/default-config.txt @@ -197,6 +197,7 @@ four-digit-banana-counter: disabled fix-minimap-color: disabled fix-widescreen: disabled + smb1-timer: disabled } // Toggles which party games are accessible from the party game menu. diff --git a/src/mkb/mkb2_ghidra.h b/src/mkb/mkb2_ghidra.h index bd36a2d..7b7c4bb 100644 --- a/src/mkb/mkb2_ghidra.h +++ b/src/mkb/mkb2_ghidra.h @@ -6762,7 +6762,7 @@ extern "C" { void PSMTXScale(double param_1, double param_2, double param_3, float * param_4); void C_MTXLookAt(Mtx * mtx, struct Vec * cam_pos, struct Vec * cam_up, struct Vec * target); void C_MTXFrustum(double param_1, double param_2, double param_3, double param_4, double param_5, double param_6, float * param_7); - void C_MTXPerspective(Mtx44 * m, double fovy, double aspect, double n, double f); + void C_MTXPerspective(Mtx44 m, double fovy, double aspect, double n, double f); void C_MTXOrtho(double param_1, double param_2, double param_3, double param_4, double param_5, double param_6, float * m); void PSVECAdd(float * param_1, float * param_2, float * param_3); void PSVECSubtract(float * param_1, float * param_2, float * param_3); @@ -7195,7 +7195,7 @@ extern "C" { void GXBeginDisplayList(void * list, u32 size); u32 GXEndDisplayList(void); void GXCallDisplayList(void * list, u32 nbytes); - void GXSetProjection(f32 mtx[4][4], GXProjectionType type); + void GXSetProjection(Mtx44 mtx, GXProjectionType type); void GXSetProjectionv(f32 * ptr); void GXGetProjectionv(float * ptr); undefined8 WriteMTXPS4x3(float * param_1, float * param_2); diff --git a/src/patches/tweaks/bomb_fuse.gma b/src/patches/tweaks/bomb_fuse.gma new file mode 100644 index 0000000000000000000000000000000000000000..052c01aa0256be2ca7b09c54bdd15c2ab53772f4 GIT binary patch literal 12832 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 yU*vXrIR9GSKa>A4(<-H@rU6^%uVXukAmG3z^>l literal 0 HcmV?d00001 diff --git a/src/patches/tweaks/bomb_fuse.tpl b/src/patches/tweaks/bomb_fuse.tpl new file mode 100644 index 0000000000000000000000000000000000000000..5364ed4b228e0142332c127a3c087950768a541a GIT binary patch literal 576 zcmZQzU|?ckVBiB{2L=HkWEC=j@EH+&MkZz!RyKAHPA+a9UOs*SK_OugQ894|Nh#^? z`=(5)00IVv|NldQ0G*F4t_uX1d(1B rp(7&D<=0OA|9?F``O^RY-{X--_b)mh)4zytf`kWo{)YKup#2X3Gwup6 literal 0 HcmV?d00001 diff --git a/src/patches/tweaks/smb1_timer.cpp b/src/patches/tweaks/smb1_timer.cpp new file mode 100644 index 0000000..6f88cbf --- /dev/null +++ b/src/patches/tweaks/smb1_timer.cpp @@ -0,0 +1,741 @@ +/* Classic bomb-style timer, ported from the SMB1 decompilation project + * In order to use this, you must copy the bomb_fuse.gma and bomb_fuse.tpl + * files to the root of the GameCube disc (the same directory that + * mkb2.rel_sample.rel goes in), and also copy the test/bmp/bmp_nml.tpl file + * from SMB1 into the test/bmp directory of SMB2, and name it bmp_nml1.tpl. + * Do NOT overwrite the one that's already there. + * It also must be enabled by having `smb1-timer: disabled` in the REL Patches + * section of your config.txt. */ +#include "internal/patch.h" +#include "internal/tickable.h" +#include "mkb/mkb.h" + +using namespace mkb; + +#define FATAL(...) OSPanic(__FILE__, __LINE__, __VA_ARGS__) +#define ARRAY_COUNT(arr) (sizeof(arr) / sizeof(arr[0])) + +namespace smb1_timer +{ + +/* from bitmap.h */ + +enum BitmapGroupID +{ + BMP_COM, + BMP_ADV, + BMP_END, + BMP_RNK, + BMP_SEL, + BMP_NML, + BMP_BWL, + BMP_RAC, + BMP_BIL, + BMP_FGT, + BMP_GLF, + BMP_TGT, + BMP_HOW, + BMP_CMD, + BMP_ALL, +}; + +#define BMP_NML1 BMP_ADV // we replace the BMP_ADV group with SMB1's BMP_NML + +// NML group from SMB1 +enum +{ + BMP_NML1_icon_bombtimer = (BMP_NML1 << 8), + BMP_NML1_icon_lv1234_j, + BMP_NML1_game_rank, + BMP_NML1_game_result_e3, + BMP_NML1_game_goal, + BMP_NML1_asc_ball22x22, + BMP_NML1_asc_komo16x16, + BMP_NML1_asc_tama32x32, + BMP_NML1_asc_ball18x16, + BMP_NML1_asc_ball20x20, + BMP_NML1_fukidashi, + BMP_NML1_game_player, + BMP_NML1_asc_ball26x38, + BMP_NML1_asc_ball16x22, + BMP_NML1_DUMMY14, + BMP_NML1_DUMMY15, + BMP_NML1_icon_bomb_hibi, // 0x510 + BMP_NML1_icon_bomb_part_a, + BMP_NML1_icon_bomb_part_b, + BMP_NML1_icon_bomb_part_c, + BMP_NML1_icon_bomb_part_d, + BMP_NML1_icon_bomb_part_e, + BMP_NML1_icon_bomb_part_f, + BMP_NML1_icon_bomb_part_g, + BMP_NML1_icon_bomb_part_h, + BMP_NML1_icon_bomb_part_i, + BMP_NML1_icon_bomb_part_j, +}; + +static char *filepathOld = NULL; +static char *categoryOld = NULL; + +// replaces some bitmaps in the NML bitmap group with ones from bmp_nml1.tpl +// The TPL is freed in the sprite dest callback. +static void load_smb1_nml_bmp(void) +{ + /* + // debug stuff + OSReport("Bitmap Groups:\n"); + for (int i = 0; i < 25; i++) + OSReport("%i: file: %s, category: %s, loaded: %i\n", i, bmp_infos[i].filepath, bmp_infos[i].category, bmp_infos[i].is_loaded); + */ + + // Replace the ADV bitmap group with our own. TODO: reset this when finished + if (bmp_infos[BMP_NML1].is_loaded) + { + if (mkb::strcmp(bmp_infos[BMP_NML1].category, "BMP_ADV") == 0) + FATAL("[smb1-timer] original ADV bitmap group is loaded. Not replacing it.\n"); + if (mkb::strcmp(bmp_infos[BMP_NML1].category, "BMP_NML1") == 0) + return; // already replaced, nothing to do + } + filepathOld = bmp_infos[BMP_NML1].filepath; + categoryOld = bmp_infos[BMP_NML1].category; + bmp_infos[BMP_NML1].filepath = "bmp/bmp_nml1.tpl"; + bmp_infos[BMP_NML1].category = "BMP_NML1"; + load_bmp_by_id_child(BMP_NML1); // load it +} + +static void free_smb1_nml_bmp(void) +{ + if (filepathOld == NULL || categoryOld == NULL) + FATAL("[smb1-timer] Tried to destroy bomb sprite, but SMB1 bitmaps aren't loaded somehow!\n"); + + // unload SMB1 bitmap group + g_something_with_freeing_memory(BMP_NML1); + // change it back to what it was before + bmp_infos[BMP_NML1].filepath = filepathOld; + bmp_infos[BMP_NML1].category = categoryOld; + filepathOld = NULL; + categoryOld = NULL; +} + +/* from hud.c */ + +static float calc_bomb_scale(u16 timer) +{ + float t; + + if (timer > 60) + { + float t = fabs(math_sin(((60 - ((u32)timer % 60)) & 0x3F) << 8)); + return 0.20000000298023224 * (1.0 - fabs(1.0f - t * 2.0f)); + } + if (timer < 15) + { + t = (u32)(15 - timer) / 15.0f; + if (t < 0.5f) + return 0.2f - t; + else + return (-0.3f + t) - 0.5f; + } + else + { + t = 1.0f - (u32)(timer - 15) / 45.0f; + t *= 0.2f; + return t; + } +} + +static void scale_bomb_timer(struct Sprite *sprite) // inline +{ + float scale = calc_bomb_scale(mode_info.stage_time_frames_remaining) + 1.0f; + + sprite->width = scale; + sprite->height = scale; +} + +static void bomb_crack_sprite_main(u8 *status, struct Sprite *sprite) +{ + if (mode_info.stage_time_frames_remaining <= 480) + { + if (mode_info.stage_time_frames_remaining > 420) + sprite->alpha = 1.0f - ((mode_info.stage_time_frames_remaining - 420) / 60.0f); + else + sprite->alpha = 1.0f; + scale_bomb_timer(sprite); + if (mode_info.stage_time_frames_remaining < 240) + { + sprite->para1 += 40.0f - (mode_info.stage_time_frames_remaining * 40.0f) / 240.0f; + sprite->mult_color.green = abs(255 - (sprite->para1 % 510)); + sprite->mult_color.blue = sprite->mult_color.green; + if (sprite->mult_color.blue < 128) + sprite->mult_color.blue = 128; + sprite->mult_color.blue = (sprite->mult_color.blue - 128) * 2.0f; + } + if (mode_info.stage_time_frames_remaining <= 0) + *status = 0; + } +} + +static void bomb_frag_sprite_main(u8 *status, struct Sprite *sprite) +{ + s16 x, y; + float dx, dy; + + sprite->alpha *= 0.95f; + sprite->width *= 1.01f; + sprite->height *= 1.01f; + + x = ((s16*)&sprite->para1)[0]; + y = ((s16*)&sprite->para1)[1]; + + dx = (x * 0.9f) * (sprite->alpha * sprite->alpha); + dy = (y * 0.97f) * (sprite->alpha * sprite->alpha) + (1.0f - (sprite->alpha * sprite->alpha)); + + sprite->pos.x += dx; + sprite->pos.y += dy; + +/* + // pointless, since the variables aren't modified + ((s16*)&sprite->para1)[0] = x; + ((s16*)&sprite->para1)[1] = y; +*/ + if (sprite->alpha < 0.005f) + *status = 0; +} + +static s16 bombFragBitmapIds[] = +{ + BMP_NML1_icon_bomb_part_a, + BMP_NML1_icon_bomb_part_b, + BMP_NML1_icon_bomb_part_c, + BMP_NML1_icon_bomb_part_d, + BMP_NML1_icon_bomb_part_e, + BMP_NML1_icon_bomb_part_f, + BMP_NML1_icon_bomb_part_g, + BMP_NML1_icon_bomb_part_h, + BMP_NML1_icon_bomb_part_i, + BMP_NML1_icon_bomb_part_j +}; + +static float bombFragX[] = { 7.0f, 16.0f, 26.0f, 48.0f, 0.0f, 9.0f, 55.0f, 12.0f, 33.0f, 71.0f }; +static float bombFragY[] = { 9.0f, 0.0f, 0.0f, 4.0f, 24.0f, 16.0f, 23.0f, 63.0f, 56.0f, 69.0f }; + +static void bomb_sprite_main(u8 *status, struct Sprite *sprite) +{ + float x; + float y; + float xscale; + float yscale; + struct Sprite *fragSprite; + u32 i; + + if (mode_info.stage_time_frames_remaining <= 600) + { + if (mode_info.stage_time_frames_remaining > 0) + { + scale_bomb_timer(sprite); + return; + } + + // with no time left on clock, destroy this sprite and spawn fragments + x = sprite->pos.x; + y = sprite->pos.y; + xscale = sprite->width; + yscale = sprite->height; + *status = 0; + //u_debug_set_cursor_pos(5, 5); + for (i = 0; i < 10; i++) + { + fragSprite = create_sprite(); + if (fragSprite == NULL) + return; + fragSprite->type = SPRT_BMP; + fragSprite->unique_id = 2; + fragSprite->pos.x = x - 44.0f + bombFragX[i]; + fragSprite->pos.y = y - 44.0f + bombFragY[i]; + fragSprite->font = FONT_ASCII; + fragSprite->bmp = bombFragBitmapIds[i]; + fragSprite->alignment = ALIGN_LOWER_RIGHT; + fragSprite->depth = 0.2f; + fragSprite->tick_func = bomb_frag_sprite_main; + fragSprite->width = xscale; + fragSprite->height = yscale; + ((s16 *)&fragSprite->para1)[0] = 1.2f * (bombFragX[i] - 30.0f); + ((s16 *)&fragSprite->para1)[1] = 1.2f * (bombFragY[i] - 20.0f); + sprintf(fragSprite->text, "bomb_scat%d.pic", i); + } + } +} + +// When the bomb sprite is destroyed, clean up the hacking we did earlier +static void bomb_sprite_dest(struct Sprite *sprite) +{ + //OSReport("[smb1-timer] bomb_sprite_dest\n"); + + free_smb1_nml_bmp(); +} + +static void hud_show_bomb(float x, float y) +{ + struct Sprite *sprite; + float crackX; + float crackY; + + sprite = create_sprite(); + if (sprite != NULL) + { + sprite->type = SPRT_BMP; + sprite->unique_id = 2; + sprite->pos.x = x; + sprite->pos.y = y; + sprite->font = FONT_ASCII; + sprite->bmp = BMP_NML1_icon_bombtimer; + sprite->alignment = ALIGN_CENTER; + sprite->depth = 0.2f; + sprite->tick_func = bomb_sprite_main; + sprite->dest_func = bomb_sprite_dest; + sprintf(sprite->text, "timer.pic"); + crackY = sprite->pos.y; + crackX = sprite->pos.x; + + // spawn a second sprite to show cracks + sprite = create_sprite(); + if (sprite != NULL) + { + sprite->type = SPRT_BMP; + sprite->unique_id = 2; + sprite->pos.x = crackX; + sprite->pos.y = crackY; + sprite->font = FONT_ASCII; + sprite->bmp = BMP_NML1_icon_bomb_hibi; + sprite->alignment = ALIGN_CENTER; + sprite->depth = 0.197f; + sprite->alpha = 0.0f; + sprite->tick_func = bomb_crack_sprite_main; + sprite->para1 = 0; + sprintf(sprite->text, "hibi"); + } + } +} + +/* Time numbers */ + +// TODO: these functions must already be in SMB2, right? Do we need func_80049E7C? +static void normal_timer_seconds_sprite_main(u8 *arg0, struct Sprite *sprite) +{ + //int time = (int)func_80049E7C(replayInfo.unk0[replayInfo.unk14], replayInfo.unk10) + 1; + int time = mode_info.stage_time_frames_remaining; + sprintf(sprite->text, "%03d", time / 60); +} + +static void normal_timer_100th_seconds_sprite_main(u8 *arg0, struct Sprite *sprite) +{ + //int time = (int)func_80049E7C(replayInfo.unk0[replayInfo.unk14], replayInfo.unk10) + 1; + int time = mode_info.stage_time_frames_remaining; + int val = 100.0 * ((float)(time % 60) / 60.0); + sprintf(sprite->text, ":%02d", val); +} + +// TODO: don't hardcode position. I don't know where else the timer can be drawn in SMB2. +static void show_smb1_timer(float x, float y) +{ + struct Sprite *sprite; + + //OSReport("[smb1-timer] show_smb1_timer(%.2f, %.2f)\n", x, y); + + load_smb1_nml_bmp(); + + hud_show_bomb(320.0f, 68.0f); + + // numbers + sprite = create_sprite(); + if (sprite != NULL) + { + sprite->pos.x = 320.0f; + sprite->pos.y = 85.0f; + //sprite->font = FONT_NUM_24x37; + sprite->font = FONT_NUM_NML_TIME; // TODO: is the classic SMB1 FONT_NUM_24x37 font available? + sprite->alignment = ALIGN_UPPER_CENTER; + sprite->depth = 0.19f; + sprite->tick_func = normal_timer_seconds_sprite_main; + sprintf(sprite->text, "000"); + sprite = create_linked_sprite(sprite); + if (sprite != NULL) + { + sprite->pos.x = -4.0f; + //sprite->font = FONT_NUM_12x19; + sprite->font = FONT_NUM_NML_TIME_S; + sprite->alignment = ALIGN_UPPER_CENTER; + sprite->depth = 0.19f; + sprite->tick_func = normal_timer_100th_seconds_sprite_main; + sprintf(sprite->text, ":00"); + } + } +} + +/* from polydisp.c */ + +struct +{ + //u32 unk0; + //Vec unk4; + //Vec unk10; + //Vec unk1C; + //Vec unk28; + //Vec unk34; + //Vec unk40; + s32 unk4C; // 5C + //u8 filler50[4]; + u32 unk54; + s32 unk58; + float unk5C; + float unk60; + //u8 filler64[4]; +} polyDisp; // TODO: see if this struct exists in SMB2 + +static void reset_spark_vars(void) +{ + polyDisp.unk4C = 0; + polyDisp.unk54 = 0; + polyDisp.unk58 = 0; + polyDisp.unk5C = 1.0f; + polyDisp.unk60 = 0.0f; +} + +struct StagedefAnimKeyframe bombSparkXKeyframes[] = +{ + { 1, 0, 8.7540102, 0, 0 }, + { 1, 72, 1.83571005, -0.090412, -0.090412 }, + { 1, 74, 1.66866, -0.07464, -0.07464 }, + { 1, 76, 1.536, -0.0599843, -0.0599843 }, + { 1, 84, 1.11173, -0.0567173, -0.0567173 }, + { 1, 89, 0.801074, -0.0672826, -0.0672826 }, + { 1, 92, 0.582271, -0.0860023, -0.0860023 }, + { 1, 93, 0.48935, -0.0852437, -0.0852437 }, + { 1, 95, 0.33974, -0.0706416, -0.0706416 }, + { 1, 100, 0.0010883, 0, 0 }, +}; + +struct StagedefAnimKeyframe bombSparkYKeyframes[] = +{ + { 1, 0, -1.00663, 0, 0 }, + { 1, 49, -1.00662, -0.000118196, -0.000118196 }, + { 1, 70, -0.994419, 0.010028, 0.010028 }, + { 1, 72, -0.957594, 0.0308768, 0.0308768 }, + { 1, 73, -0.919437, 0.0458789, 0.0458789 }, + { 1, 75, -0.800302, 0.0691816, 0.0691816 }, + { 1, 83, -0.16478, 0.079378, 0.079378 }, + { 1, 88, 0.210374, 0.0705764, 0.0705764 }, + { 1, 91, 0.411975, 0.0589553, 0.0589553 }, + { 1, 92, 0.465595, 0.0239604, 0.0239604 }, + { 1, 93, 0.459896, -0.0309341, -0.0309341 }, + { 1, 95, 0.340102, -0.065165, -0.065165 }, + { 1, 100, -0.0010541, 0, 0 }, +}; + +static struct TplBuffer *customTpl = NULL; +static struct GmaBuffer *customGma = NULL; + +static /*const*/ char tplName[] = "bomb_fuse.tpl"; +static /*const*/ char gmaName[] = "bomb_fuse.gma"; + +static void debug_gma(struct GmaBuffer *gma) +{ + OSReport("%i models:\n", gma->model_count); + for (int i = 0; i < gma->model_count; i++) + { + struct GmaModelEntry *entry = &gma->model_entries[i]; + struct GmaModel *model = entry->model; + OSReport("%i: '%s' %p\n", i, entry->name, entry->model); + if (model != NULL) + OSReport(" attrs: 0x%X, header_size: 0x%X, tex_objs: %p\n", model->attrs, model->header_size, model->texobjs); + } +} + +static void load_smb1_common_assets(void) +{ + if (customGma == NULL) + { + if (customTpl == NULL) + { + customTpl = g_load_tpl(tplName); + if (customTpl == NULL) + FATAL("[smb1-timer] Could not load %s\n", tplName); + OSReport("[smb1-timer] Loaded %s\n", tplName); + } + customGma = g_load_gma(gmaName, customTpl); + if (customGma == NULL) + FATAL("[smb1-timer] Could not load %s\n", gmaName); + OSReport("[smb1-timer] Loaded %s\n", gmaName); + //debug_gma(customGma); + } +} + +#define INFO_FLAG_TIMER_PAUSED (1 << 3) + +enum +{ + EV_STATE_INACTIVE = 0, + EV_STATE_RUNNING = 2, + EV_STATE_SUSPENDED = 4 +}; + +void draw_timer_bomb_fuse(void) +{ + load_smb1_common_assets(); + + //struct NlModel *tempModel; + struct Sprite *sprite; + float t; // portion of clock time remaining (from 0.0 to 1.0) + float x; + float y; + float scale; + //Vec sp94; + Mtx44 mtx; + //Vec sp48; + //Vec sp3C; + //Vec sp30; + //Vec sp24; + Vec sparkPos; + //float f4; + //float f3; + //struct NlVtxTypeB *vtx; + //int i; + //int r7; + //int faceCount; + //float f1; + //struct NlMesh *mesh; + + if (events[EVENT_VIEW].status == EV_STATE_RUNNING || mode_info.stage_time_frames_remaining <= 0) + return; + + sprite = get_sprite_with_unique_id(2); + if (sprite == NULL) + { + x = 0.0f; + y = 0.0f; + } + else + { + x = (sprite->pos.x - 320.0f) / 320.0f; + y = (56.0f - sprite->pos.y) / 240.0f; + } + + C_MTXPerspective(mtx, 60.0f, 1.3333332538604736f, 0.00989999994635582f, 20000.0f); + mtx[0][2] -= mtx[0][0] * x * 1.3333332538604736f * 0.5773502588272095f; + mtx[1][2] -= mtx[1][1] * y * 0.5773502588272095f; + GXSetProjection(mtx, 0); + + /* NOTE: Most of the code here deals with manipulating vertices for the + * arcade fuse model, which is never drawn in-game. + */ + //tempModel = lbl_802F1B4C; + t = (float)mode_info.stage_time_frames_remaining / (float)mode_info.stage_time_limit; +/* + // Make a temporary copy of the timer fuse, which we will modify + memcpy( + tempModel, + NLOBJ_MODEL(g_commonNlObj, NLMODEL_common_OBJ_COLOR_BAR_03), + NLMODEL_HEADER(NLOBJ_MODEL(g_commonNlObj, NLMODEL_common_OBJ_COLOR_BAR_03))->unk4->modelSize); + + mesh = (struct NlMesh *)tempModel->meshStart; + faceCount = ((struct NlDispList *)(((struct NlMesh *)tempModel->meshStart)->dispListStart))->faceCount; + + f4 = 2.0 * (t - 0.5); + f4 = CLAMP(f4, 0.0, 1.0); + + f3 = f4 * (faceCount - 2.0); + r7 = mathutil_floor(f3 * 0.5) * 2.0f; + f1 = (f3 - r7) * 0.5; + + vtx = (struct NlVtxTypeB *)((struct NlDispList *)mesh->dispListStart)->vtxData; + for (i = faceCount - 1; i >= 0; i--, vtx++) + { + if (t < 0.5) + vtx->s = 0.25; + else if (i < r7) + vtx->s = 0.75f; + else if (i < r7 + 2) + vtx->s = f1 * 0.25 + 0.5; + else if (i < r7 + 4) + vtx->s = 0.25 + f1 * 0.25; + else + vtx->s = 0.25; + } + + // Calculate something based on vertex positions? + // The result is never used, so this is pointless. + if (t >= 0.5) + { + int index = faceCount - 4 - r7; + float f2 = 1.0 - f1; + + vtx = &((struct NlVtxTypeB *)((struct NlDispList *)mesh->dispListStart)->vtxData)[index]; + + sp48.x = vtx[0].x * f1 + vtx[2].x * f2; + sp48.y = vtx[0].y * f1 + vtx[2].y * f2; + sp48.z = vtx[0].z * f1 + vtx[2].z * f2; + + sp3C.x = vtx[1].x * f1 + vtx[3].x * f2; + sp3C.y = vtx[1].y * f1 + vtx[3].y * f2; + sp3C.z = vtx[1].z * f1 + vtx[3].z * f2; + + sp94.x = 0.5 * (sp48.x + sp3C.x); + sp94.y = 0.5 * (sp48.y + sp3C.y); + sp94.z = 0.001 + 0.5 * (sp48.z + sp3C.z); + } + + // WTF?? + mesh = (void *)((u32 *)mesh + (((s32)mesh->dispListSize >> 2) + 0x14)); + + faceCount = ((struct NlDispList *)mesh->dispListStart)->faceCount; + + f4 = t * 2.0; + f4 = CLAMP(f4, 0.0, 1.0); + + f3 = f4 * (faceCount - 2.0); + r7 = mathutil_floor(f3 * 0.5) * 2.0f; + f1 = (f3 - r7) * 0.5; + + vtx = (void *)((struct NlDispList *)mesh->dispListStart)->vtxData; + for (i = faceCount - 1; i >= 0; i--, vtx++) + { + if (t > 0.5) + vtx->s = 0.75; + else if (i < r7) + vtx->s = 0.75; + else if (i < r7 + 2) + vtx->s = 0.5 + f1 * 0.25; + else if (i < r7 + 4) + vtx->s = 0.25 + f1 * 0.25; + else + vtx->s = 0.25; + } + + // Calculate something based on vertex positions? + // The result is never used, so this is pointless. + if (t < 0.5) + { + int index = faceCount - 4 - r7; + float f2 = 1.0 - f1; + + vtx = &((struct NlVtxTypeB *)((struct NlDispList *)mesh->dispListStart)->vtxData)[index]; + + sp30.x = vtx[0].x * f1 + vtx[2].x * f2; + sp30.y = vtx[0].y * f1 + vtx[2].y * f2; + sp30.z = vtx[0].z * f1 + vtx[2].z * f2; + + sp24.x = vtx[1].x * f1 + vtx[3].x * f2; + sp24.y = vtx[1].y * f1 + vtx[3].y * f2; + sp24.z = vtx[1].z * f1 + vtx[3].z * f2; + + sp94.x = 0.5 * (sp30.x + sp24.x); + sp94.y = 0.5 * (sp30.y + sp24.y); + sp94.z = 0.001 + 0.5 * (sp30.z + sp24.z); + } +*/ + switch (polyDisp.unk4C) + { + case 0: + if (!(mode_info.ball_mode & INFO_FLAG_TIMER_PAUSED)) + { + polyDisp.unk4C = 1; + polyDisp.unk60 = 0.125f; + polyDisp.unk58 = -((rand() & 0x3FF) + 0x400); + } + break; + case 1: + polyDisp.unk60 -= 0.0083333333333333332; + polyDisp.unk5C += polyDisp.unk60; + if (polyDisp.unk5C < 1.0) + { + polyDisp.unk5C = 1.0f; + polyDisp.unk60 = 0.0f; + polyDisp.unk4C = 2; + } + break; + case 2: + if (mode_info.ball_mode & INFO_FLAG_TIMER_PAUSED) + polyDisp.unk4C = 3; + break; + case 3: + polyDisp.unk4C = 4; + break; + case 4: + polyDisp.unk4C = 0; + break; + } + if (mode_info.ball_mode & INFO_FLAG_TIMER_PAUSED) + polyDisp.unk58 -= (polyDisp.unk58 >> 3); + else if (t > 0.5) + polyDisp.unk58 += (-768 - polyDisp.unk58) >> 4; + else + polyDisp.unk58 += (-1536 - polyDisp.unk58) >> 4; + if (!(g_some_other_flags & 0xA)) + polyDisp.unk54 += polyDisp.unk58; + + //nlObjPutSetFadeColorBase(1.0f, 1.0f, 1.0f); + + avdisp_set_post_mult_color(1.0f, t, 0.0f, 1.0f); + mtxa_from_translate_xyz(0.0f, (1.0 - t) - 0.5, 0.0f); + //avdisp_set_custom_tex_mtx(0, mtxa); + mkb::memcpy(avdisp_tex_mtx, mtxa, sizeof(Mtx)); + + // Draw new bomb fuse + mtxa_from_identity(); + mtxa_translate_xyz(0.00094f, 0.00519f, -0.01f); + scale = 0.0007f; + mtxa_scale_s(scale); + //u_gxutil_upload_some_mtx(mtxa, 0); + GXLoadPosMtxImm(*mtxa, 0); + GXLoadNrmMtxImm(*mtxa, 0); + //avdisp_set_bound_sphere_scale(scale); + //avdisp_enable_custom_tex_mtx(1); + //g_avdisp_func8(1); + //avdisp_draw_model_unculled_sort_translucent(init_common_gma->modelEntries[2].model); + avdisp_draw_model_unculled_sort_auto(customGma->model_entries[0].model); + //avdisp_enable_custom_tex_mtx(0); + //g_avdisp_func8(0); + + // Draw spark + sparkPos.x = evaluate_stagedef_keyframe((1.0 - t) * 100.0, ARRAY_COUNT(bombSparkXKeyframes), bombSparkXKeyframes); + sparkPos.y = evaluate_stagedef_keyframe((1.0 - t) * 100.0, ARRAY_COUNT(bombSparkYKeyframes), bombSparkYKeyframes); + sparkPos.z = 0.141f; + mtxa_translate(&sparkPos); + mtxa_sq_from_identity(); + mtxa_rotate_z(polyDisp.unk54); + mtxa_scale_s(0.0149f); + mtxa_scale_xyz(polyDisp.unk5C, polyDisp.unk5C, polyDisp.unk5C); + //nlObjPutImm(NLOBJ_MODEL(g_commonNlObj, NLMODEL_common_TIMER_FIRE)); + GXLoadPosMtxImm(*mtxa, 0); + GXLoadNrmMtxImm(*mtxa, 0); + avdisp_set_post_mult_color(1, 1, 1, 1); + avdisp_draw_model_unculled_sort_never(init_common_gma->model_entries[88].model); + //fade_color_base_default(); +} + +static patch::Tramp s_timerSpiteTramp; +static patch::Tramp s_bombFuseTramp; + +static void polydisp_main_override(void) +{ + s_bombFuseTramp.dest(); + //if (spriteClassMask & 4) + if (get_sprite_with_unique_id(2)) + draw_timer_bomb_fuse(); +} + +void init_main_loop() +{ + // TODO: I would like to load stuff here, at the beginning, but for some reason, the custom GMA and + // TPL get overwritten with other stuff and cause the game to crash. + //load_smb1_common_assets(); + reset_spark_vars(); + patch::hook_function(s_timerSpiteTramp, mkb::create_timer_sprites, show_smb1_timer); + patch::hook_function(s_bombFuseTramp, mkb::polydisp_main, polydisp_main_override); +} + +TICKABLE_DEFINITION(( + .name = "smb1-timer", + .description = "Classic bomb timer from SMB1", + .init_main_loop = init_main_loop, )) + +} // namespace smb1_timer From bc1e219f2a8a895b9547c8da9e017b5ac692b354 Mon Sep 17 00:00:00 2001 From: camthehaxman Date: Wed, 7 Feb 2024 18:51:40 -0600 Subject: [PATCH 02/12] delete assets, and load timer sprites from modified bmp_nml.tpl --- src/patches/tweaks/bomb_fuse.gma | Bin 12832 -> 0 bytes src/patches/tweaks/bomb_fuse.tpl | Bin 576 -> 0 bytes src/patches/tweaks/smb1_timer.cpp | 134 +++++++----------------------- 3 files changed, 31 insertions(+), 103 deletions(-) delete mode 100644 src/patches/tweaks/bomb_fuse.gma delete mode 100644 src/patches/tweaks/bomb_fuse.tpl diff --git a/src/patches/tweaks/bomb_fuse.gma b/src/patches/tweaks/bomb_fuse.gma deleted file mode 100644 index 052c01aa0256be2ca7b09c54bdd15c2ab53772f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12832 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 yU*vXrIR9GSKa>A4(<-H@rU6^%uVXukAmG3z^>l diff --git a/src/patches/tweaks/bomb_fuse.tpl b/src/patches/tweaks/bomb_fuse.tpl deleted file mode 100644 index 5364ed4b228e0142332c127a3c087950768a541a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 576 zcmZQzU|?ckVBiB{2L=HkWEC=j@EH+&MkZz!RyKAHPA+a9UOs*SK_OugQ894|Nh#^? z`=(5)00IVv|NldQ0G*F4t_uX1d(1B rp(7&D<=0OA|9?F``O^RY-{X--_b)mh)4zytf`kWo{)YKup#2X3Gwup6 diff --git a/src/patches/tweaks/smb1_timer.cpp b/src/patches/tweaks/smb1_timer.cpp index 6f88cbf..b1d9faf 100644 --- a/src/patches/tweaks/smb1_timer.cpp +++ b/src/patches/tweaks/smb1_timer.cpp @@ -1,9 +1,8 @@ /* Classic bomb-style timer, ported from the SMB1 decompilation project * In order to use this, you must copy the bomb_fuse.gma and bomb_fuse.tpl * files to the root of the GameCube disc (the same directory that - * mkb2.rel_sample.rel goes in), and also copy the test/bmp/bmp_nml.tpl file - * from SMB1 into the test/bmp directory of SMB2, and name it bmp_nml1.tpl. - * Do NOT overwrite the one that's already there. + * mkb2.rel_sample.rel goes in), and replace test/bmp/bmp_nml.tpl file + * with the modified one containing the old timer sprites. * It also must be enabled by having `smb1-timer: disabled` in the REL Patches * section of your config.txt. */ #include "internal/patch.h" @@ -39,83 +38,25 @@ enum BitmapGroupID BMP_ALL, }; -#define BMP_NML1 BMP_ADV // we replace the BMP_ADV group with SMB1's BMP_NML +//#define BMP_NML BMP_ADV // we replace the BMP_ADV group with SMB1's BMP_NML -// NML group from SMB1 +// NML group bomb images enum { - BMP_NML1_icon_bombtimer = (BMP_NML1 << 8), - BMP_NML1_icon_lv1234_j, - BMP_NML1_game_rank, - BMP_NML1_game_result_e3, - BMP_NML1_game_goal, - BMP_NML1_asc_ball22x22, - BMP_NML1_asc_komo16x16, - BMP_NML1_asc_tama32x32, - BMP_NML1_asc_ball18x16, - BMP_NML1_asc_ball20x20, - BMP_NML1_fukidashi, - BMP_NML1_game_player, - BMP_NML1_asc_ball26x38, - BMP_NML1_asc_ball16x22, - BMP_NML1_DUMMY14, - BMP_NML1_DUMMY15, - BMP_NML1_icon_bomb_hibi, // 0x510 - BMP_NML1_icon_bomb_part_a, - BMP_NML1_icon_bomb_part_b, - BMP_NML1_icon_bomb_part_c, - BMP_NML1_icon_bomb_part_d, - BMP_NML1_icon_bomb_part_e, - BMP_NML1_icon_bomb_part_f, - BMP_NML1_icon_bomb_part_g, - BMP_NML1_icon_bomb_part_h, - BMP_NML1_icon_bomb_part_i, - BMP_NML1_icon_bomb_part_j, + BMP_NML_icon_bombtimer = (BMP_NML << 8) | 0x18, + BMP_NML_icon_bomb_hibi, + BMP_NML_icon_bomb_part_a, + BMP_NML_icon_bomb_part_b, + BMP_NML_icon_bomb_part_c, + BMP_NML_icon_bomb_part_d, + BMP_NML_icon_bomb_part_e, + BMP_NML_icon_bomb_part_f, + BMP_NML_icon_bomb_part_g, + BMP_NML_icon_bomb_part_h, + BMP_NML_icon_bomb_part_i, + BMP_NML_icon_bomb_part_j, }; -static char *filepathOld = NULL; -static char *categoryOld = NULL; - -// replaces some bitmaps in the NML bitmap group with ones from bmp_nml1.tpl -// The TPL is freed in the sprite dest callback. -static void load_smb1_nml_bmp(void) -{ - /* - // debug stuff - OSReport("Bitmap Groups:\n"); - for (int i = 0; i < 25; i++) - OSReport("%i: file: %s, category: %s, loaded: %i\n", i, bmp_infos[i].filepath, bmp_infos[i].category, bmp_infos[i].is_loaded); - */ - - // Replace the ADV bitmap group with our own. TODO: reset this when finished - if (bmp_infos[BMP_NML1].is_loaded) - { - if (mkb::strcmp(bmp_infos[BMP_NML1].category, "BMP_ADV") == 0) - FATAL("[smb1-timer] original ADV bitmap group is loaded. Not replacing it.\n"); - if (mkb::strcmp(bmp_infos[BMP_NML1].category, "BMP_NML1") == 0) - return; // already replaced, nothing to do - } - filepathOld = bmp_infos[BMP_NML1].filepath; - categoryOld = bmp_infos[BMP_NML1].category; - bmp_infos[BMP_NML1].filepath = "bmp/bmp_nml1.tpl"; - bmp_infos[BMP_NML1].category = "BMP_NML1"; - load_bmp_by_id_child(BMP_NML1); // load it -} - -static void free_smb1_nml_bmp(void) -{ - if (filepathOld == NULL || categoryOld == NULL) - FATAL("[smb1-timer] Tried to destroy bomb sprite, but SMB1 bitmaps aren't loaded somehow!\n"); - - // unload SMB1 bitmap group - g_something_with_freeing_memory(BMP_NML1); - // change it back to what it was before - bmp_infos[BMP_NML1].filepath = filepathOld; - bmp_infos[BMP_NML1].category = categoryOld; - filepathOld = NULL; - categoryOld = NULL; -} - /* from hud.c */ static float calc_bomb_scale(u16 timer) @@ -203,16 +144,16 @@ static void bomb_frag_sprite_main(u8 *status, struct Sprite *sprite) static s16 bombFragBitmapIds[] = { - BMP_NML1_icon_bomb_part_a, - BMP_NML1_icon_bomb_part_b, - BMP_NML1_icon_bomb_part_c, - BMP_NML1_icon_bomb_part_d, - BMP_NML1_icon_bomb_part_e, - BMP_NML1_icon_bomb_part_f, - BMP_NML1_icon_bomb_part_g, - BMP_NML1_icon_bomb_part_h, - BMP_NML1_icon_bomb_part_i, - BMP_NML1_icon_bomb_part_j + BMP_NML_icon_bomb_part_a, + BMP_NML_icon_bomb_part_b, + BMP_NML_icon_bomb_part_c, + BMP_NML_icon_bomb_part_d, + BMP_NML_icon_bomb_part_e, + BMP_NML_icon_bomb_part_f, + BMP_NML_icon_bomb_part_g, + BMP_NML_icon_bomb_part_h, + BMP_NML_icon_bomb_part_i, + BMP_NML_icon_bomb_part_j, }; static float bombFragX[] = { 7.0f, 16.0f, 26.0f, 48.0f, 0.0f, 9.0f, 55.0f, 12.0f, 33.0f, 71.0f }; @@ -265,14 +206,6 @@ static void bomb_sprite_main(u8 *status, struct Sprite *sprite) } } -// When the bomb sprite is destroyed, clean up the hacking we did earlier -static void bomb_sprite_dest(struct Sprite *sprite) -{ - //OSReport("[smb1-timer] bomb_sprite_dest\n"); - - free_smb1_nml_bmp(); -} - static void hud_show_bomb(float x, float y) { struct Sprite *sprite; @@ -287,11 +220,10 @@ static void hud_show_bomb(float x, float y) sprite->pos.x = x; sprite->pos.y = y; sprite->font = FONT_ASCII; - sprite->bmp = BMP_NML1_icon_bombtimer; + sprite->bmp = BMP_NML_icon_bombtimer; sprite->alignment = ALIGN_CENTER; sprite->depth = 0.2f; sprite->tick_func = bomb_sprite_main; - sprite->dest_func = bomb_sprite_dest; sprintf(sprite->text, "timer.pic"); crackY = sprite->pos.y; crackX = sprite->pos.x; @@ -305,7 +237,7 @@ static void hud_show_bomb(float x, float y) sprite->pos.x = crackX; sprite->pos.y = crackY; sprite->font = FONT_ASCII; - sprite->bmp = BMP_NML1_icon_bomb_hibi; + sprite->bmp = BMP_NML_icon_bomb_hibi; sprite->alignment = ALIGN_CENTER; sprite->depth = 0.197f; sprite->alpha = 0.0f; @@ -339,10 +271,6 @@ static void show_smb1_timer(float x, float y) { struct Sprite *sprite; - //OSReport("[smb1-timer] show_smb1_timer(%.2f, %.2f)\n", x, y); - - load_smb1_nml_bmp(); - hud_show_bomb(320.0f, 68.0f); // numbers @@ -450,7 +378,7 @@ static void debug_gma(struct GmaBuffer *gma) } } -static void load_smb1_common_assets(void) +static void load_smb1_bombfuse_assets(void) { if (customGma == NULL) { @@ -480,7 +408,7 @@ enum void draw_timer_bomb_fuse(void) { - load_smb1_common_assets(); + load_smb1_bombfuse_assets(); //struct NlModel *tempModel; struct Sprite *sprite; @@ -727,7 +655,7 @@ void init_main_loop() { // TODO: I would like to load stuff here, at the beginning, but for some reason, the custom GMA and // TPL get overwritten with other stuff and cause the game to crash. - //load_smb1_common_assets(); + //load_smb1_bombfuse_assets(); reset_spark_vars(); patch::hook_function(s_timerSpiteTramp, mkb::create_timer_sprites, show_smb1_timer); patch::hook_function(s_bombFuseTramp, mkb::polydisp_main, polydisp_main_override); From 53a989daa7cce73a88ceeae4bf8385f4788ea39a Mon Sep 17 00:00:00 2001 From: camthehaxman Date: Tue, 20 Feb 2024 21:21:13 -0600 Subject: [PATCH 03/12] fuse now changes length --- src/patches/tweaks/smb1_timer.cpp | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/src/patches/tweaks/smb1_timer.cpp b/src/patches/tweaks/smb1_timer.cpp index b1d9faf..a99b0d1 100644 --- a/src/patches/tweaks/smb1_timer.cpp +++ b/src/patches/tweaks/smb1_timer.cpp @@ -604,24 +604,17 @@ void draw_timer_bomb_fuse(void) avdisp_set_post_mult_color(1.0f, t, 0.0f, 1.0f); mtxa_from_translate_xyz(0.0f, (1.0 - t) - 0.5, 0.0f); - //avdisp_set_custom_tex_mtx(0, mtxa); - mkb::memcpy(avdisp_tex_mtx, mtxa, sizeof(Mtx)); + g_something_with_texture_scroll_3(0, mtxa); // Draw new bomb fuse mtxa_from_identity(); mtxa_translate_xyz(0.00094f, 0.00519f, -0.01f); scale = 0.0007f; mtxa_scale_s(scale); - //u_gxutil_upload_some_mtx(mtxa, 0); - GXLoadPosMtxImm(*mtxa, 0); - GXLoadNrmMtxImm(*mtxa, 0); + load_gx_pos_nrm_mtx(mtxa, 0); //avdisp_set_bound_sphere_scale(scale); - //avdisp_enable_custom_tex_mtx(1); - //g_avdisp_func8(1); - //avdisp_draw_model_unculled_sort_translucent(init_common_gma->modelEntries[2].model); - avdisp_draw_model_unculled_sort_auto(customGma->model_entries[0].model); - //avdisp_enable_custom_tex_mtx(0); - //g_avdisp_func8(0); + g_avdisp_bound_sphere_scale = scale; + g_avdisp_draw_model_now1(customGma->model_entries[0].model); // Draw spark sparkPos.x = evaluate_stagedef_keyframe((1.0 - t) * 100.0, ARRAY_COUNT(bombSparkXKeyframes), bombSparkXKeyframes); @@ -633,10 +626,10 @@ void draw_timer_bomb_fuse(void) mtxa_scale_s(0.0149f); mtxa_scale_xyz(polyDisp.unk5C, polyDisp.unk5C, polyDisp.unk5C); //nlObjPutImm(NLOBJ_MODEL(g_commonNlObj, NLMODEL_common_TIMER_FIRE)); - GXLoadPosMtxImm(*mtxa, 0); - GXLoadNrmMtxImm(*mtxa, 0); - avdisp_set_post_mult_color(1, 1, 1, 1); - avdisp_draw_model_unculled_sort_never(init_common_gma->model_entries[88].model); + // SMB1 draws the spark as a Naomi model. However, SMB2 seems to also have the spark model in common.gma + load_gx_pos_nrm_mtx(mtxa, 0); + avdisp_set_post_mult_color(1, 1, 1, 1); + avdisp_draw_model_unculled_sort_never(init_common_gma->model_entries[88].model); //fade_color_base_default(); } From c8faae97fd116cb927e60fa857b191a5258b50be Mon Sep 17 00:00:00 2001 From: camthehaxman Date: Tue, 20 Feb 2024 21:39:13 -0600 Subject: [PATCH 04/12] reposition life icon to left side --- src/patches/tweaks/smb1_timer.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/patches/tweaks/smb1_timer.cpp b/src/patches/tweaks/smb1_timer.cpp index a99b0d1..69d4a5d 100644 --- a/src/patches/tweaks/smb1_timer.cpp +++ b/src/patches/tweaks/smb1_timer.cpp @@ -635,7 +635,9 @@ void draw_timer_bomb_fuse(void) static patch::Tramp s_timerSpiteTramp; static patch::Tramp s_bombFuseTramp; +static patch::Tramp s_lifeIconTramp; +// insert code to draw the SMB1 bomb fuse model static void polydisp_main_override(void) { s_bombFuseTramp.dest(); @@ -644,6 +646,12 @@ static void polydisp_main_override(void) draw_timer_bomb_fuse(); } +// reposition the life icon as to not cover up the timer fuse +void create_monkey_counter_sprites_override(double x, double y) +{ + s_lifeIconTramp.dest(52.0, 90.0); +} + void init_main_loop() { // TODO: I would like to load stuff here, at the beginning, but for some reason, the custom GMA and @@ -652,6 +660,7 @@ void init_main_loop() reset_spark_vars(); patch::hook_function(s_timerSpiteTramp, mkb::create_timer_sprites, show_smb1_timer); patch::hook_function(s_bombFuseTramp, mkb::polydisp_main, polydisp_main_override); + patch::hook_function(s_lifeIconTramp, mkb::create_monkey_counter_sprites, create_monkey_counter_sprites_override); } TICKABLE_DEFINITION(( From 7c14a84ba182e7a1372d3c31db28d662ffb9b77f Mon Sep 17 00:00:00 2001 From: camthehaxman Date: Tue, 20 Feb 2024 21:47:07 -0600 Subject: [PATCH 05/12] update with new SMB1 decomp labels and clean up --- src/patches/tweaks/smb1_timer.cpp | 224 +++++------------------------- 1 file changed, 34 insertions(+), 190 deletions(-) diff --git a/src/patches/tweaks/smb1_timer.cpp b/src/patches/tweaks/smb1_timer.cpp index 69d4a5d..a40c4db 100644 --- a/src/patches/tweaks/smb1_timer.cpp +++ b/src/patches/tweaks/smb1_timer.cpp @@ -38,8 +38,6 @@ enum BitmapGroupID BMP_ALL, }; -//#define BMP_NML BMP_ADV // we replace the BMP_ADV group with SMB1's BMP_NML - // NML group bomb images enum { @@ -133,11 +131,6 @@ static void bomb_frag_sprite_main(u8 *status, struct Sprite *sprite) sprite->pos.x += dx; sprite->pos.y += dy; -/* - // pointless, since the variables aren't modified - ((s16*)&sprite->para1)[0] = x; - ((s16*)&sprite->para1)[1] = y; -*/ if (sprite->alpha < 0.005f) *status = 0; } @@ -279,7 +272,6 @@ static void show_smb1_timer(float x, float y) { sprite->pos.x = 320.0f; sprite->pos.y = 85.0f; - //sprite->font = FONT_NUM_24x37; sprite->font = FONT_NUM_NML_TIME; // TODO: is the classic SMB1 FONT_NUM_24x37 font available? sprite->alignment = ALIGN_UPPER_CENTER; sprite->depth = 0.19f; @@ -289,7 +281,6 @@ static void show_smb1_timer(float x, float y) if (sprite != NULL) { sprite->pos.x = -4.0f; - //sprite->font = FONT_NUM_12x19; sprite->font = FONT_NUM_NML_TIME_S; sprite->alignment = ALIGN_UPPER_CENTER; sprite->depth = 0.19f; @@ -301,31 +292,23 @@ static void show_smb1_timer(float x, float y) /* from polydisp.c */ -struct +static struct { - //u32 unk0; - //Vec unk4; - //Vec unk10; - //Vec unk1C; - //Vec unk28; - //Vec unk34; - //Vec unk40; - s32 unk4C; // 5C - //u8 filler50[4]; - u32 unk54; - s32 unk58; - float unk5C; - float unk60; - //u8 filler64[4]; -} polyDisp; // TODO: see if this struct exists in SMB2 + int state; + int unused; + u32 angle; + s32 angleDelta; + float scale; + float scaleDelta; +} bombSpark; static void reset_spark_vars(void) { - polyDisp.unk4C = 0; - polyDisp.unk54 = 0; - polyDisp.unk58 = 0; - polyDisp.unk5C = 1.0f; - polyDisp.unk60 = 0.0f; + bombSpark.state = 0; + bombSpark.angle = 0; + bombSpark.angleDelta = 0; + bombSpark.scale = 1.0f; + bombSpark.scaleDelta = 0.0f; } struct StagedefAnimKeyframe bombSparkXKeyframes[] = @@ -362,21 +345,8 @@ struct StagedefAnimKeyframe bombSparkYKeyframes[] = static struct TplBuffer *customTpl = NULL; static struct GmaBuffer *customGma = NULL; -static /*const*/ char tplName[] = "bomb_fuse.tpl"; -static /*const*/ char gmaName[] = "bomb_fuse.gma"; - -static void debug_gma(struct GmaBuffer *gma) -{ - OSReport("%i models:\n", gma->model_count); - for (int i = 0; i < gma->model_count; i++) - { - struct GmaModelEntry *entry = &gma->model_entries[i]; - struct GmaModel *model = entry->model; - OSReport("%i: '%s' %p\n", i, entry->name, entry->model); - if (model != NULL) - OSReport(" attrs: 0x%X, header_size: 0x%X, tex_objs: %p\n", model->attrs, model->header_size, model->texobjs); - } -} +static char tplName[] = "bomb_fuse.tpl"; +static char gmaName[] = "bomb_fuse.gma"; static void load_smb1_bombfuse_assets(void) { @@ -393,7 +363,6 @@ static void load_smb1_bombfuse_assets(void) if (customGma == NULL) FATAL("[smb1-timer] Could not load %s\n", gmaName); OSReport("[smb1-timer] Loaded %s\n", gmaName); - //debug_gma(customGma); } } @@ -410,27 +379,13 @@ void draw_timer_bomb_fuse(void) { load_smb1_bombfuse_assets(); - //struct NlModel *tempModel; struct Sprite *sprite; float t; // portion of clock time remaining (from 0.0 to 1.0) float x; float y; float scale; - //Vec sp94; Mtx44 mtx; - //Vec sp48; - //Vec sp3C; - //Vec sp30; - //Vec sp24; Vec sparkPos; - //float f4; - //float f3; - //struct NlVtxTypeB *vtx; - //int i; - //int r7; - //int faceCount; - //float f1; - //struct NlMesh *mesh; if (events[EVENT_VIEW].status == EV_STATE_RUNNING || mode_info.stage_time_frames_remaining <= 0) return; @@ -452,155 +407,47 @@ void draw_timer_bomb_fuse(void) mtx[1][2] -= mtx[1][1] * y * 0.5773502588272095f; GXSetProjection(mtx, 0); - /* NOTE: Most of the code here deals with manipulating vertices for the - * arcade fuse model, which is never drawn in-game. - */ - //tempModel = lbl_802F1B4C; t = (float)mode_info.stage_time_frames_remaining / (float)mode_info.stage_time_limit; -/* - // Make a temporary copy of the timer fuse, which we will modify - memcpy( - tempModel, - NLOBJ_MODEL(g_commonNlObj, NLMODEL_common_OBJ_COLOR_BAR_03), - NLMODEL_HEADER(NLOBJ_MODEL(g_commonNlObj, NLMODEL_common_OBJ_COLOR_BAR_03))->unk4->modelSize); - - mesh = (struct NlMesh *)tempModel->meshStart; - faceCount = ((struct NlDispList *)(((struct NlMesh *)tempModel->meshStart)->dispListStart))->faceCount; - - f4 = 2.0 * (t - 0.5); - f4 = CLAMP(f4, 0.0, 1.0); - - f3 = f4 * (faceCount - 2.0); - r7 = mathutil_floor(f3 * 0.5) * 2.0f; - f1 = (f3 - r7) * 0.5; - - vtx = (struct NlVtxTypeB *)((struct NlDispList *)mesh->dispListStart)->vtxData; - for (i = faceCount - 1; i >= 0; i--, vtx++) - { - if (t < 0.5) - vtx->s = 0.25; - else if (i < r7) - vtx->s = 0.75f; - else if (i < r7 + 2) - vtx->s = f1 * 0.25 + 0.5; - else if (i < r7 + 4) - vtx->s = 0.25 + f1 * 0.25; - else - vtx->s = 0.25; - } - - // Calculate something based on vertex positions? - // The result is never used, so this is pointless. - if (t >= 0.5) - { - int index = faceCount - 4 - r7; - float f2 = 1.0 - f1; - - vtx = &((struct NlVtxTypeB *)((struct NlDispList *)mesh->dispListStart)->vtxData)[index]; - - sp48.x = vtx[0].x * f1 + vtx[2].x * f2; - sp48.y = vtx[0].y * f1 + vtx[2].y * f2; - sp48.z = vtx[0].z * f1 + vtx[2].z * f2; - sp3C.x = vtx[1].x * f1 + vtx[3].x * f2; - sp3C.y = vtx[1].y * f1 + vtx[3].y * f2; - sp3C.z = vtx[1].z * f1 + vtx[3].z * f2; - - sp94.x = 0.5 * (sp48.x + sp3C.x); - sp94.y = 0.5 * (sp48.y + sp3C.y); - sp94.z = 0.001 + 0.5 * (sp48.z + sp3C.z); - } - - // WTF?? - mesh = (void *)((u32 *)mesh + (((s32)mesh->dispListSize >> 2) + 0x14)); - - faceCount = ((struct NlDispList *)mesh->dispListStart)->faceCount; - - f4 = t * 2.0; - f4 = CLAMP(f4, 0.0, 1.0); - - f3 = f4 * (faceCount - 2.0); - r7 = mathutil_floor(f3 * 0.5) * 2.0f; - f1 = (f3 - r7) * 0.5; - - vtx = (void *)((struct NlDispList *)mesh->dispListStart)->vtxData; - for (i = faceCount - 1; i >= 0; i--, vtx++) - { - if (t > 0.5) - vtx->s = 0.75; - else if (i < r7) - vtx->s = 0.75; - else if (i < r7 + 2) - vtx->s = 0.5 + f1 * 0.25; - else if (i < r7 + 4) - vtx->s = 0.25 + f1 * 0.25; - else - vtx->s = 0.25; - } - - // Calculate something based on vertex positions? - // The result is never used, so this is pointless. - if (t < 0.5) - { - int index = faceCount - 4 - r7; - float f2 = 1.0 - f1; - - vtx = &((struct NlVtxTypeB *)((struct NlDispList *)mesh->dispListStart)->vtxData)[index]; - - sp30.x = vtx[0].x * f1 + vtx[2].x * f2; - sp30.y = vtx[0].y * f1 + vtx[2].y * f2; - sp30.z = vtx[0].z * f1 + vtx[2].z * f2; - - sp24.x = vtx[1].x * f1 + vtx[3].x * f2; - sp24.y = vtx[1].y * f1 + vtx[3].y * f2; - sp24.z = vtx[1].z * f1 + vtx[3].z * f2; - - sp94.x = 0.5 * (sp30.x + sp24.x); - sp94.y = 0.5 * (sp30.y + sp24.y); - sp94.z = 0.001 + 0.5 * (sp30.z + sp24.z); - } -*/ - switch (polyDisp.unk4C) + switch (bombSpark.state) { case 0: if (!(mode_info.ball_mode & INFO_FLAG_TIMER_PAUSED)) { - polyDisp.unk4C = 1; - polyDisp.unk60 = 0.125f; - polyDisp.unk58 = -((rand() & 0x3FF) + 0x400); + bombSpark.state = 1; + bombSpark.scaleDelta = 0.125f; + bombSpark.angleDelta = -((rand() & 0x3FF) + 0x400); } break; case 1: - polyDisp.unk60 -= 0.0083333333333333332; - polyDisp.unk5C += polyDisp.unk60; - if (polyDisp.unk5C < 1.0) + bombSpark.scaleDelta -= 0.0083333333333333332; + bombSpark.scale += bombSpark.scaleDelta; + if (bombSpark.scale < 1.0) { - polyDisp.unk5C = 1.0f; - polyDisp.unk60 = 0.0f; - polyDisp.unk4C = 2; + bombSpark.scale = 1.0f; + bombSpark.scaleDelta = 0.0f; + bombSpark.state = 2; } break; case 2: if (mode_info.ball_mode & INFO_FLAG_TIMER_PAUSED) - polyDisp.unk4C = 3; + bombSpark.state = 3; break; case 3: - polyDisp.unk4C = 4; + bombSpark.state = 4; break; case 4: - polyDisp.unk4C = 0; + bombSpark.state = 0; break; } if (mode_info.ball_mode & INFO_FLAG_TIMER_PAUSED) - polyDisp.unk58 -= (polyDisp.unk58 >> 3); + bombSpark.angleDelta -= (bombSpark.angleDelta >> 3); else if (t > 0.5) - polyDisp.unk58 += (-768 - polyDisp.unk58) >> 4; + bombSpark.angleDelta += (-768 - bombSpark.angleDelta) >> 4; else - polyDisp.unk58 += (-1536 - polyDisp.unk58) >> 4; + bombSpark.angleDelta += (-1536 - bombSpark.angleDelta) >> 4; if (!(g_some_other_flags & 0xA)) - polyDisp.unk54 += polyDisp.unk58; - - //nlObjPutSetFadeColorBase(1.0f, 1.0f, 1.0f); + bombSpark.angle += bombSpark.angleDelta; avdisp_set_post_mult_color(1.0f, t, 0.0f, 1.0f); mtxa_from_translate_xyz(0.0f, (1.0 - t) - 0.5, 0.0f); @@ -622,15 +469,13 @@ void draw_timer_bomb_fuse(void) sparkPos.z = 0.141f; mtxa_translate(&sparkPos); mtxa_sq_from_identity(); - mtxa_rotate_z(polyDisp.unk54); + mtxa_rotate_z(bombSpark.angle); mtxa_scale_s(0.0149f); - mtxa_scale_xyz(polyDisp.unk5C, polyDisp.unk5C, polyDisp.unk5C); - //nlObjPutImm(NLOBJ_MODEL(g_commonNlObj, NLMODEL_common_TIMER_FIRE)); + mtxa_scale_xyz(bombSpark.scale, bombSpark.scale, bombSpark.scale); // SMB1 draws the spark as a Naomi model. However, SMB2 seems to also have the spark model in common.gma load_gx_pos_nrm_mtx(mtxa, 0); avdisp_set_post_mult_color(1, 1, 1, 1); avdisp_draw_model_unculled_sort_never(init_common_gma->model_entries[88].model); - //fade_color_base_default(); } static patch::Tramp s_timerSpiteTramp; @@ -641,7 +486,6 @@ static patch::Tramp s_lifeIconTra static void polydisp_main_override(void) { s_bombFuseTramp.dest(); - //if (spriteClassMask & 4) if (get_sprite_with_unique_id(2)) draw_timer_bomb_fuse(); } From 98421557a66b816f7ea8c7ff9ae9c6b6e8fcce7b Mon Sep 17 00:00:00 2001 From: camthehaxman Date: Tue, 20 Feb 2024 22:37:28 -0600 Subject: [PATCH 06/12] sprites compatible with widescreen --- src/patches/tweaks/smb1_timer.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/patches/tweaks/smb1_timer.cpp b/src/patches/tweaks/smb1_timer.cpp index a40c4db..70df91b 100644 --- a/src/patches/tweaks/smb1_timer.cpp +++ b/src/patches/tweaks/smb1_timer.cpp @@ -195,6 +195,8 @@ static void bomb_sprite_main(u8 *status, struct Sprite *sprite) ((s16 *)&fragSprite->para1)[0] = 1.2f * (bombFragX[i] - 30.0f); ((s16 *)&fragSprite->para1)[1] = 1.2f * (bombFragY[i] - 20.0f); sprintf(fragSprite->text, "bomb_scat%d.pic", i); + sprite->g_flags1 |= 0x01000000; + sprite->widescreen_translation_x = 320; } } } @@ -218,6 +220,8 @@ static void hud_show_bomb(float x, float y) sprite->depth = 0.2f; sprite->tick_func = bomb_sprite_main; sprintf(sprite->text, "timer.pic"); + sprite->g_flags1 |= 0x01000000; + sprite->widescreen_translation_x = 320; crackY = sprite->pos.y; crackX = sprite->pos.x; @@ -237,6 +241,8 @@ static void hud_show_bomb(float x, float y) sprite->tick_func = bomb_crack_sprite_main; sprite->para1 = 0; sprintf(sprite->text, "hibi"); + sprite->g_flags1 |= 0x01000000; + sprite->widescreen_translation_x = 320; } } } @@ -277,6 +283,8 @@ static void show_smb1_timer(float x, float y) sprite->depth = 0.19f; sprite->tick_func = normal_timer_seconds_sprite_main; sprintf(sprite->text, "000"); + sprite->g_flags1 |= 0x01000000; + sprite->widescreen_translation_x = 320; sprite = create_linked_sprite(sprite); if (sprite != NULL) { @@ -286,6 +294,8 @@ static void show_smb1_timer(float x, float y) sprite->depth = 0.19f; sprite->tick_func = normal_timer_100th_seconds_sprite_main; sprintf(sprite->text, ":00"); + sprite->g_flags1 |= 0x01000000; + sprite->widescreen_translation_x = 320; } } } @@ -493,7 +503,11 @@ static void polydisp_main_override(void) // reposition the life icon as to not cover up the timer fuse void create_monkey_counter_sprites_override(double x, double y) { - s_lifeIconTramp.dest(52.0, 90.0); + x = 52.0; + y = 92.0; + if (widescreen_mode != NORMAL) + x -= 150; + s_lifeIconTramp.dest(x, y); } void init_main_loop() From 9d22c9641250d0c85bd27056777e1a6d8f43f0e6 Mon Sep 17 00:00:00 2001 From: camthehaxman Date: Tue, 20 Feb 2024 23:01:34 -0600 Subject: [PATCH 07/12] make bomb fuse work properly with widescreen --- src/patches/tweaks/smb1_timer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/patches/tweaks/smb1_timer.cpp b/src/patches/tweaks/smb1_timer.cpp index 70df91b..a10c5fb 100644 --- a/src/patches/tweaks/smb1_timer.cpp +++ b/src/patches/tweaks/smb1_timer.cpp @@ -412,8 +412,8 @@ void draw_timer_bomb_fuse(void) y = (56.0f - sprite->pos.y) / 240.0f; } - C_MTXPerspective(mtx, 60.0f, 1.3333332538604736f, 0.00989999994635582f, 20000.0f); - mtx[0][2] -= mtx[0][0] * x * 1.3333332538604736f * 0.5773502588272095f; + C_MTXPerspective(mtx, 60.0f, g_current_camera->aspect, 0.00989999994635582f, 20000.0f); + mtx[0][2] -= mtx[0][0] * x * g_current_camera->aspect * 0.5773502588272095f; mtx[1][2] -= mtx[1][1] * y * 0.5773502588272095f; GXSetProjection(mtx, 0); From 18efb7931071cae8173e8aee4cf9446efecff19a Mon Sep 17 00:00:00 2001 From: camthehaxman Date: Tue, 20 Feb 2024 23:06:11 -0600 Subject: [PATCH 08/12] use para2 instead of the ugly type punning that SMB1 does --- src/patches/tweaks/smb1_timer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/patches/tweaks/smb1_timer.cpp b/src/patches/tweaks/smb1_timer.cpp index a10c5fb..4722245 100644 --- a/src/patches/tweaks/smb1_timer.cpp +++ b/src/patches/tweaks/smb1_timer.cpp @@ -122,8 +122,8 @@ static void bomb_frag_sprite_main(u8 *status, struct Sprite *sprite) sprite->width *= 1.01f; sprite->height *= 1.01f; - x = ((s16*)&sprite->para1)[0]; - y = ((s16*)&sprite->para1)[1]; + x = sprite->para1; + y = sprite->para2; dx = (x * 0.9f) * (sprite->alpha * sprite->alpha); dy = (y * 0.97f) * (sprite->alpha * sprite->alpha) + (1.0f - (sprite->alpha * sprite->alpha)); @@ -192,8 +192,8 @@ static void bomb_sprite_main(u8 *status, struct Sprite *sprite) fragSprite->tick_func = bomb_frag_sprite_main; fragSprite->width = xscale; fragSprite->height = yscale; - ((s16 *)&fragSprite->para1)[0] = 1.2f * (bombFragX[i] - 30.0f); - ((s16 *)&fragSprite->para1)[1] = 1.2f * (bombFragY[i] - 20.0f); + fragSprite->para1 = 1.2f * (bombFragX[i] - 30.0f); + fragSprite->para2 = 1.2f * (bombFragY[i] - 20.0f); sprintf(fragSprite->text, "bomb_scat%d.pic", i); sprite->g_flags1 |= 0x01000000; sprite->widescreen_translation_x = 320; From 3bd366c81be54e49a8b6fb5a98a320036f24215a Mon Sep 17 00:00:00 2001 From: camthehaxman Date: Tue, 20 Feb 2024 23:15:25 -0600 Subject: [PATCH 09/12] fix typo --- src/patches/tweaks/smb1_timer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/patches/tweaks/smb1_timer.cpp b/src/patches/tweaks/smb1_timer.cpp index 4722245..a098191 100644 --- a/src/patches/tweaks/smb1_timer.cpp +++ b/src/patches/tweaks/smb1_timer.cpp @@ -3,7 +3,7 @@ * files to the root of the GameCube disc (the same directory that * mkb2.rel_sample.rel goes in), and replace test/bmp/bmp_nml.tpl file * with the modified one containing the old timer sprites. - * It also must be enabled by having `smb1-timer: disabled` in the REL Patches + * It also must be enabled by having `smb1-timer: enabled` in the REL Patches * section of your config.txt. */ #include "internal/patch.h" #include "internal/tickable.h" From 08bfe3afc77f1595f8267e8908b3cadd6e3f7f0b Mon Sep 17 00:00:00 2001 From: camthehaxman Date: Tue, 20 Feb 2024 23:23:53 -0600 Subject: [PATCH 10/12] tabs to spaces --- src/patches/tweaks/smb1_timer.cpp | 66 +++++++++++++++---------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/patches/tweaks/smb1_timer.cpp b/src/patches/tweaks/smb1_timer.cpp index a098191..5299e24 100644 --- a/src/patches/tweaks/smb1_timer.cpp +++ b/src/patches/tweaks/smb1_timer.cpp @@ -268,11 +268,11 @@ static void normal_timer_100th_seconds_sprite_main(u8 *arg0, struct Sprite *spri // TODO: don't hardcode position. I don't know where else the timer can be drawn in SMB2. static void show_smb1_timer(float x, float y) { - struct Sprite *sprite; + struct Sprite *sprite; - hud_show_bomb(320.0f, 68.0f); + hud_show_bomb(320.0f, 68.0f); - // numbers + // numbers sprite = create_sprite(); if (sprite != NULL) { @@ -360,20 +360,20 @@ static char gmaName[] = "bomb_fuse.gma"; static void load_smb1_bombfuse_assets(void) { - if (customGma == NULL) - { - if (customTpl == NULL) - { - customTpl = g_load_tpl(tplName); - if (customTpl == NULL) - FATAL("[smb1-timer] Could not load %s\n", tplName); - OSReport("[smb1-timer] Loaded %s\n", tplName); - } - customGma = g_load_gma(gmaName, customTpl); - if (customGma == NULL) - FATAL("[smb1-timer] Could not load %s\n", gmaName); - OSReport("[smb1-timer] Loaded %s\n", gmaName); - } + if (customGma == NULL) + { + if (customTpl == NULL) + { + customTpl = g_load_tpl(tplName); + if (customTpl == NULL) + FATAL("[smb1-timer] Could not load %s\n", tplName); + OSReport("[smb1-timer] Loaded %s\n", tplName); + } + customGma = g_load_gma(gmaName, customTpl); + if (customGma == NULL) + FATAL("[smb1-timer] Could not load %s\n", gmaName); + OSReport("[smb1-timer] Loaded %s\n", gmaName); + } } #define INFO_FLAG_TIMER_PAUSED (1 << 3) @@ -387,7 +387,7 @@ enum void draw_timer_bomb_fuse(void) { - load_smb1_bombfuse_assets(); + load_smb1_bombfuse_assets(); struct Sprite *sprite; float t; // portion of clock time remaining (from 0.0 to 1.0) @@ -468,7 +468,7 @@ void draw_timer_bomb_fuse(void) mtxa_translate_xyz(0.00094f, 0.00519f, -0.01f); scale = 0.0007f; mtxa_scale_s(scale); - load_gx_pos_nrm_mtx(mtxa, 0); + load_gx_pos_nrm_mtx(mtxa, 0); //avdisp_set_bound_sphere_scale(scale); g_avdisp_bound_sphere_scale = scale; g_avdisp_draw_model_now1(customGma->model_entries[0].model); @@ -482,10 +482,10 @@ void draw_timer_bomb_fuse(void) mtxa_rotate_z(bombSpark.angle); mtxa_scale_s(0.0149f); mtxa_scale_xyz(bombSpark.scale, bombSpark.scale, bombSpark.scale); - // SMB1 draws the spark as a Naomi model. However, SMB2 seems to also have the spark model in common.gma - load_gx_pos_nrm_mtx(mtxa, 0); - avdisp_set_post_mult_color(1, 1, 1, 1); - avdisp_draw_model_unculled_sort_never(init_common_gma->model_entries[88].model); + // SMB1 draws the spark as a Naomi model. However, SMB2 seems to also have the spark model in common.gma + load_gx_pos_nrm_mtx(mtxa, 0); + avdisp_set_post_mult_color(1, 1, 1, 1); + avdisp_draw_model_unculled_sort_never(init_common_gma->model_entries[88].model); } static patch::Tramp s_timerSpiteTramp; @@ -495,9 +495,9 @@ static patch::Tramp s_lifeIconTra // insert code to draw the SMB1 bomb fuse model static void polydisp_main_override(void) { - s_bombFuseTramp.dest(); - if (get_sprite_with_unique_id(2)) - draw_timer_bomb_fuse(); + s_bombFuseTramp.dest(); + if (get_sprite_with_unique_id(2)) + draw_timer_bomb_fuse(); } // reposition the life icon as to not cover up the timer fuse @@ -512,13 +512,13 @@ void create_monkey_counter_sprites_override(double x, double y) void init_main_loop() { - // TODO: I would like to load stuff here, at the beginning, but for some reason, the custom GMA and - // TPL get overwritten with other stuff and cause the game to crash. - //load_smb1_bombfuse_assets(); - reset_spark_vars(); - patch::hook_function(s_timerSpiteTramp, mkb::create_timer_sprites, show_smb1_timer); - patch::hook_function(s_bombFuseTramp, mkb::polydisp_main, polydisp_main_override); - patch::hook_function(s_lifeIconTramp, mkb::create_monkey_counter_sprites, create_monkey_counter_sprites_override); + // TODO: I would like to load stuff here, at the beginning, but for some reason, the custom GMA and + // TPL get overwritten with other stuff and cause the game to crash. + //load_smb1_bombfuse_assets(); + reset_spark_vars(); + patch::hook_function(s_timerSpiteTramp, mkb::create_timer_sprites, show_smb1_timer); + patch::hook_function(s_bombFuseTramp, mkb::polydisp_main, polydisp_main_override); + patch::hook_function(s_lifeIconTramp, mkb::create_monkey_counter_sprites, create_monkey_counter_sprites_override); } TICKABLE_DEFINITION(( From 7611b10168466dc09f7876ac2cf69c668b041246 Mon Sep 17 00:00:00 2001 From: camthehaxman Date: Tue, 20 Feb 2024 23:24:13 -0600 Subject: [PATCH 11/12] oops --- src/patches/tweaks/smb1_timer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/patches/tweaks/smb1_timer.cpp b/src/patches/tweaks/smb1_timer.cpp index 5299e24..101a1e9 100644 --- a/src/patches/tweaks/smb1_timer.cpp +++ b/src/patches/tweaks/smb1_timer.cpp @@ -195,8 +195,8 @@ static void bomb_sprite_main(u8 *status, struct Sprite *sprite) fragSprite->para1 = 1.2f * (bombFragX[i] - 30.0f); fragSprite->para2 = 1.2f * (bombFragY[i] - 20.0f); sprintf(fragSprite->text, "bomb_scat%d.pic", i); - sprite->g_flags1 |= 0x01000000; - sprite->widescreen_translation_x = 320; + fragSprite->g_flags1 |= 0x01000000; + fragSprite->widescreen_translation_x = 320; } } } From aca1fb2497c748d85a9e57073671c1a7ac4ef746 Mon Sep 17 00:00:00 2001 From: camthehaxman Date: Wed, 21 Feb 2024 09:15:12 -0600 Subject: [PATCH 12/12] make numbers fade out on timeover --- src/patches/tweaks/smb1_timer.cpp | 34 +++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/patches/tweaks/smb1_timer.cpp b/src/patches/tweaks/smb1_timer.cpp index 101a1e9..f7fa098 100644 --- a/src/patches/tweaks/smb1_timer.cpp +++ b/src/patches/tweaks/smb1_timer.cpp @@ -249,20 +249,32 @@ static void hud_show_bomb(float x, float y) /* Time numbers */ -// TODO: these functions must already be in SMB2, right? Do we need func_80049E7C? -static void normal_timer_seconds_sprite_main(u8 *arg0, struct Sprite *sprite) +static void maingame_timer_seconds_sprite_main(u8 *status, struct Sprite *sprite) { - //int time = (int)func_80049E7C(replayInfo.unk0[replayInfo.unk14], replayInfo.unk10) + 1; - int time = mode_info.stage_time_frames_remaining; - sprintf(sprite->text, "%03d", time / 60); + sprintf(sprite->text, "%03d", mode_info.stage_time_frames_remaining / 60); + if (mode_info.stage_time_frames_remaining <= 0) + { + sprite->width *= 1.01f; + sprite->height *= 1.01f; + sprite->alpha *= 0.88f; + if (sprite->alpha < 0.05f) + *status = 0; + } } -static void normal_timer_100th_seconds_sprite_main(u8 *arg0, struct Sprite *sprite) +static void maingame_timer_100th_seconds_sprite_main(u8 *status, struct Sprite *sprite) { - //int time = (int)func_80049E7C(replayInfo.unk0[replayInfo.unk14], replayInfo.unk10) + 1; - int time = mode_info.stage_time_frames_remaining; - int val = 100.0 * ((float)(time % 60) / 60.0); + int val = 100.0 * ((float)(mode_info.stage_time_frames_remaining % 60) / 60.0); + sprintf(sprite->text, ":%02d", val); + if (mode_info.stage_time_frames_remaining <= 0) + { + sprite->width *= 1.01f; + sprite->height *= 1.01f; + sprite->alpha *= 0.88f; + if (sprite->alpha < 0.05f) + *status = 0; + } } // TODO: don't hardcode position. I don't know where else the timer can be drawn in SMB2. @@ -281,7 +293,7 @@ static void show_smb1_timer(float x, float y) sprite->font = FONT_NUM_NML_TIME; // TODO: is the classic SMB1 FONT_NUM_24x37 font available? sprite->alignment = ALIGN_UPPER_CENTER; sprite->depth = 0.19f; - sprite->tick_func = normal_timer_seconds_sprite_main; + sprite->tick_func = maingame_timer_seconds_sprite_main; sprintf(sprite->text, "000"); sprite->g_flags1 |= 0x01000000; sprite->widescreen_translation_x = 320; @@ -292,7 +304,7 @@ static void show_smb1_timer(float x, float y) sprite->font = FONT_NUM_NML_TIME_S; sprite->alignment = ALIGN_UPPER_CENTER; sprite->depth = 0.19f; - sprite->tick_func = normal_timer_100th_seconds_sprite_main; + sprite->tick_func = maingame_timer_100th_seconds_sprite_main; sprintf(sprite->text, ":00"); sprite->g_flags1 |= 0x01000000; sprite->widescreen_translation_x = 320;