Add a mod menu where mods can put DJUI elements (#56)
* Add a menu where mods can put their options at * Document mod menu hook functions * Add HOOK_ON_LANGUAGE_CHANGED * Add new Cheats mod * Make player menu disable singleplayer pause * fix some git merge conflicts that weren't resolved (#55) and added -latomic to build flags to fix compile warnings while compiling miniaudio * Remove legacy 'deluxe' field from built-in mods * Lots of improvements to memory safety * Abbreviated hex color parsing Co-Authored-By: Mechstreme <84944335+mechstreme@users.noreply.github.com> --------- Co-authored-by: Isaac0-dev <62234577+Isaac0-dev@users.noreply.github.com> Co-authored-by: Mechstreme <84944335+mechstreme@users.noreply.github.com>
This commit is contained in:
parent
cb3b7ebef9
commit
2b2dceb333
|
@ -1227,6 +1227,7 @@ def def_function(function):
|
|||
if rtype.startswith('Pointer_') and rtype not in def_pointers:
|
||||
def_pointers.append(rtype)
|
||||
|
||||
if rtype != "nil":
|
||||
s += '--- @return %s\n' % rtype
|
||||
s += "function %s(%s)\n -- ...\nend\n\n" % (fid, param_str)
|
||||
|
||||
|
|
|
@ -9228,7 +9228,27 @@ HOOK_ON_SEQ_LOAD = 42
|
|||
HOOK_ON_ATTACK_OBJECT = 43
|
||||
|
||||
--- @type LuaHookedEventType
|
||||
HOOK_MAX = 44
|
||||
HOOK_ON_LANGUAGE_CHANGED = 44
|
||||
|
||||
--- @type LuaHookedEventType
|
||||
HOOK_MAX = 45
|
||||
|
||||
--- @class LuaModMenuElementType
|
||||
|
||||
--- @type LuaModMenuElementType
|
||||
MOD_MENU_ELEMENT_BUTTON = 0
|
||||
|
||||
--- @type LuaModMenuElementType
|
||||
MOD_MENU_ELEMENT_CHECKBOX = 1
|
||||
|
||||
--- @type LuaModMenuElementType
|
||||
MOD_MENU_ELEMENT_SLIDER = 2
|
||||
|
||||
--- @type LuaModMenuElementType
|
||||
MOD_MENU_ELEMENT_INPUTBOX = 3
|
||||
|
||||
--- @type LuaModMenuElementType
|
||||
MOD_MENU_ELEMENT_MAX = 4
|
||||
|
||||
--- @class HudDisplayFlags
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,13 +3,13 @@
|
|||
-------------
|
||||
|
||||
--- @type MarioState[]
|
||||
--- Array of MarioStates, from 0 to MAX_PLAYERS - 1
|
||||
--- Array of `MarioState`s, from 0 to `MAX_PLAYERS` - 1
|
||||
--- - Uses the local index, which is different between every player
|
||||
--- - Index 0 always refers to the local player
|
||||
gMarioStates = {}
|
||||
|
||||
--- @type NetworkPlayer[]
|
||||
--- Array of NetworkPlayers, from 0 to MAX_PLAYERS - 1
|
||||
--- Array of `NetworkPlayer`s, from 0 to `MAX_PLAYERS` - 1
|
||||
--- - Uses the local index, which is different between every player
|
||||
--- - Index 0 always refers to the local player
|
||||
gNetworkPlayers = {}
|
||||
|
@ -21,45 +21,56 @@ gNetworkPlayers = {}
|
|||
gActiveMods = {}
|
||||
|
||||
--- @type Character[]
|
||||
--- Array of every character, from 0 to `CT_MAX` - 1
|
||||
--- - The contents or order of the characters can never change
|
||||
gCharacters = {}
|
||||
|
||||
--- @type Controller[]
|
||||
--- Array of every controller, from 0 to `MAX_PLAYERS` - 1
|
||||
--- - Uses the local index, which is different between every player
|
||||
--- - Index 0 always refers to the local player
|
||||
gControllers = {}
|
||||
|
||||
--- @type GlobalTextures
|
||||
--- Struct containing HUD glyph textures
|
||||
gTextures = {}
|
||||
|
||||
--- @type GlobalObjectAnimations
|
||||
--- Struct containing every object animation
|
||||
gObjectAnimations = {}
|
||||
|
||||
--- @type GlobalObjectCollisionData
|
||||
--- Struct containing all object collision data
|
||||
gGlobalObjectCollisionData = {}
|
||||
|
||||
--- @type PaintingValues
|
||||
--- Struct containing all paintings and their fields
|
||||
gPaintingValues = {}
|
||||
|
||||
--- @alias SyncTable table
|
||||
|
||||
--- @type SyncTable
|
||||
--- Any keys added and modified to this table will be synced among everyone.
|
||||
--- - This shouldn't be used to sync player-specific values; Use gPlayerSyncTable for that
|
||||
--- - This shouldn't be used to sync player-specific values; Use `gPlayerSyncTable` for that
|
||||
--- - Note: Does not support tables as keys
|
||||
gGlobalSyncTable = {}
|
||||
|
||||
--- @type SyncTable[]
|
||||
--- An array of sync tables. Any change to any sync tables will be synced to everyone else.
|
||||
--- Array of sync tables. Any change to any sync tables will be synced to everyone else.
|
||||
--- - This array takes in a local index, however it automatically translates to the global index
|
||||
--- - Note: Does not support tables as keys
|
||||
gPlayerSyncTable = {}
|
||||
|
||||
--- @type LevelValues
|
||||
--- Struct containing fields that modify specific gameplay or level properties
|
||||
gLevelValues = {}
|
||||
|
||||
--- @type BehaviorValues
|
||||
--- Struct containing fields that modify specific object behavior properties
|
||||
gBehaviorValues = {}
|
||||
|
||||
--- @type FirstPersonCamera
|
||||
--- The struct that contains the values for the first person camera
|
||||
--- Struct that contains the fields for the first person camera
|
||||
gFirstPersonCamera = {}
|
||||
|
||||
--- @type LakituState
|
||||
|
@ -68,9 +79,12 @@ gFirstPersonCamera = {}
|
|||
gLakituState = {}
|
||||
|
||||
--- @type ServerSettings
|
||||
--- Struct containing the settings for the server
|
||||
--- - enablePlayersInLevelDisplay and enablePlayerList are not synced
|
||||
gServerSettings = {}
|
||||
|
||||
--- @type NametagsSettings
|
||||
--- Struct containing the settings for Nametags
|
||||
gNametagsSettings = {}
|
||||
|
||||
-----------
|
||||
|
@ -92,7 +106,6 @@ end
|
|||
--- @param command string The command to run. Should be easy to type
|
||||
--- @param description string Should describe what the command does and how to use it
|
||||
--- @param func fun(msg:string): boolean Run upon activating the command. Return `true` to confirm the command has succeeded
|
||||
--- @return nil
|
||||
function hook_chat_command(command, description, func)
|
||||
-- ...
|
||||
end
|
||||
|
@ -132,6 +145,48 @@ function hook_on_sync_table_change(syncTable, field, tag, func)
|
|||
-- ...
|
||||
end
|
||||
|
||||
--- @param name string The text to show on the button
|
||||
--- @param func fun(index:integer) The function that is called when the button is pressed
|
||||
--- Hooks a DJUI button into the mod menu. If you want to unpause the game when the button is pressed, return `true` from `func` to do so
|
||||
function hook_mod_menu_button(name, func)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param name string The text to show on the left
|
||||
--- @param defaultValue boolean The default state of the checkbox
|
||||
--- @param func fun(index:integer, value:boolean) The function that is called when the checkbox is changed
|
||||
--- Hooks a DJUI checkbox into the mod menu
|
||||
function hook_mod_menu_checkbox(name, defaultValue, func)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param name string The text to show on the left
|
||||
--- @param defaultValue integer The default value of the slider
|
||||
--- @param min integer The lowest the slider can go
|
||||
--- @param max integer The highest the slider can go
|
||||
--- @param func fun(index:integer, value:integer) The function that is called when the value of the slider changes
|
||||
--- Hooks a DJUI slider into the mod menu
|
||||
function hook_mod_menu_slider(name, defaultValue, min, max, func)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param name string The text to show on the left
|
||||
--- @param defaultValue string The default text in the inputbox
|
||||
--- @param stringLength integer The max length of the inputbox
|
||||
--- @param func fun(index:integer, value:string) The function that is called when the value of the inputbox changes
|
||||
--- Hooks a DJUI inputbox into the mod menu
|
||||
function hook_mod_menu_inputbox(name, defaultValue, stringLength, func)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param index integer The index of the element in the order in which they were hooked
|
||||
--- @param name string The name to change to
|
||||
--- Updates a mod menu element's text
|
||||
--- - NOTE: `index` is zero-indexed
|
||||
function update_mod_menu_element_name(index, name)
|
||||
-- ...
|
||||
end
|
||||
|
||||
---------------
|
||||
-- functions --
|
||||
---------------
|
||||
|
@ -156,7 +211,6 @@ function atan2s(y, x)
|
|||
end
|
||||
|
||||
--- @param objFieldTable table<any, "u32"|"s32"|"f32">
|
||||
--- @return nil
|
||||
--- Keys must start with `o` and values must be `"u32"`, `"s32"`, or `"f32"`
|
||||
function define_custom_obj_fields(objFieldTable)
|
||||
-- ...
|
||||
|
@ -165,7 +219,6 @@ end
|
|||
--- @param object Object Object to sync
|
||||
--- @param standardSync boolean Automatically syncs common fields and syncs with distance. If `false`, all syncing must be done with `network_send_object`.
|
||||
--- @param fieldTable table<string> The fields to sync
|
||||
--- @return nil
|
||||
--- All synced fields must start with `o` and there should not be any keys, just values
|
||||
function network_init_object(object, standardSync, fieldTable)
|
||||
-- ...
|
||||
|
@ -173,7 +226,6 @@ end
|
|||
|
||||
--- @param object Object Object to sync
|
||||
--- @param reliable boolean Whether or not the game should try to resend the packet in case it gets lost, good for important packets
|
||||
--- @return nil
|
||||
--- Sends a sync packet to sync up the object with everyone else
|
||||
function network_send_object(object, reliable)
|
||||
-- ...
|
||||
|
@ -181,7 +233,6 @@ end
|
|||
|
||||
--- @param reliable boolean Whether or not the game should try to resend the packet in case its lost, good for important packets
|
||||
--- @param dataTable table Table of values to be included in the packet
|
||||
--- @return nil
|
||||
--- `dataTable` can only contain strings, integers, numbers, booleans, and nil
|
||||
function network_send(reliable, dataTable)
|
||||
-- ...
|
||||
|
@ -190,13 +241,12 @@ end
|
|||
--- @param toLocalIndex integer The local index to send the packet to
|
||||
--- @param reliable boolean Whether or not the game should try to resend the packet in case its lost, good for important packets
|
||||
--- @param dataTable table Table of values to be included in the packet
|
||||
--- @return nil
|
||||
--- `dataTable` can only contain strings, integers, numbers, booleans, and nil
|
||||
function network_send_to(toLocalIndex, reliable, dataTable)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param textureName string
|
||||
--- @param textureName string The texture name
|
||||
--- @return TextureInfo
|
||||
--- Gets the `TextureInfo` of a texture by name
|
||||
--- - Note: This also works with vanilla textures
|
||||
|
@ -204,78 +254,72 @@ function get_texture_info(textureName)
|
|||
-- ...
|
||||
end
|
||||
|
||||
--- @param texInfo TextureInfo
|
||||
--- @param x number
|
||||
--- @param y number
|
||||
--- @param scaleW number
|
||||
--- @param scaleH number
|
||||
--- @return nil
|
||||
--- @param texInfo TextureInfo The texture
|
||||
--- @param x number Where the texture is horizontally (left anchored)
|
||||
--- @param y number Where the texture is vertically (top anchored)
|
||||
--- @param scaleW number The scaled width of the texture
|
||||
--- @param scaleH number The scaled height of the texture
|
||||
--- Renders a texture to the screen
|
||||
function djui_hud_render_texture(texInfo, x, y, scaleW, scaleH)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param texInfo TextureInfo
|
||||
--- @param x number
|
||||
--- @param y number
|
||||
--- @param scaleW number
|
||||
--- @param scaleH number
|
||||
--- @param tileX number
|
||||
--- @param tileY number
|
||||
--- @param tileW number
|
||||
--- @param tileH number
|
||||
--- @return nil
|
||||
--- @param texInfo TextureInfo The texture
|
||||
--- @param x number Where the texture is horizontally (left anchored)
|
||||
--- @param y number Where the texture is vertically (top anchored)
|
||||
--- @param scaleW number The scaled width of the texture
|
||||
--- @param scaleH number The scaled height of the texture
|
||||
--- @param tileX number Where the tile is horizontally (left anchored)
|
||||
--- @param tileY number Where the tile is vertically (top anchored)
|
||||
--- @param tileW number The width of the tile
|
||||
--- @param tileH number The height of the tile
|
||||
--- Renders a tile of a texture to the screen
|
||||
function djui_hud_render_texture_tile(texInfo, x, y, scaleW, scaleH, tileX, tileY, tileW, tileH)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param texInfo TextureInfo
|
||||
--- @param prevX number
|
||||
--- @param prevY number
|
||||
--- @param prevScaleW number
|
||||
--- @param prevScaleH number
|
||||
--- @param x number
|
||||
--- @param y number
|
||||
--- @param scaleW number
|
||||
--- @param scaleH number
|
||||
--- @return nil
|
||||
--- @param texInfo TextureInfo The texture
|
||||
--- @param prevX number Where the texture previously was horizontally (left anchored)
|
||||
--- @param prevY number Where the texture previously was vertically (top anchored)
|
||||
--- @param prevScaleW number The previous scaled width of the texture
|
||||
--- @param prevScaleH number The previous scaled height of the texture
|
||||
--- @param x number Where the texture is horizontally (left anchored)
|
||||
--- @param y number Where the texture is vertically (top anchored)
|
||||
--- @param scaleW number The scaled width of the texture
|
||||
--- @param scaleH number The scaled height of the texture
|
||||
--- Renders an interpolated texture to the screen
|
||||
function djui_hud_render_texture_interpolated(texInfo, prevX, prevY, prevScaleW, prevScaleH, x, y, scaleW, scaleH)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param texInfo TextureInfo
|
||||
--- @param prevX number
|
||||
--- @param prevY number
|
||||
--- @param prevScaleW number
|
||||
--- @param prevScaleH number
|
||||
--- @param x number
|
||||
--- @param y number
|
||||
--- @param scaleW number
|
||||
--- @param scaleH number
|
||||
--- @param tileX number
|
||||
--- @param tileY number
|
||||
--- @param tileW number
|
||||
--- @param tileH number
|
||||
--- @return nil
|
||||
--- @param texInfo TextureInfo The texture
|
||||
--- @param prevX number Where the texture previously was horizontally (left anchored)
|
||||
--- @param prevY number Where the texture previously was vertically (top anchored)
|
||||
--- @param prevScaleW number The previous scaled width of the texture
|
||||
--- @param prevScaleH number The previous scaled height of the texture
|
||||
--- @param x number Where the texture is horizontally (left anchored)
|
||||
--- @param y number Where the texture is vertically (top anchored)
|
||||
--- @param scaleW number The scaled width of the texture
|
||||
--- @param scaleH number The scaled height of the texture
|
||||
--- @param tileX number Where the tile is horizontally (left anchored)
|
||||
--- @param tileY number Where the tile is vertically (top anchored)
|
||||
--- @param tileW number The width of the tile
|
||||
--- @param tileH number The height of the tile
|
||||
--- Renders an interpolated tile of a texture to the screen
|
||||
function djui_hud_render_texture_tile_interpolated(texInfo, prevX, prevY, prevScaleW, prevScaleH, x, y, scaleW, scaleH, tileX, tileY, tileW, tileH)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param textureName string
|
||||
--- @param overrideTexInfo TextureInfo
|
||||
--- @return nil
|
||||
--- @param textureName string The name of the texture
|
||||
--- @param overrideTexInfo TextureInfo The texture to override with
|
||||
--- Overrides a texture with a custom `TextureInfo`
|
||||
--- * textureName must be the codename of a vanilla texture, you can find these in files such as `texture.inc.c`s
|
||||
--- * overrideTexInfo can be any TextureInfo
|
||||
--- - `textureName` must be the codename of a vanilla texture, you can find these in files such as `texture.inc.c`s
|
||||
--- - `overrideTexInfo` can be any TextureInfo
|
||||
function texture_override_set(textureName, overrideTexInfo)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param textureName string
|
||||
--- @return nil
|
||||
--- @param textureName string The name of the texture
|
||||
--- Resets an overridden texture
|
||||
function texture_override_reset(textureName)
|
||||
-- ...
|
||||
|
@ -287,7 +331,6 @@ end
|
|||
|
||||
--- @param levelNum LevelNum | integer
|
||||
--- @param func fun(areaIndex:number, bhvData:bhvData, macroBhvIds:BehaviorId[], macroBhvArgs:integer[])
|
||||
--- @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`.
|
||||
|
@ -296,15 +339,14 @@ function level_script_parse(levelNum, func)
|
|||
-- ...
|
||||
end
|
||||
|
||||
--- @param name string
|
||||
--- @param flags integer
|
||||
--- @param animYTransDivisor integer
|
||||
--- @param startFrame integer
|
||||
--- @param loopStart integer
|
||||
--- @param loopEnd integer
|
||||
--- @param values table
|
||||
--- @param index table
|
||||
--- @return nil
|
||||
--- @param name string The name of the animation
|
||||
--- @param flags integer The flags of the animation (`ANIM_FLAG_*`)
|
||||
--- @param animYTransDivisor integer The vertical animation translation divisor
|
||||
--- @param startFrame integer What frame the animation starts on
|
||||
--- @param loopStart integer When the loop starts
|
||||
--- @param loopEnd integer When the loop ends
|
||||
--- @param values table The table containing animation values
|
||||
--- @param index table The table containing animation indices
|
||||
--- Registers an animation that can be used in objects if `smlua_anim_util_set_animation` is called
|
||||
function smlua_anim_util_register_animation(name, flags, animYTransDivisor, startFrame, loopStart, loopEnd, values, index)
|
||||
-- ...
|
||||
|
@ -312,7 +354,6 @@ end
|
|||
|
||||
--- @param message string The message to log
|
||||
--- @param level? ConsoleMessageLevel Optional; Determines whether the message should appear as info, a warning or an error.
|
||||
--- @return nil
|
||||
--- Logs a message to the in-game console
|
||||
function log_to_console(message, level)
|
||||
-- ...
|
||||
|
@ -320,7 +361,6 @@ end
|
|||
|
||||
--- @param index integer The index of the scroll target, should match up with the behavior param of RM_Scroll_Texture or editor_Scroll_Texture
|
||||
--- @param name string The name of the vertex buffer that should be used while scrolling the texture
|
||||
--- @return nil
|
||||
--- Registers a vertex buffer to be used for a scrolling texture. Should be used with RM_Scroll_Texture or editor_Scroll_Texture
|
||||
function add_scroll_target(index, name)
|
||||
-- ...
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
- [smlua_hooks.h](#smlua_hooksh)
|
||||
- [enum LuaActionHookType](#enum-LuaActionHookType)
|
||||
- [enum LuaHookedEventType](#enum-LuaHookedEventType)
|
||||
- [enum LuaModMenuElementType](#enum-LuaModMenuElementType)
|
||||
- [smlua_misc_utils.h](#smlua_misc_utilsh)
|
||||
- [enum HudDisplayFlags](#enum-HudDisplayFlags)
|
||||
- [enum HudDisplayValue](#enum-HudDisplayValue)
|
||||
|
@ -3293,7 +3294,17 @@
|
|||
| HOOK_ON_PLAY_SOUND | 41 |
|
||||
| HOOK_ON_SEQ_LOAD | 42 |
|
||||
| HOOK_ON_ATTACK_OBJECT | 43 |
|
||||
| HOOK_MAX | 44 |
|
||||
| HOOK_ON_LANGUAGE_CHANGED | 44 |
|
||||
| HOOK_MAX | 45 |
|
||||
|
||||
### [enum LuaModMenuElementType](#LuaModMenuElementType)
|
||||
| Identifier | Value |
|
||||
| :--------- | :---- |
|
||||
| MOD_MENU_ELEMENT_BUTTON | 0 |
|
||||
| MOD_MENU_ELEMENT_CHECKBOX | 1 |
|
||||
| MOD_MENU_ELEMENT_SLIDER | 2 |
|
||||
| MOD_MENU_ELEMENT_INPUTBOX | 3 |
|
||||
| MOD_MENU_ELEMENT_MAX | 4 |
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
|
|
|
@ -8401,6 +8401,26 @@
|
|||
<br />
|
||||
|
||||
|
||||
## [get_mario_vanilla_animation](#get_mario_vanilla_animation)
|
||||
|
||||
### Lua Example
|
||||
`local AnimationValue = get_mario_vanilla_animation(index)`
|
||||
|
||||
### Parameters
|
||||
| Field | Type |
|
||||
| ----- | ---- |
|
||||
| index | `integer` |
|
||||
|
||||
### Returns
|
||||
[Animation](structs.md#Animation)
|
||||
|
||||
### C Prototype
|
||||
`struct Animation *get_mario_vanilla_animation(u16 index);`
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
<br />
|
||||
|
||||
## [smlua_anim_util_get_current_animation_name](#smlua_anim_util_get_current_animation_name)
|
||||
|
||||
### Lua Example
|
||||
|
|
|
@ -9,6 +9,10 @@ Hooks are a way for SM64 to trigger Lua code, whereas the functions listed in [f
|
|||
- [hook_event](#hook_event)
|
||||
- [hook_mario_action](#hook_mario_action)
|
||||
- [hook_on_sync_table_change](#hook_on_sync_table_change)
|
||||
- [hook_mod_menu_button](#hook_mod_menu_button)
|
||||
- [hook_mod_menu_checkbox](#hook_mod_menu_checkbox)
|
||||
- [hook_mod_menu_slider](#hook_mod_menu_slider)
|
||||
- [hook_mod_menu_inputbox](#hook_mod_menu_inputbox)
|
||||
|
||||
<br />
|
||||
|
||||
|
@ -63,17 +67,17 @@ id_bhvExample = hook_behavior(nil, OBJ_LIST_DEFAULT, true, bhv_example_init, bhv
|
|||
|
||||
```lua
|
||||
function on_test_command(msg)
|
||||
if msg == 'on' then
|
||||
djui_chat_message_create('Test: enabled')
|
||||
if msg == "on" then
|
||||
djui_chat_message_create("Test: enabled")
|
||||
return true
|
||||
elseif msg == 'off' then
|
||||
djui_chat_message_create('Test: disabled')
|
||||
elseif msg == "off" then
|
||||
djui_chat_message_create("Test: disabled")
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
hook_chat_command('test', "[on|off] turn test on or off", on_hide_and_seek_command)
|
||||
hook_chat_command("test", "[on|off] turn test on or off", on_hide_and_seek_command)
|
||||
```
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
@ -131,6 +135,7 @@ The lua functions sent to `hook_event()` will be automatically called by SM64 wh
|
|||
| HOOK_ON_PLAY_SOUND | Called when a sound is going to play, return a `SOUND_*` constant or `NO_SOUND` to override the sound | `integer` soundBits, `Vec3f` pos |
|
||||
| HOOK_ON_SEQ_LOAD | Called when a sequence is going to play, return a `SEQ_*` constant to override the sequence. `SEQ_SOUND_PLAYER` (0) is silence. | `integer` player, `integer` seqID |
|
||||
| HOOK_ON_ATTACK_OBJECT | Called when a player attacks an object. May be double-fired in some cases, you'll need to write special code for this | [MarioState](structs.md#MarioState) attacker, [Object](structs.md#Object) victim, `integer` interactionId |
|
||||
| HOOK_ON_LANGUAGE_CHANGED | Called when the language is changed | `string` language |
|
||||
|
||||
### Parameters
|
||||
|
||||
|
@ -144,7 +149,7 @@ The lua functions sent to `hook_event()` will be automatically called by SM64 wh
|
|||
The following example will print out a message 16 times per frame (once for every possible player).
|
||||
```lua
|
||||
function mario_update(m)
|
||||
print('Mario update was called for player index ', m.playerIndex)
|
||||
print("Mario update was called for player index ", m.playerIndex)
|
||||
end
|
||||
|
||||
hook_event(HOOK_MARIO_UPDATE, mario_update)
|
||||
|
@ -261,14 +266,140 @@ hook_mario_action(ACT_WALL_SLIDE, { every_frame = act_wall_slide, gravity = act_
|
|||
|
||||
```lua
|
||||
function on_testing_field_changed(tag, oldVal, newVal)
|
||||
print('testingField changed:', tag, ',', oldVal, '->', newVal)
|
||||
print("testingField changed:", tag, ",", oldVal, "->", newVal)
|
||||
end
|
||||
|
||||
hook_on_sync_table_change(gGlobalSyncTable, 'testingField', 'tag', on_testing_field_changed)
|
||||
|
||||
-- now when testingField is set, either locally or over the network, on_testing_field_changed() will be called
|
||||
gGlobalSyncTable.testingField = 'hello'
|
||||
hook_on_sync_table_change(gGlobalSyncTable, "testingField", "tag", on_testing_field_changed)
|
||||
|
||||
-- now when testingField is set, either locally or over the network on_testing_field_changed() will be called
|
||||
gGlobalSyncTable.testingField = "hello"
|
||||
```
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
<br />
|
||||
|
||||
## [hook_mod_menu_button](#hook_mod_menu_button)
|
||||
`hook_mod_menu_button()` allows Lua to add buttons to their designated mod menu submenu.
|
||||
|
||||
### Parameters
|
||||
|
||||
| Field | Type |
|
||||
| ----- | ---- |
|
||||
| message | `string` |
|
||||
| func | `Lua Function` (`integer` index) |
|
||||
|
||||
### Lua Example
|
||||
|
||||
```lua
|
||||
local menu1Open = false
|
||||
local menu2Open = false
|
||||
|
||||
--- @param index integer
|
||||
local function on_open_menu(index)
|
||||
if index == 0 then
|
||||
menu1Open = true
|
||||
menu2Open = false
|
||||
else
|
||||
menu1Open = false
|
||||
menu2Open = true
|
||||
end
|
||||
end
|
||||
|
||||
-- you can always do separate functions too!
|
||||
hook_mod_menu_button("Open Menu 1", on_open_menu)
|
||||
hook_mod_menu_button("Open Menu 2", on_open_menu)
|
||||
```
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
<br />
|
||||
|
||||
## [hook_mod_menu_checkbox](#hook_mod_menu_checkbox)
|
||||
`hook_mod_menu_checkbox()` allows Lua to add checkboxes to their designated mod menu submenu.
|
||||
|
||||
### Parameters
|
||||
|
||||
| Field | Type |
|
||||
| ----- | ---- |
|
||||
| message | `string` |
|
||||
| defaultValue | `boolean` |
|
||||
| func | `Lua Function` (`integer` index, `boolean` value) |
|
||||
|
||||
### Lua Example
|
||||
|
||||
```lua
|
||||
local flyMode = false
|
||||
local noclipMode = false
|
||||
|
||||
--- @param index integer
|
||||
--- @param value boolean
|
||||
local function on_set_player_mode(index, value)
|
||||
if index == 0 then
|
||||
flyMode = value
|
||||
else
|
||||
noclipMode = value
|
||||
end
|
||||
end
|
||||
|
||||
-- you can always do separate functions too!
|
||||
hook_mod_menu_checkbox("Fly Mode", false, on_set_player_mode)
|
||||
hook_mod_menu_checkbox("Noclip Mode", false, on_set_player_mode)
|
||||
```
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
<br />
|
||||
|
||||
## [hook_mod_menu_slider](#hook_mod_menu_slider)
|
||||
`hook_mod_menu_slider()` allows Lua to add sliders to their designated mod menu submenu.
|
||||
|
||||
### Parameters
|
||||
|
||||
| Field | Type |
|
||||
| ----- | ---- |
|
||||
| message | `string` |
|
||||
| defaultValue | `integer` |
|
||||
| min | `integer` |
|
||||
| max | `integer` |
|
||||
| func | `Lua Function` (`integer` index, `integer` value) |
|
||||
|
||||
### Lua Example
|
||||
|
||||
```lua
|
||||
local timeScale = 0.0
|
||||
|
||||
local function on_set_time_scale(index, value)
|
||||
timeScale = value
|
||||
end
|
||||
|
||||
hook_mod_menu_slider("Time Scale", 1, 0, 10, on_set_time_scale)
|
||||
```
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
<br />
|
||||
|
||||
## [hook_mod_menu_inputbox](#hook_mod_menu_inputbox)
|
||||
`hook_mod_menu_inputbox()` allows Lua to add textboxes to their designated mod menu submenu.
|
||||
|
||||
### Parameters
|
||||
|
||||
| Field | Type |
|
||||
| ----- | ---- |
|
||||
| message | `string` |
|
||||
| defaultValue | `string` |
|
||||
| stringLength | `integer` |
|
||||
| func | `Lua Function` (`integer` index, `string` value) |
|
||||
|
||||
### Lua Example
|
||||
|
||||
```lua
|
||||
--- @param index integer
|
||||
--- @param value string
|
||||
local function on_set_network_player_description(index, value)
|
||||
network_player_set_description(gNetworkPlayers[0], value, 255, 255, 255, 255)
|
||||
end
|
||||
|
||||
hook_mod_menu_inputbox("Network Player Description", on_set_network_player_description)
|
||||
```
|
|
@ -305,6 +305,8 @@ SERVER_SETTINGS = "Nastavení serveru"
|
|||
RESUME = "Pokračovat"
|
||||
STOP_HOSTING = "Vypnout server"
|
||||
DISCONNECT = "Odpojit se"
|
||||
MOD_MENU = "Menu modů"
|
||||
MOD_MENU_TITLE = "MENU MODŮ"
|
||||
|
||||
[PLAYER]
|
||||
PLAYER_TITLE = "HRAC"
|
||||
|
|
|
@ -305,6 +305,8 @@ SERVER_SETTINGS = "Server Instellingen"
|
|||
RESUME = "Verder gaan"
|
||||
STOP_HOSTING = "Stop Met Organizeren"
|
||||
DISCONNECT = "Verbinding Verbreken"
|
||||
MOD_MENU = "Modusmenu"
|
||||
MOD_MENU_TITLE = "MODUSMENU"
|
||||
|
||||
[PLAYER]
|
||||
PLAYER_TITLE = "Speler"
|
||||
|
|
|
@ -305,6 +305,8 @@ SERVER_SETTINGS = "Server Settings"
|
|||
RESUME = "Resume"
|
||||
STOP_HOSTING = "Stop Hosting"
|
||||
DISCONNECT = "Disconnect"
|
||||
MOD_MENU = "Mod Menu"
|
||||
MOD_MENU_TITLE = "MOD MENU"
|
||||
|
||||
[PLAYER]
|
||||
PLAYER_TITLE = "PLAYER"
|
||||
|
|
|
@ -305,6 +305,8 @@ SERVER_SETTINGS = "Paramètres du serveur"
|
|||
RESUME = "Reprendre"
|
||||
STOP_HOSTING = "Arrêter d'héberger"
|
||||
DISCONNECT = "Se déconnecter"
|
||||
MOD_MENU = "Menu des mods"
|
||||
MOD_MENU_TITLE = "MENU DES MODS"
|
||||
|
||||
[PLAYER]
|
||||
PLAYER_TITLE = "JOUEUR"
|
||||
|
|
|
@ -305,6 +305,8 @@ SERVER_SETTINGS = "Servereinstellungen"
|
|||
RESUME = "Zurück zum Spiel"
|
||||
STOP_HOSTING = "Hosting beenden"
|
||||
DISCONNECT = "Verbindung trennen"
|
||||
MOD_MENU = "Mod-Menü"
|
||||
MOD_MENU_TITLE = "MOD-MENÜ"
|
||||
|
||||
[PLAYER]
|
||||
PLAYER_TITLE = "SPIELER"
|
||||
|
|
|
@ -303,6 +303,8 @@ SERVER_SETTINGS = "Impostazioni Server"
|
|||
RESUME = "Riprendi"
|
||||
STOP_HOSTING = "Interrompi la connessione"
|
||||
DISCONNECT = "Disconnettiti"
|
||||
MOD_MENU = "Menu delle mod"
|
||||
MOD_MENU_TITLE = "MENU DELLE MOD"
|
||||
|
||||
[PLAYER]
|
||||
PLAYER_TITLE = "GICATORE"
|
||||
|
|
|
@ -305,6 +305,8 @@ SERVER_SETTINGS = "Ustawienia Serwera"
|
|||
RESUME = "Kontynuuj"
|
||||
STOP_HOSTING = "Przerwij Hostowanie"
|
||||
DISCONNECT = "Rozlacz"
|
||||
MOD_MENU = "Menu modyfikacji"
|
||||
MOD_MENU_TITLE = "MENU MODYFIKACJI"
|
||||
|
||||
[PLAYER]
|
||||
PLAYER_TITLE = "GRACZ"
|
||||
|
|
|
@ -305,6 +305,8 @@ SERVER_SETTINGS = "Configurações de servidor"
|
|||
RESUME = "Resumo"
|
||||
STOP_HOSTING = "Parar a partida"
|
||||
DISCONNECT = "Desconectar"
|
||||
MOD_MENU = "Menu de mods"
|
||||
MOD_MENU_TITLE = "MENU DE MODS"
|
||||
|
||||
[PLAYER]
|
||||
PLAYER_TITLE = "JOGADOR"
|
||||
|
|
|
@ -304,6 +304,8 @@ SERVER_SETTINGS = "Настройки сервера"
|
|||
RESUME = "Продолжить"
|
||||
STOP_HOSTING = "Остановить хостинг"
|
||||
DISCONNECT = "Отключиться"
|
||||
MOD_MENU = "Меню модов"
|
||||
MOD_MENU_TITLE = "МЕНЮ МОДОВ"
|
||||
|
||||
[PLAYER]
|
||||
PLAYER_TITLE = "PLAYER"
|
||||
|
|
|
@ -305,6 +305,8 @@ SERVER_SETTINGS = "Ajustes de la partida"
|
|||
RESUME = "Continuar"
|
||||
STOP_HOSTING = "Finalizar partida"
|
||||
DISCONNECT = "Desconectarse"
|
||||
MOD_MENU = "Menú de mods"
|
||||
MOD_MENU_TITLE = "MENÚ DE MODS"
|
||||
|
||||
[PLAYER]
|
||||
PLAYER_TITLE = "JUGADOR"
|
||||
|
|
|
@ -0,0 +1,366 @@
|
|||
-- name: Cheats
|
||||
-- incompatible: cheats
|
||||
-- description: Cheats\nA mod that adds a bunch of cheats to the mod menu, accessible through the pause menu.
|
||||
-- pausable: true
|
||||
|
||||
-- localize functions to improve performance
|
||||
local math_floor,smlua_text_utils_get_language,table_insert,approach_s32,set_mario_action,get_network_area_timer = math.floor,smlua_text_utils_get_language,table.insert,approach_s32,set_mario_action,get_network_area_timer
|
||||
|
||||
--- @class Cheat
|
||||
--- @field public codename string
|
||||
--- @field public names table
|
||||
--- @field public hook LuaHookedEventType
|
||||
--- @field public func function
|
||||
--- @field public allowHazardSurfaces boolean
|
||||
|
||||
--- @type Cheat[]
|
||||
local sCheats = {}
|
||||
|
||||
--- @param m MarioState
|
||||
--- Checks if `m` is active
|
||||
local function active_player(m)
|
||||
local np = gNetworkPlayers[m.playerIndex]
|
||||
if m.playerIndex == 0 then
|
||||
return true
|
||||
end
|
||||
if not np.connected then
|
||||
return false
|
||||
end
|
||||
if np.currCourseNum ~= gNetworkPlayers[0].currCourseNum then
|
||||
return false
|
||||
end
|
||||
if np.currActNum ~= gNetworkPlayers[0].currActNum then
|
||||
return false
|
||||
end
|
||||
if np.currLevelNum ~= gNetworkPlayers[0].currLevelNum then
|
||||
return false
|
||||
end
|
||||
if np.currAreaIndex ~= gNetworkPlayers[0].currAreaIndex then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--- @param num integer
|
||||
--- Limits an integer in the s16 range
|
||||
local function s16(num)
|
||||
num = math_floor(num) & 0xFFFF
|
||||
if num >= 32768 then return num - 65536 end
|
||||
return num
|
||||
end
|
||||
|
||||
local function lang_string(strings)
|
||||
local table = strings[smlua_text_utils_get_language()]
|
||||
if table == nil then return strings["English"] end
|
||||
return table
|
||||
end
|
||||
|
||||
--- @param codename string
|
||||
--- @param names table
|
||||
--- @param hook LuaHookedEventType
|
||||
--- @param func function
|
||||
--- @param allowHazardSurfaces boolean
|
||||
--- Registers a cheat
|
||||
---
|
||||
--- Supported hooks:
|
||||
--- - `HOOK_MARIO_UPDATE`
|
||||
--- - `HOOK_BEFORE_MARIO_UPDATE`
|
||||
--- - `HOOK_BEFORE_PHYS_STEP`
|
||||
local function register_cheat(codename, names, hook, func, allowHazardSurfaces)
|
||||
table_insert(sCheats, {
|
||||
codename = codename,
|
||||
names = names,
|
||||
hook = hook,
|
||||
func = func,
|
||||
allowHazardSurfaces = allowHazardSurfaces
|
||||
})
|
||||
|
||||
for i = 0, MAX_PLAYERS - 1 do
|
||||
gPlayerSyncTable[i][codename] = false
|
||||
end
|
||||
end
|
||||
|
||||
--- @param m MarioState
|
||||
local function moon_jump_update(m)
|
||||
if m.controller.buttonDown & L_TRIG ~= 0 then
|
||||
m.faceAngle.y = m.intendedYaw - approach_s32(s16(m.intendedYaw - m.faceAngle.y), 0, 0x800, 0x800)
|
||||
m.vel.y = 40
|
||||
|
||||
if m.action == ACT_FORWARD_GROUND_KB or
|
||||
m.action == ACT_BACKWARD_GROUND_KB or
|
||||
m.action == ACT_SOFT_FORWARD_GROUND_KB or
|
||||
m.action == ACT_HARD_BACKWARD_GROUND_KB or
|
||||
m.action == ACT_FORWARD_AIR_KB or
|
||||
m.action == ACT_BACKWARD_AIR_KB or
|
||||
m.action == ACT_HARD_FORWARD_AIR_KB or
|
||||
m.action == ACT_HARD_BACKWARD_AIR_KB or
|
||||
m.action == ACT_AIR_HIT_WALL then
|
||||
set_mario_action(m, ACT_FREEFALL, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- @param m MarioState
|
||||
local function god_mode_update(m)
|
||||
m.health = 0x880
|
||||
m.healCounter = 0
|
||||
m.hurtCounter = 0
|
||||
m.peakHeight = m.pos.y
|
||||
end
|
||||
|
||||
--- @param m MarioState
|
||||
local function infinite_lives_update(m)
|
||||
m.numLives = 100
|
||||
end
|
||||
|
||||
--- @param m MarioState
|
||||
local function super_speed_update(m)
|
||||
if m.action ~= ACT_BUBBLED and m.action ~= ACT_WATER_JUMP and m.action ~= ACT_HOLD_WATER_JUMP then
|
||||
m.vel.x = m.vel.x * 4
|
||||
m.vel.z = m.vel.z * 4
|
||||
end
|
||||
end
|
||||
|
||||
--- @param m MarioState
|
||||
local function responsive_controls_update(m)
|
||||
if m.action == ACT_WALKING or
|
||||
m.action == ACT_HOLD_WALKING or
|
||||
m.action == ACT_HOLD_HEAVY_WALKING or
|
||||
m.action == ACT_FINISH_TURNING_AROUND or
|
||||
m.action == ACT_CRAWLING then
|
||||
m.faceAngle.y = m.intendedYaw
|
||||
end
|
||||
end
|
||||
|
||||
--- @param m MarioState
|
||||
local function rapid_fire_update(m)
|
||||
if (m.controller.buttonDown & A_BUTTON) ~= 0 and get_network_area_timer() % 2 == 0 then
|
||||
m.controller.buttonPressed = m.controller.buttonPressed | A_BUTTON
|
||||
end
|
||||
end
|
||||
|
||||
local function blj_anywhere_update(m)
|
||||
if m.action == ACT_LONG_JUMP and
|
||||
m.controller.buttonDown & Z_TRIG ~= 0 and
|
||||
m.forwardVel < -15 then
|
||||
m.vel.y = -30
|
||||
end
|
||||
end
|
||||
|
||||
local function always_triple_jump_update(m, action)
|
||||
if m.forwardVel < 20 and m.action == ACT_DOUBLE_JUMP_LAND and action == ACT_JUMP then
|
||||
return ACT_TRIPLE_JUMP
|
||||
end
|
||||
end
|
||||
|
||||
register_cheat(
|
||||
"moonJump",
|
||||
{
|
||||
["Czech"] = "Nekonečný Skok",
|
||||
["Dutch"] = "Maan Sprong",
|
||||
["English"] = "Moon Jump",
|
||||
["French"] = "Saut Antigravité",
|
||||
["German"] = "Mond-Sprung",
|
||||
["Italian"] = "Salto della Luna",
|
||||
["Polish"] = "Skok Ksiezycowy",
|
||||
["Portuguese"] = "Pulo da Lua",
|
||||
["Russian"] = "Супер прыжок",
|
||||
["Spanish"] = "Salto Lunar"
|
||||
},
|
||||
HOOK_MARIO_UPDATE,
|
||||
moon_jump_update,
|
||||
true
|
||||
)
|
||||
|
||||
register_cheat(
|
||||
"godMode",
|
||||
{
|
||||
["Czech"] = "Nenech Se Zranit",
|
||||
["Dutch"] = "God Modus",
|
||||
["English"] = "God Mode",
|
||||
["French"] = "Mode Invincible",
|
||||
["German"] = "Gott Modus",
|
||||
["Italian"] = "Modalità Dio",
|
||||
["Polish"] = "Tryb Boga",
|
||||
["Portuguese"] = "Modo Deus",
|
||||
["Russian"] = "Режим бога",
|
||||
["Spanish"] = "Modo Dios",
|
||||
},
|
||||
HOOK_MARIO_UPDATE,
|
||||
god_mode_update,
|
||||
false
|
||||
)
|
||||
|
||||
register_cheat(
|
||||
"infiniteLives",
|
||||
{
|
||||
["Czech"] = "Nekonečné Životy",
|
||||
["Dutch"] = "Oneindige Levens",
|
||||
["English"] = "Infinite Lives",
|
||||
["French"] = "Vies Infinies",
|
||||
["German"] = "Unbegrenzte Leben",
|
||||
["Italian"] = "Vite Infinite",
|
||||
["Polish"] = "Nieskonczone Zycia",
|
||||
["Portuguese"] = "Vidas Infinitas",
|
||||
["Russian"] = "Бесконечные жизни",
|
||||
["Spanish"] = "Vidas Infinitas",
|
||||
},
|
||||
HOOK_MARIO_UPDATE,
|
||||
infinite_lives_update,
|
||||
true
|
||||
)
|
||||
|
||||
register_cheat(
|
||||
"superSpeed",
|
||||
{
|
||||
["Czech"] = "Super Rychlost",
|
||||
["Dutch"] = "Super Snelheid",
|
||||
["English"] = "Super Speed",
|
||||
["French"] = "Super Vitesse",
|
||||
["German"] = "Supergeschwindigkeit",
|
||||
["Italian"] = "Super Velocità",
|
||||
["Polish"] = "Super Szybkosc",
|
||||
["Portuguese"] = "Super Velocidade",
|
||||
["Russian"] = "Супер cкорость",
|
||||
["Spanish"] = "Super Velocidad",
|
||||
},
|
||||
HOOK_BEFORE_PHYS_STEP,
|
||||
super_speed_update,
|
||||
true
|
||||
)
|
||||
|
||||
register_cheat(
|
||||
"responsiveControls",
|
||||
{
|
||||
["Czech"] = "Citlivé Ovládání",
|
||||
["Dutch"] = "Snel Reagerende Controles",
|
||||
["English"] = "Responsive Controls",
|
||||
["French"] = "Contrôles Réactifs",
|
||||
["German"] = "Reaktionsschnelle Steuerung",
|
||||
["Italian"] = "Controlli Reattivi",
|
||||
["Polish"] = "Responsywne Sterowanie",
|
||||
["Portuguese"] = "Controle Responsivos",
|
||||
["Russian"] = "Отзывчивое управление",
|
||||
["Spanish"] = "Controles Responsivos",
|
||||
},
|
||||
HOOK_MARIO_UPDATE,
|
||||
responsive_controls_update,
|
||||
true
|
||||
)
|
||||
|
||||
register_cheat(
|
||||
"rapidFire",
|
||||
{
|
||||
["Czech"] = "Rychle Mačkat Tlačítko",
|
||||
["Dutch"] = "Snel Vuur",
|
||||
["English"] = "Rapid Fire",
|
||||
["French"] = "Tir Rapide",
|
||||
["German"] = "Schnellfeuer",
|
||||
["Italian"] = "Fuoco Rapido",
|
||||
["Polish"] = "Szybkostrzelnosc",
|
||||
["Portuguese"] = "Fogo Rápido",
|
||||
["Russian"] = "Быстрый огонь",
|
||||
["Spanish"] = "Pulsación Rápida",
|
||||
},
|
||||
HOOK_BEFORE_MARIO_UPDATE,
|
||||
rapid_fire_update,
|
||||
true
|
||||
)
|
||||
|
||||
register_cheat(
|
||||
"bljAnywhere",
|
||||
{
|
||||
["Czech"] = "BLJ Všude",
|
||||
["Dutch"] = "BLJ Overal",
|
||||
["English"] = "BLJ Anywhere",
|
||||
["French"] = "BLJ N'importe Où",
|
||||
["German"] = "Überall Rückwertsweitspringen",
|
||||
["Italian"] = "BLJ Ovunque",
|
||||
["Polish"] = "BLJ Gdziekolwiek",
|
||||
["Portuguese"] = "BLJ Em Qualquer Lugar",
|
||||
["Russian"] = "BLJ в любом месте",
|
||||
["Spanish"] = "BLJ Donde Sea",
|
||||
},
|
||||
HOOK_BEFORE_MARIO_UPDATE,
|
||||
blj_anywhere_update,
|
||||
true
|
||||
)
|
||||
|
||||
register_cheat(
|
||||
"alwaysTripleJump",
|
||||
{
|
||||
["Czech"] = "Vždy Trojitý Skok",
|
||||
["Dutch"] = "Altijd Drievoudige Sprong",
|
||||
["English"] = "Always Triple Jump",
|
||||
["French"] = "Triple Sauts Infinis",
|
||||
["German"] = "Immer Dreisprung",
|
||||
["Italian"] = "Sempre Salto Triplo",
|
||||
["Polish"] = "Potrojny Skok Zawsze",
|
||||
["Portuguese"] = "Sempre Fazer Triple Jump",
|
||||
["Russian"] = "Всегда тройной прыжок",
|
||||
["Spanish"] = "Siempre Hacer Salto Triple",
|
||||
},
|
||||
HOOK_BEFORE_SET_MARIO_ACTION,
|
||||
always_triple_jump_update,
|
||||
true
|
||||
)
|
||||
|
||||
--- @param hookType LuaHookedEventType
|
||||
local function generate_mario_hook_function(hookType)
|
||||
--- @param m MarioState
|
||||
return function(m)
|
||||
if not active_player(m) then return end
|
||||
|
||||
for _, cheat in ipairs(sCheats) do
|
||||
if cheat.hook == hookType and gPlayerSyncTable[m.playerIndex][cheat.codename] then
|
||||
cheat.func(m)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function before_set_mario_action(m, action)
|
||||
if not active_player(m) then return end
|
||||
|
||||
for _, cheat in ipairs(sCheats) do
|
||||
if cheat.hook == HOOK_BEFORE_SET_MARIO_ACTION and gPlayerSyncTable[m.playerIndex][cheat.codename] then
|
||||
return cheat.func(m, action)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- @param m MarioState
|
||||
local function allow_hazard_surface(m)
|
||||
for _, cheat in ipairs(sCheats) do
|
||||
if gPlayerSyncTable[m.playerIndex][cheat.codename] and not cheat.allowHazardSurfaces then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function on_language_changed()
|
||||
for i, cheat in ipairs(sCheats) do
|
||||
update_mod_menu_element_name(i - 1, lang_string(cheat.names))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- @param index integer
|
||||
--- @param value boolean
|
||||
local function update_cheat(index, value)
|
||||
for i, cheat in ipairs(sCheats) do
|
||||
if i - 1 == index then
|
||||
gPlayerSyncTable[0][cheat.codename] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
hook_event(HOOK_MARIO_UPDATE, generate_mario_hook_function(HOOK_MARIO_UPDATE))
|
||||
hook_event(HOOK_BEFORE_MARIO_UPDATE, generate_mario_hook_function(HOOK_BEFORE_MARIO_UPDATE))
|
||||
hook_event(HOOK_BEFORE_PHYS_STEP, generate_mario_hook_function(HOOK_BEFORE_PHYS_STEP))
|
||||
hook_event(HOOK_BEFORE_SET_MARIO_ACTION, before_set_mario_action)
|
||||
hook_event(HOOK_ALLOW_HAZARD_SURFACE, allow_hazard_surface)
|
||||
hook_event(HOOK_ON_LANGUAGE_CHANGED, on_language_changed)
|
||||
|
||||
for _, cheat in ipairs(sCheats) do
|
||||
hook_mod_menu_checkbox(lang_string(cheat.names), false, update_cheat)
|
||||
end
|
|
@ -139,6 +139,7 @@ s8 gLastDialogResponse = 0;
|
|||
u8 gMenuHoldKeyIndex = 0;
|
||||
u8 gMenuHoldKeyTimer = 0;
|
||||
s32 gDialogResponse = 0;
|
||||
bool gForceUnpause = false;
|
||||
|
||||
#if defined(VERSION_JP) || defined(VERSION_SH) || defined(VERSION_EU)
|
||||
#ifdef VERSION_EU
|
||||
|
@ -3103,16 +3104,19 @@ s16 render_pause_courses_and_castle(void) {
|
|||
}
|
||||
|
||||
#ifdef VERSION_EU
|
||||
if (gPlayer1Controller->buttonPressed & (A_BUTTON | Z_TRIG | START_BUTTON))
|
||||
if (gPlayer1Controller->buttonPressed & (A_BUTTON | Z_TRIG | START_BUTTON)
|
||||
|| gForceUnpause)
|
||||
#else
|
||||
if (gPlayer1Controller->buttonPressed & A_BUTTON
|
||||
|| gPlayer1Controller->buttonPressed & START_BUTTON)
|
||||
|| gPlayer1Controller->buttonPressed & START_BUTTON
|
||||
|| gForceUnpause)
|
||||
#endif
|
||||
{
|
||||
level_set_transition(0, NULL);
|
||||
play_sound(SOUND_MENU_PAUSE_2, gGlobalSoundSource);
|
||||
gDialogBoxState = DIALOG_STATE_OPENING;
|
||||
gMenuMode = -1;
|
||||
gForceUnpause = false;
|
||||
|
||||
if (gDialogLineNum == 2 || gDialogLineNum == 3) {
|
||||
num = gDialogLineNum;
|
||||
|
@ -3138,16 +3142,19 @@ s16 render_pause_courses_and_castle(void) {
|
|||
}
|
||||
|
||||
#ifdef VERSION_EU
|
||||
if (gPlayer1Controller->buttonPressed & (A_BUTTON | Z_TRIG | START_BUTTON))
|
||||
if (gPlayer1Controller->buttonPressed & (A_BUTTON | Z_TRIG | START_BUTTON)
|
||||
|| gForceUnpause)
|
||||
#else
|
||||
if (gPlayer1Controller->buttonPressed & A_BUTTON
|
||||
|| gPlayer1Controller->buttonPressed & START_BUTTON)
|
||||
|| gPlayer1Controller->buttonPressed & START_BUTTON
|
||||
|| gForceUnpause)
|
||||
#endif
|
||||
{
|
||||
level_set_transition(0, NULL);
|
||||
play_sound(SOUND_MENU_PAUSE_2, gGlobalSoundSource);
|
||||
gMenuMode = -1;
|
||||
gDialogBoxState = DIALOG_STATE_OPENING;
|
||||
gForceUnpause = false;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -129,6 +129,7 @@ extern u8 gDialogTextColorR;
|
|||
extern u8 gDialogTextColorG;
|
||||
extern u8 gDialogTextColorB;
|
||||
extern u8 gDialogTextColorA;
|
||||
extern bool gForceUnpause;
|
||||
|
||||
void create_dl_identity_matrix(void);
|
||||
void create_dl_translation_matrix(s8 pushOp, f32 x, f32 y, f32 z);
|
||||
|
|
|
@ -60,7 +60,7 @@ void player_palettes_read(const char* palettesPath, bool appendPalettes) {
|
|||
if (appendPalettes) {
|
||||
snprintf(lpath, SYS_MAX_PATH, "%s/palettes", palettesPath);
|
||||
} else {
|
||||
strncpy(lpath, palettesPath, SYS_MAX_PATH);
|
||||
snprintf(lpath, SYS_MAX_PATH, "%s", palettesPath);
|
||||
}
|
||||
|
||||
// open directory
|
||||
|
@ -104,7 +104,7 @@ void player_palettes_read(const char* palettesPath, bool appendPalettes) {
|
|||
// free
|
||||
ini_free(sPalette);
|
||||
sPalette = NULL;
|
||||
strncpy(gPresetPalettes[gPresetPaletteCount].name, path, 4096);
|
||||
snprintf(gPresetPalettes[gPresetPaletteCount].name, 64, "%s", path);
|
||||
gPresetPalettes[gPresetPaletteCount].palette = palette;
|
||||
gPresetPaletteCount++;
|
||||
#ifdef DEVELOPMENT
|
||||
|
|
|
@ -18,7 +18,7 @@ struct PlayerPalette {
|
|||
#pragma pack()
|
||||
|
||||
struct PresetPalette {
|
||||
char name[4096];
|
||||
char name[64];
|
||||
struct PlayerPalette palette;
|
||||
};
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ bool parse_cli_opts(int argc, char* argv[]) {
|
|||
gCLIOpts.networkPort = 7777;
|
||||
}
|
||||
} else if (!strcmp(argv[i], "--playername") && (i + 1) < argc) {
|
||||
arg_string("--playername", argv[++i], gCLIOpts.playerName, MAX_PLAYER_STRING);
|
||||
arg_string("--playername", argv[++i], gCLIOpts.playerName, MAX_CONFIG_STRING);
|
||||
} else if (!strcmp(argv[i], "--help")) {
|
||||
print_help();
|
||||
return false;
|
||||
|
|
|
@ -24,7 +24,7 @@ struct CLIOptions {
|
|||
enum NetworkType network;
|
||||
unsigned int networkPort;
|
||||
char joinIp[IP_MAX_LEN];
|
||||
char playerName[MAX_PLAYER_STRING];
|
||||
char playerName[MAX_CONFIG_STRING];
|
||||
bool hideLoadingScreen;
|
||||
};
|
||||
|
||||
|
|
|
@ -144,7 +144,7 @@ bool configDebugError = false;
|
|||
bool configCtxProfiler = false;
|
||||
#endif
|
||||
// player settings
|
||||
char configPlayerName[MAX_PLAYER_STRING] = "";
|
||||
char configPlayerName[MAX_CONFIG_STRING] = "";
|
||||
unsigned int configPlayerModel = 0;
|
||||
struct PlayerPalette configPlayerPalette = { { { 0x00, 0x00, 0xff }, { 0xff, 0x00, 0x00 }, { 0xff, 0xff, 0xff }, { 0x72, 0x1c, 0x0e }, { 0x73, 0x06, 0x00 }, { 0xfe, 0xc1, 0x79 }, { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0x00 } } };
|
||||
// coop settings
|
||||
|
@ -257,7 +257,7 @@ static const struct ConfigOption options[] = {
|
|||
{.name = "ctx_profiler", .type = CONFIG_TYPE_BOOL, .boolValue = &configCtxProfiler},
|
||||
#endif
|
||||
// player settings
|
||||
{.name = "coop_player_name", .type = CONFIG_TYPE_STRING, .stringValue = (char*)&configPlayerName, .maxStringLength = MAX_PLAYER_STRING},
|
||||
{.name = "coop_player_name", .type = CONFIG_TYPE_STRING, .stringValue = (char*)&configPlayerName, .maxStringLength = MAX_CONFIG_STRING},
|
||||
{.name = "coop_player_model", .type = CONFIG_TYPE_UINT, .uintValue = &configPlayerModel},
|
||||
{.name = "coop_player_palette_pants", .type = CONFIG_TYPE_COLOR, .colorValue = &configPlayerPalette.parts[PANTS]},
|
||||
{.name = "coop_player_palette_shirt", .type = CONFIG_TYPE_COLOR, .colorValue = &configPlayerPalette.parts[SHIRT]},
|
||||
|
@ -446,7 +446,7 @@ static void save_name_read(char** tokens, int numTokens) {
|
|||
}
|
||||
|
||||
}
|
||||
strncpy(configSaveNames[index], fullSaveName, MAX_SAVE_NAME_STRING);
|
||||
snprintf(configSaveNames[index], MAX_SAVE_NAME_STRING, "%s", fullSaveName);
|
||||
}
|
||||
|
||||
static void save_name_write(FILE* file) {
|
||||
|
@ -679,7 +679,7 @@ NEXT_OPTION:
|
|||
|
||||
if (configDjuiTheme >= DJUI_THEME_MAX) { configDjuiTheme = 0; }
|
||||
|
||||
if (!strcmp(configLastVersion, "")) { strncpy(configLastVersion, get_version(), MAX_CONFIG_STRING); }
|
||||
if (!strcmp(configLastVersion, "")) { snprintf(configLastVersion, MAX_CONFIG_STRING, "%s", get_version()); }
|
||||
|
||||
#ifndef COOPNET
|
||||
configNetworkSystem = NS_SOCKET;
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#define MAX_BINDS 3
|
||||
#define MAX_VOLUME 127
|
||||
#define MAX_CONFIG_STRING 64
|
||||
#define MAX_PLAYER_STRING 60
|
||||
#define MAX_SAVE_NAME_STRING 32
|
||||
|
||||
#define DEFAULT_PORT 7777
|
||||
|
@ -96,7 +95,7 @@ extern bool configDebugError;
|
|||
extern bool configCtxProfiler;
|
||||
#endif
|
||||
// player settings
|
||||
extern char configPlayerName[MAX_PLAYER_STRING];
|
||||
extern char configPlayerName[MAX_CONFIG_STRING];
|
||||
extern unsigned int configPlayerModel;
|
||||
extern struct PlayerPalette configPlayerPalette;
|
||||
// coop settings
|
||||
|
|
|
@ -94,7 +94,7 @@ static void on_current_user_update(UNUSED void* data) {
|
|||
if (configPlayerName[0] == '\0' && strlen(user.username) > 0) {
|
||||
char* cname = configPlayerName;
|
||||
char* dname = user.username;
|
||||
for (int i = 0; i < MAX_PLAYER_STRING - 1; i++) {
|
||||
for (int i = 0; i < MAX_CONFIG_STRING - 1; i++) {
|
||||
if (*dname >= '!' && *dname <= '~') {
|
||||
*cname = *dname;
|
||||
cname++;
|
||||
|
|
|
@ -93,10 +93,10 @@ static void discord_populate_details(char* buffer, int bufferLength) {
|
|||
void discord_activity_update(void) {
|
||||
sCurActivity.type = DiscordActivityType_Playing;
|
||||
|
||||
strncpy(sCurActivity.assets.large_image, "characters", 128);
|
||||
strncpy(sCurActivity.assets.large_text, "sm64coopdx Characters", 128);
|
||||
strncpy(sCurActivity.assets.small_image, "icon", 128);
|
||||
strncpy(sCurActivity.assets.small_text, "sm64coopdx Icon", 128);
|
||||
snprintf(sCurActivity.assets.large_image, 128, "characters");
|
||||
snprintf(sCurActivity.assets.large_text, 128, "sm64coopdx Characters");
|
||||
snprintf(sCurActivity.assets.small_image, 128, "icon");
|
||||
snprintf(sCurActivity.assets.small_text, 128, "sm64coopdx Icon");
|
||||
|
||||
if (gNetworkType != NT_NONE && gNetworkSystem) {
|
||||
gNetworkSystem->get_lobby_id(sCurActivity.party.id, 128);
|
||||
|
|
|
@ -103,7 +103,7 @@ void djui_init_late(void) {
|
|||
djui_panel_language_create(NULL);
|
||||
}
|
||||
if (strcmp(configLastVersion, get_version())) {
|
||||
strncpy(configLastVersion, get_version(), MAX_CONFIG_STRING);
|
||||
snprintf(configLastVersion, MAX_CONFIG_STRING, "%s", get_version());
|
||||
djui_panel_changelog_create(NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ static char* sSaveLetters[] = { "A", "B", "C", "D" };
|
|||
static void djui_panel_host_save_update_button(struct DjuiButton* button, int slot);
|
||||
|
||||
static void djui_panel_host_save_save_name_change(UNUSED struct DjuiBase* caller) {
|
||||
strncpy(configSaveNames[sButtonTag], sSaveNameInputBox->buffer, MAX_SAVE_NAME_STRING);
|
||||
snprintf(configSaveNames[sButtonTag], MAX_SAVE_NAME_STRING, "%s", sSaveNameInputBox->buffer);
|
||||
if (strlen(sSaveNameInputBox->buffer) >= 64) {
|
||||
djui_inputbox_set_text(sSaveNameInputBox, configSaveNames[sButtonTag]);
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ static void djui_panel_edit_create(struct DjuiBase* caller) {
|
|||
djui_base_set_size(&sSaveNameInputBox->base, 0.45f, 32);
|
||||
djui_base_set_alignment(&sSaveNameInputBox->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
|
||||
char saveName[MAX_SAVE_NAME_STRING] = { 0 };
|
||||
strncpy(saveName, configSaveNames[sButtonTag], MAX_SAVE_NAME_STRING);
|
||||
snprintf(saveName, MAX_SAVE_NAME_STRING, "%s", configSaveNames[sButtonTag]);
|
||||
djui_inputbox_set_text(sSaveNameInputBox, saveName);
|
||||
djui_interactable_hook_value_change(&sSaveNameInputBox->base, djui_panel_host_save_save_name_change);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "pc/utils/misc.h"
|
||||
#include "pc/configfile.h"
|
||||
#include "pc/os/os.h"
|
||||
#include "pc/lua/smlua_hooks.h"
|
||||
|
||||
extern bool directory_sanity_check(struct dirent* dir, char* dirPath, char* outPath);
|
||||
static bool sTrue = true;
|
||||
|
@ -34,6 +35,7 @@ static void select_language(struct DjuiBase* caller) {
|
|||
if (strcmp(configLanguage, checkbox->text->message)) {
|
||||
snprintf(configLanguage, MAX_CONFIG_STRING, "%s", checkbox->text->message);
|
||||
sLanguageChanged = true;
|
||||
smlua_call_event_hooks_string_param(HOOK_ON_LANGUAGE_CHANGED, configLanguage);
|
||||
}
|
||||
|
||||
checkbox->value = &sTrue;
|
||||
|
|
|
@ -83,7 +83,7 @@ struct DjuiThreePanel* djui_panel_menu_create(char* headerText) {
|
|||
djui_base_set_location(&header->base, 0, DJUI_PANEL_HEADER_OFFSET);
|
||||
djui_text_set_alignment(header, DJUI_HALIGN_CENTER, DJUI_VALIGN_BOTTOM);
|
||||
djui_text_set_font(header, hudFontHeader ? gDjuiFonts[2] : gDjuiFonts[1]);
|
||||
djui_text_set_font_scale(header, gDjuiFonts[1]->defaultFontScale * (hudFontHeader ? 0.7f : 1.0f));
|
||||
djui_text_set_font_scale(header, gDjuiFonts[1]->defaultFontScale * (hudFontHeader ? 0.7f : 1.0f) * (strlen(headerText) > 15 ? 0.9f : 1.0f));
|
||||
|
||||
struct DjuiFlowLayout* body = djui_flow_layout_create(&panel->base);
|
||||
djui_base_set_alignment(&body->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER);
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
#include "djui.h"
|
||||
#include "djui_panel.h"
|
||||
#include "djui_panel_menu.h"
|
||||
#include "pc/lua/smlua_hooks.h"
|
||||
|
||||
static char* sDjuiPanelModMenuModName = NULL;
|
||||
|
||||
static char* to_uppercase(char* str) {
|
||||
char* buffer = strdup(str);
|
||||
int i = 0;
|
||||
while (buffer[i] != '\0') {
|
||||
buffer[i] = toupper(buffer[i]);
|
||||
i++;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// generic
|
||||
void djui_panel_mod_menu_mod_element(struct DjuiBase* caller) {
|
||||
struct LuaHookedModMenuElement* hooked = &gHookedModMenuElements[caller->tag];
|
||||
smlua_call_mod_menu_element_hook(hooked, caller->tag);
|
||||
}
|
||||
|
||||
static void djui_panel_mod_menu_mod_inputbox(struct DjuiBase* caller) {
|
||||
struct DjuiInputbox* inputbox = (struct DjuiInputbox*)caller;
|
||||
struct LuaHookedModMenuElement* hooked = &gHookedModMenuElements[caller->tag];
|
||||
snprintf(hooked->stringValue, 256, "%s", inputbox->buffer);
|
||||
smlua_call_mod_menu_element_hook(hooked, caller->tag);
|
||||
}
|
||||
|
||||
static void djui_panel_mod_menu_mod_create_element(struct DjuiBase* parent, int i) {
|
||||
struct LuaHookedModMenuElement* hooked = &gHookedModMenuElements[i];
|
||||
switch (hooked->element) {
|
||||
case MOD_MENU_ELEMENT_BUTTON:
|
||||
struct DjuiButton* button = djui_button_create(parent, hooked->name, DJUI_BUTTON_STYLE_NORMAL, djui_panel_mod_menu_mod_element);
|
||||
button->base.tag = i;
|
||||
break;
|
||||
case MOD_MENU_ELEMENT_CHECKBOX:
|
||||
struct DjuiCheckbox* checkbox = djui_checkbox_create(parent, hooked->name, &hooked->boolValue, djui_panel_mod_menu_mod_element);
|
||||
checkbox->base.tag = i;
|
||||
break;
|
||||
case MOD_MENU_ELEMENT_SLIDER:
|
||||
struct DjuiSlider* slider = djui_slider_create(parent, hooked->name, &hooked->uintValue, hooked->sliderMin, hooked->sliderMax, djui_panel_mod_menu_mod_element);
|
||||
slider->base.tag = i;
|
||||
break;
|
||||
case MOD_MENU_ELEMENT_INPUTBOX:
|
||||
struct DjuiRect* rect = djui_rect_container_create(parent, 32);
|
||||
{
|
||||
struct DjuiText* text1 = djui_text_create(&rect->base, hooked->name);
|
||||
djui_base_set_size_type(&text1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_color(&text1->base, 220, 220, 220, 255);
|
||||
djui_base_set_size(&text1->base, 0.585f, 64);
|
||||
djui_base_set_alignment(&text1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
|
||||
djui_text_set_drop_shadow(text1, 64, 64, 64, 100);
|
||||
|
||||
struct DjuiInputbox* inputbox = djui_inputbox_create(&rect->base, hooked->length);
|
||||
djui_base_set_size_type(&inputbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&inputbox->base, 0.45f, 32);
|
||||
djui_base_set_alignment(&inputbox->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
|
||||
djui_inputbox_set_text(inputbox, hooked->stringValue);
|
||||
djui_interactable_hook_value_change(&inputbox->base, djui_panel_mod_menu_mod_inputbox);
|
||||
inputbox->base.tag = i;
|
||||
}
|
||||
break;
|
||||
case MOD_MENU_ELEMENT_MAX:
|
||||
}
|
||||
}
|
||||
|
||||
void djui_panel_mod_menu_mod_create(struct DjuiBase* caller) {
|
||||
struct DjuiThreePanel* panel = djui_panel_menu_create(to_uppercase(sDjuiPanelModMenuModName));
|
||||
struct DjuiBase* body = djui_three_panel_get_body(panel);
|
||||
{
|
||||
struct DjuiPaginated* paginated = djui_paginated_create(body, 8);
|
||||
struct DjuiBase* layoutBase = &paginated->layout->base;
|
||||
for (int i = 0; i < gHookedModMenuElementsCount; i++) {
|
||||
djui_panel_mod_menu_mod_create_element(layoutBase, i);
|
||||
}
|
||||
djui_paginated_calculate_height(paginated);
|
||||
|
||||
djui_button_create(body, DLANG(MENU, BACK), DJUI_BUTTON_STYLE_BACK, djui_panel_menu_back);
|
||||
}
|
||||
|
||||
djui_panel_add(caller, panel, NULL);
|
||||
}
|
||||
|
||||
void djui_panel_mod_menu_create(struct DjuiBase* caller) {
|
||||
struct DjuiThreePanel* panel = djui_panel_menu_create(DLANG(PAUSE, MOD_MENU_TITLE));
|
||||
struct DjuiBase* body = djui_three_panel_get_body(panel);
|
||||
{
|
||||
struct DjuiPaginated* paginated = djui_paginated_create(body, 8);
|
||||
struct DjuiBase* layoutBase = &paginated->layout->base;
|
||||
struct Mod* lastMod = NULL;
|
||||
for (int i = 0; i < gHookedModMenuElementsCount; i++) {
|
||||
struct LuaHookedModMenuElement* hooked = &gHookedModMenuElements[i];
|
||||
if (lastMod == hooked->mod) { continue; }
|
||||
lastMod = hooked->mod;
|
||||
sDjuiPanelModMenuModName = lastMod->name;
|
||||
djui_button_create(layoutBase, hooked->mod->name, DJUI_BUTTON_STYLE_NORMAL, djui_panel_mod_menu_mod_create);
|
||||
}
|
||||
djui_paginated_calculate_height(paginated);
|
||||
|
||||
djui_button_create(body, DLANG(MENU, BACK), DJUI_BUTTON_STYLE_BACK, djui_panel_menu_back);
|
||||
}
|
||||
|
||||
djui_panel_add(caller, panel, NULL);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
#include "djui.h"
|
||||
|
||||
void djui_panel_mod_menu_mod_element(struct DjuiBase* caller);
|
||||
void djui_panel_mod_menu_mod_create(struct DjuiBase* caller);
|
||||
void djui_panel_mod_menu_create(struct DjuiBase* caller);
|
|
@ -1,3 +1,4 @@
|
|||
#include "sm64.h"
|
||||
#include "djui.h"
|
||||
#include "djui_panel.h"
|
||||
#include "djui_panel_player.h"
|
||||
|
@ -6,11 +7,12 @@
|
|||
#include "djui_panel_host.h"
|
||||
#include "djui_panel_menu.h"
|
||||
#include "djui_panel_confirm.h"
|
||||
#include "djui_panel_mod_menu.h"
|
||||
#include "pc/pc_main.h"
|
||||
#include "pc/network/network.h"
|
||||
#include "pc/lua/smlua_hooks.h"
|
||||
#include "game/object_helpers.h"
|
||||
#include "behavior_table.h"
|
||||
#include "sm64.h"
|
||||
|
||||
bool gDjuiPanelPauseCreated = false;
|
||||
|
||||
|
@ -56,7 +58,6 @@ void djui_panel_pause_create(struct DjuiBase* caller) {
|
|||
struct DjuiThreePanel* panel = djui_panel_menu_create(DLANG(PAUSE, PAUSE_TITLE));
|
||||
struct DjuiBase* body = djui_three_panel_get_body(panel);
|
||||
{
|
||||
|
||||
struct DjuiRect* rect1 = djui_rect_container_create(body, 64);
|
||||
{
|
||||
djui_button_left_create(&rect1->base, DLANG(PAUSE, PLAYER), DJUI_BUTTON_STYLE_NORMAL, djui_panel_player_create);
|
||||
|
@ -70,6 +71,20 @@ void djui_panel_pause_create(struct DjuiBase* caller) {
|
|||
djui_button_create(body, DLANG(PAUSE, SERVER_SETTINGS), DJUI_BUTTON_STYLE_NORMAL, djui_panel_host_create);
|
||||
}
|
||||
|
||||
if (gHookedModMenuElementsCount == 1 && gHookedModMenuElements[0].element == MOD_MENU_ELEMENT_BUTTON) {
|
||||
struct LuaHookedModMenuElement* hooked = &gHookedModMenuElements[0];
|
||||
char buffer[256] = { 0 };
|
||||
if (strlen(hooked->name) > 0) {
|
||||
snprintf(buffer, 256, "%s - %s", hooked->mod->name, hooked->name);
|
||||
} else {
|
||||
snprintf(buffer, 256, "%s", hooked->mod->name);
|
||||
}
|
||||
struct DjuiButton* button = djui_button_create(body, buffer, DJUI_BUTTON_STYLE_NORMAL, djui_panel_mod_menu_mod_element);
|
||||
button->base.tag = 0;
|
||||
} else if (gHookedModMenuElementsCount > 0) {
|
||||
djui_button_create(body, DLANG(PAUSE, MOD_MENU), DJUI_BUTTON_STYLE_NORMAL, djui_panel_mod_menu_create);
|
||||
}
|
||||
|
||||
djui_button_create(body, DLANG(PAUSE, RESUME), DJUI_BUTTON_STYLE_NORMAL, djui_panel_pause_resume);
|
||||
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
|
|
|
@ -26,8 +26,8 @@ static struct DjuiInputbox* sPalettePresetNameTextBox = NULL;
|
|||
|
||||
void djui_panel_player_create(struct DjuiBase* caller);
|
||||
|
||||
////////////////////////
|
||||
// edit palette panel //
|
||||
////////////////////////
|
||||
// edit palette panel //
|
||||
////////////////////////
|
||||
|
||||
static unsigned int djui_panel_player_edit_palette_get_palette_index(struct PlayerPalette palette) {
|
||||
|
@ -290,8 +290,8 @@ static void djui_panel_player_edit_palette_create(struct DjuiBase* caller) {
|
|||
}
|
||||
|
||||
|
||||
//////////////////
|
||||
// player panel //
|
||||
//////////////////
|
||||
// player panel //
|
||||
//////////////////
|
||||
|
||||
static bool djui_panel_player_name_valid(char* buffer) {
|
||||
|
@ -319,7 +319,7 @@ static void djui_panel_player_name_on_focus_end(struct DjuiBase* caller) {
|
|||
if (!djui_panel_player_name_valid(inputbox1->buffer)) {
|
||||
djui_inputbox_set_text(inputbox1, DLANG(PLAYER, PLAYER));
|
||||
}
|
||||
snprintf(configPlayerName, MAX_PLAYER_STRING, "%s", inputbox1->buffer);
|
||||
snprintf(configPlayerName, MAX_CONFIG_STRING, "%s", inputbox1->buffer);
|
||||
djui_inputbox_set_text_color(inputbox1, 0, 0, 0, 255);
|
||||
|
||||
if (gNetworkType != NT_NONE) {
|
||||
|
@ -384,7 +384,7 @@ void djui_panel_player_create(struct DjuiBase* caller) {
|
|||
djui_base_set_alignment(&text1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
|
||||
djui_text_set_drop_shadow(text1, 64, 64, 64, 100);
|
||||
|
||||
struct DjuiInputbox* inputbox1 = djui_inputbox_create(&rect1->base, MAX_PLAYER_STRING);
|
||||
struct DjuiInputbox* inputbox1 = djui_inputbox_create(&rect1->base, MAX_CONFIG_STRING);
|
||||
djui_base_set_size_type(&inputbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&inputbox1->base, 0.45f, 32);
|
||||
djui_base_set_alignment(&inputbox1->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
|
||||
|
|
|
@ -232,7 +232,23 @@ static char* djui_text_render_line_parse_escape(char* c1, char* c2) {
|
|||
}
|
||||
|
||||
if (parsingColor) {
|
||||
if (colorPieces == 6) {
|
||||
if (colorPieces == 3) {
|
||||
u32 r = (color >> 8) & 0xF;
|
||||
u32 g = (color >> 4) & 0xF;
|
||||
u32 b = (color >> 0) & 0xF;
|
||||
sSavedR = (r << 4) | r;
|
||||
sSavedG = (g << 4) | g;
|
||||
sSavedB = (b << 4) | b;
|
||||
} else if (colorPieces == 4) {
|
||||
u32 r = (color >> 12) & 0xF;
|
||||
u32 g = (color >> 8) & 0xF;
|
||||
u32 b = (color >> 4) & 0xF;
|
||||
u32 a = (color >> 0) & 0xF;
|
||||
sSavedR = (r << 4) | r;
|
||||
sSavedG = (g << 4) | g;
|
||||
sSavedB = (b << 4) | b;
|
||||
sSavedA = (a << 4) | a;
|
||||
} else if (colorPieces == 6) {
|
||||
sSavedR = ((color >> 16) & 0xFF);
|
||||
sSavedG = ((color >> 8) & 0xFF);
|
||||
sSavedB = ((color >> 0) & 0xFF);
|
||||
|
|
|
@ -3291,10 +3291,16 @@ char gSmluaConstants[] = ""
|
|||
"HOOK_ON_PLAY_SOUND = 41\n"
|
||||
"HOOK_ON_SEQ_LOAD = 42\n"
|
||||
"HOOK_ON_ATTACK_OBJECT = 43\n"
|
||||
"HOOK_MAX = 44\n"
|
||||
"HOOK_ON_LANGUAGE_CHANGED = 44\n"
|
||||
"HOOK_MAX = 45\n"
|
||||
"ACTION_HOOK_EVERY_FRAME = 0\n"
|
||||
"ACTION_HOOK_GRAVITY = 1\n"
|
||||
"ACTION_HOOK_MAX = 2\n"
|
||||
"MOD_MENU_ELEMENT_BUTTON = 0\n"
|
||||
"MOD_MENU_ELEMENT_CHECKBOX = 1\n"
|
||||
"MOD_MENU_ELEMENT_SLIDER = 2\n"
|
||||
"MOD_MENU_ELEMENT_INPUTBOX = 3\n"
|
||||
"MOD_MENU_ELEMENT_MAX = 4\n"
|
||||
"HUD_DISPLAY_LIVES = 0\n"
|
||||
"HUD_DISPLAY_COINS = 1\n"
|
||||
"HUD_DISPLAY_STARS = 2\n"
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "pc/network/socket/socket.h"
|
||||
#include "pc/chat_commands.h"
|
||||
#include "pc/pc_main.h"
|
||||
#include "pc/djui/djui_panel.h"
|
||||
|
||||
#include "../mods/mods.h"
|
||||
#include "game/print.h"
|
||||
|
@ -1116,6 +1117,25 @@ const char *smlua_call_event_hooks_int_ret_bool_and_string(enum LuaHookedEventTy
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void smlua_call_event_hooks_string_param(enum LuaHookedEventType hookType, const char* string) {
|
||||
lua_State* L = gLuaState;
|
||||
if (L == NULL) { return; }
|
||||
struct LuaHookedEvent* hook = &sHookedEvents[hookType];
|
||||
for (int i = 0; i < hook->count; i++) {
|
||||
// push the callback onto the stack
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]);
|
||||
|
||||
// push string
|
||||
lua_pushstring(L, string);
|
||||
|
||||
// call the callback
|
||||
if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i])) {
|
||||
LOG_LUA("Failed to call the callback: %u", hookType);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
// hooked actions //
|
||||
////////////////////
|
||||
|
@ -1213,7 +1233,6 @@ int smlua_hook_mario_action(lua_State* L) {
|
|||
hooked->action = action;
|
||||
hooked->interactionType = interactionType;
|
||||
hooked->mod = gLuaActiveMod;
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
|
||||
sHookedMarioActionsCount++;
|
||||
return 1;
|
||||
|
@ -1633,7 +1652,6 @@ int smlua_hook_chat_command(lua_State* L) {
|
|||
hooked->description = strdup(description);
|
||||
hooked->reference = ref;
|
||||
hooked->mod = gLuaActiveMod;
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
|
||||
sHookedChatCommandsCount++;
|
||||
return 1;
|
||||
|
@ -1966,6 +1984,292 @@ int smlua_hook_on_sync_table_change(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////
|
||||
// hooked mod menu button //
|
||||
////////////////////////////
|
||||
|
||||
#define MAX_HOOKED_MOD_MENU_ELEMENTS 256
|
||||
|
||||
struct LuaHookedModMenuElement gHookedModMenuElements[MAX_HOOKED_MOD_MENU_ELEMENTS] = { 0 };
|
||||
int gHookedModMenuElementsCount = 0;
|
||||
|
||||
int smlua_hook_mod_menu_button(lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
if (!smlua_functions_valid_param_count(L, 2)) { return 0; }
|
||||
|
||||
if (gLuaLoadingMod == NULL) {
|
||||
LOG_LUA_LINE("hook_mod_menu_button() can only be called on load.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (gHookedModMenuElementsCount >= MAX_HOOKED_MOD_MENU_ELEMENTS) {
|
||||
LOG_LUA_LINE("Hooked mod menu element exceeded maximum references!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* name = smlua_to_string(L, 1);
|
||||
if (name == NULL || !gSmLuaConvertSuccess) {
|
||||
LOG_LUA_LINE("Hook mod menu element: tried to hook invalid element");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
if (ref == -1) {
|
||||
LOG_LUA_LINE("Hook mod menu element: tried to hook undefined function '%s'", gLuaActiveMod->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct LuaHookedModMenuElement* hooked = &gHookedModMenuElements[gHookedModMenuElementsCount];
|
||||
hooked->element = MOD_MENU_ELEMENT_BUTTON;
|
||||
snprintf(hooked->name, 64, "%s", name);
|
||||
hooked->boolValue = false;
|
||||
hooked->uintValue = 0;
|
||||
hooked->stringValue[0] = '\0';
|
||||
hooked->length = 0;
|
||||
hooked->sliderMin = 0;
|
||||
hooked->sliderMax = 0;
|
||||
hooked->reference = ref;
|
||||
hooked->mod = gLuaActiveMod;
|
||||
|
||||
gHookedModMenuElementsCount++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_hook_mod_menu_checkbox(lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
if (!smlua_functions_valid_param_count(L, 3)) { return 0; }
|
||||
|
||||
if (gLuaLoadingMod == NULL) {
|
||||
LOG_LUA_LINE("hook_mod_menu_checkbox() can only be called on load.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (gHookedModMenuElementsCount >= MAX_HOOKED_MOD_MENU_ELEMENTS) {
|
||||
LOG_LUA_LINE("Hooked mod menu element exceeded maximum references!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* name = smlua_to_string(L, 1);
|
||||
if (name == NULL || strlen(name) == 0 || !gSmLuaConvertSuccess) {
|
||||
LOG_LUA_LINE("Hook mod menu element: tried to hook invalid element");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool defaultValue = smlua_to_boolean(L, 2);
|
||||
if (!gSmLuaConvertSuccess) {
|
||||
LOG_LUA_LINE("Hook mod menu element: tried to hook invalid element");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
if (ref == -1) {
|
||||
LOG_LUA_LINE("Hook mod menu element: tried to hook undefined function '%s'", gLuaActiveMod->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct LuaHookedModMenuElement* hooked = &gHookedModMenuElements[gHookedModMenuElementsCount];
|
||||
hooked->element = MOD_MENU_ELEMENT_CHECKBOX;
|
||||
snprintf(hooked->name, 64, "%s", name);
|
||||
hooked->boolValue = defaultValue;
|
||||
hooked->uintValue = 0;
|
||||
hooked->stringValue[0] = '\0';
|
||||
hooked->length = 0;
|
||||
hooked->sliderMin = 0;
|
||||
hooked->sliderMax = 0;
|
||||
hooked->reference = ref;
|
||||
hooked->mod = gLuaActiveMod;
|
||||
|
||||
gHookedModMenuElementsCount++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_hook_mod_menu_slider(lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
if (!smlua_functions_valid_param_count(L, 5)) { return 0; }
|
||||
|
||||
if (gLuaLoadingMod == NULL) {
|
||||
LOG_LUA_LINE("hook_mod_menu_slider() can only be called on load.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (gHookedModMenuElementsCount >= MAX_HOOKED_MOD_MENU_ELEMENTS) {
|
||||
LOG_LUA_LINE("Hooked mod menu element exceeded maximum references!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* name = smlua_to_string(L, 1);
|
||||
if (name == NULL || strlen(name) == 0 || !gSmLuaConvertSuccess) {
|
||||
LOG_LUA_LINE("Hook mod menu element: tried to hook invalid element");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 defaultValue = smlua_to_integer(L, 2);
|
||||
if (!gSmLuaConvertSuccess) {
|
||||
LOG_LUA_LINE("Hook mod menu element: tried to hook invalid element");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sliderMin = smlua_to_integer(L, 3);
|
||||
if (!gSmLuaConvertSuccess) {
|
||||
LOG_LUA_LINE("Hook mod menu element: tried to hook invalid element");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sliderMax = smlua_to_integer(L, 4);
|
||||
if (!gSmLuaConvertSuccess) {
|
||||
LOG_LUA_LINE("Hook mod menu element: tried to hook invalid element");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
if (ref == -1) {
|
||||
LOG_LUA_LINE("Hook mod menu element: tried to hook undefined function '%s'", gLuaActiveMod->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct LuaHookedModMenuElement* hooked = &gHookedModMenuElements[gHookedModMenuElementsCount];
|
||||
hooked->element = MOD_MENU_ELEMENT_SLIDER;
|
||||
snprintf(hooked->name, 64, "%s", name);
|
||||
hooked->boolValue = false;
|
||||
hooked->uintValue = defaultValue;
|
||||
hooked->stringValue[0] = '\0';
|
||||
hooked->length = 0;
|
||||
hooked->sliderMin = sliderMin;
|
||||
hooked->sliderMax = sliderMax;
|
||||
hooked->reference = ref;
|
||||
hooked->mod = gLuaActiveMod;
|
||||
|
||||
gHookedModMenuElementsCount++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_hook_mod_menu_inputbox(lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
if (!smlua_functions_valid_param_count(L, 4)) { return 0; }
|
||||
|
||||
if (gLuaLoadingMod == NULL) {
|
||||
LOG_LUA_LINE("hook_mod_menu_inputbox() can only be called on load.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (gHookedModMenuElementsCount >= MAX_HOOKED_MOD_MENU_ELEMENTS) {
|
||||
LOG_LUA_LINE("Hooked mod menu element exceeded maximum references!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* name = smlua_to_string(L, 1);
|
||||
if (name == NULL || strlen(name) == 0 || !gSmLuaConvertSuccess) {
|
||||
LOG_LUA_LINE("Hook mod menu element: tried to hook invalid element");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* defaultValue = smlua_to_string(L, 2);
|
||||
if (defaultValue == NULL || !gSmLuaConvertSuccess) {
|
||||
LOG_LUA_LINE("Hook mod menu element: tried to hook invalid element");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 length = smlua_to_integer(L, 3);
|
||||
length = MIN(length, 256);
|
||||
if (!gSmLuaConvertSuccess) {
|
||||
LOG_LUA_LINE("Hook mod menu element: tried to hook invalid element");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
if (ref == -1) {
|
||||
LOG_LUA_LINE("Hook mod menu element: tried to hook undefined function '%s'", gLuaActiveMod->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct LuaHookedModMenuElement* hooked = &gHookedModMenuElements[gHookedModMenuElementsCount];
|
||||
hooked->element = MOD_MENU_ELEMENT_INPUTBOX;
|
||||
snprintf(hooked->name, 64, "%s", name);
|
||||
hooked->boolValue = false;
|
||||
hooked->uintValue = 0;
|
||||
snprintf(hooked->stringValue, 256, "%s", defaultValue);
|
||||
hooked->length = length;
|
||||
hooked->sliderMin = 0;
|
||||
hooked->sliderMax = 0;
|
||||
hooked->reference = ref;
|
||||
hooked->mod = gLuaActiveMod;
|
||||
|
||||
gHookedModMenuElementsCount++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_update_mod_menu_element_name(lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
if (!smlua_functions_valid_param_count(L, 2)) { return 0; }
|
||||
|
||||
int index = smlua_to_integer(L, 1);
|
||||
if (index >= gHookedModMenuElementsCount || !gSmLuaConvertSuccess) {
|
||||
LOG_LUA_LINE("Update mod menu element: tried to update invalid element");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* name = smlua_to_string(L, 2);
|
||||
if (name == NULL || !gSmLuaConvertSuccess) {
|
||||
LOG_LUA_LINE("Update mod menu element: tried to update invalid name");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (gHookedModMenuElements[index].element != MOD_MENU_ELEMENT_BUTTON && strlen(name) == 0) {
|
||||
LOG_LUA_LINE("Update mod menu element: tried to update invalid name");
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(gHookedModMenuElements[index].name, 64, "%s", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void smlua_call_mod_menu_element_hook(struct LuaHookedModMenuElement* hooked, int index) {
|
||||
lua_State* L = gLuaState;
|
||||
if (L == NULL) { return; }
|
||||
|
||||
// push the callback onto the stack
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, hooked->reference);
|
||||
|
||||
// push parameter
|
||||
u8 params = 2;
|
||||
lua_pushinteger(L, index);
|
||||
switch (hooked->element) {
|
||||
case MOD_MENU_ELEMENT_BUTTON:
|
||||
params = 1;
|
||||
break;
|
||||
case MOD_MENU_ELEMENT_CHECKBOX:
|
||||
lua_pushboolean(L, hooked->boolValue);
|
||||
break;
|
||||
case MOD_MENU_ELEMENT_SLIDER:
|
||||
lua_pushinteger(L, hooked->uintValue);
|
||||
break;
|
||||
case MOD_MENU_ELEMENT_INPUTBOX:
|
||||
lua_pushstring(L, hooked->stringValue);
|
||||
break;
|
||||
case MOD_MENU_ELEMENT_MAX:
|
||||
}
|
||||
|
||||
// call the callback
|
||||
if (0 != smlua_call_hook(L, params, 1, 0, hooked->mod)) {
|
||||
LOG_LUA("Failed to call the mod menu element callback: %s", hooked->name);
|
||||
return;
|
||||
}
|
||||
|
||||
// output the return value
|
||||
bool returnValue = false;
|
||||
if (lua_type(L, -1) == LUA_TBOOLEAN) {
|
||||
returnValue = smlua_to_boolean(L, -1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
if (!gSmLuaConvertSuccess || !returnValue || hooked->element != MOD_MENU_ELEMENT_BUTTON) { return; }
|
||||
|
||||
gForceUnpause = true;
|
||||
djui_panel_shutdown();
|
||||
}
|
||||
|
||||
|
||||
//////////
|
||||
// misc //
|
||||
//////////
|
||||
|
@ -2001,6 +2305,21 @@ void smlua_clear_hooks(void) {
|
|||
}
|
||||
sHookedChatCommandsCount = 0;
|
||||
|
||||
for (int i = 0; i < gHookedModMenuElementsCount; i++) {
|
||||
struct LuaHookedModMenuElement* hooked = &gHookedModMenuElements[i];
|
||||
hooked->element = MOD_MENU_ELEMENT_BUTTON;
|
||||
hooked->name[0] = '\0';
|
||||
hooked->boolValue = false;
|
||||
hooked->uintValue = 0;
|
||||
hooked->stringValue[0] = '\0';
|
||||
hooked->length = 0;
|
||||
hooked->sliderMin = 0;
|
||||
hooked->sliderMax = 0;
|
||||
hooked->reference = 0;
|
||||
hooked->mod = NULL;
|
||||
}
|
||||
gHookedModMenuElementsCount = 0;
|
||||
|
||||
for (int i = 0; i < sHookedBehaviorsCount; i++) {
|
||||
struct LuaHookedBehavior* hooked = &sHookedBehaviors[i];
|
||||
|
||||
|
@ -2040,5 +2359,10 @@ void smlua_bind_hooks(void) {
|
|||
smlua_bind_function(L, "hook_chat_command", smlua_hook_chat_command);
|
||||
smlua_bind_function(L, "hook_on_sync_table_change", smlua_hook_on_sync_table_change);
|
||||
smlua_bind_function(L, "hook_behavior", smlua_hook_behavior);
|
||||
smlua_bind_function(L, "hook_mod_menu_button", smlua_hook_mod_menu_button);
|
||||
smlua_bind_function(L, "hook_mod_menu_checkbox", smlua_hook_mod_menu_checkbox);
|
||||
smlua_bind_function(L, "hook_mod_menu_slider", smlua_hook_mod_menu_slider);
|
||||
smlua_bind_function(L, "hook_mod_menu_inputbox", smlua_hook_mod_menu_inputbox);
|
||||
smlua_bind_function(L, "update_chat_command_description", smlua_update_chat_command_description);
|
||||
smlua_bind_function(L, "update_mod_menu_element_name", smlua_update_mod_menu_element_name);
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ enum LuaHookedEventType {
|
|||
HOOK_ON_PLAY_SOUND,
|
||||
HOOK_ON_SEQ_LOAD,
|
||||
HOOK_ON_ATTACK_OBJECT,
|
||||
HOOK_ON_LANGUAGE_CHANGED,
|
||||
HOOK_MAX,
|
||||
};
|
||||
|
||||
|
@ -103,6 +104,7 @@ static const char* LuaHookedEventTypeName[] = {
|
|||
"HOOK_ON_PLAY_SOUND",
|
||||
"HOOK_ON_SEQ_LOAD",
|
||||
"HOOK_ON_ATTACK_OBJECT",
|
||||
"HOOK_ON_LANGUAGE_CHANGED",
|
||||
"HOOK_MAX"
|
||||
};
|
||||
|
||||
|
@ -118,7 +120,31 @@ static const char* LuaActionHookTypeArgName[] = {
|
|||
"max (dummy)",
|
||||
};
|
||||
|
||||
enum LuaModMenuElementType {
|
||||
MOD_MENU_ELEMENT_BUTTON,
|
||||
MOD_MENU_ELEMENT_CHECKBOX,
|
||||
MOD_MENU_ELEMENT_SLIDER,
|
||||
MOD_MENU_ELEMENT_INPUTBOX,
|
||||
MOD_MENU_ELEMENT_MAX
|
||||
};
|
||||
|
||||
struct LuaHookedModMenuElement {
|
||||
enum LuaModMenuElementType element;
|
||||
char name[64];
|
||||
// use a union here?
|
||||
bool boolValue;
|
||||
u32 uintValue;
|
||||
char stringValue[256];
|
||||
u32 length;
|
||||
u32 sliderMin;
|
||||
u32 sliderMax;
|
||||
int reference;
|
||||
struct Mod* mod;
|
||||
};
|
||||
|
||||
extern u32 gLuaMarioActionIndex[];
|
||||
extern struct LuaHookedModMenuElement gHookedModMenuElements[];
|
||||
extern int gHookedModMenuElementsCount;
|
||||
|
||||
int smlua_hook_custom_bhv(BehaviorScript *bhvScript, const char *bhvName);
|
||||
|
||||
|
@ -154,6 +180,7 @@ bool smlua_call_event_hooks_mario_param_and_int_and_int_ret_int(enum LuaHookedEv
|
|||
void smlua_call_event_hooks_graph_node_object_and_int_param(enum LuaHookedEventType hookType, struct GraphNodeObject* node, s32 param);
|
||||
void smlua_call_event_hooks_on_seq_load(enum LuaHookedEventType hookType, u32 player, u32 seqId, s32 loadAsync, u8* returnValue);
|
||||
const char *smlua_call_event_hooks_int_ret_bool_and_string(enum LuaHookedEventType hookType, s32 param, bool* returnValue);
|
||||
void smlua_call_event_hooks_string_param(enum LuaHookedEventType hookType, const char* string);
|
||||
|
||||
enum BehaviorId smlua_get_original_behavior_id(const BehaviorScript* behavior);
|
||||
const BehaviorScript* smlua_override_behavior(const BehaviorScript* behavior);
|
||||
|
@ -174,6 +201,8 @@ char** smlua_get_chat_subcommands_list(const char* maincommand);
|
|||
bool smlua_maincommand_exists(const char* maincommand);
|
||||
bool smlua_subcommand_exists(const char* maincommand, const char* subcommand);
|
||||
|
||||
void smlua_call_mod_menu_element_hook(struct LuaHookedModMenuElement* hooked, int index);
|
||||
|
||||
void smlua_clear_hooks(void);
|
||||
void smlua_bind_hooks(void);
|
||||
|
||||
|
|
|
@ -91,8 +91,8 @@ void nametags_render(void) {
|
|||
scale = clampf(1 - scale, 0, NAMETAG_MAX_SCALE);
|
||||
}
|
||||
|
||||
char name[MAX_PLAYER_STRING + 1];
|
||||
strncpy(name, np->name, MAX_PLAYER_STRING + 1);
|
||||
char name[MAX_CONFIG_STRING];
|
||||
snprintf(name, MAX_CONFIG_STRING, "%s", np->name);
|
||||
name_without_hex(name);
|
||||
Color color = {
|
||||
np->palette.parts[CAP][0],
|
||||
|
|
|
@ -259,7 +259,7 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 mode
|
|||
np->palette = *palette;
|
||||
network_player_update_model(localIndex);
|
||||
|
||||
snprintf(np->name, MAX_PLAYER_STRING, "%s", name);
|
||||
snprintf(np->name, MAX_CONFIG_STRING, "%s", name);
|
||||
return localIndex;
|
||||
}
|
||||
|
||||
|
@ -289,7 +289,7 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 mode
|
|||
np->overrideModelIndex = modelIndex;
|
||||
np->overridePalette = *palette;
|
||||
|
||||
snprintf(np->name, MAX_PLAYER_STRING, "%s", name);
|
||||
snprintf(np->name, MAX_CONFIG_STRING, "%s", name);
|
||||
network_player_update_model(localIndex);
|
||||
|
||||
// clear networking fields
|
||||
|
|
|
@ -44,9 +44,9 @@ struct NetworkPlayer {
|
|||
u8 gag;
|
||||
u32 ping;
|
||||
struct PlayerPalette palette;
|
||||
char name[MAX_PLAYER_STRING+1];
|
||||
char name[MAX_CONFIG_STRING];
|
||||
|
||||
char description[MAX_DESCRIPTION_STRING+1];
|
||||
char description[MAX_DESCRIPTION_STRING];
|
||||
u8 descriptionR;
|
||||
u8 descriptionG;
|
||||
u8 descriptionB;
|
||||
|
@ -58,7 +58,7 @@ struct NetworkPlayer {
|
|||
u16 rxSeqIds[MAX_RX_SEQ_IDS];
|
||||
u32 rxPacketHash[MAX_RX_SEQ_IDS];
|
||||
|
||||
// legacy fields to allow mods not to break (they don't do anything anymore)
|
||||
// legacy fields to allow mods not to fully break (they don't do anything anymore)
|
||||
u8 paletteIndex;
|
||||
u8 overridePaletteIndex;
|
||||
u8 overridePaletteIndexLp;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <stdio.h>
|
||||
#include "network_utils.h"
|
||||
#include "game/level_update.h"
|
||||
#include "game/mario_misc.h"
|
||||
#include "pc/mods/mods.h"
|
||||
|
||||
|
@ -53,5 +54,5 @@ const char* network_get_player_text_color_string(u8 localIndex) {
|
|||
|
||||
extern s16 gMenuMode;
|
||||
bool network_check_singleplayer_pause(void) {
|
||||
return gMenuMode != -1 && network_player_connected_count() == 1 && mods_get_all_pausable();
|
||||
return gMenuMode != -1 && network_player_connected_count() == 1 && mods_get_all_pausable() && !gInPlayerMenu;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ static u8 eeprom[512] = { 0 };
|
|||
|
||||
static u8 sJoinRequestPlayerModel;
|
||||
static struct PlayerPalette sJoinRequestPlayerPalette;
|
||||
static char sJoinRequestPlayerName[MAX_PLAYER_STRING];
|
||||
static char sJoinRequestPlayerName[MAX_CONFIG_STRING];
|
||||
bool gCurrentlyJoining = false;
|
||||
|
||||
void network_send_join_request(void) {
|
||||
|
@ -48,7 +48,7 @@ void network_send_join_request(void) {
|
|||
|
||||
packet_write(&p, &configPlayerModel, sizeof(u8));
|
||||
packet_write(&p, &configPlayerPalette, sizeof(struct PlayerPalette));
|
||||
packet_write(&p, &configPlayerName, sizeof(u8) * MAX_PLAYER_STRING);
|
||||
packet_write(&p, &configPlayerName, sizeof(u8) * MAX_CONFIG_STRING);
|
||||
|
||||
network_send_to((gNetworkPlayerServer != NULL) ? gNetworkPlayerServer->localIndex : 0, &p);
|
||||
LOG_INFO("sending join request");
|
||||
|
@ -63,11 +63,11 @@ void network_receive_join_request(struct Packet* p) {
|
|||
packet_read(p, &version, sizeof(u8) * MAX_VERSION_LENGTH);
|
||||
packet_read(p, &sJoinRequestPlayerModel, sizeof(u8));
|
||||
packet_read(p, &sJoinRequestPlayerPalette, sizeof(struct PlayerPalette));
|
||||
packet_read(p, &sJoinRequestPlayerName, sizeof(u8) * MAX_PLAYER_STRING);
|
||||
packet_read(p, &sJoinRequestPlayerName, sizeof(u8) * MAX_CONFIG_STRING);
|
||||
} else {
|
||||
sJoinRequestPlayerModel = 0;
|
||||
sJoinRequestPlayerPalette = DEFAULT_MARIO_PALETTE;
|
||||
snprintf(sJoinRequestPlayerName, MAX_PLAYER_STRING, "%s", "Player");
|
||||
snprintf(sJoinRequestPlayerName, MAX_CONFIG_STRING, "%s", "Player");
|
||||
}
|
||||
|
||||
network_send_join(p);
|
||||
|
|
|
@ -34,7 +34,7 @@ static void network_send_to_network_players(u8 sendToLocalIndex) {
|
|||
packet_write(&p, &networkId, sizeof(s64));
|
||||
packet_write(&p, &gNetworkPlayers[i].modelIndex, sizeof(u8));
|
||||
packet_write(&p, &gNetworkPlayers[i].palette, sizeof(struct PlayerPalette));
|
||||
packet_write(&p, &gNetworkPlayers[i].name, sizeof(u8) * MAX_PLAYER_STRING);
|
||||
packet_write(&p, &gNetworkPlayers[i].name, sizeof(u8) * MAX_CONFIG_STRING);
|
||||
LOG_INFO("send network player [%d == %d]", gNetworkPlayers[i].globalIndex, npType);
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ void network_receive_network_players(struct Packet *p) {
|
|||
s64 networkId;
|
||||
u8 modelIndex;
|
||||
struct PlayerPalette palette;
|
||||
char playerName[MAX_PLAYER_STRING] = { 0 };
|
||||
char playerName[MAX_CONFIG_STRING] = { 0 };
|
||||
|
||||
packet_read(p, &npType, sizeof(u8));
|
||||
packet_read(p, &globalIndex, sizeof(u8));
|
||||
|
@ -105,7 +105,7 @@ void network_receive_network_players(struct Packet *p) {
|
|||
packet_read(p, &networkId, sizeof(s64));
|
||||
packet_read(p, &modelIndex, sizeof(u8));
|
||||
packet_read(p, &palette, sizeof(struct PlayerPalette));
|
||||
packet_read(p, &playerName, sizeof(u8) * MAX_PLAYER_STRING);
|
||||
packet_read(p, &playerName, sizeof(u8) * MAX_CONFIG_STRING);
|
||||
|
||||
u8 localIndex = network_player_connected(npType, globalIndex, modelIndex, &palette, playerName);
|
||||
LOG_INFO("received network player [%d == %d] (%d)", globalIndex, npType, localIndex);
|
||||
|
|
|
@ -3,20 +3,20 @@
|
|||
#include "pc/debuglog.h"
|
||||
|
||||
void network_send_player_settings(void) {
|
||||
char playerName[MAX_PLAYER_STRING+1] = { 0 };
|
||||
if (snprintf(playerName, MAX_PLAYER_STRING, "%s", configPlayerName) < 0) {
|
||||
char playerName[MAX_CONFIG_STRING] = { 0 };
|
||||
if (snprintf(playerName, MAX_CONFIG_STRING, "%s", configPlayerName) < 0) {
|
||||
LOG_INFO("truncating player name");
|
||||
}
|
||||
|
||||
struct Packet p = { 0 };
|
||||
packet_init(&p, PACKET_PLAYER_SETTINGS, true, PLMT_NONE);
|
||||
packet_write(&p, &gNetworkPlayers[0].globalIndex, sizeof(u8));
|
||||
packet_write(&p, playerName, MAX_PLAYER_STRING * sizeof(u8));
|
||||
packet_write(&p, playerName, MAX_CONFIG_STRING * sizeof(u8));
|
||||
packet_write(&p, &configPlayerModel, sizeof(u8));
|
||||
packet_write(&p, &configPlayerPalette, sizeof(struct PlayerPalette));
|
||||
|
||||
if (gNetworkPlayerLocal != NULL) {
|
||||
if (snprintf(gNetworkPlayerLocal->name, MAX_PLAYER_STRING, "%s", playerName) < 0) {
|
||||
if (snprintf(gNetworkPlayerLocal->name, MAX_CONFIG_STRING, "%s", playerName) < 0) {
|
||||
LOG_INFO("truncating player name");
|
||||
}
|
||||
}
|
||||
|
@ -26,12 +26,12 @@ void network_send_player_settings(void) {
|
|||
|
||||
void network_receive_player_settings(struct Packet* p) {
|
||||
u8 globalId;
|
||||
char playerName[MAX_PLAYER_STRING+1] = { 0 };
|
||||
char playerName[MAX_CONFIG_STRING] = { 0 };
|
||||
u8 playerModel;
|
||||
struct PlayerPalette playerPalette;
|
||||
|
||||
packet_read(p, &globalId, sizeof(u8));
|
||||
packet_read(p, &playerName, MAX_PLAYER_STRING * sizeof(u8));
|
||||
packet_read(p, &playerName, MAX_CONFIG_STRING * sizeof(u8));
|
||||
packet_read(p, &playerModel, sizeof(u8));
|
||||
packet_read(p, &playerPalette, sizeof(struct PlayerPalette));
|
||||
|
||||
|
@ -51,7 +51,7 @@ void network_receive_player_settings(struct Packet* p) {
|
|||
|
||||
struct NetworkPlayer* np = network_player_from_global_index(globalId);
|
||||
if (!np) { LOG_ERROR("Failed to retrieve network player."); return; }
|
||||
if (snprintf(np->name, MAX_PLAYER_STRING, "%s", playerName) < 0) {
|
||||
if (snprintf(np->name, MAX_CONFIG_STRING, "%s", playerName) < 0) {
|
||||
LOG_INFO("truncating player name");
|
||||
}
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ static const char *sys_old_user_path(void) {
|
|||
char *sdlPath = SDL_GetPrefPath("", "sm64ex-coop");
|
||||
if (sdlPath) {
|
||||
const unsigned int len = strlen(sdlPath);
|
||||
strncpy(path, sdlPath, sizeof(path));
|
||||
snprintf(path, sizeof(path), "%s", sdlPath);
|
||||
path[sizeof(path)-1] = 0;
|
||||
|
||||
SDL_free(sdlPath);
|
||||
|
@ -113,7 +113,7 @@ const char *sys_user_path(void) {
|
|||
}
|
||||
|
||||
const unsigned int len = strlen(sdlPath);
|
||||
strncpy(path, sdlPath, sizeof(path));
|
||||
snprintf(path, sizeof(path), "%s", sdlPath);
|
||||
path[sizeof(path)-1] = 0;
|
||||
|
||||
SDL_free(sdlPath);
|
||||
|
@ -131,7 +131,7 @@ const char *sys_exe_path(void) {
|
|||
if (sdlPath && sdlPath[0]) {
|
||||
// use the SDL path if it exists
|
||||
const unsigned int len = strlen(sdlPath);
|
||||
strncpy(path, sdlPath, sizeof(path));
|
||||
snprintf(path, sizeof(path), "%s", sdlPath);
|
||||
path[sizeof(path)-1] = 0;
|
||||
SDL_free(sdlPath);
|
||||
if (path[len-1] == '/' || path[len-1] == '\\')
|
||||
|
|
|
@ -75,7 +75,7 @@ void get_version_remote(void) {
|
|||
}
|
||||
|
||||
buffer[bytesRead] = '\0';
|
||||
strncpy(sRemoteVersion, buffer, 8);
|
||||
snprintf(sRemoteVersion, 8, "%s", buffer);
|
||||
|
||||
// close handles
|
||||
InternetCloseHandle(hUrl);
|
||||
|
@ -107,7 +107,7 @@ void get_version_remote(void) {
|
|||
|
||||
if (!buffer) { return; }
|
||||
|
||||
strncpy(sRemoteVersion, buffer, 8);
|
||||
snprintf(sRemoteVersion, 8, "%s", buffer);
|
||||
|
||||
// Clean up
|
||||
curl_easy_cleanup(curl);
|
||||
|
|
Loading…
Reference in New Issue