diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua
index 8dfca5f9c..d9ae5c46c 100644
--- a/autogen/lua_definitions/functions.lua
+++ b/autogen/lua_definitions/functions.lua
@@ -7759,11 +7759,6 @@ function hud_show()
-- ...
end
---- @return nil
-function init_scroll_targets()
- -- ...
-end
-
--- @return boolean
function is_game_paused()
-- ...
diff --git a/data/dynos.c.h b/data/dynos.c.h
index d3fa1225b..25e61a251 100644
--- a/data/dynos.c.h
+++ b/data/dynos.c.h
@@ -66,7 +66,6 @@ void dynos_behavior_hook_all_custom_behaviors(void);
// -- other -- //
void dynos_mod_shutdown(void);
void dynos_add_scroll_target(u32 index, const char *name, u32 offset, u32 size);
-void dynos_init_scroll_targets(void);
#endif
#endif
diff --git a/data/dynos.cpp.h b/data/dynos.cpp.h
index 7b5d0bc22..b165e70ba 100644
--- a/data/dynos.cpp.h
+++ b/data/dynos.cpp.h
@@ -1065,7 +1065,6 @@ bool DynOS_Bin_Compress(const SysPath &aFilename);
BinFile *DynOS_Bin_Decompress(const SysPath &aFilename);
void DynOS_Add_Scroll_Target(u32 index, const char *name, u32 offset, u32 size);
-void DynOS_Init_Scroll_Targets(void);
#endif
#endif
diff --git a/data/dynos_c.cpp b/data/dynos_c.cpp
index 3adc2df6b..25eedf6ad 100644
--- a/data/dynos_c.cpp
+++ b/data/dynos_c.cpp
@@ -202,8 +202,4 @@ void dynos_add_scroll_target(u32 index, const char *name, u32 offset, u32 size)
DynOS_Add_Scroll_Target(index, name, offset, size);
}
-void dynos_init_scroll_targets(void) {
- DynOS_Init_Scroll_Targets();
-}
-
}
diff --git a/data/dynos_misc.cpp b/data/dynos_misc.cpp
index 3c99d6a42..a1bb0ec43 100644
--- a/data/dynos_misc.cpp
+++ b/data/dynos_misc.cpp
@@ -189,7 +189,3 @@ void DynOS_Add_Scroll_Target(u32 index, const char* name, u32 offset, u32 size)
}
}
}
-
-void DynOS_Init_Scroll_Targets(void) {
- init_vtx_scroll_targets();
-}
diff --git a/docs/lua/functions-4.md b/docs/lua/functions-4.md
index 61d8eb8a1..55f559911 100644
--- a/docs/lua/functions-4.md
+++ b/docs/lua/functions-4.md
@@ -7047,24 +7047,6 @@
-## [init_scroll_targets](#init_scroll_targets)
-
-### Lua Example
-`init_scroll_targets()`
-
-### Parameters
-- None
-
-### Returns
-- None
-
-### C Prototype
-`void init_scroll_targets(void);`
-
-[:arrow_up_small:](#)
-
-
-
## [is_game_paused](#is_game_paused)
### Lua Example
diff --git a/docs/lua/functions.md b/docs/lua/functions.md
index d8d9cb142..6774e03cd 100644
--- a/docs/lua/functions.md
+++ b/docs/lua/functions.md
@@ -1444,7 +1444,6 @@
- [hud_render_power_meter](functions-4.md#hud_render_power_meter)
- [hud_set_value](functions-4.md#hud_set_value)
- [hud_show](functions-4.md#hud_show)
- - [init_scroll_targets](functions-4.md#init_scroll_targets)
- [is_game_paused](functions-4.md#is_game_paused)
- [is_transition_playing](functions-4.md#is_transition_playing)
- [movtexqc_register](functions-4.md#movtexqc_register)
diff --git a/src/game/behaviors/texscroll.inc.c b/src/game/behaviors/texscroll.inc.c
index b135469c0..7a006b3b4 100644
--- a/src/game/behaviors/texscroll.inc.c
+++ b/src/game/behaviors/texscroll.inc.c
@@ -20,8 +20,8 @@
/* SCROLLING TYPES */
#define MODE_SCROLL_UV 0
-#define MODE_SCROLL_SINE 182 // 1
-#define MODE_SCROLL_JUMP 108 // 2
+#define MODE_SCROLL_SINE 1
+#define MODE_SCROLL_JUMP 2
// typedef struct {
// float ob[3]; /* x, y, z */
@@ -36,13 +36,15 @@
// Vtx_tn n; /* Use this one for normals */
// long long int force_structure_alignment;
// } Vtx;
-extern Vtx *gScrollTargets[];
-extern f32 gRenderingDelta;
static void shift_UV_JUMP(s32 vtxIndex, u16 vertcount, s16 speed, u16 bhv, u16 cycle) {
Vtx* *verts = get_scroll_targets(vtxIndex);
u16 i;
+ if (verts == NULL) {
+ return;
+ }
+
if (verts[0]->n.flag++ <= cycle) {
return;
}
@@ -66,6 +68,10 @@ static void shift_UV_NORMAL(u32 vtxIndex, u16 vertcount, s16 speed, u16 bhv, u16
u16 correction = 0;
u16 i;
+ if (verts == NULL) {
+ return;
+ }
+
if (bhv < SCROLL_UV_X) {
if (verts[0]->n.flag >= cycle) {
correction = verts[0]->n.flag * speed;
@@ -103,6 +109,10 @@ static void shift_UV_SINE(u32 vtxIndex, u16 vertcount, s16 speed, u16 bhv, u16 c
Vtx* *verts = get_scroll_targets(vtxIndex);
u32 i;
+ if (verts == NULL) {
+ return;
+ }
+
if (bhv < SCROLL_UV_X) {
for (i = 0; i < vertcount; i++) {
verts[i]->n.ob[bhv] += sins(verts[0]->n.flag) * speed;
@@ -115,15 +125,29 @@ static void shift_UV_SINE(u32 vtxIndex, u16 vertcount, s16 speed, u16 bhv, u16 c
verts[0]->n.flag += cycle * 0x23;
}
-// format I will use is x=spd, y=bhv, z=vert amount, rx=offset, ry=scrollType, rz=cycle, bparam=addr
+/*
+ * Scroll parameters are took from the object's properties:
+ * Xpos = speed
+ * Ypos = scrolling behavior/axis
+ * Zpos = vertices amount
+ * Xrot = offset (unused)
+ * Yrot = scrolling type
+ * Zrot = cycle
+ * Behavior param = scroll target index
+ */
void uv_update_scroll(void) {
s16 speed = (s16) o->oPosX;
u16 bhv = (u16) o->oPosY;
u16 vertCount = (u16) o->oPosZ;
- u8 scrollType = (u8) o->oFaceAngleYaw;
- u16 cycle = (u16) o->oFaceAngleRoll * 180 / 0x8000;
+ u16 scrollType = (u16) round(o->oFaceAngleYaw * 180.0 / 0x8000);
+ u16 cycle = (u16) round(o->oFaceAngleRoll * 180.0 / 0x8000);
u32 vtxIndex = (u32) o->oBehParams;
+ // Check for invalid scrolling behavior
+ if (bhv == 3 || bhv > SCROLL_UV_Y) {
+ return;
+ }
+
switch (scrollType) {
case MODE_SCROLL_UV:
shift_UV_NORMAL(vtxIndex, vertCount, speed, bhv, cycle);
@@ -134,5 +158,7 @@ void uv_update_scroll(void) {
case MODE_SCROLL_JUMP:
shift_UV_JUMP(vtxIndex, vertCount, speed, bhv, cycle);
break;
+ default:
+ break;
}
}
diff --git a/src/game/scroll_targets.c b/src/game/scroll_targets.c
index 1e1c023a1..f67f61a03 100644
--- a/src/game/scroll_targets.c
+++ b/src/game/scroll_targets.c
@@ -1,27 +1,122 @@
#include "scroll_targets.h"
-Vtx *gScrollTargets[1024];
+/*
+ * A scroll target is basically just a bunch of Vtx to
+ * apply a movement to. Each scroll targets have an id.
+ * The id is what the behavior is using to know which
+ * vertices to move.
+ */
+struct ScrollTarget {
+ u32 id;
+ u32 size;
+ Vtx* *vertices;
+ struct ScrollTarget *next;
+};
-static int startIndex[128];
-static int lastIndex = 0;
+static struct ScrollTarget *sScrollTargets = NULL;
+/*
+ * Gets the scroll targets identified by the given id
+ * and returns the vertices.
+ * Returns NULL if not found.
+ */
Vtx* *get_scroll_targets(u32 id) {
- return &gScrollTargets[startIndex[id]];
+ struct ScrollTarget *scroll = sScrollTargets;
+
+ while (scroll) {
+ if (scroll->id == id) {
+ break;
+ }
+ scroll = scroll->next;
+ }
+
+ if (scroll) {
+ return scroll->vertices;
+ }
+ return NULL;
}
-void add_vtx_scroll_target(u32 id, Vtx *vtx, u32 size) {
- if (startIndex[id] == -1) {
- startIndex[id] = lastIndex;
+/*
+ * Finds the scroll targets identified by the given id and
+ * returns it.
+ * If it doesn't find it, create one and returns an allocated
+ * pointer to it.
+ * Also sets up the static sScrollTargets variable if there
+ * isn't any scroll targets.
+ */
+struct ScrollTarget* find_or_create_scroll_targets(u32 id) {
+ struct ScrollTarget *scroll = sScrollTargets;
+ struct ScrollTarget *lastScroll = NULL;
+
+ while (scroll) {
+ if (scroll->id == id) {
+ break;
+ }
+
+ lastScroll = scroll;
+ scroll = scroll->next;
}
+ if (scroll == NULL) {
+ scroll = malloc(sizeof(struct ScrollTarget));
+ scroll->id = id;
+ scroll->size = 0;
+ scroll->vertices = NULL;
+ scroll->next = NULL;
+ if (lastScroll) {
+ lastScroll->next = scroll;
+ } else {
+ sScrollTargets = scroll;
+ }
+ }
+
+ return scroll;
+}
+
+/*
+ * Adds the given vertices to the scroll targets with the
+ * given id.
+ * Mods have to use the lua binding of this function to
+ * make the scrolling textures work.
+ */
+void add_vtx_scroll_target(u32 id, Vtx *vtx, u32 size) {
+ struct ScrollTarget *scroll = find_or_create_scroll_targets(id);
+ Vtx* *newArray;
+ u32 oldSize = sizeof(void*) * scroll->size;
+ u32 newSize = oldSize + (sizeof(void*) * size);
+
+ newArray = realloc(scroll->vertices, newSize);
+
+ if (!newArray) {
+ newArray = malloc(newSize);
+ memcpy(newArray, scroll->vertices, oldSize);
+ free(scroll->vertices);
+ }
+
+ scroll->vertices = newArray;
+
for (u32 i = 0; i < size; ++i) {
- gScrollTargets[lastIndex++] = &vtx[i];
+ scroll->vertices[scroll->size++] = &vtx[i];
}
}
-void init_vtx_scroll_targets(void) {
- for (int i = 0; i < 128; ++i) {
- startIndex[i] = -1;
+/*
+ * Free the static sScrollTargets variable and
+ * all its content that was allocated by
+ * find_or_create_scroll_targets(id)
+ * and
+ * add_vtx_scroll_targets(id, vtx, size)
+ */
+void free_vtx_scroll_targets() {
+ struct ScrollTarget* scroll = sScrollTargets;
+ struct ScrollTarget* nextScroll;
+
+ while (scroll) {
+ nextScroll = scroll->next;
+ free(scroll->vertices);
+ free(scroll);
+ scroll = nextScroll;
}
- lastIndex = 0;
+
+ sScrollTargets = NULL;
}
diff --git a/src/game/scroll_targets.h b/src/game/scroll_targets.h
index ede2b4e70..86bac2d0a 100644
--- a/src/game/scroll_targets.h
+++ b/src/game/scroll_targets.h
@@ -9,11 +9,6 @@
#include "sm64.h"
#include "types.h"
-//Q. Why does this exist instead of just directly referencing VBs?
-//A. Because gcc is dumb and will seg fault if you reference a VB by abstracting it through a bparam
-//instead of directly refencing it, causing this horrible shit.
-extern Vtx *gScrollTargets[];
-
Vtx* *get_scroll_targets(u32 id);
void add_vtx_scroll_target(u32 id, Vtx *vtx, u32 size);
-void init_vtx_scroll_targets(void);
+void free_vtx_scroll_targets(void);
diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c
index 7c4071fa8..805699db2 100644
--- a/src/pc/lua/smlua_functions_autogen.c
+++ b/src/pc/lua/smlua_functions_autogen.c
@@ -17063,15 +17063,6 @@ int smlua_func_hud_show(UNUSED lua_State* L) {
return 1;
}
-int smlua_func_init_scroll_targets(UNUSED lua_State* L) {
- if(!smlua_functions_valid_param_count(L, 0)) { return 0; }
-
-
- init_scroll_targets();
-
- return 1;
-}
-
int smlua_func_is_game_paused(UNUSED lua_State* L) {
if(!smlua_functions_valid_param_count(L, 0)) { return 0; }
@@ -19521,7 +19512,6 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "hud_render_power_meter", smlua_func_hud_render_power_meter);
smlua_bind_function(L, "hud_set_value", smlua_func_hud_set_value);
smlua_bind_function(L, "hud_show", smlua_func_hud_show);
- smlua_bind_function(L, "init_scroll_targets", smlua_func_init_scroll_targets);
smlua_bind_function(L, "is_game_paused", smlua_func_is_game_paused);
smlua_bind_function(L, "is_transition_playing", smlua_func_is_transition_playing);
smlua_bind_function(L, "movtexqc_register", smlua_func_movtexqc_register);
diff --git a/src/pc/lua/utils/smlua_misc_utils.c b/src/pc/lua/utils/smlua_misc_utils.c
index 5097140c0..1cd8ef405 100644
--- a/src/pc/lua/utils/smlua_misc_utils.c
+++ b/src/pc/lua/utils/smlua_misc_utils.c
@@ -359,7 +359,3 @@ void set_override_far(f32 far) {
void add_scroll_target(u32 index, const char* name, u32 offset, u32 size) {
dynos_add_scroll_target(index, name, offset, size);
}
-
-void init_scroll_targets(void) {
- dynos_init_scroll_targets();
-}
diff --git a/src/pc/lua/utils/smlua_misc_utils.h b/src/pc/lua/utils/smlua_misc_utils.h
index e29929bd1..7615f7f1a 100644
--- a/src/pc/lua/utils/smlua_misc_utils.h
+++ b/src/pc/lua/utils/smlua_misc_utils.h
@@ -84,7 +84,6 @@ void set_override_near(f32 near);
void set_override_far(f32 far);
void add_scroll_target(u32 index, const char* name, u32 offset, u32 size);
-void init_scroll_targets(void);
void play_transition(s16 transType, s16 time, u8 red, u8 green, u8 blue);
diff --git a/src/pc/network/network.c b/src/pc/network/network.c
index 2ab06e819..59debee28 100644
--- a/src/pc/network/network.c
+++ b/src/pc/network/network.c
@@ -5,6 +5,7 @@
#include "object_constants.h"
#include "behavior_table.h"
#include "src/game/hardcoded.h"
+#include "src/game/scroll_targets.h"
#ifdef DISCORD_SDK
#include "discord/discord.h"
#endif
@@ -124,7 +125,7 @@ bool network_init(enum NetworkType inNetworkType) {
mods_activate(&gLocalMods);
smlua_init();
-
+
dynos_behavior_hook_all_custom_behaviors();
network_player_connected(NPT_LOCAL, 0, configPlayerModel, &configPlayerPalette, configPlayerName);
@@ -504,7 +505,7 @@ void network_shutdown(bool sendLeaving, bool exiting, bool popup) {
gNetworkServerAddr = NULL;
}
gNetworkPlayerServer = NULL;
-
+
gNetworkType = NT_NONE;
@@ -530,6 +531,7 @@ void network_shutdown(bool sendLeaving, bool exiting, bool popup) {
extern s16 gChangeLevel;
gChangeLevel = LEVEL_CASTLE_GROUNDS;
network_player_init();
+ free_vtx_scroll_targets();
struct Controller* cnt = gMarioStates[0].controller;
cnt->rawStickX = 0;