diff --git a/autogen/lua_definitions/constants.lua b/autogen/lua_definitions/constants.lua index 84078962..d1d6d242 100644 --- a/autogen/lua_definitions/constants.lua +++ b/autogen/lua_definitions/constants.lua @@ -11522,7 +11522,7 @@ MAX_LOCAL_VERSION_LENGTH = 12 MAX_VERSION_LENGTH = 10 --- @type integer -MINOR_VERSION_NUMBER = 0 +MINOR_VERSION_NUMBER = 1 --- @type integer PATCH_VERSION_NUMBER = 0 diff --git a/autogen/lua_definitions/manual.lua b/autogen/lua_definitions/manual.lua index 0ecdb6de..bab2a3eb 100644 --- a/autogen/lua_definitions/manual.lua +++ b/autogen/lua_definitions/manual.lua @@ -222,8 +222,12 @@ function djui_hud_render_texture_tile_interpolated(texInfo, prevX, prevY, prevSc end --- @param levelNum number ---- @param func fun(areaNum:number, bhv:table) +--- @param func fun(areaIndex:number, bhvData:table, macroBhvIds:table, macroBhvArgs:table) --- @return nil +--- When `func` is called, arguments are filled depending on the level command: +--- - `AREA` command: only `areaIndex` is filled. It's a number. +--- - `OBJECT` command: only `bhvData` is filled. `bhvData` is a table with two fields: `behavior` and `behaviorArg`. +--- - `MACRO` command: only `macroBhvIds` and `macroBhvArgs` are filled. `macrobhvIds` is a list of behavior ids. `macroBhvArgs` is a list of behavior params. Both lists have the same size and start at index 0. function level_script_parse(levelNum, func) -- ... end diff --git a/lang/Spanish.ini b/lang/Spanish.ini index 19397856..16233422 100644 --- a/lang/Spanish.ini +++ b/lang/Spanish.ini @@ -2,47 +2,47 @@ CONNECTED = "@ se ha conectado" DISCONNECTED = "@ se ha desconectado" LEFT_THIS_LEVEL = "@ ha salido del nivel" -ENTERED_THIS_LEVEL = "@ ha entrado al nivel" -ENTERED = "@ se ha unido\n#" -SERVER_CLOSED = "\\#ffa0a0\\Desconectado:\\#dcdcdc\\ servidor cerrado" +ENTERED_THIS_LEVEL = "@ se ha unido a tu nivel" +ENTERED = "@ ha entrado a \n#" +SERVER_CLOSED = "\\#ffa0a0\\Desconectado:\\#dcdcdc\\ El servidor ha sido cerrado." DISCORD_ERROR = "Discord ha lanzado un error.\nPara solucionarlo, intenta: \n1. Cerrar el juego.\n2. Reiniciar Discord.\n3. Iniciar el juego." DISCORD_DETECT = "\\#ffa0a0\\Error:\\#c8c8c8\\ No se ha podido detectar Discord.\n\\#a0a0a0\\Prueba a cerrar el juego, reiniciar Discord, e iniciar el juego otra vez." -DISCONNECT_FULL = "\\#ffa0a0\\Desconectado:\\#c8c8c8\\ La partida está llena." -DISCONNECT_KICK = "\\#ffa0a0\\Desconectado:\\#c8c8c8\\ Has sido expulsado del servidor." -DISCONNECT_BAN = "\\#ffa0a0\\Desconectado:\\#c8c8c8\\ Has sido vetado del servidor." -DISCONNECT_REJOIN = "\\#ffa0a0\\Desconectado:\\#c8c8c8\\ Uniendose de nuevo..." -DISCONNECT_CLOSED = "\\#ffa0a0\\Desconectado:\\#c8c8c8\\ El anfitrión ha cerrado la conexion." -DISCONNECT_BIG_MOD = "El servidor tenía un mod demasiado pesado.\nSaliendo." -DIED = "@ ha muerto" -DEBUG_FLY = "@ está en estado de vuelo libre debug" -IMPORT_MOD_SUCCESS = "\\#a0ffa0\\Mod \n\\#c8c8c8\\'@'\n\\#a0ffa0\\Importado" -IMPORT_DYNOS_SUCCESS = "\\#a0ffa0\\DynOS pack \n\\#c8c8c8\\'@'\n\\#a0ffa0\\Importado" -IMPORT_FAIL = "\\#ffa0a0\\Fallo al importar \\#c8c8c8\\\n'@'" -IMPORT_FAIL_INGAME = "\\#ffa0a0\\No se puede importar mientras se está en juego" +DISCONNECT_FULL = "\\#ffa0a0\\Desconectado:\\#c8c8c8\\ La partida está llena" +DISCONNECT_KICK = "\\#ffa0a0\\Desconectado:\\#c8c8c8\\ has sido\nexpulsado del servidor" +DISCONNECT_BAN = "\\#ffa0a0\\Desconectado:\\#c8c8c8\\ has sido\nbaneado del servidor" +DISCONNECT_REJOIN = "\\#ffa0a0\\Desconectado:\\#c8c8c8\\ Uniéndose de nuevo..." +DISCONNECT_CLOSED = "\\#ffa0a0\\Desconectado:\\#c8c8c8\\ El alfitrión ha cerrado el servidor" +DISCONNECT_BIG_MOD = "\\#ffa0a0\\Desconectado:\\#c8c8c8\\ El servidor tenía\nun mod demasiado pesado" +DIED = "@ ha muerto." +DEBUG_FLY = "@ Está en estado de vuelo libre debug." +IMPORT_MOD_SUCCESS = "El mod \\#c8c8c8\\'@'\\#a0ffa0\\\nha sido importado con éxito." +IMPORT_DYNOS_SUCCESS = "El pack de DynOS \\#c8c8c8\\'@'\\#a0ffa0\\\nha sido importado con éxito." +IMPORT_FAIL = "\n\\#ffa0a0\\Error al importar archivo. \\#c8c8c8\\\n'@'" +IMPORT_FAIL_INGAME = "\\#ffa0a0\\No se pueden importar archivos\nen medio de una partida." [CHAT] -KICKING = "¡Expulsando a '@'!" -BANNING = "¡Vetando a '@'!" -SERVER_ONLY = "Solo el servidor puede usar este comando." -PERM_BANNING = "¡Vetando permanentemente a '@'!" -ADD_MODERATOR = "¡Añadiendo a '@' como Moderador!" +KICKING = "¡'@' ha sido expulsado!" +BANNING = "¡'@' ha sido baneado!" +SERVER_ONLY = "Solo el anfitrión puede usar este comando." +PERM_BANNING = "¡'@' ha sido baneado permanentemente!" +ADD_MODERATOR = "¡'@' ahora es un moderador!" PLAYERS = "Jugadores" NO_PERMS = "No tienes permiso para usar este comando." PLAYER_NOT_FOUND = "No se ha podido encontrar al jugador." SELF_KICK = "No te puedes expulsar a tí mismo." -SELF_BAN = "No te puedes vetar a tí mismo." -SELF_MOD = "No te puedes hacerte moderador a tí mismo." -KICK_CONFIRM = "¿Seguro que quieres expulsar a '@'?\nEscribe '\\#a0ffa0\\/confirm\\#fff982\\' para expusar." -BAN_CONFIRM = "¿Seguro que quieres vetar a '@'?\nEscribe '\\#a0ffa0\\/confirm\\#fff982\\' para vetar." -PERM_BAN_CONFIRM = "¿Seguro que quieres vetar permanentemente a '@'?\nEscribe '\\#a0ffa0\\/confirm\\#fff982\\' para vetar." -MOD_CONFIRM = "¿Seguro que quieres convertir a '@' en moderador?\Escribe '\\#a0ffa0\\/confirm\\#fff982\\'." -PLAYERS_DESC = "/players - Mostrar lista de todos los jugadores y sus IDs" -KICK_DESC = "/kick [NAME|ID] - Expulsar al jugador de la partida actual" -BAN_DESC = "/ban [NAME|ID] - Vetar al jugador de la partida actual" -PERM_BAN_DESC = "/permban [NAME|ID] - Vetar al jugador de todas tus partidas" -MOD_DESC = "/moderator [NAME|ID] - Permitir a este jugador usar comandos como /kick, /ban o /permban de cualquier juego que alojes" -UNRECOGNIZED = "Comando de chat desconocido." -MOD_GRANTED = "\\#fff982\\Ahora eres un Moderador." +SELF_BAN = "No te puedes banear a tí mismo." +SELF_MOD = "No puedes hacerte moderador a tí mismo." +KICK_CONFIRM = "¿Seguro que quieres expulsar a '@'?\nEscribe '\\#a0ffa0\\/confirm\\#fff982\\' para expulsar." +BAN_CONFIRM = "¿Seguro que quieres banear a '@'?\nEscribe '\\#a0ffa0\\/confirm\\#fff982\\' para banear." +PERM_BAN_CONFIRM = "¿Seguro que quieres banear permanentemente a '@'?\nEscribe '\\#a0ffa0\\/confirm\\#fff982\\' para banear." +MOD_CONFIRM = "¿Seguro que quieres hacer moderador a '@'?\nEscribe '\\#a0ffa0\\/confirm\\#fff982\\'." +PLAYERS_DESC = "/players - Muestra la lista de todos los jugadores y sus IDs." +KICK_DESC = "/kick [NAME|ID] - Expulsa al jugador de la partida actual." +BAN_DESC = "/ban [NAME|ID] - Banea al jugador de la partida actual." +PERM_BAN_DESC = "/permban [NAME|ID] - Banea al jugador de todas tus partidas." +MOD_DESC = "/moderator [NAME|ID] - Permite a un jugador usar comandos como /kick, /ban o /permban de cualquier partida que crees." +UNRECOGNIZED = "Comando desconocido." +MOD_GRANTED = "\\#fff982\\Ahora eres un moderador." [MENU] BACK = "Volver" @@ -52,37 +52,37 @@ YES = "Sí" [CAMERA] CAMERA = "CÁMARA" -FREE_CAMERA = "Cámara Libre" -ANALOG_CAMERA = "Cámara Analógica" -MOUSE_LOOK = "Moviemiento con Ratón" +FREE_CAMERA = "Cámara libre" +ANALOG_CAMERA = "Cámara analógica" +MOUSE_LOOK = "Movimiento con mouse" INVERT_X = "Invertir eje X" INVERT_Y = "Invertir eje Y" -X_SENSITIVITY = "Sensibilidad Eje X" -Y_SENSITIVITY = "Sensibilidad Eje Y" -AGGRESSION = "Agresíon" -PAN_LEVEL = "Nivel Seguimiento" +X_SENSITIVITY = "Sensibilidad eje X" +Y_SENSITIVITY = "Sensibilidad eje Y" +AGGRESSION = "Agresión" +PAN_LEVEL = "Nivel de seguimiento" DECELERATION = "Deceleración" [CHEATS] CHEATS = "TRUCOS" -MOON_JUMP = "Salto Lunar" +MOON_JUMP = "Salto lunar" GOD_MODE = "Modo Dios" -INFINITE_LIVES = "Vidas Ilimitadas" -SUPER_SPEED = "Super Velocidad" -RESPONSIVE_CONTROLS = "Controles Responsivos" -RAPID_FIRE = "Pulsación Rápida (A)" -BLJ_ANYWHERE = "BLJ en cualquier parte" -ALWAYS_TRIPLE_JUMP = "Siempre hacer Triple Salto" +INFINITE_LIVES = "Vidas infinitas" +SUPER_SPEED = "Super velocidad" +RESPONSIVE_CONTROLS = "Controles responsivos" +RAPID_FIRE = "Pulsación rápida (A)" +BLJ_ANYWHERE = "BLJ donde sea" +ALWAYS_TRIPLE_JUMP = "Siempre hacer triple salto" [CONTROLS] CONTROLS = "CONTROLES" -N64_BINDS = "Asignaciones N64" -EXTRA_BINDS = "Asignaciones Extra" +N64_BINDS = "Botones N64" +EXTRA_BINDS = "Botones Extra" BACKGROUND_GAMEPAD = "Mando en segundo plano" GAMEPAD = "Mando" DEADZONE = "Zona muerta" -RUMBLE_STRENGTH = "Fuerza de Vibración" +RUMBLE_STRENGTH = "Fuerza de vibración" CHAT = "Chat" PLAYERS = "Jugadores" @@ -111,12 +111,12 @@ C_RIGHT = "C Derecha" [DISPLAY] DISPLAY = "PANTALLA" FULLSCREEN = "Pantalla completa" -PRELOAD_TEXTURES = "Precargar Texturas" -VSYNC = "Sincronización Vertical" +PRELOAD_TEXTURES = "Precargar texturas" +VSYNC = "Sincronización vertical" UNCAPPED_FRAMERATE = "FPS sin límite" FRAME_LIMIT = "Límite de FPS" -FAST = "Rápido" -ACCURATE = "Preciso" +FAST = "Rápida" +ACCURATE = "Precisa" INTERPOLATION = "Interpolación" NEAREST = "Más cercano" LINEAR = "Lineal" @@ -128,33 +128,33 @@ D1P5X = "1.5x" D3X = "3x" D10X = "10x" D100X = "100x" -DRAW_DISTANCE = "Distancia de Dibujado" -DYNOS_PACKS = "Packs DynOS" +DRAW_DISTANCE = "Distancia de dibujado" +DYNOS_PACKS = "Packs de DynOS" [DYNOS] DYNOS = "DYNOS" [HOST_MESSAGE] INFO_TITLE = "INFO" -WARN_DISCORD = "Invita a amigos haciendo click derecho en su nombre en Discord y seleccionando\n'\\#d0d0ff\\Invitar a unirse\\#c8c8c8\\'.\n\nPuedes invitar en canales de un servidor también presionando el\nbotón \\#d0d0ff\\+\\#c8c8c8\\ al lado del cuadro de texto del chat.\n\nEl estado de Actividad Actual \\#ffa0a0\\debe estar\\#c8c8c8\\ activado en tus \najustes de Discord.\n\nEstár invisible \\#ffa0a0\\te prevendrá\\#c8c8c8\\ de crear invitaciones." -WARN_DISCORD2 = "\\#ffa0a0\\Error:\\#c8c8c8\\ No se ha detectado a Discord.\n\n\\#a0a0a0\\Prueba a cerrar el juego,\nreiniciar Discord,\ny abrir el juego de nuevo." -WARN_SOCKET = "Las conexiones directas \\#ffa0a0\\requieren\\#c8c8c8\\ que abras los puertos en tu rúter.\n\nAbre el puerto '\\#d0d0ff\\%d\\#c8c8c8\\' con protocolo UDP." -HOST = "Alojar" +WARN_DISCORD = "Invita a amigos haciendo click derecho en su nombre en Discord y seleccionando\n'\\#d0d0ff\\Invitar a unirse\\#c8c8c8\\'.\n\nPuedes invitar en canales de un servidor también presionando el botón \\#d0d0ff\\+\\#c8c8c8\\ al lado del cuadro de texto del chat.\n\nEl estado de Actividad Actual \\#ffa0a0\\debe estar\\#c8c8c8\\ activado en tus ajustes de Discord.\n\nEstar invisible \\#ffa0a0\\te prevendrá\\#c8c8c8\\ de crear invitaciones." +WARN_DISCORD2 = "\\#ffa0a0\\Error:\\#c8c8c8\\ No se ha detectado Discord.\n\n\\#a0a0a0\\Prueba a cerrar el juego,\nreiniciar Discord,\ny abrir el juego de nuevo." +WARN_SOCKET = "Las conexiones directas \\#ffa0a0\\requieren\\#c8c8c8\\ que abras los puertos en tu router.\n\nAbre el puerto '\\#d0d0ff\\%d\\#c8c8c8\\' con protocolo UDP." +HOST = "Crear" [HOST_MODS] ROMHACKS = "ROMHACKS" MODS = "MODS" [HOST_SAVE] -SAVE_TITLE = "GUARDAR" +SAVE_TITLE = "RANURAS DE\nGUARDADO" ERASE_TITLE = "BORRAR" CONFIRM = "¿Seguro que quieres borrar esta partida?" ERASE = "Borrar" [HOST_SETTINGS] SETTINGS = "AJUSTES" -NONSOLID = "Intangible" -SOLID = "Tangible" +NONSOLID = "No Sólida" +SOLID = "Sólida" FRIENDLY_FIRE = "Fuego Amigo" PLAYER_INTERACTION = "Interacción entre jugadores" WEAK = "Poca" @@ -163,7 +163,7 @@ TOO_MUCH = "Demasiada" KNOCKBACK_STRENGTH = "Fuerza de retroceso" LEAVE_LEVEL = "Salir del nivel" STAY_IN_LEVEL = "Seguir en el nivel" -NONSTOP = "Siguiente misión" +NONSTOP = "Sin parar" ON_STAR_COLLECTION = "Al conseguir una estrella" SKIP_INTRO_CUTSCENE = "Saltar cinemática de introducción" SHARE_LIVES = "Compartir vidas" @@ -172,33 +172,33 @@ BUBBLE_ON_DEATH = "Burbuja al morir" AMOUNT_OF_PLAYERS = "Número de jugadores" [HOST] -SERVER_TITLE = "SERVIDOR" -HOST_TITLE = "ALOJAR" +SERVER_TITLE = "PARTIDA" +HOST_TITLE = "CREAR" DISCORD = "Discord" COOPNET = "CoopNet" DIRECT_CONNECTION = "Conexión Directa" NETWORK_SYSTEM = "Modo de conexión" PORT = "Puerto" -SAVE_SLOT = "Ranura de Guardado" +SAVE_SLOT = "Ranuras" SETTINGS = "Ajustes" MODS = "Mods" ROMHACKS = "Rom-Hacks" APPLY = "Aplicar" -HOST = "Alojar" +HOST = "Crear" [JOIN_MESSAGE] -JOINING = "UNIENDOSE" +JOINING = "UNIÉNDOSE" [JOIN] JOIN_TITLE = "UNIRSE" -JOIN_DISCORD = "Para unirte a un lobby en \\#d0d0ff\\Discord\\#c8c8c8\\:\n\nManten el juego abierto y acepta la invitación.\n\nSi la invitación dice que la partida ha terminado, haz click en el nombre de la persona que te invitó para refrescarla." -JOIN_SOCKET = "Introduce la IP y el puerto de \\#d0d0ff\\conexión directa\\#c8c8c8\\:" +JOIN_DISCORD = "Para unirte a un lobby en \\#d0d0ff\\Discord\\#c8c8c8\\:\n\nMantén el juego abierto y acepta la invitación.\n\nSi la invitación dice que la partida ha terminado, haz click en el nombre de la persona que te invitó para\nrefrescarla." +JOIN_SOCKET = "Introduce la IP y el puerto de la \\#d0d0ff\\conexión directa\\#c8c8c8\\:" JOIN = "Unirse" [MAIN] QUIT_TITLE = "SALIR" QUIT_CONFIRM = "¿Seguro que quieres salir?" -HOST = "Alojar" +HOST = "Crear" JOIN = "Unirse" OPTIONS = "Opciones" QUIT = "Salir" @@ -206,9 +206,9 @@ QUIT = "Salir" [MENU_OPTIONS] MAIN_MENU = "MENÚ PRINCIPAL" LEVEL = "Nivel" -USE_STAGE_MUSIC = "Usar Música del Nivel" -RANDOM_STAGE = "Nivel Aleatório" -PLAY_VANILLA_DEMOS = "Reproducir Demostraciones Vanilla" +USE_STAGE_MUSIC = "Usar música del nivel" +RANDOM_STAGE = "Nivel aleatorio" +PLAY_VANILLA_DEMOS = "Demos originales" [MISC] DEBUG_TITLE = "DEPURACIÓN" @@ -217,10 +217,10 @@ LUA_PROFILER = "Perfilador de Lua" DEBUG_PRINT = "Mensajes de Depuración" DEBUG_INFO = "Información de Depuración" DEBUG_ERRORS = "Errores de Depuración" -MISC_TITLE = "MISCELÁNEO" -PAUSE_IN_SINGLEPLAYER = "Pausa en Modo de Un jugador" -DISABLE_POPUPS = "Deshabilitar Mensajes Emergentes" -MENU_OPTIONS = "Opciones del Menú" +MISC_TITLE = "OTROS" +PAUSE_IN_SINGLEPLAYER = "Pausa en modo de un jugador" +DISABLE_POPUPS = "Deshabilitar mensajes emergentes" +MENU_OPTIONS = "Opciones del menú" DEBUG = "Depuración" LANGUAGE = "Idioma" @@ -234,26 +234,26 @@ CAMERA = "Cámara" CONTROLS = "Controles" DISPLAY = "Pantalla" SOUND = "Sonido" -MISC = "Misceláneo" +MISC = "Otros" [PAUSE] QUIT_TITLE = "SALIR" -QUIT_HOST = "¿Seguro que quieres dejar de alojar?" +QUIT_HOST = "¿Seguro que quieres finalizar la partida?" QUIT_CLIENT = "¿Seguro que te quieres desconectar?" PAUSE_TITLE = "PAUSA" PLAYER = "Jugador" -DYNOS_PACKS = "Packs DynOS" +DYNOS_PACKS = "Packs de DynOS" OPTIONS = "Opciones" CHEATS = "Trucos" -SERVER_SETTINGS = "Ajustes del Servidor" +SERVER_SETTINGS = "Ajustes de la partida" RESUME = "Continuar" -STOP_HOSTING = "Dejar de Alojar" +STOP_HOSTING = "Finalizar partida" DISCONNECT = "Desconectarse" [PLAYER] PLAYER_TITLE = "JUGADOR" -OVERALLS = "Tirantes" -SHIRT = "Camisa" +OVERALLS = "Overoles" +SHIRT = "Camiseta" GLOVES = "Guantes" SHOES = "Zapatos" HAIR = "Pelo" @@ -268,7 +268,7 @@ BLUE = "Azul" PLAYER = "Jugador" NAME = "Nombre" MODEL = "Modelo" -PALETTE_PRESET = "Perfil de Paleta" +PALETTE_PRESET = "Paletas predeterminadas" EDIT_PALETTE = "Editar Paleta" [PALETTE] @@ -304,20 +304,20 @@ RASPBERRY = "Frambuesa" BUBBLEGUM = "Chicle" ICE_MARIO = "Mario de Hielo" ICE_LUIGI = "Luigi de Hielo" -CUSTOM = "Personalizado" +CUSTOM = "Personalizada" [PLAYER_LIST] PLAYERS = "JUGADORES" NAME = "nombre" LOCATION = "localización" -ACT = "recorrido" +ACT = "acto" [SOUND] SOUND = "SONIDO" -MASTER_VOLUME = "Volumen Maestro" -MUSIC_VOLUME = "Volumen Música" -SFX_VOLUME = "Volumen Efectos de Sonido" -ENV_VOLUME = "Volumen Entorno" +MASTER_VOLUME = "Volumen General" +MUSIC_VOLUME = "Volumen de Música" +SFX_VOLUME = "Volumen de Efectos de Sonido" +ENV_VOLUME = "Volumen de Entorno" [LANGUAGE] LANGUAGE = "IDIOMA" \ No newline at end of file diff --git a/mods/arena/arena-player.lua b/mods/arena/arena-player.lua index 42ff344b..d8afe043 100644 --- a/mods/arena/arena-player.lua +++ b/mods/arena/arena-player.lua @@ -28,6 +28,14 @@ for i = 0, (MAX_PLAYERS - 1) do s.rank = 0 end +local sKnockbackActions = { + ACT_SOFT_FORWARD_GROUND_KB, ACT_FORWARD_GROUND_KB, ACT_HARD_FORWARD_GROUND_KB, + ACT_FORWARD_AIR_KB, ACT_FORWARD_AIR_KB, ACT_HARD_FORWARD_AIR_KB, + ACT_FORWARD_WATER_KB, ACT_FORWARD_WATER_KB, ACT_FORWARD_WATER_KB, + ACT_SOFT_BACKWARD_GROUND_KB, ACT_BACKWARD_GROUND_KB, ACT_HARD_BACKWARD_GROUND_KB, + ACT_BACKWARD_AIR_KB, ACT_BACKWARD_AIR_KB, ACT_HARD_BACKWARD_AIR_KB, + ACT_BACKWARD_WATER_KB, ACT_BACKWARD_WATER_KB, ACT_BACKWARD_WATER_KB +} ------------ -- hammer -- ------------ @@ -361,6 +369,27 @@ function mario_update(m) local s = gPlayerSyncTable[m.playerIndex] local np = gNetworkPlayers[m.playerIndex] + -- increase knockback animations + local animInfo = nil + if m.marioObj ~= nil then + animInfo = m.marioObj.header.gfx.animInfo + end + for i, value in ipairs(sKnockbackActions) do + if m.action == value then + local frame = animInfo.animFrame + local loopEnd = frame + if animInfo.curAnim ~= nil then + loopEnd = animInfo.curAnim.loopEnd + end + + if frame < loopEnd - 2 then + frame = frame + 1 + end + + animInfo.animFrame = frame + end + end + -- clear invincibilities m.invincTimer = 0 if m.knockbackTimer > 5 then diff --git a/mods/extended-moveset.lua b/mods/extended-moveset.lua index 2cd8644d..1ff1f6bf 100644 --- a/mods/extended-moveset.lua +++ b/mods/extended-moveset.lua @@ -1163,7 +1163,7 @@ function act_walking(m) end function act_hold_walking(m) - if m.heldObj.behavior == bhvJumpingBox then + if m.heldObj ~= nil and m.heldObj.behavior == bhvJumpingBox then return set_mario_action(m, ACT_CRAZY_BOX_BOUNCE, 0) end diff --git a/mods/sm74/dialog.lua b/mods/sm74/dialog.lua index cabb1ad9..1f1e58d9 100644 --- a/mods/sm74/dialog.lua +++ b/mods/sm74/dialog.lua @@ -2195,27 +2195,46 @@ possibility.\ Good luck and\ frustration resistance.") +-- smlua_text_utils_dialog_replace(DIALOG_063,1,5,30,200, "It's really a shame but\ +-- this level was way too\ +-- big for the level importer\ +-- so I had to split it\ +-- into two parts.\ +-- That means I CAN'T place\ +-- red coins in the whole\ +-- level. Sad, isn't it?\ +-- I know that you would\ +-- enjoy collecting 30\ +-- red coins, right?\ +-- Well then, instead,\ +-- the red coins are all\ +-- beyond the cannon.\ +-- And since they are so\ +-- close together\ +-- I won't tell you how\ +-- many there are.\ +-- \ +-- (Well, honestly, I forgot\ +-- how many I placed.)") + smlua_text_utils_dialog_replace(DIALOG_063,1,5,30,200, "It's really a shame but\ this level was way too\ big for the level importer\ so I had to split it\ into two parts.\ -That means I CAN'T place\ +Nah! Just kidding!\ +You're no longer playing\ +a Nintendo 64 rom-hack.\ +It's the pc port we're\ +talking about!\ +That means I CAN place\ red coins in the whole\ -level. Sad, isn't it?\ +level. Great, isn't it?\ I know that you would\ enjoy collecting 30\ -red coins, right?\ -Well then, instead,\ -the red coins are all\ -beyond the cannon.\ -And since they are so\ -close together\ -I won't tell you how\ -many there are.\ -\ -(Well, honestly, I forgot\ -how many I placed.)") +red coins. So, after 9\ +years, it's finally\ +possible. Have fun!") smlua_text_utils_dialog_replace(DIALOG_064,1,5,30,200, "You should already know\ the concept of this\ diff --git a/src/game/area.c b/src/game/area.c index f66dc314..bb1688af 100644 --- a/src/game/area.c +++ b/src/game/area.c @@ -161,6 +161,8 @@ u32 get_mario_spawn_type(struct Object *o) { } struct ObjectWarpNode *area_get_warp_node(u8 id) { + if (!gCurrentArea || !gCurrentArea->warpNodes) { return NULL; } + struct ObjectWarpNode *node = NULL; for (node = gCurrentArea->warpNodes; node != NULL; node = node->next) { diff --git a/src/game/behaviors/beta_boo_key.inc.c b/src/game/behaviors/beta_boo_key.inc.c index 27a85dee..2e81c7f0 100644 --- a/src/game/behaviors/beta_boo_key.inc.c +++ b/src/game/behaviors/beta_boo_key.inc.c @@ -170,5 +170,5 @@ static void (*sBetaBooKeyActions[])(void) = { beta_boo_key_inside_boo_loop, beta * Update function for bhvBetaBooKey. */ void bhv_beta_boo_key_loop(void) { - cur_obj_call_action_function(sBetaBooKeyActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sBetaBooKeyActions); } diff --git a/src/game/behaviors/boo.inc.c b/src/game/behaviors/boo.inc.c index d799209f..45e4a960 100644 --- a/src/game/behaviors/boo.inc.c +++ b/src/game/behaviors/boo.inc.c @@ -555,7 +555,7 @@ void bhv_boo_loop(void) { //PARTIAL_UPDATE cur_obj_update_floor_and_walls(); - cur_obj_call_action_function(sBooActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sBooActions); cur_obj_move_standard(78); boo_approach_target_opacity_and_update_scale(); @@ -793,7 +793,7 @@ void bhv_big_boo_loop(void) { o->oGraphYOffset = o->oBooBaseScale * 60.0f; cur_obj_update_floor_and_walls(); - cur_obj_call_action_function(sBooGivingStarActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sBooGivingStarActions); cur_obj_move_standard(78); boo_approach_target_opacity_and_update_scale(); @@ -870,7 +870,7 @@ void bhv_boo_with_cage_loop(void) { //PARTIAL_UPDATE cur_obj_update_floor_and_walls(); - cur_obj_call_action_function(sBooWithCageActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sBooWithCageActions); cur_obj_move_standard(78); boo_approach_target_opacity_and_update_scale(); diff --git a/src/game/behaviors/bowser.inc.c b/src/game/behaviors/bowser.inc.c index 3b88896a..8cf90add 100644 --- a/src/game/behaviors/bowser.inc.c +++ b/src/game/behaviors/bowser.inc.c @@ -59,7 +59,7 @@ void bhv_bowser_tail_anchor_init(void) { } void bhv_bowser_tail_anchor_loop(void) { - cur_obj_call_action_function(sBowserTailAnchorActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sBowserTailAnchorActions); o->oParentRelativePosX = 90.0f; if (o->parentObj->oAction == 4) o->parentObj->oIntangibleTimer = -1; @@ -1204,7 +1204,7 @@ void bowser_free_update(void) { o->oBowserUnk10E = 0; cur_obj_update_floor_and_walls(); - cur_obj_call_action_function(sBowserActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sBowserActions); cur_obj_move_standard(-78); if (bowser_check_fallen_off_stage()) o->oAction = 2; // bowser go home? @@ -1657,7 +1657,7 @@ void bhv_falling_bowser_platform_loop(void) { } } - cur_obj_call_action_function(sFallingBowserPlatformActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sFallingBowserPlatformActions); } void bowser_flame_despawn(void) { diff --git a/src/game/behaviors/bowser_puzzle_piece.inc.c b/src/game/behaviors/bowser_puzzle_piece.inc.c index fa8250d9..c6eb6338 100644 --- a/src/game/behaviors/bowser_puzzle_piece.inc.c +++ b/src/game/behaviors/bowser_puzzle_piece.inc.c @@ -275,7 +275,7 @@ void (*sBowserPuzzlePieceActions[])(void) = { void bhv_lll_bowser_puzzle_piece_loop(void) { bhv_lll_bowser_puzzle_piece_update(); - cur_obj_call_action_function(sBowserPuzzlePieceActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sBowserPuzzlePieceActions); o->oPosX = o->oBowserPuzzlePieceOffsetX + o->oHomeX; o->oPosY = o->oBowserPuzzlePieceOffsetY + o->oHomeY; diff --git a/src/game/behaviors/bub.inc.c b/src/game/behaviors/bub.inc.c index bb4e83fb..831b2916 100644 --- a/src/game/behaviors/bub.inc.c +++ b/src/game/behaviors/bub.inc.c @@ -28,7 +28,7 @@ void (*sBirdChirpChirpActions[])(void) = { bub_spawner_act_0, bub_spawner_act_1, bub_spawner_act_2, bub_spawner_act_3 }; void bhv_bub_spawner_loop(void) { - cur_obj_call_action_function(sBirdChirpChirpActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sBirdChirpChirpActions); } void bub_move_vertically(s32 a0) { @@ -136,7 +136,7 @@ void bhv_bub_loop(void) { } o->oWallHitboxRadius = 30.0f; cur_obj_update_floor_and_walls(); - cur_obj_call_action_function(sCheepCheepActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sCheepCheepActions); cur_obj_move_using_fvel_and_gravity(); if (o->parentObj->oAction == 2) obj_mark_for_deletion(o); diff --git a/src/game/behaviors/bullet_bill.inc.c b/src/game/behaviors/bullet_bill.inc.c index b1cf7ef0..8260f1fa 100644 --- a/src/game/behaviors/bullet_bill.inc.c +++ b/src/game/behaviors/bullet_bill.inc.c @@ -86,7 +86,7 @@ void (*sBulletBillActions[])(void) = { bullet_bill_act_0, bullet_bill_act_1, bul bullet_bill_act_3, bullet_bill_act_4 }; void bhv_bullet_bill_loop(void) { - cur_obj_call_action_function(sBulletBillActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sBulletBillActions); if (cur_obj_check_interacted()) o->oAction = 4; } diff --git a/src/game/behaviors/cannon.inc.c b/src/game/behaviors/cannon.inc.c index a942bd09..c5d7bc6d 100644 --- a/src/game/behaviors/cannon.inc.c +++ b/src/game/behaviors/cannon.inc.c @@ -237,7 +237,7 @@ void bhv_cannon_base_loop(void) { cur_obj_push_mario_away_from_cylinder(220, 300); } - cur_obj_call_action_function(sOpenedCannonActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sOpenedCannonActions); if (o->oCannonUnkF8) o->oCannonUnkF8++; o->oInteractStatus = 0; diff --git a/src/game/behaviors/capswitch.inc.c b/src/game/behaviors/capswitch.inc.c index 2e147963..dab3e6ad 100644 --- a/src/game/behaviors/capswitch.inc.c +++ b/src/game/behaviors/capswitch.inc.c @@ -65,5 +65,5 @@ void bhv_cap_switch_loop(void) { sync_object_init_field(o, &capSwitchForcePress); } - cur_obj_call_action_function(sCapSwitchActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sCapSwitchActions); } diff --git a/src/game/behaviors/chuckya.inc.c b/src/game/behaviors/chuckya.inc.c index 443fef3d..798e5dc0 100644 --- a/src/game/behaviors/chuckya.inc.c +++ b/src/game/behaviors/chuckya.inc.c @@ -193,7 +193,7 @@ void (*sChuckyaActions[])(void) = { chuckya_act_0, chuckya_act_1, chuckya_act_2, void chuckya_move(void) { cur_obj_update_floor_and_walls(); - cur_obj_call_action_function(sChuckyaActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sChuckyaActions); cur_obj_move_standard(-30); if (o->oInteractStatus & INT_STATUS_GRABBED_MARIO) { o->oAction = 1; diff --git a/src/game/behaviors/coin.inc.c b/src/game/behaviors/coin.inc.c index 4733bcd7..b44835da 100644 --- a/src/game/behaviors/coin.inc.c +++ b/src/game/behaviors/coin.inc.c @@ -255,7 +255,7 @@ void coin_inside_boo_act_0(void) { void (*sCoinInsideBooActions[])(void) = { coin_inside_boo_act_0, coin_inside_boo_act_1 }; void bhv_coin_inside_boo_loop(void) { - cur_obj_call_action_function(sCoinInsideBooActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sCoinInsideBooActions); } void bhv_coin_sparkles_loop(void) { diff --git a/src/game/behaviors/elevator.inc.c b/src/game/behaviors/elevator.inc.c index 19c78e49..a0c02815 100644 --- a/src/game/behaviors/elevator.inc.c +++ b/src/game/behaviors/elevator.inc.c @@ -154,7 +154,7 @@ struct SpawnParticlesInfo D_8032F3FC = { 0, 5, MODEL_WHITE_PARTICLE_DL, 0, 2.0f, 2.0f }; void bhv_elevator_loop(void) { - cur_obj_call_action_function(sElevatorActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sElevatorActions); // allow bubbled players to pass through if (gMarioStates[0].action == ACT_BUBBLED) { diff --git a/src/game/behaviors/exclamation_box.inc.c b/src/game/behaviors/exclamation_box.inc.c index 8a1ea789..01a2e758 100644 --- a/src/game/behaviors/exclamation_box.inc.c +++ b/src/game/behaviors/exclamation_box.inc.c @@ -214,5 +214,5 @@ void bhv_exclamation_box_init(void) { void bhv_exclamation_box_loop(void) { cur_obj_scale(2.0f); - cur_obj_call_action_function(sExclamationBoxActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sExclamationBoxActions); } diff --git a/src/game/behaviors/fish.inc.c b/src/game/behaviors/fish.inc.c index 0c4e36c5..330758f6 100644 --- a/src/game/behaviors/fish.inc.c +++ b/src/game/behaviors/fish.inc.c @@ -73,7 +73,7 @@ static void (*sFishSpawnerActions[])(void) = { }; void bhv_fish_spawner_loop(void) { - cur_obj_call_action_function(sFishSpawnerActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sFishSpawnerActions); } /** @@ -276,7 +276,7 @@ void bhv_fish_loop(void) } // Call fish action methods and apply physics engine. - cur_obj_call_action_function(sFishActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sFishActions); cur_obj_move_using_fvel_and_gravity(); // If the parent object has action set to two, then delete the fish object. diff --git a/src/game/behaviors/heave_ho.inc.c b/src/game/behaviors/heave_ho.inc.c index 7b84f977..8e86f057 100644 --- a/src/game/behaviors/heave_ho.inc.c +++ b/src/game/behaviors/heave_ho.inc.c @@ -99,7 +99,7 @@ void (*sHeaveHoActions[])(void) = { heave_ho_act_0, heave_ho_act_1, heave_ho_act void heave_ho_move(void) { cur_obj_update_floor_and_walls(); - cur_obj_call_action_function(sHeaveHoActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sHeaveHoActions); cur_obj_move_standard(-78); if (o->oMoveFlags & OBJ_MOVE_MASK_IN_WATER) o->oGraphYOffset = -15.0f; diff --git a/src/game/behaviors/jumping_box.inc.c b/src/game/behaviors/jumping_box.inc.c index 8dc8ef8f..732348ac 100644 --- a/src/game/behaviors/jumping_box.inc.c +++ b/src/game/behaviors/jumping_box.inc.c @@ -41,7 +41,7 @@ void jumping_box_free_update(void) { obj_set_hitbox(o, &sJumpingBoxHitbox); cur_obj_update_floor_and_walls(); cur_obj_move_standard(78); - cur_obj_call_action_function(sJumpingBoxActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sJumpingBoxActions); } void bhv_jumping_box_loop(void) { diff --git a/src/game/behaviors/king_bobomb.inc.c b/src/game/behaviors/king_bobomb.inc.c index 17710e01..ffc786e1 100644 --- a/src/game/behaviors/king_bobomb.inc.c +++ b/src/game/behaviors/king_bobomb.inc.c @@ -365,7 +365,7 @@ void king_bobomb_move(void) { cur_obj_move_standard(-78); else cur_obj_move_using_fvel_and_gravity(); - cur_obj_call_action_function(sKingBobombActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sKingBobombActions); exec_anim_sound_state(sKingBobombSoundStates); s32 distanceToPlayer = dist_between_objects(o, gMarioStates[0].marioObj); if (distanceToPlayer < 5000.0f * draw_distance_scalar()) diff --git a/src/game/behaviors/lll_rotating_hex_flame.inc.c b/src/game/behaviors/lll_rotating_hex_flame.inc.c index a47d7ec5..02c55cd2 100644 --- a/src/game/behaviors/lll_rotating_hex_flame.inc.c +++ b/src/game/behaviors/lll_rotating_hex_flame.inc.c @@ -60,7 +60,7 @@ void bhv_lll_rotating_block_fire_bars_loop(void) { sync_object_init(o, 4000.0f); sync_object_init_field(o, &o->oAngleVelYaw); } - cur_obj_call_action_function(sRotatingCwFireBarsActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sRotatingCwFireBarsActions); if (o->oBehParams2ndByte == 0) load_object_collision_model(); } diff --git a/src/game/behaviors/mr_i.inc.c b/src/game/behaviors/mr_i.inc.c index 3202eefd..3033d717 100644 --- a/src/game/behaviors/mr_i.inc.c +++ b/src/game/behaviors/mr_i.inc.c @@ -33,7 +33,7 @@ void mr_i_piranha_particle_act_1(void) { void (*sMrIParticleActions[])(void) = { mr_i_piranha_particle_act_0, mr_i_piranha_particle_act_1 }; void bhv_mr_i_particle_loop(void) { - cur_obj_call_action_function(sMrIParticleActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sMrIParticleActions); } void spawn_mr_i_particle(void) { @@ -283,7 +283,7 @@ void bhv_mr_i_loop(void) { s32 distanceToPlayer = player ? dist_between_objects(o, player) : 10000; obj_set_hitbox(o, &sMrIHitbox); - cur_obj_call_action_function(sMrIActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sMrIActions); if (o->oAction != 3) { if (distanceToPlayer > 3000.0f || o->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM) { o->oAction = 0; diff --git a/src/game/behaviors/piranha_plant.inc.c b/src/game/behaviors/piranha_plant.inc.c index e7db9cb0..97569d24 100644 --- a/src/game/behaviors/piranha_plant.inc.c +++ b/src/game/behaviors/piranha_plant.inc.c @@ -369,7 +369,7 @@ void bhv_piranha_plant_loop(void) { cur_obj_set_hitbox_radius_and_height(150.0f, 100.0f); cur_obj_set_hurtbox_radius_and_height(150.0f, 100.0f); - cur_obj_call_action_function(TablePiranhaPlantActions); + CUR_OBJ_CALL_ACTION_FUNCTION(TablePiranhaPlantActions); // In WF, hide all Piranha Plants once high enough up. if (gCurrLevelNum == LEVEL_WF) { struct Object* player = gMarioStates[0].marioObj; diff --git a/src/game/behaviors/thwomp.inc.c b/src/game/behaviors/thwomp.inc.c index e016b67b..51d71150 100644 --- a/src/game/behaviors/thwomp.inc.c +++ b/src/game/behaviors/thwomp.inc.c @@ -63,5 +63,5 @@ void bhv_grindel_thwomp_loop(void) { sync_object_init_field(o, &o->oTimer); sync_object_init_field(o, &o->oVelY); } - cur_obj_call_action_function(sGrindelThwompActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sGrindelThwompActions); } diff --git a/src/game/behaviors/tox_box.inc.c b/src/game/behaviors/tox_box.inc.c index 4bdb567b..2a5bbd5d 100644 --- a/src/game/behaviors/tox_box.inc.c +++ b/src/game/behaviors/tox_box.inc.c @@ -85,6 +85,6 @@ void bhv_tox_box_loop(void) { sync_object_init_field(o, &o->oToxBoxMovementStep); } } - cur_obj_call_action_function(sToxBoxActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sToxBoxActions); load_object_collision_model(); } diff --git a/src/game/behaviors/tumbling_bridge.inc.c b/src/game/behaviors/tumbling_bridge.inc.c index 7e2b2152..c8ce02b9 100644 --- a/src/game/behaviors/tumbling_bridge.inc.c +++ b/src/game/behaviors/tumbling_bridge.inc.c @@ -164,5 +164,5 @@ void bhv_tumbling_bridge_loop(void) { } } - cur_obj_call_action_function(sTumblingBridgeActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sTumblingBridgeActions); } diff --git a/src/game/behaviors/tuxie.inc.c b/src/game/behaviors/tuxie.inc.c index fe696cde..0b1fe7a4 100644 --- a/src/game/behaviors/tuxie.inc.c +++ b/src/game/behaviors/tuxie.inc.c @@ -160,7 +160,7 @@ void bhv_tuxies_mother_loop(void) { } o->activeFlags |= ACTIVE_FLAG_UNK10; cur_obj_update_floor_and_walls(); - cur_obj_call_action_function(sTuxiesMotherActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sTuxiesMotherActions); cur_obj_move_standard(-78); play_penguin_walking_sound(PENGUIN_WALK_BIG); o->oInteractStatus = 0; @@ -289,7 +289,7 @@ void small_penguin_free_actions(void) { cur_obj_become_tangible(); cur_obj_enable_rendering(); cur_obj_update_floor_and_walls(); - cur_obj_call_action_function(sSmallPenguinActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sSmallPenguinActions); cur_obj_move_standard(-78); play_penguin_walking_sound(PENGUIN_WALK_BABY); } diff --git a/src/game/behaviors/tweester.inc.c b/src/game/behaviors/tweester.inc.c index 0f97a9fe..8ac1eadc 100644 --- a/src/game/behaviors/tweester.inc.c +++ b/src/game/behaviors/tweester.inc.c @@ -149,7 +149,7 @@ void bhv_tweester_loop(void) { } obj_set_hitbox(o, &sTweesterHitbox); - cur_obj_call_action_function(sTweesterActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sTweesterActions); o->oInteractStatus = 0; } diff --git a/src/game/behaviors/ukiki.inc.c b/src/game/behaviors/ukiki.inc.c index 0e0e987b..1d437351 100644 --- a/src/game/behaviors/ukiki.inc.c +++ b/src/game/behaviors/ukiki.inc.c @@ -504,7 +504,7 @@ void ukiki_free_loop(void) { s32 steepSlopeAngleDegrees; cur_obj_update_floor_and_walls(); - cur_obj_call_action_function(sUkikiActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sUkikiActions); if (o->oAction == UKIKI_ACT_GO_TO_CAGE || o->oAction == UKIKI_ACT_RETURN_HOME) { steepSlopeAngleDegrees = -88; diff --git a/src/game/behaviors/ukiki_cage.inc.c b/src/game/behaviors/ukiki_cage.inc.c index 6ef80bd1..31b47d40 100644 --- a/src/game/behaviors/ukiki_cage.inc.c +++ b/src/game/behaviors/ukiki_cage.inc.c @@ -103,5 +103,5 @@ void (*sUkikiCageActions[])(void) = { * Main behavior loop for the cage. Only calls the relevant action. */ void bhv_ukiki_cage_loop(void) { - cur_obj_call_action_function(sUkikiCageActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sUkikiCageActions); } diff --git a/src/game/behaviors/whomp.inc.c b/src/game/behaviors/whomp.inc.c index 67468d55..75abccbe 100644 --- a/src/game/behaviors/whomp.inc.c +++ b/src/game/behaviors/whomp.inc.c @@ -284,7 +284,7 @@ void bhv_whomp_loop(void) { } cur_obj_update_floor_and_walls(); - cur_obj_call_action_function(sWhompActions); + CUR_OBJ_CALL_ACTION_FUNCTION(sWhompActions); cur_obj_move_standard(-20); if (o->oAction != 9) { // o->oBehParams2ndByte here seems to be a flag diff --git a/src/game/camera.c b/src/game/camera.c index bc775111..ff68369c 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -3297,11 +3297,6 @@ void soft_reset_camera(struct Camera* c) { * Reset all the camera variables to their arcane defaults */ void reset_camera(struct Camera *c) { - UNUSED s32 unused = 0; - UNUSED u8 unused1[16]; - UNUSED struct LinearTransitionPoint *start = &sModeInfo.transitionStart; - UNUSED struct LinearTransitionPoint *end = &sModeInfo.transitionEnd; - gCamera = c; gCameraMovementFlags = 0; s2ndRotateFlags = 0; @@ -3315,7 +3310,6 @@ void reset_camera(struct Camera *c) { unused8032CFCC = 0; gSecondCameraFocus = NULL; sCButtonsPressed = 0; - vec3f_copy(sModeTransition.marioPos, sMarioCamState->pos); sModeTransition.framesLeft = 0; unused8032CFCC = -1; unused8032CFC8 = -1; @@ -3340,11 +3334,19 @@ void reset_camera(struct Camera *c) { sCSideButtonYaw = 0; s8DirModeBaseYaw = 0; s8DirModeYawOffset = 0; - c->doorStatus = DOOR_DEFAULT; - sMarioCamState->headRotation[0] = 0; - sMarioCamState->headRotation[1] = 0; - sMarioCamState->cameraEvent = 0; - sMarioCamState->usedObj = NULL; + + if (c) { + c->doorStatus = DOOR_DEFAULT; + } + + if (sMarioCamState) { + vec3f_copy(sModeTransition.marioPos, sMarioCamState->pos); + sMarioCamState->headRotation[0] = 0; + sMarioCamState->headRotation[1] = 0; + sMarioCamState->cameraEvent = 0; + sMarioCamState->usedObj = NULL; + } + gLakituState.shakeMagnitude[0] = 0; gLakituState.shakeMagnitude[1] = 0; gLakituState.shakeMagnitude[2] = 0; @@ -3355,12 +3357,14 @@ void reset_camera(struct Camera *c) { gLakituState.unusedVec1[1] = 0.f; gLakituState.unusedVec1[2] = 0.f; gLakituState.lastFrameAction = 0; + set_fov_function(CAM_FOV_DEFAULT); sFOVState.fov = 45.f; sFOVState.fovOffset = 0.f; sFOVState.unusedIsSleeping = 0; sFOVState.shakeAmplitude = 0.f; sFOVState.shakePhase = 0; + sObjectCutscene = 0; gRecentCutscene = 0; unused8033B30C = 0; diff --git a/src/game/interaction.c b/src/game/interaction.c index f8739cc2..6c1ff96d 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -59,7 +59,7 @@ enum InteractionFlag { (INT_SLIDE_KICK | INT_FAST_ATTACK_OR_SHELL) u8 sDelayInvincTimer; -s16 sInvulnerable; +s16 gInteractionInvulnerable; u32 interact_coin(struct MarioState *, u32, struct Object *); u32 interact_water_ring(struct MarioState *, u32, struct Object *); u32 interact_star_or_key(struct MarioState *, u32, struct Object *); @@ -824,7 +824,7 @@ u32 take_damage_from_interact_object(struct MarioState *m) { u32 take_damage_and_knock_back(struct MarioState *m, struct Object *o) { u32 damage; - if (!sInvulnerable && !(m->flags & MARIO_VANISH_CAP) + if (!gInteractionInvulnerable && !(m->flags & MARIO_VANISH_CAP) && !(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { o->oInteractStatus = INT_STATUS_INTERACTED | INT_STATUS_ATTACKED_MARIO; m->interactObj = o; @@ -1309,7 +1309,7 @@ static u8 resolve_player_collision(struct MarioState* m, struct MarioState* m2) velY = fmax(fmin(55.0f, 15.0f + fabs(m->vel[1])), 35.0f); } else if (m->action == ACT_DOUBLE_JUMP) { mario_stop_riding_and_holding(m); - set_mario_action(m, (m->specialTripleJump && m->playerIndex == 0) ? ACT_SPECIAL_TRIPLE_JUMP : ACT_TRIPLE_JUMP, 0); + set_mario_action(m, (m->specialTripleJump && m->playerIndex == 0) ? ACT_SPECIAL_TRIPLE_JUMP : m->flags & MARIO_WING_CAP ? ACT_FLYING_TRIPLE_JUMP : ACT_TRIPLE_JUMP, 0); velY = fmax(fmin(60.0f, 20.0f + fabs(m->vel[1])), 40.0f); } else { mario_stop_riding_and_holding(m); @@ -1353,6 +1353,8 @@ u8 player_is_sliding(struct MarioState* m) { } u8 passes_pvp_interaction_checks(struct MarioState* attacker, struct MarioState* victim) { + if (!attacker || !victim) { return false; } + // attacked u8 isInCutscene = ((attacker->action & ACT_GROUP_MASK) == ACT_GROUP_CUTSCENE) || ((victim->action & ACT_GROUP_MASK) == ACT_GROUP_CUTSCENE); isInCutscene = isInCutscene || (attacker->action == ACT_IN_CANNON) || (victim->action == ACT_IN_CANNON); @@ -1587,7 +1589,7 @@ u32 interact_strong_wind(struct MarioState *m, UNUSED u32 interactType, struct O u32 interact_flame(struct MarioState *m, UNUSED u32 interactType, struct Object *o) { u32 burningAction = ACT_BURNING_JUMP; - if (!sInvulnerable && !(m->flags & MARIO_METAL_CAP) && !(m->flags & MARIO_VANISH_CAP) + if (!gInteractionInvulnerable && !(m->flags & MARIO_METAL_CAP) && !(m->flags & MARIO_VANISH_CAP) && !(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { queue_rumble_data_mario(m, 5, 80); @@ -1614,7 +1616,7 @@ u32 interact_flame(struct MarioState *m, UNUSED u32 interactType, struct Object } u32 interact_snufit_bullet(struct MarioState *m, UNUSED u32 interactType, struct Object *o) { - if (!sInvulnerable && !(m->flags & MARIO_VANISH_CAP)) { + if (!gInteractionInvulnerable && !(m->flags & MARIO_VANISH_CAP)) { if (m->flags & MARIO_METAL_CAP) { o->oInteractStatus = INT_STATUS_INTERACTED | INT_STATUS_WAS_ATTACKED; play_sound(SOUND_ACTION_UNKNOWN458, m->marioObj->header.gfx.cameraToObject); @@ -1679,7 +1681,7 @@ u32 interact_bully(struct MarioState *m, UNUSED u32 interactType, struct Object return TRUE; } - else if (!sInvulnerable && !(m->flags & MARIO_VANISH_CAP) + else if (!gInteractionInvulnerable && !(m->flags & MARIO_VANISH_CAP) && !(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { o->oInteractStatus = INT_STATUS_INTERACTED; m->invincTimer = 2; @@ -1699,7 +1701,7 @@ u32 interact_bully(struct MarioState *m, UNUSED u32 interactType, struct Object } u32 interact_shock(struct MarioState *m, UNUSED u32 interactType, struct Object *o) { - if (!sInvulnerable && !(m->flags & MARIO_VANISH_CAP) + if (!gInteractionInvulnerable && !(m->flags & MARIO_VANISH_CAP) && !(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { u32 actionArg = (m->action & (ACT_FLAG_AIR | ACT_FLAG_ON_POLE | ACT_FLAG_HANGING)) == 0; @@ -1916,7 +1918,7 @@ u32 interact_koopa_shell(struct MarioState *m, UNUSED u32 interactType, struct O u32 check_object_grab_mario(struct MarioState *m, UNUSED u32 interactType, struct Object *o) { if (m != &gMarioStates[0]) { return false; } - if ((!(m->action & (ACT_FLAG_AIR | ACT_FLAG_INVULNERABLE | ACT_FLAG_ATTACKING)) || !sInvulnerable) + if ((!(m->action & (ACT_FLAG_AIR | ACT_FLAG_INVULNERABLE | ACT_FLAG_ATTACKING)) || !gInteractionInvulnerable) && (o->oInteractionSubtype & INT_SUBTYPE_GRABS_MARIO)) { if (object_facing_mario(m, o, 0x2AAA)) { mario_stop_riding_and_holding(m); @@ -2222,7 +2224,7 @@ void check_kick_or_punch_wall(struct MarioState *m) { void mario_process_interactions(struct MarioState *m) { sDelayInvincTimer = FALSE; - sInvulnerable = (m->action & ACT_FLAG_INVULNERABLE) || m->invincTimer != 0; + gInteractionInvulnerable = (m->action & ACT_FLAG_INVULNERABLE) || m->invincTimer != 0; if (!(m->action & ACT_FLAG_INTANGIBLE) && m->collidedObjInteractTypes != 0 && is_player_active(m)) { s32 i; diff --git a/src/game/interaction.h b/src/game/interaction.h index 6ab63441..5be968c4 100644 --- a/src/game/interaction.h +++ b/src/game/interaction.h @@ -98,6 +98,7 @@ enum InteractionType { #define INT_STATUS_STOP_RIDING (1 << 22) /* 0x00400000 */ #define INT_STATUS_TOUCHED_BOB_OMB (1 << 23) /* 0x00800000 */ +extern s16 gInteractionInvulnerable; extern u8 gPssSlideStarted; s16 mario_obj_angle_to_object(struct MarioState *m, struct Object *o); diff --git a/src/game/mario.c b/src/game/mario.c index abe156b0..d1cdb75e 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -176,7 +176,11 @@ void set_anim_to_frame(struct MarioState *m, s16 animFrame) { s32 is_anim_past_frame(struct MarioState *m, s16 animFrame) { s32 isPastFrame; s32 acceleratedFrame = animFrame << 0x10; + + if (!m || !m->marioObj) { return TRUE; } struct AnimInfo *animInfo = &m->marioObj->header.gfx.animInfo; + + if (!animInfo->curAnim) { return TRUE; } struct Animation *curAnim = animInfo->curAnim; if (animInfo->animAccel) { diff --git a/src/game/object_helpers.c b/src/game/object_helpers.c index 3cc94e64..350b7e01 100644 --- a/src/game/object_helpers.c +++ b/src/game/object_helpers.c @@ -2282,6 +2282,8 @@ s32 cur_obj_follow_path(UNUSED s32 unusedArg) { f32 objToNextXZ; f32 objToNextX, objToNextY, objToNextZ; + if (o == NULL) { return PATH_NONE; } + if (o->oPathedPrevWaypointFlags == 0) { o->oPathedPrevWaypoint = o->oPathedStartWaypoint; o->oPathedPrevWaypointFlags = WAYPOINT_FLAGS_INITIALIZED; @@ -2295,12 +2297,15 @@ s32 cur_obj_follow_path(UNUSED s32 unusedArg) { struct Waypoint* tmpWaypoint = (lastWaypoint + 1); if (tmpWaypoint == NULL) { tmpWaypoint = lastWaypoint; } - if (tmpWaypoint->flags != WAYPOINT_FLAGS_END) { + if (tmpWaypoint && tmpWaypoint->flags != WAYPOINT_FLAGS_END) { targetWaypoint = tmpWaypoint; } else { targetWaypoint = startWaypoint; } + if (lastWaypoint == NULL) { return PATH_NONE; } + if (targetWaypoint == NULL) { return PATH_NONE; } + o->oPathedPrevWaypointFlags = lastWaypoint->flags | WAYPOINT_FLAGS_INITIALIZED; prevToNextX = targetWaypoint->pos[0] - lastWaypoint->pos[0]; @@ -2320,7 +2325,7 @@ s32 cur_obj_follow_path(UNUSED s32 unusedArg) { o->oPathedPrevWaypoint = targetWaypoint; struct Waypoint* tmpWaypoint2 = (targetWaypoint + 1); if (tmpWaypoint2 == NULL) { tmpWaypoint2 = targetWaypoint; } - if (tmpWaypoint2->flags == WAYPOINT_FLAGS_END) { + if (tmpWaypoint2 && tmpWaypoint2->flags == WAYPOINT_FLAGS_END) { return PATH_REACHED_END; } else { return PATH_REACHED_WAYPOINT; @@ -2658,8 +2663,11 @@ s32 cur_obj_move_up_and_down(s32 a0) { return FALSE; } -void cur_obj_call_action_function(void (*actionFunctions[])(void)) { +void cur_obj_call_action_function(void (*actionFunctions[])(void), uint32_t actionFunctionsLength) { + if (!actionFunctions) { return; } + if ((uint32_t)o->oAction >= actionFunctionsLength) { return; } void (*actionFunction)(void) = actionFunctions[o->oAction]; + if (!actionFunction) { return; } actionFunction(); } diff --git a/src/game/object_helpers.h b/src/game/object_helpers.h index 9e8ef5f3..83c8c531 100644 --- a/src/game/object_helpers.h +++ b/src/game/object_helpers.h @@ -256,6 +256,8 @@ struct GraphNode_802A45E4 { /*0x22*/ s16 unk22; }; +#define CUR_OBJ_CALL_ACTION_FUNCTION(_action_func) cur_obj_call_action_function(_action_func, (sizeof(_action_func) / sizeof(&_action_func[0]))) + void obj_set_hitbox(struct Object *obj, struct ObjectHitbox *hitbox); s32 signum_positive(s32 x); f32 absf(f32 x); @@ -273,7 +275,7 @@ void cur_obj_scale_over_time(s32 a0, s32 a1, f32 sp10, f32 sp14); void cur_obj_set_pos_to_home_with_debug(void); s32 cur_obj_is_mario_on_platform(void); s32 cur_obj_move_up_and_down(s32 a0); -void cur_obj_call_action_function(void (*actionFunctions[])(void)); +void cur_obj_call_action_function(void (*actionFunctions[])(void), uint32_t actionFunctionsLength); void spawn_base_star_with_no_lvl_exit(void); s32 bit_shift_left(s32 a0); s32 cur_obj_mario_far_away(void); diff --git a/src/game/object_list_processor.c b/src/game/object_list_processor.c index af4219f9..7d0015bf 100644 --- a/src/game/object_list_processor.c +++ b/src/game/object_list_processor.c @@ -337,6 +337,7 @@ void bhv_mario_update(void) { update_character_anim_offset(gMarioState); // reset mario state to the local player + gInteractionInvulnerable = false; gMarioState = &gMarioStates[0]; } diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index 207e0f23..95ac6e43 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -1554,7 +1554,7 @@ void geo_process_node_and_siblings(struct GraphNode *firstNode) { } } } else { - if (curGraphNode->type == GRAPH_NODE_TYPE_OBJECT) { + if (curGraphNode && curGraphNode->type == GRAPH_NODE_TYPE_OBJECT) { ((struct GraphNodeObject *) curGraphNode)->throwMatrix = NULL; } } diff --git a/src/pc/djui/djui.c b/src/pc/djui/djui.c index 6c0aa995..34204393 100644 --- a/src/pc/djui/djui.c +++ b/src/pc/djui/djui.c @@ -98,6 +98,7 @@ void djui_render(void) { gDjuiHudUtilsZ = 0; create_dl_ortho_matrix(); + djui_gfx_displaylist_begin(); smlua_call_event_hooks(HOOK_ON_HUD_RENDER); @@ -119,4 +120,5 @@ void djui_render(void) { djui_cursor_update(); djui_interactable_update(); + djui_gfx_displaylist_end(); } diff --git a/src/pc/djui/djui_gbi.h b/src/pc/djui/djui_gbi.h index ef5c5900..45c6722d 100644 --- a/src/pc/djui/djui_gbi.h +++ b/src/pc/djui/djui_gbi.h @@ -4,8 +4,14 @@ #define G_TEXOVERRIDE_DJUI 0xe0 #define G_DJUI_SIMPLE_VERT 0x11 #define G_DJUI_SIMPLE_TRI2 0x12 +#define G_TEXADDR_DJUI 0x13 #define G_EXECUTE_DJUI 0xdd +#define gsSPTextureAddrDjui(c) \ +{{ \ + (_SHIFTL(G_TEXADDR_DJUI,24,8)|_SHIFTL(~(u32)(c),0,24)),(u32)(0) \ +}} + #define gSetClippingDjui(pkt, cmd, x1, y1, x2, y2) \ { \ Gfx *_g = (Gfx *)(pkt); \ diff --git a/src/pc/djui/djui_gfx.c b/src/pc/djui/djui_gfx.c index c01099b7..26a185f3 100644 --- a/src/pc/djui/djui_gfx.c +++ b/src/pc/djui/djui_gfx.c @@ -6,6 +6,25 @@ #include "src/pc/pc_main.h" #include "src/pc/gfx/gfx_window_manager_api.h" #include "gfx_dimensions.h" +#include "djui_gfx.h" + +const Gfx dl_djui_display_list_begin[] = { + gsSPTextureAddrDjui(1), + gsSPEndDisplayList(), +}; + +const Gfx dl_djui_display_list_end[] = { + gsSPTextureAddrDjui(0), + gsSPEndDisplayList(), +}; + +void djui_gfx_displaylist_begin(void) { + gSPDisplayList(gDisplayListHead++, dl_djui_display_list_begin); +} + +void djui_gfx_displaylist_end(void) { + gSPDisplayList(gDisplayListHead++, dl_djui_display_list_end); +} static const Vtx vertex_djui_simple_rect[] = { {{{ 0, -1, 0}, 0, { 0, 0 }, { 0xff, 0xff, 0xff, 0xff }}}, diff --git a/src/pc/djui/djui_gfx.h b/src/pc/djui/djui_gfx.h index 205508e9..8369bc15 100644 --- a/src/pc/djui/djui_gfx.h +++ b/src/pc/djui/djui_gfx.h @@ -9,6 +9,9 @@ extern const Gfx dl_djui_simple_rect[]; extern const Gfx dl_djui_img_begin[]; extern const Gfx dl_djui_img_end[]; +void djui_gfx_displaylist_begin(void); +void djui_gfx_displaylist_end(void); + f32 djui_gfx_get_scale(void); void djui_gfx_render_texture(const u8* texture, u32 w, u32 h, u32 bitSize); diff --git a/src/pc/djui/djui_hud_utils.c b/src/pc/djui/djui_hud_utils.c index f92f2de2..6d2e1890 100644 --- a/src/pc/djui/djui_hud_utils.c +++ b/src/pc/djui/djui_hud_utils.c @@ -91,6 +91,7 @@ struct InterpHud { f32 scaleH; f32 width; f32 height; + enum HudUtilsResolution resolution; }; static struct InterpHud sInterpHuds[MAX_INTERP_HUD] = { 0 }; static u16 sInterpHudCount = 0; @@ -102,12 +103,14 @@ void patch_djui_hud_before(void) { void patch_djui_hud(f32 delta) { f32 savedZ = gDjuiHudUtilsZ; Gfx* savedHeadPos = gDisplayListHead; + enum HudUtilsResolution savedResolution = sResolution; for (u16 i = 0; i < sInterpHudCount; i++) { struct InterpHud* interp = &sInterpHuds[i]; f32 x = delta_interpolate_f32(interp->prevX, interp->x, delta); f32 y = delta_interpolate_f32(interp->prevY, interp->y, delta); f32 scaleW = delta_interpolate_f32(interp->prevScaleW, interp->scaleW, delta); f32 scaleH = delta_interpolate_f32(interp->prevScaleH, interp->scaleH, delta); + sResolution = interp->resolution; gDjuiHudUtilsZ = interp->z; gDisplayListHead = interp->headPos; @@ -125,6 +128,7 @@ void patch_djui_hud(f32 delta) { djui_hud_size_translate(&translatedH); create_dl_scale_matrix(DJUI_MTX_NOPUSH, interp->width * translatedW, interp->height * translatedH, 1.0f); } + sResolution = savedResolution; gDisplayListHead = savedHeadPos; gDjuiHudUtilsZ = savedZ; } @@ -326,6 +330,7 @@ void djui_hud_render_texture_interpolated(struct TextureInfo* texInfo, f32 prevX interp->width = texInfo->width; interp->height = texInfo->height; interp->z = savedZ; + interp->resolution = sResolution; } void djui_hud_render_texture_tile_interpolated(struct TextureInfo* texInfo, f32 prevX, f32 prevY, f32 prevScaleW, f32 prevScaleH, f32 x, f32 y, f32 scaleW, f32 scaleH, u32 tileX, u32 tileY, u32 tileW, u32 tileH) { diff --git a/src/pc/djui/djui_paginated.c b/src/pc/djui/djui_paginated.c index 101395d3..e99ec21d 100644 --- a/src/pc/djui/djui_paginated.c +++ b/src/pc/djui/djui_paginated.c @@ -8,16 +8,11 @@ // events // //////////// -static void djui_paginated_prev(struct DjuiBase* base) { - struct DjuiPaginated* paginated = (struct DjuiPaginated*)base->parent; - paginated->startIndex -= paginated->showCount; - if (paginated->startIndex < 0) { paginated->startIndex = 0; } -} - -static void djui_paginated_next(struct DjuiBase* base) { - struct DjuiPaginated* paginated = (struct DjuiPaginated*)base->parent; - paginated->startIndex += paginated->showCount; +static struct DjuiButton* sPrevButton = NULL; +static struct DjuiButton* sNextButton = NULL; +static struct DjuiText* sPageNumText = NULL; +static s32 djui_paginated_get_count(struct DjuiPaginated* paginated) { s32 count = 0; struct DjuiBaseChild* dbc = paginated->layout->base.child; while (dbc != NULL) { @@ -25,6 +20,35 @@ static void djui_paginated_next(struct DjuiBase* base) { dbc = dbc->next; } + return count; +} + +static void djui_paginated_prev(struct DjuiBase* base) { + struct DjuiPaginated* paginated = (struct DjuiPaginated*)base->parent; + paginated->startIndex -= paginated->showCount; + + djui_base_set_enabled(&sPrevButton->base, (paginated->startIndex > 0)); + djui_base_set_enabled(&sNextButton->base, true); + + char pageNumString[32] = { 0 }; + snprintf(pageNumString, 32, "%d/%d", paginated->startIndex / paginated->showCount + 1, djui_paginated_get_count(paginated) / paginated->showCount + 1); + djui_text_set_text(sPageNumText, pageNumString); + + if (paginated->startIndex < 0) { paginated->startIndex = 0; } +} + +static void djui_paginated_next(struct DjuiBase* base) { + struct DjuiPaginated* paginated = (struct DjuiPaginated*)base->parent; + paginated->startIndex += paginated->showCount; + s32 count = djui_paginated_get_count(paginated); + + djui_base_set_enabled(&sNextButton->base, (paginated->startIndex < count - 8)); + djui_base_set_enabled(&sPrevButton->base, true); + + char pageNumString[32] = { 0 }; + snprintf(pageNumString, 32, "%d/%d", paginated->startIndex / paginated->showCount + 1, count / paginated->showCount + 1); + djui_text_set_text(sPageNumText, pageNumString); + if (paginated->startIndex >= count) { paginated->startIndex -= paginated->showCount; } } @@ -57,6 +81,10 @@ void djui_paginated_calculate_height(struct DjuiPaginated* paginated) { } djui_base_set_size(&paginated->base, paginated->base.width.value, height); + + char pageNumString[32] = { 0 }; + snprintf(pageNumString, 32, "%d/%d", paginated->startIndex / paginated->showCount + 1, count / paginated->showCount + 1); + djui_text_set_text(sPageNumText, pageNumString); } bool djui_paginated_render(struct DjuiBase* base) { @@ -112,22 +140,23 @@ struct DjuiPaginated* djui_paginated_create(struct DjuiBase* parent, u32 showCou paginated->layout = layout; } - { - struct DjuiButton* button = djui_button_create(&paginated->base, "<", DJUI_BUTTON_STYLE_NORMAL, djui_paginated_prev); - djui_base_set_alignment(&button->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM); - djui_base_set_size_type(&button->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE); - djui_base_set_size(&button->base, 128, 32); - paginated->prevButton = button; - } + sPrevButton = djui_button_create(&paginated->base, "<", DJUI_BUTTON_STYLE_NORMAL, djui_paginated_prev); + djui_base_set_alignment(&sPrevButton->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM); + djui_base_set_size_type(&sPrevButton->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&sPrevButton->base, 128, 32); + djui_base_set_enabled(&sPrevButton->base, false); + paginated->prevButton = sPrevButton; - { - struct DjuiButton* button = djui_button_create(&paginated->base, ">", DJUI_BUTTON_STYLE_NORMAL, djui_paginated_next); - djui_base_set_alignment(&button->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_BOTTOM); - djui_base_set_size_type(&button->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE); - djui_base_set_size(&button->base, 128, 32); - djui_interactable_hook_click(&button->base, djui_paginated_next); - paginated->nextButton = button; - } + sPageNumText = djui_text_create(&paginated->base, ""); + djui_base_set_color(&sPageNumText->base, 200, 200, 200, 255); + djui_base_set_alignment(&sPageNumText->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_BOTTOM); + sPageNumText->base.y.value -= 30; + + sNextButton = djui_button_create(&paginated->base, ">", DJUI_BUTTON_STYLE_NORMAL, djui_paginated_next); + djui_base_set_alignment(&sNextButton->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_BOTTOM); + djui_base_set_size_type(&sNextButton->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&sNextButton->base, 128, 32); + paginated->nextButton = sNextButton; return paginated; } diff --git a/src/pc/gfx/gfx_pc.c b/src/pc/gfx/gfx_pc.c index dfd34647..c76544b5 100644 --- a/src/pc/gfx/gfx_pc.c +++ b/src/pc/gfx/gfx_pc.c @@ -189,6 +189,18 @@ static const uint8_t missing_texture[MISSING_W * MISSING_H * 4] = { 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, }; +static bool sOnlyTextureChangeOnAddrChange = false; + +static void gfx_update_loaded_texture(uint8_t tile_number, uint32_t size_bytes, const uint8_t* addr) { + if (!sOnlyTextureChangeOnAddrChange) { + rdp.textures_changed[tile_number] = true; + } else if (!rdp.textures_changed[tile_number]) { + rdp.textures_changed[tile_number] = rdp.loaded_texture[tile_number].addr != addr; + } + rdp.loaded_texture[tile_number].size_bytes = size_bytes; + rdp.loaded_texture[tile_number].addr = addr; +} + ////////////////////////////////// // forward declaration for djui // ////////////////////////////////// @@ -210,15 +222,9 @@ static unsigned long get_time(void) { static void gfx_flush(void) { if (buf_vbo_len > 0) { - /*int num = buf_vbo_num_tris; - unsigned long t0 = get_time();*/ gfx_rapi->draw_triangles(buf_vbo, buf_vbo_len, buf_vbo_num_tris); buf_vbo_len = 0; buf_vbo_num_tris = 0; - /*unsigned long t1 = get_time(); - if (t1 - t0 > 1000) { - printf("f: %d %d\n", num, (int)(t1 - t0)); - }*/ } } @@ -1241,8 +1247,11 @@ static void gfx_dp_set_tile(uint8_t fmt, uint32_t siz, uint32_t line, uint32_t t rdp.texture_tile.cms = cms; rdp.texture_tile.cmt = cmt; rdp.texture_tile.line_size_bytes = line * 8; - rdp.textures_changed[0] = true; - rdp.textures_changed[1] = true; + if (!sOnlyTextureChangeOnAddrChange) { + // I don't know if we ever need to set these... + rdp.textures_changed[0] = true; + rdp.textures_changed[1] = true; + } } if (tile == G_TX_LOADTILE) { @@ -1256,8 +1265,11 @@ static void gfx_dp_set_tile_size(uint8_t tile, uint16_t uls, uint16_t ult, uint1 rdp.texture_tile.ult = ult; rdp.texture_tile.lrs = lrs; rdp.texture_tile.lrt = lrt; - rdp.textures_changed[0] = true; - rdp.textures_changed[1] = true; + if (!sOnlyTextureChangeOnAddrChange) { + // I don't know if we ever need to set these... + rdp.textures_changed[0] = true; + rdp.textures_changed[1] = true; + } } } @@ -1290,9 +1302,7 @@ static void gfx_dp_load_block(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t break; } uint32_t size_bytes = (lrs + 1) << word_size_shift; - rdp.loaded_texture[rdp.texture_to_load.tile_number].size_bytes = size_bytes; - rdp.loaded_texture[rdp.texture_to_load.tile_number].addr = rdp.texture_to_load.addr; - rdp.textures_changed[rdp.texture_to_load.tile_number] = true; + gfx_update_loaded_texture(rdp.texture_to_load.tile_number, size_bytes, rdp.texture_to_load.addr); } static void gfx_dp_load_tile(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t lrs, uint32_t lrt) { @@ -1318,15 +1328,11 @@ static void gfx_dp_load_tile(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t } uint32_t size_bytes = (((lrs >> G_TEXTURE_IMAGE_FRAC) + 1) * ((lrt >> G_TEXTURE_IMAGE_FRAC) + 1)) << word_size_shift; - rdp.loaded_texture[rdp.texture_to_load.tile_number].size_bytes = size_bytes; - - rdp.loaded_texture[rdp.texture_to_load.tile_number].addr = rdp.texture_to_load.addr; + gfx_update_loaded_texture(rdp.texture_to_load.tile_number, size_bytes, rdp.texture_to_load.addr); rdp.texture_tile.uls = uls; rdp.texture_tile.ult = ult; rdp.texture_tile.lrs = lrs; rdp.texture_tile.lrt = lrt; - - rdp.textures_changed[rdp.texture_to_load.tile_number] = true; } static uint8_t color_comb_component(uint32_t v) { @@ -1977,10 +1983,7 @@ static void OPTIMIZE_O3 djui_gfx_dp_execute_override(void) { uint32_t wordSizeShift = (sDjuiOverrideB == 32) ? 2 : 1; uint32_t lrs = (sDjuiOverrideW * sDjuiOverrideH) - 1; uint32_t sizeBytes = (lrs + 1) << wordSizeShift; - rdp.loaded_texture[rdp.texture_to_load.tile_number].size_bytes = sizeBytes; - rdp.textures_changed[rdp.texture_to_load.tile_number] = rdp.loaded_texture[rdp.texture_to_load.tile_number].addr != rdp.texture_to_load.addr; - rdp.loaded_texture[rdp.texture_to_load.tile_number].addr = rdp.texture_to_load.addr; - //rdp.textures_changed[rdp.texture_to_load.tile_number] = true; + gfx_update_loaded_texture(rdp.texture_to_load.tile_number, sizeBytes, rdp.texture_to_load.addr); // gsDPSetTile uint32_t line = (((sDjuiOverrideW * 2) + 7) >> 3); @@ -2135,6 +2138,9 @@ void OPTIMIZE_O3 djui_gfx_run_dl(Gfx* cmd) { djui_gfx_sp_simple_tri1(C0(16, 8) / 2, C0(8, 8) / 2, C0(0, 8) / 2); djui_gfx_sp_simple_tri1(C1(16, 8) / 2, C1(8, 8) / 2, C1(0, 8) / 2); break; + case G_TEXADDR_DJUI: + sOnlyTextureChangeOnAddrChange = !(C0(0, 24) & 0x01); + break; case G_EXECUTE_DJUI: djui_gfx_dp_execute_djui(cmd->words.w1); break; diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index bf6469a6..422513fe 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -4016,7 +4016,7 @@ char gSmluaConstants[] = "" "COOP_OBJ_FLAG_INITIALIZED = (1 << 3)\n" "VERSION_TEXT = 'beta'\n" "VERSION_NUMBER = 33\n" -"MINOR_VERSION_NUMBER = 0\n" +"MINOR_VERSION_NUMBER = 1\n" "PATCH_VERSION_NUMBER = 0\n" "MAX_VERSION_LENGTH = 10\n" "MAX_LOCAL_VERSION_LENGTH = 12\n" diff --git a/src/pc/lua/smlua_functions.c b/src/pc/lua/smlua_functions.c index 9f595df5..4d9f30a5 100644 --- a/src/pc/lua/smlua_functions.c +++ b/src/pc/lua/smlua_functions.c @@ -473,66 +473,104 @@ struct LuaLevelScriptParse { struct LuaLevelScriptParse sLevelScriptParse = { 0 }; s32 smlua_func_level_script_parse_callback(u8 type, void *cmd) { - if (type != 0x24 && type != 0x39 && type != 0x1F) { - return 0; + u32 areaIndex, bhvId, bhvArgs; + u32 *pAreaIndex = NULL, *pBhvId = NULL, *pBhvArgs = NULL; + MacroObject *pMacroData = NULL; + + // Gather arguments + switch (type) { + + // AREA + case 0x1F: { + areaIndex = (u8) dynos_level_cmd_get(cmd, 2); + pAreaIndex = &areaIndex; + } break; + + // OBJECT_WITH_ACTS + case 0x24: { + const BehaviorScript *bhv = (const BehaviorScript *) dynos_level_cmd_get(cmd, 20); + if (bhv) { + bhvId = (u32) get_id_from_behavior(bhv); + bhvArgs = (u32) dynos_level_cmd_get(cmd, 16); + pBhvId = &bhvId; + pBhvArgs = &bhvArgs; + } + } break; + + // OBJECT_WITH_ACTS_EXT + case 0x3F: { + const char *bhvStr = dynos_level_get_token(dynos_level_cmd_get(cmd, 20)); + if (bhvStr) { + bhvId = (u32) smlua_get_any_integer_mod_variable(bhvStr); + bhvArgs = (u32) dynos_level_cmd_get(cmd, 16); + pBhvId = &bhvId; + pBhvArgs = &bhvArgs; + } + } break; + + // OBJECT_WITH_ACTS_EXT2 + case 0x40: { + const char *bhvStr = dynos_level_get_token(dynos_level_cmd_get(cmd, 24)); + if (bhvStr) { + bhvId = (u32) smlua_get_any_integer_mod_variable(bhvStr); + bhvArgs = (u32) dynos_level_cmd_get(cmd, 16); + pBhvId = &bhvId; + pBhvArgs = &bhvArgs; + } + } break; + + // MACRO_OBJECTS + case 0x39: { + pMacroData = (MacroObject *) dynos_level_cmd_get(cmd, 4); + } break; + + // None of the above + default: return 0; } + + // Retrieve Lua state lua_State* L = gLuaState; if (L == NULL) { return 0; } struct LuaLevelScriptParse* preprocess = &sLevelScriptParse; - lua_rawgeti(L, LUA_REGISTRYINDEX, preprocess->reference); - if (type == 0x1F) { - u8 area = (u8) dynos_level_cmd_get(cmd, 2); - lua_pushinteger(L, area); + // Push 'areaIndex' + if (pAreaIndex) { + lua_pushinteger(L, *pAreaIndex); } else { lua_pushnil(L); } - if (type == 0x24) { - const BehaviorScript *bhv = (const BehaviorScript *) dynos_level_cmd_get(cmd, 20); - u32 behaviorArg = (u32) dynos_level_cmd_get(cmd, 16); - + // Push 'bhvData' + if (pBhvId && pBhvArgs) { lua_newtable(L); - lua_pushstring(L, "behavior"); - lua_pushinteger(L, get_id_from_behavior(bhv)); + lua_pushinteger(L, *pBhvId); lua_settable(L, -3); - lua_pushstring(L, "behaviorArg"); - lua_pushinteger(L, behaviorArg); + lua_pushinteger(L, *pBhvArgs); lua_settable(L, -3); } else { lua_pushnil(L); } - if (type == 0x39) { - MacroObject *data = (MacroObject *) dynos_level_cmd_get(cmd, 4); - int i = 0; - s32 len = 0; - + // Push 'macroBhvIds' and 'macroBhvArgs' + if (pMacroData) { lua_newtable(L); - int t = lua_gettop(gLuaState); - + s32 macroBhvIdsIdx = lua_gettop(gLuaState); lua_newtable(L); - int args = lua_gettop(gLuaState); - while (data[len++] != MACRO_OBJECT_END()) { - s32 presetId = (s32) ((data[len - 1] & 0x1FF) - 0x1F); - const BehaviorScript *bhv = (const BehaviorScript *) MacroObjectPresets[presetId].behavior; + s32 macroBhvArgsIdx = lua_gettop(gLuaState); + for (s32 i = 0; *pMacroData != MACRO_OBJECT_END(); pMacroData += 5, i++) { + s32 presetId = (s32) ((pMacroData[0] & 0x1FF) - 0x1F); s32 presetParams = MacroObjectPresets[presetId].param; - s32 objParams = (data[4] & 0xFF00) + (presetParams & 0x00FF); - u32 behaviorArg = ((objParams & 0x00FF) << 16) + (objParams & 0xFF00); - + s32 objParams = (pMacroData[4] & 0xFF00) | (presetParams & 0x00FF); + s32 bhvParams = ((objParams & 0x00FF) << 16) | (objParams & 0xFF00); lua_pushinteger(L, i); - lua_pushinteger(L, get_id_from_behavior(bhv)); - lua_settable(L, t); - + lua_pushinteger(L, get_id_from_behavior(MacroObjectPresets[presetId].behavior)); + lua_settable(L, macroBhvIdsIdx); lua_pushinteger(L, i); - lua_pushinteger(L, behaviorArg); - lua_settable(L, args); - - i++; - len += 4; + lua_pushinteger(L, bhvParams); + lua_settable(L, macroBhvArgsIdx); } } else { lua_pushnil(L); diff --git a/src/pc/lua/smlua_sync_table.c b/src/pc/lua/smlua_sync_table.c index cd2ae3d4..570aa448 100644 --- a/src/pc/lua/smlua_sync_table.c +++ b/src/pc/lua/smlua_sync_table.c @@ -271,7 +271,11 @@ static bool smlua_sync_table_send_field(u8 toLocalIndex, int stackIndex, bool al // send over the network if (!gLuaInitializingScript) { - network_send_lua_sync_table(toLocalIndex, seq, modRemoteIndex, sUnwoundLntsCount, sUnwoundLnts, &lntValue); + if (sUnwoundLntsCount < 2) { + LOG_ERROR("Sent sync table field packet with an invalid key count: %u", sUnwoundLntsCount); + } else { + network_send_lua_sync_table(toLocalIndex, seq, modRemoteIndex, sUnwoundLntsCount, sUnwoundLnts, &lntValue); + } } @@ -311,6 +315,12 @@ void smlua_set_sync_table_field_from_network(u64 seq, u16 modRemoteIndex, u16 ln return; } + // sanity check key count + if (lntKeyCount < 2) { + LOG_ERROR("Received sync table field packet with an invalid key count: %u", lntKeyCount); + return; + } + lua_getglobal(L, "_G"); // get global table lua_getfield(L, LUA_REGISTRYINDEX, mod->relativePath); // get the file's "global" table lua_remove(L, -2); // remove global table diff --git a/src/pc/mods/mod.c b/src/pc/mods/mod.c index 0ac0c44a..e7ba2f36 100644 --- a/src/pc/mods/mod.c +++ b/src/pc/mods/mod.c @@ -152,15 +152,19 @@ void mod_activate(struct Mod* mod) { } void mod_clear(struct Mod* mod) { - for (int j = 0; j < mod->fileCount; j++) { - struct ModFile* file = &mod->files[j]; - if (file->fp != NULL) { - fclose(file->fp); - file->fp = NULL; - } - if (file->cachedPath != NULL) { - free((char*)file->cachedPath); - file->cachedPath = NULL; + if (!mod) { return; } + + if (mod->files) { + for (int j = 0; j < mod->fileCount; j++) { + struct ModFile* file = &mod->files[j]; + if (file->fp != NULL) { + fclose(file->fp); + file->fp = NULL; + } + if (file->cachedPath != NULL) { + free((char*)file->cachedPath); + file->cachedPath = NULL; + } } } @@ -437,15 +441,10 @@ bool mod_load(struct Mods* mods, char* basePath, char* modName) { valid = true; } else if (is_directory(fullPath)) { char tmpPath[SYS_MAX_PATH] = { 0 }; - char path1[SYS_MAX_PATH] = { 0 }; - char path2[SYS_MAX_PATH] = { 0 }; if (!concat_path(tmpPath, fullPath, "main.lua")) { LOG_ERROR("Failed to concat path '%s' + '%s'", fullPath, "main.lua"); return true; } - if ((concat_path(path1, fullPath, "c-update.lua") && path_exists(path1)) || (concat_path(path2, fullPath, "m-update.lua") && path_exists(path2))) { - return true; - } valid = path_exists(tmpPath); } @@ -513,12 +512,10 @@ bool mod_load(struct Mods* mods, char* basePath, char* modName) { // print LOG_INFO(" %s", mod->name); - if (isDirectory) { - for (int i = 0; i < mod->fileCount; i++) { - struct ModFile* file = &mod->files[i]; - mod_cache_add(mod, file, true); - LOG_INFO(" - %s", file->relativePath); - } + for (int i = 0; i < mod->fileCount; i++) { + struct ModFile* file = &mod->files[i]; + mod_cache_add(mod, file, true); + LOG_INFO(" - %s", file->relativePath); } return true; diff --git a/src/pc/mods/mod_import.c b/src/pc/mods/mod_import.c index ce2ad599..e57097da 100644 --- a/src/pc/mods/mod_import.c +++ b/src/pc/mods/mod_import.c @@ -56,6 +56,7 @@ static bool mod_import_lua(char* src) { static bool mod_import_zip(char* path, bool* isLua, bool* isDynos) { LOG_INFO("Importing zip mod: %s", path); + char luaPath[SYS_MAX_PATH] = { 0 }; mz_zip_archive zip_archive = { 0 }; mz_bool status = mz_zip_reader_init_file(&zip_archive, path, 0); if (!status) { @@ -75,6 +76,7 @@ static bool mod_import_zip(char* path, bool* isLua, bool* isDynos) { } if (str_ends_with(file_stat.m_filename, ".lua")) { + path_get_folder(file_stat.m_filename, luaPath); *isLua = true; break; } else if (str_ends_with(file_stat.m_filename, ".tex")) { @@ -99,12 +101,32 @@ static bool mod_import_zip(char* path, bool* isLua, bool* isDynos) { snprintf(dstDirectory, SYS_MAX_PATH, "%s", (char*)fs_get_write_path(DYNOS_PACKS_FOLDER)); } else { LOG_ERROR("Could not figure out what type of mod this is"); + mz_zip_reader_end(&zip_archive); return false; } + + // create mod/dynos path if it doesn't exist if (!fs_sys_dir_exists(dstDirectory)) { fs_sys_mkdir(dstDirectory); } + // erase and create lua path + if (*isLua && strlen(luaPath) > 0) { + if (!concat_path(dst, dstDirectory, luaPath)) { + LOG_ERROR("Failed to concat path for base lua directory"); + mz_zip_reader_end(&zip_archive); + return false; + } + if (fs_sys_dir_exists(dst)) { + mods_delete_folder(dst); + } + if (!fs_sys_mkdir(dst)) { + LOG_ERROR("Failed to mkdir for base lua directory"); + mz_zip_reader_end(&zip_archive); + return false; + } + } + // Extract the archive for (int i = 0; i < (int)mz_zip_reader_get_num_files(&zip_archive); i++) { mz_zip_archive_file_stat file_stat; @@ -159,6 +181,8 @@ static bool mod_import_zip(char* path, bool* isLua, bool* isDynos) { FILE* fout = fopen(dst, "wb"); if (fout == NULL) { LOG_ERROR("Failed to open dst path for zip mod import"); + mz_free((void*)p); + mz_zip_reader_end(&zip_archive); return false; } diff --git a/src/pc/network/discord/activity.c b/src/pc/network/discord/activity.c index 2806ec94..e787927c 100644 --- a/src/pc/network/discord/activity.c +++ b/src/pc/network/discord/activity.c @@ -132,6 +132,16 @@ void discord_activity_update(bool hosting) { LOGFILE_INFO(LFT_DISCORD, "truncating details"); } + if (!app.activities) { + LOGFILE_INFO(LFT_DISCORD, "no activities"); + return; + } + + if (!app.activities->update_activity) { + LOGFILE_INFO(LFT_DISCORD, "no update_activity"); + return; + } + app.activities->update_activity(app.activities, &gCurActivity, NULL, on_activity_update_callback); LOGFILE_INFO(LFT_DISCORD, "set activity"); } diff --git a/src/pc/network/lag_compensation.c b/src/pc/network/lag_compensation.c index 8c15c2ae..f0e5246f 100644 --- a/src/pc/network/lag_compensation.c +++ b/src/pc/network/lag_compensation.c @@ -6,7 +6,7 @@ #include "behavior_table.h" #include "model_ids.h" -#define MAX_LOCAL_STATE_HISTORY 20 +#define MAX_LOCAL_STATE_HISTORY 30 struct StateHistory { struct MarioState m; struct Object marioObj; @@ -40,16 +40,16 @@ void lag_compensation_store(void) { } struct MarioState* lag_compensation_get_local_state(struct NetworkPlayer* otherNp) { - if (!otherNp) { return NULL; } - if (gNetworkType == NT_NONE) { return NULL; } - if (!sLocalStateHistoryReady) { return NULL; } + if (!otherNp) { return &gMarioStates[0]; } + if (gNetworkType == NT_NONE) { return &gMarioStates[0]; } + if (!sLocalStateHistoryReady) { return &gMarioStates[0]; } s32 pingToTicks = (otherNp->ping / 1000.0f) * 30; if (pingToTicks > (MAX_LOCAL_STATE_HISTORY-1)) { pingToTicks = (MAX_LOCAL_STATE_HISTORY-1); } //LOG_INFO("Ping: %s :: %u :: %d", otherNp->name, otherNp->ping, pingToTicks); - if (pingToTicks == 0) { return NULL; } + if (pingToTicks == 0) { return &gMarioStates[0]; } s32 index = (s32)sLocalStateHistoryIndex - pingToTicks; while (index < 0) { index += MAX_LOCAL_STATE_HISTORY; } diff --git a/src/pc/network/packets/packet.c b/src/pc/network/packets/packet.c index 69983834..0596f4f4 100644 --- a/src/pc/network/packets/packet.c +++ b/src/pc/network/packets/packet.c @@ -52,8 +52,8 @@ void packet_process(struct Packet* p) { case PACKET_JOIN: network_receive_join(p); break; case PACKET_CHAT: network_receive_chat(p); break; case PACKET_KICK: network_receive_kick(p); break; - case PACKET_COMMAND: network_recieve_chat_command(p); break; - case PACKET_MODERATOR: network_recieve_moderator(p); break; + case PACKET_COMMAND: network_receive_chat_command(p); break; + case PACKET_MODERATOR: network_receive_moderator(p); break; case PACKET_KEEP_ALIVE: network_receive_keep_alive(p); break; case PACKET_LEAVING: network_receive_leaving(p); break; case PACKET_SAVE_FILE: network_receive_save_file(p); break; diff --git a/src/pc/network/packets/packet.h b/src/pc/network/packets/packet.h index c0fdc0f8..c74d13e5 100644 --- a/src/pc/network/packets/packet.h +++ b/src/pc/network/packets/packet.h @@ -234,11 +234,11 @@ void network_receive_kick(struct Packet* p); // packet_command_mod.c void network_send_chat_command(u8 localIndex, enum ChatConfirmCommand CCC); -void network_recieve_chat_command(struct Packet* p); +void network_receive_chat_command(struct Packet* p); // packet_moderator.c void network_send_moderator(u8 localIndex); -void network_recieve_moderator(struct Packet* p); +void network_receive_moderator(struct Packet* p); // packet_keep_alive.c void network_send_keep_alive(u8 localIndex); diff --git a/src/pc/network/packets/packet_area.c b/src/pc/network/packets/packet_area.c index a7d58057..b2d61fe5 100644 --- a/src/pc/network/packets/packet_area.c +++ b/src/pc/network/packets/packet_area.c @@ -138,7 +138,7 @@ void network_receive_area(struct Packet* p) { LOG_INFO("rx area"); if (p == NULL) { - LOG_ERROR("rx area: the packet was NULL, failed to recieve the area."); + LOG_ERROR("rx area: the packet was NULL, failed to receive the area."); return; } diff --git a/src/pc/network/packets/packet_command_mod.c b/src/pc/network/packets/packet_command_mod.c index c612b553..76b735d2 100644 --- a/src/pc/network/packets/packet_command_mod.c +++ b/src/pc/network/packets/packet_command_mod.c @@ -18,7 +18,7 @@ void network_send_chat_command(u8 globalIndex, enum ChatConfirmCommand ccc) { } } -void network_recieve_chat_command(struct Packet *p) { +void network_receive_chat_command(struct Packet *p) { if (!moderator_list_contains(gNetworkSystem->get_id_str(p->localIndex))) { return; } @@ -59,7 +59,7 @@ void network_send_moderator(u8 localIndex) { network_send_to(localIndex, &p); } -void network_recieve_moderator(struct Packet *p) { +void network_receive_moderator(struct Packet *p) { if ((gIsModerator) || (network_player_any_connected() && gNetworkPlayers[p->localIndex].type != NPT_SERVER)) { return; } diff --git a/src/pc/network/packets/packet_download.c b/src/pc/network/packets/packet_download.c index e418c877..de5a4a94 100644 --- a/src/pc/network/packets/packet_download.c +++ b/src/pc/network/packets/packet_download.c @@ -332,6 +332,11 @@ static void open_mod_file(struct Mod* mod, struct ModFile* file) { } void network_receive_download(struct Packet* p) { + if (!p) { + LOG_ERROR("Received null packet"); + return; + } + SOFT_ASSERT(gNetworkType == NT_CLIENT); if (p->localIndex != UNKNOWN_LOCAL_INDEX) { if (gNetworkPlayerServer == NULL || gNetworkPlayerServer->localIndex != p->localIndex) { @@ -343,9 +348,13 @@ void network_receive_download(struct Packet* p) { // read the chunk u64 receiveOffset = 0; u64 chunkLength = 0; - u8 chunk[CHUNK_SIZE] = { 0 }; + u8 chunk[CHUNK_SIZE+1] = { 0 }; packet_read(p, &receiveOffset, sizeof(u64)); packet_read(p, &chunkLength, sizeof(u64)); + if (chunkLength > CHUNK_SIZE) { + LOG_ERROR("Received improper chunk length"); + return; + } packet_read(p, &chunk, sizeof(u8) * chunkLength); // mark the offset group as received @@ -379,6 +388,10 @@ after_group:; u64 fileStartOffset = 0; for (u64 modIndex = 0; modIndex < gRemoteMods.entryCount; modIndex++) { struct Mod* mod = gRemoteMods.entries[modIndex]; + if (!mod) { + LOG_ERROR("Null mod"); + continue; + } // skip past mods to get to the right offset if ((fileStartOffset + mod->size) < receiveOffset) { @@ -386,6 +399,11 @@ after_group:; continue; } + if (mod->fileCount > 0 && !mod->files) { + LOG_ERROR("Null mod files"); + continue; + } + for (u64 fileIndex = 0; fileIndex < mod->fileCount; fileIndex++) { struct ModFile* modFile = &mod->files[fileIndex]; diff --git a/src/pc/network/packets/packet_lua_custom.c b/src/pc/network/packets/packet_lua_custom.c index a61d690c..61852494 100644 --- a/src/pc/network/packets/packet_lua_custom.c +++ b/src/pc/network/packets/packet_lua_custom.c @@ -11,6 +11,11 @@ void network_send_lua_custom(bool broadcast) { u16 zero = 0; s32 paramIndex = 1; + if (!L) { + LOG_ERROR("Sent lua custom packet when lua is dead"); + return; + } + // figure out mod index if (gLuaActiveMod == NULL) { LOG_LUA_LINE("Could not figure out the current active mod!"); @@ -99,6 +104,11 @@ void network_receive_lua_custom(struct Packet* p) { packet_read(p, &modIndex, sizeof(u16)); packet_read(p, &keyCount, sizeof(u8)); + if (!L) { + LOG_ERROR("Received lua custom packet when lua is dead"); + return; + } + lua_newtable(L); s32 tableIndex = lua_gettop(L); for(u16 i = 0; i < keyCount; i++) { diff --git a/src/pc/network/packets/packet_lua_sync_table.c b/src/pc/network/packets/packet_lua_sync_table.c index fd950129..fbe4e5a2 100644 --- a/src/pc/network/packets/packet_lua_sync_table.c +++ b/src/pc/network/packets/packet_lua_sync_table.c @@ -36,6 +36,7 @@ void network_send_lua_sync_table(u8 toLocalIndex, u64 seq, u16 modRemoteIndex, u //LOG_INFO(" %s", smlua_lnt_to_str(&lntKeys[i])); } //LOG_INFO(" -> %s", smlua_lnt_to_str(lntValue)); + //LOG_INFO(" count %u", lntKeyCount); if (!packet_write_lnt(&p, lntValue)) { return; } @@ -66,6 +67,7 @@ void network_receive_lua_sync_table(struct Packet* p) { //LOG_INFO(" %s", smlua_lnt_to_str(&lntKeys[i])); } //LOG_INFO(" -> %s", smlua_lnt_to_str(&lntValue)); + //LOG_INFO(" count %u", lntKeyCount); if (!packet_read_lnt(p, &lntValue)) { goto cleanup; } diff --git a/src/pc/network/packets/packet_mod_list.c b/src/pc/network/packets/packet_mod_list.c index 92fe88b2..dfe32c5e 100644 --- a/src/pc/network/packets/packet_mod_list.c +++ b/src/pc/network/packets/packet_mod_list.c @@ -28,7 +28,10 @@ void network_send_mod_list_request(void) { } void network_receive_mod_list_request(UNUSED struct Packet* p) { - SOFT_ASSERT(gNetworkType == NT_SERVER); + if (gNetworkType != NT_SERVER) { + LOG_ERROR("Network type should be server!"); + return; + } LOG_INFO("received mod list request"); network_send_mod_list(); diff --git a/src/pc/network/packets/packet_spawn_objects.c b/src/pc/network/packets/packet_spawn_objects.c index a3e03597..6bca1587 100644 --- a/src/pc/network/packets/packet_spawn_objects.c +++ b/src/pc/network/packets/packet_spawn_objects.c @@ -59,6 +59,11 @@ void network_send_spawn_objects_to(u8 sendToLocalIndex, struct Object* objects[] return; } + if (objectCount == 0) { + LOG_ERROR("Tried to send 0 objects"); + return; + } + SOFT_ASSERT(objectCount < MAX_SPAWN_OBJECTS_PER_PACKET); // prevent sending spawn objects during credits if (gCurrActStarNum == 99) { @@ -74,6 +79,11 @@ void network_send_spawn_objects_to(u8 sendToLocalIndex, struct Object* objects[] for (u8 i = 0; i < objectCount; i++) { struct Object* o = objects[i]; + if (!o) { + LOG_ERROR("Tried to send null object"); + return; + } + u32 model = models[i]; u32 parentId = generate_parent_id(objects, i, true); u32 behaviorId = get_id_from_behavior(o->behavior); @@ -96,10 +106,14 @@ void network_send_spawn_objects_to(u8 sendToLocalIndex, struct Object* objects[] if (sendToLocalIndex == PACKET_DESTINATION_BROADCAST) { network_send(&p); - LOG_INFO("tx spawn objects (BROADCAST) | %u", get_id_from_behavior(objects[0]->behavior)); + if (objects[0] && objects[0]->behavior) { + LOG_INFO("tx spawn objects (BROADCAST) | %u", get_id_from_behavior(objects[0]->behavior)); + } } else { network_send_to(sendToLocalIndex, &p); - LOG_INFO("tx spawn objects to %d | %u", gNetworkPlayers[sendToLocalIndex].globalIndex, get_id_from_behavior(objects[0]->behavior)); + if (objects[0] && objects[0]->behavior) { + LOG_INFO("tx spawn objects to %d | %u", gNetworkPlayers[sendToLocalIndex].globalIndex, get_id_from_behavior(objects[0]->behavior)); + } } } diff --git a/src/pc/network/version.h b/src/pc/network/version.h index 4f6b24c3..72842593 100644 --- a/src/pc/network/version.h +++ b/src/pc/network/version.h @@ -3,7 +3,7 @@ #define VERSION_TEXT "beta" #define VERSION_NUMBER 33 -#define MINOR_VERSION_NUMBER 0 +#define MINOR_VERSION_NUMBER 1 #define PATCH_VERSION_NUMBER 0 #define MAX_VERSION_LENGTH 10 diff --git a/src/pc/ultra_reimplementation.c b/src/pc/ultra_reimplementation.c index 85651ef7..6cd99cc1 100644 --- a/src/pc/ultra_reimplementation.c +++ b/src/pc/ultra_reimplementation.c @@ -14,6 +14,7 @@ u64 osClockRate = 62500000; s32 osPiStartDma(UNUSED OSIoMesg *mb, UNUSED s32 priority, UNUSED s32 direction, uintptr_t devAddr, void *vAddr, size_t nbytes, UNUSED OSMesgQueue *mq) { + if (!vAddr || !devAddr) { return 0; } memcpy(vAddr, (const void *) devAddr, nbytes); return 0; } diff --git a/textures/custom_font/custom_font_normal.rgba32.png b/textures/custom_font/custom_font_normal.rgba32.png index c4552460..14dee894 100644 Binary files a/textures/custom_font/custom_font_normal.rgba32.png and b/textures/custom_font/custom_font_normal.rgba32.png differ diff --git a/textures/custom_font/custom_font_tiny.rgba32.png b/textures/custom_font/custom_font_tiny.rgba32.png index 43e8a70f..843af03e 100644 Binary files a/textures/custom_font/custom_font_tiny.rgba32.png and b/textures/custom_font/custom_font_tiny.rgba32.png differ